edit 框架设计
This commit is contained in:
commit
dc2831c101
|
@ -136,14 +136,6 @@ export function syllabusList(params) {
|
|||
})
|
||||
}
|
||||
|
||||
// 大纲详情
|
||||
export function syllabuss(id) {
|
||||
return request({
|
||||
url: '/education/generate/' + id,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
// 删除大纲
|
||||
export function removeSyllabus(id) {
|
||||
return request({
|
||||
|
|
|
@ -11,15 +11,21 @@
|
|||
:default-expanded-keys="defaultExpandedKeys" :current-node-key="curNode.data.id" highlight-current
|
||||
@node-click="handleNodeClick">
|
||||
<template #default="{ node, data }">
|
||||
<div v-if="props.isClassTask && (data.bookId == '' || data.bookId == '0')">
|
||||
<el-tooltip effect="light" placement="right" content="该单元章节无自主试题">
|
||||
<span class="tree-label" style="color: #A5B3CA">
|
||||
<div v-if="props.isClassTask && (data.bookId == '' || data.bookId == '0')" class="tree-label-wrap">
|
||||
<el-tooltip effect="light" placement="right" >
|
||||
<template #content> {{ node.label }}<br /><span style="color: red;">-该单元章节无自主试题-</span> </template>
|
||||
<div class="tree-label" style="color: #A5B3CA" >
|
||||
{{ node.label }}
|
||||
</span>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div v-else>
|
||||
<span class="tree-label">{{ node.label }}</span>
|
||||
<div v-else class="tree-label-wrap">
|
||||
<el-tooltip effect="light" placement="right" >
|
||||
<template #content> {{ node.label }}</template>
|
||||
<div class="tree-label">
|
||||
{{ node.label }}
|
||||
</div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
</el-tree>
|
||||
|
@ -38,8 +44,9 @@
|
|||
|
||||
<div class="textbook-container">
|
||||
<el-scrollbar height="450px">
|
||||
<div class="textbook-item flex" v-for="item in subjectList" :class="curBook.data.id == item.id ? 'active-item' : ''"
|
||||
:key="item.id" @click="changeBook(item)">
|
||||
<div
|
||||
v-for="item in subjectList" :key="item.id" class="textbook-item flex"
|
||||
:class="curBook.data.id == item.id ? 'active-item' : ''" @click="changeBook(item)">
|
||||
<img v-if="item.avartar" :src="item.avartar.indexOf('http') === 0 ? item.avartar : BaseUrl + item.avartar" class="textbook-img" alt="">
|
||||
<div v-else class="textbook-img">
|
||||
<i class="iconfont icon-jiaocaixuanze" style="font-size: 40px;"></i>
|
||||
|
@ -334,7 +341,8 @@ onMounted( async () => {
|
|||
}
|
||||
}
|
||||
|
||||
.tree-label {
|
||||
.tree-label-wrap, .tree-label {
|
||||
max-width: 100%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
|
|
@ -328,7 +328,7 @@ export const processList = (row, aloneOption=false) => {
|
|||
// 处理[答案显示] - 1-正常 0-错误
|
||||
const answer = workAnswerArr
|
||||
.map((item) => {
|
||||
return item === '1' ? '正确' : '错误'
|
||||
return DICT_TRUE_OR_FALSE.TRUE.includes(item) ? '正确' : DICT_TRUE_OR_FALSE.FALSE.includes(item)?'错误':item;
|
||||
})
|
||||
.join('、')
|
||||
row[i].workanswerFormat = answer
|
||||
|
@ -341,3 +341,8 @@ export const processList = (row, aloneOption=false) => {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
const DICT_TRUE_OR_FALSE = {
|
||||
TRUE: ['正确', '对', '√', '1'],
|
||||
FALSE: ['错误', '错', '×', '0'],
|
||||
};
|
|
@ -107,12 +107,12 @@ const getBackGroundV2 = async () => {
|
|||
}
|
||||
};
|
||||
|
||||
const createOutlineV2 = async (params) => {
|
||||
const createOutlineV2 = async (data) => {
|
||||
try {
|
||||
const response = await request({
|
||||
url:"/api/aipptV2/createOutlineV2",
|
||||
method: "POST",
|
||||
params
|
||||
data
|
||||
});
|
||||
console.log("createOutline response:", response);
|
||||
|
||||
|
@ -133,6 +133,18 @@ const createPPTV2 = async (data) => {
|
|||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const createPptByOutline = async (data) => {
|
||||
try {
|
||||
const response = await req("/api/aipptV2/createPptByOutline", "POST", data);
|
||||
console.log("createOutline response:", response);
|
||||
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error("请求失败:", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
const getProgressV2 = async (id) => {
|
||||
try {
|
||||
const response = await req(`/api/aipptV2/progressV2?sid=${id}`, "GET");
|
||||
|
@ -143,4 +155,4 @@ const getProgressV2 = async (id) => {
|
|||
}
|
||||
};
|
||||
|
||||
export { createOutline, getBackGround, createPPT, getProgress, getBackGroundV2, createOutlineV2, createPPTV2, getProgressV2, createByOutline };
|
||||
export { createOutline, getBackGround, createPPT, getProgress, getBackGroundV2, createOutlineV2, createPPTV2, getProgressV2, createByOutline, createPptByOutline };
|
||||
|
|
|
@ -680,6 +680,7 @@ onMounted(async () => {
|
|||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 15px;
|
||||
padding: 10px;
|
||||
.content-body-right-item{
|
||||
&:hover{
|
||||
cursor: pointer;
|
||||
|
|
|
@ -1,30 +1,123 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-dialog class="ppt-dialog" v-model="model" :show-close="false" width="800" destroy-on-close :top="'3vh'">
|
||||
<template #header="{ close, titleId, titleClass }">
|
||||
<div class="dialog-header">
|
||||
<h4 :id="titleId" :class="titleClass">生成PPT(试验版)</h4>
|
||||
<i class="iconfont icon-guanbi" @click="close"></i>
|
||||
<el-dialog class="ppt-dialog" v-model="model" title="生成PPT(试验版)"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:show-close="false" width="1000" destroy-on-close >
|
||||
<!-- <AiPptist @add-success="addAiPPT" :dataList="dataList"/>-->
|
||||
<div class="ppt-dialog-content">
|
||||
<div v-if="activeStep === 1" class="ppt-dialog-cover-wrap">
|
||||
<div v-for="(item,index) in backGroundList"
|
||||
:key="item.templateIndexId"
|
||||
@click="outlineData.templateId = item.templateIndexId"
|
||||
:class="outlineData.templateId === item.templateIndexId?'active-mode':''"
|
||||
class="ppt-dialog-cover-item">
|
||||
<div class="icon-select">
|
||||
<Select />
|
||||
</div>
|
||||
<img :src="getBackGroundImg(item.detailImage)">
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<AiPptist @add-success="addAiPPT" :dataList="dataList"/>
|
||||
<div class="ppt-dialog-prog-wrap" v-if="activeStep === 2">
|
||||
<el-progress :percentage="percentage" type="circle"></el-progress>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ppt-dialog-footer" v-if="activeStep === 1">
|
||||
<el-button @click="closeDialog">关闭</el-button>
|
||||
<el-button type="primary" :loading="createPPTLoading" @click="createPPT">生成课件</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import AiPptist from './ai-pptistV2.vue';
|
||||
import {Select} from "@element-plus/icons-vue";
|
||||
import {ref, defineEmits, onMounted} from "vue";
|
||||
import {createPPTV2, getBackGroundV2, getProgressV2, createPptByOutline} from "@/utils/ppt-request";
|
||||
import {ElMessage} from "element-plus";
|
||||
import useUserStore from '@/store/modules/user'
|
||||
const userStore = useUserStore()
|
||||
const model = defineModel()
|
||||
const emit = defineEmits(['addSuccess'])
|
||||
const emit = defineEmits(['addSuccess', 'close-dialogs'])
|
||||
const backGroundList = ref([]);
|
||||
const activeStep = ref(1);
|
||||
const props = defineProps({
|
||||
dataList: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
})
|
||||
const closeDialog = () => {
|
||||
emit('close-dialogs')
|
||||
}
|
||||
const addAiPPT = (data) => {
|
||||
emit('addSuccess', data)
|
||||
}
|
||||
const getBackGroundImg = (imgUrlStr) => {
|
||||
return JSON.parse(imgUrlStr).titleCoverImage
|
||||
};
|
||||
|
||||
const createPPTLoading = ref(false);
|
||||
const outlineData = ref({
|
||||
query: '', // 用户要求(最多8000字)
|
||||
templateId: '', // ppt生成主题
|
||||
author: userStore.user.nickName,
|
||||
isFigure: false, // 是否自动配图
|
||||
search: true,
|
||||
language: "cn"
|
||||
})
|
||||
const percentage = ref(0);
|
||||
const outlineCreatePPT = () => {
|
||||
const newOutlineData = { ...outlineData.value, };
|
||||
newOutlineData.outline = props.dataList.outline;
|
||||
newOutlineData.query = "通过传入大纲帮我生成相应的PPT课件"
|
||||
createPPTLoading.value = true;
|
||||
createPptByOutline(newOutlineData).then((res) => {
|
||||
console.log(res, "正在生成中");
|
||||
createPPTLoading.value = false;
|
||||
activeStep.value = 2
|
||||
|
||||
const checkProgress = () => {
|
||||
getProgressV2(res.sid).then(response => {
|
||||
percentage.value = Math.round(response?.donePages*100/response?.totalPages);
|
||||
if (response.pptStatus === "done") {
|
||||
emit('addSuccess',{...res,url:response.pptUrl})
|
||||
ElMessage.success("生成成功");
|
||||
} else {
|
||||
const sleepTime = 2000;
|
||||
let remainingTime = sleepTime;
|
||||
const intervalId = setInterval(() => {
|
||||
remainingTime -= 100;
|
||||
if (remainingTime <= 0) {
|
||||
clearInterval(intervalId);
|
||||
checkProgress();
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
checkProgress();
|
||||
}).finally(()=>{
|
||||
createPPTLoading.value = false
|
||||
})
|
||||
};
|
||||
|
||||
const createPPT = () => {
|
||||
if (outlineData.value.templateId) {
|
||||
outlineCreatePPT()
|
||||
}else {
|
||||
ElMessage.warning("请选择模板");
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// emit('addSuccess',{url:'https://bjcdn.openstorage.cn/xinghuo-privatedata/%2Ftmp/apiTempFileba724e0344f74e1480535eedf3ebec661601807661085006275/%E9%87%91%E9%A9%AC%E5%A5%96%E5%B0%B4%E5%B0%AC%E4%BA%8B%E4%BB%B6%E5%88%86%E6%9E%90%E4%B8%8E%E5%BA%94%E5%AF%B9%E7%AD%96%E7%95%A5.pptx'})
|
||||
getBackGroundV2().then((res) => {
|
||||
backGroundList.value = res.records;
|
||||
});
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -40,4 +133,50 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.ppt-dialog-footer{
|
||||
padding-top: 20px;
|
||||
text-align: right;
|
||||
}
|
||||
.ppt-dialog-content{
|
||||
height: 500px;
|
||||
overflow: auto;
|
||||
.ppt-dialog-prog-wrap{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
.ppt-dialog-cover-wrap{
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-around;
|
||||
.ppt-dialog-cover-item{
|
||||
margin-bottom: 10px;
|
||||
border: 10px solid #ccc;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
img{
|
||||
width: 200px;
|
||||
}
|
||||
.icon-select{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.active-mode{
|
||||
border: 10px solid #5e24d0;
|
||||
position: relative;
|
||||
.icon-select{
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
color: #fff;
|
||||
background: #5e24d0;
|
||||
border-radius: 5px;
|
||||
display: block!important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,282 +0,0 @@
|
|||
<template>
|
||||
<el-dialog v-model="isDialog" :show-close="false" width="800" destroy-on-close>
|
||||
<template #header>
|
||||
<div class="custom-header flex">
|
||||
<span>{{ item.name }}</span>
|
||||
<i class="iconfont icon-guanbi" @click="isDialog = false"></i>
|
||||
</div>
|
||||
</template>
|
||||
<div class="dialog-content">
|
||||
<el-scrollbar height="400px">
|
||||
<div class="chart-con flex">
|
||||
<template v-for="item in msgList">
|
||||
<div class="flex-end flex" v-if="item.type == 'user'">
|
||||
<div class="chart-item user">{{ item.msg }}</div>
|
||||
</div>
|
||||
<div class="flex-start flex" v-else>
|
||||
<div class="flex" v-loading="!item.msg">
|
||||
<div class="chart-item robot">{{ item.msg }}</div>
|
||||
</div>
|
||||
<div class="flex flex-end replace-item">
|
||||
<span @click="saveAdjust(item)"><i class="iconfont icon-tihuan"></i>替换分析结果</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="loaded" class="chart-loading">
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
<div class="input-box flex">
|
||||
<el-input v-model="textarea" @keyup.enter="send" :disabled="loaded" />
|
||||
<div class="ipt-icon" @click="send">
|
||||
<i class="iconfont icon-fasong"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { completion } from '@/api/mode/index'
|
||||
import { dataSetJson } from '@/utils/comm.js'
|
||||
import emitter from '@/utils/mitt';
|
||||
import { sessionStore } from '@/utils/store'
|
||||
import { sendChart } from '@/api/ai/index'
|
||||
|
||||
const textarea = ref('')
|
||||
|
||||
const isDialog = defineModel()
|
||||
|
||||
const props = defineProps({
|
||||
item: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return { name: '11' }
|
||||
}
|
||||
},
|
||||
curMode:{
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
conversation_id: {
|
||||
type: [Number, String],
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['saveEdit'])
|
||||
|
||||
const loaded = ref(false)
|
||||
|
||||
const msgList = ref([])
|
||||
|
||||
const send = () => {
|
||||
if (loaded.value) return
|
||||
msgList.value.push({
|
||||
type: 'user',
|
||||
msg: textarea.value
|
||||
})
|
||||
loaded.value = true
|
||||
getConversation(textarea.value)
|
||||
textarea.value = ''
|
||||
}
|
||||
const curNode = reactive({})
|
||||
|
||||
const params = reactive(
|
||||
{
|
||||
prompt: '',
|
||||
dataset_id: '',
|
||||
template: ''
|
||||
}
|
||||
)
|
||||
|
||||
// 大模型对话
|
||||
const getConversation = async (val) => {
|
||||
try {
|
||||
params.prompt = `按照${val}的要求,针对${curNode.edustage}${curNode.edusubject}课标,对${curNode.itemtitle}进行教学分析`
|
||||
params.template = props.item.prompt
|
||||
|
||||
let data = null;
|
||||
// 教学大模型
|
||||
if(props.curMode == 1){
|
||||
const res = await sendChart({
|
||||
content: params.prompt,
|
||||
conversationId: props.conversation_id,
|
||||
stream: false
|
||||
})
|
||||
data = res.data
|
||||
}
|
||||
else{
|
||||
// 知识库模型
|
||||
const res = await completion(params)
|
||||
data = res.data
|
||||
}
|
||||
|
||||
msgList.value.push({
|
||||
type: 'robot',
|
||||
msg: data.answer,
|
||||
})
|
||||
} finally {
|
||||
loaded.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const saveAdjust = (item) => {
|
||||
isDialog.value = false
|
||||
emitter.emit('onSaveAdjust', item.msg)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
let data = sessionStore.get('subject.curNode')
|
||||
Object.assign(curNode, data);
|
||||
// 框架设计 用课标的dataset_id
|
||||
let jsonKey = `课标-${data.edustage}-${data.edusubject}`
|
||||
params.dataset_id = dataSetJson[jsonKey]
|
||||
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.custom-header {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.icon-guanbi {
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 20px;
|
||||
|
||||
.chart-con {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
|
||||
.flex-end {
|
||||
width: 100%;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.flex-start {
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
flex-direction: column;
|
||||
|
||||
}
|
||||
|
||||
.chart-item {
|
||||
border-radius: 5px;
|
||||
padding: 5px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.user {
|
||||
background: #F2F2F2;
|
||||
margin-bottom: 10px;
|
||||
|
||||
}
|
||||
|
||||
.robot {
|
||||
background: #409EFF;
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
.replace-item {
|
||||
font-size: 12px;
|
||||
color: #409EFF;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.input-box {
|
||||
position: relative;
|
||||
|
||||
.ipt-icon {
|
||||
cursor: pointer;
|
||||
padding: 0 5px;
|
||||
|
||||
.icon-fasong {
|
||||
font-size: 26px;
|
||||
color: #409EFF;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.chart-loading,
|
||||
.chart-loading>div {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.chart-loading {
|
||||
display: block;
|
||||
font-size: 0;
|
||||
color: #66b1ff;
|
||||
}
|
||||
|
||||
.chart-loading.la-dark {
|
||||
color: #66b1ff;
|
||||
}
|
||||
|
||||
.chart-loading>div {
|
||||
display: inline-block;
|
||||
float: none;
|
||||
background-color: currentColor;
|
||||
border: 0 solid currentColor;
|
||||
}
|
||||
|
||||
.chart-loading {
|
||||
width: 54px;
|
||||
height: 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.chart-loading>div:nth-child(1) {
|
||||
animation-delay: -200ms;
|
||||
}
|
||||
|
||||
.chart-loading>div:nth-child(2) {
|
||||
animation-delay: -100ms;
|
||||
}
|
||||
|
||||
.chart-loading>div:nth-child(3) {
|
||||
animation-delay: 0ms;
|
||||
}
|
||||
|
||||
.chart-loading>div {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 100%;
|
||||
margin-right: 4px;
|
||||
animation: ball-pulse 1s ease infinite;
|
||||
}
|
||||
|
||||
@keyframes ball-pulse {
|
||||
|
||||
0%,
|
||||
60%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
30% {
|
||||
opacity: 0.1;
|
||||
transform: scale(0.01);
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -9,14 +9,10 @@
|
|||
<el-button type="primary" @click="createAi">
|
||||
<i class="iconfont icon-chuangzuo"></i>生成教学大纲
|
||||
</el-button>
|
||||
<el-button type="danger" :disabled="curItem.parentId" @click="delAnswer">
|
||||
<el-button type="danger" :disabled="!!curItem.parentId" @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 class="center-con" v-loading="loading">
|
||||
|
@ -55,7 +51,7 @@ import EditDialog from './edit-dialog.vue'
|
|||
import emitter from '@/utils/mitt'
|
||||
import * as commUtils from '@/utils/comm.js'
|
||||
import { createChart, sendChart } from '@/api/ai/index'
|
||||
import { completion, addSyllabus, syllabuss, removeSyllabus, editSyllabus } from '@/api/mode/index.js'
|
||||
import { completion, addSyllabus, removeSyllabus, editSyllabus } from '@/api/mode/index.js'
|
||||
import { createOutlineV2 } from '@/utils/ppt-request.js'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import { cloneDeep } from 'lodash'
|
||||
|
@ -85,17 +81,15 @@ emitter.on('selected', (data) => {
|
|||
// 回显大纲
|
||||
const curItem = reactive({})
|
||||
emitter.on('onShow', (data) => {
|
||||
console.log(data)
|
||||
aiShow.value = false
|
||||
Object.assign(answer, JSON.parse(data.outline))
|
||||
|
||||
|
||||
Object.assign(curItem, data)
|
||||
emitter.emit('onResult',data)
|
||||
curItem.outline = JSON.parse(curItem.outline)
|
||||
emitter.emit('onResult',curItem)
|
||||
})
|
||||
|
||||
|
||||
|
||||
const params = reactive(
|
||||
{
|
||||
prompt: '',
|
||||
|
@ -114,7 +108,7 @@ const createAi = async () => {
|
|||
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] + '版'
|
||||
loading.value = true
|
||||
aiShow.value = true
|
||||
|
@ -140,9 +134,10 @@ const createAi = async () => {
|
|||
data = res.data
|
||||
}
|
||||
const res = await createOutlineV2({ query: data.answer })
|
||||
console.log(res)
|
||||
emitter.emit('onResult', res)
|
||||
|
||||
Object.assign(answer, res.outline)
|
||||
curItem.outline = res.outline
|
||||
emitter.emit('onResult', curItem)
|
||||
onSaveTemp(JSON.stringify(res.outline))
|
||||
} finally {
|
||||
loading.value = false
|
||||
|
@ -182,6 +177,8 @@ emitter.on('editItem', (item) =>{
|
|||
loading.value = true
|
||||
|
||||
editSyllabus(data).then( res =>{
|
||||
curItem.outline = answer
|
||||
emitter.emit('onResult', curItem)
|
||||
ElMessage.success('操作成功')
|
||||
}).finally( ()=>{
|
||||
loading.value = false
|
||||
|
@ -221,7 +218,7 @@ const delAnswer = () => {
|
|||
answer.value = ''
|
||||
emitter.emit('resetSelect')
|
||||
})
|
||||
.catch(() => { })
|
||||
.catch(() => {})
|
||||
|
||||
}
|
||||
|
||||
|
@ -301,4 +298,5 @@ onMounted(() => {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
|
@ -1,159 +0,0 @@
|
|||
<template>
|
||||
<el-dialog v-model="mode" :show-close="false" width="600" append-to-body destroy-on-close>
|
||||
<template #header>
|
||||
<div class="custom-header flex">
|
||||
<span>{{ item.ex3 == '1' ? '请输入新的模板名称' : item.isAdd ? '添加提示词' : '编辑提示词' }}</span>
|
||||
<i class="iconfont icon-guanbi" @click="mode = false"></i>
|
||||
</div>
|
||||
</template>
|
||||
<div class="dialog-content" v-loading="loading">
|
||||
<p class="small-tip" v-if="item && item.ex3 == '1'">*当前模板为系统预设,不支持直接操作。需要复制一份为自己的然后再操作</p>
|
||||
<el-form :model="form" label-width="auto">
|
||||
<el-form-item label="名称">
|
||||
<el-input v-model="form.name" />
|
||||
</el-form-item>
|
||||
<el-form-item label="提示词" v-if="item.ex3 == '1' ? false : true">
|
||||
<el-input v-model="form.prompt" type="textarea" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="mode = false">取消</el-button>
|
||||
<el-button type="primary" @click="saveAdd">
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, watch } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import emitter from '@/utils/mitt';
|
||||
import { addKeyWords, addChildTemp, editChildTemp } from '@/api/mode/index'
|
||||
|
||||
const mode = defineModel()
|
||||
const props = defineProps({
|
||||
modeType: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
item: { // 当前操作的模板
|
||||
type: Object,
|
||||
default: () => {
|
||||
return { ex3: '' }
|
||||
}
|
||||
},
|
||||
|
||||
})
|
||||
|
||||
const form = reactive({
|
||||
name: '',
|
||||
prompt: '',
|
||||
})
|
||||
|
||||
|
||||
watch(() => mode.value, (newVal) => {
|
||||
if(newVal){
|
||||
if (props.item.isAdd) {
|
||||
form.name = ''
|
||||
form.prompt = ''
|
||||
}
|
||||
else{
|
||||
form.name = props.item?.name
|
||||
form.prompt = props.item?.prompt
|
||||
|
||||
}
|
||||
}
|
||||
},{ deep: true})
|
||||
|
||||
const loading = ref(false)
|
||||
const saveAdd = async () => {
|
||||
loading.value = true
|
||||
|
||||
if (props.item.ex3 == '1') {
|
||||
let id; // id 为主模板id
|
||||
if (props.item.isAdd) {
|
||||
id = props.item.id
|
||||
}
|
||||
else{
|
||||
// 编辑状态下 item 为子模板 主模板则是item.parentId
|
||||
id = props.item.parentId
|
||||
}
|
||||
try {
|
||||
// 系统预设模板 copy一份
|
||||
const { msg } = await addKeyWords({ name: form.name, id })
|
||||
emitter.emit('onGetMain', props.item)
|
||||
ElMessage.success(msg)
|
||||
mode.value = false
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
} else {
|
||||
if (props.item.isAdd) {
|
||||
onAddChildTemp(props.item.id)
|
||||
}
|
||||
else {
|
||||
try {
|
||||
let data = JSON.parse(JSON.stringify(props.item))
|
||||
data.name = form.name;
|
||||
data.prompt = form.prompt
|
||||
const { msg } = await editChildTemp(data)
|
||||
emitter.emit('onGetChild', data )
|
||||
ElMessage.success(msg)
|
||||
mode.value = false
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 添加子模板
|
||||
const onAddChildTemp = async (parentId) => {
|
||||
// 添加子模板
|
||||
let obj = {
|
||||
name: form.name,
|
||||
type: 2, // 子模板 固定值为2
|
||||
sortNum: 1,
|
||||
parentId,
|
||||
lmType: 1,
|
||||
model: props.modeType,
|
||||
prompt: form.prompt,
|
||||
ex1: props.item.ex1, //学段
|
||||
ex2: props.item.ex2, // 学科
|
||||
ex3: '', //是否系统预设 这里默认空
|
||||
}
|
||||
try {
|
||||
var { msg } = await addChildTemp(obj)
|
||||
emitter.emit('onGetChild')
|
||||
ElMessage.success(msg)
|
||||
mode.value = false
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.custom-header {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.icon-guanbi {
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.small-tip {
|
||||
text-align: left;
|
||||
font-size: 12px;
|
||||
margin-bottom: 15px;
|
||||
color: #F56C6C;
|
||||
}
|
||||
</style>
|
|
@ -1,193 +1,394 @@
|
|||
<template>
|
||||
<div class="container-left flex">
|
||||
<div class="left-header flex">教学模式</div>
|
||||
<div class="left-con" v-loading="loading">
|
||||
<el-empty v-if="!(tempList.length)" description="暂无数据" />
|
||||
<div class="con-item" v-for="item in tempList" :key="item.id" :class=" actId == item.id ? 'item-act' : ''">
|
||||
<div class="item-header flex">
|
||||
<span>{{ item.name }}</span>
|
||||
<el-button type="primary" link @click="onSelect(item)">选择模式</el-button>
|
||||
</div>
|
||||
<div class="content-list">
|
||||
<div class="item-list flex" >
|
||||
<el-card class="item-card" shadow="never" v-for="el in item.child" :key="el.id">
|
||||
<p class="card-name">
|
||||
<el-text line-clamp="1" :title="el.name">
|
||||
{{ el.name }}
|
||||
</el-text>
|
||||
</p>
|
||||
<div class="card-text">
|
||||
<el-text line-clamp="4" :title="el.prompt">
|
||||
{{ el.prompt }}
|
||||
</el-text>
|
||||
</div>
|
||||
</el-card>
|
||||
<div class="container-left flex" v-loading="loading">
|
||||
<div class="left-header flex">
|
||||
<span>教学模式</span>
|
||||
<div>
|
||||
<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"></i>新增</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="left-list">
|
||||
<div class="item" v-for="item in templateList" :key="item.id">
|
||||
<div class="item-name flex" @mouseenter="item.isAdd = true" @mouseleave="item.isAdd = false"
|
||||
@click="toggleParent(item)">
|
||||
<div class="flex">
|
||||
<span>{{ item.name }}</span>
|
||||
<!--个人教学模式才会有添加、编辑-->
|
||||
<div v-if="!item.ex3" class="ml-3">
|
||||
<el-button type="primary" link @click.stop="addModeChild(item)">添加</el-button>
|
||||
<el-button type="primary" link @click.stop="editMode(item)">编辑</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<!--加号 数鼠标悬浮 显示-->
|
||||
<i v-show="item.isAdd && !item.selected" class="iconfont icon-jiahao"></i>
|
||||
<!--减号 选中之后显示-->
|
||||
<i v-show="item.selected" class="iconfont icon-zuixiaohua"></i>
|
||||
</div>
|
||||
<div class="item-child flex" :class="child.selected ? 'act-child' : ''" v-for="child in item.children"
|
||||
:key="child.id" @mouseenter="child.isAdd = true" @mouseleave="child.isAdd = false"
|
||||
@click="toggleChild(item, child)">
|
||||
<div>
|
||||
<span>{{ child.name }}</span>
|
||||
<!--个人教学模式才会有编辑-->
|
||||
<el-button v-if="!child.ex3" class="ml-3" type="primary" link @click.stop="editMode(child)">编辑</el-button>
|
||||
</div>
|
||||
<i v-show="child.isAdd && !child.selected" class="iconfont icon-jiahao"></i>
|
||||
<i v-show="child.selected" class="iconfont icon-zuixiaohua"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--弹窗-->
|
||||
<el-dialog v-model="addVisible" append-to-body :show-close="false" width="550" :before-close="handleBeforeClose"
|
||||
style="border-radius: 10px; padding: 10px 15px">
|
||||
<template #header>
|
||||
<div class="mode-dialog-header flex">
|
||||
<span>{{ addChild ? '教学环节' : '教学模式' }}</span>
|
||||
<i class="iconfont icon-guanbi" @click="addVisible = false"></i>
|
||||
</div>
|
||||
</template>
|
||||
<el-form ref="ruleFormRef" style="max-width: 600px" :model="ruleForm" :rules="rules" label-width="auto"
|
||||
class="demo-ruleForm">
|
||||
<el-form-item :label="`教学${addChild ? '环节' : '模式'}名称`" prop="name">
|
||||
<div class="flex" style="width: 100%">
|
||||
<el-input v-model="ruleForm.name" />
|
||||
<el-button v-if="isEdit" link type="danger" class="ml-5 mr-3" @click="onDel">删除</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="说明" v-if="addChild" prop="prompt">
|
||||
<el-input v-model="ruleForm.prompt" type="textarea" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="mt-10 form-btn">
|
||||
<el-button @click="closeDialog">关闭</el-button>
|
||||
<el-button type="primary" @click="onSubmit(ruleFormRef)">保存</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, onUnmounted } from 'vue';
|
||||
import emitter from '@/utils/mitt';
|
||||
import { ref, reactive, onMounted, onUnmounted } from 'vue'
|
||||
import { modelList } from '@/api/mode/index'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import { sessionStore } from '@/utils/store'
|
||||
import emitter from '@/utils/mitt'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { addChildTemp, editChildTemp, removeChildTemp, syllabusList } from '@/api/mode'
|
||||
import { cloneDeep } from 'lodash'
|
||||
|
||||
const { user } = useUserStore()
|
||||
|
||||
// 获取模板
|
||||
let list = ref([])
|
||||
const getTemplate = async (id) => {
|
||||
const { rows } = await modelList({ createUser: user.userId, model: 4, type: 1, pageNum: 1, pageSize: 10000})
|
||||
list.value = rows
|
||||
if(list.value.length){
|
||||
getChildTemp(id)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取子模板
|
||||
const actId = ref('')
|
||||
const loading = ref(false)
|
||||
const tempList = ref([])
|
||||
const getChildTemp = async (parentId) => {
|
||||
tempList.value.length = 0
|
||||
const templateList = ref([])
|
||||
const getTemplate = async () => {
|
||||
loading.value = true
|
||||
for (let item of list.value) {
|
||||
try {
|
||||
const { rows } = await modelList({ model: 4, type: 2, parentId: item.id })
|
||||
tempList.value.push({
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
child: rows
|
||||
})
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
actId.value = tempList.value[0].id
|
||||
}
|
||||
if(parentId){
|
||||
const item = tempList.value.find(item => item.id == parentId)
|
||||
emitter.emit('changeMode', item)
|
||||
}
|
||||
else{
|
||||
emitter.emit('changeMode', tempList.value[0])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 操作之后获取子模板
|
||||
emitter.on('onGetChild', async (data) => {
|
||||
|
||||
await getTemplate(data.parentId)
|
||||
|
||||
})
|
||||
// 操作之后获取主模板
|
||||
emitter.on('onGetMain', (item) => {
|
||||
getTemplate(item.parentId)
|
||||
})
|
||||
|
||||
// 选择模板
|
||||
const emit = defineEmits([''])
|
||||
const onSelect = (item) =>{
|
||||
actId.value = item.id
|
||||
item.child.forEach(el =>{
|
||||
el.aiShow = false
|
||||
const { rows } = await modelList({
|
||||
createUser: user.userId,
|
||||
model: 4,
|
||||
pageNum: 1,
|
||||
pageSize: 10000
|
||||
})
|
||||
emitter.emit('changeMode', item)
|
||||
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()
|
||||
}
|
||||
|
||||
// 查询生成大纲记录
|
||||
const getSyllabus = async () => {
|
||||
const { rows } = await syllabusList({
|
||||
createUserId: user.userId,
|
||||
eduId: curNode.id,
|
||||
sourceType: 1,
|
||||
pageSize: 1,
|
||||
orderByColumn: 'createTime',
|
||||
isAsc: 'desc'
|
||||
})
|
||||
if (rows && rows.length) {
|
||||
const idsAry = rows
|
||||
.at(-1)
|
||||
.modelIds.split(',')
|
||||
.map((item) => Number(item))
|
||||
// 设置选中
|
||||
let ary = []
|
||||
templateList.value.forEach((parent) => {
|
||||
parent.children.forEach((child) => {
|
||||
child.selected = idsAry.includes(child.id)
|
||||
if (child.selected) {
|
||||
ary.push(child)
|
||||
}
|
||||
})
|
||||
// 更新父项的 selected 状态
|
||||
parent.selected = parent.children.every((child) => child.selected)
|
||||
})
|
||||
// 回显大纲数据
|
||||
emitter.emit('onShow', rows.at(-1))
|
||||
emitter.emit('selected', ary)
|
||||
}
|
||||
}
|
||||
|
||||
// 重置选中
|
||||
const resetSelect = () => {
|
||||
templateList.value.forEach((item) => {
|
||||
item.selected = false
|
||||
item.children.forEach((el) => {
|
||||
el.selected = false
|
||||
})
|
||||
})
|
||||
emitter.emit('selected', [])
|
||||
}
|
||||
|
||||
emitter.on('resetSelect', () => {
|
||||
resetSelect()
|
||||
})
|
||||
|
||||
// 点击教学模式
|
||||
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 toggleChild = (parent, child) => {
|
||||
child.selected = !child.selected
|
||||
updateParentSelection(parent)
|
||||
const selectedData = templateList.value
|
||||
.map((item) => item.children.filter((child) => child.selected))
|
||||
.flat()
|
||||
emitter.emit('selected', selectedData)
|
||||
}
|
||||
|
||||
// 检查父项(教学模式)的所有子项(教学环节)是否都被选中,如果是,则设置父项为选中状态,否则取消选中
|
||||
const updateParentSelection = (parent) => {
|
||||
parent.selected = parent.children.every((child) => child.selected)
|
||||
}
|
||||
|
||||
// 弹窗
|
||||
const addVisible = ref(false)
|
||||
|
||||
const ruleFormRef = ref()
|
||||
const rules = reactive({
|
||||
name: [{ required: true, message: '不能为空', trigger: 'blur' }]
|
||||
})
|
||||
const ruleForm = reactive({
|
||||
name: '',
|
||||
prompt: ''
|
||||
})
|
||||
// 提交
|
||||
const onSubmit = async (formEl) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate(async (valid, fields) => {
|
||||
if (valid) {
|
||||
// 修改
|
||||
if (isEdit.value) {
|
||||
let data = cloneDeep(curEditItem)
|
||||
data.name = ruleForm.name
|
||||
await editChildTemp(data)
|
||||
}
|
||||
// 新增
|
||||
else {
|
||||
let obj = {
|
||||
ex1: curNode.edustage,
|
||||
ex2: curNode.edusubject,
|
||||
model: 4,
|
||||
name: ruleForm.name,
|
||||
sortNum: 1,
|
||||
type: 1
|
||||
}
|
||||
// 新增教学环节
|
||||
if (addChild.value) {
|
||||
obj.parentId = curEditItem.id
|
||||
obj.prompt = ruleForm.prompt
|
||||
obj.type = 2
|
||||
}
|
||||
await addChildTemp(obj)
|
||||
}
|
||||
ElMessage.success('操作成功')
|
||||
resetForm()
|
||||
addVisible.value = false
|
||||
getTemplate()
|
||||
} else {
|
||||
console.log('error submit!', fields)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 是否编辑
|
||||
const isEdit = ref(false)
|
||||
// 区分是新增教学模式false 还是现在教学环节true
|
||||
const addChild = ref(false)
|
||||
|
||||
const curEditItem = reactive({})
|
||||
const addModeChild = (item) => {
|
||||
isEdit.value = false
|
||||
Object.assign(curEditItem, item)
|
||||
addChild.value = true
|
||||
addVisible.value = true
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
const editMode = (item) => {
|
||||
isEdit.value = true
|
||||
addChild.value = false
|
||||
Object.assign(curEditItem, item)
|
||||
ruleForm.name = item.name
|
||||
addVisible.value = true
|
||||
}
|
||||
|
||||
// 删除 教学模式 教学环节
|
||||
const onDel = () => {
|
||||
ElMessageBox.confirm('确定要删除模板吗?', '温馨提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(async () => {
|
||||
await removeChildTemp(curEditItem.id)
|
||||
ElMessage.success('操作成功')
|
||||
resetForm()
|
||||
addVisible.value = false
|
||||
getTemplate()
|
||||
})
|
||||
.catch(() => { })
|
||||
}
|
||||
|
||||
const closeDialog = () => {
|
||||
handleBeforeClose(() => (addVisible.value = false))
|
||||
}
|
||||
|
||||
const handleBeforeClose = (done) => {
|
||||
resetForm()
|
||||
done()
|
||||
}
|
||||
const resetForm = () => {
|
||||
if (ruleFormRef.value) {
|
||||
ruleFormRef.value.resetFields()
|
||||
}
|
||||
}
|
||||
|
||||
const curNode = reactive({})
|
||||
onMounted(() => {
|
||||
let data = sessionStore.get('subject.curNode')
|
||||
Object.assign(curNode, data);
|
||||
Object.assign(curNode, data)
|
||||
getTemplate()
|
||||
})
|
||||
|
||||
|
||||
// 解绑
|
||||
onUnmounted(() => {
|
||||
|
||||
emitter.off('onGetMain');
|
||||
emitter.off('onGetChild');
|
||||
emitter.off('resetSelect')
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container-left {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 15px;
|
||||
flex-direction: column;
|
||||
|
||||
.left-header {
|
||||
height: 45px;
|
||||
background: #F6F6F6;
|
||||
border-radius: 5px 0 0 0;
|
||||
height: 32px;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
text-indent: 2em;
|
||||
|
||||
.icon-jiahao {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.left-con {
|
||||
.left-list {
|
||||
flex: 1;
|
||||
background: #fff;
|
||||
border-radius: 0 0 0 5px;
|
||||
padding: 15px;
|
||||
box-sizing: border-box;
|
||||
font-size: 14px;
|
||||
overflow: auto;
|
||||
.item-header {
|
||||
margin-top: 5px;
|
||||
background-color: #fff;
|
||||
border-radius: 5px;
|
||||
text-align: left;
|
||||
padding: 0 10px;
|
||||
line-height: 30px;
|
||||
overflow-y: auto;
|
||||
|
||||
.item-name {
|
||||
line-height: 40px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 5px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
.con-item {
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 10px;
|
||||
}
|
||||
.item-list{
|
||||
|
||||
padding: 10px;
|
||||
.item-child {
|
||||
padding-left: 3em;
|
||||
justify-content: space-between;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
padding-right: 10px;
|
||||
margin-bottom: 3px;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
border-radius: 50%;
|
||||
background-color: #666;
|
||||
position: absolute;
|
||||
left: 2em;
|
||||
top: 50%;
|
||||
transform: translate(0, -50%);
|
||||
}
|
||||
}
|
||||
.item-act{
|
||||
border: solid 1px #409eff;
|
||||
|
||||
.iconfont {
|
||||
font-weight: bold;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.icon-jiahao {
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.icon-zuixiaohua {
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.act-child {
|
||||
border-radius: 5px;
|
||||
}
|
||||
.item-card {
|
||||
width: 130px;
|
||||
font-size: 13px;
|
||||
padding: 10px;
|
||||
margin-right: 20px;
|
||||
flex-shrink: 0;
|
||||
border-radius: 10px;
|
||||
:deep(.el-card__body) {
|
||||
padding: 0 !important;
|
||||
}
|
||||
background: #eaf3ff;
|
||||
|
||||
.card-name {
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.card-text {
|
||||
text-align: left;
|
||||
|
||||
.el-text{
|
||||
font-size: 12px !important;
|
||||
}
|
||||
&::after {
|
||||
background-color: #409eff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.content-list{
|
||||
overflow-x: auto
|
||||
|
||||
.mode-dialog-header {
|
||||
justify-content: space-between;
|
||||
font-size: 15px;
|
||||
font-weight: bold;
|
||||
|
||||
.icon-guanbi {
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.content-list::-webkit-scrollbar {
|
||||
height: 8px;
|
||||
|
||||
.form-btn {
|
||||
text-align: right;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
|
@ -1,394 +0,0 @@
|
|||
<template>
|
||||
<div class="container-left flex" v-loading="loading">
|
||||
<div class="left-header flex">
|
||||
<span>教学模式</span>
|
||||
<div>
|
||||
<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"></i>新增</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="left-list">
|
||||
<div class="item" v-for="item in templateList" :key="item.id">
|
||||
<div class="item-name flex" @mouseenter="item.isAdd = true" @mouseleave="item.isAdd = false"
|
||||
@click="toggleParent(item)">
|
||||
<div class="flex">
|
||||
<span>{{ item.name }}</span>
|
||||
<!--个人教学模式才会有添加、编辑-->
|
||||
<div v-if="!item.ex3" class="ml-3">
|
||||
<el-button type="primary" link @click.stop="addModeChild(item)">添加</el-button>
|
||||
<el-button type="primary" link @click.stop="editMode(item)">编辑</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<!--加号 数鼠标悬浮 显示-->
|
||||
<i v-show="item.isAdd && !item.selected" class="iconfont icon-jiahao"></i>
|
||||
<!--减号 选中之后显示-->
|
||||
<i v-show="item.selected" class="iconfont icon-zuixiaohua"></i>
|
||||
</div>
|
||||
<div class="item-child flex" :class="child.selected ? 'act-child' : ''" v-for="child in item.children"
|
||||
:key="child.id" @mouseenter="child.isAdd = true" @mouseleave="child.isAdd = false"
|
||||
@click="toggleChild(item, child)">
|
||||
<div>
|
||||
<span>{{ child.name }}</span>
|
||||
<!--个人教学模式才会有编辑-->
|
||||
<el-button v-if="!child.ex3" class="ml-3" type="primary" link @click.stop="editMode(child)">编辑</el-button>
|
||||
</div>
|
||||
<i v-show="child.isAdd && !child.selected" class="iconfont icon-jiahao"></i>
|
||||
<i v-show="child.selected" class="iconfont icon-zuixiaohua"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--弹窗-->
|
||||
<el-dialog v-model="addVisible" append-to-body :show-close="false" width="550" :before-close="handleBeforeClose"
|
||||
style="border-radius: 10px; padding: 10px 15px">
|
||||
<template #header>
|
||||
<div class="mode-dialog-header flex">
|
||||
<span>{{ addChild ? '教学环节' : '教学模式' }}</span>
|
||||
<i class="iconfont icon-guanbi" @click="addVisible = false"></i>
|
||||
</div>
|
||||
</template>
|
||||
<el-form ref="ruleFormRef" style="max-width: 600px" :model="ruleForm" :rules="rules" label-width="auto"
|
||||
class="demo-ruleForm">
|
||||
<el-form-item :label="`教学${addChild ? '环节' : '模式'}名称`" prop="name">
|
||||
<div class="flex" style="width: 100%">
|
||||
<el-input v-model="ruleForm.name" />
|
||||
<el-button v-if="isEdit" link type="danger" class="ml-5 mr-3" @click="onDel">删除</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="说明" v-if="addChild" prop="prompt">
|
||||
<el-input v-model="ruleForm.prompt" type="textarea" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="mt-10 form-btn">
|
||||
<el-button @click="closeDialog">关闭</el-button>
|
||||
<el-button type="primary" @click="onSubmit(ruleFormRef)">保存</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, onUnmounted } from 'vue'
|
||||
import { modelList } from '@/api/mode/index'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import { sessionStore } from '@/utils/store'
|
||||
import emitter from '@/utils/mitt'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { addChildTemp, editChildTemp, removeChildTemp, syllabusList } from '@/api/mode'
|
||||
import { cloneDeep } from 'lodash'
|
||||
|
||||
const { user } = useUserStore()
|
||||
|
||||
// 获取模板
|
||||
const loading = ref(false)
|
||||
const templateList = ref([])
|
||||
const getTemplate = async () => {
|
||||
loading.value = true
|
||||
const { rows } = await modelList({
|
||||
createUser: user.userId,
|
||||
model: 4,
|
||||
pageNum: 1,
|
||||
pageSize: 10000
|
||||
})
|
||||
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()
|
||||
}
|
||||
|
||||
// 查询生成大纲记录
|
||||
const getSyllabus = async () => {
|
||||
const { rows } = await syllabusList({
|
||||
createUserId: user.userId,
|
||||
eduId: curNode.id,
|
||||
sourceType: 1,
|
||||
pageSize: 1,
|
||||
orderByColumn: 'createTime',
|
||||
isAsc: 'desc'
|
||||
})
|
||||
if (rows && rows.length) {
|
||||
const idsAry = rows
|
||||
.at(-1)
|
||||
.modelIds.split(',')
|
||||
.map((item) => Number(item))
|
||||
// 设置选中
|
||||
let ary = []
|
||||
templateList.value.forEach((parent) => {
|
||||
parent.children.forEach((child) => {
|
||||
child.selected = idsAry.includes(child.id)
|
||||
if (child.selected) {
|
||||
ary.push(child)
|
||||
}
|
||||
})
|
||||
// 更新父项的 selected 状态
|
||||
parent.selected = parent.children.every((child) => child.selected)
|
||||
})
|
||||
// 回显大纲数据
|
||||
emitter.emit('onShow', rows.at(-1))
|
||||
emitter.emit('selected', ary)
|
||||
}
|
||||
}
|
||||
|
||||
// 重置选中
|
||||
const resetSelect = () => {
|
||||
templateList.value.forEach((item) => {
|
||||
item.selected = false
|
||||
item.children.forEach((el) => {
|
||||
el.selected = false
|
||||
})
|
||||
})
|
||||
emitter.emit('selected', [])
|
||||
}
|
||||
|
||||
emitter.on('resetSelect', () => {
|
||||
resetSelect()
|
||||
})
|
||||
|
||||
// 点击教学模式
|
||||
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 toggleChild = (parent, child) => {
|
||||
child.selected = !child.selected
|
||||
updateParentSelection(parent)
|
||||
const selectedData = templateList.value
|
||||
.map((item) => item.children.filter((child) => child.selected))
|
||||
.flat()
|
||||
emitter.emit('selected', selectedData)
|
||||
}
|
||||
|
||||
// 检查父项(教学模式)的所有子项(教学环节)是否都被选中,如果是,则设置父项为选中状态,否则取消选中
|
||||
const updateParentSelection = (parent) => {
|
||||
parent.selected = parent.children.every((child) => child.selected)
|
||||
}
|
||||
|
||||
// 弹窗
|
||||
const addVisible = ref(false)
|
||||
|
||||
const ruleFormRef = ref()
|
||||
const rules = reactive({
|
||||
name: [{ required: true, message: '不能为空', trigger: 'blur' }]
|
||||
})
|
||||
const ruleForm = reactive({
|
||||
name: '',
|
||||
prompt: ''
|
||||
})
|
||||
// 提交
|
||||
const onSubmit = async (formEl) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate(async (valid, fields) => {
|
||||
if (valid) {
|
||||
// 修改
|
||||
if (isEdit.value) {
|
||||
let data = cloneDeep(curEditItem)
|
||||
data.name = ruleForm.name
|
||||
await editChildTemp(data)
|
||||
}
|
||||
// 新增
|
||||
else {
|
||||
let obj = {
|
||||
ex1: curNode.edustage,
|
||||
ex2: curNode.edusubject,
|
||||
model: 4,
|
||||
name: ruleForm.name,
|
||||
sortNum: 1,
|
||||
type: 1
|
||||
}
|
||||
// 新增教学环节
|
||||
if (addChild.value) {
|
||||
obj.parentId = curEditItem.id
|
||||
obj.prompt = ruleForm.prompt
|
||||
obj.type = 2
|
||||
}
|
||||
await addChildTemp(obj)
|
||||
}
|
||||
ElMessage.success('操作成功')
|
||||
resetForm()
|
||||
addVisible.value = false
|
||||
getTemplate()
|
||||
} else {
|
||||
console.log('error submit!', fields)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 是否编辑
|
||||
const isEdit = ref(false)
|
||||
// 区分是新增教学模式false 还是现在教学环节true
|
||||
const addChild = ref(false)
|
||||
|
||||
const curEditItem = reactive({})
|
||||
const addModeChild = (item) => {
|
||||
isEdit.value = false
|
||||
Object.assign(curEditItem, item)
|
||||
addChild.value = true
|
||||
addVisible.value = true
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
const editMode = (item) => {
|
||||
isEdit.value = true
|
||||
addChild.value = false
|
||||
Object.assign(curEditItem, item)
|
||||
ruleForm.name = item.name
|
||||
addVisible.value = true
|
||||
}
|
||||
|
||||
// 删除 教学模式 教学环节
|
||||
const onDel = () => {
|
||||
ElMessageBox.confirm('确定要删除模板吗?', '温馨提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
.then(async () => {
|
||||
await removeChildTemp(curEditItem.id)
|
||||
ElMessage.success('操作成功')
|
||||
resetForm()
|
||||
addVisible.value = false
|
||||
getTemplate()
|
||||
})
|
||||
.catch(() => { })
|
||||
}
|
||||
|
||||
const closeDialog = () => {
|
||||
handleBeforeClose(() => (addVisible.value = false))
|
||||
}
|
||||
|
||||
const handleBeforeClose = (done) => {
|
||||
resetForm()
|
||||
done()
|
||||
}
|
||||
const resetForm = () => {
|
||||
if (ruleFormRef.value) {
|
||||
ruleFormRef.value.resetFields()
|
||||
}
|
||||
}
|
||||
|
||||
const curNode = reactive({})
|
||||
onMounted(() => {
|
||||
let data = sessionStore.get('subject.curNode')
|
||||
Object.assign(curNode, data)
|
||||
getTemplate()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
emitter.off('resetSelect')
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container-left {
|
||||
height: 100%;
|
||||
font-size: 15px;
|
||||
flex-direction: column;
|
||||
|
||||
.left-header {
|
||||
height: 32px;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.icon-jiahao {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.left-list {
|
||||
flex: 1;
|
||||
margin-top: 5px;
|
||||
background-color: #fff;
|
||||
border-radius: 5px;
|
||||
text-align: left;
|
||||
padding: 0 10px;
|
||||
line-height: 30px;
|
||||
overflow-y: auto;
|
||||
|
||||
.item-name {
|
||||
line-height: 40px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
justify-content: space-between;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.item-child {
|
||||
padding-left: 3em;
|
||||
justify-content: space-between;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
padding-right: 10px;
|
||||
margin-bottom: 3px;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
border-radius: 50%;
|
||||
background-color: #666;
|
||||
position: absolute;
|
||||
left: 2em;
|
||||
top: 50%;
|
||||
transform: translate(0, -50%);
|
||||
}
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-weight: bold;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.icon-jiahao {
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.icon-zuixiaohua {
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.act-child {
|
||||
border-radius: 5px;
|
||||
background: #eaf3ff;
|
||||
|
||||
&::after {
|
||||
background-color: #409eff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mode-dialog-header {
|
||||
justify-content: space-between;
|
||||
font-size: 15px;
|
||||
font-weight: bold;
|
||||
|
||||
.icon-guanbi {
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.form-btn {
|
||||
text-align: right;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
<template>
|
||||
<el-dialog v-model="open" v-bind="dAttrs">
|
||||
<el-dialog class="aix-progress-dialog" v-model="open" v-bind="dAttrs">
|
||||
<el-progress type="dashboard" v-bind="$attrs.pg" />
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
@ -29,5 +29,10 @@ const dAttrs = computed(() => {
|
|||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
<style>
|
||||
.aix-progress-dialog .el-dialog__body{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
|
@ -1,107 +1,49 @@
|
|||
<template>
|
||||
<div class="container-right flex">
|
||||
<div class="right-header flex">
|
||||
<div class="header-left">
|
||||
<!-- <el-button type="primary" link>
|
||||
<i class="iconfont icon-jiahao"></i>新活动
|
||||
</el-button>
|
||||
<el-button type="primary" link>
|
||||
<i class="iconfont icon-baocun"></i>保存为教学模式
|
||||
</el-button> -->
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<el-select v-model="curMode" placeholder="Select" class="mr-4 w-30">
|
||||
<el-option v-for="item in modeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
<el-button type="primary" :disabled="!(resultList.length)" @click="getCompletion">一键研读</el-button>
|
||||
<el-button type="danger" @click="onCreate">生成PPT</el-button>
|
||||
<span>课件预览</span>
|
||||
<div>
|
||||
<el-button type="danger" @click="onCreate">一键生成</el-button>
|
||||
<el-button :disabled="!result?.parentId" @click="openAiPPT">编辑课件</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right-con flex" ref="listRef">
|
||||
<el-empty v-if="!(resultList.length)" description="暂无数据" />
|
||||
<div class="con-item flex" v-for="(item, index) in resultList" :key="item.id" v-loading="item.loading">
|
||||
<div class="item-top flex">
|
||||
<span>{{ item.name }}</span>
|
||||
<el-popover placement="bottom-end" trigger="hover" popper-class="template-custom-popover">
|
||||
<template #reference>
|
||||
<el-button link type="primary">
|
||||
<i class="iconfont icon-shenglvehao"></i></el-button>
|
||||
</template>
|
||||
<template #default>
|
||||
<el-button type="primary" link @click="editKeyWord(item, false)">编辑</el-button>
|
||||
<el-button type="primary" link @click="removeItem(item, true)">移除</el-button>
|
||||
</template>
|
||||
</el-popover>
|
||||
</div>
|
||||
<div class="item-bom">
|
||||
<div class="item-prompt">{{ item.prompt }}</div>
|
||||
<div class="item-answer" v-if="item.answer">
|
||||
<div class="answer-text">
|
||||
<TypingEffect v-if="isStarted[index]" :text="item.answer" :delay="10" :aiShow="item.aiShow"
|
||||
@complete="handleCompleteText($event, index)" @updateScroll="scrollToBottom($event, index)" />
|
||||
</div>
|
||||
<div class="item-btn flex">
|
||||
<el-button type="primary" link @click="againResult(index, item)">
|
||||
<i class="iconfont icon-ai1"></i>
|
||||
重新生成
|
||||
</el-button>
|
||||
<el-button type="primary" link @click="onAdjust(index, item)">
|
||||
<i class="iconfont icon-duihua"></i>
|
||||
AI对话调整
|
||||
</el-button>
|
||||
<el-button type="primary" link @click="onEdit(index, item)">
|
||||
<i class="iconfont icon-bianji1"></i>
|
||||
手动编辑结果
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="right-con">
|
||||
<el-empty v-if="!result?.parentId" description="请先生成教学大纲,再生成教学课件" />
|
||||
<div v-for="(item,index) in pptSlides" class="right-con-item">
|
||||
<div>{{index+1}}</div><img :src="item.fileurl">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<EditDialog v-model="isEdit" :item="curItem" />
|
||||
<AdjustDialog v-model="isAdjust" :item="curItem" :curMode="curMode" :conversation_id="conversation_id" />
|
||||
<PptDialog @add-success="addAiPPT" :dataList="resultList" v-model="pptDialog" />
|
||||
<PptDialog @close-dialogs="pptDialog = false" @add-success="addAiPPT" :dataList="result" v-model="pptDialog" />
|
||||
<progress-dialog v-model:visible="pgDialog.visible" v-bind="pgDialog" />
|
||||
<!--添加、编辑提示词-->
|
||||
<keywordDialog v-model="isWordDialog" :item="curItem" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted, reactive, nextTick } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { sessionStore } from '@/utils/store'
|
||||
import {ref, onUnmounted, onMounted, reactive} from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import emitter from '@/utils/mitt'
|
||||
import EditDialog from './edit-dialog.vue'
|
||||
import AdjustDialog from './adjust-dialog.vue'
|
||||
import progressDialog from './progress-dialog.vue'
|
||||
import { completion, tempResult, tempSave, removeChildTemp, editTempResult, modelList } from '@/api/mode/index.js'
|
||||
import { createChart, sendChart } from '@/api/ai/index'
|
||||
// import { dataSetJson } from '@/utils/comm.js'
|
||||
import PptDialog from "@/views/prepare/container/pptist-dialog.vue";
|
||||
import msgUtils from "@/plugins/modal";
|
||||
import {PPTXFileToJson} from "@/AixPPTist/src/hooks/useImport";
|
||||
import {slidesToImg} from "@/utils/ppt";
|
||||
import {getEntpcoursefile, listEntpcoursefileNew} from "@/api/education/entpcoursefile";
|
||||
import {sessionStore} from "@/utils/store";
|
||||
import * as API_smarttalk from "@/api/file";
|
||||
import * as API_entpcourse from "@/api/education/entpcourse";
|
||||
import * as API_entpcoursefile from "@/api/education/entpcoursefile";
|
||||
import * as commUtils from '@/utils/comm.js'
|
||||
import PptDialog from '@/views/prepare/container/pptist-dialog.vue'
|
||||
import keywordDialog from './keyword-dialog.vue'
|
||||
import TypingEffect from '@/components/typing-effect/index.vue'
|
||||
import { cloneDeep } from 'lodash'
|
||||
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import { PPTXFileToJson } from '@/AixPPTist/src/hooks/useImport' // ppt转json
|
||||
import * as API_entpcourse from '@/api/education/entpcourse' // 相关api
|
||||
import * as API_entpcoursefile from '@/api/education/entpcoursefile' // 相关api
|
||||
import * as Api_server from '@/api/apiService' // 相关api
|
||||
import * as API_smarttalk from '@/api/file' // 文件相关api
|
||||
import msgUtils from '@/plugins/modal'
|
||||
import { getEntpcoursefile } from '@/api/education/entpcoursefile'
|
||||
import { createWindow } from '@/utils/tool' // 消息工具
|
||||
import { slidesToImg } from '@/utils/ppt' // ppt相关工具
|
||||
|
||||
import {createWindow} from "@/utils/tool";
|
||||
import {editSyllabus} from "@/api/mode";
|
||||
import { getSmarttalkPage } from "@/api/file"
|
||||
import useUserStore from '@/store/modules/user'
|
||||
const userStore = useUserStore()
|
||||
const pptDialog = ref(false)
|
||||
const resultList = ref([])
|
||||
const result = ref(null)
|
||||
const courseObj = reactive({
|
||||
node: null, // 选择的课程节点
|
||||
})
|
||||
const curNode = reactive({})
|
||||
const pgDialog = reactive({ // 弹窗-进度条
|
||||
visible: false,
|
||||
title: 'PPT解析中...',
|
||||
|
@ -119,214 +61,27 @@ const pgDialog = reactive({ // 弹窗-进度条
|
|||
}
|
||||
})
|
||||
|
||||
const curMode = ref(2)
|
||||
const modeOptions = ref([
|
||||
{
|
||||
label: '教学大模型',
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
label: '知识库模型',
|
||||
value: 2
|
||||
}
|
||||
])
|
||||
const pptSlides = ref([])
|
||||
|
||||
emitter.on('changeMode', (item) => {
|
||||
resultList.value = item.child
|
||||
getTempResult(item.id)
|
||||
emitter.on('onResult', (data)=>{
|
||||
result.value = data
|
||||
if (!!result.value.parentId) {
|
||||
listEntpcoursefileNew({parentid: result.value.parentId}).then(res=>{
|
||||
pptSlides.value = res.rows
|
||||
})
|
||||
}else {
|
||||
pptSlides.value = []
|
||||
}
|
||||
})
|
||||
|
||||
const onCreate = () =>{
|
||||
let isAnswer = resultList.value.every(item => !item.answer)
|
||||
if(isAnswer){
|
||||
if(!result.value){
|
||||
ElMessage.warning('请先进行研读')
|
||||
return
|
||||
}
|
||||
pptDialog.value = true
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 一键研读
|
||||
const getCompletion = async () => {
|
||||
isStarted.value = new Array(resultList.length).fill(false)
|
||||
isStarted.value[0] = true
|
||||
|
||||
resultList.value.forEach(item => {
|
||||
if (item.answer) {
|
||||
item.answer = ''
|
||||
}
|
||||
})
|
||||
for (let item of resultList.value) {
|
||||
|
||||
try {
|
||||
item.loading = true
|
||||
item.aiShow = true
|
||||
|
||||
let str = cloneDeep(prompt.value)
|
||||
str = str.replace(/{模板名称}/g, item.name)
|
||||
params.prompt = str
|
||||
params.template = item.prompt
|
||||
|
||||
// 教学大模型
|
||||
let data = null
|
||||
if (curMode.value == 1) {
|
||||
const res = await sendChart({
|
||||
content: params.prompt,
|
||||
conversationId: conversation_id.value,
|
||||
stream: false
|
||||
})
|
||||
data = res.data
|
||||
}
|
||||
// 知识库模型
|
||||
else {
|
||||
const res = await completion(params)
|
||||
data = res.data
|
||||
}
|
||||
|
||||
item.answer = getResult(data.answer)
|
||||
onSaveTemp(item)
|
||||
} finally {
|
||||
item.loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleCompleteText = async (answer, index) => {
|
||||
if (index < resultList.value.length - 1) {
|
||||
isStarted.value[index + 1] = true; // 开始显示下一个文本
|
||||
}
|
||||
if (isAgain.value) {
|
||||
try {
|
||||
await editTempResult({ id: resultList.value[index].resultId, content: answer })
|
||||
} finally {
|
||||
isAgain.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 保存模板
|
||||
const onSaveTemp = async (item) => {
|
||||
if (item.answer == '') return
|
||||
|
||||
const data = {
|
||||
mainModelId: item.parentId,
|
||||
modelId: item.id,
|
||||
examDocld: '',
|
||||
content: item.answer,
|
||||
ex1: curNode.id
|
||||
}
|
||||
const res = await tempSave(data)
|
||||
|
||||
if(!item.resultId){
|
||||
item.resultId = res.data
|
||||
}
|
||||
}
|
||||
|
||||
const isWordDialog = ref(false)
|
||||
const editKeyWord = (item, val) => {
|
||||
/**
|
||||
* isAdd: 子模板中的移除 为编辑false 头部删除 添加提示词为新增 true
|
||||
*/
|
||||
Object.assign(curItem, item)
|
||||
curItem.isAdd = val
|
||||
isWordDialog.value = true
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 移除模板
|
||||
const removeItem = async (item, isChild) => {
|
||||
/**
|
||||
* item: 当前操作的模板
|
||||
* isChild: 子模板中的移除为 true
|
||||
*/
|
||||
if (item.ex3 != '1') {
|
||||
ElMessageBox.confirm(
|
||||
'确认是否移除?',
|
||||
'提示',
|
||||
{
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}
|
||||
).then(() => {
|
||||
removeChildTemp(item.id).then(res => {
|
||||
ElMessage.success('操作成功')
|
||||
if (isChild) {
|
||||
// 获取子模板
|
||||
emitter.emit('onGetChild', item)
|
||||
}
|
||||
else {
|
||||
// 获取主模板
|
||||
// getTemplateList()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
else {
|
||||
// editKeyWord(item, !isChild)
|
||||
}
|
||||
}
|
||||
const listRef = ref()
|
||||
// 查询模板结果
|
||||
const isStarted = ref([]);
|
||||
const getTempResult = (id) => {
|
||||
tempResult({ mainModelId: id, pageNum: 1, pageSize: 10000, ex1: curNode.id }).then(res => {
|
||||
let rows = res.rows
|
||||
if (rows.length > 0) {
|
||||
isStarted.value = new Array(rows.length).fill(true)
|
||||
resultList.value.forEach(item => {
|
||||
rows.forEach(el => {
|
||||
if (item.id == el.modelId) {
|
||||
item.answer = getResult(el.content)
|
||||
item.resultId = el.id
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
const scrollToBottom = (height, index) => {
|
||||
|
||||
if (listRef.value) {
|
||||
let sum = 0
|
||||
let listDom = listRef.value.children
|
||||
|
||||
if (index == 0) {
|
||||
// 220 去掉头部
|
||||
let screenHeight = window.innerHeight - 220
|
||||
if (height > screenHeight) {
|
||||
listRef.value.scrollTop = (height - screenHeight + 50)
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (let i = 0; i < index; i++) {
|
||||
sum += listDom[i].clientHeight
|
||||
}
|
||||
listRef.value.scrollTop = sum + height
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 去掉字符串中的 ### **
|
||||
let getResult = (str) => {
|
||||
let newStr = str.replace(/#+|(\*\*)/g, '');
|
||||
return newStr
|
||||
}
|
||||
|
||||
const params = reactive(
|
||||
{
|
||||
prompt: '',
|
||||
dataset_id: '',
|
||||
template: ''
|
||||
}
|
||||
)
|
||||
const prompt = ref('')
|
||||
|
||||
|
||||
const addAiPPT = async (res) => {
|
||||
// res = { url: 'https://bjcdn.openstorage.cn/xinghuo-privatedata/%2Ftmp/apiTempFileba724e0344f74e1480535eedf3ebec661601807661085006275/%E9%87%91%E9%A9%AC%E5%A5%96%E5%B0%B4%E5%B0%AC%E4%BA%8B%E4%BB%B6%E5%88%86%E6%9E%90%E4%B8%8E%E5%BA%94%E5%AF%B9%E7%AD%96%E7%95%A5.pptx' }
|
||||
let node = courseObj.node
|
||||
|
@ -373,6 +128,10 @@ const addAiPPT = async (res) => {
|
|||
if (res_3 && res_3.code == 200) {
|
||||
msgUtils.msgSuccess('生成PPT课件成功')
|
||||
//TODO 打开生成的课件
|
||||
updateGen(parentid)
|
||||
listEntpcoursefileNew({parentid: parentid}).then(res=>{
|
||||
pptSlides.value = res.rows
|
||||
})
|
||||
const res = await getEntpcoursefile(parentid)
|
||||
if (res && res.code === 200) {
|
||||
openPublicScreen('edit', res.data, smarttalk.resData) // 打开公屏-窗口
|
||||
|
@ -384,7 +143,25 @@ const addAiPPT = async (res) => {
|
|||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}).finally(()=>{
|
||||
pgDialog.visible = false
|
||||
})
|
||||
}
|
||||
|
||||
const openAiPPT = async () =>{
|
||||
let parentid = result.value.parentId
|
||||
const res = await getEntpcoursefile(parentid)
|
||||
if (res && res.code === 200) {
|
||||
const smarttalk = getSmarttalkPage({fileId: parentid})
|
||||
openPublicScreen('edit', res.data, smarttalk.resData) // 打开公屏-窗口
|
||||
} else {
|
||||
ElMessage.warning(res.msg||'文件获取异常!')
|
||||
}
|
||||
}
|
||||
|
||||
const updateGen = (parentid)=>{
|
||||
result.value.parentId = parentid
|
||||
editSyllabus(result.value)
|
||||
}
|
||||
|
||||
const openPublicScreen = (type, resource, currData)=> {
|
||||
|
@ -401,92 +178,50 @@ const openPublicScreen = (type, resource, currData)=> {
|
|||
}
|
||||
})
|
||||
}
|
||||
const isEdit = ref(false)
|
||||
// 当前操作的索引
|
||||
const curIndex = ref(-1)
|
||||
// 当前操作的item
|
||||
const curItem = reactive({})
|
||||
|
||||
// 重新生成
|
||||
const isAgain = ref(false)
|
||||
const againResult = async (index, item) => {
|
||||
isAgain.value = true
|
||||
isStarted.value[index] = false
|
||||
resultList.value[index].answer = ''
|
||||
if (index == 0) {
|
||||
listRef.value.scrollTop = 0
|
||||
|
||||
} else {
|
||||
scrollToBottom(50, index)
|
||||
}
|
||||
|
||||
try {
|
||||
await nextTick()
|
||||
resultList.value[index].loading = true
|
||||
item.aiShow = true
|
||||
|
||||
let str = cloneDeep(prompt.value)
|
||||
str = str.replace(/{模板名称}/g, item.name)
|
||||
params.prompt = str
|
||||
params.template = item.prompt
|
||||
|
||||
let data = null;
|
||||
// 教学大模型
|
||||
if (curMode.value == 1) {
|
||||
const res = await sendChart({
|
||||
content: params.prompt,
|
||||
conversationId: conversation_id.value,
|
||||
stream: false
|
||||
})
|
||||
data = res.data
|
||||
} else {
|
||||
// 知识库模型
|
||||
const res = await completion(params)
|
||||
data = res.data
|
||||
// 图片|音频|视频 转换为在线地址
|
||||
const toRousrceUrl = async (o) => {
|
||||
if (!!o.src) { // 如果有src就转换
|
||||
const isBase64 = /^data:image\/(\w+);base64,/.test(o.src)
|
||||
const isBlobUrl = /^blob:/.test(o.src)
|
||||
console.log('isBase64', o, isBase64)
|
||||
if (isBase64) {
|
||||
const bolb = commUtils.base64ToBlob(o.src)
|
||||
const fileName = Date.now() + '.png'
|
||||
const file = commUtils.blobToFile(bolb, fileName)
|
||||
// o.src = fileName
|
||||
// console.log('file', file)
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
const res = await Api_server.Other.uploadFile(formData)
|
||||
if (res && res.code == 200) {
|
||||
const url = res?.url
|
||||
url && (o.src = url)
|
||||
}
|
||||
} else if (isBlobUrl) { // 视频和音频
|
||||
const res = await fetch(o.src)
|
||||
const blob = await res.blob()
|
||||
const fileName = o.type == 'video' ? Date.now() + '.mp4' : Date.now() + '.mp3'
|
||||
const file = commUtils.blobToFile(blob, fileName)
|
||||
// o.src = fileName
|
||||
// console.log('file', file)
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
const ress = await Api_server.Other.uploadFile(formData)
|
||||
if (ress && ress.code == 200) {
|
||||
const url = ress?.url
|
||||
url && (o.src = url)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (o?.background?.image) await toRousrceUrl(o.background.image)
|
||||
if (o?.elements) {
|
||||
for (let element of o.elements) {
|
||||
await toRousrceUrl(element);
|
||||
}
|
||||
|
||||
resultList.value[index].answer = getResult(data.answer)
|
||||
isStarted.value[index] = true
|
||||
} finally {
|
||||
resultList.value[index].loading = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 对话调整
|
||||
const isAdjust = ref(false)
|
||||
const onAdjust = (index, item) => {
|
||||
curIndex.value = index
|
||||
Object.assign(curItem, item)
|
||||
isAdjust.value = true
|
||||
}
|
||||
|
||||
// 替换分析结果
|
||||
emitter.on('onSaveAdjust', (item) => {
|
||||
resultList.value[curIndex.value].answer = item
|
||||
onEditSave(resultList.value[curIndex.value])
|
||||
})
|
||||
|
||||
|
||||
// 保存 重新研读后的结果
|
||||
const onEditSave = async (item) => {
|
||||
const { msg } = await editTempResult({ id: item.resultId, content: item.answer })
|
||||
ElMessage.success(msg)
|
||||
getChildTemplate()
|
||||
}
|
||||
|
||||
// 编辑
|
||||
const onEdit = (index, item) => {
|
||||
curIndex.value = index
|
||||
Object.assign(curItem, item)
|
||||
isEdit.value = true
|
||||
}
|
||||
emitter.on('changeResult', (item) => {
|
||||
resultList.value[curIndex.value].answer = item
|
||||
})
|
||||
|
||||
// ======== zdg start ============
|
||||
// 统一HTTP处理
|
||||
const HTTP_SERVER_API = (type, params = {}) => {
|
||||
switch (type) {
|
||||
case 'addSmarttalk': { // 获取课程
|
||||
|
@ -564,214 +299,43 @@ const getDefParams = (params) => {
|
|||
}
|
||||
return Object.assign(def, params)
|
||||
}
|
||||
// 图片|音频|视频 转换为在线地址
|
||||
const toRousrceUrl = async (o) => {
|
||||
if (!!o.src) { // 如果有src就转换
|
||||
const isBase64 = /^data:image\/(\w+);base64,/.test(o.src)
|
||||
const isBlobUrl = /^blob:/.test(o.src)
|
||||
console.log('isBase64', o, isBase64)
|
||||
if (isBase64) {
|
||||
const bolb = commUtils.base64ToBlob(o.src)
|
||||
const fileName = Date.now() + '.png'
|
||||
const file = commUtils.blobToFile(bolb, fileName)
|
||||
// o.src = fileName
|
||||
// console.log('file', file)
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
const res = await Api_server.Other.uploadFile(formData)
|
||||
if (res && res.code == 200) {
|
||||
const url = res?.url
|
||||
url && (o.src = url)
|
||||
}
|
||||
} else if (isBlobUrl) { // 视频和音频
|
||||
const res = await fetch(o.src)
|
||||
const blob = await res.blob()
|
||||
const fileName = o.type == 'video' ? Date.now() + '.mp4' : Date.now() + '.mp3'
|
||||
const file = commUtils.blobToFile(blob, fileName)
|
||||
// o.src = fileName
|
||||
// console.log('file', file)
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
const ress = await Api_server.Other.uploadFile(formData)
|
||||
if (ress && ress.code == 200) {
|
||||
const url = ress?.url
|
||||
url && (o.src = url)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (o?.background?.image) await toRousrceUrl(o.background.image)
|
||||
if (o?.elements) {
|
||||
for (let element of o.elements) {
|
||||
await toRousrceUrl(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
// ======== zdg end ============
|
||||
|
||||
// 创建对话
|
||||
const conversation_id = ref('')
|
||||
const getChartId = () => {
|
||||
createChart({ app_id: '712ff0df-ed6b-470f-bf87-8cfbaf757be5' }).then(res => {
|
||||
localStorage.setItem("conversation_id", res.data.conversation_id);
|
||||
conversation_id.value = res.data.conversation_id;
|
||||
})
|
||||
}
|
||||
|
||||
// 查询prompt 替换
|
||||
const getPrompt = async () => {
|
||||
const { rows } = await modelList({ model: 5 })
|
||||
let str = rows.find(item => item.name.indexOf('框架设计') != -1).prompt
|
||||
str = str.replace('{学段}', curNode.edustage)
|
||||
str = str.replace('{学科}', curNode.edusubject)
|
||||
let bookV = curNode.roottitle.split('-')[1] + '版本'
|
||||
str = str.replace('{教材版本}', bookV)
|
||||
str = str.replace('{课程名称}', `《${curNode.itemtitle}》`)
|
||||
prompt.value = str
|
||||
}
|
||||
|
||||
const curNode = reactive({})
|
||||
onMounted(() => {
|
||||
onMounted(()=>{
|
||||
let data = sessionStore.get('subject.curNode')
|
||||
Object.assign(curNode, data);
|
||||
courseObj.node = data
|
||||
// 框架设计 用课标的dataset_id
|
||||
let jsonKey = `课标-${data.edustage}-${data.edusubject}`
|
||||
params.dataset_id = commUtils.dataSetJson[jsonKey]
|
||||
|
||||
// 获取百度千帆会话ID
|
||||
conversation_id.value = localStorage.getItem('conversation_id')
|
||||
if (!conversation_id.value) {
|
||||
getChartId();
|
||||
}
|
||||
|
||||
// 获取prompt
|
||||
getPrompt()
|
||||
})
|
||||
|
||||
|
||||
// 解绑
|
||||
onUnmounted(() => {
|
||||
emitter.off('changeMode')
|
||||
emitter.off('changeResult')
|
||||
emitter.off('changeAdjust')
|
||||
emitter.off('onSaveAdjust');
|
||||
onUnmounted(()=>{
|
||||
emitter.off('onResult')
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container-right {
|
||||
flex-direction: column;
|
||||
.container-right{
|
||||
height: 100%;
|
||||
|
||||
.right-header {
|
||||
height: 45px;
|
||||
background: #fff;
|
||||
font-size: 15px;
|
||||
flex-direction: column;
|
||||
.right-header{
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 20px;
|
||||
border-radius: 0 5px 0 0;
|
||||
.icon-jiahao{
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.right-con {
|
||||
.right-con{
|
||||
flex: 1;
|
||||
background: #F6F6F6;
|
||||
padding: 15px;
|
||||
flex-direction: column;
|
||||
margin-top: 5px;
|
||||
background-color: #fff;
|
||||
border-radius: 5px;
|
||||
overflow-y: auto;
|
||||
|
||||
.con-item {
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
padding-bottom: 20px;
|
||||
position: relative;
|
||||
padding-left: 15px;
|
||||
box-sizing: border-box;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
border-radius: 50%;
|
||||
background: #409eff;
|
||||
position: absolute;
|
||||
left: -8px;
|
||||
top: 5px;
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
width: 2px;
|
||||
height: 100%;
|
||||
background: #409eff;
|
||||
position: absolute;
|
||||
left: -1px;
|
||||
top: 5px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
&::before {
|
||||
content: '';
|
||||
width: 0
|
||||
}
|
||||
}
|
||||
|
||||
.item-top {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 5px;
|
||||
|
||||
.icon-shenglvehao {
|
||||
font-weight: bold
|
||||
}
|
||||
}
|
||||
|
||||
.item-bom {
|
||||
background: #fff;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
|
||||
.item-prompt {
|
||||
text-align: left;
|
||||
margin-bottom: 5px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.item-answer {
|
||||
padding: 10px;
|
||||
background: #F2F2F2;
|
||||
border-radius: 5px;
|
||||
|
||||
.answer-text {
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 10px;
|
||||
text-align: left;
|
||||
font-size: 13px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.item-btn {
|
||||
justify-content: flex-end;
|
||||
|
||||
.iconfont {
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.icon-ai1 {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.right-con-item{
|
||||
display: flex;
|
||||
margin: 10px 0;
|
||||
justify-content: space-around;
|
||||
img{
|
||||
width: 150px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.template-custom-popover {
|
||||
width: 110px !important;
|
||||
min-width: 110px !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
<template>
|
||||
<div class="container-right flex">
|
||||
<div class="right-header flex">
|
||||
<span>课件预览</span>
|
||||
<div>
|
||||
<el-button type="danger" @click="onCreate">一键生成</el-button>
|
||||
<el-button>编辑课件</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right-con">
|
||||
<el-empty v-if="!result" description="请先生成教学大纲,再生成教学课件" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, onUnmounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import emitter from '@/utils/mitt'
|
||||
|
||||
const result = ref('')
|
||||
emitter.on('onResult', (data)=>{
|
||||
result.value = data
|
||||
})
|
||||
|
||||
const onCreate = () =>{
|
||||
if(!result.value){
|
||||
ElMessage.warning('请先进行研读')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
onUnmounted(()=>{
|
||||
emitter.off('onResult')
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.container-right{
|
||||
height: 100%;
|
||||
font-size: 15px;
|
||||
flex-direction: column;
|
||||
.right-header{
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.icon-jiahao{
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
.right-con{
|
||||
flex: 1;
|
||||
margin-top: 5px;
|
||||
background-color: #fff;
|
||||
border-radius: 5px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
|
@ -1,54 +1,35 @@
|
|||
<template>
|
||||
<div class="page-design">
|
||||
<!-- <div class="page-left">
|
||||
|
||||
<left />
|
||||
</div>
|
||||
<div class="page-right">
|
||||
|
||||
<right />
|
||||
</div> -->
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="5">
|
||||
<Left/>
|
||||
</el-col>
|
||||
<el-col :span="13">
|
||||
<Center/>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<Right/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="5">
|
||||
<Left />
|
||||
</el-col>
|
||||
<el-col :span="14">
|
||||
<Center />
|
||||
</el-col>
|
||||
<el-col :span="5">
|
||||
<Right />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// import left from './container/left.vue';
|
||||
// import right from './container/right.vue';
|
||||
import Left from './container/left2.vue'
|
||||
import Left from './container/left.vue'
|
||||
import Center from './container/center.vue'
|
||||
import Right from './container/right2.vue'
|
||||
import Right from './container/right.vue'
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page-design {
|
||||
height: 100%;
|
||||
.el-row{
|
||||
|
||||
.el-row {
|
||||
height: 100%;
|
||||
.el-col{
|
||||
|
||||
.el-col {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// .page-design {
|
||||
// height: 100%;
|
||||
// .page-left{
|
||||
// width: 50%;
|
||||
// }
|
||||
// .page-right{
|
||||
// width: 50%;
|
||||
// }
|
||||
// }
|
||||
</style>
|
Loading…
Reference in New Issue