This commit is contained in:
zhangxuelin 2024-11-12 09:31:02 +08:00
commit 21cf2c9cfa
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,70 +477,87 @@ 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,
edusubject: userStore.edusubject,
edustage: userStore.edustage,
//
//
worktype: entpCourseWorkQueryParams.worktype.label,
workTypeId: entpCourseWorkQueryParams.worktype.value,
//
workgroup: entpCourseWorkQueryParams.workgroup,
//
yearStr: entpCourseWorkQueryParams.yearStr !== '-1' ? entpCourseWorkQueryParams.yearStr:'',
//
thirdId: entpCourseWorkQueryParams.point.length > 0 ? entpCourseWorkQueryParams.point[0]:'',
//
keyword: entpCourseWorkQueryParams.keyWord && entpCourseWorkQueryParams.keyWord !== '' ? entpCourseWorkQueryParams.keyWord:'',
const queryForm = {
//
eid: props.bookobj.levelSecondId,
sectionName: props.bookobj.coursetitle,
edusubject: userStore.edusubject,
edustage: userStore.edustage,
//
//
worktype: entpCourseWorkQueryParams.worktype.label,
workTypeId: entpCourseWorkQueryParams.worktype.value,
//
workgroup: entpCourseWorkQueryParams.workgroup,
//
yearStr: entpCourseWorkQueryParams.yearStr !== '-1' ? entpCourseWorkQueryParams.yearStr:'',
//
thirdId: entpCourseWorkQueryParams.point.length > 0 ? entpCourseWorkQueryParams.point[0]:'',
//
keyword: entpCourseWorkQueryParams.keyWord && entpCourseWorkQueryParams.keyWord !== '' ? entpCourseWorkQueryParams.keyWord:'',
}
const entpcourseworkres = listEntpcourseworkNew(queryForm);
resolve(entpcourseworkres);
})
}
//
// pageNum: paginationParams.pageNum,
// pageSize: paginationParams.pageSize,
const handleQueryFromEntpCourseWork= async (queryType) => {
pageParams.value.loading = true;
// ( warn: )
// if (this.courseObj.edusubject=='' && this.courseObj.edustage=='') {
// // [+][+]
// 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;
// }
if(entpcourseworkres.data&&entpcourseworkres.data.length>0){
workResource.entpCourseWorkList = entpcourseworkres.data;
workResource.entpCourseWorkTotal = entpcourseworkres.data.length;
workResource.entpCourseWorkList.forEach(item=> {
if (item.worktype == '选择题') {
item.worktype = '单选题'
}
})
//
processList(workResource.entpCourseWorkList);
}else{
client(t('任务1', 1500)).then(res => {
console.log("请求返回",res);
if(paginationParams.pageNum == 1){
workResource.entpCourseWorkList = [];
workResource.entpCourseWorkTotal = 0
workResource.entpCourseWorkTotal = 0;
//
// 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;
data.forEach(item=> {
if (item.worktype == '选择题') {
item.worktype = '单选题'
}
})
//
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,7 +1144,47 @@ 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>
<style src="@/assets/styles/JYStyle.css"></style>

View File

@ -1,81 +1,147 @@
<template>
<div class="read-container">
<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-col :span="24">
<div class="template-item template-item-result">
<div class="result-item-header">
<i class="iconfont icon-xiaoxi"></i>
语言建构与运用是指学生在丰富的语言实践中通过主动的积累梳理和整合逐步掌握祖国语言文字特点及其运用规律形成个体言语经验......
</div>
<div class="result-icon-btn flex pl-25">
<div class="flex">
<span><i class="iconfont icon-fuzhi"></i>复制</span>
<span><i class="iconfont icon-bianji-gangbi"></i>写想法</span>
</div>
<div>
<span><i class="iconfont icon-tianjia"></i>加入备课篮</span>
<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>
<div class="line"></div>
<div class="other-msg pl-25">
<div class="other-user flex">
<i class="iconfont icon-touxiang"></i>
重庆市酉阳县二中 - 李丽
</el-col>
</el-row>
<!-- <el-row>
<el-col :span="24">
<div class="template-item template-item-result">
<div class="result-item-header">
<i class="iconfont icon-xiaoxi"></i>
语言建构与运用是指学生在丰富的语言实践中通过主动的积累梳理和整合逐步掌握祖国语言文字特点及其运用规律形成个体言语经验......
</div>
<div class="result-icon-btn flex pl-25">
<div class="flex">
<span><i class="iconfont icon-fuzhi"></i>复制</span>
<span><i class="iconfont icon-bianji-gangbi"></i>写想法</span>
</div>
<div>
<span><i class="iconfont icon-tianjia"></i>加入备课篮</span>
</div>
</div>
<div class="line"></div>
<div class="other-msg pl-25">
<div class="other-user flex">
<i class="iconfont icon-touxiang"></i>
重庆市酉阳县二中 - 李丽
</div>
<div class="other-text flex">北师大王宁老师说语言建构有两方面的含义一是指出于表达思想的目的二是指在个人言语经验的基础上逐步建构起自己的言语体系</div>
</div>
<div class="other-text flex">北师大王宁老师说语言建构有两方面的含义一是指出于表达思想的目的二是指在个人言语经验的基础上逐步建构起自己的言语体系</div>
</div>
</div>
</el-col>
</el-row>
</div>
</el-col>
</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()