zhangjie 1 жил өмнө
parent
commit
474e1838d1
39 өөрчлөгдсөн 1476 нэмэгдсэн , 1189 устгасан
  1. 0 12
      src/assets/icons/form-大小.svg
  2. 12 0
      src/assets/icons/icon-all-zero.svg
  3. 0 12
      src/assets/icons/icon-back.svg
  4. 0 0
      src/assets/icons/icon-circle.svg
  5. 12 0
      src/assets/icons/icon-clear-white.svg
  6. 12 0
      src/assets/icons/icon-clear.svg
  7. 15 0
      src/assets/icons/icon-close.svg
  8. 0 0
      src/assets/icons/icon-down.svg
  9. 12 0
      src/assets/icons/icon-drag.svg
  10. 0 0
      src/assets/icons/icon-drag1.svg
  11. 12 0
      src/assets/icons/icon-goback.svg
  12. 12 0
      src/assets/icons/icon-return.svg
  13. 0 0
      src/assets/icons/icon-right.svg
  14. 0 0
      src/assets/icons/icon-star.svg
  15. 0 0
      src/assets/icons/icon-text.svg
  16. 5 5
      src/assets/icons/icon-track-mode.svg
  17. 0 0
      src/assets/icons/icon-up.svg
  18. 0 0
      src/assets/icons/icon-wrong.svg
  19. 0 17
      src/assets/icons/icon-上一页-无法选择.svg
  20. 0 17
      src/assets/icons/icon-下一页.svg
  21. 0 12
      src/assets/icons/icon-下拉.svg
  22. 0 12
      src/assets/icons/icon-清除.svg
  23. BIN
      src/assets/image-none-task.png
  24. 12 38
      src/components/QmDialog.vue
  25. 24 61
      src/features/mark/AllPaperModal.vue
  26. 38 134
      src/features/mark/CommonMarkBody.vue
  27. 1 2
      src/features/mark/Mark.vue
  28. 117 269
      src/features/mark/MarkBoardTrack.vue
  29. 2 3
      src/features/mark/MarkBoardTrackDialog.vue
  30. 2 2
      src/features/mark/MarkChangeProfile.vue
  31. 178 178
      src/features/mark/MarkDrawTrack.vue
  32. 15 154
      src/features/mark/MarkHeader.vue
  33. 9 29
      src/features/mark/MarkHistory.vue
  34. 14 31
      src/features/mark/MarkProblemDialog.vue
  35. 13 41
      src/features/mark/MarkSwitchGroupDialog.vue
  36. 111 8
      src/features/mark/MarkTool.vue
  37. 24 24
      src/features/mark/MinimapModal.vue
  38. 98 104
      src/features/mark/ShortCutModal.vue
  39. 726 24
      src/styles/page.less

+ 0 - 12
src/assets/icons/form-大小.svg

@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg width="12px" height="12px" viewBox="0 0 12 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-    <title>form-大小</title>
-    <g id="页面-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
-        <g id="01-评卷" transform="translate(-196, -70)">
-            <g id="form-大小" transform="translate(196, 70)">
-                <path d="M6,12 C9.3137085,12 12,9.3137085 12,6 C12,2.6862915 9.3137085,0 6,0 C2.6862915,0 0,2.6862915 0,6 C0,9.3137085 2.6862915,12 6,12 Z" id="Ellipse" fill="#165DFF"></path>
-                <circle id="Ellipse" fill="#FFFFFF" cx="6" cy="6" r="4.66666667"></circle>
-            </g>
-        </g>
-    </g>
-</svg>

+ 12 - 0
src/assets/icons/icon-all-zero.svg

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>icon-全部零分</title>
+    <g id="页面-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="01-评卷" transform="translate(-1112, -66)">
+            <g id="icon-全部零分" transform="translate(1112, 66)">
+                <rect id="file-excel-(Background)" opacity="0" x="0" y="0" width="20" height="20"></rect>
+                <path d="M14.30025,11.15 C15.151,11.15 15.81725,11.4985 16.299,12.216 C16.75,12.8925 16.9755,13.80475 16.9755,14.95275 C16.9755,16.10075 16.75,17.013 16.299,17.6895 C15.81725,18.39675 15.151,18.7555 14.30025,18.7555 C13.43925,18.7555 12.773,18.39675 12.3015,17.6895 C11.8505,17.013 11.625,16.10075 11.625,14.95275 C11.625,13.80475 11.8505,12.8925 12.3015,12.216 C12.773,11.4985 13.43925,11.15 14.30025,11.15 Z M11.0823625,1.25 C11.418025,1.25 11.7395875,1.3850025 11.97465,1.624615 L16.51725,6.2550025 C16.746625,6.48869 16.875,6.803015 16.875,7.13039 L16.875,9.3750025 L15.625,9.3750025 L15.625,7.51594 L10.6251,7.51594 L10.6251,2.5000025 L4.375,2.5000025 L4.375,17.5000275 L10,17.5000275 L10,18.7500275 L4.369175,18.7500275 C3.7750625,18.7500275 3.125,18.3284025 3.125,17.5976525 L3.125,2.40239 C3.125,1.67159 3.7750625,1.25 4.369175,1.25 L11.0823625,1.25 Z M14.30025,12.16475 C13.716,12.16475 13.306,12.4825 13.07025,13.1385 C12.90625,13.57925 12.82425,14.184 12.82425,14.95275 C12.82425,15.71125 12.90625,16.316 13.07025,16.767 C13.306,17.41275 13.716,17.74075 14.30025,17.74075 C14.87425,17.74075 15.28425,17.41275 15.53025,16.767 C15.69425,16.316 15.77625,15.71125 15.77625,14.95275 C15.77625,14.184 15.69425,13.57925 15.53025,13.1385 C15.28425,12.4825 14.87425,12.16475 14.30025,12.16475 Z M11.8751,3.308065 L11.8751,6.26594 L14.776875,6.26594 L11.8751,3.308065 Z" id="形状结合" fill="#262626"></path>
+            </g>
+        </g>
+    </g>
+</svg>

+ 0 - 12
src/assets/icons/icon-back.svg

@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-    <title>icon-返回</title>
-    <g id="页面-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
-        <g id="01-评卷" transform="translate(-1306, -19)">
-            <g id="icon-返回" transform="translate(1306, 19)">
-                <rect id="rollback-(Background)" opacity="0" x="0" y="0" width="18" height="18"></rect>
-                <path d="M6.58533248,3.7727901 L5.78983757,2.97729492 L2.93314325,5.833989 C2.73788107,6.02925111 2.73788105,6.3458336 2.93314319,6.54109575 C2.9331432,6.54109576 2.93314321,6.54109577 2.93314325,6.54109575 L5.78983757,9.39778984 L5.78983757,9.39778984 L6.58533248,8.60229492 L4.73307994,6.75004238 L11.2500848,6.75004238 C13.1140462,6.75004238 14.6250848,8.26108092 14.6250848,10.1250424 C14.6250848,11.9890038 13.1140462,13.5000429 11.2500848,13.5000429 L5.62508503,13.5000429 L5.62508503,14.6250429 L11.2500848,14.6250429 C13.735366,14.6250429 15.7500848,12.6103236 15.7500848,10.1250424 C15.7500848,7.63976115 13.735366,5.62504238 11.2500848,5.62504238 L4.73307994,5.62504238 L6.58533248,3.7727901 Z" id="rollback" fill="#FFFFFF"></path>
-            </g>
-        </g>
-    </g>
-</svg>

+ 0 - 0
src/assets/icons/icon-圈取.svg → src/assets/icons/icon-circle.svg


+ 12 - 0
src/assets/icons/icon-clear-white.svg

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>icon-清空白</title>
+    <g id="页面-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="02-按钮状态" transform="translate(-1319, -780)">
+            <g id="icon-清空白" transform="translate(1319, 780)">
+                <rect id="clear-(Background)" opacity="0" x="0" y="0" width="16" height="16"></rect>
+                <path d="M7,4 L9,4 L9,2 L7,2 L7,4 Z M10,2 L10,4 L13,4 C13.5523,4 14,4.44772 14,5 L14,7 C14,7.50427 13.6267,7.92137 13.1414,7.99007 L13.8369,12.8586 C13.923,13.461 13.4555,14 12.847,14 L3.15301,14 C2.54446,14 2.077,13.461 2.16306,12.8586 L2.85856,7.99007 C2.37326,7.92137 2,7.50427 2,7 L2,5 C2,4.44772 2.44772,4 3,4 L6,4 L6,2 C6,1.44772 6.44772,1 7,1 L9,1 C9.55228,1 10,1.44772 10,2 Z M12.1327,7 L13,7 L13,5 L9,5 L7,5 L3,5 L3,7 L3.8673,7 L12.1327,7 Z M12.1327,8 L3.8673,8 L3.15301,13 L5,13 L5,11 L6,11 L6,13 L7.5,13 L7.5,11 L8.5,11 L8.5,13 L10,13 L10,11 L11,11 L11,13 L12.847,13 L12.1327,8 Z" id="clear" fill="#FFFFFF"></path>
+            </g>
+        </g>
+    </g>
+</svg>

+ 12 - 0
src/assets/icons/icon-clear.svg

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>icon-清空</title>
+    <g id="页面-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="01-评卷" transform="translate(-1319, -780)">
+            <g id="icon-清空" transform="translate(1319, 780)">
+                <rect id="clear-(Background)" opacity="0" x="0" y="0" width="16" height="16"></rect>
+                <path d="M7,4 L9,4 L9,2 L7,2 L7,4 Z M10,2 L10,4 L13,4 C13.5523,4 14,4.44772 14,5 L14,7 C14,7.50427 13.6267,7.92137 13.1414,7.99007 L13.8369,12.8586 C13.923,13.461 13.4555,14 12.847,14 L3.15301,14 C2.54446,14 2.077,13.461 2.16306,12.8586 L2.85856,7.99007 C2.37326,7.92137 2,7.50427 2,7 L2,5 C2,4.44772 2.44772,4 3,4 L6,4 L6,2 C6,1.44772 6.44772,1 7,1 L9,1 C9.55228,1 10,1.44772 10,2 Z M12.1327,7 L13,7 L13,5 L9,5 L7,5 L3,5 L3,7 L3.8673,7 L12.1327,7 Z M12.1327,8 L3.8673,8 L3.15301,13 L5,13 L5,11 L6,11 L6,13 L7.5,13 L7.5,11 L8.5,11 L8.5,13 L10,13 L10,11 L11,11 L11,13 L12.847,13 L12.1327,8 Z" id="clear" fill="#F53F3F"></path>
+            </g>
+        </g>
+    </g>
+</svg>

+ 15 - 0
src/assets/icons/icon-close.svg

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>icon-关闭</title>
+    <g id="页面-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="04-切换分组" transform="translate(-867, -287)">
+            <g id="icon-关闭" transform="translate(867, 287)">
+                <rect id="矩形" x="0" y="0" width="24" height="24" rx="4"></rect>
+                <g id="1.Base基础/3.Icon图标/操作/close-normal" transform="translate(4, 4)">
+                    <path d="M16,3 L16,13 C16,14.6568542 14.6568542,16 13,16 L3,16 C1.34314575,16 1.01453063e-16,14.6568542 0,13 L0,3 C-2.02906125e-16,1.34314575 1.34314575,2.02906125e-16 3,0 L13,0 C14.6568542,-3.04359188e-16 16,1.34314575 16,3 Z" id="矩形" opacity="0"></path>
+                    <polygon id="Vector-(Stroke)" fill="#595959" points="4.00484467 4.92412162 4.92408347 4.00488281 7.99999809 7.08079767 11.0759125 4.00488281 11.9951515 4.92412162 8.91923666 8.00003624 11.9951515 11.0759506 11.0759125 11.9951897 7.99999809 8.91927481 4.92408347 11.9951897 4.00484467 11.0759506 7.08075953 8.00003624"></polygon>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

+ 0 - 0
src/assets/icons/icon-向下.svg → src/assets/icons/icon-down.svg


+ 12 - 0
src/assets/icons/icon-drag.svg

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>icon-拖动</title>
+    <g id="页面-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="01-评卷" transform="translate(-1251, -444)">
+            <g id="icon-拖动" transform="translate(1251, 444)">
+                <rect id="view-list-(Background)" opacity="0" x="0" y="0" width="14" height="14"></rect>
+                <path d="M1.75,3.9375 L1.75,3.0625 L12.25,3.0625 L12.25,3.9375 L1.75,3.9375 Z M1.75,7.4375 L1.75,6.5625 L12.25,6.5625 L12.25,7.4375 L1.75,7.4375 Z M12.25,10.9375 L12.25,10.0625 L1.75,10.0625 L1.75,10.9375 L12.25,10.9375 Z" id="view-list" fill="#262626"></path>
+            </g>
+        </g>
+    </g>
+</svg>

+ 0 - 0
src/assets/icons/icon-拖动.svg → src/assets/icons/icon-drag1.svg


+ 12 - 0
src/assets/icons/icon-goback.svg

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>icon-回退</title>
+    <g id="页面-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="01-评卷" transform="translate(-1145, -780)">
+            <g id="icon-回退" transform="translate(1145, 780)">
+                <rect id="rollback-(Background)" opacity="0" x="0" y="0" width="16" height="16"></rect>
+                <path d="M5.85362887,3.3535912 L5.14652228,2.64648438 L2.64652216,5.14648429 C2.45125997,5.3417464 2.45125996,5.65832889 2.6465221,5.85359105 C2.64652211,5.85359106 2.64652212,5.85359107 2.64652216,5.85359105 L5.14652228,8.35359097 L5.14652228,8.35359097 L5.85362887,7.64648438 L4.20718217,6.00003767 L10.0000753,6.00003767 C11.65693,6.00003767 13.0000753,7.34318304 13.0000753,9.00003767 C13.0000753,10.6568923 11.65693,12.0000381 10.0000753,12.0000381 L5.00007558,12.0000381 L5.00007558,13.0000381 L10.0000753,13.0000381 C12.2092142,13.0000381 14.0000753,11.2091765 14.0000753,9.00003767 C14.0000753,6.7908988 12.2092142,5.00003767 10.0000753,5.00003767 L4.20718217,5.00003767 L5.85362887,3.3535912 Z" id="rollback" fill-opacity="0.9" fill="#000000"></path>
+            </g>
+        </g>
+    </g>
+</svg>

+ 12 - 0
src/assets/icons/icon-return.svg

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>icon-返回</title>
+    <g id="页面-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="01-评卷" transform="translate(-1308, -20)">
+            <g id="icon-返回" transform="translate(1308, 20)">
+                <rect id="swap-left-(Background)" opacity="0" x="0" y="0" width="16" height="16"></rect>
+                <path d="M1.54160998,6.14637125 L1.54160998,5.14637125 L14.4691813,5.14637125 C14.9413645,5.14637125 15.1778366,5.71727303 14.8439362,6.05115283 L10.8951552,9.99975527 L10.1880648,9.29263247 L13.3344652,6.14637125 L1.54160998,6.14637125 Z" id="swap-left" fill="#FFFFFF" transform="translate(8.2709, 7.5731) rotate(-180) translate(-8.2709, -7.5731)"></path>
+            </g>
+        </g>
+    </g>
+</svg>

+ 0 - 0
src/assets/icons/icon-对.svg → src/assets/icons/icon-right.svg


+ 0 - 0
src/assets/icons/icon-总数.svg → src/assets/icons/icon-star.svg


+ 0 - 0
src/assets/icons/icon-文本.svg → src/assets/icons/icon-text.svg


+ 5 - 5
src/assets/icons/icon-track-mode.svg

@@ -1,11 +1,11 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
     <title>icon-模式</title>
     <g id="页面-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
-        <g id="01-评卷" transform="translate(-954, -19)">
-            <g id="icon-模式" transform="translate(954, 19)">
-                <rect id="app-(Background)" opacity="0" x="0" y="0" width="18" height="18"></rect>
-                <path d="M9.28125,5.34375 C9.28125,7.20771092 10.7922891,8.71875 12.65625,8.71875 C14.5202115,8.71875 16.03125,7.20771092 16.03125,5.34375 C16.03125,3.47978908 14.5202115,1.96875 12.65625,1.96875 C10.7922891,1.96875 9.28125,3.47978908 9.28125,5.34375 Z M12.65625,7.59375 C13.8988906,7.59375 14.90625,6.58639061 14.90625,5.34375 C14.90625,4.10110952 13.8988906,3.09375 12.65625,3.09375 C11.4136094,3.09375 10.40625,4.10110952 10.40625,5.34375 C10.40625,6.58639061 11.4136094,7.59375 12.65625,7.59375 Z M3.375,2.25 L7.3125,2.25 C7.93382031,2.25 8.4375,2.75367969 8.4375,3.375 L8.4375,7.3125 C8.4375,7.93382031 7.93382031,8.4375 7.3125,8.4375 L3.375,8.4375 C2.75367969,8.4375 2.25,7.93382031 2.25,7.3125 L2.25,3.375 C2.25,2.75367969 2.75367969,2.25 3.375,2.25 Z M7.3125,3.375 L7.3125,7.3125 L3.375,7.3125 L3.375,3.375 L7.3125,3.375 Z M3.375,9.5625 L7.3125,9.5625 C7.93382031,9.5625 8.4375,10.0661797 8.4375,10.6875 L8.4375,14.625 C8.4375,15.2463198 7.93382031,15.75 7.3125,15.75 L3.375,15.75 C2.75367969,15.75 2.25,15.2463198 2.25,14.625 L2.25,10.6875 C2.25,10.0661797 2.75367969,9.5625 3.375,9.5625 Z M7.3125,10.6875 L7.3125,14.625 L3.375,14.625 L3.375,10.6875 L7.3125,10.6875 Z M10.6875,9.5625 L14.625,9.5625 C15.2463198,9.5625 15.75,10.0661797 15.75,10.6875 L15.75,14.625 C15.75,15.2463198 15.2463198,15.75 14.625,15.75 L10.6875,15.75 C10.0661797,15.75 9.5625,15.2463198 9.5625,14.625 L9.5625,10.6875 C9.5625,10.0661797 10.0661797,9.5625 10.6875,9.5625 Z M10.6875,10.6875 L14.625,10.6875 L14.625,14.625 L10.6875,14.625 L10.6875,10.6875 Z" id="app" fill="#FFFFFF"></path>
+        <g id="01-评卷" transform="translate(-964, -20)">
+            <g id="icon-模式" transform="translate(964, 20)">
+                <rect id="layers-(Background)" opacity="0" x="0" y="0" width="16" height="16"></rect>
+                <path d="M7.99975586,7.5084095 L1.92640564,4.97791052 C1.5159767,4.80690241 1.51597583,4.20040798 1.92640558,4.02939963 L7.99975586,1.49890137 L14.0731058,4.02939963 C14.4835348,4.20040751 14.4835358,4.80690193 14.0731068,4.97791028 L7.99975586,7.5084095 Z M7.99975586,2.59850323 L12.572237,4.50365543 L7.99975538,6.40880775 L3.42727458,4.50365567 L7.99975586,2.59850323 Z M1.49902344,8.25379086 L8.00001335,11.1119394 L14.4990234,8.25466061 L14.4990234,7.02751637 L8.00001335,9.88479519 L1.49902344,7.02664614 L1.49902344,8.25379086 Z M1.49902344,11.6465769 L8.00010777,14.5047674 L14.4990234,11.6475306 L14.4990234,10.4203844 L8.00010777,13.2776222 L1.49902344,10.4194317 L1.49902344,11.6465769 Z" id="layers" fill="#FFFFFF"></path>
             </g>
         </g>
     </g>

+ 0 - 0
src/assets/icons/icon-向上.svg → src/assets/icons/icon-up.svg


+ 0 - 0
src/assets/icons/icon-叉.svg → src/assets/icons/icon-wrong.svg


+ 0 - 17
src/assets/icons/icon-上一页-无法选择.svg

@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-    <title>icon-上一页-无法选择</title>
-    <g id="页面-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
-        <g id="01-评卷" transform="translate(-101, -772)">
-            <g id="icon-上一页-无法选择" transform="translate(101, 772)">
-                <g id="1.Base基础/1.Button按钮/按钮背景/1.Fill/Gray中性/Transparent/矩形" opacity="0">
-                    <rect id="按钮背景" x="0" y="0" width="32" height="32"></rect>
-                </g>
-                <g id="1.Base基础/3.Icon图标/操作/search" transform="translate(8, 8)">
-                    <polygon id="矩形" opacity="0" transform="translate(8, 8) scale(-1, -1) rotate(-90) translate(-8, -8)" points="16.0000003 3.49691106e-07 16.0000003 16.0000003 3.49691049e-07 16.0000003 3.49691049e-07 3.49691106e-07"></polygon>
-                    <polygon id="路径-4-(Stroke)" fill="#BFBFBF" transform="translate(7.7702, 8) scale(-1, -1) rotate(-90) translate(-7.7702, -8)" points="4.22981599 5.31059633 7.7701967 8.85097681 11.3105772 5.31059633 12.2298162 6.22983514 7.7701967 10.6894544 3.31057718 6.22983514"></polygon>
-                </g>
-            </g>
-        </g>
-    </g>
-</svg>

+ 0 - 17
src/assets/icons/icon-下一页.svg

@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-    <title>icon-下一页</title>
-    <g id="页面-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
-        <g id="01-评卷" transform="translate(-280, -772)">
-            <g id="icon-下一页" transform="translate(280, 772)">
-                <g id="1.Base基础/1.Button按钮/按钮背景/1.Fill/Gray中性/Transparent/矩形" opacity="0">
-                    <rect id="按钮背景" x="0" y="0" width="32" height="32"></rect>
-                </g>
-                <g id="1.Base基础/3.Icon图标/操作/search" transform="translate(8, 8)">
-                    <polygon id="矩形" opacity="0" transform="translate(8, 8) scale(-1, -1) rotate(90) translate(-8, -8)" points="16.0000003 3.49691106e-07 16.0000003 16.0000003 3.49691106e-07 16.0000003 3.49691106e-07 3.49691106e-07"></polygon>
-                    <polygon id="路径-4-(Stroke)" fill="#262626" transform="translate(8.2298, 8) scale(-1, -1) rotate(90) translate(-8.2298, -8)" points="4.68942359 5.31054674 8.22980431 8.85092722 11.7701848 5.31054674 12.6894238 6.22978555 8.22980431 10.6894048 3.77018478 6.22978555"></polygon>
-                </g>
-            </g>
-        </g>
-    </g>
-</svg>

+ 0 - 12
src/assets/icons/icon-下拉.svg

@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-    <title>icon-下拉</title>
-    <g id="页面-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
-        <g id="01-评卷" transform="translate(-56, -171)">
-            <g id="icon-下拉" transform="translate(56, 171)">
-                <polygon id="矩形" opacity="0" points="16 0 16 16 0 16 0 0"></polygon>
-                <polygon id="路径-4-(Stroke)" fill="#8C8C8C" points="4.45961356 5.54040527 7.99999428 9.08078575 11.5403748 5.54040527 12.4596138 6.45964408 7.99999428 10.9192634 3.54037476 6.45964408"></polygon>
-            </g>
-        </g>
-    </g>
-</svg>

+ 0 - 12
src/assets/icons/icon-清除.svg

@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-    <title>icon-清除</title>
-    <g id="页面-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
-        <g id="01-评卷" transform="translate(-1281, -341)">
-            <g id="icon-清除" transform="translate(1281, 341)">
-                <rect id="delete-(Background)" opacity="0" x="0" y="0" width="14" height="14"></rect>
-                <path d="M5.25,5.25 L6.125,5.25 L6.125,10.5 L5.25,10.5 L5.25,5.25 Z M7.875,10.5 L8.75,10.5 L8.75,5.25 L7.875,5.25 L7.875,10.5 Z M12.25,2.625 L12.25,3.5 L11.375,3.5 L11.375,12.25 C11.375,12.7332495 10.9832487,13.125 10.5,13.125 L3.5,13.125 C3.01675066,13.125 2.625,12.7332487 2.625,12.25 L2.625,3.5 L1.75,3.5 L1.75,2.625 L4.8125,2.625 L4.81249979,1.57500064 C4.81249979,1.18840141 5.12590066,0.875 5.51250017,0.875 L8.48749983,0.875 C8.87409914,0.875 9.1875,1.18840063 9.1875,1.57500011 L9.1875,2.625 L12.25,2.625 Z M5.6875,1.75000063 L8.31249958,1.75000031 L8.3125,2.625 L5.6875,2.625 L5.6875,1.75000063 Z M3.5,12.25 L10.5,12.25 L10.5,3.5 L3.5,3.5 L3.5,12.25 Z" id="delete" fill="#262626"></path>
-            </g>
-        </g>
-    </g>
-</svg>

BIN
src/assets/image-none-task.png


+ 12 - 38
src/components/QmDialog.vue

@@ -1,31 +1,28 @@
 <template>
   <teleport to="body">
     <div
-      class="dialog-container"
+      :class="['qm-dialog', customClass]"
       :style="positionStyle"
       @click="increaseZIndex"
     >
-      <header
+      <div
         ref="mouseHandler"
-        class="tw-flex tw-place-content-between tw-items-center"
+        class="qm-dialog-header"
+        @mousedown="handleDragMouseDown"
       >
-        <div
-          class="tw-text-base tw-ml-5 tw-my-2 tw-cursor-move tw-flex-grow tw-font-bold"
-          @mousedown="handleDragMouseDown"
-        >
+        <div class="qm-dialog-title">
           {{ title }}
         </div>
+
         <a-button
-          shape="circle"
-          size="small"
-          class="tw-mr-2"
+          class="qm-dialog-close"
+          @mousedown.stop
           @click="$emit('close')"
         >
-          <template #icon><CloseOutlined /></template>
         </a-button>
-      </header>
+      </div>
 
-      <div class="tw-m-1 tw-overflow-auto" style="height: calc(100% - 50px)">
+      <div class="qm-dialog-body">
         <slot></slot>
       </div>
 
@@ -40,7 +37,6 @@
 
 <script setup lang="ts">
 import { onMounted, onUpdated, reactive } from "vue";
-import { CloseOutlined } from "@ant-design/icons-vue";
 import { store } from "@/store/store";
 
 // 因为要更改props取得的值,所以不需要reactivity
@@ -52,6 +48,7 @@ const {
   zIndex = 1020,
   enableResize = true,
   fixedWidth = false,
+  customClass = "",
 } = defineProps<{
   title: string;
   top?: string;
@@ -60,6 +57,7 @@ const {
   zIndex?: number;
   enableResize?: boolean;
   fixedWidth?: boolean;
+  customClass?: string;
 }>();
 
 defineEmits(["close"]);
@@ -174,27 +172,3 @@ const increaseZIndex = () => {
   }
 };
 </script>
-
-<style scoped>
-.dialog-container {
-  z-index: 1020;
-  position: absolute;
-  min-width: 100px;
-  background-color: var(--app-container-bg-color);
-  border: 1px solid var(--app-main-bg-color);
-  border-radius: 5px;
-  box-shadow: 0px 4px 8px 0px rgba(25, 27, 55, 0.1);
-}
-header {
-  color: var(--app-main-text-color);
-  border-bottom: 1px solid var(--app-main-bg-color);
-}
-.resize-handler {
-  position: absolute;
-  bottom: -10px;
-  right: -10px;
-  width: 20px;
-  height: 20px;
-  cursor: nwse-resize;
-}
-</style>

+ 24 - 61
src/features/mark/AllPaperModal.vue

@@ -1,44 +1,39 @@
 <template>
   <teleport to="body">
-    <div v-if="store.allPaperModal" class="dialog-container">
-      <header class="tw-flex tw-place-content-between tw-items-center">
-        <div class="tw-text-2xl ctw-text-base tw-ml-5 tw-my-2">全卷切换</div>
-        <div class="tw-flex tw-items-center tw-gap-2 tw-mx-8 tw-flex-grow">
-          <span
-            v-for="(u, index) in urls"
-            :key="index"
-            class="image-index hover:tw-bg-gray-300"
-            :class="checkedIndex === index && 'tw-bg-gray-300'"
-            @click="checkedIndex = index"
-          >
-            {{ index + 1 }}
-          </span>
+    <div
+      v-if="store.allPaperModal"
+      class="common-dialog is-fullscreen all-paper-modal"
+    >
+      <header class="common-dialog-header">
+        <div>
+          <div class="common-dialog-title">全卷切换</div>
+          <div class="paper-menu">
+            <span
+              v-for="(u, index) in urls"
+              :key="index"
+              :class="{ 'is-active': checkedIndex === index }"
+              @click="checkedIndex = index"
+            >
+              {{ index + 1 }}
+            </span>
+          </div>
         </div>
-        <a-button
-          shape="circle"
-          class="tw-mr-2"
-          @click="store.allPaperModal = false"
-        >
-          <template #icon><CloseOutlined /></template>
+
+        <a-button @click="store.allPaperModal = false">
+          <template #icon> <SwapLeftOutlined /> </template>
+          返回
         </a-button>
       </header>
 
-      <div>
-        <div
-          v-for="(url, index) in urls"
-          :key="index"
-          style="display: none"
-          :class="index === checkedIndex && 'show-image'"
-        >
-          <img :src="url" />
-        </div>
+      <div class="common-dialog-body">
+        <img :src="urls[checkedIndex]" />
       </div>
     </div>
   </teleport>
 </template>
 
 <script setup lang="ts">
-import { CloseOutlined } from "@ant-design/icons-vue";
+import { SwapLeftOutlined } from "@ant-design/icons-vue";
 import { store } from "@/store/store";
 
 const urls = $computed(() => {
@@ -47,35 +42,3 @@ const urls = $computed(() => {
 
 let checkedIndex = $ref(0);
 </script>
-
-<style scoped>
-.dialog-container {
-  /* always top */
-  z-index: 99999;
-  position: absolute;
-  background-color: white;
-  top: 0;
-  left: 0;
-  width: 100vw;
-  height: 100vh;
-  overflow: auto;
-  min-width: var(--app-min-width);
-}
-header {
-  color: var(--app-main-text-color);
-  border-bottom: 1px solid var(--app-main-bg-color);
-}
-.image-index {
-  display: inline-block;
-  border: 1px solid grey;
-  width: 25px;
-  text-align: center;
-  border-radius: 5px;
-
-  cursor: pointer;
-}
-
-.show-image {
-  display: block !important;
-}
-</style>

+ 38 - 134
src/features/mark/CommonMarkBody.vue

@@ -1,85 +1,48 @@
 <template>
-  <div
-    ref="dragContainer"
-    class="mark-body-container tw-flex-auto tw-p-2 tw-pt-0 tw-relative"
-  >
-    <div
-      v-if="!store.currentTask"
-      class="tw-text-center empty-task tw-flex tw-flex-col tw-place-items-center tw-justify-center"
-    >
-      <img src="./images/empty-task.png" />
-      {{ store.message }}
-    </div>
-    <div
-      v-else-if="store.isScanImage"
-      :style="{ width: answerPaperScale }"
-      :class="['tw-pt-2', `rotate-board-${rotateBoard}`]"
-    >
-      <div
-        v-for="(item, index) in sliceImagesWithTrackList"
-        :key="index"
-        class="single-image-container"
-      >
-        <img
-          :src="item.url"
-          draggable="false"
-          @click="(event) => innerMakeTrack(event, item)"
-          @contextmenu="showBigImage"
-        />
-        <MarkDrawTrack
-          :trackList="item.trackList"
-          :specialTagList="item.tagList"
-          :sliceImageWidth="item.sliceImageWidth"
-          :sliceImageHeight="item.sliceImageHeight"
-          :dx="item.dx"
-          :dy="item.dy"
-        />
-        <hr class="image-seperator" />
-      </div>
-    </div>
-    <div v-else-if="store.isMultiMedia">
-      <MultiMediaMarkBody />
-    </div>
-    <div v-else>impossible</div>
-    <div v-if="markStatus" class="status-container">
+  <div class="mark-body">
+    <div v-if="markStatus" class="mark-body-status">
       {{ markStatus }}
-      <div class="double-triangle"></div>
     </div>
-    <ZoomPaper
-      v-if="
-        store.isScanImage &&
-        store.currentTask &&
-        sliceImagesWithTrackList.length
-      "
-    />
-
-    <!-- 非启用功能 -->
-    <div class="kb-circle tw-hidden">
+    <div ref="dragContainer" class="mark-body-container">
+      <div v-if="!store.currentTask" class="mark-body-none">
+        <div>
+          <img src="@/assets/image-none-task.png" />
+          <p>
+            {{ store.message }}
+          </p>
+        </div>
+      </div>
       <div
-        style="
-          text-align: center;
-          margin-top: -20px;
-          color: red;
-          font-weight: bold;
-          background-color: rgb(248, 250, 250);
-          height: 12px;
-          opacity: 0.7;
-        "
+        v-else-if="store.isScanImage"
+        :style="{ width: answerPaperScale }"
+        :class="[`rotate-board-${rotateBoard}`]"
       >
-        <!-- {{ store.currentQuestion?.title }} -->
-        {{ store.currentQuestion?.mainNumber }}-{{
-          store.currentQuestion?.subNumber
-        }}({{
-          store.currentTask?.markResult
-            ? store.currentTask?.markResult.scoreList[
-                store.currentQuestion?.__index || 0
-              ]
-            : " "
-        }})
+        <div
+          v-for="(item, index) in sliceImagesWithTrackList"
+          :key="index"
+          class="single-image-container"
+        >
+          <img
+            :src="item.url"
+            draggable="false"
+            @click="(event) => innerMakeTrack(event, item)"
+            @contextmenu="showBigImage"
+          />
+          <MarkDrawTrack
+            :trackList="item.trackList"
+            :specialTagList="item.tagList"
+            :sliceImageWidth="item.sliceImageWidth"
+            :sliceImageHeight="item.sliceImageHeight"
+            :dx="item.dx"
+            :dy="item.dy"
+          />
+          <hr class="image-seperator" />
+        </div>
       </div>
-      <div class="text">
-        {{ store.currentSpecialTag || store.currentScore }}
+      <div v-else-if="store.isMultiMedia">
+        <MultiMediaMarkBody />
       </div>
+      <div v-else>未知数据</div>
     </div>
   </div>
 </template>
@@ -99,7 +62,6 @@ import { dragImage } from "./use/draggable";
 import MultiMediaMarkBody from "./MultiMediaMarkBody.vue";
 import "viewerjs/dist/viewer.css";
 import Viewer from "viewerjs";
-import ZoomPaper from "@/components/ZoomPaper.vue";
 import { message } from "ant-design-vue";
 import EventBus from "@/plugins/eventBus";
 type MakeTrack = (
@@ -741,61 +703,6 @@ function scrollToFirstScore() {
 </script>
 
 <style scoped>
-.mark-body-container {
-  position: relative;
-  min-height: calc(100vh - 56px);
-  height: calc(100vh - 56px);
-  overflow: auto;
-  /* background-size: 8px 8px;
-  background-image: linear-gradient(to right, #e7e7e7 4px, transparent 4px),
-    linear-gradient(to bottom, transparent 4px, #e7e7e7 4px); */
-  background-color: var(--app-container-bg-color);
-  background-image: linear-gradient(45deg, #e0e0e0 25%, transparent 25%),
-    linear-gradient(-45deg, #e0e0e0 25%, transparent 25%),
-    linear-gradient(45deg, transparent 75%, #e0e0e0 75%),
-    linear-gradient(-45deg, transparent 75%, #e0e0e0 75%);
-  background-size: 20px 20px;
-  background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
-  transform: inherit;
-}
-.mark-body-container img {
-  width: 100%;
-}
-.empty-task {
-  width: calc(100%);
-  height: calc(100%);
-  font-size: 20px;
-  overflow: hidden;
-  background-color: var(--app-container-bg-color);
-}
-.empty-task img {
-  display: block;
-  width: 288px;
-  height: 225px;
-  clip-path: polygon(0 0, 0 80%, 100% 80%, 100% 0);
-}
-.single-image-container {
-  position: relative;
-}
-.image-seperator {
-  border: 2px solid transparent;
-}
-.status-container {
-  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);
-  background-color: #ef7c78;
-
-  width: 30px;
-  height: 50px;
-  text-align: center;
-  z-index: 1000;
-}
 .double-triangle {
   background-color: #ef7c78;
   width: 30px;
@@ -820,9 +727,6 @@ function scrollToFirstScore() {
     opacity: 0;
   }
 }
-.rotate-board-1 {
-  /* animation: rotate 0.6s ease-in-out; */
-}
 
 .kb-circle {
   position: fixed;

+ 1 - 2
src/features/mark/Mark.vue

@@ -1,14 +1,13 @@
 <template>
   <div class="mark">
     <mark-header :showTotalScore="store.isMultiMedia" />
-    <mark-tool />
+    <mark-tool @allZeroSubmit="allZeroSubmit" />
     <div class="mark-main">
       <mark-history showSearch showOrder :getHistory="getHistoryTask" />
       <mark-body @error="removeBrokenTask" />
       <mark-board-track
         v-if="store.isTrackMode"
         @submit="saveTaskToServer"
-        @allZeroSubmit="allZeroSubmit"
         @unselectiveSubmit="unselectiveSubmit"
       />
       <mark-board-key-board

+ 117 - 269
src/features/mark/MarkBoardTrack.vue

@@ -1,12 +1,11 @@
 <template>
   <div
     v-if="store.currentTask"
-    class="mark-board-track-container tw-flex tw-flex-col"
+    class="mark-board-track"
     :class="[
       {
         hide: store.isScoreBoardCollapsed && !props.modal,
-        'mark-board-track-container-in-dialog':
-          store.isScoreBoardCollapsed && !props.modal,
+        'in-dialog': store.isScoreBoardCollapsed && props.modal,
         show: !store.isScoreBoardCollapsed,
       },
     ]"
@@ -14,28 +13,30 @@
       height: props.modal ? '100%' : 'auto',
     }"
   >
+    <div class="board-header">
+      <div class="board-header-info">
+        <img src="@/assets/icons/icon-star.svg" /><span>总分</span>
+      </div>
+      <div class="board-header-score">
+        <transition-group name="score-number-animation" tag="span">
+          <span :key="store.currentTask.markResult?.markerScore || 0">{{
+            store.currentTask.markResult?.markerScore
+          }}</span>
+        </transition-group>
+      </div>
+    </div>
+    <qm-button
+      class="board-submit"
+      size="medium"
+      type="primary"
+      @click="submit"
+    >
+      提交
+    </qm-button>
+    <!-- 暂时隐藏
     <div
       class="tw-flex tw-rounded tw-justify-between tw-p-2 tw-pl-5 top-container tw-mb-4"
     >
-      <div class="tw-flex tw-flex-col">
-        <div class="tw-flex tw-items-center tw-gap-2">
-          <img
-            src="./images/totalscore.png"
-            style="width: 13px; height: 16px"
-          />
-          总分
-        </div>
-        <div class="total-score tw-ml-5 tw-font-bold" style="height: 50px">
-          <transition-group name="score-number-animation" tag="span">
-            <span
-              :key="store.currentTask.markResult?.markerScore || 0"
-              class="tw-inline-block"
-              >{{ store.currentTask.markResult?.markerScore }}</span
-            >
-          </transition-group>
-        </div>
-      </div>
-
       <div class="tw-flex tw-place-content-center tw-items-center tw-gap-2">
         <div class="tw-flex tw-flex-col tw-gap-1">
           <a-popconfirm
@@ -67,57 +68,20 @@
             </a-button>
           </a-popconfirm>
         </div>
-
-        <qm-button
-          type="primary"
-          shape="round"
-          size="middle"
-          style="height: 76px; border-radius: 10px; padding: 12px"
-          @click="submit"
-        >
-          提交
-        </qm-button>
       </div>
     </div>
+    -->
 
     <div
-      style="
-        height: calc(100% - 56px);
-        overflow: hidden;
-        user-select: none;
-        position: relative;
-      "
+      v-if="store.currentTask && store.currentTask.questionList"
+      class="board-questions"
+      :style="{ height: `${topPercent}%` }"
     >
-      <div
-        v-if="store.currentTask && store.currentTask.questionList"
-        class="tw-flex tw-gap-2 tw-flex-wrap tw-justify-between tw-overflow-auto tw-content-start"
-        :style="{ height: `${topPercent}%` }"
+      <template
+        v-for="(question, index) in store.currentTask.questionList"
+        :key="index"
       >
-        <template
-          v-for="(question, index) in store.currentTask.questionList"
-          :key="index"
-        >
-          <!-- <div
-            :id="
-              store.isScoreBoardCollapsed
-                ? props.modal
-                  ? ['bq', question.mainNumber, question.subNumber].join('-')
-                  : ''
-                : ['bq', question.mainNumber, question.subNumber].join('-')
-            "
-            class="question tw-rounded tw-cursor-pointer tw-relative tw-mb-2"
-            :class="isCurrentQuestion(question) && 'current-question'"
-            @click="chooseQuestion(question)"
-            @mouseover="
-              addFocusTrack(
-                undefined,
-                question.mainNumber,
-                question.subNumber,
-                true
-              )
-            "
-            @mouseleave="removeFocusTrack"
-          > -->
+        <div class="board-quesion-box">
           <div
             :id="
               store.isScoreBoardCollapsed
@@ -126,8 +90,10 @@
                   : ''
                 : ['bq', question.mainNumber, question.subNumber].join('-')
             "
-            class="question tw-rounded tw-cursor-pointer tw-relative tw-mb-2"
-            :class="isCurrentQuestion(question) && 'current-question'"
+            :class="[
+              'board-quesion',
+              { 'is-current': isCurrentQuestion(question) },
+            ]"
             tabindex="0"
             outline="0"
             hidefocus="true"
@@ -151,20 +117,19 @@
                 定位
               </div>
             </div>
-            <div v-if="!!question.questionName" class="tihao">
+            <div v-if="!!question.questionName" class="quesion-title">
               {{ question.questionName }}
             </div>
-            <div v-else class="tihao">
+            <div v-else class="quesion-title">
               {{ question.title }} {{ question.mainNumber }}-{{
                 question.subNumber
               }}
             </div>
             <!-- 设置高度 避免动画跳动 -->
-            <div style="height: 32px">
+            <div class="quesion-score">
               <transition-group name="score-number-animation" tag="span">
                 <span
                   :key="store.currentTask?.markResult?.scoreList[index] || 0"
-                  class="tw-font-medium tw-text-2xl score tw-inline-block"
                 >
                   <!-- 特殊的空格符号 -->
                   <!-- eslint-disable-next-line no-irregular-whitespace -->
@@ -173,103 +138,103 @@
               </transition-group>
             </div>
           </div>
-        </template>
+        </div>
+      </template>
+    </div>
+    <div ref="dragSpliter" class="board-spliter">
+      <div class="board-spliter-up" @click="topPercent = 20">
+        <img src="@/assets/icons/icon-up.svg" />
       </div>
-
+      <div class="board-spliter-bar">
+        <img src="@/assets/icons/icon-drag.svg" />
+      </div>
+      <div class="board-spliter-down" @click="topPercent = 90">
+        <img src="@/assets/icons/icon-down.svg" />
+      </div>
+    </div>
+    <div class="board-scores">
       <div
-        ref="dragSpliter"
-        style="
-          width: 100%;
-          height: 4px;
-          border: 2px solid grey;
-          background-color: grey;
-          cursor: row-resize;
-        "
-        class="split-pane tw-flex tw-justify-evenly"
+        :class="[
+          'board-score',
+          'score-icon',
+          { 'is-current': Object.is(store.currentScore, -0) },
+        ]"
+        @click="chooseScore(-0)"
       >
-        <div
-          style="
-            margin-top: -14px;
-            width: 20px;
-            height: 16px;
-            text-align: center;
-            clip-path: polygon(0 100%, 100% 100%, 50% 0);
-            background-color: lightskyblue;
-            cursor: pointer;
-          "
-          @click="topPercent = 20"
-        ></div>
-        <div
-          style="
-            margin-top: -3px;
-            width: 20px;
-            height: 16px;
-            text-align: center;
-            clip-path: polygon(0 0, 100% 0, 50% 100%);
-            background-color: lightskyblue;
-            cursor: pointer;
-          "
-          @click="topPercent = 90"
-        ></div>
+        <img src="@/assets/icons/icon-right.svg" />
       </div>
       <div
-        class="tw-flex tw-flex-wrap tw-mt-5 tw-overflow-auto tw-content-start"
-        style="padding-bottom: 40px; gap: 8px"
-        :style="{ height: `${100 - topPercent}%` }"
+        :class="[
+          'board-score',
+          'score-icon',
+          { 'is-current': Object.is(store.currentScore, -0) },
+        ]"
+        @click="chooseScore(-0)"
       >
-        <div
-          v-for="(s, i) in questionScoreSteps.slice(1)"
-          :key="i"
-          class="single-score tw-cursor-pointer tw-font-bold"
-          :class="isCurrentScore(s) && 'current-score'"
-          @click="chooseScore(s)"
-        >
-          {{ s }}
-        </div>
-        <div
-          class="single-score tw-cursor-pointer tw-font-bold"
-          :class="Object.is(store.currentScore, 0) && 'current-score'"
-          @click="chooseScore(0)"
-        >
-          0
-        </div>
-        <div
-          class="single-score tw-cursor-pointer tw-font-bold"
-          :class="Object.is(store.currentScore, -0) && 'current-score'"
-          title="按 # 可以选中"
-          @click="chooseScore(-0)"
-        >
-          空
-        </div>
+        <img src="@/assets/icons/icon-wrong.svg" />
+      </div>
+      <div
+        :class="[
+          'board-score',
+          'score-icon',
+          { 'is-current': Object.is(store.currentScore, -0) },
+        ]"
+        title="标记圆圈"
+        @click="chooseScore(-0)"
+      >
+        <img src="@/assets/icons/icon-circle.svg" />
+      </div>
+      <div
+        :class="[
+          'board-score',
+          'score-icon',
+          { 'is-current': Object.is(store.currentScore, -0) },
+        ]"
+        title="标记文本"
+        @click="chooseScore(-0)"
+      >
+        <img class="icon-text" src="@/assets/icons/icon-text.svg" />
+      </div>
+      <br />
+      <div
+        v-for="(s, i) in questionScoreSteps.slice(1)"
+        :key="i"
+        :class="['board-score', { 'is-current': isCurrentScore(s) }]"
+        @click="chooseScore(s)"
+      >
+        {{ s }}
+      </div>
+      <div
+        class="board-score"
+        :class="Object.is(store.currentScore, 0) && 'is-current'"
+        @click="chooseScore(0)"
+      >
+        0
       </div>
     </div>
-    <div
-      class="tw-flex tw-justify-between tw-mt-4"
-      style="position: relative; bottom: 0px; right: 0px; width: 230px"
-    >
+    <div class="board-footer">
       <qm-button
-        type="primary"
-        shape="round"
-        size="large"
-        style="
-          background-color: var(--app-undo-button-bg-color);
-          border-color: var(--app-undo-button-bg-color);
-        "
+        class="board-goback"
         :clickTimeout="300"
         @click="clearLatestMarkOfCurrentQuetion"
       >
+        <template #icon>
+          <img src="@/assets/icons/icon-goback.svg" />
+        </template>
         回退
       </qm-button>
 
       <qm-button
-        type="primary"
-        shape="round"
-        size="large"
+        class="board-clear"
         :clickTimeout="300"
         data-test="clear-score"
         @click="clearAllMarksOfCurrentQuetion"
       >
-        清除本题
+        <template #icon>
+          <img class="icon-common" src="@/assets/icons/icon-clear.svg" />
+          <img class="icon-active" src="@/assets/icons/icon-clear-white.svg" />
+        </template>
+        清空
       </qm-button>
     </div>
   </div>
@@ -285,8 +250,9 @@ import { dragSplitPane } from "./use/splitPane";
 import { addFocusTrack, removeFocusTrack } from "./use/focusTracks";
 import EventBus from "@/plugins/eventBus";
 import { cloneDeep } from "lodash-es";
+
 const props = defineProps<{ modal?: boolean }>();
-const emit = defineEmits(["submit", "allZeroSubmit", "unselectiveSubmit"]);
+const emit = defineEmits(["submit", "unselectiveSubmit"]);
 const { dragSpliter, topPercent } = dragSplitPane();
 const activeRightMenuItem = ref<any>(null);
 const tmpStyle = reactive<any>({
@@ -355,11 +321,7 @@ watch(topPercent, () => {
 const { chooseQuestion } = autoChooseFirstQuestion();
 let sliceImagesWithTrackListCopy = ref([]);
 EventBus.on("draw-change", (list: any) => {
-  // if (store.getMarkStatus === "正评" || store.getMarkStatus === "试评") {
   sliceImagesWithTrackListCopy.value = cloneDeep(list);
-  // } else {
-  // sliceImagesWithTrackListCopy.value = [];
-  // }
 });
 
 // 切换题目是清空上一题的分数
@@ -375,34 +337,6 @@ const questionScore = $computed(
     store.currentTask.markResult?.scoreList[store.currentQuestion.__index]
 );
 
-// const questionScoreSteps = $computed(() => {
-//   const question = store.currentQuestion;
-//   if (!question) return [];
-
-//   const remainScore =
-//     Math.round(question.maxScore * 100 - (questionScore || 0) * 100) / 100;
-
-//   const steps = [];
-//   if (question.intervalScore <= 0) {
-//     console.warn(`question.intervalScore got: ${question.intervalScore}`);
-//   }
-//   for (
-//     let i = 0;
-//     i <= remainScore && question.intervalScore > 0;
-//     i = Math.round(i * 100 + question.intervalScore * 100) / 100
-//   ) {
-//     steps.push(i);
-//   }
-//   if (
-//     Math.round(remainScore * 100) % Math.round(question.intervalScore * 100) !==
-//     0
-//   ) {
-//     steps.push(remainScore);
-//   }
-
-//   return steps;
-// });
-
 const questionScoreSteps = $computed(() => {
   const question = store.currentQuestion;
   if (!question) return [];
@@ -577,14 +511,6 @@ function clearAllMarksOfCurrentQuetion() {
 function submit() {
   emit("submit");
 }
-
-const buttonHeightForSelective = $computed(() =>
-  store.setting.selective &&
-  store.setting.enableAllZero &&
-  !store.setting.forceSpecialTag
-    ? "36px"
-    : "76px"
-);
 </script>
 
 <style lang="less" scoped>
@@ -607,82 +533,4 @@ const buttonHeightForSelective = $computed(() =>
     }
   }
 }
-.mark-board-track-container {
-  max-width: 290px;
-  min-width: 290px;
-  padding: 20px;
-  max-height: calc(100vh - 56px - 57px);
-  overflow: auto;
-  z-index: 1001;
-  transition: margin-right 0.5s;
-  color: var(--app-small-header-text-color);
-  background-color: var(--app-main-bg-color);
-}
-
-.mark-board-track-container-in-dialog {
-  max-width: 100%;
-  min-width: 100%;
-  height: 100%;
-}
-
-.mark-board-track-container.show {
-  margin-right: 0;
-}
-
-.mark-board-track-container.hide {
-  margin-right: -100%;
-}
-
-.top-container {
-  background-color: var(--app-container-bg-color);
-}
-
-.total-score {
-  color: var(--app-main-text-color);
-  font-size: 32px;
-}
-
-.question {
-  min-width: 110px;
-  max-width: 110px;
-  min-height: 72px;
-  padding: 10px;
-  background-color: var(--app-container-bg-color);
-  position: relative;
-  .tihao {
-    &:hover {
-      // font-weight: bold;
-    }
-  }
-}
-
-.current-question {
-  color: white;
-  background-color: var(--app-score-color);
-}
-
-.single-score {
-  position: relative;
-  width: 32px;
-  height: 32px;
-  font-size: var(--app-secondary-font-size);
-  display: grid;
-  place-content: center;
-  background-color: var(--app-container-bg-color);
-
-  border-radius: 30px;
-}
-
-.current-score {
-  background-color: var(--app-score-color);
-  color: white;
-}
-
-.all-zero-unselective-button {
-  height: v-bind(buttonHeightForSelective);
-  border-radius: 10px;
-  padding: 7px;
-  background-color: #4db9ff;
-  border: none;
-}
 </style>

+ 2 - 3
src/features/mark/MarkBoardTrackDialog.vue

@@ -3,9 +3,10 @@
     v-if="store.isScoreBoardCollapsed"
     title="给分板"
     top="10%"
-    width="300px"
     fixedWidth
+    width="362px"
     height="400px"
+    customClass="board-track-dialog"
     @close="close"
   >
     <mark-board-track
@@ -28,5 +29,3 @@ const close = () => {
   store.toggleScoreBoard();
 };
 </script>
-
-<style scoped></style>

+ 2 - 2
src/features/mark/MarkChangeProfile.vue

@@ -4,13 +4,13 @@
     title="修改个人信息"
     :confirmLoading="confirmLoading"
     :zIndex="6000"
-    wrapClassName="profile-wrapper"
+    wrapClassName="mark-dialog"
     @ok="handleOk"
     @cancel="handleCancel"
   >
     <a-form
       labelAlign="right"
-      :labelCol="{ span: 4 }"
+      :labelCol="{ span: 5 }"
       @keydown.stop=""
       @keypress.stop=""
     >

+ 178 - 178
src/features/mark/MarkDrawTrack.vue

@@ -1,178 +1,178 @@
-<template>
-  <transition-group name="track-score" tag="div">
-    <template v-for="track in trackList">
-      <div
-        v-if="store.shouldShowTrack && (doubleTrack || !track.isByMultMark)"
-        :key="`key-${track.mainNumber}-${track.subNumber}-${track.offsetY}-${track.offsetX}`"
-        class="score-container"
-        :class="[focusedTrack(track) && 'score-animation']"
-        :style="computeTopAndLeft(track)"
-      >
-        <span
-          :id="`a-${track.mainNumber}-${track.subNumber}-${track.offsetY}-${track.offsetX}`"
-          class="tw-m-auto"
-        >
-          {{ track.unanswered ? "空" : track.score }}
-        </span>
-      </div>
-    </template>
-  </transition-group>
-  <template v-for="(tag, index) in specialTagList" :key="index">
-    <div class="score-container" :style="computeTopAndLeft(tag)">
-      <span class="tw-m-auto">
-        {{ tag.tagName }}
-      </span>
-    </div>
-  </template>
-</template>
-
-<script setup lang="ts">
-import type { SpecialTag, Track } from "@/types";
-import { toRefs, watch, nextTick, computed } from "vue";
-import { store } from "@/store/store";
-import { message } from "ant-design-vue";
-import { useRoute } from "vue-router";
-const route = useRoute();
-
-const doubleTrack = computed(() => {
-  return !!store.setting?.doubleTrack;
-});
-const props = defineProps<{
-  trackList: Array<Track>;
-  specialTagList: Array<SpecialTag>;
-  sliceImageWidth: number;
-  sliceImageHeight: number;
-  dx: number;
-  dy: number;
-}>();
-const { trackList } = toRefs(props);
-
-const computeTopAndLeft = (track: Track | SpecialTag) => {
-  const topInsideSlice = track.offsetY - props.dy;
-  const leftInsideSlice = track.offsetX - props.dx;
-  const topInsideSliceRatio = topInsideSlice / props.sliceImageHeight;
-  const leftInsideSliceRatio = leftInsideSlice / props.sliceImageWidth;
-  if (
-    topInsideSliceRatio < 0 ||
-    topInsideSliceRatio > 1 ||
-    leftInsideSliceRatio < 0 ||
-    leftInsideSliceRatio > 1
-  ) {
-    /** 解决message提示死循环的问题 */
-    void nextTick(() => {
-      void message.error("轨迹坐标有误,可能是图片被修改过,请联系管理员!");
-    });
-  }
-
-  return {
-    color:
-      route.path === "/admin/exam/arbitrate/start"
-        ? "green"
-        : track.color || "red",
-    top: topInsideSliceRatio * 100 + "%",
-    left: leftInsideSliceRatio * 100 + "%",
-    "font-size":
-      (store.setting.uiSetting["score.fontSize.scale"] || 1) *
-        store.setting.uiSetting["answer.paper.scale"] *
-        2.2 +
-      "em",
-  };
-};
-const hasMember = (track: any) => {
-  return (
-    // (store.getMarkStatus === "正评" || store.getMarkStatus === "试评") &&
-    store.focusTracks.find((item: any) => {
-      return (
-        item.mainNumber == track.mainNumber && item.subNumber == track.subNumber
-      );
-    })
-  );
-};
-const focusedTrack = (track: Track) => {
-  return store.focusTracks.includes(track) || hasMember(track);
-};
-
-watch(
-  () => store.focusTracks,
-  () => {
-    if (store.focusTracks.length === 0) return;
-    const minImageIndex = Math.min(
-      ...store.focusTracks.map((t) => t.offsetIndex)
-    );
-    const minImageOffsetY = Math.min(
-      ...store.focusTracks
-        .filter((t) => t.offsetIndex === minImageIndex)
-        .map((t) => t.offsetY)
-    );
-    const topTrack = store.focusTracks.find(
-      (t) => t.offsetIndex === minImageIndex && t.offsetY === minImageOffsetY
-    );
-    if (topTrack) {
-      let allHeaderTracks = store.currentTask.questionList
-        .map((item: any) => item.headerTrack || [])
-        .flat();
-      console.log("allHeaderTracks", allHeaderTracks);
-      let find = allHeaderTracks.find(
-        (item: any) =>
-          item.mainNumber == topTrack.mainNumber &&
-          item.subNumber == topTrack.subNumber
-      );
-      document
-        .querySelector(
-          `#a-${topTrack.mainNumber}-${topTrack.subNumber}-${
-            find?.offsetY || topTrack.offsetY
-          }-${find?.offsetX || topTrack.offsetX}`
-        )
-        ?.scrollIntoView({ behavior: "smooth" });
-    }
-  },
-  {
-    deep: true,
-  }
-);
-</script>
-
-<style scoped>
-.score-container {
-  position: absolute;
-  display: flex;
-  place-content: center;
-  /* color: red; */
-
-  /* to center score */
-  width: 200px;
-  height: 200px;
-  margin-top: -100px;
-  margin-left: -100px;
-
-  /* to click through div */
-  pointer-events: none;
-}
-.score-animation {
-  animation: 2s ease-in-out 0s infinite alternate change_size;
-}
-
-@keyframes change_size {
-  from {
-    font-size: 2em;
-    margin-top: -100px;
-    margin-left: -100px;
-  }
-  to {
-    font-size: 4em;
-    margin-top: -80px;
-    margin-left: -80px;
-  }
-}
-.track-score-enter-active {
-  transition: opacity 0.3s ease;
-}
-.track-score-leave-active {
-  transition: opacity 0.6s ease;
-}
-
-.track-score-enter-from,
-.track-score-leave-to {
-  opacity: 0;
-}
-</style>
+<template>
+  <transition-group name="track-score" tag="div">
+    <template v-for="track in trackList">
+      <div
+        v-if="store.shouldShowTrack && (doubleTrack || !track.isByMultMark)"
+        :key="`key-${track.mainNumber}-${track.subNumber}-${track.offsetY}-${track.offsetX}`"
+        class="score-container"
+        :class="[focusedTrack(track) && 'score-animation']"
+        :style="computeTopAndLeft(track)"
+      >
+        <span
+          :id="`a-${track.mainNumber}-${track.subNumber}-${track.offsetY}-${track.offsetX}`"
+          class="tw-m-auto"
+        >
+          {{ track.unanswered ? "空" : track.score }}
+        </span>
+      </div>
+    </template>
+  </transition-group>
+  <template v-for="(tag, index) in specialTagList" :key="index">
+    <div class="score-container" :style="computeTopAndLeft(tag)">
+      <span class="tw-m-auto">
+        {{ tag.tagName }}
+      </span>
+    </div>
+  </template>
+</template>
+
+<script setup lang="ts">
+import type { SpecialTag, Track } from "@/types";
+import { toRefs, watch, nextTick, computed } from "vue";
+import { store } from "@/store/store";
+import { message } from "ant-design-vue";
+import { useRoute } from "vue-router";
+const route = useRoute();
+
+const doubleTrack = computed(() => {
+  return !!store.setting?.doubleTrack;
+});
+const props = defineProps<{
+  trackList: Array<Track>;
+  specialTagList: Array<SpecialTag>;
+  sliceImageWidth: number;
+  sliceImageHeight: number;
+  dx: number;
+  dy: number;
+}>();
+const { trackList } = toRefs(props);
+
+const computeTopAndLeft = (track: Track | SpecialTag) => {
+  const topInsideSlice = track.offsetY - props.dy;
+  const leftInsideSlice = track.offsetX - props.dx;
+  const topInsideSliceRatio = topInsideSlice / props.sliceImageHeight;
+  const leftInsideSliceRatio = leftInsideSlice / props.sliceImageWidth;
+  if (
+    topInsideSliceRatio < 0 ||
+    topInsideSliceRatio > 1 ||
+    leftInsideSliceRatio < 0 ||
+    leftInsideSliceRatio > 1
+  ) {
+    /** 解决message提示死循环的问题 */
+    void nextTick(() => {
+      void message.error("轨迹坐标有误,可能是图片被修改过,请联系管理员!");
+    });
+  }
+
+  return {
+    color:
+      route.path === "/admin/exam/arbitrate/start"
+        ? "green"
+        : track.color || "red",
+    top: topInsideSliceRatio * 100 + "%",
+    left: leftInsideSliceRatio * 100 + "%",
+    "font-size":
+      (store.setting.uiSetting["score.fontSize.scale"] || 1) *
+        store.setting.uiSetting["answer.paper.scale"] *
+        2.2 +
+      "em",
+  };
+};
+const hasMember = (track: any) => {
+  return (
+    // (store.getMarkStatus === "正评" || store.getMarkStatus === "试评") &&
+    store.focusTracks.find((item: any) => {
+      return (
+        item.mainNumber == track.mainNumber && item.subNumber == track.subNumber
+      );
+    })
+  );
+};
+const focusedTrack = (track: Track) => {
+  return store.focusTracks.includes(track) || hasMember(track);
+};
+
+watch(
+  () => store.focusTracks,
+  () => {
+    if (store.focusTracks.length === 0) return;
+    const minImageIndex = Math.min(
+      ...store.focusTracks.map((t) => t.offsetIndex)
+    );
+    const minImageOffsetY = Math.min(
+      ...store.focusTracks
+        .filter((t) => t.offsetIndex === minImageIndex)
+        .map((t) => t.offsetY)
+    );
+    const topTrack = store.focusTracks.find(
+      (t) => t.offsetIndex === minImageIndex && t.offsetY === minImageOffsetY
+    );
+    if (topTrack) {
+      let allHeaderTracks = store.currentTask.questionList
+        .map((item: any) => item.headerTrack || [])
+        .flat();
+      console.log("allHeaderTracks", allHeaderTracks);
+      let find = allHeaderTracks.find(
+        (item: any) =>
+          item.mainNumber == topTrack.mainNumber &&
+          item.subNumber == topTrack.subNumber
+      );
+      document
+        .querySelector(
+          `#a-${topTrack.mainNumber}-${topTrack.subNumber}-${
+            find?.offsetY || topTrack.offsetY
+          }-${find?.offsetX || topTrack.offsetX}`
+        )
+        ?.scrollIntoView({ behavior: "smooth" });
+    }
+  },
+  {
+    deep: true,
+  }
+);
+</script>
+
+<style scoped>
+.score-container {
+  position: absolute;
+  display: flex;
+  place-content: center;
+  /* color: red; */
+
+  /* to center score */
+  width: 200px;
+  height: 200px;
+  margin-top: -100px;
+  margin-left: -100px;
+
+  /* to click through div */
+  pointer-events: none;
+}
+.score-animation {
+  animation: 1s ease-in-out 0s infinite alternate change_size;
+}
+
+@keyframes change_size {
+  from {
+    font-size: 2em;
+    margin-top: -100px;
+    margin-left: -100px;
+  }
+  to {
+    font-size: 4em;
+    margin-top: -80px;
+    margin-left: -80px;
+  }
+}
+.track-score-enter-active {
+  transition: opacity 0.3s ease;
+}
+.track-score-leave-active {
+  transition: opacity 0.6s ease;
+}
+
+.track-score-enter-from,
+.track-score-leave-to {
+  opacity: 0;
+}
+</style>

+ 15 - 154
src/features/mark/MarkHeader.vue

@@ -67,22 +67,7 @@
           class="header-noun"
         >
           <span>成绩:</span>
-          <span>
-            {{
-              parseFloat(
-                (
-                  ((Math.max(store.currentTask.objectiveScore || 0, 0) * 100 +
-                    Math.max(
-                      store.currentTask.markResult?.markerScore || 0,
-                      0
-                    ) *
-                      100) |
-                    0) /
-                  100
-                ).toFixed(2)
-              )
-            }}
-          </span>
+          <span> {{ totalScore }} </span>
         </div>
       </div>
       <div v-show="store.status.totalCount" class="header-total">
@@ -116,14 +101,14 @@
     </div>
 
     <div class="mark-header-part">
-      <a-tooltip overlayClassName="mark-tooltip" trigger="click">
+      <a-tooltip overlayClassName="mark-tooltip">
         <template #title>
           {{
             store.setting.startTime > 0
               ? $filters.datetimeFilter(store.setting.startTime)
               : "-"
           }}
-          <br />~<br />
+          <div style="text-align: center">~</div>
           {{
             store.setting.endTime > 0
               ? $filters.datetimeFilter(store.setting.endTime)
@@ -152,133 +137,6 @@
           <CaretDownOutlined v-if="!store.setting.forceMode" class="a-icon" />
         </div>
       </a-dropdown>
-      <!-- 
-      <a-popover
-        v-if="!store.isScanImage"
-        title="小助手"
-        trigger="hover"
-        class="tw-cursor-pointer"
-      >
-        <template #content>
-          <table class="assistant-table">
-            <tr v-if="store.setting.statusValue !== 'TRIAL'">
-              <td>问题卷</td>
-              <td>
-                <a-button @click="openProblemModal">选择问题类型</a-button>
-              </td>
-            </tr>
-          </table>
-        </template>
-        <div class="header-text-btn">
-          <img
-            src="./images/assistant.png"
-            style="width: 10px; height: 12px; margin-right: 2px"
-          />
-          <span>小助手</span>
-          <div class="dropdown-triangle"></div>
-        </div>
-      </a-popover>
-      <a-popover
-        v-if="store.isScanImage"
-        trigger="hover"
-        class="tw-cursor-pointer"
-      >
-        <template #content>
-          <table class="assistant-table">
-            <tr v-if="store.setting.subject.paperUrl">
-              <td>试卷</td>
-              <td>
-                <a-switch
-                  v-model:checked="store.setting.uiSetting['paper.modal']"
-                />
-              </td>
-            </tr>
-            <tr v-if="store.setting.subject.answerUrl">
-              <td>答案</td>
-              <td>
-                <a-switch
-                  v-model:checked="store.setting.uiSetting['answer.modal']"
-                />
-              </td>
-            </tr>
-            <tr>
-              <td>全卷</td>
-              <td>
-                <a-switch v-model:checked="store.allPaperModal" />
-              </td>
-            </tr>
-            <tr v-if="store.setting.sheetView">
-              <td>原图</td>
-              <td>
-                <a-switch v-model:checked="store.sheetViewModal" />
-              </td>
-            </tr>
-            <tr>
-              <td>缩略图</td>
-              <td>
-                <a-switch
-                  v-model:checked="store.setting.uiSetting['minimap.modal']"
-                />
-              </td>
-            </tr>
-            <tr>
-              <td>特殊标记</td>
-              <td>
-                <a-switch
-                  v-model:checked="store.setting.uiSetting['specialTag.modal']"
-                />
-              </td>
-            </tr>
-            <tr v-if="store.setting.statusValue !== 'TRIAL'">
-              <td>问题卷</td>
-              <td>
-                <a-button
-                  type="text"
-                  style="
-                    color: var(--app-primary-button-bg-color);
-                    margin-right: -15px;
-                    height: 25px;
-                  "
-                  @click="openProblemModal"
-                >
-                  选择问题类型
-                </a-button>
-              </td>
-            </tr>
-            <tr v-if="store.isScanImage">
-              <td>分数/标记大小</td>
-              <td>
-                <a-slider
-                  v-model:value="
-                    store.setting.uiSetting['score.fontSize.scale']
-                  "
-                  :min="0.5"
-                  :step="0.1"
-                  :max="2"
-                  style="margin: 0"
-                />
-              </td>
-            </tr>
-            <tr v-if="store.isScanImage">
-              <td>快捷键</td>
-              <td>
-                <a-switch
-                  v-model:checked="store.setting.uiSetting['shortCut.modal']"
-                />
-              </td>
-            </tr>
-          </table>
-        </template>
-        <div class="tw-flex tw-items-center assistant-text">
-          <img
-            src="./images/assistant.png"
-            style="width: 10px; height: 12px; margin-right: 2px"
-          />
-          <span>小助手</span>
-          <div class="dropdown-triangle"></div>
-        </div>
-      </a-popover>
-      -->
       <div
         class="header-text-btn"
         :title="store.setting.groupTitle + '-' + store.setting.groupNumber"
@@ -296,7 +154,7 @@
         }}
       </div>
       <div class="header-text-btn header-logout" @click="logout">
-        <img class="header-icon" src="@/assets/icons/icon-back.svg" />返回
+        <img class="header-icon" src="@/assets/icons/icon-return.svg" />返回
       </div>
 
       <a-tooltip placement="bottomRight">
@@ -315,7 +173,6 @@
   </div>
   <MarkChangeProfile ref="changeProfileRef" />
   <MarkSwitchGroupDialog ref="switchGroupRef" />
-  <MarkProblemDialog ref="problemRef" />
 </template>
 
 <script setup lang="ts">
@@ -324,7 +181,6 @@ import { watch, watchEffect } from "vue";
 import { store } from "@/store/store";
 import MarkChangeProfile from "./MarkChangeProfile.vue";
 import MarkSwitchGroupDialog from "./MarkSwitchGroupDialog.vue";
-import MarkProblemDialog from "./MarkProblemDialog.vue";
 import { isNumber } from "lodash-es";
 import { Modal } from "ant-design-vue";
 import { CaretDownOutlined } from "@ant-design/icons-vue";
@@ -363,6 +219,17 @@ const progress = $computed(() => {
   return p;
 });
 
+const totalScore = $computed(() => {
+  return parseFloat(
+    (
+      ((Math.max(store.currentTask.objectiveScore || 0, 0) * 100 +
+        Math.max(store.currentTask.markResult?.markerScore || 0, 0) * 100) |
+        0) /
+      100
+    ).toFixed(2)
+  );
+});
+
 const logout = () => {
   doLogout();
 };
@@ -382,12 +249,6 @@ const openSwitchGroupModal = () => {
   (switchGroupRef.showModal as ShowModalFunc)();
 };
 
-let problemRef = $ref<InstanceType<typeof MarkProblemDialog>>();
-
-// const openProblemModal = () => {
-//   (problemRef.showModal as ShowModalFunc)();
-// };
-
 watchEffect(() => {
   if (
     isNumber(store.setting.topCount) &&

+ 9 - 29
src/features/mark/MarkHistory.vue

@@ -67,25 +67,12 @@
     </div>
     <div class="mark-history-table-page">
       <div>共{{ total }}项数据</div>
-      <a-pagination v-model:current="currentPage" simple :total="total" />
-
-      <!-- <a-button
-        shape="circle"
-        type="primary"
-        title="上一页"
-        @click="previousPage"
-      >
-        <div class="page-prev"></div>
-        <div class="page-body"></div>
-        <div class="page-next"></div>
-        <a-button
-          shape="circle"
-          type=" d"
-          title="下一页"
-          @click="nextPage"
-        >
-        </a-button>
-      </a-button> -->
+      <a-pagination
+        v-model:current="currentPage"
+        simple
+        :total="total"
+        @change="pageChange"
+      />
     </div>
   </div>
 </template>
@@ -211,7 +198,7 @@ EventBus.on("should-reload-history", () => {
   // });
   // // 提交后,渲染第一条
   // replaceCurrentTask(store.historyTasks[0]);
-  // TODO: 因为 mitt 不支持 async,这里是个workaround。 https://github.com/developit/mitt/issues/122
+  // TODO: 因为 mitt 不支持 å https://github.com/developit/mitt/issues/122
   (async () => {
     store.globalMask = true;
     try {
@@ -319,15 +306,8 @@ async function replaceCurrentTask(task: Task | undefined) {
   store.currentTask = task;
 }
 
-function previousPage() {
-  if (currentPage > 1) {
-    currentPage -= 1;
-  }
-}
-function nextPage() {
-  if (store.historyTasks.length >= 20) {
-    currentPage += 1;
-  }
+function pageChange(page) {
+  currentPage = page;
 }
 
 // eslint-disable-next-line @typescript-eslint/no-unused-vars

+ 14 - 31
src/features/mark/MarkProblemDialog.vue

@@ -2,28 +2,32 @@
   <a-modal
     v-model:visible="visible"
     title="选择试卷的问题类型"
-    width="300px"
+    width="406px"
     :zIndex="6000"
-    wrapClassName="profile-wrapper"
+    wrapClassName="mark-dialog"
     @cancel="handleCancel"
   >
-    <template #footer>
-      <a-button key="back" @click="handleCancel">取消</a-button>
-    </template>
-    <table class="group-table">
+    <table class="table">
       <tr>
-        <th class="tw-text-left">问题类型</th>
-        <th class="tw-text-right" style="padding-right: 20px">操作</th>
+        <th>问题类型</th>
+        <th style="width: 76px">操作</th>
       </tr>
       <tr v-for="(problem, index) in store.setting.problemTypes" :key="index">
         <td>{{ problem.name }}</td>
-        <td class="tw-text-right">
-          <a-button type="primary" @click="chooseProblemType(problem.id)">
+        <td style="width: 76px">
+          <a-button
+            type="text"
+            class="btn-primary"
+            @click="chooseProblemType(problem.id)"
+          >
             选择
           </a-button>
         </td>
       </tr>
     </table>
+    <template #footer>
+      <a-button class="btn-cancel" @click="handleCancel">取消</a-button>
+    </template>
   </a-modal>
 </template>
 
@@ -79,24 +83,3 @@ const handleCancel = () => {
 
 defineExpose({ showModal });
 </script>
-
-<style scoped>
-.profile-wrapper .ant-modal-title {
-  color: var(--app-main-text-color);
-}
-.profile-wrapper .anticon-close {
-  vertical-align: text-top;
-}
-.group-table {
-  width: 100%;
-
-  border-collapse: separate;
-  border-spacing: 0 0.5em;
-}
-.group-table th {
-  color: var(--app-small-header-text-color);
-}
-.group-table tr td {
-  color: var(--app-bold-text-color);
-}
-</style>

+ 13 - 41
src/features/mark/MarkSwitchGroupDialog.vue

@@ -3,36 +3,38 @@
     v-model:visible="visible"
     title="切换分组"
     :zIndex="6000"
-    wrapClassName="profile-wrapper"
+    centered
+    wrapClassName="mark-dialog"
   >
-    <table class="group-table">
+    <table class="table">
       <tr>
-        <th style="padding-left: 15px">分组号</th>
+        <th>分组号</th>
         <th>分组名</th>
         <th>进度</th>
-        <td class="tw-text-right" style="padding-right: 15px">操作</td>
+        <th>操作</th>
       </tr>
       <tr
         v-for="(group, index) in store.groups"
         :key="index"
-        :class="isCurrentGroup(group.number) && 'current-group'"
+        :class="isCurrentGroup(group.number) && 'is-current'"
       >
-        <td style="padding-left: 15px">{{ group.number }}</td>
+        <td>{{ group.number }}</td>
         <td>{{ group.title }}</td>
         <td>{{ progress(group.totalCount, group.markedCount) }}%</td>
-        <td class="tw-text-right">
-          <qm-button
+        <td>
+          <a-button
             :disabled="isCurrentGroup(group.number)"
-            type="primary"
+            type="text"
+            class="btn-primary"
             @click="chooseGroup(group.markerId)"
           >
             选择
-          </qm-button>
+          </a-button>
         </td>
       </tr>
     </table>
     <template #footer>
-      <a-button key="back" @click="handleCancel">取消</a-button>
+      <a-button class="btn-cancel" @click="handleCancel">取消</a-button>
     </template>
   </a-modal>
 </template>
@@ -96,33 +98,3 @@ const handleCancel = () => {
 
 defineExpose({ showModal });
 </script>
-
-<style scoped>
-.group-table {
-  width: 100%;
-  border-collapse: separate;
-  border-spacing: 0 0.5em;
-}
-
-.group-table th {
-  text-align: left;
-}
-
-.current-group {
-  background-color: #f2f7ff;
-}
-</style>
-<style>
-.profile-wrapper .ant-modal-title {
-  color: var(--app-main-text-color);
-}
-.profile-wrapper .anticon-close {
-  vertical-align: text-top;
-}
-.profile-wrapper .ant-modal-body {
-  color: var(--app-bold-text-color);
-}
-.profile-wrapper .ant-modal-body th {
-  color: var(--app-small-header-text-color);
-}
-</style>

+ 111 - 8
src/features/mark/MarkTool.vue

@@ -1,38 +1,141 @@
 <template>
   <div class="mark-tool">
     <div>
-      <div class="mark-tool-item">
+      <div class="mark-tool-item" @click="toAllPage">
         <img src="@/assets/icons/icon-all-page.svg" />
         <p>全卷</p>
       </div>
-      <div class="mark-tool-item">
+      <div
+        :class="[
+          'mark-tool-item',
+          { 'is-active': store.setting.uiSetting['minimap.modal'] },
+        ]"
+        @click="toThumbnail"
+      >
         <img src="@/assets/icons/icon-thumbnail.svg" />
         <p>缩略图</p>
       </div>
-      <div class="mark-tool-item">
+      <div class="mark-tool-item" @click="toIssuePaper">
         <img src="@/assets/icons/icon-issue-paper.svg" />
         <p>问题试卷</p>
       </div>
-      <div class="mark-tool-item">
+      <div class="mark-tool-item tool-scale">
+        <div>
+          <span>Aa</span>
+          <a-slider
+            v-model:value="store.setting.uiSetting['score.fontSize.scale']"
+            :min="0.5"
+            :step="0.1"
+            :max="2"
+          />
+        </div>
+        <p>分数/标记大小</p>
+      </div>
+      <div
+        :class="[
+          'mark-tool-item',
+          { 'is-active': store.setting.uiSetting['shortCut.modal'] },
+        ]"
+        @click="toShortcut"
+      >
         <img src="@/assets/icons/icon-shortcut.svg" />
         <p>快捷键</p>
       </div>
     </div>
     <div>
-      <div class="mark-tool-item">
+      <div class="mark-tool-item" @click="toAllZero">
+        <img src="@/assets/icons/icon-all-zero.svg" />
+        <p>全部零分</p>
+      </div>
+      <div
+        :class="['mark-tool-item', { 'is-active': greaterThanOneScale }]"
+        @click="toMagnify"
+      >
         <img src="@/assets/icons/icon-magnify.svg" />
         <p>放大</p>
       </div>
-      <div class="mark-tool-item">
+      <div
+        :class="['mark-tool-item', { 'is-active': lessThanOneScale }]"
+        @click="toMinify"
+      >
         <img src="@/assets/icons/icon-minify.svg" />
         <p>缩小</p>
       </div>
-      <div class="mark-tool-item">
+      <div class="mark-tool-item" @click="toOrigin">
         <img src="@/assets/icons/icon-origin-size.svg" />
         <p>实际大小</p>
       </div>
     </div>
   </div>
+  <MarkProblemDialog ref="problemRef" />
 </template>
 
-<script setup lang="ts"></script>
+<script setup lang="ts">
+import { computed, onMounted, onUnmounted } from "vue";
+import { store } from "@/store/store";
+import { Modal } from "ant-design-vue";
+import MarkProblemDialog from "./MarkProblemDialog.vue";
+
+type ShowModalFunc = () => void;
+
+const emit = defineEmits(["allZeroSubmit"]);
+let problemRef = $ref<InstanceType<typeof MarkProblemDialog>>();
+
+const toAllPage = () => {
+  store.allPaperModal = !store.allPaperModal;
+};
+const toThumbnail = () => {
+  store.setting.uiSetting["minimap.modal"] =
+    !store.setting.uiSetting["minimap.modal"];
+};
+const toIssuePaper = () => {
+  (problemRef.showModal as ShowModalFunc)();
+};
+
+const toShortcut = () => {
+  store.setting.uiSetting["shortCut.modal"] =
+    !store.setting.uiSetting["shortCut.modal"];
+};
+
+const toAllZero = () => {
+  Modal.confirm({
+    title: "操作警告",
+    content: "确定给全零分?",
+    onOk() {
+      emit("allZeroSubmit");
+    },
+  });
+};
+const toMagnify = () => {
+  const s = store.setting.uiSetting["answer.paper.scale"];
+  if (s < 3)
+    store.setting.uiSetting["answer.paper.scale"] = +(s + 0.2).toFixed(1);
+};
+const toMinify = () => {
+  const s = store.setting.uiSetting["answer.paper.scale"];
+  if (s > 0.2)
+    store.setting.uiSetting["answer.paper.scale"] = +(s - 0.2).toFixed(1);
+};
+const toOrigin = () => {
+  store.setting.uiSetting["answer.paper.scale"] = 1;
+};
+const greaterThanOneScale = computed(() => {
+  return store.setting.uiSetting["answer.paper.scale"] > 1;
+});
+const lessThanOneScale = computed(() => {
+  return store.setting.uiSetting["answer.paper.scale"] < 1;
+});
+function keyListener(event: KeyboardEvent) {
+  if (event.key === "+") {
+    toMagnify();
+  } else if (event.key === "-") {
+    toMinify();
+  }
+}
+onMounted(() => {
+  document.addEventListener("keydown", keyListener);
+});
+onUnmounted(() => {
+  document.removeEventListener("keydown", keyListener);
+});
+</script>

+ 24 - 24
src/features/mark/MinimapModal.vue

@@ -2,16 +2,18 @@
   <qm-dialog
     v-if="store.setting.uiSetting['minimap.modal']"
     top="10%"
-    width="200px"
-    height="500px"
+    width="312px"
+    height="700px"
     title="缩略图"
     @close="close"
   >
     <div
+      v-if="imagesHtml && imagesHtml.length"
       class="mini-map-container"
       @click.stop="setScrollTo"
       v-html="imagesHtml"
     ></div>
+    <div v-else>请关闭或重新打开</div>
   </qm-dialog>
 </template>
 
@@ -27,12 +29,20 @@ watch(
   }
 );
 
-let imagesHtml = $ref("");
+let imagesHtml = $ref([]);
 
 onBeforeUpdate(() => {
-  imagesHtml =
-    document.querySelector(".mark-body-container div:first-of-type")
-      ?.innerHTML ?? "请关闭或重新打开";
+  const imgDom = document.querySelectorAll(
+    ".mark-body-container .single-image-container > img"
+  );
+  if (!imgDom.length) {
+    imagesHtml = "";
+    return;
+  }
+  imagesHtml = "";
+  imgDom.forEach((item) => {
+    imagesHtml += item.outerHTML;
+  });
 });
 
 const setScrollTo = (e: MouseEvent) => {
@@ -60,24 +70,14 @@ const close = () => {
 </script>
 
 <style>
-.mini-map-container {
-  background-image: linear-gradient(45deg, #e0e0e0 25%, transparent 25%),
-    linear-gradient(-45deg, #e0e0e0 25%, transparent 25%),
-    linear-gradient(45deg, transparent 75%, #e0e0e0 75%),
-    linear-gradient(-45deg, transparent 75%, #e0e0e0 75%);
-  background-size: 20px 20px;
-  background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
-}
-
-.mini-map-container div div:not(.single-image-container) {
-  display: none;
+.mini-map-container img {
+  display: block;
+  padding: 5px;
+  border: 1px solid #f0f0f0;
+  cursor: pointer;
+  margin-bottom: 10px;
 }
-
-.mini-map-container .ant-spin-container > div {
-  width: 100% !important;
-}
-
-.mini-map-container .score-container {
-  display: none;
+.mini-map-container img:hover {
+  border-color: #165dff;
 }
 </style>

+ 98 - 104
src/features/mark/ShortCutModal.vue

@@ -2,97 +2,109 @@
   <qm-dialog
     v-if="store.setting.uiSetting['shortCut.modal']"
     top="10%"
-    width="500px"
-    height="350px"
+    width="442px"
+    height="508px"
     title="快捷键"
     :enableResize="false"
     @close="close"
   >
-    <div class="short-cut-container">
-      <div class="row">
-        <div class="tw-text-base tw-border-b-2 tw-mb-2">通用</div>
-      </div>
-      <div class="row">
-        <div>放大</div>
-        <div>+</div>
-      </div>
-      <div class="row">
-        <div>缩小</div>
-        <div>-</div>
-      </div>
-      <div class="row">
-        <div>向上滑动</div>
-        <div>w</div>
-      </div>
-      <div class="row">
-        <div>向下滑动</div>
-        <div>s</div>
-      </div>
-      <div class="row">
-        <div>向左滑动</div>
-        <div>a</div>
-      </div>
-      <div class="row">
-        <div>向右滑动</div>
-        <div>d</div>
-      </div>
-      <div class="row">
-        <div>图片旋转</div>
-        <div>鼠标右键</div>
-      </div>
-      <div class="row">
-        <div>全屏窗口</div>
-        <div>F11</div>
-      </div>
-      <div class="row">
-        <div>取消全屏</div>
-        <div>F11</div>
-      </div>
-      <div class="row">
-        <div>刷新页面</div>
-        <div>F5</div>
-      </div>
+    <a-row class="short-cut-container">
+      <a-col :span="11">
+        <div class="cut-item">
+          <h4>通用</h4>
+        </div>
+        <div class="cut-item">
+          <div>放大</div>
+          <div><span class="cut-key">+</span></div>
+        </div>
+        <div class="cut-item">
+          <div>缩小</div>
+          <div><span class="cut-key">-</span></div>
+        </div>
+        <div class="cut-item">
+          <div>向上滑动</div>
+          <div><span class="cut-key">w</span></div>
+        </div>
+        <div class="cut-item">
+          <div>向下滑动</div>
+          <div><span class="cut-key">s</span></div>
+        </div>
+        <div class="cut-item">
+          <div>向左滑动</div>
+          <div><span class="cut-key">a</span></div>
+        </div>
+        <div class="cut-item">
+          <div>向右滑动</div>
+          <div><span class="cut-key">d</span></div>
+        </div>
+        <div class="cut-item">
+          <div>图片旋转</div>
+          <div><span class="cut-key">鼠标右键</span></div>
+        </div>
+        <div class="cut-item">
+          <div>全屏窗口</div>
+          <div><span class="cut-key">F11</span></div>
+        </div>
+        <div class="cut-item">
+          <div>取消全屏</div>
+          <div><span class="cut-key">F11</span></div>
+        </div>
+        <div class="cut-item">
+          <div>刷新页面</div>
+          <div><span class="cut-key">F5</span></div>
+        </div>
+      </a-col>
+      <a-col :span="13">
+        <div class="cut-item">
+          <h4>轨迹模式</h4>
+        </div>
+        <div class="cut-item">
+          <div>交卷</div>
+          <div>
+            <span class="cut-key">Ctrl</span>
+            <span>+</span>
+            <span class="cut-key">Enter</span>
+          </div>
+        </div>
+        <div class="cut-item">
+          <div>切题</div>
+          <div><span class="cut-key">Tab</span></div>
+        </div>
+        <div class="cut-item">
+          <div>键盘选分</div>
+          <div><span class="cut-key">数字 或 . 或 #</span></div>
+        </div>
+        <div class="cut-item">
+          <div>取消选分</div>
+          <div><span class="cut-key">Esc</span></div>
+        </div>
+        <div class="cut-item"></div>
 
-      <div class="row">
-        <div class="tw-text-base tw-border-b-2 tw-mb-2">轨迹模式</div>
-      </div>
-      <div class="row">
-        <div>交卷</div>
-        <div>Ctrl + Enter</div>
-      </div>
-      <div class="row">
-        <div>切题</div>
-        <div>Tab</div>
-      </div>
-      <div class="row">
-        <div>键盘选分</div>
-        <div>数字 或 . 或 #</div>
-      </div>
-      <div class="row">
-        <div>取消选分</div>
-        <div>Esc</div>
-      </div>
-
-      <div class="row">
-        <div class="tw-text-base tw-border-b-2 tw-mt-5">键盘模式</div>
-      </div>
-      <div class="row">
-        <div>切题</div>
-        <div>← 或 →</div>
-      </div>
-      <div class="row">
-        <div>确认输入</div>
-        <div>Enter</div>
-      </div>
-      <div class="row">
-        <div>撤销上次</div>
-        <div>Backspace(删除)</div>
-      </div>
-      <div class="row">
-        <div>取消输入</div>
-        <div>Esc</div>
-      </div>
-    </div>
+        <div class="cut-item">
+          <h4>键盘模式</h4>
+        </div>
+        <div class="cut-item">
+          <div>切题</div>
+          <div>
+            <span class="cut-key">←</span>
+            <span>或</span>
+            <span class="cut-key">→</span>
+          </div>
+        </div>
+        <div class="cut-item">
+          <div>确认输入</div>
+          <div><span class="cut-key">Enter</span></div>
+        </div>
+        <div class="cut-item">
+          <div>撤销上次</div>
+          <div><span class="cut-key">Backspace(删除)</span></div>
+        </div>
+        <div class="cut-item">
+          <div>取消输入</div>
+          <div><span class="cut-key">Esc</span></div>
+        </div>
+      </a-col>
+    </a-row>
   </qm-dialog>
 </template>
 
@@ -103,21 +115,3 @@ const close = () => {
   store.setting.uiSetting["shortCut.modal"] = false;
 };
 </script>
-
-<style>
-.short-cut-container {
-  margin: 20px;
-  columns: 2;
-  column-fill: auto;
-  height: calc(100% - 40px);
-}
-
-.short-cut-container .row {
-  display: flex;
-  gap: 2em;
-}
-.short-cut-container .row div:first-child {
-  color: var(--app-bold-text-color);
-  min-width: 60px;
-}
-</style>

+ 726 - 24
src/styles/page.less

@@ -1,10 +1,20 @@
+.flex-static {
+  flex-grow: 0;
+  flex-shrink: 0;
+}
+.flex-between {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
 // mark
 .mark {
   width: 100%;
   overflow: clip;
 
   .mark-main {
-    height: calc(100vh - 56px - 57px);
+    height: calc(100vh - 56px - 58px);
     display: flex;
     justify-content: stretch;
   }
@@ -16,10 +26,7 @@
   line-height: 20px;
   background-color: var(--header-bg-color);
   color: rgba(255, 255, 255, 0.5);
-
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
+  .flex-between;
 
   &-part {
     &:first-child {
@@ -128,7 +135,7 @@
 
     .header-icon {
       display: inline;
-      margin-right: 5px;
+      margin-right: 8px;
       margin-top: -2px;
       opacity: 0.8;
     }
@@ -147,23 +154,32 @@
 
 // mark-tool
 .mark-tool {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  padding: 10px;
+  .flex-between;
+  padding: 10px 10px 7px;
   background: #ffffff;
   border-bottom: 1px solid #e5e5e5;
 
   &-item {
     display: inline-block;
     vertical-align: middle;
-    width: 50px;
+    min-width: 50px;
     color: #8c8c8c;
     cursor: pointer;
+    position: relative;
 
     &:hover {
       color: #000;
     }
+    &.is-active::after {
+      content: "";
+      display: block;
+      position: absolute;
+      height: 3px;
+      width: 90%;
+      bottom: -7px;
+      left: 5%;
+      background-color: #f53f3f;
+    }
 
     > img {
       display: block;
@@ -174,25 +190,58 @@
     > p {
       font-size: 12px;
       font-weight: 400;
-      line-height: 16px;
       margin: 0;
       text-align: center;
+      height: 20px;
+      line-height: 20px;
+    }
+
+    &.tool-scale {
+      width: 132px;
+      margin: 0 20px;
+      > div {
+        color: #262626;
+        font-weight: 600;
+        line-height: 20px;
+        font-size: 0;
+
+        > span {
+          display: inline-block;
+          vertical-align: middle;
+          font-size: 14px;
+        }
+      }
+      .ant-slider {
+        display: inline-block;
+        vertical-align: middle;
+        width: 98px;
+        margin: 0 0 0 3px;
+      }
+      .ant-slider-rail {
+        background-color: #e5e5e5;
+      }
+      .ant-slider-track {
+        background-color: #165dff;
+      }
+      .ant-slider-handle {
+        border-color: #165dff;
+      }
     }
   }
 }
 // mark-history
 .mark-history {
-  min-width: 328px;
-  width: 328px;
+  width: 360px;
   padding: 16px;
-  font-size: var(--app-secondary-font-size);
   overflow-y: auto;
   transition: margin-left 0.5s;
   background-color: #fff;
+  border-right: 1px solid #e5e5e5;
 
   display: flex;
   flex-direction: column;
   justify-content: space-between;
+  .flex-static;
 
   .search-value .ant-input::-webkit-input-placeholder {
     font-size: 12px;
@@ -204,7 +253,7 @@
     margin-left: 0;
   }
   &.hide {
-    margin-left: -328px;
+    margin-left: -100%;
   }
 
   &-title {
@@ -213,33 +262,37 @@
     color: #262626;
     line-height: 24px;
     margin-bottom: 16px;
+    .flex-static;
   }
   &-search {
     display: flex;
     justify-content: space-between;
     align-items: center;
     margin-bottom: 16px;
+    .flex-static;
   }
   &-table-head {
     display: flex;
     justify-content: space-between;
     align-items: center;
     height: 44px;
-    font-size: 12px;
+    font-size: 14px;
     font-weight: 400;
     color: #8c8c8c;
+    .flex-static;
     .head-item {
       &:nth-of-type(1) {
-        width: 86px;
+        .flex-static;
+        width: 94px;
         padding-left: 16px;
       }
       &:nth-of-type(2) {
-        width: 86px;
         padding-left: 16px;
         flex-grow: 2;
       }
       &:nth-of-type(3) {
-        width: 52px;
+        .flex-static;
+        width: 60px;
         padding-right: 6px;
         padding-left: 6px;
       }
@@ -250,6 +303,7 @@
     overflow-x: hidden;
     overflow-y: auto;
     color: #262626;
+    font-weight: 400;
 
     .body-row {
       padding: 12px 0;
@@ -273,21 +327,22 @@
       }
     }
     .body-col {
-      font-size: 12px;
+      font-size: 14px;
       font-weight: 400;
       line-height: 20px;
 
       &:nth-of-type(1) {
-        width: 86px;
+        .flex-static;
+        width: 94px;
         padding-left: 16px;
       }
       &:nth-of-type(2) {
-        width: 86px;
         padding-left: 16px;
         flex-grow: 2;
       }
       &:nth-of-type(3) {
-        width: 52px;
+        .flex-static;
+        width: 60px;
         padding-left: 6px;
         padding-right: 6px;
       }
@@ -298,6 +353,7 @@
     justify-content: space-between;
     align-items: center;
     height: 32px;
+    .flex-static;
 
     .ant-pagination-simple {
       .ant-pagination-prev,
@@ -331,6 +387,433 @@
     }
   }
 }
+// mark-board-track
+.mark-board-track {
+  width: 360px;
+  padding: 16px;
+  overflow-y: auto;
+  transition: margin-left 0.5s;
+  background-color: #fff;
+
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+  border-left: 1px solid #e5e5e5;
+  .flex-static;
+
+  &.in-dialog {
+    max-width: 100%;
+    min-width: 100%;
+    height: 100%;
+    border: none;
+  }
+  &.show {
+    margin-right: 0;
+  }
+  &.hide {
+    margin-right: -100%;
+  }
+
+  .board-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    .flex-static;
+    border-radius: 4px;
+    border: 1px solid #e5e5e5;
+    padding: 10px 16px;
+
+    &-info {
+      color: #8c8c8c;
+
+      > img {
+        display: inline-block;
+        vertical-align: middle;
+        width: 16px;
+        height: 16px;
+      }
+      > span {
+        display: inline-block;
+        vertical-align: middle;
+        margin-left: 5px;
+      }
+    }
+    &-score {
+      background: #f7f7f7;
+      border-radius: 3px;
+      border: 1px solid #f0f0f0;
+      padding: 6px;
+
+      > span {
+        display: block;
+        width: 50px;
+        height: 36px;
+        font-size: 30px;
+        font-weight: 600;
+        color: #f53f3f;
+        line-height: 36px;
+        text-align: center;
+      }
+    }
+  }
+  .board-submit {
+    .flex-static;
+    margin: 16px 0;
+    border-radius: 4px;
+  }
+
+  .board-questions {
+    flex-grow: 2;
+    margin: 0 -8px;
+    font-size: 0;
+    overflow-x: hidden;
+    overflow-y: auto;
+  }
+  .board-quesion-box {
+    display: inline-block;
+    vertical-align: top;
+    width: 50%;
+    padding: 0 8px;
+    font-size: 14px;
+  }
+  .board-quesion {
+    .flex-between;
+    border-radius: 4px;
+    border: 1px solid #e5e5e5;
+    padding: 16px;
+    height: 74px;
+    overflow: hidden;
+    color: #262626;
+    position: relative;
+
+    .quesion-title {
+      flex-grow: 2;
+      max-height: 42px;
+      overflow: hidden;
+      line-height: 21px;
+    }
+    .quesion-score {
+      .flex-static;
+      margin-left: 10px;
+      height: 36px;
+      width: 42px;
+      text-align: center;
+      background: #f7f7f7;
+      border-radius: 3px;
+      border: 1px solid #f0f0f0;
+      line-height: 36px;
+      color: #165dff;
+      font-size: 20px;
+      font-weight: 600;
+    }
+
+    &.is-current,
+    &:hover {
+      border-color: #165dff;
+      color: #165dff;
+    }
+  }
+
+  .board-spliter {
+    .flex-static;
+    .flex-between;
+    margin: 16px 0;
+    height: 18px;
+    img {
+      display: block;
+      height: 14px;
+      width: 14px;
+      margin: 2px auto;
+    }
+    .board-spliter-item {
+      background: #f7f7f7;
+      cursor: pointer;
+      &:hover {
+        background-color: #e8f3ff;
+      }
+    }
+
+    &-up {
+      flex-grow: 2;
+      border-radius: 4px 0px 0px 4px;
+      .board-spliter-item;
+    }
+    &-bar {
+      .flex-static;
+      width: 66px;
+      margin: 0 2px;
+      .board-spliter-item;
+      cursor: row-resize;
+    }
+    &-down {
+      flex-grow: 2;
+      border-radius: 0px 4px 4px 0px;
+      .board-spliter-item;
+    }
+  }
+  .board-scores {
+    .flex-static;
+    font-size: 0;
+    margin: 0 -5px;
+  }
+  .board-score {
+    display: inline-block;
+    vertical-align: top;
+    font-size: 14px;
+    width: 34px;
+    height: 34px;
+    line-height: 30px;
+    border-radius: 4px;
+    border: 1px solid #e5e5e5;
+    text-align: center;
+    margin: 0 4px 16px;
+    cursor: pointer;
+
+    &:hover {
+      border-color: #165dff;
+      background-color: #165dff;
+      color: #fff;
+    }
+
+    &.score-icon:hover {
+      background-color: #fff;
+    }
+
+    > img {
+      display: inline-block;
+      vertical-align: middle;
+      width: 16px;
+      height: 16px;
+      &.icon-text {
+        height: 20px;
+      }
+    }
+  }
+
+  .board-footer {
+    height: 36px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    .flex-static;
+
+    .ant-btn {
+      width: 156px;
+      border-radius: 4px;
+
+      img {
+        display: inline-block;
+        vertical-align: middle;
+        width: 16px;
+        height: 16px;
+        margin: -5px 5px 0 0;
+      }
+    }
+    .board-goback {
+      background-color: #fff;
+      border: 1px solid #e5e5e5;
+      color: #262626;
+
+      &:hover {
+        background: #f0f0f0;
+      }
+    }
+    .board-clear {
+      background-color: #fff2f0;
+      color: #f53f3f;
+      border: none;
+      .icon-common {
+        display: inline-block;
+      }
+      .icon-active {
+        display: none;
+      }
+      img {
+        margin: -3px 5px 0 0;
+      }
+      &:hover {
+        background-color: #f53f3f;
+        color: #fff;
+
+        .icon-common {
+          display: none;
+        }
+        .icon-active {
+          display: inline-block;
+        }
+      }
+    }
+  }
+}
+// mark-body
+.mark-body {
+  position: relative;
+  flex-grow: 2;
+
+  &-status {
+    position: absolute;
+    width: 56px;
+    height: 30px;
+    background: #ffece8;
+    border-radius: 4px;
+    font-size: 12px;
+    font-weight: 600;
+    color: #f53f3f;
+    line-height: 30px;
+    text-align: center;
+
+    top: 4px;
+    right: 4px;
+    pointer-events: none;
+    z-index: 1000;
+  }
+
+  &-none {
+    height: 100%;
+    display: flex;
+    align-items: center;
+    background-color: #fff;
+    justify-content: center;
+
+    img {
+      display: block;
+      width: 200px;
+      height: 140px;
+    }
+    p {
+      height: 24px;
+      font-size: 16px;
+      font-weight: 600;
+      color: #7584ac;
+      line-height: 24px;
+      margin-top: 16px;
+      text-align: center;
+    }
+  }
+
+  &-container {
+    position: relative;
+    height: 100%;
+    overflow: auto;
+    background-color: var(--app-container-bg-color);
+    background-image: linear-gradient(45deg, #e0e0e0 25%, transparent 25%),
+      linear-gradient(-45deg, #e0e0e0 25%, transparent 25%),
+      linear-gradient(45deg, transparent 75%, #e0e0e0 75%),
+      linear-gradient(-45deg, transparent 75%, #e0e0e0 75%);
+    background-size: 10px 10px;
+    background-position: 0 0, 0 5px, 5px -5px, -5px 0px;
+    transform: inherit;
+    padding: 16px;
+    img {
+      width: 100%;
+    }
+  }
+  .single-image-container {
+    position: relative;
+  }
+  .image-seperator {
+    border: 2px solid transparent;
+  }
+}
+
+// short-cut-container
+.short-cut-container {
+  .cut-item {
+    display: flex;
+    font-size: 14px;
+    font-weight: 400;
+    color: #262626;
+    line-height: 22px;
+    min-height: 22px;
+
+    &:not(:first-child) {
+      margin-top: 16px;
+    }
+
+    > div:nth-of-type(1) {
+      width: 80px;
+    }
+    > div:nth-of-type(2) {
+      font-size: 0;
+      span {
+        font-size: 12px;
+      }
+    }
+    h4 {
+      color: #8c8c8c;
+      margin: 0;
+    }
+    span {
+      display: inline-block;
+      vertical-align: middle;
+
+      &:not(:first-child) {
+        margin-left: 4px;
+      }
+    }
+    .cut-key {
+      min-width: 22px;
+      padding: 0 7px;
+      height: 22px;
+      background: #ffffff;
+      border-radius: 2px;
+      border: 1px solid #e5e5e5;
+      line-height: 20px;
+      text-align: center;
+      font-size: 12px;
+    }
+  }
+}
+// all-paper-modal
+.all-paper-modal {
+  .common-dialog-title {
+    display: inline-block;
+    vertical-align: middle;
+  }
+  .paper-menu {
+    margin-left: 16px;
+    display: inline-block;
+    vertical-align: middle;
+
+    span {
+      display: inline-block;
+      vertical-align: middle;
+      width: 32px;
+      height: 32px;
+      border-radius: 4px;
+      border: 1px solid #e5e5e5;
+      font-size: 14px;
+      font-weight: 400;
+      padding: 4px;
+      color: #262626;
+      line-height: 22px;
+      text-align: center;
+      cursor: pointer;
+
+      &:not(:first-child) {
+        margin-left: 8px;
+      }
+
+      &:hover {
+        color: #134fdb;
+        border-color: #134fdb;
+      }
+      &.is-active {
+        color: #fff;
+        background-color: #134fdb;
+        border-color: #134fdb;
+      }
+    }
+  }
+}
+// board-track-dialog
+.board-track-dialog {
+  &.qm-dialog {
+    .qm-dialog-body {
+      padding: 0;
+    }
+  }
+}
 
 // common
 .mark-tooltip {
@@ -346,3 +829,222 @@
     border-radius: 4px;
   }
 }
+
+// mark-dialog
+.mark-dialog {
+  .ant-modal-content {
+    background: #ffffff;
+    box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.12);
+    border-radius: 4px;
+    border: 1px solid #d9d9d9;
+    position: relative;
+  }
+  .ant-modal-close {
+    top: 24px;
+    right: 32px;
+    width: 24px;
+    height: 24px;
+    background-image: url(../assets/icons/icon-close.svg);
+    background-size: 100% 100%;
+
+    &:hover {
+      background-color: #f0f0f0;
+    }
+
+    .ant-modal-close-x {
+      display: none;
+    }
+  }
+  .ant-modal-header {
+    padding: 24px 32px 0;
+    border: none;
+
+    .ant-modal-title {
+      font-size: 16px;
+      font-weight: bold;
+      color: #262626;
+      line-height: 24px;
+    }
+  }
+  .ant-modal-body {
+    padding: 24px 32px;
+  }
+  .ant-modal-footer {
+    padding: 0 32px 24px;
+    border: none;
+  }
+}
+// qm-dialog
+.qm-dialog {
+  z-index: 1020;
+  position: absolute;
+  min-width: 100px;
+  background: #ffffff;
+  box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.12);
+  border-radius: 4px;
+  border: 1px solid #d9d9d9;
+  display: flex;
+  flex-direction: column;
+
+  .resize-handler {
+    position: absolute;
+    bottom: -10px;
+    right: -10px;
+    width: 20px;
+    height: 20px;
+    cursor: nwse-resize;
+  }
+
+  .qm-dialog-header {
+    .flex-static;
+    .flex-between;
+    padding: 24px 32px 0;
+    cursor: move;
+
+    .qm-dialog-title {
+      font-size: 16px;
+      font-weight: bold;
+      color: #262626;
+      line-height: 24px;
+      flex-grow: 2;
+    }
+
+    .qm-dialog-close {
+      .flex-static;
+      margin-left: 10px;
+      width: 24px;
+      height: 24px;
+      background-image: url(../assets/icons/icon-close.svg);
+      background-size: 100% 100%;
+      padding: 0;
+      border: none;
+      visibility: visible;
+
+      &:hover {
+        background-color: #f0f0f0;
+      }
+    }
+  }
+  .qm-dialog-body {
+    padding: 24px 32px;
+    flex-grow: 2;
+    overflow: auto;
+  }
+  .qm-dialog-footer {
+    .flex-static;
+    padding: 0 32px 24px;
+    border: none;
+  }
+}
+// common-dialog
+.common-dialog {
+  z-index: 1020;
+  position: absolute;
+  top: 10px;
+  min-height: 400px;
+  background: #ffffff;
+  box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.12);
+  border-radius: 4px;
+  border: 1px solid #d9d9d9;
+  display: flex;
+  flex-direction: column;
+
+  &.is-fullscreen {
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    border-radius: 0;
+    overflow: hidden;
+  }
+
+  &-header {
+    .flex-static;
+    .flex-between;
+    padding: 16px;
+    border-bottom: 1px solid #e5e5e5;
+  }
+  &-title {
+    font-size: 16px;
+    font-weight: bold;
+    color: #262626;
+    line-height: 24px;
+    flex-grow: 2;
+  }
+  &-close {
+    .flex-static;
+    margin-left: 10px;
+    width: 24px;
+    height: 24px;
+    background-image: url(../assets/icons/icon-close.svg);
+    background-size: 100% 100%;
+    padding: 0;
+    border: none;
+    visibility: visible;
+
+    &:hover {
+      background-color: #f0f0f0;
+    }
+  }
+  &-body {
+    padding: 16px;
+    flex-grow: 2;
+    overflow: auto;
+  }
+  &-footer {
+    .flex-static;
+    padding: 16px;
+    border-top: 1px solid #e5e5e5;
+  }
+}
+// table
+.table {
+  width: 100%;
+  border-spacing: 0;
+  border-collapse: collapse;
+  text-align: left;
+  color: #262626;
+
+  td,
+  th {
+    border-bottom: 1px solid #e5e5e5;
+    padding: 12px;
+    line-height: 22px;
+  }
+  th {
+    color: #8c8c8c;
+    font-weight: 400;
+  }
+
+  tr.is-current {
+    background-color: #e8f3ff;
+  }
+}
+.btn-primary {
+  &.ant-btn-text {
+    padding: 0;
+    border: none;
+    height: auto;
+  }
+  &.ant-btn-text:not([disabled]) {
+    color: #165dff !important;
+    &:hover {
+      color: #134fdb !important;
+    }
+  }
+}
+.btn-cancel {
+  &.ant-btn {
+    background: #f0f0f0;
+    border-radius: 3px;
+    font-size: 14px;
+    font-weight: 400;
+    color: #262626 !important;
+    line-height: 22px;
+    border: none;
+
+    &:hover {
+      background-color: #e5e5e5;
+    }
+  }
+}