customer.js 11 KB

1234567891011121314151617181920212223242526272829303132333435363738394041
  1. register('customer', 'chat', 'H01', '咨询与人工协助', () => {
  2. const messages = state.messages.map(item => `<div class="message ${item.sender === '客户' ? 'customer' : ''}"><small>${escapeHtml(item.sender)}</small>${escapeHtml(item.text)}</div>`).join('');
  3. return mobile('咨询', `${!state.loggedIn ? hint(`登录后可以查询本人订单和发起售后。${link('进入登录', 'login')}`) : tag('客户 A01 · 已登录')}
  4. ${!state.connected ? hint(`连接已中断,输入内容保留。${button('重新连接', 'reconnect')}`) : ''}
  5. ${state.blocked ? hint(`助手暂时不可用,你可以查询已有工单或申请人工协助。${link('查看售后', 'ticket')}`) : ''}
  6. ${state.owner === 'HUMAN' ? hint('客服王芳正在为你服务。') : state.humanRequested ? hint('已申请人工协助,等待客服接管。你可以继续补充问题。') : tag('智能助手服务中')}
  7. ${state.aiContext ? box('正在咨询', `<p>${escapeHtml(state.aiContext)}</p>`) : ''}
  8. <div class="message"><small>AI 购物助手</small>你好,可以向我咨询商品使用、订单进度和售后规则。需要换货时,我会协助你确认订单和申请信息。</div>${messages}
  9. ${actions(`${link('选择订单', 'orders')}${button('申请人工协助', 'request-human', state.humanRequested || state.owner === 'HUMAN' ? 'disabled' : '')}`)}
  10. ${state.ticket !== 'NONE' ? box('当前售后', `${tag(statusLabels[state.ticket])}${actions(link('查看当前方案与进度', 'ticket'))}`) : ''}
  11. ${form('customer-message', area('补充问题', 'message', '', 'required maxlength="2000" placeholder="例如:收到的键盘空格键无法使用"'), '发送', !state.connected ? 'disabled' : '')}
  12. ${state.replyActive ? `${hint('助手正在查询,请稍候。')}${actions(button('停止本次回复', 'stop-answer'))}` : ''}`);
  13. }, ['入口来自商家店铺,客户身份和商家范围由登录结果确定。', '申请人工只登记服务请求;客服取得控制权后切换服务提示。', '断线恢复继续读取已有消息,不重复发送已受理内容。停止回复不会取消售后工单。']);
  14. register('customer', 'login', 'H02', '登录与身份确认', () => mobile('登录', `${hint('当前进入 A 商家配件店。账户仅用于本商家服务。')}${form('login', `${field('账户', 'account', 'A01', 'text', 'required autocomplete="username"')}${field('密码', 'password', '', 'password', 'required autocomplete="current-password" placeholder="线稿可填写任意内容,请勿输入真实密码"')}${consent('accept', '确认进入当前商家的客户服务')}`, '登录并返回咨询')}`), ['正式产品由身份服务验证账户;线稿只演示进入已登录状态。', '登录失效后保留当前页面入口,重新登录后返回原页面并重新检查权限。']);
  15. register('customer', 'orders', 'H03', '我的订单', () => mobile('我的订单', `<div class="tabs order-filters">${['全部', '待付款', '待发货', '待收货', '已完成'].map(label => `<button data-action="order-filter" data-filter="${label}" ${state.orderFilter === label ? 'aria-current="page"' : ''}>${label}</button>`).join('')}</div>${state.empty || !['全部', '已完成'].includes(state.orderFilter) ? '<div class="empty">暂无该状态的订单。</div>' : `<section class="order-card"><div class="section-heading"><strong>A 商家 · 配件店</strong><span>已签收</span></div><div class="order-product"><div class="goods-image">键盘</div><div><strong>办公键盘</strong><p>标准款 · 数量 1</p><p>订单 A-20260918-001</p></div></div><p class="muted">签收后第 2 天</p>${actions(`${link('查看订单', 'order')}${link('申请售后', 'apply')}${link('联系 AI 客服', 'chat')}`)}</section>`}`), ['订单采用状态标签和订单卡片结构。', '订单详情、申请售后、联系客服分别提供直接入口。']);
  16. register('customer', 'order', 'H04', '订单详情与申请条件', () => mobile('订单详情', `${box('订单信息', orderSummary())}${box('适用规则', `<p>《键盘换货规则》V${state.ruleVersion}</p><p>签收后 ${state.ruleDays} × 24 小时以内,包含时间边界;功能故障需填写描述。</p>${link('阅读规则原文', 'policy')}`)}${!state.ruleActive ? hint('当前订单不符合申请条件:适用规则已失效。可以申请人工协助核实。') : ''}${actions(`${link('填写换货申请', 'apply')}${button('申请人工协助', 'request-human')}`)}`), ['订单详情明确显示商品、可申请数量和规则依据。', '超过期限、未签收、数量不足或规则失效时,展示具体原因;提交时再次检查最新状态。']);
  17. register('customer', 'policy', 'H05', '规则依据', () => mobile('规则详情', `<h2>键盘换货规则 · V${state.ruleVersion}</h2>${tag(state.ruleActive ? '当前有效' : '已撤销')}<p>第一条:签收后 ${state.ruleDays} × 24 小时以内,键盘存在功能故障时可以申请换货。</p><p>第二条:申请数量需在可售后数量范围内,必须描述故障。</p><p>第三条:方案由客户确认,主管批准后提交履约系统。</p>${hint('规则内容为需求文档中的验收商家示例。')}${actions(link('返回订单', 'order'))}`), ['引用包含文档标题、版本和条款。', '规则撤销后,原方案需要重新核实适用条件。']);
  18. register('customer', 'apply', 'H06', '填写或修订换货申请', () => mobile('换货申请', `${box('已选择订单', orderSummary())}${state.ticket !== 'NONE' ? hint(`当前方案 V${state.version}。修订后需要重新确认,原确认与审批失效。`) : ''}${form('proposal', `${field('申请数量', 'quantity', state.quantity, 'number', 'min="1" max="1" required')}${area('故障描述', 'reason', state.reason, 'required maxlength="2000"')}`, canRevise() ? '保存新版本并检查' : '生成方案并检查', !canCreate() && !canRevise() ? 'disabled' : '')}`), ['数量为正整数且不超过可申请数量;故障描述必填。', '保存后进入确认页,不直接提交审批或创建外部申请。', '等待审批时修订会撤销当前审批资格,新版本重新确认。']);
  19. register('customer', 'proposal', 'H07', '检查并确认方案', () => mobile('方案确认', state.ticket === 'NONE' ? `${hint('请先选择订单并填写申请。')}${link('选择订单', 'orders')}` : `${box('请核对以下信息', proposalSummary())}${state.stale ? hint('此方案已有新版本,请刷新后重新检查。') : ''}${form('confirm-proposal', consent('confirmed', `我确认商品、数量、故障描述及方案 V${state.version},同意提交主管审批。`), '确认并提交审批', state.ticket !== 'DRAFT' || state.stale ? 'disabled' : '')}${actions(`${link('修改方案', 'apply')}${button('取消申请', 'cancel-ticket', canCancel() ? '' : 'disabled')}${state.stale ? button('读取最新方案', 'refresh-proposal') : ''}`)}`), ['只有客户可以确认;客服和主管查看确认记录。', '按钮绑定用户看到的方案版本,版本变化时必须重新检查。', '重复点击应返回同一确认结果和审批任务。']);
  20. register('customer', 'ticket', 'H08', '售后进度与取消', () => {
  21. if (state.ticket === 'NONE') return mobile('我的售后', `<div class="empty">当前没有售后申请。${actions(link('查看订单', 'orders'))}</div>`);
  22. const messages = {
  23. DRAFT: '请检查方案并确认,确认后交由主管审批。', WAITING_REVIEW: '主管正在审核,处理结果会显示在这里。',
  24. APPROVED: '审批通过,系统正在复核订单和规则。尚未提交外部申请时可以取消。',
  25. PROCESSING: '履约系统已受理换货,等待完成。', RESULT_UNKNOWN: '正在查询同一笔申请的受理结果。请继续等待,可申请人工协助。',
  26. COMPLETED: '履约系统已确认换货完成。', REJECTED: `审批未通过:${escapeHtml(state.formValues.approvalReason || '当前故障材料不足,请联系人工了解原因。')}`,
  27. NEEDS_REVISION: '适用条件已变化,请修订方案并重新确认。', CANCELLED: '本次申请已取消。', FAILED: '履约系统明确拒绝:当前库存不足。',
  28. };
  29. return mobile('售后 SH-001', `${tag(statusLabels[state.ticket])}${hint(messages[state.ticket])}${box('方案信息', proposalSummary())}<ol class="timeline"><li>方案 V${state.version} 已保存</li><li>${state.customerConfirmed ? '客户已确认当前版本' : '等待客户确认当前版本'}</li><li>${['APPROVED', 'PROCESSING', 'RESULT_UNKNOWN', 'COMPLETED'].includes(state.ticket) ? '主管已批准' : state.ticket === 'REJECTED' ? '主管已拒绝' : '主管审批'}</li><li>${state.ticket === 'COMPLETED' ? '履约完成' : '履约结果待确认'}</li></ol>${actions(`${state.ticket === 'DRAFT' ? link('检查并确认', 'proposal') : ''}${canRevise() ? link('修订方案', 'apply') : ''}${button('取消申请', 'cancel-ticket', canCancel() ? '' : 'disabled')}${button('申请人工协助', 'request-human')}`)}${!canCancel() ? '<p class="muted">当前状态不提供取消操作。已登记的外部申请继续跟踪。</p>' : ''}`);
  30. }, ['受理成功与履约完成分别显示。', '结果未知时保持原申请,禁止重复建单;展示持续核实与人工协助入口。', '取消需要再次确认;提交时根据最新状态判断,已经登记外部操作则保留跟踪。']);
  31. register('customer', 'memory', 'H09', '沟通习惯与账户', () => mobile('我的', `${box('账户', `<p>A01 · A 商家</p>${actions(`${link('渠道身份关联', 'identity')}${button('退出登录', 'logout')}`)}`)}${tag(state.memoryConsent ? '已授权保存沟通习惯' : '尚未授权')}<p>授权后仅保存回复方式、语言及联系方式。可以随时更正、清空或撤销授权。</p>${!state.memoryConsent ? button('授权保存', 'memory-consent') : form('memory', `${select('回复方式', 'style', ['简洁回复', '详细回复'], state.memoryStyle)}${select('回复语言', 'language', ['中文', 'English'], state.memoryLanguage)}`, '保存沟通习惯')}${state.memorySaved ? hint(`已保存:${escapeHtml(state.memoryStyle)} / ${escapeHtml(state.memoryLanguage)} / 文字沟通`) : hint('当前没有已保存的沟通习惯。')}${actions(`${button('清空已保存内容', 'memory-clear', state.memorySaved ? '' : 'disabled')}${button('撤销授权', 'memory-revoke', state.memoryConsent ? '' : 'disabled')}`)}<p class="muted">清空沟通习惯保留历史咨询记录。</p>`), ['授权默认关闭;清空内容与撤销授权是独立操作。', '所有变更由本人确认,删除后旧任务不能恢复已删除内容。']);
  32. register('customer', 'identity', 'H10', '关联渠道身份', () => mobile('身份关联', `${hint('关联后,可以在本商家的两个渠道查询本人同一工单。各渠道聊天记录独立。')}${tag(state.linked ? 'Webhook 渠道已关联' : '尚未关联')}<ol><li>确认当前 H5 登录身份 A01</li><li>在目标渠道完成一次身份验证</li><li>检查两个身份并确认关联</li></ol>${state.identityVerified ? box('已验证的身份', '<p>H5:A01</p><p>目标渠道:已通过渠道验证的账户</p>') : '<div class="placeholder">目标渠道验证入口<br>正式接入方式由渠道授权能力确定</div>'}${actions(`${button('演示目标渠道验证完成', 'identity-verify')}${button('确认关联', 'identity-link', !state.identityVerified || state.linked ? 'disabled' : '')}`)}`), ['这里表达双身份验证与确认步骤,具体渠道验证方式保留为接入条件。', '姓名、昵称及聊天里提供的手机号不作为关联依据。']);