diff --git a/README.md b/README.md index 0e0f4c60..502fff50 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,6 @@ - 图标来源 [@ant-design/icons-vue](https://ant.design/components/icon) - 菜单图标使用自定义 iconfont `font_8d5l8fzk5b87iudi.js`图标文件 -## 测试环境 - -```text -Nginx: http://192.168.2.166:3188/#/index -后端暴露端口: http://192.168.2.166:33030 -``` - ## 程序命令 项目目录下 `.env.[环境]` 文件对应环境的一些配置,启动前请检查文件内是否配置正确。 diff --git a/package.json b/package.json index 71bbe0a8..76e7b0c8 100644 --- a/package.json +++ b/package.json @@ -16,31 +16,31 @@ "@antv/g6": "~4.8.24", "@codemirror/lang-javascript": "^6.2.2", "@codemirror/lang-yaml": "^6.1.1", - "@codemirror/merge": "^6.6.3", + "@codemirror/merge": "^6.7.2", "@codemirror/theme-one-dark": "^6.1.2", - "@tato30/vue-pdf": "^1.10.0", - "@vueuse/core": "~10.10.1", + "@tato30/vue-pdf": "^1.11.2", + "@vueuse/core": "^11.1.0", "@xterm/addon-fit": "^0.10.0", "@xterm/xterm": "^5.5.0", - "ant-design-vue": "^3.2.20", - "antdv-pro-layout": "~3.3.5", - "antdv-pro-modal": "^3.1.0", + "ant-design-vue": "^4.2.5", + "antdv-pro-layout": "^4.1.8", + "antdv-pro-modal": "^4.0.5", "codemirror": "^6.0.1", "crypto-js": "^4.2.0", "dayjs": "^1.11.11", "echarts": "~5.5.0", "file-saver": "^2.0.5", "grid-layout-plus": "^1.0.5", - "intl-tel-input": "^23.8.1", + "intl-tel-input": "^24.6.0", "js-base64": "^3.7.7", "js-cookie": "^3.0.5", "localforage": "^1.10.0", "nprogress": "^0.2.0", "p-queue": "~8.0.1", - "pinia": "^2.1.7", - "vue": "~3.3.13", - "vue-i18n": "^9.13.1", - "vue-router": "^4.4.0", + "pinia": "^2.2.4", + "vue": "^3.5.12", + "vue-i18n": "^10.0.4", + "vue-router": "^4.4.5", "vue3-smooth-dnd": "^0.0.6", "xlsx": "~0.18.5" }, @@ -48,14 +48,14 @@ "@types/crypto-js": "^4.2.2", "@types/file-saver": "^2.0.7", "@types/js-cookie": "^3.0.6", - "@types/node": "^18.0.0", + "@types/node": "^22.7.7", "@types/nprogress": "^0.2.3", - "@vitejs/plugin-vue": "^5.0.5", + "@vitejs/plugin-vue": "^5.1.4", "less": "^4.2.0", - "typescript": "~5.4.5", - "unplugin-vue-components": "~0.26.0", - "vite": "~5.3.1", + "typescript": "^5.6.3", + "unplugin-vue-components": "^0.27.4", + "vite": "5.4.10", "vite-plugin-compression": "~0.5.1", - "vue-tsc": "~2.0.22" + "vue-tsc": "^2.1.8" } } diff --git a/public/wiregasm/worker.js b/public/wiregasm/worker.js index 74baa7e5..8d6b9b4f 100644 --- a/public/wiregasm/worker.js +++ b/public/wiregasm/worker.js @@ -1,7 +1,7 @@ // load the Wiregasm library importScripts( - '/wiregasm/wiregasm_new.js', // self-compilation es5 - '/wiregasm/wiregasm_load.js' + 'wiregasm_new.js', // self-compilation es5 + 'wiregasm_load.js' // 'https://cdn.jsdelivr.net/npm/@goodtools/wiregasm/dist/wiregasm.js' ); @@ -16,11 +16,11 @@ const fetchPackages = async () => { console.log('Fetching packages'); let [wasmBuffer, dataBuffer] = await Promise.all([ await inflateRemoteBuffer( - '/wiregasm/wiregasm.wasm' + 'wiregasm.wasm' // 'https://cdn.jsdelivr.net/npm/@goodtools/wiregasm/dist/wiregasm.wasm' ), await inflateRemoteBuffer( - '/wiregasm/wiregasm.data' + 'wiregasm.data' // 'https://cdn.jsdelivr.net/npm/@goodtools/wiregasm/dist/wiregasm.data' ), ]); diff --git a/src/App.vue b/src/App.vue index 020167b8..fc9f4331 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,22 +1,48 @@ diff --git a/src/assets/background_dark.jpg b/src/assets/background_dark.jpg new file mode 100644 index 00000000..1b64e7df Binary files /dev/null and b/src/assets/background_dark.jpg differ diff --git a/src/assets/background.jpg b/src/assets/background_light.jpg similarity index 100% rename from src/assets/background.jpg rename to src/assets/background_light.jpg diff --git a/src/assets/svg/dark.svg b/src/assets/svg/dark.svg new file mode 100644 index 00000000..9b27cc61 --- /dev/null +++ b/src/assets/svg/dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/svg/light.svg b/src/assets/svg/light.svg new file mode 100644 index 00000000..161b3bd9 --- /dev/null +++ b/src/assets/svg/light.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/CronModal/index.vue b/src/components/CronModal/index.vue index abd76ff7..5a7adf60 100644 --- a/src/components/CronModal/index.vue +++ b/src/components/CronModal/index.vue @@ -3,7 +3,7 @@ :drag="true" :destroyOnClose="true" :title="t('components.CronModal.title')" - :visible="props.visible" + :open="props.open" :body-style="{ padding: '0 24px' }" @cancel="fnCronModal(false)" @ok="fnCronModal(true)" @@ -35,6 +35,7 @@ diff --git a/src/layouts/components/Tabs.vue b/src/layouts/components/Tabs.vue index b72f87b9..341bcd01 100644 --- a/src/layouts/components/Tabs.vue +++ b/src/layouts/components/Tabs.vue @@ -4,9 +4,9 @@ import { computed, watch } from 'vue'; import { useRouter } from 'vue-router'; import useTabsStore from '@/store/modules/tabs'; import useI18n from '@/hooks/useI18n'; -const { t } = useI18n(); const tabsStore = useTabsStore(); const router = useRouter(); +const { t } = useI18n(); defineProps({ /**标签栏宽度 */ @@ -112,7 +112,7 @@ watch(router.currentRoute, v => tabsStore.tabOpen(v), { immediate: true }); tabsStore.tabOpen(v), { immediate: true }); - + @@ -199,7 +199,18 @@ watch(router.currentRoute, v => tabsStore.tabOpen(v), { immediate: true }); } } +[data-theme='dark'] .tabs { + background: #141414; +} + .tabs :deep(.ant-tabs-nav:before) { border-bottom: none; } +.tabs :deep(.ant-tabs-nav-list .ant-tabs-tab) { + border-radius: 8px; +} +.tabs :deep(.ant-tabs-nav-list .ant-tabs-tab.ant-tabs-tab-active) { + border-bottom-right-radius: unset; + border-bottom-left-radius: unset; +} diff --git a/src/main.ts b/src/main.ts index 358d7988..f770c37a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,16 +4,15 @@ import App from './App.vue'; import router from './router'; import directive from './directive'; import i18n from './i18n'; -import ProModal from "antdv-pro-modal"; -import 'antdv-pro-layout/dist/style.css'; + import 'antdv-pro-modal/dist/style.css'; -import 'ant-design-vue/dist/antd.variable.min.css'; +import 'antdv-pro-layout/dist/style.css'; +import 'ant-design-vue/dist/reset.css'; const app = createApp(App); app.use(store); app.use(router); app.use(directive); app.use(i18n); -app.use(ProModal); app.mount('#app'); diff --git a/src/plugins/file-static-url.ts b/src/plugins/file-static-url.ts index f0d1e275..4dfcfbfb 100644 --- a/src/plugins/file-static-url.ts +++ b/src/plugins/file-static-url.ts @@ -19,3 +19,26 @@ export function parseUrlPath(path: string) { : import.meta.env.VITE_API_BASE_URL; return `${baseUrl}${path}?r=${Math.random().toFixed(2)}`; } + +/** + * 解析静态文件相对路径 + * @param path 静态资源文件 + * @returns + */ +export function parseBasePath(path: string) { + if (!path || path === '#') { + return '#'; + } + if (validHttp(path)) { + return path; + } + // 兼容旧前端可改配置文件 + const baseUrl = import.meta.env.VITE_HISTORY_BASE_URL; + let scriptUrl = + baseUrl.length === 1 && baseUrl.indexOf('/') === 0 + ? '' + : baseUrl.indexOf('/') === -1 + ? '/' + baseUrl + : baseUrl; + return `${scriptUrl}${path}?r=${Math.random().toFixed(2)}`; +} diff --git a/src/store/modules/layout.ts b/src/store/modules/layout.ts index c297498b..21c9cf34 100644 --- a/src/store/modules/layout.ts +++ b/src/store/modules/layout.ts @@ -1,16 +1,23 @@ -import { CACHE_LOCAL_PROCONFIG } from '@/constants/cache-keys-constants'; -import { localGetJSON, localSetJSON } from '@/utils/cache-local-utils'; +import { theme } from 'ant-design-vue/es'; +import type { ThemeConfig } from 'ant-design-vue/es/config-provider/context'; import { defineStore } from 'pinia'; +import { + CACHE_LOCAL_PRIMARY_COLOR, + CACHE_LOCAL_PROCONFIG, +} from '@/constants/cache-keys-constants'; +import { + localGet, + localGetJSON, + localSetJSON, +} from '@/utils/cache-local-utils'; /**布局参数类型 */ type LayoutStore = { - /**布局设置抽屉显示 */ - visible: boolean; /**布局配置 */ proConfig: { /**导航布局 */ layout: 'side' | 'top' | 'mix'; - /**全局主题色,需要导入样式文件 */ + /**全局主题色*/ theme: 'dark' | 'light'; /**菜单导航主题色 */ menuTheme: 'dark' | 'light'; @@ -29,10 +36,33 @@ type LayoutStore = { /**内容区域-导航标签项 */ tabRender: any | boolean | undefined; }; + /**主题配置 */ + themeConfig: ThemeConfig; /**水印内容 */ waterMarkContent: string; }; +/** + * 获取随机颜色范围 + * @returns 颜色 + */ +function getRandomColor(): string { + const colors: string[] = [ + '#f5222d', + '#fa541c', + '#fa8c16', + '#a0d911', + '#13c2c2', + '#1890ff', + '#722ed1', + '#eb2f96', + '#faad14', + '#52c41a', + ]; + const i = Math.floor(Math.random() * 10); + return colors[i]; +} + /**判断是否关闭内容区域 */ const proRender = (render: any) => (render === false ? false : undefined); @@ -40,7 +70,7 @@ const proRender = (render: any) => (render === false ? false : undefined); const proConfigLocal: LayoutStore['proConfig'] = localGetJSON( CACHE_LOCAL_PROCONFIG ) || { - layout: 'mix', + layout: 'side', theme: 'light', menuTheme: 'light', fixSiderbar: true, @@ -50,7 +80,6 @@ const proConfigLocal: LayoutStore['proConfig'] = localGetJSON( const useLayoutStore = defineStore('layout', { state: (): LayoutStore => ({ - visible: false, proConfig: { layout: proConfigLocal.layout, theme: proConfigLocal.theme, @@ -63,13 +92,27 @@ const useLayoutStore = defineStore('layout', { menuHeaderRender: proRender(proConfigLocal.menuHeaderRender), tabRender: proRender(proConfigLocal.tabRender), }, + themeConfig: { + algorithm: [theme.darkAlgorithm], + // algorithm: themeColor["dark"], + token: { + // colorBgContainer: "#fff", + colorPrimary: localGet(CACHE_LOCAL_PRIMARY_COLOR) || '#1890ff', + // borderRadius: 6, + }, + }, waterMarkContent: import.meta.env.VITE_APP_NAME, }), - actions: { - /**改变显示状态 */ - changeVisibleLayoutSetting() { - this.visible = !this.visible; + getters: { + getColorPrimary(): string { + let color = '#1890ff'; + if (this.themeConfig.token) { + color = this.themeConfig.token.colorPrimary || color; + } + return color; }, + }, + actions: { /**修改水印文字 */ changeWaterMark(text: string) { this.waterMarkContent = text; @@ -77,10 +120,48 @@ const useLayoutStore = defineStore('layout', { /**修改布局设置 */ changeConf(key: string, value: boolean | string | number | undefined) { if (Reflect.has(this.proConfig, key)) { + console.log(key, value); + if (key === 'theme') { + // const themeColor = { + // light: theme.defaultAlgorithm, + // compact: theme.compactAlgorithm, + // dark: theme.darkAlgorithm, + // }; + if (value === 'dark') { + document.documentElement.setAttribute('data-theme', 'dark'); + this.themeConfig.algorithm = [theme.darkAlgorithm]; + } else { + document.documentElement.setAttribute('data-theme', 'light'); + this.themeConfig.algorithm = [theme.defaultAlgorithm]; + } + } Reflect.set(this.proConfig, key, value); localSetJSON(CACHE_LOCAL_PROCONFIG, this.proConfig); } }, + /**主题色初始化 */ + initPrimaryColor() { + // 主题色初始化 + this.changePrimaryColor(this.getColorPrimary); + // 明暗模式初始化 + const themeMode = this.proConfig.theme; + document.documentElement.setAttribute('data-theme', themeMode); + this.changeConf('theme', themeMode); + }, + /** + * 主题色变更 + * @param color 颜色 + */ + changePrimaryColor(color?: string) { + if (!color) { + color = getRandomColor(); + } + + if (this.themeConfig && this.themeConfig.token) { + this.themeConfig.token.colorPrimary = color; + localStorage.setItem(CACHE_LOCAL_PRIMARY_COLOR, color); + } + }, }, }); diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts index 1a9b1932..a7bb65a6 100644 --- a/src/store/modules/user.ts +++ b/src/store/modules/user.ts @@ -1,7 +1,7 @@ import defaultAvatar from '@/assets/images/default_avatar.png'; import useLayoutStore from './layout'; import { login, logout, getInfo } from '@/api/login'; -import { getToken, setToken, removeToken } from '@/plugins/auth-token'; +import { setToken, removeToken } from '@/plugins/auth-token'; import { defineStore } from 'pinia'; import { TOKEN_RESPONSE_FIELD } from '@/constants/token-constants'; import { RESULT_CODE_SUCCESS } from '@/constants/result-constants'; @@ -133,10 +133,10 @@ const useUserStore = defineStore('user', { } // 水印文字信息=用户昵称 手机号 - let waterMarkContent = this.userName; - if (this.phonenumber) { - waterMarkContent = `${this.userName} ${this.phonenumber}`; - } + // let waterMarkContent = this.userName; + // if (this.phonenumber) { + // waterMarkContent = `${this.userName} ${this.phonenumber}`; + // } // useLayoutStore().changeWaterMark(waterMarkContent); useLayoutStore().changeWaterMark(''); } diff --git a/src/views/account/components/base-info.vue b/src/views/account/components/base-info.vue index 5f4a309f..7287b028 100644 --- a/src/views/account/components/base-info.vue +++ b/src/views/account/components/base-info.vue @@ -1,7 +1,7 @@ @@ -56,13 +66,31 @@ function fnColorChange(e: Event) { + + {{ t('views.account.settings.theme') }} + + + {{ t('views.account.settings.navTheme') }} diff --git a/src/views/dashboard/overview/components/Topology/index.vue b/src/views/dashboard/overview/components/Topology/index.vue index 8c2116e1..29fcde82 100644 --- a/src/views/dashboard/overview/components/Topology/index.vue +++ b/src/views/dashboard/overview/components/Topology/index.vue @@ -2,9 +2,10 @@ import { onMounted, ref } from 'vue'; import { RESULT_CODE_SUCCESS } from '@/constants/result-constants'; import { listAllNeInfo } from '@/api/ne/neInfo'; -import { message } from 'ant-design-vue/lib'; +import { message } from 'ant-design-vue/es'; import { getGraphData } from '@/api/monitor/topology'; import { Graph, GraphData, Tooltip } from '@antv/g6'; +import { parseBasePath } from '@/plugins/file-static-url'; import { edgeLineAnimateState } from '@/views/monitor/topologyBuild/hooks/registerEdge'; import { nodeImageAnimateState } from '@/views/monitor/topologyBuild/hooks/registerNode'; import { @@ -186,6 +187,12 @@ function fnGraphDataLoad(reload: boolean = false) { const nf: Record[] = nodes.filter( (node: Record) => { Reflect.set(node, 'neState', { online: false }); + // 图片路径处理 + if (node.img) node.img = parseBasePath(node.img); + if (node.icon.show && node.icon?.img) { + node.icon.img = parseBasePath(node.icon.img); + } + // 遍历是否有网元数据 const nodeID: string = node.id; const hasNe = res.neList.some(ne => { Reflect.set(node, 'neInfo', ne.neType === nodeID ? ne : {}); diff --git a/src/views/dashboard/smfCDR/index.vue b/src/views/dashboard/smfCDR/index.vue index ebe1db3b..699f3cca 100644 --- a/src/views/dashboard/smfCDR/index.vue +++ b/src/views/dashboard/smfCDR/index.vue @@ -1,10 +1,10 @@