bug:订单详情问题修复
This commit is contained in:
parent
bb958ce2fe
commit
c4f85aa9dc
@ -1,46 +1,72 @@
|
|||||||
export type PrDetailType = {
|
export type ProductDetailType = {
|
||||||
adminCategoryId1: 146
|
adminCategoryId1: number
|
||||||
adminCategoryId2: 147
|
adminCategoryId2: number
|
||||||
appCategoryId1: 48
|
appCategoryId1: number
|
||||||
appCategoryId2: 56
|
appCategoryId2: number
|
||||||
createTime: 1762760434000
|
createTime: number
|
||||||
defaultSort: 0
|
defaultSort: number
|
||||||
frontPage: 1
|
frontPage: number
|
||||||
id: 73
|
id: number
|
||||||
isDelete: 0
|
isDelete: number
|
||||||
isFlash: 0
|
isFlash: number
|
||||||
isNew: 1
|
isNew: number
|
||||||
isTest: 0
|
isTest: number
|
||||||
mainImageUrl: 'https://heyuimage.ihzhy.com/prd/202511/9a77567562f87caf.jpg?key=xxxxxxx'
|
mainImageUrl: string
|
||||||
modifyTime: 1762760434000
|
modifyTime: number
|
||||||
realSaleCount: 0
|
realSaleCount: number
|
||||||
showPromotionPrice: 0
|
showPromotionPrice: number
|
||||||
showSaleCount: 0
|
showSaleCount: number
|
||||||
showSalePrice: 0
|
showSalePrice: number
|
||||||
status: 'online'
|
status: string
|
||||||
title: 'Akoya双珠海水戒指'
|
title: string
|
||||||
vvSkuList: SkuType[]
|
vvSkuList: SkuType[]
|
||||||
vvProductDetailList: []
|
vvProductDetailList: ProductDetailImagesType[]
|
||||||
vvProductPropertyList: []
|
vvProductPropertyList: ProudictProductPropertyType[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SkuType = {
|
export type SkuType = {
|
||||||
createTime: number
|
createTime: number
|
||||||
id: 364
|
id: number
|
||||||
isDelete: 0
|
isDelete: number
|
||||||
modifyTime: 1762760434000
|
modifyTime: number
|
||||||
productId: 73
|
productId: number
|
||||||
promotionPrice: 0
|
promotionPrice: number
|
||||||
showSaleCount: 0
|
showSaleCount: number
|
||||||
stock: 0
|
stock: number
|
||||||
|
imageUrl: string
|
||||||
|
salePrice: number
|
||||||
|
vvSkuPropertyValueList: SkuPropretyType[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SkuPropretyType = {
|
||||||
|
createTime: number
|
||||||
|
id: number
|
||||||
|
isDelete: number
|
||||||
|
modifyTime: number
|
||||||
|
productId: number
|
||||||
|
productPropertyName: string
|
||||||
|
productPropertyValue: string
|
||||||
|
skuId: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ProductDetailImagesType = {
|
export type ProductDetailImagesType = {
|
||||||
createTime: 1762760434000
|
createTime: number
|
||||||
detail: 'https://heyuimage.ihzhy.com/prd/202511/304182481ebfc9ab.jpg?key=xxxxxxx'
|
detail: string
|
||||||
id: 187
|
id: number
|
||||||
isDelete: 0
|
isDelete: number
|
||||||
modifyTime: 1762760434000
|
modifyTime: number
|
||||||
productId: 73
|
productId: number
|
||||||
type: 1
|
type: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ProudictProductPropertyType = {
|
||||||
|
createTime: number
|
||||||
|
defaultSort: number
|
||||||
|
id: number
|
||||||
|
isDelete: number
|
||||||
|
modifyTime: number
|
||||||
|
productId: number
|
||||||
|
productPropertyName: string
|
||||||
|
vvProductPropertyList?: ProudictProductPropertyType[] // 如需树状结构可用此字段
|
||||||
|
vvProductPropertyValueList: ProudictProductPropertyType[] // 按你原写法保持不变
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,8 +15,8 @@ const service: AxiosInstance = axios.create({
|
|||||||
timeout: 150000, // 请求超时时间
|
timeout: 150000, // 请求超时时间
|
||||||
})
|
})
|
||||||
|
|
||||||
const noEncryptWhiteList = ['/common/protocol/content', '/portal/common/protocol/content', '/bl-log/web/log/add']
|
// const noEncryptWhiteList = ['/common/protocol/content', '/portal/common/protocol/content', '/bl-log/web/log/add']
|
||||||
const noConsoleWhiteList = ['bl-log/web/log/add']
|
// const noConsoleWhiteList = ['bl-log/web/log/add']
|
||||||
|
|
||||||
// request拦截器
|
// request拦截器
|
||||||
service.interceptors.request.use(
|
service.interceptors.request.use(
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
<div class="cart-wrap">
|
<div class="cart-wrap">
|
||||||
<p class="flex justify-between" @click="showAddressList = true">
|
<p class="flex justify-between" @click="showAddressList = true">
|
||||||
<van-icon name="location-o" class="mr-1" /><span class="max-w-12 mr-1">{{ curAddressData?.buyerName }}</span>
|
<van-icon name="location-o" class="mr-1" /><span class="max-w-12 mr-1">{{ curAddressData?.buyerName }}</span>
|
||||||
<b class="font- flex-1">{{ (curAddressData?.province ?? '') + (curAddressData?.city ?? '') + (curAddressData?.district ?? '') + (curAddressData?.detail?? '') }}</b
|
<b class="font- flex-1">{{ (curAddressData?.province ?? '') + (curAddressData?.city ?? '') + (curAddressData?.district ?? '') + (curAddressData?.detail ?? '') }}</b
|
||||||
><van-icon name="arrow" />
|
><van-icon name="arrow" />
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -19,6 +19,13 @@
|
|||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<van-stepper v-model="formData.num" input-width=".4rem" button-size=".2rem" min="1" :max="curPageData.num" />
|
<van-stepper v-model="formData.num" input-width=".4rem" button-size=".2rem" min="1" :max="curPageData.num" />
|
||||||
|
<span class="text-[10px] text-hex-cccccc ml-[5px]">
|
||||||
|
(最大可购买{{ curPageData?.num }})
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="text-[10px] text-hex-cccccc ml-[3px]">
|
||||||
|
{{ curPageData?.num > 0 ? "有货" : "缺货"}}
|
||||||
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -28,11 +35,11 @@
|
|||||||
<div class="cagetory">
|
<div class="cagetory">
|
||||||
<p
|
<p
|
||||||
v-for="v in arr"
|
v-for="v in arr"
|
||||||
:key="v.propertyId"
|
:key="v.sid"
|
||||||
:class="{ 'theme-border-color theme-color': v.propertyId === curPropertyIds.find((it) => it.productPropertyName === key).id }"
|
:class="[{ 'theme-border-color theme-color': v.label === curSelection[key] }, { disabled: v.disabled }]"
|
||||||
@click="onChooseProperty(v, key)"
|
@click="!v.disabled && onChooseProperty(v, key)"
|
||||||
>
|
>
|
||||||
{{ v?.label }}
|
{{ v.label }} {{ v.num }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -49,59 +56,109 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import { requestPayment } from '@/utils/wx-minprogram'
|
import { requestPayment } from '@/utils/wx-minprogram'
|
||||||
|
import type { SkuType } from '@/api/types/shop'
|
||||||
const model = defineModel<boolean>()
|
const model = defineModel<boolean>()
|
||||||
const showAddressList = defineModel<boolean>('showAddressList')
|
const showAddressList = defineModel<boolean>('showAddressList')
|
||||||
const props = defineProps<{ list: Array<any>; curAddressData: Recordable<any>; scene: 'order' | 'cart' }>()
|
const props = defineProps<{ list: Array<any>; curAddressData: Recordable<any>; scene: 'order' | 'cart' }>()
|
||||||
const skuData = ref<any>({}) // sku分类,key为属性的类目,value为属性的分类{ 颜色: [{ '黄色'}]}
|
type SkuOption = { sid: string; label: string; num: number; disabled?: boolean }
|
||||||
const commodityData = ref<any>({}) // 商品对象, value为每种商品的skuId,图片,销售价,成交价,库存(key为属性id的集合)
|
const skuData = ref<Record<string, SkuOption[]>>({}) // sku分类,key为属性的类目
|
||||||
const curPropertyIds = ref<any>([]) // 当前选中的属性id的集合[{ id: 1, name: '颜色'},{id: 2, name: '重量'}] name是用来赋值的
|
const commodityData = ref<Record<string, { id: number; imageUrl?: string; salePrice?: number; price?: number; num: number }>>({}) // 商品对象,每种组合的 sku 信息
|
||||||
const curPageData = ref<any>({ price: '', imageUrl: '', num: 0 }) // 当前商品页面数据
|
const categoryOrder = ref<string[]>([]) // 类目
|
||||||
const formData = ref<any>({ skuId: NaN, num: 1 })
|
const curSelection = ref<Record<string, string>>({})
|
||||||
|
const curPageData = ref({ price: 0, imageUrl: '', num: 0 })
|
||||||
|
const formData = ref({ skuId: NaN, num: 1 })
|
||||||
|
|
||||||
|
// 设置pathset
|
||||||
|
const buildSignature = (order: string[], selection: Record<string, string>) => order.map((name) => `${name}:${selection[name] ?? ''}`).join('|')
|
||||||
|
|
||||||
|
// 设置唯一id
|
||||||
|
const buildOptionSid = (vv: SkuType['vvSkuPropertyValueList'][number]) => `${vv.productPropertyName}:${vv.productPropertyValue}`
|
||||||
|
|
||||||
watch(model, (val) => {
|
watch(model, (val) => {
|
||||||
if (val) {
|
if (!val) return
|
||||||
const { result, commodityMap, firstShopIds } = handleGetSkuList(props.list)
|
const { result, commodityMap, firstSelection } = handleGetSkuList(props.list)
|
||||||
skuData.value = result
|
skuData.value = result
|
||||||
commodityData.value = commodityMap
|
commodityData.value = commodityMap
|
||||||
curPropertyIds.value = firstShopIds
|
curSelection.value = firstSelection
|
||||||
const { pageData, skuId } = handleGetPageData(commodityData.value, curPropertyIds.value)
|
syncCurrentSku()
|
||||||
curPageData.value = pageData
|
updateOptionDisabled()
|
||||||
formData.value = { skuId, num: 1 }
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleGetSkuList = (list: any[]) => {
|
// 更新
|
||||||
const result = {} as any // sku分类
|
const updateOptionDisabled = () => {
|
||||||
const commodityMap = {} //
|
Object.entries(skuData.value).forEach(([categoryName, options]) => {
|
||||||
let firstShopIds = []
|
options.forEach((opt) => {
|
||||||
list.forEach((item, i) => {
|
const trialSelection = { ...curSelection.value, [categoryName]: opt.label }
|
||||||
const commodityValue = { id: item.id, imageUrl: item.imageUrl, salePrice: item.salePrice, price: item.promotionPrice, num: item.stock }
|
const match = commodityData.value[buildSignature(categoryOrder.value, trialSelection)]
|
||||||
let commodityPropertyId = ''
|
opt.disabled = !match || (match.num ?? 0) <= 0
|
||||||
if (i === 0) {
|
})
|
||||||
firstShopIds = item.vvSkuPropertyValueList.map((child) => ({ id: child.id, productPropertyName: child.productPropertyName }))
|
})
|
||||||
}
|
}
|
||||||
item.vvSkuPropertyValueList.forEach((item2, index) => {
|
|
||||||
commodityPropertyId += item2.id + (index < item.vvSkuPropertyValueList.length - 1 ? '_' : '')
|
const handleGetSkuList = (list: SkuType[]) => {
|
||||||
if (!result[item2.productPropertyName]) result[item2.productPropertyName] = []
|
const result: Record<string, SkuOption[]> = {}
|
||||||
if (result[item2.productPropertyName].some((child) => child.propertyId === item2.id)) return
|
const commodityMap: Record<string, { id: number; imageUrl?: string; salePrice?: number; price?: number; num: number }> = {}
|
||||||
result[item2.productPropertyName].push({ propertyId: item2.id, label: item2.productPropertyValue })
|
// 提取类目
|
||||||
|
const order = list[0]?.vvSkuPropertyValueList?.map((vv) => vv.productPropertyName) || []
|
||||||
|
categoryOrder.value = order
|
||||||
|
let firstSelection: Record<string, string> = {}
|
||||||
|
|
||||||
|
list.forEach((sku, index) => {
|
||||||
|
// 第一次默认选择
|
||||||
|
if (index === 0) {
|
||||||
|
firstSelection = Object.fromEntries(sku.vvSkuPropertyValueList.map((vv) => [vv.productPropertyName, vv.productPropertyValue]))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取 类目对应值
|
||||||
|
const selection = Object.fromEntries(sku.vvSkuPropertyValueList.map((vv) => [vv.productPropertyName, vv.productPropertyValue]))
|
||||||
|
|
||||||
|
// 类目生成 唯一值 设置属性 一位数组
|
||||||
|
const comboKey = buildSignature(order, selection)
|
||||||
|
|
||||||
|
commodityMap[comboKey] = {
|
||||||
|
id: sku.id,
|
||||||
|
imageUrl: sku.imageUrl,
|
||||||
|
salePrice: sku.salePrice,
|
||||||
|
price: sku.promotionPrice,
|
||||||
|
num: sku.stock,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成展示的数组
|
||||||
|
sku.vvSkuPropertyValueList.forEach((vv, idx) => {
|
||||||
|
if (!result[vv.productPropertyName]) result[vv.productPropertyName] = []
|
||||||
|
const bucket = result[vv.productPropertyName]
|
||||||
|
const sid = buildOptionSid(vv)
|
||||||
|
const existing = bucket.find((item) => item.sid === sid)
|
||||||
|
const isLeafProperty = idx === order.length - 1
|
||||||
|
if (existing) {
|
||||||
|
// 非叶子类目需要展示该类目下所有 SKU 的累计库存;叶子类目保持当前 SKU 库存
|
||||||
|
existing.num = isLeafProperty ? sku.stock : existing.num + sku.stock
|
||||||
|
} else {
|
||||||
|
bucket.push({
|
||||||
|
sid,
|
||||||
|
label: vv.productPropertyValue,
|
||||||
|
num: sku.stock,
|
||||||
|
disabled: isLeafProperty ? sku.stock <= 0 : false,
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
commodityMap[commodityPropertyId] = commodityValue
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return { result, commodityMap, firstShopIds }
|
return { result, commodityMap, firstSelection }
|
||||||
}
|
}
|
||||||
|
|
||||||
const onChooseProperty = (v, categoryName) => {
|
const onChooseProperty = (v, categoryName) => {
|
||||||
curPropertyIds.value.find((it) => it.productPropertyName === categoryName).id = v.propertyId
|
if (v.disabled) return
|
||||||
const { pageData, skuId } = handleGetPageData(commodityData.value, curPropertyIds.value)
|
|
||||||
curPageData.value = pageData
|
curSelection.value[categoryName] = v.label
|
||||||
formData.value = { skuId, num: 1 }
|
syncCurrentSku()
|
||||||
|
updateOptionDisabled()
|
||||||
}
|
}
|
||||||
const handleGetPageData = (commodityData, curPropertyIds) => {
|
|
||||||
const data = commodityData[curPropertyIds.map((item) => item.id).join('_')]
|
const syncCurrentSku = () => {
|
||||||
return { pageData: { price: data?.price, imageUrl: data?.imageUrl, num: data?.num }, skuId: data?.id }
|
const data = commodityData.value[buildSignature(categoryOrder.value, curSelection.value)]
|
||||||
|
curPageData.value = { price: data?.price ?? 0, imageUrl: data?.imageUrl ?? '', num: data?.num ?? 0 }
|
||||||
|
formData.value = { skuId: data?.id ?? NaN, num: 1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
const onSubmit = async () => {
|
const onSubmit = async () => {
|
||||||
@ -125,15 +182,18 @@ const onSubmit = async () => {
|
|||||||
border-radius: 0.04rem;
|
border-radius: 0.04rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cart-cagetory-wrap {
|
.cart-cagetory-wrap {
|
||||||
h4 {
|
h4 {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin-top: 0.16rem;
|
margin-top: 0.16rem;
|
||||||
margin-bottom: 0.12rem;
|
margin-bottom: 0.12rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cagetory {
|
.cagetory {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|
||||||
& > p {
|
& > p {
|
||||||
border: 1px solid #f2f2f2;
|
border: 1px solid #f2f2f2;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
@ -146,14 +206,24 @@ const onSubmit = async () => {
|
|||||||
border-radius: 0.04rem;
|
border-radius: 0.04rem;
|
||||||
margin-right: 0.08rem;
|
margin-right: 0.08rem;
|
||||||
margin-bottom: 0.08rem;
|
margin-bottom: 0.08rem;
|
||||||
|
|
||||||
&.theme-border-color {
|
&.theme-border-color {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
background: #eee;
|
||||||
|
color: #bbb;
|
||||||
|
border-color: #eee;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.van-popup--bottom.van-popup--round {
|
&.van-popup--bottom.van-popup--round {
|
||||||
border-radius: 0.08rem 0.08rem 0 0;
|
border-radius: 0.08rem 0.08rem 0 0;
|
||||||
|
|
||||||
:deep(.van-popup__close-icon) {
|
:deep(.van-popup__close-icon) {
|
||||||
top: 0.06rem;
|
top: 0.06rem;
|
||||||
font-size: 0.2rem;
|
font-size: 0.2rem;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user