Commit b3cb242d by lijiabin

【需求 17679】 feat: 继续完善商城页面功能

parent 34405c0b
import service from '@/utils/request/index' import service from '@/utils/request/index'
import type { BackendServicePageResult, PageSearchParams } from '@/utils/request/types' import type { BackendServicePageResult, PageSearchParams } from '@/utils/request/types'
import type { ExchangeGoodsParams, ShopItemDto, ShopSearchParams, YaBiData } from './types' import type {
ExchangeGoodsParams,
ExchangeGoodsRecordItemDto,
ShopItemDto,
ShopSearchParams,
YaBiData,
ExchangeYabiRecordItemDto,
ExchangeGoodsRecordSearchParams,
} from './types'
/** /**
* 积分商城列表 * 获取用户亚币相关数据
*/
export const getYaBiData = () => {
return service.request<YaBiData>({
url: '/api/culture/action/record/yabiData',
method: 'POST',
data: {},
})
}
/**
* 积分商城商品列表
*/ */
export const getShopItemList = (data: ShopSearchParams) => { export const getShopItemList = (data: ShopSearchParams) => {
return service.request<BackendServicePageResult<ShopItemDto>>({ return service.request<BackendServicePageResult<ShopItemDto>>({
...@@ -13,33 +32,33 @@ export const getShopItemList = (data: ShopSearchParams) => { ...@@ -13,33 +32,33 @@ export const getShopItemList = (data: ShopSearchParams) => {
} }
/** /**
* 获取用户YA币兑换记录 * 兑换商品
*/ */
export const getYabiExchangeList = (data: PageSearchParams) => { export const exchangeGoods = (data: ExchangeGoodsParams) => {
return service.request<BackendServicePageResult<any>>({ return service.request({
url: '/api/culture/action/record/yabiList', url: '/api/culture/shop/item/exchange',
method: 'POST', method: 'POST',
data, data,
}) })
} }
/** /**
* 获取用户亚币相关数据 * 商品领取列表
*/ */
export const getYaBiData = () => { export const getExchangeGoodsRecordList = (data: ExchangeGoodsRecordSearchParams) => {
return service.request<YaBiData>({ return service.request<BackendServicePageResult<ExchangeGoodsRecordItemDto>>({
url: '/api/culture/action/record/yabiData', url: '/api/culture/shop/order/exchangeList',
method: 'POST', method: 'POST',
data: {}, data,
}) })
} }
/** /**
* 兑换商品 * 获取用户YA币兑换记录
*/ */
export const exchangeGoods = (data: ExchangeGoodsParams) => { export const getExchangeYabiRecordList = (data: PageSearchParams) => {
return service.request({ return service.request<BackendServicePageResult<ExchangeYabiRecordItemDto>>({
url: '/api/culture/shop/item/exchange', url: '/api/culture/action/record/yabiList',
method: 'POST', method: 'POST',
data, data,
}) })
......
import type { PageSearchParams } from '@/utils/request/types' import type { PageSearchParams } from '@/utils/request/types'
import { ShopGoodsTypeEnum } from '@/constants' import { BooleanFlag, ShopGoodsTypeEnum } from '@/constants'
/** /**
* 请求参数类型 * 商品列表搜索参数
*/ */
export interface ShopSearchParams extends PageSearchParams { export interface ShopSearchParams extends PageSearchParams {
region: string region: string
...@@ -28,6 +28,15 @@ export interface ShopItemDto { ...@@ -28,6 +28,15 @@ export interface ShopItemDto {
} }
/** /**
* 商品领取列表搜索参数
*/
export interface ExchangeGoodsRecordSearchParams extends PageSearchParams {
receiveTimeStart: number
receiveTimeEnd: number
itemType: ShopGoodsTypeEnum
}
/**
* yabi信息对象类型 * yabi信息对象类型
*/ */
export interface YaBiData { export interface YaBiData {
...@@ -42,3 +51,42 @@ export interface ExchangeGoodsParams { ...@@ -42,3 +51,42 @@ export interface ExchangeGoodsParams {
num: number num: number
deliveryInfo?: string deliveryInfo?: string
} }
/**
* 商品领取列表item Dto
*/
export interface ExchangeGoodsRecordItemDto {
createTime: number
deliveryInfo: string
id: number
isDelete: BooleanFlag
itemId: number
itemName: string
itemType: ShopGoodsTypeEnum
num: number
price: number
status: number
userId: number
}
/**
* 获取用户YA币收支记录
*/
export interface ExchangeYabiRecordItemDto {
actionType: string
actionTypeText: string
createdAt: number
createdTimeText: string
currentValue: number
id: number
incrText: string
isDelete: BooleanFlag
isIncr: BooleanFlag
isSign: BooleanFlag
relationId: number
remark: string
scoreAyabi: number
scoreExp: number
subType: string
userId: number
}
...@@ -111,7 +111,7 @@ export function usePageSearch< ...@@ -111,7 +111,7 @@ export function usePageSearch<
} }
return { return {
list: readonly(list), list,
total: readonly(total), total: readonly(total),
loading, loading,
searchParams, searchParams,
......
<template>
<el-dialog
v-model="visible"
title="商品领取记录"
width="1100px"
class="exchange-record-dialog"
align-center
destroy-on-close
>
<div class="px-6 py-4">
<!-- 搜索筛选区域 - 优化布局 -->
<div class="mb-4 flex items-center gap-3 justify-end">
<div class="w-750px flex items-center gap-3">
<el-select v-model="searchParams.itemType" placeholder="选择商品类型" clearable>
<el-option label="亚声实物" :value="ShopGoodsTypeEnum.REAL_GOODS" />
<el-option label="虚拟装饰" :value="ShopGoodsTypeEnum.VIRTUAL_GOODS" />
</el-select>
<el-date-picker
v-model="timeRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
format="YYYY-MM-DD"
value-format="x"
clearable
style="width: 700px"
/>
<el-button type="primary" @click="refresh" style="width: 80px"> 搜索 </el-button>
</div>
</div>
<!-- 表格 - 调整列宽 -->
<el-table :data="list" stripe height="420" class="w-full">
<el-table-column prop="itemName" label="名称" min-width="140" show-overflow-tooltip />
<el-table-column prop="itemType" label="商品类型" width="100" align="center">
<template #default="scope">
{{ scope.row.itemType === ShopGoodsTypeEnum.REAL_GOODS ? '亚声实物' : '虚拟装饰' }}
</template>
</el-table-column>
<el-table-column prop="price" label="商品单价" width="100" align="center" />
<el-table-column prop="num" label="兑换数量" width="100" align="center" />
<el-table-column label="扣除YA币" width="110" align="center">
<template #default="scope">
<span class="text-red-500 font-semibold"> -{{ scope.row.price * scope.row.num }} </span>
</template>
</el-table-column>
<el-table-column
prop="deliveryInfo"
label="收货地址"
min-width="160"
show-overflow-tooltip
/>
<el-table-column prop="createTime" label="领取时间" width="200">
<template #default="scope">
{{ dayjs(scope.row.createTime * 1000).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
</el-table>
<!-- 分页 - 优化对齐 -->
<div class="flex justify-end mt-4">
<el-pagination
v-model:current-page="searchParams.current"
:page-size="searchParams.size"
@current-change="goToPage"
:total="total"
layout="total, prev, pager, next"
small
/>
</div>
</div>
</el-dialog>
</template>
<script setup lang="ts">
import { usePageSearch } from '@/hooks'
import { getExchangeGoodsRecordList } from '@/api'
import dayjs from 'dayjs'
import { ShopGoodsTypeEnum } from '@/constants'
const { total, searchParams, refresh, goToPage, list } = usePageSearch(getExchangeGoodsRecordList, {
immediate: false,
})
const timeRange = computed({
get() {
if (!searchParams.value.receiveTimeStart || !searchParams.value.receiveTimeEnd) {
return []
} else {
return [searchParams.value.receiveTimeStart * 1000, searchParams.value.receiveTimeEnd * 1000]
}
},
set(value) {
console.log(value)
if (!value) {
searchParams.value.receiveTimeStart = 0
searchParams.value.receiveTimeEnd = 0
} else {
searchParams.value.receiveTimeStart = value[0]! / 1000
searchParams.value.receiveTimeEnd = value[1]! / 1000
}
},
})
const visible = shallowRef(false)
const open = () => {
visible.value = true
refresh()
}
defineExpose({
open,
})
</script>
<style scoped></style>
<template>
<el-dialog
v-model="visible"
title="兑换记录"
width="1000px"
class="exchange-record-dialog"
align-center
destroy-on-close
>
<div class="p-6">
<!-- 搜索筛选区域 -->
<div class="flex gap-4 mb-6">
<el-select v-model="searchParams.type" placeholder="选择类型" clearable>
<el-option label="全部类型" value="" />
<el-option label="商品兑换" value="product" />
<el-option label="积分消费" value="consume" />
<el-option label="积分获得" value="earn" />
</el-select>
<el-date-picker
v-model="searchParams.dateRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
class="w-80"
clearable
/>
<el-button type="primary" @click="onSearch">搜索</el-button>
</div>
<!-- 表格 -->
<el-table :data="tableData" class="exchange-table" stripe style="width: 100%" height="400">
<el-table-column prop="name" label="名称" width="200" />
<el-table-column prop="detail" label="详情" min-width="250" show-overflow-tooltip />
<el-table-column prop="yaCoin" label="YA币" width="120" align="center">
<template #default="scope">
<span
:class="scope.row.yaCoin > 0 ? 'text-green-500' : 'text-red-500'"
class="font-semibold"
>
{{ scope.row.yaCoin > 0 ? '+' : '' }}{{ scope.row.yaCoin }}
</span>
</template>
</el-table-column>
<el-table-column prop="time" label="时间" width="160" />
<el-table-column prop="type" label="类型" width="120" align="center">
<template #default="scope">
<el-tag :type="getTagType(scope.row.type)" size="small" round>
{{ getTypeText(scope.row.type) }}
</el-tag>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div class="flex justify-center mt-6">
<el-pagination
v-model:current-page="searchParams.current"
:page-size="searchParams.size"
:total="total"
layout="prev, pager, next,total"
class="custom-pagination"
/>
</div>
</div>
</el-dialog>
</template>
<script setup lang="ts">
import { usePageSearch } from '@/hooks'
import { getYabiExchangeList } from '@/api'
const { total, searchParams } = usePageSearch(getYabiExchangeList, {
immediate: false,
})
const visible = shallowRef(false)
// 示例数据
const tableData = ref([
{
name: 'YAYA限定T恤',
detail: '2024年春季限定款T恤,100%纯棉材质,经典YAYA图案印花',
yaCoin: -2000,
time: '2024-01-15 14:30',
type: 'product',
},
{
name: '每日签到奖励',
detail: '连续签到第7天奖励,感谢您的坚持!',
yaCoin: 100,
time: '2024-01-15 09:00',
type: 'earn',
},
{
name: 'YAYA公仔玩偶',
detail: '超可爱的YAYA毛绒公仔,高度约20cm,柔软舒适',
yaCoin: -3500,
time: '2024-01-14 16:45',
type: 'product',
},
{
name: '发布优质内容',
detail: '您发布的内容《技能升级指南》获得了社区认可',
yaCoin: 500,
time: '2024-01-14 11:20',
type: 'earn',
},
{
name: '专属徽章套装',
detail: '包含5枚不同主题的金属徽章,限量发行',
yaCoin: -1500,
time: '2024-01-13 20:15',
type: 'product',
},
{
name: '参与活动奖励',
detail: '参与"新年创作挑战"活动获得奖励',
yaCoin: 300,
time: '2024-01-13 15:30',
type: 'earn',
},
{
name: '定制保温杯',
detail: '不锈钢保温杯,印有专属YAYA标志,容量500ml',
yaCoin: -1200,
time: '2024-01-12 09:20',
type: 'product',
},
{
name: '邀请好友奖励',
detail: '成功邀请新用户注册并完成首次任务',
yaCoin: 200,
time: '2024-01-12 08:45',
type: 'earn',
},
])
const getTagType = (type: string) => {
switch (type) {
case 'product':
return 'danger'
case 'earn':
return 'success'
case 'consume':
return 'warning'
default:
return 'info'
}
}
const getTypeText = (type: string) => {
switch (type) {
case 'product':
return '商品兑换'
case 'earn':
return '积分获得'
case 'consume':
return '积分消费'
default:
return '其他'
}
}
const open = () => {
visible.value = true
}
const onSearch = () => {}
defineExpose({
open,
})
</script>
<style scoped></style>
<template>
<el-dialog
v-model="visible"
title="YA币收支记录"
width="1100px"
class="exchange-record-dialog"
align-center
destroy-on-close
>
<div class="px-6 py-4">
<!-- 搜索筛选区域 - 优化布局 -->
<div class="mb-4 flex items-center gap-3 justify-end">
<div class="w-750px flex items-center gap-3">
<el-select v-model="searchParams.type" placeholder="选择商品类型" clearable>
<el-option label="亚声实物" :value="ShopGoodsTypeEnum.REAL_GOODS" />
<el-option label="虚拟装饰" :value="ShopGoodsTypeEnum.VIRTUAL_GOODS" />
</el-select>
<el-date-picker
v-model="searchParams.dateRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
clearable
style="width: 700px"
/>
<el-button type="primary" @click="onSearch" style="width: 80px"> 搜索 </el-button>
</div>
</div>
<!-- 表格 - 调整列宽 -->
<el-table :data="list" stripe height="420" class="w-full">
<el-table-column prop="remark" label="名称" min-width="140" show-overflow-tooltip />
<el-table-column prop="itemType" label="YA币" width="100" align="center">
<template #default="scope">
<span
class="font-semibold"
:class="{ 'text-red-500': !scope.row.isIncr, 'text-green-500': scope.row.isIncr }"
>
{{ scope.row.isIncr ? '+' : '-' }}
{{ scope.row.scoreAyabi }}
</span>
</template>
</el-table-column>
<el-table-column prop="createdAt" label="时间" width="300">
<template #default="scope">
{{ dayjs(scope.row.createdAt * 1000).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
</el-table>
<!-- 分页 - 优化对齐 -->
<div class="flex justify-end mt-4">
<el-pagination
v-model:current-page="searchParams.current"
:page-size="searchParams.size"
@current-change="goToPage"
:total="total"
layout="total, prev, pager, next"
small
/>
</div>
</div>
</el-dialog>
</template>
<script setup lang="ts">
import { usePageSearch } from '@/hooks'
import { getExchangeYabiRecordList } from '@/api'
import dayjs from 'dayjs'
import { ShopGoodsTypeEnum } from '@/constants'
const { total, searchParams, refresh, goToPage, list } = usePageSearch(getExchangeYabiRecordList, {
immediate: false,
})
const visible = shallowRef(false)
const open = () => {
visible.value = true
refresh()
}
const onSearch = () => {}
defineExpose({
open,
})
</script>
<style scoped></style>
...@@ -13,13 +13,13 @@ ...@@ -13,13 +13,13 @@
<div class="flex gap-3"> <div class="flex gap-3">
<button <button
class="cursor-pointer px-6 py-2.5 bg-white text-[#8b5cf6] rounded-full text-sm font-medium border-2 border-[#8b5cf6] hover:bg-[#8b5cf6] hover:text-white transition-all duration-300 shadow-sm hover:shadow-md" class="cursor-pointer px-6 py-2.5 bg-white text-[#8b5cf6] rounded-full text-sm font-medium border-2 border-[#8b5cf6] hover:bg-[#8b5cf6] hover:text-white transition-all duration-300 shadow-sm hover:shadow-md"
@click="onOpenExchangeRecordDialog" @click="onOpenExchangeGoodsRecordDialog"
> >
商品领取列表 商品领取列表
</button> </button>
<button <button
class="cursor-pointer px-6 py-2.5 bg-gradient-to-r from-[#8b5cf6] to-[#6366f1] text-white rounded-full text-sm font-medium hover:shadow-lg transition-all duration-300" class="cursor-pointer px-6 py-2.5 bg-gradient-to-r from-[#8b5cf6] to-[#6366f1] text-white rounded-full text-sm font-medium hover:shadow-lg transition-all duration-300"
@click="onOpenExchangeRecordDialog" @click="onOpenExchangeYabiRecordDialog"
> >
YA币收支记录 YA币收支记录
</button> </button>
...@@ -135,10 +135,9 @@ ...@@ -135,10 +135,9 @@
</div> </div>
<!-- 分页 --> <!-- 分页 -->
<div class="flex justify-center mt-6"> <div class="flex justify-end mt-6">
<div class="bg-gray-50 rounded-xl shadow-sm border border-gray-200 p-3"> <div class="bg-gray-50 rounded-xl shadow-sm border border-gray-200 p-3">
<el-pagination <el-pagination
size="small"
v-model:current-page="realGoodsSearchParams.current" v-model:current-page="realGoodsSearchParams.current"
v-model:page-size="realGoodsSearchParams.size" v-model:page-size="realGoodsSearchParams.size"
:total="realGoodsTotal" :total="realGoodsTotal"
...@@ -167,7 +166,8 @@ ...@@ -167,7 +166,8 @@
</div> </div>
</div> </div>
<ExchangeRecordDialog ref="exchangeRecordDialogRef" /> <ExchangeGoodsRecordDialog ref="exchangeGoodsRecordDialogRef" />
<ExchangeYabiRecordDialog ref="exchangeYabiRecordDialogRef" />
</div> </div>
</div> </div>
</template> </template>
...@@ -180,14 +180,19 @@ import { regionListOptions, ShopGoodsTypeEnum } from '@/constants' ...@@ -180,14 +180,19 @@ import { regionListOptions, ShopGoodsTypeEnum } from '@/constants'
import type { ExchangeGoodsParams, ShopItemDto } from '@/api' import type { ExchangeGoodsParams, ShopItemDto } from '@/api'
import Tabs from '@/components/common/Tabs' import Tabs from '@/components/common/Tabs'
import ExchangeRecordDialog from './components/exchangeRecordDilaog.vue'
import ExchangeContent from './components/exchangeContent.tsx' import ExchangeContent from './components/exchangeContent.tsx'
import ExchangeGoodsRecordDialog from './components/exchangeGoodsRecordDilaog.vue'
import ExchangeYabiRecordDialog from './components/exchangeYabiRecordDilaog.vue'
const activeTab = ref('深圳') const activeTab = ref('深圳')
const tabs = ref(regionListOptions) const tabs = ref(regionListOptions)
const currentYaBi = ref(0) const currentYaBi = ref(0)
const exchangeRecordDialogRef = const exchangeGoodsRecordDialogRef = useTemplateRef<InstanceType<typeof ExchangeGoodsRecordDialog>>(
useTemplateRef<InstanceType<typeof ExchangeRecordDialog>>('exchangeRecordDialogRef') 'exchangeGoodsRecordDialogRef',
)
const exchangeYabiRecordDialogRef = useTemplateRef<InstanceType<typeof ExchangeYabiRecordDialog>>(
'exchangeYabiRecordDialogRef',
)
// 虚拟商品 // 虚拟商品
const { const {
...@@ -220,8 +225,12 @@ const onChangeRegion = () => { ...@@ -220,8 +225,12 @@ const onChangeRegion = () => {
realGoodsGoToPage(1) realGoodsGoToPage(1)
} }
const onOpenExchangeRecordDialog = () => { const onOpenExchangeYabiRecordDialog = () => {
exchangeRecordDialogRef.value?.open() exchangeYabiRecordDialogRef.value?.open()
}
const onOpenExchangeGoodsRecordDialog = () => {
exchangeGoodsRecordDialogRef.value?.open()
} }
// 获取YA币数据 // 获取YA币数据
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<div class="col-span-8 space-y-6"> <div class="col-span-8 space-y-6">
<!-- 视频上传区域 --> <!-- 视频上传区域 -->
<div <div
class="bg-white/70 backdrop-blur-sm rounded-2xl shadow-lg border border-white/20 p-8 hover:shadow-xl transition-all duration-300" class="bg-white backdrop-blur-sm rounded-2xl shadow-lg border border-white/20 p-8 hover:shadow-xl transition-all duration-300"
> >
<div class="flex items-center justify-between mb-6"> <div class="flex items-center justify-between mb-6">
<h3 class="text-xl font-bold text-gray-800">上传视频</h3> <h3 class="text-xl font-bold text-gray-800">上传视频</h3>
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
</div> </div>
<!-- 基本设置 --> <!-- 基本设置 -->
<div <div
class="bg-white/70 backdrop-blur-sm rounded-2xl shadow-lg border border-white/20 p-8 hover:shadow-xl transition-all duration-300" class="bg-white backdrop-blur-sm rounded-2xl shadow-lg border border-white/20 p-8 hover:shadow-xl transition-all duration-300"
> >
<div class="flex items-center justify-between mb-6"> <div class="flex items-center justify-between mb-6">
<h3 class="text-xl font-bold text-gray-800">基本设置</h3> <h3 class="text-xl font-bold text-gray-800">基本设置</h3>
...@@ -126,7 +126,7 @@ ...@@ -126,7 +126,7 @@
</div> </div>
</div> </div>
<div <div
class="bg-white/70 backdrop-blur-sm rounded-2xl shadow-lg border border-white/20 p-6 hover:shadow-xl transition-all duration-300" class="bg-white backdrop-blur-sm rounded-2xl shadow-lg border border-white/20 p-6 hover:shadow-xl transition-all duration-300"
> >
<h4 class="text-lg font-bold text-gray-800 mb-4">发布设置</h4> <h4 class="text-lg font-bold text-gray-800 mb-4">发布设置</h4>
...@@ -205,6 +205,7 @@ import { ArticleTypeEnum, SendTypeEnum } from '@/constants' ...@@ -205,6 +205,7 @@ import { ArticleTypeEnum, SendTypeEnum } from '@/constants'
import { addOrUpdateArticle } from '@/api' import { addOrUpdateArticle } from '@/api'
import SelectTags from '@/components/common/SelectTags/index.vue' import SelectTags from '@/components/common/SelectTags/index.vue'
import type { TagItemDto } from '@/api'
const formRef = useTemplateRef('formRef') const formRef = useTemplateRef('formRef')
...@@ -219,8 +220,8 @@ const [form] = useResetData({ ...@@ -219,8 +220,8 @@ const [form] = useResetData({
sendTime: '', sendTime: '',
}) })
const filterTagsFn = (tags: { value: number; label: string }[]) => { const filterTagsFn = (tags: TagItemDto[]) => {
return tags.filter((tag) => tag.value !== Number(form.value.mainTagId)) return tags.filter((tag) => tag.id !== Number(form.value.mainTagId))
} }
const rules = { const rules = {
......
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