import DOMPurify from 'dompurify'; import { changeNumToHan } from '@/utils/transform'; // 选项类型 export const optionTypeList = [{ value: 'letter', label: '字母' }, { value: 'number', label: '数字' }, { value: 'capital', label: '大写字母' }, { value: 'bracket_number', label: '括号数字' }, ]; // 题号选项 export const computeOptionMethods = { [optionTypeList[0].value]: (i) => `${String.fromCharCode(97 + i)}.`, [optionTypeList[1].value]: (i) => `${i + 1}.`, [optionTypeList[2].value]: (i) => `${String.fromCharCode(65 + i)}.`, // [optionTypeList[2].value]: (i) => changeNumToHan(i + 1) + '.', // [optionTypeList[3].value]: (i) => `(${i + 1})`, //中文括号 [optionTypeList[3].value]: (i) => `(${i + 1})`, //英文括号 }; /** * 改变选项类型 * @param {object} data 数据 */ export function changeOptionType(data) { let index = optionTypeList.findIndex(({ value }) => value === data.option_number_show_mode); data.option_number_show_mode = optionTypeList[index + 1]?.value || optionTypeList[0].value; } /** * 计算选项题号 * @param {Number} i 序号 * @param {String} option_number_show_mode 选项类型 * @returns String 题号 */ export function computedQuestionNumber(i, option_number_show_mode) { const computationMethod = computeOptionMethods[option_number_show_mode]; if (computationMethod) { return computationMethod(i); } return ''; } // 题干类型 export const stemTypeList = [{ value: 'text', label: '纯文本' }, { value: 'rich', label: '富文本' }, ]; // 分值类型 export const scoreTypeList = [{ value: 'aggregate', label: '总分' }, { value: 'subdivision', label: '细分' }, ]; // 选择类型 export const selectTypeList = [{ value: 'single', label: '单选' }, { value: 'multiple', label: '多选' }, ]; // 开关选项 export const switchOption = [{ value: 'true', label: '开启' }, { value: 'false', label: '关闭' }, ]; // 题号类型 export const questionNumberTypeList = [{ value: 'recalculate', label: '重新计算' }, { value: 'follow', label: '跟随上题' }, ]; // 选项类型列表 export const option_type_list = [{ value: 'right', label: '是' }, { value: 'error', label: '非' }, { value: 'incertitude', label: '不确定' }, ]; // 布局方式,horizontal 【横排】,vertical【竖排】 export const layout_type_list = [{ value: 'horizontal', label: '横排' }, { value: 'vertical', label: '竖排' } ]; // 答题模式列表 export const answer_mode_list = [{ value: 1, label: '练习模式' }, { value: 2, label: '考试模式' } ]; // 答题模式列表 export const answer_status_list = [{ value: 0, label: '未作答' }, { value: 1, label: '客观题(正确)' }, { value: 2, label: '客观题(错误)' }, { value: 3, label: '主观题(已答)' } ]; // 任务时间类型列表 export const time_type_list = [{ value: 0, label: '课前任务' }, { value: 1, label: '课中任务' }, { value: 2, label: '课后任务' }, { value: 3, label: '练习任务' } ]; // 任务完成状态列表 export const task_finish_status_list = [{ value: 0, label: '未开始' }, { value: 1, label: '进行中' }, { value: 2, label: '结束' } ]; export const questionData = { share_record_id: '', parentType: '', answer_record_id: '', question_id: '', type: '', // 题型 stem: '', // 题干 option_number_show_mode: optionTypeList[0].value, // 选项类型 description: '', // 描述 option_list: [{ content: '', mark: '', answer: '', checked: false }], // 选项 question_list: [{ //阅读题特有 id: '', // 小题id type: '', // 小题类型 additional_type: '', // 附加类型多选单选等 }], file_id_list: [], // 文件 id 列表 file_list: [], audioSrc: '', answer: { answer_list: [], score: 0, score_type: scoreTypeList[0].value, }, // 答案 // 题型属性 property: { stem_type: stemTypeList[0].value, // 题干类型 question_number: 1, // 题号 is_enable_description: false, // 描述 select_type: selectTypeList[0].value, // 选择类型 is_enable_listening: true, // 是否听力 score: 1, // 分值 score_type: scoreTypeList[0].value, // 分值类型 }, // 其他属性 other: { question_number_type: questionNumberTypeList[0].value, // 题号类型 }, user_answer: {}, audio: new Audio(), playing: false, isSubSub: false, //子组件的子组件 isLoaded: false, //数据加载完成 remark: {}, //教师批注 answer_mode: 1, //答题模式 /** * 阅读题专用,用于切换题目时给阅读题小题答题控制赋值 */ isReadQuestionWatch: false, } export const answer_control = {}; //是否直接切换题目索引 export const isSwitchQuestionIndex = {}; /** * 过滤 html,防止 xss 攻击 * @param {String} html 需要过滤的html * @returns {String} 过滤后的html */ export function sanitizeHTML(html) { html = html.replace(/]*>/g, function(match) { if (match.includes('controlsList="')) { return match.replace(/controlsList="[^"]*"/, 'controlsList="nodownload nodirection noplaybackrate" disablePictureInPicture'); } else { return match.replace('>', ' controlsList="nodownload nodirection noplaybackrate" disablePictureInPicture>'); } }); var platform = "android"; uni.getSystemInfo({ success: function(res) { platform = res.platform; // 操作系统类型,如 "android", "ios" 等 } }); if (platform === "android") { html = html.replace(/]*>/g, function(match) { if (match.includes('controlsList="')) { return match.replace(/controlsList="[^"]*"/, 'controlsList="nodownload nodirection noplaybackrate" style="height:47px"'); } else { return match.replace('>', ' controlsList="nodownload nodirection noplaybackrate" style="height:47px">'); } }); html = html.replace(/

]*>/g, function(match) { return match.replace('

', '

'); }); } else { html = html.replace(/]*>/g, function(match) { if (match.includes('controlsList="')) { return match.replace(/controlsList="[^"]*"/, 'controlsList="nodownload nodirection noplaybackrate" style="height:27px;margin:0"'); } else { return match.replace('>', ' controlsList="nodownload nodirection noplaybackrate" style="height:27px;margin:0">'); } }); html = html.replace(/

]*>/g, function(match) { return match.replace('

', '

' ); }); } return DOMPurify.sanitize(html); } /** * 是否开启 * @param {String} value 值 * @returns Boolean */ export function isEnable(value) { return value === switchOption[0].value; } export const tone_data = [ ['ā', 'á', 'ǎ', 'à', 'a'], ['ō', 'ó', 'ǒ', 'ò', 'o'], ['ē', 'é', 'ě', 'è', 'e'], ['ī', 'í', 'ǐ', 'ì', 'i'], ['ū', 'ú', 'ǔ', 'ù', 'u'], ['ǖ', 'ǘ', 'ǚ', 'ǜ', 'ü'], ['ǖ', 'ǘ', 'ǚ', 'ǜ', 'ü'], ['Ā', 'Á', 'Â', 'À', 'A'], ['Ō', 'Ó', 'Ô', 'Ò', 'O'], ['Ē', 'É', 'Ê', 'È', 'E'], ['Ī', 'Í', 'Î', 'Ì', 'I'], ['Ū', 'Ú', 'Û', 'Ù', 'U'], ]; /** * 添加声调 * @param {Number} number * @param {String} con * @returns String */ export function addTone(number, con) { const zmList = ['a', 'o', 'e', 'i', 'u', 'v', 'ü', 'A', 'O', 'E', 'I', 'U']; let cons = con; if (number) { for (let i = 0; i < zmList.length; i++) { let zm = zmList[i]; if (con.includes(zm)) { let zm2 = tone_data[i][number - 1]; if (con.includes('iu')) { zm2 = tone_data[4][number - 1]; cons = con.replace('u', zm2); } else if (con.includes('ui')) { zm2 = tone_data[3][number - 1]; cons = con.replace('i', zm2); } else if (/yv|jv|qv|xv/.test(con)) { zm2 = tone_data[4][number - 1]; cons = con.replace('v', zm2); } else if (/yü|jü|qü|xü/.test(con)) { zm2 = tone_data[4][number - 1]; cons = con.replace('ü', zm2); } else { cons = con.replace(zm, zm2); } break; } } } return cons; } export function handleToneValue(valItem) { let numList = []; if (/[A-Za-zü]+\d/g.test(valItem)) { valItem.split('').forEach((item, i) => { if (/\d/.test(item)) { let numIndex = numList.length === 0 ? 0 : numList[numList.length - 1].index; let con = valItem.substring(numIndex, i).replace(/\d/g, ''); numList.push({ number: item, con, }); } }); } else { numList = []; } return numList.length === 0 ? [{ con: valItem }] : numList; } export const svgNS = 'http://www.w3.org/2000/svg'; // SVG命名空间