|
@@ -0,0 +1,308 @@
|
|
|
+<template>
|
|
|
+ <div
|
|
|
+ v-if="store.currentTask"
|
|
|
+ class="mark-board-track-container"
|
|
|
+ :class="[store.setting.uiSetting['score.board.collapse'] ? 'hide' : 'show']"
|
|
|
+ >
|
|
|
+ <div class="top-container tw-flex-shrink-0 tw-flex tw-items-center">
|
|
|
+ <div class="tw-flex tw-flex-col tw-flex-1 tw-text-center">
|
|
|
+ <div class="tw-flex tw-justify-center">
|
|
|
+ <img
|
|
|
+ src="../../mark/images/totalscore.png"
|
|
|
+ style="width: 13px; height: 16px"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div>试卷总分</div>
|
|
|
+ </div>
|
|
|
+ <div class="tw-flex-1" style="font-size: 40px">
|
|
|
+ {{ markerScore > 0 ? markerScore : 0 }}
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="star"
|
|
|
+ :class="props.tagged ? 'star-yes' : 'star-no'"
|
|
|
+ @click="makeTag(!props.tagged)"
|
|
|
+ ></div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="tw-flex-grow tw-overflow-auto tw-my-5" v-if="groups">
|
|
|
+ <template v-for="(groupNumber, index) in groups" :key="index">
|
|
|
+ <div class="tw-mb-4 tw-bg-white tw-p-4">
|
|
|
+ <div
|
|
|
+ class="
|
|
|
+ tw-flex tw-justify-between tw-place-items-center
|
|
|
+ hover:tw-bg-gray-200
|
|
|
+ "
|
|
|
+ @mouseover="addFocusTrack(groupNumber, undefined, undefined)"
|
|
|
+ @mouseleave="removeFocusTrack"
|
|
|
+ >
|
|
|
+ <span class="secondary-text">分组 {{ groupNumber }}</span>
|
|
|
+ </div>
|
|
|
+ <div v-if="questions">
|
|
|
+ <template v-for="(question, index) in questions" :key="index">
|
|
|
+ <div
|
|
|
+ v-if="question.groupNumber === groupNumber"
|
|
|
+ class="
|
|
|
+ question
|
|
|
+ tw-flex tw-place-items-center tw-mb-1 tw-font-bold
|
|
|
+ hover:tw-bg-gray-200
|
|
|
+ "
|
|
|
+ @mouseover="
|
|
|
+ addFocusTrack(
|
|
|
+ undefined,
|
|
|
+ question.mainNumber,
|
|
|
+ question.subNumber
|
|
|
+ )
|
|
|
+ "
|
|
|
+ @mouseleave="removeFocusTrack"
|
|
|
+ >
|
|
|
+ <span class="tw-flex-1">
|
|
|
+ {{ question.title }} {{ question.mainNumber }}-{{
|
|
|
+ question.subNumber
|
|
|
+ }}
|
|
|
+ </span>
|
|
|
+ <span class="tw-flex-1 tw-text-center">
|
|
|
+ {{ question.score === -1 ? "未选做" : question.score || 0 }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="tw-flex tw-flex-shrink-0 tw-justify-center tw-gap-4">
|
|
|
+ <a-button
|
|
|
+ type="primary"
|
|
|
+ class="full-width-btn"
|
|
|
+ :disabled="props.isFirst"
|
|
|
+ @click="fetchTask(false)"
|
|
|
+ >
|
|
|
+ 上一个
|
|
|
+ </a-button>
|
|
|
+ <a-button
|
|
|
+ @click="fetchTask(true)"
|
|
|
+ type="primary"
|
|
|
+ class="full-width-btn"
|
|
|
+ :disabled="props.isLast"
|
|
|
+ >下一个</a-button
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import type { Question } from "@/types";
|
|
|
+import { computed, reactive, watch } from "vue";
|
|
|
+import { store } from "@/features/mark/store";
|
|
|
+
|
|
|
+const emit = defineEmits(["makeTag", "fetchTask"]);
|
|
|
+const props =
|
|
|
+ defineProps<{ tagged: boolean; isFirst: boolean; isLast: boolean }>();
|
|
|
+let checkedQuestions = reactive([] as Array<Question>);
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => store.currentTask,
|
|
|
+ () => {
|
|
|
+ checkedQuestions.splice(0);
|
|
|
+ }
|
|
|
+);
|
|
|
+const groups = computed(() => {
|
|
|
+ const gs = store.currentTask?.questionList.map((q) => q.groupNumber);
|
|
|
+ return [...new Set(gs)].sort((a, b) => a - b);
|
|
|
+});
|
|
|
+
|
|
|
+const questions = computed(() => {
|
|
|
+ const qs = store.currentTask?.questionList;
|
|
|
+ return qs;
|
|
|
+});
|
|
|
+
|
|
|
+const markerScore = computed(
|
|
|
+ () =>
|
|
|
+ (questions.value
|
|
|
+ ?.map((q) => Math.round((q.score || 0) * 100))
|
|
|
+ .reduce((acc, s) => acc + s) || 0) / 100
|
|
|
+);
|
|
|
+
|
|
|
+function addToCheckedQuestion(question: Question) {
|
|
|
+ checkedQuestions.push(question);
|
|
|
+}
|
|
|
+function removeCheckedQuestion(question: Question) {
|
|
|
+ const idx = checkedQuestions.indexOf(question);
|
|
|
+ checkedQuestions.splice(idx, 1);
|
|
|
+}
|
|
|
+function groupChecked(groupNumber: number) {
|
|
|
+ return (
|
|
|
+ checkedQuestions.filter((q) => q.groupNumber === groupNumber).length ===
|
|
|
+ questions.value?.filter((q) => q.groupNumber === groupNumber).length
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+function questionChecked(question: Question) {
|
|
|
+ return checkedQuestions.includes(question);
|
|
|
+}
|
|
|
+
|
|
|
+function questionCheckChanged(question: Question) {
|
|
|
+ const checked = questionChecked(question);
|
|
|
+ if (checked) {
|
|
|
+ removeCheckedQuestion(question);
|
|
|
+ } else {
|
|
|
+ addToCheckedQuestion(question);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function groupClicked(groupNumber: number) {
|
|
|
+ if (groupChecked(groupNumber)) {
|
|
|
+ checkedQuestions
|
|
|
+ .filter((q) => q.groupNumber === groupNumber)
|
|
|
+ .forEach((q) => {
|
|
|
+ const idx = checkedQuestions.indexOf(q);
|
|
|
+ checkedQuestions.splice(idx, 1);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ questions.value
|
|
|
+ ?.filter((q) => q.groupNumber === groupNumber)
|
|
|
+ .forEach((q) => {
|
|
|
+ if (!questionChecked(q)) checkedQuestions.push(q);
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function addFocusTrack(
|
|
|
+ groupNumber: number | undefined,
|
|
|
+ mainNumber: number | undefined,
|
|
|
+ subNumber: string | undefined
|
|
|
+) {
|
|
|
+ store.focusTracks.splice(0);
|
|
|
+
|
|
|
+ if (groupNumber) {
|
|
|
+ questions.value
|
|
|
+ ?.filter((q) => q.groupNumber === groupNumber)
|
|
|
+ ?.map((q) => q.trackList)
|
|
|
+ .reduce((acc, ts) => acc.concat(ts))
|
|
|
+ .forEach((t) => {
|
|
|
+ store.focusTracks.push(t);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ questions.value
|
|
|
+ ?.map((q) => q.trackList)
|
|
|
+ .reduce((acc, ts) => acc.concat(ts))
|
|
|
+ .filter((t) => {
|
|
|
+ if (mainNumber) {
|
|
|
+ return t.mainNumber === mainNumber && t.subNumber === subNumber;
|
|
|
+ } else {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .forEach((t) => {
|
|
|
+ store.focusTracks.push(t);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ // console.log(store.focusTracks);
|
|
|
+}
|
|
|
+
|
|
|
+function removeFocusTrack() {
|
|
|
+ store.focusTracks.splice(0);
|
|
|
+}
|
|
|
+
|
|
|
+function fetchTask(next: boolean) {
|
|
|
+ emit("fetchTask", next);
|
|
|
+}
|
|
|
+
|
|
|
+function makeTag(isTag: boolean) {
|
|
|
+ emit("makeTag", isTag);
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.mark-board-track-container {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ max-width: 290px;
|
|
|
+ min-width: 290px;
|
|
|
+ max-height: calc(100vh - 56px);
|
|
|
+ padding: 20px;
|
|
|
+ z-index: 1001;
|
|
|
+ transition: margin-right 0.5s;
|
|
|
+ color: var(--app-small-header-text-color);
|
|
|
+}
|
|
|
+.mark-board-track-container.show {
|
|
|
+ margin-right: 0;
|
|
|
+}
|
|
|
+.mark-board-track-container.hide {
|
|
|
+ margin-right: -290px;
|
|
|
+}
|
|
|
+
|
|
|
+.top-container {
|
|
|
+ background-color: var(--app-container-bg-color);
|
|
|
+ height: 86px;
|
|
|
+ border-radius: 5px;
|
|
|
+
|
|
|
+ color: white;
|
|
|
+ background-color: var(--app-primary-button-bg-color);
|
|
|
+}
|
|
|
+.total-score {
|
|
|
+ color: var(--app-main-text-color);
|
|
|
+ font-size: 32px;
|
|
|
+}
|
|
|
+.question {
|
|
|
+ min-width: 80px;
|
|
|
+ background-color: var(--app-container-bg-color);
|
|
|
+}
|
|
|
+.current-question .score {
|
|
|
+ color: var(--high-light-score-color);
|
|
|
+}
|
|
|
+
|
|
|
+.current-score {
|
|
|
+ color: var(--app-score-color);
|
|
|
+}
|
|
|
+.current-score-indicator {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 5px;
|
|
|
+ height: 5px;
|
|
|
+ background-color: #5c69f6;
|
|
|
+}
|
|
|
+.all-zero-unselective-button {
|
|
|
+ border-radius: 10px;
|
|
|
+ padding: 7px;
|
|
|
+ background-color: #4db9ff;
|
|
|
+ border: none;
|
|
|
+}
|
|
|
+.full-width-btn {
|
|
|
+ width: 100%;
|
|
|
+ border-radius: 20px;
|
|
|
+}
|
|
|
+.undo-btn {
|
|
|
+ background-color: var(--app-undo-button-bg-color);
|
|
|
+ border-color: var(--app-undo-button-bg-color);
|
|
|
+}
|
|
|
+
|
|
|
+.star {
|
|
|
+ margin-top: -30px;
|
|
|
+ margin-right: 20px;
|
|
|
+ width: 30px;
|
|
|
+ height: 30px;
|
|
|
+ cursor: pointer;
|
|
|
+
|
|
|
+ clip-path: polygon(
|
|
|
+ 50% 0%,
|
|
|
+ 61% 35%,
|
|
|
+ 98% 35%,
|
|
|
+ 68% 57%,
|
|
|
+ 79% 91%,
|
|
|
+ 50% 70%,
|
|
|
+ 21% 91%,
|
|
|
+ 32% 57%,
|
|
|
+ 2% 35%,
|
|
|
+ 39% 35%
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+.star.star-yes {
|
|
|
+ background-color: yellowgreen;
|
|
|
+}
|
|
|
+.star.star-no {
|
|
|
+ background-color: white;
|
|
|
+}
|
|
|
+</style>
|