Merge remote-tracking branch 'origin/main'

This commit is contained in:
朱浩 2025-01-07 11:03:13 +08:00
commit 2b17cc103d
5 changed files with 168 additions and 136 deletions

View File

@ -11,15 +11,21 @@
:default-expanded-keys="defaultExpandedKeys" :current-node-key="curNode.data.id" highlight-current :default-expanded-keys="defaultExpandedKeys" :current-node-key="curNode.data.id" highlight-current
@node-click="handleNodeClick"> @node-click="handleNodeClick">
<template #default="{ node, data }"> <template #default="{ node, data }">
<div v-if="props.isClassTask && (data.bookId == '' || data.bookId == '0')"> <div v-if="props.isClassTask && (data.bookId == '' || data.bookId == '0')" class="tree-label-wrap">
<el-tooltip effect="light" placement="right" content="该单元章节无自主试题"> <el-tooltip effect="light" placement="right" >
<template #content> {{ node.label }}<br /><span style="color: red;">-该单元章节无自主试题-</span> </template>
<span class="tree-label" style="color: #A5B3CA" > <span class="tree-label" style="color: #A5B3CA" >
{{ node.label }} {{ node.label }}
</span> </span>
</el-tooltip> </el-tooltip>
</div> </div>
<div v-else> <div v-else class="tree-label-wrap">
<span class="tree-label">{{ node.label }}</span> <el-tooltip effect="light" placement="right" >
<template #content> {{ node.label }}</template>
<span class="tree-label">
{{ node.label }}
</span>
</el-tooltip>
</div> </div>
</template> </template>
</el-tree> </el-tree>
@ -334,7 +340,7 @@ onMounted( async () => {
} }
} }
.tree-label { .tree-label-wrap, .tree-label {
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;

View File

@ -328,7 +328,7 @@ export const processList = (row, aloneOption=false) => {
// 处理[答案显示] - 1-正常 0-错误 // 处理[答案显示] - 1-正常 0-错误
const answer = workAnswerArr const answer = workAnswerArr
.map((item) => { .map((item) => {
return item === '1' ? '正确' : '错误' return DICT_TRUE_OR_FALSE.TRUE.includes(item) ? '正确' : DICT_TRUE_OR_FALSE.FALSE.includes(item)?'错误':item;
}) })
.join('、') .join('、')
row[i].workanswerFormat = answer row[i].workanswerFormat = answer
@ -341,3 +341,8 @@ export const processList = (row, aloneOption=false) => {
} }
} }
} }
const DICT_TRUE_OR_FALSE = {
TRUE: ['正确', '对', '√', '1'],
FALSE: ['错误', '错', '×', '0'],
};

View File

@ -107,9 +107,13 @@ const getBackGroundV2 = async () => {
} }
}; };
const createOutlineV2 = async (data) => { const createOutlineV2 = async (params) => {
try { try {
const response = await req("/api/aipptV2/createOutlineV2", "POST", data); const response = await request({
url:"/api/aipptV2/createOutlineV2",
method: "POST",
params
});
console.log("createOutline response:", response); console.log("createOutline response:", response);
return response.data; return response.data;

View File

@ -20,8 +20,20 @@
</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"/> <!-- <TypingEffect v-if="answer" :text="answer" :delay="10" :aiShow="aiShow"/> -->
<el-empty v-if="!answer" description="请选择符合您需要的教学模式,生成教学大纲" /> <div style="font-size: 18px;color: #409eff;">封面页</div>
<div class="con-item mb-5">
<div class="item-name">标题{{ answer.title }}</div>
<div class="item-name">副标题{{answer.subTitle }}</div>
</div>
<div style="font-size: 18px;color: #409eff;">目录页</div>
<div class="con-item" v-for="(item,index) in answer.chapters">
<div class="item-name">{{index + 1}}{{ item.chapterTitle }}</div>
<div class="item-text">
<p v-for="(el,i) in item.chapterContents">{{ index + 1 }} - {{ i + 1}} : {{ el.chapterTitle }}</p>
</div>
</div>
<el-empty v-if="!answer.title" description="请选择符合您需要的教学模式,生成教学大纲" />
</div> </div>
</div> </div>
<EditDialog v-model="isEdit" :item="curItem" /> <EditDialog v-model="isEdit" :item="curItem" />
@ -36,7 +48,7 @@ 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 } from '@/api/mode/index.js'
import TypingEffect from '@/components/typing-effect/index.vue' import { createOutlineV2 } from '@/utils/ppt-request.js'
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
const curMode = ref(2) const curMode = ref(2)
@ -64,8 +76,9 @@ emitter.on('selected', (data)=>{
// //
const curItem = reactive({}) const curItem = reactive({})
emitter.on('onShow', (data)=>{ emitter.on('onShow', (data)=>{
console.log(data)
aiShow.value = false aiShow.value = false
answer.value = getResult(data.outline) Object.assign(answer, JSON.parse(data.outline))
Object.assign(curItem, data) Object.assign(curItem, data)
curItem.answer = curItem.outline curItem.answer = curItem.outline
getDetails(data.id) getDetails(data.id)
@ -88,10 +101,9 @@ const params = reactive(
// //
const loading = ref(false) const loading = ref(false)
const answer = ref('') const answer = reactive({})
const createAi = async ()=>{ const createAi = async ()=>{
console.log(selectedData.value)
if(selectedData.value.length == 0){ if(selectedData.value.length == 0){
ElMessage.warning('请先选择教学环节后再生成教学大纲') ElMessage.warning('请先选择教学环节后再生成教学大纲')
return return
@ -119,17 +131,17 @@ const createAi = async ()=>{
// //
else { else {
const res = await completion(params) const res = await completion(params)
data = res.data data = res.data
} }
console.log(data) const res = await createOutlineV2({query: data.answer})
emitter.emit('onResult', data.answer) console.log(res)
answer.value = getResult(data.answer) emitter.emit('onResult', res)
Object.assign(answer, res.outline)
onSaveTemp(data.answer) onSaveTemp(JSON.stringify(res.outline))
} finally { } finally {
loading.value = false loading.value = false
} }
} }
@ -170,11 +182,6 @@ const delAnswer = () =>{
} }
// ### **
let getResult = (str) => {
let newStr = str.replace(/#+|(\*\*)/g, '');
return newStr
}
// //
const conversation_id = ref('') const conversation_id = ref('')
@ -227,6 +234,18 @@ onMounted(() => {
border-radius: 5px; border-radius: 5px;
text-align: left; text-align: left;
overflow-y: auto; overflow-y: auto;
padding: 15px;
.con-item{
display: flex;
flex-direction: column;
margin-top: 15px;
.item-text{
background: #F2F2F2;
padding: 15px;
border-radius: 5px;
margin-top: 10px;
}
}
} }
} }

View File

@ -4,8 +4,11 @@
<span>教学模式</span> <span>教学模式</span>
<div> <div>
<el-button type="primary" link @click="resetSelect">重置</el-button> <el-button type="primary" link @click="resetSelect">重置</el-button>
<el-button type="primary" link @click="addVisible = true; addChild = false; isEdit = false"><i class="iconfont icon-jiahao" <el-button type="primary" link @click="
></i>新增</el-button> addVisible = true,
addChild = false,
isEdit = false
"><i class="iconfont icon-jiahao"></i>新增</el-button>
</div> </div>
</div> </div>
<div class="left-list"> <div class="left-list">
@ -25,8 +28,9 @@
<!--减号 选中之后显示--> <!--减号 选中之后显示-->
<i v-show="item.selected" class="iconfont icon-zuixiaohua"></i> <i v-show="item.selected" class="iconfont icon-zuixiaohua"></i>
</div> </div>
<div class="item-child flex" :class="child.selected ? 'act-child' : ''" v-for="child in item.children" :key="child.id" <div class="item-child flex" :class="child.selected ? 'act-child' : ''" v-for="child in item.children"
@mouseenter="child.isAdd = true" @mouseleave="child.isAdd = false" @click="toggleChild(item,child)"> :key="child.id" @mouseenter="child.isAdd = true" @mouseleave="child.isAdd = false"
@click="toggleChild(item, child)">
<div> <div>
<span>{{ child.name }}</span> <span>{{ child.name }}</span>
<!--个人教学模式才会有编辑--> <!--个人教学模式才会有编辑-->
@ -39,7 +43,7 @@
</div> </div>
<!--弹窗--> <!--弹窗-->
<el-dialog v-model="addVisible" append-to-body :show-close="false" width="550" :before-close="handleBeforeClose" <el-dialog v-model="addVisible" append-to-body :show-close="false" width="550" :before-close="handleBeforeClose"
style="border-radius: 10px; padding: 10px 15px;"> style="border-radius: 10px; padding: 10px 15px">
<template #header> <template #header>
<div class="mode-dialog-header flex"> <div class="mode-dialog-header flex">
<span>{{ addChild ? '教学环节' : '教学模式' }}</span> <span>{{ addChild ? '教学环节' : '教学模式' }}</span>
@ -49,7 +53,7 @@
<el-form ref="ruleFormRef" style="max-width: 600px" :model="ruleForm" :rules="rules" label-width="auto" <el-form ref="ruleFormRef" style="max-width: 600px" :model="ruleForm" :rules="rules" label-width="auto"
class="demo-ruleForm"> class="demo-ruleForm">
<el-form-item :label="`教学${addChild ? '环节' : '模式'}名称`" prop="name"> <el-form-item :label="`教学${addChild ? '环节' : '模式'}名称`" prop="name">
<div class="flex" style="width: 100%;"> <div class="flex" style="width: 100%">
<el-input v-model="ruleForm.name" /> <el-input v-model="ruleForm.name" />
<el-button v-if="isEdit" link type="danger" class="ml-5 mr-3" @click="onDel">删除</el-button> <el-button v-if="isEdit" link type="danger" class="ml-5 mr-3" @click="onDel">删除</el-button>
</div> </div>
@ -64,7 +68,6 @@
</div> </div>
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
<script setup> <script setup>
@ -77,65 +80,68 @@ import { ElMessage, ElMessageBox } from 'element-plus'
import { addChildTemp, editChildTemp, removeChildTemp, syllabusList } from '@/api/mode' import { addChildTemp, editChildTemp, removeChildTemp, syllabusList } from '@/api/mode'
import { cloneDeep } from 'lodash' import { cloneDeep } from 'lodash'
const { user } = useUserStore() const { user } = useUserStore()
// //
const loading = ref(false) const loading = ref(false)
let list = ref([])
const getTemplate = async (id) => {
loading.value = true
const { rows } = await modelList({ createUser: user.userId, model: 4, type: 1, pageNum: 1, pageSize: 10000 })
loading.value = false
list.value = rows
if (list.value.length) {
getChildTemp(id)
}
}
//
const templateList = ref([]) const templateList = ref([])
const getChildTemp = async () => { const getTemplate = async () => {
templateList.value = []
loading.value = true loading.value = true
const { rows } = await modelList({
for (let item of list.value) { createUser: user.userId,
try { model: 4,
let { rows } = await modelList({ model: 4, type: 2, parentId: item.id }) pageNum: 1,
templateList.value.push({ pageSize: 10000
...item,
children: rows
}) })
} finally {
loading.value = false loading.value = false
}
} // type 1
let ary1 = rows.filter((item) => item.type === 1)
templateList.value = ary1.map((parent) => {
parent.children = rows.filter((child) => child.type === 2 && child.parentId === parent.id)
return parent
})
getSyllabus() getSyllabus()
} }
// //
const getSyllabus = async () => { const getSyllabus = async () => {
const { rows } = await syllabusList() const { rows } = await syllabusList({
createUserId: user.userId,
eduId: curNode.id,
sourceType: 1,
pageSize: 1,
orderByColumn: 'createTime',
isAsc: 'desc'
})
if (rows && rows.length) { if (rows && rows.length) {
const idsAry = rows.at(-1).modelIds.split(',').map(item => Number(item)); const idsAry = rows
.at(-1)
.modelIds.split(',')
.map((item) => Number(item))
// //
let ary = []
templateList.value.forEach((parent) => { templateList.value.forEach((parent) => {
parent.children.forEach((child) => { parent.children.forEach((child) => {
child.selected = idsAry.includes(child.id); child.selected = idsAry.includes(child.id)
}); if (child.selected) {
ary.push(child)
}
})
// selected // selected
parent.selected = parent.children.every((child) => child.selected); parent.selected = parent.children.every((child) => child.selected)
}); })
// //
emitter.emit('onShow', rows.at(-1)) emitter.emit('onShow', rows.at(-1))
emitter.emit('selected', ary)
} }
} }
// //
const resetSelect = () => { const resetSelect = () => {
templateList.value.forEach(item =>{ templateList.value.forEach((item) => {
item.selected = false item.selected = false
item.children.forEach( el=>{ item.children.forEach((el) => {
el.selected = false el.selected = false
}) })
}) })
@ -148,37 +154,38 @@ emitter.on('resetSelect', () =>{
// //
const toggleParent = (parent) => { const toggleParent = (parent) => {
parent.selected = !parent.selected; parent.selected = !parent.selected
parent.children.forEach(child => { parent.children.forEach((child) => {
child.selected = parent.selected; child.selected = parent.selected
}); })
const selectedData = templateList.value.map((item) => item.children.filter((child) => child.selected)).flat() const selectedData = templateList.value
.map((item) => item.children.filter((child) => child.selected))
.flat()
// .flat() // .flat()
emitter.emit('selected', selectedData) emitter.emit('selected', selectedData)
} }
// //
const toggleChild = (parent, child) => { const toggleChild = (parent, child) => {
child.selected = !child.selected; child.selected = !child.selected
updateParentSelection(parent) updateParentSelection(parent)
const selectedData = templateList.value.map((item) => item.children.filter((child) => child.selected)).flat() const selectedData = templateList.value
.map((item) => item.children.filter((child) => child.selected))
.flat()
emitter.emit('selected', selectedData) emitter.emit('selected', selectedData)
} }
// ()() // ()()
const updateParentSelection = (parent) => { const updateParentSelection = (parent) => {
parent.selected = parent.children.every((child) => child.selected); parent.selected = parent.children.every((child) => child.selected)
} }
// //
const addVisible = ref(false) const addVisible = ref(false)
const ruleFormRef = ref() const ruleFormRef = ref()
const rules = reactive({ const rules = reactive({
name: [ name: [{ required: true, message: '不能为空', trigger: 'blur' }]
{ required: true, message: '不能为空', trigger: 'blur' },
]
}) })
const ruleForm = reactive({ const ruleForm = reactive({
name: '', name: '',
@ -189,7 +196,6 @@ const onSubmit = async (formEl) =>{
if (!formEl) return if (!formEl) return
await formEl.validate(async (valid, fields) => { await formEl.validate(async (valid, fields) => {
if (valid) { if (valid) {
// //
if (isEdit.value) { if (isEdit.value) {
let data = cloneDeep(curEditItem) let data = cloneDeep(curEditItem)
@ -213,7 +219,6 @@ const onSubmit = async (formEl) =>{
obj.type = 2 obj.type = 2
} }
await addChildTemp(obj) await addChildTemp(obj)
} }
ElMessage.success('操作成功') ElMessage.success('操作成功')
resetForm() resetForm()
@ -250,15 +255,11 @@ const editMode = (item)=>{
// //
const onDel = () => { const onDel = () => {
ElMessageBox.confirm( ElMessageBox.confirm('确定要删除模板吗?', '温馨提示', {
'确定要删除模板吗?',
'温馨提示',
{
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning', type: 'warning'
} })
)
.then(async () => { .then(async () => {
await removeChildTemp(curEditItem.id) await removeChildTemp(curEditItem.id)
ElMessage.success('操作成功') ElMessage.success('操作成功')
@ -269,9 +270,8 @@ const onDel = () =>{
.catch(() => { }) .catch(() => { })
} }
const closeDialog = () => { const closeDialog = () => {
handleBeforeClose(() => addVisible.value = false); handleBeforeClose(() => (addVisible.value = false))
} }
const handleBeforeClose = (done) => { const handleBeforeClose = (done) => {
@ -280,22 +280,20 @@ const handleBeforeClose = (done) =>{
} }
const resetForm = () => { const resetForm = () => {
if (ruleFormRef.value) { if (ruleFormRef.value) {
ruleFormRef.value.resetFields(); ruleFormRef.value.resetFields()
}
} }
};
const curNode = reactive({}) const curNode = reactive({})
onMounted(() => { onMounted(() => {
let data = sessionStore.get('subject.curNode') let data = sessionStore.get('subject.curNode')
Object.assign(curNode, data); Object.assign(curNode, data)
getTemplate() getTemplate()
}) })
onUnmounted(() => { onUnmounted(() => {
emitter.off('resetSelect') emitter.off('resetSelect')
}) })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -342,7 +340,7 @@ onUnmounted(()=>{
position: relative; position: relative;
&::after { &::after {
content: ""; content: '';
width: 5px; width: 5px;
height: 5px; height: 5px;
border-radius: 50%; border-radius: 50%;
@ -352,7 +350,6 @@ onUnmounted(()=>{
top: 50%; top: 50%;
transform: translate(0, -50%); transform: translate(0, -50%);
} }
} }
.iconfont { .iconfont {
@ -389,6 +386,7 @@ onUnmounted(()=>{
cursor: pointer; cursor: pointer;
} }
} }
.form-btn { .form-btn {
text-align: right; text-align: right;
margin-bottom: 10px; margin-bottom: 10px;