Commit Graph
195 Commits
Author SHA1 Message Date
jif2.zhang 5622e4b3d4 fix(打卡): 修复日历切上月看不到记录; 当日进度改按当天份额统计
Docker Build and Push / build-image (push) Successful in 1m40s
- date.js: addMonths 对 "YYYY-MM" 月粒度保持月粒度, 不再生成 "YYYY-MM-01"。
  旧逻辑使日历切上月时请求 month=2026-10-01, 服务端判为非法后静默回退本月,
  表现为上个月一片空白。
- MergedView: 「回到今天」同时把月份切回当前月; 日标题「已完成 x/y」改为
  按 items 的 dayDone 现算, 避免把同周期后续日期的打卡计入历史日期,
  并让打卡/撤销的乐观更新立即反映到标题。
- server /calendar: 兼容旧的 month=YYYY-MM-DD 请求并截回月份, 不再静默回退。
- server /habits: 回看历史日期时过滤当天尚未创建的打卡项, 与 /calendar 口径一致;
  summary.done 改用 dayDone (当天份额) 而非 completed (周期完成度)。

验证: Vite dev + 生产数据 (admin) 2026-10 显示 10 个环 / 完成率 32%,
10-22 的标题由错误的 3/14 修正为 1/14; 「回到今天」回到 2026-11 (14%)。
2026-11-02 13:54:59 +08:00
jif2.zhang afbb9bc603 feat(宏观): ifinance 分类动态挂载为宏观 tab, 报警迁入监控, 下线油价/本地经济数据/策略研究
Docker Build and Push / build-image (push) Successful in 2m37s
- 宏观只保留本地 新闻/经济文章, 外接 ifinance categories[] 动态成为 tab (纯前端直连, CORS/_headers, https)
- 报警从宏观迁到监控第 4 个 tab (保留 Alert 模块, 供未来新增报警源)
- 彻底删除油价/经济数据/策略研究: 前端组件+api、后端 apizero/data 路由、cron、fetchers、种子数据
- 新增迁移 DROP Indicator/IndicatorPoint/Strategy/OilPriceHistory; 重新生成 Prisma Client
- CSP 放开 *.honor3.com (含端口通配), 避免新增子域反复重装外壳
2026-10-30 17:17:10 +08:00
jif2.zhang 82c4ae8a84 fix(项目设置): 修复「隐藏的任务自动归档」提示成功但不生效
Docker Build and Push / build-image (push) Successful in 1m34s
现象: 项目设置 -> 归档设置 -> 隐藏的任务自动归档, 选完档位提示「已保存」,
重新打开仍是「永不」, 且不会产生任何归档。

根因 (读写两条路都断了, 缺一不可):
1. 读: projectSummary() 没有回传 autoArchive, 而 ProjectManage 读的是
   project.autoArchive -> 永远是 undefined -> 界面恒显示默认值「永不」;
2. 写: projectApi.update() 的字段白名单里没有 autoArchive 分支
   (只有 name/code/taskKinds/icon/archived/notes), 传进来直接被忽略,
   data 为空 -> 一条 SQL 都不执行 -> 但函数正常返回, 调用方照常弹「已保存」。

服务端一直是对的: powersync 上传分支处理了 autoArchive, REST 也有校验,
所以不是同步丢字段。

修复:
- projectSummary 增加 autoArchive: p.autoArchive || 'never';
- projectApi.update 增加 autoArchive 分支, 校验取值与 AUTO_ARCHIVE_OPTIONS 同口径。

验证 (真实 Windows 外壳, 临时暴露 API 直调被修改的函数):
- update({autoArchive:'3d'}) 返回 3d; 重新 list/detail 仍为 3d (已落库);
- 进项目设置, 该行显示「一周后 ›」(设成 1w 后), 不再恒为「永不」;
- 还原为 never 后界面同步回「永不」。
- 顺带确认「同样隐藏已完成」的列级设置 retention 读写都正常:
  Done 列 retention=3d, 服务端 26 条已完成中 9 条超 3 天,
  App 实际只返回 14 条 -> 过滤本身是生效的, 此前不生效的只有自动归档档位。
- 控制台无异常; 验证用的临时钩子已移除。
2026-10-28 18:32:40 +08:00
jif2.zhang c5fc328f2b feat(任务/打卡): 已归档页面按原型重做; 打卡日历完成度改 4 档配色
Docker Build and Push / build-image (push) Successful in 1m27s
一、已归档任务管理: 按评审通过的原型落地 (docs/V0.2/任务模块/已归档任务管理-原型.html)

- 去掉「任务类型」过滤: 类型是弱维度, 归档场景几乎不按它检索, 反而占掉一整行;
  类型标签仍在行内展示。
- 关键词输入框前加常驻标签「标题」, 框内占位改为「输入关键词」。
- 归档时间新增快捷项: 全部 / 本周 / 本月 / 本季度 / 自定义;
  选中后下方灰字回显实际区间 (本周=周一起算, 区间截至今天, 不跨未来);
  「自定义」才展开两个日期选择器。
- 补上「筛选」按钮 (带生效条件数徽标) 与「重置」: 条件先编辑, 点按钮统一提交。
  原实现改任一条件就即时重查, 连点会连发请求, 输关键词时列表会闪。
- 列表上方显示已应用条件标签 (可单独 ✕ 撤销) + 命中条数。
- 列表行重排: 标题独占一行, 元信息收成一行 (#编号 · 看板列 · 归档于日期),
  「恢复 / 删除」由右侧竖排改到底部右侧横排, 降低行高。
- 空状态区分「这个项目还没有归档任务」(提示去 ⋯ 菜单归档) 与
  「没有符合条件的归档任务」(建议放宽条件)。
- 修正日期边界: archivedList 的 from/to 原来直接拼 'T00:00:00Z',
  本地选的日期会偏移 8 小时, 当天凌晨的归档被漏掉; 改为按本地时区换算成 UTC 瞬时。

二、打卡日历完成度配色: 由 3 档改 4 档

    小半 (ratio < 0.5)  -> 红 #ff3141
    大半 (0.5 <= r < 1) -> 橘 #ff8f1f
    完成 (r = 1)        -> 蓝 #1677ff
    超额                -> 绿 #00b578

  注意服务端统计时把 actual 封顶在 expected (`Math.min(cnt, exp)`),
  所以 ratio 永远 <= 1,**超额只能靠 status === 'over' 判断**,不能看比例;
  DayRing 内新增 tierOf() 统一分级,图例同步改为四档。

验证 (真实 Windows 外壳 + CDP):
- 打卡页: 图例显示「小半/大半/完成/超额」, 计算样式分别为
  rgb(255,49,65) / rgb(255,143,31) / rgb(22,119,255) / rgb(0,181,120);
  当月实际渲染出 low=5 / high=1 / over=1。
- 已归档页: 筛选行标签为 标题/看板列/归档时间; 时间选项五项齐全;
  按钮为 重置/筛选; 点「本周」回显 2026-10-26 ~ 2026-10-28, 点「筛选」后
  徽标显示 1、条件标签可撤销、命中条数正确。
- 归档 → 已归档列表可见 → 恢复 全链路走通 (含上次修好的 TDZ 问题),
  服务端确认 archived 由 t 变回 f。
- 控制台无异常。
2026-10-28 10:19:17 +08:00
jif2.zhang 77e057c580 docs(任务): 已归档任务管理界面重设计原型 (待评审, 未改业务代码)
Docker Build and Push / build-image (push) Successful in 1m29s
按评审意见重做「已归档任务」全屏弹层的界面, 产出可交互原型:
docs/V0.2/任务模块/已归档任务管理-原型.html

四点改动:
1. 去掉「类型」过滤 —— 类型是弱维度, 归档场景几乎不按类型检索, 反而占掉一整行;
2. 关键词输入框前加常驻标签「标题」, 框内占位改为「输入关键词」;
3. 归档时间新增快捷预设: 全部 / 本周 / 本月 / 本季度 (+ 自定义才展开日期区间),
   选完在下方灰字回显实际区间, 避免"以为选的是整周";
4. 补上「筛选」按钮 —— 原版改任何条件都立即查询且没有确认动作; 改为条件填完一次性提交,
   按钮带生效条件数徽标, 另有「重置」。

附带改进:
- 列表上方显示已应用条件标签(可单独 × 撤销) + 命中条数;
- 列表行重排: 标题独占一行, 元信息收成一行(#编号 · 看板列 · 归档于日期),
  「恢复/删除」从右侧竖排改到底部右侧横排, 降低行高;
- 空状态区分「还没归档过」与「筛选无结果」, 分别给出下一步提示;
- 类型标签仍在行内展示, 只是不再作为筛选项。

原型为单文件 HTML (无外部依赖), 可交互: 点预设/筛选/恢复/删除均有反馈。
已用无头浏览器验证: 无 JS 错误, 本周预设算出 2026-10-26~2026-10-28, 筛选命中条数正确。

业务代码未改动, 等待评审确认后再落地。
2026-10-28 09:51:00 +08:00
jif2.zhang 75cabe8339 fix(任务): 修复归档/恢复归档报 "Cannot access 'a' before initialization"
根因: api/task.js 的 archive / unarchive 里写了 `const now = now()`。
同一函数作用域内的 `const now` 会遮蔽模块级的 now 函数, 而初始化表达式的右侧
在求值时该 const 正处于 TDZ, 于是抛 ReferenceError。
源码里报错信息是 "Cannot access 'now' before initialization",
经 vite 压缩后变量被重命名为单字母, 用户端看到的就是 "Cannt access 'a' before i"。

影响: 点「归档」确认后必然失败 (弹错误框); 恢复归档同理。删除/编辑不受影响。

修复: 局部变量改名为 ts, 并补注释避免后人再写回同名。

验证 (真实 Windows 外壳 + CDP 走 UI):
- 点任务行 ⋯ → 归档 → 确认: 无异常, 行从列表消失, 任务数减少;
- 服务端确认已落库: archived=t / archivedAt / archiveSource=manual;
- 测试数据已还原 (archived=f)。

顺带全仓搜索 `const X = X()` 自遮蔽写法, 仅这两处, 无其它同类隐患。
2026-10-28 09:45:43 +08:00
jif2.zhang 58879024a2 docs+feat(即时同步): 实测端到端 1~2s 达标; 补回滚开关; 订正两次错误排查结论
Docker Build and Push / build-image (push) Successful in 1m26s
一、结论订正 (第二次, 前两次均被测量方式误导)

初次把 ~14s 延迟归因于 nginx 未关 proxy_buffering —— 实测被推翻:
加了 proxy_buffering off / proxy_read_timeout 1h 并热重载, nginx -T 确认生效, 延迟毫无变化。
(该配置已回滚: advanced_config 清空、生效 conf 还原、nginx 已重载。保留它反而会让 OTA 大包
 下载失去缓冲保护, 属净负收益。)

随后把 ~15-30s 延迟归因于客户端 db.watch/渲染滞后 —— 同样被推翻:
错误在于测量方法, 用 CDP 反复读 document.body.innerText (长列表页开销大) 去轮询,
且把 ssh + docker exec 的 ~6s 开销算进了延迟。

改为**页面内自计时**后 (50ms 轮询本地库 + MutationObserver 观察 DOM, 各自记录 performance.now),
一次干净测量的结果:
- psql 命令总耗时 (ssh + docker exec + UPDATE): 2138ms
- 数据出现在客户端本地库: 2251ms  (≈ 命令返回后 113ms)
- 界面更新: 2580ms
- 同步数据到达 -> 渲染完成: 329ms

即端到端约 1~2s, 其中 UI 渲染只占 ~0.33s, useDbSignal 的表级 watch 工作正常,
无需改用 useQuery。服务端侧的 powersync 日志也一致 (checkpoint_complete 与改库同一秒,
stream_ms 达 42 分钟、close_reason: client closing stream, 长连接稳定)。

二、补回滚开关

文档验收标准里的"回滚开关"此前并未实现。useDbSignal 现在读取
localStorage['iboard_realtime'] === '0' 时完全不订阅, 退回手动刷新,
用于线上出问题时的快速止损 (重启应用生效)。

三、文档

§7.0 改为"端到端约 1~2s (达标)", 写入可复现的页面内自计时测量方法,
并留档两次被推翻的结论及各自错因, 避免后人重复踩坑。§6.2 验收标准同步更新。
2026-10-27 22:20:53 +08:00
jif2.zhang 96f4e09bd5 docs(即时同步): 订正延迟排查结论 —— 不是 nginx 缓冲, 瓶颈在客户端应用/渲染段
Docker Build and Push / build-image (push) Successful in 1m28s
上一版文档把 ~14s 延迟归因于 nginx 未关闭 proxy_buffering, 实测推翻了该判断:
- 已为 iboard.honor3.com 配置 proxy_buffering off / proxy_read_timeout 1h 并热重载,
  nginx -T 确认生效, 但端到端延迟无任何改善;
- powersync 服务日志 (docker logs -t): 改库与服务端 checkpoint_complete 几乎同一秒
  (13:46:53.738), 另一次约 6s —— 服务端推送很快;
- 同步流是长连接 (stream_ms 达 42 分钟, close_reason: client closing stream), 非频繁重连;
- 临时把 db 挂到 window.__psdb 轮询: 数据确实已写入客户端本地库, 但 DOM 更新明显滞后。

结论修正为: 瓶颈在客户端「同步数据应用 → db.watch 通知 → React 渲染」这一段,
延迟 15~30s 且波动 (1s/6s/17s/27s), 更像排队或重试退避。文档补充了下一步排查方向。

nginx 那组配置未回滚: 对长连接流式接口属合理配置, 且已验证不影响其它站点。
2026-10-27 21:54:20 +08:00
jif2.zhang fd4079c9c3 feat(任务): 即时同步 —— 订阅本地库变更, 跨端改动无需切页自动刷新
Docker Build and Push / build-image (push) Failing after 1m48s
现象: 多端同时打开同一项目时, 一端改完, 另一端必须切到别的页面再切回来才更新。

根因: 不是同步没到, 而是 UI 从未订阅本地库变化 ——
PowerSync 的下行推送 (PG 逻辑复制 → sync service → 客户端本地 SQLite) 本身正常,
但任务模块的读全是命令式 db().getAll() (api/task.js), 读完不再看;
lib/powersync/react.jsx 虽然导出了 useQuery/useStatus, 全项目一次都没用过;
TaskPage/ProjectView 只在 useEffect 里 load() 一次, 连 useRefreshOnVisible 都没接
(只有打卡与宏观页面在用)。「切面板能刷新」纯粹是因为组件重新挂载又 load 了一次。

实现 (docs/V0.2/离线编辑模块/即时同步方案.md, 方案 C):
- 新增 lib/powersync/useDbSignal.js: 用 db.watch() 的表级过滤 (tables) + 节流
  (throttleMs) + AbortSignal, 订阅本地库变更; 跳过订阅时的首次通知, 避免与
  挂载时的 load() 重复。
  (初版设计是手写 count/sum/max(updatedAt) 的「信号 SQL」, 实施时发现 SDK 原生
   支持 tables 过滤, 更可靠, 已改为表过滤并在文档中记录变更。)
- api/task.js 新增 TASK_TABLES / PROJECT_TABLES 常量 (表名须与客户端 schema 一致)。
- ProjectView: 订阅任务域 (Task/BoardColumn/TaskMember/TaskTag) → 重算;
  TaskPage: 订阅项目域 (Project/ProjectMember) → 重算。
- 不打断操作: BoardView/ListView 上报 onDragActiveChange, 拖拽期间收到变更只记
  pending, 松手后补一次刷新, 避免卡片在手指下跳位。
- 回前台兜底: 两页都接 useRefreshOnVisible (WebView 后台可能节流订阅回调)。

验证 (真实 Windows 外壳 + CDP, 服务端直接改库模拟另一端):
- 服务端改任务标题后, 页面在**无任何操作**的情况下自动更新 (三次复测均成功);
- 改回原标题后同样自动还原; 测试数据已恢复。

已知瓶颈 (不在 UI 层, 另见文档 §7.0):
- 实测端到端延迟约 13~14s, 未达 ≤1s 目标;
- CDP Network 观察客户端: 无 WebSocket, 仅 /sync/stream 长连接;
- NPM (baishe nginx-app-1, proxy_host/5.conf) 未关闭 proxy_buffering,
  流式响应被 nginx 缓冲后按批下发, 与观测到的固定批次延迟吻合;
- 修复属运维配置 (proxy_buffering off 等), 需单独评估后执行。
2026-10-27 20:57:05 +08:00
jif2.zhang 86335dfaa4 fix(离线库): 关闭 PowerSync 多标签共享 worker —— 修复 Windows 升级后任务页永久「加载中」
Docker Build and Push / build-image (push) Successful in 1m30s
现象: Windows 外壳 OTA 升级后, 任务页一直「加载中」; 其它不访问本地库的页面正常。
Android 正常。仅「原地升级/reload 之后」出现, 全新启动进程则正常。

根因: PowerSync Web 的 enableMultiTabs 默认在桌面端开启 (有 SharedWorker 时),
开启后会额外用 **共享 IndexedDB worker** 承载本地库。该 SharedWorker 跨页面 reload
存活, OTA applyUpdate 后 location.reload() 的新页面连上去时, 本地库读取永久挂起
—— 无异常、纯 pending, 所以 TaskPage 的 projects 一直是 null, 停在「加载中…」。
Android WebView 不支持 SharedWorker, 走独立 worker (随页面销毁), 因此不受影响。

实测 (真实 Windows 外壳 + WebView2 CDP):
- 修复前: 目标页 /me 正常; Page.reload 后落到 /task 显示「加载中…」, 再导航仍卡住;
  shared_worker 目标仍在 (worker-*.js 前后同 URL)。
- 修复后: reload 后 /task 正常渲染 25 个任务; shared_worker 目标消失;
  控制台仅剩 PowerSync「未启用多标签」提示。

修复: database.enableMultiTabs = false。本应用是单窗口外壳 (dock.html 不访问本地库),
不需要多标签同步; 该选项关闭后本地库改用随页面销毁的独立 worker, reload 干净。

注: 该问题与 OTA 包内容无关 (同一个包全新启动正常), 属 reload 路径的运行时缺陷。
2026-10-27 19:56:25 +08:00
jif2.zhang a23b10959c fix(同步): 上传路径补上 Task.status 与 Project.icon —— 此前静默丢弃
Docker Build and Push / build-image (push) Successful in 1m35s
现象: 任务点完成后被自动移入 Done 分组, 但详情页状态仍是「未开始」。

根因: /api/powersync/upload 的 **更新分支** 漏了 status 字段 ——
Task 更新分支逐个处理了 title/description/kind/markDate/extras/sortOrder/
assigneeId/doneAt/archived*/columnId/parentId, 唯独没有 d.status
(离线新建分支是处理了的, 所以只有"改已有任务"这条路丢状态)。
客户端 api/task.js 本地写入时 status 与 columnId 是一起算、一起写的
(改状态会按列绑定归位到 Done 列), connector 上行回读整行, 所以 payload 里
status 一定存在 —— 是服务端 prisma.task.update 时没把它放进 data。

结果: 列变更落地、状态被丢弃; 下行同步以服务端为权威, 又把本地 status 覆盖
回去, 于是"看板在 Done、详情未开始"。

数据实证 (生产 PG): 9 条顶层任务处于 Done 列 (boundStatus=done) 但 status
非 done (8 条 todo + 1 条 doing), 且全部 doneAt 有值; 反向 (status=done 却
不在 done 列) 0 条 —— 单向故障, 排除下行覆盖/并发冲突。这 9 条的 columnId 与
doneAt 在同一个 update 里都写成功了, 唯独 status 没有, 只可能是它压根没进 data。

修复 (稳妥方案, 复用唯一口径):
- resolveStatus.js 新增 resolveTaskUpload(): 客户端上行的是**本地整行**, 字段
  总是存在, 不能用"字段是否存在"判断变更, 必须先与服务端现值比较, 再交给
  resolveTaskWrite 裁决。不这样做会踩 T-BD-16: 任务从 Plan 拖到未绑定状态的
  Action 列时, 整行里 status 仍是 todo, 若当作"本次变更"提交, 场景 B 会把任务
  从 Action 归位回 Plan (拖过去又被弹回来)。
- powersync.js Task 更新分支改为调用 resolveTaskUpload, 并把 task.column 与
  columnId 一起指向目标列 (否则场景 B 会拿旧列判断, 同样误归位);
  doneAt 与最终状态保持一致 (进入 done 记时 / 离开 done 清空, 口径同 REST)。
- Project 更新分支补 icon (客户端本地写了 icon, 服务端同样丢弃), 校验口径与
  REST 写接口一致: 必须 data:image/ 前缀, 长度 <= 300_000。
- 上传处理器新增按项目缓存的 loadColumns (ops 已按表序排列, BoardColumn 先于
  Task 落地, 故 Task 阶段读到的列是本批次最终结果)。

用例 (10 项, 含关键回归与旧思路对照):
仅换列到未绑定列保持列与状态 / 换列到绑定列状态跟随 / 仅改状态归位 /
无变化返回 null / 脏数据自愈 / 子任务豁免 / 无匹配列不移动 /
对照证明旧思路会把 Action 里的任务弹回 Plan。

存量脏数据 (9 条) 需另行订正为 done, 不在本提交内。
2026-10-27 17:28:38 +08:00
jif2.zhang c460f09821 chore(dev): 新增 Windows 本地实时预览脚本 win:dev (不打包)
Docker Build and Push / build-image (push) Successful in 2m31s
改完前端 UI 想立刻在 Windows 外壳里看效果, 原本要 tauri build 打包。实际外壳
用 tauri-plugin-hotswap, 启动时优先读 %APPDATA%\<identifier>\hotswap\ 下的覆盖
包, 没有才回退 exe 内置 dist —— 与线上 OTA 同一条路径。因此只构建前端并写进
覆盖目录 + 重启外壳即可, 不编译 Rust、不打 NSIS/便携包、不重装。

  npm run win:dev                  构建(shell 模式) + 挂载 + 重启
  npm run win:dev -- --no-build    复用现有 dist, 只挂载+重启 (~2s)
  npm run win:dev -- --clear       卸载覆盖, 回到内置前端
  npm run win:dev -- --no-launch   只改覆盖目录, 不碰外壳进程

读插件源码得到的两个硬约束 (写错会被静默丢弃或启动即回滚), 脚本已处理:
- min_binary_version 必须 == 外壳版本: 默认 DiscardOnUpgrade 在 binary > min 时
  丢弃缓存, 而安全线又要求 binary >= min, 只能取等号;
- confirmed 必须为 true: 默认 SingleLaunch 对未确认版本启动即回滚。
另: 目录名须为 seq-<数字>; sequence 取 Date.now() 让 OTA 检查认为已是最新,
避免线上更新顶掉本地版本。

README 补「Windows 本地实时预览(不打包)」章节: 用法/原理/约束表/注意事项。
2026-10-27 15:49:39 +08:00
jif2.zhang 1d800c536e feat(任务): 详情页编号右置到副标题行、换列后自动收起、固定头尾滚动
- 完整任务编号从标题下方独立一行, 移到「看板列 · 状态」同一行右侧
  (左侧可省略号截断, 编号 flex-shrink:0 不被挤压)
- 切换看板列后 ActionSheet 未收起: 补 handler.close?.(), 且放在 onAction
  最前 (选中即收, 不等接口返回), 与项目视图 ⋯ 菜单同口径
- 滚动优化: 原整个弹层是一个滚动容器, 标题与保存按钮都会随内容滚走。
  改为三段式弹性布局 —— .td-head 固定 / .td-body 唯一滚动区 /
  .td-foot 固定 (保存按钮), 键盘弹出时底部随 kb 上抬

验证: 390x720 矮屏渲染真实 TaskDetail (14 条子任务撑出溢出), 11 项断言通过 ——
主体 scrollH 1531 > clientH 465; 滚动 1066px 到底后头部 top 86->86、
底部 top 657->657 均不变; 保存按钮 bottom 708 <= 720 始终在屏内;
头+体+底高度之和等于弹层总高 (无重叠/无空隙)。
2026-10-27 15:49:06 +08:00
jif2.zhang 0fc45aa6ec feat(打卡): 日历日期标记改为比例环, 并移除无引用死代码
日期标记 (F-CL-06): 旧实现是只按状态上色的 4px 圆点, 看不出完成度 ——
3/5 与 5/5 是同一个绿点。改为环形进度, 弧长 = 当天完成比例:
  expected = 0        -> 不画环 (当天没有应打卡项)
  expected > 0, 0 次  -> 空心环 (未开始)
  部分完成            -> 弧长按比例 (半填充)
  达标 / 超额         -> 整圈 (实心; 超额换色区分)
未来日期不画环 (计划 != 未完成); 选中日改用白环, 弧长仍表完成度;
「本月完成率」右侧补图例。

- 新增 components/checkin/DayRing.jsx (共享环形标记, 颜色交由 CSS 按视图上色)
- MergedView 日历格子接入该环
- 删除无引用死代码: pages/checkin/CalendarView.jsx (173 行) 与
  HabitView.jsx (338 行) —— V0.2.1 合并「打卡/日历」tab 后遗留, 全库扫描确认
  无任何 import/动态 import 引用; 连带清理仅服务于它们的 CSS
  (保留仍被 ListView 使用的 .habit-link)

验证: 桩 fetch 渲染真实 MergedView, 15 项断言通过 —— 空心环 / 弧长 25%·50%
精确匹配 / 整圈 / 三态配色 / 未来不画环 / 选中日白弧 60% / 图例 / 旧圆点已移除。
2026-10-27 15:48:14 +08:00
jif2.zhang 32f404ac90 fix(任务): 修复列表与看板拖拽「能触发但放不下」—— uuid 主键被 Number() 成 NaN
Docker Build and Push / build-image (push) Successful in 1m34s
0.2.1 切本地库后 Task.id / BoardColumn.id 为 uuid 字符串, 拖拽落点却用
Number(dataset.xxxId) 取值得到 NaN:
  - 看板 hitColumn 返回 NaN -> NaN 为 falsy, onDrop 永不触发; 目标列也不高亮
  - 列表 colId/taskId 为 NaN -> 组内命中与换列 findIndex 恒失败, 松手无操作
(打卡侧仍走 REST 数字 id, 故未受影响)

- 新增 src/pages/task/ids.js: idStr / sameId / datasetId, 统一按字符串比对
- useColumnDrag / useRowDrag: 落点、组内命中、换列、提交判定改用 sameId
- ProjectView: moveToColumn / reorderTask / changeStatus 改用 sameId,
  落点为空直接忽略, 不把坏 id 写进本地库
- api/task.js: update 拦截 "NaN"/"undefined" 列 id, 报「看板列无效」

验证: headless Edge + CDP 派发真实指针事件驱动两个 hook (uuid 数据),
修复前 4 条落点断言全挂, 修复后全部通过。
2026-10-27 10:06:37 +08:00
jif2.zhang 06e9a3e694 fix(任务): 编号改为 #序号展示、详情页完整编号可复制、修复详情改列报「看板列不存在」
- 列表/看板任务编号徽标改为 `#序号`(如 #18), 移除不再需要的 codePrefix 透传
- 详情页标题下新增完整任务编号胶囊 (项目编号-序号, 如 ADMIN-18), 点按复制:
  Clipboard API 优先, 非安全上下文/旧 WebView 回退 execCommand, 并提示已复制
- 修复详情页「看板列」切换报错: 0.2.1 本地库列 id 为 uuid 字符串,
  ActionSheet 的 key 恒为字符串, 旧代码 Number(key) 得到 NaN ->
  update 校验失败抛「看板列不存在」。改为字符串比对 (currentCol/勾选标记同步)
- 详情页保存后先就地替换该行再回源刷新
2026-10-27 10:06:12 +08:00
jif2.zhang 317072539d docs(0.2.1): 记录 OTA 链路打通与遗留清单实测数据
Docker Build and Push / build-image (push) Successful in 1m27s
2026-10-27 08:12:54 +08:00
jif2.zhang 08dd766886 fix(ci): OTA 包写入路径对齐 compose 挂载点 (deploy/prod/data/ota)
Docker Build and Push / build-image (push) Successful in 1m26s
2026-10-27 08:12:12 +08:00
jif2.zhang c9477b562e ci(ota): 新增 OTA 包同步步骤 —— 用 docker cp 经 bind-mount 容器写入宿主 data/ota
Docker Build and Push / build-image (push) Successful in 1m27s
2026-10-27 08:09:00 +08:00
jif2.zhang 50283269fb fix(ota): 生产 app 挂载宿主 data/ota 为 OTA 包目录 (此前镜像内为空, 线上 OTA 不可用)
Docker Build and Push / build-image (push) Successful in 1m14s
2026-10-27 08:06:05 +08:00
jif2.zhang 04bc48b6a7 fix(ota): OTA_MIN_BINARY 提到 0.2.1 —— 旧外壳 CSP 不含新域名, 拉新前端会白屏; 补充遗留清单与外壳升级策略
Docker Build and Push / build-image (push) Successful in 1m16s
2026-10-27 07:52:25 +08:00
jif2.zhang 702c8daf6c docs(0.2.1): 记录发布结果 —— master CI 10/10、Android 16/16、Windows 打包通过
Docker Build and Push / build-image (push) Successful in 1m18s
2026-10-27 07:30:30 +08:00
jif2.zhang a1c267b0d4 feat(0.2.1): 生产切换完成 —— 单端口上线 (3001 + 内网 PG/PowerSync), 迁移 MySQL 全量数据, 补 uuid 镜像触发器
Docker Build and Push / build-image (push) Successful in 2m14s
2026-10-27 07:26:47 +08:00
jif2.zhang 836035f4cd docs(0.2.1): 新增 021任务.md —— 目标/现状/卡点/待确认信息速查 2026-10-27 07:08:04 +08:00
jif2.zhang b29be62747 fix(deps): dev-0.2 同步 package-lock (tauri CLI 2.12.4), 修复镜像构建 npm ci 失败 2026-10-26 22:53:46 +08:00
jif2.zhang a9dc632986 chore(deploy): 生产 compose 增加 app 构建段 (服务器 buildKit 仅 compose 可用) 2026-10-26 22:52:27 +08:00
jif2.zhang cc2677ce06 chore(deploy): 生产 compose 支持 HOST_PORT 变量 (灰度验证时先用备用端口) 2026-10-26 22:18:31 +08:00
jif2.zhang 71dcf7e1b1 ci(0.2.1): 部署段改为调用宿主 /app/iboard-prod 部署脚本 —— 无 PG secrets 时跳过自动部署 2026-10-26 22:18:14 +08:00
jif2.zhang 30bc489b5c feat(0.2.1): 单端口生产架构 —— /sync 同域反代 (去掉 13002 独立同步端口), 新增 deploy/prod 生产编排 2026-10-26 21:57:40 +08:00
jif2.zhang 4b19d1d929 chore: artifacts 打包产物不入库 2026-10-26 21:22:57 +08:00
jif2.zhang 921f3496ea chore(0.2.1): OTA 基址切正式域名 https://iboard.honor3.com 2026-10-26 21:22:49 +08:00
jif2.zhang 7234b4b40a chore: 忽略 .esbuild-tmp 临时目录 2026-10-26 20:53:46 +08:00
jif2.zhang eef296942f feat(0.2.1): 合并 Windows 外壳 + 离线编辑, 版本 0.2.1, 正式域名 https://iboard.honor3.com 2026-10-26 20:53:38 +08:00
jif2.zhang e689e44923 Merge branch 'dev-0.2.1' into dev-0.2
# Conflicts:
#	generated/prisma/internal/class.ts
#	generated/prisma/internal/prismaNamespace.ts
#	generated/prisma/internal/prismaNamespaceBrowser.ts
#	generated/prisma/models/BoardColumn.ts
#	generated/prisma/models/Project.ts
#	generated/prisma/models/ProjectMember.ts
#	generated/prisma/models/Task.ts
#	generated/prisma/models/TaskMember.ts
#	generated/prisma/models/TaskTag.ts
#	generated/prisma/models/User.ts
#	server/routes/projects.js
#	server/routes/tasks.js
#	src/api/task.js
2026-10-26 20:46:25 +08:00
jif2.zhang fc23919a4e chore(prisma): 补齐 generated 任务模块模型 (Project/Task/BoardColumn 等 6 个), 与 schema 对齐 2026-10-26 20:42:05 +08:00
jif2.zhang f34c8c3bae feat(离线): 界面离线可看 —— GET 响应本地缓存 + 同步凭证持久化 (离线不清库) + 左上角离线徽标 (与 Windows 外壳分支同源) 2026-10-26 16:05:59 +08:00
jif2.zhang 9f16db4286 feat(0.2.1): 同步端点支持 VITE_POWERSYNC_URL 覆写 (Tauri 外壳等打包端按需指定) 2026-10-26 08:58:37 +08:00
jif2.zhang fd029ad124 fix(0.2.1): PowerSync 升级 v2 线 (web 2.5.0 + react 2.1.0 + wa-sqlite 2.0.8) —— 1.39.1 与自动装配的 wa-sqlite 1.7.2 不兼容 (缺 sqlite3_prepare_v3) 2026-10-26 02:24:49 +08:00
jif2.zhang e963140bf9 feat(0.2.1): TLS 前置 13443 —— PowerSync 网页端必须安全上下文 (navigator.locks), 自签证书按路径分流 app/sync 2026-10-26 01:59:31 +08:00
jif2.zhang 533a05832e fix(0.2.1): crypto.randomUUID 仅安全上下文可用 —— http 明文部署下用 getRandomValues 兜底生成 uuid 2026-10-26 01:52:38 +08:00
jif2.zhang 086f7aecf9 fix(0.2.1): 验证脚本依赖移出 package.json (dev-only 工具不进镜像), 锁文件同步 2026-10-26 01:42:17 +08:00
jif2.zhang 1edf57b75d fix(0.2.1): 运行时镜像 npm ci 加 --omit=optional (跳过 devOptional 的 better-sqlite3, 免 node-gyp) 2026-10-26 01:40:38 +08:00
jif2.zhang 4ce701e99a feat(0.2.1): M5 闭环验证通过 —— verify 脚本 7 步全绿 (下行/离线写/上行/定号/回填/REST确认/删除同步); 方案文档补 Sequential ID Mapping 2026-10-26 01:37:24 +08:00
jif2.zhang 8813766aff fix(0.2.1): 镜像列 Prisma 侧可空 (库级 NOT NULL, 触发器填充), 避免 create 校验拦截 2026-10-26 01:27:46 +08:00
jif2.zhang aca8a05c0f feat(0.2.1): Sequential ID Mapping —— 外键 uuid 镜像列+触发器, 同步流改 uuid 主键 (离线行回填后本地 id 稳定), 客户端零改动 2026-10-26 01:21:40 +08:00
jif2.zhang 9caaa303e5 fix(0.2.1): upload 契约对齐客户端 —— 外键列即父行 uuid (projectId/columnId/parentId/taskId); 附 Node 闭环验证脚本 2026-10-26 01:14:34 +08:00
jif2.zhang a714013e3e feat(0.2.1): M3 前端接入 —— PowerSyncProvider/登录连接/登出清库, 任务模块数据层切本地库 (projectApi/columnApi/taskApi 本地实现, 离线读写+自动上行), 任务编号徽标展示 2026-10-26 00:41:51 +08:00
jif2.zhang 1a695920ce fix(0.2.1): ETL 按目标 PG 列白名单取数 + boolean/bigint/json 类型感知转换 (现网库 schema 领先于本分支) 2026-10-26 00:29:08 +08:00
jif2.zhang 025fcc3244 feat(0.2.1): M4-b ETL —— 现网 MariaDB 只读快照导入 PG (uuid/code/number 回填, 时序表限量, 序列校准) 2026-10-26 00:27:20 +08:00
jif2.zhang 636e566657 fix(0.2.1): initdb 增加 powersync publication (服务不自建, PSYNC_S1141) 2026-10-26 00:21:00 +08:00