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
Commit
60d2e311
authored
Aug 30, 2023
by
owen
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
mall:优惠券 商品选择组件
parent
beef6a0a
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
253 additions
and
119 deletions
+253
-119
src/views/mall/product/spu/components/SpuTableSelect.vue
+177
-93
src/views/mall/promotion/coupon/template/CouponTemplateForm.vue
+76
-26
No files found.
src/views/mall/product/spu/components/SpuTableSelect.vue
View file @
60d2e311
<
template
>
<Dialog
v-model=
"dialogVisible"
:appendToBody=
"true"
title=
"选择商品"
width=
"70%"
>
<el-row
:gutter=
"20"
class=
"mb-10px"
>
<el-col
:span=
"6"
>
<el-input
v-model=
"queryParams.name"
class=
"!w-240px"
clearable
placeholder=
"请输入商品名称"
@
keyup
.
enter=
"handleQuery"
/>
</el-col>
<el-col
:span=
"6"
>
<el-tree-select
v-model=
"queryParams.categoryId"
:data=
"categoryTreeList"
:props=
"defaultProps"
check-strictly
class=
"w-1/1"
node-key=
"id"
placeholder=
"请选择商品分类"
/>
</el-col>
<el-col
:span=
"6"
>
<el-date-picker
v-model=
"queryParams.createTime"
:default-time=
"[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class=
"!w-240px"
end-placeholder=
"结束日期"
start-placeholder=
"开始日期"
type=
"daterange"
value-format=
"YYYY-MM-DD HH:mm:ss"
/>
</el-col>
<el-col
:span=
"6"
>
<el-button
@
click=
"handleQuery"
>
<Icon
class=
"mr-5px"
icon=
"ep:search"
/>
搜索
</el-button>
<el-button
@
click=
"resetQuery"
>
<Icon
class=
"mr-5px"
icon=
"ep:refresh"
/>
重置
</el-button>
</el-col>
</el-row>
<el-table
ref=
"spuListRef"
v-loading=
"loading"
:data=
"list"
show-overflow-tooltip
>
<el-table-column
label=
"#"
width=
"55"
>
<template
#
default=
"
{ row }">
<el-radio
:label=
"row.id"
v-model=
"selectedSpuId"
@
change=
"handleSelected(row)"
>
</el-radio
>
</
template
>
</el-table-column>
<el-table-column
key=
"id"
align=
"center"
label=
"商品编号"
prop=
"id"
min-width=
"60"
/>
<el-table-column
label=
"商品图"
min-width=
"80"
>
<
template
#
default=
"{ row }"
>
<el-image
:src=
"row.picUrl"
class=
"w-30px h-30px"
:preview-src-list=
"[row.picUrl]"
preview-teleported
<ContentWrap>
<el-row
:gutter=
"20"
class=
"mb-10px"
>
<el-col
:span=
"6"
>
<el-input
v-model=
"queryParams.name"
class=
"!w-240px"
clearable
placeholder=
"请输入商品名称"
@
keyup
.
enter=
"handleQuery"
/>
</
template
>
</el-table-column>
<el-table-column
label=
"商品名称"
min-width=
"200"
prop=
"name"
/>
<el-table-column
label=
"商品分类"
min-width=
"100"
prop=
"categoryId"
>
<
template
#
default=
"{ row }"
>
<span>
{{
categoryList
.
find
((
c
)
=>
c
.
id
===
row
.
categoryId
)?.
name
}}
</span>
</
template
>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
v-model:limit=
"queryParams.pageSize"
v-model:page=
"queryParams.pageNo"
:total=
"total"
@
pagination=
"getList"
/>
</el-col>
<el-col
:span=
"6"
>
<el-tree-select
v-model=
"queryParams.categoryId"
:data=
"categoryTreeList"
:props=
"defaultProps"
check-strictly
class=
"w-1/1"
node-key=
"id"
placeholder=
"请选择商品分类"
/>
</el-col>
<el-col
:span=
"6"
>
<el-date-picker
v-model=
"queryParams.createTime"
:default-time=
"[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class=
"!w-240px"
end-placeholder=
"结束日期"
start-placeholder=
"开始日期"
type=
"daterange"
value-format=
"YYYY-MM-DD HH:mm:ss"
/>
</el-col>
<el-col
:span=
"6"
>
<el-button
@
click=
"handleQuery"
>
<Icon
class=
"mr-5px"
icon=
"ep:search"
/>
搜索
</el-button>
<el-button
@
click=
"resetQuery"
>
<Icon
class=
"mr-5px"
icon=
"ep:refresh"
/>
重置
</el-button>
</el-col>
</el-row>
<el-table
v-loading=
"loading"
:data=
"list"
show-overflow-tooltip
>
<!-- 多选模式 -->
<el-table-column
key=
"2"
type=
"selection"
width=
"55"
v-if=
"multiple"
>
<template
#
header
>
<el-checkbox
:value=
"allChecked && checkedPageNos.indexOf(queryParams.pageNo) > -1"
@
change=
"handleCheckAll"
/>
</
template
>
<
template
#
default=
"{ row }"
>
<el-checkbox
:value=
"checkedSpuIds.indexOf(row.id) > -1"
@
change=
"(checked: boolean) => handleCheckOne(checked, row)"
/>
</
template
>
</el-table-column>
<!-- 单选模式 -->
<el-table-column
label=
"#"
width=
"55"
v-else
>
<
template
#
default=
"{ row }"
>
<el-radio
:label=
"row.id"
v-model=
"selectedSpuId"
@
change=
"handleSingleSelected(row)"
>
</el-radio
>
</
template
>
</el-table-column>
<el-table-column
key=
"id"
align=
"center"
label=
"商品编号"
prop=
"id"
min-width=
"60"
/>
<el-table-column
label=
"商品图"
min-width=
"80"
>
<
template
#
default=
"{ row }"
>
<el-image
:src=
"row.picUrl"
class=
"w-30px h-30px"
:preview-src-list=
"[row.picUrl]"
preview-teleported
/>
</
template
>
</el-table-column>
<el-table-column
label=
"商品名称"
min-width=
"200"
prop=
"name"
/>
<el-table-column
label=
"商品分类"
min-width=
"100"
prop=
"categoryId"
>
<
template
#
default=
"{ row }"
>
<span>
{{
categoryList
?.
find
((
c
)
=>
c
.
id
===
row
.
categoryId
)?.
name
}}
</span>
</
template
>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
v-model:limit=
"queryParams.pageSize"
v-model:page=
"queryParams.pageNo"
:total=
"total"
@
pagination=
"getList"
/>
</ContentWrap>
<
template
#
footer
v-if=
"multiple"
>
<el-button
type=
"primary"
@
click=
"handleEmitChange"
>
确 定
</el-button>
<el-button
@
click=
"dialogVisible = false"
>
取 消
</el-button>
</
template
>
</Dialog>
</template>
...
...
@@ -85,12 +107,19 @@ import { defaultProps, handleTree } from '@/utils/tree'
import
*
as
ProductCategoryApi
from
'@/api/mall/product/category'
import
*
as
ProductSpuApi
from
'@/api/mall/product/spu'
import
{
propTypes
}
from
'@/utils/propTypes'
type
Spu
=
Required
<
ProductSpuApi
.
Spu
>
defineOptions
({
name
:
'SpuTableSelect'
})
const
message
=
useMessage
()
// 消息弹窗
const
props
=
defineProps
({
// 多选
multiple
:
propTypes
.
bool
.
def
(
false
)
})
const
total
=
ref
(
0
)
// 列表的总页数
const
list
=
ref
<
any
[]
>
([])
// 列表的数据
const
list
=
ref
<
Spu
[]
>
([])
// 列表的数据
const
loading
=
ref
(
false
)
// 列表的加载中
const
dialogVisible
=
ref
(
false
)
// 弹窗的是否展示
const
queryParams
=
ref
({
...
...
@@ -101,26 +130,24 @@ const queryParams = ref({
categoryId
:
null
,
createTime
:
[]
})
// 查询参数
const
spuListRef
=
ref
<
InstanceType
<
typeof
ElTable
>>
()
const
selectedSpuId
=
ref
()
// 选中的商品 spuId
/** 选中时触发 */
const
handleSelected
=
(
row
:
ProductSpuApi
.
Spu
)
=>
{
emits
(
'change'
,
row
)
// 关闭弹窗
dialogVisible
.
value
=
false
selectedSpuId
.
value
=
undefined
}
// 确认选择时的触发事件
const
emits
=
defineEmits
<
{
(
e
:
'change'
,
spu
:
ProductSpuApi
.
Spu
):
void
}
>
()
/** 打开弹窗 */
const
open
=
()
=>
{
const
open
=
(
spus
?:
Spu
[])
=>
{
if
(
spus
&&
spus
.
length
>
0
)
{
// todo check-box不显示选中?
checkedSpus
.
value
=
[...
spus
]
checkedSpuIds
.
value
=
spus
.
map
((
spu
)
=>
spu
.
id
)
}
else
{
checkedSpus
.
value
=
[]
checkedSpuIds
.
value
=
[]
}
allChecked
.
value
=
false
checkedPageNos
.
value
=
[]
dialogVisible
.
value
=
true
resetQuery
()
}
defineExpose
({
open
})
// 提供 open 方法,用于打开弹窗
...
...
@@ -138,6 +165,7 @@ const getList = async () => {
/** 搜索按钮操作 */
const
handleQuery
=
()
=>
{
queryParams
.
value
.
pageNo
=
1
getList
()
}
...
...
@@ -154,9 +182,65 @@ const resetQuery = () => {
getList
()
}
const
allChecked
=
ref
(
false
)
//是否全选
const
checkedPageNos
=
ref
<
number
[]
>
([])
//选中的页码
const
checkedSpuIds
=
ref
<
number
[]
>
([])
//选中的商品ID
const
checkedSpus
=
ref
<
Spu
[]
>
([])
//选中的商品
/** 单选中时触发 */
const
handleSingleSelected
=
(
row
:
Spu
)
=>
{
emits
(
'change'
,
row
)
// 关闭弹窗
dialogVisible
.
value
=
false
// 记住上次选择的ID
selectedSpuId
.
value
=
row
.
id
}
/** 多选完成 */
const
handleEmitChange
=
()
=>
{
// 关闭弹窗
dialogVisible
.
value
=
false
emits
(
'change'
,
[...
checkedSpus
.
value
])
}
/** 确认选择时的触发事件 */
const
emits
=
defineEmits
<
{
(
e
:
'change'
,
spu
:
Spu
|
Spu
[]
|
any
):
void
}
>
()
/** 全选 */
const
handleCheckAll
=
(
checked
:
boolean
)
=>
{
//todo 不触发?
console
.
log
(
'checkAll'
,
checked
)
allChecked
.
value
=
checked
const
index
=
checkedPageNos
.
value
.
indexOf
(
queryParams
.
value
.
pageNo
)
checkedPageNos
.
value
.
push
(
queryParams
.
value
.
pageNo
)
if
(
index
>
-
1
)
{
checkedPageNos
.
value
.
splice
(
index
,
1
)
}
list
.
value
.
forEach
((
item
)
=>
handleCheckOne
(
checked
,
item
))
}
/** 选中一行 */
const
handleCheckOne
=
(
checked
:
boolean
,
spu
:
Spu
)
=>
{
if
(
checked
)
{
const
index
=
checkedSpuIds
.
value
.
indexOf
(
spu
.
id
)
if
(
index
===
-
1
)
{
checkedSpuIds
.
value
.
push
(
spu
.
id
)
checkedSpus
.
value
.
push
(
spu
)
}
}
else
{
const
index
=
checkedSpuIds
.
value
.
indexOf
(
spu
.
id
)
if
(
index
>
-
1
)
{
checkedSpuIds
.
value
.
splice
(
index
,
1
)
checkedSpus
.
value
.
splice
(
index
,
1
)
}
}
}
const
categoryList
=
ref
()
// 分类列表
const
categoryTreeList
=
ref
()
// 分类树
/** 初始化 **/
onMounted
(
async
()
=>
{
await
getList
()
...
...
src/views/mall/promotion/coupon/template/CouponTemplateForm.vue
View file @
60d2e311
...
...
@@ -29,7 +29,7 @@
<el-input-number
v-model=
"formData.discountPrice"
placeholder=
"请输入优惠金额,单位:元"
style=
"width: 400px
"
class=
"!w-400px mr-2
"
:precision=
"2"
:min=
"0"
/>
...
...
@@ -43,7 +43,7 @@
<el-input-number
v-model=
"formData.discountPercent"
placeholder=
"优惠券折扣不能小于 1 折,且不可大于 9.9 折"
style=
"width: 400px
"
class=
"!w-400px mr-2
"
:precision=
"1"
:min=
"1"
:max=
"9.9"
...
...
@@ -58,7 +58,7 @@
<el-input-number
v-model=
"formData.discountLimitPrice"
placeholder=
"请输入最多优惠"
style=
"width: 400px
"
class=
"!w-400px mr-2
"
:precision=
"2"
:min=
"0"
/>
...
...
@@ -68,7 +68,7 @@
<el-input-number
v-model=
"formData.usePrice"
placeholder=
"无门槛请设为 0"
style=
"width: 400px
"
class=
"!w-400px mr-2
"
:precision=
"2"
:min=
"0"
/>
...
...
@@ -84,7 +84,7 @@
<el-input-number
v-model=
"formData.totalCount"
placeholder=
"发放数量,没有之后不能领取或发放,-1 为不限制"
style=
"width: 400px
"
class=
"!w-400px mr-2
"
:precision=
"0"
:min=
"-1"
/>
...
...
@@ -94,7 +94,7 @@
<el-input-number
v-model=
"formData.takeLimitCount"
placeholder=
"设置为 -1 时,可无限领取"
style=
"width: 400px
"
class=
"!w-400px mr-2
"
:precision=
"0"
:min=
"-1"
/>
...
...
@@ -133,7 +133,7 @@
<el-input-number
v-model=
"formData.fixedStartTerm"
placeholder=
"0 为今天生效"
style=
"width: 165px
"
class=
"mx-2
"
:precision=
"0"
:min=
"0"
/>
...
...
@@ -141,7 +141,7 @@
<el-input-number
v-model=
"formData.fixedEndTerm"
placeholder=
"请输入结束天数"
style=
"width: 165px
"
class=
"mx-2
"
:precision=
"0"
:min=
"0"
/>
...
...
@@ -162,21 +162,15 @@
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>
<div
class=
"flex items-center gap-1 flex-wrap"
>
<div
class=
"select-box spu-pic"
v-for=
"(spu, index) in productSpus"
:key=
"spu.id"
>
<el-image
:src=
"spu.picUrl"
/>
<Icon
icon=
"ep:circle-close-filled"
class=
"del-icon"
@
click=
"handleRemoveSpu(index)"
/>
</div>
<div
class=
"select-box"
@
click=
"openSpuTableSelect"
>
<Icon
icon=
"ep:plus"
/>
</div>
</div>
</el-form-item>
</el-form>
<template
#
footer
>
...
...
@@ -184,6 +178,7 @@
<el-button
@
click=
"dialogVisible = false"
>
取 消
</el-button>
</
template
>
</Dialog>
<SpuTableSelect
ref=
"spuTableSelectRef"
multiple
@
change=
"handleSpuSelected"
/>
</template>
<
script
lang=
"ts"
setup
>
import
{
DICT_TYPE
,
getIntDictOptions
}
from
'@/utils/dict'
...
...
@@ -194,6 +189,7 @@ import {
PromotionDiscountTypeEnum
,
PromotionProductScopeEnum
}
from
'@/utils/constants'
import
SpuTableSelect
from
'@/views/mall/product/spu/components/SpuTableSelect.vue'
defineOptions
({
name
:
'CouponTemplateForm'
})
...
...
@@ -242,7 +238,7 @@ const formRules = reactive({
productSpuIds
:
[{
required
:
true
,
message
:
'商品范围不能为空'
,
trigger
:
'blur'
}]
})
const
formRef
=
ref
()
// 表单 Ref
const
productSpus
=
ref
([])
// 商品列表
const
productSpus
=
ref
<
ProductSpuApi
.
Spu
[]
>
([])
// 商品列表
/** 打开弹窗 */
const
open
=
async
(
type
:
string
,
id
?:
number
)
=>
{
...
...
@@ -265,12 +261,12 @@ const open = async (type: string, id?: number) => {
usePrice
:
data
.
usePrice
!==
undefined
?
data
.
usePrice
/
100.0
:
undefined
,
validTimes
:
[
data
.
validStartTime
,
data
.
validEndTime
]
}
// 获得商品范围
await
getProductScope
()
}
finally
{
formLoading
.
value
=
false
}
}
// 获得商品列表
productSpus
.
value
=
await
ProductSpuApi
.
getSpuSimpleList
()
}
defineExpose
({
open
})
// 提供 open 方法,用于打开弹窗
...
...
@@ -344,5 +340,59 @@ const resetForm = () => {
productSpuIds
:
[]
}
formRef
.
value
?.
resetFields
()
productSpus
.
value
=
[]
}
/** 获得商品范围 */
const
getProductScope
=
async
()
=>
{
switch
(
formData
.
value
.
productScope
)
{
case
PromotionProductScopeEnum
.
SPU
.
scope
:
// 获得商品列表
productSpus
.
value
=
await
ProductSpuApi
.
getSpuDetailList
(
formData
.
value
.
productSpuIds
)
break
default
:
break
}
}
/** 活动商品 按钮 */
const
spuTableSelectRef
=
ref
()
const
openSpuTableSelect
=
()
=>
{
spuTableSelectRef
.
value
.
open
(
productSpus
.
value
)
}
/** 选择商品后触发 */
const
handleSpuSelected
=
(
spus
:
ProductSpuApi
.
Spu
[])
=>
{
productSpus
.
value
=
spus
formData
.
value
.
productSpuIds
=
spus
.
map
((
spu
)
=>
spu
.
id
)
as
[]
}
/** 选择商品后触发 */
const
handleRemoveSpu
=
(
index
:
number
)
=>
{
productSpus
.
value
.
splice
(
index
,
1
)
formData
.
value
.
productSpuIds
.
splice
(
index
,
1
)
}
</
script
>
<
style
scoped
lang=
"scss"
>
.select-box
{
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
border
:
1px
dashed
var
(
--el-border-color-darker
);
border-radius
:
8px
;
width
:
60px
;
height
:
60px
;
}
.spu-pic
{
position
:
relative
;
}
.del-icon
{
position
:
absolute
;
z-index
:
1
;
width
:
20px
!important
;
height
:
20px
!important
;
right
:
-10px
;
top
:
-10px
;
}
</
style
>
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