fix(任务): 修复列表与看板拖拽「能触发但放不下」—— uuid 主键被 Number() 成 NaN
Docker Build and Push / build-image (push) Successful in 1m34s

0.2.1 切本地库后 Task.id / BoardColumn.id 为 uuid 字符串, 拖拽落点却用
Number(dataset.xxxId) 取值得到 NaN:
  - 看板 hitColumn 返回 NaN -> NaN 为 falsy, onDrop 永不触发; 目标列也不高亮
  - 列表 colId/taskId 为 NaN -> 组内命中与换列 findIndex 恒失败, 松手无操作
(打卡侧仍走 REST 数字 id, 故未受影响)

- 新增 src/pages/task/ids.js: idStr / sameId / datasetId, 统一按字符串比对
- useColumnDrag / useRowDrag: 落点、组内命中、换列、提交判定改用 sameId
- ProjectView: moveToColumn / reorderTask / changeStatus 改用 sameId,
  落点为空直接忽略, 不把坏 id 写进本地库
- api/task.js: update 拦截 "NaN"/"undefined" 列 id, 报「看板列无效」

验证: headless Edge + CDP 派发真实指针事件驱动两个 hook (uuid 数据),
修复前 4 条落点断言全挂, 修复后全部通过。
This commit is contained in:
jif2.zhang
2026-10-27 10:06:37 +08:00
parent 06e9a3e694
commit 32f404ac90
5 changed files with 58 additions and 19 deletions
+11 -8
View File
@@ -2,6 +2,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react'
import { ActionSheet, Dialog, DotLoading, Toast } from 'antd-mobile'
import { projectApi, taskApi } from '../../api/task.js'
import { filterVisible, msToNextBoundary } from './date.js'
import { sameId } from './ids.js'
import { getViewMode, setViewMode } from './prefs.js'
import { parseTimePrefix, splitTitle } from './quickAdd.js'
import ListView from './ListView.jsx'
@@ -100,10 +101,12 @@ export default function ProjectView({ projectId, onProjectChanged, onProjectExit
/** 拖拽换列 (T-BD-04/07) */
const moveToColumn = async (task, columnId) => {
const col = columns.find((c) => c.id === columnId)
// columnId 来自拖动落点 (uuid 字符串); 空值直接忽略, 不要把坏 id 写进本地库
if (columnId === null || columnId === undefined || columnId === '') return
const col = columns.find((c) => sameId(c.id, columnId))
try {
await updateTask(task.id, { columnId })
const target = columns.find((c) => c.id === columnId)
const target = columns.find((c) => sameId(c.id, columnId))
if (target?.boundStatus && target.boundStatus !== task.status) {
Toast.show({ content: `已移入 ${col?.name},状态改为「${target.boundStatus === 'done' ? '完成' : target.boundStatus === 'doing' ? '执行中' : '未开始'}」` })
} else {
@@ -116,11 +119,11 @@ export default function ProjectView({ projectId, onProjectChanged, onProjectExit
const reorderTask = async (task, targetId, after) => {
const snapshot = tasks
const orderedCols = [...(columns || [])].sort((a, b) => a.sortOrder - b.sortOrder)
const groups = orderedCols.map((c) => (tasks || []).filter((t) => t.columnId === c.id)).filter((l) => l.length)
const g = groups.find((l) => l.some((t) => t.id === task.id))
const groups = orderedCols.map((c) => (tasks || []).filter((t) => sameId(t.columnId, c.id))).filter((l) => l.length)
const g = groups.find((l) => l.some((t) => sameId(t.id, task.id)))
if (!g) return
const rest = g.filter((t) => t.id !== task.id)
const ti = rest.findIndex((t) => t.id === targetId)
const rest = g.filter((t) => !sameId(t.id, task.id))
const ti = rest.findIndex((t) => sameId(t.id, targetId))
if (ti < 0) return
rest.splice(after ? ti + 1 : ti, 0, task)
const flat = groups.map((l) => (l === g ? rest : l)).flat()
@@ -143,9 +146,9 @@ export default function ProjectView({ projectId, onProjectChanged, onProjectExit
const changeStatus = async (task, status) => {
try {
const fresh = await updateTask(task.id, { status })
const moved = fresh && fresh.columnId !== task.columnId
const moved = fresh && !sameId(fresh.columnId, task.columnId)
if (moved) {
const col = columns.find((c) => c.id === fresh.columnId)
const col = columns.find((c) => sameId(c.id, fresh.columnId))
Toast.show({ content: `已移至 ${col?.name || '目标列'}` })
}
} catch { /* ignore */ }