提交 8b8a07a6 作者: 施汉文

Merge branch '6.8' into shw-uiOptimize

......@@ -32,6 +32,8 @@
"vconsole": "^3.15.1",
"vue": "^2.6.14",
"vue-router": "^3.5.1",
"autoprefixer": "^10.4.0",
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.2.17",
"vuex": "^3.6.2"
},
"devDependencies": {
......@@ -44,6 +46,11 @@
"@vue/cli-plugin-vuex": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"element-theme-chalk": "^2.15.14",
"html-webpack-plugin": "3.2.0",
"script-ext-html-webpack-plugin": "2.1.3",
"serve-static": "1.13.2",
"svg-sprite-loader": "6.0.9",
"svgo": "1.2.2",
"vue-template-compiler": "^2.6.14"
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
* @Author: maoxiya 937667504@qq.com
* @Date: 2025-08-30 10:58:38
* @LastEditors: maoxiya 937667504@qq.com
* @LastEditTime: 2025-08-30 10:58:43
* @FilePath: /company_app/postcss.config.js
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
module.exports = {
plugins: [
require('tailwindcss'),
require('autoprefixer')
]
}
\ No newline at end of file
No preview for this file type
......@@ -12,7 +12,8 @@
<!-- Prevent caching at the proxy server -->
<meta http-equiv="expires" content="0">
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE9" />
<title><%= htmlWebpackPlugin.options.title %></title>
<!-- <title><%= htmlWebpackPlugin.options.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"> -->
<script src="https://g.alicdn.com/dingding/dinglogin/0.0.5/ddLogin.js"></script>
</head>
......
......@@ -4,16 +4,9 @@
<div class="mobile-menu-bar" v-if="token && external_userid && showMemberId">
<!-- 临时调试信息 -->
<div class="menu-container">
<el-menu
:default-active="selectedPath"
mode="horizontal"
class="mobile-el-menu"
:class="{ 'collapsed': !isMenuExpanded && shouldShowToggle }"
background-color="#fff"
router
@select="handleSelect"
ref="menuRef"
>
<el-menu :default-active="selectedPath" mode="horizontal" 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">
......@@ -27,20 +20,14 @@
<span v-else>{{ item.label }}</span>
</el-menu-item>
</el-menu>
<!-- 展开收起按钮 -->
<el-button
type="text"
size="mini"
v-if="shouldShowToggle"
class="menu-toggle-btn"
@click="toggleMenu"
>
<el-button type="text" 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>
</div>
<!-- 绑定的 w 账号 -->
<bindUserList />
</div>
......@@ -90,7 +77,7 @@ export default {
label: '礼包记录',
path: '/giftRecord'
},
// {
// label: '任务记录',
// path: '/taskRecord'
......@@ -112,6 +99,10 @@ export default {
path: '/taskList',
hasRedDot: false // 红点状态
},
{
label: '微言助手',
path: '/aiChat'
},
// {
// label: '通讯录',
// path: '/addressBook'
......@@ -192,7 +183,7 @@ export default {
this.selectedPath = currentPath
}
console.log('创建时路径:', currentPath, '选中路径:', this.selectedPath)
// 监听窗口大小变化
window.addEventListener('resize', this.handleResize)
// 初始检查
......@@ -210,7 +201,7 @@ export default {
...mapActions('game', ['getTaskUnReadData']),
// 设置缓存
cacheCorp_id(corp_id) {
Cookies.set('corp_id', corp_id, { expires: 7 })
Cookies.set('corp_id', corp_id, { expires: 30 })
this.set_corp_id(corp_id)
},
initVuexValue() {
......@@ -236,25 +227,25 @@ export default {
toggleMenu() {
this.isMenuExpanded = !this.isMenuExpanded
},
// 检查菜单是否需要换行
checkMenuOverflow() {
this.$nextTick(() => {
const menuElement = this.$refs.menuRef?.$el
if (!menuElement) return
// 临时展开菜单来检查实际高度
const wasCollapsed = !this.isMenuExpanded && this.shouldShowToggle
if (wasCollapsed) {
menuElement.classList.remove('collapsed')
}
const menuHeight = menuElement.scrollHeight
const singleLineHeight = 50 // 单行高度
// 如果菜单高度超过单行,说明需要换行
this.shouldShowToggle = menuHeight > singleLineHeight + 10 // 加10px容错
// 如果不需要展开收起按钮,则直接展开
if (!this.shouldShowToggle) {
this.isMenuExpanded = true
......@@ -264,7 +255,7 @@ export default {
}
})
},
// 窗口大小变化处理
handleResize() {
clearTimeout(this.resizeTimer)
......
import request from '@/utils/request'
// 清除上下文
export function corp_beta_question_session_clearTag(data) {
return request({
url: '/sidebar/corp_beta_question_session/clearTag',
method: 'post',
data
})
}
// 侧边栏-重试
export function retry(data) {
return request({
url: '/sidebar/corp_beta_question_log/retry',
method: 'post',
data
})
}
// 聊天记录
export function corp_beta_question_log_index(data) {
return request({
url: '/sidebar/corp_beta_question_log/index',
method: 'post',
data
})
}
// 发送欢迎语
export function welcomemsg(data) {
return request({
url: '/sidebar/corp_beta_question_session/welcome',
method: 'post',
data
})
}
// 配置-聊天
export function corp_beta_question_log_chat(data) {
return request({
url: '/sidebar/corp_beta_question_log/chat',
method: 'post',
data
})
}
// 配置-列表
export function corp_beta_question_config(data) {
return request({
url: '/sidebar/corp_beta_question_config/index',
method: 'post',
data
})
}
// 问答模块
export function getAiResponse(data) {
return request({
url: '/sidebar/corp_beta_question_log/chat',
method: 'post',
data
})
}
// 赞同模块
export function answerComment(data) {
return request({
url: '/sidebar/corp_beta_question_log/answerComment',
method: 'post',
data
})
}
......@@ -141,4 +141,3 @@ export function cserSelected(data) {
data
})
}
......@@ -259,3 +259,13 @@ export function shareInfoDel(data) {
data
})
}
// 跟进总结列表
export function corp_follow_up_summary_index(data) {
return request({
url: returnApi('/corp_follow_up_summary/index'),
method: 'post',
data
})
}
\ No newline at end of file
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="zhinengkefu(1)">
<rect id="&#231;&#159;&#169;&#229;&#189;&#162;" opacity="0.01" width="30" height="30" fill="#00BF8A"/>
<path id="&#229;&#189;&#162;&#231;&#138;&#182;" fill-rule="evenodd" clip-rule="evenodd" d="M27.0653 10.3441C25.5488 6.28958 21.6797 3.59819 17.3509 3.58671H12.6536C8.32641 3.60169 4.45971 6.29199 2.9414 10.3441C2.91233 10.3533 2.88393 10.3645 2.8564 10.3776L2.74232 5.69825C3.19914 5.51413 3.49954 5.07237 3.50283 4.57985V2.19318C3.50283 1.52362 2.96005 0.980835 2.29049 0.980835C1.62093 0.980835 1.07814 1.52362 1.07814 2.19318V4.5709C1.08106 5.06287 1.38048 5.50448 1.83642 5.6893L1.70892 11.0129C0.631358 11.8411 -0.000118498 13.1231 0 14.4822V18.1215C0.00549071 19.9831 1.18143 21.64 2.93692 22.2595C4.45561 26.3136 8.3244 29.005 12.6536 29.0192H17.3509C21.6795 29.0048 25.5474 26.3133 27.0653 22.2595C28.8195 21.6386 29.9942 19.9823 30 18.1215V14.4822C29.9962 12.6207 28.8208 10.9633 27.0653 10.3441ZM25.9715 17.8016C25.9629 20.261 23.9707 22.2522 21.5113 22.2595H8.49985C6.03525 22.2596 4.03487 20.2662 4.02625 17.8016V14.8065C4.03364 12.3411 6.03438 10.3463 8.49985 10.3463H21.5248C23.985 10.3537 25.9776 12.3463 25.9849 14.8065L25.9715 17.8016ZM15.8992 17.9761L18.5834 13.5673L20.4981 16.6586L24.0255 17.2334L19.9993 17.428L18.6572 15.7929L15.9283 20.6244L12.5462 14.2876L10.7053 17.3923L5.99016 17.22L9.97614 16.6161L12.5753 11.4714L15.8992 17.9761Z" fill="#00BF8A"/>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><defs><linearGradient id="a" y2="75.742%" x2="89.14%" y1="0%" x1="17.97%"><stop offset="0%" stop-color="#00EEAC"/><stop offset="53.553%" stop-color="#A9DD00"/><stop offset="100%" stop-color="#F7B500"/></linearGradient></defs><path fill="url(#a)" d="M10.673 5.201a2.604 2.604 0 0 1-2.6-2.6C8.072 1.167 9.238 0 10.672 0c1.434 0 2.6 1.167 2.6 2.6 0 1.434-1.166 2.601-2.6 2.601ZM5.137 7.266A2.378 2.378 0 0 1 2.76 4.89a2.378 2.378 0 0 1 2.376-2.376A2.378 2.378 0 0 1 7.512 4.89a2.378 2.378 0 0 1-2.375 2.376ZM2.784 12.64A2.097 2.097 0 0 1 .69 10.545 2.097 2.097 0 0 1 2.784 8.45a2.097 2.097 0 0 1 2.094 2.095 2.097 2.097 0 0 1-2.094 2.095Zm2.353 5.324a1.778 1.778 0 0 1-1.776-1.776 1.779 1.779 0 0 1 1.776-1.776c.98.001 1.774.796 1.776 1.776 0 .98-.797 1.776-1.776 1.776ZM10.673 20a1.553 1.553 0 0 1-1.552-1.552c0-.856.697-1.551 1.552-1.551.857 0 1.55.695 1.551 1.551 0 .856-.695 1.552-1.551 1.552Zm5.62-2.623a1.254 1.254 0 0 1-1.252-1.252c0-.692.56-1.252 1.252-1.253a1.254 1.254 0 0 1 0 2.505Zm2.302-5.795a1.029 1.029 0 0 1 0-2.055c.567 0 1.027.46 1.028 1.027a1.03 1.03 0 0 1-1.028 1.028Zm-3.1-6.615a.797.797 0 1 0 1.596 0 .797.797 0 0 0-1.595 0Z" fill-rule="nonzero"/></svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 60.1 (88133) - https://sketch.com -->
<title>编辑</title>
<desc>Created with Sketch.</desc>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="工作台" transform="translate(-1881.000000, -278.000000)" fill-rule="nonzero">
<g id="编辑" transform="translate(1880.000000, 277.000000)">
<rect id="矩形" fill="#000000" opacity="0" x="0" y="0" width="20" height="20"></rect>
<path d="M18.0820312,8.68359375 C17.8125,8.68359375 17.59375,8.90234375 17.59375,9.171875 L17.59375,15.5546875 C17.59375,16.9003906 16.4980469,17.9960938 15.1523438,17.9960938 L4.7734375,17.9960938 C3.42773438,17.9960938 2.33203125,16.9003906 2.33203125,15.5546875 L2.33203125,4.67773438 C2.33203125,3.33203125 3.42773438,2.23632812 4.7734375,2.23632812 L11.15625,2.23632812 C11.4257813,2.23632812 11.6445313,2.01757812 11.6445313,1.74804688 C11.6445313,1.47851562 11.4257813,1.25976562 11.15625,1.25976562 L4.7734375,1.25976562 C2.88867188,1.25976562 1.35546875,2.79296875 1.35546875,4.67773438 L1.35546875,15.5527344 C1.35546875,17.4375 2.88867188,18.9707031 4.7734375,18.9707031 L15.1523438,18.9707031 C17.0371094,18.9707031 18.5703125,17.4375 18.5703125,15.5527344 L18.5703125,9.171875 C18.5703125,8.90234375 18.3515625,8.68359375 18.0820312,8.68359375 Z M18.6816406,3.65429687 L16.3417969,1.3984375 C16.2480469,1.30859375 16.1230469,1.25976562 15.9941406,1.26166234 C15.8652344,1.26367187 15.7421875,1.31835937 15.6523438,1.41015625 L14.359375,2.75195312 C14.3515625,2.7578125 14.3457031,2.765625 14.3378906,2.7734375 L6.95898438,10.421875 C6.9296875,10.453125 6.90429688,10.4863281 6.88476563,10.5214844 C6.85742188,10.5605469 6.8359375,10.6035156 6.82226563,10.6484375 L5.66015625,14.2382812 C5.6015625,14.4179687 5.65234375,14.6152344 5.7890625,14.7441406 C5.88085938,14.8300781 6.00195313,14.8769531 6.12304688,14.8769531 C6.18359375,14.8769531 6.24414063,14.8652344 6.30078125,14.84375 L9.73828125,13.4980469 C9.83398438,13.4804687 9.92773438,13.4335937 10,13.3574219 L17.3085937,5.78125 C17.3164062,5.77539062 17.3222656,5.76757812 17.3300781,5.76171875 L18.6953125,4.34570312 C18.8828125,4.15039062 18.8769531,3.84179687 18.6816406,3.65429687 Z M14.6484375,3.85546875 L16.2851562,5.43554688 L9.63671875,12.3300781 L8,10.75 L14.6484375,3.85546875 Z M6.90625,13.5585938 L7.51367188,11.6816406 L8.74609375,12.8378906 L6.90625,13.5585938 Z M17.0175781,4.67773438 L15.3808594,3.09765625 L16.0175781,2.4375 L17.6542969,4.01757813 L17.0175781,4.67773438 Z" id="形状" fill="#666666"></path>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>发送备份</title>
<defs>
<linearGradient x1="14.2586009%" y1="0%" x2="93.6750771%" y2="75.7420422%" id="linearGradient-1">
<stop stop-color="#00EEAC" offset="0%"></stop>
<stop stop-color="#A9DD00" offset="53.5526729%"></stop>
<stop stop-color="#F7B500" offset="100%"></stop>
</linearGradient>
</defs>
<g id="游戏" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="游戏-快捷回复AI" transform="translate(-1727, -981)" fill-rule="nonzero">
<g id="编组-4备份-2" transform="translate(1378, 169.68)">
<g id="4.数据展示/10.Popover气泡卡片/⬅️右上备份-16" transform="translate(0, 798.32)">
<g id="发送备份" transform="translate(349, 13)">
<rect id="矩形" fill="#000000" opacity="0" x="0" y="0" width="20" height="20"></rect>
<polygon id="路径" fill="url(#linearGradient-1)" points="0 20 2.08 10.74 13.58 10.02 2.08 9.24 0 0 20 10"></polygon>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 60.1 (88133) - https://sketch.com -->
<title>复制</title>
<desc>Created with Sketch.</desc>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="快捷回复" transform="translate(-1093.000000, -386.000000)" fill-rule="nonzero">
<g id="编组-6" transform="translate(1086.000000, 379.000000)">
<g id="复制" transform="translate(6.000000, 6.000000)">
<rect id="矩形" fill="#000000" opacity="0" x="0" y="0" width="20" height="20"></rect>
<path d="M13,4.375 L4.00976562,4.375 C2.80273438,4.375 1.82226562,5.35546875 1.82226562,6.5625 L1.82226562,16.5625 C1.82226562,17.7695312 2.80273438,18.75 4.00976562,18.75 L13,18.75 C14.2070312,18.75 15.1875,17.7695312 15.1875,16.5625 L15.1875,6.5625 C15.1875,5.35546875 14.2070312,4.375 13,4.375 Z M13.9375,16.5625 C13.9375,17.0800781 13.5175781,17.5 13,17.5 L4.00976562,17.5 C3.4921875,17.5 3.07226562,17.0800781 3.07226562,16.5625 L3.07226562,6.5625 C3.07226562,6.04492188 3.4921875,5.625 4.00976562,5.625 L13,5.625 C13.5175781,5.625 13.9375,6.04492188 13.9375,6.5625 L13.9375,16.5625 Z M16.0292969,1.25 L5.88476562,1.25 C4.67773438,1.25 3.69726562,2.23046875 3.69726562,3.4375 L4.94726562,3.4375 C4.94726562,2.91992188 5.3671875,2.5 5.88476562,2.5 L16.0292969,2.5 C16.546875,2.5 16.9667969,2.91992188 16.9667969,3.4375 L16.9667969,14.6875 C16.9667969,15.2050781 16.546875,15.625 16.0292969,15.625 L16.0292969,16.875 C17.2363281,16.875 18.2167969,15.8945312 18.2167969,14.6875 L18.2167969,3.4375 C18.2167969,2.23046875 17.2363281,1.25 16.0292969,1.25 Z M4.75585938,7.8125 L12.2558594,7.8125 L12.2558594,9.0625 L4.75585938,9.0625 L4.75585938,7.8125 Z M4.75585938,10.9375 L12.2558594,10.9375 L12.2558594,12.1875 L4.75585938,12.1875 L4.75585938,10.9375 Z M4.75585937,14.0625 L9.57617188,14.0625 L9.57617188,15.3125 L4.75585937,15.3125 L4.75585937,14.0625 Z" id="形状" fill="#8CA4BA"></path>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>不点赞</title>
<g id="游戏" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="游戏-快捷回复AI" transform="translate(-1476, -617)" fill-rule="nonzero">
<g id="编组-4备份-2" transform="translate(1378, 169.68)">
<g id="不点赞" transform="translate(106, 455.32) scale(-1, 1) rotate(180) translate(-106, -455.32)translate(98, 447.32)">
<rect id="矩形" fill="#000000" opacity="0" x="0" y="0" width="16" height="16"></rect>
<path d="M13.395,5.3905 L9.257,5.3905 C9.4535,4.699 9.553,4.0845 9.553,3.5435 C9.553,2.316 8.431,1.1405 7.357,1.2965 C6.41,1.434 5.958,2.2325 5.958,3.258 L5.958,4.1845 C5.958,5.373 5.0485,6.3865 3.892,6.498 L2.0525,6.495 C1.4712203,6.495 1,6.9662203 1,7.5475 L1,13.625 C1,14.2065 1.471,14.6775 2.0525,14.6775 L12.243,14.6775 C13.0141535,14.6775 13.6763396,14.1291539 13.82,13.3715 L14.972,7.294 C15.0608892,6.82439182 14.9358631,6.3395998 14.6309458,5.97155283 C14.3260285,5.60350586 13.8729468,5.39049941 13.395,5.3905 Z M2,13.625 L2,7.5475 C2,7.5185 2.0235,7.495 2.0525,7.495 L3.25,7.495 L3.25,13.6775 L2.0525,13.6775 C2.02350505,13.6775 2,13.6539949 2,13.625 L2,13.625 Z M13.9895,7.108 L12.8375,13.1855 C12.7832202,13.4709991 12.5336132,13.6775 12.243,13.6775 L4.25,13.6775 L4.25,7.451 C5.8188449,7.15150285 6.95470437,5.78117313 6.958,4.184 L6.958,3.258 C6.958,2.671 7.1465,2.3375 7.5005,2.2865 C7.923,2.225 8.553,2.8855 8.553,3.544 C8.553,4.127 8.4045,4.8565 8.102,5.727 C8.04891415,5.87989332 8.07311785,6.0490253 8.16695458,6.1808932 C8.2607913,6.31276111 8.41265293,6.39105216 8.5745,6.391 L13.395,6.391 C13.5750607,6.3910127 13.7457587,6.47122841 13.8606881,6.60983965 C13.9756175,6.74845089 14.0228335,6.93105165 13.9895,7.108 Z" id="形状" fill="#8CA4BA"></path>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>不够好</title>
<g id="游戏" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="游戏-快捷回复AI" transform="translate(-1528, -617)" fill-rule="nonzero">
<g id="编组-4备份-2" transform="translate(1378, 169.68)">
<g id="不够好" transform="translate(158, 455.32) scale(-1, 1) rotate(180) translate(-158, -455.32)translate(150, 447.32)">
<rect id="矩形" fill="#000000" opacity="0" x="0" y="0" width="16" height="16"></rect>
<path d="M1,7.5475 L1,13.625 C1,14.2065 1.471,14.6775 2.0525,14.6775 L3,14.6775 L3,6.505 L2.0525,6.495 C1.4712203,6.495 1,6.9662203 1,7.5475 Z M13.395,5.3905 L9.2105,5.417 C9.407,4.7255 9.5065,4.111 9.5065,3.57 C9.5065,2.3425 8.431,1.1405 7.357,1.2965 C6.41,1.434 6.306,2.2525 6.306,3.278 L6.306,4.204 C6.306,5.3925 5.3085,6.405 4.152,6.5165 L4,6.515 L4,14.6775 L12.243,14.6775 C13.0141535,14.6775 13.6763396,14.1291539 13.82,13.3715 L14.972,7.294 C15.0608892,6.82439182 14.9358631,6.3395998 14.6309458,5.97155283 C14.3260285,5.60350586 13.8729468,5.39049941 13.395,5.3905 L13.395,5.3905 Z" id="形状" fill="#8CA4BA"></path>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>点赞</title>
<rect id="矩形" fill="#000000" opacity="0" x="0" y="0" width="16" height="16"></rect>
<path d="M13.395,5.3905 L9.257,5.3905 C9.4535,4.699 9.553,4.0845 9.553,3.5435 C9.553,2.316 8.431,1.1405 7.357,1.2965 C6.41,1.434 5.958,2.2325 5.958,3.258 L5.958,4.1845 C5.958,5.373 5.0485,6.3865 3.892,6.498 L2.0525,6.495 C1.4712203,6.495 1,6.9662203 1,7.5475 L1,13.625 C1,14.2065 1.471,14.6775 2.0525,14.6775 L12.243,14.6775 C13.0141535,14.6775 13.6763396,14.1291539 13.82,13.3715 L14.972,7.294 C15.0608892,6.82439182 14.9358631,6.3395998 14.6309458,5.97155283 C14.3260285,5.60350586 13.8729468,5.39049941 13.395,5.3905 Z M2,13.625 L2,7.5475 C2,7.5185 2.0235,7.495 2.0525,7.495 L3.25,7.495 L3.25,13.6775 L2.0525,13.6775 C2.02350505,13.6775 2,13.6539949 2,13.625 L2,13.625 Z M13.9895,7.108 L12.8375,13.1855 C12.7832202,13.4709991 12.5336132,13.6775 12.243,13.6775 L4.25,13.6775 L4.25,7.451 C5.8188449,7.15150285 6.95470437,5.78117313 6.958,4.184 L6.958,3.258 C6.958,2.671 7.1465,2.3375 7.5005,2.2865 C7.923,2.225 8.553,2.8855 8.553,3.544 C8.553,4.127 8.4045,4.8565 8.102,5.727 C8.04891415,5.87989332 8.07311785,6.0490253 8.16695458,6.1808932 C8.2607913,6.31276111 8.41265293,6.39105216 8.5745,6.391 L13.395,6.391 C13.5750607,6.3910127 13.7457587,6.47122841 13.8606881,6.60983965 C13.9756175,6.74845089 14.0228335,6.93105165 13.9895,7.108 Z" id="形状" fill="#8CA4BA"></path>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>已点赞</title>
<g id="游戏" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="游戏-快捷回复AI" transform="translate(-1502, -617)" fill-rule="nonzero">
<g id="编组-4备份-2" transform="translate(1378, 169.68)">
<g id="已点赞" transform="translate(124, 447.32)">
<rect id="矩形" fill="#000000" opacity="0" x="0" y="0" width="16" height="16"></rect>
<path d="M1,7.5475 L1,13.625 C1,14.2065 1.471,14.6775 2.0525,14.6775 L3,14.6775 L3,6.505 L2.0525,6.495 C1.4712203,6.495 1,6.9662203 1,7.5475 Z M13.395,5.3905 L9.2105,5.417 C9.407,4.7255 9.5065,4.111 9.5065,3.57 C9.5065,2.3425 8.431,1.1405 7.357,1.2965 C6.41,1.434 6.306,2.2525 6.306,3.278 L6.306,4.204 C6.306,5.3925 5.3085,6.405 4.152,6.5165 L4,6.515 L4,14.6775 L12.243,14.6775 C13.0141535,14.6775 13.6763396,14.1291539 13.82,13.3715 L14.972,7.294 C15.0608892,6.82439182 14.9358631,6.3395998 14.6309458,5.97155283 C14.3260285,5.60350586 13.8729468,5.39049941 13.395,5.3905 L13.395,5.3905 Z" id="形状" fill="#8CA4BA"></path>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 60.1 (88133) - https://sketch.com -->
<title></title>
<desc>Created with Sketch.</desc>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="账号管理" transform="translate(-1147.000000, -762.000000)" fill-rule="nonzero">
<g id="4.数据展示/10.Popover气泡卡片/上左⬇️" transform="translate(1136.000000, 649.000000)">
<g id="怒" transform="translate(11.000000, 113.000000)">
<rect id="矩形" fill="#000000" opacity="0" x="0" y="0" width="14" height="14"></rect>
<path d="M12.768,4.83 C12.8986667,5.166 12.9966667,5.51366667 13.062,5.873 C13.1273333,6.23233333 13.16,6.608 13.16,7 C13.16,7.84 12.999,8.63333333 12.677,9.38 C12.355,10.1266667 11.9163333,10.7753333 11.361,11.326 C10.8056667,11.8766667 10.157,12.313 9.415,12.635 C8.673,12.957 7.87733333,13.118 7.028,13.118 C6.188,13.118 5.39466667,12.957 4.648,12.635 C3.90133333,12.313 3.25266667,11.8766667 2.702,11.326 C2.15133333,10.7753333 1.715,10.1266667 1.393,9.38 C1.071,8.63333333 0.91,7.84 0.91,7 C0.91,6.61733333 0.942666667,6.24633333 1.008,5.887 C1.07333333,5.52766667 1.17133333,5.18 1.302,4.844 C1.302,4.77138003 1.80645408,3.67280698 2.058,3.416 C2.618,2.64133333 3.32966667,2.023 4.193,1.561 C5.05633333,1.099 6.00133333,0.868 7.028,0.868 C8.05466667,0.868 8.99733333,1.09666667 9.856,1.554 C10.7146667,2.01133333 11.424,2.62266667 11.984,3.388 C12.1504838,3.56624497 12.768,4.80553547 12.768,4.83 Z" id="形状" fill="#FFD840"></path>
<path d="M3.416,3.752 C3.53733333,4.15333333 3.668,4.51733333 3.808,4.844 C3.92933333,5.124 4.06466667,5.39466667 4.214,5.656 C4.36333333,5.91733333 4.51733333,6.09 4.676,6.174 C4.83466667,6.258 5.00266667,6.26266667 5.18,6.188 C5.35733333,6.11333333 5.52066667,6.01533333 5.67,5.894 C5.838,5.754 6.01066667,5.58133333 6.188,5.376 L3.416,3.752 Z" id="路径" fill="#873618"></path>
<path d="M9.9100167,10.630065 C9.97364586,10.6075526 10.0233561,10.5775361 10.0591476,10.5400154 C10.094939,10.5024948 10.1187999,10.4612221 10.1307304,10.4161973 C10.1426608,10.3711726 10.1486261,10.3298999 10.1486261,10.2923792 C10.1486261,10.2548586 10.1446492,10.2248421 10.1366956,10.2023297 C10.1207883,10.164809 10.1088578,10.1385446 10.1009042,10.1235363 C10.0929505,10.1085281 10.0889737,10.0935198 10.0889737,10.0785116 C9.89808623,9.66578455 9.53818376,9.33185086 9.00926632,9.07671052 C8.48034888,8.82157017 7.85002246,8.694 7.11828706,8.694 C6.75241936,8.694 6.40444736,8.73152064 6.07437106,8.80656192 C5.74429476,8.88160319 5.44802146,8.98478495 5.18555115,9.11610719 C4.92308085,9.24742942 4.69839035,9.40501611 4.51147968,9.58886724 C4.32456901,9.77271837 4.19532226,9.96970172 4.12373945,10.1798173 C4.12373945,10.1873214 4.11976263,10.1948256 4.11180898,10.2023297 C4.09590169,10.2473545 4.09987852,10.3242718 4.12373945,10.4330816 C4.14760039,10.5418915 4.2191832,10.6075526 4.33848789,10.630065 C4.52142174,10.4199494 4.74412382,10.2285941 5.00659413,10.0559992 C5.23724985,9.90591664 5.5235811,9.77084234 5.86558786,9.65077629 C6.20759463,9.53071025 6.61720738,9.47067723 7.09442612,9.47067723 C7.57164486,9.47067723 7.98722285,9.53071025 8.34116008,9.65077629 C8.69509732,9.77084234 8.9873938,9.90591664 9.21804952,10.0559992 C9.48847348,10.2285941 9.7191292,10.4199494 9.9100167,10.630065 L9.9100167,10.630065 Z" id="路径" fill="#873618"></path>
<path d="M9.338,6.174 C9.49666667,6.09 9.65066667,5.91733333 9.8,5.656 C9.94933333,5.39466667 10.0846667,5.124 10.206,4.844 C10.346,4.51733333 10.4766667,4.15333333 10.598,3.752 L7.826,5.376 C8.00333333,5.58133333 8.176,5.754 8.344,5.894 C8.49333333,6.01533333 8.65666667,6.11333333 8.834,6.188 C9.01133333,6.26266667 9.17933333,6.258 9.338,6.174 L9.338,6.174 Z" id="路径" fill="#873618"></path>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 11 10">
<defs>
<linearGradient id="a" y2="50%" x2="100%" y1="50%" x1="0%">
<stop offset="0%" stop-color="#6EE7E9" />
<stop offset="47.431%" stop-color="#9FF2CD" />
<stop offset="100%" stop-color="#E3FDB2" />
</linearGradient>
</defs>
<path fill="url(#a)"
d="M8.995 4.884a.141.141 0 0 1-.009.264c-.726.247-2.33.82-2.696 1.188-.447.447-.932 1.887-1.154 2.607a.14.14 0 0 1-.267.006c-.255-.714-.807-2.144-1.275-2.613-.348-.348-1.892-.936-2.58-1.188a.141.141 0 0 1-.01-.261c.668-.295 2.166-.985 2.59-1.408.402-.403 1.006-1.785 1.277-2.437a.141.141 0 0 1 .263.007c.234.655.755 2.029 1.156 2.43.423.422 1.996 1.11 2.705 1.405Z"
transform="translate(.157)" fill-rule="nonzero" />
</svg>
\ No newline at end of file
<svg t="1756195887325" class="icon" viewBox="0 0 1034 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7768" width="200" height="200"><path d="M1011.982 842.518 606.673 140.565c-49.575-85.822-130.595-85.822-180.157 0L21.205 842.518c-49.562 85.91-9.015 155.99 90.04 155.99l810.693 0C1020.997 998.507 1061.502 928.423 1011.982 842.518zM460.924 339.737c14.565-15.747 33.082-23.622 55.665-23.622 22.595 0 41.095 7.792 55.675 23.307 14.485 15.55 21.725 34.997 21.725 58.382 0 20.12-30.235 168.07-40.32 275.704l-72.825 0c-8.845-107.635-41.652-255.584-41.652-275.704C439.194 374.774 446.446 355.407 460.924 339.737zM571.244 851.538c-15.32 14.92-33.55 22.355-54.65 22.355-21.095 0-39.33-7.435-54.647-22.355-15.275-14.885-22.867-32.915-22.867-54.09 0-21.065 7.592-39.29 22.867-54.565 15.317-15.28 33.552-22.92 54.647-22.92 21.1 0 39.33 7.64 54.65 22.92 15.265 15.275 22.875 33.5 22.875 54.565C594.119 818.623 586.509 836.653 571.244 851.538z" p-id="7769"></path></svg>
\ No newline at end of file
import Vue from 'vue'
import SvgIcon from '@/components/svgIcon'// svg component
// register globally
Vue.component('svg-icon', SvgIcon)
// 只批量导入,交由 svg-sprite-loader 处理生成与注入 sprite
const req = require.context('./icon/svg', false, /\.svg$/)
req.keys().forEach(req)
<!--
# getRoleList 传入 member_id 获取角色列表
-->
<template>
<el-select v-model="selectedValue" placeholder="请选择" clearable size="small" :style="{ width: width || '100%' }"
v-bind="$attrs" :clearable="false" filterable remote :remote-method="remoteMethod" @clear="handleClear"
v-on="$listeners" @change="handleChange" @visible-change="handleVisibleChange">
<div class="select-dropdown" @scroll="handleScroll">
<el-option v-for="item in RuleList" :key="item.value" :label="item.label" :value="item.value"></el-option>
<div v-if="loading" v-loading="true" class="loading-more">
加载中...
</div>
</div>
</el-select>
</template>
<script lang="jsx">
import { getRoleHoLo } from '@/api/game'
import { debounce } from '@/utils'
export default {
name: 'getRoleList',
props: {
member_id: {
type: [String, Number],
default: ''
},
value: {
type: [String, Number],
default: ''
},
width: {
type: [String, Number],
default: ''
}
},
data() {
return {
RuleList: [],
loading: false,
currentPage: 1,
hasMore: true,
searchQuery: '',
selectedValue: this.value,
_debouncedRemote: null
}
},
watch: {
value(newVal) {
this.selectedValue = newVal
},
member_id(newVal) {
this.getRuleList()
}
},
created() {
this.getRuleList()
},
methods: {
async getRuleList(isLoadMore = false, query) {
// 仅在加载更多时受 hasMore 限制;新检索应始终允许
if (this.loading || (isLoadMore && !this.hasMore)) return
try {
this.loading = true
const keyword = typeof query === 'string' ? query : this.searchQuery
if (!isLoadMore) {
// 新检索时记录关键字
this.searchQuery = keyword || ''
}
const res = await getRoleHoLo({
page: isLoadMore ? this.currentPage + 1 : 1,
page_size: 20,
role_name: keyword,
search_type: 'list',
member_id: this.member_id
})
if (res.status_code === 1 && res.data && res.data.data) {
res.data.data.forEach(item => {
item.server_name ? item.label = `${item.role_name} - ${item.server_name}` : item.label = item.role_name
item.value = item.role_id
})
if (isLoadMore) {
this.RuleList = [...this.RuleList, ...res.data.data]
this.currentPage++
} else {
this.RuleList = res.data.data
this.currentPage = 1
}
this.hasMore = res.data.data.length >= 20
} else {
this.$message.warning(res.data.msg)
}
} catch (error) {
this.$message.error('获取数据失败')
} finally {
this.loading = false
}
},
handleScroll(e) {
const { scrollTop, scrollHeight, clientHeight } = e.target
if (scrollHeight - scrollTop - clientHeight < 50 && this.hasMore) {
this.getRuleList(true, this.searchQuery)
}
},
handleClear() {
this.selectedValue = ''
this.searchQuery = ''
this.$emit('clear')
},
handleChange() {
const roleInfo = this.RuleList.find(item => item.value === this.selectedValue)
this.$emit('selectChange', roleInfo)
},
handleVisibleChange(visible) {
// if (visible) {
// this.getRuleList()
// }
},
remoteMethod(query) {
if (!this._debouncedRemote) {
this._debouncedRemote = debounce((q) => {
this.getRuleList(false, q)
}, 300)
}
this._debouncedRemote(query)
}
}
}
</script>
<style lang="scss" scoped>
.select-dropdown {
max-height: 300px;
overflow-y: auto;
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-thumb {
background-color: #e4e7ed;
border-radius: 3px;
}
}
.loading-more {
text-align: center;
padding: 5px 0;
}
</style>
\ No newline at end of file
<template>
<div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
<svg v-else :class="svgClass" aria-hidden="true" :style="{ display: iconClass || svgName ? '' : 'none' }"
v-on="$listeners">
<use :xlink:href="iconName" />
</svg>
</template>
<script lang="jsx">
// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage
import { isExternal } from '@/utils/validate'
export default {
name: 'SvgIcon',
props: {
iconClass: {
type: String,
default: ''
},
svgName: {
type: String,
default: ''
},
className: {
type: String,
default: ''
}
},
computed: {
isExternal() {
return isExternal(this.iconClass)
},
iconName() {
if (this.svgName) {
return `#${this.svgName}`
}
return `#icon-${this.iconClass}`
},
svgClass() {
if (this.className) {
return 'svg-icon ' + this.className
} else {
return 'svg-icon'
}
},
styleExternalIcon() {
return {
mask: `url(${this.iconClass}) no-repeat 50% 50%`,
'-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
}
}
}
}
</script>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
/* vertical-align: -0.15em; */
fill: currentColor;
overflow: hidden;
}
.svg-external-icon {
background-color: currentColor;
mask-size: cover !important;
display: inline-block;
}
</style>
......@@ -7,10 +7,13 @@ import _ from 'lodash';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import 'lib-flexible/flexible.js'
// 引入 SVG 图标系统
import '@/assets/index.js'
Vue.use(ElementUI);
// import '@/styles/element-theme-colors.css';
import '@/styles/index.scss';
import moment from 'moment'
import '@/styles/tailwind.css'
import VConsole from 'vconsole';
import uploading from '@/utils/cos-upload'
import errorHandle from '@/utils/errorHandle'
......@@ -26,27 +29,26 @@ Vue.use(globalComponent).use(permission).use(clickagain).use(loadmore).use(scrol
import '@/utils/vconsoleCleanup'
// 开发环境下初始化 stagewise 工具栏
if (process.env.NODE_ENV === 'development') {
import('@stagewise/toolbar-vue').then(({ StagewiseToolbar }) => {
import('@stagewise-plugins/vue').then(({ VuePlugin }) => {
const stagewiseConfig = {
plugins: [VuePlugin]
};
// 动态创建并挂载 StagewiseToolbar 组件
const ToolbarConstructor = Vue.extend({
render(h) {
return h(StagewiseToolbar, { props: { config: stagewiseConfig } });
}
});
const toolbarInstance = new ToolbarConstructor();
toolbarInstance.$mount();
document.body.appendChild(toolbarInstance.$el);
});
}).catch(err => {
console.error('Failed to initialize stagewise toolbar:', err);
});
}
// if (process.env.NODE_ENV === 'development') {
// import('@stagewise/toolbar-vue').then(({ StagewiseToolbar }) => {
// import('@stagewise-plugins/vue').then(({ VuePlugin }) => {
// const stagewiseConfig = {
// plugins: [VuePlugin]
// };
// // 动态创建并挂载 StagewiseToolbar 组件
// const ToolbarConstructor = Vue.extend({
// render(h) {
// return h(StagewiseToolbar, { props: { config: stagewiseConfig } });
// }
// });
// const toolbarInstance = new ToolbarConstructor();
// toolbarInstance.$mount();
// document.body.appendChild(toolbarInstance.$el);
// });
// }).catch(err => {
// console.error('Failed to initialize stagewise toolbar:', err);
// });
// }
// 开发环境不收集日志
if (process.env.NODE_ENV !== 'development') {
errorHandle.onload()
......
......@@ -12,6 +12,7 @@ import taskRecord from '../views/taskRecord.vue'
import mailList from '@/views/mailList.vue'
import quickSendGame from '@/views/quickSendGame.vue'
import taskList from '@/views/taskList.vue'
import aiChat from '@/views/components/aiChat/aiChat.vue'
import Cookies from 'js-cookie'
import store from '@/store'
Vue.use(VueRouter)
......@@ -84,10 +85,16 @@ const routes = [
component: taskList
},
{
path: '/aiChat',
name: 'aiChat',
component: aiChat
},
{
path: '/login',
name: 'login',
component: () => import('../views/newLogin.vue')
},
]
const router = new VueRouter({
/* 这里用 hash 模式 因为本项目是在企微 服务器下的一个二级页面 如果用 history 模式 需要修改 nginx 配置 在 nginx 配置中 需要添加 location /company_app/ {
......
@tailwind base;
@tailwind components;
@tailwind utilities;
/*
* @Author: maoxiya 937667504@qq.com
* @Date: 2025-05-27 11:32:14
* @LastEditors: maoxiya 937667504@qq.com
* @LastEditTime: 2025-09-01 16:17:04
* @FilePath: /company_app/src/utils/auth.js
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import Cookies from 'js-cookie'
import store from '@/store/index'
const TokenKey = 'token'
......
......@@ -71,11 +71,16 @@ service.interceptors.response.use(
// cancelPending(response.config)
// 如果状态码不是成功,则判断为错误
if (res.status_code !== STATUS_CODE_SUCCESS) {
// 如果请求参数中 有 noMessage 则不显示错误信息
if (response.config.data && JSON.parse(response.config.data) && JSON.parse(response.config.data).noMessage) {
return res
}else{
Message({
message: res.msg || 'Error',
type: 'error',
duration: 2 * 1000
})
}
if (res.status_code === -100) {
// 登录 过期 重新去登录
setTimeout(() => {
......
/**
* @param {string} str
* @returns {Boolean}
*/
export function isExternal(str) {
return /^(https?:|mailto:|tel:)/.test(str)
}
/**
* @param {string} str
* @returns {Boolean}
*/
export function validUsername(str) {
const valid_map = ['admin', 'editor']
return valid_map.indexOf(str.trim()) >= 0
}
/**
* @param {string} url
* @returns {Boolean}
*/
export function validURL(url) {
const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
return reg.test(url)
}
/**
* @param {string} str
* @returns {Boolean}
*/
export function validLowerCase(str) {
const reg = /^[a-z]+$/
return reg.test(str)
}
/**
* @param {string} str
* @returns {Boolean}
*/
export function validUpperCase(str) {
const reg = /^[A-Z]+$/
return reg.test(str)
}
/**
* @param {string} str
* @returns {Boolean}
*/
export function validAlphabets(str) {
const reg = /^[A-Za-z]+$/
return reg.test(str)
}
/**
* @param {string} email
* @returns {Boolean}
*/
export function validEmail(email) {
const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
return reg.test(email)
}
/**
* @param {string} str
* @returns {Boolean}
*/
export function isString(str) {
if (typeof str === 'string' || str instanceof String) {
return true
}
return false
}
/**
* @param {Array} arg
* @returns {Boolean}
*/
export function isArray(arg) {
if (typeof Array.isArray === 'undefined') {
return Object.prototype.toString.call(arg) === '[object Array]'
}
return Array.isArray(arg)
}
<template>
<div class="violationRecord">
<el-form
v-loading="loading"
class="violationRecordContent"
label-width="90px"
>
<el-form v-loading="loading" class="violationRecordContent" label-width="90px">
<div v-if="violationList.length > 0">
<div
v-for="(item, index) in violationList"
:key="index"
class="contentItem"
>
<div v-for="(item, index) in violationList" :key="index" class="contentItem">
<el-form-item label="违规时间:">
<p>{{ item.violation_time }}</p>
</el-form-item>
......@@ -31,15 +23,9 @@
<el-form-item label="是否允许申诉:">
<p class="error">{{ item.appeal_name }}</p>
</el-form-item>
<el-form-item
v-if="item.remake != ''"
label="详情:"
>
<el-form-item v-if="item.remake != ''" label="详情:">
<!-- AI自动封禁 -->
<div
v-if="item.information_type === 6"
class="remarkType"
>
<div v-if="item.information_type === 6" class="remarkType">
<p>
<span class="label">所属项目:</span><span>{{ item.newRemake.project || "" }}</span>
</p>
......@@ -66,68 +52,31 @@
</p>
</div>
<!-- 其他类型 -->
<div
v-else
class="remarkType"
>
<div
v-if="item.remake.indexOf('src=') !== -1"
class="remakeImage"
>
<div v-else class="remarkType">
<div v-if="item.remake.indexOf('src=') !== -1" class="remakeImage">
<p class="watchDetails">
<el-button
type="text"
icon="el-icon-view"
size="medium"
<el-button type="text" icon="el-icon-view" size="medium"
style="z-index: 1; position: relative; margin-left: 5px"
@click="showRemake(item.remake)"
>查看大图</el-button>
@click="showRemake(item.remake)">查看大图</el-button>
</p>
<p class="remakeDetails" v-html="item.remake"></p>
</div>
<div
v-else
class="remakeImage"
>
<div v-else class="remakeImage">
<p class="remakeDetails" v-html="item.remake"></p>
</div>
</div>
</el-form-item>
<!-- 命中统计表格 -->
<div v-if="item && item.newRemake && item.newRemake.hit">
<div
class="title"
style="font-weight: 600; margin-bottom: 10px"
>
<div v-if="item && item.newRemake && item.newRemake.hit">
<div class="title" style="font-weight: 600; margin-bottom: 10px">
命中统计
</div>
<el-table
:data="item.newRemake.hit"
size="medium"
style="width: 100%"
class="hit-statistics-table"
>
<el-table-column
prop="content"
label="文本内容"
show-overflow-tooltip
/>
<el-table-column
prop="type"
label="命中类型"
width="120"
/>
<el-table-column
prop="key"
label="关键字"
width="120"
show-overflow-tooltip
/>
<el-table-column
label="时间"
width="180"
>
<el-table :data="item.newRemake.hit" size="medium" style="width: 100%" class="hit-statistics-table">
<el-table-column prop="content" label="文本内容" show-overflow-tooltip />
<el-table-column prop="type" label="命中类型" width="120" />
<el-table-column prop="key" label="关键字" width="120" show-overflow-tooltip />
<el-table-column label="时间" width="180">
<template slot-scope="{ row }">
<span>{{ $moment(row.time).format("YYYY-MM-DD HH:mm:ss") }}</span>
</template>
......@@ -136,29 +85,16 @@
</div>
</div>
</div>
<!-- 无数据状态 -->
<div
v-if="!loading && violationList.length == 0"
class="noContent rowFlex allCenter"
>
<div v-if="!loading && violationList.length == 0" class="noContent rowFlex allCenter">
<noContent title="暂无数据" description="当前没有任何数据,请稍后再试或联系管理员" />
</div>
</el-form>
<!-- 查看大图弹窗 -->
<el-dialog
title="查看大图"
:visible.sync="imageLayer"
width="320px"
center
append-to-body
@close="imageLayer = false"
>
<div
v-html="imageSrc"
class="layerImage"
></div>
<el-dialog title="查看大图" :visible.sync="imageLayer" width="320px" center append-to-body @close="imageLayer = false">
<div v-html="imageSrc" class="layerImage"></div>
</el-dialog>
</div>
</template>
......@@ -188,13 +124,13 @@ export default {
...mapState("game", ["accountSelect"]),
},
mounted() {
this.requestViolationList()
this.requestViolationList()
},
methods: {
memberChange() {
this.requestViolationList()
},
handleRemark(remark) {
try {
const remarkObj = JSON.parse(JSON.parse(remark.replace(/\r\n\t/g, "")));
......@@ -204,12 +140,12 @@ export default {
return remark;
}
},
showRemake(remake) {
this.imageSrc = remake;
this.imageLayer = true;
},
requestViolationList() {
const data = {
account_type: 1,
......@@ -262,8 +198,8 @@ export default {
height: 100%;
background: #fff;
overflow-y: auto;
overflow-x: hidden;
overflow-x: hidden;
.violationRecordContent {
width: 100%;
padding: 20px;
......@@ -274,10 +210,11 @@ export default {
border-bottom: 1px dashed #ebeef5;
margin-bottom: 20px;
padding-bottom: 20px;
::v-deep .el-form-item__label{
::v-deep .el-form-item__label {
line-height: 40px;
}
&:last-child {
border-bottom: none;
}
......@@ -304,11 +241,11 @@ export default {
.hit-statistics-table {
margin-top: 10px;
margin-bottom: 20px;
::v-deep .el-table__header-wrapper th {
background-color: #f7f8fa;
}
::v-deep .el-button--text {
color: #3491FA;
}
......@@ -317,22 +254,22 @@ export default {
::v-deep .el-form-item {
margin-bottom: 8px;
}
::v-deep .el-form-item__label {
color: #86909C;
font-weight: 500;
}
::v-deep .el-form-item__content {
color: #333;
}
.title {
color: #333;
font-size: 16px;
position: relative;
padding-left: 10px;
&:before {
content: '';
position: absolute;
......@@ -345,15 +282,15 @@ export default {
border-radius: 3px;
}
}
::v-deep .el-dialog__header {
padding: 15px 20px;
background-color: #f7f8fa;
}
::v-deep .el-button--text {
color: #3491FA;
&:hover {
color: #5ba8fb;
}
......@@ -362,6 +299,7 @@ export default {
.remakeDetails {
word-break: break-all;
::v-deep img {
max-width: 200px;
max-height: 200px;
......
<!--
* @Author: maoxiya 937667504@qq.com
* @Date: 2025-06-25 16:46:39
* @LastEditors: maoxiya 937667504@qq.com
* @LastEditTime: 2025-09-02 15:38:31
* @FilePath: /company_app/src/views/applyRecord.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
<div class="gift-tab-container-errorHanledle">
<el-tabs v-model="activeTab">
<el-tab-pane label="举报记录" name="report">
<report v-if="activeTab === 'report'" />
</el-tab-pane>
<el-tab-pane label="误操作" name="errorHandle">
<errorHandle v-if="activeTab=='errorHandle'"></errorHandle>
<errorHandle v-if="activeTab == 'errorHandle'"></errorHandle>
</el-tab-pane>
<el-tab-pane label="转区申请" name="serve">
<AreaTransferApply v-if="activeTab=='serve'" />
<AreaTransferApply v-if="activeTab == 'serve'" />
</el-tab-pane>
<el-tab-pane label="转端申请" name="terminal">
<TerminalTransfer v-if="activeTab=='terminal'" />
<el-tab-pane label="转端申请" name="terminal">
<TerminalTransfer v-if="activeTab == 'terminal'" />
</el-tab-pane>
</el-tabs>
</div>
......@@ -17,43 +28,51 @@
import AreaTransferApply from './components/ApplyRecords/AreaTransferApply.vue'
import errorHandle from './components/ApplyRecords/errorHandle.vue'
import TerminalTransfer from './components/ApplyRecords/TerminaTranfer.vue'
import report from './components/roleInfo/report.vue'
export default {
name: 'applyRecord',
components: {
AreaTransferApply,
errorHandle,
TerminalTransfer
TerminalTransfer,
report
},
data() {
return {
activeTab: 'errorHandle'
activeTab: 'report'
}
}
}
</script>
<style lang="scss" scoped>
.gift-tab-container-errorHanledle {
//padding: 20px;
width: 100%;
<style lang="scss" scoped>
.gift-tab-container-errorHanledle {
//padding: 20px;
width: 100%;
height: 100%;
padding-top: 10px;
background: #fff;
::v-deep .el-tabs {
height: calc(100% - 40px);
}
::v-deep .el-tabs__content {
height: 100%;
padding-top: 10px;
background: #fff;
::v-deep .el-tabs{
height: calc(100% - 40px);
}
::v-deep .el-tabs__content{
height: 100%;
}
::v-deep .el-tab-pane{
height: 100%;
}
::v-deep .el-tabs .el-tabs__header{
margin: 0;
// height: 60px;
}
::v-deep .el-tabs__nav-next, ::v-deep .el-tabs__nav-prev{
line-height: 50px;
}
}
</style>
\ No newline at end of file
::v-deep .el-tab-pane {
height: 100%;
}
::v-deep .el-tabs .el-tabs__header {
margin: 0;
// height: 60px;
}
::v-deep .el-tabs__nav-next,
::v-deep .el-tabs__nav-prev {
line-height: 50px;
}
}
</style>
\ No newline at end of file
......@@ -2,58 +2,26 @@
<div class="terminaListContent" v-scroll="paperScroll">
<div class="addApply rowFlex spaceBetween">
<span></span>
<el-button
type="primary"
icon="el-icon-plus"
size="small"
@click="(showaddAreaTransfer = true,areaTransferItem = {})"
>新增转端申请</el-button>
<el-button type="primary" icon="el-icon-plus" size="small"
@click="(showaddAreaTransfer = true, areaTransferItem = {})">新增转端申请</el-button>
</div>
<el-form
ref="taskForm"
:model="terminaForm"
label-position="top"
class="terminaListForm"
label-width="85px"
>
<el-form ref="taskForm" :model="terminaForm" label-position="top" class="terminaListForm" label-width="85px">
<el-form-item label="审批状态">
<el-select
v-model="terminaForm.approval_status"
style="width:95%;"
clearable
placeholder="请选择审批状态"
@change="filterChange"
>
<el-option
v-for="item in approvalList"
:key="item.value"
:label="item.label"
:value="item.value"
>
<el-select v-model="terminaForm.approval_status" style="width:95%;" clearable placeholder="请选择审批状态"
@change="filterChange">
<el-option v-for="item in approvalList" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="创建时间">
<selectDate
:default-value="dateValue"
:type="true"
style="width: 95%"
@result="createResult"
/>
<selectDate :default-value="dateValue" :type="true" style="width: 95%" @result="createResult" />
</el-form-item>
</el-form>
<div
class="terminaListContentList"
>
<div class="terminaListContentList">
<!-- 举报申请 -->
<div v-if="terminaList.length>0" class="scrollMain">
<div
v-for="(item, index) in terminaList"
:key="index"
class="terminaContent"
@click="terminaProcess(item, index)"
>
<div v-if="terminaList.length > 0" class="scrollMain">
<div v-for="(item, index) in terminaList" :key="index" class="terminaContent"
@click="terminaProcess(item, index)">
<div class="terminaItem rowFlex spaceBetween columnCenter">
<div class="terminaItemLeft">
<p><span class="label">角色名称:</span><span class="value">{{ item.role_name }}</span></p>
......@@ -64,7 +32,8 @@
<p>
<span class="label">登记时间:</span><span class="value">{{ item.create_time || '' }}</span>
</p>
<p><span class="label">转端状态:</span><span class="value">{{ item.trans_check_status_text || '-' }}</span></p>
<p><span class="label">转端状态:</span><span class="value">{{ item.trans_check_status_text || '-' }}</span>
</p>
</div>
<!-- 审批进度 -->
<el-collapse-transition>
......@@ -171,11 +140,11 @@ import { removeDp, formatNumber, debounce } from '@/utils/index'
import TerminalTransferDialog from './TerminalTransferDialog.vue'
import selectDate from '@/components/selectDate.vue'
// 导入审批状态图标
import shenpi1 from '@/assets/icon/shenpi1.svg'
import shenpi2 from '@/assets/icon/shenpi2.svg'
import shenpi4 from '@/assets/icon/shenpi4.svg'
import shenpi5 from '@/assets/icon/shenpi5.svg'
import shenpi6 from '@/assets/icon/shenpi6.svg'
import shenpi1 from '@/assets/icon/svg/shenpi1.svg'
import shenpi2 from '@/assets/icon/svg/shenpi2.svg'
import shenpi4 from '@/assets/icon/svg/shenpi4.svg'
import shenpi5 from '@/assets/icon/svg/shenpi5.svg'
import shenpi6 from '@/assets/icon/svg/shenpi6.svg'
import noContent from '@/components/noContent.vue'
export default {
name: 'terminaTranfer',
......@@ -392,12 +361,14 @@ export default {
.terminaListContent {
width: 100%;
height: 100%;
.TerminaTranferContent{
.TerminaTranferContent {
width: 100%;
height: 100%;
overflow: auto;
overflow-x: hidden;
}
.terminaListForm {
::v-deep .el-form-item__label {
font-weight: 400;
......@@ -462,6 +433,7 @@ export default {
.terminaListContentList {
width: 100%;
.scrollMain {
width: 100%;
height: auto;
......
<template>
<div class="quickSendGame columnFlex">
<div class="content search-form">
<el-tabs v-model="activeName">
<el-tab-pane label="AI微言" name="aiChat">
<aiArgenChat v-if="activeName === 'aiChat'" />
</el-tab-pane>
<el-tab-pane label="AI 跟进记录" name="aiFollow">
<summaryList v-if="activeName === 'aiFollow'" />
</el-tab-pane>
</el-tabs>
</div>
</div>
</template>
<script>
import aiArgenChat from './aiArgenChat.vue'
import summaryList from './summaryList.vue'
import { mapActions } from 'vuex'
export default {
name: 'quickSendGame',
components: {
aiArgenChat,
summaryList,
},
data() {
return {
activeName: 'aiChat'
}
},
created() {
},
mounted() {
// this.initializeWecom()
},
methods: {
...mapActions('user', ['initWecom']),
async initializeWecom() {
try {
console.log('🚀 开始初始化企业微信 SDK')
const result = await this.initWecom()
console.log('✅ 企业微信 SDK 初始化成功', result)
} catch (error) {
console.error('❌ 企业微信 SDK 初始化失败:', error)
}
},
}
}
</script>
<style lang="scss" scoped>
.quickSendGame {
::v-deep .el-tabs__nav-next,
::v-deep .el-tabs__nav-prev {
line-height: 50px;
}
width: 100%;
height: 100%;
background: #fff;
::v-deep .el-tabs__item {
padding: 0 15px;
}
.detailsTitle {
width: 100%;
padding: 0 10px;
height: 60px;
font-size: 18px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
border-bottom: 1px solid #ebeef5;
border-left: 1px solid #ebeef5;
p {
color: #333333;
}
}
.content {
width: 100%;
height: calc(100% - 10px);
::v-deep .el-tabs__header {
margin: 0 0 20px;
}
}
::v-deep .el-tabs--border-card .is-active {
border: none !important;
}
::v-deep .is-active {
border: none;
}
.inputContent {
width: 100%;
::v-deep .el-input {
width: 80%;
}
}
::v-deep .el-tabs,
.el-tabs__content,
.el-tab-pane {
width: 100%;
height: 100%;
}
::v-deep .el-tabs__content {
width: 100%;
height: calc(100% - 50px);
}
::v-deep .el-tab-pane {
width: 100%;
height: 100%;
}
.scrollList {
width: 100%;
height: calc(100% - 40px);
overflow: auto;
}
.draggable {
position: relative;
transition: all 0.3s;
.icon {
position: absolute;
left: 10px;
top: 15px;
z-index: 10;
}
}
::v-deep .el-icon-circle-close {
color: #fff;
}
.bate {
width: 42px;
height: 20px;
background: linear-gradient(135deg, #6ee7e9 0%, #9ff2cd 47%, #e3fdb2 100%);
border-radius: 10px;
padding: 0px 10px 3px 10px;
}
}
</style>
\ No newline at end of file
<template>
<div class="noSummaryContent">
<div class="noContent">
<div class="noContent-icon">
<svg-icon icon-class="warning" />
</div>
<div class="noContent-text">
<span>当前客服号知识库配置异常 请联系管理员处理</span>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'NoSummaryContent'
}
</script>
<style lang="scss" scoped>
.noSummaryContent {
width: 100%;
height: 100%;
.noContent {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
.noContent-icon {
color: #FF7D00;
font-size: 40px;
}
.noContent-text {
font-family: PingFang SC, PingFang SC;
font-weight: 400;
font-size: 14px;
color: #4E5969;
text-align: center;
font-style: normal;
text-transform: none;
}
}
}
</style>
\ No newline at end of file
<template>
<div class="summaryListContainer ">
<div v-scroll:50="requestDataList" v-loading="loading" class="messageDetailsScroll">
<div v-if="messageList.length > 0">
<div v-for="(item, index) in messageList" :key="index" class="messageListItem">
<div class="itemTop">
{{ item.date }}
</div>
<div class="itemCenter">
{{ item.summary }}
</div>
</div>
</div>
<div class="no-content-main" v-if="!loading && messageList.length == 0">
<noContent />
</div>
</div>
</div>
</template>
<script>
import { mapMutations, mapState } from 'vuex'
import { corp_follow_up_summary_index } from '@/api/works'
import { throttle } from '@/utils'
import noContent from '@/components/noContent.vue'
export default {
components: {
noContent
},
props: {
chatUserDetails: {
typeof: Object,
default: () => { }
}
},
data() {
return {
loading: false,
isloadMore: true,
messageList: [],
pageInfo: {
page: 0,
page_size: 20,
total: 0
}
}
},
computed: {
...mapState('game', ['accountSelect']),
...mapState('user', ['external_userid']),
},
mounted() {
this.pageInfo = {
page: 0,
page_size: 20,
total: 0
}
this.isloadMore = true
this.messageList = []
this.loading = true
this.requestDataList()
},
methods: {
requestDataList: throttle(function () {
if (this.accountSelect) {
if (!this.isloadMore) {
console.log('没有更多数据了')
return false
}
this.loading = true
this.pageInfo.page += 1
const data = {
external_userid: this.external_userid,
...this.pageInfo
}
corp_follow_up_summary_index(data).then(
(res) => {
this.loading = false
if (res.data.data && res.data.data.length < 20) {
this.isloadMore = false
}
this.messageList = this.messageList.concat(res.data.data)
if (res.data.page_info) {
this.pageInfo = res.data.page_info
}
},
(err) => {
this.loading = false
}
)
} else {
this.isloadMore = false
this.loading = false
}
}, 500)
}
}
</script>
<style lang="scss" scoped>
.summaryListContainer {
width: 100%;
height: 100%;
background: #fff;
position: relative;
overflow: hidden;
.messageDetailsScroll {
width: 100%;
height: 100%;
overflow: auto;
overflow-x: hidden;
padding-bottom: 50px;
}
.messageListItem {
width: 100%;
height: auto;
margin-bottom: 10px;
.itemTop {
font-family: PingFang SC, PingFang SC;
font-weight: 400;
font-size: 14px;
color: #86909C;
line-height: 20px;
text-align: left;
font-style: normal;
text-transform: none;
margin-bottom: 5px;
}
.itemCenter {
width: 100%;
background: #F9FAFF;
border-radius: 4px 4px 4px 4px;
padding: 10px;
font-family: PingFang SC, PingFang SC;
font-weight: 400;
font-size: 16px;
color: #4E5969;
text-align: left;
font-style: normal;
text-transform: none;
// 换行
white-space: pre-wrap;
word-break: break-all
}
}
.no-content-main {
width: 320px;
margin: 0 auto;
}
}
</style>
\ No newline at end of file
<!--
* @Author: maoxiya 937667504@qq.com
* @Date: 2025-08-28 15:59:46
* @LastEditors: maoxiya 937667504@qq.com
* @LastEditTime: 2025-09-02 09:51:24
* @FilePath: /company_wx_frontend/src/views/works/component/chat/giftCodeDialog.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
<el-dialog title="请确认发放的角色" :visible="dialogVisible" class="giftCodeDialogForm" width="360px" @close="closeDialog">
<p class="font12 mb-[10px] mt-[-10px]">即将发送召回礼包<span v-if="gameName" style="color: #00BF8A;"> ({{ gameName
}})</span>,发送后可在礼包记录中查看</p>
<el-form :model="form" ref="giftCodeDialogForm" label-width="80px" :rules="rules">
<el-form-item label="账号ID:" prop="member_id">
<el-select style="width: 320px;" :clearable="false" @change="handleMemberIdChange"
v-model="form.member_id" placeholder="请选择账号ID">
<el-option v-for="item in bindGameUserList" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="角色ID:" prop="role_id">
<getRoleList v-model="form.role_id" width="320px" placeholder="请选择角色" :member_id="form.member_id"
@selectChange="handleSelectionChange" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button size="mini" @click="closeDialog">取消</el-button>
<el-button type="primary" size="mini" @click="getGiftCodeSubmit('send')">确定</el-button>
<el-button type="text" size="mini" @click="getGiftCodeSubmit('copy')">仅复制</el-button>
</div>
</el-dialog>
</template>
<script>
import getRoleList from '@/components/getRoleList.vue'
import { getRoleHoLo } from '@/api/game'
import { mapState } from 'vuex'
export default {
props: {
dialogVisible: {
type: Boolean,
default: false
},
gameName: {
type: String,
default: ''
}
},
components: {
getRoleList
},
data() {
return {
form: {
member_id: '',
username: '',
role_id: '',
role_name: '',
},
rules: {
member_id: [{ required: true, message: '请选择账号ID', trigger: 'change' }],
role_id: [{ required: true, message: '请选择角色ID', trigger: 'change' }]
},
getRoleHoLo: getRoleHoLo,
gift_code: [],
roleList: [],
pageInfo: {
page: 1,
page_size: 10
},
loading: false
}
},
mounted() {
this.form.member_id = this.accountSelect
this.form.username = this.bindGameUserList.find(item => item.member_id === this.accountSelect).username
},
computed: {
...mapState('game', ['accountSelect', 'bindGameUserList'])
},
methods: {
handleMemberIdChange(value) {
this.form.role_id = ''
this.form.role_name = ''
const userInfo = this.bindGameUserList.find(item => item.value === value)
this.form.username = userInfo.label || userInfo.username
this.form.member_id = value
},
handleSelectionChange(roleInfo) {
console.log(roleInfo, 'roleInfo')
this.form.role_name = roleInfo.label || ''
},
closeDialog() {
this.$emit('update:dialogVisible', false)
},
getGiftCodeSubmit(type) {
this.$refs.giftCodeDialogForm.validate((valid) => {
if (valid) {
this.$emit('update:dialogVisible', false)
this.$emit('result', this.form, type)
}
})
}
}
}
</script>
<style lang="scss" scoped>
.giftCodeDialogForm {
.dialog-footer {
border: none;
padding: 0;
}
::v-deep .el-input__inner {
font-size: 14px;
width: 240px;
}
::v-deep .el-form-item__label {
line-height: 40px;
}
}
</style>
\ No newline at end of file
......@@ -12,14 +12,15 @@
<!-- 转端 -->
<el-collapse v-if="activeName == '1' && conversionGameList.length > 0" :disabled="disabled"
@change="conversionChangeOld">
<el-collapse-item v-for="(item, index) in conversionGameList" :key="index" :name="item.game_type">
<el-collapse-item class="mb-[10px]" v-for="(item, index) in conversionGameList" :key="index"
:name="item.game_type">
<template slot="title">
<div class="title-with-icon">
<img v-if="item.game_type == 1" src="@/assets/icon/wxgame.svg" class="game-icon" alt="微信小游戏">
<img v-else-if="item.game_type == 5" src="@/assets/icon/douyin.svg" class="game-icon" alt="抖音小游戏">
<img v-else-if="item.game_type == 3" src="@/assets/icon/Android.svg" class="game-icon" alt="安卓游戏">
<img v-else-if="item.game_type == 4" src="@/assets/icon/IOS.svg" class="game-icon" alt="IOS游戏">
<img v-else-if="item.game_type == 2" src="@/assets/icon/H5.svg" class="game-icon" alt="H5游戏">
<svg-icon v-if="item.game_type == 1" icon-class="wxgame" 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 }}
</div>
</template>
......@@ -62,11 +63,11 @@
<el-collapse-item v-for="(item, index) in recallGameList" :key="index" :name="item.game_type">
<template slot="title">
<div class="title-with-icon">
<img v-if="item.game_type == 1" src="@/assets/icon/wxgame.svg" class="game-icon" alt="微信小游戏">
<img v-else-if="item.game_type == 5" src="@/assets/icon/douyin.svg" class="game-icon" alt="抖音小游戏">
<img v-else-if="item.game_type == 3" src="@/assets/icon/Android.svg" class="game-icon" alt="安卓游戏">
<img v-else-if="item.game_type == 4" src="@/assets/icon/IOS.svg" class="game-icon" alt="IOS游戏">
<img v-else-if="item.game_type == 2" src="@/assets/icon/H5.svg" class="game-icon" alt="H5游戏">
<svg-icon v-if="item.game_type == 1" icon-class="wxgame" 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 }}
</div>
</template>
......@@ -106,11 +107,14 @@
<el-collapse-item v-for="(item, index) in regGameList" :key="index" :name="item.label">
<template slot="title">
<div class="title-with-icon">
<img v-if="item.label.includes('微信')" src="@/assets/icon/wxgame.svg" class="game-icon" alt="微信小游戏">
<img v-else-if="item.label.includes('抖音')" src="@/assets/icon/douyin.svg" class="game-icon" alt="抖音小游戏">
<img v-else-if="item.label.includes('安卓')" src="@/assets/icon/Android.svg" class="game-icon" alt="安卓游戏">
<img v-else-if="item.label.includes('IOS') || item.label.includes('iOS') || item.label.includes('ios')" src="@/assets/icon/IOS.svg" class="game-icon" alt="IOS游戏">
<img v-else-if="item.label.includes('H5') || item.label.includes('h5')" src="@/assets/icon/H5.svg" class="game-icon" alt="H5游戏">
<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
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 }}
</div>
</template>
......@@ -431,7 +435,7 @@ export default {
channelList(data).then((res) => {
if (res?.data?.data?.data?.length > 0) {
// 只有一个的时候自动发送渠道链接
this.channelInfoList = {
this.channelInfoList = {
game_id: items.game_id || items.id,
use_type: this.activeName,
sendType: this.sendType,
......@@ -524,11 +528,18 @@ export default {
handleConversionGameList() {
if (this.conversionGameList.length > 0) {
this.conversionGameList.forEach((item, index) => {
// 隐藏 h5的游戏 912:神权之战
if (item.game_type === 2 && item.children && item.children.length > 0) {
const filteredChildren = item.children.filter(child => {
return child.game_id !== '912'
})
this.$set(this.conversionGameList[index], 'children', filteredChildren)
}
// 隐藏安卓游戏 安卓游戏 game_type: 3
if (item.game_type === 3 && item.children && item.children.length > 0) {
// 过滤掉 game_name 为"破日开天"的数据
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 !== '破日开天' && child.game_name !== '英雄霸业' && child.game_id !== '741' && child.game_id !== '912'
})
this.$set(this.conversionGameList[index], 'children', filteredChildren)
}
......@@ -1111,6 +1122,7 @@ export default {
height: 100%;
overflow: auto;
margin-top: -10px;
.createChannel {
font-size: 14px;
margin-top: 16px;
......@@ -1126,7 +1138,7 @@ export default {
.title-with-icon {
display: flex;
align-items: center;
.game-icon {
width: 20px;
height: 20px;
......@@ -1149,17 +1161,18 @@ export default {
display: flex;
margin: 12px 16px;
width: calc(100% - 32px);
.radio-group {
width: 100%;
::v-deep .el-radio-group {
width: 100%;
display: flex;
}
::v-deep .el-radio-button {
flex: 1;
&__inner {
width: 100%;
height: 100%;
......@@ -1268,7 +1281,7 @@ export default {
}
/* 当转端按钮处于激活状态时保持自定义样式 */
::v-deep .el-radio-button.is-active{
::v-deep .el-radio-button.is-active {
.el-radio-button__inner {
background: #E8F7FF;
border-color: #3491FA;
......@@ -1277,11 +1290,11 @@ export default {
box-shadow: none;
}
}
/* 统一collapse样式 */
::v-deep .el-collapse-item__header {
background-color: #F7F8FA;
.el-collapse-item__arrow {
color: #3491FA;
}
......
......@@ -20,7 +20,7 @@ export default {
EmailGift,
WxGift
},
created(){
created() {
this.initializeWecom()
},
methods: {
......@@ -45,43 +45,43 @@ export default {
<style lang="scss" scoped>
.gift-tab-container-apply-gift {
width: 100%;
height: 100%;
padding-top: 10px;
background: #fff;
width: 100%;
height: 100%;
padding-top: 10px;
background: #fff;
::v-deep .el-tabs__content{
height: calc(100% - 55px);
}
::v-deep .el-tabs {
.el-tabs__header {
margin: 0;
padding: 0 15px;
}
.el-tabs__item {
height: 40px;
line-height: 40px;
font-size: 16px;
color: #333333;
&.is-active {
color: #3491FA;
}
}
.el-tabs__active-bar {
background-color: #3491FA;
height: 3px;
border-radius: 1.5px;
}
.el-tabs__nav-wrap::after {
height: 1px;
background-color: #e4e7ed;
::v-deep .el-tabs__content {
height: calc(100% - 55px);
}
::v-deep .el-tabs {
.el-tabs__header {
margin: 0;
padding: 0 15px;
}
.el-tabs__item {
height: 40px;
line-height: 40px;
font-size: 16px;
color: #333333;
&.is-active {
color: #3491FA;
}
}
.el-tabs__active-bar {
background-color: #3491FA;
height: 3px;
border-radius: 1.5px;
}
.el-tabs__nav-wrap::after {
height: 1px;
background-color: #e4e7ed;
}
}
}
</style>
\ No newline at end of file
import { getRoleRecentActivityNotPushNumApi } from '@/api/game';
// 账号近期要开活动数
let roleRecentActivityNotPushNum = null;
let cacheMemberId = null; //缓存请求id
const computedMap = new Map([]); //观察者列表
// 观察者收集
export function roleRecentActivitySubscription(fn, key) {
computedMap.set(key, fn);
}
//通知所有观察者
function roleRecentActivityRelease() {
computedMap.forEach((fn) => {
fn(roleRecentActivityNotPushNum);
});
}
function setCacheMemberId(member_id) {
cacheMemberId = member_id;
}
//获取数据
export async function queryRoleRecentActivityNotPushNum(
member_id = cacheMemberId
) {
const { data } = await getRoleRecentActivityNotPushNumApi({
member_id: member_id,
});
roleRecentActivityNotPushNum = data.data;
roleRecentActivityRelease();
}
function validate(v) {
if (!roleRecentActivityNotPushNum)
console.log(new Error(`执行${v},但是数据为空`));
}
//获取总数量
export function getTotalNum() {
validate('getTotalNum');
return roleRecentActivityNotPushNum?.totalNum || null;
}
//获取列表
export function getRoleNum() {
validate('getRoleNum');
return roleRecentActivityNotPushNum?.roleNum;
}
//销毁
export function destroy() {
roleRecentActivityNotPushNum = null;
cacheMemberId = null;
computedMap.clear();
}
//初始化
export async function createRoleRecentActivityNotPushNum(member_id) {
if (member_id && member_id !== cacheMemberId) {
setCacheMemberId(member_id);
await queryRoleRecentActivityNotPushNum(member_id);
}
return {
roleRecentActivitySubscription,
queryRoleRecentActivityNotPushNum,
getTotalNum,
getRoleNum,
destroy,
};
}
......@@ -17,6 +17,7 @@
<span class="loading-spinner"></span>
</div>
</div>
<!-- 新增手机号验证码登录功能 -->
</div>
<!-- 组织切换弹窗 -->
<el-dialog :visible.sync="showOrgDialog" width="300px" title="选择组织">
......@@ -104,16 +105,16 @@ export default {
},
// 设置缓存
cacheCorp_id(corp_id) {
Cookies.set('corp_id', corp_id, { expires: 7 })
Cookies.set('corp_id', corp_id, { expires: 30 })
this.set_corp_id(corp_id)
},
cacheuserid(userid) {
Cookies.set('userid', userid, { expires: 7 })
Cookies.set('userid', userid, { expires: 30 })
this.set_userid(userid)
},
cacheCser(cser_id, cser_name) {
Cookies.set('cser_id', cser_id, { expires: 7 })
Cookies.set('cser_name', cser_name, { expires: 7 })
Cookies.set('cser_id', cser_id, { expires: 30 })
Cookies.set('cser_name', cser_name, { expires: 30 })
this.set_cser_info({
cser_id: cser_id,
cser_name: cser_name
......@@ -122,7 +123,7 @@ export default {
this.set_cser_name(cser_name)
},
cacheSignData(signData) {
Cookies.set('signData', JSON.stringify(signData), { expires: 7 })
Cookies.set('signData', JSON.stringify(signData), { expires: 30 })
this.set_signData(signData)
},
// 进入的页面地址是 https://companywx.jianshuwenhua.com/company_app/index.html?corp_id=wweaefe716636df3d1
......
<template>
<div class="mail-list-container"
ref="mailListScroll"
v-scroll:50="loadMoreMail"
>
<!-- 搜索过滤区域 -->
......@@ -89,7 +88,6 @@
<!-- 通讯录列表 -->
<div
ref="mailListScroll"
v-scroll="loadMoreMail"
class="contact-list"
>
......
<template>
<div v-loading="loading">
<div class="px-[20px] h-full space-y-[8px] rounded-[4px] overflow-y-auto">
<template v-if="list.length">
<div
class="bg-[#F7F8FA] min-h-[99px] p-[8px]"
v-for="item in list"
:key="item.id"
>
<div
class="text-[#131920] pb-[8px] text-[14px] border-b-[1px] border-solid border-[#E5E5E6]"
>
<div>{{ item.name }}活动</div>
<div class="text-[#86909C] text-[12px]">
主服 {{ item.main_server_day }} 天开启
</div>
</div>
<div class="text-[13px] flex pt-[8px]">
<!-- <div class="text-[#6D7176] mr-[16px] flex-shrink-0">活动详情</div> -->
<div class="text-[#131920]">{{ item.detail }}</div>
</div>
</div>
</template>
<svg-icon v-else icon-class="noContent" class="text-[280px]" />
</div>
</div>
</template>
<script>
import { mapState } from 'vuex';
import { getRecentActivityListApi } from '@/api/game';
export default {
name: 'ActivityConfigurationList',
components: {},
props: ['role_id'],
data() {
return {
list: [],
loading: false,
};
},
computed: {
...mapState('game', ['gameUserInfo']),
},
methods: {
async getRecentActivityList() {
try {
this.loading = true;
const { data } = await getRecentActivityListApi({
role_id: this.role_id,
main_game_id: this.gameUserInfo.main_game_id,
weixin_blongs_id: this.gameUserInfo.weixin_blongs_id,
});
this.list = data.data;
} catch (error) {
} finally {
this.loading = false;
}
},
},
created() {
this.getRecentActivityList();
},
};
</script>
<style lang="scss" scoped></style>
<template>
<div v-loading="loading">
<div class="px-[20px] h-full gap-y-[8px] overflow-y-auto">
<template v-if="list.length">
<RecentActivities
@handleUpdate="query"
:item="item"
v-for="item in list"
:key="item.activity_rule_id"
/>
</template>
<svg-icon v-else icon-class="noContent" class="text-[280px]" />
</div>
</div>
</template>
<script>
import RecentActivities from '@/views/popup/RecentActivitiesPopup/templates/RecentActivities.vue';
import { getRoleRecentActivityListApi } from '@/api/game';
export default {
name: 'RecentActivitiesList',
components: { RecentActivities },
props: ['role_id'],
data() {
return {
list: [],
loading: false,
};
},
methods: {
async query() {
try {
this.loading = true;
const { data } = await getRoleRecentActivityListApi({
role_id: this.role_id,
});
this.list = data.data;
} catch (error) {
} finally {
this.loading = false;
}
},
},
created() {
this.query();
},
};
</script>
<style lang="scss" scoped></style>
// utils/componentHelper.js 或 useCreatePlayerDetails.js
import Vue from 'vue'
import RecentActivitiesPopup from './index.vue'
import store from '@/store' // 导入你的 Vuex store
export function createDetails(propsData = {}) {
const ComponentConstructor = Vue.extend(RecentActivitiesPopup)
const instance = new ComponentConstructor({
propsData,
// 手动注入 store
store
})
const mountNode = document.createElement('div')
document.querySelector('#recentActivitiesPopup').appendChild(mountNode)
instance.$mount(mountNode)
return {
instance,
destroy: () => {
instance.$destroy()
if (instance.$el && instance.$el.parentNode) {
instance.$el.parentNode.removeChild(instance.$el)
}
}
}
}
\ No newline at end of file
<template>
<div class="absolute z-10 top-0 left-0 h-full w-full bg-white" v-if="show">
<div
class="h-[60px] relative px-[18px] flex items-center border-b-[1px] border-solid border-[#e5e6eb]"
>
<i
class="el-icon-arrow-left text-[25px] hover:cursor-pointer"
@click="close"
></i>
<span
class="absolute left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 text-[#323335] font-bold"
>{{ title }}</span
>
</div>
<el-tabs class="h-[40px]" v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="近期要开" name="0"> </el-tab-pane>
<el-tab-pane label="活动配置" name="1"> </el-tab-pane>
</el-tabs>
<RecentActivitiesList v-if="activeName === '0'" :role_id="role_id" />
<ActivityConfigurationList v-if="activeName === '1'" :role_id="role_id" />
</div>
</template>
<script>
import RecentActivitiesList from './components/RecentActivitiesList.vue';
import ActivityConfigurationList from './components/ActivityConfigurationList.vue';
export default {
name: 'RecentActivitiesPopup',
components: { RecentActivitiesList, ActivityConfigurationList },
data() {
return {
show: false,
activeName: '0',
role_id: '',
title: '',
};
},
methods: {
open(role_id, title) {
this.show = true;
this.role_id = role_id;
this.title = title;
},
handleClick() {},
close() {
this.show = false;
this.activeName = '0';
},
},
created() {},
};
</script>
<style lang="scss" scoped>
::v-deep .el-tabs__item {
padding: 0 20px !important;
}
</style>
<template>
<div
class="space-y-[12px] mt-[10px] !p-[8px] bg-[#F7F8FA] rounded-[4px] item"
>
<div>
<span class="label">近期要开:</span>
<el-popover
placement="top-start"
width="250"
trigger="hover"
:content="item.activity_rule_detail"
>
<span slot="reference">{{ item.activity_rule_name }}</span>
</el-popover>
</div>
<div>
<span class="label">开启时间:</span
><span>{{ item.open_activity_time }}</span>
</div>
<div>
<span class="label">关联客服:</span><span>{{ item.cser_name }}</span>
</div>
<div class="group flex items-center">
<span class="label flex-shrink-0">备注:</span
><span v-show="!editShow">{{ item.remark }}</span>
<el-input
@blur="updated"
v-show="editShow"
type="textarea"
:rows="2"
placeholder="请输入内容"
v-model.trim="textarea"
>
</el-input>
<svg-icon
icon-class="edit"
class="icon invisible group-hover:visible"
style="font-size: 14px"
@click="editRemark"
/>
</div>
<div class="flex items-center">
<span class="label flex-shrink-0">推送状态:</span>
<span v-if="item.is_push === '2'">已推送</span>
<el-select
v-else
class="w-[70px]"
:clearable="false"
:value="item.is_push"
@change="handleChange"
>
<el-option label="未推送" value="1"> </el-option>
<el-option label="已推送" value="2"> </el-option>
</el-select>
</div>
<div class="flex items-center">
<span class="label flex-shrink-0">推送话术:</span>
<span
class="group flex-1 w-0 flex items-center"
v-if="pushLanguageTechnique"
>
<span class="truncate flex-1">{{ pushLanguageTechnique }}</span>
<i
class="el-icon-refresh mr-[8px] refreshList invisible group-hover:visible"
:class="isRefresh ? 'refreshListActive' : ''"
@click="refreshTag"
></i>
<svg-icon
icon-class="fuzhi"
class="icon invisible group-hover:visible"
style="font-size: 14px"
@click="copyText"
/>
</span>
<el-button
v-else
size="mini"
@click="queryGenerateProcedure"
:loading="isRefresh"
>生成话术</el-button
>
</div>
<slot></slot>
</div>
</template>
<script>
import { getRoleRecentActivityEditApi } from '@/api/game.js';
import { getGenerateProcedureApi } from '@/api/skill';
import { mapState } from 'vuex';
import { queryRoleRecentActivityNotPushNum } from '@/views/hooks/useGetCount';
const UpdateType = {
PUSH: 1, //修改推送
REMARK: 2, //修改备注
};
export default {
name: 'RecentActivitiesTemplate',
emits: ['handleUpdate'],
components: {},
props: ['item'],
data() {
return {
editShow: false,
textarea: '',
isRefresh: false,
pushLanguageTechnique: '', //推送话术
};
},
computed: {
...mapState('user', ['cser_id', 'cser_name']),
...mapState('game', ['accountSelect', 'bindGameUserList']),
nowGameUserInfo() {
return {
member_id: this.accountSelect,
username: this.bindGameUserList.find(
(item) => item.member_id == this.accountSelect
)?.username,
};
},
},
methods: {
editRemark() {
this.editShow = true;
this.textarea = this.item.remark;
},
async updated() {
this.editShow = false;
if (this.textarea === this.item.remark) return;
this.edit(UpdateType.REMARK);
},
handleChange() {
this.edit(UpdateType.PUSH);
},
async edit(type) {
try {
await getRoleRecentActivityEditApi({
type,
role_id: this.item.role_id,
open_activity_time: this.item.open_activity_time,
remark: this.textarea,
activity_rule_id: this.item.activity_rule_id,
is_push: 2,
user_id: this.cser_id,
user_name: this.cser_name,
});
this.$message.success('修改成功');
queryRoleRecentActivityNotPushNum(this.accountSelect);
this.$emit('handleUpdate');
} catch (error) {
this.$message.error(error);
}
},
async queryGenerateProcedure() {
try {
this.isRefresh = true;
const { data } = await getGenerateProcedureApi({
...this.item,
...this.nowGameUserInfo,
});
this.pushLanguageTechnique = data.content;
} catch (error) {
} finally {
this.isRefresh = false;
}
},
async copyText() {
try {
await navigator.clipboard.writeText(this.pushLanguageTechnique);
this.$message.success('复制成功');
} catch (err) {
console.error('复制失败:', err);
}
},
refreshTag() {
this.queryGenerateProcedure();
},
},
created() {
console.log(this.nowGameUserInfo, 1111111);
},
};
</script>
<style lang="scss" scoped>
.item {
width: 100%;
height: auto;
font-size: 14px;
font-weight: 400;
color: #333333;
transition: all 0.5s;
position: relative;
cursor: pointer;
.label {
font-size: 14px;
color: #999999;
font-weight: 500;
margin-right: 8px;
}
.tag-icon {
cursor: pointer;
font-size: 14px;
color: #333333;
margin-right: 8px;
}
}
.refreshListActive {
animation: rotate 0.5s linear infinite;
}
.refreshList {
color: #3491fa;
cursor: pointer;
font-size: 18px;
}
::v-deep .el-input__inner {
background-color: transparent;
border: 0;
box-shadow: none;
padding: 0;
}
::v-deep .el-select .el-input.is-focus .el-input__inner {
border-color: transparent !important;
box-shadow: none;
}
</style>
<!--
* @Author: maoxiya 937667504@qq.com
* @Date: 2025-06-25 16:46:39
* @LastEditors: maoxiya 937667504@qq.com
* @LastEditTime: 2025-09-02 14:16:38
* @FilePath: /company_app/src/views/roleInfo.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
<div class="roleTab">
<el-tabs v-model="roleActive">
<el-tab-pane label="角色信息" name="roleInfo">
<roleInfoPanel v-if="roleActive === 'roleInfo'" :chatUserDetails="chatUserInfo" />
</el-tab-pane>
<el-tab-pane label="举报信息" name="report">
<report v-if="roleActive === 'report'" />
</el-tab-pane>
<el-tab-pane label="申诉记录" name="approval">
<approval v-if="roleActive === 'approval'" />
</el-tab-pane>
<el-tab-pane label="违规记录" name="violation">
<violationRecord v-if="roleActive === 'violation'" />
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import roleInfoPanel from './components/roleInfo/roleInfoPanel.vue'
import report from './components/roleInfo/report.vue'
import approval from './components/roleInfo/approval.vue'
import { mapState } from 'vuex'
import violationRecord from '@/views/ViolationRecord.vue';
export default {
name: 'roleInfo',
components: {
roleInfoPanel,
approval,
report
violationRecord,
},
computed: {
...mapState('game', ['chatUserInfo'])
......@@ -53,43 +62,43 @@ export default {
width: 100%;
height: 100%;
background: #fff;
::v-deep .el-tabs {
width: 100%;
height: 100%;
.el-tabs__header {
margin: 0;
padding: 0 15px;
}
.el-tabs__item {
height: 40px;
line-height: 40px;
font-size: 16px;
color: #333333;
&.is-active {
color: #3491FA;
}
}
.el-tabs__active-bar {
background-color: #3491FA;
height: 3px;
border-radius: 1.5px;
}
.el-tabs__nav-wrap::after {
height: 1px;
background-color: #e4e7ed;
}
.el-tab-pane {
width: 100%;
height: 100%;
}
.el-tabs__content {
height: calc(100% - 40px);
padding: 15px;
......
......@@ -18,7 +18,8 @@
</el-tab-pane>
</el-tabs>
<!-- 运营任务 -->
<div class="taskListContent" v-if="taskForm.type !== 'user_task' && taskForm.type !== 'account_task'" v-scroll="paperScroll" >
<div class="taskListContent" v-if="taskForm.type !== 'user_task' && taskForm.type !== 'account_task'"
v-scroll="paperScroll">
<el-form ref="taskForm" :model="taskForm" class="taskForm" label-position="top" label-width="85px">
<!-- 运营任务 -->
<div v-if="taskForm.type == 1" class="taskFormItem">
......@@ -116,14 +117,14 @@
</span>
</p>
</div>
<div class="taskListScroll" v-loading="loading"
:class="taskForm.type != 1 ? 'taskListScrollActive' : ''">
<div class="taskListScroll" v-loading="loading" :class="taskForm.type != 1 ? 'taskListScrollActive' : ''">
<!-- 运营任务 -->
<div v-if="taskForm.type == 1" class="scrollMain">
<div v-for="(item, index) in taskList" :key="index" class="chatListItem columnCenter spaceBetween"
:class="item.id === taskDetails.id ? 'chatListItemActive' : ''" @click="selectTaskItem(item)">
<div class="top rowFlex spaceBetween">
<div v-if="item.username && item.username.split('\n') && item.username.split('\n').length > 0" class="value">
<div v-if="item.username && item.username.split('\n') && item.username.split('\n').length > 0"
class="value">
<div v-if="item.username.split('\n').length <= 1" class="rowFlex columnCenter">
<div v-for="(items, indexs) in item.username.split('\n')" :key="indexs"
class="rowFlex columnCenter userInfoStyle">
......@@ -139,7 +140,9 @@
<span class="textHidden" style="max-width:150px;">{{ items }}</span>
</p>
</div>
<el-button slot="reference" type="text">{{ item.username && item.username.split("\n") && item.username.split("\n").length?item.username.split("\n").length : 0
<el-button slot="reference" type="text">{{ item.username &&
item.username.split("\n") &&
item.username.split("\n").length ?item.username.split("\n").length : 0
}}个</el-button>
</el-popover>
</div>
......@@ -156,8 +159,8 @@
k.value
==
item.plan_type).label ? taskTypeList.find((k) => k.value == item.plan_type).label :
""
}}</span>
""
}}</span>
</p>
<div class="right">¥{{ formatNumber(item.member_recharge) }}</div>
</div>
......@@ -168,9 +171,9 @@
<noContent v-if="taskList.length == 0" />
</div>
<!-- 用户任务 和 运营任务 -->
<div class="taskListContent" v-else-if="taskForm.type == 'user_task' || taskForm.type == 'account_task'">
<userTask :taskForm="taskForm" :activeType="taskForm.type" />
</div>
<div class="taskListContent" v-else-if="taskForm.type == 'user_task' || taskForm.type == 'account_task'">
<userTask :taskForm="taskForm" :activeType="taskForm.type" />
</div>
<taskDetails v-if="showTaskDetails" :show.sync="showTaskDetails" />
</div>
</template>
......@@ -188,17 +191,17 @@ import mainGameSelect from '@/components/mainGame.vue'
import { removeDp } from '@/utils/index'
import selectDate from '@/components/selectDate.vue'
import { formatNumber } from '@/utils/index'
import shenpi1 from '@/assets/icon/shenpi1.svg'
import shenpi2 from '@/assets/icon/shenpi2.svg'
import shenpi3 from '@/assets/icon/shenpi3.svg'
import shenpi4 from '@/assets/icon/shenpi4.svg'
import shenpi5 from '@/assets/icon/shenpi5.svg'
import shenpi1 from '@/assets/icon/svg/shenpi1.svg'
import shenpi2 from '@/assets/icon/svg/shenpi2.svg'
import shenpi3 from '@/assets/icon/svg/shenpi3.svg'
import shenpi4 from '@/assets/icon/svg/shenpi4.svg'
import shenpi5 from '@/assets/icon/svg/shenpi5.svg'
import noContent from '@/components/noContent.vue'
import userTask from './components/taskList/uesrTask.vue'
import taskDetails from './components/taskList/taskDetails.vue'
export default {
props: {
},
watch: {
accountSelect(newVal, oldVal) {
......@@ -387,7 +390,7 @@ export default {
} catch (error) {
console.error('❌ 企业微信 SDK 初始化失败:', error)
}
},
},
// 刷新任务数据
async refreshTaskData() {
try {
......@@ -415,13 +418,13 @@ export default {
this.typeList.forEach(item => {
// 重置红点数量
item.redNum = 0
// 根据任务类型设置红点数量
if (taskNum[item.type] && taskNum[item.type] > 0) {
item.redNum = taskNum[item.type]
}
})
this.$forceUpdate()
},
iconSort(type) {
......@@ -665,14 +668,17 @@ export default {
::v-deep .el-tabs {
height: auto;
}
.taskListContent {
width: 100%;
height: calc(100% - 40px);
overflow-y: auto;
}
.taskFormItem {
margin-top: 10px;
}
.taskForm {
::v-deep .el-form-item {
margin-bottom: 5px;
......@@ -754,11 +760,13 @@ export default {
.taskListScroll {
width: 100%;
.scrollMain {
width: 100%;
height: auto;
margin-bottom: 50px;
padding: 0 10px;
//举报申请
.reportItem {
padding: 10px;
......@@ -863,7 +871,7 @@ export default {
top: 12px !important;
right: -2px !important;
}
::v-deep .el-badge__content.is-dot {
top: 10px !important;
right: -2px !important;
......
<template>
<!-- 营销面板组件 -->
<div class="item">
<div class="rowFlex columnCenter">
<span class="label">营销面板:</span>
<i
v-if="recentInfo.role_id"
:class="['el-icon-arrow-' + (active ? 'down' : 'right'), 'tag-icon']"
@click="handleClick"
></i>
</div>
<RecentActivities
v-if="recentInfo.role_id"
:item="recentInfo"
v-show="active"
@handleUpdate="getRoleData"
>
<el-button
type="text"
size="mini"
@click="
() =>
recentActivitiesPopupInstance.instance.open(
recentInfo.role_id,
popupTitle
)
"
>
查看更多 >
</el-button>
</RecentActivities>
</div>
</template>
<script>
import RecentActivities from '@/views/popup/RecentActivitiesPopup/templates/RecentActivities.vue';
import { createDetails } from '@/views/popup/RecentActivitiesPopup/index.js';
import { getRoleRecentActivityOneApi } from '@/api/game';
import { getRoleHoLo } from '@/api/game';
import { mapState } from 'vuex';
export default {
name: 'MarketingPanel',
components: { RecentActivities },
data() {
return {
active: true,
recentActivitiesPopupInstance: null, //近期要开模块弹框
recentInfo: {},
roleInfoList: [],
};
},
computed: {
...mapState('game', ['accountSelect']),
popupTitle() {
const findItem = this.roleInfoList.find(
(item) => item.role_id == this.recentInfo.role_id
);
if (findItem) {
return `${findItem.role_name}-${findItem.server_name}-${findItem.recharge_total}元`;
}
return;
},
},
methods: {
async queryGetRoleHoLo() {
const { data } = await getRoleHoLo({
page_size: 100,
page: 1,
member_id: this.accountSelect,
search_type: 'list',
});
this.roleInfoList = data.data;
},
handleClick() {
this.active = !this.active;
},
async getRoleData() {
const { data } = await getRoleRecentActivityOneApi({
member_id: this.accountSelect,
});
this.recentInfo = data.data;
},
},
created() {
this.getRoleData();
this.queryGetRoleHoLo();
},
mounted() {
this.recentActivitiesPopupInstance = createDetails({
gameUserInfoInject: this.gameUserInfoInject,
});
},
beforeDestroy() {
this.recentActivitiesPopupInstance.destroy();
},
};
</script>
<style lang="scss" scoped>
.item {
width: 100%;
height: auto;
font-size: 14px;
padding: 16px;
font-weight: 400;
color: #333333;
padding: 10px 0;
transition: all 0.5s;
position: relative;
cursor: pointer;
.label {
font-size: 14px;
color: #999999;
font-weight: 500;
margin-right: 8px;
}
.tag-icon {
cursor: pointer;
font-size: 14px;
color: #333333;
margin-right: 8px;
}
}
.refreshListActive {
animation: rotate 0.5s linear infinite;
}
.refreshList {
color: #3491fa;
cursor: pointer;
font-size: 18px;
}
</style>
<template>
<div class="userInfo-content">
<div class="userInfo-content relative" id="recentActivitiesPopup">
<el-tabs v-model="activeTab" class="user-tabs">
<el-tab-pane label="客户信息" name="info">
<Info :chatUserDetails="chatUserInfo"/>
<Info :chatUserDetails="chatUserInfo" />
</el-tab-pane>
<el-tab-pane label="角色信息" name="role">
<template #label v-if="totalNum">
<el-badge :value="totalNum" class="text-center">
<p>角色信息</p>
</el-badge>
</template>
<roleInfo v-if="activeTab === 'role'" />
</el-tab-pane>
<el-tab-pane label="订单信息" name="order">
<orderList v-if="activeTab === 'order'" />
</el-tab-pane>
<el-tab-pane label="违规记录" name="violation">
<violationRecord v-if="activeTab === 'violation'" />
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import Info from './components/Info.vue'
import roleInfo from '@/views/roleInfo.vue'
import orderList from '@/views/orderList.vue'
import violationRecord from '@/views/ViolationRecord.vue'
import { mapState, mapMutations } from 'vuex'
import Cookies from 'js-cookie'
import Info from './components/Info.vue';
import roleInfo from '@/views/roleInfo.vue';
import orderList from '@/views/orderList.vue';
import { mapState, mapMutations } from 'vuex';
import { createRoleRecentActivityNotPushNum } from '@/views/hooks/useGetCount';
import Cookies from 'js-cookie';
export default {
name: 'userInfo',
components: {
Info,
roleInfo,
orderList,
violationRecord
},
mounted() {
watch: {
async accountSelect(newVal) {
await this.initInstance();
},
},
data() {
return {
activeTab: 'info'
}
activeTab: 'info',
instance: null,
totalNum: 0,
};
},
computed: {
...mapState('game', ['chatUserInfo']),
...mapState('game', ['chatUserInfo', 'accountSelect']),
},
created() {
// 初始化 vuex 中的值
this.initInstance();
},
mounted() {
this.$nextTick(() => {
this.initVuexValue()
})
this.initVuexValue();
});
},
methods: {
...mapMutations('user', ['set_userInfo']),
initVuexValue(){
async initInstance() {
this.instance = await createRoleRecentActivityNotPushNum(
this.accountSelect
);
this.totalNum = this.instance.getTotalNum();
this.instance.roleRecentActivitySubscription(() => {
this.totalNum = this.instance.getTotalNum();
}, this);
},
initVuexValue() {
const userinfo = {
cser_id: Cookies.get('cser_id'),
cser_name: Cookies.get('cser_name'),
username: Cookies.get('cser_name'),
id: Cookies.get('cser_id'),
}
this.set_userInfo(userinfo)
}
}
}
};
this.set_userInfo(userinfo);
},
},
beforeDestroy() {
this.instance && this.instance.destroy();
},
};
</script>
<style lang="scss" scoped>
......@@ -74,29 +93,34 @@ export default {
.user-tabs {
width: 100%;
::v-deep .el-tabs__header {
margin-bottom: 15px;
padding: 0 10px;
}
::v-deep .el-tabs__nav-wrap::after {
height: 1px;
}
::v-deep .el-tabs__item {
height: 40px;
line-height: 40px;
font-size: 14px;
}
::v-deep .el-tabs__active-bar {
height: 2px;
}
::v-deep .el-tabs__content {
height: calc(100% - 55px);
}
}
}
::v-deep .el-badge__content.is-fixed {
top: 8px;
right: 6px;
}
</style>
/*
* @Author: maoxiya 937667504@qq.com
* @Date: 2025-08-30 10:54:21
* @LastEditors: maoxiya 937667504@qq.com
* @LastEditTime: 2025-08-30 10:54:29
* @FilePath: /company_app/tailwind.config.js
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
module.exports = {
mode: 'jit', // 关键配置
purge: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
darkMode: false,
theme: {
extend: {}
},
variants: {
extend: {}
},
plugins: [
function({ addUtilities }) {
const newUtilities = {
'.truncate-2': {
display: '-webkit-box',
'-webkit-box-orient': 'vertical',
'-webkit-line-clamp': '2',
'overflow': 'hidden',
'text-overflow': 'ellipsis',
'word-wrap': 'break-word',
'word-break': 'break-word',
},
'.truncate-3': {
display: '-webkit-box',
'-webkit-box-orient': 'vertical',
'-webkit-line-clamp': '3',
'overflow': 'hidden',
'text-overflow': 'ellipsis',
'word-wrap': 'break-word',
'word-break': 'break-word',
}
}
addUtilities(newUtilities, ['responsive', 'hover'])
}
],
corePlugins: {
container: false // 禁用默认的 container
}
}
......@@ -74,5 +74,48 @@ module.exports = defineConfig({
// }
}
}
},
chainWebpack(config) {
// set svg-sprite-loader
config.module.rule('svg').exclude.add(resolve('src/assets/icon/svg')).end()
config.module
.rule('icons')
.test(/\.svg$/)
.include.add(resolve('src/assets/icon/svg'))
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]'
})
.end()
config.when(process.env.NODE_ENV !== 'development', (config) => {
config.optimization.splitChunks({
chunks: 'all',
cacheGroups: {
libs: {
name: 'chunk-libs',
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: 'initial' // only package third parties that are initially dependent
},
elementUI: {
name: 'chunk-elementUI', // split elementUI into a single package
priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
},
commons: {
name: 'chunk-commons',
test: resolve('src/components'), // can customize your rules
minChunks: 3, // minimum common number
priority: 5,
reuseExistingChunk: true
}
}
})
// https:// webpack.js.org/configuration/optimization/#optimizationruntimechunk
config.optimization.runtimeChunk('single')
})
}
})
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论