vr-shopxo-plugin/plan.md

272 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# vr-shopxo-plugin Phase 2 Bugfix — plan.md
> 版本v1.0 | 日期2026-04-16 | Agentcouncil/FrontendDev
> 背景Phase 2 后台管理两个致命问题 — 侧栏乱码 + 路由无法渲染
---
## 问题总览
| # | 问题 | 症状 | 优先级 |
|---|------|------|--------|
| **P1** | 插件控制器路由无法渲染 | 内容区空白,"template not exists" | 高 |
| **P2** | 侧边栏插件名乱码 | `VR票务`(应为 `VR票务` | 中 |
---
## P1 — 路由无法渲染问题
### 已知现象
- 访问 `adminwatekc.php?s=VrTicket/SeatTemplateList` → 侧栏正常,主内容区空白
- ShopXO `Plugins/Index` 控制器调用插件时有 `strtolower+ucfirst` 类名匹配问题
- 当前 `SeatTemplate.php``admin/controller/` 子目录
### 已知正确模式freightfee/answers
```
app/plugins/{plugin}/
├── Admin.php ← 直接在插件根目录,继承 think\Controller
├── Hook.php
├── config.json
└── admin/view/... ← 视图在 admin/view/ 子目录
```
### 当前 vr_ticket 结构(有问题)
```
app/plugins/vr_ticket/
├── admin/controller/SeatTemplate.php ← ❌ 在子目录
└── admin/view/seat_template/list.html
```
### 任务清单
- [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 问题 — 修复方案
- 方案AALTER TABLE 转换 latin1 → utf8mb4
- 方案BMySQL CONVERT/CAST 函数读取时转换
- 方案CPHP 层以 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/`
---
## 阶段划分
| 阶段 | 内容 | 负责 |
|------|------|------|
| **Round 1规划** | 分析根因,制定修复方案 | FrontendDev |
| **Round 2执行** | 实施 admin/Admin.php + plugin.json 修复 | FrontendDev |
| **Round 3综合** | 合并到 main完整验证 | 所有成员 |
---
## 依赖关系
- P1-T3 和 P1-T4 需要实际访问 URL 验证(无法在 CLI 环境截图)
- P2-T1 需要连接数据库检查编码
---
## 交付物
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`
---
## SecurityEngineer Round 6 — 文档评审
> 任务:对 Phase 2 相关 3 份文档进行评审
> 规则:只读文档,不读代码文件;不修改任何文件;不 push
### 待评审文档
| # | 文档 | 评审重点 |
|---|------|---------|
| D1 | `docs/14_TEMPLATE_RENDER_INVESTIGATION.md` | 数据流表名是否正确、Think驱动结论是否有效、解决方案是否合理 |
| D2 | `docs/PHASE2_PLAN.md` | 任务优先级、风险评估、决策点清晰度 |
| D3 | `docs/DEVELOPMENT_LOG.md`(第十一+十二章) | 事实准确性、时间线一致性、遗漏的关键信息 |
### 评审维度(每份文档覆盖)
1. **准确性** — 技术描述、数据流、表名是否正确
2. **完整性** — 是否遗漏边界条件/安全考量/依赖项
3. **可操作性** — 下一步行动是否清晰可执行
4. **一致性** — 各文档之间表名/文件路径/状态描述是否一致
5. **误导风险** — 是否有表述易让接手者误解
### 任务清单
- [ ] **D1-T1**: 评审 `docs/14_TEMPLATE_RENDER_INVESTIGATION.md` → 输出到 `reviews/SecurityEngineer-on-docs-review.md`
- [ ] **D1-T2**: 评审 `docs/PHASE2_PLAN.md` → 追加到 `reviews/SecurityEngineer-on-docs-review.md`
- [ ] **D1-T3**: 评审 `docs/DEVELOPMENT_LOG.md`(第十一+十二章)→ 追加到 `reviews/SecurityEngineer-on-docs-review.md`
- [ ] **D1-T4**: 综合建议 + Top 3 最需要修正的问题 → 追加到 `reviews/SecurityEngineer-on-docs-review.md`
- [ ] **D1-T5**: 合并评审结果到 `reviews/SecurityEngineer-on-docs-review.md` 并提交到 main
### 交付物
`reviews/SecurityEngineer-on-docs-review.md` — 三份文档各自的评分5维度+ 总体评价 + Top 3 修正建议
### 状态
- [ ] D1-T1 `[Claimed: council/SecurityEngineer]`
- [ ] D1-T2 `[Claimed: council/SecurityEngineer]`
- [ ] D1-T3 `[Claimed: council/SecurityEngineer]`
- [ ] D1-T4 `[Claimed: council/SecurityEngineer]`
- [ ] D1-T5 `[Claimed: council/SecurityEngineer]`