Compare commits

...

18 Commits

Author SHA1 Message Date
zhangxuelin 21cf2c9cfa Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into zxl 2024-11-12 09:31:02 +08:00
lyc 5a1b95ea5d Merge pull request 'lyc-dev' (#22) from lyc-dev into main 2024-11-11 17:28:10 +08:00
lyc 0ec8ec7480 路由冲突 2024-11-11 17:28:49 +08:00
baigl 2c1e9923c5 Merge pull request 'baigl' (#21) from baigl into main
Reviewed-on: #21
2024-11-11 17:27:09 +08:00
白了个白 2f58722206 Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into baigl 2024-11-11 17:26:12 +08:00
白了个白 317dc9f184 1 2024-11-11 17:25:55 +08:00
lyc c3ef8d881e 模板 2024-11-11 17:16:06 +08:00
baigl 3f81e36dd9 Merge pull request 'baigl' (#20) from baigl into main
Reviewed-on: #20
2024-11-11 15:07:29 +08:00
白了个白 ecc74e4666 Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into baigl 2024-11-11 15:06:57 +08:00
白了个白 0cc3d970d1 作业设计:课程切换数据覆盖bug修复 2024-11-11 15:06:40 +08:00
baigl 3c4c035703 Merge pull request 'baigl' (#19) from baigl into main
Reviewed-on: #19
2024-11-11 10:19:10 +08:00
白了个白 a0bfb5be70 作业设计:课程选择太快增加防抖 2024-11-11 10:13:41 +08:00
白了个白 f53d7f104c Merge branch 'main' of http://27.128.240.72:3000/zhuhao/AIx_Smarttalk_WS into baigl 2024-11-11 10:03:48 +08:00
zhangxuelin 225982ec0c Merge pull request 'zxl' (#18) from zxl into main
Reviewed-on: #18
2024-11-08 17:24:13 +08:00
白了个白 cbd706fed1 习题查询:加上分页传参 2024-11-08 15:38:13 +08:00
lyc 756d7fdaa1 模板 2024-11-07 14:14:46 +08:00
lyc d05e50218d 模板 2024-11-06 17:33:32 +08:00
lyc 71e6b74dd4 调整路由 2024-11-05 00:39:06 +08:00
23 changed files with 1361 additions and 256 deletions

View File

@ -48,6 +48,11 @@ export default defineConfig({
changeOrigin: true, // 改变请求的起源
rewrite: (path) => path.replace(/^\/parth/, '') // 重写路径
},
'/v1': {
target: 'https://ai.ysaix.com:7864',
changeOrigin: true,
pathRewrite: { '^/v1': '' }
}
},
},
plugins: [vue(), WindiCSS()],

View File

@ -0,0 +1,39 @@
import request from '@/utils/request'
import axios from 'axios'
// 查询模板列表
export function modelList(params) {
return request({
url: '/education/llmModel/list',
method: 'get',
params
})
}
export function conversation(data) {
return axios({
url: '/v1/api/new_conversation',
method: 'get',
headers: {
isToken: true,
'Authorization':'Bearer ragflow-IwNzMxMTIyOGY0ZTExZWZiOGE2MDI0Mm',
'Content-Type': 'application/json',
'Accept': '*/*'
},
params: data
})
}
// 进行课标研读对话
export function completion(data) {
return axios({
url: '/v1/api/completion',
method: 'post',
headers: {
'Authorization':'Bearer ragflow-IwNzMxMTIyOGY0ZTExZWZiOGE2MDI0Mm',
'Content-Type': 'application/json',
'Accept': '*/*'
},
data: data
})
}

View File

@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 4723712 */
src: url('iconfont.woff2?t=1730448425319') format('woff2'),
url('iconfont.woff?t=1730448425319') format('woff'),
url('iconfont.ttf?t=1730448425319') format('truetype');
src: url('iconfont.woff2?t=1731315402630') format('woff2'),
url('iconfont.woff?t=1731315402630') format('woff'),
url('iconfont.ttf?t=1731315402630') format('truetype');
}
.iconfont {
@ -13,6 +13,26 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-ai1:before {
content: "\e70a";
}
.icon-duihua:before {
content: "\e60d";
}
.icon-bianji1:before {
content: "\e678";
}
.icon-a-ziyuan91:before {
content: "\e611";
}
.icon-ai:before {
content: "\e626";
}
.icon-xiaoxi:before {
content: "\e677";
}

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,41 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "41844021",
"name": "ai",
"font_class": "ai1",
"unicode": "e70a",
"unicode_decimal": 59146
},
{
"icon_id": "2286510",
"name": "对话",
"font_class": "duihua",
"unicode": "e60d",
"unicode_decimal": 58893
},
{
"icon_id": "4093249",
"name": "编辑",
"font_class": "bianji1",
"unicode": "e678",
"unicode_decimal": 59000
},
{
"icon_id": "39732311",
"name": "AI分析",
"font_class": "a-ziyuan91",
"unicode": "e611",
"unicode_decimal": 58897
},
{
"icon_id": "41784801",
"name": "ai",
"font_class": "ai",
"unicode": "e626",
"unicode_decimal": 58918
},
{
"icon_id": "2158298",
"name": "消息",

View File

@ -0,0 +1,135 @@
<template>
<el-dialog v-model="isDialog" :show-close="false" width="900">
<template #header>
<div class="custom-header flex">
<span>选择{{ title }}</span>
<i class="iconfont icon-guanbi" @click="isDialog = false"></i>
</div>
</template>
<div class="dialog-content">
<div class="flex">
<el-radio-group v-model="radio" @change="changeRadio">
<el-radio :value="item.value" v-for="item in radioList">{{ item.label }}</el-radio>
</el-radio-group>
</div>
<div class="content-list">
<ul>
<li v-for="(item, index) in list" :class="activeIndex == index ? 'li-active' : ''" @click="clickItem(index)">
<el-image class="img" :src="item.url" />
<span>{{ item.name }}</span>
</li>
</ul>
</div>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="isDialog = false">取消</el-button>
<el-button type="primary" @click="isDialog = false">
确定
</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { ref, computed } from 'vue'
const url = 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F11044b08-04c1-41a0-a453-1fd20b58a614%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1732953359&t=7ab1d1b3a903db85b1149914407aea35'
const isDialog = defineModel()
const props = defineProps({
model: {
type: [String, Number],
default: 1
}
})
const title = computed(() => {
if (props.model == 1) return '课标';
if (props.model == 2) return '教材';
if (props.model == 3) return '考试';
})
const radio = ref(1)
const radioList = ref([
{ label: '浏览研读', value: 1 },
{ label: '跨学科研读', value: 2 },
{ label: '跨学段研读', value: 3 },
{ label: '课标修订研读', value: 4 },
{ label: '自由研读', value: 5 },
])
const list = ref([
{
name: '高中语文课程标准',
url
}
])
const changeRadio = () => {
list.value = []
for (let i = 0; i < Math.floor(Math.random() * 5) + 1; i++) {
list.value.push({
name: '高中语文课程标准',
url
})
}
}
const activeIndex = ref(-1)
const clickItem = (index) => {
activeIndex.value = index
}
</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;
.content-list {
padding-top: 10px;
ul {
display: flex;
flex-wrap: wrap;
li {
display: flex;
flex-direction: column;
font-size: 13px;
padding: 10px;
cursor: pointer;
border-radius: 5px;
overflow: hidden;
margin-right: 20px;
margin-bottom: 10px;
.img {
width: 100px;
height: 130px;
border: solid #ccc 1px;
margin-bottom: 10px;
}
&:hover {
background: #E0EAFF;
}
}
.li-active {
background: #E0EAFF;
}
}
}
}
</style>

View File

@ -0,0 +1,124 @@
<template>
<div class="container-header flex">
<div class="header-left flex">
<el-button link @click="showDialog = true">
高中语文课程标准<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>
<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>
<Dialog v-model="showDialog" :model="model" />
</template>
<script setup>
import { ref, reactive, onMounted } 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'
const props = defineProps({
model: {
type: [String, Number],
default: 1
}
})
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: 1, type: 1 }).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)
})
}
onMounted(() => {
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

@ -0,0 +1,27 @@
<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')
console.log('pdfUrl.value', pdfUrl.value)
})
</script>
<style lang="scss" scoped>
.container-pdf{
height: 100%;
}
</style>

View File

@ -0,0 +1,356 @@
<template>
<div class="read-container">
<el-scrollbar height="100%">
<div class="template-list">
<el-row v-for="item in childTempList">
<el-col :span="24">
<div class="template-item" v-loading="item.loading">
<div class="item-header"><span class="blue">#</span>{{ item.name }}</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>
<i class="iconfont icon-ai1"></i>
重新研读
</el-button>
<el-button type="primary" link>
<i class="iconfont icon-duihua"></i>
AI对话调整
</el-button>
<el-button type="primary" link>
<i class="iconfont icon-bianji1"></i>
手动编辑结果
</el-button>
</div>
</div>
</el-col>
</el-row>
</div>
</el-scrollbar>
</div>
</template>
<script setup>
import { ref, reactive, onMounted, watch } from 'vue';
import { sessionStore } from '@/utils/store'
import useUserStore from '@/store/modules/user'
import { conversation, completion } from '@/api/mode/index'
import { modelList } from '@/api/mode/index'
const userStore = useUserStore()
const props = defineProps({
curTemp: {
type: Array,
default: () => {
return []
}
},
tempId: {
type: [String, Number],
default: ''
},
model: {
type: [String, Number],
default: 1
}
})
//
const tempLoading = ref(false)
const childTempList = ref([])
const getChildTemplate = () => {
tempLoading.value = true
modelList({ model: props.model, type: 2, parentId: props.tempId }).then(res => {
childTempList.value = res.rows
console.log('res.rows=====>', res.rows)
}).finally(() => {
tempLoading.value = false
})
}
watch(() => props.tempId, (newVal) => {
if (newVal) {
getChildTemplate()
}
})
const loading = ref(false)
// ID
const params = reactive(
{
"conversation_id": "",
"messages": [
{
"role": "user",
"content": ""
}
],
"quote": false,
"stream": false
}
)
const isAiDeal = ref(false)
const curNode = reactive({})
const getConversation = async () => {
const { user: { userId } } = userStore
const result = await conversation({ user_id: String(userId) })
params.conversation_id = result.data.data.id
getCompletion()
}
//
const resultList = ref([])
const getCompletion = async () => {
console.log('params=====>', params)
for (let item of childTempList.value) {
try {
item.loading = true
params.messages[0].content = `根据${curNode.edustage}语文课标,提炼出${item.name}`
const res = await completion(params)
console.log('对话结果===》', res)
let answer = res.data.data.answer
item.answer = getResult(answer);
} finally {
item.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
}
onMounted(() => {
let data = sessionStore.get('subject.curNode')
Object.assign(curNode, data);
})
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;
.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;
}
}
}
}
.pl-25 {
padding-left: 25px;
}
</style>

View File

@ -0,0 +1,44 @@
<template>
<div class="page-template flex">
<!--头部-->
<Header @changeTemp="changeTemp" @onRead="onRead"/>
<el-row :gutter="20" class="tempalte-main">
<el-col :span="12">
<!--左侧pdf-->
<Pdf />
</el-col>
<el-col :span="12">
<!--右侧模板研读-->
<Result ref="resultRef" :tempId="tempId"/>
</el-col>
</el-row>
</div>
</template>
<script setup>
import { ref } from 'vue'
import Header from './container/header.vue'
import Pdf from './container/pdf.vue'
import Result from './container/result.vue'
const resultRef = ref()
const tempId = ref('')
const changeTemp = (id) =>{
tempId.value = id
}
const onRead = () =>{
resultRef.value.getConversation()
}
</script>
<style lang="scss" scoped>
.page-template {
flex-direction: column;
height: 100%;
.tempalte-main {
flex: 1;
}
}
</style>

View File

@ -85,13 +85,13 @@ const headerMenus = [
name: '教学工作台',
id: 2,
icon: 'icon-gongzuotai',
path: '/home'
path: '/desktop'
},
{
name: '资源中心',
id: 3,
icon: 'icon-kechengziyuan1',
path: '/resource'
path: '/resource/index'
},
]
@ -100,13 +100,13 @@ const sideBottomMenu = [
name: '算力',
id: 4,
icon: 'icon-yanhouke-shengyinyichang',
path: '/hashrate'
path: '/hashrate/index'
},
{
name: '设置',
id: 5,
icon: 'icon-set',
path: '/setting'
path: '/setting/index'
},
]

View File

@ -58,23 +58,40 @@ export const constantRoutes = [
},
]
},
...toolRouters
]
const dynamicRoutes = [
{
path: '/',
component: Layout,
redirect: '/home',
redirect: '/desktop',
meta: { title: '教学工作台' },
children: [
{
path: '/home',
path: 'desktop',
component: () => import('@/views/desktop/index.vue'),
name: 'desktop',
meta: { title: '教学工作台' }
},
{
path: '/resource',
component: () => import('@/views/resource/index.vue'),
name: 'resource',
meta: { title: '资源库' }
path: 'standardanalysis',
component: () => import('@/views/teach/standardAnalysis/index.vue'),
name: 'standardanalysis',
meta: { title: '课标分析', showBread: true }
},
{
path: 'textbookAnalysis',
component: () => import('@/views/textbookAnalysis/index.vue'),
name: 'textbookAnalysis',
meta: { title: '教材分析', showBread: true }
},
{
path: 'examReport',
component: () => import('@/views/examReport/index.vue'),
name: 'examReport',
meta: { title: '考试分析', showBread: true }
},
{
path: 'prepare',
@ -82,24 +99,33 @@ export const constantRoutes = [
name: 'prepare',
meta: { title: '教学实践', showBread: true }
},
{
path: 'newClassTask',
component: () => import('@/views/classTask/newClassTask.vue'),
name: 'newClassCorrect',
meta: { title: '作业设计', showBread: true }
},
{
path: 'classTaskAssign',
component: () => import('@/views/classTask/classTaskAssign.vue'),
name: 'classTaskAssign',
meta: { title: '作业布置', showBread: true }
},
{
path: 'classTask',
component: () => import('@/views/classTask/classTask.vue'),
name: 'classCorrect',
meta: { title: '作业批改', showBread: true }
},
{
path: '/teach',
component: () => import('@/views/teach/index.vue'),
name: 'teach',
meta: { title: '授课' }
},
{
path: '/standardanalysis',
component: () => import('@/views/teach/standardAnalysis/index.vue'),
name: 'standardanalysis',
meta: { title: '课标分析', showBread: true }
},
{
path: '/textbookAnalysis',
component: () => import('@/views/textbookAnalysis/index.vue'),
name: 'textbookAnalysis',
meta: { title: '教材分析', showBread: true }
},
{
path: '/profile',
component: () => import('@/views/profile/index.vue'),
@ -125,42 +151,6 @@ export const constantRoutes = [
name: 'class',
meta: { title: '班级中心' }
},
{
path: '/classTaskAssign',
component: () => import('@/views/classTask/classTaskAssign.vue'),
name: 'classTaskAssign',
meta: { title: '作业布置', showBread: true }
},
{
path: '/classTask',
component: () => import('@/views/classTask/classTask.vue'),
name: 'classCorrect',
meta: { title: '作业批改', showBread: true }
},
{
path: '/newClassTask',
component: () => import('@/views/classTask/newClassTask.vue'),
name: 'newClassCorrect',
meta: { title: '作业设计', showBread: true }
},
{
path: '/examReport',
component: () => import('@/views/examReport/index.vue'),
name: 'examReport',
meta: { title: '考试分析', showBread: true }
},
{
path: '/hashrate',
component: () => import('@/views/hashrate/index.vue'),
name: 'hashrate',
meta: { title: '算力' }
},
{
path: '/setting',
component: () => import('@/views/setting/index.vue'),
name: 'setting',
meta: { title: '设置' }
},
{
path: '/joinSchool',
component: () => import('@/views/joinSchool/index.vue'),
@ -179,14 +169,50 @@ export const constantRoutes = [
name: 'schoolManagement',
meta: {title: '学校管理'}
},
]
},
...toolRouters
{
path: '/resource',
component: Layout,
children: [
{
path: 'index',
component: () => import('@/views/resource/index.vue'),
name: 'resource',
meta: { title: '资源库' },
}
]
},
{
path: '/hashrate',
component: Layout,
children: [
{
path: 'index',
component: () => import('@/views/hashrate/index.vue'),
name: 'hashrate',
meta: { title: '算力' },
}
]
},
{
path: '/setting',
component: Layout,
children: [
{
path: 'index',
component: () => import('@/views/setting/index.vue'),
name: 'setting',
meta: { title: '设置' },
}
]
}
]
const router = createRouter({
history: createWebHashHistory(), //hash 模式
routes: constantRoutes
routes: [...constantRoutes,...dynamicRoutes]
})
export default router

View File

@ -89,8 +89,8 @@
</el-col>
</el-row>
<!-- 习题表格 -->
<div class="middle" >
<el-table :data="workResource.entpCourseWorkList" style="width: 100%; height: 100%;">
<div class="infinite-list-wrapper" >
<!-- <el-table :data="workResource.entpCourseWorkList" style="width: 100%; height: 100%;">
<el-table-column type="index" width="60" />
<el-table-column align="left" >
<template #header>
@ -114,7 +114,48 @@
<el-button type="primary" @click="handleClassWorkQuizAdd('entpcourseworklist', scope.row.id)">添加</el-button>
</template>
</el-table-column>
</el-table>
</el-table> -->
<ul
v-infinite-scroll="pageLoad"
class="infinite-list"
infinite-scroll-immediate="false"
infinite-scroll-distance='1'
infinite-scroll-delay="1000"
:infinite-scroll-disabled="pageDisabled"
>
<li v-for="(item,index) in workResource.entpCourseWorkList" :key="item" class="infinite-list-item">
<div align="left" style="width: 100%;" >
<!-- <template #header>
<div style="display: flex">
<div style="align-items: center;">题目内容</div>
</div>
</template> -->
<div @click="showExamAnalyseDrawer(item)">
<div>
<span style="width: 20px;">{{ index +1 }}. </span>
<span style="overflow: hidden; text-overflow: ellipsis" v-html="item.titleFormat"></span>
</div>
<div style="overflow: hidden; text-overflow: ellipsis; font-size: 0.9em; margin-top: 6px;" v-html="item.workdescFormat"></div>
<el-col :span="24" style="display: flex">
<div style="font-size: 1em; color: silver; padding-top: 5px">{{ item.entpname }} {{ item.editusername }}</div>
<div style="margin-left: 30px; font-size: 1em; color: silver; padding-top: 5px">{{ item.worktag }}</div>
</el-col>
</div>
</div>
<div align="right" style="width: 72px;">
<el-button type="primary" @click="handleClassWorkQuizAdd('entpcourseworklist', item.id)">添加</el-button>
</div>
</li>
</ul>
<p class="infinite-list-loading" v-if="pageParams.loading">加载中...</p>
<p class="infinite-list-noMove" v-if="pageNoMore">无更多试题...</p>
<div v-if="workResource.entpCourseWorkList.length == 0 && !pageParams.loading">
<el-empty
description="未找到相关试题"
style="width: 100%; height: 200px; margin-top: 20px;"
></el-empty>
</div>
</div>
<!-- 分页 这里不用-->
<!-- <div style="height: 55px;">
@ -231,14 +272,14 @@
</template>
<script setup>
import { onMounted, ref, nextTick, watch, reactive, getCurrentInstance } from 'vue'
import { onMounted, ref, nextTick, watch, reactive, getCurrentInstance, computed } from 'vue'
import { ElMessage } from 'element-plus'
import { cloneDeep } from 'lodash'
import { useRouter } from 'vue-router'
import {listEntpcoursework, listEntpcourseworkNew, getEntpcoursework} from '@/api/education/entpCourseWork'
import { addClassworkReturnId } from '@/api/teaching/classwork'
import { updateClasswork, listEvaluationclue,readFile, listClassworkeval,delClassworkeval,addClassworkeval,updateClassworkeval } from '@/api/classTask'
import { updateClasswork, listEvaluationclue, listClassworkeval,delClassworkeval,addClassworkeval,updateClassworkeval } from '@/api/classTask'
import { listEvaluation } from '@/api/subject'
import { listEntpcoursefile } from '@/api/education/entpcoursefile'
import { listKnowledgePoint } from "@/api/knowledge/knowledgePoint";
@ -250,8 +291,9 @@ import FileUpload from "@/components/FileUpload/index.vue";
import whiteboard from '@/components/whiteboard/whiteboard.vue'
import prevReadMsgDialog from '@/views/classTask/container/newTask/prevReadMsg-Dialog.vue'
import examDetailsDrawer from '@/components/exam-question/examDetailsDrawer.vue'
import { JYApiListCT, JYApiListOriginYear, JYApiListSO} from "@/utils/examQuestion/jyeoo"
import {throttle,debounce } from '@/utils/comm'
import { useToolState } from '@/store/modules/tool'
import useUserStore from '@/store/modules/user'
const userStore = useUserStore().user
@ -365,6 +407,24 @@ const boardLoading = ref(false);
//----------
const fileLoading = ref(false); // loading
//
const BASE_LIMIT_COUT = 50; //
const pageNoMore = computed( () => {
if (pageParams.value.total < 1) {
return false;
}
let count = BASE_LIMIT_COUT >= pageParams.value.total ? pageParams.value.total : pageParams.value.originCount+BASE_LIMIT_COUT;
return workResource.entpCourseWorkList.length >= count;
});
const pageDisabled = computed(() => pageParams.value.loading || pageNoMore.value);
const pageParams = ref({
loading: false, //
originCount: 0, //
isFirst: true, //
total: 0,
})
/***
* 作业类型切换
*/
@ -382,9 +442,33 @@ const changeFormType = (val) => {
const handleQueryParamFromEntpCourseWork = (queryType) => {
//
// this.paginationParams = {pageNum: 1,pageSize: 10};
//
initPageParams();
handleQueryFromEntpCourseWork(queryType);
};
let obj = {};
function Apis(key) {
obj[key] = [];
return function(task) {
return new Promise((resolve, reject) => {
obj[key].push(task);
Promise.all([...obj[key]]).then(res => {
const i = obj[key].findIndex(item => {
return item == task;
});
resolve(obj[key][i]);
//arr.splice(i, 1);
})
})
}
}
const client = new Apis('/paht');
/**
* @desc: 1习题训练 - 新查询试题
* @return: {*}
@ -393,11 +477,12 @@ const handleQueryParamFromEntpCourseWork = (queryType) => {
* 1 - 按条件查询
* 2 - 按关键词查询
*/
const handleQueryFromEntpCourseWork= (queryType) => {
//queryForm.pageNum = this.paginationParams.pageNum;
//queryForm.pageSize = this.paginationParams.pageSize;
const t = function(name, time) {
return new Promise(resolve => {
const queryForm = {
//
currentPage: paginationParams.pageNum,
pageSize: paginationParams.pageSize,
//
eid: props.bookobj.levelSecondId,
sectionName: props.bookobj.coursetitle,
@ -417,10 +502,15 @@ const handleQueryFromEntpCourseWork= (queryType) => {
keyword: entpCourseWorkQueryParams.keyWord && entpCourseWorkQueryParams.keyWord !== '' ? entpCourseWorkQueryParams.keyWord:'',
}
const entpcourseworkres = listEntpcourseworkNew(queryForm);
resolve(entpcourseworkres);
})
}
const handleQueryFromEntpCourseWork= async (queryType) => {
pageParams.value.loading = true;
//
// pageNum: paginationParams.pageNum,
// pageSize: paginationParams.pageSize,
// ( warn: )
// if (this.courseObj.edusubject=='' && this.courseObj.edustage=='') {
@ -428,35 +518,46 @@ const handleQueryFromEntpCourseWork= (queryType) => {
// queryForm.edusubject = '';
// }
listEntpcourseworkNew(queryForm).then(entpcourseworkres => {
// if (queryType == 1 && this.entpCourseWorkQueryParams.worktype == '') {
// // ,
// const allowedWorkTypes = ['', '', '', '', ''];
// workResource.entpCourseWorkList = entpcourseworkres.rows.filter(item => {
// return !allowedWorkTypes.includes(item.worktype);
// });
// } else {
// workResource.entpCourseWorkList = entpcourseworkres.rows;
// }
client(t('任务1', 1500)).then(res => {
console.log("请求返回",res);
if(paginationParams.pageNum == 1){
workResource.entpCourseWorkList = [];
workResource.entpCourseWorkTotal = 0;
if(entpcourseworkres.data&&entpcourseworkres.data.length>0){
workResource.entpCourseWorkList = entpcourseworkres.data;
workResource.entpCourseWorkTotal = entpcourseworkres.data.length;
//
// pageParams.value.loading = false;
// pageParams.value.isFirst = true;
// pageParams.value.originCount = 0;
}
const data = res.data || [];
if(data && data.length>0){
// workResource.entpCourseWorkList = entpcourseworkres.data;
// workResource.entpCourseWorkTotal = entpcourseworkres.data.length;
workResource.entpCourseWorkList.forEach(item=> {
data.forEach(item=> {
if (item.worktype == '选择题') {
item.worktype = '单选题'
}
})
//
processList(workResource.entpCourseWorkList);
}else{
workResource.entpCourseWorkList = [];
workResource.entpCourseWorkTotal = 0
processList(data);
workResource.entpCourseWorkList.push(...data);
//
if (pageParams.value.isFirst) {
pageParams.value.isFirst = false;
pageParams.value.originCount = workResource.entpCourseWorkList.length;
pageParams.value.total = parseInt(res.msg);
}
})
}
pageParams.value.loading = false;
});
//const entpcourseworkres = await listEntpcourseworkNew(queryForm);
// const data = entpcourseworkres.data;
}
//
@ -877,6 +978,29 @@ const showExamAnalyseDrawer = (row) => {
}
const pageLoad = async() => {
console.log("加载中...")
paginationParams.pageNum ++ ,
//paginationParams.pageSize = 2,
await handleQueryFromEntpCourseWork(0);
}
const initPageParams = () => {
//
workResource.entpCourseWorkList = [];
workResource.entpCourseWorkTotal = 0
//
pageParams.value.loading = false;
pageParams.value.isFirst = true;
pageParams.value.originCount = 0;
pageParams.value.total = 0;
//
paginationParams.pageNum = 1;
paginationParams.pageSize = 10;
}
onMounted(async() => {
//
@ -893,21 +1017,46 @@ onMounted(async() => {
})
watch(() => props.propsformobj.uniquekey, (newVal) => {
console.log(props.propsformobj,'propsformobj')
if(props.propsformobj.uniquekey){
classWorkForm.uniquekey = props.propsformobj.uniquekey?cloneDeep(props.propsformobj.uniquekey):''; //
}
})
watch(() => props.bookobj.levelSecondId, (newVal) => {
console.log(props.bookobj,'课程选择')
// const refreshData = () => {
// console.log("")
// //
// initPageParams();
// //
// handleQueryFromEntpCourseWork(0);
// //
// getQueryFromEvaluationclue();
// //
// getEntpCourseWorkPointList();
// }
// //
// const debounceQueryData = debounce(throttle(refreshData, 1000), 1000);
//
const debounceQueryData = debounce(() => {
console.log("防抖 加载数据中...")
//
initPageParams();
//
handleQueryFromEntpCourseWork(0);
//
getQueryFromEvaluationclue();
//
getEntpCourseWorkPointList();
}, 1000);
watch(() => props.propsformobj.uniquekey, (newVal) => {
console.log(props.propsformobj,'propsformobj')
if(props.propsformobj.uniquekey){
classWorkForm.uniquekey = props.propsformobj.uniquekey?cloneDeep(props.propsformobj.uniquekey):''; //
}
})
watch(() => props.bookobj.levelSecondId, (newVal, oldVal) => {
console.log(props.bookobj,'课程选择')
debounceQueryData();
})
</script>
<style lang="scss" scoped>
@ -995,6 +1144,46 @@ watch(() => props.bookobj.levelSecondId, (newVal) => {
box-sizing: border-box;
background-color: rgb(231, 231, 231)
}
.infinite-list-wrapper{
height: 100%;
text-align: center;
overflow: auto;
.infinite-list {
padding: 0;
margin: 0;
list-style: none;
.infinite-list-item {
display: flex;
align-items: center;
//justify-content: center;
//height: 50px;
//background: var(--el-color-primary-light-9);
padding: 10px;
border-top: 1px solid #eee;
//color: var(--el-color-primary);
}
.infinite-list-item:hover {
background-color: #F3F5F8;
}
.infinite-list-item + .list-item {
margin-top: 10px;
}
}
.infinite-list-loading{
padding: 10px 0;
border-top: 1px solid #eee;
color: red;
}
.infinite-list-noMove{
padding: 10px 0;
border-top: 1px solid #eee;
color: #999;
}
}
}
</style>

View File

@ -1,43 +1,22 @@
<template>
<div class="read-container">
<el-scrollbar height="100%">
<div class="template-list" v-loading="loading">
<el-row v-for="item in 6">
<el-col :span="24">
<div class="template-item">
<div class="item-header"><span class="blue">#</span>{{ item }}</div>
<div class="item-text" >
<div class="item-icon">
<i class="iconfont icon-ai"></i>
</div>
<div class="item-answer" v-html="item"></div>
</div>
</div>
</el-col>
</el-row>
<div class="template-list">
<el-row>
<el-col :span="24">
<div class="template-item">
<div class="item-header"><span class="blue">#</span>核心素养与课程目标</div>
<div class="item-text">研读课程标准提取出与本课相关的核心素养与课程目标</div>
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<div class="template-item">
<div class="item-header"><span class="blue">#</span>课程内容相关</div>
<div class="item-text">研读课程标准提取出与本课相关的课程内容要求
</div>
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<div class="template-item">
<div class="item-header"><span class="blue">#</span>学业质量要求</div>
<div class="item-text">研读课程标准提取出与本课相关的学业水平要求包括水平一水平二水平三各自的要求描述
</div>
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<div class="template-item">
<div class="item-header"><span class="blue">#</span>教学实施建议</div>
<div class="item-text">研读课程标准提取出与本课相关的教学实施建议
</div>
</div>
</el-col>
</el-row>
<el-row>
<!-- <el-row>
<el-col :span="24">
<div class="template-item template-item-result">
<div class="result-item-header">
@ -63,19 +42,106 @@
</div>
</div>
</el-col>
</el-row>
</el-row> -->
</div>
</el-scrollbar>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { sessionStore } from '@/utils/store'
import useUserStore from '@/store/modules/user'
import { conversation, completion } from '@/api/mode/index'
const userStore = useUserStore()
const props = defineProps({
curTemp: {
type: Array,
default: () =>{
return []
}
}
})
const loading = ref(false)
// ID
const params = reactive(
{
"conversation_id": "",
"messages": [
{
"role": "user",
"content": ""
}
],
"quote": false,
"stream": false
}
)
const curNode = reactive({})
const getConversation = async() =>{
const { user: { userId } } = userStore
const result = await conversation({ user_id: String(userId) })
params.conversation_id = result.data.data.id
getCompletion()
}
//
const resultList = ref([])
const getCompletion = async() =>{
console.log('params=====>',params)
for (const item of props.curTemp) {
try {
loading.value = true
params.messages[0].content = `根据${curNode.edustage}语文课标,提炼出${item.name}`
const res = await completion(params)
console.log('对话结果===》', res)
let answer = res.data.data.answer
answer = getResult(answer);
resultList.value.push({
title: item.name,
answer
})
} finally{
loading.value = 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
}
onMounted(() => {
let data = sessionStore.get('subject.curNode')
Object.assign(curNode, data);
console.log(props.curTemp,'curTemp')
// getConversation()
})
</script>
<style lang="scss" scoped>
.read-container {
display: flex;
flex-direction: column;
width: 100%;
padding: 15px;
height: 100%;
.el-dropdown-link {
font-weight: bold;
@ -98,6 +164,9 @@
}
}
.right-con{
display: flex;
}
.template-list {
@ -123,10 +192,32 @@
.item-text {
display: flex;
margin-top: 10px;
color: #409eff;
font-size: 13px;
padding-left: 20px;
text-align: left;
.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;
}
}
}
}
}

View File

@ -1,65 +1,80 @@
<template>
<div class="read-container">
<div class="read-header flex">
<el-dropdown>
<el-dropdown @command="changeTemplate">
<span class="el-dropdown-link">
课标研读模板
{{ curTemplate.name }}
<i class="iconfont icon-xiangxia" </i>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>课标研读模板一</el-dropdown-item>
<el-dropdown-item>课标研读模板二</el-dropdown-item>
<el-dropdown-item v-for="item in templateList" :command="item" :key="item.id">{{ item.name
}}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<el-button text class="add-btn">
<i class="iconfont icon-jiahao"></i>
添加
</el-button>
<el-button type="primary" @click="aiRead">一键研读</el-button>
</div>
<div class="template-list">
<el-row>
<div class="template-list" v-loading="tempLoading">
<el-row v-for="item in childTempList" :key="item.id">
<el-col :span="24">
<div class="template-item">
<div class="item-header"><span class="blue">#</span>核心素养与课标目标</div>
<div class="item-text">研读课程标准提取出与本课相关的核心素养与课程目标</div>
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<div class="template-item">
<div class="item-header"><span class="blue">#</span>课程内容要求</div>
<div class="item-text">研读课程标准提取出与本课相关的课程内容要求
</div>
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<div class="template-item">
<div class="item-header"><span class="blue">#</span>学业质量要求</div>
<div class="item-text">研读课程标准提取出与本课相关的学业水平要求包括水平一水平二水平三各自的要求描述
</div>
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<div class="template-item">
<div class="item-header"><span class="blue">#</span>教学实施建议</div>
<div class="item-text">研读课程标准提取出与本课相关的教学实施建议
</div>
<div class="item-header"><span class="blue">#</span>{{ item.name }}</div>
<div class="item-text">{{ item.prompt }}</div>
</div>
</el-col>
</el-row>
<el-empty v-if="!childTempList.length" description="暂无模板数据" />
</div>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { modelList} from '@/api/mode/index'
//
const curTemplate = reactive({ name: '', id: '' })
//
const templateList = ref([])
//
const getTemplateList = () => {
modelList({ model: 1, type: 1 }).then(res => {
templateList.value = res.rows
Object.assign(curTemplate, res.rows[0]);
getChildTemplate()
})
}
//
const changeTemplate = (val) => {
Object.assign(curTemplate, val);
getChildTemplate()
}
//
const tempLoading = ref(false)
const childTempList = ref([])
const getChildTemplate = () => {
tempLoading.value = true
modelList({ model: 1, type: 2, parentId: curTemplate.id }).then(res => {
childTempList.value = res.rows
}).finally(() => {
tempLoading.value = false
})
}
const emit = defineEmits(['changeMenu'])
const aiRead = async () => {
emit('changeMenu', childTempList.value)
}
onMounted(() => {
getTemplateList()
})
</script>
<style lang="scss" scoped>
@ -78,15 +93,6 @@
justify-content: space-between;
align-items: center;
.add-btn {
font-size: 13px;
.icon-jiahao {
margin-right: 3px;
font-size: 14px;
}
}
}
.template-list {

View File

@ -1,5 +1,6 @@
<template>
<div class="page-curriculum flex">
<TemplateStudy/>
<!-- <div class="page-curriculum flex">
<el-row>
<el-col :span="12" class="flex">
<div class="page-left">
@ -31,18 +32,19 @@
}}</el-button>
</div>
<div class="right-con">
<ReadTemplate v-if="activeMenu == 1" />
<ReadTemplate v-if="activeMenu == 1" @changeMenu="changeMenu" />
<QuestionAnswer v-if="activeMenu == 2" />
<ReadResult v-if="activeMenu == 3" />
<ReadResult v-if="activeMenu == 3" :curTemp="curTemp" />
</div>
</div>
</el-col>
</el-row>
</div>
</div> -->
</template>
<script setup>
import { ref } from 'vue'
import TemplateStudy from '@/components/template-study/index.vue'
import ReadTemplate from './container/read-template.vue';
import QuestionAnswer from './container/question-answer.vue'
import ReadResult from './container/read-result.vue'
@ -93,6 +95,12 @@ const onClickMenu = (item) => {
activeMenu.value = item.value
}
const curTemp = ref([])
const changeMenu = (data) =>{
activeMenu.value = 3
curTemp.value = data
}
</script>

View File

@ -70,19 +70,19 @@ const menuList = [{
{
name: '课标分析',
icon: '#icon-kebiao',
path: '/standardanalysis?',
path: 'standardanalysis?',
id: '1-1'
},
{
name: '教材分析',
icon: '#icon-jiaocaixuanze',
path: '/textbookAnalysis',
path: 'textbookAnalysis',
id: '1-2'
},
{
name: '考试分析',
icon: '#icon-kaoshi',
path: '/examReport',
path: 'examReport',
id: '1-3'
},
{
@ -115,7 +115,7 @@ const menuList = [{
icon: '#icon-zuoyesheji',
// isOuter: true,
// path: '/teaching/classtaskassign?titleName=&openDialog=newClassTask',
path: '/newClassTask',
path: 'newClassTask',
id: '2-1'
},
{
@ -123,13 +123,13 @@ const menuList = [{
icon: '#icon-zuoyebuzhi',
// isOuter: true,
// path: '/teaching/classtaskassign?titleName=',
path: '/classTaskAssign',
path: 'classTaskAssign',
id: '2-2'
},
{
name: '作业批改',
icon: '#icon-zuoyepigai',
path: '/classTask',
path: 'classTask',
id: '2-3'
},
{

View File

@ -170,7 +170,7 @@ const getregisterinfo=()=>{
//
const closed=()=>{
if (ruleFormRef.value) ruleFormRef.value.resetFields()
router.push("/home")
router.push("/")
}
onMounted(async () => {
getUser()

View File

@ -2,8 +2,8 @@
<div>
<div class="mb-4">
<el-button type="primary" @click="onchange('/model/curriculum')">课标研读</el-button>
<el-button type="success" @click="onchange('/model/teaching')">教材研读</el-button>
<el-button type="info" @click="onchange('/model/examination')">考试分析</el-button>
<!-- <el-button type="success" @click="onchange('/model/teaching')">教材研读</el-button> -->
<!-- <el-button type="info" @click="onchange('/model/examination')">考试分析</el-button> -->
</div>
</div>
</template>

View File

@ -183,7 +183,7 @@ const submitForm = async (formEl) => {
//
const closed=()=>{
if (ruleFormRef.value) ruleFormRef.value.resetFields()
router.push("/home")
router.push("/")
}
onMounted(() => {
getUser()