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
ac0f3873
authored
Aug 07, 2023
by
芋道源码
Committed by
Gitee
Aug 07, 2023
Browse files
Options
Browse Files
Download
Plain Diff
!190 完善砍价活动管理
Merge pull request !190 from puhui999/dev-to-dev
parents
7c87f949
79413e0a
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
564 additions
and
0 deletions
+564
-0
src/api/mall/promotion/bargain/bargainActivity.ts
+62
-0
src/views/mall/promotion/bargain/BargainActivityForm.vue
+220
-0
src/views/mall/promotion/bargain/bargainActivity.data.ts
+165
-0
src/views/mall/promotion/bargain/index.vue
+117
-0
No files found.
src/api/mall/promotion/bargain/bargainActivity.ts
0 → 100644
View file @
ac0f3873
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/views/mall/promotion/bargain/BargainActivityForm.vue
0 → 100644
View file @
ac0f3873
<
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/bargainActivity.data.ts
0 → 100644
View file @
ac0f3873
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/index.vue
0 → 100644
View file @
ac0f3873
<
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
{
cloneDeep
}
from
'lodash-es'
import
{
createImageViewer
}
from
'@/components/ImageViewer'
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
)
}
// TODO @puhui999:要不还是使用原生的 element plus 做。感觉 crud schema 复杂界面,做起来麻烦
/** 初始化 **/
onMounted
(()
=>
{
/**
TODO
后面准备封装成一个函数来操作 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
()
})
</
script
>
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