Docker Build and Push / build-image (push) Failing after 3m51s
需求 142 条 (T-*), 设计见 docs/V0.2/任务模块/ 数据层: - 新增 6 张表: Project / ProjectMember / BoardColumn / Task / TaskMember / TaskTag - 看板列是实体(可增删改排序), Task.columnId 外键 RESTRICT 防误删列丢任务 - Task.status(todo/doing/done) 与 columnId 双落库, 二者正交 领域层 server/task-domain/ (唯一口径, 前后端不重复实现): - resolveStatus: 列决定状态(只看目标列, 无拖出回退); 状态与列不匹配时按列序取第一个绑定该状态的列自动归位, 无匹配列则不移动; 子任务完全豁免 - retention: 逐列 6 档保留窗口(永不显示/当天/3天/本周/本月/永久显示), 以 doneAt 判定 - copyTask: 跨项目深拷贝, 人员按目标项目成员过滤并回报丢弃名单 接口: /api/projects, /api/columns, /api/tasks (均校验项目成员) 前端: - 底部 Tab 插入「任务」, 位于「打卡」之后; 默认首页仍为打卡 - 列表视图(子任务缩进+折叠) / 看板视图(长按拖拽换列、拖到卡片降为子任务) - 列设置(列管理+状态绑定+保留选项) / 任务详情(扩展信息卡片默认收起) / 成员管理 - 视图记忆与上次项目存设备端 已验证: 95 文件语法 0 错误、相对导入 0 缺失、领域逻辑用例全部通过
32 lines
1.3 KiB
JavaScript
32 lines
1.3 KiB
JavaScript
// 任务模块: 保留选项的可见性过滤 (T-FL-*)
|
|
// 前端 src/pages/task/date.js 有一份同口径实现, 用于即时过滤; 后端用于统计/兜底
|
|
import { isVisibleByRetention } from './date.js'
|
|
|
|
/**
|
|
* 按"任务所属列"的保留选项过滤任务列表 (T-FL-11)
|
|
* @param {object[]} tasks 任务(需含 status / doneAt / columnId)
|
|
* @param {object[]} columns 列(需含 id / retention)
|
|
*/
|
|
export function filterVisible(tasks, columns, now = new Date()) {
|
|
const retentionById = new Map((columns || []).map((c) => [c.id, c.retention || 'forever']))
|
|
return (tasks || []).filter((t) => {
|
|
const opt = retentionById.get(t.columnId) || 'forever'
|
|
return isVisibleByRetention(t, opt, now)
|
|
})
|
|
}
|
|
|
|
/** 单条判定, 供详情接口复用 */
|
|
export function isTaskVisible(task, columns, now = new Date()) {
|
|
const col = (columns || []).find((c) => c.id === task.columnId)
|
|
return isVisibleByRetention(task, col?.retention || 'forever', now)
|
|
}
|
|
|
|
/** 列内计数: 过滤后条数 (T-FL-14 计数与展示同源) */
|
|
export function countByColumn(tasks, columns, now = new Date()) {
|
|
const visible = filterVisible(tasks, columns, now)
|
|
const out = {}
|
|
for (const c of columns || []) out[c.id] = 0
|
|
for (const t of visible) out[t.columnId] = (out[t.columnId] || 0) + 1
|
|
return out
|
|
}
|