# PinMAP → PinList 转换器 — 修改需求评估 > **版本**: v1.0 > **日期**: 2026-05-25 > **评估人**: 脚本架构师 (Script Architect) > **状态**: 待审批 --- ## 1. 修改需求总览 | 编号 | 需求 | 优先级 | 复杂度 | |------|------|--------|--------| | R1 | 增加交互提示(启动说明、详细日志、结果摘要) | 高 | 低 | | R2 | 文件选择方式调整(路径输入 → 弹窗回退 → 报错重试) | 高 | 低 | | R3 | 窗口属性(UTF-8 编码、固定窗口、颜色、署名、pause) | 高 | 低 | --- ## 2. 逐项需求分析 ### 2.1 需求 R1:增加交互提示 **现状**: - 当前 `main.py` 启动即进入文件选择,无任何说明 - 日志输出已有 `[INFO]`、`[WARN]`、`[ERROR]`、`[FATAL]` 分级,但粒度不够细 - 转换完成后直接 `return` 退出,窗口瞬间关闭(双击 bat 运行时) **修改目标**: 1. **启动 Banner**:显示程序名称、功能说明、版本信息、署名 2. **详细日志**:在 Excel 读取、PinMAP 解析、验证、生成、写入各阶段增加 `[INFO]` 日志 3. **结果摘要**:转换完成后不立即退出,显示统计摘要,等待用户确认后退出 **具体改动**: ``` 启动 Banner 示例: ╔══════════════════════════════════════════════════════════╗ ║ PinMAP → PinList 转换器 ║ ║ 自动将 Excel PinMAP 文件转换为 PinList ║ ║ ║ ║ 版本: v1.0.1 ║ ║ -By: LeeQwQ ║ ╚══════════════════════════════════════════════════════════╝ 详细日志示例: [INFO] 正在读取文件: C:\Users\test\sample_4x4.xlsx [INFO] 文件读取完成,共 16 个非空单元格 [INFO] 正在解析 PinMAP 结构... [INFO] 解析完成: 4x4 方形,共 12 个Pin [INFO] 封装信息: QFN-12 [INFO] 正在验证数据... [INFO] 验证通过,0 个错误,2 个警告 [INFO] 正在生成 PinList... [INFO] 正在写入输出文件... [SUCCESS] 转换完成! 结果摘要示例: ═══════════════════════════════════════════════════════════ 转换结果摘要 ═══════════════════════════════════════════════════════════ 输入文件: C:\Users\test\sample_4x4.xlsx 输出文件: C:\Users\test\sample_4x4_PinList.xlsx 封装信息: QFN-12 Pin 数量: 12 错误数量: 0 警告数量: 2 ═══════════════════════════════════════════════════════════ 按任意键退出... ``` ### 2.2 需求 R2:文件选择方式调整 **现状**: - 当前 `file_selector.py` 的 `select_file()` 函数: - 有命令行参数 → 直接使用 - 无命令行参数 → 直接弹出 tkinter 文件对话框 - 无 GUI 环境 → 回退到命令行参数 - **问题**:用户没有"输入路径"的机会,直接跳到了弹窗 **修改目标**: 新的文件选择流程: ``` ┌─────────────────────────────────────────┐ │ 1. 提示用户输入文件路径 │ │ "请输入 PinMAP 文件路径: " │ ├─────────────────────────────────────────┤ │ 2a. 用户输入了路径 │ │ ├─ 路径存在? → 使用该路径 │ │ └─ 路径不存在? → 报错 + 返回步骤 1 │ │ 2b. 用户直接回车(空输入) │ │ → 弹出 tkinter 文件选择对话框 │ │ ├─ 选择了文件? → 使用该路径 │ │ └─ 取消了? → 返回 None │ └─────────────────────────────────────────┘ ``` **具体改动**: - 修改 `file_selector.py` 中的 `select_file()` 函数 - 新增路径验证逻辑(`os.path.exists()` + 文件扩展名检查) - 新增循环重试逻辑(路径不存在时提示重新输入,最多重试 N 次或无限重试) - 保留 tkinter 弹窗作为空输入时的回退方案 ### 2.3 需求 R3:窗口属性 **现状**: - 项目没有 bat 启动脚本 - 用户通过 `python main.py` 或 `python main.py input.xls` 直接运行 - 窗口属性完全依赖用户 CMD 默认设置 **修改目标**: 创建 `run.bat` 作为标准启动入口,配置窗口属性。 **bat 脚本内容**: ```bat @ECHO OFF chcp 65001 title PinMAP转PinList -By:LeeQwQ mode con cols=80 lines=20 color 0B cls python main.py %* pause EXIT ``` **属性说明**: | 属性 | 命令 | 效果 | |------|------|------| | 编码 | `chcp 65001` | 设置 UTF-8 编码,正确显示中文 | | 窗口标题 | `title PinMAP转PinList -By:LeeQwQ` | 固定署名 | | 窗口大小 | `mode con cols=80 lines=20` | 80列 × 20行可见区域 | | 颜色 | `color 0B` | 黑底(0) + 青字(B/浅蓝) | | 清屏 | `cls` | 启动时清除历史输出 | | 暂停退出 | `pause` | 转换完成后等待按键 | **关于"支持往上滑看历史 log 输出信息"**: - `mode con lines=20` 设置的是**可见窗口行数**(20行),不是缓冲区大小 - Windows CMD 默认的**屏幕缓冲区高度**为 300 行 - 即使可见区域只有 20 行,用户仍可以通过鼠标滚轮或滚动条向上滚动查看历史输出 - 如果需要更大的缓冲区,可额外设置:`mode con cols=80 lines=20` 后,缓冲区默认 300 行已足够 - 如需显式指定缓冲区(可选):可通过注册表或 `mode con` 的缓冲区参数,但通常不需要 **关于"报错时重新输入(不退出)"**: - R2 的文件选择循环已覆盖此场景(路径不存在时返回重试) - 其他阶段的错误(文件读取失败、结构错误等)仍会退出,但 `pause` 确保窗口不关闭,用户可以看到错误信息 --- ## 3. 影响模块列表 | 模块 | 文件 | 影响程度 | 修改内容 | 关联需求 | |------|------|---------|---------|---------| | **入口流程** | `src/main.py` | **高** | 增加启动 Banner、详细日志、结果摘要、任意键退出 | R1, R3 | | **文件选择** | `src/file_selector.py` | **高** | 重写 `select_file()`:路径输入 → 验证 → 弹窗回退 → 循环重试 | R2 | | **启动脚本** | `run.bat`(新建) | **中** | 创建 bat 启动脚本,配置窗口属性 | R3 | | **工具函数** | `src/utils.py` | 无 | 无需修改 | — | | **数据模型** | `src/models.py` | 无 | 无需修改 | — | | **Excel 读写** | `src/xls_reader.py`
`src/xlsx_reader.py`
`src/xlsx_writer.py` | 无 | 无需修改 | — | | **PinMAP 解析** | `src/pinmap_parser.py` | 无 | 无需修改 | — | | **数据验证** | `src/validator.py` | 无 | 无需修改 | — | | **PinList 生成** | `src/pinlist_generator.py` | 无 | 无需修改 | — | **总结**:仅需修改 **2 个现有文件** + 新建 **1 个 bat 脚本**,其余 6 个核心业务模块完全不受影响。 --- ## 4. 技术方案 ### 4.1 R1 技术方案:交互提示 #### 4.1.1 启动 Banner 在 `main.py` 的 `main()` 函数开头添加: ```python def show_banner(): """显示程序启动 Banner""" print("=" * 56) print(" PinMAP → PinList 转换器") print(" 自动将 Excel PinMAP 文件转换为 PinList") print() print(" 版本: v1.0.1") print(" -By: LeeQwQ") print("=" * 56) print() ``` #### 4.1.2 详细日志 在现有流程的每个阶段增加日志输出: ```python # 文件读取前 print(f"[INFO] 正在读取文件: {filepath}") # 文件读取后 print(f"[INFO] 文件读取完成,共 {len(cells)} 个非空单元格") # PinMAP 解析前 print(f"[INFO] 正在解析 PinMAP 结构...") # 验证前 print(f"[INFO] 正在验证数据...") # 验证后(已有) print(f"[INFO] 验证通过,{len(validation.errors)} 个错误,{len(validation.warnings)} 个警告") # 生成前 print(f"[INFO] 正在生成 PinList...") # 写入前 print(f"[INFO] 正在写入输出文件: {output_path}") ``` #### 4.1.3 结果摘要 + 任意键退出 在 `main()` 末尾(所有成功/失败分支)添加: ```python def show_summary(input_path, output_path, pinlist, validation): """显示转换结果摘要""" print() print("=" * 56) print(" 转换结果摘要") print("=" * 56) print(f" 输入文件: {input_path}") print(f" 输出文件: {output_path}") print(f" 封装信息: {pinlist.package_info}") print(f" Pin 数量: {len(pinlist.rows)}") print(f" 错误数量: {len(validation.errors)}") print(f" 警告数量: {len(validation.warnings)}") print("=" * 56) def wait_for_exit(): """等待用户按键后退出""" try: import msvcrt print("\n按任意键退出...") msvcrt.getch() # Windows 专属,无需回车 except ImportError: input("\n按 Enter 键退出...") # 跨平台回退 ``` **技术要点**: - 使用 `msvcrt.getch()` 实现 Windows 上的"任意键退出"(无需按 Enter) - 跨平台回退使用 `input()` - 结果摘要仅在成功转换时显示;错误时直接显示错误信息 + 等待退出 ### 4.2 R2 技术方案:文件选择方式调整 #### 4.2.1 新的 `select_file()` 流程 ```python def select_file() -> Optional[str]: """ 文件选择流程: 1. 提示用户输入文件路径 2. 空输入 → 弹出 tkinter 文件对话框 3. 有输入但路径不存在 → 报错 + 重新输入 4. 有输入且路径存在 → 返回路径 """ while True: # Step 1: 用户输入路径 filepath = input("请输入 PinMAP 文件路径(直接回车使用文件选择器): ").strip() # Step 2: 空输入 → 弹窗 if not filepath: return _select_file_dialog() # Step 3: 路径验证 if not os.path.exists(filepath): print(f"[ERROR] 文件不存在: {filepath}") print("请重新输入...") continue # Step 4: 扩展名检查 if not filepath.lower().endswith(('.xls', '.xlsx')): print(f"[WARN] 文件扩展名不是 .xls 或 .xlsx,是否继续?") confirm = input("输入 Y 继续,其他键重新输入: ").strip().upper() if confirm != 'Y': continue return filepath ``` #### 4.2.2 弹窗回退函数 ```python def _select_file_dialog() -> Optional[str]: """弹出 tkinter 文件选择对话框""" try: import tkinter import tkinter.filedialog root = tkinter.Tk() root.withdraw() root.attributes("-topmost", True) filepath = tkinter.filedialog.askopenfilename( title="选择 PinMAP 文件", filetypes=[ ("Excel 文件", "*.xls *.xlsx"), ("所有文件", "*.*"), ], ) root.destroy() return str(filepath) if filepath else None except (ImportError, Exception): print("[ERROR] 无法打开文件选择器,请手动输入路径") return None ``` **技术要点**: - 使用 `while True` 循环实现路径不存在时的重试 - 扩展名检查为 WARN 级别(允许用户强制继续) - 弹窗回退函数独立封装,保持代码清晰 ### 4.3 R3 技术方案:窗口属性 #### 4.3.1 创建 `run.bat` 在项目根目录创建 `run.bat`: ```bat @ECHO OFF chcp 65001 >nul title PinMAP转PinList -By:LeeQwQ mode con cols=80 lines=20 color 0B cls python main.py %* pause EXIT ``` **说明**: - `chcp 65001 >nul`:静默设置 UTF-8 编码,避免输出 `Active code page: 65001` 干扰界面 - `%*`:透传所有命令行参数(如 `run.bat input.xls`) - `pause`:确保窗口不自动关闭 - `EXIT`:按键后退出 CMD #### 4.3.2 关于"支持往上滑看历史 log" - Windows CMD 默认屏幕缓冲区高度为 **300 行** - `mode con lines=20` 仅设置可见窗口为 20 行,**不影响缓冲区** - 用户可通过鼠标滚轮或滚动条向上滚动查看完整日志历史 - 如需显式增大缓冲区(可选),可在 bat 中通过 PowerShell 设置,但通常 300 行已足够 #### 4.3.3 关于"报错时重新输入(不退出)" - R2 的文件选择循环已覆盖"路径不存在"场景 - 其他阶段报错(文件读取失败、结构错误等)会退出 `main()` 但被 `pause` 拦截 - 窗口不会关闭,用户可阅读错误信息后按任意键退出 --- ## 5. 任务拆分建议 ### 5.1 拆分方案 由于修改范围小(2 个文件 + 1 个新文件),**建议不拆分**,由单个编码 Agent 完成。 | 子任务 | 文件 | 预估工作量 | 依赖 | |--------|------|-----------|------| | T1: 交互提示 | `src/main.py` | 30 分钟 | 无 | | T2: 文件选择调整 | `src/file_selector.py` | 20 分钟 | 无 | | T3: 启动脚本 | `run.bat` | 5 分钟 | 无 | **总计预估**:约 1 小时 ### 5.2 推荐编码 Agent **Python 编码 Agent**(单个 Agent 即可完成) 理由: 1. 修改不涉及核心业务逻辑(解析、验证、生成) 2. 纯 Python 标准库实现,无第三方依赖 3. bat 脚本简单,任何 Agent 均可完成 4. 拆分反而增加沟通成本 ### 5.3 开发顺序 ``` T2(文件选择) → T1(交互提示) → T3(启动脚本) → 集成测试 ``` 理由:T2 和 T1 都修改 `main.py`,建议先完成 T2(file_selector.py 独立),再合并 T1 到 main.py,避免冲突。 --- ## 6. 风险评估 | 风险 | 影响 | 概率 | 缓解措施 | |------|------|------|---------| | `msvcrt.getch()` 在非 Windows 平台不可用 | 低 | 低 | 已设计跨平台回退(`input()`) | | tkinter 在无 GUI 环境不可用 | 低 | 低 | 已设计回退到路径输入模式 | | `mode con lines=20` 窗口过小导致日志被截断 | 中 | 中 | 缓冲区默认 300 行,可滚动查看;如需调整可修改 lines 参数 | | 用户输入路径含特殊字符(空格、中文) | 低 | 中 | Python `os.path.exists()` 和 Excel 读写引擎已支持 Unicode | | bat 脚本中 `python` 命令不在 PATH 中 | 中 | 中 | 可在 bat 中使用 `py` 命令替代(Windows Python Launcher) | ### 6.1 技术难点 **无重大技术难点**。所有需求均使用 Python 标准库实现: - 交互提示:`print()` + `input()` + `msvcrt` - 文件选择:`os.path.exists()` + `tkinter.filedialog` - 窗口属性:bat 内置命令 ### 6.2 兼容性考虑 | 场景 | 处理方式 | |------|---------| | 双击 `run.bat` 运行 | 正常流程,窗口不关闭 | | `run.bat input.xls` 带参数 | `%*` 透传,跳过文件选择 | | 直接 `python main.py`(不用 bat) | 交互提示仍生效,但窗口属性不生效(预期行为) | | 无 GUI 环境(服务器/远程桌面) | 文件选择回退到路径输入模式 | | 非 Windows 平台 | `msvcrt` 回退到 `input()`,bat 不适用 | --- ## 7. 修改后目录结构 ``` pinmap-to-pinlist/ ├── Code/ │ ├── src/ │ │ ├── main.py # ✏️ 修改:增加 Banner、日志、摘要 │ │ ├── file_selector.py # ✏️ 修改:重写 select_file() │ │ ├── xls_reader.py # (不变) │ │ ├── xlsx_reader.py # (不变) │ │ ├── pinmap_parser.py # (不变) │ │ ├── validator.py # (不变) │ │ ├── pinlist_generator.py # (不变) │ │ ├── xlsx_writer.py # (不变) │ │ ├── models.py # (不变) │ │ └── utils.py # (不变) │ └── docs/ │ ├── architecture-design.md # (不变) │ └── modification-assessment.md # 🆕 本文档 ├── run.bat # 🆕 新建:启动脚本 ├── Test/ └── Releases/ ``` --- ## 8. 总结 | 项目 | 内容 | |------|------| | 修改文件数 | 2 个现有 + 1 个新建 | | 影响核心模块 | 无(仅修改入口和文件选择) | | 技术难度 | 低 | | 预估工作量 | ~1 小时 | | 推荐 Agent | Python 编码 Agent(单个) | | 风险等级 | 低 | **结论**:修改需求清晰、范围可控、无技术难点,建议直接分配给单个编码 Agent 执行。 --- *文档结束 — 请审批后进入编码阶段*