feat(V0.2): 快速添加输入框三行/失焦收起; ⋯菜单点选即收; 项目图标可设图片
Docker Build and Push / build-image (push) Successful in 1m22s

- 快速添加改 3 行 textarea, Enter 创建/Shift+Enter 换行/Esc 关闭,
  焦点离开且无内容时自动收起
- 任务 ⋯ ActionSheet 点选动作后 handler.close() 收回菜单
- Project.icon (TEXT data URL, 迁移 20261025130000): 项目管理可选图片,
  客户端裁为 96x96 cover JPEG (~15KB); 项目列表/最近项目/管理页图标位
  显示图片, 保持原尺寸与圆角; 可恢复默认首字色块
This commit is contained in:
jif2.zhang
2026-10-25 12:02:29 +08:00
parent e3ac00a641
commit cee21a39d9
7 changed files with 107 additions and 12 deletions
+11 -1
View File
@@ -62,6 +62,7 @@ function projectSummary(p) {
createdAt: p.createdAt,
updatedAt: p.updatedAt,
taskKinds: normTaskKinds(p.taskKinds) || DEFAULT_TASK_KINDS,
icon: p.icon || null,
memberCount: p._count?.members ?? undefined,
taskCount: p._count?.tasks ?? undefined,
}
@@ -134,7 +135,7 @@ router.put('/:id', async (req, res, next) => {
const userId = req.user.sub
const project = await loadProjectForUser(req.params.id, userId)
if (!project) return res.status(404).json({ error: '项目不存在或无权限' })
const { name, archived, notes, taskKinds } = req.body || {}
const { name, archived, notes, taskKinds, icon } = req.body || {}
const data = {}
if (name !== undefined) {
const t = String(name).trim()
@@ -149,6 +150,15 @@ router.put('/:id', async (req, res, next) => {
if (!kinds?.length) return res.status(400).json({ error: '至少保留一个任务类型' })
data.taskKinds = kinds
}
// 项目图标: data URL (客户端已裁剪), null 清除回退首字色块
if (icon !== undefined && icon !== null) {
const s = String(icon)
if (!s.startsWith('data:image/')) return res.status(400).json({ error: '图标格式非法' })
if (s.length > 300_000) return res.status(400).json({ error: '图标过大' })
data.icon = s
} else if (icon === null) {
data.icon = null
}
if (archived !== undefined) data.archived = !!archived
// 项目信息块 (T-PJ-13): 任意多个 { title, content }, 整体替换
if (notes !== undefined) {