128 lines
15 KiB
Markdown
128 lines
15 KiB
Markdown
# 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 无需重启。
|
||
|