Commit Graph
59 Commits
Author SHA1 Message Date
jif2.zhang 61d3028909 feat(0.2.1): M1 数据库迁移 PostgreSQL —— schema 切 pg, 任务域六表加 uuid, 项目 code/任务 number, db.js 切 adapter-pg, 重建 PG 基线迁移; 附实施方案文档 2026-10-25 23:38:54 +08:00
jif2.zhang 1cd5b85a4b Merge remote-tracking branch 'origin/master' into dev-0.2
Docker Build and Push / build-image (push) Successful in 1m6s
# Conflicts:
#	CHANGELOG.md
2026-10-25 21:59:52 +08:00
jif2.zhang 8203a7f893 fix(V0.2): 版本规则收尾 —— 手动 OTA 工作流对齐发布说明/commit 口径
Docker Build and Push / build-image (push) Successful in 1m1s
- ota-build.yml: notes 默认取检出 commit 的 message, --commit 写入
  manifest (与 docker-build 一致); 参数加引号防空格断裂
- docker-build.yml: 去掉 head -c 400 字节截断 (会把多字节汉字切成
  非法 UTF-8 导致 latest.json 解析失败), 截断统一由打包脚本按字符处理
- build-ota.mjs: CI 日志输出 build_id 与 commit
2026-10-25 21:40:13 +08:00
jif2.zhang 0f71323c11 docs: CHANGELOG 按程序/Android外壳/Windows外壳 三部分独立记录当前值与变更
Docker Build and Push / build-image (push) Successful in 1m2s
2026-10-25 21:36:01 +08:00
jif2.zhang 93b7c7bb0a docs(changelog): 记录 V0.2.1 —— 主要解决离线编辑与不同终端数据合并问题 2026-10-25 21:34:17 +08:00
jif2.zhang 67be8d8f7b feat(V0.2): 版本方案落地 —— 前端/外壳解绑, build 标识统一, 外壳版本展示
Docker Build and Push / build-image (push) Successful in 1m5s
- check-version: 分组校验 (前端 package.json / 外壳 tauri.conf+Cargo),
  两组不再要求相等; 分支前缀校验只针对前端版本
- build-ota: build_id 改为 YYYYMMDDHHmmss (北京时间, 与前端 BUILD_ID
  同格式); sequence 保持毫秒仅用于判新
- 我的页: 当前版本恢复 v0.2.0 · build <原始BUILD_ID>; 新版本附 OTA
  build_id; 底部替换为外壳版本 (Tauri getVersion, Web 端 —)
- README: 合并遗留 readme 全部内容并按决议重写版本管理章节;
  新增 CHANGELOG.md (PATCH 仅明确提出时自增)
2026-10-25 21:28:06 +08:00
jif2.zhang 06aa48f6ad docs: 版本方案 (V0.2) 整理稿 —— 版本构成/分支映射/OTA 口径/PATCH 记录/展示修复清单, 含待确认问题 A-E
Docker Build and Push / build-image (push) Successful in 1m7s
2026-10-25 20:46:11 +08:00
jif2.zhang 6bd39aeed2 feat(V0.2): 看板列内纵向滚动加固 + 滚动时右缘滚动条 (方案 B)
Docker Build and Push / build-image (push) Successful in 1m6s
- 列体外包 .bcol-main (relative): 叠加自绘细滚动条, 滚动时出现、
  停止约 700ms 后淡出, 宽 3px 不占卡片空间
- bcol-body 补 -webkit-overflow-scrolling/overscroll-behavior,
  高度链显式化 (height:100%), 修真机列内滚不动的问题
- 列头保持固定不随滚动
2026-10-25 18:57:35 +08:00
jif2.zhang fd66c529c2 fix(V0.2): 智能截断去尾部标点; 看板左列收窄; 项目头像三处统一
Docker Build and Push / build-image (push) Successful in 1m7s
- splitTitle: 截断后用 \p{P} 去掉标题尾部连续分隔符 (原字符类重组有
  转义坑, 换 Unicode 属性类)
- 看板卡片左列 (状态点+⋯) 收窄至 14px 并负外距悬进卡片内边距
- 项目头像统一: 新增 .pavatar 基类与 projectIcon.colorOfProject,
  项目管理预览改用同配色/同圆角/居中首字, 修复灰底与文字歪斜
2026-10-25 18:38:16 +08:00
jif2.zhang cee21a39d9 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); 项目列表/最近项目/管理页图标位
  显示图片, 保持原尺寸与圆角; 可恢复默认首字色块
2026-10-25 12:02:29 +08:00
jif2.zhang e3ac00a641 fix(V0.2): OTA 发布说明改为 commit message, sha 单独展示; 版本附构建时间
Docker Build and Push / build-image (push) Successful in 1m2s
- CI: notes 取 git log -1 的 commit message (标题+正文, 截断 400 字),
  commit sha 经 --commit 写入 manifest (不再把裸 sha 塞进发布说明)
- build-ota: 新增 --commit 参数; latest.json 增加 commit 字段
- 服务端 /ota/check 与 /manifest-web 透传 commit 与 sequence
- 我的页: 当前版本/新版本后附 seq 时间戳 (MM-dd HH:mm),
  发布说明下方新增「提交」行显示短 sha
2026-10-25 11:56:04 +08:00
jif2.zhang 74e1e7dd13 feat(V0.2): 标题30字+智能拆分 / 时间标记 MM-dd / 时间词前缀 (T-TK-14~16)
Docker Build and Push / build-image (push) Successful in 1m25s
- 标题上限收紧至 30 字 (服务端校验+详情编辑框); 快速添加输入框
  放宽到 200 字: 超长时在 30 字内分隔符处截断为标题, 完整原文进描述
- Task.markDate (DateTime, 迁移 20261025120000): 详情页 DatePicker
  选择/清除, 列表行与看板卡显示 MM-dd 小标签
- 快速添加时间词前缀: 今天/明天/后天/本周/下周/本月/下月 开头
  (后跟分隔符) 自动设为时间标记并移出标题; 本周=本周日, 本月=月末
- 需求/功能/数据库设计文档同步更新 T-TK-14~16 与 Task 表字段
2026-10-25 11:47:44 +08:00
jif2.zhang fd27242e4e fix(V0.2): 全局禁用非编辑框文字选中 + 标题类文本溢出省略
Docker Build and Push / build-image (push) Successful in 1m6s
- * 级 user-select/touch-callout 禁用, input/textarea/contenteditable 放行
- 项目列表标题、项目管理导航标题、看板列名: 单行省略
- 弹层 sheet-title 限两行截断, sheet-sub 单行省略 (任务详情 200 字标题
  不再撑爆弹层头部)
2026-10-25 10:41:29 +08:00
jif2.zhang 20cc1ccde9 feat(V0.2): 列表/看板负责人改为头像 (姓氏首字+按名稳定配色)
Docker Build and Push / build-image (push) Successful in 59s
2026-10-25 03:04:15 +08:00
jif2.zhang 9401bd2b3d refactor(V0.2): 列表行等高 (无标签保留元信息行); 看板类型标签与负责人同行
Docker Build and Push / build-image (push) Successful in 1m1s
2026-10-25 02:59:52 +08:00
jif2.zhang fb9e2350b3 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紫/优化橙, 自定义类型灰)
2026-10-25 02:53:25 +08:00
jif2.zhang 2e6cc986a0 refactor(V0.2): 列表主行去掉状态圆点, 元信息行仅在有成员时显示
Docker Build and Push / build-image (push) Successful in 1m1s
2026-10-25 02:44:03 +08:00
jif2.zhang d20837f9f1 refactor(V0.2): 看板 ⋯ 沉到左下角; 列表负责人右下角, 去掉状态文字
Docker Build and Push / build-image (push) Successful in 59s
- 看板卡片左列改为上下撑满: 状态点在上, ⋯ 落到卡片左下角
- 列表行右列改为上下撑满: ⋯ 在右上, 负责人落到右下角
- 列表行第二行不再显示未开始/执行中/完成小字, 只留状态点与成员
2026-10-25 02:40:02 +08:00
jif2.zhang c0b55277a4 fix(V0.2): 列表组内排序乐观更新未重排数组, 松手后界面不动
Docker Build and Push / build-image (push) Successful in 1m0s
列表分组渲染按 tasks 数组顺序, reorderTask 此前只给任务打新
sortOrder 字段而保持原数组顺序 —— 松手后界面无任何变化, 看起来
就是组内无法排序 (数据其实已提交)。改为直接按新顺序重建数组,
不在分组内的任务 (孤儿) 追加在尾部。
2026-10-25 02:37:39 +08:00
jif2.zhang 49037371f8 refactor(V0.2): 看板卡片左列布局 / 列表负责人右移 / 把手再收窄
Docker Build and Push / build-image (push) Successful in 1m0s
- 看板卡片: 状态点与 ⋯ 竖排移到卡片左侧, 负责人+成员靠右, 标题独占中间
- 列表行: 负责人从第二行元信息移到行右侧 (⋯ 左边)
- ⠿ 把手: 宽度收到约 10px, 负外距悬进卡片内边距, 基本不占横向空间
2026-10-25 02:32:49 +08:00
jif2.zhang 2fa41c774b fix(V0.2): 拖动浮层残留蓝色背景 —— 类名与遗留 .drag-ghost 规则冲突
Docker Build and Push / build-image (push) Successful in 1m3s
globals.css 里有一条无人使用的旧 .drag-ghost 规则 (蓝色气泡,
max-width 180px, 看板早期方案遗留), 排在新增规则之后同特异性胜出,
克隆卡片容器被套上蓝色背景并被压缩到 180px 宽, 即真机上手下面的
蓝色 div。删除遗留规则; 新规则显式清零背景/内边距并禁用
tap-highlight/user-select (克隆脱离 .mv-view/.task-content 祖先后
需自带防选中)。CDP 实测拖动中容器背景已透明、宽度正常。
2026-10-25 02:28:09 +08:00
jif2.zhang 1673cbdb7d refactor(V0.2): 拖动交互收紧 —— 仅把手触发 / 缩小把手 / 去多余元素 / 打卡跨组
Docker Build and Push / build-image (push) Successful in 1m3s
- 打卡与列表: 去掉卡片整体长按拖动路径, 只有 ⠿ 把手可拖; 把手缩小
- 列表行去掉跟动的蓝色目标列徽标 (drag-pill), 占位/克隆浮层承担全部反馈
- 打卡支持跨组拖动: 落到其他周期组的目标卡 = 改周期 + 落位一次完成
  (updateHabit period + reorder), 组内排序不变
- 看板: 去掉 ⠿ 把手, 恢复长按拖动
2026-10-25 02:19:03 +08:00
jif2.zhang 5066007d9d feat(V0.2): 克隆卡片跟手浮层 + 列表组内排序 + 把手统一移到最左
Docker Build and Push / build-image (push) Successful in 1m1s
- 浮层改为激活时克隆原卡片 (DOM clone, 淡化+投影) 挂 body 顶层,
  移动直接改 transform —— 替代蓝色信息条, 所见即所拖
- 任务列表支持组内排序: 拖到本组某行上/下半显示插入指示, 松手提交
  POST /projects/:id/tasks/reorder (顶层任务按展平顺序重写 sortOrder);
  拖到其他分组仍为换列
- ⠿ 把手统一移到卡片最左: 打卡 / 列表任务行 / 看板卡片 (看板新增把手
  即按即拖路径, 与列表同款 touchstart preventDefault 双保险)
- useColumnDrag onDrop 经 ref 桥接防陈旧闭包
2026-10-25 02:07:58 +08:00
jif2.zhang 9a8313173d fix(V0.2): 浮层 Portal 修复被遮挡 + 列表落点改为手指所在分组
Docker Build and Push / build-image (push) Successful in 1m1s
- 打卡/任务浮层 createPortal 挂 document.body: 页签滑动容器 transform
  破坏 position:fixed 包含块, 浮层被压进卡片流只能看到边缘
- 任务列表落点: 弃用 80px/列步进换算 (视觉位置与换算不一致, 落点随机),
  改为 elementFromPoint 命中 [data-column-id] 分组 —— 手指在哪个分组
  松手就落到哪, 与看板行为一致; 划出分组时保持上一目标
2026-10-25 01:51:17 +08:00
jif2.zhang 83cc218c5e feat(V0.2): 拖动跟手浮层 —— 半透明副本随指针, 原位虚线占位
Docker Build and Push / build-image (push) Successful in 1m5s
- useRowDrag/useHabitDrag 暴露 ghostRef, 拖动激活与移动时直接改
  transform (绕过 React 重渲染, 保证跟手流畅)
- 打卡浮层带颜色点 + 名称; 任务列表浮层带任务名 + 实时目标列名
- 原位卡片降为低透明度虚线占位, 落点指示不变
2026-10-25 01:42:29 +08:00
jif2.zhang 215263bf2f fix(V0.2): 打卡排序闭包陈旧 + 把手拖动双保险
Docker Build and Push / build-image (push) Successful in 1m1s
- useHabitDrag: onDrop 经 ref 桥接实时闭包 —— bind/bindHandle 空依赖
  useCallback 固化了首次渲染(groups=[] 数据未加载)的落位函数, 松手
  静默早退, 顺序永远不变
- 把手路径挂非 passive touchstart preventDefault: 规范上禁止浏览器对
  整个触摸的默认处理 (含滚动), 与 touch-action:none 双保险
- 把手触区放大 (36px 高), 降低按到行体触发不可靠长按路径的概率
2026-10-25 01:31:27 +08:00
jif2.zhang 2725f00f68 fix(V0.2): 拖动可靠性重做 —— 把手入口 + 打卡排序接入实际渲染视图
Docker Build and Push / build-image (push) Successful in 1m1s
问题定位:
- 打卡页实际渲染的是 MergedView (CheckinPage 路由), 上次改的 HabitView
  是未使用的旧组件, 打包时被 tree-shake, 线上自然无任何效果
- 任务列表长按抬起后一动即脱手: touch-action:pan-y 下手指出现纵向分量,
  WebView/渲染器直接把触摸判给滚动并 pointercancel, touchmove preventDefault
  拦不住已决定的滚动 (看板可用只因该模式下页面无纵向可滚祖先)

修复:
- 新增 ⠿ 拖动把手 (touch-action:none): 浏览器按规范完全不接管该触摸,
  按下立即拖动, CDP 触摸仿真验证: 垂直拖动穿过可滚列表正常落点,
  跨组(每天/每周/每月)正确拒绝; 任务行把手拖动换列, 打卡卡片把手组内排序
- useRowDrag/useHabitDrag 抽出 armListeners, 新增 bindHandle 立即激活路径
- MergedView: 组内排序改按 sortOrder (服务端已返回), 拖动落位乐观更新 +
  POST /checkin/habits/reorder, 失败回滚; 打卡点击加拖动余波保护
- 长按路径保留为补充入口 (不可滚场景仍可用)
2026-10-25 01:21:42 +08:00
jif2.zhang b1c1b16e66 ci: minisign 静态包混多平台二进制, 试运行挑可用者, 失败回退 apt
Docker Build and Push / build-image (push) Successful in 3m31s
2026-10-25 00:56:35 +08:00
jif2.zhang 51256335ba ci: 优化构建速度与资源消耗
Docker Build and Push / build-image (push) Failing after 39s
- docker-build: 停用 docker system prune --volumes (保住 build 层缓存), 改为 image prune -f
- 新增 .dockerignore, node_modules/.git/src-tauri 等不再进 build context
- 前端只构建一次: CI 构建 dist 供 OTA 与镜像复用 (PREBUILT_DIST 构建参数)
- Dockerfile: npm install → npm ci + BuildKit cache mount
- setup-node 开启 npm 缓存; master/android-* 加 concurrency 取消旧 run
- android: 只构建 aarch64; tauri target 缓存 key 按 Cargo.lock hash
- minisign 改为静态二进制下载, 去掉 apt-get
2026-10-25 00:48:50 +08:00
jif2.zhang 20a5105c23 refactor(V0.2): 详情页精简 + 列表行样式调整
Docker Build and Push / build-image (push) Successful in 4m20s
- 任务详情: 移除底部「拷贝到其他项目 / 删除任务」按钮 (⋯ 菜单仍保留入口), 清理相关死代码
- 列表子任务: 改为与普通任务同构的两行布局 (标题 + 左侧状态点/状态文字, 字体略小)
- 列表任务卡片第二行不再显示看板分组标签
2026-10-25 00:23:01 +08:00
jif2.zhang 9467d4c242 feat(V0.2): 列表拖动修复 + 打卡项组内拖动排序
- 任务列表/看板拖动: 激活后用非 passive touchmove preventDefault 拦截浏览器滚动接管, 修复列表长按抬起后 pointercancel 导致无法真正拖动
- 打卡: 列表按周期分组展示(每天/每周/每月/每年), 长按拖动组内排序(上下落点指示), 新增 POST /checkin/habits/reorder 重写 sortOrder; 新建项排到末尾
- 打卡卡片加 touch-action/user-select 防长按误触; 拖动结束 350ms 内抑制点击余波
2026-10-25 00:06:44 +08:00
jif2.zhang d6ca7573f3 fix(V0.2): 三轮反馈 5 项 —— 回滚键盘方案 / 列表卡片拖动 / 看板防误触 / 横滑整屏 / 详情页恢复
Docker Build and Push / build-image (push) Successful in 4m9s
1. 回滚键盘遮挡统一方案 (真机测试不通过, 需求搁置): 恢复 TaskDetail/
   UserPicker/CopyTaskPopup/ProjectManage 与 useKeyboardInset 到 9fea1a5^,
   删除 useKeyboardInsetWatcher / .kb-safe / interactive-widget=resizes-content
2. 任务详情页样式随 1 一并恢复提交前状态 (含底部拷贝/删除按钮)
3. 列表视图换列改为卡片拖动: 新 useRowDrag (长按 400ms 行抬起, 左右
   80px/列步进, 行尾徽标显示目标列, 松手落列), 移除长按 ActionSheet
   —— 旧长按与复选框/行点击互相误触, 抬手合成 click 落在控件上触发状态切换
4. 看板拖动防误触: 任务区禁长按文字选择与系统菜单 (输入框除外);
   pointercancel 只放弃不提交; 拖动结束 350ms 内抑制 click 误开详情;
   状态点/⋯/子任务行 pointerdown 不冒泡, 不发起拖动
5. 看板横滑扩展到整屏: .page-transition 补 height:100% 打通
   app-main → page-with-navbar 百分比链, board-wrap 撑满剩余高度

已验证: kb-safe/Watcher/onLongPress 残留引用清零, 逐文件 diff 审阅通过;
本机无 Node 运行时, 未跑 vite build
2026-10-24 23:24:31 +08:00
jif2.zhang 9fea1a5a3a fix(V0.2): 二轮评审 6 项 —— BUILD_ID 格式 / 菜单与详情精简 / 拖动重做 / 键盘统一方案
Docker Build and Push / build-image (push) Successful in 4m5s
1. BUILD_ID 改为 yyyyMMddHHmmss (去掉中间点), 仍 UTC+8
2. 任务 ⋯ 菜单去掉顶部任务名标题
3. 任务详情去掉底部「拷贝到其他项目」「删除任务」按钮 (⋯ 菜单已有)
4+6. 键盘遮挡统一方案 (重点设计 §7.2):
   - index.html 加 interactive-widget=resizes-content
   - App 级 useKeyboardInsetWatcher 写 --kb-inset (visualViewport+window 双源)
   - 底部弹层统一 .kb-safe 类 (安全区+20px+键盘插入量, dvh 收缩+内部滚动)
   - TaskDetail/UserPicker/CopyTaskPopup/信息块弹层全部迁移, 删除 per-component hook
   - 信息块 textarea 补 focus scrollIntoView 兜底
5. 拖动方案重做 (重点设计 §7.1):
   - 新 useColumnDrag: Pointer Events + setPointerCapture, 长按400ms原位抬起,
     elementFromPoint 高亮目标列, 边缘 rAF 自动横滚; 移除手指跟随浮层(任务名)
   - 列表行长按 500ms → 「移动到列」ActionSheet (不做自由拖动)
   - 移除「拖到卡片转子任务」误触路径, 统一走详情页层级区
   - 删除旧 useLongPressDrag

已验证: 99 文件语法 0 错误、导入 0 缺失
2026-10-24 22:15:52 +08:00
jif2.zhang 506db0795b feat(V0.2): 任务操作菜单 / 状态指示 / 移动与转子任务 / 移除扩展信息
Docker Build and Push / build-image (push) Successful in 4m13s
1. 任务 ⋯ 菜单 (列表行与看板卡片): 编辑 / 拷贝到其他项目 / 删除
   (antd-mobile ActionSheet, 带任务名标题; 拷贝抽出为 CopyTaskPopup 复用)
2. 点击任务非按钮区域 = 打开编辑页 (原本即如此, ⋯ 不再误触为编辑)
3. 修复状态选择器堆成三行: 此前 .seg 只有 .pv-head 作用域样式,
   详情弹层裸用导致纵向堆叠; 新增通用 .seg 分段样式, 当前项高亮点按即切
4. 移除任务的扩展信息 UI (T-TK-04~07 标注已取消, 决策 35):
   ExtrasCard 组件删除, DB extras 字段保留不再使用;
   项目相关长文本由项目信息块 (T-PJ-13) 承载
5. 任务移动入口: 详情页新增「看板列」ActionSheet 换列(联动裁决不变)
   与「层级」区(转为子任务=选父任务 / 转为顶层), 覆盖无法拖拽的场景
6. 列表页移除「+ 子任务」入口: 添加子任务只在详情页, 或经转子任务

已验证: 99 文件语法 0 错误、导入 0 缺失、文档 149 条/决策 35 连续
2026-10-24 21:51:26 +08:00
jif2.zhang b71ceca3f2 fix(V0.2): BUILD_ID 时区 / 新建弹框残留 / 项目信息块
Docker Build and Push / build-image (push) Successful in 4m19s
1. BUILD_ID 改用 UTC+8 生成: CI runner 是 UTC 时区, 原来取本地时间会错位;
   统一偏移 +8h 后按 UTC 读取 (vite.config.js makeBuildId)

2. 修复「我的项目」页反复弹新建框: createSignal 一次性消费,
   ProjectList 处理后回调清零 (此前 TaskPage 状态在 /task 与 /task/list
   间保留, 信号残留导致每次进入都触发)

3. 新增项目信息块 (T-PJ-13):
   - Project.notes Json ([{title,content}], <=50 块 / 标题<=50 字 / 内容<=20000 字)
   - 迁移 20261024130000: 加列(NULL)->回填'[]'->收紧 NOT NULL, 存量行安全
   - GET 详情返回 notes; PUT 接受 notes 整体替换
   - 项目管理新增「信息块」分区: 列表预览 + 底部弹层独立编辑(标题+多行
     textarea+删除), 键盘弹出复用 useKeyboardInset 抬升
   - 文档: 需求 T-PJ-13 (149 条) + 功能设计对应行

已验证: 109 文件语法 0 错误、文档 149/149 覆盖
2026-10-24 21:37:05 +08:00
jif2.zhang 1fd7522fa6 fix(V0.2): 任务模块 4 个 bug —— 覆盖层安全区/返回键/项目列表排序/键盘遮挡
Docker Build and Push / build-image (push) Successful in 4m17s
1. 项目管理等 cs-page 覆盖层与系统状态栏重合:
   .cs-page 补 padding-top: var(--safe-top) (复用 main.jsx 实测校准的变量)

2. 项目管理按返回键跑到上一个 Tab:
   新增 useOverlayBack —— 覆盖层打开时 pushState 哨兵, 返回键先关覆盖层
   应用于 项目管理(内层视图先回主区) 与 任务详情弹层

3. 更多项目页:
   - 头部补「+ 新建」入口
   - 项目列表支持长按拖动排序(纵向), 顺序存设备端, 与首屏最近项目共用 recentOrder
   - 顺带修复首屏 RecentProjects 拖动排序的闭包缺陷(监听器读到旧下标, 首次移动
     会 splice(-1)); 两处均改为 ref 取当前下标

4. 任务详情输入子任务被键盘遮挡:
   新增 useKeyboardInset (visualViewport 差值), 键盘弹出时抬升弹层内容并收缩
   maxHeight; 输入框聚焦后再 scrollIntoView 到可视区中部 (双保险)

已验证: 99 文件语法 0 错误、相对导入 0 缺失
2026-10-24 21:09:19 +08:00
jif2.zhang 0cdbfb434f feat(V0.2): 任务模块界面调整 —— 首屏/项目管理/底部安全距离
Docker Build and Push / build-image (push) Successful in 4m8s
按 2026-10-24 评审的 5 条调整实现 (需求 T-VW-08~10 / T-PJ-11/12 / T-UI-11):

首屏 (T-VW-08/09):
- /task 改为「上=最近项目条(3 个+更多入口), 下=当前项目任务管理」
- 完整项目列表迁至 /task/list, 从「更多项目」进入; /task/:pid 保留供深链

最近项目排序 (T-VW-10):
- 卡片长按 300ms 拖动换位, 结果存设备端 prefs.recentOrder
- 顺序 = 手动排序 > 最近访问(recentIds) > 列表序, 归档项目不展示

项目管理 (T-PJ-11/12):
- 新增 ProjectManage: 成员 / 看板列 / 项目信息 三分区统一入口
- 项目信息含 改名 / 归档切换 / 删除(个人项目隐藏) / 退出(仅创建人)
- 项目页头部只留「项目管理 + 新增」, 移除散置的成员/列设置按钮

底部安全距离 (T-UI-11):
- 任务详情 / 人员选择 / 拷贝弹层 padding-bottom = 安全区 + 20px
- 小屏下弹层 maxHeight + 内部滚动, 底部按钮完整可见

已验证: 97 文件语法 0 错误、相对导入 0 缺失
2026-10-24 20:32:44 +08:00
jif2.zhang 6153b9db99 fix(V0.2): 清除 schema.prisma 中段 BOM, 修复 CI prisma generate 失败
Docker Build and Push / build-image (push) Successful in 4m24s
追加任务模块模型时临时文件带入 U+FEFF, Prisma 解析在 383 行报 Validation Error (run 200)
2026-10-24 17:43:30 +08:00
jif2.zhang 6c9cd3fd99 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 缺失、领域逻辑用例全部通过
2026-10-24 11:21:16 +08:00
jif2.zhang 42acf72f1e 合并 dev-0.2 到 master: 修复打卡按钮点不动
Docker Build and Push / build-image (push) Successful in 4m9s
2026-10-24 09:53:14 +08:00
jif2.zhang e57b7902be 修复打卡页所有打卡/再打一次按钮点不动
回归原因: 合并视图引入 doCheck 时加了 `if (!item.canCheck || isFuture) return`.
但 canCheck 字段**只有 /day 接口返回**, 本视图数据取自 /habits, 该接口
不返回 canCheck → item.canCheck === undefined → !undefined === true
→ 每个按钮点击都在第一行直接 return, 表现为"点不动".

修复: doCheck 只按 isFuture 拦截, 与后端 POST /habits/:id/check 的校验
口径一致 (后端只拒绝未来日期与超过补打窗口的日期).

影响范围: 打卡按钮、再打一次按钮、环形点击 (三处共用 doCheck).
2026-10-24 09:53:08 +08:00
jif2.zhang 6a48b7311b 合并 dev-0.2 到 master: 打卡页新建按钮调整
Docker Build and Push / build-image (push) Successful in 4m4s
2026-10-24 08:40:15 +08:00
jif2.zhang 7e229ecc84 打卡页: 「点环即打卡」提示换成新建按钮, 去掉底部歪掉的按钮
问题:
- 当日栏右侧的「点环即打卡」是纯文字提示, 看着像可点但实际无交互, 容易误导
- 分组列表底部另有一个「+ 新建打卡项」按钮, 带内联 margin,
  与卡片左右边距不一致, 视觉上是歪的

改动:
- 当日栏右侧改为「+ 新建」按钮 (antd-mobile Button, mini) 右对齐,
  复用原有 openCreate, 一个入口完成新建
- 删除底部「+ 新建打卡项」按钮及其 .mv-add-wrap 样式
- .mv-daybar 移除废弃的 .sum 样式, 新增 .mv-new-btn (margin-left:auto 右对齐)

空态「创建第一个打卡项」保留 (无任何打卡项时的引导)。
2026-10-24 08:40:09 +08:00
jif2.zhang 3250b94bc6 合并 dev-0.2 到 master: 打卡与日历合并视图 (按天/周/月分组)
Docker Build and Push / build-image (push) Successful in 4m1s
2026-10-24 08:30:53 +08:00
jif2.zhang 330e6585d9 feat(V0.2): 打卡与日历合并为单视图, 打卡内容按 每天/每周/每月 分组
实现设计文档 §11.5「日历与打卡合并」待确认项 (界面设计.html 2.12 ②).

结构:
- CheckinPage 由 3 个 tab 收敛为 2 个: 打卡(含日历) / 清单
- 新增 MergedView.jsx: 上为月历, 下为当日打卡项
  (原 CalendarView + HabitView 的展示/交互合并到一个组件)

按规格落地:
- 月历: 月份切换 + 回到今天; 去掉「昨天/今天/明天」分段; 日期格 38→31px
- 分组: 每天 → 每周 → 每月, 组标题左侧 3px 主色竖条 + 右侧项数; 去掉「每年」分组
  (若存在历史 year 项则归入"其它周期"分组, 避免数据凭空消失)
- 卡片紧凑化: 内边距 12→8px, 环形 58→42px (环宽 6→5), 间距 10→7px
- 操作: 撤销 / 编辑 / 归档 由卡片底部三个文字链接收进「⋯」底部面板
- 联动: 点日期即切换当日数据; 未来日期只读, 按钮灰显「计划」
- 组内仍按「未完成在前、已完成在后」排序 (F-CK-16)

样式: globals.css 新增 .mv-* 段 (月历/分组/紧凑卡片/操作面板), 数值与设计稿一致.

服务端无需改动: habits 接口已返回 period/periodLabel/expectedPerDay/canCheck 等字段.
2026-10-24 08:30:48 +08:00
jif2.zhang 99cedce4ed 修复「我」页顶部安全区与蓝色渐变头部割裂
现象: 顶部安全区修好后, 其他页面正常, 但「我」页顶部多出一条白色/色块,
把原本从屏幕顶端开始的蓝色渐变隔断.

原因: .app-safe-top 是独立占位元素, 固定使用页面底色.
「我」页头部 me-profile 是通栏蓝色渐变 (无 PageHeader), 安全区夹在中间
就形成一条异色带, 视觉上把蓝色切成两段.

修复:
- MePage 挂载时给 body 加 me-safe-top 标记, 卸载时移除
- 该标记下把 .app-safe-top 高度归零, 改由 .me-profile 的
  padding-top: calc(24px + var(--safe-top)) 吸收状态栏高度
- 这样蓝色渐变直接从屏幕最顶端开始, 是一整块连续色域, 无接缝,
  同时内容仍正确避开电量/信号栏

其他页面不受影响 (无该 body 标记, 安全区照常占位).
2026-10-24 08:15:09 +08:00
jif2.zhang a150706cc4 修复「我」页顶部安全区与蓝色渐变头部割裂
Docker Build and Push / build-image (push) Successful in 4m3s
现象: 顶部安全区修好后, 其他页面正常, 但「我」页顶部多出一条白色/色块,
把原本从屏幕顶端开始的蓝色渐变隔断.

原因: .app-safe-top 是独立占位元素, 固定使用页面底色.
「我」页头部 me-profile 是通栏蓝色渐变 (无 PageHeader), 安全区夹在中间
就形成一条异色带, 视觉上把蓝色切成两段.

修复:
- MePage 挂载时给 body 加 me-safe-top 标记, 卸载时移除
- 该标记下把 .app-safe-top 高度归零, 改由 .me-profile 的
  padding-top: calc(24px + var(--safe-top)) 吸收状态栏高度
- 这样蓝色渐变直接从屏幕最顶端开始, 是一整块连续色域, 无接缝,
  同时内容仍正确避开电量/信号栏

其他页面不受影响 (无该 body 标记, 安全区照常占位).
2026-10-24 08:15:05 +08:00
jif2.zhang a915a08f4d 修复 OTA 后顶部内容顶到状态栏 (未让出电量/信号栏)
现象: 直装 APK 时头部正常让开状态栏; 经 OTA 升级到 V0.2 前端后,
页面从屏幕最顶部开始, 与电量/信号栏重叠.

根因: 顶部让位一直只依赖 antd-mobile 的 <SafeArea position="top" />,
它只是一个空 div, 高度完全来自 env(safe-area-inset-top). 而 Android
WebView (Tauri) 下该变量常返回 0.
旧版每页顶部都有 45px 的 antd-mobile <NavBar>, 视觉上兜住了状态栏,
掩盖了 inset 失效; V0.2 把 NavBar 换成 23px 的 PageHeader
(「我」页甚至无头部), 兜底消失后问题暴露. 与 OTA 机制本身无关.

修复:
- MobileShell: <SafeArea> 换成 .app-safe-top, 高度由 --safe-top 控制
- main.jsx: 新增 calibrateSafeTop(), 用临时元素测 env(safe-area-inset-top),
  并与 screen.height - visualViewport.height 交叉校验, 取较大值写入
  --safe-top; 两者都不可用时保底 24px; 监听旋转/视口变化重算
- globals.css: --safe-top 保留 env() 表达式, 新增 .app-safe-top 样式

这样无论 WebView 是否上报 inset, 顶部都能正确让位.
2026-10-24 08:05:19 +08:00
jif2.zhang 2ea0da758f 修复 OTA 后顶部内容顶到状态栏 (未让出电量/信号栏)
Docker Build and Push / build-image (push) Successful in 4m2s
现象: 直装 APK 时头部正常让开状态栏; 经 OTA 升级到 V0.2 前端后,
页面从屏幕最顶部开始, 与电量/信号栏重叠.

根因: 顶部让位一直只依赖 antd-mobile 的 <SafeArea position="top" />,
它只是一个空 div, 高度完全来自 env(safe-area-inset-top). 而 Android
WebView (Tauri) 下该变量常返回 0.
旧版每页顶部都有 45px 的 antd-mobile <NavBar>, 视觉上兜住了状态栏,
掩盖了 inset 失效; V0.2 把 NavBar 换成 23px 的 PageHeader
(「我」页甚至无头部), 兜底消失后问题暴露. 与 OTA 机制本身无关.

修复:
- MobileShell: <SafeArea> 换成 .app-safe-top, 高度由 --safe-top 控制
- main.jsx: 新增 calibrateSafeTop(), 用临时元素测 env(safe-area-inset-top),
  并与 screen.height - visualViewport.height 交叉校验, 取较大值写入
  --safe-top; 两者都不可用时保底 24px; 监听旋转/视口变化重算
- globals.css: --safe-top 保留 env() 表达式, 新增 .app-safe-top 样式

这样无论 WebView 是否上报 inset, 顶部都能正确让位.
2026-10-24 08:05:15 +08:00
jif2.zhang 2f55865092 合并 dev-0.2 到 master: V0.2 功能 + 米家修复 + 分支策略调整
Docker Build and Push / build-image (push) Successful in 8m0s
2026-10-24 07:36:58 +08:00
jif2.zhang 5e6ea552d1 调整分支策略: 仅 master 部署, 取消 dev-* 自动发布
分支规则 (写入 readme):
- master   主分支, 唯一部署出口, push 即发布生产
- dev-*    开发集成分支, 只跑 CI 校验, 不部署; 上线先合到 master
- tmp-*    临时分支, 针对单个问题, 合到 dev-* 后删除
- android-* 仅触发 APK 外壳构建, 构建前须与 master 同步

CI 变更:
- .gitea/workflows/docker-build.yml 触发分支收窄为 master
  此前 dev-* 与 master 共用同一套生产环境, 推送开发分支即直接发布,
  容易把半成品带上线, 现取消该触发
- 同步修正工作流内相关注释 (迁移时机, 版本校验范围)

文档变更:
- readme 新增「分支规则」章节: 职责表/流程图/CI 触发范围/变更说明
- readme 原「分支与 CI/CD」章节与新规则冲突, 已按新策略重写
  (dev-* 不再触发部署; 数据库迁移只在 master 发布时应用)
- 明确团队约定的 main 主分支在本仓库落地为 master
2026-10-24 07:36:53 +08:00
jif2.zhang a66ddb457a 修复扫码弹窗一闪而过
现象: 米家授权过期后, 扫码弹窗从底部弹出但瞬间消失, 看不到二维码.

三处缺陷:
1. 服务端 startQrLogin() 在已有流程运行时提前 return, 未清 done.
   上一轮成功残留的 done=true 会让前端第一次轮询就拿到
   {running:false, done:true}, 误判为扫码成功立即关窗.
   改为复用流程时显式返回 done:false.
2. 前端 AuthPopup 的成功/失败判定没有幂等保护, 且 onClose/onOk 是
   父组件每次渲染新建的函数. 父级轮询触发重渲染后, 回调身份变化
   会波及弹窗关闭路径. 改用 ref 持有最新回调 + settledRef 保证
   一轮流程只结算一次.
3. 弹窗遮罩绑定 onMaskClick=cancel, 手机端极易误触; 关闭遮罩点击,
   只允许显式点「取消」关闭.

注意: 前端需重新构建发布, 服务端需重启后生效.
2026-10-24 07:27:03 +08:00
jif2.zhang 3de002aae8 修复米家会话失效后不弹登录二维码
根因一: 过期检测形同虚设
- @zythum02/mijia-api 的 refreshToken() 在本地凭证字段齐全时直接返回成功,
  根本不发请求, 因此 checkAuth() 永远判定 ok, 过期后既不出横幅也不出扫码入口
- checkAuth() 改为真打一次 getHomesList() 验证 token; 成功缓存 5 分钟,
  失败只缓存 30 秒(便于网络恢复后自愈); 增加并发探测合并; 状态未变不写库
- getStatus() 以实时探测结果为准, DB 里的 status 仅在探测为 unknown 时兜底,
  避免残留的 ok 遮蔽已失效状态

根因二: 二维码图片 401 导致弹窗空白
- /api/mihome/reauthorize/qr-image 在 authRequired 之后, 而 <img src> 无法携带
  Authorization 头, 图片请求被拒, 用户看到的是空白/裂图
- 新增 fetchMihomeQrImage(): 带 JWT fetch 后转 blob URL 给 <img>, 并在卸载/换码时释放

其他修复
- EnvView 的 load 依赖 [status] 且成功回调又 setStatus, 造成 /status 无限重复请求;
  改为空依赖 + 函数式 setStatus; 首屏与重试走 ?force=1 强查
- 会话失效(非网络类错误)时自动弹出扫码窗, 每次挂载仅弹一次
- 扫码状态机新增 done 标记, 只有真正登录成功才算成功, 避免取消后误判
- 二维码 120s 超时自动续码(最多 2 次), 慢扫不再直接失败
- 取消后不再丢弃可能已成功的扫码结果
- scripts/mihome-login.mjs 适配 done 语义
- 同步更新设计文档 §5.2 / §5.4 / §6

注意: 前端需重新构建发布后生效。
2026-10-24 07:26:59 +08:00
jif2.zhang d1f36b3b8f 修复扫码弹窗一闪而过
Docker Build and Push / build-image (push) Successful in 4m5s
现象: 米家授权过期后, 扫码弹窗从底部弹出但瞬间消失, 看不到二维码.

三处缺陷:
1. 服务端 startQrLogin() 在已有流程运行时提前 return, 未清 done.
   上一轮成功残留的 done=true 会让前端第一次轮询就拿到
   {running:false, done:true}, 误判为扫码成功立即关窗.
   改为复用流程时显式返回 done:false.
2. 前端 AuthPopup 的成功/失败判定没有幂等保护, 且 onClose/onOk 是
   父组件每次渲染新建的函数. 父级轮询触发重渲染后, 回调身份变化
   会波及弹窗关闭路径. 改用 ref 持有最新回调 + settledRef 保证
   一轮流程只结算一次.
3. 弹窗遮罩绑定 onMaskClick=cancel, 手机端极易误触; 关闭遮罩点击,
   只允许显式点「取消」关闭.

注意: 前端需重新构建发布, 服务端需重启后生效.
2026-10-24 06:30:00 +08:00
jif2.zhang 95b9985e8b 修复米家会话失效后不弹登录二维码
Docker Build and Push / build-image (push) Successful in 5m46s
根因一: 过期检测形同虚设
- @zythum02/mijia-api 的 refreshToken() 在本地凭证字段齐全时直接返回成功,
  根本不发请求, 因此 checkAuth() 永远判定 ok, 过期后既不出横幅也不出扫码入口
- checkAuth() 改为真打一次 getHomesList() 验证 token; 成功缓存 5 分钟,
  失败只缓存 30 秒(便于网络恢复后自愈); 增加并发探测合并; 状态未变不写库
- getStatus() 以实时探测结果为准, DB 里的 status 仅在探测为 unknown 时兜底,
  避免残留的 ok 遮蔽已失效状态

根因二: 二维码图片 401 导致弹窗空白
- /api/mihome/reauthorize/qr-image 在 authRequired 之后, 而 <img src> 无法携带
  Authorization 头, 图片请求被拒, 用户看到的是空白/裂图
- 新增 fetchMihomeQrImage(): 带 JWT fetch 后转 blob URL 给 <img>, 并在卸载/换码时释放

其他修复
- EnvView 的 load 依赖 [status] 且成功回调又 setStatus, 造成 /status 无限重复请求;
  改为空依赖 + 函数式 setStatus; 首屏与重试走 ?force=1 强查
- 会话失效(非网络类错误)时自动弹出扫码窗, 每次挂载仅弹一次
- 扫码状态机新增 done 标记, 只有真正登录成功才算成功, 避免取消后误判
- 二维码 120s 超时自动续码(最多 2 次), 慢扫不再直接失败
- 取消后不再丢弃可能已成功的扫码结果
- scripts/mihome-login.mjs 适配 done 语义
- 同步更新设计文档 §5.2 / §5.4 / §6

注意: 前端需重新构建发布后生效。
2026-10-23 22:21:08 +08:00
jif2.zhang 7b4e59957b 修复容器内 news/oil 定时失效: 运行时镜像携带 scripts/ + axios 转生产依赖 + cron 脚本模块惰性加载降级
Docker Build and Push / build-image (push) Failing after 9m34s
2026-09-21 14:09:18 +08:00
jif2.zhang 1d69915cf3 米家调度独立模块注册, 避免被容器中无法加载的旧 cron.js 连带失效
Docker Build and Push / build-image (push) Successful in 4m36s
2026-09-21 11:52:24 +08:00
jif2.zhang 8e2c6ffa35 新增米家环境监控模块 (采集/聚合/历史/前端 EnvView) + CI 挂载米家凭证目录并自动应用迁移
Docker Build and Push / build-image (push) Successful in 6m54s
2026-09-21 11:42:58 +08:00
jif2.zhang 53f63e0986 新增 CI secrets 同步到注册中心的独立 workflow
Docker Build and Push / build-image (push) Successful in 10m57s
2026-09-20 20:32:54 +08:00