create-iking-admin
Version:
金合技术中台脚手架
221 lines (210 loc) • 7.62 kB
text/typescript
/*
* @Author : wfl
* @LastEditors: qiye
* @description :
* @updateInfo :
* @Date : 2023-07-26 11:10:34
* @LastEditTime: 2024-02-05 11:56:16
*/
import { ElNotification } from 'element-plus'
import router from '@main/router'
import useUserStore from './user'
import useNotificationStore from './notification'
import useApproveFlowStore from './approveFlow'
export const REDIRECT = {
// 审批模块跳转
approve: {
path: '/approve-center/approve-list',
value: {
// 进入 我审批的
'back-to-approve': 1,
'submit': 1,
'remind': 1,
// 进入 我提交的
'reject': 2,
'pass': 2,
'back-to-initiator': 2,
// 进入 抄送我的
'carbon-copy': 3,
},
},
}
const logStyle = 'font-size: 14px; color: green; '
const logErrStyle = 'text-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);color: red;'
const useSocketStore = defineStore(
// 唯一ID
'socket',
() => {
ikNotification.checkPermission()
// =======================Socket相关================================
// socket实例
let socketApp: WebSocket | null = null
// 初始重连间隔为 1 秒
let reconnectInterval = 1000
// 最大重连间隔
const maxReconnectInterval = import.meta.env.VITE_APP_MAX_SOCKET_RECONNECT_TIME
// 重连定时器
let timer: number | null = null
// 保存消息实例,用于点击后关闭对应实例
const notificationMap = new Map()
const userStore = useUserStore()
const flowStore = useApproveFlowStore()
const notificationStore = useNotificationStore()
// 是否连接
const connected = ref(false)
// 系统消息
const systemMsgList = ref<any[]>([])
// 消息地址
const SOCKET_URL = `${window.location.href.startsWith('https') ? 'wss' : 'ws'}://${location.host}${import.meta.env.VITE_APP_SOCKET_URL}/server/ws/message`
// =======================Socket相关================================
const linkTo = (path: string, info: { tabId?: string, id?: string, target?: '_black' | '_self', uuid?: string }) => {
if (path.startsWith('http')) {
window.open(path, info.target)
}
else {
flowStore.setSocketInfo({
path,
...info,
})
router.push({
path,
})
}
if (notificationMap.has(info?.uuid)) {
notificationMap.get(info?.uuid)?.close()
notificationMap.delete(info?.uuid)
}
}
// 创建socket
const createSocket = () => {
const user = userStore.userInfo
if (!user) { return }
socketApp = new WebSocket(`${SOCKET_URL}?userId=${user?.id}&token=${ikStore.local.getItem('token')}`)
// 连接成功
socketApp.onopen = () => {
console.info('%c[Iking Admin] Socket已连接', logStyle)
reconnectInterval = 1000 // 重连成功后重置重连间隔
}
// 收到消息
socketApp.onmessage = (e: any) => {
console.info(`%c[Iking Admin] Socket消息: ${e?.data}`, logStyle)
try {
const data = JSON.parse(e?.data)
const { redirectTo, text, showNotification }: { redirectTo: Array<{ redirectLink: string, redirectName: string }>, text: string, showNotification: boolean } = data
const linkArr: any[] = []
// 不需要系统提示的消息
if (!showNotification) {
ikMitt.emit('socket-message', e)
return
}
const uuid = buildUUID()
if (Array.isArray(redirectTo)) {
for (const li of redirectTo) {
const isHttpLink = li?.redirectLink.startsWith('http')
if (isHttpLink) {
linkArr.push(h('a', { class: 'ik-sys-msg-no', onClick: () => linkTo(li?.redirectLink, { uuid, target: '_black' }) }, li?.redirectName || '查看详情'))
}
else {
const splitPath = li?.redirectLink.split('/')
const tabId = splitPath?.[2]
const id = splitPath?.[3]
let redirectObj: any
if (li?.redirectLink.startsWith('approve://')) { redirectObj = REDIRECT.approve }
linkArr.push(h('a', {
class: 'ik-sys-msg-no',
onClick: () => redirectObj
? linkTo(redirectObj.path, { tabId: redirectObj.value[tabId], id, uuid, target: '_self' })
: (() => {
router.push({
path: li.redirectLink,
query: {
link: li.redirectLink,
},
})
// 跳转后关闭消息框
if (notificationMap.has(uuid)) {
notificationMap.get(uuid)?.close()
notificationMap.delete(uuid)
}
})(),
}, li?.redirectName || '查看详情'))
}
}
}
// 顶部消息图表 - 未读消息数+1
notificationStore.message += 1
const infoHtml = []
for (const i of text?.split('\r\n')) { infoHtml.push(h('p', { class: '' }, i)) }
const Notifion = ElNotification({
title: '有新消息',
// dangerouslyUseHTMLString: true,
type: 'success',
duration: 0,
message: h('p', {
style: '',
},
[...infoHtml, ...linkArr],
),
})
notificationMap.set(uuid, Notifion)
}
catch (error) {
}
try {
ikMitt.emit('socket-message', e)
const data = JSON.parse(e?.data)
systemMsgList.value.push(data)
ikNotification.showNotification({
title: '有新消息',
message: e?.data,
}, () => { })
}
catch (error) {
}
}
// 连接错误
socketApp.onerror = () => {
console.error('%c[Iking Admin] Socket连接错误', logErrStyle)
}
// 连接关闭
socketApp.onclose = (e: any) => {
console.info('%c[Iking Admin] Socket连接关闭', logStyle, e)
timer && clearTimeout(timer)
// 根据需要判断是否进行重连
const isLoginPage = location.href.includes('/login')
if (!e.wasClean && !isLoginPage) { reconnect() }
}
return socketApp
}
// 重连
const reconnect = () => {
if (socketApp) { socketApp.close() }
// 指数退避重连时间逐步增加
timer = window.setTimeout(() => {
if (reconnectInterval < maxReconnectInterval) { reconnectInterval *= 2 } // 重连间隔翻倍
console.info(`%c[Iking Admin] 下次重连时间${reconnectInterval}ms后`, logStyle)
createSocket()
}, reconnectInterval)
}
// 页面加载完成后创建socket
window.onload = () => {
createSocket()
}
// 发送消息
const emitMessage = (data?: string) => {
socketApp?.send(JSON.stringify({ data }))
}
// 关闭socket
const closeScoket = () => {
socketApp?.close()
}
return {
connected,
systemMsgList,
createSocket,
closeScoket,
emitMessage,
}
},
)
export default useSocketStore