/**
* Demo 数据层:统一加载 assets/mock.json
* 页面定义 window.renderPage(DB) 后由本文件回调渲染;
* 交互函数直接修改 DB 并调用对应 renderPage 重渲染。
* 交互产生的数据变更通过 localStorage 持久化,跨页面/刷新保留;
* mock.json 结构升级时提升 SCHEMA_VER 使旧存档失效。
*/
const SCHEMA_VER = 5;
const DB_KEY = 'opc_demo_db';
let DB = null;
/** 徽章 */
const B = (pair) => pair ? `${pair[0]}` : '—';
/** 进度条 */
const BAR = (w, cls = '') => `
`;
/** 步骤条 */
const STEPS = (steps) => `` + steps
.map((s, i) => `${i ? '→' : ''}${s[0]}`)
.join('') + `
`;
/** 标签 */
const TAG = (t) => `${t}`;
/** 列表行(key-value) */
const LI = (l, r) => `${l}${r}`;
/** 将当前 DB 持久化到 localStorage */
function saveDB() {
if (!DB) return;
try {
localStorage.setItem(DB_KEY, JSON.stringify({ v: SCHEMA_VER, data: DB }));
} catch (e) { /* 存储满或隐私模式下静默降级 */ }
}
/** 清除演示存档,恢复 mock.json 初始数据 */
function resetDemo() {
localStorage.removeItem(DB_KEY);
location.reload();
}
async function loadMock() {
let fresh = {};
try {
const res = await fetch('assets/mock.json');
fresh = await res.json();
} catch (e) {
console.error('mock.json 加载失败(请通过 http 服务访问,勿用 file:// 直开)', e);
}
let saved = null;
try {
const raw = localStorage.getItem(DB_KEY);
if (raw) {
const pack = JSON.parse(raw);
if (pack.v === SCHEMA_VER) saved = pack.data;
}
} catch (e) { /* 存档损坏时回退到初始数据 */ }
// 存档优先,但用 fresh 补齐新增加的业务域
DB = saved ? Object.assign({}, fresh, saved) : fresh;
window.addEventListener('beforeunload', saveDB);
if (typeof window.renderPage === 'function') window.renderPage(DB);
}
document.addEventListener('DOMContentLoaded', loadMock);