init: init proj
This commit is contained in:
103
CLAUDE.md
Normal file
103
CLAUDE.md
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
本项目是**报价工作区**:输入一份 PDR(产品需求文档)或简短项目概述,输出一份报价单 xlsx(必要时附开发排期表)。所有规则提炼自西藏移动项目管理平台系列历史报价(2025-06,来源:`/Users/kid/Development/Fusion/Projects/tibet-mobile/documents/`,副本见 `reference/`)。
|
||||||
|
|
||||||
|
## 目录约定
|
||||||
|
|
||||||
|
- `input/<项目名>/` —— 存放报价参考材料(PDR、概述、会议纪要等)
|
||||||
|
- `output/<项目名>/` —— 输出的报价单、排期表
|
||||||
|
- `scripts/` —— 生成 xlsx 的 Python 脚本(openpyxl)
|
||||||
|
- `reference/` —— 历史报价单与排期表副本,作为格式模板和估算参照
|
||||||
|
|
||||||
|
## 核心报价规则
|
||||||
|
|
||||||
|
### 单价与金额
|
||||||
|
|
||||||
|
- **单价按项目确认**:历史默认 1000 元/人天(西藏移动系列),也有按 1200 元/人天计的项目(生产系统 AI 项目,2026-08)。每次报价在确认口径时问清单价。
|
||||||
|
- 金额一律用公式:`=D4*<单价>`,合计用 `=SUM(...)`,绝不硬编码数字。
|
||||||
|
- 人天允许 0.5 天粒度(历史例:4.5、1.5)。
|
||||||
|
|
||||||
|
### 计费结构(关键口径)
|
||||||
|
|
||||||
|
1. **全新系统**按四大类计全量:
|
||||||
|
- 公共底座(初始化/认证/权限/审批流/文件服务)
|
||||||
|
- 业务功能
|
||||||
|
- 测试与交付(联调自测 + 系统测试/UAT + 部署上线)
|
||||||
|
- 项目管理(需求/文档/沟通)
|
||||||
|
2. **同一系统的新增模块**只计业务功能增量——公共底座、测试与交付、项目管理为一次性投入,不重复计费,并在报价单说明行写明该口径。
|
||||||
|
3. **复用模块人天计 0**,保留行项并在名称后注明(复用),例如「RBAC 权限管理(复用)」「欠费催缴工单(复用,随相关模块交付)」——让客户看到功能范围但不收费,这是历史报价的展示习惯。
|
||||||
|
4. **复用框架只算差异**:如「支出计划确认(复用收入确认框架,仅算差异)」计 4 天,而完整的收入计划编制计 10 天。
|
||||||
|
|
||||||
|
### 人天估算基准(历史校准值)
|
||||||
|
|
||||||
|
| 工作项类型 | 参考人天 | 历史例证 |
|
||||||
|
|---|---|---|
|
||||||
|
| 项目初始化+模块接入+脚手架+CI/CD | 3 | DICT 底座 |
|
||||||
|
| 统一认证对接(如中国移动 4A)+登录页 | 2 | DICT 底座 |
|
||||||
|
| 审批流接入配置 | 1/条 | 4 条流程 4 天 |
|
||||||
|
| 文件服务+Excel 导入导出 | 3 | DICT 底座 |
|
||||||
|
| 简单列表页(列表/查询/简单表单) | 4 | 线索管理 4、线索录入 4 |
|
||||||
|
| 标准业务模块(列表+表单+详情) | 5–7 | 合同管理 6、项目管理 7、专属云 5 |
|
||||||
|
| 较重业务模块(多子页/多状态流转) | 8–9 | 商机管理 8、5G 泛项目 9、大单填报 9、激励管理(三级审批)9 |
|
||||||
|
| 复杂模块(多段表单/评分模型/多 Tab 审核) | 10–12 | 商机录入 12、招标信息 10、收入计划编制 10 |
|
||||||
|
| 报表 | 约 1.5/张 | 6 张报表 9 天 |
|
||||||
|
| 工单类(创建/我的/处理) | 5–6 | 售前支撑工单 6、欠费催缴类似 |
|
||||||
|
| Dashboard 首页 | 5 | 登录后首页 |
|
||||||
|
| 待办/消息/个人工作台 | 6(复用后 2) | 我的 6、我的商机 2 |
|
||||||
|
| AI 文档智能解析(PDF/Excel 提取) | 6 | 融业财智能化 |
|
||||||
|
| 外部系统对接联调 | 约 1–1.5/系统 | 4 系统 5 天 |
|
||||||
|
| 流程节点类(审批链/状态机节点) | 简单 1.5–3,含外部对接或多步流程 4–5,重节点 7–10 | 360 视图 17 节点共 74 天 |
|
||||||
|
| 联调+自测+Bug 修复 | 业务规模的比例项 | DICT 为 8 天 |
|
||||||
|
| 系统测试/UAT | 同上 | DICT 为 5 天 |
|
||||||
|
| 部署上线 | 3 | DICT |
|
||||||
|
| 项目管理+需求+文档+沟通 | 全项目约 10% | DICT 108.5 天中占 10 天 |
|
||||||
|
|
||||||
|
整体校验参考:测试与交付合计约占(底座+业务)人天的 **20%**;项目管理约占总人天的 **10%**。估算完成后用这两个比例反查是否失衡。
|
||||||
|
|
||||||
|
### 估算方法
|
||||||
|
|
||||||
|
1. 通读输入材料,把需求拆成「类别 → 功能模块/工作项」两级清单,粒度对齐历史报价(一个工作项 ≈ 2–12 天,超过 12 天要再拆)。
|
||||||
|
2. 每个工作项对照上方基准表定人天;无先例的按最接近的类型内插,并在说明中标注假设。
|
||||||
|
3. 识别可复用项(本次或历史已有实现),按规则计 0 或只算差异。
|
||||||
|
4. 判断是全新系统还是新增模块,决定是否计列底座/测试/项目管理。
|
||||||
|
5. 出数后做比例校验,再与同量级历史项目总量对比(DICT 全系统 108.5 天、融业财模块 56 天、拓商机模块 46 天、360 视图专项 74 天)。
|
||||||
|
|
||||||
|
## 去 AI 味(所有交付物硬性要求)
|
||||||
|
|
||||||
|
最终产物(报价单、排期表、Word/PDF 文档等)会直接发给客户,不能让人看出是 AI 制作的:
|
||||||
|
|
||||||
|
- **少说明、不解释**。不写「本文档旨在」「以下是」「需要注意的是」「综上所述」之类的引导语和总结语;不解释自己为什么这样做;交付文件里不放说明文案。
|
||||||
|
- **不穷举**。范围说明、备注只写重点三四项,不把功能点从头到尾列全——逐项穷举是 AI 的典型痕迹,人只挑要紧的写。
|
||||||
|
- **文字简单直接**。工作项名称、范围说明照实写,不堆修饰词,不写排比句和对称句式,不用「全面」「高效」「赋能」「一站式」这类空词。
|
||||||
|
- **克制的结构**。不为了显得完整而加多余的列、sheet、图例、注释;历史模板里没有的元素不主动加。
|
||||||
|
- **不用 emoji、不用分割线、不用加粗滥用**。文档里加粗只用于标题和合计等惯例位置。
|
||||||
|
- **像人手写的 Excel**。允许小的不完美:说明行就是一行普通小字,不做成花哨的信息框;没有页眉页脚水印。
|
||||||
|
- 交付前通读一遍,问自己:这份东西像不像一个熟手售前顺手做出来的?像才算过关。
|
||||||
|
|
||||||
|
## 报价单格式规范(xlsx)
|
||||||
|
|
||||||
|
用 openpyxl 生成,样式严格对齐 `reference/` 中的模板:
|
||||||
|
|
||||||
|
- **文件命名**:`<项目名>报价单.xlsx`;多子系统合并版可加后缀,如 `(合并)`、`(含XX专项)`。
|
||||||
|
- **Sheet 结构**:每份报价单固定含两类 sheet——首 sheet「报价汇总」+ 明细 sheet(单系统一个「报价明细」,多子系统时每个子系统各一个)。汇总表颗粒度为功能模块/子系统级(每个功能一行,外加底座、测试与交付、项目管理各一行),人天与金额用跨表引用或 `=SUM('报价明细'!D4:D8)` 这类区间引用,不抄数字。
|
||||||
|
- **明细表列**:`序号 | 类别 | 功能模块 / 工作项 | 人天 | 金额(元)`,列宽约 `6 / 12 / 48 / 9 / 15`;汇总表列 `序号 | 子系统 / 模块 | 范围说明 | 人天 | 金额(元)`,列宽约 `6 / 26 / 40 / 10 / 16`。
|
||||||
|
- **样式**:全表微软雅黑(Microsoft YaHei)11 号;标题行 15 号加粗白字、深蓝底 `1F4E79`、跨列合并;表头行加粗白字深蓝底;「类别」列纵向合并、浅蓝底 `DDEBF7`;合计行加粗、绿底 `C6E0B4`;全表细边框;人天/金额右对齐,功能项左对齐,其余居中,自动换行。
|
||||||
|
- **不加说明行**(用户确认的偏好,2026-08):表格下方不放说明文案,单价、复用口径、二期范围这类信息在对话里向用户交代,不写进交付文件;确有必须随文件传达的口径时,先问用户。
|
||||||
|
- **交付前必查**:跑 recalc 确认零公式错误;核对合计;按码点检查中文正文无残留半角标点(,。()等必须全角);按「去 AI 味」标准通读一遍。
|
||||||
|
|
||||||
|
## 排期表格式规范(如需)
|
||||||
|
|
||||||
|
参照 `reference/西藏移动项目管理平台开发排期.xlsx`:
|
||||||
|
|
||||||
|
- Sheet 1「开发排期甘特图」:`序号 | 子系统 | 类别 | 功能模块/工作项 | 开始 | 结束` + 逐日日期列,用子系统配色填充甘特条;复用项不排期,在名称后注明「(复用,随相关模块交付)」。
|
||||||
|
- Sheet 2「关键里程碑」:M1 底座就绪 → M2 核心功能 → M3 扩展模块 → M4 系统测试/UAT → M5 部署上线,各配计划完成日与阶段交付物。
|
||||||
|
- 排期天数与报价人天解耦:多人并行时日历工期 < 总人天(历史例:108.5+ 人天压缩在 18 个日历日内完成)。
|
||||||
|
|
||||||
|
## 工作流程
|
||||||
|
|
||||||
|
新报价任务的标准步骤:
|
||||||
|
|
||||||
|
1. 把用户给的材料存入 `input/<项目名>/`(如用户直接给路径则原地读取)。
|
||||||
|
2. 按「估算方法」产出模块清单与人天,先以 Markdown 表格形式给用户过目确认口径(是否含底座、单价是否 1000 等有疑义时询问)。
|
||||||
|
3. 确认后写脚本生成 xlsx 到 `output/<项目名>/`,跑 recalc 验证。
|
||||||
|
4. 汇报总人天、总金额及与历史同量级项目的对比。
|
||||||
BIN
output/生产系统/生产系统开发报价单.xlsx
Normal file
BIN
output/生产系统/生产系统开发报价单.xlsx
Normal file
Binary file not shown.
BIN
reference/拓商机系统报价单.xlsx
Normal file
BIN
reference/拓商机系统报价单.xlsx
Normal file
Binary file not shown.
BIN
reference/融业财系统报价单.xlsx
Normal file
BIN
reference/融业财系统报价单.xlsx
Normal file
Binary file not shown.
BIN
reference/西藏DICT项目管理系统报价单.xlsx
Normal file
BIN
reference/西藏DICT项目管理系统报价单.xlsx
Normal file
Binary file not shown.
BIN
reference/西藏移动项目管理平台开发排期.xlsx
Normal file
BIN
reference/西藏移动项目管理平台开发排期.xlsx
Normal file
Binary file not shown.
BIN
reference/西藏移动项目管理平台报价单(合并).xlsx
Normal file
BIN
reference/西藏移动项目管理平台报价单(合并).xlsx
Normal file
Binary file not shown.
BIN
reference/西藏移动项目管理平台报价单(含360视图专项).xlsx
Normal file
BIN
reference/西藏移动项目管理平台报价单(含360视图专项).xlsx
Normal file
Binary file not shown.
197
scripts/gen_production_quote.py
Normal file
197
scripts/gen_production_quote.py
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
# 生产系统开发报价单生成脚本(单价 1200 元/人天)
|
||||||
|
import openpyxl
|
||||||
|
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
|
||||||
|
from openpyxl.utils import get_column_letter
|
||||||
|
|
||||||
|
RATE = 1200
|
||||||
|
OUT = "output/生产系统/生产系统开发报价单.xlsx"
|
||||||
|
|
||||||
|
FONT = "Microsoft YaHei"
|
||||||
|
DARK = "1F4E79"
|
||||||
|
LIGHT = "DDEBF7"
|
||||||
|
GREEN = "C6E0B4"
|
||||||
|
|
||||||
|
thin = Side(style="thin", color="BFBFBF")
|
||||||
|
border = Border(left=thin, right=thin, top=thin, bottom=thin)
|
||||||
|
|
||||||
|
# 明细数据:(类别, 工作项, 人天)
|
||||||
|
items = [
|
||||||
|
("公共底座", "项目初始化+模块接入+前端脚手架+CI/CD", 3),
|
||||||
|
("公共底座", "登录+用户权限管理", 3),
|
||||||
|
("公共底座", "文件服务+Excel/报表导出", 3),
|
||||||
|
("公共底座", "OPC/Modbus数据采集服务(协议接入+点位配置+断线重连+采集入库)", 8),
|
||||||
|
("公共底座", "DCS历史站历史数据接入", 3),
|
||||||
|
("报表系统", "自定义生产日报表(模板配置+自动生成)", 6),
|
||||||
|
("报表系统", "生产过程数据查询、统计", 4),
|
||||||
|
("报表系统", "多批次数据对比分析", 4),
|
||||||
|
("报表系统", "趋势、异常、合格率分析", 5),
|
||||||
|
("批次管理", "Batch批次管理(定义/启停/列表查询)", 6),
|
||||||
|
("批次管理", "每釜过程数据记录(温度/压力/流量/液位曲线)", 6),
|
||||||
|
("批次管理", "原料、设备、人员、生产时间基础资料管理", 5),
|
||||||
|
("批次管理", "阶段性及最终物料指标录入与批次关联", 4),
|
||||||
|
("批次管理", "批次数据查询与追溯", 4),
|
||||||
|
("批次管理", "AI训练/推理数据集构建(抽取/清洗/版本管理)", 5),
|
||||||
|
("AI指标预测", "生产数据清洗与特征提取", 6),
|
||||||
|
("AI指标预测", "纯度预测模型建立与训练(单设备基准模型)", 8),
|
||||||
|
("AI指标预测", "多设备模型复制框架(按设备独立训练与管理)", 4),
|
||||||
|
("AI指标预测", "实时预测服务与结果展示", 5),
|
||||||
|
("AI指标预测", "预测值与实际检测值对比", 3),
|
||||||
|
("AI指标预测", "模型持续训练与优化", 5),
|
||||||
|
("工艺反向优化", "生产工艺-物料指标关联模型", 5),
|
||||||
|
("工艺反向优化", "根据目标指标反向计算工艺参数(寻优算法)", 8),
|
||||||
|
("工艺反向优化", "原料配比优化(原液添加量建议)", 5),
|
||||||
|
("工艺反向优化", "最佳工艺方案生成与展示", 4),
|
||||||
|
("工艺反向优化", "AI工艺调整建议", 3),
|
||||||
|
("工艺反向优化", "实际执行结果记录与模型迭代", 3),
|
||||||
|
("DCS智能控制", "AI模型/Agent服务接入与调度", 6),
|
||||||
|
("DCS智能控制", "DCS实时数据分析与调整方案生成", 5),
|
||||||
|
("DCS智能控制", "参数上下限与安全约束控制", 4),
|
||||||
|
("DCS智能控制", "半自动控制(人工确认后经OPC下发指令)", 6),
|
||||||
|
("DCS智能控制", "控制执行记录与追溯", 2),
|
||||||
|
("测试与交付", "联调+自测+Bug修复", 14),
|
||||||
|
("测试与交付", "系统测试/UAT", 9),
|
||||||
|
("测试与交付", "部署上线", 4),
|
||||||
|
("项目管理", "项目管理+需求+文档+沟通", 16),
|
||||||
|
]
|
||||||
|
|
||||||
|
# 汇总行:(名称, 范围说明),区间由类别在明细中的行号推出
|
||||||
|
summary_rows = [
|
||||||
|
("公共底座", "脚手架、权限、OPC/Modbus采集、DCS历史数据接入"),
|
||||||
|
("报表系统", "生产日报表、查询统计、对比与合格率分析"),
|
||||||
|
("批次管理", "批次与过程数据记录、指标关联、追溯、AI数据集"),
|
||||||
|
("AI指标预测", "纯度预测模型、实时预测、持续优化"),
|
||||||
|
("工艺反向优化", "反向寻优、原料配比、最佳工艺方案"),
|
||||||
|
("DCS智能控制", "实时分析、安全约束、半自动控制"),
|
||||||
|
("测试与交付", "联调自测、系统测试/UAT、部署上线"),
|
||||||
|
("项目管理", "项目管理、需求、文档、沟通"),
|
||||||
|
]
|
||||||
|
|
||||||
|
wb = openpyxl.Workbook()
|
||||||
|
|
||||||
|
# ---------- 报价明细 ----------
|
||||||
|
ws = wb.active
|
||||||
|
ws.title = "报价明细"
|
||||||
|
ws.merge_cells("A1:E1")
|
||||||
|
c = ws["A1"]
|
||||||
|
c.value = "生产系统 — 开发报价单"
|
||||||
|
c.font = Font(name=FONT, size=15, bold=True, color="FFFFFF")
|
||||||
|
c.fill = PatternFill("solid", fgColor=DARK)
|
||||||
|
c.alignment = Alignment(horizontal="center", vertical="center", wrap_text=True)
|
||||||
|
ws.row_dimensions[1].height = 34
|
||||||
|
|
||||||
|
headers = ["序号", "类别", "功能模块 / 工作项", "人天", "金额(元)"]
|
||||||
|
for i, h in enumerate(headers, 1):
|
||||||
|
c = ws.cell(row=3, column=i, value=h)
|
||||||
|
c.font = Font(name=FONT, size=11, bold=True, color="FFFFFF")
|
||||||
|
c.fill = PatternFill("solid", fgColor=DARK)
|
||||||
|
c.alignment = Alignment(horizontal="center", vertical="center", wrap_text=True)
|
||||||
|
c.border = border
|
||||||
|
ws.row_dimensions[3].height = 24
|
||||||
|
|
||||||
|
cat_ranges = {} # 类别 -> (起始行, 结束行)
|
||||||
|
row = 4
|
||||||
|
for idx, (cat, name, days) in enumerate(items, 1):
|
||||||
|
ws.cell(row=row, column=1, value=idx)
|
||||||
|
ws.cell(row=row, column=2, value=cat)
|
||||||
|
ws.cell(row=row, column=3, value=name)
|
||||||
|
ws.cell(row=row, column=4, value=days)
|
||||||
|
ws.cell(row=row, column=5, value=f"=D{row}*{RATE}")
|
||||||
|
for col in range(1, 6):
|
||||||
|
c = ws.cell(row=row, column=col)
|
||||||
|
c.font = Font(name=FONT, size=11)
|
||||||
|
c.border = border
|
||||||
|
if col == 3:
|
||||||
|
c.alignment = Alignment(horizontal="left", vertical="center", wrap_text=True)
|
||||||
|
elif col in (4, 5):
|
||||||
|
c.alignment = Alignment(horizontal="right", vertical="center", wrap_text=True)
|
||||||
|
else:
|
||||||
|
c.alignment = Alignment(horizontal="center", vertical="center", wrap_text=True)
|
||||||
|
if cat not in cat_ranges:
|
||||||
|
cat_ranges[cat] = [row, row]
|
||||||
|
cat_ranges[cat][1] = row
|
||||||
|
row += 1
|
||||||
|
|
||||||
|
total_row = row
|
||||||
|
# 类别列合并 + 填色
|
||||||
|
for cat, (r1, r2) in cat_ranges.items():
|
||||||
|
if r2 > r1:
|
||||||
|
ws.merge_cells(start_row=r1, start_column=2, end_row=r2, end_column=2)
|
||||||
|
a = ws.cell(row=r1, column=2)
|
||||||
|
a.fill = PatternFill("solid", fgColor=LIGHT)
|
||||||
|
for r in range(r1, r2 + 1):
|
||||||
|
ws.cell(row=r, column=2).fill = PatternFill("solid", fgColor=LIGHT)
|
||||||
|
|
||||||
|
ws.merge_cells(start_row=total_row, start_column=1, end_row=total_row, end_column=3)
|
||||||
|
ws.cell(row=total_row, column=1, value="合计")
|
||||||
|
ws.cell(row=total_row, column=4, value=f"=SUM(D4:D{total_row-1})")
|
||||||
|
ws.cell(row=total_row, column=5, value=f"=SUM(E4:E{total_row-1})")
|
||||||
|
for col in range(1, 6):
|
||||||
|
c = ws.cell(row=total_row, column=col)
|
||||||
|
c.font = Font(name=FONT, size=11, bold=True)
|
||||||
|
c.fill = PatternFill("solid", fgColor=GREEN)
|
||||||
|
c.border = border
|
||||||
|
c.alignment = Alignment(
|
||||||
|
horizontal="right" if col in (4, 5) else "center", vertical="center"
|
||||||
|
)
|
||||||
|
|
||||||
|
for col, w in zip("ABCDE", [6, 14, 52, 9, 15]):
|
||||||
|
ws.column_dimensions[col].width = w
|
||||||
|
|
||||||
|
# ---------- 报价汇总 ----------
|
||||||
|
ws2 = wb.create_sheet("报价汇总", 0)
|
||||||
|
ws2.merge_cells("A1:E1")
|
||||||
|
c = ws2["A1"]
|
||||||
|
c.value = "生产系统 — 开发报价汇总"
|
||||||
|
c.font = Font(name=FONT, size=15, bold=True, color="FFFFFF")
|
||||||
|
c.fill = PatternFill("solid", fgColor=DARK)
|
||||||
|
c.alignment = Alignment(horizontal="center", vertical="center", wrap_text=True)
|
||||||
|
ws2.row_dimensions[1].height = 34
|
||||||
|
|
||||||
|
headers2 = ["序号", "功能 / 模块", "范围说明", "人天", "金额(元)"]
|
||||||
|
for i, h in enumerate(headers2, 1):
|
||||||
|
c = ws2.cell(row=3, column=i, value=h)
|
||||||
|
c.font = Font(name=FONT, size=11, bold=True, color="FFFFFF")
|
||||||
|
c.fill = PatternFill("solid", fgColor=DARK)
|
||||||
|
c.alignment = Alignment(horizontal="center", vertical="center", wrap_text=True)
|
||||||
|
c.border = border
|
||||||
|
ws2.row_dimensions[3].height = 24
|
||||||
|
|
||||||
|
r = 4
|
||||||
|
for i, (name, scope) in enumerate(summary_rows, 1):
|
||||||
|
r1, r2 = cat_ranges[name]
|
||||||
|
ws2.cell(row=r, column=1, value=i)
|
||||||
|
ws2.cell(row=r, column=2, value=name)
|
||||||
|
ws2.cell(row=r, column=3, value=scope)
|
||||||
|
ws2.cell(row=r, column=4, value=f"=SUM(报价明细!D{r1}:D{r2})")
|
||||||
|
ws2.cell(row=r, column=5, value=f"=SUM(报价明细!E{r1}:E{r2})")
|
||||||
|
for col in range(1, 6):
|
||||||
|
c = ws2.cell(row=r, column=col)
|
||||||
|
c.font = Font(name=FONT, size=11)
|
||||||
|
c.border = border
|
||||||
|
if col == 3:
|
||||||
|
c.alignment = Alignment(horizontal="left", vertical="center", wrap_text=True)
|
||||||
|
elif col in (4, 5):
|
||||||
|
c.alignment = Alignment(horizontal="right", vertical="center", wrap_text=True)
|
||||||
|
else:
|
||||||
|
c.alignment = Alignment(horizontal="center", vertical="center", wrap_text=True)
|
||||||
|
r += 1
|
||||||
|
|
||||||
|
sum_total = r
|
||||||
|
ws2.merge_cells(start_row=sum_total, start_column=1, end_row=sum_total, end_column=3)
|
||||||
|
ws2.cell(row=sum_total, column=1, value="合计")
|
||||||
|
ws2.cell(row=sum_total, column=4, value=f"=SUM(D4:D{sum_total-1})")
|
||||||
|
ws2.cell(row=sum_total, column=5, value=f"=SUM(E4:E{sum_total-1})")
|
||||||
|
for col in range(1, 6):
|
||||||
|
c = ws2.cell(row=sum_total, column=col)
|
||||||
|
c.font = Font(name=FONT, size=11, bold=True)
|
||||||
|
c.fill = PatternFill("solid", fgColor=GREEN)
|
||||||
|
c.border = border
|
||||||
|
c.alignment = Alignment(
|
||||||
|
horizontal="right" if col in (4, 5) else "center", vertical="center"
|
||||||
|
)
|
||||||
|
|
||||||
|
for col, w in zip("ABCDE", [6, 16, 46, 10, 16]):
|
||||||
|
ws2.column_dimensions[col].width = w
|
||||||
|
|
||||||
|
wb.save(OUT)
|
||||||
|
print("saved:", OUT, "| 明细行数:", len(items), "| 合计人天:", sum(d for _, _, d in items))
|
||||||
Reference in New Issue
Block a user