Merge branch 'main' into qinqing_dev
This commit is contained in:
commit
47329aea75
|
@ -16,7 +16,7 @@ win:
|
||||||
nsis:
|
nsis:
|
||||||
oneClick: false
|
oneClick: false
|
||||||
allowToChangeInstallationDirectory: true
|
allowToChangeInstallationDirectory: true
|
||||||
artifactName: ${name}-${version}-setup.${ext}
|
artifactName: ${name}-${version}-test.${ext}
|
||||||
shortcutName: ${productName}
|
shortcutName: ${productName}
|
||||||
uninstallDisplayName: ${productName}
|
uninstallDisplayName: ${productName}
|
||||||
createDesktopShortcut: always
|
createDesktopShortcut: always
|
||||||
|
|
|
@ -43,6 +43,11 @@ export default defineConfig({
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (p) => p.replace(/^\/baidubce/, '')
|
rewrite: (p) => p.replace(/^\/baidubce/, '')
|
||||||
},
|
},
|
||||||
|
'/parth': {
|
||||||
|
target: 'https://zwapi.xfyun.cn', // 第三方API的地址
|
||||||
|
changeOrigin: true, // 改变请求的起源
|
||||||
|
rewrite: (path) => path.replace(/^\/parth/, '') // 重写路径
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [vue(), WindiCSS()],
|
plugins: [vue(), WindiCSS()],
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "aix-win",
|
"name": "aix-win",
|
||||||
"version": "2.1.5",
|
"version": "2.1.12",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "./out/main/index.js",
|
"main": "./out/main/index.js",
|
||||||
"author": "example.com",
|
"author": "example.com",
|
||||||
|
|
|
@ -243,6 +243,81 @@ export default async function ({ app, shell, BrowserWindow, ipcMain }) {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/*创建新的ppt文件*/
|
||||||
|
ipcMain.on('creat-ai-file-default', (e, { name, url, uploadData, cookie }) => {
|
||||||
|
createFolder('tempFile').then(async () => {
|
||||||
|
let lastname = decodeURIComponent(url);
|
||||||
|
name = lastname.substring(lastname.lastIndexOf("/")+1)
|
||||||
|
let path = appTempFilePath + name.replace(/[\\/:*?"<>|]/, '')
|
||||||
|
let {type,item} = await downloadFiles(url,name)
|
||||||
|
if (type==="成功") {
|
||||||
|
let fileType = 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
|
||||||
|
let formData = new FormData()
|
||||||
|
for (let key in uploadData) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(uploadData, key)) {
|
||||||
|
// 检查是否是对象自身的属性
|
||||||
|
formData.append(key, uploadData[key])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
formData.append('fileFlag', '课件')
|
||||||
|
uploadFileByFS({
|
||||||
|
url: uploadUrl,
|
||||||
|
path,
|
||||||
|
name,
|
||||||
|
cookie,
|
||||||
|
fileType,
|
||||||
|
formData,
|
||||||
|
success: (response) => {
|
||||||
|
e.reply('creat-ai-file-default-reply', response.data)
|
||||||
|
console.log('File uploaded successfully:', response.data)
|
||||||
|
},
|
||||||
|
error: (err) => {
|
||||||
|
console.error('Error uploading file:', err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}else {
|
||||||
|
e.reply('creat-ai-file-default-reply', type)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
function downloadFiles(url,fileName) {
|
||||||
|
console.log(url,fileName)
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
const browserWindow = BrowserWindow.getFocusedWindow()
|
||||||
|
const id = manager.download({
|
||||||
|
window: browserWindow,
|
||||||
|
url: url,
|
||||||
|
saveAsFilename: fileName,
|
||||||
|
directory: appTempFilePath,
|
||||||
|
callbacks: {
|
||||||
|
onDownloadStarted: async ({ id, item, webContents }) => {
|
||||||
|
// Do something with the download id
|
||||||
|
},
|
||||||
|
onDownloadProgress: async ({ id, item, percentCompleted }) => {
|
||||||
|
// console.log(percentCompleted)
|
||||||
|
},
|
||||||
|
onDownloadCompleted: async ({ id, item }) => {
|
||||||
|
console.log('完成')
|
||||||
|
resolve({type:"成功",item})
|
||||||
|
},
|
||||||
|
onDownloadCancelled: async () => {
|
||||||
|
console.log("取消")
|
||||||
|
reject({type:"取消了下载"})
|
||||||
|
},
|
||||||
|
onDownloadInterrupted: async () => {
|
||||||
|
console.log('中断')
|
||||||
|
reject({type:"下载被中断"})
|
||||||
|
},
|
||||||
|
onError: (err, data) => {
|
||||||
|
console.log(err.toString())
|
||||||
|
reject({type:"下载出错",err})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
//获取应用文件目录
|
//获取应用文件目录
|
||||||
ipcMain.on('get-root-file-path', (e) => {
|
ipcMain.on('get-root-file-path', (e) => {
|
||||||
e.reply('get-root-file-path-reply', appRootFilePath)
|
e.reply('get-root-file-path-reply', appRootFilePath)
|
||||||
|
|
|
@ -18,6 +18,14 @@ export function listClassworkdataByDeadDate(query) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 查询classworkdata详细
|
||||||
|
export function getClassworkdata(id) {
|
||||||
|
return request({
|
||||||
|
url: '/education/classworkdata/' + id,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 查询classworkdata列表 班级作业列表
|
// 查询classworkdata列表 班级作业列表
|
||||||
export function listClassworkdata(query) {
|
export function listClassworkdata(query) {
|
||||||
return request({
|
return request({
|
||||||
|
|
|
@ -55,14 +55,15 @@ import { saveByClassWorkArray } from '@/api/teaching/classwork'
|
||||||
import useUserStore from '@/store/modules/user'
|
import useUserStore from '@/store/modules/user'
|
||||||
import { getCurrentTime } from '@/utils/date'
|
import { getCurrentTime } from '@/utils/date'
|
||||||
import { uniqBy, groupBy } from 'lodash'
|
import { uniqBy, groupBy } from 'lodash'
|
||||||
|
import { sessionStore } from '@/utils/store'
|
||||||
|
|
||||||
const model = defineModel({ type: Boolean, default: false })
|
const model = defineModel({ type: Boolean, default: false })
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
entpcourseid: {
|
entpcourseid: {
|
||||||
default: ''
|
default: ''
|
||||||
},
|
},
|
||||||
row: {
|
rows: {
|
||||||
default: ''
|
default: []
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -211,6 +212,8 @@ const delStudent = (index) => {
|
||||||
|
|
||||||
const onSubmit = (formEl) => {
|
const onSubmit = (formEl) => {
|
||||||
if (!formEl) return
|
if (!formEl) return
|
||||||
|
// 课堂id
|
||||||
|
const classRoomId = sessionStore.get('curClassRoom.id')
|
||||||
formEl.validate((valid) => {
|
formEl.validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
/**
|
/**
|
||||||
|
@ -222,31 +225,34 @@ const onSubmit = (formEl) => {
|
||||||
let ary = []
|
let ary = []
|
||||||
for (const value in gradeObj) {
|
for (const value in gradeObj) {
|
||||||
//这些参数 参照AIx web端 作业推送
|
//这些参数 参照AIx web端 作业推送
|
||||||
let obj = {
|
for (var i = 0; i < props.rows.length; i++) {
|
||||||
id: 0,
|
let obj = {
|
||||||
parentid: props.row.id,
|
id: 0,
|
||||||
classid: value,
|
parentid: props.rows[i].id,
|
||||||
classcourseid: 0,
|
classid: value,
|
||||||
entpcourseid: props.entpcourseid,
|
classcourseid: 0, // 课堂id-ppt为字符串不能使用
|
||||||
studentlist: JSON.stringify(gradeObj[value]),
|
classReservId: classRoomId, // 课堂id
|
||||||
feedback: form.feedback,
|
entpcourseid: props.entpcourseid,
|
||||||
workkey: '',
|
studentlist: JSON.stringify(gradeObj[value]),
|
||||||
timelength: form.timelength,
|
feedback: form.feedback,
|
||||||
weights: 1,
|
workkey: '',
|
||||||
deaddate: form.deaddate,
|
timelength: form.timelength,
|
||||||
workdate: getCurrentTime('YYYY-MM-DD'),
|
weights: 1,
|
||||||
uniquekey: props.row.uniquekey,
|
deaddate: form.deaddate,
|
||||||
entpcourseworklist: '[' + props.row.entpcourseworklist + ']',
|
workdate: getCurrentTime('YYYY-MM-DD'),
|
||||||
needMsgNotifine: 'false',
|
uniquekey: props.rows[i].uniquekey,
|
||||||
msgkey: 'newclasswork',
|
entpcourseworklist: '[' + props.rows[i].entpcourseworklist + ']',
|
||||||
title: '作业任务',
|
needMsgNotifine: 'false',
|
||||||
msgcontent: '',
|
msgkey: 'newclasswork',
|
||||||
teachername: userInfo.nickName,
|
title: '作业任务',
|
||||||
unixstamp: new Date().getTime(),
|
msgcontent: '',
|
||||||
worktype: props.row.worktype,
|
teachername: userInfo.nickName,
|
||||||
status: '1'
|
unixstamp: new Date().getTime(),
|
||||||
|
worktype: props.rows[i].worktype,
|
||||||
|
status: '1'
|
||||||
|
}
|
||||||
|
ary.push(obj)
|
||||||
}
|
}
|
||||||
ary.push(obj)
|
|
||||||
}
|
}
|
||||||
setLoading.value = true
|
setLoading.value = true
|
||||||
saveByClassWorkArray({
|
saveByClassWorkArray({
|
||||||
|
@ -280,8 +286,9 @@ const cloneDialog = (formEl) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 默认当前
|
// 默认当前 改为 延后3小时后截止
|
||||||
form.deaddate = getCurrentTime('YYYY-MM-DD HH:mm')
|
// form.deaddate = getCurrentTime('YYYY-MM-DD HH:mm')
|
||||||
|
form.deaddate = `${getCurrentTime('YYYY-MM-DD')} ${getCurrentTime('HH+3')}:${getCurrentTime('mm')}`;
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
import { listEntpcoursework,getEvaluationclue } from '@/api/classTask';
|
||||||
|
import { processList } from '@/hooks/useProcessList';
|
||||||
|
|
||||||
|
const isJson = (str) => {
|
||||||
|
if (typeof str == 'string') {
|
||||||
|
try {
|
||||||
|
let obj = JSON.parse(str)
|
||||||
|
if (typeof obj == 'object' && obj) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 编辑作业配置
|
||||||
|
* @param {*} row
|
||||||
|
*/
|
||||||
|
export const editListItem = (row, courseObj) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
// 作业内容编辑-跳转到设计界面-传参
|
||||||
|
let classtaskObj = {
|
||||||
|
id: '', //
|
||||||
|
bookName: '', // 课程名称
|
||||||
|
uniquekey: '', // 设计中的标题
|
||||||
|
title: '', // 设计中的说明
|
||||||
|
worktype: '', // 设计中的作业类型
|
||||||
|
quizlist: [], // 设计中的试题列表
|
||||||
|
chooseWorkLists: [],// 设计中的框架梳理list
|
||||||
|
fileHomeworkList: [],// 设计中的常规作业list
|
||||||
|
whiteboardObj: '',// 设计中的课堂展示对象
|
||||||
|
};
|
||||||
|
console.log('编辑的行', row);
|
||||||
|
|
||||||
|
//重新更新[新任务]中右侧列表数据
|
||||||
|
var listCourseWork = [];
|
||||||
|
for (var i=0; i < row.entpcourseworklistarray.length; i++) {
|
||||||
|
listCourseWork.push(row.entpcourseworklistarray[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listCourseWork.length > 0) {
|
||||||
|
classtaskObj.id= row.id; //
|
||||||
|
classtaskObj.bookObj = courseObj; // 教材对象
|
||||||
|
classtaskObj.bookName = row.evaltitle? row.evalparenttitle? row.evalparenttitle+'/'+row.evaltitle : row.evaltitle: row.evalparenttitle// 课程名称:单元/章节: 单元
|
||||||
|
classtaskObj.uniquekey= row.uniquekey; // 设计中的标题
|
||||||
|
classtaskObj.title= row.title; // 设计中的说明
|
||||||
|
classtaskObj.worktype= row.worktype; // 设计中的作业类型
|
||||||
|
classtaskObj.quizlist= []; // 设计中的试题列表
|
||||||
|
classtaskObj.chooseWorkLists = []; //设计中的 框架梳理list
|
||||||
|
classtaskObj.fileHomeworkList = []; //设计中的 常规作业list
|
||||||
|
classtaskObj.whiteboardObj = ''; //设计中的 课堂展示对象
|
||||||
|
|
||||||
|
|
||||||
|
if (row.worktype == '框架梳理') {
|
||||||
|
// 框架梳理对应只有一个内容
|
||||||
|
getEvaluationclue(listCourseWork[0].id).then(res => {
|
||||||
|
if ( res.data==null || res.data==undefined ) {
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
res.data.worktype = '框架梳理';
|
||||||
|
res.data.score = listCourseWork[0].score;
|
||||||
|
classtaskObj.chooseWorkLists.push(res.data);
|
||||||
|
//
|
||||||
|
// console.log('框架梳理', classtaskObj);
|
||||||
|
return resolve(classtaskObj);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (row.worktype == '习题训练') {
|
||||||
|
const ids = listCourseWork.map(item => item.id).join(",");
|
||||||
|
listEntpcoursework({ids: ids, pageSize: 50}).then(idres => {
|
||||||
|
// for (var i=0; i<idres.rows.length; i++) {
|
||||||
|
// idres.rows[i].titletext = idres.rows[i].title.replace(/<[^>]+>/g, '');
|
||||||
|
// }
|
||||||
|
// 格式化试题
|
||||||
|
if(idres.rows&&idres.rows.length > 0){
|
||||||
|
processList(idres.rows);
|
||||||
|
//重新将task中的分值更新
|
||||||
|
row.entpcourseworklistarray.forEach(item => {
|
||||||
|
const quizItem = idres.rows.find(quiz => quiz.id === item.id);
|
||||||
|
if (quizItem) {
|
||||||
|
quizItem.score = item.score;
|
||||||
|
quizItem.scoreOrigin = item.score;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
classtaskObj.quizlist = idres.rows;
|
||||||
|
//
|
||||||
|
// console.log('习题训练', classtaskObj);
|
||||||
|
return resolve(classtaskObj);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else if (row.worktype == '课堂展示') {
|
||||||
|
console.log('row.课堂展示', row.workcodes);
|
||||||
|
const workcodes = JSON.parse(row.workcodes);
|
||||||
|
classtaskObj.whiteboardObj = JSON.stringify(workcodes.json);
|
||||||
|
//
|
||||||
|
// console.log('课堂展示', classtaskObj);
|
||||||
|
return resolve(classtaskObj);
|
||||||
|
}
|
||||||
|
else if (row.worktype == '常规作业') {
|
||||||
|
if(isJson(row.workcodes)){
|
||||||
|
classtaskObj.fileHomeworkList = JSON.parse(row.workcodes);
|
||||||
|
//
|
||||||
|
// console.log('常规作业', classtaskObj);
|
||||||
|
return resolve(classtaskObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -71,6 +71,7 @@ const getHomeWorkList = async () => {
|
||||||
return await homeworklist({
|
return await homeworklist({
|
||||||
entpcourseid: chapterId,
|
entpcourseid: chapterId,
|
||||||
edituserid: userStore.user.userId,
|
edituserid: userStore.user.userId,
|
||||||
|
orderby: "timestamp DESC",
|
||||||
pageSize: 100,
|
pageSize: 100,
|
||||||
status: '10'
|
status: '10'
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
|
@ -79,7 +80,25 @@ const getHomeWorkList = async () => {
|
||||||
for (var i = 0; i < res.rows.length; i++) {
|
for (var i = 0; i < res.rows.length; i++) {
|
||||||
res.rows[i].taskconfig = []
|
res.rows[i].taskconfig = []
|
||||||
|
|
||||||
// 找child
|
// 处理任务类型的UI
|
||||||
|
// if (res.rows[i].worktype == '学习目标定位') {
|
||||||
|
// res.rows[i].workclass = 'success';
|
||||||
|
// res.rows[i].workcodesList = JSON.parse(res.rows[i].workcodes);
|
||||||
|
// } else
|
||||||
|
// 课标研读 目标设定 教材研读 框架梳理 学科定位 TODO 后续接入在添加
|
||||||
|
if (res.rows[i].worktype == '课堂展示') {
|
||||||
|
res.rows[i].workclass = 'primary';
|
||||||
|
} else if (res.rows[i].worktype == '框架梳理') {
|
||||||
|
res.rows[i].workclass = 'warning';
|
||||||
|
} else if (res.rows[i].worktype == '常规作业') {
|
||||||
|
res.rows[i].workclass = 'info';
|
||||||
|
} else if (res.rows[i].worktype == '习题训练') {
|
||||||
|
res.rows[i].workclass = 'danger';
|
||||||
|
} else {
|
||||||
|
res.rows[i].workclass = 'primary';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 找child
|
||||||
for (var j = 0; j < res.rows.length; j++) {
|
for (var j = 0; j < res.rows.length; j++) {
|
||||||
if (res.rows[j].parentid == res.rows[i].id) {
|
if (res.rows[j].parentid == res.rows[i].id) {
|
||||||
var ss = []
|
var ss = []
|
||||||
|
|
|
@ -10,12 +10,12 @@
|
||||||
<li class="flex" :class="[activeId == menu.path ? 'active-li' : '', menu.disabled ? 'disabled' : '']"
|
<li class="flex" :class="[activeId == menu.path ? 'active-li' : '', menu.disabled ? 'disabled' : '']"
|
||||||
v-for="menu in headerMenus" :key="menu.id" @click="clickMenu(menu)">
|
v-for="menu in headerMenus" :key="menu.id" @click="clickMenu(menu)">
|
||||||
<div class="icon-box">
|
<div class="icon-box">
|
||||||
|
|
||||||
|
|
||||||
<svg class="icon iconfont" aria-hidden="true">
|
<svg class="icon iconfont" aria-hidden="true">
|
||||||
<use :xlink:href="menu.icon"></use>
|
<use :xlink:href="menu.icon"></use>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<span class="text">{{ menu.name }}</span>
|
<span class="text">{{ menu.name }}</span>
|
||||||
</li>
|
</li>
|
||||||
|
@ -80,6 +80,8 @@ import { updateUserInfo } from '@/api/system/user'
|
||||||
import logoIco from '@/assets/images/logo.png'
|
import logoIco from '@/assets/images/logo.png'
|
||||||
import { listEvaluation } from '@/api/classManage/index'
|
import { listEvaluation } from '@/api/classManage/index'
|
||||||
import { sessionStore } from '@/utils/store'
|
import { sessionStore } from '@/utils/store'
|
||||||
|
// import Chat from '@/utils/chat' // im 登录初始化
|
||||||
|
// if (!Chat.imChat) Chat.init()
|
||||||
|
|
||||||
let homeTitle = ref(import.meta.env.VITE_APP_TITLE)
|
let homeTitle = ref(import.meta.env.VITE_APP_TITLE)
|
||||||
const { ipcRenderer } = window.electron || {}
|
const { ipcRenderer } = window.electron || {}
|
||||||
|
@ -143,6 +145,7 @@ function handleCommand(command) {
|
||||||
break
|
break
|
||||||
case 'logout':
|
case 'logout':
|
||||||
logout()
|
logout()
|
||||||
|
// Chat?.logout() // im 退出登录
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
|
@ -158,7 +161,9 @@ function logout() {
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
type: 'warning'
|
type: 'warning'
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(async () => {
|
||||||
|
const Chat = (await import('@/utils/chat')).default
|
||||||
|
if (!!Chat.imChat) Chat.logout()
|
||||||
userStore
|
userStore
|
||||||
.logOut()
|
.logOut()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
@ -169,8 +174,7 @@ function logout() {
|
||||||
// router.replace('/login')
|
// router.replace('/login')
|
||||||
ipcRenderer && ipcRenderer.send('openLoginWindow')
|
ipcRenderer && ipcRenderer.send('openLoginWindow')
|
||||||
})
|
})
|
||||||
})
|
}).catch(()=>{})
|
||||||
.catch(() => { })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const emits = defineEmits(['setLayout'])
|
const emits = defineEmits(['setLayout'])
|
||||||
|
@ -180,10 +184,10 @@ function setLayout() {
|
||||||
// 切换学科
|
// 切换学科
|
||||||
const changeSubject = async (command) =>{
|
const changeSubject = async (command) =>{
|
||||||
let sessionSubject = {
|
let sessionSubject = {
|
||||||
bookList: null,
|
bookList: null,
|
||||||
curBook: null,
|
curBook: null,
|
||||||
curNode: null,
|
curNode: null,
|
||||||
defaultExpandedKeys: [],
|
defaultExpandedKeys: [],
|
||||||
subjectTree: []
|
subjectTree: []
|
||||||
}
|
}
|
||||||
sessionStore.set( 'subject', sessionSubject)
|
sessionStore.set( 'subject', sessionSubject)
|
||||||
|
|
|
@ -19,8 +19,11 @@ import AppMain from './components/AppMain.vue'
|
||||||
import Uploader from './components/Uploader.vue'
|
import Uploader from './components/Uploader.vue'
|
||||||
import AiChart from '@/components/ai-chart/index.vue'
|
import AiChart from '@/components/ai-chart/index.vue'
|
||||||
import uploaderState from '@/store/modules/uploader'
|
import uploaderState from '@/store/modules/uploader'
|
||||||
|
// import Chat from '@/utils/chat'
|
||||||
|
|
||||||
let uploaderStore = ref(uploaderState())
|
let uploaderStore = ref(uploaderState())
|
||||||
|
// window.test = Chat
|
||||||
|
// Chat.init()
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,10 @@ export class ImChat {
|
||||||
// 日志监听
|
// 日志监听
|
||||||
this.timChat.TIMSetLogCallback({
|
this.timChat.TIMSetLogCallback({
|
||||||
callback: data => {
|
callback: data => {
|
||||||
this.setConsole('%cchat-log ', data[1])
|
const [type, log] = data
|
||||||
|
if (type == log_level) { // 打印对应日志
|
||||||
|
this.setConsole('%cchat-log ', log)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
user_data: ''
|
user_data: ''
|
||||||
})
|
})
|
||||||
|
@ -86,7 +89,7 @@ export class ImChat {
|
||||||
if (code == 0) { // 初始化成功
|
if (code == 0) { // 初始化成功
|
||||||
this.setConsole('%cim-chat: init', '初始化成功')
|
this.setConsole('%cim-chat: init', '初始化成功')
|
||||||
this.status.isConnect = true
|
this.status.isConnect = true
|
||||||
this.setConfig() // 设置日志级别
|
// this.setConfig() // 设置日志级别
|
||||||
resolve(this)
|
resolve(this)
|
||||||
} else { // 失败:具体请看code
|
} else { // 失败:具体请看code
|
||||||
console.error('[im-chat]:初始化失败', code)
|
console.error('[im-chat]:初始化失败', code)
|
||||||
|
@ -227,10 +230,11 @@ export class ImChat {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 删除群组
|
// 删除群组
|
||||||
deleteGroup() {
|
deleteGroup(timGroupId) {
|
||||||
if (!this.timGroupId) return
|
const groupId = timGroupId || this.timGroupId
|
||||||
|
if (!groupId) return
|
||||||
return this.timChat.TIMGroupDelete({
|
return this.timChat.TIMGroupDelete({
|
||||||
groupId: this.timGroupId,
|
groupId,
|
||||||
data: '', // 用户自定义数据
|
data: '', // 用户自定义数据
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -249,7 +253,7 @@ export class ImChat {
|
||||||
}
|
}
|
||||||
// 获取群组列表
|
// 获取群组列表
|
||||||
getGroupList() {
|
getGroupList() {
|
||||||
return this.timChat.getGroupList().then(res => {
|
return this.timChat.TIMGroupGetJoinedGroupList().then(res => {
|
||||||
console.log('获取群组列表', res)
|
console.log('获取群组列表', res)
|
||||||
return res
|
return res
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
|
@ -281,8 +285,11 @@ export class ImChat {
|
||||||
// callback: (data) => {}
|
// callback: (data) => {}
|
||||||
}
|
}
|
||||||
// console.log('发送消息', option)
|
// console.log('发送消息', option)
|
||||||
this.setConsole('%cim-chat: 发送消息', option)
|
this.setConsole('%cim-chat: 发送消息【req】', conv_id, msg)
|
||||||
return this.timChat.TIMMsgSendMessageV2(option)
|
return this.timChat.TIMMsgSendMessageV2(option).then(res => {
|
||||||
|
this.setConsole('%cim-chat: 发送消息【res】', JSON.stringify(res))
|
||||||
|
return res
|
||||||
|
})
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @description 发送群消息
|
* @description 发送群消息
|
||||||
|
|
|
@ -18,7 +18,7 @@ export const useToolState = defineStore('tool', {
|
||||||
showBoardAll: false, // 全屏画板-是否显示
|
showBoardAll: false, // 全屏画板-是否显示
|
||||||
isPdfWin: false, // pdf窗口是否打开
|
isPdfWin: false, // pdf窗口是否打开
|
||||||
isToolWin: false, // 工具窗口是否打开
|
isToolWin: false, // 工具窗口是否打开
|
||||||
isTaskWin: false, // 批改窗口是否打开
|
isTaskWin: false, // 批改窗口是否打开
|
||||||
curSubjectNode: {
|
curSubjectNode: {
|
||||||
querySearch: {} // 查询资源所需参数
|
querySearch: {} // 查询资源所需参数
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
import axios from "axios";
|
||||||
|
import { getSignature } from "./index";
|
||||||
|
|
||||||
|
let appId = "01ec9aa3";
|
||||||
|
let secret = "M2QxMDAxMjYyYTEzODMwMGRkZTQ4NmUy";
|
||||||
|
let timestamp = Math.floor(Date.now() / 1000);
|
||||||
|
let signature = getSignature(appId, secret, timestamp);
|
||||||
|
|
||||||
|
export function text2Text(data) {
|
||||||
|
return axios({
|
||||||
|
url: "v1/chat/completions",
|
||||||
|
method: "post",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Authorization: "Bearer yjCwlZCeUtBYvjHAQZdk:FtWNmJSWcZMCmTBQZfoH",
|
||||||
|
Accept: "*/*",
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
model: "4.0Ultra",
|
||||||
|
messages: data,
|
||||||
|
stream: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
export function uploadDoc(data) {
|
||||||
|
return axios({
|
||||||
|
url: "openapi/v1/file/upload",
|
||||||
|
method: "post",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "multipart/form-data",
|
||||||
|
appId: appId,
|
||||||
|
timestamp: timestamp,
|
||||||
|
signature: signature,
|
||||||
|
},
|
||||||
|
data: data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
export function queryDocStatus(data) {
|
||||||
|
return axios({
|
||||||
|
url: "openapi/v1/file/status",
|
||||||
|
method: "post",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/form-data",
|
||||||
|
appId: appId,
|
||||||
|
timestamp: timestamp,
|
||||||
|
signature: signature,
|
||||||
|
},
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
export function chatByDoc(fileId, data) {
|
||||||
|
const wsUrl = `wss://chatdoc.xfyun.cn/openapi/chat?fileId=${fileId}&appId=${appId}×tamp=${timestamp}&signature=${signature}`;
|
||||||
|
|
||||||
|
const ws = new WebSocket(wsUrl);
|
||||||
|
|
||||||
|
ws.onopen = () => {
|
||||||
|
const messageBody = {
|
||||||
|
fileIds: [fileId],
|
||||||
|
messages: data,
|
||||||
|
chatExtends: {
|
||||||
|
wikiPromptTpl:
|
||||||
|
"请将以下内容作为已知信息:\n<wikicontent>\n请根据以上内容回答用户的问题。\n问题:<wikiquestion>\n回答:",
|
||||||
|
wikiFilterScore: 0.82,
|
||||||
|
temperature: 0.5,
|
||||||
|
sparkWhenWithoutEmbedding: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.send(JSON.stringify(messageBody));
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onmessage = (event) => {
|
||||||
|
const response = JSON.parse(event.data);
|
||||||
|
console.log("WebSocket 消息:", response);
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onerror = (error) => {
|
||||||
|
console.error("WebSocket 错误:", error);
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
/**
|
||||||
|
* 实现单例模式
|
||||||
|
*/
|
||||||
|
import useUserStore from '@/store/modules/user'
|
||||||
|
import { ImChat } from '@/plugins/imChat'
|
||||||
|
import * as http from '@/api/apiService' // 自定义api service
|
||||||
|
|
||||||
|
export class Chat {
|
||||||
|
instance = null;
|
||||||
|
sdkAppId = 0; // 应用id
|
||||||
|
sign = ''; // 签名
|
||||||
|
imUserId = ''; // 用户id
|
||||||
|
imChat = null; // IM实例
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
if (!Chat.instance) { // 存在的时候
|
||||||
|
Chat.instance = this;
|
||||||
|
}
|
||||||
|
return Chat.instance;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 初始化 获取IM签名
|
||||||
|
* @param {*} isInit : 是否初始化IM
|
||||||
|
* @param {*} isLogin : 是否登录IM
|
||||||
|
* @param {*} callback: 监听消息回调函数
|
||||||
|
* @returns Promise<ImChat>
|
||||||
|
*/
|
||||||
|
async init(isInit = true, isLogin = true, callback) {
|
||||||
|
// 特殊处理,只传1个参数且为函数,则默认为callback,isInit和isLogin默认为true
|
||||||
|
if (typeof isInit == 'function'){
|
||||||
|
callback = isInit
|
||||||
|
isInit = true
|
||||||
|
isLogin = true
|
||||||
|
}
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const { timuserid: imUserId } = userStore.user
|
||||||
|
// 获取腾讯云签名
|
||||||
|
const res = await http.imChat.getTxCloudSign({imUserId})
|
||||||
|
if (res && res.code == 200) {
|
||||||
|
const { sdkAppId, sign } = res.data
|
||||||
|
this.sdkAppId = sdkAppId
|
||||||
|
this.sign = sign
|
||||||
|
this.imUserId = imUserId
|
||||||
|
// 初始化IM
|
||||||
|
if (isInit) return await this.initIM(isLogin, callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 初始化IM
|
||||||
|
async initIM(isLogin, callback) {
|
||||||
|
const imChat = new ImChat(this.sdkAppId, this.sign, this.imUserId)
|
||||||
|
this.imChat = imChat
|
||||||
|
await imChat.init() // 初始化IM
|
||||||
|
callback && this.listenMsg(callback) // 监听消息
|
||||||
|
if(isLogin) await imChat.login() // 登录IM
|
||||||
|
return imChat
|
||||||
|
}
|
||||||
|
// 监听消息
|
||||||
|
async listenMsg(callback) {
|
||||||
|
if (!callback) return
|
||||||
|
if (!this.imChat) return
|
||||||
|
await this.imChat?.watch(msg => callback(msg))
|
||||||
|
}
|
||||||
|
// 解散群
|
||||||
|
async dismissGroup(groupId) {
|
||||||
|
if (!this.imChat) return
|
||||||
|
await this.imChat?.deleteGroup(groupId)
|
||||||
|
}
|
||||||
|
// 退出登录
|
||||||
|
async logout() {
|
||||||
|
if (!this.imChat) return
|
||||||
|
await this.imChat?.logout()
|
||||||
|
this.imChat = null
|
||||||
|
}
|
||||||
|
// 发群消息
|
||||||
|
async sendMsg(conv_id, msg) {
|
||||||
|
if (!this.imChat) return
|
||||||
|
await this.imChat?.sendMsg(conv_id, msg)
|
||||||
|
}
|
||||||
|
// 发群消息
|
||||||
|
async sendMsgGroup(msg, head, type) {
|
||||||
|
if (!this.imChat) return
|
||||||
|
this.imChat?.sendMsgGroup(msg, head, type)
|
||||||
|
}
|
||||||
|
// 发群消息
|
||||||
|
async sendMsgGroupId(groupId, msg, head, type) {
|
||||||
|
if (!this.imChat) return
|
||||||
|
const msgObj = this.imChat?.getMsgObj(head, msg, type)
|
||||||
|
this.imChat?.sendMsg(groupId, msgObj)
|
||||||
|
}
|
||||||
|
// 获取群列表
|
||||||
|
async getGroupList() {
|
||||||
|
if (!this.imChat) return
|
||||||
|
return await this.imChat?.getGroupList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new Chat()
|
|
@ -0,0 +1,33 @@
|
||||||
|
import CryptoJS from 'crypto-js';
|
||||||
|
|
||||||
|
// 生成签名的主方法
|
||||||
|
export function getSignature(appId, secret, ts) {
|
||||||
|
try {
|
||||||
|
const auth = md5(appId + ts);
|
||||||
|
return hmacSHA1Encrypt(auth, secret);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error generating signature:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MD5 加密
|
||||||
|
function md5(cipherText) {
|
||||||
|
try {
|
||||||
|
return CryptoJS.MD5(cipherText).toString(); // 使用 CryptoJS 进行 MD5 加密
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error in MD5 hashing:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HMAC-SHA1 加密
|
||||||
|
function hmacSHA1Encrypt(encryptText, encryptKey) {
|
||||||
|
try {
|
||||||
|
// 使用 CryptoJS 进行 HMAC-SHA1 加密,并转换为 Base64 格式
|
||||||
|
return CryptoJS.HmacSHA1(encryptText, encryptKey).toString(CryptoJS.enc.Base64);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error in HMAC-SHA1 encryption:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
import axios from "axios";
|
||||||
|
import { getSignature } from "./index";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
let appId = "01ec9aa3";
|
||||||
|
let secret = "M2QxMDAxMjYyYTEzODMwMGRkZTQ4NmUy";
|
||||||
|
let timestamp = Math.floor(Date.now() / 1000);
|
||||||
|
let signature = getSignature(appId, secret, timestamp);
|
||||||
|
let req = (url, type, data)=>{
|
||||||
|
let config = {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
appId: appId,
|
||||||
|
timestamp: timestamp,
|
||||||
|
signature: signature,
|
||||||
|
},
|
||||||
|
url: url,
|
||||||
|
method: type,
|
||||||
|
}
|
||||||
|
if (type === "GET") {
|
||||||
|
config.params = data;
|
||||||
|
} else {
|
||||||
|
config.data = data;
|
||||||
|
}
|
||||||
|
return request(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*const instance = axios.create({
|
||||||
|
// baseURL: import.meta.env.VITE_APP_ENV === "development"?"/parth":import.meta.env.VITE_APP_BASE_API,
|
||||||
|
baseURL: "/dev-api",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
'Authorization': 'Bearer ' + getToken(),
|
||||||
|
appId: appId,
|
||||||
|
timestamp: timestamp,
|
||||||
|
signature: signature,
|
||||||
|
},
|
||||||
|
});*/
|
||||||
|
|
||||||
|
const createOutline = async (data) => {
|
||||||
|
console.log("createOutline data:", data);
|
||||||
|
try {
|
||||||
|
const response = await req(
|
||||||
|
"/api/aippt/createOutline",
|
||||||
|
"POST",
|
||||||
|
data
|
||||||
|
);
|
||||||
|
console.log("createOutline response:", response);
|
||||||
|
if (response.code == 81002) {
|
||||||
|
ElMessage.error("并发数量超过限制");
|
||||||
|
}
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("请求失败:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const getBackGround = async () => {
|
||||||
|
try {
|
||||||
|
const response = await req("/api/aippt/themeList", "GET");
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("请求失败:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const createPPT = async (data) => {
|
||||||
|
try {
|
||||||
|
const response = await req("/api/aippt/create", "POST", data);
|
||||||
|
console.log("createOutline response:", response);
|
||||||
|
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("请求失败:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const createByOutline = async (data) => {
|
||||||
|
try {
|
||||||
|
const response = await req("/api/aippt/createByOutline","POST", data);
|
||||||
|
console.log("createByOutline response:", response);
|
||||||
|
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("请求失败:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const getProgress = async (id) => {
|
||||||
|
try {
|
||||||
|
const response = await req(`/api/aippt/progress?sid=${id}`, "GET");
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("请求失败:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export { createOutline, getBackGround, createPPT, getProgress, createByOutline };
|
|
@ -96,3 +96,19 @@ export const creatPPT = (name, uploadData) => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const creatAIPPT = (name, url, uploadData) => {
|
||||||
|
JSON.parse(JSON.stringify(uploadData))
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let cookie = localStorage.getItem('Admin-Token')
|
||||||
|
ipcRenderer.send('creat-ai-file-default', {
|
||||||
|
name,
|
||||||
|
url,
|
||||||
|
uploadData: JSON.parse(JSON.stringify(uploadData)),
|
||||||
|
cookie
|
||||||
|
})
|
||||||
|
ipcRenderer.once('creat-ai-file-default-reply', (e, res) => {
|
||||||
|
resolve(res)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
v-if="item.bookImg"
|
v-if="item.bookImg"
|
||||||
@open-edit="reservDialog.openDialog(item)"
|
@open-edit="reservDialog.openDialog(item)"
|
||||||
@delete-reserv="deleteReserv(item)"
|
@delete-reserv="deleteReserv(item)"
|
||||||
|
@change="(...o) => emit('change', ...o)"
|
||||||
></reserv-item>
|
></reserv-item>
|
||||||
<reserv-item-apt
|
<reserv-item-apt
|
||||||
v-if="!item.bookImg"
|
v-if="!item.bookImg"
|
||||||
|
@ -18,6 +19,7 @@
|
||||||
:item="item"
|
:item="item"
|
||||||
@open-edit="reservDialog.openDialog(item)"
|
@open-edit="reservDialog.openDialog(item)"
|
||||||
@delete-reserv="deleteReserv(item)"
|
@delete-reserv="deleteReserv(item)"
|
||||||
|
@change="(...o) => emit('change', ...o)"
|
||||||
></reserv-item-apt>
|
></reserv-item-apt>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
@ -34,6 +36,10 @@ import Reserv from '@/views/prepare/container/reserv.vue'
|
||||||
import { useToolState } from '@/store/modules/tool'
|
import { useToolState } from '@/store/modules/tool'
|
||||||
import useUserStore from '@/store/modules/user'
|
import useUserStore from '@/store/modules/user'
|
||||||
import ReservItemApt from '@/views/classManage/reserv-item-apt.vue'
|
import ReservItemApt from '@/views/classManage/reserv-item-apt.vue'
|
||||||
|
// import Chat from '@/utils/chat' // im 登录初始化
|
||||||
|
// if (!Chat.imChat) Chat.init()
|
||||||
|
|
||||||
|
const emit = defineEmits(['change'])
|
||||||
const reservDialog = ref(null)
|
const reservDialog = ref(null)
|
||||||
const tabOptions = ref(['进行中', '已结束'])
|
const tabOptions = ref(['进行中', '已结束'])
|
||||||
const tabActive = ref('进行中')
|
const tabActive = ref('进行中')
|
||||||
|
|
|
@ -7,14 +7,14 @@
|
||||||
<span>{{item.caption}}</span>
|
<span>{{item.caption}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="class-reserv-item-tool" style="width: 200px;max-width: 300px">
|
<div class="class-reserv-item-tool" style="width: 200px;max-width: 300px">
|
||||||
<el-tag v-if="item.status === 'close'" style="margin-right: 5px" type="success">已结束</el-tag>
|
<el-tag v-if="item.status === 'closed'" style="margin-right: 5px" type="success">已结束</el-tag>
|
||||||
<el-tag v-if="item.status === 'open'" style="margin-right: 5px" type="danger">上课中</el-tag>
|
<el-tag v-if="item.status === 'open'" style="margin-right: 5px" type="danger">上课中</el-tag>
|
||||||
<el-button v-if="item.status === 'open'" :disabled="toolStore.isToolWin" size="small" type="primary" @click="startClassR(item)"
|
<el-button v-if="item.status === 'open'" :disabled="toolStore.isToolWin" size="small" type="primary" @click="startClassR(item)"
|
||||||
>继续上课</el-button
|
>继续上课</el-button
|
||||||
>
|
>
|
||||||
<!-- <el-button v-if="item.status === '未开始'" @click="openEdit">编辑</el-button>-->
|
<!-- <el-button v-if="item.status === '未开始'" @click="openEdit">编辑</el-button>-->
|
||||||
<el-button v-if="item.status === 'open'" size="small" type="info" @click="endClassR(item)"
|
<el-button v-if="item.status === 'open'" :loading="loading" size="small" type="info" @click="endClassR(item)"
|
||||||
>下课</el-button
|
>下课{{ loading?'中...':'' }}</el-button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="class-reserv-item-tool" style="width: 50px;">
|
<div class="class-reserv-item-tool" style="width: 50px;">
|
||||||
|
@ -25,13 +25,11 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
import { useToolState } from '@/store/modules/tool'
|
import { useToolState } from '@/store/modules/tool'
|
||||||
import useUserStore from '@/store/modules/user'
|
import { deleteSmartReserv } from '@/api/classManage'
|
||||||
import { createWindow } from '@/utils/tool'
|
|
||||||
import { deleteSmartReserv, startClass, endClass } from '@/api/classManage'
|
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { listEntpcourse } from '@/api/teaching/classwork'
|
const emit = defineEmits(['openEdit', 'deleteReserv', 'change'])
|
||||||
const emit = defineEmits(['openEdit', 'deleteReserv'])
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
item: {
|
item: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
@ -40,6 +38,7 @@ const props = defineProps({
|
||||||
})
|
})
|
||||||
const basePath = import.meta.env.VITE_APP_BUILD_BASE_PATH
|
const basePath = import.meta.env.VITE_APP_BUILD_BASE_PATH
|
||||||
const toolStore = useToolState() // 获取状态管理-tool
|
const toolStore = useToolState() // 获取状态管理-tool
|
||||||
|
const loading = ref(false) // 下课中的loading
|
||||||
const openEdit = () => {
|
const openEdit = () => {
|
||||||
emit('openEdit', props.item)
|
emit('openEdit', props.item)
|
||||||
}
|
}
|
||||||
|
@ -54,42 +53,15 @@ const deleteReserv = () => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// 继续上课
|
||||||
const startClassR = (item) => {
|
const startClassR = (item) => {
|
||||||
// startClass(item.id).then((res) => {
|
emit('change', 'continue', item)
|
||||||
// if (res.data === true) {
|
|
||||||
// item.status = '上课中'
|
|
||||||
// openLesson()
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// item.status = '上课中'
|
|
||||||
openLesson()
|
|
||||||
}
|
}
|
||||||
|
// 下课
|
||||||
const endClassR = (item) => {
|
const endClassR = (item) => {
|
||||||
/*endClass(item.id).then((res) => {
|
emit('change', 'close', item, { type: 2, loading })
|
||||||
if (res.data === true) {
|
|
||||||
ElMessage({
|
|
||||||
message: '下课成功',
|
|
||||||
type: 'success'
|
|
||||||
})
|
|
||||||
item.status = '已结束'
|
|
||||||
}
|
|
||||||
})*/
|
|
||||||
}
|
|
||||||
// const toolStore = useToolState()
|
|
||||||
let wins = null;
|
|
||||||
// 上课-工具类悬浮
|
|
||||||
const openLesson = () => {
|
|
||||||
// startClass(props.item.id)
|
|
||||||
/*listEntpcourse({
|
|
||||||
evalid: props.item.ex2,
|
|
||||||
edituserid: useUserStore().user.userId,
|
|
||||||
pageSize: 500
|
|
||||||
}).then(async res=>{
|
|
||||||
if (res.rows[0].id) {
|
|
||||||
wins = await createWindow('tool-sphere', { url: '/tool/sphere?entpcourseid=' + res.rows[0].id + "&reservId=" + props.item.id })
|
|
||||||
}
|
|
||||||
})*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.class-reserv-item {
|
.class-reserv-item {
|
||||||
|
|
|
@ -13,8 +13,8 @@
|
||||||
>继续上课</el-button
|
>继续上课</el-button
|
||||||
>
|
>
|
||||||
<!-- <el-button v-if="item.status === '未开始'" @click="openEdit">编辑</el-button>-->
|
<!-- <el-button v-if="item.status === '未开始'" @click="openEdit">编辑</el-button>-->
|
||||||
<el-button v-if="item.status === '上课中'" size="small" type="info" @click="endClassR(item)"
|
<el-button v-if="item.status === '上课中'" :loading="loading" size="small" type="info" @click="endClassR(item)"
|
||||||
>下课</el-button
|
>下课{{ loading?'中...':'' }}</el-button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="class-reserv-item-tool" style="width: 50px;">
|
<div class="class-reserv-item-tool" style="width: 50px;">
|
||||||
|
@ -25,13 +25,14 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
import { useToolState } from '@/store/modules/tool'
|
import { useToolState } from '@/store/modules/tool'
|
||||||
import useUserStore from '@/store/modules/user'
|
import useUserStore from '@/store/modules/user'
|
||||||
import { createWindow } from '@/utils/tool'
|
import { createWindow } from '@/utils/tool'
|
||||||
import { deleteSmartReserv, startClass, endClass } from '@/api/classManage'
|
import { deleteSmartReserv, startClass, endClass } from '@/api/classManage'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { listEntpcourse } from '@/api/teaching/classwork'
|
import { listEntpcourse } from '@/api/teaching/classwork'
|
||||||
const emit = defineEmits(['openEdit', 'deleteReserv'])
|
const emit = defineEmits(['openEdit', 'deleteReserv','change'])
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
item: {
|
item: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
@ -40,6 +41,7 @@ const props = defineProps({
|
||||||
})
|
})
|
||||||
const basePath = import.meta.env.VITE_APP_BUILD_BASE_PATH
|
const basePath = import.meta.env.VITE_APP_BUILD_BASE_PATH
|
||||||
const toolStore = useToolState() // 获取状态管理-tool
|
const toolStore = useToolState() // 获取状态管理-tool
|
||||||
|
const loading = ref(false) // 下课中的loading
|
||||||
const openEdit = () => {
|
const openEdit = () => {
|
||||||
emit('openEdit', props.item)
|
emit('openEdit', props.item)
|
||||||
}
|
}
|
||||||
|
@ -80,15 +82,7 @@ const openLesson = () => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const endClassR = (item) => {
|
const endClassR = (item) => {
|
||||||
endClass(item.id).then((res) => {
|
emit('change', 'close', item, { type: 2, loading })
|
||||||
if (res.data === true) {
|
|
||||||
ElMessage({
|
|
||||||
message: '下课成功',
|
|
||||||
type: 'success'
|
|
||||||
})
|
|
||||||
item.status = '已结束'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|
|
@ -58,17 +58,17 @@
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, onUnmounted, computed, watch } from 'vue'
|
import { ref, onMounted, onUnmounted, computed, watch } from 'vue'
|
||||||
import { listByDeadDate, listClassworkdata, listClassworkdataNew } from '@/api/classTask'
|
import { listByDeadDate, listClassworkdata } from '@/api/classTask'
|
||||||
|
|
||||||
import TaskItem from '@/views/classTask/container/task-item.vue'
|
import TaskItem from '@/views/classTask/container/classTask/task-item.vue'
|
||||||
// import ItemDialog from '@/views/classTask/container/item-dialog.vue'
|
// import ItemDialog from '@/views/classTask/container/item-dialog.vue'
|
||||||
import { useToolState } from '@/store/modules/tool'
|
import { useToolState } from '@/store/modules/tool'
|
||||||
import { getCurrentTime, getTomorrow } from '@/utils/date'
|
import { getCurrentTime } from '@/utils/date'
|
||||||
import useUserStore from '@/store/modules/user'
|
import useUserStore from '@/store/modules/user'
|
||||||
import useClassTaskStore from "@/store/modules/classTask";
|
import useClassTaskStore from "@/store/modules/classTask";
|
||||||
import {createWindow} from '@/utils/tool'
|
import {createWindow} from '@/utils/tool'
|
||||||
import {sessionStore} from '@/utils/store'
|
import {sessionStore} from '@/utils/store'
|
||||||
import {throttle,debounce } from '@/utils/comm'
|
import {debounce } from '@/utils/comm'
|
||||||
|
|
||||||
|
|
||||||
const toolState = useToolState();
|
const toolState = useToolState();
|
||||||
|
@ -141,67 +141,80 @@ const getClassWorkList = async () => {
|
||||||
{
|
{
|
||||||
// 班级作业数据,包含多个班级 homeworklist
|
// 班级作业数据,包含多个班级 homeworklist
|
||||||
const response = await listByDeadDate({
|
const response = await listByDeadDate({
|
||||||
//classidarray: classTaskStore.classListIds.join(','),
|
|
||||||
edituserid: userStore.userId, // 老师的id
|
edituserid: userStore.userId, // 老师的id
|
||||||
edustage: userStore.edustage, // 学段
|
edustage: userStore.edustage, // 学段
|
||||||
edusubject: userStore.edusubject,//学科
|
edusubject: userStore.edusubject,//学科
|
||||||
deaddate: tabActive.value === '进行中'? getTomorrow() : EndDate.value,// 进行中:明天,已结束:选择的日期
|
// deaddate: tabActive.value === '进行中'? getTomorrow() : EndDate.value,// 进行中:明天,已结束:选择的日期 弃用
|
||||||
|
deaddate: EndDate.value,// 进行中:明天,已结束:选择的日期
|
||||||
status: '1', // 作业状态:1-已发布
|
status: '1', // 作业状态:1-已发布
|
||||||
// orderby: 'concat(deaddate,uniquekey) DESC',
|
|
||||||
orderby: 'deaddate DESC',
|
orderby: 'deaddate DESC',
|
||||||
pageSize: 100,
|
pageSize: 100,
|
||||||
})
|
})
|
||||||
|
|
||||||
for (var i = 0; i < response.rows.length; i++) {
|
/**
|
||||||
|
* 2024-10-17 由于 后面截止时间加了 时分,特加判断
|
||||||
|
* 1、进行中、以前是以明天判断。现改为传当天的日期,并根据当前日期的时分与截止日期进行判断,
|
||||||
|
* 2、已结束、以前默认是以明天判断。现依然以明天为判断,并根据当前日期时分大于截止日期时分判断。
|
||||||
|
*/
|
||||||
|
let list = [];
|
||||||
|
if(tabActive.value === '进行中'){
|
||||||
|
// 进行中 当前日期时间 小于 截止 日期时间
|
||||||
|
list = response.rows&&response.rows.filter(item => item.deaddate && getCurrentTime('YYYY-MM-DD HH:mm') < item.deaddate); // 进行中
|
||||||
|
}else{
|
||||||
|
list = response.rows&&response.rows.filter(item => item.deaddate && getCurrentTime('YYYY-MM-DD HH:mm') > item.deaddate); // 已结束
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (var i = 0; i < list.length; i++) {
|
||||||
// 初始化部分新增字段值
|
// 初始化部分新增字段值
|
||||||
response.rows[i].workdatalist = []
|
list[i].workdatalist = []
|
||||||
response.rows[i].workdatacount = 0 // 人数
|
list[i].workdatacount = 0 // 人数
|
||||||
response.rows[i].workdatalistVisible = false
|
list[i].workdatalistVisible = false
|
||||||
response.rows[i].workdatafeedbackcount = 0 // 已交人数
|
list[i].workdatafeedbackcount = 0 // 已交人数
|
||||||
response.rows[i].feedtimelength = 0
|
list[i].feedtimelength = 0
|
||||||
response.rows[i].rightAnswerCount = 0
|
list[i].rightAnswerCount = 0
|
||||||
response.rows[i].scoingRate = 0 + '%' // 得分率
|
list[i].scoingRate = 0 + '%' // 得分率
|
||||||
response.rows[i].averagetime = 0 // 平均用时
|
list[i].averagetime = 0 // 平均用时
|
||||||
|
|
||||||
// ----------------------------------------------
|
// ----------------------------------------------
|
||||||
// 处理任务类型的UI
|
// 处理任务类型的UI
|
||||||
if (response.rows[i].worktype == '学习目标定位') {
|
if (list[i].worktype == '学习目标定位') {
|
||||||
response.rows[i].workclass = 'success'
|
list[i].workclass = 'success'
|
||||||
response.rows[i].workcodesList = JSON.parse(response.rows[i].workcodes)
|
list[i].workcodesList = JSON.parse(list[i].workcodes)
|
||||||
} else if (response.rows[i].worktype == '教材研读') {
|
} else if (list[i].worktype == '教材研读') {
|
||||||
response.rows[i].workclass = 'primary'
|
list[i].workclass = 'primary'
|
||||||
} else if (response.rows[i].worktype == '框架梳理') {
|
} else if (list[i].worktype == '框架梳理') {
|
||||||
response.rows[i].workclass = 'warning'
|
list[i].workclass = 'warning'
|
||||||
} else if (response.rows[i].worktype == '学科定位') {
|
} else if (list[i].worktype == '学科定位') {
|
||||||
response.rows[i].workclass = 'info'
|
list[i].workclass = 'info'
|
||||||
} else if (response.rows[i].worktype == '习题训练') {
|
} else if (list[i].worktype == '习题训练') {
|
||||||
response.rows[i].workclass = 'danger'
|
list[i].workclass = 'danger'
|
||||||
} else {
|
} else {
|
||||||
response.rows[i].workclass = ''
|
list[i].workclass = ''
|
||||||
}
|
}
|
||||||
// 如果是习题训练任务,则检查一共有多少道
|
// 如果是习题训练任务,则检查一共有多少道
|
||||||
if (response.rows[i].entpcourseworklist != '') {
|
if (list[i].entpcourseworklist != '') {
|
||||||
response.rows[i].entpcourseworklistarray = JSON.parse(
|
list[i].entpcourseworklistarray = JSON.parse(
|
||||||
'[' + response.rows[i].entpcourseworklist + ']'
|
'[' + list[i].entpcourseworklist + ']'
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
response.rows[i].entpcourseworklistarray = []
|
list[i].entpcourseworklistarray = []
|
||||||
}
|
}
|
||||||
// 根据 classworkdatastudentids 初始化判断分配的人数
|
// 根据 classworkdatastudentids 初始化判断分配的人数
|
||||||
if (
|
if (
|
||||||
response.rows[i].classworkdatastudentids != '' &&
|
list[i].classworkdatastudentids != '' &&
|
||||||
response.rows[i].classworkdatastudentids != null &&
|
list[i].classworkdatastudentids != null &&
|
||||||
response.rows[i].classworkdatastudentids != 'null'
|
list[i].classworkdatastudentids != 'null'
|
||||||
) {
|
) {
|
||||||
const stuList = JSON.parse('[' + response.rows[i].classworkdatastudentids + ']')
|
const stuList = JSON.parse('[' + list[i].classworkdatastudentids + ']')
|
||||||
response.rows[i].workdatacount = stuList.length
|
list[i].workdatacount = stuList.length
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 显示分配人数(workdatacount)>0 的
|
// 显示分配人数(workdatacount)>0 的
|
||||||
if (response.rows && response.rows.length > 0) {
|
if (list && list.length > 0) {
|
||||||
classWorkList.value = response.rows && response.rows.filter((item) => item.workdatacount > 0)
|
classWorkList.value = list && list.filter((item) => item.workdatacount > 0)
|
||||||
//TODO: 这里没分页,貌似这个 total 不重要,后续看
|
//TODO: 这里没分页,貌似这个 total 不重要,后续看
|
||||||
total.value = response.total
|
total.value = 0
|
||||||
}else{
|
}else{
|
||||||
classWorkList.value = []
|
classWorkList.value = []
|
||||||
total.value = 0
|
total.value = 0
|
||||||
|
@ -222,8 +235,9 @@ const getStudentClassWorkData = async() => {
|
||||||
// classids: classTaskStore.classListIds.join(','),
|
// classids: classTaskStore.classListIds.join(','),
|
||||||
// edusubject: userStore.edusubject,//学科
|
// edusubject: userStore.edusubject,//学科
|
||||||
// deaddate: tabActive.value === '进行中'? getTomorrow() : EndDate.value,// 进行中:明天,已结束:选择的日期
|
// deaddate: tabActive.value === '进行中'? getTomorrow() : EndDate.value,// 进行中:明天,已结束:选择的日期
|
||||||
|
// deaddate: EndDate.value,// 进行中:明天,已结束:选择的日期
|
||||||
// //status: '1', // 作业状态:1-已发布
|
// //status: '1', // 作业状态:1-已发布
|
||||||
// orderby: "deaddate DESC",// TODO: 这里是否加 deaddate 的排序,后续看
|
// orderby: "deaddate DESC",//
|
||||||
// pageSize: 1000,
|
// pageSize: 1000,
|
||||||
// })
|
// })
|
||||||
|
|
||||||
|
@ -387,7 +401,8 @@ const onClickItem = (item) => {
|
||||||
clearInterval(pollingST.value)
|
clearInterval(pollingST.value)
|
||||||
|
|
||||||
console.log('防抖开启弹窗')
|
console.log('防抖开启弹窗')
|
||||||
sessionStore.set('teachClassWorkItem', item); // 缓存点击的item
|
// sessionStore.set('teachClassWorkItem', item); // 缓存点击的item
|
||||||
|
localStorage.setItem('teachClassWorkItem', JSON.stringify(item));
|
||||||
debounceOpenWin();
|
debounceOpenWin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,13 +422,28 @@ const getStudentVisible = async () => {
|
||||||
edituserid: userStore.userId, // 老师的id
|
edituserid: userStore.userId, // 老师的id
|
||||||
edustage: userStore.edustage,// 学段
|
edustage: userStore.edustage,// 学段
|
||||||
edusubject: userStore.edusubject,//学科
|
edusubject: userStore.edusubject,//学科
|
||||||
deaddate: tabActive.value === '进行中'? getTomorrow() : EndDate.value,// 进行中:明天,已结束:选择的日期
|
// deaddate: tabActive.value === '进行中'? getTomorrow() : EndDate.value,// 进行中:明天,已结束:选择的日期
|
||||||
|
deaddate: EndDate.value,// 进行中:明天,已结束:选择的日期
|
||||||
status: '1', // 作业状态:1-已发布
|
status: '1', // 作业状态:1-已发布
|
||||||
// orderby: 'concat(deaddate,uniquekey) DESC',
|
// orderby: 'concat(deaddate,uniquekey) DESC',
|
||||||
orderby: 'deaddate DESC',
|
orderby: 'deaddate DESC',
|
||||||
pageSize: 100
|
pageSize: 100
|
||||||
})
|
})
|
||||||
const curWorkList = response.rows
|
|
||||||
|
/**
|
||||||
|
* 2024-10-17 由于 后面截止时间加了 时分,特加判断
|
||||||
|
* 1、进行中、以前是以明天判断。现改为传当天的日期,并根据当前日期的时分与截止日期进行判断,
|
||||||
|
* 2、已结束、以前默认是以明天判断。现依然以明天为判断,并根据当前日期时分大于截止日期时分判断。
|
||||||
|
*/
|
||||||
|
let list = [];
|
||||||
|
if(tabActive.value === '进行中'){
|
||||||
|
// 进行中 当前日期时间 小于 截止 日期时间
|
||||||
|
list = response.rows&&response.rows.filter(item => item.deaddate && getCurrentTime('YYYY-MM-DD HH:mm') < item.deaddate); // 进行中
|
||||||
|
}else{
|
||||||
|
list = response.rows&&response.rows.filter(item => item.deaddate && getCurrentTime('YYYY-MM-DD HH:mm') > item.deaddate); // 已结束
|
||||||
|
}
|
||||||
|
|
||||||
|
const curWorkList = list
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* warn: 这里仅更新了finishpercent(进度条), 且当前作业布置推送新任务时, curWorkList中会查到新的任务与当前页面中this.classWorkList长度不一致,
|
* warn: 这里仅更新了finishpercent(进度条), 且当前作业布置推送新任务时, curWorkList中会查到新的任务与当前页面中this.classWorkList长度不一致,
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -15,11 +15,11 @@ const chartRef = ref(null);
|
||||||
|
|
||||||
// 数据源
|
// 数据源
|
||||||
const dataList = ref([
|
const dataList = ref([
|
||||||
{name: '优', value: 0,rating:1},
|
{name: '完美', value: 0,rating:1,max:100,min:100,},
|
||||||
{name: '优-', value: 0,rating:2},
|
{name: '优秀', value: 0,rating:2,max:99,min:80,},
|
||||||
{name: '良', value: 0,rating:3},
|
{name: '良好', value: 0,rating:3,max:79,min:70,},
|
||||||
{name: '良-', value: 0,rating:4},
|
{name: '及格', value: 0,rating:4,max:69,min:60,},
|
||||||
{name: '差', value: 0,rating:5},
|
{name: '不及格', value: 0,rating:5,max:59,min:0,},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 根据数据生成不同的颜色
|
// 根据数据生成不同的颜色
|
||||||
|
@ -32,6 +32,8 @@ function getColor(index) {
|
||||||
// 初始化图表
|
// 初始化图表
|
||||||
function initChart() {
|
function initChart() {
|
||||||
const myChart = echarts.init(chartRef.value);
|
const myChart = echarts.init(chartRef.value);
|
||||||
|
const total = dataList.value.reduce((acc, cur) => acc + cur.value, 0); // 计算总数
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
|
@ -70,7 +72,11 @@ function initChart() {
|
||||||
label: {
|
label: {
|
||||||
show: true,
|
show: true,
|
||||||
position: 'top',
|
position: 'top',
|
||||||
formatter: '{c}人',
|
formatter: params => {
|
||||||
|
const value = dataList.value[params.dataIndex].value;
|
||||||
|
const percentage = value ? ((value / total) * 100).toFixed() : 0; // 计算百分比并保留两位小数
|
||||||
|
return `${value}人 ${percentage}%`; // 显示为百分比形式
|
||||||
|
},
|
||||||
color: '#333',
|
color: '#333',
|
||||||
fontSize: 12
|
fontSize: 12
|
||||||
}
|
}
|
||||||
|
@ -81,10 +87,13 @@ function initChart() {
|
||||||
}
|
}
|
||||||
// 获取表的数据
|
// 获取表的数据
|
||||||
const showEcharts =() => {
|
const showEcharts =() => {
|
||||||
useOverview.tableList.forEach(item => {
|
useOverview.tableList.forEach((item,index) => {
|
||||||
const index = dataList.value.findIndex(item1 => item1.rating === item.rating)
|
if(item.rating === 0) return // 没批改不计数
|
||||||
if(index !== -1)
|
dataList.value.forEach((item1,index1) => {
|
||||||
dataList.value[index].value ++
|
if(item1.min <= Number(item.scoingRate) && Number(item.scoingRate) <= item1.max ){
|
||||||
|
item1.value ++
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
watch(() => useOverview.tableList,() => {
|
watch(() => useOverview.tableList,() => {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<el-tabs :tab-position="tabPosition" style="height: 100%" class="demo-tabs" @tabChange="handelChange">
|
<el-tabs :tab-position="tabPosition" style="height: 100%" class="demo-tabs" @tabChange="handelChange">
|
||||||
<template v-for="(item,index) in leftList" :key="index">
|
<template v-for="(item,index) in leftList" :key="index">
|
||||||
<el-tab-pane :label="item.label" style="text-align:left">
|
<el-tab-pane :label="item.label" style="text-align:left" stretch="true">
|
||||||
<template v-if="item.stuList.length > 0">
|
<template v-if="item.stuList.length > 0">
|
||||||
<template v-for="(stuItem,stuIndex) in item.stuList" :key="stuIndex">
|
<template v-for="(stuItem,stuIndex) in item.stuList" :key="stuIndex">
|
||||||
<el-tag style="margin:5px 10px 0 0" type="primary">{{stuItem.studentname}}</el-tag>
|
<el-tag style="margin:5px 10px 0 0" type="primary">{{stuItem.studentname}}</el-tag>
|
||||||
|
@ -23,29 +23,40 @@ const useOverview = overviewStore()
|
||||||
const tabPosition = ref('left')
|
const tabPosition = ref('left')
|
||||||
const leftList = ref([
|
const leftList = ref([
|
||||||
{
|
{
|
||||||
label:'优',
|
label:'完美',
|
||||||
stuList:[],
|
stuList:[],
|
||||||
rating:1
|
rating:1,
|
||||||
|
max:100,
|
||||||
|
min:100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label:'优-',
|
label:'优秀',
|
||||||
stuList:[],
|
stuList:[],
|
||||||
rating:2
|
rating:2,
|
||||||
|
max:99,
|
||||||
|
min:80,
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label:'良',
|
label:'良好',
|
||||||
stuList:[],
|
stuList:[],
|
||||||
rating:3
|
rating:3,
|
||||||
|
max:79,
|
||||||
|
min:70,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label:'良-',
|
label:'及格',
|
||||||
stuList:[],
|
stuList:[],
|
||||||
rating:4
|
rating:4,
|
||||||
|
max:69,
|
||||||
|
min:60,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label:'差',
|
label:'不及格',
|
||||||
stuList:[],
|
stuList:[],
|
||||||
rating:5
|
rating:5,
|
||||||
|
max:59,
|
||||||
|
min:0,
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
//切换展示区域学生
|
//切换展示区域学生
|
||||||
|
@ -54,9 +65,12 @@ const handelChange = (item) => {
|
||||||
}
|
}
|
||||||
//取区域的学生
|
//取区域的学生
|
||||||
const showStudents = (index) => {
|
const showStudents = (index) => {
|
||||||
console.log(useOverview.tableList,'lef')
|
|
||||||
leftList.value[index].stuList = useOverview.tableList.filter(item => {
|
leftList.value[index].stuList = useOverview.tableList.filter(item => {
|
||||||
if(item.rating == leftList.value[index].rating) return item
|
if(item.rating > 0){
|
||||||
|
if(leftList.value[index].min <= Number(item.scoingRate || 0) && Number(item.scoingRate || 0) <= leftList.value[index].max ){
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
watch(() => useOverview.tableList,() => {
|
watch(() => useOverview.tableList,() => {
|
||||||
|
@ -107,9 +121,9 @@ watch(() => useOverview.tableList,() => {
|
||||||
:deep(.el-tabs__item.is-active){
|
:deep(.el-tabs__item.is-active){
|
||||||
background-color: rgb(238, 241, 246);
|
background-color: rgb(238, 241, 246);
|
||||||
}
|
}
|
||||||
:deep(.el-tabs--left .el-tabs__item.is-left){
|
:deep(.el-tabs--left .el-tabs__item.is-left, .el-tabs--right .el-tabs__item.is-left){
|
||||||
text-align: left;
|
text-align: left;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
|
@ -196,7 +196,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="teachFileList.length > 0">
|
<div v-if="teachFileList.length > 0">
|
||||||
<div style="margin: 10px 0;text-align: left;">
|
<div style="margin: 10px 0;text-align: left; cursor: pointer;">
|
||||||
<span style="color: red" @click="openFile"
|
<span style="color: red" @click="openFile"
|
||||||
>温馨提示:点击此处 可预览其他类型附件!
|
>温馨提示:点击此处 可预览其他类型附件!
|
||||||
</span>
|
</span>
|
||||||
|
@ -245,7 +245,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="fileList.length > 0">
|
<div v-if="fileList.length > 0">
|
||||||
<div style="margin: 10px 0;text-align: left;">
|
<div style="margin: 10px 0;text-align: left; cursor: pointer;">
|
||||||
<span style="color: red" @click="openFile"
|
<span style="color: red" @click="openFile"
|
||||||
>温馨提示:点击此处 可预览其他类型附件!
|
>温馨提示:点击此处 可预览其他类型附件!
|
||||||
</span>
|
</span>
|
||||||
|
@ -460,12 +460,13 @@ import useUserStore from '@/store/modules/user'
|
||||||
import { ref, reactive } from 'vue'
|
import { ref, reactive } from 'vue'
|
||||||
// import { Plus } from '@element-plus/icons-vue'
|
// import { Plus } from '@element-plus/icons-vue'
|
||||||
import { ElMessageBox, ElMessage } from 'element-plus'
|
import { ElMessageBox, ElMessage } from 'element-plus'
|
||||||
import { updateClassworkeval, updateClassworkdata } from '@/api/classTask'
|
import { updateClassworkeval, updateClassworkdata, getClassworkdata } from '@/api/classTask'
|
||||||
import { getTimeDate } from '@/utils/date'
|
import { getTimeDate } from '@/utils/date'
|
||||||
import ReFilePreview from '@/components/refile-preview/index.vue'
|
import ReFilePreview from '@/components/refile-preview/index.vue'
|
||||||
import { quizStrToList } from '@/utils/comm';
|
import { quizStrToList } from '@/utils/comm';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
@ -644,7 +645,7 @@ const selectScore = (score) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 接收父组件传过来的参数
|
// 接收父组件传过来的参数
|
||||||
const acceptParams = (params) => {
|
const acceptParams = async (params) => {
|
||||||
console.log(params)
|
console.log(params)
|
||||||
console.log(dialogProps, 'dialogProps')
|
console.log(dialogProps, 'dialogProps')
|
||||||
// 先重置一下 参数
|
// 先重置一下 参数
|
||||||
|
@ -709,8 +710,9 @@ const acceptParams = (params) => {
|
||||||
if (params.studentObj.worktype == '常规作业') {
|
if (params.studentObj.worktype == '常规作业') {
|
||||||
try {
|
try {
|
||||||
// 老师布置的附件 datacontent TODO:常规作业、其他类型还未接入
|
// 老师布置的附件 datacontent TODO:常规作业、其他类型还未接入
|
||||||
if (params.studentObj.datacontent != '') {
|
const res = await getClassworkdata(params.studentObj.id);
|
||||||
const teachWorkFileList = JSON.parse(params.studentObj.datacontent)
|
if(res.data.datacontent != ''){
|
||||||
|
const teachWorkFileList = JSON.parse(res.data.datacontent);
|
||||||
console.log(teachWorkFileList, '老师filelist-------------')
|
console.log(teachWorkFileList, '老师filelist-------------')
|
||||||
teachWorkFileList &&
|
teachWorkFileList &&
|
||||||
teachWorkFileList.forEach((item) => {
|
teachWorkFileList.forEach((item) => {
|
||||||
|
@ -727,7 +729,6 @@ const acceptParams = (params) => {
|
||||||
teacherFeedContentList.value.push(teachWorkFileList)
|
teacherFeedContentList.value.push(teachWorkFileList)
|
||||||
}
|
}
|
||||||
|
|
||||||
dialogProps.value.studentObj.datacontent = dialogProps.value.studentObj.datacontent
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Invalid JSON:', error)
|
console.error('Invalid JSON:', error)
|
||||||
}
|
}
|
|
@ -0,0 +1,179 @@
|
||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-model="fileReadopen"
|
||||||
|
title="文件预览"
|
||||||
|
width="80%"
|
||||||
|
:style="{ height: '72vh' }"
|
||||||
|
append-to-body
|
||||||
|
>
|
||||||
|
<div class="file-read-dialog">
|
||||||
|
<div>
|
||||||
|
<!-- 老师附件 -->
|
||||||
|
<div v-if="teachFileList.length > 0">
|
||||||
|
<el-card style="max-width: 480px">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span>文件列表</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div
|
||||||
|
v-for="item in teachFileList"
|
||||||
|
:key="item"
|
||||||
|
style="margin: 10px; display: flex; align-items: center"
|
||||||
|
>
|
||||||
|
<span style="margin-right: 10px">{{ item.name }}</span>
|
||||||
|
<el-button type="primary" @click="onFileRead(item)">预览</el-button>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="width: 100%" :style="{ height: '72vh' }">
|
||||||
|
<div style="margin-left: 10px">
|
||||||
|
预览展示区域<span style="color: red; margin-left: 10px">
|
||||||
|
温馨提示:若预览失败,<span style="margin-left: 10px">{{ props.name }}</span
|
||||||
|
>可点击此处<a
|
||||||
|
:href="fileitem.url ? fileitem.url : ''"
|
||||||
|
target="_blank"
|
||||||
|
style="color: blue"
|
||||||
|
>下载!</a
|
||||||
|
></span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<ReFilePreview
|
||||||
|
:name="fileitem.name"
|
||||||
|
:type="fileitem.type"
|
||||||
|
:file-type="fileitem.type"
|
||||||
|
:file-path="fileitem.url"
|
||||||
|
:text-content="textContent"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup name="prevReadImgFileDialogRef">
|
||||||
|
import { ref, reactive } from 'vue'
|
||||||
|
import ReFilePreview from '@/components/refile-preview/index.vue'
|
||||||
|
|
||||||
|
const props = defineProps({})
|
||||||
|
|
||||||
|
const fileReadopen = ref(false)
|
||||||
|
|
||||||
|
// 老师常规作业、课堂展示布置题目附件list
|
||||||
|
const teacherFeedContentList = ref([])
|
||||||
|
const teachImageList = ref([])
|
||||||
|
const teachFileList = ref([])
|
||||||
|
|
||||||
|
|
||||||
|
// 确定的线上图片数据
|
||||||
|
//#region 文件内容相关
|
||||||
|
const fileitem = reactive({
|
||||||
|
name: '',
|
||||||
|
type: '',
|
||||||
|
url: ''
|
||||||
|
})
|
||||||
|
// 文件预览
|
||||||
|
const onFileRead = (file) => {
|
||||||
|
textContent.value = '1'
|
||||||
|
//
|
||||||
|
fileitem.type = file.name.split('.').pop().toLowerCase()
|
||||||
|
fileitem.url = file.url
|
||||||
|
fileitem.name = file.name
|
||||||
|
|
||||||
|
// txt 读取
|
||||||
|
if (fileitem.type == 'txt') {
|
||||||
|
loadFileTextContent(fileitem.url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// txt文件读取
|
||||||
|
const textContent = ref('')
|
||||||
|
const loadFileTextContent = async (url) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(url)
|
||||||
|
if (!response.ok) {
|
||||||
|
textContent.value = '文件读取失败,您可以点击上方链接跳到另外页面查看'
|
||||||
|
throw new Error('文件读取失败')
|
||||||
|
}
|
||||||
|
textContent.value = await response.text()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('读取文件时出错:', error)
|
||||||
|
textContent.value = '文件读取失败,您可以点击上方链接跳到另外页面查看'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 接收父组件传过来的参数
|
||||||
|
const acceptParams = (params) => {
|
||||||
|
console.log(params)
|
||||||
|
fileReadopen.value = true;
|
||||||
|
teacherFeedContentList.value = params.teacherFeedContentList
|
||||||
|
teachImageList.value = params.teachImageList
|
||||||
|
teachFileList.value = params.teachFileList
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 初始化请求
|
||||||
|
// onMounted(() => {})
|
||||||
|
|
||||||
|
// 暴露给父组件的参数和方法(外部需要什么,都可以从这里暴露出去)
|
||||||
|
defineExpose({
|
||||||
|
acceptParams
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
|
||||||
|
.card-header{
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image_list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.file-read-dialog {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.score-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
/* margin-bottom: 20px; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.score-circle {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: pink;
|
||||||
|
color: red;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 13px;
|
||||||
|
margin: 0 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.score-circle.active {
|
||||||
|
background-color: red;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header{
|
||||||
|
align-items: left;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -167,7 +167,7 @@ import useUserStore from '@/store/modules/user'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { getCurrentTime, getAfterMinutes } from '@/utils/date'
|
import { getCurrentTime, getAfterMinutes } from '@/utils/date'
|
||||||
import { processList } from '@/hooks/useProcessList'
|
import { processList } from '@/hooks/useProcessList'
|
||||||
import ItemDialogScore from '@/views/classTask/container/item-dialog-score.vue'
|
import ItemDialogScore from '@/views/classTask/container/classTask/item-dialog-score.vue'
|
||||||
// zdg: 组件导入
|
// zdg: 组件导入
|
||||||
import quizStats from '@/views/classTask/container/quizStats.vue'
|
import quizStats from '@/views/classTask/container/quizStats.vue'
|
||||||
import ClassOverview from '@/views/classTask/container/classOverview.vue'
|
import ClassOverview from '@/views/classTask/container/classOverview.vue'
|
||||||
|
@ -418,15 +418,15 @@ const getStudentClassWorkDataDetail = (row) => {
|
||||||
wevalres.rows[w].score = wevalres.rows[w].score ? wevalres.rows[w].score : 0
|
wevalres.rows[w].score = wevalres.rows[w].score ? wevalres.rows[w].score : 0
|
||||||
|
|
||||||
// 参考答案 去除下html标签
|
// 参考答案 去除下html标签
|
||||||
wevalres.rows[w].rightanswer =
|
// wevalres.rows[w].rightanswer =
|
||||||
wevalres.rows[w].rightanswer != '' && wevalres.rows[w].rightanswer != null
|
// wevalres.rows[w].rightanswer != '' && wevalres.rows[w].rightanswer != null
|
||||||
? wevalres.rows[w].rightanswer.replace(/<[^>]+>/g, '')
|
// ? wevalres.rows[w].rightanswer.replace(/<[^>]+>/g, '')
|
||||||
: wevalres.rows[w].rightanswer
|
// : wevalres.rows[w].rightanswer
|
||||||
// 学生回答 去除下html标签
|
// // 学生回答 去除下html标签
|
||||||
wevalres.rows[w].feedcontent =
|
// wevalres.rows[w].feedcontent =
|
||||||
wevalres.rows[w].feedcontent != '' && wevalres.rows[w].feedcontent != null
|
// wevalres.rows[w].feedcontent != '' && wevalres.rows[w].feedcontent != null
|
||||||
? wevalres.rows[w].feedcontent.replace(/<[^>]+>/g, '')
|
// ? wevalres.rows[w].feedcontent.replace(/<[^>]+>/g, '')
|
||||||
: wevalres.rows[w].feedcontent
|
// : wevalres.rows[w].feedcontent
|
||||||
|
|
||||||
if (classWorkAnalysis.row.worktype == '常规作业') {
|
if (classWorkAnalysis.row.worktype == '常规作业') {
|
||||||
wevalres.rows[w].feedcontent = JSON.parse(wevalres.rows[w].feedcontent)
|
wevalres.rows[w].feedcontent = JSON.parse(wevalres.rows[w].feedcontent)
|
||||||
|
|
|
@ -0,0 +1,148 @@
|
||||||
|
<template>
|
||||||
|
<!-- 预览框 -->
|
||||||
|
<el-dialog v-if="prevReadMsg.visible" v-model="prevReadMsg.visible" class="prev-read-zy-wrap" width="90%" style="height: 80vh" append-to-body>
|
||||||
|
<!-- <div v-if="prevReadMsg.type=='课标研读'" style="height: 100%;">
|
||||||
|
<standard book-type="课标研读" :show-cata="true" :show-tools="false" :course-obj="courseObj" :bookdatahtml="versionObj.bookdata" :teachResObj="activeTeachResOfStandard"></standard>
|
||||||
|
</div>
|
||||||
|
<div v-if="prevReadMsg.type=='目标设定'" style="height: 100%;display: flex;">
|
||||||
|
<degreeevolution :courseObj="courseObj" :show-class="true" :teachResObj="activeTeachResOfStandard" :attainmentList="attainmentList" :courseQualityList="courseQualityList"/>
|
||||||
|
</div>
|
||||||
|
<div v-if="prevReadMsg.type=='教材研读'" style="height: 100%;">
|
||||||
|
<standard book-type="教材研读" :course-obj="courseObj" :show-tools="false" :bookdatahtml="versionObj.bookdata" :teachResObj="activeTeachResOfStandard"></standard>
|
||||||
|
</div> -->
|
||||||
|
<div v-if="prevReadMsg.type=='框架梳理'" style="height: 100%;">
|
||||||
|
<FlowChart ref="flowref" :flowHeight="mainHeight" :dataSource="flowData"/>
|
||||||
|
</div>
|
||||||
|
<!-- <div v-if="prevReadMsg.type=='学科定位'" style="height: 100%;">
|
||||||
|
<teachJsMind :course-obj="courseObj" :teachResObj="activeTeachResOfStandard"></teachJsMind>
|
||||||
|
</div> -->
|
||||||
|
<!-- <div v-if="prevReadMsg.type=='习题训练'">习题训练</div> -->
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup name="prevReadMsgDialogRef">
|
||||||
|
import { onMounted, ref, watch, reactive, getCurrentInstance } from 'vue'
|
||||||
|
|
||||||
|
import { listEntpcoursefile } from '@/api/education/entpcoursefile'
|
||||||
|
import { useGetHomework } from '@/hooks/useGetHomework'
|
||||||
|
import FlowChart from "@/components/Flowchart/index.vue";
|
||||||
|
|
||||||
|
// 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 { listEvaluation } from '@/api/subject'
|
||||||
|
|
||||||
|
// import { listKnowledgePoint } from "@/api/knowledge/knowledgePoint";
|
||||||
|
|
||||||
|
|
||||||
|
import FileUpload from "@/components/FileUpload/index.vue";
|
||||||
|
import whiteboard from '@/components/whiteboard/whiteboard.vue'
|
||||||
|
|
||||||
|
import useUserStore from '@/store/modules/user'
|
||||||
|
const userStore = useUserStore().user
|
||||||
|
const { proxy } = getCurrentInstance()
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
bookobj: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const mainHeight = ref(document.documentElement.clientHeight - 110)
|
||||||
|
|
||||||
|
// 预览
|
||||||
|
const prevReadMsg = reactive({
|
||||||
|
visible: false,
|
||||||
|
type: ""
|
||||||
|
});// 预览msg
|
||||||
|
// 框架梳理----------
|
||||||
|
const flowData = ref({})// 框架梳理
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 1、打开弹窗: 预览资源
|
||||||
|
const openDialog = async (item) => {
|
||||||
|
prevReadMsg.visible = true;
|
||||||
|
prevReadMsg.type = item.worktype;
|
||||||
|
// // if (item.worktype==='课标研读'){
|
||||||
|
// // //获取教材文件和批注信息
|
||||||
|
// // listEvaluation({itemkey: 'subject', edusubject: userStore.edusubject, edustage: userStore.edustage}).then(res => {
|
||||||
|
// // // TODO 课标研读-还未接入
|
||||||
|
// // console.log("课标研读-还未接入",res);
|
||||||
|
// // // this.versionObj = res.rows[0];
|
||||||
|
// // // // 读取出课标文件的每一行
|
||||||
|
// // // if (this.versionObj.fileurl.length > 0) {
|
||||||
|
// // // readFile({cluelink: this.versionObj.fileurl}).then(fileres => {
|
||||||
|
// // // this.versionObj.bookdata = fileres;
|
||||||
|
// // // this.activeTeachResOfStandard = item;
|
||||||
|
// // // })
|
||||||
|
// // // }
|
||||||
|
// // })
|
||||||
|
// // }
|
||||||
|
// // if (item.worktype==='目标设定'){
|
||||||
|
// // // TODO 目标设定-还未接入
|
||||||
|
// // // this.activeTeachResOfStandard = item;
|
||||||
|
// // }
|
||||||
|
// if (item.worktype==='教材研读'){
|
||||||
|
// // TODO 教材研读-还未接入
|
||||||
|
// // getEvaluation(this.courseObj.evalrootid).then(bookres => {
|
||||||
|
// // this.versionObj = bookres.data;
|
||||||
|
// // if (this.versionObj.fileurl.length > 0) {
|
||||||
|
// // readFile({cluelink: this.versionObj.fileurl}).then(fileres => {
|
||||||
|
// // this.versionObj.bookdata = fileres;
|
||||||
|
// // this.activeTeachResOfStandard = item;
|
||||||
|
// // })
|
||||||
|
// // }
|
||||||
|
// // })
|
||||||
|
// }
|
||||||
|
if (item.worktype==='框架梳理'){
|
||||||
|
flowData.value = {};
|
||||||
|
const { chapterId } = await useGetHomework(props.bookobj.node)
|
||||||
|
// this.entpcourseid = chapterId
|
||||||
|
let queryParams = {
|
||||||
|
entpcourseid: chapterId,
|
||||||
|
ppttype: '教材分析',
|
||||||
|
parentid: item.id,
|
||||||
|
title: '逻辑框架建构',
|
||||||
|
filetype: 'draw'
|
||||||
|
}
|
||||||
|
listEntpcoursefile(queryParams).then(response=>{
|
||||||
|
if (response.rows.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
flowData.value = JSON.parse(response.rows[0].datacontent)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// if (item.worktype==='学科定位'){
|
||||||
|
// // TODO 学科定位-还未接入
|
||||||
|
// // this.activeTeachResOfStandard = item;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
watch(() => props.bookobj.levelSecondId, (newVal) => {
|
||||||
|
// console.log(props.bookobj,'课程选择')
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
openDialog,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.prev-read-zy-wrap .el-dialog__header{
|
||||||
|
padding: 0!important;
|
||||||
|
}
|
||||||
|
.prev-read-zy-wrap .el-dialog__header button{
|
||||||
|
z-index: 99;
|
||||||
|
}
|
||||||
|
.prev-read-zy-wrap .el-dialog__body{
|
||||||
|
padding: 0!important;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -222,25 +222,8 @@
|
||||||
</div>
|
</div>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<!-- 预览框 -->
|
<!-- 预览框 -->
|
||||||
<el-dialog v-if="prevReadMsg.visible" v-model="prevReadMsg.visible" class="prev-read-zy-wrap" width="90%" style="height: 80vh" append-to-body>
|
<prevReadMsgDialog ref="prevReadMsgDialogRef" :bookobj="props.bookobj"/>
|
||||||
<!-- <div v-if="prevReadMsg.type=='课标研读'" style="height: 100%;">
|
|
||||||
<standard book-type="课标研读" :show-cata="true" :show-tools="false" :course-obj="courseObj" :bookdatahtml="versionObj.bookdata" :teachResObj="activeTeachResOfStandard"></standard>
|
|
||||||
</div>
|
|
||||||
<div v-if="prevReadMsg.type=='目标设定'" style="height: 100%;display: flex;">
|
|
||||||
<degreeevolution :courseObj="courseObj" :show-class="true" :teachResObj="activeTeachResOfStandard" :attainmentList="attainmentList" :courseQualityList="courseQualityList"/>
|
|
||||||
</div>
|
|
||||||
<div v-if="prevReadMsg.type=='教材研读'" style="height: 100%;">
|
|
||||||
<standard book-type="教材研读" :course-obj="courseObj" :show-tools="false" :bookdatahtml="versionObj.bookdata" :teachResObj="activeTeachResOfStandard"></standard>
|
|
||||||
</div> -->
|
|
||||||
<div v-if="prevReadMsg.type=='框架梳理'" style="height: 100%;">
|
|
||||||
<FlowChart ref="flowref" :flowHeight="mainHeight" :dataSource="flowData"/>
|
|
||||||
</div>
|
|
||||||
<!-- <div v-if="prevReadMsg.type=='学科定位'" style="height: 100%;">
|
|
||||||
<teachJsMind :course-obj="courseObj" :teachResObj="activeTeachResOfStandard"></teachJsMind>
|
|
||||||
</div> -->
|
|
||||||
<!-- <div v-if="prevReadMsg.type=='习题训练'">习题训练</div> -->
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -260,16 +243,16 @@ import { listKnowledgePoint } from "@/api/knowledge/knowledgePoint";
|
||||||
import { useGetHomework } from '@/hooks/useGetHomework'
|
import { useGetHomework } from '@/hooks/useGetHomework'
|
||||||
import { processList } from '@/hooks/useProcessList'
|
import { processList } from '@/hooks/useProcessList'
|
||||||
import { getCurrentTime } from '@/utils/date'
|
import { getCurrentTime } from '@/utils/date'
|
||||||
import FlowChart from "@/components/Flowchart/index.vue";
|
|
||||||
import FileUpload from "@/components/FileUpload/index.vue";
|
import FileUpload from "@/components/FileUpload/index.vue";
|
||||||
import whiteboard from '@/components/whiteboard/whiteboard.vue'
|
import whiteboard from '@/components/whiteboard/whiteboard.vue'
|
||||||
|
import prevReadMsgDialog from '@/views/classTask/container/newTask/prevReadMsg-Dialog.vue'
|
||||||
|
|
||||||
import { useToolState } from '@/store/modules/tool'
|
import { useToolState } from '@/store/modules/tool'
|
||||||
import useUserStore from '@/store/modules/user'
|
import useUserStore from '@/store/modules/user'
|
||||||
const userStore = useUserStore().user
|
const userStore = useUserStore().user
|
||||||
const { proxy } = getCurrentInstance()
|
const { proxy } = getCurrentInstance()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const toolStore = useToolState()
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
bookobj: {
|
bookobj: {
|
||||||
|
@ -283,15 +266,15 @@ const props = defineProps({
|
||||||
isedit: {
|
isedit: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
},
|
||||||
|
isback:{
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const prevReadMsgDialogRef = ref(null);// 预览框ref
|
||||||
|
|
||||||
const isDialogOpen = ref(false)
|
|
||||||
const toolStore = useToolState()
|
|
||||||
const openDialog = () => {
|
|
||||||
isDialogOpen.value = true
|
|
||||||
}
|
|
||||||
const classWorkFormRef = ref(null);
|
const classWorkFormRef = ref(null);
|
||||||
const entpCourseWorkTypeList = ref([
|
const entpCourseWorkTypeList = ref([
|
||||||
{value: 0, label: "不限"},
|
{value: 0, label: "不限"},
|
||||||
|
@ -372,12 +355,6 @@ const listWorkType = ref(['习题训练', '框架梳理', '课堂展示', '常
|
||||||
|
|
||||||
// 课堂展示-------
|
// 课堂展示-------
|
||||||
const boardLoading = ref(false);
|
const boardLoading = ref(false);
|
||||||
const prevReadMsg = reactive({
|
|
||||||
visible: false,
|
|
||||||
type: ""
|
|
||||||
});// 预览msg
|
|
||||||
// 框架梳理----------
|
|
||||||
const flowData = ref({})// 框架梳理
|
|
||||||
//常规作业----------
|
//常规作业----------
|
||||||
const fileLoading = ref(false); // 常规作业loading
|
const fileLoading = ref(false); // 常规作业loading
|
||||||
|
|
||||||
|
@ -388,8 +365,6 @@ const changeFormType = (val) => {
|
||||||
classWorkForm.worktype = val;
|
classWorkForm.worktype = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(props.propsformobj)
|
|
||||||
console.log(classWorkForm,'==============zizujian===================')
|
|
||||||
/**
|
/**
|
||||||
* @desc: 根据查询参数查询试题
|
* @desc: 根据查询参数查询试题
|
||||||
* @return: {*}
|
* @return: {*}
|
||||||
|
@ -565,61 +540,7 @@ const handleClassWorkQuizAdd = (fromsrc, entpcourseworkid) => {
|
||||||
* 预览资源
|
* 预览资源
|
||||||
*/
|
*/
|
||||||
const prevRead = async (item) => {
|
const prevRead = async (item) => {
|
||||||
prevReadMsg.visible = true;
|
proxy.$refs.prevReadMsgDialogRef.openDialog(item);
|
||||||
prevReadMsg.type = item.worktype;
|
|
||||||
if (item.worktype==='课标研读'){
|
|
||||||
//获取教材文件和批注信息
|
|
||||||
listEvaluation({itemkey: 'subject', edusubject: userStore.edusubject, edustage: userStore.edustage}).then(res => {
|
|
||||||
// TODO 课标研读-还未接入
|
|
||||||
console.log("课标研读-还未接入",res);
|
|
||||||
// this.versionObj = res.rows[0];
|
|
||||||
// // 读取出课标文件的每一行
|
|
||||||
// if (this.versionObj.fileurl.length > 0) {
|
|
||||||
// readFile({cluelink: this.versionObj.fileurl}).then(fileres => {
|
|
||||||
// this.versionObj.bookdata = fileres;
|
|
||||||
// this.activeTeachResOfStandard = item;
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (item.worktype==='目标设定'){
|
|
||||||
// TODO 目标设定-还未接入
|
|
||||||
// this.activeTeachResOfStandard = item;
|
|
||||||
}
|
|
||||||
if (item.worktype==='教材研读'){
|
|
||||||
// TODO 教材研读-还未接入
|
|
||||||
// getEvaluation(this.courseObj.evalrootid).then(bookres => {
|
|
||||||
// this.versionObj = bookres.data;
|
|
||||||
// if (this.versionObj.fileurl.length > 0) {
|
|
||||||
// readFile({cluelink: this.versionObj.fileurl}).then(fileres => {
|
|
||||||
// this.versionObj.bookdata = fileres;
|
|
||||||
// this.activeTeachResOfStandard = item;
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
}
|
|
||||||
if (item.worktype==='框架梳理'){
|
|
||||||
flowData.value = {};
|
|
||||||
const { chapterId } = await useGetHomework(props.bookobj.node)
|
|
||||||
// this.entpcourseid = chapterId
|
|
||||||
let queryParams = {
|
|
||||||
entpcourseid: chapterId,
|
|
||||||
ppttype: '教材分析',
|
|
||||||
parentid: item.id,
|
|
||||||
title: '逻辑框架建构',
|
|
||||||
filetype: 'draw'
|
|
||||||
}
|
|
||||||
listEntpcoursefile(queryParams).then(response=>{
|
|
||||||
if (response.rows.length == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
flowData.value = JSON.parse(response.rows[0].datacontent)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (item.worktype==='学科定位'){
|
|
||||||
// TODO 学科定位-还未接入
|
|
||||||
// this.activeTeachResOfStandard = item;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* 添加到作业
|
* 添加到作业
|
||||||
|
@ -731,16 +652,7 @@ const handleClassWorkSave = async () => {
|
||||||
// 情况选择的资源缓存
|
// 情况选择的资源缓存
|
||||||
classWorkForm.chooseWorkLists = []; // 框架梳理list
|
classWorkForm.chooseWorkLists = []; // 框架梳理list
|
||||||
classWorkForm.whiteboardObj = ''; // ? // 清空白板
|
classWorkForm.whiteboardObj = ''; // ? // 清空白板
|
||||||
// refresh the list
|
|
||||||
//这里分离了,所以不需要更新表单数据了
|
|
||||||
// this.getClassWorkAllList();
|
|
||||||
|
|
||||||
// TODO 后续看是否跳转到 作业布置页面
|
|
||||||
|
|
||||||
//TODO 下面3个后续看是啥
|
|
||||||
// this.newWorkSpace = false;
|
|
||||||
// this.newWorkSpaceEdit = false;
|
|
||||||
// this.workEdit = false;
|
|
||||||
boardLoading.value = false
|
boardLoading.value = false
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -764,16 +676,6 @@ const handleClassWorkSave = async () => {
|
||||||
classWorkForm.chooseWorkLists = []; // 框架梳理list
|
classWorkForm.chooseWorkLists = []; // 框架梳理list
|
||||||
classWorkForm.whiteboardObj = ''; // ? // 清空白板
|
classWorkForm.whiteboardObj = ''; // ? // 清空白板
|
||||||
classWorkForm.fileHomeworkList = []; // 常规作业list
|
classWorkForm.fileHomeworkList = []; // 常规作业list
|
||||||
// refresh the list
|
|
||||||
//这里分离了,所以不需要更新表单数据了
|
|
||||||
// this.getClassWorkAllList();
|
|
||||||
|
|
||||||
// TODO 后续看是否跳转到 作业布置页面
|
|
||||||
|
|
||||||
//TODO 下面3个后续看是啥
|
|
||||||
// this.newWorkSpace = false;
|
|
||||||
// this.newWorkSpaceEdit = false;
|
|
||||||
// this.workEdit = false;
|
|
||||||
|
|
||||||
fileLoading.value = false
|
fileLoading.value = false
|
||||||
})
|
})
|
||||||
|
@ -820,18 +722,23 @@ const handleClassWorkSave = async () => {
|
||||||
//这里分离了,所以不需要更新表单数据了
|
//这里分离了,所以不需要更新表单数据了
|
||||||
// this.getClassWorkAllList();
|
// this.getClassWorkAllList();
|
||||||
|
|
||||||
// TODO 后续看是否跳转到 作业布置页面
|
|
||||||
|
|
||||||
//TODO 下面3个后续看是啥
|
|
||||||
// this.newWorkSpace = false;
|
|
||||||
// this.newWorkSpaceEdit = false;
|
|
||||||
// this.workEdit = false;
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(props.isback){
|
||||||
|
// 其他页面进入的 返回上一页
|
||||||
|
router.back();
|
||||||
|
}else{
|
||||||
|
// 首页进入的,跳转到作业布置页面
|
||||||
|
router.push({ path: '/classTaskAssign' });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* 编辑作业内容
|
||||||
|
* @param cform 表单数据
|
||||||
|
*/
|
||||||
const editWork = async (cform) =>{
|
const editWork = async (cform) =>{
|
||||||
// 基础参数
|
// 基础参数
|
||||||
cform.id= classWorkForm.id;
|
cform.id= classWorkForm.id;
|
||||||
|
@ -1056,3 +963,4 @@ watch(() => props.bookobj.levelSecondId, (newVal) => {
|
||||||
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<style src="@/assets/styles/JYStyle.css"></style>
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
<el-row style="align-items: center; margin-bottom: 0px; flex: 0 0 auto">
|
<el-row style="align-items: center; margin-bottom: 0px; flex: 0 0 auto">
|
||||||
<el-col :span="12" style="padding-left: 20px; text-align: left;">
|
<el-col :span="12" style="padding-left: 20px; text-align: left;">
|
||||||
<div v-if="!isOpenLeftBook" class="unit-top-left cursor-pointer" @click="onOpenLeftBook">
|
<div v-if="!isOpenLeftBook" class="unit-top-left cursor-pointer" @click="onOpenLeftBook">
|
||||||
|
<i v-if="isback" class="iconfont icon-xiangzuo cursor-pointer" style="color: blue;" @click="goBack">返回上页</i>
|
||||||
<i v-if="!isCollapse" class="iconfont icon-xiangzuo" style="color: blue;"></i>
|
<i v-if="!isCollapse" class="iconfont icon-xiangzuo" style="color: blue;"></i>
|
||||||
<span>课程目录</span>
|
<span>课程目录</span>
|
||||||
<i v-if="isCollapse" class="iconfont icon-xiangyou" style="color: blue;"></i>
|
<i v-if="isCollapse" class="iconfont icon-xiangyou" style="color: blue;"></i>
|
||||||
|
@ -35,7 +36,7 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<!-- 作业类型:内容 -->
|
<!-- 作业类型:内容 -->
|
||||||
<task-type-view :bookobj="courseObj" :propsformobj="classWorkForm" :isedit="isOpenLeftBook" style="flex: 1; overflow: hidden;"/>
|
<task-type-view :bookobj="courseObj" :isback="isback" :propsformobj="classWorkForm" :isedit="isOpenLeftBook" style="flex: 1; overflow: hidden;"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -53,6 +54,7 @@ const route = useRoute();
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { proxy } = getCurrentInstance()
|
const { proxy } = getCurrentInstance()
|
||||||
|
|
||||||
|
const isback = ref(route.query.isBack?true:false);
|
||||||
const classtaskObj = route.query.classtaskObj;//作业布置的内容对象
|
const classtaskObj = route.query.classtaskObj;//作业布置的内容对象
|
||||||
const bookTitle = ref(classtaskObj? JSON.parse(classtaskObj).bookName: '');// 课程名称
|
const bookTitle = ref(classtaskObj? JSON.parse(classtaskObj).bookName: '');// 课程名称
|
||||||
const isOpenLeftBook = ref(classtaskObj? JSON.parse(classtaskObj).id ? true : false: false ); // 是否打开左侧目录
|
const isOpenLeftBook = ref(classtaskObj? JSON.parse(classtaskObj).id ? true : false: false ); // 是否打开左侧目录
|
||||||
|
@ -183,3 +185,4 @@ onMounted(() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<style src="@/assets/styles/JYStyle.css"></style>
|
||||||
|
|
|
@ -152,7 +152,7 @@ import useUserStore from '@/store/modules/user'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { getCurrentTime, getAfterMinutes } from '@/utils/date'
|
import { getCurrentTime, getAfterMinutes } from '@/utils/date'
|
||||||
import { processList } from '@/hooks/useProcessList'
|
import { processList } from '@/hooks/useProcessList'
|
||||||
import ItemDialogScore from '@/views/classTask/container/item-dialog-score.vue'
|
import ItemDialogScore from '@/views/classTask/container/classTask/item-dialog-score.vue'
|
||||||
// zdg: 组件导入
|
// zdg: 组件导入
|
||||||
import quizStats from '@/views/classTask/container/quizStats.vue'
|
import quizStats from '@/views/classTask/container/quizStats.vue'
|
||||||
import ClassOverview from '@/views/classTask/container/classOverview.vue'
|
import ClassOverview from '@/views/classTask/container/classOverview.vue'
|
||||||
|
@ -410,15 +410,15 @@ const getStudentClassWorkDataDetail = (row) => {
|
||||||
wevalres.rows[w].score = wevalres.rows[w].score ? wevalres.rows[w].score : 0
|
wevalres.rows[w].score = wevalres.rows[w].score ? wevalres.rows[w].score : 0
|
||||||
|
|
||||||
// 参考答案 去除下html标签
|
// 参考答案 去除下html标签
|
||||||
wevalres.rows[w].rightanswer =
|
// wevalres.rows[w].rightanswer =
|
||||||
wevalres.rows[w].rightanswer != '' && wevalres.rows[w].rightanswer != null
|
// wevalres.rows[w].rightanswer != '' && wevalres.rows[w].rightanswer != null
|
||||||
? wevalres.rows[w].rightanswer.replace(/<[^>]+>/g, '')
|
// ? wevalres.rows[w].rightanswer.replace(/<[^>]+>/g, '')
|
||||||
: wevalres.rows[w].rightanswer
|
// : wevalres.rows[w].rightanswer
|
||||||
// 学生回答 去除下html标签
|
// // 学生回答 去除下html标签
|
||||||
wevalres.rows[w].feedcontent =
|
// wevalres.rows[w].feedcontent =
|
||||||
wevalres.rows[w].feedcontent != '' && wevalres.rows[w].feedcontent != null
|
// wevalres.rows[w].feedcontent != '' && wevalres.rows[w].feedcontent != null
|
||||||
? wevalres.rows[w].feedcontent.replace(/<[^>]+>/g, '')
|
// ? wevalres.rows[w].feedcontent.replace(/<[^>]+>/g, '')
|
||||||
: wevalres.rows[w].feedcontent
|
// : wevalres.rows[w].feedcontent
|
||||||
|
|
||||||
if (classWorkAnalysis.row.worktype == '常规作业') {
|
if (classWorkAnalysis.row.worktype == '常规作业') {
|
||||||
wevalres.rows[w].feedcontent = JSON.parse(wevalres.rows[w].feedcontent)
|
wevalres.rows[w].feedcontent = JSON.parse(wevalres.rows[w].feedcontent)
|
||||||
|
@ -634,8 +634,9 @@ const closeDialog = () => {
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|
||||||
// const data = JSON.parse(localStorage.getItem('teachClassWorkItem'));
|
const data = JSON.parse(localStorage.getItem('teachClassWorkItem'));
|
||||||
const data = sessionStore.get('teachClassWorkItem');
|
// const data = sessionStore.get('teachClassWorkItem');
|
||||||
|
// const data = localStorage.getItem('teachClassWorkItem');
|
||||||
console.log(data,'????????????????????' )
|
console.log(data,'????????????????????' )
|
||||||
if(data){
|
if(data){
|
||||||
openDialog(data)
|
openDialog(data)
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
<span class="name">{{ item.uniquekey }}</span>
|
<span class="name">{{ item.uniquekey }}</span>
|
||||||
<el-tag class="tag" round :type="tagType(item.deaddate)" effect="dark" size="small">{{
|
<el-tag class="tag" round :type="tagType(item.deaddate)" effect="dark" size="small">{{
|
||||||
getCurrentTime('YYYY-MM-DD HH:mm') > item.deaddate ? '已结束' : '进行中' }}</el-tag>
|
getCurrentTime('YYYY-MM-DD HH:mm') > item.deaddate ? '已结束' : '进行中' }}</el-tag>
|
||||||
|
<el-tag :type="item.workclass" size="large">{{ item.worktype }}</el-tag>
|
||||||
</div>
|
</div>
|
||||||
<div class="class-time">{{ item.classcaption }} | 截止时间:{{ item.deaddate }} </div>
|
<div class="class-time">{{ item.classcaption }} | 截止时间:{{ item.deaddate }} </div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -50,11 +51,27 @@ const getHomework = async () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
const { edustage, edusubject } = user
|
const { edustage, edusubject } = user
|
||||||
try {
|
try {
|
||||||
const { rows } = await homeworklist({ edituserid: user.userId, edustage, edusubject, deaddate: getTomorrow(), status: '1', orderby: 'uniquekey DESC', pageSize: 500 })
|
const { rows } = await homeworklist({ edituserid: user.userId, edustage, edusubject, deaddate: getTomorrow(), status: '1', orderby: 'deaddate DESC', pageSize: 500 })
|
||||||
// 只展示进行中的
|
// 只展示进行中的
|
||||||
// homeworkList.value = rows.filter(item => item.deaddate && item.uniquekey && getCurrentTime('YYYY-MM-DD HH:mm') < item.deaddate)
|
homeworkList.value = rows.filter(item => item.deaddate && item.uniquekey && getCurrentTime('YYYY-MM-DD HH:mm') < item.deaddate) // 当前日期的时分与截止日期进行判断
|
||||||
homeworkList.value = rows.filter(item => item.deaddate && item.uniquekey && getTomorrow() <= item.deaddate) //大于今天的才算进行中
|
// homeworkList.value = rows.filter(item => item.deaddate && item.uniquekey && getTomorrow() <= item.deaddate) //大于今天的才算进行中 弃用
|
||||||
homeworkList.value.forEach((item) => {
|
homeworkList.value.forEach((item) => {
|
||||||
|
// 处理任务类型的UI
|
||||||
|
if (item.worktype == '学习目标定位') {
|
||||||
|
item.workclass = 'success'
|
||||||
|
item.workcodesList = JSON.parse(item.workcodes)
|
||||||
|
} else if (item.worktype == '教材研读') {
|
||||||
|
item.workclass = 'primary'
|
||||||
|
} else if (item.worktype == '框架梳理') {
|
||||||
|
item.workclass = 'warning'
|
||||||
|
} else if (item.worktype == '学科定位') {
|
||||||
|
item.workclass = 'info'
|
||||||
|
} else if (item.worktype == '习题训练') {
|
||||||
|
item.workclass = 'danger'
|
||||||
|
} else {
|
||||||
|
item.workclass = ''
|
||||||
|
}
|
||||||
|
|
||||||
item.workdatacount = JSON.parse('[' + item.classworkdatastudentids + ']').length
|
item.workdatacount = JSON.parse('[' + item.classworkdatastudentids + ']').length
|
||||||
// 如果是习题训练任务,则检查一共有多少道
|
// 如果是习题训练任务,则检查一共有多少道
|
||||||
if (item.entpcourseworklist != '') {
|
if (item.entpcourseworklist != '') {
|
||||||
|
@ -79,7 +96,8 @@ const debounceOpenWin = debounce(() => {
|
||||||
// 批改作业
|
// 批改作业
|
||||||
const onClickItem = (item) => {
|
const onClickItem = (item) => {
|
||||||
console.log('防抖开启弹窗')
|
console.log('防抖开启弹窗')
|
||||||
sessionStore.set('teachClassWorkItem', item); // 缓存点击的item
|
// sessionStore.set('teachClassWorkItem', item); // 缓存点击的item
|
||||||
|
localStorage.setItem('teachClassWorkItem', JSON.stringify(item));
|
||||||
debounceOpenWin();
|
debounceOpenWin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -113,17 +113,17 @@ const menuList = [{
|
||||||
{
|
{
|
||||||
name: '作业设计',
|
name: '作业设计',
|
||||||
icon: '#icon-zuoyesheji',
|
icon: '#icon-zuoyesheji',
|
||||||
isOuter: true,
|
// isOuter: true,
|
||||||
path: '/teaching/classtaskassign?titleName=作业布置&openDialog=newClassTask',
|
// path: '/teaching/classtaskassign?titleName=作业布置&openDialog=newClassTask',
|
||||||
// path: '/newClassTask',
|
path: '/newClassTask',
|
||||||
id: '2-1'
|
id: '2-1'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '作业布置',
|
name: '作业布置',
|
||||||
icon: '#icon-zuoyebuzhi',
|
icon: '#icon-zuoyebuzhi',
|
||||||
isOuter: true,
|
// isOuter: true,
|
||||||
path: '/teaching/classtaskassign?titleName=作业布置',
|
// path: '/teaching/classtaskassign?titleName=作业布置',
|
||||||
// path: '/classTaskAssign',
|
path: '/classTaskAssign',
|
||||||
id: '2-2'
|
id: '2-2'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,22 +19,29 @@
|
||||||
|
|
||||||
<!-- 试题详情 -->
|
<!-- 试题详情 -->
|
||||||
<el-drawer v-model="activeExamInfoDrawer" title="题目详情" :with-header="false" direction="rtl" size="60%">
|
<el-drawer v-model="activeExamInfoDrawer" title="题目详情" :with-header="false" direction="rtl" size="60%">
|
||||||
<el-row class="drawer-main">
|
<div style="height: calc(100% - 50px);">
|
||||||
<el-col :span="24">
|
<el-scrollbar style="background: #e9e9e9;border-radius: 8px;">
|
||||||
<span>{{activeExam.worktag}}</span>
|
<el-row class="drawer-main">
|
||||||
<span style="margin-left: 4px" v-html="activeExam.titleFormat" ></span>
|
<el-col :span="24">
|
||||||
</el-col>
|
<span>{{activeExam.worktag}}</span>
|
||||||
<el-col :span="24" style="padding: 4px" v-html="activeExam.workdescFormat">
|
<span style="margin-left: 4px" v-html="activeExam.titleFormat" ></span>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="3" class="drawer-main-col"><em>【答案】</em></el-col>
|
<el-col :span="24" style="padding: 4px" v-html="activeExam.workdescFormat">
|
||||||
<el-col :span="20" class="drawer-main-col" v-html="activeExam.workanswerFormat"></el-col>
|
</el-col>
|
||||||
<el-col :span="3" class="drawer-main-col"><em>【分析】</em></el-col>
|
<el-col :span="3" class="drawer-main-col"><em>【答案】</em></el-col>
|
||||||
<el-col :span="20" class="drawer-main-col" v-html="activeExam.method"></el-col>
|
<el-col :span="20" class="drawer-main-col" v-html="activeExam.workanswerFormat"></el-col>
|
||||||
<el-col :span="3" class="drawer-main-col"><em>【解答】</em></el-col>
|
<el-col :span="3" class="drawer-main-col"><em>【分析】</em></el-col>
|
||||||
<el-col :span="20" class="drawer-main-col" v-html="activeExam.analyse"></el-col>
|
<el-col :span="20" class="drawer-main-col" v-html="activeExam.method"></el-col>
|
||||||
<el-col :span="3" class="drawer-main-col" ><em>【点评】</em></el-col>
|
<el-col :span="3" class="drawer-main-col"><em>【解答】</em></el-col>
|
||||||
<el-col :span="20" class="drawer-main-col" v-html="activeExam.discuss"></el-col>
|
<el-col :span="20" class="drawer-main-col" v-html="activeExam.analyse"></el-col>
|
||||||
</el-row>
|
<el-col :span="3" class="drawer-main-col" ><em>【点评】</em></el-col>
|
||||||
|
<el-col :span="20" class="drawer-main-col" v-html="activeExam.discuss"></el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-scrollbar>
|
||||||
|
</div>
|
||||||
|
<div class="drawer-footer">
|
||||||
|
<el-button type="primary" @click="activeExamInfoDrawer = false">关闭</el-button>
|
||||||
|
</div>
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -89,13 +96,17 @@ const showExamAnalyseDrawer = (row) => {
|
||||||
|
|
||||||
.drawer-main{
|
.drawer-main{
|
||||||
margin: 1%;
|
margin: 1%;
|
||||||
padding: 1% 2%;
|
padding: 2%;
|
||||||
border: 2px dotted;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
|
||||||
.drawer-main-col{
|
.drawer-main-col{
|
||||||
padding: 10px 0px;
|
padding: 10px 0px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.drawer-footer{
|
||||||
|
padding-top: 15px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
|
@ -0,0 +1,719 @@
|
||||||
|
<template>
|
||||||
|
<div class="ai-container">
|
||||||
|
<el-steps style="max-width:100% " :active="activeStep" align-center>
|
||||||
|
<el-step title="开始创作" />
|
||||||
|
<el-step title="输入主题" />
|
||||||
|
<el-step title="编辑大纲" />
|
||||||
|
<el-step title="选择模板" />
|
||||||
|
<el-step title="制作PPT" />
|
||||||
|
</el-steps>
|
||||||
|
<div class="card-box">
|
||||||
|
<el-card class="card1" v-if="activeStep == 0">
|
||||||
|
<el-tabs v-model="activeName" type="card" class="demo-tabs">
|
||||||
|
<el-tab-pane label="输入主题与要求" name="first">
|
||||||
|
<div style="padding: 20px;">输入主题</div>
|
||||||
|
<el-input type="textarea" v-model="inputTheme" :rows="3" placeholder="在此输入您的PPT主题..."
|
||||||
|
@keydown.enter.exact.prevent="addMessage" @keydown.enter.shift.exact.prevent="inputTheme += '\n'" />
|
||||||
|
<div style="padding: 20px;">具体生成要求</div>
|
||||||
|
<el-input type="textarea" v-model="inputRequire" :rows="3" placeholder="请输入对生成大纲的具体要求,比如要包含那些内容"
|
||||||
|
@keydown.enter.exact.prevent="addMessage" @keydown.enter.shift.exact.prevent="inputRequire += '\n'" />
|
||||||
|
<div>
|
||||||
|
<el-button style="margin:15px 0" type="primary" @click="addMessage">生成大纲→</el-button>
|
||||||
|
</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
<!-- <el-tab-pane label="上传文件并解析" name="second">
|
||||||
|
<el-upload action="#" :on-change="onFileChange" :before-upload="beforeUpload" :show-file-list="false">
|
||||||
|
<el-button type="primary">点击上传并解析文件</el-button>
|
||||||
|
<text>(支持 doc/docx、pdf、md、txt 格式文档,不超过 20M,不超过 100W 字符)</text>
|
||||||
|
</el-upload>
|
||||||
|
<br/>
|
||||||
|
<div v-if="enableButton">{{docName}}文档已解析完毕</div>
|
||||||
|
<br/>
|
||||||
|
<div style="padding: 20px;">输入主题</div>
|
||||||
|
<textarea style="width:50vw" v-model="inputTheme" :rows="3" placeholder="在此输入您的PPT主题..."
|
||||||
|
@keydown.enter.shift.exact.prevent="inputTheme += '\n'">
|
||||||
|
</textarea>
|
||||||
|
<div style="padding: 20px;">具体生成要求</div>
|
||||||
|
<textarea style="width:50vw; margin:20px" v-model="docRequire" :rows="3"
|
||||||
|
placeholder="请输入对生成大纲的具体要求,比如要包含那些内容" @keydown.enter.shift.exact.prevent="inputRequire += '\n'">
|
||||||
|
</textarea>
|
||||||
|
<div>
|
||||||
|
<el-button style="padding:15px" type="primary" :disabled="!enableButton"
|
||||||
|
@click="chatDoc">生成大纲→</el-button>
|
||||||
|
</div>
|
||||||
|
</el-tab-pane> -->
|
||||||
|
</el-tabs>
|
||||||
|
</el-card>
|
||||||
|
<el-card class="card2" v-if="activeStep == 1">
|
||||||
|
<div class="paragraphs">
|
||||||
|
{{ outputText }}
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
<el-card class="card3" v-if="activeStep == 2">
|
||||||
|
<div class="outline">
|
||||||
|
<el-scrollbar height="250px">
|
||||||
|
<el-row :gutter="20" class="outline-row">
|
||||||
|
<el-col :span="8">
|
||||||
|
<div v-for="item in firstArray" :key="item" class="item-with-dash">{{ item }}</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="16">
|
||||||
|
<div v-for="(item, index) in secondArray" :key="index">
|
||||||
|
<el-input v-model="item.value"></el-input>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-scrollbar>
|
||||||
|
</div>
|
||||||
|
<el-input type="textarea" v-model="fixRequire" :rows="3" placeholder="与AI对话,告诉AI您想如何修改"
|
||||||
|
@keydown.enter.exact.prevent="fixOutline" @keydown.enter.shift.exact.prevent="inputRequire += '\n'" />
|
||||||
|
<br />
|
||||||
|
<el-button v-if="fixRequire.length > 0" style="padding:15px" type="primary"
|
||||||
|
@click="fixOutline()">发送修改</el-button>
|
||||||
|
<el-button style="margin-top:15px" type="primary" @click="combineOutline()">下一步→</el-button>
|
||||||
|
</el-card>
|
||||||
|
<el-card v-if="activeStep == 3">
|
||||||
|
<div style="padding-bottom: 10px">ppt模板选择</div>
|
||||||
|
<div class="themes">
|
||||||
|
<div v-for="item in backGroundList" :key="item.key" :style="{
|
||||||
|
padding: '20px',
|
||||||
|
paddingRight: '30px',
|
||||||
|
paddingLeft: '30px',
|
||||||
|
margin: '10px',
|
||||||
|
backgroundColor: getBackgroundColor(item.key),
|
||||||
|
borderRadius: '10px',
|
||||||
|
borderBlock: '10px solid #e6e6e6'
|
||||||
|
}" @click="chooseBackground(item.key)" @mouseenter="changeCursor('pointer')" @mouseleave="changeCursor('default')">
|
||||||
|
{{ item.name }}
|
||||||
|
<br />
|
||||||
|
<img style="width: 150px; height: auto" :src="item.thumbnail" alt="" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-row class="el-row">
|
||||||
|
<el-col :span="6" class="el-col">
|
||||||
|
<div class="grid-content-1">
|
||||||
|
<div>演讲备注</div>
|
||||||
|
<el-switch v-model="outlineData.is_card_note" />
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6" class="el-col">
|
||||||
|
<div class="grid-content-2">
|
||||||
|
<div>生成封面</div>
|
||||||
|
<el-switch v-model="outlineData.is_cover_img" />
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6" class="el-col">
|
||||||
|
<div class="grid-content-1">
|
||||||
|
<div>自动配图</div>
|
||||||
|
<el-switch v-model="outlineData.is_figure" />
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6" class="el-col">
|
||||||
|
<div class="grid-content-2">
|
||||||
|
<div>PPT作者名:</div>
|
||||||
|
<el-input v-model="outlineData.author" style="width: 50%" />
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<div>
|
||||||
|
<el-button style="margin-bottom: 5px;" type="primary" @click="outlineCreatePPT()">生成PPT</el-button>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
<el-card v-if="activeStep == 4">
|
||||||
|
<el-progress :percentage="30" type="circle" v-if="percentage == 30"></el-progress>
|
||||||
|
<el-progress :percentage="70" type="circle" v-if="percentage == 70"></el-progress>
|
||||||
|
<el-progress :percentage="100" type="circle" v-if="percentage == 100"></el-progress>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
import { creatAIPPT } from '@/utils/talkFile'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import {
|
||||||
|
getBackGround,
|
||||||
|
createPPT,
|
||||||
|
getProgress,
|
||||||
|
} from "@/utils/ppt-request.js";
|
||||||
|
import { uploadDoc, queryDocStatus } from "@/utils/aichat.js";
|
||||||
|
import CryptoJS from "crypto-js"
|
||||||
|
|
||||||
|
import { getSignature } from "@/utils/index.js";
|
||||||
|
|
||||||
|
let appId = "01ec9aa3";
|
||||||
|
let secret = "M2QxMDAxMjYyYTEzODMwMGRkZTQ4NmUy";
|
||||||
|
let apikey = "39d05b269fa229f431a56c21794a8ea5"
|
||||||
|
let timestamp = Math.floor(Date.now() / 1000);
|
||||||
|
let signature = getSignature(appId, secret, timestamp);
|
||||||
|
const { ipcRenderer } = window.electron || {}
|
||||||
|
|
||||||
|
|
||||||
|
const outputText = ref(""); // 用于展示的大纲数据
|
||||||
|
const stagingData = ref([]); //储存的对话数据,用于多轮对话
|
||||||
|
const stagOutputText = ref(""); // 暂存大纲用于拆分
|
||||||
|
let extractedParts = ref([]) // 初步拆分
|
||||||
|
|
||||||
|
let firstArray = ref([]); //大纲的大纲等级数字部分
|
||||||
|
let secondArray = ref([]); //大纲的文字部分
|
||||||
|
|
||||||
|
|
||||||
|
const backGroundList = ref([]);
|
||||||
|
|
||||||
|
const inputTheme = ref(""); // 输入的主题
|
||||||
|
const inputRequire = ref("") // 输入的需求
|
||||||
|
const activeStep = ref(0); // 上方进度条
|
||||||
|
const fixRequire = ref(""); // 对话修改大纲
|
||||||
|
const combined = ref('') // 修改完毕的大纲数据,准备传入ppt生成模型
|
||||||
|
|
||||||
|
const treeData = ref([]);
|
||||||
|
const status = ref("init");
|
||||||
|
|
||||||
|
const percentage = ref(0);
|
||||||
|
|
||||||
|
const activeName = ref("first");
|
||||||
|
|
||||||
|
const getBackground = () => {
|
||||||
|
treeData.value = [];
|
||||||
|
getBackGround().then((res) => {
|
||||||
|
console.log(res);
|
||||||
|
backGroundList.value = res;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getBackgroundColor = (key) => {
|
||||||
|
return outlineData.value.theme === key ? '#83e2b6' : '#f5f5f5';
|
||||||
|
};
|
||||||
|
|
||||||
|
const outlineData = ref({
|
||||||
|
query: '', // 用户要求(最多8000字)
|
||||||
|
theme: 'auto', // ppt生成主题
|
||||||
|
author: 'AIX平台',
|
||||||
|
is_card_note: false, // 是否自动生成ppt演讲备注
|
||||||
|
is_cover_img: false, // 是否自动生成封面
|
||||||
|
is_figure: false, // 是否自动配图
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const emit = defineEmits(['addSuccess'])
|
||||||
|
const props = defineProps({
|
||||||
|
currentNode: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {}
|
||||||
|
},
|
||||||
|
uploadData: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 将输入数据或返回数据存入记忆中
|
||||||
|
function updateStagingData(role, newData) {
|
||||||
|
stagingData.value.push({ role: role, content: newData });
|
||||||
|
}
|
||||||
|
//大纲直接生成ppt
|
||||||
|
const outlineCreatePPT = () => {
|
||||||
|
const newOutlineData = { ...outlineData.value, };
|
||||||
|
newOutlineData.query = combined.value;
|
||||||
|
|
||||||
|
createPPT(newOutlineData).then((res) => {
|
||||||
|
console.log(res, "正在生成中");
|
||||||
|
activeStep.value = 4
|
||||||
|
|
||||||
|
const checkProgress = () => {
|
||||||
|
getProgress(res.sid).then((response) => {
|
||||||
|
percentage.value = response.process;
|
||||||
|
if (response && response.pptUrl && response.pptUrl.length > 4) {
|
||||||
|
console.log('PPT',response)
|
||||||
|
// window.location.href = response.data.pptUrl;
|
||||||
|
//发消息到主进程,携带名称和URL,将URL下载下来后复制到文件列表并上传到服务
|
||||||
|
// let url = "https://bjcdn.openstorage.cn/xinghuo-privatedata/%2Ftmp/apiTempFiledf28bf990a4c40ffb7477ed4b65392c27232357022409613439/%E3%80%8A%E9%9D%99%E5%A5%B3%E3%80%8B%E6%B7%B1%E5%BA%A6%E8%A7%A3%E8%AF%BB%E4%B8%8E%E7%A0%94%E7%A9%B6.pptx"
|
||||||
|
creatAIPPT(props.currentNode.itemtitle + '.pptx',response.pptUrl, props.uploadData).then((res) => {
|
||||||
|
emit('addSuccess',res)
|
||||||
|
})
|
||||||
|
ElMessage.success("生成成功");
|
||||||
|
} else {
|
||||||
|
const sleepTime = 2000;
|
||||||
|
let remainingTime = sleepTime;
|
||||||
|
const intervalId = setInterval(() => {
|
||||||
|
remainingTime -= 100;
|
||||||
|
if (remainingTime <= 0) {
|
||||||
|
clearInterval(intervalId);
|
||||||
|
checkProgress();
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
checkProgress();
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
//初次对话
|
||||||
|
const addMessage = () => {
|
||||||
|
const themeValue = inputTheme.value;
|
||||||
|
const requireValue = inputRequire.value;
|
||||||
|
firstArray.value = []
|
||||||
|
secondArray.value = []
|
||||||
|
extractedParts.value = []
|
||||||
|
stagOutputText.value = ''
|
||||||
|
const combinedString = `请帮我生成一个ppt大纲,主题为:${themeValue}。具体内容要求为:${requireValue}。注意,用三个等级大纲展示,如1. 1.1 1.1.2 2. 2.1这种类型,且按照这种顺序,不要有完全相同数字等级的大纲,不要有目录`
|
||||||
|
updateStagingData("user", combinedString);
|
||||||
|
connectWebSocket(stagingData.value);
|
||||||
|
activeStep.value = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
//修改大纲时和ai对话
|
||||||
|
const fixOutline = () => {
|
||||||
|
outputText.value = '';
|
||||||
|
firstArray.value = [];
|
||||||
|
secondArray.value = [];
|
||||||
|
extractedParts.value = []
|
||||||
|
stagOutputText.value = ''
|
||||||
|
|
||||||
|
const fixValue = fixRequire.value;
|
||||||
|
updateStagingData('user', fixValue)
|
||||||
|
activeStep.value = 1
|
||||||
|
if (enableButton.value) {
|
||||||
|
uploadAndAskMainContent(stagingData.value)
|
||||||
|
} else { connectWebSocket(stagingData.value); }
|
||||||
|
fixRequire.value = ''
|
||||||
|
};
|
||||||
|
|
||||||
|
// 大纲的拆分
|
||||||
|
function extractAndRemove() {
|
||||||
|
let startIndex = -1;
|
||||||
|
let endIndex = -1;
|
||||||
|
|
||||||
|
for (let i = 0; i < stagOutputText.value.length; i++) {
|
||||||
|
const char = stagOutputText.value[i];
|
||||||
|
if (!isNaN(parseInt(char))) {
|
||||||
|
startIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startIndex !== -1) {
|
||||||
|
for (let j = startIndex; j < stagOutputText.value.length; j++) {
|
||||||
|
const char2 = stagOutputText.value[j];
|
||||||
|
if (char2 === '\n') {
|
||||||
|
endIndex = j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let extractedPart = '';
|
||||||
|
if (startIndex !== -1 && endIndex !== -1) {
|
||||||
|
extractedPart = stagOutputText.value.slice(startIndex, endIndex).replace(/\n/g, '');
|
||||||
|
extractedParts.value.push(extractedPart);
|
||||||
|
stagOutputText.value = stagOutputText.value.replace(extractedPart, '');
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始大纲拆分
|
||||||
|
function startExtraction() {
|
||||||
|
stagOutputText.value = outputText.value
|
||||||
|
while (extractAndRemove()) { }
|
||||||
|
|
||||||
|
//将拆分好的大纲的大纲等级和文字部分拆分到两个数组中
|
||||||
|
extractedParts.value.forEach(item => {
|
||||||
|
const parts = item.split(' ');
|
||||||
|
if (parts.length === 2) {
|
||||||
|
firstArray.value.push(parts[0]);
|
||||||
|
secondArray.value.push({ value: parts[1] });
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拼接修改完毕的大纲
|
||||||
|
function combineOutline() {
|
||||||
|
let tempCombined = '';
|
||||||
|
for (let i = 0; i < Math.max(firstArray.value.length, secondArray.value.length); i++) {
|
||||||
|
tempCombined += firstArray.value[i] || '';
|
||||||
|
tempCombined += secondArray.value[i] ? secondArray.value[i].value : '';
|
||||||
|
tempCombined += i < Math.max(firstArray.value.length, secondArray.value.length) - 1 ? ',' : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
combined.value = tempCombined;
|
||||||
|
fixRequire.value = ''
|
||||||
|
activeStep.value = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let ttsWS
|
||||||
|
function connectWebSocket(data) {
|
||||||
|
outputText.value = ""; //清楚展示部分内容
|
||||||
|
status.value = "ttsing";
|
||||||
|
return getWebsocketUrl().then((url) => {
|
||||||
|
ttsWS = new WebSocket(url);
|
||||||
|
ttsWS.onopen = () => {
|
||||||
|
webSocketSend(ttsWS, data);
|
||||||
|
};
|
||||||
|
ttsWS.onmessage = (e) => {
|
||||||
|
result1(e.data);
|
||||||
|
};
|
||||||
|
ttsWS.onerror = (e) => {
|
||||||
|
status.value = "error";
|
||||||
|
console.log("WebSocket error:", e);
|
||||||
|
};
|
||||||
|
ttsWS.onclose = () => {
|
||||||
|
status.value = "init";
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWebsocketUrl() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
var apiKey = apikey;
|
||||||
|
var apiSecret = secret;
|
||||||
|
var url = "wss://spark-api.xf-yun.com/v4.0/chat";
|
||||||
|
|
||||||
|
var host = "spark-api.xf-yun.com";
|
||||||
|
var date = new Date().toGMTString();
|
||||||
|
var algorithm = "hmac-sha256";
|
||||||
|
var headers = "host date request-line";
|
||||||
|
var signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v4.0/chat HTTP/1.1`;
|
||||||
|
var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret);
|
||||||
|
var signature = CryptoJS.enc.Base64.stringify(signatureSha);
|
||||||
|
|
||||||
|
var authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`;
|
||||||
|
var authorization = CryptoJS.enc.Base64.stringify(
|
||||||
|
CryptoJS.enc.Utf8.parse(authorizationOrigin)
|
||||||
|
);
|
||||||
|
|
||||||
|
url = `${url}?authorization=${authorization}&date=${date}&host=${host}`;
|
||||||
|
console.log(url);
|
||||||
|
resolve(url);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function webSocketSend(ws, data) {
|
||||||
|
const params = {
|
||||||
|
header: {
|
||||||
|
app_id: appId,
|
||||||
|
},
|
||||||
|
parameter: {
|
||||||
|
chat: {
|
||||||
|
domain: "4.0Ultra",
|
||||||
|
temperature: 0.5,
|
||||||
|
max_tokens: 1024,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
payload: {
|
||||||
|
message: {
|
||||||
|
text: data,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
ws.send(JSON.stringify(params));
|
||||||
|
}
|
||||||
|
|
||||||
|
function result1(resultData) {
|
||||||
|
let jsonData = JSON.parse(resultData);
|
||||||
|
outputText.value += jsonData.payload.choices.text[0].content;
|
||||||
|
const div = document.querySelector('.paragraphs');
|
||||||
|
if (div) {
|
||||||
|
div.scrollTop = div.scrollHeight;
|
||||||
|
}
|
||||||
|
if (jsonData.payload && jsonData.payload.usage) {
|
||||||
|
startExtraction() // 返回完毕后开始拆分大纲
|
||||||
|
console.log(firstArray.value, secondArray.value)
|
||||||
|
activeStep.value = 2
|
||||||
|
updateStagingData("assistant", outputText.value) //返回数据存入记忆池
|
||||||
|
}
|
||||||
|
if (jsonData.header.code !== 0) {
|
||||||
|
alert(`提问失败: ${jsonData.header.code}:${jsonData.header.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const selectedFile = ref(null);
|
||||||
|
|
||||||
|
const maxSize = 1024 * 1024 * 20;
|
||||||
|
const allowedTypes = [
|
||||||
|
"application/pdf",
|
||||||
|
"application/msword",
|
||||||
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||||
|
"text/markdown",
|
||||||
|
"text/plain",
|
||||||
|
];
|
||||||
|
const fileType = "wiki";
|
||||||
|
const parseType = "AUTO";
|
||||||
|
const upfileId = ref('');
|
||||||
|
const docName = ref('')
|
||||||
|
|
||||||
|
const docTheme = ref('') // 文档生成ppt的主题
|
||||||
|
const docRequire = ref('') // 文档生成要求
|
||||||
|
|
||||||
|
const onFileChange = (file) => {
|
||||||
|
console.log(file);
|
||||||
|
if (!allowedTypes.includes(file.raw.type)) {
|
||||||
|
console.error("不支持的文件类型");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (file.size > maxSize) {
|
||||||
|
console.error("文件过大");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
docName.value = file.raw.name
|
||||||
|
selectedFile.value = file.raw;
|
||||||
|
uploadFile();
|
||||||
|
};
|
||||||
|
const beforeUpload = (file) => {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
const uploadFile = async () => {
|
||||||
|
if (!selectedFile.value) {
|
||||||
|
console.error("请先选择文件");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("file", selectedFile.value);
|
||||||
|
formData.append("fileType", fileType);
|
||||||
|
formData.append("parseType", parseType);
|
||||||
|
|
||||||
|
for (const pair of formData.entries()) {
|
||||||
|
console.log(pair[0], pair[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await uploadDoc(formData);
|
||||||
|
const upfileData = new FormData();
|
||||||
|
upfileId.value = response.data.data.fileId;
|
||||||
|
upfileData.append("fileIds", upfileId.value);
|
||||||
|
askdoc(upfileData);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//文档状态查询
|
||||||
|
const askdoc = async (data) => {
|
||||||
|
const response = await queryDocStatus(data);
|
||||||
|
if (response.data.data && response.data.data.length > 0) {
|
||||||
|
let foundVectored = false;
|
||||||
|
for (const item of response.data.data) {
|
||||||
|
if (item.fileStatus === 'vectored') {
|
||||||
|
foundVectored = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (foundVectored) {
|
||||||
|
enableButton.value = true
|
||||||
|
} else {
|
||||||
|
const sleepTime = 2000;
|
||||||
|
let remainingTime = sleepTime;
|
||||||
|
const intervalId = setInterval(() => {
|
||||||
|
remainingTime -= 100;
|
||||||
|
if (remainingTime <= 0) {
|
||||||
|
clearInterval(intervalId);
|
||||||
|
askdoc(data);
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//文档对话
|
||||||
|
function chatDoc() {
|
||||||
|
const docthemeValue = docTheme.value;
|
||||||
|
const docrequireValue = docRequire.value;
|
||||||
|
firstArray.value = []
|
||||||
|
secondArray.value = []
|
||||||
|
extractedParts.value = []
|
||||||
|
stagOutputText.value = ''
|
||||||
|
const combinedString = `请帮我生成一个ppt大纲,主题为:${docthemeValue}。具体内容要求为:${docrequireValue}。注意,用三个等级大纲展示,如1. 1.1 1.1.2 2. 2.1这种类型,且按照这种顺序,不要有完全相同数字等级的大纲,不要有目录`
|
||||||
|
updateStagingData("user", combinedString);
|
||||||
|
activeStep.value = 1
|
||||||
|
uploadAndAskMainContent(stagingData.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function chatByDoc(fileId, data) {
|
||||||
|
const wsUrl = `wss://chatdoc.xfyun.cn/openapi/chat?fileId=${fileId}&appId=${appId}×tamp=${timestamp}&signature=${signature}`;
|
||||||
|
|
||||||
|
const ws = new WebSocket(wsUrl);
|
||||||
|
|
||||||
|
ws.onopen = () => {
|
||||||
|
const messageBody = {
|
||||||
|
fileIds: [fileId],
|
||||||
|
messages: data,
|
||||||
|
chatExtends: {
|
||||||
|
wikiPromptTpl:
|
||||||
|
"请将以下内容作为已知信息:\n<wikicontent>\n请根据以上内容回答用户的问题。\n问题:<wikiquestion>\n回答:",
|
||||||
|
wikiFilterScore: 0.82,
|
||||||
|
temperature: 0.5,
|
||||||
|
sparkWhenWithoutEmbedding: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.send(JSON.stringify(messageBody));
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onmessage = (event) => {
|
||||||
|
const response = JSON.parse(event.data);
|
||||||
|
result2(response)
|
||||||
|
console.log("WebSocket 消息:", response);
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onerror = (error) => {
|
||||||
|
console.error("WebSocket 错误:", error);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function result2(resultData) {
|
||||||
|
const div = document.querySelector('.paragraphs');
|
||||||
|
if (div) {
|
||||||
|
div.scrollTop = div.scrollHeight;
|
||||||
|
}
|
||||||
|
if (resultData.status == 1) {
|
||||||
|
outputText.value += resultData.content
|
||||||
|
}
|
||||||
|
if (resultData.status == 2) {
|
||||||
|
startExtraction() // 返回完毕后开始拆分大纲
|
||||||
|
activeStep.value = 2
|
||||||
|
updateStagingData("assistant", outputText.value) //返回数据存入记忆池
|
||||||
|
}
|
||||||
|
if (resultData.code !== 0) {
|
||||||
|
alert(`提问失败: ${jsonData.header.code}:${jsonData.header.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//文档上传问题查询
|
||||||
|
const uploadAndAskMainContent = async (data) => {
|
||||||
|
try {
|
||||||
|
// const formData = new FormData();
|
||||||
|
// formData.append(
|
||||||
|
// "url",
|
||||||
|
// "https://bjcdn.openstorage.cn/xinghuo/chatdocs/2024-09-13/dad35a4f-e7c1-4efc-b6df-cae763cb984b/39052b09-d154-419f-9832-20884adeb2f41726226211177.pdf"
|
||||||
|
// );
|
||||||
|
// formData.append("fileName", "test.pdf");
|
||||||
|
// formData.append("appId", "2ff2cc26");
|
||||||
|
// formData.append("secret", "YTMyZWFiOGVlYTc5ZGM5NGIwOTU3NWMx");
|
||||||
|
// // formData.append("fileType", "wiki");
|
||||||
|
// // formData.append("parseType", "AUTO");
|
||||||
|
|
||||||
|
// const uploadResp = await uploadDoc(formData);
|
||||||
|
// const fileId = uploadResp.data.data.fileId;
|
||||||
|
const fileId = upfileId.value;
|
||||||
|
chatByDoc(fileId, data);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error("上传或提问过程中发生错误:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const enableButton = ref(false);
|
||||||
|
|
||||||
|
const chooseBackground = (data) => {
|
||||||
|
outlineData.value.theme = data
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeCursor = (cursorStyle) => {
|
||||||
|
document.documentElement.style.cursor = cursorStyle;
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// let url = "https://bjcdn.openstorage.cn/xinghuo-privatedata/%2Ftmp/apiTempFiledf28bf990a4c40ffb7477ed4b65392c27232357022409613439/%E3%80%8A%E9%9D%99%E5%A5%B3%E3%80%8B%E6%B7%B1%E5%BA%A6%E8%A7%A3%E8%AF%BB%E4%B8%8E%E7%A0%94%E7%A9%B6.pptx"
|
||||||
|
// creatAIPPT(props.currentNode.itemtitle + '.pptx',url, props.uploadData).then((res) => {
|
||||||
|
// emit('addSuccess',res)
|
||||||
|
// })
|
||||||
|
connectWebSocket("");
|
||||||
|
getBackground();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.ai-container {
|
||||||
|
width: 100%;
|
||||||
|
background-color: #f5f7f6;
|
||||||
|
padding: 20px
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-box {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card1 {
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.paragraphs {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
text-align: left;
|
||||||
|
max-height: 60vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
border: 1px solid #409EFF;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 5px
|
||||||
|
}
|
||||||
|
|
||||||
|
.themes {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
height: 250px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
border: 1px solid #409EFF;
|
||||||
|
padding: 10px;
|
||||||
|
outline-style: none;
|
||||||
|
/* margin: 5px */
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline-row {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline-row>.el-col {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline-row>.el-col>div,
|
||||||
|
.outline-row>.el-col>div>.el-input {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-with-dash {
|
||||||
|
margin-left: 100px
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-with-dash::after {
|
||||||
|
content: "";
|
||||||
|
border-bottom: 1px dashed #000;
|
||||||
|
flex-grow: 1;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-content-1 {
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #c2dbf3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-content-2 {
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-row {
|
||||||
|
padding: 20px
|
||||||
|
}
|
||||||
|
:deep(.el-card__body){
|
||||||
|
padding: 10px 15px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -24,9 +24,10 @@
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<c-form v-bind="classForm">
|
<c-form v-bind="classForm">
|
||||||
<template #item_classid="{prop, form}">
|
<template #item_classid="{prop, form}">
|
||||||
<el-select v-model="form[prop]" placeholder="请选择班级">
|
<span v-if="dt.ctCourse">{{ dt.ctCourse?.caption }}</span>
|
||||||
|
<el-select v-else v-model="form[prop]" placeholder="请选择班级">
|
||||||
<el-option v-for="item in listData.classList" :value="item.id"
|
<el-option v-for="item in listData.classList" :value="item.id"
|
||||||
:label="`${item.caption} (${item.classstudentcount}人)`" />
|
:label="`${item.caption} (${item.classstudentcount}人)`" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</template>
|
</template>
|
||||||
</c-form>
|
</c-form>
|
||||||
|
@ -118,7 +119,9 @@ const dt = reactive({ // 其他数据
|
||||||
isHistory: false, // 是否显示-历史记录
|
isHistory: false, // 是否显示-历史记录
|
||||||
loading: false, // 加载-loading
|
loading: false, // 加载-loading
|
||||||
loadingDel: false, // 删除-loading
|
loadingDel: false, // 删除-loading
|
||||||
|
atClass: {}, // 当前班级
|
||||||
atCourse: {}, // 当前课程
|
atCourse: {}, // 当前课程
|
||||||
|
ctCourse: null, // 继续课程
|
||||||
})
|
})
|
||||||
let chat = null // im-chat 对象
|
let chat = null // im-chat 对象
|
||||||
|
|
||||||
|
@ -128,9 +131,10 @@ onMounted(() => {
|
||||||
})
|
})
|
||||||
/**
|
/**
|
||||||
* @description 暴露方法-打开对话框
|
* @description 暴露方法-打开对话框
|
||||||
* @param row 课件对象
|
* @param id 课件id
|
||||||
|
* @param classObj 课程对象-用于继续上课
|
||||||
*/
|
*/
|
||||||
const open = async (id) => {
|
const open = async (id, classObj) => {
|
||||||
visible.value = true
|
visible.value = true
|
||||||
if (id) {
|
if (id) {
|
||||||
// 重置数据
|
// 重置数据
|
||||||
|
@ -139,6 +143,11 @@ const open = async (id) => {
|
||||||
await getAptInfo(id)
|
await getAptInfo(id)
|
||||||
// 获取班级列表
|
// 获取班级列表
|
||||||
getClassList()
|
getClassList()
|
||||||
|
// 继续上课
|
||||||
|
if (!!classObj) {
|
||||||
|
dt.ctCourse = classObj
|
||||||
|
teacherForm.form.classcourseid = classObj.id
|
||||||
|
}
|
||||||
// 初始化im-chat
|
// 初始化im-chat
|
||||||
nextTick(async() => {
|
nextTick(async() => {
|
||||||
chat = await imChatRef.value?.initImChat()
|
chat = await imChatRef.value?.initImChat()
|
||||||
|
@ -148,8 +157,9 @@ const open = async (id) => {
|
||||||
// 关闭弹窗
|
// 关闭弹窗
|
||||||
const handleClose = async () => {
|
const handleClose = async () => {
|
||||||
reset() // 重置数据
|
reset() // 重置数据
|
||||||
await chat?.logout()
|
// await chat?.logout()
|
||||||
chat = null
|
// chat = null
|
||||||
|
dt.ctCourse = null
|
||||||
emit('close')
|
emit('close')
|
||||||
}
|
}
|
||||||
// 初始化-数据
|
// 初始化-数据
|
||||||
|
@ -177,8 +187,10 @@ const reset = () => {
|
||||||
teacherForm.form = { classcourseid: 0 }
|
teacherForm.form = { classcourseid: 0 }
|
||||||
dt.isCreate = false
|
dt.isCreate = false
|
||||||
dt.isHistory = false
|
dt.isHistory = false
|
||||||
|
dt.atClass = {}
|
||||||
dt.atCourse = {}
|
dt.atCourse = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取课件APT
|
// 获取课件APT
|
||||||
const getAptInfo = async (id) => {
|
const getAptInfo = async (id) => {
|
||||||
const res = await Http_Entpcoursefile.getEntpcoursefile(id)
|
const res = await Http_Entpcoursefile.getEntpcoursefile(id)
|
||||||
|
@ -338,9 +350,9 @@ const chatChange = (type, data, ...args) => {
|
||||||
// 监听-班级id
|
// 监听-班级id
|
||||||
watch(() => classForm.form.classid, (val)=> {
|
watch(() => classForm.form.classid, (val)=> {
|
||||||
// 获取选中课程
|
// 获取选中课程
|
||||||
dt.atCourse = listData.classList.find(o => o.id === val) || {}
|
dt.atClass = listData.classList.find(o => o.id === val) || {}
|
||||||
// 获取选中课程-学生列表
|
// 获取选中课程-学生列表
|
||||||
listData.activeStudentList = dt.atCourse?.classstudentlist || []
|
// listData.activeStudentList = dt.atClass?.classstudentlist || []
|
||||||
// 清空课程列表
|
// 清空课程列表
|
||||||
listData.classcourseList = []
|
listData.classcourseList = []
|
||||||
// 如果当前显示历史, 就从新获取
|
// 如果当前显示历史, 就从新获取
|
||||||
|
|
|
@ -22,7 +22,8 @@
|
||||||
<div class="prepare-item-info-message">
|
<div class="prepare-item-info-message">
|
||||||
<div style="width: 60px">
|
<div style="width: 60px">
|
||||||
<template v-if="item.uniquekey">
|
<template v-if="item.uniquekey">
|
||||||
{{ item.worktype }}
|
<!-- {{ item.worktype }} -->
|
||||||
|
<el-tag :type="item.workclass" size="large">{{ item.worktype }}</el-tag>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<el-icon
|
<el-icon
|
||||||
|
|
|
@ -102,7 +102,7 @@ import { deleteSmarttalk, updateSmarttalk, getPrepareById } from '@/api/file'
|
||||||
import useUserStore from '@/store/modules/user'
|
import useUserStore from '@/store/modules/user'
|
||||||
import outLink from '@/utils/linkConfig'
|
import outLink from '@/utils/linkConfig'
|
||||||
import { sessionStore } from '@/utils/store'
|
import { sessionStore } from '@/utils/store'
|
||||||
import { listClasscourseNew } from '@/api/teaching/classcourse'
|
import { listClasscourseNew, updateClasscourse } from '@/api/teaching/classcourse'
|
||||||
import { endClass, getSelfReserv } from '@/api/classManage'
|
import { endClass, getSelfReserv } from '@/api/classManage'
|
||||||
import { listEntpcourse } from '@/api/teaching/classwork'
|
import { listEntpcourse } from '@/api/teaching/classwork'
|
||||||
import { createWindow } from '@/utils/tool'
|
import { createWindow } from '@/utils/tool'
|
||||||
|
@ -137,7 +137,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
expose: ['openFileWin'],
|
expose: ['openFileWin'],
|
||||||
emits: { 'on-start-class': null, 'on-delete': null, 'on-set': null, 'on-delhomework': null,'on-filearg': null },
|
emits: { 'on-start-class': null, 'on-delete': null, 'on-set': null, 'on-delhomework': null,'on-filearg': null, 'change': null },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
listenList: [],
|
listenList: [],
|
||||||
|
@ -166,8 +166,24 @@ export default {
|
||||||
return one
|
return one
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
// 获取当前上课的课程列表
|
||||||
|
/*getOpenCourse(isApt) {
|
||||||
|
const curNodeId = this.curNode.id
|
||||||
|
if (isApt) { // APT课程
|
||||||
|
const params = {teacherid: this.userInfo.userId,status:"open",evalid: curNodeId,pageSize:1000}
|
||||||
|
return listClasscourseNew(params).then(res => {
|
||||||
|
return (res.rows || [])
|
||||||
|
})
|
||||||
|
} else { // 普通课程PPT
|
||||||
|
return getSelfReserv({ex2: curNodeId}).then(res => {
|
||||||
|
return (res.data || []).filter(o => o.status === "上课中")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},*/
|
||||||
clickStartClass(item) {
|
clickStartClass(item) {
|
||||||
this.getOpenCourse().then(res=>{
|
const isApt = item.fileFlag === 'apt'
|
||||||
|
this.getOpenCourse(isApt).then(res => {
|
||||||
|
console.log(res)
|
||||||
if(!res){
|
if(!res){
|
||||||
this.$emit('on-start-class', item)
|
this.$emit('on-start-class', item)
|
||||||
}else{
|
}else{
|
||||||
|
@ -185,47 +201,56 @@ export default {
|
||||||
confirmButtonClass: "el-button--danger",
|
confirmButtonClass: "el-button--danger",
|
||||||
center: true,
|
center: true,
|
||||||
beforeClose: (action, instance, done) => {
|
beforeClose: (action, instance, done) => {
|
||||||
|
const obj = res
|
||||||
if (action === 'confirm'){
|
if (action === 'confirm'){
|
||||||
// 下课
|
// 下课
|
||||||
if (res.bookImg) {
|
this.$emit('change', 'close', obj, { type: 1, instance, done })
|
||||||
//PPT
|
|
||||||
endClass(res.id).then((res1) => {
|
|
||||||
if (res1.data === true) {
|
|
||||||
ElMessage({
|
|
||||||
message: '下课成功',
|
|
||||||
type: 'success'
|
|
||||||
})
|
|
||||||
res.status = '已结束'
|
|
||||||
done()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}else {
|
|
||||||
//APT
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (action === 'cancel'){
|
if (action === 'cancel'){
|
||||||
// 继续上课
|
// 继续上课
|
||||||
if (res.bookImg) {
|
if (obj.bookImg) {
|
||||||
//PPT
|
//PPT
|
||||||
listEntpcourse({
|
listEntpcourse({
|
||||||
evalid: res.ex2,
|
evalid: obj.ex2,
|
||||||
edituserid: useUserStore().user.userId,
|
edituserid: useUserStore().user.userId,
|
||||||
pageSize: 500
|
pageSize: 500
|
||||||
}).then(async res1=>{
|
}).then(async res1=>{
|
||||||
if (res1.rows[0].id) {
|
if (res1.rows[0].id) {
|
||||||
createWindow('tool-sphere', { url: '/tool/sphere?entpcourseid=' + res1.rows[0].id + "&reservId=" + res.id })
|
createWindow('tool-sphere', { url: '/tool/sphere?entpcourseid=' + res1.rows[0].id + "&reservId=" + obj.id })
|
||||||
|
if (obj.ex4) {
|
||||||
|
getPrepareById(obj.ex4).then(res2=>{
|
||||||
|
console.log(res2)
|
||||||
|
this.openFileWin(res2);
|
||||||
|
})
|
||||||
|
}else {
|
||||||
|
ElMessageBox.confirm(
|
||||||
|
'抱歉,版本V2.1.9前创建的课程,无法直接打开PPT,请自行打开PPT!',
|
||||||
|
'Warning',
|
||||||
|
{
|
||||||
|
confirmButtonText: 'OK',
|
||||||
|
type: 'warning',
|
||||||
|
center: true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
})
|
||||||
|
}
|
||||||
done()
|
done()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}else {
|
}else {
|
||||||
//APT
|
//APT
|
||||||
|
this.$emit('on-start-class', item, obj)
|
||||||
|
done()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (action === 'close') {
|
if (action === 'close') {
|
||||||
done()
|
done()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
}).catch(() => {})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// this.$emit('on-start-class', item)
|
// this.$emit('on-start-class', item)
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-dialog class="ppt-dialog" v-model="model" :show-close="false" width="900" destroy-on-close :top="'3vh'">
|
||||||
|
<template #header="{ close, titleId, titleClass }">
|
||||||
|
<div class="dialog-header">
|
||||||
|
<h4 :id="titleId" :class="titleClass">生成PPT(试验版)</h4>
|
||||||
|
<i class="iconfont icon-guanbi" @click="close"></i>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<AiPpt @add-success="addAiPPT" :currentNode="currentNode" :uploadData="uploadData"/>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import AiPpt from './ai-ppt.vue';
|
||||||
|
const model = defineModel()
|
||||||
|
const emit = defineEmits(['addSuccess'])
|
||||||
|
const props = defineProps({
|
||||||
|
currentNode: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {}
|
||||||
|
},
|
||||||
|
uploadData: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const addAiPPT = (data) => {
|
||||||
|
emit('addSuccess', data)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:deep(.ppt-dialog){
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
|
}
|
||||||
|
.dialog-header{
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
.icon-guanbi {
|
||||||
|
font-size: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -101,6 +101,12 @@ const props = defineProps({
|
||||||
default: () => {
|
default: () => {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
curFile: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const ruleFormDialog = ref(null)
|
const ruleFormDialog = ref(null)
|
||||||
|
@ -292,7 +298,8 @@ const addClassReserv = (formData) => {
|
||||||
classRoom: formData.classRoom,
|
classRoom: formData.classRoom,
|
||||||
classSubject: props.currentNode.edusubject,
|
classSubject: props.currentNode.edusubject,
|
||||||
ex1: props.bookId,
|
ex1: props.bookId,
|
||||||
ex2: props.currentNode.id
|
ex2: props.currentNode.id,
|
||||||
|
ex4: props.curFile.id
|
||||||
}
|
}
|
||||||
addSmartClassReserv(param).then((res) => {
|
addSmartClassReserv(param).then((res) => {
|
||||||
if (res.msg) {
|
if (res.msg) {
|
||||||
|
|
|
@ -13,6 +13,10 @@
|
||||||
<div class="create-btn-title"><el-icon><Plus /></el-icon><label>创建PPT</label></div>
|
<div class="create-btn-title"><el-icon><Plus /></el-icon><label>创建PPT</label></div>
|
||||||
<div class="create-btn-info">传统课件</div>
|
<div class="create-btn-info">传统课件</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="center-create-btn" style="background-color: #909399" @click="pptDialog = true">
|
||||||
|
<div class="create-btn-title"><el-icon><Plus /></el-icon><label>生成PPT</label></div>
|
||||||
|
<div class="create-btn-info">试验版</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="prepare-center-body">
|
<div class="prepare-center-body">
|
||||||
<kj-list-item
|
<kj-list-item
|
||||||
|
@ -24,12 +28,14 @@
|
||||||
:curNode="currentNode"
|
:curNode="currentNode"
|
||||||
@on-delete="deleteTalk"
|
@on-delete="deleteTalk"
|
||||||
@on-start-class="startClass"
|
@on-start-class="startClass"
|
||||||
|
@change="changeClass"
|
||||||
>
|
>
|
||||||
</kj-list-item>
|
</kj-list-item>
|
||||||
</div>
|
</div>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="教学实录" name="教学实录" class="prepare-center-jxsl">
|
<el-tab-pane label="教学实录" name="教学实录" class="prepare-center-jxsl">
|
||||||
<class-reserv v-if="activeAptTab==='教学实录'" :curNode="currentNode"></class-reserv>
|
<class-reserv v-if="activeAptTab==='教学实录'" :curNode="currentNode"
|
||||||
|
@change="changeClass"></class-reserv>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
|
@ -89,7 +95,8 @@
|
||||||
<div class="prepare-body-header">
|
<div class="prepare-body-header">
|
||||||
<div>
|
<div>
|
||||||
<label style="font-size: 15px">共{{ currentWorkList.length }}个作业</label>
|
<label style="font-size: 15px">共{{ currentWorkList.length }}个作业</label>
|
||||||
<el-button size="small" @click="handleOutLink('homeWork')">作业设计</el-button>
|
<!-- <el-button size="small" @click="handleOutLink('homeWork')">作业设计</el-button> -->
|
||||||
|
<el-button size="small" @click="goNewClassTask()">作业设计</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="prepare-work-wrap">
|
<div class="prepare-work-wrap">
|
||||||
|
@ -99,7 +106,7 @@
|
||||||
:item="item"
|
:item="item"
|
||||||
:index="index"
|
:index="index"
|
||||||
@on-set="openSet"
|
@on-set="openSet"
|
||||||
@on-reSet="openReSet"
|
@on-reSet="openReSet"
|
||||||
@on-delhomework="delhomework"
|
@on-delhomework="delhomework"
|
||||||
>
|
>
|
||||||
</file-list-item>
|
</file-list-item>
|
||||||
|
@ -120,22 +127,26 @@
|
||||||
</div>
|
</div>
|
||||||
<MoveFile v-model="isMoveDialogOpen" @on-submit="chooseMoveCata" />
|
<MoveFile v-model="isMoveDialogOpen" @on-submit="chooseMoveCata" />
|
||||||
<uploadDialog v-model="isDialogOpen" @submit-file="submitFile" />
|
<uploadDialog v-model="isDialogOpen" @submit-file="submitFile" />
|
||||||
<SetHomework v-model="setDialog" :entpcourseid="entpcourseid" :row="row" />
|
<SetHomework v-model="setDialog" :entpcourseid="entpcourseid" :rows="rows" />
|
||||||
</div>
|
</div>
|
||||||
<reserv
|
<reserv
|
||||||
ref="reservDialog"
|
ref="reservDialog"
|
||||||
:current-node="currentNode"
|
:current-node="currentNode"
|
||||||
:book-id="uploadData.textbookId"
|
:book-id="uploadData.textbookId"
|
||||||
|
:cur-file="activeClass"
|
||||||
@add-success="initReserv"
|
@add-success="initReserv"
|
||||||
@close="closeChange"
|
@close="closeChange"
|
||||||
></reserv>
|
></reserv>
|
||||||
<!-- 上课配置 -->
|
<!-- 上课配置 -->
|
||||||
<class-start ref="calssRef" @close="closeChange"/>
|
<class-start ref="calssRef" @close="closeChange"/>
|
||||||
|
<PptDialog @add-success="addAiPPT" :currentNode="currentNode" :uploadData="uploadData" v-model="pptDialog"/>
|
||||||
|
<!-- <button @click="test">test</button> -->
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { Check,Plus } from '@element-plus/icons-vue'
|
import { Check,Plus } from '@element-plus/icons-vue'
|
||||||
import Reserv from '@/views/prepare/container/reserv.vue'
|
import Reserv from '@/views/prepare/container/reserv.vue'
|
||||||
import { ArrowDown } from '@element-plus/icons-vue'
|
import { ArrowDown } from '@element-plus/icons-vue'
|
||||||
|
import PptDialog from '@/views/prepare/container/ppt-dialog.vue'
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
const Remote = require('@electron/remote')
|
const Remote = require('@electron/remote')
|
||||||
|
@ -155,16 +166,21 @@ import { parseCataByNode, creatPPT, asyncLocalFile } from '@/utils/talkFile'
|
||||||
import FileOperBatch from '@/views/prepare/container/file-oper-batch.vue'
|
import FileOperBatch from '@/views/prepare/container/file-oper-batch.vue'
|
||||||
import SetHomework from '@/components/set-homework/index.vue'
|
import SetHomework from '@/components/set-homework/index.vue'
|
||||||
import outLink from '@/utils/linkConfig'
|
import outLink from '@/utils/linkConfig'
|
||||||
import { createWindow, sessionStore, getAppInstallUrl } from '@/utils/tool'
|
import { createWindow, sessionStore, getAppInstallUrl, ipcMsgSend } from '@/utils/tool'
|
||||||
import { cloneDeep } from 'lodash'
|
import { cloneDeep } from 'lodash'
|
||||||
import { delClasswork, listEntpcourse } from '@/api/teaching/classwork'
|
import { delClasswork, listEntpcourse } from '@/api/teaching/classwork'
|
||||||
import { getClassInfo, getSelfReserv } from '@/api/classManage'
|
import { updateClasscourse } from '@/api/teaching/classcourse'
|
||||||
|
import { getClassInfo, getSelfReserv, endClass } from '@/api/classManage'
|
||||||
import { useGetHomework } from '@/hooks/useGetHomework'
|
import { useGetHomework } from '@/hooks/useGetHomework'
|
||||||
|
import { editListItem } from '@/hooks/useClassTask'
|
||||||
import { addEntpcoursefileReturnId } from '@/api/education/entpcoursefile'
|
import { addEntpcoursefileReturnId } from '@/api/education/entpcoursefile'
|
||||||
import ClassReserv from '@/views/classManage/classReserv.vue'
|
import ClassReserv from '@/views/classManage/classReserv.vue'
|
||||||
import classStart from './container/class-start.vue' // 预备上课
|
import classStart from './container/class-start.vue' // 预备上课
|
||||||
const toolStore = useToolState()
|
import MsgEnum from '@/plugins/imChat/msgEnum' // im 消息枚举
|
||||||
|
import Chat from '@/utils/chat' // im 登录初始化
|
||||||
|
if (!Chat.imChat) Chat.init()
|
||||||
|
|
||||||
|
const toolStore = useToolState()
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const { ipcRenderer } = window.electron || {}
|
const { ipcRenderer } = window.electron || {}
|
||||||
|
|
||||||
|
@ -215,10 +231,11 @@ export default {
|
||||||
entpcourseid: '',
|
entpcourseid: '',
|
||||||
// 布置作业弹窗
|
// 布置作业弹窗
|
||||||
setDialog: false,
|
setDialog: false,
|
||||||
row: '',
|
rows: '',
|
||||||
isOpenHomework: false,
|
isOpenHomework: false,
|
||||||
// 当前上课课程
|
// 当前上课课程
|
||||||
activeClass: null,
|
activeClass: null,
|
||||||
|
pptDialog: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -272,7 +289,16 @@ export default {
|
||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
methods: {
|
methods: {
|
||||||
startClass(item) {
|
addAiPPT(item) {
|
||||||
|
this.currentFileList.unshift(item.resData)
|
||||||
|
this.pptDialog = false
|
||||||
|
},
|
||||||
|
// test() {
|
||||||
|
// toolStore.resetDef() // 重置状态
|
||||||
|
// ipcMsgSend('tool-sphere:close') // 关闭窗口
|
||||||
|
// },
|
||||||
|
// 开始上课
|
||||||
|
startClass(item, classObj) {
|
||||||
// 关闭状态,打开上课相关功能(已打开,忽略)
|
// 关闭状态,打开上课相关功能(已打开,忽略)
|
||||||
const id = sessionStore.has('activeClass.id') ? sessionStore.get('activeClass.id') : null
|
const id = sessionStore.has('activeClass.id') ? sessionStore.get('activeClass.id') : null
|
||||||
if (id && id == item.id) return ElMessage.warning('当前正在上课,请勿重复操作')
|
if (id && id == item.id) return ElMessage.warning('当前正在上课,请勿重复操作')
|
||||||
|
@ -283,11 +309,68 @@ export default {
|
||||||
this.openReserv()
|
this.openReserv()
|
||||||
}
|
}
|
||||||
if(item.fileFlag === 'apt') {
|
if(item.fileFlag === 'apt') {
|
||||||
this.$refs.calssRef.open(item.fileId)
|
this.$refs.calssRef.open(item.fileId, classObj)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 继续上课-apt
|
||||||
|
async changeClass(type, row, other) {
|
||||||
|
switch(type) {
|
||||||
|
case 'continue': { // 继续上课
|
||||||
|
const aptFileId = row.entpcoursefileid
|
||||||
|
this.$refs.calssRef.open(aptFileId, row)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'close': { // 关闭上课
|
||||||
|
const head = MsgEnum.HEADS.MSG_closed // closed
|
||||||
|
const msgT = MsgEnum.TYPES.TEACHER // teacher
|
||||||
|
const isApt = !row.bookImg // bookImg ppt 否则Apt
|
||||||
|
row.ex3 == 'undefined' && (row.ex3 = null)
|
||||||
|
const timgroupid = isApt ? row.timgroupid : row.ex3 // ex3 ppt 否则Apt
|
||||||
|
if (other.type == 1) { // 弹窗-下课
|
||||||
|
other.instance.confirmButtonLoading = true
|
||||||
|
other.instance.confirmButtonText = '下课中...'
|
||||||
|
} else { // 列表-下课
|
||||||
|
other.loading.value = true
|
||||||
|
}
|
||||||
|
// 发送-下课消息
|
||||||
|
if (!!timgroupid) {
|
||||||
|
const msg = { msgKey: head, actor: msgT, classcourseid: row.id }
|
||||||
|
Chat.sendMsg(timgroupid, msg)
|
||||||
|
}
|
||||||
|
if (isApt) { // Apt
|
||||||
|
// 接口-修改状态
|
||||||
|
await updateClasscourse({ id: row.id, status: head, timgroupid: '' })
|
||||||
|
} else { // PPT
|
||||||
|
const toolStore = useToolState()
|
||||||
|
// 窗口已打开,直接关闭
|
||||||
|
if (toolStore.isToolWin) {
|
||||||
|
toolStore.resetDef() // 重置状态
|
||||||
|
ipcMsgSend('tool-sphere:close') // 关闭窗口
|
||||||
|
}
|
||||||
|
// 接口-修改状态
|
||||||
|
await endClass(row.id)
|
||||||
|
}
|
||||||
|
// 解散群
|
||||||
|
setTimeout(async() => {
|
||||||
|
if (!!timgroupid) await Chat.dismissGroup(timgroupid)
|
||||||
|
if (other.type == 1) { // 弹窗-下课
|
||||||
|
other.instance.confirmButtonLoading = false
|
||||||
|
other.instance.confirmButtonText = '下课'
|
||||||
|
other.done()
|
||||||
|
} else {
|
||||||
|
other.loading.value = false
|
||||||
|
row.status = isApt ? head : '已结束'
|
||||||
|
}
|
||||||
|
ElMessage({ type: 'success', message: `下课成功!` })
|
||||||
|
}, 1000)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
closeChange() { // 上课弹窗被关闭-触发
|
closeChange() { // 上课弹窗被关闭-触发
|
||||||
console.log('关闭上课弹窗')
|
// console.log('关闭上课弹窗')
|
||||||
// this.activeClass = null
|
// this.activeClass = null
|
||||||
sessionStore.delete('activeClass')
|
sessionStore.delete('activeClass')
|
||||||
},
|
},
|
||||||
|
@ -574,34 +657,44 @@ export default {
|
||||||
this.$refs['reservDialog'].openDialog()
|
this.$refs['reservDialog'].openDialog()
|
||||||
},
|
},
|
||||||
|
|
||||||
// 打开外部链接
|
// 打开外部链接
|
||||||
handleOutLink(key) {
|
// handleOutLink(key) {
|
||||||
if (key == 'homeWork') {
|
// if (key == 'homeWork') {
|
||||||
this.isOpenHomework = true
|
// this.isOpenHomework = true
|
||||||
}
|
// }
|
||||||
// key 对应的 linkConfig.js 外部链接配置
|
// // key 对应的 linkConfig.js 外部链接配置
|
||||||
let configObj = outLink()[key]
|
// let configObj = outLink()[key]
|
||||||
let fullPath = configObj.fullPath
|
// let fullPath = configObj.fullPath
|
||||||
//打开作业 高考 url增加unitId 章节ID
|
// //打开作业 高考 url增加unitId 章节ID
|
||||||
if (key != 'standard' && key != 'aiModel') {
|
// if (key != 'standard' && key != 'aiModel') {
|
||||||
let unitId = this.uploadData.levelSecondId
|
// let unitId = this.uploadData.levelSecondId
|
||||||
? this.uploadData.levelSecondId
|
// ? this.uploadData.levelSecondId
|
||||||
: this.uploadData.levelFirstId
|
// : this.uploadData.levelFirstId
|
||||||
let bookId = this.uploadData.textbookId;
|
// let bookId = this.uploadData.textbookId;
|
||||||
if(fullPath.indexOf('?') == -1){
|
// if(fullPath.indexOf('?') == -1){
|
||||||
fullPath += `?unitId=${unitId}&bookId=${bookId}&openDialog=newClassTask`
|
// fullPath += `?unitId=${unitId}&bookId=${bookId}&openDialog=newClassTask`
|
||||||
}
|
// }
|
||||||
else{
|
// else{
|
||||||
fullPath += `&unitId=${unitId}&bookId=${bookId}&openDialog=newClassTask`
|
// fullPath += `&unitId=${unitId}&bookId=${bookId}&openDialog=newClassTask`
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 通知主进程
|
// // 通知主进程
|
||||||
ipcRenderer.send('openWindow', {
|
// ipcRenderer.send('openWindow', {
|
||||||
key,
|
// key,
|
||||||
fullPath: fullPath,
|
// fullPath: fullPath,
|
||||||
cookieData: { ...configObj.data }
|
// cookieData: { ...configObj.data }
|
||||||
})
|
// })
|
||||||
|
// },
|
||||||
|
// 前往作业设计页面
|
||||||
|
goNewClassTask(){
|
||||||
|
// router.push({ path: '/newClassTask' });
|
||||||
|
this.$router.push({
|
||||||
|
path: '/newClassTask',
|
||||||
|
query: {
|
||||||
|
isBack: true,
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
getWeekday1(date) {
|
getWeekday1(date) {
|
||||||
const weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
|
const weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
|
||||||
|
@ -610,29 +703,51 @@ export default {
|
||||||
},
|
},
|
||||||
// 打开布置作业窗口
|
// 打开布置作业窗口
|
||||||
openSet(row) {
|
openSet(row) {
|
||||||
this.row = row
|
// 布置推送:row 这里是单个,转为list
|
||||||
|
this.rows = [row]
|
||||||
this.setDialog = true
|
this.setDialog = true
|
||||||
},
|
},
|
||||||
// 打开作业编辑窗口
|
// 打开作业编辑窗口
|
||||||
openReSet(row) {
|
openReSet(row) {
|
||||||
// 新窗口打开标识
|
//跳转 作业设计 编辑页面
|
||||||
this.isOpenHomework = true;
|
const courseObj = {
|
||||||
// key 对应的 linkConfig.js 外部链接配置
|
textbookId: this.uploadData.textbookId,
|
||||||
let configObj = outLink()['homeWork']
|
levelFirstId: this.uploadData.levelFirstId,
|
||||||
let fullPath = configObj.fullPath
|
levelSecondId: this.uploadData.levelSecondId,
|
||||||
|
coursetitle: this.currentNode.itemtitle, // (单元/章节) 名称,
|
||||||
|
node: this.currentNode, // 选择的课程节点
|
||||||
|
}
|
||||||
|
console.log('courseObj', courseObj)
|
||||||
|
editListItem(row, courseObj).then((obj) => {
|
||||||
|
if(obj){
|
||||||
|
//前往作业设计
|
||||||
|
this.$router.push({
|
||||||
|
path: '/newClassTask',
|
||||||
|
query: {
|
||||||
|
classtaskObj: JSON.stringify(obj),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//---------------------
|
||||||
|
// 暂时弃用 外链 新窗口打开标识
|
||||||
|
// this.isOpenHomework = true;
|
||||||
|
// // key 对应的 linkConfig.js 外部链接配置
|
||||||
|
// let configObj = outLink()['homeWork']
|
||||||
|
// let fullPath = configObj.fullPath
|
||||||
|
|
||||||
let unitId = this.uploadData.levelSecondId
|
// let unitId = this.uploadData.levelSecondId
|
||||||
? this.uploadData.levelSecondId
|
// ? this.uploadData.levelSecondId
|
||||||
: this.uploadData.levelFirstId
|
// : this.uploadData.levelFirstId
|
||||||
let bookId = this.uploadData.textbookId;
|
// let bookId = this.uploadData.textbookId;
|
||||||
fullPath += `&unitId=${unitId}&bookId=${bookId}&courseWorkId=${row.id}`
|
// fullPath += `&unitId=${unitId}&bookId=${bookId}&courseWorkId=${row.id}`
|
||||||
|
|
||||||
// 通知主进程
|
// // 通知主进程
|
||||||
ipcRenderer.send('openWindow', {
|
// ipcRenderer.send('openWindow', {
|
||||||
key: 'homeWork',
|
// key: 'homeWork',
|
||||||
fullPath: fullPath,
|
// fullPath: fullPath,
|
||||||
cookieData: { ...configObj.data }
|
// cookieData: { ...configObj.data }
|
||||||
})
|
// })
|
||||||
},
|
},
|
||||||
// 删除作业
|
// 删除作业
|
||||||
delhomework(item) {
|
delhomework(item) {
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<el-image class="imges" :src="bookInfo ? bookInfo.avartar : ''" />
|
<el-image class="imges" :src="bookInfo ? bookInfo.avartar : ''" />
|
||||||
</div>
|
</div>
|
||||||
<div class="stand-head-right">
|
<div class="stand-head-right">
|
||||||
<div class="stand-head-right-tit">{{bookInfo ? bookInfo.bookName : ''}}</div>
|
<div class="stand-head-right-tit">{{bookInfo ? bookInfo.itemtitle : ''}}</div>
|
||||||
<i class="iconfont icon-yidongdaozu stand-head-right-icon" @click="dialogVisible = true"></i>
|
<i class="iconfont icon-yidongdaozu stand-head-right-icon" @click="dialogVisible = true"></i>
|
||||||
<div class="stand-head-right-row">
|
<div class="stand-head-right-row">
|
||||||
<div class="stand-head-right-row-time">更新2024.9.10</div>
|
<div class="stand-head-right-row-time">更新2024.9.10</div>
|
||||||
|
@ -72,7 +72,7 @@
|
||||||
<div class="booklist">
|
<div class="booklist">
|
||||||
<div :class="{'item': true,'active': booksel === idx}" v-for="item,idx in bookList" :key="idx" @click="bookChange(item,idx)">
|
<div :class="{'item': true,'active': booksel === idx}" v-for="item,idx in bookList" :key="idx" @click="bookChange(item,idx)">
|
||||||
<el-image class="bookimg" :src="item.avartar" />
|
<el-image class="bookimg" :src="item.avartar" />
|
||||||
<div class="bookname">{{item.bookName}}</div>
|
<div class="bookname">{{item.itemtitle}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
@ -173,7 +173,7 @@ const selectHandel = (value) => {
|
||||||
}
|
}
|
||||||
//保存json文件
|
//保存json文件
|
||||||
const saveJSON = (data) => {
|
const saveJSON = (data) => {
|
||||||
|
|
||||||
let filename = ''
|
let filename = ''
|
||||||
// const data = {
|
// const data = {
|
||||||
// name: 'txt',
|
// name: 'txt',
|
||||||
|
@ -247,11 +247,12 @@ const getAllSubject = async () => {
|
||||||
rows && rows.map(item => {
|
rows && rows.map(item => {
|
||||||
if(edustage === item.edustage && item.edusubject === edusubject){
|
if(edustage === item.edustage && item.edusubject === edusubject){
|
||||||
bookInfo.value = {...item,avartar: import.meta.env.VITE_APP_BUILD_BASE_PATH + item.avartar,bookName: bookNameFormat(item.edustage,item.edusubject)}
|
bookInfo.value = {...item,avartar: import.meta.env.VITE_APP_BUILD_BASE_PATH + item.avartar,bookName: bookNameFormat(item.edustage,item.edusubject)}
|
||||||
}
|
if(item.fileurl !== ''){
|
||||||
if(item.fileurl !== ''){
|
bookList.value.push(bookInfo.value)
|
||||||
bookList.value.push({...item,avartar: import.meta.env.VITE_APP_BUILD_BASE_PATH + item.avartar,bookName: bookNameFormat(item.edustage,item.edusubject)})
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
console.log(bookList)
|
||||||
const textselidx = bookList.value.findIndex(item => item.edustage === edustage && item.edusubject === edusubject)
|
const textselidx = bookList.value.findIndex(item => item.edustage === edustage && item.edusubject === edusubject)
|
||||||
booksel.value = textselidx
|
booksel.value = textselidx
|
||||||
const filePath = import.meta.env.VITE_APP_RES_FILE_PATH + bookList.value[textselidx].fileurl.replace('.txt','.pdf')
|
const filePath = import.meta.env.VITE_APP_RES_FILE_PATH + bookList.value[textselidx].fileurl.replace('.txt','.pdf')
|
||||||
|
@ -282,7 +283,7 @@ onMounted(async () => {
|
||||||
const searchh = searchref.value.offsetHeight;
|
const searchh = searchref.value.offsetHeight;
|
||||||
listHeight.value = Math.floor(cardH) - Math.floor(headh) - Math.floor(searchh) - 60;
|
listHeight.value = Math.floor(cardH) - Math.floor(headh) - Math.floor(searchh) - 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('resize', () => {
|
window.addEventListener('resize', () => {
|
||||||
if(cardref.value && headref.value){
|
if(cardref.value && headref.value){
|
||||||
const cardH = cardref.value.offsetHeight;
|
const cardH = cardref.value.offsetHeight;
|
||||||
|
@ -333,9 +334,9 @@ onMounted(async () => {
|
||||||
console.log('转换后整体文字------',StartStr + midStr + EndStr);
|
console.log('转换后整体文字------',StartStr + midStr + EndStr);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// const isDev = process.env.NODE_ENV == 'development'
|
// const isDev = process.env.NODE_ENV == 'development'
|
||||||
// if (isDev)
|
// if (isDev)
|
||||||
// pdfUrl.value = '/'+getStaticUrl('aaa.pdf', 'user', 'selfFile', true)
|
// pdfUrl.value = '/'+getStaticUrl('aaa.pdf', 'user', 'selfFile', true)
|
||||||
// else
|
// else
|
||||||
// pdfUrl.value = getStaticUrl(route.query.path, 'user', 'selfFile', true)
|
// pdfUrl.value = getStaticUrl(route.query.path, 'user', 'selfFile', true)
|
||||||
|
@ -552,4 +553,4 @@ onMounted(async () => {
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<el-image class="imges" :src="bookInfo ? bookInfo.avartar : ''" />
|
<el-image class="imges" :src="bookInfo ? bookInfo.avartar : ''" />
|
||||||
</div>
|
</div>
|
||||||
<div class="stand-head-right">
|
<div class="stand-head-right">
|
||||||
<div class="stand-head-right-tit">{{bookInfo ? bookInfo.bookName: ''}}</div>
|
<div class="stand-head-right-tit">{{bookInfo ? bookInfo.itemtitle: ''}}</div>
|
||||||
<i class="iconfont icon-yidongdaozu stand-head-right-icon" @click="dialogVisible = true"></i>
|
<i class="iconfont icon-yidongdaozu stand-head-right-icon" @click="dialogVisible = true"></i>
|
||||||
<div class="stand-head-right-row">
|
<div class="stand-head-right-row">
|
||||||
<div class="stand-head-right-row-time">更新2024.9.10</div>
|
<div class="stand-head-right-row-time">更新2024.9.10</div>
|
||||||
|
@ -72,7 +72,7 @@
|
||||||
<div class="booklist">
|
<div class="booklist">
|
||||||
<div :class="{'item': true,'active': booksel === idx}" v-for="item,idx in bookList" :key="idx" @click="bookChange(item,idx)">
|
<div :class="{'item': true,'active': booksel === idx}" v-for="item,idx in bookList" :key="idx" @click="bookChange(item,idx)">
|
||||||
<el-image class="bookimg" :src="item.avartar" />
|
<el-image class="bookimg" :src="item.avartar" />
|
||||||
<div class="bookname">{{item.bookName}}</div>
|
<div class="bookname">{{item.itemtitle}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
@ -175,7 +175,7 @@ const selectHandel = (value) => {
|
||||||
}
|
}
|
||||||
//保存json文件
|
//保存json文件
|
||||||
const saveJSON = (data) => {
|
const saveJSON = (data) => {
|
||||||
|
|
||||||
let filename = ''
|
let filename = ''
|
||||||
// const data = {
|
// const data = {
|
||||||
// name: 'txt',
|
// name: 'txt',
|
||||||
|
@ -249,7 +249,11 @@ const getAllSubject = async () => {
|
||||||
const dataList = [];
|
const dataList = [];
|
||||||
rows && rows.map((item,idx) => {
|
rows && rows.map((item,idx) => {
|
||||||
if(item.fileurl !== ''){
|
if(item.fileurl !== ''){
|
||||||
dataList.push({...item,avartar: import.meta.env.VITE_APP_BUILD_BASE_PATH + item.avartar,bookName: item.fileurl.replace('.txt','')})
|
let infos = {...item,avartar: import.meta.env.VITE_APP_BUILD_BASE_PATH + item.avartar,bookName: item.fileurl.replace('.txt','')}
|
||||||
|
if(infos.itemgroup==="校本课程") {
|
||||||
|
infos.avartar = item.avartar
|
||||||
|
}
|
||||||
|
dataList.push(infos)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
bookList.value = dataList
|
bookList.value = dataList
|
||||||
|
@ -265,7 +269,7 @@ const getAllSubject = async () => {
|
||||||
bookInfo.value = {...dataList[0]}
|
bookInfo.value = {...dataList[0]}
|
||||||
filePath += dataList[0].fileurl.replace('.txt','.pdf')
|
filePath += dataList[0].fileurl.replace('.txt','.pdf')
|
||||||
}
|
}
|
||||||
await loadPdfAnimation(filePath)
|
await loadPdfAnimation(filePath)
|
||||||
}else{
|
}else{
|
||||||
bookInfo.value = {...dataList[0]}
|
bookInfo.value = {...dataList[0]}
|
||||||
filePath += dataList[0].fileurl.replace('.txt','.pdf')
|
filePath += dataList[0].fileurl.replace('.txt','.pdf')
|
||||||
|
@ -295,7 +299,7 @@ onMounted(async () => {
|
||||||
const searchh = searchref.value.offsetHeight;
|
const searchh = searchref.value.offsetHeight;
|
||||||
listHeight.value = Math.floor(cardH) - Math.floor(headh) - Math.floor(searchh) - 60;
|
listHeight.value = Math.floor(cardH) - Math.floor(headh) - Math.floor(searchh) - 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('resize', () => {
|
window.addEventListener('resize', () => {
|
||||||
if(cardref.value && headref.value){
|
if(cardref.value && headref.value){
|
||||||
const cardH = cardref.value.offsetHeight;
|
const cardH = cardref.value.offsetHeight;
|
||||||
|
@ -346,9 +350,9 @@ onMounted(async () => {
|
||||||
console.log('转换后整体文字------',StartStr + midStr + EndStr);
|
console.log('转换后整体文字------',StartStr + midStr + EndStr);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// const isDev = process.env.NODE_ENV == 'development'
|
// const isDev = process.env.NODE_ENV == 'development'
|
||||||
// if (isDev)
|
// if (isDev)
|
||||||
// pdfUrl.value = '/'+getStaticUrl('aaa.pdf', 'user', 'selfFile', true)
|
// pdfUrl.value = '/'+getStaticUrl('aaa.pdf', 'user', 'selfFile', true)
|
||||||
// else
|
// else
|
||||||
// pdfUrl.value = getStaticUrl(route.query.path, 'user', 'selfFile', true)
|
// pdfUrl.value = getStaticUrl(route.query.path, 'user', 'selfFile', true)
|
||||||
|
@ -570,4 +574,4 @@ onMounted(async () => {
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-button color="#349d44" @click="sendHomework(item)">推送</el-button>
|
<el-button color="#349d44" @click="sendHomework(item,'item')">推送</el-button>
|
||||||
</li>
|
</li>
|
||||||
<div class="no-data flex" v-if="!dataList.length && !resourceList.length">
|
<div class="no-data flex" v-if="!dataList.length && !resourceList.length">
|
||||||
<i class="iconfont icon-zanwushuju"></i>
|
<i class="iconfont icon-zanwushuju"></i>
|
||||||
|
@ -56,7 +56,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
</div>
|
</div>
|
||||||
<SetHomework v-model="setDialog" :title="'推送作业'" :entpcourseid="entpcourseid" :row="curRow"
|
<SetHomework v-model="setDialog" :title="'推送作业'" :entpcourseid="entpcourseid" :rows="curRow"
|
||||||
@on-close="closeHomework" @on-success="successHomework"/>
|
@on-close="closeHomework" @on-success="successHomework"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="homework flex" v-else>
|
<div class="homework flex" v-else>
|
||||||
|
@ -110,8 +110,11 @@ const curNode = reactive({
|
||||||
data: {}
|
data: {}
|
||||||
})
|
})
|
||||||
|
|
||||||
const sendHomework = (row) => {
|
const sendHomework = (row,type) => {
|
||||||
curRow.value = row
|
if(type == 'item'){
|
||||||
|
// 布置推送单个作业
|
||||||
|
curRow.value = [row]
|
||||||
|
}
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
ipcMsgSend('tool-sphere:set:ignore', false)
|
ipcMsgSend('tool-sphere:set:ignore', false)
|
||||||
}, 200)
|
}, 200)
|
||||||
|
@ -125,7 +128,7 @@ const closeHomework = async() => {
|
||||||
const successHomework = (data)=>{
|
const successHomework = (data)=>{
|
||||||
// console.log('推送成功', data)
|
// console.log('推送成功', data)
|
||||||
// 发送im消息-推送作业(app|平板)
|
// 发送im消息-推送作业(app|平板)
|
||||||
ipcMsgInvoke('im-chat:msg', data, MsgEnum.HEADS.MSG_0016)
|
// ipcMsgInvoke('im-chat:msg', data, MsgEnum.HEADS.MSG_0016)
|
||||||
}
|
}
|
||||||
// 章节目录change
|
// 章节目录change
|
||||||
const changeChapter = async (data)=>{
|
const changeChapter = async (data)=>{
|
||||||
|
|
|
@ -12,7 +12,7 @@ const props = defineProps({
|
||||||
})
|
})
|
||||||
const imChatObj = reactive({imChat:null})
|
const imChatObj = reactive({imChat:null})
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
ipcMainHandle() // 绑定-监听ipcMain im相关消息
|
// ipcMainHandle() // 绑定-监听ipcMain im相关消息
|
||||||
})
|
})
|
||||||
// 初始化 im-chat
|
// 初始化 im-chat
|
||||||
const initImChat = async (timGroupId) => {
|
const initImChat = async (timGroupId) => {
|
||||||
|
|
|
@ -98,13 +98,14 @@ onMounted(async() => {
|
||||||
const getClassInfo = async () => {
|
const getClassInfo = async () => {
|
||||||
const { data } = await classManageApi.getClassInfo(classObj.id)
|
const { data } = await classManageApi.getClassInfo(classObj.id)
|
||||||
classObj.data = data
|
classObj.data = data
|
||||||
|
sessionStore.set('curClassRoom', classObj) // 课堂信息-缓存
|
||||||
// 群id
|
// 群id
|
||||||
let timGroupId = data?.ex3 || ''
|
let timGroupId = data?.ex3 || ''
|
||||||
console.log('获取群ID:', timGroupId)
|
console.log('获取群ID:', timGroupId)
|
||||||
const chat = await imChatRef.value?.initImChat(timGroupId) // 初始化im-chat
|
const chat = await imChatRef.value?.initImChat(timGroupId) // 初始化im-chat
|
||||||
if (!timGroupId) timGroupId = chat?.timGroupId
|
if (!timGroupId) timGroupId = chat?.timGroupId
|
||||||
if (!timGroupId) return ElMessage.error('房间创建-失败')
|
if (!timGroupId) return ElMessage.error('房间创建-失败')
|
||||||
classManageApi.startClass(classObj.id, timGroupId) // 开始上课
|
if (data.status != '上课中') classManageApi.startClass(classObj.id, timGroupId) // 开始上课
|
||||||
}
|
}
|
||||||
// 切换tab-change
|
// 切换tab-change
|
||||||
const tabChange = (val) => {
|
const tabChange = (val) => {
|
||||||
|
@ -157,7 +158,7 @@ const touchChange = (e) => {
|
||||||
const chatChange = (type, data, ...args) => {
|
const chatChange = (type, data, ...args) => {
|
||||||
if (type == 'createGroup') { // 创建群-监听
|
if (type == 'createGroup') { // 创建群-监听
|
||||||
console.log('创建群:', data)
|
console.log('创建群:', data)
|
||||||
!!data && classManageApi.startClass(classObj.id, data)
|
// !!data && classManageApi.startClass(classObj.id, data)
|
||||||
} else if (type == 'msg') { // im-chat 消息监听
|
} else if (type == 'msg') { // im-chat 消息监听
|
||||||
if (!data) return // 没有msg数据 message_msg_id
|
if (!data) return // 没有msg数据 message_msg_id
|
||||||
const msgId = (args||[])[0].message_msg_id
|
const msgId = (args||[])[0].message_msg_id
|
||||||
|
@ -239,7 +240,7 @@ const sideChange = async o => {
|
||||||
// 延迟2秒后关闭窗口,如果马上解散群,会导致群组不存在
|
// 延迟2秒后关闭窗口,如果马上解散群,会导致群组不存在
|
||||||
setTimeout(async() => {
|
setTimeout(async() => {
|
||||||
await imChatRef.value?.deleteGroup() // 解散群
|
await imChatRef.value?.deleteGroup() // 解散群
|
||||||
await imChatRef.value?.logout() // 退出im
|
// await imChatRef.value?.logout() // 退出im
|
||||||
elMsg.close()
|
elMsg.close()
|
||||||
ipcMsgSend('tool-sphere:close') // 关闭窗口
|
ipcMsgSend('tool-sphere:close') // 关闭窗口
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
Loading…
Reference in New Issue