代码更新
This commit is contained in:
90
index.html
90
index.html
@@ -9,6 +9,7 @@
|
||||
name="keywords"
|
||||
/>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<link rel="stylesheet" href="/gva-loading-boot.css" />
|
||||
<title></title>
|
||||
<style>
|
||||
.transition-colors {
|
||||
@@ -21,95 +22,14 @@
|
||||
margin: 0;
|
||||
background: #020617;
|
||||
}
|
||||
#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 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%);
|
||||
}
|
||||
#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;
|
||||
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: gvaBootSpin 0.85s linear infinite;
|
||||
box-shadow: 0 0 18px rgba(0, 212, 255, 0.22);
|
||||
}
|
||||
#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;
|
||||
}
|
||||
#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% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="gva-loading-box">
|
||||
<div id="gva-loading-panel">
|
||||
<div id="loading-ring"></div>
|
||||
<div id="loading-text">系统正在加载中,请稍候...</div>
|
||||
<div id="gva-loading-box" class="gva-loading-box">
|
||||
<div class="gva-loading-panel">
|
||||
<div class="gva-loading-ring"></div>
|
||||
<div class="gva-loading-text">系统正在加载中,请稍候...</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="app"></div>
|
||||
|
||||
124
public/gva-loading-boot.css
Normal file
124
public/gva-loading-boot.css
Normal file
@@ -0,0 +1,124 @@
|
||||
@keyframes gvaLoadingSpin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes gvaLoadingOrbit {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes gvaLoadingPulse {
|
||||
0%,
|
||||
100% {
|
||||
opacity: 0.72;
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes gvaLoadingFadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.gva-loading-box,
|
||||
.el-loading-mask.gva-tech-loading {
|
||||
background:
|
||||
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%) !important;
|
||||
}
|
||||
|
||||
.gva-loading-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.gva-loading-panel,
|
||||
.el-loading-mask.gva-tech-loading .el-loading-spinner {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: 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);
|
||||
}
|
||||
|
||||
.gva-loading-ring {
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
.gva-loading-ring::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
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: gvaLoadingSpin 0.85s linear infinite;
|
||||
box-shadow: 0 0 18px rgba(0, 212, 255, 0.22);
|
||||
}
|
||||
|
||||
.gva-loading-ring::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: -6px;
|
||||
border: 1px dashed rgba(0, 212, 255, 0.16);
|
||||
border-radius: 50%;
|
||||
animation: gvaLoadingOrbit 2.4s linear infinite;
|
||||
}
|
||||
|
||||
.gva-loading-text,
|
||||
.el-loading-mask.gva-tech-loading .el-loading-text {
|
||||
margin: 0 !important;
|
||||
padding-top: 0;
|
||||
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;
|
||||
}
|
||||
|
||||
.el-loading-mask.gva-tech-loading .el-loading-spinner .circular {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.gva-loading-ring::before,
|
||||
.gva-loading-ring::after,
|
||||
.gva-loading-text,
|
||||
.el-loading-mask.gva-tech-loading .el-loading-text {
|
||||
animation: none !important;
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
<div class="flex gap-[30px] h-[600px]">
|
||||
<!-- 左侧编辑区 -->
|
||||
<div class="flex flex-col flex-1">
|
||||
<div class="flex-1 bg-[#f8f8f8] rounded-lg overflow-hidden">
|
||||
<div class="flex-1 gva-tech-cropper rounded-lg overflow-hidden">
|
||||
<VueCropper
|
||||
ref="cropperRef"
|
||||
:img="imgSrc"
|
||||
@@ -38,7 +38,7 @@
|
||||
</div>
|
||||
|
||||
<!-- 工具栏 -->
|
||||
<div class="mt-[20px] flex items-center p-[10px] bg-white rounded-lg shadow-[0_2px_12px_rgba(0,0,0,0.1)]">
|
||||
<div class="mt-[20px] flex items-center p-[10px] gva-tech-cropper-panel rounded-lg">
|
||||
<el-button-group>
|
||||
<el-tooltip content="向左旋转">
|
||||
<el-button @click="rotate(-90)" :icon="RefreshLeft" />
|
||||
@@ -59,9 +59,9 @@
|
||||
|
||||
<!-- 右侧预览区 -->
|
||||
<div class="w-[340px]">
|
||||
<div class="bg-white p-5 rounded-lg shadow-[0_2px_12px_rgba(0,0,0,0.1)]">
|
||||
<div class="mb-[15px] text-gray-600">裁剪预览</div>
|
||||
<div class="bg-white p-5 rounded-lg shadow-[0_2px_12px_rgba(0,0,0,0.1)]"
|
||||
<div class="gva-tech-cropper-panel p-5 rounded-lg">
|
||||
<div class="mb-[15px] gva-setting-hint">裁剪预览</div>
|
||||
<div class="gva-tech-cropper p-5 rounded-lg"
|
||||
:style="{'width': previews.w + 'px', 'height': previews.h + 'px'}"
|
||||
>
|
||||
<div class="w-full h-full relative overflow-hidden">
|
||||
|
||||
@@ -32,6 +32,7 @@ export const useAppStore = defineStore('app', () => {
|
||||
const preferredDark = usePreferredDark()
|
||||
|
||||
const toggleTheme = (darkMode) => {
|
||||
config.darkMode = darkMode ? 'dark' : 'light'
|
||||
isDark.value = darkMode
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { login, getUserInfo } from '@/api/user'
|
||||
import { jsonInBlacklist } from '@/api/jwt'
|
||||
import router from '@/router/index'
|
||||
import { ElLoading, ElMessage } from 'element-plus'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { defineStore } from 'pinia'
|
||||
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 { createTechFullscreenLoading } from '@/utils/loadingTheme'
|
||||
|
||||
import { useAppStore } from '@/pinia'
|
||||
|
||||
@@ -64,9 +64,7 @@ export const useUserStore = defineStore('user', () => {
|
||||
/* 登录*/
|
||||
const LoginIn = async (loginInfo) => {
|
||||
try {
|
||||
loadingInstance.value = ElLoading.service(
|
||||
techFullscreenLoadingOptions('登录中,请稍候...')
|
||||
)
|
||||
loadingInstance.value = createTechFullscreenLoading('登录中,请稍候...')
|
||||
|
||||
const res = await login(loginInfo)
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
@use '@/style/reset';
|
||||
@use '@/style/table-tech.scss';
|
||||
@use '@/style/loading-tech.scss';
|
||||
@use '@/style/setting-tech.scss';
|
||||
|
||||
.el-button {
|
||||
font-weight: 600;
|
||||
@@ -329,7 +330,8 @@ body:not(.login-light-mode) {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
html.dark {
|
||||
html.dark,
|
||||
html.light {
|
||||
--el-bg-color: rgb(7, 17, 31);
|
||||
--el-bg-color-overlay: rgb(8, 27, 54);
|
||||
--el-fill-color-light: rgb(15, 23, 42);
|
||||
@@ -344,7 +346,8 @@ html.dark {
|
||||
--el-mask-color: rgba(2, 6, 23, 0.72);
|
||||
}
|
||||
|
||||
html.dark.login-light-mode {
|
||||
#userLayout.login-light-mode,
|
||||
html.login-light-mode {
|
||||
--el-bg-color: #ffffff !important;
|
||||
--el-bg-color-overlay: #ffffff !important;
|
||||
--el-text-color-primary: #303133 !important;
|
||||
|
||||
@@ -1,130 +1,11 @@
|
||||
@keyframes gvaLoadingFadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
@import '../../public/gva-loading-boot.css';
|
||||
|
||||
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 {
|
||||
.el-loading-mask.gva-tech-loading {
|
||||
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 {
|
||||
.el-loading-mask.gva-tech-loading {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,8 @@ body {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
html.dark {
|
||||
html.dark,
|
||||
html.light {
|
||||
--tech-bg: #07111f;
|
||||
--tech-bg-deep: #020617;
|
||||
--tech-panel: rgba(8, 27, 54, 0.92);
|
||||
|
||||
@@ -2,14 +2,18 @@
|
||||
.gva-tech-layout {
|
||||
.text-slate-700,
|
||||
.text-gray-700,
|
||||
.text-gray-600 {
|
||||
.text-gray-600,
|
||||
.text-gray-900,
|
||||
.text-gray-800,
|
||||
.text-black {
|
||||
color: var(--tech-text) !important;
|
||||
}
|
||||
|
||||
.text-slate-500,
|
||||
.text-slate-400,
|
||||
.text-slate-300,
|
||||
.text-gray-500 {
|
||||
.text-gray-500,
|
||||
.text-gray-400 {
|
||||
color: var(--tech-text-muted) !important;
|
||||
}
|
||||
|
||||
@@ -130,12 +134,21 @@
|
||||
|
||||
.device-grid .device-card,
|
||||
.profile-container > .bg-white,
|
||||
.profile-card {
|
||||
.profile-card,
|
||||
.detail-card,
|
||||
.chart-card,
|
||||
.trend-toolbar {
|
||||
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;
|
||||
|
||||
h3,
|
||||
h4 {
|
||||
color: var(--tech-text-strong) !important;
|
||||
border-bottom-color: rgba(0, 212, 255, 0.18) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
123
src/style/setting-tech.scss
Normal file
123
src/style/setting-tech.scss
Normal file
@@ -0,0 +1,123 @@
|
||||
.theme-config-drawer.el-drawer,
|
||||
.theme-config-drawer .el-drawer {
|
||||
color: var(--tech-text);
|
||||
background:
|
||||
radial-gradient(circle at 12% 10%, rgba(0, 212, 255, 0.12), transparent 28%),
|
||||
linear-gradient(180deg, rgba(7, 17, 31, 0.98), rgba(2, 8, 23, 0.98)) !important;
|
||||
box-shadow: -12px 0 40px rgba(0, 0, 0, 0.42), 0 0 28px rgba(0, 212, 255, 0.08);
|
||||
}
|
||||
|
||||
.theme-config-drawer {
|
||||
.gva-setting-header,
|
||||
.gva-setting-body,
|
||||
.gva-setting-tabs-wrap,
|
||||
.gva-setting-section,
|
||||
.gva-setting-card,
|
||||
.gva-setting-tab-bar {
|
||||
color: var(--tech-text);
|
||||
border-color: rgba(0, 212, 255, 0.18) !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;
|
||||
}
|
||||
|
||||
.gva-setting-header {
|
||||
border-bottom: 1px solid rgba(0, 212, 255, 0.18) !important;
|
||||
background: rgba(2, 8, 23, 0.72) !important;
|
||||
}
|
||||
|
||||
.gva-setting-title,
|
||||
.gva-setting-section-title,
|
||||
.gva-setting-card-title {
|
||||
color: var(--tech-text-strong) !important;
|
||||
}
|
||||
|
||||
.gva-setting-subtitle,
|
||||
.gva-setting-hint,
|
||||
.gva-setting-tab-item:not(.is-active) {
|
||||
color: var(--tech-text-muted) !important;
|
||||
}
|
||||
|
||||
.gva-setting-tab-bar {
|
||||
padding: 6px;
|
||||
border-radius: 14px;
|
||||
background: rgba(2, 8, 23, 0.72) !important;
|
||||
box-shadow: inset 0 0 18px rgba(0, 212, 255, 0.05);
|
||||
}
|
||||
|
||||
.gva-setting-tab-item {
|
||||
min-width: 80px;
|
||||
padding: 10px 18px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
|
||||
&:not(.is-active):hover {
|
||||
color: var(--tech-text-strong) !important;
|
||||
background: rgba(0, 212, 255, 0.1) !important;
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
color: #031424 !important;
|
||||
box-shadow: 0 0 18px rgba(0, 212, 255, 0.24);
|
||||
}
|
||||
}
|
||||
|
||||
.gva-setting-divider {
|
||||
background: rgba(0, 212, 255, 0.18) !important;
|
||||
}
|
||||
|
||||
.gva-setting-color-item,
|
||||
.gva-setting-color-panel {
|
||||
border-color: rgba(0, 212, 255, 0.18) !important;
|
||||
background: rgba(2, 8, 23, 0.62) !important;
|
||||
|
||||
&:hover {
|
||||
border-color: rgba(0, 212, 255, 0.42) !important;
|
||||
background: rgba(0, 212, 255, 0.08) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.gva-setting-color-code {
|
||||
color: var(--tech-text) !important;
|
||||
border-color: rgba(0, 212, 255, 0.18) !important;
|
||||
background: rgba(2, 8, 23, 0.72) !important;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: rgba(2, 8, 23, 0.72);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: rgba(0, 212, 255, 0.24);
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 212, 255, 0.38);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.gva-tech-tool-btn {
|
||||
color: var(--tech-text);
|
||||
border: 1px solid rgba(0, 212, 255, 0.22) !important;
|
||||
background: rgba(2, 8, 23, 0.62);
|
||||
box-shadow: inset 0 0 14px rgba(0, 212, 255, 0.05);
|
||||
|
||||
&:hover {
|
||||
color: #67e8f9;
|
||||
border-color: rgba(0, 212, 255, 0.42) !important;
|
||||
background: rgba(0, 212, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.gva-tech-cropper {
|
||||
color: var(--tech-text);
|
||||
border-color: rgba(0, 212, 255, 0.18) !important;
|
||||
background: rgba(2, 8, 23, 0.72) !important;
|
||||
}
|
||||
|
||||
.gva-tech-cropper-panel {
|
||||
border-color: rgba(0, 212, 255, 0.18) !important;
|
||||
background:
|
||||
linear-gradient(135deg, rgba(9, 24, 48, 0.88), rgba(5, 16, 32, 0.76)) !important;
|
||||
}
|
||||
@@ -1,3 +1,25 @@
|
||||
import { ElLoading } from 'element-plus'
|
||||
|
||||
export const patchTechLoadingSpinner = (root = document) => {
|
||||
const masks = root.querySelectorAll('.el-loading-mask.gva-tech-loading')
|
||||
const mask = masks[masks.length - 1]
|
||||
if (!mask) return
|
||||
|
||||
const spinner = mask.querySelector('.el-loading-spinner')
|
||||
if (!spinner || spinner.querySelector('.gva-loading-ring')) return
|
||||
|
||||
const ring = document.createElement('div')
|
||||
ring.className = 'gva-loading-ring'
|
||||
ring.setAttribute('aria-hidden', 'true')
|
||||
|
||||
const circular = spinner.querySelector('.circular')
|
||||
if (circular) {
|
||||
spinner.insertBefore(ring, circular)
|
||||
} else {
|
||||
spinner.insertBefore(ring, spinner.firstChild)
|
||||
}
|
||||
}
|
||||
|
||||
export const techLoadingOptions = (overrides = {}) => ({
|
||||
text: '数据加载中...',
|
||||
background: 'transparent',
|
||||
@@ -10,6 +32,24 @@ export const techFullscreenLoadingOptions = (text, overrides = {}) => ({
|
||||
lock: true,
|
||||
text,
|
||||
background: 'transparent',
|
||||
customClass: 'gva-tech-loading gva-tech-loading--fullscreen',
|
||||
customClass: 'gva-tech-loading',
|
||||
...overrides
|
||||
})
|
||||
|
||||
export const createTechLoading = (options = {}) => {
|
||||
const instance = ElLoading.service(techLoadingOptions(options))
|
||||
requestAnimationFrame(() => {
|
||||
patchTechLoadingSpinner()
|
||||
})
|
||||
return instance
|
||||
}
|
||||
|
||||
export const createTechFullscreenLoading = (text, overrides = {}) => {
|
||||
const instance = ElLoading.service(
|
||||
techFullscreenLoadingOptions(text, overrides)
|
||||
)
|
||||
requestAnimationFrame(() => {
|
||||
patchTechLoadingSpinner()
|
||||
})
|
||||
return instance
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import axios from 'axios' // 引入axios
|
||||
import { useUserStore } from '@/pinia/modules/user'
|
||||
import { ElLoading, ElMessage } from 'element-plus'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { emitter } from '@/utils/bus'
|
||||
import router from '@/router/index'
|
||||
import { techLoadingOptions } from '@/utils/loadingTheme'
|
||||
import { createTechLoading } from '@/utils/loadingTheme'
|
||||
|
||||
const service = axios.create({
|
||||
baseURL: import.meta.env.VITE_BASE_API,
|
||||
@@ -37,8 +37,7 @@ const showLoading = (
|
||||
// 再次检查activeAxios状态,防止竞态条件
|
||||
if (activeAxios > 0 && !isLoadingVisible) {
|
||||
if (!option.target) option.target = loadDom
|
||||
option = techLoadingOptions(option)
|
||||
loadingInstance = ElLoading.service(option)
|
||||
loadingInstance = createTechLoading(option)
|
||||
isLoadingVisible = true
|
||||
|
||||
// 设置强制关闭定时器,防止loading永远不关闭(30秒超时)
|
||||
|
||||
@@ -25,3 +25,17 @@ export const techChartCenterText = {
|
||||
primary: '#ffffff',
|
||||
secondary: 'rgba(220, 243, 255, 0.88)'
|
||||
}
|
||||
|
||||
export const techChartSeriesColors = [
|
||||
'#00d4ff',
|
||||
'#10b981',
|
||||
'#f59e0b',
|
||||
'#ef4444',
|
||||
'#3b82f6',
|
||||
'#8b5cf6',
|
||||
'#14b8a6',
|
||||
'#67e8f9'
|
||||
]
|
||||
|
||||
export const techChartMutedColor = 'rgba(220, 243, 255, 0.88)'
|
||||
export const techChartSplitTrackColor = 'rgba(0, 212, 255, 0.12)'
|
||||
|
||||
@@ -13,20 +13,25 @@
|
||||
import Chart from '@/components/charts/index.vue'
|
||||
import useChartOption from '@/hooks/charts'
|
||||
import { graphic } from 'echarts'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useAppStore } from '@/pinia'
|
||||
import { ref } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
const appStore = useAppStore()
|
||||
const { config } = storeToRefs(appStore)
|
||||
import { useAppStore } from '@/pinia'
|
||||
import {
|
||||
techChartMutedColor,
|
||||
techChartSplitTrackColor,
|
||||
techChartTooltip
|
||||
} from '@/utils/techChartTheme'
|
||||
|
||||
defineProps({
|
||||
height: {
|
||||
type: String,
|
||||
default: '128px'
|
||||
}
|
||||
})
|
||||
const dotColor = computed(() => {
|
||||
return appStore.isDark ? '#333' : '#E5E8EF'
|
||||
})
|
||||
|
||||
const appStore = useAppStore()
|
||||
const { config } = storeToRefs(appStore)
|
||||
const dotColor = techChartSplitTrackColor
|
||||
const graphicFactory = (side) => {
|
||||
return {
|
||||
type: 'text',
|
||||
@@ -35,7 +40,7 @@
|
||||
style: {
|
||||
text: '',
|
||||
textAlign: 'center',
|
||||
fill: '#4E5969',
|
||||
fill: techChartMutedColor,
|
||||
fontSize: 12
|
||||
}
|
||||
}
|
||||
@@ -69,7 +74,7 @@
|
||||
data: xAxis.value,
|
||||
boundaryGap: false,
|
||||
axisLabel: {
|
||||
color: '#4E5969',
|
||||
color: techChartMutedColor,
|
||||
formatter(value, idx) {
|
||||
if (idx === 0) return ''
|
||||
if (idx === xAxis.value.length - 1) return ''
|
||||
@@ -122,6 +127,7 @@
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
...techChartTooltip,
|
||||
formatter(params) {
|
||||
const [firstElement] = params
|
||||
return `<div>
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
import { ref } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useAppStore } from '@/pinia'
|
||||
import { techChartMutedColor } from '@/utils/techChartTheme'
|
||||
const appStore = useAppStore()
|
||||
const { config } = storeToRefs(appStore)
|
||||
|
||||
@@ -38,7 +39,7 @@
|
||||
style: {
|
||||
text: '',
|
||||
textAlign: 'center',
|
||||
fill: '#4E5969',
|
||||
fill: techChartMutedColor,
|
||||
fontSize: 12
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,18 +150,18 @@
|
||||
}
|
||||
|
||||
.detail-card {
|
||||
background-color: var(--el-bg-color-overlay, #ffffff);
|
||||
border-radius: 8px;
|
||||
background: var(--tech-panel-soft);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
border: 1px solid var(--el-border-color, #e4e7ed);
|
||||
border: 1px solid var(--tech-border);
|
||||
|
||||
h3 {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary, #303133);
|
||||
color: var(--tech-text-strong);
|
||||
margin: 0 0 16px 0;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid var(--el-border-color-lighter, #ebeef5);
|
||||
border-bottom: 1px solid rgba(0, 212, 255, 0.18);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -146,6 +146,13 @@
|
||||
import { TitleComponent, TooltipComponent, LegendComponent, GridComponent } from 'echarts/components'
|
||||
import VChart from 'vue-echarts'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import {
|
||||
techChartAxisLabel,
|
||||
techChartAxisLine,
|
||||
techChartSeriesColors,
|
||||
techChartSplitLine,
|
||||
techChartTooltip
|
||||
} from '@/utils/techChartTheme'
|
||||
use([CanvasRenderer, LineChart, TitleComponent, TooltipComponent, LegendComponent, GridComponent])
|
||||
|
||||
const props = defineProps({
|
||||
@@ -359,7 +366,8 @@
|
||||
const createLineOption = (name, color, data = [], xAxis = []) => {
|
||||
return {
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
trigger: 'axis',
|
||||
...techChartTooltip
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
@@ -372,25 +380,14 @@
|
||||
type: 'category',
|
||||
data: xAxis,
|
||||
boundaryGap: false,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#909399'
|
||||
}
|
||||
}
|
||||
axisLine: techChartAxisLine,
|
||||
axisLabel: techChartAxisLabel
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#909399'
|
||||
}
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#ebeef5',
|
||||
type: 'dashed'
|
||||
}
|
||||
}
|
||||
axisLine: techChartAxisLine,
|
||||
axisLabel: techChartAxisLabel,
|
||||
splitLine: techChartSplitLine
|
||||
},
|
||||
series: [
|
||||
{
|
||||
@@ -430,43 +427,43 @@
|
||||
key: 'voltage',
|
||||
title: '电压',
|
||||
unit: 'V',
|
||||
color: '#409EFF',
|
||||
option: createLineOption('电压', '#409EFF', [], [])
|
||||
color: techChartSeriesColors[0],
|
||||
option: createLineOption('电压', techChartSeriesColors[0], [], [])
|
||||
},
|
||||
{
|
||||
key: 'leakageCurrent',
|
||||
title: '漏电流值',
|
||||
unit: 'mA',
|
||||
color: '#67C23A',
|
||||
option: createLineOption('漏电流', '#67C23A', [], [])
|
||||
color: techChartSeriesColors[1],
|
||||
option: createLineOption('漏电流', techChartSeriesColors[1], [], [])
|
||||
},
|
||||
{
|
||||
key: 'cumulativeElectricity',
|
||||
title: '累计用电量',
|
||||
unit: 'kWh',
|
||||
color: '#E6A23C',
|
||||
option: createLineOption('用电量', '#E6A23C', [], [])
|
||||
color: techChartSeriesColors[2],
|
||||
option: createLineOption('用电量', techChartSeriesColors[2], [], [])
|
||||
},
|
||||
{
|
||||
key: 'current',
|
||||
title: '电流值',
|
||||
unit: 'A',
|
||||
color: '#F56C6C',
|
||||
option: createLineOption('电流', '#F56C6C', [], [])
|
||||
color: techChartSeriesColors[3],
|
||||
option: createLineOption('电流', techChartSeriesColors[3], [], [])
|
||||
},
|
||||
{
|
||||
key: 'internalTemperature',
|
||||
title: '内部温度',
|
||||
unit: '℃',
|
||||
color: '#909399',
|
||||
option: createLineOption('内部温度', '#909399', [], [])
|
||||
color: techChartSeriesColors[4],
|
||||
option: createLineOption('内部温度', techChartSeriesColors[4], [], [])
|
||||
},
|
||||
{
|
||||
key: 'powerFactor',
|
||||
title: '功率因数',
|
||||
unit: '',
|
||||
color: '#1ABC9C',
|
||||
option: createLineOption('功率因数', '#1ABC9C', [], [])
|
||||
color: techChartSeriesColors[5],
|
||||
option: createLineOption('功率因数', techChartSeriesColors[5], [], [])
|
||||
}
|
||||
])
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
<tools />
|
||||
<el-dropdown>
|
||||
<div class="flex justify-center items-center h-full w-full">
|
||||
<span class="cursor-pointer flex justify-center items-center text-black dark:text-gray-100">
|
||||
<span class="cursor-pointer flex justify-center items-center text-[var(--tech-text)]">
|
||||
<CustomPic />
|
||||
<span v-show="!isMobile" class="w-16">{{ userStore.userInfo.nickName }}</span>
|
||||
<el-icon>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<div class="flex items-center mx-4 gap-4">
|
||||
<el-tooltip class="" effect="dark" content="搜索" placement="bottom">
|
||||
<span
|
||||
class="w-8 h-8 p-2 rounded-full flex items-center justify-center shadow border border-gray-200 dark:border-gray-600 cursor-pointer border-solid"
|
||||
class="w-8 h-8 p-2 rounded-full flex items-center justify-center gva-tech-tool-btn cursor-pointer border-solid"
|
||||
>
|
||||
<el-icon @click="handleCommand">
|
||||
<Search />
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
<el-tooltip class="" effect="dark" content="系统设置" placement="bottom">
|
||||
<span
|
||||
class="w-8 h-8 p-2 rounded-full flex items-center justify-center shadow border border-gray-200 dark:border-gray-600 cursor-pointer border-solid"
|
||||
class="w-8 h-8 p-2 rounded-full flex items-center justify-center gva-tech-tool-btn cursor-pointer border-solid"
|
||||
>
|
||||
<el-icon @click="toggleSetting">
|
||||
<Setting />
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
<el-tooltip class="" effect="dark" content="刷新" placement="bottom">
|
||||
<span
|
||||
class="w-8 h-8 p-2 rounded-full flex items-center justify-center shadow border border-gray-200 dark:border-gray-600 cursor-pointer border-solid"
|
||||
class="w-8 h-8 p-2 rounded-full flex items-center justify-center gva-tech-tool-btn cursor-pointer border-solid"
|
||||
>
|
||||
<el-icon :class="showRefreshAnmite ? 'animate-spin' : ''" @click="toggleRefresh">
|
||||
<Refresh />
|
||||
@@ -36,7 +36,7 @@
|
||||
</el-tooltip>
|
||||
<el-tooltip class="" effect="dark" content="切换主题" placement="bottom">
|
||||
<span
|
||||
class="w-8 h-8 p-2 rounded-full flex items-center justify-center shadow border border-gray-200 dark:border-gray-600 cursor-pointer border-solid"
|
||||
class="w-8 h-8 p-2 rounded-full flex items-center justify-center gva-tech-tool-btn cursor-pointer border-solid"
|
||||
>
|
||||
<el-icon v-if="appStore.isDark" @click="appStore.toggleTheme(false)">
|
||||
<Sunny />
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<template>
|
||||
<div class="font-inter">
|
||||
<div class="bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl p-8 shadow-sm">
|
||||
<div class="gva-setting-card rounded-xl p-8">
|
||||
<div class="mb-8">
|
||||
<p class="text-base font-semibold text-gray-700 dark:text-gray-300 mb-5">精选色彩</p>
|
||||
<p class="gva-setting-section-title text-base font-semibold mb-5">精选色彩</p>
|
||||
<div class="grid grid-cols-3 gap-4">
|
||||
<div
|
||||
v-for="colorItem in presetColors"
|
||||
:key="colorItem.color"
|
||||
class="flex items-center gap-4 p-4 bg-white dark:bg-gray-700 border-2 border-gray-200 dark:border-gray-600 rounded-xl cursor-pointer transition-all duration-150 ease-in-out hover:transform hover:-translate-y-1 hover:shadow-lg"
|
||||
class="gva-setting-color-item flex items-center gap-4 p-4 border-2 rounded-xl cursor-pointer transition-all duration-150 ease-in-out hover:-translate-y-1"
|
||||
:class="{
|
||||
'ring-2 ring-offset-2 ring-offset-gray-50 dark:ring-offset-gray-800 transform -translate-y-1 shadow-lg': modelValue === colorItem.color
|
||||
'ring-2 ring-offset-2 transform -translate-y-1 shadow-lg': modelValue === colorItem.color
|
||||
}"
|
||||
:style="modelValue === colorItem.color ? {
|
||||
borderColor: colorItem.color,
|
||||
@@ -18,8 +18,8 @@
|
||||
@click="handleColorChange(colorItem.color)"
|
||||
>
|
||||
<div
|
||||
class="relative w-10 h-10 rounded-lg border border-gray-300 dark:border-gray-500 flex-shrink-0 shadow-sm"
|
||||
:style="{ backgroundColor: colorItem.color }"
|
||||
class="relative w-10 h-10 rounded-lg border flex-shrink-0 shadow-sm"
|
||||
:style="{ backgroundColor: colorItem.color, borderColor: 'rgba(0, 212, 255, 0.22)' }"
|
||||
>
|
||||
<div
|
||||
v-if="modelValue === colorItem.color"
|
||||
@@ -32,16 +32,16 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="min-w-0 flex-1">
|
||||
<span class="block text-sm font-semibold text-gray-900 dark:text-white">{{ colorItem.name }}</span>
|
||||
<span class="block text-sm font-semibold gva-setting-card-title">{{ colorItem.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between p-5 bg-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-xl mb-6 shadow-sm">
|
||||
<div class="gva-setting-color-panel flex items-center justify-between p-5 rounded-xl mb-6">
|
||||
<div class="flex-1">
|
||||
<h4 class="text-base font-semibold text-gray-900 dark:text-white">自定义颜色</h4>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">选择任意颜色作为主题色</p>
|
||||
<h4 class="text-base font-semibold gva-setting-card-title">自定义颜色</h4>
|
||||
<p class="text-sm gva-setting-hint mt-1">选择任意颜色作为主题色</p>
|
||||
</div>
|
||||
<el-color-picker
|
||||
v-model="customColor"
|
||||
@@ -52,15 +52,15 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="bg-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-xl p-5 shadow-sm">
|
||||
<div class="gva-setting-color-panel rounded-xl p-5">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-base font-semibold text-gray-700 dark:text-gray-300">当前主题色</span>
|
||||
<span class="text-base font-semibold gva-setting-section-title">当前主题色</span>
|
||||
<div class="flex items-center gap-3">
|
||||
<div
|
||||
class="w-6 h-6 rounded-lg border border-gray-300 dark:border-gray-500 shadow-sm"
|
||||
:style="{ backgroundColor: modelValue }"
|
||||
class="w-6 h-6 rounded-lg border shadow-sm"
|
||||
:style="{ backgroundColor: modelValue, borderColor: 'rgba(0, 212, 255, 0.22)' }"
|
||||
></div>
|
||||
<code class="text-sm font-mono bg-gray-100 dark:bg-gray-600 text-gray-700 dark:text-gray-300 px-3 py-2 rounded-lg border border-gray-200 dark:border-gray-500">
|
||||
<code class="gva-setting-color-code text-sm font-mono px-3 py-2 rounded-lg border">
|
||||
{{ modelValue }}
|
||||
</code>
|
||||
</div>
|
||||
@@ -81,7 +81,7 @@ defineOptions({
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: '#3b82f6'
|
||||
default: '#00d4ff'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -90,19 +90,15 @@ const emit = defineEmits(['update:modelValue'])
|
||||
const customColor = ref(props.modelValue)
|
||||
|
||||
const presetColors = [
|
||||
{ color: '#4E80EE', name: '默认' },
|
||||
{ color: '#8bb5d1', name: '晨雾蓝' },
|
||||
{ color: '#a8c8a8', name: '薄荷绿' },
|
||||
{ color: '#d4a5a5', name: '玫瑰粉' },
|
||||
{ color: '#c8a8d8', name: '薰衣草' },
|
||||
{ color: '#f0c674', name: '暖阳黄' },
|
||||
{ color: '#b8b8b8', name: '月光银' },
|
||||
{ color: '#d8a8a8', name: '珊瑚橙' },
|
||||
{ color: '#a8d8d8', name: '海雾青' },
|
||||
{ color: '#c8c8a8', name: '橄榄绿' },
|
||||
{ color: '#d8c8a8', name: '奶茶棕' },
|
||||
{ color: '#a8a8d8', name: '梦幻紫' },
|
||||
{ color: '#c8d8a8', name: '抹茶绿' }
|
||||
{ color: '#00d4ff', name: '科技青' },
|
||||
{ color: '#67e8f9', name: '电光蓝' },
|
||||
{ color: '#3b82f6', name: '深空蓝' },
|
||||
{ color: '#10b981', name: '运行绿' },
|
||||
{ color: '#f59e0b', name: '告警橙' },
|
||||
{ color: '#ef4444', name: '危险红' },
|
||||
{ color: '#8b5cf6', name: '紫电' },
|
||||
{ color: '#14b8a6', name: '海雾青' },
|
||||
{ color: '#22d3ee', name: '冰晶蓝' }
|
||||
]
|
||||
|
||||
const handleColorChange = (color) => {
|
||||
@@ -128,24 +124,14 @@ watch(() => props.modelValue, (newValue) => {
|
||||
|
||||
.custom-color-picker {
|
||||
::v-deep(.el-color-picker__trigger) {
|
||||
border: 1px solid #e5e7eb;
|
||||
border: 1px solid rgba(0, 212, 255, 0.22);
|
||||
border-radius: 6px;
|
||||
transition: all 150ms ease-in-out;
|
||||
|
||||
&:hover {
|
||||
border-color: #9ca3af;
|
||||
border-color: rgba(0, 212, 255, 0.42);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dark .custom-color-picker {
|
||||
::v-deep(.el-color-picker__trigger) {
|
||||
border-color: #4b5563;
|
||||
|
||||
&:hover {
|
||||
border-color: #6b7280;
|
||||
box-shadow: 0 2px 8px rgba(0, 212, 255, 0.16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
<template>
|
||||
<div class="flex justify-center">
|
||||
<div class="inline-flex bg-gray-100 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg p-1 gap-1">
|
||||
<div class="gva-setting-tab-bar inline-flex rounded-lg p-1 gap-1">
|
||||
<div
|
||||
v-for="mode in themeModes"
|
||||
:key="mode.value"
|
||||
class="flex flex-col items-center justify-center px-4 py-3 rounded-md cursor-pointer transition-all duration-150 ease-in-out min-w-[64px]"
|
||||
:class="[
|
||||
modelValue === mode.value
|
||||
? 'text-white shadow-sm transform -translate-y-0.5'
|
||||
: 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700'
|
||||
]"
|
||||
class="gva-setting-tab-item flex flex-col items-center justify-center px-4 py-3 rounded-md cursor-pointer min-w-[64px]"
|
||||
:class="{ 'is-active': modelValue === mode.value }"
|
||||
:style="modelValue === mode.value ? { backgroundColor: primaryColor } : {}"
|
||||
@click="handleModeChange(mode.value)"
|
||||
>
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
class="theme-config-drawer"
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between w-full px-6 py-4 bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-700">
|
||||
<h2 class="text-xl font-semibold text-gray-900 dark:text-white font-inter">系统配置</h2>
|
||||
<div class="gva-setting-header flex items-center justify-between w-full px-6 py-4">
|
||||
<h2 class="gva-setting-title text-xl font-semibold font-inter">系统配置</h2>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@@ -22,19 +22,15 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="bg-white dark:bg-gray-900">
|
||||
<div class="px-8 pt-4 pb-6 border-b border-gray-200 dark:border-gray-700">
|
||||
<div class="gva-setting-body">
|
||||
<div class="gva-setting-tabs-wrap px-8 pt-4 pb-6 border-b">
|
||||
<div class="flex justify-center">
|
||||
<div class="inline-flex bg-gray-100 dark:bg-gray-800 rounded-xl p-1.5 border border-gray-200 dark:border-gray-700 shadow-sm">
|
||||
<div class="gva-setting-tab-bar inline-flex rounded-xl">
|
||||
<div
|
||||
v-for="tab in tabs"
|
||||
:key="tab.key"
|
||||
class="px-6 py-3 text-base text-center cursor-pointer font-medium rounded-lg transition-all duration-150 ease-in-out min-w-[80px]"
|
||||
:class="[
|
||||
activeTab === tab.key
|
||||
? 'text-white shadow-md transform -translate-y-0.5'
|
||||
: 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700'
|
||||
]"
|
||||
class="gva-setting-tab-item px-6 py-3 text-base text-center font-medium min-w-[80px]"
|
||||
:class="{ 'is-active': activeTab === tab.key }"
|
||||
:style="activeTab === tab.key ? { backgroundColor: config.primaryColor } : {}"
|
||||
@click="activeTab = tab.key"
|
||||
>
|
||||
@@ -110,10 +106,6 @@
|
||||
.theme-config-drawer {
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
|
||||
::v-deep(.el-drawer) {
|
||||
background: white;
|
||||
}
|
||||
|
||||
::v-deep(.el-drawer__header) {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
@@ -124,12 +116,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.dark .theme-config-drawer {
|
||||
::v-deep(.el-drawer) {
|
||||
background: #111827;
|
||||
}
|
||||
}
|
||||
|
||||
.font-inter {
|
||||
font-family: 'Inter', sans-serif;
|
||||
}
|
||||
@@ -142,38 +128,7 @@
|
||||
&:hover {
|
||||
transform: translateY(-2px);
|
||||
filter: brightness(0.9);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom scrollbar for webkit browsers */
|
||||
::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: #f3f4f6;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #d1d5db;
|
||||
border-radius: 3px;
|
||||
|
||||
&:hover {
|
||||
background: #9ca3af;
|
||||
}
|
||||
}
|
||||
|
||||
.dark ::-webkit-scrollbar-track {
|
||||
background: #1f2937;
|
||||
}
|
||||
|
||||
.dark ::-webkit-scrollbar-thumb {
|
||||
background: #4b5563;
|
||||
|
||||
&:hover {
|
||||
background: #6b7280;
|
||||
box-shadow: 0 4px 12px rgba(0, 212, 255, 0.18);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
<!-- Theme Mode Section -->
|
||||
<div class="mb-10">
|
||||
<div class="flex items-center justify-center mb-6">
|
||||
<div class="h-px bg-gray-200 dark:bg-gray-700 flex-1"></div>
|
||||
<span class="px-6 text-lg font-semibold text-gray-700 dark:text-gray-300">主题模式</span>
|
||||
<div class="h-px bg-gray-200 dark:bg-gray-700 flex-1"></div>
|
||||
<div class="gva-setting-divider h-px flex-1"></div>
|
||||
<span class="gva-setting-section-title px-6 text-lg font-semibold">主题模式</span>
|
||||
<div class="gva-setting-divider h-px flex-1"></div>
|
||||
</div>
|
||||
|
||||
<div class="section-content">
|
||||
@@ -19,9 +19,9 @@
|
||||
<!-- Theme Color Section -->
|
||||
<div class="mb-10">
|
||||
<div class="flex items-center justify-center mb-6">
|
||||
<div class="h-px bg-gray-200 dark:bg-gray-700 flex-1"></div>
|
||||
<span class="px-6 text-lg font-semibold text-gray-700 dark:text-gray-300">主题颜色</span>
|
||||
<div class="h-px bg-gray-200 dark:bg-gray-700 flex-1"></div>
|
||||
<div class="gva-setting-divider h-px flex-1"></div>
|
||||
<span class="gva-setting-section-title px-6 text-lg font-semibold">主题颜色</span>
|
||||
<div class="gva-setting-divider h-px flex-1"></div>
|
||||
</div>
|
||||
|
||||
<div class="section-content">
|
||||
@@ -35,16 +35,16 @@
|
||||
<!-- Visual Accessibility Section -->
|
||||
<div class="mb-10">
|
||||
<div class="flex items-center justify-center mb-6">
|
||||
<div class="h-px bg-gray-200 dark:bg-gray-700 flex-1"></div>
|
||||
<span class="px-6 text-lg font-semibold text-gray-700 dark:text-gray-300">视觉辅助</span>
|
||||
<div class="h-px bg-gray-200 dark:bg-gray-700 flex-1"></div>
|
||||
<div class="gva-setting-divider h-px flex-1"></div>
|
||||
<span class="gva-setting-section-title px-6 text-lg font-semibold">视觉辅助</span>
|
||||
<div class="gva-setting-divider h-px flex-1"></div>
|
||||
</div>
|
||||
|
||||
<div class="section-content">
|
||||
<div class="bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl p-6 shadow-sm">
|
||||
<div class="gva-setting-card rounded-xl p-6">
|
||||
<SettingItem label="灰色模式">
|
||||
<template #suffix>
|
||||
<span class="text-xs text-gray-400 dark:text-gray-500 ml-2">降低色彩饱和度</span>
|
||||
<span class="text-xs gva-setting-hint ml-2">降低色彩饱和度</span>
|
||||
</template>
|
||||
<el-switch
|
||||
v-model="config.grey"
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
<SettingItem label="色弱模式">
|
||||
<template #suffix>
|
||||
<span class="text-xs text-gray-400 dark:text-gray-500 ml-2">优化色彩对比度</span>
|
||||
<span class="text-xs gva-setting-hint ml-2">优化色彩对比度</span>
|
||||
</template>
|
||||
<el-switch
|
||||
v-model="config.weakness"
|
||||
@@ -64,7 +64,7 @@
|
||||
|
||||
<SettingItem label="显示水印">
|
||||
<template #suffix>
|
||||
<span class="text-xs text-gray-400 dark:text-gray-500 ml-2">在页面显示水印标识</span>
|
||||
<span class="text-xs gva-setting-hint ml-2">在页面显示水印标识</span>
|
||||
</template>
|
||||
<el-switch
|
||||
v-model="config.show_watermark"
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
|
||||
<script setup>
|
||||
import { captcha } from '@/api/user'
|
||||
import { reactive, ref } from 'vue'
|
||||
import { reactive, ref, onMounted, onUnmounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useUserStore } from '@/pinia/modules/user'
|
||||
@@ -170,6 +170,14 @@
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
document.documentElement.classList.add('login-light-mode')
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
document.documentElement.classList.remove('login-light-mode')
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -150,18 +150,18 @@
|
||||
}
|
||||
|
||||
.detail-card {
|
||||
background-color: var(--el-bg-color-overlay, #ffffff);
|
||||
border-radius: 8px;
|
||||
background: var(--tech-panel-soft);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
border: 1px solid var(--el-border-color, #e4e7ed);
|
||||
border: 1px solid var(--tech-border);
|
||||
|
||||
h3 {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary, #303133);
|
||||
color: var(--tech-text-strong);
|
||||
margin: 0 0 16px 0;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid var(--el-border-color-lighter, #ebeef5);
|
||||
border-bottom: 1px solid rgba(0, 212, 255, 0.18);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -119,18 +119,18 @@
|
||||
}
|
||||
|
||||
.detail-card {
|
||||
background-color: var(--el-bg-color-overlay, #ffffff);
|
||||
border-radius: 8px;
|
||||
background: var(--tech-panel-soft);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
border: 1px solid var(--el-border-color, #e4e7ed);
|
||||
border: 1px solid var(--tech-border);
|
||||
|
||||
h3 {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary, #303133);
|
||||
color: var(--tech-text-strong);
|
||||
margin: 0 0 16px 0;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid var(--el-border-color-lighter, #ebeef5);
|
||||
border-bottom: 1px solid rgba(0, 212, 255, 0.18);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -146,6 +146,13 @@
|
||||
import { TitleComponent, TooltipComponent, LegendComponent, GridComponent } from 'echarts/components'
|
||||
import VChart from 'vue-echarts'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import {
|
||||
techChartAxisLabel,
|
||||
techChartAxisLine,
|
||||
techChartSeriesColors,
|
||||
techChartSplitLine,
|
||||
techChartTooltip
|
||||
} from '@/utils/techChartTheme'
|
||||
use([CanvasRenderer, LineChart, TitleComponent, TooltipComponent, LegendComponent, GridComponent])
|
||||
|
||||
const props = defineProps({
|
||||
@@ -359,7 +366,8 @@
|
||||
const createLineOption = (name, color, data = [], xAxis = []) => {
|
||||
return {
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
trigger: 'axis',
|
||||
...techChartTooltip
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
@@ -372,25 +380,14 @@
|
||||
type: 'category',
|
||||
data: xAxis,
|
||||
boundaryGap: false,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#909399'
|
||||
}
|
||||
}
|
||||
axisLine: techChartAxisLine,
|
||||
axisLabel: techChartAxisLabel
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#909399'
|
||||
}
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#ebeef5',
|
||||
type: 'dashed'
|
||||
}
|
||||
}
|
||||
axisLine: techChartAxisLine,
|
||||
axisLabel: techChartAxisLabel,
|
||||
splitLine: techChartSplitLine
|
||||
},
|
||||
series: [
|
||||
{
|
||||
@@ -430,43 +427,43 @@
|
||||
key: 'voltage',
|
||||
title: '电压',
|
||||
unit: 'V',
|
||||
color: '#409EFF',
|
||||
option: createLineOption('电压', '#409EFF', [], [])
|
||||
color: '#00d4ff',
|
||||
option: createLineOption('电压', techChartSeriesColors[0], [], [])
|
||||
},
|
||||
{
|
||||
key: 'leakageCurrent',
|
||||
title: '漏电流值',
|
||||
unit: 'mA',
|
||||
color: '#67C23A',
|
||||
option: createLineOption('漏电流', '#67C23A', [], [])
|
||||
color: techChartSeriesColors[1],
|
||||
option: createLineOption('漏电流', techChartSeriesColors[1], [], [])
|
||||
},
|
||||
{
|
||||
key: 'cumulativeElectricity',
|
||||
title: '累计用电量',
|
||||
unit: 'kWh',
|
||||
color: '#E6A23C',
|
||||
option: createLineOption('用电量', '#E6A23C', [], [])
|
||||
color: techChartSeriesColors[2],
|
||||
option: createLineOption('用电量', techChartSeriesColors[2], [], [])
|
||||
},
|
||||
{
|
||||
key: 'current',
|
||||
title: '电流值',
|
||||
unit: 'A',
|
||||
color: '#F56C6C',
|
||||
option: createLineOption('电流', '#F56C6C', [], [])
|
||||
color: techChartSeriesColors[3],
|
||||
option: createLineOption('电流', techChartSeriesColors[3], [], [])
|
||||
},
|
||||
{
|
||||
key: 'internalTemperature',
|
||||
title: '内部温度',
|
||||
unit: '℃',
|
||||
color: '#909399',
|
||||
option: createLineOption('内部温度', '#909399', [], [])
|
||||
color: techChartSeriesColors[4],
|
||||
option: createLineOption('内部温度', techChartSeriesColors[4], [], [])
|
||||
},
|
||||
{
|
||||
key: 'powerFactor',
|
||||
title: '功率因数',
|
||||
unit: '',
|
||||
color: '#1ABC9C',
|
||||
option: createLineOption('功率因数', '#1ABC9C', [], [])
|
||||
color: techChartSeriesColors[5],
|
||||
option: createLineOption('功率因数', techChartSeriesColors[5], [], [])
|
||||
}
|
||||
])
|
||||
|
||||
@@ -630,26 +627,27 @@
|
||||
gap: 12px;
|
||||
margin-bottom: 16px;
|
||||
padding: 16px;
|
||||
background-color: var(--el-bg-color-overlay, #ffffff);
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--el-border-color, #e4e7ed);
|
||||
background: var(--tech-panel-soft);
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--tech-border);
|
||||
}
|
||||
|
||||
.toolbar-label {
|
||||
font-size: 14px;
|
||||
color: var(--el-text-color-regular, #606266);
|
||||
color: var(--tech-text-muted);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.chart-card {
|
||||
background-color: var(--el-bg-color-overlay, #ffffff);
|
||||
border-radius: 8px;
|
||||
background: var(--tech-panel-soft);
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
margin-bottom: 16px;
|
||||
border: 1px solid var(--tech-border);
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
box-shadow: 0 0 18px rgba(0, 212, 255, 0.12);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -663,12 +661,12 @@
|
||||
.chart-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary, #303133);
|
||||
color: var(--tech-text-strong);
|
||||
}
|
||||
|
||||
.chart-unit {
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-regular, #606266);
|
||||
color: var(--tech-text-muted);
|
||||
}
|
||||
|
||||
.chart {
|
||||
|
||||
@@ -396,9 +396,7 @@
|
||||
return {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
backgroundColor: 'rgba(15, 23, 42, 0.9)',
|
||||
borderColor: 'transparent',
|
||||
textStyle: { color: '#fff' }
|
||||
...techChartTooltip
|
||||
},
|
||||
grid: {
|
||||
left: 36,
|
||||
|
||||
Reference in New Issue
Block a user