import type { ConsignmentPricingConfig, ConsignmentSpecField, ConsignmentSpecFieldType, ConsignmentSpecValues, } from '@/types/consignment' /** * 旧版客服手工入库表单的选项常量。 * 新链路以「每个寄卖配置的 specs」为准,这里只给没有配置快照的旧数据兜底。 */ export const CONSIGNMENT_SYSTEM_OPTIONS = [ { label: '苹果', value: '苹果' }, { label: '安卓', value: '安卓' }, { label: '通用', value: '通用' }, ] as const export const CONSIGNMENT_ZONE_OPTIONS = [ { label: '微信区', value: '微信区' }, { label: 'QQ区', value: 'QQ区' }, { label: '互通(QQ/微信)', value: '互通' }, ] as const export const SPEC_FIELD_TYPE_OPTIONS: Array<{ label: string; value: ConsignmentSpecFieldType }> = [ { label: '文本', value: 'text' }, { label: '长文本', value: 'textarea' }, { label: '下拉', value: 'select' }, { label: '单选', value: 'radio' }, { label: '数字', value: 'number' }, { label: '日期', value: 'date' }, ] export function specFieldTypeLabel(type: ConsignmentSpecFieldType): string { return SPEC_FIELD_TYPE_OPTIONS.find((item) => item.value === type)?.label || '文本' } export function isOptionSpecField(field: Pick): boolean { return field.type === 'select' || field.type === 'radio' } export function formatSpecValue( field: ConsignmentSpecField, value: unknown, options: { forItemName?: boolean } = {}, ): string { const raw = String(value ?? '').trim() if (!raw) return '' if (options.forItemName && (field.key === 'diamondLevel' || field.key === 'brillianceCount')) { const numeric = Number(raw) if (!Number.isFinite(numeric)) return raw if (field.key === 'brillianceCount' && numeric <= 0) return '' return String(Math.round(numeric)) } if (isOptionSpecField(field)) { const option = field.options.find((item) => item.value === raw) if (options.forItemName && field.key === 'serverZone' && field.wildcardValues.includes(raw)) { return '' } return option?.label || raw } return raw } export function buildSpecText( specs: ConsignmentSpecField[], values: ConsignmentSpecValues | undefined, ): string { if (!values) return '' return specs .slice() .sort((a, b) => a.sortOrder - b.sortOrder || a.key.localeCompare(b.key)) .map((field) => { const display = formatSpecValue(field, values[field.key]) return display ? `${field.label} ${display}` : '' }) .filter(Boolean) .join(' / ') } export function buildSpecItemName( template: string, specs: ConsignmentSpecField[], values: ConsignmentSpecValues | undefined, categoryName = '', ): string { if (!values) return categoryName const tokens = new Map() for (const field of specs) { tokens.set(field.key, formatSpecValue(field, values[field.key], { forItemName: true })) } tokens.set('category', categoryName) let result = String(template || '').trim() if (result) { result = result.replace( /\{([a-zA-Z][a-zA-Z0-9_]*)\}/g, (_, key: string) => tokens.get(key) || '', ) } else { result = specs .filter((field) => field.showInItemName) .map((field) => formatSpecValue(field, values[field.key], { forItemName: true })) .filter(Boolean) .join('') } const normalized = result.replace(/\s+/g, ' ').trim() return normalized || categoryName || '寄卖物品' } export type SpecPriceResult = { priceFen: number capFen: number templatePriceFen: number breakdown: Array<{ label: string; amountFen: number }> } /** 与后端 computeConsignmentPrice 保持同口径,仅用于配置面板预览。 */ export function computeSpecPrice( pricing: ConsignmentPricingConfig, templatePriceFen = 0, ): SpecPriceResult { const template = Math.max(0, Math.round(Number(templatePriceFen || 0))) const breakdown: Array<{ label: string; amountFen: number }> = [] let priceFen = 0 if (pricing.priceType === 'fixed') { priceFen = Math.max(0, Math.round(Number(pricing.fixedPriceFen || 0))) if (priceFen > 0) breakdown.push({ label: '固定价格', amountFen: priceFen }) } else if (template > 0) { const discount = Math.min(10, Math.max(0.1, Number(pricing.discount || 10))) priceFen = Math.round((template * discount) / 10) breakdown.push({ label: '接单模板价', amountFen: template }) if (discount !== 10) { breakdown.push({ label: `${discount} 折`, amountFen: priceFen - template }) } } priceFen = Math.max(0, Math.round(priceFen)) return { priceFen, capFen: priceFen, templatePriceFen: template, breakdown, } }