150 lines
4.8 KiB
TypeScript
150 lines
4.8 KiB
TypeScript
export type StoreDraftForm = {
|
|
regionCodes: string[];
|
|
cityId: string;
|
|
province: string;
|
|
city: string;
|
|
district: string;
|
|
name: string;
|
|
phone: string;
|
|
address: string;
|
|
intro: string;
|
|
coverUrl: string;
|
|
envPhotoUrls: string[];
|
|
contractUrl: string;
|
|
bankAccountName: string;
|
|
bankAccountNo: string;
|
|
bankBranch: string;
|
|
};
|
|
|
|
export type StoreDraft = {
|
|
step: number;
|
|
form: StoreDraftForm;
|
|
};
|
|
|
|
export const STORE_DRAFT_KEY = 'partner_store_draft_v2';
|
|
|
|
export function storeDraftKey(accountId?: string): string {
|
|
return accountId ? `${STORE_DRAFT_KEY}_${accountId}` : STORE_DRAFT_KEY;
|
|
}
|
|
|
|
export const defaultStoreForm = (): StoreDraftForm => ({
|
|
regionCodes: [],
|
|
cityId: '',
|
|
province: '',
|
|
city: '',
|
|
district: '',
|
|
name: '',
|
|
phone: '',
|
|
address: '',
|
|
intro: '',
|
|
coverUrl: '',
|
|
envPhotoUrls: ['', '', ''],
|
|
contractUrl: '',
|
|
bankAccountName: '',
|
|
bankAccountNo: '',
|
|
bankBranch: '',
|
|
});
|
|
|
|
function normalizeStringArray(raw: unknown, length: number): string[] {
|
|
if (!Array.isArray(raw)) return Array.from({ length }, () => '');
|
|
const items = raw.map((item) => String(item ?? ''));
|
|
while (items.length < length) items.push('');
|
|
return items.slice(0, length);
|
|
}
|
|
|
|
function normalizeForm(raw: Record<string, unknown>): StoreDraftForm {
|
|
const base = defaultStoreForm();
|
|
const regionCodes = Array.isArray(raw.regionCodes)
|
|
? raw.regionCodes.map((code) => String(code))
|
|
: base.regionCodes;
|
|
return {
|
|
regionCodes,
|
|
cityId: String(raw.cityId ?? base.cityId),
|
|
province: String(raw.province ?? base.province),
|
|
city: String(raw.city ?? base.city),
|
|
district: String(raw.district ?? base.district),
|
|
name: String(raw.name ?? base.name),
|
|
phone: String(raw.phone ?? base.phone),
|
|
address: String(raw.address ?? base.address),
|
|
intro: String(raw.intro ?? base.intro),
|
|
coverUrl: String(raw.coverUrl ?? base.coverUrl),
|
|
envPhotoUrls: normalizeStringArray(raw.envPhotoUrls, 3),
|
|
contractUrl: String(raw.contractUrl ?? base.contractUrl),
|
|
bankAccountName: String(raw.bankAccountName ?? base.bankAccountName),
|
|
bankAccountNo: String(raw.bankAccountNo ?? base.bankAccountNo),
|
|
bankBranch: String(raw.bankBranch ?? base.bankBranch),
|
|
};
|
|
}
|
|
|
|
export function loadStoreDraft(accountId?: string): StoreDraft | null {
|
|
try {
|
|
const key = storeDraftKey(accountId);
|
|
let raw = localStorage.getItem(key);
|
|
if (!raw && accountId) {
|
|
raw = localStorage.getItem(STORE_DRAFT_KEY);
|
|
if (raw) {
|
|
localStorage.setItem(key, raw);
|
|
localStorage.removeItem(STORE_DRAFT_KEY);
|
|
}
|
|
}
|
|
if (!raw) return null;
|
|
const parsed = JSON.parse(raw) as Record<string, unknown>;
|
|
if (parsed.form && typeof parsed.form === 'object') {
|
|
return {
|
|
step: Math.min(3, Math.max(1, Number(parsed.step) || 1)),
|
|
form: normalizeForm(parsed.form as Record<string, unknown>),
|
|
};
|
|
}
|
|
return { step: 1, form: normalizeForm(parsed) };
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export function saveStoreDraft(draft: StoreDraft, accountId?: string) {
|
|
localStorage.setItem(storeDraftKey(accountId), JSON.stringify(draft));
|
|
}
|
|
|
|
export function clearStoreDraft(accountId?: string) {
|
|
localStorage.removeItem(storeDraftKey(accountId));
|
|
}
|
|
|
|
const PHONE_RE = /^1\d{10}$/;
|
|
const BANK_RE = /^\d{16,19}$/;
|
|
|
|
export function validateStoreStep1(
|
|
form: Pick<StoreDraftForm, 'regionCodes' | 'cityId' | 'name' | 'phone' | 'address' | 'intro'>,
|
|
): string | null {
|
|
if (!form.regionCodes || form.regionCodes.length < 3) return '请选择省 / 市 / 区县';
|
|
if (!form.cityId) return '所选地区未匹配到开城城市,请联系总部配置开城区划';
|
|
if (!form.name.trim()) return '请填写门店名称';
|
|
if (!form.phone.trim()) return '请填写联系电话';
|
|
if (!PHONE_RE.test(form.phone.trim())) return '联系电话须为11位手机号';
|
|
if (!form.address.trim()) return '请填写详细地址';
|
|
if (form.intro.trim()) {
|
|
const len = form.intro.trim().length;
|
|
if (len < 10 || len > 500) return '门店简介须为 10~500 字';
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function validateStoreStep2(
|
|
form: Pick<StoreDraftForm, 'coverUrl' | 'envPhotoUrls' | 'contractUrl'>,
|
|
): string | null {
|
|
if (!form.coverUrl.trim()) return '请上传门头照';
|
|
const envCount = form.envPhotoUrls.filter((u) => u.trim()).length;
|
|
if (envCount < 3) return '请上传至少 3 张环境照片';
|
|
if (!form.contractUrl.trim()) return '请上传签约合同';
|
|
return null;
|
|
}
|
|
|
|
export function validateStoreStep3(
|
|
form: Pick<StoreDraftForm, 'bankAccountName' | 'bankAccountNo' | 'bankBranch'>,
|
|
): string | null {
|
|
if (!form.bankAccountName.trim()) return '请填写户主姓名';
|
|
if (!form.bankAccountNo.trim()) return '请填写银行卡号';
|
|
if (!BANK_RE.test(form.bankAccountNo.replace(/\s/g, ''))) return '银行卡号须为 16~19 位数字';
|
|
if (!form.bankBranch.trim()) return '请填写开户支行';
|
|
return null;
|
|
}
|