diff --git a/package.json b/package.json index 946990a..75644fa 100644 --- a/package.json +++ b/package.json @@ -34,10 +34,13 @@ "electron-updater": "^6.1.7", "element-plus": "^2.7.6", "fabric": "^5.3.0", + "im_electron_sdk": "^8.0.5904", + "@vue-office/docx": "^1.6.2", + "@vue-office/excel": "^1.7.11", + "@vue-office/pdf": "^2.0.2", "js-cookie": "^3.0.5", "jsencrypt": "^3.3.2", "jsondiffpatch": "0.6.0", - "im_electron_sdk": "^8.0.5904", "lodash": "^4.17.21", "pdfjs-dist": "4.4.168", "pinia": "^2.1.7", diff --git a/src/renderer/src/api/classTask/index.js b/src/renderer/src/api/classTask/index.js index f441957..a6ebe4b 100644 --- a/src/renderer/src/api/classTask/index.js +++ b/src/renderer/src/api/classTask/index.js @@ -39,6 +39,15 @@ export function updateClassworkeval(data) { }) } +// 修改classworkdata +export function updateClassworkdata(data) { + return request({ + url: '/education/classworkdata', + method: 'put', + data: data + }) +} + diff --git a/src/renderer/src/components/refile-preview/index.vue b/src/renderer/src/components/refile-preview/index.vue new file mode 100644 index 0000000..227a465 --- /dev/null +++ b/src/renderer/src/components/refile-preview/index.vue @@ -0,0 +1,118 @@ + + + + + diff --git a/src/renderer/src/components/refile-preview/types.ts b/src/renderer/src/components/refile-preview/types.ts new file mode 100644 index 0000000..167bbff --- /dev/null +++ b/src/renderer/src/components/refile-preview/types.ts @@ -0,0 +1,7 @@ +export interface FileProps { + id?: number; + type?: string; + fileType?: string; + raw?: File; + filePath?: string; +} diff --git a/src/renderer/src/components/refile-preview/useReadFile.ts b/src/renderer/src/components/refile-preview/useReadFile.ts new file mode 100644 index 0000000..d93e785 --- /dev/null +++ b/src/renderer/src/components/refile-preview/useReadFile.ts @@ -0,0 +1,261 @@ +import type { FileProps } from "@/components/refile-preview/types"; +import { onUnmounted, ref } from "vue"; +import axios from "axios"; + +export function useHooks(props: FileProps) { + const excelOptions = { + xls: props.fileType !== "xlsx", //预览xlsx文件设为false;预览xls文件设为true + minColLength: 0, // excel最少渲染多少列,如果想实现xlsx文件内容有几列,就渲染几列,可以将此值设置为0. + minRowLength: 0, // excel最少渲染多少行,如果想实现根据xlsx实际函数渲染,可以将此值设置为0. + widthOffset: 10, //如果渲染出来的结果感觉单元格宽度不够,可以在默认渲染的列表宽度上再加 Npx宽 + heightOffset: 10, //在默认渲染的列表高度上再加 Npx高 + beforeTransformData: workbookData => { + return workbookData; + }, //底层通过exceljs获取excel文件内容,通过该钩子函数,可以对获取的excel文件内容进行修改,比如某个单元格的数据显示不正确,可以在此自行修改每个单元格的value值。 + transformData: workbookData => { + return workbookData; + } //将获取到的excel数据进行处理之后且渲染到页面之前,可通过transformData对即将渲染的数据及样式进行修改,此时每个单元格的text值就是即将渲染到页面上的内容 + }; + const src = ref(); + const filePreviewRef = ref(); + /** + * 渲染完成 + */ + const renderedHandler = () => { + console.log("渲染完成"); + }; + /** + * 渲染失败 + * @param e + */ + const errorHandler = e => { + console.log("渲染失败", e); + }; + + /** + * 渲染文件 + */ + async function renderTheFile() { + if (props.type === "local") { + console.log("本地文件" + props.fileType); + isImage(props.fileType) && localImagePreview(props.raw); + isDoc(props.fileType) && localOfficePreview(props.raw); + isText(props.fileType) && localTextPreview(props.raw); + isVideo(props.fileType) && localVideoPreview(props.raw); + isAudio(props.fileType) && localAudioPreview(props.raw); + } else { + if (isVideo(props.fileType)) { + src.value = + import.meta.env.VITE_APP_BASE_URL + + "/upload/attachments/getTeamOfVideo?id=" + + props.id; + return; + } + if (isText(props.fileType)) { + const response = await axios.get( + import.meta.env.VITE_STATIC_URL + props.filePath, + { + responseType: "text" + } + ); + src.value = response.data; + return; + } + src.value = import.meta.env.VITE_STATIC_URL + props.filePath; + } + } + + /** + * 校验图片类型 + * @param type + */ + function isImage(type: string) { + const types = [ + "jpg", + "png", + "gif", + "jpeg", + "bmp", + "webp", + "svg", + "tiff", + "tif", + "jpeg", + "jfif", + "pjpeg", + "pjp" + ]; + return types.includes(type); + } + + /** + * 校验文档类型 + * @param type + */ + function isDoc(type: string) { + const types = ["docx", "doc", "xlsx", "xls", "pdf"]; + return types.includes(type); + } + + /** + * 校验文本类型 + * @param type + */ + function isText(type: string) { + const types = [ + "txt", + "md", + "log", + "json", + "xml", + "html", + "css", + "js", + "java", + "c", + "cpp", + "h", + "hpp", + "py", + "rb", + "go", + "sh", + "bat", + "ps1", + "psm1", + "ps1xml", + "psc1", + "psd1", + "psm1", + "ps1xml", + "psc1", + "psd1", + "ps1xml", + "psc1", + "ps1xml", + "psc1", + "psd1" + ]; + return types.includes(type); + } + + // 检验视频格式 + function isVideo(type: string) { + const types = [ + "mp4", + "avi", + "rmvb", + "mkv", + "flv", + "wmv", + "mov", + "webm", + "m4v", + "mpg", + "mpeg", + "3gp", + "3g2", + "vob", + "ogv", + "ogg", + "mts", + "m2ts", + "ts", + "m2v", + "mpe", + "mpv", + "m4p", + "m4v", + "mpv2", + "m4v", + "m4p", + "m4v", + "m4p" + ]; + return types.includes(type); + } + + // 检验音频文件 + function isAudio(type: string) { + const types = ["mp3", "wav", "ogg", "flac", "aac", "wma", "m4a", "wma"]; + return types.includes(type); + } + + /** + * 预览本地Office文件 + * @param file + */ + function localOfficePreview(file: File) { + const reader = new FileReader(); + reader.readAsArrayBuffer(file); + reader.onload = loadEvent => { + const arrayBuffer = loadEvent.target.result; + const blob = new Blob([arrayBuffer], { + type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document" + }); + src.value = URL.createObjectURL(blob); + }; + } + + /** + * 预览本地图片 + * @param file + */ + function localImagePreview(file: File) { + const reader = new FileReader(); + reader.onload = e => { + src.value = e.target.result; + }; + reader.readAsDataURL(file); + } + + /** + * 预览本地文本 + * @param file + */ + function localTextPreview(file: File) { + const reader = new FileReader(); + reader.onload = e => { + src.value = e.target.result; + }; + reader.readAsText(file); + } + + /** + * 预览本地视频 + * @param file + */ + function localVideoPreview(file: File) { + src.value = URL.createObjectURL(file); + } + + function localAudioPreview(file: File) { + const reader = new FileReader(); + reader.onloadend = () => { + const blob = new Blob([reader.result], { type: "audio/mpeg" }); + src.value = URL.createObjectURL(blob); + }; + reader.readAsArrayBuffer(file); + } + + // 清理工作:当组件卸载时释放URL对象 + onUnmounted(() => { + if (src.value) { + isVideo(props.fileType) && URL.revokeObjectURL(src.value); + isAudio(props.fileType) && URL.revokeObjectURL(src.value); + } + }); + return { + excelOptions, + src, + filePreviewRef, + isImage, + renderedHandler, + errorHandler, + renderTheFile, + isVideo, + isText, + isAudio + }; +} + diff --git a/src/renderer/src/views/classTask/classTask.vue b/src/renderer/src/views/classTask/classTask.vue index 98a5d7b..1425e8c 100644 --- a/src/renderer/src/views/classTask/classTask.vue +++ b/src/renderer/src/views/classTask/classTask.vue @@ -92,7 +92,9 @@ const getData = () => { // 班级作业数据,包含多个班级 homeworklist({ classidarray: classListIds.value.join(','), - entpcourseid: '', // 章节id? 这里要全课程的作业 不分章节? + //entpcourseid: '', // 章节id? 这里要全课程的作业 不分章节? 根据学段学科查询所有的作业 + edustage: userStore.edustage,// 学段 + edusubject: userStore.edusubject,//学科 orderby: 'uniquekey DESC', pageSize: 100 }).then((response) => { @@ -101,7 +103,7 @@ const getData = () => { response.rows[i].workdatalist = [] response.rows[i].workdatacount = 0 // 人数 response.rows[i].workdatalistVisible = false - response.rows[i].workdatafeedbackcount = 0 + response.rows[i].workdatafeedbackcount = 0 // 已交人数 response.rows[i].feedtimelength = 0 response.rows[i].rightAnswerCount = 0 response.rows[i].scoingRate = 0 + '%' // 得分率 @@ -142,10 +144,10 @@ const getData = () => { } } - // 显示分配人数>0 的 + // 显示分配人数(workdatacount)>0 的 if (response.rows && response.rows.length > 0) { - classWorkList.value = - response.rows && response.rows.filter((item) => item.workdatacount > 0) + classWorkList.value = response.rows && response.rows.filter((item) => item.workdatacount > 0) + // classWorkList.value = response.rows && response.rows.filter((item) => item.workdatacount > 0 && item.uniquekey == '语文-0808-1') //TODO: 这里没分页,貌似这个 total 不重要,后续看 total.value = response.total } @@ -211,7 +213,9 @@ const getStudentVisible = async () => { // 班级作业数据,多个班级 const response = await homeworklist({ classidarray: classListIds.value.join(','), - entpcourseid: '', // 章节???这里不需要,全课程的 + //entpcourseid: '', // 章节id? 这里要全课程的作业 不分章节? 根据学段学科查询所有的作业 + edustage: userStore.edustage,// 学段 + edusubject: userStore.edusubject,//学科 orderby: 'uniquekey DESC', pageSize: 100 }) @@ -228,7 +232,7 @@ const getStudentVisible = async () => { // } // 确保当前拿到的任务与页面中存在的任务能一对一(避免因删除其他操作而删除作业任务导致两个数组的index不统一而越界) let curWork = curWorkList.find((work) => work.id === classWorkList.value[t].id) - // workdataresultcount 完成人数 workdatacount人数要大于0 + // workdataresultcount 完成人数 workdatacount人数要大于0 if (curWork && curWork.workdataresultcount > 0 && classWorkList.value[t].workdatacount > 0) { classWorkList.value[t].workdataresultcount = curWork.workdataresultcount // 桌面端貌似不需要进度条了? @@ -236,12 +240,8 @@ const getStudentVisible = async () => { (classWorkList.value[t].workdataresultcount / classWorkList.value[t].workdatacount) * 100 ) // 计算参与学习任务的平均用时 - console.log('平均用时??---', classWorkList.value[t].workdatafeedbackcount) if (classWorkList.value[t].workdatafeedbackcount > 0) { - classWorkList.value[t].averagetime = ( - classWorkList.value[t].feedtimelength / classWorkList.value[t].workdatafeedbackcount - ).toFixed(0) - console.log('平均用时---', classWorkList.value[t].averagetime) + classWorkList.value[t].averagetime = (classWorkList.value[t].feedtimelength / classWorkList.value[t].workdatafeedbackcount).toFixed(0) } else { classWorkList.value[t].averagetime = 0 } @@ -257,15 +257,18 @@ const getStudentVisible = async () => { const getStudentClassWorkData = () => { // 再查找多个班级里,每个学生的作业数据 console.log('======????????""""""""""') + //TODO 这里id变动,看后续用什么判断 listClassworkdata({ classids: classListIds.value.join(','), - entpcourseid: '', // 章节id? 这里要全课程的作业 不分章节? + //entpcourseid: '', // 章节id? 这里要全课程的作业 不分章节? 根据学段学科查询所有的作业 + edustage: userStore.edustage,// 学段 + edusubject: userStore.edusubject,//学科 + orderby: "deaddate DESC", pageSize: 1000 }).then((res) => { - console.log('多个班级里,每个学生的作业数据', res.rows) for (var t = 0; t < classWorkList.value.length; t++) { for (var i = 0; i < res.rows.length; i++) { - if (res.rows[i].classworkid == classWorkList.value[t].id) { + if (res.rows[i].uniquekey == classWorkList.value[t].uniquekey) { // if (res.rows[i].classworkid == classWorkList.value[t].id && res.rows[i].resultcount > 0) { console.log('==================') // 有几个学生完成/正在完成学习任务 @@ -332,10 +335,7 @@ const getStudentClassWorkData = () => { // 计算参与学习任务的平均用时 if (classWorkList.value[t].workdatafeedbackcount > 0) { - classWorkList.value[t].averagetime = - ( - classWorkList.value[t].feedtimelength / classWorkList.value[t].workdatafeedbackcount - ).toFixed(0) + classWorkList.value[t].averagetime = (classWorkList.value[t].feedtimelength / classWorkList.value[t].workdatafeedbackcount).toFixed(0) } else { classWorkList.value[t].averagetime = 0 } diff --git a/src/renderer/src/views/classTask/container/item-dialog-score.vue b/src/renderer/src/views/classTask/container/item-dialog-score.vue index fcd5ee4..619cc44 100644 --- a/src/renderer/src/views/classTask/container/item-dialog-score.vue +++ b/src/renderer/src/views/classTask/container/item-dialog-score.vue @@ -1,6 +1,7 @@ - +
@@ -491,6 +491,25 @@ const handleClassWorkAnalysissScoreOpen = (row) => { } //#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.resultcount > 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.resultcount == 0) + tableRadio.value = '0'; + tableRadio.num0 = tableRadio.list.length; + tableRadio.num1 = classWorkAnalysis.classworkdata.length - tableRadio.list.length; + } +} + // 将标签中的双引号增加转义 const escapeHtmlQuotes = (str) => { // 后端已replace双引号, 故前端不用在处理 diff --git a/src/renderer/src/views/classTask/container/task-item.vue b/src/renderer/src/views/classTask/container/task-item.vue index 9e7142e..44d93df 100644 --- a/src/renderer/src/views/classTask/container/task-item.vue +++ b/src/renderer/src/views/classTask/container/task-item.vue @@ -14,13 +14,16 @@  |  截止时间:{{ item.deaddate }}  | {{ tabactive }}
- +
- {{ item.workdataresultcount }}/{{ item.workdatacount }} + + {{ item.workdataresultcount }} + {{ item.workdataresultcount }} + /{{ item.workdatacount }} 已交
- 2 + {{ item.teacherRationgCount?item.teacherRationgCount:0 }} 待批阅