410 lines
34 KiB
Markdown
410 lines
34 KiB
Markdown
# 软件开发部 · 关键任务追踪看板
|
||
|
||
基于《软件开发部管理工作执行表.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
|
||
```
|
||
|
||
打开 <http://127.0.0.1:8770>
|
||
|
||
首次运行 `run.sh` 会自动完成:选择带依赖的 Python 解释器 → 缺依赖则安装 → 建库 → 导入历史 Excel → 拆分定制交付项目,然后启动并打开浏览器。
|
||
|
||
### 启动方式与排错
|
||
|
||
| 场景 | 命令 |
|
||
|---|---|
|
||
| 正常启动 | `./run.sh` |
|
||
| 报 `permission denied` | `chmod +x run.sh` 后重试(**不要用 sudo**) |
|
||
| 不想改权限 | `bash run.sh` |
|
||
| 换端口 | `PORT=8771 ./run.sh` |
|
||
| 开发模式热加载 | `DEV=1 ./run.sh` |
|
||
| 不自动开浏览器 | `NO_OPEN=1 ./run.sh` |
|
||
| 提示"端口已被占用" | 原窗口 `Ctrl+C`,或 `lsof -ti:8770 \| xargs kill` 后重跑 |
|
||
|
||
> ⚠️ 不要用 `sudo` 启动:数据库文件会变成 root 属主,后续写入会失败。
|
||
|
||
> **DEV=1 热加载**:uvicorn 除 `*.py` 外还会监听 `web/**` 的 js/css/html 与 `.env`,改动即重启;
|
||
> 页面里的 `web/livereload.js` 每秒读一次 `/health` 的启动代际,发现服务重启后自动刷新浏览器。
|
||
> 非 DEV 启动时该脚本首轮即自行停止,`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 <xlsx> --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`:入库日期落在本周期首末日之内)的定制项目;右栏总览默认只列「本周新增」与「本周有变化」两段,其余只在组头计数里出现,并在底部提示「另有 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 <xlsx> # 指定别的文件;首次运行 ./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` 属性防重复,标题里**自带** `<svg class="ic">`(如阶段看板按阶段取图标)时跳过自动补图,不会出现两个图标。新增区块只要标题里带对应关键词就自动带图标,不用手写。
|
||
- **阶段看板列头不带色条**:列头用 `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`,容易挤窄的列(区域、负责人)在 `<td>` 上加 `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=
|
||
```
|