Browse Source

完成特殊标记

Michael Wang 4 years ago
parent
commit
c6a43f5868

+ 1 - 1
src/api/markPage.ts

@@ -66,7 +66,7 @@ export async function getHistoryTask({
 export async function saveTask() {
   let markResult = findCurrentTaskMarkResult();
   if (markResult) {
-    markResult.specialTagList = [];
+    // markResult.specialTagList = [];
     markResult.problem = false;
     markResult.spent = Date.now() - markResult.__markStartTime;
     markResult = { ...markResult };

+ 2 - 2
src/components/QmDialog.vue

@@ -179,8 +179,8 @@ header {
   position: absolute;
   bottom: 0;
   right: 0;
-  width: 100px;
-  height: 100px;
+  width: 20px;
+  height: 20px;
   cursor: nwse-resize;
 }
 </style>

+ 101 - 4
src/features/mark/MarkBody.vue

@@ -32,11 +32,12 @@
         >
           <img
             :src="item.url"
-            @click="(event) => makeScoreTrack(event, item)"
+            @click="(event) => makeTrack(event, item)"
             draggable="false"
           />
           <MarkDrawTrack
             :track-list="item.trackList"
+            :special-tag-list="item.tagList"
             :original-image="item.originalImage"
             :slice-image="item.sliceImage"
             :dx="item.dx"
@@ -49,7 +50,11 @@
   </div>
   <div class="cursor">
     <div class="cursor-border">
-      <span class="text">{{ store.currentScore }}</span>
+      <span class="text">{{
+        store.setting.uiSetting["specialTag.modal"]
+          ? store.currentSpecialTag
+          : store.currentScore
+      }}</span>
     </div>
   </div>
 </template>
@@ -68,7 +73,7 @@ import {
 import { findCurrentTaskMarkResult, getMarkStatus, store } from "./store";
 import filters from "@/filters";
 import MarkDrawTrack from "./MarkDrawTrack.vue";
-import { ModeEnum, Track } from "@/types";
+import { ModeEnum, SpecialTag, Track } from "@/types";
 import { useTimers } from "@/setups/useTimers";
 import {
   getDataUrlForSliceConfig,
@@ -85,6 +90,7 @@ interface SliceImage {
   url: string;
   indexInSliceUrls: number;
   trackList: Array<Track>;
+  tagList: Array<SpecialTag>;
   originalImage: HTMLImageElement;
   sliceImage: HTMLImageElement;
   dx: number;
@@ -158,6 +164,9 @@ export default defineComponent({
         const thisImageTrackList = markResult.trackList.filter(
           (v) => v.offsetIndex === sliceConfig.i
         );
+        const thisImageTagList = markResult.specialTagList.filter(
+          (v) => v.offsetIndex === sliceConfig.i
+        );
         const sliceImage = new Image();
         sliceImage.src = dataUrl;
         sliceImagesWithTrackList.push({
@@ -169,6 +178,11 @@ export default defineComponent({
               t.positionY >= accumTopHeight / theFinalHeight &&
               t.positionY < accumBottomHeight / theFinalHeight
           ),
+          tagList: thisImageTagList.filter(
+            (t) =>
+              t.positionY >= accumTopHeight / theFinalHeight &&
+              t.positionY < accumBottomHeight / theFinalHeight
+          ),
           originalImage: image,
           sliceImage,
           dx: sliceConfig.x,
@@ -228,6 +242,12 @@ export default defineComponent({
               (store.currentTask &&
                 store.currentTask.sliceUrls.indexOf(url) + 1)
           );
+          const thisImageTagList = markResult.specialTagList.filter(
+            (t) =>
+              t.offsetIndex ===
+              (store.currentTask &&
+                store.currentTask.sliceUrls.indexOf(url) + 1)
+          );
           const sliceImage = new Image();
           sliceImage.src = dataUrl;
           sliceImagesWithTrackList.push({
@@ -238,6 +258,11 @@ export default defineComponent({
                 t.positionY >= accumTopHeight / theFinalHeight &&
                 t.positionY < accumBottomHeight / theFinalHeight
             ),
+            tagList: thisImageTagList.filter(
+              (t) =>
+                t.positionY >= accumTopHeight / theFinalHeight &&
+                t.positionY < accumBottomHeight / theFinalHeight
+            ),
             originalImage: image,
             sliceImage,
             dx: image.naturalWidth * config[0],
@@ -409,6 +434,57 @@ export default defineComponent({
       item.trackList.push(track);
     };
 
+    const makeSpecialTagTrack = (event: MouseEvent, item: SliceImage) => {
+      // 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
+          );
+        })
+      ) {
+        console.log("两个轨迹相距过近");
+        return;
+      }
+      const markResult = findCurrentTaskMarkResult();
+      if (markResult) {
+        markResult.specialTagList.push(track);
+      }
+      item.tagList.push(track);
+    };
+
+    const makeTrack = (event: MouseEvent, item: SliceImage) => {
+      if (
+        store.setting.uiSetting["specialTag.modal"] &&
+        store.currentSpecialTag
+      ) {
+        makeSpecialTagTrack(event, item);
+      } else {
+        makeScoreTrack(event, item);
+      }
+    };
+
     // 清除分数轨迹
     watchEffect(() => {
       for (const track of store.removeScoreTracks) {
@@ -427,6 +503,27 @@ export default defineComponent({
       store.removeScoreTracks.splice(0);
     });
 
+    // 清除特殊标记轨迹
+    watchEffect(() => {
+      for (const track of store.currentMarkResult?.specialTagList || []) {
+        for (const sliceImage of sliceImagesWithTrackList) {
+          sliceImage.tagList = sliceImage.tagList.filter((t) =>
+            store.currentMarkResult?.specialTagList.find(
+              (st) =>
+                st.offsetIndex === t.offsetIndex &&
+                st.offsetX === t.offsetX &&
+                st.offsetY === t.offsetY
+            )
+          );
+        }
+      }
+      if (store.currentMarkResult?.specialTagList.length === 0) {
+        for (const sliceImage of sliceImagesWithTrackList) {
+          sliceImage.tagList = [];
+        }
+      }
+    });
+
     // 轨迹模式下,添加轨迹,更新分数
     watch(
       () => store.currentMarkResult?.trackList,
@@ -554,7 +651,7 @@ export default defineComponent({
       rendering,
       sliceImagesWithTrackList,
       answerPaperScale,
-      makeScoreTrack,
+      makeTrack,
       markStatus,
     };
   },

+ 18 - 15
src/features/mark/MarkDrawTrack.vue

@@ -10,11 +10,22 @@
       </span>
     </div>
   </template>
+  <template v-for="(tag, index) in specialTagList" :key="index">
+    <div
+      v-if="isTrackMode"
+      class="score-container"
+      :style="computeTopAndLeft(tag)"
+    >
+      <span class="tw-m-auto">
+        {{ tag.tagName }}
+      </span>
+    </div>
+  </template>
 </template>
 
 <script lang="ts">
-import { ModeEnum, Track } from "@/types";
-import { defineComponent, PropType, ref, watchEffect } from "vue";
+import { ModeEnum, SpecialTag, Track } from "@/types";
+import { computed, defineComponent, PropType, ref, watchEffect } from "vue";
 import { store } from "./store";
 
 export default defineComponent({
@@ -23,6 +34,9 @@ export default defineComponent({
     trackList: {
       type: Array as PropType<Array<Track>>,
     },
+    specialTagList: {
+      type: Array as PropType<Array<SpecialTag>>,
+    },
     originalImage: {
       type: Object as PropType<HTMLImageElement>,
     },
@@ -34,22 +48,11 @@ export default defineComponent({
     dy: { type: Number, required: true },
   },
   setup({ trackList, originalImage, sliceImage, dx, dy }) {
-    const isTrackMode = ref(false);
-    watchEffect(() => {
-      isTrackMode.value = store.setting.mode === ModeEnum.TRACK;
-    });
+    const isTrackMode = computed(() => store.setting.mode === ModeEnum.TRACK);
 
-    const computeTopAndLeft = (track: Track) => {
+    const computeTopAndLeft = (track: Track | SpecialTag) => {
       const topInsideSlice = track.offsetY - dy;
       const leftInsideSlice = track.offsetX - dx;
-      // console.log({
-      //   topInsideSlice,
-      //   leftInsideSlice,
-      //   offx: track.offsetX,
-      //   offy: track.offsetY,
-      //   dx,
-      //   dy,
-      // });
       return {
         top: (topInsideSlice / sliceImage.naturalHeight) * 100 + "%",
         left: (leftInsideSlice / sliceImage.naturalWidth) * 100 + "%",

+ 35 - 8
src/features/mark/SpecialTagModal.vue

@@ -9,12 +9,33 @@
     @close="close"
   >
     <div
-      class="special-tag-container tw-flex tw-place-content-between tw-m-4 tw-text-xl tw-cursor-pointer"
+      class="tw-flex tw-place-content-between tw-m-4 tw-text-xl tw-cursor-pointer"
     >
-      <div>√</div>
-      <div>X</div>
-      <div>乄</div>
-      <div><u>下划线</u></div>
+      <div
+        @click="store.currentSpecialTag = '√'"
+        :class="[store.currentSpecialTag === '√' && 'tag-selected', 'tag']"
+      >
+        √
+      </div>
+      <div
+        @click="store.currentSpecialTag = 'X'"
+        :class="[store.currentSpecialTag === 'X' && 'tag-selected', 'tag']"
+      >
+        X
+      </div>
+      <div
+        @click="store.currentSpecialTag = '乄'"
+        :class="[store.currentSpecialTag === '乄' && 'tag-selected', 'tag']"
+      >
+        乄
+      </div>
+      <div
+        @click="store.currentSpecialTag = '_____'"
+        :class="[store.currentSpecialTag === '_____' && 'tag-selected', 'tag']"
+        style="width: 60px"
+      >
+        <u>下划线</u>
+      </div>
     </div>
 
     <div class="tw-flex tw-place-content-between tw-mt-8">
@@ -35,7 +56,7 @@
         :clickTimeout="300"
         @click="clearAllTagsOfCurrentTask"
       >
-        清除本题
+        清除全部
       </qm-button>
     </div>
   </qm-dialog>
@@ -72,7 +93,13 @@ export default defineComponent({
 </script>
 
 <style>
-.special-tag-container {
-  /* border: 1px dotted grey; */
+.tag {
+  width: 30px;
+  height: 30px;
+  text-align: center;
+  border-radius: 2px;
+}
+.tag-selected {
+  background-color: lightgrey;
 }
 </style>

+ 3 - 0
src/features/mark/store.ts

@@ -39,6 +39,7 @@ const obj = {
   currentTask: undefined,
   currentQuestion: undefined,
   currentScore: undefined,
+  currentSpecialTag: undefined,
   markResults: [],
   historyOpen: false,
   MarkBoardTrackCollapse: false,
@@ -74,6 +75,8 @@ export function findCurrentTaskMarkResult() {
       (all, c) => all.concat(c.trackList),
       [] as Array<Track>
     );
+    markResult.specialTagList =
+      store.currentTask.specialTagList?.splice(0) ?? [];
     markResult.scoreList = store.currentTask.questionList.map((q) => q.score);
     markResult.markerScore =
       markResult.scoreList

+ 2 - 1
src/types/index.ts

@@ -13,6 +13,7 @@ export interface MarkStore {
   currentMarkResult?: MarkResult;
   currentQuestion?: Question;
   currentScore?: number;
+  currentSpecialTag?: string;
   markResults: Array<MarkResult>;
   historyOpen: boolean; // 是否打开回评侧边栏
   MarkBoardTrackCollapse: boolean; // 是否收缩评分版
@@ -127,7 +128,7 @@ export interface Track {
   score: number;
 }
 
-interface SpecialTag {
+export interface SpecialTag {
   offsetIndex: number; // 第几张图
   offsetX: number; // 左上角为原点
   offsetY: number;