Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
C
company_app
概览
概览
详情
活动
周期分析
版本库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
毛细亚
company_app
Commits
7af060b5
提交
7af060b5
authored
12月 22, 2025
作者:
毛细亚
浏览文件
操作
浏览文件
下载
差异文件
合并分支 '7.2' 到 'release'
7.2 查看合并请求
!49
上级
acf9b56c
dce6c578
隐藏空白字符变更
内嵌
并排
正在显示
13 个修改的文件
包含
1131 行增加
和
184 行删除
+1131
-184
game.js
src/api/game.js
+59
-2
uncheck.svg
src/assets/icon/svg/uncheck.svg
+2
-0
copy.js
src/directive/copy/copy.js
+22
-4
sendGame.vue
src/views/components/quickSendGame/sendGame.vue
+76
-90
SendTransAppGame.vue
...ws/components/quickSendGame/sendGame/SendTransAppGame.vue
+6
-5
SendTransWxGame.vue
...ews/components/quickSendGame/sendGame/SendTransWxGame.vue
+536
-66
selectChannel.vue
...views/components/quickSendGame/sendGame/selectChannel.vue
+0
-1
sendSelectChannel.vue
...s/components/quickSendGame/sendGame/sendSelectChannel.vue
+0
-5
vipTools.vue
src/views/components/quickSendGame/vipTools.vue
+1
-1
roleInfoPanel.vue
src/views/components/roleInfo/roleInfoPanel.vue
+96
-3
skillPersonal.vue
src/views/components/skill/skillPersonal.vue
+0
-6
Info.vue
src/views/userInfo/components/Info.vue
+1
-1
mentorRecord.vue
src/views/userInfo/components/gameInfo/mentorRecord.vue
+332
-0
没有找到文件。
src/api/game.js
浏览文件 @
7af060b5
...
@@ -1537,4 +1537,62 @@ export function teachingVideoVideoListApi(data) {
...
@@ -1537,4 +1537,62 @@ export function teachingVideoVideoListApi(data) {
reject
(
error
)
reject
(
error
)
})
})
})
})
}
}
\ No newline at end of file
// 发送分身包
export
function
memberRegGameCloneLink
(
data
)
{
return
new
Promise
((
resolve
,
reject
)
=>
{
cross_systemRequest
({
system
:
'zhangyou'
,
api
:
'/api/member/memberRegGameCloneLink'
,
params
:
data
}).
then
((
res
)
=>
{
resolve
(
res
)
}).
catch
((
error
)
=>
{
reject
(
error
)
})
})
}
// 带教记录列表
export
function
roleTeachingList
(
data
)
{
return
new
Promise
((
resolve
,
reject
)
=>
{
cross_systemRequest
({
system
:
'zhangyou'
,
api
:
'/api/role/roleTeachingList'
,
params
:
data
}).
then
((
res
)
=>
{
resolve
(
res
)
}).
catch
((
error
)
=>
{
reject
(
error
)
})
})
}
// 新增带教
export
function
roleTeachingAdd
(
data
)
{
return
new
Promise
((
resolve
,
reject
)
=>
{
cross_systemRequest
({
system
:
'zhangyou'
,
api
:
'/api/role/roleTeachingAdd'
,
params
:
data
}).
then
((
res
)
=>
{
resolve
(
res
)
}).
catch
((
error
)
=>
{
reject
(
error
)
})
})
}
// 获取带教次数
export
function
roleTeachingNum
(
data
)
{
return
new
Promise
((
resolve
,
reject
)
=>
{
cross_systemRequest
({
system
:
'zhangyou'
,
api
:
'/api/role/roleTeachingNum'
,
params
:
data
}).
then
((
res
)
=>
{
resolve
(
res
)
}).
catch
((
error
)
=>
{
reject
(
error
)
})
})
}
src/assets/icon/svg/uncheck.svg
0 → 100644
浏览文件 @
7af060b5
<svg
t=
"1765950660083"
class=
"icon"
viewBox=
"0 0 1024 1024"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
p-id=
"5445"
width=
"200"
height=
"200"
><path
d=
"M512 938.666667C276.362667 938.666667 85.333333 747.637333 85.333333 512S276.362667 85.333333 512 85.333333s426.666667 191.029333 426.666667 426.666667-191.029333 426.666667-426.666667 426.666667z m0-64c200.298667 0 362.666667-162.368 362.666667-362.666667S712.298667 149.333333 512 149.333333 149.333333 311.701333 149.333333 512s162.368 362.666667 362.666667 362.666667z"
p-id=
"5446"
></path></svg>
\ No newline at end of file
src/directive/copy/copy.js
浏览文件 @
7af060b5
...
@@ -71,13 +71,31 @@ const copy = {
...
@@ -71,13 +71,31 @@ const copy = {
el
.
__copyIcon
=
copyIcon
el
.
__copyIcon
=
copyIcon
},
},
// 当指令与元素解绑时
// 当指令与元素解绑时
unbind
:
function
(
el
)
{
unbind
:
function
(
el
)
{
// 清理事件监听器和元素
// 清理事件监听器和元素
if
(
el
.
__copyIcon
)
{
if
(
el
.
__copyIcon
)
{
el
.
__copyIcon
.
removeEventListener
(
'click'
,
null
)
try
{
el
.
parentNode
.
removeChild
(
el
.
__copyIcon
)
// 移除事件监听器
delete
el
.
__copyIcon
const
clickHandler
=
el
.
__copyIcon
.
__clickHandler
if
(
clickHandler
)
{
el
.
__copyIcon
.
removeEventListener
(
'click'
,
clickHandler
)
delete
el
.
__copyIcon
.
__clickHandler
}
// 安全地移除图标元素
if
(
el
.
__copyIcon
&&
el
.
__copyIcon
.
parentNode
)
{
el
.
__copyIcon
.
parentNode
.
removeChild
(
el
.
__copyIcon
)
}
else
if
(
el
.
__copyIcon
&&
el
.
__copyIcon
.
remove
)
{
// 如果节点还在DOM中,使用 remove() 方法
el
.
__copyIcon
.
remove
()
}
}
catch
(
error
)
{
// 忽略移除节点时的错误,可能节点已经被移除了
console
.
warn
(
'移除复制图标时出错:'
,
error
)
}
finally
{
delete
el
.
__copyIcon
}
}
}
}
}
}
}
...
...
src/views/components/quickSendGame/sendGame.vue
浏览文件 @
7af060b5
...
@@ -97,6 +97,12 @@
...
@@ -97,6 +97,12 @@
>
>
下载二维码
下载二维码
</p>
</p>
<!-- h5 安卓游戏 IOS游戏 发送分身包 -->
<div
v-if=
"[2].includes(item.game_type)"
>
<p
class=
"sendLink"
@
click=
"sendTransferCloneGame(2,items)"
>
发送分身包-H5
</p>
<p
class=
"sendLink"
@
click=
"sendTransferCloneGame(3,items)"
>
发送分身包-安卓
</p>
<p
class=
"sendLink"
@
click=
"sendTransferCloneGame(4,items)"
>
发送分身包-IOS
</p>
</div>
</div>
</div>
<el-button
<el-button
slot=
"reference"
slot=
"reference"
...
@@ -279,49 +285,24 @@
...
@@ -279,49 +285,24 @@
<p>
{{ items.label + "/" + items.id }}
</p>
<p>
{{ items.label + "/" + items.id }}
</p>
<!--game_type: 1 微信小游戏 2 H5 游戏 3 安卓游戏 4 IOS 游戏 5 抖音小游戏 -->
<!--game_type: 1 微信小游戏 2 H5 游戏 3 安卓游戏 4 IOS 游戏 5 抖音小游戏 -->
<!-- 微信小游戏 安卓游戏 IOS游戏 处理逻辑 -->
<!-- 微信小游戏 安卓游戏 IOS游戏 处理逻辑 -->
<el-popover
<el-popover
v-if=
"items.game_type == 1 || items.game_type == 3 || items.game_type == 4 || items.game_type == 5"
placement=
"top"
trigger=
"click"
>
v-if=
"
<div
v-if=
"items.game_type!=5"
>
items.game_type == 1 ||
<p
class=
"sendLink"
@
click=
"sendChannelGame(items, item)"
>
发送链接/渠道二维码
</p>
items.game_type == 3 ||
<p
class=
"sendLink"
@
click=
"handleGameType(items, item, item.game_type, index)"
>
发送落地页
</p>
items.game_type == 4
"
<div
v-if=
"items.game_type == 1"
>
placement=
"top"
<!-- 发送 H5 安卓分身包 -->
trigger=
"click"
<p
class=
"sendLink"
@
click=
"sendH5CloneGame(items, 'android')"
>
发送H5-安卓分身包
</p>
>
<!-- 发送 H5 IOS 分身包 -->
<p
class=
"sendLink"
@
click=
"sendChannelGame(items, item)"
>
<p
class=
"sendLink"
@
click=
"sendH5CloneGame(items, 'ios')"
>
发送H5-IOS分身包
</p>
发送链接/渠道二维码
</div>
</p>
</div>
<p
<!-- 抖音小游戏发送落地页 -->
class=
"sendLink"
<div
v-else
>
@
click=
"
<p
class=
"sendLink"
@
click=
"handleGameType(items, item, item.game_type, index)"
>
发送落地页
</p>
handleGameType(items, item, item.game_type, index)
</div>
"
<el-button
slot=
"reference"
size=
"mini"
:disabled=
"accountSelect == ''"
>
发送
</el-button>
>
</el-popover>
发送落地页
</p>
<div
v-if=
"items.game_type == 1"
>
<!-- 发送 H5 安卓分身包 -->
<p
class=
"sendLink"
@
click=
"sendH5CloneGame(items, 'android')"
>
发送H5-安卓分身包
</p>
<!-- 发送 H5 IOS 分身包 -->
<p
class=
"sendLink"
@
click=
"sendH5CloneGame(items, 'ios')"
>
发送H5-IOS分身包
</p>
</div>
<el-button
slot=
"reference"
size=
"mini"
:disabled=
"accountSelect == ''"
>
发送
</el-button
>
</el-popover>
<el-button
<el-button
v-else
v-else
size=
"mini"
size=
"mini"
...
@@ -426,6 +407,7 @@ import {
...
@@ -426,6 +407,7 @@ import {
getClonePackageLink
,
getClonePackageLink
,
getLandingPageConfig
,
getLandingPageConfig
,
getMemberTransStatus
,
getMemberTransStatus
,
memberRegGameCloneLink
}
from
"@/api/game"
;
}
from
"@/api/game"
;
import
{
import
{
getRecentSendLog
,
getRecentSendLog
,
...
@@ -492,6 +474,7 @@ export default {
...
@@ -492,6 +474,7 @@ export default {
showSendChannel
:
false
,
showSendChannel
:
false
,
channelInfoList
:
{},
channelInfoList
:
{},
transMemberStatus
:
true
,
transMemberStatus
:
true
,
h5CloneGameInfo
:
{},
qrCodeValue
:
""
,
// 二维码内容
qrCodeValue
:
""
,
// 二维码内容
qrCodeSize
:
200
,
// 二维码大小
qrCodeSize
:
200
,
// 二维码大小
};
};
...
@@ -1035,13 +1018,6 @@ export default {
...
@@ -1035,13 +1018,6 @@ export default {
).
username
;
).
username
;
passwardEncryption
({
member_id
:
this
.
accountSelect
})
passwardEncryption
({
member_id
:
this
.
accountSelect
})
.
then
((
res
)
=>
{
.
then
((
res
)
=>
{
// const list = [
// {
// msgtype: 'text',
// text: { content: `账号:${username} \n密码:${res.data.password}`, key: res.data.key, iv: res.data.iv }
// }
// ]
// this.set_sendSkillMessage(list)
this
.
sendChatMessage
(
this
.
sendChatMessage
(
`账号:
${
username
}
\n密码:
${
res
.
data
.
password
}
`
,
`账号:
${
username
}
\n密码:
${
res
.
data
.
password
}
`
,
"text"
"text"
...
@@ -1053,7 +1029,6 @@ export default {
...
@@ -1053,7 +1029,6 @@ export default {
const
list
=
[
const
list
=
[
{
msgtype
:
"text"
,
text
:
{
content
:
`账号:
${
username
}
`
}
},
{
msgtype
:
"text"
,
text
:
{
content
:
`账号:
${
username
}
`
}
},
];
];
// this.set_sendSkillMessage(list)
this
.
sendChatMessage
(
`账号:
${
username
}
`
,
"text"
);
this
.
sendChatMessage
(
`账号:
${
username
}
`
,
"text"
);
item
.
type
=
1
;
item
.
type
=
1
;
this
.
sendGameLog
(
item
);
this
.
sendGameLog
(
item
);
...
@@ -1094,7 +1069,6 @@ export default {
...
@@ -1094,7 +1069,6 @@ export default {
},
},
},
},
];
];
// this.set_sendSkillMessage(list)
this
.
sendChatMessage
(
this
.
sendChatMessage
(
`
${
str
}${
item
.
url
}
\n账号:
${
username
}
\n密码:
${
res
.
data
.
password
}
`
,
`
${
str
}${
item
.
url
}
\n账号:
${
username
}
\n密码:
${
res
.
data
.
password
}
`
,
"text"
"text"
...
@@ -1110,7 +1084,6 @@ export default {
...
@@ -1110,7 +1084,6 @@ export default {
text
:
{
content
:
`
${
str
}${
item
.
url
}
\n账号:
${
username
}
`
},
text
:
{
content
:
`
${
str
}${
item
.
url
}
\n账号:
${
username
}
`
},
},
},
];
];
// this.set_sendSkillMessage(list)
this
.
sendChatMessage
(
`
${
str
}${
item
.
url
}
\n账号:
${
username
}
`
,
"text"
);
this
.
sendChatMessage
(
`
${
str
}${
item
.
url
}
\n账号:
${
username
}
`
,
"text"
);
this
.
sendGameLog
(
item
);
this
.
sendGameLog
(
item
);
console
.
log
(
err
);
console
.
log
(
err
);
...
@@ -1119,7 +1092,6 @@ export default {
...
@@ -1119,7 +1092,6 @@ export default {
// 发送游戏落地页
// 发送游戏落地页
startSendPage
(
value
)
{
startSendPage
(
value
)
{
console
.
log
(
value
,
"value"
);
console
.
log
(
value
,
"value"
);
// this.set_sendSkillMessage(list)
this
.
getMediaId
(
value
,
"image"
);
this
.
getMediaId
(
value
,
"image"
);
},
},
// 转端发送落地页面
// 转端发送落地页面
...
@@ -1135,6 +1107,53 @@ export default {
...
@@ -1135,6 +1107,53 @@ export default {
);
);
this
.
showSendPage
=
true
;
this
.
showSendPage
=
true
;
},
500
),
},
500
),
// 转端发送游戏分身包 h5 安卓游戏 IOS游戏 发送分身包
async
sendTransferCloneGame
(
type
,
items
)
{
if
(
!
this
.
h5CloneGameInfo
?.
data
?.
h5_download_url
){
this
.
h5CloneGameInfo
=
await
memberRegGameCloneLink
({
member_id
:
this
.
accountSelect
,
game_id
:
items
.
game_id
})
||
{}
}
if
(
this
.
h5CloneGameInfo
?.
status_code
==
1
)
{
// 通过 type 判断 用 switch
switch
(
type
)
{
case
2
:
if
(
!
this
.
h5CloneGameInfo
?.
data
?.
h5_download_url
)
{
this
.
$message
.
warning
(
'H5安卓分身包链接不存在,请联系掌游配置'
)
return
}
break
case
3
:
if
(
!
this
.
h5CloneGameInfo
?.
data
?.
android_download_url
)
{
this
.
$message
.
warning
(
'安卓分身包链接不存在,请联系掌游配置'
)
return
}
break
case
4
:
if
(
!
this
.
h5CloneGameInfo
?.
data
?.
ios_download_url
)
{
this
.
$message
.
warning
(
'IOS分身包链接不存在,请联系掌游配置'
)
return
}
break
default
:
this
.
$message
.
warning
(
'不支持的游戏类型'
)
return
}
let
srt
=
''
switch
(
type
)
{
case
2
:
srt
=
'H5分身包链接: '
+
this
.
h5CloneGameInfo
?.
data
?.
h5_download_url
break
case
3
:
srt
=
'安卓分身包链接: '
+
this
.
h5CloneGameInfo
?.
data
?.
android_download_url
break
case
4
:
srt
=
'IOS分身包链接: '
+
this
.
h5CloneGameInfo
?.
data
?.
ios_download_url
break
}
this
.
sendChatMessage
(
srt
,
"text"
);
}
else
{
this
.
$message
.
warning
(
this
.
h5CloneGameInfo
?.
msg
)
}
},
// 转端发送游戏二维码
// 转端发送游戏二维码
sendDownLoadQrCode
:
throttleStart
(
async
function
(
items
,
type
,
index
)
{
sendDownLoadQrCode
:
throttleStart
(
async
function
(
items
,
type
,
index
)
{
if
(
!
this
.
transMemberStatus
)
{
if
(
!
this
.
transMemberStatus
)
{
...
@@ -1339,14 +1358,12 @@ export default {
...
@@ -1339,14 +1358,12 @@ export default {
page
:
data
.
share_data
.
page
,
page
:
data
.
share_data
.
page
,
imgUrl
:
data
.
share_data
.
share_img
,
imgUrl
:
data
.
share_data
.
share_img
,
};
};
// this.set_sendSkillMessage(list)
this
.
sendChatMessage
(
miniprogramInfo
,
"miniprogram"
);
this
.
sendChatMessage
(
miniprogramInfo
,
"miniprogram"
);
const
game_data
=
this
.
$clone
(
data
.
game_data
);
const
game_data
=
this
.
$clone
(
data
.
game_data
);
game_data
.
type
=
3
;
game_data
.
type
=
3
;
console
.
log
(
game_data
,
"data----------"
);
console
.
log
(
game_data
,
"data----------"
);
this
.
sendGameLog
(
game_data
);
this
.
sendGameLog
(
game_data
);
}
else
{
}
else
{
// this.set_sendSkillMessage(list)
this
.
getMediaId
(
data
.
game_data
.
game_url
,
"image"
);
this
.
getMediaId
(
data
.
game_data
.
game_url
,
"image"
);
this
.
sendGameLog
(
data
.
game_data
);
this
.
sendGameLog
(
data
.
game_data
);
}
}
...
@@ -1399,8 +1416,6 @@ export default {
...
@@ -1399,8 +1416,6 @@ export default {
},
},
},
},
];
];
// 这里需要特殊处理,因为有taskInfo参数
// this.set_sendSkillMessage(list)
this
.
sendChatMessage
(
this
.
sendChatMessage
(
`
${
str
}${
item
.
game_url
}
\n账号:
${
username
}
\n密码:
${
res
.
data
.
password
}
`
,
`
${
str
}${
item
.
game_url
}
\n账号:
${
username
}
\n密码:
${
res
.
data
.
password
}
`
,
"text"
"text"
...
@@ -1414,12 +1429,7 @@ export default {
...
@@ -1414,12 +1429,7 @@ export default {
const
params
=
{
const
params
=
{
main_game_id
:
items
.
main_game_id
,
main_game_id
:
items
.
main_game_id
,
weixin_blongs_id
:
items
.
weixin_blongs_id
,
weixin_blongs_id
:
items
.
weixin_blongs_id
,
type
:
type
:
items
.
game_type
==
1
||
items
.
game_type
==
5
?
2
:
items
.
game_type
==
3
||
items
.
game_type
==
4
?
1
:
''
items
.
game_type
==
1
?
2
:
items
.
game_type
==
3
||
items
.
game_type
==
4
?
1
:
""
,
};
};
const
res
=
await
getLandingPageConfig
(
params
);
const
res
=
await
getLandingPageConfig
(
params
);
if
(
res
.
status_code
===
1
&&
res
.
data
)
{
if
(
res
.
status_code
===
1
&&
res
.
data
)
{
...
@@ -1511,16 +1521,10 @@ export default {
...
@@ -1511,16 +1521,10 @@ export default {
},
},
// 主方法
// 主方法
async
handleGameType
(
items
,
item
,
type
,
index
)
{
async
handleGameType
(
items
,
item
,
type
,
index
)
{
if
(
if
((
items
.
game_type
==
1
||
items
.
game_type
==
3
||
items
.
game_type
==
4
||
items
.
game_type
==
5
)
&&
items
.
main_game_id
&&
items
.
weixin_blongs_id
)
{
(
items
.
game_type
==
1
||
items
.
game_type
==
3
||
items
.
game_type
==
4
)
&&
items
.
main_game_id
&&
items
.
weixin_blongs_id
)
{
const
result
=
await
this
.
getLandingPageConfig
(
items
,
item
);
const
result
=
await
this
.
getLandingPageConfig
(
items
,
item
);
if
(
result
&&
result
.
data
?.
data
?.
tag
)
{
if
(
result
&&
result
.
data
?.
data
?.
tag
)
{
if
(
items
.
game_type
==
1
)
{
if
(
items
.
game_type
==
1
||
items
.
game_type
==
5
)
{
// 处理微信小程序游戏
// 处理微信小程序游戏
this
.
handleWechatMiniGame
(
items
,
item
,
index
);
this
.
handleWechatMiniGame
(
items
,
item
,
index
);
}
else
{
}
else
{
...
@@ -1541,15 +1545,6 @@ export default {
...
@@ -1541,15 +1545,6 @@ export default {
// 小游戏游戏确认
// 小游戏游戏确认
async
handleWxGameConfirm
(
value
)
{
async
handleWxGameConfirm
(
value
)
{
console
.
log
(
value
,
"value"
);
console
.
log
(
value
,
"value"
);
// const list = [
// {
// msgtype: 'image',
// image: {
// picurl: value
// }
// }
// ]
// this.set_sendSkillMessage(list)
this
.
getMediaId
(
value
,
"image"
);
this
.
getMediaId
(
value
,
"image"
);
},
},
SendTransAppGameClose
()
{
SendTransAppGameClose
()
{
...
@@ -1561,15 +1556,6 @@ export default {
...
@@ -1561,15 +1556,6 @@ export default {
// 安卓或者 IOS 游戏处理
// 安卓或者 IOS 游戏处理
handleAppGameConfirm
(
data
)
{
handleAppGameConfirm
(
data
)
{
this
.
selectedAppGameList
=
[];
this
.
selectedAppGameList
=
[];
// const list = [
// {
// msgtype: 'text',
// text: {
// content: `游戏地址:${data.landing_page_url} \n账号:${data.username} \n密码:${data.password}`
// }
// }
// ]
// this.set_sendSkillMessage(list)
this
.
sendChatMessage
(
this
.
sendChatMessage
(
`游戏地址:
${
data
.
landing_page_url
}
\n账号:
${
data
.
username
}
\n密码:
${
data
.
password
}
`
,
`游戏地址:
${
data
.
landing_page_url
}
\n账号:
${
data
.
username
}
\n密码:
${
data
.
password
}
`
,
"text"
"text"
...
...
src/views/components/quickSendGame/sendGame/SendTransAppGame.vue
浏览文件 @
7af060b5
...
@@ -321,11 +321,12 @@
...
@@ -321,11 +321,12 @@
}
}
const
res
=
await
getLandingPageMemberLink
(
params
)
const
res
=
await
getLandingPageMemberLink
(
params
)
if
(
res
&&
res
.
data
.
data
)
{
if
(
res
&&
res
.
data
.
data
)
{
this
.
loading
=
false
this
.
loading
=
false
this
.
close
()
this
.
close
()
this
.
$emit
(
'confirm'
,
res
.
data
.
data
)
this
.
$emit
(
'confirm'
,
res
.
data
.
data
)
this
.
$message
.
success
(
'发送成功'
)
this
.
$message
.
success
(
'发送成功'
)
}
}
}
catch
(
error
)
{
}
catch
(
error
)
{
this
.
loading
=
false
this
.
loading
=
false
console
.
error
(
'获取链接失败:'
,
error
)
console
.
error
(
'获取链接失败:'
,
error
)
...
...
src/views/components/quickSendGame/sendGame/SendTransWxGame.vue
浏览文件 @
7af060b5
...
@@ -3,18 +3,20 @@
...
@@ -3,18 +3,20 @@
<el-drawer
<el-drawer
title=
"选择游戏"
title=
"选择游戏"
:visible=
"show"
:visible=
"show"
size=
"360px"
size=
"80%"
append-to-body
@
close=
"close"
@
close=
"close"
>
>
<div
class=
"sendTransWxGame"
>
<el-form
ref=
"wxGameForm"
:model=
"wxGameForm"
:rules=
"wxGameRules"
label-position=
"top"
class=
"game-select-container"
>
<el-form
ref=
"wxGameForm"
:model=
"wxGameForm"
:rules=
"wxGameRules"
label-position=
"top"
class=
"game-select-container"
>
<!-- 微信小游戏 -->
<!-- 微信
/抖音
小游戏 -->
<el-form-item
label=
""
>
<el-form-item
label=
""
>
<template
slot=
"label"
>
<template
slot=
"label"
>
<p
class=
"formLabel"
>
微信小游戏
</p>
<p
class=
"formLabel"
>
微信
/抖音
小游戏
</p>
</
template
>
</
template
>
<el-select
<el-select
v-model=
"wxGameForm.wx_game_send_id"
v-model=
"wxGameForm.wx_game_send_id"
placeholder=
"请选择微信小游戏"
placeholder=
"请选择微信
/抖音
小游戏"
style=
"width: 100%"
style=
"width: 100%"
disabled
disabled
>
>
...
@@ -27,22 +29,71 @@
...
@@ -27,22 +29,71 @@
</el-option>
</el-option>
</el-select>
</el-select>
</el-form-item>
</el-form-item>
<el-form-item
label=
""
>
<el-form-item
label=
"
选择渠道
"
>
<el-select
<el-select
v-model=
"wxGameForm.wx_game_channel"
v-model=
"wxGameForm.wx_game_channel"
placeholder=
"请选择渠道"
placeholder=
"请选择渠道"
style=
"width: 100%"
style=
"width: 100%"
:clearable=
"true"
:clearable=
"true"
@
change=
"handleChannelChange"
>
>
<el-option
<el-option
v-for=
"(item,index) in wxGameChannelList"
v-for=
"(item,index) in wxGameChannelList"
:key=
"i
ndex
"
:key=
"i
tem.key
"
:label=
"item.name"
:label=
"item.name"
:value=
"item.key"
:value=
"item.key"
>
>
</el-option>
</el-option>
</el-select>
</el-select>
</el-form-item>
</el-form-item>
<!-- 选择背景图 新增背景图的选项 -->
<el-form-item
v-if=
"backgroundImgsList.length > 0"
label=
""
style=
"margin-bottom: 100px;"
>
<
template
slot=
"label"
>
<p
class=
"formLabel"
>
<span
class=
"required-mark"
>
*
</span>
<span>
背景图
</span>
</p>
</
template
>
<el-radio-group
v-model=
"wxGameForm.selectedBackgroundIndex"
@
change=
"handleBackgroundChange"
>
<div
class=
"background-options"
>
<el-radio
v-for=
"(item, index) in backgroundImgsList"
:key=
"item.background_img"
:label=
"index"
class=
"background-radio-item"
>
<div
class=
"background-card"
>
<div
class=
"background-preview-wrapper"
>
<img
:ref=
"`bgImg_${index}`"
:src=
"item.background_img"
class=
"background-preview"
alt=
"背景图预览"
@
load=
"handleBackgroundImageLoad(index, item)"
>
<!-- 二维码叠加显示 -->
<img
v-if=
"channelQrcode && item.qrStyle"
:src=
"channelQrcode"
class=
"background-qrcode"
:style=
"item.qrStyle"
alt=
"二维码"
>
</div>
<!-- 左上角小眼睛图标 -->
<div
class=
"eye-icon"
:class=
"{'eye-icon-checked': wxGameForm.selectedBackgroundIndex === index}"
@
click
.
stop=
"showPreview(item, index)"
>
<i
class=
"el-icon-view"
></i>
</div>
<!-- 右上角选中/未选中图标 -->
<div
class=
"status-icon"
>
<i
v-if=
"wxGameForm.selectedBackgroundIndex === index"
class=
"el-icon-success status-icon-checked"
></i>
<svg-icon
v-else
icon-class=
"uncheck"
class=
"status-icon-unchecked"
></svg-icon>
</div>
</div>
</el-radio>
</div>
</el-radio-group>
</el-form-item>
</el-form>
</el-form>
<span
class=
"dialog-footer rowFlex"
>
<span
class=
"dialog-footer rowFlex"
>
<el-button
class=
"btn"
@
click=
"close"
size=
"small"
>
取消
</el-button>
<el-button
class=
"btn"
@
click=
"close"
size=
"small"
>
取消
</el-button>
...
@@ -75,6 +126,40 @@
...
@@ -75,6 +126,40 @@
>
>
</div>
</div>
</div>
</div>
<!-- 大图预览弹窗 -->
<el-drawer
title=
"预览"
:visible
.
sync=
"previewVisible"
size=
"80%"
:modal=
"false"
:close-on-click-modal=
"false"
append-to-body
class=
"preview-dialog"
>
<div
class=
"preview-content"
>
<div
class=
"preview-wrapper"
v-if=
"previewImageInfo"
>
<img
ref=
"previewBgImgDisplay"
:src=
"previewImageInfo.background_img"
class=
"preview-background"
alt=
"背景图"
@
load=
"handlePreviewImageLoad"
>
<img
v-if=
"previewImageInfo.channel_qrcode"
ref=
"previewQrImgDisplay"
:src=
"previewImageInfo.channel_qrcode"
class=
"preview-qrcode"
:style=
"previewQrcodeStyle"
alt=
"二维码"
>
</div>
</div>
<span
slot=
"footer"
class=
"dialog-footer"
>
<el-button
@
click=
"previewVisible = false"
>
关闭
</el-button>
</span>
</el-drawer>
</div>
</el-drawer>
</el-drawer>
</template>
</template>
...
@@ -119,14 +204,20 @@
...
@@ -119,14 +204,20 @@
wxGameForm
:
{
wxGameForm
:
{
wx_game_send_id
:
''
,
wx_game_send_id
:
''
,
wx_game_send_info
:
{},
wx_game_send_info
:
{},
wx_game_channel
:
''
wx_game_channel
:
''
,
selectedBackgroundIndex
:
0
// 选中的背景图索引
},
},
messageInfo
:
null
,
messageInfo
:
null
,
handleConfirmWithDebounce
:
{},
handleConfirmWithDebounce
:
{},
wxGameChannelList
:
[],
wxGameChannelList
:
[],
backgroundImgsList
:
[],
// 背景图列表
channelQrcode
:
''
,
// 二维码链接
previewVisible
:
false
,
// 预览弹窗显示状态
previewImageInfo
:
null
,
// 预览图片信息(包含背景图和二维码)
previewQrcodeStyle
:
{},
// 预览二维码样式
wxGameRules
:
{
wxGameRules
:
{
wx_game_send_id
:
[
wx_game_send_id
:
[
{
required
:
true
,
message
:
'请选择微信小游戏'
,
trigger
:
'change'
}
{
required
:
true
,
message
:
'请选择微信
/抖音
小游戏'
,
trigger
:
'change'
}
],
],
wx_game_channel
:
[
wx_game_channel
:
[
{
required
:
true
,
message
:
'请选择渠道'
,
trigger
:
'change'
}
{
required
:
true
,
message
:
'请选择渠道'
,
trigger
:
'change'
}
...
@@ -150,6 +241,8 @@
...
@@ -150,6 +241,8 @@
wx_game_channel
:
''
wx_game_channel
:
''
}
}
this
.
wxGameChannelList
=
[]
this
.
wxGameChannelList
=
[]
this
.
backgroundImgsList
=
[]
this
.
channelQrcode
=
''
this
.
closeMessage
()
this
.
closeMessage
()
this
.
loading
=
false
this
.
loading
=
false
// 清理图片资源
// 清理图片资源
...
@@ -320,6 +413,19 @@
...
@@ -320,6 +413,19 @@
}
}
})
})
},
},
// 处理渠道选择变化
async
handleChannelChange
(
value
)
{
if
(
!
value
)
{
// 清空渠道时,清空背景图列表
this
.
backgroundImgsList
=
[]
this
.
channelQrcode
=
''
this
.
wxGameForm
.
selectedBackgroundIndex
=
0
this
.
imageInfo
=
{}
return
}
// 选择渠道后自动请求接口
await
this
.
handleWxGameChannel
()
},
async
uploadCos
(
File
)
{
async
uploadCos
(
File
)
{
const
uploadConfig
=
{
const
uploadConfig
=
{
dir
:
'/company_wx/service/avatars/'
dir
:
'/company_wx/service/avatars/'
...
@@ -336,7 +442,30 @@
...
@@ -336,7 +442,30 @@
}
}
},
},
handleConfirm
()
{
handleConfirm
()
{
this
.
handleWxGameChannel
()
if
(
!
this
.
imageInfo
.
background_img
)
{
this
.
$message
.
warning
(
'请先选择背景图'
)
return
false
}
if
(
!
this
.
imageInfo
.
channel_qrcode
)
{
this
.
$message
.
warning
(
'渠道二维码图片不存在'
)
return
false
}
// 检查是否选择了渠道
if
(
!
this
.
wxGameForm
.
wx_game_channel
)
{
this
.
$message
.
warning
(
'请选择渠道'
)
return
}
// 如果有背景图列表,直接合成图片
if
(
this
.
backgroundImgsList
.
length
>
0
)
{
this
.
confirmAndCompose
()
}
else
{
// 如果没有背景图列表,说明接口返回的是旧格式,直接合成
if
(
this
.
imageInfo
.
background_img
)
{
this
.
confirmAndCompose
()
}
else
{
this
.
$message
.
warning
(
'请先选择渠道'
)
}
}
},
},
// 保存微信小游戏的信息
// 保存微信小游戏的信息
...
@@ -387,11 +516,37 @@
...
@@ -387,11 +516,37 @@
const
linkRes
=
await
getLandingPageMemberLink
(
params
)
const
linkRes
=
await
getLandingPageMemberLink
(
params
)
console
.
log
(
'获取到的落地页数据:'
,
linkRes
)
console
.
log
(
'获取到的落地页数据:'
,
linkRes
)
if
(
linkRes
?.
data
?.
data
)
{
if
(
linkRes
?.
data
?.
data
)
{
// 检查返回的数据结构
const
responseData
=
linkRes
.
data
.
data
console
.
log
(
'设置前的imageInfo:'
,
this
.
imageInfo
)
// 保存二维码链接
this
.
imageInfo
=
linkRes
.
data
.
data
this
.
channelQrcode
=
responseData
.
channel_qrcode
||
''
console
.
log
(
'设置后的imageInfo:'
,
this
.
imageInfo
)
await
this
.
composeImage
()
// 处理背景图列表
if
(
responseData
.
background_imgs
&&
responseData
.
background_imgs
.
length
>
0
)
{
// 如果有背景图列表,使用列表中的图片
// 初始化二维码样式
this
.
backgroundImgsList
=
responseData
.
background_imgs
.
map
(
item
=>
({
...
item
,
qrStyle
:
null
// 等待图片加载后计算
}))
// 默认选中第一个
this
.
wxGameForm
.
selectedBackgroundIndex
=
0
// 设置默认的 imageInfo
this
.
updateImageInfo
(
0
)
// 不立即合成,等待用户选择后点击确认
this
.
loading
=
false
return
}
else
{
// 如果没有背景图列表,使用默认背景图(兼容旧逻辑)
this
.
backgroundImgsList
=
[]
this
.
imageInfo
=
{
background_img
:
responseData
.
background_img
||
''
,
channel_qrcode
:
this
.
channelQrcode
,
'x-coordinate'
:
responseData
[
'x-coordinate'
]
||
0
,
'y-coordinate'
:
responseData
[
'y-coordinate'
]
||
0
}
// 不立即合成,等待用户点击确认
this
.
loading
=
false
}
}
else
{
}
else
{
throw
new
Error
(
'获取落地页数据失败'
)
throw
new
Error
(
'获取落地页数据失败'
)
}
}
...
@@ -405,73 +560,387 @@
...
@@ -405,73 +560,387 @@
},
},
close
()
{
close
()
{
this
.
closeMessage
()
this
.
closeMessage
()
// 清理背景图相关数据
this
.
backgroundImgsList
=
[]
this
.
channelQrcode
=
''
this
.
wxGameForm
.
selectedBackgroundIndex
=
0
this
.
imageInfo
=
{}
this
.
previewVisible
=
false
this
.
previewImageInfo
=
null
this
.
$emit
(
'close'
)
this
.
$emit
(
'close'
)
this
.
$emit
(
'update:show'
,
false
)
this
.
$emit
(
'update:show'
,
false
)
},
// 处理背景图选择变化
handleBackgroundChange
(
index
)
{
this
.
updateImageInfo
(
index
)
},
// 更新 imageInfo
updateImageInfo
(
index
)
{
if
(
this
.
backgroundImgsList
.
length
>
0
&&
this
.
backgroundImgsList
[
index
])
{
const
selectedBg
=
this
.
backgroundImgsList
[
index
]
this
.
imageInfo
=
{
background_img
:
selectedBg
.
background_img
,
channel_qrcode
:
this
.
channelQrcode
,
'x-coordinate'
:
selectedBg
[
'x-coordinate'
]
||
0
,
'y-coordinate'
:
selectedBg
[
'y-coordinate'
]
||
0
}
}
},
// 确认选择背景图后合成图片
async
confirmAndCompose
()
{
if
(
this
.
backgroundImgsList
.
length
===
0
)
{
// 如果没有背景图列表,直接合成(兼容旧逻辑)
await
this
.
composeImage
()
return
}
}
// 确保 imageInfo 已设置
if
(
!
this
.
imageInfo
.
background_img
)
{
this
.
updateImageInfo
(
this
.
wxGameForm
.
selectedBackgroundIndex
)
}
await
this
.
composeImage
()
},
// 显示大图预览
showPreview
(
item
,
index
)
{
// 构建预览图片信息
const
previewInfo
=
{
background_img
:
item
.
background_img
,
channel_qrcode
:
this
.
channelQrcode
,
'x-coordinate'
:
item
[
'x-coordinate'
]
||
0
,
'y-coordinate'
:
item
[
'y-coordinate'
]
||
0
}
this
.
previewImageInfo
=
previewInfo
this
.
previewVisible
=
true
// 重置二维码样式,等待图片加载后计算
this
.
previewQrcodeStyle
=
{}
// 等待 DOM 更新后,检查图片是否已加载
this
.
$nextTick
(()
=>
{
if
(
this
.
$refs
.
previewBgImgDisplay
)
{
const
bgImg
=
this
.
$refs
.
previewBgImgDisplay
// 如果图片已经加载完成(complete 属性为 true),直接计算样式
if
(
bgImg
.
complete
&&
bgImg
.
naturalWidth
>
0
)
{
this
.
calculatePreviewQrcodeStyle
()
}
}
})
},
// 处理预览背景图加载完成
handlePreviewImageLoad
()
{
this
.
calculatePreviewQrcodeStyle
()
},
// 计算预览二维码样式
calculatePreviewQrcodeStyle
()
{
if
(
!
this
.
previewImageInfo
||
!
this
.
$refs
.
previewBgImgDisplay
)
{
return
}
const
bgImg
=
this
.
$refs
.
previewBgImgDisplay
// 参考生成图片时的逻辑:背景图宽度固定为 750px
const
bgOriginalWidth
=
750
// 原始宽度(生成图片时的宽度)
// 等待下一帧,确保图片已渲染
this
.
$nextTick
(()
=>
{
// 获取背景图的实际显示尺寸(参考生成图片时的逻辑)
// 使用 getBoundingClientRect 获取实际渲染尺寸
const
imgRect
=
bgImg
.
getBoundingClientRect
()
const
displayWidth
=
imgRect
.
width
const
displayHeight
=
imgRect
.
height
// 如果图片还没有渲染完成,延迟重试
if
(
displayWidth
===
0
||
displayHeight
===
0
)
{
setTimeout
(()
=>
{
this
.
calculatePreviewQrcodeStyle
()
},
100
)
return
}
// 计算缩放比例(基于实际显示宽度与原始宽度的比例)
// 参考生成图片时:width = 750, height = (naturalHeight / naturalWidth) * width
const
scale
=
displayWidth
/
bgOriginalWidth
// 计算二维码位置和尺寸(参考生成图片时的逻辑)
// x-coordinate 和 y-coordinate 是相对于 750px 宽度的绝对位置
// 二维码直接使用坐标值,相对于背景图容器定位
const
qrSize
=
180
*
scale
const
qrLeft
=
(
this
.
previewImageInfo
[
'x-coordinate'
]
||
0
)
*
scale
const
qrTop
=
(
this
.
previewImageInfo
[
'y-coordinate'
]
||
0
)
*
scale
this
.
previewQrcodeStyle
=
{
position
:
'absolute'
,
left
:
`
${
qrLeft
}
px`
,
top
:
`
${
qrTop
}
px`
,
width
:
`
${
qrSize
}
px`
,
height
:
`
${
qrSize
}
px`
}
})
},
// 处理背景图列表中的图片加载完成
handleBackgroundImageLoad
(
index
,
item
)
{
const
bgImgRef
=
this
.
$refs
[
`bgImg_
${
index
}
`
]
// Vue 2 中,ref 可能是数组或单个元素
const
bgImg
=
Array
.
isArray
(
bgImgRef
)
?
bgImgRef
[
0
]
:
bgImgRef
if
(
!
bgImg
)
{
return
}
// 参考生成图片时的逻辑:背景图宽度固定为 750px
const
bgOriginalWidth
=
750
// 原始宽度(生成图片时的宽度)
// 等待下一帧,确保图片已渲染
this
.
$nextTick
(()
=>
{
// 获取背景图的实际显示尺寸(参考生成图片时的逻辑)
// 使用 getBoundingClientRect 获取实际渲染尺寸
const
imgRect
=
bgImg
.
getBoundingClientRect
()
const
displayWidth
=
imgRect
.
width
const
displayHeight
=
imgRect
.
height
// 计算缩放比例(基于实际显示宽度与原始宽度的比例)
// 参考生成图片时:width = 750, height = (naturalHeight / naturalWidth) * width
const
scale
=
displayWidth
/
bgOriginalWidth
// 计算二维码位置和尺寸(参考生成图片时的逻辑)
// x-coordinate 和 y-coordinate 是相对于 750px 宽度的绝对位置
// 二维码直接使用坐标值,相对于背景图容器定位
const
qrSize
=
180
*
scale
const
qrLeft
=
(
item
[
'x-coordinate'
]
||
0
)
*
scale
const
qrTop
=
(
item
[
'y-coordinate'
]
||
0
)
*
scale
// 更新二维码样式
this
.
$set
(
this
.
backgroundImgsList
[
index
],
'qrStyle'
,
{
position
:
'absolute'
,
left
:
`
${
qrLeft
}
px`
,
top
:
`
${
qrTop
}
px`
,
width
:
`
${
qrSize
}
px`
,
height
:
`
${
qrSize
}
px`
})
})
}
}
}
}
}
</
script
>
</
script
>
<
style
scoped
lang=
"scss"
>
<
style
scoped
lang=
"scss"
>
.formLabel
{
.formLabel
{
font-size
:
16px
;
font-size
:
16px
;
font-weight
:
500
;
font-weight
:
500
;
}
.sendTransWxGame
{
width
:
100%
;
height
:
100%
;
overflow
:
auto
;
padding-bottom
:
50px
;
}
.dialog-footer
{
width
:
calc
(
100%
);
height
:
auto
;
position
:
absolute
;
padding-top
:
20px
;
padding-bottom
:
20px
;
bottom
:
0
;
right
:
0
;
justify-content
:
flex-end
;
border-top
:
1px
solid
rgba
(
0
,
0
,
0
,
0.06
);
background
:
#fff
;
.btn{
width
:
84px
;
height
:
32px
;
}
}
.dialog-footer
{
}
width
:
calc
(
100%
);
.game-select-container
{
height
:
auto
;
padding
:
0
20px
;
position
:
absolute
;
::v-deep
.el-icon-circle-close{
padding-top
:
20px
;
color
:
#C0C4CC
!important
;
padding-bottom
:
20px
;
bottom
:
0
;
right
:
0
;
justify-content
:
flex-end
;
border-top
:
1px
solid
rgba
(
0
,
0
,
0
,
0.06
);
background
:
#fff
;
.btn{
width
:
84px
;
height
:
32px
;
}
}
}
.game-select-container
{
::v-deep
.el-form-item__label
{
padding
:
0
20px
;
line-height
:
32px
;
::v-deep
.el-icon-circle-close{
padding
:
3px
;
color
:
#C0C4CC
!important
;
}
::v-deep
.el-form-item__label
{
line-height
:
32px
;
padding
:
3px
;
}
}
}
.compose-container
{
}
position
:
fixed
;
.compose-container
{
left
:
-9999px
;
position
:
fixed
;
top
:
-9999px
;
left
:
-9999px
;
overflow
:
hidden
;
top
:
-9999px
;
z-index
:
-1
;
overflow
:
hidden
;
z-index
:
-1
;
}
.image-wrapper
{
position
:
relative
;
display
:
none
;
font-size
:
0
;
width
:
750px
;
/* 固定容器宽度 */
}
.background-img
{
display
:
block
;
width
:
750px
!important
;
/* 固定宽度 */
height
:
auto
!important
;
/* 高度自适应 */
object-fit
:
contain
;
}
.qr-code
{
position
:
absolute
;
display
:
block
;
width
:
180px
!important
;
height
:
180px
!important
;
object-fit
:
contain
;
pointer-events
:
none
;
}
.required-mark
{
color
:
#f53f3f
;
margin-right
:
4px
;
}
.background-options
{
display
:
flex
;
flex-wrap
:
wrap
;
gap
:
16px
;
width
:
100%
;
}
.background-radio-item
{
margin-right
:
0
!important
;
margin-bottom
:
0
!important
;
width
:
120px
;
::v-deep
.el-radio__input
{
display
:
none
;
}
}
.image-wrapper
{
::v-deep
.el-radio__label
{
position
:
relative
;
padding-left
:
0
;
display
:
none
;
cursor
:
pointer
;
font-size
:
0
;
width
:
100%
;
width
:
750px
;
/* 固定容器宽度 */
}
}
.background-card
{
position
:
relative
;
width
:
100%
;
height
:
200px
;
background
:
#fff
;
border
:
1.5px
solid
#e5e7eb
;
border-radius
:
8px
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
overflow
:
hidden
;
transition
:
all
0.3s
;
padding
:
10px
30px
;
}
.background-radio-item.is-checked
.background-card
{
border-color
:
#00bf8a
;
}
.background-preview-wrapper
{
position
:
relative
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
}
.background-preview
{
width
:
100%
;
object-fit
:
100%
100%
;
pointer-events
:
none
;
border-radius
:
5px
;
}
.background-qrcode
{
pointer-events
:
none
;
object-fit
:
contain
;
}
.eye-icon
{
position
:
absolute
;
left
:
6.5px
;
top
:
6.5px
;
width
:
16px
;
height
:
16px
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
cursor
:
pointer
;
z-index
:
10
;
i
{
font-size
:
16px
;
color
:
#C9CDD4
;
}
}
.background-img
{
&
:hover
{
display
:
block
;
opacity
:
0.8
;
width
:
750px
!important
;
/* 固定宽度 */
color
:
#00bf8a
;
height
:
auto
!important
;
/* 高度自适应 */
}
object-fit
:
contain
;
}
.eye-icon-checked
{
i{
color
:
#00bf8a
;
}
}
.status-icon
{
position
:
absolute
;
right
:
6.5px
;
top
:
6.5px
;
width
:
16px
;
height
:
16px
;
z-index
:
10
;
.status-icon-checked
{
font-size
:
14px
;
color
:
#00bf8a
;
width
:
14px
;
height
:
14px
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
}
}
.qr-code
{
.status-icon-unchecked
{
position
:
absolute
;
font-size
:
14px
;
display
:
block
;
color
:
#b1b2b4
;
width
:
180px
!important
;
width
:
14px
;
height
:
180px
!important
;
height
:
14px
;
object-fit
:
contain
;
display
:
flex
;
pointer-events
:
none
;
align-items
:
center
;
justify-content
:
center
;
}
}
</
style
>
}
.preview-dialog
{
height
:
auto
;
background
:
none
;
}
.preview-content
{
width
:
100%
;
height
:
100%
;
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
min-height
:
400px
;
padding
:
20px
;
padding-top
:
0
;
}
.preview-wrapper
{
position
:
relative
;
display
:
flex
;
justify-content
:
center
;
}
.preview-background
{
display
:
block
;
border-radius
:
10px
;
max-width
:
100%
;
}
.preview-qrcode
{
object-fit
:
contain
;
pointer-events
:
none
;
}
</
style
>
\ No newline at end of file
src/views/components/quickSendGame/sendGame/selectChannel.vue
浏览文件 @
7af060b5
...
@@ -147,7 +147,6 @@ export default {
...
@@ -147,7 +147,6 @@ export default {
// list = [{ msgtype: 'text', text: { content: str }}]
// list = [{ msgtype: 'text', text: { content: str }}]
this
.
sendChatMessage
(
str
,
'text'
)
this
.
sendChatMessage
(
str
,
'text'
)
}
}
// this.set_sendSkillMessage(list)
// 3:召回 召回的时候请求召回染色的接口
// 3:召回 召回的时候请求召回染色的接口
this
.
recallChannelSeq
()
this
.
recallChannelSeq
()
}
}
...
...
src/views/components/quickSendGame/sendGame/sendSelectChannel.vue
浏览文件 @
7af060b5
...
@@ -37,9 +37,6 @@ export default {
...
@@ -37,9 +37,6 @@ export default {
close
()
{
close
()
{
this
.
$emit
(
'update:show'
,
false
)
this
.
$emit
(
'update:show'
,
false
)
},
},
// const list = [{ msgtype: 'text', text: { content: `${str}${item.url}` }}]
// this.set_sendSkillMessage(list)
onConfirm
()
{
onConfirm
()
{
if
(
this
.
webForm
.
channel_id
===
''
)
{
if
(
this
.
webForm
.
channel_id
===
''
)
{
this
.
$message
.
warning
(
'请选择渠道'
)
this
.
$message
.
warning
(
'请选择渠道'
)
...
@@ -105,8 +102,6 @@ export default {
...
@@ -105,8 +102,6 @@ export default {
// list = [{ msgtype: 'text', text: { content: str }}]
// list = [{ msgtype: 'text', text: { content: str }}]
this
.
sendChatMessage
(
str
,
'text'
)
this
.
sendChatMessage
(
str
,
'text'
)
}
}
// this.set_sendSkillMessage(list)
// this.sendChatMessage(str,'text')
// 3:召回 召回的时候请求召回染色的接口
// 3:召回 召回的时候请求召回染色的接口
this
.
recallChannelSeq
()
this
.
recallChannelSeq
()
}
}
...
...
src/views/components/quickSendGame/vipTools.vue
浏览文件 @
7af060b5
...
@@ -286,7 +286,7 @@ export default {
...
@@ -286,7 +286,7 @@ export default {
handleFlowerLinkSuccess
(
url
)
{
handleFlowerLinkSuccess
(
url
)
{
if
(
url
)
{
if
(
url
)
{
this
.
sendChatMessage
(
url
,
"text"
);
this
.
sendChatMessage
(
url
,
"text"
);
this
.
$message
.
success
(
"发送成功"
);
this
.
$message
.
success
(
'发送成功'
)
}
}
},
},
// 发送举报申诉自助链接
// 发送举报申诉自助链接
...
...
src/views/components/roleInfo/roleInfoPanel.vue
浏览文件 @
7af060b5
...
@@ -184,6 +184,17 @@
...
@@ -184,6 +184,17 @@
</p>
</p>
</div>
</div>
</div>
</div>
<!-- 带教记录 -->
<div
class=
"item rowFlex columnCenter spaceBetween"
>
<div
class=
"rowFlex columnCenter"
>
<span
class=
"label"
>
带教次数:
</span>
<el-button
type=
"text"
style=
"cursor: pointer;z-index:10;"
@
click
.
stop=
"openMentorRecordDrawer(items)"
>
{{ items.teach_num || '-' }}次
</el-button>
</div>
</div>
</div>
</div>
</el-collapse-item>
</el-collapse-item>
</div>
</div>
...
@@ -204,24 +215,39 @@
...
@@ -204,24 +215,39 @@
:show
.
sync=
"showAppeal"
:show
.
sync=
"showAppeal"
:appeal-info=
"appealInfo"
:appeal-info=
"appealInfo"
/>
/>
<!-- 带教记录弹窗 -->
<el-drawer
:visible
.
sync=
"showMentorRecord"
v-if=
"showMentorRecord"
:title=
"`${currentRoleName}带教记录`"
size=
"300px"
:append-to-body=
"true"
>
<mentorRecord
:role-id=
"currentRoleId"
@
refresh=
"handleMentorRecordRefresh"
/>
</el-drawer>
</div>
</div>
</template>
</template>
<
script
>
<
script
>
import
{
mapState
,
mapMutations
,
mapActions
}
from
"vuex"
;
import
{
mapState
,
mapMutations
,
mapActions
}
from
"vuex"
;
import
{
getRoleHoLo
,
marketingRoleGrade
,
getServerDayApi
}
from
"@/api/game"
;
import
{
getRoleHoLo
,
marketingRoleGrade
,
getServerDayApi
,
roleTeachingNum
}
from
"@/api/game"
;
import
noContent
from
"@/components/noContent.vue"
;
import
noContent
from
"@/components/noContent.vue"
;
import
appeal
from
"./layer/appeal.vue"
;
import
appeal
from
"./layer/appeal.vue"
;
import
watchMember
from
"@/mixins/watchMember"
;
import
watchMember
from
"@/mixins/watchMember"
;
import
{
createDetails
}
from
"@/views/popup/RecentActivitiesPopup/index.js"
;
import
{
createDetails
}
from
"@/views/popup/RecentActivitiesPopup/index.js"
;
import
{
createRoleRecentActivityNotPushNum
}
from
"@/views/hooks/useGetCount.js"
;
import
{
createRoleRecentActivityNotPushNum
}
from
"@/views/hooks/useGetCount.js"
;
import
vipLevel
from
"@/views/userInfo/components/gameInfo/vipLevel.vue"
;
import
vipLevel
from
"@/views/userInfo/components/gameInfo/vipLevel.vue"
;
import
mentorRecord
from
"@/views/userInfo/components/gameInfo/mentorRecord.vue"
;
export
default
{
export
default
{
name
:
"roleInfo"
,
name
:
"roleInfo"
,
components
:
{
components
:
{
noContent
,
noContent
,
appeal
,
appeal
,
vipLevel
,
vipLevel
,
mentorRecord
,
},
},
data
()
{
data
()
{
return
{
return
{
...
@@ -240,6 +266,9 @@ export default {
...
@@ -240,6 +266,9 @@ export default {
recentActivitiesPopupInstance
:
null
,
//近期要开模块弹框
recentActivitiesPopupInstance
:
null
,
//近期要开模块弹框
roleRecentActivityNotPushNumInstance
:
null
,
//侧边栏计数弹框
roleRecentActivityNotPushNumInstance
:
null
,
//侧边栏计数弹框
numRoleIdList
:
[],
numRoleIdList
:
[],
showMentorRecord
:
false
,
// 带教记录弹窗显示状态
currentRoleId
:
null
,
// 当前查看带教记录的角色ID
currentRoleName
:
''
// 当前查看带教记录的角色名称
};
};
},
},
computed
:
{
computed
:
{
...
@@ -248,7 +277,11 @@ export default {
...
@@ -248,7 +277,11 @@ export default {
watch
:
{
watch
:
{
collapseActive
(
newVal
,
oldVal
)
{
collapseActive
(
newVal
,
oldVal
)
{
if
(
newVal
.
length
>
0
)
{
if
(
newVal
.
length
>
0
)
{
this
.
handleChange
(
newVal
.
filter
((
item
)
=>
!
oldVal
.
includes
(
item
)));
const
newOpenedItems
=
newVal
.
filter
(
item
=>
!
oldVal
.
includes
(
item
))
this
.
handleChange
(
newOpenedItems
)
// 处理带教次数获取
this
.
handleChangeRoleTeachingNum
(
newOpenedItems
)
}
}
},
},
},
},
...
@@ -303,7 +336,6 @@ export default {
...
@@ -303,7 +336,6 @@ export default {
});
});
}
}
},
},
async
handleChange
(
v
)
{
async
handleChange
(
v
)
{
const
index
=
this
.
roleList
.
findIndex
(
const
index
=
this
.
roleList
.
findIndex
(
(
item
)
=>
v
.
includes
(
item
.
role_id
)
&&
!
item
.
server_day
(
item
)
=>
v
.
includes
(
item
.
role_id
)
&&
!
item
.
server_day
...
@@ -354,6 +386,67 @@ export default {
...
@@ -354,6 +386,67 @@ export default {
}
}
);
);
},
},
/**
* 打开带教记录弹窗
*/
openMentorRecordDrawer
(
roleItem
)
{
console
.
log
(
roleItem
,
'roleItem'
)
this
.
currentRoleId
=
roleItem
.
role_id
this
.
currentRoleName
=
`
${
roleItem
.
role_name
}
-
${
roleItem
.
server_name
}
`
this
.
showMentorRecord
=
true
},
/**
* 带教记录刷新后,更新角色列表中的带教次数
*/
async
handleMentorRecordRefresh
(
roleId
,
teachingListLength
)
{
// 重新获取角色列表,更新带教次数
const
index
=
this
.
roleList
.
findIndex
(
item
=>
item
.
role_id
===
roleId
)
if
(
index
!==
-
1
)
{
this
.
$set
(
this
.
roleList
[
index
],
'teach_num'
,
teachingListLength
)
}
this
.
roleList
=
this
.
roleList
.
concat
([])
},
/**
* 处理角色展开时获取带教次数
* @param {Array} openedRoleIds - 新展开的角色ID数组
*/
handleChangeRoleTeachingNum
(
openedRoleIds
)
{
if
(
!
openedRoleIds
||
openedRoleIds
.
length
===
0
)
{
return
}
// 遍历新展开的角色,获取带教次数
openedRoleIds
.
forEach
(
roleId
=>
{
const
roleItem
=
this
.
roleList
.
find
(
item
=>
item
.
role_id
===
roleId
)
if
(
roleItem
)
{
// 如果已经存在 teach_num 字段,则不请求接口
if
(
roleItem
.
teach_num
===
undefined
||
roleItem
.
teach_num
===
null
)
{
this
.
getRoleTeachingNum
(
roleId
)
}
}
})
},
/**
* 获取角色带教次数
* @param {String|Number} roleId - 角色ID
*/
async
getRoleTeachingNum
(
roleId
)
{
try
{
const
res
=
await
roleTeachingNum
({
role_id
:
roleId
})
console
.
log
(
res
,
'res'
)
if
(
res
.
status_code
===
1
)
{
// 更新对应角色的 teach_num 字段
const
index
=
this
.
roleList
.
findIndex
(
item
=>
item
.
role_id
===
roleId
)
if
(
index
!==
-
1
)
{
this
.
$set
(
this
.
roleList
[
index
],
'teach_num'
,
res
.
data
.
data
?.
role_teaching_num
||
0
)
this
.
roleList
=
[...
this
.
roleList
]
}
}
}
catch
(
error
)
{
console
.
error
(
'获取带教次数失败:'
,
error
)
}
}
},
},
beforeDestroy
()
{
beforeDestroy
()
{
this
.
recentActivitiesPopupInstance
.
destroy
();
this
.
recentActivitiesPopupInstance
.
destroy
();
...
...
src/views/components/skill/skillPersonal.vue
浏览文件 @
7af060b5
...
@@ -140,7 +140,6 @@ export default {
...
@@ -140,7 +140,6 @@ export default {
this
.
requestGroup
()
this
.
requestGroup
()
}
,
}
,
methods
:
{
methods
:
{
// ...mapMutations('common', ['set_sendSkillMessage', 'set_isEditSkill']),
sendMessage
:
debounce
(
function
(
item
,
id
)
{
sendMessage
:
debounce
(
function
(
item
,
id
)
{
console
.
log
(
item
,
id
,
'sendMessage'
)
console
.
log
(
item
,
id
,
'sendMessage'
)
}
,
500
),
}
,
500
),
...
@@ -150,11 +149,6 @@ export default {
...
@@ -150,11 +149,6 @@ export default {
// 复制内容到粘贴板
// 复制内容到粘贴板
if
(
item
.
msgtype
==
'text'
)
{
if
(
item
.
msgtype
==
'text'
)
{
if
(
item
&&
item
.
text
&&
item
.
text
.
content
)
{
if
(
item
&&
item
.
text
&&
item
.
text
.
content
)
{
// copyToClipboard(
// item.text.content,
// (message) => this.$message.success(message),
// (message) => this.$message.error(message)
// )
this
.
sendChatMessage
(
item
.
text
.
content
)
this
.
sendChatMessage
(
item
.
text
.
content
)
}
}
}
else
if
(
item
.
msgtype
==
'image'
&&
item
.
image
.
picurl
)
{
}
else
if
(
item
.
msgtype
==
'image'
&&
item
.
image
.
picurl
)
{
...
...
src/views/userInfo/components/Info.vue
浏览文件 @
7af060b5
...
@@ -389,7 +389,7 @@ export default {
...
@@ -389,7 +389,7 @@ export default {
}
,
}
,
methods
:
{
methods
:
{
...
mapMutations
(
'game'
,
[
'set_accountSelect'
,
'accountSelect'
]),
...
mapMutations
(
'game'
,
[
'set_accountSelect'
]),
...
mapActions
(
'user'
,
[
'initWecom'
]),
...
mapActions
(
'user'
,
[
'initWecom'
]),
// 初始化企业微信SDK
// 初始化企业微信SDK
...
...
src/views/userInfo/components/gameInfo/mentorRecord.vue
0 → 100644
浏览文件 @
7af060b5
<!--
* @Author: 金多虾 937667504@qq.com
* @Date: 2025-12-11 11:01:15
* @LastEditors: 金多虾 937667504@qq.com
* @LastEditTime: 2025-12-20 11:25:56
* @FilePath: /company_wx_frontend/src/views/works/component/gameInfo/roleInfo/mentorRecord.vue
* @Description: 带教记录组件
-->
<
template
>
<div
class=
"mentor-record-page"
>
<!-- 提示信息和添加按钮区域 -->
<div
class=
"mentor-record-page__toolbar"
>
<el-button
v-if=
"teachingList.length
<
5
"
type=
"primary"
size=
"small"
@
click=
"showAddForm = !showAddForm"
>
添加记录
</el-button>
</div>
<!-- 新增记录表单 -->
<div
v-if=
"showAddForm && teachingList.length
<
5
"
class=
"mentor-record-page__add-form"
>
<el-input
v-model=
"formData.content"
type=
"textarea"
:rows=
"3"
placeholder=
"请输入"
maxlength=
"500"
show-word-limit
class=
"mentor-record-page__add-form-input"
/>
<div
class=
"mentor-record-page__add-form-buttons"
>
<el-button
size=
"mini"
@
click=
"handleCancelAdd"
>
取消
</el-button>
<el-button
type=
"primary"
size=
"mini"
:loading=
"submitLoading"
@
click=
"handleSubmitAdd"
>
保存
</el-button>
</div>
</div>
<!-- 带教记录列表 -->
<div
class=
"mentor-record-page__list"
>
<div
v-for=
"(item, index) in teachingList"
:key=
"item.id || index"
class=
"mentor-record-page__list-item"
>
<p
class=
"mentor-record-page__list-item-title"
>
第
{{
item
.
teaching_num
}}
次带教
</p>
<p
class=
"mentor-record-page__list-item-content"
>
{{
item
.
teaching_text
}}
</p>
<div
class=
"mentor-record-page__list-item-footer"
>
<span
class=
"mentor-record-page__list-item-creator"
>
新增人:
{{
item
.
update_user
||
'-'
}}
</span>
<span
class=
"mentor-record-page__list-item-divider"
>
|
</span>
<span
class=
"mentor-record-page__list-item-time"
>
{{
item
.
update_time
}}
</span>
</div>
</div>
<div
v-if=
"teachingList.length === 0 && !loading"
class=
"mentor-record-page__empty"
>
<svg-icon
icon-class=
"noContent"
/>
<p>
暂无带教记录
</p>
</div>
</div>
</div>
</
template
>
<
script
>
import
{
roleTeachingList
,
roleTeachingAdd
}
from
'@/api/game'
import
{
mapState
}
from
'vuex'
export
default
{
name
:
'MentorRecord'
,
props
:
{
roleId
:
{
type
:
[
String
,
Number
],
required
:
true
},
},
data
()
{
return
{
loading
:
false
,
submitLoading
:
false
,
showAddForm
:
false
,
teachingList
:
[],
formData
:
{
content
:
''
}
}
},
watch
:
{
roleId
:
{
immediate
:
true
,
handler
(
newVal
)
{
if
(
newVal
)
{
this
.
getTeachingList
()
}
}
}
},
computed
:
{
...
mapState
(
'user'
,
[
'userInfo'
])
},
methods
:
{
/**
* 获取带教记录列表
*/
async
getTeachingList
()
{
if
(
!
this
.
roleId
)
{
return
}
try
{
this
.
loading
=
true
const
res
=
await
roleTeachingList
({
role_id
:
this
.
roleId
})
if
(
res
.
status_code
===
1
)
{
this
.
teachingList
=
res
.
data
.
data
||
[]
// 按teaching_num倒序排列
this
.
teachingList
.
sort
((
a
,
b
)
=>
{
return
(
b
.
teaching_num
||
0
)
-
(
a
.
teaching_num
||
0
)
})
}
else
{
this
.
$message
({
message
:
res
.
data
.
msg
||
'获取带教记录失败'
,
type
:
'error'
})
}
}
catch
(
error
)
{
console
.
error
(
'获取带教记录失败:'
,
error
)
this
.
$message
({
message
:
'获取带教记录失败,请稍后重试'
,
type
:
'error'
})
}
finally
{
this
.
loading
=
false
}
},
/**
* 新增带教记录
*/
async
handleSubmitAdd
()
{
if
(
!
this
.
formData
.
content
||
!
this
.
formData
.
content
.
trim
())
{
this
.
$message
({
message
:
'请输入带教记录内容'
,
type
:
'warning'
})
return
}
try
{
this
.
submitLoading
=
true
const
res
=
await
roleTeachingAdd
({
role_id
:
this
.
roleId
,
teaching_num
:
this
.
teachingList
.
length
+
1
,
teaching_text
:
this
.
formData
.
content
.
trim
(),
create_user_id
:
this
.
userInfo
.
id
,
create_user
:
this
.
userInfo
.
username
})
if
(
res
.
status_code
===
1
)
{
this
.
$message
({
message
:
res
.
data
.
msg
||
'添加成功'
,
type
:
'success'
})
this
.
formData
.
content
=
''
this
.
showAddForm
=
false
// 重新获取列表
await
this
.
getTeachingList
()
// 通知父组件更新带教次数
this
.
$emit
(
'refresh'
,
this
.
roleId
,
this
.
teachingList
.
length
)
}
else
{
this
.
$message
({
message
:
res
.
data
.
msg
||
'添加失败'
,
type
:
'error'
})
}
}
catch
(
error
)
{
console
.
error
(
'新增带教记录失败:'
,
error
)
this
.
$message
({
message
:
'添加失败,请稍后重试'
,
type
:
'error'
})
}
finally
{
this
.
submitLoading
=
false
}
},
/**
* 取消新增
*/
handleCancelAdd
()
{
this
.
formData
.
content
=
''
this
.
showAddForm
=
false
},
}
}
</
script
>
<
style
lang=
"scss"
scoped
>
.mentor-record-page
{
width
:
100%
;
height
:
100%
;
padding
:
12px
;
padding-top
:
0
;
background
:
#fff
;
border-right
:
1px
solid
#ebedf0
;
display
:
flex
;
flex-direction
:
column
;
overflow
:
hidden
;
&__header
{
display
:
flex
;
align-items
:
center
;
padding
:
12px
0
;
padding-top
:
0
;
border-bottom
:
1px
solid
#ebedf0
;
&-title
{
font-family
:
PingFangSC-Medium
,
PingFang
SC
;
font-size
:
14px
;
font-weight
:
500
;
line-height
:
22px
;
color
:
#131920
;
}
}
&
__toolbar
{
display
:
flex
;
align-items
:
center
;
justify-content
:
flex-end
;
margin-bottom
:
20px
;
&-tip
{
font-family
:
PingFangSC-Regular
,
PingFang
SC
;
font-size
:
12px
;
font-weight
:
400
;
line-height
:
20px
;
color
:
#909399
;
}
}
&
__add-form
{
display
:
flex
;
flex-direction
:
column
;
gap
:
8px
;
margin-bottom
:
12px
;
&-input
{
::v-deep
.el-textarea__inner
{
border
:
1px
solid
#d6d9e0
;
border-radius
:
6px
;
padding
:
4px
6px
;
font-size
:
13px
;
line-height
:
22px
;
color
:
#323335
;
min-height
:
60px
;
resize
:
none
;
&::placeholder
{
color
:
#c9cdd4
;
}
}
}
&
-buttons
{
display
:
flex
;
gap
:
8px
;
justify-content
:
flex-end
;
}
}
&
__list
{
flex
:
1
;
overflow-y
:
auto
;
display
:
flex
;
flex-direction
:
column
;
gap
:
12px
;
&-item
{
background
:
#fff
;
border
:
1px
solid
#ebedf0
;
border-radius
:
6px
;
padding
:
8px
;
display
:
flex
;
flex-direction
:
column
;
gap
:
4px
;
&-title
{
font-family
:
PingFangSC-Regular
,
PingFang
SC
;
font-size
:
12px
;
font-weight
:
400
;
line-height
:
20px
;
color
:
#6d7176
;
}
&
-content
{
font-family
:
PingFangSC-Regular
,
PingFang
SC
;
font-size
:
15px
;
font-weight
:
500
;
line-height
:
22px
;
color
:
#131920
;
word-break
:
break-all
;
}
&
-footer
{
display
:
flex
;
align-items
:
center
;
gap
:
4px
;
}
&
-creator
,
&
-time
{
font-family
:
PingFangSC-Regular
,
PingFang
SC
;
font-size
:
12px
;
font-weight
:
400
;
line-height
:
20px
;
color
:
#b0b2b5
;
}
&
-divider
{
color
:
#ebedf0
;
font-size
:
12px
;
}
}
}
&
__empty
{
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
justify-content
:
center
;
padding
:
40px
0
;
color
:
#909399
;
font-size
:
14px
;
p
{
margin-top
:
12px
;
}
}
}
</
style
>
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论