From ab1c67dbc563983141c394e9bfcdc8fb3b50f156 Mon Sep 17 00:00:00 2001 From: qubiaobiao <3294694717@qq.com> Date: Wed, 21 Oct 2026 13:44:38 +0800 Subject: [PATCH] =?UTF-8?q?feat(admin-ui):=20=E6=97=B6=E9=97=B4=E5=B9=B6?= =?UTF-8?q?=E5=8F=91=E5=86=B2=E7=AA=81=E8=87=AA=E5=8A=A8=E5=9B=9E=E8=AF=BB?= =?UTF-8?q?=20+=20=E8=BD=AE=E6=92=AD=E6=8E=92=E5=BA=8F=E8=84=8F=E6=A0=87?= =?UTF-8?q?=E8=AE=B0=20+=20=E6=9D=83=E9=99=90=E7=83=AD=E6=A0=A1=E5=87=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - api/admin.js:setTimes(data, expected);⚠️ 只在基线**非空**时才带 expectedTimes (空对象会让后端误判"所有组都要求校验"而恒冲突)。 - Admin.vue(时间设置):timesBaseline 记录 fetchTimes 载入时的服务端旧值, ⛔ 不用表单当前值(那样永远等于提交值 ⇒ 校验恒真 = 假保护)。冲突时自动 fetchTimes 重载(表单已过期,拿它重试只会再冲突);其它失败保留用户输入。 - Admin.vue(轮播):carouselOrderDirty —— 拖拽只改前端顺序、不落库, 此前卡片"排序: N"用的是渲染下标,拖完立刻变新序号,看起来已生效、刷新却回退。 现加"排序未保存"标签 + 按钮文案变化,未保存状态可见。 - Admin.vue(权限):切菜单时 8s 节流重拉 /api/admin/me,权限变化即提示。 原先前端只在 onMounted 拉一次 ⇒ 被改权限后必须手动刷新页面, 否则停在旧菜单上每个请求都撞 403 且无任何提示。⛔ 不用 location.reload() (会丢未提交的表单输入)。 --- src/api/admin.js | 9 ++++-- src/views/Admin.vue | 76 +++++++++++++++++++++++++++++++++++++++------ 2 files changed, 74 insertions(+), 11 deletions(-) diff --git a/src/api/admin.js b/src/api/admin.js index eb96d95..186ec8e 100644 --- a/src/api/admin.js +++ b/src/api/admin.js @@ -68,9 +68,11 @@ export function getTimes() { /** * 设置比赛时间 * @param {Object} data - { zhongzhi: {start, end}, gaozhi: ... } + * @param {Object} [expected] - B② 乐观锁:打开表单时读到的旧值 + * { zhongzhi: { start, end, deadline }, ... };不传 ⇒ 后端不校验(旧行为) * @returns {Promise} */ -export function setTimes(data) { +export function setTimes(data, expected) { // 后端要求 times 数组,格式:[{ group, startTime, endTime, deadline, choiceCount, judgeCount }] // 注意:必须携带 choiceCount / judgeCount,否则后端按缺省 50/20 处理,后台「抽取数量」配置无法落库 const times = Object.entries(data).map(([group, item]) => ({ @@ -81,7 +83,10 @@ export function setTimes(data) { choiceCount: item.choiceCount != null ? parseInt(item.choiceCount, 10) : 50, judgeCount: item.judgeCount != null ? parseInt(item.judgeCount, 10) : 20, })) - return request.put('/admin/times', { times }) + const payload = { times } + // ⛔ 只在真的有基线时才带:空对象会让后端误以为「所有组都要求校验」而恒冲突 + if (expected && Object.keys(expected).length > 0) payload.expectedTimes = expected + return request.put('/admin/times', payload) } /** diff --git a/src/views/Admin.vue b/src/views/Admin.vue index 6048cb9..4a7ea88 100644 --- a/src/views/Admin.vue +++ b/src/views/Admin.vue @@ -1950,9 +1950,15 @@

轮播管理

添加轮播 - 保存排序 + {{ carouselOrderDirty ? '保存排序(有未保存改动)' : '保存排序' }} + 排序未保存 - 拖拽卡片可调整排序 + 拖拽卡片可调整排序;拖完须点「保存排序」才写入服务器