营销活动:完善 review 提到的问题,添加拼团列表查看弹窗

(cherry picked from commit 3500a20630)
This commit is contained in:
puhui999 2023-10-10 16:53:22 +08:00 committed by shizhong
parent dbcefcca9b
commit 848e0b7023
10 changed files with 213 additions and 93 deletions

View File

@ -24,7 +24,7 @@ export interface BargainProductVO {
spuId: number spuId: number
skuId: number skuId: number
bargainFirstPrice: number // 砍价起始价格,单位分 bargainFirstPrice: number // 砍价起始价格,单位分
bargainPrice: number // 砍价底价 bargainMinPrice: number // 砍价底价
stock: number // 活动库存 stock: number // 活动库存
} }

View File

@ -22,6 +22,11 @@ export const getCombinationRecordPage = async (params) => {
return await request.get({ url: '/promotion/combination-record/page', params }) return await request.get({ url: '/promotion/combination-record/page', params })
} }
// 查询一个拼团的完整拼团记录
export const getCombinationRecordPageByHeadId = async (params) => {
return await request.get({ url: '/promotion/combination-record/page-by-headId', params })
}
// 获得拼团记录的概要信息 // 获得拼团记录的概要信息
export const getCombinationRecordSummary = async () => { export const getCombinationRecordSummary = async () => {
return await request.get({ url: '/promotion/combination-record/get-summary' }) return await request.get({ url: '/promotion/combination-record/get-summary' })

View File

@ -1,5 +1,56 @@
import dayjs from 'dayjs' import dayjs from 'dayjs'
/**
* el-date-picker
*/
export const defaultShortcuts = [
{
text: '今天',
value: () => {
return new Date()
}
},
{
text: '昨天',
value: () => {
const date = new Date()
date.setTime(date.getTime() - 3600 * 1000 * 24)
return [date, date]
}
},
{
text: '最近七天',
value: () => {
const date = new Date()
date.setTime(date.getTime() - 3600 * 1000 * 24 * 7)
return [date, new Date()]
}
},
{
text: '最近 30 天',
value: () => {
const date = new Date()
date.setTime(date.getTime() - 3600 * 1000 * 24 * 30)
return [date, new Date()]
}
},
{
text: '本月',
value: () => {
const date = new Date()
date.setDate(1) // 设置为当前月的第一天
return [date, new Date()]
}
},
{
text: '今年',
value: () => {
const date = new Date()
return [new Date(`${date.getFullYear()}-01-01`), date]
}
}
]
/** /**
* *
* @param date new Date() * @param date new Date()

View File

@ -1,12 +1,7 @@
import { fenToYuan } from '@/utils' import { floatToFixed2 } from '@/utils'
import { TableColumnCtx } from 'element-plus'
// 格式化金额【分转元】 // 格式化金额【分转元】
export const fenToYuanFormat = ( // @ts-ignore
row: any, export const fenToYuanFormat = (_, _, cellValue: any, _) => {
column: TableColumnCtx<any>, return `${floatToFixed2(cellValue)}`
cellValue: any,
index: number
) => {
return `${fenToYuan(cellValue)}`
} }

View File

@ -227,15 +227,14 @@ export const convertToInteger = (num: number | string | undefined): number => {
* *
*/ */
export const yuanToFen = (amount: string | number): number => { export const yuanToFen = (amount: string | number): number => {
return Math.round(Number(amount) * 100) return convertToInteger(amount)
} }
/** /**
* *
*/ */
export const fenToYuan = (price: string | number): number => { export const fenToYuan = (price: string | number): number => {
price = Number(price) return formatToFraction(price)
return (price / 100.0).toFixed(2)
} }
export const treeFormatter = (ary: any, val: string, valueField = 'value', nameField = 'label') => { export const treeFormatter = (ary: any, val: string, valueField = 'value', nameField = 'label') => {

View File

@ -61,6 +61,7 @@ import { SpuAndSkuList, SpuProperty, SpuSelect } from '@/views/mall/promotion/co
import { getPropertyList, RuleConfig } from '@/views/mall/product/spu/components' import { getPropertyList, RuleConfig } from '@/views/mall/product/spu/components'
import * as ProductSpuApi from '@/api/mall/product/spu' import * as ProductSpuApi from '@/api/mall/product/spu'
import { convertToInteger, formatToFraction } from '@/utils' import { convertToInteger, formatToFraction } from '@/utils'
import { cloneDeep } from 'lodash-es'
defineOptions({ name: 'PromotionBargainActivityForm' }) defineOptions({ name: 'PromotionBargainActivityForm' })
@ -204,8 +205,7 @@ const submitForm = async () => {
// //
formLoading.value = true formLoading.value = true
try { try {
// TODO @puhui999: const data = cloneDeep(formRef.value.formModel) as BargainActivityApi.BargainActivityVO
const data = formRef.value.formModel as BargainActivityApi.BargainActivityVO
const products = spuAndSkuListRef.value.getSkuConfigs('productConfig') const products = spuAndSkuListRef.value.getSkuConfigs('productConfig')
products.forEach((item: BargainProductVO) => { products.forEach((item: BargainProductVO) => {
// //

View File

@ -167,8 +167,7 @@ const submitForm = async () => {
products.forEach((item: CombinationActivityApi.CombinationProductVO) => { products.forEach((item: CombinationActivityApi.CombinationProductVO) => {
item.combinationPrice = convertToInteger(item.combinationPrice) item.combinationPrice = convertToInteger(item.combinationPrice)
}) })
// TODO @puhui999: const data = cloneDeep(formRef.value.formModel) as CombinationActivityApi.CombinationActivityVO
const data = formRef.value.formModel as CombinationActivityApi.CombinationActivityVO
data.products = products data.products = products
// //
if (formType.value === 'create') { if (formType.value === 'create') {

View File

@ -0,0 +1,119 @@
<template>
<Dialog v-model="dialogVisible" title="拼团列表">
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list">
<el-table-column align="center" label="编号" prop="id" />
<el-table-column align="center" label="头像" prop="avatar" />
<el-table-column align="center" label="昵称" prop="nickname" />
<el-table-column align="center" label="开团团长" prop="headId">
<template #default="{ row }: { row: CombinationRecordApi.CombinationRecordVO }">
{{ row.headId ? list.find((item) => item.id === row.headId)?.nickname : row.nickname }}
</template>
</el-table-column>
<el-table-column
:formatter="dateFormatter"
align="center"
label="开团时间"
prop="startTime"
width="180"
/>
<el-table-column
align="center"
label="拼团商品"
prop="type"
show-overflow-tooltip
width="300"
>
<template #defaul="{ row }">
<el-image
:src="row.picUrl"
class="mr-5px h-30px w-30px align-middle"
@click="imagePreview(row.picUrl)"
/>
<span class="align-middle">{{ row.spuName }}</span>
</template>
</el-table-column>
<el-table-column align="center" label="几人团" prop="userSize" />
<el-table-column align="center" label="参与人数" prop="userCount" />
<el-table-column
:formatter="dateFormatter"
align="center"
label="参团时间"
prop="createTime"
width="180"
/>
<el-table-column
:formatter="dateFormatter"
align="center"
label="结束时间"
prop="endTime"
width="180"
/>
<el-table-column align="center" label="拼团状态" prop="status">
<template #default="scope">
<dict-tag
:type="DICT_TYPE.PROMOTION_COMBINATION_RECORD_STATUS"
:value="scope.row.status"
/>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
v-model:limit="queryParams.pageSize"
v-model:page="queryParams.pageNo"
:total="total"
@pagination="getList"
/>
</ContentWrap>
</Dialog>
</template>
<script lang="ts" setup>
import { dateFormatter } from '@/utils/formatTime'
import * as CombinationRecordApi from '@/api/mall/promotion/combination/combinationRecord'
import { DICT_TYPE } from '@/utils/dict'
import { createImageViewer } from '@/components/ImageViewer'
/** 助力列表 */
defineOptions({ name: 'CombinationRecordListDialog' })
const message = useMessage() //
const loading = ref(true) //
const total = ref(0) //
const list = ref([]) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
headId: undefined
})
/** 打开弹窗 */
const dialogVisible = ref(false) //
const open = async (headId: any) => {
dialogVisible.value = true
queryParams.headId = headId
await getList()
}
defineExpose({ open }) // open
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await CombinationRecordApi.getCombinationRecordPageByHeadId(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/** 商品图预览 */
const imagePreview = (imgUrl: string) => {
createImageViewer({
urlList: [imgUrl]
})
}
</script>

View File

@ -78,7 +78,7 @@
<el-form-item label="创建时间" prop="createTime"> <el-form-item label="创建时间" prop="createTime">
<el-date-picker <el-date-picker
v-model="queryParams.createTime" v-model="queryParams.createTime"
:shortcuts="shortcuts" :shortcuts="defaultShortcuts"
class="!w-240px" class="!w-240px"
end-placeholder="结束日期" end-placeholder="结束日期"
start-placeholder="开始日期" start-placeholder="开始日期"
@ -171,9 +171,17 @@
/> />
</template> </template>
</el-table-column> </el-table-column>
<!-- TODO puhui999这里加个查看拼团点击后查看完整的拼团列表 -->
<el-table-column align="center" fixed="right" label="操作"> <el-table-column align="center" fixed="right" label="操作">
<template #default></template> <template #default="scope">
<el-button
v-hasPermi="['promotion:combination-record:query']"
link
type="primary"
@click="openRecordListDialog(scope.row)"
>
查看拼团
</el-button>
</template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<!-- 分页 --> <!-- 分页 -->
@ -184,23 +192,27 @@
@pagination="getList" @pagination="getList"
/> />
</ContentWrap> </ContentWrap>
<!-- 表单弹窗 -->
<CombinationRecordListDialog ref="combinationRecordListRef" />
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import CombinationRecordListDialog from './CombinationRecordListDialog.vue'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime' import { dateFormatter, defaultShortcuts } from '@/utils/formatTime'
import { createImageViewer } from '@/components/ImageViewer' import { createImageViewer } from '@/components/ImageViewer'
import * as CombinationRecordApi from '@/api/mall/promotion/combination/combinationRecord' import * as CombinationRecordApi from '@/api/mall/promotion/combination/combinationRecord'
defineOptions({ name: 'CombinationRecord' }) defineOptions({ name: 'CombinationRecord' })
const queryParams = ref({ const queryParams = ref({
dateType: 0, //
status: undefined, // status: undefined, //
createTime: undefined, // createTime: undefined, //
pageSize: 10, pageSize: 10,
pageNo: 1 pageNo: 1
}) })
const queryFormRef = ref() // const queryFormRef = ref() //
const combinationRecordListRef = ref() // Ref
const loading = ref(true) // const loading = ref(true) //
const total = ref(0) // const total = ref(0) //
const pageList = ref<CombinationRecordApi.CombinationRecordVO[]>([]) // const pageList = ref<CombinationRecordApi.CombinationRecordVO[]>([]) //
@ -225,68 +237,10 @@ const recordSummary = ref({
const getSummary = async () => { const getSummary = async () => {
recordSummary.value = await CombinationRecordApi.getCombinationRecordSummary() recordSummary.value = await CombinationRecordApi.getCombinationRecordSummary()
} }
//
// TODO @puhui999 dateType shortcuts date ok shortcuts defaultProps
const shortcuts = ref([
{
text: '今天',
type: 'toDay',
value: () => {
queryParams.value.dateType = 1
return new Date()
}
},
{
text: '昨天',
type: 'yesterday',
value: () => {
const date = new Date()
date.setTime(date.getTime() - 3600 * 1000 * 24)
queryParams.value.dateType = 2
return [date, date]
}
},
{
text: '最近七天',
type: 'lastSevenDays',
value: () => {
const date = new Date()
date.setTime(date.getTime() - 3600 * 1000 * 24 * 7)
queryParams.value.dateType = 3
return [date, new Date()]
}
},
{
text: '最近 30 天',
type: 'last30Days',
value: () => {
const date = new Date()
date.setTime(date.getTime() - 3600 * 1000 * 24 * 30)
queryParams.value.dateType = 4
return [date, new Date()]
}
},
{
text: '本月',
type: 'thisMonth',
value: () => {
const date = new Date()
date.setDate(1) //
queryParams.value.dateType = 5
return [date, new Date()]
}
},
{
text: '今年',
type: 'thisYear',
value: () => {
const date = new Date()
queryParams.value.dateType = 6
return [new Date(`${date.getFullYear()}-01-01`), date]
}
}
])
const openRecordListDialog = (row: CombinationRecordApi.CombinationRecordVO) => {
combinationRecordListRef.value?.open(row.headId)
}
/** 搜索按钮操作 */ /** 搜索按钮操作 */
const handleQuery = () => { const handleQuery = () => {
queryParams.value.pageNo = 1 queryParams.value.pageNo = 1

View File

@ -121,26 +121,24 @@
@keyup.enter="handleQuery" @keyup.enter="handleQuery"
/> />
</el-form-item> </el-form-item>
<!-- TODO puhui 聚合搜索等售后结束后实现-->
<!-- TODO puhui999尽量不要用 .k 这样的参数完整拼写有完整的业务含义 -->
<el-form-item label="聚合搜索"> <el-form-item label="聚合搜索">
<el-input <el-input
v-show="true" v-show="true"
v-model="queryParams[queryType.k]" v-model="queryParams[queryType.queryParam]"
class="!w-280px" class="!w-280px"
clearable clearable
placeholder="请输入" placeholder="请输入"
> >
<template #prepend> <template #prepend>
<el-select <el-select
v-model="queryType.k" v-model="queryType.queryParam"
class="!w-110px" class="!w-110px"
clearable clearable
placeholder="全部" placeholder="全部"
@change="inputChangeSelect" @change="inputChangeSelect"
> >
<el-option <el-option
v-for="dict in searchList" v-for="dict in dynamicSearchList"
:key="dict.value" :key="dict.value"
:label="dict.label" :label="dict.label"
:value="dict.value" :value="dict.value"
@ -386,11 +384,10 @@ const queryParams = ref({
pickUpStoreId: null, // pickUpStoreId: null, //
pickUpVerifyCode: null // pickUpVerifyCode: null //
}) })
const queryType = reactive({ k: '' }) // k const queryType = reactive({ queryParam: '' }) // queryParam
// select // select
// TODO @puhui999dynamicSearchList const dynamicSearchList = ref([
const searchList = ref([
{ value: 'no', label: '订单号' }, { value: 'no', label: '订单号' },
{ value: 'userId', label: '用户UID' }, { value: 'userId', label: '用户UID' },
{ value: 'userNickname', label: '用户昵称' }, { value: 'userNickname', label: '用户昵称' },
@ -401,7 +398,7 @@ const searchList = ref([
* @param val * @param val
*/ */
const inputChangeSelect = (val: string) => { const inputChangeSelect = (val: string) => {
searchList.value dynamicSearchList.value
.filter((item) => item.value !== val) .filter((item) => item.value !== val)
?.forEach((item1) => { ?.forEach((item1) => {
// //
@ -475,6 +472,7 @@ const handleQuery = async () => {
const resetQuery = () => { const resetQuery = () => {
queryFormRef.value?.resetFields() queryFormRef.value?.resetFields()
queryParams.value = { queryParams.value = {
pickUpVerifyCode: null, //
pageNo: 1, // pageNo: 1, //
pageSize: 10, // pageSize: 10, //
status: null, // status: null, //