This commit is contained in:
lyc 2025-01-05 20:53:39 +08:00
parent a31a7d9c7e
commit e9bc48963b
6 changed files with 198 additions and 100 deletions

View File

@ -118,7 +118,6 @@ export function docList(params) {
}) })
} }
// 保存教学大纲 // 保存教学大纲
export function addSyllabus(data) { export function addSyllabus(data) {
return request({ return request({
@ -128,3 +127,35 @@ export function addSyllabus(data) {
}) })
} }
// 获取保存的大纲列表
export function syllabusList(params) {
return request({
url: '/education/generate/list',
method: 'get',
params
})
}
// 大纲详情
export function syllabuss(id) {
return request({
url: '/education/generate/' + id,
method: 'get',
})
}
// 删除大纲
export function removeSyllabus(id) {
return request({
url: '/education/generate/' + id,
method: 'delete',
})
}
export function editSyllabus(data) {
return request({
url: '/education/generate',
method: 'put',
data
})
}

View File

@ -344,6 +344,8 @@ const againResult = async (index, item) => {
} }
} }
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
// //
const getCompletion = async () => { const getCompletion = async () => {
isStarted.value = new Array(childTempList.length).fill(false) isStarted.value = new Array(childTempList.length).fill(false)
@ -372,6 +374,7 @@ const getCompletion = async () => {
conversationId: conversation_id.value, conversationId: conversation_id.value,
stream: false stream: false
}) })
await delay(1000); // 1
data = res.data data = res.data
} }
// //

View File

@ -9,29 +9,41 @@
<el-button type="primary" @click="createAi"> <el-button type="primary" @click="createAi">
<i class="iconfont icon-chuangzuo"></i>生成教学大纲 <i class="iconfont icon-chuangzuo"></i>生成教学大纲
</el-button> </el-button>
<el-button type="danger" :disabled="Boolean(!answer)" @click="delAnswer">
<i class="iconfont icon-shanchu"></i>
删除大纲
</el-button>
<el-button type="primary" @click="isEdit = true">
<i class="iconfont icon-bianji"></i>编辑大纲
</el-button>
</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/> <TypingEffect v-if="answer" :text="answer" :delay="10" :aiShow="aiShow"/>
<el-empty v-if="!answer" description="请选择符合您需要的教学模式,生成教学大纲" /> <el-empty v-if="!answer" description="请选择符合您需要的教学模式,生成教学大纲" />
</div> </div>
</div> </div>
<EditDialog v-model="isEdit" :item="curItem" />
</template> </template>
<script setup> <script setup>
import { ref, reactive, onMounted, onUnmounted } from 'vue' import { ref, reactive, onMounted, onUnmounted } from 'vue'
import { ElMessage } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { sessionStore } from '@/utils/store' import { sessionStore } from '@/utils/store'
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 } from '@/api/mode/index.js' import { completion, addSyllabus, syllabuss, removeSyllabus } from '@/api/mode/index.js'
import TypingEffect from '@/components/typing-effect/index.vue' import TypingEffect from '@/components/typing-effect/index.vue'
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
const curMode = ref(2) const curMode = ref(2)
const isEdit = ref(false)
const { user } = useUserStore() const { user } = useUserStore()
const aiShow = ref(false)
const modeOptions = ref([ const modeOptions = ref([
{ {
@ -49,7 +61,21 @@ const selectedData = ref([])
emitter.on('selected', (data)=>{ emitter.on('selected', (data)=>{
selectedData.value = data selectedData.value = data
}) })
//
const curItem = reactive({})
emitter.on('onShow', (data)=>{
aiShow.value = false
answer.value = getResult(data.outline)
Object.assign(curItem, data)
curItem.answer = curItem.outline
getDetails(data.id)
})
const getDetails = (id) =>{
syllabuss(id).then( res =>{
console.log(res)
})
}
const params = reactive( const params = reactive(
{ {
@ -62,17 +88,18 @@ const params = reactive(
// //
const loading = ref(false) const loading = ref(false)
const answer = ref('') const answer = ref('')
const createAi = async ()=>{ const createAi = async ()=>{
console.log(selectedData.value) console.log(selectedData.value)
if(selectedData.value.length == 0){ if(selectedData.value.length == 0){
ElMessage.warning('请先选择教学环节后再生成教学大纲') ElMessage.warning('请先选择教学环节后再生成教学大纲')
return return
} }
onSaveTemp()
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
try { try {
params.prompt = `针对${curNode.edustage}${curNode.edusubject}${bookV}${curNode.itemtitle}这一课,根据以下教学环节:${str}进行课件教学PPT内容设计` params.prompt = `针对${curNode.edustage}${curNode.edusubject}${bookV}${curNode.itemtitle}这一课,根据以下教学环节:${str}进行课件教学PPT内容设计`
@ -94,10 +121,10 @@ const createAi = async ()=>{
data = res.data data = res.data
} }
console.log(data) console.log(data)
emitter('onResult', data.answer) emitter.emit('onResult', data.answer)
answer.value = getResult(data.answer) answer.value = getResult(data.answer)
// onSaveTemp(item) onSaveTemp(data.answer)
} finally { } finally {
loading.value = false loading.value = false
} }
@ -106,27 +133,41 @@ const createAi = async ()=>{
// //
const onSaveTemp = async (data) => { const onSaveTemp = async (answer) => {
if (data == '') return if (answer == '') return
console.log(selectedData)
let modelIds = selectedData.value.map( item => item.id).join(',') let modelIds = selectedData.value.map( item => item.id).join(',')
console.log(modelIds) const data = {
console.log(user)
const data1 = {
eduId: curNode.id, eduId: curNode.id,
outline: data, outline: answer,
outlineType: curMode.value == 1 ? 0 : 1, outlineType: curMode.value == 1 ? 0 : 1,
modelIds, modelIds,
sourceType: 1, sourceType: 1,
createUserId: 1 createUserId: user.userId,
} createUserName: user.nickName
// const res = await addSyllabus(data)
if(!item.resultId){
item.resultId = res.data
} }
await addSyllabus(data)
} }
//
const delAnswer = () =>{
ElMessageBox.confirm(
'确定要删除大纲吗?',
'温馨提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
)
.then(async () => {
await removeSyllabus(curItem.id)
ElMessage.success('操作成功')
answer.value = ''
emitter.emit('resetSelect')
})
.catch(() => {})
}
// ### ** // ### **
let getResult = (str) => { let getResult = (str) => {
@ -145,6 +186,8 @@ const getChartId = () => {
onUnmounted(()=>{ onUnmounted(()=>{
emitter.off('selected') emitter.off('selected')
emitter.off('onShow')
}) })
const curNode = reactive({}) const curNode = reactive({})

View File

@ -6,7 +6,7 @@
<i class="iconfont icon-guanbi" @click="isDialog = false"></i> <i class="iconfont icon-guanbi" @click="isDialog = false"></i>
</div> </div>
</template> </template>
<div class="dialog-content"> <div class="dialog-content" v-loading="loading">
<el-row> <el-row>
<el-col :span="24"> <el-col :span="24">
<el-input v-model="textarea" :autosize="{ minRows: 5, maxRows: 15 }" type="textarea" /> <el-input v-model="textarea" :autosize="{ minRows: 5, maxRows: 15 }" type="textarea" />
@ -28,11 +28,14 @@
<script setup> <script setup>
import { ref, watch} from 'vue' import { ref, watch} from 'vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { editSyllabus } from '@/api/mode/index.js'
import { cloneDeep } from 'lodash';
import emitter from '@/utils/mitt'; import emitter from '@/utils/mitt';
const textarea = ref('') const textarea = ref('')
const isDialog = defineModel() const isDialog = defineModel()
const loading = ref(false)
const props = defineProps({ const props = defineProps({
item: { item: {
@ -51,9 +54,17 @@ watch(() => props.item.answer, (newVal) => {
const emit = defineEmits(['saveEdit']) const emit = defineEmits(['saveEdit'])
const onSave = () =>{ const onSave = () =>{
emitter.emit('changeResult', textarea.value) loading.value = true
isDialog.value = false let data = cloneDeep(props.item)
ElMessage.success('操作成功') data.outline = textarea.value
editSyllabus(data).then( res =>{
isDialog.value = false
ElMessage.success('操作成功')
emitter.emit('onShow', data)
}).finally( ()=>{
loading.value = false
})
} }

View File

@ -11,7 +11,7 @@
<div class="left-list"> <div class="left-list">
<div class="item" v-for="item in templateList" :key="item.id"> <div class="item" v-for="item in templateList" :key="item.id">
<div class="item-name flex" @mouseenter="item.isAdd = true" @mouseleave="item.isAdd = false" <div class="item-name flex" @mouseenter="item.isAdd = true" @mouseleave="item.isAdd = false"
@click="handleItem(item)"> @click="toggleParent(item)">
<div class="flex"> <div class="flex">
<span>{{ item.name }}</span> <span>{{ item.name }}</span>
<!--个人教学模式才会有添加编辑--> <!--个人教学模式才会有添加编辑-->
@ -21,19 +21,19 @@
</div> </div>
</div> </div>
<!--加号 数鼠标悬浮 显示--> <!--加号 数鼠标悬浮 显示-->
<i v-show="item.isAdd && !item.isSelect" class="iconfont icon-jiahao"></i> <i v-show="item.isAdd && !item.selected" class="iconfont icon-jiahao"></i>
<!--减号 选中之后显示--> <!--减号 选中之后显示-->
<i v-show="item.isSelect" class="iconfont icon-zuixiaohua"></i> <i v-show="item.selected" class="iconfont icon-zuixiaohua"></i>
</div> </div>
<div class="item-child flex" :class="el.isSelect ? 'act-child' : ''" v-for="el in item.child" :key="el.id" <div class="item-child flex" :class="child.selected ? 'act-child' : ''" v-for="child in item.children" :key="child.id"
@mouseenter="el.isAdd = true" @mouseleave="el.isAdd = false" @click="handleItemChild(el)"> @mouseenter="child.isAdd = true" @mouseleave="child.isAdd = false" @click="toggleChild(item,child)">
<div> <div>
<span>{{ el.name }}</span> <span>{{ child.name }}</span>
<!--个人教学模式才会有编辑--> <!--个人教学模式才会有编辑-->
<el-button v-if="!el.ex3" class="ml-3" type="primary" link @click.stop="editMode(el)">编辑</el-button> <el-button v-if="!child.ex3" class="ml-3" type="primary" link @click.stop="editMode(child)">编辑</el-button>
</div> </div>
<i v-show="el.isAdd && !el.isSelect" class="iconfont icon-jiahao"></i> <i v-show="child.isAdd && !child.selected" class="iconfont icon-jiahao"></i>
<i v-show="el.isSelect" class="iconfont icon-zuixiaohua "></i> <i v-show="child.selected" class="iconfont icon-zuixiaohua "></i>
</div> </div>
</div> </div>
</div> </div>
@ -68,13 +68,13 @@
</template> </template>
<script setup> <script setup>
import { ref, reactive, onMounted } from 'vue' import { ref, reactive, onMounted, onUnmounted } from 'vue'
import { modelList } from '@/api/mode/index' import { modelList } from '@/api/mode/index'
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
import { sessionStore } from '@/utils/store' import { sessionStore } from '@/utils/store'
import emitter from '@/utils/mitt' import emitter from '@/utils/mitt'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { addChildTemp, editChildTemp, removeChildTemp } from '@/api/mode' import { addChildTemp, editChildTemp, removeChildTemp, syllabusList } from '@/api/mode'
import { cloneDeep } from 'lodash' import { cloneDeep } from 'lodash'
@ -104,67 +104,73 @@ const getChildTemp = async () => {
let { rows } = await modelList({ model: 4, type: 2, parentId: item.id }) let { rows } = await modelList({ model: 4, type: 2, parentId: item.id })
templateList.value.push({ templateList.value.push({
...item, ...item,
child: rows children: rows
}) })
} finally { } finally {
loading.value = false loading.value = false
} }
} }
getSyllabus()
} }
//
const getSyllabus = async () =>{
const { rows } = await syllabusList()
if(rows && rows.length){
const idsAry = rows.at(-1).modelIds.split(',').map(item => Number(item));
//
templateList.value.forEach((parent) => {
parent.children.forEach((child) => {
child.selected = idsAry.includes(child.id);
});
// selected
parent.selected = parent.children.every((child) => child.selected);
});
//
emitter.emit('onShow', rows.at(-1))
}
}
// //
const resetSelect = () =>{ const resetSelect = () =>{
templateList.value.forEach(item =>{ templateList.value.forEach(item =>{
item.isSelect = false item.selected = false
item.child.forEach( el=>{ item.children.forEach( el=>{
el.isSelect = false el.selected = false
}) })
}) })
emitter.emit('selected', [])
} }
const handleItem = (item) => { emitter.on('resetSelect', () =>{
if(item.newMode) return resetSelect()
item.isSelect = !item.isSelect })
item.child.forEach(el => {
el.isSelect = !el.isSelect
})
let data = collectSelectedItems(templateList.value) //
emitter.emit('selected', data) const toggleParent = (parent) => {
parent.selected = !parent.selected;
parent.children.forEach(child => {
child.selected = parent.selected;
});
const selectedData = templateList.value.map((item) => item.children.filter((child) => child.selected)).flat()
// .flat()
emitter.emit('selected', selectedData)
} }
const handleItemChild = (el) =>{ //
el.isSelect = !el.isSelect const toggleChild = (parent,child) =>{
child.selected = !child.selected;
let data = collectSelectedItems(templateList.value) updateParentSelection(parent)
emitter.emit('selected', data) const selectedData = templateList.value.map((item) => item.children.filter((child) => child.selected)).flat()
emitter.emit('selected', selectedData)
} }
// ()()
const updateParentSelection = (parent) => {
// children isSelect true parent.selected = parent.children.every((child) => child.selected);
const collectSelectedItems = (data) => {
let result = [];
//
data.forEach(parent => {
if (Array.isArray(parent.child)) {
// 使 filter children isSelect true
const selectedChildren = parent.child.filter(child => child.isSelect === true);
//
result = result.concat(selectedChildren.map(child => ({
...child
})));
}
});
return result;
} }
// //
const addVisible = ref(false) const addVisible = ref(false)
@ -286,6 +292,10 @@ onMounted(() => {
}) })
onUnmounted(()=>{
emitter.off('resetSelect')
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -1,14 +1,14 @@
<template> <template>
<div class="page-design flex"> <div class="page-design">
<div class="page-left"> <!-- <div class="page-left">
<left /> <left />
</div> </div>
<div class="page-right"> <div class="page-right">
<right /> <right />
</div> </div> -->
<!-- <el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="5"> <el-col :span="5">
<Left/> <Left/>
</el-col> </el-col>
@ -18,37 +18,37 @@
<el-col :span="6"> <el-col :span="6">
<Right/> <Right/>
</el-col> </el-col>
</el-row> --> </el-row>
</div> </div>
</template> </template>
<script setup> <script setup>
import left from './container/left.vue'; // import left from './container/left.vue';
import right from './container/right.vue'; // import right from './container/right.vue';
// import Left from './container/left2.vue' import Left from './container/left2.vue'
// import Center from './container/center.vue' import Center from './container/center.vue'
// import Right from './container/right2.vue' import Right from './container/right2.vue'
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
// .page-design {
// height: 100%;
// .el-row{
// height: 100%;
// .el-col{
// height: 100%;
// }
// }
// }
.page-design { .page-design {
height: 100%; height: 100%;
.page-left{ .el-row{
width: 50%; height: 100%;
} .el-col{
.page-right{ height: 100%;
width: 50%; }
} }
} }
// .page-design {
// height: 100%;
// .page-left{
// width: 50%;
// }
// .page-right{
// width: 50%;
// }
// }
</style> </style>