|
@@ -1,18 +1,25 @@
|
|
<template>
|
|
<template>
|
|
<div :class="['report', { 'is-print': viewType === 'print' }]">
|
|
<div :class="['report', { 'is-print': viewType === 'print' }]">
|
|
<ReportCover :paper="sasPaper" :hasCompareProject="hasCompareProject" />
|
|
<ReportCover :paper="sasPaper" :hasCompareProject="hasCompareProject" />
|
|
- <ReportCompare v-if="hasCompareProject" :paper="sasPaper" />
|
|
|
|
|
|
+ <ReportCompare
|
|
|
|
+ v-if="hasCompareProject && comparePapers.length && compareCourses.length"
|
|
|
|
+ :scoreGap="scoreGap"
|
|
|
|
+ :comparePapers="comparePapers"
|
|
|
|
+ :compareCourses="compareCourses"
|
|
|
|
+ />
|
|
<ReportSummary
|
|
<ReportSummary
|
|
- v-if="sasPaper"
|
|
|
|
|
|
+ v-if="sasPaper.id"
|
|
:paper="sasPaper"
|
|
:paper="sasPaper"
|
|
:partNo="partNos.summary"
|
|
:partNo="partNos.summary"
|
|
/>
|
|
/>
|
|
<ReportScore
|
|
<ReportScore
|
|
|
|
+ v-if="sasCourse.id"
|
|
:course="sasCourse"
|
|
:course="sasCourse"
|
|
:scoreGap="scoreGap"
|
|
:scoreGap="scoreGap"
|
|
:partNo="partNos.score"
|
|
:partNo="partNos.score"
|
|
/>
|
|
/>
|
|
<ReportScoreGroup
|
|
<ReportScoreGroup
|
|
|
|
+ v-if="sasCourse.id"
|
|
:course="sasCourse"
|
|
:course="sasCourse"
|
|
:scoreGap="scoreGap"
|
|
:scoreGap="scoreGap"
|
|
:partNo="partNos.scoreGroup"
|
|
:partNo="partNos.scoreGroup"
|
|
@@ -33,7 +40,7 @@
|
|
:partNo="partNos.discrimination"
|
|
:partNo="partNos.discrimination"
|
|
/>
|
|
/>
|
|
<ReportQuestionGroup
|
|
<ReportQuestionGroup
|
|
- v-if="sasPaper && paperQuestions.length"
|
|
|
|
|
|
+ v-if="sasPaper.id && paperQuestions.length"
|
|
:questions="paperQuestions"
|
|
:questions="paperQuestions"
|
|
:paper="sasPaper"
|
|
:paper="sasPaper"
|
|
:partNo="partNos.questionGroup"
|
|
:partNo="partNos.questionGroup"
|
|
@@ -47,6 +54,10 @@ import {
|
|
getPaperQuestions,
|
|
getPaperQuestions,
|
|
getSasPaper,
|
|
getSasPaper,
|
|
} from "@/api/paperAnalysisPage";
|
|
} from "@/api/paperAnalysisPage";
|
|
|
|
+import {
|
|
|
|
+ getPaperCompareList,
|
|
|
|
+ getPaperCompareScoreList,
|
|
|
|
+} from "@/api/projectCompareDetailPage";
|
|
import { getSasCourseList } from "@/api/allAnalysisPage";
|
|
import { getSasCourseList } from "@/api/allAnalysisPage";
|
|
import ReportCover from "./ReportCover.vue";
|
|
import ReportCover from "./ReportCover.vue";
|
|
import ReportCompare from "./ReportCompare.vue";
|
|
import ReportCompare from "./ReportCompare.vue";
|
|
@@ -61,7 +72,7 @@ import { RANGE_POINT_TYPE } from "@/constants/constants";
|
|
|
|
|
|
import { SASPaper, SASQuestion, SasCourse, RangeConfig } from "@/types";
|
|
import { SASPaper, SASQuestion, SasCourse, RangeConfig } from "@/types";
|
|
import { useRoute } from "vue-router";
|
|
import { useRoute } from "vue-router";
|
|
-import { computed, onMounted } from "vue";
|
|
|
|
|
|
+import { computed, onMounted, nextTick, reactive } from "vue";
|
|
|
|
|
|
let courseId = $ref(undefined as unknown as number);
|
|
let courseId = $ref(undefined as unknown as number);
|
|
let sasPaper = $ref<SASPaper>({} as SASPaper);
|
|
let sasPaper = $ref<SASPaper>({} as SASPaper);
|
|
@@ -74,8 +85,11 @@ const paperId = +route.params.paperId;
|
|
const compareProjectId = +route.params.compareProjectId;
|
|
const compareProjectId = +route.params.compareProjectId;
|
|
const viewType = route.params.viewType;
|
|
const viewType = route.params.viewType;
|
|
|
|
|
|
|
|
+let comparePapers = $ref<SASPaper[]>([]);
|
|
|
|
+let compareCourses = $ref<SasCourse[]>([]);
|
|
|
|
+
|
|
let paperQuestions = $ref<SASQuestion[]>([]);
|
|
let paperQuestions = $ref<SASQuestion[]>([]);
|
|
-let partNos = $shallowRef({
|
|
|
|
|
|
+let partNos = reactive({
|
|
summary: "二",
|
|
summary: "二",
|
|
score: "三",
|
|
score: "三",
|
|
scoreGroup: "四",
|
|
scoreGroup: "四",
|
|
@@ -90,19 +104,38 @@ const hasCompareProject = computed(() => !!compareProjectId);
|
|
onMounted(async () => {
|
|
onMounted(async () => {
|
|
await fetchData();
|
|
await fetchData();
|
|
|
|
|
|
- if (!hasCompareProject.value) {
|
|
|
|
- partNos = {
|
|
|
|
- summary: "一",
|
|
|
|
- score: "二",
|
|
|
|
- scoreGroup: "三",
|
|
|
|
- question: "四",
|
|
|
|
- difficulty: "五",
|
|
|
|
- discrimination: "六",
|
|
|
|
- questionGroup: "七",
|
|
|
|
- };
|
|
|
|
- }
|
|
|
|
|
|
+ await nextTick();
|
|
|
|
+
|
|
|
|
+ commonInfoUpdate();
|
|
|
|
+ publishReady();
|
|
});
|
|
});
|
|
|
|
|
|
|
|
+function commonInfoUpdate() {
|
|
|
|
+ document.querySelectorAll(".report-page").forEach((dom, index) => {
|
|
|
|
+ if (!index) return;
|
|
|
|
+ let page = index + 1;
|
|
|
|
+ let pageStr = index < 9 ? "0" + page : page + "";
|
|
|
|
+ const footDom = dom.querySelector(".report-pfoot");
|
|
|
|
+ if (footDom) {
|
|
|
|
+ footDom.innerHTML = `PAGE ${pageStr}`;
|
|
|
|
+ }
|
|
|
|
+ const nameDom = dom.querySelector(".report-name");
|
|
|
|
+ if (nameDom) {
|
|
|
|
+ nameDom.innerHTML = `${sasPaper.projectName}成绩分析报告`;
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function publishReady() {
|
|
|
|
+ const eventEmitInterval = setInterval(function () {
|
|
|
|
+ document.body.dispatchEvent(new Event("view-ready"));
|
|
|
|
+ }, 25);
|
|
|
|
+
|
|
|
|
+ document.body.addEventListener("view-ready-acknowledged", function () {
|
|
|
|
+ clearInterval(eventEmitInterval);
|
|
|
|
+ });
|
|
|
|
+}
|
|
|
|
+
|
|
function numberPrecision(num: number) {
|
|
function numberPrecision(num: number) {
|
|
return Math.round(num * 100) / 100;
|
|
return Math.round(num * 100) / 100;
|
|
}
|
|
}
|
|
@@ -112,6 +145,21 @@ async function fetchData() {
|
|
await fetchSasPaper();
|
|
await fetchSasPaper();
|
|
await fetchPaperQuestions();
|
|
await fetchPaperQuestions();
|
|
await fetchSasCourse();
|
|
await fetchSasCourse();
|
|
|
|
+
|
|
|
|
+ if (hasCompareProject.value) {
|
|
|
|
+ await fetchComparePaperData();
|
|
|
|
+ await fetchCompareCourseData();
|
|
|
|
+ } else {
|
|
|
|
+ partNos = {
|
|
|
|
+ summary: "一",
|
|
|
|
+ score: "二",
|
|
|
|
+ scoreGroup: "三",
|
|
|
|
+ question: "四",
|
|
|
|
+ difficulty: "五",
|
|
|
|
+ discrimination: "六",
|
|
|
|
+ questionGroup: "七",
|
|
|
|
+ };
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
async function fetchPaper() {
|
|
async function fetchPaper() {
|
|
@@ -161,14 +209,52 @@ async function fetchSasCourse() {
|
|
courseId,
|
|
courseId,
|
|
});
|
|
});
|
|
|
|
|
|
- sasCourse = res.data[0];
|
|
|
|
|
|
+ sasCourse = parseSasCourse(res.data[0]);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function scoreTitle(rangeConfig: RangeConfig) {
|
|
|
|
+ if (!rangeConfig) return false;
|
|
|
|
+ if (rangeConfig.type === "ZERO") return "0-";
|
|
|
|
|
|
- sasCourse.scoreRange = Object.values(
|
|
|
|
|
|
+ return `${rangeConfig.baseScore + rangeConfig.adjustScore}(${
|
|
|
|
+ RANGE_POINT_TYPE[rangeConfig.type]
|
|
|
|
+ }${rangeConfig.adjustScore > 0 ? "+" : ""}${rangeConfig.adjustScore})-`;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+async function fetchComparePaperData() {
|
|
|
|
+ const res = await getPaperCompareList({
|
|
|
|
+ projectIds: [compareProjectId],
|
|
|
|
+ contrastProjectId: projectId,
|
|
|
|
+ courseCode: sasPaper.courseCode,
|
|
|
|
+ });
|
|
|
|
+ comparePapers = res.data.map((v) => {
|
|
|
|
+ v.avgScore = numberPrecision(v.avgScore);
|
|
|
|
+ v.stdev = numberPrecision(v.stdev);
|
|
|
|
+ v.coefficient = numberPrecision(v.coefficient);
|
|
|
|
+ v.difficulty = numberPrecision(v.difficulty);
|
|
|
|
+ v.reliability1 = numberPrecision(v.reliability1);
|
|
|
|
+ return v;
|
|
|
|
+ });
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+async function fetchCompareCourseData() {
|
|
|
|
+ const res = await getPaperCompareScoreList({
|
|
|
|
+ projectIds: [compareProjectId],
|
|
|
|
+ contrastProjectId: projectId,
|
|
|
|
+ courseCode: sasPaper.courseCode,
|
|
|
|
+ });
|
|
|
|
+ compareCourses = res.data.map((v) => {
|
|
|
|
+ return parseSasCourse(v);
|
|
|
|
+ });
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function parseSasCourse(course: SasCourse) {
|
|
|
|
+ course.scoreRange = Object.values(
|
|
// eslint-disable-next-line
|
|
// eslint-disable-next-line
|
|
- JSON.parse(<string>(<unknown>sasCourse.scoreRange) || "{}")
|
|
|
|
|
|
+ JSON.parse(<string>(<unknown>course.scoreRange) || "{}")
|
|
);
|
|
);
|
|
- sasCourse.rangeConfig = JSON.parse(
|
|
|
|
- <string>(<unknown>sasCourse.rangeConfig) || "0"
|
|
|
|
|
|
+ course.rangeConfig = JSON.parse(
|
|
|
|
+ <string>(<unknown>course.rangeConfig) || "0"
|
|
) || [
|
|
) || [
|
|
{
|
|
{
|
|
type: "ZERO",
|
|
type: "ZERO",
|
|
@@ -177,86 +263,78 @@ async function fetchSasCourse() {
|
|
},
|
|
},
|
|
];
|
|
];
|
|
let acc = 0;
|
|
let acc = 0;
|
|
- if (Array.isArray(sasCourse.scoreRange))
|
|
|
|
- sasCourse.scoreRangeAcc = sasCourse.scoreRange.map((_v, i, a) => {
|
|
|
|
|
|
+ if (Array.isArray(course.scoreRange))
|
|
|
|
+ course.scoreRangeAcc = course.scoreRange.map((_v, i, a) => {
|
|
acc += a[i];
|
|
acc += a[i];
|
|
return acc;
|
|
return acc;
|
|
});
|
|
});
|
|
- sasCourse.scoreRangeTotal = acc;
|
|
|
|
|
|
+ course.scoreRangeTotal = acc;
|
|
|
|
|
|
- sasCourse.segements = [];
|
|
|
|
- const validSeg = Math.round(sasCourse.totalScore / scoreGap);
|
|
|
|
|
|
+ course.segements = [];
|
|
|
|
+ const validSeg = Math.round(course.totalScore / scoreGap);
|
|
for (let score = 0; score < validSeg; score++) {
|
|
for (let score = 0; score < validSeg; score++) {
|
|
const row = [];
|
|
const row = [];
|
|
row[0] = score * scoreGap;
|
|
row[0] = score * scoreGap;
|
|
- let nextScore = score + 1 > validSeg ? sasCourse.totalScore : score + 1;
|
|
|
|
- row[1] = sasCourse.scoreRange
|
|
|
|
|
|
+ let nextScore = score + 1 > validSeg ? course.totalScore : score + 1;
|
|
|
|
+ row[1] = course.scoreRange
|
|
.slice(row[0], nextScore * scoreGap)
|
|
.slice(row[0], nextScore * scoreGap)
|
|
.reduce((p, c) => p + c, 0);
|
|
.reduce((p, c) => p + c, 0);
|
|
row[2] = numberPrecision(
|
|
row[2] = numberPrecision(
|
|
- (100 * row[1]) / sasCourse.scoreRangeAcc[sasCourse.totalScore]
|
|
|
|
|
|
+ (100 * row[1]) / course.scoreRangeAcc[course.totalScore]
|
|
);
|
|
);
|
|
const endGap =
|
|
const endGap =
|
|
- nextScore * scoreGap - 1 >= sasCourse.totalScore
|
|
|
|
- ? sasCourse.totalScore
|
|
|
|
|
|
+ nextScore * scoreGap - 1 >= course.totalScore
|
|
|
|
+ ? course.totalScore
|
|
: nextScore * scoreGap - 1;
|
|
: nextScore * scoreGap - 1;
|
|
- row[3] = sasCourse.scoreRangeAcc[endGap];
|
|
|
|
|
|
+ row[3] = course.scoreRangeAcc[endGap];
|
|
row[4] = numberPrecision(
|
|
row[4] = numberPrecision(
|
|
- (100 * row[3]) / sasCourse.scoreRangeAcc[sasCourse.totalScore]
|
|
|
|
|
|
+ (100 * row[3]) / course.scoreRangeAcc[course.totalScore]
|
|
);
|
|
);
|
|
- sasCourse.segements.push(row);
|
|
|
|
|
|
+ course.segements.push(row);
|
|
}
|
|
}
|
|
- if (validSeg * scoreGap === sasCourse.totalScore) {
|
|
|
|
- sasCourse.segements.push([
|
|
|
|
- sasCourse.totalScore,
|
|
|
|
- sasCourse.scoreRange[sasCourse.totalScore],
|
|
|
|
- sasCourse.scoreRange[sasCourse.totalScore] /
|
|
|
|
- sasCourse.scoreRangeAcc[sasCourse.totalScore],
|
|
|
|
- sasCourse.scoreRangeAcc[sasCourse.totalScore],
|
|
|
|
|
|
+ if (validSeg * scoreGap === course.totalScore) {
|
|
|
|
+ course.segements.push([
|
|
|
|
+ course.totalScore,
|
|
|
|
+ course.scoreRange[course.totalScore],
|
|
|
|
+ course.scoreRange[course.totalScore] /
|
|
|
|
+ course.scoreRangeAcc[course.totalScore],
|
|
|
|
+ course.scoreRangeAcc[course.totalScore],
|
|
100,
|
|
100,
|
|
]);
|
|
]);
|
|
}
|
|
}
|
|
|
|
|
|
- sasCourse.rangeSegements = [];
|
|
|
|
- for (let i = 0; i < sasCourse.rangeConfig.length; i++) {
|
|
|
|
- const range = sasCourse.rangeConfig[i]!;
|
|
|
|
|
|
+ course.rangeSegements = [];
|
|
|
|
+ for (let i = 0; i < course.rangeConfig.length; i++) {
|
|
|
|
+ const range = course.rangeConfig[i]!;
|
|
const nextRange =
|
|
const nextRange =
|
|
- i === sasCourse.rangeConfig.length - 1
|
|
|
|
- ? { baseScore: sasCourse.totalScore, adjustScore: 0 }
|
|
|
|
- : sasCourse.rangeConfig[i + 1];
|
|
|
|
|
|
+ i === course.rangeConfig.length - 1
|
|
|
|
+ ? { baseScore: course.totalScore, adjustScore: 0 }
|
|
|
|
+ : course.rangeConfig[i + 1];
|
|
const row = [];
|
|
const row = [];
|
|
row[0] = scoreTitle(range);
|
|
row[0] = scoreTitle(range);
|
|
row[1] =
|
|
row[1] =
|
|
- sasCourse.scoreRange
|
|
|
|
|
|
+ course.scoreRange
|
|
.slice(
|
|
.slice(
|
|
range.baseScore + range.adjustScore,
|
|
range.baseScore + range.adjustScore,
|
|
nextRange.baseScore + nextRange.adjustScore
|
|
nextRange.baseScore + nextRange.adjustScore
|
|
)
|
|
)
|
|
.reduce((p, c) => p + c, 0) || 0;
|
|
.reduce((p, c) => p + c, 0) || 0;
|
|
- row[2] = numberPrecision((100 * row[1]) / sasCourse.scoreRangeTotal);
|
|
|
|
|
|
+ row[2] = numberPrecision((100 * row[1]) / course.scoreRangeTotal);
|
|
row[3] =
|
|
row[3] =
|
|
- sasCourse.scoreRangeAcc[
|
|
|
|
- nextRange.baseScore + nextRange.adjustScore - 1
|
|
|
|
- ] || 0;
|
|
|
|
|
|
+ course.scoreRangeAcc[nextRange.baseScore + nextRange.adjustScore - 1] ||
|
|
|
|
+ 0;
|
|
if (
|
|
if (
|
|
nextRange.baseScore + nextRange.adjustScore >=
|
|
nextRange.baseScore + nextRange.adjustScore >=
|
|
- sasCourse.scoreRangeAcc.length
|
|
|
|
|
|
+ course.scoreRangeAcc.length
|
|
) {
|
|
) {
|
|
- row[3] = sasCourse.scoreRangeAcc[sasCourse.scoreRangeAcc.length - 1];
|
|
|
|
|
|
+ row[3] = course.scoreRangeAcc[course.scoreRangeAcc.length - 1];
|
|
}
|
|
}
|
|
- row[4] = numberPrecision((100 * row[3]) / sasCourse.scoreRangeTotal);
|
|
|
|
|
|
+ row[4] = numberPrecision((100 * row[3]) / course.scoreRangeTotal);
|
|
|
|
|
|
- sasCourse.rangeSegements.push(row);
|
|
|
|
|
|
+ course.rangeSegements.push(row);
|
|
}
|
|
}
|
|
|
|
|
|
- function scoreTitle(rangeConfig: RangeConfig) {
|
|
|
|
- if (!rangeConfig) return false;
|
|
|
|
- if (rangeConfig.type === "ZERO") return "0-";
|
|
|
|
-
|
|
|
|
- return `${rangeConfig.baseScore + rangeConfig.adjustScore}(${
|
|
|
|
- RANGE_POINT_TYPE[rangeConfig.type]
|
|
|
|
- }${rangeConfig.adjustScore > 0 ? "+" : ""}${rangeConfig.adjustScore})-`;
|
|
|
|
- }
|
|
|
|
|
|
+ return course;
|
|
}
|
|
}
|
|
|
|
|
|
function getScoreGap(totalScore: number) {
|
|
function getScoreGap(totalScore: number) {
|