Commit Graph

63 Commits (main)

Author SHA1 Message Date
sileya-ai 57cc10f8c5 Phase 2 完成:spec渲染+多座位选择+submit修复 → 合并入主线 (#19) 2026-04-22 09:59:39 +00:00
Council 6688a10d95 fix: submit 改为 AJAX POST 到 buy/add,base64 编码 goods_data,修复非法访问错误
- ticket_detail.html: form.submit() → jQuery AJAX POST
  - 改为 POST 到 ?s=buy/add(直接走 OrderInsert)
  - goods_data 用 CryptoJS.base64 编码(ShopXO BuyGoods 期望格式)
  - 显式传 buy_type=goods, address_id=0, site_model=2
  - 成功跳转 jump_url,code=-400 走登录页,失败 alert 提示
- footer.html: 追加 base64csvtojson.js + common.js(修正 JS 加载顺序)

⚠️ CHECKPOINT 已解决:submit() 报"非法访问"问题已修复
⚠️ 注意:base64csvtojson.js 由 ShopXO Docker 容器生成,需同步到 public/static/
⚠️ Phase 3 待完成:订单确认页/支付/观演人信息存储
2026-04-22 01:02:57 +08:00
Council f6f02a0c79 fix: CSS 文件路径 - 同步到 public/plugins/ 目录 2026-04-21 13:12:27 +08:00
Council fdd89fbb70 fix: 优化规格选择器样式 - 处理长名称显示和添加 tooltip 2026-04-21 13:09:48 +08:00
Council dce3c45b23 fix: 添加缺失的 buildSeatSpecMap() 调用 2026-04-21 13:04:54 +08:00
Council de9134773f feat: 添加场馆和分区选择器 + specTypeList 支持
- SeatSkuService: 返回 specTypeList 包含所有4维规格
- Goods.php: 注入 specTypeList
- ticket_detail.html:
  - 添加 venueSelector 和 sectionSelector HTML 容器
  - 添加 renderAllSelectors() 渲染场次/场馆/分区
  - 添加 selectVenue/selectSection/filterSeats 函数
- CSS: 添加规格选择器样式
2026-04-21 13:02:38 +08:00
Council fc07c2ece6 chore: 删除临时脚本 2026-04-21 12:54:42 +08:00
Council 8ea0c1a229 fix: GetGoodsViewData 使用 GoodsSpecType.name 通过值匹配确定维度 2026-04-21 12:46:59 +08:00
Council 4683862688 fix: GetGoodsViewData 使用 SPEC_DIMS 顺序推断维度,不再依赖 type 字段 2026-04-21 12:45:50 +08:00
Council 416fe0a067 fix: 移除 type 字段插入(数据库已回滚) 2026-04-21 12:44:37 +08:00
Council 461dd6b101 fix: 修复 seat map 数据结构 + selected seats UI + encoding + submit button
1. renderSeatMap: 修复 map.seat_map 数据结构访问
2. updateSelectedUI: 渲染 selectedList + 启用 submit button
3. 修复 GoodsSpecValue 中文编码问题
4. 添加 barCount/barPrice 更新
2026-04-21 12:30:09 +08:00
Council 82a5b2129d fix: 修复 seatMap 数据结构错误 - vr_seat_template 已经是解码后的 seat_map 2026-04-21 12:08:48 +08:00
Council fb300e00fc feat(Phase2): 修复 seatSpecMap 生成 + room ID 硬编码问题
关键修复:
1. BatchGenerate(): 新增 extends.seat_key 字段写入 GoodsSpecBase
2. BatchGenerate(): 新增 type 字段写入 GoodsSpecValue(4维spec类型)
3. ticket_detail.html: renderSeatMap() 不再用 room_001_ 硬编码,改用模板实际 roomId
4. Goods.php: seatSpecMap 注入(已在上次提交)

数据库修复:
- 为 vrt_goods_spec_value 新增 type 字段
- 重新生成商品 118 的规格数据(含 seat_key 和 type)
2026-04-21 12:03:56 +08:00
Council c581395a9c feat(Phase2): Issue 1 修复购买提交流程
- Goods.php: 注入 seatSpecMap 到票务模板
- ticket_detail.html: submit() 改 POST + 4维spec数组

关键修复:
- submit() 使用隐藏表单 POST 到 Buy 链路(不再用 location.href)
- spec 从 seatSpecMap[seatKey].spec 读取完整4维数组
- extension_data 嵌套在 order_base 内
- 直接 JSON.stringify,不需要 base64
2026-04-21 11:41:59 +08:00
Council 2311f17b90 fix(vr_ticket): 修复幽灵 spec 问题 (Issue #15 + #16)
Issue #15 — AdminGoodsSaveHandle.php:
1. 读取优先级调换:data['vr_goods_config'] 优先,DB 兜底(从源头避免脏数据)
2. 模板不存在时 unset($configs[$i]) 移除无效 config 块(防御层)
3. array_values 重排索引 + 写回前判空(防御层)

Issue #16 — SeatSkuService.php GetGoodsViewData:
1. 多模板模式:遍历所有配置块过滤有效块
2. 模板不存在时清理无效块并写回有效配置(而非覆盖)

参考:reports/GHOST_SPEC_INVESTIGATION_REPORT.md
参考:docs/PLAN_GHOST_SPEC_FIX.md
2026-04-20 22:42:41 +08:00
Council 9f3a46e5a1 fix(vr_ticket): 修复硬删除按钮 + 清理残留代码
1. Admin.php SeatTemplateDelete/VenueDelete:
   - is_delete → is_delete_time(ShopXO Goods 表软删除字段)
   - VenueDelete 新增 value='hard' 参数支持(兼容 submit-ajax)

2. list.html:
   - 删除按钮从 btn-open-delete-confirm 改为 submit-ajax
   - 删除按钮移出条件判断,始终可见
   - 移除残留的 old modal + custom JS handler

3. 清理 shopxo/app/event.php 变动(还原)
2026-04-20 18:06:23 +08:00
Council 95346206dc fix: 移除不存在的座位模板菜单 + 调整删除提示文案 + 取消阻塞式商品关联检查
1. Hook.php:移除 'plugins-vr_ticket-seat' 菜单项(对应 view 文件已删除)
2. Admin.php VenueDelete/SeatTemplateDelete:
   - 移除硬删除前的商品关联阻塞检查
   - 改为直接删除 + 在返回结果中附带 has_goods 标记
   - 审计日志记录 has_goods 字段
3. view/venue/list.html:删除确认弹窗文案改为
   '删除后,关联商品的场馆信息将被自动清除'
2026-04-20 15:48:11 +08:00
Council df8353a697 feat: 真删除功能 + 三按钮布局 + seat_template 视图补全
后端(Admin.php):
- SeatTemplateDelete/VenueDelete:新增 hard_delete 参数
  - hard_delete=0(默认):软删除(status→0),返回'已禁用'
  - hard_delete=1:真删除,先检查商品关联再 DELETE
- SeatTemplateEnable/VenueEnable:新增启用 API,含审计日志

前端(view/venue/list.html):
- 按钮改为三按钮布局:编辑 / 禁用/启用 / 删除
- 删除按钮点击后弹出警告弹窗
  - 警告:删除记录不会导致已上架商品内容变动
  - 若需同步,请编辑对应商品并保存
- 禁用/启用按钮使用 submit-ajax,data-view=reload 自动刷新

新增(admin/view/seat_template/):
- list.html:座位模板列表(三按钮布局,与 venue/list.html 相同)
- save.html:座位模板编辑页(基础版,seat_map 由 venue 编辑器管理)
2026-04-20 15:08:27 +08:00
Council 5675bb679f fix: 模板硬删除场景下优雅降级 + snapshot 同步清空
方案逻辑(用户提出):
- 模板被硬删除后,GetGoodsViewData() 将 template_id + template_snapshot 同时置 null
- 前端看到选单为空,用户可重新选择或清空配置
- AdminGoodsSaveHandle() 跳过不存在模板的 snapshot 重建(continue)

修改文件:
- SeatSkuService.php: GetGoodsViewData() 加硬删除检测,空模板时清空 config
- AdminGoodsSaveHandle.php: 模板不存在时 continue,不触发 json_decode(null) Fatal Error
2026-04-20 14:32:38 +08:00
Council 05b69588f5 chore: remove debug logging from AdminGoodsSaveHandle
All debugging code (vr_debug.log writes) removed.
Template snapshot rebuild is now stable and verified.
2026-04-20 13:31:17 +08:00
Council c03737308b fix(Admin): 改用 random_int() CSPRNG,修正 UUID v4 版本/变体位
mt_rand() → random_int()(防种子预测)
版本号 nibble: 8 → 4(符合 RFC 4122 UUID v4)
变体位保持 10xx 格式不变
2026-04-20 13:21:44 +08:00
Council 1244adfaae feat(Admin): SeatTemplateSave 时为无 id 的 room 生成 UUID
兜底逻辑:在保存场馆模板时,遍历 rooms,
若 room.id 为空则用 time()+mt_rand 生成唯一 UUID。
不修改已有数据的读取逻辑(读取端已有 room_N 兼容兜底)。
2026-04-20 12:58:19 +08:00
Council 8a33e7fa29 fix(AdminGoodsSaveHandle): 空id房间用数组索引匹配 room_0/room_1
DB 中模板5的room[0].id为空,selected_rooms发来room_0。
filter无法匹配空id导致selectedRoomIds=[],rooms为空。

修复:空id时用数组索引作为room_N(N从0开始)进行匹配。
PHP 7.x兼容,无str_starts_with。
2026-04-20 12:42:46 +08:00
Council 5dc9a98420 fix: Db::find() 全量查询 + fallback 到 params[data];同时加调试日志 2026-04-20 12:25:02 +08:00
Council 0a2fd29d7c debug: add temp logging to trace template_snapshot rebuild 2026-04-20 12:23:58 +08:00
Council da001797ab fix(vr_ticket): template_snapshot 重建逻辑重写 + 幽灵配置过滤
=== 问题 1: template_snapshot.rooms 为空 ===

根因:前端 outputBase64 根本不包含 template_snapshot,导致:
- template_snapshot 永远是空的
- 无论 v1/v3 格式,rooms 信息都丢失

修复(AdminGoodsSaveHandle.php):
- 条件从「template_snapshot 为空才读 DB」改为「selected_rooms 有值就永远从 DB 重建」
- 读 DB 时同时做 v1→v3 迁移(sections+map → rooms 数组)
- ID 匹配支持前端标准化的 "room_0" 格式和 DB 原始 "0" 格式双向兼容
- PHP 7.x 兼容(strpos 而非 str_starts_with)

=== 问题 2: 幽灵配置(软删除场馆仍出现在表单)===

根因:AdminGoodsSave.php 查询模板时用 where('status', 1),软删除模板不加载,
但 configs.value 里还保留着旧配置 → 场馆 checkbox 选中但无法操作。

修复(AdminGoodsSave.php):
- 加载时用 Set 过滤掉 status=0 模板的配置
- 幽灵配置在编辑表单加载时直接排除,不出现在 UI
2026-04-20 12:16:31 +08:00
Council ca7bee5494 fix(AdminGoodsSaveHandle): save_thing_end 改为直接读 DB 而非 值拷贝
确保 template_snapshot 兜底逻辑在正确的数据上执行:
1. ShopXO save_thing_end 传入的 $data 是值拷贝,改用 Db::find() 直接从DB读
2. 加 json_last_error() 检查,防止损坏的 JSON 静默失败
2026-04-20 11:28:34 +08:00
Council 3f06f36e50 fix(AdminGoodsSaveHandle): template_snapshot rooms为空时DB兜底 + v1→v3迁移
修复 Issue #13:
1. 条件从 empty(template_snapshot) 改为 empty(rooms),解决前端发送空rooms对象时跳过兜底的问题
2. 新增 v1 旧格式兼容:sections+map 扁平结构自动升級为 v3 rooms 数组
2026-04-20 10:40:26 +08:00
Council 804d465d09 fix(AdminGoodsSaveHandle): P1+P2 空安全修复 — 解决 "Undefined array key 'id'" 错误
P1 (line 80): array_filter 回调内 $r['id'] 前加 isset() 空安全
P2 (line 71-73): find() 返回 null 时 continue 跳过,避免访问 $template['seat_map']

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 09:59:31 +08:00
Council bbea35d837 feat(AdminGoodsSaveHandle): 保存时自动填充 template_snapshot
Issue #13 Step 1:
- save_thing_end 时机:遍历 vr_goods_config[],检测 template_snapshot 是否缺失
- 若缺失:从 vr_seat_templates 读最新 seat_map,按 selected_rooms 过滤 rooms
- 将填充后的完整 config JSON 写回 goods 表,再执行 BatchGenerate
- 前端已传 template_snapshot 时:直接透传,无需后端处理
2026-04-20 09:36:06 +08:00
Council 1b0ac3276d fix: 替换为票务专用精简 footer
移除 ShopXO 默认导航(关于我们/招聘/客户服务等)
保留:返回首页 + 版权 + ICP备案
2026-04-20 06:35:24 +08:00
Council c894e70188 fix: 复制 ShopXO public 模板 + 修复 footer_page 不存在问题
- 将 ShopXO 默认主题 public/ 目录完整复制到插件 goods/public/
- ticket_detail.html 中 footer_page → footer(footer_page.html 不存在于 ShopXO)
- ModuleInclude() 现在可以正确解析:view_path(goods/) + public/header.html 
2026-04-20 06:29:37 +08:00
Council 349ec063c1 fix: 替换 ThinkTemplate 标签为 PHP ModuleInclude
路线 B:票务模板不依赖 ThinkTemplate 解析引擎
- {include file=...} → <?php echo ModuleInclude(...) ?>
- {:Config()} / {:IsMobileLogin()} → <?php echo Config() ?> / <?php echo IsMobileLogin() ?>
- {$var|default=...} → <?php echo $var ?? 'default' ?>
- {$var|json_encode|raw} → <?php echo json_encode($var ?? []) ?>

绕过 ThinkTemplate parseTemplateFile() 路径拼接 bug(Linux view_depr=/ 导致 include 路径解析错误)
2026-04-20 06:23:29 +08:00
Council 7bd8967648 feat(Phase 2): 完成票务商品前端展示层
- Goods.php: item_type=ticket 时加载 ticket_detail.html 模板
- SeatSkuService.php: 新增 GetGoodsViewData() 供前端模板使用
- TicketService.php: onOrderPaid 改用 sxo_order_detail 表 + JSON spec 解析

关联: Phase 2 前台展示层完成
2026-04-20 05:22:07 +08:00
Council dc63cff77c chore: clean up my_test_plugin residual hooks from event.php
删除 event.php 中的 my_test_plugin 残留引用(插件已删除)。
保留 vr_ticket 所有钩子映射不变。
2026-04-19 15:56:48 +08:00
Council bbb2e65330 fix: 修复 vr_ticket 插件文件被 gitignore 忽略的问题
- 强制追踪 vr_ticket/Event.php(被 shopxo/app/.gitignore 的 event.php 规则遮蔽)
- 强制追踪 vr_ticket/database/migrations/*.sql(被全局 gitignore 的 database 规则遮蔽)
- 删除 shopxo/app/.gitignore(规则过宽,影响插件文件)
- 追踪 shopxo/app/event.php(ShopXO 源码,被上条 .gitignore 遮蔽)
- 更新项目 .gitignore(vendor/upload/adminufgeyw/强制追踪database)
2026-04-19 15:54:03 +08:00
Council 9603ab42f6 refactor(vr_ticket): Admin.php root pattern → Hook-based goods save
- DELETE old Admin.php root controller (Vrticket.php)
- DELETE old Layui view files (seat_template/ticket/venue/verification/verifier)
- ADD hook/AdminGoodsSave.php: plugins_view_admin_goods_save hook (Vue3 form injection)
- ADD hook/AdminGoodsSaveHandle.php: handle save flow (save_handle + save_thing_end)
- UPDATE config.json: register 3 new hooks
- UPDATE SeatSkuService.php: refactored BatchGenerate
- ADD data.db: SQLite venue data
- UPDATE venue/save.html: venue editing form
- docs: add GOODS_ADD_HOOK_RESEARCH.md + update plan.md
2026-04-19 05:46:37 +08:00
Council 2452fde466 refactor(vr_ticket): full plugin restructure - Admin.php root pattern + Hook.php
Phase 2 completion - complete backend management rebuild:

Plugin architecture change (旧 → 新):
- 删: admin/controller/ 子目录多控制器 → 留: admin/Admin.php 单控制器
- 删: admin/view/ → 留: view/{module}/
- 删: EventListener.php, app.php, plugin.json → 留: Hook.php, config.json

New files:
- Hook.php: 插件钩子入口(侧边栏菜单 + 订单支付处理)
- config.json: 插件配置(is_enable 等)
- install.sql / uninstall.sql: 安装卸载脚本
- view/venue/list.html, save.html: 场馆管理视图(AmazeUI)
- view/admin/setup.html: 插件设置页

Modified files:
- service/AuditService.php, BaseService.php, SeatSkuService.php, TicketService.php
- admin/Admin.php: 全新 Admin.php 根目录控制器

ShopXO core changes:
- app/index/controller/Goods.php: ticket 类型商品详情页路由
- app/service/AdminPowerService.php: 权限系统适配
- config/shopxo.php: 配置

AmazeUI frontend migration:
- All views migrated from LayUI to AmazeUI
- Vue 3 editor for venue/seat configuration
- CDN: unpkg.com → cdn.staticfile.net

Fixes included:
- Infinite loading (missing footer include)
- Vue3 textarea interpolation bug
- Template path resolution (../../../plugins/...)
- Hook return fields (id/url/is_show)
- DB field names verified from source
2026-04-17 00:46:00 +08:00
Council f6bcad6bfb fix: 表名前缀修复 + 创建缺失的audit_log表
- BaseService::table() 从 'plugins_vr_' 改为 'vr_'
  (原名 plugins_vr_seat_templates → ShopXO前缀后变成 vrt_plugins_vr_seat_templates,实际表名是 vrt_vr_seat_templates)
- Admin.php 所有硬编码 Db::name('plugins_vr_xxx') 改为 Db::name('vr_xxx')
- 在数据库创建缺失的 vrt_vr_audit_log 表
2026-04-16 17:23:40 +08:00
Council 28103e7d9b docs: 补充自定义侧边栏快速入口机制说明 2026-04-16 15:59:37 +08:00
Council 35c10a7f66 council(security): SecurityEngineer - add missing VenueList methods + security audit
Security findings:
- SQL injection: LOW (query builder + parameter binding)
- XSS: LOW (ThinkPHP auto-escape, no |raw detected)
- Path traversal: LOW (all view paths hardcoded)
- CSRF: MEDIUM (ShopXO framework-level gap, out of scope for plugin)

Critical fix: admin/Admin.php was missing VenueList(), VenueSave(),
VenueDelete() — sidebar URL "/plugins/vr_ticket/admin/venueList" would
return 500 error. Added all three methods with v3.0 seat_map support.

P1 garbled name: documented DB fix SQL for shx_plugins + vrt_power tables.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 08:53:41 +08:00
Council 000a0990e7 council(round3): merge main (BackendArchitect Phase 2 fixes) + FrontendDev Admin.php routing
BackendArchitect 贡献:
- Vrticket.php (app/admin/controller/) - 独立后台控制器
- 视图复制到 app/admin/view/default/plugins/view/vr_ticket/admin/view/
- admin/controller/Plugins.php - 插件路由入口
- admin/controller/Venue.php + view/venue/ - 场馆管理
- app.php - 插件主文件

FrontendDev 贡献(本次):
- admin/Admin.php - 统一入口控制器(admin/ 子目录模式)
- plugin.json - sidebar URL 改为 camelCase 格式匹配 ucfirst()

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 08:35:26 +08:00
Council b41e268a77 council(round3): FrontendDev - fix admin/Admin.php routing + camelCase sidebar URLs
路由分析结论:
- PluginsService::PluginsControlCall 使用 ucfirst() 转换类名
- sidebar URL /plugins/vr_ticket/admin/seatTemplateList
- → class=\app\plugins\vr_ticket\admin\Admin, method=SeatTemplateList()
- admin/Admin.php 方法名使用 camelCase 与 URL 匹配

修改内容:
- admin/Admin.php: 更新注释,方法名已使用 camelCase ✓
- plugin.json: sidebar URL 从 snake_case 改为 camelCase 格式

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 08:34:50 +08:00
Council 5749edf6ad fix(Phase 2): 修复后台路由+视图路径,Vrticket控制器上线
- 新增 Vrticket.php(ThinkPHP小写路由约定,类名Vrticket)
- 修复视图标签:{include} → {{include}}(ShopXO使用{{}}分隔符)
- 视图文件同步到 app/admin/view/default/plugins/view/vr_ticket/
- 插件控制器类名 Seattemplate(ThinkPHP路由适配)
- plugin.json 新增场馆配置菜单项
- 删除废弃的 plugins/index.html 符号链接
- 自动载入:app.php 注册 app\plugins\ 命名空间映射
2026-04-16 07:59:27 +08:00
Council 49e256a9ab feat(Phase 3-1): Vue3 交互式场馆配置表单编辑器 save.html
- admin/view/venue/save.html:Vue3 CDN 嵌入
  - 实时彩色座位预览(每格 30x30px,背景色=zone.color,悬浮显示座位号/分区/价格)
  - 动态增删分区(char/name/price/color + 预设色板)
  - 每排座位行编辑器(动态 input)
  - 双向同步:改 zone char/color → 预览即时刷新
  - 初始默认值:3 区(VIP区/看台区/普通区),6座/排
  - mounted() 回填:zones_json / map_json / venue_json
  - computed 序列化:zonesJson / seatMapRowsJson / venueJson → 隐藏字段

- Venue.php 补充:新增 venue_json 字段供 Vue3 回填
  - venue_json = {name, address, image}

关联:docs/11_EDITOR_AND_INJECTION_DESIGN.md v3.0
2026-04-15 22:06:21 +08:00
Council 136efb9b92 feat(Phase 3-1): Venue.php CRUD + list.html + BatchGenerate venue.name 动态读取
- 新增 admin/controller/Venue.php:场馆配置 CRUD
  - list(): 解析 seat_map.venue.name 展示,zone_count / seat_count
  - save(): 构建 v3.0 seat_map JSON(venue + map + seats + sections)
  - delete(): 软删除 + 审计日志
  - preview(): 调试接口,返回 seat_map JSON + seat_count

- 新增 admin/view/venue/list.html:场馆列表页

- 改造 SeatSkuService.php BatchGenerate:
  - ensureVrSpecTypes() 增加 $venueName 参数
  - $vr-场馆 spec 值从 seat_map.venue.name 读取,不再硬编码
  - 降级:取模板 name 或 '未命名场馆'

关联:docs/11_EDITOR_AND_INJECTION_DESIGN.md v3.0
2026-04-15 22:02:03 +08:00
Council d411073885 council(fix): BackendArchitect - Fix regex bug in getExistingSpecBaseIds()
Bug: regex '^([A-Za-z]+)(\d+)排(\d)座$' with $m[3] misparsed seat labels
like "A排10座" → colNum=1 (wrong). Fixed to '^([A-Za-z]+)排(\d+)座$' with $m[2].

Also clarified spec_base_id_map docblock: frontend expects flat integer,
not nested object.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 20:16:49 +08:00
Council 96337bc840 council(execute): BackendArchitect - Fix 2 bugs in P0-A/B/P1 implementations
Bug 1: SeatSkuService.php:381 - regex has syntax error
  '/^([A-Za-z]+)(\d+)排(\d+)座$/' → '/^([A-Za-z]+)(\d+)排(\d)座$/'
  The third capture group only needs single digit (col number 1-9).

Bug 2: ticket_detail.html:416 - frontend accesses specBaseIdMap as object
  but PHP returns flat integer: specBaseIdMap['A_1'] = 2001 (int), not {spec_base_id: 2001}.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 20:09:22 +08:00
Council 5e9c111370 council(draft): BackendArchitect - P0-A initGoodsSpecs + P0-B BatchGenerate
P0-A: BaseService::initGoodsSpecs() — 启用 is_exist_many_spec=1,
      插入 $vr-场馆/$vr-分区/$vr-时段/$vr-座位号 四维规格类型,幂等保护

P0-B: 新建 SeatSkuService.php,含:
      - BatchGenerate(): 批量生成座位级 SKU(500条/批,直接 SQL INSERT)
      - UpdateSessionSku(): 按场次更新 $vr-时段 维度
      - 幂等:已存在座位不重复生成

关联:Issue #9

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 20:00:29 +08:00
Council 93b70d4d50 council(execute): FrontendDev - Issue #9 P1 submit() refactor (seat-level goods_params)
- renderSeatMap(): add data-row-label + data-col-num attrs for specBaseIdMap key format
- toggleSeat(): change seatKey from "0_0" (numeric) to "A_1" (label_colNum) to match specBaseIdMap
- removeSeat(): use [data-row-label][data-col-num] selector
- submit(): refactor from 1 goods_params (zone-level) to N entries (seat-level, stock=1)
- Plan B fallback: if specBaseIdMap[key] missing, use sessionSpecId

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 19:56:25 +08:00