Commit e5af948b by lijiabin

【需求 23684】feat: 优化积分商城地区兑换逻辑

parent 049bef0f
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
clearable clearable
> >
<el-option <el-option
v-for="item in regionListOptions" v-for="item in goodsRegionListOptions"
:key="item.value" :key="item.value"
:label="item.label" :label="item.label"
:value="item.value" :value="item.value"
...@@ -147,7 +147,7 @@ ...@@ -147,7 +147,7 @@
<el-form-item label="上架地区" prop="region"> <el-form-item label="上架地区" prop="region">
<el-select v-model="form.region" placeholder="请选择上架地区"> <el-select v-model="form.region" placeholder="请选择上架地区">
<el-option <el-option
v-for="item in regionListOptions" v-for="item in goodsRegionListOptions"
:key="item.value" :key="item.value"
:label="item.label" :label="item.label"
:value="item.value" :value="item.value"
...@@ -197,7 +197,7 @@ import type { BackendShopItemDto } from '@/api/backend' ...@@ -197,7 +197,7 @@ import type { BackendShopItemDto } from '@/api/backend'
import { push } from 'notivue' import { push } from 'notivue'
import { useMessageBox } from '@/hooks' import { useMessageBox } from '@/hooks'
const { confirm } = useMessageBox() const { confirm } = useMessageBox()
const goodsRegionListOptions = [...regionListOptions, { label: '四地通用', value: '四地通用' }]
const { loading, list, total, reset, goToPage, changePageSize, refresh, searchParams, search } = const { loading, list, total, reset, goToPage, changePageSize, refresh, searchParams, search } =
usePageSearch(getShopItemList) usePageSearch(getShopItemList)
......
...@@ -5,6 +5,11 @@ import { ShopGoodsTypeEnum, regionListOptions } from '@/constants' ...@@ -5,6 +5,11 @@ import { ShopGoodsTypeEnum, regionListOptions } from '@/constants'
import type { BackendShopItemDto, ExchangeGoodsParams } from '@/api' import type { BackendShopItemDto, ExchangeGoodsParams } from '@/api'
import type { SetupContext } from 'vue' import type { SetupContext } from 'vue'
const UNIVERSAL_REGION = '四地通用'
const universalRegionOptions = regionListOptions.filter((item) =>
['深圳', '合肥', '武汉', '长沙'].includes(item.value),
)
type ExchangeContentProps = { type ExchangeContentProps = {
item: BackendShopItemDto item: BackendShopItemDto
modelValue: ExchangeGoodsParams modelValue: ExchangeGoodsParams
...@@ -17,7 +22,14 @@ export default function ExchangeContent( ...@@ -17,7 +22,14 @@ export default function ExchangeContent(
{ item, modelValue }: ExchangeContentProps, { item, modelValue }: ExchangeContentProps,
context: SetupContext<ExchangeContentEvents>, context: SetupContext<ExchangeContentEvents>,
) { ) {
const totalPrice = computed(() => item.price * (modelValue.num || 1)) const totalPrice = item.price * (modelValue.num || 1)
const deliveryOfficeOptions =
item.region === UNIVERSAL_REGION
? universalRegionOptions
: (() => {
const currentRegion = regionListOptions.find((region) => region.value === item.region)
return currentRegion ? [currentRegion] : [{ label: item.region, value: item.region }]
})()
return ( return (
<div class="py-4"> <div class="py-4">
...@@ -58,8 +70,9 @@ export default function ExchangeContent( ...@@ -58,8 +70,9 @@ export default function ExchangeContent(
} }
placeholder="请选择办公点" placeholder="请选择办公点"
class="w-full" class="w-full"
disabled={item.region !== UNIVERSAL_REGION}
> >
{regionListOptions.map((office) => ( {deliveryOfficeOptions.map((office) => (
<el-option key={office.value} label={office.label} value={office.value} /> <el-option key={office.value} label={office.label} value={office.value} />
))} ))}
</el-select> </el-select>
...@@ -94,7 +107,7 @@ export default function ExchangeContent( ...@@ -94,7 +107,7 @@ export default function ExchangeContent(
</span> </span>
<div class="flex items-baseline gap-0.5"> <div class="flex items-baseline gap-0.5">
<span class="text-sm text-orange-400">¥</span> <span class="text-sm text-orange-400">¥</span>
<span class="text-2xl font-bold text-orange-500">{totalPrice.value}</span> <span class="text-2xl font-bold text-orange-500">{totalPrice}</span>
<span class="text-xs text-gray-400 ml-1">积分</span> <span class="text-xs text-gray-400 ml-1">积分</span>
</div> </div>
</div> </div>
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
<div class="w-750px flex items-center gap-3"> <div class="w-750px flex items-center gap-3">
<el-select v-model="searchParams.itemType" placeholder="选择商品类型" clearable> <el-select v-model="searchParams.itemType" placeholder="选择商品类型" clearable>
<el-option label="亚声实物" :value="ShopGoodsTypeEnum.REAL_GOODS" /> <el-option label="亚声实物" :value="ShopGoodsTypeEnum.REAL_GOODS" />
<el-option label="虚拟装饰" :value="ShopGoodsTypeEnum.VIRTUAL_GOODS" /> <el-option label="虚拟商品" :value="ShopGoodsTypeEnum.VIRTUAL_GOODS" />
</el-select> </el-select>
<el-date-picker <el-date-picker
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
<el-table-column prop="itemType" label="商品类型" width="100" align="center"> <el-table-column prop="itemType" label="商品类型" width="100" align="center">
<template #default="scope"> <template #default="scope">
{{ scope.row.itemType === ShopGoodsTypeEnum.REAL_GOODS ? '亚声实物' : '虚拟装饰' }} {{ scope.row.itemType === ShopGoodsTypeEnum.REAL_GOODS ? '亚声实物' : '虚拟商品' }}
</template> </template>
</el-table-column> </el-table-column>
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
<div class="w-750px flex items-center gap-3"> <div class="w-750px flex items-center gap-3">
<!-- <el-select v-model="searchParams.type" placeholder="选择商品类型" clearable> <!-- <el-select v-model="searchParams.type" placeholder="选择商品类型" clearable>
<el-option label="亚声实物" :value="ShopGoodsTypeEnum.REAL_GOODS" /> <el-option label="亚声实物" :value="ShopGoodsTypeEnum.REAL_GOODS" />
<el-option label="虚拟装饰" :value="ShopGoodsTypeEnum.VIRTUAL_GOODS" /> <el-option label="虚拟商品" :value="ShopGoodsTypeEnum.VIRTUAL_GOODS" />
</el-select> --> </el-select> -->
<el-date-picker <el-date-picker
......
...@@ -4,13 +4,13 @@ ...@@ -4,13 +4,13 @@
<BackButton /> <BackButton />
<!-- 左侧:商品列表区域 --> <!-- 左侧:商品列表区域 -->
<div class="flex-3/4 min-w-0"> <div class="flex-3/4 min-w-0">
<!-- 虚拟装饰区域 --> <!-- 虚拟商品区域 -->
<div class="bg-white/90 rounded-lg p-6 shadow-lg mb-3 border border-white/60"> <div class="bg-white/90 rounded-lg p-6 shadow-lg mb-3 border border-white/60">
<div class="flex items-center gap-3 mb-6"> <div class="flex items-center gap-3 mb-6">
<div <div
class="w-1.5 h-7 bg-gradient-to-b from-[#8b5cf6] to-[#6366f1] rounded-full shadow-sm" class="w-1.5 h-7 bg-gradient-to-b from-[#8b5cf6] to-[#6366f1] rounded-full shadow-sm"
></div> ></div>
<h2 class="text-xl font-bold text-gray-800">虚拟装饰</h2> <h2 class="text-xl font-bold text-gray-800">虚拟商品</h2>
</div> </div>
<template v-if="virtualGoodsList.length"> <template v-if="virtualGoodsList.length">
...@@ -78,27 +78,6 @@ ...@@ -78,27 +78,6 @@
<h2 class="text-xl font-bold text-gray-800">亚声实物</h2> <h2 class="text-xl font-bold text-gray-800">亚声实物</h2>
</div> </div>
<!-- 地区筛选 -->
<div class="flex gap-3 text-sm mb-6 items-center flex-wrap">
<span class="text-gray-600 font-medium">地区:</span>
<button
v-for="item in tabs"
:key="item.value"
class="cursor-pointer px-3 py-1.5 text-sm transition-all relative"
@click="onChangeRegion(item.value)"
:class="{
'text-indigo-600 font-medium': realGoodsSearchParams.region === item.value,
'text-gray-600 hover:text-gray-900': realGoodsSearchParams.region !== item.value,
}"
>
{{ item.label }}
<span
v-if="realGoodsSearchParams.region === item.value"
class="absolute bottom-0 left-0 right-0 h-0.5 bg-gradient-to-b from-[#8b5cf6] to-[#6366f1]"
></span>
</button>
</div>
<template v-if="realGoodsList.length"> <template v-if="realGoodsList.length">
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-4"> <div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-4">
<div <div
...@@ -211,7 +190,7 @@ ...@@ -211,7 +190,7 @@
<!-- 统计信息(可选) --> <!-- 统计信息(可选) -->
<div class="mt-6 pt-6 border-t border-gray-100 space-y-3"> <div class="mt-6 pt-6 border-t border-gray-100 space-y-3">
<div class="flex justify-between items-center text-sm"> <div class="flex justify-between items-center text-sm">
<span class="text-gray-500">虚拟装饰</span> <span class="text-gray-500">虚拟商品</span>
<span class="font-medium text-gray-700">{{ virtualGoodsTotal }} 件</span> <span class="font-medium text-gray-700">{{ virtualGoodsTotal }} 件</span>
</div> </div>
<div class="flex justify-between items-center text-sm"> <div class="flex justify-between items-center text-sm">
...@@ -231,7 +210,7 @@ ...@@ -231,7 +210,7 @@
<script setup lang="tsx"> <script setup lang="tsx">
import { exchangeGoods, getShopItemList } from '@/api' import { exchangeGoods, getShopItemList } from '@/api'
import { usePageSearch } from '@/hooks' import { usePageSearch } from '@/hooks'
import { regionListOptions, ShopGoodsTypeEnum } from '@/constants' import { ShopGoodsTypeEnum } from '@/constants'
import type { ExchangeGoodsParams, BackendShopItemDto } from '@/api' import type { ExchangeGoodsParams, BackendShopItemDto } from '@/api'
import ExchangeContent from './components/exchangeContent.tsx' import ExchangeContent from './components/exchangeContent.tsx'
import ExchangeGoodsRecordDialog from './components/exchangeGoodsRecordDilaog.vue' import ExchangeGoodsRecordDialog from './components/exchangeGoodsRecordDilaog.vue'
...@@ -242,9 +221,7 @@ import BackButton from '@/components/common/BackButton/index.vue' ...@@ -242,9 +221,7 @@ import BackButton from '@/components/common/BackButton/index.vue'
import { push } from 'notivue' import { push } from 'notivue'
const yabiStore = useYaBiStore() const yabiStore = useYaBiStore()
const { yabiData } = storeToRefs(yabiStore) const { yabiData } = storeToRefs(yabiStore)
const UNIVERSAL_REGION = '四地通用'
const activeTab = ref('深圳')
const tabs = ref(regionListOptions)
const exchangeGoodsRecordDialogRef = useTemplateRef<InstanceType<typeof ExchangeGoodsRecordDialog>>( const exchangeGoodsRecordDialogRef = useTemplateRef<InstanceType<typeof ExchangeGoodsRecordDialog>>(
'exchangeGoodsRecordDialogRef', 'exchangeGoodsRecordDialogRef',
...@@ -276,15 +253,9 @@ const { ...@@ -276,15 +253,9 @@ const {
} = usePageSearch(getShopItemList, { } = usePageSearch(getShopItemList, {
defaultParams: { defaultParams: {
itemType: ShopGoodsTypeEnum.REAL_GOODS, itemType: ShopGoodsTypeEnum.REAL_GOODS,
region: activeTab.value,
}, },
}) })
const onChangeRegion = (region: string) => {
realGoodsSearchParams.value.region = region
realGoodsGoToPage(1)
}
const onOpenExchangeYabiRecordDialog = () => { const onOpenExchangeYabiRecordDialog = () => {
exchangeYabiRecordDialogRef.value?.open() exchangeYabiRecordDialogRef.value?.open()
} }
...@@ -296,12 +267,16 @@ const onOpenExchangeGoodsRecordDialog = () => { ...@@ -296,12 +267,16 @@ const onOpenExchangeGoodsRecordDialog = () => {
// 兑换商品 // 兑换商品
const onExchangeGoods = async (item: BackendShopItemDto) => { const onExchangeGoods = async (item: BackendShopItemDto) => {
if(item.stock === 0) return push.warning('库存为0,不可兑换')
const form = ref<ExchangeGoodsParams>({ const form = ref<ExchangeGoodsParams>({
itemId: item.id, itemId: item.id,
num: 1, num: 1,
}) })
if (item.itemType === ShopGoodsTypeEnum.REAL_GOODS) { const isRealGoods = item.itemType === ShopGoodsTypeEnum.REAL_GOODS
form.value.deliveryInfo = '广州' const isUniversalRegion = item.region === UNIVERSAL_REGION
if (isRealGoods && !isUniversalRegion) {
form.value.deliveryInfo = item.region
} }
await ElMessageBox({ await ElMessageBox({
...@@ -320,6 +295,18 @@ const onExchangeGoods = async (item: BackendShopItemDto) => { ...@@ -320,6 +295,18 @@ const onExchangeGoods = async (item: BackendShopItemDto) => {
return push.error( return push.error(
`您的YA币不足,兑换所需${item.price * form.value.num}YA币,当前YA币${yabiData.value.currentValue}`, `您的YA币不足,兑换所需${item.price * form.value.num}YA币,当前YA币${yabiData.value.currentValue}`,
) )
if (isRealGoods && !form.value.deliveryInfo) return push.warning('请选择配送办公点')
if (isRealGoods && isUniversalRegion) {
try {
await ElMessageBox.confirm('请确认配送办公点准确性,准确无误可继续提交', '提示', {
confirmButtonText: '继续提交',
cancelButtonText: '返回修改',
type: 'warning',
})
} catch {
return
}
}
try { try {
instance.confirmButtonLoading = true instance.confirmButtonLoading = true
await exchangeGoods(form.value) await exchangeGoods(form.value)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment