# FrontendDev — Issue 3 Findings: Spec 加载问题(前端视角) ## 当前状态 `loadSoldSeats()` 函数(ticket_detail.html:375-383)**完全是 TODO stub**: ```javascript loadSoldSeats: function() { // TODO: 从后端加载已售座位 // $.get(this.requestUrl + '?s=plugins/vr_ticket/index/sold_seats', { // goods_id: this.goodsId, // spec_base_id: this.sessionSpecId // }, function(res) { // // 标记已售座位 // }); }, ``` 没有任何网络请求,soldSeats 永远是空对象 `{}`。 ## 真实库存加载 **GetGoodsViewData 返回的数据(SeatSkuService.php:358-464)**: `$goods_spec_data` 只包含**场次维度的 spec_base_id**(非座位级): ```php [ 'spec_id' => $specValue['goods_spec_base_id'] ?? 0, // 场次级 ID 'spec_name' => $timeRange, // "08:00-23:59" 'price' => floatval($sv['price']), ] ``` 前端通过 `selectSession()` 选择场次后,`this.sessionSpecId` 被设置为场次级 spec_base_id。**但座位级的 spec_base_id_map(每个座位的 SKU ID)需要从后端接口查询**。 ## specBaseIdMap 的局限性 ticket_detail.html:187 注入的 `specBaseIdMap` 来自 `seatTemplate['spec_base_id_map']`。这个 map 的 key 格式是 `rowLabel_colNum`(如 "A_1"),value 是座位级 GoodsSpecBase ID。 问题:**前端无法仅凭前端数据知道哪些座位已售**。需要后端接口: 1. 根据 `goods_id` + `sessionSpecId` 查询所有已售 GoodsSpecBase(`inventory = 0`) 2. 返回已售座位 key 列表 3. 前端在 `loadSoldSeats()` 中标记 `.sold` class ## 修复方案(前端部分) 需要实现一个 AJAX 接口 `plugins/vr_ticket/index/sold_seats`,前端调用: ```javascript loadSoldSeats: function() { if (!this.sessionSpecId) return; var self = this; $.get(this.requestUrl + '?s=plugins/vr_ticket/index/sold_seats', { goods_id: this.goodsId, spec_base_id: this.sessionSpecId // 场次级 ID }, function(res) { if (res.code === 0 && res.data) { // res.data: [{row_col: "A_1", row_label: "A", col_num: 1}, ...] res.data.forEach(function(sold) { self.soldSeats[sold.row_label + '_' + sold.col_num] = true; }); self.markSoldSeats(); } }); }, markSoldSeats: function() { var self = this; document.querySelectorAll('.vr-seat-row .vr-seat:not(.aisle):not(.space)').forEach(function(el) { var key = el.dataset.rowLabel + '_' + el.dataset.colNum; if (self.soldSeats[key]) { el.classList.add('sold'); } }); } ``` ## API 设计建议 后端需要新增一个控制器方法(可能是 `plugins/vr_ticket/index/Index` 中的 `sold_seats` action),查询 `GoodsSpecBase` 中 `inventory = 0` 的座位记录,按场次 ID 过滤。 ## 依赖 - BackendArchitect 提供 `sold_seats` 接口的准确路径和返回格式 - BackendArchitect 确认 GoodsSpecBase 的 inventory 字段在购票后是否被正确扣减