门店审核功能

This commit is contained in:
2026-07-14 15:25:17 +08:00
parent d61a43cc8c
commit e0f5977dd9
13 changed files with 479 additions and 40 deletions
+68 -8
View File
@@ -6,7 +6,14 @@ import { request } from '../lib/api';
import { toastSuccess } from '../lib/toast';
import { usePartnerSession } from '../contexts/PartnerSessionContext';
import { isSubAccount } from '../lib/partnerAccess';
import { storeStatusLabel, storeStatusPillClass, type StoreStatusValue } from '../lib/storeStatus';
import {
canPartnerOpenStore,
storeAuditLabel,
storeAuditPillClass,
storeStatusLabel,
storeStatusPillClass,
type StoreStatusValue,
} from '../lib/storeStatus';
const STATUS_OPTIONS: StoreStatusValue[] = ['OPEN', 'PAUSED', 'CLOSED'];
@@ -48,6 +55,15 @@ export default function StoreDetailPage() {
async function changeStatus(next: StoreStatusValue) {
if (!id || next === status || statusSaving) return;
if (status === 'CLOSED') return;
const auditStatus = String(store?.auditStatus || 'APPROVED').toUpperCase();
if (next === 'OPEN' && !canPartnerOpenStore(auditStatus)) {
setActionError(
auditStatus === 'REJECTED'
? `门店审核未通过${store?.rejectReason ? `${String(store.rejectReason)}` : ''}`
: '门店尚在总部审核中,通过后方可开门',
);
return;
}
if (next === 'CLOSED') {
const ok = window.confirm('关闭后不可恢复营业,确认关闭该门店?');
if (!ok) return;
@@ -71,6 +87,11 @@ export default function StoreDetailPage() {
async function saveBasic() {
if (!id || saving || status === 'CLOSED') return;
const auditStatus = String(store?.auditStatus || 'APPROVED').toUpperCase();
if (auditStatus === 'PENDING') {
setActionError('门店审核中,暂不可修改资料');
return;
}
setSaving(true);
setActionError('');
try {
@@ -84,7 +105,7 @@ export default function StoreDetailPage() {
}),
});
applyStore(data);
toastSuccess('已保存');
toastSuccess(auditStatus === 'REJECTED' ? '已保存并重新提交审核' : '已保存');
} catch (e) {
setActionError(e instanceof Error ? e.message : '保存失败');
} finally {
@@ -106,7 +127,11 @@ export default function StoreDetailPage() {
const envPhotos = Array.isArray(store.media)
? (store.media as Array<{ url?: string; bizType?: string }>).filter((m) => m.bizType === 'ENV')
: [];
const readOnly = subReadonly || status === 'CLOSED';
const auditStatus = String(store.auditStatus || 'APPROVED').toUpperCase();
const auditPending = auditStatus === 'PENDING';
const auditRejected = auditStatus === 'REJECTED';
const readOnly = subReadonly || status === 'CLOSED' || auditPending;
const canOpen = canPartnerOpenStore(auditStatus);
return (
<div className="partner-detail-page">
@@ -114,6 +139,37 @@ export default function StoreDetailPage() {
<main style={{ padding: '16px 20px' }}>
{actionError && <p className="partner-form-error" role="alert" style={{ marginBottom: 12 }}>{actionError}</p>}
<section className="partner-form-card" style={{ margin: '0 0 16px' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 }}>
<h3 className="label-md text-muted" style={{ textTransform: 'uppercase', letterSpacing: '0.1em' }}></h3>
<span className={`partner-status-pill ${storeAuditPillClass(auditStatus)}`}>
{storeAuditLabel(auditStatus)}
</span>
</div>
{auditPending && (
<p className="body-md" style={{ color: 'var(--color-secondary)' }}>
</p>
)}
{auditRejected && (
<div>
<p className="body-md" style={{ color: 'var(--color-heritage-red)', fontWeight: 600, marginBottom: 8 }}>
</p>
<p className="body-md" style={{ background: 'rgba(180,35,24,0.06)', padding: 12, borderRadius: 8 }}>
{String(store.rejectReason || '未填写驳回原因')}
</p>
<p className="label-md text-muted" style={{ marginTop: 8 }}>
</p>
</div>
)}
{auditStatus === 'APPROVED' && (
<p className="label-md text-muted"></p>
)}
</section>
{!subReadonly && (
<section className="partner-form-card" style={{ margin: '0 0 16px' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 }}>
@@ -129,10 +185,10 @@ export default function StoreDetailPage() {
key={s}
type="button"
className={status === s ? 'active' : ''}
disabled={readOnly || statusSaving}
disabled={readOnly || statusSaving || (s === 'OPEN' && !canOpen) || status === 'CLOSED'}
onClick={() => void changeStatus(s)}
>
{storeStatusLabel(s)}
{s === 'OPEN' && !canOpen ? '待审核' : storeStatusLabel(s)}
</button>
))}
</div>
@@ -195,10 +251,14 @@ export default function StoreDetailPage() {
<section className="partner-form-card" style={{ margin: 0, background: 'var(--color-surface-container)' }}>
<h3 className="headline-md" style={{ borderLeft: '4px solid var(--color-subtle-gray)', paddingLeft: 12, marginBottom: 16 }}></h3>
<div>
<label className="label-md text-muted"></label>
<div style={{ marginBottom: 12 }}>
<label className="label-md text-muted"></label>
<p className="body-md" style={{ fontWeight: 500 }}>{storeStatusLabel(status)}</p>
</div>
<div>
<label className="label-md text-muted"></label>
<p className="body-md" style={{ fontWeight: 500 }}>{storeAuditLabel(auditStatus)}</p>
</div>
</section>
</main>
@@ -207,7 +267,7 @@ export default function StoreDetailPage() {
{!subReadonly && (
<button type="button" className="partner-save-submit" onClick={() => void saveBasic()} disabled={readOnly || saving}>
<span className="material-symbols-outlined">save</span>
{saving ? '保存中…' : '保存修改'}
{saving ? '保存中…' : auditRejected ? '保存并重新提交' : '保存修改'}
</button>
)}
</footer>