模板 #31

Merged
lyc merged 1 commits from lyc-dev into main 2024-11-12 17:09:28 +08:00
13 changed files with 467 additions and 26 deletions

View File

@ -15,7 +15,6 @@ export function conversation(data) {
url: '/v1/api/new_conversation', url: '/v1/api/new_conversation',
method: 'get', method: 'get',
headers: { headers: {
isToken: true,
'Authorization':'Bearer ragflow-IwNzMxMTIyOGY0ZTExZWZiOGE2MDI0Mm', 'Authorization':'Bearer ragflow-IwNzMxMTIyOGY0ZTExZWZiOGE2MDI0Mm',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Accept': '*/*' 'Accept': '*/*'

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=1731315402630') format('woff2'), src: url('iconfont.woff2?t=1731393731097') format('woff2'),
url('iconfont.woff?t=1731315402630') format('woff'), url('iconfont.woff?t=1731393731097') format('woff'),
url('iconfont.ttf?t=1731315402630') format('truetype'); url('iconfont.ttf?t=1731393731097') format('truetype');
} }
.iconfont { .iconfont {
@ -13,6 +13,14 @@
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
.icon-tihuan:before {
content: "\e7ab";
}
.icon-fasong:before {
content: "\e692";
}
.icon-ai1:before { .icon-ai1:before {
content: "\e70a"; content: "\e70a";
} }

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,20 @@
"css_prefix_text": "icon-", "css_prefix_text": "icon-",
"description": "", "description": "",
"glyphs": [ "glyphs": [
{
"icon_id": "12730938",
"name": "替换",
"font_class": "tihuan",
"unicode": "e7ab",
"unicode_decimal": 59307
},
{
"icon_id": "34833984",
"name": "发送",
"font_class": "fasong",
"unicode": "e692",
"unicode_decimal": 59026
},
{ {
"icon_id": "41844021", "icon_id": "41844021",
"name": "ai", "name": "ai",

View File

@ -0,0 +1,260 @@
<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" :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 { conversation, completion } from '@/api/mode/index'
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({})
const params = reactive(
{
"conversation_id": "",
"messages": [
{
"role": "user",
"content": ""
}
],
"quote": false,
"stream": false
}
)
// ID
const getConversation = async (val) => {
const result = await conversation()
params.conversation_id = result.data.data.id
getCompletion(val)
}
//
const getCompletion = async (val) => {
try {
params.messages[0].content = `根据${curNode.edustage}语文课标${props.item.name}${val}`
const res = await completion(params)
console.log('对话结果===》', res)
let answer = res.data.data.answer
msgList.value.push({
type: 'robot',
msg: answer,
})
} finally {
loaded.value = false
}
}
const saveAdjust = (item) =>{
emit('saveAdjust', 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,75 @@
<template>
<el-dialog v-model="isDialog" :show-close="false" width="900">
<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'
const textarea = ref('')
const isDialog = defineModel()
const props = defineProps({
item: {
type: Object,
default: () => {
return { name: '11' }
}
}
})
watch(() => props.item.oldAnswer, (newVal) => {
if (newVal) {
textarea.value = newVal
}
},{ deep: true })
const emit = defineEmits(['saveEdit'])
const onSave = () =>{
emit('saveEdit', 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

@ -20,7 +20,7 @@
</template> </template>
</el-dropdown> </el-dropdown>
<div> <div>
<el-button type="primary" link> <el-button type="primary" link @click="keywordDialog = true">
<el-icon> <el-icon>
<Plus /> <Plus />
</el-icon> </el-icon>
@ -31,6 +31,35 @@
</div> </div>
</div> </div>
</div> </div>
<el-dialog v-model="keywordDialog" :show-close="false" width="600">
<template #header>
<div class="custom-header flex">
<span>添加提示词</span>
<i class="iconfont icon-guanbi" @click="isDialog = false"></i>
</div>
</template>
<div class="dialog-content">
<el-form :model="form" label-width="auto">
<el-form-item label="名称">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="提示词">
<el-input v-model="form.desc" type="textarea" />
</el-form-item>
</el-form>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="keywordDialog = false">取消</el-button>
<el-button type="primary" @click="keywordDialog = false">
确定
</el-button>
</div>
</template>
</el-dialog>
<Dialog v-model="showDialog" :model="model" /> <Dialog v-model="showDialog" :model="model" />
</template> </template>
@ -41,6 +70,7 @@ import { ElMessageBox } from 'element-plus'
import { modelList } from '@/api/mode/index' import { modelList } from '@/api/mode/index'
import Dialog from './dialog.vue' import Dialog from './dialog.vue'
const keywordDialog = ref(false)
const props = defineProps({ const props = defineProps({
model: { model: {
type: [String, Number], type: [String, Number],
@ -88,6 +118,11 @@ const changeTemplate = (val) => {
} }
const form = reactive({
name: '',
desc: '',
})
onMounted(() => { onMounted(() => {
getTemplateList() getTemplateList()
@ -121,4 +156,14 @@ onMounted(() => {
font-weight: bold; font-weight: bold;
} }
} }
.custom-header {
justify-content: space-between;
align-items: center;
.icon-guanbi {
cursor: pointer;
font-weight: bold;
}
}
</style> </style>

View File

@ -3,7 +3,7 @@
<el-scrollbar height="100%"> <el-scrollbar height="100%">
<div class="template-list"> <div class="template-list">
<el-row v-for="item in childTempList"> <el-row v-for="(item,index) in childTempList">
<el-col :span="24"> <el-col :span="24">
<div class="template-item" v-loading="item.loading"> <div class="template-item" v-loading="item.loading">
<div class="item-header"><span class="blue">#</span>{{ item.name }}</div> <div class="item-header"><span class="blue">#</span>{{ item.name }}</div>
@ -17,15 +17,15 @@
<div class="item-answer" v-html="item.answer"></div> <div class="item-answer" v-html="item.answer"></div>
</div> </div>
<div class="ai-btn" v-if="item.answer"> <div class="ai-btn" v-if="item.answer">
<el-button type="primary" link> <el-button type="primary" link @click="againResult(index, item)">
<i class="iconfont icon-ai1"></i> <i class="iconfont icon-ai1"></i>
重新研读 重新研读
</el-button> </el-button>
<el-button type="primary" link> <el-button type="primary" link @click="onAdjust(index, item)">
<i class="iconfont icon-duihua"></i> <i class="iconfont icon-duihua"></i>
AI对话调整 AI对话调整
</el-button> </el-button>
<el-button type="primary" link> <el-button type="primary" link @click="onEdit(index, item)">
<i class="iconfont icon-bianji1"></i> <i class="iconfont icon-bianji1"></i>
手动编辑结果 手动编辑结果
</el-button> </el-button>
@ -36,16 +36,21 @@
</div> </div>
</el-scrollbar> </el-scrollbar>
<!--编辑结果-->
<EditDialog v-model="isEdit" :item="editItem" @saveEdit="saveEdit"/>
<!--AI 对话调整-->
<AdjustDialog v-model="isAdjust" :item="editItem" @saveAdjust="saveAdjust"/>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, reactive, onMounted, watch } from 'vue'; import { ref, reactive, onMounted, watch } from 'vue';
import EditDialog from './edit-dialog.vue'
import AdjustDialog from './adjust-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 } from '@/api/mode/index' import { conversation, completion, modelList } from '@/api/mode/index'
import { modelList } from '@/api/mode/index'
const userStore = useUserStore() const userStore = useUserStore()
@ -79,17 +84,15 @@ const getChildTemplate = () => {
tempLoading.value = false tempLoading.value = false
}) })
} }
const isEdit = ref(false)
watch(() => props.tempId, (newVal) => { watch(() => props.tempId, (newVal) => {
if (newVal) { if (newVal) {
// isEdit.value = true
getChildTemplate() getChildTemplate()
} }
}) })
const loading = ref(false)
// ID // ID
const params = reactive( const params = reactive(
{ {
@ -104,22 +107,17 @@ const params = reactive(
"stream": false "stream": false
} }
) )
const isAiDeal = ref(false)
const curNode = reactive({}) const curNode = reactive({})
const getConversation = async () => { const getConversation = async () => {
const { user: { userId } } = userStore const { user: { userId } } = userStore
const result = await conversation({ user_id: String(userId) }) const result = await conversation({ user_id: String(userId) })
console.log('result',result)
params.conversation_id = result.data.data.id params.conversation_id = result.data.data.id
getCompletion() getCompletion()
} }
// //
const resultList = ref([])
const getCompletion = async () => { const getCompletion = async () => {
console.log('params=====>', params)
for (let item of childTempList.value) { for (let item of childTempList.value) {
try { try {
item.loading = true item.loading = true
@ -127,6 +125,7 @@ const getCompletion = async () => {
const res = await completion(params) const res = await completion(params)
console.log('对话结果===》', res) console.log('对话结果===》', res)
let answer = res.data.data.answer let answer = res.data.data.answer
item.oldAnswer = answer
item.answer = getResult(answer); item.answer = getResult(answer);
} finally { } finally {
@ -136,6 +135,20 @@ const getCompletion = async () => {
} }
//
const againResult = async (index,item) =>{
try{
childTempList.value[index].loading = true
params.messages[0].content = `根据${curNode.edustage}语文课标,提炼出${item.name}`
const res = await completion(params)
let answer = res.data.data.answer
item.oldAnswer = answer
item.answer = getResult(answer);
}finally {
childTempList.value[index].loading = false
}
}
// //
let getResult = (text) => { let getResult = (text) => {
@ -144,7 +157,34 @@ let getResult = (text) => {
text = text.replace(/\*\*(.*?)\*\*/g, "<div class='text-tit'>$1</div>"); text = text.replace(/\*\*(.*?)\*\*/g, "<div class='text-tit'>$1</div>");
text = text.replace(/(\d+\..*?)\n/g, "<div class='text-num'>$1</div>\n"); text = text.replace(/(\d+\..*?)\n/g, "<div class='text-num'>$1</div>\n");
return text 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
}
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
} }
onMounted(() => { onMounted(() => {

View File

@ -895,7 +895,7 @@ ol {
font-size: 14px; font-size: 14px;
color: #000; color: #000;
/deep/ .jsontree_tree { :deep(.jsontree_tree) {
font-family: 'Trebuchet MS', Arial, sans-serif !important; font-family: 'Trebuchet MS', Arial, sans-serif !important;
} }
} }

View File

@ -71,7 +71,7 @@ const getHomework = async () => {
} else if (item.worktype == '习题训练') { } else if (item.worktype == '习题训练') {
item.workclass = 'danger' item.workclass = 'danger'
} else { } else {
item.workclass = '' item.workclass = 'info'
} }
item.workdatacount = JSON.parse('[' + item.classworkdatastudentids + ']').length item.workdatacount = JSON.parse('[' + item.classworkdatastudentids + ']').length