diff --git a/.env.development b/.env.development index 52553ff9b0f7ba5be7d1b4954fe58fdc127e6a1a..05d67782d62fb6104cbf15025f633a036a5de8be 100644 --- a/.env.development +++ b/.env.development @@ -28,5 +28,5 @@ VITE_APP_RSA_PRIVATE_KEY = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3C # 客户端id VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e' -# websocket 开关 -VITE_APP_WEBSOCKET = true +# websocket 开关 默认使用sse推送 +VITE_APP_WEBSOCKET = false diff --git a/.env.production b/.env.production index bf9e644407f1d025f6d23f32ecf5678d7aaee8ad..c6b1f8539f2ba232ace93657d1be69d6df674871 100644 --- a/.env.production +++ b/.env.production @@ -31,5 +31,5 @@ VITE_APP_RSA_PRIVATE_KEY = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3C # 客户端id VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e' -# websocket 开关 -VITE_APP_WEBSOCKET = true +# websocket 开关 默认使用sse推送 +VITE_APP_WEBSOCKET = false diff --git a/package.json b/package.json index f1c8084557d0138cf978a077901197a8118f1208..48b15717141e2dae432e886c492fc0f29f1e9053 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ruoyi-vue-plus", - "version": "5.2.1", + "version": "5.2.2", "description": "RuoYi-Vue-Plus多租户管理系统", "author": "LionLi", "license": "MIT", @@ -30,7 +30,7 @@ "diagram-js": "12.3.0", "didi": "9.0.2", "echarts": "5.5.0", - "element-plus": "2.7.5", + "element-plus": "2.7.8", "file-saver": "2.0.5", "fuse.js": "7.0.0", "highlight.js": "11.9.0", @@ -40,7 +40,7 @@ "nprogress": "0.2.0", "pinia": "2.1.7", "screenfull": "6.0.2", - "vue": "3.4.25", + "vue": "3.4.34", "vue-cropper": "1.1.1", "vue-i18n": "9.10.2", "vue-router": "4.3.2", @@ -81,7 +81,7 @@ "unplugin-icons": "0.18.5", "unplugin-vue-components": "0.26.0", "unplugin-vue-setup-extend-plus": "1.0.1", - "vite": "5.2.10", + "vite": "5.2.12", "vite-plugin-compression": "0.5.1", "vite-plugin-svg-icons": "2.0.1", "vitest": "1.5.0", diff --git a/src/api/login.ts b/src/api/login.ts index b6955debe2b3e26f0eb58b9fc1c2207216676244..c7c291e58f20ed2ffbc35a67ea53d2d26114ffea 100644 --- a/src/api/login.ts +++ b/src/api/login.ts @@ -51,6 +51,10 @@ export function register(data: any) { * 注销 */ export function logout() { + request({ + url: '/resource/sse/close', + method: 'get' + }); return request({ url: '/auth/logout', method: 'post' diff --git a/src/api/workflow/nodeConfig/index.ts b/src/api/workflow/nodeConfig/index.ts deleted file mode 100644 index 3270c17e55398cfe314506301a226479aeafb430..0000000000000000000000000000000000000000 --- a/src/api/workflow/nodeConfig/index.ts +++ /dev/null @@ -1,63 +0,0 @@ -import request from '@/utils/request'; -import { AxiosPromise } from 'axios'; -import { NodeConfigVO, NodeConfigForm, NodeConfigQuery } from '@/api/workflow/nodeConfig/types'; - -/** - * 查询节点配置列表 - * @param query - * @returns {*} - */ - -export const listNodeConfig = (query?: NodeConfigQuery): AxiosPromise => { - return request({ - url: '/workflow/nodeConfig/list', - method: 'get', - params: query - }); -}; - -/** - * 查询节点配置详细 - * @param id - */ -export const getNodeConfig = (id: string | number): AxiosPromise => { - return request({ - url: '/workflow/nodeConfig/' + id, - method: 'get' - }); -}; - -/** - * 新增节点配置 - * @param data - */ -export const addNodeConfig = (data: NodeConfigForm) => { - return request({ - url: '/workflow/nodeConfig', - method: 'post', - data: data - }); -}; - -/** - * 修改节点配置 - * @param data - */ -export const updateNodeConfig = (data: NodeConfigForm) => { - return request({ - url: '/workflow/nodeConfig', - method: 'put', - data: data - }); -}; - -/** - * 删除节点配置 - * @param id - */ -export const delNodeConfig = (id: string | number | Array) => { - return request({ - url: '/workflow/nodeConfig/' + id, - method: 'delete' - }); -}; diff --git a/src/layout/components/Navbar.vue b/src/layout/components/Navbar.vue index fd4eb8c4073c63d213705db8014eaacb66ba3727..c2ed0b6e4ee8e2f19db3136c70d24b92d90ffbbe 100644 --- a/src/layout/components/Navbar.vue +++ b/src/layout/components/Navbar.vue @@ -128,6 +128,7 @@ const dynamicTenantEvent = async (tenantId: string) => { dynamic.value = true; proxy?.$tab.closeAllPage(); proxy?.$router.push('/'); + proxy?.$tab.refreshPage(); } }; @@ -136,6 +137,7 @@ const dynamicClearEvent = async () => { dynamic.value = false; proxy?.$tab.closeAllPage(); proxy?.$router.push('/'); + proxy?.$tab.refreshPage(); }; /** 租户列表 */ diff --git a/src/layout/index.vue b/src/layout/index.vue index 29fb5ff56d844be923b18fb46fc7eebef2a5aad0..0919aad7e69227384401e615adc33d2d466a926d 100644 --- a/src/layout/index.vue +++ b/src/layout/index.vue @@ -27,6 +27,7 @@ import { AppMain, Navbar, Settings, TagsView } from './components'; import useAppStore from '@/store/modules/app'; import useSettingsStore from '@/store/modules/settings'; import { initWebSocket } from '@/utils/websocket'; +import { initSSE } from "@/utils/sse"; const settingsStore = useSettingsStore(); const theme = computed(() => settingsStore.theme); @@ -71,6 +72,10 @@ onMounted(() => { initWebSocket(protocol + window.location.host + import.meta.env.VITE_APP_BASE_API + '/resource/websocket'); }); +onMounted(() => { + initSSE(import.meta.env.VITE_APP_BASE_API + '/resource/sse') +}); + const handleClickOutside = () => { useAppStore().closeSideBar({ withoutAnimation: false }); }; diff --git a/src/permission.ts b/src/permission.ts index 6771f8cc1f21060d580a681ce9c1704105779dcf..125438bd4fae8308740115c4b88686cd914727df 100644 --- a/src/permission.ts +++ b/src/permission.ts @@ -40,6 +40,7 @@ router.beforeEach(async (to, from, next) => { router.addRoute(route); // 动态添加可访问路由表 } }); + // @ts-ignore next({ path: to.path, replace: true, params: to.params, query: to.query, hash: to.hash, name: to.name as string }); // hack方法 确保addRoutes已完成 } } else { diff --git a/src/plugins/tab.ts b/src/plugins/tab.ts index dd240cd419abb70a4a2995d62e65cd0ca2aeae98..86421a8fee0e89351e5dbe5de3c32dfaf4458d8e 100644 --- a/src/plugins/tab.ts +++ b/src/plugins/tab.ts @@ -1,5 +1,5 @@ import router from '@/router'; -import { RouteLocationMatched, RouteLocationNormalized } from 'vue-router'; +import {RouteLocationMatched, RouteLocationNormalized, RouteLocationRaw} from 'vue-router'; import useTagsViewStore from '@/store/modules/tagsView'; export default { @@ -41,7 +41,7 @@ export default { }); }, // 关闭当前tab页签,打开新页签 - closeOpenPage(obj: RouteLocationNormalized): void { + closeOpenPage(obj: RouteLocationRaw): void { useTagsViewStore().delView(router.currentRoute.value); if (obj !== undefined) { router.push(obj); diff --git a/src/router/index.ts b/src/router/index.ts index 438708f99ba6910bc3ba53b163a3e6d69c30af0e..86e00929cbbad086cff139670f5b27ae6f9fb1da 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -159,7 +159,7 @@ export const dynamicRoutes: RouteRecordRaw[] = [ path: 'index/:tableId(\\d+)', component: () => import('@/views/tool/gen/editTable.vue'), name: 'GenEdit', - meta: { title: '修改生成配置', activeMenu: '/tool/gen', icon: '' } + meta: { title: '修改生成配置', activeMenu: '/tool/gen', icon: '', noCache: true } } ] }, diff --git a/src/store/modules/permission.ts b/src/store/modules/permission.ts index 2e719bae3e22cd7d0a345a139d5fb6d772d9bcda..e90df4c344ebfdfdc4724247a05d12ab7f3f991b 100644 --- a/src/store/modules/permission.ts +++ b/src/store/modules/permission.ts @@ -21,13 +21,13 @@ export const usePermissionStore = defineStore('permission', () => { const sidebarRouters = ref([]); const getRoutes = (): RouteRecordRaw[] => { - return routes.value; + return routes.value as RouteRecordRaw[]; }; const getSidebarRoutes = (): RouteRecordRaw[] => { - return sidebarRouters.value; + return sidebarRouters.value as RouteRecordRaw[]; }; const getTopbarRoutes = (): RouteRecordRaw[] => { - return topbarRouters.value; + return topbarRouters.value as RouteRecordRaw[]; }; const setRoutes = (newRoutes: RouteRecordRaw[]): void => { diff --git a/src/store/modules/tagsView.ts b/src/store/modules/tagsView.ts index b9502eb52a36e16beaf23c6f9760560646766220..9756ac28f8c5a2dcb6e79c2133b3ad38fc39fbf9 100644 --- a/src/store/modules/tagsView.ts +++ b/src/store/modules/tagsView.ts @@ -6,10 +6,10 @@ export const useTagsViewStore = defineStore('tagsView', () => { const iframeViews = ref([]); const getVisitedViews = (): RouteLocationNormalized[] => { - return visitedViews.value; + return visitedViews.value as RouteLocationNormalized[]; }; const getIframeViews = (): RouteLocationNormalized[] => { - return iframeViews.value; + return iframeViews.value as RouteLocationNormalized[]; }; const getCachedViews = (): string[] => { return cachedViews.value; @@ -31,7 +31,7 @@ export const useTagsViewStore = defineStore('tagsView', () => { const delIframeView = (view: RouteLocationNormalized): Promise => { return new Promise((resolve) => { iframeViews.value = iframeViews.value.filter((item: RouteLocationNormalized) => item.path !== view.path); - resolve([...iframeViews.value]); + resolve([...iframeViews.value as RouteLocationNormalized[]]); }); }; const addVisitedView = (view: RouteLocationNormalized): void => { @@ -54,7 +54,7 @@ export const useTagsViewStore = defineStore('tagsView', () => { delCachedView(view); } resolve({ - visitedViews: [...visitedViews.value], + visitedViews: [...visitedViews.value as RouteLocationNormalized[]], cachedViews: [...cachedViews.value] }); }); @@ -68,7 +68,7 @@ export const useTagsViewStore = defineStore('tagsView', () => { break; } } - resolve([...visitedViews.value]); + resolve([...visitedViews.value as RouteLocationNormalized[]]); }); }; const delCachedView = (view?: RouteLocationNormalized): Promise => { @@ -92,7 +92,7 @@ export const useTagsViewStore = defineStore('tagsView', () => { delOthersVisitedViews(view); delOthersCachedViews(view); resolve({ - visitedViews: [...visitedViews.value], + visitedViews: [...visitedViews.value as RouteLocationNormalized[]], cachedViews: [...cachedViews.value] }); }); @@ -103,7 +103,7 @@ export const useTagsViewStore = defineStore('tagsView', () => { visitedViews.value = visitedViews.value.filter((v: RouteLocationNormalized) => { return v.meta?.affix || v.path === view.path; }); - resolve([...visitedViews.value]); + resolve([...visitedViews.value as RouteLocationNormalized[]]); }); }; const delOthersCachedViews = (view: RouteLocationNormalized): Promise => { @@ -124,7 +124,7 @@ export const useTagsViewStore = defineStore('tagsView', () => { delAllVisitedViews(); delAllCachedViews(); resolve({ - visitedViews: [...visitedViews.value], + visitedViews: [...visitedViews.value as RouteLocationNormalized[]], cachedViews: [...cachedViews.value] }); }); @@ -132,7 +132,7 @@ export const useTagsViewStore = defineStore('tagsView', () => { const delAllVisitedViews = (): Promise => { return new Promise((resolve) => { visitedViews.value = visitedViews.value.filter((tag: RouteLocationNormalized) => tag.meta?.affix); - resolve([...visitedViews.value]); + resolve([...visitedViews.value as RouteLocationNormalized[]]); }); }; @@ -167,7 +167,7 @@ export const useTagsViewStore = defineStore('tagsView', () => { } return false; }); - resolve([...visitedViews.value]); + resolve([...visitedViews.value as RouteLocationNormalized[]]); }); }; const delLeftTags = (view: RouteLocationNormalized): Promise => { @@ -186,7 +186,7 @@ export const useTagsViewStore = defineStore('tagsView', () => { } return false; }); - resolve([...visitedViews.value]); + resolve([...visitedViews.value as RouteLocationNormalized[]]); }); }; diff --git a/src/utils/sse.ts b/src/utils/sse.ts new file mode 100644 index 0000000000000000000000000000000000000000..a08f282a68e775aed7c084f20be50cb1c3199845 --- /dev/null +++ b/src/utils/sse.ts @@ -0,0 +1,45 @@ +import { getToken } from '@/utils/auth'; +import { ElNotification } from 'element-plus'; +import useNoticeStore from '@/store/modules/notice'; + +let message = ''; + +// 初始化 +export const initSSE = (url: any) => { + url = url + '?Authorization=Bearer ' + getToken() + '&clientid=' + import.meta.env.VITE_APP_CLIENT_ID + const { + data, + error + } = useEventSource(url, [], { + autoReconnect: { + retries: 10, + delay: 3000, + onFailed() { + console.log('Failed to connect after 10 retries') + }, + } + }); + + watch(error, () => { + console.log('SSE connection error:', error.value) + error.value = null; + }); + + watch(data, () => { + if (!data.value) return; + useNoticeStore().addNotice({ + message: data.value, + read: false, + time: new Date().toLocaleString() + }); + ElNotification({ + title: '消息', + message: data.value, + type: 'success', + duration: 3000 + }); + data.value = null; + }); +}; + + diff --git a/src/utils/websocket.ts b/src/utils/websocket.ts index d4dd8a87649d32f9c38ba535ce47ff09a213bf22..ade13ef85c10929dc74ba2a11f4f26f114566054 100644 --- a/src/utils/websocket.ts +++ b/src/utils/websocket.ts @@ -1,139 +1,51 @@ -/** - * @module initWebSocket 初始化 - * @module websocketonopen 连接成功 - * @module websocketonerror 连接失败 - * @module websocketclose 断开连接 - * @module resetHeart 重置心跳 - * @module sendSocketHeart 心跳发送 - * @module reconnect 重连 - * @module sendMsg 发送数据 - * @module websocketonmessage 接收数据 - * @module test 测试收到消息传递 - * @description socket 通信 - * @param {any} url socket地址 - * @param {any} websocket websocket 实例 - * @param {any} heartTime 心跳定时器实例 - * @param {number} socketHeart 心跳次数 - * @param {number} HeartTimeOut 心跳超时时间 - * @param {number} socketError 错误次数 - */ - import { getToken } from '@/utils/auth'; import { ElNotification } from 'element-plus'; import useNoticeStore from '@/store/modules/notice'; -let socketUrl: any = ''; // socket地址 -let websocket: any = null; // websocket 实例 -let heartTime: any = null; // 心跳定时器实例 -let socketHeart = 0 as number; // 心跳次数 -const HeartTimeOut = 10000; // 心跳超时时间 10000 = 10s -let socketError = 0 as number; // 错误次数 - // 初始化socket export const initWebSocket = (url: any) => { if (import.meta.env.VITE_APP_WEBSOCKET === 'false') { return; } - socketUrl = url; - // 初始化 websocket - websocket = new WebSocket(url + '?Authorization=Bearer ' + getToken() + '&clientid=' + import.meta.env.VITE_APP_CLIENT_ID); - websocketonopen(); - websocketonmessage(); - websocketonerror(); - websocketclose(); - sendSocketHeart(); - return websocket; -}; - -// socket 连接成功 -export const websocketonopen = () => { - websocket.onopen = function () { - console.log('连接 websocket 成功'); - resetHeart(); - }; -}; - -// socket 连接失败 -export const websocketonerror = () => { - websocket.onerror = function (e: any) { - console.log('连接 websocket 失败', e); - }; -}; - -// socket 断开链接 -export const websocketclose = () => { - websocket.onclose = function (e: any) { - console.log('断开连接', e); - }; -}; - -// socket 重置心跳 -export const resetHeart = () => { - socketHeart = 0; - socketError = 0; - clearInterval(heartTime); - sendSocketHeart(); -}; - -// socket心跳发送 -export const sendSocketHeart = () => { - heartTime = setInterval(() => { - // 如果连接正常则发送心跳 - if (websocket.readyState == 1) { - // if (socketHeart <= 30) { - websocket.send( - JSON.stringify({ - type: 'ping' - }) - ); - socketHeart = socketHeart + 1; - } else { - // 重连 - reconnect(); - } - }, HeartTimeOut); -}; - -// socket重连 -export const reconnect = () => { - if (socketError <= 2) { - clearInterval(heartTime); - initWebSocket(socketUrl); - socketError = socketError + 1; - // eslint-disable-next-line prettier/prettier - console.log('socket重连', socketError); - } else { - // eslint-disable-next-line prettier/prettier - console.log('重试次数已用完'); - clearInterval(heartTime); - } -}; - -// socket 发送数据 -export const sendMsg = (data: any) => { - websocket.send(data); -}; - -// socket 接收数据 -export const websocketonmessage = () => { - websocket.onmessage = function (e: any) { - if (e.data.indexOf('heartbeat') > 0) { - resetHeart(); - } - if (e.data.indexOf('ping') > 0) { - return; + url = url + '?Authorization=Bearer ' + getToken() + '&clientid=' + import.meta.env.VITE_APP_CLIENT_ID + useWebSocket(url, { + autoReconnect: { + // 重连最大次数 + retries: 3, + // 重连间隔 + delay: 1000, + onFailed() { + console.log('websocket重连失败'); + }, + }, + heartbeat: { + message: JSON.stringify({type: 'ping'}), + // 发送心跳的间隔 + interval: 10000, + // 接收到心跳response的超时时间 + pongTimeout: 2000, + }, + onConnected() { + console.log('websocket已经连接'); + }, + onDisconnected() { + console.log('websocket已经断开'); + }, + onMessage: (_, e) => { + if (e.data.indexOf('ping') > 0) { + return; + } + useNoticeStore().addNotice({ + message: e.data, + read: false, + time: new Date().toLocaleString() + }); + ElNotification({ + title: '消息', + message: e.data, + type: 'success', + duration: 3000 + }); } - useNoticeStore().addNotice({ - message: e.data, - read: false, - time: new Date().toLocaleString() - }); - ElNotification({ - title: '消息', - message: e.data, - type: 'success', - duration: 3000 - }); - return e.data; - }; + }); }; diff --git a/src/views/index.vue b/src/views/index.vue index aa60a9b350e93ef4a40d931fc89188e6d364a94d..7bd19e429ff472c7b79bc8d415dd75f7609f289b 100644 --- a/src/views/index.vue +++ b/src/views/index.vue @@ -33,7 +33,7 @@ * 部署方式 Docker 容器编排 一键部署业务集群
* 国际化 SpringMessage Spring标准国际化方案

-

当前版本: v5.2.1

+

当前版本: v5.2.2

¥免费开源

@@ -77,7 +77,7 @@ * 分布式监控 Prometheus、Grafana 全方位性能监控
* 其余与 Vue 版本一致

-

当前版本: v2.2.0

+

当前版本: v2.2.1

¥免费开源

diff --git a/src/views/system/oss/index.vue b/src/views/system/oss/index.vue index a6e60e83ed426b29ff1d41fc67e595c443584365..d057c2382b96251dbe7c9bc41a2d8949ccb47c31 100644 --- a/src/views/system/oss/index.vue +++ b/src/views/system/oss/index.vue @@ -60,7 +60,7 @@ > - 配置管理 + 配置管理 diff --git a/src/views/system/role/index.vue b/src/views/system/role/index.vue index 0b6ba00877a658c28a1233cf4d6ae0f354a0313f..f2299d71c73bab24235737d3c6b7038d8f667fa7 100644 --- a/src/views/system/role/index.vue +++ b/src/views/system/role/index.vue @@ -18,7 +18,7 @@ { /** 导出按钮操作 */ const handleExport = () => { proxy?.download( - 'system/tenantPackage/export', + 'system/package/export', { ...queryParams.value }, diff --git a/src/views/system/user/authRole.vue b/src/views/system/user/authRole.vue index 87d233453e21e0023d1fd62ec4033999aa471df6..fe119aed154b20fe2fee28e12294820a802d698d 100644 --- a/src/views/system/user/authRole.vue +++ b/src/views/system/user/authRole.vue @@ -80,8 +80,8 @@ const tableRef = ref(); /** 单击选中行数据 */ const clickRow = (row: RoleVO) => { - // ele的方法有问题,selected应该为可选参数 - tableRef.value?.toggleRowSelection(row, false); + row.flag = !row.flag + tableRef.value?.toggleRowSelection(row, row.flag); }; /** 多选框选中数据 */ const handleSelectionChange = (selection: RoleVO[]) => { diff --git a/src/views/system/user/index.vue b/src/views/system/user/index.vue index c1bdcf9a4f0dae6f406af72a317e0b9eb7b5bb9b..46bffd2ba44c8b897ad5363a38d94a850b274e5e 100644 --- a/src/views/system/user/index.vue +++ b/src/views/system/user/index.vue @@ -39,11 +39,12 @@ diff --git a/src/views/workflow/leave/index.vue b/src/views/workflow/leave/index.vue index d9c50c4cd0f424ccbe9e5cecd430e3d111ae49c4..f413136b034d16731442da9ab0d0cbd66973da52 100644 --- a/src/views/workflow/leave/index.vue +++ b/src/views/workflow/leave/index.vue @@ -176,7 +176,6 @@ const handleSelectionChange = (selection: LeaveVO[]) => { /** 新增按钮操作 */ const handleAdd = () => { proxy.$tab.closePage(proxy.$route); - proxy.$router.push(`/workflow/leaveEdit/index/add/add`); proxy.$router.push({ path: `/workflow/leaveEdit/index`, query: { diff --git a/vite.config.ts b/vite.config.ts index f8b1200d8c50a12d0ebada49a69aa2f6df3ca7c3..97c8d9d33d4c4bbd9abc25513853aa3dcd750df8 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -75,61 +75,7 @@ export default defineConfig(({ mode, command }: ConfigEnv): UserConfig => { 'diagram-js/lib/draw/BaseRenderer', 'tiny-svg', 'image-conversion', - - 'element-plus/es/components/text/style/css', - 'element-plus/es/components/collapse-item/style/css', - 'element-plus/es/components/collapse/style/css', - 'element-plus/es/components/space/style/css', - 'element-plus/es/components/container/style/css', - 'element-plus/es/components/aside/style/css', - 'element-plus/es/components/main/style/css', - 'element-plus/es/components/header/style/css', - 'element-plus/es/components/button-group/style/css', - 'element-plus/es/components/radio-button/style/css', - 'element-plus/es/components/checkbox-group/style/css', - 'element-plus/es/components/form/style/css', - 'element-plus/es/components/form-item/style/css', - 'element-plus/es/components/button/style/css', - 'element-plus/es/components/input/style/css', - 'element-plus/es/components/input-number/style/css', - 'element-plus/es/components/switch/style/css', - 'element-plus/es/components/upload/style/css', - 'element-plus/es/components/menu/style/css', - 'element-plus/es/components/col/style/css', - 'element-plus/es/components/icon/style/css', - 'element-plus/es/components/row/style/css', - 'element-plus/es/components/tag/style/css', - 'element-plus/es/components/dialog/style/css', - 'element-plus/es/components/loading/style/css', - 'element-plus/es/components/radio/style/css', - 'element-plus/es/components/radio-group/style/css', - 'element-plus/es/components/popover/style/css', - 'element-plus/es/components/scrollbar/style/css', - 'element-plus/es/components/tooltip/style/css', - 'element-plus/es/components/dropdown/style/css', - 'element-plus/es/components/dropdown-menu/style/css', - 'element-plus/es/components/dropdown-item/style/css', - 'element-plus/es/components/sub-menu/style/css', - 'element-plus/es/components/menu-item/style/css', - 'element-plus/es/components/divider/style/css', - 'element-plus/es/components/card/style/css', - 'element-plus/es/components/link/style/css', - 'element-plus/es/components/breadcrumb/style/css', - 'element-plus/es/components/breadcrumb-item/style/css', - 'element-plus/es/components/table/style/css', - 'element-plus/es/components/tree-select/style/css', - 'element-plus/es/components/table-column/style/css', - 'element-plus/es/components/select/style/css', - 'element-plus/es/components/option/style/css', - 'element-plus/es/components/pagination/style/css', - 'element-plus/es/components/tree/style/css', - 'element-plus/es/components/alert/style/css', - 'element-plus/es/components/checkbox/style/css', - 'element-plus/es/components/date-picker/style/css', - 'element-plus/es/components/transfer/style/css', - 'element-plus/es/components/tabs/style/css', - 'element-plus/es/components/image/style/css', - 'element-plus/es/components/tab-pane/style/css' + 'element-plus/es/components/**/css' ] } };