feat(V0.2): 任务模块 —— 项目 / 列表与看板 / 列-状态绑定 / 一级子任务
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 缺失、领域逻辑用例全部通过
This commit is contained in:
jif2.zhang
2026-10-24 11:21:16 +08:00
parent 42acf72f1e
commit 6c9cd3fd99
36 changed files with 6194 additions and 0 deletions
+40
View File
@@ -0,0 +1,40 @@
import { api } from './client.js'
const q = (params) => {
const s = new URLSearchParams()
Object.entries(params || {}).forEach(([k, v]) => {
if (v !== undefined && v !== null && v !== '') s.set(k, v)
})
const str = s.toString()
return str ? '?' + str : ''
}
// 项目
export const projectApi = {
list: () => api('/projects'),
detail: (id) => api(`/projects/${id}`),
create: (body) => api('/projects', { method: 'POST', body }),
update: (id, body) => api(`/projects/${id}`, { method: 'PUT', body }),
remove: (id) => api(`/projects/${id}`, { method: 'DELETE' }),
addMember: (id, body) => api(`/projects/${id}/members`, { method: 'POST', body }),
removeMember: (id, uid) => api(`/projects/${id}/members/${uid}`, { method: 'DELETE' }),
}
// 看板列
export const columnApi = {
list: (projectId) => api(`/projects/${projectId}/columns`),
add: (projectId, body) => api(`/projects/${projectId}/columns`, { method: 'POST', body }),
update: (id, body) => api(`/columns/${id}`, { method: 'PUT', body }),
remove: (id, moveToColumnId) => api(`/columns/${id}${q({ moveToColumnId })}`, { method: 'DELETE' }),
order: (projectId, ids) => api(`/projects/${projectId}/columns/order`, { method: 'PUT', body: { ids } }),
}
// 任务
export const taskApi = {
list: (projectId) => api(`/projects/${projectId}/tasks`),
create: (projectId, body) => api(`/projects/${projectId}/tasks`, { method: 'POST', body }),
detail: (id) => api(`/tasks/${id}`),
update: (id, body) => api(`/tasks/${id}`, { method: 'PUT', body }),
remove: (id) => api(`/tasks/${id}`, { method: 'DELETE' }),
copy: (id, projectId) => api(`/tasks/${id}/copy`, { method: 'POST', body: { projectId } }),
}