qinqing_dev #312

Merged
qinqing merged 2 commits from qinqing_dev into main 2024-10-11 16:39:11 +08:00
61 changed files with 3062 additions and 1295 deletions
Showing only changes of commit 7cab923fa4 - Show all commits

View File

@ -1,6 +1,6 @@
{
"name": "aix-win",
"version": "2.1.1",
"version": "2.1.5",
"description": "",
"main": "./out/main/index.js",
"author": "example.com",
@ -66,7 +66,7 @@
"xlsx": "^0.18.5",
"less": "^4.2.0",
"less-loader": "^7.3.0",
"whiteboard_lyc": "^0.0.8"
"whiteboard_lyc": "^0.1.3"
},
"devDependencies": {
"@electron-toolkit/eslint-config": "^1.0.2",

View File

@ -74,7 +74,7 @@ function createLoginWindow() {
updateInit(loginWindow)
}
// loginWindow.webContents.openDevTools()
loginWindow.webContents.openDevTools()
loginWindow.once('ready-to-show', () => {
loginWindow.show()
})
@ -128,14 +128,14 @@ function createMainWindow() {
shell.openExternal(details.url)
return { action: 'deny' }
})
// mainWindow.webContents.openDevTools()
mainWindow.webContents.openDevTools()
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
} else {
mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
}
// mainWindow.setAlwaysOnTop(true, "screen-saver") // 将窗口设置为顶层窗口
// mainWindow.setVisibleOnAllWorkspaces(true) // 如果窗口在所有工作区都可见
// 第三步: 开启remote服务
@ -280,14 +280,10 @@ function handleAll() {
})
// 用于监听-状态管理变化-同步所有窗口
ipcMain.handle('pinia-state-change', (e, storeName, jsonStr) => {
console.log('pinia-state-change-1', storeName, jsonStr)
for(const curWin of BrowserWindow.getAllWindows()){
const id = curWin.webContents.id
const bool = id !== e.sender.id && !curWin.isDestroyed()
if (id === e.sender.id) {
console.log('pinia-state-change-2', 'windows-send', curWin.type)
}
if (bool) { // 除了消息发送窗口和销毁的窗口 其他都发送
curWin.webContents.send('pinia-state-set', storeName, jsonStr)
}

View File

@ -13,6 +13,7 @@ const defaultData = {
showBoardAll: false, // 全屏画板-是否显示
isPdfWin: false, // pdf窗口是否打开
isToolWin: false, // 工具窗口是否打开
isTaskWin: false, // 批改窗口是否打开
curSubjectNode: {
querySearch: {} // 查询资源所需参数
},

View File

@ -26,3 +26,13 @@ export class imChat {
// 获取腾讯im-chat appid 签名
static getTxCloudSign = data => ApiService.publicHttp('/system/user/txCloudSign', data)
}
// zdg: url跳转-后端存储
export class toLink {
// 设置链接-返回key(默认15分钟有效时间)
static setLink = url => ApiService.publicHttp(`/smarttalk/toLink`, {url}, 'post', null, 'form')
// 获取链接
static getLink = key => ApiService.publicHttp(`/smarttalk/toLink/${key}`)
// 删除链接-缓存
static delLink = key => ApiService.publicHttp(`/smarttalk/toLink/${key}`, null, 'delete')
}

View File

@ -147,10 +147,11 @@ export function updateSmartClassReserv(data) {
})
}
//查询课程预约
export function getSelfReserv() {
export function getSelfReserv(params) {
return request({
url: '/smarttalk/classReserv/getSelfReserv',
method: 'get'
method: 'get',
params
})
}
export function deleteSmartReserv(id) {

View File

@ -27,6 +27,15 @@ export function listClassworkdata(query) {
})
}
// 新接口---查询classworkdata列表 班级作业列表
export function listClassworkdataNew(query) {
return request({
url: '/education/classworkdata/new/list',
method: 'get',
params: query
})
}
// 查询entpcoursework列表 课程作业列表
export function listEntpcoursework(query) {
return request({
@ -72,7 +81,21 @@ export function updateClasswork(data) {
})
}
// 删除classworkeval
export function delClassworkeval(id) {
return request({
url: '/education/classworkeval/' + id,
method: 'delete'
})
}
// 新增classworkeval
export function addClassworkeval(data) {
return request({
url: '/education/classworkeval',
method: 'post',
data: data
})
}
// 查询evaluationclue列表
export function listEvaluationclue(query) {

View File

@ -9,6 +9,14 @@ export function listClasscourse(query) {
})
}
export function listClasscourseNew(query) {
return request({
url: '/education/classcourse/new/list',
method: 'get',
params: query
})
}
// 查询classcourse详细
export function getClasscourse(id) {
return request({

View File

@ -1,9 +1,9 @@
@font-face {
font-family: "iconfont"; /* Project id 2794390 */
src: url('iconfont.woff2?t=1725847033097') format('woff2'),
url('iconfont.woff?t=1725847033097') format('woff'),
url('iconfont.ttf?t=1725847033097') format('truetype'),
url('iconfont.svg?t=1725847033097#iconfont') format('svg');
src: url('iconfont.woff2?t=1728543886557') format('woff2'),
url('iconfont.woff?t=1728543886557') format('woff'),
url('iconfont.ttf?t=1728543886557') format('truetype'),
url('iconfont.svg?t=1728543886557#iconfont') format('svg');
}
.iconfont {
@ -14,38 +14,110 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-A1:before {
content: "\e635";
}
.icon-A:before {
content: "\e6ef";
}
.icon--kejian:before {
content: "\e6a3";
}
.icon-a-1_jiaoxuefansi:before {
content: "\e6cd";
}
.icon-iconfontzhizuobiaozhunbduan3-1:before {
content: "\100af";
}
.icon-gongzuotai_xuanzhong:before {
content: "\e605";
}
.icon-yijianfankui:before {
content: "\e8a1";
}
.icon-zuoyesheji:before {
content: "\e619";
}
.icon-jihua:before {
content: "\e601";
}
.icon-xueqingfenxi:before {
content: "\e68a";
}
.icon-zuoyebuzhi:before {
content: "\e607";
}
.icon-zuoyepigai:before {
content: "\ec35";
}
.icon-jiaocai1:before {
content: "\e781";
}
.icon-yanjiushi:before {
content: "\e70a";
}
.icon-zuzhi:before {
content: "\e63b";
}
.icon-zhiliang:before {
content: "\e642";
}
.icon-jiaoxueshijian:before {
content: "\e676";
}
.icon-kebiao:before {
content: "\e67a";
}
.icon-yanjiuyuan:before {
content: "\e6bf";
}
.icon-kaoshi:before {
content: "\eb14";
}
.icon-iconfontzhizuobiaozhunbduan36:before {
content: "\e6eb";
}
.icon-ziyuanku:before {
content: "\eb01";
}
.icon-yanjiushi-2:before {
content: "\100b0";
}
.icon-fasong:before {
content: "\e692";
}
.icon-aijiqiren:before {
content: "\e73c";
}
.icon-saoyisao:before {
content: "\e691";
}
.icon-jiaoxuezhiliangfenxi:before {
content: "\e690";
}
.icon-jiaoxuejihua:before {
content: "\e7e9";
}
.icon-tongji:before {
content: "\e68f";
}
.icon-pigai:before {
content: "\e68d";
}
.icon-jiaoxuefansi:before {
content: "\e6b2";
}
.icon-kaoshi:before {
content: "\e68a";
}
.icon-yiwen:before {
content: "\e687";
}
@ -174,10 +246,6 @@
content: "\e642";
}
.icon-organization-framework-line:before {
content: "\e9fe";
}
.icon-jiaocai:before {
content: "\e67b";
}
@ -246,10 +314,6 @@
content: "\eb13";
}
.icon-fankui:before {
content: "\e738";
}
.icon-tiku:before {
content: "\e621";
}
@ -270,10 +334,6 @@
content: "\e61c";
}
.icon-jiaoxuefenxi:before {
content: "\e605";
}
.icon-wenjianjia:before {
content: "\ec17";
}
@ -298,14 +358,6 @@
content: "\e675";
}
.icon-yanjiushi:before {
content: "\e607";
}
.icon-gongzuotai:before {
content: "\e676";
}
.icon-lunwen:before {
content: "\e60e";
}
@ -322,10 +374,6 @@
content: "\e6fe";
}
.icon-pengyouquan1:before {
content: "\e635";
}
.icon-beike1:before {
content: "\e61b";
}
@ -346,10 +394,6 @@
content: "\e612";
}
.icon-fankui1:before {
content: "\e6fa";
}
.icon-shezhi:before {
content: "\e614";
}
@ -394,10 +438,6 @@
content: "\e654";
}
.icon-kecheng:before {
content: "\e619";
}
.icon-bianji1:before {
content: "\e61d";
}
@ -426,10 +466,6 @@
content: "\e79a";
}
.icon-xueqingfenxi:before {
content: "\e67a";
}
.icon-check:before {
content: "\e622";
}
@ -546,10 +582,6 @@
content: "\e636";
}
.icon-ziyuanfenxi:before {
content: "\e637";
}
.icon-shoucang1:before {
content: "\e638";
}
@ -566,10 +598,6 @@
content: "\e772";
}
.icon-xiezuo1:before {
content: "\e63b";
}
.icon-fenxi1:before {
content: "\e63c";
}
@ -798,10 +826,6 @@
content: "\e672";
}
.icon-jiaoxueziyuan:before {
content: "\e601";
}
.icon-beike:before {
content: "\e6c2";
}

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,174 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "11657531",
"name": "A",
"font_class": "A1",
"unicode": "e635",
"unicode_decimal": 58933
},
{
"icon_id": "12688893",
"name": "A",
"font_class": "A",
"unicode": "e6ef",
"unicode_decimal": 59119
},
{
"icon_id": "6571029",
"name": "课件",
"font_class": "-kejian",
"unicode": "e6a3",
"unicode_decimal": 59043
},
{
"icon_id": "37027693",
"name": "教学反思",
"font_class": "a-1_jiaoxuefansi",
"unicode": "e6cd",
"unicode_decimal": 59085
},
{
"icon_id": "41983432",
"name": "朋友圈-copy",
"font_class": "iconfontzhizuobiaozhunbduan3-1",
"unicode": "100af",
"unicode_decimal": 65711
},
{
"icon_id": "9478557",
"name": "工作台_选中",
"font_class": "gongzuotai_xuanzhong",
"unicode": "e605",
"unicode_decimal": 58885
},
{
"icon_id": "2076317",
"name": " 意见反馈",
"font_class": "yijianfankui",
"unicode": "e8a1",
"unicode_decimal": 59553
},
{
"icon_id": "2468169",
"name": "作业指导书",
"font_class": "zuoyesheji",
"unicode": "e619",
"unicode_decimal": 58905
},
{
"icon_id": "3865266",
"name": "计划",
"font_class": "jihua",
"unicode": "e601",
"unicode_decimal": 58881
},
{
"icon_id": "4308245",
"name": "学情概览",
"font_class": "xueqingfenxi",
"unicode": "e68a",
"unicode_decimal": 59018
},
{
"icon_id": "5113507",
"name": "教学中心_作业批改",
"font_class": "zuoyebuzhi",
"unicode": "e607",
"unicode_decimal": 58887
},
{
"icon_id": "5767879",
"name": "执行反馈",
"font_class": "zuoyepigai",
"unicode": "ec35",
"unicode_decimal": 60469
},
{
"icon_id": "10992961",
"name": "课程标准",
"font_class": "jiaocai1",
"unicode": "e781",
"unicode_decimal": 59265
},
{
"icon_id": "11744086",
"name": "策略研究 选中",
"font_class": "yanjiushi",
"unicode": "e70a",
"unicode_decimal": 59146
},
{
"icon_id": "12732492",
"name": "组织",
"font_class": "zuzhi",
"unicode": "e63b",
"unicode_decimal": 58939
},
{
"icon_id": "18909227",
"name": "质量管理",
"font_class": "zhiliang",
"unicode": "e642",
"unicode_decimal": 58946
},
{
"icon_id": "21156217",
"name": "培训",
"font_class": "jiaoxueshijian",
"unicode": "e676",
"unicode_decimal": 58998
},
{
"icon_id": "33378945",
"name": "课程标准",
"font_class": "kebiao",
"unicode": "e67a",
"unicode_decimal": 59002
},
{
"icon_id": "33722029",
"name": "研究院",
"font_class": "yanjiuyuan",
"unicode": "e6bf",
"unicode_decimal": 59071
},
{
"icon_id": "35203493",
"name": "考试 (3)",
"font_class": "kaoshi",
"unicode": "eb14",
"unicode_decimal": 60180
},
{
"icon_id": "1236933",
"name": "朋友圈",
"font_class": "iconfontzhizuobiaozhunbduan36",
"unicode": "e6eb",
"unicode_decimal": 59115
},
{
"icon_id": "40912837",
"name": "智慧图书馆",
"font_class": "ziyuanku",
"unicode": "eb01",
"unicode_decimal": 60161
},
{
"icon_id": "41983489",
"name": "策略研究 选中-copy",
"font_class": "yanjiushi-2",
"unicode": "100b0",
"unicode_decimal": 65712
},
{
"icon_id": "34833984",
"name": "发送",
"font_class": "fasong",
"unicode": "e692",
"unicode_decimal": 59026
},
{
"icon_id": "34666608",
"name": "ai机器人",
@ -12,27 +180,6 @@
"unicode": "e73c",
"unicode_decimal": 59196
},
{
"icon_id": "12657402",
"name": "资源库",
"font_class": "saoyisao",
"unicode": "e691",
"unicode_decimal": 59025
},
{
"icon_id": "6513175",
"name": "教学质量分析",
"font_class": "jiaoxuezhiliangfenxi",
"unicode": "e690",
"unicode_decimal": 59024
},
{
"icon_id": "38447338",
"name": "教学计划",
"font_class": "jiaoxuejihua",
"unicode": "e7e9",
"unicode_decimal": 59369
},
{
"icon_id": "8455509",
"name": "统计",
@ -40,27 +187,6 @@
"unicode": "e68f",
"unicode_decimal": 59023
},
{
"icon_id": "5969226",
"name": "批改",
"font_class": "pigai",
"unicode": "e68d",
"unicode_decimal": 59021
},
{
"icon_id": "36295514",
"name": "教学反思",
"font_class": "jiaoxuefansi",
"unicode": "e6b2",
"unicode_decimal": 59058
},
{
"icon_id": "21088705",
"name": "考试",
"font_class": "kaoshi",
"unicode": "e68a",
"unicode_decimal": 59018
},
{
"icon_id": "20574719",
"name": "疑问",
@ -285,13 +411,6 @@
"unicode": "e642",
"unicode_decimal": 58946
},
{
"icon_id": "6235034",
"name": "组织框架",
"font_class": "organization-framework-line",
"unicode": "e9fe",
"unicode_decimal": 59902
},
{
"icon_id": "10900222",
"name": "教材",
@ -411,13 +530,6 @@
"unicode": "eb13",
"unicode_decimal": 60179
},
{
"icon_id": "577336",
"name": "反馈",
"font_class": "fankui",
"unicode": "e738",
"unicode_decimal": 59192
},
{
"icon_id": "1447760",
"name": "题库",
@ -453,13 +565,6 @@
"unicode": "e61c",
"unicode_decimal": 58908
},
{
"icon_id": "4686996",
"name": "教学分析",
"font_class": "jiaoxuefenxi",
"unicode": "e605",
"unicode_decimal": 58885
},
{
"icon_id": "4893191",
"name": "文件夹",
@ -502,20 +607,6 @@
"unicode": "e675",
"unicode_decimal": 58997
},
{
"icon_id": "7327280",
"name": "研究室",
"font_class": "yanjiushi",
"unicode": "e607",
"unicode_decimal": 58887
},
{
"icon_id": "7905547",
"name": "工作台",
"font_class": "gongzuotai",
"unicode": "e676",
"unicode_decimal": 58998
},
{
"icon_id": "9023128",
"name": "论文",
@ -544,13 +635,6 @@
"unicode": "e6fe",
"unicode_decimal": 59134
},
{
"icon_id": "16364339",
"name": "朋友圈",
"font_class": "pengyouquan1",
"unicode": "e635",
"unicode_decimal": 58933
},
{
"icon_id": "37075078",
"name": "备课",
@ -586,13 +670,6 @@
"unicode": "e612",
"unicode_decimal": 58898
},
{
"icon_id": "2680657",
"name": "反馈",
"font_class": "fankui1",
"unicode": "e6fa",
"unicode_decimal": 59130
},
{
"icon_id": "4520331",
"name": "设置",
@ -670,13 +747,6 @@
"unicode": "e654",
"unicode_decimal": 58964
},
{
"icon_id": "6560965",
"name": "课程",
"font_class": "kecheng",
"unicode": "e619",
"unicode_decimal": 58905
},
{
"icon_id": "6682548",
"name": "编辑",
@ -726,13 +796,6 @@
"unicode": "e79a",
"unicode_decimal": 59290
},
{
"icon_id": "8225912",
"name": "学情分析",
"font_class": "xueqingfenxi",
"unicode": "e67a",
"unicode_decimal": 59002
},
{
"icon_id": "9922803",
"name": "check",
@ -936,13 +999,6 @@
"unicode": "e636",
"unicode_decimal": 58934
},
{
"icon_id": "39506557",
"name": "资源分析",
"font_class": "ziyuanfenxi",
"unicode": "e637",
"unicode_decimal": 58935
},
{
"icon_id": "3267408",
"name": "收藏",
@ -971,13 +1027,6 @@
"unicode": "e772",
"unicode_decimal": 59250
},
{
"icon_id": "6837777",
"name": "写作",
"font_class": "xiezuo1",
"unicode": "e63b",
"unicode_decimal": 58939
},
{
"icon_id": "7171145",
"name": "粮食动态决策分析系统",
@ -1377,13 +1426,6 @@
"unicode": "e672",
"unicode_decimal": 58994
},
{
"icon_id": "15841963",
"name": "教学资源",
"font_class": "jiaoxueziyuan",
"unicode": "e601",
"unicode_decimal": 58881
},
{
"icon_id": "5562910",
"name": "备课",

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 362 KiB

After

Width:  |  Height:  |  Size: 362 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 51 KiB

View File

@ -122,7 +122,8 @@ const outerAi = [
title: '教学大模型',
secondTit: '中小学基础教学大模型',
img: new URL('../../../src/assets/images/ai-02.png', import.meta.url).href,
disabled: true,
path: '/ais/aimoss'
},
{
id: 3,

View File

@ -49,7 +49,7 @@ import { useGetSubject } from '@/hooks/useGetSubject'
const BaseUrl = import.meta.env.VITE_APP_BUILD_BASE_PATH
// emit
const emit = defineEmits(['nodeClick'])
const emit = defineEmits(['nodeClick', 'changeBook'])
let useSubject = null
const subjectList = ref([])
const dialogVisible = ref(false)
@ -164,7 +164,6 @@ const handleNodeClick = (data) => {
sessionStore.set('subject.defaultExpandedKeys', defaultExpandedKeys)
sessionStore.set('subject.curNode', nodeData)
emit('nodeClick', curData)
}
onMounted( async () => {
treeLoading.value = true

View File

@ -145,7 +145,6 @@ export default {
}
},
created() {
window.test = this
this.slotKeys = Object.keys(this.$slots)
},
methods: {

View File

@ -34,7 +34,7 @@ const getFileTypeIcon = () => {
gif: 'icon-gif',
txt: 'icon-txt',
rar: 'icon-rar',
apt: 'icon-lunwen'
apt: 'icon-A'
}
if (iconObj[name]) {
return '#' + iconObj[name]

View File

@ -285,7 +285,7 @@ onMounted(async () => {
canvas2.canvas.setWidth(window.innerWidth / 2 - 100)
// canvas2.canvas.isDrawingMode=false
canvas1FabricVue.value = canvas2
window.test = { canvas1, canvas2 }
// window.test = { canvas1, canvas2 }
emit('update:numPagesTotal', pdf.numPages)
if (props.pdfObj.allPageData.length) {

View File

@ -294,7 +294,7 @@ onMounted(async () => {
canvas2.canvas.setWidth(window.innerWidth / 2 - 100)
// canvas2.canvas.isDrawingMode=false
canvas1FabricVue.value = canvas2
window.test = { canvas1, canvas2 }
// window.test = { canvas1, canvas2 }
emit('update:numPagesTotal', pdf.numPages)
if (props.pdfObj.allPageData.length) {

View File

@ -276,6 +276,7 @@ const cloneDialog = (formEl) => {
expandedKeys.value = []
formEl.resetFields()
model.value = false
emit('on-close')
}
onMounted(() => {

View File

@ -60,10 +60,12 @@
<el-button>{{ type == 'design' ? '形状' : '工具' }}</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="square">正方形</el-dropdown-item>
<el-dropdown-item command="rectangle">矩形</el-dropdown-item>
<el-dropdown-item command="diamond">菱形</el-dropdown-item>
<el-dropdown-item command="triangle">三角形</el-dropdown-item>
<el-dropdown-item command="circle">圆形</el-dropdown-item>
<el-dropdown-item command="elliptic">椭圆形</el-dropdown-item>
<el-dropdown-item command="line">线段</el-dropdown-item>
<el-dropdown-item command="arrow">箭头</el-dropdown-item>
<template v-if="type != 'design'">
@ -397,7 +399,7 @@ const scroll = reactive({
//
const showGrid = ref(false)
//
// const readonly = ref(false)
const readonly = ref(false)
//
const elReadonly = ref(false)
@ -675,8 +677,8 @@ const getCanvasBase64 = async () =>{
let base64 = await app.exportImage({
type: 'image/jpeg',
renderBg: exportRenderBackground.value,
paddingX: 0,
paddingY: 0,
paddingX: 10,
paddingY: 10,
onlySelected: exportOnlySelected.value,
backgroundColor: '#ffffff'
})

View File

@ -305,210 +305,11 @@ export const processList = (row) => {
.join('、')
row[i].workanswerFormat = answer
}
// else {
// // 其余类型试题类型(因学科不同, 大多为主观题类型, 结构为数组)
// row[i].workanswerFormat = workAnswerArr.join('、')
// }
}
/*
//2、处理单选题
if(row[i].worktype == '单选题' || row[i].worktype == '多选题' ){
//1.选项前增加ABCD workdesc: "①②#&①③#&②④#&③④" || "<div>为了活着</div>#&<div>为了填报肚子</div>#&<div>为了吃饭而吃饭</div>"
let workDescArr = [];
if(row[i].workdesc.indexOf('[')!==-1 && row[i].workdesc.indexOf(']')!==-1) {
//123会直接被转换, 且不是数组对象, 故手动判断是否有[和]两个字符
workDescArr = JSON.parse(row[i].workdesc);
}
else if(row[i].workdesc.indexOf('#&')) {
workDescArr = row[i].workdesc.split('#&');
}
else if(row[i].workdesc.indexOf(',')){
workDescArr = row[i].workdesc.split(',');
}
else {
// 待考虑
workDescArr.push(item.workdesc)
}
//2.答案 - 数字转为ABCD
if(row[i].worktype == '单选题') {
const str2Char = String.fromCharCode(65+Number(row[i].workanswer));
row[i].workanswerFormat = str2Char;
} else if (row[i].worktype == '多选题') {
const answerArr = row[i].workanswer.split('#&');
let arr2Char = '';
for(let k=0; k<answerArr.length; k++){
arr2Char += String.fromCharCode(65+Number(answerArr[k]));
}
row[i].workanswerFormat = arr2Char;
}
}
else if(row[i].worktype == '填空题') {
// console.log(row[i].workanswer.replace(/<[^>]*>/g, "").split('#&'),'????')
// 填空题答案
row[i].workanswerFormat = row[i].workanswer.replace(/#&/g," ");
// 填空选项不需要展示,
row[i].workdescFormat = '';
}
else if(row[i].worktype == '判断题'){
// console.log(row[i].workanswer.replace(/<[^>]*>/g, "").split('#&'),'????')
// 判断题答案
row[i].workanswerFormat = row[i].workanswer.replace(/#&/g," ");
// 判断选项不需要展示,
row[i].workdescFormat = '';
}
else if(row[i].worktype == '复合题') {
// 1.选项解析替换
const options = JSON.parse(row[i].workdesc);
// 题目(背景材料+复合题目)
const bjTitle = row[i].title.split('!@#$%')[0];
const tmTitles = row[i].title.split('!@#$%').filter((it,ix)=>ix>0);
// console.log(bjTitle,'背景标题');
// console.log(tmTitles,'复合题目');
let titls = [];
options.forEach((element,index1) => {
const workDescArr = element.split('#&');
let tmp = '';
let j=0;
for(; j<jsonArr.length; j++){
if(j%2 == 0){
tmp += `<div style='width:80%;display:flex;'>`;
}
const char = String.fromCharCode(65+j);
tmp += `<div style='display:flex;margin-left: 2%; width: 36%'>${char}.${jsonArr[j]}</div>`;
if(j%2 == 1){
tmp += '</div>';
}
}
if(j%2== 0){
tmp += '</div>';
}
workdesc = tmp;
}
row[i].workdescFormat = workdesc; // 题目选项
// 答案处理
let workanswer = '';
if(row[i].workanswer && row[i].workanswer != '') {
// 因答案内容存在多种格式: 1.["123","1234"] 2.123#&1234 3.123
if(row[i].workanswer.indexOf('[')!==-1 && row[i].workanswer.indexOf(']')!==-1) {
//123会直接被转换, 且不是数组对象, 故手动判断是否有[和]两个字符
let json = JSON.parse(row[i].workanswer);
// 单选、多选 需要 数字转为ABCD
if(row[i].worktype == '单选题') {
const str2Char = String.fromCharCode(65+Number(json[0]));
workanswer = str2Char;
} else if (row[i].worktype == '多选题') {
// const answerArr = row[i].workanswer.split('#&');
let arr2Char = '';
for(let k=0; k<json.length; k++){
arr2Char += String.fromCharCode(65+Number(json[k]));
}
workanswer = arr2Char;
} else if(row[i].worktype == '主观题' ) {
let arr2Char = '';
for(let k=0; k<json.length; k++){
const itemArr = json[k];
arr2Char += '('+ (parseInt(k) + 1) +')'+ itemArr.join('、')+ '<br />';
}
workanswer = arr2Char;
row[i].titleFormat = row[i].titleFormat.replace(/!@#\$%/g, '');
} else {
workanswer = json.join('、');
}
} else if(row[i].workanswer.indexOf('#&')) {
// 意味着多个答案或者填空内容
let workanswerList = row[i].workanswer.split('#&');
if(row[i].worktype == '多选题') {
// 数字转为ABCD
let arr2Char = '';
for(let k=0; k<workanswerList.length; k++){
arr2Char += String.fromCharCode(65+Number(workanswerList[k]));
}
workanswer = arr2Char;
}else{
workanswer = workanswerList.join('、');
}
} else if(row[i].workanswer.indexOf(',')){
// 意味这同样多个答案或者填空内容
let workanswerList = row[i].workanswer.split(',');
if(row[i].worktype == '多选题') {
// 数字转为ABCD
let arr2Char = '';
for(let k=0; k<workanswerList.length; k++){
arr2Char += String.fromCharCode(65+Number(workanswerList[k]));
}
workanswer = arr2Char;
}else{
workanswer = workanswerList.join('、');
}
} else {
// 待考虑
workanswer = row[i].workanswer;
}
}
row[i].workanswerFormat = workanswer; // 题目正确答案
//2.答案 - 数字转为ABCD
const answerArr = JSON.parse(row[i].workanswer);
let indexLabel = 1;
let arr = [];
answerArr.forEach(item => {
const arrTmp = item.answer.split('#&');
let value = `(${indexLabel})`;
arrTmp.forEach((element,i) => {
if(item.type == '单选题' || item.type == '多选题'){
value += `${String.fromCharCode(65+Number(element))}`;
}
if(item.type == '判断题' || item.type == '填空题'){
// 去除下 html标签
value += `${element.replace(/<[^>]+>/g, '')}`+ (i==arrTmp.length-1?'':'、');
}
})
arr.push(value);
indexLabel++;
})
const answer = arr.join('<br />');
row[i].workanswerFormat = answer;
}
else if(row[i].worktype == '主观题') {
// 1.选项解析替换---主观题没选项
// 题目(背景材料+主观题目)
const bjTitle = row[i].title.split('!@#$%')[0];
const tmTitles = row[i].title.split('!@#$%').filter((it,ix)=>ix>0);
// console.log(bjTitle,'背景标题');
// console.log(tmTitles,'主观题目');
let titls = [];
const s = [];
tmTitles.map((it,ix)=>{
s.push(it);
})
// console.log(s,'?????????????????')
row[i].titleFormat = bjTitle + s.join('');
// 填空选项不需要展示,
row[i].workdescFormat = '';
//2.答案
// 填空题答案
const workanswerList = JSON.parse(row[i].workanswer);
let tmp='';
workanswerList&&workanswerList.map((item,index)=>{
tmp += '<div>'+(index+1)+'.'+item.replace(/#&/g, '')+'</div>';
})
row[i].workanswerFormat = tmp;
}
else {
//处理答案
row[i].workanswerFormat = '见试题解答内容';
}
*/
}
}
}

View File

@ -9,7 +9,14 @@
<ul class="flex">
<li class="flex" :class="[activeId == menu.path ? 'active-li' : '', menu.disabled ? 'disabled' : '']"
v-for="menu in headerMenus" :key="menu.id" @click="clickMenu(menu)">
<i class="iconfont" :class="menu.icon"></i>
<div class="icon-box">
<svg class="icon iconfont" aria-hidden="true">
<use :xlink:href="menu.icon"></use>
</svg>
</div>
<span class="text">{{ menu.name }}</span>
</li>
</ul>
@ -73,9 +80,7 @@ import { updateUserInfo } from '@/api/system/user'
import logoIco from '@/assets/images/logo.png'
import { listEvaluation } from '@/api/classManage/index'
import { sessionStore } from '@/utils/store'
import { useToolState } from '@/store/modules/tool'
const toolState = useToolState();
let homeTitle = ref(import.meta.env.VITE_APP_TITLE)
const { ipcRenderer } = window.electron || {}
const userStore = useUserStore()
@ -89,25 +94,25 @@ const headerMenus = [
{
name: '工作台',
id: 1,
icon: 'icon-gongzuotai',
icon: '#icon-gongzuotai_xuanzhong',
path: '/home'
},
{
name: '研究室',
id: 2,
icon: 'icon-yanjiushi',
icon: '#icon-yanjiushi-2',
disabled: true
},
{
name: '资源库',
id: 3,
icon: 'icon-saoyisao',
icon: '#icon-ziyuanku',
path: '/resource'
},
{
name: '朋友圈',
id: 4,
icon: 'icon-pengyouquan1',
icon: '#icon-iconfontzhizuobiaozhunbduan3-1',
disabled: true
}
]
@ -146,7 +151,8 @@ function handleCommand(command) {
function logout() {
const hasClass = sessionStore.has('activeClass.id')
if (hasClass || toolState.isToolWin) return ElMessage.warning('当前正在上课,请先结结束上课')
const hasTool = sessionStore.get('isToolWin')
if (hasClass || hasTool) return ElMessage.warning('当前正在上课,请先结束上课')
ElMessageBox.confirm('确认退出系统吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
@ -245,10 +251,19 @@ onMounted(() => {
li {
cursor: pointer;
flex-direction: column;
border-radius: 8px;
margin: 0 10px;
border-radius: 5px;
padding: 5px 8px;
height: 60px;
align-items: center;
.icon-box{
width: 100%;
height: 35px;
display: flex;
align-items: center;
justify-content: center;
}
.text {
margin-top: 3px;
font-size: 13px;
font-weight: bold;
}
@ -257,24 +272,9 @@ onMounted(() => {
font-size: 26px;
}
.icon-resource {
color: #f99b53;
}
.icon-homepage {
color: #0a84ff;
}
.icon-prepare {
color: #b088e8;
}
.icon-teach {
color: #367dea;
}
&:hover {
color: #409eff;
background-color: #fff
}
}
@ -284,11 +284,13 @@ onMounted(() => {
&:hover {
color: #bfbfbf;
background: none;
}
}
.active-li {
color: #409eff;
background-color: #fff
}
}
}

View File

@ -4,14 +4,7 @@
<Header />
</el-header>
<el-main>
<template v-if="currentRoute.path != '/home'">
<el-page-header @back="goBack">
<template #content>
<span class="text-large mr-3"> {{ currentRoute.meta.title }} </span>
</template>
</el-page-header>
</template>
<AppMain :style="{ height: currentRoute.path == '/home' ? '100%' : 'calc(100% - 45px)'}" />
<AppMain />
</el-main>
<Uploader v-if="uploaderStore.uploadList && uploaderStore.uploadList.length > 0" />
<AiChart/>
@ -19,38 +12,25 @@
</template>
<script setup>
import { watch } from 'vue'
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import Header from './components/Header.vue'
import AppMain from './components/AppMain.vue'
import Uploader from './components/Uploader.vue'
import AiChart from '@/components/ai-chart/index.vue'
import uploaderState from '@/store/modules/uploader'
import { ref } from 'vue'
const router = useRouter()
const currentRoute = ref('')
watch(
() => router.currentRoute.value,
(newValue) => {
currentRoute.value = newValue
},
{ immediate: true }
)
let uploaderStore = ref(uploaderState())
const goBack = () =>{
router.back()
}
</script>
<style lang="scss" scoped>
.el-container {
height: 100%;
background: url(@/assets/images/login/login-bg.png) no-repeat center;
// background: url(@/assets/images/login/login-bg.png) no-repeat center;
// background: #EAEFF8;
background: linear-gradient(to bottom right, #cce6ff 0%, #79d0fc 100%);
// background: linear-gradient(to top, #a6e3e9, #e3fdfd);
background-size: cover;
}

View File

@ -10,6 +10,8 @@ import _ from 'lodash'
// import { diff } from 'jsondiffpatch'
// const Remote = isNode?require('@electron/remote'):{} // 远程模块
const exArrs = ['subject'] // 不需要同步key-排除
export function shareStorePlugin({store}) {
store.$subscribe((mutation, state) => { // 自动同步
// mutation 变量包含了变化前后的状态
@ -54,43 +56,45 @@ function stateSync(storeName, key, value, state) {
// 同步数据-发送给主线程-单独($subscribe-监听使用)
function stateSyncWatch(storeName, newState) {
const oldState = sessionStore.store // 旧数据
exArrs.forEach(k => Object.keys(oldState).includes(k) && (delete oldState[k]))
const diffData = findDifferences(oldState, newState)
if(!_.keys(diffData).length) return // 没有变化就终止执行
// 数据处理: 找出差异
console.log('state-change-diffData', diffData)
// console.log('state-change-diffData', diffData)
try {
let pinaValue = {} // store pina状态管理需要的数据格式
// 数据转换处理
for(const key in diffData) {
const value = diffData[key] || null
const value = diffData[key]
const newValue = {} // 重新组装pinia需要的数据 {a:{b:1}} 这种
const keyArr = key.split('.') || []
keyArr.reduce((o,c,i)=>{o[c] = i === keyArr.length-1 ? value : {};return o[c]}, newValue)
// 合并数据 loadsh _.merge() 函数
_.merge(pinaValue, newValue)
}
const piniaArr = _.toPairs(pinaValue) // 对象转换为数组 {a:1} toPairs [['a',1]]
const setData = (key, value) => {
// 无数据就终止执行
if (!key) return
// 更新本地数据-session
// 直接获取当前最新值(整体更新)上面获取到value是差异值并不能知道删除还是新增
const newValAll = _.get(newState, key)
const oldValAll = sessionStore.get(key)
// 没变化也终止执行
if (_.isEqual(oldValAll, newValAll)) return
// 更新本地数据-session
sessionStore.set(key, newValAll)
// 数据处理: pina-store
const jsonStr = JSON.stringify(pinaValue) // 从新组装-json数据
// 通知主线程更新
ipcRenderer?.invoke('pinia-state-change', storeName, jsonStr)
// console.log('======',key, value, jsonStr )
}
// 数据处理: electron-store
const [key, value] = _.toPairs(pinaValue)[0] // 对象转换为数组 {a:1} toPairs [['a',1]]
// 无数据就终止执行
if (!key || !value) return
// 更新本地数据-session
// 直接获取当前最新值(整体更新)上面获取到value是差异值并不能知道删除还是新增
const newValAll = _.get(newState, key)
const oldValAll = sessionStore.get(key)
// 没变化也终止执行
if (_.isEqual(oldValAll, newValAll)) return
// 更新本地数据-session
sessionStore.set(key, newValAll)
// 数据处理: pina-store
const jsonStr = JSON.stringify(pinaValue) // 从新组装-json数据
// 通知主线程更新
ipcRenderer?.invoke('pinia-state-change', storeName, jsonStr)
// console.log('======',key, value, jsonStr )
for(let [key, value] of piniaArr) {
setData(key, value)
}
} catch (error) {
console.log('state-change-error', error)
}
@ -116,7 +120,7 @@ function stateSyncInit(wid, store) {
function sessionWatch(store) {
const unsubscribe = sessionStore.onDidAnyChange((newV, oldV) => {
if (newV !== oldV) {
console.log('session-change', newV, oldV)
// console.log('session-change', newV, oldV)
// 通知主线程更新
// ipcRenderer?.invoke('pinia-state-change', storeName, jsonStr)
}
@ -129,7 +133,7 @@ function stateChange(store) {
const storeName = store.$id
ipcRenderer?.on('pinia-state-set', (e, sName, jsonStr) => {
if (sName == storeName) { // 更新对应数据
console.log('state-set', jsonStr, sName)
// console.log('state-set', jsonStr, sName)
const curJson = circularSafeStringify(store.$state) // 当前数据
const isUp = curJson != jsonStr // 不同的时候才写入,不然会导致触发数据变化监听,导致死循环
if (!isUp) return

View File

@ -21,6 +21,11 @@ export const constantRoutes = [
name: 'fullscreenpdf',
meta: {title: '全屏显示PDF'}
},
{
path: '/teachClassTask',
component: () => import('@/views/classTask/teachClassTask.vue'),
hidden: true
},
{
path: '/',
component: Layout,

View File

@ -18,6 +18,7 @@ export const useToolState = defineStore('tool', {
showBoardAll: false, // 全屏画板-是否显示
isPdfWin: false, // pdf窗口是否打开
isToolWin: false, // 工具窗口是否打开
isTaskWin: false, // 批改窗口是否打开
curSubjectNode: {
querySearch: {} // 查询资源所需参数
},

View File

@ -310,3 +310,44 @@ export function timeToStr(time,str = '时分秒', isPad = false) {
if (isPad) return `${h?toStr(h)+arr[0]:''}${m?toStr(m)+arr[1]:''}${toStr(s)}${arr[2]||''}`
return `${h?h+arr[0]:''}${m?m+arr[1]:''}${s?s+arr[2]||'':''}`
}
/**
* 防抖一定时间内如果函数被连续调用则只执行最后一次调用
* debounce(() => {
console.log('Input event handled');
}, 300);
* @param {*} func
* @param {*} wait
* @returns
*/
export function debounce(func, wait) {
let timeout;
return function() {
const context = this;
const args = arguments;
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(context, args), wait);
};
}
/**
* 节流一定时间内函数最多只执行一次
* throttle(() => {
console.log('Scroll event handled');
}, 300);
* @param {*} func
* @param {*} wait
* @returns
*/
export function throttle(func, wait) {
let lastTime = 0;
return function() {
const context = this;
const args = arguments;
const now = new Date();
if (now - lastTime >= wait) {
func.apply(context, args);
lastTime = now;
}
};
}

View File

@ -100,6 +100,17 @@ export const getCurrentTime = (format)=> {
if(format == 'MMDD'){
return `${month}${day}`;
}
if(format == 'HH'){
return `${hours}`;
}
if(format == 'HH+3'){
//往后延时3个小时
const hours = (now.getHours()+3).toString().padStart(2, '0');
return `${hours}`
}
if(format == 'mm'){
return `${minutes}`;
}
}
/**
*

View File

@ -112,6 +112,7 @@ export function ipcHandle(fn,key, cb) {
*/
let wins_tool = null
let winPdf=null
let winChild=null
export const createWindow = async (type, data) => {
switch(type) {
case 'tool-sphere': { // 创建-悬浮球
@ -137,7 +138,7 @@ export const createWindow = async (type, data) => {
wins_tool.setIgnoreMouseEvents(true, {forward: true}) // 忽略鼠标事件但是事件继续传递给窗口
wins_tool.setAlwaysOnTop(true,'screen-saver') // 将窗口设置为顶层窗口
wins_tool.setVisibleOnAllWorkspaces(true) // 如果窗口在所有工作区都可见
// wins_tool.webContents.openDevTools() // 打开调试工具
wins_tool.webContents.openDevTools() // 打开调试工具
eventHandles(type, wins_tool) // 事件监听处理
return wins_tool
}
@ -164,11 +165,41 @@ export const createWindow = async (type, data) => {
win.type = type // 唯一标识
win.show()
win.setFullScreen(true) // 设置窗口为全屏
// win.webContents.openDevTools() // 打开调试工具
win.webContents.openDevTools() // 打开调试工具
eventHandles(type, win) // 事件监听处理
winPdf=win
break
}
case 'open-taskwin': { //作业批改-web
if(winChild){ //判断是否已经打开
winChild.focus();
return
}
const option = data.option||{}
const defOption = {
// width: 1280,// 1920,
// height: 720,// 1080,
width: 1450,
minWidth: 1200,
height: 800,
minHeight: 700,
frame: true, // 要创建无边框窗口
// resizable: true, // 禁止窗口大小缩放
alwaysOnTop: false, // 窗口是否总是显示在其他窗口之前
title:'子窗口',
show: false, //创建时窗口不可见
maximizable: true,
autoHideMenuBar: true,// 自动隐藏菜单栏
}
data.isConsole = true // 是否开启控制台
data.option = {...defOption, ...option}
winChild = await toolWindow(data)
winChild.type = type // 唯一标识
winChild.show()
winChild.setFullScreen(false) // 设置窗口为全屏
eventHandles(type, winChild) // 事件监听处理
return winChild
}
default:
break
}
@ -246,6 +277,7 @@ const eventHandles = (type, win) => {
if(onClosed) onClosed() // 自定义关闭事件
win = null
wins_tool = null
winChild=null
})
// 新窗口-创建事件(如:主进程加载远程服务)
@ -304,6 +336,27 @@ const eventHandles = (type, win) => {
}
publicMethods(on) // 加载公共方法
break}
case 'open-taskwin': { // -子窗口
// 监听窗口的激活事件
win.on('focus', async () => {
toolState.isTaskWin=true
win&&win.reload(); //刷新该窗口
});
// 监听窗口关闭事件
win.on('closed', function () {
console.log('关闭窗口')
// 设置状态(再次设置-防止未设置到)
if(toolState.isTaskWin) toolState.isTaskWin = false
winChild=null
win&&win.destroy()
});
const on = {
onClosed: () => {
}
}
publicMethods(on) // 加载公共方法
break;
}
default:
break
}

View File

@ -266,6 +266,9 @@ const btnSave = () => {
}
//
const addGroup = () => {
//
groupForm.groupname = ''
groupForm.orderidx = 0
groupVisible.value = true
}
const btnGroupSave = () => {

View File

@ -4,7 +4,7 @@
<el-descriptions-item label="班级名称">{{ classInfo.caption }}</el-descriptions-item>
<el-descriptions-item label="教师">
<template v-if="classInfo.teacher.length > 0">
<el-tag type="primary" v-for="(item, index) in classInfo.teacher" :key="index">{{item.name}}</el-tag>
<el-tag style="margin-right: 5px;margin-bottom: 5px;" type="primary" v-for="(item, index) in classInfo.teacher" :key="index">{{item.name}}</el-tag>
</template>
<template v-else>{{ classInfo.teachername }}</template>
</el-descriptions-item>

View File

@ -1,25 +1,25 @@
<template>
<el-container class="class-reserv-wrap">
<div class="class-reserv-tabs">
<!-- <div class="class-reserv-tabs">
<el-segmented v-model="tabActive" block :options="tabOptions" size="large" />
</div>
</div>-->
<div class="class-reserv-body">
<reserv-item
v-for="(item, index) in activeDataList"
v-show="tabActive === '进行中'"
:key="index"
:item="item"
@open-edit="reservDialog.openDialog(item)"
@delete-reserv="deleteReserv(item)"
></reserv-item>
<reserv-item
v-for="(item, index) in doneDataList"
v-show="tabActive === '已结束'"
:key="index"
:item="item"
@open-edit="reservDialog.openDialog(item)"
@delete-reserv="deleteReserv(item)"
></reserv-item>
<template v-for="(item, index) in dataList" :key="index">
<reserv-item
:style="{'background-color': index%2==0?'#f5f5f5':''}"
:item="item"
v-if="item.bookImg"
@open-edit="reservDialog.openDialog(item)"
@delete-reserv="deleteReserv(item)"
></reserv-item>
<reserv-item-apt
v-if="!item.bookImg"
:style="{'background-color': index%2==0?'#f5f5f5':''}"
:item="item"
@open-edit="reservDialog.openDialog(item)"
@delete-reserv="deleteReserv(item)"
></reserv-item-apt>
</template>
</div>
<reserv ref="reservDialog"></reserv>
</el-container>
@ -28,44 +28,62 @@
<script setup>
import { ref, onMounted, computed, watch } from 'vue'
import { getSelfReserv } from '@/api/classManage'
import { listClasscourseNew } from '@/api/teaching/classcourse' // api
import ReservItem from '@/views/classManage/reserv-item.vue'
import Reserv from '@/views/prepare/container/reserv.vue'
import { useToolState } from '@/store/modules/tool'
import { sessionStore } from '@/utils/tool'
import useUserStore from '@/store/modules/user'
import ReservItemApt from '@/views/classManage/reserv-item-apt.vue'
const reservDialog = ref(null)
const tabOptions = ref(['进行中', '已结束'])
const tabActive = ref('进行中')
const dataList = ref([])
const activeDataList = computed(() => {
const toolStore = useToolState()
const userStore = useUserStore()
/*const activeDataList = computed(() => {
return dataList.value.filter((item) => {
return item.status !== '已结束'
})
})*/
const props = defineProps({
curNode: {
type: Object,
default: () => {}
}
})
const deleteReserv = (item) => {
dataList.value = dataList.value.filter((is) => {
return is.id !== item.id
})
}
const doneDataList = computed(() => {
/*const doneDataList = computed(() => {
return dataList.value.filter((item) => {
return item.status === '已结束'
})
})
})*/
//
const getData = () => {
getSelfReserv().then((res) => {
Promise.all([listClasscourseNew({teacherid: userStore.id,evalid: props.curNode.id,pageSize:1000}), getSelfReserv({ex2:props.curNode.id})]).then(([res1,res2])=>{
let list = res2.data || []
let list2 = res1.rows || []
// list.sort((a,b) => { if(a.status=='') return -1; else return 0 })
list = list.concat(list2)
list.sort((a,b) => { return new Date(b.createTime) - new Date(a.createTime) })
dataList.value = list
})
/*getSelfReserv().then((res) => {
const list = res.data || []
list.sort((a,b) => { if(a.status=='上课中') return -1; else return 0 })
dataList.value = list
})
})*/
}
const toolStore = useToolState()
watch(
() => [dataList,toolStore.isToolWin],
() => [dataList,toolStore.isToolWin,props.curNode],
() => {
console.log('====',toolStore)
setTimeout(()=>{
getData() //
},300)
@ -81,13 +99,14 @@ onMounted(() => {
height: 100%;
display: flex;
flex-direction: column;
padding: 15px 30px;
//padding: 15px 10px;
.class-reserv-tabs {
width: 30%;
text-align: left;
}
.class-reserv-body {
height: 100%;
font-size: 12px;
flex: 1;
overflow: auto;
padding: 10px 0;

View File

@ -0,0 +1,127 @@
<template>
<div class="class-reserv-item">
<div class="class-reserv-item-body">
{{ item.openDate }}&nbsp;{{ item.openTime }}
</div>
<div style="flex: 1;max-width: 400px">
<span>{{item.caption}}</span>
</div>
<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 === '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
>
<!-- <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
>
</div>
<div class="class-reserv-item-tool" style="width: 50px;">
<!-- <el-button v-if="item.status!='open'" size="small" type="danger" @click="deleteReserv">删除</el-button>-->
<el-tag>APT</el-tag>
</div>
<div style="min-width: 150px;"><span> 浏览25955 点赞26605</span></div>
</div>
</template>
<script setup>
import { useToolState } from '@/store/modules/tool'
import useUserStore from '@/store/modules/user'
import { createWindow } from '@/utils/tool'
import { deleteSmartReserv, startClass, endClass } from '@/api/classManage'
import { ElMessage } from 'element-plus'
import { listEntpcourse } from '@/api/teaching/classwork'
const emit = defineEmits(['openEdit', 'deleteReserv'])
const props = defineProps({
item: {
type: Object,
default: () => {}
}
})
const basePath = import.meta.env.VITE_APP_BUILD_BASE_PATH
const toolStore = useToolState() // -tool
const openEdit = () => {
emit('openEdit', props.item)
}
const deleteReserv = () => {
deleteSmartReserv([props.item.id]).then((res) => {
if (res.data === true) {
ElMessage({
message: '删除成功',
type: 'success'
})
emit('deleteReserv', props.item)
}
})
}
const startClassR = (item) => {
// startClass(item.id).then((res) => {
// if (res.data === true) {
// item.status = ''
// openLesson()
// }
// })
// item.status = ''
openLesson()
}
const endClassR = (item) => {
/*endClass(item.id).then((res) => {
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>
<style scoped lang="scss">
.class-reserv-item {
display: flex;
background-color: white;
border-radius: 10px;
padding: 5px;
margin-bottom: 10px;
.class-reserv-item-img {
width: 60px;
img {
width: 100%;
}
}
.class-reserv-item-body {
display: flex;
align-items: center;
text-align: left;
padding-left: 5px;
width: 120px;
.class-reserv-item-title1 {
flex: 1;
label {
font-size: 20px;
font-weight: bold;
}
}
}
.class-reserv-item-tool {
margin-left: 15px;
display: flex;
align-items: center;
}
}
</style>

View File

@ -1,34 +1,27 @@
<template>
<div class="class-reserv-item">
<div class="class-reserv-item-img">
<img :src="basePath + item.bookImg" alt="封面" />
</div>
<div class="class-reserv-item-body">
<div class="class-reserv-item-title1">
<label>{{ item.className }}</label>
<el-tag style="margin-left: 5px" type="primary"> {{ item.classType }}</el-tag>
<el-tag style="margin-left: 5px" type="primary"> {{ item.classSubject }}</el-tag>
</div>
<div class="class-reserv-item-title2">
{{ item.classDay }}&nbsp;{{ item.startTime }} ~ {{ item.classDay }}&nbsp;{{ item.endTime }}
{{ item.createUserName }}老师
</div>
<div class="class-reserv-item-title3">
<span v-for="(tag, index) in item.classItemList" :key="index" style="margin-left: 5px">
{{ index === 0 ? tag.name : '、' + tag.name }}</span
>
</div>
{{ item.classDay }}&nbsp;{{ item.startTime }}
</div>
<div class="class-reserv-item-tool">
<el-button v-if="item.status !== '已结束'" :disabled="toolStore.isToolWin" type="primary" @click="startClassR(item)"
>{{item.status == '上课中'?'上课中':'上课'}}</el-button
<div style="flex: 1;max-width: 400px">
<span v-for="(tag, index) in item.classItemList" :key="index">{{ index === 0 ? tag.name : '' + tag.name }}</span>
</div>
<div class="class-reserv-item-tool" style="width: 200px;max-width: 300px">
<el-tag v-if="item.status === '已结束'" style="margin-right: 5px" type="success">已结束</el-tag>
<el-tag v-if="item.status === '上课中'" style="margin-right: 5px" type="danger">上课中</el-tag>
<el-button v-if="item.status === '上课中'" :disabled="toolStore.isToolWin" size="small" type="primary" @click="startClassR(item)"
>继续上课</el-button
>
<el-button v-if="item.status === '未开始'" @click="openEdit">编辑</el-button>
<!-- <el-button v-if="item.status === '上课中'" type="info" @click="endClassR(item)"
<!-- <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
>-->
<el-button v-if="item.status!='上课中'" type="danger" @click="deleteReserv">删除</el-button>
>
</div>
<div class="class-reserv-item-tool" style="width: 50px;">
<!-- <el-button v-if="item.status!='上课中'" size="small" type="danger" @click="deleteReserv">删除</el-button>-->
<el-tag type="success">PPT</el-tag>
</div>
<div style="min-width: 150px;"></div>
</div>
</template>
<script setup>
@ -100,25 +93,24 @@ const endClassR = (item) => {
</script>
<style scoped lang="scss">
.class-reserv-item {
font-size: 13px;
display: flex;
background-color: white;
border-radius: 10px;
padding: 5px;
margin-bottom: 10px;
.class-reserv-item-img {
width: 80px;
padding-left: 20px;
width: 60px;
img {
width: 100%;
}
}
.class-reserv-item-body {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
text-align: left;
padding-left: 30px;
font-size: 14px;
padding-left: 5px;
width: 120px;
.class-reserv-item-title1 {
flex: 1;
label {

View File

@ -57,24 +57,29 @@
></el-empty>
</div>
</div>
<item-dialog ref="itemDialogRef" @cle-click="closeDialog"></item-dialog>
<!-- <item-dialog ref="itemDialogRef" @cle-click="closeDialog"></item-dialog> -->
</el-container>
</template>
<script setup>
import { ref, onMounted, onUnmounted, computed, watch, reactive } from 'vue'
import { listByDeadDate, listClassworkdataByDeadDate, listClassworkdata } from '@/api/classTask'
import { ref, onMounted, onUnmounted, computed, watch } from 'vue'
import { listByDeadDate, listClassworkdata, listClassworkdataNew } from '@/api/classTask'
import TaskItem from '@/views/classTask/container/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 { getCurrentTime, getTomorrow } from '@/utils/date'
import useUserStore from '@/store/modules/user'
import useClassTaskStore from "@/store/modules/classTask";
import {sessionStore, createWindow} from '@/utils/tool'
import {throttle,debounce } from '@/utils/comm'
const toolState = useToolState();
const classTaskStore = useClassTaskStore()
const userStore = useUserStore().user
const itemDialogRef = ref(null)
// const itemDialogRef = ref(null)
const tabOptions = ref(['进行中', '已结束'])
const tabActive = ref('进行中')
const dataList = ref([])
@ -85,6 +90,8 @@ const classWorkList = ref([])
const total = ref(0)
const loading = ref(false)
const activeDataList = computed(() => {
return classWorkList.value
})
@ -113,7 +120,7 @@ const getData = async () => {
classWorkList.value = []
loading.value = true
// 1
getClassList()
//getClassList()
// 2
await getClassWorkList()
// 3
@ -134,10 +141,11 @@ const getClassList = () => {
* 2获取班级作业
*/
const getClassWorkList = async () => {
if(classTaskStore.classListIds.length>0){
//if(classTaskStore.classListIds.length>0){
{
// homeworklist
const response = await listByDeadDate({
classidarray: classTaskStore.classListIds.join(','),
//classidarray: classTaskStore.classListIds.join(','),
edituserid: userStore.userId, // id
edustage: userStore.edustage, //
edusubject: userStore.edusubject,//
@ -209,8 +217,10 @@ const getClassWorkList = async () => {
/**
* 3获取多个班级学生作业数据
*/
const getStudentClassWorkData = () => {
if(classTaskStore.classListIds.length>0){
const getStudentClassWorkData = async() => {
// const { chapterId } = await useGetHomework(props.bookobj.node)
// this.entpcourseid = chapterId
//if(classTaskStore.classListIds.length>0){
// listClassworkdataByDeadDate({
// edituserid: userStore.userId, // id
// classids: classTaskStore.classListIds.join(','),
@ -220,7 +230,21 @@ const getStudentClassWorkData = () => {
// orderby: "deaddate DESC",// TODO deaddate
// pageSize: 1000,
// })
// listClassworkdataNew({
// classworkids: ids, // id
// edituserid: userStore.userId, // id
// edusubject: userStore.edusubject,//
// evalStatus: 1,
// pageSize: 1000,
// })
{
const ids = classWorkList.value.map((item) => item.id).join(',');
if (ids == '') {
return;
}
listClassworkdata({
classworkids: ids,
pageSize: 1000,
@ -323,9 +347,6 @@ const getStudentClassWorkData = () => {
}
const toolStore = useToolState()
//
const escapeHtmlQuotes = (str) => {
// replace,
@ -339,7 +360,7 @@ const pollingST = ref(null) //轮询定时器标识
onMounted(() => {
getData() //
//
getStudentClassWorkDataPolling()
closeDialog();
})
//
@ -353,13 +374,25 @@ const getStudentClassWorkDataPolling = () => {
}
const closeDialog = () => {
console.log('关闭弹窗,开启作业进度轮询')
clearInterval(pollingST.value) //
getStudentClassWorkDataPolling()
}
const debounceOpenWin = debounce(() => {
toolState.isTaskWin=true; //
createWindow('open-taskwin',{url:'/teachClassTask'}); //
}, 1000);
/**
* 开启新批改弹窗
* @param item 作业对象
*/
const onClickItem = (item) => {
console.log('开启弹窗,关闭作业进度轮询')
clearInterval(pollingST.value)
itemDialogRef.value.openDialog(item)
console.log('防抖开启弹窗')
sessionStore.set('teachClassWorkItem', item); // item
debounceOpenWin();
}
@ -413,6 +446,11 @@ const getStudentVisible = async () => {
//
classWorkList.value[t].teacherrationgcount = curWork.teacherrationgcount
} else {
//
if(curWork && curWork.workdataresultcount == 0){
//
classWorkList.value[t].teacherrationgcount = curWork.teacherrationgcount
}
classWorkList.value[t].finishpercent = 0
}
}
@ -423,9 +461,13 @@ const getStudentVisible = async () => {
watch(
() => [dataList, toolStore.isToolWin],
() => [dataList, toolState.isTaskWin],
() => {
console.log('====', toolStore)
console.log('=监听到批改窗口打开了===', toolState.isTaskWin)
if(!toolState.isTaskWin){
closeDialog();//
}
}
)
watch(tabActive, (newVal,oldVal)=>{

View File

@ -16,9 +16,9 @@
<el-row style="align-items: center; margin-bottom: 0px; flex: 0 0 auto">
<el-col :span="12" style="padding-left: 20px; text-align: left;">
<div class="unit-top-left" @click="isCollapse = !isCollapse">
<i v-if="!isCollapse" class="iconfont icon-xiangzuo"></i>
<i v-if="!isCollapse" class="iconfont icon-xiangzuo" style="color: blue;"></i>
<span>课程目录</span>
<i v-if="isCollapse" class="iconfont icon-xiangyou"></i>
<i v-if="isCollapse" class="iconfont icon-xiangyou" style="color: blue;"></i>
</div>
</el-col>
<el-col :span="12">
@ -92,7 +92,7 @@
<el-table-column v-if="props.initDataProps.queryType!=='single'" label="推送配置" align="left" min-width="16%">
<template #default="scope">
<div style="display: flex">
<el-button link icon="Setting" @click="scope.row.status == '10' ? openClassWorkConfigDialog(scope.row, -1,'item') : ''" :style="formatStyle(scope.row)" v-hasPermi="['teaching:classwork:edit']">{{scope.row.status == '10'? '推送' : '已推送'}}</el-button>
<el-button v-hasPermi="['teaching:classwork:edit']" link icon="Setting" :style="formatStyle(scope.row)" @click="scope.row.status == '10' ? openClassWorkConfigDialog(scope.row, -1,'item') : ''">{{scope.row.status == '10'? '推送' : '已推送'}}</el-button>
</div>
</template>
</el-table-column>
@ -132,8 +132,8 @@
<div slot="footer" class="dialog-footer" style="text-align: right; margin-top: 20px;">
<div style="display: flex">
<el-button v-if="currentTag=='习题训练'" style="margin-right: auto" type="primary"
:disabled="checkTaskAssigned(currentWorkEdit.currentTask)" @click="handleWorkEdit2ClassWorkQuizAdd">添加作业</el-button>
<!-- <el-button v-if="currentTag=='习题训练'" style="margin-right: auto" type="primary"
:disabled="checkTaskAssigned(currentWorkEdit.currentTask)" @click="handleWorkEdit2ClassWorkQuizAdd">添加作业</el-button> -->
<el-button type="primary" style="margin-left: auto" :disabled="checkTaskAssigned(currentWorkEdit.currentTask)"
@click="submitStudy('submit')"> </el-button>
</div>
@ -149,25 +149,108 @@
@click="submitWorkTitle('submit')"> </el-button>
</div>
</el-dialog>
<!-- 推送作业的配置对话框 -->
<el-dialog v-model="workConfDialogOpen" title="作业布置推送配置" width="60%" append-to-body>
<el-row>
<el-col :span="24">
<el-form ref="classWorkConfigFormRef" :model="classWorkConfigForm" label-width="100px">
<el-row>
<el-col :span="24">
<el-form-item label="班级" prop="grade">
<el-scrollbar max-height="300px" style="width: 100%">
<el-tree
ref="treeRef" :props="defaultProps" :load="getLoad" node-key="id" highlight-current show-checkbox
lazy @check="handleCheckChange" />
</el-scrollbar>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="选中学生">
<div style="max-height: 150px; overflow: auto">
<template v-for="(item, index) in classWorkConfigForm.studentlist" :key="item" >
<el-tag :label="item.studentid" size="large" closable style="margin: 3px" @close="handleClassDialogClassStudentRemove(item, index)">{{ item.name }}</el-tag>
</template>
</div>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="完成要求">
<el-radio-group v-model="classWorkConfigForm.feedtype">
<el-radio label="必做">必做</el-radio>
<el-radio label="选做">选做</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="截止日期">
<el-date-picker v-model="classWorkConfigForm.deaddate" type="date" placeholder="选择日期"></el-date-picker>
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item label="截止时间">
<el-input-number v-model="classWorkConfigForm.deadhour" :min="8" :max="22"></el-input-number>
<el-input-number v-model="classWorkConfigForm.deadmin" :min="0" :max="60" :step="15" style="margin-left: 10px"></el-input-number>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="推荐用时">
<el-input-number v-model="classWorkConfigForm.timelength" :min="1"></el-input-number>分钟
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="分值" v-show="false">
<el-input-number v-model="classWorkConfigForm.weights" :min="1"></el-input-number>
</el-form-item>
</el-col>
</el-row>
<el-row>
</el-row>
</el-form>
</el-col>
</el-row>
<div slot="footer" class="dialog-footer" style="text-align: right">
<el-button @click="handleWorkConfigUpdate('cancel')">取消</el-button>
<!-- <el-button type="primary" @click="handleTaskAssignToAllClassType()" :loading="classWorkToStudent_Loading">{{classWorkToStudent_Loading?'推送中……':'推送'}}</el-button> -->
<el-button type="primary" @click="handleTaskAssignToAllClassType()" >{{'推送'}}</el-button>
</div>
</el-dialog>
</div>
</div>
</template>
<script setup>
import { onMounted, ref, toRaw,watch, reactive, getCurrentInstance } from 'vue'
import { ElMessage } from 'element-plus'
import { onMounted, ref,watch, reactive, getCurrentInstance,nextTick } from 'vue'
import { useRouter } from 'vue-router'
import ChooseTextbook from '@/components/choose-textbook/index.vue'
import { homeworklist, delClasswork } from '@/api/teaching/classwork'
import { listEntpcoursework, listClassworkeval,updateClasswork } from '@/api/classTask'
import { listEntpcoursework, listClassworkeval,updateClasswork,getEvaluationclue } from '@/api/classTask'
import { listClassmain, listClassgroup } from '@/api/classManage/index'
import { saveByClassWorkArray } from '@/api/teaching/classwork'
import { useGetHomework } from '@/hooks/useGetHomework'
import { processList } from '@/hooks/useProcessList'
import { uniqBy, groupBy } from 'lodash'
import { getCurrentTime } from '@/utils/date'
import useUserStore from '@/store/modules/user'
const userStore = useUserStore().user
const { proxy } = getCurrentInstance()
const router = useRouter()
const props = defineProps({
initDataProps: {
@ -209,6 +292,22 @@ const workConfObj = reactive({
quizlist: [], // list
});
//
const defaultProps = ref({
children: 'children',
label: 'label',
isLeaf: 'leaf'
});
const gradeList = ref([]);//
const workConfDialogOpen = ref(false);//
const classWorkConfigForm = reactive({
formRowsType: '',//
formRowsList: null,
//
feedtype: '必做',
studentlist: [], //list
}); //
// ---------------------------------------------------
@ -267,7 +366,7 @@ const getTaskList = async () => {
const { chapterId } = await useGetHomework(courseObj.node)
// this.entpcourseid = chapterId
//
homeworklist({entpcourseid: chapterId, orderby: "concat(deaddate,uniquekey) DESC" , edituserid: userStore.userId, pageSize: 100}).then(res => {
homeworklist({entpcourseid: chapterId, orderby: "deaddate DESC" , edituserid: userStore.userId, pageSize: 500}).then(res => {
let model = [];
let mission = [];
@ -353,7 +452,6 @@ const getTaskList = async () => {
}
list.push(item);
}
console.log(list,'========================')
taskList.value = list;
loading.value = false;
})
@ -369,20 +467,21 @@ const handleWorkTitleEdit = (row, index) => {
};
//
// -
const handleWorkEdit = (row, index) =>{
console.log(row, index)
workEdit.value = true
// this.currentTask = row;
// this.currentIndex = index;
currentWorkEdit.currentTask = row;
// currentWorkEdit.currentIndex = index;
currentTag.value = row.worktype;
this.attainmentList = row.workcodesList?.attlist;
this.courseQualityList = row.workcodesList?.qualist;
// this.attainmentList = row.workcodesList?.attlist;
// this.courseQualityList = row.workcodesList?.qualist;
if (row.worktype == '框架梳理') {
this.$nextTick(()=>{
this.getFlowData()
})
}
// if (currentTag.value.worktype == '') {
// if (row.worktype == '') {
// // TODO
// rootid:entpcourseworkid rootid: row.entpcourseworklistarray[0].id,
// listEvaluationclue({ cluegroup: 'graph', edusubject: this.courseObj.edusubject, pageSize: 1000 }).then((res) => {
@ -398,7 +497,8 @@ const handleWorkEdit = (row, index) =>{
// }
// //
if (currentTag.value.worktype == '习题训练') {
if (row.worktype == '习题训练') {
console.log('习题训练')
var idlist = JSON.parse('['+row.entpcourseworklist+']');
var ids = [];
for (var i=0; i<idlist.length; i++) {
@ -426,14 +526,14 @@ const handleWorkEdit = (row, index) =>{
}
});
});
console.log(workConfObj.quizlist,'workConfObj.quizlist');
//
processList(workConfObj.quizlist);
})
}
//
if(currentTag.value.worktype == '常规作业' || row.worktype == '课堂展示'){
if(row.worktype == '常规作业' || row.worktype == '课堂展示'){
console.log(row,'常规作业-课堂展示');
// workcodes
if(row.workcodes != ''){
@ -449,44 +549,522 @@ const handleWorkEdit = (row, index) =>{
}
}
};
// --
let classtaskObj = reactive({
id: '', //
bookName: '', //
uniquekey: '', //
title: '', //
worktype: '', //
quizlist: [], //
chooseWorkLists: [],// list
fileHomeworkList: [],// list
whiteboardObj: '',//
})
// -
const newHandleWorkEdit2ClassWorkQuizAdd = async (row, index) =>{
// this.newWorkSpace = true;
// this.newWorkSpaceEdit = true;
// this.currentTask = row;
// this.currentIndex = index;
// this.currentTag = row.worktype;
// this.attainmentList = row.workcodesList?.attlist;
// this.courseQualityList = row.workcodesList?.qualist;
// -
const submitWorkTitle = () => {
console.log(taskList.value)
console.log(currentWorkEdit)
// ? taskList currentIndex
// if (taskList.value[currentWorkEdit.currentIndex].title == currentWorkEdit.currentTitle) {
// currentWorkEdit.workTitleEdit = false;
// return;
// }
taskList.value&&taskList.value.forEach((item)=>{
if(item.children.length>0){
item.children.map(_item=>{
if(_item.title == currentWorkEdit.currentTitle){
currentWorkEdit.workTitleEdit = false;
return;
}
})
}else{
if(item.title == currentWorkEdit.currentTitle){
currentWorkEdit.workTitleEdit = false;
//
// this.classWorkForm.uniquekey = this.currentTask.uniquekey;
// this.classWorkForm.title = this.currentTask.title;
//
// this.classWorkForm.worktype = this.currentTask.worktype;
//[]
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.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 == '框架梳理') {
//
// let queryParams = {}
// queryParams.id = listCourseWork[0].id;
// queryParams.ppttype = '';
// queryParams.title = '';
// queryParams.filetype = 'draw';
const res = await getEvaluationclue(listCourseWork[0].id);
if ( res.data==null || res.data==undefined ) {
return;
}
console.log('res.data', res.data);
// this.chooseWorkLists = [];
res.data.worktype = '框架梳理';
res.data.score = listCourseWork[0].score;
classtaskObj.chooseWorkLists.push(res.data);
//
}
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;
//
}
})
}
else if (row.worktype == '课堂展示') {
console.log('row.课堂展示', row.workcodes);
const workcodes = JSON.parse(row.workcodes);
classtaskObj.whiteboardObj = JSON.stringify(workcodes.json);
//
}
else if (row.worktype == '常规作业') {
if(isJson(row.workcodes)){
classtaskObj.fileHomeworkList = JSON.parse(row.workcodes);
//
}
}
//
router.push({
path: '/newClassTask',
query: {
classtaskObj: JSON.stringify(classtaskObj),
}
})
}
};
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
}
}
}
//
const getGradeList = async() => {
let { rows } = await listClassmain({
classuserid: userStore.userId,
pageSize: 100,
status: 'open'
})
rows.forEach((item) => {
item.label = item.caption
item.level = 0
item.leaf = false
item.children = []
item.classstudentlist = JSON.parse('[' + item.classstudentlist + ']')
item.classstudentlist.forEach((el) => {
el.classid = item.id
})
})
return rows
};
//
const getLoad = async (node, resolve) =>{
//
if (node.level == 0) {
gradeList.value = await getGradeList()
resolve(gradeList.value)
}
//
if (node.level == 1) {
listClassgroup({ classid: node.key, orderby: 'orderidx', pageSize: 100 }).then((res) => {
if (res.rows.length > 0) {
let ary = []
res.rows.forEach((item) => {
if (item.parentid === 0) {
//studentGroup
let studentGroup = JSON.parse('[' + item.studentlist + ']')
studentGroup.forEach((el) => {
el.label = el.name
el.leaf = true
el.level = 2
el.id = el.studentid
el.classid = item.classid
})
ary.push({
label: item.groupname,
leaf: false,
...item,
level: 1,
// children
children: studentGroup
})
}
})
resolve(ary)
} else {
//
let students = node.data.classstudentlist
students.forEach((item) => {
item.label = item.name
item.level = 2
item.leaf = true
})
resolve(students)
}
})
}
//
if (node.level == 2) {
resolve(node.data.children)
}
}
//
const handleCheckChange = (data, checked) => {
classWorkConfigForm.studentlist = [];
//
let checkNodes = checked.checkedNodes
let ary = []
checkNodes.forEach((item) => {
//
if (item.level == 0) {
ary = [...ary, ...item.classstudentlist]
}
//
if (item.level == 1) {
ary = [...ary, ...item.children]
}
//
if (item.level == 2) {
ary = [...ary, item]
}
})
console.log('有更改!')
//
taskList.value[currentWorkEdit.currentIndex].title = currentWorkEdit.currentTitle;
updateClasswork({id: taskList.value[currentWorkEdit.currentIndex].id, title: currentWorkEdit.currentTitle}).then(response => {
ElMessage("修改成功");
classWorkConfigForm.studentlist = uniqBy(ary, 'studentid')
};
//
const handleClassDialogClassStudentRemove = (item,index) => {
classWorkConfigForm.studentlist.splice(index, 1);
// []]
proxy.$refs.treeRef.setChecked(item.id, false, true);
//TODO
// const ids = this.$refs.treeRef.getCheckedKeys();
// console.log(ids)
// console.log(ids.filter((_item)=>_item == item.id),'???????')
// if(ids&&ids.filter((_item)=>_item == item.id).length>0){
// console.log(ids,'?====?')
// console.log(item.id,'?=item.id===?')
// // ?
// this.$refs.treeRef.setChecked(item.id, false, true);
// // setCheckedKeys
// }
};
/**
* 处理在作业推送前的任务配置
*/
const openClassWorkConfigDialog = (row, configindex, type) => {
//
workConfDialogOpen.value = true;
classWorkConfigForm.formRowsType = '';//
classWorkConfigForm.formRowsList = null;
if(type == 'list'){
classWorkConfigForm.formRowsType = 'list';
classWorkConfigForm.formRowsList = row;
}else{
classWorkConfigForm.formRowsType = 'item';
classWorkConfigForm.formRowsList = [row];
}
// TODO
// if (configindex > -1) {
// this.handleClassDialogConfigShow(configindex, 0)
// }
classWorkConfigForm.deaddate = getCurrentTime('YYYY-MM-DD');
classWorkConfigForm.deadhour = getCurrentTime('HH+3');// 3
classWorkConfigForm.deadmin = getCurrentTime('mm');
classWorkConfigForm.timelength = 1;
};
/**
* 推送配置保存配置
* @param key 'cancel' or 'submit'
*/
const handleWorkConfigUpdate = (key,row) => {
if (key == 'cancel') {
workConfDialogOpen.value = false;
} else if (key == 'submit') {
// 2024-04-08, by jackyshen
// this.classWorkConfigForm.classlist
var clist = [];
var cidlist = [];
for (var i=0; i< classWorkConfigForm.studentlist.length; i++) {
if (cidlist.indexOf(classWorkConfigForm.studentlist[i].classid) == -1) {
// UI
var clsname = '';
for (var d = 0; d<gradeList.value.length; d++) {
if (gradeList.value[d].id == classWorkConfigForm.studentlist[i].classid) {
clsname = gradeList.value[d].caption;
}
}
clist.push({id: classWorkConfigForm.studentlist[i].classid, caption: clsname});
cidlist.push(classWorkConfigForm.studentlist[i].classid);
}
}
// 20240408207
// index > -1
//
//
//
// if (classWorkConfigForm.index > -1) {
// classWorkConfigForm.classWorkConfigList.splice(classWorkConfigForm.activeClassWorkIndex);
// }
//
var hh = classWorkConfigForm.deadhour;
hh = "0"+hh;
hh = hh.substr(hh.length-2, 2);
var mm = classWorkConfigForm.deadmin;
mm = "0"+mm;
mm = mm.substr(mm.length-2, 2);
//
classWorkConfigForm.deaddate = '' + classWorkConfigForm.deaddate;
if (isNaN(classWorkConfigForm.deaddate.substring(0,4))) {
var dd = new Date(classWorkConfigForm.deaddate);
var year = dd.getFullYear(); //
var month = dd.getMonth() + 1; //0-11
month = "0"+month;
month = month.substr(month.length-2,2);
var day = dd.getDate(); //131
day = "0"+day;
day = day.substr(day.length-2,2);
classWorkConfigForm.deaddate = year+'-'+month+'-'+day;
}
classWorkConfigForm.classWorkConfigList = [];
//
for (var i=0; i<clist.length; i++) {
classWorkConfigForm.classWorkConfigList.push({
id: 0,
classid: clist[i].id,
classcaption: clist[i].caption, //
parentid: 0,
worktype: '',
workkey: classWorkConfigForm.workkey,
worktag: '',
entpcourseid: 0,
evalid: 0,
edusubject: '',
edudegree: '',
workdate: '',
title: '',
workcodes: '',
studentlist: classWorkConfigForm.studentlist,
timelength: classWorkConfigForm.timelength,
weights: classWorkConfigForm.weights,
feedtype: classWorkConfigForm.feedtype,
deaddate: classWorkConfigForm.deaddate+' '+hh+":"+mm,
});
}
if(classWorkConfigForm.formRowsType == 'list'){
// list
for(var d=0;d<classWorkConfigForm.formRowsList.length;d++){
classWorkConfigForm.rowid = classWorkConfigForm.formRowsList[d].id;
// 20240308by jackyshen
// classWorkConfigForm.classWorkConfigListtaskList[i]
// classWorkConfigForm.classWorkConfigList
for (var i=0; i<taskList.value.length; i++) {
if (taskList.value[i].id == classWorkConfigForm.rowid) {
taskList.value[i].taskconfig = classWorkConfigForm.classWorkConfigList;
break;
}
}
}
}else{
// item
classWorkConfigForm.rowid = classWorkConfigForm.formRowsList[0].id;
// 20240308by jackyshen
// classWorkConfigForm.classWorkConfigListtaskList[i]
// classWorkConfigForm.classWorkConfigList
for (var i=0; i<taskList.value.length; i++) {
if (taskList.value[i].id == classWorkConfigForm.rowid) {
taskList.value[i].taskconfig = classWorkConfigForm.classWorkConfigList;
break;
}
}
}
//
classWorkConfigForm.id = 0;
classWorkConfigForm.index = -1;
classWorkConfigForm.selclassid = 0;
classWorkConfigForm.classlist = [];
classWorkConfigForm.studentlist = [];
classWorkConfigForm.feedtype = '必做';
classWorkConfigForm.workkey = '';
classWorkConfigForm.selgroupid = 0;
classWorkConfigForm.classGroups = [];
classWorkConfigForm.availableStudents = [];
classWorkConfigForm.deaddate = getCurrentTime('YYYY-MM-DD');
classWorkConfigForm.deadhour = getCurrentTime('HH+3');
classWorkConfigForm.deadmin = getCurrentTime('mm');
classWorkConfigForm.timelength = 1;
classWorkConfigForm.weights = 1;
}
};
/**
* 推送
*/
const handleTaskAssignToAllClassType = async() => {
if(classWorkConfigForm.studentlist.length == 0){
return proxy.$modal.msgWarning('请选择需要推送的学生!');
}
// this.classWorkToStudent_Loading = true;
//
handleWorkConfigUpdate('submit', '')
const { chapterId } = await useGetHomework(courseObj.node)
// this.entpcourseid = chapterId
console.log(taskList.value,'===============this.taskListthis.taskList')
var ttt = [];
for (var i=0; i<taskList.value.length; i++) {
// 20240408, by jackyshen
// taskconfig.classWorkList
for (var t=0; t<taskList.value[i].taskconfig.length; t++) {
if (taskList.value[i].taskconfig[t].id == 0) {
ttt.push({
id: 0,
parentid: taskList.value[i].id,
classid: taskList.value[i].taskconfig[t].classid,
classcourseid: 0,
entpcourseid: chapterId,
studentlist: JSON.stringify(taskList.value[i].taskconfig[t].studentlist),
feedback: taskList.value[i].taskconfig[t].feedtype,
workkey: taskList.value[i].taskconfig[t].workkey,
timelength: taskList.value[i].taskconfig[t].timelength,
weights: taskList.value[i].taskconfig[t].weights,
deaddate: taskList.value[i].taskconfig[t].deaddate,
workdate: getCurrentTime('YYYY-MM-DD'),
uniquekey: taskList.value[i].uniquekey,
entpcourseworklist: '['+taskList.value[i].entpcourseworklist+']', // JSON
needMsgNotifine: 'false',
msgkey: 'newclasswork',
title: taskList.value[i].title,
status:'1',
msgcontent: '', // classworkjson
teachername: userStore.nickName,
unixstamp: new Date().getTime(),
});
}
}
}
console.log(ttt,'===============ttt')
if(ttt.length == 0){
proxy.$modal.msgError('您还未进行作业配置,请配置后再推送');
return;
}
var wForm = {};
wForm.classworkarray = JSON.stringify(ttt);
saveByClassWorkArray(wForm).then(response => {
console.log(response,'===============response');
// this.classWorkToStudent_Loading = false;
workConfDialogOpen.value = false;
proxy.$modal.msgSuccess("作业推送成功");
//
proxy.$refs.treeRef.setCheckedKeys([]);
//
nextTick(() => {
getTaskList();
})
}).catch((error) =>{
// this.classWorkToStudent_Loading = false;
workConfDialogOpen.value = false;
});
};
/**
* 一键推送
*/
const handleTaskAssignToAllClass = () => {
let rows = proxy.$refs.taskTable.getSelectionRows();
if (rows.length > 0) {
proxy.$modal.confirm('是否确认推送选中的学习任务?').then(()=> {
}).then(() => {
//
openClassWorkConfigDialog(rows, -1,'list')
}).catch(() => {})
}else{
return proxy.$modal.alertWarning("请选择需要推送的任务!");
}
}
/**
* 设计作业
*/
const handleNewClassWorkDialog = () => {
//
router.push({ path: '/newClassTask' });
}
// -
const submitWorkTitle = () => {
if(currentWorkEdit.currentTask.title == currentWorkEdit.currentTitle){
currentWorkEdit.workTitleEdit = false;
//this.getClassWorkAllList();
return;
}
//
updateClasswork({id: currentWorkEdit.currentTask.id, title: currentWorkEdit.currentTitle}).then(response => {
proxy.$modal.msgSuccess("修改成功");
currentWorkEdit.workTitleEdit = false;
//
getTaskList();
});
};
//
const checkTaskAssigned = (row) => {
console.log(row,'checkTaskAssigned')
// taskconfigid0
let bAssigned = false;
for (let i=0; i<row.taskconfig.length; i++) {

View File

@ -1,8 +1,8 @@
<template>
<el-form ref="classWorkFormScoreRef" :model="classWorkFormScore">
<el-form ref="classWorkFormScoreRef" :model="classWorkFormScore" style="height: 100%">
<!-- <div class="teacher_content" :style="{ height: dialogProps.maxheight + 'px' }"> -->
<div class="teacher_content" :style="{ height: '72vh' }">
<div style="font-size: 18px; width: 100%; padding: 5px 10px" class="sticky">
<div class="teacher_content" :style="{ height: '100%' }">
<div style="font-size: 18px; width: 100%; padding: 5px 10px; flex: 0 0 auto;">
{{ classWorkFormScore.name }} 答题详情
</div>
<div class="teacher_content_con">
@ -24,7 +24,7 @@
<!-- 习题训练 -->
<div v-if="dialogProps.studentObj.worktype == '习题训练'">
<el-row>
<el-col :span="24" style="padding: 10px">
<el-col :span="24" style="padding: 10px;text-align: left;">
<!-- 题源题目标题题目选项 -->
<span>{{ quItem.worktag }}</span>
<span style="margin-left: 4px" v-html="quItem.titleFormat"></span>
@ -121,9 +121,7 @@
:max="classWorkFormScore.teacherRating[sIndex].maxScore"
size="small"
:disabled="
(quItem.worktype == '单选题' || quItem.worktype == '多选题') &&
stuItem.feedcontent == stuItem.rightanswer &&
stuItem.feedcontent != ''
(quItem.worktype == '单选题' || quItem.worktype == '多选题' || quItem.worktype == '判断题')
? true
: false
"
@ -171,10 +169,10 @@
<el-collapse-item title="老师布置详情" name="1">
<div class="image_list">
<div v-if="teachImageList.length > 0">
<div style="margin-bottom: 5px">
<div style="margin-bottom: 5px;text-align: left;">
<span style="color: red">温馨提示点击图片可放大预览 </span>
</div>
<div v-for="(imageItem, index) in teachImageList" :key="index">
<div v-for="(imageItem, index) in teachImageList" :key="index" style="text-align: left;">
<el-image
style="width: 400px; height: 400px"
:src="imageItem.url"
@ -198,7 +196,7 @@
</div>
<div v-if="teachFileList.length > 0">
<div style="margin: 10px 0">
<div style="margin: 10px 0;text-align: left;">
<span style="color: red" @click="openFile"
>温馨提示点击此处 可预览其他类型附件
</span>
@ -214,16 +212,16 @@
<div v-if="feedContentList.length > 0">
<div v-if="dialogProps.studentObj.worktype == '常规作业' && stuItem.rightanswer != ''&& stuItem.rightanswer != null">
<!-- 常规作业学生有的会答复 -->
<p style="padding: 10px 0;">学生答复内容</p>
<div style="padding: 0 20px">{{stuItem.rightanswer}}</div>
<p style="padding: 10px 0;text-align: left;">学生答复内容</p>
<div style="padding: 0 20px;text-align: left;">{{stuItem.rightanswer}}</div>
</div>
<p>学生答题附件内容</p>
<p style="text-align: left;">学生答题附件内容</p>
<div class="image_list">
<div v-if="imageList.length > 0">
<div style="margin-bottom: 5px">
<div style="margin-bottom: 5px;text-align: left;">
<span style="color: red">温馨提示点击图片可放大预览 </span>
</div>
<div v-for="(imageItem, index) in imageList" :key="index">
<div v-for="(imageItem, index) in imageList" :key="index" style="text-align: left;">
<el-image
style="width: 500px; height: 500px"
:src="imageItem.url"
@ -247,7 +245,7 @@
</div>
<div v-if="fileList.length > 0">
<div style="margin: 10px 0">
<div style="margin: 10px 0;text-align: left;">
<span style="color: red" @click="openFile"
>温馨提示点击此处 可预览其他类型附件
</span>
@ -255,7 +253,7 @@
</div>
<!-- 无附件内容 -->
<div v-if="imageList.length == 0 && fileList.length == 0" style="padding: 0 20px">未提交附件内容</div>
<div v-if="imageList.length == 0 && fileList.length == 0" style="padding: 0 20px;text-align: left;">未提交附件内容</div>
</div>
</div>
<div v-else>
@ -924,6 +922,7 @@ defineExpose({
<style scoped>
.teacher_content {
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-around;
@ -935,11 +934,16 @@ defineExpose({
width: 100%;
height: 100%;
overflow-y: auto;
}
.tacher_conten_foot {
width: 100%;
}
.card-header{
text-align: left;
}
.image_list {
display: flex;
flex-wrap: nowrap;
@ -985,4 +989,8 @@ defineExpose({
background-color: red;
color: white;
}
.card-header{
align-items: left;
}
</style>

View File

@ -33,13 +33,13 @@
v-if="classWorkAnalysis.row.worktype == '习题训练'"
:type="classWorkAnalysis.view == 'quizStats' ? 'success' : ''"
@click="workHandle('quizStats')"
>作业概况</el-button
>逐题分析</el-button
>
<el-button
v-if="classWorkAnalysis.row.worktype == '习题训练'"
:type="classWorkAnalysis.view == 'report' ? 'success' : ''"
@click="handleClassOverviewOpen('report')"
>作业报告</el-button
>整体分析</el-button
>
</el-button-group>
</el-row>
@ -81,12 +81,17 @@
>
<el-table-column type="index" label="序号" width="52" reserve-selection align="center" />
<el-table-column label="姓名" prop="studentname" width="100" align="center" />
<el-table-column label="提交时间" prop="updatedate" width="170" align="center" />
<el-table-column :label="tableRadio.value==0?'提交状态':'提交时间'" prop="updatedate" width="170" align="center">
<template #default="scope">
<span v-if="tableRadio.value==0" style="color: #2196f3">未提交</span>
<span v-if="tableRadio.value==1">{{ scope.row.updatedate }}</span>
</template>
</el-table-column>
<el-table-column label="批阅状态" prop="teacherRating" align="center" width="120" sortable>
<template #default="scope">
<template v-if="scope.row.teacherRating == 0"
><span style="color: #2196f3">待批阅</span></template
>
<template v-if="scope.row.teacherRating == 0">
<span v-if="tableRadio.value==1" style="color: #2196f3">待批阅</span>
</template>
<!-- 1- 2-优减 3- 4-良减 5- -->
<template v-if="scope.row.teacherRating == 1"
><el-tag type="danger"></el-tag></template
@ -136,12 +141,12 @@
</div>
</div>
<!-- 作业概况 -->
<!-- 逐题分析 -->
<div v-else-if="classWorkAnalysis.view == 'quizStats'">
<quiz-stats :active-data="classWorkActiveData" />
</div>
<!-- 作业报告-->
<!-- 整体分析-->
<div v-else-if="classWorkAnalysis.view == 'report'" style="overflow-y: scroll">
<!-- <ClassOverview :table-list="overviewData" :eval-id="courseObj.evalid"></ClassOverview> -->
<ClassOverview :table-list="overviewData"></ClassOverview>
@ -188,7 +193,7 @@ const tableRadio = reactive({
const loading_dt_table = ref(false)
const isopen_dtwk_table = ref(false)
// zdg:
// zdg:
const classWorkActiveData = reactive({
quizlist: [], //
studentList: [], // -
@ -234,7 +239,7 @@ const openDialog = (data) => {
classWorkAnalysis.activeQuizAnalysisData = []
classWorkAnalysis.row = data
window.test = this
// window.test = this
// zdg:
const studentArr = data.classworkdatastudentids
? JSON.parse(`[${data.classworkdatastudentids}]`)
@ -349,7 +354,7 @@ const getClassWorkStudentList = (rowId) => {
// .replace(/"(\[.*\])"/g, '$1'); eg: "feedcontent\":\"[{\"name\":\"Bliss.jpg\",\"url\":\"https://wzyzoss.3b8daa474.jpg\"}]\",
// json .replace(/""/g, '"') eg: """"
response.rows[i].classworkevallist = escapeHtmlQuotes(response.rows[i].classworkevallist)
console.log('学生完成情况分析classworkevallist', response.rows[i].classworkevallist)
//console.log('classworkevallist', response.rows[i].classworkevallist)
const evalarray = JSON.parse('[' + response.rows[i].classworkevallist + ']')
var scoingCount = 0
var feedcount = 0
@ -362,7 +367,7 @@ const getClassWorkStudentList = (rowId) => {
}
}
}
console.log(evalarray, 'evalarray------------------------------------')
//console.log(evalarray, 'evalarray------------------------------------')
if (feedcount > 0) {
// : /*100
response.rows[i].scoingRate = ((scoingCount / feedcount) * 100).toFixed(0) + '%'
@ -531,7 +536,7 @@ const escapeHtmlQuotes = (str) => {
return result;
}
//#region
//#region
// -
const workHandle = (type) => {
// ui
@ -566,11 +571,11 @@ const getWorkFeedList = async() =>{
//#endregion
//#regin
//#regin
/*
author: yangws
time: 2024-8-06 16:35:33
function:作业报告的处理
function: 整体分析的处理
*/
const handleClassOverviewOpen = (type) =>{
// ui
@ -638,12 +643,12 @@ const closeDialog = () => {
watch(classWorkAnalysis, (newVal, oldVal) => {
if(newVal.view != 'quizStats'){
console.log('关闭zdg: 定时执行')
clearInterval(classWorkActiveData.timerId) //
clearInterval(classWorkActiveData.timerId) //
}
})
onUnmounted(() => {
clearInterval(classWorkActiveData.timerId) //
clearInterval(classWorkActiveData.timerId) //
})
defineExpose({

View File

@ -7,9 +7,9 @@
<el-row class="top">
<el-col :span="24">
<el-form-item label="作业类型:">
<el-radio-group v-model="formType" @change="changeFormType">
<el-radio-group v-model="classWorkForm.worktype" @change="changeFormType">
<template v-for="(item) in listWorkType" :key="item">
<el-radio :value="item" >{{ item }}</el-radio>
<el-radio :value="item" :disabled="props.isedit">{{ item }}</el-radio>
</template>
</el-radio-group>
</el-form-item>
@ -21,12 +21,12 @@
<div v-if="classWorkForm.worktype == '课堂展示'" style="height: 100%; display: flex; flex-direction: column;">
<div style="flex: 0 0 auto;">
<el-form-item label="问题">
<el-input v-model="question" type="text" placeholder="请输入问题" />
<el-input v-model="classWorkForm.title" type="text" placeholder="请输入问题" />
</el-form-item>
</div>
<div v-loading="boardLoading" class="board-wrap" style="height: 100%; flex: 1; overflow: hidden;">
<!-- <whiteboard v-if="isShowBoard" ref="boardref" :height="mainHeight - 150" :isShowSave="false" :data="whiteboardObj"/> -->
<whiteboard ref="boardref" :height="mainHeight - 150" :isShowSave="false" :data="whiteboardObj"/>
<whiteboard ref="boardref" :height="mainHeight - 150" :isShowSave="false" :data="classWorkForm.whiteboardObj"/>
</div>
</div>
<div v-else class="el-form-work-list">
@ -154,7 +154,7 @@
</template>
<template v-if="classWorkForm.worktype =='常规作业'">
<div v-loading="fileLoading" class="upload-homework">
<FileUpload v-model="fileHomeworkList" :fileSize="800" :fileType="['mp3','mp4','doc','docx','xlsx','xls','pdf','ppt','pptx','jpg','jpeg','gif','png','txt']"/>
<FileUpload v-model="classWorkForm.fileHomeworkList" :fileSize="800" :fileType="['mp3','mp4','doc','docx','xlsx','xls','pdf','ppt','pptx','jpg','jpeg','gif','png','txt']"/>
</div>
</template>
</div>
@ -180,7 +180,7 @@
<div v-if="classWorkForm.worktype!='习题训练'" :style="{'overflow': 'auto', 'border':'1px dotted blue','border-radius':'5px', 'background-color': '#f7f7f7'}">
<div style="margin: 5px; background-color: white">
<template v-for="(item) in chooseWorkLists" :key="item.id">
<template v-for="(item) in classWorkForm.chooseWorkLists" :key="item.id">
<div v-if="item.worktype==classWorkForm.worktype">
<div class="choose-work">
<div class="choose-work-title">{{ item.worktype }}</div>
@ -247,10 +247,12 @@
<script setup>
import { onMounted, ref, nextTick, watch, reactive, getCurrentInstance } from 'vue'
import { ElMessage } from 'element-plus'
import { useToolState } from '@/store/modules/tool'
import { cloneDeep } from 'lodash'
import { useRouter } from 'vue-router'
import {listEntpcoursework, listEntpcourseworkNew, getEntpcoursework} from '@/api/education/entpCourseWork'
import { addClassworkReturnId } from '@/api/teaching/classwork'
import { updateClasswork, listEvaluationclue,readFile } from '@/api/classTask'
import { updateClasswork, listEvaluationclue,readFile, listClassworkeval,delClassworkeval,addClassworkeval,updateClassworkeval } from '@/api/classTask'
import { listEvaluation } from '@/api/subject'
import { listEntpcoursefile } from '@/api/education/entpcoursefile'
import { listKnowledgePoint } from "@/api/knowledge/knowledgePoint";
@ -263,19 +265,24 @@ import FileUpload from "@/components/FileUpload/index.vue";
import whiteboard from '@/components/whiteboard/whiteboard.vue'
import { useToolState } from '@/store/modules/tool'
import useUserStore from '@/store/modules/user'
const userStore = useUserStore().user
const { proxy } = getCurrentInstance()
const router = useRouter()
const props = defineProps({
bookobj: {
type: Object,
default: () => ({})
},
uniquekey: {
type: String,
default: ''
propsformobj: {
type: Object,
default: () =>({})
},
isedit: {
type: Boolean,
default: false
}
})
@ -286,11 +293,6 @@ const openDialog = () => {
isDialogOpen.value = true
}
const classWorkFormRef = ref(null);
const formType = ref('习题训练')
const newWorkSpaceEdit = ref(false); //
// ---------------------------------------------------
const listWorkType = ref(['习题训练', '框架梳理', '课堂展示', '常规作业']); //
const entpCourseWorkTypeList = ref([
{value: 0, label: "不限"},
{value: 1, label: "单选题"},
@ -356,17 +358,20 @@ const workResource = reactive({
entpCourseWorkTotal: 0, //
}); //
let classWorkForm = reactive({
uniquekey: props.uniquekey, //
worktype: '习题训练', //
title: '',//
quizlist: [], //
id: cloneDeep(props.propsformobj.id),
uniquekey: props.propsformobj.uniquekey?cloneDeep(props.propsformobj.uniquekey):'', //
worktype: props.propsformobj.worktype?cloneDeep(props.propsformobj.worktype): '习题训练', //
title: props.propsformobj.title?cloneDeep(props.propsformobj.title):'',//
quizlist: props.propsformobj.quizlist?cloneDeep(props.propsformobj.quizlist):[], //
chooseWorkLists: props.propsformobj.chooseWorkLists?cloneDeep(props.propsformobj.chooseWorkLists):[], // list
fileHomeworkList: props.propsformobj.fileHomeworkList?cloneDeep(props.propsformobj.fileHomeworkList):[], //
whiteboardObj: props.propsformobj.whiteboardObj?cloneDeep(props.propsformobj.whiteboardObj):'', // -
}); //
const chooseWorkLists = ref([]); //
const whiteboardObj = ref(''); // -
// ---------------------------------------------------
const listWorkType = ref(['习题训练', '框架梳理', '课堂展示', '常规作业']); //
// -------
const boardLoading = ref(false);
const isShowBoard = ref(false); //
const question = ref(''); // --
const prevReadMsg = reactive({
visible: false,
type: ""
@ -375,17 +380,16 @@ const prevReadMsg = reactive({
const flowData = ref({})//
//----------
const fileLoading = ref(false); // loading
const fileHomeworkList = ref([]);//
/***
* 作业类型切换
*/
const changeFormType = (val) => {
console.log(val)
classWorkForm.worktype = val;
classWorkForm.worktype = val;
}
console.log(props.propsformobj)
console.log(classWorkForm,'==============zizujian===================')
/**
* @desc: 根据查询参数查询试题
* @return: {*}
@ -623,7 +627,7 @@ const prevRead = async (item) => {
//
const handleClassWorkAddOfResource = (work) => {
//
let arrSole = chooseWorkLists.value.filter((item) => {
let arrSole = classWorkForm.chooseWorkLists.filter((item) => {
return item.worktype === classWorkForm.worktype
})
//
@ -632,25 +636,29 @@ const handleClassWorkAddOfResource = (work) => {
return;
}
//
let arr = chooseWorkLists.value.filter((item) => {
let arr = classWorkForm.chooseWorkLists.filter((item) => {
return item.id === work.id
})
if (arr.length===0) {
work.score = 1;
chooseWorkLists.value.push(work);
classWorkForm.chooseWorkLists.push(work);
}
};
/**
* 删除作业
* 右侧资源删除作业 非习题list
*/
const deleteClassWorkAddOfResource = (work) => {
chooseWorkLists.value.filter((item, index) => {
classWorkForm.chooseWorkLists.filter((item, index) => {
if (item.id === work.id) {
chooseWorkLists.value.splice(index, 1);
classWorkForm.chooseWorkLists.splice(index, 1);
return;
}
})
}
/** 右侧资源删除按钮 习题list */
const handleClassWorkFormQuizRemove = (index) =>{
classWorkForm.quizlist.splice(index, 1);
}
@ -662,305 +670,67 @@ const handleClassWorkSave = async () => {
await nextTick(); // DOM
proxy.$refs["classWorkFormRef"].validate(async valid => {
if (valid) {
if (classWorkForm.id != null) {
// []
updateClasswork(classWorkForm).then(response => {
ElMessage("修改成功");
// this.workConfDialogOpen = false;
//
// this.getClassWorkAllList(); //
});
} else {
// [] newWorkSpaceEdit true
if(newWorkSpaceEdit.value ) {
//
const { chapterId } = await useGetHomework(props.bookobj.node)
// this.entpcourseid = chapterId
// 0.
if (this.currentTag == '习题训练') {
if (this.classWorkForm.quizlist.length == 0) {
ElMessage.error('请先添加作业资源!');
return;
}
}
else if (this.currentTag == '课堂展示' || this.currentTag == '常规作业') {
//
const cform = {
id: 0,
workdate: classWorkForm.workdate, // //web
deaddate: '', //
entpid: userStore.deptId, //
level: 1,
parentid: 0,
worktype: classWorkForm.worktype, //
workkey: '',
worktag: '',
uniquekey: classWorkForm.uniquekey,//
classid: 0,
classcourseid: 0,
entpcourseid: chapterId, //
slideid: 0,
title: classWorkForm.title, //
workcodes: JSON.stringify(classWorkForm.workcodes), //
edusubject: userStore.edusubject, //
evalid: props.bookobj.levelSecondId, //userStore.evalid, // // ID
edustage: userStore.edustage, // ,,
status: '10', //2024-09-11
edituserid: userStore.userId, // id
entpcourseworklist: '', // list
};
}
else {
if (this.chooseWorkLists.length == 0) {
ElMessage.error('请先添加作业资源!');
return;
}
}
//
let classWorkParams = {
id: this.currentTask.id,
uniquekey: this.classWorkForm.uniquekey, // []
//title: classWorkForm.title, // []
}
//
if (this.currentTag=='习题训练'){
// console.log(this.workConfObj.quizlist);
// console.log(this.currentTask);
// console.log(this.classWorkList);
// 1.
let needUplEval = false;
if (this.classWorkForm.quizlist.length !== this.currentTask.entpcourseworklistarray.length) {
needUplEval = true;
}
else {
//
// [] newWorkSpaceEdit true
if(classWorkForm.id != '' ) {// id
// for (let cur of this.classWorkForm.quizlist){
// let isSame = false;
// for (let last of this.currentTask.entpcourseworklistarray) {
// if (last.id === cur.id && last.score === cur.score){
// isSame = true;
// break;
// }
// }
// if (!isSame) {
// needUplEval = true;
// break;
// }
// }
needUplEval = this.classWorkForm.quizlist.some(cur =>
!this.currentTask.entpcourseworklistarray.some(last =>
last.id === cur.id && last.score === cur.score
)
);
}
// 2.eval
if (needUplEval) {
// : , ,
// 2.1.workidid
let arrEvalids = [];
const wevalres = await listClassworkeval({'workid': this.currentTask.id});
wevalres.rows.forEach(element => {
arrEvalids.push(element.id);
});
const ids = arrEvalids.join(',');
// 2.2.
const delRes = await delClassworkeval(ids);
editWork(cform); //
return;
}
// 2.3.
for(let i=0; i<this.classWorkForm.quizlist.length; i++){
const addRes = await addClassworkeval({
'workid': this.currentTask.id,
'entpcourseworkid': this.classWorkForm.quizlist[i].id,
'workdataid': 0,
'score': this.classWorkForm.quizlist[i].score}
);
}
}
// 3.
// const evalid = this.homeworkLesson.length==0 ? '' : this.homeworkLesson.length==1 ? this.homeworkLesson[0] : this.homeworkLesson[1];
// const formObj = {
// id: this.currentTask.id,
// uniquekey: this.classWorkForm.uniquekey, // []
// // warn:
// //evalid = evalid, // []
// }
// let res = await updateClasswork(formObj);
}
else if (this.currentTag=='框架梳理') {
// 1.workidid
const wevalres = await listClassworkeval({'workid': this.currentTask.id});
if (wevalres.rows.length == 0) {
ElMessage.error('未找到原框架梳理任务,请或退出重试');
return;
}
// 2.
let needUplEval = false;
if (this.chooseWorkLists.length !== this.currentTask.entpcourseworklistarray.length) {
needUplEval = true;
}
else {
//
needUplEval = this.chooseWorkLists.some(cur =>
!this.currentTask.entpcourseworklistarray.some(last =>
last.id === cur.id && last.score === cur.score
)
);
}
if (needUplEval) {
const uplParams = {
id: wevalres.rows[0].id,
entpcourseworkid: this.chooseWorkLists[0].id,
score: this.chooseWorkLists[0].score,
}
let res = await updateClassworkeval(uplParams);
}
}
else if (this.currentTag=='课堂展示') {
}
else if (this.currentTag=='常规作业') {
// 1. (, )
classWorkParams.workcodes = JSON.stringify(this.fileHomeworkList);
}
// 3.
let res = await updateClasswork(classWorkParams);
this.fileHomeworkList = [];
this.chooseWorkLists = [];
// 4.
//
// this.getClassWorkAllList();
this.classWorkForm.worktype = "习题训练";
this.newWorkSpace = false;
this.newWorkSpaceEdit = false;
this.workEdit = false;
return;
}
//
const { chapterId } = await useGetHomework(props.bookobj.node)
// this.entpcourseid = chapterId
const cform = {
id: 0,
workdate: classWorkForm.workdate, // //web
deaddate: '', //
entpid: userStore.deptId, //
level: 1,
parentid: 0,
worktype: classWorkForm.worktype, //
workkey: '',
worktag: '',
uniquekey: classWorkForm.uniquekey,//
classid: 0,
classcourseid: 0,
entpcourseid: chapterId, //
slideid: 0,
title: classWorkForm.title, //
workcodes: JSON.stringify(classWorkForm.workcodes), //
edusubject: userStore.edusubject, //
evalid: props.bookobj.levelSecondId, //userStore.evalid, // // ID
edustage: userStore.edustage, // ,,
status: '10', //2024-09-11
edituserid: userStore.userId, // id
entpcourseworklist: '', // list
};
if (classWorkForm.worktype === "课堂展示") {
boardLoading.value = true
let canvasJson = proxy.$refs.boardref.getCanvasJson()
let canvasBase64 = await proxy.$refs.boardref.getCanvasBase64()
//
// cform.worktag = question.value;
cform.title = question.value;
cform.workcodes = JSON.stringify({json: canvasJson, base64: canvasBase64});
cform.entpcourseworklist = JSON.stringify([{'id':-1, 'score': '10'}]);
try {
addClassworkReturnId(cform).then(() => {
ElMessage({ type: 'success', message: '作业设计成功!'});
//
classWorkForm.worktype = "课堂展示";
classWorkForm.uniquekey = props.uniquekey, //
classWorkForm.title = "";
classWorkForm.quizlist = [], //
//
chooseWorkLists.value = [];
whiteboardObj.value = ''; // ? //
// refresh the list
//
// this.getClassWorkAllList();
// TODO
//TODO 3
// this.newWorkSpace = false;
// this.newWorkSpaceEdit = false;
// this.workEdit = false;
boardLoading.value = false
})
} finally {
boardLoading.value = false
}
}
else if(classWorkForm.worktype === "常规作业"){
fileLoading.value = true
cform.workcodes = JSON.stringify(fileHomeworkList.value);
cform.entpcourseworklist = JSON.stringify([{'id':-2, 'score': '10'}]);
try {
addClassworkReturnId(cform).then(() => {
ElMessage({ type: 'success', message: '作业设计成功!'});
//
classWorkForm.worktype = "常规作业";
classWorkForm.uniquekey = props.uniquekey, //
classWorkForm.title = "";
classWorkForm.quizlist = [], //
//
chooseWorkLists.value = [];
whiteboardObj.value = ''; // ? //
fileHomeworkList.value = []; // list
// refresh the list
//
// this.getClassWorkAllList();
// TODO
//TODO 3
// this.newWorkSpace = false;
// this.newWorkSpaceEdit = false;
// this.workEdit = false;
fileLoading.value = false
})
} finally {
fileLoading.value = false
}
}
else {
//
var ll = [];
if (classWorkForm.worktype === "习题训练") {
for (var i=0; i< classWorkForm.quizlist.length; i++) {
//
ll.push({'id': classWorkForm.quizlist[i].id, 'score': classWorkForm.quizlist[i].score});
}
}else if( classWorkForm.worktype === "框架梳理") {
chooseWorkLists.value.filter((item) => {
if (item.worktype === classWorkForm.worktype) {
ll.push({'id':item.id, 'score': item.score});
}
})
}
// list
if (ll.length > 0) {
cform.entpcourseworklist = JSON.stringify(ll);
} else {
cform.entpcourseworklist = '';
}
console.log(cform,'提交的数据');
if(cform.entpcourseworklist == '') return ElMessage({ type: 'warning', message: '请先添加作业资源!'});
addClassworkReturnId(cform).then(workres => {
if (classWorkForm.worktype === "课堂展示") {
boardLoading.value = true
let canvasJson = proxy.$refs.boardref.getCanvasJson()
let canvasBase64 = await proxy.$refs.boardref.getCanvasBase64()
//
cform.title = classWorkForm.title;
cform.workcodes = JSON.stringify({json: canvasJson, base64: canvasBase64});
cform.entpcourseworklist = JSON.stringify([{'id':-1, 'score': '10'}]);
try {
addClassworkReturnId(cform).then(() => {
ElMessage({ type: 'success', message: '作业设计成功!'});
//
classWorkForm.worktype = "习题训练";
classWorkForm.uniquekey = props.uniquekey, //
classWorkForm.worktype = "课堂展示";
classWorkForm.uniquekey = props.propsformobj.uniquekey, //
classWorkForm.title = "";
classWorkForm.quizlist = [], //
//
chooseWorkLists.value = [];
whiteboardObj.value = ''; // ? //
classWorkForm.chooseWorkLists = []; // list
classWorkForm.whiteboardObj = ''; // ? //
// refresh the list
//
// this.getClassWorkAllList();
@ -971,17 +741,222 @@ const handleClassWorkSave = async () => {
// this.newWorkSpace = false;
// this.newWorkSpaceEdit = false;
// this.workEdit = false;
boardLoading.value = false
})
} finally {
boardLoading.value = false
}
}
else if(classWorkForm.worktype === "常规作业"){
fileLoading.value = true
cform.workcodes = JSON.stringify(classWorkForm.fileHomeworkList);
cform.entpcourseworklist = JSON.stringify([{'id':-2, 'score': '10'}]);
try {
addClassworkReturnId(cform).then(() => {
ElMessage({ type: 'success', message: '作业设计成功!'});
//
classWorkForm.worktype = "常规作业";
classWorkForm.uniquekey = props.propsformobj.uniquekey, //
classWorkForm.title = "";
classWorkForm.quizlist = [], //
//
classWorkForm.chooseWorkLists = []; // list
classWorkForm.whiteboardObj = ''; // ? //
classWorkForm.fileHomeworkList = []; // list
// refresh the list
//
// this.getClassWorkAllList();
// TODO
//TODO 3
// this.newWorkSpace = false;
// this.newWorkSpaceEdit = false;
// this.workEdit = false;
fileLoading.value = false
})
} finally {
fileLoading.value = false
}
}
else {
//
var ll = [];
if (classWorkForm.worktype === "习题训练") {
for (var i=0; i< classWorkForm.quizlist.length; i++) {
//
ll.push({'id': classWorkForm.quizlist[i].id, 'score': classWorkForm.quizlist[i].score});
}
}else if( classWorkForm.worktype === "框架梳理") {
classWorkForm.chooseWorkLists.filter((item) => {
if (item.worktype === classWorkForm.worktype) {
ll.push({'id':item.id, 'score': item.score});
}
})
}
// list
if (ll.length > 0) {
cform.entpcourseworklist = JSON.stringify(ll);
} else {
cform.entpcourseworklist = '';
}
console.log(cform,'提交的数据');
if(cform.entpcourseworklist == '') return ElMessage({ type: 'warning', message: '请先添加作业资源!'});
addClassworkReturnId(cform).then(workres => {
ElMessage({ type: 'success', message: '作业设计成功!'});
//
classWorkForm.worktype = "习题训练";
classWorkForm.uniquekey = props.propsformobj.uniquekey, //
classWorkForm.title = "";
classWorkForm.quizlist = [], //
//
classWorkForm.chooseWorkLists = [];
classWorkForm.whiteboardObj = ''; // ? //
// refresh the list
//
// this.getClassWorkAllList();
// TODO
//TODO 3
// this.newWorkSpace = false;
// this.newWorkSpaceEdit = false;
// this.workEdit = false;
})
}
}
});
};
const editWork = async (cform) =>{
//
cform.id= classWorkForm.id;
// 0.
if (classWorkForm.worktype == '习题训练') {
if (classWorkForm.quizlist.length == 0) {
ElMessage.error('请先添加作业资源!');
return;
}
}else if (classWorkForm.worktype == '课堂展示' || classWorkForm.worktype == '常规作业') {
//
}else {
if (classWorkForm.chooseWorkLists.length == 0) {
//
ElMessage.error('请先添加作业资源!');
return;
}
}
//
if (classWorkForm.worktype=='习题训练'){
// 1.
let needUplEval = false;
if (classWorkForm.quizlist.length != props.propsformobj.quizlist.length) {
needUplEval = true;
}else {
//
needUplEval = classWorkForm.quizlist.some(cur =>
!props.propsformobj.quizlist.some(last =>
last.id === cur.id && last.score === cur.score
)
);
}
// 2.eval
if (needUplEval) {
// : , ,
// 2.1.workidid
let arrEvalids = [];
const wevalres = await listClassworkeval({'workid': classWorkForm.id});
wevalres.rows.forEach(element => {
arrEvalids.push(element.id);
});
const ids = arrEvalids.join(',');
// 2.2.
const delRes = await delClassworkeval(ids);
// 2.3.
for(let i=0; i< classWorkForm.quizlist.length; i++){
const addRes = await addClassworkeval({
'workid': classWorkForm.id,
'entpcourseworkid': classWorkForm.quizlist[i].id,
'workdataid': 0,
'score': classWorkForm.quizlist[i].score}
);
}
}
// 3.-
}
else if (classWorkForm.worktype=='框架梳理') {
// 1.workidid
const wevalres = await listClassworkeval({'workid': classWorkForm.id});
if (wevalres.rows.length == 0) {
ElMessage.error('未找到原框架梳理任务,请或退出重试');
return;
}
// 2.
let needUplEval = false;
if (classWorkForm.chooseWorkLists.length !== props.propsformobj.chooseWorkLists.length) {
needUplEval = true;
}else {
//
needUplEval = classWorkForm.chooseWorkLists.some(cur =>
!props.propsformobj.chooseWorkLists.some(last =>
last.id === cur.id && last.score === cur.score
)
);
}
if (needUplEval) {
const uplParams = {
id: wevalres.rows[0].id,
entpcourseworkid: classWorkForm.chooseWorkLists[0].id,
score: classWorkForm.chooseWorkLists[0].score,
}
//
let res = await updateClassworkeval(uplParams);
}
}
else if (classWorkForm.worktype=='课堂展示') {
let canvasJson = proxy.$refs.boardref.getCanvasJson()
let canvasBase64 = await proxy.$refs.boardref.getCanvasBase64()
cform.workcodes = JSON.stringify({json: canvasJson, base64: canvasBase64});
}
else if (classWorkForm.worktype=='常规作业') {
// 1. (, )
cform.workcodes = JSON.stringify(classWorkForm.fileHomeworkList);
}
// 3.
let res = await updateClasswork(cform);
if (res.code == 200) {
ElMessage.success('更新成功');
//
router.back()
}
}
onMounted(() => {
})
watch(() => props.propsformobj.uniquekey, (newVal) => {
console.log(props.propsformobj,'propsformobj')
if(props.propsformobj.uniquekey){
classWorkForm.uniquekey = props.propsformobj.uniquekey?cloneDeep(props.propsformobj.uniquekey):''; //
}
})
watch(() => props.bookobj.levelSecondId, (newVal) => {
console.log(props.bookobj,'课程选择')
//

View File

@ -1,6 +1,6 @@
<template>
<el-row class="c-warp" :gutter="10">
<el-col class="left" :span="16">
<el-col class="left" :span="14">
<el-collapse class="c-item" v-model="activeTopic" accordion>
<template v-for="(item, index) in dataList">
<el-collapse-item class="collapse-item" :name="index+1" :id="'collapse-'+(index+1)">
@ -54,9 +54,9 @@
</template>
</el-collapse>
</el-col>
<el-col class="right" :span="8">
<el-col class="right" :span="10">
<div class="c-item">
<div class="title">答题情况</div>
<div class="title">提交情况</div>
<div class="respond">
<el-space wrap>
<!-- <template v-for="it in 11"> -->
@ -114,7 +114,9 @@ colorArr = [
]
// === ===
onMounted(() => {})
onMounted(() => {
activeTopic.value = dataList.value.map((_, index) => index + 1);
})
// === (methods) ===
@ -309,16 +311,16 @@ watchEffect(() => { initData() })
//
.c-warp{
background: #F2F3F5;
height: 73vh;
height: 100%;
margin: 0 !important;
.left{padding-left: 0 !important;}
.left{padding-left: 0 !important; height: 100%;}
.right{padding-right: 0 !important;}
.c-item{
padding: 10px;
background: #fff;
border: none;
overflow-y: auto;
height: 73vh;
height: 100%;
}
.collapse-item{
.item-title-o{
@ -345,6 +347,7 @@ watchEffect(() => { initData() })
}
.t-left{width: 160px;text-align: left;}
.c-respond{
text-align: left;
.el-tag{margin: 0 5px;}
}
}
@ -359,7 +362,7 @@ watchEffect(() => { initData() })
margin-bottom: 10px;
}
.respond{
height: calc(70vh - 65px);
height: calc(100% - 65px);
overflow: auto;
.el-space{padding: 5px;}
.card-warp{

View File

@ -14,7 +14,6 @@
&nbsp;|&nbsp; 截止时间{{ item.deaddate }} &nbsp;|&nbsp;{{ tabactive }}
</div>
</div>
<!-- <el-switch v-model="value1" active-text="云同步"> </el-switch> -->
<div class="class-reserv-item-tool">
<span>
<span v-if="item.workdataresultcount!=0" style="color:#000fff; font-weight: 900; font-size: 15px">{{ item.workdataresultcount }}</span>
@ -68,60 +67,8 @@ const props = defineProps({
default: () => ''
}
})
import { ref, reactive } from 'vue'
const value1 = ref(true);
const basePath = import.meta.env.VITE_APP_BUILD_BASE_PATH
const toolStore = useToolState() // -tool
const openEdit = () => {
emit('openEdit', props.item)
}
const deleteReserv = () => {
deleteSmartReserv([props.item.id]).then((res) => {
if (res.data === true) {
ElMessage({
message: '删除成功',
type: 'success'
})
emit('deleteReserv', props.item)
}
})
}
const startClassR = (item) => {
// startClass(item.id).then((res) => {
// if (res.data === true) {
// item.status = ''
// openLesson()
// }
// })
item.status = '上课中'
openLesson()
}
// 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 })
}
})
}
const endClassR = (item) => {
endClass(item.id).then((res) => {
if (res.data === true) {
ElMessage({
message: '下课成功',
type: 'success'
})
item.status = '已结束'
}
})
}
</script>
<style scoped lang="scss">
.class-reserv-item {
@ -130,6 +77,7 @@ const endClassR = (item) => {
border-radius: 10px;
padding: 10px 5px;
margin-bottom: 10px;
cursor: pointer;
.class-reserv-item-body {
flex: 1;

View File

@ -15,10 +15,15 @@
<!-- 标题 -->
<el-row style="align-items: center; margin-bottom: 0px; flex: 0 0 auto">
<el-col :span="12" style="padding-left: 20px; text-align: left;">
<div class="unit-top-left" @click="isCollapse = !isCollapse">
<i v-if="!isCollapse" class="iconfont icon-xiangzuo"></i>
<div v-if="!isOpenLeftBook" class="unit-top-left cursor-pointer" @click="onOpenLeftBook">
<i v-if="!isCollapse" class="iconfont icon-xiangzuo" style="color: blue;"></i>
<span>课程目录</span>
<i v-if="isCollapse" class="iconfont icon-xiangyou"></i>
<i v-if="isCollapse" class="iconfont icon-xiangyou" style="color: blue;"></i>
</div>
<div v-else class="unit-top-left">
<i class="iconfont icon-xiangzuo cursor-pointer" style="color: blue;" @click="goBack">返回上页</i>
<span>课程</span>
<span>{{bookTitle}}</span>
</div>
</el-col>
<el-col :span="12">
@ -30,26 +35,39 @@
</el-col>
</el-row>
<!-- 作业类型:内容 -->
<task-type-view :bookobj="courseObj" :uniquekey="classWorkForm.uniquekey" style="flex: 1; overflow: hidden;"/>
<task-type-view :bookobj="courseObj" :propsformobj="classWorkForm" :isedit="isOpenLeftBook" style="flex: 1; overflow: hidden;"/>
</div>
</div>
</template>
<script setup>
import { onMounted, ref, toRaw,watch, reactive } from 'vue'
import { onMounted, ref, toRaw,watch, reactive, getCurrentInstance } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import ChooseTextbook from '@/components/choose-textbook/index.vue'
import TaskTypeView from '@/views/classTask/container/newTask/taskTypeView.vue'
import { getCurrentTime } from '@/utils/date'
import useUserStore from '@/store/modules/user'
const userStore = useUserStore().user
const route = useRoute();
const router = useRouter()
const { proxy } = getCurrentInstance()
const classtaskObj = route.query.classtaskObj;//
const bookTitle = ref(classtaskObj? JSON.parse(classtaskObj).bookName: '');//
const isOpenLeftBook = ref(classtaskObj? JSON.parse(classtaskObj).id ? true : false: false ); //
const isCollapse = ref(isOpenLeftBook.value?true:false); // : false
// ---------------------------------------------------
const classWorkForm = reactive({
// uniquekey: userStore.edusubject+'-' + getCurrentTime('MMDD')+'-'+(this.taskList.length+1),
uniquekey: userStore.edusubject+'-' + getCurrentTime('MMDD')+'-'+(1),
id: classtaskObj? JSON.parse(classtaskObj).id : '', // id
uniquekey: classtaskObj? JSON.parse(classtaskObj).uniquekey : userStore.edusubject+'-' + getCurrentTime('MMDD')+'-'+(1), //
title: classtaskObj? JSON.parse(classtaskObj).title : '', //
worktype: classtaskObj? JSON.parse(classtaskObj).worktype : '', //
quizlist: classtaskObj? JSON.parse(classtaskObj).quizlist : [], //
chooseWorkLists: classtaskObj? JSON.parse(classtaskObj).chooseWorkLists : [],// list
fileHomeworkList: classtaskObj? JSON.parse(classtaskObj).fileHomeworkList : [],// list
whiteboardObj: classtaskObj? JSON.parse(classtaskObj).whiteboardObj : '',//
})
const isCollapse = ref(false)
const courseObj = reactive({
@ -61,7 +79,6 @@ const courseObj = reactive({
node: null, //
//
})
// ---------------------------------------------------
@ -88,19 +105,32 @@ const getData = (data) => {
localStorage.setItem('unitId', JSON.stringify({ levelFirstId, levelSecondId}))
}
onMounted(() => {
init()
// sourceStore.getCreate()
})
const init = () => {
classWorkForm.uniquekey = userStore.edusubject+'-' + getCurrentTime('MMDD')+'-'+(1);
const onOpenLeftBook = () => {
if(isOpenLeftBook.value){
//
proxy.$modal.msgError(`当前为编辑状态不可选择课程!`);
}else{
//
isCollapse.value = !isCollapse.value
}
}
// ---
const goBack = () =>{
router.back()
}
// watch(() => sourceStore.query.fileSource,() => {
// sourceStore.query.fileSource === ''?isThird.value = true:isThird.value = false
// })
onMounted(() => {
//
if(classtaskObj&&JSON.parse(classtaskObj).bookObj){
const bookobj = JSON.parse(classtaskObj).bookObj;
courseObj.textbookId = bookobj.bookObj //
courseObj.levelFirstId = bookobj.levelFirstId //
courseObj.levelSecondId = bookobj.levelSecondId //
courseObj.coursetitle = bookobj.node.itemtitle // (/)
courseObj.node = bookobj.node; //
}
})
</script>
<style lang="scss" scoped>
@ -117,8 +147,10 @@ const init = () => {
width: 300px;
min-height: 100%;
}
.cursor-pointer {
cursor: pointer;//
}
.unit-top-left {
cursor: pointer;
.icon-xiangzuo {
margin-right: 5px;

View File

@ -0,0 +1,797 @@
<template>
<div class="teachClassTask">
<div class="teachClassTask_header">
<div style="font-size: 18px; display: flex; flex-wrap: nowrap">
<div style="flex: 1">
{{ classWorkAnalysis.title }}答题情况
<el-tag :type="classWorkAnalysis.workclass" size="large" style="height: 25px">{{
classWorkAnalysis.worktype
}}</el-tag>
</div>
<!-- classWorkAnalysis.entpcourseworklistarray 当前学习任务所包含的试题ID -->
<div
v-if="classWorkAnalysis.entpcourseworklistarray.length > 0"
style="margin: 0 auto; flex: 1"
>
<el-button-group style="margin-bottom: 10px">
<el-button
:type="classWorkAnalysis.view == 'studentview' ? 'success' : ''"
@click="classWorkAnalysis.view = 'studentview'"
>作业批阅</el-button
>
<el-button
v-if="classWorkAnalysis.row.worktype == '习题训练'"
:type="classWorkAnalysis.view == 'quizStats' ? 'success' : ''"
@click="workHandle('quizStats')"
>逐题分析</el-button
>
<el-button
v-if="classWorkAnalysis.row.worktype == '习题训练'"
:type="classWorkAnalysis.view == 'report' ? 'success' : ''"
@click="handleClassOverviewOpen('report')"
>整体分析</el-button
>
</el-button-group>
</div>
<div style="flex: 1">
<!-- <div
style="float: right; padding: 0 10px; cursor: pointer"
icon="el-icon-close"
@click="closeDialog"
>
x
</div> -->
</div>
</div>
</div>
<div class="teachClassTask_content">
<!-- 如果当前学习没有试题 :height="mainHeight" height:73vh;-->
<div
v-if="classWorkAnalysis.view == 'studentview'"
style="width: 100%; "
class="clwk_dialog_view"
>
<div class="view_table">
<el-radio-group
v-model="tableRadio.value"
style="margin-bottom: 1px"
@change="tableRadioChange"
>
<el-radio-button :value="1" :label="'已交' + '' + tableRadio.num1 + ''" />
<el-radio-button :value="0" :label="'未交' + '' + tableRadio.num0 + ''" />
</el-radio-group>
<!-- 学生列表classWorkAnalysis.classworkdata; 已交未交tableRadio.list -->
<el-table
v-loading="loading_dt_table"
:data="tableRadio.list"
row-key="id"
style="height: 100%;overflow: hidden;"
highlight-current-row
@row-click="getStudentClassWorkDataDetail"
>
<el-table-column type="index" label="序号" width="52" reserve-selection align="center" />
<el-table-column label="姓名" prop="studentname" width="100" align="center" />
<el-table-column :label="tableRadio.value==0?'提交状态':'提交时间'" prop="updatedate" width="170" align="center">
<template #default="scope">
<span v-if="tableRadio.value==0" style="color: #2196f3">未提交</span>
<span v-if="tableRadio.value==1">{{ scope.row.updatedate }}</span>
</template>
</el-table-column>
<el-table-column label="批阅状态" prop="teacherRating" align="center" width="120" sortable>
<template #default="scope">
<template v-if="scope.row.teacherRating == 0">
<span v-if="tableRadio.value==1" style="color: #2196f3">待批阅</span>
</template>
<!-- 1- 2-优减 3- 4-良减 5- -->
<template v-if="scope.row.teacherRating == 1"
><el-tag type="danger"></el-tag></template
>
<template v-if="scope.row.teacherRating == 2"
><el-tag type="danger">-</el-tag></template
>
<template v-if="scope.row.teacherRating == 3"
><el-tag type="warning"></el-tag></template
>
<template v-if="scope.row.teacherRating == 4"
><el-tag type="info">-</el-tag></template
>
<template v-if="scope.row.teacherRating == 5"
><el-tag type="info"></el-tag></template
>
</template>
</el-table-column>
</el-table>
</div>
<div class="view_teachrting">
<div class="classwork-score">
<div v-if="classWorkAnalysis.activeStudentQuizlist.length == 0">
<el-empty
description="点击左侧表格学生信息可查看批阅详情"
style="width: 100%; height: 500px"
></el-empty>
</div>
<div v-else style="height: 100%;">
<div v-if="isopen_dtwk_table" style="height: 100%;">
<div v-show="classWorkAnalysis.activeStudentQuizlist.length > 0" style="height: 100%;">
<item-dialog-score
ref="classWorkAnalysisScoreDialogRef"
@class_work_score_submit="onClassWorkScoreSubmit"
/>
</div>
</div>
<div v-else>
<el-empty
description="点击左侧表格学生信息可查看批阅详情"
style="width: 100%; height: 500px"
></el-empty>
</div>
</div>
</div>
</div>
</div>
<!-- 逐题分析 -->
<div v-else-if="classWorkAnalysis.view == 'quizStats'" style="width: 100%;">
<quiz-stats :active-data="classWorkActiveData" style="width: 100%;height: 100%;"/>
</div>
<!-- 整体分析-->
<div v-else-if="classWorkAnalysis.view == 'report'" style="width: 100%;overflow-y: scroll">
<!-- <ClassOverview :table-list="overviewData" :eval-id="courseObj.evalid"></ClassOverview> -->
<ClassOverview :table-list="overviewData" style="width: 100%;"></ClassOverview>
</div>
</div>
</div>
</template>
<script setup name="itemDialogRef">
import { ref, defineExpose, onMounted, reactive, computed, watch, onUnmounted, nextTick, getCurrentInstance } from 'vue'
import { listClassworkdata, listEntpcoursework, listClassworkeval } from '@/api/classTask'
import useUserStore from '@/store/modules/user'
import { ElMessage } from 'element-plus'
import { getCurrentTime, getAfterMinutes } from '@/utils/date'
import { processList } from '@/hooks/useProcessList'
import ItemDialogScore from '@/views/classTask/container/item-dialog-score.vue'
// zdg:
import quizStats from '@/views/classTask/container/quizStats.vue'
import ClassOverview from '@/views/classTask/container/classOverview.vue'
import {sessionStore} from '@/utils/tool'
const { proxy } = getCurrentInstance()
const emit = defineEmits(['cle-click'])
const props = defineProps({
bookId: {
type: Number,
default: 0
},
})
const mainHeight = ref(document.documentElement.clientHeight - 110)
const classWorkAnalysis = reactive({
open: false,
entpcourseworklistarray: [], // ID
})
const tableRadio = reactive({
value: '1', //
list: [], // list
num1: 0, //
num0: 0 //
}) //
const loading_dt_table = ref(false)
const isopen_dtwk_table = ref(false)
// zdg:
const classWorkActiveData = reactive({
quizlist: [], //
studentList: [], // -
workFeedList: [], // -
timerId: 0 // id
})
//-
const classWorkAnalysisScore = reactive({
studentObj: {}, //
studentQuizAllList: [], // list
quizlist: [] // list
})
//
const overviewData = ref([])
// watch(
// // () => props.currentNode,
// (newValue, oldValue) => {
// form.name = newValue.label
// }
// )
const openDialog = (data) => {
console.log(data, '点击的item答题情况')
classWorkAnalysis.title = data.uniquekey ? data.uniquekey + '--' : ''
classWorkAnalysis.worktype = data.worktype
classWorkAnalysis.workclass = data.workclass
//
tableRadio.list = []
tableRadio.value = '1'
tableRadio.num0 = 0
tableRadio.num1 = 0
classWorkAnalysis.open = true
//
classWorkAnalysis.view = 'studentview'
// ID
classWorkAnalysis.entpcourseworklistarray = data.entpcourseworklistarray
//
classWorkAnalysis.activeStudentQuizlist = []
//
classWorkAnalysis.activeQuizAnalysisData = []
classWorkAnalysis.row = data
window.test = this
// zdg:
const studentArr = data.classworkdatastudentids
? JSON.parse(`[${data.classworkdatastudentids}]`)
: []
classWorkActiveData.studentList = studentArr
/** 学生完成情况分析--获取作业学生list数据 */
getClassWorkStudentList(data.id)
// idlist
var ids = []
for (var i = 0; i < data.entpcourseworklistarray.length; i++) {
ids.push(data.entpcourseworklistarray[i].id)
}
//
listEntpcoursework({ ids: ids.join(','), pageSize: 500 }).then((idres) => {
for (var i = 0; i < idres.rows.length; i++) {
// // + .replace(/!@#\$%/g,'')
idres.rows[i].titletext = idres.rows[i].title.replace(/!@#\$%/g, '')
}
classWorkAnalysis.quizlist = idres.rows
classWorkActiveData.quizlist = idres.rows // zdg: 使
//
// + , pageSize: 100
listClassworkeval({ workid: data.id, pageSize: 1000 }).then((wevalres) => {
for (var i = 0; i < classWorkAnalysis.quizlist.length; i++) {
//
var scoingCount = 0
var feedcount = 0
//
var evalCount = 0
for (var w = 0; w < wevalres.rows.length; w++) {
if (wevalres.rows[w].entpcourseworkid == classWorkAnalysis.quizlist[i].id) {
evalCount++
//
if (wevalres.rows[w].feedcontent != '') {
//
feedcount++
//
if (wevalres.rows[w].feedcontent == wevalres.rows[w].rightanswer) {
wevalres.rows[w].scoingStatus = true
scoingCount++
// =
wevalres.rows[w].teacherRating = wevalres.rows[w].score
} else {
wevalres.rows[w].scoingStatus = false
}
}
}
}
classWorkAnalysis.quizlist[i].evalCount = evalCount
//
classWorkAnalysis.quizlist[i].feedcount = feedcount
// NaN% scoingRate
if (scoingCount == 0 && feedcount == 0) {
classWorkAnalysis.quizlist[i].scoingRate = '0%'
} else {
classWorkAnalysis.quizlist[i].scoingRate =
((scoingCount / feedcount) * 100).toFixed(0) + '%'
}
}
// zdg:
const getStudentid = (workdataid) => {
// id
const classworkdata = (classWorkAnalysis.classworkdata || []).find(
(o) => o.id === workdataid
)
return classworkdata ? classworkdata.studentid : ''
}
wevalres.rows.forEach((o) => {
o.studentid = getStudentid(o.workdataid)
})
classWorkActiveData.workFeedList = wevalres.rows
})
})
console.log(classWorkAnalysis, '点击进度后获得的数据')
}
//#region
/** 1、获取作业学生列表 */
const getClassWorkStudentList = (rowId) => {
// rowid使
localStorage.setItem('activeClassWorkRowId', rowId)
//
classWorkAnalysis.classworkdata = []
// _
loading_dt_table.value = true
// classworkdata
listClassworkdata({ classworkid: rowId, pageSize: 100 })
.then((response) => {
for (var i = 0; i < response.rows.length; i++) {
if (response.rows[i].entpcourseworklist != '') {
response.rows[i].entpcourseworkarray = JSON.parse(
'[' + response.rows[i].entpcourseworklist + ']'
)
} else {
response.rows[i].entpcourseworkarray = []
}
// 0
response.rows[i].teacherRating = 0
//
if (
response.rows[i].classworkevallist != '' &&
response.rows[i].classworkevallist != null &&
response.rows[i].classworkevallist != 'null'
) {
// , : "{\"id\":172910, \"feedcontent\":\"<bdo class=\"mathjye-underpoint2\"></bdo>\", \"score\":4, \"rightanswer\":\"<bdo class=\"mathjye-underpoint2\"></bdo>\"},{\"id\":172911, \"rating\":0, \"teacherRating\":0, \"entpcourseworkid\":363100, \"feedcontent\":\"<bdo class=\"mathjye-underpoint2\"></bdo>\", \"score\":4, \"rightanswer\":\"<bdo class=\"mathjye-underpoint2\"></bdo>\"}"
// .replace(/"(\[.*\])"/g, '$1'); eg: "feedcontent\":\"[{\"name\":\"Bliss.jpg\",\"url\":\"https://wzyzoss.3b8daa474.jpg\"}]\",
// json .replace(/""/g, '"') eg: """"
response.rows[i].classworkevallist = escapeHtmlQuotes(response.rows[i].classworkevallist)
//console.log('classworkevallist', response.rows[i].classworkevallist)
const evalarray = JSON.parse('[' + response.rows[i].classworkevallist + ']')
var scoingCount = 0
var feedcount = 0
for (var e = 0; e < evalarray.length; e++) {
if (evalarray[e].feedcontent != '') {
feedcount++
//
if (evalarray[e].feedcontent == evalarray[e].rightanswer) {
scoingCount++
}
}
}
//console.log(evalarray, 'evalarray------------------------------------')
if (feedcount > 0) {
// : /*100
response.rows[i].scoingRate = ((scoingCount / feedcount) * 100).toFixed(0) + '%'
} else {
response.rows[i].scoingRate = '0%'
}
// :
if (evalarray[0].rating != '') {
response.rows[i].teacherRating = evalarray[0].rating
}
} else {
response.rows[i].scoingRate = '0%'
}
}
classWorkAnalysis.classworkdata = response.rows
loading_dt_table.value = false
//
tableRadio.list =
classWorkAnalysis.classworkdata &&
classWorkAnalysis.classworkdata.filter((item) => item.finishtimelength != '0')
tableRadio.value = '1'
tableRadio.num0 = classWorkAnalysis.classworkdata.length - tableRadio.list.length
tableRadio.num1 = tableRadio.list.length
})
.catch(() => {
loading_dt_table.value = false
})
}
/** 2、查看某一个学生的学习任务完成详情*/
const getStudentClassWorkDataDetail = (row) => {
//
// this.classWorkAnalysis.quizlist
console.log(row, '点击了左侧学生')
//
classWorkAnalysisScore.studentObj = row
listClassworkeval({ workdataid: row.id, pageSize: 100 })
.then((wevalres) => {
for (var i = 0; i < classWorkAnalysis.quizlist.length; i++) {
//
for (var w = 0; w < wevalres.rows.length; w++) {
if (wevalres.rows[w].entpcourseworkid == classWorkAnalysis.quizlist[i].id) {
wevalres.rows[w].quiztitle = classWorkAnalysis.quizlist[i].title
wevalres.rows[w].quiztitletext = classWorkAnalysis.quizlist[i].title.replace(
/<[^>]*>/g,
''
)
wevalres.rows[w].score = wevalres.rows[w].score ? wevalres.rows[w].score : 0
// html
wevalres.rows[w].rightanswer =
wevalres.rows[w].rightanswer != '' && wevalres.rows[w].rightanswer != null
? wevalres.rows[w].rightanswer.replace(/<[^>]+>/g, '')
: wevalres.rows[w].rightanswer
// html
wevalres.rows[w].feedcontent =
wevalres.rows[w].feedcontent != '' && wevalres.rows[w].feedcontent != null
? wevalres.rows[w].feedcontent.replace(/<[^>]+>/g, '')
: wevalres.rows[w].feedcontent
if (classWorkAnalysis.row.worktype == '常规作业') {
wevalres.rows[w].feedcontent = JSON.parse(wevalres.rows[w].feedcontent)
}
if (wevalres.rows[w].feedcontent != '') {
if (wevalres.rows[w].feedcontent == wevalres.rows[w].rightanswer) {
wevalres.rows[w].scoingStatus = true
// =
wevalres.rows[w].teacherRating = wevalres.rows[w].score
} else {
wevalres.rows[w].scoingStatus = false
}
} else {
wevalres.rows[w].scoingStatus = ''
}
//
}
// "" prop="feedcontent" width="200" align="center"></el-table-column>
// <el-table-column label="" prop="rightanswer"
// +
wevalres.rows[w].worktitle = wevalres.rows[w].worktitle.replace(/!@#\$%/g, '')
// feedcontent\r<br />
wevalres.rows[w].feedcontent = wevalres.rows[w].feedcontent.replace(/(?<!\\)\n/g, '<br />'); //\n\\n \\n
}
}
classWorkAnalysis.activeStudentQuizlist = wevalres.rows
//
isopen_dtwk_table.value = true
//
if (wevalres.rows.length > 0) {
handleClassWorkAnalysissScoreOpen(row)
} else {
ElMessage({
type: 'warning',
message: '未获取到答题信息,请稍后再看,或者联系管理员查看情况!'
})
}
})
.catch(() => {
console.log('获取答题情况失败')
ElMessage({
type: 'warning',
message: '未获取到答题信息!'
})
})
}
/** 3、教师批改后返回的方法*/
const onClassWorkScoreSubmit = () => {
console.log('批改后返回的方法')
loading_dt_table.value = true
isopen_dtwk_table.value = false
// 1table- classWorkAnalysis.classworkdata- classWorkAnalysis.activeStudentQuizlist
// -
classWorkAnalysis.classworkdata = []
classWorkAnalysis.activeStudentQuizlist = []
// 2
const rowid = localStorage.getItem('activeClassWorkRowId')
getClassWorkStudentList(rowid)
}
// ()
const handleClassWorkAnalysissScoreOpen = (row) => {
console.log(row, '所选点击的信息')
// list
classWorkAnalysisScore.studentQuizAllList = classWorkAnalysis.activeStudentQuizlist
// list
classWorkAnalysisScore.quizlist = classWorkAnalysis.quizlist
//
processList(classWorkAnalysisScore.quizlist)
//
classWorkAnalysisScore.maxheight = mainHeight.value - 100
//
nextTick(() => {
proxy.$refs.classWorkAnalysisScoreDialogRef.acceptParams(classWorkAnalysisScore)
})
}
//#endregion
/** 批阅:已交未交事件 */
const tableRadioChange = (e) => {
// ui
isopen_dtwk_table.value = false;
console.log(e,'??????')
console.log("学生列表:", classWorkAnalysis.classworkdata)
if(e=='1'){
tableRadio.list = classWorkAnalysis.classworkdata.filter(item => item.finishtimelength != '0')
tableRadio.value = '1';
tableRadio.num0 = classWorkAnalysis.classworkdata.length - tableRadio.list.length;
tableRadio.num1 = tableRadio.list.length;
}else if(e=='0'){
tableRadio.list = classWorkAnalysis.classworkdata.filter(item => item.finishtimelength == '0')
tableRadio.value = '0';
tableRadio.num0 = tableRadio.list.length;
tableRadio.num1 = classWorkAnalysis.classworkdata.length - tableRadio.list.length;
}
}
//
const escapeHtmlQuotes = (str) => {
// replace,
const regex1 = /\\+/g; //
let result = str.replace(regex1, '\\');
result = str.replace(/(?<!\\)\n/g, '<br />'); //\n\\n \\n
return result;
}
//#region
// -
const workHandle = (type) => {
// ui
isopen_dtwk_table.value = false;
classWorkAnalysis.view = type
const isClose = type != 'quizStats' && !! classWorkActiveData.timerId
const isOpen = type == 'quizStats' && !classWorkActiveData.timerId
//
if(type == 'quizStats') {
getWorkFeedList();
}
if (isClose) clearInterval(classWorkActiveData.timerId) //
if (isOpen) {
//
classWorkActiveData.timerId = setInterval(() => {
console.log('zdg: 定时执行')
getWorkFeedList()
}, 20 * 1000);
}
}
// -
const getWorkFeedList = async() =>{
const workid = classWorkAnalysis.row.id
const res = await listClassworkeval({workid, isFinish: 1, pageSize: 1000})
const getStudentid = (workdataid) => { // id
const classworkdata = (classWorkAnalysis.classworkdata||[]).find(o => o.id === workdataid)
return classworkdata ? classworkdata.studentid : ''
}
res.rows.forEach(o => { o.studentid = getStudentid(o.workdataid) })
classWorkActiveData.workFeedList = res.rows
}
//#endregion
//#regin
/*
author: yangws
time: 2024-8-06 16:35:33
function: 整体分析的处理
*/
const handleClassOverviewOpen = (type) =>{
// ui
isopen_dtwk_table.value = false;
classWorkAnalysis.view = type
const data = classWorkAnalysis.row
//
listClassworkdata({classworkid: data.id, pageSize: 100}).then((response) => {
if(response.code === 200){
response.rows.forEach(item => {
let rightAnswer = 0
let answers = 0
if(!item.classworkevallist) return
// 使
let replacedString = item.classworkevallist.replace(/""/g, "\"");
// , : "{\"id\":172907, \"rating\":0, \"teacherRating\":0, \"entpcourseworkid\":358520, \"feedcontent\":\"\", \"score\":4, \"rightanswer\":\"\"},{\"id\":172908, \"rating\":0, \"teacherRating\":0, \"entpcourseworkid\":358521, \"feedcontent\":\"\", \"score\":4, \"rightanswer\":\"\"},{\"id\":172909, \"rating\":0, \"teacherRating\":0, \"entpcourseworkid\":363096, \"feedcontent\":\"\", \"score\":4, \"rightanswer\":\"\"},{\"id\":172910, \"rating\":0, \"teacherRating\":0, \"entpcourseworkid\":363098, \"feedcontent\":\"<bdo class=\"mathjye-underpoint2\"></bdo>\", \"score\":4, \"rightanswer\":\"<bdo class=\"mathjye-underpoint2\"></bdo>\"},{\"id\":172911, \"rating\":0, \"teacherRating\":0, \"entpcourseworkid\":363100, \"feedcontent\":\"<bdo class=\"mathjye-underpoint2\"></bdo>\", \"score\":4, \"rightanswer\":\"<bdo class=\"mathjye-underpoint2\"></bdo>\"}"
replacedString = escapeHtmlQuotes(item.classworkevallist);
let allTopic
try{
allTopic = JSON.parse(`[${item.classworkevallist}]`)
}catch{
allTopic = JSON.parse(`[${replacedString}]`)
}
if(item.classworkevallist != ''){
allTopic.forEach(itemTopic => {
if(itemTopic.feedcontent != ''){
answers ++
//
if(itemTopic.feedcontent === itemTopic.rightanswer){
rightAnswer ++
}
}
})
rightAnswer > 0?item.scoingRate = (rightAnswer/answers * 100).toFixed(0):item.scoingRate = ''
}else{
item.scoingRate = ''
}
//
const point = allTopic.reduce((acc, cur) => {
if(cur.rating !== 0){
return acc + cur.teacherRating;
}
},0)
// item.chapter = this.courseObj.evalid
item.point = point || 0
item.rating = allTopic[0].rating
})
overviewData.value = [...response.rows]
}
})
}
//#endregion
const onBeforeClose = () =>{
console.log('非正常关闭dialog?esc、dialog外部区域')
closeDialog()
}
const closeDialog = () => {
classWorkAnalysis.open = false
emit('cle-click')
}
onMounted(() => {
// const data = JSON.parse(localStorage.getItem('teachClassWorkItem'));
const data = sessionStore.get('teachClassWorkItem');
// console.log(data,'????????????????????' )
if(data){
openDialog(data)
}
})
watch(classWorkAnalysis, (newVal, oldVal) => {
if(newVal.view != 'quizStats'){
console.log('关闭zdg: 定时执行')
clearInterval(classWorkActiveData.timerId) //
}
})
onUnmounted(() => {
clearInterval(classWorkActiveData.timerId) //
})
// defineExpose({
// })
</script>
<style src="@/assets/styles/JYStyle.css"></style>
<style scoped lang="scss">
.teachClassTask{
height: 100%;
display: flex;
flex-direction: column;
.teachClassTask_header{
flex: 0 0 auto;
}
.teachClassTask_content{
flex: 1;
height: 100%;
overflow: hidden;
display: flex;
justify-content: center;
overflow: hidden;
.clwk_dialog_view {
display: flex;
flex-direction: row;
justify-content: flex-start;
overflow: hidden;
}
.view_table {
flex: 0 0 auto;
height: 100%;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
}
.view_teachrting {
flex: 1;
height: 100%;
/*overflow-y: auto; */
overflow: hidden;
.classwork-score{
// overflow-y: auto;
height: 100%;
}
}
}
}
// .clwk_dialog {
// }
// .clwk_dialog {
// display: flex;
// justify-content: center;
// overflow: hidden;
// }
// .clwk_dialog .el-dialog {
// margin: 0 auto !important;
// height: 85%!important;
// overflow: hidden;
// }
// .clwk_dialog .el-dialog__header {
// /* position: absolute;
// top: 0;
// left: 0; */
// width: 100%!important;
// }
// .clwk_dialog .el-dialog__body {
// position: absolute;
// left: 0;
// top: 15px;
// bottom: 1px;
// right:0;
// padding:5px;
// z-index:1;
// display: flex;
// flex-direction: column;
// overflow: hidden;
// /* overflow:hidden;
// overflow-y: auto; */
// }
// .clwk_dialog .el-dialog__footer{
// position: absolute;
// bottom: 10px;
// right: 10px;
// }
// .clwk_dialog .classwork-score{
// overflow-y: auto;
// }
</style>
<style scoped>
/* .clwk_dialog {
display: flex;
justify-content: center;
overflow: hidden;
}
.clwk_dialog .el-dialog {
margin: 0 auto !important;
height: 85%!important;
overflow: hidden;
}
.clwk_dialog .el-dialog__header {
/* position: absolute;
top: 0;
left: 0;
width: 100%!important;
}
.clwk_dialog .el-dialog__body {
position: absolute;
left: 0;
top: 15px;
bottom: 1px;
right:0;
padding:5px;
z-index:1;
display: flex;
flex-direction: column;
overflow: hidden;
/* overflow:hidden;
overflow-y: auto;
}
.clwk_dialog .el-dialog__footer{
position: absolute;
bottom: 10px;
right: 10px;
}
.clwk_dialog .classwork-score{
overflow-y: auto;
} */
</style>

View File

@ -28,20 +28,21 @@
</ul>
</el-scrollbar>
</div>
<item-dialog ref="itemDialogRef" @cle-click="closeDialog"></item-dialog>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { ref, onMounted, watch } from 'vue'
import useUserStore from '@/store/modules/user'
import { homeworklist } from '@/api/teaching/classwork'
import { getCurrentTime, getTomorrow } from '@/utils/date'
import ItemDialog from '@/views/classTask/container/item-dialog.vue'
import {sessionStore, createWindow} from '@/utils/tool'
import { useToolState } from '@/store/modules/tool'
import {throttle,debounce } from '@/utils/comm'
const user = useUserStore().user
const toolState = useToolState();
const loading = ref(false)
const homeworkList = ref([])
const itemDialogRef = ref(null)
//
const getHomework = async () => {
@ -67,15 +68,18 @@ const getHomework = async () => {
loading.value = false
}
}
const debounceOpenWin = debounce(() => {
toolState.isTaskWin=true; //
createWindow('open-taskwin',{url:'/teachClassTask'}); //
}, 1000);
//
const onClickItem = (item) => {
console.log('开启弹窗')
itemDialogRef.value.openDialog(item)
}
//
const closeDialog = () => {
console.log('关闭弹窗,查询一下作业数据,更新界面')
getHomework()
console.log('防抖开启弹窗')
sessionStore.set('teachClassWorkItem', item); // item
debounceOpenWin();
}
const tagType = (time) => {
@ -86,6 +90,16 @@ const tagType = (time) => {
onMounted(() => {
getHomework()
})
watch(
() => [toolState.isTaskWin],
() => {
console.log('=监听到批改窗口是否关闭了===', toolState.isTaskWin)
if(!toolState.isTaskWin){
getHomework()//
}
}
)
</script>
<style lang="scss" scoped>
@ -121,6 +135,7 @@ onMounted(() => {
border-radius: 5px;
margin-bottom: 10px;
padding: 10px;
cursor: pointer;
.class-left {
flex-direction: column;

View File

@ -9,7 +9,16 @@
<div class="item-content">
<ul class="flex con-ul">
<li v-for="menu in item.list" :key="menu.id" @click="clickMenu(menu)" class="flex item-menu" :class="menu.disabled ? 'menu-disabled' : ''">
<i class="iconfont" :class="menu.icon"></i>
<div class="icon-box">
<template v-if="menu.disabled">
<i class="iconfont" :class="menu.icon"></i>
</template>
<template v-else>
<svg class="icon iconfont icon-svg" aria-hidden="true">
<use :xlink:href="menu.icon"></use>
</svg>
</template>
</div>
<span>{{ menu.name }}</span>
</li>
</ul>
@ -60,19 +69,19 @@ const menuList = [{
list: [
{
name: '课标分析',
icon: 'icon-kecheng',
icon: '#icon-kebiao',
path: '/standardanalysis?',
id: '1-1'
},
{
name: '教材分析',
icon: 'icon-jiaocaixuanze',
icon: '#icon-jiaocaixuanze',
path: '/textbookAnalysis',
id: '1-2'
},
{
name: '考试分析',
icon: 'icon-kaoshi',
icon: '#icon-kaoshi',
path: '/examReport',
id: '1-3'
},
@ -84,13 +93,13 @@ const menuList = [{
},
{
name: '教学实践',
icon: 'icon-jiaoxuefenxi',
icon: '#icon-jiaoxueshijian',
path: '/prepare',
id: '1-5'
},
{
name: '教学反思',
icon: 'icon-jiaoxuefansi',
icon: 'icon-a-1_jiaoxuefansi',
disabled: true,
id: '1-6'
},
@ -103,7 +112,7 @@ const menuList = [{
list: [
{
name: '作业设计',
icon: 'icon-jiaoxuefansi',
icon: '#icon-zuoyesheji',
isOuter: true,
path: '/teaching/classtaskassign?titleName=作业布置&openDialog=newClassTask',
// path: '/newClassTask',
@ -111,7 +120,7 @@ const menuList = [{
},
{
name: '作业布置',
icon: 'icon-xiezuo1',
icon: '#icon-zuoyebuzhi',
isOuter: true,
path: '/teaching/classtaskassign?titleName=作业布置',
// path: '/classTaskAssign',
@ -119,7 +128,7 @@ const menuList = [{
},
{
name: '作业批改',
icon: 'icon-pigai',
icon: '#icon-zuoyepigai',
path: '/classTask',
id: '2-3'
},
@ -138,25 +147,25 @@ const menuList = [{
list: [
{
name: '教学计划',
icon: 'icon-jiaoxuejihua',
icon: 'icon-jihua',
disabled: true,
id: '3-1'
},
{
name: '教学组织',
icon: 'icon-organization-framework-line',
icon: 'icon-zuzhi',
disabled: true,
id: '3-2'
},
{
name: '教学质量',
icon: 'icon-jiaoxuezhiliangfenxi',
icon: 'icon-zhiliang',
disabled: true,
id: '3-3'
},
{
name: '教学反馈',
icon: 'icon-fankui',
icon: 'icon-yijianfankui',
disabled: true,
id: '3-4'
},
@ -174,10 +183,10 @@ const clickMenu = ({isOuter, path, disabled, id}) =>{
// ID
const { id, rootid } = sessionStore.get('subject.curNode')
if(fullPath.indexOf('?') == -1){
fullPath += `?unitId=${id}&bookeId=${rootid}`
fullPath += `?unitId=${id}&bookId=${rootid}`
}
else{
fullPath += `&unitId=${id}&bookeId=${rootid}`
fullPath += `&unitId=${id}&bookId=${rootid}`
}
}
fullPath = fullPath.replaceAll('//', '/')
@ -276,20 +285,37 @@ onMounted(async ()=>{
padding: 10px 0;
.con-ul{
justify-content: space-around;
.item-menu{
cursor: pointer;
flex-direction: column;
font-size: 14px;
align-items: center;
.icon-box{
width: 100%;
height: 45px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 5px;
}
.iconfont{
font-size: 28px;
color: #707070;
// font-weight: bold;
}
.icon-svg{
height: 42px;
font-weight: bold;
}
&:hover{
color: #409EFF;
// color: #409EFF;
.iconfont{
color: #409EFF;
}
.icon-box{
background-color: #F2F2F2;
}
}
}
.menu-disabled{
@ -303,6 +329,9 @@ onMounted(async ()=>{
.iconfont{
color: #bfbfbf;
}
.icon-box{
background-color: #fff;
}
}
}
}
@ -324,7 +353,9 @@ onMounted(async ()=>{
align-items: center;
}
.item-content{
border-radius: 5px;
background: #fff;
box-sizing: border-box;
flex: 1;
.chart-box{
height: 100%;

View File

@ -58,8 +58,8 @@
v-else-if="curTask.viewkey=='考点分析' "
/>
<examMocks v-else
<examMocks
v-else
/>
</div>
</div>
@ -75,12 +75,13 @@ import { ArrowRight } from '@element-plus/icons-vue'
import useResoureStore from '@/views/resource/store'
import ChooseTextbook from '@/components/choose-textbook/index.vue'
import {listEntpcoursework, listEntpcourseworkNew} from '@/api/education/entpCourseWork'
import {processExamQuestion} from '@/utils/examQuestion/tool'
import { processList } from '@/hooks/useProcessList'
import { JYApiListCT} from "@/utils/examQuestion/jyeoo"
import examReview from './container/examReview.vue'
import pointAnalysis from './container/pointAnalysis.vue'
import examMocks from './container/examMocks.vue'
import { ElMessage } from 'element-plus'
const {proxy} = getCurrentInstance();
const sourceStore = useResoureStore();
@ -106,6 +107,19 @@ const listWorkType = ref([{
value: 0,
}]);
const getCourseWorkList = async (params) => {
const res = await listEntpcourseworkNew(params);
if(res.data == null) {
listExamQuestion.value = [];
// queryParams.total = 0
return;
}
listExamQuestion.value = res.data;
// queryParams.total = res.total;
//
processList(listExamQuestion.value);
}
/**
* @desc: 选中单元章节后的回调, 获取单元章节信息
* @return: {*}
@ -134,6 +148,15 @@ const getData = async (data) => {
// const res = await listEntpcoursework(params);
// listExamQuestion.value = res.rows;
// id,
// : id[/evaluation/bind]
if (curNode.value.bookId == null || curNode.value.bookId == '' || curNode.value.bookId == '0') {
listExamQuestion.value = [];
loading.value = false;
ElMessage.error("当前单元/章节下无试题");
return;
}
// +()
const params = {
eid: curNode.value.id,
@ -144,17 +167,7 @@ const getData = async (data) => {
edustage: curNode.value.edustage,
sectionName: curNode.value.itemtitle,
}
const res = await listEntpcourseworkNew(params);
if(res.data == null) {
listExamQuestion.value = [];
// queryParams.total = 0
loading.value = false;
return;
}
listExamQuestion.value = res.data;
// queryParams.total = res.total;
//
processExamQuestion(listExamQuestion.value);
await getCourseWorkList(params);
loading.value = false;
}
@ -202,6 +215,13 @@ const queryExamQuestionByParams = async () => {
// const res = await listEntpcoursework(params);
// listExamQuestion.value = res.rows;
if (curNode.value.bookId == null || curNode.value.bookId == '' || curNode.value.bookId == '0') {
listExamQuestion.value = [];
loading.value = false;
ElMessage.error("当前单元/章节下无试题");
return;
}
// +()
const params = {
eid: curNode.value.id,
@ -212,17 +232,7 @@ const queryExamQuestionByParams = async () => {
edustage: curNode.value.edustage,
sectionName: curNode.value.itemtitle,
}
const res = await listEntpcourseworkNew(params);
if(res.data == null) {
listExamQuestion.value = [];
// queryParams.total = 0
loading.value = false;
return;
}
listExamQuestion.value = res.data;
// queryParams.total = res.total;
//
processExamQuestion(listExamQuestion.value);
await getCourseWorkList(params);
loading.value = false;
}

View File

@ -0,0 +1,35 @@
<template>
<PDF :url="pdfUrl" :isWin="true" v-if="pdfUrl" />
</template>
<script setup>
import { onMounted, ref } from 'vue'
import PDF from '@/components/PdfJs/index.vue'
import { useRoute } from 'vue-router';
import { getStaticUrl } from '@/utils/tool'
const route = useRoute();
const pdfUrl = ref('');
const loadPdfAnimation = (path) => {
console.log('书本地址====',path);
const timer = setTimeout(() => {
pdfUrl.value = path
clearTimeout(timer);
},2000)
}
onMounted(() => {
const bookpath = localStorage.getItem('PDF-LOCAL-PATH')
// const filepath = import.meta.env.VITE_APP_RES_FILE_PATH + bookpath
// const isDev = process.env.NODE_ENV == 'development'
// if (isDev)
// pdfUrl.value = getStaticUrl(bookpath, 'user', 'selfFile', true) //
// else
// pdfUrl.value = getStaticUrl(bookpath, 'user', 'selfFile', true) //线
// const newpath = getStaticUrl(bookpath, 'user', 'selfFile', true)
loadPdfAnimation(bookpath)
// pdfUrl.value = filepath
// console.log('',newpath);
})
</script>
<style>
</style>

View File

@ -44,7 +44,6 @@
v-model="ruleForm.address"
:options="regionData"
@change="handleChange"
:props="{checkStrictly: true}"
/>
</el-form-item>
<el-form-item label="学校" prop="school" v-if="activeIndex==2">
@ -233,23 +232,24 @@ const OpenModel = v =>{
//
const handleClose = () => {
var restValue={
name: '',
idNumber:'',
phoneNumber: '',
Code:'',
password:'',
confirmPassword:'',
class:[],
discipline:[],
school:[],
}
name: '',
idNumber:'',
phoneNumber: '',
Code:'',
password:'',
confirmPassword:'',
class:[],
discipline:[],
school:[100,255,279],
address:["50","5001","500101"]
}
Object.assign(ruleForm, restValue);
schoolSubject.value=[]
gradeTree.value=[]
if (ruleFormRef.value) ruleFormRef.value.resetFields()
removeToken();
activeIndex.value=1
dialogVisible.value=false
activeIndex.value=1
}
const nextStep = (formEl) => {
@ -346,13 +346,14 @@ const submitForm = async (formEl) => {
confirmPassword:'',
class:[],
discipline:[],
school:[],
school:[100,255,279],
address:["50","5001","500101"]
}
schoolSubject.value=[]
gradeTree.value=[]
Object.assign(ruleForm, restValue);
dialogVisible.value=false
activeIndex.value=1
dialogVisible.value=false
}else{
ElMessage.error(res.msg)
}
@ -495,7 +496,7 @@ const gradeName = (key) =>{
}
onMounted(()=>{
//
ruleForm.address = ['50']
ruleForm.address = ["50","5001","500101"]
//
ruleForm.school = [100,255,279]
})

View File

@ -2,7 +2,7 @@
<div class="login-container">
<div class="box-item desc">
<div class="welcome">
<p>欢迎登录 {{homeTitle}}</p>
<p>欢迎登录 {{ homeTitle }}</p>
</div>
<img class="welcome-img" :src="leftBg2" />
</div>
@ -14,46 +14,28 @@
<el-input v-model.trim="loginForm.username" placeholder="请输入用户名" />
</el-form-item>
<el-form-item prop="password" style="margin-bottom: 15px">
<el-input
v-model="loginForm.password"
autocomplete="on"
type="password"
placeholder="请输入密码"
/>
<el-input v-model="loginForm.password" autocomplete="on" type="password" placeholder="请输入密码" />
</el-form-item>
<div class="flex mb-5">
<el-checkbox v-model="loginForm.rememberMe" >记住密码</el-checkbox>
<!-- <el-checkbox >阅读并同意xxx</el-checkbox> -->
<el-checkbox v-model="loginForm.rememberMe">记住密码</el-checkbox>
<!-- <el-checkbox >阅读并同意xxx</el-checkbox> -->
</div>
<el-form-item>
<el-button :loading="btnLoading" class="btn" type="primary" @click="submitForm(formRef)"
>登录</el-button
>
<el-button :loading="btnLoading" class="btn" type="primary" @click="submitForm(formRef)">登录</el-button>
</el-form-item>
<div class="flex mb-4" style="display: flex;justify-content: center;color: #ccc;cursor: pointer;">
<a class="hover:text-sky-500" style="margin-right: 10px;" @click="RegisterModel(1)">注册账号</a>
|
<a class="hover:text-sky-500" style="margin-left: 10px;" @click="RegisterModel(2)">忘记密码</a>
<a class="hover:text-sky-500" style="margin-right: 10px;" @click="RegisterModel(1)">注册账号</a>
|
<a class="hover:text-sky-500" style="margin-left: 10px;" @click="RegisterModel(2)">忘记密码</a>
</div>
</el-form>
</div>
</div>
<el-dialog
v-model="showDownLoading"
width="500"
:show-close="false"
:close-on-click-modal="false"
:close-on-press-escape="false"
align-center
>
<el-progress
:text-inside="true"
:stroke-width="22"
:percentage="downloadProp"
:show-text="false"
status="success"
/>
<el-dialog v-model="showDownLoading" width="500" :show-close="false" :close-on-click-modal="false"
:close-on-press-escape="false" align-center>
<el-progress :text-inside="true" :stroke-width="22" :percentage="downloadProp" :show-text="false"
status="success" />
</el-dialog>
<!--选择学科-->
<SelectSubject v-model="isSubject" :login-data="loginForm" />
@ -69,6 +51,7 @@ import leftBg2 from '@/assets/images/login/left-bg2.png'
import WindowTools from '@/components/window-tools/index.vue'
import SelectSubject from '@/components/select-subject/index.vue'
import Register from './components/Register.vue'
import { sessionStore } from '@/utils/store'
const { session } = require('@electron/remote')
const downloadProp = ref(0)
@ -99,7 +82,7 @@ ipcRenderer.on('update-app-progress', (e, prop) => {
showDownLoading.value = prop !== 100
})
//
const RegisterModel = type =>{
const RegisterModel = type => {
RegModel.value.OpenModel(type)
}
//
@ -168,6 +151,13 @@ const setCookie = (name, value) => {
onMounted(() => {
localStorage.clear()
sessionStore.set('subject', {
bookList: null,
curBook: null,
curNode: null,
defaultExpandedKeys: [],
subjectTree: []
})
getCookie()
})
</script>
@ -179,6 +169,7 @@ onMounted(() => {
align-items: center;
justify-content: center;
-webkit-app-region: drag;
.box-item {
width: 444px;
height: 520px;

View File

@ -52,6 +52,7 @@
<div :title="value" v-if="!!value">
<vue-qr :text="value" :size="200" :margin="10" colorDark="green" colorLight="white" :logoSrc="getStaticUrl('/img/logo.png')" :logoScale="0.2" :dotScale="0.7"></vue-qr>
</div>
<el-button type="primary" :icon="Refresh" round title="刷新" @click="getQrUrl()" />
<!-- <el-button type="warning" :loading="dt.loadingDel" @click="removeClasscourse()">删除记录</el-button>-->
</template>
<!-- 手机登录 -->
@ -80,19 +81,22 @@
<script setup>
//
import { onMounted, reactive, ref, watchEffect, watch, nextTick } from 'vue' // vue
import { Refresh } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus' // ui:
import vueQr from 'vue-qr/src/packages/vue-qr.vue' // :
import imChat from '@/views/tool/components/imChat.vue' // im-chat-
import MsgEnum from '@/plugins/imChat/msgEnum' // -(nuem)
import * as commUtil from '@/utils/comm' // -
import { toLinkWeb, getStaticUrl } from '@/utils/tool'
import { toLinkWeb, getStaticUrl } from '@/utils/tool' // -
import * as Http_ClassManage from '@/api/classManage' // api
import * as Http_Classcourse from '@/api/teaching/classcourse' // api
import * as Http_Entpcoursefile from '@/api/education/entpcoursefile' // api
import * as Http_Entpcoursefile from '@/api/education/entpcoursefile' // api
import * as Http_api from '@/api/apiService' // api
import useUserStore from "@/store/modules/user" // user
import CryptoJS from 'crypto-js'
const baseUrl = import.meta.env.VITE_APP_BUILD_BASE_PATH
let baseUrl = import.meta.env.VITE_APP_BUILD_BASE_PATH
const userStore = useUserStore()
const visible = ref(false) //
const myClassActive = ref({}) // APT
@ -189,9 +193,9 @@ const getClassList = async () => {
})
if (res.code == 200) {
listData.classList = (res.rows || []).map(o => {
if(!!o.classstudentlist) { //
o.classstudentlist = JSON.parse('[' + o.classstudentlist + ']')
}
// if(!!o.classstudentlist) { //
// o.classstudentlist = JSON.parse('[' + o.classstudentlist + ']')
// }
return o
});
//
@ -277,13 +281,37 @@ const classTeachingStart = async () => {
}
}
//
const getQrUrl = () => {
const getQrUrl = async() => {
const { classcourseid:id } = teacherForm.form
const { userName } = userStore.user
const { userName, userId } = userStore.user
if (!id||!userName) return
const qrCodeUrl = `wxlogin?username=${userName}&nextaction=classteaching&id=${id}`
// (wx)
// const qrCodeUrl = `wxlogin?username=${userName}&nextaction=classteaching&id=${id}`
// teacherForm.form.qrUrl = baseUrl + qrCodeUrl
// baseUrl = 'https://localhost:7860'
// token
let url = `teaching/classteachingonmobile?classcourseid=${id}` // -
let qrCodeUrl = '' // -
try {
// url
const res = await Http_api.toLink.setLink('/' + url) // -
if (res.code == 200) {
const redisKey = res.data
const base64Key = CryptoJS.enc.Utf8.parse(redisKey).toString(CryptoJS.enc.Base64) // base64
const enStrUrl = encodeURIComponent(base64Key) // url
qrCodeUrl = `${url}&_server=${enStrUrl}`
teacherForm.form.qrUrl = baseUrl + qrCodeUrl
}
} catch (error) { // , token
const jsonStr = JSON.stringify({ url, token: userStore.token }) // json{url, token}
const key = `Ax19i14Ga6qEDOkGTo` // AES-key
const enStr = CryptoJS.AES.encrypt(jsonStr, key).toString() // AES-
const enStrUrl = encodeURIComponent(enStr) // url
qrCodeUrl = `${url}&?_web=${enStrUrl}`
}
teacherForm.form.qrUrl = baseUrl + qrCodeUrl
}
//
// ================== =======================
// im-chat: {type, data}

View File

@ -86,10 +86,16 @@
<span>布置</span>
</el-button>
</div>
<div class="item-popover-item">
<el-button text @click="reSetHomeWork(item, index)">
<i class="iconfont icon-bianji"></i>
<span>编辑</span>
</el-button>
</div>
<div class="item-popover-item">
<el-button text @click="deleteHomework(item)">
<i class="iconfont icon-shanchu"></i>
<span>删除</span>
<span style="color: red;">删除</span>
</el-button>
</div>
</template>
@ -110,7 +116,7 @@
<div class="item-popover-item" v-if="userInfo.userId === Number(item.createUserId)">
<el-button text @click="deleteTalk(item)">
<i class="iconfont icon-shanchu"></i>
<span>删除</span>
<span style="color: red;">删除</span>
</el-button>
</div>
<div class="item-popover-item">
@ -168,7 +174,7 @@ export default {
}
}
},
emits: { 'on-move': null, 'on-delete': null, 'on-set': null, 'on-delhomework': null,'on-filearg': null },
emits: { 'on-move': null, 'on-delete': null, 'on-set': null, 'on-reSet': null, 'on-delhomework': null,'on-filearg': null },
data() {
return {
listenList: [],
@ -275,6 +281,10 @@ export default {
setHomeWork(item) {
this.$emit('on-set', item)
},
//
reSetHomeWork(item) {
this.$emit('on-reSet', item)
},
//
deleteHomework(item){
this.$emit('on-delhomework', item)

View File

@ -76,7 +76,7 @@
<div class="item-popover-item">
<el-button text @click="deleteTalk(item)">
<i class="iconfont icon-shanchu"></i>
<span>删除</span>
<span style="color: red;">删除</span>
</el-button>
</div>
</template>
@ -102,6 +102,11 @@ import { deleteSmarttalk, updateSmarttalk, getPrepareById } from '@/api/file'
import useUserStore from '@/store/modules/user'
import outLink from '@/utils/linkConfig'
import { sessionStore } from '@/utils/store'
import { listClasscourseNew } from '@/api/teaching/classcourse'
import { endClass, getSelfReserv } from '@/api/classManage'
import { listEntpcourse } from '@/api/teaching/classwork'
import { createWindow } from '@/utils/tool'
import { defineExpose } from 'vue'
const { ipcRenderer } = window.electron || {}
export default {
@ -131,6 +136,7 @@ export default {
default: ''
}
},
expose: ['openFileWin'],
emits: { 'on-start-class': null, 'on-delete': null, 'on-set': null, 'on-delhomework': null,'on-filearg': null },
data() {
return {
@ -142,8 +148,87 @@ export default {
this.userInfo = useUserStore().user
},
methods: {
getOpenCourse() {
return Promise.all([listClasscourseNew({teacherid: this.userInfo.userId,status:"open",evalid: this.curNode.id,pageSize:1000}), getSelfReserv({ex2:this.curNode.id})]).then(([res1,res2])=>{
let list2 = res1.rows || []
let list = res2.data || []
let one = list.find(item1 => {
if (item1.status === "上课中") {
return true
}
})
if (one) {
return one
}
if (list2.length>0) {
one = list2[0]
}
return one
})
},
clickStartClass(item) {
this.$emit('on-start-class', item)
this.getOpenCourse().then(res=>{
if(!res){
this.$emit('on-start-class', item)
}else{
ElMessageBox.alert('<strong>上次课程尚未结束,是否继续上课?</strong>', '', {
// if you want to disable its autofocus
// autofocus: false,
confirmButtonText: '下课  ',
cancelButtonText: '继续上课',
showCancelButton: true,
showClose: false,
closeOnClickModal: true,
distinguishCancelAndClose: true,
dangerouslyUseHTMLString: true,
cancelButtonClass: "el-button--primary",
confirmButtonClass: "el-button--danger",
center: true,
beforeClose: (action, instance, done) => {
if (action === 'confirm'){
//
if (res.bookImg) {
//PPT
endClass(res.id).then((res1) => {
if (res1.data === true) {
ElMessage({
message: '下课成功',
type: 'success'
})
res.status = '已结束'
done()
}
})
}else {
//APT
}
}
if (action === 'cancel'){
//
if (res.bookImg) {
//PPT
listEntpcourse({
evalid: res.ex2,
edituserid: useUserStore().user.userId,
pageSize: 500
}).then(async res1=>{
if (res1.rows[0].id) {
createWindow('tool-sphere', { url: '/tool/sphere?entpcourseid=' + res1.rows[0].id + "&reservId=" + res.id })
done()
}
})
}else {
//APT
}
}
if (action === 'close') {
done()
}
},
})
}
})
// this.$emit('on-start-class', item)
},
editTalk(item) {
ElMessageBox.prompt('请输入新的标签', '添加标签', {

View File

@ -18,6 +18,7 @@
<kj-list-item
v-for="(item, index) in currentKJFileList"
:key="index"
:ref="'kjItemRef'+item.id"
:item="item"
:index="index"
:curNode="currentNode"
@ -28,42 +29,11 @@
</div>
</el-tab-pane>
<el-tab-pane label="教学实录" name="教学实录" class="prepare-center-jxsl">
<class-reserv></class-reserv>
<class-reserv v-if="activeAptTab==='教学实录'" :curNode="currentNode"></class-reserv>
</el-tab-pane>
</el-tabs>
</div>
<div class="page-right">
<!-- <div class="header-top flex">
<div class="textbook-img" @click="navtoPdf">
<el-image style="width: 80px; height: 110px" :src="curBookImg" />
<el-progress
v-if="downloadNum > 0 && downloadNum < 100"
style="position: absolute; left: 0; z-index: 999"
type="circle"
:percentage="downloadNum"
/>
</div>
<div class="top-item">
<el-button class="btn" @click="handleOutLink('standard')">课标研读</el-button>
<el-button class="btn" @click="openReserv">预约课程</el-button>
<el-button class="btn" @click="handleOutLink('gk')">高考研读</el-button>
<el-button class="btn" @click="handleOutLink('aiModel')">教学大模型</el-button>
</div>
<el-button
:type="!curClassReserv.id ? 'info' : 'primary'"
:disabled="!curClassReserv.id || toolStore.isToolWin"
class="to-class-btn"
@click="openLesson"
>
<label
><i class="iconfont icon-lingdang"></i
>{{ curClassReserv.status == '上课中' ? '上课中' : '上课' }}</label
>
<label>{{ curClassReserv.classDay }} {{ getWeekday1(curClassReserv.classDay) }}</label>
<label>{{ curClassReserv.startTime }}-{{ curClassReserv.endTime }}</label>
</el-button>
<div class="top-zoom-style"></div>
</div>-->
<div style="padding: 0 20px;height: 100%;">
<el-tabs v-model="activeTab" class="prepare-tabs" >
<el-tab-pane label="素材" name="素材">
@ -116,22 +86,20 @@
</el-checkbox-group>
</el-tab-pane>
<el-tab-pane label="作业" name="作业">
<!-- <div class="prepare-body-header">
<div class="prepare-body-header">
<div>
<label style="font-size: 15px">{{ currentWorkList.length }}个作业</label>&nbsp;
<el-button size="small" @click="handleOutLink('feedback')">作业反馈</el-button>
<el-button size="small" @click="handleOutLink('homeWork')">布置作业</el-button>
<el-button size="small" @click="handleOutLink('homeWork')">作业设计</el-button>
</div>
</div>-->
</div>
<div class="prepare-work-wrap">
<file-list-item
v-for="(item, index) in currentWorkList"
:key="index"
:item="item"
:index="index"
@on-move="onMoveSingleFile"
@on-delete="deleteTalk"
@on-set="openSet"
@on-reSet="openReSet"
@on-delhomework="delhomework"
>
</file-list-item>
@ -305,29 +273,29 @@ export default {
// },
methods: {
startClass(item) {
// console.log(item, sessionStore)
// ()
const id = sessionStore.has('activeClass.id') ? sessionStore.get('activeClass.id') : null
if (id && id == item.id) return ElMessage.warning('当前正在上课,请勿重复操作')
// -store
sessionStore.set('activeClass', item)
this.activeClass = item
if(item.fileFlag === '课件') {
this.openReserv()
}
if(item.fileFlag === 'apt') {
this.$refs.calssRef.open(item.fileId)
}
// -store
sessionStore.set('activeClass', item)
this.activeClass = item
},
closeChange() { // -
console.log('关闭上课弹窗')
this.activeClass = null
// this.activeClass = null
sessionStore.delete('activeClass')
},
initReserv(id) {
getClassInfo(id).then((res) => {
this.curClassReserv = res.data
this.openLesson(res.data.id);
this.$refs['kjItemRef'+this.activeClass.id][0].openFileWin(this.activeClass);
})
},
getBookPathFromServer(path) {
@ -370,6 +338,9 @@ export default {
createFile() {
creatPPT(this.currentNode.itemtitle + '.pptx', this.uploadData).then((res) => {
this.currentFileList.unshift(res.resData)
setTimeout(()=>{
this.$refs['kjItemRef'+res.resData.id][0].openFileWin(res.resData);
},500)
})
},
createAptFile() {
@ -451,6 +422,9 @@ export default {
fileShowName: this.currentNode.itemtitle + '.apt'
}).then((res) => {
this.currentFileList.unshift(res.resData)
setTimeout(()=>{
this.$refs['kjItemRef'+res.resData.id][0].openFileWin(res.resData);
},500)
})
})
})
@ -599,6 +573,7 @@ export default {
openReserv() {
this.$refs['reservDialog'].openDialog()
},
//
handleOutLink(key) {
if (key == 'homeWork') {
@ -612,12 +587,15 @@ export default {
let unitId = this.uploadData.levelSecondId
? this.uploadData.levelSecondId
: this.uploadData.levelFirstId
if (key == 'gk') {
fullPath += `?unitId=${unitId}`
} else {
fullPath += `&unitId=${unitId}`
let bookId = this.uploadData.textbookId;
if(fullPath.indexOf('?') == -1){
fullPath += `?unitId=${unitId}&bookId=${bookId}&openDialog=newClassTask`
}
else{
fullPath += `&unitId=${unitId}&bookId=${bookId}&openDialog=newClassTask`
}
}
//
ipcRenderer.send('openWindow', {
key,
@ -635,6 +613,27 @@ export default {
this.row = row
this.setDialog = true
},
//
openReSet(row) {
//
this.isOpenHomework = true;
// key linkConfig.js
let configObj = outLink()['homeWork']
let fullPath = configObj.fullPath
let unitId = this.uploadData.levelSecondId
? this.uploadData.levelSecondId
: this.uploadData.levelFirstId
let bookId = this.uploadData.textbookId;
fullPath += `&unitId=${unitId}&bookId=${bookId}&courseWorkId=${row.id}`
//
ipcRenderer.send('openWindow', {
key: 'homeWork',
fullPath: fullPath,
cookieData: { ...configObj.data }
})
},
//
delhomework(item) {
this.isLoading = true
@ -714,7 +713,10 @@ export default {
.page-center-wrap{
flex: 1;
height: 100%;
padding: 0 10px;
padding: 0 5px;
margin: 0 5px;
border-radius: 10px;
background-color: white;
.prepare-center-jxkj{
height: 100%;
display: flex;
@ -874,6 +876,7 @@ export default {
width: 100%;
flex: 1;
overflow: auto;
margin-top: 10px;
}
.prepare-body-main {
flex: 1;

View File

@ -57,6 +57,13 @@
</div>
<div class="right-align">{{ state.user.createTime }}</div>
</li>
<li class="list-group-item">
<div class="left-align">
<Paperclip class="Calendar"/>
<span>版本编号</span>
</div>
<div class="right-align">v{{version}}</div>
</li>
</ul>
</div>
</el-card>
@ -83,13 +90,15 @@
</template>
<script setup name="Profile">
import { UserFilled, Cellphone, Message, Suitcase, Avatar, Calendar } from '@element-plus/icons-vue'
import { UserFilled, Cellphone, Message, Suitcase, Avatar, Calendar, Paperclip } from '@element-plus/icons-vue'
import { ref, reactive } from 'vue'
import userAvatar from './userAvatar.vue'
import userInfo from './userInfo.vue'
import resetPwd from './resetPwd.vue'
import { getUserProfile } from '@/api/system/user'
import pkc from "../../../../../package.json"
const version = ref(pkc.version)
const activeTab = ref('userinfo')
const state = reactive({
user: {},

View File

@ -61,7 +61,7 @@
@click="delRow(item)"
>
<i class="iconfont icon-shanchu"></i>
<span>删除</span>
<span style="color: red;">删除</span>
</div>
<div class="item-popover-item" @click="downloadFile(item)">
<i class="iconfont icon-xiazai"></i>

View File

@ -8,25 +8,31 @@
<h3 class="title">{{ lesson }}</h3>
<div class="grade">{{ usertore.edusubject }}</div>
</div>
<i class="iconfont icon-xiangyou" @click="showLeft = !showLeft"></i>
<!-- <i class="iconfont icon-xiangyou" @click="showLeft = !showLeft"></i> -->
</div>
<div class="homework-list" v-loading="loading">
<el-scrollbar height="360px">
<ul>
<!--资源-->
<li class="item flex" v-for="item in resourceList" :key="item.id">
<div class="item-left flex">
<FileImage :size="50" :file-name="item.fileShowName" />
<div class="item-info flex">
<span class="item-name">{{ item.fileShowName }}</span>
<div class="item-student">
<span class="item-option">{{ item.fileFlag }}</span>
<span>{{ item.fileSuffix }}</span>
<template v-for="item in resourceList" :key="item.id">
<!--
apt pptx 暂时不显示
2024-10-10
-->
<li class="item flex" v-if="item.fileFlag != 'apt' && item.fileSuffix != 'pptx' && item.fileSuffix != 'ppt'">
<div class="item-left flex" >
<FileImage :size="50" :file-name="item.fileShowName" />
<div class="item-info flex">
<span class="item-name">{{ item.fileShowName }}</span>
<div class="item-student">
<span class="item-option">{{ item.fileFlag }}</span>
<span>{{ item.fileSuffix }}</span>
</div>
</div>
</div>
</div>
<el-button color="#349d44" @click="openFileLink(item)">推送</el-button>
</li>
<el-button color="#349d44" @click="openFileLink(item)">推送</el-button>
</li>
</template>
<!--作业-->
<li class="item flex" v-for="item in dataList" :key="item.id">
<div class="item-left flex">
@ -170,7 +176,6 @@ const openFileLink = async (item) =>{
//
const getResource = () => {
let querySearch = toRaw(toolStore.curSubjectNode).querySearch
querySearch.orderByColumn = 'uploadTime'
querySearch.isAsc = 'desc'
querySearch.pageSize = 500
@ -217,8 +222,6 @@ onMounted(async () => {
curNode.data = sessionStore.get('subject.curNode')
getHomework()
getResource()
})
</script>

View File

@ -49,9 +49,9 @@ const props = defineProps({
type: Array,
default: () => [
{ label: '课件', prop: 'book', isExtra: true, icon: 'icon--kejian' },
{ label: '资源', prop: 'resource', icon: 'icon-kechengziyuan1' },
{ label: '互动', prop: 'interact', icon: 'icon-hudong' },
{ label: '窗口', prop: 'win', icon: 'icon-tubiaozhizuomobanyihuifu-' },
{ label: '活动', prop: 'resource', icon: 'icon-kechengziyuan1' },
// { label: '', prop: 'interact', icon: 'icon-hudong' },
// { label: '', prop: 'win', icon: 'icon-tubiaozhizuomobanyihuifu-' },
{ label: '下课', prop: 'over', isExtra: true, icon: 'icon-a-lujing13357' },
]
}
@ -104,7 +104,7 @@ const clickHandel = (o, e) => {
top: 50%;
transform: translateY(-50%);
right: 10px;
min-height: 40vh;
//min-height: 40vh;
min-width: 4em;
border-radius: 4em;
background-color: #121212;

View File

@ -86,8 +86,8 @@ const btnList = [ // 工具栏按钮列表
// === ===
onMounted(async() => {
if (!electron) return //
window.test = sessionStore
window.test1 = toolStore
// window.test = sessionStore
// window.test1 = toolStore
getClassInfo() // ex3
resetStatus() // -
@ -233,13 +233,13 @@ const sideChange = async o => {
await imChatRef.value?.imChatObj?.imChat?.sendMsgClosed() //
// const elMsg = ElMessage.warning({duration:0,message:'...'})
const elMsg = ElLoading.service({lock: true, text: '正在下课...', background: 'rgba(0, 0, 0, 0.7)'})
// toolStore.isToolWin = false
toolStore.resetDef() //
await classManageApi.endClass(route.query.reservId)
// 2
setTimeout(async() => {
// toolStore.isToolWin = false
toolStore.resetDef() //
await imChatRef.value?.deleteGroup() //
await imChatRef.value?.logout() // 退im
await classManageApi.endClass(route.query.reservId)
elMsg.close()
ipcMsgSend('tool-sphere:close') //
}, 500);