feat(V0.2): 任务类型标签 —— 项目级自定义 + 任务标记 + 列表/看板展示
Docker Build and Push / build-image (push) Successful in 1m21s

- 数据: Project.taskKinds (JSON, 未配置回落默认 需求/Bug/FEATURE/优化),
  Task.kind (≤20字); 迁移 20261025030000_task_kind
- 服务: 项目 PUT 支持整体替换 taskKinds (去重/上限30/至少1个);
  任务 create/update 支持 kind (空串清空)
- 项目管理: 新增「任务类型」分区, chips 展示 + 弹层编辑 (删除/新增)
- 任务详情: 新增「类型」字段, 项目类型 chips 点选, 可清空
- 展示: 列表行左下与看板卡左下显示彩色小标签
  (需求蓝/Bug红/FEATURE紫/优化橙, 自定义类型灰)
This commit is contained in:
jif2.zhang
2026-10-25 02:53:25 +08:00
parent 2e6cc986a0
commit fb9e2350b3
11 changed files with 192 additions and 7 deletions
+7 -1
View File
@@ -70,7 +70,7 @@ router.post('/projects/:id/tasks', async (req, res, next) => {
const project = await loadProjectForUser(req.params.id, userId)
if (!project) return res.status(404).json({ error: '项目不存在或无权限' })
const { title, description = '', parentId, assigneeId, memberIds = [], tags = [] } = req.body || {}
const { title, description = '', parentId, assigneeId, memberIds = [], tags = [], kind } = req.body || {}
const cleanTitle = String(title || '').trim()
if (!cleanTitle) return res.status(400).json({ error: '任务标题不能为空' })
if (cleanTitle.length > 200) return res.status(400).json({ error: '任务标题不能超过 200 字' })
@@ -107,6 +107,7 @@ router.post('/projects/:id/tasks', async (req, res, next) => {
parentId: pid,
title: cleanTitle,
description: String(description || ''),
kind: kind ? String(kind).trim().slice(0, 20) : null,
status: firstCol.boundStatus || 'todo',
assigneeId: finalAssignee,
creatorId: userId,
@@ -177,6 +178,11 @@ router.put('/tasks/:id', async (req, res, next) => {
data.title = t
}
if (body.description !== undefined) data.description = String(body.description)
// 任务类型标签: null 清空, 否则截断保存
if (body.kind !== undefined) {
const k = String(body.kind || '').trim().slice(0, 20)
data.kind = k || null
}
if (body.extras !== undefined) {
if (!Array.isArray(body.extras)) return res.status(400).json({ error: '扩展信息格式非法' })
data.extras = body.extras.map((e) => ({