|
@@ -0,0 +1,847 @@
|
|
|
+import $tools from './public.js'
|
|
|
+import { app } from '@/main.js'
|
|
|
+
|
|
|
+
|
|
|
+export default {
|
|
|
+ /* 根据登录后的用户信息获取blobHOST域名 */
|
|
|
+ getBlobHost(url) {
|
|
|
+ let s = url || store.state.user.userProfile.blob_uri || store.state.user.studentProfile.blob_uri
|
|
|
+ let pattern = /[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\.?/
|
|
|
+ return s.split('//')[0] + '//' + s.match(pattern)[0]
|
|
|
+ },
|
|
|
+ getAbilityDetailById(abilityId) {
|
|
|
+ return new Promise((r, j) => {
|
|
|
+ $api.ability.FindAbilityById({
|
|
|
+ "scope": "school",
|
|
|
+ "schoolCode": store.state.userInfo.schoolCode,
|
|
|
+ "abilityId": abilityId,
|
|
|
+ "standard": sessionStorage.getItem('standard')
|
|
|
+ }).then(res => {
|
|
|
+ if (!res.error) {
|
|
|
+ r(res.ability)
|
|
|
+ } else {
|
|
|
+ j(res.error)
|
|
|
+ }
|
|
|
+ }).catch(e => {
|
|
|
+ j(e)
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ /* 获取试题保存在Blob的JSON文件 */
|
|
|
+ /* 创建Blob试题格式 */
|
|
|
+ createBlobItem(item) {
|
|
|
+ return new Promise((r, j) => {
|
|
|
+ let itemJson = {
|
|
|
+ id: item.id,
|
|
|
+ pid: item.pid || null,
|
|
|
+ exercise: {
|
|
|
+ answer: item.answer,
|
|
|
+ explain: item.explain,
|
|
|
+ type: item.type,
|
|
|
+ answerType: item.answerType || 'text',
|
|
|
+ useAutoScore: item.useAutoScore || false,
|
|
|
+ answerLang: item.answerLang || 'en-US',
|
|
|
+ objective: this.getItemType(item.type),
|
|
|
+ opts: item.option ? item.option.length : 0,
|
|
|
+ knowledge: item.knowledge,
|
|
|
+ field: item.field,
|
|
|
+ level: item.level,
|
|
|
+ periodId: item.periodId,
|
|
|
+ gradeIds: item.gradeIds,
|
|
|
+ subjectId: item.subjectId,
|
|
|
+ children: item.children || [],
|
|
|
+ // scope:item.scope,
|
|
|
+ score: item.score || 0,
|
|
|
+ source: item.source || 0,
|
|
|
+ blankCount: item.blankCount || 1,
|
|
|
+ repair: item.repair,
|
|
|
+ createTime: new Date().getTime(),
|
|
|
+ creator: store.state.userInfo.TEAMModelId || 'null'
|
|
|
+ },
|
|
|
+ item: [{
|
|
|
+ type: 'Html',
|
|
|
+ uid: item.id,
|
|
|
+ question: item.question,
|
|
|
+ option: item.option
|
|
|
+ }]
|
|
|
+ }
|
|
|
+ r(itemJson)
|
|
|
+ })
|
|
|
+ },
|
|
|
+ /* 获取保存在COSMOS里面的试题格式 */
|
|
|
+ createCosmosItem(item, scope, code) {
|
|
|
+ return new Promise((r, j) => {
|
|
|
+ let cosmosItem = {
|
|
|
+ id: item.id,
|
|
|
+ pid: item.pid || null,
|
|
|
+ code: code || item.code,
|
|
|
+ scope: scope || item.scope,
|
|
|
+ score: item.score || 0,
|
|
|
+ source: item.source || 0,
|
|
|
+ type: item.type,
|
|
|
+ answer: item.answer || [],
|
|
|
+ answerType: item.answerType || 'text',
|
|
|
+ useAutoScore: item.useAutoScore || false,
|
|
|
+ answerLang: item.answerLang || 'en-US',
|
|
|
+ objective: this.getItemType(item.type),
|
|
|
+ question: this.getSimpleText(item.question),
|
|
|
+ knowledge: item.knowledge,
|
|
|
+ field: item.field,
|
|
|
+ level: item.level,
|
|
|
+ periodId: item.periodId,
|
|
|
+ gradeIds: item.gradeIds,
|
|
|
+ subjectId: item.subjectId,
|
|
|
+ repair: item.repair,
|
|
|
+ blankCount: item.blankCount || 1,
|
|
|
+ blob: item.blob,
|
|
|
+ createTime: new Date().getTime(),
|
|
|
+ creator: store.state.userInfo.TEAMModelId || 'null',
|
|
|
+ tags: item.tags || []
|
|
|
+ }
|
|
|
+ r(cosmosItem)
|
|
|
+ })
|
|
|
+ },
|
|
|
+ /* 生成试卷的index.json文件格式 */
|
|
|
+ createBlobPaper(paper, slides) {
|
|
|
+ return new Promise((r, j) => {
|
|
|
+ let paperItem = {
|
|
|
+ id: paper.id,
|
|
|
+ name: paper.name,
|
|
|
+ // code:paper.code,
|
|
|
+ // scope:paper.scope,
|
|
|
+ blob: paper.blob || '',
|
|
|
+ itemSort: paper.itemSort || 0,
|
|
|
+ isNumOption: paper.isNumOption || 0,
|
|
|
+ qamode: paper.qamode || 0,
|
|
|
+ multipleRule: paper.multipleRule,
|
|
|
+ attachments: paper.attachments || [],
|
|
|
+ tags: paper.tags || [],
|
|
|
+ slides: slides,
|
|
|
+ points: paper.points,
|
|
|
+ periodId: paper.periodId,
|
|
|
+ gradeIds: paper.gradeIds,
|
|
|
+ subjectId: paper.subjectId,
|
|
|
+ subjectName: paper.subjectName,
|
|
|
+ score: paper.score,
|
|
|
+ sheet: paper.sheet || null,
|
|
|
+ typeSummaryInfo: paper.typeSummaryInfo || null,
|
|
|
+ orderTemp: paper.orderTemp || 0,
|
|
|
+ secret: paper.secret || 0,
|
|
|
+ markModel: paper.markModel || 0,
|
|
|
+ creatorId: paper.creatorId || store.state.userInfo.TEAMModelId
|
|
|
+ }
|
|
|
+ r(paperItem)
|
|
|
+ })
|
|
|
+ },
|
|
|
+ /* 生成试卷保存在cosmos的数据结构 */
|
|
|
+ createCosmosPaper(paper) {
|
|
|
+ return new Promise((r, j) => {
|
|
|
+ let paperItem = {
|
|
|
+ id: paper.id,
|
|
|
+ name: paper.name,
|
|
|
+ code: paper.code,
|
|
|
+ blob: paper.blob,
|
|
|
+ tags: paper.tags || [],
|
|
|
+ qamode: paper.qamode || 0,
|
|
|
+ attachments: paper.attachments || [],
|
|
|
+ sheet: paper.sheet || null,
|
|
|
+ itemSort: paper.itemSort || 0,
|
|
|
+ isNumOption: paper.isNumOption || 0,
|
|
|
+ scope: paper.scope,
|
|
|
+ scoring: paper.scoring,
|
|
|
+ points: paper.points,
|
|
|
+ periodId: paper.periodId,
|
|
|
+ gradeIds: paper.gradeIds,
|
|
|
+ subjectId: paper.subjectId,
|
|
|
+ subjectName: paper.subjectName,
|
|
|
+ score: paper.score,
|
|
|
+ multipleRule: paper.multipleRule,
|
|
|
+ secret: paper.secret || 0,
|
|
|
+ markModel: paper.markModel || 0,
|
|
|
+ creatorId: paper.creatorId || store.state.userInfo.TEAMModelId
|
|
|
+ }
|
|
|
+ r(paperItem)
|
|
|
+ })
|
|
|
+ },
|
|
|
+ /* 根据醍摩豆ID获取对应用户Blob内部的完整试题 */
|
|
|
+ getFullItemByTmdId(tmdId, blob, inSyllabus) {
|
|
|
+ return new Promise(async (r, j) => {
|
|
|
+ let privateSas = await this.getBlobPrivateSas(tmdId)
|
|
|
+ let fullPath = this.getBlobHost() + '/' + tmdId + blob + privateSas
|
|
|
+ let jsonData = JSON.parse(await $tools.getFile(fullPath))
|
|
|
+ // 如果是综合题 那就拿到children里面的小题id集合 去换取小题的blobJSON文件 然后替换children的内容
|
|
|
+ if (jsonData.exercise.children.length && jsonData.exercise.type === 'compose') {
|
|
|
+ let childrenUrls;
|
|
|
+ if (inSyllabus) {
|
|
|
+ let syllabusPrefix = '/syllabus/' + blob.split('/')[2] + '/' + jsonData.id
|
|
|
+ childrenUrls = jsonData.exercise.children.map(i => this.getBlobHost() + '/' + tmdId + syllabusPrefix + '/' + i.id + '.json' + privateSas)
|
|
|
+ } else {
|
|
|
+ childrenUrls = jsonData.exercise.children.map(i => this.getBlobHost() + '/' + tmdId + '/item/' + i + '/' + i + '.json' + privateSas)
|
|
|
+ }
|
|
|
+ console.log(childrenUrls);
|
|
|
+ jsonData.exercise.children = await this.getFullChildren(childrenUrls, tmdId, inSyllabus)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 调整渲染试题数据结构
|
|
|
+ jsonData.exercise.question = jsonData.item[0].question
|
|
|
+ jsonData.exercise.blob = fullPath
|
|
|
+ jsonData.exercise.code = tmdId
|
|
|
+ jsonData.exercise.option = jsonData.item[0].option
|
|
|
+ jsonData.exercise.id = jsonData.id
|
|
|
+ jsonData.exercise.scope = 'private'
|
|
|
+ jsonData.exercise.pid = jsonData.pid
|
|
|
+ jsonData.exercise = await this.doAddHost(jsonData.exercise, null, tmdId, inSyllabus)
|
|
|
+ r(jsonData.exercise)
|
|
|
+ })
|
|
|
+ },
|
|
|
+ /* 根据醍摩豆ID获取对应BLOB个人容器授权信息 */
|
|
|
+ getBlobPrivateSas(tmdId) {
|
|
|
+ return new Promise((r, j) => {
|
|
|
+ $api.blob.blobSasR({
|
|
|
+ name: tmdId,
|
|
|
+ role: 'teacher'
|
|
|
+ }).then(res => {
|
|
|
+ if (!res.error) {
|
|
|
+ r('?' + res.sas)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ /* 根据醍摩豆ID获取对应BLOB个人容器授权信息 */
|
|
|
+ getBlobPrivateSasObj(tmdId) {
|
|
|
+ return new Promise((r, j) => {
|
|
|
+ $api.blob.blobSasR({
|
|
|
+ name: tmdId,
|
|
|
+ role: 'teacher'
|
|
|
+ }).then(res => {
|
|
|
+ if (!res.error) {
|
|
|
+ res.sas = '?' + res.sas
|
|
|
+ r(res)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ /* 根据醍摩豆ID获取对应BLOB个人容器授权信息 */
|
|
|
+ getBlobSchoolSas(schoolCode) {
|
|
|
+ return new Promise((r, j) => {
|
|
|
+ $api.blob.blobSasR({
|
|
|
+ name: schoolCode,
|
|
|
+ role: 'school'
|
|
|
+ }).then(res => {
|
|
|
+ if (!res.error) {
|
|
|
+ r('?' + res.sas)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ /* 获取完整的试题数据 */
|
|
|
+ getFullItem(list, examScope, inSyllabus) {
|
|
|
+ console.log('接受到的examScope', examScope)
|
|
|
+ return new Promise(async (resolve, reject) => {
|
|
|
+ if (list.length === 0) return
|
|
|
+ let promiseArr = []
|
|
|
+ console.log('getFullITEM接收到的list')
|
|
|
+ console.log(list)
|
|
|
+ for (let i = 0; i < list.length; i++) {
|
|
|
+ promiseArr.push(new Promise(async (r, j) => {
|
|
|
+ if (list[i].blob) {
|
|
|
+ let curScope = list[i].scope
|
|
|
+ const blobHost = curScope === 'school' ? JSON.parse(decodeURIComponent(localStorage.school_profile, "utf-8")).blob_uri : JSON.parse(decodeURIComponent(localStorage.user_profile, "utf-8")).blob_uri
|
|
|
+ // 根据试题的Blob地址 去读取JSON文件
|
|
|
+ let sasString = curScope === 'school' ? await $tools.getSchoolSas() : await $tools.getPrivateSas()
|
|
|
+ try {
|
|
|
+ let jsonInfo = list[i].blob.includes('https://') ? await $tools.getFile(list[i].blob + sasString.sas) : await $tools.getFile(blobHost + list[i].blob + sasString.sas)
|
|
|
+ let jsonData = JSON.parse(jsonInfo)
|
|
|
+ // 如果是综合题 那就拿到children里面的小题id集合 去换取小题的blobJSON文件 然后替换children的内容
|
|
|
+ if (jsonData.exercise.children.length && jsonData.exercise.type === 'compose') {
|
|
|
+ let childrenUrls;
|
|
|
+ if (inSyllabus) {
|
|
|
+ let syllabusPrefix = '/syllabus/' + list[i].blob.split('/')[2] + '/' + list[i].id
|
|
|
+ childrenUrls = jsonData.exercise.children.map(i => blobHost + syllabusPrefix + '/' + i.id + '.json' + sasString.sas)
|
|
|
+ } else {
|
|
|
+ childrenUrls = jsonData.exercise.children.map(i => blobHost + '/item/' + i + '/' + i + '.json' + sasString.sas)
|
|
|
+ }
|
|
|
+ jsonData.exercise.children = await this.getFullChildren(childrenUrls, list[i].code, list[i].scope, inSyllabus)
|
|
|
+ }
|
|
|
+ // 调整渲染试题数据结构
|
|
|
+ jsonData.id = list[i].id
|
|
|
+ jsonData.exercise.question = jsonData.item[0].question
|
|
|
+ jsonData.exercise.createTime = list[i].createTime || 0
|
|
|
+ jsonData.exercise.blob = list[i].blob
|
|
|
+ jsonData.exercise.code = list[i].code
|
|
|
+ jsonData.exercise.scope = list[i].scope
|
|
|
+ jsonData.exercise.option = jsonData.item[0].option
|
|
|
+ jsonData.exercise.id = list[i].id
|
|
|
+ jsonData.exercise.pid = jsonData.pid
|
|
|
+ jsonData.exercise.tags = list[i]?.tags || []
|
|
|
+ if(inSyllabus && list[i].nodeId) jsonData.exercise.nodeId = list[i].nodeId
|
|
|
+ jsonData.exercise = await this.doAddHost(jsonData.exercise, null, null, inSyllabus)
|
|
|
+ r(jsonData.exercise)
|
|
|
+ } catch (e) {
|
|
|
+ console.log(e)
|
|
|
+ j(e)
|
|
|
+ // this.$Message.error(e)
|
|
|
+ }
|
|
|
+
|
|
|
+ } else {
|
|
|
+ r(null)
|
|
|
+ }
|
|
|
+ }))
|
|
|
+ }
|
|
|
+ Promise.allSettled(promiseArr).then(result => {
|
|
|
+ console.log('从Blob获取来的试题', result.filter(i => i.status === 'fulfilled').map(j => j.value))
|
|
|
+ resolve(result.filter(i => i.status === 'fulfilled').map(j => j.value))
|
|
|
+ }).catch(err => {
|
|
|
+ Message.error(app.$t('utils.fileReadFail'))
|
|
|
+ reject(err)
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ /* 保存综合题小题 */
|
|
|
+ saveChildren(children, containerClient) {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ let promiseArr = []
|
|
|
+ let itemJsonFiles = []
|
|
|
+ children.forEach(exerciseItem => {
|
|
|
+ promiseArr.push(new Promise(async (r, j) => {
|
|
|
+ // 将当前的试题数据转化为BLOB内部的试题JSON格式
|
|
|
+ const itemJsonFile = await this.createBlobItem(exerciseItem)
|
|
|
+ const cosmosItem = await this.createCosmosItem(exerciseItem)
|
|
|
+ // 首先保存新题目的JSON文件到Blob 然后返回URL链接
|
|
|
+ let file = new File([JSON.stringify(itemJsonFile)], exerciseItem.id + ".json");
|
|
|
+ try {
|
|
|
+ // 等待上传blob的返回结果
|
|
|
+ let blobFile = await containerClient.upload(file, { path: 'item/' + exerciseItem.id })
|
|
|
+ if (blobFile.blob) {
|
|
|
+ // 保存试题JSON文件到试卷文件夹需要
|
|
|
+ itemJsonFiles.push(file)
|
|
|
+ // 保存到COSMOS是不含base64图片编码的数据 避免数据量过大
|
|
|
+ cosmosItem.blob = blobFile.blob
|
|
|
+ // 保存当前试题到数据库
|
|
|
+ that.saveExercise(cosmosItem).then(res => {
|
|
|
+ r(res.itemInfo)
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ j(500)
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ j(500)
|
|
|
+ }
|
|
|
+ }))
|
|
|
+ })
|
|
|
+ Promise.all(promiseArr).then(result => {
|
|
|
+ if (result.length) {
|
|
|
+ resolve(itemJsonFiles)
|
|
|
+ } else {
|
|
|
+ resolve([])
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ })
|
|
|
+
|
|
|
+ },
|
|
|
+ /* 获取综合题子题的Blob数据 */
|
|
|
+ getFullChildren(urls, code, scope, inSyllabus) {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ let promiseArr = []
|
|
|
+ urls.forEach(url => {
|
|
|
+ promiseArr.push(new Promise(async (r, j) => {
|
|
|
+ try {
|
|
|
+ let jsonData = JSON.parse(await $tools.getFile(url))
|
|
|
+ // 调整渲染试题数据结构
|
|
|
+ jsonData.exercise.question = jsonData.item[0].question
|
|
|
+ jsonData.exercise.blob = url
|
|
|
+ jsonData.exercise.code = code
|
|
|
+ jsonData.exercise.option = jsonData.item[0].option
|
|
|
+ jsonData.exercise.id = jsonData.id
|
|
|
+ jsonData.exercise.pid = jsonData.pid
|
|
|
+ jsonData.exercise.scope = scope || 'private'
|
|
|
+ jsonData.exercise = await this.doAddHost(jsonData.exercise, null, null, inSyllabus)
|
|
|
+ r(jsonData.exercise)
|
|
|
+ } catch (e) {
|
|
|
+ j(e)
|
|
|
+ }
|
|
|
+ }))
|
|
|
+ })
|
|
|
+
|
|
|
+ Promise.allSettled(promiseArr).then(result => {
|
|
|
+ if (result.length) {
|
|
|
+ // resolve(result)
|
|
|
+ resolve(result.filter(i => i.status === 'fulfilled').map(j => j.value))
|
|
|
+ } else {
|
|
|
+ resolve([])
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ /* 根据醍摩豆ID获取对应用户Blob内部的完整试卷 */
|
|
|
+ getFullPaperByTmdId(tmdId, blob, nodeId) {
|
|
|
+ return new Promise(async (r, j) => {
|
|
|
+ console.log('根据ID获取试题')
|
|
|
+ let privateSas = await this.getBlobPrivateSas(tmdId)
|
|
|
+ let fullPath = this.getBlobHost() + '/' + tmdId + blob + '/index.json' + privateSas
|
|
|
+ try {
|
|
|
+ let jsonInfo = await $tools.getFile(fullPath)
|
|
|
+ let jsonData = JSON.parse(jsonInfo)
|
|
|
+ jsonData.scope = 'private'
|
|
|
+ jsonData.code = tmdId
|
|
|
+ // 获取试卷包含的试题数据并包装好
|
|
|
+ if (jsonData.slides && jsonData.slides.length) {
|
|
|
+ let promiseArr = []
|
|
|
+ let allItems = []
|
|
|
+ jsonData.item = []
|
|
|
+ const path = this.getBlobHost() + '/' + tmdId + blob
|
|
|
+ jsonData.slides.forEach(async (item, index) => {
|
|
|
+ promiseArr.push(new Promise(async (resolve, reject) => {
|
|
|
+ try {
|
|
|
+ // 获取题目JSON并且包装成完整试题对象
|
|
|
+ let itemJson = JSON.parse(await $tools.getFile(path + '/' + item.url + privateSas))
|
|
|
+ itemJson.exercise.question = itemJson.item[0].question
|
|
|
+ itemJson.exercise.option = itemJson.item[0].option
|
|
|
+ itemJson.exercise.id = itemJson.id
|
|
|
+ itemJson.exercise.pid = itemJson.pid
|
|
|
+ itemJson.exercise.blob = path + '/' + item.url // 添加blob是方便在保存试卷是 refresh 与导入的试题区分开
|
|
|
+ itemJson.exercise.scope = 'private'
|
|
|
+ itemJson.exercise.score = item.scoring ? item.scoring.score : 0
|
|
|
+ try {
|
|
|
+ itemJson.exercise = await this.doAddHost(itemJson.exercise, { name: jsonData.name }, nodeId ? 'syllabus' : tmdId, nodeId) // 检测试题中的富文本 为有src为相对路径的音视频文件添加blob的HOST地址
|
|
|
+ resolve(itemJson.exercise)
|
|
|
+ } catch (e) {
|
|
|
+ reject(e)
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ reject(e)
|
|
|
+ }
|
|
|
+ }))
|
|
|
+ })
|
|
|
+
|
|
|
+ Promise.all(promiseArr).then(res => {
|
|
|
+ res.forEach((resItem, resIndex) => {
|
|
|
+ resItem.children = []
|
|
|
+ if (resItem.pid) {
|
|
|
+ let pItem = res.filter(i => i.id === resItem.pid)[0]
|
|
|
+ pItem.children.push(resItem)
|
|
|
+ pItem.score = pItem.score + resItem.score
|
|
|
+ }
|
|
|
+ })
|
|
|
+ jsonData.item = res.filter(i => !i.pid)
|
|
|
+ r(jsonData)
|
|
|
+ }).catch(e => {
|
|
|
+ // Message.error('试卷文件读取失败')
|
|
|
+ j(e)
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.log(e)
|
|
|
+ j(e)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ /* 获取完整的试卷数据 */
|
|
|
+ getFullPaper(paper, examScope, nodeId) {
|
|
|
+ console.log(paper)
|
|
|
+ console.log(examScope)
|
|
|
+ console.log(nodeId)
|
|
|
+ let curScope = examScope || paper.examScope || paper.scope
|
|
|
+ return new Promise(async (r, j) => {
|
|
|
+ let blobHost = curScope === 'school' ? JSON.parse(decodeURIComponent(localStorage.school_profile, "utf-8")).blob_uri :
|
|
|
+ JSON.parse(decodeURIComponent(localStorage.user_profile, "utf-8")).blob_uri
|
|
|
+ let sasString = curScope === 'school' ? await $tools.getSchoolSas() : await $tools.getPrivateSas()
|
|
|
+ let privateSas = sasString.sas
|
|
|
+ // 如果是活動版sas拿法不同
|
|
|
+ if(paper.blob.indexOf("jointexam") != -1){
|
|
|
+ if(paper.creatorId){
|
|
|
+ privateSas = await this.getBlobPrivateSas(paper.creatorId)
|
|
|
+ }else{
|
|
|
+ privateSas = await this.getBlobPrivateSas(paper.examId)
|
|
|
+ }
|
|
|
+
|
|
|
+ blobHost ="https://teammodel.blob.core.windows.net/"+paper.creatorId
|
|
|
+ }
|
|
|
+
|
|
|
+ // 根据试卷的Blob地址 去读取JSON文件
|
|
|
+ try {
|
|
|
+ let paperBlob = paper.blob
|
|
|
+ let jsonInfo = await $tools.getFile(blobHost + paperBlob + '/index.json' + privateSas)
|
|
|
+ let jsonData = JSON.parse(jsonInfo)
|
|
|
+ jsonData.scope = paper.scope
|
|
|
+ jsonData.code = paper.code
|
|
|
+ jsonData.sheet = paper.sheet || null
|
|
|
+ // 获取试卷包含的试题数据并包装好
|
|
|
+ if (jsonData.slides && jsonData.slides.length) {
|
|
|
+ let promiseArr = []
|
|
|
+ let allItems = []
|
|
|
+ jsonData.item = []
|
|
|
+ const path = blobHost + paper.blob
|
|
|
+ jsonData.slides.forEach(async (item, index) => {
|
|
|
+ promiseArr.push(new Promise(async (resolve, reject) => {
|
|
|
+ try {
|
|
|
+ // 获取题目JSON并且包装成完整试题对象
|
|
|
+ let itemJson = JSON.parse(await $tools.getFile(path + '/' + item.url + privateSas))
|
|
|
+ itemJson.exercise.question = itemJson.item[0].question
|
|
|
+ itemJson.exercise.option = itemJson.item[0].option
|
|
|
+ itemJson.exercise.id = itemJson.id
|
|
|
+ itemJson.exercise.pid = itemJson.pid
|
|
|
+ itemJson.exercise.scope = paper.scope
|
|
|
+ itemJson.exercise.blob = path + '/' + item.url // 添加blob是方便在保存试卷是 refresh 与导入的试题区分开
|
|
|
+ itemJson.exercise.score = item.scoring ? item.scoring.score : 0
|
|
|
+ try {
|
|
|
+ let p = nodeId ? { name: paper.name } : paper
|
|
|
+ itemJson.exercise = await this.doAddHost(itemJson.exercise, p, nodeId ? 'syllabus' : null, nodeId) // 检测试题中的富文本 为有src为相对路径的音视频文件添加blob的HOST地址
|
|
|
+ resolve(itemJson.exercise)
|
|
|
+ } catch (e) {
|
|
|
+ reject(e)
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ reject(e)
|
|
|
+ }
|
|
|
+ }))
|
|
|
+ })
|
|
|
+
|
|
|
+ Promise.allSettled(promiseArr).then(res => {
|
|
|
+ res = res.filter(i => i.status === 'fulfilled').map(j => j.value)
|
|
|
+ res.forEach((resItem, resIndex) => {
|
|
|
+ resItem.children = []
|
|
|
+ if (resItem.pid) {
|
|
|
+ let pItem = res.filter(i => i.id === resItem.pid)[0]
|
|
|
+ pItem.children.push(resItem)
|
|
|
+ pItem.score = pItem.score + resItem.score
|
|
|
+ }
|
|
|
+ })
|
|
|
+ jsonData.item = res.filter(i => !i.pid)
|
|
|
+ r(jsonData)
|
|
|
+ }).catch(e => {
|
|
|
+ // Message.error('试卷文件读取失败')
|
|
|
+ j(e)
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ j(e)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ /* 获取完整的试卷数据 */
|
|
|
+ getStuPaper(paper, examScope) {
|
|
|
+ let curScope = examScope || paper.scope
|
|
|
+ console.log(...arguments);
|
|
|
+ return new Promise(async (r, j) => {
|
|
|
+ // let blobHost = this.getBlobHost()
|
|
|
+ // 根据试卷的Blob地址 去读取JSON文件
|
|
|
+ let cntr = paper.code
|
|
|
+ let sas = await $tools.getBlobSas(cntr)
|
|
|
+ let sasString = "?" + sas.sas
|
|
|
+ let blobHost = sas.url
|
|
|
+ let paperBlobPath = blobHost + '/' + cntr + paper.blob
|
|
|
+ let fullPath = paperBlobPath + '/index.json' + sasString
|
|
|
+ console.log(fullPath);
|
|
|
+ try {
|
|
|
+ let jsonInfo = await $tools.getFile(fullPath)
|
|
|
+ let jsonData = JSON.parse(jsonInfo)
|
|
|
+ jsonData.scope = curScope
|
|
|
+ jsonData.code = paper.code
|
|
|
+ jsonData.sheet = paper.sheet || null
|
|
|
+ paper.tags = paper.tags || jsonData.tags
|
|
|
+ // 获取试卷包含的试题数据并包装好
|
|
|
+ if (jsonData.slides && jsonData.slides.length) {
|
|
|
+ jsonData.item = []
|
|
|
+ let promiseArr = []
|
|
|
+ jsonData.slides.forEach((item, index) => {
|
|
|
+ promiseArr.push(new Promise(async (resolve, reject) => {
|
|
|
+ // 获取题目JSON并且包装成完整试题对象
|
|
|
+ let itemFullPath = paperBlobPath + '/' + item.url + sasString
|
|
|
+ let itemJson = JSON.parse(await $tools.getFile(itemFullPath))
|
|
|
+ itemJson.exercise.question = itemJson.item[0].question
|
|
|
+ itemJson.exercise.option = itemJson.item[0].option
|
|
|
+ itemJson.exercise.id = itemJson.id
|
|
|
+ itemJson.exercise.pid = itemJson.pid
|
|
|
+ itemJson.exercise.scope = curScope
|
|
|
+ itemJson.exercise.score = item.scoring ? item.scoring.score : 0
|
|
|
+ // jsonData.item.push(itemJson.exercise)
|
|
|
+ try {
|
|
|
+ itemJson.exercise = await this.doAddHost(itemJson.exercise, paper, paper.code, null, sasString)
|
|
|
+ resolve(itemJson.exercise)
|
|
|
+ } catch (e) {
|
|
|
+ reject(e)
|
|
|
+ }
|
|
|
+ }))
|
|
|
+ })
|
|
|
+ Promise.all(promiseArr).then(res => {
|
|
|
+ res.forEach((resItem, resIndex) => {
|
|
|
+ resItem.children = []
|
|
|
+ if (resItem.pid) {
|
|
|
+ let pItem = res.filter(i => i.id === resItem.pid)[0]
|
|
|
+ pItem.children.push(resItem)
|
|
|
+ pItem.score = pItem.score + resItem.score
|
|
|
+ }
|
|
|
+ })
|
|
|
+ jsonData.item = res.filter(i => !i.pid)
|
|
|
+ r(jsonData)
|
|
|
+ }).catch(e => {
|
|
|
+ j(e)
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ j(e)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ // 艺术测评专用获取试卷方案
|
|
|
+ getStuPaperForArt(paper, examScope, sas) {
|
|
|
+ let curScope = examScope || paper.scope
|
|
|
+ console.log(...arguments);
|
|
|
+ return new Promise(async (r, j) => {
|
|
|
+ // let blobHost = this.getBlobHost()
|
|
|
+ // 根据试卷的Blob地址 去读取JSON文件
|
|
|
+ let cntr = paper.code
|
|
|
+ let sasString = "?" + sas.sas
|
|
|
+ let blobHost = sas.url
|
|
|
+ let paperBlobPath = blobHost + '/' + cntr + paper.blob
|
|
|
+ let fullPath = paperBlobPath + '/index.json' + sasString
|
|
|
+ console.log(fullPath);
|
|
|
+ try {
|
|
|
+ let jsonInfo = await $tools.getFile(fullPath)
|
|
|
+ let jsonData = JSON.parse(jsonInfo)
|
|
|
+ jsonData.scope = curScope
|
|
|
+ jsonData.code = paper.code
|
|
|
+ jsonData.sheet = paper.sheet || null
|
|
|
+ paper.tags = paper.tags || jsonData.tags
|
|
|
+ r(jsonData)
|
|
|
+ // 获取试卷包含的试题数据并包装好
|
|
|
+ // if (jsonData.slides && jsonData.slides.length) {
|
|
|
+ // jsonData.item = []
|
|
|
+ // let promiseArr = []
|
|
|
+ // jsonData.slides.forEach((item, index) => {
|
|
|
+ // promiseArr.push(new Promise(async (resolve, reject) => {
|
|
|
+ // // 获取题目JSON并且包装成完整试题对象
|
|
|
+ // let itemFullPath = paperBlobPath + '/' + item.url + sasString
|
|
|
+ // let itemJson = JSON.parse(await $tools.getFile(itemFullPath))
|
|
|
+ // itemJson.exercise.question = itemJson.item[0].question
|
|
|
+ // itemJson.exercise.option = itemJson.item[0].option
|
|
|
+ // itemJson.exercise.id = itemJson.id
|
|
|
+ // itemJson.exercise.pid = itemJson.pid
|
|
|
+ // itemJson.exercise.scope = curScope
|
|
|
+ // itemJson.exercise.score = item.scoring ? item.scoring.score : 0
|
|
|
+ // // jsonData.item.push(itemJson.exercise)
|
|
|
+ // try {
|
|
|
+ // itemJson.exercise = await this.doAddHost(itemJson.exercise, paper, paper.code, null, sasString)
|
|
|
+ // resolve(itemJson.exercise)
|
|
|
+ // } catch (e) {
|
|
|
+ // reject(e)
|
|
|
+ // }
|
|
|
+ // }))
|
|
|
+ // })
|
|
|
+ // Promise.all(promiseArr).then(res => {
|
|
|
+ // res.forEach((resItem, resIndex) => {
|
|
|
+ // resItem.children = []
|
|
|
+ // if (resItem.pid) {
|
|
|
+ // let pItem = res.filter(i => i.id === resItem.pid)[0]
|
|
|
+ // pItem.children.push(resItem)
|
|
|
+ // pItem.score = pItem.score + resItem.score
|
|
|
+ // }
|
|
|
+ // })
|
|
|
+ // jsonData.item = res.filter(i => !i.pid)
|
|
|
+ // r(jsonData)
|
|
|
+ // }).catch(e => {
|
|
|
+ // j(e)
|
|
|
+ // })
|
|
|
+ // }
|
|
|
+ } catch (e) {
|
|
|
+ j(e)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ /* 获取完整的试卷数据 */
|
|
|
+ getComposeItem(paper) {
|
|
|
+ return new Promise(async (r, j) => {
|
|
|
+ console.log(paper);
|
|
|
+ // 根据试卷的Blob地址 去读取JSON文件
|
|
|
+ let cntr = paper.code
|
|
|
+ let sas = await $tools.getBlobSas(cntr)
|
|
|
+ let sasString = sas.sas
|
|
|
+ let fullPath = paper.blob + "?" + sasString
|
|
|
+ try {
|
|
|
+ let jsonInfo = await $tools.getFile(fullPath)
|
|
|
+ let jsonData = JSON.parse(jsonInfo)
|
|
|
+ // 获取试卷包含的试题数据并包装好
|
|
|
+ if (jsonData.length) {
|
|
|
+ r(jsonData)
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ j(e)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ /* 提取富文本内容中的文本 */
|
|
|
+ getSimpleText(html) {
|
|
|
+ var r = /<\/?(img)[^>]*>/gi;
|
|
|
+ return html.replace(r, "");
|
|
|
+ },
|
|
|
+ /* 判断是否为客观题 */
|
|
|
+ getItemType(type) {
|
|
|
+ const objective = ['single', 'multiple', 'judge']
|
|
|
+ return objective.includes(type)
|
|
|
+ },
|
|
|
+ /* 获取img标签内的src */
|
|
|
+ getImgSrc(richtext) {
|
|
|
+ let imgList = [];
|
|
|
+ richtext.replace(/<video [^>]*src=['"]([^'"]+)[^>]*>/g, (match, capture) => {
|
|
|
+ imgList.push(capture);
|
|
|
+ });
|
|
|
+ return imgList;
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ getPaperInfo(examId, paperId) {
|
|
|
+ return new Promise(async (resolve, reject) => {
|
|
|
+ let url = `/package/${examId}/papers/${paperId}`
|
|
|
+ let indexUrl = url + '/index.json'
|
|
|
+ try {
|
|
|
+ let jsonInfo = await $tools.getFile(indexUrl)
|
|
|
+ let jsonData = JSON.parse(jsonInfo)
|
|
|
+ // 获取试卷包含的试题数据并包装好
|
|
|
+ if (jsonData.slides && jsonData.slides.length) {
|
|
|
+ jsonData.item = []
|
|
|
+ let promiseArr = []
|
|
|
+ jsonData.slides.forEach((item, index) => {
|
|
|
+ promiseArr.push(new Promise(async (resolve, reject) => {
|
|
|
+ // 获取题目JSON并且包装成完整试题对象
|
|
|
+ let itemFullPath = url + '/' + item.url
|
|
|
+ let itemJson = JSON.parse(await $tools.getFile(itemFullPath))
|
|
|
+ itemJson.exercise.question = itemJson.item[0].question
|
|
|
+ itemJson.exercise.option = itemJson.item[0].option
|
|
|
+ itemJson.exercise.id = itemJson.id
|
|
|
+ itemJson.exercise.pid = itemJson.pid
|
|
|
+ // itemJson.exercise.scope = curScope
|
|
|
+ itemJson.exercise.score = item.scoring ? item.scoring.score : 0
|
|
|
+ try {
|
|
|
+ console.log('多媒体链接', await this.doAddHost(itemJson.exercise, url));
|
|
|
+ // this.processNum++
|
|
|
+ resolve(itemJson.exercise)
|
|
|
+ } catch (e) {
|
|
|
+ reject(e)
|
|
|
+ }
|
|
|
+ }))
|
|
|
+ })
|
|
|
+ Promise.all(promiseArr).then(res => {
|
|
|
+ res.forEach((resItem, resIndex) => {
|
|
|
+ resItem.children = []
|
|
|
+ if (resItem.pid) {
|
|
|
+ let pItem = res.filter(i => i.id === resItem.pid)[0]
|
|
|
+ pItem.children.push(resItem)
|
|
|
+ pItem.score = pItem.score + resItem.score
|
|
|
+ }
|
|
|
+ })
|
|
|
+ jsonData.item = res.filter(i => !i.pid)
|
|
|
+ console.log('题目详细内容', jsonData);
|
|
|
+ /* this.paperList.push(jsonData)
|
|
|
+ this.paperInfo = jsonData
|
|
|
+ this.isShowPaper = true
|
|
|
+ this.isLoading.close() */
|
|
|
+ resolve(jsonData)
|
|
|
+ }).catch(e => {
|
|
|
+ console.error('22222222222', e);
|
|
|
+ reject(undefined)
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('33333333333333', error);
|
|
|
+ reject(undefined)
|
|
|
+ /* this.$message({
|
|
|
+ message: '打开试卷失败',
|
|
|
+ type: 'error'
|
|
|
+ }); */
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ /* 给富文本添加 cntr是防止读取的是其他用户的BLOB */
|
|
|
+ async doAddHost(exerciseItem, url) {
|
|
|
+ // console.log(exerciseItem, paperItem, cntr, nodeId, sasString)
|
|
|
+ if (exerciseItem.source && exerciseItem.source === 3) {
|
|
|
+ return exerciseItem
|
|
|
+ }
|
|
|
+ /* 如果操作的是试卷内的试题 则需要拿试卷的code来作为containerName */
|
|
|
+ let isSubjective = exerciseItem.type === 'complete' || exerciseItem.type === 'subjective' || exerciseItem.type === 'compose'
|
|
|
+ let richTextObj = {
|
|
|
+ question: exerciseItem.question,
|
|
|
+ answer: Array.isArray(exerciseItem.answer) && exerciseItem.answer.length ? exerciseItem.answer[0] : exerciseItem.answer,
|
|
|
+ explain: exerciseItem.explain,
|
|
|
+ }
|
|
|
+ isSubjective && delete richTextObj.answer
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ let promiseArr = []
|
|
|
+ // 遍历题目的所有富文本内容
|
|
|
+ for (let key in richTextObj) {
|
|
|
+ promiseArr.push(new Promise(async (r, j) => {
|
|
|
+ let videoSrcList = this.getRichTextSrc(richTextObj[key], 'video')
|
|
|
+ let audioSrcList = this.getRichTextSrc(richTextObj[key], 'audio')
|
|
|
+ let srcList = videoSrcList.concat(audioSrcList)
|
|
|
+ if (srcList.length) {
|
|
|
+ console.log('要添加list', srcList)
|
|
|
+ for (let i = 0; i < srcList.length; i++) {
|
|
|
+ let src = decodeURI(srcList[i])
|
|
|
+ let showSrc = src
|
|
|
+ let spStr = src.split('.')
|
|
|
+ if(spStr[spStr.length - 1] === 'MP4' || spStr[spStr.length - 1] === 'MP3') {
|
|
|
+ showSrc = src.split('.').slice(0, -1).join('.')
|
|
|
+ showSrc = showSrc + '_1.' + spStr[spStr.length - 1]
|
|
|
+ }
|
|
|
+ let blobUrl = url + '/' + showSrc
|
|
|
+ try {
|
|
|
+ richTextObj[key] = richTextObj[key].replaceAll(`src="${src}"`, `src="${blobUrl}"`);
|
|
|
+ } catch (e) {
|
|
|
+ j(500)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (key === 'answer' && Array.isArray(exerciseItem.answer) && exerciseItem.answer.length) {
|
|
|
+ exerciseItem.answer[0] = richTextObj[key]
|
|
|
+ } else {
|
|
|
+ exerciseItem[key] = richTextObj[key]
|
|
|
+ }
|
|
|
+ r(200)
|
|
|
+ } else {
|
|
|
+ r(200)
|
|
|
+ }
|
|
|
+ }))
|
|
|
+ }
|
|
|
+ Promise.all(promiseArr).then(result => {
|
|
|
+ //console.log('添加HOST之后的',exerciseItem)
|
|
|
+ resolve(exerciseItem)
|
|
|
+ }).catch(e => {
|
|
|
+ reject(e)
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ /* 获取富文本的资源src数据 */
|
|
|
+ getRichTextSrc(richText, type) {
|
|
|
+ if (!richText) {
|
|
|
+ return []
|
|
|
+ }
|
|
|
+ var videoReg = /<video.*?(?:>|\/>)/gi;
|
|
|
+ var imgReg = /<img.*?(?:>|\/>)/gi;
|
|
|
+ var audioReg = /<audio.*?(?:>|\/>)/gi;
|
|
|
+ //匹配src属性
|
|
|
+ var srcReg = /src=[\'\"]?([^\'\"]*)[\'\"]?/i;
|
|
|
+ var arr = String(richText).match(type === 'img' ? imgReg : type === 'video' ? videoReg : audioReg);
|
|
|
+ var result = []
|
|
|
+ if (!arr || !arr.length) {
|
|
|
+ return []
|
|
|
+ } else {
|
|
|
+ for (var i = 0; i < arr.length; i++) {
|
|
|
+ var src = arr[i].match(srcReg);
|
|
|
+ //获取图片地址
|
|
|
+ if (src[1]) {
|
|
|
+ result.push(src[1])
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+}
|