189 lines
5.9 KiB
JavaScript
189 lines
5.9 KiB
JavaScript
(function () {
|
||
var VALID_TABS = ['cp', 'brother', 'sister'];
|
||
var LEVEL_IMAGES = {
|
||
1: './assets/level-1@4x.png',
|
||
2: './assets/level-2@4x.png',
|
||
3: './assets/level-3@4x.png',
|
||
4: './assets/level-4@4x.png',
|
||
5: './assets/level-5@4x.png',
|
||
};
|
||
|
||
var page = document.getElementById('page');
|
||
var contentPanel = document.getElementById('contentPanel');
|
||
var backButton = document.getElementById('backButton');
|
||
var tabButtons = Array.prototype.slice.call(
|
||
document.querySelectorAll('.tab-button[data-tab]')
|
||
);
|
||
|
||
var state = {
|
||
activeTab: normalizeTab(readParam('tab')) || 'cp',
|
||
tabs: {
|
||
cp: [normalizeLevel(readParam('level')) || 1],
|
||
brother: [2, 2],
|
||
sister: [4, 5],
|
||
},
|
||
};
|
||
|
||
function readParam(name) {
|
||
var params = new URLSearchParams(window.location.search || '');
|
||
return params.get(name);
|
||
}
|
||
|
||
function normalizeTab(value) {
|
||
var tab = String(value || '')
|
||
.trim()
|
||
.toLowerCase();
|
||
return VALID_TABS.indexOf(tab) >= 0 ? tab : '';
|
||
}
|
||
|
||
function normalizeLevel(value) {
|
||
var level = Number(value);
|
||
return Number.isFinite(level) && level >= 1 && level <= 5
|
||
? Math.floor(level)
|
||
: 0;
|
||
}
|
||
|
||
function t(key, fallback) {
|
||
if (window.HyAppI18n && window.HyAppI18n.t) {
|
||
return window.HyAppI18n.t(key, fallback);
|
||
}
|
||
return fallback || key;
|
||
}
|
||
|
||
function escapeHTML(value) {
|
||
return String(value == null ? '' : value)
|
||
.replace(/&/g, '&')
|
||
.replace(/</g, '<')
|
||
.replace(/>/g, '>')
|
||
.replace(/"/g, '"')
|
||
.replace(/'/g, ''');
|
||
}
|
||
|
||
function setActiveTab(tab) {
|
||
var nextTab = normalizeTab(tab) || 'cp';
|
||
state.activeTab = nextTab;
|
||
page.setAttribute('data-tab', nextTab);
|
||
tabButtons.forEach(function (button) {
|
||
button.classList.toggle(
|
||
'is-active',
|
||
button.getAttribute('data-tab') === nextTab
|
||
);
|
||
});
|
||
render();
|
||
}
|
||
|
||
function cardHTML(level, index) {
|
||
var safeLevel = normalizeLevel(level) || 1;
|
||
var label = t('cpSpace.levelCard', 'Best friend level {level}').replace(
|
||
'{level}',
|
||
String(safeLevel)
|
||
);
|
||
|
||
return [
|
||
'<article class="relation-card" data-level="',
|
||
safeLevel,
|
||
'">',
|
||
'<img src="',
|
||
LEVEL_IMAGES[safeLevel],
|
||
'" alt="',
|
||
escapeHTML(label),
|
||
'" draggable="false" />',
|
||
'<button class="cancel-hotspot" type="button" data-cancel-index="',
|
||
index,
|
||
'" aria-label="',
|
||
escapeHTML(t('cpSpace.cancel', 'Cancel')),
|
||
'"></button>',
|
||
'</article>',
|
||
].join('');
|
||
}
|
||
|
||
function render() {
|
||
var levels = state.tabs[state.activeTab] || [];
|
||
if (!levels.length) {
|
||
contentPanel.innerHTML =
|
||
'<div class="empty-state">' +
|
||
escapeHTML(t('cpSpace.empty', 'No relationship data yet.')) +
|
||
'</div>';
|
||
return;
|
||
}
|
||
|
||
contentPanel.innerHTML =
|
||
'<div class="relation-list">' +
|
||
levels.map(cardHTML).join('') +
|
||
'</div>';
|
||
}
|
||
|
||
function applyExternalData(payload) {
|
||
var data = payload || {};
|
||
var nextTabs = {};
|
||
VALID_TABS.forEach(function (tab) {
|
||
var raw = data[tab];
|
||
if (!Array.isArray(raw)) return;
|
||
var normalized = raw
|
||
.map(function (item) {
|
||
return normalizeLevel(
|
||
typeof item === 'object' ? item.level : item
|
||
);
|
||
})
|
||
.filter(Boolean);
|
||
if (normalized.length) nextTabs[tab] = normalized;
|
||
});
|
||
|
||
// Flutter 可以在 WebView 注入 window.HyAppCPSpaceData 或派发 hyapp:cp-space-data;
|
||
// 页面只接受 1-5 的等级编号,避免 H5 自己猜测关系状态或渲染后端未确认的数据。
|
||
Object.keys(nextTabs).forEach(function (tab) {
|
||
state.tabs[tab] = nextTabs[tab];
|
||
});
|
||
if (normalizeTab(data.activeTab)) state.activeTab = data.activeTab;
|
||
setActiveTab(state.activeTab);
|
||
}
|
||
|
||
function handleCancel(index) {
|
||
var level = (state.tabs[state.activeTab] || [])[Number(index)] || 0;
|
||
if (window.HyAppBridge && window.HyAppBridge.post) {
|
||
window.HyAppBridge.post('cpSpaceCancel', {
|
||
relation_type: state.activeTab,
|
||
level: level,
|
||
});
|
||
}
|
||
}
|
||
|
||
function bindEvents() {
|
||
if (backButton) {
|
||
backButton.addEventListener('click', function () {
|
||
if (window.HyAppBridge && window.HyAppBridge.back) {
|
||
window.HyAppBridge.back();
|
||
return;
|
||
}
|
||
window.history.back();
|
||
});
|
||
}
|
||
|
||
tabButtons.forEach(function (button) {
|
||
button.addEventListener('click', function () {
|
||
setActiveTab(button.getAttribute('data-tab'));
|
||
});
|
||
});
|
||
|
||
contentPanel.addEventListener('click', function (event) {
|
||
var target = event.target.closest('[data-cancel-index]');
|
||
if (!target) return;
|
||
handleCancel(target.getAttribute('data-cancel-index'));
|
||
});
|
||
|
||
window.addEventListener('hyapp:cp-space-data', function (event) {
|
||
applyExternalData(event.detail || {});
|
||
});
|
||
|
||
window.addEventListener('hyapp:i18n-ready', render);
|
||
}
|
||
|
||
bindEvents();
|
||
if (window.HyAppCPSpaceData) applyExternalData(window.HyAppCPSpaceData);
|
||
else setActiveTab(state.activeTab);
|
||
|
||
if (window.HyAppBridge && window.HyAppBridge.ready) {
|
||
window.HyAppBridge.ready({ page: 'cp-space' });
|
||
}
|
||
})();
|