添加通知弹窗、音效,具有防抖

This commit is contained in:
peak 2025-06-12 18:43:40 +08:00
parent d8f71b14cb
commit 8114f48e70
9 changed files with 9346 additions and 7592 deletions

View File

@ -5,7 +5,8 @@ VITE_DEV=true
# 请求路径
VITE_BASE_URL='https://zysc.fjptzykj.com'
# VITE_BASE_URL='http://192.168.1.12:6127'
# VITE_BASE_URL='http://192.168.10.75:6127'
# VITE_BASE_URL='http://127.0.0.1:6127'
# 文件上传类型server - 后端上传, client - 前端直连上传,仅支持 S3 服务
VITE_UPLOAD_TYPE=server

View File

@ -62,7 +62,7 @@
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
"editor.defaultFormatter": "vscode.typescript-language-features"
},
"[typescriptreact]": {
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,9 @@ import { useAppStore } from '@/store/modules/app'
import { useDesign } from '@/hooks/web/useDesign'
import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
import routerSearch from '@/components/RouterSearch/index.vue'
import EventBus from '@/utils/eventBus'
import { debounce } from 'lodash'
import { ElNotification } from 'element-plus'
defineOptions({ name: 'APP' })
const { getPrefixCls } = useDesign()
@ -23,6 +25,17 @@ const setDefaultTheme = () => {
appStore.setIsDark(isDarkTheme)
}
setDefaultTheme()
const debounceNotify = debounce((msg) => {
alert(msg)
ElNotification.info({
title: "新消息",
message: msg,
duration: 3000,
})
}, 600);
onMounted(() => {
EventBus.on('show-notification', debounceNotify);
})
</script>
<template>
<ConfigGlobal :size="currentSize">

View File

@ -5,6 +5,9 @@ import { Backtop } from '@/components/Backtop'
import { Setting } from '@/layout/components/Setting'
import { useRenderLayout } from './components/useRenderLayout'
import { useDesign } from '@/hooks/web/useDesign'
import EventBus from '@/utils/eventBus'
import { debounce } from 'lodash'
import { ElNotification } from 'element-plus'
const { getPrefixCls } = useDesign()
@ -42,7 +45,14 @@ const renderLayout = () => {
break
}
}
const debounceNotify = debounce((msg) => {
ElNotification.info({
title: "新消息",
message: msg,
duration: 3000,
})
}, 600);
EventBus.on('notification', debounceNotify);
export default defineComponent({
name: 'Layout',
setup() {

View File

@ -0,0 +1,2 @@
import mitt from 'mitt';
export default mitt();

View File

@ -7,8 +7,7 @@
<div style="width:100%;height:68px;background-color:#3c80ff;">
<el-row>
<el-col :span="6">
<el-input @input="findNameInput" v-model="findName"
style="width: 80%;margin-top: 20px;margin-left:23px;"
<el-input @input="findNameInput" v-model="findName" style="width: 80%;margin-top: 20px;margin-left:23px;"
:suffix-icon="Search" />
</el-col>
@ -28,16 +27,14 @@
<span style="display: flex; margin-top: 15px;">
<!-- <el-avatar :src="pic"/> -->
<span style="margin-left:5px;margin-top: 9px;">{{ name }}</span>
<el-switch
style="margin-top: 4px;--el-switch-on-color: #13ce66; --el-switch-off-color: #b6bac1;"
v-model="lineStatus" class="ml-2" width="60" inline-prompt active-text="在线"
inactive-text="下线" @change="handleSwitchChange"/>
<el-switch style="margin-top: 4px;--el-switch-on-color: #13ce66; --el-switch-off-color: #b6bac1;"
v-model="lineStatus" class="ml-2" width="60" inline-prompt active-text="在线" inactive-text="下线"
@change="handleSwitchChange" />
</span>
</el-col>
<el-col :span="4">
<el-button @click="out" size="small" round
style="margin-top:23px;margin-left:72%">退出
<el-button @click="out" size="small" round style="margin-top:23px;margin-left:72%">退出
</el-button>
</el-col>
@ -166,9 +163,12 @@
import * as UserApi from '@/api/member/user'
import { SupportStaffApi, SupportStaffVO } from '@/api/mall/promotion/supportstaff'
import { string } from 'vue-types'
import EventBus from '@/utils/eventBus';
import bgm from './xm3463.mp3'
import type { TabsPaneContext } from 'element-plus'
import { ElNotification } from 'element-plus'
const findName = ref('')
const audio = new Audio(bgm)
defineOptions({ name: 'KeFu' })
const lineStatus = ref(true)
@ -191,7 +191,7 @@ import type { TabsPaneContext } from 'element-plus'
// ======================= WebSocket start =======================
const server = ref(
(import.meta.env.VITE_BASE_URL + '/infra/ws').replace('http', 'ws') +
'?token=' + getRefreshToken()
'?token=' + getAccessToken()
// getAccessToken()
// 使 getRefreshToken() 使 getAccessToken() WebSocket 便访
) // WebSocket
@ -241,8 +241,6 @@ import type { TabsPaneContext } from 'element-plus'
// }
// },
onMessage: function (ws, event) {
// console.log(' WebSocket :', event.data);
a = a + 1;
if (a == 2) {
getConversationList()
@ -252,25 +250,17 @@ import type { TabsPaneContext } from 'element-plus'
keFuChatBoxRef.value?.refreshMessageList()
}
}
a = 0;
}
},
autoReconnect: true, //
heartbeat: true
});
// const { data, close, open } = useWebSocket(server.value, {
// autoReconnect: true,
// heartbeat: true
// })
/** 监听 WebSocket 数据 */
watchEffect(() => {
console.log('连接服务器得到消息:', data.value)
if (!data.value) {
return
}
@ -292,6 +282,23 @@ import type { TabsPaneContext } from 'element-plus'
// 2.2 KEFU_MESSAGE_TYPE
if (type === WebSocketMessageTypeConstants.KEFU_MESSAGE_TYPE) {
console.log('来自用户发送的消息:', JSON.parse(jsonMessage.content))
const message = JSON.parse(jsonMessage.content)
if (message.senderType == 1) {
audio.play()
EventBus.emit('notification', message.content)
// Notification.requestPermission().then(permission => {
// if (permission === 'granted') {
// console.log('');
// }
// });
// if (Notification.permission === 'granted') {
// console.warn('');
// new Notification(":"+message.content);
// } else {
// console.warn('');
// }
}
//
// TODO @puhui999 update
getConversationList()

View File

@ -169,6 +169,8 @@ import { SupportStaffApi, SupportStaffVO } from '@/api/mall/promotion/supportsta
import SupportStaffForm from './SupportStaffForm.vue'
import { setStaffToken} from '@/utils/auth'
import { createImageViewer } from '@/components/ImageViewer'
import { useRouter } from 'vue-router'
const router = useRouter()
/** 客服人员 列表 */
defineOptions({ name: 'SupportStaff' })
@ -247,8 +249,10 @@ const handleDelete = async (id: number) => {
/** 客服进入工作台 */
const handleEnterConsole = async (id: number,name: string,pic: string) => {
setStaffToken(id);
const url = `${window.location.origin}/kefu/kefu?id=${encodeURIComponent(id)}&name=${encodeURIComponent(name)}&pic=${encodeURIComponent(pic)}`;
const url = `${window.location.origin}/kefu/chat?id=${encodeURIComponent(id)}&name=${encodeURIComponent(name)}&pic=${encodeURIComponent(pic)}`;
window.open(url, '_blank');
// const url = `/kefu/chat?id=${encodeURIComponent(id)}&name=${encodeURIComponent(name)}&pic=${encodeURIComponent(pic)}`;
// router.push(url);
}
/** 导出按钮操作 */
const handleExport = async () => {