This commit is contained in:
魔方熊成祥
2026-05-07 22:54:21 +08:00
parent 1c8de9b5f4
commit 5a968a719f
16 changed files with 4549 additions and 283 deletions

View File

@@ -1,31 +1,43 @@
import type {
AppAddressDefaultSetResponse,
AppAddressListResponse,
AppAddressSaveResponse,
AppAfterSaleApplyResponse,
AppCartListResponse,
AppCartSaveResponse,
AppGoodsDetailResponse,
AppGoodsPageResponse,
AppHomeMerchantGoodsResponse,
AppHomeResponse,
AppRecentNewGoodsResponse,
AppOrderDetailResponse,
AppOrderConfirmResponse,
AppOrderPageResponse,
AppTradeCreateResponse,
CartItemInfo,
CartGoodsGroupInfo,
CartMerchantGroupInfo,
GoodsDetailInfo,
GoodsSkuInfo,
GoodsSummary,
AppTradePreviewResponse,
HomeMerchantGoodsBlock,
MerchantDeliveryOptionInfo,
MerchantId,
MerchantInfo,
MerchantPackageOptionInfo,
OrderDetailInfo,
OrderSummary,
RecommendMerchantInfo,
RecentNewGoodsItem,
TradePreviewInfo,
TradePreviewItemInfo,
TradePreviewStoreInfo,
} from '@/types/mall'
type MaybeMallUidPayload = {
type MaybeMallIdentityPayload = {
uid?: number
memberId?: number
memberId?: MerchantId | number
}
type MaybeMallMerchantPayload = {
@@ -33,6 +45,22 @@ type MaybeMallMerchantPayload = {
storeId?: number | string
}
type MaybeMallIdPayload = {
id?: string | number
skuId?: string | number
skuIds?: Array<string | number>
addressId?: string | number
orderId?: string | number
orderItemId?: string | number
categoryId?: string | number
buyItems?: Array<{ skuId?: string | number; buyNum?: number }>
merchantOptions?: Array<{
merchantId?: MerchantId | number
deliveryOptionId?: string | number
packageOptionId?: string | number
}>
}
type RawRecommendMerchantPayload = Partial<RecommendMerchantInfo> & {
id?: RecommendMerchantInfo['id']
merchantId?: MerchantId | number | string
@@ -56,6 +84,8 @@ type RawMerchantEntityPayload = Partial<MerchantInfo> & {
}
type RawGoodsSummaryPayload = Partial<GoodsSummary> & {
id?: GoodsSummary['id'] | number
spuId?: GoodsSummary['id'] | number
merchantId?: MerchantId | number | string
createdAt?: GoodsSummary['createdAt'] | string | null
updatedAt?: GoodsSummary['updatedAt'] | string | null
@@ -69,14 +99,29 @@ type RawGoodsSummaryPayload = Partial<GoodsSummary> & {
update_time?: number | string | null
}
const toMerchantId = (value: MerchantId | number | string | null | undefined): MerchantId =>
value == null ? '' : String(value)
const toId = (value: string | number | null | undefined): string => (value == null ? '' : String(value))
const toMerchantId = (value: MerchantId | number | string | null | undefined): MerchantId => toId(value)
const toNumber = (value: number | string | null | undefined): number => {
const parsed = Number(value)
return Number.isFinite(parsed) ? parsed : 0
}
const toBoolean = (value: boolean | number | string | null | undefined): boolean => {
if (typeof value === 'boolean') {
return value
}
if (typeof value === 'number') {
return value !== 0
}
if (typeof value === 'string') {
return ['1', 'true', 'yes'].includes(value.trim().toLowerCase())
}
return false
}
const pickText = (...values: Array<string | null | undefined>): string => {
for (const value of values) {
if (typeof value === 'string' && value.trim()) {
@@ -111,12 +156,52 @@ const toUnixTime = (value: number | string | null | undefined): number => {
}
export const normalizeMallAppPayload = <TPayload extends object>(payload: TPayload): TPayload => {
const normalized = { ...payload } as TPayload & MaybeMallUidPayload & MaybeMallMerchantPayload
const normalized = { ...payload } as TPayload &
MaybeMallIdentityPayload &
MaybeMallMerchantPayload &
MaybeMallIdPayload
if (normalized.uid == null && normalized.memberId != null) {
normalized.uid = normalized.memberId
delete normalized.uid
if (normalized.memberId != null) {
normalized.memberId = toMerchantId(normalized.memberId)
}
if (normalized.id != null) {
normalized.id = toId(normalized.id)
}
if (normalized.skuId != null) {
normalized.skuId = toId(normalized.skuId)
}
if (normalized.skuIds != null) {
normalized.skuIds = normalized.skuIds.map(toId)
}
if (normalized.addressId != null) {
normalized.addressId = toId(normalized.addressId)
}
if (normalized.orderId != null) {
normalized.orderId = toId(normalized.orderId)
}
if (normalized.orderItemId != null) {
normalized.orderItemId = toId(normalized.orderItemId)
}
if (normalized.categoryId != null) {
normalized.categoryId = toId(normalized.categoryId)
}
if (normalized.buyItems != null) {
normalized.buyItems = normalized.buyItems.map(item => ({
...item,
skuId: item.skuId == null ? item.skuId : toId(item.skuId),
}))
}
if (normalized.merchantOptions != null) {
normalized.merchantOptions = normalized.merchantOptions.map(option => ({
...option,
merchantId: option.merchantId == null ? option.merchantId : toMerchantId(option.merchantId),
deliveryOptionId:
option.deliveryOptionId == null ? option.deliveryOptionId : toId(option.deliveryOptionId),
packageOptionId: option.packageOptionId == null ? option.packageOptionId : toId(option.packageOptionId),
}))
}
delete normalized.memberId
if (normalized.merchantId != null) {
normalized.merchantId = toMerchantId(normalized.merchantId)
@@ -131,7 +216,10 @@ export const normalizeMallAppPayload = <TPayload extends object>(payload: TPaylo
const normalizeGoodsSku = (sku: GoodsSkuInfo): GoodsSkuInfo => ({
...sku,
id: toId(sku.id),
spuId: String(sku.spuId),
merchantId: toMerchantId(sku.merchantId),
storeId: toId(sku.storeId),
})
const normalizeGoodsSummary = (goods: RawGoodsSummaryPayload): GoodsSummary => {
@@ -139,9 +227,12 @@ const normalizeGoodsSummary = (goods: RawGoodsSummaryPayload): GoodsSummary => {
return {
...normalized,
id: String(goods.spuId ?? goods.id ?? ''),
merchantId: toMerchantId(goods.merchantId),
merchantName: pickText(goods.merchantName),
merchantLogo: pickText(goods.merchantLogo),
storeId: toId(goods.storeId),
categoryId: toId(goods.categoryId),
createdAt: toUnixTime(goods.createdAt ?? goods.createAt ?? goods.created_at ?? goods.createTime ?? goods.create_time),
updatedAt: toUnixTime(goods.updatedAt ?? goods.updateAt ?? goods.updated_at ?? goods.updateTime ?? goods.update_time),
}
@@ -159,7 +250,10 @@ const normalizeRecentNewGoodsItem = (goods: RecentNewGoodsItem): RecentNewGoodsI
const normalizeGoodsDetailInfo = (detail: GoodsDetailInfo): GoodsDetailInfo => ({
...detail,
id: toId(detail.id),
merchantId: toMerchantId(detail.merchantId),
storeId: toId(detail.storeId),
categoryId: toId(detail.categoryId),
createdAt: toUnixTime(detail.createdAt),
updatedAt: toUnixTime(detail.updatedAt),
skus: (detail.skus ?? []).map(normalizeGoodsSku),
@@ -167,22 +261,104 @@ const normalizeGoodsDetailInfo = (detail: GoodsDetailInfo): GoodsDetailInfo => (
const normalizeCartItem = (item: CartItemInfo): CartItemInfo => ({
...item,
id: toId(item.id),
memberId: item.memberId == null ? undefined : toMerchantId(item.memberId),
merchantId: toMerchantId(item.merchantId),
merchantName: pickText(item.merchantName),
merchantLogo: pickText(item.merchantLogo),
storeId: toId(item.storeId),
spuId: String(item.spuId),
skuId: toId(item.skuId),
itemAmount:
item.itemAmount ??
(Number.isFinite(Number(item.salePrice)) && Number.isFinite(Number(item.buyNum))
? (Number(item.salePrice) * Number(item.buyNum)).toFixed(2)
: '0'),
})
const normalizeCartGoodsGroup = (goods: CartGoodsGroupInfo): CartGoodsGroupInfo => ({
...goods,
spuId: String(goods.spuId),
spuName: pickText(goods.spuName),
coverUrl: pickText(goods.coverUrl),
checked: Boolean(goods.checked),
goodsAmount: goods.goodsAmount ?? '0',
checkedAmount: goods.checkedAmount ?? '0',
items: (goods.items ?? []).map(normalizeCartItem),
})
const normalizeCartMerchantGroup = (group: CartMerchantGroupInfo): CartMerchantGroupInfo => ({
...group,
merchantId: toMerchantId(group.merchantId),
merchantName: pickText(group.merchantName) || '未命名商家',
merchantLogo: pickText(group.merchantLogo),
checked: Boolean(group.checked),
itemCount: toNumber(group.itemCount),
goodsCount: toNumber(group.goodsCount),
goodsAmount: group.goodsAmount ?? '0',
checkedAmount: group.checkedAmount ?? '0',
goods: (group.goods ?? []).map(normalizeCartGoodsGroup),
})
const normalizeTradePreviewItem = (item: TradePreviewItemInfo): TradePreviewItemInfo => ({
...item,
spuId: String(item.spuId),
skuId: toId(item.skuId),
})
const normalizeDeliveryOption = (option: MerchantDeliveryOptionInfo): MerchantDeliveryOptionInfo => ({
...option,
id: toId(option.id),
merchantId: toMerchantId(option.merchantId),
})
const normalizePackageOption = (option: MerchantPackageOptionInfo): MerchantPackageOptionInfo => ({
...option,
id: toId(option.id),
merchantId: toMerchantId(option.merchantId),
})
const normalizeTradePreviewGroup = (group: TradePreviewStoreInfo): TradePreviewStoreInfo => ({
...group,
merchantId: toMerchantId(group.merchantId),
storeId: group.storeId == null ? undefined : toId(group.storeId),
deliveryOptions: (group.deliveryOptions ?? []).map(normalizeDeliveryOption),
packageOptions: (group.packageOptions ?? []).map(normalizePackageOption),
selectedDeliveryOption: group.selectedDeliveryOption
? normalizeDeliveryOption(group.selectedDeliveryOption)
: undefined,
selectedPackageOption: group.selectedPackageOption ? normalizePackageOption(group.selectedPackageOption) : undefined,
items: (group.items ?? []).map(normalizeTradePreviewItem),
})
const normalizeOrderSummary = (order: OrderSummary): OrderSummary => ({
...order,
id: toId(order.id),
tradeId: toId(order.tradeId),
memberId: order.memberId == null ? undefined : toMerchantId(order.memberId),
merchantId: toMerchantId(order.merchantId),
storeId: toId(order.storeId),
})
const normalizeOrderDetailInfo = (order: OrderDetailInfo): OrderDetailInfo => ({
...order,
id: toId(order.id),
tradeId: toId(order.tradeId),
memberId: order.memberId == null ? undefined : toMerchantId(order.memberId),
merchantId: toMerchantId(order.merchantId),
storeId: toId(order.storeId),
selectedDeliveryOption: order.selectedDeliveryOption
? normalizeDeliveryOption(order.selectedDeliveryOption)
: undefined,
selectedPackageOption: order.selectedPackageOption ? normalizePackageOption(order.selectedPackageOption) : undefined,
items: (order.items ?? []).map(item => ({
...item,
id: toId(item.id),
orderId: toId(item.orderId),
tradeId: toId(item.tradeId),
spuId: String(item.spuId),
skuId: toId(item.skuId),
})),
})
const normalizeRecommendMerchant = (
@@ -194,6 +370,7 @@ const normalizeRecommendMerchant = (
return {
...(merchant as RecommendMerchantInfo),
id: toId(merchant.id ?? merchant.merchantId),
merchantId: toMerchantId(merchant.merchantId ?? merchant.id),
storeName: pickText(merchant.storeName, merchant.merchantName),
storeLogo: pickText(merchant.storeLogo, merchant.logo),
@@ -215,6 +392,7 @@ const normalizeMerchantEntity = (
return {
...(merchant as MerchantInfo),
id: toId(merchant.id ?? merchant.merchantId),
merchantId: toMerchantId(merchant.merchantId ?? merchant.id),
storeName: pickText(merchant.storeName, merchant.merchantName),
storeLogo: pickText(merchant.storeLogo, merchant.logo),
@@ -223,6 +401,26 @@ const normalizeMerchantEntity = (
}
}
const normalizeAddressInfo = (address: AppAddressListResponse['list'][number]) => ({
...address,
id: toId(address.id),
})
const normalizeBanner = (banner: AppHomeResponse['banners'][number]) => ({
...banner,
id: toId(banner.id),
})
const normalizeCategoryNav = (category: AppHomeResponse['categoryNavs'][number]) => ({
...category,
categoryId: toId(category.categoryId),
})
const normalizeChannel = (channel: AppHomeResponse['channels'][number]) => ({
...channel,
id: toId(channel.id),
})
const normalizeHomeMerchantGoodsBlock = (
block: HomeMerchantGoodsBlock | undefined
): HomeMerchantGoodsBlock | undefined => {
@@ -262,7 +460,40 @@ export const normalizeAppCartListResponse = (
payload: AppCartListResponse
): AppCartListResponse => ({
...payload,
list: payload.list.map(normalizeCartItem),
merchantGroups: (payload.merchantGroups ?? []).map(normalizeCartMerchantGroup),
itemCount: toNumber(payload.itemCount),
goodsCount: toNumber(payload.goodsCount),
goodsAmount: payload.goodsAmount ?? '0',
checkedCount: toNumber(payload.checkedCount),
checkedAmount: payload.checkedAmount ?? '0',
})
export const normalizeAppCartSaveResponse = (
payload: AppCartSaveResponse
): AppCartSaveResponse => ({
...payload,
cartId: toId(payload.cartId),
})
export const normalizeAppAddressListResponse = (
payload: AppAddressListResponse
): AppAddressListResponse => ({
...payload,
list: (payload.list ?? []).map(normalizeAddressInfo),
})
export const normalizeAppAddressSaveResponse = (
payload: AppAddressSaveResponse
): AppAddressSaveResponse => ({
...payload,
addressId: toId(payload.addressId),
})
export const normalizeAppAddressDefaultSetResponse = (
payload: AppAddressDefaultSetResponse
): AppAddressDefaultSetResponse => ({
...payload,
addressId: toId(payload.addressId),
})
export const normalizeAppOrderPageResponse = (
@@ -279,6 +510,20 @@ export const normalizeAppOrderDetailResponse = (
data: normalizeOrderDetailInfo(payload.data),
})
export const normalizeAppOrderConfirmResponse = (
payload: AppOrderConfirmResponse
): AppOrderConfirmResponse => ({
...payload,
orderId: toId(payload.orderId),
})
export const normalizeAppAfterSaleApplyResponse = (
payload: AppAfterSaleApplyResponse
): AppAfterSaleApplyResponse => ({
...payload,
afterSaleId: toId(payload.afterSaleId),
})
export const normalizeAppHomeResponse = (payload: AppHomeResponse): AppHomeResponse => {
const recommendMerchants = (payload.recommendMerchants ?? payload.recommendStores ?? [])
.map(normalizeRecommendMerchant)
@@ -289,6 +534,9 @@ export const normalizeAppHomeResponse = (payload: AppHomeResponse): AppHomeRespo
return {
...payload,
banners: (payload.banners ?? []).map(normalizeBanner),
categoryNavs: (payload.categoryNavs ?? []).map(normalizeCategoryNav),
channels: (payload.channels ?? []).map(normalizeChannel),
recommendGoods: payload.recommendGoods.map(normalizeGoodsSummary),
recommendMerchants,
featuredMerchants,
@@ -305,7 +553,7 @@ export const normalizeAppHomeMerchantGoodsResponse = (
normalizeHomeMerchantGoodsBlock(payload.data) ??
({
merchant: {
id: 0,
id: '0',
merchantId: '0',
storeName: '',
storeLogo: '',
@@ -319,7 +567,7 @@ export const normalizeAppHomeMerchantGoodsResponse = (
orderCount: 0,
},
store: {
id: 0,
id: '0',
merchantId: '0',
storeName: '',
storeLogo: '',
@@ -354,7 +602,7 @@ export const normalizeAppTradePreviewResponse = (
): AppTradePreviewResponse => {
const data = payload.data as TradePreviewInfo & {
uid?: number
memberId?: number
memberId?: MerchantId | number
merchantGroups?: TradePreviewInfo['merchantGroups']
storeGroups?: TradePreviewInfo['merchantGroups']
}
@@ -364,10 +612,24 @@ export const normalizeAppTradePreviewResponse = (
...payload,
data: {
...data,
uid: data.uid ?? data.memberId ?? 0,
memberId: data.memberId ?? data.uid,
addressId: toId(data.addressId),
uid: data.uid ?? 0,
memberId: data.memberId == null ? undefined : toMerchantId(data.memberId),
merchantGroups: merchantGroups.map(normalizeTradePreviewGroup),
storeGroups: merchantGroups.map(normalizeTradePreviewGroup),
},
}
}
export const normalizeAppTradeCreateResponse = (
payload: AppTradeCreateResponse
): AppTradeCreateResponse => ({
...payload,
tradeId: toId(payload.tradeId),
payUrl: pickText(payload.payUrl),
payExternal: toBoolean(payload.payExternal),
payExpiredAt: toUnixTime(payload.payExpiredAt),
payChannel: pickText(payload.payChannel),
paySubject: pickText(payload.paySubject),
orderIds: (payload.orderIds ?? []).map(toId),
})