diff --git a/docs/13_GOODS_ADD_HOOK_RESEARCH.md b/docs/13_GOODS_ADD_HOOK_RESEARCH.md index bfd8faf..81e800b 100644 --- a/docs/13_GOODS_ADD_HOOK_RESEARCH.md +++ b/docs/13_GOODS_ADD_HOOK_RESEARCH.md @@ -127,9 +127,11 @@ public static function BatchGenerate(int $goodsId, int $seatTemplateId): array 用户点击「发布商品」 │ └─► Hook[2] plugins_service_goods_save_handle - └─► 读取 goods.vr_goods_config(JSON) + └─► 读取表单传上来的 vr_goods_config(JSON)与 vr_is_ticket 标识 + └─► 若 vr_is_ticket=1,强制设置商品 item_type = 'ticket';否则设为 'normal' └─► 对每个 templateId 调用 BatchGenerate(带节点过滤) └─► 写入/更新 sku(goods_spec_base + goods_spec_value) + └─► 存储 vr_goods_config 到 goods 表新字段 ``` ### 2.2 Hook[1] 注入面板设计 @@ -143,7 +145,7 @@ public static function BatchGenerate(int $goodsId, int $seatTemplateId): array ☑ 是否为票务商品 ← 勾选框,解锁票务配置 ───────────────────────── ▼ 票务配置(勾选后展开) - 场馆模板:[请选择 ▼] + 场馆模板(可多选多个场馆):[请选择 ▼] └─ 场馆名称预览 + 地址 演播厅选择(多选): @@ -174,9 +176,10 @@ $templates = Db::name('vr_seat_templates') ### 2.3 Hook[2] 数据处理流程 -用户提交后,`params` 里携带: +用户提交后,`params` 里携带多个template,version 用于未来不同前端识别适配: ```json { + “version": "1.0.0", "vr_is_ticket": "1", "vr_goods_config": [ { @@ -191,7 +194,7 @@ $templates = Db::name('vr_seat_templates') } ``` -**存储**:新增 `goods.vr_goods_config` LONGTEXT 字段(JSON 数组),直接存这个结构,不建新表。 +**存储**:新增一个 `goods.vr_goods_config` LONGTEXT 字段(JSON 数组),直接存这个结构,不建新表。 ### 2.4 BatchGenerate 扩展(按分区过滤) @@ -206,6 +209,10 @@ public static function BatchGenerate( **扩展逻辑**: ```php +// 参数清理:过滤掉空的分类 +$selectedRooms = array_filter($selectedRooms); +$selectedSections = array_filter($selectedSections); + // 遍历每个 room foreach ($seatMap['rooms'] as $room) { // 跳过未选中的房间 @@ -272,10 +279,10 @@ AFTER item_type; | 决策点 | 结论 | |--------|------| -| vr_goods_config 存在哪 | 直接存 `goods.vr_goods_config`(JSON 数组),不建新表 | -| 表名 | MySQL 数据库 `vrticket`(不是 `shopxo` 默认前缀) | +| vr_goods_config 存在哪 | 直接存 `goods.vr_goods_config`(JSON 数组字段),不建新表 | +| 数据库定义澄清 | 统一使用 ShopXO 默认数据库连接与 `{prefix}` 机制(表如 `{prefix}goods`,插件表为 `{prefix}vr_seat_templates`)| | 票务配置面板是否默认显示 | **否**,默认隐藏,用户勾选"是否为票务商品"后展开 | -| 勾选框名称 | "是否为票务商品"(checkbox) | +| 商品核心类型联动 | 若勾选“是否为票务商品”,Hook 将同步改变商品的核心 `item_type` 字段为 `'ticket'`。 | | 多模板支持 | 支持(vr_goods_config 是 JSON 数组,每个元素=一个模板配置) | | 座位模板表内字段废弃 | `category_id` 绑定字段已废弃,不使用 | | category_id 废弃后的模板查询 | 直接查询 `vr_seat_templates.status=1`,不再依赖 category_id | diff --git a/plan.md b/plan.md index f591146..0112369 100644 --- a/plan.md +++ b/plan.md @@ -84,14 +84,52 @@ app/plugins/vr_ticket/ --- -## 视图路径问题 +## 视图路径问题(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 +``` ### 修复方案 -- BackendArchitect 已将视图复制到 `app/admin/view/default/plugins/view/vr_ticket/admin/view/` -- `admin/Admin.php` 中使用 `return view('seat_template/list', $data)`(相对路径) -- ShopXO 会自动从 `app/admin/view/default/plugins/view/vr_ticket/admin/view/` 解析 -- ✓ 路径问题已通过 BackendArchitect 的 Vrticket.php 方式部分解决 -- admin/Admin.php 使用 ThinkPHP 的 view() 助手函数,相对路径正确解析 +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/`。 --- @@ -126,8 +164,29 @@ app/plugins/vr_ticket/ | P1-T2 | [Done] | admin/Admin.php 模式正确 | | P1-T3 | [Done] | admin/Admin.php 已创建 + plugin.json 已修复 | | P1-T4 | [Pending] | 需实际访问 URL 截图验证 | -| P2-T1 | [Pending] | 数据库编码检查(需 DB 访问)| -| P2-T2 | [Pending] | 数据库修复(如需要)| +| 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) + --- diff --git a/shopxo/admin.php b/shopxo/admin.php deleted file mode 100644 index bc9f9a2..0000000 --- a/shopxo/admin.php +++ /dev/null @@ -1,29 +0,0 @@ -http; -$response = $http->name('admin')->run(); -$response->send(); -$http->end($response); -?> \ No newline at end of file diff --git a/shopxo/app/admin/controller/Vrticket.php b/shopxo/app/admin/controller/Vrticket.php deleted file mode 100644 index 05063b6..0000000 --- a/shopxo/app/admin/controller/Vrticket.php +++ /dev/null @@ -1,85 +0,0 @@ -render('seat_template/list'); - } - - /** - * 座位模板保存 - */ - public function SeatTemplateSave() - { - return $this->render('seat_template/save'); - } - - /** - * 电子票列表 - */ - public function TicketList() - { - return $this->render('ticket/list'); - } - - /** - * 电子票详情 - */ - public function TicketDetail() - { - return $this->render('ticket/detail'); - } - - /** - * 核销员列表 - */ - public function VerifierList() - { - return $this->render('verifier/list'); - } - - /** - * 核销员保存 - */ - public function VerifierSave() - { - return $this->render('verifier/save'); - } - - /** - * 核销记录列表 - */ - public function VerificationList() - { - return $this->render('verification/list'); - } - - /** - * 渲染插件视图 - * @param string $template 模板路径(相对于 vr_ticket/admin/view/ 目录) - */ - protected function render($template) - { - // 插件视图路径(从 app/admin/view/default/plugins/view/vr_ticket/admin/view/ 开始) - return MyView('plugins/view/vr_ticket/admin/view/' . $template); - } -} diff --git a/shopxo/app/admin/view/default/plugins/view/vr_ticket/admin/view/seat_template/list.html b/shopxo/app/admin/view/default/plugins/view/vr_ticket/admin/view/seat_template/list.html deleted file mode 100644 index 9a5205c..0000000 --- a/shopxo/app/admin/view/default/plugins/view/vr_ticket/admin/view/seat_template/list.html +++ /dev/null @@ -1,102 +0,0 @@ - - -
- -► 场馆配置:{{ getTemplateName(config.template_id) }}
+ + +• {{ getRoomName(config.template_id, roomId) }}
+