c7de728c18
- 导航「进入系统 · 名字」改为下拉:个人信息 / 进入系统 / 退出登录,导航可重入刷新(window.jiuNavRender) - 新增 /profile/(账号 / 门店 / 授权三卡,authFetch 实时拉取)与 /logout/(撤销会话 + 清本地凭证) - 登录成功默认落地 /profile/(?next= 站内白名单不变),不再直跳 /app/ - auth.js 增加 jiuAuth.clear();site.css 含本轮下拉 / profile / 特惠卡样式 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JJ1g8XV1YhhmHRzhwWEW7o
92 lines
4.8 KiB
Plaintext
92 lines
4.8 KiB
Plaintext
---
|
||
layout: base.njk
|
||
title: 登录
|
||
description: 登录岩美酒库管理系统。
|
||
permalink: /login/
|
||
---
|
||
{# 官网内登录(不跳 App):POST /api/v1/auth/login,成功后把凭证写入与
|
||
Web 版 App(shared_preferences_web)共享的 localStorage['flutter.*']
|
||
(值为 JSON 编码,与插件格式一致),默认落地 /profile/;后续打开 /app/ 即已登录。 #}
|
||
<div class="auth-wrap">
|
||
<div class="auth">
|
||
<div class="auth-brand">
|
||
<img class="mk" src="/assets/logo-mark.svg" alt="岩美酒库" />
|
||
<div class="bname">岩美酒库</div>
|
||
<div class="btag">酒水进销存 · 审核驱动业务流</div>
|
||
<div class="pts">
|
||
<div class="pt"><span class="pi"><svg class="ic"><use href="#i-box"/></svg></span>入库出库 · 审核后实时改库存</div>
|
||
<div class="pt"><span class="pi"><svg class="ic"><use href="#i-ic08"/></svg></span>往来对账 · 财务一目了然</div>
|
||
<div class="pt"><span class="pi"><svg class="ic"><use href="#i-ic23"/></svg></span>多端协同 · 多租户安全隔离</div>
|
||
</div>
|
||
</div>
|
||
<div class="auth-form">
|
||
<h1>登录</h1>
|
||
<p class="alead">欢迎回来,请输入账号信息</p>
|
||
<div class="auth-alert" id="loginErr"></div>
|
||
<div class="field"><label>门店编号<span class="req">*</span></label><input class="input" id="shop" placeholder="例如 S000001" autocomplete="organization" /></div>
|
||
<div class="field"><label>登录账号<span class="req">*</span></label><input class="input" id="user" placeholder="请输入登录账号" autocomplete="username" /></div>
|
||
<div class="field"><label>密码<span class="req">*</span></label><input class="input" id="pass" type="password" placeholder="请输入密码" autocomplete="current-password" /></div>
|
||
<button class="btn primary lg" id="loginBtn" style="margin-top:8px">登 录</button>
|
||
<div class="auth-foot">还没有门店账号?<a href="/register/" style="font-weight:600">注册新门店 →</a></div>
|
||
<div class="auth-foot" style="margin-top:6px;color:var(--faint);font-size:var(--fs-xs)">岩美酒库 © 2026 · 仅授权门店可登录</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
(function () {
|
||
var API = '{{ site.appBaseUrl }}';
|
||
function $(id) { return document.getElementById(id); }
|
||
function showErr(msg) { var el = $('loginErr'); el.textContent = msg; el.classList.add('show'); }
|
||
|
||
// 与 shared_preferences_web 同格式(值 JSON 编码),Web 版 App 可直接恢复会话
|
||
function persist(data, shopNo) {
|
||
var u = data.user || {};
|
||
var kv = {
|
||
access_token: data.access_token, refresh_token: data.refresh_token,
|
||
user_id: u.id || 0, username: u.username || '', real_name: u.real_name || '',
|
||
shop_no: shopNo, shop_id: String(data.shop_id || ''), role: u.role || 'operator',
|
||
};
|
||
Object.keys(kv).forEach(function (k) {
|
||
localStorage.setItem('flutter.' + k, JSON.stringify(kv[k]));
|
||
});
|
||
}
|
||
|
||
function doLogin() {
|
||
var shop = $('shop').value.trim(), user = $('user').value.trim(), pass = $('pass').value;
|
||
if (!shop) return showErr('请输入门店编号');
|
||
if (!user) return showErr('请输入登录账号');
|
||
if (!pass) return showErr('请输入密码');
|
||
$('loginErr').classList.remove('show');
|
||
var btn = $('loginBtn'); btn.disabled = true; btn.textContent = '登录中…';
|
||
fetch(API + '/api/v1/auth/login', {
|
||
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ shop_code: shop, username: user, password: pass }),
|
||
})
|
||
.then(function (r) { return r.json().then(function (j) { return { ok: r.ok, j: j }; }); })
|
||
.then(function (res) {
|
||
if (!res.ok) throw new Error((res.j && res.j.error) || '登录失败,请检查账号信息');
|
||
persist(res.j.data || {}, shop);
|
||
// ?next= 仅允许站内路径(防开放跳转);默认留在官网(个人信息页),不跳 App
|
||
var next = new URLSearchParams(location.search).get('next') || '';
|
||
location.href = (next.charAt(0) === '/' && next.indexOf('//') !== 0) ? next : '/profile/';
|
||
})
|
||
.catch(function (e) {
|
||
showErr(e && e.message ? e.message : '无法连接服务器,请稍后重试');
|
||
btn.disabled = false; btn.textContent = '登 录';
|
||
});
|
||
}
|
||
// 登录过的浏览器回填门店编号/账号(token 过期重登时少敲两栏)
|
||
if (window.jiuAuth) {
|
||
var savedShop = jiuAuth.get('shop_no'), savedUser = jiuAuth.get('username');
|
||
if (savedShop && !$('shop').value) $('shop').value = savedShop;
|
||
if (savedUser && !$('user').value) $('user').value = savedUser;
|
||
}
|
||
|
||
$('loginBtn').addEventListener('click', doLogin);
|
||
['shop', 'user', 'pass'].forEach(function (id) {
|
||
$(id).addEventListener('keydown', function (e) { if (e.key === 'Enter') doLogin(); });
|
||
});
|
||
})();
|
||
</script>
|