unis_manager/.workbuddy/memory/2026-09-17.md

128 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 2026-09-17
## 清空「定开项目」模块数据
按用户要求清空 `data/board.db` 里定开项目模块的全部数据(保留表结构与其余模块)。
- 备份:`data/board.db.bak-before-clear-custom-20260917_105824`
- 删除顺序:先子表 `custom_updates`(28 行)→ 再父表 `custom_projects`(119 行),避免外键孤儿。
- 清空前摘要:119 个定开项目(归档 0),合同额合计约 395.2 万,累计计收 0。
- 清空后校验:两表均 0 行,`custom_updates` 孤儿记录 0。
- 接口验证:`/api/custom/projects` 返回 `[]`;`/api/weekly` 的 `custom` 段 0 条,KPI 中 `custom_total / custom_amount / custom_new / custom_updated / revenue_delta` 全部归零。项目管理模块(`projects`/`tasks`/`updates`)未受影响。
- `ledger_items`(定开台账)本来就是 0 行,未动。
## 导入《定开项目.xlsx》市场台账 + 扩展 custom_projects 字段
用户提供 `C:/Users/Administrator/Desktop/定开项目.xlsx`(Sheet1,120 行含表头 → **119 条数据**,14 列),要求导入定开项目库、按表格调整字段、并加「更新时间」字段便于按周查看变化。经确认采用:**新增字段(不重构)** + **每行一个更新时间** + **项目状态新增独立字段**。
### 表结构(10 个新字段,靠 `schema_patch.ensure_columns` 自动 ALTER TABLE)
`origin`(项目归属) / `project_code`(项目ID, index) / `office`(办事处) / `industry`(行业) / `man_days`(市场下单人天) / `market_owner`(市场责任人) / `project_status`(项目状态) / `accept_plan`(推动验收计划) / `risk_level`(风险值) / `update_date`(更新时间 YYYY-MM-DD, index)
### 字段映射(表格列 → DB 列)
- 项目归属→origin、项目名称→name、项目ID→project_code、行业→industry、市场下单人天→man_days、市场责任人→market_owner、项目状态→project_status、推动验收计划→accept_plan、风险值→risk_level、备注→remark
- **下单时间→`sign_date`**(原字段注释就是「签单/下单时间」);**办事处→`region`(归一化)+ `office`(原样)**;**验收时间→`accept_date`**
- `entry_date`(入库时间)兜底取下单时间,保证明细列表「按入库时间倒序」有排序键
### 数据质量(表格里就有的问题,未擅自改)
- 重名 2 行:「甘肃省水利厅图像站建设项目二期」×2,**项目ID 不同**(HGSE25122401N / HGS025010202N)→ 导入脚本**有 ID 时只按 ID 匹配**,否则会互相覆盖
- 1 行无项目ID(高新区感知源-钰田(定制开发))、1 行无办事处
- 「验收时间/推动验收计划」是**季度文本**(Q1..Q4/27年),互补:60+59=119
- 「下单时间」混格式:91 个真日期 + 28 个文本(`2024年3月前`、`2024/`)→ 日期转 YYYY-MM-DD,文本原样存
- 「市场责任人」51 人**全部不在花名册**(销售侧人员,与 `owner` 交付负责人是两个概念)
- 只有「深圳」不在区域词表 → 已在 `constants.REGION_ALIAS` 加 `深圳/深圳市 → 广东`
### 改动文件
- `app/models.py`:CustomProject 加 10 字段 + `to_dict` 输出
- `app/routers/custom.py`:PATCH 白名单加新字段;**台账字段有变化时刷新 `update_date`**(无变化不刷新,已实测);创建时写 `update_date`;`CustomProjectIn` 补字段
- `app/routers/export.py`:导出追加 10 列(末尾追加,保持原 money_cols 索引不变)
- `web/app.js`:明细列表 16→25 列(加 项目ID/行业/项目归属/市场责任人/项目状态/风险值/人天/推动验收/更新时间);新增 `statusPill`/`riskPill` 小色块;详情抽屉加「市场台账」区块(只读 + 编辑);KPI 提示加 人天/高风险
- `scripts/import_custom_ledger.py`:**新建**,openpyxl 读取 + 按 ID/名称 upsert + 变更比对,支持 `--dry-run` / `--date`
### 验证
- 导入:新增 119 / 更新 0 / 无变化 0;**重复导入幂等**(0/0/119)
- 分布与源表一致:项目状态 已验收60/待开发31/交付完成17/交付中9/退单2;行业 安平51/政府25/企业22/教育11/交通6/医疗2/行业1/高速1
- `/api/custom/projects` 返回 119 条含全部新字段;导出 34 列、合计行人天 5066
- PATCH 改 industry → update_date 由 2026-01-01 刷新为今天;提交相同值 → 保持旧日期(变更检测正确),测试后已还原
- 备份:`data/board.db.bak-before-ledger-import-20260917_141759`
### 遗留 / 待确认
- 119 行 `stage` 全是默认 `signed`、`progress` 0、计收/开票/回款为空 —— 新台账不带这些业务字段,模块里依赖它们的旧列(进度%、可确认、已计收、开票、回款)目前是空的
- 页面未做浏览器截图验证(agent-browser 未安装,装 Chromium 要 ~500MB 且规则禁止全局 npm),只做了 JS 语法校验 + 接口/导出功能验证
## 定开项目明细表改为按 Excel 表头顺序展示
用户要求明细表字段参考导入的 Excel 表头。实际 Excel 表头顺序(14 列)为:项目归属 / 项目名称 / 项目ID / 下单时间 / 办事处 / 行业 / 市场下单人天 / 订单金额 / 市场责任人 / 项目状态 / 验收时间 / 推动验收计划 / 风险值 / 备注。
- 重排 `renderCustomList` 表头+数据行,完全按此顺序;追加「更新时间」(用户此前要求,非 Excel 字段)与「操作」列 → 共 16 列。
- 从主表移除 Excel 没有的旧列:区域、负责人(owner)、入库、交付、阶段、进度%、可确认/已计收/开票/回款 —— 这些仍保留在详情抽屉里。
- 顶部统计行改为:合同额/万、人天、高风险数、已验收数(去掉空的计收/开票/回款)。
- 纯前端改动(`web/app.js`),后端无需重启;接口此前已验证返回全部新字段。node `--check` 语法通过。
## 明细表交互改造:去按钮 / 状态筛选 / 新建表单对齐 Excel / 统计条
用户四项要求:① 明细表去掉「详情」「归档」按钮 ② 新增「项目状态」筛选 ③「新建定开项目」字段参考 Excel 调整 ④ 表格上方加统计(项目数量+金额、本月/本年新增下单、本月/本年验收)。
### 新增字段 `accept_date_real`(验收日期,真实日期)
Excel 里「验收时间」是季度文本(Q1..Q4),无法算「本月/本年」,故新增 **`accept_date_real`**(String(16), YYYY-MM-DD, index)专门用于验收统计,与 `accept_date`(季度文本,展示用)并存互补。
- 改动:`models.py`(字段 + to_dict)、`custom.py`(CustomProjectIn / PATCH 白名单 / create 时 `region` 可由 `office` 归一化推导)、`scripts/import_custom_ledger.py`(导入时对「已验收」+季度文本的行补当年季度末占位;**仅在库中为空时补,不覆盖用户手改的真日期**)。
- 一次性回填:已导入的 119 行中 60 条「已验收」补上 2026 季度末(Q1→03-31/Q2→06-30/Q3→09-30/Q4→12-31),不动 `update_date`。结果:本年验收 60、本月(9月)验收 17。
### 前端(web/app.js + styles.css)
- **去按钮**:`renderCustomList` 行操作列只留「修改」(`data-cedit`);名称仍可点开详情(`data-copen`)。`bindCustomList` 移除 `data-carch` 绑定。
- **状态筛选**:工具栏加 `<select id="cStatus">`(全部/已验收/待开发/交付完成/交付中/退单),state 加 `customStatus`,在 `renderCustomList` 内对已加载行做客户端筛选。
- **新建表单**:`openNewCustomDialog` 重写为对齐 Excel 的字段(项目归属/项目名称*/项目ID/下单时间/办事处/行业/市场下单人天/订单金额/市场责任人/项目状态/验收时间(季度文本)/推动验收计划/风险值/验收日期/备注/重点项目);提交时把台账字段发给后端,`region` 由后端按 office 归一化(实测 深圳→广东)。更新录入页共用此函数,一并生效。
- **统计条**:新增 `.stat-row/.stat`(styles.css),在 `renderCustomList` 表头上方展示 5 个格子:项目数量/合同额、本月新增下单、本年新增下单、本月验收、本年验收(均「个数 · 金额万」)。下单按 `sign_date`、验收按 `accept_date_real`,基于当前筛选后的行计算;card-head 的 period-hint 保留人天/高风险/已验收。
### 验证
- 语法:node `--check`(app.js)、ast.parse(models.py/custom.py/export.py/import_custom_ledger.py/constants.py)全通过。
- 接口:重启后 `/api/custom/projects` 119 条含 `accept_date_real`;POST 新建含全部台账字段 → region 由 office 推导正确(深圳→广东),测试项目已删除;`/api/export/custom` 200。
- 统计口径实测:本年验收 60、本月(2026-09)验收 17、本年新增下单 31、本月新增下单 0。
- 页面未做浏览器截图(agent-browser 未装),刷新浏览器查看即可。
## 明细表:去掉归档下拉 / 按更新时间排序 / 删除本周更新
用户(附截图:归档状态下拉「在库/已归档/全部」)要求:① 删除该下拉 ② 新增展示并「按更新时间排序」 ③ 可按周删除「本周更新」的数据。
### 前端(web/app.js)
- **移除**明细表 card-head 里的 `#cArchived` 归档状态下拉及 `bindCustomList` 里的绑定;`state.customArchived` 保留(恒为 "false",仍只查非归档)。
- **排序**:`renderCustomList` 的 `view` 改为按 `update_date` 倒序(`String(b.update_date).localeCompare(...)`),表头副标题改为「按「更新时间」倒序」。
- **删除本周更新**:card-head 加 `<button id="btnPurgeWeek" class="btn sm danger">删除本周更新</button>`;`purgeWeek()` 先 `GET /custom/weekly-preview` 拿数量/金额/名单 → `confirmDialog({danger:true, requireText:"删除"})` 二次确认(并要求手动输入「删除」)→ `POST /custom/purge-week` → `afterWrite()` 刷新。
- `confirmDialog` 增加可选 `o.requirePlaceholder`(原来输入框 placeholder 硬编码「逐字输入项目名称」,批量删除场景不适用)。
### 后端(app/routers/custom.py)
- 新增 `_sort_by_update()`(update_date 倒序,无则回落 entry_date);`GET /custom/projects` 改用之(原来是 `_sort_by_entry`)。
- 新增 `_week_range()`(当前自然周 周一~周日,基于 `date.today()` 的 `weekday()`)。
- 新增 `GET /custom/weekly-preview`(本周有 update_date 的项目数/金额/名单,供确认)。
- 新增 `POST /custom/purge-week`(删除 update_date 落在本周的项目,`db.delete(cp)` 靠 relationship cascade 连带删 custom_updates),返回 `{deleted,start,end,names}`。
- 路径用 `/custom/weekly-preview`、`/custom/purge-week`,**避开** `/custom/projects/{cid}`(int 路径参数会被非数字段 422),未放在 projects 前缀下。
### 验证
- node `--check` + ast OK;服务重启后 `/health` ok。
- `/api/custom/weekly-preview` → 本周 **2026-09-14 ~ 2026-09-20**,**119 个**(因导入把 119 行 update_date 都写成 2026-09-17=今天),合同额约 1130.7 万。
- `/api/custom/projects` 已按 update_date 倒序返回。
- ⚠️ 注意:当前所有行 update_date 都是导入当周,所以「删除本周更新」= 会删掉全部 119 条;已用「显示数量 + 需输入『删除』」做强确认。**未实际执行 purge**(只验证了 preview)。
## 定开金额单位:明细表用元、汇总统计用万
用户要求表格列「订单金额/万」去掉「/万」,单位换成正常的个位(元);但**汇总统计仍需用「万」**。
- **关键事实**:`custom_projects.amount` 在库里本来就是**元**(实测 sum≈11,307,268、avg≈95,019、max=1,000,000),之前的「/万」只是展示约定——`fen()`/`wan()` 把元÷10000 显示成万。
- **最终约定(定开金额)**:**明细表格每行 = 元**(`money(p.amount)`,¥+千分位);**所有汇总/统计 = 万**(`fen()`/`wan()`)。
- 改动(纯前端 `web/app.js`,静态服务无需重启):
- 定开项目明细表:表头 `订单金额/万` → `订单金额`;单元格 `fen(p.amount)` → `money(p.amount)`(元)。
- 上方统计条、人力资源页「定开合同额/定开待计收」、工作看板 KPI「定开合同额」、`删除本周更新`确认框的「合同额合计」——**仍用万**(`fen()`/`wan()`),未改/已改回。
- **未动**:项目管理(交付跟踪)模块的「合同额」仍用 wan/fen+万(另一套 `projects` 数据);导出沿用原始元值。
- 服务 `/health` ok,浏览器刷新即可见(static 带 no-cache+ETag)。
## 更新时间 = 下单时间 + 修改表单对齐台账字段
两项需求:(1) 更新时间全部改为项目下单时间;(2) 定开「修改」表单只保留《定开项目.xlsx》14 列表字段,删除交付跟踪类多余字段。
### 1) update_date = sign_date(全量)
- 备份:`data/board.db.bak-before-updatedate-sign-20260917_000000`。
- `UPDATE custom_projects SET update_date = sign_date`(119/119 行;0 个 null sign_date,91 个真日期 + 28 个文本如「2024年3月前」)。
- 后端 `app/routers/custom.py` PATCH:原本改任何字段就 `update_date=today`,改为 `update_date = cp.sign_date if cp.sign_date else cp.update_date`(跟随下单时间)。已用 API 实测:改 remark 后 update_date 仍为 2024-04-30(=sign_date),不是今天。
- `scripts/import_custom_ledger.py`:新增/更新行的 `update_date` 改默认取 `sign_date`(无则回退 args.date);同步改了文档注释。
- 副作用:「删除本周更新」现在按 sign_date 周判断,历史台账(2024/2025)不会命中本周 → 之前「会删光 119 条」的危险消失。
### 2) 修改表单对齐台账(前端 `web/app.js`)
- `openCustomDrawer` 的 edit 模式:section「定开项目信息」只放 Excel 14 列(项目归属/项目名称/项目ID/下单时间/办事处/行业/市场下单人天/订单金额/市场责任人/项目状态/验收时间/推动验收计划/风险值/备注)+ 验收日期 + 只读「更新时间(跟随下单时间)」。
- **删除的多余字段**:基础信息里的 阶段/开发进度/已计收/确认比例/交付环节/区域/交付负责人/团队成员/客户;收入确认里的 开票金额/已回款 编辑框(收入确认 KPI 只读区仅在 view 模式显示,edit 模式整段不渲染)。edit 模式只渲染 ledgerSec 表单,baseSec/收入确认/周期执行记录/阶段流转 仅 view 模式渲染。
- `cdSave` PATCH payload 精简为上述台账字段(不再传 stage/owner/region/members 等,未传字段不动;`set_people` 对 None 不改成员)。
- view 模式补充显示 下单时间、验收时间(之前漏显示)。
- **数据保护**:编辑表单的「下单时间」用 text 输入(非 date),因为 28 行 sign_date 是文本(date 控件会清空它们);新建对话框仍用 date。
- 重启 uvicorn 使后端生效(原 PID 40088 → 新进程);`node --check` 与 `ast.parse` 均通过;前端 static 无需重启。