1
This commit is contained in:
64
src/apis/mall-app/address.ts
Normal file
64
src/apis/mall-app/address.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import {
|
||||
APP_API_PATHS,
|
||||
normalizeAppAddressDefaultSetResponse,
|
||||
normalizeAppAddressListResponse,
|
||||
normalizeAppAddressSaveResponse,
|
||||
normalizeMallAppPayload,
|
||||
postMallApp,
|
||||
} from './shared'
|
||||
import type {
|
||||
AppAddressDefaultSetRequest,
|
||||
AppAddressDefaultSetResponse,
|
||||
AppAddressDeleteRequest,
|
||||
AppAddressDeleteResponse,
|
||||
AppAddressListRequest,
|
||||
AppAddressListResponse,
|
||||
AppAddressSaveRequest,
|
||||
AppAddressSaveResponse,
|
||||
} from '@/types/mall'
|
||||
|
||||
export const apiAppAddressList = async (payload: AppAddressListRequest, signal?: AbortSignal) => {
|
||||
const response = await postMallApp<AppAddressListResponse, AppAddressListRequest>(
|
||||
APP_API_PATHS.addressList,
|
||||
normalizeMallAppPayload(payload),
|
||||
signal
|
||||
)
|
||||
|
||||
return {
|
||||
...response,
|
||||
data: normalizeAppAddressListResponse(response.data),
|
||||
}
|
||||
}
|
||||
|
||||
export const apiAppAddressSave = async (payload: AppAddressSaveRequest, signal?: AbortSignal) => {
|
||||
const response = await postMallApp<AppAddressSaveResponse, AppAddressSaveRequest>(
|
||||
APP_API_PATHS.addressSave,
|
||||
normalizeMallAppPayload(payload),
|
||||
signal
|
||||
)
|
||||
|
||||
return {
|
||||
...response,
|
||||
data: normalizeAppAddressSaveResponse(response.data),
|
||||
}
|
||||
}
|
||||
|
||||
export const apiAppAddressDelete = (payload: AppAddressDeleteRequest, signal?: AbortSignal) =>
|
||||
postMallApp<AppAddressDeleteResponse, AppAddressDeleteRequest>(
|
||||
APP_API_PATHS.addressDelete,
|
||||
normalizeMallAppPayload(payload),
|
||||
signal
|
||||
)
|
||||
|
||||
export const apiAppAddressDefaultSet = async (payload: AppAddressDefaultSetRequest, signal?: AbortSignal) => {
|
||||
const response = await postMallApp<AppAddressDefaultSetResponse, AppAddressDefaultSetRequest>(
|
||||
APP_API_PATHS.addressDefaultSet,
|
||||
normalizeMallAppPayload(payload),
|
||||
signal
|
||||
)
|
||||
|
||||
return {
|
||||
...response,
|
||||
data: normalizeAppAddressDefaultSetResponse(response.data),
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,26 @@
|
||||
import { APP_API_PATHS, normalizeMallAppPayload, postMallApp } from './shared'
|
||||
import {
|
||||
APP_API_PATHS,
|
||||
normalizeAppAfterSaleApplyResponse,
|
||||
normalizeMallAppPayload,
|
||||
postMallApp,
|
||||
} from './shared'
|
||||
import type {
|
||||
AppAfterSaleApplyRequest,
|
||||
AppAfterSaleApplyResponse,
|
||||
} from '@/types/mall'
|
||||
|
||||
export const apiAppAfterSaleApply = (
|
||||
export const apiAppAfterSaleApply = async (
|
||||
payload: AppAfterSaleApplyRequest,
|
||||
signal?: AbortSignal
|
||||
) =>
|
||||
postMallApp<AppAfterSaleApplyResponse, AppAfterSaleApplyRequest>(
|
||||
) => {
|
||||
const response = await postMallApp<AppAfterSaleApplyResponse, AppAfterSaleApplyRequest>(
|
||||
APP_API_PATHS.afterSaleApply,
|
||||
normalizeMallAppPayload(payload),
|
||||
signal
|
||||
)
|
||||
|
||||
return {
|
||||
...response,
|
||||
data: normalizeAppAfterSaleApplyResponse(response.data),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import { APP_API_PATHS, normalizeAppCartListResponse, normalizeMallAppPayload, postMallApp } from './shared'
|
||||
import {
|
||||
APP_API_PATHS,
|
||||
normalizeAppCartListResponse,
|
||||
normalizeAppCartSaveResponse,
|
||||
normalizeMallAppPayload,
|
||||
postMallApp,
|
||||
} from './shared'
|
||||
import type {
|
||||
AppCartListRequest,
|
||||
AppCartListResponse,
|
||||
@@ -21,13 +27,19 @@ export const apiAppCartList = async (payload: AppCartListRequest, signal?: Abort
|
||||
}
|
||||
}
|
||||
|
||||
export const apiAppCartSave = (payload: AppCartSaveRequest, signal?: AbortSignal) =>
|
||||
postMallApp<AppCartSaveResponse, AppCartSaveRequest>(
|
||||
export const apiAppCartSave = async (payload: AppCartSaveRequest, signal?: AbortSignal) => {
|
||||
const response = await postMallApp<AppCartSaveResponse, AppCartSaveRequest>(
|
||||
APP_API_PATHS.cartSave,
|
||||
normalizeMallAppPayload(payload),
|
||||
signal
|
||||
)
|
||||
|
||||
return {
|
||||
...response,
|
||||
data: normalizeAppCartSaveResponse(response.data),
|
||||
}
|
||||
}
|
||||
|
||||
export const apiAppCartRemove = (payload: AppCartRemoveRequest, signal?: AbortSignal) =>
|
||||
postMallApp<AppCartRemoveResponse, AppCartRemoveRequest>(
|
||||
APP_API_PATHS.cartRemove,
|
||||
|
||||
@@ -2,6 +2,7 @@ export * from './shared'
|
||||
export * from './home'
|
||||
export * from './goods'
|
||||
export * from './cart'
|
||||
export * from './address'
|
||||
export * from './trade'
|
||||
export * from './order'
|
||||
export * from './afterSale'
|
||||
|
||||
@@ -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),
|
||||
})
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
APP_API_PATHS,
|
||||
normalizeAppOrderDetailResponse,
|
||||
normalizeAppOrderConfirmResponse,
|
||||
normalizeAppOrderPageResponse,
|
||||
normalizeMallAppPayload,
|
||||
postMallApp,
|
||||
@@ -40,9 +41,15 @@ export const apiAppOrderDetail = async (payload: AppOrderDetailRequest, signal?:
|
||||
}
|
||||
}
|
||||
|
||||
export const apiAppOrderConfirm = (payload: AppOrderConfirmRequest, signal?: AbortSignal) =>
|
||||
postMallApp<AppOrderConfirmResponse, AppOrderConfirmRequest>(
|
||||
export const apiAppOrderConfirm = async (payload: AppOrderConfirmRequest, signal?: AbortSignal) => {
|
||||
const response = await postMallApp<AppOrderConfirmResponse, AppOrderConfirmRequest>(
|
||||
APP_API_PATHS.orderConfirm,
|
||||
normalizeMallAppPayload(payload),
|
||||
signal
|
||||
)
|
||||
|
||||
return {
|
||||
...response,
|
||||
data: normalizeAppOrderConfirmResponse(response.data),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,10 @@ export const APP_API_PATHS = {
|
||||
cartList: '/api/v1/mall/app/cart_list',
|
||||
cartSave: '/api/v1/mall/app/cart_save',
|
||||
cartRemove: '/api/v1/mall/app/cart_remove',
|
||||
addressList: '/api/v1/mall/app/address_list',
|
||||
addressSave: '/api/v1/mall/app/address_save',
|
||||
addressDelete: '/api/v1/mall/app/address_delete',
|
||||
addressDefaultSet: '/api/v1/mall/app/address_default_set',
|
||||
tradePreview: '/api/v1/mall/app/trade_preview',
|
||||
tradeCreate: '/api/v1/mall/app/trade_create',
|
||||
orderPage: '/api/v1/mall/app/order_page',
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
APP_API_PATHS,
|
||||
normalizeAppTradeCreateResponse,
|
||||
normalizeAppTradePreviewResponse,
|
||||
normalizeMallAppPayload,
|
||||
postMallApp,
|
||||
@@ -24,9 +25,15 @@ export const apiAppTradePreview = async (payload: AppTradePreviewRequest, signal
|
||||
}
|
||||
}
|
||||
|
||||
export const apiAppTradeCreate = (payload: AppTradeCreateRequest, signal?: AbortSignal) =>
|
||||
postMallApp<AppTradeCreateResponse, AppTradeCreateRequest>(
|
||||
export const apiAppTradeCreate = async (payload: AppTradeCreateRequest, signal?: AbortSignal) => {
|
||||
const response = await postMallApp<AppTradeCreateResponse, AppTradeCreateRequest>(
|
||||
APP_API_PATHS.tradeCreate,
|
||||
normalizeMallAppPayload(payload),
|
||||
signal
|
||||
)
|
||||
|
||||
return {
|
||||
...response,
|
||||
data: normalizeAppTradeCreateResponse(response.data),
|
||||
}
|
||||
}
|
||||
|
||||
1591
src/index.css
1591
src/index.css
File diff suppressed because it is too large
Load Diff
@@ -152,10 +152,10 @@ const buildGoods = (seed: string[], index: number): GoodsSummary => {
|
||||
const price = 29 + index * 7
|
||||
|
||||
return {
|
||||
id: 10001 + index,
|
||||
id: String(10001 + index),
|
||||
merchantId: String(5001 + (index % 4)),
|
||||
storeId: 6001 + (index % 5),
|
||||
categoryId: index + 1,
|
||||
storeId: String(6001 + (index % 5)),
|
||||
categoryId: String(index + 1),
|
||||
categoryName: category.label,
|
||||
spuNo: `YTSPU${String(index + 1).padStart(4, '0')}`,
|
||||
spuName: seed[0],
|
||||
@@ -181,7 +181,7 @@ const buildStore = (seed: string[], index: number): RecommendMerchantInfo => {
|
||||
const category = MARKET_CATEGORIES[(index % (MARKET_CATEGORIES.length - 1)) + 1]
|
||||
|
||||
return {
|
||||
id: 9001 + index,
|
||||
id: String(9001 + index),
|
||||
merchantId: String(5001 + index),
|
||||
storeName: seed[0],
|
||||
storeLogo: createArtwork(seed[0], seed[1], category.accent, category.accentSoft),
|
||||
@@ -206,14 +206,14 @@ export const FALLBACK_GOODS_PAGE: AppGoodsPageResponse = {
|
||||
|
||||
export const FALLBACK_HOME: AppHomeResponse = {
|
||||
categoryNavs: MARKET_CATEGORIES.map((item, index) => ({
|
||||
categoryId: index + 1,
|
||||
categoryId: String(index + 1),
|
||||
categoryName: item.label,
|
||||
goodsCount: Math.max(0, goodsList.length - index),
|
||||
sort: index,
|
||||
})),
|
||||
banners: [
|
||||
{
|
||||
id: 1,
|
||||
id: '1',
|
||||
title: '精准搜款 · 一件代发',
|
||||
subTitle: '多平台供给与商家资源聚合',
|
||||
description: '首页主视觉广告栏',
|
||||
@@ -228,7 +228,7 @@ export const FALLBACK_HOME: AppHomeResponse = {
|
||||
endTime: 1730000000,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
id: '2',
|
||||
title: '热卖数码专场',
|
||||
subTitle: '快充、支架、耳机同步起量',
|
||||
description: '首页活动广告栏',
|
||||
@@ -245,7 +245,7 @@ export const FALLBACK_HOME: AppHomeResponse = {
|
||||
],
|
||||
searchKeywords: HOT_KEYWORDS,
|
||||
channels: PLATFORM_CHANNELS.map((item, index) => ({
|
||||
id: index + 1,
|
||||
id: String(index + 1),
|
||||
title: item.label,
|
||||
subTitle: item.subtitle,
|
||||
iconUrl: '',
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { useNavigate, useParams } from 'react-router-dom'
|
||||
import { apiAppGoodsDetail } from '@/apis'
|
||||
import { toast } from 'sonner'
|
||||
import { apiAppCartSave, apiAppGoodsDetail } from '@/apis'
|
||||
import MarketPageHeader from '@/components/MarketPageHeader'
|
||||
import { useUserStore } from '@/store/user'
|
||||
import type {
|
||||
@@ -58,12 +59,12 @@ const WHITE_IMAGE_KEYWORDS = ['white', 'wash', 'clean', 'plain', 'background', '
|
||||
|
||||
const getSpecValue = (sku: ResolvedGoodsSkuInfo, patterns: string[]) => {
|
||||
const matched = sku.specs.find(spec => {
|
||||
const name = typeof spec.name === 'string' ? spec.name : ''
|
||||
const name = typeof spec.attributeName === 'string' ? spec.attributeName : ''
|
||||
|
||||
return patterns.some(pattern => name.toLowerCase().includes(pattern.toLowerCase()))
|
||||
})
|
||||
|
||||
return typeof matched?.value === 'string' ? matched.value.trim() : ''
|
||||
return typeof matched?.attributeValue === 'string' ? matched.attributeValue.trim() : ''
|
||||
}
|
||||
|
||||
const splitSkuName = (skuName: string) =>
|
||||
@@ -175,14 +176,18 @@ const getProductParams = (detail: ResolvedGoodsDetailInfo): ParamItem[] => {
|
||||
].filter(item => item.value)
|
||||
}
|
||||
|
||||
const getSelectedCartItems = (skus: ResolvedGoodsSkuInfo[], quantities: Record<string, number>) =>
|
||||
skus
|
||||
.map(sku => ({
|
||||
sku,
|
||||
buyNum: Math.min(Math.max(0, quantities[sku.id] ?? 0), sku.stock),
|
||||
}))
|
||||
.filter(item => item.buyNum > 0)
|
||||
|
||||
function GoodsDetailPage() {
|
||||
const { spuId = '' } = useParams()
|
||||
const navigate = useNavigate()
|
||||
const token = useUserStore(state => state.token)
|
||||
const userInfo = useUserStore(state => state.userInfo)
|
||||
const storedMemberId = useUserStore(state => state.memberId)
|
||||
|
||||
const currentUid = userInfo?.uid ?? storedMemberId ?? token?.memberId ?? token?.uid ?? 0
|
||||
|
||||
const [payload, setPayload] = useState<AppGoodsDetailResponse | null>(null)
|
||||
const [loading, setLoading] = useState(true)
|
||||
@@ -191,7 +196,8 @@ function GoodsDetailPage() {
|
||||
const [keyword, setKeyword] = useState('')
|
||||
const [selectedColor, setSelectedColor] = useState('')
|
||||
const [activeDetailTab, setActiveDetailTab] = useState<DetailTabKey>('detail')
|
||||
const [quantities, setQuantities] = useState<Record<number, number>>({})
|
||||
const [quantities, setQuantities] = useState<Record<string, number>>({})
|
||||
const [cartSaving, setCartSaving] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (!spuId) {
|
||||
@@ -204,7 +210,7 @@ function GoodsDetailPage() {
|
||||
setLoading(true)
|
||||
setError(null)
|
||||
|
||||
apiAppGoodsDetail({ uid: currentUid, spuId }, controller.signal)
|
||||
apiAppGoodsDetail({ spuId }, controller.signal)
|
||||
.then(response => {
|
||||
setPayload(response.data)
|
||||
})
|
||||
@@ -220,7 +226,7 @@ function GoodsDetailPage() {
|
||||
})
|
||||
|
||||
return () => controller.abort()
|
||||
}, [currentUid, spuId])
|
||||
}, [spuId])
|
||||
|
||||
const detail = useMemo(() => (payload?.data ? resolveGoodsDetailInfo(payload.data) : null), [payload])
|
||||
const merchant = payload?.merchant ?? payload?.store ?? null
|
||||
@@ -273,6 +279,14 @@ function GoodsDetailPage() {
|
||||
return galleryImages
|
||||
}, [detailImages, galleryImages])
|
||||
const whiteImages = useMemo(() => (detail ? getWhiteImageList(detail) : []), [detail])
|
||||
const selectedCartItems = useMemo(
|
||||
() => getSelectedCartItems(detail?.skus ?? [], quantities),
|
||||
[detail, quantities]
|
||||
)
|
||||
const selectedCartTotal = useMemo(
|
||||
() => selectedCartItems.reduce((total, item) => total + item.buyNum, 0),
|
||||
[selectedCartItems]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
setActiveImage(galleryImages[0] ?? '')
|
||||
@@ -282,9 +296,9 @@ function GoodsDetailPage() {
|
||||
setSelectedColor(colorOptions[0]?.color ?? '')
|
||||
}, [colorOptions])
|
||||
|
||||
const updateQuantity = (skuId: number, delta: number) => {
|
||||
const updateQuantity = (skuId: string, delta: number, stock: number) => {
|
||||
setQuantities(current => {
|
||||
const nextValue = Math.max(0, (current[skuId] ?? 0) + delta)
|
||||
const nextValue = Math.min(stock, Math.max(0, (current[skuId] ?? 0) + delta))
|
||||
return {
|
||||
...current,
|
||||
[skuId]: nextValue,
|
||||
@@ -292,6 +306,36 @@ function GoodsDetailPage() {
|
||||
})
|
||||
}
|
||||
|
||||
const handleAddCart = async () => {
|
||||
if (!token?.accessToken) {
|
||||
navigate('/login')
|
||||
return
|
||||
}
|
||||
|
||||
if (selectedCartItems.length === 0) {
|
||||
toast.warning('请先选择要加入购物车的商品数量')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
setCartSaving(true)
|
||||
await Promise.all(
|
||||
selectedCartItems.map(item =>
|
||||
apiAppCartSave({
|
||||
skuId: item.sku.id,
|
||||
buyNum: item.buyNum,
|
||||
checked: true,
|
||||
})
|
||||
)
|
||||
)
|
||||
toast.success(`已加入购物车 ${selectedCartTotal} 件商品`)
|
||||
} catch (nextError) {
|
||||
toast.error(nextError instanceof Error ? nextError.message : '加入购物车失败')
|
||||
} finally {
|
||||
setCartSaving(false)
|
||||
}
|
||||
}
|
||||
|
||||
const handleHeaderSearch = (nextKeyword: string) => {
|
||||
const trimmedKeyword = nextKeyword.trim()
|
||||
navigate(trimmedKeyword ? `/list/new?key=${encodeURIComponent(trimmedKeyword)}` : '/list/new')
|
||||
@@ -425,11 +469,15 @@ function GoodsDetailPage() {
|
||||
<strong>{formatMoney(option.sku.salePrice || detail.minPrice)}</strong>
|
||||
<small>库存 {option.sku.stock}</small>
|
||||
<div>
|
||||
<button type="button" onClick={() => updateQuantity(option.sku.id, -1)}>
|
||||
<button type="button" onClick={() => updateQuantity(option.sku.id, -1, option.sku.stock)}>
|
||||
-
|
||||
</button>
|
||||
<b>{quantities[option.sku.id] ?? 0}</b>
|
||||
<button type="button" onClick={() => updateQuantity(option.sku.id, 1)}>
|
||||
<button
|
||||
type="button"
|
||||
disabled={option.sku.stock <= 0 || (quantities[option.sku.id] ?? 0) >= option.sku.stock}
|
||||
onClick={() => updateQuantity(option.sku.id, 1, option.sku.stock)}
|
||||
>
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
@@ -440,6 +488,27 @@ function GoodsDetailPage() {
|
||||
) : (
|
||||
<div className="market-empty-state">暂无 SKU 信息</div>
|
||||
)}
|
||||
|
||||
{detail.skus.length > 0 ? (
|
||||
<div className="market-detail-cart-actions">
|
||||
<button
|
||||
className="market-detail-cart-actions__primary"
|
||||
type="button"
|
||||
disabled={cartSaving}
|
||||
onClick={() => void handleAddCart()}
|
||||
>
|
||||
{cartSaving ? '加入中...' : '加入购物车'}
|
||||
</button>
|
||||
<button
|
||||
className="market-detail-cart-actions__ghost"
|
||||
type="button"
|
||||
onClick={() => navigate('/member?tab=cart')}
|
||||
>
|
||||
查看购物车
|
||||
</button>
|
||||
{selectedCartTotal > 0 ? <span>已选 {selectedCartTotal} 件</span> : null}
|
||||
</div>
|
||||
) : null}
|
||||
</section>
|
||||
|
||||
<aside
|
||||
|
||||
@@ -4,7 +4,6 @@ import { toast } from 'sonner'
|
||||
import { apiAppGoodsPage, apiAppHome, apiAppRecentNewGoods } from '@/apis'
|
||||
import MarketPageHeader from '@/components/MarketPageHeader'
|
||||
import type { MarketNavKey } from '@/components/MarketNav'
|
||||
import { useUserStore } from '@/store/user'
|
||||
import type {
|
||||
AppGoodsPageResponse,
|
||||
AppHomeResponse,
|
||||
@@ -150,11 +149,7 @@ function HomePage() {
|
||||
const navigate = useNavigate()
|
||||
const location = useLocation()
|
||||
const [searchParams] = useSearchParams()
|
||||
const token = useUserStore(state => state.token)
|
||||
const userInfo = useUserStore(state => state.userInfo)
|
||||
const storedMemberId = useUserStore(state => state.memberId)
|
||||
|
||||
const currentUid = userInfo?.uid ?? storedMemberId ?? token?.memberId ?? token?.uid ?? 0
|
||||
const initialSearchKeyword = searchParams.get('key')?.trim() ?? ''
|
||||
const isInitialSearchPage = location.pathname === '/list/new' || Boolean(initialSearchKeyword)
|
||||
|
||||
@@ -193,7 +188,7 @@ function HomePage() {
|
||||
setHomeLoading(true)
|
||||
|
||||
try {
|
||||
const response = await apiAppHome({ uid: currentUid })
|
||||
const response = await apiAppHome()
|
||||
|
||||
if (canceled) {
|
||||
return
|
||||
@@ -221,7 +216,7 @@ function HomePage() {
|
||||
return () => {
|
||||
canceled = true
|
||||
}
|
||||
}, [currentUid])
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
let canceled = false
|
||||
@@ -231,7 +226,6 @@ function HomePage() {
|
||||
|
||||
try {
|
||||
const response = await apiAppRecentNewGoods({
|
||||
uid: currentUid,
|
||||
page: 1,
|
||||
size: RECENT_GOODS_PAGE_SIZE,
|
||||
})
|
||||
@@ -262,7 +256,7 @@ function HomePage() {
|
||||
return () => {
|
||||
canceled = true
|
||||
}
|
||||
}, [currentUid, recentNewGoodsRefreshKey])
|
||||
}, [recentNewGoodsRefreshKey])
|
||||
|
||||
useEffect(() => {
|
||||
let canceled = false
|
||||
@@ -272,7 +266,6 @@ function HomePage() {
|
||||
|
||||
try {
|
||||
const response = await apiAppGoodsPage({
|
||||
uid: currentUid,
|
||||
keyword: submittedKeyword || undefined,
|
||||
sortType,
|
||||
page: 1,
|
||||
@@ -305,7 +298,7 @@ function HomePage() {
|
||||
return () => {
|
||||
canceled = true
|
||||
}
|
||||
}, [currentUid, sortType, submittedKeyword])
|
||||
}, [sortType, submittedKeyword])
|
||||
|
||||
const banners = useMemo(() => resolveHomeTopBanners(homePayload), [homePayload])
|
||||
const recommendStores = useMemo(() => resolveHomeRankStores(homePayload), [homePayload])
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,6 @@ import { useEffect, useMemo, useState } from 'react'
|
||||
import { Link, useNavigate, useParams } from 'react-router-dom'
|
||||
import { apiAppGoodsPage, apiAppHomeMerchantGoods } from '@/apis'
|
||||
import MarketPageHeader from '@/components/MarketPageHeader'
|
||||
import { useUserStore } from '@/store/user'
|
||||
import type { AppGoodsPageResponse, HomeMerchantGoodsBlock, GoodsSortType, GoodsSummary } from '@/types/mall'
|
||||
|
||||
const GOODS_SORT_OPTIONS: Array<{ key: GoodsSortType; label: string }> = [
|
||||
@@ -36,11 +35,6 @@ const formatPrice = (item: GoodsSummary) => {
|
||||
function ShopPage() {
|
||||
const { merchantId = '' } = useParams()
|
||||
const navigate = useNavigate()
|
||||
const token = useUserStore(state => state.token)
|
||||
const userInfo = useUserStore(state => state.userInfo)
|
||||
const storedMemberId = useUserStore(state => state.memberId)
|
||||
|
||||
const currentUid = userInfo?.uid ?? storedMemberId ?? token?.memberId ?? token?.uid ?? 0
|
||||
|
||||
const [headerKeyword, setHeaderKeyword] = useState('')
|
||||
const [keyword, setKeyword] = useState('')
|
||||
@@ -61,14 +55,14 @@ function ShopPage() {
|
||||
const controller = new AbortController()
|
||||
setError(null)
|
||||
|
||||
apiAppHomeMerchantGoods({ uid: currentUid, merchantId, limit: 12 }, controller.signal)
|
||||
apiAppHomeMerchantGoods({ merchantId, limit: 12 }, controller.signal)
|
||||
.then(response => {
|
||||
setMerchantBlock(response.data.data)
|
||||
})
|
||||
.catch(() => undefined)
|
||||
|
||||
return () => controller.abort()
|
||||
}, [currentUid, merchantId])
|
||||
}, [merchantId])
|
||||
|
||||
useEffect(() => {
|
||||
if (!merchantId) {
|
||||
@@ -81,7 +75,6 @@ function ShopPage() {
|
||||
|
||||
apiAppGoodsPage(
|
||||
{
|
||||
uid: currentUid,
|
||||
merchantId,
|
||||
keyword: searchKeyword || undefined,
|
||||
sortType,
|
||||
@@ -105,7 +98,7 @@ function ShopPage() {
|
||||
})
|
||||
|
||||
return () => controller.abort()
|
||||
}, [currentUid, merchantId, searchKeyword, sortType])
|
||||
}, [merchantId, searchKeyword, sortType])
|
||||
|
||||
const goodsList = useMemo(() => goodsPayload?.list ?? merchantBlock?.goods ?? [], [goodsPayload, merchantBlock])
|
||||
const merchant = merchantBlock?.merchant ?? merchantBlock?.store ?? null
|
||||
|
||||
@@ -48,8 +48,8 @@ export interface DetailJson {
|
||||
}
|
||||
|
||||
export interface SpecItem {
|
||||
name: string
|
||||
value: string
|
||||
attributeName: string
|
||||
attributeValue: string
|
||||
}
|
||||
|
||||
export interface ParamItem {
|
||||
@@ -74,7 +74,7 @@ export interface ExtraInfoJson {
|
||||
}
|
||||
|
||||
export interface StoreInfo {
|
||||
id: number
|
||||
id: string
|
||||
merchantId: MerchantId
|
||||
merchantName?: string
|
||||
logo?: string
|
||||
@@ -102,10 +102,10 @@ export interface StoreInfo {
|
||||
export type MerchantInfo = StoreInfo
|
||||
|
||||
export interface GoodsSkuInfo {
|
||||
id: number
|
||||
spuId: number
|
||||
id: string
|
||||
spuId: string
|
||||
merchantId: MerchantId
|
||||
storeId: number
|
||||
storeId: string
|
||||
skuNo: string
|
||||
skuName: string
|
||||
barcode: string
|
||||
@@ -124,12 +124,12 @@ export interface GoodsSkuInfo {
|
||||
}
|
||||
|
||||
export interface GoodsSummary {
|
||||
id: number
|
||||
id: string
|
||||
merchantId: MerchantId
|
||||
merchantName?: string
|
||||
merchantLogo?: string
|
||||
storeId: number
|
||||
categoryId: number
|
||||
storeId: string
|
||||
categoryId: string
|
||||
categoryName: string
|
||||
spuNo: string
|
||||
spuName: string
|
||||
@@ -151,10 +151,10 @@ export interface GoodsSummary {
|
||||
}
|
||||
|
||||
export interface GoodsDetailInfo {
|
||||
id: number
|
||||
id: string
|
||||
merchantId: MerchantId
|
||||
storeId: number
|
||||
categoryId: number
|
||||
storeId: string
|
||||
categoryId: string
|
||||
categoryName?: string
|
||||
spuNo: string
|
||||
spuName: string
|
||||
@@ -182,13 +182,15 @@ export interface GoodsDetailInfo {
|
||||
}
|
||||
|
||||
export interface CartItemInfo {
|
||||
id: number
|
||||
id: string
|
||||
uid: number
|
||||
memberId?: number
|
||||
memberId?: MerchantId
|
||||
merchantId: MerchantId
|
||||
storeId: number
|
||||
spuId: number
|
||||
skuId: number
|
||||
merchantName?: string
|
||||
merchantLogo?: string
|
||||
storeId: string
|
||||
spuId: string
|
||||
skuId: string
|
||||
spuName: string
|
||||
skuName: string
|
||||
coverUrl: string
|
||||
@@ -196,19 +198,91 @@ export interface CartItemInfo {
|
||||
buyNum: number
|
||||
checked: boolean
|
||||
salePrice: string
|
||||
itemAmount: string
|
||||
status: CartItemStatus
|
||||
createdAt: number
|
||||
updatedAt: number
|
||||
}
|
||||
|
||||
export interface CartGoodsGroupInfo {
|
||||
spuId: string
|
||||
spuName: string
|
||||
coverUrl: string
|
||||
checked: boolean
|
||||
goodsAmount?: string
|
||||
checkedAmount?: string
|
||||
items: CartItemInfo[]
|
||||
}
|
||||
|
||||
export interface CartMerchantGroupInfo {
|
||||
merchantId: MerchantId
|
||||
merchantName: string
|
||||
merchantLogo: string
|
||||
checked: boolean
|
||||
itemCount?: number
|
||||
goodsCount?: number
|
||||
goodsAmount?: string
|
||||
checkedAmount?: string
|
||||
goods: CartGoodsGroupInfo[]
|
||||
}
|
||||
|
||||
export interface UserAddressInfo {
|
||||
id: string
|
||||
uid: number
|
||||
receiverName: string
|
||||
receiverMobile: string
|
||||
countryCode: string
|
||||
province: string
|
||||
city: string
|
||||
district: string
|
||||
addressDetail: string
|
||||
zipCode: string
|
||||
tag: string
|
||||
isDefault: boolean
|
||||
createdAt: number
|
||||
updatedAt: number
|
||||
}
|
||||
|
||||
export interface TradeBuyItem {
|
||||
skuId: number
|
||||
skuId: string
|
||||
buyNum: number
|
||||
}
|
||||
|
||||
export interface TradeMerchantOptionInput {
|
||||
merchantId: MerchantId
|
||||
deliveryOptionId?: string
|
||||
packageOptionId?: string
|
||||
}
|
||||
|
||||
export interface MerchantDeliveryOptionInfo {
|
||||
id: string
|
||||
merchantId: MerchantId
|
||||
optionName: string
|
||||
deliveryCode: string
|
||||
feeAmount: string
|
||||
description: string
|
||||
sort: number
|
||||
status: EnabledStatus
|
||||
createdAt: number
|
||||
updatedAt: number
|
||||
}
|
||||
|
||||
export interface MerchantPackageOptionInfo {
|
||||
id: string
|
||||
merchantId: MerchantId
|
||||
optionName: string
|
||||
packageCode: string
|
||||
feeAmount: string
|
||||
description: string
|
||||
sort: number
|
||||
status: EnabledStatus
|
||||
createdAt: number
|
||||
updatedAt: number
|
||||
}
|
||||
|
||||
export interface TradePreviewItemInfo {
|
||||
spuId: number
|
||||
skuId: number
|
||||
spuId: string
|
||||
skuId: string
|
||||
spuName: string
|
||||
skuName: string
|
||||
coverUrl: string
|
||||
@@ -220,19 +294,25 @@ export interface TradePreviewItemInfo {
|
||||
|
||||
export interface TradePreviewStoreInfo {
|
||||
merchantId: MerchantId
|
||||
storeId: number
|
||||
storeName: string
|
||||
merchantName: string
|
||||
storeId?: string
|
||||
storeName?: string
|
||||
goodsAmount: string
|
||||
freightAmount: string
|
||||
packageAmount: string
|
||||
discountAmount: string
|
||||
payAmount: string
|
||||
deliveryOptions: MerchantDeliveryOptionInfo[]
|
||||
packageOptions: MerchantPackageOptionInfo[]
|
||||
selectedDeliveryOption?: MerchantDeliveryOptionInfo
|
||||
selectedPackageOption?: MerchantPackageOptionInfo
|
||||
items: TradePreviewItemInfo[]
|
||||
}
|
||||
|
||||
export interface TradePreviewInfo {
|
||||
uid: number
|
||||
memberId?: number
|
||||
addressId: number
|
||||
memberId?: MerchantId
|
||||
addressId: string
|
||||
receiverName: string
|
||||
receiverMobile: string
|
||||
receiverCountryCode: string
|
||||
@@ -245,6 +325,7 @@ export interface TradePreviewInfo {
|
||||
currency: string
|
||||
goodsAmount: string
|
||||
freightAmount: string
|
||||
packageAmount: string
|
||||
discountAmount: string
|
||||
payAmount: string
|
||||
orderCount: number
|
||||
@@ -253,12 +334,12 @@ export interface TradePreviewInfo {
|
||||
}
|
||||
|
||||
export interface OrderItemInfo {
|
||||
id: number
|
||||
orderId: number
|
||||
tradeId: number
|
||||
id: string
|
||||
orderId: string
|
||||
tradeId: string
|
||||
orderNo: string
|
||||
spuId: number
|
||||
skuId: number
|
||||
spuId: string
|
||||
skuId: string
|
||||
spuName: string
|
||||
skuName: string
|
||||
coverUrl: string
|
||||
@@ -273,20 +354,21 @@ export interface OrderItemInfo {
|
||||
}
|
||||
|
||||
export interface OrderSummary {
|
||||
id: number
|
||||
tradeId: number
|
||||
id: string
|
||||
tradeId: string
|
||||
tradeNo: string
|
||||
orderNo: string
|
||||
uid: number
|
||||
memberId?: number
|
||||
memberId?: MerchantId
|
||||
merchantId: MerchantId
|
||||
storeId: number
|
||||
storeId: string
|
||||
storeName: string
|
||||
orderStatus: OrderStatus
|
||||
afterSaleStatus: AfterSaleStatus
|
||||
currency: string
|
||||
goodsAmount: string
|
||||
freightAmount: string
|
||||
packageAmount: string
|
||||
discountAmount: string
|
||||
payAmount: string
|
||||
payTime: number
|
||||
@@ -298,20 +380,21 @@ export interface OrderSummary {
|
||||
}
|
||||
|
||||
export interface OrderDetailInfo {
|
||||
id: number
|
||||
tradeId: number
|
||||
id: string
|
||||
tradeId: string
|
||||
tradeNo: string
|
||||
orderNo: string
|
||||
uid: number
|
||||
memberId?: number
|
||||
memberId?: MerchantId
|
||||
merchantId: MerchantId
|
||||
storeId: number
|
||||
storeId: string
|
||||
storeName: string
|
||||
orderStatus: OrderStatus
|
||||
afterSaleStatus: AfterSaleStatus
|
||||
currency: string
|
||||
goodsAmount: string
|
||||
freightAmount: string
|
||||
packageAmount: string
|
||||
discountAmount: string
|
||||
payAmount: string
|
||||
buyerRemark: string
|
||||
@@ -327,6 +410,8 @@ export interface OrderDetailInfo {
|
||||
deliveryCompany: string
|
||||
deliveryNo: string
|
||||
payChannel: string
|
||||
selectedDeliveryOption?: MerchantDeliveryOptionInfo
|
||||
selectedPackageOption?: MerchantPackageOptionInfo
|
||||
extraInfoJson: string
|
||||
payTime: number
|
||||
shipTime: number
|
||||
@@ -339,7 +424,7 @@ export interface OrderDetailInfo {
|
||||
}
|
||||
|
||||
export interface BannerInfo {
|
||||
id: number
|
||||
id: string
|
||||
title: string
|
||||
subTitle: string
|
||||
description: string
|
||||
@@ -355,14 +440,14 @@ export interface BannerInfo {
|
||||
}
|
||||
|
||||
export interface HomeCategoryNav {
|
||||
categoryId: number
|
||||
categoryId: string
|
||||
categoryName: string
|
||||
goodsCount: number
|
||||
sort: number
|
||||
}
|
||||
|
||||
export interface HomeChannelCard {
|
||||
id: number
|
||||
id: string
|
||||
title: string
|
||||
subTitle: string
|
||||
iconUrl: string
|
||||
@@ -373,7 +458,7 @@ export interface HomeChannelCard {
|
||||
}
|
||||
|
||||
export interface RecommendStoreInfo {
|
||||
id: string | number
|
||||
id: string
|
||||
merchantId: MerchantId
|
||||
storeName: string
|
||||
storeLogo: string
|
||||
@@ -439,9 +524,7 @@ export interface ResolvedOrderDetailInfo extends OrderDetailInfo {
|
||||
}
|
||||
|
||||
export interface AppHomeRequest {
|
||||
uid?: number
|
||||
/** @deprecated use uid */
|
||||
memberId?: number
|
||||
memberId?: MerchantId
|
||||
}
|
||||
|
||||
export interface AppHomeResponse {
|
||||
@@ -470,9 +553,7 @@ export interface RecentNewGoodsItem {
|
||||
}
|
||||
|
||||
export interface AppRecentNewGoodsRequest {
|
||||
uid?: number
|
||||
/** @deprecated use uid */
|
||||
memberId?: number
|
||||
memberId?: MerchantId
|
||||
page?: number
|
||||
size?: number
|
||||
}
|
||||
@@ -483,12 +564,10 @@ export interface AppRecentNewGoodsResponse {
|
||||
}
|
||||
|
||||
export interface AppHomeMerchantGoodsRequest {
|
||||
uid?: number
|
||||
/** @deprecated use uid */
|
||||
memberId?: number
|
||||
memberId?: MerchantId
|
||||
merchantId?: MerchantId
|
||||
/** @deprecated use merchantId */
|
||||
storeId?: number
|
||||
storeId?: string
|
||||
limit?: number
|
||||
}
|
||||
|
||||
@@ -497,13 +576,11 @@ export interface AppHomeMerchantGoodsResponse {
|
||||
}
|
||||
|
||||
export interface AppGoodsPageRequest extends IPageParams {
|
||||
uid?: number
|
||||
/** @deprecated use uid */
|
||||
memberId?: number
|
||||
memberId?: MerchantId
|
||||
merchantId?: MerchantId
|
||||
/** @deprecated use merchantId */
|
||||
storeId?: number
|
||||
categoryId?: number
|
||||
storeId?: string
|
||||
categoryId?: string
|
||||
keyword?: string
|
||||
sortType?: GoodsSortType
|
||||
}
|
||||
@@ -514,10 +591,8 @@ export interface AppGoodsPageResponse {
|
||||
}
|
||||
|
||||
export interface AppGoodsDetailRequest {
|
||||
uid?: number
|
||||
/** @deprecated use uid */
|
||||
memberId?: number
|
||||
spuId: number | string
|
||||
memberId?: MerchantId
|
||||
spuId: string
|
||||
}
|
||||
|
||||
export interface AppGoodsDetailResponse {
|
||||
@@ -528,50 +603,86 @@ export interface AppGoodsDetailResponse {
|
||||
}
|
||||
|
||||
export interface AppCartListRequest {
|
||||
uid?: number
|
||||
/** @deprecated use uid */
|
||||
memberId?: number
|
||||
memberId?: MerchantId
|
||||
}
|
||||
|
||||
export interface AppCartListResponse {
|
||||
list: CartItemInfo[]
|
||||
merchantGroups: CartMerchantGroupInfo[]
|
||||
itemCount: number
|
||||
goodsCount: number
|
||||
goodsAmount: string
|
||||
checkedCount: number
|
||||
checkedAmount: string
|
||||
}
|
||||
|
||||
export interface AppCartSaveRequest {
|
||||
uid?: number
|
||||
/** @deprecated use uid */
|
||||
memberId?: number
|
||||
skuId: number
|
||||
memberId?: MerchantId
|
||||
skuId: string
|
||||
buyNum: number
|
||||
checked: boolean
|
||||
}
|
||||
|
||||
export interface AppCartSaveResponse {
|
||||
cartId: number
|
||||
cartId: string
|
||||
buyNum: number
|
||||
checked: boolean
|
||||
}
|
||||
|
||||
export interface AppCartRemoveRequest {
|
||||
uid?: number
|
||||
/** @deprecated use uid */
|
||||
memberId?: number
|
||||
skuIds: number[]
|
||||
memberId?: MerchantId
|
||||
skuIds: string[]
|
||||
}
|
||||
|
||||
export interface AppCartRemoveResponse {
|
||||
removedCount: number
|
||||
}
|
||||
|
||||
export type AppAddressListRequest = Record<string, never>
|
||||
|
||||
export interface AppAddressListResponse {
|
||||
list: UserAddressInfo[]
|
||||
}
|
||||
|
||||
export interface AppAddressSaveRequest {
|
||||
id?: string
|
||||
receiverName: string
|
||||
receiverMobile: string
|
||||
countryCode?: string
|
||||
province?: string
|
||||
city?: string
|
||||
district?: string
|
||||
addressDetail: string
|
||||
zipCode?: string
|
||||
tag?: string
|
||||
isDefault?: boolean
|
||||
}
|
||||
|
||||
export interface AppAddressSaveResponse {
|
||||
addressId: string
|
||||
}
|
||||
|
||||
export interface AppAddressDeleteRequest {
|
||||
addressId: string
|
||||
}
|
||||
|
||||
export interface AppAddressDeleteResponse {
|
||||
removedCount: number
|
||||
}
|
||||
|
||||
export interface AppAddressDefaultSetRequest {
|
||||
addressId: string
|
||||
}
|
||||
|
||||
export interface AppAddressDefaultSetResponse {
|
||||
addressId: string
|
||||
}
|
||||
|
||||
export interface AppTradePreviewRequest {
|
||||
uid?: number
|
||||
/** @deprecated use uid */
|
||||
memberId?: number
|
||||
memberId?: MerchantId
|
||||
buyItems?: TradeBuyItem[]
|
||||
addressId: number
|
||||
addressId: string
|
||||
buyerRemark?: string
|
||||
merchantOptions?: TradeMerchantOptionInput[]
|
||||
}
|
||||
|
||||
export interface AppTradePreviewResponse {
|
||||
@@ -579,30 +690,32 @@ export interface AppTradePreviewResponse {
|
||||
}
|
||||
|
||||
export interface AppTradeCreateRequest {
|
||||
uid?: number
|
||||
/** @deprecated use uid */
|
||||
memberId?: number
|
||||
memberId?: MerchantId
|
||||
buyItems?: TradeBuyItem[]
|
||||
addressId: number
|
||||
addressId: string
|
||||
buyerRemark?: string
|
||||
payChannel: string
|
||||
merchantOptions?: TradeMerchantOptionInput[]
|
||||
}
|
||||
|
||||
export interface AppTradeCreateResponse {
|
||||
tradeId: number
|
||||
tradeId: string
|
||||
tradeNo: string
|
||||
payStatus: PayStatus
|
||||
tradeStatus: TradeStatus
|
||||
payAmount: string
|
||||
expiredAt: number
|
||||
orderIds: number[]
|
||||
payUrl?: string
|
||||
payExternal?: boolean
|
||||
payExpiredAt?: number
|
||||
payChannel?: string
|
||||
paySubject?: string
|
||||
orderIds: string[]
|
||||
orderNos: string[]
|
||||
}
|
||||
|
||||
export interface AppOrderPageRequest extends IPageParams {
|
||||
uid?: number
|
||||
/** @deprecated use uid */
|
||||
memberId?: number
|
||||
memberId?: MerchantId
|
||||
orderStatus?: OrderStatus
|
||||
afterSaleStatus?: AfterSaleStatus
|
||||
}
|
||||
@@ -613,10 +726,8 @@ export interface AppOrderPageResponse {
|
||||
}
|
||||
|
||||
export interface AppOrderDetailRequest {
|
||||
uid?: number
|
||||
/** @deprecated use uid */
|
||||
memberId?: number
|
||||
orderId: number
|
||||
memberId?: MerchantId
|
||||
orderId: string
|
||||
}
|
||||
|
||||
export interface AppOrderDetailResponse {
|
||||
@@ -624,24 +735,20 @@ export interface AppOrderDetailResponse {
|
||||
}
|
||||
|
||||
export interface AppOrderConfirmRequest {
|
||||
uid?: number
|
||||
/** @deprecated use uid */
|
||||
memberId?: number
|
||||
orderId: number
|
||||
memberId?: MerchantId
|
||||
orderId: string
|
||||
}
|
||||
|
||||
export interface AppOrderConfirmResponse {
|
||||
orderId: number
|
||||
orderId: string
|
||||
orderStatus: OrderStatus
|
||||
finishTime: number
|
||||
}
|
||||
|
||||
export interface AppAfterSaleApplyRequest {
|
||||
uid?: number
|
||||
/** @deprecated use uid */
|
||||
memberId?: number
|
||||
orderId: number
|
||||
orderItemId: number
|
||||
memberId?: MerchantId
|
||||
orderId: string
|
||||
orderItemId: string
|
||||
afterSaleType: AfterSaleType
|
||||
reason: string
|
||||
description?: string
|
||||
@@ -650,7 +757,7 @@ export interface AppAfterSaleApplyRequest {
|
||||
}
|
||||
|
||||
export interface AppAfterSaleApplyResponse {
|
||||
afterSaleId: number
|
||||
afterSaleId: string
|
||||
afterSaleNo: string
|
||||
afterSaleStatus: Exclude<AfterSaleStatus, 'none'>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user