v1.1.0: 增加交互提示、路径输入、窗口属性配置
- main.py: 增加show_banner()启动说明、各阶段[INFO]日志、结果摘要、任意键退出 - file_selector.py: 重写为路径输入→验证→空输入弹窗回退→不存在循环重试 - run.bat: 新建启动脚本(chcp 65001, mode con cols=80 lines=20, color 0B, title固定署名, pause) - Code/docs/modification-assessment.md: 修改需求评估文档
This commit is contained in:
315
Releases/v1.0.1/docs/QUICKSTART.md
Normal file
315
Releases/v1.0.1/docs/QUICKSTART.md
Normal file
@@ -0,0 +1,315 @@
|
||||
# 快速入门指南
|
||||
|
||||
本文档帮助你快速上手 PinMAP → PinList 转换器。
|
||||
|
||||
---
|
||||
|
||||
## 环境要求
|
||||
|
||||
### 系统要求
|
||||
|
||||
| 项目 | 要求 |
|
||||
|------|------|
|
||||
| 操作系统 | Windows 7+ / Linux / macOS |
|
||||
| Python | 3.6+(推荐 3.8+) |
|
||||
| 内存 | ≥ 64MB(实际使用 < 20MB) |
|
||||
| 磁盘 | ≥ 1MB |
|
||||
|
||||
### 依赖项
|
||||
|
||||
**零第三方依赖** — 仅需 Python 标准库。
|
||||
|
||||
```bash
|
||||
# 检查 Python 版本
|
||||
python --version
|
||||
# 输出示例: Python 3.12.3
|
||||
```
|
||||
|
||||
### GUI 支持(可选)
|
||||
|
||||
- **Windows**: tkinter 内置,开箱即用
|
||||
- **Linux**: 需要 `python3-tk` 包(`sudo apt install python3-tk`)
|
||||
- **macOS**: tkinter 内置
|
||||
|
||||
> 无 GUI 环境时自动回退到命令行模式,不影响核心功能。
|
||||
|
||||
---
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 第一步:获取项目
|
||||
|
||||
```bash
|
||||
# 进入项目目录
|
||||
cd pinmap-to-pinlist/Code/src/
|
||||
```
|
||||
|
||||
### 第二步:运行转换
|
||||
|
||||
#### 方式一:GUI 模式(推荐)
|
||||
|
||||
```bash
|
||||
python main.py
|
||||
```
|
||||
|
||||
弹出文件选择对话框,选择 `.xls` 或 `.xlsx` 文件即可。
|
||||
|
||||
#### 方式二:命令行模式
|
||||
|
||||
```bash
|
||||
python main.py /path/to/your/input.xlsx
|
||||
```
|
||||
|
||||
### 第三步:查看输出
|
||||
|
||||
转换完成后,在当前目录生成 `{原文件名}_PinList.xlsx`:
|
||||
|
||||
```
|
||||
输入: QFP44_PinMAP.xlsx
|
||||
输出: QFP44_PinMAP_PinList.xlsx
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 示例 1:标准方形 PinMAP
|
||||
|
||||
**输入文件** `QFP44.xlsx`:
|
||||
|
||||
```
|
||||
A B C D E F
|
||||
1 QFP-44
|
||||
2 Pin6 6
|
||||
3 Pin5 5
|
||||
4 1 Pin1
|
||||
5 2 Pin2
|
||||
6 Pin3 Pin4
|
||||
7 3 4
|
||||
```
|
||||
|
||||
**运行命令**:
|
||||
|
||||
```bash
|
||||
python main.py QFP44.xlsx
|
||||
```
|
||||
|
||||
**输出**:
|
||||
|
||||
```
|
||||
[INFO] 解析完成: 6x6 方形,共 8 个Pin
|
||||
[INFO] 封装信息: QFP-44
|
||||
|
||||
[SUCCESS] 转换完成!输出文件: QFP44_PinList.xlsx
|
||||
- 封装信息: QFP-44
|
||||
- Pin数量: 8
|
||||
```
|
||||
|
||||
**输出文件内容**:
|
||||
|
||||
```
|
||||
A B
|
||||
1 QFP-44
|
||||
2 Pin1 1
|
||||
3 Pin2 2
|
||||
4 Pin3 3
|
||||
5 Pin4 4
|
||||
6 Pin5 5
|
||||
7 Pin6 6
|
||||
```
|
||||
|
||||
### 示例 2:长方形 PinMAP
|
||||
|
||||
**输入文件** `LQFP100.xlsx`(13 个引脚的长方形封装)
|
||||
|
||||
```bash
|
||||
python main.py LQFP100.xlsx
|
||||
```
|
||||
|
||||
**输出**:
|
||||
|
||||
```
|
||||
[INFO] 解析完成: 长方形结构,共 13 个Pin
|
||||
[INFO] 封装信息: LQFP-100
|
||||
|
||||
[SUCCESS] 转换完成!输出文件: LQFP100_PinList.xlsx
|
||||
- 封装信息: LQFP-100
|
||||
- Pin数量: 13
|
||||
```
|
||||
|
||||
### 示例 3:处理警告
|
||||
|
||||
当 PinMAP 中部分引脚缺少 PinName 时:
|
||||
|
||||
```
|
||||
[INFO] 解析完成: 6x6 方形,共 8 个Pin
|
||||
[INFO] 封装信息: QFP-44
|
||||
|
||||
[WARN] 发现 3 个警告:
|
||||
- 检测到 3 个引脚缺少 PinName: 缺失引脚序号: [2, 3, 4],将默认为 NC
|
||||
|
||||
[SUCCESS] 转换完成!输出文件: QFP44_PinList.xlsx
|
||||
- 封装信息: QFP-44
|
||||
- Pin数量: 8
|
||||
```
|
||||
|
||||
缺失 PinName 的引脚在输出中自动标记为 "NC"。
|
||||
|
||||
### 示例 4:处理错误
|
||||
|
||||
当 PinMAP 存在数据错误时:
|
||||
|
||||
```
|
||||
[INFO] 解析完成: 6x6 方形,共 8 个Pin
|
||||
[INFO] 封装信息: QFP-44
|
||||
|
||||
[ERROR] 发现 1 个错误:
|
||||
- Pin序号不连续: 缺失的序号: [3]
|
||||
|
||||
转换终止,请修正PinMAP文件后重试。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PinMAP 文件规范
|
||||
|
||||
### 格式要求
|
||||
|
||||
| 要求 | 说明 |
|
||||
|------|------|
|
||||
| A1 单元格 | 必须包含封装信息(如 "QFP-44") |
|
||||
| 方形区域 | 至少 2×2,引脚沿四条边分布 |
|
||||
| 引脚序号 | 1-based 整数,从 1 到 N 连续 |
|
||||
| 排序方向 | 左上角为 1 脚,逆时针排列 |
|
||||
| PinName 位置 | 在序号单元格的"内侧相邻"位置 |
|
||||
|
||||
### 四边 PinName 位置
|
||||
|
||||
```
|
||||
左边:序号在 (r, min_col),PinName 在 (r, min_col+1)
|
||||
下边:序号在 (max_row, c),PinName 在 (max_row-1, c)
|
||||
右边:序号在 (r, max_col),PinName 在 (r, max_col-1)
|
||||
上边:序号在 (min_row, c),PinName 在 (min_row+1, c)
|
||||
```
|
||||
|
||||
### 支持的输入格式
|
||||
|
||||
| 格式 | 扩展名 | 支持情况 |
|
||||
|------|--------|----------|
|
||||
| Excel 97-2003 | `.xls` | ✅ 支持(BIFF8 引擎) |
|
||||
| Excel 2007+ | `.xlsx` | ✅ 支持(OOXML 引擎) |
|
||||
|
||||
### 输出格式
|
||||
|
||||
| 格式 | 扩展名 | 说明 |
|
||||
|------|--------|------|
|
||||
| Excel 2007+ | `.xlsx` | 唯一输出格式 |
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q1: 运行时提示 "未选择文件,退出"
|
||||
|
||||
**原因**:在 GUI 模式下点击了"取消",或在无 GUI 环境下未提供命令行参数。
|
||||
|
||||
**解决**:
|
||||
```bash
|
||||
# 提供命令行参数
|
||||
python main.py input.xlsx
|
||||
```
|
||||
|
||||
### Q2: 提示 "文件读取失败"
|
||||
|
||||
**可能原因**:
|
||||
- 文件路径不存在
|
||||
- 文件格式不是有效的 Excel 文件
|
||||
- 文件已损坏
|
||||
|
||||
**解决**:
|
||||
- 检查文件路径是否正确
|
||||
- 确认文件可以用 Excel 正常打开
|
||||
- 尝试用 Excel 重新保存文件
|
||||
|
||||
### Q3: 提示 "A1 单元格为空,缺少封装信息"
|
||||
|
||||
**原因**:PinMAP 文件的 A1 单元格为空。
|
||||
|
||||
**解决**:在 Excel 中打开文件,在 A1 单元格填入封装信息(如 "QFP-44"),保存后重新转换。
|
||||
|
||||
### Q4: 提示 "Pin序号不连续"
|
||||
|
||||
**原因**:Pin 序号存在间隔(如 1, 2, 4, 5,缺少 3)。
|
||||
|
||||
**解决**:检查 PinMAP 文件,补全缺失的引脚序号。
|
||||
|
||||
### Q5: 提示 "Pin序号重复"
|
||||
|
||||
**原因**:同一个 Pin 序号出现了多次。
|
||||
|
||||
**解决**:检查 PinMAP 文件,修正重复的序号。
|
||||
|
||||
### Q6: 警告 "检测到 N 个引脚缺少 PinName"
|
||||
|
||||
**说明**:这是警告而非错误,转换会继续进行。缺失的 PinName 会自动设为 "NC"。
|
||||
|
||||
**解决**(可选):在 Excel 中补全缺失的 PinName,重新转换。
|
||||
|
||||
### Q7: Linux 下没有弹出文件选择对话框
|
||||
|
||||
**说明**:Linux 无头环境(无显示器)不支持 tkinter GUI。
|
||||
|
||||
**解决**:使用命令行模式:
|
||||
```bash
|
||||
python main.py /path/to/input.xlsx
|
||||
```
|
||||
|
||||
如需 GUI,安装 tkinter:
|
||||
```bash
|
||||
sudo apt install python3-tk
|
||||
```
|
||||
|
||||
### Q8: 输出文件打不开
|
||||
|
||||
**可能原因**:Excel 版本过旧(2003 及以下不支持 .xlsx)。
|
||||
|
||||
**解决**:使用 Excel 2007+ 或 WPS Office 打开输出文件。
|
||||
|
||||
### Q9: 支持多大的 PinMAP?
|
||||
|
||||
**回答**:当前实现适合 < 1000 引脚的场景。典型 IC 封装引脚数在 8~200 之间,完全满足需求。
|
||||
|
||||
### Q10: 能否批量转换多个文件?
|
||||
|
||||
**回答**:当前版本一次处理一个文件。如需批量转换,可使用 shell 脚本:
|
||||
|
||||
```bash
|
||||
for f in *.xlsx; do
|
||||
python main.py "$f"
|
||||
done
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 测试验证
|
||||
|
||||
运行内置单元测试:
|
||||
|
||||
```bash
|
||||
cd Code/src/
|
||||
python test_pinmap.py
|
||||
```
|
||||
|
||||
预期输出:
|
||||
```
|
||||
✓ test_4x4_parse passed
|
||||
✓ test_4x4_validate passed
|
||||
✓ test_missing_names_warning passed
|
||||
✓ test_duplicate_numbers passed
|
||||
✓ test_gap_in_numbers passed
|
||||
✓ test_empty_cells passed
|
||||
✓ test_no_pins passed
|
||||
✓ test_12pin_square passed
|
||||
|
||||
✅ All tests passed!
|
||||
```
|
||||
242
Releases/v1.0.1/docs/README.md
Normal file
242
Releases/v1.0.1/docs/README.md
Normal file
@@ -0,0 +1,242 @@
|
||||
# PinMAP → PinList 转换器
|
||||
|
||||
将 Excel 格式的 **PinMAP** 文件(方形封装引脚布局图)自动转换为 **PinList** 格式(引脚序号列表),消除手动抄录的低效与错误风险。
|
||||
|
||||
---
|
||||
|
||||
## 项目简介
|
||||
|
||||
在 IC 封装设计中,PinMAP 以方形/长方形矩阵形式展示引脚分布,而 PinList 则以线性列表形式提供引脚序号对照。本项目通过纯 Python 实现,自动完成从 PinMAP 到 PinList 的转换,支持 `.xls` 和 `.xlsx` 两种格式。
|
||||
|
||||
**版本**: v1.0.0
|
||||
**发布日期**: 2026-05-25
|
||||
**运行平台**: Windows(tkinter GUI)/ Linux(命令行回退)
|
||||
**技术栈**: Python 标准库,零第三方依赖
|
||||
|
||||
---
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 核心功能
|
||||
|
||||
| 功能 | 说明 |
|
||||
|------|------|
|
||||
| **PinMAP 解析** | 自动识别方形/长方形结构,沿四条边(左→下→右→上)逆时针提取引脚 |
|
||||
| **数据验证** | 检测序号不连续、序号重复、PinName 缺失、A1 封装信息缺失 |
|
||||
| **PinList 生成** | A 列 PinName,B 列 Pin 序号,按序号递增排序 |
|
||||
| **双格式支持** | 同时支持 `.xls`(BIFF8 引擎)和 `.xlsx`(OOXML 引擎) |
|
||||
| **双模式运行** | GUI 文件选择对话框 + 命令行参数模式 |
|
||||
|
||||
### 验证规则
|
||||
|
||||
- **序号连续性**:Pin 序号必须为 1~N 连续整数,无间隔
|
||||
- **序号唯一性**:每个 Pin 序号只能出现一次,无重复
|
||||
- **PinName 完整性**:缺失 PinName 的引脚自动标记为 "NC"(警告级别,不中断流程)
|
||||
- **结构完整性**:方形区域至少 2×2,A1 单元格必须包含封装信息
|
||||
|
||||
---
|
||||
|
||||
## 技术栈
|
||||
|
||||
### 零第三方依赖
|
||||
|
||||
本项目完全使用 Python 标准库实现,不依赖任何第三方包。
|
||||
|
||||
| 模块 | 用途 | 标准库 |
|
||||
|------|------|--------|
|
||||
| `xls_reader.py` | BIFF8 解析引擎(~19KB OLE2 解析) | `struct` |
|
||||
| `xlsx_reader.py` | XLSX 读取引擎(ZIP + XML 解析) | `zipfile`, `xml.etree.ElementTree` |
|
||||
| `xlsx_writer.py` | XLSX 写入引擎(OOXML 构建) | `zipfile`, `xml.etree.ElementTree` |
|
||||
| `file_selector.py` | 文件选择对话框 | `tkinter.filedialog` |
|
||||
| `pinmap_parser.py` | PinMAP 结构解析 | 纯 Python |
|
||||
| `validator.py` | 数据验证 | `collections.Counter` |
|
||||
| `pinlist_generator.py` | PinList 生成 | 纯 Python |
|
||||
|
||||
### 核心技术亮点
|
||||
|
||||
- **BIFF8 手动解析**:从零实现 OLE2 复合文档 + BIFF8 记录流解析,支持 SST、LABELSST、NUMBER、FORMULA、RK、MULRK、LABEL 等记录类型
|
||||
- **OOXML 手动构建**:不使用 openpyxl/xlrd,纯手工构建 `[Content_Types].xml`、`workbook.xml`、`sharedStrings.xml`、`sheet1.xml` 等 OOXML 结构
|
||||
- **模块化架构**:解析 → 验证 → 生成 → 输出,各模块职责清晰,接口契约明确
|
||||
|
||||
---
|
||||
|
||||
## 使用方式
|
||||
|
||||
### 前提条件
|
||||
|
||||
- Python 3.6+(推荐 3.8+)
|
||||
- Windows 环境(GUI 模式需要 tkinter)
|
||||
- Linux/Mac 环境(仅命令行模式)
|
||||
|
||||
### 命令行模式
|
||||
|
||||
```bash
|
||||
# 基本用法
|
||||
python main.py input.xlsx
|
||||
|
||||
# 支持 .xls 格式
|
||||
python main.py input.xls
|
||||
|
||||
# 输出文件自动命名为 input_PinList.xlsx
|
||||
```
|
||||
|
||||
### GUI 模式
|
||||
|
||||
```bash
|
||||
# 不带参数运行,弹出文件选择对话框
|
||||
python main.py
|
||||
```
|
||||
|
||||
在对话框中选择 `.xls` 或 `.xlsx` 文件,点击"打开"即可开始转换。
|
||||
|
||||
### 输出示例
|
||||
|
||||
输入 PinMAP(方形封装):
|
||||
|
||||
```
|
||||
A B C D E F
|
||||
1 QFP-44
|
||||
2 Pin6 6
|
||||
3 Pin5 5
|
||||
4 1 Pin1
|
||||
5 2 Pin2
|
||||
6 Pin3 Pin4
|
||||
7 3 4
|
||||
```
|
||||
|
||||
输出 PinList:
|
||||
|
||||
```
|
||||
A B
|
||||
1 QFP-44
|
||||
2 Pin1 1
|
||||
3 Pin2 2
|
||||
4 Pin3 3
|
||||
5 Pin4 4
|
||||
6 Pin5 5
|
||||
7 Pin6 6
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
pinmap-to-pinlist/
|
||||
├── Code/
|
||||
│ ├── src/
|
||||
│ │ ├── main.py # 主入口:流程编排
|
||||
│ │ ├── file_selector.py # 文件选择(GUI + 命令行回退)
|
||||
│ │ ├── xls_reader.py # XLS (BIFF8) 读取引擎
|
||||
│ │ ├── xlsx_reader.py # XLSX 读取引擎
|
||||
│ │ ├── xlsx_writer.py # XLSX 写入引擎
|
||||
│ │ ├── pinmap_parser.py # PinMAP 结构解析
|
||||
│ │ ├── validator.py # 数据验证
|
||||
│ │ ├── pinlist_generator.py # PinList 生成
|
||||
│ │ ├── models.py # 数据模型
|
||||
│ │ ├── utils.py # 工具函数
|
||||
│ │ └── test_pinmap.py # 单元测试
|
||||
│ └── docs/
|
||||
│ ├── README.md # 本文档
|
||||
│ ├── QUICKSTART.md # 快速入门指南
|
||||
│ ├── RELEASE.md # 版本发布说明
|
||||
│ ├── architecture-design.md # 架构设计文档
|
||||
│ └── team.md # 团队成员
|
||||
├── Test/
|
||||
│ ├── fixtures/ # 测试夹具
|
||||
│ │ ├── sample_4x4.xlsx # 标准 4×4 PinMAP
|
||||
│ │ ├── sample_rect.xlsx # 长方形 PinMAP
|
||||
│ │ ├── error_gap.xlsx # 序号不连续测试
|
||||
│ │ ├── error_dup.xlsx # 序号重复测试
|
||||
│ │ ├── error_empty_a1.xlsx # A1 为空测试
|
||||
│ │ └── warning_missing.xlsx # PinName 缺失测试
|
||||
│ └── test_report.md # 测试报告
|
||||
├── README.md # 项目根目录 README
|
||||
├── CHANGELOG.md # 变更日志
|
||||
└── .gitignore
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 测试情况
|
||||
|
||||
### 单元测试
|
||||
|
||||
运行 `python test_pinmap.py`(在 `Code/src/` 目录下):
|
||||
|
||||
| 测试用例 | 说明 | 状态 |
|
||||
|----------|------|------|
|
||||
| `test_4x4_parse` | 4×4 方形 PinMAP 解析 | ✅ 通过 |
|
||||
| `test_4x4_validate` | 4×4 方形验证 | ✅ 通过 |
|
||||
| `test_missing_names_warning` | PinName 缺失警告 | ✅ 通过 |
|
||||
| `test_duplicate_numbers` | 序号重复检测 | ✅ 通过 |
|
||||
| `test_gap_in_numbers` | 序号不连续检测 | ✅ 通过 |
|
||||
| `test_empty_cells` | 空单元格处理 | ✅ 通过 |
|
||||
| `test_no_pins` | 无引脚数据检测 | ✅ 通过 |
|
||||
| `test_12pin_square` | 12 引脚方形解析 | ✅ 通过 |
|
||||
|
||||
### 集成测试
|
||||
|
||||
| 测试用例 | 输入文件 | 说明 | 状态 |
|
||||
|----------|----------|------|------|
|
||||
| TC001 | `sample_4x4.xlsx` | 标准 4×4 转换(8 Pin) | ✅ 通过 |
|
||||
| TC002 | `sample_rect.xlsx` | 长方形转换(13 Pin) | ✅ 通过 |
|
||||
| TC003 | `error_gap.xlsx` | 序号不连续检测 | ✅ 通过 |
|
||||
| TC004 | `error_dup.xlsx` | 序号重复检测 | ✅ 通过 |
|
||||
| TC005 | `warning_missing.xlsx` | PinName 缺失警告 | ✅ 通过 |
|
||||
| TC006 | `error_empty_a1.xlsx` | A1 为空检测 | ✅ 通过 |
|
||||
|
||||
**结论**:所有测试用例通过,无阻塞性问题。详见 `Test/test_report.md`。
|
||||
|
||||
---
|
||||
|
||||
## 解析算法说明
|
||||
|
||||
### PinMAP 结构
|
||||
|
||||
PinMAP 以方形/长方形矩阵展示引脚分布:
|
||||
|
||||
```
|
||||
col A(0) col B(1) col C(2) col D(3)
|
||||
row 0 [A1=封装]
|
||||
row 1 [1] [2] [3] [4] ← 上边 Pin 序号
|
||||
row 2 [PinName] [ ] [PinName] ← PinName 行
|
||||
row 3 [PinName] [ ] [PinName]
|
||||
row 4 [13] [12] [11] [10] ← 下边 Pin 序号
|
||||
```
|
||||
|
||||
### 逆时针提取规则
|
||||
|
||||
引脚沿四条边**逆时针**提取:
|
||||
|
||||
1. **左边**:从上到下
|
||||
2. **下边**:从左到右
|
||||
3. **右边**:从下到上
|
||||
4. **上边**:从右到左
|
||||
|
||||
角点单元格只计数一次(按单元格位置去重)。
|
||||
|
||||
### PinList 输出规则
|
||||
|
||||
- A1 单元格:封装信息(从 PinMAP 的 A1 复制)
|
||||
- A 列:PinName(缺失时自动设为 "NC")
|
||||
- B 列:Pin 序号
|
||||
- 按 Pin 序号递增排序
|
||||
|
||||
---
|
||||
|
||||
## 错误处理
|
||||
|
||||
| 级别 | 类型 | 行为 |
|
||||
|------|------|------|
|
||||
| `[FATAL]` | 文件格式错误 / 结构错误 | 终止处理,显示错误信息 |
|
||||
| `[ERROR]` | 数据验证错误(重复/不连续) | 终止处理,显示详细错误 |
|
||||
| `[WARN]` | PinName 缺失 | 提示警告,自动设为 "NC",继续处理 |
|
||||
| `[INFO]` | 解析进度信息 | 仅显示,不影响流程 |
|
||||
| `[SUCCESS]` | 转换完成 | 显示输出文件路径和统计信息 |
|
||||
|
||||
---
|
||||
|
||||
## 许可证
|
||||
|
||||
内部项目
|
||||
160
Releases/v1.0.1/docs/RELEASE.md
Normal file
160
Releases/v1.0.1/docs/RELEASE.md
Normal file
@@ -0,0 +1,160 @@
|
||||
# 版本发布说明
|
||||
|
||||
---
|
||||
|
||||
## v1.0.0 — 2026-05-25
|
||||
|
||||
### 🎉 首次发布
|
||||
|
||||
这是 PinMAP → PinList 转换器的第一个正式版本,实现了从 Excel PinMAP 到 PinList 的完整转换流程。
|
||||
|
||||
---
|
||||
|
||||
### 新增功能
|
||||
|
||||
#### PinMAP 解析
|
||||
- 自动识别方形和长方形封装结构
|
||||
- 沿四条边(左→下→右→上)逆时针提取引脚
|
||||
- 角点共享处理(按单元格位置去重)
|
||||
- 支持 2×2 及以上任意尺寸
|
||||
|
||||
#### 数据验证
|
||||
- **序号连续性检查**:检测 1~N 序列中的间隔
|
||||
- **序号唯一性检查**:检测重复的引脚序号
|
||||
- **PinName 完整性检查**:检测缺失的引脚名称(警告级别)
|
||||
- **结构完整性检查**:验证方形区域最小尺寸和 A1 封装信息
|
||||
|
||||
#### PinList 生成
|
||||
- A 列 PinName,B 列 Pin 序号
|
||||
- 按 Pin 序号递增排序
|
||||
- 缺失 PinName 自动设为 "NC"
|
||||
|
||||
#### 格式支持
|
||||
- `.xls` 读取:BIFF8 引擎(OLE2 复合文档解析)
|
||||
- `.xlsx` 读取:OOXML 引擎(ZIP + XML 解析)
|
||||
- `.xlsx` 写入:OOXML 引擎(纯手工构建)
|
||||
|
||||
#### 运行模式
|
||||
- **GUI 模式**:tkinter 文件选择对话框(Windows 推荐)
|
||||
- **命令行模式**:`python main.py input.xlsx`(Linux/Mac 推荐)
|
||||
- 自动回退:无 GUI 环境自动切换至命令行模式
|
||||
|
||||
---
|
||||
|
||||
### 技术实现
|
||||
|
||||
| 模块 | 代码量 | 说明 |
|
||||
|------|--------|------|
|
||||
| `xls_reader.py` | ~400 行 | BIFF8 OLE2 解析引擎,支持 SST/LABELSST/NUMBER/FORMULA/RK/MULRK/LABEL |
|
||||
| `xlsx_reader.py` | ~80 行 | ZIP + XML 解析,支持共享字符串表 |
|
||||
| `xlsx_writer.py` | ~120 行 | OOXML 构建,生成标准 .xlsx 文件 |
|
||||
| `pinmap_parser.py` | ~100 行 | 方形边界检测 + 四边引脚提取 |
|
||||
| `validator.py` | ~60 行 | 连续性/唯一性/完整性验证 |
|
||||
| `pinlist_generator.py` | ~40 行 | PinList 生成 + NC 默认值 |
|
||||
| `file_selector.py` | ~35 行 | tkinter 对话框 + 命令行回退 |
|
||||
| `main.py` | ~60 行 | 流程编排 + 异常处理 |
|
||||
| `models.py` | ~40 行 | 数据模型定义 |
|
||||
| `utils.py` | ~35 行 | 坐标转换工具 |
|
||||
|
||||
**总代码量**:约 1000 行(不含注释和空行)
|
||||
**第三方依赖**:0
|
||||
|
||||
---
|
||||
|
||||
### 测试覆盖
|
||||
|
||||
#### 单元测试(8 个用例)
|
||||
|
||||
| 用例 | 测试内容 | 结果 |
|
||||
|------|----------|------|
|
||||
| `test_4x4_parse` | 4×4 方形 PinMAP 解析 | ✅ |
|
||||
| `test_4x4_validate` | 4×4 方形验证 | ✅ |
|
||||
| `test_missing_names_warning` | PinName 缺失警告 | ✅ |
|
||||
| `test_duplicate_numbers` | 序号重复检测 | ✅ |
|
||||
| `test_gap_in_numbers` | 序号不连续检测 | ✅ |
|
||||
| `test_empty_cells` | 空单元格处理 | ✅ |
|
||||
| `test_no_pins` | 无引脚数据检测 | ✅ |
|
||||
| `test_12pin_square` | 12 引脚方形解析 | ✅ |
|
||||
|
||||
#### 集成测试(6 个用例)
|
||||
|
||||
| 用例 | 输入文件 | 测试内容 | 结果 |
|
||||
|------|----------|----------|------|
|
||||
| TC001 | `sample_4x4.xlsx` | 标准 4×4 转换(8 Pin) | ✅ |
|
||||
| TC002 | `sample_rect.xlsx` | 长方形转换(13 Pin) | ✅ |
|
||||
| TC003 | `error_gap.xlsx` | 序号不连续检测 | ✅ |
|
||||
| TC004 | `error_dup.xlsx` | 序号重复检测 | ✅ |
|
||||
| TC005 | `warning_missing.xlsx` | PinName 缺失警告 | ✅ |
|
||||
| TC006 | `error_empty_a1.xlsx` | A1 为空检测 | ✅ |
|
||||
|
||||
**测试通过率**:100%(14/14)
|
||||
|
||||
---
|
||||
|
||||
### 已知问题
|
||||
|
||||
| # | 问题 | 严重性 | 说明 |
|
||||
|---|------|--------|------|
|
||||
| K1 | XLS 读取缺乏真实样本验证 | 中 | 当前测试环境无 `.xls` 格式测试文件,BIFF8 引擎尚未在真实 `.xls` 文件上验证 |
|
||||
| K2 | 无字体/格式保留 | 低 | 输出文件不保留原始 Excel 的字体、颜色、边框等格式信息 |
|
||||
| K3 | 仅支持 sheet1 | 低 | 仅读取 Excel 文件的第一个工作表 |
|
||||
| K4 | Linux 无头环境无 GUI | 低 | 无显示器环境下 tkinter 不可用,需使用命令行模式 |
|
||||
|
||||
---
|
||||
|
||||
### 限制
|
||||
|
||||
| 限制项 | 说明 |
|
||||
|--------|------|
|
||||
| 引脚数量 | 建议 < 1000 引脚(典型封装 < 200 引脚,无压力) |
|
||||
| 输入格式 | 仅支持 `.xls` 和 `.xlsx`,不支持 CSV/其他格式 |
|
||||
| 输出格式 | 仅输出 `.xlsx`,不支持 `.xls` |
|
||||
| 工作表 | 仅处理第一个工作表 |
|
||||
| 公式单元格 | 仅读取公式的计算结果,不保留公式本身 |
|
||||
|
||||
---
|
||||
|
||||
### 未来计划
|
||||
|
||||
#### v1.1.0 — 格式增强(规划中)
|
||||
|
||||
- [ ] 支持 `.xls` 格式输出
|
||||
- [ ] 保留原始 Excel 的字体和格式
|
||||
- [ ] 支持多工作表选择
|
||||
|
||||
#### v1.2.0 — 功能扩展(规划中)
|
||||
|
||||
- [ ] 批量转换(拖拽多个文件)
|
||||
- [ ] CSV 格式输出
|
||||
- [ ] PinMAP 结构可视化预览
|
||||
|
||||
#### v2.0.0 — 架构升级(远期规划)
|
||||
|
||||
- [ ] 支持更多封装类型(BGA、QFN 等)
|
||||
- [ ] 插件式解析器架构
|
||||
- [ ] Web 界面
|
||||
|
||||
---
|
||||
|
||||
### 升级指南
|
||||
|
||||
**首次使用**:直接运行即可,无需升级。
|
||||
|
||||
**从测试版升级**:替换 `Code/src/` 目录下所有文件。
|
||||
|
||||
---
|
||||
|
||||
### 贡献者
|
||||
|
||||
- 架构设计:Script Architect
|
||||
- 编码实现:Coding Agent × 3
|
||||
- 测试验证:QA Agent
|
||||
- 文档编写:Doc Gen Agent
|
||||
|
||||
---
|
||||
|
||||
### 获取帮助
|
||||
|
||||
- 查看 `QUICKSTART.md` 了解使用方法
|
||||
- 查看 `architecture-design.md` 了解技术细节
|
||||
- 查看 `Test/test_report.md` 了解测试详情
|
||||
860
Releases/v1.0.1/docs/architecture-design.md
Normal file
860
Releases/v1.0.1/docs/architecture-design.md
Normal file
@@ -0,0 +1,860 @@
|
||||
# PinMAP → PinList 转换器 — 全局架构设计
|
||||
|
||||
> **版本**: v1.0
|
||||
> **日期**: 2026-05-25
|
||||
> **架构师**: 脚本架构师 (Script Architect)
|
||||
> **状态**: 待审批
|
||||
|
||||
---
|
||||
|
||||
## 1. 项目概述
|
||||
|
||||
### 1.1 背景
|
||||
|
||||
将 Excel 格式的 **PinMAP** 文件(方形封装引脚布局图)自动转换为 **PinList** 格式(引脚序号列表),消除手动抄录的低效与错误风险。
|
||||
|
||||
### 1.2 核心规则
|
||||
|
||||
- PinMAP 为方形/长方形结构,引脚沿四条边分布,左上角为 1 脚,**逆时针**排序
|
||||
- 左上角 = 1 脚,右上角 = 上边最后一个脚,右下角 = 下边最后一个脚,左下角 = 左边最后一个脚
|
||||
- 四个角点被相邻两边共享(不重复计数)
|
||||
|
||||
### 1.3 约束
|
||||
|
||||
| 约束项 | 说明 |
|
||||
|--------|------|
|
||||
| 运行平台 | Windows |
|
||||
| 技术栈 | Python 标准库,**零第三方依赖** |
|
||||
| 输入格式 | `.xls`(必须支持)、`.xlsx`(优先支持) |
|
||||
| 输出格式 | `.xlsx` 仅 |
|
||||
| 交互方式 | 命令行 + 文件选择对话框 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 技术选型
|
||||
|
||||
### 2.1 为什么不用 openpyxl / xlrd?
|
||||
|
||||
项目明确要求 **无第三方依赖**,因此必须使用 Python 标准库自行实现 Excel 读写。
|
||||
|
||||
### 2.2 XLS 读取 — BIFF8 二进制解析
|
||||
|
||||
`.xls` 是 Microsoft **BIFF8** 二进制格式(复合文档 OLE2 容器)。
|
||||
|
||||
**实现策略**:
|
||||
|
||||
```
|
||||
1. 使用 struct 模块解析 OLE2 复合文档头
|
||||
2. 解析 FAT(文件分配表)定位 MiniFAT 和目录流
|
||||
3. 定位 Workbook 流,读取 BIFF8 记录序列
|
||||
4. 关键记录类型:
|
||||
- 0x0009 (BOF) → 块起始标记
|
||||
- 0x00FD (LABELSST) → 共享字符串表中的文本单元格
|
||||
- 0x0006 (FORMULA) → 公式/数值单元格
|
||||
- 0x0203 (NUMBER) → 数值单元格
|
||||
- 0x000C (RK) → RK 数值(压缩整数/浮点)
|
||||
- 0x000D (RString) → 内联字符串
|
||||
- 0x00FC (STRING) → 字符串结果
|
||||
- 0x0034 (SST) → 全局共享字符串表
|
||||
- 0x0042 (BOUNDSHEET) → 工作表信息
|
||||
5. 提取每个单元格的 (行, 列, 值) 三元组
|
||||
```
|
||||
|
||||
**复杂度评估**:中等。BIFF8 是固定长度记录流,struct 解析直接。需处理 Unicode 编码(BIFF8 默认 UTF-16LE,部分兼容 ASCII)。
|
||||
|
||||
### 2.3 XLSX 读取 — ZIP + XML
|
||||
|
||||
`.xlsx` 本质是 ZIP 压缩包,内部为 Office Open XML (OOXML)。
|
||||
|
||||
**实现策略**:
|
||||
|
||||
```python
|
||||
import zipfile
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
1. zipfile.ZipFile 打开 .xlsx
|
||||
2. 读取 [Content_Types].xml 确认结构
|
||||
3. 读取 xl/workbook.xml 获取工作表关系
|
||||
4. 读取 xl/worksheets/sheet1.xml 获取单元格数据
|
||||
5. 读取 xl/sharedStrings.xml 获取共享字符串表
|
||||
6. 解析单元格坐标(如 "A2" → 列A行2)和值类型
|
||||
```
|
||||
|
||||
**复杂度评估**:低。zipfile 和 xml.etree 均为标准库,XML 结构规范清晰。
|
||||
|
||||
### 2.4 XLSX 写入 — ZIP + XML 生成
|
||||
|
||||
**实现策略**:
|
||||
|
||||
```python
|
||||
import zipfile
|
||||
import xml.etree.ElementTree as ET
|
||||
from io import BytesIO
|
||||
|
||||
1. 构建 OOXML 目录结构:
|
||||
[Content_Types].xml
|
||||
_rels/.rels
|
||||
xl/workbook.xml
|
||||
xl/worksheets/sheet1.xml
|
||||
xl/sharedStrings.xml
|
||||
xl/_rels/workbook.xml.rels
|
||||
|
||||
2. 使用 zipfile.ZipFile 写入(ZIP_DEFLATED)
|
||||
|
||||
3. 关键 XML 构建:
|
||||
- sharedStrings.xml: 所有唯一字符串的 SST
|
||||
- sheet1.xml: 单元格坐标 + si (SST index) 引用
|
||||
- workbook.xml: 工作表引用
|
||||
- [Content_Types].xml: MIME 类型声明
|
||||
```
|
||||
|
||||
**复杂度评估**:低。XML 结构固定,模板化生成即可。
|
||||
|
||||
### 2.5 技术选型总结
|
||||
|
||||
| 操作 | 格式 | 标准库模块 | 难度 |
|
||||
|------|------|-----------|------|
|
||||
| 读取 | xls | `struct` + 手动 OLE2/BIFF8 解析 | 中 |
|
||||
| 读取 | xlsx | `zipfile` + `xml.etree.ElementTree` | 低 |
|
||||
| 写入 | xlsx | `zipfile` + `xml.etree.ElementTree` | 低 |
|
||||
| 文件选择 | — | `tkinter.filedialog` | 低 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 模块划分
|
||||
|
||||
```
|
||||
pinmap-to-pinlist/
|
||||
├── Code/
|
||||
│ ├── src/
|
||||
│ │ ├── main.py # 入口:流程编排
|
||||
│ │ ├── file_selector.py # 模块1:文件选择
|
||||
│ │ ├── xls_reader.py # 模块2a:XLS 解析引擎
|
||||
│ │ ├── xlsx_reader.py # 模块2b:XLSX 解析引擎
|
||||
│ │ ├── pinmap_parser.py # 模块3:PinMAP 结构解析
|
||||
│ │ ├── validator.py # 模块4:数据验证
|
||||
│ │ ├── pinlist_generator.py # 模块5:PinList 生成
|
||||
│ │ └── xlsx_writer.py # 模块6:XLSX 输出引擎
|
||||
│ └── docs/
|
||||
│ └── architecture-design.md
|
||||
├── Test/
|
||||
└── Releases/
|
||||
```
|
||||
|
||||
### 3.1 模块职责
|
||||
|
||||
#### 模块1:`file_selector` — 文件选择
|
||||
|
||||
```python
|
||||
def select_file() -> str | None:
|
||||
"""弹出文件选择对话框,返回选中文件路径或 None(取消)"""
|
||||
```
|
||||
|
||||
- 使用 `tkinter.filedialog.askopenfilename`
|
||||
- 文件类型过滤:`*.xls;*.xlsx`
|
||||
- 无 GUI 环境时回退到命令行参数
|
||||
|
||||
#### 模块2a:`xls_reader` — XLS 解析引擎
|
||||
|
||||
```python
|
||||
class XLSReader:
|
||||
def __init__(self, filepath: str)
|
||||
def read_all_cells(self) -> dict[tuple[int, int], str]:
|
||||
"""返回 {(row, col): value} 字典,行列从 0 开始"""
|
||||
def close(self)
|
||||
```
|
||||
|
||||
**内部结构**:
|
||||
|
||||
```
|
||||
XLSReader
|
||||
├── OLE2Parser → 解析复合文档,定位 Workbook 流
|
||||
├── BIFF8Parser → 解析 BIFF8 记录流
|
||||
│ ├── SSTParser → 共享字符串表
|
||||
│ └── CellParser → 单元格记录
|
||||
└── CellMap → 组装为 (row, col) → value 映射
|
||||
```
|
||||
|
||||
#### 模块2b:`xlsx_reader` — XLSX 解析引擎
|
||||
|
||||
```python
|
||||
class XLSXReader:
|
||||
def __init__(self, filepath: str)
|
||||
def read_all_cells(self) -> dict[tuple[int, int], str]:
|
||||
"""返回 {(row, col): value} 字典,行列从 0 开始"""
|
||||
def close(self)
|
||||
```
|
||||
|
||||
**内部结构**:
|
||||
|
||||
```
|
||||
XLSXReader
|
||||
├── ZipExtractor → 解压 .xlsx 到内存
|
||||
├── SharedStrings → 解析 sharedStrings.xml
|
||||
├── SheetParser → 解析 sheet1.xml
|
||||
│ ├── CoordParser → 列字母转索引 (A→0, B→1, ...)
|
||||
│ └── CellParser → 提取单元格值
|
||||
└── CellMap → 组装为 (row, col) → value 映射
|
||||
```
|
||||
|
||||
#### 模块3:`pinmap_parser` — PinMAP 结构解析
|
||||
|
||||
```python
|
||||
def parse_pinmap(cells: dict[tuple[int, int], str]) -> PinMAP:
|
||||
"""
|
||||
解析步骤:
|
||||
1. 排除 (0,0) 后扫描非空单元格,确定方形边界
|
||||
2. 提取 A1 封装信息
|
||||
3. 沿四条边提取引脚序号(边界单元格)和 PinName(相邻内侧单元格)
|
||||
4. 逆时针遍历(左→下→右→上),按单元格位置去重(角点共享)
|
||||
5. 返回 PinMAP 对象
|
||||
"""
|
||||
```
|
||||
|
||||
**解析算法**:
|
||||
|
||||
```
|
||||
Step 1: 确定方形边界
|
||||
- 排除 (0,0)(封装信息单元格)
|
||||
- 扫描所有非空单元格,找到最小/最大行号和列号
|
||||
- width = max_col - min_col + 1
|
||||
- height = max_row - min_row + 1
|
||||
- 验证:width >= 2 且 height >= 2
|
||||
|
||||
Step 2: 提取 A1 封装信息
|
||||
- cells[(0, 0)] → package_info
|
||||
|
||||
Step 3: 构建 PinName 查找表
|
||||
每条边的 PinName 位于序号单元格的"内侧相邻"位置:
|
||||
左边:序号在 (r, min_col), Name 在 (r, min_col+1)
|
||||
下边:序号在 (max_row, c), Name 在 (max_row-1, c)
|
||||
右边:序号在 (r, max_col), Name 在 (r, max_col-1)
|
||||
上边:序号在 (min_row, c), Name 在 (min_row+1, c)
|
||||
|
||||
Step 4: 逆时针遍历四条边(按单元格位置去重)
|
||||
4a. 左边:从上到下 (row: min_row → max_row, col: min_col)
|
||||
4b. 下边:从左到右 (row: max_row, col: min_col+1 → max_col)
|
||||
4c. 右边:从下到上 (row: max_row-1 → min_row, col: max_col)
|
||||
4d. 上边:从右到左 (row: min_row, col: max_col-1 → min_col)
|
||||
|
||||
角点去重:按 (row, col) 单元格位置去重,而非按 Pin 序号。
|
||||
这样如果两个不同单元格恰好有相同序号,validator 能检测到。
|
||||
|
||||
Step 5: 组装 Pin 列表
|
||||
按逆时针顺序:Pin1(左上角) → Pin2 → ... → PinN
|
||||
```
|
||||
|
||||
#### 模块4:`validator` — 数据验证
|
||||
|
||||
```python
|
||||
def validate_pinmap(pinmap: PinMAP) -> ValidationResult:
|
||||
"""
|
||||
验证项:
|
||||
1. Pin序号唯一性(无重复)
|
||||
2. Pin序号连续性(1..N 无间隔)
|
||||
3. PinName 缺失检测(warning,默认 NC)
|
||||
4. 方形结构完整性(width/height >= 2)
|
||||
"""
|
||||
```
|
||||
|
||||
#### 模块5:`pinlist_generator` — PinList 生成
|
||||
|
||||
```python
|
||||
class PinListGenerator:
|
||||
def __init__(self, pinmap: PinMAP, validation: ValidationResult)
|
||||
def generate(self) -> PinList:
|
||||
"""
|
||||
生成规则:
|
||||
- A1 = 封装信息
|
||||
- A列 = PinName
|
||||
- B列 = Pin序号
|
||||
- 按 Pin序号 递增排序
|
||||
"""
|
||||
```
|
||||
|
||||
#### 模块6:`xlsx_writer` — XLSX 输出引擎
|
||||
|
||||
```python
|
||||
class XLSXWriter:
|
||||
def __init__(self)
|
||||
def write_pinlist(self, pinlist: PinList, output_path: str)
|
||||
```
|
||||
|
||||
### 3.2 模块依赖关系
|
||||
|
||||
```
|
||||
main.py
|
||||
├── file_selector.py
|
||||
├── xls_reader.py ──┐
|
||||
├── xlsx_reader.py ─┤
|
||||
│ ▼
|
||||
│ pinmap_parser.py
|
||||
│ ▼
|
||||
│ validator.py
|
||||
│ ▼
|
||||
│ pinlist_generator.py
|
||||
│ ▼
|
||||
└─────────── xlsx_writer.py
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 数据结构设计
|
||||
|
||||
### 4.1 Pin(引脚)
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class Pin:
|
||||
number: int # 引脚序号(1-based)
|
||||
name: str # 引脚名称(缺失时默认为 "NC")
|
||||
edge: str # 所在边: "top" | "right" | "bottom" | "left"
|
||||
position_on_edge: int # 在该边上的位置(0-based)
|
||||
```
|
||||
|
||||
### 4.2 PinMAP(引脚映射图)
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class PinMAP:
|
||||
package_info: str # A1 单元格封装信息
|
||||
pins: list[Pin] # 所有引脚(按序号排序)
|
||||
width: int # 方形宽度(列数)
|
||||
height: int # 方形高度(行数)
|
||||
grid_origin: tuple[int, int] # (row, col) 方形左上角
|
||||
raw_cells: dict[tuple[int, int], str] # 原始单元格数据(调试用)
|
||||
```
|
||||
|
||||
### 4.3 PinList(引脚列表)
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class PinList:
|
||||
package_info: str # 输出 A1 单元格
|
||||
rows: list[tuple[str, int]] # [(PinName, Pin序号), ...] 按序号排序
|
||||
```
|
||||
|
||||
### 4.4 ValidationResult(验证结果)
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class ValidationError:
|
||||
level: str # "error" | "warning"
|
||||
message: str # 错误描述
|
||||
details: str # 详细信息(如重复的序号、缺失的Pin等)
|
||||
|
||||
@dataclass
|
||||
class ValidationResult:
|
||||
is_valid: bool
|
||||
errors: list[ValidationError]
|
||||
warnings: list[ValidationError]
|
||||
```
|
||||
|
||||
### 4.5 内部:单元格坐标体系
|
||||
|
||||
```
|
||||
统一使用 (row, col) 元组,0-based:
|
||||
- row 0 = Excel 第1行
|
||||
- col 0 = Excel A列
|
||||
- A1 = (0, 0)
|
||||
- A2 = (1, 0)
|
||||
- C2 = (1, 2)
|
||||
- B4 = (3, 1)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 异常处理策略
|
||||
|
||||
### 5.1 异常分类
|
||||
|
||||
| 级别 | 类型 | 处理方式 | 示例 |
|
||||
|------|------|---------|------|
|
||||
| FATAL | 文件格式错误 | 终止 + 错误信息 | 非Excel文件、BIFF损坏 |
|
||||
| FATAL | 结构错误 | 终止 + 错误信息 | 非方形、缺少A1、无边数据 |
|
||||
| ERROR | 数据错误 | 终止 + 详细错误 | 序号不连续、序号重复 |
|
||||
| WARN | 数据警告 | 提示 + 继续 | PinName缺失(默认NC) |
|
||||
| INFO | 信息提示 | 仅显示 | 转换完成、统计信息 |
|
||||
|
||||
### 5.2 自定义异常层次
|
||||
|
||||
```python
|
||||
class PinMapError(Exception):
|
||||
"""基类异常"""
|
||||
|
||||
class FileFormatError(PinMapError):
|
||||
"""文件格式错误(非xls/xlsx、文件损坏)"""
|
||||
|
||||
class StructureError(PinMapError):
|
||||
"""PinMAP结构错误(非方形、缺少必要数据)"""
|
||||
|
||||
class ValidationError(PinMapError):
|
||||
"""数据验证错误(序号不连续、重复)"""
|
||||
|
||||
class WarningLevel(PinMapError):
|
||||
"""警告级别(PinName缺失等,可继续处理)"""
|
||||
```
|
||||
|
||||
### 5.3 错误信息规范
|
||||
|
||||
```
|
||||
[级别] 错误类别: 具体描述
|
||||
详细信息: ...
|
||||
建议操作: ...
|
||||
```
|
||||
|
||||
示例:
|
||||
```
|
||||
[ERROR] 序号不连续: 检测到序号间断
|
||||
预期: 1,2,3,4,5,6 实际: 1,2,3,5,6
|
||||
缺失序号: 4
|
||||
建议: 检查PinMAP文件中是否有遗漏的引脚
|
||||
|
||||
[WARN] PinName缺失: 检测到 3 个引脚缺少PinName
|
||||
缺失引脚: Pin 7, Pin 12, Pin 18
|
||||
处理: 已自动设为 "NC"
|
||||
```
|
||||
|
||||
### 5.4 主流程异常处理
|
||||
|
||||
```python
|
||||
def main():
|
||||
try:
|
||||
filepath = select_file()
|
||||
if not filepath:
|
||||
return # 用户取消
|
||||
|
||||
cells = read_excel(filepath)
|
||||
pinmap = parse_pinmap(cells)
|
||||
result = validate(pinmap)
|
||||
|
||||
if result.has_errors():
|
||||
print_errors(result.errors)
|
||||
return
|
||||
|
||||
if result.has_warnings():
|
||||
print_warnings(result.warnings)
|
||||
if not confirm_continue():
|
||||
return
|
||||
|
||||
pinlist = generate(pinmap, result)
|
||||
output_path = build_output_path(filepath)
|
||||
write_xlsx(pinlist, output_path)
|
||||
print_success(output_path)
|
||||
|
||||
except FileFormatError as e:
|
||||
print_fatal(f"文件格式错误: {e}")
|
||||
except StructureError as e:
|
||||
print_fatal(f"结构错误: {e}")
|
||||
except ValidationError as e:
|
||||
print_fatal(f"数据验证失败: {e}")
|
||||
except Exception as e:
|
||||
print_fatal(f"未知错误: {e}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 文件处理流程图
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 主流程 (main.py) │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌───────────────────────────┐
|
||||
│ 1. 文件选择 (file_selector) │
|
||||
│ - tkinter 文件对话框 │
|
||||
│ - 过滤 *.xls, *.xlsx │
|
||||
└───────────┬───────────────┘
|
||||
│
|
||||
┌───────────▼───────────────┐
|
||||
│ 2. 读取 Excel 文件 │
|
||||
│ ┌─────────────────────┐ │
|
||||
│ │ 判断文件格式 │ │
|
||||
│ │ .xls → xls_reader │ │
|
||||
│ │ .xlsx → xlsx_reader│ │
|
||||
│ └─────────┬───────────┘ │
|
||||
│ ┌─────────▼───────────┐ │
|
||||
│ │ 解析为单元格字典 │ │
|
||||
│ │ {(row,col): value} │ │
|
||||
│ └─────────┬───────────┘ │
|
||||
└────────────┬──────────────┘
|
||||
│
|
||||
┌────────────▼──────────────┐
|
||||
│ 3. PinMAP 解析 (pinmap_parser) │
|
||||
│ ┌─────────────────────┐ │
|
||||
│ │ ① 定位方形边界 │ │
|
||||
│ │ 扫描非空单元格 │ │
|
||||
│ │ 确定 width/height│ │
|
||||
│ └─────────┬───────────┘ │
|
||||
│ ┌─────────▼───────────┐ │
|
||||
│ │ ② 提取 A1 封装信息 │ │
|
||||
│ └─────────┬───────────┘ │
|
||||
│ ┌─────────▼───────────┐ │
|
||||
│ │ ③ 沿四边提取引脚 │ │
|
||||
│ │ 上边 → 右边 │ │
|
||||
│ │ 下边 → 左边 │ │
|
||||
│ │ 逆时针排序 │ │
|
||||
│ └─────────┬───────────┘ │
|
||||
│ ┌─────────▼───────────┐ │
|
||||
│ │ ④ 组装 PinMAP 对象 │ │
|
||||
│ └─────────┬───────────┘ │
|
||||
└────────────┬──────────────┘
|
||||
│
|
||||
┌────────────▼──────────────┐
|
||||
│ 4. 数据验证 (validator) │
|
||||
│ ┌─────────────────────┐ │
|
||||
│ │ ✓ 序号连续性检查 │ │
|
||||
│ │ ✓ 序号唯一性检查 │ │
|
||||
│ │ ✓ PinName 缺失检查 │ │
|
||||
│ │ ✓ 方形结构完整性 │ │
|
||||
│ └─────────┬───────────┘ │
|
||||
│ ┌─────────▼───────────┐ │
|
||||
│ │ ERROR → 终止流程 │ │
|
||||
│ │ WARN → 提示确认 │ │
|
||||
│ └─────────┬───────────┘ │
|
||||
└────────────┬──────────────┘
|
||||
│
|
||||
┌────────────▼──────────────┐
|
||||
│ 5. PinList 生成 (generator) │
|
||||
│ ┌─────────────────────┐ │
|
||||
│ │ A1 = 封装信息 │ │
|
||||
│ │ A列 = PinName │ │
|
||||
│ │ B列 = Pin序号 │ │
|
||||
│ │ 按序号递增排序 │ │
|
||||
│ └─────────┬───────────┘ │
|
||||
└────────────┬──────────────┘
|
||||
│
|
||||
┌────────────▼──────────────┐
|
||||
│ 6. XLSX 输出 (xlsx_writer) │
|
||||
│ ┌─────────────────────┐ │
|
||||
│ │ 构建 OOXML 结构 │ │
|
||||
│ │ [Content_Types].xml │ │
|
||||
│ │ xl/workbook.xml │ │
|
||||
│ │ xl/sharedStrings.xml│ │
|
||||
│ │ xl/worksheets/ │ │
|
||||
│ │ sheet1.xml │ │
|
||||
│ └─────────┬───────────┘ │
|
||||
│ ┌─────────▼───────────┐ │
|
||||
│ │ ZIP 打包输出 │ │
|
||||
│ └─────────┬───────────┘ │
|
||||
└────────────┬──────────────┘
|
||||
│
|
||||
▼
|
||||
┌───────────────────────────┐
|
||||
│ 完成!输出 .xlsx 文件 │
|
||||
│ 默认命名: {原文件名}_PinList.xlsx │
|
||||
└───────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. PinMAP 结构详解
|
||||
|
||||
### 7.1 坐标映射
|
||||
|
||||
以 4×4 方形为例(width=4, height=4):
|
||||
|
||||
```
|
||||
col A(0) col B(1) col C(2) col D(3)
|
||||
row 0 [A1=封装] [PinName] [PinName] [PinName] ← 上边PinName行
|
||||
row 1 [1] [2] [3] [4] ← 上边Pin序号行
|
||||
row 2 [PinName] [ ] [PinName] ← 中间区域(留空)
|
||||
row 3 [PinName] [ ] [PinName] ← 中间区域(留空)
|
||||
row 4 [13] [12] [11] [10] ← 下边Pin序号行
|
||||
[PinName] [PinName] [PinName] [PinName] ← 下边PinName行(行5)
|
||||
↑ ↑ ↑ ↑
|
||||
左边 左边 右边 右边
|
||||
PinName PinName PinName PinName
|
||||
(列前) (列前) (列后) (列后)
|
||||
```
|
||||
|
||||
**实际引脚分布**:
|
||||
- 上边:Pin 1(A,row1) → Pin 2(B,row1) → Pin 3(C,row1) → Pin 4(D,row1)
|
||||
- 右边:Pin 5(D,row2) → Pin 6(D,row3) → Pin 7(D,row4)
|
||||
- 下边:Pin 8(D,row4) ... 等等
|
||||
|
||||
等等,让我重新理清。根据需求描述:
|
||||
|
||||
```
|
||||
C2 是上边最后一个Pin序号,C3是对应PinName
|
||||
A4 是左边第一个Pin序号,B4是对应PinName
|
||||
```
|
||||
|
||||
这说明:
|
||||
- 行1(Excel第2行)= 上边Pin序号行
|
||||
- 行2(Excel第3行)= 上边PinName行
|
||||
- 行3(Excel第4行)= 左边第一个Pin序号行
|
||||
|
||||
所以方形区域从 row=1 开始(Excel第2行),row=0 是PinName行。
|
||||
|
||||
### 7.2 四边提取规则(修正版)
|
||||
|
||||
设方形区域:行范围 [r_top, r_bottom],列范围 [c_left, c_right]
|
||||
|
||||
```
|
||||
上边 (Top Edge):
|
||||
Pin序号位置:row=r_top, col=c_left → c_right(从左到右)
|
||||
PinName位置:row=r_top-1, col=c_left → c_right
|
||||
|
||||
右边 (Right Edge):
|
||||
Pin序号位置:col=c_right, row=r_top → r_bottom(从上到下)
|
||||
PinName位置:col=c_right+1, row=r_top → r_bottom
|
||||
|
||||
下边 (Bottom Edge):
|
||||
Pin序号位置:row=r_bottom, col=c_right → c_left(从右到左)
|
||||
PinName位置:row=r_bottom+1, col=c_right → c_left
|
||||
|
||||
左边 (Left Edge):
|
||||
Pin序号位置:col=c_left, row=r_bottom → r_top(从下到上)
|
||||
PinName位置:col=c_left-1, row=r_bottom → r_top(即B列,当c_left=0时)
|
||||
```
|
||||
|
||||
### 7.3 角点共享规则
|
||||
|
||||
```
|
||||
左上角 (c_left, r_top) = 上边起点 = 左边终点 → Pin 1
|
||||
右上角 (c_right, r_top) = 上边终点 = 右边起点
|
||||
右下角 (c_right, r_bottom) = 右边终点 = 下边起点
|
||||
左下角 (c_left, r_bottom) = 下边终点 = 左边终点
|
||||
|
||||
总Pin数 = 2 × width + 2 × height - 4
|
||||
```
|
||||
|
||||
### 7.4 长方形支持
|
||||
|
||||
```
|
||||
非正方形示例:width=6, height=4
|
||||
|
||||
总Pin数 = 2×6 + 2×4 - 4 = 16
|
||||
|
||||
上边:6个引脚(1-6)
|
||||
右边:3个引脚(7-9)
|
||||
下边:5个引脚(10-14)
|
||||
左边:3个引脚(15-16,回到Pin 1)
|
||||
|
||||
验证:6 + 3 + 5 + 2 = 16 ✓(左边排除两个角点)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 任务拆分建议
|
||||
|
||||
### 8.1 推荐拆分方案
|
||||
|
||||
建议拆分为 **3 个子任务**,由 2-3 个编码 Agent 并行开发:
|
||||
|
||||
#### 任务 A:Excel 读写引擎(最复杂,优先开发)
|
||||
|
||||
**负责模块**:`xls_reader.py`, `xlsx_reader.py`, `xlsx_writer.py`
|
||||
|
||||
**工作内容**:
|
||||
1. 实现 BIFF8 OLE2 解析器(xls 读取)
|
||||
2. 实现 ZIP+XML 解析器(xlsx 读取)
|
||||
3. 实现 OOXML 生成器(xlsx 写入)
|
||||
4. 统一接口:`read_excel(filepath) → dict[(row,col), str]`
|
||||
5. 编写单元测试(用已知 xls/xlsx 文件验证)
|
||||
|
||||
**预估工作量**:高(BIFF8 解析是最大难点)
|
||||
|
||||
**关键风险**:
|
||||
- BIFF8 变体多(BIFF5/BIFF8 混用、不同 Unicode 编码)
|
||||
- 需要大量测试文件验证
|
||||
|
||||
#### 任务 B:PinMAP 解析与验证(核心业务逻辑)
|
||||
|
||||
**负责模块**:`pinmap_parser.py`, `validator.py`
|
||||
|
||||
**工作内容**:
|
||||
1. 实现方形边界检测算法
|
||||
2. 实现四边引脚提取逻辑
|
||||
3. 实现角点共享处理
|
||||
4. 实现验证规则(连续性、唯一性、完整性)
|
||||
5. 编写单元测试(模拟各种 PinMAP 布局)
|
||||
|
||||
**预估工作量**:中
|
||||
|
||||
**关键风险**:
|
||||
- 边界条件处理(长方形 vs 正方形、最小尺寸)
|
||||
- 角点共享逻辑的正确性
|
||||
|
||||
#### 任务 C:流程编排与输出(集成层)
|
||||
|
||||
**负责模块**:`main.py`, `file_selector.py`, `pinlist_generator.py`
|
||||
|
||||
**工作内容**:
|
||||
1. 实现文件选择对话框
|
||||
2. 实现 PinList 数据转换
|
||||
3. 实现输出文件命名和保存
|
||||
4. 实现主流程异常处理和用户提示
|
||||
5. 端到端集成测试
|
||||
|
||||
**预估工作量**:低
|
||||
|
||||
**关键风险**:
|
||||
- tkinter 在 Windows 上的兼容性
|
||||
- 用户交互流程的友好性
|
||||
|
||||
### 8.2 开发顺序
|
||||
|
||||
```
|
||||
第1轮:任务 A(Excel 读写引擎)
|
||||
↓ 完成后
|
||||
第2轮:任务 B(PinMAP 解析与验证)
|
||||
↓ 完成后
|
||||
第3轮:任务 C(流程编排与输出)
|
||||
↓ 完成后
|
||||
集成测试 → 发布
|
||||
```
|
||||
|
||||
### 8.3 接口契约(模块间约定)
|
||||
|
||||
```python
|
||||
# xls_reader / xlsx_reader 统一接口
|
||||
def read_excel_cells(filepath: str) -> dict[tuple[int, int], str]:
|
||||
"""
|
||||
输入: Excel 文件路径
|
||||
输出: {(row, col): str} 单元格字典
|
||||
约定: row/col 从 0 开始,所有值转为 str
|
||||
"""
|
||||
|
||||
# pinmap_parser 接口
|
||||
def parse_pinmap(cells: dict[tuple[int, int], str]) -> PinMAP:
|
||||
"""
|
||||
输入: 单元格字典
|
||||
输出: PinMAP 对象
|
||||
约定: 结构错误时抛出 StructureError
|
||||
"""
|
||||
|
||||
# validator 接口
|
||||
def validate_pinmap(pinmap: PinMAP) -> ValidationResult:
|
||||
"""
|
||||
输入: PinMAP 对象
|
||||
输出: ValidationResult
|
||||
约定: 不抛出异常,所有问题记录在 ValidationResult 中
|
||||
"""
|
||||
|
||||
# pinlist_generator 接口
|
||||
def generate_pinlist(pinmap: PinMAP, validation: ValidationResult) -> PinList:
|
||||
"""
|
||||
输入: PinMAP + ValidationResult
|
||||
输出: PinList 对象
|
||||
约定: 自动处理 WARN 级别的缺失 PinName(设为 NC)
|
||||
"""
|
||||
|
||||
# xlsx_writer 接口
|
||||
def write_pinlist_xlsx(pinlist: PinList, output_path: str):
|
||||
"""
|
||||
输入: PinList + 输出路径
|
||||
输出: 无(写入文件)
|
||||
约定: 自动创建父目录
|
||||
"""
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 项目目录结构
|
||||
|
||||
```
|
||||
pinmap-to-pinlist/
|
||||
├── Code/
|
||||
│ ├── src/
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── main.py # 入口点
|
||||
│ │ ├── file_selector.py # 文件选择
|
||||
│ │ ├── xls_reader.py # XLS 读取引擎
|
||||
│ │ ├── xlsx_reader.py # XLSX 读取引擎
|
||||
│ │ ├── pinmap_parser.py # PinMAP 解析
|
||||
│ │ ├── validator.py # 数据验证
|
||||
│ │ ├── pinlist_generator.py # PinList 生成
|
||||
│ │ ├── xlsx_writer.py # XLSX 写入引擎
|
||||
│ │ └── models.py # 数据模型定义
|
||||
│ └── docs/
|
||||
│ └── architecture-design.md # 本文档
|
||||
├── Test/
|
||||
│ ├── fixtures/ # 测试用 Excel 文件
|
||||
│ │ ├── sample_4x4.xls
|
||||
│ │ ├── sample_4x4.xlsx
|
||||
│ │ ├── sample_rect.xls
|
||||
│ │ └── ...
|
||||
│ └── test_*.py # 单元测试
|
||||
└── Releases/
|
||||
└── pinmap2pinlist.exe # 打包后的可执行文件
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 风险与缓解
|
||||
|
||||
| 风险 | 影响 | 概率 | 缓解措施 |
|
||||
|------|------|------|---------|
|
||||
| BIFF8 格式变体导致解析失败 | 高 | 中 | 收集多种 xls 样本测试;优先实现 BIFF8 最常见子集 |
|
||||
| tkinter 在无头环境不可用 | 中 | 低 | 回退到命令行参数模式 |
|
||||
| xlsx 写入的 XML 结构不兼容老版本 Excel | 中 | 低 | 遵循 OOXML 标准,使用最小兼容集 |
|
||||
| 超大文件(>1000引脚)性能问题 | 低 | 低 | 当前场景引脚数通常 <100,无需优化 |
|
||||
|
||||
---
|
||||
|
||||
## 11. 附录
|
||||
|
||||
### A. BIFF8 记录类型速查
|
||||
|
||||
| 记录码 | 名称 | 说明 |
|
||||
|--------|------|------|
|
||||
| 0x0009 | BOF | 块起始 |
|
||||
| 0x000A | EOF | 文件结束 |
|
||||
| 0x00FD | LABELSST | 共享字符串表引用单元格 |
|
||||
| 0x0203 | NUMBER | 浮点数单元格 |
|
||||
| 0x0006 | FORMULA | 公式单元格 |
|
||||
| 0x000C | RK | RK 数值 |
|
||||
| 0x00FC | STRING | 公式字符串结果 |
|
||||
| 0x0034 | SST | 全局共享字符串表 |
|
||||
| 0x0042 | BOUNDSHEET | 工作表信息 |
|
||||
| 0x00E0 | EXTSST | 扩展共享字符串表 |
|
||||
|
||||
### B. OOXML xlsx 目录结构
|
||||
|
||||
```
|
||||
example.xlsx (ZIP)
|
||||
├── [Content_Types].xml
|
||||
├── _rels/
|
||||
│ └── .rels
|
||||
├── xl/
|
||||
│ ├── workbook.xml
|
||||
│ ├── _rels/
|
||||
│ │ └── workbook.xml.rels
|
||||
│ ├── sharedStrings.xml
|
||||
│ ├── styles.xml
|
||||
│ └── worksheets/
|
||||
│ ├── sheet1.xml
|
||||
│ └── sheet2.xml
|
||||
└── docProps/
|
||||
├── core.xml
|
||||
└── app.xml
|
||||
```
|
||||
|
||||
### C. 列字母 ↔ 索引转换
|
||||
|
||||
```python
|
||||
def col_letter_to_index(letter: str) -> int:
|
||||
"""A→0, B→1, ..., Z→25, AA→26, AB→27, ..."""
|
||||
result = 0
|
||||
for ch in letter.upper():
|
||||
result = result * 26 + (ord(ch) - ord('A') + 1)
|
||||
return result - 1
|
||||
|
||||
def col_index_to_letter(index: int) -> str:
|
||||
"""0→A, 1→B, ..., 25→Z, 26→AA, ..."""
|
||||
result = ""
|
||||
index += 1
|
||||
while index > 0:
|
||||
index -= 1
|
||||
result = chr(index % 26 + ord('A')) + result
|
||||
index //= 26
|
||||
return result
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*文档结束 — 请审批后进入编码阶段*
|
||||
46
Releases/v1.0.1/docs/team.md
Normal file
46
Releases/v1.0.1/docs/team.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# 项目团队
|
||||
|
||||
> **项目**: PinMAP → PinList 转换器
|
||||
> **创建日期**: 2026-05-25
|
||||
|
||||
---
|
||||
|
||||
## 参与 Agent
|
||||
|
||||
| Agent | 职责 | 完成时间 |
|
||||
|-------|------|---------|
|
||||
| 项目管理 Agent (router-agent) | 项目协调、任务分发、进度跟踪 | 2026-05-25 |
|
||||
| 脚本架构师 (script-architect) | 全局架构设计、技术选型、任务拆分 | 2026-05-25 |
|
||||
| Python 编码 Agent (python-coding-agent) | 任务A/B/C 编码实现 | 2026-05-25 |
|
||||
| 测试验证 Agent (test-qa-agent) | 集成测试、端到端测试、测试报告 | 2026-05-25 |
|
||||
|
||||
---
|
||||
|
||||
## 模块负责人
|
||||
|
||||
| 模块 | 负责人 | 文件 |
|
||||
|------|--------|------|
|
||||
| Excel 读写引擎 | Python 编码 Agent | xls_reader.py, xlsx_reader.py, xlsx_writer.py |
|
||||
| PinMAP 解析 | Python 编码 Agent | pinmap_parser.py |
|
||||
| 数据验证 | Python 编码 Agent | validator.py |
|
||||
| PinList 生成 | Python 编码 Agent | pinlist_generator.py |
|
||||
| 流程编排 | Python 编码 Agent | main.py, file_selector.py |
|
||||
| 数据模型 | Python 编码 Agent | models.py |
|
||||
| 工具函数 | Python 编码 Agent | utils.py |
|
||||
|
||||
---
|
||||
|
||||
## 修改流程
|
||||
|
||||
当用户提出修改意见时:
|
||||
1. 通知需求分析 Agent 拆解修改需求
|
||||
2. 通知脚本架构师评估修改需求
|
||||
3. 按架构师评估文档分发任务
|
||||
4. 跟踪修改执行进度
|
||||
5. 通知测试 Agent 验证修改
|
||||
6. 通知文档生成 Agent 更新文档
|
||||
7. 通知打包发布 Agent 发布新版本
|
||||
|
||||
---
|
||||
|
||||
*团队信息 — 2026-05-25*
|
||||
Reference in New Issue
Block a user