Compare commits

...

10 Commits

Author SHA1 Message Date
“zouyf” d5a8da438a Merge branch 'main' into zouyf_dev
# Conflicts:
#	package.json
2024-11-20 15:29:21 +08:00
lyc 45aa0a91a2 Merge pull request 'lyc-dev' (#45) from lyc-dev into main 2024-11-20 15:26:00 +08:00
lyc 0ccdbfe37a 冲突 2024-11-20 15:25:25 +08:00
lyc 1a0a2f9a67 模板 2024-11-20 15:23:42 +08:00
lyc c803ecd796 教学框架设计 2024-11-19 17:08:34 +08:00
lyc 19283456d4 Merge branch 'main' into lyc-dev 2024-11-19 10:01:09 +08:00
lyc 1a88d63893 冲突 2024-11-19 09:57:36 +08:00
lyc d283b60af7 模板 2024-11-18 17:31:01 +08:00
lyc 0f63afd277 Merge branch 'main' into lyc-dev 2024-11-18 10:17:23 +08:00
lyc f168e04405 模板 2024-11-16 23:37:11 +08:00
26 changed files with 1040 additions and 113 deletions

View File

@ -49,14 +49,21 @@ export default defineConfig({
changeOrigin: true, // 改变请求的起源 changeOrigin: true, // 改变请求的起源
rewrite: (path) => path.replace(/^\/parth/, '') // 重写路径 rewrite: (path) => path.replace(/^\/parth/, '') // 重写路径
}, },
'/v1': { '/api': {
target: 'https://ai.ysaix.com:7864', target: 'https://ai.ysaix.com:7864',
changeOrigin: true, changeOrigin: true,
pathRewrite: { '^/v1': '' } pathRewrite: { '^/api': '' }
} }
}, },
}, },
plugins: [vue(), WindiCSS(),vitePpt()], plugins: [vue(), WindiCSS(),vitePpt()],
assetsInclude:('**/*.woff', '**/*.woff2', '**/*.ttf'), assetsInclude:('**/*.woff', '**/*.woff2', '**/*.ttf'),
css: {
preprocessorOptions: {
scss: {
silenceDeprecations: ['legacy-js-api']
}
}
}
} }
}) })

View File

@ -1,7 +1,69 @@
import request from '@/utils/request' import request from '@/utils/request'
import axios from 'axios' import axios from 'axios'
let rootPath = import.meta.env.VITE_APP_ENV === 'production' ? "https://ai.ysaix.com:7864" : ''; let rootPath = import.meta.env.VITE_APP_ENV === 'production' ? 'https://ai.ysaix.com:7864' : ''
export function conversation(data) {
return axios({
url: rootPath + '/v1/api/new_conversation',
method: 'get',
headers: {
Authorization: 'Bearer ragflow-IwNzMxMTIyOGY0ZTExZWZiOGE2MDI0Mm',
'Content-Type': 'application/json'
},
data: data
})
}
// 进行课标研读对话
export function completion(data) {
return axios({
url: rootPath + '/api/v1/parse/docs',
method: 'post',
headers: {
Authorization: 'Bearer ragflow-IwMDI1MGU2YTU3NjExZWZiNWEzMDI0Mm',
'Content-Type': 'application/json',
Accept: '*/*'
},
data: data
})
}
// 添加提示词 (系统预设)
export function addKeyWords(data) {
return request({
url: '/education/llmModel/copy',
method: 'post',
data
})
}
// 添加子模板
export function addChildTemp(data) {
return request({
url: '/education/llmModel',
method: 'post',
data
})
}
// 编辑子模板
export function editChildTemp(data) {
return request({
url: '/education/llmModel',
method: 'put',
data
})
}
// 删除子模板
export function removeChildTemp(id) {
return request({
url: '/education/llmModel/' + id,
method: 'delete'
})
}
// 查询模板列表 // 查询模板列表
export function modelList(params) { export function modelList(params) {
return request({ return request({
@ -11,28 +73,37 @@ export function modelList(params) {
}) })
} }
export function conversation(data) { // 保存模板 结果
return axios({ export function tempSave(data) {
url: rootPath + '/v1/api/new_conversation', return request({
method: 'get', url: '/education/result',
headers: { method: 'post',
'Authorization':'Bearer ragflow-IwNzMxMTIyOGY0ZTExZWZiOGE2MDI0Mm', data
'Content-Type': 'application/json',
},
data: data
}) })
} }
// 进行课标研读对话 // 修改模板结果
export function completion(data) { export function editTempResult(data) {
return axios({ return request({
url: rootPath + '/v1/api/completion', url: '/education/result',
method: 'post', method: 'put',
headers: { data
'Authorization':'Bearer ragflow-IwNzMxMTIyOGY0ZTExZWZiOGE2MDI0Mm',
'Content-Type': 'application/json',
'Accept': '*/*'
},
data: data
}) })
} }
// 查询模板结果
export function tempResult(params) {
return request({
url: '/education/result/list',
method: 'get',
params
})
}
// 删除模板结果
export function tempResultRemove(id) {
return request({
url: `/education/result/${id}`,
method: 'get',
})
}

View File

@ -1,8 +1,8 @@
@font-face { @font-face {
font-family: "iconfont"; /* Project id 4723712 */ font-family: "iconfont"; /* Project id 4723712 */
src: url('iconfont.woff2?t=1731393731097') format('woff2'), src: url('iconfont.woff2?t=1731913617367') format('woff2'),
url('iconfont.woff?t=1731393731097') format('woff'), url('iconfont.woff?t=1731913617367') format('woff'),
url('iconfont.ttf?t=1731393731097') format('truetype'); url('iconfont.ttf?t=1731913617367') format('truetype');
} }
.iconfont { .iconfont {
@ -13,6 +13,10 @@
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
.icon-baocun:before {
content: "\e60e";
}
.icon-tihuan:before { .icon-tihuan:before {
content: "\e7ab"; content: "\e7ab";
} }

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,13 @@
"css_prefix_text": "icon-", "css_prefix_text": "icon-",
"description": "", "description": "",
"glyphs": [ "glyphs": [
{
"icon_id": "11467388",
"name": "保存",
"font_class": "baocun",
"unicode": "e60e",
"unicode_decimal": 58894
},
{ {
"icon_id": "12730938", "icon_id": "12730938",
"name": "替换", "name": "替换",

View File

@ -44,6 +44,7 @@ import { ref, reactive, onMounted } from 'vue'
import { conversation, completion } from '@/api/mode/index' import { conversation, completion } from '@/api/mode/index'
import { sessionStore } from '@/utils/store' import { sessionStore } from '@/utils/store'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { dataSetJson } from '@/utils/comm.js'
const textarea = ref('') const textarea = ref('')
@ -55,6 +56,10 @@ const props = defineProps({
default: () => { default: () => {
return { name: '11' } return { name: '11' }
} }
},
modeType: {
type: Number,
default: 1
} }
}) })
@ -77,31 +82,22 @@ const send = () =>{
const curNode = reactive({}) const curNode = reactive({})
const params = reactive( const params = reactive(
{ {
"conversation_id": "", prompt: '',
"messages": [ dataset_id: ''
{
"role": "user",
"content": ""
}
],
"quote": false,
"stream": false
} }
) )
// ID // ID
const getConversation = async (val) => { const getConversation = (val) => {
const result = await conversation()
params.conversation_id = result.data.data.id
getCompletion(val) getCompletion(val)
} }
// //
const getCompletion = async (val) => { const getCompletion = async (val) => {
try { try {
params.messages[0].content = `根据${curNode.edustage}语文课标${props.item.name}${val}` params.prompt = `根据${curNode.edustage}${curNode.edusubject}课标${props.item.name}${val}`
const res = await completion(params) const { data } = await completion(params)
console.log('对话结果===》', res) let answer = data.answer
let answer = res.data.data.answer
msgList.value.push({ msgList.value.push({
type: 'robot', type: 'robot',
msg: answer, msg: answer,
@ -121,7 +117,11 @@ const saveAdjust = (item) =>{
onMounted(() => { onMounted(() => {
let data = sessionStore.get('subject.curNode') let data = sessionStore.get('subject.curNode')
Object.assign(curNode, data); Object.assign(curNode, data);
let text = props.modeType == 1 ? '课标': props.modeType == 2 ? '教材' : '考试'
let jsonKey = `${text}-${data.edustage}-${data.edusubject}`
params.dataset_id = dataSetJson[jsonKey]
}) })
</script> </script>

View File

@ -28,6 +28,7 @@
<script setup> <script setup>
import { ref, watch} from 'vue' import { ref, watch} from 'vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { editTempResult } from '@/api/mode/index.js'
const textarea = ref('') const textarea = ref('')
@ -42,7 +43,7 @@ const props = defineProps({
} }
}) })
watch(() => props.item.oldAnswer, (newVal) => { watch(() => props.item.answer, (newVal) => {
if (newVal) { if (newVal) {
textarea.value = newVal textarea.value = newVal
} }
@ -50,9 +51,11 @@ watch(() => props.item.oldAnswer, (newVal) => {
const emit = defineEmits(['saveEdit']) const emit = defineEmits(['saveEdit'])
const onSave = () =>{ const onSave = () =>{
emit('saveEdit', textarea.value) editTempResult({id: props.item.reultId, content: textarea.value}).then( res =>{
isDialog.value = false isDialog.value = false
ElMessage.success('操作成功') ElMessage.success('操作成功')
emit('saveEdit', textarea.value)
})
} }
</script> </script>

View File

@ -10,7 +10,7 @@
<el-dropdown @command="changeTemplate" :hide-on-click="false"> <el-dropdown @command="changeTemplate" :hide-on-click="false">
<span class="el-dropdown-link"> <span class="el-dropdown-link">
{{ curTemplate.name }} {{ curTemplate.name }}
<i class="iconfont icon-xiangxia" </i> <i class="iconfont icon-xiangxia"></i>
</span> </span>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
@ -20,7 +20,7 @@
</template> </template>
</el-dropdown> </el-dropdown>
<div> <div>
<el-button type="primary" link @click="wordDialog = true"> <el-button type="primary" link @click="onAdd">
<el-icon> <el-icon>
<Plus /> <Plus />
</el-icon> </el-icon>
@ -31,7 +31,8 @@
</div> </div>
</div> </div>
</div> </div>
<keywordDialog v-model="wordDialog"/> <!--添加提示词-->
<keywordDialog v-model="wordDialog" :modeType="type" :isAdd="wordDialog" :item="curTemplate"/>
<Dialog v-model="showDialog" :modeType="type" /> <Dialog v-model="showDialog" :modeType="type" />
</template> </template>
@ -93,6 +94,11 @@ const changeTemplate = (val) => {
}) })
} }
const onAdd = () =>{
wordDialog.value = true
}
onMounted(() => { onMounted(() => {
getTemplateList() getTemplateList()
}) })

View File

@ -1,28 +1,28 @@
<template> <template>
<el-dialog v-model="mode" :show-close="false" width="600"> <el-dialog v-model="mode" :show-close="false" width="600" destroy-on-close>
<template #header> <template #header>
<div class="custom-header flex"> <div class="custom-header flex">
<span>{{ isAdd ? '添加' : '编辑' }}提示词</span> <span>{{ isAdd ? item && item.ex3 == '1' ? '请输入新的模板名称' : '添加提示词' : '编辑提示词' }}</span>
<i class="iconfont icon-guanbi" @click="mode = false"></i> <i class="iconfont icon-guanbi" @click="mode = false"></i>
</div> </div>
</template> </template>
<div class="dialog-content"> <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 :model="form" label-width="auto">
<el-form-item label="名称"> <el-form-item label="名称">
<el-input v-model="form.name" /> <el-input v-model="form.name" />
</el-form-item> </el-form-item>
<el-form-item label="提示词"> <el-form-item label="提示词" v-if="isAdd ? !(item && item.ex3 == '1') : true">
<el-input v-model="form.prompt" type="textarea" /> <el-input v-model="form.prompt" type="textarea" />
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div>
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
<el-button @click="mode = false">取消</el-button> <el-button @click="mode = false">取消</el-button>
<el-button type="primary" @click="mode = false"> <el-button type="primary" @click="saveAdd">
确定 确定
</el-button> </el-button>
</div> </div>
@ -31,16 +31,27 @@
</template> </template>
<script setup> <script setup>
import { reactive, watch } from 'vue' import { ref, reactive, watch } from 'vue'
const mode = defineModel() import { ElMessage } from 'element-plus'
import { addKeyWords, addChildTemp, editChildTemp } from '@/api/mode/index'
const mode = defineModel()
const props = defineProps({ const props = defineProps({
modeType: {
type: Number,
default: 1
},
isAdd: { isAdd: {
type: Boolean, type: Boolean,
default: true default: true
}, },
item: { item: { //
type: Object type: Object
},
temp: { //
Object
} }
}) })
@ -50,12 +61,60 @@ const form = reactive({
}) })
watch(() => props.isAdd, (newVal) => { watch(() => props.isAdd, (newVal) => {
console.log(newVal)
if (!newVal) { if (!newVal) {
console.log(props.item) form.name = props.item?.name
form.name = props.item.name form.prompt = props.item?.prompt
form.prompt = props.item.prompt
} }
}, { immediate: true })
}, { immediate: false })
const loading = ref(false)
const saveAdd = async () => {
loading.value = true
if (props.isAdd) {
try {
var msg = null
//
if (props.item.ex3 == '1') {
var { msg } = await addKeyWords({ name: form.name, id: props.item.id })
}
else {
//
let obj = {
name: form.name,
type: 2, // 2
sortNum: 1,
parentId: props.item.id,
lmType: 1,
model: props.modeType,
prompt: form.prompt,
ex1: props.item.ex1, //
ex2: props.item.ex2, //
ex3: '', //
}
var { msg } = await addChildTemp(obj)
}
ElMessage.success(msg)
mode.value = false
} finally {
loading.value = false
}
} else {
//
try {
let data = JSON.parse(JSON.stringify(props.item))
data.name = form.name;
data.prompt = form.prompt
const { msg } = await editChildTemp(data)
ElMessage.success(msg)
mode.value = false
} finally {
loading.value = false
}
}
}
</script> </script>
@ -69,4 +128,10 @@ watch(() => props.isAdd, (newVal) => {
font-weight: bold; font-weight: bold;
} }
} }
.small-tip{
text-align: left;
font-size: 12px;
margin-bottom: 15px;
color: #F56C6C;
}
</style> </style>

View File

@ -17,7 +17,7 @@
</template> </template>
<template #default> <template #default>
<el-button type="primary" link @click="editKeyWord(item)">编辑</el-button> <el-button type="primary" link @click="editKeyWord(item)">编辑</el-button>
<el-button type="primary" link>移除</el-button> <el-button type="primary" link @click="removeItem(item)">移除</el-button>
</template> </template>
</el-popover> </el-popover>
</div> </div>
@ -53,21 +53,22 @@
<!--编辑结果--> <!--编辑结果-->
<EditDialog v-model="isEdit" :item="editItem" @saveEdit="saveEdit" /> <EditDialog v-model="isEdit" :item="editItem" @saveEdit="saveEdit" />
<!--AI 对话调整--> <!--AI 对话调整-->
<AdjustDialog v-model="isAdjust" :item="editItem" @saveAdjust="saveAdjust" /> <AdjustDialog v-model="isAdjust" :modeType="modeType" :item="editItem" @saveAdjust="saveAdjust" />
<!--编辑提示词--> <!--编辑提示词-->
<keywordDialog v-model="isEditKeyWord" :isAdd="false" :item="keywordItem"/> <keywordDialog v-model="isEditKeyWord" :isAdd="!isEditKeyWord" :item="keywordItem"/>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, reactive, onMounted, watch } from 'vue'; import { ref, reactive, onMounted, watch } from 'vue';
import { ElMessage } from 'element-plus'
import EditDialog from './edit-dialog.vue' import EditDialog from './edit-dialog.vue'
import AdjustDialog from './adjust-dialog.vue' import AdjustDialog from './adjust-dialog.vue'
import keywordDialog from './keyword-dialog.vue'; import keywordDialog from './keyword-dialog.vue';
import { sessionStore } from '@/utils/store' import { sessionStore } from '@/utils/store'
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
import { conversation, completion, modelList } from '@/api/mode/index' import { tempSave, completion, modelList, removeChildTemp, tempResult } from '@/api/mode/index'
import { dataSetJson } from '@/utils/comm.js'
const userStore = useUserStore() const userStore = useUserStore()
@ -89,16 +90,35 @@ const getChildTemplate = () => {
tempLoading.value = true tempLoading.value = true
modelList({ model: props.modeType, type: 2, parentId: props.tempId }).then(res => { modelList({ model: props.modeType, type: 2, parentId: props.tempId }).then(res => {
childTempList.value = res.rows childTempList.value = res.rows
getTempResult()
}).finally(() => { }).finally(() => {
tempLoading.value = false tempLoading.value = false
}) })
} }
//
const getTempResult = () =>{
tempResult({mainModelId: props.tempId}).then(res =>{
console.log(res,1000)
let rows = res.rows
childTempList.value.forEach(item =>{
rows.forEach(el =>{
if(item.id == el.modelId){
item.answer = el.content
item.reultId = el.id
}
})
})
})
}
const isEdit = ref(false) const isEdit = ref(false)
watch(() => props.tempId, (newVal) => { watch(() => props.tempId, (newVal) => {
if (newVal) { if (newVal) {
// isEdit.value = true // isEdit.value = true
getChildTemplate() getChildTemplate()
} }
}) })
@ -106,24 +126,14 @@ watch(() => props.tempId, (newVal) => {
// ID // ID
const params = reactive( const params = reactive(
{ {
"conversation_id": "", prompt: '',
"messages": [ dataset_id: ''
{
"role": "user",
"content": ""
}
],
"quote": false,
"stream": false
} }
) )
const curNode = reactive({}) const curNode = reactive({})
const getConversation = async () => { const getConversation = () => {
const { user: { userId } } = userStore
const result = await conversation({ user_id: String(userId) })
console.log('result', result)
params.conversation_id = result.data.data.id
getCompletion() getCompletion()
} }
// //
@ -131,29 +141,42 @@ const getCompletion = async () => {
for (let item of childTempList.value) { for (let item of childTempList.value) {
try { try {
item.loading = true item.loading = true
params.messages[0].content = `根据${curNode.edustage}语文课标,提炼出${item.name}` params.prompt = `根据${curNode.edustage}${curNode.edusubject}课标,提炼出${item.name}`
const res = await completion(params) const { data } = await completion(params)
console.log('对话结果===》', res) let answer = data.answer
let answer = res.data.data.answer
item.oldAnswer = answer item.oldAnswer = answer
item.answer = getResult(answer); item.answer = getResult(answer);
onSaveTemp(item)
} finally { } finally {
item.loading = false item.loading = false
} }
} }
} }
//
const onSaveTemp = (item) =>{
const data = {
mainModelId: props.tempId,
modelId: item.id,
examDocld: '',
content: item.oldAnswer
}
tempSave(data).then(res =>{
console.log(res)
})
}
// //
const againResult = async (index, item) => { const againResult = async (index, item) => {
try { try {
childTempList.value[index].loading = true childTempList.value[index].loading = true
params.messages[0].content = `根据${curNode.edustage}语文课标,提炼出${item.name}` params.prompt = `根据${curNode.edustage}${curNode.edusubject}课标,提炼出${item.name}`
const res = await completion(params) const { data } = await completion(params)
let answer = res.data.data.answer let answer = data.answer
item.oldAnswer = answer childTempList.value[index].oldAnswer = answer
item.answer = getResult(answer); childTempList.value[index].answer = getResult(answer);
} finally { } finally {
childTempList.value[index].loading = false childTempList.value[index].loading = false
} }
@ -180,9 +203,10 @@ const onEdit = (index, item) => {
// //
const saveEdit = (data) => { const saveEdit = (data) => {
childTempList.value[curIndex.value].oldAnswer = data // childTempList.value[curIndex.value].oldAnswer = data
let answer = getResult(data); // let answer = getResult(data);
childTempList.value[curIndex.value].answer = answer // childTempList.value[curIndex.value].answer = answer
getChildTemplate()
} }
const isAdjust = ref(false) const isAdjust = ref(false)
@ -201,15 +225,28 @@ const saveAdjust = (item) => {
const keywordItem = reactive({}) const keywordItem = reactive({})
const isEditKeyWord = ref(false) const isEditKeyWord = ref(false)
const editKeyWord = (item) =>{ const editKeyWord = (item) =>{
console.log(item)
isEditKeyWord.value = true isEditKeyWord.value = true
Object.assign(keywordItem, item) Object.assign(keywordItem, item)
} }
//
const removeItem = async(item) =>{
const { msg } = await removeChildTemp(item.id)
ElMessage.success(msg)
getChildTemplate()
}
onMounted(() => { onMounted(() => {
let data = sessionStore.get('subject.curNode') let data = sessionStore.get('subject.curNode')
Object.assign(curNode, data); Object.assign(curNode, data);
let text = props.modeType == 1 ? '课标': props.modeType == 2 ? '教材' : '考试'
let jsonKey = `${text}-${data.edustage}-${data.edusubject}`
params.dataset_id = dataSetJson[jsonKey]
}) })
defineExpose({ defineExpose({

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="whiteboart-container" :style="{ height: height + 'px' }"> <div class="whiteboart-container">
<div class="canvasBox" ref="box"></div> <div class="canvasBox" ref="box"></div>
<div class="footerLeft" @click.stop <div class="footerLeft" @click.stop

View File

@ -66,20 +66,12 @@ export const constantRoutes = [
component: () => import('@/views/job-management/index.vue'), component: () => import('@/views/job-management/index.vue'),
name: 'job-management', name: 'job-management',
meta: { title: '作业管理' }, meta: { title: '作业管理' },
// children: [ },
// { {
// path: 'details', path: 'design',
// component: () => import('@/views/job-management/Details/index.vue'), component: () => import('@/views/teachingDesign/index.vue'),
// name: 'details', name: 'teaching-design',
// meta: { title: '详情' } meta: { title: '教学框架设计' },
// },
// {
// path: 'right',
// component: () => import('@/views/job-management/Right/index.vue'),
// name: 'right',
// meta: { title: '主页' }
// },
// ]
}, },
] ]
}, },

View File

@ -351,3 +351,26 @@ export function throttle(func, wait) {
} }
}; };
} }
/**
*
* 大模型对话dataset_id
*/
export const dataSetJson = {
"考试-高中-地理": "e790f68aa19811efbe0b0242ac140006",
"考试-高中-数学": "9cc3084ea19811ef97f00242ac140006",
"考试-高中-物理": "b19749c4a19811ef89a80242ac140006",
"考试-高中-化学": "bb7dcd40a19811efb6090242ac140006",
"考试-高中-生物": "c31f8df8a19811efbd6d0242ac140006",
"考试-高中-英语": "a84527afa19811ef8bf00242ac140006",
"考试-高中-语文": "928e6da0a19811efb6e50242ac140006",
"考试-高中-历史": "df2c09e6a19811ef84d00242ac140006",
"考试-高中-政治": "ce43ea58a19811efb41c0242ac140006",
"课标-高中-语文": "cee3062a9fcf11efa6910242ac140006",
"课标-高中-生物": "fb5d01d59fd011ef9bb90242ac140006",
"课标-高中-历史": "f2f6c1fb9fd011ef98740242ac140006",
"课标-高中-英语": "e889fcac9fd011efb22a0242ac140006",
"课标-高中-数学": "e03aa4fe9fd011ef91270242ac140006",
"课标-高中-地理": "270516829fd111efb13c0242ac140006",
"鉴权": "ragflow-IwMDI1MGU2YTU3NjExZWZiNWEzMDI0Mm"
}

View File

@ -0,0 +1,5 @@
import mitt from 'mitt'
// 创建mitt实例
const emitter = mitt()
// 导出
export default emitter

View File

@ -0,0 +1,12 @@
<template>
<!-- <whiteboard/> -->
<div> 1</div>
</template>
<script setup>
import whiteboard from '@/components/whiteboard/whiteboard.vue';
</script>
<style lang="scss" scoped>
</style>

View File

@ -40,6 +40,7 @@
<script setup> <script setup>
import { ref,defineProps ,defineEmits,nextTick , onMounted,shallowRef } from 'vue' import { ref,defineProps ,defineEmits,nextTick , onMounted,shallowRef } from 'vue'
import ClassroomPresentation from './classroomPresentation/index.vue' import ClassroomPresentation from './classroomPresentation/index.vue'
import ClassPresentation from './classPresentation/index.vue'
import selfSearchQuestions from './selfSearchQuestions/index.vue' import selfSearchQuestions from './selfSearchQuestions/index.vue'
const props = defineProps({ const props = defineProps({
parameter: Object parameter: Object
@ -65,6 +66,8 @@ const rightComponets = (str) => {
return ClassroomPresentation return ClassroomPresentation
case 'selfSearchQuestions': case 'selfSearchQuestions':
return selfSearchQuestions return selfSearchQuestions
case 'classPresentation':
return ClassPresentation
default: default:
return null return null
} }

View File

@ -76,7 +76,7 @@ const items = ref([
label:'智能推荐', label:'智能推荐',
}, },
] }, ] },
{ title: '课堂展示', description: '555555', icon: markRaw(Document), type: 'primary', text: '课堂展示',components:'selfSearchQuestions',titleList:[ { title: '课堂展示', description: '555555', icon: markRaw(Document), type: 'primary', text: '课堂展示',components:'classPresentation',titleList:[
{ {
id:1, id:1,
label:'课堂展示', label:'课堂展示',

View File

@ -4,6 +4,7 @@
<el-button type="primary" @click="onchange('/model/curriculum')">课标研读</el-button> <el-button type="primary" @click="onchange('/model/curriculum')">课标研读</el-button>
<el-button type="primary" @click="onchange('/model/management')">作业管理</el-button> <el-button type="primary" @click="onchange('/model/management')">作业管理</el-button>
<el-button type="success" @click="onchange('/model/teaching')">教材研读</el-button> <el-button type="success" @click="onchange('/model/teaching')">教材研读</el-button>
<el-button type="info" @click="onchange('/model/design')">教学框架设计</el-button>
<el-button type="success" @click="openPPTist">打开PPTist</el-button> <el-button type="success" @click="openPPTist">打开PPTist</el-button>
<!-- <el-button type="info" @click="onchange('/model/examination')">考试分析</el-button> --> <!-- <el-button type="info" @click="onchange('/model/examination')">考试分析</el-button> -->
</div> </div>

View File

@ -0,0 +1,249 @@
<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 emitter from '@/utils/mitt';
import { sessionStore } from '@/utils/store'
import { ElMessage } from 'element-plus'
const textarea = ref('')
const isDialog = defineModel()
const props = defineProps({
item: {
type: Object,
default: () => {
return { name: '11' }
}
}
})
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({})
// ID
const getConversation = async (val) => {
try {
const { data } = await completion({
dataset_id: 'cee3062a9fcf11efa6910242ac140006',
prompt: val
})
msgList.value.push({
type: 'robot',
msg: data.answer,
})
} finally {
loaded.value = false
}
}
const saveAdjust = (item) => {
// emit('saveAdjust', item.msg)
emitter.emit('changeAdjust', item.msg)
isDialog.value = false
ElMessage.success('操作成功')
}
onMounted(() => {
let data = sessionStore.get('subject.curNode')
Object.assign(curNode, data);
})
</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>

View File

@ -0,0 +1,77 @@
<template>
<el-dialog v-model="isDialog" :show-close="false" width="900" 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-row>
<el-col :span="24">
<el-input v-model="textarea" :autosize="{ minRows: 5, maxRows: 15 }" type="textarea" />
</el-col>
</el-row>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="isDialog = false">取消</el-button>
<el-button type="primary" @click="onSave">
确定
</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { ref, watch} from 'vue'
import { ElMessage } from 'element-plus'
import emitter from '@/utils/mitt';
const textarea = ref('')
const isDialog = defineModel()
const props = defineProps({
item: {
type: Object,
default: () => {
return { name: '11' }
}
}
})
watch(() => props.item.answer, (newVal) => {
if (newVal) {
textarea.value = newVal
}
},{ deep: true })
const emit = defineEmits(['saveEdit'])
const onSave = () =>{
emitter.emit('changeResult', textarea.value)
isDialog.value = false
ElMessage.success('操作成功')
}
</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;
}
</style>

View File

@ -0,0 +1,126 @@
<template>
<div class="container-left flex">
<div class="left-header flex">教学模式</div>
<div class="left-con" v-loading="loading">
<div class="con-item" v-for="item in tempList" :key="item.id">
<div class="item-header flex">
<span>{{ item.name }}</span>
<el-button type="primary" link @click="onSelect(item)">选择模式</el-button>
</div>
<el-scrollbar>
<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.name }}</p>
<div class="card-text">
<el-text line-clamp="2">
{{ el.prompt }}
</el-text>
</div>
</el-card>
</div>
</el-scrollbar>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import emitter from '@/utils/mitt';
import { modelList } from '@/api/mode/index'
//
let list = []
const getTemplate = () => {
modelList({ model: 1, type: 1, ex3: 1 }).then(res => {
list = res.rows
getChildTemp()
})
}
//
const loading = ref(false)
const tempList = ref([])
const getChildTemp = async () => {
loading.value = true
for (let item of list) {
try {
const { rows } = await modelList({ model: 1, type: 2, parentId: item.id })
tempList.value.push({
id: item.id,
name: item.name,
child: rows
})
} finally {
loading.value = false
emitter.emit('changeMode', tempList.value[0])
}
}
}
//
const emit = defineEmits([''])
const onSelect = (item) =>{
emitter.emit('changeMode', item)
}
onMounted(() => {
getTemplate()
})
</script>
<style lang="scss" scoped>
.container-left {
width: 100%;
height: 100%;
flex-direction: column;
.left-header {
height: 45px;
background: #F6F6F6;
border-radius: 5px 0 0 0;
align-items: center;
font-size: 14px;
font-weight: bold;
text-indent: 2em;
}
.left-con {
flex: 1;
background: #fff;
border-radius: 0 0 0 5px;
padding: 15px;
box-sizing: border-box;
font-size: 14px;
.item-header {
justify-content: space-between;
margin-bottom: 5px;
}
.con-item {
margin-bottom: 20px;
}
.item-card {
width: 130px;
font-size: 13px;
padding: 10px;
margin-right: 20px;
:deep(.el-card__body) {
padding: 0 !important;
}
.card-name {
text-align: center;
}
.card-text {
text-align: left;
font-size: 12px;
}
}
}
}
</style>

View File

@ -0,0 +1,208 @@
<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-button type="primary">生成大纲</el-button>
<el-button type="danger">生成PPT</el-button>
</div>
</div>
<div class="right-con flex">
<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-button type="info" link>
<i class="iconfont icon-xiazai9"></i>
</el-button>
</div>
<div class="item-bom">
<div class="item-prompt">{{ item.prompt }}</div>
<div class="item-answer" v-if="item.answer">
<div class="answer-text" v-html="item.answer">
</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>
</div>
</div>
<EditDialog v-model="isEdit" :item="curItem" />
<AdjustDialog v-model="isAdjust" :item="curItem" />
</template>
<script setup>
import { ref, onUnmounted, reactive } from 'vue'
import emitter from '@/utils/mitt'
import EditDialog from './edit-dialog.vue'
import AdjustDialog from './adjust-dialog.vue'
import { completion } from '@/api/mode/index.js'
const resultList = ref([])
emitter.on('changeMode', (item) => {
console.log(item, 3000)
resultList.value = item.child
conversation()
})
const conversation = async () => {
for (let item of resultList.value) {
item.loading = true
try {
const { data } = await completion({
dataset_id: 'cee3062a9fcf11efa6910242ac140006',
prompt: item.prompt
})
item.answer = data.answer
} finally {
item.loading = false
}
}
}
const isEdit = ref(false)
//
const curIndex = ref(-1)
// item
const curItem = reactive({})
//
const againResult = async (index, item) => {
try {
resultList.value[index].loading = true
const { data } = await completion({
dataset_id: 'cee3062a9fcf11efa6910242ac140006',
prompt: item.prompt
})
resultList.value[index].answer = data.answer
} 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('changeAdjust', (item) =>{
resultList.value[curIndex.value].answer = item
})
//
const onEdit = (index, item) => {
curIndex.value = index
Object.assign(curItem, item)
isEdit.value = true
}
emitter.on('changeResult', (item) => {
resultList.value[curIndex.value].answer = item
})
//
onUnmounted(() => {
emitter.off('changeMode')
emitter.off('changeResult')
emitter.off('changeAdjust')
})
</script>
<style lang="scss" scoped>
.container-right {
flex-direction: column;
height: 100%;
.right-header {
height: 45px;
background: #fff;
justify-content: space-between;
align-items: center;
padding: 0 20px;
border-radius: 0 5px 0 0;
}
.right-con {
flex: 1;
background: #F6F6F6;
padding: 15px;
flex-direction: column;
overflow-y: scroll;
.con-item {
width: 100%;
flex-direction: column;
margin-bottom: 20px;
.item-top {
justify-content: space-between;
align-items: center;
margin-bottom: 5px;
}
.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;
}
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,31 @@
<template>
<div class="page-design flex">
<div class="page-left">
<!--左侧-->
<left />
</div>
<div class="page-right">
<!--右侧-->
<right />
</div>
</div>
</template>
<script setup>
import left from './container/left.vue';
import right from './container/right.vue';
</script>
<style lang="scss" scoped>
.page-design {
height: 100%;
.page-left{
width: 50%;
}
.page-right{
width: 50%;
}
}
</style>