|
@@ -1,7 +1,7 @@
|
|
|
<template>
|
|
|
<div
|
|
|
ref="dragContainer"
|
|
|
- class="mark-body-container tw-flex-auto tw-p-2 tw-relative"
|
|
|
+ class="mark-body-container tw-flex-auto tw-p-2 tw-pt-0 tw-relative"
|
|
|
>
|
|
|
<div
|
|
|
v-if="!store.currentTask"
|
|
@@ -13,7 +13,7 @@
|
|
|
<div
|
|
|
v-else-if="store.isScanImage"
|
|
|
:style="{ width: answerPaperScale }"
|
|
|
- :class="[`rotate-board-${rotateBoard}`]"
|
|
|
+ :class="['tw-pt-2', `rotate-board-${rotateBoard}`]"
|
|
|
>
|
|
|
<div
|
|
|
v-for="(item, index) in sliceImagesWithTrackList"
|
|
@@ -45,7 +45,7 @@
|
|
|
{{ markStatus }}
|
|
|
<div class="double-triangle"></div>
|
|
|
</div>
|
|
|
- <ZoomPaper v-if="store.isScanImage && store.currentTask" />
|
|
|
+ <ZoomPaper v-if="store.isScanImage && store.currentTask && sliceImagesWithTrackList.length" />
|
|
|
|
|
|
<!-- 非启用功能 -->
|
|
|
<div class="kb-circle tw-hidden">
|
|
@@ -121,9 +121,9 @@ const { addTimeout } = useTimers();
|
|
|
watch(
|
|
|
() => [store.minimapScrollToX, store.minimapScrollToY],
|
|
|
() => {
|
|
|
- const container = document.querySelector(
|
|
|
+ const container = document.querySelector<HTMLDivElement>(
|
|
|
".mark-body-container"
|
|
|
- ) as HTMLDivElement;
|
|
|
+ );
|
|
|
addTimeout(() => {
|
|
|
if (
|
|
|
container &&
|
|
@@ -144,9 +144,12 @@ watch(
|
|
|
|
|
|
//#region : 快捷键定位
|
|
|
const scrollContainerByKey = (e: KeyboardEvent) => {
|
|
|
- const container = document.querySelector(
|
|
|
+ const container = document.querySelector<HTMLDivElement>(
|
|
|
".mark-body-container"
|
|
|
- ) as HTMLDivElement;
|
|
|
+ );
|
|
|
+ if (!container) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
if (e.key === "w") {
|
|
|
container.scrollBy({ top: -100, behavior: "smooth" });
|
|
|
} else if (e.key === "s") {
|
|
@@ -216,7 +219,7 @@ async function processSliceConfig() {
|
|
|
? markResult.specialTagList ?? []
|
|
|
: store.currentTask.specialTagList ?? [];
|
|
|
|
|
|
- const tempSliceImagesWithTrackList = [] as Array<SliceImage>;
|
|
|
+ const tempSliceImagesWithTrackList: Array<SliceImage> = [];
|
|
|
for (const sliceConfig of store.currentTask.sliceConfig) {
|
|
|
accumBottomHeight += sliceConfig.h;
|
|
|
const url = store.currentTask.sliceUrls[sliceConfig.i - 1];
|
|
@@ -308,14 +311,20 @@ async function processSplitConfig() {
|
|
|
images.push(image);
|
|
|
}
|
|
|
|
|
|
- // 裁切块,可能是一块,两块,三块... [start, width ...] => [0, 0.3] | [0, 0.55, 0.45, 0.55] | [0, 0.35, 0.33, 0.35, 0.66, 0.35]
|
|
|
// 如果拒绝裁切,则保持整卷
|
|
|
if (!store.setting.enableSplit) {
|
|
|
store.setting.splitConfig = [0, 1];
|
|
|
}
|
|
|
- const splitConfigPairs = store.setting.splitConfig
|
|
|
- .map((v, index, ary) => (index % 2 === 0 ? [v, ary[index + 1]] : false))
|
|
|
- .filter((v) => v) as unknown as Array<[number, number]>;
|
|
|
+ // 裁切块,可能是一块,两块,三块... [start, width ...] => [0, 0.3] | [0, 0.55, 0.45, 0.55] | [0, 0.35, 0.33, 0.35, 0.66, 0.35]
|
|
|
+ // 要转变为 [[0, 0.3]] | [[0, 0.55], [0.45, 0.55]] | [[0, 0.35], [0.33, 0.35], [0.66, 0.35]]
|
|
|
+ const splitConfigPairs = store.setting.splitConfig.reduce<[number, number][]>(
|
|
|
+ (a, v, index) => {
|
|
|
+ // 偶数位组成数组的第一位,奇数位组成数组的第二位
|
|
|
+ index % 2 === 0 ? a.push([v, -1]) : (a.at(-1)![1] = v);
|
|
|
+ return a;
|
|
|
+ },
|
|
|
+ []
|
|
|
+ );
|
|
|
|
|
|
// 最大的 splitConfig 的宽度
|
|
|
const maxSplitConfig = Math.max(
|
|
@@ -345,7 +354,7 @@ async function processSplitConfig() {
|
|
|
|
|
|
let accumTopHeight = 0;
|
|
|
let accumBottomHeight = 0;
|
|
|
- const tempSliceImagesWithTrackList = [] as Array<SliceImage>;
|
|
|
+ const tempSliceImagesWithTrackList: SliceImage[] = [];
|
|
|
const trackLists = hasMarkResultToRender
|
|
|
? markResult.trackList
|
|
|
: (store.currentTask.questionList || []).map((q) => q.trackList).flat();
|
|
@@ -674,22 +683,21 @@ onUnmounted(() => {
|
|
|
// }, 1000);
|
|
|
|
|
|
//#region autoScroll自动跳转
|
|
|
-let oldFirstScoreContainer: HTMLDivElement;
|
|
|
+let oldFirstScoreContainer: HTMLDivElement | null;
|
|
|
watch(
|
|
|
() => store.currentTask,
|
|
|
() => {
|
|
|
if (store.setting.autoScroll) {
|
|
|
// 给任务清理和动画留一点时间
|
|
|
- oldFirstScoreContainer = document.querySelector(
|
|
|
- ".score-container"
|
|
|
- ) as HTMLDivElement;
|
|
|
+ oldFirstScoreContainer =
|
|
|
+ document.querySelector<HTMLDivElement>(".score-container");
|
|
|
oldFirstScoreContainer?.scrollIntoView({ behavior: "smooth" });
|
|
|
addTimeout(scrollToFirstScore, 1000);
|
|
|
} else {
|
|
|
- const container = document.querySelector(
|
|
|
+ const container = document.querySelector<HTMLDivElement>(
|
|
|
".mark-body-container"
|
|
|
- ) as HTMLDivElement;
|
|
|
- container.scrollTo({ top: 0, left: 0, behavior: "smooth" });
|
|
|
+ );
|
|
|
+ container?.scrollTo({ top: 0, left: 0, behavior: "smooth" });
|
|
|
}
|
|
|
}
|
|
|
);
|
|
@@ -698,12 +706,9 @@ function scrollToFirstScore() {
|
|
|
window.requestAnimationFrame(scrollToFirstScore);
|
|
|
}
|
|
|
addTimeout(() => {
|
|
|
- let firstScore = document.querySelector(
|
|
|
- ".score-container"
|
|
|
- ) as HTMLDivElement;
|
|
|
- if (firstScore) {
|
|
|
- firstScore?.scrollIntoView({ behavior: "smooth" });
|
|
|
- }
|
|
|
+ const firstScore =
|
|
|
+ document.querySelector<HTMLDivElement>(".score-container");
|
|
|
+ firstScore?.scrollIntoView({ behavior: "smooth" });
|
|
|
}, 1000);
|
|
|
}
|
|
|
//#endregion
|
|
@@ -750,9 +755,11 @@ function scrollToFirstScore() {
|
|
|
border: 2px solid transparent;
|
|
|
}
|
|
|
.status-container {
|
|
|
- position: fixed;
|
|
|
- top: 56px;
|
|
|
- right: 340px;
|
|
|
+ position: sticky;
|
|
|
+ /* top: 56px; */
|
|
|
+ bottom: calc(100% - 50px);
|
|
|
+ /* right: 340px; */
|
|
|
+ left: calc(100% - 20px);
|
|
|
color: white;
|
|
|
pointer-events: none;
|
|
|
font-size: var(--app-title-font-size);
|