提交 9e546236 作者: 毛细亚

合并分支 'shw-feat-7.1' 到 'test'

Shw feat 7.1

查看合并请求 !38
<!DOCTYPE html> <!DOCTYPE html>
<html lang=""> <html lang="">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0"> <meta name="viewport" content="width=device-width,initial-scale=1.0" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico"> <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<!-- HTTP 1.1 --> <!-- HTTP 1.1 -->
<meta http-equiv="pragma" content="no-cache"> <meta http-equiv="pragma" content="no-cache" />
<!-- HTTP 1.0 --> <!-- HTTP 1.0 -->
<meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="cache-control" content="no-cache" />
<!-- Prevent caching at the proxy server --> <!-- Prevent caching at the proxy server -->
<meta http-equiv="expires" content="0"> <meta http-equiv="expires" content="0" />
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE9" /> <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE9" />
<!-- <title><%= htmlWebpackPlugin.options.title %></title> --> <!-- <title><%= htmlWebpackPlugin.options.title %></title> -->
<title>企微侧边栏</title> <title>企微侧边栏</title>
<!-- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0,shrink-to-fit=no,user-scalable=no"> --> <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0,shrink-to-fit=no,user-scalable=no"> -->
<script src="https://g.alicdn.com/dingding/dinglogin/0.0.5/ddLogin.js"></script> <script src="https://g.alicdn.com/dingding/dinglogin/0.0.5/ddLogin.js"></script>
<script src="https://lf1-cdn-tos.bytegoofy.com/obj/iconpark/icons_27278_172.5464f393968eda872f41eab2242bbbd7.es5.js"></script>
</head> </head>
<body> <body>
<noscript> <noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> <strong
>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
properly without JavaScript enabled. Please enable it to
continue.</strong
>
</noscript> </noscript>
<div id="app"></div> <div id="app"></div>
</body> </body>
......
<template> <template>
<div id="app" class="mobile-app-wrapper"> <div id="app" class="mobile-app-wrapper">
<Debug /> <Debug />
<div class="mobile-menu-bar" v-if="token && external_userid && showMemberId"> <div
class="mobile-menu-bar"
v-if="token && external_userid && showMemberId"
>
<!-- 临时调试信息 --> <!-- 临时调试信息 -->
<div class="menu-container"> <div class="menu-container">
<el-menu :default-active="selectedPath" mode="horizontal" class="mobile-el-menu" <el-menu
:class="{ 'collapsed': !isMenuExpanded && shouldShowToggle }" background-color="#fff" router :default-active="selectedPath"
@select="handleSelect" ref="menuRef"> mode="horizontal"
<el-menu-item v-for="item in menuList" :key="item.path" :index="item.path" class="mobile-menu-item"> class="mobile-el-menu"
:class="{ collapsed: !isMenuExpanded && shouldShowToggle }"
background-color="#fff"
router
@select="handleSelect"
ref="menuRef"
>
<el-menu-item
v-for="item in menuList"
:key="item.path"
:index="item.path"
class="mobile-menu-item"
>
<!-- 任务列表菜单项显示红点 --> <!-- 任务列表菜单项显示红点 -->
<div v-if="item.path === '/taskList' && hasTaskRedDot" class="menu-item-with-badge"> <div
v-if="item.path === '/taskList' && hasTaskRedDot"
class="menu-item-with-badge"
>
<div class="task-badge"> <div class="task-badge">
<el-badge is-dot> <el-badge is-dot>
<span>{{ item.label }}</span> <span>{{ item.label }}</span>
...@@ -22,9 +40,17 @@ ...@@ -22,9 +40,17 @@
</el-menu> </el-menu>
<!-- 展开收起按钮 --> <!-- 展开收起按钮 -->
<el-button type="text" size="mini" v-if="shouldShowToggle" class="menu-toggle-btn" @click="toggleMenu"> <el-button
<i :class="isMenuExpanded ? 'el-icon-arrow-up' : 'el-icon-arrow-down'"></i> type="text"
<span>{{ isMenuExpanded ? '收起' : '展开' }}</span> size="mini"
v-if="shouldShowToggle"
class="menu-toggle-btn"
@click="toggleMenu"
>
<i
:class="isMenuExpanded ? 'el-icon-arrow-up' : 'el-icon-arrow-down'"
></i>
<span>{{ isMenuExpanded ? "收起" : "展开" }}</span>
</el-button> </el-button>
</div> </div>
...@@ -37,25 +63,25 @@ ...@@ -37,25 +63,25 @@
</div> </div>
</template> </template>
<script> <script>
import bindUserList from '@/views/components/bindGameAccount/bindUserList.vue' import bindUserList from "@/views/components/bindGameAccount/bindUserList.vue";
import { getToken } from '@/utils/auth' import { getToken } from "@/utils/auth";
import { mapState, mapMutations, mapActions } from 'vuex' import { mapState, mapMutations, mapActions } from "vuex";
import Cookies from 'js-cookie' import Cookies from "js-cookie";
import { getParams } from '@/utils/index' import { getParams } from "@/utils/index";
import Debug from '@/components/debug.vue' import Debug from "@/components/debug.vue";
export default { export default {
name: 'App', name: "App",
components: { components: {
bindUserList, bindUserList,
Debug Debug,
}, },
data() { data() {
return { return {
menuList: [ menuList: [
{ {
label: '客户资料', label: "客户资料",
path: '/userInfo' path: "/userInfo",
}, },
// { // {
// label: '角色信息', // label: '角色信息',
...@@ -66,16 +92,16 @@ export default { ...@@ -66,16 +92,16 @@ export default {
// path: '/orderList' // path: '/orderList'
// }, // },
{ {
label: '快捷回复', label: "快捷回复",
path: '/quickReply' path: "/quickReply",
}, },
// { // {
// label: '违规记录', // label: '违规记录',
// path: '/violationRecord' // path: '/violationRecord'
// }, // },
{ {
label: '礼包记录', label: "礼包记录",
path: '/giftRecord' path: "/giftRecord",
}, },
// { // {
...@@ -83,188 +109,220 @@ export default { ...@@ -83,188 +109,220 @@ export default {
// path: '/taskRecord' // path: '/taskRecord'
// }, // },
{ {
label: '申请记录', label: "申请记录",
path: '/applyRecord' path: "/applyRecord",
}, },
{ {
label: '通讯录', label: "通讯录",
path: '/addressBook' path: "/addressBook",
}, },
{ {
label: '快捷发送', label: "快捷发送",
path: '/quickSendGame' path: "/quickSendGame",
}, },
{ {
label: '任务列表', label: "任务列表",
path: '/taskList', path: "/taskList",
hasRedDot: false // 红点状态 hasRedDot: false, // 红点状态
}, },
{ {
label: '微言助手', label: "微言助手",
path: '/aiChat' path: "/aiChat",
}, },
// { // {
// label: '通讯录', // label: '通讯录',
// path: '/addressBook' // path: '/addressBook'
// }, // },
], ],
selectedPath: '/userInfo', selectedPath: "/userInfo",
showMemberId: false, showMemberId: false,
isMenuExpanded: false, // 菜单展开状态 isMenuExpanded: false, // 菜单展开状态
shouldShowToggle: false, // 是否显示展开收起按钮 shouldShowToggle: false, // 是否显示展开收起按钮
} };
}, },
computed: { computed: {
...mapState('user', ['external_userid', 'token', 'userInfo']), ...mapState("user", ["external_userid", "token", "userInfo"]),
...mapState('game', ['taskData']), ...mapState("game", ["taskData"]),
// 计算任务列表是否需要显示红点 // 计算任务列表是否需要显示红点
hasTaskRedDot() { hasTaskRedDot() {
return this.taskData.user_task > 0 || this.taskData.account_task > 0 return this.taskData.user_task > 0 || this.taskData.account_task > 0;
} },
}, },
watch: { watch: {
'$route.path'(val) { "$route.path"(val) {
// 处理各种可能的路径情况 // 处理各种可能的路径情况
if (val === '/' || val === '/index.html') { if (val === "/" || val === "/index.html") {
this.selectedPath = '/userInfo' this.selectedPath = "/userInfo";
} else { } else {
this.selectedPath = val this.selectedPath = val;
} }
console.log('路由变化:', val, '选中路径:', this.selectedPath) console.log("路由变化:", val, "选中路径:", this.selectedPath);
}, },
// 监听用户信息变化,只在初始化时获取一次任务数据 // 监听用户信息变化,只在初始化时获取一次任务数据
userInfo: { userInfo: {
handler(newVal, oldVal) { handler(newVal, oldVal) {
if (newVal && newVal.id && (!oldVal || !oldVal.id) && this.token) { if (newVal && newVal.id && (!oldVal || !oldVal.id) && this.token) {
console.log('用户信息初始化完成,获取任务数据:', newVal) console.log("用户信息初始化完成,获取任务数据:", newVal);
// 只在用户信息第一次设置时获取任务数据 // 只在用户信息第一次设置时获取任务数据
this.getTaskUnReadData() this.getTaskUnReadData();
} }
}, },
deep: true, deep: true,
immediate: true immediate: true,
}, },
// 监听 external_userid 的变化,确保界面及时更新 // 监听 external_userid 的变化,确保界面及时更新
external_userid: { external_userid: {
handler(newVal) { handler(newVal) {
if (newVal) { if (newVal) {
this.$nextTick(() => { this.$nextTick(() => {
this.showMemberId = true this.showMemberId = true;
console.log('external_userid 已设置:', newVal, window.location.href, this.token, Cookies.get('token')) console.log(
"external_userid 已设置:",
newVal,
window.location.href,
this.token,
Cookies.get("token")
);
// 强制更新组件 // 强制更新组件
this.$forceUpdate() this.$forceUpdate();
// 检查是否需要显示展开收起按钮 // 检查是否需要显示展开收起按钮
this.checkMenuOverflow() this.checkMenuOverflow();
}) });
} }
}, },
immediate: true immediate: true,
} },
}, },
created() { created() {
const urlParams = getParams(); const urlParams = getParams();
// 每次进入页面都缓存corp_id // 每次进入页面都缓存corp_id
if (urlParams.corp_id) { if (urlParams.corp_id) {
this.cacheCorp_id(urlParams.corp_id) // 缓存 corp_id this.cacheCorp_id(urlParams.corp_id); // 缓存 corp_id
} }
}, },
mounted() { mounted() {
// 页面刷新时从 Cookie 恢复 token 到 store // 页面刷新时从 Cookie 恢复 token 到 store
const cookieToken = Cookies.get('token') // Cookies.set(
// "token",
// "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOjQwOTAsImRhdGEiOnsiY3Nlcl9pZCI6NDA5MCwiY3Nlcl9uYW1lIjoi5q-b57uG5LqaIn0sImlhdCI6MTc2NTE3MjI0NywiZXhwIjoxNzY3NzY0MjQ3LCJuYmYiOjE3NjUxNzIyNDcsInN1YiI6InRva2Vu6K6k6K-BIiwianRpIjoiN2Q5NjYxNDVjNjgyZWU0Y2UyY2Y2MTc2ZjA0NTNlNGMifQ.QpEtYzoXK11RHwn8la-OMoS-BnlTyEEAa0lmlpYu2IQ"
// );
// Cookies.set("corp_id", "wweaefe716636df3d1");
// Cookies.set("userid", "maoxiya");
// Cookies.set("cser_name", "毛细亚");
// Cookies.set("external_userid", "wm5rUgMgAAG_vfF4AHClsrS1S6MImVsQ");
// Cookies.set("cser_id", 4090);
// Cookies.set("weixin_blongs_id", 2862);
const cookieToken = Cookies.get("token");
if (cookieToken && !this.token) { if (cookieToken && !this.token) {
this.set_token(cookieToken) this.set_token(cookieToken);
console.log('从 Cookie 恢复 token:', cookieToken) console.log("从 Cookie 恢复 token:", cookieToken);
} }
// 初始化时处理路径 // 初始化时处理路径
const currentPath = this.$route.path const currentPath = this.$route.path;
if (currentPath === '/' || currentPath === '' || currentPath === '/index.html') { if (
this.selectedPath = '/userInfo' currentPath === "/" ||
currentPath === "" ||
currentPath === "/index.html"
) {
this.selectedPath = "/userInfo";
} else { } else {
this.selectedPath = currentPath this.selectedPath = currentPath;
} }
console.log('创建时路径:', currentPath, '选中路径:', this.selectedPath) console.log("创建时路径:", currentPath, "选中路径:", this.selectedPath);
// 监听窗口大小变化 // 监听窗口大小变化
window.addEventListener('resize', this.handleResize) window.addEventListener("resize", this.handleResize);
// 初始检查 // 初始检查
this.$nextTick(() => { this.$nextTick(() => {
this.checkMenuOverflow() this.checkMenuOverflow();
this.initVuexValue() this.initVuexValue();
}) });
}, },
beforeDestroy() { beforeDestroy() {
window.removeEventListener('resize', this.handleResize) window.removeEventListener("resize", this.handleResize);
// 移除 localStorage 中的 weixin_blongs_id
localStorage.removeItem("weixin_blongs_id");
}, },
methods: { methods: {
...mapMutations('user', ['set_userid', 'set_corp_id', 'set_token', 'set_cser_info', 'set_cser_id', 'set_cser_name', 'set_userInfo']), ...mapMutations("user", [
...mapMutations('game', ['set_accountSelect']), "set_userid",
...mapActions('game', ['getTaskUnReadData']), "set_corp_id",
"set_token",
"set_cser_info",
"set_cser_id",
"set_cser_name",
"set_userInfo",
]),
...mapMutations("game", ["set_accountSelect"]),
...mapActions("game", ["getTaskUnReadData"]),
// 设置缓存 // 设置缓存
cacheCorp_id(corp_id) { cacheCorp_id(corp_id) {
Cookies.set('corp_id', corp_id, { expires: 30 }) Cookies.set("corp_id", corp_id, { expires: 30 });
this.set_corp_id(corp_id) this.set_corp_id(corp_id);
}, },
initVuexValue() { initVuexValue() {
this.set_userid(Cookies.get('userid')) this.set_userid(Cookies.get("userid"));
this.set_corp_id(Cookies.get('corp_id')) this.set_corp_id(Cookies.get("corp_id"));
this.set_token(Cookies.get('token')) this.set_token(Cookies.get("token"));
this.set_cser_id(Cookies.get('cser_id')) this.set_cser_id(Cookies.get("cser_id"));
this.set_cser_name(Cookies.get('cser_name')) this.set_cser_name(Cookies.get("cser_name"));
const userinfo = { const userinfo = {
cser_id: Cookies.get('cser_id'), cser_id: Cookies.get("cser_id"),
cser_name: Cookies.get('cser_name'), cser_name: Cookies.get("cser_name"),
username: Cookies.get('cser_name'), username: Cookies.get("cser_name"),
id: Cookies.get('cser_id'), id: Cookies.get("cser_id"),
} };
this.set_userInfo(userinfo) this.set_userInfo(userinfo);
const cser_info = Cookies.get('cser_info') const cser_info = Cookies.get("cser_info");
cser_info ? this.set_cser_info(JSON.parse(cser_info)) : this.set_cser_info({}) cser_info
? this.set_cser_info(JSON.parse(cser_info))
: this.set_cser_info({});
}, },
handleSelect(key, keyPath) { handleSelect(key, keyPath) {
console.log('菜单选择:', key, keyPath, window.location.href) console.log("菜单选择:", key, keyPath, window.location.href);
}, },
// 切换菜单展开收起状态 // 切换菜单展开收起状态
toggleMenu() { toggleMenu() {
this.isMenuExpanded = !this.isMenuExpanded this.isMenuExpanded = !this.isMenuExpanded;
}, },
// 检查菜单是否需要换行 // 检查菜单是否需要换行
checkMenuOverflow() { checkMenuOverflow() {
this.$nextTick(() => { this.$nextTick(() => {
const menuElement = this.$refs.menuRef?.$el const menuElement = this.$refs.menuRef?.$el;
if (!menuElement) return if (!menuElement) return;
// 临时展开菜单来检查实际高度 // 临时展开菜单来检查实际高度
const wasCollapsed = !this.isMenuExpanded && this.shouldShowToggle const wasCollapsed = !this.isMenuExpanded && this.shouldShowToggle;
if (wasCollapsed) { if (wasCollapsed) {
menuElement.classList.remove('collapsed') menuElement.classList.remove("collapsed");
} }
const menuHeight = menuElement.scrollHeight const menuHeight = menuElement.scrollHeight;
const singleLineHeight = 50 // 单行高度 const singleLineHeight = 50; // 单行高度
// 如果菜单高度超过单行,说明需要换行 // 如果菜单高度超过单行,说明需要换行
this.shouldShowToggle = menuHeight > singleLineHeight + 10 // 加10px容错 this.shouldShowToggle = menuHeight > singleLineHeight + 10; // 加10px容错
// 如果不需要展开收起按钮,则直接展开 // 如果不需要展开收起按钮,则直接展开
if (!this.shouldShowToggle) { if (!this.shouldShowToggle) {
this.isMenuExpanded = true this.isMenuExpanded = true;
} else if (wasCollapsed) { } else if (wasCollapsed) {
// 恢复收起状态 // 恢复收起状态
menuElement.classList.add('collapsed') menuElement.classList.add("collapsed");
} }
}) });
}, },
// 窗口大小变化处理 // 窗口大小变化处理
handleResize() { handleResize() {
clearTimeout(this.resizeTimer) clearTimeout(this.resizeTimer);
this.resizeTimer = setTimeout(() => { this.resizeTimer = setTimeout(() => {
this.checkMenuOverflow() this.checkMenuOverflow();
}, 150) }, 150);
}
}, },
} },
};
</script> </script>
<style scoped> <style scoped>
...@@ -352,14 +410,14 @@ export default { ...@@ -352,14 +410,14 @@ export default {
overflow-y: auto; overflow-y: auto;
} }
.mobile-content>div { .mobile-content > div {
background: #fff; background: #fff;
border-radius: 8px; border-radius: 8px;
min-height: 60vh; min-height: 60vh;
padding: 10px; padding: 10px;
} }
.el-menu--horizontal>.el-menu-item { .el-menu--horizontal > .el-menu-item {
height: 35px; height: 35px;
line-height: 35px; line-height: 35px;
} }
......
...@@ -1424,3 +1424,88 @@ export function getClonePackageLink(data) { ...@@ -1424,3 +1424,88 @@ export function getClonePackageLink(data) {
}) })
}) })
} }
// 使用权益
export function useBenefit(data) {
return new Promise((resolve, reject) => {
cross_systemRequest({
system: 'zhangyou',
api: '/api/marketing_role_grade/useRight',
params: data
}).then((res) => {
resolve(res)
}).catch((error) => {
reject(error)
})
})
}
// 使用权益记录
export function useRightList(data) {
return new Promise((resolve, reject) => {
cross_systemRequest({
system: 'zhangyou',
api: '/api/marketing_role_grade/useRightList',
params: data
}).then((res) => {
resolve(res)
}).catch((error) => {
reject(error)
})
})
}
// 发送邮件
export function sendEmail(data) {
return new Promise((resolve, reject) => {
cross_systemRequest({
system: 'zhangyou',
api: '/api/operator_task/sendEmail',
params: data
}).then((res) => {
resolve(res)
}).catch((error) => {
reject(error)
})
})
}
// 获取开/合服天数
export function getServerDayApi(data) {
return new Promise((resolve, reject) => {
cross_systemRequest({
system: 'zhangyou',
api: '/api/role/getServerDay',
params: data
}).then((res) => {
resolve(res)
}).catch((error) => {
reject(error)
})
})
}
// 项目-视频分类
export function teachingVideoCategoryListApi(data) {
return new Promise((resolve, reject) => {
cross_systemRequest({
system: 'zhangyou',
api: '/api/teaching_video/categoryList',
params: data
}).then((res) => {
resolve(res)
}).catch((error) => {
reject(error)
})
})
}
// 视频列表
export function teachingVideoVideoListApi(data) {
return new Promise((resolve, reject) => {
cross_systemRequest({
system: 'zhangyou',
api: '/api/teaching_video/videoList',
params: data
}).then((res) => {
resolve(res)
}).catch((error) => {
reject(error)
})
})
}
\ No newline at end of file
...@@ -284,3 +284,19 @@ export function getUserQrCode(data) { ...@@ -284,3 +284,19 @@ export function getUserQrCode(data) {
data, data,
}); });
} }
// 打开会话绑定任务
export function clientSessionBindTaskApi(data) {
return request({
url: returnApi('/client_session/bindTask'),
method: 'post',
data,
});
}
// 根据w账号获取上一次交互时间
export function getMemberInfoApi(data) {
return request({
url: returnApi('/corp_zyou_bind/getMemberInfo'),
method: 'post',
data,
});
}
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#a)"><mask id="b" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="14" height="14"><path d="M14 0H0v14h14z" fill="#fff"/></mask><g mask="url(#b)" stroke="#267ef0" stroke-width=".875" stroke-linecap="round" stroke-linejoin="round"><path d="M9.333 7.525v2.45c0 2.042-.816 2.858-2.858 2.858h-2.45c-2.042 0-2.858-.816-2.858-2.858v-2.45c0-2.042.816-2.858 2.858-2.858h2.45c2.042 0 2.858.816 2.858 2.858"/><path d="M12.833 4.025v2.45c0 2.042-.816 2.858-2.858 2.858h-.642V7.525c0-2.042-.816-2.858-2.858-2.858H4.667v-.642c0-2.042.816-2.858 2.858-2.858h2.45c2.042 0 2.858.816 2.858 2.858"/></g></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h14v14H0z"/></clipPath></defs></svg>
\ No newline at end of file
import Vue from 'vue'
{/* <iconpark-icon name="icon-fuzhi"></iconpark-icon> */}
const copy = {
// 当被绑定的元素插入到DOM中时
inserted: function(el, binding) {
// 创建复制图标元素
const copyIcon = document.createElement('iconpark-icon')
// const copyIcon = document.createElement('div')
// copyIcon.setAttribute('icon-class', 'copy')
copyIcon.name='icon-fuzhi'
copyIcon.style.cursor = 'pointer'
copyIcon.style.marginLeft = '8px'
copyIcon.style.fontSize = '16px'
copyIcon.title = '点击复制'
copyIcon.innerHTML='<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#a)"><mask id="b" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="14" height="14"><path d="M14 0H0v14h14z" fill="#fff"/></mask><g mask="url(#b)" stroke="#267ef0" stroke-width=".875" stroke-linecap="round" stroke-linejoin="round"><path d="M9.333 7.525v2.45c0 2.042-.816 2.858-2.858 2.858h-2.45c-2.042 0-2.858-.816-2.858-2.858v-2.45c0-2.042.816-2.858 2.858-2.858h2.45c2.042 0 2.858.816 2.858 2.858"/><path d="M12.833 4.025v2.45c0 2.042-.816 2.858-2.858 2.858h-.642V7.525c0-2.042-.816-2.858-2.858-2.858H4.667v-.642c0-2.042.816-2.858 2.858-2.858h2.45c2.042 0 2.858.816 2.858 2.858"/></g></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h14v14H0z"/></clipPath></defs></svg>'
// 设置元素的position为relative,确保图标的absolute定位正确
if (getComputedStyle(el).position === 'static') {
el.style.position = 'relative'
}
// 添加复制图标到元素后面
el.insertBefore(copyIcon, el.nextSibling)
// 复制功能实现
copyIcon.addEventListener('click', async function(e) {
// 阻止事件冒泡
e.stopPropagation()
try {
// 获取要复制的内容
const textToCopy = binding.value || ''
if (!textToCopy) {
Vue.prototype.$message.warning('没有可复制的内容')
return
}
// 使用现代的剪贴板API
if (navigator.clipboard && window.isSecureContext) {
await navigator.clipboard.writeText(textToCopy)
} else {
// 兼容旧版浏览器
const textArea = document.createElement('textarea')
textArea.value = textToCopy
textArea.style.position = 'fixed'
textArea.style.left = '-999999px'
textArea.style.top = '-999999px'
document.body.appendChild(textArea)
textArea.focus()
textArea.select()
// 执行复制命令
const success = document.execCommand('copy')
document.body.removeChild(textArea)
if (!success) {
throw new Error('复制失败')
}
}
// 显示复制成功的提示
Vue.prototype.$message.success('复制成功')
} catch (error) {
console.error('复制失败:', error)
Vue.prototype.$message.error('复制失败,请手动复制')
}
})
// 存储图标引用,以便在组件卸载时清理
el.__copyIcon = copyIcon
},
// 当指令与元素解绑时
unbind: function(el) {
// 清理事件监听器和元素
if (el.__copyIcon) {
el.__copyIcon.removeEventListener('click', null)
el.parentNode.removeChild(el.__copyIcon)
delete el.__copyIcon
}
}
}
export default copy
\ No newline at end of file
import copy from './copy.js'
const install = function(Vue) {
Vue.directive('copy', copy)
}
if (window.Vue) {
window.copy = copy
Vue.use(install); // eslint-disable-line
}
copy.install = install
export default copy
...@@ -15,6 +15,7 @@ import '@/styles/index.scss'; ...@@ -15,6 +15,7 @@ import '@/styles/index.scss';
import moment from 'moment' import moment from 'moment'
import '@/styles/tailwind.css' import '@/styles/tailwind.css'
import VConsole from 'vconsole'; import VConsole from 'vconsole';
import copy from './directive/copy'
import uploading from '@/utils/cos-upload' import uploading from '@/utils/cos-upload'
import errorHandle from '@/utils/errorHandle' import errorHandle from '@/utils/errorHandle'
import { getParams,deepClone } from '@/utils/index' import { getParams,deepClone } from '@/utils/index'
...@@ -24,7 +25,7 @@ import loadmore from '@/directive/loadmore/index.js' // 加载更多 ...@@ -24,7 +25,7 @@ import loadmore from '@/directive/loadmore/index.js' // 加载更多
import clickagain from './directive/clickagain' import clickagain from './directive/clickagain'
import permission from '@/directive/permission/index.js' // 权限判断指令 import permission from '@/directive/permission/index.js' // 权限判断指令
import scroll from '@/directive/scroll' // 下拉加载更多指令 import scroll from '@/directive/scroll' // 下拉加载更多指令
Vue.use(globalComponent).use(permission).use(clickagain).use(loadmore).use(scroll) Vue.use(globalComponent).use(permission).use(clickagain).use(loadmore).use(scroll).use(copy)
// 导入 VConsole 清理工具 // 导入 VConsole 清理工具
import '@/utils/vconsoleCleanup' import '@/utils/vconsoleCleanup'
......
...@@ -14,6 +14,7 @@ const state = { ...@@ -14,6 +14,7 @@ const state = {
external_userid:'' external_userid:''
}, },
userid:Cookies.get('userid'), userid:Cookies.get('userid'),
weixin_blongs_id:localStorage.getItem('weixin_blongs_id'),//客服号项目id
corp_id:'', corp_id:'',
external_userid:'', external_userid:'',
token:'', token:'',
...@@ -37,6 +38,12 @@ const state = { ...@@ -37,6 +38,12 @@ const state = {
} }
const mutations = { const mutations = {
set_weixin_blongs_id(state,weixin_blongs_id){
state.weixin_blongs_id = weixin_blongs_id
// Cookies.set('weixin_blongs_id', weixin_blongs_id)
localStorage.setItem('weixin_blongs_id', weixin_blongs_id)
},
set_userInfo(state,userInfo){ set_userInfo(state,userInfo){
state.userInfo = userInfo state.userInfo = userInfo
}, },
......
...@@ -537,6 +537,10 @@ li { ...@@ -537,6 +537,10 @@ li {
height: 100%; height: 100%;
font-size: 300px; font-size: 300px;
} }
.el-loading-spinner{
display: flex;
justify-content: center;
}
.el-loading-spinner .circular { .el-loading-spinner .circular {
width: 60px !important; width: 60px !important;
......
<template>
<div class="h-full flex flex-col">
<el-input
placeholder="请输入内容"
prefix-icon="el-icon-search"
v-model.trim="searchText"
@input="debouncedGetVideoList"
>
</el-input>
<el-cascader
class="w-full mt-[8px]"
v-model="categoryValue"
:props="{ emitPath: false, expandTrigger: 'click' }"
:options="categoryList"
@change="debouncedGetVideoList"
></el-cascader>
<div
class="mt-[2px] space-y-[8px] flex-1 overflow-auto pb-[10px]"
v-loading="loading"
>
<div
v-for="item in videoList"
:key="item.id"
class="flex justify-between items-center py-[3px] px-[8px] bottom-[1px] border border-[#E5E7EB] rounded-[4px]"
>
<div class="text-[14px]">{{ item.video_name }}</div>
<div class="flex items-center">
<el-button
type="text"
size="small"
class="text-[12px] button-color-hover"
@click="previewVideo(item)"
>
<div class="flex items-center">
<iconpark-icon
name="xiaoxicaozuo-chakan"
class="mr-[4px] text-[14px]"
></iconpark-icon>
预览
</div>
</el-button>
<div
@click="sendVideo(item)"
class="h-[24px] ml-[8px] cursor-pointer hover:bg-[#E7F1FD] text-[12px] w-[58px] p-0 flex justify-center items-center rounded-full bg-[#F7F8FA] text-[#267EF0]"
>
<iconpark-icon
name="icon-fasonghuashu"
class="text-[14px] mr-[4px]"
></iconpark-icon>
<span> 发送</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import {
teachingVideoVideoListApi,
teachingVideoCategoryListApi,
} from "@/api/game";
import { mapMutations, mapState } from "vuex";
import { sendChatMessage } from "@/utils/index";
import { debounce } from "@/utils";
export default {
name: "InstructionalVideo",
data() {
return {
searchText: "",
categoryValue: {},
categoryList: [],
videoList: [],
debouncedGetVideoList: () => {},
loading: false,
};
},
mounted() {
this.getCategoryList();
// 初始化防抖函数,延迟300ms执行
this.debouncedGetVideoList = debounce(() => {
this.loading = true;
this.getVideoList().finally(() => {
this.loading = false;
});
}, 300);
},
computed: {
...mapState("user", ["userInfo", "weixin_blongs_id"]),
},
methods: {
...mapMutations("common", ["set_sendSkillMessage"]),
// 视频分类
async getCategoryList() {
// return;
const { data } = await teachingVideoCategoryListApi({
weixin_blongs_id: this.weixin_blongs_id,
});
this.categoryList = this.formatCategoryList(data);
},
formatCategoryList(data) {
return data.map((item) => {
return {
value: item,
label: item.main_game_name,
children: item.category.map((item) => ({
value: item,
label: item.category_name,
})),
};
});
},
// 视频列表
async getVideoList() {
if (!this.categoryValue.id) {
return;
}
const { data } = await teachingVideoVideoListApi({
weixin_blongs_id:
this.categoryValue.weixin_blongs_id || this.weixin_blongs_id,
main_game_id: this.categoryValue.main_game_id,
video_type: this.categoryValue.id,
video_name: this.searchText,
page: 1,
page_size: 200,
});
this.videoList = data.data;
},
sendVideo(item) {
try {
const link = {
title: item.video_name,
imgUrl: item.cover_url || "",
desc: "点击观看教学视频",
link: item.video_url,
};
sendChatMessage(link, "link");
} catch (error) {
console.error("发送视频链接失败:", error);
this.$message({ message: "发送视频链接失败", type: "error" });
}
},
previewVideo(item) {
window.open(item.video_url);
},
},
};
</script>
<style scoped>
.button-color-hover.el-button--text:hover {
color: #267ef0 !important;
}
.button-color-hover.el-button--text {
color: #86909c;
}
</style>
...@@ -8,22 +8,22 @@ ...@@ -8,22 +8,22 @@
> >
<div> <div>
<el-form ref="ruleForm" :model="ruleForm" label-width="100px" class="content"> <el-form ref="ruleForm" :model="ruleForm" label-width="100px" class="content">
<el-form-item label="选择角色"> <el-form-item label="选择角色:">
<el-select v-model="ruleForm.role_id" placeholder="请选择角色" style="width:90%;margin-bottom:10px;" @change="selectRole"> <el-select v-model="ruleForm.role_id" placeholder="请选择角色" style="width:90%;margin-bottom:10px;" @change="selectRole">
<el-option <el-option
v-for="(item,index) in roleList" v-for="(item,index) in roleList"
:key="index+1" :key="item.value"
:label="item.label" :label="item.label"
:value="item.value" :value="item.value"
> >
</el-option> </el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="活动类型"> <el-form-item label="活动类型:">
<el-select v-model="ruleForm.gift_type" placeholder="请选择" style="width:90%;margin-bottom:10px;" @change="giftTypeResult"> <el-select v-model="ruleForm.gift_type" placeholder="请选择" style="width:90%;margin-bottom:10px;" @change="giftTypeResult">
<el-option <el-option
v-for="(item,index) in giftTypeList" v-for="(item,index) in giftTypeList"
:key="index+1" :key="item.value"
:label="item.label" :label="item.label"
:value="item.value" :value="item.value"
> >
...@@ -31,11 +31,11 @@ ...@@ -31,11 +31,11 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<!-- 活动类型为角色累充的时候 活动可以多选其他的都为单选 --> <!-- 活动类型为角色累充的时候 活动可以多选其他的都为单选 -->
<el-form-item label="选择活动" prop="rule_id"> <el-form-item label="选择活动:" prop="rule_id">
<el-select v-model="ruleForm.rule_id" :disabled="activeList.length==0" placeholder="请选择" style="width:90%;margin-bottom:10px;" :multiple="ruleForm.gift_type==1 || ruleForm.gift_type == 4 || ruleForm.gift_type== 5 " clearable @change="activeListResult"> <el-select v-model="ruleForm.rule_id" :disabled="activeList.length==0" placeholder="请选择" style="width:90%;margin-bottom:10px;" :multiple="ruleForm.gift_type==1 || ruleForm.gift_type == 4 || ruleForm.gift_type== 5 " clearable @change="activeListResult">
<el-option <el-option
v-for="(item,index) in activeList" v-for="(item,index) in activeList"
:key="index+1" :key="item.id"
:label="item.title_name" :label="item.title_name"
:value="item.id" :value="item.id"
> >
...@@ -56,16 +56,16 @@ ...@@ -56,16 +56,16 @@
</el-form> </el-form>
<!-- 申请礼包 --> <!-- 申请礼包 -->
<!-- 角色累充 --> <!-- 角色累充 -->
<roleRecharge v-if="showGiftDetails && (ruleForm.gift_type==1 || ruleForm.gift_type==4 || ruleForm.gift_type==5) && roleActiveInfo.length>0" :show.sync="showGiftDetails" :request-loading="requestLoading" :active-info="roleActiveInfo" :gift-info="giftDetailsInfo" title="礼包详情" /> <roleRecharge v-if="showGiftDetails && (ruleForm.gift_type==1 || ruleForm.gift_type==4 || ruleForm.gift_type==5) && roleActiveInfo.length>0" :show.sync="showGiftDetails" :request-loading="requestLoading" :active-info="roleActiveInfo" :task_id="task_id" :gift-info="giftDetailsInfo" title="礼包详情" />
<!-- 时间段累充 和 单日累充 积分关的情况 --> <!-- 时间段累充 和 单日累充 积分关的情况 -->
<roleTimeRecharge v-if="showGiftDetails && (ruleForm.gift_type==2 || (ruleForm.gift_type==3 && activeInfo.exchange_score_status==2 ) ) && activeInfo.id " :change-date="changeDate" :request-loading="requestLoading" :show.sync="showGiftDetails" :active-info="activeInfo" :gift-info="giftDetailsInfo" title="礼包详情" @changeDateResult="changeDateResult" @giftDetailsInfo="requestDetailsInfo" /> <roleTimeRecharge v-if="showGiftDetails && (ruleForm.gift_type==2 || ruleForm.gift_type == 7 || (ruleForm.gift_type==3 && activeInfo.exchange_score_status==2 ) ) && activeInfo.id " :change-date="changeDate" :request-loading="requestLoading" :task_id="task_id" :show.sync="showGiftDetails" :active-info="activeInfo" :gift-info="giftDetailsInfo" title="礼包详情" @changeDateResult="changeDateResult" @giftDetailsInfo="requestDetailsInfo" />
<!-- 单日累充 积分开的情况 --> <!-- 单日累充 积分开的情况 显示 svip 权益 并且可以选择 svip权益-->
<oneDayCharge v-if="showGiftDetails && ruleForm.gift_type==3 && activeInfo.exchange_score_status==1 && activeInfo.id" :show.sync="showGiftDetails" :request-loading="requestLoading" :active-info="activeInfo" :change-date="changeDate" :gift-info="giftDetailsInfo" title="礼包详情" @changeDateResult="changeDateResult" @giftDetailsInfo="requestDetailsInfo" /> <oneDayCharge v-if="showGiftDetails && (ruleForm.gift_type==3 || ruleForm.gift_type == 7) && activeInfo.exchange_score_status==1 && activeInfo.id" :show.sync="showGiftDetails" :task_id="task_id" :request-loading="requestLoading" :active-info="activeInfo" :change-date="changeDate" :gift-info="giftDetailsInfo" title="礼包详情" @changeDateResult="changeDateResult" @giftDetailsSVIPInfo="giftDetailsSVIPInfo" @giftDetailsInfo="requestDetailsInfo" />
</div> </div>
</el-drawer> </el-drawer>
</template> </template>
<script type="text/javascript"> <script type="text/javascript">
import { roleList, activeList, giftBagApply, giftTypeList, giftDetailsData } from '@/api/game' import { getRoleHoLo, activeList, giftBagApply, giftTypeList, giftDetailsData } from '@/api/game'
import { mapState, mapMutations, mapActions } from 'vuex' import { mapState, mapMutations, mapActions } from 'vuex'
// import giftDetails from './giftDetails.vue' // import giftDetails from './giftDetails.vue'
import roleRecharge from './giftDetails/roleRecharge.vue' import roleRecharge from './giftDetails/roleRecharge.vue'
...@@ -79,8 +79,8 @@ ...@@ -79,8 +79,8 @@
oneDayCharge, // 单日累充 oneDayCharge, // 单日累充
roleTimeRecharge // 角色时间段累充 roleTimeRecharge // 角色时间段累充
}, },
// type 3:image 4:video // type 3:image 4:video task_id // 账号任务点击礼包申请过来传递的任务id member_id // 我的任务 任务详情 点击 礼包申请的时候 需要用到任务详情的 member_id,这时候需要传递过来
props: ['show', 'width', 'title'], props: ['show', 'width', 'title', 'task_id','member_id'],
data() { data() {
return { return {
roleList: [], roleList: [],
...@@ -124,6 +124,15 @@ ...@@ -124,6 +124,15 @@
this.requestRoleList() this.requestRoleList()
this.giftTypeListData() this.giftTypeListData()
}, },
beforeDestroy() {
// 清理组件销毁时的状态,防止内存泄漏
this.roleList = []
this.activeList = []
this.giftTypeList = []
this.roleActiveInfo = []
this.activeInfo = {}
this.giftDetailsInfo = {}
},
methods: { methods: {
requestActiveList() { requestActiveList() {
if (this.ruleForm.role_id !== '' && this.ruleForm.gift_type !== '') { if (this.ruleForm.role_id !== '' && this.ruleForm.gift_type !== '') {
...@@ -156,15 +165,18 @@ ...@@ -156,15 +165,18 @@
}) })
}, },
requestRoleList() { requestRoleList() {
if (this.accountSelect == '') { if (this.accountSelect == '' && !this.member_id) {
this.$message.warning('暂无关联的账号,请先去关联账号!') this.$message.warning('暂无关联的账号,请先去关联账号!')
return false return false
} }
const data = { const data = {
api_search_name: '', api_search_name: '',
member_id: this.accountSelect member_id:this.member_id || this.accountSelect, // 先取任务详情的member_id,没有的话取账号的member_id
search_type: 'list',
page_size:100,
page:1
} }
roleList(data).then(res => { getRoleHoLo(data).then(res => {
if (res.status_code == 1) { if (res.status_code == 1) {
if (res.data.data.length > 0) { if (res.data.data.length > 0) {
const list = res.data.data.sort((a, b) => { return Number(b.recharge_total) - Number(a.recharge_total) }) const list = res.data.data.sort((a, b) => { return Number(b.recharge_total) - Number(a.recharge_total) })
...@@ -197,7 +209,7 @@ ...@@ -197,7 +209,7 @@
this.activeList = [] this.activeList = []
const gift_type = this.giftTypeList.find(item => item.value == data) const gift_type = this.giftTypeList.find(item => item.value == data)
console.log(gift_type, 'gift_type') console.log(gift_type, 'gift_type')
this.gift_type_text = gift_type.label this.gift_type_text = gift_type.label || ''
this.requestActiveList() this.requestActiveList()
this.activeInfo = {} this.activeInfo = {}
this.giftInfo = {} this.giftInfo = {}
...@@ -246,7 +258,7 @@ ...@@ -246,7 +258,7 @@
this.showGiftDetails = true this.showGiftDetails = true
} else { } else {
this.ruleForm.recharge_date = '' this.ruleForm.recharge_date = ''
if (this.ruleForm.gift_type == 2) { if (this.ruleForm.gift_type == 2 || this.ruleForm.gift_type == 7) {
this.requestGiftDetails() this.requestGiftDetails()
this.showGiftDetails = true this.showGiftDetails = true
} }
...@@ -274,6 +286,21 @@ ...@@ -274,6 +286,21 @@
this.$message.warning('请选择充值日期') this.$message.warning('请选择充值日期')
} }
}, },
// 积分开的情况 显示 svip 权益 并且可以选择 svip权益
giftDetailsSVIPInfo(params){
console.log(params, 'params')
const data = {
role_id: this.ruleForm.role_id,
rule_id: this.ruleForm.rule_id.toString(),
recharge_date: params.recharge_date || '',
right_type: params.right_type || '',
select_type: params.select_type || ''
}
giftDetailsData(data).then(res => {
this.giftDetailsInfo = res.data
this.showGiftDetails = true
})
},
requestGiftDetails(value) { requestGiftDetails(value) {
const data = { const data = {
role_id: this.ruleForm.role_id, role_id: this.ruleForm.role_id,
......
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
</div> </div>
</div> </div>
<!-- 活动列表 --> <!-- 活动列表 -->
<span class="dialog-footer rowFlex"> <span class="rowFlex">
<el-button class="btn" type="primary" :loading="loading" @click="submit">确 定</el-button> <el-button class="btn" type="primary" :loading="loading" @click="submit">确 定</el-button>
<el-button class="btn" @click="close">取 消</el-button> <el-button class="btn" @click="close">取 消</el-button>
</span> </span>
...@@ -68,7 +68,7 @@ ...@@ -68,7 +68,7 @@
export default { export default {
name: 'confirmLayer', name: 'confirmLayer',
// type 3:image 4:video // type 3:image 4:video
props: ['show', 'width', 'title', 'activeInfo', 'remark'], props: ['show', 'width', 'title', 'activeInfo', 'remark','task_id','svipObj'],
data() { data() {
return { return {
loading: false loading: false
...@@ -104,8 +104,11 @@ ...@@ -104,8 +104,11 @@
role_id, role_id,
remark: this.remark, remark: this.remark,
recharge_date: this.activeInfo[0].recharge_date || '', recharge_date: this.activeInfo[0].recharge_date || '',
task_id: this.task_id || null,
create_user: this.cser_name, create_user: this.cser_name,
rule: rule rule: rule,
right_type: this.svipObj?.right_type || '',
select_type: this.svipObj?.select_type || ''
} }
giftBagApply(data).then(res => { giftBagApply(data).then(res => {
this.loading = false this.loading = false
......
...@@ -28,6 +28,13 @@ ...@@ -28,6 +28,13 @@
</el-option> </el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="svip权益">
<el-select v-model.trim="form.right_type" filterable style="width:100%;"
placeholder="请选择svip权益" @change="searchInput">
<el-option v-for="item in benefitOptions" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="角色名称"> <el-form-item label="角色名称">
<el-input v-model="form.role_name_or_cp_id" placeholder="请输入角色名称" style="width:100%;" <el-input v-model="form.role_name_or_cp_id" placeholder="请输入角色名称" style="width:100%;"
@change="searchInput"></el-input> @change="searchInput"></el-input>
...@@ -59,6 +66,7 @@ ...@@ -59,6 +66,7 @@
</div> </div>
<el-collapse-transition> <el-collapse-transition>
<div v-if="item.showDetails"> <div v-if="item.showDetails">
<p class="text hidden"><label>svip权益:</label> {{ item.right_type_name || '-'}}</p>
<p v-if="item.status == '待提交'" class="text"><label>状态:</label> <span class="noSend">{{ item.status <p v-if="item.status == '待提交'" class="text"><label>状态:</label> <span class="noSend">{{ item.status
}}</span> </p> }}</span> </p>
<p v-else-if="item.status == '已提交'" class="text"><label>状态:</label> <span class="sended">{{ <p v-else-if="item.status == '已提交'" class="text"><label>状态:</label> <span class="sended">{{
...@@ -165,8 +173,10 @@ export default { ...@@ -165,8 +173,10 @@ export default {
role_name_or_cp_id: '', role_name_or_cp_id: '',
member_id: '', member_id: '',
active_title: '', active_title: '',
gift_type: '' gift_type: '',
right_type: '',
}, },
benefitOptions: [],
inputValue: '', inputValue: '',
pageInfo: { pageInfo: {
page: 0, page: 0,
...@@ -198,6 +208,7 @@ export default { ...@@ -198,6 +208,7 @@ export default {
mounted() { mounted() {
this.requestGameList() this.requestGameList()
this.requestGiftType() this.requestGiftType()
this.getBenefitOptions()
}, },
methods: { methods: {
// 重新拉去数据 // 重新拉去数据
...@@ -286,6 +297,27 @@ export default { ...@@ -286,6 +297,27 @@ export default {
this.emailGiftList = [] this.emailGiftList = []
this.requestemailGiftList() this.requestemailGiftList()
}, },
async getBenefitOptions() {
try {
const data = {
type: 'svip_right',
}
const res = await selectSearch(data)
if (res.status_code === 1 && res.data && res.data.data && res.data.data.length > 0) {
const showList = ['转生石福利','月核心玩家礼包','超R生日福利礼包','超R行会专属礼包']
this.benefitOptions = res.data.data.filter((item, index) => {
return showList.includes(item.label)
}).map(item => ({
...item,
value: item.value || item.id // 确保每个选项都有value属性,优先使用value,不存在则使用id
}));
console.log(this.benefitOptions)
}
} catch (error) {
console.error('获取权益选项失败:', error)
}
},
requestemailGiftList() { requestemailGiftList() {
this.listLoading = true this.listLoading = true
if (this.accountSelect == '') { if (this.accountSelect == '') {
......
...@@ -24,9 +24,23 @@ ...@@ -24,9 +24,23 @@
<div class="activeValue">{{ activeInfo.recharge_start_date + '至' + activeInfo.recharge_end_date }}</div> <div class="activeValue">{{ activeInfo.recharge_start_date + '至' + activeInfo.recharge_end_date }}</div>
</div> </div>
<!-- 选择的时候重新请求活动详情接口 --> <!-- 选择的时候重新请求活动详情接口 -->
<div class="activeItem rowFlex"> <div class="activeItem rowFlex">
<div class="activeLabel">充值日期</div> <div style="display: flex; align-items: center;width: 100%;">
<el-select v-model="select_type" :clearable="false" style="width: 120px" @change="onSelectTypeChange">
<el-option label="充值日期" :value="1"></el-option>
<el-option label="SVIP权益" :value="2"></el-option>
</el-select>
<template v-if="select_type === 1">
<el-date-picker v-model="recharge_date_time" :default-value="activeInfo.recharge_date" style="width: 210px" type="date" value-format="yyyy-MM-dd" :picker-options="activeInfo.pickerOptions " @change="dateChange"> </el-date-picker> <el-date-picker v-model="recharge_date_time" :default-value="activeInfo.recharge_date" style="width: 210px" type="date" value-format="yyyy-MM-dd" :picker-options="activeInfo.pickerOptions " @change="dateChange"> </el-date-picker>
</template>
<template v-else-if="select_type === 2">
<el-select v-model="right_type" :clearable="false" style="width: 210px" placeholder="请选择权益" @change="onRightTypeChange">
<el-option v-for="item in benefitOptions" :key="item.id || item.value" :label="item.label" :value="item.value || item.id"></el-option>
</el-select>
</template>
</div>
</div> </div>
<div class="activeItem rowFlex"> <div class="activeItem rowFlex">
<div class="activeLabel">申请角色</div> <div class="activeLabel">申请角色</div>
...@@ -127,13 +141,13 @@ ...@@ -127,13 +141,13 @@
<el-button class="btn" size="small" @click="close">取 消</el-button> <el-button class="btn" size="small" @click="close">取 消</el-button>
</span> </span>
<!-- 确认弹窗 --> <!-- 确认弹窗 -->
<confirmLayer v-if="showConfirmLayer" :remark="remark" :active-info="[activeInfo]" :show.sync="showConfirmLayer" title="请核对申请奖品信息" @close="close" /> <confirmLayer v-if="showConfirmLayer" :remark="remark" :task_id="task_id" :active-info="[activeInfo]" :show.sync="showConfirmLayer" :svipObj="svipObj" title="请核对申请奖品信息" @close="close" />
</div> </div>
</el-drawer> </el-drawer>
</template> </template>
<script type="text/javascript"> <script type="text/javascript">
import { giftBagApply } from '@/api/game' import { giftBagApply,selectSearch } from '@/api/game'
import { mapState, mapMutations, mapActions } from 'vuex' import { mapState, mapMutations, mapActions } from 'vuex'
import confirmLayer from '../confirmLayer' import confirmLayer from '../confirmLayer'
export default { export default {
...@@ -142,7 +156,7 @@ export default { ...@@ -142,7 +156,7 @@ export default {
components: { components: {
confirmLayer confirmLayer
}, },
props: ['show', 'width', 'title', 'info', 'body', 'giftInfo', 'activeInfo', 'changeDate','requestLoading'], props: ['show', 'width', 'title', 'info', 'body', 'giftInfo', 'activeInfo', 'changeDate','requestLoading','task_id'],
data() { data() {
return { return {
remark: '', remark: '',
...@@ -155,7 +169,16 @@ export default { ...@@ -155,7 +169,16 @@ export default {
num: '', num: '',
allpoints: 0, allpoints: 0,
showContent: true, showContent: true,
showConfirmLayer: false benefitOptions:[],
showConfirmLayer: false,
svipObj: {
right_type: '',
select_type: ''
},
// 新增:1 充值日期 2 svip权益
select_type: 1,
// 权益类型选中的值
right_type: ''
} }
}, },
...@@ -175,7 +198,18 @@ export default { ...@@ -175,7 +198,18 @@ export default {
}, },
mounted() { mounted() {
this.recharge_date_time = this.activeInfo.recharge_date this.recharge_date_time = this.activeInfo.recharge_date
this.getBenefitOptions()
},
computed: {
// 根据选择类型显示对应的内容
showDatePicker() {
return this.select_type === 1
}, },
showBenefitSelect() {
return this.select_type === 2
}
},
methods: { methods: {
close() { close() {
this.$emit('update:show', false) this.$emit('update:show', false)
...@@ -187,6 +221,50 @@ export default { ...@@ -187,6 +221,50 @@ export default {
this.$emit('giftDetailsInfo', value) this.$emit('giftDetailsInfo', value)
} }
}, },
async getBenefitOptions() {
try {
const data = {
type: 'svip_right',
}
const res = await selectSearch(data)
if (res.status_code === 1 && res.data && res.data.data && res.data.data.length > 0) {
const showList = ['月核心玩家礼包','超R生日福利礼包']
this.benefitOptions = res.data.data.filter((item, index) => {
return showList.includes(item.label)
}).map(item => ({
...item,
value: item.value || item.id // 确保每个选项都有value属性,优先使用value,不存在则使用id
}));
console.log(this.benefitOptions)
}
} catch (error) {
console.error('获取权益选项失败:', error)
}
},
// 选择类型改变时触发
onSelectTypeChange() {
// 重置选择的值
if (this.select_type === 1) {
this.recharge_date_time = this.activeInfo.recharge_date
// 触发日期变化的接口
this.dateChange(this.recharge_date_time)
} else {
this.right_type = ''
}
},
// 权益类型改变时触发
onRightTypeChange() {
if (this.right_type) {
const data = {
right_type: this.right_type,
select_type: this.select_type
}
// 复用日期变化的接口
this.$emit('giftDetailsSVIPInfo', data)
}
},
openPrizeItem(item, index, value) { openPrizeItem(item, index, value) {
console.log(item, index, value) console.log(item, index, value)
this.$set(this.giftInfo.rule.level_attribute[index], 'showContent', value) this.$set(this.giftInfo.rule.level_attribute[index], 'showContent', value)
...@@ -242,6 +320,8 @@ export default { ...@@ -242,6 +320,8 @@ export default {
} }
this.showConfirmLayer = true this.showConfirmLayer = true
this.activeInfo.type_details = this.giftInfo this.activeInfo.type_details = this.giftInfo
this.svipObj.right_type = this.right_type
this.svipObj.select_type = this.select_type
} }
} }
} }
...@@ -360,6 +440,7 @@ export default { ...@@ -360,6 +440,7 @@ export default {
left: 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
bottom: 100px; bottom: 100px;
z-index: 100;
} }
.consumption-point{ .consumption-point{
font-size: 14px; font-size: 14px;
......
...@@ -57,7 +57,7 @@ ...@@ -57,7 +57,7 @@
<el-button size="small" class="btn" @click="close">取 消</el-button> <el-button size="small" class="btn" @click="close">取 消</el-button>
</span> </span>
<!-- 确认弹窗 --> <!-- 确认弹窗 -->
<confirmLayer :is-submit="isSubmit" :remark="remark" :active-info="activeInfo" :show.sync="showConfirmLayer" title="请核对申请奖品信息" @close="close" /> <confirmLayer :is-submit="isSubmit" :remark="remark" :task_id="task_id" :active-info="activeInfo" :show.sync="showConfirmLayer" title="请核对申请奖品信息" @close="close" />
</div> </div>
</el-drawer> </el-drawer>
</template> </template>
...@@ -72,7 +72,7 @@ export default { ...@@ -72,7 +72,7 @@ export default {
components: { components: {
confirmLayer confirmLayer
}, },
props: ['show', 'width', 'title', 'info', 'body', 'giftInfo', 'activeInfo','requestLoading'], props: ['show', 'width', 'title', 'info', 'body', 'giftInfo', 'activeInfo','requestLoading','task_id'],
data() { data() {
return { return {
isSubmit: false, isSubmit: false,
...@@ -121,6 +121,7 @@ export default { ...@@ -121,6 +121,7 @@ export default {
role_id, role_id,
remark: this.remark, remark: this.remark,
recharge_date: this.activeInfo[0].recharge_date || '', recharge_date: this.activeInfo[0].recharge_date || '',
task_id: this.task_id || null,
create_user: this.cser_name, create_user: this.cser_name,
rule: rule rule: rule
} }
......
...@@ -64,8 +64,30 @@ ...@@ -64,8 +64,30 @@
class="activeValue" class="activeValue"
>{{ activeInfo.role_info.label }}</div> >{{ activeInfo.role_info.label }}</div>
</div> </div>
<div class="activeItem rowFlex">
<div class="activeLabel">SVIP权益</div>
<div
v-if="giftInfo.rule?.right_type_name"
class="activeValue"
>{{ giftInfo.rule?.right_type_name || '-' }}</div>
</div>
<div class="rowFlex">
<div class="activeItem rowFlex">
<div class="activeLabel" style="width: 70px">可领取次数</div>
<div
v-if="giftInfo.total_recharge"
class="activeValue"
>{{ giftInfo.total_recharge || '-' }}</div>
</div>
<div class="activeItem rowFlex">
<div class="activeLabel" style="width: 90px">剩余领取次数</div>
<div
v-if="giftInfo.real_score"
class="activeValue"
>{{ giftInfo.real_score || '-' }}</div>
</div>
</div>
<!-- 积分关的情况 --> <!-- 积分关的情况 -->
<div <div
v-if="activeInfo.gift_type == 2" v-if="activeInfo.gift_type == 2"
class="activeItem rowFlex" class="activeItem rowFlex"
...@@ -234,7 +256,7 @@ ...@@ -234,7 +256,7 @@
type="primary" type="primary"
size="small" size="small"
:disabled="requestLoading" :disabled="requestLoading"
@click="submit" @click="submitBtn"
:loading="btnLoading" :loading="btnLoading"
>确 定</el-button> >确 定</el-button>
<el-button <el-button
...@@ -247,6 +269,7 @@ ...@@ -247,6 +269,7 @@
<confirmLayer <confirmLayer
v-if="showConfirmLayer" v-if="showConfirmLayer"
:remark="remark" :remark="remark"
:task_id="task_id"
:active-info="[activeInfo]" :active-info="[activeInfo]"
:show.sync="showConfirmLayer" :show.sync="showConfirmLayer"
title="请核对申请奖品信息" title="请核对申请奖品信息"
...@@ -266,7 +289,7 @@ export default { ...@@ -266,7 +289,7 @@ export default {
components: { components: {
confirmLayer confirmLayer
}, },
props: ['show', 'width', 'title', 'info', 'body', 'giftInfo', 'activeInfo', 'changeDate','requestLoading'], props: ['show', 'width', 'title', 'info', 'body', 'giftInfo', 'activeInfo', 'changeDate','requestLoading','task_id'],
data() { data() {
return { return {
remark: '', remark: '',
...@@ -285,6 +308,9 @@ export default { ...@@ -285,6 +308,9 @@ export default {
showConfirmLayer: false showConfirmLayer: false
} }
}, },
computed: {
...mapState('user', ['cser_name'])
},
watch: { watch: {
show(newVal, oldVal) { show(newVal, oldVal) {
if (newVal) { if (newVal) {
...@@ -385,7 +411,58 @@ export default { ...@@ -385,7 +411,58 @@ export default {
handleChange() { handleChange() {
}, },
async submit() { submitBtn(){
// svip 权益礼包
if(this.activeInfo.gift_type==7){
this.submitSvipGfit()
} else{
this.submitGift()
}
},
submitSvipGfit(){
this.loading = true
const role_id = this.activeInfo.role_info.value
// 直接处理activeInfo对象,避免不必要的数组包装和map操作
const activeInfo = this.activeInfo
let level_attribute = []
try {
// 安全地访问嵌套属性
if (this.giftInfo?.rule?.gift_type === 1) {
level_attribute = this.giftInfo.rule.level_attribute || []
} else if (this.giftInfo?.rule?.level_attribute) {
// 过滤出可申请的等级属性
level_attribute = this.giftInfo.rule.level_attribute.filter(item => item.apply_num > 0)
}
} catch (error) {
console.error('处理礼包等级属性时出错:', error)
}
// 构建规则数据
const rule = [{ level_attribute, id: activeInfo.id }]
const data = {
role_id:role_id,
recharge_date:'',
remark: this.remark,
create_user: this.cser_name,
task_id: this.task_id || null,
right_type: this.activeInfo.right_type || '',
select_type:this.activeInfo.gift_type==7?2:'',
rule: rule
}
giftBagApply(data).then(res => {
this.loading = false
if (res.status_code === 1) {
this.$message.success(res.msg)
this.close()
this.$emit('close')
} else {
this.close()
}
}, err => {
this.loading = false
})
},
async submitGift() {
this.btnLoading = true this.btnLoading = true
const data = { const data = {
role_id: this.giftInfo.role_id, role_id: this.giftInfo.role_id,
......
...@@ -3,51 +3,114 @@ ...@@ -3,51 +3,114 @@
<div v-if="!disabled && bindGameUserList.length > 0" class="btnRelease"> <div v-if="!disabled && bindGameUserList.length > 0" class="btnRelease">
<div class="btntab"> <div class="btntab">
<el-radio-group size="small" v-model="activeName" class="radio-group"> <el-radio-group size="small" v-model="activeName" class="radio-group">
<el-radio-button border label="1" @click.native="activeName = '1'">转端</el-radio-button> <el-radio-button border label="1" @click.native="activeName = '1'"
<el-radio-button border label="3" @click.native="recallTabChange">召回</el-radio-button> >转端</el-radio-button
<el-radio-button border label="2" @click.native="requestRegGameList">转游</el-radio-button> >
<el-radio-button border label="3" @click.native="recallTabChange"
>召回</el-radio-button
>
<el-radio-button border label="2" @click.native="requestRegGameList"
>转游</el-radio-button
>
</el-radio-group> </el-radio-group>
</div> </div>
<div v-loading="contentLoading" class="gameList"> <div v-loading="contentLoading" class="gameList">
<!-- 转端 --> <!-- 转端 -->
<el-collapse v-if="activeName == '1' && conversionGameList.length > 0" :disabled="disabled" <el-collapse
@change="conversionChangeOld"> v-if="activeName == '1' && conversionGameList.length > 0"
<el-collapse-item class="mb-[10px]" v-for="(item, index) in conversionGameList" :key="index" :disabled="disabled"
:name="item.game_type"> @change="conversionChangeOld"
>
<el-collapse-item
class="mb-[10px]"
v-for="(item, index) in conversionGameList"
:key="index"
:name="item.game_type"
>
<template slot="title"> <template slot="title">
<div class="title-with-icon"> <div class="title-with-icon">
<svg-icon v-if="item.game_type == 1" icon-class="wxgame" class="game-icon" /> <svg-icon
<svg-icon v-else-if="item.game_type == 5" icon-class="douyin" class="game-icon" /> v-if="item.game_type == 1"
<svg-icon v-else-if="item.game_type == 3" icon-class="Android" class="game-icon" /> icon-class="wxgame"
<svg-icon v-else-if="item.game_type == 4" icon-class="IOS" class="game-icon" /> class="game-icon"
<svg-icon v-else-if="item.game_type == 2" icon-class="H5" class="game-icon" /> />
<svg-icon
v-else-if="item.game_type == 5"
icon-class="douyin"
class="game-icon"
/>
<svg-icon
v-else-if="item.game_type == 3"
icon-class="Android"
class="game-icon"
/>
<svg-icon
v-else-if="item.game_type == 4"
icon-class="IOS"
class="game-icon"
/>
<svg-icon
v-else-if="item.game_type == 2"
icon-class="H5"
class="game-icon"
/>
{{ item.game_text }} {{ item.game_text }}
</div> </div>
</template> </template>
<div v-if="item.children && item.children.length > 0"> <div v-if="item.children && item.children.length > 0">
<div v-for="(items, indexs) in item.children" :key="indexs" <div
class="gameListItem rowFlex columnCenter spaceBetween"> v-for="(items, indexs) in item.children"
<p>{{ items.game_name + '/' + items.game_id }}</p> :key="indexs"
class="gameListItem rowFlex columnCenter spaceBetween"
>
<p>{{ items.game_name + "/" + items.game_id }}</p>
<el-popover placement="top" width="160" trigger="hover"> <el-popover placement="top" width="160" trigger="hover">
<div> <div>
<p class="sendLink" @click="sendLink(items, item.game_type)"> <p
class="sendLink"
@click="sendLink(items, item.game_type)"
>
仅发送链接 仅发送链接
</p> </p>
<p class="sendLink" @click="sendPassword(items, item.game_type)"> <p
class="sendLink"
@click="sendPassword(items, item.game_type)"
>
仅发送账号密码 仅发送账号密码
</p> </p>
<p class="sendLink" @click="sendMessage(items, item.game_type)"> <p
class="sendLink"
@click="sendMessage(items, item.game_type)"
>
发送链接和账号密码 发送链接和账号密码
</p> </p>
<p class="sendLink" @click="sendDownLoadPage(items, item.game_type, index)"> <p
class="sendLink"
@click="sendDownLoadPage(items, item.game_type, index)"
>
发送落地页 发送落地页
</p> </p>
<p
class="sendLink"
v-if="[3, 4].includes(item.game_type)"
@click="sendDownLoadQrCode(items, item.game_type, index)"
>
下载二维码
</p>
</div> </div>
<el-button slot="reference" size="mini" :disabled="accountSelect == ''">发送</el-button> <el-button
slot="reference"
size="mini"
:disabled="accountSelect == ''"
>发送</el-button
>
</el-popover> </el-popover>
</div> </div>
</div> </div>
<div v-else-if="gameLoding" class="channelLoading rowFlex allCenter"> <div
v-else-if="gameLoding"
class="channelLoading rowFlex allCenter"
>
<i class="el-icon-loading"></i> <i class="el-icon-loading"></i>
<el-button type="text">加载中</el-button> <el-button type="text">加载中</el-button>
</div> </div>
...@@ -55,31 +118,75 @@ ...@@ -55,31 +118,75 @@
</el-collapse-item> </el-collapse-item>
</el-collapse> </el-collapse>
<!-- 召回 --> <!-- 召回 -->
<div v-else-if="activeName == '3' && recallGameList.length > 0" class="collapseContent"> <div
v-else-if="activeName == '3' && recallGameList.length > 0"
class="collapseContent"
>
<!-- v-if="chatUser.task_type && chatUser.task_type == 7"--> <!-- v-if="chatUser.task_type && chatUser.task_type == 7"-->
<el-button v-if='false' type="primary" style="margin-left:50px;" :loading="sendLoading" <el-button
@click="sendTaskChannel">根据任务一键发送链接</el-button> v-if="false"
type="primary"
style="margin-left: 50px"
:loading="sendLoading"
@click="sendTaskChannel"
>根据任务一键发送链接</el-button
>
<el-collapse :disabled="disabled" @change="recallChange"> <el-collapse :disabled="disabled" @change="recallChange">
<el-collapse-item v-for="(item, index) in recallGameList" :key="index" :name="item.game_type"> <el-collapse-item
v-for="(item, index) in recallGameList"
:key="index"
:name="item.game_type"
>
<template slot="title"> <template slot="title">
<div class="title-with-icon"> <div class="title-with-icon">
<svg-icon v-if="item.game_type == 1" icon-class="wxgame" class="game-icon" /> <svg-icon
<svg-icon v-else-if="item.game_type == 5" icon-class="douyin" class="game-icon" /> v-if="item.game_type == 1"
<svg-icon v-else-if="item.game_type == 3" icon-class="Android" class="game-icon" /> icon-class="wxgame"
<svg-icon v-else-if="item.game_type == 4" icon-class="IOS" class="game-icon" /> class="game-icon"
<svg-icon v-else-if="item.game_type == 2" icon-class="H5" class="game-icon" /> />
<svg-icon
v-else-if="item.game_type == 5"
icon-class="douyin"
class="game-icon"
/>
<svg-icon
v-else-if="item.game_type == 3"
icon-class="Android"
class="game-icon"
/>
<svg-icon
v-else-if="item.game_type == 4"
icon-class="IOS"
class="game-icon"
/>
<svg-icon
v-else-if="item.game_type == 2"
icon-class="H5"
class="game-icon"
/>
{{ item.game_text }} {{ item.game_text }}
</div> </div>
</template> </template>
<div v-if="item.children && item.children.length > 0"> <div v-if="item.children && item.children.length > 0">
<div v-for="(items, indexs) in item.children" :key="indexs" <div
class="gameListItem rowFlex columnCenter spaceBetween"> v-for="(items, indexs) in item.children"
<p>{{ items.game_name + '/' + items.game_id }}</p> :key="indexs"
<el-button slot="reference" size="mini" :disabled="accountSelect == ''" class="gameListItem rowFlex columnCenter spaceBetween"
@click="sendChannel(items)">发送</el-button> >
<p>{{ items.game_name + "/" + items.game_id }}</p>
<el-button
slot="reference"
size="mini"
:disabled="accountSelect == ''"
@click="sendChannel(items)"
>发送</el-button
>
</div> </div>
</div> </div>
<div v-else-if="gameLoding" class="channelLoading rowFlex allCenter"> <div
v-else-if="gameLoding"
class="channelLoading rowFlex allCenter"
>
<i class="el-icon-loading"></i> <i class="el-icon-loading"></i>
<el-button type="text">加载中</el-button> <el-button type="text">加载中</el-button>
</div> </div>
...@@ -89,7 +196,12 @@ ...@@ -89,7 +196,12 @@
</el-collapse> </el-collapse>
<div class="createChannel rowFlex allCenter"> <div class="createChannel rowFlex allCenter">
<span class="label">找不到对应游戏的链接点此</span> <span class="label">找不到对应游戏的链接点此</span>
<el-button type="text" size="medium" @click="showCreateChannel = true">新建渠道链接</el-button> <el-button
type="text"
size="medium"
@click="showCreateChannel = true"
>新建渠道链接</el-button
>
</div> </div>
</div> </div>
<!-- <!--
...@@ -100,21 +212,53 @@ ...@@ -100,21 +212,53 @@
--> -->
<div v-else-if="activeName == '2'"> <div v-else-if="activeName == '2'">
<el-collapse :disabled="disabled"> <el-collapse :disabled="disabled">
<el-input v-model="filterGameText" placeholder="请输入游戏名 按回车搜索" style="margin-top: 10px" <el-input
@keydown.enter.native="changeGameText" @blur="changeGameText"> v-model="filterGameText"
placeholder="请输入游戏名 按回车搜索"
style="margin-top: 10px"
@keydown.enter.native="changeGameText"
@blur="changeGameText"
>
<i slot="prefix" class="el-input__icon el-icon-search"></i> <i slot="prefix" class="el-input__icon el-icon-search"></i>
</el-input> </el-input>
<el-collapse-item v-for="(item, index) in regGameList" :key="index" :name="item.label"> <el-collapse-item
v-for="(item, index) in regGameList"
:key="index"
:name="item.label"
>
<template slot="title"> <template slot="title">
<div class="title-with-icon"> <div class="title-with-icon">
<svg-icon v-if="item.label.includes('微信')" icon-class="wxgame" class="game-icon" />
<svg-icon v-else-if="item.label.includes('抖音')" icon-class="douyin" class="game-icon" />
<svg-icon v-else-if="item.label.includes('安卓')" icon-class="Android" class="game-icon" />
<svg-icon <svg-icon
v-else-if="item.label.includes('IOS') || item.label.includes('iOS') || item.label.includes('ios')" v-if="item.label.includes('微信')"
icon-class="IOS" class="game-icon" /> icon-class="wxgame"
<svg-icon v-else-if="item.label.includes('H5') || item.label.includes('h5')" icon-class="H5" class="game-icon"
class="game-icon" /> />
<svg-icon
v-else-if="item.label.includes('抖音')"
icon-class="douyin"
class="game-icon"
/>
<svg-icon
v-else-if="item.label.includes('安卓')"
icon-class="Android"
class="game-icon"
/>
<svg-icon
v-else-if="
item.label.includes('IOS') ||
item.label.includes('iOS') ||
item.label.includes('ios')
"
icon-class="IOS"
class="game-icon"
/>
<svg-icon
v-else-if="
item.label.includes('H5') || item.label.includes('h5')
"
icon-class="H5"
class="game-icon"
/>
{{ item.label }} {{ item.label }}
</div> </div>
</template> </template>
...@@ -127,39 +271,64 @@ ...@@ -127,39 +271,64 @@
H5游戏 item.game_type == 2 icon 是 H5.svg H5游戏 item.game_type == 2 icon 是 H5.svg
--> -->
<div v-if="regGameList.length > 0"> <div v-if="regGameList.length > 0">
<div v-for="(items, indexs) in item.children" :key="indexs" <div
class="gameListItem rowFlex columnCenter spaceBetween"> v-for="(items, indexs) in item.children"
:key="indexs"
class="gameListItem rowFlex columnCenter spaceBetween"
>
<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 v-if="items.game_type == 1 || items.game_type == 3 || items.game_type == 4" <el-popover
placement="top" trigger="click"> v-if="
items.game_type == 1 ||
items.game_type == 3 ||
items.game_type == 4
"
placement="top"
trigger="click"
>
<p class="sendLink" @click="sendChannelGame(items, item)"> <p class="sendLink" @click="sendChannelGame(items, item)">
发送链接/渠道二维码 发送链接/渠道二维码
</p> </p>
<p class="sendLink" @click="handleGameType(items, item, item.game_type, index)"> <p
class="sendLink"
@click="
handleGameType(items, item, item.game_type, index)
"
>
发送落地页 发送落地页
</p> </p>
<div v-if="items.game_type == 1"> <div v-if="items.game_type == 1">
<!-- 发送 H5 安卓分身包 --> <!-- 发送 H5 安卓分身包 -->
<p <p
class="sendLink" class="sendLink"
@click="sendH5CloneGame(items,'android')" @click="sendH5CloneGame(items, 'android')"
> >
发送H5-安卓分身包 发送H5-安卓分身包
</p> </p>
<!-- 发送 H5 IOS 分身包 --> <!-- 发送 H5 IOS 分身包 -->
<p <p
class="sendLink" class="sendLink"
@click="sendH5CloneGame(items,'ios')" @click="sendH5CloneGame(items, 'ios')"
> >
发送H5-IOS分身包 发送H5-IOS分身包
</p> </p>
</div> </div>
<el-button slot="reference" size="mini" :disabled="accountSelect == ''">发送</el-button> <el-button
slot="reference"
size="mini"
:disabled="accountSelect == ''"
>发送</el-button
>
</el-popover> </el-popover>
<el-button v-else size="mini" :disabled="accountSelect == ''" <el-button
@click="noH5AndroidIOSGame(items, item)">发送</el-button> v-else
size="mini"
:disabled="accountSelect == ''"
@click="noH5AndroidIOSGame(items, item)"
>发送</el-button
>
</div> </div>
</div> </div>
<!-- <div <!-- <div
...@@ -170,12 +339,16 @@ ...@@ -170,12 +339,16 @@
<el-button type="text">加载中</el-button> <el-button type="text">加载中</el-button>
</div> --> </div> -->
<div v-else class="rowFlex allCenter">暂无游戏</div> <div v-else class="rowFlex allCenter">暂无游戏</div>
</el-collapse-item> </el-collapse-item>
</el-collapse> </el-collapse>
<div class="createChannel rowFlex allCenter"> <div class="createChannel rowFlex allCenter">
<span class="label">找不到对应游戏的链接点此</span> <span class="label">找不到对应游戏的链接点此</span>
<el-button type="text" size="medium" @click="showCreateChannel = true">新建渠道链接</el-button> <el-button
type="text"
size="medium"
@click="showCreateChannel = true"
>新建渠道链接</el-button
>
</div> </div>
</div> </div>
</div> </div>
...@@ -184,23 +357,62 @@ ...@@ -184,23 +357,62 @@
<p>暂未绑定关联账号,请先去绑定账号</p> <p>暂未绑定关联账号,请先去绑定账号</p>
</div> </div>
<!-- 新建渠道链接 --> <!-- 新建渠道链接 -->
<createChannel v-if="showCreateChannel" :type="activeName" :show="showCreateChannel" :game-user-info="gameUserInfo" <createChannel
@close="showCreateChannel = false" /> v-if="showCreateChannel"
<sendPage v-if="showSendPage" :show.sync="showSendPage" :game-list="conversionGameList" @confirm="startSendPage" /> :type="activeName"
:show="showCreateChannel"
:game-user-info="gameUserInfo"
@close="showCreateChannel = false"
/>
<sendPage
v-if="showSendPage"
:show.sync="showSendPage"
:game-list="conversionGameList"
@confirm="startSendPage"
/>
<!-- 小游戏转游判断 --> <!-- 小游戏转游判断 -->
<SendTransWxGame v-if="showWxGameDrawer" :show.sync="showWxGameDrawer" :game-list="selectedWxGameList" <SendTransWxGame
:chat-user-info="chatUserInfo" @close="SendTransWxGameClose" @confirm="handleWxGameConfirm" /> v-if="showWxGameDrawer"
<SendTransAppGame v-if="showAppGameDrawer" :show.sync="showAppGameDrawer" :game-list="selectedAppGameList" :show.sync="showWxGameDrawer"
:chat-user-info="chatUserInfo" @close="SendTransAppGameClose" @confirm="handleAppGameConfirm" /> :game-list="selectedWxGameList"
:chat-user-info="chatUserInfo"
@close="SendTransWxGameClose"
@confirm="handleWxGameConfirm"
/>
<SendTransAppGame
v-if="showAppGameDrawer"
:show.sync="showAppGameDrawer"
:game-list="selectedAppGameList"
:chat-user-info="chatUserInfo"
@close="SendTransAppGameClose"
@confirm="handleAppGameConfirm"
/>
<!-- 选择发送渠道 --> <!-- 选择发送渠道 -->
<selectChannel v-if="showLayer" :show.sync="showLayer" :chat-user="chatUserInfo" <selectChannel
:channel-info-list="channelInfoList" /> v-if="showLayer"
:show.sync="showLayer"
:chat-user="chatUserInfo"
:channel-info-list="channelInfoList"
/>
<!-- 如果选择发送的渠道链接只有一个 直接发送 --> <!-- 如果选择发送的渠道链接只有一个 直接发送 -->
<sendSelectChannel :show.sync="showSendChannel" :chat-user="chatUserInfo" :channel-info-list="channelInfoList" /> <sendSelectChannel
:show.sync="showSendChannel"
:chat-user="chatUserInfo"
:channel-info-list="channelInfoList"
/>
<!-- 二维码生成组件 (隐藏) -->
<div v-show="false" class="qrcode-container">
<qrcode-vue
ref="qrcode"
:value="qrCodeValue"
:size="qrCodeSize"
level="H"
></qrcode-vue>
</div>
</div> </div>
</template> </template>
<script> <script>
import { mapState, mapMutations, mapActions } from 'vuex' import { mapState, mapMutations, mapActions } from "vuex";
import { import {
memberExtensionGameList, memberExtensionGameList,
passwardEncryption, passwardEncryption,
...@@ -213,21 +425,29 @@ import { ...@@ -213,21 +425,29 @@ import {
getLandingPageMemberLink, getLandingPageMemberLink,
getClonePackageLink, getClonePackageLink,
getLandingPageConfig, getLandingPageConfig,
getMemberTransStatus getMemberTransStatus,
} from '@/api/game' } from "@/api/game";
import { getRecentSendLog, markTransScene, getZqCserGroup, getZqCserWxBelong, getMediaId, send_log_add } from '@/api/works' import {
import { companyviewConfig } from '@/api/user' getRecentSendLog,
import { throttle, throttleStart } from '@/utils/index' markTransScene,
import createChannel from './sendGame/createChannel' getZqCserGroup,
import sendPage from './sendGame/SendTransPage.vue' getZqCserWxBelong,
import SendTransWxGame from './sendGame/SendTransWxGame.vue' getMediaId,
import SendTransAppGame from './sendGame/SendTransAppGame.vue' send_log_add,
import selectChannel from './sendGame/selectChannel.vue' } from "@/api/works";
import sendSelectChannel from './sendGame/sendSelectChannel.vue' import { companyviewConfig } from "@/api/user";
import gameLogMixin from '@/mixins/gameLogMixin' import { throttle, throttleStart } from "@/utils/index";
import { sendChatMessage } from '@/utils/index' import createChannel from "./sendGame/createChannel";
import sendPage from "./sendGame/SendTransPage.vue";
import SendTransWxGame from "./sendGame/SendTransWxGame.vue";
import SendTransAppGame from "./sendGame/SendTransAppGame.vue";
import selectChannel from "./sendGame/selectChannel.vue";
import sendSelectChannel from "./sendGame/sendSelectChannel.vue";
import gameLogMixin from "@/mixins/gameLogMixin";
import { sendChatMessage } from "@/utils/index";
import QrcodeVue from "qrcode.vue";
export default { export default {
name: 'sendGame', name: "sendGame",
mixins: [gameLogMixin], mixins: [gameLogMixin],
components: { components: {
createChannel, createChannel,
...@@ -235,7 +455,8 @@ export default { ...@@ -235,7 +455,8 @@ export default {
SendTransWxGame, SendTransWxGame,
SendTransAppGame, SendTransAppGame,
selectChannel, selectChannel,
sendSelectChannel sendSelectChannel,
QrcodeVue,
}, },
data() { data() {
return { return {
...@@ -250,15 +471,15 @@ export default { ...@@ -250,15 +471,15 @@ export default {
weixin_blongs_id: [], weixin_blongs_id: [],
regGameList: [], regGameList: [],
allRegGameList: [], allRegGameList: [],
filterGameText: '', filterGameText: "",
channelselectList: [], channelselectList: [],
webForm: { webForm: {
channel_id: '' channel_id: "",
}, },
sendLoading: false, sendLoading: false,
belongList: [], // 项目列表 belongList: [], // 项目列表
activeName: '1', // 转端 1 转游 2 召回 3 activeName: "1", // 转端 1 转游 2 召回 3
sendType: '', // 1 进发送链接 2 仅发送账号密码 3 发送链接和账号密码 sendType: "", // 1 进发送链接 2 仅发送账号密码 3 发送链接和账号密码
showCreateChannel: false, showCreateChannel: false,
showImageComposer: false, showImageComposer: false,
showWxGameDrawer: false, showWxGameDrawer: false,
...@@ -270,206 +491,227 @@ export default { ...@@ -270,206 +491,227 @@ export default {
showLayer: false, showLayer: false,
showSendChannel: false, showSendChannel: false,
channelInfoList: {}, channelInfoList: {},
transMemberStatus: true transMemberStatus: true,
} qrCodeValue: "", // 二维码内容
qrCodeSize: 200, // 二维码大小
};
}, },
mounted() { mounted() {
this.initDisable() this.initDisable();
this.sendGameInfo() this.sendGameInfo();
}, },
computed: { computed: {
...mapState('game', ['accountSelect', 'bindGameUserList', 'chatUserInfo', 'gameUserInfo', 'send_game_log']), ...mapState("game", [
...mapState('user', ['userInfo', 'corp_id']) "accountSelect",
"bindGameUserList",
"chatUserInfo",
"gameUserInfo",
"send_game_log",
]),
...mapState("user", ["userInfo", "corp_id"]),
}, },
// props: [ 'chatUserInfo', 'chatUser'], // props: [ 'chatUserInfo', 'chatUser'],
watch: { watch: {
accountSelect(newVal, oldVal) { accountSelect(newVal, oldVal) {
// 切换 w 账号的时候清空 conversionGameList 数据 // 切换 w 账号的时候清空 conversionGameList 数据
this.conversionGameList = [] this.conversionGameList = [];
this.getMemberTransStatus() this.getMemberTransStatus();
if (newVal && newVal !== '' && this.bindGameUserList.length > 0) { if (newVal && newVal !== "" && this.bindGameUserList.length > 0) {
this.disabled = false this.disabled = false;
} else { } else {
this.disabled = true this.disabled = true;
} }
}, },
activeName(newVal, oldVal) { activeName(newVal, oldVal) {
if (newVal) { if (newVal) {
}
} }
}, },
},
methods: { methods: {
...mapMutations('game', ['set_send_game_log']), ...mapMutations("game", ["set_send_game_log"]),
initDisable() { initDisable() {
// 切换 w 账号的时候清空 conversionGameList 数据 // 切换 w 账号的时候清空 conversionGameList 数据
this.conversionGameList = [] this.conversionGameList = [];
this.getMemberTransStatus() this.getMemberTransStatus();
if (this.accountSelect && this.accountSelect !== '' && this.bindGameUserList.length > 0) { if (
this.disabled = false this.accountSelect &&
this.accountSelect !== "" &&
this.bindGameUserList.length > 0
) {
this.disabled = false;
} else { } else {
this.disabled = true this.disabled = true;
} }
}, },
channelInfo(info) { channelInfo(info) {
this.channelInfoList = info this.channelInfoList = info;
// 只有 1 个渠道的时候 直接发送不出现弹窗 // 只有 1 个渠道的时候 直接发送不出现弹窗
if (info.channelList.length === 1) { if (info.channelList.length === 1) {
this.showSendChannel = true this.showSendChannel = true;
} else { } else {
this.showLayer = true this.showLayer = true;
} }
}, },
async sendH5CloneGame(items, type) { async sendH5CloneGame(items, type) {
const res = await getClonePackageLink({ mini_game_id: items.id }) const res = await getClonePackageLink({ mini_game_id: items.id });
if (res.status_code == 1 ) { if (res.status_code == 1) {
if(type == 'android' && !res?.data?.data?.android_download_url){ if (type == "android" && !res?.data?.data?.android_download_url) {
this.$message.warning('安卓分身包链接不存在,请联系掌游配置') this.$message.warning("安卓分身包链接不存在,请联系掌游配置");
return return;
}else if(type == 'ios' && !res?.data?.data?.ios_download_url){ } else if (type == "ios" && !res?.data?.data?.ios_download_url) {
this.$message.warning('IOS分身包链接不存在,请联系掌游配置') this.$message.warning("IOS分身包链接不存在,请联系掌游配置");
return return;
} }
let srt = '' let srt = "";
if(type == 'android'){ if (type == "android") {
srt = '安卓分身包链接: '+res.data.data.android_download_url srt = "安卓分身包链接: " + res.data.data.android_download_url;
}else{ } else {
srt = 'IOS分身包链接: '+res.data.data.ios_download_url srt = "IOS分身包链接: " + res.data.data.ios_download_url;
} }
sendChatMessage(srt,'text') sendChatMessage(srt, "text");
}else{ } else {
this.$message.warning(res.msg) this.$message.warning(res.msg);
} }
}, },
requestConfig() { requestConfig() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
companyviewConfig({ corp_id: this.corp_id }).then((res) => { companyviewConfig({ corp_id: this.corp_id }).then((res) => {
this.weixin_blongs_id = res.data.weixin_blongs_id this.weixin_blongs_id = res.data.weixin_blongs_id;
resolve() resolve();
}) });
}) });
}, },
// 请求当前 W 账号是否符合转端条件 如果不符合 提示 当前w账号不满足转端要求,请联系组长处理 // 请求当前 W 账号是否符合转端条件 如果不符合 提示 当前w账号不满足转端要求,请联系组长处理
async getMemberTransStatus() { async getMemberTransStatus() {
if (this.accountSelect && this.accountSelect !== '') { if (this.accountSelect && this.accountSelect !== "") {
const res = await getMemberTransStatus({ member_id: this.accountSelect }) const res = await getMemberTransStatus({
member_id: this.accountSelect,
});
if (res.status_code == 1) { if (res.status_code == 1) {
this.transMemberStatus = res.data.data.allow_trans || false this.transMemberStatus = res.data.data.allow_trans || false;
} }
} else { } else {
this.transMemberStatus = false this.transMemberStatus = false;
} }
}, },
recallTabChange() { recallTabChange() {
this.activeName = '3' this.activeName = "3";
this.sendGameRecallList() this.sendGameRecallList();
}, },
async requestGameSendLog() { async requestGameSendLog() {
this.filterGameText = '' this.filterGameText = "";
const res = await getRecentSendLog() const res = await getRecentSendLog();
if (res.status_code == 1) { if (res.status_code == 1) {
if (res.status_code == 1 && res.data.length > 0) { if (res.status_code == 1 && res.data.length > 0) {
res.data.map((item) => { res.data.map((item) => {
item.label = item.game_name item.label = item.game_name;
item.id = item.game_id item.id = item.game_id;
}) });
} }
// 检查是否已经存在"最近发送"项 // 检查是否已经存在"最近发送"项
const recentSendIndex = this.regGameList.findIndex(item => item.label === '最近发送') const recentSendIndex = this.regGameList.findIndex(
(item) => item.label === "最近发送"
);
if (recentSendIndex !== -1) { if (recentSendIndex !== -1) {
// 如果已存在,更新它 // 如果已存在,更新它
this.$set(this.regGameList[recentSendIndex], 'children', res.data) this.$set(this.regGameList[recentSendIndex], "children", res.data);
} else { } else {
// 如果不存在,添加它 // 如果不存在,添加它
this.regGameList.unshift({ this.regGameList.unshift({
label: '最近发送', label: "最近发送",
children: res.data children: res.data,
}) });
} }
} }
}, },
async sendGameInfo() { async sendGameInfo() {
this.activeName = '1' this.activeName = "1";
this.conversionGameList = [] this.conversionGameList = [];
this.recallGameList = [] this.recallGameList = [];
this.getMemberTransStatus() this.getMemberTransStatus();
await this.requestConfig() await this.requestConfig();
this.sendGameList() this.sendGameList();
}, },
requestRegGameList() { requestRegGameList() {
this.activeName = '2' this.activeName = "2";
if (this.gameUserInfo.main_game_id || this.gameUserInfo.main_game_id == 0) { if (
this.contentLoading = true this.gameUserInfo.main_game_id ||
this.gameUserInfo.main_game_id == 0
) {
this.contentLoading = true;
const data = { const data = {
type: 'gameListWithType', type: "gameListWithType",
value: '', value: "",
use_type: 2, use_type: 2,
game_id: this.gameUserInfo.main_game_id, game_id: this.gameUserInfo.main_game_id,
use_user_id: this.userInfo.id, use_user_id: this.userInfo.id,
weixin_blongs_id: this.weixin_blongs_id weixin_blongs_id: this.weixin_blongs_id,
} };
selectSearch(data).then((res) => { selectSearch(data).then((res) => {
this.contentLoading = false this.contentLoading = false;
if (res.status_code == 1) { if (res.status_code == 1) {
// 暂时隐藏快手小游戏 // 暂时隐藏快手小游戏
const ksGameIndex = res.data.data.findIndex(item => item.label === '快手小游戏') const ksGameIndex = res.data.data.findIndex(
(item) => item.label === "快手小游戏"
);
if (ksGameIndex !== -1) { if (ksGameIndex !== -1) {
res.data.data.splice(ksGameIndex, 1) res.data.data.splice(ksGameIndex, 1);
} }
this.regGameList = res.data.data this.regGameList = res.data.data;
this.allRegGameList = this.regGameList this.allRegGameList = this.regGameList;
} }
this.requestGameSendLog() this.requestGameSendLog();
setTimeout(() => { setTimeout(() => {
this.contentLoading = false this.contentLoading = false;
}, 2000) }, 2000);
}) });
} else { } else {
} }
}, },
onConfirm() { }, onConfirm() {},
// 召回发送渠道 // 召回发送渠道
sendChannel(items, type) { sendChannel(items, type) {
items.type = 3 items.type = 3;
type ? this.sendType = type : '' type ? (this.sendType = type) : "";
this.channelList(items) this.channelList(items);
}, },
// 转游发送渠道 // 转游发送渠道
sendChannelGame(items, item, type) { sendChannelGame(items, item, type) {
console.log(items, 'items', item) console.log(items, "items", item);
type ? this.sendType = type : '' type ? (this.sendType = type) : "";
const gameInfo = this.$clone(items) const gameInfo = this.$clone(items);
gameInfo.type = 2 gameInfo.type = 2;
this.channelList(gameInfo) this.channelList(gameInfo);
}, },
changeGameText() { changeGameText() {
console.log(this.filterGameText) console.log(this.filterGameText);
if (this.filterGameText.trim() === '') { if (this.filterGameText.trim() === "") {
this.regGameList = this.allRegGameList this.regGameList = this.allRegGameList;
} else { } else {
const list = JSON.parse(JSON.stringify(this.allRegGameList)) const list = JSON.parse(JSON.stringify(this.allRegGameList));
list.map((item, index) => { list.map((item, index) => {
item.children = item.children.filter( item.children = item.children.filter(
(items) => items.label.indexOf(this.filterGameText) !== -1 (items) => items.label.indexOf(this.filterGameText) !== -1
) );
}) });
this.regGameList = list this.regGameList = list;
} }
}, },
// 获取渠道列表 // 获取渠道列表
channelList(items) { channelList(items) {
console.log(items, 'items') console.log(items, "items");
const data = { const data = {
game_id: items.game_id || items.id, game_id: items.game_id || items.id,
page_size: 200, page_size: 200,
page: 1, page: 1,
zq_user_id: this.userInfo.id, zq_user_id: this.userInfo.id,
weixin_blongs_id: items.weixin_blongs_id ? [items.weixin_blongs_id] : this.weixin_blongs_id, weixin_blongs_id: items.weixin_blongs_id
request_system: 'company_wx', ? [items.weixin_blongs_id]
: this.weixin_blongs_id,
request_system: "company_wx",
member_id: this.accountSelect, member_id: this.accountSelect,
use_type: this.activeName use_type: this.activeName,
} };
channelList(data).then((res) => { channelList(data).then((res) => {
if (res?.data?.data?.data?.length > 0) { if (res?.data?.data?.data?.length > 0) {
// 只有一个的时候自动发送渠道链接 // 只有一个的时候自动发送渠道链接
...@@ -477,89 +719,94 @@ export default { ...@@ -477,89 +719,94 @@ export default {
game_id: items.game_id || items.id, game_id: items.game_id || items.id,
use_type: this.activeName, use_type: this.activeName,
sendType: this.sendType, sendType: this.sendType,
channelList: res.data.data.data channelList: res.data.data.data,
} };
// 只有 1 个渠道的时候 直接发送不出现弹窗 // 只有 1 个渠道的时候 直接发送不出现弹窗
if (this.channelInfoList.channelList.length === 1) { if (this.channelInfoList.channelList.length === 1) {
this.showSendChannel = true this.showSendChannel = true;
} else { } else {
this.showLayer = true this.showLayer = true;
} }
this.sendGameLog(items) this.sendGameLog(items);
} else { } else {
this.$message.warning('请到掌游创建运营渠道') this.$message.warning("请到掌游创建运营渠道");
} }
}) });
}, },
showSendGameLayer() { showSendGameLayer() {
this.showLayer = true this.showLayer = true;
}, },
async sendGameList() { async sendGameList() {
if (this.conversionGameList.length == 0) { if (this.conversionGameList.length == 0) {
this.contentLoading = true this.contentLoading = true;
// 获取召回转端的游戏列表 user_type: 1 转端 3 召回 // 获取召回转端的游戏列表 user_type: 1 转端 3 召回
const res = await getGameConfig({ use_type: 1 }) const res = await getGameConfig({ use_type: 1 });
this.contentLoading = false this.contentLoading = false;
if (res.status_code === 1 && res.data.data.length > 0) { if (res.status_code === 1 && res.data.data.length > 0) {
const ksGameIndex = res.data.data.findIndex(item => item.game_type == 6) const ksGameIndex = res.data.data.findIndex(
(item) => item.game_type == 6
);
if (ksGameIndex != -1) { if (ksGameIndex != -1) {
res.data.data.splice(ksGameIndex, 1) res.data.data.splice(ksGameIndex, 1);
this.conversionGameList = res.data.data this.conversionGameList = res.data.data;
} else { } else {
this.conversionGameList = res.data.data this.conversionGameList = res.data.data;
} }
} }
setTimeout(() => { setTimeout(() => {
this.contentLoading = false this.contentLoading = false;
}, 2000) }, 2000);
} }
}, },
async conversionChangeOld(value) { async conversionChangeOld(value) {
console.log('请求数据', this.conversionGameList) console.log("请求数据", this.conversionGameList);
if (this.isReqeustData) { if (this.isReqeustData) {
return return;
} }
try { try {
this.isReqeustData = true this.isReqeustData = true;
this.gameLoding = true this.gameLoding = true;
// 使用 Promise.all 并发请求游戏列表数据 // 使用 Promise.all 并发请求游戏列表数据
const promiseList = this.conversionGameList.map(async (item, index) => { const promiseList = this.conversionGameList.map(async (item, index) => {
// 如果已有子项数据则跳过 // 如果已有子项数据则跳过
if (this.conversionGameList[index].children?.length > 0) { if (this.conversionGameList[index].children?.length > 0) {
return return;
} }
try { try {
const params = { const params = {
member_id: this.accountSelect, member_id: this.accountSelect,
type: item.game_type type: item.game_type,
} };
const reslist = await memberExtensionGameList(params) const reslist = await memberExtensionGameList(params);
if (reslist.status_code === 1) { if (reslist.status_code === 1) {
// 使用解构赋值简化数据设置 // 使用解构赋值简化数据设置
const updates = { const updates = {
children: reslist.data?.length > 0 ? reslist.data : [], children: reslist.data?.length > 0 ? reslist.data : [],
send_trans_page_id: '', // 转端要发送的游戏 ID send_trans_page_id: "", // 转端要发送的游戏 ID
isReqeustData: true isReqeustData: true,
} };
Object.entries(updates).forEach(([key, value]) => { Object.entries(updates).forEach(([key, value]) => {
this.$set(this.conversionGameList[index], key, value) this.$set(this.conversionGameList[index], key, value);
}) });
} }
} catch (error) { } catch (error) {
console.error(`Failed to fetch game list for index ${index}:`, error) console.error(
`Failed to fetch game list for index ${index}:`,
error
);
// 设置空数组作为默认值 // 设置空数组作为默认值
this.$set(this.conversionGameList[index], 'children', []) this.$set(this.conversionGameList[index], "children", []);
} }
}) });
await Promise.all(promiseList) await Promise.all(promiseList);
this.handleConversionGameList() this.handleConversionGameList();
} catch (error) { } catch (error) {
console.error('Failed to fetch conversion game lists:', error) console.error("Failed to fetch conversion game lists:", error);
} finally { } finally {
this.gameLoding = false this.gameLoding = false;
this.isReqeustData = false this.isReqeustData = false;
} }
}, },
// 处理转端数据 之前王鑫和冯渊说要隐藏破日开天游戏 至于什么时候放开 没说 // 处理转端数据 之前王鑫和冯渊说要隐藏破日开天游戏 至于什么时候放开 没说
...@@ -567,38 +814,72 @@ export default { ...@@ -567,38 +814,72 @@ export default {
if (this.conversionGameList.length > 0) { if (this.conversionGameList.length > 0) {
this.conversionGameList.forEach((item, index) => { this.conversionGameList.forEach((item, index) => {
// 隐藏 h5的游戏 912:神权之战 784:荣耀时刻 // 隐藏 h5的游戏 912:神权之战 784:荣耀时刻
if (item.game_type === 2 && item.children && item.children.length > 0) { if (
const filteredChildren = item.children.filter(child => { item.game_type === 2 &&
return child.game_id !== '912' && child.game_id != '784' item.children &&
}) item.children.length > 0
this.$set(this.conversionGameList[index], 'children', filteredChildren) ) {
const filteredChildren = item.children.filter((child) => {
return child.game_id !== "912" && child.game_id != "784";
});
this.$set(
this.conversionGameList[index],
"children",
filteredChildren
);
} }
// 隐藏安卓游戏 安卓游戏 game_type: 3 // 隐藏安卓游戏 安卓游戏 game_type: 3
if (item.game_type === 3 && item.children && item.children.length > 0) { if (
item.game_type === 3 &&
item.children &&
item.children.length > 0
) {
// 过滤掉 game_name 为"破日开天"的数据 // 过滤掉 game_name 为"破日开天"的数据
const filteredChildren = item.children.filter(child => { const filteredChildren = item.children.filter((child) => {
return child.game_name !== '破日开天' && child.game_name !== '英雄霸业' && child.game_id !== '741' && child.game_id !== '912' return (
}) child.game_name !== "破日开天" &&
this.$set(this.conversionGameList[index], 'children', filteredChildren) child.game_name !== "英雄霸业" &&
child.game_id !== "741" &&
child.game_id !== "912"
);
});
this.$set(
this.conversionGameList[index],
"children",
filteredChildren
);
} }
// 隐藏 IOS 游戏 雄霸天下 有两个包 1 个是 691 一个是 819 王鑫说 暂时先隐藏 691 的功能 // 隐藏 IOS 游戏 雄霸天下 有两个包 1 个是 691 一个是 819 王鑫说 暂时先隐藏 691 的功能
if (item.game_type === 4 && item.children && item.children.length > 0) { if (
const filteredChildren = item.children.filter(child => { item.game_type === 4 &&
return Number(child.game_id) !== 691 item.children &&
}) item.children.length > 0
this.$set(this.conversionGameList[index], 'children', filteredChildren) ) {
} const filteredChildren = item.children.filter((child) => {
}) return Number(child.game_id) !== 691;
console.log(this.conversionGameList, 'conversionGameList') });
this.$set(
this.conversionGameList[index],
"children",
filteredChildren
);
}
});
console.log(this.conversionGameList, "conversionGameList");
} }
}, },
// 转端展开 // 转端展开
async conversionChange(value) { async conversionChange(value) {
if (value && value.length > 0) { if (value && value.length > 0) {
const gameType = value[value.length - 1] const gameType = value[value.length - 1];
const gameIndex = this.conversionGameList.findIndex(item => item.game_type === gameType) const gameIndex = this.conversionGameList.findIndex(
if (!this.conversionGameList[gameIndex].children || this.conversionGameList[gameIndex].children.length == 0) { (item) => item.game_type === gameType
this.gameLoding = true );
if (
!this.conversionGameList[gameIndex].children ||
this.conversionGameList[gameIndex].children.length == 0
) {
this.gameLoding = true;
const params = { const params = {
page_size: 200, page_size: 200,
page: 1, page: 1,
...@@ -606,50 +887,60 @@ export default { ...@@ -606,50 +887,60 @@ export default {
weixin_blongs_id: this.weixin_blongs_id, weixin_blongs_id: this.weixin_blongs_id,
use_type: 1, use_type: 1,
member_id: this.accountSelect, member_id: this.accountSelect,
type: this.conversionGameList[gameIndex].game_type type: this.conversionGameList[gameIndex].game_type,
} };
const reslist = await getTransferRecallGameList(params) const reslist = await getTransferRecallGameList(params);
this.gameLoding = false this.gameLoding = false;
if (reslist.status_code === 1 && reslist.data.data.length > 0) { if (reslist.status_code === 1 && reslist.data.data.length > 0) {
this.$set(this.conversionGameList[gameIndex], 'children', reslist.data.data) this.$set(
this.conversionGameList[gameIndex],
"children",
reslist.data.data
);
} else { } else {
this.$set(this.conversionGameList[gameIndex], 'children', []) this.$set(this.conversionGameList[gameIndex], "children", []);
} }
setTimeout(() => { setTimeout(() => {
this.gameLoding = false this.gameLoding = false;
}, 2000) }, 2000);
} else { } else {
} }
} }
}, },
// 召回的游戏列表 // 召回的游戏列表
async sendGameRecallList() { async sendGameRecallList() {
if (this.recallGameList.length == 0) { if (this.recallGameList.length == 0) {
this.contentLoading = true this.contentLoading = true;
const res = await getGameConfig({ use_type: 3 }) const res = await getGameConfig({ use_type: 3 });
this.contentLoading = false this.contentLoading = false;
if (res.status_code === 1 && res.data.data.length > 0) { if (res.status_code === 1 && res.data.data.length > 0) {
const ksGameIndex = res.data.data.findIndex(item => item.game_type == 6) const ksGameIndex = res.data.data.findIndex(
(item) => item.game_type == 6
);
if (ksGameIndex !== -1) { if (ksGameIndex !== -1) {
res.data.data.splice(ksGameIndex, 1) res.data.data.splice(ksGameIndex, 1);
this.recallGameList = res.data.data this.recallGameList = res.data.data;
} else { } else {
this.recallGameList = res.data.data this.recallGameList = res.data.data;
} }
} }
setTimeout(() => { setTimeout(() => {
this.contentLoading = false this.contentLoading = false;
}, 2000) }, 2000);
} }
}, },
// 召回展开 // 召回展开
async recallChange(value) { async recallChange(value) {
if (value && value.length > 0) { if (value && value.length > 0) {
const gameType = value[value.length - 1] const gameType = value[value.length - 1];
const gameIndex = this.recallGameList.findIndex(item => item.game_type === gameType) const gameIndex = this.recallGameList.findIndex(
if (!this.recallGameList[gameIndex].children || this.recallGameList[gameIndex].children.length == 0) { (item) => item.game_type === gameType
this.gameLoding = true );
if (
!this.recallGameList[gameIndex].children ||
this.recallGameList[gameIndex].children.length == 0
) {
this.gameLoding = true;
const params = { const params = {
// type: 2, // type: 2,
page_size: 200, page_size: 200,
...@@ -658,86 +949,90 @@ export default { ...@@ -658,86 +949,90 @@ export default {
weixin_blongs_id: this.weixin_blongs_id, weixin_blongs_id: this.weixin_blongs_id,
use_type: 3, use_type: 3,
member_id: this.accountSelect, member_id: this.accountSelect,
type: this.recallGameList[gameIndex].game_type type: this.recallGameList[gameIndex].game_type,
} };
const reslist = await getTransferRecallGameList(params) const reslist = await getTransferRecallGameList(params);
this.gameLoding = false this.gameLoding = false;
if (reslist.status_code === 1 && reslist.data.data.length > 0) { if (reslist.status_code === 1 && reslist.data.data.length > 0) {
this.$set(this.recallGameList[gameIndex], 'children', reslist.data.data) this.$set(
this.recallGameList[gameIndex],
"children",
reslist.data.data
);
} else { } else {
this.$set(this.recallGameList[gameIndex], 'children', []) this.$set(this.recallGameList[gameIndex], "children", []);
} }
setTimeout(() => { setTimeout(() => {
this.gameLoding = false this.gameLoding = false;
}, 2000) }, 2000);
} else { } else {
console.log('之前请求过了') console.log("之前请求过了");
} }
} }
}, },
showPopover() { showPopover() {
this.showCreateChannel = false this.showCreateChannel = false;
this.isReqeustData = false this.isReqeustData = false;
}, },
handlePopover() { handlePopover() {
this.showCreateChannel = false this.showCreateChannel = false;
}, },
handleAccount() { handleAccount() {
if (this.bindGameUserList.length > 0) { if (this.bindGameUserList.length > 0) {
const account = this.bindGameUserList.find( const account = this.bindGameUserList.find(
(item) => item.member_id == this.accountSelect (item) => item.member_id == this.accountSelect
) );
if (account) { if (account) {
return true return true;
} else { } else {
return false return false;
} }
} else { } else {
return false return false;
} }
}, },
sendLink: throttle(function (item, type) { sendLink: throttle(function (item, type) {
if (!this.transMemberStatus) { if (!this.transMemberStatus) {
this.$message.warning('当前w账号不满足转端要求,请联系组长处理') this.$message.warning("当前w账号不满足转端要求,请联系组长处理");
return return;
} }
console.log(item, '转端发送仅发送链接') console.log(item, "转端发送仅发送链接");
const result = this.handleAccount() const result = this.handleAccount();
if (!result) { if (!result) {
this.$message.warning('请稍后再试') this.$message.warning("请稍后再试");
return false return false;
} }
let str = '' let str = "";
if (type == 2) { if (type == 2) {
str = '网页游戏链接:' str = "网页游戏链接:";
} else if (type == 3) { } else if (type == 3) {
str = '安卓游戏链接:' str = "安卓游戏链接:";
} else if (type == 4) { } else if (type == 4) {
str = 'IOS游戏链接:' str = "IOS游戏链接:";
} else { } else {
} }
// const list = [ // const list = [
// { msgtype: 'text', text: { content: `${str}${item.url}` }} // { msgtype: 'text', text: { content: `${str}${item.url}` }}
// ] // ]
this.sendChatMessage(`${str}${item.url}`, 'text') this.sendChatMessage(`${str}${item.url}`, "text");
this.markTransScene(type) this.markTransScene(type);
item.type = 1 item.type = 1;
this.sendGameLog(item) this.sendGameLog(item);
}, 500), }, 500),
sendPassword: throttle(function (item, type) { sendPassword: throttle(function (item, type) {
if (!this.transMemberStatus) { if (!this.transMemberStatus) {
this.$message.warning('当前w账号不满足转端要求,请联系组长处理') this.$message.warning("当前w账号不满足转端要求,请联系组长处理");
return return;
} }
console.log(item, '转端仅发送账号密码') console.log(item, "转端仅发送账号密码");
const result = this.handleAccount() const result = this.handleAccount();
if (!result) { if (!result) {
this.$message.warning('请稍后再试') this.$message.warning("请稍后再试");
return false return false;
} }
const username = this.bindGameUserList.find( const username = this.bindGameUserList.find(
(items) => items.member_id == this.accountSelect (items) => items.member_id == this.accountSelect
).username ).username;
passwardEncryption({ member_id: this.accountSelect }) passwardEncryption({ member_id: this.accountSelect })
.then((res) => { .then((res) => {
// const list = [ // const list = [
...@@ -747,132 +1042,239 @@ export default { ...@@ -747,132 +1042,239 @@ export default {
// } // }
// ] // ]
// this.set_sendSkillMessage(list) // this.set_sendSkillMessage(list)
this.sendChatMessage(`账号:${username} \n密码:${res.data.password}`, 'text') this.sendChatMessage(
this.markTransScene(type) `账号:${username} \n密码:${res.data.password}`,
this.sendGameLog(item) "text"
);
this.markTransScene(type);
this.sendGameLog(item);
}) })
.catch((err) => { .catch((err) => {
const list = [ const list = [
{ msgtype: 'text', text: { content: `账号:${username}` } } { msgtype: "text", text: { content: `账号:${username}` } },
] ];
// this.set_sendSkillMessage(list) // this.set_sendSkillMessage(list)
this.sendChatMessage(`账号:${username}`, 'text') this.sendChatMessage(`账号:${username}`, "text");
item.type = 1 item.type = 1;
this.sendGameLog(item) this.sendGameLog(item);
console.log(err) console.log(err);
}) });
}, 500), }, 500),
sendMessage: throttle(function (item, type) { sendMessage: throttle(function (item, type) {
if (!this.transMemberStatus) { if (!this.transMemberStatus) {
this.$message.warning('当前w账号不满足转端要求,请联系组长处理') this.$message.warning("当前w账号不满足转端要求,请联系组长处理");
return return;
} }
const result = this.handleAccount() const result = this.handleAccount();
if (!result) { if (!result) {
this.$message.warning('请稍后再试') this.$message.warning("请稍后再试");
return false return false;
} }
let str = '' let str = "";
if (type == 2) { if (type == 2) {
str = '网页游戏链接:' str = "网页游戏链接:";
} else if (type == 3) { } else if (type == 3) {
str = '安卓游戏链接:' str = "安卓游戏链接:";
} else if (type == 4) { } else if (type == 4) {
str = 'IOS游戏链接:' str = "IOS游戏链接:";
} else { } else {
} }
const username = this.bindGameUserList.find( const username = this.bindGameUserList.find(
(items) => items.member_id == this.accountSelect (items) => items.member_id == this.accountSelect
).username ).username;
passwardEncryption({ member_id: this.accountSelect }) passwardEncryption({ member_id: this.accountSelect })
.then((res) => { .then((res) => {
const list = [ const list = [
{ {
msgtype: 'text', msgtype: "text",
text: { text: {
content: `${str}${item.url} \n账号:${username} \n密码:${res.data.password}`, content: `${str}${item.url} \n账号:${username} \n密码:${res.data.password}`,
key: res.data.key, iv: res.data.iv key: res.data.key,
} iv: res.data.iv,
} },
] },
];
// this.set_sendSkillMessage(list) // this.set_sendSkillMessage(list)
this.sendChatMessage(`${str}${item.url} \n账号:${username} \n密码:${res.data.password}`, 'text') this.sendChatMessage(
this.markTransScene(type) `${str}${item.url} \n账号:${username} \n密码:${res.data.password}`,
item.type = 1 "text"
this.sendGameLog(item) );
this.markTransScene(type);
item.type = 1;
this.sendGameLog(item);
}) })
.catch((err) => { .catch((err) => {
const list = [ const list = [
{ {
msgtype: 'text', msgtype: "text",
text: { content: `${str}${item.url} \n账号:${username}` } text: { content: `${str}${item.url} \n账号:${username}` },
} },
] ];
// this.set_sendSkillMessage(list) // 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);
}) });
}, 500), }, 500),
// 发送游戏落地页 // 发送游戏落地页
startSendPage(value) { startSendPage(value) {
console.log(value, 'value') console.log(value, "value");
// this.set_sendSkillMessage(list) // this.set_sendSkillMessage(list)
this.getMediaId(value, 'image') this.getMediaId(value, "image");
}, },
// 转端发送落地页面 // 转端发送落地页面
sendDownLoadPage: throttleStart(function (items, type, index) { sendDownLoadPage: throttleStart(function (items, type, index) {
if (!this.transMemberStatus) { if (!this.transMemberStatus) {
this.$message.warning('当前w账号不满足转端要求,请联系组长处理') this.$message.warning("当前w账号不满足转端要求,请联系组长处理");
return return;
}
this.$set(
this.conversionGameList[index],
"send_trans_page_id",
items.game_id
);
this.showSendPage = true;
}, 500),
// 转端发送游戏二维码
sendDownLoadQrCode: throttleStart(async function (items, type, index) {
if (!this.transMemberStatus) {
this.$message.warning("当前w账号不满足转端要求,请联系组长处理");
return;
}
const result = this.handleAccount();
if (!result) {
this.$message.warning("请稍后再试");
return false;
}
try {
this.sendLoading = true;
// 获取游戏落地页链接
let landingPageUrl = "";
if (items.url) {
landingPageUrl = items.url;
}
if (!landingPageUrl) {
this.$message.error("没有有效的链接可生成二维码");
return;
}
// 设置二维码内容
this.qrCodeValue = landingPageUrl;
// 等待DOM更新,确保二维码已生成
await this.$nextTick();
// 获取二维码canvas并转换为Blob
const canvas = this.$refs.qrcode.$el.querySelector("canvas");
if (!canvas) {
throw new Error("获取二维码canvas失败");
}
const blob = await new Promise((resolve) => {
canvas.toBlob((blob) => {
resolve(blob);
}, "image/png");
});
// 创建File对象
blob.name = "qrcode.png";
// 上传图片
const uploadConfig = {
dir: "/company_wx/service/avatars/",
};
const uploadResult = await this.uploading(blob, uploadConfig);
debugger;
if (uploadResult.data) {
// 发送上传后的链接
// const list = [
// {
// msgtype: "image",
// image: {
// picurl: uploadResult.data,
// },
// },
// ];
// const image = {
// picurl: uploadResult.data,
// };
// console.log(image, 12312321);
this.sendChatMessage(uploadResult.data, "image");
this.markTransScene(type);
items.type = 1;
this.sendGameLog(items);
this.$message.success("二维码发送成功");
} else {
throw new Error("上传失败");
}
} catch (error) {
console.error("发送二维码失败:", error);
this.$message.error("发送二维码失败,请重试");
} finally {
this.sendLoading = false;
} }
this.$set(this.conversionGameList[index], 'send_trans_page_id', items.game_id)
this.showSendPage = true
}, 500), }, 500),
// 转端标记 // 转端标记
async markTransScene(type) { async markTransScene(type) {
const data = { const data = {
external_userid: this.chatUserInfo.external_userid, external_userid: this.chatUserInfo.external_userid,
trans_scene: type trans_scene: type,
} };
const res = await markTransScene(data) const res = await markTransScene(data);
if (res.status_code == 1) { if (res.status_code == 1) {
console.log('标记转端成功') console.log("标记转端成功");
if (this.chatUserInfo.trans_scene && this.chatUserInfo.trans_scene !== '' && this.chatUserInfo.trans_scene != type) { if (
this.chatUserInfo.trans_scene = type this.chatUserInfo.trans_scene &&
this.chatUserInfo.trans_scene !== "" &&
this.chatUserInfo.trans_scene != type
) {
this.chatUserInfo.trans_scene = type;
} }
} }
}, },
getZqCserWxBelong() { getZqCserWxBelong() {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
const data = { const data = {
zq_user_id: Number(this.userInfo.id) zq_user_id: Number(this.userInfo.id),
} };
const res = await getZqCserWxBelong(data) const res = await getZqCserWxBelong(data);
if (res.status_code === 1 && res.data.data) { if (res.status_code === 1 && res.data.data) {
this.belongList = res.data.data.map(item => { this.belongList = res.data.data.map((item) => {
return { return {
value: item.value, value: item.value,
label: item.label && item.label.split('-')[0] ? item.label.split('-')[0] : '' label:
} item.label && item.label.split("-")[0]
}) ? item.label.split("-")[0]
resolve(this.belongList) : "",
};
});
resolve(this.belongList);
} else { } else {
this.$message.warning('暂无绑定项目,请先绑定项目') this.$message.warning("暂无绑定项目,请先绑定项目");
reject(null) reject(null);
} }
}) });
}, },
// 一键发送任务链接 // 一键发送任务链接
async sendTaskChannel() { async sendTaskChannel() {
let groupItem = {} let groupItem = {};
let belonsList = {} let belonsList = {};
const group = await getZqCserGroup({ zq_user_id: Number(this.userInfo.id) }) const group = await getZqCserGroup({
belonsList = await this.getZqCserWxBelong() zq_user_id: Number(this.userInfo.id),
if (group.status_code == 1 && group.data.data.length > 0 && belonsList && belonsList.length > 0) { });
groupItem = group.data.data[0] belonsList = await this.getZqCserWxBelong();
const group_name_list = groupItem.label.split('-') if (
group.status_code == 1 &&
group.data.data.length > 0 &&
belonsList &&
belonsList.length > 0
) {
groupItem = group.data.data[0];
const group_name_list = groupItem.label.split("-");
const data = { const data = {
blongs_name: belonsList[0].label, blongs_name: belonsList[0].label,
member_id: this.accountSelect, member_id: this.accountSelect,
...@@ -880,27 +1282,27 @@ export default { ...@@ -880,27 +1282,27 @@ export default {
use_user_name: this.userInfo.username, use_user_name: this.userInfo.username,
group_id: groupItem.value, group_id: groupItem.value,
group_name: group_name_list[group_name_list.length - 1], group_name: group_name_list[group_name_list.length - 1],
game_type: this.chatUserInfo.trans_scene || '' game_type: this.chatUserInfo.trans_scene || "",
} };
this.sendLoading = true this.sendLoading = true;
try { try {
setTimeout(() => { setTimeout(() => {
this.sendLoading = false this.sendLoading = false;
}, 3000) }, 3000);
const res = await quickRecallChannelLink(data) const res = await quickRecallChannelLink(data);
this.sendLoading = false this.sendLoading = false;
if (res.status_code == 1) { if (res.status_code == 1) {
this.sendGameInfoSave = res.data.data this.sendGameInfoSave = res.data.data;
this.handleSendType(res.data.data) this.handleSendType(res.data.data);
this.$message.success(res.msg) this.$message.success(res.msg);
} }
} catch (error) { } catch (error) {
this.$message.error('获取召回链接失败,请重新再试') this.$message.error("获取召回链接失败,请重新再试");
this.sendLoading = false this.sendLoading = false;
} }
} else { } else {
this.$message.error('获取分组失败,请到掌权添加分组') this.$message.error("获取分组失败,请到掌权添加分组");
return return;
} }
}, },
/** /**
...@@ -917,16 +1319,17 @@ export default { ...@@ -917,16 +1319,17 @@ export default {
*/ */
handleSendType(data) { handleSendType(data) {
console.log(data, '获取一键发送的信息') console.log(data, "获取一键发送的信息");
// 转端发送优先逻辑 不需要了 现在发送当前会话框选中的账号对应的注册游戏 // 转端发送优先逻辑 不需要了 现在发送当前会话框选中的账号对应的注册游戏
data?.game_data?.game_type ? this.chatUserInfo.trans_scene = data.game_data.game_type : '' data?.game_data?.game_type
? (this.chatUserInfo.trans_scene = data.game_data.game_type)
: "";
if (this.chatUserInfo.trans_scene && this.chatUserInfo.trans_scene != 1) { if (this.chatUserInfo.trans_scene && this.chatUserInfo.trans_scene != 1) {
this.sendCreateChannel(data.game_data, data.game_data.game_type) this.sendCreateChannel(data.game_data, data.game_data.game_type);
} else { } else {
// 没有转端标记过,发送小程序链接 判断标题和封面是否存在 存在发小程序卡片 不存在发二维码 // 没有转端标记过,发送小程序链接 判断标题和封面是否存在 存在发小程序卡片 不存在发二维码
if (data.share_data.share_title && data.share_data.share_img) { if (data.share_data.share_title && data.share_data.share_img) {
const miniprogramInfo = const miniprogramInfo = {
{
appid: data.share_data.app_id, appid: data.share_data.app_id,
rawid: data.share_data.raw_id, rawid: data.share_data.raw_id,
channle_id: data.share_data.channel_key, channle_id: data.share_data.channel_key,
...@@ -934,182 +1337,210 @@ export default { ...@@ -934,182 +1337,210 @@ export default {
title: data.share_data.share_title, title: data.share_data.share_title,
platform: 27, platform: 27,
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.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.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);
} }
} }
this.recallChannelSeq(data) this.recallChannelSeq(data);
}, },
// 召回染色 // 召回染色
async recallChannelSeq(data) { async recallChannelSeq(data) {
const param = { const param = {
game_id: data.game_data.game_id, game_id: data.game_data.game_id,
member_id: this.accountSelect, member_id: this.accountSelect,
key: data.game_data.channel_key || data.share_data.channel_key key: data.game_data.channel_key || data.share_data.channel_key,
} };
const res = await recallChannelSeq(param) const res = await recallChannelSeq(param);
}, },
sendCreateChannel: throttle(function (item, type) { sendCreateChannel: throttle(function (item, type) {
const result = this.handleAccount() const result = this.handleAccount();
if (!result) { if (!result) {
this.$message.warning('请稍后再试') this.$message.warning("请稍后再试");
return false return false;
} }
let str = '' let str = "";
if (type == 2) { if (type == 2) {
str = '网页游戏链接:' str = "网页游戏链接:";
} else if (type == 3) { } else if (type == 3) {
str = '安卓游戏链接:' str = "安卓游戏链接:";
} else if (type == 4) { } else if (type == 4) {
str = 'IOS游戏链接:' str = "IOS游戏链接:";
} else { } else {
} }
const username = this.bindGameUserList.find( const username = this.bindGameUserList.find(
(items) => items.member_id == this.accountSelect (items) => items.member_id == this.accountSelect
).username ).username;
passwardEncryption({ member_id: this.accountSelect }) passwardEncryption({ member_id: this.accountSelect }).then((res) => {
.then((res) => {
const list = [ const list = [
{ {
msgtype: 'text', msgtype: "text",
// 一键发送渠道任务相关的参数 // 一键发送渠道任务相关的参数
taskInfo: { taskInfo: {
task_id: this.chatUser.task_id, task_id: this.chatUser.task_id,
game_id: item.game_id, game_id: item.game_id,
member_id: this.accountSelect, member_id: this.accountSelect,
channel_key: item.channel_key channel_key: item.channel_key,
}, },
text: { text: {
content: `${str}${item.game_url} \n账号:${username} \n密码:${res.data.password}`, content: `${str}${item.game_url} \n账号:${username} \n密码:${res.data.password}`,
key: res.data.key, iv: res.data.iv key: res.data.key,
} iv: res.data.iv,
} },
] },
];
// 这里需要特殊处理,因为有taskInfo参数 // 这里需要特殊处理,因为有taskInfo参数
// this.set_sendSkillMessage(list) // this.set_sendSkillMessage(list)
this.sendChatMessage(`${str}${item.game_url} \n账号:${username} \n密码:${res.data.password}`, 'text') this.sendChatMessage(
item.type = 3 `${str}${item.game_url} \n账号:${username} \n密码:${res.data.password}`,
this.sendGameLog(item) "text"
}) );
item.type = 3;
this.sendGameLog(item);
});
}, 500), }, 500),
async getLandingPageConfig(items, item) { async getLandingPageConfig(items, item) {
try { try {
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: items.game_type == 1 ? 2 : items.game_type == 3 || items.game_type == 4 ? 1 : '' type:
} items.game_type == 1
const res = await getLandingPageConfig(params) ? 2
: items.game_type == 3 || items.game_type == 4
? 1
: "",
};
const res = await getLandingPageConfig(params);
if (res.status_code === 1 && res.data) { if (res.status_code === 1 && res.data) {
return { return {
data: res.data, data: res.data,
game_type: items.game_type game_type: items.game_type,
} };
} else { } else {
return null return null;
}
} catch (error) {
} }
} catch (error) {}
}, },
// 处理微信小程序游戏 // 处理微信小程序游戏
handleWechatMiniGame(items, item, index) { handleWechatMiniGame(items, item, index) {
try { try {
this.selectedWxGameList = [] this.selectedWxGameList = [];
// 直接替换微信小游戏列表(单选) // 直接替换微信小游戏列表(单选)
this.selectedWxGameList = [item] this.selectedWxGameList = [item];
this.selectedWxGameList[0].send_trans_game_id = items.id this.selectedWxGameList[0].send_trans_game_id = items.id;
this.selectedWxGameList[0].send_trans_game_info = items this.selectedWxGameList[0].send_trans_game_info = items;
this.showWxGameDrawer = true this.showWxGameDrawer = true;
return true return true;
} catch (error) { } catch (error) {
console.error('处理微信小游戏失败:', error) console.error("处理微信小游戏失败:", error);
return false return false;
} }
}, },
// 过滤游戏列表的公共方法 // 过滤游戏列表的公共方法
filterGameList(sourceGame, targetList) { filterGameList(sourceGame, targetList) {
if (!sourceGame || !targetList?.length) return [] if (!sourceGame || !targetList?.length) return [];
return targetList.filter(game => return targetList.filter(
(game) =>
game.weixin_blongs_id === sourceGame.weixin_blongs_id && game.weixin_blongs_id === sourceGame.weixin_blongs_id &&
game.main_game_id === sourceGame.main_game_id game.main_game_id === sourceGame.main_game_id
) );
}, },
handleAndroidList(items, item) { handleAndroidList(items, item) {
const androidGameList = this.regGameList.find(item => item.label.includes('安卓')) const androidGameList = this.regGameList.find((item) =>
if (androidGameList && androidGameList.children && androidGameList.children.length > 0) { item.label.includes("安卓")
androidGameList.children = this.filterGameList(items, androidGameList.children) );
if (
androidGameList &&
androidGameList.children &&
androidGameList.children.length > 0
) {
androidGameList.children = this.filterGameList(
items,
androidGameList.children
);
} else { } else {
androidGameList.children = [] androidGameList.children = [];
} }
androidGameList.game_type = 3 androidGameList.game_type = 3;
if (items.game_type == 3) { if (items.game_type == 3) {
androidGameList.android_game_id = items.id androidGameList.android_game_id = items.id;
androidGameList.android_game_info = items androidGameList.android_game_info = items;
} }
return androidGameList return androidGameList;
}, },
handleIosList(items, item) { handleIosList(items, item) {
const IOSGameList = this.regGameList.find(item => item.label.includes('IOS' || 'ios')) const IOSGameList = this.regGameList.find((item) =>
IOSGameList.game_type = 4 item.label.includes("IOS" || "ios")
if (IOSGameList && IOSGameList.children && IOSGameList.children.length > 0) { );
IOSGameList.children = this.filterGameList(items, IOSGameList.children) IOSGameList.game_type = 4;
if (
IOSGameList &&
IOSGameList.children &&
IOSGameList.children.length > 0
) {
IOSGameList.children = this.filterGameList(items, IOSGameList.children);
} else { } else {
IOSGameList.children = [] IOSGameList.children = [];
} }
if (items.game_type == 4) { if (items.game_type == 4) {
IOSGameList.ios_game_id = items.id IOSGameList.ios_game_id = items.id;
IOSGameList.ios_game_info = items IOSGameList.ios_game_info = items;
} }
return IOSGameList return IOSGameList;
}, },
// 处理安卓 IOS 游戏 // 处理安卓 IOS 游戏
handleAppGameList(items, item, index) { handleAppGameList(items, item, index) {
this.showAppGameDrawer = true this.showAppGameDrawer = true;
const androidGameList = this.handleAndroidList(items, item) const androidGameList = this.handleAndroidList(items, item);
const IOSGameList = this.handleIosList(items, item) const IOSGameList = this.handleIosList(items, item);
androidGameList ? this.selectedAppGameList.push(androidGameList) : '' androidGameList ? this.selectedAppGameList.push(androidGameList) : "";
IOSGameList ? this.selectedAppGameList.push(IOSGameList) : '' IOSGameList ? this.selectedAppGameList.push(IOSGameList) : "";
console.log(this.selectedAppGameList, 'selectedAppGameList') console.log(this.selectedAppGameList, "selectedAppGameList");
}, },
// 主方法 // 主方法
async handleGameType(items, item, type, index) { async handleGameType(items, item, type, index) {
if ((items.game_type == 1 || items.game_type == 3 || items.game_type == 4) && items.main_game_id && items.weixin_blongs_id) { if (
const result = await this.getLandingPageConfig(items, item) (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);
if (result && result.data?.data?.tag) { if (result && result.data?.data?.tag) {
if (items.game_type == 1) { if (items.game_type == 1) {
// 处理微信小程序游戏 // 处理微信小程序游戏
this.handleWechatMiniGame(items, item, index) this.handleWechatMiniGame(items, item, index);
} else { } else {
// 处理安卓/iOS游戏 // 处理安卓/iOS游戏
this.handleAppGameList(items, item, index) this.handleAppGameList(items, item, index);
} }
} else { } else {
this.sendChannelGame(items, item) this.sendChannelGame(items, item);
} }
} else { } else {
this.sendChannelGame(items, item) this.sendChannelGame(items, item);
} }
}, },
// 不是小游戏 安卓 IOS 游戏处理 // 不是小游戏 安卓 IOS 游戏处理
noH5AndroidIOSGame(items, item) { noH5AndroidIOSGame(items, item) {
this.sendChannelGame(items, item) this.sendChannelGame(items, item);
}, },
// 小游戏游戏确认 // 小游戏游戏确认
async handleWxGameConfirm(value) { async handleWxGameConfirm(value) {
console.log(value, 'value') console.log(value, "value");
// const list = [ // const list = [
// { // {
// msgtype: 'image', // msgtype: 'image',
...@@ -1119,17 +1550,17 @@ export default { ...@@ -1119,17 +1550,17 @@ export default {
// } // }
// ] // ]
// this.set_sendSkillMessage(list) // this.set_sendSkillMessage(list)
this.getMediaId(value, 'image') this.getMediaId(value, "image");
}, },
SendTransAppGameClose() { SendTransAppGameClose() {
this.selectedAppGameList = [] this.selectedAppGameList = [];
}, },
SendTransWxGameClose() { SendTransWxGameClose() {
this.selectedWxGameList = [] this.selectedWxGameList = [];
}, },
// 安卓或者 IOS 游戏处理 // 安卓或者 IOS 游戏处理
handleAppGameConfirm(data) { handleAppGameConfirm(data) {
this.selectedAppGameList = [] this.selectedAppGameList = [];
// const list = [ // const list = [
// { // {
// msgtype: 'text', // msgtype: 'text',
...@@ -1139,20 +1570,23 @@ export default { ...@@ -1139,20 +1570,23 @@ export default {
// } // }
// ] // ]
// this.set_sendSkillMessage(list) // this.set_sendSkillMessage(list)
this.sendChatMessage(`游戏地址:${data.landing_page_url} \n账号:${data.username} \n密码:${data.password}`, 'text') this.sendChatMessage(
`游戏地址:${data.landing_page_url} \n账号:${data.username} \n密码:${data.password}`,
"text"
);
}, },
async getMediaId(picurl) { async getMediaId(picurl) {
// 发送图片作为链接消息 // 发送图片作为链接消息
if (picurl) { if (picurl) {
this.sendChatMessage(picurl, 'image') this.sendChatMessage(picurl, "image");
} else { } else {
// 如果没有图片URL,提示用户 // 如果没有图片URL,提示用户
this.$message.error('图片链接不存在,无法发送') this.$message.error("图片链接不存在,无法发送");
} }
}, },
} },
} };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.sendGameContent { .sendGameContent {
...@@ -1181,7 +1615,7 @@ export default { ...@@ -1181,7 +1615,7 @@ export default {
} }
.channelLoading { .channelLoading {
color: #3491FA; color: #3491fa;
font-size: 16px; font-size: 16px;
text-align: center; text-align: center;
padding: 20px; padding: 20px;
...@@ -1246,8 +1680,8 @@ export default { ...@@ -1246,8 +1680,8 @@ export default {
} }
::v-deep .el-button { ::v-deep .el-button {
background: #3491FA; background: #3491fa;
border-color: #3491FA; border-color: #3491fa;
color: #fff; color: #fff;
font-size: 14px; font-size: 14px;
height: 32px; height: 32px;
...@@ -1268,8 +1702,8 @@ export default { ...@@ -1268,8 +1702,8 @@ export default {
::v-deep .el-popover__reference { ::v-deep .el-popover__reference {
.el-button { .el-button {
background: #3491FA; background: #3491fa;
border-color: #3491FA; border-color: #3491fa;
color: #fff; color: #fff;
&:hover { &:hover {
...@@ -1296,7 +1730,7 @@ export default { ...@@ -1296,7 +1730,7 @@ export default {
font-size: 14px; font-size: 14px;
&:focus { &:focus {
border-color: #3491FA; border-color: #3491fa;
} }
} }
...@@ -1317,20 +1751,20 @@ export default { ...@@ -1317,20 +1751,20 @@ export default {
/* 当转端按钮处于激活状态时保持自定义样式 */ /* 当转端按钮处于激活状态时保持自定义样式 */
::v-deep .el-radio-button.is-active { ::v-deep .el-radio-button.is-active {
.el-radio-button__inner { .el-radio-button__inner {
background: #E8F7FF; background: #e8f7ff;
border-color: #3491FA; border-color: #3491fa;
border: 1px solid #3491FA; border: 1px solid #3491fa;
color: #3491FA; color: #3491fa;
box-shadow: none; box-shadow: none;
} }
} }
/* 统一collapse样式 */ /* 统一collapse样式 */
::v-deep .el-collapse-item__header { ::v-deep .el-collapse-item__header {
background-color: #F7F8FA; background-color: #f7f8fa;
.el-collapse-item__arrow { .el-collapse-item__arrow {
color: #3491FA; color: #3491fa;
} }
} }
} }
...@@ -1345,7 +1779,7 @@ export default { ...@@ -1345,7 +1779,7 @@ export default {
} }
.sendLink:hover { .sendLink:hover {
color: #3491FA; color: #3491fa;
background-color: #f5f7fa; background-color: #f5f7fa;
} }
</style> </style>
...@@ -6,23 +6,69 @@ ...@@ -6,23 +6,69 @@
<p class="textInfo"> <p class="textInfo">
角色充值金额信息会有5-10分钟延迟,请以订单信息为准 角色充值金额信息会有5-10分钟延迟,请以订单信息为准
</p> </p>
<el-button type="primary" size="small" class="h-[30px]" @click.stop="appealLayer()">申诉</el-button> <el-button
</div> type="primary"
<el-collapse v-model="collapseActive" @change="handleChange"> size="small"
<div v-for="(items, indexs) in roleList" :key="indexs" class="contentItem mb-[10px]"> class="h-[30px]"
@click.stop="appealLayer()"
>申诉</el-button
>
</div>
<el-collapse v-model="collapseActive">
<div
v-for="(items, indexs) in roleList"
:key="indexs"
class="contentItem"
>
<div class="title"></div> <div class="title"></div>
<el-collapse-item :name="items.id"> <el-collapse-item :name="items.role_id">
<template slot="title"> <template slot="title">
<!-- <div class="collapseTitle rowFlex columnCenter spaceBetween"> <div
<p class="hidden"> class="grid grid-cols-7 w-[100%] leading-[24px] gap-[8px] py-[12px]"
{{ items.role_name }} - {{ items.server_name }} - {{ >
items.recharge_total ? items.recharge_total + '元' : '0元' }} <div class="col-span-3">
</p> <div
<el-button type="primary" size="mini" class="collapseTitleBtn" class="text-[#323335] text-[16px] font-medium group hover:text-[#409EFF]"
@click.stop="appealLayer(items)">申诉</el-button> >
</div> --> <span class="flex items-center"
<div class="flex w-[100%] justify-between"> >{{ items.role_name
<div class="py-[10px]"> }}<i
class="group-hover:visible invisible"
v-copy="
`${items.role_name}-${items.server_name}-${
items.recharge_total || 0
}元`
"
></i>
</span>
</div>
<div class="text-[#4E5969] text-[14px]">
<span>区服:</span><span>{{ items.server_name }}</span>
</div>
</div>
<div class="col-span-2">
<div class="text-[#4E5969] text-[14px]">充值金额</div>
<div class="text-[#4E5969] text-[16px]">
<!-- <span>{{ items.recharge_total ? items.recharge_total + '元' : '0元' }}</span> -->
<span>{{ items.recharge_total || 0 }}</span>
</div>
</div>
<div
class="col-span-2"
@click.stop="
() =>
recentActivitiesPopupInstance.instance.open(
items.role_id,
`${items.role_name}-${items.server_name}-${items.recharge_total}元`
)
"
>
<div class="text-[#4E5969] text-[14px]">近期要开</div>
<el-button type="text" class="text-[16px] font-medium">{{
getNumRoleIdList(items.role_id)
}}</el-button>
</div>
<!-- <div class="py-[10px]">
<div class="leading-[25px]"> <div class="leading-[25px]">
<span>角色名:</span><span>{{ items.role_name }}</span> <span>角色名:</span><span>{{ items.role_name }}</span>
</div> </div>
...@@ -30,46 +76,38 @@ ...@@ -30,46 +76,38 @@
<span>区服:</span><span>{{ items.server_name }}</span> <span>区服:</span><span>{{ items.server_name }}</span>
</div> </div>
<div class="leading-[25px]"> <div class="leading-[25px]">
<span>充值金额:</span><span>{{ <span>充值金额:</span><span>{{ items.recharge_total ? items.recharge_total + '元' : '0元' }}</span>
items.recharge_total
? items.recharge_total + '元'
: '0元'
}}</span>
<vip-level :role-info="items" /> <vip-level :role-info="items" />
</div> </div>
</div> </div>
<div class="flex-1 h-0 flex justify-end items-start pt-[10px]"> <div class="flex-1 h-0 flex justify-end items-start pt-[10px]">
<el-badge :value="getNumRoleIdList(items.role_id)" class="text-center leading-[0] ml-[8px]"> <el-badge :value="getNumRoleIdList(items.role_id)" class="text-center leading-[0] ml-[8px]">
<el-button type="primary" size="mini" @click.stop=" <el-button type="primary" size="mini" @click.stop="() => recentActivitiesPopupInstance.instance.open(items.role_id, `${items.role_name}-${items.server_name}-${items.recharge_total}元`)">近期要开</el-button>
() =>
recentActivitiesPopupInstance.instance.open(
items.role_id,
`${items.role_name}-${items.server_name}-${items.recharge_total}元`
)
">
近期要开</el-button>
</el-badge> </el-badge>
</div> </div> -->
</div> </div>
</template> </template>
<div class="item rowFlex columnCenter spaceBetween"> <div
class="w-full border-t-[1px] border-t-[#E5E7EB] border-dashed"
>
<!-- <div class="item rowFlex columnCenter spaceBetween">
<div class="rowFlex columnCenter"> <div class="rowFlex columnCenter">
<span class="label">区服:</span> <span class="label">区服:</span>
<p class="text">{{ items.server_name }}</p> <p class="text">{{ items.server_name }}</p>
</div> </div>
</div> </div> -->
<div class="item rowFlex columnCenter spaceBetween"> <div class="item rowFlex columnCenter spaceBetween">
<div class="rowFlex columnCenter"> <div class="rowFlex columnCenter">
<span class="label">合区区服:</span> <span class="label">合区区服:</span>
<p class="text">{{ items.merge_server_name }}</p> <p class="text">{{ items.merge_server_name }}</p>
</div> </div>
</div> </div>
<div class="item rowFlex columnCenter spaceBetween"> <!-- <div class="item rowFlex columnCenter spaceBetween">
<div class="rowFlex columnCenter"> <div class="rowFlex columnCenter">
<span class="label">角色名称:</span> <span class="label">角色名称:</span>
<p class="text">{{ items.role_name }}</p> <p class="text">{{ items.role_name }}</p>
</div> </div>
</div> </div> -->
<div class="item rowFlex columnCenter spaceBetween"> <div class="item rowFlex columnCenter spaceBetween">
<div class="rowFlex columnCenter"> <div class="rowFlex columnCenter">
<span class="label">等级:</span> <span class="label">等级:</span>
...@@ -82,16 +120,16 @@ ...@@ -82,16 +120,16 @@
<p class="text">{{ items.combat_num }}</p> <p class="text">{{ items.combat_num }}</p>
</div> </div>
</div> </div>
<div class="item rowFlex columnCenter spaceBetween"> <!-- <div class="item rowFlex columnCenter spaceBetween">
<div class="rowFlex columnCenter"> <div class="rowFlex columnCenter">
<span class="label">充值金额:</span> <span class="label">充值金额:</span>
<p class="text">{{ items.recharge_total }}</p> <p class="text">{{ items.recharge_total }}</p>
</div> </div>
</div> </div> -->
<div class="item rowFlex columnCenter spaceBetween"> <div class="item rowFlex columnCenter spaceBetween">
<div class="rowFlex columnCenter"> <div class="rowFlex columnCenter">
<span class="label">转端审核:</span> <span class="label">转端审核:</span>
<p class="text">{{ items.trans_status_name || '无' }}</p> <p class="text">{{ items.trans_status_name || "无" }}</p>
</div> </div>
</div> </div>
<div class="item rowFlex columnCenter spaceBetween"> <div class="item rowFlex columnCenter spaceBetween">
...@@ -106,7 +144,7 @@ ...@@ -106,7 +144,7 @@
<p class="text"> <p class="text">
{{ {{
$moment(items.last_login_time * 1000).format( $moment(items.last_login_time * 1000).format(
'YYYY-MM-DD HH:mm:ss' "YYYY-MM-DD HH:mm:ss"
) )
}} }}
</p> </p>
...@@ -118,7 +156,7 @@ ...@@ -118,7 +156,7 @@
<p class="text"> <p class="text">
{{ {{
$moment(items.create_time * 1000).format( $moment(items.create_time * 1000).format(
'YYYY-MM-DD HH:mm:ss' "YYYY-MM-DD HH:mm:ss"
) )
}} }}
</p> </p>
...@@ -130,29 +168,48 @@ ...@@ -130,29 +168,48 @@
<p class="text">{{ items.create_role_day }}天</p> <p class="text">{{ items.create_role_day }}天</p>
</div> </div>
</div> </div>
<div class="item rowFlex columnCenter spaceBetween">
<div class="rowFlex columnCenter">
<span class="label">开/合服天数:</span>
<p class="text" v-if="items.server_day">
{{ items?.server_day }}天
</p>
</div>
</div>
</div>
</el-collapse-item> </el-collapse-item>
</div> </div>
</el-collapse> </el-collapse>
</div> </div>
<div v-else-if="!loading && roleList.length == 0" class="noContent rowFlex allCenter"> <div
<noContent title="暂无数据" description="当前没有任何数据,请稍后再试或联系管理员" /> v-else-if="!loading && roleList.length == 0"
class="noContent rowFlex allCenter"
>
<noContent
title="暂无数据"
description="当前没有任何数据,请稍后再试或联系管理员"
/>
</div> </div>
</div> </div>
<appeal v-if="showAppeal" :show.sync="showAppeal" :appeal-info="appealInfo" /> <appeal
v-if="showAppeal"
:show.sync="showAppeal"
:appeal-info="appealInfo"
/>
</div> </div>
</template> </template>
<script> <script>
import { mapState, mapMutations, mapActions } from 'vuex'; import { mapState, mapMutations, mapActions } from "vuex";
import { getRoleHoLo,marketingRoleGrade } from '@/api/game'; import { getRoleHoLo, marketingRoleGrade, getServerDayApi } 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";
export default { export default {
name: 'roleInfo', name: "roleInfo",
components: { components: {
noContent, noContent,
appeal, appeal,
...@@ -162,7 +219,7 @@ export default { ...@@ -162,7 +219,7 @@ export default {
return { return {
collapseActive: [], collapseActive: [],
roleList: [], roleList: [],
nowTime: '', nowTime: "",
loading: false, loading: false,
showAppeal: false, showAppeal: false,
appealInfo: {}, appealInfo: {},
...@@ -178,7 +235,14 @@ export default { ...@@ -178,7 +235,14 @@ export default {
}; };
}, },
computed: { computed: {
...mapState('game', ['accountSelect']), ...mapState("game", ["accountSelect"]),
},
watch: {
collapseActive(newVal, oldVal) {
if (newVal.length > 0) {
this.handleChange(newVal.filter((item) => !oldVal.includes(item)));
}
},
}, },
mixins: [watchMember], mixins: [watchMember],
mounted() { mounted() {
...@@ -208,29 +272,42 @@ export default { ...@@ -208,29 +272,42 @@ export default {
this this
); );
}, },
async handleRoleListLevel(roleList){ async handleRoleListLevel(roleList) {
try { try {
const role_id_list = roleList.map((item) => item.role_id) const role_id_list = roleList.map((item) => item.role_id);
const res = await marketingRoleGrade({role_id:role_id_list}) const res = await marketingRoleGrade({ role_id: role_id_list });
if(res.status_code == 1 && res?.data?.data?.length > 0){ if (res.status_code == 1 && res?.data?.data?.length > 0) {
const levelList = res.data.data const levelList = res.data.data;
roleList.forEach((item) => { roleList.forEach((item) => {
const levelItem = levelList.find((level) => level.role_id == item.role_id) const levelItem = levelList.find(
if(levelItem){ (level) => level.role_id == item.role_id
item.vip_level = levelItem.vip_level );
if (levelItem) {
item.vip_level = levelItem.vip_level;
} }
}) });
} }
} catch (error) { } catch (error) {
console.log(error) console.log(error);
} finally { } finally {
this.roleList = roleList.sort((a, b) => { this.roleList = roleList.sort((a, b) => {
return Number(b.recharge_total) - Number(a.recharge_total) return Number(b.recharge_total) - Number(a.recharge_total);
}) });
} }
}, },
handleChange() { }, async handleChange(v) {
const index = this.roleList.findIndex(
(item) => v.includes(item.role_id) && !item.server_day
);
if (index !== -1) {
const res = await getServerDayApi({
role_id: this.roleList[index].role_id,
});
this.roleList[index].server_day = res.data.data?.server_day;
this.roleList = [...this.roleList];
}
},
memberChange() { memberChange() {
this.requestRoleList(); this.requestRoleList();
}, },
...@@ -240,15 +317,15 @@ export default { ...@@ -240,15 +317,15 @@ export default {
this.showAppeal = true; this.showAppeal = true;
}, },
requestRoleList() { requestRoleList() {
if (this.accountSelect === '') { if (this.accountSelect === "") {
this.$message.warning('暂无关联的账号,请先去关联账号!'); this.$message.warning("暂无关联的账号,请先去关联账号!");
return false; return false;
} }
this.loading = true; this.loading = true;
const data = { const data = {
api_search_name: '', api_search_name: "",
member_id: this.accountSelect, member_id: this.accountSelect,
search_type: 'list', search_type: "list",
...this.pageInfo, ...this.pageInfo,
}; };
getRoleHoLo(data).then( getRoleHoLo(data).then(
...@@ -256,7 +333,7 @@ export default { ...@@ -256,7 +333,7 @@ export default {
this.loading = false; this.loading = false;
if (res.status_code == 1) { if (res.status_code == 1) {
if (res.data.data.length > 0) { if (res.data.data.length > 0) {
this.handleRoleListLevel(res.data.data) this.handleRoleListLevel(res.data.data);
} else { } else {
this.roleList = []; this.roleList = [];
} }
...@@ -396,11 +473,12 @@ export default { ...@@ -396,11 +473,12 @@ export default {
} }
::v-deep .el-collapse-item { ::v-deep .el-collapse-item {
margin-bottom: 20px; margin-bottom: 1px;
} }
::v-deep .el-collapse-item__content { ::v-deep .el-collapse-item__content {
padding-bottom: 10px; // padding-bottom: 10px;
padding: 0 0 10px 0;
} }
::v-deep .el-collapse { ::v-deep .el-collapse {
...@@ -408,13 +486,17 @@ export default { ...@@ -408,13 +486,17 @@ export default {
} }
::v-deep .el-collapse-item__header { ::v-deep .el-collapse-item__header {
flex-direction: row-reverse;
width: 100%; width: 100%;
height: auto; height: auto;
background: #f9faff; background: transparent;
color: #333333; color: #333333;
padding-left: 10px; padding-left: 10px;
font-size: 14px; font-size: 14px;
font-weight: 400; font-weight: 400;
&:hover {
background: #f7f8fa;
}
} }
::v-deep .el-collapse .el-collapse-item__header .el-collapse-item__arrow { ::v-deep .el-collapse .el-collapse-item__header .el-collapse-item__arrow {
...@@ -428,7 +510,15 @@ export default { ...@@ -428,7 +510,15 @@ export default {
::v-deep .el-card__header, ::v-deep .el-card__header,
::v-deep .el-collapse, ::v-deep .el-collapse,
::v-deep .el-collapse-item__header { ::v-deep .el-collapse-item__header {
border: 0 !important; // border: 0 !important;
}
::v-deep .el-collapse-item__arrow {
color: #b1b3b8 !important;
margin-right: 10px !important;
}
::v-deep .el-collapse-item__wrap {
background-color: transparent !important;
border-bottom: 1px solid #ebeef5 !important;
} }
/* 已移除局部 el-collapse 样式,使用全局样式 */ /* 已移除局部 el-collapse 样式,使用全局样式 */
......
...@@ -4,23 +4,49 @@ ...@@ -4,23 +4,49 @@
<!-- 标签 --> <!-- 标签 -->
<el-collapse-transition> <el-collapse-transition>
<div v-if="groupList.length > 0" class="tagList columnFlex"> <div v-if="groupList.length > 0" class="tagList columnFlex">
<div v-for="(item, index) in groupList" :key="index" class="tagItem columnCenter" :draggable="false" <div
v-for="(item, index) in groupList"
:key="index"
class="tagItem columnCenter"
:draggable="false"
:class="groupActive == item.value ? 'tagItemActiveText' : ''" :class="groupActive == item.value ? 'tagItemActiveText' : ''"
@dragstart="handleDragStart($event, item, index)" @dragover.prevent="handleDragOver($event, item)" @dragstart="handleDragStart($event, item, index)"
@dragenter="handleDragEnter($event, item, 'group')" @dragend="handleDragEnd($event, item, 'group')"> @dragover.prevent="handleDragOver($event, item)"
<div class="rowFlex columnCenter spaceBetween tagItemGroup" @click="groupFilter(item, index)"> @dragenter="handleDragEnter($event, item, 'group')"
@dragend="handleDragEnd($event, item, 'group')"
>
<div
class="rowFlex columnCenter spaceBetween tagItemGroup"
@click="groupFilter(item, index)"
>
<div class="rowFlex columnCenter"> <div class="rowFlex columnCenter">
<el-tooltip effect="dark" placement="top" :content="item.name" v-if="item.name.length >= 6"> <el-tooltip
effect="dark"
placement="top"
:content="item.name"
v-if="item.name.length >= 6"
>
<p class="text hidden">{{ item.name }}</p> <p class="text hidden">{{ item.name }}</p>
</el-tooltip> </el-tooltip>
<p v-else class="text hidden">{{ item.name }}</p> <p v-else class="text hidden">{{ item.name }}</p>
</div> </div>
<i class="el-icon-caret-right rotageIcon" :class="groupActive == item.value ? 'rotage' : ''"></i> <i
class="el-icon-caret-right rotageIcon"
:class="groupActive == item.value ? 'rotage' : ''"
></i>
</div> </div>
<!-- 二级分组 --> <!-- 二级分组 -->
<div v-if="item.child.length > 0 && groupActive == item.value" class="childGroup"> <div
<div v-for="child in item.child" :key="child._id" class="childGroupText" v-if="item.child.length > 0 && groupActive == item.value"
:class="[groupActiveChild == child._id ? 'tagItemActive' : '']" @click.stop="groupFilterChild(child)"> class="childGroup"
>
<div
v-for="child in item.child"
:key="child._id"
class="childGroupText"
:class="[groupActiveChild == child._id ? 'tagItemActive' : '']"
@click.stop="groupFilterChild(child)"
>
<p class="text hidden">{{ child.name }}</p> <p class="text hidden">{{ child.name }}</p>
</div> </div>
</div> </div>
...@@ -33,27 +59,67 @@ ...@@ -33,27 +59,67 @@
<!-- 话术 --> <!-- 话术 -->
<div class="libraryListContent"> <div class="libraryListContent">
<div class="inputContent"> <div class="inputContent">
<el-input v-model="requestData.title" placeholder="请输入话术内容" class="input-with-select"> <el-input
<el-button slot="append" icon="el-icon-search" @click="contentSearch"></el-button> v-model="requestData.title"
placeholder="请输入话术内容"
class="input-with-select"
>
<el-button
slot="append"
icon="el-icon-search"
@click="contentSearch"
></el-button>
</el-input> </el-input>
</div> </div>
<div ref="skillLibrary" v-loading="skillLoading" @scroll="paperScroll" class="scrollList"> <div
<div v-for="(items, indexs) in groupDataList" :key="indexs" class="answerContent"> ref="skillLibrary"
<div class="question"><span class="title">Q:</span>{{ items.question }}</div> v-loading="skillLoading"
<div v-for="(answer, answerIndex) in items.answer" :key="answerIndex" class="answerItem" @scroll="paperScroll"
style="width: 100%"> class="scrollList"
>
<div
v-for="(items, indexs) in groupDataList"
:key="indexs"
class="answerContent"
>
<div class="question">
<span class="title">Q:</span>{{ items.question }}
</div>
<div
v-for="(answer, answerIndex) in items.answer"
:key="answerIndex"
class="answerItem"
style="width: 100%"
>
<!-- <span class="question">{{ answerIndex + 1 }}: {{ answer }}</span> --> <!-- <span class="question">{{ answerIndex + 1 }}: {{ answer }}</span> -->
<div v-if="answer.msgtype == 'text'" class="answerText rowFlex spaceBetween"> <div
v-if="answer.msgtype == 'text'"
class="answerText rowFlex spaceBetween"
>
<span class="title rowFlex">A{{ answerIndex + 1 }}:</span> <span class="title rowFlex">A{{ answerIndex + 1 }}:</span>
<p v-if="answer.msgtype == 'text'" class="rowFlex textAnswer flex1"> <p
{{ answer.text.content || '' }} v-if="answer.msgtype == 'text'"
class="rowFlex textAnswer flex1"
>
{{ answer.text.content || "" }}
</p> </p>
<i class="el-icon-document-copy copyIcon rowFlex" @click="sendMessageEdit(answer, items._id)"></i> <i
class="el-icon-document-copy copyIcon rowFlex"
@click="sendMessageEdit(answer, items._id)"
></i>
</div> </div>
<div v-else-if="answer.msgtype == 'image'" class="answerText rowFlex"> <div
v-else-if="answer.msgtype == 'image'"
class="answerText rowFlex"
>
<span class="title rowFlex">A{{ answerIndex + 1 }}:</span> <span class="title rowFlex">A{{ answerIndex + 1 }}:</span>
<el-image style="max-width: 200px" :src="answer.image.picurl" <el-image
@click="sendMessageImage(answer, items._id)" :preview-src-list="[answer.image.picurl]"> </el-image> style="max-width: 200px"
:src="answer.image.picurl"
@click="sendMessageImage(answer, items._id)"
:preview-src-list="[answer.image.picurl]"
>
</el-image>
</div> </div>
</div> </div>
</div> </div>
...@@ -65,26 +131,34 @@ ...@@ -65,26 +131,34 @@
<script> <script>
// procedure_group, procedureList, procedureSort, procedureGroupSort, skillQuote, // procedure_group, procedureList, procedureSort, procedureGroupSort, skillQuote,
import { cross_corp_robot_knowledge_group_index, cross_corp_robot_knowledge_group_getList } from '@/api/skill' import {
import { mapState, mapMutations, mapActions } from 'vuex' cross_corp_robot_knowledge_group_index,
import { throttle, debounce, copyToClipboard, sendChatMessage } from '@/utils/index' cross_corp_robot_knowledge_group_getList,
import noContent from '@/components/noContent.vue' } from "@/api/skill";
import { mapState, mapMutations, mapActions } from "vuex";
import {
throttle,
debounce,
copyToClipboard,
sendChatMessage,
} from "@/utils/index";
import noContent from "@/components/noContent.vue";
export default { export default {
name: 'skillLibrary', name: "skillLibrary",
components: { components: {
noContent noContent,
}, },
props: { props: {
activeName: { activeName: {
default: '', default: "",
type: String type: String,
} },
}, },
data() { data() {
return { return {
collapseActive: '', collapseActive: "",
groupActive: '0', groupActive: "0",
groupActiveChild: '0', groupActiveChild: "0",
activeGroup: {}, activeGroup: {},
groupList: [], groupList: [],
groupLastList: [], groupLastList: [],
...@@ -93,93 +167,93 @@ export default { ...@@ -93,93 +167,93 @@ export default {
pageInfo: { pageInfo: {
page: 1, page: 1,
page_size: 20, page_size: 20,
total: 0 total: 0,
}, },
skillLoading: false, skillLoading: false,
loading: false, loading: false,
requestData: { requestData: {
title: '', title: "",
first_group_id: '', first_group_id: "",
second_group_id: '' second_group_id: "",
}, },
sortType: '', sortType: "",
sortID: { sortID: {
_id: '', _id: "",
before_id: '', before_id: "",
after_id: '' after_id: "",
}, },
filterText: {}, filterText: {},
dragging: null, dragging: null,
orderList: [ orderList: [
{ label: '知识库', type: 'library' }, { label: "知识库", type: "library" },
{ label: '个人话术', type: 'personal' }, { label: "个人话术", type: "personal" },
{ label: '企业话术', type: 'company' } { label: "企业话术", type: "company" },
] ],
} };
}, },
computed: { computed: {
...mapState('game', ['accountSelect', 'chatUserInfo']), ...mapState("game", ["accountSelect", "chatUserInfo"]),
}, },
watch: { watch: {
accountSelect(newVal, oldVal) { accountSelect(newVal, oldVal) {
if (newVal && newVal !== '') { if (newVal && newVal !== "") {
this.pageInfo = { this.pageInfo = {
page: 1, page: 1,
page_size: 20, page_size: 20,
total: 0 total: 0,
} };
} }
}, },
activeName(newVal, oldVal) { activeName(newVal, oldVal) {
if (newVal == 'library' && newVal != oldVal) { if (newVal == "library" && newVal != oldVal) {
this.resizeSelect() this.resizeSelect();
this.requestLibraryData() this.requestLibraryData();
}
} }
}, },
},
mounted() { mounted() {
this.requestLibraryData() this.requestLibraryData();
}, },
methods: { methods: {
sendMessage: throttle(function (item, id) { sendMessage: throttle(function (item, id) {
console.log(item, id) console.log(item, id);
// this.skillQuote(id, item.length) // this.skillQuote(id, item.length)
}, 500), }, 500),
handleDragStart(e, item, index) { handleDragStart(e, item, index) {
this.sortID._id = item._id this.sortID._id = item._id;
this.dragging = item this.dragging = item;
}, },
paperScroll: debounce(function () { paperScroll: debounce(function () {
const el = this.$refs.skillLibrary const el = this.$refs.skillLibrary;
if (el.offsetHeight + el.scrollTop + 10 >= el.scrollHeight) { if (el.offsetHeight + el.scrollTop + 10 >= el.scrollHeight) {
console.log('下一页') console.log("下一页");
this.pageInfo.page++ this.pageInfo.page++;
this.searchTable() this.searchTable();
} }
}, 500), }, 500),
skillQuote(id, num) { skillQuote(id, num) {
const data = { const data = {
type: this.activeName, type: this.activeName,
procedure_id: id, procedure_id: id,
quote_count: num || 1 quote_count: num || 1,
} };
skillQuote(data).then((res) => { skillQuote(data).then((res) => {
console.log(res) console.log(res);
}) });
}, },
sortSkill() { sortSkill() {
procedureSort(this.sortID).then((res) => { procedureSort(this.sortID).then((res) => {
if (res.status_code == 1) { if (res.status_code == 1) {
this.$message.success(res.msg) this.$message.success(res.msg);
} }
}) });
}, },
sortSkillGroup() { sortSkillGroup() {
procedureGroupSort(this.sortID).then((res) => { procedureGroupSort(this.sortID).then((res) => {
if (res.status_code == 1) { if (res.status_code == 1) {
this.$message.success(res.msg) this.$message.success(res.msg);
} }
}) });
}, },
// 发送语音的时候 先编辑再发送 // 发送语音的时候 先编辑再发送
sendMessageEdit(item, id) { sendMessageEdit(item, id) {
...@@ -189,98 +263,107 @@ export default { ...@@ -189,98 +263,107 @@ export default {
item.text.content, item.text.content,
(message) => this.$message.success(message), (message) => this.$message.success(message),
(message) => this.$message.error(message) (message) => this.$message.error(message)
) );
} }
this.sendChatMessage(item.text.content || '', 'text') this.sendChatMessage(item.text.content || "", "text");
}, },
sendMessageImage(item) { sendMessageImage(item) {
console.log(item, 'item') console.log(item, "item");
this.sendChatMessage(item.image.picurl || '', 'image') this.sendChatMessage(item.image.picurl || "", "image");
}, },
contentSearch() { contentSearch() {
this.pageInfo = { this.pageInfo = {
page: 1, page: 1,
page_size: 20, page_size: 20,
total: 0 total: 0,
} };
this.searchTable('msg') this.searchTable("msg");
}, },
// 知识库话术 // 知识库话术
requestLibraryData() { requestLibraryData() {
console.log(this.chatUserInfo, 'chatUserInfo') console.log(this.chatUserInfo, "chatUserInfo");
this.loading = true this.loading = true;
const data = { const data = {
page: 1, page: 1,
page_size: 100, page_size: 100,
userid: this.chatUserInfo.userid userid: this.chatUserInfo.userid,
} };
cross_corp_robot_knowledge_group_index(data).then((res) => { cross_corp_robot_knowledge_group_index(data).then((res) => {
this.loading = false this.loading = false;
if (res.data.data) { if (res.data.data) {
res.data.data.unshift({ res.data.data.unshift({
name: '全部分组', name: "全部分组",
value: '', value: "",
child: [] child: [],
}) });
this.groupList = res.data.data.map((item, index) => { this.groupList = res.data.data.map((item, index) => {
item.label = item.name item.label = item.name;
item.value = item._id item.value = item._id;
return item return item;
}) });
this.groupLastList = this.groupList this.groupLastList = this.groupList;
this.groupFilter(this.groupList[0]) this.groupFilter(this.groupList[0]);
} else { } else {
this.groupList = [] this.groupList = [];
this.groupLastList = [] this.groupLastList = [];
} }
}) });
}, },
groupFilter(item, index) { groupFilter(item, index) {
if (!item._id) { if (!item._id) {
this.requestData.second_group_id = '' this.requestData.second_group_id = "";
this.activeGroup = {} this.activeGroup = {};
} }
this.groupActive = item.value this.groupActive = item.value;
item.child && item.child[0] ? ((this.activeGroup = item.child[0]), (this.groupActiveChild = item.child[0]._id)) : '' item.child && item.child[0]
this.searchTable() ? ((this.activeGroup = item.child[0]),
(this.groupActiveChild = item.child[0]._id))
: "";
this.searchTable();
}, },
groupFilterChild(child) { groupFilterChild(child) {
this.groupActiveChild = 0 this.groupActiveChild = 0;
this.activeGroup = child this.activeGroup = child;
this.groupActiveChild = child._id this.groupActiveChild = child._id;
this.searchTable() this.searchTable();
this.$forceUpdate() this.$forceUpdate();
}, },
// 搜索结果 // 搜索结果
async searchTable(msg) { async searchTable(msg) {
this.skillLoading = true this.skillLoading = true;
this.requestData.second_group_id = this.activeGroup._id || '' this.requestData.second_group_id = this.activeGroup._id || "";
this.requestData.title = this.requestData.title.trim() this.requestData.title = this.requestData.title.trim();
const data = { ...this.requestData, ...this.pageInfo, log_scan: msg ? 1 : 0, userid: this.chatUserInfo.userid } const data = {
...this.requestData,
...this.pageInfo,
log_scan: msg ? 1 : 0,
userid: this.chatUserInfo.userid,
};
cross_corp_robot_knowledge_group_getList(data).then((res) => { cross_corp_robot_knowledge_group_getList(data).then((res) => {
this.skillLoading = false this.skillLoading = false;
this.pageInfo.page === 1 ? this.groupDataList = res.data.data : this.groupDataList = this.groupDataList.concat(res.data.data) this.pageInfo.page === 1
this.groupLastDataList = this.groupDataList ? (this.groupDataList = res.data.data)
}) : (this.groupDataList = this.groupDataList.concat(res.data.data));
this.groupLastDataList = this.groupDataList;
});
}, },
handleChange() { }, handleChange() {},
// 重置select // 重置select
resizeSelect() { resizeSelect() {
this.groupActive = '0' this.groupActive = "0";
this.isResize = true this.isResize = true;
this.groupDataList = [] this.groupDataList = [];
this.requestData.content = '' this.requestData.content = "";
this.pageInfo.page = 1 this.pageInfo.page = 1;
setTimeout(() => { setTimeout(() => {
this.isResize = false this.isResize = false;
}, 2000) }, 2000);
}, },
sendChatMessage(content, type) { sendChatMessage(content, type) {
sendChatMessage(content, type) sendChatMessage(content, type);
}, },
} },
} };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.skillLibrary { .skillLibrary {
...@@ -321,7 +404,7 @@ export default { ...@@ -321,7 +404,7 @@ export default {
font-size: 14px; font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC; font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400; font-weight: 400;
color: #409EFF; color: #409eff;
margin-right: 10px; margin-right: 10px;
} }
...@@ -467,7 +550,6 @@ export default { ...@@ -467,7 +550,6 @@ export default {
.skillBox { .skillBox {
width: 100%; width: 100%;
height: calc(100% - 20px); height: calc(100% - 20px);
} }
.tagList { .tagList {
...@@ -513,14 +595,14 @@ export default { ...@@ -513,14 +595,14 @@ export default {
} }
.tagItemActive { .tagItemActive {
color: #409EFF !important; color: #409eff !important;
font-family: PingFangSC-Regular, PingFang SC; font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400; font-weight: 400;
background: #e4fff1; background: #e4fff1;
} }
.tagItemActiveText { .tagItemActiveText {
color: #409EFF; color: #409eff;
} }
} }
...@@ -607,7 +689,7 @@ export default { ...@@ -607,7 +689,7 @@ export default {
.copyIcon { .copyIcon {
width: 20px; width: 20px;
color: #409EFF; color: #409eff;
font-size: 16px; font-size: 16px;
position: relative; position: relative;
top: 2px; top: 2px;
...@@ -619,7 +701,7 @@ export default { ...@@ -619,7 +701,7 @@ export default {
} }
.scrollList::-webkit-scrollbar { .scrollList::-webkit-scrollbar {
display: none display: none;
} }
.container { .container {
...@@ -676,7 +758,7 @@ export default { ...@@ -676,7 +758,7 @@ export default {
} }
.skillLibrary::-webkit-scrollbar { .skillLibrary::-webkit-scrollbar {
display: none display: none;
} }
::v-deep .el-icon-circle-close { ::v-deep .el-icon-circle-close {
......
<!--
* @Description: 发送邮件弹窗组件
* @Date: 2025-10-15
-->
<template>
<el-dialog
:visible.sync="dialogVisible"
title="发送邮件"
width="300px"
:close-on-click-modal="false"
:before-close="handleClose"
append-to-body
>
<el-form
ref="emailForm"
:model="formData"
:rules="formRules"
label-width="80px"
class="email-form"
>
<el-form-item label="邮件标题:" prop="email_title">
<el-input
v-model="formData.email_title"
placeholder="请输入邮件标题"
maxlength="100"
show-word-limit
clearable
/>
</el-form-item>
<el-form-item label="邮件内容:" prop="email_content">
<el-input
v-model="formData.email_content"
type="textarea"
:rows="8"
placeholder="请输入邮件内容"
maxlength="1000"
show-word-limit
clearable
/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button size="small" @click="handleClose">取消</el-button>
<el-button
type="primary"
:loading="sending"
@click="handleConfirm"
size="small"
>确定</el-button>
</div>
</el-dialog>
</template>
<script>
import { sendEmail } from '@/api/game'
export default {
name: 'SendEmailDialog',
props: {
// 控制弹窗显示
visible: {
type: Boolean,
default: false
},
// 任务ID
taskId: {
type: [String, Number],
required: true
}
},
data() {
return {
// 弹窗显示状态
dialogVisible: false,
// 发送中状态
sending: false,
// 表单数据
formData: {
email_title: '',
email_content: ''
},
// 表单验证规则
formRules: {
email_title: [
{ required: true, message: '请输入邮件标题', trigger: 'blur' },
{ min: 1, max: 100, message: '邮件标题长度在 1 到 100 个字符', trigger: 'blur' }
],
email_content: [
{ required: true, message: '请输入邮件内容', trigger: 'blur' },
{ min: 1, max: 1000, message: '邮件内容长度在 1 到 1000 个字符', trigger: 'blur' }
]
}
}
},
watch: {
visible(val) {
this.dialogVisible = val
if (!val) {
// 关闭时重置表单
this.resetForm()
}
}
},
methods: {
/**
* 关闭弹窗
*/
handleClose() {
this.dialogVisible = false
this.$emit('update:visible', false)
this.resetForm()
},
/**
* 重置表单
*/
resetForm() {
this.formData = {
email_title: '',
email_content: ''
}
// 清除表单验证
this.$nextTick(() => {
this.$refs.emailForm && this.$refs.emailForm.clearValidate()
})
},
/**
* 确认发送邮件
*/
handleConfirm() {
// 表单验证
this.$refs.emailForm.validate((valid) => {
if (valid) {
this.sendEmailRequest()
} else {
console.log('表单验证失败')
return false
}
})
},
/**
* 发送邮件请求
*/
async sendEmailRequest() {
try {
this.sending = true
const params = {
id: this.taskId,
email_title: this.formData.email_title,
email_content: this.formData.email_content
}
const res = await sendEmail(params)
if (res.status_code === 1) {
this.$message({
message: res.msg || '邮件发送成功',
type: 'success'
})
// 通知父组件发送成功
this.$emit('send-success')
// 关闭弹窗
this.handleClose()
}
} catch (error) {
console.error('发送邮件失败:', error)
} finally {
this.sending = false
}
}
}
}
</script>
<style lang="scss" scoped>
.email-form {
::v-deep .el-form-item {
margin-bottom: 22px;
}
::v-deep .el-textarea__inner {
resize: vertical;
font-family: inherit;
}
::v-deep .el-input__count {
background-color: transparent;
}
}
.dialog-footer {
text-align: right;
padding: 10px 20px 0;
border: none;
.el-button {
min-width: 80px;
}
}
</style>
...@@ -27,62 +27,42 @@ ...@@ -27,62 +27,42 @@
class="rowFlex" class="rowFlex"
> >
<div class="label">{{ item.label }}</div> <div class="label">{{ item.label }}</div>
<div <div v-if="item.type == 'money'" class="value">
v-if="item.type == 'money'"
class="value"
>
<p> <p>
<span></span><span>{{ assionInfo[item.value] || 0 }}</span> <span></span><span>{{ assionInfo[item.value] || 0 }}</span>
</p> </p>
</div> </div>
<div <div v-else class="value">
v-else
class="value"
>
<span v-if="assionInfo[item.value]">{{ <span v-if="assionInfo[item.value]">{{
assionInfo[item.value] || "" assionInfo[item.value] || ''
}}</span> }}</span>
</div> </div>
</div> </div>
<div <div v-else-if="item.value == 'plan_type'" class="rowFlex">
v-else-if="item.value == 'plan_type'"
class="rowFlex"
>
<div class="label">{{ item.label }}</div> <div class="label">{{ item.label }}</div>
<div class="value"> <div class="value">
<span style="color: #0787f2">{{ <span style="color: #0787f2">{{
taskTypeList.find((k) => k.value == assionInfo[item.value]) taskTypeList.find((k) => k.value == assionInfo[item.value])
? taskTypeList.find((k) => k.value == assionInfo[item.value]) ? taskTypeList.find(
.label (k) => k.value == assionInfo[item.value]
: "" ).label
: ''
}}</span> }}</span>
</div> </div>
</div> </div>
<div <div v-else-if="item.value == 'target'" class="rowFlex">
v-else-if="item.value == 'target'"
class="rowFlex"
>
<div class="label">{{ item.label }}</div> <div class="label">{{ item.label }}</div>
<div class="value"> <div class="value">
<span <span v-if="assionInfo.target" style="color: #0787f2">{{
v-if="assionInfo.target"
style="color: #0787f2"
>{{
assionInfo.target.first && assionInfo.target.first.is_finished assionInfo.target.first && assionInfo.target.first.is_finished
? "已完成" ? '已完成'
: "未完成" : '未完成'
}}</span> }}</span>
</div> </div>
</div> </div>
<div <div v-else-if="item.value == 'finished_event'" class="rowFlex">
v-else-if="item.value == 'finished_event'"
class="rowFlex"
>
<div class="label">{{ item.label }}</div> <div class="label">{{ item.label }}</div>
<div <div v-if="assionInfo.finished_event" class="value">
v-if="assionInfo.finished_event"
class="value"
>
<span <span
v-for="(item, index) in assionInfo.finished_event" v-for="(item, index) in assionInfo.finished_event"
:key="index" :key="index"
...@@ -92,20 +72,14 @@ ...@@ -92,20 +72,14 @@
</div> </div>
</div> </div>
<!-- w 账号 --> <!-- w 账号 -->
<div <div v-else-if="item.value == 'username'" class="rowFlex">
v-else-if="item.value == 'username'"
class="rowFlex"
>
<div class="label">{{ item.label }}</div> <div class="label">{{ item.label }}</div>
<div <div
v-if="assionInfo.username && assionInfo.username.length > 0" v-if="assionInfo.username && assionInfo.username.length > 0"
class="value" class="value"
> >
<div <div v-if="assionInfo.username.length <= 1" class="rowFlex">
v-if="assionInfo.username.length <= 1"
class="rowFlex"
>
<div <div
v-for="(items, indexs) in assionInfo.username" v-for="(items, indexs) in assionInfo.username"
:key="indexs" :key="indexs"
...@@ -113,15 +87,13 @@ ...@@ -113,15 +87,13 @@
> >
<p <p
class="textHidden rowFlex userAlias" class="textHidden rowFlex userAlias"
style="max-width:150px;" style="max-width: 150px"
>{{ items }}</p> >
{{ items }}
</p>
</div> </div>
</div> </div>
<el-popover <el-popover v-else placement="top" trigger="click">
v-else
placement="top"
trigger="click"
>
<div style="max-width: 400px"> <div style="max-width: 400px">
<p <p
v-for="(items, indexs) in assionInfo.username" v-for="(items, indexs) in assionInfo.username"
...@@ -129,10 +101,9 @@ ...@@ -129,10 +101,9 @@
class="rowFlex columnCenter userInfoStyle" class="rowFlex columnCenter userInfoStyle"
style="margin-bottom: 10px" style="margin-bottom: 10px"
> >
<span <span class="textHidden" style="max-width: 150px">{{
class="textHidden" items
style="max-width:150px;" }}</span>
>{{ items }}</span>
</p> </p>
</div> </div>
<el-button <el-button
...@@ -140,7 +111,8 @@ ...@@ -140,7 +111,8 @@
type="text" type="text"
size="medium" size="medium"
style="margin-top: -10px" style="margin-top: -10px"
>{{ assionInfo.username.length }}</el-button> >{{ assionInfo.username.length }}</el-button
>
</el-popover> </el-popover>
</div> </div>
</div> </div>
...@@ -149,24 +121,12 @@ ...@@ -149,24 +121,12 @@
<div class="contentInfo"> <div class="contentInfo">
<div class="contentInfoItem rowFlex"> <div class="contentInfoItem rowFlex">
<div class="label">跟进状态</div> <div class="label">跟进状态</div>
<div <div v-if="assionInfo.status == 1" class="noSend">待跟进</div>
v-if="assionInfo.status == 1" <div v-else-if="assionInfo.status == 2" class="noSend">跟进中</div>
class="noSend" <div v-else-if="assionInfo.status == 3" class="sended">已跟进</div>
>待跟进</div>
<div
v-else-if="assionInfo.status == 2"
class="noSend"
>跟进中</div>
<div
v-else-if="assionInfo.status == 3"
class="sended"
>已跟进</div>
</div> </div>
<div v-if="remarks.remarks" class="remarks rowFlex flexWarp"> <div v-if="remarks.remarks" class="remarks rowFlex flexWarp">
<div <div v-for="(item, index) in remarks.remarks" :key="index">
v-for="(item, index) in remarks.remarks"
:key="index"
>
<div class="contentInfoItem rowFlex"> <div class="contentInfoItem rowFlex">
<div class="label">跟进时间</div> <div class="label">跟进时间</div>
<div class="value">{{ item.update_time }}</div> <div class="value">{{ item.update_time }}</div>
...@@ -174,10 +134,7 @@ ...@@ -174,10 +134,7 @@
<div class="contentInfoItem rowFlex"> <div class="contentInfoItem rowFlex">
<div class="label">备注</div> <div class="label">备注</div>
<div class="value"> <div class="value">
<div <div class="remarkContent" v-html="item.remark"></div>
class="remarkContent"
v-html="item.remark"
></div>
</div> </div>
</div> </div>
</div> </div>
...@@ -185,41 +142,40 @@ ...@@ -185,41 +142,40 @@
<!-- 发起会话 --> <!-- 发起会话 -->
<!-- 新增判断逻辑 根据 taskDetails 中的is_bind 判断 1:显示发起会话按钮 0:不显示发起会话按钮 --> <!-- 新增判断逻辑 根据 taskDetails 中的is_bind 判断 1:显示发起会话按钮 0:不显示发起会话按钮 -->
<div <div
v-if="kfhList && kfhList.length > 0 && assionInfo.status_name !== '已完成'" v-if="
kfhList &&
kfhList.length > 0 &&
assionInfo.status_name !== '已完成'
"
class="kfhList rowFlex columnCenter flexWarp" class="kfhList rowFlex columnCenter flexWarp"
> >
<div <div
v-for="(item, index) in kfhList" v-for="(item, index) in kfhList"
:key="index" :key="index"
class="sessionUserList " class="sessionUserList"
> >
<div style="margin-bottom: 10px" class="sessionUser"> <div style="margin-bottom: 10px" class="sessionUser">
<div class="kfhItem rowFlex spaceBetween"> <div class="kfhItem rowFlex spaceBetween">
<div class="left rowFlex columnCenter"> <div class="left rowFlex columnCenter">
<el-image <el-image :src="item.user.avatar" class="image"></el-image>
:src="item.user.avatar"
class="image"
></el-image>
<div class="name">{{ item.user.alias }}</div> <div class="name">{{ item.user.alias }}</div>
</div> </div>
<el-button <el-button
v-if="item.userid == userid " v-if="item.userid == userid"
class="right" class="right"
type="primary" type="primary"
size="small" size="small"
@click="requestSession(item)" @click="requestSession(item)"
>发起会话</el-button> >发起会话</el-button
>
<div v-else> <div v-else>
<svg-icon <svg-icon icon-class="chat" style="font-size: 26px" />
icon-class="chat"
style="font-size:26px;"
/>
</div> </div>
</div> </div>
<div class="wxUserInfo columnFlex"> <div class="wxUserInfo columnFlex">
<p> <p>
<span>用户备注:</span> <span>用户备注:</span>
<label style="word-break: break-all;">{{ <label style="word-break: break-all">{{
item.external_user.remark || item.external_user.name item.external_user.remark || item.external_user.name
}}</label> }}</label>
</p> </p>
...@@ -228,6 +184,27 @@ ...@@ -228,6 +184,27 @@
</div> </div>
</div> </div>
</div> </div>
<!-- 发送邮件按钮 -->
<!-- -->
<el-button
v-if="kfhList.length == 0 && assionInfo?.email?.is_send_email == 1 && !assionInfo?.email?.send_status && assionInfo.status != 3"
type="primary"
size="small"
style="margin-top: 20px; margin-right: 10px"
@click="showEmailDialog = true"
>发送邮件</el-button>
<!-- 礼包申请按钮 单日申请礼包任务和累充礼包申请时显示 -->
<!-- v-if="(assionInfo.plan_type == 19 || assionInfo.plan_type == 21) && assionInfo.status != 3" -->
<el-button
v-if="(assionInfo.plan_type == 19 || assionInfo.plan_type == 21) && assionInfo.status != 3"
type="primary"
size="small"
style="margin-top: 20px; margin-right: 10px"
:loading="loading"
@click="giftApply()"
>礼包申请</el-button>
<!-- 完成任务按钮 -->
<el-button <el-button
v-if="kfhList.length == 0 && taskDetails.status != 3 && !is_finished" v-if="kfhList.length == 0 && taskDetails.status != 3 && !is_finished"
type="primary" type="primary"
...@@ -255,7 +232,7 @@ ...@@ -255,7 +232,7 @@
> >
<!-- 新增异常原因筛选 当 plan_type==5 5:为大R异跟进异常时 新增异常原因筛选 --> <!-- 新增异常原因筛选 当 plan_type==5 5:为大R异跟进异常时 新增异常原因筛选 -->
<el-form-item <el-form-item
v-if="taskDetails.plan_type==5" v-if="taskDetails.plan_type == 5"
label="异常原因" label="异常原因"
prop="abnormal_types" prop="abnormal_types"
> >
...@@ -275,10 +252,7 @@ ...@@ -275,10 +252,7 @@
</el-option> </el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item <el-form-item label="跟进结果:" prop="trace_result">
label="跟进结果:"
prop="trace_result"
>
<el-select <el-select
v-model="webForm.trace_result" v-model="webForm.trace_result"
style="width: 100%" style="width: 100%"
...@@ -308,6 +282,24 @@ ...@@ -308,6 +282,24 @@
</el-form> </el-form>
</div> </div>
</layer> </layer>
<!-- 发送邮件弹窗 -->
<SendEmailDialog
:visible.sync="showEmailDialog"
:task-id="assionInfo.id"
@send-success="handleEmailSendSuccess"
/>
<!-- 礼包申请弹窗 -->
<applyGift
v-if="showApplyGift"
:show.sync="showApplyGift"
:member_id="assionInfo.member_id"
title="礼包申请"
width="25%"
:task_id="task_id"
@requestData="handleGiftApplySuccess"
/>
</div> </div>
</template> </template>
<script> <script>
...@@ -320,15 +312,19 @@ ...@@ -320,15 +312,19 @@
taskDetails, taskDetails,
taskTrack, taskTrack,
} from '@/api/game' } from '@/api/game'
import { memberBindExternalUser } from '@/api/works' import { memberBindExternalUser,clientSessionBindTaskApi } from '@/api/works'
import layer from '@/components/dialog.vue' import layer from '@/components/dialog.vue'
import SendEmailDialog from './SendEmailDialog.vue'
import applyGift from '@/views/components/giftRecord/applyGift.vue'
export default { export default {
computed: { computed: {
...mapState('game', ['taskDetails']), ...mapState('game', ['taskDetails']),
...mapState('user', ['userInfo','userid']) ...mapState('user', ['userInfo','userid'])
}, },
components: { components: {
layer layer,
SendEmailDialog,
applyGift
}, },
props: ['show'], props: ['show'],
data() { data() {
...@@ -344,6 +340,9 @@ ...@@ -344,6 +340,9 @@
assionInfo: {}, assionInfo: {},
current: 0, current: 0,
showLayer: false, showLayer: false,
showEmailDialog: false, // 控制发送邮件弹窗显示
showApplyGift: false, // 控制礼包申请弹窗显示
task_id: null, // 礼包申请任务ID
dialogRemake: '', dialogRemake: '',
webForm: { webForm: {
trace_result: '', trace_result: '',
...@@ -386,70 +385,70 @@ ...@@ -386,70 +385,70 @@
{ label: '目标客服号', value: 'target_service_name' }, { label: '目标客服号', value: 'target_service_name' },
{ label: '实名累充金额', value: 'recharge_total', type: 'money' }, { label: '实名累充金额', value: 'recharge_total', type: 'money' },
], ],
} };
}, },
watch: { watch: {
taskDetails(newVal, oldVal) { taskDetails(newVal, oldVal) {
if (newVal.member_id) { if (newVal.member_id) {
this.requestInit() this.requestInit();
}
} }
}, },
},
created() { created() {
this.assionInfo = this.taskDetails this.assionInfo = this.taskDetails;
}, },
mounted() { mounted() {
if (this.taskDetails.id) { if (this.taskDetails.id) {
this.requestInit() this.requestInit();
} }
}, },
methods: { methods: {
...mapMutations('game', ['set_taskDetails', 'set_task_session_member_id']), ...mapMutations('game', ['set_taskDetails', 'set_task_session_member_id']),
requestInit() { requestInit() {
this.current = 0 this.current = 0;
this.is_finished = false this.is_finished = false;
this.assionInfo = this.taskDetails this.assionInfo = this.taskDetails;
this.taskRecord() this.taskRecord();
this.memberOrder() this.memberOrder();
this.requestTaskDetails() this.requestTaskDetails();
this.searchTrackList() this.searchTrackList();
// 只有状态是 5 的时候 才请求 // 只有状态是 5 的时候 才请求
if (this.taskDetails.plan_type == 5) { if (this.taskDetails.plan_type == 5) {
this.searchconditionError() this.searchconditionError();
} }
}, },
close() { close() {
this.$emit('update:show', false) this.$emit('update:show', false);
}, },
searchconditionError() { searchconditionError() {
const data = { const data = {
type: 'dictionaries', type: 'dictionaries',
table_name: 'zs_operator_task', table_name: 'zs_operator_task',
field_name: 'abnormal_type' field_name: 'abnormal_type',
} };
searchcondition(data).then((res) => { searchcondition(data).then((res) => {
this.errorTypeList = res.data.data this.errorTypeList = res.data.data;
}) });
}, },
searchcondition() { searchcondition() {
const data = { const data = {
type: 'dictionaries', type: 'dictionaries',
table_name: 'zs_operator_plan', table_name: 'zs_operator_plan',
field_name: 'plan_type' field_name: 'plan_type',
} };
searchcondition(data).then((res) => { searchcondition(data).then((res) => {
this.taskTypeList = res.data.data this.taskTypeList = res.data.data;
}) });
}, },
searchTrackList() { searchTrackList() {
const data = { const data = {
type: 'dictionaries', type: 'dictionaries',
table_name: 'zs_operator_task', table_name: 'zs_operator_task',
field_name: 'trace_result' field_name: 'trace_result',
} };
searchcondition(data).then((res) => { searchcondition(data).then((res) => {
this.traceList = res.data.data this.traceList = res.data.data;
}) });
}, },
// 完成任务 // 完成任务
submitForm() { submitForm() {
...@@ -459,49 +458,62 @@ ...@@ -459,49 +458,62 @@
create_user: this.userInfo.username, create_user: this.userInfo.username,
remark: this.webForm.remark, remark: this.webForm.remark,
abnormal_types: this.webForm.abnormal_types, abnormal_types: this.webForm.abnormal_types,
create_department: this.userInfo.department_name create_department: this.userInfo.department_name,
} };
taskTrack(data).then((res) => { taskTrack(data).then((res) => {
if (res.status_code == 1) { if (res.status_code == 1) {
this.$message.success(res.msg) this.$message.success(res.msg);
this.webForm = { this.webForm = {
trace_result: '', trace_result: '',
remark: '', remark: '',
abnormal_types: [] abnormal_types: [],
};
this.is_finished = true;
this.showLayer = false;
} }
this.is_finished = true });
this.showLayer = false
}
})
}, },
onConfirm() { onConfirm() {
this.$refs.ruleForm.validate((valid) => { this.$refs.ruleForm.validate((valid) => {
if (valid) { if (valid) {
this.submitForm() this.submitForm();
} else { } else {
console.log('error submit!!') console.log('error submit!!');
} }
}) });
}, },
requestTaskDetails() { requestTaskDetails() {
const data = { const data = {
id: this.taskDetails.id id: this.taskDetails.id,
} };
taskDetails(data).then((res) => { taskDetails(data).then((res) => {
res.data && res.data.id ? this.assionInfo = { ...this.assionInfo, ...res.data } : '' res.data && res.data.id
this.memberBindExternalUser() ? (this.assionInfo = { ...this.assionInfo, ...res.data })
if (this.assionInfo && this.assionInfo.username && this.assionInfo.username.indexOf('\n') !== -1) { : '';
this.assionInfo.username = this.assionInfo.username.split('\n') this.memberBindExternalUser();
if (
this.assionInfo &&
this.assionInfo.username &&
this.assionInfo.username.indexOf('\n') !== -1
) {
this.assionInfo.username = this.assionInfo.username.split('\n');
} else { } else {
this.assionInfo.username = [this.assionInfo.username] this.assionInfo.username = [this.assionInfo.username];
} }
}) });
}, },
requestSession(item) { requestSession(item) {
clientSessionBindTaskApi({
userid: item.userid,
external_userid: item.external_userid,
task_id: this.assionInfo.id,
member_id: item.member_id,
username: item.username,
});
this.$ww.openEnterpriseChat({ this.$ww.openEnterpriseChat({
externalUserIds:item.external_userid, externalUserIds: item.external_userid,
success: (res) => { success: (res) => {
console.log(res, '打开会话窗口成功') console.log(res, '打开会话窗口成功');
}, },
fail: (err) => { fail: (err) => {
console.log(err, '打开会话窗口失败') console.log(err, '打开会话窗口失败')
...@@ -548,16 +560,46 @@ ...@@ -548,16 +560,46 @@
} catch (error) { } catch (error) {
this.loading = false this.loading = false
} }
},
/**
* 处理邮件发送成功的回调
* 设置任务的邮件发送状态为已发送
*/
handleEmailSendSuccess() {
// 标记任务已发送邮件
this.assionInfo.send_status = 1
// 可以选择刷新任务详情
// this.requestTaskDetails()
},
/**
* 显示礼包申请弹窗
* @param {Object} item - 任务信息对象,包含任务ID
*/
giftApply() {
this.task_id = this.assionInfo.id || null
this.showApplyGift = true
},
/**
* 处理礼包申请完成后的回调
* 关闭弹窗并显示成功提示
*/
handleGiftApplySuccess() {
this.showApplyGift = false
this.$message({
message: '礼包申请已提交',
type: 'success'
})
} }
} }
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.contet { .contet {
height: 100%; height: 100%;
background: #fff; background: #fff;
padding: 10px; padding: 10px;
overflow: auto; overflow: auto;
.title { .title {
font-size: 14px; font-size: 14px;
...@@ -566,7 +608,6 @@ ...@@ -566,7 +608,6 @@
color: #333333; color: #333333;
margin-bottom: 10px; margin-bottom: 10px;
} }
.taskInfo { .taskInfo {
height: auto; height: auto;
background: #f7f8fa; background: #f7f8fa;
...@@ -655,23 +696,23 @@ ...@@ -655,23 +696,23 @@
height: auto; height: auto;
margin-top: 22px; margin-top: 22px;
margin-bottom: 60px; margin-bottom: 60px;
.sessionUserList{ .sessionUser {
margin-right: 10px;
}
.sessionUser{
width: 100%; width: 100%;
height: auto; height: auto;
background: #F8F8F8; background: #f8f8f8;
border-radius: 4px; border-radius: 4px;
padding: 10px; padding: 10px;
} }
.sessionUserList {
margin-right: 10px;
}
.wxUserInfo { .wxUserInfo {
span{ span {
font-family: PingFangSC, PingFang SC; font-family: PingFangSC, PingFang SC;
font-weight: 400; font-weight: 400;
font-size: 14px; font-size: 14px;
color: #949FB0; color: #949fb0;
} }
} }
...@@ -964,14 +1005,13 @@ ...@@ -964,14 +1005,13 @@
width: 440px; width: 440px;
} }
} }
} }
.editLayer { .editLayer {
padding: 20px; padding: 20px;
padding-right: 0; padding-right: 0;
::v-deep .el-textarea__inner { ::v-deep .el-textarea__inner {
height: 150px; height: 150px;
} }
} }
</style> </style>
\ No newline at end of file
...@@ -76,9 +76,11 @@ ...@@ -76,9 +76,11 @@
</div> </div>
</div> </div>
<div class="btns rowFlex allCenter" style="margin-top: 20px"> <div class="btns rowFlex allCenter" style="margin-top: 20px">
<el-button :disabled="item.status == 3" :loading="remarkLoading" <el-button size="small" :disabled="item.status == 3" :loading="remarkLoading"
@click="saveRemak(item, index)">保存</el-button> @click="saveRemak(item, index)">保存</el-button>
<el-button type="primary" :disabled="item.status == 3" :loading="taskLoading" <!-- 单日申请礼包任务才展示礼包申请按钮 v-if="item.plan_type == 19 || item.plan_type == 21" 新增 累充礼包申请时 和 单日礼包申请一样 显示 礼包申请按钮 -->
<el-button type="primary" size="small" v-if="item.plan_type == 19 || item.plan_type == 21" :loading="taskLoading" @click="giftApply(item)">礼包申请</el-button>
<el-button type="primary" size="small" :disabled="item.status == 3" :loading="taskLoading"
@click="completeTask(item, index)">保存并完成任务</el-button> @click="completeTask(item, index)">保存并完成任务</el-button>
</div> </div>
</el-collapse-item> </el-collapse-item>
...@@ -92,6 +94,15 @@ ...@@ -92,6 +94,15 @@
</div> </div>
</div> </div>
</div> </div>
<!-- 礼包申请弹窗 -->
<applyGift
v-if="showApplyGift"
:show.sync="showApplyGift"
title="礼包申请"
width="25%"
:task_id="task_id"
@requestData="handleGiftApplySuccess"
/>
</div> </div>
</template> </template>
<script> <script>
...@@ -99,10 +110,12 @@ ...@@ -99,10 +110,12 @@
import { mapState } from 'vuex' import { mapState } from 'vuex'
import textEditor from '@/components/textEditor.vue' import textEditor from '@/components/textEditor.vue'
import noContent from '@/components/noContent.vue' import noContent from '@/components/noContent.vue'
import applyGift from '@/views/components/giftRecord/applyGift.vue'
export default { export default {
components: { components: {
textEditor, textEditor,
noContent, noContent,
applyGift
}, },
data() { data() {
return { return {
...@@ -131,6 +144,8 @@ ...@@ -131,6 +144,8 @@
showLayer: false, showLayer: false,
taskLoading: false, taskLoading: false,
remarkLoading: false, remarkLoading: false,
showApplyGift: false,
task_id: null,
pageInfo: { pageInfo: {
page: 0, page: 0,
page_size: 20, page_size: 20,
...@@ -190,6 +205,24 @@ ...@@ -190,6 +205,24 @@
this.searchconditionError() this.searchconditionError()
}, },
methods: { methods: {
/**
* 显示礼包申请弹窗
*/
giftApply(item) {
this.task_id = item.id || null
this.showApplyGift = true
},
/**
* 处理礼包申请完成后的回调
* 关闭弹窗并显示成功提示
*/
handleGiftApplySuccess() {
this.showApplyGift = false
this.$message({
message: '礼包申请已提交',
type: 'success'
})
},
searchcondition() { searchcondition() {
const data = { const data = {
type: 'dictionaries', type: 'dictionaries',
......
...@@ -27,21 +27,21 @@ ...@@ -27,21 +27,21 @@
</template> </template>
<script> <script>
import * as ww from '@wecom/jssdk'; import * as ww from "@wecom/jssdk";
import { import {
getOrganization, getOrganization,
getAuthUser, getAuthUser,
getSignature, getSignature,
getUserList, getUserList,
cserSelected, cserSelected,
} from '@/api/user'; } from "@/api/user";
import Cookies from 'js-cookie'; import Cookies from "js-cookie";
import { getParams } from '@/utils/index'; import { getParams } from "@/utils/index";
import { mapMutations, mapState } from 'vuex'; import { mapMutations, mapState } from "vuex";
import { getToken, setToken } from '@/utils/auth'; import { getToken, setToken } from "@/utils/auth";
import jsApiList from '@/utils/jsApiList'; import jsApiList from "@/utils/jsApiList";
export default { export default {
name: 'login', name: "login",
components: {}, components: {},
data() { data() {
return { return {
...@@ -57,10 +57,10 @@ export default { ...@@ -57,10 +57,10 @@ export default {
showRefresh: false, // 控制刷新按钮显示 showRefresh: false, // 控制刷新按钮显示
qrLoading: false, // 控制二维码 loading qrLoading: false, // 控制二维码 loading
redirectUri: redirectUri:
process.env.NODE_ENV === 'production' process.env.NODE_ENV === "production"
? 'https://companywx.zwnet.cn/api/api/sidebar_login/ding' ? "https://companywx.zwnet.cn/api/api/sidebar_login/ding"
: 'https://companywx.zwwlkj03.top/api/api/sidebar_login/ding', : "https://companywx.zwwlkj03.top/api/api/sidebar_login/ding",
DDTestUrl: '', DDTestUrl: "",
token: getToken(), token: getToken(),
userList: [], userList: [],
cser_user_id: null, cser_user_id: null,
...@@ -72,23 +72,24 @@ export default { ...@@ -72,23 +72,24 @@ export default {
}); });
}, },
computed: { computed: {
...mapState('user', ['corp_id']), ...mapState("user", ["corp_id"]),
}, },
methods: { methods: {
...mapMutations('user', [ ...mapMutations("user", [
'set_corp_id', "set_corp_id",
'set_userid', "set_userid",
'set_userInfo', "set_userInfo",
'set_token', "set_token",
'set_cser_info', "set_cser_info",
'set_signData', "set_signData",
'set_cser_id', "set_cser_id",
'set_cser_name', "set_cser_name",
'set_external_userid', "set_external_userid",
"set_weixin_blongs_id",
]), ]),
async initLogin() { async initLogin() {
const urlParams = getParams(); const urlParams = getParams();
const userid = Cookies.get('userid'); const userid = Cookies.get("userid");
if (this.token && userid) { if (this.token && userid) {
// 已经钉钉扫码过 重新获取授权 获取签名 注册企微js-sdk // 已经钉钉扫码过 重新获取授权 获取签名 注册企微js-sdk
this.getUserList(userid); this.getUserList(userid);
...@@ -101,20 +102,20 @@ export default { ...@@ -101,20 +102,20 @@ export default {
}, },
async getUserList(userid) { async getUserList(userid) {
this.urlParams = getParams(); this.urlParams = getParams();
const corp_id = Cookies.get('corp_id') || this.urlParams.corp_id; const corp_id = Cookies.get("corp_id") || this.urlParams.corp_id;
const res = await getUserList({ userid: userid, corp_id: corp_id }); const res = await getUserList({ userid: userid, corp_id: corp_id });
this.userList = res.data; this.userList = res.data;
}, },
async userStartLogin() { async userStartLogin() {
if (!this.cser_user_id) { if (!this.cser_user_id) {
this.$message.error('请选择客服人员'); this.$message.error("请选择客服人员");
return; return;
} }
const cser_user = this.userList.find( const cser_user = this.userList.find(
(item) => item.zq_user_id === this.cser_user_id (item) => item.zq_user_id === this.cser_user_id
); );
const corp_id = Cookies.get('corp_id'); const corp_id = Cookies.get("corp_id");
const userid = Cookies.get('userid'); const userid = Cookies.get("userid");
this.cacheCser(cser_user.zq_user_id, cser_user.name); this.cacheCser(cser_user.zq_user_id, cser_user.name);
try { try {
const res = await cserSelected({ const res = await cserSelected({
...@@ -122,10 +123,10 @@ export default { ...@@ -122,10 +123,10 @@ export default {
corp_id: corp_id, corp_id: corp_id,
userid: userid, userid: userid,
}); });
console.log(res, '选择客服人员登录'); console.log(res, "选择客服人员登录");
if (res.status_code === 1 && res.data.tokens) { if (res.status_code === 1 && res.data.tokens) {
this.$message({ this.$message({
type: 'warning', type: "warning",
message: `当前【${cser_user.name}】已上线,下班后请记得点击下线哦~`, message: `当前【${cser_user.name}】已上线,下班后请记得点击下线哦~`,
duration: 3 * 1000, duration: 3 * 1000,
}); });
...@@ -137,20 +138,20 @@ export default { ...@@ -137,20 +138,20 @@ export default {
setTimeout(() => { setTimeout(() => {
window.location.href = window.location.href =
window.location.origin + window.location.origin +
'/company_app/index.html?corp_id=' + "/company_app/index.html?corp_id=" +
corp_id + corp_id +
'&msg=cser_error'; "&msg=cser_error";
}, 5000); }, 5000);
} }
} catch (error) { } catch (error) {
console.log(error, '选择客服人员登录失败'); console.log(error, "选择客服人员登录失败");
this.$message.error(error.msg); this.$message.error(error.msg);
setTimeout(() => { setTimeout(() => {
window.location.href = window.location.href =
window.location.origin + window.location.origin +
'/company_app/index.html?corp_id=' + "/company_app/index.html?corp_id=" +
corp_id + corp_id +
'&msg=cser_error'; "&msg=cser_error";
}, 5000); }, 5000);
} }
}, },
...@@ -160,32 +161,32 @@ export default { ...@@ -160,32 +161,32 @@ export default {
); );
this.$confirm( this.$confirm(
`确认登录上线吗,上线后所有会话都会归属到客服【${cser_user.name}】`, `确认登录上线吗,上线后所有会话都会归属到客服【${cser_user.name}】`,
'提示', "提示",
{ {
confirmButtonText: '确定', confirmButtonText: "确定",
cancelButtonText: '取消', cancelButtonText: "取消",
type: 'warning', type: "warning",
} }
) )
.then(() => { .then(() => {
this.userStartLogin(); this.userStartLogin();
}) })
.catch(() => { .catch(() => {
this.$message.info('已取消登录'); this.$message.info("已取消登录");
}); });
}, },
// 设置缓存 // 设置缓存
cacheCorp_id(corp_id) { cacheCorp_id(corp_id) {
Cookies.set('corp_id', corp_id, { expires: 30 }); Cookies.set("corp_id", corp_id, { expires: 30 });
this.set_corp_id(corp_id); this.set_corp_id(corp_id);
}, },
cacheuserid(userid) { cacheuserid(userid) {
Cookies.set('userid', userid, { expires: 30 }); Cookies.set("userid", userid, { expires: 30 });
this.set_userid(userid); this.set_userid(userid);
}, },
cacheCser(cser_id, cser_name) { cacheCser(cser_id, cser_name) {
Cookies.set('cser_id', cser_id, { expires: 30 }); Cookies.set("cser_id", cser_id, { expires: 30 });
Cookies.set('cser_name', cser_name, { expires: 30 }); Cookies.set("cser_name", cser_name, { expires: 30 });
this.set_cser_info({ this.set_cser_info({
cser_id: cser_id, cser_id: cser_id,
cser_name: cser_name, cser_name: cser_name,
...@@ -194,16 +195,16 @@ export default { ...@@ -194,16 +195,16 @@ export default {
this.set_cser_name(cser_name); this.set_cser_name(cser_name);
}, },
cacheSignData(signData) { cacheSignData(signData) {
Cookies.set('signData', JSON.stringify(signData), { expires: 30 }); Cookies.set("signData", JSON.stringify(signData), { expires: 30 });
this.set_signData(signData); this.set_signData(signData);
}, },
// 进入的页面地址是 https://companywx.jianshuwenhua.com/company_app/index.html?corp_id=wweaefe716636df3d1 // 进入的页面地址是 https://companywx.jianshuwenhua.com/company_app/index.html?corp_id=wweaefe716636df3d1
// 1. 企微静默授权 // 1. 企微静默授权
async startWeComSilentAuth() { async startWeComSilentAuth() {
this.urlParams = getParams(); this.urlParams = getParams();
const corp_id = Cookies.get('corp_id') || this.urlParams.corp_id; const corp_id = Cookies.get("corp_id") || this.urlParams.corp_id;
if (!corp_id) { if (!corp_id) {
this.$message.error('当前客服号信息异常,请切换会话后重试'); this.$message.error("当前客服号信息异常,请切换会话后重试");
return; return;
} }
// 确定是第一次进入页面 没有 code 和 state // 确定是第一次进入页面 没有 code 和 state
...@@ -224,18 +225,19 @@ export default { ...@@ -224,18 +225,19 @@ export default {
if (res.data.userid) { if (res.data.userid) {
this.cacheuserid(res.data.userid); this.cacheuserid(res.data.userid);
this.getUserList(res.data.userid); this.getUserList(res.data.userid);
this.set_weixin_blongs_id(res.data.weixin_blongs_id);
} else { } else {
this.$message.error('获取用户id失败'); this.$message.error("获取用户id失败");
return; return;
} }
} else { } else {
console.log('获取useid失败', res); console.log("获取useid失败", res);
// 错误处理 // 错误处理
} }
}, },
async getSignature() { async getSignature() {
console.log('获取签名', window.location.href); console.log("获取签名", window.location.href);
const corp_id = Cookies.get('corp_id'); const corp_id = Cookies.get("corp_id");
try { try {
const res = await getSignature({ const res = await getSignature({
corp_id: corp_id, corp_id: corp_id,
...@@ -247,42 +249,42 @@ export default { ...@@ -247,42 +249,42 @@ export default {
try { try {
this.registerWeComSDK(); this.registerWeComSDK();
} catch (err) { } catch (err) {
console.log(err, '初始化sdk 失败'); console.log(err, "初始化sdk 失败");
} }
} }
} catch (err) { } catch (err) {
console.log(err, '获取签名失败'); console.log(err, "获取签名失败");
window.location.href = window.location.href =
window.location.origin + window.location.origin +
'/company_app/index.html?corp_id=' + "/company_app/index.html?corp_id=" +
corp_id + corp_id +
'&msg=signerror'; "&msg=signerror";
} }
}, },
getCurExternalContact() { getCurExternalContact() {
this.$ww.getCurExternalContact({ this.$ww.getCurExternalContact({
success: (res) => { success: (res) => {
if (res.err_msg === 'getCurExternalContact:ok') { if (res.err_msg === "getCurExternalContact:ok") {
console.log(res, '重新进入获取企微外部联系人'); console.log(res, "重新进入获取企微外部联系人");
this.set_external_userid(res.userId); this.set_external_userid(res.userId);
// 确保 Vuex 状态更新后再跳转 // 确保 Vuex 状态更新后再跳转
this.$nextTick(() => { this.$nextTick(() => {
this.$router.replace('/'); this.$router.replace("/");
console.log(window.location.href, 'window.location.hrefuserInfo'); console.log(window.location.href, "window.location.hrefuserInfo");
}); });
} }
}, },
fail: (err) => { fail: (err) => {
console.log(err, '获取企微外部联系人失败'); console.log(err, "获取企微外部联系人失败");
// 错误处理 // 错误处理
}, },
}); });
}, },
// 2. 注册企微JS-SDK // 2. 注册企微JS-SDK
registerWeComSDK() { registerWeComSDK() {
console.log('删除企业签名', 1231); console.log("删除企业签名", 1231);
this.$ww.register({ this.$ww.register({
corpId: Cookies.get('corp_id'), corpId: Cookies.get("corp_id"),
agentId: this.signData.agent_id, agentId: this.signData.agent_id,
jsApiList: jsApiList, jsApiList: jsApiList,
// getConfigSignature: () => Promise.resolve({ // getConfigSignature: () => Promise.resolve({
...@@ -298,12 +300,12 @@ export default { ...@@ -298,12 +300,12 @@ export default {
signature: this.signData.agent_signature, signature: this.signData.agent_signature,
}), }),
onAgentConfigSuccess: (res) => { onAgentConfigSuccess: (res) => {
console.log('注册成功可以调用企微 js-sdk', res); console.log("注册成功可以调用企微 js-sdk", res);
// 注册成功后不立即获取外部联系人,等钉钉扫码后再获取 // 注册成功后不立即获取外部联系人,等钉钉扫码后再获取
this.getCurExternalContact(); this.getCurExternalContact();
}, },
onAgentConfigFail: (err) => { onAgentConfigFail: (err) => {
console.log('注册失败不能使用企微js-sdk', err); console.log("注册失败不能使用企微js-sdk", err);
// 错误处理123 // 错误处理123
}, },
}); });
...@@ -322,15 +324,15 @@ export default { ...@@ -322,15 +324,15 @@ export default {
}, },
initCurrentApp() { initCurrentApp() {
const currentApp = this.orgList.find( const currentApp = this.orgList.find(
(item) => item.app_key === 'dingjigp0ksn9nbljdli' (item) => item.app_key === "dingjigp0ksn9nbljdli"
); );
this.$set(this, 'currentOrg', currentApp); this.$set(this, "currentOrg", currentApp);
}, },
// 7. 钉钉扫码回调页面处理 // 7. 钉钉扫码回调页面处理
async handleDingCallback(token) { async handleDingCallback(token) {
// 在这里处理钉钉扫码成功的回调 // 在这里处理钉钉扫码成功的回调
const corp_id = Cookies.get('corp_id'); const corp_id = Cookies.get("corp_id");
if (token && token != 'undefined') { if (token && token != "undefined") {
setToken(token); setToken(token);
this.set_token(token); this.set_token(token);
// 获取签名 // 获取签名
...@@ -338,9 +340,9 @@ export default { ...@@ -338,9 +340,9 @@ export default {
} else { } else {
window.location.href = window.location.href =
window.location.origin + window.location.origin +
'/company_app/index.html?corp_id=' + "/company_app/index.html?corp_id=" +
corp_id + corp_id +
'&msg=notoken'; "&msg=notoken";
} }
}, },
}, },
......
...@@ -2,87 +2,81 @@ ...@@ -2,87 +2,81 @@
<div class="details columnFlex"> <div class="details columnFlex">
<div class="content search-form"> <div class="content search-form">
<el-tabs v-model="activeName"> <el-tabs v-model="activeName">
<el-tab-pane <el-tab-pane label="个人话术" name="personal">
label="个人话术"
name="personal"
>
<skillPersonal <skillPersonal
v-if="activeName === 'personal'" v-if="activeName === 'personal'"
:active-name="activeName" :active-name="activeName"
/> />
</el-tab-pane> </el-tab-pane>
<el-tab-pane <el-tab-pane label="企业话术" name="company">
label="企业话术" <skillCompany :active-name="activeName" />
name="company"
>
<skillCompany
:active-name="activeName"
/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane <el-tab-pane label="知识库" name="library">
label="知识库"
name="library"
>
<skillLibrary <skillLibrary
v-if="activeName === 'library'" v-if="activeName === 'library'"
:active-name="activeName" :active-name="activeName"
/> />
</el-tab-pane> </el-tab-pane>
<el-tab-pane <el-tab-pane label="跨主体知识库" name="robotLibrary">
label="跨主体知识库"
name="robotLibrary"
>
<crossLibrary <crossLibrary
v-if="activeName === 'robotLibrary'" v-if="activeName === 'robotLibrary'"
:active-name="activeName" :active-name="activeName"
/> />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="教学视频" name="instructionalVideo">
<InstructionalVideo
v-if="activeName === 'instructionalVideo'"
:active-name="activeName"
/>
</el-tab-pane>
</el-tabs> </el-tabs>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import skillCompany from './components/skill/skillCompany.vue' import skillCompany from "./components/skill/skillCompany.vue";
import skillPersonal from './components/skill/skillPersonal.vue' import skillPersonal from "./components/skill/skillPersonal.vue";
import skillLibrary from './components/skill/skillLibrary.vue' import skillLibrary from "./components/skill/skillLibrary.vue";
import crossLibrary from './components/skill/crossLibrary.vue' import crossLibrary from "./components/skill/crossLibrary.vue";
import { mapActions } from 'vuex' import InstructionalVideo from "./components/InstructionalVideo/index.vue";
import { mapActions } from "vuex";
export default { export default {
name: 'quickReply', name: "quickReply",
components: { components: {
skillCompany, skillCompany,
skillPersonal, skillPersonal,
skillLibrary, skillLibrary,
crossLibrary crossLibrary,
InstructionalVideo,
}, },
data() { data() {
return { return {
activeName: 'personal' activeName: "personal",
} };
},
created() {
}, },
created() {},
mounted() { mounted() {
this.initializeWecom() this.initializeWecom();
}, },
methods: { methods: {
...mapActions('user', ['initWecom']), ...mapActions("user", ["initWecom"]),
async initializeWecom() { async initializeWecom() {
try { try {
console.log('🚀 开始初始化企业微信 SDK') console.log("🚀 开始初始化企业微信 SDK");
const result = await this.initWecom() const result = await this.initWecom();
console.log('✅ 企业微信 SDK 初始化成功', result) console.log("✅ 企业微信 SDK 初始化成功", result);
} catch (error) { } catch (error) {
console.error('❌ 企业微信 SDK 初始化失败:', error) console.error("❌ 企业微信 SDK 初始化失败:", error);
} }
}, },
} },
} };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.details { .details {
::v-deep .el-tabs__nav-next,::v-deep .el-tabs__nav-prev{ ::v-deep .el-tabs__nav-next,
::v-deep .el-tabs__nav-prev {
line-height: 50px; line-height: 50px;
} }
width: 100%; width: 100%;
......
...@@ -4,11 +4,13 @@ ...@@ -4,11 +4,13 @@
<div class="content" v-loading="viewLoading"> <div class="content" v-loading="viewLoading">
<div v-if="chatUserDetails.is_phishing_account == 1" class="warnText"> <div v-if="chatUserDetails.is_phishing_account == 1" class="warnText">
<p>高风险玩家,请立即通知组长!!!!</p> <p>高风险玩家,请立即通知组长!!!!</p>
<p>①千万不能推转游!!不要发送违禁词汇!!不要发送礼包和告知任何礼包信息!!</p> <p>
①千万不能推转游!!不要发送违禁词汇!!不要发送礼包和告知任何礼包信息!!
</p>
<p>②不能以任何形式推送APP/网页链接,也不可承认有APP/网页端口!!</p> <p>②不能以任何形式推送APP/网页链接,也不可承认有APP/网页端口!!</p>
</div> </div>
<div v-if="change_appraisal" class="warnText"> <div v-if="change_appraisal" class="warnText">
<p> 钓鱼号 禁止转端通知组长!</p> <p>钓鱼号 禁止转端通知组长!</p>
</div> </div>
<div v-else-if="gameUserInfo.exp_ip" class="warnText"> <div v-else-if="gameUserInfo.exp_ip" class="warnText">
<p>高风险用户,禁止转端 !!!</p> <p>高风险用户,禁止转端 !!!</p>
...@@ -20,66 +22,138 @@ ...@@ -20,66 +22,138 @@
<!-- 添加客服状态显示及按钮 --> <!-- 添加客服状态显示及按钮 -->
<div class="cser_status"> <div class="cser_status">
<div class="status-actions"> <div class="status-actions">
<el-button type="danger" v-if="clientStatus !== 'offline'" style="margin-left: 0px;" size="mini" <el-button
@click="logout">下线</el-button> type="danger"
v-if="clientStatus !== 'offline'"
style="margin-left: 0px"
size="mini"
@click="logout"
>下线</el-button
>
<!-- 休息中状态显示结束休息按钮 --> <!-- 休息中状态显示结束休息按钮 -->
<el-button v-if="clientStatus === 'rest'" type="primary" size="mini" <el-button
@click="handleFinishRest">结束休息</el-button> v-if="clientStatus === 'rest'"
type="primary"
size="mini"
@click="handleFinishRest"
>结束休息</el-button
>
<!-- 在线状态显示开始休息按钮 --> <!-- 在线状态显示开始休息按钮 -->
<el-tooltip v-if="clientStatus === 'online'" content="午休或者临时有事可点击休息" placement="top"> <el-tooltip
<el-button type="warning" size="mini" @click="handleStartRest">开始休息</el-button> v-if="clientStatus === 'online'"
content="午休或者临时有事可点击休息"
placement="top"
>
<el-button type="warning" size="mini" @click="handleStartRest"
>开始休息</el-button
>
</el-tooltip> </el-tooltip>
<!-- 发送评价按钮 --> <!-- 发送评价按钮 -->
<el-button type="primary" style="margin-left: 0px;" size="mini" <el-button
@click="handleSendComment">发送评价</el-button> type="primary"
style="margin-left: 0px"
size="mini"
@click="handleSendComment"
>发送评价</el-button
>
</div> </div>
</div> </div>
</div> </div>
<!-- 会话内容存档状态 --> <!-- 会话内容存档状态 -->
<div class="archive-status" v-if="agreeStatus !== 'Agree' || !hasPermit"> <div
class="archive-status"
v-if="agreeStatus !== 'Agree' || !hasPermit"
>
<p v-if="agreeStatus !== 'Agree'">当前微信用户未开启会话内容存档</p> <p v-if="agreeStatus !== 'Agree'">当前微信用户未开启会话内容存档</p>
<p v-if="!hasPermit">当前客服号未授权开启会话内容存档</p> <p v-if="!hasPermit">当前客服号未授权开启会话内容存档</p>
</div> </div>
<div class="item rowFlex"> <div class="item rowFlex">
<!-- 公共的信息 --> <!-- 公共的信息 -->
<el-image fit="fill" draggable="false" style="-webkit-user-drag: none" :src="chatUserDetails.avatar" <el-image
class="tableImage"></el-image> fit="fill"
draggable="false"
style="-webkit-user-drag: none"
:src="chatUserDetails.avatar"
class="tableImage"
></el-image>
<div class="columnFlex"> <div class="columnFlex">
<div class="rowFlex" style="margin-bottom: 3px"> <div class="rowFlex" style="margin-bottom: 3px">
<p class="text" style="font-weight: 600"> <p class="text" style="font-weight: 600">
{{ chatUserDetails.name }} {{ chatUserDetails.name }}
</p> </p>
<span v-if="chatUserDetails.add_way_text" style="color: #09b159; margin-left: 10px">@{{ <span
chatUserDetails.add_way_text }}</span> v-if="chatUserDetails.add_way_text"
style="color: #09b159; margin-left: 10px"
>@{{ chatUserDetails.add_way_text }}</span
>
</div> </div>
<!-- 游戏模块特有 --> <!-- 游戏模块特有 -->
<div v-if="accountSelect && accountSelect !== ''" class="rowFlex columnCenter" style="margin-top: 3px"> <div
v-if="accountSelect && accountSelect !== ''"
class="rowFlex columnCenter"
style="margin-top: 3px"
>
<vipLevel :gameUserInfo="gameUserInfo" /> <vipLevel :gameUserInfo="gameUserInfo" />
<el-button-group> <el-button-group>
<el-button type="text" @click="zyouUnBindConfirm">解绑</el-button> <el-button type="text" @click="zyouUnBindConfirm"
>解绑</el-button
>
<!-- <el-button type="text" size="mini" @click="autoResetPassword">修改密码</el-button> <!-- <el-button type="text" size="mini" @click="autoResetPassword">修改密码</el-button>
<el-button type="text" size="mini" @click="changePhoneClick">修改手机号</el-button> --> <el-button type="text" size="mini" @click="changePhoneClick">修改手机号</el-button> -->
<el-button v-if="!chatUserDetails.bind_cser" type="text" @click="relationKfh">关联客服</el-button> <el-button
<el-button type="text" v-if="false" @click="errorHandle">误操作</el-button> v-if="!chatUserDetails.bind_cser"
type="text"
@click="relationKfh"
>关联客服</el-button
>
<el-button type="text" v-if="false" @click="errorHandle"
>误操作</el-button
>
</el-button-group> </el-button-group>
</div> </div>
</div> </div>
</div> </div>
<div class="item rowFlex columnCenter"> <div class="item rowFlex columnCenter">
<div class="rowFlex columnCenter"> <div class="rowFlex columnCenter">
<span class="label" style="min-width: 45px;">备注:</span> <span class="label" style="min-width: 45px">备注:</span>
<p v-if="!showInputRemark" class="text" style="max-width: 170px;"> <p v-if="!showInputRemark" class="text" style="max-width: 170px">
{{ {{
chatUserDetails.remark && chatUserDetails.remark != "" chatUserDetails.remark && chatUserDetails.remark != ''
? chatUserDetails.remark ? chatUserDetails.remark
: chatUserDetails.name : chatUserDetails.name
}} }}
</p> </p>
</div> </div>
<el-input v-if="showInputRemark" v-model="showInputRemarkValue" class="showInputRemarkInput" type="textarea" <el-input
@change="handleInputRemark" @blur="showInputRemark = false"></el-input> v-if="showInputRemark"
<i class="el-icon-edit icon" style="font-size: 14px" @click="editRemark"></i> v-model="showInputRemarkValue"
class="showInputRemarkInput"
type="textarea"
@change="handleInputRemark"
@blur="showInputRemark = false"
></el-input>
<i
class="el-icon-edit icon"
style="font-size: 14px"
@click="editRemark"
></i>
</div>
<div class="item rowFlex columnCenter" v-if="lastTime">
<div class="rowFlex columnCenter">
<span class="label">最后交互日期:</span>
<span>
<span>({{ getDaysDifference }})</span>
{{ lastTime }}
</span>
<el-popover
placement="top-start"
width="200"
trigger="hover"
content="最后交互时间为VIP客服号与客户的最近一次会话发起时间"
>
<i class="el-icon-question ml-[4px]" slot="reference"></i>
</el-popover>
</div>
</div> </div>
<div> <div>
<!-- 自定义列 --> <!-- 自定义列 -->
...@@ -110,35 +184,66 @@ ...@@ -110,35 +184,66 @@
</div> </div>
</div> --> </div> -->
<!-- 游戏业务的账号信息 --> <!-- 游戏业务的账号信息 -->
<gameDetails v-if="gameUserInfo.username && !viewLoading" :chat-user-details="chatUserDetails" <gameDetails
:game-user-info="gameUserInfo" @changeAppraisal="changeAppraisal" /> v-if="gameUserInfo.username && !viewLoading"
:chat-user-details="chatUserDetails"
:game-user-info="gameUserInfo"
@changeAppraisal="changeAppraisal"
/>
<!-- 游戏标签 --> <!-- 游戏标签 -->
<div class="item rowFlex columnCenter spaceBetween tagsLost"> <div class="item rowFlex columnCenter spaceBetween tagsLost">
<div class="rowFlex"> <div class="rowFlex">
<span class="label">关联标签:</span> <span class="label">关联标签:</span>
<div v-if=" <div
v-if="
chatUserDetails.tag_group && chatUserDetails.tag_group &&
chatUserDetails.tag_group.length > 0 chatUserDetails.tag_group.length > 0
"> "
>
<!-- 第一个标签组的所有标签 --> <!-- 第一个标签组的所有标签 -->
<el-tag v-for="(items, indexs) in chatUserDetails.tag_group[0].tag" :key="indexs">{{ items.name <el-tag
}}</el-tag> v-for="(items, indexs) in chatUserDetails.tag_group[0].tag"
:key="indexs"
>{{ items.name }}</el-tag
>
<!-- 如果有多个标签组,显示+n --> <!-- 如果有多个标签组,显示+n -->
<el-popover v-if="chatUserDetails.tag_group.length > 1" placement="top" trigger="hover" <el-popover
popper-class="tag-popover"> v-if="chatUserDetails.tag_group.length > 1"
<div class="groups-popover-content" style="max-height: 600px;overflow-y: auto;"> placement="top"
<div v-for="(group, groupIndex) in chatUserDetails.tag_group.slice(1)" :key="groupIndex" trigger="hover"
class="group-item"> popper-class="tag-popover"
<el-tag v-for="(tagItem, tagIndex) in group.tag" :key="tagIndex" style="margin-right: 10px;">{{ >
tagItem.name }}</el-tag> <div
class="groups-popover-content"
style="max-height: 600px; overflow-y: auto"
>
<div
v-for="(
group, groupIndex
) in chatUserDetails.tag_group.slice(1)"
:key="groupIndex"
class="group-item"
>
<el-tag
v-for="(tagItem, tagIndex) in group.tag"
:key="tagIndex"
style="margin-right: 10px"
>{{ tagItem.name }}</el-tag
>
</div> </div>
</div> </div>
<span slot="reference" class="tag-more">+{{ chatUserDetails.tag_group.length - 1 }}</span> <span slot="reference" class="tag-more"
>+{{ chatUserDetails.tag_group.length - 1 }}</span
>
</el-popover> </el-popover>
</div> </div>
</div> </div>
<i class="el-icon-edit icon" style="font-size: 14px;margin-right: 10px;" @click="editTags"></i> <i
class="el-icon-edit icon"
style="font-size: 14px; margin-right: 10px"
@click="editTags"
></i>
</div> </div>
<!-- 共享信息 --> <!-- 共享信息 -->
<shareInfo :chat-user-details="chatUserDetails" /> <shareInfo :chat-user-details="chatUserDetails" />
...@@ -146,26 +251,50 @@ ...@@ -146,26 +251,50 @@
</div> </div>
</div> </div>
<!-- 修改手机号 --> <!-- 修改手机号 -->
<changePhone :show.sync="changePhone" :phone.sync="gameUserInfo.mobile" title="修改手机号" width="350px" /> <changePhone
:show.sync="changePhone"
:phone.sync="gameUserInfo.mobile"
title="修改手机号"
width="350px"
/>
<!-- 修改标签 --> <!-- 修改标签 -->
<selectTag v-if="showTag" :show.sync="showTag" :checkbox="true" :check-list="chatUserDetails.tag_group || []" <selectTag
@submit="selectTags" /> v-if="showTag"
:show.sync="showTag"
:checkbox="true"
:check-list="chatUserDetails.tag_group || []"
@submit="selectTags"
/>
</div> </div>
</template> </template>
<script> <script>
import { mapState, mapMutations, mapActions } from 'vuex' import { mapState, mapMutations, mapActions } from 'vuex';
import gameDetails from './gameInfo/gameUserInfo.vue' import gameDetails from './gameInfo/gameUserInfo.vue';
import shareInfo from './shareInfo.vue' import shareInfo from './shareInfo.vue';
import changePhone from './changePhone.vue' import changePhone from './changePhone.vue';
import watchMember from '@/mixins/watchMember' import watchMember from '@/mixins/watchMember';
import { autoResetPassword, bindUserSelfAdd } from '@/api/game' import { autoResetPassword, bindUserSelfAdd } from '@/api/game';
import { memberBindCser, editUser, zyouUnBind } from '@/api/works' import {
import selectTag from '@/components/selectTag.vue' memberBindCser,
import { getClientStatus, remarkSessionIntelTag, finishRest, client_session_rest, checkSingleAgree, checkUserPermit, sendComment, logout } from '@/api/user.js' editUser,
import { sendChatMessage } from '@/utils/index.js' zyouUnBind,
import { getToken, removeToken } from '@/utils/auth' getMemberInfoApi,
import vipLevel from './gameInfo/vipLevel.vue' } from '@/api/works';
import Cookies from 'js-cookie' import selectTag from '@/components/selectTag.vue';
import {
getClientStatus,
remarkSessionIntelTag,
finishRest,
client_session_rest,
checkSingleAgree,
checkUserPermit,
sendComment,
logout,
} from '@/api/user.js';
import { sendChatMessage } from '@/utils/index.js';
import { getToken, removeToken } from '@/utils/auth';
import vipLevel from './gameInfo/vipLevel.vue';
import Cookies from 'js-cookie';
export default { export default {
name: 'info', name: 'info',
components: { components: {
...@@ -173,13 +302,13 @@ export default { ...@@ -173,13 +302,13 @@ export default {
changePhone, changePhone,
shareInfo, shareInfo,
selectTag, selectTag,
vipLevel vipLevel,
}, },
props: { props: {
// 用户详情 // 用户详情
chatUserDetails: { chatUserDetails: {
type: Object, type: Object,
default: () => ({}) default: () => ({}),
}, },
}, },
data() { data() {
...@@ -197,121 +326,159 @@ export default { ...@@ -197,121 +326,159 @@ export default {
// 新增状态数据 // 新增状态数据
agreeStatus: '', // 用户是否同意聊天内容存档:Agreen同意 Disagree不同意 agreeStatus: '', // 用户是否同意聊天内容存档:Agreen同意 Disagree不同意
hasPermit: false, // 客服号是否开启会话内容存档权限 hasPermit: false, // 客服号是否开启会话内容存档权限
} lastTime: '', //上一次交互时间
};
}, },
computed: { computed: {
...mapState('game', [ ...mapState('game', [
'accountSelect', 'accountSelect',
'gameUserInfo', 'gameUserInfo',
'bindGameUserList', 'bindGameUserList',
'viewLoading' 'viewLoading',
]),
...mapState('user', [
'cser_info',
'cser_id',
'cser_name',
'corp_id',
'external_userid',
'userid',
'client_online_status',
'token',
]), ]),
...mapState('user', ['cser_info', 'cser_id', 'cser_name', 'corp_id', 'external_userid', 'userid', 'client_online_status', 'token']),
// 客服状态文本 // 客服状态文本
clientStatusText() { clientStatusText() {
const statusMap = { const statusMap = {
'online': '在线', online: '在线',
'offline': '离线', offline: '离线',
'rest': '休息中' rest: '休息中',
} };
return statusMap[this.client_online_status] || '未知' return statusMap[this.client_online_status] || '未知';
}, },
// 客服休息状态:online上线 offline下线 rest休息中 // 客服休息状态:online上线 offline下线 rest休息中
clientStatus() { clientStatus() {
return this.client_online_status return this.client_online_status;
},
getDaysDifference() {
// 解析目标日期字符串
const targetDate = new Date(this.lastTime);
// 获取当前日期(去除时间部分,只保留日期)
const currentDate = new Date();
currentDate.setHours(0, 0, 0, 0);
// 计算时间戳差值(毫秒)
const timeDiff = targetDate.getTime() - currentDate.getTime();
// 将毫秒转换为天数(24小时 × 60分钟 × 60秒 × 1000毫秒)
const daysDiff = Math.abs(Math.floor(timeDiff / (1000 * 60 * 60 * 24)));
return daysDiff;
}, },
}, },
mixins: [watchMember], mixins: [watchMember],
mounted() { mounted() {
// 初始化企业微信SDK // 初始化企业微信SDK
this.initializeWecom() this.initializeWecom();
// 获取客服状态和相关信息 // 获取客服状态和相关信息
if (this.cser_id && this.token) { if (this.cser_id && this.token) {
this.getInitialData() this.getInitialData();
} }
//获取最后交互时间
this.getLastTime();
}, },
methods: { methods: {
...mapMutations('game', ['set_accountSelect']), ...mapMutations('game', ['set_accountSelect', 'accountSelect']),
...mapActions('user', ['initWecom']), ...mapActions('user', ['initWecom']),
// 初始化企业微信SDK // 初始化企业微信SDK
async initializeWecom() { async initializeWecom() {
try { try {
console.log('🚀 开始初始化企业微信 SDK') console.log('🚀 开始初始化企业微信 SDK');
const result = await this.initWecom() const result = await this.initWecom();
console.log('✅ 企业微信 SDK 初始化成功', result) console.log('✅ 企业微信 SDK 初始化成功', result);
} catch (error) { } catch (error) {
console.error('❌ 企业微信 SDK 初始化失败:', error) console.error('❌ 企业微信 SDK 初始化失败:', error);
} }
}, },
logout() { logout() {
if (this.client_online_status === 'rest') { if (this.client_online_status === 'rest') {
this.$message({ this.$message({
type: 'error', type: 'error',
message: '当前客服号处于休息状态,不能下线' message: '当前客服号处于休息状态,不能下线',
}) });
return return;
} }
this.$confirm('确定下线吗?', '提示', { this.$confirm('确定下线吗?', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning',
}).then(() => {
this.userLogout()
}).catch(() => {
this.$message({
type: 'info',
message: '已取消'
}) })
.then(() => {
this.userLogout();
}) })
.catch(() => {
this.$message({
type: 'info',
message: '已取消',
});
});
}, },
async userLogout() { async userLogout() {
const data = { const data = {
userid: this.userid, userid: this.userid,
} };
const res = await logout(data) const res = await logout(data);
if (res.status_code === 1) { if (res.status_code === 1) {
this.$message({ this.$message({
type: 'success', type: 'success',
message: '下线成功' message: '下线成功',
}) });
removeToken() removeToken();
Cookies.remove('external_userid') Cookies.remove('external_userid');
Cookies.remove('userid') Cookies.remove('userid');
window.location.href = window.location.origin + '/company_app/index.html?corp_id=' + this.corp_id window.location.href =
window.location.origin +
'/company_app/index.html?corp_id=' +
this.corp_id;
} else { } else {
this.$message({ this.$message({
type: 'error', type: 'error',
message: '下线失败' message: '下线失败',
}) });
} }
}, },
// 获取初始数据 // 获取初始数据
async getInitialData() { async getInitialData() {
try { try {
// 1. 获取客服休息状态 // 1. 获取客服休息状态
const statusRes = await getClientStatus() const statusRes = await getClientStatus();
if (statusRes.status_code === 1) { if (statusRes.status_code === 1) {
if (statusRes.data.client_online_status === 'offline') { if (statusRes.data.client_online_status === 'offline') {
removeToken() removeToken();
window.location.href = window.location.origin + '/company_app/index.html?corp_id=' + this.corp_id window.location.href =
window.location.origin +
'/company_app/index.html?corp_id=' +
this.corp_id;
} }
this.$store.commit('user/set_client_online_status', statusRes.data.client_online_status) this.$store.commit(
'user/set_client_online_status',
statusRes.data.client_online_status
);
} }
// 2. 同步智能标签 // 2. 同步智能标签
this.syncIntelligentTags() this.syncIntelligentTags();
// 3. 检查用户是否同意聊天内容存档 // 3. 检查用户是否同意聊天内容存档
this.checkAgreeStatus() this.checkAgreeStatus();
// 4. 检查客服号是否开启会话内容存档 // 4. 检查客服号是否开启会话内容存档
this.checkPermitStatus() this.checkPermitStatus();
} catch (error) { } catch (error) {
console.error('获取初始数据失败:', error) console.error('获取初始数据失败:', error);
} }
}, },
...@@ -321,11 +488,11 @@ export default { ...@@ -321,11 +488,11 @@ export default {
await remarkSessionIntelTag({ await remarkSessionIntelTag({
corp_id: this.corp_id, corp_id: this.corp_id,
external_userid: this.external_userid, external_userid: this.external_userid,
userid: this.userid userid: this.userid,
}) });
console.log('智能标签同步成功') console.log('智能标签同步成功');
} catch (error) { } catch (error) {
console.error('智能标签同步失败:', error) console.error('智能标签同步失败:', error);
} }
}, },
...@@ -334,13 +501,13 @@ export default { ...@@ -334,13 +501,13 @@ export default {
try { try {
const res = await checkSingleAgree({ const res = await checkSingleAgree({
external_userid: this.external_userid, external_userid: this.external_userid,
userid: this.userid userid: this.userid,
}) });
if (res.status_code === 1) { if (res.status_code === 1) {
this.agreeStatus = res.data.agree_status this.agreeStatus = res.data.agree_status;
} }
} catch (error) { } catch (error) {
console.error('检查用户同意状态失败:', error) console.error('检查用户同意状态失败:', error);
} }
}, },
...@@ -348,45 +515,45 @@ export default { ...@@ -348,45 +515,45 @@ export default {
async checkPermitStatus() { async checkPermitStatus() {
try { try {
const res = await checkUserPermit({ const res = await checkUserPermit({
userid: this.userid userid: this.userid,
}) });
if (res.status_code === 1) { if (res.status_code === 1) {
this.hasPermit = res.data.has_permit this.hasPermit = res.data.has_permit;
} }
} catch (error) { } catch (error) {
console.error('检查客服权限失败:', error) console.error('检查客服权限失败:', error);
} }
}, },
// 开始休息 // 开始休息
async handleStartRest() { async handleStartRest() {
try { try {
const res = await client_session_rest() const res = await client_session_rest();
if (res.status_code === 1) { if (res.status_code === 1) {
this.$store.commit('user/set_client_online_status', 'rest') this.$store.commit('user/set_client_online_status', 'rest');
this.$message.success('已开始休息') this.$message.success('已开始休息');
} else { } else {
this.$message.error(res.msg || '开始休息失败') this.$message.error(res.msg || '开始休息失败');
} }
} catch (error) { } catch (error) {
console.error('开始休息失败:', error) console.error('开始休息失败:', error);
this.$message.error('开始休息失败') this.$message.error('开始休息失败');
} }
}, },
// 结束休息 // 结束休息
async handleFinishRest() { async handleFinishRest() {
try { try {
const res = await finishRest() const res = await finishRest();
if (res.status_code === 1) { if (res.status_code === 1) {
this.$store.commit('user/set_client_online_status', 'online') this.$store.commit('user/set_client_online_status', 'online');
this.$message.success('已结束休息') this.$message.success('已结束休息');
} else { } else {
this.$message.error(res.msg || '结束休息失败') this.$message.error(res.msg || '结束休息失败');
} }
} catch (error) { } catch (error) {
console.error('结束休息失败:', error) console.error('结束休息失败:', error);
this.$message.error('结束休息失败') this.$message.error('结束休息失败');
} }
}, },
...@@ -396,195 +563,213 @@ export default { ...@@ -396,195 +563,213 @@ export default {
const res = await sendComment({ const res = await sendComment({
corp_id: this.corp_id, corp_id: this.corp_id,
external_userid: this.external_userid, external_userid: this.external_userid,
userid: this.userid userid: this.userid,
}) });
if (res.status_code === 1 && res.data.news) { if (res.status_code === 1 && res.data.news) {
// 使用企业微信JSSDK发送评价 // 使用企业微信JSSDK发送评价
const result = await sendChatMessage(res.data.news, 'link') const result = await sendChatMessage(res.data.news, 'link');
if (result.success) { if (result.success) {
this.$message.success('评价已发送') this.$message.success('评价已发送');
} else { } else {
this.$message.error('评价发送失败') this.$message.error('评价发送失败');
} }
} else { } else {
this.$message.error(res.msg || '获取评价内容失败') this.$message.error(res.msg || '获取评价内容失败');
} }
} catch (error) { } catch (error) {
console.error('发送评价失败:', error) console.error('发送评价失败:', error);
this.$message.error('发送评价失败') this.$message.error('发送评价失败');
} }
}, },
memberChange() { memberChange() {
this.requestBindUser() this.requestBindUser();
//获取最后一次交互时间
this.getLastTime();
}, },
// 解绑确认 // 解绑确认
zyouUnBindConfirm() { zyouUnBindConfirm() {
this.$confirm('确定要解绑当前账号么?', '确认提示', { this.$confirm('确定要解绑当前账号么?', '确认提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning',
}) })
.then(() => { .then(() => {
this.zyouUnBind() this.zyouUnBind();
}) })
.catch(() => { .catch(() => {
this.$message({ this.$message({
type: 'info', type: 'info',
message: '已取消' message: '已取消',
}) });
}) });
}, },
requestBindUser() { requestBindUser() {
const data = { const data = {
member_id: this.accountSelect member_id: this.accountSelect,
} };
memberBindCser(data).then((res) => { memberBindCser(data).then((res) => {
console.log(res.data.cser_name, 'cser_namecser_namecser_namecser_name') console.log(res.data.cser_name, 'cser_namecser_namecser_namecser_name');
if (res.data.cser_name) { if (res.data.cser_name) {
this.$set(this.chatUserDetails, 'bind_cser', res.data.cser_name) this.$set(this.chatUserDetails, 'bind_cser', res.data.cser_name);
} else { } else {
this.$set(this.chatUserDetails, 'bind_cser', '') this.$set(this.chatUserDetails, 'bind_cser', '');
} }
}) });
}, },
zyouUnBind() { zyouUnBind() {
const data = { const data = {
userid: this.chatUserDetails.userid, userid: this.chatUserDetails.userid,
external_userid: this.chatUserDetails.external_userid, external_userid: this.chatUserDetails.external_userid,
member_id: this.accountSelect member_id: this.accountSelect,
} };
zyouUnBind(data).then((res) => { zyouUnBind(data).then((res) => {
if (res.status_code == 1) { if (res.status_code == 1) {
this.$message.success(res.msg) this.$message.success(res.msg);
const index = this.bindGameUserList.findIndex(item => item.member_id == this.accountSelect) const index = this.bindGameUserList.findIndex(
this.bindGameUserList.splice(index, 1) (item) => item.member_id == this.accountSelect
this.set_accountSelect(this.bindGameUserList[0].member_id) );
this.bindGameUserList.splice(index, 1);
this.set_accountSelect(this.bindGameUserList[0].member_id);
} }
}) });
}, },
// 修改密码 之前是客服手动设置密码 现在改成系统自动设置密码 // 修改密码 之前是客服手动设置密码 现在改成系统自动设置密码
autoResetPassword() { autoResetPassword() {
this.$confirm('确认重置密码吗?密码重置后玩家将无法登录,请谨慎操作!', '重置密码', { this.$confirm(
'确认重置密码吗?密码重置后玩家将无法登录,请谨慎操作!',
'重置密码',
{
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning',
}).then(res => { }
)
.then((res) => {
const data = { const data = {
member_id: this.accountSelect, member_id: this.accountSelect,
zq_user_name: this.cser_name zq_user_name: this.cser_name,
} };
autoResetPassword(data).then((res) => { autoResetPassword(data).then((res) => {
if (res.status_code == 1) { if (res.status_code == 1) {
this.$message.success('密码重置成功') this.$message.success('密码重置成功');
} }
});
}) })
}).catch(() => { .catch(() => {
this.$message({ this.$message({
type: 'info', type: 'info',
message: '已取消' message: '已取消',
}) });
}) });
}, },
// 修改手机号 // 修改手机号
changePhoneClick() { changePhoneClick() {
this.changePhone = true this.changePhone = true;
}, },
// 关联客服 // 关联客服
relationKfh() { relationKfh() {
const username = this.bindGameUserList.find( const username = this.bindGameUserList.find(
(item) => item.value == this.accountSelect (item) => item.value == this.accountSelect
) );
const params = { const params = {
member_id: this.accountSelect, member_id: this.accountSelect,
user_id: this.cser_id, user_id: this.cser_id,
user_name: this.cser_name, user_name: this.cser_name,
username: username.username username: username.username,
} };
bindUserSelfAdd(params).then((res) => { bindUserSelfAdd(params).then((res) => {
if (res.status_code == 1) { if (res.status_code == 1) {
this.$set(this.chatUserDetails, 'bind_cser', 1) this.$set(this.chatUserDetails, 'bind_cser', 1);
this.$message.success(res.msg) this.$message.success(res.msg);
} }
}) });
}, },
// 误操作处理 // 误操作处理
errorHandle() { errorHandle() {
this.$emit('error-handle') this.$emit('error-handle');
}, },
// 编辑备注 // 编辑备注
editRemark() { editRemark() {
this.showInputRemark = true this.showInputRemark = true;
this.showInputRemarkValue = this.chatUserDetails.remark || this.chatUserDetails.name this.showInputRemarkValue =
this.chatUserDetails.remark || this.chatUserDetails.name;
this.$nextTick(() => { this.$nextTick(() => {
// document.querySelector('.showInputRemarkInput input').focus() // document.querySelector('.showInputRemarkInput input').focus()
}) });
}, },
// 处理备注输入 // 处理备注输入
handleInputRemark(val) { handleInputRemark(val) {
this.showInputRemark = false this.showInputRemark = false;
this.chatUserDetails.remark = this.showInputRemarkValue this.chatUserDetails.remark = this.showInputRemarkValue;
const data = { const data = {
userid: this.chatUserDetails.userid, userid: this.chatUserDetails.userid,
external_userid: this.chatUserDetails.external_userid, external_userid: this.chatUserDetails.external_userid,
remark: this.chatUserDetails.remark, remark: this.chatUserDetails.remark,
self_defined_columns: this.chatUserDetails.self_defined_columns, self_defined_columns: this.chatUserDetails.self_defined_columns,
tag_group: this.chatUserDetails.tag_group tag_group: this.chatUserDetails.tag_group,
} };
this.editUserInfo(data) this.editUserInfo(data);
}, },
editUserInfo(data) { editUserInfo(data) {
editUser(data).then((res) => { editUser(data).then((res) => {
if (res.status_code == 1) { if (res.status_code == 1) {
this.$message({ this.$message({
type: 'success', type: 'success',
message: res.msg message: res.msg,
}) });
} }
}) });
}, },
// 显示自定义列输入 // 显示自定义列输入
inputShow(item, index) { inputShow(item, index) {
this.showInput = true this.showInput = true;
this.inputIndex = index this.inputIndex = index;
this.showInputValue = item.value this.showInputValue = item.value;
this.$nextTick(() => { this.$nextTick(() => {
document.querySelectorAll('input')[0].focus() document.querySelectorAll('input')[0].focus();
}) });
}, },
// 处理自定义列输入 // 处理自定义列输入
handleInput(item, index) { handleInput(item, index) {
this.$emit('update-custom-column', { this.$emit('update-custom-column', {
item, item,
index, index,
value: this.showInputValue value: this.showInputValue,
}) });
this.showInput = false this.showInput = false;
}, },
// 编辑标签 // 编辑标签
editTags() { editTags() {
this.showTag = true this.showTag = true;
}, },
// 处理评估变更 // 处理评估变更
changeAppraisal(val) { changeAppraisal(val) {
this.change_appraisal = val this.change_appraisal = val;
}, },
// 选择的标签 // 选择的标签
selectTags(data, is_tag_sync) { selectTags(data, is_tag_sync) {
this.chatUserDetails.tag_group = data this.chatUserDetails.tag_group = data;
const params = { const params = {
userid: this.chatUserDetails.userid, userid: this.chatUserDetails.userid,
external_userid: this.chatUserDetails.external_userid, external_userid: this.chatUserDetails.external_userid,
remark: this.chatUserDetails.remark, remark: this.chatUserDetails.remark,
is_tag_sync: is_tag_sync, is_tag_sync: is_tag_sync,
self_defined_columns: this.chatUserDetails.self_defined_columns, self_defined_columns: this.chatUserDetails.self_defined_columns,
tag_group: this.chatUserDetails.tag_group tag_group: this.chatUserDetails.tag_group,
} };
this.editUserInfo(params) this.editUserInfo(params);
}, },
} async getLastTime() {
} if (!this.accountSelect) return;
const { data } = await getMemberInfoApi({
member_id: this.accountSelect,
});
this.lastTime = data.last_chat_time;
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.info-tab-content { .info-tab-content {
...@@ -607,7 +792,7 @@ export default { ...@@ -607,7 +792,7 @@ export default {
font-size: 18px; font-size: 18px;
p { p {
color: #F56C6C; color: #f56c6c;
line-height: 25px; line-height: 25px;
} }
} }
...@@ -639,7 +824,7 @@ export default { ...@@ -639,7 +824,7 @@ export default {
p { p {
margin: 5px 0; margin: 5px 0;
color: #F56C6C; color: #f56c6c;
font-weight: 600; font-weight: 600;
} }
} }
...@@ -663,7 +848,7 @@ export default { ...@@ -663,7 +848,7 @@ export default {
margin-bottom: 10px; margin-bottom: 10px;
p { p {
color: #F56C6C; color: #f56c6c;
line-height: 25px; line-height: 25px;
} }
} }
...@@ -697,7 +882,7 @@ export default { ...@@ -697,7 +882,7 @@ export default {
} }
.noBind { .noBind {
color: #3491FA; color: #3491fa;
cursor: pointer; cursor: pointer;
margin-right: 10px; margin-right: 10px;
} }
...@@ -772,7 +957,7 @@ export default { ...@@ -772,7 +957,7 @@ export default {
.tag-more { .tag-more {
display: inline-block; display: inline-block;
color: #3491FA; color: #3491fa;
margin-left: 5px; margin-left: 5px;
cursor: pointer; cursor: pointer;
} }
......
<!--
* @Author: maoxiya 937667504@qq.com
* @Date: 2025-10-31 15:00:00
* @LastEditors: maoxiya 937667504@qq.com
* @LastEditTime: 2025-10-31 17:18:17
* @FilePath: /company_wx_frontend/src/components/common/game/benefitUsageRecord.vue
* @Description: 权益使用记录组件
-->
<template>
<div class="benefit-usage-record">
<!-- 搜索区域 -->
<div class="search-content">
<el-form label-position="top" :model="formData" class="search-form">
<el-form-item label="权益">
<el-select
v-model="formData.type"
clearable
placeholder="请选择权益"
@change="handleTypeChange"
style="width:100%;"
>
<el-option
v-for="item in benefitOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="时间范围">
<el-date-picker
v-model="formData.dateRange"
type="datetimerange"
format="yyyy-MM-dd HH:mm:ss"
value-format="yyyy-MM-dd HH:mm:ss"
range-separator="至"
start-placeholder="开始时间"
end-placeholder="结束时间"
clearable
:default-time="['00:00:00', '23:59:59']"
style="width:100%;"
/>
</el-form-item>
<el-form-item>
<el-button
type="primary"
:loading="loading"
@click="startSearch"
>
搜索
</el-button>
<el-button @click="resetForm">重置</el-button>
</el-form-item>
</el-form>
</div>
<!-- 表格区域 -->
<div class="table-container">
<el-table
v-loading="loading"
:data="tableData"
style="width: 100%"
:header-cell-style="{ background: '#f5f7fa', color: '#606266' }"
>
<el-table-column
label="角色名称/cp角色Id"
min-width="200"
>
<template slot-scope="scope">
<p>{{ scope.row.role_name }}</p>
<p class="infoText">{{ scope.row.cp_role_id }}</p>
</template>
</el-table-column>
<el-table-column
label="权益"
prop="type_name"
min-width="150"
/>
<el-table-column
label="使用人"
prop="create_user"
min-width="120"
/>
<el-table-column
label="使用时间"
prop="create_time"
min-width="180"
/>
</el-table>
<!-- 分页 -->
<div class="pagination-container">
<el-pagination
@current-change="handleCurrentChange"
@size-change="handleSizeChange"
:current-page="page_info.page"
:page-sizes="[10, 20, 50, 100]"
:page-size="page_info.page_size"
layout="total, sizes, prev, pager, next, jumper"
:total="page_info.total"
/>
</div>
</div>
</div>
</template>
<script>
import { useRightList,selectSearch } from '@/api/game'
export default {
name: 'BenefitUsageRecord',
props: {
benefitItem: {
type: Object,
default: () => ({})
},
roleInfo: {
type: Object,
default: () => ({})
}
},
data() {
return {
loading: false,
formData: {
type: '',
dateRange: []
},
benefitOptions: [],
tableData: [],
tableColums: [
{
label: '角色名称/cp角色Id',
prop: 'role_info',
minWidth: 200,
slotScope: true
},
{
label: '权益',
prop: 'type_name',
minWidth: 150
},
{
label: '使用人',
prop: 'create_user',
minWidth: 120,
},
{
label: '使用时间',
prop: 'create_time',
minWidth: 180
}
],
page_info: {
page: 1,
page_size: 20,
total: 0
}
}
},
mounted() {
this.getBenefitOptions()
this.getTableData()
},
methods: {
/**
* 获取权益下拉选项
*/
async getBenefitOptions() {
try {
const data = {
type: 'svip_right',
}
const res = await selectSearch(data)
if (res.status_code === 1 && res.data && res.data.data && res.data.data.length > 0) {
this.benefitOptions = res.data.data
}
} catch (error) {
console.error('获取权益选项失败:', error)
}
},
/**
* 获取表格数据
*/
async getTableData() {
try {
this.loading = true
const requestData = {
cp_role_id: this.roleInfo.cp_role_id,
type: this.formData.type,
create_time_start: this.formData.dateRange && this.formData.dateRange.length > 0 ? this.formData.dateRange[0] : '',
create_time_end: this.formData.dateRange && this.formData.dateRange.length > 0 ? this.formData.dateRange[1] : '',
page: this.page_info.page,
page_size: this.page_info.page_size
}
const res = await useRightList(requestData)
if (res.status_code === 1) {
this.tableData = res.data.data || []
this.page_info.total = Number(res.data.page_info.total) || 0
} else {
this.$message({
message: res.data.msg || '获取数据失败',
type: 'error'
})
}
} catch (error) {
console.error('获取权益使用记录失败:', error)
this.$message({
message: '获取数据失败,请重试',
type: 'error'
})
} finally {
this.loading = false
}
},
/**
* 处理页码变化
*/
handleCurrentChange(currentPage) {
this.page_info.page = currentPage
this.getTableData()
},
/**
* 处理每页条数变化
*/
handleSizeChange(pageSize) {
this.page_info.page_size = pageSize
this.page_info.page = 1
this.getTableData()
},
/**
* 处理权益类型变化
*/
handleTypeChange() {
this.page_info.page = 1
this.getTableData()
},
/**
* 开始搜索
*/
startSearch() {
this.page_info.page = 1
this.getTableData()
},
/**
* 重置表单
*/
resetForm() {
this.formData = {
type: '',
dateRange: []
}
this.startSearch()
}
}
}
</script>
<style lang="scss" scoped>
.benefit-usage-record {
::v-deep .el-table__header-wrapper{
position: static;
top: 0;
}
.search-content {
padding: 20px;
background: #fff;
border-radius: 4px;
max-height: 80%;
overflow: auto;
.search-form {
.el-form-item {
margin-bottom: 16px;
&:last-child {
margin-bottom: 0;
}
}
}
}
.table-container {
background: #fff;
border-radius: 4px;
padding: 20px;
}
.pagination-container {
margin-top: 20px;
text-align: right;
}
.infoText {
color: #c9cdd4;
font-size: 12px;
margin-top: 4px;
}
}
</style>
<!-- <!--
* @Author: maoxiya 937667504@qq.com * @Author: maoxiya 937667504@qq.com
* @Date: 2025-09-13 14:05:01 * @Date: 2025-09-13 14:05:01
* @LastEditors: maoxiya 937667504@qq.com * @LastEditors: 金多虾 937667504@qq.com
* @LastEditTime: 2025-09-22 17:24:19 * @LastEditTime: 2025-12-05 17:03:24
* @FilePath: /company_wx_frontend/src/views/works/component/gameInfo/vipLevel.vue * @FilePath: /company_wx_frontend/src/views/works/component/gameInfo/vipLevel.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
--> -->
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
:disabled="loading" :disabled="loading"
> >
<!-- 最大宽度 400px --> <!-- 最大宽度 400px -->
<div class="vipLevelContent" style="max-width: 400px;max-height: 300px;overflow: auto;"> <div class="vipLevelContent" style="min-width:250px;">
<div v-if="loading" class="loading-content"> <div v-if="loading" class="loading-content">
<i class="el-icon-loading"></i> <i class="el-icon-loading"></i>
<span>加载中...</span> <span>加载中...</span>
...@@ -25,7 +25,22 @@ ...@@ -25,7 +25,22 @@
<div class="vipLevelItem rowFlex columnCenter" v-for="(item,index) in vipLevelBenefit" :key="index"> <div class="vipLevelItem rowFlex columnCenter" v-for="(item,index) in vipLevelBenefit" :key="index">
<p class="vipLevelItemRow" v-if="item.num" :style="{color: item.target ? '#333333' : '#c9cdd4'}" > <p class="vipLevelItemRow" v-if="item.num" :style="{color: item.target ? '#333333' : '#c9cdd4'}" >
<span v-if="item.name" class="label">{{item.name}} </span> <span v-if="item.name" class="label">{{item.name}} </span>
<span v-if="item.num" :style="{color: item.target ? '#00bf8a' : '#c9cdd4'}" class="value"> {{item.num }}</span> <span v-if="item.num && item.type!=8" :style="{color: item.target ? '#00bf8a' : '#c9cdd4'}" class="value">
{{item.remain_num || item.num }}/{{item.num}} {{item.unit || '次'}}
</span>
<!-- 人工权益显示使用按钮 -->
<div v-if="item.monitor_type === 2" class="benefit-actions">
<el-button
type="primary"
size="mini"
style="margin-left: 10px;"
:disabled="!item.target"
@click.stop="handleUseBenefit(item)"
class="use-button"
>
使用
</el-button>
</div>
</p> </p>
</div> </div>
<div v-if="vipLevelBenefit.length === 0" class="no-data"> <div v-if="vipLevelBenefit.length === 0" class="no-data">
...@@ -37,11 +52,62 @@ ...@@ -37,11 +52,62 @@
<span class="vipLevelText" v-if="vip_role_info.vip_level" @click.stop="showVipLevel">{{ `SVIP等级${vip_role_info.vip_level}` }}</span> <span class="vipLevelText" v-if="vip_role_info.vip_level" @click.stop="showVipLevel">{{ `SVIP等级${vip_role_info.vip_level}` }}</span>
</div> </div>
</el-popover> </el-popover>
<!-- 使用权益确认弹窗 -->
<el-dialog
v-if="useBenefitDialogVisible"
title="确认提示"
:visible.sync="useBenefitDialogVisible"
width="400px"
:before-close="handleDialogClose"
>
<div class="dialog-content">
<div class="rowFlex columnCenter">
<i class="el-icon-warning" style="color: #E6A23C; font-size: 24px; margin-right: 10px;"></i>
<span>是否确认使用{{ currentBenefitItem?.name }}权益?</span>
</div>
<p class="text-center" style="color: #999; font-size: 14px; margin-top: 10px;">点击确定后,权益剩余使用数量将减 1</p>
</div>
<div slot="footer" >
<el-button
type="text"
@click="showUsageRecordFromDialog"
class="record-button"
>
使用记录
</el-button>
<el-button @click="handleDialogClose">取消</el-button>
<el-button
type="primary"
:loading="loading"
@click="confirmUseBenefit"
>
确认
</el-button>
</div>
</el-dialog>
<!-- 使用记录弹窗 -->
<el-dialog
title="权益使用记录"
:visible.sync="usageRecordVisible"
width="80%"
:before-close="closeUsageRecord"
append-to-body
@close="closeUsageRecord"
>
<BenefitUsageRecord
:benefit-item="currentBenefitItem"
:role-info="vip_role_info"
/>
</el-dialog>
</div> </div>
</template> </template>
<script> <script>
import { marketingRoleGradeBenefit,marketingMemberRoleGrade } from '@/api/game' import { marketingRoleGradeBenefit,marketingMemberRoleGrade,useBenefit } from '@/api/game'
import { mapState, mapMutations } from 'vuex' import { mapState, mapMutations } from 'vuex'
import BenefitUsageRecord from './benefitusageRecord.vue'
export default { export default {
name: 'VipLevel', name: 'VipLevel',
data() { data() {
...@@ -49,9 +115,15 @@ export default { ...@@ -49,9 +115,15 @@ export default {
vip_role_info: {}, vip_role_info: {},
vipLevelBenefit: [], vipLevelBenefit: [],
popoverVisible: false, popoverVisible: false,
loading: false loading: false,
usageRecordVisible: false,
currentBenefitItem: null,
useBenefitDialogVisible: false
} }
}, },
components: {
BenefitUsageRecord
},
props: { props: {
roleInfo: { roleInfo: {
type: Object, type: Object,
...@@ -73,7 +145,8 @@ export default { ...@@ -73,7 +145,8 @@ export default {
} }
}, },
computed: { computed: {
...mapState('game', ['accountSelect']) ...mapState('game', ['accountSelect']),
...mapState('user', ['userInfo']),
}, },
methods: { methods: {
async marketingMemberRoleGrade() { async marketingMemberRoleGrade() {
...@@ -134,7 +207,80 @@ export default { ...@@ -134,7 +207,80 @@ export default {
// 获取数据并显示popover // 获取数据并显示popover
await this.getVipLevel(); await this.getVipLevel();
},
/**
* 处理使用权益
*/
handleUseBenefit(item) {
this.currentBenefitItem = item;
this.useBenefitDialogVisible = true;
},
/**
* 确认使用权益
*/
async confirmUseBenefit() {
try {
this.loading = true;
const requestData = {
role_id: this.vip_role_info.role_id,
grade_config_id: this.currentBenefitItem.grade_config_id,
user_name:this.userInfo.username
};
const res = await useBenefit(requestData);
if (res.status_code === 1) {
this.$message({
message: res.data.msg || '使用成功',
type: 'success'
});
// 直接更新本地权益数据
const benefitIndex = this.vipLevelBenefit.findIndex(item =>
item.grade_config_id === this.currentBenefitItem.grade_config_id
);
if (benefitIndex !== -1) {
this.vipLevelBenefit[benefitIndex].remain_num -= 1;
}
this.useBenefitDialogVisible = false;
this.currentBenefitItem = null;
} else {
this.$message({
message: res.data.msg || '使用失败',
type: 'error'
});
}
} catch (error) {
console.error('使用权益失败:', error);
} finally {
this.loading = false;
}
},
/**
* 处理dialog关闭
*/
handleDialogClose() {
this.useBenefitDialogVisible = false;
this.currentBenefitItem = null;
},
/**
* 从dialog中显示使用记录弹窗
*/
showUsageRecordFromDialog() {
this.usageRecordVisible = true;
this.useBenefitDialogVisible = false;
},
/**
* 关闭使用记录弹窗
*/
closeUsageRecord() {
this.usageRecordVisible = false;
this.currentBenefitItem = null;
} }
} }
} }
</script> </script>
...@@ -185,8 +331,54 @@ export default { ...@@ -185,8 +331,54 @@ export default {
.value { .value {
font-weight: bold; font-weight: bold;
} }
.benefit-actions {
display: flex;
align-items: center;
gap: 8px;
margin-left: auto;
.use-button {
margin-left: 10px;
}
.record-button {
font-size: 12px;
padding: 0;
} }
} }
} }
}
}
.dialog-content {
font-size: 16px;
color: #333;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
align-items: center;
.record-button {
margin-left: 10px;
color: #409EFF;
cursor: pointer;
&:hover {
color: #66b1ff;
}
}
}
// 使用记录弹窗样式
.el-dialog {
::v-deep .el-dialog__body {
padding: 0;
max-height: 70vh;
overflow-y: auto;
}
}
} }
</style> </style>
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论