docs(design): 移动原型 设备/设置/授权管理/关于 四屏对齐桌面能力

- m-devices:补 登录设备管理 卡片流(用户/平台/IP/最近活跃 + 本机标识 + 详情
  sheet 强制下线);外设卡补 连接方式/最近活动 + 测试/配置/解绑;添加设备入口
  移至区块行(无 FAB),sheet 表单登记;打印模板区块按拍板裁剪
- m-settings:hub 升级为真实 5 面板——门店信息 sheet 表单 / 用户与角色 /
  编号规则(新)/ 授权管理(改词+二级视图)/ 偏好(主题+默认仓库,打印偏好删)
- 授权管理二级视图:授权信息三行 + 在线购买卡(特惠/标准/高级 tab、年付省2月
  划线原价与省钱行、支付宝支付 → waiting → success 三阶段)+ 兑换券 + 降级规则,
  对齐 settings_screen 四卡与 purchase_card 三阶段
- m-about:hero 下补 官网/微信客服/隐私政策/服务条款 链接组;反馈升级为
  sheet 表单(类型 chip+描述+联系方式);页脚 © + 京ICP备2026039814号;
  授权信息块删除(随真相源迁设置);版本示例 v1.1.3
- CONTRACT 增「移动愿景原型」小节:m-* 为移动目标设计(tab+我的),与 Flutter
  当前响应式复用为有意愿景超前;登记已对齐屏与「移动无建单/无打印」裁剪口径

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JJ1g8XV1YhhmHRzhwWEW7o
This commit is contained in:
wangjia
2026-07-04 10:35:27 +08:00
parent f3cfdcadca
commit 781e2c5e2d
4 changed files with 194 additions and 36 deletions
+20 -8
View File
@@ -37,9 +37,16 @@
<div class="ab-hero">
<div class="ab-ico"><svg viewBox="0 0 64 64"><g stroke="#fff" stroke-width="5" stroke-linecap="round" stroke-linejoin="round" fill="none"><path d="M14 33L23 16L32 25L41 16L50 33"/><path d="M15 41L49 41"/></g><circle cx="32" cy="48" r="3.4" fill="#C97B86"/></svg></div>
<div class="ab-nm">岩美酒库</div>
<div class="ab-ver">v1.0.72 · 酒水进销存管理系统</div>
<div class="ab-ver">v1.1.3 · 酒水进销存管理系统</div>
<div style="margin-top:10px"><div class="btn ghost sm" onclick="mToast('已是最新版本 ✓')"><svg viewBox="0 0 24 24"><use href="#i-refresh"/></svg>检查更新</div></div>
<div class="ab-btns"><div class="btn primary" style="flex:1; justify-content:center" onclick="mToast('感谢反馈,我们会尽快跟进 ✓')"><svg viewBox="0 0 24 24"><use href="#i-bug"/></svg>反馈 Bug</div><div class="btn ghost" style="flex:1; justify-content:center" onclick="mToast('感谢建议,我们会认真考虑 ✓')"><svg viewBox="0 0 24 24"><use href="#i-lightbulb"/></svg>功能建议</div></div>
<div class="ab-btns"><div class="btn primary" style="flex:1; justify-content:center" onclick="openFb('Bug')"><svg viewBox="0 0 24 24"><use href="#i-bug"/></svg>反馈 Bug</div><div class="btn ghost" style="flex:1; justify-content:center" onclick="openFb('功能建议')"><svg viewBox="0 0 24 24"><use href="#i-lightbulb"/></svg>功能建议</div></div>
</div>
<div class="m-hub" style="margin-top:10px">
<a onclick="mToast('打开官网 jiu.51yanmei.com(原型)')"><span class="hic"><svg viewBox="0 0 24 24"><use href="#i-ic01"/></svg></span>官方网站<span class="hchev"><svg viewBox="0 0 24 24"><use href="#i-chevron-right"/></svg></span></a>
<a onclick="mToast('微信客服 yammy2023(原型)')"><span class="hic"><svg viewBox="0 0 24 24"><use href="#i-ic02"/></svg></span>微信客服<span class="hchev"><svg viewBox="0 0 24 24"><use href="#i-chevron-right"/></svg></span></a>
<a onclick="mToast('隐私政策(原型)')"><span class="hic"><svg viewBox="0 0 24 24"><use href="#i-shield-2"/></svg></span>隐私政策<span class="hchev"><svg viewBox="0 0 24 24"><use href="#i-chevron-right"/></svg></span></a>
<a onclick="mToast('服务条款(原型)')"><span class="hic"><svg viewBox="0 0 24 24"><use href="#i-ic06"/></svg></span>服务条款<span class="hchev"><svg viewBox="0 0 24 24"><use href="#i-chevron-right"/></svg></span></a>
</div>
<div class="m-section">产品信息</div>
@@ -49,15 +56,12 @@
<div class="drow" style="border-bottom:none"><span>产品定位</span><b style="text-align:right">酒水进销存 / 财务 / 防伪溯源</b></div>
</div></div>
<div class="m-section">授权信息</div>
<div class="pe-card"><div class="pe-b" style="padding-top:2px;padding-bottom:2px">
<div class="drow"><span>授权状态</span><b><span class="badge b-在售">已授权</span></b></div>
<div class="drow"><span>到期日</span><b style="font-family:var(--font-mono)">2027-03-15</b></div>
<div class="drow" style="border-bottom:none"><span>剩余天数</span><b>267 天</b></div>
</div></div>
<!-- 授权信息已迁至 设置 → 授权管理(对齐 Flutter 2026-07-04 -->
<div class="m-section">更新日志</div>
<div class="pe-card" style="padding:14px"><div class="tl" id="tl"></div></div>
<div style="text-align:center;font-size:var(--fs-xs);color:var(--faint);padding:18px 0 6px">© 2026 岩美科技 · 保留所有权利 · <a style="color:var(--faint);text-decoration:underline;text-underline-offset:2px;cursor:pointer" onclick="mToast('跳转 beian.miit.gov.cn(原型)')">京ICP备2026039814号</a></div>
</div>
</div>
<div class="toast" id="toast"></div>
@@ -84,6 +88,14 @@ const CHANGELOG=[
]},
];
const tagCls={feat:'tlt-feat',impr:'tlt-impr',fix:'tlt-fix'};
let fbType='Bug';
function openFb(t){ fbType=t; drawFb(); }
function drawFb(){
openSheet('意见反馈', `<div class="m-field"><label>反馈类型</label><div style="display:flex;gap:8px">${['Bug','功能建议','其他'].map(v=>`<div class="m-pill ${fbType===v?'on':''}" onclick="fbType='${v}';drawFb()">${v}</div>`).join('')}</div></div>
<div class="m-field"><label>问题描述</label><textarea class="m-input" placeholder="请描述遇到的问题或建议…"></textarea></div>
<div class="m-field"><label>联系方式(选填)</label><input class="m-input" placeholder="微信 / 手机号,便于我们回访"></div>
<div style="display:flex;gap:10px;margin-top:16px"><div class="btn ghost" style="flex:1;justify-content:center" onclick="closeSheet()">取消</div><div class="btn primary" style="flex:2;justify-content:center" onclick="mToast('感谢反馈,我们会尽快跟进 ✓');closeSheet()">提交</div></div>`);
}
document.getElementById('tl').innerHTML=CHANGELOG.map(v=>`<div class="tl-item"><div class="tl-v">${v.ver}<small>${v.date}</small></div>${v.groups.map(g=>`<div class="tl-grp"><span class="tlt ${tagCls[g.tag]}">${g.label}</span><ul class="tl-ul">${g.items.map(it=>`<li>${it}</li>`).join('')}</ul></div>`).join('')}</div>`).join('');
</script>
</body>
+47 -13
View File
@@ -11,31 +11,65 @@
</head>
<body>
<div class="m-top" data-m-top data-back data-title="设备管理"></div>
<div class="m-page" style="padding-bottom:84px">
<div class="m-page">
<div class="m-scroll">
<div class="m-section">已连接设备</div>
<div class="m-section">登录设备管理</div>
<div id="sessions"></div>
<div class="m-section" style="display:flex;align-items:center">外设设备<a style="margin-left:auto;color:var(--primary);font-weight:600;cursor:pointer" onclick="openAdd()">+ 添加设备</a></div>
<div id="list"></div>
</div>
</div>
<div class="m-fab" onclick="mToast('添加设备(原型)')"><svg viewBox="0 0 24 24"><use href="#i-plus"/></svg></div>
<div class="toast" id="toast"></div>
<script src="icons.js"></script>
<script src="mobile-shell.js"></script>
<script>
const DEV=[
{name:'热敏标签打印机',model:'佳博 GP-1124T',type:'打印机',status:'在线'},
{name:'单据针式打印机',model:'爱普生 LQ-630K',type:'打印机',status:'在线'},
{name:'蓝牙扫码枪',model:'新大陆 NLS-BS80',type:'扫码枪',status:'离线'},
/* 登录会话(对齐桌面 device_management:用户/平台/设备/IP/最近活跃 + 强制下线) */
const SESSIONS=[
{user:'王经理',role:'管理员',platform:'macOS',device:'MacBook Pro',ip:'192.168.3.66',last:'刚刚',online:true,current:true},
{user:'王经理',role:'管理员',platform:'iOS',device:'iPhone 16 Pro Max',ip:'192.168.3.88',last:'5 分钟前',online:true},
{user:'李采购',role:'操作员',platform:'Windows',device:'DESKTOP-8FK2',ip:'192.168.3.102',last:'2 小时前',online:true},
{user:'张主管',role:'管理员',platform:'Android',device:'Xiaomi 15',ip:'10.12.8.31',last:'昨天 18:42',online:false},
];
document.getElementById('list').innerHTML=DEV.map(d=>`<div class="m-card" onclick="openD('${d.name}')"><div class="m-row">
<div class="mc-main"><div class="mc-nm">${d.name}</div><div class="mc-sub">${d.model} · ${d.type}</div></div>
<div class="mc-right"><span class="badge b-${d.status}">${d.status}</span></div>
document.getElementById('sessions').innerHTML=SESSIONS.map((s,i)=>`<div class="m-card" onclick="openS(${i})"><div class="m-row">
<div class="mc-main"><div class="mc-nm">${s.user} · ${s.platform}${s.current?' <span style="color:var(--primary);font-size:var(--fs-xs);font-weight:600">本机</span>':''}</div><div class="mc-sub">${s.device} · ${s.ip}</div></div>
<div class="mc-right"><span class="badge b-${s.online?'在线':'离线'}">${s.online?'在线':'离线'}</span><span style="font-size:var(--fs-xs);color:var(--faint)">${s.last}</span></div>
<div class="mc-chev"><svg viewBox="0 0 24 24"><use href="#i-chevron-right"/></svg></div>
</div></div>`).join('');
function openD(n){ const d=DEV.find(x=>x.name===n);
openSheet(d.name, `<div class="drow"><span>型号</span><b>${d.model}</b></div><div class="drow"><span>类型</span><b>${d.type}</b></div><div class="drow" style="border-bottom:none"><span>状态</span><b><span class="badge b-${d.status}">${d.status}</span></b></div>
<div style="display:flex;gap:10px;margin-top:16px"><div class="btn ghost" style="flex:1;justify-content:center" onclick="mToast('测试打印(原型)')">测试</div><div class="btn primary" style="flex:1;justify-content:center" onclick="mToast('重新连接(原型)');closeSheet()">重新连接</div></div>`);
function openS(i){ const s=SESSIONS[i];
openSheet(`${s.user} · ${s.platform}`, `<div class="drow"><span>用户</span><b>${s.user}${s.role}</b></div><div class="drow"><span>设备</span><b>${s.device}</b></div><div class="drow"><span>IP 地址</span><b style="font-family:var(--font-mono)">${s.ip}</b></div><div class="drow"><span>最近活跃</span><b>${s.last}</b></div><div class="drow" style="border-bottom:none"><span>状态</span><b><span class="badge b-${s.online?'在线':'离线'}">${s.online?'在线':'离线'}</span>${s.current?' <span style="color:var(--primary);font-size:var(--fs-xs);font-weight:600">本机会话</span>':''}</b></div>
<div style="display:flex;gap:10px;margin-top:16px">${s.current?'<div class="btn ghost" style="flex:1;justify-content:center" onclick="closeSheet()">关闭</div>':`<div class="btn ghost" style="flex:1;justify-content:center" onclick="closeSheet()">关闭</div><div class="btn danger" style="flex:1;justify-content:center" onclick="mToast('已强制下线该会话');closeSheet()">强制下线</div>`}</div>`);
}
/* 外设(对齐桌面 dev-grid:连接方式/最近活动 + 测试/配置/解绑;打印模板不进移动端) */
const DEV=[
{name:'热敏标签打印机',model:'佳博 GP-1124T',type:'打印机',conn:'USB',last:'今天 10:24 测试打印',status:'在线'},
{name:'单据针式打印机',model:'爱普生 LQ-630K',type:'打印机',conn:'网络 192.168.3.201',last:'昨天 17:05 出库单据',status:'在线'},
{name:'蓝牙扫码枪',model:'新大陆 NLS-BS80',type:'扫码枪',conn:'蓝牙',last:'06-20 盘点扫码',status:'离线'},
];
document.getElementById('list').innerHTML=DEV.map(d=>`<div class="m-card" onclick="openD('${d.name}')"><div class="m-row">
<div class="mc-main"><div class="mc-nm">${d.name}</div><div class="mc-sub">${d.model} · ${d.type} · ${d.conn}</div></div>
<div class="mc-right"><span class="badge b-${d.status}">${d.status}</span></div>
<div class="mc-chev"><svg viewBox="0 0 24 24"><use href="#i-chevron-right"/></svg></div>
</div>
<div class="mc-foot"><svg width="13" height="13" viewBox="0 0 24 24" stroke-width="1.9" style="color:var(--muted)"><use href="#i-info"/></svg>最近活动 ${d.last}</div></div>`).join('');
function openD(n){ const d=DEV.find(x=>x.name===n);
openSheet(d.name, `<div class="drow"><span>型号</span><b>${d.model}</b></div><div class="drow"><span>类型</span><b>${d.type}</b></div><div class="drow"><span>连接方式</span><b>${d.conn}</b></div><div class="drow"><span>最近活动</span><b>${d.last}</b></div><div class="drow" style="border-bottom:none"><span>状态</span><b><span class="badge b-${d.status}">${d.status}</span></b></div>
<div style="display:flex;gap:10px;margin-top:16px"><div class="btn ghost" style="flex:1;justify-content:center" onclick="mToast('测试指令已发送(原型)')">测试</div><div class="btn ghost" style="flex:1;justify-content:center" onclick="mToast('配置(原型)')">配置</div><div class="btn danger" style="flex:1;justify-content:center" onclick="mToast('已解绑该设备');closeSheet()">解绑</div></div>`);
}
/* 添加设备(对齐桌面 modal:类型/连接方式/名称/型号) */
let addSel={type:'打印机',conn:'USB'};
function addSelect(key,label,opts){
return `<div class="m-field"><label>${label}</label><div style="display:flex;gap:8px;flex-wrap:wrap">${opts.map(v=>`<div class="m-pill ${addSel[key]===v?'on':''}" onclick="addSel.${key}='${v}';drawAdd()">${v}</div>`).join('')}</div></div>`;
}
function drawAdd(){
openSheet('添加设备', addSelect('type','设备类型',['打印机','扫码枪','电子秤','钱箱'])
+addSelect('conn','连接方式',['USB','蓝牙','网络'])
+`<div class="m-field"><label>设备名称</label><input class="m-input" placeholder="如:吧台标签机"></div>
<div class="m-field"><label>品牌型号</label><input class="m-input" placeholder="如:佳博 GP-1124T"></div>
<div style="display:flex;gap:10px;margin-top:16px"><div class="btn ghost" style="flex:1;justify-content:center" onclick="closeSheet()">取消</div><div class="btn primary" style="flex:2;justify-content:center" onclick="mToast('设备已登记 ✓');closeSheet()">保存</div></div>`);
}
function openAdd(){ addSel={type:'打印机',conn:'USB'}; drawAdd(); }
</script>
</body>
</html>
+123 -15
View File
@@ -13,27 +13,135 @@
<div class="m-top" data-m-top data-back data-title="系统设置"></div>
<div class="m-page">
<div class="m-scroll">
<div class="m-section">门店</div>
<div class="m-hub">
<a onclick="mToast('门店信息(原型)')"><span class="hic"><svg viewBox="0 0 24 24"><use href="#i-ic57"/></svg></span>门店信息<span class="hchev"><svg viewBox="0 0 24 24"><use href="#i-chevron-right"/></svg></span></a>
<a href="m-users.html"><span class="hic"><svg viewBox="0 0 24 24"><use href="#i-ic45"/></svg></span>用户与角色<span class="hchev"><svg viewBox="0 0 24 24"><use href="#i-chevron-right"/></svg></span></a>
<a onclick="mToast('授权兑换券(原型)')"><span class="hic"><svg viewBox="0 0 24 24"><use href="#i-ic07"/></svg></span>授权兑换券<span class="hchev"><svg viewBox="0 0 24 24"><use href="#i-chevron-right"/></svg></span></a>
<!-- ============ 主视图:设置 hub ============ -->
<div id="vHub">
<div class="m-section">门店</div>
<div class="m-hub">
<a onclick="openShopSheet()"><span class="hic"><svg viewBox="0 0 24 24"><use href="#i-ic57"/></svg></span>门店信息<span class="hchev"><svg viewBox="0 0 24 24"><use href="#i-chevron-right"/></svg></span></a>
<a href="m-users.html"><span class="hic"><svg viewBox="0 0 24 24"><use href="#i-ic45"/></svg></span>用户与角色<span class="hchev"><svg viewBox="0 0 24 24"><use href="#i-chevron-right"/></svg></span></a>
<a onclick="openRulesSheet()"><span class="hic"><svg viewBox="0 0 24 24"><use href="#i-ic36"/></svg></span>编号规则<span class="hchev"><svg viewBox="0 0 24 24"><use href="#i-chevron-right"/></svg></span></a>
<a onclick="showLic()"><span class="hic"><svg viewBox="0 0 24 24"><use href="#i-ic07"/></svg></span>授权管理<span class="hchev"><svg viewBox="0 0 24 24"><use href="#i-chevron-right"/></svg></span></a>
</div>
<div class="m-section">偏好</div>
<div class="m-hub">
<a onclick="openThemeSheet()"><span class="hic"><svg viewBox="0 0 24 24"><use href="#i-shirt"/></svg></span>主题外观<span class="hchev"><svg viewBox="0 0 24 24"><use href="#i-chevron-right"/></svg></span></a>
<a onclick="openWhSheet()"><span class="hic"><svg viewBox="0 0 24 24"><use href="#i-ic05"/></svg></span>默认仓库<span class="hchev"><svg viewBox="0 0 24 24"><use href="#i-chevron-right"/></svg></span></a>
<a href="m-devices.html"><span class="hic"><svg viewBox="0 0 24 24"><use href="#i-ic63"/></svg></span>设备管理<span class="hchev"><svg viewBox="0 0 24 24"><use href="#i-chevron-right"/></svg></span></a>
</div>
<div class="m-section">数据</div>
<div class="m-hub">
<a onclick="mToast('数据备份(原型)')"><span class="hic"><svg viewBox="0 0 24 24"><use href="#i-cloud"/></svg></span>数据备份<span class="hchev"><svg viewBox="0 0 24 24"><use href="#i-chevron-right"/></svg></span></a>
<a href="m-about.html"><span class="hic"><svg viewBox="0 0 24 24"><use href="#i-info"/></svg></span>关于与版本<span class="hchev"><svg viewBox="0 0 24 24"><use href="#i-chevron-right"/></svg></span></a>
</div>
</div>
<div class="m-section">偏好</div>
<div class="m-hub">
<a onclick="openThemeSheet()"><span class="hic"><svg viewBox="0 0 24 24"><use href="#i-shirt"/></svg></span>主题外观<span class="hchev"><svg viewBox="0 0 24 24"><use href="#i-chevron-right"/></svg></span></a>
<a onclick="mToast('打印偏好(原型)')"><span class="hic"><svg viewBox="0 0 24 24"><use href="#i-ic49"/></svg></span>打印偏好<span class="hchev"><svg viewBox="0 0 24 24"><use href="#i-chevron-right"/></svg></span></a>
<a href="m-devices.html"><span class="hic"><svg viewBox="0 0 24 24"><use href="#i-ic63"/></svg></span>设备管理<span class="hchev"><svg viewBox="0 0 24 24"><use href="#i-chevron-right"/></svg></span></a>
</div>
<div class="m-section">数据</div>
<div class="m-hub">
<a onclick="mToast('数据备份(原型)')"><span class="hic"><svg viewBox="0 0 24 24"><use href="#i-cloud"/></svg></span>数据备份<span class="hchev"><svg viewBox="0 0 24 24"><use href="#i-chevron-right"/></svg></span></a>
<a href="m-about.html"><span class="hic"><svg viewBox="0 0 24 24"><use href="#i-ic24"/></svg></span>关于与版本<span class="hchev"><svg viewBox="0 0 24 24"><use href="#i-chevron-right"/></svg></span></a>
<!-- ============ 二级视图:授权管理(对齐桌面 授权信息/在线购买/兑换券/降级规则 四卡) ============ -->
<div id="vLic" style="display:none">
<div class="m-section" style="display:flex;align-items:center">授权管理<a style="margin-left:auto;color:var(--primary);font-weight:600;cursor:pointer" onclick="showHub()"> 返回设置</a></div>
<div class="pe-card"><div class="pe-b" style="padding-top:2px;padding-bottom:2px">
<div class="drow"><span>授权状态</span><b><span class="badge b-已通过">已授权</span></b></div>
<div class="drow"><span>到期日</span><b style="font-family:var(--font-mono)">2027-03-15</b></div>
<div class="drow" style="border-bottom:none"><span>剩余天数</span><b>267 天</b></div>
</div></div>
<div style="font-size:var(--fs-xs);color:var(--faint);margin:6px 2px 0">续期时长在现有到期时间上叠加,不会浪费剩余天数</div>
<div class="m-section">在线购买 / 续费</div>
<div class="pe-card" style="padding:14px" id="buyCard"></div>
<div class="m-section">兑换券</div>
<div class="pe-card" style="padding:14px">
<div class="m-field" style="margin-bottom:10px"><label>兑换券短码</label><input class="m-input" placeholder="如 8K3F-Q9ZT-27MB" style="font-family:var(--font-mono)"></div>
<div class="btn primary" style="justify-content:center" onclick="mToast('兑换成功,授权已续期 ✓')">兑换续期</div>
</div>
<div class="m-section">到期后的降级规则</div>
<div class="pe-card"><div class="pe-b" style="padding-top:2px;padding-bottom:2px">
<div class="drow"><span>查看数据</span><b style="color:var(--success)">保留,可继续查询导出</b></div>
<div class="drow"><span>入库 / 出库 / 审核</span><b style="color:var(--warn)">停用,续期后恢复</b></div>
<div class="drow"><span>新增用户 / 设备</span><b style="color:var(--warn)">停用</b></div>
<div class="drow" style="border-bottom:none"><span>数据安全</span><b style="color:var(--success)">云端保留 180 天</b></div>
</div></div>
</div>
</div>
</div>
<div class="toast" id="toast"></div>
<script src="icons.js"></script>
<script src="mobile-shell.js"></script>
<script>
function showLic(){ document.getElementById('vHub').style.display='none'; document.getElementById('vLic').style.display=''; drawBuy(); }
function showHub(){ document.getElementById('vLic').style.display='none'; document.getElementById('vHub').style.display=''; }
/* ---- 门店信息(对齐桌面 settings 门店面板:名称/编号只读/电话/微信/地址) ---- */
function openShopSheet(){
openSheet('门店信息', `<div class="m-field"><label>门店名称</label><input class="m-input" value="山城酒业连锁 · 解放碑店"></div>
<div class="m-field"><label>门店编号(不可改)</label><input class="m-input" value="S001" disabled style="color:var(--faint)"></div>
<div class="m-field"><label>联系电话</label><input class="m-input" value="023-6337-8899"></div>
<div class="m-field"><label>微信</label><input class="m-input" value="yammy2023"></div>
<div class="m-field"><label>门店地址</label><input class="m-input" value="重庆市渝中区民族路 188 号"></div>
<div style="display:flex;gap:10px;margin-top:16px"><div class="btn ghost" style="flex:1;justify-content:center" onclick="closeSheet()">取消</div><div class="btn primary" style="flex:2;justify-content:center" onclick="mToast('门店信息已保存 ✓');closeSheet()">保存</div></div>`);
}
/* ---- 编号规则(app 专属面板,展示型) ---- */
function openRulesSheet(){
openSheet('编号规则', `<div class="notice info" style="margin-bottom:14px"><svg viewBox="0 0 24 24"><use href="#i-info"/></svg><div>单据编号自动生成,规则全店统一;序号每日从 1 递增。</div></div>
<div class="drow"><span>入库单</span><b style="font-family:var(--font-mono)">RK-{年月日}-{序号}</b></div>
<div class="drow"><span>出库单</span><b style="font-family:var(--font-mono)">CK-{年月日}-{序号}</b></div>
<div class="drow"><span>盘点单</span><b style="font-family:var(--font-mono)">PD-{年月日}-{序号}</b></div>
<div class="drow" style="border-bottom:none"><span>商品编号</span><b style="font-family:var(--font-mono)">P{五位递增}</b></div>
<div style="display:flex;gap:10px;margin-top:16px"><div class="btn ghost" style="flex:1;justify-content:center" onclick="closeSheet()">关闭</div></div>`);
}
/* ---- 默认仓库 ---- */
let wh='主仓';
function openWhSheet(){
openSheet('默认仓库', ['主仓','名酒仓','一号仓'].map(v=>`<div class="m-opt ${v===wh?'sel':''}" onclick="wh='${v}';mToast('默认仓库:'+wh+' ✓');closeSheet()">${v}<svg class="ck" viewBox="0 0 24 24"><use href="#i-check"/></svg></div>`).join(''));
}
/* ==================== 在线购买卡(对齐 purchase_card.dart 三阶段) ==================== */
const PLANS={
promo:{name:'首月特惠',price:1,days:'30 天标准版全部功能',note:'新店专享 · 每店限购一次'},
standard:{name:'标准版',monthly:299,annual:2999},
pro:{name:'高级版',monthly:599,annual:5999},
};
const buy={tab:'promo',cycle:'annual',phase:'pick',promoUsed:false};
function fmt(n){ return n.toLocaleString(); }
function drawBuy(){
const el=document.getElementById('buyCard');
if(buy.phase==='waiting'){
el.innerHTML=`<div class="notice info" style="margin-bottom:14px"><svg viewBox="0 0 24 24"><use href="#i-info"/></svg><div>已拉起支付宝收银台,请在支付宝内完成付款。支付成功后自动到账,本页每 3 秒自动查询。</div></div>
<div style="text-align:center;color:var(--muted);font-size:var(--fs-sm);padding:8px 0 14px">等待支付结果…</div>
<div style="display:flex;gap:10px"><div class="btn ghost" style="flex:1;justify-content:center" onclick="buy.phase='pick';drawBuy()">返回</div><div class="btn primary" style="flex:2;justify-content:center" onclick="buy.phase='success';drawBuy()">我已完成支付</div></div>`;
return;
}
if(buy.phase==='success'){
el.innerHTML=`<div style="text-align:center;padding:8px 0 4px"><span class="badge bi b-已通过" style="height:28px;padding:0 14px"><svg class="ic"><use href="#i-check"/></svg>支付成功,授权已续期</span></div>
<div class="drow"><span>新到期日</span><b style="font-family:var(--font-mono)">2028-03-15</b></div>
<div class="drow" style="border-bottom:none"><span>剩余天数</span><b>632 天</b></div>
<div style="display:flex;gap:10px;margin-top:12px"><div class="btn ghost" style="flex:1;justify-content:center" onclick="buy.phase='pick';drawBuy()">继续购买</div></div>`;
return;
}
const tabs=[['promo',buy.promoUsed?'首月特惠(已享受)':'🔥 首月特惠 ¥1'],['standard','标准版'],['pro','高级版']];
let html=`<div style="display:flex;gap:8px;flex-wrap:wrap;margin-bottom:12px">${tabs.map(([k,label])=>`<div class="m-pill ${buy.tab===k?'on':''}" ${k==='promo'&&buy.promoUsed?'style="opacity:.45"':''} onclick="${k==='promo'&&buy.promoUsed?"mToast('本店已享受过首月特惠')":`buy.tab='${k}';drawBuy()`}">${label}</div>`).join('')}</div>`;
if(buy.tab==='promo'){
html+=`<div style="display:flex;align-items:baseline;gap:8px"><span style="font-size:var(--fs-display);font-weight:800;color:var(--heading);font-family:var(--font-mono)">¥1</span><span style="color:var(--muted);font-size:var(--fs-sm)">/ 首月</span></div>
<div style="font-size:var(--fs-sm);color:var(--muted);margin-top:6px">${PLANS.promo.days} · ${PLANS.promo.note}</div>`;
} else {
const p=PLANS[buy.tab];
html+=`<div style="display:flex;gap:8px;margin-bottom:10px"><div class="m-pill ${buy.cycle==='annual'?'on':''}" onclick="buy.cycle='annual';drawBuy()">年付 · 省 2 个月</div><div class="m-pill ${buy.cycle==='monthly'?'on':''}" onclick="buy.cycle='monthly';drawBuy()">月付</div></div>`;
if(buy.cycle==='annual'){
const save=p.monthly*12-p.annual;
html+=`<div style="display:flex;align-items:baseline;gap:8px"><span style="font-size:var(--fs-display);font-weight:800;color:var(--heading);font-family:var(--font-mono)">¥${fmt(p.annual)}</span><span style="color:var(--muted);font-size:var(--fs-sm)">/ 年</span><span style="color:var(--faint);font-size:var(--fs-sm);text-decoration:line-through;font-family:var(--font-mono)">¥${fmt(p.monthly*12)}</span></div>
<div style="font-size:var(--fs-sm);color:var(--success);margin-top:6px">月付 ¥${fmt(p.monthly)} × 12 = ¥${fmt(p.monthly*12)},年付立省 ¥${fmt(save)},相当于免费用 2 个月</div>`;
} else {
html+=`<div style="display:flex;align-items:baseline;gap:8px"><span style="font-size:var(--fs-display);font-weight:800;color:var(--heading);font-family:var(--font-mono)">¥${fmt(p.monthly)}</span><span style="color:var(--muted);font-size:var(--fs-sm)">/ 月</span></div>`;
}
}
html+=`<div class="btn primary" style="justify-content:center;margin-top:14px" onclick="buy.phase='waiting';drawBuy()"><svg viewBox="0 0 24 24"><use href="#i-ic08"/></svg>支付宝支付</div>
<div style="font-size:var(--fs-xs);color:var(--faint);margin-top:8px;text-align:center">手机端直接拉起支付宝 App · 到账即时续期</div>`;
el.innerHTML=html;
}
</script>
</body>
</html>
+4
View File
@@ -123,6 +123,10 @@ AppTokens 目前**仅颜色**。原型还驱动:
| 购买卡(首月特惠/标准/高级 tab + 年付月付 + 支付轮询三态) | `purchase_card.dart` | 无独立 golden;改动后人工目检 + `flutter test` 回归 | 价格展示以 `license_plans.dart` 为源,实付以 pay 侧为准 |
| 官网 定价区/checkout/license-result/profile/logout | `web/index.njk` `checkout.njk` 等 | 人工验收(web 无 golden 体系) | 原型 `pricing.html`/`checkout.html` 为当初设计参考,已漂移,视为历史快照 |
### 移动愿景原型(m-*2026-07-04 起对齐轮)
`m-*` 屏是**移动端目标设计**(底部 tab + 「我的」hub 导航),Flutter 窄屏当前为响应式复用桌面屏(Drawer 导航),tab 形态未实现——两者差异是**有意的愿景超前**,不算漂移。已按桌面/实现能力对齐的移动屏:`m-stock-in-list`/`m-stock-out-list`(详细搜索/退单/确认定价/KPI)、`m-devices`(登录会话+外设,**打印相关移动端裁剪**)、`m-settings`(5 面板 + 授权管理二级视图=授权信息/在线购买/兑换券/降级规则)、`m-about`(链接行/反馈表单/ICP 页脚,授权块已删随迁)。移动端**不提供建单入口**(无 + / FAB)。Flutter 移动改版实现时以这批原型为 design-first 基准。
> **共享组件杠杆**`StatusBadge`(入/出库单据状态)一处升级两屏受益;`StatusPill`/`KpiCard` 现已被库存/往来/入出库/财务/设备/设置/关于复用——新屏直接套,无需重做徽章/卡片。
### 全量清扫收尾(其余屏状态)