# 城市DIY模板 — VR Plugin 端实施计划 > 创建日期:2026-06-10 > 基于审查文档:[city-diy-plan-review.md](file:///Users/bigemon/WorkSpace/vr-shopxo-uniapp/docs/city-diy-plan-review.md) > 目标:零核心文件改动,通过插件钩子实现「用户坐标→城市→DIY模板」动态路由 --- ## 架构概述 ``` UniApp 发送 user_lng, user_lat → /api.php?s=index/index ↓ app/api/controller/Index::Index() ← 无需修改 ↓ DiyService::AppClientHomeDiyData() ← 无需修改 ↓ 钩子: plugins_service_diy_app_client_home_diy_data ← 🔑 新增 ↓ DiyHomeCityRouter::handle() ├─ input('user_lng'), input('user_lat') → 直接读请求参数 ├─ GeoCityService::FindNearestCityId() → 城市ID ├─ Db::name('Diy')->where(['name'=>"home_{city_id}",'is_enable'=>1])->value('id') └─ 通过引用 &$diy_id 设置模板ID(未找到则回退默认) ``` --- ## 实施步骤 ### 步骤1:注册钩子 — 修改 [config.json](file:///Users/bigemon/WorkSpace/vr-shopxo-plugin/shopxo/app/plugins/vr_ticket/config.json) **文件**:`shopxo/app/plugins/vr_ticket/config.json` **操作**:在 `hook` 对象中新增一条记录 **当前状态**(hooks 末尾): ```json "plugins_view_admin_goods_content_inside_bottom": [ "app\\plugins\\vr_ticket\\hook\\AdminGoodsIndex" ] ``` **修改后**(在末尾追加逗号+新钩子): ```json "plugins_view_admin_goods_content_inside_bottom": [ "app\\plugins\\vr_ticket\\hook\\AdminGoodsIndex" ], "plugins_service_diy_app_client_home_diy_data": [ "app\\plugins\\vr_ticket\\hook\\DiyHomeCityRouter" ] ``` > [!NOTE] > 钩子名 `plugins_service_diy_app_client_home_diy_data` 来自 [DiyService.php:48](file:///Users/bigemon/WorkSpace/vr-shopxo-plugin/shopxo/app/service/DiyService.php#L48) --- ### 步骤2:新建钩子处理类 — 创建 [DiyHomeCityRouter.php](file:///Users/bigemon/WorkSpace/vr-shopxo-plugin/shopxo/app/plugins/vr_ticket/hook/DiyHomeCityRouter.php) **文件**:`shopxo/app/plugins/vr_ticket/hook/DiyHomeCityRouter.php`(新建) **命名空间**:`app\plugins\vr_ticket\hook` **类名**:`DiyHomeCityRouter` **参考实现**:[Hook.php OnGoodsListBegin](file:///Users/bigemon/WorkSpace/vr-shopxo-plugin/shopxo/app/plugins/vr_ticket/Hook.php#L400-L436) — 已有相同的「坐标→城市ID」逻辑 **关键设计点**: 1. `is_backend` 检查:仅前端请求生效(`is_backend === true` 时才处理,与 DiyService 传来的参数一致) 2. `input('user_lat')` / `input('user_lng')`:直接从 ThinkPHP 请求参数读取,无需依赖 `$params['params']` 3. `GeoCityService::FindNearestCityId()`:复用已有的最近城市查找方法 4. `&$diy_id`:通过引用修改,无需返回值 5. 兜底策略:找不到城市场景模板时 `diy_id` 保持原值,`DiyService` 会走 `AppClientHomeDiyId()` 的默认逻辑 **模板命名约定**: - `home_110100` → 北京市 - `home_310100` → 上海市 - `home_440100` → 广州市 - `home_default` → 默认模板(兜底,由 DiyService 自动匹配) --- ### 步骤3:验证测试 **3a. 后端验证** 直接用浏览器访问 API 端点,模拟带坐标的 UniApp 请求: ``` http://localhost:10000/api.php?s=index/index&user_lng=118.110652&user_lat=24.585 ``` **预期行为**: - 无坐标:返回默认 DIY 模板(与现有行为一致,向下兼容) - 有坐标且城市存在对应模板:返回该城市的 DIY 配置 - 有坐标但城市无对应模板:回退到默认模板 **验证方法**: 1. 先在后台创建一个测试用 DIY 模板,`name` 设为 `home_{测试城市ID}` 2. 用该城市的坐标访问 API,检查返回的 JSON 是否为该模板的配置 3. 用一个不存在模板的城市坐标访问,确认回退到默认模板 **3b. GitNexus 变更检测** 在提交前运行: ```bash npx gitnexus detect-changes ``` 验证改动只影响预期的符号和执行流。 --- ## 文件变更清单 | 文件 | 操作 | 行数变化 | |------|------|----------| | [config.json](file:///Users/bigemon/WorkSpace/vr-shopxo-plugin/shopxo/app/plugins/vr_ticket/config.json) | 修改 | +4 行 | | [DiyHomeCityRouter.php](file:///Users/bigemon/WorkSpace/vr-shopxo-plugin/shopxo/app/plugins/vr_ticket/hook/DiyHomeCityRouter.php) | 新建 | ~35 行 | | **核心文件** | **无修改** | **0 行** | --- ## 风险评估 | 风险 | 等级 | 缓解措施 | |------|------|----------| | 无坐标时走默认逻辑 | 🟢 无风险 | 向下兼容,行为不变 | | GeoCityService 性能 | 🟢 低 | 已有内存+文件双层缓存,1小时过期 | | 钩子未注册 | 🟢 低 | config.json 改动量极小,可快速验证 | | 模板命名冲突 | 🟡 中 | 使用 `home_{city_id}` 前缀约定,后台创建时需遵守 | | 核心升级冲突 | 🟢 无 | 零核心文件修改 | --- > [!TIP] > 实施顺序:步骤1 → 步骤2 → 步骤3,共约 40 行代码改动。任何中断都可以从此文档恢复。