import { useEffect, useRef, useState } from 'react' import TaskCard from '../../components/task/TaskCard.jsx' import useColumnDrag from '../../components/task/useColumnDrag.js' // 列体 + 右缘滚动条: 滚动时出现细滚动条, 停止约 700ms 后淡出 // (移动端 WebView 原生滚动条是即隐式的, 看板列窄、需要明确的滚动指示) function ScrollBody({ children }) { const ref = useRef(null) const fade = useRef(null) const [bar, setBar] = useState(null) // { h, y } 滚动条几何 useEffect(() => () => clearTimeout(fade.current), []) function onScroll() { const el = ref.current if (!el) return const max = el.scrollHeight - el.clientHeight if (max <= 2) { setBar(null); return } const h = Math.max(28, Math.round(el.clientHeight * (el.clientHeight / el.scrollHeight))) const y = Math.round((el.scrollTop / max) * (el.clientHeight - h)) setBar({ h, y }) clearTimeout(fade.current) fade.current = setTimeout(() => setBar(null), 700) } return (
{children}
) } // 看板视图 (T-BD-01, T-UI-07) // 拖动 = 长按 400ms 激活, 卡片原位抬起, 指针划过列高亮, 松手落列 (重点设计 §7.1) // 横向滚列; 列内独立纵向滚动, 列头固定, 滚动时右缘显示滚动条 // 不做"拖到卡片上转子任务" —— 统一走详情页「转为子任务」 export default function BoardView({ tasks, columns, onMoveColumn, onOpen, onToggleSub, onToggle, onMore, onQuickAdd, onDragActiveChange, }) { const drag = useColumnDrag({ onDrop: onMoveColumn }) // 把"是否正在拖拽"上报给容器: 拖拽期间收到远端变更时, 容器会延后刷新, // 避免卡片在手中跳位 (见 docs/V0.2/离线编辑模块/即时同步方案.md §4.4) const dragging = !!drag.dragTask useEffect(() => { onDragActiveChange?.(dragging) }, [dragging, onDragActiveChange]) const ordered = [...(columns || [])].sort((a, b) => a.sortOrder - b.sortOrder) return (
{ordered.map((col) => { const list = (tasks || []).filter((t) => t.columnId === col.id) return (
{col.name} {list.length} {col.boundStatus ? ( ↔ {col.boundStatus === 'done' ? '完成' : col.boundStatus === 'doing' ? '执行中' : '未开始'} ) : ( 未绑定 )}
{list.map((t) => ( { if (!drag.dragTask && !drag.justEnded()) onOpen?.(t) }} onToggleSub={onToggleSub} onToggle={onToggle} onMore={onMore} /> ))} {list.length === 0 &&
暂无任务
}
onQuickAdd?.(col.id)}>+ 添加任务
) })}
) }