From d136266acd768591c03b93788259c428702a762e Mon Sep 17 00:00:00 2001 From: "Ray.Hao" <1490493387@qq.com> Date: Tue, 1 Sep 2026 07:22:19 +0800 Subject: [PATCH] =?UTF-8?q?refactor(sse):=20=E9=87=8D=E6=9E=84=20SSE=20?= =?UTF-8?q?=E5=88=86=E5=B1=82=E5=B9=B6=E5=90=8C=E6=AD=A5=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E9=80=9A=E7=9F=A5=E4=B8=AD=E5=BF=83=E4=B8=8E=E7=A4=BA=E4=BE=8B?= =?UTF-8?q?=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - src/composables/sse: 删除,连接实现下沉到 utils/sse,事件名枚举迁到 enums/sse - src/utils/sse: 新增 SSE 连接与事件订阅实现 - src/stores/dict: 改用 utils/sse 订阅字典变更 - src/stores/user: 登出清理改用 utils/sse 的 cleanupSse - src/views/dashboard: 在线用户订阅下沉为页面级 composable - src/components/NoticeCenter: 由 NoticeDropdown 改名 - src/views/demo: 示例页面按 component/route/table 归类 - src/router: 同步示例详情页路由路径 --- .../index.vue | 0 .../useNotice.ts | 3 +- src/composables/index.ts | 5 - src/composables/sse/index.ts | 37 ---- src/composables/sse/sseTopics.ts | 17 -- src/composables/sse/useDictSync.ts | 88 -------- src/composables/sse/useOnlineUsers.ts | 50 ----- src/enums/index.ts | 1 + src/enums/sse.ts | 24 +++ src/router/index.ts | 2 +- src/stores/dict.ts | 70 +++++++ src/stores/user.ts | 47 ++++- .../sse/useSse.ts => utils/sse.ts} | 0 .../dashboard/composables/useOnlineUsers.ts | 37 ++++ src/views/dashboard/index.vue | 2 +- src/views/demo/{ => component}/dict-sync.vue | 16 +- src/views/demo/{ => component}/dictionary.vue | 2 +- src/views/demo/{ => component}/drag.vue | 0 .../demo/{ => component}/icon-select.vue | 9 +- src/views/demo/{ => component}/icons.vue | 0 .../table-select/config/select.ts | 0 .../{ => component}/table-select/index.vue | 2 +- .../demo/{ => component}/text-scroll.vue | 2 + src/views/demo/{ => component}/upload.vue | 2 +- .../demo/{ => component}/wang-editor.vue | 4 +- src/views/demo/icon-selector.vue | 21 -- src/views/demo/{ => route}/detail.vue | 0 .../multi-level/components/LevelOnePanel.vue | 0 .../multi-level/components/LevelTwoPanel.vue | 0 .../multi-level/components/ToDetail.ts | 0 .../level-two/level-three-a/index.vue | 0 .../level-two/level-three-b/index.vue | 0 src/views/demo/{ => route}/route-param.vue | 0 src/views/demo/signature.vue | 188 ------------------ .../{ => table}/auto-operation-column.vue | 4 +- src/views/demo/{ => table}/curd-single.vue | 2 +- src/views/demo/{ => table}/curd/config/add.ts | 0 .../demo/{ => table}/curd/config/content.ts | 0 .../demo/{ => table}/curd/config/edit.ts | 0 .../demo/{ => table}/curd/config/options.ts | 0 .../demo/{ => table}/curd/config/search.ts | 0 .../demo/{ => table}/curd/config2/add.ts | 0 .../demo/{ => table}/curd/config2/content.ts | 0 .../demo/{ => table}/curd/config2/edit.ts | 0 .../demo/{ => table}/curd/config2/search.ts | 0 src/views/demo/{ => table}/curd/index.vue | 2 +- .../demo/{ => table}/vxe-table/index.vue | 0 47 files changed, 207 insertions(+), 430 deletions(-) rename src/components/{NoticeDropdown => NoticeCenter}/index.vue (100%) rename src/components/{NoticeDropdown => NoticeCenter}/useNotice.ts (98%) delete mode 100644 src/composables/sse/index.ts delete mode 100644 src/composables/sse/sseTopics.ts delete mode 100644 src/composables/sse/useDictSync.ts delete mode 100644 src/composables/sse/useOnlineUsers.ts create mode 100644 src/enums/sse.ts rename src/{composables/sse/useSse.ts => utils/sse.ts} (100%) create mode 100644 src/views/dashboard/composables/useOnlineUsers.ts rename src/views/demo/{ => component}/dict-sync.vue (95%) rename src/views/demo/{ => component}/dictionary.vue (97%) rename src/views/demo/{ => component}/drag.vue (100%) rename src/views/demo/{ => component}/icon-select.vue (52%) rename src/views/demo/{ => component}/icons.vue (100%) rename src/views/demo/{ => component}/table-select/config/select.ts (100%) rename src/views/demo/{ => component}/table-select/index.vue (96%) rename src/views/demo/{ => component}/text-scroll.vue (80%) rename src/views/demo/{ => component}/upload.vue (99%) rename src/views/demo/{ => component}/wang-editor.vue (69%) delete mode 100644 src/views/demo/icon-selector.vue rename src/views/demo/{ => route}/detail.vue (100%) rename src/views/demo/{ => route}/multi-level/components/LevelOnePanel.vue (100%) rename src/views/demo/{ => route}/multi-level/components/LevelTwoPanel.vue (100%) rename src/views/demo/{ => route}/multi-level/components/ToDetail.ts (100%) rename src/views/demo/{ => route}/multi-level/level-one/level-two/level-three-a/index.vue (100%) rename src/views/demo/{ => route}/multi-level/level-one/level-two/level-three-b/index.vue (100%) rename src/views/demo/{ => route}/route-param.vue (100%) delete mode 100644 src/views/demo/signature.vue rename src/views/demo/{ => table}/auto-operation-column.vue (96%) rename src/views/demo/{ => table}/curd-single.vue (99%) rename src/views/demo/{ => table}/curd/config/add.ts (100%) rename src/views/demo/{ => table}/curd/config/content.ts (100%) rename src/views/demo/{ => table}/curd/config/edit.ts (100%) rename src/views/demo/{ => table}/curd/config/options.ts (100%) rename src/views/demo/{ => table}/curd/config/search.ts (100%) rename src/views/demo/{ => table}/curd/config2/add.ts (100%) rename src/views/demo/{ => table}/curd/config2/content.ts (100%) rename src/views/demo/{ => table}/curd/config2/edit.ts (100%) rename src/views/demo/{ => table}/curd/config2/search.ts (100%) rename src/views/demo/{ => table}/curd/index.vue (99%) rename src/views/demo/{ => table}/vxe-table/index.vue (100%) diff --git a/src/components/NoticeDropdown/index.vue b/src/components/NoticeCenter/index.vue similarity index 100% rename from src/components/NoticeDropdown/index.vue rename to src/components/NoticeCenter/index.vue diff --git a/src/components/NoticeDropdown/useNotice.ts b/src/components/NoticeCenter/useNotice.ts similarity index 98% rename from src/components/NoticeDropdown/useNotice.ts rename to src/components/NoticeCenter/useNotice.ts index 6ffd374c..68130b4d 100644 --- a/src/components/NoticeDropdown/useNotice.ts +++ b/src/components/NoticeCenter/useNotice.ts @@ -1,7 +1,8 @@ import { computed, onBeforeUnmount, onMounted, ref } from "vue"; import type { NoticeDetail, NoticeItem, NoticeQueryParams } from "@/api/system/notice"; import NoticeAPI from "@/api/system/notice"; -import { useSse, SseTopics } from "@/composables"; +import { useSse } from "@/utils/sse"; +import { SseTopics } from "@/enums/sse"; import router from "@/router"; /** 下拉面板每页展示条数 */ diff --git a/src/composables/index.ts b/src/composables/index.ts index 297c1697..8a637acc 100644 --- a/src/composables/index.ts +++ b/src/composables/index.ts @@ -1,8 +1,3 @@ -// SSE 服务 -export { setupSse, cleanupSseServices } from "./sse"; -export { useSse, useDictSync, useOnlineUsers, cleanupSse, SseConnectionState, SseTopics } from "./sse"; -export type { DictChangeMessage, DictChangeCallback, SseTopic } from "./sse"; - // 表格相关 export { useTableSelection } from "./useTableSelection"; export { usePageTable } from "./usePageTable"; diff --git a/src/composables/sse/index.ts b/src/composables/sse/index.ts deleted file mode 100644 index d2b130cb..00000000 --- a/src/composables/sse/index.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { useDictSync } from "./useDictSync"; -import { useOnlineUsers } from "./useOnlineUsers"; -import { useSse, cleanupSse } from "./useSse"; - -/** - * 初始化所有 SSE 服务 - */ -export function setupSse() { - const sse = useSse(); - sse.connect(); - - const dictSync = useDictSync(); - dictSync.initialize(); - - const onlineUsers = useOnlineUsers(); - onlineUsers.initialize(); -} - -/** - * 清理所有 SSE 连接 - */ -export function cleanupSseServices() { - const dictSync = useDictSync(); - dictSync.cleanup(); - - const onlineUsers = useOnlineUsers(); - onlineUsers.cleanup(); - - cleanupSse(); -} - -export { useDictSync } from "./useDictSync"; -export { useOnlineUsers } from "./useOnlineUsers"; -export { useSse, cleanupSse, SseConnectionState } from "./useSse"; -export { SseTopics } from "./sseTopics"; -export type { DictChangeMessage, DictChangeCallback } from "./useDictSync"; -export type { SseTopic } from "./sseTopics"; diff --git a/src/composables/sse/sseTopics.ts b/src/composables/sse/sseTopics.ts deleted file mode 100644 index aec8ad1e..00000000 --- a/src/composables/sse/sseTopics.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** SSE 事件名常量,与后端 SseTopics.java 一一对应 */ -export const SseTopics = { - /** 字典变更事件 */ - DICT: "dict", - /** 在线用户数事件 */ - ONLINE_USERS: "online-users", - /** 系统消息事件 */ - SYSTEM: "system", - /** 心跳事件 */ - PING: "ping", - /** 通知事件 */ - NOTICE: "notice", - /** 通知撤回事件 */ - NOTICE_REVOKE: "notice-revoke", -} as const; - -export type SseTopic = (typeof SseTopics)[keyof typeof SseTopics]; diff --git a/src/composables/sse/useDictSync.ts b/src/composables/sse/useDictSync.ts deleted file mode 100644 index cc59185d..00000000 --- a/src/composables/sse/useDictSync.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { useDictStoreHook } from "@/stores/dict"; -import { useSse } from "./useSse"; -import { SseTopics } from "./sseTopics"; - -/** 字典变更消息体 */ -export interface DictChangeMessage { - /** 字典编码 */ - dictCode: string; -} - -/** 字典变更回调函数类型 */ -export type DictChangeCallback = (message: DictChangeMessage) => void; - -let globalInstance: ReturnType | null = null; - -function createDictSyncComposable() { - const dictStore = useDictStoreHook(); - const sse = useSse(); - - const callbacks: DictChangeCallback[] = []; - let unsubscribe: (() => void) | null = null; - let initialized = false; // 防止重复初始化导致重复订阅 - - // 处理字典变更消息:清除指定字典缓存,并通知所有已注册回调 - const handleDictChange = (data: DictChangeMessage) => { - const { dictCode } = data; - if (!dictCode) { - console.warn("[DictSync] 收到无效的字典变更消息:缺少 dictCode"); - return; - } - - dictStore.removeDictItem(dictCode); - callbacks.forEach((cb) => { - try { - cb(data); - } catch (err) { - console.error("[DictSync] 回调执行失败:", err); - } - }); - }; - - // 订阅 SSE 字典变更事件(幂等:重复调用不会产生重复订阅) - const initialize = () => { - if (initialized) return; - initialized = true; - unsubscribe = sse.on(SseTopics.DICT, handleDictChange); - }; - - // 取消 SSE 订阅并清空所有回调 - const cleanup = () => { - initialized = false; - unsubscribe?.(); - unsubscribe = null; - callbacks.length = 0; - }; - - // 注册字典变更回调,返回取消注册函数 - const onDictChange = (cb: DictChangeCallback) => { - callbacks.push(cb); - return () => { - const idx = callbacks.indexOf(cb); - if (idx !== -1) callbacks.splice(idx, 1); - }; - }; - - return { - isConnected: sse.isConnected, - connectionState: sse.connectionState, - initialize, - cleanup, - onDictChange, - }; -} - -/** - * 字典同步组合式函数(单例模式) - * - * 监听 SSE 字典变更事件,收到变更时自动清除对应字典缓存, - * 并通知所有已注册的回调函数。 - * - * @returns 字典同步实例,包含连接状态、初始化、清理和回调注册方法 - */ -export function useDictSync() { - if (!globalInstance) { - globalInstance = createDictSyncComposable(); - } - return globalInstance; -} diff --git a/src/composables/sse/useOnlineUsers.ts b/src/composables/sse/useOnlineUsers.ts deleted file mode 100644 index 9901467a..00000000 --- a/src/composables/sse/useOnlineUsers.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { ref, readonly } from "vue"; -import { useSse } from "./useSse"; -import { SseTopics } from "./sseTopics"; - -let globalInstance: ReturnType | null = null; - -function createOnlineUsersComposable() { - const onlineUserCount = ref(0); - const lastUpdateTime = ref(0); - - const sse = useSse(); - - let unsubscribe: (() => void) | null = null; - - const handleOnlineUsersMessage = (count: number) => { - if (!Number.isFinite(count) || count < 0) return; - onlineUserCount.value = count; - lastUpdateTime.value = Date.now(); - }; - - const initialize = () => { - unsubscribe = sse.on(SseTopics.ONLINE_USERS, handleOnlineUsersMessage); - }; - - const cleanup = () => { - if (unsubscribe) { - unsubscribe(); - unsubscribe = null; - } - onlineUserCount.value = 0; - lastUpdateTime.value = 0; - }; - - return { - onlineUserCount: readonly(onlineUserCount), - lastUpdateTime: readonly(lastUpdateTime), - isConnected: sse.isConnected, - connectionState: sse.connectionState, - initialize, - cleanup, - }; -} - -/** 在线用户数组合式函数(单例模式) */ -export function useOnlineUsers() { - if (!globalInstance) { - globalInstance = createOnlineUsersComposable(); - } - return globalInstance; -} diff --git a/src/enums/index.ts b/src/enums/index.ts index bc41a3f0..1f8afa1d 100644 --- a/src/enums/index.ts +++ b/src/enums/index.ts @@ -10,3 +10,4 @@ export * from "./business"; export * from "./codegen"; export * from "./common"; export * from "./settings"; +export * from "./sse"; diff --git a/src/enums/sse.ts b/src/enums/sse.ts new file mode 100644 index 00000000..8728b5c1 --- /dev/null +++ b/src/enums/sse.ts @@ -0,0 +1,24 @@ +/** + * SSE 相关枚举 + * + * @description + * SSE 事件名枚举,与后端 SseTopics.java 一一对应 + */ + +/** + * SSE 事件名枚举 + */ +export const enum SseTopics { + /** 字典变更事件 */ + DICT = "dict", + /** 在线用户数事件 */ + ONLINE_USERS = "online-users", + /** 系统消息事件 */ + SYSTEM = "system", + /** 心跳事件 */ + PING = "ping", + /** 通知事件 */ + NOTICE = "notice", + /** 通知撤回事件 */ + NOTICE_REVOKE = "notice-revoke", +} diff --git a/src/router/index.ts b/src/router/index.ts index beec72b6..cf097a1e 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -75,7 +75,7 @@ export const constantRoutes: RouteRecordRaw[] = [ { path: "/detail/:id(\\d+)", name: "DemoDetail", - component: () => import("@/views/demo/detail.vue"), + component: () => import("@/views/demo/route/detail.vue"), meta: { title: "详情页缓存", icon: "user", hidden: true, keepAlive: true }, }, ], diff --git a/src/stores/dict.ts b/src/stores/dict.ts index 5a63c6e0..20b38c07 100644 --- a/src/stores/dict.ts +++ b/src/stores/dict.ts @@ -2,6 +2,17 @@ import { store } from "@/stores"; import DictAPI from "@/api/system/dict"; import type { DictItemOption } from "@/api/system/dict"; import { STORAGE_KEYS } from "@/constants"; +import { useSse } from "@/utils/sse"; +import { SseTopics } from "@/enums/sse"; + +/** 字典变更消息体 */ +export interface DictChangeMessage { + /** 字典编码 */ + dictCode: string; +} + +/** 字典变更回调函数类型 */ +export type DictChangeCallback = (message: DictChangeMessage) => void; export const useDictStore = defineStore("dict", () => { // 字典数据缓存 @@ -67,11 +78,70 @@ export const useDictStore = defineStore("dict", () => { dictCache.value = {}; }; + // ---------- SSE 字典同步 ---------- + + // 字典变更回调列表(供页面在缓存失效时执行自定义逻辑) + const dictChangeCallbacks: DictChangeCallback[] = []; + let unsubscribeDictChange: (() => void) | null = null; + + /** + * 处理字典变更消息:清除指定字典缓存,并通知所有已注册回调 + * @param message SSE 推送的字典变更消息 + */ + const handleDictChange = (message: DictChangeMessage) => { + const { dictCode } = message; + if (!dictCode) { + console.warn("[DictStore] 收到无效的字典变更消息:缺少 dictCode"); + return; + } + + removeDictItem(dictCode); + dictChangeCallbacks.forEach((cb) => { + try { + cb(message); + } catch (err) { + console.error("[DictStore] 字典变更回调执行失败:", err); + } + }); + }; + + /** + * 订阅 SSE 字典变更事件(幂等:重复调用不会产生重复订阅) + */ + const setupDictSync = () => { + if (unsubscribeDictChange) return; + unsubscribeDictChange = useSse().on(SseTopics.DICT, handleDictChange); + }; + + /** + * 取消 SSE 字典订阅并清空所有回调 + */ + const teardownDictSync = () => { + unsubscribeDictChange?.(); + unsubscribeDictChange = null; + dictChangeCallbacks.length = 0; + }; + + /** + * 注册字典变更回调,返回取消注册函数 + * @param cb 字典变更回调 + */ + const onDictChange = (cb: DictChangeCallback) => { + dictChangeCallbacks.push(cb); + return () => { + const idx = dictChangeCallbacks.indexOf(cb); + if (idx !== -1) dictChangeCallbacks.splice(idx, 1); + }; + }; + return { loadDictItems, getDictItems, removeDictItem, clearDictCache, + setupDictSync, + teardownDictSync, + onDictChange, }; }); diff --git a/src/stores/user.ts b/src/stores/user.ts index 6629a595..d2f1a504 100644 --- a/src/stores/user.ts +++ b/src/stores/user.ts @@ -9,7 +9,11 @@ import { AuthStorage } from "@/utils/auth"; import { usePermissionStoreHook } from "@/stores/permission"; import { useDictStoreHook } from "@/stores/dict"; import { useTagsViewStore } from "@/stores"; -import { cleanupSseServices } from "@/composables"; +import { cleanupSse } from "@/utils/sse"; +import router from "@/router"; + +// 防止并发会话失效触发重复跳转登录页 +let redirectingToLogin = false; export const useUserStore = defineStore("user", () => { // 用户信息 @@ -83,10 +87,11 @@ export const useUserStore = defineStore("user", () => { // 2. 重置其他模块状态 usePermissionStoreHook().resetRouter(); useDictStoreHook().clearDictCache(); + useDictStoreHook().teardownDictSync(); useTagsViewStore().delAllViews(); // 3. 清理 SSE 连接 - cleanupSseServices(); + cleanupSse(); } /** @@ -99,6 +104,43 @@ export const useUserStore = defineStore("user", () => { userInfo.value = {} as UserInfo; } + /** + * 会话失效的统一出口:通知用户、清理全局状态、携带当前路由跳转登录页 + * + * @param message 通知文案 + * @param notify 是否弹出通知 + */ + async function redirectToLogin( + message: string = "请重新登录", + notify: boolean = true + ): Promise { + if (redirectingToLogin) return; + redirectingToLogin = true; + + try { + if (notify) { + ElNotification({ + title: "提示", + message, + type: "warning", + duration: 3000, + }); + } + + await resetAllState(); + + // 跳转到登录页,保留当前路由用于登录后跳转 + const currentPath = router.currentRoute.value.fullPath; + await router.push(`/login?redirect=${encodeURIComponent(currentPath)}`); + } catch (error) { + console.error("Redirect to login error:", error); + // 强制跳转,即使路由重定向失败 + window.location.href = "/login"; + } finally { + redirectingToLogin = false; + } + } + /** * 刷新 token */ @@ -124,6 +166,7 @@ export const useUserStore = defineStore("user", () => { getUserInfo, resetAllState, resetUserState, + redirectToLogin, refreshToken: doRefreshToken, refreshTokenOnce, }; diff --git a/src/composables/sse/useSse.ts b/src/utils/sse.ts similarity index 100% rename from src/composables/sse/useSse.ts rename to src/utils/sse.ts diff --git a/src/views/dashboard/composables/useOnlineUsers.ts b/src/views/dashboard/composables/useOnlineUsers.ts new file mode 100644 index 00000000..2bc14226 --- /dev/null +++ b/src/views/dashboard/composables/useOnlineUsers.ts @@ -0,0 +1,37 @@ +import { onMounted, onUnmounted, readonly, ref } from "vue"; +import { useSse } from "@/utils/sse"; +import { SseTopics } from "@/enums/sse"; + +/** + * 在线用户数组合式函数(页面级) + * + * 订阅 SSE 在线用户数事件,组件挂载时订阅、卸载时自动取消; + * 进入页面后需等待下一次推送才有数据。 + */ +export function useOnlineUsers() { + const onlineUserCount = ref(0); + + const { isConnected, on } = useSse(); + + let unsubscribe: (() => void) | null = null; + + const handleOnlineUsersMessage = (count: number) => { + if (!Number.isFinite(count) || count < 0) return; + onlineUserCount.value = count; + }; + + onMounted(() => { + unsubscribe = on(SseTopics.ONLINE_USERS, handleOnlineUsersMessage); + }); + + onUnmounted(() => { + unsubscribe?.(); + unsubscribe = null; + onlineUserCount.value = 0; + }); + + return { + onlineUserCount: readonly(onlineUserCount), + isConnected, + }; +} diff --git a/src/views/dashboard/index.vue b/src/views/dashboard/index.vue index a40694be..227bfed6 100644 --- a/src/views/dashboard/index.vue +++ b/src/views/dashboard/index.vue @@ -261,7 +261,7 @@ import { Document, VideoPlay, } from "@element-plus/icons-vue"; -import { useOnlineUsers } from "@/composables"; +import { useOnlineUsers } from "./composables/useOnlineUsers"; const userStore = useUserStore(); const settingsStore = useSettingsStore(); diff --git a/src/views/demo/dict-sync.vue b/src/views/demo/component/dict-sync.vue similarity index 95% rename from src/views/demo/dict-sync.vue rename to src/views/demo/component/dict-sync.vue index 323b3ba2..15a3c59a 100644 --- a/src/views/demo/dict-sync.vue +++ b/src/views/demo/component/dict-sync.vue @@ -141,11 +141,11 @@ diff --git a/src/views/demo/upload.vue b/src/views/demo/component/upload.vue similarity index 99% rename from src/views/demo/upload.vue rename to src/views/demo/component/upload.vue index 5828eefd..5f9c58e7 100644 --- a/src/views/demo/upload.vue +++ b/src/views/demo/component/upload.vue @@ -13,7 +13,7 @@
diff --git a/src/views/demo/detail.vue b/src/views/demo/route/detail.vue similarity index 100% rename from src/views/demo/detail.vue rename to src/views/demo/route/detail.vue diff --git a/src/views/demo/multi-level/components/LevelOnePanel.vue b/src/views/demo/route/multi-level/components/LevelOnePanel.vue similarity index 100% rename from src/views/demo/multi-level/components/LevelOnePanel.vue rename to src/views/demo/route/multi-level/components/LevelOnePanel.vue diff --git a/src/views/demo/multi-level/components/LevelTwoPanel.vue b/src/views/demo/route/multi-level/components/LevelTwoPanel.vue similarity index 100% rename from src/views/demo/multi-level/components/LevelTwoPanel.vue rename to src/views/demo/route/multi-level/components/LevelTwoPanel.vue diff --git a/src/views/demo/multi-level/components/ToDetail.ts b/src/views/demo/route/multi-level/components/ToDetail.ts similarity index 100% rename from src/views/demo/multi-level/components/ToDetail.ts rename to src/views/demo/route/multi-level/components/ToDetail.ts diff --git a/src/views/demo/multi-level/level-one/level-two/level-three-a/index.vue b/src/views/demo/route/multi-level/level-one/level-two/level-three-a/index.vue similarity index 100% rename from src/views/demo/multi-level/level-one/level-two/level-three-a/index.vue rename to src/views/demo/route/multi-level/level-one/level-two/level-three-a/index.vue diff --git a/src/views/demo/multi-level/level-one/level-two/level-three-b/index.vue b/src/views/demo/route/multi-level/level-one/level-two/level-three-b/index.vue similarity index 100% rename from src/views/demo/multi-level/level-one/level-two/level-three-b/index.vue rename to src/views/demo/route/multi-level/level-one/level-two/level-three-b/index.vue diff --git a/src/views/demo/route-param.vue b/src/views/demo/route/route-param.vue similarity index 100% rename from src/views/demo/route-param.vue rename to src/views/demo/route/route-param.vue diff --git a/src/views/demo/signature.vue b/src/views/demo/signature.vue deleted file mode 100644 index 7897b6fc..00000000 --- a/src/views/demo/signature.vue +++ /dev/null @@ -1,188 +0,0 @@ - - - diff --git a/src/views/demo/auto-operation-column.vue b/src/views/demo/table/auto-operation-column.vue similarity index 96% rename from src/views/demo/auto-operation-column.vue rename to src/views/demo/table/auto-operation-column.vue index 99158041..3575be28 100644 --- a/src/views/demo/auto-operation-column.vue +++ b/src/views/demo/table/auto-operation-column.vue @@ -2,7 +2,7 @@