# PinMAP ↔ PinList 双向转换器 — 修改需求评估 v1.3 > **版本**: v1.3 > **日期**: 2026-05-31 > **评估人**: 脚本架构师 (Script Architect) > **状态**: 待审批 > **变更**: 4 个 Bug 修复 + 4 个功能增强(BUG-001~004, F005~F008) --- ## 1. 修改需求总览 | 编号 | 类型 | 标题 | 优先级 | 复杂度 | 关联需求 | |------|------|------|--------|--------|---------| | BUG-001 | Bug | run.bat 换行符 + lines 设置不匹配 Windows | 中 | 低 | F005 | | BUG-002 | Bug | 周长计算公式错误 | **高** | 中 | F006 | | BUG-003 | Bug | 双向转换未读取模板样式 | 中 | 中 | F007 | | BUG-004 | Bug | 不支持循环处理流程 | 中 | 中 | F008 | | F005 | 功能 | BAT 脚本修复 | 3 | 低 | BUG-001 | | F006 | 功能 | 周长公式修复 | **1** | 中 | BUG-002 | | F007 | 功能 | 模板读取(双向) | 2 | 中 | BUG-003 | | F008 | 功能 | 循环处理流程 | 2 | 中 | BUG-004 | --- ## 2. 当前代码状态分析 ### 2.1 代码库结构(v1.2.0) ``` pinmap-to-pinlist/ ├── run.bat # ✏️ 需修改(BUG-001/F005) ├── Code/src/ │ ├── main.py # ✏️ 需修改(BUG-003/F007, BUG-004/F008) │ ├── file_selector.py # (不变) │ ├── validator.py # ✏️ 需修改(BUG-002/F006) │ ├── pinlist_validator.py # ✏️ 需修改(BUG-002/F006) │ ├── pinmap_layout.py # ✏️ 需修改(BUG-002/F006) │ ├── pinlist_parser.py # (不变) │ ├── pinmap_generator.py # (不变) │ ├── template_reader.py # (不变) │ ├── xlsx_writer.py # (不变) │ ├── models.py # (不变) │ ├── xls_reader.py # (不变) │ ├── xlsx_reader.py # (不变) │ ├── pinlist_generator.py # (不变) │ └── utils.py # (不变) └── docs/ ├── bugs.md # ✏️ 需更新状态 ├── features.md # ✏️ 需更新状态 └── modification-assessment-v1.3.md # 🆕 本文档 ``` ### 2.2 各 Bug 当前代码状态 #### BUG-001: run.bat 问题 **当前 run.bat 内容**: ```bat @ECHO OFF chcp 65001 >nul title PinMAP转PinList -By:LeeQwQ mode con cols=80 lines=50 ← 问题:含 lines=50 color 0B cls cd /d "%~dp0Code\src" python main.py echo. pause EXIT ``` **问题 1**:文件使用 Unix LF 换行符(`\n`),Windows 下应使用 CRLF(`\r\n`)。 **问题 2**:`mode con cols=80 lines=50` 中的 `lines=50` 是多余的,需求仅保留 `cols=80`。 --- #### BUG-002: 周长公式错误 **当前公式**(3 处代码): ``` expected_total = 2 * rows + 2 * cols - 4 ``` **问题**:对于 15×15 网格 + 60 Pin,当前公式计算为 `2*15+2*15-4 = 56`,但用户期望 `(15+15)*2 = 60`。 **涉及文件**: 1. `Code/src/pinlist_validator.py` — `validate_pinlist()` 中的周长匹配检查 2. `Code/src/validator.py` — `validate_pinlist_for_map()` 中的周长匹配检查 3. `Code/src/pinmap_layout.py` — `calculate_layout()` 中的 `total` 计算和 `LayoutError` **数学分析**: | 网格 | 当前公式 `2r+2c-4` | 新公式 `(r+c)*2` | 说明 | |------|-------------------|-----------------|------| | 4×8 | 20 | 24 | 当前公式少算 4 | | 15×15 | 56 | 60 | 当前公式少算 4 | | 2×2 | 4 | 8 | 当前公式少算 4 | 新公式 `(rows+cols)*2` 对所有尺寸均多 4 个 Pin。这意味着布局分配算法也需要相应调整。 **布局分配需同步修改**: 当前分配(`pinmap_layout.py`): ``` 左边: rows 个 下边: cols-1 个 右边: rows-2 个 上边: cols-1 个 总计: 2*rows + 2*cols - 4 ``` 新分配(`(rows+cols)*2`): ``` 左边: rows 个 下边: cols 个 右边: rows 个 上边: cols 个 总计: 2*rows + 2*cols ``` 这意味着四个角点不再共享,每个角点归属一条边。需重新设计单元格坐标计算逻辑。 --- #### BUG-003: 模板读取路径错误 **当前代码**(`main.py` → `run_list_to_map()`): ```python template_style = read_template_styles(filepath) ``` **问题**:`filepath` 是用户选择的 PinList 输入文件路径,而非模板文件路径。模板文件应为根目录下的 `PinMAP-Template.xlsx`。 **MAP→List 方向**(`run_map_to_list()`): 当前代码未调用 `read_template_styles()`,PinList 输出直接使用 `write_xlsx()`(无样式)。 **需要修复**: 1. List→MAP:将 `read_template_styles(filepath)` 改为读取根目录模板 2. MAP→List:增加模板读取和样式应用 --- #### BUG-004: 无循环处理流程 **当前 `main()` 流程**: ```python def main(): show_banner() # 选择方向 → 执行一次转换 → wait_for_exit() → 程序结束 ``` **问题**:转换完成后直接退出,用户需重新运行程序才能处理下一个文件。 **期望流程**: ``` 启动 → 选择方向 → 处理文件 → [处理完成] → 等待输入下一个文件 / Q 返回主菜单 ``` --- ## 3. 逐项修改方案 --- ### 3.1 BUG-001 / F005: BAT 脚本修复 **修改范围**:`run.bat`(1 个文件) **具体修改**: 1. **换行符**:确保文件使用 CRLF(`\r\n`)换行。写入文件时指定 `newline='\r\n'`。 2. **去掉 lines=50**:将 `mode con cols=80 lines=50` 改为 `mode con cols=80`。 **修改后 run.bat**: ```bat @ECHO OFF chcp 65001 >nul title PinMAP转PinList -By:LeeQwQ mode con cols=80 color 0B cls cd /d "%~dp0Code\src" python main.py echo. pause EXIT ``` **风险评估**: | 风险 | 影响 | 概率 | 缓解措施 | |------|------|------|---------| | CRLF 写入失败 | 低 | 极低 | Python `open(path, 'w', newline='\r\n')` 保证 | | 去掉 lines 后窗口行数变回默认 | 低 | 确认 | 默认 300 行缓冲区,足够查看日志 | **工作量**:5 分钟 --- ### 3.2 BUG-002 / F006: 周长公式修复 **修改范围**:3 个文件 | 文件 | 修改内容 | 修改行数 | |------|---------|---------| | `pinlist_validator.py` | 周长匹配公式 + 错误提示文案 | ~5 行 | | `validator.py` | `validate_pinlist_for_map()` 周长公式 | ~5 行 | | `pinmap_layout.py` | 边分配计数 + 单元格坐标计算 | ~20 行 | **具体修改**: #### 3.2.1 `pinlist_validator.py` — `validate_pinlist()` ```python # 修改前: expected_total = 2 * rows + 2 * cols - 4 # 修改后: expected_total = (rows + cols) * 2 ``` #### 3.2.2 `validator.py` — `validate_pinlist_for_map()` ```python # 修改前: expected_total = 2 * rows + 2 * cols - 4 # 修改后: expected_total = (rows + cols) * 2 ``` #### 3.2.3 `pinmap_layout.py` — `calculate_layout()` **边分配计数修改**: ```python # 修改前: left_count = rows bottom_count = cols - 1 right_count = rows - 2 top_count = cols - 1 # total = 2*rows + 2*cols - 4 # 修改后: left_count = rows bottom_count = cols right_count = rows top_count = cols # total = 2*rows + 2*cols ``` **单元格坐标计算修改**: ```python # 修改前(角点共享): # 左边: (r, 0) r ∈ [1, rows] # 下边: (rows, c) c ∈ [1, cols-1] # 右边: (r, cols) r ∈ [rows-1, 2] 逆序 # 上边: (1, c) c ∈ [cols-1, 2] 逆序 # 修改后(角点不共享,每条边独立): # 左边: (r, 0) r ∈ [1, rows] # 下边: (rows, c) c ∈ [1, cols] # 右边: (r, cols) r ∈ [rows, 1] 逆序 # 上边: (1, c) c ∈ [cols, 1] 逆序 ``` ```python # 修改后代码: left_cells = [(r, 0) for r in range(1, rows + 1)] bottom_cells = [(rows, c) for c in range(1, cols + 1)] right_cells = [(r, cols) for r in range(rows, 0, -1)] top_cells = [(1, c) for c in range(cols, 0, -1)] ``` **`get_name_cell()` 函数修改**: ```python # 修改前: # left: (r, c+1) # bottom: (r-1, c) # right: (r, c-1) # top: (r+1, c) # 修改后:逻辑不变(Name 单元格相对于序号单元格的位置不变) # 但需确保角点单元格 Name 不冲突 ``` **风险评估**: | 风险 | 影响 | 概率 | 缓解措施 | |------|------|------|---------| | 布局算法修改引入新 Bug | **高** | 中 | 对 4×8、15×15、2×2 等典型尺寸做单元测试 | | 角点单元格 Name 重叠 | 中 | 中 | 修改 `get_name_cell()` 确保角点 Name 不冲突 | | 已有用户数据不兼容 | 低 | 低 | 用户需重新输入正确的 PinList | | 修改 3 个文件不一致 | 中 | 低 | 使用同一公式常量,避免硬编码 | **工作量**:1.5 小时 --- ### 3.3 BUG-003 / F007: 模板读取修复 **修改范围**:1 个文件(`main.py`) **问题根因**: 1. List→MAP:`read_template_styles(filepath)` 传入的是输入文件路径,而非模板路径 2. MAP→List:完全没有模板读取逻辑 **具体修改**: #### 3.3.1 新增模板路径解析辅助函数 ```python def _find_template_path() -> str | None: """查找根目录下的 PinMAP-Template.xlsx。 搜索顺序: 1. 与 run.bat 同级的根目录 2. 当前工作目录 """ # 尝试从 Code/src 回退到根目录 src_dir = os.path.dirname(os.path.abspath(__file__)) root_dir = os.path.dirname(os.path.dirname(src_dir)) # pinmap-to-pinlist/ template_path = os.path.join(root_dir, "PinMAP-Template.xlsx") if os.path.exists(template_path): return template_path # 回退到当前工作目录 cwd_template = os.path.join(os.getcwd(), "PinMAP-Template.xlsx") if os.path.exists(cwd_template): return cwd_template return None ``` #### 3.3.2 修改 `run_list_to_map()` ```python # 修改前: template_style = read_template_styles(filepath) # 修改后: template_path = _find_template_path() if template_path: template_style = read_template_styles(template_path) if template_style: print(f"[INFO] 已加载模板样式: {template_path}") else: print("[WARN] 模板文件存在但解析失败,使用默认样式") else: template_style = None print("[INFO] 未检测到模板文件,使用默认样式") ``` #### 3.3.3 修改 `run_map_to_list()` ```python # 在写入 PinList 之前,增加模板读取逻辑: template_path = _find_template_path() template_style = None if template_path: template_style = read_template_styles(template_path) if template_style: print(f"[INFO] 已加载模板样式: {template_path}") # 写入时: if template_style is not None: write_xlsx_with_style(data, output_path, template_style) else: write_xlsx(data, output_path) ``` **风险评估**: | 风险 | 影响 | 概率 | 缓解措施 | |------|------|------|---------| | 模板路径解析错误 | 中 | 低 | 多路径回退 + 优雅降级 | | 模板解析失败导致崩溃 | 低 | 低 | `template_reader.py` 已有 try-except 优雅降级 | | MAP→List 应用模板样式后 PinList 格式不符合用户预期 | 中 | 低 | 模板仅影响样式(字体/边框),不影响数据 | **工作量**:1 小时 --- ### 3.4 BUG-004 / F008: 循环处理流程 **修改范围**:1 个文件(`main.py`) **具体修改**: 将 `main()` 改造为循环结构: ```python def main(): show_banner() while True: # ── Direction selection ─────────────────────────────── if len(sys.argv) > 1: # Legacy mode: 直接文件参数 → MAP→List → 循环 direction = 1 filepath = sys.argv[1] sys.argv = [sys.argv[0]] # 清除 argv,下次循环进入交互模式 else: print("请选择转换方向:") print(" 1 — PinMAP → PinList") print(" 2 — PinList → PinMAP") print(" Q — 退出程序") print() choice = input("请输入选项 (1/2/Q): ").strip().upper() if choice == 'Q': print("感谢使用,再见!") return elif choice == '1': direction = 1 elif choice == '2': direction = 2 else: print("[ERROR] 无效选项,请输入 1、2 或 Q") continue filepath = None # ── Dispatch ────────────────────────────────────────── if direction == 1: print() print("─" * 40) print(" 方向: PinMAP → PinList") print("─" * 40) print() run_map_to_list(filepath) else: print() print("─" * 40) print(" 方向: PinList → PinMAP") print("─" * 40) print() run_list_to_map(filepath) # ── 处理完成后循环 ──────────────────────────────────── print() print("=" * 40) next_action = input("输入文件名继续处理,或按 Enter 返回主菜单,输入 Q 退出: ").strip() if next_action.upper() == 'Q': print("感谢使用,再见!") return elif next_action: # 直接处理指定文件(自动检测方向) filepath = next_action # 根据文件内容自动判断方向,或默认 MAP→List direction = 1 else: # 返回主菜单(继续 while 循环) pass ``` **同时需要修改 `run_map_to_list()` 和 `run_list_to_map()`**: 将两个函数末尾的 `wait_for_exit()` 替换为 `input("按 Enter 键继续...")`,这样处理完成后用户可以继续操作而不是退出。 ```python # 修改前(两处): wait_for_exit() # 修改后: input("按 Enter 键继续...") ``` **但注意**:`wait_for_exit()` 仍保留,用于: - 致命错误(FATAL)时的退出 - 用户未选择文件时的退出 - 命令行参数模式下最后一次退出 **风险评估**: | 风险 | 影响 | 概率 | 缓解措施 | |------|------|------|---------| | 循环导致内存泄漏(模块重复 import) | 低 | 低 | Python import 有缓存,重复 import 无开销 | | 用户输入 Q 后状态混乱 | 中 | 低 | Q 只在主菜单和处理完成后接受,转换过程中不响应 | | 命令行参数模式与循环模式冲突 | 中 | 中 | 命令行参数模式执行一次后清除 argv,进入交互循环 | **工作量**:1 小时 --- ## 4. 修改影响矩阵 | 文件 | BUG-001 | BUG-002 | BUG-003 | BUG-004 | 总改动量 | |------|---------|---------|---------|---------|---------| | `run.bat` | ✏️ 换行+CRLF, 去lines | | | | 2 行 | | `main.py` | | | ✏️ 模板路径 | ✏️ 循环流程 | ~40 行 | | `pinlist_validator.py` | | ✏️ 公式 | | | ~5 行 | | `validator.py` | | ✏️ 公式 | | | ~5 行 | | `pinmap_layout.py` | | ✏️ 公式+布局 | | | ~20 行 | | **合计** | **1 文件** | **3 文件** | **1 文件** | **1 文件** | **5 文件** | --- ## 5. 优先级排序 | 优先级 | 编号 | 原因 | |--------|------|------| | **P0** | BUG-002 / F006 | 核心公式错误,所有 List→MAP 转换均受影响 | | **P1** | BUG-001 / F005 | 影响 Windows 用户体验,修复简单 | | **P2** | BUG-003 / F007 | 功能增强,模板样式对输出质量有影响 | | **P2** | BUG-004 / F008 | 体验优化,批量处理场景需要 | --- ## 6. 工作量估算 | 任务 | 文件 | 预估时间 | 依赖 | |------|------|---------|------| | BUG-001/F005 | `run.bat` | 5 分钟 | 无 | | BUG-002/F006 | `pinlist_validator.py`, `validator.py`, `pinmap_layout.py` | 1.5 小时 | 无 | | BUG-003/F007 | `main.py` | 1 小时 | 无 | | BUG-004/F008 | `main.py` | 1 小时 | 无 | | 文档更新 | `bugs.md`, `features.md` | 10 分钟 | 无 | **总计预估**:约 3 小时 --- ## 7. 推荐开发顺序 ``` 第1轮(独立,可并行): BUG-001/F005: BAT 脚本修复(5 分钟,任何 Agent) 第2轮(核心,必须最先): BUG-002/F006: 周长公式修复(1.5 小时,需理解布局算法) 第3轮(独立): BUG-003/F007: 模板读取修复(1 小时) BUG-004/F008: 循环处理流程(1 小时) (两者都修改 main.py,建议先后执行避免冲突) 第4轮(收尾): 文档更新:bugs.md + features.md ``` --- ## 8. 验收标准 ### 8.1 BUG-001 / F005 验收 | 验收项 | 方法 | 预期结果 | |--------|------|---------| | run.bat 使用 CRLF 换行 | 二进制查看文件 | 每行末尾为 `\r\n` | | 不含 `lines=` 参数 | 文本搜索 | 无 `lines=` 字符串 | | 仅含 `mode con cols=80` | 文本搜索 | 仅一行 `mode con cols=80` | | Windows 下双击运行正常 | 实际运行 | 窗口正常打开,中文显示正确 | ### 8.2 BUG-002 / F006 验收 | 验收项 | 方法 | 预期结果 | |--------|------|---------| | 15×15 网格 + 60 Pin 验证通过 | 输入测试 | 无错误提示,转换成功 | | 4×8 网格 + 24 Pin 验证通过 | 输入测试 | 无错误提示,转换成功 | | 2×2 网格 + 8 Pin 验证通过 | 输入测试 | 无错误提示,转换成功 | | 错误 Pin 数量仍报错 | 输入 15×15+56Pin | 提示不匹配 | | 布局计算正确 | 检查输出文件 | 四条边 Pin 分布正确 | ### 8.3 BUG-003 / F007 验收 | 验收项 | 方法 | 预期结果 | |--------|------|---------| | List→MAP 读取模板 | 放置模板文件后转换 | 日志显示"已加载模板样式" | | MAP→List 读取模板 | 放置模板文件后转换 | 日志显示"已加载模板样式" | | 无模板时优雅降级 | 不放置模板文件 | 日志显示"未检测到模板文件",使用默认样式 | | 模板解析失败降级 | 放置损坏的模板文件 | 日志显示"解析失败",使用默认样式 | | 输出文件样式正确 | 打开输出文件 | 字体、边框、对齐与模板一致 | ### 8.4 BUG-004 / F008 验收 | 验收项 | 方法 | 预期结果 | |--------|------|---------| | 处理完不退出 | 完成一次转换 | 显示"按 Enter 键继续"或循环提示 | | 输入 Q 返回主菜单 | 处理完成后输入 Q | 返回方向选择菜单 | | 主菜单输入 Q 退出 | 主菜单输入 Q | 程序退出 | | 连续处理多个文件 | 连续选择文件 | 可连续处理,无需重新运行 | | 命令行参数模式 | `run.bat input.xls` | 处理完成后进入循环 | --- ## 9. 风险评估汇总 | 风险 | 影响 | 概率 | 缓解措施 | |------|------|------|---------| | 周长公式修改导致已有布局算法不一致 | **高** | 中 | 同步修改 validator + layout,确保公式统一 | | 角点单元格 Name 冲突 | 中 | 中 | 修改 `get_name_cell()` 确保不重叠 | | main.py 两处修改冲突 | 中 | 中 | 先完成 BUG-003,再完成 BUG-004,避免同时修改 | | 模板路径在命令行模式下解析错误 | 低 | 低 | 使用 `__file__` 绝对路径而非 cwd | | 循环流程中模块重复 import 性能 | 低 | 极低 | Python 有 import 缓存 | --- ## 10. 总结 | 项目 | 内容 | |------|------| | 修改文件数 | 5 个(run.bat, main.py, pinlist_validator.py, validator.py, pinmap_layout.py) | | 新增文件数 | 0 | | 影响核心模块 | 是(pinmap_layout.py 布局算法) | | 技术难度 | 中(周长公式 + 布局算法需同步修改) | | 预估工作量 | ~3 小时 | | 推荐 Agent | Python 编码 Agent(1-2 个) | | 风险等级 | 中(公式修改需仔细验证) | **结论**: 1. BUG-002 为最高优先级,影响所有 List→MAP 转换的正确性 2. BUG-001 修复最简单,可快速完成 3. BUG-003 和 BUG-004 都修改 `main.py`,需先后执行避免冲突 4. 所有修改均使用 Python 标准库,无新增依赖 5. 建议修改完成后运行完整测试套件验证 --- *文档结束 — 请审批后进入编码阶段*