Merge branch 'main' into zouyf_dev

# Conflicts:
#	src/renderer/src/views/profile/userInfo.vue
This commit is contained in:
“zouyf” 2024-11-26 17:09:05 +08:00
commit 2d9518804e
18 changed files with 676 additions and 760 deletions

View File

@ -45,6 +45,7 @@ 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' import { dataSetJson } from '@/utils/comm.js'
import emitter from '@/utils/mitt';
const textarea = ref('') const textarea = ref('')
@ -109,13 +110,16 @@ const getCompletion = async (val) => {
} }
const saveAdjust = (item) =>{ const saveAdjust = (item) =>{
emit('saveAdjust', item.msg)
isDialog.value = false isDialog.value = false
ElMessage.success('操作成功') ElMessage.success('操作成功')
emitter.on('saveAdjust', item.msg)
} }
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 text = props.modeType == 1||props.modeType == 2 ? '课标' : '考试'
let jsonKey = `${text}-${data.edustage}-${data.edusubject}` let jsonKey = `${text}-${data.edustage}-${data.edusubject}`

View File

@ -29,6 +29,7 @@
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' import { editTempResult } from '@/api/mode/index.js'
import emitter from '@/utils/mitt';
const textarea = ref('') const textarea = ref('')
@ -49,12 +50,12 @@ watch(() => props.item.answer, (newVal) => {
} }
},{ deep: true }) },{ deep: true })
const emit = defineEmits(['saveEdit'])
const onSave = () =>{ const onSave = () =>{
editTempResult({id: props.item.reultId, content: textarea.value}).then( res =>{ editTempResult({id: props.item.reultId, content: textarea.value}).then( res =>{
isDialog.value = false isDialog.value = false
ElMessage.success('操作成功') ElMessage.success('操作成功')
emit('saveEdit', textarea.value) emitter.emit('onGetChild', textarea.value)
}) })
} }

View File

@ -1,144 +0,0 @@
<template>
<div class="container-header flex">
<div class="header-left flex">
<el-button link @click="showDialog = true">
{{ curNode.edustage}}{{ curNode.edusubject }}{{ type == 1 ? '课标研读': '教材分析'}}<i class="iconfont icon-xiangxia"></i>
</el-button>
</div>
<div class="header-right flex">
<el-dropdown @command="changeTemplate" :hide-on-click="false">
<span class="el-dropdown-link">
{{ curTemplate.name }}
<i class="iconfont icon-xiangxia"></i>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item v-for="item in templateList" :command="item" :key="item.id">{{ item.name
}}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<div>
<el-button type="primary" link @click="onAdd">
<el-icon>
<Plus />
</el-icon>
添加提示词
</el-button>
<!-- <el-button type="primary" link>保存模板</el-button> -->
<el-button type="primary" @click="aiRead">一键研读</el-button>
</div>
</div>
</div>
<!--添加提示词-->
<keywordDialog v-model="wordDialog" :modeType="type" :isAdd="wordDialog" :item="curTemplate" />
<Dialog v-model="showDialog" :modeType="type" />
</template>
<script setup>
import { ref, reactive, onMounted, onUnmounted, watch } from 'vue'
import { Plus } from '@element-plus/icons-vue'
import { ElMessageBox } from 'element-plus'
import { modelList } from '@/api/mode/index'
import Dialog from './dialog.vue'
import keywordDialog from './keyword-dialog.vue'
import emitter from '@/utils/mitt';
import { sessionStore } from '@/utils/store'
const wordDialog = ref(false)
const props = defineProps({
type: {
type: Number,
default: 1
}
})
watch(() => props.type, (newValue) => {
console.log(newValue, 'newValue2');
}, { immediate: true });
const emit = defineEmits(['changeTemp', 'onRead'])
const showDialog = ref(false)
const aiRead = () => {
emit('onRead')
}
//
const curTemplate = reactive({ name: '', id: '' })
//
const templateList = ref([])
//
const getTemplateList = () => {
modelList({ model: props.type, type: 1, pageNum: 1, pageSize: 10000 }).then(res => {
templateList.value = res.rows
Object.assign(curTemplate, res.rows[0]);
emit('changeTemp', res.rows[0].id)
})
}
//
const changeTemplate = (val) => {
ElMessageBox.confirm(
'切换模板将清除当前研读结果?',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
)
.then(() => {
Object.assign(curTemplate, val);
emit('changeTemp', curTemplate.id)
})
}
emitter.on('onGetMain', () =>{
getTemplateList()
})
const onAdd = () => {
wordDialog.value = true
}
onUnmounted(() => {
emitter.off('onGetMain')
})
const curNode = reactive({})
onMounted(() => {
let data = sessionStore.get('subject.curNode')
Object.assign(curNode, data);
getTemplateList()
})
</script>
<style lang="scss" scoped>
.container-header {
height: 45px;
background: #fff;
border-radius: 5px 5px 0 0;
box-shadow: 0px 0px 20px 0px rgba(99, 99, 99, 0.06);
.header-left {
width: 50%;
align-items: center;
padding-left: 20px;
}
.header-right {
width: 50%;
justify-content: space-between;
align-items: center;
padding: 0 10px;
}
.icon-xiangxia {
margin-left: 5px;
font-weight: bold;
}
}
</style>

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog v-model="mode" :show-close="false" width="600" destroy-on-close> <el-dialog v-model="mode" :show-close="false" width="600" append-to-body destroy-on-close>
<template #header> <template #header>
<div class="custom-header flex"> <div class="custom-header flex">
<span>{{ item.ex3 == '1' ? '请输入新的模板名称' : isAdd ? '添加提示词' : '编辑提示词' }}</span> <span>{{ item.ex3 == '1' ? '请输入新的模板名称' : isAdd ? '添加提示词' : '编辑提示词' }}</span>
@ -12,12 +12,10 @@
<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="提示词" v-if="item.ex3 == '1' ? false : true"> <el-form-item label="提示词" v-if="item.ex3 == '1' ? false : 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">
@ -52,14 +50,9 @@ const props = defineProps({
return { ex3: '' } return { ex3: '' }
} }
}, },
tempId: {
type: [String, Number],
default: ''
},
}) })
const form = reactive({ const form = reactive({
name: '', name: '',
prompt: '', prompt: '',
@ -73,16 +66,17 @@ watch(() => props.isAdd, (newVal) => {
}, { immediate: false }) }, { immediate: false })
const loading = ref(false) const loading = ref(false)
const saveAdd = async () => { const saveAdd = async () => {
loading.value = true loading.value = true
if (props.item.ex3 == '1') { if (props.item.ex3 == '1') {
if (props.isAdd) { if (props.isAdd) {
try { try {
// copy // copy
const { msg } = await addKeyWords({ name: form.name, id: props.item.id }) const { msg } = await addKeyWords({ name: form.name, id: props.item.id })
emitter.emit('onGetChild') emitter.emit('onGetMain')
ElMessage.success(msg) ElMessage.success(msg)
mode.value = false mode.value = false
} finally { } finally {
@ -138,7 +132,6 @@ const onAddChildTemp = async (parentId) => {
} }
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -56,10 +56,10 @@ const title = computed(() => {
const radio = ref(1) const radio = ref(1)
const radioList = ref([ const radioList = ref([
{ label: '浏览研读', value: 1 }, { label: '浏览研读', value: 1 },
{ label: '跨学科研读', value: 2 }, // { label: '', value: 2 },
{ label: '跨学段研读', value: 3 }, // { label: '', value: 3 },
{ label: '课标修订研读', value: 4 }, // { label: '', value: 4 },
{ label: '自由研读', value: 5 }, // { label: '', value: 5 },
]) ])
const list = ref([ const list = ref([
{ {

View File

@ -0,0 +1,60 @@
<template>
<div class="container-left-page flex">
<div class="container-left-header flex">
<el-button link @click="onClick">
{{ curNode.edustage }}{{ curNode.edusubject }}{{ type == 1 ? '课标研读' : '教材分析' }}<i
class="iconfont icon-xiangxia"></i>
</el-button>
</div>
<div class="container-left-pdf">
<PDF :url="pdfUrl" :showCatalog="false" v-if="pdfUrl" />
</div>
<!--弹窗-->
<LeftDialog v-model="showDialog" :modeType="type" />
</div>
</template>
<script setup>
import { ref, onMounted, nextTick } from 'vue'
import PDF from '@/components/PdfJs/index.vue'
import LeftDialog from './left-dialog.vue'
const props = defineProps(['curNode', 'type'])
const showDialog = ref(false)
const onClick = () => {
if (props.type == 1) return
showDialog.value = true
}
// PDF
const pdfUrl = ref('')
onMounted(async () => {
await nextTick()
const { fileurl } = props.curNode
pdfUrl.value = import.meta.env.VITE_APP_RES_FILE_PATH + fileurl.replace('.txt', '.pdf')
})
</script>
<style lang="scss" scoped>
.container-left-page {
height: 100%;
flex-direction: column;
.container-left-header {
height: 45px;
background: #fff;
border-radius: 5px 0 0 0;
justify-content: flex-start;
padding-left: 10px;
.icon-xiangxia {
margin-left: 5px;
font-weight: bold;
}
}
.container-left-pdf {
flex: 1;
}
}
</style>

View File

@ -1,26 +0,0 @@
<template>
<div class="container-pdf">
<PDF :url="pdfUrl" :showCatalog="false" v-if="pdfUrl" />
</div>
</template>
<script setup>
import { ref, onMounted, nextTick } from 'vue';
import PDF from '@/components/PdfJs/index.vue'
import { sessionStore } from '@/utils/store'
const pdfUrl = ref('')
onMounted(async () =>{
await nextTick()
const { fileurl } = sessionStore.get('subject.curBook')
pdfUrl.value = import.meta.env.VITE_APP_RES_FILE_PATH + fileurl.replace('.txt','.pdf')
})
</script>
<style lang="scss" scoped>
.container-pdf{
height: 100%;
}
</style>

View File

@ -1,505 +0,0 @@
<template>
<div class="read-container">
<el-scrollbar height="100%">
<div class="template-list">
<el-row v-for="(item, index) in childTempList">
<el-col :span="24">
<div class="template-item" v-loading="item.loading">
<div class="item-header">
<div>
<span class="blue">#</span>{{ item.name }}
</div>
<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)">编辑</el-button>
<el-button type="primary" link @click="removeItem(item)">移除</el-button>
</template>
</el-popover>
</div>
<div class="item-text">
{{ item.prompt }}
</div>
<div class="item-text text-answer" v-if="item.answer">
<div class="item-icon">
<i class="iconfont icon-ai"></i>
</div>
<div class="item-answer" v-html="item.answer"></div>
</div>
<div class="ai-btn" v-if="item.answer">
<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>
</el-col>
</el-row>
<el-empty v-if="!childTempList.length" description="暂无模板数据" />
</div>
</el-scrollbar>
<!--编辑结果-->
<EditDialog v-model="isEdit" :item="editItem" @saveEdit="saveEdit" />
<!--AI 对话调整-->
<AdjustDialog v-model="isAdjust" :modeType="modeType" :item="editItem" @saveAdjust="saveAdjust" />
<!--编辑提示词-->
<keywordDialog v-model="isEditKeyWord" :isAdd="isAdd" :item="keywordItem" :tempId="tempId" />
</div>
</template>
<script setup>
import { ref, reactive, onMounted, watch, onUnmounted } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus'
import EditDialog from './edit-dialog.vue'
import AdjustDialog from './adjust-dialog.vue'
import keywordDialog from './keyword-dialog.vue';
import { sessionStore } from '@/utils/store'
import useUserStore from '@/store/modules/user'
import { tempSave, completion, modelList, removeChildTemp, tempResult } from '@/api/mode/index'
import { dataSetJson } from '@/utils/comm.js'
import emitter from '@/utils/mitt';
const userStore = useUserStore()
const props = defineProps({
tempId: {
type: [String, Number],
default: ''
},
modeType: {
type: Number,
default: 1
}
})
emitter.on('onGetChild', () =>{
getChildTemplate()
})
//
const tempLoading = ref(false)
const childTempList = ref([])
const getChildTemplate = () => {
tempLoading.value = true
modelList({ model: props.modeType, type: 2, parentId: props.tempId }).then(res => {
childTempList.value = res.rows
getTempResult()
}).finally(() => {
tempLoading.value = false
})
}
//
const getTempResult = () => {
tempResult({ mainModelId: props.tempId }).then(res => {
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)
watch(() => props.tempId, (newVal) => {
if (newVal) {
// isEdit.value = true
getChildTemplate()
}
})
// ID
const params = reactive(
{
prompt: '',
dataset_id: ''
}
)
const curNode = reactive({})
const getConversation = () => {
getCompletion()
}
//
const getCompletion = async () => {
for (let item of childTempList.value) {
try {
item.loading = true
params.prompt = `根据${curNode.edustage}${curNode.edusubject}课标,提炼出${item.name}`
const { data } = await completion(params)
let answer = data.answer
item.oldAnswer = answer
item.answer = getResult(answer);
onSaveTemp(item)
} finally {
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) => {
try {
childTempList.value[index].loading = true
params.prompt = `根据${curNode.edustage}${curNode.edusubject}课标,提炼出${item.name}`
const { data } = await completion(params)
let answer = data.answer
childTempList.value[index].oldAnswer = answer
childTempList.value[index].answer = getResult(answer);
} finally {
childTempList.value[index].loading = false
}
}
//
let getResult = (text) => {
text = text.replace(/^\n\n(.*?)\n\n$/s, '<div>$1</div>');
text = text.replace(/^\n(.*?)\n$/s, '<p>$1</p>');
text = text.replace(/\*\*(.*?)\*\*/g, "<div class='text-tit'>$1</div>");
text = text.replace(/(\d+\..*?)\n/g, "<div class='text-num'>$1</div>\n");
return text
}
//
const curIndex = ref(-1)
const editItem = reactive({})
const onEdit = (index, item) => {
curIndex.value = index
Object.assign(editItem, item)
isEdit.value = true
}
//
const saveEdit = (data) => {
// childTempList.value[curIndex.value].oldAnswer = data
// let answer = getResult(data);
// childTempList.value[curIndex.value].answer = answer
getChildTemplate()
}
const isAdjust = ref(false)
const onAdjust = (index, item) => {
curIndex.value = index
Object.assign(editItem, item)
isAdjust.value = true
}
const saveAdjust = (item) => {
childTempList.value[curIndex.value].oldAnswer = item
let answer = getResult(item);
childTempList.value[curIndex.value].answer = answer
}
//
const keywordItem = reactive({})
const isEditKeyWord = ref(false)
const isAdd = ref(true)
const editKeyWord = (item) => {
console.log(item)
isAdd.value = false
isEditKeyWord.value = true
Object.assign(keywordItem, item)
}
//
const removeItem = async (item) => {
if (item.ex3 != '1') {
ElMessageBox.confirm(
'确认是否移除?',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
).then(() => {
console.log(item)
removeChildTemp(item.id).then(res => {
ElMessage.success('操作成功')
getChildTemplate()
})
})
}
else{
isAdd.value = false
Object.assign(keywordItem, item)
isEditKeyWord.value = true
}
// const { msg } = await removeChildTemp(item.id)
// ElMessage.success(msg)
// getChildTemplate()
}
onMounted(() => {
let data = sessionStore.get('subject.curNode')
Object.assign(curNode, data);
let text = props.modeType == 1 || props.modeType == 2 ? '课标' : '考试'
let jsonKey = `${text}-${data.edustage}-${data.edusubject}`
params.dataset_id = dataSetJson[jsonKey]
})
//
onUnmounted(() => {
emitter.off('onGetChild')
})
defineExpose({
getConversation
})
</script>
<style lang="scss" scoped>
.read-container {
display: flex;
flex-direction: column;
width: 100%;
padding: 15px 0;
height: 100%;
position: relative;
.el-scrollbar {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
}
.el-dropdown-link {
font-weight: bold;
.el-icon--right {
font-weight: bold;
}
}
.read-header {
justify-content: space-between;
align-items: center;
.add-btn {
font-size: 13px;
.icon-jiahao {
margin-right: 3px;
font-size: 14px;
}
}
}
.right-con {
display: flex;
}
.template-list {
.template-item {
background: #fff;
padding: 10px;
margin-top: 10px;
border-radius: 5px;
.item-header {
display: flex;
align-items: center;
font-size: 16px;
font-weight: bold;
color: #000;
justify-content: space-between;
.blue {
font-size: 22px;
color: #409eff;
margin-right: 5px;
}
}
.item-text {
display: flex;
margin-top: 10px;
font-size: 14px;
text-align: left;
color: #606266;
.item-icon {
width: 30px;
height: 30px;
line-height: 30px;
text-align: center;
background: #F6F6F6;
border-radius: 50%;
margin-right: 10px;
flex-shrink: 0;
}
.item-answer {
flex-direction: column;
padding-top: 5px;
:deep(.text-tit) {
font-weight: bold;
margin: 10px 0;
}
:deep(.text-num) {
padding-left: 2em;
}
}
}
.text-answer {
color: #409eff;
}
.ai-btn {
margin-top: 10px;
display: flex;
justify-content: flex-end;
.iconfont {
margin-right: 3px;
}
:deep(.el-button) {
font-size: 13px;
}
.icon-ai1 {
font-size: 18px;
}
}
}
}
.template-item-result {
background: #DDEAFD !important;
.result-item-header {
display: flex;
align-items: flex-start;
text-align: left;
font-size: 16px;
font-weight: bold;
color: #3D3D3D;
.icon-xiaoxi {
color: #5881D5;
font-weight: bold;
font-size: 20px;
margin-right: 10px;
}
}
.result-icon-btn {
justify-content: space-between;
font-size: 13px;
margin-top: 5px;
span {
display: flex;
align-items: center;
cursor: pointer;
margin-right: 10px;
&:hover {
background: #cfe0fa
}
}
.iconfont {
margin-right: 3px;
color: #3498fc;
}
}
.line {
height: 1px;
background: #D8D8D8;
margin: 10px 0;
}
.other-msg {
font-size: 13px;
.other-user {
align-items: center;
color: #BA4B0F;
font-size: 12px;
.icon-touxiang {
color: #BA4B0F;
font-weight: bold;
font-size: 16px;
margin-right: 5px;
}
}
.other-text {
color: #191919;
text-align: left;
}
}
}
}
.icon-shenglvehao {
font-weight: bold;
font-size: 22px;
}
:deep(.el-popover) {
min-width: 50px;
width: 50px !important;
}
.pl-25 {
padding-left: 25px;
}
</style>
<style>
.template-custom-popover {
width: 110px !important;
min-width: 110px !important;
}
</style>

View File

@ -0,0 +1,451 @@
<template>
<div class="container-right-page flex">
<!--头部-->
<div class="container-right-header flex">
<el-dropdown @command="changeTemplate" :hide-on-click="false">
<span class="el-dropdown-link">
{{ curTemplate.name }}
<i class="iconfont icon-xiangxia"></i>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item v-for="item in templateList" :command="item" :key="item.id">{{ item.name
}}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<div>
<el-button type="danger" link @click="removeItem(curTemplate, false)">
删除
</el-button>
<el-button type="primary" link @click="onAdd">
<i class="iconfont icon-jiahao"></i>
添加提示词
</el-button>
<el-button type="primary" :disabled="!(childTempList.length)" @click="getCompletion">一键研读</el-button>
</div>
</div>
<!--List-->
<div class="container-right-list">
<template v-for="(item, index) in childTempList">
<div class="template-item" v-loading="item.loading">
<div class="item-header">
<div>
<span class="blue">#</span>{{ item.name }}
</div>
<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)">编辑</el-button>
<el-button type="primary" link @click="removeItem(item, true)">移除</el-button>
</template>
</el-popover>
</div>
<div class="item-text">
{{ item.prompt }}
</div>
<div class="item-text text-answer" v-if="item.answer">
<div class="item-icon">
<i class="iconfont icon-ai"></i>
</div>
<div class="item-answer" v-html="item.answer"></div>
</div>
<div class="ai-btn" v-if="item.answer">
<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>
</template>
<el-empty v-if="!childTempList.length" description="暂无模板数据" />
</div>
</div>
<!--编辑结果-->
<EditDialog v-model="isEdit" :item="editItem" />
<!--AI 对话调整-->
<AdjustDialog v-model="isAdjust" :modeType="type" :item="editItem" />
<!--添加编辑提示词-->
<keywordDialog v-model="isWordDialog" :isAdd="isAdd" :item="editItem" />
</template>
<script setup>
import { ref, reactive, onMounted, computed, onUnmounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { tempSave, completion, modelList, removeChildTemp, tempResult } from '@/api/mode/index'
import keywordDialog from './keyword-dialog.vue';
import AdjustDialog from './adjust-dialog.vue'
import EditDialog from './edit-dialog.vue'
import emitter from '@/utils/mitt';
import { dataSetJson } from '@/utils/comm.js'
const props = defineProps(['curNode', 'type'])
/*****************提示词相关****************/
/**
* isWordDialog : 提示词弹窗
* isAdd 是否添加 默认false
* editItem: 当前操作的item (添加的时候不需要这个)
*/
const isWordDialog = ref(false)
const isAdd = ref(false)
const editItem = reactive({})
const onAdd = () => {
isAdd.value = true
Object.assign(editItem, curTemplate)
isWordDialog.value = true
}
const editKeyWord = (item, val) => {
/**
* isAdd: 字模板中的移除 为编辑 头部删除 添加提示词为新增
*/
isAdd.value = val
Object.assign(editItem, item)
isWordDialog.value = true
}
/*******************模板相关**********************/
/**
* curTemplate 当前模板
* templateList 主模板List
* childTempList : 子模板List
* getTemplateList() : 获取主模板
* getChildTemplate() :获取子模板
*/
const tempLoading = ref(false)
const curTemplate = reactive({ name: '', id: '' })
const templateList = ref([])
const childTempList = ref([])
const getTemplateList = () => {
modelList({ model: props.type, type: 1, pageNum: 1, pageSize: 10000 }).then(res => {
templateList.value = res.rows
Object.assign(curTemplate, res.rows[0]);
getChildTemplate()
})
}
const getChildTemplate = () => {
tempLoading.value = true
modelList({ model: props.type, type: 2, parentId: curTemplate.id }).then(res => {
childTempList.value = res.rows
getTempResult()
}).finally(() => {
tempLoading.value = false
})
}
//
const getTempResult = () => {
tempResult({ mainModelId: curTemplate.id }).then(res => {
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 changeTemplate = (val) => {
ElMessageBox.confirm(
'切换模板将清除当前研读结果?',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
).then(() => {
Object.assign(curTemplate, val);
getChildTemplate()
})
}
//
const removeItem = async (item, isChild) => {
/**
* item: 当前操作的模板
* isChild: 子模板中的移除为 true 否则为false
*/
if (item.ex3 != '1') {
ElMessageBox.confirm(
'确认是否移除?',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
).then(() => {
removeChildTemp(item.id).then(res => {
ElMessage.success('操作成功')
if(isChild){
//
getChildTemplate()
}
else{
//
getTemplateList()
}
})
})
}
else {
editKeyWord(item,!isChild)
}
}
// Ai
const curIndex = ref(-1)
const isAdjust = ref(false)
const onAdjust = (index, item) => {
curIndex.value = index
Object.assign(editItem, item)
isAdjust.value = true
}
//
const isEdit = ref(false)
const onEdit = (index, item) => {
curIndex.value = index
Object.assign(editItem, item)
isEdit.value = true
}
const modeType = computed(() => {
if (props.type == 1) return '课标';
if (props.type == 2) return '教材';
if (props.type == 3) return '考试';
})
//
const params = reactive(
{
prompt: '',
dataset_id: ''
}
)
//
const againResult = async (index, item) => {
try {
childTempList.value[index].loading = true
params.prompt = `按照${item.name}的要求,针对${props.curNode.edustage}${props.curNode.edusubject}${modeType}${props.curNode.itemtitle}进行教学分析`
const { data } = await completion(params)
let answer = data.answer
childTempList.value[index].oldAnswer = answer
childTempList.value[index].answer = getResult(answer);
onSaveTemp(item)
} finally {
childTempList.value[index].loading = false
}
}
//
const getCompletion = async () => {
for (let item of childTempList.value) {
try {
item.loading = true
params.prompt = `按照${item.name}的要求,针对${props.curNode.edustage}${props.curNode.edusubject}${modeType}${props.curNode.itemtitle}进行教学分析`
const { data } = await completion(params)
let answer = data.answer
item.oldAnswer = answer
item.answer = getResult(answer);
onSaveTemp(item)
} finally {
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)
})
}
//
emitter.on('saveAdjust', (item) => {
childTempList.value[curIndex.value].oldAnswer = item
let answer = getResult(item);
childTempList.value[curIndex.value].answer = answer
})
//
let getResult = (text) => {
text = text.replace(/^\n\n(.*?)\n\n$/s, '<div>$1</div>');
text = text.replace(/^\n(.*?)\n$/s, '<p>$1</p>');
text = text.replace(/\*\*(.*?)\*\*/g, "<div class='text-tit'>$1</div>");
text = text.replace(/(\d+\..*?)\n/g, "<div class='text-num'>$1</div>\n");
return text
}
//
emitter.on('onGetChild', () => {
getChildTemplate()
})
//
emitter.on('onGetMain', () => {
getTemplateList()
})
onMounted(() => {
getTemplateList()
let jsonKey = `${modeType}-${props.curNode.edustage}-${props.curNode.edusubject}`
params.dataset_id = dataSetJson[jsonKey]
})
//
onUnmounted(() => {
emitter.off('onGetChild');
emitter.off('saveAdjust');
})
</script>
<style lang="scss" scoped>
.container-right-page {
height: 100%;
flex-direction: column;
.container-right-header {
height: 45px;
align-items: center;
justify-content: space-between;
background: #fff;
border-left: solid #EBF0F4 1px;
box-sizing: border-box;
padding: 0 15px;
border-radius: 0 5px 0 0
}
.container-right-list {
flex: 1;
overflow-y: auto;
padding: 5px 15px;
box-sizing: border-box;
.template-item {
background: #fff;
padding: 10px;
margin-top: 10px;
border-radius: 5px;
.item-header {
display: flex;
align-items: center;
font-size: 16px;
font-weight: bold;
color: #000;
justify-content: space-between;
.blue {
font-size: 22px;
color: #409eff;
margin-right: 5px;
}
}
.item-text {
display: flex;
margin-top: 10px;
font-size: 14px;
text-align: left;
color: #606266;
.item-icon {
width: 30px;
height: 30px;
line-height: 30px;
text-align: center;
background: #F6F6F6;
border-radius: 50%;
margin-right: 10px;
flex-shrink: 0;
}
.item-answer {
flex-direction: column;
padding-top: 5px;
:deep(.text-tit) {
font-weight: bold;
margin: 10px 0;
}
:deep(.text-num) {
padding-left: 2em;
}
}
}
.text-answer {
color: #409eff;
}
.ai-btn {
margin-top: 10px;
display: flex;
justify-content: flex-end;
.iconfont {
margin-right: 3px;
}
:deep(.el-button) {
font-size: 13px;
}
.icon-ai1 {
font-size: 18px;
}
}
}
}
}
</style>
<style>
.template-custom-popover {
width: 110px !important;
min-width: 110px !important;
}
</style>

View File

@ -1,26 +1,21 @@
<template> <template>
<div class="page-template flex"> <div class="page-template flex">
<!--头部--> <el-row>
<Header :type="type" @changeTemp="changeTemp" @onRead="onRead"/>
<el-row :gutter="20" class="tempalte-main">
<el-col :span="12"> <el-col :span="12">
<!--左侧pdf--> <Left :curNode="curNode" :type="type" />
<Pdf />
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<!--右侧模板研读--> <Right :curNode="curNode" :type="type" />
<Result ref="resultRef" :modeType="type" :tempId="tempId"/>
</el-col> </el-col>
</el-row> </el-row>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref } from 'vue' import { reactive, onMounted } from 'vue'
import Header from './container/header.vue' import { sessionStore } from '@/utils/store'
import Pdf from './container/pdf.vue' import Left from './container/left.vue'
import Result from './container/result.vue' import Right from './container/right.vue'
const props = defineProps({ const props = defineProps({
type: { type: {
@ -29,22 +24,24 @@ const props = defineProps({
}, },
}) })
const curNode = reactive({})
onMounted(() =>{
let data = sessionStore.get('subject.curNode')
Object.assign(curNode, data);
})
const resultRef = ref()
const tempId = ref('')
const changeTemp = (id) =>{
tempId.value = id
}
const onRead = () =>{
resultRef.value.getConversation()
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.page-template { .page-template {
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
.el-row{
height: 100%;
.el-col{
height: 100%;
}
}
.tempalte-main { .tempalte-main {
flex: 1; flex: 1;
} }

View File

@ -117,4 +117,8 @@ export const coursewareTypeList = [
label:'素材', label:'素材',
value:6 value:6
}, },
{
label:'视频',
value:12
},
] ]

View File

@ -60,6 +60,7 @@ import { sessionStore } from '@/utils/store'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { dataSetJson } from '@/utils/comm.js' import { dataSetJson } from '@/utils/comm.js'
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
import emitter from '@/utils/mitt';
const userInfo = useUserStore().user const userInfo = useUserStore().user
const textarea = ref('') const textarea = ref('')
@ -132,6 +133,8 @@ const saveAdjust = (item) =>{
} }
const curFile = reactive({}) const curFile = reactive({})
const dataset_id = ref('') const dataset_id = ref('')
const fileList = ref([]) const fileList = ref([])
@ -144,7 +147,9 @@ const getList = () =>{
Object.assign(curFile, fileList.value[0]) Object.assign(curFile, fileList.value[0])
}) })
} }
emitter.on('curFile', (item) =>{
changeFile(item)
})
const changeFile = (val) =>{ const changeFile = (val) =>{
Object.assign(curFile, val); Object.assign(curFile, val);

View File

@ -8,16 +8,16 @@
</template> </template>
<div class="dialog-content"> <div class="dialog-content">
<div class="flex dialog-top"> <div class="flex dialog-top">
<el-radio-group v-model="radio" @change="changeRadio"> <!-- <el-radio-group v-model="radio" @change="changeRadio">
<el-radio :value="item.value" v-for="item in radioList">{{ item.label }}</el-radio> <el-radio :value="item.value" v-for="item in radioList">{{ item.label }}</el-radio>
</el-radio-group> </el-radio-group> -->
</div> </div>
<div class="content-list"> <div class="content-list">
<ul> <ul>
<li v-for="(item, index) in list" :class="activeIndex == index ? 'li-active' : ''" @click="clickItem(index)"> <li v-for="(item, index) in fileList" :class="activeIndex == index ? 'li-active' : ''" @click="clickItem(index, item)">
<el-image class="img" :src="item.url" /> <el-image class="img" :src="url" />
<span>{{ item.name }}</span> <el-text truncated>{{ item.fileName }}</el-text>
</li> </li>
</ul> </ul>
</div> </div>
@ -47,6 +47,7 @@ import { sessionStore } from '@/utils/store'
import { dataSetJson } from '@/utils/comm.js' import { dataSetJson } from '@/utils/comm.js'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
import emitter from '@/utils/mitt';
const userInfo = useUserStore().user const userInfo = useUserStore().user
const uploadFileUrl = ref(import.meta.env.VITE_APP_BASE_API + "/common/upload"); const uploadFileUrl = ref(import.meta.env.VITE_APP_BASE_API + "/common/upload");
@ -93,11 +94,7 @@ const changeRadio = () => {
}) })
} }
} }
const activeIndex = ref(-1) const activeIndex = ref(0)
const clickItem = (index) => {
activeIndex.value = index
}
const dataset_id = ref('') const dataset_id = ref('')
@ -109,7 +106,7 @@ const onSuccess = async (response) =>{
dataset_id: dataset_id.value dataset_id: dataset_id.value
} }
const res = await completion(data) const res = await completion(data)
console.log(res)
if(res.data.code != 200) return if(res.data.code != 200) return
let docData = { let docData = {
fileUrl: response.url, fileUrl: response.url,
@ -123,19 +120,30 @@ const onSuccess = async (response) =>{
} }
const { msg } = await addDoc(docData) const { msg } = await addDoc(docData)
ElMessage.success(msg) ElMessage.success(msg)
getList()
} }
const curNode = reactive({}) const curNode = reactive({})
const fileList = ref([])
const curFile = reactive({})
const getList = () =>{ const getList = () =>{
docList({ docList({
userId: userInfo.userId, userId: userInfo.userId,
dataset_id: dataset_id.value dataset_id: dataset_id.value
}).then( res =>{ }).then( res =>{
console.log(res) fileList.value = [...res.rows]
Object.assign(curFile, fileList.value[0])
}) })
} }
const clickItem = (index, item) => {
activeIndex.value = index
Object.assign(curFile, item)
emitter.emit('curFile',item)
}
onMounted(() =>{ onMounted(() =>{
let data = sessionStore.get('subject.curNode') let data = sessionStore.get('subject.curNode')
@ -174,6 +182,7 @@ onMounted(() =>{
flex-wrap: wrap; flex-wrap: wrap;
li { li {
width: 130px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
font-size: 13px; font-size: 13px;

View File

@ -42,6 +42,7 @@ import useUserStore from '@/store/modules/user'
import {ArrowDown} from '@element-plus/icons-vue' import {ArrowDown} from '@element-plus/icons-vue'
import { onMounted,ref } from 'vue'; import { onMounted,ref } from 'vue';
import { listEvaluation } from '@/api/subject/index' import { listEvaluation } from '@/api/subject/index'
import {sessionStore} from '@/utils/store'
const userStore = useUserStore().user const userStore = useUserStore().user
const subjectList = ref([]) const subjectList = ref([])
// //
@ -58,6 +59,7 @@ const getSubject = () => {
// //
const handleUserEduStage = (item) => { const handleUserEduStage = (item) => {
userStore.edustage = item userStore.edustage = item
sessionStore.set('edustage',item)
if(item === '幼儿园'){ if(item === '幼儿园'){
// //
userStore.edusubject = '语文' userStore.edusubject = '语文'
@ -74,6 +76,7 @@ const handleUserEduStage = (item) => {
// //
const handleUserEduSubject = (item) => { const handleUserEduSubject = (item) => {
userStore.edusubject = item; userStore.edusubject = item;
sessionStore.set('edusubject',item)
} }
onMounted(() => { onMounted(() => {
getSubject() getSubject()

View File

@ -165,7 +165,8 @@ setTimeout(() => {
function submit() { function submit() {
proxy.$refs.userRef.validate((valid) => { proxy.$refs.userRef.validate((valid) => {
if (valid) { if (valid) {
userStore.user.avatar = userStore.user.avatar userStore.user.edusubject = sessionStore.get('edusubject')
userStore.user.edustage = sessionStore.get('edustage')
console.log('userStore更新前', userStore.user); console.log('userStore更新前', userStore.user);
updateUserInfo(userStore.user).then((response) => { updateUserInfo(userStore.user).then((response) => {
if(response.code == 200){ if(response.code == 200){

View File

@ -32,7 +32,15 @@
</el-row> --> </el-row> -->
<el-row class="resoure-btns"> <el-row class="resoure-btns">
<el-col :span="24" class="query-row flex"> <el-col :span="24" class="query-row flex">
<div class="flex row-left"> <el-select v-model="sourceStore.query.fileSuffix" @change="sourceStore.changeSuffix" <div class="flex row-left">
<!-- 第三方资源筛选-->
<el-select v-if="isThird" v-model="sourceStore.thirdQuery.type" @change="sourceStore.thirdChangeType"
style="width: 110px">
<el-option v-for="item in coursewareTypeList" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
<el-select v-else v-model="sourceStore.query.fileSuffix" @change="sourceStore.changeSuffix"
style="width: 110px"> style="width: 110px">
<el-option v-for="item in sourceStore.resourceFormatList" :key="item.value" :label="item.label" <el-option v-for="item in sourceStore.resourceFormatList" :key="item.value" :label="item.label"
:value="item.value" /> :value="item.value" />
@ -48,7 +56,6 @@
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
</div> </div>
</template> </template>

View File

@ -7,18 +7,22 @@
<span>{{ item.name }}</span> <span>{{ item.name }}</span>
<el-button type="primary" link @click="onSelect(item)">选择模式</el-button> <el-button type="primary" link @click="onSelect(item)">选择模式</el-button>
</div> </div>
<el-scrollbar> <div class="content-list">
<div class="item-list flex"> <div class="item-list flex">
<el-card class="item-card" shadow="never" v-for="el in item.child" :key="el.id"> <el-card class="item-card" shadow="never" v-for="el in item.child" :key="el.id">
<p class="card-name">{{ el.name }}</p> <p class="card-name">
<el-text line-clamp="1" :title="el.name">
{{ el.name }}
</el-text>
</p>
<div class="card-text"> <div class="card-text">
<el-text line-clamp="2"> <el-text line-clamp="4" :title="el.prompt">
{{ el.prompt }} {{ el.prompt }}
</el-text> </el-text>
</div> </div>
</el-card> </el-card>
</div> </div>
</el-scrollbar> </div>
</div> </div>
</div> </div>
</div> </div>
@ -97,30 +101,44 @@ onMounted(() => {
justify-content: space-between; justify-content: space-between;
margin-bottom: 5px; margin-bottom: 5px;
} }
.con-item { .con-item {
margin-bottom: 20px; margin-bottom: 20px;
display: flex;
flex-direction: column
}
.item-list{
margin-bottom: 10px;
} }
.item-card { .item-card {
width: 130px; width: 130px;
font-size: 13px; font-size: 13px;
padding: 10px; padding: 10px;
margin-right: 20px; margin-right: 20px;
flex-shrink: 0;
border-radius: 10px;
:deep(.el-card__body) { :deep(.el-card__body) {
padding: 0 !important; padding: 0 !important;
} }
.card-name { .card-name {
text-align: center; text-align: center;
font-size: 14px;
} }
.card-text { .card-text {
text-align: left; text-align: left;
font-size: 12px;
.el-text{
font-size: 12px !important;
}
} }
} }
} }
} }
.content-list{
overflow-x: auto
}
.content-list::-webkit-scrollbar {
height: 8px;
}
</style> </style>

View File

@ -52,26 +52,55 @@
</template> </template>
<script setup> <script setup>
import { ref, onUnmounted, reactive } from 'vue' import { ref, onMounted, onUnmounted, reactive } from 'vue'
import { sessionStore } from '@/utils/store'
import emitter from '@/utils/mitt' import emitter from '@/utils/mitt'
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 { completion } from '@/api/mode/index.js' import { completion, tempResult } from '@/api/mode/index.js'
import { dataSetJson } from '@/utils/comm.js'
const resultList = ref([]) const resultList = ref([])
emitter.on('changeMode', (item) => { emitter.on('changeMode', (item) => {
console.log(item, 'item')
resultList.value = item.child resultList.value = item.child
conversation() // conversation()
getTempResult(item.id)
}) })
//
const getTempResult = (id) => {
tempResult({ mainModelId: id }).then(res => {
console.log(res, 2000)
let rows = res.rows
if (rows.length > 0) {
resultList.value.forEach(item => {
rows.forEach(el => {
if (item.id == el.modelId) {
item.answer = el.content
item.reultId = el.id
}
})
})
}
})
}
const params = reactive(
{
prompt: '',
dataset_id: ''
}
)
const conversation = async () => { const conversation = async () => {
for (let item of resultList.value) { for (let item of resultList.value) {
item.loading = true item.loading = true
try { try {
const { data } = await completion({ params.prompt = `按照${item.prompt}的要求,针对${curNode.edustage}${curNode.edusubject}课标对${curNode.itemtitle}进行教学分析`
dataset_id: 'cee3062a9fcf11efa6910242ac140006', const { data } = await completion(params)
prompt: item.prompt
})
item.answer = data.answer item.answer = data.answer
} finally { } finally {
item.loading = false item.loading = false
@ -89,10 +118,8 @@ const curItem = reactive({})
const againResult = async (index, item) => { const againResult = async (index, item) => {
try { try {
resultList.value[index].loading = true resultList.value[index].loading = true
const { data } = await completion({ params.prompt = `按照${item.prompt}的要求,针对${curNode.edustage}${curNode.edusubject}课标对${curNode.itemtitle}进行教学分析`
dataset_id: 'cee3062a9fcf11efa6910242ac140006', const { data } = await completion(params)
prompt: item.prompt
})
resultList.value[index].answer = data.answer resultList.value[index].answer = data.answer
} finally { } finally {
resultList.value[index].loading = false resultList.value[index].loading = false
@ -106,7 +133,7 @@ const onAdjust = (index, item) => {
Object.assign(curItem, item) Object.assign(curItem, item)
isAdjust.value = true isAdjust.value = true
} }
emitter.on('changeAdjust', (item) =>{ emitter.on('changeAdjust', (item) => {
resultList.value[curIndex.value].answer = item resultList.value[curIndex.value].answer = item
}) })
@ -122,6 +149,17 @@ emitter.on('changeResult', (item) => {
}) })
const curNode = reactive({})
onMounted(() => {
let data = sessionStore.get('subject.curNode')
Object.assign(curNode, data);
let jsonKey = `课标-${data.edustage}-${data.edusubject}`
params.dataset_id = dataSetJson[jsonKey]
})
// //
onUnmounted(() => { onUnmounted(() => {
emitter.off('changeMode') emitter.off('changeMode')