|
@@ -15,232 +15,204 @@
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
-<script lang="ts">
|
|
|
-import {
|
|
|
- defineComponent,
|
|
|
- onMounted,
|
|
|
- onUnmounted,
|
|
|
- watch,
|
|
|
- watchEffect,
|
|
|
-} from "vue";
|
|
|
+<script setup lang="ts">
|
|
|
+import { defineEmit, onMounted, onUnmounted, watch, watchEffect } from "vue";
|
|
|
import { store } from "./store";
|
|
|
-import MarkDrawTrack from "./MarkDrawTrack.vue";
|
|
|
-import { ModeEnum, SliceImage, SpecialTag, Track } from "@/types";
|
|
|
-import { useTimers } from "@/setups/useTimers";
|
|
|
+import { ModeEnum } from "@/types";
|
|
|
+import type { SliceImage, SpecialTag, Track } from "@/types";
|
|
|
import { isNumber } from "lodash";
|
|
|
// @ts-ignore
|
|
|
import CustomCursor from "custom-cursor.js";
|
|
|
import CommonMarkBody from "./CommonMarkBody.vue";
|
|
|
|
|
|
-export default defineComponent({
|
|
|
- name: "MarkBody",
|
|
|
- components: { MarkDrawTrack, CommonMarkBody },
|
|
|
- emits: ["error"],
|
|
|
- setup(props, { emit }) {
|
|
|
- const makeScoreTrack = (
|
|
|
- event: MouseEvent,
|
|
|
- item: SliceImage,
|
|
|
- maxSliceWidth: number,
|
|
|
- theFinalHeight: number
|
|
|
- ) => {
|
|
|
- // console.log(item);
|
|
|
- if (!store.currentQuestion || typeof store.currentScore === "undefined")
|
|
|
- return;
|
|
|
- const target = event.target as HTMLImageElement;
|
|
|
- const track = {} as Track;
|
|
|
- track.mainNumber = store.currentQuestion?.mainNumber;
|
|
|
- track.subNumber = store.currentQuestion?.subNumber;
|
|
|
- track.score = store.currentScore;
|
|
|
- track.offsetIndex = item.indexInSliceUrls;
|
|
|
- track.offsetX = Math.round(
|
|
|
- event.offsetX * (target.naturalWidth / target.width) + item.dx
|
|
|
- );
|
|
|
- track.offsetY = Math.round(
|
|
|
- event.offsetY * (target.naturalHeight / target.height) + item.dy
|
|
|
- );
|
|
|
- track.positionX = (track.offsetX - item.dx) / maxSliceWidth;
|
|
|
- track.positionY =
|
|
|
- (track.offsetY - item.dy + item.accumTopHeight) / theFinalHeight;
|
|
|
- if (track.offsetX > item.effectiveWidth + item.dx) {
|
|
|
- console.log("不在有效宽度内,轨迹不生效");
|
|
|
- return;
|
|
|
- }
|
|
|
- if (
|
|
|
- item.trackList.some((t) => {
|
|
|
- return (
|
|
|
- Math.pow(Math.abs(t.offsetX - track.offsetX), 2) +
|
|
|
- Math.pow(Math.abs(t.offsetY - track.offsetY), 2) <
|
|
|
- 500
|
|
|
- );
|
|
|
- })
|
|
|
- ) {
|
|
|
- console.log("两个轨迹相距过近");
|
|
|
- return;
|
|
|
- }
|
|
|
- // 是否保留当前的轨迹分
|
|
|
- const ifKeepScore =
|
|
|
- Math.round(
|
|
|
- store.currentQuestion.maxScore * 100 -
|
|
|
- (store.currentQuestion.score || 0) * 100 -
|
|
|
- store.currentScore * 2 * 100
|
|
|
- ) / 100;
|
|
|
- if (ifKeepScore < 0 && store.currentScore > 0) {
|
|
|
- store.currentScore = undefined;
|
|
|
- }
|
|
|
- const markResult = store.currentMarkResult;
|
|
|
- if (markResult) {
|
|
|
- const maxNumber =
|
|
|
- markResult.trackList.length === 0
|
|
|
- ? 0
|
|
|
- : Math.max(...markResult.trackList.map((t) => t.number));
|
|
|
- track.number = maxNumber + 1;
|
|
|
- // console.log(
|
|
|
- // maxNumber,
|
|
|
- // track.number,
|
|
|
- // markResult.trackList.map((t) => t.number),
|
|
|
- // Math.max(...markResult.trackList.map((t) => t.number))
|
|
|
- // );
|
|
|
- markResult.trackList = [...markResult.trackList, track];
|
|
|
- }
|
|
|
- item.trackList.push(track);
|
|
|
- };
|
|
|
+const emit = defineEmit(["error", "allZeroSubmit"]);
|
|
|
|
|
|
- const makeSpecialTagTrack = (
|
|
|
- event: MouseEvent,
|
|
|
- item: SliceImage,
|
|
|
- maxSliceWidth: number,
|
|
|
- theFinalHeight: number
|
|
|
- ) => {
|
|
|
- // console.log(item);
|
|
|
- if (!store.currentTask || typeof store.currentSpecialTag === "undefined")
|
|
|
- return;
|
|
|
- const target = event.target as HTMLImageElement;
|
|
|
- const track = {} as SpecialTag;
|
|
|
- track.tagName = store.currentSpecialTag;
|
|
|
- track.offsetIndex = item.indexInSliceUrls;
|
|
|
- track.offsetX = Math.round(
|
|
|
- event.offsetX * (target.naturalWidth / target.width) + item.dx
|
|
|
+const makeScoreTrack = (
|
|
|
+ event: MouseEvent,
|
|
|
+ item: SliceImage,
|
|
|
+ maxSliceWidth: number,
|
|
|
+ theFinalHeight: number
|
|
|
+) => {
|
|
|
+ // console.log(item);
|
|
|
+ if (!store.currentQuestion || typeof store.currentScore === "undefined")
|
|
|
+ return;
|
|
|
+ const target = event.target as HTMLImageElement;
|
|
|
+ const track = {} as Track;
|
|
|
+ track.mainNumber = store.currentQuestion?.mainNumber;
|
|
|
+ track.subNumber = store.currentQuestion?.subNumber;
|
|
|
+ track.score = store.currentScore;
|
|
|
+ track.offsetIndex = item.indexInSliceUrls;
|
|
|
+ track.offsetX = Math.round(
|
|
|
+ event.offsetX * (target.naturalWidth / target.width) + item.dx
|
|
|
+ );
|
|
|
+ track.offsetY = Math.round(
|
|
|
+ event.offsetY * (target.naturalHeight / target.height) + item.dy
|
|
|
+ );
|
|
|
+ track.positionX = (track.offsetX - item.dx) / maxSliceWidth;
|
|
|
+ track.positionY =
|
|
|
+ (track.offsetY - item.dy + item.accumTopHeight) / theFinalHeight;
|
|
|
+ if (track.offsetX > item.effectiveWidth + item.dx) {
|
|
|
+ console.log("不在有效宽度内,轨迹不生效");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (
|
|
|
+ item.trackList.some((t) => {
|
|
|
+ return (
|
|
|
+ Math.pow(Math.abs(t.offsetX - track.offsetX), 2) +
|
|
|
+ Math.pow(Math.abs(t.offsetY - track.offsetY), 2) <
|
|
|
+ 500
|
|
|
);
|
|
|
- track.offsetY = Math.round(
|
|
|
- event.offsetY * (target.naturalHeight / target.height) + item.dy
|
|
|
+ })
|
|
|
+ ) {
|
|
|
+ console.log("两个轨迹相距过近");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 是否保留当前的轨迹分
|
|
|
+ const ifKeepScore =
|
|
|
+ Math.round(
|
|
|
+ store.currentQuestion.maxScore * 100 -
|
|
|
+ (store.currentQuestion.score || 0) * 100 -
|
|
|
+ store.currentScore * 2 * 100
|
|
|
+ ) / 100;
|
|
|
+ if (ifKeepScore < 0 && store.currentScore > 0) {
|
|
|
+ store.currentScore = undefined;
|
|
|
+ }
|
|
|
+ const markResult = store.currentMarkResult;
|
|
|
+ if (markResult) {
|
|
|
+ const maxNumber =
|
|
|
+ markResult.trackList.length === 0
|
|
|
+ ? 0
|
|
|
+ : Math.max(...markResult.trackList.map((t) => t.number));
|
|
|
+ track.number = maxNumber + 1;
|
|
|
+ // console.log(
|
|
|
+ // maxNumber,
|
|
|
+ // track.number,
|
|
|
+ // markResult.trackList.map((t) => t.number),
|
|
|
+ // Math.max(...markResult.trackList.map((t) => t.number))
|
|
|
+ // );
|
|
|
+ markResult.trackList = [...markResult.trackList, track];
|
|
|
+ }
|
|
|
+ item.trackList.push(track);
|
|
|
+};
|
|
|
+
|
|
|
+const makeSpecialTagTrack = (
|
|
|
+ event: MouseEvent,
|
|
|
+ item: SliceImage,
|
|
|
+ maxSliceWidth: number,
|
|
|
+ theFinalHeight: number
|
|
|
+) => {
|
|
|
+ // console.log(item);
|
|
|
+ if (!store.currentTask || typeof store.currentSpecialTag === "undefined")
|
|
|
+ return;
|
|
|
+ const target = event.target as HTMLImageElement;
|
|
|
+ const track = {} as SpecialTag;
|
|
|
+ track.tagName = store.currentSpecialTag;
|
|
|
+ track.offsetIndex = item.indexInSliceUrls;
|
|
|
+ track.offsetX = Math.round(
|
|
|
+ event.offsetX * (target.naturalWidth / target.width) + item.dx
|
|
|
+ );
|
|
|
+ track.offsetY = Math.round(
|
|
|
+ event.offsetY * (target.naturalHeight / target.height) + item.dy
|
|
|
+ );
|
|
|
+ track.positionX = (track.offsetX - item.dx) / maxSliceWidth;
|
|
|
+ track.positionY =
|
|
|
+ (track.offsetY - item.dy + item.accumTopHeight) / theFinalHeight;
|
|
|
+ if (track.offsetX > item.effectiveWidth + item.dx) {
|
|
|
+ console.log("不在有效宽度内,轨迹不生效");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (
|
|
|
+ item.tagList.some((t) => {
|
|
|
+ return (
|
|
|
+ Math.pow(Math.abs(t.offsetX - track.offsetX), 2) +
|
|
|
+ Math.pow(Math.abs(t.offsetY - track.offsetY), 2) <
|
|
|
+ 500
|
|
|
);
|
|
|
- track.positionX = (track.offsetX - item.dx) / maxSliceWidth;
|
|
|
- track.positionY =
|
|
|
- (track.offsetY - item.dy + item.accumTopHeight) / theFinalHeight;
|
|
|
- if (track.offsetX > item.effectiveWidth + item.dx) {
|
|
|
- console.log("不在有效宽度内,轨迹不生效");
|
|
|
- return;
|
|
|
- }
|
|
|
- if (
|
|
|
- item.tagList.some((t) => {
|
|
|
- return (
|
|
|
- Math.pow(Math.abs(t.offsetX - track.offsetX), 2) +
|
|
|
- Math.pow(Math.abs(t.offsetY - track.offsetY), 2) <
|
|
|
- 500
|
|
|
- );
|
|
|
- })
|
|
|
- ) {
|
|
|
- console.log("两个轨迹相距过近");
|
|
|
- return;
|
|
|
- }
|
|
|
- const markResult = store.currentMarkResult;
|
|
|
- if (markResult) {
|
|
|
- markResult.specialTagList.push(track);
|
|
|
- }
|
|
|
- item.tagList.push(track);
|
|
|
- };
|
|
|
+ })
|
|
|
+ ) {
|
|
|
+ console.log("两个轨迹相距过近");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const markResult = store.currentMarkResult;
|
|
|
+ if (markResult) {
|
|
|
+ markResult.specialTagList.push(track);
|
|
|
+ }
|
|
|
+ item.tagList.push(track);
|
|
|
+};
|
|
|
|
|
|
- const makeTrack = (
|
|
|
- event: MouseEvent,
|
|
|
- item: SliceImage,
|
|
|
- maxSliceWidth: number,
|
|
|
- theFinalHeight: number
|
|
|
- ) => {
|
|
|
- if (
|
|
|
- store.setting.uiSetting["specialTag.modal"] &&
|
|
|
- store.currentSpecialTag
|
|
|
- ) {
|
|
|
- makeSpecialTagTrack(event, item, maxSliceWidth, theFinalHeight);
|
|
|
- } else {
|
|
|
- makeScoreTrack(event, item, maxSliceWidth, theFinalHeight);
|
|
|
- }
|
|
|
- };
|
|
|
+const makeTrack = (
|
|
|
+ event: MouseEvent,
|
|
|
+ item: SliceImage,
|
|
|
+ maxSliceWidth: number,
|
|
|
+ theFinalHeight: number
|
|
|
+) => {
|
|
|
+ if (store.setting.uiSetting["specialTag.modal"] && store.currentSpecialTag) {
|
|
|
+ makeSpecialTagTrack(event, item, maxSliceWidth, theFinalHeight);
|
|
|
+ } else {
|
|
|
+ makeScoreTrack(event, item, maxSliceWidth, theFinalHeight);
|
|
|
+ }
|
|
|
+};
|
|
|
|
|
|
- // 轨迹模式下,添加轨迹,更新分数
|
|
|
- watch(
|
|
|
- () => store.currentMarkResult?.trackList,
|
|
|
- () => {
|
|
|
- if (store.setting.mode !== ModeEnum.TRACK) return;
|
|
|
- const markResult = store.currentMarkResult;
|
|
|
- if (markResult) {
|
|
|
- const cq = store.currentQuestion;
|
|
|
- // 当无轨迹时,不更新;无轨迹时,将分数置null
|
|
|
- if (cq) {
|
|
|
- if (markResult.trackList.length > 0) {
|
|
|
- const cqTrackList = markResult.trackList.filter(
|
|
|
- (v) =>
|
|
|
- v.mainNumber === cq.mainNumber && v.subNumber === cq.subNumber
|
|
|
- );
|
|
|
- if (cqTrackList.length > 0) {
|
|
|
- cq.score =
|
|
|
- cqTrackList
|
|
|
- .map((v) => v.score)
|
|
|
- .reduce((acc, v) => (acc += Math.round(v * 100)), 0) / 100;
|
|
|
- } else {
|
|
|
- cq.score = null;
|
|
|
- }
|
|
|
- } else {
|
|
|
- // TODO: 不需要?如果此行代码生效,则无法清除最后一道题的分数 此时的场景是回评普通模式评的分,需要看见
|
|
|
- // cq.score = cq.__origScore;
|
|
|
- }
|
|
|
+// 轨迹模式下,添加轨迹,更新分数
|
|
|
+watch(
|
|
|
+ () => store.currentMarkResult?.trackList,
|
|
|
+ () => {
|
|
|
+ if (store.setting.mode !== ModeEnum.TRACK) return;
|
|
|
+ const markResult = store.currentMarkResult;
|
|
|
+ if (markResult) {
|
|
|
+ const cq = store.currentQuestion;
|
|
|
+ // 当无轨迹时,不更新;无轨迹时,将分数置null
|
|
|
+ if (cq) {
|
|
|
+ if (markResult.trackList.length > 0) {
|
|
|
+ const cqTrackList = markResult.trackList.filter(
|
|
|
+ (v) =>
|
|
|
+ v.mainNumber === cq.mainNumber && v.subNumber === cq.subNumber
|
|
|
+ );
|
|
|
+ if (cqTrackList.length > 0) {
|
|
|
+ cq.score =
|
|
|
+ cqTrackList
|
|
|
+ .map((v) => v.score)
|
|
|
+ .reduce((acc, v) => (acc += Math.round(v * 100)), 0) / 100;
|
|
|
+ } else {
|
|
|
+ cq.score = null;
|
|
|
}
|
|
|
- // renderPaperAndMark();
|
|
|
+ } else {
|
|
|
+ // TODO: 不需要?如果此行代码生效,则无法清除最后一道题的分数 此时的场景是回评普通模式评的分,需要看见
|
|
|
+ // cq.score = cq.__origScore;
|
|
|
}
|
|
|
- },
|
|
|
- { deep: true }
|
|
|
- );
|
|
|
+ }
|
|
|
+ // renderPaperAndMark();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ { deep: true }
|
|
|
+);
|
|
|
|
|
|
- // question.score更新后,自动关联markResult.scoreList和markResult.markerScore
|
|
|
- watchEffect(() => {
|
|
|
- const markResult = store.currentMarkResult;
|
|
|
+// question.score更新后,自动关联markResult.scoreList和markResult.markerScore
|
|
|
+watchEffect(() => {
|
|
|
+ const markResult = store.currentMarkResult;
|
|
|
|
|
|
- if (markResult && store.currentTask) {
|
|
|
- const scoreList = store.currentTask.questionList.map((q) => q.score);
|
|
|
- markResult.scoreList = [...(scoreList as number[])];
|
|
|
- markResult.markerScore =
|
|
|
- (markResult.scoreList.filter((s) => isNumber(s)) as number[]).reduce(
|
|
|
- (acc, v) => (acc += Math.round(v * 100)),
|
|
|
- 0
|
|
|
- ) / 100;
|
|
|
- }
|
|
|
- });
|
|
|
+ if (markResult && store.currentTask) {
|
|
|
+ const scoreList = store.currentTask.questionList.map((q) => q.score);
|
|
|
+ markResult.scoreList = [...(scoreList as number[])];
|
|
|
+ markResult.markerScore =
|
|
|
+ (markResult.scoreList.filter((s) => isNumber(s)) as number[]).reduce(
|
|
|
+ (acc, v) => (acc += Math.round(v * 100)),
|
|
|
+ 0
|
|
|
+ ) / 100;
|
|
|
+ }
|
|
|
+});
|
|
|
|
|
|
- watch(
|
|
|
- () => store.setting.mode,
|
|
|
- () => {
|
|
|
- const shouldHide = store.setting.mode === ModeEnum.COMMON;
|
|
|
- if (shouldHide) {
|
|
|
- // console.log("hide cursor", theCursor);
|
|
|
- theCursor && theCursor.destroy();
|
|
|
- } else {
|
|
|
- if (document.querySelector(".cursor")) {
|
|
|
- // console.log("show cursor", theCursor);
|
|
|
- // theCursor && theCursor.enable();
|
|
|
- theCursor = new CustomCursor(".cursor", {
|
|
|
- focusElements: [
|
|
|
- {
|
|
|
- selector: ".mark-body-container",
|
|
|
- focusClass: "cursor--focused-view",
|
|
|
- },
|
|
|
- ],
|
|
|
- }).initialize();
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- );
|
|
|
- let theCursor = null as any;
|
|
|
- onMounted(() => {
|
|
|
- if (store.setting.mode === ModeEnum.TRACK) {
|
|
|
+watch(
|
|
|
+ () => store.setting.mode,
|
|
|
+ () => {
|
|
|
+ const shouldHide = store.setting.mode === ModeEnum.COMMON;
|
|
|
+ if (shouldHide) {
|
|
|
+ // console.log("hide cursor", theCursor);
|
|
|
+ theCursor && theCursor.destroy();
|
|
|
+ } else {
|
|
|
+ if (document.querySelector(".cursor")) {
|
|
|
+ // console.log("show cursor", theCursor);
|
|
|
+ // theCursor && theCursor.enable();
|
|
|
theCursor = new CustomCursor(".cursor", {
|
|
|
focusElements: [
|
|
|
{
|
|
@@ -250,20 +222,25 @@ export default defineComponent({
|
|
|
],
|
|
|
}).initialize();
|
|
|
}
|
|
|
- });
|
|
|
-
|
|
|
- onUnmounted(() => {
|
|
|
- theCursor && theCursor.destroy();
|
|
|
- });
|
|
|
+ }
|
|
|
+ }
|
|
|
+);
|
|
|
+let theCursor = null as any;
|
|
|
+onMounted(() => {
|
|
|
+ if (store.setting.mode === ModeEnum.TRACK) {
|
|
|
+ theCursor = new CustomCursor(".cursor", {
|
|
|
+ focusElements: [
|
|
|
+ {
|
|
|
+ selector: ".mark-body-container",
|
|
|
+ focusClass: "cursor--focused-view",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ }).initialize();
|
|
|
+ }
|
|
|
+});
|
|
|
|
|
|
- return {
|
|
|
- store,
|
|
|
- makeTrack,
|
|
|
- };
|
|
|
- },
|
|
|
- // renderTriggered({ key, target, type }) {
|
|
|
- // console.log({ key, target, type });
|
|
|
- // },
|
|
|
+onUnmounted(() => {
|
|
|
+ theCursor && theCursor.destroy();
|
|
|
});
|
|
|
</script>
|
|
|
|