MarkBoardTrack.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730
  1. <template>
  2. <div
  3. v-if="store.currentTask"
  4. class="mark-board-track-container tw-flex tw-flex-col"
  5. :class="[
  6. {
  7. hide: store.isScoreBoardCollapsed && !props.modal,
  8. 'mark-board-track-container-in-dialog':
  9. store.isScoreBoardCollapsed && !props.modal,
  10. show: !store.isScoreBoardCollapsed,
  11. },
  12. ]"
  13. :style="{
  14. height: props.modal ? '100%' : 'auto',
  15. }"
  16. >
  17. <div
  18. class="tw-flex tw-rounded tw-justify-between tw-p-2 tw-pl-5 top-container tw-mb-4"
  19. >
  20. <div class="tw-flex tw-flex-col">
  21. <div class="tw-flex tw-items-center tw-gap-2">
  22. <img
  23. src="./images/totalscore.png"
  24. style="width: 13px; height: 16px"
  25. />
  26. 总分
  27. </div>
  28. <div class="total-score tw-ml-5 tw-font-bold" style="height: 50px">
  29. <transition-group name="score-number-animation" tag="span">
  30. <span
  31. :key="store.currentTask.markResult?.markerScore || 0"
  32. class="tw-inline-block"
  33. >{{ store.currentTask.markResult?.markerScore }}</span
  34. >
  35. </transition-group>
  36. </div>
  37. </div>
  38. <div class="tw-flex tw-place-content-center tw-items-center tw-gap-2">
  39. <div class="tw-flex tw-flex-col tw-gap-1">
  40. <a-popconfirm
  41. v-if="store.setting.enableAllZero && !store.setting.forceSpecialTag"
  42. title="确定给全零分?"
  43. :overlayStyle="{ width: '200px' }"
  44. @confirm="$emit('allZeroSubmit')"
  45. >
  46. <a-button
  47. type="primary"
  48. size="middle"
  49. class="all-zero-unselective-button"
  50. >
  51. <span>全零分</span>
  52. </a-button>
  53. </a-popconfirm>
  54. <a-popconfirm
  55. v-if="store.setting.selective"
  56. title="确定是未选做?"
  57. :overlayStyle="{ width: '200px' }"
  58. @confirm="$emit('unselectiveSubmit')"
  59. >
  60. <a-button
  61. type="primary"
  62. size="middle"
  63. class="all-zero-unselective-button"
  64. >
  65. <span>未选做</span>
  66. </a-button>
  67. </a-popconfirm>
  68. </div>
  69. <qm-button
  70. type="primary"
  71. shape="round"
  72. size="middle"
  73. style="height: 76px; border-radius: 10px; padding: 12px"
  74. @click="submit"
  75. >
  76. 提交
  77. </qm-button>
  78. </div>
  79. </div>
  80. <div
  81. style="
  82. height: calc(100% - 56px);
  83. overflow: hidden;
  84. user-select: none;
  85. position: relative;
  86. "
  87. >
  88. <div
  89. v-if="store.currentTask && store.currentTask.questionList"
  90. class="tw-flex tw-gap-2 tw-flex-wrap tw-justify-between tw-overflow-auto tw-content-start"
  91. :style="{ height: `${topPercent}%` }"
  92. >
  93. <template
  94. v-for="(question, index) in store.currentTask.questionList"
  95. :key="index"
  96. >
  97. <!-- <div
  98. :id="
  99. store.isScoreBoardCollapsed
  100. ? props.modal
  101. ? ['bq', question.mainNumber, question.subNumber].join('-')
  102. : ''
  103. : ['bq', question.mainNumber, question.subNumber].join('-')
  104. "
  105. class="question tw-rounded tw-cursor-pointer tw-relative tw-mb-2"
  106. :class="isCurrentQuestion(question) && 'current-question'"
  107. @click="chooseQuestion(question)"
  108. @mouseover="
  109. addFocusTrack(
  110. undefined,
  111. question.mainNumber,
  112. question.subNumber,
  113. true
  114. )
  115. "
  116. @mouseleave="removeFocusTrack"
  117. > -->
  118. <div
  119. :id="
  120. store.isScoreBoardCollapsed
  121. ? props.modal
  122. ? ['bq', question.mainNumber, question.subNumber].join('-')
  123. : ''
  124. : ['bq', question.mainNumber, question.subNumber].join('-')
  125. "
  126. class="question tw-rounded tw-cursor-pointer tw-relative tw-mb-2"
  127. :class="{
  128. 'current-question': isCurrentQuestion(question),
  129. disabled: notInActive(index),
  130. }"
  131. tabindex="0"
  132. outline="0"
  133. hidefocus="true"
  134. @click="willChooseQuestion(question, index)"
  135. @contextmenu="onRightClick($event, index)"
  136. @blur="rightBlur"
  137. >
  138. <div
  139. v-if="
  140. activeRightMenuItem?.id ==
  141. (store.isScoreBoardCollapsed
  142. ? props.modal
  143. ? ['bq', question.mainNumber, question.subNumber].join('-')
  144. : ''
  145. : ['bq', question.mainNumber, question.subNumber].join('-'))
  146. "
  147. class="tw-fixed right-menu-box"
  148. :style="tmpStyle"
  149. >
  150. <div class="right-menu-item" @click="positioning(question)">
  151. 定位
  152. </div>
  153. </div>
  154. <div v-if="!!question.questionName" class="tihao">
  155. {{ question.questionName }}
  156. </div>
  157. <div v-else class="tihao">
  158. {{ question.title }} {{ question.mainNumber }}-{{
  159. question.subNumber
  160. }}
  161. </div>
  162. <!-- 设置高度 避免动画跳动 -->
  163. <div style="height: 32px">
  164. <transition-group name="score-number-animation" tag="span">
  165. <span
  166. :key="store.currentTask?.markResult?.scoreList[index] || 0"
  167. class="tw-font-medium tw-text-2xl score tw-inline-block"
  168. >
  169. <!-- 特殊的空格符号 -->
  170. <!-- eslint-disable-next-line no-irregular-whitespace -->
  171. {{ store.currentTask?.markResult?.scoreList[index] ?? " " }}
  172. </span>
  173. </transition-group>
  174. </div>
  175. </div>
  176. </template>
  177. </div>
  178. <div
  179. ref="dragSpliter"
  180. style="
  181. width: 100%;
  182. height: 4px;
  183. border: 2px solid grey;
  184. background-color: grey;
  185. cursor: row-resize;
  186. "
  187. class="split-pane tw-flex tw-justify-evenly"
  188. >
  189. <div
  190. style="
  191. margin-top: -14px;
  192. width: 20px;
  193. height: 16px;
  194. text-align: center;
  195. clip-path: polygon(0 100%, 100% 100%, 50% 0);
  196. background-color: lightskyblue;
  197. cursor: pointer;
  198. "
  199. @click="topPercent = 20"
  200. ></div>
  201. <div
  202. style="
  203. margin-top: -3px;
  204. width: 20px;
  205. height: 16px;
  206. text-align: center;
  207. clip-path: polygon(0 0, 100% 0, 50% 100%);
  208. background-color: lightskyblue;
  209. cursor: pointer;
  210. "
  211. @click="topPercent = 90"
  212. ></div>
  213. </div>
  214. <div
  215. class="tw-flex tw-flex-wrap tw-mt-5 tw-overflow-auto tw-content-start"
  216. style="padding-bottom: 40px; gap: 8px"
  217. :style="{ height: `${100 - topPercent}%` }"
  218. >
  219. <div
  220. v-for="(s, i) in questionScoreSteps.slice(1)"
  221. :key="i"
  222. class="single-score tw-cursor-pointer tw-font-bold"
  223. :class="isCurrentScore(s) && 'current-score'"
  224. @click="chooseScore(s)"
  225. >
  226. {{ s }}
  227. </div>
  228. <a-tooltip placement="bottom" :destroyTooltipOnHide="true">
  229. <template #title>作答错误,或只书写题号等情况</template>
  230. <div
  231. class="single-score tw-cursor-pointer tw-font-bold"
  232. :class="Object.is(store.currentScore, 0) && 'current-score'"
  233. @click="chooseScore(0)"
  234. >
  235. 0
  236. </div>
  237. </a-tooltip>
  238. <a-tooltip placement="bottom" :destroyTooltipOnHide="true">
  239. <template #title>作答为空、未作答、或完全没找到作答</template>
  240. <div
  241. class="single-score tw-cursor-pointer tw-font-bold"
  242. :class="Object.is(store.currentScore, -0) && 'current-score'"
  243. @click="chooseScore(-0)"
  244. >
  245. </div>
  246. </a-tooltip>
  247. </div>
  248. </div>
  249. <div
  250. class="tw-flex tw-justify-between tw-mt-4"
  251. style="position: relative; bottom: 0px; right: 0px; width: 230px"
  252. >
  253. <qm-button
  254. type="primary"
  255. shape="round"
  256. size="large"
  257. style="
  258. background-color: var(--app-undo-button-bg-color);
  259. border-color: var(--app-undo-button-bg-color);
  260. "
  261. :clickTimeout="300"
  262. @click="clearLatestMarkOfCurrentQuetion"
  263. >
  264. 回退
  265. </qm-button>
  266. <qm-button
  267. type="primary"
  268. shape="round"
  269. size="large"
  270. :clickTimeout="300"
  271. data-test="clear-score"
  272. @click="clearAllMarksOfCurrentQuetion"
  273. >
  274. 清除本题
  275. </qm-button>
  276. </div>
  277. </div>
  278. </template>
  279. <script setup lang="ts">
  280. import type { Question } from "@/types";
  281. import { isNumber } from "lodash-es";
  282. import { onMounted, onUnmounted, watch, ref, reactive, computed } from "vue";
  283. import { store } from "@/store/store";
  284. import { autoChooseFirstQuestion } from "./use/autoChooseFirstQuestion";
  285. import { dragSplitPane } from "./use/splitPane";
  286. import { addFocusTrack, removeFocusTrack } from "./use/focusTracks";
  287. import EventBus from "@/plugins/eventBus";
  288. import { cloneDeep } from "lodash-es";
  289. const props = defineProps<{ modal?: boolean; arbitrateIndex?: string }>();
  290. const activeIndex = computed(() => {
  291. return (
  292. props.arbitrateIndex ? props.arbitrateIndex?.split(",") || [] : []
  293. ).map((indexStr: string) => Number(indexStr) - 1);
  294. });
  295. const notInActive = (index: number) => {
  296. return activeIndex.value.length && activeIndex.value.indexOf(index) == -1;
  297. };
  298. const emit = defineEmits(["submit", "allZeroSubmit", "unselectiveSubmit"]);
  299. const { dragSpliter, topPercent } = dragSplitPane();
  300. const activeRightMenuItem = ref<any>(null);
  301. const tmpStyle = reactive<any>({
  302. left: 0,
  303. top: 0,
  304. zIndex: 300,
  305. });
  306. function getParentNode(el: any, c: string): any {
  307. if (el.className?.includes(c)) {
  308. return el;
  309. } else {
  310. if (el.parentNode) {
  311. return getParentNode(el.parentNode, c);
  312. } else {
  313. return null;
  314. }
  315. }
  316. }
  317. const onRightClick = (e: any, index?: any) => {
  318. e.preventDefault();
  319. if (
  320. store.currentTask?.markResult.scoreList[index] ||
  321. store.currentTask?.markResult.scoreList[index] === 0
  322. ) {
  323. tmpStyle.left = e.clientX + "px";
  324. tmpStyle.top = e.clientY + "px";
  325. let parentNode = getParentNode(e.target, "question");
  326. if (parentNode) {
  327. activeRightMenuItem.value = parentNode;
  328. }
  329. console.log("activeRightMenuItem:", activeRightMenuItem.value);
  330. }
  331. };
  332. const rightBlur = () => {
  333. activeRightMenuItem.value = null;
  334. removeFocusTrack();
  335. };
  336. const positioning = (question: Question) => {
  337. // let list =
  338. // store.getMarkStatus === "正评" || store.getMarkStatus === "试评"
  339. // ? sliceImagesWithTrackListCopy.value
  340. // : undefined;
  341. // addFocusTrack(undefined, question.mainNumber, question.subNumber, true, list);
  342. console.log(
  343. "sliceImagesWithTrackListCopy:",
  344. sliceImagesWithTrackListCopy.value
  345. );
  346. addFocusTrack(
  347. undefined,
  348. question.mainNumber,
  349. question.subNumber,
  350. true,
  351. sliceImagesWithTrackListCopy.value || []
  352. );
  353. activeRightMenuItem.value = null;
  354. };
  355. watch(topPercent, () => {
  356. if (topPercent.value < 10) {
  357. topPercent.value = 10;
  358. }
  359. if (topPercent.value > 90) {
  360. topPercent.value = 90;
  361. }
  362. });
  363. const { chooseQuestion } = autoChooseFirstQuestion();
  364. const willChooseQuestion = (question: any, index: number) => {
  365. if (notInActive(index)) {
  366. return;
  367. }
  368. chooseQuestion(question);
  369. };
  370. let sliceImagesWithTrackListCopy = ref([]);
  371. EventBus.on("draw-change", (list: any) => {
  372. // if (store.getMarkStatus === "正评" || store.getMarkStatus === "试评") {
  373. sliceImagesWithTrackListCopy.value = cloneDeep(list);
  374. // } else {
  375. // sliceImagesWithTrackListCopy.value = [];
  376. // }
  377. });
  378. // 切换题目是清空上一题的分数
  379. watch(
  380. () => store.currentQuestion,
  381. () => (store.currentScore = undefined)
  382. );
  383. const questionScore = $computed(
  384. () =>
  385. store.currentTask &&
  386. store.currentQuestion &&
  387. store.currentTask.markResult?.scoreList[store.currentQuestion.__index]
  388. );
  389. // const questionScoreSteps = $computed(() => {
  390. // const question = store.currentQuestion;
  391. // if (!question) return [];
  392. // const remainScore =
  393. // Math.round(question.maxScore * 100 - (questionScore || 0) * 100) / 100;
  394. // const steps = [];
  395. // if (question.intervalScore <= 0) {
  396. // console.warn(`question.intervalScore got: ${question.intervalScore}`);
  397. // }
  398. // for (
  399. // let i = 0;
  400. // i <= remainScore && question.intervalScore > 0;
  401. // i = Math.round(i * 100 + question.intervalScore * 100) / 100
  402. // ) {
  403. // steps.push(i);
  404. // }
  405. // if (
  406. // Math.round(remainScore * 100) % Math.round(question.intervalScore * 100) !==
  407. // 0
  408. // ) {
  409. // steps.push(remainScore);
  410. // }
  411. // return steps;
  412. // });
  413. const questionScoreSteps = $computed(() => {
  414. const question = store.currentQuestion;
  415. if (!question) return [];
  416. const remainScore =
  417. Math.round(question.maxScore * 1000 - (questionScore || 0) * 1000) / 1000;
  418. const steps = [];
  419. if (question.intervalScore <= 0) {
  420. console.warn(`question.intervalScore got: ${question.intervalScore}`);
  421. }
  422. for (
  423. let i = 0;
  424. i <= remainScore && question.intervalScore > 0;
  425. i = Math.round(i * 1000 + question.intervalScore * 1000) / 1000
  426. ) {
  427. steps.push(i);
  428. }
  429. if (
  430. Math.round(remainScore * 1000) %
  431. Math.round(question.intervalScore * 1000) !==
  432. 0
  433. ) {
  434. steps.push(remainScore);
  435. }
  436. return steps;
  437. });
  438. function isCurrentQuestion(question: Question) {
  439. return (
  440. store.currentQuestion?.mainNumber === question.mainNumber &&
  441. store.currentQuestion?.subNumber === question.subNumber
  442. );
  443. }
  444. function isCurrentScore(score: number) {
  445. return store.currentScore === score;
  446. }
  447. function chooseScore(score: number) {
  448. if (store.currentScore === score) {
  449. store.currentScore = undefined;
  450. } else {
  451. store.currentScore = score;
  452. store.currentSpecialTag = undefined;
  453. }
  454. }
  455. let keyPressTimestamp = 0;
  456. let keys: string[] = [];
  457. function numberKeyListener(event: KeyboardEvent) {
  458. if (!store.currentQuestion) return;
  459. if (" jiklc".includes(event.key)) return;
  460. if (event.key === "#") {
  461. keys = [];
  462. store.currentScore = -0;
  463. return;
  464. }
  465. function indexOfCurrentQuestion() {
  466. return (
  467. store.currentTask?.questionList.findIndex(
  468. (q) =>
  469. q.mainNumber === store.currentQuestion?.mainNumber &&
  470. q.subNumber === store.currentQuestion.subNumber
  471. ) ?? -1
  472. );
  473. }
  474. // tab 循环答题列表
  475. if (event.key === "Tab") {
  476. const idx = indexOfCurrentQuestion();
  477. if (idx >= 0 && store.currentTask) {
  478. if (!activeIndex.value.length) {
  479. const len = store.currentTask.questionList.length;
  480. chooseQuestion(store.currentTask.questionList[(idx + 1) % len]);
  481. } else {
  482. let curActiveIdx = activeIndex.value.indexOf(idx);
  483. let len = activeIndex.value.length;
  484. chooseQuestion(
  485. store.currentTask.questionList[
  486. activeIndex.value[(curActiveIdx + 1) % len]
  487. ]
  488. );
  489. }
  490. event.preventDefault();
  491. }
  492. return;
  493. }
  494. // 为了cypress可以加速时间
  495. if (Date.now() - keyPressTimestamp > 1 * 1000) {
  496. keys = [];
  497. }
  498. keyPressTimestamp = Date.now();
  499. keys.push(event.key);
  500. if (isNaN(parseFloat(keys.join("")))) {
  501. keys = [];
  502. }
  503. if (event.key === "Escape") {
  504. keys = [];
  505. store.currentScore = undefined;
  506. store.currentSpecialTag = undefined;
  507. return;
  508. }
  509. const score = parseFloat(keys.join(""));
  510. if (isNumber(score) && questionScoreSteps.includes(score)) {
  511. chooseScore(score);
  512. }
  513. }
  514. function submitListener(e: KeyboardEvent) {
  515. // if (import.meta.env.DEV && e.ctrlKey && e.key === "Enter") {
  516. if (e.ctrlKey && e.key === "Enter") {
  517. submit();
  518. }
  519. }
  520. onMounted(() => {
  521. document.addEventListener("keydown", numberKeyListener);
  522. document.addEventListener("keydown", submitListener);
  523. });
  524. onUnmounted(() => {
  525. document.removeEventListener("keydown", numberKeyListener);
  526. document.removeEventListener("keydown", submitListener);
  527. });
  528. watch(
  529. () => store.isScoreBoardCollapsed,
  530. () => {
  531. // 此处的逻辑是 MarkBoardTrackDialog 带来的,不然 numberKeyListener 在两个组件中多次触发有问题
  532. if (store.isScoreBoardCollapsed) {
  533. document.removeEventListener("keydown", numberKeyListener);
  534. document.removeEventListener("keydown", submitListener);
  535. } else {
  536. // 重复添加相同的function是没问题,不会重复触发
  537. document.addEventListener("keydown", numberKeyListener);
  538. document.addEventListener("keydown", submitListener);
  539. }
  540. },
  541. { immediate: true }
  542. );
  543. function clearLatestMarkOfCurrentQuetion() {
  544. if (!store.currentTask?.markResult || !store.currentQuestion) return;
  545. const { __index, mainNumber, subNumber } = store.currentQuestion;
  546. const markResult = store.currentTask.markResult;
  547. const ts = markResult.trackList.filter(
  548. (q) => q.mainNumber === mainNumber && q.subNumber === subNumber
  549. );
  550. if (ts.length === 0) {
  551. return;
  552. }
  553. const lastMark = ts.splice(-1)[0];
  554. store.removeScoreTracks = [lastMark];
  555. markResult.trackList = markResult.trackList.filter((t) => t !== lastMark);
  556. markResult.scoreList[__index] =
  557. ts.length === 0
  558. ? null
  559. : ts
  560. .map((t) => t.score)
  561. .reduce((acc, v) => (acc += Math.round(v * 1000)), 0) / 1000;
  562. }
  563. function clearAllMarksOfCurrentQuetion() {
  564. if (!store.currentTask?.markResult || !store.currentQuestion) return;
  565. const markResult = store.currentTask.markResult;
  566. store.removeScoreTracks = markResult.trackList.filter(
  567. (q) =>
  568. q.mainNumber === store.currentQuestion?.mainNumber &&
  569. q.subNumber === store.currentQuestion?.subNumber
  570. );
  571. markResult.trackList = markResult.trackList.filter(
  572. (q) => !store.removeScoreTracks.includes(q)
  573. );
  574. const { __index } = store.currentQuestion;
  575. markResult.scoreList[__index] = null;
  576. }
  577. function submit() {
  578. emit("submit");
  579. }
  580. const buttonHeightForSelective = $computed(() =>
  581. store.setting.selective &&
  582. store.setting.enableAllZero &&
  583. !store.setting.forceSpecialTag
  584. ? "36px"
  585. : "76px"
  586. );
  587. </script>
  588. <style lang="less" scoped>
  589. .right-menu-box {
  590. z-index: 10;
  591. background-color: #fff;
  592. border-radius: 4px;
  593. width: 80px;
  594. padding: 2px 0;
  595. box-shadow: 0 0 3px #ddd;
  596. .right-menu-item {
  597. height: 30px;
  598. line-height: 30px;
  599. font-size: 14px;
  600. padding: 0 10px;
  601. color: #333;
  602. &:hover {
  603. background: var(--app-main-bg-color);
  604. }
  605. }
  606. }
  607. .mark-board-track-container {
  608. max-width: 290px;
  609. min-width: 290px;
  610. padding: 20px;
  611. max-height: calc(100vh - 56px - 0px);
  612. overflow: auto;
  613. z-index: 1001;
  614. transition: margin-right 0.5s;
  615. color: var(--app-small-header-text-color);
  616. background-color: var(--app-main-bg-color);
  617. }
  618. .mark-board-track-container-in-dialog {
  619. max-width: 100%;
  620. min-width: 100%;
  621. height: 100%;
  622. }
  623. .mark-board-track-container.show {
  624. margin-right: 0;
  625. }
  626. .mark-board-track-container.hide {
  627. margin-right: -100%;
  628. }
  629. .top-container {
  630. background-color: var(--app-container-bg-color);
  631. }
  632. .total-score {
  633. color: var(--app-main-text-color);
  634. font-size: 32px;
  635. }
  636. .question {
  637. min-width: 110px;
  638. max-width: 110px;
  639. min-height: 72px;
  640. padding: 10px;
  641. background-color: var(--app-container-bg-color);
  642. &.disabled {
  643. background-color: #f5f5f5 !important;
  644. // pointer-events: none;
  645. cursor: not-allowed;
  646. * {
  647. color: rgba(0, 0, 0, 0.25) !important;
  648. }
  649. }
  650. position: relative;
  651. .tihao {
  652. &:hover {
  653. // font-weight: bold;
  654. }
  655. }
  656. }
  657. .current-question {
  658. color: white;
  659. background-color: var(--app-score-color);
  660. }
  661. .single-score {
  662. position: relative;
  663. width: 32px;
  664. height: 32px;
  665. font-size: var(--app-secondary-font-size);
  666. display: grid;
  667. place-content: center;
  668. background-color: var(--app-container-bg-color);
  669. border-radius: 30px;
  670. }
  671. .current-score {
  672. background-color: var(--app-score-color);
  673. color: white;
  674. }
  675. .all-zero-unselective-button {
  676. height: v-bind(buttonHeightForSelective);
  677. border-radius: 10px;
  678. padding: 7px;
  679. background-color: #4db9ff;
  680. border: none;
  681. }
  682. </style>