docs(design): 授权管理上升为独立移动屏,入口移至「我的」系统组用户管理下

- 新建 m-license.html(授权信息/在线购买三阶段/兑换券/降级规则,自 m-settings
  二级视图整体迁出,m-top 返回导航)
- m-me 系统组 用户管理 之下加「授权管理」入口
- m-settings 撤内嵌授权视图与入口,回归纯 hub(门店/编号规则/偏好等 sheet 保留)

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:43:37 +08:00
parent 781e2c5e2d
commit b683adece9
3 changed files with 94 additions and 77 deletions
@@ -0,0 +1,93 @@
<!DOCTYPE html>
<html lang="zh-CN" data-theme="a">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>授权管理 · 岩美酒库</title>
<link rel="stylesheet" href="../tokens.css">
<link rel="stylesheet" href="../atoms.css">
<link rel="stylesheet" href="../mobile-atoms.css">
<style>body{margin:0; font-family:var(--font); color:var(--text); background:var(--page); -webkit-font-smoothing:antialiased;}</style>
</head>
<body>
<div class="m-top" data-m-top data-back data-title="授权管理"></div>
<div class="m-page">
<div class="m-scroll">
<!-- 对齐桌面 settings 授权管理四卡:授权信息 / 在线购买续费 / 兑换券 / 降级规则 -->
<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>
<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 class="toast" id="toast"></div>
<script src="icons.js"></script>
<script src="mobile-shell.js"></script>
<script>
/* ==================== 在线购买卡(对齐 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;
}
drawBuy();
</script>
</body>
</html>
+1
View File
@@ -36,6 +36,7 @@
<div class="m-section">系统</div>
<div class="m-hub">
<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 href="m-license.html"><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>
<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>
<a href="m-settings.html"><span class="hic"><svg viewBox="0 0 24 24"><use href="#i-gear"/></svg></span>系统设置<span class="hchev"><svg viewBox="0 0 24 24"><use href="#i-chevron-right"/></svg></span></a>
<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>
@@ -14,14 +14,11 @@
<div class="m-page">
<div class="m-scroll">
<!-- ============ 主视图:设置 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">
@@ -34,35 +31,6 @@
<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 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>
@@ -70,8 +38,6 @@
<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(){
@@ -99,49 +65,6 @@ 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>