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 const defaultStoreForm = (): StoreDraftForm => ({ regionCodes: [], cityId: '', province: '', city: '', district: '', name: '', phone: '', address: '', intro: '', coverUrl: '', envPhotoUrls: ['', '', ''], contractUrl: '', bankAccountName: '', bankAccountNo: '', bankBranch: '', }); export 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): 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(): StoreDraft | null { try { const raw = localStorage.getItem(STORE_DRAFT_KEY); if (!raw) return null; const parsed = JSON.parse(raw) as Record; 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), }; } return { step: 1, form: normalizeForm(parsed) }; } catch { return null; } } export function saveStoreDraft(draft: StoreDraft) { localStorage.setItem(STORE_DRAFT_KEY, JSON.stringify(draft)); } export function clearStoreDraft() { localStorage.removeItem(STORE_DRAFT_KEY); } const PHONE_RE = /^1\d{10}$/; const BANK_RE = /^\d{16,19}$/; export function validateStoreStep1( form: Pick, ): 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, ): 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 patchEnvPhotoAt(urls: string[], index: number, url: string): string[] { const envPhotoUrls = normalizeStringArray(urls, 3); envPhotoUrls[index] = url; return envPhotoUrls; } export function validateStoreStep3( form: Pick, ): 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; }