From 0f511f34c83296a7228c5829a5db524fec8936e0 Mon Sep 17 00:00:00 2001 From: Super12138 <70494801+Super12138@users.noreply.github.com> Date: Sun, 22 Sep 2024 15:24:40 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=82=E9=85=8D=E6=9C=80=E6=96=B0=E9=87=8F?= =?UTF-8?q?=E8=A1=A8=E6=96=87=E4=BB=B6=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/interfaces.ts | 137 ++++++++++++++++++------------------------ src/list/index.ts | 2 +- src/settings/index.ts | 2 +- src/test/index.ts | 27 ++------- src/test/question.ts | 4 +- src/test/scoring.ts | 94 ++++++++++++++++------------- 6 files changed, 116 insertions(+), 150 deletions(-) diff --git a/src/interfaces.ts b/src/interfaces.ts index b4464c0..efc66c5 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -2,7 +2,7 @@ import type { ListItem } from 'mdui/components/list-item.js'; export type Colors = 'green' | 'yellow' | 'orange' | 'red'; export type Languages = 'zh' | 'en'; -export type Method = 'plus' | 'average' | 'multiply'; +export type Method = 'plus' | 'average' | 'multiply' | 'division'; /** * 导航栏元素接口 @@ -121,6 +121,49 @@ export interface QuestionnairesList { // 量表文件类型接口 +/** + * 量表题目文件 + */ +export interface QuestionnaireFile { + /** + * 量表名称 + */ + name: string; + /** + * 量表介绍 + */ + description: string; + /** + * 作答提示 + */ + answerTips: string; + /** + * 结果提示&解析,支持 `HTML` 标签,用 `innerHTML` 上屏 + */ + resultTips: string; + /** + * 题目来源(引用) + * 比如从哪儿找到题目,从哪儿找的评分标准之类的 + * @type {string[]} + */ + references: string[]; + /** + * 题目选项 + * @type {OptionItem[]} + */ + options: OptionItem[]; + /** + * 题目 + * @type {QuestionItem[]} + */ + questions: QuestionItem[]; + /** + * 评分标准 + * @type {Scoring[]} + */ + scoring: Scoring[]; +} + /** * 单个选项 */ @@ -159,15 +202,17 @@ export interface QuestionItem { } /** - * 单个评分标准 + * 评分标准组 */ -export interface Criterion { +export interface Scoring { /** - * 评分组组id - * 需与题目的题目组id完全对应 - * @see QuestionItem.groupId + * 组Id */ - groupId: number; + groupId: number + /** + * 该范围对外现实的名称 + */ + name: string /** * 计算方法 * * `plus` 全部求和 @@ -175,7 +220,12 @@ export interface Criterion { * * `multiply` 求和后将结果 × 2(只返回计算后的结果) */ method: Method | string; + /** + * 分值范围 + */ + ranges: Range[] } + /** * 单个分值范围 */ @@ -203,79 +253,6 @@ export interface Range { max: number; } -/** - * 分值范围(带分组) - */ -export interface Ranges { - /** - * 范围组id - * 需与题目的题目组id完全对应 - * @see QuestionItem.groupId - */ - groupId: number; - /** - * 组名称 - */ - name: string; - /** - * 单个评分范围 - * @type {Range[]} - */ - ranges: Range[]; -} -/** - * 评分标准组 - */ -export interface Scoring { - /** - * 单个评分标准 - */ - criteria: Criterion[]; - ranges: Ranges[]; -} - -/** - * 量表题目文件 - */ -export interface QuestionnaireFile { - /** - * 量表名称 - */ - name: string; - /** - * 量表介绍 - */ - description: string; - /** - * 作答提示 - */ - answerTips: string; - /** - * 结果提示&解析,支持 `HTML` 标签,用 `innerHTML` 上屏 - */ - resultTips: string; - /** - * 题目来源(引用) - * 比如从哪儿找到题目,从哪儿找的评分标准之类的 - * @type {string[]} - */ - references: string[]; - /** - * 题目选项 - * @type {OptionItem[]} - */ - options: OptionItem[]; - /** - * 题目 - * @type {QuestionItem[]} - */ - questions: QuestionItem[]; - /** - * 评分标准 - * @type {Scoring} - */ - scoring: Scoring; -} /** * 计算完成后评分接口 diff --git a/src/list/index.ts b/src/list/index.ts index 3cfbfdf..ebfa314 100644 --- a/src/list/index.ts +++ b/src/list/index.ts @@ -24,7 +24,7 @@ document.addEventListener('listPageLoaded', async () => { const loadingTip: HTMLDivElement = document.querySelector('#loadingTip')!; const searchBar: TextField = document.querySelector('#searchBar')!; - getFile(`https://cdn.jsdelivr.net/gh/Super12138/AY-Questionnaires-DB@main/list.json?${new Date().getTime()}`) + getFile(`https://cdn.jsdelivr.net/gh/Super12138/AY-Questionnaires-DB@minify/list.json?${new Date().getTime()}`) .then((response: string) => { const json: QuestionnairesList = JSON.parse(response); const catogories: Category[] = json.categories; // 获取分组 diff --git a/src/settings/index.ts b/src/settings/index.ts index 2dbc340..d6e943a 100644 --- a/src/settings/index.ts +++ b/src/settings/index.ts @@ -26,7 +26,7 @@ document.addEventListener('settingsPageLoaded', async () => { const listVersion: HTMLParagraphElement = document.querySelector('#listVersion')!; appVersion.innerHTML = `网站版本:${VERSION_NAME}-${VARIANT}-${COMMIT_HASH} (${VERSION_CODE})`; - getFile(`https://cdn.jsdelivr.net/gh/Super12138/AY-Questionnaires-DB@main/list.json?${new Date().getTime()}`) + getFile(`https://cdn.jsdelivr.net/gh/Super12138/AY-Questionnaires-DB@minify/list.json?${new Date().getTime()}`) .then((response: string) => { const json: QuestionnairesList = JSON.parse(response); diff --git a/src/test/index.ts b/src/test/index.ts index b753d9d..163efd0 100644 --- a/src/test/index.ts +++ b/src/test/index.ts @@ -16,9 +16,8 @@ import '@mdui/icons/check--outlined.js'; import '@mdui/icons/tips-and-updates--outlined.js'; import { RadioGroup } from 'mdui/components/radio-group.js'; -import { BasicScoreResult, ButtonType, Criterion, GroupedData, QuestionnaireFile, QuestionResult, Ranges, ScoreResult, Scoring } from '../interfaces'; +import { BasicScoreResult, ButtonType, GroupedData, QuestionnaireFile, QuestionResult, ScoreResult, Scoring } from '../interfaces'; import { hide, show } from '../utils/element'; -import { LogHelper } from '../utils/LogHelper'; import { getFile } from '../utils/network'; import { showKeyboardNotice } from '../utils/notices'; import { Question } from './question'; @@ -28,7 +27,6 @@ const appTitle: TopAppBarTitle = document.querySelector('#appTitle')!; const url: URL = new URL(window.location.href); const questionnaire: string | null = url.searchParams.get("name"); const backBtn: ButtonIcon = document.querySelector('#backBtn')!; -const logHelper = LogHelper.getInstance(); enum NextButtonType { START, @@ -82,7 +80,7 @@ document.addEventListener('testPageLoaded', async () => { setUpNextButton(nextBtn, NextButtonType.START); // 获取量表json - getFile(`https://cdn.jsdelivr.net/gh/Super12138/AY-Questionnaires-DB@main/questionnaires/${questionnaire}.json?${new Date().getTime()}`) + getFile(`https://cdn.jsdelivr.net/gh/Super12138/AY-Questionnaires-DB@minify/questionnaires/${questionnaire}.json?${new Date().getTime()}`) .then((response: string) => { // 加载完了显示答题页面,隐藏加载提示 loadingTip.style.opacity = "0"; @@ -160,7 +158,6 @@ document.addEventListener('testPageLoaded', async () => { switch (currentNextBtnType) { case NextButtonType.NEXT: // “下一题”按钮 currentQuestion += 1; - logHelper.log(currentQuestion); show(questions[currentQuestion].html); hide(questions[currentQuestion - 1].html); if (currentQuestion === questionnaireTotal - 1) { @@ -212,23 +209,8 @@ document.addEventListener('testPageLoaded', async () => { acc[name].push(current.value); // 将用户分数存入数组 return acc; }, {}); - // 获取评分组 - const scoring: Scoring = json.scoring; - // 获取评分标准 - const criteria: Criterion[] = scoring.criteria; - // 获取分值范围 - const ranges: Ranges[] = scoring.ranges; - - // 获取每个评分标准,并按照groupId对其分组 - const groupedCriteria: GroupedData = criteria.reduce((acc: GroupedData, current: Criterion) => { - const name: number = current.groupId; - if (!acc[name]) { - acc[name] = []; - } - acc[name].push(current.method); - return acc; - }, {}); + const scoring: Scoring[] = json.scoring; const resultTbody: HTMLTableSectionElement = document.querySelector('#resultTbody')!; @@ -250,7 +232,7 @@ document.addEventListener('testPageLoaded', async () => { } // 将分组后的题目和分组后的评分标准匹配起来,并计算得分 - const score: ScoreResult[] = getScore(groupedQuestions, groupedCriteria, ranges); + const score: ScoreResult[] = getScore(groupedQuestions, scoring); // 将得分上屏 score.forEach((item: ScoreResult) => { const itemContainer: HTMLTableRowElement = document.createElement('tr'); @@ -296,7 +278,6 @@ document.addEventListener('testPageLoaded', async () => { currentQuestion -= 1; show(questions[currentQuestion].html); hide(questions[currentQuestion + 1].html); - logHelper.log(currentQuestion); setUpNextButton(nextBtn, NextButtonType.NEXT); previousBtn.disabled = currentQuestion === 0; updateProgress(); diff --git a/src/test/question.ts b/src/test/question.ts index 1d473a5..c702d5e 100644 --- a/src/test/question.ts +++ b/src/test/question.ts @@ -33,8 +33,8 @@ export class Question { const radio: Option = new Option(option.name, currentScoreList[index]); radioGroup.appendChild(radio.html); }); - // 测试用 生成随机数(0-3) - // const randomNumber = Math.floor(Math.random() * 5); + // 测试用 生成随机数 + // const randomNumber = Math.floor(Math.random() * 4); // radioGroup.value = randomNumber.toString(); div.appendChild(questionContent); diff --git a/src/test/scoring.ts b/src/test/scoring.ts index 8cfdf10..333f478 100644 --- a/src/test/scoring.ts +++ b/src/test/scoring.ts @@ -1,76 +1,84 @@ import { RadioGroup } from "mdui"; -import { BasicScoreResult, GroupedData, Range, Ranges, ScoreResult } from "../interfaces"; +import { BasicScoreResult, GroupedData, Range, ScoreResult, Scoring } from "../interfaces"; import { LogHelper } from "../utils/LogHelper"; const logHelper = LogHelper.getInstance(); /** * 计算最终得分 * @param groupedQuestions 分好组的题目组id+每题的分数 - * @param groupedCriteria 分好组的评分组id+评分方法 - * @param ranges 原始的范围对象 + * @param scoring 评分方法对象 * @returns 最终得分的:项目名称+得分+范围名称+显示文字颜色 */ -export function getScore(groupedQuestions: GroupedData, groupedCriteria: GroupedData, ranges: Ranges[]): ScoreResult[] { - let score: ScoreResult[] = []; +export function getScore(groupedQuestions: GroupedData, scoring: Scoring[]): ScoreResult[] { + let scoreResult: ScoreResult[] = []; - Object.entries(groupedQuestions).forEach(([key, values]: [string, string[]]) => { - const method: string[] = groupedCriteria[key][0].split(", ", 2); // 对于有参数的计算方法按照`, `进行拆分 - const operator: string = method[0]; // 使用计算方法字段进行判断 - logHelper.log(`计算方法:${operator}`); + // 解构分好组的题目Id和每题分数 + Object.entries(groupedQuestions).forEach(([questionGroupId, scores]: [string, string[]]) => { + scoring.forEach((scoreGroup: Scoring, i: number) => { + logHelper.log(`Scoring ${i}:`) + const groupId: number = scoreGroup.groupId; + if (groupId.toString() !== questionGroupId) return; - // 匹配与groupId对应的分值范围 - const group: Ranges | undefined = ranges.find((group) => group.groupId === Number.parseInt(key, 10)); - logHelper.log(group); + const groupMethod: string[] = scoreGroup.method.split(", ", 3); + const groupOperator: string = groupMethod[0]; + const ratio: number = Number.parseFloat(groupMethod[1]); + const saveFractionDigits: number = groupMethod[2] ? Number.parseInt(groupMethod[2]) : 2; - // group 被定义 - if (group) { + const groupName: string = scoreGroup.name; + const groupRages: Range[] = scoreGroup.ranges; + + /** + * 计算后的得分结果 + */ let result: number = 0; // 判断计算方法 - switch (operator) { + switch (groupOperator) { case "plus": // 求和 - result = getSum(values); - logHelper.log(`评分组 ${key} 的总和:${result}`); + result = getSum(scores); + logHelper.log(`评分组 ${questionGroupId} 的总和:${result}`); + break; + case "average": // 取平均数 + result = parseFloat((getSum(scores) / scores.length).toFixed(2)); + logHelper.log(`评分组 ${questionGroupId} 的平均值:${result}`); break; - case "average": // 平均数 - result = parseFloat((getSum(values) / values.length).toFixed(2)); // 确保输出结果为小数点后2位 - logHelper.log(`评分组 ${key} 的平均值:${result}`); + case "multiply": // 乘某个数 + result = getSum(scores) * ratio; + logHelper.log(`评分组 ${questionGroupId} 乘 ${ratio} 的结果:${result}`); break; - case "multiply": // 按照某个值翻倍 - const ratio = Number.parseFloat(method[1]); - result = getSum(values) * ratio; - logHelper.log(`评分组 ${key} 翻 ${ratio} 倍:${result}`); + case "division": // 除以某个数 + result = parseFloat((getSum(scores) / ratio).toFixed(saveFractionDigits)); // 输出保留指定小数点 + logHelper.log(`评分组 ${questionGroupId} 乘 ${ratio} 的结果:${result}`); break; default: - logHelper.error(`未知计算方法:${operator}`); + logHelper.error(`未知计算方法:${groupOperator}`); break; } - // 匹配分数的分值范围 - const matchingRange: Range | undefined = group.ranges.find((range: Range) => { - return result >= range.min && result <= range.max; + groupRages.forEach((range: Range) => { + if (result >= range.min && result <= range.max) { + scoreResult.push({ + name: groupName, + result: result, + range: range.name, + color: range.color + }); + } else { + logHelper.log("这个不是计算后得分应在的范围") + } }); - - // 拼合结果 - if (matchingRange) { - score.push({ - name: group.name, - result: result, - range: matchingRange.name, - color: matchingRange.color - }); - } - } + }); }); - return score; + + return scoreResult; } /** * 计算总分通用方法 - * @param values 得分字符串 + * @param scores 得分字符串 * @returns 总分 */ -function getSum(values: string[]): number { - return values.reduce((acc: number, current: string) => { +function getSum(scores: string[]): number { + return scores.reduce((acc: number, current: string) => { if (current !== "") { return acc + Number.parseInt(current, 10); } else {