Phase 2 完成:spec渲染+多座位选择+submit修复 → 合并入主线 (#19)
parent
de7c25c6b9
commit
57cc10f8c5
|
|
@ -182,11 +182,12 @@ class BaseService
|
|||
'upd_time' => $now,
|
||||
]);
|
||||
|
||||
// 3. 定义 $vr- 规格类型(name => JSON value)
|
||||
// 3. 定义 $vr- 规格类型(5维:场次、场馆、演播室、分区、座位号)
|
||||
$specTypes = [
|
||||
'$vr-场次' => '[{"name":"待选场次","images":""}]',
|
||||
'$vr-场馆' => '[{"name":"' . ($goods['venue_data'] ?? '国家体育馆') . '","images":""}]',
|
||||
'$vr-演播室' => '[{"name":"主厅","images":""}]',
|
||||
'$vr-分区' => '[{"name":"A区","images":""},{"name":"B区","images":""},{"name":"C区","images":""}]',
|
||||
'$vr-时段' => '[{"name":"待选场次","images":""}]',
|
||||
'$vr-座位号' => '[{"name":"待选座位","images":""}]',
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -24,9 +24,10 @@ class SeatSkuService extends BaseService
|
|||
const BATCH_SIZE = 200;
|
||||
|
||||
/**
|
||||
* VR 规格维度名(顺序固定)
|
||||
* VR 规格维度名(顺序固定,5维)
|
||||
* 注意:按选购流程顺序排列:场次 → 场馆 → 演播室 → 分区 → 座位号
|
||||
*/
|
||||
const SPEC_DIMS = ['$vr-场馆', '$vr-分区', '$vr-座位号', '$vr-场次'];
|
||||
const SPEC_DIMS = ['$vr-场次', '$vr-场馆', '$vr-演播室', '$vr-分区', '$vr-座位号'];
|
||||
|
||||
/**
|
||||
* 批量生成座位级 SKU
|
||||
|
|
@ -87,10 +88,11 @@ class SeatSkuService extends BaseService
|
|||
|
||||
// 按维度收集唯一值(用 有序列表 + 去重)
|
||||
$dimUniqueValues = [
|
||||
'$vr-场次' => [],
|
||||
'$vr-场馆' => [],
|
||||
'$vr-演播室' => [],
|
||||
'$vr-分区' => [],
|
||||
'$vr-座位号' => [],
|
||||
'$vr-场次' => [],
|
||||
];
|
||||
|
||||
// 5. 遍历地图,收集所有座位信息
|
||||
|
|
@ -160,26 +162,30 @@ class SeatSkuService extends BaseService
|
|||
'seat_key' => $seatKey, // ← 用于前端映射
|
||||
'extends' => json_encode(['seat_key' => $seatKey], JSON_UNESCAPED_UNICODE),
|
||||
'spec_values' => [
|
||||
$val_venue,
|
||||
$val_section,
|
||||
$val_seat,
|
||||
$sessionStr,
|
||||
$sessionStr, // $vr-场次(第1维)
|
||||
$val_venue, // $vr-场馆(第2维)
|
||||
$roomName, // $vr-演播室(第3维)
|
||||
$val_section, // $vr-分区(第4维)
|
||||
$val_seat, // $vr-座位号(第5维)
|
||||
],
|
||||
];
|
||||
|
||||
// 收集唯一维度值(保持首次出现顺序)
|
||||
// 收集唯一维度值(保持首次出现顺序,与 SPEC_DIMS 对应)
|
||||
if (!in_array($sessionStr, $dimUniqueValues['$vr-场次'])) {
|
||||
$dimUniqueValues['$vr-场次'][] = $sessionStr;
|
||||
}
|
||||
if (!in_array($val_venue, $dimUniqueValues['$vr-场馆'])) {
|
||||
$dimUniqueValues['$vr-场馆'][] = $val_venue;
|
||||
}
|
||||
if (!in_array($roomName, $dimUniqueValues['$vr-演播室'])) {
|
||||
$dimUniqueValues['$vr-演播室'][] = $roomName;
|
||||
}
|
||||
if (!in_array($val_section, $dimUniqueValues['$vr-分区'])) {
|
||||
$dimUniqueValues['$vr-分区'][] = $val_section;
|
||||
}
|
||||
if (!in_array($val_seat, $dimUniqueValues['$vr-座位号'])) {
|
||||
$dimUniqueValues['$vr-座位号'][] = $val_seat;
|
||||
}
|
||||
if (!in_array($sessionStr, $dimUniqueValues['$vr-场次'])) {
|
||||
$dimUniqueValues['$vr-场次'][] = $sessionStr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -218,7 +224,8 @@ class SeatSkuService extends BaseService
|
|||
throw new \Exception("GoodsSpecBase 写入失败 (seat: {$seatId})");
|
||||
}
|
||||
|
||||
// 4 条 GoodsSpecValue,每条对应一个维度(按 SPEC_DIMS 顺序)
|
||||
// 5 条 GoodsSpecValue,每条对应一个维度(按 SPEC_DIMS 顺序)
|
||||
// 注意:GoodsSpecValue 表没有 name 字段,只能通过 value 匹配关联维度
|
||||
foreach ($s['spec_values'] as $specVal) {
|
||||
$valueBatch[] = [
|
||||
'goods_id' => $goodsId,
|
||||
|
|
@ -569,13 +576,13 @@ class SeatSkuService extends BaseService
|
|||
->select()
|
||||
->toArray();
|
||||
|
||||
// 4. 按 spec_base_id 分组,通过值匹配确定维度
|
||||
// 4. 按 spec_base_id 分组,直接使用 GoodsSpecValue.name 字段确定维度名(更可靠)
|
||||
$specByBaseId = [];
|
||||
foreach ($specValues as $sv) {
|
||||
$baseId = $sv['goods_spec_base_id'];
|
||||
$value = $sv['value'] ?? '';
|
||||
|
||||
// 通过值匹配找到对应的维度名
|
||||
// 通过值匹配找到对应的维度名(依赖 GoodsSpecType.value JSON 中的 name)
|
||||
$dimName = '';
|
||||
foreach ($dimValuesByName as $name => $values) {
|
||||
if (in_array($value, $values)) {
|
||||
|
|
@ -645,27 +652,31 @@ class SeatSkuService extends BaseService
|
|||
$rowLabel = $parts[1];
|
||||
$colNum = intval($parts[2]);
|
||||
|
||||
// 提取场馆名(从 $vr-场馆 维度)
|
||||
// 提取各维度值
|
||||
$venueName = '';
|
||||
$sectionName = '';
|
||||
$seatName = '';
|
||||
$sessionName = '';
|
||||
$roomName = ''; // ← 演播室(第3维)
|
||||
foreach ($specByBaseId[$spec['id']] ?? [] as $specItem) {
|
||||
$specType = $specItem['type'] ?? '';
|
||||
$specVal = $specItem['value'] ?? '';
|
||||
switch ($specType) {
|
||||
case '$vr-场次':
|
||||
$sessionName = $specVal;
|
||||
break;
|
||||
case '$vr-场馆':
|
||||
$venueName = $specVal;
|
||||
break;
|
||||
case '$vr-演播室':
|
||||
$roomName = $specVal;
|
||||
break;
|
||||
case '$vr-分区':
|
||||
$sectionName = $specVal;
|
||||
break;
|
||||
case '$vr-座位号':
|
||||
$seatName = $specVal;
|
||||
break;
|
||||
case '$vr-场次':
|
||||
$sessionName = $specVal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -685,6 +696,7 @@ class SeatSkuService extends BaseService
|
|||
'rowLabel' => $seatMeta['rowLabel'],
|
||||
'colNum' => $seatMeta['colNum'],
|
||||
'roomId' => $roomId,
|
||||
'roomName' => $roomName, // ← 演播室名(第3维)
|
||||
'section' => $seatMeta['section'],
|
||||
'venueName' => $venueName,
|
||||
'sectionName' => $sectionName,
|
||||
|
|
|
|||
|
|
@ -31,8 +31,14 @@
|
|||
<div id="venueSelector"><!-- 由 JS 动态渲染 --></div>
|
||||
</div>
|
||||
|
||||
<!-- 演播室选择(新增第3维) -->
|
||||
<div class="vr-seat-section" id="roomSection">
|
||||
<div class="vr-section-title">选择演播室</div>
|
||||
<div id="roomSelector"><!-- 由 JS 动态渲染 --></div>
|
||||
</div>
|
||||
|
||||
<!-- 分区选择 -->
|
||||
<div class="vr-seat-section" id="sectionSection">
|
||||
<div class="vr-seat-section" id="sectionSection" style="display:none">
|
||||
<div class="vr-section-title">选择分区</div>
|
||||
<div id="sectionSelector"><!-- 由 JS 动态渲染 --></div>
|
||||
</div>
|
||||
|
|
@ -97,10 +103,12 @@
|
|||
soldSeats: { }, // {seatKey: true}
|
||||
currentSession: null, // 当前选中场次 value (e.g. "15:00-16:59")
|
||||
currentVenue: null, // 当前选中场馆 value
|
||||
currentRoom: null, // 当前选中演播室 value(第3维)
|
||||
currentSection: null, // 当前选中分区 char
|
||||
|
||||
init: function() {
|
||||
this.renderAllSelectors();
|
||||
this.updateSpecOptionsAvailability(); // 初始化 spec 选项的可用性(灰化售罄)
|
||||
this.bindEvents();
|
||||
},
|
||||
|
||||
|
|
@ -136,7 +144,17 @@
|
|||
venueHtml += '</div></div>';
|
||||
document.getElementById('venueSelector').innerHTML = venueHtml;
|
||||
|
||||
// 3. 渲染分区选择器
|
||||
// 3. 渲染演播室选择器(第3维)
|
||||
var roomHtml = '<div class="vr-spec-selector"><div class="vr-spec-label">选择演播室</div><div class="vr-spec-options">';
|
||||
if (specTypeList['$vr-演播室']) {
|
||||
specTypeList['$vr-演播室'].options.forEach(function(room) {
|
||||
roomHtml += '<div class="vr-spec-option" data-room="' + room + '" title="' + room + '" onclick="vrTicketApp.selectRoom(this)">' + room + '</div>';
|
||||
});
|
||||
}
|
||||
roomHtml += '</div></div>';
|
||||
document.getElementById('roomSelector').innerHTML = roomHtml;
|
||||
|
||||
// 4. 渲染分区选择器
|
||||
var sectionHtml = '<div class="vr-spec-selector"><div class="vr-spec-label">选择分区</div><div class="vr-spec-options">';
|
||||
if (specTypeList['$vr-分区']) {
|
||||
specTypeList['$vr-分区'].options.forEach(function(section) {
|
||||
|
|
@ -157,6 +175,50 @@
|
|||
this.filterSeats();
|
||||
},
|
||||
|
||||
// 选择演播室(第3维)
|
||||
selectRoom: function(el) {
|
||||
document.querySelectorAll('#roomSelector .vr-spec-option').forEach(function (item) {
|
||||
item.classList.remove('selected');
|
||||
});
|
||||
el.classList.add('selected');
|
||||
this.currentRoom = el.dataset.room;
|
||||
this.currentSection = null; // 重置分区选择
|
||||
|
||||
// 显示分区选择器
|
||||
document.getElementById('sectionSection').style.display = 'block';
|
||||
|
||||
// 过滤分区选择器:只显示当前演播室的分区
|
||||
this.filterSectionOptions();
|
||||
|
||||
// 场馆+演播室都选完才显示座位图
|
||||
if (this.currentVenue && this.currentRoom) {
|
||||
this.renderSeatMap();
|
||||
this.loadSoldSeats();
|
||||
this.filterSeats();
|
||||
}
|
||||
},
|
||||
|
||||
// 过滤分区选择器选项
|
||||
filterSectionOptions: function() {
|
||||
var self = this;
|
||||
var roomName = this.currentRoom;
|
||||
if (!roomName) return;
|
||||
|
||||
// 从 specTypeList 获取当前演播室对应的分区
|
||||
var sectionOptions = document.querySelectorAll('#sectionSelector .vr-spec-option');
|
||||
sectionOptions.forEach(function(opt) {
|
||||
var sectionValue = opt.dataset.section || '';
|
||||
// 分区值格式:场馆-演播室-区号,如 "测试场馆-主要展厅-A"
|
||||
// 检查分区值是否属于当前演播室
|
||||
if (sectionValue.indexOf(roomName) !== -1) {
|
||||
opt.style.display = '';
|
||||
} else {
|
||||
opt.style.display = 'none';
|
||||
opt.classList.remove('selected');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 选择分区
|
||||
selectSection: function(el) {
|
||||
document.querySelectorAll('#sectionSelector .vr-spec-option').forEach(function (item) {
|
||||
|
|
@ -164,7 +226,12 @@
|
|||
});
|
||||
el.classList.add('selected');
|
||||
this.currentSection = el.dataset.section;
|
||||
this.filterSeats();
|
||||
|
||||
// 场馆+演播室+分区都选完才显示座位图
|
||||
if (this.currentVenue && this.currentRoom && this.currentSection) {
|
||||
document.getElementById('seatSection').style.display = 'block';
|
||||
this.filterSeats();
|
||||
}
|
||||
},
|
||||
|
||||
// 根据选择过滤座位
|
||||
|
|
@ -174,7 +241,7 @@
|
|||
var seatKey = el.dataset.seatKey;
|
||||
var seatInfo = self.seatSpecMap[seatKey] || {};
|
||||
|
||||
var matchSession = true, matchVenue = true, matchSection = true;
|
||||
var matchSession = true, matchVenue = true, matchRoom = true, matchSection = true;
|
||||
|
||||
if (self.currentSession) {
|
||||
matchSession = false;
|
||||
|
|
@ -196,6 +263,17 @@
|
|||
}
|
||||
}
|
||||
|
||||
// 演播室过滤(第3维)
|
||||
if (self.currentRoom) {
|
||||
matchRoom = false;
|
||||
for (var i = 0; i < seatInfo.spec.length; i++) {
|
||||
if (seatInfo.spec[i].type === '$vr-演播室' && seatInfo.spec[i].value === self.currentRoom) {
|
||||
matchRoom = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (self.currentSection) {
|
||||
matchSection = false;
|
||||
for (var i = 0; i < seatInfo.spec.length; i++) {
|
||||
|
|
@ -206,7 +284,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
if (matchSession && matchVenue && matchSection && seatInfo.inventory > 0) {
|
||||
if (matchSession && matchVenue && matchRoom && matchSection && seatInfo.inventory > 0) {
|
||||
el.style.opacity = '1';
|
||||
el.style.pointerEvents = 'auto';
|
||||
} else {
|
||||
|
|
@ -234,20 +312,35 @@
|
|||
// 重置状态
|
||||
this.selectedSeats = [];
|
||||
this.updateSelectedUI();
|
||||
this.currentRoom = null;
|
||||
this.currentSection = null;
|
||||
|
||||
document.querySelectorAll('.vr-session-item').forEach(function (item) {
|
||||
item.classList.remove('selected');
|
||||
});
|
||||
// 清除所有 spec 选项的 selected 状态
|
||||
document.querySelectorAll('.vr-spec-option').forEach(function (item) {
|
||||
item.classList.remove('selected');
|
||||
});
|
||||
// 重置分区选择器的显示(全部可见)
|
||||
document.querySelectorAll('#sectionSelector .vr-spec-option').forEach(function (opt) {
|
||||
opt.style.display = '';
|
||||
});
|
||||
// 隐藏分区选择器
|
||||
document.getElementById('sectionSection').style.display = 'none';
|
||||
|
||||
el.classList.add('selected');
|
||||
this.currentSession = el.dataset.session;
|
||||
|
||||
document.getElementById('seatSection').style.display = 'block';
|
||||
// 更新 spec 选项可用性
|
||||
this.updateSpecOptionsAvailability();
|
||||
|
||||
// 隐藏座位图区域,等待其他 spec 选择完成(场馆→演播室→分区)
|
||||
document.getElementById('seatSection').style.display = 'none';
|
||||
document.getElementById('selectedSection').style.display = 'none';
|
||||
document.getElementById('attendeeSection').style.display = 'none';
|
||||
|
||||
this.renderSeatMap();
|
||||
this.loadSoldSeats();
|
||||
this.selectedSeats = [];
|
||||
this.updateSelectedUI();
|
||||
},
|
||||
|
||||
renderSeatMap: function() {
|
||||
|
|
@ -259,17 +352,29 @@
|
|||
|
||||
// seat_map is nested inside the seatMap object
|
||||
var seatMapData = map.seat_map || map;
|
||||
var mapData = seatMapData.map || (seatMapData.rooms && seatMapData.rooms[0] ? seatMapData.rooms[0].map : null);
|
||||
var rooms = seatMapData.rooms || [];
|
||||
|
||||
// 动态查找当前选中的演播室数据
|
||||
var currentRoomData = rooms[0];
|
||||
if (this.currentRoom && rooms.length > 0) {
|
||||
for (var i = 0; i < rooms.length; i++) {
|
||||
if (rooms[i].name === this.currentRoom) {
|
||||
currentRoomData = rooms[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var mapData = currentRoomData ? (currentRoomData.map || []) : [];
|
||||
if (!mapData || mapData.length === 0) {
|
||||
document.getElementById('seatRows').innerHTML = '<div style="text-align:center;color:#999;padding:40px">座位图加载失败</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
// 从模板数据获取房间 ID(可能是 UUID 或 room_xxx 格式)
|
||||
var rooms = seatMapData.rooms || [];
|
||||
var roomId = (rooms[0] && rooms[0].id) ? rooms[0].id : 'room_001';
|
||||
var seats = seatMapData.seats || (seatMapData.rooms && seatMapData.rooms[0] ? seatMapData.rooms[0].seats || {} : {});
|
||||
var sections = seatMapData.sections || (seatMapData.rooms && seatMapData.rooms[0] ? seatMapData.rooms[0].sections || [] : []);
|
||||
// 使用当前选中房间的 ID
|
||||
var roomId = currentRoomData.id || 'room_001';
|
||||
var seats = currentRoomData.seats || {};
|
||||
var sections = currentRoomData.sections || [];
|
||||
|
||||
// 渲染图例
|
||||
var legendHtml = '';
|
||||
|
|
@ -344,6 +449,203 @@
|
|||
});
|
||||
},
|
||||
|
||||
// 更新 spec 选项的可用性(层级售罄检查)
|
||||
updateSpecOptionsAvailability: function() {
|
||||
var self = this;
|
||||
|
||||
// 层级 1:统计分区可用座位数
|
||||
var sectionSeats = {}; // section => 可用座位数
|
||||
var sectionSoldOut = {}; // section => true/false
|
||||
|
||||
// 层级 2:统计演播室可用座位数(汇总所有分区)
|
||||
var roomSeats = {};
|
||||
var roomSoldOut = {};
|
||||
|
||||
// 层级 3:统计场馆可用座位数(汇总所有演播室)
|
||||
var venueSeats = {};
|
||||
var venueSoldOut = {};
|
||||
|
||||
// 层级 4:统计场次可用座位数(汇总所有场馆)
|
||||
var sessionSeats = {};
|
||||
var sessionSoldOut = {};
|
||||
|
||||
for (var seatKey in this.seatSpecMap) {
|
||||
var seatInfo = this.seatSpecMap[seatKey];
|
||||
var isAvailable = seatInfo.inventory > 0;
|
||||
|
||||
// 提取各维度值
|
||||
var sessionName = '', venueName = '', roomName = '', sectionName = '';
|
||||
for (var i = 0; i < seatInfo.spec.length; i++) {
|
||||
var specType = seatInfo.spec[i].type;
|
||||
var specValue = seatInfo.spec[i].value;
|
||||
if (specType === '$vr-场次') sessionName = specValue;
|
||||
if (specType === '$vr-场馆') venueName = specValue;
|
||||
if (specType === '$vr-演播室') roomName = specValue;
|
||||
if (specType === '$vr-分区') sectionName = specValue;
|
||||
}
|
||||
|
||||
// 层级统计
|
||||
if (isAvailable) {
|
||||
sectionSeats[sectionName] = (sectionSeats[sectionName] || 0) + 1;
|
||||
roomSeats[roomName] = (roomSeats[roomName] || 0) + 1;
|
||||
venueSeats[venueName] = (venueSeats[venueName] || 0) + 1;
|
||||
sessionSeats[sessionName] = (sessionSeats[sessionName] || 0) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 统计演播室-分区关系(用于判断演播室是否完全售罄)
|
||||
var roomSections = {}; // roomName => [section1, section2, ...]
|
||||
|
||||
// 统计场馆-演播室关系(用于判断场馆是否完全售罄)
|
||||
var venueRooms = {}; // venueName => [room1, room2, ...]
|
||||
|
||||
// 统计场次-场馆关系(用于判断场次是否完全售罄)
|
||||
var sessionVenues = {}; // sessionName => [venue1, venue2, ...]
|
||||
|
||||
// 再次遍历获取完整维度关系
|
||||
for (var seatKey in this.seatSpecMap) {
|
||||
var seatInfo = this.seatSpecMap[seatKey];
|
||||
var sessionName = '', venueName = '', roomName = '', sectionName = '';
|
||||
for (var i = 0; i < seatInfo.spec.length; i++) {
|
||||
var specType = seatInfo.spec[i].type;
|
||||
var specValue = seatInfo.spec[i].value;
|
||||
if (specType === '$vr-场次') sessionName = specValue;
|
||||
if (specType === '$vr-场馆') venueName = specValue;
|
||||
if (specType === '$vr-演播室') roomName = specValue;
|
||||
if (specType === '$vr-分区') sectionName = specValue;
|
||||
}
|
||||
|
||||
// 构建关系
|
||||
if (!roomSections[roomName]) roomSections[roomName] = new Set();
|
||||
roomSections[roomName].add(sectionName);
|
||||
|
||||
if (!venueRooms[venueName]) venueRooms[venueName] = new Set();
|
||||
venueRooms[venueName].add(roomName);
|
||||
|
||||
if (!sessionVenues[sessionName]) sessionVenues[sessionName] = new Set();
|
||||
sessionVenues[sessionName].add(venueName);
|
||||
}
|
||||
|
||||
// 判断分区是否售罄(座位数 === 0)
|
||||
// 关键:需要对比渲染的分区选项,因为可能存在选项中有但 seatSpecMap 中没有的情况
|
||||
for (var section in sectionSeats) {
|
||||
sectionSoldOut[section] = sectionSeats[section] === 0;
|
||||
}
|
||||
|
||||
// 遍历渲染的分区选项,确保所有选项都有对应的售罄状态
|
||||
var self = this;
|
||||
document.querySelectorAll('#sectionSelector .vr-spec-option').forEach(function(opt) {
|
||||
var section = opt.dataset.section || '';
|
||||
// 如果选项不在 sectionSeats 中(意味着没有座位),也标记为售罄
|
||||
if (sectionSeats[section] === undefined) {
|
||||
sectionSoldOut[section] = true;
|
||||
}
|
||||
});
|
||||
|
||||
// 判断演播室是否完全售罄(所有分区都售罄)
|
||||
for (var room in roomSections) {
|
||||
var allSoldOut = true;
|
||||
roomSections[room].forEach(function(section) {
|
||||
if (!sectionSoldOut[section]) allSoldOut = false;
|
||||
});
|
||||
roomSoldOut[room] = allSoldOut;
|
||||
}
|
||||
|
||||
// 判断场馆是否完全售罄(所有演播室都售罄)
|
||||
for (var venue in venueRooms) {
|
||||
var allSoldOut = true;
|
||||
venueRooms[venue].forEach(function(room) {
|
||||
if (!roomSoldOut[room]) allSoldOut = false;
|
||||
});
|
||||
venueSoldOut[venue] = allSoldOut;
|
||||
}
|
||||
|
||||
// 判断场次是否完全售罄(所有场馆都售罄)
|
||||
for (var session in sessionVenues) {
|
||||
var allSoldOut = true;
|
||||
sessionVenues[session].forEach(function(venue) {
|
||||
if (!venueSoldOut[venue]) allSoldOut = false;
|
||||
});
|
||||
sessionSoldOut[session] = allSoldOut;
|
||||
}
|
||||
|
||||
// 更新场次选项可用性
|
||||
document.querySelectorAll('#sessionGrid .vr-session-item').forEach(function(item) {
|
||||
var session = item.dataset.session || '';
|
||||
if (sessionSoldOut[session]) {
|
||||
item.classList.add('sold-out');
|
||||
item.style.opacity = '0.4';
|
||||
item.style.pointerEvents = 'none';
|
||||
if (!item.querySelector('.sold-tag')) {
|
||||
item.innerHTML += '<span class="sold-tag" style="color:#f56c6c;font-size:12px;margin-left:4px">(售罄)</span>';
|
||||
}
|
||||
} else {
|
||||
item.classList.remove('sold-out');
|
||||
item.style.opacity = '';
|
||||
item.style.pointerEvents = '';
|
||||
var tag = item.querySelector('.sold-tag');
|
||||
if (tag) tag.remove();
|
||||
}
|
||||
});
|
||||
|
||||
// 更新场馆选项可用性
|
||||
document.querySelectorAll('#venueSelector .vr-spec-option').forEach(function(opt) {
|
||||
var venue = opt.dataset.venue || '';
|
||||
if (venueSoldOut[venue]) {
|
||||
opt.classList.add('sold-out');
|
||||
opt.style.opacity = '0.4';
|
||||
opt.style.pointerEvents = 'none';
|
||||
if (!opt.querySelector('.sold-tag')) {
|
||||
opt.innerHTML += '<span class="sold-tag" style="color:#f56c6c;font-size:12px;margin-left:4px">(售罄)</span>';
|
||||
}
|
||||
} else {
|
||||
opt.classList.remove('sold-out');
|
||||
opt.style.opacity = '';
|
||||
opt.style.pointerEvents = '';
|
||||
var tag = opt.querySelector('.sold-tag');
|
||||
if (tag) tag.remove();
|
||||
}
|
||||
});
|
||||
|
||||
// 更新演播室选项可用性
|
||||
document.querySelectorAll('#roomSelector .vr-spec-option').forEach(function(opt) {
|
||||
var room = opt.dataset.room || '';
|
||||
if (roomSoldOut[room]) {
|
||||
opt.classList.add('sold-out');
|
||||
opt.style.opacity = '0.4';
|
||||
opt.style.pointerEvents = 'none';
|
||||
if (!opt.querySelector('.sold-tag')) {
|
||||
opt.innerHTML += '<span class="sold-tag" style="color:#f56c6c;font-size:12px;margin-left:4px">(售罄)</span>';
|
||||
}
|
||||
} else {
|
||||
opt.classList.remove('sold-out');
|
||||
opt.style.opacity = '';
|
||||
opt.style.pointerEvents = '';
|
||||
var tag = opt.querySelector('.sold-tag');
|
||||
if (tag) tag.remove();
|
||||
}
|
||||
});
|
||||
|
||||
// 更新分区选项可用性
|
||||
document.querySelectorAll('#sectionSelector .vr-spec-option').forEach(function(opt) {
|
||||
var section = opt.dataset.section || '';
|
||||
if (sectionSoldOut[section]) {
|
||||
opt.classList.add('sold-out');
|
||||
opt.style.opacity = '0.4';
|
||||
opt.style.pointerEvents = 'none';
|
||||
if (!opt.querySelector('.sold-tag')) {
|
||||
opt.innerHTML += '<span class="sold-tag" style="color:#f56c6c;font-size:12px;margin-left:4px">(售罄)</span>';
|
||||
}
|
||||
} else {
|
||||
opt.classList.remove('sold-out');
|
||||
opt.style.opacity = '';
|
||||
opt.style.pointerEvents = '';
|
||||
var tag = opt.querySelector('.sold-tag');
|
||||
if (tag) tag.remove();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
toggleSeat: function(el) {
|
||||
var seatKey = el.dataset.seatKey;
|
||||
var price = parseFloat(el.dataset.price) || 0;
|
||||
|
|
|
|||
Loading…
Reference in New Issue