edit 框架设计

This commit is contained in:
lyc 2025-01-07 16:25:07 +08:00
parent 586ce134f8
commit 49facdffa9
2 changed files with 142 additions and 59 deletions

View File

@ -20,23 +20,31 @@
</div> </div>
</div> </div>
<div class="center-con" v-loading="loading"> <div class="center-con" v-loading="loading">
<!-- <TypingEffect v-if="answer" :text="answer" :delay="10" :aiShow="aiShow"/> --> <template v-if="answer.title">
<div style="font-size: 18px;color: #409eff;">封面页</div> <div class="flex justify-between">
<span style="font-size: 18px;color: #409eff;">封面页</span>
<el-button type="primary" link @click="onEdit(item, -1)">编辑</el-button>
</div>
<div class="con-item mb-5"> <div class="con-item mb-5">
<div class="item-name">标题{{ answer.title }}</div> <div class="item-name">标题{{ answer.title }}</div>
<div class="item-name">副标题{{answer.subTitle }}</div> <div class="item-name">副标题{{ answer.subTitle }}</div>
</div> </div>
<div style="font-size: 18px;color: #409eff;">目录页</div> <div style="font-size: 18px;color: #409eff;">目录页</div>
<div class="con-item" v-for="(item,index) in answer.chapters"> <div class="con-item" v-for="(item, index) in answer.chapters">
<div class="item-name">{{index + 1}}{{ item.chapterTitle }}</div> <div class="item-name">
<span>{{ index + 1 }}{{ item.chapterTitle }}</span>
<el-button type="primary" link @click="onEdit(item, index)">编辑</el-button>
</div>
<div class="item-text"> <div class="item-text">
<p v-for="(el,i) in item.chapterContents">{{ index + 1 }} - {{ i + 1}} : {{ el.chapterTitle }}</p> <p v-for="(el, i) in item.chapterContents">{{ index + 1 }} - {{ i + 1 }} : {{ el.chapterTitle }}</p>
</div>
</div>
</template>
<el-empty v-else description="请选择符合您需要的教学模式,生成教学大纲" />
</div> </div>
</div> </div>
<el-empty v-if="!answer.title" description="请选择符合您需要的教学模式,生成教学大纲" /> <EditDialog v-model="isEdit" :item="editItem" :index="editIndex" />
</div>
</div>
<EditDialog v-model="isEdit" :item="curItem" />
</template> </template>
<script setup> <script setup>
@ -47,9 +55,10 @@ import EditDialog from './edit-dialog.vue'
import emitter from '@/utils/mitt' import emitter from '@/utils/mitt'
import * as commUtils from '@/utils/comm.js' import * as commUtils from '@/utils/comm.js'
import { createChart, sendChart } from '@/api/ai/index' import { createChart, sendChart } from '@/api/ai/index'
import { completion, addSyllabus, syllabuss, removeSyllabus } from '@/api/mode/index.js' import { completion, addSyllabus, syllabuss, removeSyllabus, editSyllabus } from '@/api/mode/index.js'
import { createOutlineV2 } from '@/utils/ppt-request.js' import { createOutlineV2 } from '@/utils/ppt-request.js'
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
import { cloneDeep } from 'lodash'
const curMode = ref(2) const curMode = ref(2)
const isEdit = ref(false) const isEdit = ref(false)
@ -70,26 +79,22 @@ const modeOptions = ref([
// //
const selectedData = ref([]) const selectedData = ref([])
emitter.on('selected', (data)=>{ emitter.on('selected', (data) => {
selectedData.value = data selectedData.value = data
}) })
// //
const curItem = reactive({}) const curItem = reactive({})
emitter.on('onShow', (data)=>{ emitter.on('onShow', (data) => {
console.log(data) console.log(data)
aiShow.value = false aiShow.value = false
Object.assign(answer, JSON.parse(data.outline)) Object.assign(answer, JSON.parse(data.outline))
Object.assign(curItem, data) Object.assign(curItem, data)
curItem.answer = curItem.outline emitter.emit('onResult',data)
getDetails(data.id)
}) })
const getDetails = (id) =>{
syllabuss(id).then( res =>{
Object.assign(curItem, res.data)
emitter.emit('onResult', res.data)
})
}
const params = reactive( const params = reactive(
{ {
@ -103,13 +108,13 @@ const params = reactive(
const loading = ref(false) const loading = ref(false)
const answer = reactive({}) const answer = reactive({})
const createAi = async ()=>{ const createAi = async () => {
if(selectedData.value.length == 0){ if (selectedData.value.length == 0) {
ElMessage.warning('请先选择教学环节后再生成教学大纲') ElMessage.warning('请先选择教学环节后再生成教学大纲')
return return
} }
let str = selectedData.value.map( item => item.name).join('、') let str = selectedData.value.map(item => item.name).join('、')
let bookV = curNode.roottitle.split('-')[1] + '版' let bookV = curNode.roottitle.split('-')[1] + '版'
loading.value = true loading.value = true
aiShow.value = true aiShow.value = true
@ -134,7 +139,7 @@ const createAi = async ()=>{
data = res.data data = res.data
} }
const res = await createOutlineV2({query: data.answer}) const res = await createOutlineV2({ query: data.answer })
console.log(res) console.log(res)
emitter.emit('onResult', res) emitter.emit('onResult', res)
Object.assign(answer, res.outline) Object.assign(answer, res.outline)
@ -144,11 +149,49 @@ const createAi = async ()=>{
} }
} }
//
const editItem = reactive({})
const editIndex = ref(0)
const onEdit = (item, index)=>{
let obj = null
if(index == -1){
obj = {
title: answer.title,
subTitle: answer.subTitle
}
}
else{
obj = cloneDeep(item)
}
editIndex.value = index
isEdit.value = true
Object.assign(editItem, obj)
}
emitter.on('editItem', (item) =>{
if(editIndex.value == -1){
answer.title = item.title
answer.subTitle = item.subTitle
}else{
answer.chapters[editIndex.value] = item
}
let data = cloneDeep(curItem)
data.outline = JSON.stringify(cloneDeep(answer))
loading.value = true
editSyllabus(data).then( res =>{
ElMessage.success('操作成功')
}).finally( ()=>{
loading.value = false
})
})
// //
const onSaveTemp = async (answer) => { const onSaveTemp = async (answer) => {
if (answer == '') return if (answer == '') return
let modelIds = selectedData.value.map( item => item.id).join(',') let modelIds = selectedData.value.map(item => item.id).join(',')
const data = { const data = {
eduId: curNode.id, eduId: curNode.id,
outline: answer, outline: answer,
@ -162,7 +205,7 @@ const onSaveTemp = async (answer) => {
} }
// //
const delAnswer = () =>{ const delAnswer = () => {
ElMessageBox.confirm( ElMessageBox.confirm(
'确定要删除大纲吗?', '确定要删除大纲吗?',
'温馨提示', '温馨提示',
@ -178,7 +221,7 @@ const delAnswer = () =>{
answer.value = '' answer.value = ''
emitter.emit('resetSelect') emitter.emit('resetSelect')
}) })
.catch(() => {}) .catch(() => { })
} }
@ -192,9 +235,11 @@ const getChartId = () => {
}) })
} }
onUnmounted(()=>{ onUnmounted(() => {
emitter.off('selected') emitter.off('selected')
emitter.off('onShow') emitter.off('onShow')
emitter.off('editItem')
}) })
@ -216,18 +261,21 @@ onMounted(() => {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.container-center{ .container-center {
height: 100%; height: 100%;
font-size: 15px; font-size: 15px;
flex-direction: column; flex-direction: column;
.center-header{
.center-header {
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
.icon-jiahao{
.icon-jiahao {
font-size: 12px; font-size: 12px;
} }
} }
.center-con{
.center-con {
flex: 1; flex: 1;
margin-top: 5px; margin-top: 5px;
background-color: #fff; background-color: #fff;
@ -235,11 +283,16 @@ onMounted(() => {
text-align: left; text-align: left;
overflow-y: auto; overflow-y: auto;
padding: 15px; padding: 15px;
.con-item{
.con-item {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
margin-top: 15px; margin-top: 15px;
.item-text{ .item-name{
display: flex;
justify-content: space-between;
}
.item-text {
background: #F2F2F2; background: #F2F2F2;
padding: 15px; padding: 15px;
border-radius: 5px; border-radius: 5px;
@ -248,5 +301,4 @@ onMounted(() => {
} }
} }
} }
</style> </style>

View File

@ -7,11 +7,28 @@
</div> </div>
</template> </template>
<div class="dialog-content" v-loading="loading"> <div class="dialog-content" v-loading="loading">
<el-row> <template v-if="props.index == -1">
<el-col :span="24"> <div class="flex mb-5">
<el-input v-model="textarea" :autosize="{ minRows: 5, maxRows: 15 }" type="textarea" /> <span class="name">标题</span>
</el-col> <el-input v-model="editItem.title" />
</el-row> </div>
<div class="flex mb-5">
<span class="name">副标题</span>
<el-input v-model="editItem.subTitle" />
</div>
</template>
<template v-else>
<div class="flex mb-5">
<span class="name">标题</span>
<el-input v-model="editItem.chapterTitle" />
</div>
<div class="flex">
<span class="name">内容</span>
<div class="flex edit-con">
<el-input class="mb-3" v-model="item.chapterTitle" v-for="item in editItem.chapterContents" />
</div>
</div>
</template>
</div> </div>
<template #footer> <template #footer>
@ -26,13 +43,13 @@
</template> </template>
<script setup> <script setup>
import { ref, watch} from 'vue' import { reactive, ref, watch} from 'vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { editSyllabus } from '@/api/mode/index.js' import { editSyllabus } from '@/api/mode/index.js'
import { cloneDeep } from 'lodash'; import { cloneDeep } from 'lodash';
import emitter from '@/utils/mitt'; import emitter from '@/utils/mitt';
const textarea = ref('')
const isDialog = defineModel() const isDialog = defineModel()
const loading = ref(false) const loading = ref(false)
@ -40,20 +57,28 @@ const loading = ref(false)
const props = defineProps({ const props = defineProps({
item: { item: {
type: Object, type: Object,
default: () => {
return { name: '11' } },
} index: {
type: [Number, String]
} }
}) })
watch(() => props.item.answer, (newVal) => { const editItem = reactive({})
if (newVal) {
textarea.value = newVal watch(() => isDialog.value, (newVal) => {
if(newVal){
let data = cloneDeep(props.item)
Object.assign(editItem, data)
} }
},{ deep: true }) },{ deep: true })
const emit = defineEmits(['saveEdit']) const emit = defineEmits(['saveEdit'])
const onSave = () =>{ const onSave = () =>{
emitter.emit('editItem', editItem)
isDialog.value = false
return
loading.value = true loading.value = true
let data = cloneDeep(props.item) let data = cloneDeep(props.item)
data.outline = textarea.value data.outline = textarea.value
@ -83,6 +108,12 @@ const onSave = () =>{
.dialog-content { .dialog-content {
padding-top: 10px; padding-top: 10px;
.name{
flex-shrink: 0;
}
.edit-con{
width: 100%;
flex-direction: column;
}
} }
</style> </style>