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
df3b381d
authored
Apr 12, 2023
by
dhb52
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactor: mp模块ts重构
parent
ebbf47f5
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
753 additions
and
413 deletions
+753
-413
src/views/mp/autoReply/index.vue
+145
-88
src/views/mp/components/WxMpSelect.vue
+10
-12
src/views/mp/components/wx-editor/WxEditor.vue
+10
-105
src/views/mp/draft/index.vue
+68
-75
src/views/mp/freePublish/index.vue
+24
-9
src/views/mp/material/index.vue
+41
-47
src/views/mp/menu/index.vue
+38
-38
src/views/mp/tag/TagForm.vue
+12
-7
src/views/mp/tag/index.vue
+30
-15
src/views/mp/user/index.vue
+69
-17
src/views/pay/order/orderForm.vue
+152
-0
src/views/pay/refund/refundForm.vue
+154
-0
No files found.
src/views/mp/autoReply/index.vue
View file @
df3b381d
...
@@ -3,13 +3,16 @@
...
@@ -3,13 +3,16 @@
<!-- 搜索工作栏 -->
<!-- 搜索工作栏 -->
<ContentWrap>
<ContentWrap>
<!-- TODO @芋艿:调整成 el-form 和 WxAccountSelect -->
<el-form
class=
"-mb-15px"
:model=
"queryParams"
:inline=
"true"
label-width=
"68px"
>
<WxAccountSelect
@
change=
"accountChanged"
/>
<el-form-item
label=
"公众号"
prop=
"accountId"
>
<WxMpSelect
@
change=
"onAccountChanged"
/>
</el-form-item>
</el-form>
</ContentWrap>
</ContentWrap>
<!-- tab 切换 -->
<!-- tab 切换 -->
<ContentWrap>
<ContentWrap>
<el-tabs
v-model=
"
t
ype"
@
tab-change=
"handleTabChange"
>
<el-tabs
v-model=
"
msgT
ype"
@
tab-change=
"handleTabChange"
>
<!-- 操作工具栏 -->
<!-- 操作工具栏 -->
<el-row
:gutter=
"10"
class=
"mb8"
>
<el-row
:gutter=
"10"
class=
"mb8"
>
<el-col
:span=
"1.5"
>
<el-col
:span=
"1.5"
>
...
@@ -18,26 +21,26 @@
...
@@ -18,26 +21,26 @@
plain
plain
@
click=
"handleAdd"
@
click=
"handleAdd"
v-hasPermi=
"['mp:auto-reply:create']"
v-hasPermi=
"['mp:auto-reply:create']"
v-if=
"
type !== '1'
|| list.length
<
=
0
"
v-if=
"
msgType !== MsgType.Follow
|| list.length
<
=
0
"
>
>
<Icon
icon=
"ep:plus"
/>
新增
<Icon
icon=
"ep:plus"
/>
新增
</el-button>
</el-button>
</el-col>
</el-col>
</el-row>
</el-row>
<!-- tab 项 -->
<!-- tab 项 -->
<el-tab-pane
name=
"1
"
>
<el-tab-pane
:name=
"MsgType.Follow
"
>
<template
#
label
>
<template
#
label
>
<span><Icon
icon=
"ep:star
-off
"
/>
关注时回复
</span>
<span><Icon
icon=
"ep:star"
/>
关注时回复
</span>
</
template
>
</
template
>
</el-tab-pane>
</el-tab-pane>
<el-tab-pane
name=
"2
"
>
<el-tab-pane
:name=
"MsgType.Message
"
>
<
template
#
label
>
<
template
#
label
>
<span><Icon
icon=
"ep:chat-line-round"
/>
消息回复
</span>
<span><Icon
icon=
"ep:chat-line-round"
/>
消息回复
</span>
</
template
>
</
template
>
</el-tab-pane>
</el-tab-pane>
<el-tab-pane
name=
"3
"
>
<el-tab-pane
:name=
"MsgType.Keyword
"
>
<
template
#
label
>
<
template
#
label
>
<span><Icon
icon=
"
ep:news
"
/>
关键词回复
</span>
<span><Icon
icon=
"
fa:newspaper-o
"
/>
关键词回复
</span>
</
template
>
</
template
>
</el-tab-pane>
</el-tab-pane>
</el-tabs>
</el-tabs>
...
@@ -47,10 +50,20 @@
...
@@ -47,10 +50,20 @@
label=
"请求消息类型"
label=
"请求消息类型"
align=
"center"
align=
"center"
prop=
"requestMessageType"
prop=
"requestMessageType"
v-if=
"type === '2'"
v-if=
"msgType === MsgType.Message"
/>
<el-table-column
label=
"关键词"
align=
"center"
prop=
"requestKeyword"
v-if=
"msgType === MsgType.Keyword"
/>
/>
<el-table-column
label=
"关键词"
align=
"center"
prop=
"requestKeyword"
v-if=
"type === '3'"
/>
<el-table-column
<el-table-column
label=
"匹配类型"
align=
"center"
prop=
"requestMatch"
v-if=
"type === '3'"
>
label=
"匹配类型"
align=
"center"
prop=
"requestMatch"
v-if=
"msgType === MsgType.Keyword"
>
<
template
#
default=
"scope"
>
<
template
#
default=
"scope"
>
<dict-tag
:type=
"DICT_TYPE.MP_AUTO_REPLY_REQUEST_MATCH"
:value=
"scope.row.requestMatch"
/>
<dict-tag
:type=
"DICT_TYPE.MP_AUTO_REPLY_REQUEST_MATCH"
:value=
"scope.row.requestMatch"
/>
</
template
>
</
template
>
...
@@ -64,7 +77,7 @@
...
@@ -64,7 +77,7 @@
<
template
#
default=
"scope"
>
<
template
#
default=
"scope"
>
<div
v-if=
"scope.row.responseMessageType === 'text'"
>
{{
scope
.
row
.
responseContent
}}
</div>
<div
v-if=
"scope.row.responseMessageType === 'text'"
>
{{
scope
.
row
.
responseContent
}}
</div>
<div
v-else-if=
"scope.row.responseMessageType === 'voice'"
>
<div
v-else-if=
"scope.row.responseMessageType === 'voice'"
>
<WxVoicePlayer
:url=
"scope.row.responseMediaUrl"
/>
<WxVoicePlayer
v-if=
"scope.row.responseMediaUrl"
:url=
"scope.row.responseMediaUrl"
/>
</div>
</div>
<div
v-else-if=
"scope.row.responseMessageType === 'image'"
>
<div
v-else-if=
"scope.row.responseMessageType === 'image'"
>
<a
target=
"_blank"
:href=
"scope.row.responseMediaUrl"
>
<a
target=
"_blank"
:href=
"scope.row.responseMediaUrl"
>
...
@@ -77,7 +90,11 @@
...
@@ -77,7 +90,11 @@
scope.row.responseMessageType === 'shortvideo'
scope.row.responseMessageType === 'shortvideo'
"
"
>
>
<WxVideoPlayer
:url=
"scope.row.responseMediaUrl"
style=
"margin-top: 10px"
/>
<WxVideoPlayer
v-if=
"scope.row.responseMediaUrl"
:url=
"scope.row.responseMediaUrl"
style=
"margin-top: 10px"
/>
</div>
</div>
<div
v-else-if=
"scope.row.responseMessageType === 'news'"
>
<div
v-else-if=
"scope.row.responseMessageType === 'news'"
>
<WxNews
:articles=
"scope.row.responseArticles"
/>
<WxNews
:articles=
"scope.row.responseArticles"
/>
...
@@ -123,21 +140,21 @@
...
@@ -123,21 +140,21 @@
</el-table>
</el-table>
<!-- 添加或修改自动回复的对话框 -->
<!-- 添加或修改自动回复的对话框 -->
<el-dialog
:title=
"title"
v-model=
"
open
"
width=
"800px"
append-to-body
>
<el-dialog
:title=
"title"
v-model=
"
showReplyFormDialog
"
width=
"800px"
append-to-body
>
<el-form
ref=
"formRef"
:model=
"
f
orm"
:rules=
"rules"
label-width=
"80px"
>
<el-form
ref=
"formRef"
:model=
"
replyF
orm"
:rules=
"rules"
label-width=
"80px"
>
<el-form-item
label=
"消息类型"
prop=
"requestMessageType"
v-if=
"
type === '2'
"
>
<el-form-item
label=
"消息类型"
prop=
"requestMessageType"
v-if=
"
msgType === MsgType.Message
"
>
<el-select
v-model=
"
f
orm.requestMessageType"
placeholder=
"请选择"
>
<el-select
v-model=
"
replyF
orm.requestMessageType"
placeholder=
"请选择"
>
<
template
v-for=
"dict in getDictOptions(DICT_TYPE.MP_MESSAGE_TYPE)"
:key=
"dict.value"
>
<
template
v-for=
"dict in getDictOptions(DICT_TYPE.MP_MESSAGE_TYPE)"
:key=
"dict.value"
>
<el-option
<el-option
v-if=
"
r
equestMessageTypes.includes(dict.value)"
v-if=
"
R
equestMessageTypes.includes(dict.value)"
:label=
"dict.label"
:label=
"dict.label"
:value=
"dict.value"
:value=
"dict.value"
/>
/>
</
template
>
</
template
>
</el-select>
</el-select>
</el-form-item>
</el-form-item>
<el-form-item
label=
"匹配类型"
prop=
"requestMatch"
v-if=
"
type === '3'
"
>
<el-form-item
label=
"匹配类型"
prop=
"requestMatch"
v-if=
"
msgType === MsgType.Keyword
"
>
<el-select
v-model=
"
f
orm.requestMatch"
placeholder=
"请选择匹配类型"
clearable
>
<el-select
v-model=
"
replyF
orm.requestMatch"
placeholder=
"请选择匹配类型"
clearable
>
<el-option
<el-option
v-for=
"dict in getDictOptions(DICT_TYPE.MP_AUTO_REPLY_REQUEST_MATCH)"
v-for=
"dict in getDictOptions(DICT_TYPE.MP_AUTO_REPLY_REQUEST_MATCH)"
:key=
"dict.value"
:key=
"dict.value"
...
@@ -146,8 +163,8 @@
...
@@ -146,8 +163,8 @@
/>
/>
</el-select>
</el-select>
</el-form-item>
</el-form-item>
<el-form-item
label=
"关键词"
prop=
"requestKeyword"
v-if=
"
type === '3'
"
>
<el-form-item
label=
"关键词"
prop=
"requestKeyword"
v-if=
"
msgType === MsgType.Keyword
"
>
<el-input
v-model=
"
f
orm.requestKeyword"
placeholder=
"请输入内容"
clearable
/>
<el-input
v-model=
"
replyF
orm.requestKeyword"
placeholder=
"请输入内容"
clearable
/>
</el-form-item>
</el-form-item>
<el-form-item
label=
"回复消息"
>
<el-form-item
label=
"回复消息"
>
<WxReplySelect
:objData=
"objData"
v-if=
"hackResetWxReplySelect"
/>
<WxReplySelect
:objData=
"objData"
v-if=
"hackResetWxReplySelect"
/>
...
@@ -160,38 +177,47 @@
...
@@ -160,38 +177,47 @@
</el-dialog>
</el-dialog>
</ContentWrap>
</ContentWrap>
</template>
</template>
<
script
setup
name=
"MpAutoReply"
>
<
script
setup
lang=
"ts"
name=
"MpAutoReply"
>
import
WxVideoPlayer
from
'@/views/mp/components/wx-video-play/main.vue'
import
WxVideoPlayer
from
'@/views/mp/components/wx-video-play/main.vue'
import
WxVoicePlayer
from
'@/views/mp/components/wx-voice-play/main.vue'
import
WxVoicePlayer
from
'@/views/mp/components/wx-voice-play/main.vue'
import
WxMusic
from
'@/views/mp/components/wx-music/main.vue'
import
WxMusic
from
'@/views/mp/components/wx-music/main.vue'
import
WxNews
from
'@/views/mp/components/wx-news/main.vue'
import
WxNews
from
'@/views/mp/components/wx-news/main.vue'
import
WxReplySelect
from
'@/views/mp/components/wx-reply/main.vue'
import
WxReplySelect
from
'@/views/mp/components/wx-reply/main.vue'
import
Wx
AccountSelect
from
'@/views/mp/components/wx-account-select/main
.vue'
import
Wx
MpSelect
from
'@/views/mp/components/WxMpSelect
.vue'
import
*
as
MpAutoReplyApi
from
'@/api/mp/autoReply'
import
*
as
MpAutoReplyApi
from
'@/api/mp/autoReply'
import
{
DICT_TYPE
,
getDictOptions
}
from
'@/utils/dict'
import
{
DICT_TYPE
,
getDictOptions
}
from
'@/utils/dict'
import
{
dateFormatter
}
from
'@/utils/formatTime'
import
{
dateFormatter
}
from
'@/utils/formatTime'
import
{
ContentWrap
}
from
'@/components/ContentWrap'
import
{
ContentWrap
}
from
'@/components/ContentWrap'
import
{
TabPaneName
}
from
'element-plus'
const
message
=
useMessage
()
const
message
=
useMessage
()
// const queryFormRef = ref()
const
formRef
=
ref
()
const
formRef
=
ref
()
// tab 类型(1、关注时回复;2、消息回复;3、关键词回复)
// 消息类型(Follow: 关注时回复;Message: 消息回复;Keyword: 关键词回复)
const
type
=
ref
(
'3'
)
// 作为tab.name
enum
MsgType
{
Follow
=
1
,
Message
=
2
,
Keyword
=
3
}
const
msgType
=
ref
<
MsgType
>
(
MsgType
.
Keyword
)
// 允许选择的请求消息类型
// 允许选择的请求消息类型
const
r
equestMessageTypes
=
[
'text'
,
'image'
,
'voice'
,
'video'
,
'shortvideo'
,
'location'
,
'link'
]
const
R
equestMessageTypes
=
[
'text'
,
'image'
,
'voice'
,
'video'
,
'shortvideo'
,
'location'
,
'link'
]
// 遮罩层
// 遮罩层
const
loading
=
ref
(
true
)
const
loading
=
ref
(
true
)
// 显示搜索条件
// const showSearch = ref(true)
// 总条数
// 总条数
const
total
=
ref
(
0
)
const
total
=
ref
(
0
)
// 自动回复列表
// 自动回复列表
const
list
=
ref
([])
const
list
=
ref
<
any
[]
>
([])
// 查询参数
// 查询参数
const
queryParams
=
reactive
({
interface
QueryParams
{
pageNo
:
number
pageSize
:
number
accountId
?:
number
}
const
queryParams
:
QueryParams
=
reactive
({
pageNo
:
1
,
pageNo
:
1
,
pageSize
:
10
,
pageSize
:
10
,
accountId
:
undefined
accountId
:
undefined
...
@@ -200,12 +226,50 @@ const queryParams = reactive({
...
@@ -200,12 +226,50 @@ const queryParams = reactive({
// 弹出层标题
// 弹出层标题
const
title
=
ref
(
''
)
const
title
=
ref
(
''
)
// 是否显示弹出层
// 是否显示弹出层
const
open
=
ref
(
false
)
const
showReplyFormDialog
=
ref
(
false
)
// 表单参数
// 表单参数
const
form
=
ref
({})
type
ReplyType
=
'text'
|
'image'
|
'voice'
|
'video'
|
'shortvideo'
|
'location'
|
'link'
interface
ReplyForm
{
// relation:
id
?:
number
accountId
?:
number
type
?:
MsgType
// request:
requestMessageType
?:
ReplyType
requestMatch
?:
number
requestKeyword
?:
string
// response:
responseMessageType
?:
ReplyType
responseContent
?:
string
responseMediaId
?:
number
responseMediaUrl
?:
string
responseTitle
?:
string
responseDescription
?:
number
responseThumbMediaId
?:
string
responseThumbMediaUrl
?:
string
responseArticles
?:
any
[]
responseMusicUrl
?:
string
responseHqMusicUrl
?:
string
}
interface
ObjData
{
type
:
ReplyType
accountId
?:
number
content
?:
string
mediaId
?:
number
url
?:
string
title
?:
string
description
?:
string
thumbMediaId
?:
number
thumbMediaUrl
?:
string
articles
?:
any
[]
musicUrl
?:
string
hqMusicUrl
?:
string
}
const
replyForm
=
ref
<
ReplyForm
>
({})
// 回复消息
// 回复消息
const
objData
=
ref
({
const
objData
=
ref
<
ObjData
>
({
type
:
'text'
type
:
'text'
,
accountId
:
undefined
})
})
// 表单校验
// 表单校验
const
rules
=
{
const
rules
=
{
...
@@ -216,8 +280,8 @@ const rules = {
...
@@ -216,8 +280,8 @@ const rules = {
// 重置 WxReplySelect 组件,解决无法清除的问题
// 重置 WxReplySelect 组件,解决无法清除的问题
const
hackResetWxReplySelect
=
ref
(
false
)
const
hackResetWxReplySelect
=
ref
(
false
)
const
accountChanged
=
(
accountId
)
=>
{
const
onAccountChanged
=
(
id
?:
number
)
=>
{
queryParams
.
accountId
=
accountI
d
queryParams
.
accountId
=
i
d
getList
()
getList
()
}
}
...
@@ -227,7 +291,7 @@ const getList = async () => {
...
@@ -227,7 +291,7 @@ const getList = async () => {
try
{
try
{
const
data
=
await
MpAutoReplyApi
.
getAutoReplyPage
({
const
data
=
await
MpAutoReplyApi
.
getAutoReplyPage
({
...
queryParams
,
...
queryParams
,
type
:
t
ype
.
value
type
:
msgT
ype
.
value
})
})
list
.
value
=
data
.
list
list
.
value
=
data
.
list
total
.
value
=
data
.
total
total
.
value
=
data
.
total
...
@@ -242,8 +306,8 @@ const handleQuery = () => {
...
@@ -242,8 +306,8 @@ const handleQuery = () => {
getList
()
getList
()
}
}
const
handleTabChange
=
(
tabName
)
=>
{
const
handleTabChange
=
(
tabName
:
TabPaneName
)
=>
{
type
.
value
=
tabNam
e
msgType
.
value
=
tabName
as
MsgTyp
e
handleQuery
()
handleQuery
()
}
}
...
@@ -252,29 +316,29 @@ const handleAdd = () => {
...
@@ -252,29 +316,29 @@ const handleAdd = () => {
reset
()
reset
()
resetEditor
()
resetEditor
()
// 打开表单,并设置初始化
// 打开表单,并设置初始化
open
.
value
=
true
title
.
value
=
'新增自动回复'
objData
.
value
=
{
objData
.
value
=
{
type
:
'text'
,
type
:
'text'
,
accountId
:
queryParams
.
accountId
accountId
:
queryParams
.
accountId
}
}
title
.
value
=
'新增自动回复'
showReplyFormDialog
.
value
=
true
}
}
/** 修改按钮操作 */
/** 修改按钮操作 */
const
handleUpdate
=
(
row
)
=>
{
const
handleUpdate
=
async
(
row
:
any
)
=>
{
reset
()
reset
()
resetEditor
()
resetEditor
()
console
.
log
(
row
)
MpAutoReplyApi
.
getAutoReply
(
row
.
id
).
then
((
data
)
=>
{
const
data
=
await
MpAutoReplyApi
.
getAutoReply
(
row
.
id
)
// 设置属性
// 设置属性
f
orm
.
value
=
{
...
data
}
replyF
orm
.
value
=
{
...
data
}
delete
f
orm
.
value
[
'responseMessageType'
]
delete
replyF
orm
.
value
[
'responseMessageType'
]
delete
f
orm
.
value
[
'responseContent'
]
delete
replyF
orm
.
value
[
'responseContent'
]
delete
f
orm
.
value
[
'responseMediaId'
]
delete
replyF
orm
.
value
[
'responseMediaId'
]
delete
f
orm
.
value
[
'responseMediaUrl'
]
delete
replyF
orm
.
value
[
'responseMediaUrl'
]
delete
f
orm
.
value
[
'responseDescription'
]
delete
replyF
orm
.
value
[
'responseDescription'
]
delete
f
orm
.
value
[
'responseArticles'
]
delete
replyF
orm
.
value
[
'responseArticles'
]
objData
.
value
=
{
objData
.
value
=
{
type
:
data
.
responseMessageType
,
type
:
data
.
responseMessageType
,
accountId
:
queryParams
.
accountId
,
accountId
:
queryParams
.
accountId
,
...
@@ -291,55 +355,48 @@ const handleUpdate = (row) => {
...
@@ -291,55 +355,48 @@ const handleUpdate = (row) => {
}
}
// 打开表单
// 打开表单
open
.
value
=
true
title
.
value
=
'修改自动回复'
title
.
value
=
'修改自动回复'
})
showReplyFormDialog
.
value
=
true
}
}
const
handleSubmit
=
()
=>
{
const
handleSubmit
=
async
()
=>
{
formRef
.
value
?.
validate
((
valid
)
=>
{
const
valid
=
await
formRef
.
value
?.
validate
()
if
(
!
valid
)
{
if
(
!
valid
)
return
return
}
// 处理回复消息
// 处理回复消息
const
form
=
{
...
f
orm
.
value
}
const
submitForm
:
any
=
{
...
replyF
orm
.
value
}
f
orm
.
responseMessageType
=
objData
.
value
.
type
submitF
orm
.
responseMessageType
=
objData
.
value
.
type
f
orm
.
responseContent
=
objData
.
value
.
content
submitF
orm
.
responseContent
=
objData
.
value
.
content
f
orm
.
responseMediaId
=
objData
.
value
.
mediaId
submitF
orm
.
responseMediaId
=
objData
.
value
.
mediaId
f
orm
.
responseMediaUrl
=
objData
.
value
.
url
submitF
orm
.
responseMediaUrl
=
objData
.
value
.
url
f
orm
.
responseTitle
=
objData
.
value
.
title
submitF
orm
.
responseTitle
=
objData
.
value
.
title
f
orm
.
responseDescription
=
objData
.
value
.
description
submitF
orm
.
responseDescription
=
objData
.
value
.
description
f
orm
.
responseThumbMediaId
=
objData
.
value
.
thumbMediaId
submitF
orm
.
responseThumbMediaId
=
objData
.
value
.
thumbMediaId
f
orm
.
responseThumbMediaUrl
=
objData
.
value
.
thumbMediaUrl
submitF
orm
.
responseThumbMediaUrl
=
objData
.
value
.
thumbMediaUrl
f
orm
.
responseArticles
=
objData
.
value
.
articles
submitF
orm
.
responseArticles
=
objData
.
value
.
articles
f
orm
.
responseMusicUrl
=
objData
.
value
.
musicUrl
submitF
orm
.
responseMusicUrl
=
objData
.
value
.
musicUrl
f
orm
.
responseHqMusicUrl
=
objData
.
value
.
hqMusicUrl
submitF
orm
.
responseHqMusicUrl
=
objData
.
value
.
hqMusicUrl
if
(
f
orm
.
value
.
id
!==
undefined
)
{
if
(
replyF
orm
.
value
.
id
!==
undefined
)
{
MpAutoReplyApi
.
updateAutoReply
(
form
).
then
(()
=>
{
await
MpAutoReplyApi
.
updateAutoReply
(
submitForm
)
message
.
success
(
'修改成功'
)
message
.
success
(
'修改成功'
)
open
.
value
=
false
getList
()
})
}
else
{
}
else
{
MpAutoReplyApi
.
createAutoReply
(
form
).
then
(()
=>
{
await
MpAutoReplyApi
.
createAutoReply
(
submitForm
)
message
.
success
(
'新增成功'
)
message
.
success
(
'新增成功'
)
open
.
value
=
false
getList
()
})
}
}
})
showReplyFormDialog
.
value
=
false
getList
()
}
}
// 表单重置
// 表单重置
const
reset
=
()
=>
{
const
reset
=
()
=>
{
f
orm
.
value
=
{
replyF
orm
.
value
=
{
id
:
undefined
,
id
:
undefined
,
accountId
:
queryParams
.
accountId
,
accountId
:
queryParams
.
accountId
,
type
:
t
ype
.
value
,
type
:
msgT
ype
.
value
,
requestKeyword
:
undefined
,
requestKeyword
:
undefined
,
requestMatch
:
type
.
value
===
'3'
?
1
:
undefined
,
requestMatch
:
msgType
.
value
===
MsgType
.
Keyword
?
1
:
undefined
,
requestMessageType
:
undefined
requestMessageType
:
undefined
}
}
formRef
.
value
?.
resetFields
()
formRef
.
value
?.
resetFields
()
...
@@ -347,7 +404,7 @@ const reset = () => {
...
@@ -347,7 +404,7 @@ const reset = () => {
// 取消按钮
// 取消按钮
const
cancel
=
()
=>
{
const
cancel
=
()
=>
{
open
.
value
=
false
showReplyFormDialog
.
value
=
false
reset
()
reset
()
}
}
...
...
src/views/mp/components/WxMpSelect.vue
View file @
df3b381d
<
template
>
<
template
>
<el-select
<el-select
v-model=
"account.id"
placeholder=
"请选择公众号"
class=
"!w-240px"
@
change=
"onChanged"
>
v-model=
"accountId"
placeholder=
"请选择公众号"
class=
"!w-240px"
@
change=
"accountChanged"
>
<el-option
v-for=
"item in accountList"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
/>
<el-option
v-for=
"item in accountList"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
/>
</el-select>
</el-select>
</
template
>
</
template
>
...
@@ -12,11 +7,14 @@
...
@@ -12,11 +7,14 @@
<
script
lang=
"ts"
setup
name=
"WxMpSelect"
>
<
script
lang=
"ts"
setup
name=
"WxMpSelect"
>
import
*
as
MpAccountApi
from
'@/api/mp/account'
import
*
as
MpAccountApi
from
'@/api/mp/account'
const
accountId
:
Ref
<
number
|
undefined
>
=
ref
()
const
account
:
MpAccountApi
.
AccountVO
=
reactive
({
id
:
undefined
,
name
:
''
})
const
accountList
:
Ref
<
MpAccountApi
.
AccountVO
[]
>
=
ref
([])
const
accountList
:
Ref
<
MpAccountApi
.
AccountVO
[]
>
=
ref
([])
const
emit
=
defineEmits
<
{
const
emit
=
defineEmits
<
{
(
e
:
'change'
,
id
:
number
|
undefined
):
void
(
e
:
'change'
,
id
?:
number
,
name
?:
string
):
void
}
>
()
}
>
()
onMounted
(()
=>
{
onMounted
(()
=>
{
...
@@ -27,12 +25,12 @@ const handleQuery = async () => {
...
@@ -27,12 +25,12 @@ const handleQuery = async () => {
accountList
.
value
=
await
MpAccountApi
.
getSimpleAccountList
()
accountList
.
value
=
await
MpAccountApi
.
getSimpleAccountList
()
// 默认选中第一个
// 默认选中第一个
if
(
accountList
.
value
.
length
>
0
)
{
if
(
accountList
.
value
.
length
>
0
)
{
account
Id
.
value
=
accountList
.
value
[
0
].
id
account
.
id
=
accountList
.
value
[
0
].
id
emit
(
'change'
,
account
Id
.
valu
e
)
emit
(
'change'
,
account
.
id
,
account
.
nam
e
)
}
}
}
}
const
account
Changed
=
()
=>
{
const
on
Changed
=
()
=>
{
emit
(
'change'
,
account
Id
.
valu
e
)
emit
(
'change'
,
account
.
id
,
account
.
nam
e
)
}
}
</
script
>
</
script
>
src/views/mp/components/wx-editor/WxEditor.vue
View file @
df3b381d
<
script
setup
>
<
script
setup
>
import
{
ref
,
reactive
}
from
'vue'
import
{
ref
,
reactive
}
from
'vue'
import
{
QuillEditor
}
from
'@vueup/vue-quill'
import
'@vueup/vue-quill/dist/vue-quill.snow.css'
import
{
getAccessToken
}
from
'@/utils/auth'
import
{
getAccessToken
}
from
'@/utils/auth'
import
editorOptions
from
'./quill-options
'
import
{
Editor
}
from
'@/components/Editor
'
const
BASE_URL
=
import
.
meta
.
env
.
VITE_BASE_URL
const
BASE_URL
=
import
.
meta
.
env
.
VITE_BASE_URL
const
actionUrl
=
BASE_URL
+
'/admin-api/mp/material/upload-news-image'
// 这里写你要上传的图片服务器地址
const
headers
=
{
Authorization
:
'Bearer '
+
getAccessToken
()
}
// 设置上传的请求头部
const
message
=
useMessage
()
const
message
=
useMessage
()
...
@@ -30,21 +30,16 @@ const props = defineProps({
...
@@ -30,21 +30,16 @@ const props = defineProps({
const
emit
=
defineEmits
([
'input'
])
const
emit
=
defineEmits
([
'input'
])
const
myQuillEditorRef
=
ref
()
const
myQuillEditorRef
=
ref
()
const
content
=
ref
(
props
.
value
.
replace
(
/data-src/g
,
'src'
))
const
content
=
ref
(
props
.
value
.
replace
(
/data-src/g
,
'src'
))
const
loading
=
ref
(
false
)
// 根据图片上传状态来确定是否显示loading动画,刚开始是false,不显示
const
loading
=
ref
(
false
)
// 根据图片上传状态来确定是否显示loading动画,刚开始是false,不显示
const
actionUrl
=
ref
(
BASE_URL
+
'/admin-api/mp/material/upload-news-image'
)
// 这里写你要上传的图片服务器地址
const
headers
=
ref
({
Authorization
:
'Bearer '
+
getAccessToken
()
})
// 设置上传的请求头部
const
uploadData
=
reactive
({
const
uploadData
=
reactive
({
type
:
'image'
,
// TODO 芋艿:试试要不要换成 thumb
type
:
'image'
,
// TODO 芋艿:试试要不要换成 thumb
accountId
:
props
.
accountId
accountId
:
props
.
accountId
})
})
const
onEditorChange
=
()
=>
{
const
onEditorChange
=
(
text
)
=>
{
//内容改变事件
//内容改变事件
emit
(
'input'
,
content
.
value
)
emit
(
'input'
,
text
)
}
}
// 富文本图片上传前
// 富文本图片上传前
...
@@ -98,104 +93,14 @@ const uploadError = () => {
...
@@ -98,104 +93,14 @@ const uploadError = () => {
:on-error=
"uploadError"
:on-error=
"uploadError"
:before-upload=
"beforeUpload"
:before-upload=
"beforeUpload"
/>
/>
<QuillEditor
<Editor
class=
"editor"
editor-id=
"wxEditor"
v-model=
"content"
ref=
"quillEditorRef"
ref=
"quillEditorRef"
:
options=
"editorOptions
"
:
modelValue=
"content
"
@
change=
"
onEditorChange($event
)"
@
change=
"
(editor) => onEditorChange(editor.getText()
)"
/>
/>
</div>
</div>
</div>
</div>
</
template
>
</
template
>
<
style
>
<
style
></
style
>
.editor
{
line-height
:
normal
!important
;
height
:
500px
;
}
.ql-snow
.ql-tooltip
[
data-mode
=
'link'
]
::before
{
content
:
'请输入链接地址:'
;
}
.ql-snow
.ql-tooltip.ql-editing
a
.ql-action
::after
{
border-right
:
0
;
content
:
'保存'
;
padding-right
:
0
;
}
.ql-snow
.ql-tooltip
[
data-mode
=
'video'
]
::before
{
content
:
'请输入视频地址:'
;
}
.ql-snow
.ql-picker.ql-size
.ql-picker-label
::before
,
.ql-snow
.ql-picker.ql-size
.ql-picker-item
::before
{
content
:
'14px'
;
}
.ql-snow
.ql-picker.ql-size
.ql-picker-label
[
data-value
=
'small'
]
::before
,
.ql-snow
.ql-picker.ql-size
.ql-picker-item
[
data-value
=
'small'
]
::before
{
content
:
'10px'
;
}
.ql-snow
.ql-picker.ql-size
.ql-picker-label
[
data-value
=
'large'
]
::before
,
.ql-snow
.ql-picker.ql-size
.ql-picker-item
[
data-value
=
'large'
]
::before
{
content
:
'18px'
;
}
.ql-snow
.ql-picker.ql-size
.ql-picker-label
[
data-value
=
'huge'
]
::before
,
.ql-snow
.ql-picker.ql-size
.ql-picker-item
[
data-value
=
'huge'
]
::before
{
content
:
'32px'
;
}
.ql-snow
.ql-picker.ql-header
.ql-picker-label
::before
,
.ql-snow
.ql-picker.ql-header
.ql-picker-item
::before
{
content
:
'文本'
;
}
.ql-snow
.ql-picker.ql-header
.ql-picker-label
[
data-value
=
'1'
]
::before
,
.ql-snow
.ql-picker.ql-header
.ql-picker-item
[
data-value
=
'1'
]
::before
{
content
:
'标题1'
;
}
.ql-snow
.ql-picker.ql-header
.ql-picker-label
[
data-value
=
'2'
]
::before
,
.ql-snow
.ql-picker.ql-header
.ql-picker-item
[
data-value
=
'2'
]
::before
{
content
:
'标题2'
;
}
.ql-snow
.ql-picker.ql-header
.ql-picker-label
[
data-value
=
'3'
]
::before
,
.ql-snow
.ql-picker.ql-header
.ql-picker-item
[
data-value
=
'3'
]
::before
{
content
:
'标题3'
;
}
.ql-snow
.ql-picker.ql-header
.ql-picker-label
[
data-value
=
'4'
]
::before
,
.ql-snow
.ql-picker.ql-header
.ql-picker-item
[
data-value
=
'4'
]
::before
{
content
:
'标题4'
;
}
.ql-snow
.ql-picker.ql-header
.ql-picker-label
[
data-value
=
'5'
]
::before
,
.ql-snow
.ql-picker.ql-header
.ql-picker-item
[
data-value
=
'5'
]
::before
{
content
:
'标题5'
;
}
.ql-snow
.ql-picker.ql-header
.ql-picker-label
[
data-value
=
'6'
]
::before
,
.ql-snow
.ql-picker.ql-header
.ql-picker-item
[
data-value
=
'6'
]
::before
{
content
:
'标题6'
;
}
.ql-snow
.ql-picker.ql-font
.ql-picker-label
::before
,
.ql-snow
.ql-picker.ql-font
.ql-picker-item
::before
{
content
:
'标准字体'
;
}
.ql-snow
.ql-picker.ql-font
.ql-picker-label
[
data-value
=
'serif'
]
::before
,
.ql-snow
.ql-picker.ql-font
.ql-picker-item
[
data-value
=
'serif'
]
::before
{
content
:
'衬线字体'
;
}
.ql-snow
.ql-picker.ql-font
.ql-picker-label
[
data-value
=
'monospace'
]
::before
,
.ql-snow
.ql-picker.ql-font
.ql-picker-item
[
data-value
=
'monospace'
]
::before
{
content
:
'等宽字体'
;
}
</
style
>
src/views/mp/draft/index.vue
View file @
df3b381d
...
@@ -3,14 +3,22 @@
...
@@ -3,14 +3,22 @@
<!-- 搜索工作栏 -->
<!-- 搜索工作栏 -->
<ContentWrap>
<ContentWrap>
<!-- TODO @芋艿:调整成 el-form 和 WxAccountSelect -->
<el-form
<WxAccountSelect
@
change=
"accountChanged"
>
class=
"-mb-15px"
<template
#
actions
>
:model=
"queryParams"
ref=
"queryFormRef"
:inline=
"true"
label-width=
"68px"
>
<el-form-item
label=
"公众号"
prop=
"accountId"
>
<WxMpSelect
@
change=
"onAccountChanged"
/>
</el-form-item>
<el-form-item>
<el-button
type=
"primary"
plain
@
click=
"handleAdd"
v-hasPermi=
"['mp:draft:create']"
>
<el-button
type=
"primary"
plain
@
click=
"handleAdd"
v-hasPermi=
"['mp:draft:create']"
>
<Icon
icon=
"ep:plus"
/>
新增
<Icon
icon=
"ep:plus"
/>
新增
</el-button>
</el-button>
</
template
>
</
el-form-item
>
</
WxAccountSelect
>
</
el-form
>
</ContentWrap>
</ContentWrap>
<!-- 列表 -->
<!-- 列表 -->
...
@@ -58,10 +66,8 @@
...
@@ -58,10 +66,8 @@
/>
/>
</ContentWrap>
</ContentWrap>
<!-- TODO @Dhb52:迁移成独立路由 -->
<div
class=
"app-container"
>
<div
class=
"app-container"
>
<!-- 添加或修改草稿对话框 -->
<!-- 添加或修改草稿对话框 -->
<Teleport
to=
"body"
>
<el-dialog
<el-dialog
:title=
"operateMaterial === 'add' ? '新建图文' : '修改图文'"
:title=
"operateMaterial === 'add' ? '新建图文' : '修改图文'"
width=
"80%"
width=
"80%"
...
@@ -133,7 +139,7 @@
...
@@ -133,7 +139,7 @@
<el-button
<el-button
type=
"primary"
type=
"primary"
circle
circle
@
click=
"plusNews(item)
"
@
click=
"plusNews
"
v-if=
"articlesAdd.length < 8 && operateMaterial === 'add'"
v-if=
"articlesAdd.length < 8 && operateMaterial === 'add'"
>
>
<Icon
icon=
"ep:plus"
/>
<Icon
icon=
"ep:plus"
/>
...
@@ -176,7 +182,7 @@
...
@@ -176,7 +182,7 @@
/>
/>
<div
class=
"thumb-but"
>
<div
class=
"thumb-but"
>
<el-upload
<el-upload
:action=
"action
Url"
:action=
"upload
Url"
:headers=
"headers"
:headers=
"headers"
multiple
multiple
:limit=
"1"
:limit=
"1"
...
@@ -200,15 +206,13 @@
...
@@ -200,15 +206,13 @@
</
template
>
</
template
>
</el-upload>
</el-upload>
</div>
</div>
<Teleport
to=
"body"
>
<el-dialog
title=
"选择图片"
v-model=
"dialogImageVisible"
width=
"80%"
append-to-body
>
<el-dialog
title=
"选择图片"
v-model=
"dialogImageVisible"
width=
"80%"
>
<WxMaterialSelect
<WxMaterialSelect
ref=
"materialSelectRef"
ref=
"materialSelectRef"
:objData=
"{ type: 'image', accountId: queryParams.accountId }"
:objData=
"{ type: 'image', accountId: queryParams.accountId }"
@
select-material=
"selectMaterial"
@
select-material=
"selectMaterial"
/>
/>
</el-dialog>
</el-dialog>
</Teleport>
</div>
</div>
<el-input
<el-input
:rows=
"8"
:rows=
"8"
...
@@ -234,38 +238,49 @@
...
@@ -234,38 +238,49 @@
<el-button
type=
"primary"
@
click=
"submitForm"
>
提 交
</el-button>
<el-button
type=
"primary"
@
click=
"submitForm"
>
提 交
</el-button>
</
template
>
</
template
>
</el-dialog>
</el-dialog>
</Teleport>
</div>
</div>
</template>
</template>
<
script
setup
name=
"MpDraft"
>
<
script
setup
lang=
"ts"
name=
"MpDraft"
>
import
WxEditor
from
'@/views/mp/components/wx-editor/WxEditor.vue'
import
WxEditor
from
'@/views/mp/components/wx-editor/WxEditor.vue'
import
WxNews
from
'@/views/mp/components/wx-news/main.vue'
import
WxNews
from
'@/views/mp/components/wx-news/main.vue'
import
WxMaterialSelect
from
'@/views/mp/components/wx-material-select/main.vue'
import
WxMaterialSelect
from
'@/views/mp/components/wx-material-select/main.vue'
import
Wx
AccountSelect
from
'@/views/mp/components/wx-account-select/main
.vue'
import
Wx
MpSelect
from
'@/views/mp/components/WxMpSelect
.vue'
import
{
getAccessToken
}
from
'@/utils/auth'
import
{
getAccessToken
}
from
'@/utils/auth'
import
*
as
MpDraftApi
from
'@/api/mp/draft'
import
*
as
MpDraftApi
from
'@/api/mp/draft'
import
*
as
MpFreePublishApi
from
'@/api/mp/freePublish'
import
*
as
MpFreePublishApi
from
'@/api/mp/freePublish'
import
{
UploadFiles
,
UploadProps
,
UploadRawFile
}
from
'element-plus'
// 可以用改本地数据模拟,避免API调用超限
// 可以用改本地数据模拟,避免API调用超限
// import drafts from './mock'
// import drafts from './mock'
const
message
=
useMessage
()
// 消息
const
message
=
useMessage
()
// 消息
const
loading
=
ref
(
true
)
// 列表的加载中
const
loading
=
ref
(
true
)
// 列表的加载中
const
list
=
ref
<
any
[]
>
([])
// 列表的数据
const
total
=
ref
(
0
)
// 列表的总页数
const
total
=
ref
(
0
)
// 列表的总页数
const
list
=
ref
([])
// 列表的数据
interface
QueryParams
{
const
queryParams
=
reactive
({
pageNo
:
number
pageSize
:
number
accountId
?:
number
}
const
queryParams
:
QueryParams
=
reactive
({
pageNo
:
1
,
pageNo
:
1
,
pageSize
:
10
,
pageSize
:
10
,
accountId
:
undefined
accountId
:
undefined
})
})
// ========== 文件上传 ==========
// ========== 文件上传 ==========
const
materialSelectRef
=
ref
()
const
BASE_URL
=
import
.
meta
.
env
.
VITE_BASE_URL
const
BASE_URL
=
import
.
meta
.
env
.
VITE_BASE_URL
const
actionUrl
=
ref
(
BASE_URL
+
'/admin-api/mp/material/upload-permanent'
)
// 上传永久素材的地址
const
uploadUrl
=
BASE_URL
+
'/admin-api/mp/material/upload-permanent'
// 上传永久素材的地址
const
headers
=
ref
({
Authorization
:
'Bearer '
+
getAccessToken
()
})
// 设置上传的请求头部
const
headers
=
{
Authorization
:
'Bearer '
+
getAccessToken
()
}
// 设置上传的请求头部
const
fileList
=
ref
([])
const
uploadData
=
reactive
({
const
materialSelectRef
=
ref
<
InstanceType
<
typeof
WxMaterialSelect
>
|
null
>
(
null
)
const
fileList
=
ref
<
UploadFiles
>
([])
interface
UploadData
{
type
:
'image'
|
'video'
|
'audio'
accountId
?:
number
}
const
uploadData
:
UploadData
=
reactive
({
type
:
'image'
,
type
:
'image'
,
accountId
:
1
accountId
:
1
})
})
...
@@ -273,34 +288,28 @@ const uploadData = reactive({
...
@@ -273,34 +288,28 @@ const uploadData = reactive({
// ========== 草稿新建 or 修改 ==========
// ========== 草稿新建 or 修改 ==========
const
dialogNewsVisible
=
ref
(
false
)
const
dialogNewsVisible
=
ref
(
false
)
const
addMaterialLoading
=
ref
(
false
)
// 添加草稿的 loading 标识
const
addMaterialLoading
=
ref
(
false
)
// 添加草稿的 loading 标识
const
articlesAdd
=
ref
([])
const
articlesAdd
=
ref
<
any
[]
>
([])
const
isActiveAddNews
=
ref
(
0
)
const
isActiveAddNews
=
ref
(
0
)
const
dialogImageVisible
=
ref
(
false
)
const
dialogImageVisible
=
ref
(
false
)
const
operateMaterial
=
ref
(
'add'
)
const
operateMaterial
=
ref
<
'add'
|
'edit'
>
(
'add'
)
const
articlesMediaId
=
ref
(
''
)
const
articlesMediaId
=
ref
(
''
)
const
hackResetEditor
=
ref
(
false
)
const
hackResetEditor
=
ref
(
false
)
/** 侦听公众号变化 **/
/** 侦听公众号变化 **/
const
accountChanged
=
(
accountId
)
=>
{
const
onAccountChanged
=
(
id
?:
number
)
=>
{
setAccountId
(
accountI
d
)
setAccountId
(
i
d
)
getList
()
getList
()
}
}
// ======================== 列表查询 ========================
// ======================== 列表查询 ========================
/** 设置账号编号 */
/** 设置账号编号 */
const
setAccountId
=
(
accountId
)
=>
{
const
setAccountId
=
(
id
?:
number
)
=>
{
queryParams
.
accountId
=
accountI
d
queryParams
.
accountId
=
i
d
uploadData
.
accountId
=
accountI
d
uploadData
.
accountId
=
i
d
}
}
/** 查询列表 */
/** 查询列表 */
const
getList
=
async
()
=>
{
const
getList
=
async
()
=>
{
// 如果没有选中公众号账号,则进行提示。
if
(
!
queryParams
.
accountId
)
{
message
.
error
(
'未选中公众号,无法查询草稿箱'
)
return
false
}
loading
.
value
=
true
loading
.
value
=
true
try
{
try
{
const
drafts
=
await
MpDraftApi
.
getDraftPage
(
queryParams
)
const
drafts
=
await
MpDraftApi
.
getDraftPage
(
queryParams
)
...
@@ -329,7 +338,7 @@ const handleAdd = () => {
...
@@ -329,7 +338,7 @@ const handleAdd = () => {
}
}
/** 更新按钮操作 */
/** 更新按钮操作 */
const
handleUpdate
=
(
item
)
=>
{
const
handleUpdate
=
(
item
:
any
)
=>
{
resetEditor
()
resetEditor
()
reset
()
reset
()
articlesMediaId
.
value
=
item
.
mediaId
articlesMediaId
.
value
=
item
.
mediaId
...
@@ -340,39 +349,30 @@ const handleUpdate = (item) => {
...
@@ -340,39 +349,30 @@ const handleUpdate = (item) => {
}
}
/** 提交按钮 */
/** 提交按钮 */
const
submitForm
=
()
=>
{
const
submitForm
=
async
()
=>
{
// TODO @Dhb52: 参考别的模块写法,改成 await 方式
addMaterialLoading
.
value
=
true
addMaterialLoading
.
value
=
true
try
{
if
(
operateMaterial
.
value
===
'add'
)
{
if
(
operateMaterial
.
value
===
'add'
)
{
MpDraftApi
.
createDraft
(
queryParams
.
accountId
,
articlesAdd
.
value
)
await
MpDraftApi
.
createDraft
(
queryParams
.
accountId
,
articlesAdd
.
value
)
.
then
(()
=>
{
message
.
notifySuccess
(
'新增成功'
)
message
.
notifySuccess
(
'新增成功'
)
dialogNewsVisible
.
value
=
false
getList
()
})
.
finally
(()
=>
{
addMaterialLoading
.
value
=
false
})
}
else
{
}
else
{
MpDraftApi
.
updateDraft
(
queryParams
.
accountId
,
articlesMediaId
.
value
,
articlesAdd
.
value
)
await
MpDraftApi
.
updateDraft
(
queryParams
.
accountId
,
articlesMediaId
.
value
,
articlesAdd
.
value
)
.
then
(()
=>
{
message
.
notifySuccess
(
'更新成功'
)
message
.
notifySuccess
(
'更新成功'
)
}
}
finally
{
dialogNewsVisible
.
value
=
false
dialogNewsVisible
.
value
=
false
getList
()
})
.
finally
(()
=>
{
addMaterialLoading
.
value
=
false
addMaterialLoading
.
value
=
false
}
)
getList
(
)
}
}
}
}
// 关闭弹窗
// 关闭弹窗
const
dialogNewsClose
=
async
(
done
)
=>
{
const
dialogNewsClose
=
async
(
onDone
:
()
=>
{}
)
=>
{
try
{
try
{
await
message
.
confirm
(
'修改内容可能还未保存,确定关闭吗?'
)
await
message
.
confirm
(
'修改内容可能还未保存,确定关闭吗?'
)
reset
()
reset
()
resetEditor
()
resetEditor
()
d
one
()
onD
one
()
}
catch
{}
}
catch
{}
}
}
...
@@ -391,7 +391,7 @@ const resetEditor = () => {
...
@@ -391,7 +391,7 @@ const resetEditor = () => {
}
}
// 将图文向下移动
// 将图文向下移动
const
downNews
=
(
index
)
=>
{
const
downNews
=
(
index
:
number
)
=>
{
let
temp
=
articlesAdd
.
value
[
index
]
let
temp
=
articlesAdd
.
value
[
index
]
articlesAdd
.
value
[
index
]
=
articlesAdd
.
value
[
index
+
1
]
articlesAdd
.
value
[
index
]
=
articlesAdd
.
value
[
index
+
1
]
articlesAdd
.
value
[
index
+
1
]
=
temp
articlesAdd
.
value
[
index
+
1
]
=
temp
...
@@ -407,13 +407,13 @@ const upNews = (index) => {
...
@@ -407,13 +407,13 @@ const upNews = (index) => {
}
}
// 选中指定 index 的图文
// 选中指定 index 的图文
const
activeNews
=
(
index
)
=>
{
const
activeNews
=
(
index
:
number
)
=>
{
resetEditor
()
resetEditor
()
isActiveAddNews
.
value
=
index
isActiveAddNews
.
value
=
index
}
}
// 删除指定 index 的图文
// 删除指定 index 的图文
const
minusNews
=
async
(
index
)
=>
{
const
minusNews
=
async
(
index
:
number
)
=>
{
try
{
try
{
await
message
.
confirm
(
'确定删除该图文吗?'
)
await
message
.
confirm
(
'确定删除该图文吗?'
)
articlesAdd
.
value
.
splice
(
index
,
1
)
articlesAdd
.
value
.
splice
(
index
,
1
)
...
@@ -446,20 +446,17 @@ const buildEmptyArticle = () => {
...
@@ -446,20 +446,17 @@ const buildEmptyArticle = () => {
}
}
// ======================== 文件上传 ========================
// ======================== 文件上传 ========================
const
beforeThumbImageUpload
=
(
f
ile
)
=>
{
const
beforeThumbImageUpload
:
UploadProps
[
'beforeUpload'
]
=
(
rawFile
:
UploadRawF
ile
)
=>
{
addMaterialLoading
.
value
=
true
addMaterialLoading
.
value
=
true
const
isType
=
const
isType
=
[
'image/jpeg'
,
'image/png'
,
'image/gif'
,
'image/bmp'
,
'image/jpg'
].
includes
(
file
.
type
===
'image/jpeg'
||
rawFile
.
type
file
.
type
===
'image/png'
||
)
file
.
type
===
'image/gif'
||
file
.
type
===
'image/bmp'
||
file
.
type
===
'image/jpg'
if
(
!
isType
)
{
if
(
!
isType
)
{
message
.
error
(
'上传图片格式不对!'
)
message
.
error
(
'上传图片格式不对!'
)
addMaterialLoading
.
value
=
false
addMaterialLoading
.
value
=
false
return
false
return
false
}
}
const
isLt
=
f
ile
.
size
/
1024
/
1024
<
2
const
isLt
=
rawF
ile
.
size
/
1024
/
1024
<
2
if
(
!
isLt
)
{
if
(
!
isLt
)
{
message
.
error
(
'上传图片大小不能超过 2M!'
)
message
.
error
(
'上传图片大小不能超过 2M!'
)
addMaterialLoading
.
value
=
false
addMaterialLoading
.
value
=
false
...
@@ -469,7 +466,7 @@ const beforeThumbImageUpload = (file) => {
...
@@ -469,7 +466,7 @@ const beforeThumbImageUpload = (file) => {
return
true
return
true
}
}
const
handleUploadSuccess
=
(
response
,
file
,
fileList
)
=>
{
const
handleUploadSuccess
:
UploadProps
[
'onSuccess'
]
=
(
response
:
any
)
=>
{
addMaterialLoading
.
value
=
false
addMaterialLoading
.
value
=
false
if
(
response
.
code
!==
0
)
{
if
(
response
.
code
!==
0
)
{
message
.
error
(
'上传出错:'
+
response
.
msg
)
message
.
error
(
'上传出错:'
+
response
.
msg
)
...
@@ -485,7 +482,7 @@ const handleUploadSuccess = (response, file, fileList) => {
...
@@ -485,7 +482,7 @@ const handleUploadSuccess = (response, file, fileList) => {
}
}
// 选择 or 上传完素材,设置回草稿
// 选择 or 上传完素材,设置回草稿
const
selectMaterial
=
(
item
)
=>
{
const
selectMaterial
=
(
item
:
any
)
=>
{
dialogImageVisible
.
value
=
false
dialogImageVisible
.
value
=
false
articlesAdd
.
value
[
isActiveAddNews
.
value
].
thumbMediaId
=
item
.
mediaId
articlesAdd
.
value
[
isActiveAddNews
.
value
].
thumbMediaId
=
item
.
mediaId
articlesAdd
.
value
[
isActiveAddNews
.
value
].
thumbUrl
=
item
.
url
articlesAdd
.
value
[
isActiveAddNews
.
value
].
thumbUrl
=
item
.
url
...
@@ -494,14 +491,10 @@ const selectMaterial = (item) => {
...
@@ -494,14 +491,10 @@ const selectMaterial = (item) => {
// 打开素材选择
// 打开素材选择
const
openMaterial
=
()
=>
{
const
openMaterial
=
()
=>
{
dialogImageVisible
.
value
=
true
dialogImageVisible
.
value
=
true
try
{
materialSelectRef
.
value
.
queryParams
.
accountId
=
queryParams
.
accountId
// 强制设置下 accountId,避免二次查询不对
materialSelectRef
.
value
.
handleQuery
()
// 刷新列表,失败也无所谓
}
catch
(
e
)
{}
}
}
// ======================== 草稿箱发布 ========================
// ======================== 草稿箱发布 ========================
const
handlePublish
=
async
(
item
)
=>
{
const
handlePublish
=
async
(
item
:
any
)
=>
{
const
accountId
=
queryParams
.
accountId
const
accountId
=
queryParams
.
accountId
const
mediaId
=
item
.
mediaId
const
mediaId
=
item
.
mediaId
const
content
=
const
content
=
...
@@ -510,19 +503,19 @@ const handlePublish = async (item) => {
...
@@ -510,19 +503,19 @@ const handlePublish = async (item) => {
await
message
.
confirm
(
content
)
await
message
.
confirm
(
content
)
await
MpFreePublishApi
.
submitFreePublish
(
accountId
,
mediaId
)
await
MpFreePublishApi
.
submitFreePublish
(
accountId
,
mediaId
)
message
.
notifySuccess
(
'发布成功'
)
message
.
notifySuccess
(
'发布成功'
)
await
getList
()
getList
()
}
catch
{}
}
catch
{}
}
}
/** 删除按钮操作 */
/** 删除按钮操作 */
const
handleDelete
=
async
(
item
)
=>
{
const
handleDelete
=
async
(
item
:
any
)
=>
{
const
accountId
=
queryParams
.
accountId
const
accountId
=
queryParams
.
accountId
const
mediaId
=
item
.
mediaId
const
mediaId
=
item
.
mediaId
try
{
try
{
await
message
.
confirm
(
'此操作将永久删除该草稿, 是否继续?'
)
await
message
.
confirm
(
'此操作将永久删除该草稿, 是否继续?'
)
await
MpDraftApi
.
deleteDraft
(
accountId
,
mediaId
)
await
MpDraftApi
.
deleteDraft
(
accountId
,
mediaId
)
message
.
notifySuccess
(
'删除成功'
)
message
.
notifySuccess
(
'删除成功'
)
await
getList
()
getList
()
}
catch
{}
}
catch
{}
}
}
</
script
>
</
script
>
...
...
src/views/mp/freePublish/index.vue
View file @
df3b381d
...
@@ -3,8 +3,17 @@
...
@@ -3,8 +3,17 @@
<!-- 搜索工作栏 -->
<!-- 搜索工作栏 -->
<ContentWrap>
<ContentWrap>
<!-- TODO @芋艿:调整成 el-form 和 WxAccountSelect -->
<el-form
<WxAccountSelect
@
change=
"(accountId) => accountChanged(accountId)"
/>
class=
"-mb-15px"
:model=
"queryParams"
ref=
"queryFormRef"
:inline=
"true"
label-width=
"68px"
>
<el-form-item
label=
"公众号"
prop=
"accountId"
>
<WxMpSelect
@
change=
"onAccountChanged"
/>
</el-form-item>
</el-form>
</ContentWrap>
</ContentWrap>
<!-- 列表 -->
<!-- 列表 -->
...
@@ -39,26 +48,32 @@
...
@@ -39,26 +48,32 @@
</ContentWrap>
</ContentWrap>
</
template
>
</
template
>
<
script
setup
name=
"MpFreePublish"
>
<
script
lang=
"ts"
setup
name=
"MpFreePublish"
>
import
*
as
FreePublishApi
from
'@/api/mp/freePublish'
import
*
as
FreePublishApi
from
'@/api/mp/freePublish'
import
WxNews
from
'@/views/mp/components/wx-news/main.vue'
import
WxNews
from
'@/views/mp/components/wx-news/main.vue'
import
Wx
AccountSelect
from
'@/views/mp/components/wx-account-select/main
.vue'
import
Wx
MpSelect
from
'@/views/mp/components/WxMpSelect
.vue'
const
message
=
useMessage
()
// 消息弹窗
const
message
=
useMessage
()
// 消息弹窗
const
{
t
}
=
useI18n
()
// 国际化
const
{
t
}
=
useI18n
()
// 国际化
const
loading
=
ref
(
true
)
// 列表的加载中
const
loading
=
ref
(
true
)
// 列表的加载中
const
total
=
ref
(
0
)
// 列表的总页数
const
total
=
ref
(
0
)
// 列表的总页数
const
list
=
ref
([])
// 列表的数据
const
list
=
ref
<
any
[]
>
([])
// 列表的数据
const
queryParams
=
reactive
({
interface
QueryParams
{
pageNo
:
number
pageSize
:
number
accountId
?:
number
}
const
queryParams
:
QueryParams
=
reactive
({
pageNo
:
1
,
pageNo
:
1
,
pageSize
:
10
,
pageSize
:
10
,
accountId
:
undefined
accountId
:
undefined
})
})
/** 侦听公众号变化 **/
/** 侦听公众号变化 **/
const
accountChanged
=
(
accountI
d
)
=>
{
const
onAccountChanged
=
(
id
:
number
|
undefine
d
)
=>
{
queryParams
.
accountId
=
accountI
d
queryParams
.
accountId
=
i
d
getList
()
getList
()
}
}
...
@@ -75,7 +90,7 @@ const getList = async () => {
...
@@ -75,7 +90,7 @@ const getList = async () => {
}
}
/** 删除按钮操作 */
/** 删除按钮操作 */
const
handleDelete
=
async
(
item
)
=>
{
const
handleDelete
=
async
(
item
:
any
)
=>
{
try
{
try
{
// 删除的二次确认
// 删除的二次确认
await
message
.
delConfirm
(
'删除后用户将无法访问此页面,确定删除?'
)
await
message
.
delConfirm
(
'删除后用户将无法访问此页面,确定删除?'
)
...
...
src/views/mp/material/index.vue
View file @
df3b381d
...
@@ -4,13 +4,13 @@
...
@@ -4,13 +4,13 @@
<ContentWrap>
<ContentWrap>
<el-form
class=
"-mb-15px"
:inline=
"true"
label-width=
"68px"
>
<el-form
class=
"-mb-15px"
:inline=
"true"
label-width=
"68px"
>
<el-form-item
label=
"公众号"
prop=
"accountId"
>
<el-form-item
label=
"公众号"
prop=
"accountId"
>
<WxMpSelect
@
change=
"
accountChange
"
/>
<WxMpSelect
@
change=
"
onAccountChanged
"
/>
</el-form-item>
</el-form-item>
</el-form>
</el-form>
</ContentWrap>
</ContentWrap>
<ContentWrap>
<ContentWrap>
<el-tabs
v-model=
"type"
@
tab-change=
"
handle
TabChange"
>
<el-tabs
v-model=
"type"
@
tab-change=
"
on
TabChange"
>
<!-- tab 1:图片 -->
<!-- tab 1:图片 -->
<el-tab-pane
name=
"image"
>
<el-tab-pane
name=
"image"
>
<template
#
label
>
<template
#
label
>
...
@@ -93,7 +93,7 @@
...
@@ -93,7 +93,7 @@
<el-table-column
label=
"文件名"
align=
"center"
prop=
"name"
/>
<el-table-column
label=
"文件名"
align=
"center"
prop=
"name"
/>
<el-table-column
label=
"语音"
align=
"center"
>
<el-table-column
label=
"语音"
align=
"center"
>
<
template
#
default=
"scope"
>
<
template
#
default=
"scope"
>
<WxVoicePlayer
:url=
"scope.row.url"
/>
<WxVoicePlayer
v-if=
"scope.row.url"
:url=
"scope.row.url"
/>
</
template
>
</
template
>
</el-table-column>
</el-table-column>
<el-table-column
<el-table-column
...
@@ -188,10 +188,8 @@
...
@@ -188,10 +188,8 @@
</el-row>
</el-row>
</el-form>
</el-form>
<
template
#
footer
>
<
template
#
footer
>
<!--
<span
class=
"dialog-footer"
>
-->
<el-button
@
click=
"cancelVideo"
>
取 消
</el-button>
<el-button
@
click=
"cancelVideo"
>
取 消
</el-button>
<el-button
type=
"primary"
@
click=
"submitVideo"
>
提 交
</el-button>
<el-button
type=
"primary"
@
click=
"submitVideo"
>
提 交
</el-button>
<!--
</span>
-->
</
template
>
</
template
>
</el-dialog>
</el-dialog>
...
@@ -203,7 +201,7 @@
...
@@ -203,7 +201,7 @@
<el-table-column
label=
"介绍"
align=
"center"
prop=
"introduction"
/>
<el-table-column
label=
"介绍"
align=
"center"
prop=
"introduction"
/>
<el-table-column
label=
"视频"
align=
"center"
>
<el-table-column
label=
"视频"
align=
"center"
>
<
template
#
default=
"scope"
>
<
template
#
default=
"scope"
>
<WxVideoPlayer
:url=
"scope.row.url"
/>
<WxVideoPlayer
v-if=
"scope.row.url"
:url=
"scope.row.url"
/>
</
template
>
</
template
>
</el-table-column>
</el-table-column>
<el-table-column
<el-table-column
...
@@ -284,9 +282,9 @@ const type = ref<MatertialType>('image')
...
@@ -284,9 +282,9 @@ const type = ref<MatertialType>('image')
// 遮罩层
// 遮罩层
const
loading
=
ref
(
false
)
const
loading
=
ref
(
false
)
// 总条数
// 总条数
const
total
=
ref
(
0
)
// 数据列表
// 数据列表
const
list
=
ref
([])
const
list
=
ref
<
any
[]
>
([])
const
total
=
ref
(
0
)
// 查询参数
// 查询参数
interface
QueryParams
{
interface
QueryParams
{
pageNo
:
number
pageNo
:
number
...
@@ -319,8 +317,8 @@ const dialogVideoVisible = ref(false)
...
@@ -319,8 +317,8 @@ const dialogVideoVisible = ref(false)
const
addMaterialLoading
=
ref
(
false
)
const
addMaterialLoading
=
ref
(
false
)
/** 侦听公众号变化 **/
/** 侦听公众号变化 **/
const
accountChange
=
(
accountId
:
number
|
undefined
)
=>
{
const
onAccountChanged
=
(
id
?:
number
)
=>
{
queryParams
.
accountId
=
accountI
d
queryParams
.
accountId
=
i
d
getList
()
getList
()
}
}
...
@@ -346,7 +344,7 @@ const handleQuery = () => {
...
@@ -346,7 +344,7 @@ const handleQuery = () => {
getList
()
getList
()
}
}
const
handle
TabChange
=
(
tabName
:
TabPaneName
)
=>
{
const
on
TabChange
=
(
tabName
:
TabPaneName
)
=>
{
// 设置 type
// 设置 type
uploadData
.
type
=
tabName
as
MatertialType
uploadData
.
type
=
tabName
as
MatertialType
...
@@ -359,54 +357,49 @@ const handleTabChange = (tabName: TabPaneName) => {
...
@@ -359,54 +357,49 @@ const handleTabChange = (tabName: TabPaneName) => {
}
}
// ======================== 文件上传 ========================
// ======================== 文件上传 ========================
const
beforeImageUpload
:
UploadProps
[
'beforeUpload'
]
=
(
rawFile
:
UploadRawFile
)
=>
{
const
beforeUpload
=
(
rawFile
:
UploadRawFile
,
category
:
'image'
|
'audio'
|
'video'
):
boolean
=>
{
const
isType
=
[
'image/jpeg'
,
'image/png'
,
'image/gif'
,
'image/bmp'
,
'image/jpg'
].
includes
(
let
allowTypes
:
string
[]
=
[]
rawFile
.
type
let
maxSizeMB
=
0
)
let
name
=
''
if
(
!
isType
)
{
message
.
error
(
'上传图片格式不对!'
)
switch
(
category
)
{
return
false
case
'image'
:
allowTypes
=
[
'image/jpeg'
,
'image/png'
,
'image/gif'
,
'image/bmp'
,
'image/jpg'
]
maxSizeMB
=
2
name
=
'图片'
break
case
'audio'
:
allowTypes
=
[
'audio/mp3'
,
'audio/mpeg'
,
'audio/wma'
,
'audio/wav'
,
'audio/amr'
]
maxSizeMB
=
2
name
=
'图片'
break
case
'video'
:
allowTypes
=
[
'video/mp4'
]
maxSizeMB
=
10
name
=
'视频'
}
}
const
isLt
=
rawFile
.
size
/
1024
/
1024
<
2
if
(
!
isLt
)
{
message
.
error
(
'上传图片大小不能超过 2M!'
)
return
false
}
loading
.
value
=
true
return
true
}
const
beforeVoiceUpload
:
UploadProps
[
'beforeUpload'
]
=
(
rawFile
:
UploadRawFile
)
=>
{
if
(
!
allowTypes
.
includes
(
rawFile
.
type
))
{
const
isType
=
[
'audio/mp3'
,
'audio/wma'
,
'audio/wav'
,
'audio/amr'
].
includes
(
file
.
type
)
message
.
error
(
`上传
${
name
}
格式不对!`
)
const
isLt
=
rawFile
.
size
/
1024
/
1024
<
2
if
(
!
isType
)
{
message
.
error
(
'上传语音格式不对!'
)
return
false
return
false
}
}
if
(
!
isLt
)
{
// 校验大小
message
.
error
(
'上传语音大小不能超过 2M!'
)
if
(
rawFile
.
size
/
1024
/
1024
>
maxSizeMB
)
{
message
.
error
(
`上传
${
name
}
大小不能超过
${
maxSizeMB
}
M!`
)
return
false
return
false
}
}
loading
.
value
=
true
loading
.
value
=
true
return
true
return
true
}
}
const
beforeVideoUpload
:
UploadProps
[
'beforeUpload'
]
=
(
rawFile
:
UploadRawFile
)
=>
{
const
beforeImageUpload
:
UploadProps
[
'beforeUpload'
]
=
(
rawFile
:
UploadRawFile
)
=>
const
isType
=
rawFile
.
type
===
'video/mp4'
beforeUpload
(
rawFile
,
'image'
)
if
(
!
isType
)
{
message
.
error
(
'上传视频格式不对!'
)
return
false
}
const
isLt
=
rawFile
.
size
/
1024
/
1024
<
10
const
beforeVoiceUpload
:
UploadProps
[
'beforeUpload'
]
=
(
rawFile
:
UploadRawFile
)
=>
if
(
!
isLt
)
{
beforeUpload
(
rawFile
,
'audio'
)
message
.
error
(
'上传视频大小不能超过 10M!'
)
return
false
}
addMaterialLoading
.
value
=
true
const
beforeVideoUpload
:
UploadProps
[
'beforeUpload'
]
=
(
rawFile
:
UploadRawFile
)
=>
return
true
beforeUpload
(
rawFile
,
'video'
)
}
const
handleUploadSuccess
:
UploadProps
[
'onSuccess'
]
=
(
response
:
any
)
=>
{
const
handleUploadSuccess
:
UploadProps
[
'onSuccess'
]
=
(
response
:
any
)
=>
{
loading
.
value
=
false
loading
.
value
=
false
...
@@ -441,6 +434,7 @@ const submitVideo = () => {
...
@@ -441,6 +434,7 @@ const submitVideo = () => {
})
})
}
}
// 弹出 video 新建的表单
const
handleAddVideo
=
()
=>
{
const
handleAddVideo
=
()
=>
{
resetVideo
()
resetVideo
()
dialogVideoVisible
.
value
=
true
dialogVideoVisible
.
value
=
true
...
...
src/views/mp/menu/index.vue
View file @
df3b381d
...
@@ -2,8 +2,11 @@
...
@@ -2,8 +2,11 @@
<doc-alert
title=
"公众号菜单"
url=
"https://doc.iocoder.cn/mp/menu/"
/>
<doc-alert
title=
"公众号菜单"
url=
"https://doc.iocoder.cn/mp/menu/"
/>
<!-- 搜索工作栏 -->
<!-- 搜索工作栏 -->
<ContentWrap>
<ContentWrap>
<!-- TODO @芋艿:调整成 el-form 和 WxAccountSelect -->
<el-form
class=
"-mb-15px"
ref=
"queryFormRef"
:inline=
"true"
label-width=
"68px"
>
<WxAccountSelect
@
change=
"accountChanged"
/>
<el-form-item
label=
"公众号"
prop=
"accountId"
>
<WxMpSelect
@
change=
"onAccountChanged"
/>
</el-form-item>
</el-form>
</ContentWrap>
</ContentWrap>
<!-- 列表 -->
<!-- 列表 -->
...
@@ -12,7 +15,7 @@
...
@@ -12,7 +15,7 @@
<!--左边配置菜单-->
<!--左边配置菜单-->
<div
class=
"left"
>
<div
class=
"left"
>
<div
class=
"weixin-hd"
>
<div
class=
"weixin-hd"
>
<div
class=
"weixin-title"
>
{{
n
ame
}}
</div>
<div
class=
"weixin-title"
>
{{
accountN
ame
}}
</div>
</div>
</div>
<div
class=
"weixin-menu menu_main clearfix"
>
<div
class=
"weixin-menu menu_main clearfix"
>
<div
class=
"menu_bottom"
v-for=
"(item, i) of menuList"
:key=
"i"
>
<div
class=
"menu_bottom"
v-for=
"(item, i) of menuList"
:key=
"i"
>
...
@@ -68,7 +71,7 @@
...
@@ -68,7 +71,7 @@
<div
v-if=
"showRightFlag"
class=
"right"
>
<div
v-if=
"showRightFlag"
class=
"right"
>
<div
class=
"configure_page"
>
<div
class=
"configure_page"
>
<div
class=
"delete_btn"
>
<div
class=
"delete_btn"
>
<el-button
size=
"small"
type=
"danger"
@
click=
"handleDeleteMenu
(tempObj)
"
>
<el-button
size=
"small"
type=
"danger"
@
click=
"handleDeleteMenu"
>
删除当前菜单
<Icon
icon=
"ep:delete"
/>
删除当前菜单
<Icon
icon=
"ep:delete"
/>
</el-button>
</el-button>
</div>
</div>
...
@@ -155,7 +158,7 @@
...
@@ -155,7 +158,7 @@
<div
v-else
>
<div
v-else
>
<el-row
justify=
"center"
>
<el-row
justify=
"center"
>
<el-col
:span=
"24"
style=
"text-align: center"
>
<el-col
:span=
"24"
style=
"text-align: center"
>
<el-button
type=
"success"
@
click=
"
openMaterial
"
>
<el-button
type=
"success"
@
click=
"
dialogNewsVisible = true
"
>
素材库选择
<Icon
icon=
"ep:circle-check"
/>
素材库选择
<Icon
icon=
"ep:circle-check"
/>
</el-button>
</el-button>
</el-col>
</el-col>
...
@@ -185,24 +188,26 @@
...
@@ -185,24 +188,26 @@
</div>
</div>
</ContentWrap>
</ContentWrap>
</
template
>
</
template
>
<
script
setup
name=
"MpMenu"
>
<
script
lang=
"ts"
setup
name=
"MpMenu"
>
import
{
handleTree
}
from
'@/utils/tree'
import
WxReplySelect
from
'@/views/mp/components/wx-reply/main.vue'
import
WxReplySelect
from
'@/views/mp/components/wx-reply/main.vue'
import
WxNews
from
'@/views/mp/components/wx-news/main.vue'
import
WxNews
from
'@/views/mp/components/wx-news/main.vue'
import
WxMaterialSelect
from
'@/views/mp/components/wx-material-select/main.vue'
import
WxMaterialSelect
from
'@/views/mp/components/wx-material-select/main.vue'
import
Wx
AccountSelect
from
'@/views/mp/components/wx-account-select/main
.vue'
import
Wx
MpSelect
from
'@/views/mp/components/WxMpSelect
.vue'
import
*
as
MpMenuApi
from
'@/api/mp/menu'
import
*
as
MpMenuApi
from
'@/api/mp/menu'
import
{
handleTree
}
from
'@/utils/tree'
import
menuOptions
from
'./menuOptions'
import
menuOptions
from
'./menuOptions'
const
message
=
useMessage
()
// 消息
const
message
=
useMessage
()
// 消息
// ======================== 列表查询 ========================
// ======================== 列表查询 ========================
const
loading
=
ref
(
true
)
// 遮罩层
const
loading
=
ref
(
false
)
// 遮罩层
const
accountId
=
ref
(
undefined
)
// 公众号Id
const
accountId
=
ref
<
number
|
undefined
>
()
const
menuList
=
ref
({
children
:
[]
})
const
accountName
=
ref
<
string
|
undefined
>
(
''
)
const
menuList
=
ref
<
any
>
({
children
:
[]
})
// ======================== 菜单操作 ========================
// ======================== 菜单操作 ========================
const
isActive
=
ref
(
-
1
)
// 一级菜单点中样式
const
isActive
=
ref
(
-
1
)
// 一级菜单点中样式
const
isSubMenuActive
=
ref
(
-
1
)
// 一级菜单点中样式
const
isSubMenuActive
=
ref
<
string
|
number
>
(
-
1
)
// 一级菜单点中样式
const
isSubMenuFlag
=
ref
(
-
1
)
// 二级菜单显示标志
const
isSubMenuFlag
=
ref
(
-
1
)
// 二级菜单显示标志
// ======================== 菜单编辑 ========================
// ======================== 菜单编辑 ========================
...
@@ -210,15 +215,16 @@ const showRightFlag = ref(false) // 右边配置显示默认详情还是配置
...
@@ -210,15 +215,16 @@ const showRightFlag = ref(false) // 右边配置显示默认详情还是配置
const
nameMaxLength
=
ref
(
0
)
// 菜单名称最大长度;1 级是 4 字符;2 级是 7 字符;
const
nameMaxLength
=
ref
(
0
)
// 菜单名称最大长度;1 级是 4 字符;2 级是 7 字符;
const
showConfigureContent
=
ref
(
true
)
// 是否展示配置内容;如果有子菜单,就不显示配置内容
const
showConfigureContent
=
ref
(
true
)
// 是否展示配置内容;如果有子菜单,就不显示配置内容
const
hackResetWxReplySelect
=
ref
(
false
)
// 重置 WxReplySelect 组件
const
hackResetWxReplySelect
=
ref
(
false
)
// 重置 WxReplySelect 组件
const
tempObj
=
ref
({})
// 右边临时变量,作为中间值牵引关系
const
tempObj
=
ref
<
any
>
({})
// 右边临时变量,作为中间值牵引关系
// 一些临时值放在这里进行判断,如果放在 tempObj,由于引用关系,menu 也会多了多余的参数
// 一些临时值放在这里进行判断,如果放在 tempObj,由于引用关系,menu 也会多了多余的参数
const
tempSelfObj
=
ref
({})
const
tempSelfObj
=
ref
<
any
>
({})
const
dialogNewsVisible
=
ref
(
false
)
// 跳转图文时的素材选择弹窗
const
dialogNewsVisible
=
ref
(
false
)
// 跳转图文时的素材选择弹窗
/** 侦听公众号变化 **/
/** 侦听公众号变化 **/
const
accountChanged
=
(
id
)
=>
{
const
onAccountChanged
=
(
id
?:
number
,
name
?:
string
)
=>
{
accountId
.
value
=
id
accountId
.
value
=
id
accountName
.
value
=
name
getList
()
getList
()
}
}
...
@@ -241,10 +247,10 @@ const handleQuery = () => {
...
@@ -241,10 +247,10 @@ const handleQuery = () => {
}
}
// 将后端返回的 menuList,转换成前端的 menuList
// 将后端返回的 menuList,转换成前端的 menuList
const
convertMenuList
=
(
list
)
=>
{
const
convertMenuList
=
(
list
:
any
[]
)
=>
{
if
(
!
list
)
return
[]
if
(
!
list
)
return
[]
const
menuList
=
[]
const
result
:
any
[]
=
[]
list
.
forEach
((
item
)
=>
{
list
.
forEach
((
item
)
=>
{
const
menu
=
{
const
menu
=
{
...
item
...
item
...
@@ -271,9 +277,9 @@ const convertMenuList = (list) => {
...
@@ -271,9 +277,9 @@ const convertMenuList = (list) => {
hqMusicUrl
:
item
.
replyHqMusicUrl
hqMusicUrl
:
item
.
replyHqMusicUrl
}
}
}
}
menuLis
t
.
push
(
menu
)
resul
t
.
push
(
menu
)
})
})
return
menuLis
t
return
resul
t
}
}
// 重置表单,清空表单数据
// 重置表单,清空表单数据
...
@@ -286,7 +292,7 @@ const resetForm = () => {
...
@@ -286,7 +292,7 @@ const resetForm = () => {
// 菜单编辑
// 菜单编辑
showRightFlag
.
value
=
false
showRightFlag
.
value
=
false
nameMaxLength
.
value
=
0
nameMaxLength
.
value
=
0
showConfigureContent
.
value
=
0
showConfigureContent
.
value
=
false
hackResetWxReplySelect
.
value
=
false
hackResetWxReplySelect
.
value
=
false
tempObj
.
value
=
{}
tempObj
.
value
=
{}
tempSelfObj
.
value
=
{}
tempSelfObj
.
value
=
{}
...
@@ -295,7 +301,7 @@ const resetForm = () => {
...
@@ -295,7 +301,7 @@ const resetForm = () => {
// ======================== 菜单操作 ========================
// ======================== 菜单操作 ========================
// 一级菜单点击事件
// 一级菜单点击事件
const
menuClick
=
(
i
,
item
)
=>
{
const
menuClick
=
(
i
:
number
,
item
:
any
)
=>
{
// 右侧的表单相关
// 右侧的表单相关
resetEditor
()
resetEditor
()
showRightFlag
.
value
=
true
// 右边菜单
showRightFlag
.
value
=
true
// 右边菜单
...
@@ -312,11 +318,10 @@ const menuClick = (i, item) => {
...
@@ -312,11 +318,10 @@ const menuClick = (i, item) => {
}
}
// 二级菜单点击事件
// 二级菜单点击事件
const
subMenuClick
=
(
subItem
,
index
,
k
)
=>
{
const
subMenuClick
=
(
subItem
:
any
,
index
:
number
,
k
:
number
)
=>
{
// 右侧的表单相关
// 右侧的表单相关
resetEditor
()
resetEditor
()
showRightFlag
.
value
=
true
// 右边菜单
showRightFlag
.
value
=
true
// 右边菜单
console
.
log
(
subItem
)
tempObj
.
value
=
subItem
// 将点击的数据放到临时变量,对象有引用作用
tempObj
.
value
=
subItem
// 将点击的数据放到临时变量,对象有引用作用
tempSelfObj
.
value
.
grand
=
'2'
// 表示二级菜单
tempSelfObj
.
value
.
grand
=
'2'
// 表示二级菜单
tempSelfObj
.
value
.
index
=
index
// 表示一级菜单索引
tempSelfObj
.
value
.
index
=
index
// 表示一级菜单索引
...
@@ -331,7 +336,7 @@ const subMenuClick = (subItem, index, k) => {
...
@@ -331,7 +336,7 @@ const subMenuClick = (subItem, index, k) => {
// 添加横向一级菜单
// 添加横向一级菜单
const
addMenu
=
()
=>
{
const
addMenu
=
()
=>
{
const
menuKeyLength
=
menuList
.
value
.
length
const
menuKeyLength
:
number
=
menuList
.
value
.
length
const
addButton
=
{
const
addButton
=
{
name
:
'菜单名称'
,
name
:
'菜单名称'
,
children
:
[],
children
:
[],
...
@@ -342,10 +347,10 @@ const addMenu = () => {
...
@@ -342,10 +347,10 @@ const addMenu = () => {
}
}
}
}
menuList
.
value
[
menuKeyLength
]
=
addButton
menuList
.
value
[
menuKeyLength
]
=
addButton
menuClick
(
menuKeyLength
.
value
-
1
,
addButton
)
menuClick
(
menuKeyLength
-
1
,
addButton
)
}
}
// 添加横向二级菜单;item 表示要操作的父菜单
// 添加横向二级菜单;item 表示要操作的父菜单
const
addSubMenu
=
(
i
,
item
)
=>
{
const
addSubMenu
=
(
i
:
number
,
item
:
any
)
=>
{
// 清空父菜单的属性,因为它只需要 name 属性即可
// 清空父菜单的属性,因为它只需要 name 属性即可
if
(
!
item
.
children
||
item
.
children
.
length
<=
0
)
{
if
(
!
item
.
children
||
item
.
children
.
length
<=
0
)
{
item
.
children
=
[]
item
.
children
=
[]
...
@@ -361,8 +366,8 @@ const addSubMenu = (i, item) => {
...
@@ -361,8 +366,8 @@ const addSubMenu = (i, item) => {
showConfigureContent
.
value
=
false
showConfigureContent
.
value
=
false
}
}
le
t
subMenuKeyLength
=
item
.
children
.
length
// 获取二级菜单key长度
cons
t
subMenuKeyLength
=
item
.
children
.
length
// 获取二级菜单key长度
le
t
addButton
=
{
cons
t
addButton
=
{
name
:
'子菜单名称'
,
name
:
'子菜单名称'
,
reply
:
{
reply
:
{
// 用于存储回复内容
// 用于存储回复内容
...
@@ -399,7 +404,7 @@ const handleDeleteMenu = async () => {
...
@@ -399,7 +404,7 @@ const handleDeleteMenu = async () => {
// ======================== 菜单编辑 ========================
// ======================== 菜单编辑 ========================
const
handleSave
=
async
()
=>
{
const
handleSave
=
async
()
=>
{
try
{
try
{
await
message
.
confirm
(
'确定要
删除
吗?'
)
await
message
.
confirm
(
'确定要
保存
吗?'
)
loading
.
value
=
true
loading
.
value
=
true
await
MpMenuApi
.
saveMenu
(
accountId
.
value
,
convertMenuFormList
())
await
MpMenuApi
.
saveMenu
(
accountId
.
value
,
convertMenuFormList
())
getList
()
getList
()
...
@@ -413,7 +418,6 @@ const handleSave = async () => {
...
@@ -413,7 +418,6 @@ const handleSave = async () => {
const
resetEditor
=
()
=>
{
const
resetEditor
=
()
=>
{
hackResetWxReplySelect
.
value
=
false
// 销毁组件
hackResetWxReplySelect
.
value
=
false
// 销毁组件
nextTick
(()
=>
{
nextTick
(()
=>
{
console
.
log
(
'nextTick'
)
hackResetWxReplySelect
.
value
=
true
// 重建组件
hackResetWxReplySelect
.
value
=
true
// 重建组件
})
})
}
}
...
@@ -432,9 +436,9 @@ const handleDelete = async () => {
...
@@ -432,9 +436,9 @@ const handleDelete = async () => {
// 将前端的 menuList,转换成后端接收的 menuList
// 将前端的 menuList,转换成后端接收的 menuList
const
convertMenuFormList
=
()
=>
{
const
convertMenuFormList
=
()
=>
{
const
result
=
[]
const
result
:
any
[]
=
[]
menuList
.
value
.
forEach
((
item
)
=>
{
menuList
.
value
.
forEach
((
item
)
=>
{
le
t
menu
=
convertMenuForm
(
item
)
cons
t
menu
=
convertMenuForm
(
item
)
result
.
push
(
menu
)
result
.
push
(
menu
)
// 处理子菜单
// 处理子菜单
...
@@ -450,7 +454,7 @@ const convertMenuFormList = () => {
...
@@ -450,7 +454,7 @@ const convertMenuFormList = () => {
}
}
// 将前端的 menu,转换成后端接收的 menu
// 将前端的 menu,转换成后端接收的 menu
const
convertMenuForm
=
(
menu
)
=>
{
const
convertMenuForm
=
(
menu
:
any
)
=>
{
let
result
=
{
let
result
=
{
...
menu
,
...
menu
,
children
:
undefined
,
// 不处理子节点
children
:
undefined
,
// 不处理子节点
...
@@ -473,11 +477,7 @@ const convertMenuForm = (menu) => {
...
@@ -473,11 +477,7 @@ const convertMenuForm = (menu) => {
}
}
// ======================== 菜单编辑(素材选择) ========================
// ======================== 菜单编辑(素材选择) ========================
const
openMaterial
=
()
=>
{
const
selectMaterial
=
(
item
:
any
)
=>
{
dialogNewsVisible
.
value
=
true
}
const
selectMaterial
=
(
item
)
=>
{
const
articleId
=
item
.
articleId
const
articleId
=
item
.
articleId
const
articles
=
item
.
content
.
newsItem
const
articles
=
item
.
content
.
newsItem
// 提示,针对多图文
// 提示,针对多图文
...
...
src/views/mp/tag/TagForm.vue
View file @
df3b381d
...
@@ -19,24 +19,30 @@
...
@@ -19,24 +19,30 @@
</template>
</template>
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
*
as
MpTagApi
from
'@/api/mp/tag'
import
*
as
MpTagApi
from
'@/api/mp/tag'
import
{
FormInstance
,
FormRules
}
from
'element-plus'
const
{
t
}
=
useI18n
()
// 国际化
const
{
t
}
=
useI18n
()
// 国际化
const
message
=
useMessage
()
// 消息弹窗
const
message
=
useMessage
()
// 消息弹窗
const
dialogVisible
=
ref
(
false
)
// 弹窗的是否展示
const
dialogVisible
=
ref
(
false
)
// 弹窗的是否展示
const
dialogTitle
=
ref
(
''
)
// 弹窗的标题
const
dialogTitle
=
ref
(
''
)
// 弹窗的标题
const
formLoading
=
ref
(
false
)
// 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
const
formLoading
=
ref
(
false
)
// 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
const
formType
=
ref
(
''
)
// 表单的类型:create - 新增;update - 修改
const
formType
=
ref
<
'create'
|
'update'
|
''
>
(
''
)
// 表单的类型:create - 新增;update - 修改
const
formData
=
ref
({
const
formData
=
ref
({
accountId
:
-
1
,
accountId
:
-
1
,
name
:
''
name
:
''
})
})
const
formRules
=
reactive
(
{
const
formRules
:
FormRules
=
{
name
:
[{
required
:
true
,
message
:
'请输入标签名称'
,
trigger
:
'blur'
}]
name
:
[{
required
:
true
,
message
:
'请输入标签名称'
,
trigger
:
'blur'
}]
})
}
const
formRef
=
ref
()
// 表单 Ref
const
formRef
=
ref
<
FormInstance
|
null
>
(
null
)
// 表单 Ref
const
emit
=
defineEmits
<
{
(
e
:
'success'
):
void
}
>
()
/** 打开弹窗 */
/** 打开弹窗 */
const
open
=
async
(
type
:
string
,
accountId
:
number
,
id
?:
number
)
=>
{
const
open
=
async
(
type
:
'create'
|
'update'
,
accountId
:
number
,
id
?:
number
)
=>
{
dialogVisible
.
value
=
true
dialogVisible
.
value
=
true
dialogTitle
.
value
=
t
(
'action.'
+
type
)
dialogTitle
.
value
=
t
(
'action.'
+
type
)
formType
.
value
=
type
formType
.
value
=
type
...
@@ -55,11 +61,10 @@ const open = async (type: string, accountId: number, id?: number) => {
...
@@ -55,11 +61,10 @@ const open = async (type: string, accountId: number, id?: number) => {
defineExpose
({
open
})
// 提供 open 方法,用于打开弹窗
defineExpose
({
open
})
// 提供 open 方法,用于打开弹窗
/** 提交表单 */
/** 提交表单 */
const
emit
=
defineEmits
([
'success'
])
// 定义 success 事件,用于操作成功后的回调
const
submitForm
=
async
()
=>
{
const
submitForm
=
async
()
=>
{
// 校验表单
// 校验表单
if
(
!
formRef
)
return
if
(
!
formRef
)
return
const
valid
=
await
formRef
.
value
.
validate
()
const
valid
=
await
formRef
.
value
?
.
validate
()
if
(
!
valid
)
return
if
(
!
valid
)
return
// 提交请求
// 提交请求
formLoading
.
value
=
true
formLoading
.
value
=
true
...
...
src/views/mp/tag/index.vue
View file @
df3b381d
...
@@ -3,17 +3,25 @@
...
@@ -3,17 +3,25 @@
<!-- 搜索工作栏 -->
<!-- 搜索工作栏 -->
<ContentWrap>
<ContentWrap>
<!-- TODO @芋艿:调整成 el-form 和 WxAccountSelect -->
<el-form
<WxAccountSelect
@
change=
"accountChanged"
>
class=
"-mb-15px"
<template
#
actions
>
:model=
"queryParams"
ref=
"queryFormRef"
:inline=
"true"
label-width=
"68px"
>
<el-form-item
label=
"公众号"
prop=
"accountId"
>
<WxMpSelect
@
change=
"onAccountChanged"
/>
</el-form-item>
<el-form-item>
<el-button
type=
"primary"
plain
@
click=
"openForm('create')"
v-hasPermi=
"['mp:tag:create']"
>
<el-button
type=
"primary"
plain
@
click=
"openForm('create')"
v-hasPermi=
"['mp:tag:create']"
>
<Icon
icon=
"ep:plus"
class=
"mr-5px"
/>
新增
<Icon
icon=
"ep:plus"
class=
"mr-5px"
/>
新增
</el-button>
</el-button>
<el-button
type=
"success"
plain
@
click=
"handleSync"
v-hasPermi=
"['mp:tag:sync']"
>
<el-button
type=
"success"
plain
@
click=
"handleSync"
v-hasPermi=
"['mp:tag:sync']"
>
<Icon
icon=
"ep:refresh"
class=
"mr-5px"
/>
同步
<Icon
icon=
"ep:refresh"
class=
"mr-5px"
/>
同步
</el-button>
</el-button>
</
template
>
</
el-form-item
>
</
WxAccountSelect
>
</
el-form
>
</ContentWrap>
</ContentWrap>
<!-- 列表 -->
<!-- 列表 -->
...
@@ -63,26 +71,35 @@
...
@@ -63,26 +71,35 @@
<TagForm
ref=
"formRef"
@
success=
"getList"
/>
<TagForm
ref=
"formRef"
@
success=
"getList"
/>
</template>
</template>
<
script
setup
lang=
"ts"
name=
"MpTag"
>
<
script
setup
lang=
"ts"
name=
"MpTag"
>
import
{
dateFormatter
}
from
'@/utils/formatTime'
import
WxAccountSelect
from
'@/views/mp/components/wx-account-select/main.vue'
import
*
as
MpTagApi
from
'@/api/mp/tag'
import
*
as
MpTagApi
from
'@/api/mp/tag'
import
TagForm
from
'./TagForm.vue'
import
TagForm
from
'./TagForm.vue'
import
WxMpSelect
from
'@/views/mp/components/WxMpSelect.vue'
import
{
dateFormatter
}
from
'@/utils/formatTime'
const
message
=
useMessage
()
// 消息弹窗
const
message
=
useMessage
()
// 消息弹窗
const
{
t
}
=
useI18n
()
// 国际化
const
{
t
}
=
useI18n
()
// 国际化
const
loading
=
ref
(
true
)
// 列表的加载中
const
loading
=
ref
(
true
)
// 列表的加载中
const
total
=
ref
(
0
)
// 列表的总页数
const
total
=
ref
(
0
)
// 列表的总页数
const
list
=
ref
([])
// 列表的数据
const
list
=
ref
<
any
>
([])
// 列表的数据
const
queryParams
=
reactive
({
interface
QueryParams
{
pageNo
:
number
pageSize
:
number
accountId
?:
number
}
const
queryParams
:
QueryParams
=
reactive
({
pageNo
:
1
,
pageNo
:
1
,
pageSize
:
10
,
pageSize
:
10
,
accountId
:
undefined
accountId
:
undefined
})
})
const
formRef
=
ref
<
InstanceType
<
typeof
TagForm
>
|
null
>
(
null
)
/** 侦听公众号变化 **/
/** 侦听公众号变化 **/
const
accountChanged
=
(
accountId
)
=>
{
const
onAccountChanged
=
(
id
?:
number
)
=>
{
queryParams
.
pageNo
=
1
queryParams
.
pageNo
=
1
queryParams
.
accountId
=
accountI
d
queryParams
.
accountId
=
i
d
getList
()
getList
()
}
}
...
@@ -99,9 +116,8 @@ const getList = async () => {
...
@@ -99,9 +116,8 @@ const getList = async () => {
}
}
/** 添加/修改操作 */
/** 添加/修改操作 */
const
formRef
=
ref
()
const
openForm
=
(
type
:
string
,
id
?:
number
)
=>
{
const
openForm
=
(
type
:
string
,
id
?:
number
)
=>
{
formRef
.
value
.
open
(
type
,
queryParams
.
accountId
,
id
)
formRef
.
value
?.
open
(
type
,
queryParams
.
accountId
as
number
,
id
)
}
}
/** 删除按钮操作 */
/** 删除按钮操作 */
...
@@ -121,8 +137,7 @@ const handleDelete = async (id: number) => {
...
@@ -121,8 +137,7 @@ const handleDelete = async (id: number) => {
const
handleSync
=
async
()
=>
{
const
handleSync
=
async
()
=>
{
try
{
try
{
await
message
.
confirm
(
'是否确认同步标签?'
)
await
message
.
confirm
(
'是否确认同步标签?'
)
// @ts-ignore
await
MpTagApi
.
syncTag
(
queryParams
.
accountId
as
number
)
await
MpTagApi
.
syncTag
(
queryParams
.
accountId
)
message
.
success
(
'同步标签成功'
)
message
.
success
(
'同步标签成功'
)
await
getList
()
await
getList
()
}
catch
{}
}
catch
{}
...
...
src/views/mp/user/index.vue
View file @
df3b381d
...
@@ -3,14 +3,42 @@
...
@@ -3,14 +3,42 @@
<!-- 搜索工作栏 -->
<!-- 搜索工作栏 -->
<ContentWrap>
<ContentWrap>
<!-- TODO @芋艿:调整成 el-form 和 WxAccountSelect -->
<el-form
<WxAccountSelect
@
change=
"(accountId) => accountChanged(accountId)"
>
class=
"-mb-15px"
<template
#
actions
>
:model=
"queryParams"
ref=
"queryFormRef"
:inline=
"true"
label-width=
"68px"
>
<el-form-item
label=
"公众号"
prop=
"accountId"
>
<WxMpSelect
@
change=
"onAccountChanged"
/>
</el-form-item>
<el-form-item
label=
"用户标识"
prop=
"openid"
>
<el-input
v-model=
"queryParams.openid"
placeholder=
"请输入用户标识"
clearable
@
keyup
.
enter=
"handleQuery"
class=
"!w-240px"
/>
</el-form-item>
<el-form-item
label=
"昵称"
prop=
"nickname"
>
<el-input
v-model=
"queryParams.nickname"
placeholder=
"请输入昵称"
clearable
@
keyup
.
enter=
"handleQuery"
class=
"!w-240px"
/>
</el-form-item>
<el-form-item>
<el-button
@
click=
"handleQuery"
>
<Icon
icon=
"ep:search"
/>
搜索
</el-button>
<el-button
@
click=
"resetQuery"
>
<Icon
icon=
"ep:refresh"
/>
重置
</el-button>
<el-button
type=
"success"
plain
@
click=
"handleSync"
v-hasPermi=
"['mp:user:sync']"
>
<el-button
type=
"success"
plain
@
click=
"handleSync"
v-hasPermi=
"['mp:user:sync']"
>
<Icon
icon=
"ep:refresh"
class=
"mr-5px"
/>
同步
<Icon
icon=
"ep:refresh"
class=
"mr-5px"
/>
同步
</el-button>
</el-button>
</
template
>
</
el-form-item
>
</
WxAccountSelect
>
</
el-form
>
</ContentWrap>
</ContentWrap>
<!-- 列表 -->
<!-- 列表 -->
...
@@ -66,25 +94,37 @@
...
@@ -66,25 +94,37 @@
<UserForm
ref=
"formRef"
@
success=
"getList"
/>
<UserForm
ref=
"formRef"
@
success=
"getList"
/>
</template>
</template>
<
script
lang=
"ts"
setup
name=
"MpUser"
>
<
script
lang=
"ts"
setup
name=
"MpUser"
>
import
WxAccountSelect
from
'@/views/mp/components/wx-account-select/main.vue'
import
{
dateFormatter
}
from
'@/utils/formatTime'
import
{
dateFormatter
}
from
'@/utils/formatTime'
import
*
as
MpUserApi
from
'@/api/mp/user'
import
*
as
MpUserApi
from
'@/api/mp/user'
import
*
as
MpTagApi
from
'@/api/mp/tag'
import
*
as
MpTagApi
from
'@/api/mp/tag'
import
WxMpSelect
from
'@/views/mp/components/WxMpSelect.vue'
import
{
FormInstance
}
from
'element-plus'
import
UserForm
from
'./UserForm.vue'
import
UserForm
from
'./UserForm.vue'
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
<
any
[]
>
([])
// 列表的数据
const
queryParams
=
reactive
({
interface
QueryParams
{
pageNo
:
number
pageSize
:
number
accountId
?:
number
openid
:
string
|
null
nickname
:
string
|
null
}
const
queryParams
:
QueryParams
=
reactive
({
pageNo
:
1
,
pageNo
:
1
,
pageSize
:
10
,
pageSize
:
10
,
accountId
:
null
,
accountId
:
undefined
,
openid
:
null
,
openid
:
null
,
nickname
:
null
nickname
:
null
})
})
const
tagList
=
ref
([])
// 公众号标签列表
const
tagList
=
ref
<
any
[]
>
([])
// 公众号标签列表
const
queryFormRef
=
ref
<
FormInstance
|
null
>
(
null
)
// 搜索的表单
const
formRef
=
ref
<
InstanceType
<
typeof
UserForm
>
|
null
>
(
null
)
/** 初始化 */
/** 初始化 */
onMounted
(
async
()
=>
{
onMounted
(
async
()
=>
{
...
@@ -92,9 +132,9 @@ onMounted(async () => {
...
@@ -92,9 +132,9 @@ onMounted(async () => {
})
})
/** 侦听公众号变化 **/
/** 侦听公众号变化 **/
const
accountChanged
=
(
accountId
)
=>
{
const
onAccountChanged
=
(
id
?:
number
)
=>
{
queryParams
.
pageNo
=
1
queryParams
.
pageNo
=
1
queryParams
.
accountId
=
accountI
d
queryParams
.
accountId
=
i
d
getList
()
getList
()
}
}
...
@@ -110,20 +150,32 @@ const getList = async () => {
...
@@ -110,20 +150,32 @@ const getList = async () => {
}
}
}
}
/** 搜索按钮操作 */
const
handleQuery
=
()
=>
{
queryParams
.
pageNo
=
1
getList
()
}
/** 重置按钮操作 */
const
resetQuery
=
()
=>
{
const
accountId
=
queryParams
.
accountId
queryFormRef
.
value
?.
resetFields
()
queryParams
.
accountId
=
accountId
handleQuery
()
}
/** 添加/修改操作 */
/** 添加/修改操作 */
const
formRef
=
ref
()
const
openForm
=
(
id
:
number
)
=>
{
const
openForm
=
(
id
:
number
)
=>
{
formRef
.
value
.
open
(
id
)
formRef
.
value
?
.
open
(
id
)
}
}
/** 同步标签 */
/** 同步标签 */
const
handleSync
=
async
()
=>
{
const
handleSync
=
async
()
=>
{
const
accountId
=
queryParams
.
accountId
try
{
try
{
await
message
.
confirm
(
'是否确认同步粉丝?'
)
await
message
.
confirm
(
'是否确认同步粉丝?'
)
await
MpUserApi
.
syncUser
(
accountId
)
await
MpUserApi
.
syncUser
(
queryParams
.
accountId
)
message
.
success
(
'开始从微信公众号同步粉丝信息,同步需要一段时间,建议稍后再查询'
)
message
.
success
(
'开始从微信公众号同步粉丝信息,同步需要一段时间,建议稍后再查询'
)
await
getList
()
getList
()
}
catch
{}
}
catch
{}
}
}
</
script
>
</
script
>
src/views/pay/order/orderForm.vue
0 → 100644
View file @
df3b381d
<
template
>
<Dialog
:title=
"dialogTitle"
v-model=
"dialogVisible"
width=
"50%"
>
<el-descriptions
:column=
"2"
label-class-name=
"desc-label"
>
<el-descriptions-item
label=
"商户名称"
>
{{
orderDetail
.
merchantName
}}
</el-descriptions-item>
<el-descriptions-item
label=
"应用名称"
>
{{
orderDetail
.
appName
}}
</el-descriptions-item>
<el-descriptions-item
label=
"商品名称"
>
{{
orderDetail
.
subject
}}
</el-descriptions-item>
</el-descriptions>
<el-divider
/>
<el-descriptions
:column=
"2"
label-class-name=
"desc-label"
>
<el-descriptions-item
label=
"商户订单号"
>
<el-tag
size=
"small"
>
{{
orderDetail
.
merchantOrderId
}}
</el-tag>
</el-descriptions-item>
<el-descriptions-item
label=
"渠道订单号"
>
<el-tag
class=
"tag-purple"
size=
"small"
>
{{
orderDetail
.
channelOrderNo
}}
</el-tag>
</el-descriptions-item>
<el-descriptions-item
label=
"支付订单号"
>
<el-tag
v-if=
"orderDetail.payOrderExtension.no !== ''"
class=
"tag-pink"
size=
"small"
>
{{
orderDetail
.
payOrderExtension
.
no
}}
</el-tag>
</el-descriptions-item>
<el-descriptions-item
label=
"金额"
>
<el-tag
type=
"success"
size=
"small"
>
{{
parseFloat
(
orderDetail
.
amount
/
100
,
2
)
}}
</el-tag>
</el-descriptions-item>
<el-descriptions-item
label=
"手续费"
>
<el-tag
type=
"warning"
size=
"small"
>
{{
parseFloat
(
orderDetail
.
channelFeeAmount
/
100
,
2
)
}}
</el-tag>
</el-descriptions-item>
<el-descriptions-item
label=
"手续费比例"
>
{{
parseFloat
(
orderDetail
.
channelFeeRate
/
100
,
2
)
}}
%
</el-descriptions-item>
<el-descriptions-item
label=
"支付状态"
>
<dict-tag
:type=
"DICT_TYPE.PAY_ORDER_STATUS"
:value=
"orderDetail.status"
/>
</el-descriptions-item>
<el-descriptions-item
label=
"回调状态"
>
<dict-tag
:type=
"DICT_TYPE.PAY_ORDER_NOTIFY_STATUS"
:value=
"orderDetail.notifyStatus"
/>
</el-descriptions-item>
<el-descriptions-item
label=
"回调地址"
>
{{
orderDetail
.
notifyUrl
}}
</el-descriptions-item>
<el-descriptions-item
label=
"创建时间"
:formatter=
"dateFormatter"
>
{{
formatDate
(
orderDetail
.
createTime
)
}}
</el-descriptions-item>
<el-descriptions-item
label=
"支付时间"
:formatter=
"dateFormatter"
>
{{
formatDate
(
orderDetail
.
successTime
)
}}
</el-descriptions-item>
<el-descriptions-item
label=
"失效时间"
:formatter=
"dateFormatter"
>
{{
formatDate
(
orderDetail
.
expireTime
)
}}
</el-descriptions-item>
<el-descriptions-item
label=
"通知时间"
:formatter=
"dateFormatter"
>
{{
formatDate
(
orderDetail
.
notifyTime
)
}}
</el-descriptions-item>
</el-descriptions>
<el-divider
/>
<el-descriptions
:column=
"2"
label-class-name=
"desc-label"
>
<el-descriptions-item
label=
"支付渠道"
>
{{
orderDetail
.
channelCodeName
}}
</el-descriptions-item>
<el-descriptions-item
label=
"支付IP"
>
{{
orderDetail
.
userIp
}}
</el-descriptions-item>
<el-descriptions-item
label=
"退款状态"
>
<dict-tag
:type=
"DICT_TYPE.PAY_ORDER_REFUND_STATUS"
:value=
"orderDetail.refundStatus"
/>
</el-descriptions-item>
<el-descriptions-item
label=
"退款次数"
>
{{
orderDetail
.
refundTimes
}}
</el-descriptions-item>
<el-descriptions-item
label=
"退款金额"
>
<el-tag
type=
"warning"
>
{{
parseFloat
(
orderDetail
.
refundAmount
/
100
,
2
)
}}
</el-tag>
</el-descriptions-item>
</el-descriptions>
<el-divider
/>
<el-descriptions
:column=
"1"
label-class-name=
"desc-label"
direction=
"vertical"
border
>
<el-descriptions-item
label=
"商品描述"
>
{{
orderDetail
.
body
}}
</el-descriptions-item>
<el-descriptions-item
label=
"支付通道异步回调内容"
>
{{
orderDetail
.
payOrderExtension
.
channelNotifyData
}}
</el-descriptions-item>
</el-descriptions>
</Dialog>
</
template
>
<
script
setup
lang=
"ts"
name=
"orderForm"
>
import
{
DICT_TYPE
}
from
'@/utils/dict'
import
*
as
OrderApi
from
'@/api/pay/order'
import
{
dateFormatter
,
formatDate
}
from
'@/utils/formatTime'
const
{
t
}
=
useI18n
()
// 国际化
// const message = useMessage() // 消息弹窗
const
dialogVisible
=
ref
(
false
)
// 弹窗的是否展示
const
dialogTitle
=
ref
(
'订单详情'
)
// 弹窗的标题
const
formLoading
=
ref
(
false
)
// 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
const
defaultOrderDetail
=
{
merchantName
:
''
,
appName
:
''
,
channelCodeName
:
''
,
subject
:
''
,
merchantOrderId
:
null
,
channelOrderNo
:
''
,
body
:
''
,
amount
:
null
,
channelFeeRate
:
null
,
channelFeeAmount
:
null
,
userIp
:
''
,
status
:
null
,
notifyUrl
:
''
,
notifyStatus
:
null
,
refundStatus
:
null
,
refundTimes
:
''
,
refundAmount
:
null
,
createTime
:
''
,
successTime
:
''
,
notifyTime
:
''
,
expireTime
:
''
,
payOrderExtension
:
{
channelNotifyData
:
''
,
no
:
''
}
}
const
orderDetail
=
ref
(
JSON
.
parse
(
JSON
.
stringify
(
defaultOrderDetail
)))
/** 打开弹窗 */
const
open
=
async
(
id
?:
number
)
=>
{
dialogVisible
.
value
=
true
dialogTitle
.
value
=
t
(
'action.preview'
)
// 修改时,设置数据
if
(
id
)
{
formLoading
.
value
=
true
try
{
orderDetail
.
value
=
await
OrderApi
.
getOrderDetail
(
id
)
if
(
orderDetail
.
value
.
payOrderExtension
===
null
)
{
orderDetail
.
value
.
payOrderExtension
=
Object
.
assign
(
defaultOrderDetail
.
payOrderExtension
,
{}
)
}
}
finally
{
formLoading
.
value
=
false
}
}
}
defineExpose
({
open
})
// 提供 open 方法,用于打开弹窗
</
script
>
<
style
>
.tag-purple
{
color
:
#722ed1
;
background
:
#f9f0ff
;
border-color
:
#d3adf7
;
}
.tag-pink
{
color
:
#eb2f96
;
background
:
#fff0f6
;
border-color
:
#ffadd2
;
}
</
style
>
src/views/pay/refund/refundForm.vue
0 → 100644
View file @
df3b381d
<
template
>
<Dialog
:title=
"dialogTitle"
v-model=
"dialogVisible"
width=
"50%"
>
<el-descriptions
:column=
"2"
label-class-name=
"desc-label"
>
<el-descriptions-item
label=
"商户名称"
>
{{
refundDetail
.
merchantName
}}
</el-descriptions-item>
<el-descriptions-item
label=
"应用名称"
>
{{
refundDetail
.
appName
}}
</el-descriptions-item>
<el-descriptions-item
label=
"商品名称"
>
{{
refundDetail
.
subject
}}
</el-descriptions-item>
</el-descriptions>
<el-divider
/>
<el-descriptions
:column=
"2"
label-class-name=
"desc-label"
>
<el-descriptions-item
label=
"商户退款单号"
>
<el-tag
size=
"small"
>
{{
refundDetail
.
merchantRefundNo
}}
</el-tag>
</el-descriptions-item>
<el-descriptions-item
label=
"商户订单号"
>
{{
refundDetail
.
merchantOrderId
}}
</el-descriptions-item>
<el-descriptions-item
label=
"交易订单号"
>
{{
refundDetail
.
tradeNo
}}
</el-descriptions-item>
</el-descriptions>
<el-divider
/>
<el-descriptions
:column=
"2"
label-class-name=
"desc-label"
>
<el-descriptions-item
label=
"支付金额"
>
{{
parseFloat
(
refundDetail
.
payAmount
/
100
).
toFixed
(
2
)
}}
</el-descriptions-item>
<el-descriptions-item
label=
"退款金额"
size=
"small"
>
<el-tag
class=
"tag-purple"
size=
"small"
>
{{
parseFloat
(
refundDetail
.
refundAmount
/
100
).
toFixed
(
2
)
}}
</el-tag>
</el-descriptions-item>
<el-descriptions-item
label=
"退款类型"
>
<dict-tag
:type=
"DICT_TYPE.PAY_REFUND_ORDER_TYPE"
:value=
"refundDetail.type"
/>
</el-descriptions-item>
<el-descriptions-item
label=
"退款状态"
>
<dict-tag
:type=
"DICT_TYPE.PAY_REFUND_ORDER_STATUS"
:value=
"refundDetail.status"
/>
</el-descriptions-item>
<el-descriptions-item
label=
"创建时间"
>
{{
formatDate
(
refundDetail
.
createTime
)
}}
</el-descriptions-item>
<el-descriptions-item
label=
"退款成功时间"
>
{{
formatDate
(
refundDetail
.
successTime
)
}}
</el-descriptions-item>
<el-descriptions-item
label=
"退款失效时间"
>
{{
formatDate
(
refundDetail
.
expireTime
)
}}
</el-descriptions-item>
<el-descriptions-item
label=
"更新时间"
>
{{
formatDate
(
refundDetail
.
updateTime
)
}}
</el-descriptions-item>
</el-descriptions>
<el-divider
/>
<el-descriptions
:column=
"2"
label-class-name=
"desc-label"
>
<el-descriptions-item
label=
"支付渠道"
>
{{
refundDetail
.
channelCodeName
}}
</el-descriptions-item>
<el-descriptions-item
label=
"支付IP"
size=
"small"
>
{{
refundDetail
.
userIp
}}
</el-descriptions-item>
<el-descriptions-item
label=
"回调地址"
>
{{
refundDetail
.
notifyUrl
}}
</el-descriptions-item>
<el-descriptions-item
label=
"回调状态"
>
<dict-tag
:type=
"DICT_TYPE.PAY_ORDER_NOTIFY_STATUS"
:value=
"refundDetail.notifyStatus"
/>
</el-descriptions-item>
<el-descriptions-item
label=
"回调时间"
>
{{
formatDate
(
refundDetail
.
notifyTime
)
}}
</el-descriptions-item>
</el-descriptions>
<el-divider
/>
<el-descriptions
:column=
"2"
label-class-name=
"desc-label"
>
<el-descriptions-item
label=
"渠道订单号"
>
{{
refundDetail
.
channelOrderNo
}}
</el-descriptions-item>
<el-descriptions-item
label=
"渠道退款单号"
>
{{
refundDetail
.
channelRefundNo
}}
</el-descriptions-item>
<el-descriptions-item
label=
"渠道错误码"
>
{{
refundDetail
.
channelErrorCode
}}
</el-descriptions-item>
<el-descriptions-item
label=
"渠道错误码描述"
>
{{
refundDetail
.
channelErrorMsg
}}
</el-descriptions-item>
</el-descriptions>
<br
/>
<el-descriptions
:column=
"1"
label-class-name=
"desc-label"
direction=
"vertical"
border
>
<el-descriptions-item
label=
"渠道额外参数"
>
{{
refundDetail
.
channelExtras
}}
</el-descriptions-item>
<el-descriptions-item
label=
"退款原因"
>
{{
refundDetail
.
reason
}}
</el-descriptions-item>
</el-descriptions>
</Dialog>
</
template
>
<
script
setup
lang=
"ts"
name=
"refundForm"
>
import
{
DICT_TYPE
}
from
'@/utils/dict'
import
*
as
RefundApi
from
'@/api/pay/refund'
import
{
formatDate
}
from
'@/utils/formatTime'
const
{
t
}
=
useI18n
()
// 国际化
// const message = useMessage() // 消息弹窗
const
dialogVisible
=
ref
(
false
)
// 弹窗的是否展示
const
dialogTitle
=
ref
(
'退款订单详情'
)
// 弹窗的标题
const
formLoading
=
ref
(
false
)
// 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
const
defaultrefundDetail
=
{
id
:
null
,
appId
:
null
,
appName
:
''
,
channelCode
:
''
,
channelCodeName
:
''
,
channelErrorCode
:
''
,
channelErrorMsg
:
''
,
channelExtras
:
''
,
channelId
:
null
,
channelOrderNo
:
''
,
channelRefundNo
:
''
,
createTime
:
null
,
expireTime
:
null
,
merchantId
:
null
,
merchantName
:
''
,
merchantOrderId
:
''
,
merchantRefundNo
:
''
,
notifyStatus
:
null
,
notifyTime
:
null
,
notifyUrl
:
''
,
orderId
:
null
,
payAmount
:
null
,
reason
:
''
,
refundAmount
:
null
,
status
:
null
,
subject
:
''
,
successTime
:
null
,
tradeNo
:
''
,
type
:
null
,
userIp
:
''
}
const
refundDetail
=
ref
(
JSON
.
parse
(
JSON
.
stringify
(
defaultrefundDetail
)))
/** 打开弹窗 */
const
open
=
async
(
id
?:
number
)
=>
{
dialogVisible
.
value
=
true
dialogTitle
.
value
=
t
(
'action.preview'
)
// 修改时,设置数据
if
(
id
)
{
formLoading
.
value
=
true
try
{
refundDetail
.
value
=
await
RefundApi
.
getRefundApi
(
id
)
}
finally
{
formLoading
.
value
=
false
}
}
}
defineExpose
({
open
})
// 提供 open 方法,用于打开弹窗
</
script
>
<
style
>
.tag-purple
{
color
:
#722ed1
;
background
:
#f9f0ff
;
border-color
:
#d3adf7
;
}
</
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