diff --git a/.gitignore b/.gitignore
index 93cd7ff0..dd12de0d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -101,3 +101,7 @@ CLAUDE.md
# Sync tooling local state (generated each run; report is intentionally tracked)
scripts/.*-sync-state.json
+
+# Sandbox / external client work that lives in this directory
+# but should not ship in the repo.
+outputs/
diff --git a/outputs/北京公交票务评估/build_design_doc.py b/outputs/北京公交票务评估/build_design_doc.py
deleted file mode 100644
index 63a60fe2..00000000
--- a/outputs/北京公交票务评估/build_design_doc.py
+++ /dev/null
@@ -1,367 +0,0 @@
-from __future__ import annotations
-
-from datetime import date
-from pathlib import Path
-from typing import Iterable
-
-from docx import Document
-from docx.enum.section import WD_SECTION
-from docx.enum.table import WD_ALIGN_VERTICAL, WD_TABLE_ALIGNMENT
-from docx.enum.text import WD_ALIGN_PARAGRAPH
-from docx.oxml import OxmlElement
-from docx.oxml.ns import qn
-from docx.shared import Inches, Pt, RGBColor
-
-
-OUT = Path("/Users/mate/Codes/mate/mateclaw/outputs/北京公交票务评估/北京公交集团票务综合管理平台系统升级-详细设计与Codex实施方案.docx")
-
-BLUE = RGBColor(46, 116, 181)
-DARK_BLUE = RGBColor(31, 77, 120)
-INK = RGBColor(11, 37, 69)
-MUTED = RGBColor(96, 108, 122)
-LIGHT = "F2F4F7"
-LIGHT_BLUE = "E8EEF5"
-CALLOUT = "F4F6F9"
-
-
-def set_cell_shading(cell, fill: str) -> None:
- tc_pr = cell._tc.get_or_add_tcPr()
- shd = tc_pr.find(qn("w:shd"))
- if shd is None:
- shd = OxmlElement("w:shd")
- tc_pr.append(shd)
- shd.set(qn("w:fill"), fill)
-
-
-def set_cell_margins(cell, top=80, start=120, bottom=80, end=120) -> None:
- tc = cell._tc
- tc_pr = tc.get_or_add_tcPr()
- tc_mar = tc_pr.first_child_found_in("w:tcMar")
- if tc_mar is None:
- tc_mar = OxmlElement("w:tcMar")
- tc_pr.append(tc_mar)
- for m, v in [("top", top), ("start", start), ("bottom", bottom), ("end", end)]:
- node = tc_mar.find(qn(f"w:{m}"))
- if node is None:
- node = OxmlElement(f"w:{m}")
- tc_mar.append(node)
- node.set(qn("w:w"), str(v))
- node.set(qn("w:type"), "dxa")
-
-
-def set_table_width(table, widths: list[float]) -> None:
- table.autofit = False
- table.alignment = WD_TABLE_ALIGNMENT.CENTER
- for row in table.rows:
- for idx, cell in enumerate(row.cells):
- cell.width = Inches(widths[idx])
- set_cell_margins(cell)
- cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
-
-
-def set_run_font(run, size=None, bold=None, color=None, name="Calibri"):
- run.font.name = name
- run._element.rPr.rFonts.set(qn("w:ascii"), name)
- run._element.rPr.rFonts.set(qn("w:hAnsi"), name)
- run._element.rPr.rFonts.set(qn("w:eastAsia"), "Microsoft YaHei")
- if size is not None:
- run.font.size = Pt(size)
- if bold is not None:
- run.bold = bold
- if color is not None:
- run.font.color.rgb = color
-
-
-def add_para(doc: Document, text: str = "", style: str | None = None, bold=False, color=None, size=None, align=None):
- p = doc.add_paragraph(style=style)
- if align is not None:
- p.alignment = align
- p.paragraph_format.space_after = Pt(6)
- p.paragraph_format.line_spacing = 1.1
- if text:
- r = p.add_run(text)
- set_run_font(r, size=size, bold=bold, color=color)
- return p
-
-
-def add_bullets(doc: Document, items: Iterable[str]) -> None:
- for item in items:
- p = doc.add_paragraph(style="List Bullet")
- p.paragraph_format.space_after = Pt(4)
- p.paragraph_format.line_spacing = 1.167
- r = p.add_run(item)
- set_run_font(r, size=10.5)
-
-
-def add_numbered(doc: Document, items: Iterable[str]) -> None:
- for item in items:
- p = doc.add_paragraph(style="List Number")
- p.paragraph_format.space_after = Pt(4)
- p.paragraph_format.line_spacing = 1.167
- r = p.add_run(item)
- set_run_font(r, size=10.5)
-
-
-def add_heading(doc: Document, text: str, level: int):
- p = doc.add_heading(text, level=level)
- if level == 1:
- p.paragraph_format.space_before = Pt(16)
- p.paragraph_format.space_after = Pt(8)
- elif level == 2:
- p.paragraph_format.space_before = Pt(12)
- p.paragraph_format.space_after = Pt(6)
- else:
- p.paragraph_format.space_before = Pt(8)
- p.paragraph_format.space_after = Pt(4)
- for r in p.runs:
- set_run_font(r, size={1: 16, 2: 13, 3: 12}.get(level, 11), bold=True, color=BLUE if level < 3 else DARK_BLUE)
- return p
-
-
-def add_table(doc: Document, headers: list[str], rows: list[list[str]], widths: list[float], header_fill=LIGHT) -> None:
- table = doc.add_table(rows=1, cols=len(headers))
- table.style = "Table Grid"
- hdr = table.rows[0].cells
- for i, h in enumerate(headers):
- hdr[i].text = h
- set_cell_shading(hdr[i], header_fill)
- set_cell_margins(hdr[i])
- for p in hdr[i].paragraphs:
- p.paragraph_format.space_after = Pt(0)
- for r in p.runs:
- set_run_font(r, size=9.5, bold=True, color=INK)
- for row in rows:
- cells = table.add_row().cells
- for i, value in enumerate(row):
- cells[i].text = value
- set_cell_margins(cells[i])
- for p in cells[i].paragraphs:
- p.paragraph_format.space_after = Pt(0)
- p.paragraph_format.line_spacing = 1.08
- for r in p.runs:
- set_run_font(r, size=9)
- set_table_width(table, widths)
- doc.add_paragraph()
-
-
-def add_callout(doc: Document, title: str, body: str) -> None:
- table = doc.add_table(rows=1, cols=1)
- table.style = "Table Grid"
- cell = table.cell(0, 0)
- set_cell_shading(cell, CALLOUT)
- set_cell_margins(cell, top=120, bottom=120, start=160, end=160)
- p = cell.paragraphs[0]
- p.paragraph_format.space_after = Pt(4)
- r = p.add_run(title)
- set_run_font(r, size=10.5, bold=True, color=DARK_BLUE)
- p2 = cell.add_paragraph()
- p2.paragraph_format.space_after = Pt(0)
- r2 = p2.add_run(body)
- set_run_font(r2, size=10)
- set_table_width(table, [6.5])
- doc.add_paragraph()
-
-
-def configure_document(doc: Document) -> None:
- section = doc.sections[0]
- section.top_margin = Inches(1)
- section.bottom_margin = Inches(1)
- section.left_margin = Inches(1)
- section.right_margin = Inches(1)
- section.header_distance = Inches(0.492)
- section.footer_distance = Inches(0.492)
-
- styles = doc.styles
- normal = styles["Normal"]
- normal.font.name = "Calibri"
- normal._element.rPr.rFonts.set(qn("w:eastAsia"), "Microsoft YaHei")
- normal.font.size = Pt(11)
- normal.paragraph_format.space_after = Pt(6)
- normal.paragraph_format.line_spacing = 1.1
-
- for name, size, color in [("Heading 1", 16, BLUE), ("Heading 2", 13, BLUE), ("Heading 3", 12, DARK_BLUE)]:
- st = styles[name]
- st.font.name = "Calibri"
- st._element.rPr.rFonts.set(qn("w:eastAsia"), "Microsoft YaHei")
- st.font.size = Pt(size)
- st.font.color.rgb = color
- st.font.bold = True
-
- header = section.header.paragraphs[0]
- header.text = "北京公交集团票务综合管理平台系统升级 | 详细设计与 Codex 实施方案"
- header.alignment = WD_ALIGN_PARAGRAPH.LEFT
- for r in header.runs:
- set_run_font(r, size=9, color=MUTED)
-
- footer = section.footer.paragraphs[0]
- footer.alignment = WD_ALIGN_PARAGRAPH.RIGHT
- footer.text = "内部评估文件"
- for r in footer.runs:
- set_run_font(r, size=9, color=MUTED)
-
-
-def build() -> None:
- doc = Document()
- configure_document(doc)
-
- add_para(doc, "技术方案", bold=True, color=MUTED, size=11)
- title = doc.add_paragraph()
- title.paragraph_format.space_after = Pt(4)
- r = title.add_run("北京公交集团票务综合管理平台系统升级")
- set_run_font(r, size=24, bold=True, color=INK)
- subtitle = doc.add_paragraph()
- subtitle.paragraph_format.space_after = Pt(16)
- r = subtitle.add_run("详细设计与 Codex 协作实施方案")
- set_run_font(r, size=15, color=MUTED)
-
- meta = [
- ["文档用途", "用于项目立项、报价拆分、研发实施和 Codex 协作开发规划"],
- ["编制日期", date.today().isoformat()],
- ["需求来源", "《北京公交集团票务综合管理平台系统升级-需求分析说明书(初稿0506)》"],
- ["版本", "V1.0"],
- ]
- add_table(doc, ["字段", "内容"], meta, [1.3, 5.2], header_fill=LIGHT_BLUE)
-
- add_callout(
- doc,
- "总体判断",
- "本项目属于存量核心业务系统重构升级,重点不是页面生成,而是票据库存流水、票单结算、报表口径、数据权限、历史数据迁移和国产化适配。Codex 可显著提升需求整理、重复代码生成、测试补齐和文档产出效率,但架构边界、业务规则确认和上线割接仍需人工主导。",
- )
-
- add_heading(doc, "1. 项目范围与建设目标", 1)
- add_para(doc, "本次建设目标是在继承现有生产系统主要能力的基础上,完成业务流程重构、国产化数据库迁移、权限和数据范围治理、报表整合、接口标准化和运维能力提升。系统面向集团、分公司和票务室多级用户,覆盖有人售票、无人售票、票库、票柜、票袋、票单、充值卡、特殊业务和统计报表等票务经营管理场景。")
- add_bullets(doc, [
- "完整保留并优化核心票务业务闭环:印制、调拨、核销、配票、结算、退票、库存查询和流水追溯。",
- "整合同类报表,按集团、分公司、票务室三级数据权限展示统计结果。",
- "完成 Oracle 历史数据到达梦数据库的迁移、校验和兼容适配。",
- "预留并分阶段实现与 IC 卡系统、数据湖、二维码系统、票款清分系统、电子签章系统的对接。",
- "建立可审计、可测试、可持续迭代的工程体系,支持 Codex 辅助开发和自动化校验。",
- ])
-
- add_heading(doc, "2. 总体技术架构", 1)
- add_table(doc, ["层级", "建议技术", "设计说明"], [
- ["前端展示层", "Vue 3 + TypeScript + Vite + Element Plus", "承载菜单导航、列表查询、业务表单、报表展示、打印和导入导出入口。"],
- ["后端服务层", "Java 17 + Spring Boot 3 + MyBatis-Plus", "实现业务编排、事务控制、权限校验、库存流水、报表聚合和接口服务。"],
- ["数据存储层", "达梦 DM8 + Redis + OBS/MinIO", "达梦作为主业务库,Redis 用于会话/缓存/短期任务状态,文件对象存储用于模板、导入文件和导出文件。"],
- ["集成层", "REST/OpenAPI + 批量文件导入 + 定时任务", "对外提供标准接口;对无网络银行清分场景保留线下 Excel/CSV 导入;定时同步基础信息和报表数据。"],
- ["运维层", "Nginx + 应用服务 + 日志审计 + 监控告警", "满足国产化部署、日志追溯、性能监控和上线回滚要求。"],
- ], [1.15, 1.75, 3.6], header_fill=LIGHT_BLUE)
-
- add_heading(doc, "3. 系统模块设计", 1)
- modules = [
- ["基础信息", "票务室、线路、票价、车辆、司售、普票类型、充值类型、机具、多样化运营类型、IC 卡类型", "以 CRUD 和同步查询为主,需统一数据权限和停用机制。"],
- ["票库管理", "印制、调拨、核销、调账、票库库存、票库出入库查询", "核心在审批状态、库存流水、票号段合法性和跨公司调拨。"],
- ["票柜管理", "票柜库存、入库、出库、配票申请、票务室调票", "承接票库到票务室的库存流转,需要单张/批量调票能力。"],
- ["票单管理", "票袋、票单配票、票单结算、票单查询、票袋调票、重新结算、票号查询", "项目最复杂模块,需要严格状态机和结算口径。"],
- ["无人售与特殊业务", "异物、大额币、残币、无人售线路结算、多样化收入、特殊票", "重点是异常状态、待销毁/领取/入账流程和批量导入。"],
- ["退票管理", "票袋退票、票柜退票", "支持连续退票和单张退票,必须回写库存和流水。"],
- ["充值管理", "IC 卡库存、入库、出库、网点库存、售出、充值收入", "需要处理网点维度库存、售出导入和收入记录。"],
- ["统计报表", "集团、分公司、票务室多级报表、趋势图、Excel 导出", "需先冻结报表口径,避免开发完成后重复返工。"],
- ["系统管理", "用户、角色、权限、菜单、阈值、日志", "为全系统提供认证、授权、数据范围和审计能力。"],
- ]
- add_table(doc, ["模块", "主要功能", "设计重点"], modules, [1.25, 2.9, 2.35])
-
- add_heading(doc, "4. 核心业务状态与流水设计", 1)
- add_para(doc, "票据类业务必须采用“当前库存 + 流水台账 + 状态机”的组合模型。只存库存余额无法满足审计、调账、退票、票号查询和异常追溯要求。")
- add_table(doc, ["业务对象", "关键状态", "关键校验"], [
- ["印制申请", "待审核、不同意、待确认、完成", "待审核/不同意可修改;完成后生成票库入库流水。"],
- ["调拨申请", "待审核、不同意、待确认、完成", "校验调出库存、调入公司、票号段不重叠。"],
- ["核销申请", "待审核、完成、驳回", "核销后票号段不可再配出,保留原因和审批记录。"],
- ["配票申请", "待处理、已配票、退回、完成", "票柜库存扣减,票袋或票单库存增加。"],
- ["票单结算", "已配票、已结算、重新结算中、已更正", "销售张数和金额由剩余票号段反推,保留旧结算记录。"],
- ["退票", "申请、确认、完成、驳回", "退票票号不能已核销、不能重复退票,完成后回写对应库存。"],
- ], [1.3, 2.1, 3.1])
-
- add_heading(doc, "5. 数据模型设计原则", 1)
- add_bullets(doc, [
- "基础主数据表:组织、分公司、票务室、线路、车辆、司售、票价、票种、充值类型、机具等。",
- "库存余额表:按库存主体、票种、票价、票组、起止号、状态聚合当前可用数量。",
- "库存流水表:记录每一次入库、出库、调拨、退票、核销、调账、配票、结算的来源单据和操作人。",
- "业务单据表:每类申请、审核、确认、结算均独立建单,避免把审批状态混入库存余额。",
- "报表宽表/汇总表:对日结、月结、趋势报表建立可重算的汇总层,减少实时聚合压力。",
- "审计表:记录登录、菜单访问、增删改、导入导出、审批、结账等关键操作。",
- ])
-
- add_heading(doc, "6. 权限与数据范围设计", 1)
- add_table(doc, ["角色", "功能权限", "数据范围"], [
- ["集团管理员", "最高权限,可维护菜单、角色、用户和全局参数", "全集团数据,可分配集团/分公司/票务室数据权限。"],
- ["集团操作员", "按角色授权使用业务功能", "可查看被授权的分公司和票务室数据。"],
- ["分公司管理员", "维护本分公司及下属票务室用户和权限", "默认本分公司数据,可细分到票务室。"],
- ["分公司操作员", "使用分公司层面业务和报表功能", "本分公司及授权票务室数据。"],
- ["票务室操作员", "操作票柜、票袋、票单、结算等票务室业务", "仅本票务室数据。"],
- ], [1.25, 2.55, 2.7], header_fill=LIGHT_BLUE)
- add_callout(doc, "权限实现建议", "权限必须拆成菜单权限、按钮权限、数据范围权限和字段/导出权限。所有查询接口必须统一经过数据范围拦截器,避免前端隐藏菜单但后端接口越权。")
-
- add_heading(doc, "7. 接口与集成设计", 1)
- add_table(doc, ["系统/对象", "对接方式", "一期处理建议"], [
- ["IC 卡系统", "接口同步或定时任务", "优先同步线路、车辆、司售、IC 卡基础信息;接口不稳定时保留手动导入兜底。"],
- ["数据湖/二维码系统", "标准 REST/API 或数据推送", "先定义统一数据服务接口、鉴权、频率、字段口径;具体联调作为独立里程碑。"],
- ["银行清分清点系统", "线下 Excel/CSV 导入", "按银行无网环境处理,建立模板、校验、导入日志和失败明细下载。"],
- ["票款清分/胆款系统", "批量同步或接口推送", "以票务系统生成的清分日报为主数据源,明确对账字段。"],
- ["电子签章系统", "第三方接口", "建议一期预留签章对象、签章状态和附件字段,实际签章联调单独报价/排期。"],
- ], [1.55, 1.55, 3.4])
-
- add_heading(doc, "8. 数据迁移方案", 1)
- add_numbered(doc, [
- "盘点 Oracle 现有 79 张表、序列、视图、函数、触发器和历史附件,建立字段映射表。",
- "完成达梦库结构设计,明确字段类型、索引、主键、唯一约束和历史兼容字段。",
- "开发迁移脚本,先迁移基础主数据,再迁移库存、单据、结算、报表历史数据。",
- "执行数据清洗:重复票号、缺失组织、异常状态、金额不平、非法日期等问题生成清洗报告。",
- "进行三轮迁移演练:开发环境、测试环境、准生产环境,每轮输出数量核对和金额核对报告。",
- "上线割接时冻结旧系统写入,完成增量迁移、业务抽样验证和回滚预案确认。",
- ])
-
- add_heading(doc, "9. Codex 协作开发流程", 1)
- add_table(doc, ["阶段", "Codex 可承担工作", "人工控制点"], [
- ["需求结构化", "从 Word/Excel 提取功能项、生成需求池、补充初版验收点", "业务人员确认字段、流程、报表口径和删除/保留范围。"],
- ["设计阶段", "生成表结构草案、接口草案、状态机草案、测试场景清单", "架构师确认边界、事务、权限模型和关键业务规则。"],
- ["编码阶段", "生成 CRUD、Service、Mapper、Controller、前端页面、导入导出、测试用例", "开发负责人审查代码风格、事务完整性和异常处理。"],
- ["测试阶段", "补接口测试、构造 Mock 数据、生成回归脚本、修复构建问题", "测试负责人确认场景覆盖和真实业务数据抽样。"],
- ["交付阶段", "生成部署文档、接口文档、用户手册和变更说明", "项目组确认上线窗口、培训材料、应急预案。"],
- ], [1.2, 2.8, 2.5], header_fill=LIGHT_BLUE)
-
- add_heading(doc, "10. 实施计划", 1)
- add_table(doc, ["阶段", "周期", "主要产出"], [
- ["阶段 0:需求深化", "3-5 周", "最终需求清单、原型、报表口径、接口清单、迁移清单。"],
- ["阶段 1:平台底座", "4-6 周", "登录、权限、菜单、日志、字典、导入导出、消息中心。"],
- ["阶段 2:基础与库存", "8-10 周", "基础资料、票库、票柜、库存流水、审批流程。"],
- ["阶段 3:票单核心", "8-12 周", "票袋、配票、结算、重新结算、票号查询、退票。"],
- ["阶段 4:扩展业务与报表", "8-10 周", "无人售、充值、特殊业务、集团/分公司/票务室报表。"],
- ["阶段 5:迁移联调与上线", "8-10 周", "数据迁移、接口联调、UAT、性能测试、安全整改、上线割接。"],
- ], [1.55, 1.15, 3.8])
-
- add_heading(doc, "11. 测试与验收策略", 1)
- add_bullets(doc, [
- "单元测试:覆盖票号段计算、金额计算、库存扣减、状态流转、权限过滤等纯业务逻辑。",
- "接口测试:覆盖所有新增、修改、删除、审核、确认、结账、导入导出接口。",
- "场景测试:按印制到配票、配票到结算、结算到报表、退票回库等业务闭环执行。",
- "数据迁移测试:按表数量、记录数、金额合计、票号段覆盖、异常数据清单进行核对。",
- "权限测试:集团、分公司、票务室分别验证菜单、按钮、数据、导出范围。",
- "性能测试:以峰值 150 在线用户为基准,重点压测报表查询、导入、结账和库存查询。",
- ])
-
- add_heading(doc, "12. 风险与控制措施", 1)
- add_table(doc, ["风险", "影响", "控制措施"], [
- ["报表口径未冻结", "开发完成后反复返工", "每张报表先签字确认指标、维度、过滤条件和样例数据。"],
- ["历史数据质量差", "迁移延期、上线后账不平", "提前做数据体检,问题数据单独出清洗规则和责任确认。"],
- ["接口资料不完整", "联调延期", "接口作为独立里程碑,未提供资料的内容不阻塞核心业务开发。"],
- ["票据状态规则遗漏", "库存错误、审计风险", "核心单据全部状态机化,关键状态变更必须有流水和测试用例。"],
- ["Codex 生成代码缺少业务约束", "隐藏缺陷", "Codex 只产出初稿,核心业务必须人工 review 和场景测试。"],
- ["国产化兼容问题", "部署和性能不稳定", "早期引入达梦、国产 OS、中间件环境,不到上线前再适配。"],
- ], [1.65, 1.8, 3.05])
-
- add_heading(doc, "13. 结论建议", 1)
- add_para(doc, "建议采用“核心闭环优先、接口分阶段、报表先定口径、迁移提前演练”的实施策略。Codex 应作为研发加速工具嵌入需求整理、代码生成、测试补齐和文档交付过程,但不能替代架构决策、业务确认和验收责任。")
- add_bullets(doc, [
- "一期优先交付票务核心闭环:基础信息、票库、票柜、票袋、票单、退票、无人售、充值、报表、权限和迁移。",
- "电子签章、复杂实时接口、等保/密评配合建议单独列项,降低一期范围失控风险。",
- "开发组织建议按 10-12 人、8-10 个月主计划推进,使用 Codex 后可将重复开发和文档测试工作压缩 30%-50%。",
- "正式实施前应先输出功能清单 Excel、原型稿、数据库初设和迁移体检报告,作为报价和排期基线。",
- ])
-
- doc.save(OUT)
- print(OUT)
-
-
-if __name__ == "__main__":
- build()
diff --git a/outputs/北京公交票务评估/build_svg_diagrams.py b/outputs/北京公交票务评估/build_svg_diagrams.py
deleted file mode 100644
index 89011d72..00000000
--- a/outputs/北京公交票务评估/build_svg_diagrams.py
+++ /dev/null
@@ -1,252 +0,0 @@
-from pathlib import Path
-
-OUT = Path("/Users/mate/Codes/mate/mateclaw/outputs/北京公交票务评估/svg设计图")
-OUT.mkdir(parents=True, exist_ok=True)
-
-COLORS = {
- "red": "#D71920",
- "wall_red": "#B63A2E",
- "gray": "#6F7378",
- "dark": "#1F2933",
- "light": "#F5F7FA",
- "line": "#D8DEE6",
- "blue": "#2E86C1",
- "green": "#3FA45B",
- "yellow": "#F2C94C",
- "ink": "#0B2545",
-}
-
-
-def write(name: str, body: str) -> None:
- (OUT / name).write_text(body, encoding="utf-8")
-
-
-def header(title: str, subtitle: str, width=1440, height=960) -> str:
- return f'''
-'''
-
-
-def card(x, y, w, h, title, lines, color="#D71920"):
- parts = [f'',
- f'',
- f'{title}']
- yy = y + 72
- for line in lines:
- parts.append(f'{line}')
- yy += 26
- return "\n".join(parts)
-
-
-architecture = header("总体技术架构图", "从用户访问、应用服务、数据存储、外部集成到运维保障的分层架构")
-architecture += f'''
-
- 访问与用户层
- {card(88, 206, 248, 138, "集团用户", ["集团管理员 / 操作员", "全局管理、报表、审批"], COLORS['red'])}
- {card(376, 206, 248, 138, "分公司用户", ["分公司管理员 / 操作员", "本公司业务、审核、统计"], COLORS['blue'])}
- {card(664, 206, 248, 138, "票务室用户", ["票柜、票袋、票单", "配票、结算、退票"], COLORS['green'])}
- {card(952, 206, 248, 138, "移动/内网终端", ["浏览器访问", "打印、导入、导出"], COLORS['yellow'])}
-
-
-
-
-
-
- 应用与业务服务层
- {card(88, 466, 248, 168, "前端应用", ["Vue3 / TypeScript", "菜单导航、表单、报表", "打印与导入导出"], COLORS['red'])}
- {card(376, 466, 248, 168, "网关与认证", ["统一登录认证", "菜单 / 按钮权限", "数据范围拦截"], COLORS['gray'])}
- {card(664, 466, 248, 168, "业务服务", ["票库、票柜、票单", "充值、无人售、退票", "审批与状态机"], COLORS['blue'])}
- {card(952, 466, 248, 168, "报表服务", ["日结、月结、趋势", "Excel 导出", "汇总表加速"], COLORS['green'])}
-
-
-
-
-
-
- 数据、集成与运维层
- {card(88, 752, 220, 120, "达梦数据库", ["主业务库 / 主备", "库存、流水、报表"], COLORS['red'])}
- {card(342, 752, 220, 120, "Redis / 缓存", ["会话、字典、短期任务", "热点查询缓存"], COLORS['gray'])}
- {card(596, 752, 220, 120, "文件与对象存储", ["模板、导入文件", "导出报表、附件"], COLORS['yellow'])}
- {card(850, 752, 220, 120, "外部系统集成", ["IC卡 / 数据湖 / 胆款", "银行清分线下导入"], COLORS['blue'])}
- {card(1104, 752, 220, 120, "运维保障", ["日志、监控、备份", "灰度、回滚、巡检"], COLORS['green'])}
-'''
-architecture += footer()
-write("01-总体技术架构图.svg", architecture)
-
-
-flow = header("核心票务业务流转图", "围绕票库、票柜、票袋、票单、结算、退票和报表的主业务闭环")
-flow += f'''
-
- {card(104, 190, 220, 126, "1. 印制入库", ["分公司发起印制申请", "集团审核", "确认后进入票库"], COLORS['red'])}
- {card(384, 190, 220, 126, "2. 票库管理", ["票号段入库", "库存余额与流水", "调拨 / 核销 / 调账"], COLORS['gray'])}
- {card(664, 190, 220, 126, "3. 配票申请", ["票务室申请", "分公司确认", "票库到票柜"], COLORS['blue'])}
- {card(944, 190, 220, 126, "4. 票柜库存", ["票务室库存", "入库 / 出库查询", "票务室调票"], COLORS['green'])}
-
-
-
-
-
- {card(104, 400, 220, 126, "5. 票袋管理", ["绑定线路、售票员", "更换线路", "票袋库存归属"], COLORS['green'])}
- {card(384, 400, 220, 126, "6. 票单配票", ["加载票袋数据", "录入起号止号", "票柜出库到票袋"], COLORS['red'])}
- {card(664, 400, 220, 126, "7. 票单结算", ["录入剩余票号", "自动计算张数金额", "生成结算记录"], COLORS['blue'])}
- {card(944, 400, 220, 126, "8. 票单查询", ["配票单 / 结算单", "打印、导出", "重新结算入口"], COLORS['gray'])}
-
-
-
-
-
-
- {card(104, 610, 220, 126, "9. 退票处理", ["票袋退票", "票柜退票", "库存回写"], COLORS['wall_red'])}
- {card(384, 610, 220, 126, "10. 无人售/充值", ["无人售线路结算", "IC卡库存与收入", "导入与异常处理"], COLORS['yellow'])}
- {card(664, 610, 220, 126, "11. 报表汇总", ["日结、月结", "收入、清分、趋势", "三级数据权限"], COLORS['blue'])}
- {card(944, 610, 220, 126, "12. 审计追溯", ["库存流水", "操作日志", "票号查询"], COLORS['gray'])}
-
-
-
-
-
- 异常更正 / 重新结算
-'''
-flow += footer()
-write("02-核心票务业务流转图.svg", flow)
-
-
-deployment = header("部署与可运维性架构图", "面向国产化环境的部署、监控、备份、回滚和运维交接设计")
-deployment += f'''
-
- 网络与访问区
- {card(104, 214, 230, 116, "用户浏览器", ["集团 / 分公司 / 票务室", "内网访问、统一认证"], COLORS['red'])}
- {card(394, 214, 230, 116, "Nginx / 网关", ["HTTPS 终止", "反向代理、限流"], COLORS['gray'])}
- {card(684, 214, 230, 116, "应用服务 A", ["业务 API", "前端静态资源"], COLORS['blue'])}
- {card(974, 214, 230, 116, "应用服务 B", ["热备 / 横向扩展", "版本灰度"], COLORS['blue'])}
-
-
-
-
- 数据与文件区
- {card(104, 426, 230, 128, "达梦主库", ["业务数据写入", "库存与单据主数据"], COLORS['red'])}
- {card(394, 426, 230, 128, "达梦备库", ["主备同步", "故障切换准备"], COLORS['gray'])}
- {card(684, 426, 230, 128, "Redis", ["会话、缓存", "任务状态、热点字典"], COLORS['green'])}
- {card(974, 426, 230, 128, "对象存储", ["模板、导入文件", "导出报表、附件"], COLORS['yellow'])}
-
-
-
-
- 运维保障区
- {card(104, 648, 216, 124, "日志中心", ["业务日志、接口日志", "登录与操作审计"], COLORS['gray'])}
- {card(360, 648, 216, 124, "监控告警", ["存活、慢SQL、磁盘", "异常率、任务失败"], COLORS['red'])}
- {card(616, 648, 216, 124, "备份恢复", ["数据库全量/增量", "文件备份、恢复演练"], COLORS['green'])}
- {card(872, 648, 216, 124, "CI/CD", ["构建、测试、制品", "部署、版本标记"], COLORS['blue'])}
- {card(1128, 648, 216, 124, "回滚预案", ["旧版本保留", "割接窗口、冒烟检查"], COLORS['wall_red'])}
-
-
-
-'''
-deployment += footer()
-write("03-部署与可运维性架构图.svg", deployment)
-
-
-permissions = header("权限与数据范围设计图", "菜单权限、按钮权限、接口权限、数据权限和导出权限的统一控制")
-permissions += f'''
-
- {card(96, 198, 240, 134, "集团管理员", ["配置菜单、角色、用户", "分配分公司数据范围", "查看全集团数据"], COLORS['red'])}
- {card(396, 198, 240, 134, "集团操作员", ["按角色使用功能", "查看授权公司数据", "集团级报表"], COLORS['gray'])}
- {card(696, 198, 240, 134, "分公司管理员", ["维护本公司用户", "配置票务室权限", "本公司业务管理"], COLORS['blue'])}
- {card(996, 198, 240, 134, "票务室操作员", ["票柜、票袋、票单", "结算、退票、导出", "仅本票务室数据"], COLORS['green'])}
-
-
- 统一权限拦截层
- 菜单权限 → 按钮权限 → 接口权限 → 数据范围权限 → 导出/打印权限
-
-
-
-
-
- {card(116, 604, 230, 126, "组织维度", ["集团", "分公司", "票务室 / 车队 / 线路"], COLORS['red'])}
- {card(386, 604, 230, 126, "业务维度", ["票库 / 票柜 / 票袋", "充值网点", "无人售线路"], COLORS['blue'])}
- {card(656, 604, 230, 126, "数据维度", ["单据、库存、流水", "报表汇总", "历史迁移数据"], COLORS['green'])}
- {card(926, 604, 230, 126, "审计维度", ["登录日志", "操作日志", "导入导出日志"], COLORS['gray'])}
-
-
-
-'''
-permissions += footer()
-write("04-权限与数据范围设计图.svg", permissions)
-
-
-delivery = header("Vibe Coding 协同交付流程图", "把大系统拆成可验证的小任务,形成需求、编码、测试、评审、交付闭环")
-delivery += f'''
-
- {card(102, 202, 230, 128, "1. 需求卡片化", ["按页面/动作拆分", "角色、输入、输出", "验收标准"], COLORS['red'])}
- {card(382, 202, 230, 128, "2. 领域建模", ["状态机、票号段", "库存流水、报表口径", "人工确认"], COLORS['gray'])}
- {card(662, 202, 230, 128, "3. 任务生成", ["表结构、接口", "页面、测试", "小批量执行"], COLORS['blue'])}
- {card(942, 202, 230, 128, "4. 编码实现", ["前后端协同", "导入导出", "权限与日志"], COLORS['green'])}
-
-
-
-
- {card(102, 470, 230, 128, "8. 模块验收", ["业务演示", "样例数据核对", "问题闭环"], COLORS['wall_red'])}
- {card(382, 470, 230, 128, "7. 人工评审", ["核心规则 review", "安全与权限检查", "SQL 与事务检查"], COLORS['gray'])}
- {card(662, 470, 230, 128, "6. 自动化测试", ["单元 / 接口", "场景 / 回归", "构建检查"], COLORS['blue'])}
- {card(942, 470, 230, 128, "5. 本地自测", ["页面联调", "异常分支", "导入导出校验"], COLORS['green'])}
-
-
-
-
-
-
- 交付原则
- 小任务、强测试、人工把关、持续演示;常规功能提效,核心规则不省评审。
-
-'''
-delivery += footer()
-write("05-VibeCoding协同交付流程图.svg", delivery)
-
-index = "\n".join([
- "# SVG 设计图清单",
- "",
- "- 01-总体技术架构图.svg",
- "- 02-核心票务业务流转图.svg",
- "- 03-部署与可运维性架构图.svg",
- "- 04-权限与数据范围设计图.svg",
- "- 05-VibeCoding协同交付流程图.svg",
-])
-(OUT / "README.md").write_text(index, encoding="utf-8")
-print(OUT)
diff --git a/outputs/北京公交票务评估/build_vibe_design_doc.py b/outputs/北京公交票务评估/build_vibe_design_doc.py
deleted file mode 100644
index 2a39d4cf..00000000
--- a/outputs/北京公交票务评估/build_vibe_design_doc.py
+++ /dev/null
@@ -1,475 +0,0 @@
-from __future__ import annotations
-
-from collections import defaultdict
-from datetime import date
-from pathlib import Path
-from re import sub
-from typing import Iterable
-
-from docx import Document
-from docx.enum.section import WD_ORIENT, WD_SECTION
-from docx.enum.table import WD_ALIGN_VERTICAL, WD_TABLE_ALIGNMENT
-from docx.enum.text import WD_ALIGN_PARAGRAPH
-from docx.oxml import OxmlElement
-from docx.oxml.ns import qn
-from docx.shared import Inches, Pt, RGBColor
-
-
-SOURCE = Path("/Users/mate/Docs/Work/北京公交集团票务综合管理平台系统升级-需求分析说明书(初稿0506).docx")
-OUT = Path("/Users/mate/Codes/mate/mateclaw/outputs/北京公交票务评估/北京公交集团票务综合管理平台系统升级-VibeCoding实施方案与工作量清单.docx")
-
-BLUE = RGBColor(46, 116, 181)
-DARK_BLUE = RGBColor(31, 77, 120)
-INK = RGBColor(11, 37, 69)
-MUTED = RGBColor(96, 108, 122)
-LIGHT = "F2F4F7"
-LIGHT_BLUE = "E8EEF5"
-CALLOUT = "F4F6F9"
-
-
-def clean(text: str) -> str:
- text = text.replace("\u200c", "").replace("\u200b", "").replace("\ufeff", "")
- text = sub(r"\s+", " ", text).strip()
- return text
-
-
-def module_name(text: str) -> str:
- text = clean(text)
- text = sub(r"^[\d.、\s]+", "", text)
- return text.strip(" ")
-
-
-def set_run_font(run, size=None, bold=None, color=None, name="Calibri"):
- run.font.name = name
- run._element.rPr.rFonts.set(qn("w:ascii"), name)
- run._element.rPr.rFonts.set(qn("w:hAnsi"), name)
- run._element.rPr.rFonts.set(qn("w:eastAsia"), "Microsoft YaHei")
- if size is not None:
- run.font.size = Pt(size)
- if bold is not None:
- run.bold = bold
- if color is not None:
- run.font.color.rgb = color
-
-
-def shade(cell, fill: str):
- tc_pr = cell._tc.get_or_add_tcPr()
- shd = tc_pr.find(qn("w:shd"))
- if shd is None:
- shd = OxmlElement("w:shd")
- tc_pr.append(shd)
- shd.set(qn("w:fill"), fill)
-
-
-def margins(cell, top=80, start=120, bottom=80, end=120):
- tc_pr = cell._tc.get_or_add_tcPr()
- tc_mar = tc_pr.first_child_found_in("w:tcMar")
- if tc_mar is None:
- tc_mar = OxmlElement("w:tcMar")
- tc_pr.append(tc_mar)
- for key, val in [("top", top), ("start", start), ("bottom", bottom), ("end", end)]:
- node = tc_mar.find(qn(f"w:{key}"))
- if node is None:
- node = OxmlElement(f"w:{key}")
- tc_mar.append(node)
- node.set(qn("w:w"), str(val))
- node.set(qn("w:type"), "dxa")
-
-
-def table_width(table, widths: list[float]):
- table.autofit = False
- table.alignment = WD_TABLE_ALIGNMENT.CENTER
- for row in table.rows:
- for idx, cell in enumerate(row.cells):
- cell.width = Inches(widths[idx])
- cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
- margins(cell)
-
-
-def add_para(doc, text="", bold=False, color=None, size=10.5, align=None):
- p = doc.add_paragraph()
- p.paragraph_format.space_after = Pt(6)
- p.paragraph_format.line_spacing = 1.12
- if align is not None:
- p.alignment = align
- if text:
- r = p.add_run(text)
- set_run_font(r, size=size, bold=bold, color=color)
- return p
-
-
-def heading(doc, text, level):
- p = doc.add_heading(text, level=level)
- p.paragraph_format.space_before = Pt(16 if level == 1 else 10)
- p.paragraph_format.space_after = Pt(8 if level == 1 else 5)
- for r in p.runs:
- set_run_font(r, size={1: 16, 2: 13, 3: 12}.get(level, 11), bold=True, color=BLUE if level < 3 else DARK_BLUE)
-
-
-def bullets(doc, items: Iterable[str]):
- for item in items:
- p = doc.add_paragraph(style="List Bullet")
- p.paragraph_format.space_after = Pt(3)
- p.paragraph_format.line_spacing = 1.12
- r = p.add_run(item)
- set_run_font(r, size=10)
-
-
-def numbered(doc, items: Iterable[str]):
- for item in items:
- p = doc.add_paragraph(style="List Number")
- p.paragraph_format.space_after = Pt(3)
- p.paragraph_format.line_spacing = 1.12
- r = p.add_run(item)
- set_run_font(r, size=10)
-
-
-def add_table(doc, headers: list[str], rows: list[list[str]], widths: list[float], fill=LIGHT, font_size=8.8):
- table = doc.add_table(rows=1, cols=len(headers))
- table.style = "Table Grid"
- for i, h in enumerate(headers):
- c = table.rows[0].cells[i]
- c.text = h
- shade(c, fill)
- margins(c)
- for p in c.paragraphs:
- p.paragraph_format.space_after = Pt(0)
- for r in p.runs:
- set_run_font(r, size=font_size, bold=True, color=INK)
- for row in rows:
- cells = table.add_row().cells
- for i, value in enumerate(row):
- cells[i].text = str(value)
- margins(cells[i])
- for p in cells[i].paragraphs:
- p.paragraph_format.space_after = Pt(0)
- p.paragraph_format.line_spacing = 1.02
- for r in p.runs:
- set_run_font(r, size=font_size)
- table_width(table, widths)
- doc.add_paragraph()
-
-
-def callout(doc, title, body):
- table = doc.add_table(rows=1, cols=1)
- table.style = "Table Grid"
- cell = table.cell(0, 0)
- shade(cell, CALLOUT)
- margins(cell, top=120, bottom=120, start=160, end=160)
- p = cell.paragraphs[0]
- p.paragraph_format.space_after = Pt(4)
- r = p.add_run(title)
- set_run_font(r, size=10.5, bold=True, color=DARK_BLUE)
- p2 = cell.add_paragraph()
- p2.paragraph_format.space_after = Pt(0)
- r2 = p2.add_run(body)
- set_run_font(r2, size=10)
- table_width(table, [6.5])
- doc.add_paragraph()
-
-
-def configure(doc: Document):
- section = doc.sections[0]
- section.top_margin = Inches(0.85)
- section.bottom_margin = Inches(0.85)
- section.left_margin = Inches(0.9)
- section.right_margin = Inches(0.9)
- section.header_distance = Inches(0.45)
- section.footer_distance = Inches(0.45)
- styles = doc.styles
- normal = styles["Normal"]
- normal.font.name = "Calibri"
- normal._element.rPr.rFonts.set(qn("w:eastAsia"), "Microsoft YaHei")
- normal.font.size = Pt(10.5)
- normal.paragraph_format.space_after = Pt(6)
- normal.paragraph_format.line_spacing = 1.12
- for style_name, size, color in [("Heading 1", 16, BLUE), ("Heading 2", 13, BLUE), ("Heading 3", 12, DARK_BLUE)]:
- st = styles[style_name]
- st.font.name = "Calibri"
- st._element.rPr.rFonts.set(qn("w:eastAsia"), "Microsoft YaHei")
- st.font.size = Pt(size)
- st.font.bold = True
- st.font.color.rgb = color
- header = section.header.paragraphs[0]
- header.text = "北京公交集团票务综合管理平台系统升级 | Vibe Coding 实施与工作量评估"
- for r in header.runs:
- set_run_font(r, size=8.5, color=MUTED)
- footer = section.footer.paragraphs[0]
- footer.text = "内部评估文件"
- footer.alignment = WD_ALIGN_PARAGRAPH.RIGHT
- for r in footer.runs:
- set_run_font(r, size=8.5, color=MUTED)
-
-
-def extract_items():
- doc = Document(SOURCE)
- table = doc.tables[38]
- items = []
- current = ""
- for row in table.rows[1:]:
- cells = [clean(c.text) for c in row.cells[:5]]
- mod, page, func, change, note = cells
- if mod:
- current = module_name(mod)
- if not page:
- continue
- items.append({
- "module": current,
- "page": page,
- "function": func,
- "change": change,
- "note": note,
- })
- return items
-
-
-def classify(item):
- text = f"{item['module']} {item['page']} {item['function']} {item['change']} {item['note']}"
- if "可删除" in text or "删除" in item["page"] or item["change"] == "删除":
- return "拟删除/整合", 0, 1, "确认下线、菜单隐藏、历史数据保留和跳转清理。"
- if any(k in text for k in ["结算", "重新结算", "配票", "调票", "退票", "库存", "入库", "出库", "核销", "调拨", "印制", "票号"]):
- lo, hi = 8, 18
- if any(k in text for k in ["票单结算", "重新结算", "票袋调票", "票柜退票", "票袋退票"]):
- lo, hi = 14, 26
- return "核心业务", lo, hi, "需要状态机、库存流水、票号段校验、事务一致性和回归测试。"
- if any(k in item["module"] for k in ["统计报表"]) or "报表" in text or "统计" in text:
- return "报表统计", 6, 14, "需确认统计口径、权限范围、导出格式和历史数据性能。"
- if "导入" in text or "上传" in text or "下载" in text:
- return "导入导出", 5, 10, "需模板、字段校验、失败明细、导入日志和重复处理。"
- if any(k in item["module"] for k in ["系统管理"]) or any(k in item["page"] for k in ["用户", "权限", "菜单", "日志", "阈值"]):
- return "平台能力", 6, 14, "需统一认证授权、按钮权限、数据范围和审计记录。"
- if any(k in text for k in ["查询、新建、修改、删除", "添加、编辑、删除", "添加、编辑", "新增", "管理"]):
- return "常规功能", 4, 8, "以列表、表单、校验、权限按钮和操作日志为主。"
- return "查询维护", 3, 6, "以查询、筛选、详情、导出或基础维护为主。"
-
-
-def build_rows(items):
- rows = []
- for idx, item in enumerate(items, start=1):
- kind, lo, hi, detail = classify(item)
- vibe_lo = round(lo * 0.65, 1)
- vibe_hi = round(hi * 0.75, 1)
- dev = build_dev_scope(item, kind)
- rows.append({
- **item,
- "idx": idx,
- "kind": kind,
- "lo": lo,
- "hi": hi,
- "vibe_lo": vibe_lo,
- "vibe_hi": vibe_hi,
- "dev": dev,
- "detail": detail,
- })
- return rows
-
-
-def build_dev_scope(item, kind):
- page = item["page"]
- if kind == "拟删除/整合":
- return f"确认 {page} 下线或合并路径,处理菜单、权限、历史查询入口和数据保留。"
- if kind == "核心业务":
- return f"建设 {page} 的单据、审批/确认、库存流水、票号段校验、查询导出和异常回滚。"
- if kind == "报表统计":
- return f"建设 {page} 查询、统计聚合、权限过滤、Excel 导出、必要趋势展示和口径校验。"
- if kind == "导入导出":
- return f"建设 {page} 模板下载、文件上传、字段校验、入库处理、失败明细和导入日志。"
- if kind == "平台能力":
- return f"建设 {page} 的配置管理、权限控制、审计记录、查询筛选和维护页面。"
- return f"建设 {page} 的列表查询、详情、新增/编辑/停用或删除、权限按钮、日志和导出能力。"
-
-
-def module_summary(rows):
- result = []
- grouped = defaultdict(list)
- for row in rows:
- grouped[row["module"]].append(row)
- for mod, vals in grouped.items():
- lo = sum(v["lo"] for v in vals)
- hi = sum(v["hi"] for v in vals)
- vlo = sum(v["vibe_lo"] for v in vals)
- vhi = sum(v["vibe_hi"] for v in vals)
- result.append([mod, str(len(vals)), f"{lo}-{hi}", f"{round(vlo)}-{round(vhi)}", module_focus(mod)])
- return result
-
-
-def module_focus(mod):
- if "票单" in mod:
- return "票袋、配票、结算、重新结算、票号追溯,是核心复杂域。"
- if "票柜" in mod or "票库" in mod or "申请" in mod or "审核" in mod:
- return "围绕库存流转、审批状态和票号段控制。"
- if "统计报表" in mod:
- return "以口径确认、聚合性能、导出格式和权限过滤为重点。"
- if "系统" in mod:
- return "全局权限、菜单、日志、阈值,是平台底座。"
- if "基础" in mod:
- return "主数据维护和外部同步,是后续业务依赖。"
- return "按业务场景完成查询、维护、导入导出和日志审计。"
-
-
-def make_landscape(doc):
- section = doc.add_section(WD_SECTION.NEW_PAGE)
- section.orientation = WD_ORIENT.LANDSCAPE
- section.page_width, section.page_height = section.page_height, section.page_width
- section.top_margin = Inches(0.6)
- section.bottom_margin = Inches(0.6)
- section.left_margin = Inches(0.55)
- section.right_margin = Inches(0.55)
- section.header_distance = Inches(0.35)
- section.footer_distance = Inches(0.35)
- return section
-
-
-def build():
- items = extract_items()
- rows = build_rows(items)
- normal_lo = sum(r["lo"] for r in rows)
- normal_hi = sum(r["hi"] for r in rows)
- vibe_lo = round(sum(r["vibe_lo"] for r in rows))
- vibe_hi = round(sum(r["vibe_hi"] for r in rows))
-
- doc = Document()
- configure(doc)
-
- add_para(doc, "项目实施方案", bold=True, color=MUTED, size=11)
- p = doc.add_paragraph()
- r = p.add_run("北京公交集团票务综合管理平台系统升级")
- set_run_font(r, size=23, bold=True, color=INK)
- p.paragraph_format.space_after = Pt(4)
- p = doc.add_paragraph()
- r = p.add_run("Vibe Coding 实施方案与工作量清单")
- set_run_font(r, size=15, color=MUTED)
- p.paragraph_format.space_after = Pt(14)
- add_table(doc, ["字段", "内容"], [
- ["文档用途", "用于项目立项、排期、报价拆分、研发组织和验收范围确认"],
- ["编制日期", date.today().isoformat()],
- ["需求来源", "北京公交集团票务综合管理平台系统升级需求分析说明书(初稿0506)"],
- ["估算口径", "包含需求深化、设计、开发、自测、联调、迁移、测试配合和上线支持"],
- ], [1.35, 5.15], fill=LIGHT_BLUE, font_size=9)
-
- callout(doc, "简要结论", f"本项目按完整重构口径约 {len(rows)} 个功能项,正常开发工作量约 {normal_lo}-{normal_hi} 人日。采用 Vibe Coding 协同方式后,可将重复代码、测试样例、文档和脚手架类工作压缩,执行工作量约 {vibe_lo}-{vibe_hi} 人日,但票据规则、报表口径、数据迁移和上线验收仍需人工主导。")
-
- heading(doc, "一、简要评估", 1)
- add_table(doc, ["项目", "建议口径"], [
- ["功能规模", f"{len(rows)} 个功能项,覆盖 14 个一级模块,含基础资料、票库、票柜、票单、退票、充值、报表、系统管理等。"],
- ["正常团队", "10-12 人,8-10 个月完成;包含产品、前端、后端、数据迁移、测试、实施。"],
- ["Vibe Coding 团队", "7-9 人,7-8 个月完成;前提是需求冻结、接口材料及时、测试自动化和人工评审到位。"],
- ["核心难点", "票号段连续性、库存流水、票单结算、报表口径、数据权限、历史数据迁移、国产化适配。"],
- ["报价建议", "完整建设建议按 450-650 万区间,稳妥报价点 520-580 万;电子签章、等保测评、第三方授权另列。"],
- ], [1.4, 5.1], fill=LIGHT_BLUE, font_size=9)
-
- heading(doc, "二、模块工作量简表", 1)
- add_table(doc, ["模块", "功能项数", "正常人日", "协同后人日", "重点说明"], module_summary(rows), [1.25, 0.65, 0.85, 0.9, 2.85], fill=LIGHT)
-
- heading(doc, "三、Vibe Coding 实施方式", 1)
- add_para(doc, "本方案中的 Vibe Coding 不是直接让工具一次性生成完整系统,而是把需求、设计、编码、测试、文档拆成小批量可验证任务。每个功能都按照“需求卡片 - 数据结构 - 接口 - 页面 - 测试 - 评审 - 合并”的节奏推进。")
- numbered(doc, [
- "需求卡片化:每个页面或业务动作形成独立任务,明确角色、数据范围、输入输出、状态和验收标准。",
- "先底座后业务:先完成认证、菜单、权限、字典、日志、导入导出、文件存储等平台能力。",
- "核心域手工建模:票据库存、票号段、结算、退票、调账等领域模型由架构师和业务人员先确认,再进入编码。",
- "批量生成常规代码:常规列表、表单、接口、DTO、Mapper、权限按钮、导入模板可以批量生成并统一 review。",
- "测试前置:每个核心业务先写状态流转和金额/张数计算测试,避免只实现页面不验证账务逻辑。",
- "小步交付:每个模块独立演示、独立验收、独立回归,不把问题积压到总体验收阶段。",
- ])
-
- heading(doc, "四、实施步骤简表", 1)
- add_table(doc, ["阶段", "周期", "主要工作", "交付物"], [
- ["0. 需求深化", "3-5 周", "需求清单、业务流程、角色权限、报表口径、接口范围、迁移对象确认。", "需求矩阵、原型、报表口径表、接口清单、迁移清单。"],
- ["1. 平台底座", "4-6 周", "登录、用户、角色、菜单、数据权限、日志、字典、阈值、消息、文件导入导出。", "可登录可授权的基础系统。"],
- ["2. 基础与库存", "8-10 周", "基础资料、票库、票柜、审批、库存余额和流水。", "库存闭环 MVP。"],
- ["3. 票单核心", "8-12 周", "票袋、配票、结算、重新结算、退票、票号查询。", "票务室核心业务闭环。"],
- ["4. 扩展业务与报表", "8-10 周", "无人售、充值、特殊业务、集团/分公司/票务室报表。", "完整业务与统计能力。"],
- ["5. 联调上线", "8-10 周", "数据迁移、接口联调、UAT、性能、安全整改、上线演练。", "生产上线版本与运维交接材料。"],
- ], [0.9, 0.8, 3.05, 1.75], fill=LIGHT)
-
- heading(doc, "五、关键设计细节", 1)
- heading(doc, "5.1 库存与票号设计", 2)
- bullets(doc, [
- "采用“库存余额表 + 库存流水表 + 业务单据表”三层模型,不以单一库存字段承载全部业务历史。",
- "票号段字段统一包含票价、票种、票组、起号、止号、张数、状态、库存主体、来源单据。",
- "所有出入库动作必须写流水,流水记录来源、目标、数量、金额、操作人、操作时间和业务原因。",
- "连续票号段需校验重叠、断号、越界、已核销、已退票、已结算等状态。",
- "重新结算不得覆盖原记录,应形成更正单据和差异流水,保证历史可追溯。",
- ])
- heading(doc, "5.2 权限与数据范围", 2)
- bullets(doc, [
- "权限拆分为菜单权限、按钮权限、接口权限、数据范围权限和导出权限。",
- "集团管理员可分配全局权限;集团操作员按授权查看部分分公司;分公司角色默认本分公司;票务室角色只看本票务室。",
- "后端查询必须统一注入数据范围条件,不能只依赖前端隐藏菜单。",
- "导出、打印、报表接口必须复用同一套数据权限规则。",
- ])
- heading(doc, "5.3 报表设计", 2)
- bullets(doc, [
- "每张报表上线前先确认指标定义、筛选条件、统计维度、取数来源、金额精度、导出格式。",
- "集团和分公司同类报表尽量合并,用数据权限和维度字段控制展示结果。",
- "高频报表建立日汇总/月汇总表,避免每次查询实时扫大量流水。",
- "报表验收必须使用旧系统样例数据做金额和张数比对。",
- ])
- heading(doc, "5.4 数据迁移", 2)
- bullets(doc, [
- "迁移对象包括 Oracle 表、序列、视图、函数、历史业务数据和必要附件。",
- "先做数据体检,输出重复票号、缺失组织、异常状态、金额不平、非法日期等问题清单。",
- "至少执行三轮迁移演练:开发、测试、准生产,每轮生成记录数、金额、票号覆盖和异常清单。",
- "上线割接需要冻结旧系统写入、执行增量迁移、业务抽样核验,并保留回滚方案。",
- ])
-
- heading(doc, "六、部署与可运维性设计", 1)
- add_para(doc, "本项目属于票务核心管理系统,部署和运维能力应在一期同步设计,不能等到开发完成后补。运维设计目标是:可部署、可监控、可审计、可备份、可恢复、可灰度、可回滚。")
- add_table(doc, ["运维领域", "设计要求", "工作量建议"], [
- ["环境规划", "至少规划开发、测试、预生产、生产四类环境;生产采用应用服务与数据库分离部署,数据库主备。", "12-18 人日"],
- ["国产化适配", "适配达梦数据库、国产服务器操作系统、国产中间件或 Nginx/应用服务部署要求,提前验证驱动和 SQL 兼容性。", "20-35 人日"],
- ["配置管理", "数据库连接、文件存储、外部接口、导入目录、日志级别、任务开关全部配置化,避免写死在代码中。", "8-12 人日"],
- ["CI/CD", "建立构建、单元测试、打包、制品归档、部署脚本流程;生产部署需支持版本标记和回滚。", "15-25 人日"],
- ["日志审计", "区分业务操作日志、登录日志、接口日志、导入导出日志、系统错误日志;关键单据状态变化必须可追溯。", "15-25 人日"],
- ["监控告警", "监控应用存活、接口耗时、数据库连接池、慢 SQL、磁盘空间、导入任务、定时任务和异常错误率。", "15-25 人日"],
- ["备份恢复", "数据库全量/增量备份,导入文件和导出附件备份,定期恢复演练,形成恢复时间目标。", "12-20 人日"],
- ["上线回滚", "上线前冻结窗口、迁移脚本、冒烟检查、业务抽样、失败回滚、旧系统只读策略均需预案。", "15-25 人日"],
- ["运维交接", "提供部署手册、配置手册、巡检手册、常见问题、数据恢复手册和接口联调手册。", "10-18 人日"],
- ], [1.15, 4.2, 1.15], fill=LIGHT_BLUE)
- callout(doc, "部署工作量口径", "部署与运维建设建议单独预留 120-200 人日。如果甲方要求等保测评、密评配合、信创测评、双活容灾或第三方运维平台对接,应另行增加专项工作量和报价。")
-
- heading(doc, "七、详细功能项清单", 1)
- add_para(doc, "以下清单按需求文档附录逐项展开。正常人日为完整开发、自测、联调配合口径;协同后人日为采用 Vibe Coding 方式后的执行估算,不包含甲方等待、接口资料延迟和重大需求变更。")
- make_landscape(doc)
- heading(doc, "详细功能项与工作量估算", 1)
- detail_rows = []
- for r in rows:
- detail_rows.append([
- r["idx"],
- r["module"],
- r["page"],
- r["kind"],
- r["function"] or "按页面说明",
- r["dev"],
- f"{r['lo']}-{r['hi']}",
- f"{r['vibe_lo']}-{r['vibe_hi']}",
- r["detail"],
- ])
- add_table(
- doc,
- ["序号", "模块", "功能页面", "类型", "现有功能", "开发内容", "正常人日", "协同后", "难点/备注"],
- detail_rows,
- [0.35, 0.95, 1.35, 0.75, 1.25, 2.1, 0.58, 0.58, 1.6],
- fill=LIGHT_BLUE,
- font_size=7.2,
- )
-
- doc.add_section(WD_SECTION.NEW_PAGE)
- heading(doc, "八、风险与边界", 1)
- add_table(doc, ["风险点", "表现", "建议处理"], [
- ["需求边界不清", "文档中存在“待明确”“删除”“整合”项,容易反复变更。", "在开发前形成冻结版功能清单,变更走审批和工期调整。"],
- ["接口资料缺失", "数据湖、二维码、胆款、电子签章等接口材料未完全明确。", "一期只做接口框架和已确认接口,未确认部分单独列二期。"],
- ["报表口径争议", "同一报表集团/分公司/票务室口径不同,数字验收困难。", "先用旧系统样例数据签字确认,再开发。"],
- ["历史数据异常", "旧系统长期运行导致脏数据和状态不一致。", "迁移前做数据体检,异常数据由业务确认处理规则。"],
- ["AI 生成代码质量波动", "常规代码效率高,但核心业务可能遗漏隐性规则。", "核心交易类代码必须人工 review,并要求测试覆盖状态流转和金额计算。"],
- ], [1.35, 2.45, 2.7], fill=LIGHT)
-
- heading(doc, "九、结论", 1)
- add_para(doc, f"本项目完整实施建议按 10-12 人、8-10 个月规划;采用 Vibe Coding 协同后,可把常规代码、测试样例、文档和重复性页面工作压缩,推荐按 7-9 人、7-8 个月作为进取计划。部署与可运维性需同步纳入一期,额外预留 120-200 人日。即便采用协同开发,票据库存、票单结算、报表口径、历史数据迁移和上线割接仍是项目成败关键,需要架构师、业务负责人、测试负责人和运维负责人持续把关。")
-
- doc.save(OUT)
- print(OUT)
-
-
-if __name__ == "__main__":
- build()
diff --git a/outputs/北京公交票务评估/insert_diagrams_into_doc.py b/outputs/北京公交票务评估/insert_diagrams_into_doc.py
deleted file mode 100644
index 79a34d89..00000000
--- a/outputs/北京公交票务评估/insert_diagrams_into_doc.py
+++ /dev/null
@@ -1,70 +0,0 @@
-from pathlib import Path
-
-from docx import Document
-from docx.enum.text import WD_ALIGN_PARAGRAPH
-from docx.shared import Inches, Pt
-
-
-SRC = Path("/Users/mate/Codes/mate/mateclaw/outputs/北京公交票务评估/北京公交集团票务综合管理平台系统升级-VibeCoding实施方案与工作量清单.docx")
-OUT = Path("/Users/mate/Codes/mate/mateclaw/outputs/北京公交票务评估/北京公交集团票务综合管理平台系统升级-VibeCoding实施方案与工作量清单-含设计图.docx")
-PNG = Path("/Users/mate/Codes/mate/mateclaw/outputs/北京公交票务评估/svg设计图/png预览")
-
-
-DIAGRAMS = {
- "三、Vibe Coding 实施方式": ("05-VibeCoding协同交付流程图.png", "图 1 Vibe Coding 协同交付流程图"),
- "五、关键设计细节": ("02-核心票务业务流转图.png", "图 2 核心票务业务流转图"),
- "5.2 权限与数据范围": ("04-权限与数据范围设计图.png", "图 3 权限与数据范围设计图"),
- "六、部署与可运维性设计": ("03-部署与可运维性架构图.png", "图 4 部署与可运维性架构图"),
- "七、详细功能项清单": ("01-总体技术架构图.png", "图 5 总体技术架构图"),
-}
-
-
-def insert_after(paragraph, image_path: Path, caption: str, width=Inches(6.7)):
- caption_p = paragraph.insert_paragraph_before("")
- # Move caption and picture after the heading by inserting before next paragraph is not directly
- # supported in python-docx. Use low-level insertion after heading.
- pic_p = paragraph._p.addnext(paragraph._p.__class__())
-
-
-def add_picture_after(paragraph, image_path: Path, caption: str, width=Inches(6.7)):
- doc = paragraph.part.document
- p_pic = doc.add_paragraph()
- p_pic.alignment = WD_ALIGN_PARAGRAPH.CENTER
- run = p_pic.add_run()
- run.add_picture(str(image_path), width=width)
- p_pic.paragraph_format.space_before = Pt(6)
- p_pic.paragraph_format.space_after = Pt(3)
-
- p_cap = doc.add_paragraph()
- p_cap.alignment = WD_ALIGN_PARAGRAPH.CENTER
- p_cap.paragraph_format.space_after = Pt(8)
- r = p_cap.add_run(caption)
- r.font.size = Pt(9)
- r.font.name = "Microsoft YaHei"
-
- # Move the newly appended picture + caption immediately after the target paragraph.
- paragraph._p.addnext(p_cap._p)
- paragraph._p.addnext(p_pic._p)
-
-
-def main():
- doc = Document(SRC)
- inserted = 0
- for para in list(doc.paragraphs):
- text = para.text.strip()
- if text in DIAGRAMS:
- file_name, caption = DIAGRAMS[text]
- image = PNG / file_name
- if not image.exists():
- raise FileNotFoundError(image)
- width = Inches(8.9) if "详细功能项" in text else Inches(6.7)
- add_picture_after(para, image, caption, width=width)
- inserted += 1
- if inserted != len(DIAGRAMS):
- raise RuntimeError(f"Inserted {inserted}, expected {len(DIAGRAMS)}")
- doc.save(OUT)
- print(OUT)
-
-
-if __name__ == "__main__":
- main()
diff --git a/outputs/北京公交票务评估/quicklook/北京公交集团票务综合管理平台系统升级-详细设计与Codex实施方案.docx.png b/outputs/北京公交票务评估/quicklook/北京公交集团票务综合管理平台系统升级-详细设计与Codex实施方案.docx.png
deleted file mode 100644
index 61becd5e..00000000
Binary files a/outputs/北京公交票务评估/quicklook/北京公交集团票务综合管理平台系统升级-详细设计与Codex实施方案.docx.png and /dev/null differ
diff --git a/outputs/北京公交票务评估/quicklook含图/北京公交集团票务综合管理平台系统升级-VibeCoding实施方案与工作量清单-含设计图.docx.png b/outputs/北京公交票务评估/quicklook含图/北京公交集团票务综合管理平台系统升级-VibeCoding实施方案与工作量清单-含设计图.docx.png
deleted file mode 100644
index 1f52a785..00000000
Binary files a/outputs/北京公交票务评估/quicklook含图/北京公交集团票务综合管理平台系统升级-VibeCoding实施方案与工作量清单-含设计图.docx.png and /dev/null differ
diff --git a/outputs/北京公交票务评估/svg设计图/01-总体技术架构图.svg b/outputs/北京公交票务评估/svg设计图/01-总体技术架构图.svg
deleted file mode 100644
index 136c2a44..00000000
--- a/outputs/北京公交票务评估/svg设计图/01-总体技术架构图.svg
+++ /dev/null
@@ -1,121 +0,0 @@
-
diff --git a/outputs/北京公交票务评估/svg设计图/02-核心票务业务流转图.svg b/outputs/北京公交票务评估/svg设计图/02-核心票务业务流转图.svg
deleted file mode 100644
index c790f6fc..00000000
--- a/outputs/北京公交票务评估/svg设计图/02-核心票务业务流转图.svg
+++ /dev/null
@@ -1,126 +0,0 @@
-
diff --git a/outputs/北京公交票务评估/svg设计图/03-部署与可运维性架构图.svg b/outputs/北京公交票务评估/svg设计图/03-部署与可运维性架构图.svg
deleted file mode 100644
index 3684bb9c..00000000
--- a/outputs/北京公交票务评估/svg设计图/03-部署与可运维性架构图.svg
+++ /dev/null
@@ -1,116 +0,0 @@
-
diff --git a/outputs/北京公交票务评估/svg设计图/04-权限与数据范围设计图.svg b/outputs/北京公交票务评估/svg设计图/04-权限与数据范围设计图.svg
deleted file mode 100644
index c99e90ea..00000000
--- a/outputs/北京公交票务评估/svg设计图/04-权限与数据范围设计图.svg
+++ /dev/null
@@ -1,97 +0,0 @@
-
diff --git a/outputs/北京公交票务评估/svg设计图/05-VibeCoding协同交付流程图.svg b/outputs/北京公交票务评估/svg设计图/05-VibeCoding协同交付流程图.svg
deleted file mode 100644
index c2d62f52..00000000
--- a/outputs/北京公交票务评估/svg设计图/05-VibeCoding协同交付流程图.svg
+++ /dev/null
@@ -1,98 +0,0 @@
-
diff --git a/outputs/北京公交票务评估/svg设计图/README.md b/outputs/北京公交票务评估/svg设计图/README.md
deleted file mode 100644
index 2bbab118..00000000
--- a/outputs/北京公交票务评估/svg设计图/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# SVG 设计图清单
-
-- 01-总体技术架构图.svg
-- 02-核心票务业务流转图.svg
-- 03-部署与可运维性架构图.svg
-- 04-权限与数据范围设计图.svg
-- 05-VibeCoding协同交付流程图.svg
\ No newline at end of file
diff --git a/outputs/北京公交票务评估/svg设计图/png预览/01-总体技术架构图.png b/outputs/北京公交票务评估/svg设计图/png预览/01-总体技术架构图.png
deleted file mode 100644
index ced76d32..00000000
Binary files a/outputs/北京公交票务评估/svg设计图/png预览/01-总体技术架构图.png and /dev/null differ
diff --git a/outputs/北京公交票务评估/svg设计图/png预览/02-核心票务业务流转图.png b/outputs/北京公交票务评估/svg设计图/png预览/02-核心票务业务流转图.png
deleted file mode 100644
index f72dfdd1..00000000
Binary files a/outputs/北京公交票务评估/svg设计图/png预览/02-核心票务业务流转图.png and /dev/null differ
diff --git a/outputs/北京公交票务评估/svg设计图/png预览/03-部署与可运维性架构图.png b/outputs/北京公交票务评估/svg设计图/png预览/03-部署与可运维性架构图.png
deleted file mode 100644
index 6b7f4c7a..00000000
Binary files a/outputs/北京公交票务评估/svg设计图/png预览/03-部署与可运维性架构图.png and /dev/null differ
diff --git a/outputs/北京公交票务评估/svg设计图/png预览/04-权限与数据范围设计图.png b/outputs/北京公交票务评估/svg设计图/png预览/04-权限与数据范围设计图.png
deleted file mode 100644
index f54a1a20..00000000
Binary files a/outputs/北京公交票务评估/svg设计图/png预览/04-权限与数据范围设计图.png and /dev/null differ
diff --git a/outputs/北京公交票务评估/svg设计图/png预览/05-VibeCoding协同交付流程图.png b/outputs/北京公交票务评估/svg设计图/png预览/05-VibeCoding协同交付流程图.png
deleted file mode 100644
index 83073ee7..00000000
Binary files a/outputs/北京公交票务评估/svg设计图/png预览/05-VibeCoding协同交付流程图.png and /dev/null differ
diff --git a/outputs/北京公交票务评估/svg设计图/quicklook/01-总体技术架构图.svg.png b/outputs/北京公交票务评估/svg设计图/quicklook/01-总体技术架构图.svg.png
deleted file mode 100644
index 15fa48c5..00000000
Binary files a/outputs/北京公交票务评估/svg设计图/quicklook/01-总体技术架构图.svg.png and /dev/null differ
diff --git a/outputs/北京公交票务评估/北京公交票务平台功能开发清单.xlsx b/outputs/北京公交票务评估/北京公交票务平台功能开发清单.xlsx
deleted file mode 100644
index b39ae364..00000000
Binary files a/outputs/北京公交票务评估/北京公交票务平台功能开发清单.xlsx and /dev/null differ
diff --git a/outputs/北京公交票务评估/北京公交集团票务综合管理平台系统升级-VibeCoding实施方案与工作量清单-含设计图.docx b/outputs/北京公交票务评估/北京公交集团票务综合管理平台系统升级-VibeCoding实施方案与工作量清单-含设计图.docx
deleted file mode 100644
index 3988558b..00000000
Binary files a/outputs/北京公交票务评估/北京公交集团票务综合管理平台系统升级-VibeCoding实施方案与工作量清单-含设计图.docx and /dev/null differ
diff --git a/outputs/北京公交票务评估/北京公交集团票务综合管理平台系统升级-VibeCoding实施方案与工作量清单.docx b/outputs/北京公交票务评估/北京公交集团票务综合管理平台系统升级-VibeCoding实施方案与工作量清单.docx
deleted file mode 100644
index ee6a9998..00000000
Binary files a/outputs/北京公交票务评估/北京公交集团票务综合管理平台系统升级-VibeCoding实施方案与工作量清单.docx and /dev/null differ
diff --git a/outputs/北京公交票务评估/北京公交集团票务综合管理平台系统升级-详细设计与Codex实施方案.docx b/outputs/北京公交票务评估/北京公交集团票务综合管理平台系统升级-详细设计与Codex实施方案.docx
deleted file mode 100644
index 735abe2d..00000000
Binary files a/outputs/北京公交票务评估/北京公交集团票务综合管理平台系统升级-详细设计与Codex实施方案.docx and /dev/null differ