feat(ops,store,partner): 用户权益列 + 门店合同多图上传
- admin 用户列表新增剩余/已用/累计好客权益金额三列(benefitCoupon groupBy 聚合,排除 VOID) - admin/partner 门店入驻合同支持多张照片与 PDF(CommonResource 多记录,复用 ENV 多图逻辑) - 新增 contract-urls.util 归一化工具,向后兼容旧 contractUrl 字段并标记 deprecated 需求1/2/3
This commit is contained in:
@@ -28,7 +28,8 @@ export type StoreDraftForm = {
|
||||
benefitUsageRule: string;
|
||||
coverUrl: string;
|
||||
envPhotoUrls: string[];
|
||||
contractUrl: string;
|
||||
/** 签约合同,支持多张照片 / PDF */
|
||||
contractUrls: string[];
|
||||
bankAccountName: string;
|
||||
bankAccountNo: string;
|
||||
bankBranch: string;
|
||||
@@ -70,7 +71,7 @@ export const defaultStoreForm = (): StoreDraftForm => ({
|
||||
benefitUsageRule: '',
|
||||
coverUrl: '',
|
||||
envPhotoUrls: ['', '', ''],
|
||||
contractUrl: '',
|
||||
contractUrls: [],
|
||||
bankAccountName: '',
|
||||
bankAccountNo: '',
|
||||
bankBranch: '',
|
||||
@@ -88,6 +89,9 @@ function timeToMinutes(hhmm: string): number {
|
||||
|
||||
export const MIN_ENV_PHOTO_COUNT = 3;
|
||||
|
||||
/** 签约合同最多可上传的照片 / PDF 数量 */
|
||||
export const MAX_CONTRACT_COUNT = 20;
|
||||
|
||||
export function normalizeStringArray(urls: unknown, minLen: number): string[] {
|
||||
const arr = Array.isArray(urls) ? urls.map((u) => String(u ?? '')) : [];
|
||||
while (arr.length < minLen) arr.push('');
|
||||
@@ -118,6 +122,22 @@ export function normalizeStoreDraftForm(raw: Partial<StoreDraftForm> | null | un
|
||||
closeTime2: String(raw.closeTime2 ?? base.closeTime2),
|
||||
avgPrice: String(raw.avgPrice ?? base.avgPrice),
|
||||
envPhotoUrls: normalizeStringArray(raw.envPhotoUrls, MIN_ENV_PHOTO_COUNT),
|
||||
// 兼容旧草稿:单个 contractUrl 迁移为数组
|
||||
contractUrls: (() => {
|
||||
const list = Array.isArray(raw.contractUrls)
|
||||
? raw.contractUrls
|
||||
: [(raw as { contractUrl?: unknown }).contractUrl];
|
||||
const seen = new Set<string>();
|
||||
const out: string[] = [];
|
||||
for (const item of list) {
|
||||
const url = String(item ?? '').trim();
|
||||
if (!url || seen.has(url)) continue;
|
||||
seen.add(url);
|
||||
out.push(url);
|
||||
if (out.length >= MAX_CONTRACT_COUNT) break;
|
||||
}
|
||||
return out;
|
||||
})(),
|
||||
packages: Array.isArray(raw.packages)
|
||||
? raw.packages.map((p, i) => ({
|
||||
name: String((p as { name?: string }).name ?? ''),
|
||||
@@ -224,12 +244,13 @@ export function validateStoreStep1(
|
||||
}
|
||||
|
||||
export function validateStoreStep2(
|
||||
form: Pick<StoreDraftForm, 'coverUrl' | 'envPhotoUrls' | 'contractUrl'>,
|
||||
form: Pick<StoreDraftForm, 'coverUrl' | 'envPhotoUrls' | 'contractUrls'>,
|
||||
): string | null {
|
||||
if (!form.coverUrl.trim()) return '请上传门头照';
|
||||
const envCount = form.envPhotoUrls.filter((u) => u.trim()).length;
|
||||
if (envCount < MIN_ENV_PHOTO_COUNT) return `请上传至少 ${MIN_ENV_PHOTO_COUNT} 张环境照片`;
|
||||
if (!form.contractUrl.trim()) return '请上传签约合同';
|
||||
const contractCount = (form.contractUrls ?? []).filter((u) => u.trim()).length;
|
||||
if (contractCount < 1) return '请上传签约合同';
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user