# 2026-09-13 周期错位修复 ## 问题 系统里「2026年8月第4周」混进了「9月第1周」的内容(两块录到同一周期)。 ## 根因 原始 Excel《周工作情况总结》最后一次导入时,表尾**只有一个「8月第4周」标签**,其内容里连着贴了两段。 `scripts/import_excel.py` 按 (项目, 子任务, 周期) 去重,同周期内重复出现就 append 到同一条记录 (见 import_excel.py:170-197),于是两周内容被揉在一起。Excel 文件后来(2026-09-13 16:08)被拆成了 「8月第4周」(行838-862) 和「9月第1周」(行863-890) 两个块。 ## 修复 脚本 `scripts/fix_period_split.py`(--dry-run 预演,默认执行,自动备份 data/board.db) 按 Excel 现状把数据库对齐: - 2026年8月第4周 → 只留 8月第4周内容(9 常规 + 1 定制) - 2026年9月第1周 ← 从 8月第4周拆出的 9月第1周内容(10 常规 + 1 定制「金昌视综平台定制开发」) - 2026年9月第2周 ← 原误放在 9月第1周 的数据(用户手工录入的 NEX 云桌面 2 条) - 顺带重算受影响项目的进度/状态、受影响定制项目的入库时间 ## 全量核查结论(内容级比对 Excel vs DB) - 无跨周污染残留(8月第4周/9月第1周 那个是唯一一起,已修) - 另有 7 条「DB 内容比 Excel 多」: - 2025年3月第1周 3 条(云桌面产品培训/公司内IT平台规划/云屏V1.2版) - 2026年5月第3周 2 条、5月第4周 1 条、6月第1周 1 条 → **同一周内同一子项在源表里占多行**,导入时合并成一条;非跨周问题 - Excel 里存在**同标签重复块**:2024年9月第二周(行143/160)、2025年5月第3周(行503/528), 导入必然合并,属源表歧义,未擅自拆分 - 「智听云」→ 改名「iMeeting 语音智能体」、「智空无人机平台」→ 合并进「智飞无人机平台」, 在全量比对中表现为 Excel/DB 互不匹配,属正常 ## 教训 导入脚本对「同周期同子项重复出现」采用 append 合并,源表一旦把两周内容贴在同一标签下就会静默串周。 后续若发现某周期记录数明显偏多,优先怀疑源表标签缺失。 --- # 重点项目 / 定制项目:多负责人 + 团队成员 ## 需求 重点项目和定制项目都可以指定多个负责人,并新增「团队成员」。 ## 兼容策略(关键决定) - `owner` 列语义不变 = **主负责人** = `owners[0]`。列表、看板、导出、人力负载、KPI 全部照旧读 `owner`,**一行未改**。 - **不建关联表**:两张项目表各加 `other_owners`(其他负责人,不含主)与 `members`(团队成员)两个 `String(512)` 列, 存**首尾带逗号**的 CSV:`,张三,李四,` 或 NULL。于是 `LIKE '%,张三,%'` 是精确整名匹配, 「张三」不会命中「张三丰」(已测)。 - 新列靠 `app/schema_patch.py: ensure_columns` 启动时自动 `ALTER TABLE`,**无需迁移脚本**;真实库 `data/board.db` 本次未被写入。 - API 字段:`owners`(= 主 + 其他,主在首位)、`members`。PATCH **整体替换**:不传=不改,传 `[]`=清空。 老调用方只传 `owner` 时 `other_owners` 保留 → `owners` 自动变成 `[新主, ...其他]`,不会写出脏数据。 - 工具函数集中在 `app/models.py`:`split_people / dedupe_people / join_people / people_like / all_owners / set_people`; `set_people` 同时负责「`owners[0]` 回写 `owner`」。 ## 口径(容易误解,已和用户对齐的说法) - 「负责人」筛选(项目列表 / 定制列表 / 周看板)**主负责人和其他负责人都算命中**;**团队成员不参与**该筛选(有意)。 - 列表、导出、人力负载、KPI 只按主负责人统计;列表负责人列只显示主负责人。 - 人员改名(`routers/staff.py`)会同步改写 `other_owners` / `members` 里的名字。 ## 入口 只在详情抽屉的「修改」档(`peopleEditorHtml` / `peopleValues` / `bindDrawerPeople`,增删按钮一次性委托在 `#drawerBody`)。 第 0 行:负责人档标「主」不给删;成员档空占位行不给删,有值就能删。列表行仍然只有 详情/修改/归档。 **新建弹窗(npOwner/ncOwner)保持单个负责人**——假设:建好后进详情面板补名单。 ## 并发提醒 `web/app.js` 同期被另一个任务改(人力资源表的星标计数),期间出现过一次模板串语法错误导致整站 JS 不解析(对方已自行修复)。 改这个文件前先 `node --check web/app.js` + `shasum`。 --- # 周工作 Focus:只显示当周 + 上周延期结转;录入期数 ≠ 预计完成时间 ## 需求 > 周工作Focus的只显示当周和上周延期过来的。录入的时候也要注意这点,选择的结束时间并不是作为录入的期数。 老逻辑把 `due_date` 反查成 `periods` 里的一周存进 `period_id`,于是本周录一条「两周后交付」的活儿直接掉进「未来」堆,本周看不见。 ## 语义变更(核心) - `WeeklyFocus.period_id` 语义由「预计完成时间所属周」改成**录入周**,和 `Update.period_id`(反馈所属周)一致。 字段名/`to_dict` 键名(`period_id / period_label / period_full / sort_key`)全部保留 → 前端与导出零连锁改动。 - `due_date` 退化成纯目标日期:`focus.py: _resolve_period()` → `_entry_period(db, period_id)`, **不再按日期反查周期**;POST 传 `period_id`=顶栏当前周,没传(脚本/API 直调)按 `constants.week_of_date(date.today())` 补; PATCH 只有显式传 `period_id` 才搬周,改 `due_date` 不再动归属。 - 导出列「所属周」→「录入周」(`export.py`,排序仍按 period.sort_key desc)。 ## 分堆口径(`web/app.js: focusBuckets`) - `week` = 录入周 == 基准周;`overdue` = 录入周 < 基准周 且 `delayed` 且未完成(上周及更早的结转);`done` 仍是交叉视图。 - **删掉「未来」堆**(chip 从 5 个变 4 个:本周/延期/已完成/全部);`restoreUI` 里把存量的 `focusFilter==="later"` 复位成 `week`,否则老会话进来会看到空表。 - 取舍(已明确告知用户):更早周次录入、**没标延期**又没完成的条目不进当周视图,只能在「全部」里查 → 每周收尾要手动勾「延期」才会结转。 - 抽屉:录入周只读一行(新增取顶栏周,编辑显示原周);预计完成时间与录入周在详情里拆成两行;`#fdSave` 只在 `mode==="create"` 时带 `period_id`。 - 列表「预计完成时间」下的小字改为「录入 X月第N周」;看板左栏结转条目多挂一个「录入 …」标签。 ## 顺带修的默认值问题(会导致本周看起来是空的) `/api/periods` 里已预建了未来的周(库里已有 9月第3周),而 `loadPeriods` 的默认周取「列表最后一期」→ 顶栏会落在**下周**, 新的录入周口径下当周直接空掉。改为 `/periods` 多返回 `today_id`(`constants.week_of_date(date.today())` 命中的周), 默认周取 `today_id || 最后一期`。仅在「存的 weekId 不在列表里」时生效,不覆盖用户手选的周。 ## 数据 库里 3 条 focus(全是 2026-09-13 建的)`period_id` 本来就是 9月第2周 = 今天所在周 → **无需回填**,语义切换后归属不变(已断言)。 ## 验证 `/tmp/umtest/t_focus.py`(TestClient + `data/board.db` 副本):due=两周后仍归本周 / 不传 period_id 归今天所在周 / 改 due 不搬周 / 显式 period_id 才搬周 / 旧数据不漂移 / 导出 200。 UI(8791 + 副本库,插 5 条造结转场景):本周 3(含 due 9-20 那条)· 延期 3(9月第1周×2 + 8月第4周×1,未标延期与已完成的都不进来)· 已完成 2 · 全部 8;新增 due=09-27 立即进本周;改成 12-31 仍在本周;切到 9月第3周本周空态文案正确;`dev.logs()` 为空。 ## 待办(历史遗留,未动) `scripts/import_excel.py` 里旧台账 `LedgerItem` 的导入解析是否退役。