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
council/ProductManager
Council 2026-04-20 12:13:29 +08:00
parent ca7bee5494
commit da001797ab
2 changed files with 57 additions and 38 deletions

View File

@ -194,7 +194,13 @@ class AdminGoodsSave
// 还原已保存的配置并清洗历史脏数据
if (AppData.vrGoodsConfig && Array.isArray(AppData.vrGoodsConfig)) {
configs.value = AppData.vrGoodsConfig.map(c => {
// 构建有效模板 ID 集合(只含 status=1 的模板)
const validTemplateIds = new Set((AppData.templates || []).map(t => t.id));
configs.value = AppData.vrGoodsConfig
// 过滤掉软删除模板的配置(幽灵配置)
.filter(c => validTemplateIds.has(c.template_id))
.map(c => {
// 确保 sessions 结构正确
if (!c.sessions || c.sessions.length === 0) {
c.sessions = defaultSessions();

View File

@ -67,46 +67,59 @@ class AdminGoodsSaveHandle
}
if (is_array($configs) && !empty($configs)) {
// 0) 填充 template_snapshot前端没传、或 rooms 为空时兜底从 vr_seat_templates 读)
// 0) 重建 template_snapshot — 前端不发送 template_snapshot
// 当 template_snapshot 为空、或 selected_rooms 有值时,从 DB 重建
foreach ($configs as $i => &$config) {
if (empty($config['template_snapshot']) || empty($config['template_snapshot']['rooms'])) {
$templateId = intval($config['template_id'] ?? 0);
if ($templateId > 0) {
$template = Db::name('vr_seat_templates')->find($templateId);
if (empty($template)) {
continue;
}
$seatMap = json_decode($template['seat_map'] ?? '{}', true);
$allRooms = $seatMap['rooms'] ?? [];
$templateId = intval($config['template_id'] ?? 0);
$selectedRooms = $config['selected_rooms'] ?? [];
// ── v1→v3 兼容迁移 ──
// v1 旧格式没有 rooms 嵌套,只有 sections+map 扁平结构
if (empty($allRooms) && !empty($seatMap['sections'])) {
$v1Sections = $seatMap['sections'] ?? [];
$v1Map = $seatMap['map'] ?? [];
$v1Seats = $seatMap['seats'] ?? [];
$v1RoomId = $config['selected_rooms'][0] ?? 'room_1';
$allRooms = [[
'id' => $v1RoomId,
'name' => $seatMap['venue']['name'] ?? '主馆',
'sections' => $v1Sections,
'map' => $v1Map,
'seats' => $v1Seats,
]];
}
// 按 selected_rooms 过滤,只存用户选中的房间
$selectedRoomIds = array_column(
array_filter($allRooms, function ($r) use ($config) {
return isset($r['id']) && in_array($r['id'], $config['selected_rooms'] ?? []);
}), null
);
$config['template_snapshot'] = [
'venue' => $seatMap['venue'] ?? [],
'rooms' => $selectedRoomIds,
];
// 条件snapshot 为空,或者前端有 selected_rooms
if ($templateId > 0 && (!empty($selectedRooms) || empty($config['template_snapshot']) || empty($config['template_snapshot']['rooms']))) {
$template = Db::name('vr_seat_templates')->find($templateId);
if (empty($template)) {
continue;
}
$seatMap = json_decode($template['seat_map'] ?? '{}', true);
$allRooms = $seatMap['rooms'] ?? [];
// ── v1→v3 兼容迁移 ──
// v1 旧格式没有 rooms 嵌套,只有 sections+map 扁平结构
if (empty($allRooms) && !empty($seatMap['sections'])) {
$v1Sections = $seatMap['sections'] ?? [];
$v1Map = $seatMap['map'] ?? [];
$v1Seats = $seatMap['seats'] ?? [];
$v1RoomId = $selectedRooms[0] ?? 'room_1';
$allRooms = [[
'id' => $v1RoomId,
'name' => $seatMap['venue']['name'] ?? '主馆',
'sections' => $v1Sections,
'map' => $v1Map,
'seats' => $v1Seats,
]];
}
// 按 selected_rooms 过滤(支持前端标准化的 "room_0" 格式双向兼容)
$selectedRoomIds = array_column(
array_filter($allRooms, function ($r) use ($selectedRooms) {
$rid = $r['id'] ?? '';
if (in_array($rid, $selectedRooms)) {
return true;
}
// 尝试加/减 "room_" 前缀匹配PHP 7.x 兼容)
if (strpos($rid, 'room_') === 0 && in_array(substr($rid, 5), $selectedRooms)) {
return true;
}
if (in_array('room_' . $rid, $selectedRooms)) {
return true;
}
return false;
}), null
);
$config['template_snapshot'] = [
'venue' => $seatMap['venue'] ?? [],
'rooms' => $selectedRoomIds,
];
}
}
unset($config); // 解除引用,避免后续误改