Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
admin
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
16369c00
authored
Aug 13, 2023
by
芋道源码
Committed by
Gitee
Aug 13, 2023
Browse files
Options
Browse Files
Download
Plain Diff
!197 同步商城实现
Merge pull request !197 from 芋道源码/dev
parents
c3a8479e
7bf3e41c
Show whitespace changes
Inline
Side-by-side
Showing
29 changed files
with
1326 additions
and
755 deletions
+1326
-755
src/api/mall/promotion/bargain/bargainActivity.ts
+62
-0
src/api/mall/promotion/combination/combinationActivity.ts
+3
-3
src/api/mall/promotion/coupon/coupon.ts
+0
-0
src/api/mall/promotion/coupon/couponTemplate.ts
+0
-0
src/api/mall/promotion/seckill/seckillConfig.ts
+1
-1
src/hooks/web/useCrudSchemas.ts
+10
-0
src/views/bpm/group/index.vue
+1
-1
src/views/infra/apiAccessLog/index.vue
+1
-1
src/views/infra/apiErrorLog/index.vue
+1
-1
src/views/infra/codegen/index.vue
+1
-1
src/views/mall/promotion/bargain/activity/BargainActivityForm.vue
+219
-0
src/views/mall/promotion/bargain/activity/bargainActivity.data.ts
+165
-0
src/views/mall/promotion/bargain/activity/index.vue
+107
-0
src/views/mall/promotion/combination/activity/CombinationActivityForm.vue
+12
-11
src/views/mall/promotion/combination/activity/combinationActivity.data.ts
+2
-2
src/views/mall/promotion/combination/activity/index.vue
+6
-15
src/views/mall/promotion/combination/record/index.vue
+0
-0
src/views/mall/promotion/coupon/index.vue
+37
-43
src/views/mall/promotion/coupon/template/CouponTemplateForm.vue
+348
-0
src/views/mall/promotion/coupon/template/index.vue
+295
-0
src/views/mall/promotion/couponTemplate/index.vue
+0
-614
src/views/mall/promotion/seckill/activity/SeckillActivityForm.vue
+18
-16
src/views/mall/promotion/seckill/activity/index.vue
+11
-16
src/views/mall/promotion/seckill/activity/seckillActivity.data.ts
+2
-2
src/views/mall/promotion/seckill/config/SeckillConfigForm.vue
+11
-9
src/views/mall/promotion/seckill/config/index.vue
+10
-16
src/views/mp/message/index.vue
+1
-1
src/views/pay/notify/index.vue
+1
-1
src/views/system/dict/index.vue
+1
-1
No files found.
src/api/mall/promotion/bargain/bargainActivity.ts
0 → 100644
View file @
16369c00
import
request
from
'@/config/axios'
import
{
Sku
,
Spu
}
from
'@/api/mall/product/spu'
export
interface
BargainActivityVO
{
id
?:
number
name
?:
string
startTime
?:
Date
endTime
?:
Date
status
?:
number
spuId
?:
number
userSize
?:
number
// 达到该人数,才能砍到低价
bargainCount
?:
number
// 最大帮砍次数
totalLimitCount
?:
number
// 最大购买次数
stock
?:
number
// 活动总库存
randomMinPrice
?:
number
// 用户每次砍价的最小金额,单位:分
randomMaxPrice
?:
number
// 用户每次砍价的最大金额,单位:分
successCount
?:
number
// 砍价成功数量
products
?:
BargainProductVO
[]
}
// 砍价活动所需属性
export
interface
BargainProductVO
{
spuId
:
number
skuId
:
number
bargainFirstPrice
:
number
// 砍价起始价格,单位分
bargainPrice
:
number
// 砍价底价
stock
:
number
// 活动库存
}
// 扩展 Sku 配置
export
type
SkuExtension
=
Sku
&
{
productConfig
:
BargainProductVO
}
export
interface
SpuExtension
extends
Spu
{
skus
:
SkuExtension
[]
// 重写类型
}
// 查询砍价活动列表
export
const
getBargainActivityPage
=
async
(
params
:
any
)
=>
{
return
await
request
.
get
({
url
:
'/promotion/bargain-activity/page'
,
params
})
}
// 查询砍价活动详情
export
const
getBargainActivity
=
async
(
id
:
number
)
=>
{
return
await
request
.
get
({
url
:
'/promotion/bargain-activity/get?id='
+
id
})
}
// 新增砍价活动
export
const
createBargainActivity
=
async
(
data
:
BargainActivityVO
)
=>
{
return
await
request
.
post
({
url
:
'/promotion/bargain-activity/create'
,
data
})
}
// 修改砍价活动
export
const
updateBargainActivity
=
async
(
data
:
BargainActivityVO
)
=>
{
return
await
request
.
put
({
url
:
'/promotion/bargain-activity/update'
,
data
})
}
// 删除砍价活动
export
const
deleteBargainActivity
=
async
(
id
:
number
)
=>
{
return
await
request
.
delete
({
url
:
'/promotion/bargain-activity/delete?id='
+
id
})
}
src/api/mall/promotion/combination/combinationActivity.ts
View file @
16369c00
...
@@ -10,8 +10,8 @@ export interface CombinationActivityVO {
...
@@ -10,8 +10,8 @@ export interface CombinationActivityVO {
startTime
?:
Date
startTime
?:
Date
endTime
?:
Date
endTime
?:
Date
userSize
?:
number
userSize
?:
number
total
Num
?:
number
total
Count
?:
number
success
Num
?:
number
success
Count
?:
number
orderUserCount
?:
number
orderUserCount
?:
number
virtualGroup
?:
number
virtualGroup
?:
number
status
?:
number
status
?:
number
...
@@ -23,7 +23,7 @@ export interface CombinationActivityVO {
...
@@ -23,7 +23,7 @@ export interface CombinationActivityVO {
export
interface
CombinationProductVO
{
export
interface
CombinationProductVO
{
spuId
:
number
spuId
:
number
skuId
:
number
skuId
:
number
active
Price
:
number
// 拼团价格
combination
Price
:
number
// 拼团价格
}
}
// 扩展 Sku 配置
// 扩展 Sku 配置
...
...
src/api/mall/promotion/coupon.ts
→
src/api/mall/promotion/coupon
/coupon
.ts
View file @
16369c00
File moved
src/api/mall/promotion/couponTemplate.ts
→
src/api/mall/promotion/coupon
/coupon
Template.ts
View file @
16369c00
File moved
src/api/mall/promotion/seckill/seckillConfig.ts
View file @
16369c00
...
@@ -20,7 +20,7 @@ export const getSeckillConfig = async (id: number) => {
...
@@ -20,7 +20,7 @@ export const getSeckillConfig = async (id: number) => {
}
}
// 获得所有开启状态的秒杀时段精简列表
// 获得所有开启状态的秒杀时段精简列表
export
const
get
ListAllSimple
=
async
()
=>
{
export
const
get
SimpleSeckillConfigList
=
async
()
=>
{
return
await
request
.
get
({
url
:
'/promotion/seckill-config/list-all-simple'
})
return
await
request
.
get
({
url
:
'/promotion/seckill-config/list-all-simple'
})
}
}
...
...
src/hooks/web/useCrudSchemas.ts
View file @
16369c00
...
@@ -9,6 +9,7 @@ import { TableColumn } from '@/types/table'
...
@@ -9,6 +9,7 @@ import { TableColumn } from '@/types/table'
import
{
DescriptionsSchema
}
from
'@/types/descriptions'
import
{
DescriptionsSchema
}
from
'@/types/descriptions'
import
{
ComponentOptions
,
ComponentProps
}
from
'@/types/components'
import
{
ComponentOptions
,
ComponentProps
}
from
'@/types/components'
import
{
DictTag
}
from
'@/components/DictTag'
import
{
DictTag
}
from
'@/components/DictTag'
import
{
cloneDeep
}
from
'lodash-es'
export
type
CrudSchema
=
Omit
<
TableColumn
,
'children'
>
&
{
export
type
CrudSchema
=
Omit
<
TableColumn
,
'children'
>
&
{
isSearch
?:
boolean
// 是否在查询显示
isSearch
?:
boolean
// 是否在查询显示
...
@@ -306,3 +307,12 @@ const filterOptions = (options: Recordable, labelField?: string) => {
...
@@ -306,3 +307,12 @@ const filterOptions = (options: Recordable, labelField?: string) => {
return
v
return
v
})
})
}
}
// 将 tableColumns 指定 fields 放到最前面
export
const
sortTableColumns
=
(
tableColumns
:
TableColumn
[],
field
:
string
)
=>
{
const
fieldIndex
=
tableColumns
.
findIndex
((
item
)
=>
item
.
field
===
field
)
const
fieldColumn
=
cloneDeep
(
tableColumns
[
fieldIndex
])
tableColumns
.
splice
(
fieldIndex
,
1
)
// 添加到开头
tableColumns
.
unshift
(
fieldColumn
)
}
src/views/bpm/group/index.vue
View file @
16369c00
...
@@ -30,7 +30,7 @@
...
@@ -30,7 +30,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"
value-format=
"
yyyy-MM-dd
HH:mm:ss"
value-format=
"
YYYY-MM-DD
HH:mm:ss"
type=
"daterange"
type=
"daterange"
start-placeholder=
"开始日期"
start-placeholder=
"开始日期"
end-placeholder=
"结束日期"
end-placeholder=
"结束日期"
...
...
src/views/infra/apiAccessLog/index.vue
View file @
16369c00
...
@@ -46,7 +46,7 @@
...
@@ -46,7 +46,7 @@
<el-form-item
label=
"请求时间"
prop=
"beginTime"
>
<el-form-item
label=
"请求时间"
prop=
"beginTime"
>
<el-date-picker
<el-date-picker
v-model=
"queryParams.beginTime"
v-model=
"queryParams.beginTime"
value-format=
"
yyyy-MM-dd
HH:mm:ss"
value-format=
"
YYYY-MM-DD
HH:mm:ss"
type=
"daterange"
type=
"daterange"
start-placeholder=
"开始日期"
start-placeholder=
"开始日期"
end-placeholder=
"结束日期"
end-placeholder=
"结束日期"
...
...
src/views/infra/apiErrorLog/index.vue
View file @
16369c00
...
@@ -46,7 +46,7 @@
...
@@ -46,7 +46,7 @@
<el-form-item
label=
"异常时间"
prop=
"exceptionTime"
>
<el-form-item
label=
"异常时间"
prop=
"exceptionTime"
>
<el-date-picker
<el-date-picker
v-model=
"queryParams.exceptionTime"
v-model=
"queryParams.exceptionTime"
value-format=
"
yyyy-MM-dd
HH:mm:ss"
value-format=
"
YYYY-MM-DD
HH:mm:ss"
type=
"daterange"
type=
"daterange"
start-placeholder=
"开始日期"
start-placeholder=
"开始日期"
end-placeholder=
"结束日期"
end-placeholder=
"结束日期"
...
...
src/views/infra/codegen/index.vue
View file @
16369c00
...
@@ -37,7 +37,7 @@
...
@@ -37,7 +37,7 @@
end-placeholder=
"结束日期"
end-placeholder=
"结束日期"
start-placeholder=
"开始日期"
start-placeholder=
"开始日期"
type=
"daterange"
type=
"daterange"
value-format=
"YYYY-MM-
dd
HH:mm:ss"
value-format=
"YYYY-MM-
DD
HH:mm:ss"
/>
/>
</el-form-item>
</el-form-item>
<el-form-item>
<el-form-item>
...
...
src/views/mall/promotion/bargain/activity/BargainActivityForm.vue
0 → 100644
View file @
16369c00
<
template
>
<Dialog
v-model=
"dialogVisible"
:title=
"dialogTitle"
width=
"65%"
>
<Form
ref=
"formRef"
v-loading=
"formLoading"
:is-col=
"true"
:rules=
"rules"
:schema=
"allSchemas.formSchema"
class=
"mt-10px"
>
<template
#
spuId
>
<el-button
@
click=
"spuSelectRef.open()"
>
选择商品
</el-button>
<SpuAndSkuList
ref=
"spuAndSkuListRef"
:rule-config=
"ruleConfig"
:spu-list=
"spuList"
:spu-property-list-p=
"spuPropertyList"
>
<el-table-column
align=
"center"
label=
"砍价起始价格(元)"
min-width=
"168"
>
<template
#
default=
"
{ row: sku }">
<el-input-number
v-model=
"sku.productConfig.bargainFirstPrice"
:min=
"0"
:precision=
"2"
:step=
"0.1"
class=
"w-100%"
/>
</
template
>
</el-table-column>
<el-table-column
align=
"center"
label=
"砍价底价(元)"
min-width=
"168"
>
<
template
#
default=
"{ row: sku }"
>
<el-input-number
v-model=
"sku.productConfig.bargainPrice"
:min=
"0"
:precision=
"2"
:step=
"0.1"
class=
"w-100%"
/>
</
template
>
</el-table-column>
<el-table-column
align=
"center"
label=
"活动库存"
min-width=
"168"
>
<
template
#
default=
"{ row: sku }"
>
<el-input-number
v-model=
"sku.productConfig.stock"
class=
"w-100%"
/>
</
template
>
</el-table-column>
</SpuAndSkuList>
</template>
</Form>
<
template
#
footer
>
<el-button
:disabled=
"formLoading"
type=
"primary"
@
click=
"submitForm"
>
确 定
</el-button>
<el-button
@
click=
"dialogVisible = false"
>
取 消
</el-button>
</
template
>
</Dialog>
<SpuSelect
ref=
"spuSelectRef"
:isSelectSku=
"true"
@
confirm=
"selectSpu"
/>
</template>
<
script
lang=
"ts"
setup
>
import
*
as
BargainActivityApi
from
'@/api/mall/promotion/bargain/bargainActivity'
import
{
BargainProductVO
}
from
'@/api/mall/promotion/bargain/bargainActivity'
import
{
allSchemas
,
rules
}
from
'./bargainActivity.data'
import
{
SpuAndSkuList
,
SpuProperty
,
SpuSelect
}
from
'@/views/mall/promotion/components'
import
{
getPropertyList
,
RuleConfig
}
from
'@/views/mall/product/spu/components'
import
*
as
ProductSpuApi
from
'@/api/mall/product/spu'
import
{
convertToInteger
,
formatToFraction
}
from
'@/utils'
defineOptions
({
name
:
'PromotionBargainActivityForm'
})
const
{
t
}
=
useI18n
()
// 国际化
const
message
=
useMessage
()
// 消息弹窗
const
dialogVisible
=
ref
(
false
)
// 弹窗的是否展示
const
dialogTitle
=
ref
(
''
)
// 弹窗的标题
const
formLoading
=
ref
(
false
)
// 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
const
formType
=
ref
(
''
)
// 表单的类型:create - 新增;update - 修改
const
formRef
=
ref
()
// 表单 Ref
// ================= 商品选择相关 =================
const
spuSelectRef
=
ref
()
// 商品和属性选择 Ref
const
spuAndSkuListRef
=
ref
()
// sku 秒杀配置组件Ref
const
spuList
=
ref
<
BargainActivityApi
.
SpuExtension
[]
>
([])
// 选择的 spu
const
spuPropertyList
=
ref
<
SpuProperty
<
BargainActivityApi
.
SpuExtension
>
[]
>
([])
const
ruleConfig
:
RuleConfig
[]
=
[
{
name
:
'productConfig.bargainFirstPrice'
,
rule
:
(
arg
)
=>
arg
>
0
,
message
:
'商品砍价起始价格不能小于0 !!!'
},
{
name
:
'productConfig.bargainPrice'
,
rule
:
(
arg
)
=>
arg
>
0
,
message
:
'商品砍价底价不能小于0 !!!'
},
{
name
:
'productConfig.stock'
,
rule
:
(
arg
)
=>
arg
>
1
,
message
:
'商品活动库存不能小于1 !!!'
}
]
const
selectSpu
=
(
spuId
:
number
,
skuIds
:
number
[])
=>
{
formRef
.
value
.
setValues
({
spuId
})
getSpuDetails
(
spuId
,
skuIds
)
}
/**
* 获取 SPU 详情
*/
const
getSpuDetails
=
async
(
spuId
:
number
,
skuIds
:
number
[]
|
undefined
,
products
?:
BargainProductVO
[]
)
=>
{
const
spuProperties
:
SpuProperty
<
BargainActivityApi
.
SpuExtension
>
[]
=
[]
const
res
=
(
await
ProductSpuApi
.
getSpuDetailList
([
spuId
]))
as
BargainActivityApi
.
SpuExtension
[]
if
(
res
.
length
==
0
)
{
return
}
spuList
.
value
=
[]
// 因为只能选择一个
const
spu
=
res
[
0
]
const
selectSkus
=
typeof
skuIds
===
'undefined'
?
spu
?.
skus
:
spu
?.
skus
?.
filter
((
sku
)
=>
skuIds
.
includes
(
sku
.
id
!
))
selectSkus
?.
forEach
((
sku
)
=>
{
let
config
:
BargainProductVO
=
{
spuId
:
spu
.
id
!
,
skuId
:
sku
.
id
!
,
bargainFirstPrice
:
1
,
bargainPrice
:
1
,
stock
:
1
}
if
(
typeof
products
!==
'undefined'
)
{
const
product
=
products
.
find
((
item
)
=>
item
.
skuId
===
sku
.
id
)
if
(
product
)
{
product
.
bargainFirstPrice
=
formatToFraction
(
product
.
bargainFirstPrice
)
product
.
bargainPrice
=
formatToFraction
(
product
.
bargainPrice
)
}
config
=
product
||
config
}
sku
.
productConfig
=
config
})
spu
.
skus
=
selectSkus
as
BargainActivityApi
.
SkuExtension
[]
spuProperties
.
push
({
spuId
:
spu
.
id
!
,
spuDetail
:
spu
,
propertyList
:
getPropertyList
(
spu
)
})
spuList
.
value
.
push
(
spu
)
spuPropertyList
.
value
=
spuProperties
}
// ================= end =================
/** 打开弹窗 */
const
open
=
async
(
type
:
string
,
id
?:
number
)
=>
{
dialogVisible
.
value
=
true
dialogTitle
.
value
=
t
(
'action.'
+
type
)
formType
.
value
=
type
await
resetForm
()
// 修改时,设置数据
if
(
id
)
{
formLoading
.
value
=
true
try
{
const
data
=
(
await
BargainActivityApi
.
getBargainActivity
(
id
))
as
BargainActivityApi
.
BargainActivityVO
// 用户每次砍价金额分转元, 分转元
data
.
randomMinPrice
=
formatToFraction
(
data
.
randomMinPrice
)
data
.
randomMaxPrice
=
formatToFraction
(
data
.
randomMaxPrice
)
await
getSpuDetails
(
data
.
spuId
!
,
data
.
products
?.
map
((
sku
)
=>
sku
.
skuId
),
data
.
products
)
formRef
.
value
.
setValues
(
data
)
}
finally
{
formLoading
.
value
=
false
}
}
}
defineExpose
({
open
})
// 提供 open 方法,用于打开弹窗
/** 重置表单 */
const
resetForm
=
async
()
=>
{
spuList
.
value
=
[]
spuPropertyList
.
value
=
[]
await
nextTick
()
formRef
.
value
.
getElFormRef
().
resetFields
()
}
/** 提交表单 */
const
emit
=
defineEmits
([
'success'
])
// 定义 success 事件,用于操作成功后的回调
const
submitForm
=
async
()
=>
{
// 校验表单
if
(
!
formRef
)
return
const
valid
=
await
formRef
.
value
.
getElFormRef
().
validate
()
if
(
!
valid
)
return
// 提交请求
formLoading
.
value
=
true
try
{
const
data
=
formRef
.
value
.
formModel
as
BargainActivityApi
.
BargainActivityVO
const
products
=
spuAndSkuListRef
.
value
.
getSkuConfigs
(
'productConfig'
)
products
.
forEach
((
item
:
BargainProductVO
)
=>
{
// 砍价价格元转分
item
.
bargainFirstPrice
=
convertToInteger
(
item
.
bargainFirstPrice
)
item
.
bargainPrice
=
convertToInteger
(
item
.
bargainPrice
)
})
// 用户每次砍价金额分转元, 元转分
data
.
randomMinPrice
=
convertToInteger
(
data
.
randomMinPrice
)
data
.
randomMaxPrice
=
convertToInteger
(
data
.
randomMaxPrice
)
data
.
products
=
products
if
(
formType
.
value
===
'create'
)
{
await
BargainActivityApi
.
createBargainActivity
(
data
)
message
.
success
(
t
(
'common.createSuccess'
))
}
else
{
await
BargainActivityApi
.
updateBargainActivity
(
data
)
message
.
success
(
t
(
'common.updateSuccess'
))
}
dialogVisible
.
value
=
false
// 发送操作成功的事件
emit
(
'success'
)
}
finally
{
formLoading
.
value
=
false
}
}
</
script
>
src/views/mall/promotion/bargain/activity/bargainActivity.data.ts
0 → 100644
View file @
16369c00
import
type
{
CrudSchema
}
from
'@/hooks/web/useCrudSchemas'
import
{
dateFormatter2
}
from
'@/utils/formatTime'
// 表单校验
export
const
rules
=
reactive
({
name
:
[
required
],
startTime
:
[
required
],
endTime
:
[
required
],
userSize
:
[
required
],
bargainCount
:
[
required
],
singleLimitCount
:
[
required
]
})
// CrudSchema https://doc.iocoder.cn/vue3/crud-schema/
const
crudSchemas
=
reactive
<
CrudSchema
[]
>
([
{
label
:
'砍价活动名称'
,
field
:
'name'
,
isSearch
:
true
,
isTable
:
false
,
form
:
{
colProps
:
{
span
:
24
}
}
},
{
label
:
'活动开始时间'
,
field
:
'startTime'
,
formatter
:
dateFormatter2
,
isSearch
:
true
,
search
:
{
component
:
'DatePicker'
,
componentProps
:
{
valueFormat
:
'YYYY-MM-DD'
,
type
:
'daterange'
}
},
form
:
{
component
:
'DatePicker'
,
componentProps
:
{
type
:
'date'
,
valueFormat
:
'x'
}
},
table
:
{
width
:
120
}
},
{
label
:
'活动结束时间'
,
field
:
'endTime'
,
formatter
:
dateFormatter2
,
isSearch
:
true
,
search
:
{
component
:
'DatePicker'
,
componentProps
:
{
valueFormat
:
'YYYY-MM-DD'
,
type
:
'daterange'
}
},
form
:
{
component
:
'DatePicker'
,
componentProps
:
{
type
:
'date'
,
valueFormat
:
'x'
}
},
table
:
{
width
:
120
}
},
{
label
:
'砍价人数'
,
field
:
'userSize'
,
isSearch
:
false
,
form
:
{
component
:
'InputNumber'
,
labelMessage
:
'参与人数不能少于两人'
,
value
:
2
}
},
{
label
:
'最大帮砍次数'
,
field
:
'bargainCount'
,
isSearch
:
false
,
form
:
{
component
:
'InputNumber'
,
labelMessage
:
'参与人数不能少于两人'
,
value
:
2
}
},
{
label
:
'总限购数量'
,
field
:
'totalLimitCount'
,
isSearch
:
false
,
form
:
{
component
:
'InputNumber'
,
labelMessage
:
'用户最大能发起砍价的次数'
,
value
:
0
}
},
{
label
:
'砍价的最小金额'
,
field
:
'randomMinPrice'
,
isSearch
:
false
,
isTable
:
false
,
form
:
{
component
:
'InputNumber'
,
componentProps
:
{
min
:
0
,
precision
:
2
,
step
:
0.1
},
labelMessage
:
'用户每次砍价的最小金额'
,
value
:
0
}
},
{
label
:
'砍价的最大金额'
,
field
:
'randomMaxPrice'
,
isSearch
:
false
,
isTable
:
false
,
form
:
{
component
:
'InputNumber'
,
componentProps
:
{
min
:
0
,
precision
:
2
,
step
:
0.1
},
labelMessage
:
'用户每次砍价的最大金额'
,
value
:
0
}
},
{
label
:
'砍价成功数量'
,
field
:
'successCount'
,
isSearch
:
false
,
isForm
:
false
},
{
label
:
'活动状态'
,
field
:
'status'
,
dictType
:
DICT_TYPE
.
COMMON_STATUS
,
dictClass
:
'number'
,
isSearch
:
true
,
isForm
:
false
},
{
label
:
'拼团商品'
,
field
:
'spuId'
,
isSearch
:
false
,
form
:
{
colProps
:
{
span
:
24
}
}
},
{
label
:
'操作'
,
field
:
'action'
,
isForm
:
false
}
])
export
const
{
allSchemas
}
=
useCrudSchemas
(
crudSchemas
)
src/views/mall/promotion/bargain/activity/index.vue
0 → 100644
View file @
16369c00
<
template
>
<!-- 搜索工作栏 -->
<ContentWrap>
<Search
:schema=
"allSchemas.searchSchema"
@
reset=
"setSearchParams"
@
search=
"setSearchParams"
>
<!-- 新增等操作按钮 -->
<template
#
actionMore
>
<el-button
v-hasPermi=
"['promotion:bargain-activity:create']"
plain
type=
"primary"
@
click=
"openForm('create')"
>
<Icon
class=
"mr-5px"
icon=
"ep:plus"
/>
新增
</el-button>
</
template
>
</Search>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<Table
v-model:currentPage=
"tableObject.currentPage"
v-model:pageSize=
"tableObject.pageSize"
:columns=
"allSchemas.tableColumns"
:data=
"tableObject.tableList"
:loading=
"tableObject.loading"
:pagination=
"{
total: tableObject.total
}"
>
<
template
#
spuId=
"{ row }"
>
<el-image
:src=
"row.picUrl"
class=
"w-30px h-30px align-middle mr-5px"
@
click=
"imagePreview(row.picUrl)"
/>
<span
class=
"align-middle"
>
{{
row
.
spuName
}}
</span>
</
template
>
<
template
#
action=
"{ row }"
>
<el-button
v-hasPermi=
"['promotion:bargain-activity:update']"
link
type=
"primary"
@
click=
"openForm('update', row.id)"
>
编辑
</el-button>
<el-button
v-hasPermi=
"['promotion:bargain-activity:delete']"
link
type=
"danger"
@
click=
"handleDelete(row.id)"
>
删除
</el-button>
</
template
>
</Table>
</ContentWrap>
<!-- 表单弹窗:添加/修改 -->
<BargainActivityForm
ref=
"formRef"
@
success=
"getList"
/>
</template>
<
script
lang=
"ts"
setup
>
import
{
allSchemas
}
from
'./bargainActivity.data'
import
*
as
BargainActivityApi
from
'@/api/mall/promotion/bargain/bargainActivity'
import
BargainActivityForm
from
'./BargainActivityForm.vue'
import
{
createImageViewer
}
from
'@/components/ImageViewer'
import
{
sortTableColumns
}
from
'@/hooks/web/useCrudSchemas'
defineOptions
({
name
:
'PromotionBargainActivity'
})
// tableObject:表格的属性对象,可获得分页大小、条数等属性
// tableMethods:表格的操作对象,可进行获得分页、删除记录等操作
// 详细可见:https://doc.iocoder.cn/vue3/crud-schema/
const
{
tableObject
,
tableMethods
}
=
useTable
({
getListApi
:
BargainActivityApi
.
getBargainActivityPage
,
// 分页接口
delListApi
:
BargainActivityApi
.
deleteBargainActivity
// 删除接口
})
// 获得表格的各种操作
const
{
getList
,
setSearchParams
}
=
tableMethods
/** 商品图预览 */
const
imagePreview
=
(
imgUrl
:
string
)
=>
{
createImageViewer
({
urlList
:
[
imgUrl
]
})
}
/** 添加/修改操作 */
const
formRef
=
ref
()
const
openForm
=
(
type
:
string
,
id
?:
number
)
=>
{
formRef
.
value
.
open
(
type
,
id
)
}
/** 删除按钮操作 */
const
handleDelete
=
(
id
:
number
)
=>
{
tableMethods
.
delList
(
id
,
false
)
}
/** 初始化 **/
onMounted
(()
=>
{
// 获得活动列表
sortTableColumns
(
allSchemas
.
tableColumns
,
'spuId'
)
getList
()
})
</
script
>
src/views/mall/promotion/combination/CombinationActivityForm.vue
→
src/views/mall/promotion/combination/
activity/
CombinationActivityForm.vue
View file @
16369c00
...
@@ -19,7 +19,7 @@
...
@@ -19,7 +19,7 @@
<el-table-column
align=
"center"
label=
"拼团价格(元)"
min-width=
"168"
>
<el-table-column
align=
"center"
label=
"拼团价格(元)"
min-width=
"168"
>
<template
#
default=
"
{ row: sku }">
<template
#
default=
"
{ row: sku }">
<el-input-number
<el-input-number
v-model=
"sku.productConfig.
active
Price"
v-model=
"sku.productConfig.
combination
Price"
:min=
"0"
:min=
"0"
:precision=
"2"
:precision=
"2"
:step=
"0.1"
:step=
"0.1"
...
@@ -45,6 +45,7 @@ import { SpuAndSkuList, SpuProperty, SpuSelect } from '@/views/mall/promotion/co
...
@@ -45,6 +45,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
:
'PromotionCombinationActivityForm'
})
defineOptions
({
name
:
'PromotionCombinationActivityForm'
})
...
@@ -65,8 +66,8 @@ const spuList = ref<CombinationActivityApi.SpuExtension[]>([]) // 选择的 spu
...
@@ -65,8 +66,8 @@ const spuList = ref<CombinationActivityApi.SpuExtension[]>([]) // 选择的 spu
const
spuPropertyList
=
ref
<
SpuProperty
<
CombinationActivityApi
.
SpuExtension
>
[]
>
([])
const
spuPropertyList
=
ref
<
SpuProperty
<
CombinationActivityApi
.
SpuExtension
>
[]
>
([])
const
ruleConfig
:
RuleConfig
[]
=
[
const
ruleConfig
:
RuleConfig
[]
=
[
{
{
name
:
'productConfig.
active
Price'
,
name
:
'productConfig.
combination
Price'
,
rule
:
(
arg
)
=>
arg
>
0.01
,
rule
:
(
arg
)
=>
arg
>
=
0.01
,
message
:
'商品拼团价格不能小于0.01 !!!'
message
:
'商品拼团价格不能小于0.01 !!!'
}
}
]
]
...
@@ -98,13 +99,12 @@ const getSpuDetails = async (
...
@@ -98,13 +99,12 @@ const getSpuDetails = async (
let
config
:
CombinationProductVO
=
{
let
config
:
CombinationProductVO
=
{
spuId
:
spu
.
id
!
,
spuId
:
spu
.
id
!
,
skuId
:
sku
.
id
!
,
skuId
:
sku
.
id
!
,
active
Price
:
0
combination
Price
:
0
}
}
if
(
typeof
products
!==
'undefined'
)
{
if
(
typeof
products
!==
'undefined'
)
{
const
product
=
products
.
find
((
item
)
=>
item
.
skuId
===
sku
.
id
)
const
product
=
products
.
find
((
item
)
=>
item
.
skuId
===
sku
.
id
)
if
(
product
)
{
if
(
product
)
{
// 分转元
product
.
combinationPrice
=
formatToFraction
(
product
.
combinationPrice
)
product
.
activePrice
=
formatToFraction
(
product
.
activePrice
)
}
}
config
=
product
||
config
config
=
product
||
config
}
}
...
@@ -162,13 +162,14 @@ const submitForm = async () => {
...
@@ -162,13 +162,14 @@ const submitForm = async () => {
// 提交请求
// 提交请求
formLoading
.
value
=
true
formLoading
.
value
=
true
try
{
try
{
const
data
=
formRef
.
value
.
formModel
as
CombinationActivityApi
.
CombinationActivityVO
// 获得拼团商品配置
const
products
=
spuAndSkuListRef
.
value
.
getSkuConfigs
(
'productConfig'
)
const
products
=
cloneDeep
(
spuAndSkuListRef
.
value
.
getSkuConfigs
(
'productConfig'
))
products
.
forEach
((
item
:
CombinationProductVO
)
=>
{
products
.
forEach
((
item
:
CombinationActivityApi
.
CombinationProductVO
)
=>
{
// 拼团价格元转分
item
.
combinationPrice
=
convertToInteger
(
item
.
combinationPrice
)
item
.
activePrice
=
convertToInteger
(
item
.
activePrice
)
})
})
const
data
=
formRef
.
value
.
formModel
as
CombinationActivityApi
.
CombinationActivityVO
data
.
products
=
products
data
.
products
=
products
// 真正提交
if
(
formType
.
value
===
'create'
)
{
if
(
formType
.
value
===
'create'
)
{
await
CombinationActivityApi
.
createCombinationActivity
(
data
)
await
CombinationActivityApi
.
createCombinationActivity
(
data
)
message
.
success
(
t
(
'common.createSuccess'
))
message
.
success
(
t
(
'common.createSuccess'
))
...
...
src/views/mall/promotion/combination/combinationActivity.data.ts
→
src/views/mall/promotion/combination/
activity/
combinationActivity.data.ts
View file @
16369c00
...
@@ -122,13 +122,13 @@ const crudSchemas = reactive<CrudSchema[]>([
...
@@ -122,13 +122,13 @@ const crudSchemas = reactive<CrudSchema[]>([
},
},
{
{
label
:
'开团组数'
,
label
:
'开团组数'
,
field
:
'total
Num
'
,
field
:
'total
Count
'
,
isSearch
:
false
,
isSearch
:
false
,
isForm
:
false
isForm
:
false
},
},
{
{
label
:
'成团组数'
,
label
:
'成团组数'
,
field
:
'success
Num
'
,
field
:
'success
Count
'
,
isSearch
:
false
,
isSearch
:
false
,
isForm
:
false
isForm
:
false
},
},
...
...
src/views/mall/promotion/combination/index.vue
→
src/views/mall/promotion/combination/
activity/
index.vue
View file @
16369c00
<
template
>
<
template
>
<doc-alert
title=
"功能开启"
url=
"https://doc.iocoder.cn/mall/build/"
/>
<!-- 搜索工作栏 -->
<!-- 搜索工作栏 -->
<ContentWrap>
<ContentWrap>
<Search
:schema=
"allSchemas.searchSchema"
@
reset=
"setSearchParams"
@
search=
"setSearchParams"
>
<Search
:schema=
"allSchemas.searchSchema"
@
reset=
"setSearchParams"
@
search=
"setSearchParams"
>
...
@@ -10,8 +12,7 @@
...
@@ -10,8 +12,7 @@
type=
"primary"
type=
"primary"
@
click=
"openForm('create')"
@
click=
"openForm('create')"
>
>
<Icon
class=
"mr-5px"
icon=
"ep:plus"
/>
<Icon
class=
"mr-5px"
icon=
"ep:plus"
/>
新增
新增
</el-button>
</el-button>
</
template
>
</
template
>
</Search>
</Search>
...
@@ -65,7 +66,7 @@
...
@@ -65,7 +66,7 @@
import
{
allSchemas
}
from
'./combinationActivity.data'
import
{
allSchemas
}
from
'./combinationActivity.data'
import
*
as
CombinationActivityApi
from
'@/api/mall/promotion/combination/combinationActivity'
import
*
as
CombinationActivityApi
from
'@/api/mall/promotion/combination/combinationActivity'
import
CombinationActivityForm
from
'./CombinationActivityForm.vue'
import
CombinationActivityForm
from
'./CombinationActivityForm.vue'
import
{
cloneDeep
}
from
'lodash-e
s'
import
{
sortTableColumns
}
from
'@/hooks/web/useCrudSchema
s'
import
{
createImageViewer
}
from
'@/components/ImageViewer'
import
{
createImageViewer
}
from
'@/components/ImageViewer'
defineOptions
({
name
:
'PromotionCombinationActivity'
})
defineOptions
({
name
:
'PromotionCombinationActivity'
})
...
@@ -98,20 +99,10 @@ const handleDelete = (id: number) => {
...
@@ -98,20 +99,10 @@ const handleDelete = (id: number) => {
tableMethods
.
delList
(
id
,
false
)
tableMethods
.
delList
(
id
,
false
)
}
}
// TODO @puhui999:要不还是使用原生的 element plus 做。感觉 crud schema 复杂界面,做起来麻烦
/** 初始化 **/
/** 初始化 **/
onMounted
(()
=>
{
onMounted
(()
=>
{
/**
// 获得活动列表
TODO
sortTableColumns
(
allSchemas
.
tableColumns
,
'spuId'
)
后面准备封装成一个函数来操作 tableColumns 重新排列:比如说需求是表单上商品选择是在后面的而列表展示的时候需要调到位置。
封装效果支持批量操作,给出 field 和需要插入的位置,例:[{field:'spuId',index: 1}] 效果为把 field 为 spuId 的 column 移动到第一个位置
*/
// 处理一下表格列让商品往前
const
index
=
allSchemas
.
tableColumns
.
findIndex
((
item
)
=>
item
.
field
===
'spuId'
)
const
column
=
cloneDeep
(
allSchemas
.
tableColumns
[
index
])
allSchemas
.
tableColumns
.
splice
(
index
,
1
)
// 添加到开头
allSchemas
.
tableColumns
.
unshift
(
column
)
getList
()
getList
()
})
})
</
script
>
</
script
>
src/views/mall/promotion/combination/record/index.vue
0 → 100644
View file @
16369c00
src/views/mall/promotion/coupon/index.vue
View file @
16369c00
<
template
>
<
template
>
<doc-alert
title=
"功能开启"
url=
"https://doc.iocoder.cn/mall/build/"
/>
<doc-alert
title=
"功能开启"
url=
"https://doc.iocoder.cn/mall/build/"
/>
<ContentWrap>
<!-- 搜索工作栏 -->
<!-- 搜索工作栏 -->
<el-form
:model=
"queryParams"
ref=
"queryFormRef"
:inline=
"true"
label-width=
"68px"
>
<ContentWrap>
<el-form
ref=
"queryFormRef"
:inline=
"true"
:model=
"queryParams"
class=
"-mb-15px"
label-width=
"68px"
>
<el-form-item
label=
"会员昵称"
prop=
"nickname"
>
<el-form-item
label=
"会员昵称"
prop=
"nickname"
>
<el-input
<el-input
v-model=
"queryParams.nickname"
v-model=
"queryParams.nickname"
class=
"!w-240px"
placeholder=
"请输入会员昵称"
placeholder=
"请输入会员昵称"
clearable
clearable
@
keyup=
"handleQuery"
@
keyup=
"handleQuery"
...
@@ -15,27 +22,19 @@
...
@@ -15,27 +22,19 @@
<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"
style=
"width: 240px"
type=
"datetimerange"
value-format=
"YYYY-MM-DD HH:mm:ss"
value-format=
"YYYY-MM-DD HH:mm:ss"
range-separator=
"-
"
type=
"daterange
"
start-placeholder=
"开始日期"
start-placeholder=
"开始日期"
end-placeholder=
"结束日期"
end-placeholder=
"结束日期"
:default-time=
"[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)]"
:default-time=
"[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class=
"!w-240px"
/>
/>
</el-form-item>
</el-form-item>
<el-form-item>
<el-form-item>
<el-button
type=
"primary"
@
click=
"handleQuery"
>
<el-button
@
click=
"handleQuery"
>
<Icon
icon=
"ep:search"
class=
"mr-5px"
/>
搜索
</el-button>
<Icon
icon=
"ep:search"
class=
"mr-5px"
/>
搜索
</el-button>
<el-button
@
click=
"resetQuery"
>
<Icon
icon=
"ep:refresh"
class=
"mr-5px"
/>
重置
</el-button>
<el-button
@
click=
"resetQuery"
>
<Icon
icon=
"ep:refresh"
class=
"mr-5px"
/>
重置
</el-button>
</el-form-item>
</el-form-item>
</el-form>
</el-form>
<!-- 操作工具栏 -->
<!--
<el-row
:gutter=
"10"
class=
"mb8"
>
<right-toolbar
v-model:showSearch=
"showSearch"
@
queryTable=
"getList"
/>
</el-row>
-->
</ContentWrap>
</ContentWrap>
<ContentWrap>
<ContentWrap>
...
@@ -86,43 +85,38 @@
...
@@ -86,43 +85,38 @@
<el-table-column
label=
"操作"
align=
"center"
class-name=
"small-padding fixed-width"
>
<el-table-column
label=
"操作"
align=
"center"
class-name=
"small-padding fixed-width"
>
<
template
#
default=
"scope"
>
<
template
#
default=
"scope"
>
<el-button
<el-button
size=
"small"
type=
"primary"
link
@
click=
"handleDelete(scope.row)"
v-hasPermi=
"['promotion:coupon:delete']"
v-hasPermi=
"['promotion:coupon:delete']"
><Icon
icon=
"ep:delete"
:size=
"12"
class=
"mr-1px"
/>
回收
</el-button
type=
"danger"
link
@
click=
"handleDelete(scope.row.id)"
>
>
回收
</el-button>
</
template
>
</
template
>
</el-table-column>
</el-table-column>
</el-table>
</el-table>
<!-- 分页 -->
<!-- 分页组件 -->
<Pagination
<pagination
v-show=
"total > 0"
:total=
"total"
v-model:page=
"queryParams.pageNo"
v-model:limit=
"queryParams.pageSize"
v-model:limit=
"queryParams.pageSize"
v-model:page=
"queryParams.pageNo"
:total=
"total"
@
pagination=
"getList"
@
pagination=
"getList"
/>
/>
</ContentWrap>
</ContentWrap>
</template>
</template>
<
script
setup
lang=
"ts"
name=
"PromotionCoupon"
>
<
script
setup
lang=
"ts"
name=
"PromotionCoupon"
>
import
{
deleteCoupon
,
getCouponPage
}
from
'@/api/mall/promotion/coupon'
import
{
deleteCoupon
,
getCouponPage
}
from
'@/api/mall/promotion/coupon
/coupon
'
import
{
DICT_TYPE
,
getIntDictOptions
}
from
'@/utils/dict'
import
{
DICT_TYPE
,
getIntDictOptions
}
from
'@/utils/dict'
import
{
dateFormatter
}
from
'@/utils/formatTime'
import
{
dateFormatter
}
from
'@/utils/formatTime'
import
{
FormInstance
}
from
'element-plus'
// 消息弹窗
defineOptions
({
name
:
'PromotionCoupon'
})
const
message
=
useMessage
()
// 遮罩层
const
message
=
useMessage
()
// 消息弹窗
const
loading
=
ref
(
true
)
// 总条数
const
loading
=
ref
(
true
)
// 列表的加载中
const
total
=
ref
(
0
)
const
total
=
ref
(
0
)
// 列表的总页数
// 优惠劵列表
const
list
=
ref
([])
// 字典表格数据
const
list
=
ref
([])
// 查询参数
// 查询参数
const
queryParams
=
reactive
({
const
queryParams
=
reactive
({
pageNo
:
1
,
pageNo
:
1
,
...
@@ -130,9 +124,9 @@ const queryParams = reactive({
...
@@ -130,9 +124,9 @@ const queryParams = reactive({
createTime
:
[],
createTime
:
[],
status
:
undefined
status
:
undefined
})
})
// Tab 筛选
const
queryFormRef
=
ref
()
// 搜索的表单
const
activeTab
=
ref
(
'all'
)
const
activeTab
=
ref
(
'all'
)
// Tab 筛选
const
statusTabs
=
reactive
([
const
statusTabs
=
reactive
([
{
{
label
:
'全部'
,
label
:
'全部'
,
...
@@ -140,8 +134,6 @@ const statusTabs = reactive([
...
@@ -140,8 +134,6 @@ const statusTabs = reactive([
}
}
])
])
const
queryFormRef
=
ref
<
FormInstance
|
null
>
(
null
)
/** 查询列表 */
/** 查询列表 */
const
getList
=
async
()
=>
{
const
getList
=
async
()
=>
{
loading
.
value
=
true
loading
.
value
=
true
...
@@ -168,16 +160,17 @@ const resetQuery = () => {
...
@@ -168,16 +160,17 @@ const resetQuery = () => {
}
}
/** 删除按钮操作 */
/** 删除按钮操作 */
const
handleDelete
=
async
(
row
)
=>
{
const
handleDelete
=
async
(
id
:
number
)
=>
{
const
id
=
row
.
id
try
{
try
{
// 二次确认
await
message
.
confirm
(
await
message
.
confirm
(
'回收将会收回会员领取的待使用的优惠券,已使用的将无法回收,确定要回收所选优惠券吗?'
'回收将会收回会员领取的待使用的优惠券,已使用的将无法回收,确定要回收所选优惠券吗?'
)
)
// 发起删除
await
deleteCoupon
(
id
)
await
deleteCoupon
(
id
)
getList
()
message
.
notifySuccess
(
'回收成功'
)
message
.
notifySuccess
(
'回收成功'
)
// 重新加载列表
await
getList
()
}
catch
{}
}
catch
{}
}
}
...
@@ -187,6 +180,7 @@ const onTabChange = (tabName) => {
...
@@ -187,6 +180,7 @@ const onTabChange = (tabName) => {
getList
()
getList
()
}
}
/** 初始化 **/
onMounted
(()
=>
{
onMounted
(()
=>
{
getList
()
getList
()
// 设置 statuses 过滤
// 设置 statuses 过滤
...
...
src/views/mall/promotion/coupon/template/CouponTemplateForm.vue
0 → 100644
View file @
16369c00
<
template
>
<Dialog
v-model=
"dialogVisible"
:title=
"dialogTitle"
>
<el-form
ref=
"formRef"
v-loading=
"formLoading"
:model=
"formData"
:rules=
"formRules"
label-width=
"140px"
>
<el-form-item
label=
"优惠券名称"
prop=
"name"
>
<el-input
v-model=
"formData.name"
placeholder=
"请输入优惠券名称"
/>
</el-form-item>
<el-form-item
label=
"优惠券类型"
prop=
"discountType"
>
<el-radio-group
v-model=
"formData.discountType"
>
<el-radio
v-for=
"dict in getIntDictOptions(DICT_TYPE.PROMOTION_DISCOUNT_TYPE)"
:key=
"dict.value"
:label=
"dict.value"
>
{{
dict
.
label
}}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
v-if=
"formData.discountType === PromotionDiscountTypeEnum.PRICE.type"
label=
"优惠券面额"
prop=
"discountPrice"
>
<el-input-number
v-model=
"formData.discountPrice"
placeholder=
"请输入优惠金额,单位:元"
style=
"width: 400px"
:precision=
"2"
:min=
"0"
/>
元
</el-form-item>
<el-form-item
v-if=
"formData.discountType === PromotionDiscountTypeEnum.PERCENT.type"
label=
"优惠券折扣"
prop=
"discountPercent"
>
<el-input-number
v-model=
"formData.discountPercent"
placeholder=
"优惠券折扣不能小于 1 折,且不可大于 9.9 折"
style=
"width: 400px"
:precision=
"1"
:min=
"1"
:max=
"9.9"
/>
折
</el-form-item>
<el-form-item
v-if=
"formData.discountType === PromotionDiscountTypeEnum.PERCENT.type"
label=
"最多优惠"
prop=
"discountLimitPrice"
>
<el-input-number
v-model=
"formData.discountLimitPrice"
placeholder=
"请输入最多优惠"
style=
"width: 400px"
:precision=
"2"
:min=
"0"
/>
元
</el-form-item>
<el-form-item
label=
"满多少元可以使用"
prop=
"usePrice"
>
<el-input-number
v-model=
"formData.usePrice"
placeholder=
"无门槛请设为 0"
style=
"width: 400px"
:precision=
"2"
:min=
"0"
/>
元
</el-form-item>
<el-form-item
label=
"领取方式"
prop=
"takeType"
>
<el-radio-group
v-model=
"formData.takeType"
>
<el-radio
:key=
"1"
:label=
"1"
>
直接领取
</el-radio>
<el-radio
:key=
"2"
:label=
"2"
>
指定发放
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
v-if=
"formData.takeType === 1"
label=
"发放数量"
prop=
"totalCount"
>
<el-input-number
v-model=
"formData.totalCount"
placeholder=
"发放数量,没有之后不能领取或发放,-1 为不限制"
style=
"width: 400px"
:precision=
"0"
:min=
"-1"
/>
张
</el-form-item>
<el-form-item
v-if=
"formData.takeType === 1"
label=
"每人限领个数"
prop=
"takeLimitCount"
>
<el-input-number
v-model=
"formData.takeLimitCount"
placeholder=
"设置为 -1 时,可无限领取"
style=
"width: 400px"
:precision=
"0"
:min=
"-1"
/>
张
</el-form-item>
<el-form-item
label=
"有效期类型"
prop=
"validityType"
>
<el-radio-group
v-model=
"formData.validityType"
>
<el-radio
v-for=
"dict in getIntDictOptions(DICT_TYPE.PROMOTION_COUPON_TEMPLATE_VALIDITY_TYPE)"
:key=
"dict.value"
:label=
"dict.value"
>
{{
dict
.
label
}}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
v-if=
"formData.validityType === CouponTemplateValidityTypeEnum.DATE.type"
label=
"固定日期"
prop=
"validTimes"
>
<el-date-picker
v-model=
"formData.validTimes"
style=
"width: 240px"
value-format=
"YYYY-MM-DD HH:mm:ss"
type=
"datetimerange"
:default-time=
"[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)]"
/>
</el-form-item>
<el-form-item
v-if=
"formData.validityType === CouponTemplateValidityTypeEnum.TERM.type"
label=
"领取日期"
prop=
"fixedStartTerm"
>
第
<el-input-number
v-model=
"formData.fixedStartTerm"
placeholder=
"0 为今天生效"
style=
"width: 165px"
:precision=
"0"
:min=
"0"
/>
至
<el-input-number
v-model=
"formData.fixedEndTerm"
placeholder=
"请输入结束天数"
style=
"width: 165px"
:precision=
"0"
:min=
"0"
/>
天有效
</el-form-item>
<el-form-item
label=
"活动商品"
prop=
"productScope"
>
<el-radio-group
v-model=
"formData.productScope"
>
<el-radio
v-for=
"dict in getIntDictOptions(DICT_TYPE.PROMOTION_PRODUCT_SCOPE)"
:key=
"dict.value"
:label=
"dict.value"
>
{{
dict
.
label
}}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
v-if=
"formData.productScope === PromotionProductScopeEnum.SPU.scope"
prop=
"productSpuIds"
>
<el-select
v-model=
"formData.productSpuIds"
placeholder=
"请选择活动商品"
clearable
multiple
filterable
style=
"width: 400px"
>
<el-option
v-for=
"item in productSpus"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
>
<span
style=
"float: left"
>
{{
item
.
name
}}
</span>
<span
style=
"float: right; font-size: 13px; color: #8492a6"
>
¥
{{
(
item
.
minPrice
/
100.0
).
toFixed
(
2
)
}}
</span>
</el-option>
</el-select>
</el-form-item>
</el-form>
<template
#
footer
>
<el-button
:disabled=
"formLoading"
type=
"primary"
@
click=
"submitForm"
>
确 定
</el-button>
<el-button
@
click=
"dialogVisible = false"
>
取 消
</el-button>
</
template
>
</Dialog>
</template>
<
script
lang=
"ts"
setup
>
import
{
DICT_TYPE
,
getIntDictOptions
}
from
'@/utils/dict'
import
*
as
CouponTemplateApi
from
'@/api/mall/promotion/coupon/couponTemplate'
import
*
as
ProductSpuApi
from
'@/api/mall/product/spu'
import
{
CouponTemplateValidityTypeEnum
,
PromotionDiscountTypeEnum
,
PromotionProductScopeEnum
}
from
'@/utils/constants'
defineOptions
({
name
:
'CouponTemplateForm'
})
const
{
t
}
=
useI18n
()
// 国际化
const
message
=
useMessage
()
// 消息弹窗
const
dialogVisible
=
ref
(
false
)
// 弹窗的是否展示
const
dialogTitle
=
ref
(
''
)
// 弹窗的标题
const
formLoading
=
ref
(
false
)
// 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
const
formType
=
ref
(
''
)
// 表单的类型:create - 新增;update - 修改
const
formData
=
ref
({
id
:
undefined
,
name
:
undefined
,
discountType
:
PromotionDiscountTypeEnum
.
PRICE
.
type
,
discountPrice
:
undefined
,
discountPercent
:
undefined
,
discountLimitPrice
:
undefined
,
usePrice
:
undefined
,
takeType
:
1
,
totalCount
:
undefined
,
takeLimitCount
:
undefined
,
validityType
:
CouponTemplateValidityTypeEnum
.
DATE
.
type
,
validTimes
:
[],
validStartTime
:
undefined
,
validEndTime
:
undefined
,
fixedStartTerm
:
undefined
,
fixedEndTerm
:
undefined
,
productScope
:
PromotionProductScopeEnum
.
ALL
.
scope
,
productSpuIds
:
[]
})
const
formRules
=
reactive
({
name
:
[{
required
:
true
,
message
:
'优惠券名称不能为空'
,
trigger
:
'blur'
}],
discountType
:
[{
required
:
true
,
message
:
'优惠券类型不能为空'
,
trigger
:
'change'
}],
discountPrice
:
[{
required
:
true
,
message
:
'优惠券面额不能为空'
,
trigger
:
'blur'
}],
discountPercent
:
[{
required
:
true
,
message
:
'优惠券折扣不能为空'
,
trigger
:
'blur'
}],
discountLimitPrice
:
[{
required
:
true
,
message
:
'最多优惠不能为空'
,
trigger
:
'blur'
}],
usePrice
:
[{
required
:
true
,
message
:
'满多少元可以使用不能为空'
,
trigger
:
'blur'
}],
takeType
:
[{
required
:
true
,
message
:
'领取方式不能为空'
,
trigger
:
'change'
}],
totalCount
:
[{
required
:
true
,
message
:
'发放数量不能为空'
,
trigger
:
'blur'
}],
takeLimitCount
:
[{
required
:
true
,
message
:
'每人限领个数不能为空'
,
trigger
:
'blur'
}],
validityType
:
[{
required
:
true
,
message
:
'有效期类型不能为空'
,
trigger
:
'change'
}],
validTimes
:
[{
required
:
true
,
message
:
'固定日期不能为空'
,
trigger
:
'change'
}],
fixedStartTerm
:
[{
required
:
true
,
message
:
'开始领取天数不能为空'
,
trigger
:
'blur'
}],
fixedEndTerm
:
[{
required
:
true
,
message
:
'开始领取天数不能为空'
,
trigger
:
'blur'
}],
productScope
:
[{
required
:
true
,
message
:
'商品范围不能为空'
,
trigger
:
'blur'
}],
productSpuIds
:
[{
required
:
true
,
message
:
'商品范围不能为空'
,
trigger
:
'blur'
}]
})
const
formRef
=
ref
()
// 表单 Ref
const
productSpus
=
ref
([])
// 商品列表
/** 打开弹窗 */
const
open
=
async
(
type
:
string
,
id
?:
number
)
=>
{
dialogVisible
.
value
=
true
dialogTitle
.
value
=
t
(
'action.'
+
type
)
formType
.
value
=
type
resetForm
()
// 修改时,设置数据
if
(
id
)
{
formLoading
.
value
=
true
try
{
const
data
=
await
CouponTemplateApi
.
getCouponTemplate
(
id
)
formData
.
value
=
{
...
data
,
discountPrice
:
data
.
discountPrice
!==
undefined
?
data
.
discountPrice
/
100.0
:
undefined
,
discountPercent
:
data
.
discountPercent
!==
undefined
?
data
.
discountPercent
/
10.0
:
undefined
,
discountLimitPrice
:
data
.
discountLimitPrice
!==
undefined
?
data
.
discountLimitPrice
/
100.0
:
undefined
,
usePrice
:
data
.
usePrice
!==
undefined
?
data
.
usePrice
/
100.0
:
undefined
,
validTimes
:
[
data
.
validStartTime
,
data
.
validEndTime
]
}
}
finally
{
formLoading
.
value
=
false
}
}
// 获得商品列表
productSpus
.
value
=
await
ProductSpuApi
.
getSpuSimpleList
()
}
defineExpose
({
open
})
// 提供 open 方法,用于打开弹窗
/** 提交表单 */
const
emit
=
defineEmits
([
'success'
])
// 定义 success 事件,用于操作成功后的回调
const
submitForm
=
async
()
=>
{
// 校验表单
if
(
!
formRef
)
return
const
valid
=
await
formRef
.
value
.
validate
()
if
(
!
valid
)
return
// 提交请求
formLoading
.
value
=
true
try
{
const
data
=
{
...
formData
.
value
,
discountPrice
:
formData
.
value
.
discountPrice
!==
undefined
?
formData
.
value
.
discountPrice
*
100
:
undefined
,
discountPercent
:
formData
.
value
.
discountPercent
!==
undefined
?
formData
.
value
.
discountPercent
*
10
:
undefined
,
discountLimitPrice
:
formData
.
value
.
discountLimitPrice
!==
undefined
?
formData
.
value
.
discountLimitPrice
*
100
:
undefined
,
usePrice
:
formData
.
value
.
usePrice
!==
undefined
?
formData
.
value
.
usePrice
*
100
:
undefined
,
validStartTime
:
formData
.
value
.
validTimes
&&
formData
.
value
.
validTimes
.
length
===
2
?
formData
.
value
.
validTimes
[
0
]
:
undefined
,
validEndTime
:
formData
.
value
.
validTimes
&&
formData
.
value
.
validTimes
.
length
===
2
?
formData
.
value
.
validTimes
[
1
]
:
undefined
}
as
CouponTemplateApi
.
CouponTemplateVO
if
(
formType
.
value
===
'create'
)
{
await
CouponTemplateApi
.
createCouponTemplate
(
data
)
message
.
success
(
t
(
'common.createSuccess'
))
}
else
{
await
CouponTemplateApi
.
updateCouponTemplate
(
data
)
message
.
success
(
t
(
'common.updateSuccess'
))
}
dialogVisible
.
value
=
false
// 发送操作成功的事件
emit
(
'success'
)
}
finally
{
formLoading
.
value
=
false
}
}
/** 重置表单 */
const
resetForm
=
()
=>
{
formData
.
value
=
{
id
:
undefined
,
name
:
undefined
,
discountType
:
PromotionDiscountTypeEnum
.
PRICE
.
type
,
discountPrice
:
undefined
,
discountPercent
:
undefined
,
discountLimitPrice
:
undefined
,
usePrice
:
undefined
,
takeType
:
1
,
totalCount
:
undefined
,
takeLimitCount
:
undefined
,
validityType
:
CouponTemplateValidityTypeEnum
.
DATE
.
type
,
validTimes
:
[],
validStartTime
:
undefined
,
validEndTime
:
undefined
,
fixedStartTerm
:
undefined
,
fixedEndTerm
:
undefined
,
productScope
:
PromotionProductScopeEnum
.
ALL
.
scope
,
productSpuIds
:
[]
}
formRef
.
value
?.
resetFields
()
}
</
script
>
src/views/mall/promotion/coupon/template/index.vue
0 → 100755
View file @
16369c00
<
template
>
<doc-alert
title=
"功能开启"
url=
"https://doc.iocoder.cn/mall/build/"
/>
<!-- 搜索工作栏 -->
<ContentWrap>
<el-form
ref=
"queryFormRef"
:inline=
"true"
:model=
"queryParams"
class=
"-mb-15px"
label-width=
"82px"
>
<el-form-item
label=
"优惠券名称"
prop=
"name"
>
<el-input
v-model=
"queryParams.name"
class=
"!w-240px"
placeholder=
"请输入优惠劵名"
clearable
@
keyup=
"handleQuery"
/>
</el-form-item>
<el-form-item
label=
"优惠券类型"
prop=
"discountType"
>
<el-select
v-model=
"queryParams.discountType"
class=
"!w-240px"
placeholder=
"请选择优惠券类型"
clearable
>
<el-option
v-for=
"dict in getIntDictOptions(DICT_TYPE.PROMOTION_DISCOUNT_TYPE)"
:key=
"dict.value"
:label=
"dict.label"
:value=
"dict.value"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"优惠券状态"
prop=
"status"
>
<el-select
v-model=
"queryParams.status"
class=
"!w-240px"
placeholder=
"请选择优惠券状态"
clearable
>
<el-option
v-for=
"dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
:key=
"dict.value"
:label=
"dict.label"
:value=
"dict.value"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"创建时间"
prop=
"createTime"
>
<el-date-picker
v-model=
"queryParams.createTime"
value-format=
"YYYY-MM-DD HH:mm:ss"
type=
"daterange"
start-placeholder=
"开始日期"
end-placeholder=
"结束日期"
:default-time=
"[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class=
"!w-240px"
/>
</el-form-item>
<el-form-item>
<el-button
@
click=
"handleQuery"
>
<Icon
icon=
"ep:search"
class=
"mr-5px"
/>
搜索
</el-button>
<el-button
@
click=
"resetQuery"
>
<Icon
icon=
"ep:refresh"
class=
"mr-5px"
/>
重置
</el-button>
<el-button
v-hasPermi=
"['promotion:coupon-template:create']"
plain
type=
"primary"
@
click=
"openForm('create')"
>
<Icon
class=
"mr-5px"
icon=
"ep:plus"
/>
新增
</el-button>
<el-button
plain
type=
"success"
@
click=
"$router.push('/promotion/coupon')"
v-hasPermi=
"['promotion:coupon:query']"
>
<Icon
icon=
"ep:operation"
class=
"mr-5px"
/>
会员优惠劵
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table
v-loading=
"loading"
:data=
"list"
>
<el-table-column
label=
"优惠券名称"
align=
"center"
prop=
"name"
/>
<el-table-column
label=
"优惠券类型"
align=
"center"
prop=
"discountType"
>
<template
#
default=
"scope"
>
<dict-tag
:type=
"DICT_TYPE.PROMOTION_DISCOUNT_TYPE"
:value=
"scope.row.discountType"
/>
</
template
>
</el-table-column>
<el-table-column
label=
"优惠金额 / 折扣"
align=
"center"
prop=
"discount"
:formatter=
"discountFormat"
/>
<el-table-column
label=
"发放数量"
align=
"center"
prop=
"totalCount"
/>
<el-table-column
label=
"剩余数量"
align=
"center"
prop=
"totalCount"
:formatter=
"(row) => row.totalCount - row.takeCount"
/>
<el-table-column
label=
"领取上限"
align=
"center"
prop=
"takeLimitCount"
:formatter=
"takeLimitCountFormat"
/>
<el-table-column
label=
"有效期限"
align=
"center"
prop=
"validityType"
width=
"190"
:formatter=
"validityTypeFormat"
/>
<el-table-column
label=
"状态"
align=
"center"
prop=
"status"
>
<
template
#
default=
"scope"
>
<el-switch
v-model=
"scope.row.status"
:active-value=
"0"
:inactive-value=
"1"
@
change=
"handleStatusChange(scope.row)"
/>
</
template
>
</el-table-column>
<el-table-column
label=
"创建时间"
align=
"center"
prop=
"createTime"
:formatter=
"dateFormatter"
width=
"180"
/>
<el-table-column
label=
"操作"
align=
"center"
class-name=
"small-padding fixed-width"
>
<
template
#
default=
"scope"
>
<el-button
v-hasPermi=
"['promotion:coupon-template:update']"
link
type=
"primary"
@
click=
"openForm('update', scope.row.id)"
>
修改
</el-button>
<el-button
v-hasPermi=
"['promotion:coupon-template:delete']"
link
type=
"danger"
@
click=
"handleDelete(scope.row.id)"
>
删除
</el-button>
</
template
>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
v-model:limit=
"queryParams.pageSize"
v-model:page=
"queryParams.pageNo"
:total=
"total"
@
pagination=
"getList"
/>
</ContentWrap>
<!-- 表单弹窗:添加/修改 -->
<CouponTemplateForm
ref=
"formRef"
@
success=
"getList"
/>
</template>
<
script
lang=
"ts"
setup
>
import
*
as
CouponTemplateApi
from
'@/api/mall/promotion/coupon/couponTemplate'
import
{
CommonStatusEnum
,
CouponTemplateValidityTypeEnum
,
PromotionDiscountTypeEnum
}
from
'@/utils/constants'
import
{
DICT_TYPE
,
getIntDictOptions
}
from
'@/utils/dict'
import
{
dateFormatter
,
formatDate
}
from
'@/utils/formatTime'
import
CouponTemplateForm
from
'./CouponTemplateForm.vue'
defineOptions
({
name
:
'PromotionCouponTemplate'
})
const
message
=
useMessage
()
// 消息弹窗
const
{
t
}
=
useI18n
()
// 国际化
const
loading
=
ref
(
true
)
// 列表的加载中
const
total
=
ref
(
0
)
// 列表的总页数
const
list
=
ref
([])
// 字典表格数据
const
queryParams
=
reactive
({
pageNo
:
1
,
pageSize
:
10
,
name
:
null
,
status
:
null
,
type
:
null
,
createTime
:
[]
})
const
queryFormRef
=
ref
()
// 搜索的表单
/** 查询列表 */
const
getList
=
async
()
=>
{
loading
.
value
=
true
try
{
// 执行查询
const
data
=
await
CouponTemplateApi
.
getCouponTemplatePage
(
queryParams
)
list
.
value
=
data
.
list
total
.
value
=
data
.
total
}
finally
{
loading
.
value
=
false
}
}
/** 搜索按钮操作 */
const
handleQuery
=
()
=>
{
queryParams
.
pageNo
=
1
getList
()
}
/** 重置按钮操作 */
const
resetQuery
=
()
=>
{
queryFormRef
?.
value
?.
resetFields
()
handleQuery
()
}
/** 添加/修改操作 */
const
formRef
=
ref
()
const
openForm
=
(
type
:
string
,
id
?:
number
)
=>
{
formRef
.
value
.
open
(
type
,
id
)
}
/** 优惠劵模板状态修改 */
const
handleStatusChange
=
async
(
row
:
any
)
=>
{
// 此时,row 已经变成目标状态了,所以可以直接提交请求和提示
let
text
=
row
.
status
===
CommonStatusEnum
.
ENABLE
?
'启用'
:
'停用'
try
{
await
message
.
confirm
(
'确认要"'
+
text
+
'""'
+
row
.
name
+
'"优惠劵吗?'
)
await
CouponTemplateApi
.
updateCouponTemplateStatus
(
row
.
id
,
row
.
status
)
message
.
success
(
text
+
'成功'
)
}
catch
{
// 异常时,需要将 row.status 状态重置回之前的
row
.
status
=
row
.
status
===
CommonStatusEnum
.
ENABLE
?
CommonStatusEnum
.
DISABLE
:
CommonStatusEnum
.
ENABLE
}
}
/** 删除按钮操作 */
const
handleDelete
=
async
(
id
:
number
)
=>
{
try
{
// 删除的二次确认
await
message
.
confirm
(
'是否确认删除优惠劵编号为"'
+
id
+
'"的数据项?'
)
// 发起删除
await
CouponTemplateApi
.
deleteCouponTemplate
(
id
)
message
.
success
(
t
(
'common.delSuccess'
))
// 刷新列表
await
getList
()
}
catch
{}
}
// 格式化【优惠金额/折扣】
const
discountFormat
=
(
row
:
any
)
=>
{
if
(
row
.
discountType
===
PromotionDiscountTypeEnum
.
PRICE
.
type
)
{
return
`¥
${(
row
.
discountPrice
/
100.0
).
toFixed
(
2
)}
`
}
if
(
row
.
discountType
===
PromotionDiscountTypeEnum
.
PERCENT
.
type
)
{
return
`¥
${(
row
.
discountPrice
/
100.0
).
toFixed
(
2
)}
`
}
return
'未知【'
+
row
.
discountType
+
'】'
}
// 格式化【领取上限】
const
takeLimitCountFormat
=
(
row
:
any
)
=>
{
if
(
row
.
takeLimitCount
===
-
1
)
{
return
'无领取限制'
}
return
`
${
row
.
takeLimitCount
}
张/人`
}
// 格式化【有效期限】
const
validityTypeFormat
=
(
row
:
any
)
=>
{
if
(
row
.
validityType
===
CouponTemplateValidityTypeEnum
.
DATE
.
type
)
{
return
`
${
formatDate
(
row
.
validStartTime
)}
至
${
formatDate
(
row
.
validEndTime
)}
`
}
if
(
row
.
validityType
===
CouponTemplateValidityTypeEnum
.
TERM
.
type
)
{
return
`领取后第
${
row
.
fixedStartTerm
}
-
${
row
.
fixedEndTerm
}
天内可用`
}
return
'未知【'
+
row
.
validityType
+
'】'
}
/** 初始化 **/
onMounted
(()
=>
{
getList
()
})
</
script
>
src/views/mall/promotion/couponTemplate/index.vue
deleted
100755 → 0
View file @
c3a8479e
<
template
>
<doc-alert
title=
"功能开启"
url=
"https://doc.iocoder.cn/mall/build/"
/>
<!-- 搜索工作栏 -->
<ContentWrap>
<el-form
:model=
"queryParams"
ref=
"queryFormRef"
:inline=
"true"
v-show=
"showSearch"
label-width=
"82px"
>
<el-form-item
label=
"优惠券名称"
prop=
"name"
>
<el-input
v-model=
"queryParams.name"
placeholder=
"请输入优惠劵名"
clearable
@
keyup=
"handleQuery"
/>
</el-form-item>
<el-form-item
label=
"优惠券类型"
prop=
"discountType"
>
<el-select
v-model=
"queryParams.discountType"
placeholder=
"请选择优惠券类型"
clearable
>
<el-option
v-for=
"dict in getIntDictOptions(DICT_TYPE.PROMOTION_DISCOUNT_TYPE)"
:key=
"dict.value"
:label=
"dict.label"
:value=
"dict.value"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"优惠券状态"
prop=
"status"
>
<el-select
v-model=
"queryParams.status"
placeholder=
"请选择优惠券状态"
clearable
>
<el-option
v-for=
"dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
:key=
"dict.value"
:label=
"dict.label"
:value=
"dict.value"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"创建时间"
prop=
"createTime"
>
<el-date-picker
v-model=
"queryParams.createTime"
style=
"width: 240px"
type=
"datetimerange"
value-format=
"YYYY-MM-DD HH:mm:ss"
range-separator=
"-"
start-placeholder=
"开始日期"
end-placeholder=
"结束日期"
:default-time=
"[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)]"
/>
</el-form-item>
<el-form-item>
<el-button
type=
"primary"
@
click=
"handleQuery"
>
<Icon
icon=
"ep:search"
class=
"mr-5px"
/>
搜索
</el-button>
<el-button
@
click=
"resetQuery"
>
<Icon
icon=
"ep:refresh"
class=
"mr-5px"
/>
重置
</el-button>
</el-form-item>
</el-form>
<!-- 操作工具栏 -->
<el-row
:gutter=
"10"
class=
"mb8"
>
<el-col
:span=
"1.5"
>
<el-button
type=
"primary"
plain
@
click=
"handleAdd"
v-hasPermi=
"['promotion:coupon-template:create']"
>
<Icon
icon=
"ep:plus"
class=
"mr-5px"
/>
新增
</el-button>
<el-button
type=
"info"
plain
@
click=
"$router.push('/promotion/coupon')"
v-hasPermi=
"['promotion:coupon:query']"
>
<Icon
icon=
"ep:operation"
class=
"mr-5px"
/>
会员优惠劵
</el-button>
</el-col>
<!--
<right-toolbar
v-model:showSearch=
"showSearch"
@
query-table=
"getList"
/>
-->
</el-row>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table
v-loading=
"loading"
:data=
"list"
>
<el-table-column
label=
"优惠券名称"
align=
"center"
prop=
"name"
/>
<el-table-column
label=
"优惠券类型"
align=
"center"
prop=
"discountType"
>
<template
#
default=
"scope"
>
<dict-tag
:type=
"DICT_TYPE.PROMOTION_DISCOUNT_TYPE"
:value=
"scope.row.discountType"
/>
</
template
>
</el-table-column>
<el-table-column
label=
"优惠金额 / 折扣"
align=
"center"
prop=
"discount"
:formatter=
"discountFormat"
/>
<el-table-column
label=
"发放数量"
align=
"center"
prop=
"totalCount"
/>
<el-table-column
label=
"剩余数量"
align=
"center"
prop=
"totalCount"
:formatter=
"(row) => row.totalCount - row.takeCount"
/>
<el-table-column
label=
"领取上限"
align=
"center"
prop=
"takeLimitCount"
:formatter=
"takeLimitCountFormat"
/>
<el-table-column
label=
"有效期限"
align=
"center"
prop=
"validityType"
width=
"180"
:formatter=
"validityTypeFormat"
/>
<el-table-column
label=
"状态"
align=
"center"
prop=
"status"
>
<
template
#
default=
"scope"
>
<el-switch
v-model=
"scope.row.status"
:active-value=
"0"
:inactive-value=
"1"
@
change=
"handleStatusChange(scope.row)"
/>
</
template
>
</el-table-column>
<el-table-column
label=
"创建时间"
align=
"center"
prop=
"createTime"
:formatter=
"dateFormatter"
width=
"180"
/>
<el-table-column
label=
"操作"
align=
"center"
class-name=
"small-padding fixed-width"
>
<
template
#
default=
"scope"
>
<el-button
size=
"small"
type=
"primary"
link
@
click=
"handleUpdate(scope.row)"
v-hasPermi=
"['promotion:coupon-template:update']"
>
<Icon
icon=
"ep:edit"
:size=
"12"
class=
"mr-1px"
/>
修改
</el-button>
<el-button
size=
"small"
type=
"primary"
link
@
click=
"handleDelete(scope.row)"
v-hasPermi=
"['promotion:coupon-template:delete']"
>
<Icon
icon=
"ep:delete"
:size=
"12"
class=
"mr-1px"
/>
删除
</el-button>
</
template
>
</el-table-column>
</el-table>
</ContentWrap>
<!-- 分页组件 -->
<pagination
v-show=
"total > 0"
:total=
"total"
v-model:page=
"queryParams.pageNo"
v-model:limit=
"queryParams.pageSize"
@
pagination=
"getList"
/>
<!-- 对话框(添加 / 修改) -->
<el-dialog
:title=
"title"
v-model=
"open"
width=
"600px"
append-to-body
>
<el-form
ref=
"formRef"
:model=
"form"
:rules=
"rules"
label-width=
"140px"
>
<el-form-item
label=
"优惠券名称"
prop=
"name"
>
<el-input
v-model=
"form.name"
placeholder=
"请输入优惠券名称"
/>
</el-form-item>
<el-form-item
label=
"优惠券类型"
prop=
"discountType"
>
<el-radio-group
v-model=
"form.discountType"
>
<el-radio
v-for=
"dict in getIntDictOptions(DICT_TYPE.PROMOTION_DISCOUNT_TYPE)"
:key=
"dict.value"
:label=
"parseInt(dict.value)"
>
{{ dict.label }}
</el-radio
>
</el-radio-group>
</el-form-item>
<el-form-item
v-if=
"form.discountType === PromotionDiscountTypeEnum.PRICE.type"
label=
"优惠券面额"
prop=
"discountPrice"
>
<el-input-number
v-model=
"form.discountPrice"
placeholder=
"请输入优惠金额,单位:元"
style=
"width: 400px"
:precision=
"2"
:min=
"0"
/>
元
</el-form-item>
<el-form-item
v-if=
"form.discountType === PromotionDiscountTypeEnum.PERCENT.type"
label=
"优惠券折扣"
prop=
"discountPercent"
>
<el-input-number
v-model=
"form.discountPercent"
placeholder=
"优惠券折扣不能小于 1 折,且不可大于 9.9 折"
style=
"width: 400px"
:precision=
"1"
:min=
"1"
:max=
"9.9"
/>
折
</el-form-item>
<el-form-item
v-if=
"form.discountType === PromotionDiscountTypeEnum.PERCENT.type"
label=
"最多优惠"
prop=
"discountLimitPrice"
>
<el-input-number
v-model=
"form.discountLimitPrice"
placeholder=
"请输入最多优惠"
style=
"width: 400px"
:precision=
"2"
:min=
"0"
/>
元
</el-form-item>
<el-form-item
label=
"满多少元可以使用"
prop=
"usePrice"
>
<el-input-number
v-model=
"form.usePrice"
placeholder=
"无门槛请设为 0"
style=
"width: 400px"
:precision=
"2"
:min=
"0"
/>
元
</el-form-item>
<el-form-item
label=
"领取方式"
prop=
"takeType"
>
<el-radio-group
v-model=
"form.takeType"
>
<el-radio
:key=
"1"
:label=
"1"
>
直接领取
</el-radio>
<el-radio
:key=
"2"
:label=
"2"
>
指定发放
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
v-if=
"form.takeType === 1"
label=
"发放数量"
prop=
"totalCount"
>
<el-input-number
v-model=
"form.totalCount"
placeholder=
"发放数量,没有之后不能领取或发放,-1 为不限制"
style=
"width: 400px"
:precision=
"0"
:min=
"-1"
/>
张
</el-form-item>
<el-form-item
v-if=
"form.takeType === 1"
label=
"每人限领个数"
prop=
"takeLimitCount"
>
<el-input-number
v-model=
"form.takeLimitCount"
placeholder=
"设置为 -1 时,可无限领取"
style=
"width: 400px"
:precision=
"0"
:min=
"-1"
/>
张
</el-form-item>
<el-form-item
label=
"有效期类型"
prop=
"validityType"
>
<el-radio-group
v-model=
"form.validityType"
>
<el-radio
v-for=
"dict in getIntDictOptions(DICT_TYPE.PROMOTION_COUPON_TEMPLATE_VALIDITY_TYPE)"
:key=
"dict.value"
:label=
"parseInt(dict.value)"
>
{{ dict.label }}
</el-radio
>
</el-radio-group>
</el-form-item>
<el-form-item
v-if=
"form.validityType === CouponTemplateValidityTypeEnum.DATE.type"
label=
"固定日期"
prop=
"validTimes"
>
<el-date-picker
v-model=
"form.validTimes"
style=
"width: 240px"
value-format=
"yyyy-MM-dd HH:mm:ss"
type=
"datetimerange"
:default-time=
"[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)]"
/>
</el-form-item>
<el-form-item
v-if=
"form.validityType === CouponTemplateValidityTypeEnum.TERM.type"
label=
"领取日期"
prop=
"fixedStartTerm"
>
第
<el-input-number
v-model=
"form.fixedStartTerm"
placeholder=
"0 为今天生效"
style=
"width: 165px"
:precision=
"0"
:min=
"0"
/>
至
<el-input-number
v-model=
"form.fixedEndTerm"
placeholder=
"请输入结束天数"
style=
"width: 165px"
:precision=
"0"
:min=
"0"
/>
天有效
</el-form-item>
<el-form-item
label=
"活动商品"
prop=
"productScope"
>
<el-radio-group
v-model=
"form.productScope"
>
<el-radio
v-for=
"dict in getIntDictOptions(DICT_TYPE.PROMOTION_PRODUCT_SCOPE)"
:key=
"dict.value"
:label=
"parseInt(dict.value)"
>
{{ dict.label }}
</el-radio
>
</el-radio-group>
</el-form-item>
<el-form-item
v-if=
"form.productScope === PromotionProductScopeEnum.SPU.scope"
prop=
"productSpuIds"
>
<el-select
v-model=
"form.productSpuIds"
placeholder=
"请选择活动商品"
clearable
size=
"small"
multiple
filterable
style=
"width: 400px"
>
<el-option
v-for=
"item in productSpus"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
>
<span
style=
"float: left"
>
{{ item.name }}
</span>
<span
style=
"float: right; font-size: 13px; color: #8492a6"
>
¥{{ (item.minPrice / 100.0).toFixed(2) }}
</span
>
</el-option>
</el-select>
</el-form-item>
</el-form>
<
template
#
footer
>
<div
class=
"dialog-footer"
>
<el-button
type=
"primary"
@
click=
"submitForm"
>
确 定
</el-button>
<el-button
@
click=
"cancel"
>
取 消
</el-button>
</div>
</
template
>
</el-dialog>
</template>
<
script
setup
lang=
"ts"
name=
"PromotionCouponTemplate"
>
import
{
createCouponTemplate
,
updateCouponTemplate
,
deleteCouponTemplate
,
getCouponTemplate
,
getCouponTemplatePage
,
updateCouponTemplateStatus
}
from
'@/api/mall/promotion/couponTemplate'
import
{
CommonStatusEnum
,
CouponTemplateValidityTypeEnum
,
PromotionDiscountTypeEnum
,
PromotionProductScopeEnum
}
from
'@/utils/constants'
import
{
DICT_TYPE
,
getIntDictOptions
}
from
'@/utils/dict'
import
{
getSpuSimpleList
}
from
'@/api/mall/product/spu'
import
{
dateFormatter
,
formatDate
}
from
'@/utils/formatTime'
import
{
FormInstance
}
from
'element-plus'
// 消息弹窗
const
message
=
useMessage
()
// 遮罩层
const
loading
=
ref
(
true
)
// 显示搜索条件
const
showSearch
=
ref
(
true
)
// 总条数
const
total
=
ref
(
0
)
// 优惠劵列表
const
list
=
ref
([])
// 弹出层标题
const
title
=
ref
(
''
)
// 是否显示弹出层
const
open
=
ref
(
false
)
// 查询参数
const
queryParams
=
reactive
({
pageNo
:
1
,
pageSize
:
10
,
name
:
null
,
status
:
null
,
type
:
null
,
createTime
:
[]
})
// 表单参数
const
form
=
ref
<
any
>
({})
// 表单校验
const
rules
=
{
name
:
[{
required
:
true
,
message
:
'优惠券名称不能为空'
,
trigger
:
'blur'
}],
discountType
:
[{
required
:
true
,
message
:
'优惠券类型不能为空'
,
trigger
:
'change'
}],
discountPrice
:
[{
required
:
true
,
message
:
'优惠券面额不能为空'
,
trigger
:
'blur'
}],
discountPercent
:
[{
required
:
true
,
message
:
'优惠券折扣不能为空'
,
trigger
:
'blur'
}],
discountLimitPrice
:
[{
required
:
true
,
message
:
'最多优惠不能为空'
,
trigger
:
'blur'
}],
usePrice
:
[{
required
:
true
,
message
:
'满多少元可以使用不能为空'
,
trigger
:
'blur'
}],
takeType
:
[{
required
:
true
,
message
:
'领取方式不能为空'
,
trigger
:
'change'
}],
totalCount
:
[{
required
:
true
,
message
:
'发放数量不能为空'
,
trigger
:
'blur'
}],
takeLimitCount
:
[{
required
:
true
,
message
:
'每人限领个数不能为空'
,
trigger
:
'blur'
}],
validityType
:
[{
required
:
true
,
message
:
'有效期类型不能为空'
,
trigger
:
'change'
}],
validTimes
:
[{
required
:
true
,
message
:
'固定日期不能为空'
,
trigger
:
'change'
}],
fixedStartTerm
:
[{
required
:
true
,
message
:
'开始领取天数不能为空'
,
trigger
:
'blur'
}],
fixedEndTerm
:
[{
required
:
true
,
message
:
'开始领取天数不能为空'
,
trigger
:
'blur'
}],
productScope
:
[{
required
:
true
,
message
:
'商品范围不能为空'
,
trigger
:
'blur'
}],
productSpuIds
:
[{
required
:
true
,
message
:
'商品范围不能为空'
,
trigger
:
'blur'
}]
}
// 商品列表
const
productSpus
=
ref
([])
const
queryFormRef
=
ref
<
FormInstance
|
null
>
(
null
)
const
formRef
=
ref
<
FormInstance
|
null
>
(
null
)
onMounted
(()
=>
{
getList
()
})
/** 查询列表 */
const
getList
=
async
()
=>
{
loading
.
value
=
true
try
{
// 执行查询
const
data
=
await
getCouponTemplatePage
(
queryParams
)
list
.
value
=
data
.
list
total
.
value
=
data
.
total
// 查询商品列表
productSpus
.
value
=
await
getSpuSimpleList
()
}
finally
{
loading
.
value
=
false
}
}
/** 取消按钮 */
const
cancel
=
()
=>
{
open
.
value
=
false
reset
()
}
/** 表单重置 */
const
reset
=
()
=>
{
form
.
value
=
{
id
:
undefined
,
name
:
undefined
,
discountType
:
PromotionDiscountTypeEnum
.
PRICE
.
type
,
discountPrice
:
undefined
,
discountPercent
:
undefined
,
discountLimitPrice
:
undefined
,
usePrice
:
undefined
,
takeType
:
1
,
totalCount
:
undefined
,
takeLimitCount
:
undefined
,
validityType
:
CouponTemplateValidityTypeEnum
.
DATE
.
type
,
validTimes
:
[],
validStartTime
:
undefined
,
validEndTime
:
undefined
,
fixedStartTerm
:
undefined
,
fixedEndTerm
:
undefined
,
productScope
:
PromotionProductScopeEnum
.
ALL
.
scope
,
productSpuIds
:
[]
}
formRef
.
value
?.
resetFields
()
}
/** 搜索按钮操作 */
const
handleQuery
=
()
=>
{
queryParams
.
pageNo
=
1
getList
()
}
/** 重置按钮操作 */
const
resetQuery
=
()
=>
{
queryFormRef
?.
value
?.
resetFields
()
handleQuery
()
}
/** 新增按钮操作 */
const
handleAdd
=
()
=>
{
reset
()
open
.
value
=
true
title
.
value
=
'添加优惠劵'
}
/** 修改按钮操作 */
const
handleUpdate
=
async
(
row
:
any
)
=>
{
reset
()
const
id
=
row
.
id
try
{
const
data
=
await
getCouponTemplate
(
id
)
form
.
value
=
{
...
data
,
discountPrice
:
data
.
discountPrice
!==
undefined
?
data
.
discountPrice
/
100.0
:
undefined
,
discountPercent
:
data
.
discountPercent
!==
undefined
?
data
.
discountPercent
/
10.0
:
undefined
,
discountLimitPrice
:
data
.
discountLimitPrice
!==
undefined
?
data
.
discountLimitPrice
/
100.0
:
undefined
,
usePrice
:
data
.
usePrice
!==
undefined
?
data
.
usePrice
/
100.0
:
undefined
,
validTimes
:
[
data
.
validStartTime
,
data
.
validEndTime
]
}
open
.
value
=
true
title
.
value
=
'修改优惠劵'
}
catch
{}
}
/** 提交按钮 */
const
submitForm
=
async
()
=>
{
const
valid
=
await
formRef
.
value
?.
validate
()
if
(
!
valid
)
{
return
}
// 金额相关字段的缩放
let
data
=
{
...
form
.
value
,
discountPrice
:
form
.
value
.
discountPrice
!==
undefined
?
form
.
value
.
discountPrice
*
100
:
undefined
,
discountPercent
:
form
.
value
.
discountPercent
!==
undefined
?
form
.
value
.
discountPercent
*
10
:
undefined
,
discountLimitPrice
:
form
.
value
.
discountLimitPrice
!==
undefined
?
form
.
value
.
discountLimitPrice
*
100
:
undefined
,
usePrice
:
form
.
value
.
usePrice
!==
undefined
?
form
.
value
.
usePrice
*
100
:
undefined
,
validStartTime
:
form
.
value
.
validTimes
&&
form
.
value
.
validTimes
.
length
===
2
?
form
.
value
.
validTimes
[
0
]
:
undefined
,
validEndTime
:
form
.
value
.
validTimes
&&
form
.
value
.
validTimes
.
length
===
2
?
form
.
value
.
validTimes
[
1
]
:
undefined
}
// 修改的提交
if
(
form
.
value
.
id
!=
null
)
{
try
{
await
updateCouponTemplate
(
data
)
message
.
success
(
'修改成功'
)
open
.
value
=
false
getList
()
}
catch
{}
return
}
try
{
await
createCouponTemplate
(
data
)
message
.
success
(
'新增成功'
)
open
.
value
=
false
getList
()
}
catch
{}
}
/** 优惠劵模板状态修改 */
const
handleStatusChange
=
async
(
row
:
any
)
=>
{
// 此时,row 已经变成目标状态了,所以可以直接提交请求和提示
let
text
=
row
.
status
===
CommonStatusEnum
.
ENABLE
?
'启用'
:
'停用'
try
{
await
message
.
confirm
(
'确认要"'
+
text
+
'""'
+
row
.
name
+
'"优惠劵吗?'
)
await
updateCouponTemplateStatus
(
row
.
id
,
row
.
status
)
message
.
success
(
text
+
'成功'
)
}
catch
{
// 异常时,需要将 row.status 状态重置回之前的
row
.
status
=
row
.
status
===
CommonStatusEnum
.
ENABLE
?
CommonStatusEnum
.
DISABLE
:
CommonStatusEnum
.
ENABLE
}
}
/** 删除按钮操作 */
const
handleDelete
=
async
(
row
:
any
)
=>
{
const
id
=
row
.
id
try
{
await
message
.
confirm
(
'是否确认删除优惠劵编号为"'
+
id
+
'"的数据项?'
)
await
deleteCouponTemplate
(
id
)
}
catch
{}
}
// 格式化【优惠金额/折扣】
const
discountFormat
=
(
row
:
any
)
=>
{
if
(
row
.
discountType
===
PromotionDiscountTypeEnum
.
PRICE
.
type
)
{
return
`¥
${(
row
.
discountPrice
/
100.0
).
toFixed
(
2
)}
`
}
if
(
row
.
discountType
===
PromotionDiscountTypeEnum
.
PERCENT
.
type
)
{
return
`¥
${(
row
.
discountPrice
/
100.0
).
toFixed
(
2
)}
`
}
return
'未知【'
+
row
.
discountType
+
'】'
}
// 格式化【领取上限】
const
takeLimitCountFormat
=
(
row
:
any
)
=>
{
if
(
row
.
takeLimitCount
===
-
1
)
{
return
'无领取限制'
}
return
`
${
row
.
takeLimitCount
}
张/人`
}
// 格式化【有效期限】
const
validityTypeFormat
=
(
row
:
any
)
=>
{
if
(
row
.
validityType
===
CouponTemplateValidityTypeEnum
.
DATE
.
type
)
{
return
`
${
formatDate
(
row
.
validStartTime
)}
至
${
formatDate
(
row
.
validEndTime
)}
`
}
if
(
row
.
validityType
===
CouponTemplateValidityTypeEnum
.
TERM
.
type
)
{
return
`领取后第
${
row
.
fixedStartTerm
}
-
${
row
.
fixedEndTerm
}
天内可用`
}
return
'未知【'
+
row
.
validityType
+
'】'
}
</
script
>
src/views/mall/promotion/seckill/activity/SeckillActivityForm.vue
View file @
16369c00
...
@@ -45,6 +45,7 @@
...
@@ -45,6 +45,7 @@
<
script
lang=
"ts"
setup
>
<
script
lang=
"ts"
setup
>
import
{
SpuAndSkuList
,
SpuProperty
,
SpuSelect
}
from
'../../components'
import
{
SpuAndSkuList
,
SpuProperty
,
SpuSelect
}
from
'../../components'
import
{
allSchemas
,
rules
}
from
'./seckillActivity.data'
import
{
allSchemas
,
rules
}
from
'./seckillActivity.data'
import
{
cloneDeep
}
from
'lodash-es'
import
*
as
SeckillActivityApi
from
'@/api/mall/promotion/seckill/seckillActivity'
import
*
as
SeckillActivityApi
from
'@/api/mall/promotion/seckill/seckillActivity'
import
{
SeckillProductVO
}
from
'@/api/mall/promotion/seckill/seckillActivity'
import
{
SeckillProductVO
}
from
'@/api/mall/promotion/seckill/seckillActivity'
...
@@ -70,13 +71,13 @@ const spuAndSkuListRef = ref() // sku 秒杀配置组件Ref
...
@@ -70,13 +71,13 @@ const spuAndSkuListRef = ref() // sku 秒杀配置组件Ref
const
ruleConfig
:
RuleConfig
[]
=
[
const
ruleConfig
:
RuleConfig
[]
=
[
{
{
name
:
'productConfig.stock'
,
name
:
'productConfig.stock'
,
rule
:
(
arg
)
=>
arg
>
1
,
rule
:
(
arg
)
=>
arg
>
=
1
,
message
:
'商品秒杀库存必须大于 1 !!!'
message
:
'商品秒杀库存必须大于
等于
1 !!!'
},
},
{
{
name
:
'productConfig.seckillPrice'
,
name
:
'productConfig.seckillPrice'
,
rule
:
(
arg
)
=>
arg
>
0.01
,
rule
:
(
arg
)
=>
arg
>
=
0.01
,
message
:
'商品秒杀价格必须大于 0.01 !!!'
message
:
'商品秒杀价格必须大于
等于
0.01 !!!'
}
}
]
]
const
spuList
=
ref
<
SeckillActivityApi
.
SpuExtension
[]
>
([])
// 选择的 spu
const
spuList
=
ref
<
SeckillActivityApi
.
SpuExtension
[]
>
([])
// 选择的 spu
...
@@ -112,7 +113,6 @@ const getSpuDetails = async (
...
@@ -112,7 +113,6 @@ const getSpuDetails = async (
if
(
typeof
products
!==
'undefined'
)
{
if
(
typeof
products
!==
'undefined'
)
{
const
product
=
products
.
find
((
item
)
=>
item
.
skuId
===
sku
.
id
)
const
product
=
products
.
find
((
item
)
=>
item
.
skuId
===
sku
.
id
)
if
(
product
)
{
if
(
product
)
{
// 分转元
product
.
seckillPrice
=
formatToFraction
(
product
.
seckillPrice
)
product
.
seckillPrice
=
formatToFraction
(
product
.
seckillPrice
)
}
}
config
=
product
||
config
config
=
product
||
config
...
@@ -153,13 +153,6 @@ const open = async (type: string, id?: number) => {
...
@@ -153,13 +153,6 @@ const open = async (type: string, id?: number) => {
}
}
defineExpose
({
open
})
// 提供 open 方法,用于打开弹窗
defineExpose
({
open
})
// 提供 open 方法,用于打开弹窗
/** 重置表单 */
const
resetForm
=
async
()
=>
{
spuList
.
value
=
[]
spuPropertyList
.
value
=
[]
await
nextTick
()
formRef
.
value
.
getElFormRef
().
resetFields
()
}
/** 提交表单 */
/** 提交表单 */
const
emit
=
defineEmits
([
'success'
])
// 定义 success 事件,用于操作成功后的回调
const
emit
=
defineEmits
([
'success'
])
// 定义 success 事件,用于操作成功后的回调
const
submitForm
=
async
()
=>
{
const
submitForm
=
async
()
=>
{
...
@@ -170,14 +163,14 @@ const submitForm = async () => {
...
@@ -170,14 +163,14 @@ const submitForm = async () => {
// 提交请求
// 提交请求
formLoading
.
value
=
true
formLoading
.
value
=
true
try
{
try
{
const
data
=
formRef
.
value
.
formModel
as
SeckillActivityApi
.
SeckillActivityVO
// 获取秒杀商品配置
const
products
=
spuAndSkuListRef
.
value
.
getSkuConfigs
(
'productConfig'
)
const
products
=
cloneDeep
(
spuAndSkuListRef
.
value
.
getSkuConfigs
(
'productConfig'
)
)
products
.
forEach
((
item
:
SeckillProductVO
)
=>
{
products
.
forEach
((
item
:
SeckillProductVO
)
=>
{
// 秒杀价格元转分
item
.
seckillPrice
=
convertToInteger
(
item
.
seckillPrice
)
item
.
seckillPrice
=
convertToInteger
(
item
.
seckillPrice
)
})
})
// 获取秒杀商品配置
const
data
=
formRef
.
value
.
formModel
as
SeckillActivityApi
.
SeckillActivityVO
data
.
products
=
products
data
.
products
=
products
// 真正提交
if
(
formType
.
value
===
'create'
)
{
if
(
formType
.
value
===
'create'
)
{
await
SeckillActivityApi
.
createSeckillActivity
(
data
)
await
SeckillActivityApi
.
createSeckillActivity
(
data
)
message
.
success
(
t
(
'common.createSuccess'
))
message
.
success
(
t
(
'common.createSuccess'
))
...
@@ -192,6 +185,15 @@ const submitForm = async () => {
...
@@ -192,6 +185,15 @@ const submitForm = async () => {
formLoading
.
value
=
false
formLoading
.
value
=
false
}
}
}
}
/** 重置表单 */
const
resetForm
=
async
()
=>
{
spuList
.
value
=
[]
spuPropertyList
.
value
=
[]
await
nextTick
()
formRef
.
value
.
getElFormRef
().
resetFields
()
}
// TODO @puhui999:下面的 css 名字,是不是可以改下;demo-table-expand
</
script
>
</
script
>
<
style
lang=
"scss"
scoped
>
<
style
lang=
"scss"
scoped
>
.demo-table-expand
{
.demo-table-expand
{
...
...
src/views/mall/promotion/seckill/activity/index.vue
View file @
16369c00
<
template
>
<
template
>
<doc-alert
title=
"功能开启"
url=
"https://doc.iocoder.cn/mall/build/"
/>
<!-- 搜索工作栏 -->
<!-- 搜索工作栏 -->
<ContentWrap>
<ContentWrap>
<Search
:schema=
"allSchemas.searchSchema"
@
reset=
"setSearchParams"
@
search=
"setSearchParams"
>
<Search
:schema=
"allSchemas.searchSchema"
@
reset=
"setSearchParams"
@
search=
"setSearchParams"
>
...
@@ -10,8 +12,7 @@
...
@@ -10,8 +12,7 @@
type=
"primary"
type=
"primary"
@
click=
"openForm('create')"
@
click=
"openForm('create')"
>
>
<Icon
class=
"mr-5px"
icon=
"ep:plus"
/>
<Icon
class=
"mr-5px"
icon=
"ep:plus"
/>
新增
新增
</el-button>
</el-button>
</
template
>
</
template
>
</Search>
</Search>
...
@@ -71,11 +72,11 @@
...
@@ -71,11 +72,11 @@
</template>
</template>
<
script
lang=
"ts"
setup
>
<
script
lang=
"ts"
setup
>
import
{
allSchemas
}
from
'./seckillActivity.data'
import
{
allSchemas
}
from
'./seckillActivity.data'
import
{
get
ListAllSimple
}
from
'@/api/mall/promotion/seckill/seckillConfig'
import
{
get
SimpleSeckillConfigList
}
from
'@/api/mall/promotion/seckill/seckillConfig'
import
*
as
SeckillActivityApi
from
'@/api/mall/promotion/seckill/seckillActivity'
import
*
as
SeckillActivityApi
from
'@/api/mall/promotion/seckill/seckillActivity'
import
SeckillActivityForm
from
'./SeckillActivityForm.vue'
import
SeckillActivityForm
from
'./SeckillActivityForm.vue'
import
{
cloneDeep
}
from
'lodash-es'
import
{
createImageViewer
}
from
'@/components/ImageViewer'
import
{
createImageViewer
}
from
'@/components/ImageViewer'
import
{
sortTableColumns
}
from
'@/hooks/web/useCrudSchemas'
defineOptions
({
name
:
'PromotionSeckillActivity'
})
defineOptions
({
name
:
'PromotionSeckillActivity'
})
...
@@ -99,12 +100,14 @@ const openForm = (type: string, id?: number) => {
...
@@ -99,12 +100,14 @@ const openForm = (type: string, id?: number) => {
const
handleDelete
=
(
id
:
number
)
=>
{
const
handleDelete
=
(
id
:
number
)
=>
{
tableMethods
.
delList
(
id
,
false
)
tableMethods
.
delList
(
id
,
false
)
}
}
/** 商品图预览 */
/** 商品图预览 */
const
imagePreview
=
(
imgUrl
:
string
)
=>
{
const
imagePreview
=
(
imgUrl
:
string
)
=>
{
createImageViewer
({
createImageViewer
({
urlList
:
[
imgUrl
]
urlList
:
[
imgUrl
]
})
})
}
}
const
configList
=
ref
([])
// 时段配置精简列表
const
configList
=
ref
([])
// 时段配置精简列表
const
convertSeckillConfigNames
=
computed
(
const
convertSeckillConfigNames
=
computed
(
()
=>
(
row
)
=>
()
=>
(
row
)
=>
...
@@ -120,18 +123,10 @@ const expandChange = (row, expandedRows) => {
...
@@ -120,18 +123,10 @@ const expandChange = (row, expandedRows) => {
/** 初始化 **/
/** 初始化 **/
onMounted
(
async
()
=>
{
onMounted
(
async
()
=>
{
/*
// 获得活动列表
TODO
sortTableColumns
(
allSchemas
.
tableColumns
,
'spuId'
)
后面准备封装成一个函数来操作 tableColumns 重新排列:比如说需求是表单上商品选择是在后面的而列表展示的时候需要调到位置。
封装效果支持批量操作,给出 field 和需要插入的位置,例:[{field:'spuId',index: 1}] 效果为把 field 为 spuId 的 column 移动到第一个位置
*/
// 处理一下表格列让商品往前
const
index
=
allSchemas
.
tableColumns
.
findIndex
((
item
)
=>
item
.
field
===
'spuId'
)
const
column
=
cloneDeep
(
allSchemas
.
tableColumns
[
index
])
allSchemas
.
tableColumns
.
splice
(
index
,
1
)
// 添加到开头
allSchemas
.
tableColumns
.
unshift
(
column
)
await
getList
()
await
getList
()
configList
.
value
=
await
getListAllSimple
()
// 获得秒杀时间段
configList
.
value
=
await
getSimpleSeckillConfigList
()
})
})
</
script
>
</
script
>
src/views/mall/promotion/seckill/activity/seckillActivity.data.ts
View file @
16369c00
import
type
{
CrudSchema
}
from
'@/hooks/web/useCrudSchemas'
import
type
{
CrudSchema
}
from
'@/hooks/web/useCrudSchemas'
import
{
dateFormatter
,
dateFormatter2
}
from
'@/utils/formatTime'
import
{
dateFormatter
,
dateFormatter2
}
from
'@/utils/formatTime'
import
{
get
ListAllSimple
}
from
'@/api/mall/promotion/seckill/seckillConfig'
import
{
get
SimpleSeckillConfigList
}
from
'@/api/mall/promotion/seckill/seckillConfig'
// 表单校验
// 表单校验
export
const
rules
=
reactive
({
export
const
rules
=
reactive
({
...
@@ -88,7 +88,7 @@ const crudSchemas = reactive<CrudSchema[]>([
...
@@ -88,7 +88,7 @@ const crudSchemas = reactive<CrudSchema[]>([
valueField
:
'id'
valueField
:
'id'
}
}
},
},
api
:
get
ListAllSimple
api
:
get
SimpleSeckillConfigList
},
},
table
:
{
table
:
{
width
:
300
width
:
300
...
...
src/views/mall/promotion/seckill/config/SeckillConfigForm.vue
View file @
16369c00
...
@@ -10,7 +10,6 @@
...
@@ -10,7 +10,6 @@
<
script
lang=
"ts"
name=
"SeckillConfigForm"
setup
>
<
script
lang=
"ts"
name=
"SeckillConfigForm"
setup
>
import
*
as
SeckillConfigApi
from
'@/api/mall/promotion/seckill/seckillConfig'
import
*
as
SeckillConfigApi
from
'@/api/mall/promotion/seckill/seckillConfig'
import
{
allSchemas
,
rules
}
from
'./seckillConfig.data'
import
{
allSchemas
,
rules
}
from
'./seckillConfig.data'
import
{
cloneDeep
}
from
'lodash-es'
const
{
t
}
=
useI18n
()
// 国际化
const
{
t
}
=
useI18n
()
// 国际化
const
message
=
useMessage
()
// 消息弹窗
const
message
=
useMessage
()
// 消息弹窗
...
@@ -53,19 +52,22 @@ const submitForm = async () => {
...
@@ -53,19 +52,22 @@ const submitForm = async () => {
formLoading
.
value
=
true
formLoading
.
value
=
true
try
{
try
{
// 处理轮播图列表
// 处理轮播图列表
const
data
=
formRef
.
value
.
formModel
as
SeckillConfigApi
.
SeckillConfigVO
const
sliderPicUrls
=
[]
const
cloneData
=
cloneDeep
(
data
)
formRef
.
value
.
formModel
.
sliderPicUrls
.
forEach
((
item
)
=>
{
const
newSliderPicUrls
=
[]
cloneData
.
sliderPicUrls
.
forEach
((
item
)
=>
{
// 如果是前端选的图
// 如果是前端选的图
typeof
item
===
'object'
?
newSliderPicUrls
.
push
(
item
.
url
)
:
newS
liderPicUrls
.
push
(
item
)
typeof
item
===
'object'
?
sliderPicUrls
.
push
(
item
.
url
)
:
s
liderPicUrls
.
push
(
item
)
})
})
cloneData
.
sliderPicUrls
=
newSliderPicUrls
// 真正提交
const
data
=
{
...
formRef
.
value
.
formModel
,
sliderPicUrls
}
as
SeckillConfigApi
.
SeckillConfigVO
if
(
formType
.
value
===
'create'
)
{
if
(
formType
.
value
===
'create'
)
{
await
SeckillConfigApi
.
createSeckillConfig
(
cloneD
ata
)
await
SeckillConfigApi
.
createSeckillConfig
(
d
ata
)
message
.
success
(
t
(
'common.createSuccess'
))
message
.
success
(
t
(
'common.createSuccess'
))
}
else
{
}
else
{
await
SeckillConfigApi
.
updateSeckillConfig
(
cloneD
ata
)
await
SeckillConfigApi
.
updateSeckillConfig
(
d
ata
)
message
.
success
(
t
(
'common.updateSuccess'
))
message
.
success
(
t
(
'common.updateSuccess'
))
}
}
dialogVisible
.
value
=
false
dialogVisible
.
value
=
false
...
...
src/views/mall/promotion/seckill/config/index.vue
View file @
16369c00
<
template
>
<
template
>
<doc-alert
title=
"功能开启"
url=
"https://doc.iocoder.cn/mall/build/"
/>
<!-- 搜索工作栏 -->
<!-- 搜索工作栏 -->
<ContentWrap>
<ContentWrap>
<Search
:schema=
"allSchemas.searchSchema"
@
reset=
"setSearchParams"
@
search=
"setSearchParams"
>
<Search
:schema=
"allSchemas.searchSchema"
@
reset=
"setSearchParams"
@
search=
"setSearchParams"
>
...
@@ -76,7 +78,6 @@ import * as SeckillConfigApi from '@/api/mall/promotion/seckill/seckillConfig'
...
@@ -76,7 +78,6 @@ import * as SeckillConfigApi from '@/api/mall/promotion/seckill/seckillConfig'
import
SeckillConfigForm
from
'./SeckillConfigForm.vue'
import
SeckillConfigForm
from
'./SeckillConfigForm.vue'
import
{
createImageViewer
}
from
'@/components/ImageViewer'
import
{
createImageViewer
}
from
'@/components/ImageViewer'
import
{
CommonStatusEnum
}
from
'@/utils/constants'
import
{
CommonStatusEnum
}
from
'@/utils/constants'
import
{
isArray
}
from
'@/utils/is'
const
message
=
useMessage
()
// 消息弹窗
const
message
=
useMessage
()
// 消息弹窗
// tableObject:表格的属性对象,可获得分页大小、条数等属性
// tableObject:表格的属性对象,可获得分页大小、条数等属性
...
@@ -89,21 +90,6 @@ const { tableObject, tableMethods } = useTable({
...
@@ -89,21 +90,6 @@ const { tableObject, tableMethods } = useTable({
// 获得表格的各种操作
// 获得表格的各种操作
const
{
getList
,
setSearchParams
}
=
tableMethods
const
{
getList
,
setSearchParams
}
=
tableMethods
/** 轮播图预览预览 */
const
imagePreview
=
(
args
)
=>
{
const
urlList
=
[]
if
(
isArray
(
args
))
{
args
.
forEach
((
item
)
=>
{
urlList
.
push
(
item
)
})
}
else
{
urlList
.
push
(
args
)
}
createImageViewer
({
urlList
})
}
/** 添加/修改操作 */
/** 添加/修改操作 */
const
formRef
=
ref
()
const
formRef
=
ref
()
const
openForm
=
(
type
:
string
,
id
?:
number
)
=>
{
const
openForm
=
(
type
:
string
,
id
?:
number
)
=>
{
...
@@ -131,6 +117,14 @@ const handleStatusChange = async (row: SeckillConfigApi.SeckillConfigVO) => {
...
@@ -131,6 +117,14 @@ const handleStatusChange = async (row: SeckillConfigApi.SeckillConfigVO) => {
row
.
status
===
CommonStatusEnum
.
ENABLE
?
CommonStatusEnum
.
DISABLE
:
CommonStatusEnum
.
ENABLE
row
.
status
===
CommonStatusEnum
.
ENABLE
?
CommonStatusEnum
.
DISABLE
:
CommonStatusEnum
.
ENABLE
}
}
}
}
/** 轮播图预览预览 */
const
imagePreview
=
(
args
)
=>
{
createImageViewer
({
urlList
:
args
})
}
/** 初始化 **/
/** 初始化 **/
onMounted
(()
=>
{
onMounted
(()
=>
{
getList
()
getList
()
...
...
src/views/mp/message/index.vue
View file @
16369c00
...
@@ -34,7 +34,7 @@
...
@@ -34,7 +34,7 @@
<el-date-picker
<el-date-picker
v-model=
"queryParams.createTime"
v-model=
"queryParams.createTime"
style=
"width: 240px"
style=
"width: 240px"
value-format=
"
yyyy-MM-dd
HH:mm:ss"
value-format=
"
YYYY-MM-DD
HH:mm:ss"
type=
"daterange"
type=
"daterange"
range-separator=
"-"
range-separator=
"-"
start-placeholder=
"开始日期"
start-placeholder=
"开始日期"
...
...
src/views/pay/notify/index.vue
View file @
16369c00
...
@@ -73,7 +73,7 @@
...
@@ -73,7 +73,7 @@
<el-date-picker
<el-date-picker
v-model=
"queryParams.createTime"
v-model=
"queryParams.createTime"
style=
"width: 240px"
style=
"width: 240px"
value-format=
"
yyyy-MM-dd
HH:mm:ss"
value-format=
"
YYYY-MM-DD
HH:mm:ss"
type=
"daterange"
type=
"daterange"
range-separator=
"-"
range-separator=
"-"
start-placeholder=
"开始日期"
start-placeholder=
"开始日期"
...
...
src/views/system/dict/index.vue
View file @
16369c00
...
@@ -49,7 +49,7 @@
...
@@ -49,7 +49,7 @@
end-placeholder=
"结束日期"
end-placeholder=
"结束日期"
start-placeholder=
"开始日期"
start-placeholder=
"开始日期"
type=
"daterange"
type=
"daterange"
value-format=
"
yyyy-MM-dd
HH:mm:ss"
value-format=
"
YYYY-MM-DD
HH:mm:ss"
/>
/>
</el-form-item>
</el-form-item>
<el-form-item>
<el-form-item>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment