245 lines
7.0 KiB
Vue
245 lines
7.0 KiB
Vue
<template>
|
|
<ElConfigProvider size="default" :locale="locales[language]" :z-index="3000">
|
|
<RouterView></RouterView>
|
|
</ElConfigProvider>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { useUserStore } from './store/modules/user'
|
|
import zh from 'element-plus/es/locale/lang/zh-cn'
|
|
import en from 'element-plus/es/locale/lang/en'
|
|
import { systemUpgrade } from './utils/sys'
|
|
import { UserService } from './api/usersApi'
|
|
import { setThemeTransitionClass } from './utils/theme/animation'
|
|
import { checkStorageCompatibility } from './utils/storage'
|
|
import { mittBus } from '@/utils/sys'
|
|
import appLogo from '@/assets/img/common/logox.png'
|
|
|
|
const userStore = useUserStore()
|
|
const { language, accessToken } = storeToRefs(userStore)
|
|
function setCompanyFromUrl() {
|
|
const userStore = useUserStore()
|
|
const params = new URLSearchParams(window.location.search)
|
|
const companyid = params.get('corp_id')
|
|
const companyabbr = params.get('corp_abbr')
|
|
// const systemid = params.get('system_id')
|
|
// const system_code = params.get('system_code')
|
|
if (companyid) {
|
|
userStore.setCompany(companyid, companyabbr || '')
|
|
// userStore.setSystems(systemid || '', system_code || '')
|
|
// 你也可以加 localStorage/sessionStorage 备份
|
|
}
|
|
}
|
|
const locales = {
|
|
zh: zh,
|
|
en: en
|
|
}
|
|
const isSupported = ref(false)
|
|
const permissionStatus = ref('default')
|
|
// 检查浏览器支持情况
|
|
const checkSupport = () => {
|
|
if ('Notification' in window) {
|
|
isSupported.value = true
|
|
console.log('浏览器支持原生Notification API')
|
|
} else {
|
|
isSupported.value = false
|
|
console.log('⚠️ 浏览器不支持原生Notification API')
|
|
}
|
|
}
|
|
// 请求通知权限
|
|
const requestPermission = async () => {
|
|
if (!('Notification' in window)) {
|
|
console.log('浏览器不支持原生Notification API')
|
|
return
|
|
}
|
|
try {
|
|
const permission = await Notification.requestPermission()
|
|
permissionStatus.value = permission
|
|
if (permission === 'granted') {
|
|
console.log('用户已授予通知权限')
|
|
} else if (permission === 'denied') {
|
|
console.log('用户拒绝了通知权限')
|
|
} else {
|
|
console.log('用户暂时未授予通知权限')
|
|
}
|
|
} catch (error) {
|
|
console.log(`请求权限时出错:`)
|
|
}
|
|
}
|
|
|
|
// 显示基本通知(支持自定义标题与内容)
|
|
const showBasicNotification = (
|
|
title: string = '基本通知',
|
|
body: string = '这是一个使用浏览器原生API的系统通知'
|
|
) => {
|
|
if (!('Notification' in window)) {
|
|
ElMessage({
|
|
message: '浏览器不支持原生Notification API',
|
|
type: 'warning'
|
|
})
|
|
return
|
|
}
|
|
if (Notification.permission !== 'granted') {
|
|
ElMessage({
|
|
message: '请先授予通知权限',
|
|
type: 'warning'
|
|
})
|
|
requestPermission()
|
|
return
|
|
}
|
|
try {
|
|
const iconUrl = appLogo || '/favicon.ico'
|
|
const notification = new Notification(title, {
|
|
body,
|
|
requireInteraction: true,
|
|
icon: iconUrl
|
|
})
|
|
notification.onclick = () => {
|
|
notification.close()
|
|
}
|
|
} catch (error) {}
|
|
}
|
|
onBeforeMount(() => {
|
|
setThemeTransitionClass(true)
|
|
setCompanyFromUrl()
|
|
})
|
|
|
|
// 页面刷新时重置WebSocket重连次数,同时清理事件监听
|
|
onBeforeUnmount(() => {
|
|
import('@/utils/sys/wsClient').then(({ resetWebSocketReconnect }) => {
|
|
resetWebSocketReconnect()
|
|
})
|
|
mittBus.off('ws:message')
|
|
})
|
|
|
|
const handleWsMessageNotification = (data: any) => {
|
|
if (data && data.event === 'notify.receive') {
|
|
const notice = data?.data?.notice_data
|
|
const title = notice?.message?.title || '新通知'
|
|
const rawContent = notice?.message?.content || ''
|
|
const body = typeof rawContent === 'string' ? rawContent.replace(/<[^>]+>/g, '') : ''
|
|
showBasicNotification(title, body)
|
|
}
|
|
}
|
|
|
|
onMounted(() => {
|
|
// 检查存储兼容性
|
|
checkStorageCompatibility()
|
|
checkSupport()
|
|
requestPermission()
|
|
// 提升暗黑主题下页面刷新视觉体验
|
|
setThemeTransitionClass(false)
|
|
// 系统升级
|
|
systemUpgrade()
|
|
// 获取用户信息
|
|
getUserInfo()
|
|
// 初始化 WebSocket
|
|
// showEventNotification()
|
|
if (accessToken.value) {
|
|
import('@/utils/sys/wsClient').then(
|
|
({ initWebSocket, resetWebSocketReconnect, getWebSocketStatus }) => {
|
|
// 页面刷新时重置重连次数
|
|
resetWebSocketReconnect()
|
|
initWebSocket(accessToken.value)
|
|
// 添加调试功能,可以在控制台查看WebSocket状态
|
|
// @ts-ignore
|
|
window.getWebSocketStatus = getWebSocketStatus
|
|
// console.log('WebSocket状态查看: window.getWebSocketStatus()')
|
|
}
|
|
)
|
|
}
|
|
|
|
// 监听ws消息,用于系统级通知
|
|
mittBus.on('ws:message', handleWsMessageNotification)
|
|
})
|
|
|
|
// 登录后,accessToken 变更时立即初始化 WebSocket(无需刷新)
|
|
watch(accessToken, async (token) => {
|
|
if (token) {
|
|
const { initWebSocket, getWebSocketStatus } = await import('@/utils/sys/wsClient')
|
|
const status = getWebSocketStatus?.()
|
|
// 避免重复初始化:已连接或正在连接时不再初始化
|
|
if (
|
|
!status?.readyState ||
|
|
(status.readyState !== WebSocket.OPEN && status.readyState !== WebSocket.CONNECTING)
|
|
) {
|
|
initWebSocket(token)
|
|
}
|
|
} else {
|
|
// 退出登录时,关闭并重置
|
|
const { closeWebSocket, resetWebSocketReconnect } = await import('@/utils/sys/wsClient')
|
|
closeWebSocket()
|
|
resetWebSocketReconnect()
|
|
}
|
|
})
|
|
|
|
// 获取用户信息
|
|
const getUserInfo = async () => {
|
|
if (userStore.isLogin) {
|
|
try {
|
|
const data = await UserService.getUserInfo()
|
|
userStore.setUserInfo(data)
|
|
} catch (error) {
|
|
console.error('获取用户信息失败', error)
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
<style>
|
|
.boxshadow {
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 12px 0 rgba(0, 10, 118, 0.1);
|
|
background: var(--art-main-bg-color);
|
|
padding: 10px 20px;
|
|
margin-bottom: 10px;
|
|
}
|
|
.border {
|
|
width: 6px;
|
|
height: 22px;
|
|
border-radius: 3px;
|
|
background: #3471FF;
|
|
display: inline-block;
|
|
vertical-align: bottom;
|
|
}
|
|
.el-dialog {
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
.el-dialog::before {
|
|
content: '';
|
|
position: absolute;
|
|
inset: 0;
|
|
z-index: 0;
|
|
background: linear-gradient(180deg, #E4ECFF 0%, #FFFFFF 50%);
|
|
pointer-events: none;
|
|
}
|
|
.el-dialog__header,
|
|
.el-dialog__body,
|
|
.el-dialog__footer {
|
|
background: transparent !important;
|
|
position: relative;
|
|
z-index: 1;
|
|
}
|
|
.el-dialog__header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
position: relative;
|
|
padding-right: 40px;
|
|
}
|
|
|
|
.el-dialog__title {
|
|
flex: 1;
|
|
text-align: center;
|
|
font-size: 18px;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.el-dialog__headerbtn {
|
|
position: absolute;
|
|
right: 16px;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
}
|
|
</style>
|