门店账户多账号

This commit is contained in:
2026-07-12 12:24:34 +08:00
parent 06b1cb22e0
commit 54a15d6da7
39 changed files with 1962 additions and 311 deletions
@@ -0,0 +1,90 @@
import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useStoreSession } from '../contexts/StoreSessionContext';
import {
needsStoreSelection,
request,
selectStore,
type ShopSessionPayload,
type ShopStoreOption,
} from '../lib/api';
export default function SelectStorePage() {
const navigate = useNavigate();
const { applySession, store, authenticated } = useStoreSession();
const [stores, setStores] = useState<ShopStoreOption[]>(store?.stores ?? []);
const [loading, setLoading] = useState(false);
const [msg, setMsg] = useState('');
useEffect(() => {
if (!authenticated) {
navigate('/login', { replace: true });
return;
}
void request<ShopStoreOption[]>('SHOP_H5', '/shop/auth/stores')
.then((list) => setStores(list))
.catch((e) => setMsg(e instanceof Error ? e.message : '加载门店失败'));
}, [authenticated, navigate]);
async function onSelect(storeId: string) {
setLoading(true);
setMsg('');
try {
const session = await selectStore(storeId);
applySession(session);
navigate('/', { replace: true });
} catch (e) {
setMsg(e instanceof Error ? e.message : '选店失败');
} finally {
setLoading(false);
}
}
// 仅一家店时自动选
useEffect(() => {
if (stores.length === 1 && needsStoreSelection({ store, stores })) {
void onSelect(stores[0].storeId);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [stores.length]);
return (
<div className="shop-select-store-page">
<header className="shop-select-store-header">
<h1></h1>
<p></p>
</header>
{msg ? <p className="shop-select-store-msg">{msg}</p> : null}
<ul className="shop-select-store-list">
{stores.map((item) => (
<li key={item.storeId}>
<button
type="button"
className="shop-select-store-item"
disabled={loading}
onClick={() => void onSelect(item.storeId)}
>
<span className="shop-select-store-name">{item.name}</span>
<span className="shop-select-store-meta">
{[item.district, item.address].filter(Boolean).join(' · ') || item.status}
</span>
</button>
</li>
))}
</ul>
{!stores.length && !msg ? <p className="shop-select-store-empty"></p> : null}
</div>
);
}
/** After login/wechat: route to select-store or home */
export function routeAfterShopLogin(
session: ShopSessionPayload,
navigate: (path: string, opts?: { replace?: boolean }) => void,
) {
if (needsStoreSelection(session)) {
navigate('/select-store', { replace: true });
return;
}
navigate('/', { replace: true });
}