|
@@ -28,11 +28,11 @@
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
-<script lang="ts">
|
|
|
-import { computed, defineComponent, reactive, ref, watchEffect } from "vue";
|
|
|
+<script setup lang="ts">
|
|
|
+import { computed, defineEmit, reactive, ref, watchEffect } from "vue";
|
|
|
import { store } from "./store";
|
|
|
import MarkDrawTrack from "./MarkDrawTrack.vue";
|
|
|
-import { SpecialTag, Track } from "@/types";
|
|
|
+import type { SpecialTag, Track } from "@/types";
|
|
|
import { useTimers } from "@/setups/useTimers";
|
|
|
import { loadImage } from "@/utils/utils";
|
|
|
import { dragImage } from "@/features/mark/use/draggable";
|
|
@@ -44,128 +44,110 @@ interface SliceImage {
|
|
|
tagList: Array<SpecialTag>;
|
|
|
originalImage: HTMLImageElement;
|
|
|
}
|
|
|
-// should not render twice at the same time
|
|
|
-let __lock = false;
|
|
|
-let __currentStudentId = -1; // save __currentStudentIdof lock
|
|
|
-export default defineComponent({
|
|
|
- name: "MarkBody",
|
|
|
- components: { MarkDrawTrack },
|
|
|
- emits: ["error"],
|
|
|
- setup(props, { emit }) {
|
|
|
- const { dragContainer } = dragImage();
|
|
|
-
|
|
|
- const { addTimeout } = useTimers();
|
|
|
-
|
|
|
- let rendering = ref(false);
|
|
|
- let sliceImagesWithTrackList: Array<SliceImage> = reactive([]);
|
|
|
-
|
|
|
- async function processImage() {
|
|
|
- if (!store.currentTask) return;
|
|
|
-
|
|
|
- const images = [];
|
|
|
- for (const url of store.currentTask.sliceUrls) {
|
|
|
- const image = await loadImage(url);
|
|
|
- images.push(image);
|
|
|
- }
|
|
|
-
|
|
|
- for (const url of store.currentTask.sliceUrls) {
|
|
|
- const completeUrl = url;
|
|
|
-
|
|
|
- const indexInSliceUrls = store.currentTask.sliceUrls.indexOf(url) + 1;
|
|
|
- const image = images[indexInSliceUrls - 1];
|
|
|
-
|
|
|
- const trackLists = store.currentTask.questionList
|
|
|
- .map((q) => q.trackList)
|
|
|
- .reduce((acc, t) => {
|
|
|
- acc = acc.concat(t);
|
|
|
- return acc;
|
|
|
- }, [] as Array<Track>);
|
|
|
- const thisImageTrackList = trackLists.filter(
|
|
|
- (t) => t.offsetIndex === indexInSliceUrls
|
|
|
- );
|
|
|
- const thisImageTagList = store.currentTask.specialTagList.filter(
|
|
|
- (t) => t.offsetIndex === indexInSliceUrls
|
|
|
- );
|
|
|
-
|
|
|
- sliceImagesWithTrackList.push({
|
|
|
- url: completeUrl,
|
|
|
- indexInSliceUrls,
|
|
|
- trackList: thisImageTrackList,
|
|
|
- tagList: thisImageTagList,
|
|
|
- originalImage: image,
|
|
|
- });
|
|
|
- }
|
|
|
- }
|
|
|
- const renderPaperAndMark = async () => {
|
|
|
- if (__lock) {
|
|
|
- if (store.currentTask?.studentId === __currentStudentId) {
|
|
|
- console.log("重复渲染,返回");
|
|
|
- return;
|
|
|
- }
|
|
|
- console.log("上个任务还未渲染完毕,稍等一秒再尝试渲染");
|
|
|
- await new Promise((res) => setTimeout(res, 1000));
|
|
|
- await renderPaperAndMark();
|
|
|
- return;
|
|
|
- }
|
|
|
- __lock = true;
|
|
|
- __currentStudentId = store.currentTask?.studentId ?? -1;
|
|
|
- sliceImagesWithTrackList.splice(0);
|
|
|
-
|
|
|
- if (!store.currentTask) {
|
|
|
- __lock = false;
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- try {
|
|
|
- rendering.value = true;
|
|
|
- await processImage();
|
|
|
- } catch (error) {
|
|
|
- sliceImagesWithTrackList.splice(0);
|
|
|
- console.log("render error ", error);
|
|
|
- // 图片加载出错,自动加载下一个任务
|
|
|
- emit("error");
|
|
|
- } finally {
|
|
|
- __lock = false;
|
|
|
- rendering.value = false;
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- watchEffect(renderPaperAndMark);
|
|
|
-
|
|
|
- const answerPaperScale = computed(() => {
|
|
|
- // 放大、缩小不影响页面之前的滚动条定位
|
|
|
- let percentWidth = 0;
|
|
|
- let percentTop = 0;
|
|
|
- const container = document.querySelector(
|
|
|
- ".mark-body-container"
|
|
|
- ) as HTMLDivElement;
|
|
|
- if (container) {
|
|
|
- const { scrollLeft, scrollTop, scrollWidth, scrollHeight } = container;
|
|
|
- percentWidth = scrollLeft / scrollWidth;
|
|
|
- percentTop = scrollTop / scrollHeight;
|
|
|
- }
|
|
|
-
|
|
|
- addTimeout(() => {
|
|
|
- if (container) {
|
|
|
- const { scrollWidth, scrollHeight } = container;
|
|
|
- container.scrollTo({
|
|
|
- left: scrollWidth * percentWidth,
|
|
|
- top: scrollHeight * percentTop,
|
|
|
- });
|
|
|
- }
|
|
|
- }, 10);
|
|
|
- const scale = store.setting.uiSetting["answer.paper.scale"];
|
|
|
- return scale * 100 + "%";
|
|
|
+
|
|
|
+const emit = defineEmit(["error"]);
|
|
|
+const { dragContainer } = dragImage();
|
|
|
+
|
|
|
+const { addTimeout } = useTimers();
|
|
|
+
|
|
|
+let rendering = ref(false);
|
|
|
+let sliceImagesWithTrackList: Array<SliceImage> = reactive([]);
|
|
|
+
|
|
|
+async function processImage() {
|
|
|
+ if (!store.currentTask) return;
|
|
|
+
|
|
|
+ const images = [];
|
|
|
+ for (const url of store.currentTask.sliceUrls) {
|
|
|
+ const image = await loadImage(url);
|
|
|
+ images.push(image);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (const url of store.currentTask.sliceUrls) {
|
|
|
+ const completeUrl = url;
|
|
|
+
|
|
|
+ const indexInSliceUrls = store.currentTask.sliceUrls.indexOf(url) + 1;
|
|
|
+ const image = images[indexInSliceUrls - 1];
|
|
|
+
|
|
|
+ const trackLists = store.currentTask.questionList
|
|
|
+ .map((q) => q.trackList)
|
|
|
+ .reduce((acc, t) => {
|
|
|
+ acc = acc.concat(t);
|
|
|
+ return acc;
|
|
|
+ }, [] as Array<Track>);
|
|
|
+ const thisImageTrackList = trackLists.filter(
|
|
|
+ (t) => t.offsetIndex === indexInSliceUrls
|
|
|
+ );
|
|
|
+ const thisImageTagList = store.currentTask.specialTagList.filter(
|
|
|
+ (t) => t.offsetIndex === indexInSliceUrls
|
|
|
+ );
|
|
|
+
|
|
|
+ sliceImagesWithTrackList.push({
|
|
|
+ url: completeUrl,
|
|
|
+ indexInSliceUrls,
|
|
|
+ trackList: thisImageTrackList,
|
|
|
+ tagList: thisImageTagList,
|
|
|
+ originalImage: image,
|
|
|
});
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- return {
|
|
|
- dragContainer,
|
|
|
- store,
|
|
|
- rendering,
|
|
|
- sliceImagesWithTrackList,
|
|
|
- answerPaperScale,
|
|
|
- };
|
|
|
- },
|
|
|
+// should not render twice at the same time
|
|
|
+let renderLock = false;
|
|
|
+const renderPaperAndMark = async () => {
|
|
|
+ if (renderLock) {
|
|
|
+ console.log("上个任务还未渲染完毕,稍等一秒再尝试渲染");
|
|
|
+ await new Promise((res) => setTimeout(res, 1000));
|
|
|
+ await renderPaperAndMark();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ renderLock = true;
|
|
|
+ sliceImagesWithTrackList.splice(0);
|
|
|
+
|
|
|
+ if (!store.currentTask) {
|
|
|
+ renderLock = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ rendering.value = true;
|
|
|
+ await processImage();
|
|
|
+ } catch (error) {
|
|
|
+ sliceImagesWithTrackList.splice(0);
|
|
|
+ console.log("render error ", error);
|
|
|
+ // 图片加载出错,自动加载下一个任务
|
|
|
+ emit("error");
|
|
|
+ } finally {
|
|
|
+ renderLock = false;
|
|
|
+ rendering.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+watchEffect(renderPaperAndMark);
|
|
|
+
|
|
|
+const answerPaperScale = computed(() => {
|
|
|
+ // 放大、缩小不影响页面之前的滚动条定位
|
|
|
+ let percentWidth = 0;
|
|
|
+ let percentTop = 0;
|
|
|
+ const container = document.querySelector(
|
|
|
+ ".mark-body-container"
|
|
|
+ ) as HTMLDivElement;
|
|
|
+ if (container) {
|
|
|
+ const { scrollLeft, scrollTop, scrollWidth, scrollHeight } = container;
|
|
|
+ percentWidth = scrollLeft / scrollWidth;
|
|
|
+ percentTop = scrollTop / scrollHeight;
|
|
|
+ }
|
|
|
+
|
|
|
+ addTimeout(() => {
|
|
|
+ if (container) {
|
|
|
+ const { scrollWidth, scrollHeight } = container;
|
|
|
+ container.scrollTo({
|
|
|
+ left: scrollWidth * percentWidth,
|
|
|
+ top: scrollHeight * percentTop,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }, 10);
|
|
|
+ const scale = store.setting.uiSetting["answer.paper.scale"];
|
|
|
+ return scale * 100 + "%";
|
|
|
});
|
|
|
</script>
|
|
|
|
|
@@ -180,9 +162,6 @@ export default defineComponent({
|
|
|
cursor: grab;
|
|
|
user-select: none;
|
|
|
}
|
|
|
-.grabbing {
|
|
|
- cursor: grabbing;
|
|
|
-}
|
|
|
.mark-body-container img {
|
|
|
width: 100%;
|
|
|
}
|