This commit is contained in:
2026-06-30 10:33:56 +08:00
commit 6e047dc0a5
607 changed files with 65966 additions and 0 deletions
@@ -0,0 +1,98 @@
import { useEffect, useMemo, useState } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import { isLoggedIn, request } from '../lib/api';
type StatusFilter = 'ALL' | 'OPEN' | 'PAUSED' | 'CLOSED';
function statusPill(status: string) {
const s = String(status).toUpperCase();
if (s === 'OPEN') return { cls: 'partner-status-pill--open', label: '营业中' };
if (s === 'PAUSED') return { cls: 'partner-status-pill--paused', label: '暂时闭店' };
return { cls: 'partner-status-pill--closed', label: '已关闭' };
}
const FILTERS: { key: StatusFilter; label: string }[] = [
{ key: 'ALL', label: '全部' },
{ key: 'OPEN', label: '营业中' },
{ key: 'PAUSED', label: '暂时闭店' },
{ key: 'CLOSED', label: '已关闭' },
];
export default function StoreListPage() {
const navigate = useNavigate();
const [stores, setStores] = useState<Array<Record<string, unknown>>>([]);
const [q, setQ] = useState('');
const [filter, setFilter] = useState<StatusFilter>('ALL');
useEffect(() => {
if (!isLoggedIn()) { navigate('/login'); return; }
request<Array<Record<string, unknown>>>('PARTNER_H5', '/partner/stores').then(setStores);
}, [navigate]);
const filtered = useMemo(() => stores.filter((s) => {
const matchQ = !q || String(s.name).includes(q) || String(s.address).includes(q);
const matchStatus = filter === 'ALL' || String(s.status).toUpperCase() === filter;
return matchQ && matchStatus;
}), [stores, q, filter]);
return (
<div className="page partner-store-page">
<header className="header app-page-header">
<h1 className="app-page-title"></h1>
</header>
<div className="partner-page-title-block">
<h2></h2>
<p className="text-muted body-md"></p>
</div>
<div className="partner-sticky-filter">
<div className="partner-search">
<span className="material-symbols-outlined">search</span>
<input placeholder="搜索门店名称/地址" value={q} onChange={(e) => setQ(e.target.value)} />
</div>
<div className="partner-chips">
{FILTERS.map((f) => (
<button key={f.key} type="button" className={`partner-chip${filter === f.key ? ' active' : ''}`} onClick={() => setFilter(f.key)}>
{f.label}
</button>
))}
</div>
</div>
<Link to="/stores/new" className="partner-fab-link">
<button type="button" className="partner-btn-primary">
<span className="material-symbols-outlined">add_business</span>
</button>
</Link>
{filtered.length === 0 && <div className="empty"></div>}
{filtered.map((s) => {
const pill = statusPill(String(s.status));
const dim = String(s.status).toUpperCase() === 'CLOSED';
return (
<div key={String(s.id)} className={`partner-store-card${dim ? ' partner-store-card--dim' : ''}`}>
<Link to={`/stores/${s.id}`} style={{ color: 'inherit', textDecoration: 'none' }}>
<div className="partner-store-card-header">
<div>
<h3 className="headline-md">{String(s.name)}</h3>
<p className="label-md text-muted" style={{ marginTop: 4 }}>{String(s.address || s.district || '')}</p>
</div>
<span className={`partner-status-pill ${pill.cls}`}>{pill.label}</span>
</div>
</Link>
<div className="partner-store-card-actions">
<button type="button" className="btn btn-outline" style={{ fontSize: 12, padding: '8px 12px' }}></button>
<button type="button" className="btn btn-outline" style={{ fontSize: 12, padding: '8px 12px', borderColor: 'var(--color-subtle-gray)', color: 'var(--color-subtle-gray)' }}></button>
<Link to={`/stores/${s.id}`} className="partner-menu-icon" style={{ width: 40, height: 40, borderRadius: 8, textDecoration: 'none' }}>
<span className="material-symbols-outlined" style={{ fontSize: 20 }}>edit</span>
</Link>
</div>
</div>
);
})}
</div>
);
}