diff --git a/src/pages/task/BoardView.jsx b/src/pages/task/BoardView.jsx index 5ca3b3d..a434c7b 100644 --- a/src/pages/task/BoardView.jsx +++ b/src/pages/task/BoardView.jsx @@ -1,8 +1,39 @@ +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, @@ -33,7 +64,7 @@ export default function BoardView({ )}
-
+ {list.map((t) => ( 暂无任务
}
onQuickAdd?.(col.id)}>+ 添加任务
- + ) })} diff --git a/src/styles/globals.css b/src/styles/globals.css index b623ef1..7d0889a 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -1077,13 +1077,24 @@ body.me-safe-top .app-safe-top { height: 0; } display: flex; gap: 10px; padding: 0 12px 8px; overflow-x: auto; overflow-y: hidden; flex: 1 1 auto; min-height: 0; align-items: stretch; } -.bcol { flex: 0 0 186px; display: flex; flex-direction: column; min-height: 0; } -.bcol-head { display: flex; align-items: center; gap: 5px; padding: 0 2px 7px; flex-shrink: 0; } +.bcol { flex: 0 0 186px; display: flex; flex-direction: column; min-height: 0; }.bcol-head { display: flex; align-items: center; gap: 5px; padding: 0 2px 7px; flex-shrink: 0; } .bcol-name { font-size: 12px; font-weight: 700; color: #3d4450; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .bcol-cnt { font-size: 11px; color: #999; background: #e8ebef; border-radius: 999px; padding: 0 6px; line-height: 15px; } .bcol-bind { font-size: 10px; color: var(--color-primary); background: #f0f5ff; border-radius: 4px; padding: 0 4px; margin-left: auto; } .bcol-bind.off { color: #999; background: #f2f3f5; } -.bcol-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 7px; padding-bottom: 8px; } +.bcol-body { + flex: 1 1 auto; min-height: 0; height: 100%; overflow-y: auto; + display: flex; flex-direction: column; gap: 7px; padding-bottom: 8px; + -webkit-overflow-scrolling: touch; overscroll-behavior: contain; +} +/* 列体包裹层: 承载右缘滚动条 (滚动时出现, 停止后淡出) */ +.bcol-main { flex: 1 1 auto; min-height: 0; position: relative; display: flex; } +.bcol-bar { + position: absolute; right: 1px; width: 3px; border-radius: 2px; + background: rgba(15, 23, 42, .3); opacity: 0; transition: opacity .25s ease; + pointer-events: none; z-index: 3; +} +.bcol-bar.on { opacity: 1; } .bcol.dragover .bcol-body { background: #eaf2ff; border-radius: 8px; outline: 1.5px dashed var(--color-primary); } .bcol-empty { font-size: 11px; color: #c0c4cc; text-align: center; padding: 10px 0; } .bcard {