diff --git a/plan.md b/plan.md index 0112369..93418b3 100644 --- a/plan.md +++ b/plan.md @@ -1,228 +1,54 @@ -# vr-shopxo-plugin Phase 2 Bugfix — plan.md +# Plan — 文档评估 (Architect) -> 版本:v1.0 | 日期:2026-04-16 | Agent:council/FrontendDev -> 背景:Phase 2 后台管理两个致命问题 — 侧栏乱码 + 路由无法渲染 +> 版本:v1.0 | 日期:2026-04-20 | Agent:council/Architect --- -## 问题总览 +## 任务概述 -| # | 问题 | 症状 | 优先级 | -|---|------|------|--------| -| **P1** | 插件控制器路由无法渲染 | 内容区空白,"template not exists" | 高 | -| **P2** | 侧边栏插件名乱码 | `VR票务`(应为 `VR票务`) | 中 | +对 vr-shopxo-plugin 项目三份文档进行评审: +1. `docs/14_TEMPLATE_RENDER_INVESTIGATION.md` +2. `docs/PHASE2_PLAN.md` +3. `docs/DEVELOPMENT_LOG.md`(第十一、十二章) + +评审维度:准确性、完整性、可操作性、一致性、误导风险。 +**不读代码文件,只读文档。输出到 `reviews/` 目录。** --- -## P1 — 路由无法渲染问题 +## 任务清单 -### 已知现象 -- 访问 `adminwatekc.php?s=VrTicket/SeatTemplateList` → 侧栏正常,主内容区空白 -- ShopXO `Plugins/Index` 控制器调用插件时有 `strtolower+ucfirst` 类名匹配问题 -- 当前 `SeatTemplate.php` 在 `admin/controller/` 子目录 +- [ ] **Task 1**: 评审 `docs/14_TEMPLATE_RENDER_INVESTIGATION.md` → `reviews/Architect-on-doc14.md` + - [Claimed: council/Architect] -### 已知正确模式(freightfee/answers) -``` -app/plugins/{plugin}/ -├── Admin.php ← 直接在插件根目录,继承 think\Controller -├── Hook.php -├── config.json -└── admin/view/... ← 视图在 admin/view/ 子目录 -``` +- [ ] **Task 2**: 评审 `docs/PHASE2_PLAN.md` → `reviews/Architect-on-PHASE2_PLAN.md` + - [Claimed: council/Architect] -### 当前 vr_ticket 结构(有问题) -``` -app/plugins/vr_ticket/ -├── admin/controller/SeatTemplate.php ← ❌ 在子目录 -└── admin/view/seat_template/list.html -``` +- [ ] **Task 3**: 评审 `docs/DEVELOPMENT_LOG.md`(第十一、十二章)→ `reviews/Architect-on-DEV_LOG.md` + - [Claimed: council/Architect] -### 任务清单 - -- [x] **P1-T1**: 验证 `strtolower+ucfirst` 路由匹配机制 - - PluginsService::PluginsControlCall: `class = \app\plugins\{plugin}\{group}\{ucfirst(control)}` - - sidebar URL `/plugins/vr_ticket/admin/seatTemplateList` - - → pluginsname=vr_ticket, pluginscontrol=admin, pluginsaction=seatTemplateList - - → class = \app\plugins\vr_ticket\admin\Admin ✓ - - → method = ucfirst('seatTemplateList') = 'SeatTemplateList' ✓ -- [x] **P1-T2**: 对比 Admin.php 根目录模式 vs 当前 admin/controller/ 子目录模式 - - 根目录 Admin.php (`app/plugins/vr_ticket/admin/Admin.php`) 可以被正确加载 ✓ - - 旧子目录控制器无法被 PluginsService 找到(类路径不匹配)✗ -- [x] **P1-T3**: 实施修复 — 创建 `admin/Admin.php`(注意:不是根目录,是 admin/ 子目录) - - `admin/Admin.php` 路径 → 类名 `\app\plugins\vr_ticket\admin\Admin` ✓ - - 方法使用 camelCase:`SeatTemplateList()`, `TicketList()` 等 - - sidebar URL 必须用 camelCase:`pluginsaction=seatTemplateList` - - 修复 plugin.json sidebar URL:改为 `/plugins/vr_ticket/admin/seatTemplateList` 格式 -- [ ] **P1-T4**: 验证修复后路由能否正常渲染(需实际访问 URL 截图) - ---- - -## P2 — 侧栏插件名乱码问题 - -### 已知现象 -- 侧栏显示:`VR票务`(应为 `VR票务`) -- 这是 UTF-8 字符串被当作 Latin1/ISO-8859-1 解码的结果 -- 乱码规律:`票` (E7 A5 8A) → Latin1 解码为 `票务` - -### 乱码根因假设 -| 假设 | 可能性 | 验证方式 | -|------|--------|----------| -| 数据库 `vrt_power` 表 name 字段 latin1 编码存储 | 高 | 检查 MySQL `SHOW CREATE TABLE vrt_power` | -| 数据库连接 charset 不匹配 | 中 | 检查 ShopXO 数据库配置 charset | -| plugin.json 编码问题 | 低 | plugin.json 已是正确 UTF-8 | - -### 任务清单 - -- [ ] **P2-T1**: 确认乱码根因 — 检查 vrt_power 表结构 - - `SHOW CREATE TABLE vrt_power` - - `SHOW FULL COLUMNS FROM vrt_power` - - 确认 name 字段 charset 和 collate -- [ ] **P2-T2**: 如果是数据库 latin1 问题 — 修复方案 - - 方案A:ALTER TABLE 转换 latin1 → utf8mb4 - - 方案B:MySQL CONVERT/CAST 函数读取时转换 - - 方案C:PHP 层以 latin1 读出再转 utf8 - ---- - -## 视图路径问题(Round 5 根因确认 + 修复) - -### 根因(BackendArchitect 分析) -ThinkPHP 5 视图路径解析规则: -1. 相对路径(如 `'seat_template/list'`):相对于**控制器 namespace 对应的默认视图目录** -2. namespace `app\plugins\vr_ticket\admin` → 默认视图目录 `app/plugins/vr_ticket/admin/view/` -3. 实际文件在 `app/admin/view/default/plugins/view/vr_ticket/admin/view/` ← 路径不匹配! - -### 实际文件位置 -``` -app/admin/view/default/plugins/view/vr_ticket/admin/view/ -├── seat_template/ -│ ├── list.html -│ └── save.html -├── ticket/ -│ ├── list.html -│ └── detail.html -├── venue/ -│ ├── list.html -│ └── save.html -├── verifier/ -│ ├── list.html -│ └── save.html -└── verification/ - └── list.html -``` - -### 修复方案 -ThinkPHP 5 以 `/` 开头的视图路径为**绝对路径**,相对于配置的视图根目录(`app/admin/view/default/`)解析。 - -修复前(错误): -```php -return view('seat_template/list', $data); // 解析到 app/plugins/vr_ticket/admin/view/ ← 不存在 -``` - -修复后(正确): -```php -return view('/plugins/view/vr_ticket/admin/view/seat_template/list', $data); -// → app/admin/view/default/plugins/view/vr_ticket/admin/view/seat_template/list.html ✓ -``` - -**所有 9 个 view() 调用已全部修复为绝对路径格式。** - -### Vrticket.php 的参考价值 -`shopxo/app/admin/controller/Vrticket.php` 使用 `MyView('../../../plugins/vr_ticket/admin/' . $template)` 手动处理路径。 -Admin.php 使用 ThinkPHP `view()` 函数,以 `/` 开头则由 ThinkPHP 自动解析到 `app/admin/view/default/`。 +- [ ] **Task 4**: 综合三份评审,输出 Top 3 修正建议 → `reviews/Architect-DOC-SUMMARY.md` + - [Claimed: council/Architect] --- ## 阶段划分 -| 阶段 | 内容 | 负责 | -|------|------|------| -| **Round 1(规划)** | 分析根因,制定修复方案 | FrontendDev | -| **Round 2(执行)** | 实施 admin/Admin.php + plugin.json 修复 | FrontendDev | -| **Round 3(综合)** | 合并到 main,完整验证 | 所有成员 | +| 阶段 | 内容 | +|------|------| +| **Draft** | Task 1-3:逐份文档输出独立评审报告 | +| **Review** | Task 4:综合汇总,Top 3 修正建议 | +| **Finalize** | 提交到 main,标注完成 | --- -## 依赖关系 +## 依赖 -- P1-T3 和 P1-T4 需要实际访问 URL 验证(无法在 CLI 环境截图) -- P2-T1 需要连接数据库检查编码 +- 三份文档已读取完毕,无需额外探索 +- 不需要 BackendArchitect / SecurityEngineer 配合,可独立完成 --- -## 交付物 +## 执行顺序 -1. 修复后的 `shopxo/app/plugins/vr_ticket/admin/Admin.php`(路由正确) -2. 修复后的 `shopxo/app/plugins/vr_ticket/plugin.json`(sidebar URL 使用 camelCase) -3. 乱码问题修复(需数据库层修复) - -## 状态 - -| 任务 | 状态 | 备注 | -|------|------|------| -| P1-T1 | [Done] | PluginsService 路由机制已分析 | -| P1-T2 | [Done] | admin/Admin.php 模式正确 | -| P1-T3 | [Done] | admin/Admin.php 已创建 + plugin.json 已修复 | -| P1-T4 | [Pending] | 需实际访问 URL 截图验证 | -| P2-T1 | [Done] | 根因:plugins.name 字段 Latin1 存储 | -| P2-T2 | [Done] | SQL 修复脚本见 docs/SQL_FIX_garbled_plugin_name.md | -| P1-视图路径 | [Done] | 所有 9 个 view() 改为绝对路径 `/plugins/view/vr_ticket/admin/view/...` | - ---- - -## BackendArchitect Round 5 实现 - -### 交付物 -1. ✅ `shopxo/app/plugins/vr_ticket/admin/Admin.php` — 9 个 view() 调用全部改为 `/plugins/view/vr_ticket/admin/view/...` 绝对路径 -2. ✅ `docs/SQL_FIX_garbled_plugin_name.md` — 乱码修复 SQL 脚本 -3. ✅ `plan.md` — 更新根因分析 - -### P1 乱码 DB 根因(最终确认) -- `plugins.name` 字段 = `VR票务`(Latin1 解码的 UTF-8 字节) -- 安装时 `plugin.json` 的 `title: "VR票务"` 被以 Latin1 编码存入 MySQL -- 读取时 MySQL 连接 charset 是 utf8mb4,所以 Latin1 字节被错误解码为乱码 -- **修复**:执行 `UPDATE sx_plugins SET name = 'VR票务' WHERE plugins = 'vr_ticket'` - -### 乱码字节分析 -`票` UTF-8: `E7 A5 8A` → Latin1 解读为: `票务` -`务` UTF-8: `E5 8A B1` → (in `VR票务` combined string) - - ---- - -## SecurityEngineer Round 5 补充 - -### 关键发现:VenueList() 方法缺失(Critical Bug) -plugin.json sidebar URL `/plugins/vr_ticket/admin/venueList` 链接到 `VenueList()` 方法,但 admin/Admin.php 中该方法不存在 → 点击"场馆配置"菜单会导致 500 错误。 - -**已修复**:在 admin/Admin.php 中添加: -- `VenueList()` — 场馆列表(含 v3.0 seat_map 解析) -- `VenueSave()` — 场馆创建/编辑(含 v3.0 JSON 构建和验证) -- `VenueDelete()` — 场馆软删除(含审计日志) -- `countSeatsV2()` — v2 格式(数组)座位计数辅助方法 - -### 安全审计结论 - -| 安全项 | 风险等级 | 结论 | -|--------|----------|------| -| SQL 注入 | LOW | 所有查询使用 ThinkPHP query builder + 参数绑定 | -| XSS | LOW | ThinkPHP 模板引擎自动转义,无 `\|raw` 输出 | -| 路径遍历 | LOW | 所有视图路径为硬编码方法名,无用户输入 | -| CSRF | MEDIUM | ShopXO 框架级缺失,插件层面无法单独修复 | -| 数据编码(P1乱码)| LOW | DB latin1 存储导致乱码,非安全漏洞 | - -### P1 乱码 DB 修复 SQL - -```sql --- 1. 诊断 -SELECT id, name, title, LENGTH(name), HEX(name) FROM shx_plugins WHERE name LIKE '%vr%'; - --- 2. 修复 plugins 表 -UPDATE shx_plugins SET name = 'vr_ticket', title = 'VR票务' WHERE name = 'vr_ticket'; - --- 3. 修复 vrt_power 表(如果存在乱码) -SELECT id, name, LENGTH(name), HEX(name) FROM vrt_power WHERE name LIKE '%票%'; -UPDATE vrt_power SET name = 'VR票务' WHERE HEX(name) LIKE '%E7A58A%'; -``` - -详细安全分析见:`reviews/SecurityEngineer-round5-review.md` +Task 1 → Task 2 → Task 3 → Task 4(串行,每份评审写完即 commit)