更新
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
<script setup>
|
||||
import { onMounted, computed, watch, nextTick } from 'vue'
|
||||
import { onMounted, onUnmounted, computed, watch, nextTick } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useI18nStore } from './stores/modules/i18n'
|
||||
import { useLayoutStore } from './stores/modules/layout'
|
||||
import { useUserStore } from './stores/modules/user'
|
||||
import { useWebSocket } from './composables/useWebSocket'
|
||||
import { theme } from 'ant-design-vue'
|
||||
import i18n from './i18n'
|
||||
import zhCN from 'ant-design-vue/es/locale/zh_CN'
|
||||
@@ -22,6 +24,12 @@ const i18nStore = useI18nStore()
|
||||
// layout store
|
||||
const layoutStore = useLayoutStore()
|
||||
|
||||
// user store
|
||||
const userStore = useUserStore()
|
||||
|
||||
// WebSocket
|
||||
const { initWebSocket, closeWebSocket } = useWebSocket()
|
||||
|
||||
// 解构 themeColor 以确保响应式
|
||||
const { themeColor } = storeToRefs(layoutStore)
|
||||
|
||||
@@ -82,6 +90,16 @@ onMounted(async () => {
|
||||
if (layoutStore.themeColor) {
|
||||
document.documentElement.style.setProperty('--primary-color', layoutStore.themeColor)
|
||||
}
|
||||
|
||||
// 初始化 WebSocket 连接
|
||||
if (userStore.isLoggedIn()) {
|
||||
initWebSocket()
|
||||
}
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
// 关闭 WebSocket 连接
|
||||
closeWebSocket()
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
146
resources/admin/src/composables/useWebSocket.js
Normal file
146
resources/admin/src/composables/useWebSocket.js
Normal file
@@ -0,0 +1,146 @@
|
||||
import { ref } from 'vue'
|
||||
import { getWebSocket } from '@/utils/websocket'
|
||||
import { useUserStore } from '@/stores/modules/user'
|
||||
import { useDictionaryStore } from '@/stores/modules/dictionary'
|
||||
import { message } from 'ant-design-vue'
|
||||
import config from '@/config'
|
||||
|
||||
/**
|
||||
* WebSocket Composable
|
||||
*
|
||||
* 处理 WebSocket 连接和消息监听
|
||||
*/
|
||||
export function useWebSocket() {
|
||||
const ws = ref(null)
|
||||
const userStore = useUserStore()
|
||||
const dictionaryStore = useDictionaryStore()
|
||||
|
||||
/**
|
||||
* 初始化 WebSocket 连接
|
||||
*/
|
||||
function initWebSocket() {
|
||||
if (!userStore.token) {
|
||||
console.warn('未登录,无法初始化 WebSocket')
|
||||
return
|
||||
}
|
||||
|
||||
if (!userStore.userInfo || !userStore.userInfo.id) {
|
||||
console.warn('用户信息不完整,无法初始化 WebSocket')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
// 使用配置文件中的 WS_URL
|
||||
ws.value = getWebSocket(userStore.userInfo.id, userStore.token, {
|
||||
wsUrl: config.WS_URL,
|
||||
onOpen: handleOpen,
|
||||
onMessage: handleMessage,
|
||||
onError: handleError,
|
||||
onClose: handleClose
|
||||
})
|
||||
|
||||
// 注册消息处理器
|
||||
ws.value.on('dictionary_update', handleDictionaryUpdate)
|
||||
ws.value.on('dictionary_item_update', handleDictionaryItemUpdate)
|
||||
|
||||
// 连接
|
||||
ws.value.connect()
|
||||
} catch (error) {
|
||||
console.error('初始化 WebSocket 失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理连接打开
|
||||
*/
|
||||
function handleOpen(event) {
|
||||
console.log('WebSocket 连接已建立', event)
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理接收消息
|
||||
*/
|
||||
function handleMessage(message, event) {
|
||||
console.log('收到 WebSocket 消息:', message)
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理错误
|
||||
*/
|
||||
function handleError(error) {
|
||||
console.error('WebSocket 错误:', error)
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理连接关闭
|
||||
*/
|
||||
function handleClose(event) {
|
||||
console.log('WebSocket 连接已关闭', event)
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理字典分类更新
|
||||
*/
|
||||
async function handleDictionaryUpdate(data) {
|
||||
console.log('字典分类已更新:', data)
|
||||
|
||||
const { action, resource_type, timestamp } = data
|
||||
|
||||
if (resource_type !== 'dictionary') {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
// 刷新字典缓存
|
||||
await dictionaryStore.refresh(true)
|
||||
|
||||
// 显示通知
|
||||
message.success('字典数据已更新')
|
||||
} catch (error) {
|
||||
console.error('刷新字典缓存失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理字典项更新
|
||||
*/
|
||||
async function handleDictionaryItemUpdate(data) {
|
||||
console.log('字典项已更新:', data)
|
||||
|
||||
const { action, resource_type, timestamp } = data
|
||||
|
||||
if (resource_type !== 'dictionary_item') {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
// 刷新字典缓存
|
||||
await dictionaryStore.refresh(true)
|
||||
|
||||
// 显示通知
|
||||
message.success('字典数据已更新')
|
||||
} catch (error) {
|
||||
console.error('刷新字典缓存失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭 WebSocket 连接
|
||||
*/
|
||||
function closeWebSocket() {
|
||||
if (ws.value) {
|
||||
// 取消注册消息处理器
|
||||
ws.value.off('dictionary_update')
|
||||
ws.value.off('dictionary_item_update')
|
||||
|
||||
ws.value.disconnect()
|
||||
ws.value = null
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
ws,
|
||||
initWebSocket,
|
||||
closeWebSocket
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ const defaultConfig = {
|
||||
|
||||
//接口地址
|
||||
API_URL: 'http://127.0.0.1:8000/admin/',
|
||||
WS_URL: '127.0.0.1:8000',
|
||||
|
||||
//请求超时
|
||||
TIMEOUT: 50000,
|
||||
|
||||
@@ -12,6 +12,17 @@
|
||||
<div class="form-tip">系统唯一标识,只能包含字母、数字、下划线,且必须以字母开头</div>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 值类型 -->
|
||||
<a-form-item label="值类型" name="value_type" required>
|
||||
<a-select v-model:value="form.value_type" placeholder="请选择值类型" allow-clear>
|
||||
<a-select-option value="string">字符串</a-select-option>
|
||||
<a-select-option value="number">数字</a-select-option>
|
||||
<a-select-option value="boolean">布尔值</a-select-option>
|
||||
<a-select-option value="json">JSON</a-select-option>
|
||||
</a-select>
|
||||
<div class="form-tip">指定字典项值的类型,系统会根据类型自动格式化返回数据</div>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 排序 -->
|
||||
<a-form-item label="排序" name="sort">
|
||||
<a-input-number v-model:value="form.sort" :min="0" :max="10000" style="width: 100%" />
|
||||
@@ -79,6 +90,7 @@ const form = ref({
|
||||
id: '',
|
||||
name: '',
|
||||
code: '',
|
||||
value_type: 'string',
|
||||
description: '',
|
||||
status: null,
|
||||
sort: 0
|
||||
@@ -114,6 +126,9 @@ const rules = {
|
||||
trigger: 'blur'
|
||||
},
|
||||
{ validator: validateCodeUnique, trigger: 'blur' }
|
||||
],
|
||||
value_type: [
|
||||
{ required: true, message: '请选择值类型', trigger: 'change' }
|
||||
]
|
||||
}
|
||||
|
||||
@@ -123,6 +138,7 @@ const resetForm = () => {
|
||||
id: '',
|
||||
name: '',
|
||||
code: '',
|
||||
value_type: 'string',
|
||||
description: '',
|
||||
status: null,
|
||||
sort: 0
|
||||
@@ -137,6 +153,7 @@ const setData = (data) => {
|
||||
id: data.id || '',
|
||||
name: data.name || '',
|
||||
code: data.code || '',
|
||||
value_type: data.value_type || 'string',
|
||||
description: data.description || '',
|
||||
status: data.status !== undefined ? data.status : null,
|
||||
sort: data.sort !== undefined ? data.sort : 0
|
||||
@@ -155,6 +172,7 @@ const handleSubmit = async () => {
|
||||
const submitData = {
|
||||
name: form.value.name,
|
||||
code: form.value.code,
|
||||
value_type: form.value.value_type,
|
||||
description: form.value.description,
|
||||
status: form.value.status,
|
||||
sort: form.value.sort
|
||||
|
||||
@@ -229,7 +229,9 @@ class WebSocketClient {
|
||||
*/
|
||||
export function createWebSocket(userId, token, options = {}) {
|
||||
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
|
||||
const host = window.location.host
|
||||
|
||||
// 优先使用配置的 WS_URL,否则使用当前域名
|
||||
const host = options.wsUrl || window.location.host
|
||||
const url = `${protocol}//${host}/ws?user_id=${userId}&token=${token}`
|
||||
|
||||
return new WebSocketClient(url, options)
|
||||
|
||||
Reference in New Issue
Block a user