| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061 |
- /* 评审数据只存在页面内存中;角色切换用于检查同一业务的交互,不提供实际授权。 */
- const initialState = () => ({
- loggedIn: false, ticket: 'NONE', version: 1, reason: '键盘空格键无法使用', quantity: 1,
- owner: 'AGENT', humanRequested: false, connected: true, blocked: false, empty: false, replyActive: false,
- stale: false, expired: false, selfApproval: false, customerConfirmed: false,
- memoryConsent: false, memorySaved: false, memoryStyle: '简洁回复', memoryLanguage: '中文',
- linked: false, identityVerified: false, ruleVersion: 1, ruleActive: true, ruleSaved: false,
- proposalRuleVersion: 1, ruleDays: 7, proposalRuleDays: 7,
- knowledge: 'DRAFT', knowledgeTitle: '键盘售后说明', knowledgeVersion: 1,
- staffEnabled: true, storeEnabled: true, channelEnabled: true, tenantEnabled: true,
- delivery: 'FAILED', budgetRequest: 'NONE', budget: 100, pendingBudget: 100,
- messages: [], audit: [], lastAction: '', release: '草稿', formValues: {},
- invites: [], tenantRegistrations: [], billingReviewer: false, returnPage: 'home', orderFilter: '全部', aiContext: '',
- });
- let state = initialState();
- let currentRole = 'customer';
- let merchantRole = 'merchant';
- const adminAuth = { merchant: false, platform: false };
- const adminReturn = { merchant: null, platform: null };
- let currentPage = 'home';
- let notice = '';
- let pendingConfirmation = null;
- const screens = {};
- const roleLabels = { customer: '购物商城 H5', staff: '商家后台', supervisor: '商家后台', merchant: '商家后台', platform: '平台后台' };
- const statusLabels = { NONE: '尚未申请', DRAFT: '待客户确认', WAITING_REVIEW: '等待主管审批', APPROVED: '审批通过,准备提交', PROCESSING: '换货处理中', RESULT_UNKNOWN: '正在核实受理结果', COMPLETED: '换货完成', REJECTED: '审批未通过', NEEDS_REVISION: '需要修订方案', CANCELLED: '申请已取消', FAILED: '换货申请失败' };
- const escapeHtml = value => String(value ?? '').replace(/[&<>"']/g, char => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[char]));
- const button = (label, action, extra = '') => `<button type="button" data-action="${action}" ${extra}>${label}</button>`;
- const link = (label, page, role = currentRole) => {
- const restricted = ['merchant', 'staff', 'supervisor'].includes(role) && role !== merchantRole;
- return `<button type="button" data-page="${page}" data-role="${role}" ${restricted ? 'disabled title="当前员工未获该功能权限"' : ''}>${label}</button>`;
- };
- const tag = text => `<span class="tag">${escapeHtml(text)}</span>`;
- const hint = text => `<div class="hint">${text}</div>`;
- const box = (title, content) => `<section class="box"><h3>${title}</h3>${content}</section>`;
- const table = (headers, rows) => `<div class="table-wrap"><table><thead><tr>${headers.map(h => `<th scope="col">${h}</th>`).join('')}</tr></thead><tbody>${rows.map(row => `<tr>${row.map(cell => `<td>${cell}</td>`).join('')}</tr>`).join('')}</tbody></table></div>`;
- const field = (label, name, value = '', type = 'text', extra = '') => `<label>${label}<input name="${name}" type="${type}" value="${escapeHtml(value)}" ${extra}></label>`;
- const area = (label, name, value = '', extra = '') => `<label>${label}<textarea name="${name}" ${extra}>${escapeHtml(value)}</textarea></label>`;
- const select = (label, name, options, value) => `<label>${label}<select name="${name}">${options.map(option => `<option${option === value ? ' selected' : ''}>${escapeHtml(option)}</option>`).join('')}</select></label>`;
- const actions = content => `<div class="actions">${content}</div>`;
- const form = (action, content, label = '保存', extra = '') => `<form data-submit="${action}">${content}<button class="primary" type="submit" ${extra}>${label}</button></form>`;
- const consent = (name, label) => `<label class="check"><input type="checkbox" name="${name}" required><span>${label}</span></label>`;
- const canCancel = () => ['DRAFT', 'WAITING_REVIEW', 'APPROVED'].includes(state.ticket);
- const canRevise = () => ['DRAFT', 'WAITING_REVIEW', 'NEEDS_REVISION'].includes(state.ticket);
- const canCreate = () => ['NONE', 'CANCELLED', 'REJECTED', 'FAILED'].includes(state.ticket);
- function register(role, page, code, title, render, notes) { screens[`${role}/${page}`] = { role, page, code, title, render, notes }; }
- function mobile(title, content) {
- const root = ['home', 'categories', 'cart', 'profile'].includes(currentPage);
- const tabs = [['home', '首页'], ['categories', '分类'], ['cart', '购物车'], ['profile', '我的']];
- return `<div class="surface mobile"><div class="device-status"><span>9:41</span><span>网络 电量</span></div><header class="mobile-header">${root ? '<strong>智选商城</strong>' : link('返回', currentPage === 'chat' ? 'home' : 'profile', 'customer')}<strong>${title}</strong>${link(currentPage === 'chat' ? '我的订单' : '消息', currentPage === 'chat' ? 'orders' : 'messages', 'customer')}</header><div class="content">${content}</div>${root ? `<footer class="shop-tabs">${tabs.map(([page, label]) => `<button type="button" data-page="${page}" data-role="customer" ${page === currentPage ? 'aria-current="page"' : ''}>${label}</button>`).join('')}</footer>` : ''}${currentPage !== 'chat' && currentPage !== 'login' ? '<button type="button" class="ai-float" data-page="chat" data-role="customer"><strong>AI</strong><span>购物助手</span></button>' : ''}</div>`;
- }
- function desktop(content) { return adminShell(content); }
- function orderSummary() { return `<p>订单 A-20260918-001</p><p>键盘 × 1 · 签收后第 2 天</p><p>可申请数量:1</p>`; }
- function proposalSummary() { return `${orderSummary()}<p>申请数量:${state.quantity}</p><p>故障描述:${escapeHtml(state.reason)}</p><p>方案版本:V${state.version}</p><p>依据:《键盘换货规则》V${state.proposalRuleVersion},签收后 ${state.proposalRuleDays} 天内功能故障可申请,需客户确认及主管审批。</p>`; }
- function ticketSummary() { return `${tag(statusLabels[state.ticket])}<p>工单 SH-001 · 当前方案 V${state.version}</p>${proposalSummary()}`; }
- function record(text) { state.audit.unshift(text); state.lastAction = text; }
- function confirmAction(title, body, callback) {
- pendingConfirmation = callback;
- document.getElementById('dialog-title').textContent = title;
- document.getElementById('dialog-body').textContent = body;
- document.getElementById('confirm-dialog').showModal();
- }
|