From 96a1c3808f1795c3543c373918eb6c313feadfb7 Mon Sep 17 00:00:00 2001
From: yuetsh <517252939@qq.com>
Date: Tue, 13 Oct 2026 22:24:59 +0800
Subject: [PATCH] =?UTF-8?q?fix(=E8=87=AA=E5=AD=A6):=20=E6=89=8B=E6=9C=BA?=
=?UTF-8?q?=E4=B8=8A=E3=80=8C=E4=BB=A3=E7=A0=81=E6=8E=92=E5=BA=8F=E3=80=8D?=
=?UTF-8?q?=E3=80=8C=E5=88=86=E7=BB=84=E3=80=8D=E4=B8=A4=E7=A7=8D=E7=BB=83?=
=?UTF-8?q?=E4=B8=80=E7=BB=83=E6=8B=96=E4=B8=8D=E5=8A=A8=E3=80=81=E5=81=9A?=
=?UTF-8?q?=E4=B8=8D=E4=BA=86=EF=BC=8C=E6=94=B9=E6=88=90=E7=82=B9=E4=B8=80?=
=?UTF-8?q?=E4=B8=8B=E9=80=89=E4=B8=AD=E3=80=81=E5=86=8D=E7=82=B9=E4=B8=80?=
=?UTF-8?q?=E4=B8=8B=E6=94=BE=E4=B8=8B=E4=B9=9F=E8=A1=8C=EF=BC=9B=E5=A1=AB?=
=?UTF-8?q?=E7=A9=BA=E4=B8=8D=E5=86=8D=E8=A2=AB=E6=89=8B=E6=9C=BA=E8=BE=93?=
=?UTF-8?q?=E5=85=A5=E6=B3=95=E6=8A=8A=E9=A6=96=E5=AD=97=E6=AF=8D=E6=94=B9?=
=?UTF-8?q?=E6=88=90=E5=A4=A7=E5=86=99?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-Authored-By: Claude Opus 5.5
---
.../src/oj/learn/components/ExerciseDebug.vue | 2 +-
.../src/oj/learn/components/ExerciseFill.vue | 4 ++
.../src/oj/learn/components/ExerciseGroup.vue | 40 ++++++++++-
.../oj/learn/components/ExercisePredict.vue | 1 +
.../src/oj/learn/components/ExerciseSort.vue | 66 +++++++++++++------
5 files changed, 92 insertions(+), 21 deletions(-)
diff --git a/apps/web/src/oj/learn/components/ExerciseDebug.vue b/apps/web/src/oj/learn/components/ExerciseDebug.vue
index c553500..8b5a7a1 100644
--- a/apps/web/src/oj/learn/components/ExerciseDebug.vue
+++ b/apps/web/src/oj/learn/components/ExerciseDebug.vue
@@ -101,7 +101,7 @@ function reset() {
{{ idx + 1 }}
-
+
diff --git a/apps/web/src/oj/learn/components/ExerciseFill.vue b/apps/web/src/oj/learn/components/ExerciseFill.vue
index 1b8d305..2e7432a 100644
--- a/apps/web/src/oj/learn/components/ExerciseFill.vue
+++ b/apps/web/src/oj/learn/components/ExerciseFill.vue
@@ -96,6 +96,10 @@ function inputWidth(idx: number): string {
v-else
:value="userInputs[seg.index]"
:disabled="allCorrect"
+ autocapitalize="off"
+ autocorrect="off"
+ autocomplete="off"
+ spellcheck="false"
:style="{
width: inputWidth(seg.index),
fontFamily: 'var(--learn-code-font)',
diff --git a/apps/web/src/oj/learn/components/ExerciseGroup.vue b/apps/web/src/oj/learn/components/ExerciseGroup.vue
index e9d1afa..ebddaaf 100644
--- a/apps/web/src/oj/learn/components/ExerciseGroup.vue
+++ b/apps/web/src/oj/learn/components/ExerciseGroup.vue
@@ -13,12 +13,15 @@ const data = computed(() => props.exercise.data as ExerciseGroupData)
const order = ref([]) // item 的稳定展示顺序(初始乱序)
const placement = ref([]) // placement[itemIdx] = 桶下标,-1 表示在池中
const dragIdx = ref(null)
+// 手机上没有 HTML5 拖放(触屏不触发 dragstart),所以再给一条点选的路:先点项目、再点分组
+const pickedIdx = ref(null)
const submitted = ref(false)
function init() {
order.value = shuffle(data.value.items.map((_, i) => i))
placement.value = Array(data.value.items.length).fill(-1)
dragIdx.value = null
+ pickedIdx.value = null
submitted.value = false
}
@@ -32,6 +35,7 @@ const locked = computed(() => submitted.value && allCorrect.value)
function onDragStart(i: number) {
if (locked.value) return
dragIdx.value = i
+ pickedIdx.value = null
}
function dropTo(bucket: number) {
@@ -41,6 +45,25 @@ function dropTo(bucket: number) {
submitted.value = false
}
+// 手机上分组框不大,点分组时多半点在框里已有的项目上 —— 这时算「放进它所在的分组」,
+// 只有点同一区域里的另一项才是换选
+function onItemClick(i: number) {
+ if (locked.value) return
+ const picked = pickedIdx.value
+ if (picked !== null && picked !== i && placement.value[picked] !== placement.value[i]) {
+ onAreaClick(placement.value[i])
+ return
+ }
+ pickedIdx.value = picked === i ? null : i
+}
+
+function onAreaClick(bucket: number) {
+ if (locked.value || pickedIdx.value === null) return
+ placement.value[pickedIdx.value] = bucket
+ pickedIdx.value = null
+ submitted.value = false
+}
+
const poolItems = computed(() => order.value.filter((i) => placement.value[i] === -1))
function itemsIn(bucket: number): number[] {
return order.value.filter((i) => placement.value[i] === bucket)
@@ -56,6 +79,17 @@ function chipStyle(i: number): Record {
const color =
status === "correct" ? "#18a058" : status === "wrong" ? "#d03050" : "var(--learn-control-line)"
const plain = color === "var(--learn-control-line)"
+ if (pickedIdx.value === i) {
+ return {
+ padding: "5.5px 11.5px",
+ borderRadius: "6px",
+ border: "2px solid #2080f0",
+ background: "rgba(32,128,240,0.08)",
+ cursor: "pointer",
+ userSelect: "none",
+ fontSize: "15px",
+ }
+ }
return {
padding: "6px 12px",
borderRadius: "6px",
@@ -86,7 +120,7 @@ function reset() {
{{ data.question }}
- 把下面的项目拖到对应的分组里,可在分组间拖动调整。
+ 把下面的项目拖到对应的分组里,也可以先点项目、再点分组。
(已全部归类)
@@ -112,6 +147,7 @@ function reset() {
draggable="true"
:style="chipStyle(i)"
@dragstart="onDragStart(i)"
+ @click.stop="onItemClick(i)"
>
{{ data.items[i] }}
@@ -135,6 +171,7 @@ function reset() {
}"
@dragover.prevent
@drop="dropTo(b)"
+ @click="onAreaClick(b)"
>
{{ bucket }}
@@ -146,6 +183,7 @@ function reset() {
draggable="true"
:style="chipStyle(i)"
@dragstart="onDragStart(i)"
+ @click.stop="onItemClick(i)"
>
{{ data.items[i] }}
diff --git a/apps/web/src/oj/learn/components/ExercisePredict.vue b/apps/web/src/oj/learn/components/ExercisePredict.vue
index ee62d9b..def0911 100644
--- a/apps/web/src/oj/learn/components/ExercisePredict.vue
+++ b/apps/web/src/oj/learn/components/ExercisePredict.vue
@@ -81,6 +81,7 @@ function reset() {
:rows="3"
:disabled="submitted && allCorrect"
placeholder="在这里输入程序会打印的内容"
+ :input-props="{ autocapitalize: 'off', autocorrect: 'off', spellcheck: false }"
style="font-family: var(--learn-code-font)"
/>
diff --git a/apps/web/src/oj/learn/components/ExerciseSort.vue b/apps/web/src/oj/learn/components/ExerciseSort.vue
index 871ea63..bd7a9a6 100644
--- a/apps/web/src/oj/learn/components/ExerciseSort.vue
+++ b/apps/web/src/oj/learn/components/ExerciseSort.vue
@@ -24,6 +24,7 @@ function init() {
;[shuffled[0], shuffled[1]] = [shuffled[1], shuffled[0]]
}
lines.value = shuffled
+ pickedIdx.value = null
submitted.value = false
}
@@ -31,19 +32,37 @@ onMounted(init)
watch(() => props.exercise.id, init)
const dragIdx = ref(null)
+// 手机上没有 HTML5 拖放(触屏不触发 dragstart),所以再给一条点选的路:先点一行、再点它该去的位置
+const pickedIdx = ref(null)
function onDragStart(idx: number) {
dragIdx.value = idx
+ pickedIdx.value = null
+}
+
+function moveLine(from: number, to: number) {
+ if (from === to) return
+ const newLines = [...lines.value]
+ const [moved] = newLines.splice(from, 1)
+ newLines.splice(to, 0, moved)
+ lines.value = newLines
+ submitted.value = false
}
function onDrop(targetIdx: number) {
- if (dragIdx.value === null || dragIdx.value === targetIdx) return
- const newLines = [...lines.value]
- const [moved] = newLines.splice(dragIdx.value, 1)
- newLines.splice(targetIdx, 0, moved)
- lines.value = newLines
+ if (dragIdx.value === null) return
+ moveLine(dragIdx.value, targetIdx)
dragIdx.value = null
- submitted.value = false
+}
+
+function onLineClick(idx: number) {
+ if (submitted.value && allCorrect.value) return
+ if (pickedIdx.value === null) {
+ pickedIdx.value = idx
+ return
+ }
+ moveLine(pickedIdx.value, idx)
+ pickedIdx.value = null
}
function lineStatus(idx: number): "correct" | "wrong" | "default" {
@@ -86,19 +105,24 @@ const lineHtml = computed(() => highlightLines(data.value.lines, props
gap: '10px',
padding: '8px 12px',
borderRadius: '6px',
- border: `1.5px ${submitted ? 'solid' : 'dashed'} ${
- lineStatus(idx) === 'correct'
- ? '#18a058'
- : lineStatus(idx) === 'wrong'
- ? '#d03050'
- : 'var(--learn-control-line)'
- }`,
+ border:
+ pickedIdx === idx
+ ? '2px solid #2080f0'
+ : `1.5px ${submitted ? 'solid' : 'dashed'} ${
+ lineStatus(idx) === 'correct'
+ ? '#18a058'
+ : lineStatus(idx) === 'wrong'
+ ? '#d03050'
+ : 'var(--learn-control-line)'
+ }`,
background:
- lineStatus(idx) === 'correct'
- ? 'rgba(24,160,88,0.08)'
- : lineStatus(idx) === 'wrong'
- ? 'rgba(208,48,80,0.07)'
- : 'transparent',
+ pickedIdx === idx
+ ? 'rgba(32,128,240,0.08)'
+ : lineStatus(idx) === 'correct'
+ ? 'rgba(24,160,88,0.08)'
+ : lineStatus(idx) === 'wrong'
+ ? 'rgba(208,48,80,0.07)'
+ : 'transparent',
cursor: 'grab',
fontFamily: 'var(--learn-code-font)',
userSelect: 'none',
@@ -106,9 +130,13 @@ const lineHtml = computed(() => highlightLines(data.value.lines, props
@dragstart="onDragStart(idx)"
@dragover.prevent
@drop="onDrop(idx)"
+ @click="onLineClick(idx)"
>
⠿
-
+