# 软件开发部 · 关键任务追踪看板 基于《软件开发部管理工作执行表.xlsx》构建的部门关键任务追踪系统。 侧栏是**四个业务模块 + 三个支撑页**: | 模块 | 适用 | 关心什么 | 数据表 | |---|---|---|---| | **① 工作看板** | 每天进来的第一屏 | 三类工作本周期谁更新了、谁没动,点一条从一览看到详情 | 只读汇总(`/api/weekly` + `/api/focus`) | | **② 项目管理** | NEX云桌面、AI Agent、智飞无人机平台、内部运营… | 长期重点项目的迭代执行、子任务进展、风险阻塞 | `projects` / `tasks` / `updates` | | **③ 定开项目** | 各省市客户定开子项目 | 商务阶段流转(签单→开发→交付→验收→计收)+ 按进度确认收入 | `custom_projects` / `custom_updates` | | **④ 每周重点工作** | 不值得单独建项目档案的短期活儿 | 一条就是一件事,面板里录,归在**录入周**这一周,跟到完成 | `weekly_focus` | 支撑页三个:**人力资源**(`staff`,全系统「负责人」的唯一来源)、**更新录入**(执行 / 交付记录的唯一写入口:粘贴原文 → AI 整理 → 确认写入)、**设置**(周期管理、AI 配置)。 ②③ 是**两套彼此独立的项目体系**(数据表也完全分开),共用一个**人力资源库**:项目与定开项目的「负责人」都从花名册里选,人员进出只维护一处。④ 的条目不是项目,不挂子任务与执行记录。① 只做汇总与跳转,自己不落数据。 ## 周期管理 ### 新增周期 三个入口,都会自动接续年份: | 入口 | 操作 | |---|---| | 顶部周期下拉 | 选「+ 新建周期…」 | | 更新录入页(常规 / 定开都有) | 周期下拉选「+ 新建周期…」 | | 设置页 → 周期管理 | 「+ 新建周期」按钮 | 输入格式 `9月第1周`(也可写 `2027年1月第1周` 显式指定年份),年份按以下规则自动推断: - 月份 **大于等于** 最新周期的月份 → 用最新周期的年份(9月已有第4周时补录第1周,仍留在同年) - 月份 **小于** 最新周期的月份 → 进入下一年(8月之后建 `1月第1周` → 次年) 重复创建同一周期会直接返回已存在的那个,不会产生重复数据。 ### 删除周期 设置页 → 周期管理,表格里列出所有周期及各自的记录数。**只有不含任何执行记录的空周期才能删除**,已有记录的会置灰并说明原因,接口层面也会二次校验。 ### 年份整体平移 历史数据的年份口径需要整体调整时: ```bash python scripts/shift_year.py --dry-run # 先预演,看清楚了再执行 python scripts/shift_year.py # 全部 +1 年 python scripts/shift_year.py --years -1 # 反向回滚 ``` > 内部按年份从大到小更新,避免 2024→2025 撞上尚未更新的 2025;执行后会校验 sort_key 无重复,有重复则整体回滚。 > 执行前建议手动备份:`cp data/board.db data/board.db.bak` ## 快速开始 ```bash cd /Users/jiliu/WorkSpace/unis_manager ./run.sh ``` 打开 首次运行 `run.sh` 会自动完成:选择带依赖的 Python 解释器 → 缺依赖则安装 → 建库 → 导入历史 Excel → 拆分定开项目,然后启动并打开浏览器。 ### 启动方式与排错 | 场景 | 命令 | |---|---| | 正常启动 | `./run.sh` | | 报 `permission denied` | `chmod +x run.sh` 后重试(**不要用 sudo**) | | 不想改权限 | `bash run.sh` | | 换端口 | `PORT=8771 ./run.sh` | | 关闭热加载 | `DEV=0 ./run.sh`(默认是开着的) | | 不自动开浏览器 | `NO_OPEN=1 ./run.sh` | | 提示"端口已被占用" | 原窗口 `Ctrl+C`,或 `lsof -ti:8770 \| xargs kill` 后重跑 | > ⚠️ 不要用 `sudo` 启动:数据库文件会变成 root 属主,后续写入会失败。 > **热更新(默认开启)**:uvicorn 除 `*.py` 外还会监听 `web/**` 的 js/css/html 与 `.env`,改动即重启; > 页面里的 `web/livereload.js` 每秒读一次 `/health` 的启动代际,发现服务重启后自动刷新浏览器。 > 也就是说改完代码**不用手动重启、也不用手动刷新**。`DEV=0 ./run.sh` 可关掉(关闭后该脚本首轮即自行停止)。 > `data/*.db` 的写入不会触发重启。 ### 手动分步执行(等价于 run.sh 干的事) ```bash pip install -r requirements.txt python scripts/init_db.py python scripts/import_excel.py "/Users/jiliu/WorkSpace/定开管理/软件开发部管理工作执行表.xlsx" python scripts/migrate_custom.py python -m uvicorn app.main:app --port 8770 ``` > 重新导入:`python scripts/import_excel.py --reset` 之后再跑一次 `python scripts/migrate_custom.py` > (迁移脚本会删除常规表里的「定制开发」容器,重复执行前请先 reset) ## 功能 ### 1. 工作看板 进来第一屏:三类工作在这一页从「一览」点到「详情」,左栏挑一条,右栏跟着联动。 | 区域 | 内容 | |---|---| | 顶部 KPI | 重点项目(含本期已更新数)/ 重点项目未更新 / **本周重点工作**(本周到期的重点工作条数,脚注「逾期 N 条 · 已完成 N 条」)/ 执行记录 / 定开合同额(含项目数与本期计收)/ 风险阻塞 | | **左栏** | **三组**清单,顺序固定:① **本周工作重点**(列表,逾期的置顶)② **重点项目**(列表:`is_key` 的项目,另含本期补了执行记录的非重点项目,条目前用 ★ 区分)③ **定开项目**——**只给一个入口**「本周定开项目动态」,左栏不铺清单(100 多个项目会淹没看板),点开才在右栏列本周有动态的。组头显示条数与「几个已更新 / 几条逾期 / 本周动态几个」;每条带负责人、状态或阶段、本期摘要、风险条数,本期有记录的点亮标记 | | **右栏** | 点左栏任意一条即可联动。重点项目 → 本期执行记录 / 进度与状态(含子任务)/ 近 8 期趋势;**定开项目入口 → 本周动态总览**(顶部标签:本周新增 / 本周验收 / 有交付动态 / 合同额合计 / 本期计收,下面分「本周新增」「本周验收」「本周有变化」三段,每条带阶段、负责人、金额、本期计收与摘要),点某一条再下钻到该项目 → 交付环节五段条 / 财务跟踪四联卡 + 开票·回款行内输入 / 本期交付记录 / 更早的交付记录,改开票、回款、环节日期即时保存(改日期会自动推进商务阶段);每周重点工作 → 只读的说明与状态,要改点「修改」开抽屉 | | 工具栏 | 「负责人」筛选、「导出本周期记录」,提示里带本期项目数与定开动态数;顶栏可切周 / 月视图(月视图自动汇总该月所有周)。「列入全部在途」开关(`all_custom`)不在工具栏,挪到了右栏定开总览的头部 | | 统计概览 | 页面最底部的折叠区(原「执行面板」,已不占主导航位):周期活跃度柱状图、分类环形图、状态分布、进度 Top10、低进度预警、风险清单,数据来自 `GET /api/stats`;加载失败也不影响看板主体 | 数据分两路:`GET /api/weekly?period_id=|year&month&owner=&all_custom=` 一次返回重点项目清单 + 定开项目清单 + 顶部 KPI(含 `custom_new` 本期新入库数、`custom_updated` 本期有交付记录数);**「本周工作重点」不在 `/api/weekly` 里**,前端并发取 `GET /api/focus` 后合并,分堆也在这一步判定(按条目的**录入周**:本周录入的 + 更早周次标了「延期」又没做完的结转条目)。 定开项目的口径:`/api/weekly` 返回**本期有交付记录**、**被标为重点**、**本周期新入库**(`is_new`:入库日期落在本周期首末日之内)、**本周期新下单**(`sign_date` 落在本周期)或**本周期已验收**(`update_date` 落在本周期且项目状态为「已验收」)的定开项目;右栏总览默认列「本周新增」「本周验收」「本周有变化」三段,其中**前两段与「定开项目 → 本周进展」的「新增项目 / 验收情况」口径完全一致**(前者按「下单时间」、后者按「更新时间 + 状态=已验收」),其余只在组头计数里出现,并在底部提示「另有 N 个在途定开项目本周没有动态」。勾选总览头部的「列入全部在途」后,后端补上处于在途阶段(商机 → 已验收)的项目,总览多出一段「其他在途项目」。头部几枚标签与「合同额合计」只加总**当前列出来的行**(同一项目同时落在两段时只算一次),勾与不勾数字会跟着清单变。 ### 2. 项目管理 长期重点项目(`projects` + `tasks` + `updates`)。执行记录的写入逻辑没变,仍旧统一走「更新录入」。 | 模块 | 说明 | |---|---| | **项目管理** | 表格展示分类、负责人、状态、进度、更新情况(标签只在详情抽屉里维护,列表不放,避免挤占名称列);**列表只读**,行内不放任何输入框和下拉,每行只有 **详情 / 修改 / 归档** 三个按钮(操作列吸附在表格右侧,横向滚动也不会被挤出可视区);负责人筛选下拉来自人力资源库;支持新建与「含归档」筛选。详情抽屉里的**周期反馈**可切「按周 / 按月」与「本周 · 近 4 周 · 近 12 周 · 全部」(按月为「本月 · 近 3 月 · 近 6 月 · 全部」),用 ‹ › 翻页看更早的周期,默认跟随顶栏选中的周期 | > 「执行面板」不再单列模块,已折进工作看板底部的「统计概览」折叠区。 #### 项目维护操作 | 操作 | 说明 | |---|---| | **面板分区** | 抽屉用标准对话框式标题栏:**标题在左(下面一行副标题),基础信息的操作按钮成排在右,✕ 在最右**,按钮条嵌在标题栏里(不悬浮、不吸顶,滚动时跟着标题栏常驻)。详情档是「删除 · 归档/恢复 · 标记重点 · **修改**」,修改与新增档是「取消 · **保存/添加**」,主按钮永远在最右、危险动作在最左,按钮文字不再重复对象名(标题栏已经写了是哪个项目/条目)。附表的写入另放一处:**绿虚线 = 附表 · 更新记录**条仍留在它自己的附表标题下面,只有「+ 录一笔「某周期」执行记录 / 交付记录」,点它跳到「更新录入」并自动带上该项目与顶栏当前选中的周期。附表的写入统一走更新录入(粘贴原文 → AI 整理 → 确认写入),抽屉里不另做一套表单,避免两条路写出两份数据。基础信息的按钮在标题栏、附表的更新按钮在附表上方,两类按钮不在同一个位置混着放;编辑与新增档的报错信息显示在正文最上方;周期反馈上方的 按周/按月 + 本周/近 4 周/… 标成「查看范围(只读筛选)」,只翻看不改数据 | | **改名** | 改名就是改基本信息:在详情面板点「修改」,表单第一行即项目名称(项目管理与定开项目同一套逻辑)。名称非空校验 + 重名检测,失败信息显示在面板正文最上方,不弹提示跑路 | | **负责人与团队** | **多负责人只适用于重点项目**:重点项目可以指定**多个负责人**与**团队成员**,定开项目只有一个**交付负责人**(单人下拉)外加**团队成员**。人名一律从人力资源库下拉里选。**界面上负责人不分主次**:名单横向排开自动换行,每一位都带 × 可删(没有「主」标记、没有不给删的首行),「+ 添加负责人 / + 添加成员」跟在名单末尾。名单只在详情抽屉的「修改」档维护;只读处一律一排对等的小标签:重点项目的列表与详情把负责人摆成对等的一排,定开项目的列表与详情只显示一个交付负责人加团队成员标签。存储与统计口径不变:**重点项目 `owner` 字段仍是 `owners[0]`**(删掉第一位就由后一位顶上),看板、导出、人力负载与 KPI 按它归属,修改档的提示行写明了这点;重点项目**所有负责人都算命中**,定开项目按交付负责人命中;团队成员不参与该筛选 | | **归档** | 项目从看板与列表默认视图中隐藏,数据完整保留;勾选「含归档」可查看,随时可恢复 | | **删除** | 高危操作:弹窗列出将连带删除的子任务数与执行记录数,并且必须**逐字输入项目名称**,「永久删除」按钮才会点亮。**删除后不可恢复**,仅想隐藏请用归档 | > 定开项目的「项目明细」表同理:列表只读,操作列只有 详情 / 修改 / 归档,改名 / 名单 / 删除都在抽屉里做。 #### 项目合并 把两个项目合并成一个(例如把「智空无人机平台」并入「智飞无人机平台」): ```bash python scripts/merge_project.py --from "智空无人机平台" --to "智飞无人机平台" --dry-run python scripts/merge_project.py --from "智空无人机平台" --to "智飞无人机平台" ``` - 子任务同名 → 归并到目标项目的同名子任务,执行记录一并转挂 - 子任务仅源项目有 → 直接转到目标项目名下(保留原名) - 分类 / 负责人 / 描述 / 标签仅在目标缺失时继承 - 合并后按最新记录回算目标项目的进度与状态 - 执行前建议备份:`cp data/board.db data/board.db.bak` ### 3. 定开项目 | 模块 | 说明 | |---|---| | **交付流水线**(默认页签) | 卡头给「在库 N 个 · 重点 N 个 · 本期更新 N 个」,漏斗本身按环节给项目数与金额(页签上不再叠一条全局 KPI 带,金额与项目数按环节累计);「入库 → 签单 → 交付 → 验收 → 计收」五段漏斗,每段给项目数与金额;口径为**商务阶段 + 已录环节日期**取先到哪一步算哪一步(环节日期还没补全时由商务阶段兜底)。下方「卡点项目」列出最后一个**有日期**的环节停留超过 `CUSTOM_STEP_AGING_DAYS`(默认 45)天且尚未计收的项目,可一键「处理」跳到详情抽屉补录 | | **阶段看板** | 按「商机 → 已签单 → 开发中 → 交付完成 → 已验收 → 已计收 → 暂停/异常」分列展示,卡片带金额、区域、开发进度、可确认收入;列头显示项目数与金额合计。卡片只是入口,点卡片开详情抽屉;卡上的 ★ 只读(重点标记在详情面板的基础信息区改),外层不做任何直接写入 | | **财务跟踪** | 页签内一排 KPI:合同总额 / 按进度可确认收入 / 已计收 / 待计收 / 已开票 / 已回款 / 待开票 / 待回款(各带比例脚注);再往下是阶段金额分布、周期活跃度、按负责人与区域汇总、待回款排行。财务口径的汇总只在这一页出现,环节与账期一屏对齐,方便财务逐月对账 | | **项目明细** | 表头一行给出当前列表的合同额 / 可确认 / 已计收 / 开票 / 回款合计;按入库时间倒序的**只读**总表:区域 / 负责人 / **入库 · 签单 · 交付 · 验收日期** / 阶段 / 合同额 / 进度 / 可确认 / 已计收 / **开票 / 回款**(金额列统一以「万」计)/ 备注;改数据点行尾「修改」 | | **详情抽屉** | 分「详情 / 修改」两档:详情只读,修改才给表单(含项目名称、手动确认比例、**交付环节五个日期**、区域下拉、**开票与回款金额**)+ 收入确认卡 + 周期执行记录 + 阶段流转时间线。负责人从人力资源库里选。基础信息的动作在标题栏按钮条上(修改/保存,正文里标明不会动下面的交付记录),开票与回款金额跟着标题栏的「保存」一起提交;附表的绿虚线条(「+ 录一笔」跳更新录入 · 定开项目并带上项目与周期)留在附表标题下 | ### 4. 每周重点工作 不值得建项目档案的短期活儿:一条就是一个活儿,不用先建项目,录进来就能按周跟踪。 | 区块 | 说明 | |---|---| | **新增** | 工具栏「+ 新增重点工作」开**独立面板**(列表顶部那张内嵌录入卡已撤掉):**工作内容**(必填,一句话说清干什么)/ **说明**(可选)/ **录入周**(只读=顶栏当前选中的那一周,切周再录就归到那一周)/ **预计完成时间**(日历日期,只是目标日期,**不决定条目归到哪一周**)/ **执行状态**(取 `constants.STATUSES`)/ **结果反馈** / **是否延期**(人工开关)| | 列表 | 工作内容 / 说明(截断预览)/ 预计完成时间(下面小字标「录入 X月第N周」)/ 状态(标了延期且没完成的挂红色「延期」徽章)/ 更新日期 / 操作 **详情 · 修改 · 归档 · 删除**——和两张项目列表同一套规矩:列表只读,行内不放输入框 | | 筛选 | **本周 / 延期 / 已完成 / 全部** 四个堆(chip 上实时显示各堆条数)+「含归档条目」;顶栏切周即换基准周,工具栏标明「本周/延期按录入周统计」;顶部全局搜索同时匹配工作内容与说明 | | 详情抽屉 | 同样分「详情 / 修改」两档,**基础信息的按钮全在抽屉标题栏右侧的按钮条上**:详情档是「删除 · 归档 · **修改**」,修改与新增档是「取消 · **添加/保存**」,报错信息显示在正文最上方。点「修改」才出表单,**录入周只读**(改预计完成时间不会把条目搬去别的周)。重点工作条目没有附表,所以抽屉里不出现绿的更新条 | | 删除 | 列表行与抽屉顶部都能删,走同一个确认弹窗,并提示「只是这周不再跟进?请改用归档」。条目不挂子任务与执行记录,**不要求逐字输入名称**——逐字输入项目名称只用在项目管理与定开项目的项目删除上 | | 导出 | 右上角「导出 Excel」→ `GET /api/export/focus`,带上当前筛选条件 | | 联动 | 工作看板左栏**第一组**「本周工作重点」与 KPI「本周重点工作」读的就是这张表;看板右栏点条目给只读详情,改内容走抽屉 | 分堆口径(基准周 = 顶栏选中的那一周,一律按**录入周**算,和预计完成时间无关):录入周**等于**基准周 → **本周**;录入周**早于**基准周且「是否延期」打开且未完成 → **延期**(上周及更早没做完的活儿结转进来);状态为「已完成」→ **已完成**(交叉视图,条目仍留在自己那一周)。 「更早周次录入、没标延期又没完成」的条目不进当周视图,只在**全部**里查得到——所以每周收尾时,没做完的记得勾上「延期」,它才会结转进下周。库里不存「逾期」字段,延期是人工开关。 ### 人力资源库 侧栏「人力资源」,是全系统**负责人姓名的唯一来源**(`staff` 表)。 | 区块 | 说明 | |---|---| | 顶部 KPI | 在册人数与带项目人数、各归属小组人数、人员归属(汇智 / 云数 / 外服)分布,以及**花名册外的负责人**核对(历史数据里对不上花名册的人名,一个都不藏) | | 花名册 | 姓名 / 归属小组 / 人员归属 / 说明 + 该人的**在管项目数、定开项目数、定开合同额、名下待计收、最近更新**;小组与归属可行内改(下拉),说明行内编辑失焦即存 | | 筛选与导出 | 在编 / 已归档 / 全部 + 按小组筛选;「导出 Excel」按当前筛选导出 | | 新增 | 弹窗录入:姓名必填且全库唯一,小组与归属下拉取自 `constants.STAFF_GROUPS` / `STAFF_AFFILIATIONS` | | 改名 | 走「编辑」改姓名时,**名下项目与定开项目的负责人、其他负责人、团队成员一并同步改掉**,历史数据不会断链 | | 归档 / 恢复 | 归档后不再出现在「负责人」下拉里,但历史项目仍完整保留其负责人;随时可恢复。离职人员用归档,不要用删除 | | 删除 | 名下还挂着项目或定开项目时接口直接返回 400 并说明原因,防止把在管项目变成无主项目 | 导入名单(表头按名称匹配:序号 / 姓名 / 归属小组 / 人员归属 / 说明): ```bash python scripts/import_staff.py --dry-run # 只看解析结果 python scripts/import_staff.py # 增量导入(同名跳过,不覆盖页面上的编辑) python scripts/import_staff.py --reset # 清空后重新导入 python scripts/import_staff.py # 指定别的文件;首次运行 ./run.sh 会自动导入 ``` **负责人下拉**(`ownerSelectHtml`)在项目新建/详情、定开项目新建/详情、工作看板等位置统一使用,选项来自花名册: 已归档的人不再作为可选项出现,只有他本来就是这条记录的负责人时才带「(已归档)」标注出现一次; 历史数据里花名册没有的人名同样补一个「(不在花名册)」选项,保证打开老项目不会把负责人改没。 **多负责人与团队成员**复用同一个下拉(`peopleEditorHtml`,现在只有重点项目的抽屉用它):人名下拉**横向排开、自动换行**,选项同样只有花名册里的人,所以新增成员不需要另外维护一份名单;名单里的每一位都带 × 可删,界面上不区分主次。定开项目的负责人是普通的单个 `ownerSelectHtml` 下拉,只有团队成员用这套名单编辑器。 ### 入库时间 定开项目新增「入库时间」字段,当前口径为 **该项目最早记录所在周期的第一天(周一)**: - 优先取原始《项目明细表》台账中该项目所在的周(该列是稀疏填写的,导入时按周分组向下继承) - 台账没有的,取《周工作情况总结》「定制开发」块中该项目首次出现的周 - 再没有,依次退回 custom_updates 最早记录周期 → 项目所属周期 → 记录创建日期 周期换算规则:以**该月第一个周一**所在周为第 1 周,第 N 周顺延 `7×(N-1)` 天。 例如 `2026年8月第4周` → `2026-08-24`(2026-08-01 是周六,第一个周一是 08-03)。 字段可在明细表中直接改,也可在抽屉里改;重新计算用: ```bash python scripts/add_entry_date.py --dry-run # 预演 python scripts/add_entry_date.py # 回填(跳过已有值) python scripts/add_entry_date.py --force # 全部重算 ``` ### 区域(省级行政区) - 编辑时是**规范下拉**,34 个省级行政区按大区分组(华北 / 东北 / 华东 / 华中 / 华南 / 西南 / 西北) - 列表筛选下拉同样使用规范名称,只列出实际有项目的区域 - 历史数据里若出现「内蒙古自治区」这类非规范写法,保存时会自动归一为「内蒙古」 - 早期从项目名推断的区域(`infer_region`)与标准列表口径一致,无需迁移 ## 界面设计语言 前端是零构建的原生 JS(`web/index.html` + `web/styles.css` + `web/app.js` + `web/icons.js`),设计口径固定如下,新增页面请沿用: - **禁用「彩色描边」**:卡片、列表、步骤条、表格一律中性灰边框(`--border` / `--border-strong`)或无边框,不用圆角多色边框表达状态。 - **重点色只出现在三处**:图标、关键数字/文本、小面积 tinted 底板(`.ic-badge`、`.tag-mini`、`.kpi.accent-*`)。状态色(`statusMeta`)与阶段色(`stageMeta`)是唯一配色来源,避免各页面自己调色。 - **图标系统**:`web/icons.js` 内置 50 个 24×24 线性 SVG,`stroke=currentColor`,颜色跟着文字走。对外 API: `svg(name)` 裸图标;`badge(name)` 图标 + tinted 底板(KPI 用);`status()` / `stage()` / `pipe()` 按状态·阶段·交付环节取图标; `nameOfStatus()` / `nameOfStage()` / `statusBadge()` 出文案与徽标;`hydrate()` 填 `[data-icon]`;`auto()` 自动补前导图标;`names()` 列全部图标名。 - **自动图标**:`auto()` + `MutationObserver` 在每次渲染后按标题关键词给 `.card-head h4` / `.sec-title` / `.kcol-title` / `.wk-group-head` / `.notice` / `.empty` 加前导图标,并填充 `[data-icon]`;用 `data-ico` 属性防重复,标题里**自带** ``(如阶段看板按阶段取图标)时跳过自动补图,不会出现两个图标。新增区块只要标题里带对应关键词就自动带图标,不用手写。 - **阶段看板列头不带色条**:列头用 `Ico.stage(code)` + `--c` 注入阶段色(`.kcol-title .ic { color: var(--c) }`),早期那种 `border-top:3px solid 阶段色` 的彩条已去掉。 - **交付环节图标按 `code` 取**:后端 `CUSTOM_PIPELINE` 下发的字段是 **`code`**(不是 `key`),前端一律 `Ico.pipe(s.code)`;写成 `s.key` 会静默退化成通用圆点。 - **表格防竖排**:`table.tbl th` / `.pill` / `.tag-mini` 统一 `white-space:nowrap`,容易挤窄的列(区域、负责人)在 `` 上加 `class="nowrap"`;实在挤不下交给 `.tbl-wrap { overflow:auto }` 横向滚动。 - **抽屉不被内容撑破**:`.form-row > div { min-width: 0 }`(grid 子项默认 `min-width:auto`,会被交付环节步骤条撑出整表横向滚动),步骤条本身 `flex:1 1 132px`(132px = 日期输入框含日历图标的最小可用宽度)。 > 备注:`styles.css` 里的 `.pcard`、`.board-grid` 当前没有任何 JS 引用(历史遗留样式),此处只做记录,未删除。 ## 数据导出 各列表页右上角均有 **导出 Excel**,导出内容会带上页面当前的筛选条件: | 位置 | 导出内容 | 接口 | |---|---|---| | 定开项目 | 定开项目明细(含区域、金额、进度、收入确认、入库时间、备注 + 合计行) | `GET /api/export/custom` | | 定开项目 | 定开项目周期记录 | `GET /api/export/custom-updates` | | 项目管理 | 项目管理清单(分类、负责人、状态、标签、子任务数等) | `GET /api/export/projects` | | 工作看板 | 本周期(或本月)的执行记录明细 | `GET /api/export/updates` | | 每周重点工作 | 重点工作清单(工作内容 / 说明 / 预计完成时间 / 录入周 / 执行状态 / 是否延期 / 结果反馈 / 更新) | `GET /api/export/focus` | | 人力资源库 | 花名册(含在管 / 定开项目数、合同额、待计收) | `GET /api/export/staff` | 导出的 xlsx 带表头样式、冻结首行、自动筛选,金额列按千分位格式;文件名含导出日期。 ## 收入确认口径 定开项目按**完工百分比法**确认收入: | 阶段 | 确认比例 | |---|---| | 商机/报备 | 0% | | 已签单/下单 | 10% | | 开发中 | 10% + 40% × 开发进度 | | 交付完成 | 70% | | 已验收 | 90% | | 已计收 | 100% | | 暂停/异常 | 30% | | 已关闭 | 100% | - **可确认收入** = 合同额 × 上表比例 - **待计收** = 可确认收入 − 已计收 - **待开票** = 合同额 − 已开票、**待回款** = 合同额 − 已回款(均不小于 0,随开票 / 回款金额自动更新) - 开票与回款金额在项目详情抽屉、定开项目详情抽屉、工作看板右栏都能直接填 - 项目上可填「手动确认比例」覆盖阶段推算(用于预付、分批收款等特殊情形) - 比例定义见 `app/constants.py::CUSTOM_STAGES` 与 `custom_revenue_ratio()`,改一处即可全局生效 ## 数据模型 ``` # 项目管理(长期重点项目) Period(周期: 年/月/周, sort_key) └── Project(分类, 负责人 owners[0], 其他负责人, 团队成员, 状态, 优先级, 重点标记, 进度, 标签) ├── Task(子任务) └── Update(执行情况: 正文, 摘要, 进度, 状态, 风险, 下一步, 来源, 原文) # 定开项目(独立) CustomProject(名称, 客户, 区域, 合同额, 阶段, 开发进度, 手动确认比例, 已计收金额, 交付负责人(单人), 团队成员, 入库/签单/交付/验收/计收日期, 开票/回款金额, 重点, 归档) # 定开项目不做多负责人:other_owners 列保留在库里但不再读写 └── CustomUpdate(周期, 阶段, 内容, 进度, 本期新增下单, 本期新增计收, 风险, 下一步) # 每周重点工作(独立:条目不是项目,不挂子任务与执行记录) WeeklyFocus(工作内容, 说明, 录入周→Period, 预计完成时间, 执行状态, 是否延期, 结果反馈, 归档) Staff(姓名, 归属小组, 人员归属, 说明, 排序, 归档) # 花名册:所有「负责人 / 团队成员」下拉的唯一来源 Category / Tag / Setting / ImportLog LedgerItem(客户项目台账) # 只剩模型与 Excel 导入解析,界面无入口、接口已下线 ``` 原表映射关系: - `周工作情况总结`:**时间** → Period;**工作内容** → Project;**内容说明** → Task;**完成情况** → Update (三列均为稀疏填充,导入时逐级向下继承;仅填「完成情况」的行作为上一条记录的续行合并) - 原「定制开发」的 92 个子任务 → `custom_projects`(名称尾部的金额如「(39,400.00)」会被解析成合同额) - `项目明细表` 39 条台账 → `custom_projects`(区域 / 金额 / 类别→阶段 / 状态说明),与子任务同名时自动合并 ## AI 整理 两套体系各有独立提示词: - **项目管理**(常规执行记录):抽取 摘要 / 进度 / 状态 / 子任务列表 / 风险 / 下一步 - **定开项目类**:抽取 商务阶段 / 开发进度 / 合同额 / 累计计收 / 本期新增计收 / 摘要 / 风险 / 下一步 / 本期明细 - **每周重点工作**不过 AI:在独立面板里直接填(工作内容 / 说明 / 预计完成时间填日历日期 / 执行状态) - 默认走 **OpenAI 兼容协议**,支持 DeepSeek、通义千问(兼容模式)、Moonshot、智谱、OpenAI、本地 Ollama 等。 - Ollama 示例:Base URL `http://localhost:11434/v1`,模型 `qwen2.5:14b`,Key 任意填。 - **未配置 API Key 时自动降级为本地规则解析**:按编号切分事项、正则提取百分比与金额、 关键词判定阶段 —— 无需 Key 也能完成录入。 - 阶段判定做了特殊处理:文本里同时出现「已计收」和「进度 60%」时判为**开发中**,计收金额由 `revenue_delta` 承载。 - 解析结果写入前始终提供**可编辑预览**,确认后才落库,并留痕到 `import_logs`。 ## 迁移到 MySQL 1. 安装驱动:`pip install pymysql cryptography` 2. 修改 `.env`: ``` DATABASE_URL=mysql+pymysql://user:password@127.0.0.1:3306/unis_board?charset=utf8mb4 ``` 3. 重启服务(表结构自动创建),再依次执行 `import_excel.py --reset` 与 `migrate_custom.py`。 数据访问层全部使用 SQLAlchemy ORM,无原生 SQL、无 SQLite 专有语法,切换方言无需改业务代码。 ## 目录结构 ``` app/ main.py FastAPI 入口(API 挂载在 /api,静态页面在 /) config.py 配置与 .env 加载(DATABASE_URL、AI 参数) db.py engine / Session(按 URL 自动适配方言) models.py ORM 模型(项目 + 定开项目 + 每周重点工作 + 花名册) constants.py 状态/阶段常量、收入确认比例、区域与阶段识别 ai_parser.py LLM 解析 + 本地规则兜底(通用 / 定开两套) routers/ board(周期/元数据/统计) · weekly(工作看板数据) · projects(项目管理) · custom(定开项目) · focus(每周重点工作) · staff(人力) · ai · export web/ index.html · styles.css · app.js(零依赖,无构建步骤) scripts/ init_db.py · import_excel.py · migrate_custom.py · import_staff.py · add_entry_date.py · merge_project.py · shift_year.py data/board.db SQLite 数据库 ``` ## API 速览 ``` # 通用 GET /api/meta 状态字典 / 优先级 / AI 配置状态 GET /api/periods 周列表 + 按月聚合(含各周期记录数;today_id = 今天所在的周,顶栏默认落它) POST /api/periods 新增周期(传 label 如「9月第1周」,年份自动接续) DELETE /api/periods/{id} 删除空周期(有记录则拒绝) GET /api/board?period_id=|year&month 周期汇总(页面主链路不走它,统计走 /api/stats) GET /api/stats?period_id=|year&month GET /api/weekly?period_id=|year&month&owner=&all_custom= 工作看板:重点项目 + 定开项目本周动态 + KPI (custom_new 本期新入库 / custom_updated 本期有交付记录;行上带 is_new) (左栏第一组「本周工作重点」前端另取 /api/focus 合并) GET /api/projects (?archived=false|true|all) POST /api/projects PATCH /api/projects/{id} DELETE /api/projects/{id} (owners/members 传人名数组,整体替换:不传=不改,传 []=清空;owners[0] 回写 owner 列供归属统计,界面不再区分主次) GET /api/categories POST /api/categories PATCH /api/categories/{id} DELETE /api/categories/{id} # 定开项目 GET /api/custom/meta 阶段字典 + 区域列表 + 交付环节(pipeline) + 卡点阈值(aging_days) GET /api/custom/projects?stage=®ion=&keyword= POST /api/custom/projects PATCH /api/custom/projects/{id} DELETE /api/custom/projects/{id} (owner 是单个人名;members 传人名数组,整体替换:不传=不改,传 []=清空。不再接受 owners,多负责人只属于重点项目) GET /api/custom/board?period_id=|year&month 阶段看板 GET /api/custom/stats?period_id=|year&month 收入统计 POST /api/custom/updates POST /api/custom/ai/parse 粘贴文本 → 结构化预览 POST /api/custom/ai/commit 确认写入 # 每周重点工作 GET /api/focus?archived=false|true|all&status=&keyword= 条目清单(period_id/period_label/sort_key 都是**录入周**,分堆由调用方判定) POST /api/focus PATCH /api/focus/{id} DELETE /api/focus/{id} 单条增改删;工作内容非空。period_id=录入周(前端传顶栏当前周, 不传后端按今天所在的周补;due_date 只是目标日期,不改归属周) 或直接给 period_id(必须存在);两者都不给 → 400 # 人力资源库 GET /api/staff?archived=false|true|all&group=&keyword= 花名册 + 各自工作量 + 花名册外负责人 + 小组/归属字典 POST /api/staff PATCH /api/staff/{id} DELETE /api/staff/{id}(名下有项目时拒绝,离职请归档) # 其他 GET /api/settings PUT /api/settings # 导出(均返回 xlsx) GET /api/export/custom ?region=&stage=&keyword=&archived= GET /api/export/custom-updates ?period_id=|year&month GET /api/export/projects ?category_id=&keyword=&archived= GET /api/export/staff ?archived=false|true|all GET /api/export/focus ?archived=false|true|all&status=&keyword= GET /api/export/updates ?period_id=|year&month&project_id= ```