225 lines
6.7 KiB
TypeScript
225 lines
6.7 KiB
TypeScript
import { isCorpGoodsType } from './detail'
|
|
|
|
export type UploadedImage = {
|
|
id: string
|
|
url: string
|
|
preview: string
|
|
}
|
|
|
|
export type OrderLike = {
|
|
order_id?: string
|
|
goods_type?: string
|
|
goods_name?: string
|
|
entity_name?: string
|
|
entity_phone?: string
|
|
entity_extra?: Record<string, unknown>
|
|
extra?: Record<string, any>
|
|
[key: string]: any
|
|
}
|
|
|
|
export type ResubmitValues = {
|
|
entity_name?: string
|
|
entity_address_name?: string
|
|
entity_address?: string
|
|
entity_phone?: string
|
|
entity_phone2?: string
|
|
}
|
|
|
|
const OMIT_EXTRA_KEYS = new Set([
|
|
'origin_price',
|
|
'qrCodeImgUrl',
|
|
'remoteIp',
|
|
'weixinAppId',
|
|
'entity_storefront_image',
|
|
'entity_business_license_image',
|
|
'entity_storefront_image_url',
|
|
'entity_business_license_image_url',
|
|
'goods_param',
|
|
])
|
|
|
|
function splitValues (value: unknown) {
|
|
if (value === undefined || value === null) return []
|
|
return String(value)
|
|
.split(',')
|
|
.map((item) => item.trim())
|
|
.filter(Boolean)
|
|
}
|
|
|
|
function isEmptySlotToken (value?: string) {
|
|
return !value || value === 'null' || value === '0'
|
|
}
|
|
|
|
function splitSlotValues (value: unknown) {
|
|
if (value === undefined || value === null || value === '') return []
|
|
return String(value).split(',').map((item) => item.trim())
|
|
}
|
|
|
|
export type StorefrontSlot = UploadedImage | null
|
|
|
|
export function joinStorefrontSlots (slots: Array<StorefrontSlot | undefined> = []) {
|
|
return [0, 1, 2].map((index) => {
|
|
const id = slots[index]?.id?.trim()
|
|
return id ? id : '0'
|
|
}).join(',')
|
|
}
|
|
|
|
export function parseStorefrontSlots (order: OrderLike | null | undefined): StorefrontSlot[] {
|
|
const extra = order?.extra || {}
|
|
const ids = splitSlotValues(extra.entity_storefront_image)
|
|
const urls = splitSlotValues(extra.entity_storefront_image_url)
|
|
|
|
return [0, 1, 2].map((index) => {
|
|
const id = ids[index] || ''
|
|
const url = urls[index] || ''
|
|
if (isEmptySlotToken(id) && isEmptySlotToken(url)) return null
|
|
if (isEmptySlotToken(id) && !isEmptySlotToken(url)) {
|
|
return { id: '', url, preview: url }
|
|
}
|
|
const resolvedUrl = !isEmptySlotToken(url)
|
|
? url
|
|
: (/^https?:\/\//i.test(id) ? id : '')
|
|
return {
|
|
id: /^https?:\/\//i.test(id) ? '' : id,
|
|
url: resolvedUrl,
|
|
preview: resolvedUrl,
|
|
}
|
|
})
|
|
}
|
|
|
|
export function isCoordinateAddress (address?: string) {
|
|
if (!address) return false
|
|
const parts = address.split(',').map((part) => part.trim())
|
|
if (parts.length !== 2) return false
|
|
return parts.every((part) => Number.isFinite(Number(part)))
|
|
}
|
|
|
|
export function parseCoordinate (address?: string) {
|
|
if (!isCoordinateAddress(address)) return null
|
|
const [lng, lat] = String(address).split(',').map((part) => Number(part.trim()))
|
|
return { lng, lat }
|
|
}
|
|
|
|
export function formatMapCoordinate (point: { lng: number, lat: number }) {
|
|
return `${point.lng.toFixed(6)},${point.lat.toFixed(6)}`
|
|
}
|
|
|
|
export function formatMapCoordinateDisplay (point: { lng: number, lat: number }) {
|
|
return `N${point.lat.toFixed(6)}°, E${point.lng.toFixed(6)}°`
|
|
}
|
|
|
|
export function getOrderAddressName (order: OrderLike) {
|
|
const extra = order.extra || {}
|
|
return extra.entity_address_name || (!isCoordinateAddress(extra.entity_address) ? extra.entity_address : '') || ''
|
|
}
|
|
|
|
export function getOrderMapAddress (order: OrderLike) {
|
|
const extra = order.extra || {}
|
|
return isCoordinateAddress(extra.entity_address) ? extra.entity_address : ''
|
|
}
|
|
|
|
export function getInitialPhone2 (order: OrderLike) {
|
|
const extra = order.extra || {}
|
|
return String(extra.entity_phone2 || extra.entity_phone_2 || extra.phone2 || '')
|
|
}
|
|
|
|
export function getGoodsIcons (order: OrderLike) {
|
|
const icons = order.extra?.goods_param?.['client.goods.icon']
|
|
return Array.isArray(icons) ? icons.filter((item) => typeof item === 'string') : []
|
|
}
|
|
|
|
export function normalizeOrders<T extends OrderLike> (orders: T[] = []) {
|
|
return orders.map((item) => {
|
|
const nextItem = { ...item, extra: { ...(item.extra || {}) } }
|
|
const goodsParam = nextItem.extra.goods_param
|
|
if (typeof goodsParam === 'string') {
|
|
try {
|
|
nextItem.extra.goods_param = JSON.parse(goodsParam)
|
|
} catch {
|
|
nextItem.extra.goods_param = null
|
|
}
|
|
}
|
|
return nextItem
|
|
})
|
|
}
|
|
|
|
export const MAP_LABEL_DISPLAY_NAME = '商户资料服务'
|
|
|
|
export function getOrderDisplayName (order?: OrderLike | null) {
|
|
if (order?.goods_type === 'map_label') return MAP_LABEL_DISPLAY_NAME
|
|
return String(order?.goods_name || '').trim() || '-'
|
|
}
|
|
|
|
export function filterOrdersForProduct<T extends OrderLike> (goodsType: string, orders: T[] = []) {
|
|
const normalized = normalizeOrders(orders)
|
|
if (isCorpGoodsType(goodsType)) return normalized
|
|
const target = goodsType || 'map_label'
|
|
return normalized.filter((item) => item.goods_type === target)
|
|
}
|
|
|
|
export function filterMapLabelOrders<T extends OrderLike> (orders: T[] = []) {
|
|
return filterOrdersForProduct('map_label', orders)
|
|
}
|
|
|
|
export function getOrderExtraImages (order: OrderLike | null | undefined, keys: string[]): UploadedImage[] {
|
|
const extra = order?.extra || {}
|
|
|
|
for (const key of keys) {
|
|
const values = splitValues(extra[key])
|
|
const explicitIds = splitValues(extra[`${key}_id`])
|
|
const explicitUrls = splitValues(extra[`${key}_url`])
|
|
const urls = explicitUrls.length > 0
|
|
? explicitUrls
|
|
: values.filter((value) => /^https?:\/\//i.test(value))
|
|
|
|
if (urls.length > 0) {
|
|
return urls.map((url, index) => {
|
|
const valueId = values[index] && values[index] !== url ? values[index] : ''
|
|
return {
|
|
id: valueId || explicitIds[index] || '',
|
|
url,
|
|
preview: url,
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
return []
|
|
}
|
|
|
|
export function joinUploadedImageIds (images: UploadedImage[]) {
|
|
return images
|
|
.map((image) => image.id.trim())
|
|
.filter(Boolean)
|
|
.join(',')
|
|
}
|
|
|
|
export function buildResubmitPayload (input: {
|
|
order: OrderLike
|
|
values: ResubmitValues
|
|
storefrontSlots: StorefrontSlot[]
|
|
licenseImages: UploadedImage[]
|
|
}) {
|
|
const existingExtra = Object.entries(input.order.extra || {}).reduce<Record<string, unknown>>((result, [key, value]) => {
|
|
if (!OMIT_EXTRA_KEYS.has(key)) {
|
|
result[key] = value
|
|
}
|
|
return result
|
|
}, {})
|
|
|
|
return {
|
|
id: String(input.order.order_id || ''),
|
|
corp_id: 0,
|
|
entity_name: input.values.entity_name || input.order.entity_name || '',
|
|
entity_phone: input.values.entity_phone || '',
|
|
entity_extra: input.order.entity_extra || {},
|
|
extra: {
|
|
...existingExtra,
|
|
entity_address_name: input.values.entity_address_name || '',
|
|
entity_address: input.values.entity_address || '',
|
|
entity_phone2: input.values.entity_phone2 || '',
|
|
entity_storefront_image: joinStorefrontSlots(input.storefrontSlots),
|
|
entity_business_license_image: joinUploadedImageIds(input.licenseImages),
|
|
},
|
|
}
|
|
}
|