From 06dfe98cb6711dbbd88827c67ca744291fb3b7e8 Mon Sep 17 00:00:00 2001 From: kongduo <2214111382@qq.com> Date: Thu, 11 Jun 2026 19:18:48 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AC=AC=E4=B8=80=E6=AC=A1=E7=BE=8E=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/.gitignore | 10 + .idea/codeStyles/Project.xml | 63 +++ .idea/codeStyles/codeStyleConfig.xml | 5 + .idea/inspectionProfiles/Project_Default.xml | 6 + .idea/modules.xml | 8 + .idea/prettier.xml | 6 + .idea/safePower.iml | 8 + .idea/vcs.xml | 6 + index.html | 139 +++-- src/pinia/modules/user.js | 11 +- src/style/element_visiable.scss | 126 +---- src/style/equipment-tech.scss | 477 ++++++++++++++++++ src/style/loading-tech.scss | 130 +++++ src/style/main.scss | 16 +- src/style/page-tech-compat.scss | 141 ++++++ src/style/table-tech.scss | 117 +++++ src/utils/date.js | 44 ++ src/utils/format.js | 9 + src/utils/loadingTheme.js | 15 + src/utils/request.js | 8 +- src/utils/techChartTheme.js | 27 + src/view/layout/header/index.vue | 2 +- .../equipment/components/list/index.vue | 27 +- src/view/masterStation/project/index.vue | 101 ++-- src/view/securityControl/alarmList/index.vue | 56 +- .../securityControl/currentAlarm/index.vue | 35 +- .../securityControl/overloadAlarm/index.vue | 35 +- .../securityControl/voltageAlarm/index.vue | 35 +- 28 files changed, 1338 insertions(+), 325 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/codeStyles/codeStyleConfig.xml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/prettier.xml create mode 100644 .idea/safePower.iml create mode 100644 .idea/vcs.xml create mode 100644 src/style/equipment-tech.scss create mode 100644 src/style/loading-tech.scss create mode 100644 src/style/page-tech-compat.scss create mode 100644 src/style/table-tech.scss create mode 100644 src/utils/date.js create mode 100644 src/utils/loadingTheme.js create mode 100644 src/utils/techChartTheme.js diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..b6b1ecf --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 已忽略包含查询文件的默认文件夹 +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..df6484c --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,63 @@ + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..03d9549 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..20fe489 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/prettier.xml b/.idea/prettier.xml new file mode 100644 index 0000000..b0c1c68 --- /dev/null +++ b/.idea/prettier.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/safePower.iml b/.idea/safePower.iml new file mode 100644 index 0000000..c956989 --- /dev/null +++ b/.idea/safePower.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/index.html b/index.html index 53a5ff6..4ba8e04 100644 --- a/index.html +++ b/index.html @@ -20,92 +20,86 @@ body { margin: 0; background: #020617; - --64f90c3645474bd5: #00d4ff; } #gva-loading-box { position: relative; display: flex; + flex-direction: column; align-items: center; justify-content: center; height: 100vh; width: 100vw; overflow: hidden; background: - radial-gradient(circle at 12% 10%, rgba(0, 212, 255, 0.16), transparent 28%), - radial-gradient(circle at 86% 6%, rgba(245, 158, 11, 0.1), transparent 22%), + radial-gradient(circle at 50% 40%, rgba(0, 212, 255, 0.1), transparent 38%), + radial-gradient(circle at 12% 10%, rgba(0, 212, 255, 0.12), transparent 28%), linear-gradient(135deg, #020617 0%, #07111f 52%, #0f172a 100%); } - #loading-text { + #gva-loading-panel { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + gap: 14px; + min-width: 148px; + padding: 24px 28px 20px; + border: 1px solid rgba(0, 212, 255, 0.22); + border-radius: 18px; + background: linear-gradient(145deg, rgba(10, 28, 54, 0.96), rgba(4, 14, 30, 0.92)); + box-shadow: + 0 22px 48px rgba(0, 0, 0, 0.34), + 0 0 28px rgba(0, 212, 255, 0.1), + inset 0 0 28px rgba(0, 212, 255, 0.05); + } + #loading-ring { + position: relative; + width: 44px; + height: 44px; + } + #loading-ring::before { + content: ''; position: absolute; - bottom: calc(50% - 100px); - left: 0; - width: 100%; - text-align: center; - color: #67e8f9; - font-size: 14px; - font-weight: 700; - letter-spacing: 0.08em; - text-shadow: 0 0 12px rgba(0, 212, 255, 0.38); - } - #loading { - position: absolute; - top: calc(50% - 20px); - left: calc(50% - 20px); - } - @keyframes loader { - 0% { - left: -100px; - } - 100% { - left: 110%; - } - } - #box { - width: 50px; - height: 50px; - background: var(--64f90c3645474bd5); - box-shadow: 0 0 22px rgba(0, 212, 255, 0.58); - animation: animate 0.5s linear infinite; - position: absolute; - top: 0; - left: 0; - border-radius: 3px; - } - @keyframes animate { - 17% { - border-bottom-right-radius: 3px; - } - 25% { - transform: translateY(9px) rotate(22.5deg); - } - 50% { - transform: translateY(18px) scale(1, 0.9) rotate(45deg); - border-bottom-right-radius: 40px; - } - 75% { - transform: translateY(9px) rotate(67.5deg); - } - 100% { - transform: translateY(0) rotate(90deg); - } - } - #shadow { - width: 50px; - height: 5px; - background: #67e8f9; - opacity: 0.28; - position: absolute; - top: 59px; - left: 0; + inset: 0; + border: 2px solid rgba(0, 212, 255, 0.12); + border-top-color: #00d4ff; + border-right-color: rgba(103, 232, 249, 0.55); border-radius: 50%; - animation: shadow 0.5s linear infinite; + animation: gvaBootSpin 0.85s linear infinite; + box-shadow: 0 0 18px rgba(0, 212, 255, 0.22); } - .dark #shadow { - background: #fff; + #loading-ring::after { + content: ''; + position: absolute; + inset: -6px; + border: 1px dashed rgba(0, 212, 255, 0.16); + border-radius: 50%; + animation: gvaBootOrbit 2.4s linear infinite; } - @keyframes shadow { + #loading-text { + margin: 0; + color: #dceeff; + font-size: 13px; + font-weight: 600; + letter-spacing: 0.1em; + animation: gvaBootPulse 1.6s ease-in-out infinite; + } + @keyframes gvaBootSpin { + to { + transform: rotate(360deg); + } + } + @keyframes gvaBootOrbit { + to { + transform: rotate(360deg); + } + } + @keyframes gvaBootPulse { + 0%, + 100% { + opacity: 0.72; + } 50% { - transform: scale(1.2, 1); + opacity: 1; } } @@ -113,11 +107,10 @@
-
-
-
+
+
+
系统正在加载中,请稍候...
-
系统正在加载中,请稍候...
diff --git a/src/pinia/modules/user.js b/src/pinia/modules/user.js index a69feca..b2fe957 100644 --- a/src/pinia/modules/user.js +++ b/src/pinia/modules/user.js @@ -7,6 +7,7 @@ import { ref, computed } from 'vue' import { useRouterStore } from './router' import { useCookies } from '@vueuse/integrations/useCookies' import { useStorage } from '@vueuse/core' +import { techFullscreenLoadingOptions } from '@/utils/loadingTheme' import { useAppStore } from '@/pinia' @@ -63,13 +64,9 @@ export const useUserStore = defineStore('user', () => { /* 登录*/ const LoginIn = async (loginInfo) => { try { - loadingInstance.value = ElLoading.service({ - fullscreen: true, - lock: true, - text: '登录中,请稍候...', - background: 'rgba(2, 8, 23, 0.82)', - customClass: 'gva-tech-loading' - }) + loadingInstance.value = ElLoading.service( + techFullscreenLoadingOptions('登录中,请稍候...') + ) const res = await login(loginInfo) diff --git a/src/style/element_visiable.scss b/src/style/element_visiable.scss index 2252551..4065023 100644 --- a/src/style/element_visiable.scss +++ b/src/style/element_visiable.scss @@ -1,5 +1,7 @@ @use '@/style/main.scss'; @use '@/style/reset'; +@use '@/style/table-tech.scss'; +@use '@/style/loading-tech.scss'; .el-button { font-weight: 600; @@ -45,43 +47,6 @@ @apply overflow-hidden; } -.el-loading-mask.is-fullscreen, -.el-loading-mask.gva-tech-loading, -.gva-tech-app .el-loading-mask { - color: var(--tech-text); - background: - radial-gradient(circle at 50% 36%, rgba(0, 212, 255, 0.16), transparent 28%), - rgba(2, 8, 23, 0.72) !important; - -webkit-backdrop-filter: blur(4px); - backdrop-filter: blur(4px); -} - -.el-loading-mask.is-fullscreen .el-loading-spinner, -.el-loading-mask.gva-tech-loading .el-loading-spinner, -.gva-tech-app .el-loading-mask .el-loading-spinner { - padding: 18px 24px; - border: 1px solid rgba(0, 212, 255, 0.22); - border-radius: 16px; - background: rgba(5, 16, 32, 0.78); - box-shadow: 0 16px 40px rgba(0, 0, 0, 0.38), 0 0 22px rgba(0, 212, 255, 0.14); -} - -.el-loading-mask.is-fullscreen .el-loading-spinner .path, -.el-loading-mask.gva-tech-loading .el-loading-spinner .path, -.gva-tech-app .el-loading-mask .el-loading-spinner .path { - stroke: var(--tech-cyan); -} - -.el-loading-mask.is-fullscreen .el-loading-spinner .el-loading-text, -.el-loading-mask.gva-tech-loading .el-loading-spinner .el-loading-text, -.gva-tech-app .el-loading-mask .el-loading-spinner .el-loading-text { - margin-top: 10px; - font-weight: 700; - color: #67e8f9; - letter-spacing: 0.08em; - text-shadow: 0 0 12px rgba(0, 212, 255, 0.38); -} - body:not(.login-light-mode) { .el-card, .el-dialog, @@ -120,7 +85,7 @@ body:not(.login-light-mode) { .equipment-tech-page { .el-form-item__label { font-weight: 700; - color: var(--tech-text-muted); + color: #dceeff; } .el-button { @@ -186,7 +151,7 @@ body:not(.login-light-mode) { .el-input__inner::placeholder, .el-textarea__inner::placeholder { - color: rgba(191, 226, 255, 0.44); + color: rgba(220, 243, 255, 0.56); } .el-card, @@ -210,63 +175,6 @@ body:not(.login-light-mode) { border-bottom-color: rgba(0, 212, 255, 0.18) !important; } - .el-table { - overflow: hidden; - color: var(--tech-text); - border-color: rgba(0, 212, 255, 0.18) !important; - background: transparent; - - &::before, - &::after, - .el-table__inner-wrapper::before { - background-color: rgba(0, 212, 255, 0.18); - } - - th.el-table__cell { - color: #baf6ff !important; - border-bottom-color: rgba(0, 212, 255, 0.3); - background: linear-gradient(180deg, rgba(14, 116, 144, 0.5), rgba(15, 23, 42, 0.92)) !important; - - .cell { - color: #baf6ff !important; - font-weight: 900; - letter-spacing: 0.05em; - text-shadow: 0 0 12px rgba(0, 212, 255, 0.36); - } - } - - tr, - td.el-table__cell { - color: #eafcff !important; - border-bottom-color: rgba(0, 212, 255, 0.14); - background: rgba(2, 8, 23, 0.28) !important; - } - - .el-table__row:hover > td.el-table__cell { - color: #ffffff !important; - background: rgba(14, 165, 233, 0.22) !important; - } - - .cell { - color: inherit !important; - font-weight: 600; - line-height: 34px; - text-shadow: 0 0 8px rgba(0, 212, 255, 0.12); - } - - .el-table__fixed, - .el-table__fixed-right, - .el-table__fixed-header-wrapper, - .el-table__fixed-body-wrapper, - .el-table__fixed-right-patch { - background: #061224; - } - - .el-table__empty-text { - color: rgba(191, 226, 255, 0.64); - } - } - .el-pagination { @apply mt-8; --el-pagination-bg-color: rgba(15, 23, 42, 0.76); @@ -364,30 +272,16 @@ body:not(.login-light-mode) { .el-table { tr { th { - @apply dark:bg-slate-900; .cell { - @apply leading-[36px]; - color: #baf6ff !important; - font-weight: 900; - text-shadow: 0 0 12px rgba(0, 212, 255, 0.32); + @apply leading-[1.5]; } } } + .el-table__row { td { - @apply dark:bg-slate-900; .cell { - @apply leading-[34px]; - color: #eafcff !important; - font-weight: 600; - text-shadow: 0 0 8px rgba(0, 212, 255, 0.12); - } - } - } - tr { - th { - &.is-leaf { - @apply dark:bg-slate-900; + @apply leading-[1.55]; } } } @@ -443,9 +337,9 @@ html.dark { --el-border-color: rgba(0, 212, 255, 0.24); --el-border-color-light: rgba(0, 212, 255, 0.18); --el-border-color-lighter: rgba(0, 212, 255, 0.12); - --el-text-color-primary: #e0f7ff; - --el-text-color-regular: #bfdbfe; - --el-text-color-secondary: rgba(191, 226, 255, 0.72); + --el-text-color-primary: #eefbff; + --el-text-color-regular: #dceeff; + --el-text-color-secondary: rgba(220, 243, 255, 0.88); --el-input-bg-color: rgba(2, 8, 23, 0.68); --el-mask-color: rgba(2, 6, 23, 0.72); } diff --git a/src/style/equipment-tech.scss b/src/style/equipment-tech.scss new file mode 100644 index 0000000..1fb2a93 --- /dev/null +++ b/src/style/equipment-tech.scss @@ -0,0 +1,477 @@ +.equipment-tech-page { + position: relative; + min-height: calc(100vh - 150px); + padding: 18px; + overflow: hidden; + isolation: isolate; + border-radius: 18px; + color: #dff8ff; + background: + radial-gradient(circle at 14% 10%, rgba(0, 212, 255, 0.16), transparent 28%), + radial-gradient(circle at 86% 8%, rgba(245, 158, 11, 0.12), transparent 24%), + radial-gradient(circle at 50% 92%, rgba(37, 99, 235, 0.14), transparent 34%), + linear-gradient(135deg, #020713 0%, #07111f 48%, #0f172a 100%); + + &::before, + &::after { + position: absolute; + inset: 0; + z-index: -1; + pointer-events: none; + content: ''; + } + + &::before { + opacity: 0.42; + background-image: + linear-gradient(rgba(0, 212, 255, 0.12) 1px, transparent 1px), + linear-gradient(90deg, rgba(0, 212, 255, 0.12) 1px, transparent 1px); + background-size: 34px 34px; + mask-image: radial-gradient(circle at center, #000 0%, transparent 78%); + animation: equipmentGridDrift 22s linear infinite; + } + + &::after { + background: linear-gradient(110deg, transparent 0%, rgba(0, 212, 255, 0.08) 45%, rgba(255, 255, 255, 0.16) 50%, rgba(0, 212, 255, 0.08) 55%, transparent 100%); + transform: translateX(-120%); + animation: equipmentScanLine 7s ease-in-out infinite; + } + + .equipment-tech-header { + position: relative; + display: flex; + align-items: flex-end; + justify-content: space-between; + gap: 18px; + padding: 22px 24px; + margin-bottom: 16px; + overflow: hidden; + border: 1px solid rgba(0, 212, 255, 0.28); + border-radius: 18px; + background: + linear-gradient(90deg, rgba(8, 27, 54, 0.9), rgba(4, 15, 32, 0.72)), + radial-gradient(circle at 20% 20%, rgba(0, 212, 255, 0.18), transparent 36%); + box-shadow: 0 18px 46px rgba(0, 0, 0, 0.36), inset 0 0 26px rgba(0, 212, 255, 0.08); + + &::before { + position: absolute; + top: 0; + left: -36%; + width: 36%; + height: 100%; + content: ''; + background: linear-gradient(90deg, transparent, rgba(0, 212, 255, 0.18), transparent); + animation: equipmentCardGlint 5.6s ease-in-out infinite; + } + } + + .equipment-tech-kicker { + display: inline-flex; + align-items: center; + gap: 8px; + margin-bottom: 8px; + font-size: 12px; + font-weight: 700; + color: #67e8f9; + letter-spacing: 0.18em; + text-transform: uppercase; + } + + .equipment-tech-title { + margin: 0; + font-size: 26px; + font-weight: 800; + line-height: 1.2; + color: #f0fbff; + letter-spacing: 0.08em; + text-shadow: 0 0 18px rgba(0, 212, 255, 0.42); + } + + .equipment-tech-subtitle { + margin: 8px 0 0; + font-size: 13px; + color: rgba(220, 243, 255, 0.72); + } + + .equipment-tech-header-line { + flex: 1; + min-width: 160px; + height: 2px; + margin-bottom: 16px; + background: linear-gradient(90deg, transparent, rgba(0, 212, 255, 0.92), rgba(245, 158, 11, 0.82), transparent); + box-shadow: 0 0 18px rgba(0, 212, 255, 0.46); + } + + .equipment-tech-stat-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(168px, 1fr)); + gap: 14px; + margin-bottom: 16px; + } + + .equipment-tech-stat-card { + position: relative; + min-height: 92px; + padding: 16px; + overflow: hidden; + border: 1px solid rgba(0, 212, 255, 0.22); + border-radius: 16px; + background: linear-gradient(135deg, rgba(9, 24, 48, 0.88), rgba(5, 16, 32, 0.7)); + box-shadow: inset 0 0 22px rgba(0, 212, 255, 0.06), 0 12px 28px rgba(0, 0, 0, 0.22); + transition: transform 0.24s ease, border-color 0.24s ease, box-shadow 0.24s ease; + + &::after { + position: absolute; + right: -24px; + bottom: -24px; + width: 86px; + height: 86px; + content: ''; + border: 1px solid rgba(0, 212, 255, 0.18); + border-radius: 50%; + box-shadow: 0 0 28px rgba(0, 212, 255, 0.12); + } + + &:hover { + border-color: rgba(0, 212, 255, 0.56); + box-shadow: 0 16px 34px rgba(0, 0, 0, 0.3), 0 0 24px rgba(0, 212, 255, 0.16); + transform: translateY(-3px); + } + } + + .equipment-tech-stat-card--success { + border-color: rgba(16, 185, 129, 0.38); + + .equipment-tech-stat-value { + color: #5eead4; + } + } + + .equipment-tech-stat-card--warning { + border-color: rgba(245, 158, 11, 0.42); + + .equipment-tech-stat-value { + color: #fbbf24; + } + } + + .equipment-tech-stat-card--danger { + border-color: rgba(239, 68, 68, 0.42); + + .equipment-tech-stat-value { + color: #fb7185; + } + } + + .equipment-tech-stat-label { + font-size: 13px; + color: rgba(220, 243, 255, 0.72); + } + + .equipment-tech-stat-value { + margin-top: 10px; + font-family: DIN Alternate, Arial, sans-serif; + font-size: 30px; + font-weight: 800; + line-height: 1; + color: #38bdf8; + text-shadow: 0 0 16px rgba(56, 189, 248, 0.42); + } + + .equipment-tech-stat-unit { + margin-left: 4px; + font-size: 13px; + font-weight: 500; + color: rgba(220, 243, 255, 0.78); + } + + .gva-search-box, + .gva-table-box { + position: relative; + overflow: hidden; + color: #dff8ff; + border: 1px solid rgba(0, 212, 255, 0.22); + border-radius: 16px; + background: rgba(5, 16, 32, 0.76); + box-shadow: inset 0 0 24px rgba(0, 212, 255, 0.05), 0 14px 34px rgba(0, 0, 0, 0.24); + backdrop-filter: blur(10px); + + &::before { + position: absolute; + top: 0; + left: -34%; + width: 34%; + height: 100%; + content: ''; + pointer-events: none; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.09), transparent); + animation: equipmentCardGlint 8s ease-in-out infinite; + } + } + + .gva-table-box { + margin-bottom: 0; + } + + .gva-btn-list { + min-height: 0; + margin-bottom: 12px; + } + + .el-form-item__label { + font-weight: 600; + color: rgba(218, 244, 255, 0.9); + } + + .el-input__wrapper, + .el-select__wrapper { + border: 1px solid rgba(0, 212, 255, 0.2); + background: rgba(2, 8, 23, 0.72); + box-shadow: inset 0 0 14px rgba(0, 212, 255, 0.06); + } + + .el-input__wrapper.is-focus, + .el-select__wrapper.is-focused { + border-color: rgba(0, 212, 255, 0.72); + box-shadow: 0 0 0 1px rgba(0, 212, 255, 0.34), 0 0 18px rgba(0, 212, 255, 0.18); + } + + .el-input__inner, + .el-select__placeholder, + .el-select__selected-item { + color: #e0f7ff; + } + + .el-input__inner::placeholder { + color: rgba(220, 243, 255, 0.56); + } + + .el-button { + border-radius: 999px; + } + + .el-button--primary:not(.is-link) { + border: 0; + background: linear-gradient(135deg, #0ea5e9 0%, #2563eb 52%, #7c3aed 100%); + box-shadow: 0 0 20px rgba(14, 165, 233, 0.28); + } + + .el-button:not(.el-button--primary):not(.is-link) { + color: #bfdbfe; + border-color: rgba(148, 163, 184, 0.28); + background: rgba(15, 23, 42, 0.74); + } + + .el-table { + overflow: hidden; + background: transparent; + } + + .el-divider--vertical { + border-left-color: rgba(0, 212, 255, 0.3); + } + + .gva-pagination { + display: flex; + justify-content: flex-end; + padding-top: 16px; + + .el-pagination { + --el-pagination-bg-color: rgba(15, 23, 42, 0.76); + --el-pagination-button-disabled-bg-color: rgba(15, 23, 42, 0.46); + --el-pagination-hover-color: #67e8f9; + --el-pagination-text-color: #bfdbfe; + --el-pagination-button-color: #bfdbfe; + } + + .el-pager li, + .btn-prev, + .btn-next, + .el-input__wrapper { + border: 1px solid rgba(0, 212, 255, 0.16); + background: rgba(15, 23, 42, 0.78); + } + + .el-pager li.is-active { + color: #020617; + background: #67e8f9; + } + } + + .tech-status-tag { + gap: 6px; + border: 1px solid rgba(0, 212, 255, 0.26); + border-radius: 999px; + background: rgba(15, 23, 42, 0.72); + box-shadow: 0 0 16px rgba(0, 212, 255, 0.1); + } + + .tech-status-dot { + display: inline-block; + width: 7px; + height: 7px; + border-radius: 50%; + background: #38bdf8; + box-shadow: 0 0 10px currentColor; + animation: equipmentDotBreath 1.8s ease-in-out infinite; + } + + .tech-status-dot--online, + .tech-status-dot--success { + color: #34d399; + background: #34d399; + } + + .tech-status-dot--offline, + .tech-status-dot--danger { + color: #fb7185; + background: #fb7185; + } + + .tech-status-dot--warning { + color: #fbbf24; + background: #fbbf24; + } + + .tech-value-chip, + .tech-coordinate { + display: inline-flex; + align-items: center; + gap: 5px; + min-height: 26px; + padding: 3px 10px; + font-family: DIN Alternate, Arial, sans-serif; + color: #dff8ff; + border: 1px solid rgba(0, 212, 255, 0.24); + border-radius: 999px; + background: rgba(2, 8, 23, 0.6); + box-shadow: inset 0 0 12px rgba(0, 212, 255, 0.06); + } + + .tech-coordinate { + color: #a7f3d0; + border-color: rgba(16, 185, 129, 0.26); + } + + .tech-action-buttons { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 8px; + + .el-button.is-link { + height: 26px; + padding: 0 8px; + color: #67e8f9; + border: 1px solid rgba(0, 212, 255, 0.2); + border-radius: 999px; + background: rgba(14, 165, 233, 0.08); + } + } + + .el-dropdown-link { + display: inline-flex; + align-items: center; + color: #67e8f9; + cursor: pointer; + } +} + +.equipment-alarm-page { + .equipment-tech-header { + border-color: rgba(245, 158, 11, 0.32); + background: + linear-gradient(90deg, rgba(54, 23, 8, 0.86), rgba(4, 15, 32, 0.72)), + radial-gradient(circle at 18% 20%, rgba(245, 158, 11, 0.18), transparent 36%); + } + + .equipment-tech-kicker, + .equipment-tech-title { + color: #fed7aa; + text-shadow: 0 0 18px rgba(245, 158, 11, 0.34); + } +} + +.equipment-tech-dropdown { + border: 1px solid rgba(0, 212, 255, 0.22) !important; + background: rgba(5, 16, 32, 0.96) !important; + box-shadow: 0 16px 40px rgba(0, 0, 0, 0.42), 0 0 22px rgba(0, 212, 255, 0.12) !important; + + .el-dropdown-menu { + background: transparent; + } + + .el-dropdown-menu__item { + color: #dff8ff; + } + + .el-dropdown-menu__item:not(.is-disabled):focus, + .el-dropdown-menu__item:not(.is-disabled):hover { + color: #67e8f9; + background: rgba(14, 165, 233, 0.16); + } + + .el-popper__arrow::before { + border-color: rgba(0, 212, 255, 0.22) !important; + background: rgba(5, 16, 32, 0.96) !important; + } +} + +@media (max-width: 768px) { + .equipment-tech-page { + padding: 12px; + + .equipment-tech-header { + align-items: flex-start; + flex-direction: column; + } + + .equipment-tech-header-line { + width: 100%; + margin-bottom: 0; + } + } +} + +@keyframes equipmentGridDrift { + 0% { + background-position: 0 0, 0 0; + } + 100% { + background-position: 68px 68px, 68px 68px; + } +} + +@keyframes equipmentScanLine { + 0%, 42% { + transform: translateX(-120%); + } + 72%, 100% { + transform: translateX(120%); + } +} + +@keyframes equipmentCardGlint { + 0%, 48% { + transform: translateX(0); + opacity: 0; + } + 58% { + opacity: 1; + } + 100% { + transform: translateX(390%); + opacity: 0; + } +} + +@keyframes equipmentDotBreath { + 0%, 100% { + opacity: 0.62; + transform: scale(0.86); + } + 50% { + opacity: 1; + transform: scale(1.18); + } +} diff --git a/src/style/loading-tech.scss b/src/style/loading-tech.scss new file mode 100644 index 0000000..451336f --- /dev/null +++ b/src/style/loading-tech.scss @@ -0,0 +1,130 @@ +@keyframes gvaLoadingFadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + +@keyframes gvaLoadingSpin { + to { + transform: rotate(360deg); + } +} + +@keyframes gvaLoadingPulse { + 0%, + 100% { + opacity: 0.72; + } + + 50% { + opacity: 1; + } +} + +@keyframes gvaLoadingOrbit { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } +} + +.el-loading-mask.gva-tech-loading, +.gva-tech-app .el-loading-mask { + animation: gvaLoadingFadeIn 0.22s ease; + background: + radial-gradient(circle at 50% 40%, rgba(0, 212, 255, 0.1), transparent 38%), + rgba(2, 8, 23, 0.42) !important; + -webkit-backdrop-filter: blur(10px); + backdrop-filter: blur(10px); +} + +.el-loading-mask.gva-tech-loading.gva-tech-loading--fullscreen { + background: + radial-gradient(circle at 50% 38%, rgba(0, 212, 255, 0.14), transparent 40%), + rgba(2, 8, 23, 0.58) !important; +} + +.el-loading-mask.gva-tech-loading .el-loading-spinner, +.gva-tech-app .el-loading-mask .el-loading-spinner { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 14px; + min-width: 148px; + padding: 24px 28px 20px; + margin-top: 0; + border: 1px solid rgba(0, 212, 255, 0.22); + border-radius: 18px; + background: + linear-gradient(145deg, rgba(10, 28, 54, 0.96), rgba(4, 14, 30, 0.92)); + box-shadow: + 0 22px 48px rgba(0, 0, 0, 0.34), + 0 0 28px rgba(0, 212, 255, 0.1), + inset 0 0 28px rgba(0, 212, 255, 0.05); + + .circular { + display: none !important; + } + + &::before { + content: ''; + width: 44px; + height: 44px; + border: 2px solid rgba(0, 212, 255, 0.12); + border-top-color: #00d4ff; + border-right-color: rgba(103, 232, 249, 0.55); + border-radius: 50%; + animation: gvaLoadingSpin 0.85s linear infinite; + box-shadow: 0 0 18px rgba(0, 212, 255, 0.22); + } + + &::after { + position: absolute; + top: 18px; + left: 50%; + width: 56px; + height: 56px; + margin-left: -28px; + content: ''; + border: 1px dashed rgba(0, 212, 255, 0.16); + border-radius: 50%; + animation: gvaLoadingOrbit 2.4s linear infinite; + pointer-events: none; + } + + .el-loading-text { + position: relative; + z-index: 1; + margin: 0 !important; + padding-top: 2px; + font-size: 13px; + font-weight: 600; + line-height: 1.4; + color: #dceeff !important; + letter-spacing: 0.1em; + text-shadow: none; + animation: gvaLoadingPulse 1.6s ease-in-out infinite; + } +} + +@media (prefers-reduced-motion: reduce) { + .el-loading-mask.gva-tech-loading, + .gva-tech-app .el-loading-mask { + animation: none; + } + + .el-loading-mask.gva-tech-loading .el-loading-spinner::before, + .el-loading-mask.gva-tech-loading .el-loading-spinner::after, + .el-loading-mask.gva-tech-loading .el-loading-spinner .el-loading-text { + animation: none !important; + } +} diff --git a/src/style/main.scss b/src/style/main.scss index 4314248..0ec1485 100644 --- a/src/style/main.scss +++ b/src/style/main.scss @@ -1,6 +1,7 @@ @use '@/style/iconfont.css'; @use './transition.scss'; @use './equipment-tech.scss'; +@use './page-tech-compat.scss'; :root { --tech-bg: #07111f; @@ -10,9 +11,9 @@ --tech-panel-strong: rgba(2, 8, 23, 0.92); --tech-border: rgba(0, 212, 255, 0.22); --tech-border-strong: rgba(0, 212, 255, 0.48); - --tech-text: #e0f7ff; - --tech-text-strong: #f4fbff; - --tech-text-muted: rgba(191, 226, 255, 0.72); + --tech-text: #eefbff; + --tech-text-strong: #ffffff; + --tech-text-muted: rgba(220, 243, 255, 0.88); --tech-cyan: #00d4ff; --tech-blue: #3b82f6; --tech-amber: #f59e0b; @@ -38,8 +39,9 @@ html.dark { --tech-panel-soft: rgba(15, 23, 42, 0.82); --tech-panel-strong: rgba(2, 8, 23, 0.94); --tech-border: rgba(0, 212, 255, 0.28); - --tech-text: #e0f7ff; - --tech-text-muted: rgba(191, 226, 255, 0.72); + --tech-text: #eefbff; + --tech-text-strong: #ffffff; + --tech-text-muted: rgba(220, 243, 255, 0.88); } .html-grey { @@ -429,7 +431,9 @@ html.dark { @apply p-4 rounded my-2; .el-table { - @apply border-x border-t border-b-0 rounded border-table-border border-solid -mx-[1px]; + margin-top: 2px; + border: 1px solid rgba(0, 212, 255, 0.12); + border-radius: 12px; } } diff --git a/src/style/page-tech-compat.scss b/src/style/page-tech-compat.scss new file mode 100644 index 0000000..6f349ba --- /dev/null +++ b/src/style/page-tech-compat.scss @@ -0,0 +1,141 @@ +// 业务页面与框架科技风主题的兼容层,覆盖旧页面中硬编码的浅色背景与文字色。 +.gva-tech-layout { + .text-slate-700, + .text-gray-700, + .text-gray-600 { + color: var(--tech-text) !important; + } + + .text-slate-500, + .text-slate-400, + .text-slate-300, + .text-gray-500 { + color: var(--tech-text-muted) !important; + } + + .project-overview { + min-height: calc(100% - 12px) !important; + padding: 12px !important; + color: var(--tech-text) !important; + background: transparent !important; + } + + .overview-card, + .alarm-list, + .alarm-trend, + .alarm-card, + .alarm-table-box, + .echarts-box > .item { + color: var(--tech-text) !important; + border: 1px solid rgba(0, 212, 255, 0.22) !important; + border-radius: 12px !important; + background: + linear-gradient(135deg, rgba(9, 24, 48, 0.88), rgba(5, 16, 32, 0.76)), + radial-gradient(circle at 100% 0%, rgba(0, 212, 255, 0.08), transparent 34%) !important; + box-shadow: inset 0 0 24px rgba(0, 212, 255, 0.05), 0 14px 34px rgba(0, 0, 0, 0.24) !important; + } + + .map-container { + border-color: rgba(0, 212, 255, 0.18) !important; + background: rgba(2, 8, 23, 0.62) !important; + } + + .alarm-title, + .list-title, + .project-name, + .project-option-name, + .alarm-stat-value, + .process-sub-value, + .echarts-box .title { + color: var(--tech-text-strong) !important; + } + + .tab, + .alarm-stat-label, + .alarm-labels, + .project-address, + .project-option-address, + .process-label, + .fullscreen-icon, + .device-location, + .device-channels, + .device-alarm { + color: #dceeff !important; + } + + .tab { + &:hover, + &.active { + color: #67e8f9 !important; + } + + &.active::after { + background: var(--tech-cyan) !important; + box-shadow: 0 0 10px rgba(0, 212, 255, 0.5); + } + } + + .dot { + background: var(--tech-cyan) !important; + box-shadow: 0 0 10px rgba(0, 212, 255, 0.5); + } + + .alarm-values .value-item, + .alarm-stat-value { + color: var(--tech-text-strong) !important; + } + + .project-radio-item { + border-color: rgba(0, 212, 255, 0.18) !important; + background: rgba(2, 8, 23, 0.42) !important; + + &.is-checked { + border-color: rgba(0, 212, 255, 0.56) !important; + background: rgba(0, 212, 255, 0.12) !important; + } + } + + .process-divider { + background: rgba(0, 212, 255, 0.18) !important; + } + + .device-grid, + .container-device, + .gva-search-box, + .gva-table-box { + color: var(--tech-text) !important; + } + + .device-grid .device-name { + color: var(--tech-text-strong) !important; + } + + .el-descriptions__label, + .el-descriptions__content, + .el-descriptions__cell { + color: var(--tech-text) !important; + } + + .map-device-marker { + color: var(--tech-text) !important; + border-color: rgba(0, 212, 255, 0.56) !important; + background: rgba(5, 16, 32, 0.92) !important; + box-shadow: 0 8px 20px rgba(0, 0, 0, 0.28), 0 0 16px rgba(0, 212, 255, 0.16) !important; + } + + .device-grid, + .container-device { + background: transparent !important; + } + + .device-grid .device-card, + .profile-container > .bg-white, + .profile-card { + color: var(--tech-text) !important; + border-color: rgba(0, 212, 255, 0.22) !important; + background: + linear-gradient(135deg, rgba(9, 24, 48, 0.88), rgba(5, 16, 32, 0.76)), + radial-gradient(circle at 100% 0%, rgba(0, 212, 255, 0.08), transparent 34%) !important; + box-shadow: inset 0 0 24px rgba(0, 212, 255, 0.05), 0 14px 34px rgba(0, 0, 0, 0.24) !important; + } +} diff --git a/src/style/table-tech.scss b/src/style/table-tech.scss new file mode 100644 index 0000000..c1ba70f --- /dev/null +++ b/src/style/table-tech.scss @@ -0,0 +1,117 @@ +// 全局表格柔和化:降低对比、增加过渡与留白,避免工业风表格显得生硬。 +.gva-tech-app, +.gva-tech-layout, +.equipment-tech-page { + .gva-table-box, + .alarm-table-box, + .alarm-list, + .gva-form-box { + .el-table { + border-radius: 12px; + overflow: hidden; + } + } + + .el-table { + --el-table-border-color: rgba(0, 212, 255, 0.1); + --el-table-header-bg-color: rgba(8, 27, 54, 0.72); + --el-table-row-hover-bg-color: rgba(0, 212, 255, 0.08); + --el-table-current-row-bg-color: rgba(0, 212, 255, 0.12); + --el-table-tr-bg-color: transparent; + --el-table-bg-color: transparent; + --el-table-header-text-color: rgba(191, 226, 255, 0.92); + + color: var(--tech-text); + font-size: 13px; + background: transparent; + + &::before, + &::after, + .el-table__inner-wrapper::before { + background-color: rgba(0, 212, 255, 0.1); + } + + th.el-table__cell { + padding: 10px 0; + color: rgba(191, 226, 255, 0.92) !important; + border-bottom: 1px solid rgba(0, 212, 255, 0.14) !important; + background: rgba(8, 27, 54, 0.72) !important; + + .cell { + padding: 0 14px; + color: inherit !important; + font-size: 12px; + font-weight: 600; + line-height: 1.5; + letter-spacing: 0.04em; + text-shadow: none; + } + } + + td.el-table__cell { + padding: 11px 0; + color: var(--tech-text) !important; + border-bottom: 1px solid rgba(0, 212, 255, 0.08) !important; + background: rgba(2, 8, 23, 0.22) !important; + transition: background-color 0.22s ease, box-shadow 0.22s ease, color 0.22s ease; + + .cell { + padding: 0 14px; + color: inherit !important; + font-size: 13px; + font-weight: 400; + line-height: 1.55; + text-shadow: none; + } + } + + .el-table__body tr { + transition: background-color 0.22s ease; + } + + .el-table__row:hover > td.el-table__cell { + color: #f4fbff !important; + background: rgba(0, 212, 255, 0.08) !important; + box-shadow: inset 3px 0 0 rgba(0, 212, 255, 0.55); + } + + &.el-table--striped .el-table__body tr.el-table__row--striped td.el-table__cell { + background: rgba(255, 255, 255, 0.025) !important; + } + + &.el-table--striped .el-table__body tr.el-table__row--striped:hover > td.el-table__cell { + background: rgba(0, 212, 255, 0.1) !important; + } + + &.el-table--border { + border: 1px solid rgba(0, 212, 255, 0.12) !important; + + .el-table__cell { + border-right: 1px solid rgba(0, 212, 255, 0.06) !important; + } + + th.el-table__cell, + td.el-table__cell { + border-bottom: 1px solid rgba(0, 212, 255, 0.08) !important; + } + } + + .el-table__fixed, + .el-table__fixed-right, + .el-table__fixed-header-wrapper, + .el-table__fixed-body-wrapper, + .el-table__fixed-right-patch { + background: rgba(5, 16, 32, 0.96); + } + + .el-table__empty-block { + min-height: 120px; + background: transparent; + } + + .el-table__empty-text { + color: rgba(191, 226, 255, 0.56); + font-size: 13px; + } + } +} diff --git a/src/utils/date.js b/src/utils/date.js new file mode 100644 index 0000000..987a40d --- /dev/null +++ b/src/utils/date.js @@ -0,0 +1,44 @@ +// 对Date的扩展,将 Date 转化为指定格式的String +// 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符, +// 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字) +// (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423 +// (new Date()).Format("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18 +// eslint-disable-next-line no-extend-native +Date.prototype.Format = function(fmt) { + const o = { + 'M+': this.getMonth() + 1, // 月份 + 'd+': this.getDate(), // 日 + 'h+': this.getHours(), // 小时 + 'm+': this.getMinutes(), // 分 + 's+': this.getSeconds(), // 秒 + 'q+': Math.floor((this.getMonth() + 3) / 3), // 季度 + 'S': this.getMilliseconds() // 毫秒 + } + const reg = /(y+)/ + if (reg.test(fmt)) { + const t = reg.exec(fmt)[1] + fmt = fmt.replace( + t, + (this.getFullYear() + '').substring(4 - t.length) + ) + } + for (let k in o) { + const regx = new RegExp('(' + k + ')') + if (regx.test(fmt)) { + const t = regx.exec(fmt)[1] + fmt = fmt.replace( + t, + t.length === 1 ? o[k] : ('00' + o[k]).substring(('' + o[k]).length) + ) + } + } + return fmt +} + +export function formatTimeToStr(times, pattern) { + let d = new Date(times).Format('yyyy-MM-dd hh:mm:ss') + if (pattern) { + d = new Date(times).Format(pattern) + } + return d.toLocaleString() +} diff --git a/src/utils/format.js b/src/utils/format.js index 78b84e0..318097c 100644 --- a/src/utils/format.js +++ b/src/utils/format.js @@ -32,6 +32,15 @@ export const filterDict = (value, options) => { return rowLabel && rowLabel.label } +export const formatDate = (time) => { + if (time !== null && time !== '') { + var date = new Date(time) + return formatTimeToStr(date, 'yyyy-MM-dd hh:mm:ss') + } else { + return '' + } +} + export const filterDataSource = (dataSource, value) => { // 递归查找函数 const findInDataSource = (data, targetValue) => { diff --git a/src/utils/loadingTheme.js b/src/utils/loadingTheme.js new file mode 100644 index 0000000..97fb9ff --- /dev/null +++ b/src/utils/loadingTheme.js @@ -0,0 +1,15 @@ +export const techLoadingOptions = (overrides = {}) => ({ + text: '数据加载中...', + background: 'transparent', + customClass: 'gva-tech-loading', + ...overrides +}) + +export const techFullscreenLoadingOptions = (text, overrides = {}) => ({ + fullscreen: true, + lock: true, + text, + background: 'transparent', + customClass: 'gva-tech-loading gva-tech-loading--fullscreen', + ...overrides +}) diff --git a/src/utils/request.js b/src/utils/request.js index eeeb7b1..21bdfee 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -3,6 +3,7 @@ import { useUserStore } from '@/pinia/modules/user' import { ElLoading, ElMessage } from 'element-plus' import { emitter } from '@/utils/bus' import router from '@/router/index' +import { techLoadingOptions } from '@/utils/loadingTheme' const service = axios.create({ baseURL: import.meta.env.VITE_BASE_API, @@ -36,12 +37,7 @@ const showLoading = ( // 再次检查activeAxios状态,防止竞态条件 if (activeAxios > 0 && !isLoadingVisible) { if (!option.target) option.target = loadDom - option = { - text: '数据加载中...', - background: 'rgba(2, 8, 23, 0.72)', - customClass: 'gva-tech-loading', - ...option - } + option = techLoadingOptions(option) loadingInstance = ElLoading.service(option) isLoadingVisible = true diff --git a/src/utils/techChartTheme.js b/src/utils/techChartTheme.js new file mode 100644 index 0000000..e1b4a6e --- /dev/null +++ b/src/utils/techChartTheme.js @@ -0,0 +1,27 @@ +export const techChartTooltip = { + backgroundColor: 'rgba(5, 16, 32, 0.96)', + borderColor: 'rgba(0, 212, 255, 0.22)', + textStyle: { color: '#eefbff' } +} + +export const techChartAxisLine = { + lineStyle: { color: 'rgba(0, 212, 255, 0.22)' } +} + +export const techChartAxisLabel = { + color: 'rgba(220, 243, 255, 0.88)', + fontSize: 11 +} + +export const techChartSplitLine = { + lineStyle: { color: 'rgba(0, 212, 255, 0.08)' } +} + +export const techChartLegend = { + textStyle: { color: 'rgba(220, 243, 255, 0.88)', fontSize: 12 } +} + +export const techChartCenterText = { + primary: '#ffffff', + secondary: 'rgba(220, 243, 255, 0.88)' +} diff --git a/src/view/layout/header/index.vue b/src/view/layout/header/index.vue index f37bc5d..a0631f2 100644 --- a/src/view/layout/header/index.vue +++ b/src/view/layout/header/index.vue @@ -5,7 +5,7 @@