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
881ec672
authored
Sep 03, 2023
by
YunaiV
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'dev' of
https://gitee.com/yudaocode/yudao-ui-admin-vue3
parents
067f89f1
13020895
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
888 additions
and
450 deletions
+888
-450
src/api/mall/promotion/coupon/coupon.ts
+8
-0
src/api/mall/promotion/coupon/couponTemplate.ts
+1
-1
src/api/mall/trade/order/index.ts
+15
-3
src/utils/constants.ts
+24
-2
src/views/mall/product/brand/index.vue
+1
-1
src/views/mall/product/category/components/ProductCategorySelect.vue
+47
-0
src/views/mall/product/category/index.vue
+1
-1
src/views/mall/product/comment/index.vue
+1
-1
src/views/mall/product/property/value/index.vue
+1
-1
src/views/mall/product/spu/components/SkuList.vue
+4
-13
src/views/mall/product/spu/components/SpuTableSelect.vue
+177
-93
src/views/mall/product/spu/components/index.ts
+30
-1
src/views/mall/product/spu/form/BasicInfoForm.vue
+37
-31
src/views/mall/product/spu/form/index.vue
+1
-12
src/views/mall/product/spu/index.vue
+8
-10
src/views/mall/promotion/coupon/components/CouponSendForm.vue
+162
-0
src/views/mall/promotion/coupon/formatter.ts
+44
-0
src/views/mall/promotion/coupon/index.vue
+2
-1
src/views/mall/promotion/coupon/template/CouponTemplateForm.vue
+144
-48
src/views/mall/promotion/coupon/template/index.vue
+10
-37
src/views/mall/trade/afterSale/detail/index.vue
+54
-19
src/views/mall/trade/order/detail/index.vue
+86
-174
src/views/member/user/index.vue
+30
-1
No files found.
src/api/mall/promotion/coupon/coupon.ts
View file @
881ec672
...
...
@@ -16,3 +16,11 @@ export const getCouponPage = async (params: PageParam) => {
params
:
params
})
}
// 发送优惠券
export
const
sendCoupon
=
async
(
data
:
any
)
=>
{
return
request
.
post
({
url
:
'/promotion/coupon/send'
,
data
:
data
})
}
src/api/mall/promotion/coupon/couponTemplate.ts
View file @
881ec672
...
...
@@ -9,7 +9,7 @@ export interface CouponTemplateVO {
takeType
:
number
usePrice
:
number
productScope
:
number
productS
puIds
:
string
productS
copeValues
:
number
[]
validityType
:
number
validStartTime
:
Date
validEndTime
:
Date
...
...
src/api/mall/trade/order/index.ts
View file @
881ec672
...
...
@@ -15,11 +15,11 @@ export interface OrderVO {
cancelTime
?:
Date
|
null
// 订单取消时间
cancelType
?:
number
|
null
// 取消类型
remark
?:
string
// 商家备注
payOrderId
:
number
|
null
// 支付订单编号
payOrderId
?
:
number
|
null
// 支付订单编号
payed
?:
boolean
// 是否已支付
payTime
?:
Date
|
null
// 付款时间
payChannelCode
?:
string
// 支付渠道
origin
alPrice
?:
number
|
null
// 商品原价(总)
tot
alPrice
?:
number
|
null
// 商品原价(总)
orderPrice
?:
number
|
null
// 订单原价(总)
discountPrice
?:
number
|
null
// 订单优惠(总)
deliveryPrice
?:
number
|
null
// 运费金额
...
...
@@ -44,12 +44,19 @@ export interface OrderVO {
pointPrice
?:
number
|
null
// 积分抵扣的金额
receiverAreaName
?:
string
//收件人地区名字
items
?:
OrderItemRespVO
[]
// 订单项列表
//用户信息
//
用户信息
user
?:
{
id
?:
number
|
null
nickname
?:
string
avatar
?:
string
}
// 订单操作日志
orderLog
:
orderLog
[]
}
export
interface
orderLog
{
content
?:
string
createTime
?:
Date
}
export
interface
OrderItemRespVO
{
...
...
@@ -94,6 +101,11 @@ export const getOrder = async (id: number | null) => {
return
await
request
.
get
({
url
:
`/trade/order/get-detail?id=`
+
id
})
}
// 查询交易订单物流详情
export
const
getExpressTrackList
=
async
(
id
:
number
|
null
)
=>
{
return
await
request
.
get
({
url
:
`/trade/order/get-express-track-list?id=`
+
id
})
}
export
interface
DeliveryVO
{
id
:
number
// 订单编号
logisticsId
:
number
|
null
// 物流公司编号
...
...
src/utils/constants.ts
View file @
881ec672
...
...
@@ -210,16 +210,38 @@ export const CouponTemplateValidityTypeEnum = {
}
/**
* 优惠劵模板的领取方式的枚举
*/
export
const
CouponTemplateTakeTypeEnum
=
{
USER
:
{
type
:
1
,
name
:
'直接领取'
},
ADMIN
:
{
type
:
2
,
name
:
'指定发放'
},
REGISTER
:
{
type
:
3
,
name
:
'新人券'
}
}
/**
* 营销的商品范围枚举
*/
export
const
PromotionProductScopeEnum
=
{
ALL
:
{
scope
:
1
,
name
:
'
全部商品参与
'
name
:
'
通用劵
'
},
SPU
:
{
scope
:
2
,
name
:
'指定商品参与'
name
:
'商品劵'
},
CATEGORY
:
{
scope
:
3
,
name
:
'品类劵'
}
}
...
...
src/views/mall/product/brand/index.vue
View file @
881ec672
...
...
@@ -59,7 +59,7 @@
<el-table-column
label=
"品牌名称"
prop=
"name"
sortable
/>
<el-table-column
label=
"品牌图片"
align=
"center"
prop=
"picUrl"
>
<template
#
default=
"scope"
>
<img
v-if=
"scope.row.picUrl"
:src=
"scope.row.picUrl"
alt=
"品牌图片"
class=
"h-
10
0px"
/>
<img
v-if=
"scope.row.picUrl"
:src=
"scope.row.picUrl"
alt=
"品牌图片"
class=
"h-
3
0px"
/>
</
template
>
</el-table-column>
<el-table-column
label=
"品牌排序"
align=
"center"
prop=
"sort"
/>
...
...
src/views/mall/product/category/components/ProductCategorySelect.vue
0 → 100644
View file @
881ec672
<
template
>
<el-tree-select
v-model=
"selectCategoryId"
:data=
"categoryList"
:props=
"defaultProps"
:multiple=
"multiple"
:show-checkbox=
"multiple"
class=
"w-1/1"
node-key=
"id"
placeholder=
"请选择商品分类"
/>
</
template
>
<
script
lang=
"ts"
setup
>
import
{
defaultProps
,
handleTree
}
from
'@/utils/tree'
import
*
as
ProductCategoryApi
from
'@/api/mall/product/category'
import
{
oneOfType
}
from
'vue-types'
import
{
propTypes
}
from
'@/utils/propTypes'
/** 商品分类选择组件 */
defineOptions
({
name
:
'ProductCategorySelect'
})
const
props
=
defineProps
({
modelValue
:
oneOfType
([
propTypes
.
number
.
def
(
undefined
),
propTypes
.
array
.
def
([])]).
def
(
undefined
),
// 选中的ID
multiple
:
propTypes
.
bool
.
def
(
false
)
// 是否多选
})
/** 选中的分类 ID */
const
selectCategoryId
=
computed
({
get
:
()
=>
{
return
props
.
modelValue
},
set
:
(
val
:
number
|
number
[])
=>
{
emit
(
'update:modelValue'
,
val
)
}
})
/** 分类选择 */
const
emit
=
defineEmits
([
'update:modelValue'
])
/** 初始化 **/
const
categoryList
=
ref
([])
// 分类树
onMounted
(
async
()
=>
{
// 获得分类树
const
data
=
await
ProductCategoryApi
.
getCategoryList
({})
categoryList
.
value
=
handleTree
(
data
,
'id'
,
'parentId'
)
})
</
script
>
src/views/mall/product/category/index.vue
View file @
881ec672
...
...
@@ -38,7 +38,7 @@
<el-table-column
label=
"分类名称"
prop=
"name"
sortable
/>
<el-table-column
label=
"移动端分类图"
align=
"center"
prop=
"picUrl"
>
<template
#
default=
"scope"
>
<img
v-if=
"scope.row.picUrl"
:src=
"scope.row.picUrl"
alt=
"移动端分类图"
class=
"h-
10
0px"
/>
<img
v-if=
"scope.row.picUrl"
:src=
"scope.row.picUrl"
alt=
"移动端分类图"
class=
"h-
3
0px"
/>
</
template
>
</el-table-column>
<el-table-column
label=
"分类排序"
align=
"center"
prop=
"sort"
/>
...
...
src/views/mall/product/comment/index.vue
View file @
881ec672
...
...
@@ -115,7 +115,7 @@
:formatter=
"dateFormatter"
width=
"170"
/>
<el-table-column
label=
"
状态"
align=
"center"
width=
"65
px"
>
<el-table-column
label=
"
是否展示"
align=
"center"
width=
"80
px"
>
<
template
#
default=
"scope"
>
<el-switch
v-model=
"scope.row.visible"
...
...
src/views/mall/product/property/value/index.vue
View file @
881ec672
...
...
@@ -147,7 +147,7 @@ const handleDelete = async (id: number) => {
// 删除的二次确认
await
message
.
delConfirm
()
// 发起删除
await
PropertyApi
.
deleteProperty
(
id
)
await
PropertyApi
.
deleteProperty
Value
(
id
)
message
.
success
(
t
(
'common.delSuccess'
))
// 刷新列表
await
getList
()
...
...
src/views/mall/product/spu/components/SkuList.vue
View file @
881ec672
...
...
@@ -328,24 +328,15 @@ const tableHeaders = ref<{ prop: string; label: string }[]>([]) // 多属性表
* 保存时,每个商品规格的表单要校验下。例如说,销售金额最低是 0.01 这种。
*/
const
validateSku
=
()
=>
{
const
checks
=
[
'price'
,
'marketPrice'
,
'costPrice'
]
let
warningInfo
=
'请检查商品各行相关属性配置,'
let
validate
=
true
// 默认通过
for
(
const
sku
of
formData
.
value
!
.
skus
!
)
{
// 作为活动组件的校验
if
(
props
.
isActivityComponent
)
{
for
(
const
rule
of
props
?.
ruleConfig
)
{
const
arg
=
getValue
(
sku
,
rule
.
name
)
if
(
!
rule
.
rule
(
arg
))
{
validate
=
false
// 只要有一个不通过则直接不通过
warningInfo
+=
rule
.
message
break
}
}
}
else
{
if
(
checks
.
some
((
check
)
=>
sku
[
check
]
<
0.01
))
{
for
(
const
rule
of
props
?.
ruleConfig
)
{
const
arg
=
getValue
(
sku
,
rule
.
name
)
if
(
!
rule
.
rule
(
arg
))
{
validate
=
false
// 只要有一个不通过则直接不通过
warningInfo
=
'商品相关价格不能低于 0.01 元!!'
warningInfo
+=
rule
.
message
break
}
}
...
...
src/views/mall/product/spu/components/SpuTableSelect.vue
View file @
881ec672
<
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
)
=>
{
debugger
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/product/spu/components/index.ts
View file @
881ec672
import
SkuList
from
'./SkuList.vue'
import
{
Spu
}
from
'@/api/mall/product/spu'
interface
PropertyAndValues
{
id
:
number
...
...
@@ -22,4 +23,32 @@ interface RuleConfig {
message
:
string
}
export
{
SkuList
,
PropertyAndValues
,
RuleConfig
}
/**
* 获得商品的规格列表 - 商品相关的公共函数
*
* @param spu
* @return PropertyAndValues 规格列表
*/
const
getPropertyList
=
(
spu
:
Spu
):
PropertyAndValues
[]
=>
{
// 直接拿返回的 skus 属性逆向生成出 propertyList
const
properties
:
PropertyAndValues
[]
=
[]
// 只有是多规格才处理
if
(
spu
.
specType
)
{
spu
.
skus
?.
forEach
((
sku
)
=>
{
sku
.
properties
?.
forEach
(({
propertyId
,
propertyName
,
valueId
,
valueName
})
=>
{
// 添加属性
if
(
!
properties
?.
some
((
item
)
=>
item
.
id
===
propertyId
))
{
properties
.
push
({
id
:
propertyId
!
,
name
:
propertyName
!
,
values
:
[]
})
}
// 添加属性值
const
index
=
properties
?.
findIndex
((
item
)
=>
item
.
id
===
propertyId
)
if
(
!
properties
[
index
].
values
?.
some
((
value
)
=>
value
.
id
===
valueId
))
{
properties
[
index
].
values
?.
push
({
id
:
valueId
!
,
name
:
valueName
!
})
}
})
})
}
return
properties
}
export
{
SkuList
,
PropertyAndValues
,
RuleConfig
,
getPropertyList
}
src/views/mall/product/spu/form/BasicInfoForm.vue
View file @
881ec672
...
...
@@ -109,7 +109,12 @@
<!-- 多规格添加-->
<el-col
:span=
"24"
>
<el-form-item
v-if=
"!formData.specType"
>
<SkuList
ref=
"skuListRef"
:prop-form-data=
"formData"
:propertyList=
"propertyList"
/>
<SkuList
ref=
"skuListRef"
:prop-form-data=
"formData"
:propertyList=
"propertyList"
:rule-config=
"ruleConfig"
/>
</el-form-item>
<el-form-item
v-if=
"formData.specType"
label=
"商品属性"
>
<el-button
class=
"mr-15px mb-10px"
@
click=
"attributesAddFormRef.open"
>
添加规格
</el-button>
...
...
@@ -120,7 +125,12 @@
<SkuList
:is-batch=
"true"
:prop-form-data=
"formData"
:propertyList=
"propertyList"
/>
</el-form-item>
<el-form-item
label=
"属性列表"
>
<SkuList
ref=
"skuListRef"
:prop-form-data=
"formData"
:propertyList=
"propertyList"
/>
<SkuList
ref=
"skuListRef"
:prop-form-data=
"formData"
:propertyList=
"propertyList"
:rule-config=
"ruleConfig"
/>
</el-form-item>
</
template
>
</el-col>
...
...
@@ -175,7 +185,7 @@ import { propTypes } from '@/utils/propTypes'
import
{
checkSelectedNode
,
defaultProps
,
handleTree
,
treeToString
}
from
'@/utils/tree'
import
{
createImageViewer
}
from
'@/components/ImageViewer'
import
{
DICT_TYPE
,
getIntDictOptions
}
from
'@/utils/dict'
import
{
PropertyAndValues
,
SkuList
}
from
'@/views/mall/product/spu/components/index.ts'
import
{
getPropertyList
,
RuleConfig
,
SkuList
}
from
'@/views/mall/product/spu/components/index.ts'
import
ProductAttributes
from
'./ProductAttributes.vue'
import
ProductPropertyAddForm
from
'./ProductPropertyAddForm.vue'
import
{
basicInfoSchema
}
from
'./spu.data'
...
...
@@ -186,6 +196,30 @@ import * as ExpressTemplateApi from '@/api/mall/trade/delivery/expressTemplate'
defineOptions
({
name
:
'ProductSpuBasicInfoForm'
})
// sku 相关属性校验规则
const
ruleConfig
:
RuleConfig
[]
=
[
{
name
:
'stock'
,
rule
:
(
arg
)
=>
arg
>=
1
,
message
:
'商品库存必须大于等于 1 !!!'
},
{
name
:
'price'
,
rule
:
(
arg
)
=>
arg
>=
0.01
,
message
:
'商品销售价格必须大于等于 0.01 !!!'
},
{
name
:
'marketPrice'
,
rule
:
(
arg
)
=>
arg
>=
0.01
,
message
:
'商品市场价格必须大于等于 0.01 !!!'
},
{
name
:
'costPrice'
,
rule
:
(
arg
)
=>
arg
>=
0.01
,
message
:
'商品成本价格必须大于等于 0.01 !!!'
}
]
// ====== 商品详情相关操作 ======
const
{
allSchemas
}
=
useCrudSchemas
(
basicInfoSchema
)
/** 商品图预览 */
...
...
@@ -203,34 +237,6 @@ const imagePreview = (args) => {
})
}
/**
* 获得商品的规格列表
*
* @param spu
* @return PropertyAndValues 规格列表
*/
const
getPropertyList
=
(
spu
:
Spu
):
PropertyAndValues
[]
=>
{
// 直接拿返回的 skus 属性逆向生成出 propertyList
const
properties
:
PropertyAndValues
[]
=
[]
// 只有是多规格才处理
if
(
spu
.
specType
)
{
spu
.
skus
?.
forEach
((
sku
)
=>
{
sku
.
properties
?.
forEach
(({
propertyId
,
propertyName
,
valueId
,
valueName
})
=>
{
// 添加属性
if
(
!
properties
?.
some
((
item
)
=>
item
.
id
===
propertyId
))
{
properties
.
push
({
id
:
propertyId
!
,
name
:
propertyName
!
,
values
:
[]
})
}
// 添加属性值
const
index
=
properties
?.
findIndex
((
item
)
=>
item
.
id
===
propertyId
)
if
(
!
properties
[
index
].
values
?.
some
((
value
)
=>
value
.
id
===
valueId
))
{
properties
[
index
].
values
?.
push
({
id
:
valueId
!
,
name
:
valueName
!
})
}
})
})
}
return
properties
}
// ====== end ======
const
message
=
useMessage
()
// 消息弹窗
...
...
src/views/mall/product/spu/form/index.vue
View file @
881ec672
...
...
@@ -142,17 +142,6 @@ const submitForm = async () => {
await
unref
(
otherSettingsRef
)?.
validate
()
// 深拷贝一份, 这样最终 server 端不满足,不需要恢复,
const
deepCopyFormData
=
cloneDeep
(
unref
(
formData
.
value
))
as
ProductSpuApi
.
Spu
// 兜底处理 sku 空数据
formData
.
value
.
skus
!
.
forEach
((
sku
)
=>
{
// 因为是空数据这里判断一下商品条码是否为空就行
if
(
sku
.
barCode
===
''
)
{
const
index
=
deepCopyFormData
.
skus
!
.
findIndex
(
(
item
)
=>
JSON
.
stringify
(
item
.
properties
)
===
JSON
.
stringify
(
sku
.
properties
)
)
// 删除这条 sku
deepCopyFormData
.
skus
!
.
splice
(
index
,
1
)
}
})
deepCopyFormData
.
skus
!
.
forEach
((
item
)
=>
{
// 给sku name赋值
item
.
name
=
deepCopyFormData
.
name
...
...
@@ -189,7 +178,7 @@ const submitForm = async () => {
/** 关闭按钮 */
const
close
=
()
=>
{
delView
(
unref
(
currentRoute
))
push
(
'/product/product-spu'
)
push
(
{
name
:
'ProductSpu'
}
)
}
/** 初始化 */
onMounted
(
async
()
=>
{
...
...
src/views/mall/product/spu/index.vue
View file @
881ec672
...
...
@@ -170,6 +170,14 @@
>
详情
</el-button>
<el-button
v-hasPermi=
"['product:spu:update']"
link
type=
"primary"
@
click=
"openForm(row.id)"
>
修改
</el-button>
<template
v-if=
"queryParams.tabType === 4"
>
<el-button
v-hasPermi=
"['product:spu:delete']"
...
...
@@ -189,16 +197,6 @@
</el-button>
</
template
>
<
template
v-else
>
<!-- 只有不是上架和回收站的商品可以编辑 -->
<el-button
v-if=
"queryParams.tabType !== 0"
v-hasPermi=
"['product:spu:update']"
link
type=
"primary"
@
click=
"openForm(row.id)"
>
修改
</el-button>
<el-button
v-hasPermi=
"['product:spu:update']"
link
...
...
src/views/mall/promotion/coupon/components/CouponSendForm.vue
0 → 100644
View file @
881ec672
<
template
>
<Dialog
v-model=
"dialogVisible"
:appendToBody=
"true"
title=
"发送优惠券"
width=
"70%"
>
<!-- 搜索工作栏 -->
<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>
<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-form-item>
</el-form>
<!-- 列表 -->
<el-table
v-loading=
"loading"
:data=
"list"
show-overflow-tooltip
>
<el-table-column
align=
"center"
label=
"优惠券名称"
prop=
"name"
min-width=
"60"
/>
<el-table-column
label=
"优惠金额 / 折扣"
align=
"center"
prop=
"discount"
:formatter=
"discountFormat"
min-width=
"60"
/>
<el-table-column
align=
"center"
label=
"最低消费"
prop=
"usePrice"
min-width=
"60"
:formatter=
"usePriceFormat"
/>
<el-table-column
align=
"center"
label=
"有效期限"
prop=
"validityType"
min-width=
"140"
:formatter=
"validityTypeFormat"
/>
<el-table-column
align=
"center"
label=
"剩余数量"
min-width=
"60"
:formatter=
"remainedCountFormat"
/>
<el-table-column
label=
"操作"
align=
"center"
min-width=
"60px"
fixed=
"right"
>
<template
#
default=
"scope"
>
<el-button
link
type=
"primary"
:disabled=
"sendLoading"
:loading=
"sendLoading"
@
click=
"handleSendCoupon(scope.row.id)"
v-hasPermi=
"['member:level:update']"
>
发送
</el-button>
</
template
>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
v-model:limit=
"queryParams.pageSize"
v-model:page=
"queryParams.pageNo"
:total=
"total"
@
pagination=
"getList"
/>
<div
class=
"clear-both"
></div>
</Dialog>
</template>
<
script
lang=
"ts"
setup
>
import
*
as
CouponTemplateApi
from
'@/api/mall/promotion/coupon/couponTemplate'
import
*
as
CouponApi
from
'@/api/mall/promotion/coupon/coupon'
import
{
discountFormat
,
remainedCountFormat
,
usePriceFormat
,
validityTypeFormat
}
from
'@/views/mall/promotion/coupon/formatter'
import
{
CouponTemplateTakeTypeEnum
}
from
'@/utils/constants'
defineOptions
({
name
:
'PromotionCouponSendForm'
})
const
message
=
useMessage
()
// 消息弹窗
const
total
=
ref
(
0
)
// 列表的总页数
const
list
=
ref
<
any
[]
>
([])
// 列表的数据
const
loading
=
ref
(
false
)
// 列表的加载中
const
sendLoading
=
ref
(
false
)
// 发送按钮的加载中
const
dialogVisible
=
ref
(
false
)
// 弹窗的是否展示
const
queryParams
=
ref
({
pageNo
:
1
,
pageSize
:
10
,
name
:
null
,
canTakeTypes
:
[
CouponTemplateTakeTypeEnum
.
ADMIN
.
type
]
})
// 查询参数
const
queryFormRef
=
ref
()
// 搜索的表单
// 领取人的编号列表
let
userIds
:
number
[]
=
[]
/** 打开弹窗 */
const
open
=
(
ids
:
number
[])
=>
{
userIds
=
ids
// 打开时重置查询,防止发送列表剩余数量未更新的问题
resetQuery
()
dialogVisible
.
value
=
true
}
defineExpose
({
open
})
// 提供 open 方法,用于打开弹窗
/** 查询列表 */
const
getList
=
async
()
=>
{
loading
.
value
=
true
try
{
const
data
=
await
CouponTemplateApi
.
getCouponTemplatePage
(
queryParams
.
value
)
list
.
value
=
data
.
list
total
.
value
=
data
.
total
}
finally
{
loading
.
value
=
false
}
}
/** 搜索按钮操作 */
const
handleQuery
=
()
=>
{
queryParams
.
value
.
pageNo
=
1
getList
()
}
/** 重置按钮操作 */
const
resetQuery
=
()
=>
{
queryFormRef
?.
value
?.
resetFields
()
handleQuery
()
}
/** 发送操作 **/
const
handleSendCoupon
=
async
(
templateId
:
number
)
=>
{
try
{
sendLoading
.
value
=
true
await
CouponApi
.
sendCoupon
({
templateId
,
userIds
})
// 提示
message
.
success
(
'发送成功'
)
dialogVisible
.
value
=
false
}
finally
{
sendLoading
.
value
=
false
}
}
</
script
>
src/views/mall/promotion/coupon/formatter.ts
0 → 100644
View file @
881ec672
import
{
CouponTemplateValidityTypeEnum
,
PromotionDiscountTypeEnum
}
from
'@/utils/constants'
import
{
formatDate
}
from
'@/utils/formatTime'
import
{
CouponTemplateVO
}
from
'@/api/mall/promotion/coupon/couponTemplate'
import
{
floatToFixed2
}
from
'@/utils'
// 格式化【优惠金额/折扣】
export
const
discountFormat
=
(
row
:
CouponTemplateVO
)
=>
{
if
(
row
.
discountType
===
PromotionDiscountTypeEnum
.
PRICE
.
type
)
{
return
`¥
${
floatToFixed2
(
row
.
discountPrice
)}
`
}
if
(
row
.
discountType
===
PromotionDiscountTypeEnum
.
PERCENT
.
type
)
{
return
`
${
row
.
discountPrice
}
%`
}
return
'未知【'
+
row
.
discountType
+
'】'
}
// 格式化【领取上限】
export
const
takeLimitCountFormat
=
(
row
:
CouponTemplateVO
)
=>
{
if
(
row
.
takeLimitCount
===
-
1
)
{
return
'无领取限制'
}
return
`
${
row
.
takeLimitCount
}
张/人`
}
// 格式化【有效期限】
export
const
validityTypeFormat
=
(
row
:
CouponTemplateVO
)
=>
{
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
+
'】'
}
// 格式化【剩余数量】
export
const
remainedCountFormat
=
(
row
:
CouponTemplateVO
)
=>
{
return
row
.
totalCount
-
row
.
takeCount
}
// 格式化【最低消费】
export
const
usePriceFormat
=
(
row
:
CouponTemplateVO
)
=>
{
return
`¥
${
floatToFixed2
(
row
.
usePrice
)}
`
}
src/views/mall/promotion/coupon/index.vue
View file @
881ec672
...
...
@@ -122,7 +122,8 @@ const queryParams = reactive({
pageNo
:
1
,
pageSize
:
10
,
createTime
:
[],
status
:
undefined
status
:
undefined
,
nickname
:
undefined
})
const
queryFormRef
=
ref
()
// 搜索的表单
...
...
src/views/mall/promotion/coupon/template/CouponTemplateForm.vue
View file @
881ec672
...
...
@@ -10,7 +10,40 @@
<el-form-item
label=
"优惠券名称"
prop=
"name"
>
<el-input
v-model=
"formData.name"
placeholder=
"请输入优惠券名称"
/>
</el-form-item>
<el-form-item
label=
"优惠券类型"
prop=
"discountType"
>
<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
label=
"商品"
v-if=
"formData.productScope === PromotionProductScopeEnum.SPU.scope"
prop=
"productSpuIds"
>
<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-item
label=
"分类"
v-if=
"formData.productScope === PromotionProductScopeEnum.CATEGORY.scope"
prop=
"productCategoryIds"
>
<ProductCategorySelect
v-model=
"formData.productCategoryIds"
/>
</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)"
...
...
@@ -29,7 +62,7 @@
<el-input-number
v-model=
"formData.discountPrice"
placeholder=
"请输入优惠金额,单位:元"
style=
"width: 400px
"
class=
"!w-400px mr-2
"
:precision=
"2"
:min=
"0"
/>
...
...
@@ -43,7 +76,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 +91,7 @@
<el-input-number
v-model=
"formData.discountLimitPrice"
placeholder=
"请输入最多优惠"
style=
"width: 400px
"
class=
"!w-400px mr-2
"
:precision=
"2"
:min=
"0"
/>
...
...
@@ -68,7 +101,7 @@
<el-input-number
v-model=
"formData.usePrice"
placeholder=
"无门槛请设为 0"
style=
"width: 400px
"
class=
"!w-400px mr-2
"
:precision=
"2"
:min=
"0"
/>
...
...
@@ -84,7 +117,7 @@
<el-input-number
v-model=
"formData.totalCount"
placeholder=
"发放数量,没有之后不能领取或发放,-1 为不限制"
style=
"width: 400px
"
class=
"!w-400px mr-2
"
:precision=
"0"
:min=
"-1"
/>
...
...
@@ -94,7 +127,7 @@
<el-input-number
v-model=
"formData.takeLimitCount"
placeholder=
"设置为 -1 时,可无限领取"
style=
"width: 400px
"
class=
"!w-400px mr-2
"
:precision=
"0"
:min=
"-1"
/>
...
...
@@ -119,7 +152,7 @@
<el-date-picker
v-model=
"formData.validTimes"
style=
"width: 240px"
value-format=
"
YYYY-MM-DD HH:mm:ss
"
value-format=
"
x
"
type=
"datetimerange"
:default-time=
"[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)]"
/>
...
...
@@ -133,7 +166,7 @@
<el-input-number
v-model=
"formData.fixedStartTerm"
placeholder=
"0 为今天生效"
style=
"width: 165px
"
class=
"mx-2
"
:precision=
"0"
:min=
"0"
/>
...
...
@@ -141,49 +174,19 @@
<el-input-number
v-model=
"formData.fixedEndTerm"
placeholder=
"请输入结束天数"
style=
"width: 165px
"
class=
"mx-2
"
: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>
<SpuTableSelect
ref=
"spuTableSelectRef"
multiple
@
change=
"handleSpuSelected"
/>
</template>
<
script
lang=
"ts"
setup
>
import
{
DICT_TYPE
,
getIntDictOptions
}
from
'@/utils/dict'
...
...
@@ -194,6 +197,8 @@ import {
PromotionDiscountTypeEnum
,
PromotionProductScopeEnum
}
from
'@/utils/constants'
import
SpuTableSelect
from
'@/views/mall/product/spu/components/SpuTableSelect.vue'
import
ProductCategorySelect
from
'@/views/mall/product/category/components/ProductCategorySelect.vue'
defineOptions
({
name
:
'CouponTemplateForm'
})
...
...
@@ -222,7 +227,9 @@ const formData = ref({
fixedStartTerm
:
undefined
,
fixedEndTerm
:
undefined
,
productScope
:
PromotionProductScopeEnum
.
ALL
.
scope
,
productSpuIds
:
[]
productScopeValues
:
[],
// 商品范围:值为 品类编号列表 或 商品编号列表 ,用于提交
productCategoryIds
:
[],
// 仅用于表单,不提交
productSpuIds
:
[]
// 仅用于表单,不提交
})
const
formRules
=
reactive
({
name
:
[{
required
:
true
,
message
:
'优惠券名称不能为空'
,
trigger
:
'blur'
}],
...
...
@@ -239,10 +246,11 @@ const formRules = reactive({
fixedStartTerm
:
[{
required
:
true
,
message
:
'开始领取天数不能为空'
,
trigger
:
'blur'
}],
fixedEndTerm
:
[{
required
:
true
,
message
:
'开始领取天数不能为空'
,
trigger
:
'blur'
}],
productScope
:
[{
required
:
true
,
message
:
'商品范围不能为空'
,
trigger
:
'blur'
}],
productSpuIds
:
[{
required
:
true
,
message
:
'商品范围不能为空'
,
trigger
:
'blur'
}]
productSpuIds
:
[{
required
:
true
,
message
:
'商品不能为空'
,
trigger
:
'blur'
}],
productCategoryIds
:
[{
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 +273,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 方法,用于打开弹窗
...
...
@@ -305,7 +313,11 @@ const submitForm = async () => {
formData
.
value
.
validTimes
&&
formData
.
value
.
validTimes
.
length
===
2
?
formData
.
value
.
validTimes
[
1
]
:
undefined
}
as
CouponTemplateApi
.
CouponTemplateVO
}
as
unknown
as
CouponTemplateApi
.
CouponTemplateVO
// 设置商品范围
setProductScopeValues
(
data
)
if
(
formType
.
value
===
'create'
)
{
await
CouponTemplateApi
.
createCouponTemplate
(
data
)
message
.
success
(
t
(
'common.createSuccess'
))
...
...
@@ -341,8 +353,92 @@ const resetForm = () => {
fixedStartTerm
:
undefined
,
fixedEndTerm
:
undefined
,
productScope
:
PromotionProductScopeEnum
.
ALL
.
scope
,
productSpuIds
:
[]
productScopeValues
:
[],
productSpuIds
:
[],
productCategoryIds
:
[]
}
formRef
.
value
?.
resetFields
()
productSpus
.
value
=
[]
}
/** 获得商品范围 */
const
getProductScope
=
async
()
=>
{
switch
(
formData
.
value
.
productScope
)
{
case
PromotionProductScopeEnum
.
SPU
.
scope
:
// 设置商品编号
formData
.
value
.
productSpuIds
=
formData
.
value
.
productScopeValues
// 获得商品列表
productSpus
.
value
=
await
ProductSpuApi
.
getSpuDetailList
(
formData
.
value
.
productScopeValues
)
break
case
PromotionProductScopeEnum
.
CATEGORY
.
scope
:
await
nextTick
(()
=>
{
let
productCategoryIds
=
formData
.
value
.
productScopeValues
if
(
Array
.
isArray
(
productCategoryIds
)
&&
productCategoryIds
.
length
>
0
)
{
// 单选时使用数组不能反显
productCategoryIds
=
productCategoryIds
[
0
]
}
// 设置品类编号
formData
.
value
.
productCategoryIds
=
productCategoryIds
})
break
default
:
break
}
}
/** 设置商品范围 */
function
setProductScopeValues
(
data
:
CouponTemplateApi
.
CouponTemplateVO
)
{
switch
(
formData
.
value
.
productScope
)
{
case
PromotionProductScopeEnum
.
SPU
.
scope
:
data
.
productScopeValues
=
formData
.
value
.
productSpuIds
break
case
PromotionProductScopeEnum
.
CATEGORY
.
scope
:
data
.
productScopeValues
=
Array
.
isArray
(
formData
.
value
.
productCategoryIds
)
?
formData
.
value
.
productCategoryIds
:
[
formData
.
value
.
productCategoryIds
]
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
>
src/views/mall/promotion/coupon/template/index.vue
View file @
881ec672
...
...
@@ -103,7 +103,7 @@
label=
"剩余数量"
align=
"center"
prop=
"totalCount"
:formatter=
"
(row) => row.totalCount - row.takeCoun
t"
:formatter=
"
remainedCountForma
t"
/>
<el-table-column
label=
"领取上限"
...
...
@@ -171,14 +171,16 @@
<
script
lang=
"ts"
setup
>
import
*
as
CouponTemplateApi
from
'@/api/mall/promotion/coupon/couponTemplate'
import
{
CommonStatusEnum
,
CouponTemplateValidityTypeEnum
,
PromotionDiscountTypeEnum
}
from
'@/utils/constants'
import
{
CommonStatusEnum
}
from
'@/utils/constants'
import
{
DICT_TYPE
,
getIntDictOptions
}
from
'@/utils/dict'
import
{
dateFormatter
,
formatDate
}
from
'@/utils/formatTime'
import
{
dateFormatter
}
from
'@/utils/formatTime'
import
CouponTemplateForm
from
'./CouponTemplateForm.vue'
import
{
discountFormat
,
remainedCountFormat
,
takeLimitCountFormat
,
validityTypeFormat
}
from
'@/views/mall/promotion/coupon/formatter'
defineOptions
({
name
:
'PromotionCouponTemplate'
})
...
...
@@ -193,6 +195,7 @@ const queryParams = reactive({
pageSize
:
10
,
name
:
null
,
status
:
null
,
discountType
:
null
,
type
:
null
,
createTime
:
[]
})
...
...
@@ -258,36 +261,6 @@ const handleDelete = async (id: number) => {
}
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
()
...
...
src/views/mall/trade/afterSale/detail/index.vue
View file @
881ec672
...
...
@@ -122,8 +122,36 @@
</el-row>
</el-descriptions-item>
</el-descriptions>
<!-- 售后信息 TODO @puhui999:需要接入 -->
<el-descriptions
title=
"售后日志"
/>
<el-descriptions
title=
"售后日志"
>
<el-descriptions-item
labelClassName=
"no-colon"
>
<el-timeline>
<el-timeline-item
v-for=
"saleLog in formData.afterSaleLog"
:key=
"saleLog.id"
:timestamp=
"formatDate(saleLog.createTime)"
placement=
"top"
>
<el-card>
<span>
用户类型:
</span>
<dict-tag
:type=
"DICT_TYPE.USER_TYPE"
:value=
"saleLog.userType"
class=
"mr-10px"
/>
<span>
售后状态(之前):
</span>
<dict-tag
:type=
"DICT_TYPE.TRADE_AFTER_SALE_STATUS"
:value=
"saleLog.beforeStatus"
class=
"mr-10px"
/>
<span>
售后状态(之后):
</span>
<dict-tag
:type=
"DICT_TYPE.TRADE_AFTER_SALE_STATUS"
:value=
"saleLog.afterStatus"
class=
"mr-10px"
/>
<span>
操作明细:{{ saleLog.content }}
</span>
</el-card>
</el-timeline-item>
</el-timeline>
</el-descriptions-item>
</el-descriptions>
</ContentWrap>
<!-- 各种操作的弹窗 -->
...
...
@@ -138,12 +166,14 @@ import UpdateAuditReasonForm from '@/views/mall/trade/afterSale/form/AfterSaleDi
import
{
createImageViewer
}
from
'@/components/ImageViewer'
import
{
isArray
}
from
'@/utils/is'
defineOptions
({
name
:
'Trade
OrderDetailForm
'
})
defineOptions
({
name
:
'Trade
AfterSaleDetail
'
})
const
{
t
}
=
useI18n
()
// 国际化
const
message
=
useMessage
()
// 消息弹窗
const
{
params
}
=
useRoute
()
// 查询参数
const
formData
=
ref
({
order
:
{}
order
:
{},
afterSaleLog
:
[]
})
const
updateAuditReasonFormRef
=
ref
()
// 拒绝售后表单 Ref
...
...
@@ -154,44 +184,48 @@ const getDetail = async () => {
formData
.
value
=
await
AfterSaleApi
.
getAfterSale
(
id
)
}
}
/**
* 同意售后
*/
/** 同意售后 */
const
agree
=
()
=>
{
message
.
confirm
(
'是否同意售后?'
).
then
(()
=>
{
AfterSaleApi
.
agree
(
formData
.
value
.
id
)
message
.
success
(
t
(
'common.success'
))
getDetail
()
})
}
/**
* 拒绝售后
*/
/** 拒绝售后 */
const
disagree
=
()
=>
{
updateAuditReasonFormRef
.
value
?.
open
(
formData
.
value
)
}
/**
* 确认收货
*/
/** 确认收货 */
const
receive
=
()
=>
{
message
.
confirm
(
'是否确认收货?'
).
then
(()
=>
{
AfterSaleApi
.
receive
(
formData
.
value
.
id
)
message
.
success
(
t
(
'common.success'
))
getDetail
()
})
}
/**
* 拒绝收货
*/
/** 拒绝收货 */
const
refuse
=
()
=>
{
message
.
confirm
(
'是否拒绝收货?'
).
then
(()
=>
{
AfterSaleApi
.
refuse
(
formData
.
value
.
id
)
message
.
success
(
t
(
'common.success'
))
getDetail
()
})
}
/**
* 确认退款
*/
/** 确认退款 */
const
refund
=
()
=>
{
message
.
confirm
(
'是否确认退款?'
).
then
(()
=>
{
AfterSaleApi
.
refund
(
formData
.
value
.
id
)
message
.
success
(
t
(
'common.success'
))
getDetail
()
})
}
/** 图片预览 */
const
imagePreview
=
(
args
)
=>
{
const
urlList
=
[]
...
...
@@ -206,6 +240,7 @@ const imagePreview = (args) => {
urlList
})
}
onMounted
(
async
()
=>
{
await
getDetail
()
})
...
...
src/views/mall/trade/order/detail/index.vue
View file @
881ec672
...
...
@@ -2,32 +2,32 @@
<ContentWrap>
<!-- 订单信息 -->
<el-descriptions
title=
"订单信息"
>
<el-descriptions-item
label=
"订单号: "
>
{{
orderInfo
.
no
}}
</el-descriptions-item>
<el-descriptions-item
label=
"订单号: "
>
{{
formData
.
no
}}
</el-descriptions-item>
<el-descriptions-item
label=
"配送方式: "
>
<dict-tag
:type=
"DICT_TYPE.TRADE_DELIVERY_TYPE"
:value=
"
orderInfo.deliveryType
"
/>
<dict-tag
:type=
"DICT_TYPE.TRADE_DELIVERY_TYPE"
:value=
"
formData.deliveryType!
"
/>
</el-descriptions-item>
<!-- TODO 营销活动待实现 -->
<el-descriptions-item
label=
"营销活动: "
>
秒杀活动
</el-descriptions-item>
<el-descriptions-item
label=
"订单类型: "
>
<dict-tag
:type=
"DICT_TYPE.TRADE_ORDER_TYPE"
:value=
"
orderInfo.type
"
/>
<dict-tag
:type=
"DICT_TYPE.TRADE_ORDER_TYPE"
:value=
"
formData.type!
"
/>
</el-descriptions-item>
<el-descriptions-item
label=
"收货人: "
>
{{
orderInfo
.
receiverName
}}
</el-descriptions-item>
<el-descriptions-item
label=
"买家留言: "
>
{{
orderInfo
.
userRemark
}}
</el-descriptions-item>
<el-descriptions-item
label=
"收货人: "
>
{{
formData
.
receiverName
}}
</el-descriptions-item>
<el-descriptions-item
label=
"买家留言: "
>
{{
formData
.
userRemark
}}
</el-descriptions-item>
<el-descriptions-item
label=
"订单来源: "
>
<dict-tag
:type=
"DICT_TYPE.TERMINAL"
:value=
"
orderInfo.terminal
"
/>
<dict-tag
:type=
"DICT_TYPE.TERMINAL"
:value=
"
formData.terminal!
"
/>
</el-descriptions-item>
<el-descriptions-item
label=
"联系电话: "
>
{{
orderInfo
.
receiverMobile
}}
</el-descriptions-item>
<el-descriptions-item
label=
"商家备注: "
>
{{
orderInfo
.
remark
}}
</el-descriptions-item>
<el-descriptions-item
label=
"支付单号: "
>
{{
orderInfo
.
payOrderId
}}
</el-descriptions-item>
<el-descriptions-item
label=
"联系电话: "
>
{{
formData
.
receiverMobile
}}
</el-descriptions-item>
<el-descriptions-item
label=
"商家备注: "
>
{{
formData
.
remark
}}
</el-descriptions-item>
<el-descriptions-item
label=
"支付单号: "
>
{{
formData
.
payOrderId
}}
</el-descriptions-item>
<el-descriptions-item
label=
"付款方式: "
>
<dict-tag
:type=
"DICT_TYPE.PAY_CHANNEL_CODE"
:value=
"
orderInfo.payChannelCode
"
/>
<dict-tag
:type=
"DICT_TYPE.PAY_CHANNEL_CODE"
:value=
"
formData.payChannelCode!
"
/>
</el-descriptions-item>
<!--
<el-descriptions-item
label=
"买家: "
>
{{
orderInfo
.
user
.
nickname
}}
</el-descriptions-item>
-->
<!-- TODO
芋艿
:待实现:跳转会员 -->
<!--
<el-descriptions-item
label=
"买家: "
>
{{
formData
.
user
.
nickname
}}
</el-descriptions-item>
-->
<!-- TODO
@puhui999
:待实现:跳转会员 -->
<el-descriptions-item
label=
"收货地址: "
>
{{
orderInfo
.
receiverAreaName
}}
{{
orderInfo
.
receiverDetailAddress
}}
{{
formData
.
receiverAreaName
}}
{{
formData
.
receiverDetailAddress
}}
<el-link
v-clipboard:copy=
"
orderInfo.receiverAreaName + ' ' + orderInfo
.receiverDetailAddress"
v-clipboard:copy=
"
formData.receiverAreaName + ' ' + formData
.receiverDetailAddress"
v-clipboard:success=
"clipboardSuccess"
icon=
"ep:document-copy"
type=
"primary"
...
...
@@ -38,8 +38,9 @@
<!-- 订单状态 -->
<el-descriptions
:column=
"1"
title=
"订单状态"
>
<el-descriptions-item
label=
"订单状态: "
>
<dict-tag
:type=
"DICT_TYPE.TRADE_ORDER_STATUS"
:value=
"
orderInfo.status
"
/>
<dict-tag
:type=
"DICT_TYPE.TRADE_ORDER_STATUS"
:value=
"
formData.status!
"
/>
</el-descriptions-item>
<!-- TODO @puhui999:根据状态,进行展示按钮 -->
<el-descriptions-item
label-class-name=
"no-colon"
>
<el-button
type=
"primary"
@
click=
"openForm('updatePrice')"
>
调整价格
</el-button>
<el-button
type=
"primary"
@
click=
"openForm('remark')"
>
备注
</el-button>
...
...
@@ -59,7 +60,7 @@
<el-descriptions-item
labelClassName=
"no-colon"
>
<el-row
:gutter=
"20"
>
<el-col
:span=
"15"
>
<el-table
:data=
"
orderInfo
.items"
border
>
<el-table
:data=
"
formData
.items"
border
>
<el-table-column
label=
"商品"
prop=
"spuName"
width=
"auto"
>
<
template
#
default=
"{ row }"
>
{{
row
.
spuName
}}
...
...
@@ -91,111 +92,75 @@
</el-descriptions>
<el-descriptions
:column=
"6"
>
<el-descriptions-item
label=
"商品总额: "
>
{{ floatToFixed2(
orderInfo.totalPrice
) }}元
{{ floatToFixed2(
formData.totalPrice!
) }}元
</el-descriptions-item>
<el-descriptions-item
label=
"运费金额: "
>
{{ floatToFixed2(
orderInfo.deliveryPrice
) }}元
{{ floatToFixed2(
formData.deliveryPrice!
) }}元
</el-descriptions-item>
<el-descriptions-item
label=
"订单调价: "
>
{{ floatToFixed2(
orderInfo.updatePrice
) }}元
{{ floatToFixed2(
formData.adjustPrice!
) }}元
</el-descriptions-item>
<el-descriptions-item>
<
template
#
label
><span
style=
"color: red"
>
商品优惠:
</span></
template
>
{{ floatToFixed2(
orderInfo.couponPrice
) }}元
{{ floatToFixed2(
formData.couponPrice!
) }}元
</el-descriptions-item>
<el-descriptions-item>
<
template
#
label
><span
style=
"color: red"
>
订单优惠:
</span></
template
>
{{ floatToFixed2(
orderInfo.discountPrice
) }}元
{{ floatToFixed2(
formData.discountPrice!
) }}元
</el-descriptions-item>
<el-descriptions-item>
<
template
#
label
><span
style=
"color: red"
>
积分抵扣:
</span></
template
>
{{ floatToFixed2(
orderInfo.pointPrice
) }}元
{{ floatToFixed2(
formData.pointPrice!
) }}元
</el-descriptions-item>
<el-descriptions-item
v-for=
"item in 5"
:key=
"item"
label-class-name=
"no-colon"
/>
<!-- 占位 -->
<el-descriptions-item
label=
"应付金额: "
>
{{ floatToFixed2(
orderInfo.payPrice
) }}元
{{ floatToFixed2(
formData.payPrice!
) }}元
</el-descriptions-item>
</el-descriptions>
<!-- TODO 芋艿:需要改改 -->
<div
v-for=
"group in detailGroups"
:key=
"group.title"
>
<el-descriptions
:title=
"group.title"
v-bind=
"group.groupProps"
>
<!-- 订单操作日志 -->
<el-descriptions-item
v-if=
"group.key === 'orderLog'"
labelClassName=
"no-colon"
>
<el-timeline>
<el-timeline-item
v-for=
"activity in detailInfo[group.key]"
:key=
"activity.timestamp"
:timestamp=
"activity.timestamp"
>
{{ activity.content }}
</el-timeline-item>
</el-timeline>
</el-descriptions-item>
<!-- 物流信息 TODO 等物流接口搞定重构一下 -->
<!-- TODO @xiaobai:改成一个包裹哈;目前只允许发货一次 -->
<el-descriptions-item
v-if=
"group.key === 'expressInfo'"
labelClassName=
"no-colon"
>
<!-- 循环包裹物流信息 -->
<div
v-show=
"(pkgInfo = detailInfo[group.key]) !== null"
style=
"border: 1px dashed"
>
<!-- 包裹详情 -->
<el-descriptions
class=
"m-5"
>
<el-descriptions-item
v-for=
"(pkgChild, pkgCIdx) in group.children"
:key=
"`pkgChild_${pkgCIdx}`"
:label=
"pkgChild.label"
v-bind=
"pkgChild.childProps"
>
<!-- 包裹商品列表 -->
<
template
v-if=
"pkgChild.valueKey === 'goodsList' && pkgInfo[pkgChild.valueKey]"
>
<div
v-for=
"(goodInfo, goodInfoIdx) in pkgInfo[pkgChild.valueKey]"
:key=
"`goodInfo_$
{goodInfoIdx}`"
style="display: flex"
>
<el-image
:src=
"goodInfo.imgUrl"
style=
"width: 100px; height: 100px; flex: none"
/>
<el-descriptions
:column=
"1"
>
<el-descriptions-item
labelClassName=
"no-colon"
>
{{
goodInfo
.
name
}}
</el-descriptions-item>
<el-descriptions-item
label=
"数量"
>
{{
goodInfo
.
count
}}
</el-descriptions-item>
</el-descriptions>
</div>
</
template
>
<!-- 包裹物流详情 -->
<
template
v-else-if=
"pkgChild.valueKey === 'wlxq'"
>
<el-row
:gutter=
"10"
>
<el-col
:offset=
"1"
:span=
"6"
>
<el-timeline>
<el-timeline-item
v-for=
"(activity, index) in pkgInfo[pkgChild.valueKey]"
:key=
"index"
:timestamp=
"activity.timestamp"
>
{{
activity
.
content
}}
</el-timeline-item>
</el-timeline>
</el-col>
</el-row>
</
template
>
<
template
v-else
>
{{
pkgInfo
[
pkgChild
.
valueKey
]
}}
</
template
>
</el-descriptions-item>
</el-descriptions>
</div>
</el-descriptions-item>
</el-descriptions>
</div>
<el-descriptions
:column=
"4"
title=
"物流信息"
>
<el-descriptions-item
label=
"物流公司: "
>
{{ deliveryExpressList.find((item) => item.id === formData.logisticsId)?.name }}
</el-descriptions-item>
<el-descriptions-item
label=
"运单号: "
>
{{ formData.logisticsNo }}
</el-descriptions-item>
<el-descriptions-item
label=
"发货时间: "
>
{{ formatDate(formData.deliveryTime!) }}
</el-descriptions-item>
<el-descriptions-item
label=
"物流状态: "
>
<!-- TODO 物流状态怎么获取? -->
<dict-tag
:type=
"DICT_TYPE.TRADE_ORDER_STATUS"
:value=
"formData.deliveryStatus!"
/>
</el-descriptions-item>
<!-- 占位 4 -->
<el-descriptions-item
v-for=
"item in 4"
:key=
"item"
label-class-name=
"no-colon"
/>
<el-descriptions-item
label=
"物流详情: "
>
<el-timeline>
<el-timeline-item
v-for=
"(express, index) in expressTrackList"
:key=
"index"
:timestamp=
"formatDate(express.time)"
>
{{ express.content }}
</el-timeline-item>
</el-timeline>
</el-descriptions-item>
</el-descriptions>
<el-descriptions
title=
"订单操作日志"
>
<el-descriptions-item
labelClassName=
"no-colon"
>
<el-timeline>
<el-timeline-item
v-for=
"(log, index) in formData.orderLog"
:key=
"index"
:timestamp=
"formatDate(log.createTime!)"
>
{{ log.content }}
</el-timeline-item>
</el-timeline>
</el-descriptions-item>
</el-descriptions>
</ContentWrap>
<!-- 各种操作的弹窗 -->
...
...
@@ -207,84 +172,24 @@
<
script
lang=
"ts"
setup
>
import
*
as
TradeOrderApi
from
'@/api/mall/trade/order'
import
{
floatToFixed2
}
from
'@/utils'
import
{
formatDate
}
from
'@/utils/formatTime'
import
{
DICT_TYPE
}
from
'@/utils/dict'
import
OrderUpdateRemarkForm
from
'@/views/mall/trade/order/form/OrderUpdateRemarkForm.vue'
import
OrderDeliveryForm
from
'@/views/mall/trade/order/form/OrderDeliveryForm.vue'
import
OrderUpdateAddressForm
from
'@/views/mall/trade/order/form/OrderUpdateAddressForm.vue'
import
OrderUpdatePriceForm
from
'@/views/mall/trade/order/form/OrderUpdatePriceForm.vue'
import
*
as
DeliveryExpressApi
from
'@/api/mall/trade/delivery/express'
defineOptions
({
name
:
'TradeOrderDetail
Form
'
})
defineOptions
({
name
:
'TradeOrderDetail'
})
const
message
=
useMessage
()
// 消息弹窗
const
{
params
}
=
useRoute
()
// 查询参数
const
orderInfo
=
ref
<
TradeOrderApi
.
OrderVO
>
({})
// TODO @puhui999:这个改成直接读属性,不用按照这种写法;后续再改
const
detailGroups
=
ref
([
{
title
:
'物流信息'
,
key
:
'expressInfo'
,
children
:
[
{
label
:
'发货时间: '
,
valueKey
:
'fhsj'
},
{
label
:
'物流公司: '
,
valueKey
:
'wlgs'
},
{
label
:
'运单号: '
,
valueKey
:
'ydh'
},
{
label
:
'物流状态: '
,
valueKey
:
'wlzt'
,
childProps
:
{
span
:
3
}
},
{
label
:
'物流详情: '
,
valueKey
:
'wlxq'
}
]
},
{
title
:
'订单操作日志'
,
key
:
'orderLog'
}
])
// TODO @puhui999:从后台读数据哈。后续再改
const
detailInfo
=
ref
({
// 物流信息
expressInfo
:
{
label
:
'包裹1'
,
name
:
'bg1'
,
fhsj
:
'2022-11-03 16:50:45'
,
wlgs
:
'极兔'
,
ydh
:
'2132123'
,
wlzt
:
'不支持此快递公司'
,
wlxq
:
[
{
content
:
'正在派送途中,请您准备签收(派件人:王涛,电话:13854563814)'
,
timestamp
:
'2018-04-15 15:00:16'
},
{
content
:
'快件到达 【烟台龙口东江村委营业点】'
,
timestamp
:
'2018-04-13 14:54:19'
},
{
content
:
'快件已发车'
,
timestamp
:
'2018-04-11 12:55:52'
},
{
content
:
'快件已发车'
,
timestamp
:
'2018-04-11 12:55:52'
},
{
content
:
'快件已发车'
,
timestamp
:
'2018-04-11 12:55:52'
}
]
},
orderLog
:
[
// 订单操作日志
{
content
:
'买家【乌鸦】关闭了订单'
,
timestamp
:
'2018-04-15 15:00:16'
},
{
content
:
'买家【乌鸦】下单了'
,
timestamp
:
'2018-04-15 15:00:16'
}
],
goodsInfo
:
[]
// 商品详情tableData
// 订单详情
const
formData
=
ref
<
TradeOrderApi
.
OrderVO
>
({
orderLog
:
[]
// TODO @puhui999:orderLogs
})
// TODO @puhui999:这个最好也拆掉哈
const
deliveryFormRef
=
ref
()
// 发货表单 Ref
const
updateRemarkForm
=
ref
()
// 订单备注表单 Ref
const
updateAddressFormRef
=
ref
()
// 收货地址表单 Ref
...
...
@@ -292,36 +197,43 @@ const updatePriceFormRef = ref() // 订单调价表单 Ref
const
openForm
=
(
type
:
string
)
=>
{
switch
(
type
)
{
case
'remark'
:
updateRemarkForm
.
value
?.
open
(
orderInfo
.
value
)
updateRemarkForm
.
value
?.
open
(
formData
.
value
)
break
case
'delivery'
:
deliveryFormRef
.
value
?.
open
(
orderInfo
.
value
)
deliveryFormRef
.
value
?.
open
(
formData
.
value
)
break
case
'updateAddress'
:
updateAddressFormRef
.
value
?.
open
(
orderInfo
.
value
)
updateAddressFormRef
.
value
?.
open
(
formData
.
value
)
break
case
'updatePrice'
:
updatePriceFormRef
.
value
?.
open
(
orderInfo
.
value
)
updatePriceFormRef
.
value
?.
open
(
formData
.
value
)
break
}
}
/** 获得详情 */
const
{
params
}
=
useRoute
()
// 查询参数
const
getDetail
=
async
()
=>
{
const
id
=
params
.
orderId
as
unknown
as
number
if
(
id
)
{
const
res
=
(
await
TradeOrderApi
.
getOrder
(
id
))
as
TradeOrderApi
.
OrderVO
orderInfo
.
value
=
res
formData
.
value
=
res
}
}
onMounted
(
async
()
=>
{
await
getDetail
()
})
/** 复制 */
const
clipboardSuccess
=
()
=>
{
message
.
success
(
'复制成功'
)
}
/** 初始化 **/
const
deliveryExpressList
=
ref
([])
// 物流公司
const
expressTrackList
=
ref
([])
// 物流详情
onMounted
(
async
()
=>
{
await
getDetail
()
deliveryExpressList
.
value
=
await
DeliveryExpressApi
.
getSimpleDeliveryExpressList
()
expressTrackList
.
value
=
await
TradeOrderApi
.
getExpressTrackList
(
formData
.
value
.
id
!
)
})
</
script
>
<
style
lang=
"scss"
scoped
>
:deep
(
.el-descriptions
)
{
...
...
src/views/member/user/index.vue
View file @
881ec672
...
...
@@ -60,13 +60,21 @@
<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
@
click=
"openCoupon"
v-hasPermi=
"['promotion:coupon:send']"
>
发送优惠券
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table
v-loading=
"loading"
:data=
"list"
:stripe=
"true"
:show-overflow-tooltip=
"true"
>
<el-table
v-loading=
"loading"
:data=
"list"
:stripe=
"true"
:show-overflow-tooltip=
"true"
@
selection-change=
"handleSelectionChange"
>
<el-table-column
type=
"selection"
width=
"55"
/>
<el-table-column
label=
"用户编号"
align=
"center"
prop=
"id"
width=
"120px"
/>
<el-table-column
label=
"头像"
align=
"center"
prop=
"avatar"
width=
"80px"
>
<template
#
default=
"scope"
>
...
...
@@ -145,6 +153,8 @@
<UserForm
ref=
"formRef"
@
success=
"getList"
/>
<!-- 修改用户等级弹窗 -->
<UpdateLevelForm
ref=
"updateLevelFormRef"
@
success=
"getList"
/>
<!-- 发送优惠券弹窗 -->
<CouponSendForm
ref=
"couponSendFormRef"
/>
</template>
<
script
setup
lang=
"ts"
>
import
{
dateFormatter
}
from
'@/utils/formatTime'
...
...
@@ -154,9 +164,12 @@ import MemberTagSelect from '@/views/member/tag/components/MemberTagSelect.vue'
import
MemberLevelSelect
from
'@/views/member/level/components/MemberLevelSelect.vue'
import
MemberGroupSelect
from
'@/views/member/group/components/MemberGroupSelect.vue'
import
UpdateLevelForm
from
'@/views/member/user/UpdateLevelForm.vue'
import
CouponSendForm
from
'@/views/mall/promotion/coupon/components/CouponSendForm.vue'
defineOptions
({
name
:
'MemberUser'
})
const
message
=
useMessage
()
// 消息弹窗
const
loading
=
ref
(
true
)
// 列表的加载中
const
total
=
ref
(
0
)
// 列表的总页数
const
list
=
ref
([])
// 列表的数据
...
...
@@ -173,6 +186,7 @@ const queryParams = reactive({
})
const
queryFormRef
=
ref
()
// 搜索的表单
const
updateLevelFormRef
=
ref
()
// 修改会员等级表单
const
selectedIds
=
ref
<
number
[]
>
([])
// 表格的选中 ID 数组
/** 查询列表 */
const
getList
=
async
()
=>
{
...
...
@@ -204,6 +218,21 @@ const openDetail = (id: number) => {
push
({
name
:
'MemberUserDetail'
,
params
:
{
id
}
})
}
/** 表格选中事件 */
const
handleSelectionChange
=
(
rows
:
UserApi
.
UserVO
[])
=>
{
selectedIds
.
value
=
rows
.
map
((
row
)
=>
row
.
id
)
}
/** 发送优惠券 */
const
couponSendFormRef
=
ref
()
const
openCoupon
=
()
=>
{
if
(
selectedIds
.
value
.
length
===
0
)
{
message
.
warning
(
'请选择要发送优惠券的用户'
)
return
}
couponSendFormRef
.
value
.
open
(
selectedIds
.
value
)
}
/** 初始化 **/
onMounted
(()
=>
{
getList
()
...
...
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