From acd6bbae394c997523b5051d019e584db1845c4c Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期三, 17 六月 2026 14:29:04 +0800
Subject: [PATCH] 样式修改
---
src/views/customerService/feedbackRegistration/components/formDia.vue | 34
src/assets/styles/sidebar.scss | 581 +-----
src/layout/components/Navbar.vue | 844 +++++----
src/layout/index.vue | 23
src/components/Screenfull/index.vue | 2
src/layout/components/TagsView/index.vue | 246 +-
src/views/customerService/components/viewDia.vue | 195 +
src/assets/styles/variables.module.scss | 74
src/store/modules/settings.js | 35
src/utils/theme.js | 136 +
script_backup.txt | 177 ++
src/layout/components/NotificationCenter/index.vue | 165 +
src/views/login.vue | 1796 ++++++++++++---------
src/layout/components/Sidebar/Logo.vue | 89
src/layout/components/AppMain.vue | 46
src/layout/components/Sidebar/index.vue | 97
src/layout/components/Settings/index.vue | 437 ++--
src/layout/components/Sidebar/SidebarItem.vue | 48
18 files changed, 2,622 insertions(+), 2,403 deletions(-)
diff --git a/script_backup.txt b/script_backup.txt
new file mode 100644
index 0000000..10a5f49
--- /dev/null
+++ b/script_backup.txt
@@ -0,0 +1,177 @@
+<script setup>
+import { ElMessage } from "element-plus"
+import Cookies from "js-cookie"
+import { encrypt, decrypt } from "@/utils/jsencrypt"
+import useUserStore from "@/store/modules/user"
+import defaultBrandLogo from "@/assets/logo/logo.png"
+
+const userStore = useUserStore()
+const route = useRoute()
+const router = useRouter()
+
+const appTitle = String(import.meta.env.VITE_APP_TITLE || "鏁板瓧宸ュ巶 MOM 绯荤粺").trim()
+const companySubtitle = String(import.meta.env.VITE_LOGIN_SUBTITLE || "Digital Factory Operation Center").trim()
+const configuredLogo = String(import.meta.env.VITE_APP_LOGO || "").trim()
+const logoModules = import.meta.glob("/src/assets/logo/*.png", { eager: true })
+const brandIconUrl = `${import.meta.env.BASE_URL}favicon.ico`
+
+const redirect = ref("")
+const loading = ref(false)
+const now = ref(new Date())
+const brandLogoUrl = ref(defaultBrandLogo)
+
+const loginForm = ref({
+ username: "",
+ password: "",
+ rememberMe: false,
+})
+
+const companyName = computed(() => {
+ const currentFactoryName = String(userStore.currentFactoryName || "").trim()
+ return currentFactoryName || appTitle
+})
+
+const todayLabel = computed(() => {
+ const date = now.value
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`
+})
+
+const clockLabel = computed(() => {
+ const date = now.value
+ return `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`
+})
+
+watch(
+ route,
+ (newRoute) => {
+ redirect.value = String(newRoute.query?.redirect || "")
+ },
+ { immediate: true }
+)
+
+watch(
+ () => userStore.currentFactoryName,
+ () => updateBrandLogo(),
+ { immediate: true }
+)
+
+let timer = 0
+onMounted(() => {
+ timer = window.setInterval(() => {
+ now.value = new Date()
+ }, 1000)
+})
+
+onBeforeUnmount(() => {
+ if (timer) {
+ window.clearInterval(timer)
+ timer = 0
+ }
+})
+
+function pad(value) {
+ return String(value).padStart(2, "0")
+}
+
+function resolveConfiguredLogo() {
+ if (!configuredLogo) {
+ return ""
+ }
+
+ if (/^(https?:)?\/\//.test(configuredLogo) || configuredLogo.startsWith("data:")) {
+ return configuredLogo
+ }
+
+ const cleanPath = configuredLogo.replace(/^\/+/, "")
+ const fullPath = cleanPath.startsWith("src/") ? `/${cleanPath}` : `/src/${cleanPath}`
+ const localLogo = logoModules[fullPath]
+
+ if (localLogo && localLogo.default) {
+ return localLogo.default
+ }
+
+ if (configuredLogo.startsWith("/")) {
+ return configuredLogo
+ }
+
+ return `${import.meta.env.BASE_URL}${cleanPath}`
+}
+
+function updateBrandLogo() {
+ const logoFromConfig = resolveConfiguredLogo()
+ if (logoFromConfig) {
+ brandLogoUrl.value = logoFromConfig
+ return
+ }
+
+ const currentFactoryName = String(userStore.currentFactoryName || "").trim()
+ if (!currentFactoryName) {
+ brandLogoUrl.value = defaultBrandLogo
+ return
+ }
+
+ const factoryLogoPath = `/src/assets/logo/${currentFactoryName}.png`
+ const matched = logoModules[factoryLogoPath]
+ brandLogoUrl.value = matched && matched.default ? matched.default : defaultBrandLogo
+}
+
+function handleLogoError() {
+ brandLogoUrl.value = defaultBrandLogo
+}
+
+function handleRememberCookie() {
+ if (!loginForm.value.rememberMe) {
+ Cookies.remove("username")
+ Cookies.remove("password")
+ Cookies.remove("rememberMe")
+ return
+ }
+
+ Cookies.set("username", loginForm.value.username, { expires: 30 })
+ Cookies.set("password", encrypt(loginForm.value.password), { expires: 30 })
+ Cookies.set("rememberMe", "true", { expires: 30 })
+}
+
+function getCookie() {
+ const username = Cookies.get("username")
+ const password = Cookies.get("password")
+ const rememberMe = Cookies.get("rememberMe")
+
+ loginForm.value.username = username || ""
+ loginForm.value.password = password ? decrypt(password) : ""
+ loginForm.value.rememberMe = rememberMe === "true"
+}
+
+function handleLogin() {
+ if (!loginForm.value.username) {
+ ElMessage.error("璇疯緭鍏ヨ处鍙�")
+ return
+ }
+ if (!loginForm.value.password) {
+ ElMessage.error("璇疯緭鍏ュ瘑鐮�")
+ return
+ }
+
+ loading.value = true
+ handleRememberCookie()
+ userStore
+ .loginCheckFactory(loginForm.value)
+ .then(() => {
+ const query = route.query
+ const otherQueryParams = Object.keys(query).reduce((acc, cur) => {
+ if (cur !== "redirect") {
+ acc[cur] = query[cur]
+ }
+ return acc
+ }, {})
+ router.push({ path: redirect.value || "/", query: otherQueryParams })
+ })
+ .catch(() => {})
+ .finally(() => {
+ loading.value = false
+ })
+}
+
+getCookie()
+</script>
+
\ No newline at end of file
diff --git a/src/assets/styles/sidebar.scss b/src/assets/styles/sidebar.scss
index 685a0eb..677396c 100644
--- a/src/assets/styles/sidebar.scss
+++ b/src/assets/styles/sidebar.scss
@@ -23,70 +23,8 @@
padding: 0;
font-size: 0;
background: var(--sidebar-bg);
- border-right: 1px solid rgba(255, 255, 255, 0.08);
- box-shadow: 8px 0 24px rgba(15, 23, 42, 0.08);
- isolation: isolate;
-
- &::before {
- content: "";
- position: absolute;
- inset: -28% -52% -18% -38%;
- z-index: 0;
- pointer-events: none;
- background:
- radial-gradient(circle at 9% 12%, rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.62), transparent 44%),
- radial-gradient(circle at 87% 18%, rgba(56, 189, 248, 0.4), transparent 48%),
- radial-gradient(circle at 20% 82%, rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.3), transparent 43%),
- radial-gradient(circle at 66% 62%, rgba(125, 211, 252, 0.24), transparent 50%),
- conic-gradient(
- from 210deg at 58% 38%,
- rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.14) 0deg,
- rgba(56, 189, 248, 0.05) 76deg,
- rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.16) 180deg,
- rgba(125, 211, 252, 0.04) 290deg,
- rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.14) 360deg
- );
- filter: blur(7px) saturate(1.24) contrast(1.05);
- opacity: 0.96;
- transform: translate3d(0, 0, 0);
- transform-origin: 44% 58%;
- animation:
- sidebarAuroraDrift 17.9s cubic-bezier(0.31, 0.03, 0.18, 0.99) infinite,
- sidebarAuroraBreath 9.7s ease-in-out infinite,
- sidebarAuroraSkew 6.9s steps(23, end) infinite;
- }
-
- &::after {
- content: "";
- position: absolute;
- inset: 0;
- z-index: 0;
- pointer-events: none;
- background:
- linear-gradient(
- 108deg,
- transparent 10%,
- rgba(255, 255, 255, 0.17) 34%,
- rgba(255, 255, 255, 0.04) 48%,
- transparent 72%
- ),
- linear-gradient(
- 202deg,
- rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.24) 0%,
- transparent 34%,
- rgba(56, 189, 248, 0.18) 66%,
- transparent 100%
- ),
- radial-gradient(circle at 74% 12%, rgba(125, 211, 252, 0.25), transparent 50%),
- radial-gradient(circle at 22% 84%, rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.14), transparent 56%);
- background-size: 236% 100%, 186% 186%, 164% 164%, 180% 180%;
- background-position: 224% 0, 14% 16%, 78% 10%, 18% 82%;
- opacity: 0.52;
- transform: translate3d(0, 0, 0);
- animation:
- sidebarSheenSweep 13.1s linear infinite,
- sidebarSheenJitter 4.7s steps(31, end) infinite;
- }
+ border-right: 1px solid var(--surface-border);
+ box-shadow: var(--shadow-md);
> * {
position: relative;
@@ -112,7 +50,7 @@
&.has-logo {
.el-scrollbar {
- height: calc(100% - 78px);
+ height: calc(100% - 64px);
}
}
@@ -130,117 +68,111 @@
border: none !important;
height: 100%;
width: 100% !important;
- padding: 10px 0 16px;
- border-radius: 0;
+ padding: 12px 0;
background: transparent !important;
- box-shadow: none;
- backdrop-filter: none;
}
.el-menu-item,
- .el-sub-menu__title,
.menu-title {
overflow: hidden !important;
text-overflow: ellipsis !important;
white-space: nowrap !important;
}
- .el-menu-item .el-menu-tooltip__trigger {
- display: inline-flex !important;
- width: 100%;
+ .submenu-title-noDropdown,
+ .el-menu-item {
+ display: flex;
align-items: center;
}
.submenu-title-noDropdown,
.el-sub-menu__title,
.el-menu-item {
- min-width: 0 !important;
- width: calc(100% - 24px) !important;
- margin: 0 12px 8px !important;
- height: 50px;
- line-height: 50px;
- border-radius: 14px;
+ width: calc(100% - 16px) !important;
+ margin: 4px 8px !important;
+ height: 44px;
+ line-height: 44px;
+ border-radius: var(--radius-md);
padding-left: 16px !important;
- padding-right: 36px !important;
+ padding-right: 36px !important; // 棰勭暀绠ご浣嶇疆
box-sizing: border-box;
- transition: all 0.28s ease;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
color: var(--sidebar-text);
- background: linear-gradient(128deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.01));
- border: 1px solid rgba(255, 255, 255, 0.06) !important;
+ background: transparent;
+ border: none !important;
position: relative;
- overflow: hidden;
+
+ .svg-icon {
+ margin-right: 12px;
+ width: 18px;
+ height: 18px;
+ vertical-align: middle;
+ flex-shrink: 0;
+ transition: transform 0.3s ease;
+ }
}
- .submenu-title-noDropdown::after,
- .el-sub-menu__title::after,
- .el-menu-item::after {
- content: "";
- position: absolute;
- inset: 0;
- background: linear-gradient(115deg, transparent 12%, rgba(255, 255, 255, 0.16), transparent 78%);
- transform: translateX(-100%);
- opacity: 0;
- transition: transform 0.45s ease, opacity 0.26s ease;
- pointer-events: none;
+ .el-sub-menu {
+ &.is-opened {
+ > .el-sub-menu__title {
+ color: var(--menu-active-text) !important;
+
+ .el-sub-menu__icon-arrow {
+ transform: rotate(180deg) !important;
+ color: var(--menu-active-text) !important;
+ }
+ }
+ }
+
+ .el-sub-menu__icon-arrow {
+ position: absolute !important;
+ right: 16px !important;
+ top: 50% !important;
+ margin-top: -6px !important;
+ width: 12px !important;
+ height: 12px !important;
+ font-size: 12px !important;
+ display: inline-block !important;
+ transition: transform 0.3s ease !important;
+ color: var(--sidebar-text) !important;
+ z-index: 2;
+ }
}
.submenu-title-noDropdown:hover,
.el-sub-menu__title:hover,
.el-menu-item:hover {
- background: linear-gradient(128deg, rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.28), rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.08)) !important;
- border-color: rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.32) !important;
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18), 0 8px 18px rgba(8, 36, 76, 0.24);
- transform: translateX(3px);
+ background: var(--menu-hover) !important;
+ color: var(--menu-active-text) !important;
+
+ .svg-icon {
+ transform: scale(1.1);
+ }
}
- .submenu-title-noDropdown:hover::after,
- .el-sub-menu__title:hover::after,
- .el-menu-item:hover::after,
- .el-menu-item.is-active::after,
- .el-sub-menu.is-active > .el-sub-menu__title::after {
- transform: translateX(100%);
- opacity: 1;
- }
+ .el-menu-item.is-active,
+ .el-sub-menu.is-active > .el-sub-menu__title {
+ color: var(--menu-active-text) !important;
+ background: var(--menu-active-bg) !important;
+ box-shadow: var(--menu-active-glow);
+ font-weight: 600;
- & .theme-light .is-active > .el-sub-menu__title,
- & .theme-dark .is-active > .el-sub-menu__title,
- & .el-menu-item.is-active {
- color: #fff !important;
- background: var(--menu-active-bg, linear-gradient(135deg, var(--el-color-primary), var(--el-color-primary-light-3))) !important;
- background-size: 180% 180%;
- box-shadow: var(--menu-active-glow, 0 10px 24px rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.34));
- border-color: rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.5) !important;
- animation: sidebarActiveFlow 4.6s ease infinite;
+ .svg-icon {
+ color: var(--menu-active-text) !important;
+ }
}
& .nest-menu .el-sub-menu > .el-sub-menu__title,
& .el-sub-menu .el-menu-item {
- min-width: 0 !important;
- width: calc(100% - 24px) !important;
- margin: 0 12px 8px !important;
- height: 46px;
- line-height: 46px;
- padding-left: 14px !important;
- padding-right: 14px !important;
- border-radius: 12px;
- transition: all 0.24s ease;
- color: var(--sidebar-text);
- border: 1px solid rgba(255, 255, 255, 0.06) !important;
- background: linear-gradient(128deg, rgba(255, 255, 255, 0.04), rgba(255, 255, 255, 0.01));
-
- &:hover {
- background: linear-gradient(128deg, rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.24), rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.07)) !important;
- border-color: rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.3) !important;
- transform: translateX(2px);
- }
+ height: 40px;
+ line-height: 40px;
+ margin: 2px 8px !important;
+ padding-left: 44px !important; // 澧炲姞瀛愯彍鍗曠缉杩�
+ border-radius: var(--radius-sm);
+ font-size: 13px;
&.is-active {
- background: var(--menu-active-bg, linear-gradient(135deg, var(--el-color-primary), var(--el-color-primary-light-3))) !important;
- background-size: 180% 180%;
- color: #fff !important;
- font-weight: 500;
- box-shadow: var(--menu-active-glow, 0 10px 24px rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.34));
- animation: sidebarActiveFlow 4.6s ease infinite;
+ background: var(--menu-active-bg) !important;
}
}
}
@@ -248,99 +180,29 @@
.hideSidebar {
.sidebar-container {
width: var(--sidebar-collapsed-width) !important;
+
+ .el-menu-item,
+ .el-sub-menu__title {
+ padding: 0 !important;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin: 4px 8px !important;
+ width: calc(var(--sidebar-collapsed-width) - 16px) !important;
+
+ .svg-icon {
+ margin-right: 0;
+ }
+
+ .menu-title,
+ .el-sub-menu__icon-arrow {
+ display: none;
+ }
+ }
}
.main-container {
margin-left: var(--sidebar-collapsed-width);
- }
-
- .submenu-title-noDropdown {
- padding: 0 !important;
- position: relative;
- display: flex !important;
- align-items: center;
- justify-content: center;
-
- .svg-icon {
- margin-right: 0;
- }
-
- .el-tooltip {
- padding: 0 !important;
- display: inline-flex !important;
- align-items: center;
- justify-content: center;
- width: 100%;
-
- .svg-icon {
- margin-left: 0;
- }
- }
-
- .el-menu-tooltip__trigger {
- width: 100%;
- display: inline-flex !important;
- align-items: center;
- justify-content: center;
-
- .svg-icon {
- width: 22px;
- height: 22px;
- margin-right: 0;
- flex-shrink: 0;
- }
- }
- }
-
- .el-sub-menu {
- overflow: hidden;
-
- & > .el-sub-menu__title {
- padding: 0 !important;
- display: flex !important;
- align-items: center;
- justify-content: center;
-
- .svg-icon {
- margin-left: 0;
- margin-right: 0;
- }
- }
- }
-
- .el-menu--collapse {
- width: 100% !important;
- padding: 12px 0 16px;
-
- > .el-menu-item,
- .el-sub-menu {
- & > .el-sub-menu__title,
- &.el-menu-item {
- width: calc(100% - 12px) !important;
- margin: 0 6px 8px !important;
- padding-left: 0 !important;
- padding-right: 0 !important;
- box-sizing: border-box;
- display: flex !important;
- align-items: center;
- justify-content: center;
-
- .svg-icon {
- width: 22px;
- height: 22px;
- margin-right: 0;
- flex-shrink: 0;
- }
-
- & > span {
- height: 0;
- width: 0;
- overflow: hidden;
- visibility: hidden;
- display: inline-block;
- }
- }
- }
}
}
@@ -378,139 +240,61 @@
.el-menu--vertical {
& > .el-menu {
.svg-icon {
- margin-right: 10px;
+ margin-right: 12px;
}
}
.nest-menu .el-sub-menu > .el-sub-menu__title,
.el-menu-item {
min-width: 0 !important;
- margin: 0 10px 8px;
+ margin: 4px 10px;
width: calc(100% - 20px);
- height: 46px;
- line-height: 46px;
- padding-left: 12px !important;
- padding-right: 12px !important;
+ height: 44px;
+ line-height: 44px;
+ padding-left: 16px !important;
+ padding-right: 16px !important;
box-sizing: border-box;
- border-radius: 12px;
+ border-radius: var(--radius-md);
color: var(--sidebar-text);
- border: 1px solid rgba(255, 255, 255, 0.06) !important;
- background: linear-gradient(128deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.01));
- transition: all 0.24s ease;
+ background: transparent;
+ transition: all 0.2s ease;
&:hover {
- background: linear-gradient(128deg, rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.24), rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.07)) !important;
- border-color: rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.3) !important;
- transform: translateX(2px);
+ background: var(--menu-hover) !important;
+ color: #fff !important;
}
&.is-active {
- background: var(--menu-active-bg, linear-gradient(135deg, var(--el-color-primary), var(--el-color-primary-light-3))) !important;
- background-size: 180% 180%;
- color: #fff !important;
- border-radius: 12px;
- box-shadow: var(--menu-active-glow, 0 10px 24px rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.34));
- border-color: rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.5) !important;
- animation: sidebarActiveFlow 4.6s ease infinite;
+ background: var(--menu-active-bg) !important;
+ color: var(--menu-active-text) !important;
+ font-weight: 600;
+ box-shadow: var(--menu-active-glow);
}
}
> .el-menu--popup {
max-height: 100vh;
overflow: hidden;
- padding: 10px;
- border-radius: 14px;
- position: relative;
- isolation: isolate;
- border: 1px solid rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.26);
- box-shadow:
- 0 18px 40px rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.16),
- var(--shadow-md);
+ padding: 8px;
+ border-radius: var(--radius-lg);
+ border: 1px solid var(--surface-border);
+ box-shadow: var(--shadow-menu);
background: var(--sidebar-bg);
backdrop-filter: blur(16px);
- &::before {
- content: "";
- position: absolute;
- inset: -28% -52% -18% -38%;
- z-index: 0;
- pointer-events: none;
- background:
- radial-gradient(circle at 9% 12%, rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.62), transparent 44%),
- radial-gradient(circle at 87% 18%, rgba(56, 189, 248, 0.4), transparent 48%),
- radial-gradient(circle at 20% 82%, rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.3), transparent 43%),
- radial-gradient(circle at 66% 62%, rgba(125, 211, 252, 0.24), transparent 50%),
- conic-gradient(
- from 210deg at 58% 38%,
- rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.14) 0deg,
- rgba(56, 189, 248, 0.05) 76deg,
- rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.16) 180deg,
- rgba(125, 211, 252, 0.04) 290deg,
- rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.14) 360deg
- );
- filter: blur(7px) saturate(1.24) contrast(1.05);
- opacity: 0.96;
- transform: translate3d(0, 0, 0);
- transform-origin: 44% 58%;
- animation:
- sidebarAuroraDrift 17.9s cubic-bezier(0.31, 0.03, 0.18, 0.99) infinite,
- sidebarAuroraBreath 9.7s ease-in-out infinite,
- sidebarAuroraSkew 6.9s steps(23, end) infinite;
- }
-
- &::after {
- content: "";
- position: absolute;
- inset: 0;
- z-index: 0;
- pointer-events: none;
- background:
- linear-gradient(
- 108deg,
- transparent 10%,
- rgba(255, 255, 255, 0.17) 34%,
- rgba(255, 255, 255, 0.04) 48%,
- transparent 72%
- ),
- linear-gradient(
- 202deg,
- rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.24) 0%,
- transparent 34%,
- rgba(56, 189, 248, 0.18) 66%,
- transparent 100%
- ),
- radial-gradient(circle at 74% 12%, rgba(125, 211, 252, 0.25), transparent 50%),
- radial-gradient(circle at 22% 84%, rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.14), transparent 56%);
- background-size: 236% 100%, 186% 186%, 164% 164%, 180% 180%;
- background-position: 224% 0, 14% 16%, 78% 10%, 18% 82%;
- opacity: 0.52;
- transform: translate3d(0, 0, 0);
- animation:
- sidebarSheenSweep 13.1s linear infinite,
- sidebarSheenJitter 4.7s steps(31, end) infinite;
- }
-
- > * {
- position: relative;
- z-index: 1;
- }
-
> .el-menu {
- max-height: calc(100vh - 20px);
+ max-height: calc(100vh - 16px);
overflow-y: auto;
overflow-x: hidden;
-
- &::-webkit-scrollbar-track-piece {
- background: var(--surface-muted);
- }
+ background: transparent !important;
&::-webkit-scrollbar {
- width: 5px;
+ width: 4px;
}
&::-webkit-scrollbar-thumb {
- background: var(--accent-light);
- border-radius: 10px;
+ background: var(--sidebar-muted);
+ border-radius: 4px;
}
}
}
@@ -525,140 +309,5 @@
}
100% {
background-position: 0% 50%;
- }
-}
-
-@keyframes sidebarAuroraDrift {
- 0% {
- transform: translate3d(-6.3%, -1.8%, 0) scale(1.05) rotate(-1.8deg);
- }
- 6% {
- transform: translate3d(2.2%, -4.6%, 0) scale(1.08) rotate(0.7deg);
- }
- 17% {
- transform: translate3d(-3.7%, 4.4%, 0) scale(1.11) rotate(2deg);
- }
- 27% {
- transform: translate3d(5.6%, 1.2%, 0) scale(1.03) rotate(-1deg);
- }
- 39% {
- transform: translate3d(-4.8%, -3.1%, 0) scale(1.09) rotate(1.5deg);
- }
- 52% {
- transform: translate3d(2.9%, 4.8%, 0) scale(1.04) rotate(-1.4deg);
- }
- 64% {
- transform: translate3d(-6.4%, 0.3%, 0) scale(1.08) rotate(0.5deg);
- }
- 73% {
- transform: translate3d(4.8%, -3.9%, 0) scale(1.05) rotate(1.6deg);
- }
- 81% {
- transform: translate3d(-2.4%, 2.9%, 0) scale(1.1) rotate(-0.8deg);
- }
- 92% {
- transform: translate3d(3.7%, -1.7%, 0) scale(1.06) rotate(-1.6deg);
- }
- 100% {
- transform: translate3d(-5.9%, 0.8%, 0) scale(1.08) rotate(1.2deg);
- }
-}
-
-@keyframes sidebarAuroraBreath {
- 0% {
- opacity: 0.76;
- filter: blur(5px) saturate(1.08);
- }
- 15% {
- opacity: 1;
- filter: blur(7px) saturate(1.28);
- }
- 37% {
- opacity: 0.84;
- filter: blur(8px) saturate(1.12);
- }
- 61% {
- opacity: 0.98;
- filter: blur(6px) saturate(1.24);
- }
- 83% {
- opacity: 0.86;
- filter: blur(7px) saturate(1.16);
- }
- 100% {
- opacity: 0.94;
- filter: blur(6px) saturate(1.2);
- }
-}
-
-@keyframes sidebarAuroraSkew {
- 0% {
- transform-origin: 44% 58%;
- }
- 21% {
- transform-origin: 62% 42%;
- }
- 43% {
- transform-origin: 31% 66%;
- }
- 66% {
- transform-origin: 68% 74%;
- }
- 100% {
- transform-origin: 39% 45%;
- }
-}
-
-@keyframes sidebarSheenSweep {
- 0% {
- background-position: 232% 0, 10% 18%, 80% 12%, 20% 82%;
- }
- 8% {
- background-position: 186% 0, 16% 30%, 74% 18%, 28% 74%;
- }
- 21% {
- background-position: 116% 0, 34% 10%, 62% 26%, 18% 64%;
- }
- 37% {
- background-position: 52% 0, 50% 24%, 46% 12%, 32% 58%;
- }
- 52% {
- background-position: -4% 0, 34% 54%, 22% 22%, 12% 46%;
- }
- 69% {
- background-position: -62% 0, 14% 36%, 32% 34%, 24% 56%;
- }
- 84% {
- background-position: -106% 0, 20% 20%, 46% 20%, 34% 70%;
- }
- 100% {
- background-position: -136% 0, 10% 18%, 80% 12%, 20% 82%;
- }
-}
-
-@keyframes sidebarSheenJitter {
- 0% {
- opacity: 0.28;
- transform: translate3d(0, 0, 0);
- }
- 17% {
- opacity: 0.56;
- transform: translate3d(1.8%, -0.5%, 0);
- }
- 38% {
- opacity: 0.34;
- transform: translate3d(-1.2%, 0.8%, 0);
- }
- 63% {
- opacity: 0.6;
- transform: translate3d(2.3%, -0.3%, 0);
- }
- 81% {
- opacity: 0.3;
- transform: translate3d(-1.6%, 0.7%, 0);
- }
- 100% {
- opacity: 0.52;
- transform: translate3d(2%, -0.1%, 0);
}
}
diff --git a/src/assets/styles/variables.module.scss b/src/assets/styles/variables.module.scss
index 461b545..7f8d488 100644
--- a/src/assets/styles/variables.module.scss
+++ b/src/assets/styles/variables.module.scss
@@ -73,51 +73,51 @@
--content-radius: 16px;
--layout-header-z: 20;
- --el-color-primary: #2563eb;
- --el-color-primary-rgb: 37, 99, 235;
+ --el-color-primary: #374d77;
+ --el-color-primary-rgb: 37, 89, 163;
--el-color-success: #14b8a6;
--el-color-warning: #f59e0b;
--el-color-danger: #ef4444;
- --sidebar-bg: linear-gradient(180deg, #0e2a4f 0%, #123e69 55%, #0e2a4f 100%);
- --sidebar-text: rgba(234, 242, 255, 0.82);
- --sidebar-muted: rgba(234, 242, 255, 0.82);
- --menu-hover: rgba(147, 197, 253, 0.2);
- --menu-active-bg: linear-gradient(135deg, #2f80ff 0%, #38bdf8 100%);
- --menu-active-text: #f8fbff;
- --menu-surface: linear-gradient(180deg, rgba(13, 43, 79, 0.97) 0%, rgba(8, 28, 52, 0.94) 100%);
- --menu-active-glow: 0 8px 18px rgba(56, 139, 255, 0.28);
+ --sidebar-bg: #1e293b;
+ --sidebar-text: #94a3b8;
+ --sidebar-muted: #64748b;
+ --menu-hover: rgba(255, 255, 255, 0.05);
+ --menu-active-bg: #3b82f6;
+ --menu-active-text: #ffffff;
+ --menu-surface: #1e293b;
+ --menu-active-glow: 0 4px 12px rgba(59, 130, 246, 0.3);
- --app-bg: #f3f7fc;
- --app-bg-accent: #eef5ff;
- --surface-base: rgba(255, 255, 255, 0.92);
- --surface-soft: rgba(255, 255, 255, 0.88);
- --surface-muted: #f5f9ff;
- --surface-border: rgba(148, 163, 184, 0.18);
- --surface-border-strong: rgba(96, 165, 250, 0.34);
- --text-primary: #1e293b;
+ --app-bg: #f8fafc;
+ --app-bg-accent: #f1f5f9;
+ --surface-base: #ffffff;
+ --surface-soft: rgba(255, 255, 255, 0.9);
+ --surface-muted: #f1f5f9;
+ --surface-border: #e2e8f0;
+ --surface-border-strong: #cbd5e1;
+ --text-primary: #0f172a;
--text-secondary: #334155;
--text-tertiary: #64748b;
- --shadow-sm: 0 12px 32px rgba(15, 23, 42, 0.06);
- --shadow-md: 0 20px 42px rgba(15, 23, 42, 0.1);
- --shadow-menu: 0 16px 36px rgba(8, 27, 58, 0.26);
- --radius-lg: 20px;
- --radius-md: 16px;
- --radius-sm: 12px;
- --radius-xs: 10px;
+ --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
+ --shadow-menu: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
+ --radius-lg: 12px;
+ --radius-md: 8px;
+ --radius-sm: 6px;
+ --radius-xs: 4px;
- --navbar-bg: rgba(255, 255, 255, 0.86);
- --navbar-text: #1f3658;
- --navbar-hover: rgba(37, 99, 235, 0.08);
+ --navbar-bg: rgba(30, 41, 59, 0.85);
+ --navbar-text: #f8fafc;
+ --navbar-hover: rgba(255, 255, 255, 0.08);
- --tags-bg: transparent;
- --tags-item-bg: rgba(255, 255, 255, 0.9);
- --tags-item-border: rgba(148, 163, 184, 0.22);
- --tags-item-text: #334155;
- --tags-item-hover: #f4f8ff;
- --tags-close-hover: rgba(37, 99, 235, 0.16);
+ --tags-bg: #f8fafc;
+ --tags-item-bg: #ffffff;
+ --tags-item-border: #e2e8f0;
+ --tags-item-text: #475569;
+ --tags-item-hover: #f1f5f9;
+ --tags-close-hover: rgba(239, 68, 68, 0.1);
- --accent-primary: #2563eb;
+ --accent-primary: #374d77;
--accent-light: #3b82f6;
--accent-lighter: #60a5fa;
@@ -175,7 +175,7 @@
.menu-title {
color: var(--sidebar-text);
}
-
+
.el-menu-item.is-active,
.el-menu-item.is-active .menu-title {
color: var(--menu-active-text) !important;
@@ -185,7 +185,7 @@
& .theme-dark .el-sub-menu .el-menu-item {
background-color: var(--el-bg-color) !important;
}
-
+
& .theme-dark .el-sub-menu .el-menu-item.is-active {
background-color: var(--menu-active-bg) !important;
}
diff --git a/src/components/Screenfull/index.vue b/src/components/Screenfull/index.vue
index cf23223..62ec756 100644
--- a/src/components/Screenfull/index.vue
+++ b/src/components/Screenfull/index.vue
@@ -14,7 +14,7 @@
.screenfull-svg {
display: inline-block;
cursor: pointer;
- fill: #5a5e66;
+ fill: currentColor;
width: 20px;
height: 20px;
vertical-align: 10px;
diff --git a/src/layout/components/AppMain.vue b/src/layout/components/AppMain.vue
index a511014..82aa810 100644
--- a/src/layout/components/AppMain.vue
+++ b/src/layout/components/AppMain.vue
@@ -37,29 +37,29 @@
</script>
<style lang="scss" scoped>
-.app-main {
- min-height: calc(100vh - var(--topbar-height));
- width: 100%;
- position: relative;
- overflow: visible;
- background: transparent;
-}
-
-.route-view-wrapper {
- width: 100%;
- height: 100%;
- padding: var(--content-gap);
- padding-top: 0;
-}
-
-.fixed-header + .app-main {
- padding-top: 0;
-}
-
-.hasTagsView {
- .app-main {
- min-height: calc(100vh - var(--topbar-height) - var(--tagsbar-height));
- }
+.app-main {
+ min-height: calc(100vh - var(--topbar-height));
+ width: 100%;
+ position: relative;
+ overflow: visible;
+ background: transparent;
+}
+
+.route-view-wrapper {
+ width: 100%;
+ height: 100%;
+ padding: var(--content-gap);
+ padding-top: 0;
+}
+
+.fixed-header + .app-main {
+ padding-top: 0;
+}
+
+.hasTagsView {
+ .app-main {
+ min-height: calc(100vh - var(--topbar-height) - var(--tagsbar-height));
+ }
.fixed-header + .app-main {
padding-top: 0;
diff --git a/src/layout/components/Navbar.vue b/src/layout/components/Navbar.vue
index aae5330..15de4e1 100644
--- a/src/layout/components/Navbar.vue
+++ b/src/layout/components/Navbar.vue
@@ -1,81 +1,101 @@
<template>
<div class="navbar">
- <div class="left-zone">
- <hamburger
- id="hamburger-container"
- :is-active="appStore.sidebar.opened"
- class="hamburger-container"
- @toggleClick="toggleSideBar"
- />
- <breadcrumb
- v-if="!settingsStore.topNav"
- id="breadcrumb-container"
- class="breadcrumb-container"
- />
+ <div class="left-menu">
+ <hamburger id="hamburger-container"
+ :is-active="appStore.sidebar.opened"
+ class="hamburger-container"
+ @toggleClick="toggleSideBar" />
+ <breadcrumb v-if="!settingsStore.topNav"
+ id="breadcrumb-container"
+ class="breadcrumb-container" />
</div>
-
- <div class="center-zone">
- <el-icon class="search-icon" @click="openHeaderSearch"><Search /></el-icon>
- <el-input
- v-model="topSearchKeyword"
- placeholder="鎼滅储鑿滃崟 / 鍔熻兘 / 鏁版嵁"
- clearable
- @keyup.enter="openHeaderSearch"
- />
- <header-search
- ref="headerSearchRef"
- :keyword="topSearchKeyword"
- class="search-popup-trigger"
- />
- </div>
-
<div class="right-menu">
- <el-popover
- v-model:visible="notificationVisible"
- :width="500"
- placement="bottom-end"
- trigger="click"
- :popper-options="{ modifiers: [{ name: 'offset', options: { offset: [0, 10] } }] }"
- popper-class="notification-popover"
- >
- <template #reference>
- <div class="notification-container right-menu-item hover-effect">
- <el-badge :value="unreadCount" :hidden="unreadCount === 0" class="notification-badge">
- <el-icon :size="18">
- <Bell />
- </el-icon>
- </el-badge>
- </div>
- </template>
- <NotificationCenter @unreadCountChange="handleUnreadCountChange" ref="notificationCenterRef" />
- </el-popover>
-
- <div class="right-menu-item hover-effect screenfull-container">
- <screenfull />
+ <div class="search-wrapper">
+ <el-icon class="search-icon"
+ @click="openHeaderSearch">
+ <Search />
+ </el-icon>
+ <el-input v-model="topSearchKeyword"
+ placeholder="蹇�熸悳绱�..."
+ clearable
+ @keyup.enter="openHeaderSearch" />
+ <header-search ref="headerSearchRef"
+ :keyword="topSearchKeyword"
+ class="search-popup-trigger" />
</div>
-
- <div class="avatar-container">
- <el-dropdown @command="handleCommand" class="right-menu-item hover-effect" trigger="click">
- <div class="avatar-wrapper">
- <div class="user-summary">
- <div class="user-name">{{ userStore.nickName || userStore.name || "绠$悊鍛�" }}</div>
- <div class="user-role">{{ userStore.roleName || "绯荤粺鐢ㄦ埛" }}</div>
+ <div class="action-icons">
+ <el-popover v-model:visible="notificationVisible"
+ :width="500"
+ placement="bottom-end"
+ trigger="click"
+ :popper-options="{ modifiers: [{ name: 'offset', options: { offset: [0, 10] } }] }"
+ popper-class="notification-popover">
+ <template #reference>
+ <div class="notification-container right-menu-item hover-effect">
+ <el-badge :value="unreadCount"
+ :hidden="unreadCount === 0"
+ class="notification-badge">
+ <el-icon :size="18">
+ <Bell />
+ </el-icon>
+ </el-badge>
</div>
- <img :src="userStore.avatar" class="user-avatar" />
- <el-icon><caret-bottom /></el-icon>
+ </template>
+ <NotificationCenter @unreadCountChange="handleUnreadCountChange"
+ ref="notificationCenterRef" />
+ </el-popover>
+ <div class="right-menu-item hover-effect screenfull-container">
+ <screenfull />
+ </div>
+ </div>
+ <div class="user-profile">
+ <el-dropdown @command="handleCommand"
+ class="profile-dropdown"
+ trigger="click">
+ <div class="profile-trigger">
+ <div class="avatar-inner">
+ <img :src="userStore.avatar"
+ class="user-avatar" />
+ <div class="user-status-dot"></div>
+ </div>
+ <div class="profile-trigger-text">
+ <div class="user-name">{{ userStore.nickName || userStore.name || "绠$悊鍛�" }}</div>
+ </div>
+ <el-icon class="caret-icon"><caret-bottom /></el-icon>
</div>
<template #dropdown>
- <el-dropdown-menu>
- <router-link to="/user/profile">
- <el-dropdown-item>涓汉涓績</el-dropdown-item>
- </router-link>
- <el-dropdown-item command="setLayout" v-if="settingsStore.showSettings">
- <span>甯冨眬璁剧疆</span>
- </el-dropdown-item>
- <el-dropdown-item divided command="logout">
- <span>閫�鍑虹櫥褰�</span>
- </el-dropdown-item>
- </el-dropdown-menu>
+ <div class="user-profile-dropdown-panel">
+ <div class="user-profile-dropdown-head">
+ <img :src="userStore.avatar"
+ class="user-profile-dropdown-avatar" />
+ <div class="user-profile-dropdown-meta">
+ <div class="user-profile-dropdown-name">{{ userStore.nickName || userStore.name || "绠$悊鍛�" }}</div>
+ <div class="user-profile-dropdown-role">{{ userStore.roleName || "绯荤粺鐢ㄦ埛" }}</div>
+ </div>
+ </div>
+ <el-dropdown-menu class="user-profile-dropdown">
+ <router-link to="/user/profile">
+ <el-dropdown-item>
+ <el-icon>
+ <User />
+ </el-icon>涓汉涓績
+ </el-dropdown-item>
+ </router-link>
+ <el-dropdown-item command="setLayout"
+ v-if="settingsStore.showSettings">
+ <el-icon>
+ <Setting />
+ </el-icon>甯冨眬璁剧疆
+ </el-dropdown-item>
+ <el-dropdown-item divided
+ command="logout"
+ class="logout-item">
+ <el-icon>
+ <SwitchButton />
+ </el-icon>閫�鍑虹櫥褰�
+ </el-dropdown-item>
+ </el-dropdown-menu>
+ </div>
</template>
</el-dropdown>
</div>
@@ -84,299 +104,441 @@
</template>
<script setup>
-import { ElMessageBox } from "element-plus";
-import { Bell, Search } from "@element-plus/icons-vue";
-import Breadcrumb from "@/components/Breadcrumb";
-import Hamburger from "@/components/Hamburger";
-import Screenfull from "@/components/Screenfull";
-import HeaderSearch from "@/components/HeaderSearch";
-import NotificationCenter from "./NotificationCenter/index.vue";
-import useAppStore from "@/store/modules/app";
-import useUserStore from "@/store/modules/user";
-import useSettingsStore from "@/store/modules/settings";
+ import { ElMessageBox } from "element-plus";
+ import { Bell, Search } from "@element-plus/icons-vue";
+ import Breadcrumb from "@/components/Breadcrumb";
+ import Hamburger from "@/components/Hamburger";
+ import Screenfull from "@/components/Screenfull";
+ import HeaderSearch from "@/components/HeaderSearch";
+ import NotificationCenter from "./NotificationCenter/index.vue";
+ import useAppStore from "@/store/modules/app";
+ import useUserStore from "@/store/modules/user";
+ import useSettingsStore from "@/store/modules/settings";
-const appStore = useAppStore();
-const userStore = useUserStore();
-const settingsStore = useSettingsStore();
+ const appStore = useAppStore();
+ const userStore = useUserStore();
+ const settingsStore = useSettingsStore();
-const topSearchKeyword = ref("");
-const headerSearchRef = ref(null);
-const notificationVisible = ref(false);
-const notificationCenterRef = ref(null);
-const unreadCount = ref(0);
+ const topSearchKeyword = ref("");
+ const headerSearchRef = ref(null);
+ const notificationVisible = ref(false);
+ const notificationCenterRef = ref(null);
+ const unreadCount = ref(0);
-function toggleSideBar() {
- appStore.toggleSideBar();
-}
-
-function openHeaderSearch() {
- headerSearchRef.value?.open(topSearchKeyword.value);
-}
-
-function handleCommand(command) {
- switch (command) {
- case "setLayout":
- setLayout();
- break;
- case "logout":
- logout();
- break;
- default:
- break;
+ function toggleSideBar() {
+ appStore.toggleSideBar();
}
-}
-function logout() {
- ElMessageBox.confirm("纭畾娉ㄩ攢骞堕��鍑虹郴缁熷悧锛�", "鎻愮ず", {
- confirmButtonText: "纭畾",
- cancelButtonText: "鍙栨秷",
- type: "warning",
- })
- .then(() => {
- userStore.logOut().then(() => {
- location.href = "/index";
- });
+ function openHeaderSearch() {
+ headerSearchRef.value?.open(topSearchKeyword.value);
+ }
+
+ function handleCommand(command) {
+ switch (command) {
+ case "setLayout":
+ setLayout();
+ break;
+ case "logout":
+ logout();
+ break;
+ default:
+ break;
+ }
+ }
+
+ function logout() {
+ ElMessageBox.confirm("纭畾娉ㄩ攢骞堕��鍑虹郴缁熷悧锛�", "鎻愮ず", {
+ confirmButtonText: "纭畾",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
})
- .catch(() => {});
-}
+ .then(() => {
+ userStore.logOut().then(() => {
+ location.href = "/index";
+ });
+ })
+ .catch(() => {});
+ }
-const emits = defineEmits(["setLayout"]);
-function setLayout() {
- emits("setLayout");
-}
+ const emits = defineEmits(["setLayout"]);
+ function setLayout() {
+ emits("setLayout");
+ }
-function handleUnreadCountChange(count) {
- unreadCount.value = count;
-}
+ function handleUnreadCountChange(count) {
+ unreadCount.value = count;
+ }
-let unreadCountTimer = null;
-onMounted(() => {
- nextTick(() => {
- if (notificationCenterRef.value) {
- notificationCenterRef.value.loadUnreadCount();
+ let unreadCountTimer = null;
+ onMounted(() => {
+ nextTick(() => {
+ if (notificationCenterRef.value) {
+ notificationCenterRef.value.loadUnreadCount();
+ }
+ });
+
+ unreadCountTimer = setInterval(() => {
+ if (notificationCenterRef.value) {
+ notificationCenterRef.value.loadUnreadCount();
+ }
+ }, 30000);
+ });
+
+ watch(notificationVisible, val => {
+ if (val && notificationCenterRef.value) {
+ nextTick(() => {
+ notificationCenterRef.value.loadMessages();
+ });
}
});
- unreadCountTimer = setInterval(() => {
- if (notificationCenterRef.value) {
- notificationCenterRef.value.loadUnreadCount();
+ onUnmounted(() => {
+ if (unreadCountTimer) {
+ clearInterval(unreadCountTimer);
}
- }, 30000);
-});
-
-watch(notificationVisible, (val) => {
- if (val && notificationCenterRef.value) {
- nextTick(() => {
- notificationCenterRef.value.loadMessages();
- });
- }
-});
-
-onUnmounted(() => {
- if (unreadCountTimer) {
- clearInterval(unreadCountTimer);
- }
-});
+ });
</script>
<style lang="scss" scoped>
-.navbar {
- height: var(--topbar-height);
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 14px;
- background: rgba(255, 255, 255, 0.86);
- border: 1px solid rgba(148, 163, 184, 0.18);
- border-radius: var(--content-radius);
- backdrop-filter: blur(16px);
- box-shadow: 0 8px 20px rgba(15, 23, 42, 0.05);
- padding: 0 18px;
-}
-
-.left-zone {
- flex: 0 1 420px;
- min-width: 0;
- display: flex;
- align-items: center;
- gap: 10px;
-}
-
-.hamburger-container {
- line-height: 36px;
- height: 36px;
- width: 36px;
- border-radius: 10px;
- display: flex;
- align-items: center;
- justify-content: center;
- color: var(--navbar-text);
-
- &:hover {
- background: var(--navbar-hover);
- }
-}
-
-.breadcrumb-container {
- min-width: 0;
-}
-
-.center-zone {
- width: clamp(360px, 34vw, 560px);
- min-width: 320px;
- height: 38px;
- border-radius: 999px;
- border: 1px solid rgba(148, 163, 184, 0.24);
- background: rgba(248, 251, 255, 0.92);
- display: flex;
- align-items: center;
- padding: 0 12px;
- gap: 8px;
-}
-
-.search-icon {
- color: #5b86c9;
- cursor: pointer;
-}
-
-.center-zone :deep(.el-input__wrapper) {
- border: 0;
- box-shadow: none !important;
- background: transparent;
- padding: 0;
-}
-
-.center-zone :deep(.el-input__inner) {
- color: #334155;
- font-size: 13px;
-}
-
-.search-popup-trigger :deep(.search-icon) {
- color: #5b86c9;
- font-size: 16px;
- cursor: pointer;
-}
-
-.right-menu {
- height: 100%;
- align-items: center;
- display: flex;
- gap: 14px;
-}
-
-.right-menu-item {
- display: flex;
- align-items: center;
- justify-content: center;
- color: var(--navbar-text);
- border-radius: 8px;
-}
-
-.hover-effect {
- cursor: pointer;
- transition: background 0.2s;
-
- &:hover {
- background: var(--navbar-hover);
- }
-}
-
-.notification-container,
-.screenfull-container {
- width: 36px;
- height: 36px;
-}
-
-.notification-badge :deep(.el-badge__content) {
- border: none;
-}
-
-.screenfull-container :deep(.svg-icon) {
- width: 16px;
- height: 16px;
- color: var(--navbar-text);
-}
-
-.avatar-container {
- height: 100%;
- display: flex;
- align-items: center;
-}
-
-.avatar-container :deep(.el-dropdown) {
- height: 100%;
- display: flex;
- align-items: center;
-}
-
-.avatar-wrapper {
- display: flex;
- align-items: center;
- gap: 10px;
- padding: 4px 10px 4px 8px;
- height: 44px;
- border-radius: 22px;
- background: rgba(255, 255, 255, 0.9);
- border: 1px solid rgba(148, 163, 184, 0.22);
-}
-
-.user-summary {
- display: flex;
- flex-direction: column;
- align-items: flex-end;
- gap: 2px;
-}
-
-.user-name {
- color: var(--text-primary);
- font-size: 13px;
- line-height: 1;
-}
-
-.user-role {
- color: var(--text-tertiary);
- font-size: 11px;
- line-height: 1;
-}
-
-.user-avatar {
- cursor: pointer;
- width: 36px;
- height: 36px;
- border-radius: 50%;
- border: 1px solid rgba(148, 163, 184, 0.3);
-}
-
-@media (max-width: 1200px) {
- .center-zone {
- display: none;
+ .navbar {
+ height: var(--topbar-height);
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0 24px;
+ background: var(--navbar-bg);
+ border-bottom: 1px solid rgba(255, 255, 255, 0.08);
+ backdrop-filter: blur(12px);
+ z-index: var(--layout-header-z);
}
- .user-summary {
- display: none;
+ .left-menu {
+ display: flex;
+ align-items: center;
+ gap: 12px;
}
-}
+
+ .hamburger-container {
+ height: 32px;
+ width: 32px;
+ border-radius: var(--radius-sm);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: var(--navbar-text);
+ cursor: pointer;
+ transition: all 0.2s ease;
+
+ &:hover {
+ background: var(--navbar-hover);
+ color: #fff;
+ }
+ }
+
+ .breadcrumb-container {
+ min-width: 0;
+
+ :deep(.el-breadcrumb__inner) {
+ color: var(--navbar-text) !important;
+ opacity: 0.85;
+
+ &:hover {
+ color: #fff !important;
+ opacity: 1;
+ }
+
+ a {
+ color: inherit !important;
+ font-weight: 500 !important;
+ }
+ }
+
+ :deep(.no-redirect) {
+ color: #fff !important;
+ font-weight: 600 !important;
+ opacity: 1;
+ }
+
+ :deep(.el-breadcrumb__separator) {
+ color: var(--navbar-text);
+ opacity: 0.5;
+ }
+ }
+
+ .right-menu {
+ display: flex;
+ align-items: center;
+ gap: 20px; // 澧炲姞澶х粍涔嬮棿鐨勯棿璺�
+
+ .search-wrapper {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ height: 34px;
+ padding: 0 12px;
+ background: var(--navbar-hover);
+ border: 1px solid var(--surface-border);
+ border-radius: 17px;
+ width: 240px; // 鎼滅储妗嗘洿鍔犵簿鑷村皬宸�
+ transition: all 0.3s ease;
+
+ &:focus-within {
+ width: 300px;
+ background: rgba(255, 255, 255, 0.1);
+ border-color: var(--accent-primary);
+ box-shadow: 0 0 0 2px rgba(var(--el-color-primary-rgb), 0.2);
+ }
+
+ .search-icon {
+ color: var(--sidebar-text);
+ font-size: 16px;
+ cursor: pointer;
+ }
+
+ :deep(.el-input__wrapper) {
+ background: transparent;
+ box-shadow: none !important;
+ padding: 0;
+ }
+
+ :deep(.el-input__inner) {
+ color: var(--navbar-text);
+ font-size: 13px;
+ height: 32px;
+
+ &::placeholder {
+ color: var(--sidebar-text);
+ }
+ }
+ }
+
+ .action-icons {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ padding-right: 16px;
+ border-right: 1px solid var(--surface-border); // 澧炲姞鍨傜洿鍒嗗壊绾�
+
+ .right-menu-item {
+ padding: 0 8px;
+ height: 34px;
+ display: flex;
+ align-items: center;
+ color: var(--navbar-text);
+ border-radius: var(--radius-sm);
+ transition: all 0.2s ease;
+ cursor: pointer;
+
+ &:hover {
+ background: var(--navbar-hover);
+ color: var(--menu-active-text);
+ }
+ }
+ }
+
+ .user-profile {
+ .profile-dropdown {
+ cursor: pointer;
+ }
+
+ .profile-trigger {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ height: 38px;
+ padding: 4px 10px 4px 6px;
+ border-radius: 999px;
+ border: 1px solid rgba(var(--el-color-primary-rgb), 0.32);
+ background: rgba(0, 0, 0, 0.16);
+ transition: 0.2s ease;
+
+ &:hover {
+ background: rgba(0, 0, 0, 0.24);
+ border-color: rgba(var(--el-color-primary-rgb), 0.58);
+ box-shadow: 0 0 0 2px rgba(var(--el-color-primary-rgb), 0.18);
+ }
+ }
+
+ .profile-trigger-text {
+ display: flex;
+ align-items: center;
+ max-width: 120px;
+ min-width: 0;
+ }
+
+ .user-name {
+ font-size: 13px;
+ font-weight: 700;
+ color: var(--navbar-text);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ line-height: 1;
+ }
+
+ .avatar-inner {
+ position: relative;
+ flex-shrink: 0;
+ display: flex;
+ }
+
+ .user-avatar {
+ width: 30px;
+ height: 30px;
+ border-radius: 999px;
+ border: 2px solid rgba(var(--el-color-primary-rgb), 0.28);
+ box-shadow: 0 8px 18px rgba(0, 0, 0, 0.18);
+ object-fit: cover;
+ transition: 0.2s ease;
+ }
+
+ .profile-trigger:hover .user-avatar {
+ transform: translateY(-1px);
+ }
+
+ .user-status-dot {
+ position: absolute;
+ bottom: -1px;
+ right: -1px;
+ width: 9px;
+ height: 9px;
+ background: #10b981;
+ border: 2px solid var(--navbar-bg);
+ border-radius: 999px;
+ }
+
+ .caret-icon {
+ color: var(--navbar-text);
+ opacity: 0.76;
+ font-size: 12px;
+ transition: 0.2s ease;
+ margin-left: 2px;
+ }
+
+ .profile-trigger:hover .caret-icon {
+ transform: translateY(1px);
+ opacity: 1;
+ }
+ }
+ }
+
+ :deep(.user-profile-dropdown-panel) {
+ min-width: 240px;
+ color: var(--sidebar-text);
+ }
+
+ :deep(.user-profile-dropdown-head) {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ padding: 12px 12px 10px;
+ margin: 0 6px 6px;
+ border-radius: var(--radius-lg);
+ // background: rgba(0, 0, 0, 0.18);
+ // border: 1px solid rgba(var(--el-color-primary-rgb), 0.22);
+ }
+
+ :deep(.user-profile-dropdown-avatar) {
+ width: 38px;
+ height: 38px;
+ border-radius: 999px;
+ border: 2px solid rgba(var(--el-color-primary-rgb), 0.26);
+ object-fit: cover;
+ flex-shrink: 0;
+ }
+
+ :deep(.user-profile-dropdown-meta) {
+ min-width: 0;
+ }
+
+ :deep(.user-profile-dropdown-name) {
+ font-size: 13px;
+ font-weight: 800;
+ color: #000;
+ line-height: 1.2;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ :deep(.user-profile-dropdown-role) {
+ margin-top: 2px;
+ font-size: 12px;
+ // color: var(--sidebar-muted, rgba(255, 255, 255, 0.62));
+ color: #64748b;
+ line-height: 1.2;
+ }
+
+ :deep(.user-profile-dropdown) {
+ background: var(--sidebar-bg) !important;
+ border: 1px solid var(--surface-border) !important;
+ border-radius: var(--radius-lg) !important;
+ box-shadow: var(--shadow-menu) !important;
+ padding: 6px !important;
+ backdrop-filter: blur(16px);
+
+ .el-dropdown-menu__item {
+ color: var(--sidebar-text) !important;
+ border-radius: var(--radius-md) !important;
+ margin: 2px 0 !important;
+ padding: 8px 16px !important;
+ font-size: 13px !important;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+
+ .el-icon {
+ font-size: 16px;
+ margin-right: 0;
+ }
+
+ &:hover {
+ background: var(--menu-hover) !important;
+ color: var(--menu-active-text) !important;
+ }
+
+ &.el-dropdown-menu__item--divided {
+ border-top-color: var(--surface-border) !important;
+ margin-top: 6px !important;
+ padding-top: 10px !important;
+
+ &::before {
+ display: none;
+ }
+ }
+
+ &.logout-item {
+ color: #f87171 !important;
+
+ &:hover {
+ background: rgba(239, 68, 68, 0.1) !important;
+ color: #ef4444 !important;
+ }
+ }
+ }
+ }
</style>
<style lang="scss">
-.notification-popover {
- padding: 0 !important;
- border-radius: 16px !important;
- border: 1px solid rgba(148, 163, 184, 0.22) !important;
- box-shadow: 0 18px 40px rgba(15, 23, 42, 0.12) !important;
- background: rgba(255, 255, 255, 0.94) !important;
- backdrop-filter: blur(16px);
-
- .el-popover__title {
- display: none;
- }
-
- .el-popover__body {
+ .notification-popover {
padding: 0 !important;
- }
-}
+ border-radius: var(--radius-lg) !important;
+ border: 1px solid rgba(15, 23, 42, 0.1) !important;
+ box-shadow: var(--shadow-menu) !important;
+ background: rgba(255, 255, 255, 0.96) !important;
+ backdrop-filter: blur(16px);
+ color: rgba(15, 23, 42, 0.92);
-.el-badge__content.is-fixed {
- top: 8px;
-}
+ .el-popover__title {
+ display: none;
+ }
+
+ .el-popover__body {
+ padding: 0 !important;
+ }
+ }
+
+ .el-badge__content.is-fixed {
+ top: 8px;
+ }
</style>
diff --git a/src/layout/components/NotificationCenter/index.vue b/src/layout/components/NotificationCenter/index.vue
index 66f489a..8b9d74f 100644
--- a/src/layout/components/NotificationCenter/index.vue
+++ b/src/layout/components/NotificationCenter/index.vue
@@ -255,7 +255,8 @@
flex-direction: column;
width: 500px;
padding: 16px;
- background: rgba(255, 255, 255, 0.92);
+ background: transparent;
+ color: rgba(15, 23, 42, 0.92);
}
.popover-header {
@@ -265,12 +266,12 @@
width: 100%;
margin-bottom: 16px;
padding-bottom: 12px;
- border-bottom: 1px solid var(--surface-border);
+ border-bottom: 1px solid rgba(15, 23, 42, 0.08);
.popover-title {
font-size: 18px;
font-weight: 500;
- color: var(--text-primary);
+ color: rgba(15, 23, 42, 0.92);
}
}
@@ -285,6 +286,18 @@
flex-direction: column;
min-height: 0;
+ .el-tabs__nav-wrap::after {
+ background-color: rgba(15, 23, 42, 0.08);
+ }
+
+ .el-tabs__item {
+ color: rgba(15, 23, 42, 0.7);
+
+ &.is-active {
+ color: var(--accent-primary);
+ }
+ }
+
.el-tabs__header {
margin-bottom: 0;
flex-shrink: 0;
@@ -297,90 +310,96 @@
min-height: 0;
padding-top: 16px;
}
+ }
+ }
- .el-tab-pane {
- height: 100%;
+ .notification-list {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ }
+
+ .notification-item {
+ display: flex;
+ gap: 12px;
+ padding: 12px;
+ border-radius: var(--radius-md);
+ background: rgba(15, 23, 42, 0.03);
+ border: 1px solid rgba(15, 23, 42, 0.06);
+ transition: all 0.2s ease;
+
+ &:hover {
+ background: rgba(15, 23, 42, 0.05);
+ border-color: rgba(15, 23, 42, 0.1);
+ }
+
+ &.read {
+ opacity: 0.6;
+ }
+
+ .notification-icon {
+ flex-shrink: 0;
+ }
+
+ .notification-content-wrapper {
+ flex: 1;
+ min-width: 0;
+
+ .notification-title {
+ font-size: 14px;
+ font-weight: 500;
+ color: rgba(15, 23, 42, 0.92);
+ margin-bottom: 4px;
+ }
+
+ .notification-detail {
+ font-size: 13px;
+ color: rgba(15, 23, 42, 0.7);
+ line-height: 1.4;
+ margin-bottom: 8px;
+ }
+
+ .notification-time {
+ font-size: 11px;
+ color: rgba(15, 23, 42, 0.55);
}
}
}
.empty-state {
- display: flex;
- justify-content: center;
- align-items: center;
- min-height: 300px;
padding: 40px 0;
- }
-
- .notification-list {
- .notification-item {
- display: flex;
- padding: 12px 0;
- border-bottom: 1px solid rgba(148, 163, 184, 0.18);
- transition: background-color 0.3s;
-
- &:hover {
- background-color: #f8fbff;
- }
-
- &.read {
- opacity: 0.7;
- }
-
- .notification-icon {
- flex-shrink: 0;
- width: 40px;
- height: 40px;
- display: flex;
- align-items: center;
- justify-content: center;
- background-color: rgba(59, 130, 246, 0.12);
- border-radius: 50%;
- margin-right: 12px;
- }
-
- .notification-content-wrapper {
- flex: 1;
- min-width: 0;
-
- .notification-title {
- font-size: 14px;
- font-weight: 500;
- color: var(--text-primary);
- margin-bottom: 8px;
- }
-
- .notification-detail {
- font-size: 13px;
- color: var(--text-secondary);
- line-height: 1.5;
- margin-bottom: 8px;
- word-break: break-all;
- }
-
- .notification-time {
- font-size: 12px;
- color: var(--text-tertiary);
- }
- }
-
- .notification-action {
- flex-shrink: 0;
- margin-left: 12px;
- display: flex;
- align-items: center;
- }
+ :deep(.el-empty__description p) {
+ color: rgba(15, 23, 42, 0.68);
}
}
.pagination-wrapper {
margin-top: 16px;
padding-top: 16px;
- border-top: 1px solid var(--surface-border);
+ border-top: 1px solid rgba(15, 23, 42, 0.08);
display: flex;
- justify-content: center;
- padding-left: 0;
- padding-right: 0;
+ justify-content: flex-end;
+
+ :deep(.el-pagination) {
+ --el-pagination-bg-color: transparent;
+ --el-pagination-button-bg-color: transparent;
+ --el-pagination-hover-color: var(--accent-primary);
+
+ button,
+ .el-pager li {
+ color: rgba(15, 23, 42, 0.7);
+ background: transparent;
+
+ &:disabled {
+ color: rgba(15, 23, 42, 0.3);
+ }
+ }
+
+ .el-pager li.is-active {
+ color: var(--accent-primary);
+ font-weight: bold;
+ }
+ }
}
</style>
diff --git a/src/layout/components/Settings/index.vue b/src/layout/components/Settings/index.vue
index 917b28b..c478c78 100644
--- a/src/layout/components/Settings/index.vue
+++ b/src/layout/components/Settings/index.vue
@@ -1,287 +1,280 @@
<template>
- <el-drawer v-model="showSettings" direction="rtl" size="300px">
-<!-- <div class="setting-drawer-title">-->
-<!-- <h3 class="drawer-title">涓婚椋庢牸璁剧疆</h3>-->
-<!-- </div>-->
-<!-- <div class="setting-drawer-block-checbox">-->
-<!-- <div-->
-<!-- class="setting-drawer-block-checbox-item"-->
-<!-- @click="handleTheme('theme-dark')"-->
-<!-- >-->
-<!-- <img src="@/assets/images/dark.svg" alt="dark" />-->
-<!-- <div-->
-<!-- v-if="sideTheme === 'theme-dark'"-->
-<!-- class="setting-drawer-block-checbox-selectIcon"-->
-<!-- style="display: block"-->
-<!-- >-->
-<!-- <i aria-label="鍥炬爣: check" class="anticon anticon-check">-->
-<!-- <svg-->
-<!-- viewBox="64 64 896 896"-->
-<!-- data-icon="check"-->
-<!-- width="1em"-->
-<!-- height="1em"-->
-<!-- :fill="theme"-->
-<!-- aria-hidden="true"-->
-<!-- focusable="false"-->
-<!-- class-->
-<!-- >-->
-<!-- <path-->
-<!-- d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"-->
-<!-- />-->
-<!-- </svg>-->
-<!-- </i>-->
-<!-- </div>-->
-<!-- </div>-->
-<!-- <div-->
-<!-- class="setting-drawer-block-checbox-item"-->
-<!-- @click="handleTheme('theme-light')"-->
-<!-- >-->
-<!-- <img src="@/assets/images/light.svg" alt="light" />-->
-<!-- <div-->
-<!-- v-if="sideTheme === 'theme-light'"-->
-<!-- class="setting-drawer-block-checbox-selectIcon"-->
-<!-- style="display: block"-->
-<!-- >-->
-<!-- <i aria-label="鍥炬爣: check" class="anticon anticon-check">-->
-<!-- <svg-->
-<!-- viewBox="64 64 896 896"-->
-<!-- data-icon="check"-->
-<!-- width="1em"-->
-<!-- height="1em"-->
-<!-- :fill="theme"-->
-<!-- aria-hidden="true"-->
-<!-- focusable="false"-->
-<!-- class-->
-<!-- >-->
-<!-- <path-->
-<!-- d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"-->
-<!-- />-->
-<!-- </svg>-->
-<!-- </i>-->
-<!-- </div>-->
-<!-- </div>-->
-<!-- </div>-->
+ <el-drawer v-model="showSettings"
+ direction="rtl"
+ size="300px">
+ <!-- <div class="setting-drawer-title">-->
+ <!-- <h3 class="drawer-title">涓婚椋庢牸璁剧疆</h3>-->
+ <!-- </div>-->
+ <!-- <div class="setting-drawer-block-checbox">-->
+ <!-- <div-->
+ <!-- class="setting-drawer-block-checbox-item"-->
+ <!-- @click="handleTheme('theme-dark')"-->
+ <!-- >-->
+ <!-- <img src="@/assets/images/dark.svg" alt="dark" />-->
+ <!-- <div-->
+ <!-- v-if="sideTheme === 'theme-dark'"-->
+ <!-- class="setting-drawer-block-checbox-selectIcon"-->
+ <!-- style="display: block"-->
+ <!-- >-->
+ <!-- <i aria-label="鍥炬爣: check" class="anticon anticon-check">-->
+ <!-- <svg-->
+ <!-- viewBox="64 64 896 896"-->
+ <!-- data-icon="check"-->
+ <!-- width="1em"-->
+ <!-- height="1em"-->
+ <!-- :fill="theme"-->
+ <!-- aria-hidden="true"-->
+ <!-- focusable="false"-->
+ <!-- class-->
+ <!-- >-->
+ <!-- <path-->
+ <!-- d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"-->
+ <!-- />-->
+ <!-- </svg>-->
+ <!-- </i>-->
+ <!-- </div>-->
+ <!-- </div>-->
+ <!-- <div-->
+ <!-- class="setting-drawer-block-checbox-item"-->
+ <!-- @click="handleTheme('theme-light')"-->
+ <!-- >-->
+ <!-- <img src="@/assets/images/light.svg" alt="light" />-->
+ <!-- <div-->
+ <!-- v-if="sideTheme === 'theme-light'"-->
+ <!-- class="setting-drawer-block-checbox-selectIcon"-->
+ <!-- style="display: block"-->
+ <!-- >-->
+ <!-- <i aria-label="鍥炬爣: check" class="anticon anticon-check">-->
+ <!-- <svg-->
+ <!-- viewBox="64 64 896 896"-->
+ <!-- data-icon="check"-->
+ <!-- width="1em"-->
+ <!-- height="1em"-->
+ <!-- :fill="theme"-->
+ <!-- aria-hidden="true"-->
+ <!-- focusable="false"-->
+ <!-- class-->
+ <!-- >-->
+ <!-- <path-->
+ <!-- d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"-->
+ <!-- />-->
+ <!-- </svg>-->
+ <!-- </i>-->
+ <!-- </div>-->
+ <!-- </div>-->
+ <!-- </div>-->
<div class="drawer-item">
<span>涓婚棰滆壊</span>
<span class="comp-style">
- <el-color-picker
- v-model="theme"
- :predefine="predefineColors"
- @change="themeChange"
- />
+ <el-color-picker v-model="theme"
+ :predefine="predefineColors"
+ @change="themeChange" />
</span>
</div>
<div class="drawer-item">
<span>鏄剧ず妯″紡</span>
<span class="comp-style">
- <el-select
- v-model="settingsStore.darkMode"
- placeholder="璇烽�夋嫨"
- style="width: 130px"
- @change="darkModeChange"
- >
- <el-option
- v-for="item in darkModeOptions"
- :key="item.value"
- :label="item.label"
- :value="item.value"
- />
+ <el-select v-model="settingsStore.darkMode"
+ placeholder="璇烽�夋嫨"
+ style="width: 130px"
+ @change="darkModeChange">
+ <el-option v-for="item in darkModeOptions"
+ :key="item.value"
+ :label="item.label"
+ :value="item.value" />
</el-select>
</span>
</div>
<el-divider />
-
<h3 class="drawer-title">绯荤粺甯冨眬閰嶇疆</h3>
-
<div class="drawer-item">
<span>寮�鍚� TopNav</span>
<span class="comp-style">
- <el-switch
- v-model="settingsStore.topNav"
- @change="topNavChange"
- class="drawer-switch"
- />
+ <el-switch v-model="settingsStore.topNav"
+ @change="topNavChange"
+ class="drawer-switch" />
</span>
</div>
-
<div class="drawer-item">
<span>寮�鍚� Tags-Views</span>
<span class="comp-style">
- <el-switch v-model="settingsStore.tagsView" class="drawer-switch" />
+ <el-switch v-model="settingsStore.tagsView"
+ class="drawer-switch" />
</span>
</div>
-
<div class="drawer-item">
<span>鍥哄畾 Header</span>
<span class="comp-style">
- <el-switch v-model="settingsStore.fixedHeader" class="drawer-switch" />
+ <el-switch v-model="settingsStore.fixedHeader"
+ class="drawer-switch" />
</span>
</div>
-
<div class="drawer-item">
<span>鏄剧ず Logo</span>
<span class="comp-style">
- <el-switch v-model="settingsStore.sidebarLogo" class="drawer-switch" />
+ <el-switch v-model="settingsStore.sidebarLogo"
+ class="drawer-switch" />
</span>
</div>
-
<div class="drawer-item">
<span>鍔ㄦ�佹爣棰�</span>
<span class="comp-style">
- <el-switch v-model="settingsStore.dynamicTitle" class="drawer-switch" />
+ <el-switch v-model="settingsStore.dynamicTitle"
+ class="drawer-switch" />
</span>
</div>
-
<el-divider />
-
- <el-button type="primary" plain icon="DocumentAdd" @click="saveSetting"
- >淇濆瓨閰嶇疆</el-button
- >
- <el-button plain icon="Refresh" @click="resetSetting">閲嶇疆閰嶇疆</el-button>
+ <el-button type="primary"
+ plain
+ icon="DocumentAdd"
+ @click="saveSetting">淇濆瓨閰嶇疆</el-button>
+ <el-button plain
+ icon="Refresh"
+ @click="resetSetting">閲嶇疆閰嶇疆</el-button>
</el-drawer>
</template>
<script setup>
-import variables from "@/assets/styles/variables.module.scss";
-import axios from "axios";
-import { ElLoading, ElMessage } from "element-plus";
-import { useDynamicTitle } from "@/utils/dynamicTitle";
-import useAppStore from "@/store/modules/app";
-import useSettingsStore from "@/store/modules/settings";
-import usePermissionStore from "@/store/modules/permission";
-import { handleThemeStyle } from "@/utils/theme";
+ import variables from "@/assets/styles/variables.module.scss";
+ import axios from "axios";
+ import { ElLoading, ElMessage } from "element-plus";
+ import { useDynamicTitle } from "@/utils/dynamicTitle";
+ import useAppStore from "@/store/modules/app";
+ import useSettingsStore from "@/store/modules/settings";
+ import usePermissionStore from "@/store/modules/permission";
+ import { handleThemeStyle } from "@/utils/theme";
-const { proxy } = getCurrentInstance();
-const appStore = useAppStore();
-const settingsStore = useSettingsStore();
-const permissionStore = usePermissionStore();
-const showSettings = ref(false);
-const theme = ref(settingsStore.theme);
-const sideTheme = ref(settingsStore.sideTheme);
-const storeSettings = computed(() => settingsStore);
-const predefineColors = ref([
- "#002fa7",
- "#81D8D0",
- "#E85827",
- "#008C8C",
- "#F9DC24",
- "#B05923",
- "#003153",
- "#8F4B28",
- "#4C0009",
-]);
-const darkModeOptions = ref([
- { label: "璺熼殢绯荤粺", value: "auto" },
- { label: "娴呰壊", value: "light" },
- { label: "娣辫壊", value: "dark" },
-]);
+ const { proxy } = getCurrentInstance();
+ const appStore = useAppStore();
+ const settingsStore = useSettingsStore();
+ const permissionStore = usePermissionStore();
+ const showSettings = ref(false);
+ const theme = ref(settingsStore.theme);
+ const sideTheme = ref(settingsStore.sideTheme);
+ const storeSettings = computed(() => settingsStore);
+ const predefineColors = ref([
+ "#374D77",
+ "#81D8D0",
+ "#E85827",
+ "#008C8C",
+ "#F9DC24",
+ "#B05923",
+ "#003153",
+ "#8F4B28",
+ "#4C0009",
+ ]);
+ const darkModeOptions = ref([
+ { label: "璺熼殢绯荤粺", value: "auto" },
+ { label: "娴呰壊", value: "light" },
+ { label: "娣辫壊", value: "dark" },
+ ]);
-/** 鏄惁闇�瑕乼opnav */
-function topNavChange(val) {
- if (!val) {
- appStore.toggleSideBarHide(false);
- permissionStore.setSidebarRouters(permissionStore.defaultRoutes);
+ /** 鏄惁闇�瑕乼opnav */
+ function topNavChange(val) {
+ if (!val) {
+ appStore.toggleSideBarHide(false);
+ permissionStore.setSidebarRouters(permissionStore.defaultRoutes);
+ }
}
-}
-function themeChange(val) {
- settingsStore.theme = val;
- handleThemeStyle(val);
-}
+ function themeChange(val) {
+ settingsStore.theme = val;
+ handleThemeStyle(val);
+ }
-function darkModeChange(val) {
- settingsStore.setDarkMode(val);
-}
+ function darkModeChange(val) {
+ settingsStore.setDarkMode(val);
+ }
-function handleTheme(val) {
- settingsStore.sideTheme = val;
- sideTheme.value = val;
-}
+ function handleTheme(val) {
+ settingsStore.sideTheme = val;
+ sideTheme.value = val;
+ }
-function saveSetting() {
- proxy.$modal.loading("姝e湪淇濆瓨鍒版湰鍦帮紝璇风◢鍊�...");
- let layoutSetting = {
- topNav: storeSettings.value.topNav,
- tagsView: storeSettings.value.tagsView,
- fixedHeader: storeSettings.value.fixedHeader,
- sidebarLogo: storeSettings.value.sidebarLogo,
- dynamicTitle: storeSettings.value.dynamicTitle,
- sideTheme: storeSettings.value.sideTheme,
- theme: storeSettings.value.theme,
- darkMode: storeSettings.value.darkMode,
- };
- localStorage.setItem("layout-setting", JSON.stringify(layoutSetting));
- setTimeout(proxy.$modal.closeLoading(), 1000);
-}
+ function saveSetting() {
+ proxy.$modal.loading("姝e湪淇濆瓨鍒版湰鍦帮紝璇风◢鍊�...");
+ let layoutSetting = {
+ topNav: storeSettings.value.topNav,
+ tagsView: storeSettings.value.tagsView,
+ fixedHeader: storeSettings.value.fixedHeader,
+ sidebarLogo: storeSettings.value.sidebarLogo,
+ dynamicTitle: storeSettings.value.dynamicTitle,
+ sideTheme: storeSettings.value.sideTheme,
+ theme: storeSettings.value.theme,
+ darkMode: storeSettings.value.darkMode,
+ };
+ localStorage.setItem("layout-setting", JSON.stringify(layoutSetting));
+ setTimeout(proxy.$modal.closeLoading(), 1000);
+ }
-function resetSetting() {
- proxy.$modal.loading("姝e湪娓呴櫎璁剧疆缂撳瓨骞跺埛鏂帮紝璇风◢鍊�...");
- localStorage.removeItem("layout-setting");
- setTimeout("window.location.reload()", 1000);
-}
+ function resetSetting() {
+ proxy.$modal.loading("姝e湪娓呴櫎璁剧疆缂撳瓨骞跺埛鏂帮紝璇风◢鍊�...");
+ localStorage.removeItem("layout-setting");
+ setTimeout("window.location.reload()", 1000);
+ }
-function openSetting() {
- showSettings.value = true;
-}
+ function openSetting() {
+ showSettings.value = true;
+ }
-defineExpose({
- openSetting,
-});
+ defineExpose({
+ openSetting,
+ });
</script>
<style lang="scss" scoped>
-.setting-drawer-title {
- margin-bottom: 12px;
- color: var(--el-text-color-primary, rgba(0, 0, 0, 0.85));
- line-height: 22px;
- font-weight: bold;
+ .setting-drawer-title {
+ margin-bottom: 12px;
+ color: var(--el-text-color-primary, rgba(0, 0, 0, 0.85));
+ line-height: 22px;
+ font-weight: bold;
- .drawer-title {
- font-size: 14px;
- }
-}
-
-.setting-drawer-block-checbox {
- display: flex;
- justify-content: flex-start;
- align-items: center;
- margin-top: 10px;
- margin-bottom: 20px;
-
- .setting-drawer-block-checbox-item {
- position: relative;
- margin-right: 16px;
- border-radius: 2px;
- cursor: pointer;
-
- img {
- width: 48px;
- height: 48px;
- }
-
- .setting-drawer-block-checbox-selectIcon {
- position: absolute;
- top: 0;
- right: 0;
- width: 100%;
- height: 100%;
- padding-top: 15px;
- padding-left: 24px;
- color: #1890ff;
- font-weight: 700;
+ .drawer-title {
font-size: 14px;
}
}
-}
-.drawer-item {
- color: var(--el-text-color-regular, rgba(0, 0, 0, 0.65));
- padding: 12px 0;
- font-size: 14px;
+ .setting-drawer-block-checbox {
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ margin-top: 10px;
+ margin-bottom: 20px;
- .comp-style {
- float: right;
- margin: -3px 8px 0px 0px;
+ .setting-drawer-block-checbox-item {
+ position: relative;
+ margin-right: 16px;
+ border-radius: 2px;
+ cursor: pointer;
+
+ img {
+ width: 48px;
+ height: 48px;
+ }
+
+ .setting-drawer-block-checbox-selectIcon {
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 100%;
+ height: 100%;
+ padding-top: 15px;
+ padding-left: 24px;
+ color: #1890ff;
+ font-weight: 700;
+ font-size: 14px;
+ }
+ }
}
-}
+
+ .drawer-item {
+ color: var(--el-text-color-regular, rgba(0, 0, 0, 0.65));
+ padding: 12px 0;
+ font-size: 14px;
+
+ .comp-style {
+ float: right;
+ margin: -3px 8px 0px 0px;
+ }
+ }
</style>
diff --git a/src/layout/components/Sidebar/Logo.vue b/src/layout/components/Sidebar/Logo.vue
index 1a66c4a..632a0df 100644
--- a/src/layout/components/Sidebar/Logo.vue
+++ b/src/layout/components/Sidebar/Logo.vue
@@ -1,7 +1,7 @@
<template>
<div class="sidebar-logo-container" :class="{ collapse }">
<transition name="sidebarLogoFade">
- <router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
+ <router-link style="display: flex;" v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
<img :src="faviconUrl" class="sidebar-logo sidebar-favicon" alt="绔欑偣鍥炬爣" />
</router-link>
<router-link v-else key="expand" class="sidebar-logo-link" :style="expandLogoLinkStyle" to="/">
@@ -90,108 +90,55 @@
.sidebar-logo-container {
position: relative;
width: 100% !important;
- height: 78px !important;
- line-height: 78px;
+ height: 64px !important;
+ line-height: 64px;
background: transparent;
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
text-align: left;
overflow: hidden;
- box-shadow: none;
- backdrop-filter: none;
transition: all 0.3s ease;
.sidebar-logo-link {
- position: relative;
- isolation: isolate;
height: 100%;
width: 100%;
display: flex;
align-items: center;
- justify-content: center;
- padding: 0;
-
- &::before {
- content: "";
- position: absolute;
- inset: 0;
- background-image: var(--logo-bg-image);
- background-size: cover;
- background-position: center;
- opacity: 0.26;
- filter: blur(8px) saturate(0.9);
- transform: scale(1.06);
- pointer-events: none;
- z-index: 0;
- }
-
- &::after {
- content: "";
- position: absolute;
- inset: 0;
- background: linear-gradient(180deg, rgba(16, 49, 89, 0.18), rgba(16, 49, 89, 0.08));
- pointer-events: none;
- z-index: 0;
- }
+ justify-content: flex-start; // 榛樿灞曞紑鏃堕潬宸�
+ padding: 0 16px;
}
.sidebar-logo {
- width: 100%;
- height: 100%;
- max-width: none;
- max-height: none;
- padding: 6px 10px;
+ height:100%;
+ width:100%;
+ width: auto;
+ max-width: 100%;
vertical-align: middle;
object-fit: contain;
- object-position: center;
- filter: none;
display: block;
- position: relative;
- z-index: 1;
}
.sidebar-title {
display: inline-block;
margin: 0;
- color: var(--text-primary);
+ color: #fff;
font-weight: 600;
- line-height: 1.2;
- font-size: 14px;
- font-family: "Segoe UI", "PingFang SC", sans-serif;
+ line-height: 64px;
+ font-size: 16px;
vertical-align: middle;
- position: relative;
- z-index: 1;
+ margin-left: 12px;
+ white-space: nowrap;
}
&.collapse {
.sidebar-logo-link {
- display: flex;
- align-items: center;
- justify-content: center;
padding: 0;
-
- &::before,
- &::after {
- display: none;
- }
+ justify-content: center; // 鎶樺彔鏃剁粷瀵瑰眳涓�
}
.sidebar-logo {
- width: calc(100% - 8px);
- height: calc(100% - 8px);
- max-width: none;
- max-height: none;
- padding: 4px;
- margin: 0 auto;
- filter: none;
- object-fit: contain;
- object-position: center;
- }
-
- .sidebar-favicon {
- width: calc(100% - 8px);
- height: calc(100% - 8px);
- max-width: none;
- max-height: none;
+ width: 32px;
+ height: 32px;
+ margin: 0;
}
}
}
diff --git a/src/layout/components/Sidebar/SidebarItem.vue b/src/layout/components/Sidebar/SidebarItem.vue
index 003b489..e770ee2 100644
--- a/src/layout/components/Sidebar/SidebarItem.vue
+++ b/src/layout/components/Sidebar/SidebarItem.vue
@@ -101,58 +101,40 @@
}
</script>
-<style lang="scss" scoped>
+<style lang="scss" scoped>
.sidebar-item-wrapper {
:deep(.menu-icon) {
- width: 26px;
- height: 26px;
+ width: 18px;
+ height: 18px;
margin-right: 12px;
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
- transition: color 0.2s ease;
- color: var(--sidebar-text);
- opacity: 0.88;
+ transition: all 0.3s ease;
+ color: inherit;
}
- :deep(.el-menu-item:hover .menu-icon),
- :deep(.el-sub-menu__title:hover .menu-icon) {
- color: #ffffff;
- opacity: 1;
- }
-
- :deep(.el-menu-item.is-active .menu-icon) {
- color: var(--menu-active-text) !important;
- opacity: 1;
- }
-
:deep(.menu-title) {
font-weight: 500;
transition: color 0.2s ease;
- color: var(--sidebar-text);
- opacity: 0.82;
- }
-
- :deep(.el-menu-item:hover .menu-title),
- :deep(.el-sub-menu__title:hover .menu-title) {
- color: #ffffff;
- opacity: 1;
- }
-
- :deep(.el-menu-item.is-active .menu-title) {
- color: var(--menu-active-text) !important;
- opacity: 1;
+ color: inherit;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ flex: 1;
}
:deep(.nest-menu) {
.menu-icon {
- width: 22px;
- height: 22px;
+ width: 16px;
+ height: 16px;
margin-right: 10px;
}
- .menu-title { font-size: 13px; }
+ .menu-title {
+ font-size: 13px;
+ }
}
}
</style>
diff --git a/src/layout/components/Sidebar/index.vue b/src/layout/components/Sidebar/index.vue
index 2a58c29..8f9fb89 100644
--- a/src/layout/components/Sidebar/index.vue
+++ b/src/layout/components/Sidebar/index.vue
@@ -67,100 +67,35 @@
border: none !important;
height: 100%;
width: 100% !important;
- border-radius: 0;
background: transparent !important;
- .el-menu-item,
- .el-sub-menu__title {
- margin-bottom: 8px;
- border-radius: 14px;
- color: v-bind(getMenuTextColor);
+ :deep(.el-menu-item),
+ :deep(.el-sub-menu__title) {
+ margin-bottom: 4px;
+ border-radius: var(--radius-md);
+ color: var(--sidebar-text);
font-size: 14px;
- letter-spacing: 0;
- transition:
- transform 0.18s ease,
- background 0.2s ease,
- box-shadow 0.2s ease,
- color 0.2s ease;
- border: none !important;
+ transition: all 0.2s ease;
display: flex;
align-items: center;
&:hover {
- background: linear-gradient(128deg, rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.28), rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.08)) !important;
- transform: translate3d(2px, 0, 0);
+ background: var(--menu-hover) !important;
+ color: #fff !important;
}
- }
-
- .el-menu-item {
- color: var(--sidebar-text);
-
- &.is-active {
- background: var(--menu-active-bg, linear-gradient(135deg, var(--el-color-primary), var(--el-color-primary-light-3))) !important;
- color: var(--menu-active-text) !important;
- font-weight: 500;
- border-radius: 14px;
- box-shadow: var(--menu-active-glow, 0 10px 24px rgba(var(--el-color-primary-rgb, 37, 99, 235), 0.34));
-
- .svg-icon {
- color: var(--menu-active-text) !important;
- }
- }
- }
-
- .el-sub-menu__title {
- color: v-bind(getMenuTextColor);
- }
-
- :deep(.el-sub-menu__icon-arrow) {
- display: inline-flex !important;
- align-items: center;
- justify-content: center;
- width: 14px;
- height: 14px;
- margin-top: -7px;
- right: 14px;
- font-size: 14px !important;
- color: currentColor !important;
- opacity: 0.7;
- transition: transform 0.2s ease, opacity 0.2s ease;
- }
-
- :deep(.el-sub-menu.is-opened .el-sub-menu__icon-arrow) {
- transform: rotate(180deg);
- }
-
- :deep(.el-sub-menu.is-active > .el-sub-menu__title) {
- color: var(--menu-active-text) !important;
- font-weight: 500;
- border-radius: 12px;
- margin: 0 12px 6px !important;
- padding-left: 14px !important;
- padding-right: 34px !important;
- box-sizing: border-box;
- overflow: hidden;
- background-clip: padding-box;
- background: var(--menu-active-bg) !important;
- box-shadow: var(--menu-active-glow);
- border: none !important;
}
:deep(.el-menu-item.is-active) {
- margin: 0 12px 6px !important;
- width: calc(100% - 24px) !important;
- padding-left: 14px !important;
- padding-right: 34px !important;
- box-sizing: border-box;
- overflow: hidden;
- background-clip: padding-box;
- border-radius: 12px;
+ background: var(--menu-active-bg) !important;
+ color: var(--menu-active-text) !important;
+ font-weight: 600;
+ box-shadow: var(--menu-active-glow);
+
+ .svg-icon {
+ color: var(--menu-active-text) !important;
+ }
}
- :deep(.el-sub-menu.is-active > .el-sub-menu__title .menu-title),
- :deep(.el-sub-menu.is-active > .el-sub-menu__title .svg-icon),
- :deep(.el-menu-item.is-active .menu-title) {
- color: var(--menu-active-text) !important;
- }
}
}
</style>
diff --git a/src/layout/components/TagsView/index.vue b/src/layout/components/TagsView/index.vue
index 66b6014..9b8e525 100644
--- a/src/layout/components/TagsView/index.vue
+++ b/src/layout/components/TagsView/index.vue
@@ -13,9 +13,9 @@
@contextmenu.prevent="openMenu(tag, $event)"
>
{{ tag.title }}
- <span v-if="!isAffix(tag)" class="tags-view-close" @click.prevent.stop="closeSelectedTag(tag)">
- <close class="el-icon-close" />
- </span>
+ <span v-if="!isAffix(tag)" class="tags-view-close" @click.prevent.stop="closeSelectedTag(tag)">
+ <close class="el-icon-close" />
+ </span>
</router-link>
</scroll-pane>
<ul v-show="visible" :style="{ left: left + 'px', top: top + 'px' }" class="contextmenu">
@@ -258,76 +258,96 @@
</script>
<style lang="scss" scoped>
-.tags-view-container {
- height: var(--tagsbar-height);
- width: 100%;
- margin-top: 0;
- padding: 0 2px;
- background: transparent;
- border: none;
- border-radius: 0;
- backdrop-filter: none;
- box-shadow: none;
-
- .tags-view-wrapper {
- display: flex;
- align-items: center;
- min-height: var(--tagsbar-height);
-
- .tags-view-item {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- position: relative;
- cursor: pointer;
- height: 30px;
- line-height: 1;
- color: var(--tags-item-text, #4E5463);
- background: var(--tags-item-bg, #E5E7EA);
- border: 1px solid var(--tags-item-border, #d8dce5);
- border-radius: 999px;
- padding: 0 14px;
- font-size: 12px;
- margin-right: 6px;
- flex-shrink: 0;
- gap: 6px;
- transition: all 0.24s ease;
-
- &:hover {
- background: var(--tags-item-hover, #eee);
- border-color: rgba(96, 165, 250, 0.36);
- }
-
- &.active {
- background-image: linear-gradient(132deg, rgba(47, 128, 255, 0.95), rgba(56, 189, 248, 0.9));
- color: #fff;
- box-shadow: 0 10px 20px rgba(37, 99, 235, 0.22);
- border-color: rgba(147, 197, 253, 0.72) !important;
- }
- }
- }
+.tags-view-container {
+ height: 42px; // 澧炲姞瀹瑰櫒楂樺害锛屾彁渚涙洿澶氬懠鍚告劅
+ width: 100%;
+ background: var(--tags-bg);
+ border-bottom: 1px solid var(--surface-border);
+ padding: 0 16px;
+ display: flex;
+ align-items: center;
+
+ .tags-view-wrapper {
+ flex: 1;
+ overflow: hidden;
+ white-space: nowrap;
+
+ .tags-view-item {
+ display: inline-flex;
+ align-items: center;
+ position: relative;
+ cursor: pointer;
+ height: 30px; // 澧炲姞椤电楂樺害
+ line-height: 30px;
+ color: var(--tags-item-text);
+ background: var(--tags-item-bg);
+ border: 1px solid var(--tags-item-border);
+ border-radius: 6px; // 绋嶅井鍦嗘鼎涓�鐐�
+ padding: 0 12px;
+ font-size: 12px;
+ margin-right: 6px;
+ transition: all 0.2s ease;
+ gap: 6px;
+ text-decoration: none;
+
+ &:hover {
+ background: var(--tags-item-hover);
+ color: var(--accent-primary);
+ border-color: var(--accent-primary);
+ }
+
+ &.active {
+ background: var(--accent-primary);
+ color: #fff;
+ border-color: var(--accent-primary);
+ box-shadow: 0 2px 8px rgba(37, 99, 235, 0.15);
+ font-weight: 500;
+
+ &::before {
+ content: "";
+ background: #fff;
+ display: inline-block;
+ width: 6px;
+ height: 6px;
+ border-radius: 50%;
+ margin-right: 2px;
+ }
+ }
+ }
+ }
.contextmenu {
margin: 0;
- background: var(--el-bg-color-overlay, #fff);
+ background: #fff;
z-index: 3000;
position: absolute;
list-style-type: none;
- padding: 5px 0;
- border-radius: 16px;
+ padding: 4px 0;
+ border-radius: var(--radius-md);
font-size: 12px;
- font-weight: 400;
- color: var(--tags-item-text, #333);
- box-shadow: var(--shadow-md);
- border: 1px solid var(--surface-border, #e4e7ed);
+ color: var(--text-secondary);
+ box-shadow: var(--shadow-md);
+ border: 1px solid var(--surface-border);
li {
margin: 0;
- padding: 7px 16px;
+ padding: 8px 16px;
cursor: pointer;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ transition: all 0.2s ease;
+ white-space: nowrap;
+
+ svg {
+ width: 14px;
+ height: 14px;
+ color: inherit;
+ }
&:hover {
- background: var(--tags-item-hover, #eee);
+ background: #f1f5f9;
+ color: var(--accent-primary);
}
}
}
@@ -336,56 +356,56 @@
<style lang="scss">
//reset element css of el-icon-close
-.tags-view-wrapper {
- .el-scrollbar__view {
- display: flex;
- align-items: center;
- }
-
- .tags-view-item {
- .tags-view-close {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: 12px;
- height: 12px;
- line-height: 1;
- align-self: center;
- transform: translateY(1px);
- }
-
- .el-icon-close {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: 12px;
- height: 12px;
- line-height: 1;
- vertical-align: initial !important;
- border-radius: 50%;
- text-align: center;
- transition: all .3s cubic-bezier(.645, .045, .355, 1);
- transform-origin: 100% 50%;
- align-self: center;
-
- &:before {
- transform: scale(.6);
- display: inline-flex;
- align-items: center;
- justify-content: center;
- }
-
- svg {
- display: block;
- width: 10px;
- height: 10px;
- }
-
- &:hover {
- background-color: var(--tags-close-hover, #b4bccc);
- color: #fff;
- }
- }
- }
-}
-</style>
+.tags-view-wrapper {
+ .el-scrollbar__view {
+ display: flex;
+ align-items: center;
+ }
+
+ .tags-view-item {
+ .tags-view-close {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 12px;
+ height: 12px;
+ line-height: 1;
+ align-self: center;
+ transform: translateY(1px);
+ }
+
+ .el-icon-close {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 12px;
+ height: 12px;
+ line-height: 1;
+ vertical-align: initial !important;
+ border-radius: 50%;
+ text-align: center;
+ transition: all .3s cubic-bezier(.645, .045, .355, 1);
+ transform-origin: 100% 50%;
+ align-self: center;
+
+ &:before {
+ transform: scale(.6);
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ svg {
+ display: block;
+ width: 10px;
+ height: 10px;
+ }
+
+ &:hover {
+ background-color: var(--tags-close-hover, #b4bccc);
+ color: #fff;
+ }
+ }
+ }
+}
+</style>
diff --git a/src/layout/index.vue b/src/layout/index.vue
index aa1bfb5..20f1232 100644
--- a/src/layout/index.vue
+++ b/src/layout/index.vue
@@ -100,17 +100,7 @@
position: relative;
min-height: 100%;
width: 100%;
- background: radial-gradient(
- circle at 14% -8%,
- rgba(59, 130, 246, 0.14),
- transparent 36%
- ),
- radial-gradient(
- circle at 88% -12%,
- rgba(56, 189, 248, 0.1),
- transparent 30%
- ),
- linear-gradient(165deg, #f3f7fc 0%, #eef5ff 56%, #f8fbff 100%);
+ background: var(--app-bg);
&.mobile.openSidebar {
position: fixed;
@@ -119,7 +109,7 @@
}
.drawer-bg {
- background: rgba(15, 23, 42, 0.22);
+ background: rgba(0, 0, 0, 0.3);
width: 100%;
top: 0;
height: 100%;
@@ -133,6 +123,7 @@
transition: margin-left 0.25s ease;
display: flex;
flex-direction: column;
+ padding: 0;
}
.fixed-header {
@@ -140,15 +131,15 @@
top: 0;
z-index: var(--layout-header-z);
width: 100%;
- padding: 8px var(--content-gap) 8px;
+ padding: 0;
+ background: #fff;
display: flex;
flex-direction: column;
- gap: 6px;
- background: var(--app-bg, #f3f7fc);
+ gap: 2px; // 鍦� Navbar 鍜� TagsView 涔嬮棿澧炲姞鏋佸皬鐨勭┖闅�
}
.fixed-header.with-tags {
- padding-bottom: 6px;
+ padding-bottom: 4px; // 搴曢儴鐣欏嚭涓�鐐硅窛绂伙紝涓嶈鐩存帴璐寸潃涓讳綋鍐呭
}
.hideSidebar .fixed-header {
diff --git a/src/store/modules/settings.js b/src/store/modules/settings.js
index 3a5f6a2..226fcac 100644
--- a/src/store/modules/settings.js
+++ b/src/store/modules/settings.js
@@ -7,43 +7,24 @@
emitAuto: true,
});
-const {
- sideTheme,
- showSettings,
- topNav,
- tagsView,
- fixedHeader,
- sidebarLogo,
- dynamicTitle,
- darkMode,
-} = defaultSettings;
+const { sideTheme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo, dynamicTitle, darkMode } = defaultSettings;
const storageSetting = JSON.parse(localStorage.getItem("layout-setting") || "{}");
const defaultDarkMode = darkMode || "auto";
const initialDarkMode = storageSetting.darkMode || defaultDarkMode;
colorMode.value = initialDarkMode;
-const getIsDark = (mode) => mode === "dark" || (mode === "auto" && preferredDark.value);
+const getIsDark = mode => mode === "dark" || (mode === "auto" && preferredDark.value);
const useSettingsStore = defineStore("settings", () => {
const title = ref("");
- const theme = ref(storageSetting.theme || "#002fa7");
+ const theme = ref(storageSetting.theme || "#374D77");
const sideThemeValue = ref(storageSetting.sideTheme || sideTheme);
const showSettingsValue = ref(showSettings);
- const topNavValue = ref(
- storageSetting.topNav === undefined ? topNav : storageSetting.topNav
- );
- const tagsViewValue = ref(
- storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView
- );
- const fixedHeaderValue = ref(
- storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader
- );
- const sidebarLogoValue = ref(
- storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo
- );
- const dynamicTitleValue = ref(
- storageSetting.dynamicTitle === undefined ? dynamicTitle : storageSetting.dynamicTitle
- );
+ const topNavValue = ref(storageSetting.topNav === undefined ? topNav : storageSetting.topNav);
+ const tagsViewValue = ref(storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView);
+ const fixedHeaderValue = ref(storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader);
+ const sidebarLogoValue = ref(storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo);
+ const dynamicTitleValue = ref(storageSetting.dynamicTitle === undefined ? dynamicTitle : storageSetting.dynamicTitle);
const darkModeValue = ref(initialDarkMode);
const isDark = computed(() => getIsDark(darkModeValue.value));
diff --git a/src/utils/theme.js b/src/utils/theme.js
index 90a511e..a992ae1 100644
--- a/src/utils/theme.js
+++ b/src/utils/theme.js
@@ -1,74 +1,110 @@
// 澶勭悊涓婚鏍峰紡
export function handleThemeStyle(theme) {
- const primary = normalizeHex(theme)
- const [r, g, b] = hexToRgb(primary)
- const light2 = getLightColor(primary, 0.2)
- const light3 = getLightColor(primary, 0.3)
- const light5 = getLightColor(primary, 0.5)
+ const primary = normalizeHex(theme);
+ const [r, g, b] = hexToRgb(primary);
+ const light2 = getLightColor(primary, 0.2);
+ const light3 = getLightColor(primary, 0.3);
+ const light5 = getLightColor(primary, 0.5);
- document.documentElement.style.setProperty('--el-color-primary', primary)
- document.documentElement.style.setProperty('--el-color-primary-rgb', `${r}, ${g}, ${b}`)
- for (let i = 1; i <= 9; i++) {
- document.documentElement.style.setProperty(`--el-color-primary-light-${i}`, `${getLightColor(primary, i / 10)}`)
- }
- for (let i = 1; i <= 9; i++) {
- document.documentElement.style.setProperty(`--el-color-primary-dark-${i}`, `${getDarkColor(primary, i / 10)}`)
- }
+ document.documentElement.style.setProperty("--el-color-primary", primary);
+ document.documentElement.style.setProperty("--el-color-primary-rgb", `${r}, ${g}, ${b}`);
+ for (let i = 1; i <= 9; i++) {
+ document.documentElement.style.setProperty(`--el-color-primary-light-${i}`, `${getLightColor(primary, i / 10)}`);
+ }
+ for (let i = 1; i <= 9; i++) {
+ document.documentElement.style.setProperty(`--el-color-primary-dark-${i}`, `${getDarkColor(primary, i / 10)}`);
+ }
- // 绯荤粺涓婚鑱斿姩鍒颁晶杈规爮閫変腑鎬佷笌楂樹寒
- document.documentElement.style.setProperty('--menu-active-bg', `linear-gradient(135deg, ${primary} 0%, ${light3} 100%)`)
- document.documentElement.style.setProperty('--menu-active-glow', `0 10px 24px rgba(${r}, ${g}, ${b}, 0.32)`)
- document.documentElement.style.setProperty('--menu-hover', `rgba(${r}, ${g}, ${b}, 0.2)`)
- document.documentElement.style.setProperty('--accent-primary', primary)
- document.documentElement.style.setProperty('--accent-light', light2)
- document.documentElement.style.setProperty('--accent-lighter', light5)
+ // 绯荤粺涓婚鑱斿姩鍒颁晶杈规爮閫変腑鎬佷笌楂樹寒
+ document.documentElement.style.setProperty("--menu-active-bg", `linear-gradient(135deg, ${primary} 0%, ${light3} 100%)`);
+ document.documentElement.style.setProperty("--menu-active-glow", `0 10px 24px rgba(${r}, ${g}, ${b}, 0.32)`);
+ document.documentElement.style.setProperty("--menu-hover", `rgba(${r}, ${g}, ${b}, 0.2)`);
+ document.documentElement.style.setProperty("--accent-primary", primary);
+ document.documentElement.style.setProperty("--accent-light", light2);
+ document.documentElement.style.setProperty("--accent-lighter", light5);
+
+ // 鏂板锛氫晶杈规爮涓庡鑸爮鍔ㄦ�佽壊褰╄仈鍔�
+ // 渚ц竟鏍忚儗鏅細鏋佹繁鐨勪富棰樿壊鍙樹綋锛屽鍔犱竴鐐规繁搴︽劅
+ const sidebarBg = getDarkColor(primary, 0.15);
+ document.documentElement.style.setProperty("--sidebar-bg", sidebarBg);
+
+ // 瀵艰埅鏍忚儗鏅細甯﹂�忔槑搴︾殑涓婚鑹插彉浣擄紝瀹炵幇鐜荤拑鎷熸��
+ document.documentElement.style.setProperty("--navbar-bg", `rgba(${r}, ${g}, ${b}, 0.85)`);
+
+ // 椤电鏍忚儗鏅細鏋佹祬鐨勪富棰樿壊鍙樹綋锛屽鍔犲懠鍚告劅
+ const tagsBg = getLightColor(primary, 0.96);
+ document.documentElement.style.setProperty("--tags-bg", tagsBg);
+
+ // 鏂囨湰棰滆壊閫傞厤閫昏緫
+ const brightness = (r * 299 + g * 587 + b * 114) / 1000;
+ const isDarkTheme = brightness < 128;
+
+ // 瀵艰埅鏍忔枃瀛楅鑹诧細鏍规嵁涓婚鑹蹭寒搴﹁嚜鍔ㄥ垏鎹㈡繁娴�
+ document.documentElement.style.setProperty("--navbar-text", isDarkTheme ? "#f8fafc" : "#1e293b");
+
+ // 渚ц竟鏍忔枃瀛椾笌鍥炬爣棰滆壊
+ document.documentElement.style.setProperty("--sidebar-text", isDarkTheme ? "rgba(255, 255, 255, 0.75)" : "rgba(15, 23, 42, 0.75)");
+ document.documentElement.style.setProperty("--sidebar-muted", isDarkTheme ? "rgba(255, 255, 255, 0.45)" : "rgba(15, 23, 42, 0.45)");
+
+ // 婵�娲婚」鏂囧瓧棰滆壊锛氬缁堜繚鎸侀珮瀵规瘮搴�
+ document.documentElement.style.setProperty("--menu-active-text", isDarkTheme ? "#ffffff" : "#ffffff"); // 閫氬父涓昏壊璋冩縺娲绘�佺敤鐧借壊
+
+ // 鎮仠涓庢縺娲荤姸鎬侀鑹�
+ document.documentElement.style.setProperty("--menu-hover", `rgba(${r}, ${g}, ${b}, ${isDarkTheme ? 0.12 : 0.08})`);
+ document.documentElement.style.setProperty("--navbar-hover", `rgba(${r}, ${g}, ${b}, 0.1)`);
+
+ // 杈规棰滆壊鑱斿姩
+ document.documentElement.style.setProperty("--surface-border", `rgba(${r}, ${g}, ${b}, 0.12)`);
}
// hex棰滆壊杞瑀gb棰滆壊
export function hexToRgb(str) {
- str = normalizeHex(str).replace('#', '')
- const hexs = str.match(/../g) || ['40', '9e', 'ff']
- for (let i = 0; i < 3; i++) {
- hexs[i] = parseInt(hexs[i], 16)
- }
- return hexs
+ str = normalizeHex(str).replace("#", "");
+ const hexs = str.match(/../g) || ["40", "9e", "ff"];
+ for (let i = 0; i < 3; i++) {
+ hexs[i] = parseInt(hexs[i], 16);
+ }
+ return hexs;
}
// rgb棰滆壊杞琱ex棰滆壊
export function rgbToHex(r, g, b) {
- const hexs = [r.toString(16), g.toString(16), b.toString(16)]
- for (let i = 0; i < 3; i++) {
- if (hexs[i].length === 1) {
- hexs[i] = `0${hexs[i]}`
- }
- }
- return `#${hexs.join('')}`
+ const hexs = [r.toString(16), g.toString(16), b.toString(16)];
+ for (let i = 0; i < 3; i++) {
+ if (hexs[i].length === 1) {
+ hexs[i] = `0${hexs[i]}`;
+ }
+ }
+ return `#${hexs.join("")}`;
}
// 鍙樻祬棰滆壊鍊�
export function getLightColor(color, level) {
- const rgb = hexToRgb(color)
- for (let i = 0; i < 3; i++) {
- rgb[i] = Math.floor((255 - rgb[i]) * level + rgb[i])
- }
- return rgbToHex(rgb[0], rgb[1], rgb[2])
+ const rgb = hexToRgb(color);
+ for (let i = 0; i < 3; i++) {
+ rgb[i] = Math.floor((255 - rgb[i]) * level + rgb[i]);
+ }
+ return rgbToHex(rgb[0], rgb[1], rgb[2]);
}
// 鍙樻繁棰滆壊鍊�
export function getDarkColor(color, level) {
- const rgb = hexToRgb(color)
- for (let i = 0; i < 3; i++) {
- rgb[i] = Math.floor(rgb[i] * (1 - level))
- }
- return rgbToHex(rgb[0], rgb[1], rgb[2])
+ const rgb = hexToRgb(color);
+ for (let i = 0; i < 3; i++) {
+ rgb[i] = Math.floor(rgb[i] * (1 - level));
+ }
+ return rgbToHex(rgb[0], rgb[1], rgb[2]);
}
function normalizeHex(color) {
- if (!color || typeof color !== 'string') return '#409eff'
- let value = color.trim().replace('#', '')
- if (value.length === 3) {
- value = value.split('').map((s) => s + s).join('')
- }
- if (!/^[0-9a-fA-F]{6}$/.test(value)) return '#409eff'
- return `#${value.toLowerCase()}`
+ if (!color || typeof color !== "string") return "#409eff";
+ let value = color.trim().replace("#", "");
+ if (value.length === 3) {
+ value = value
+ .split("")
+ .map(s => s + s)
+ .join("");
+ }
+ if (!/^[0-9a-fA-F]{6}$/.test(value)) return "#409eff";
+ return `#${value.toLowerCase()}`;
}
diff --git a/src/views/customerService/components/viewDia.vue b/src/views/customerService/components/viewDia.vue
index 96452b4..92833de 100644
--- a/src/views/customerService/components/viewDia.vue
+++ b/src/views/customerService/components/viewDia.vue
@@ -1,44 +1,73 @@
<template>
- <el-dialog v-model="dialogVisible" title="鍞悗鍗曡鎯�" width="80%" @close="closeDia">
+ <el-dialog v-model="dialogVisible"
+ title="鍞悗鍗曡鎯�"
+ width="80%"
+ @close="closeDia">
<div v-loading="loading">
<span class="descriptions">鍩虹璧勬枡</span>
- <el-descriptions :column="4" border style="margin-top: 10px;">
+ <el-descriptions :column="4"
+ border
+ style="margin-top: 10px;">
<el-descriptions-item label="瀹㈡埛鍚嶇О">{{ detail.customerName || '-' }}</el-descriptions-item>
<el-descriptions-item label="鍞悗绫诲瀷">{{ getDictLabel(classificationOptions, detail.serviceType) }}</el-descriptions-item>
<el-descriptions-item label="鍏宠仈閿�鍞崟鍙�">{{ detail.salesContractNo || '-' }}</el-descriptions-item>
<el-descriptions-item label="绱ф�ョ▼搴�">{{ getDictLabel(degreeOfUrgencyOptions, detail.urgency) }}</el-descriptions-item>
<el-descriptions-item label="宸ュ崟缂栧彿">{{ detail.afterSalesServiceNo || '-' }}</el-descriptions-item>
<el-descriptions-item label="澶勭悊鐘舵��">
- <el-tag :type="detail.status === 1 ? 'danger' : 'success'" size="small">
+ <el-tag :type="detail.status === 1 ? 'danger' : 'success'"
+ size="small">
{{ detail.status === 1 ? '寰呭鐞�' : '宸插鐞�' }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="鐧昏浜�">{{ detail.checkNickName || '-' }}</el-descriptions-item>
<el-descriptions-item label="鍙嶉鏃ユ湡">{{ detail.feedbackDate || '-' }}</el-descriptions-item>
- <el-descriptions-item label="瀹㈡埛璇夋眰" :span="4">{{ detail.proDesc || '-' }}</el-descriptions-item>
+ <el-descriptions-item label="瀹㈡埛璇夋眰"
+ :span="4">{{ detail.proDesc || '-' }}</el-descriptions-item>
</el-descriptions>
-
<div style="margin-top: 20px;">
<span class="descriptions">澶勭悊淇℃伅</span>
- <el-descriptions :column="3" border style="margin-top: 10px;">
+ <el-descriptions :column="3"
+ border
+ style="margin-top: 10px;">
<el-descriptions-item label="澶勭悊浜�">{{ detail.disposeNickName || '-' }}</el-descriptions-item>
<el-descriptions-item label="澶勭悊鏃ユ湡">{{ detail.disDate || '-' }}</el-descriptions-item>
- <el-descriptions-item label="澶勭悊缁撴灉" :span="3">{{ detail.disRes || '-' }}</el-descriptions-item>
+ <el-descriptions-item label="澶勭悊缁撴灉"
+ :span="3">{{ detail.disRes || '-' }}</el-descriptions-item>
</el-descriptions>
</div>
-
<div style="margin-top: 20px;">
<span class="descriptions">鍏宠仈浜у搧</span>
- <el-table :data="tableData" border style="width: 100%; margin-top: 10px;">
- <el-table-column type="index" label="搴忓彿" width="60" align="center" />
- <el-table-column prop="productCategory" label="浜у搧澶х被" align="center" />
- <el-table-column prop="specificationModel" label="瑙勬牸鍨嬪彿" align="center" />
- <el-table-column prop="unit" label="鍗曚綅" align="center" />
- <el-table-column prop="expressCompany" label="蹇�掑叕鍙�" align="center" />
- <el-table-column prop="expressNumber" label="蹇�掑崟鍙�" align="center" />
- <el-table-column prop="shippingCarNumber" label="鍙戣揣杞︾墝" align="center" />
- <el-table-column prop="shippingDate" label="鍙戣揣鏃ユ湡" align="center" />
- <el-table-column prop="quantity" label="鍞悗鏁伴噺" align="center" />
+ <el-table :data="tableData"
+ border
+ style="width: 100%; margin-top: 10px;">
+ <el-table-column type="index"
+ label="搴忓彿"
+ width="60"
+ align="center" />
+ <el-table-column prop="productCategory"
+ label="浜у搧澶х被"
+ align="center" />
+ <el-table-column prop="specificationModel"
+ label="瑙勬牸鍨嬪彿"
+ align="center" />
+ <el-table-column prop="unit"
+ label="鍗曚綅"
+ align="center" />
+ <el-table-column prop="expressCompany"
+ label="蹇�掑叕鍙�"
+ align="center" />
+ <el-table-column prop="expressNumber"
+ label="蹇�掑崟鍙�"
+ align="center" />
+ <el-table-column prop="shippingCarNumber"
+ label="鍙戣揣杞︾墝"
+ align="center" />
+ <el-table-column prop="shippingDate"
+ label="鍙戣揣鏃ユ湡"
+ align="center" />
+ <el-table-column prop="quantity"
+ label="鍞悗鏁伴噺"
+ align="center" />
</el-table>
</div>
</div>
@@ -51,73 +80,81 @@
</template>
<script setup>
-import { ref, computed, getCurrentInstance } from 'vue';
-import { getAfterSalesServiceById } from '@/api/customerService/index.js';
+ import { ref, computed, getCurrentInstance } from "vue";
+ import { getAfterSalesServiceById } from "@/api/customerService/index.js";
-const { proxy } = getCurrentInstance();
-const dialogVisible = ref(false);
-const loading = ref(false);
-const detail = ref({});
-const tableData = ref([]);
+ const { proxy } = getCurrentInstance();
+ const dialogVisible = ref(false);
+ const loading = ref(false);
+ const detail = ref({});
+ const tableData = ref([]);
-const { post_sale_waiting_list, degree_of_urgency } = proxy.useDict(
- "post_sale_waiting_list",
- "degree_of_urgency"
-);
-const classificationOptions = computed(() => post_sale_waiting_list?.value || []);
-const degreeOfUrgencyOptions = computed(() => degree_of_urgency?.value || []);
+ const { post_sale_waiting_list, degree_of_urgency } = proxy.useDict(
+ "post_sale_waiting_list",
+ "degree_of_urgency"
+ );
+ const classificationOptions = computed(
+ () => post_sale_waiting_list?.value || []
+ );
+ const degreeOfUrgencyOptions = computed(() => degree_of_urgency?.value || []);
-const getDictLabel = (options, value) => {
- if (!value) return '-';
- const item = options.find(i => String(i.value) === String(value));
- return item ? item.label : value;
-};
+ const getDictLabel = (options, value) => {
+ if (!value) return "-";
+ const item = options.find(i => String(i.value) === String(value));
+ return item ? item.label : value;
+ };
-const openDialog = (row) => {
- dialogVisible.value = true;
- loading.value = true;
- detail.value = {};
- tableData.value = [];
-
- getAfterSalesServiceById(row.id).then(res => {
- loading.value = false;
- if (res.code === 200) {
- detail.value = res.data || {};
- let productData = res.data?.salesLedgerDto?.productData || [];
- const selectedIds = res.data.productModelIds ? String(res.data.productModelIds).split(",") : [];
- tableData.value = productData.filter(item => selectedIds.includes(String(item.id)));
- }
- }).catch(() => {
- loading.value = false;
+ const openDialog = row => {
+ dialogVisible.value = true;
+ loading.value = true;
+ detail.value = {};
+ tableData.value = [];
+
+ getAfterSalesServiceById(row.id)
+ .then(res => {
+ loading.value = false;
+ if (res.code === 200) {
+ detail.value = res.data || {};
+ let productData = res.data?.salesLedgerDto?.productData || [];
+ const selectedIds = res.data.productModelIds
+ ? String(res.data.productModelIds).split(",")
+ : [];
+ tableData.value = productData.filter(item =>
+ selectedIds.includes(String(item.id))
+ );
+ }
+ })
+ .catch(() => {
+ loading.value = false;
+ });
+ };
+
+ const closeDia = () => {
+ dialogVisible.value = false;
+ };
+
+ defineExpose({
+ openDialog,
});
-};
-
-const closeDia = () => {
- dialogVisible.value = false;
-};
-
-defineExpose({
- openDialog
-});
</script>
<style scoped>
-.descriptions {
- display: inline-block;
- font-size: 1rem;
- font-weight: 600;
- padding-left: 12px;
- position: relative;
-}
-.descriptions::before {
- content: "";
- position: absolute;
- left: 0;
- top: 50%;
- transform: translateY(-50%);
- width: 4px;
- height: 1rem;
- background-color: #002fa7;
- border-radius: 2px;
-}
+ .descriptions {
+ display: inline-block;
+ font-size: 1rem;
+ font-weight: 600;
+ padding-left: 12px;
+ position: relative;
+ }
+ .descriptions::before {
+ content: "";
+ position: absolute;
+ left: 0;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 4px;
+ height: 1rem;
+ background-color: #374d77;
+ border-radius: 2px;
+ }
</style>
diff --git a/src/views/customerService/feedbackRegistration/components/formDia.vue b/src/views/customerService/feedbackRegistration/components/formDia.vue
index e606107..0db27c1 100644
--- a/src/views/customerService/feedbackRegistration/components/formDia.vue
+++ b/src/views/customerService/feedbackRegistration/components/formDia.vue
@@ -98,7 +98,9 @@
</el-tag>
</template>
<template #quantity="{ row }">
- <el-input-number v-model="row.quantity" :min="0" size="small" />
+ <el-input-number v-model="row.quantity"
+ :min="0"
+ size="small" />
</template>
</PIMTable>
</div>
@@ -442,15 +444,25 @@
);
if (opt) {
let restoredData = (opt.productData || []).map(normalizeProductRow);
- const selectedIds = form.value.productModelIds ? String(form.value.productModelIds).split(",") : [];
- const quantities = form.value.productModelQuantities ? String(form.value.productModelQuantities).split(",") : [];
- tableData.value = restoredData.filter(item => selectedIds.includes(String(item.id))).map(item => {
- let qIndex = selectedIds.indexOf(String(item.id));
- if (qIndex !== -1 && qIndex < quantities.length && quantities[qIndex] !== "") {
- item.quantity = Number(quantities[qIndex]);
- }
- return item;
- });
+ const selectedIds = form.value.productModelIds
+ ? String(form.value.productModelIds).split(",")
+ : [];
+ const quantities = form.value.productModelQuantities
+ ? String(form.value.productModelQuantities).split(",")
+ : [];
+ tableData.value = restoredData
+ .filter(item => selectedIds.includes(String(item.id)))
+ .map(item => {
+ let qIndex = selectedIds.indexOf(String(item.id));
+ if (
+ qIndex !== -1 &&
+ qIndex < quantities.length &&
+ quantities[qIndex] !== ""
+ ) {
+ item.quantity = Number(quantities[qIndex]);
+ }
+ return item;
+ });
}
}
}
@@ -510,7 +522,7 @@
transform: translateY(-50%);
width: 4px;
height: 1rem;
- background-color: #002fa7; /* Element 榛樿绾㈣壊 */
+ background-color: #374d77; /* Element 榛樿绾㈣壊 */
border-radius: 2px;
}
</style>
diff --git a/src/views/login.vue b/src/views/login.vue
index c7db15a..6bdabe5 100644
--- a/src/views/login.vue
+++ b/src/views/login.vue
@@ -4,15 +4,12 @@
<section class="factory">
<div class="brand hero-brand">
<div class="logo hero-logo">
- <img
- :src="brandLogoUrl"
- :alt="`${companyName} logo`"
- class="logo-image hero-logo-image"
- @error="handleLogoError"
- />
+ <img :src="brandLogoUrl"
+ :alt="`${companyName} logo`"
+ class="logo-image hero-logo-image"
+ @error="handleLogoError" />
</div>
</div>
-
<div class="hero">
<div class="chip">鏁板瓧宸ュ巶 路 鏅鸿兘鎺掍骇 路 璁惧浜掕仈 路 璐ㄩ噺杩芥函</div>
<h1>鏁板瓧宸ュ巶<br />MOM 鏅洪�犲钩鍙�</h1>
@@ -20,132 +17,251 @@
浠ュ疄鏃舵暟鎹┍鍔ㄧ敓浜х幇鍦猴紝鎶婂伐鍗曘�佽澶囥�佺墿鏂欍�佽川閲忋�佽兘鑰椾笌浠撳偍杩炴帴鎴愪竴寮犻�忔槑鐨勫埗閫犺繍钀ョ綉缁溿��
</p>
</div>
-
- <div class="scene" aria-hidden="true">
+ <div class="scene"
+ aria-hidden="true">
<div class="floor"></div>
- <svg class="factory-svg" viewBox="0 0 920 360" preserveAspectRatio="xMidYMid meet">
+ <svg class="factory-svg"
+ viewBox="0 0 920 360"
+ preserveAspectRatio="xMidYMid meet">
<defs>
- <linearGradient id="g1" x1="0" y1="0" x2="1" y2="1">
- <stop offset="0" stop-color="#40e4ff" stop-opacity=".9" />
- <stop offset="1" stop-color="#1f78ff" stop-opacity=".68" />
+ <linearGradient id="g1"
+ x1="0"
+ y1="0"
+ x2="1"
+ y2="1">
+ <stop offset="0"
+ stop-color="#40e4ff"
+ stop-opacity=".9" />
+ <stop offset="1"
+ stop-color="#1f78ff"
+ stop-opacity=".68" />
</linearGradient>
- <linearGradient id="g2" x1="0" y1="0" x2="1" y2="1">
- <stop offset="0" stop-color="#ffffff" stop-opacity=".28" />
- <stop offset="1" stop-color="#ffffff" stop-opacity=".06" />
+ <linearGradient id="g2"
+ x1="0"
+ y1="0"
+ x2="1"
+ y2="1">
+ <stop offset="0"
+ stop-color="#ffffff"
+ stop-opacity=".28" />
+ <stop offset="1"
+ stop-color="#ffffff"
+ stop-opacity=".06" />
</linearGradient>
</defs>
-
- <path d="M45 255H830" stroke="url(#g1)" stroke-width="16" stroke-linecap="round" opacity=".55" />
- <path class="belt" d="M45 255H830" stroke="#fff" stroke-width="3" stroke-linecap="round" opacity=".75" />
-
+ <path d="M45 255H830"
+ stroke="url(#g1)"
+ stroke-width="16"
+ stroke-linecap="round"
+ opacity=".55" />
+ <path class="belt"
+ d="M45 255H830"
+ stroke="#fff"
+ stroke-width="3"
+ stroke-linecap="round"
+ opacity=".75" />
<g class="box">
- <rect x="60" y="212" width="54" height="42" rx="8" fill="#ffb15f" />
- <path d="M60 225h54" stroke="#fff" opacity=".45" />
+ <rect x="60"
+ y="212"
+ width="54"
+ height="42"
+ rx="8"
+ fill="#ffb15f" />
+ <path d="M60 225h54"
+ stroke="#fff"
+ opacity=".45" />
</g>
<g class="box two">
- <rect x="60" y="212" width="54" height="42" rx="8" fill="#28d9cd" />
- <path d="M60 225h54" stroke="#fff" opacity=".45" />
+ <rect x="60"
+ y="212"
+ width="54"
+ height="42"
+ rx="8"
+ fill="#28d9cd" />
+ <path d="M60 225h54"
+ stroke="#fff"
+ opacity=".45" />
</g>
<g class="box three">
- <rect x="60" y="212" width="54" height="42" rx="8" fill="#8b5cf6" />
- <path d="M60 225h54" stroke="#fff" opacity=".45" />
+ <rect x="60"
+ y="212"
+ width="54"
+ height="42"
+ rx="8"
+ fill="#8b5cf6" />
+ <path d="M60 225h54"
+ stroke="#fff"
+ opacity=".45" />
</g>
-
<g>
- <rect x="120" y="112" width="138" height="128" rx="18" fill="url(#g2)" stroke="rgba(255,255,255,.42)" />
- <path d="M145 185h88M145 210h58" stroke="#40e4ff" stroke-width="6" stroke-linecap="round" />
- <path d="M145 140h88" stroke="#fff" stroke-opacity=".5" stroke-width="4" stroke-linecap="round" />
+ <rect x="120"
+ y="112"
+ width="138"
+ height="128"
+ rx="18"
+ fill="url(#g2)"
+ stroke="rgba(255,255,255,.42)" />
+ <path d="M145 185h88M145 210h58"
+ stroke="#40e4ff"
+ stroke-width="6"
+ stroke-linecap="round" />
+ <path d="M145 140h88"
+ stroke="#fff"
+ stroke-opacity=".5"
+ stroke-width="4"
+ stroke-linecap="round" />
</g>
-
<g>
- <rect x="315" y="76" width="190" height="164" rx="22" fill="url(#g2)" stroke="rgba(255,255,255,.42)" />
- <path d="M350 126h120M350 158h90M350 190h112" stroke="#fff" stroke-opacity=".5" stroke-width="6" stroke-linecap="round" />
- <circle class="signal" cx="472" cy="104" r="10" fill="#20e0d2" />
- <circle class="signal two" cx="448" cy="104" r="10" fill="#1f78ff" />
- <circle class="signal three" cx="424" cy="104" r="10" fill="#ff8a3d" />
+ <rect x="315"
+ y="76"
+ width="190"
+ height="164"
+ rx="22"
+ fill="url(#g2)"
+ stroke="rgba(255,255,255,.42)" />
+ <path d="M350 126h120M350 158h90M350 190h112"
+ stroke="#fff"
+ stroke-opacity=".5"
+ stroke-width="6"
+ stroke-linecap="round" />
+ <circle class="signal"
+ cx="472"
+ cy="104"
+ r="10"
+ fill="#20e0d2" />
+ <circle class="signal two"
+ cx="448"
+ cy="104"
+ r="10"
+ fill="#1f78ff" />
+ <circle class="signal three"
+ cx="424"
+ cy="104"
+ r="10"
+ fill="#ff8a3d" />
</g>
-
<g class="arm">
- <path d="M612 124h92" stroke="#40e4ff" stroke-width="14" stroke-linecap="round" />
- <path d="M704 124l42 56" stroke="#40e4ff" stroke-width="14" stroke-linecap="round" />
- <circle cx="612" cy="124" r="25" fill="#1f78ff" stroke="#fff" stroke-opacity=".45" />
- <circle cx="704" cy="124" r="18" fill="#20e0d2" />
- <path d="M744 180v34M727 214h34" stroke="#fff" stroke-width="7" stroke-linecap="round" />
+ <path d="M612 124h92"
+ stroke="#40e4ff"
+ stroke-width="14"
+ stroke-linecap="round" />
+ <path d="M704 124l42 56"
+ stroke="#40e4ff"
+ stroke-width="14"
+ stroke-linecap="round" />
+ <circle cx="612"
+ cy="124"
+ r="25"
+ fill="#1f78ff"
+ stroke="#fff"
+ stroke-opacity=".45" />
+ <circle cx="704"
+ cy="124"
+ r="18"
+ fill="#20e0d2" />
+ <path d="M744 180v34M727 214h34"
+ stroke="#fff"
+ stroke-width="7"
+ stroke-linecap="round" />
</g>
-
<g>
- <rect x="690" y="82" width="148" height="158" rx="20" fill="url(#g2)" stroke="rgba(255,255,255,.42)" />
- <path d="M724 206V134M764 206V112M804 206V154" stroke="#20e0d2" stroke-width="12" stroke-linecap="round" />
- <path d="M720 206h92" stroke="#fff" stroke-opacity=".44" stroke-width="5" stroke-linecap="round" />
+ <rect x="690"
+ y="82"
+ width="148"
+ height="158"
+ rx="20"
+ fill="url(#g2)"
+ stroke="rgba(255,255,255,.42)" />
+ <path d="M724 206V134M764 206V112M804 206V154"
+ stroke="#20e0d2"
+ stroke-width="12"
+ stroke-linecap="round" />
+ <path d="M720 206h92"
+ stroke="#fff"
+ stroke-opacity=".44"
+ stroke-width="5"
+ stroke-linecap="round" />
</g>
-
- <path
- d="M190 112C265 42 348 48 410 76C502 118 568 76 612 124C654 170 700 74 764 82"
- fill="none"
- stroke="#20e0d2"
- stroke-width="2"
- stroke-dasharray="8 10"
- opacity=".58"
- >
- <animate attributeName="stroke-dashoffset" from="80" to="0" dur="2s" repeatCount="indefinite" />
+ <path d="M190 112C265 42 348 48 410 76C502 118 568 76 612 124C654 170 700 74 764 82"
+ fill="none"
+ stroke="#20e0d2"
+ stroke-width="2"
+ stroke-dasharray="8 10"
+ opacity=".58">
+ <animate attributeName="stroke-dashoffset"
+ from="80"
+ to="0"
+ dur="2s"
+ repeatCount="indefinite" />
</path>
</svg>
</div>
</section>
-
<section class="login-wrap">
<div class="time">
<span>{{ todayLabel }}</span>
{{ clockLabel }}
</div>
-
- <form class="login-card" @submit.prevent="handleLogin">
+ <form class="login-card"
+ @submit.prevent="handleLogin">
<div class="brand card-brand">
<div class="logo">
- <img :src="brandIconUrl" :alt="`${companyName} icon`" class="logo-image card-logo-image" />
+ <img :src="brandIconUrl"
+ :alt="`${companyName} icon`"
+ class="logo-image card-logo-image" />
</div>
- <div class="brand-copy card-brand-copy">
- <div class="brand-title">{{ companyName }}</div>
- <small>鏁板瓧宸ュ巶缁熶竴鍏ュ彛</small>
- </div>
+ <div class="brand-copy card-brand-copy">
+ <div class="brand-title">{{ companyName }}</div>
+ <small>鏁板瓧宸ュ巶缁熶竴鍏ュ彛</small>
+ </div>
</div>
-
<h2>娆㈣繋鐧诲綍</h2>
<p class="sub">杩涘叆 MOM 鏁板瓧宸ュ巶杩愯惀椹鹃┒鑸�</p>
-
<div class="form-row">
<label>璐﹀彿</label>
<div class="input">
- <svg viewBox="0 0 24 24" fill="none">
- <path d="M20 21a8 8 0 0 0-16 0" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" />
- <path d="M12 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8Z" stroke="currentColor" stroke-width="1.8" />
+ <svg viewBox="0 0 24 24"
+ fill="none">
+ <path d="M20 21a8 8 0 0 0-16 0"
+ stroke="currentColor"
+ stroke-width="1.8"
+ stroke-linecap="round" />
+ <path d="M12 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8Z"
+ stroke="currentColor"
+ stroke-width="1.8" />
</svg>
- <input v-model.trim="loginForm.username" type="text" placeholder="璇疯緭鍏ョ鐞嗗憳璐﹀彿" />
+ <input v-model.trim="loginForm.username"
+ type="text"
+ placeholder="璇疯緭鍏ョ鐞嗗憳璐﹀彿" />
</div>
</div>
-
<div class="form-row">
<label>瀵嗙爜</label>
<div class="input">
- <svg viewBox="0 0 24 24" fill="none">
- <path d="M7 10V8a5 5 0 0 1 10 0v2" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" />
- <path d="M6.8 10h10.4A1.8 1.8 0 0 1 19 11.8v6.4A1.8 1.8 0 0 1 17.2 20H6.8A1.8 1.8 0 0 1 5 18.2v-6.4A1.8 1.8 0 0 1 6.8 10Z" stroke="currentColor" stroke-width="1.8" />
+ <svg viewBox="0 0 24 24"
+ fill="none">
+ <path d="M7 10V8a5 5 0 0 1 10 0v2"
+ stroke="currentColor"
+ stroke-width="1.8"
+ stroke-linecap="round" />
+ <path d="M6.8 10h10.4A1.8 1.8 0 0 1 19 11.8v6.4A1.8 1.8 0 0 1 17.2 20H6.8A1.8 1.8 0 0 1 5 18.2v-6.4A1.8 1.8 0 0 1 6.8 10Z"
+ stroke="currentColor"
+ stroke-width="1.8" />
</svg>
- <input
- v-model="loginForm.password"
- type="password"
- placeholder="璇疯緭鍏ョ櫥褰曞瘑鐮�"
- autocomplete="current-password"
- @keyup.enter="handleLogin"
- />
+ <input v-model="loginForm.password"
+ type="password"
+ placeholder="璇疯緭鍏ョ櫥褰曞瘑鐮�"
+ autocomplete="current-password"
+ @keyup.enter="handleLogin" />
</div>
</div>
-
<div class="options">
- <label class="check"><input v-model="loginForm.rememberMe" type="checkbox" />璁颁綇璐﹀彿</label>
+ <label class="check"><input v-model="loginForm.rememberMe"
+ type="checkbox" />璁颁綇璐﹀彿</label>
</div>
-
- <button class="login-btn" type="submit" :disabled="loading">
+ <button class="login-btn"
+ type="submit"
+ :disabled="loading">
{{ loading ? "鐧诲綍涓�..." : "鐧诲綍鏁板瓧宸ュ巶" }}
</button>
</form>
@@ -155,739 +271,901 @@
</template>
<script setup>
-import { ElMessage } from "element-plus"
-import Cookies from "js-cookie"
-import { encrypt, decrypt } from "@/utils/jsencrypt"
-import useUserStore from "@/store/modules/user"
-import defaultBrandLogo from "@/assets/logo/logo.png"
+ import { ElMessage } from "element-plus";
+ import Cookies from "js-cookie";
+ import { encrypt, decrypt } from "@/utils/jsencrypt";
+ import useUserStore from "@/store/modules/user";
+ import defaultBrandLogo from "@/assets/logo/logo.png";
-const userStore = useUserStore()
-const route = useRoute()
-const router = useRouter()
+ const userStore = useUserStore();
+ const route = useRoute();
+ const router = useRouter();
-const appTitle = String(import.meta.env.VITE_APP_TITLE || "鏁板瓧宸ュ巶 MOM 绯荤粺").trim()
-const companySubtitle = String(import.meta.env.VITE_LOGIN_SUBTITLE || "Digital Factory Operation Center").trim()
-const configuredLogo = String(import.meta.env.VITE_APP_LOGO || "").trim()
-const logoModules = import.meta.glob("/src/assets/logo/*.png", { eager: true })
-const brandIconUrl = `${import.meta.env.BASE_URL}favicon.ico`
+ const appTitle = String(
+ import.meta.env.VITE_APP_TITLE || "鏁板瓧宸ュ巶 MOM 绯荤粺"
+ ).trim();
+ const companySubtitle = String(
+ import.meta.env.VITE_LOGIN_SUBTITLE || "Digital Factory Operation Center"
+ ).trim();
+ const configuredLogo = String(import.meta.env.VITE_APP_LOGO || "").trim();
+ const logoModules = import.meta.glob("/src/assets/logo/*.png", { eager: true });
+ const brandIconUrl = `${import.meta.env.BASE_URL}favicon.ico`;
-const redirect = ref("")
-const loading = ref(false)
-const now = ref(new Date())
-const brandLogoUrl = ref(defaultBrandLogo)
+ const redirect = ref("");
+ const loading = ref(false);
+ const now = ref(new Date());
+ const brandLogoUrl = ref(defaultBrandLogo);
-const loginForm = ref({
- username: "",
- password: "",
- rememberMe: false,
-})
+ const loginForm = ref({
+ username: "",
+ password: "",
+ rememberMe: false,
+ });
-const companyName = computed(() => {
- const currentFactoryName = String(userStore.currentFactoryName || "").trim()
- return currentFactoryName || appTitle
-})
+ const companyName = computed(() => {
+ const currentFactoryName = String(userStore.currentFactoryName || "").trim();
+ return currentFactoryName || appTitle;
+ });
-const todayLabel = computed(() => {
- const date = now.value
- return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`
-})
+ const todayLabel = computed(() => {
+ const date = now.value;
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(
+ date.getDate()
+ )}`;
+ });
-const clockLabel = computed(() => {
- const date = now.value
- return `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`
-})
+ const clockLabel = computed(() => {
+ const date = now.value;
+ return `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(
+ date.getSeconds()
+ )}`;
+ });
-watch(
- route,
- (newRoute) => {
- redirect.value = String(newRoute.query?.redirect || "")
- },
- { immediate: true }
-)
+ watch(
+ route,
+ newRoute => {
+ redirect.value = String(newRoute.query?.redirect || "");
+ },
+ { immediate: true }
+ );
-watch(
- () => userStore.currentFactoryName,
- () => updateBrandLogo(),
- { immediate: true }
-)
+ watch(
+ () => userStore.currentFactoryName,
+ () => updateBrandLogo(),
+ { immediate: true }
+ );
-let timer = 0
-onMounted(() => {
- timer = window.setInterval(() => {
- now.value = new Date()
- }, 1000)
-})
+ let timer = 0;
+ onMounted(() => {
+ timer = window.setInterval(() => {
+ now.value = new Date();
+ }, 1000);
+ });
-onBeforeUnmount(() => {
- if (timer) {
- window.clearInterval(timer)
- timer = 0
- }
-})
+ onBeforeUnmount(() => {
+ if (timer) {
+ window.clearInterval(timer);
+ timer = 0;
+ }
+ });
-function pad(value) {
- return String(value).padStart(2, "0")
-}
-
-function resolveConfiguredLogo() {
- if (!configuredLogo) {
- return ""
+ function pad(value) {
+ return String(value).padStart(2, "0");
}
- if (/^(https?:)?\/\//.test(configuredLogo) || configuredLogo.startsWith("data:")) {
- return configuredLogo
+ function resolveConfiguredLogo() {
+ if (!configuredLogo) {
+ return "";
+ }
+
+ if (
+ /^(https?:)?\/\//.test(configuredLogo) ||
+ configuredLogo.startsWith("data:")
+ ) {
+ return configuredLogo;
+ }
+
+ const cleanPath = configuredLogo.replace(/^\/+/, "");
+ const fullPath = cleanPath.startsWith("src/")
+ ? `/${cleanPath}`
+ : `/src/${cleanPath}`;
+ const localLogo = logoModules[fullPath];
+
+ if (localLogo && localLogo.default) {
+ return localLogo.default;
+ }
+
+ if (configuredLogo.startsWith("/")) {
+ return configuredLogo;
+ }
+
+ return `${import.meta.env.BASE_URL}${cleanPath}`;
}
- const cleanPath = configuredLogo.replace(/^\/+/, "")
- const fullPath = cleanPath.startsWith("src/") ? `/${cleanPath}` : `/src/${cleanPath}`
- const localLogo = logoModules[fullPath]
+ function updateBrandLogo() {
+ const logoFromConfig = resolveConfiguredLogo();
+ if (logoFromConfig) {
+ brandLogoUrl.value = logoFromConfig;
+ return;
+ }
- if (localLogo && localLogo.default) {
- return localLogo.default
+ const currentFactoryName = String(userStore.currentFactoryName || "").trim();
+ if (!currentFactoryName) {
+ brandLogoUrl.value = defaultBrandLogo;
+ return;
+ }
+
+ const factoryLogoPath = `/src/assets/logo/${currentFactoryName}.png`;
+ const matched = logoModules[factoryLogoPath];
+ brandLogoUrl.value =
+ matched && matched.default ? matched.default : defaultBrandLogo;
}
- if (configuredLogo.startsWith("/")) {
- return configuredLogo
+ function handleLogoError() {
+ brandLogoUrl.value = defaultBrandLogo;
}
- return `${import.meta.env.BASE_URL}${cleanPath}`
-}
+ function handleRememberCookie() {
+ if (!loginForm.value.rememberMe) {
+ Cookies.remove("username");
+ Cookies.remove("password");
+ Cookies.remove("rememberMe");
+ return;
+ }
-function updateBrandLogo() {
- const logoFromConfig = resolveConfiguredLogo()
- if (logoFromConfig) {
- brandLogoUrl.value = logoFromConfig
- return
+ Cookies.set("username", loginForm.value.username, { expires: 30 });
+ Cookies.set("password", encrypt(loginForm.value.password), { expires: 30 });
+ Cookies.set("rememberMe", "true", { expires: 30 });
}
- const currentFactoryName = String(userStore.currentFactoryName || "").trim()
- if (!currentFactoryName) {
- brandLogoUrl.value = defaultBrandLogo
- return
+ function getCookie() {
+ const username = Cookies.get("username");
+ const password = Cookies.get("password");
+ const rememberMe = Cookies.get("rememberMe");
+
+ loginForm.value.username = username || "";
+ loginForm.value.password = password ? decrypt(password) : "";
+ loginForm.value.rememberMe = rememberMe === "true";
}
- const factoryLogoPath = `/src/assets/logo/${currentFactoryName}.png`
- const matched = logoModules[factoryLogoPath]
- brandLogoUrl.value = matched && matched.default ? matched.default : defaultBrandLogo
-}
+ function handleLogin() {
+ if (!loginForm.value.username) {
+ ElMessage.error("璇疯緭鍏ヨ处鍙�");
+ return;
+ }
+ if (!loginForm.value.password) {
+ ElMessage.error("璇疯緭鍏ュ瘑鐮�");
+ return;
+ }
-function handleLogoError() {
- brandLogoUrl.value = defaultBrandLogo
-}
-
-function handleRememberCookie() {
- if (!loginForm.value.rememberMe) {
- Cookies.remove("username")
- Cookies.remove("password")
- Cookies.remove("rememberMe")
- return
- }
-
- Cookies.set("username", loginForm.value.username, { expires: 30 })
- Cookies.set("password", encrypt(loginForm.value.password), { expires: 30 })
- Cookies.set("rememberMe", "true", { expires: 30 })
-}
-
-function getCookie() {
- const username = Cookies.get("username")
- const password = Cookies.get("password")
- const rememberMe = Cookies.get("rememberMe")
-
- loginForm.value.username = username || ""
- loginForm.value.password = password ? decrypt(password) : ""
- loginForm.value.rememberMe = rememberMe === "true"
-}
-
-function handleLogin() {
- if (!loginForm.value.username) {
- ElMessage.error("璇疯緭鍏ヨ处鍙�")
- return
- }
- if (!loginForm.value.password) {
- ElMessage.error("璇疯緭鍏ュ瘑鐮�")
- return
- }
-
- loading.value = true
- handleRememberCookie()
+ loading.value = true;
+ handleRememberCookie();
userStore
.loginCheckFactory(loginForm.value)
.then(() => {
- const query = route.query
- const otherQueryParams = Object.keys(query).reduce((acc, cur) => {
- if (cur !== "redirect") {
- acc[cur] = query[cur]
- }
- return acc
- }, {})
- router.push({ path: redirect.value || "/", query: otherQueryParams })
+ const query = route.query;
+ const otherQueryParams = Object.keys(query).reduce((acc, cur) => {
+ if (cur !== "redirect") {
+ acc[cur] = query[cur];
+ }
+ return acc;
+ }, {});
+ router.push({ path: redirect.value || "/", query: otherQueryParams });
})
.catch(() => {})
.finally(() => {
- loading.value = false
- })
-}
+ loading.value = false;
+ });
+ }
-getCookie()
+ getCookie();
</script>
<style scoped lang="scss">
-* {
- box-sizing: border-box;
-}
-
-.login-page {
- --blue: #1f78ff;
- --cyan: #20e0d2;
- --violet: #8b5cf6;
- --orange: #ff8a3d;
- --text: #09203f;
- --muted: #7a8da8;
- --line: rgba(113, 154, 214, 0.24);
- --shadow: 0 28px 80px rgba(14, 57, 120, 0.18);
- min-height: 100vh;
- overflow: hidden;
- background:
- radial-gradient(circle at 12% 16%, rgba(31, 120, 255, 0.22), transparent 32%),
- radial-gradient(circle at 84% 14%, rgba(32, 224, 210, 0.24), transparent 28%),
- radial-gradient(circle at 80% 84%, rgba(139, 92, 246, 0.14), transparent 28%),
- linear-gradient(135deg, #eef6ff 0%, #f7fbff 52%, #edf8ff 100%);
-}
-
-.login-page::before {
- content: "";
- position: fixed;
- inset: 0;
- background-image:
- linear-gradient(rgba(22, 78, 160, 0.055) 1px, transparent 1px),
- linear-gradient(90deg, rgba(22, 78, 160, 0.055) 1px, transparent 1px);
- background-size: 36px 36px;
- mask-image: radial-gradient(circle at center, #000 0%, transparent 78%);
- pointer-events: none;
-}
-
-.page {
- position: relative;
- display: grid;
- grid-template-columns: 1.15fr 0.85fr;
- gap: 28px;
- min-height: 100vh;
- padding: 36px;
-}
-
-.factory {
- position: relative;
- overflow: hidden;
- min-height: calc(100vh - 72px);
- border-radius: 30px;
- padding: 32px;
- color: #fff;
- background:
- linear-gradient(135deg, rgba(5, 27, 67, 0.98), rgba(9, 71, 143, 0.92)),
- radial-gradient(circle at 76% 18%, rgba(32, 224, 210, 0.38), transparent 30%);
- box-shadow: var(--shadow);
- border: 1px solid rgba(255, 255, 255, 0.16);
- animation: enter 0.8s ease both;
-}
-
-.factory::before {
- content: "";
- position: absolute;
- inset: 0;
- background:
- linear-gradient(120deg, transparent 0%, rgba(255, 255, 255, 0.11) 46%, transparent 72%),
- linear-gradient(rgba(255, 255, 255, 0.055) 1px, transparent 1px),
- linear-gradient(90deg, rgba(255, 255, 255, 0.055) 1px, transparent 1px);
- background-size: 100% 100%, 44px 44px, 44px 44px;
- opacity: 0.86;
-}
-
-.brand {
- position: relative;
- z-index: 2;
- display: inline-flex;
- align-items: center;
-}
-
-.logo {
- width: 76px;
- height: 76px;
- border-radius: 14px;
- display: grid;
- place-items: center;
- background: linear-gradient(135deg, var(--blue), var(--cyan));
- box-shadow: 0 16px 40px rgba(32, 224, 210, 0.26);
- overflow: hidden;
- position: relative;
-}
-
-.logo-image {
- width: 82%;
- height: 82%;
- object-fit: contain;
-}
-
-.hero-brand {
- display: block;
-}
-
-.hero-logo {
- width: 240px;
- height: 84px;
- border-radius: 0;
- background: transparent;
- box-shadow: none;
- overflow: visible;
- place-items: center start;
-}
-
-.hero-logo-image {
- width: 100%;
- height: auto;
- max-height: 100%;
- object-fit: contain;
-}
-
-.hero {
- position: relative;
- z-index: 2;
- margin-top: 64px;
- max-width: 680px;
-}
-
-.chip {
- display: inline-flex;
- align-items: center;
- gap: 8px;
- padding: 8px 14px;
- border-radius: 999px;
- border: 1px solid rgba(255, 255, 255, 0.18);
- background: rgba(255, 255, 255, 0.1);
- color: rgba(255, 255, 255, 0.78);
- font-size: 13px;
- animation: enter 0.75s ease 0.15s both;
-}
-
-.hero h1 {
- margin: 24px 0 14px;
- font-size: clamp(42px, 5.6vw, 78px);
- line-height: 1.02;
- font-weight: 900;
- letter-spacing: 0;
- animation: enter 0.8s ease 0.25s both;
-}
-
-.hero p {
- margin: 0;
- max-width: 630px;
- font-size: 17px;
- line-height: 1.8;
- color: rgba(255, 255, 255, 0.72);
- animation: enter 0.8s ease 0.35s both;
-}
-
-.scene {
- position: absolute;
- left: 42px;
- right: 42px;
- bottom: 24px;
- height: 44%;
- z-index: 1;
-}
-
-.floor {
- position: absolute;
- left: 0;
- right: 0;
- bottom: 0;
- height: 48%;
- border-radius: 28px;
- background:
- linear-gradient(90deg, rgba(32, 224, 210, 0), rgba(32, 224, 210, 0.22), rgba(31, 120, 255, 0)),
- repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.1) 0 1px, transparent 1px 64px),
- repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.1) 0 1px, transparent 1px 34px);
- transform: perspective(620px) rotateX(58deg);
- transform-origin: bottom;
- opacity: 0.82;
-}
-
-.factory-svg {
- position: absolute;
- left: 0;
- right: 0;
- bottom: 18%;
- width: 100%;
- height: 78%;
- filter: drop-shadow(0 28px 30px rgba(0, 0, 0, 0.18));
-}
-
-.belt {
- stroke-dasharray: 10 12;
- animation: flow 1.2s linear infinite;
-}
-
-.arm {
- transform-origin: 612px 124px;
- animation: armMove 3.6s ease-in-out infinite;
-}
-
-.box {
- animation: boxMove 5.4s linear infinite;
-}
-
-.box.two {
- animation-delay: -1.8s;
-}
-
-.box.three {
- animation-delay: -3.6s;
-}
-
-.signal {
- opacity: 0.8;
- animation: pulse 2.2s ease-in-out infinite;
-}
-
-.signal.two {
- animation-delay: -0.7s;
-}
-
-.signal.three {
- animation-delay: -1.4s;
-}
-
-.login-wrap {
- position: relative;
- z-index: 2;
- display: flex;
- align-items: center;
- justify-content: center;
- min-height: calc(100vh - 72px);
- border-radius: 30px;
- border: 1px solid rgba(255, 255, 255, 0.8);
- background: rgba(255, 255, 255, 0.62);
- backdrop-filter: blur(20px);
- box-shadow: var(--shadow);
- animation: enter 0.8s ease 0.12s both;
-}
-
-.time {
- position: absolute;
- top: 26px;
- right: 28px;
- display: flex;
- gap: 9px;
- align-items: center;
- font-weight: 900;
- color: #12325e;
-}
-
-.time span {
- padding: 8px 12px;
- border-radius: 999px;
- background: rgba(255, 255, 255, 0.66);
- border: 1px solid var(--line);
- color: var(--muted);
- font-size: 13px;
- font-weight: 700;
-}
-
-.login-card {
- width: min(440px, 100%);
- padding: 34px;
- border-radius: 28px;
- border: 1px solid rgba(255, 255, 255, 0.95);
- background: rgba(255, 255, 255, 0.88);
- box-shadow: 0 22px 60px rgba(21, 73, 143, 0.15);
- position: relative;
- overflow: hidden;
-}
-
-.login-card::before {
- content: "";
- position: absolute;
- right: -92px;
- top: -92px;
- width: 190px;
- height: 190px;
- border-radius: 999px;
- background: conic-gradient(from 0deg, rgba(31, 120, 255, 0.2), rgba(32, 224, 210, 0.32), rgba(139, 92, 246, 0.18), rgba(31, 120, 255, 0.2));
- animation: rotate 9s linear infinite;
-}
-
-.login-card > * {
- position: relative;
- z-index: 1;
-}
-
-.card-brand {
- margin-bottom: 18px;
-}
-
-.card-brand .logo {
- width: 52px;
- height: 52px;
-}
-
-.card-brand-copy {
- margin-left: 12px;
-}
-
-.card-logo-image {
- width: 100%;
- height: 100%;
- object-fit: contain;
-}
-
-.card-brand .logo {
- width: 68px;
- height: 68px;
-}
-
-.login-card h2 {
- margin: 8px 0;
- font-size: 31px;
- line-height: 1.15;
- color: #0d2c5e;
- font-weight: 900;
- letter-spacing: 0;
-}
-
-.sub {
- margin: 0 0 24px;
- color: var(--muted);
- font-size: 14px;
-}
-
-.form-row {
- margin-bottom: 14px;
- animation: enter 0.6s ease both;
-}
-
-.form-row:nth-of-type(1) {
- animation-delay: 0.32s;
-}
-
-.form-row:nth-of-type(2) {
- animation-delay: 0.4s;
-}
-
-.form-row:nth-of-type(3) {
- animation-delay: 0.48s;
-}
-
-label {
- display: block;
- margin-bottom: 8px;
- color: #24436b;
- font-size: 13px;
- font-weight: 800;
-}
-
-.input {
- position: relative;
-}
-
-.input svg {
- position: absolute;
- left: 15px;
- top: 50%;
- width: 19px;
- height: 19px;
- transform: translateY(-50%);
- color: #8197b6;
- pointer-events: none;
-}
-
-input[type="text"],
-input[type="password"] {
- width: 100%;
- height: 52px;
- padding: 0 15px 0 46px;
- border: 1px solid rgba(108, 143, 190, 0.34);
- border-radius: 16px;
- outline: none;
- background: linear-gradient(180deg, #fff, #f8fbff);
- color: var(--text);
- font-size: 15px;
- transition: 0.2s ease;
-}
-
-input[type="text"]:hover,
-input[type="password"]:hover {
- border-color: rgba(31, 120, 255, 0.48);
- box-shadow: 0 10px 24px rgba(31, 120, 255, 0.08);
-}
-
-input[type="text"]:focus,
-input[type="password"]:focus {
- border-color: rgba(31, 120, 255, 0.72);
- box-shadow: 0 0 0 4px rgba(31, 120, 255, 0.1);
-}
-
-.options {
- display: flex;
- justify-content: flex-start;
- align-items: center;
- margin: 12px 0 22px;
- font-size: 13px;
- color: var(--muted);
-}
-
-.check {
- display: inline-flex;
- gap: 8px;
- align-items: center;
- cursor: pointer;
-}
-
-.check input {
- width: 16px;
- height: 16px;
- padding: 0;
- accent-color: var(--blue);
-}
-
-.login-btn {
- width: 100%;
- height: 54px;
- border: none;
- border-radius: 17px;
- cursor: pointer;
- color: #fff;
- font-size: 16px;
- font-weight: 900;
- background: linear-gradient(135deg, var(--blue), var(--cyan));
- box-shadow: 0 18px 38px rgba(31, 120, 255, 0.25);
- position: relative;
- overflow: hidden;
- transition: 0.18s ease;
-}
-
-.login-btn:hover:not(:disabled) {
- transform: translateY(-2px);
- box-shadow: 0 22px 48px rgba(31, 120, 255, 0.32);
-}
-
-.login-btn:disabled {
- opacity: 0.8;
- cursor: not-allowed;
-}
-
-@keyframes enter {
- from {
- opacity: 0;
- transform: translateY(26px);
- }
- to {
- opacity: 1;
- transform: translateY(0);
- }
-}
-
-@keyframes rotate {
- to {
- transform: rotate(360deg);
- }
-}
-
-@keyframes flow {
- to {
- stroke-dashoffset: -44;
- }
-}
-
-@keyframes boxMove {
- 0% {
- transform: translateX(-150px);
- opacity: 0;
- }
- 12% {
- opacity: 1;
- }
- 78% {
- opacity: 1;
- }
- 100% {
- transform: translateX(650px);
- opacity: 0;
- }
-}
-
-@keyframes armMove {
- 0%,
- 100% {
- transform: rotate(-4deg);
- }
- 50% {
- transform: rotate(9deg);
- }
-}
-
-@keyframes pulse {
- 0%,
- 100% {
- opacity: 0.45;
- transform: scale(1);
- }
- 50% {
- opacity: 1;
- transform: scale(1.18);
- }
-}
-
-@keyframes glow {
- 0%,
- 100% {
- box-shadow: 0 0 18px rgba(32, 224, 210, 0.3);
- }
- 50% {
- box-shadow: 0 0 34px rgba(32, 224, 210, 0.68);
- }
-}
-
-@media (max-width: 1320px) {
- .hero h1 {
- font-size: clamp(52px, 5.2vw, 78px);
- }
-}
-
-@media (max-width: 980px) {
.login-page {
- overflow: auto;
+ --accent: var(--accent-primary, var(--el-color-primary, #374d77));
+ --accent-rgb: var(--el-color-primary-rgb, 22, 116, 88);
+ --text: #0f172a;
+ --muted: #64748b;
+ --border: rgba(15, 23, 42, 0.1);
+ --shadow: 0 24px 70px rgba(2, 6, 23, 0.12);
+ position: relative;
+ min-height: 100vh;
+ overflow: hidden;
+ background: radial-gradient(
+ circle at 12% 14%,
+ rgba(var(--accent-rgb), 0.14),
+ transparent 38%
+ ),
+ radial-gradient(circle at 92% 8%, rgba(2, 132, 199, 0.12), transparent 36%),
+ conic-gradient(
+ from 220deg at 24% 18%,
+ rgba(var(--accent-rgb), 0.1),
+ rgba(56, 189, 248, 0.08),
+ rgba(99, 102, 241, 0.08),
+ rgba(var(--accent-rgb), 0.1)
+ ),
+ linear-gradient(180deg, #f7f8fb 0%, #f3f5fa 100%);
+ }
+
+ .login-page * {
+ box-sizing: border-box;
+ }
+
+ .login-page::before {
+ content: "";
+ position: fixed;
+ inset: 0;
+ background-image: radial-gradient(rgba(15, 23, 42, 0.05) 1px, transparent 1px),
+ linear-gradient(rgba(15, 23, 42, 0.045) 1px, transparent 1px),
+ linear-gradient(90deg, rgba(15, 23, 42, 0.045) 1px, transparent 1px),
+ repeating-linear-gradient(
+ 118deg,
+ transparent 0 84px,
+ rgba(var(--accent-rgb), 0.26) 84px 86px,
+ transparent 86px 168px
+ ),
+ repeating-linear-gradient(
+ 208deg,
+ transparent 0 132px,
+ rgba(2, 132, 199, 0.22) 132px 134px,
+ transparent 134px 264px
+ ),
+ repeating-linear-gradient(
+ 156deg,
+ transparent 0 112px,
+ rgba(99, 102, 241, 0.2) 112px 114px,
+ transparent 114px 224px
+ ),
+ repeating-linear-gradient(
+ 118deg,
+ transparent 0 84px,
+ rgba(var(--accent-rgb), 0.12) 83px 89px,
+ transparent 89px 168px
+ );
+ background-size: 22px 22px, 52px 52px, 52px 52px, auto, auto, auto, auto;
+ background-position: 0 0, 0 0, 0 0, 0 0, -120px 140px, 120px 0;
+ mask-image: radial-gradient(circle at 42% 42%, #000 0%, transparent 80%);
+ opacity: 1;
+ mix-blend-mode: normal;
+ filter: saturate(1.08);
+ animation: lineDrift 12s linear infinite;
+ pointer-events: none;
+ z-index: 0;
+ }
+
+ .login-page::after {
+ content: "";
+ position: fixed;
+ inset: -28vmax;
+ background: radial-gradient(
+ circle at 18% 28%,
+ rgba(var(--accent-rgb), 0.22),
+ transparent 54%
+ ),
+ radial-gradient(
+ circle at 82% 22%,
+ rgba(56, 189, 248, 0.16),
+ transparent 50%
+ ),
+ radial-gradient(
+ circle at 72% 82%,
+ rgba(99, 102, 241, 0.12),
+ transparent 52%
+ ),
+ radial-gradient(circle at 26% 78%, rgba(244, 63, 94, 0.06), transparent 56%);
+ filter: blur(42px) saturate(1.05);
+ opacity: 0.9;
+ transform: translate3d(0, 0, 0);
+ animation: bgFloat 18s ease-in-out infinite;
+ pointer-events: none;
+ z-index: 0;
}
.page {
- grid-template-columns: 1fr;
- padding: 18px;
- min-height: auto;
+ position: relative;
+ z-index: 1;
+ max-width: 1200px;
+ margin: 48px auto;
+ width: calc(100% - 48px);
+ min-height: calc(100vh - 96px);
+ display: grid;
+ grid-template-columns: 3fr 2fr;
+ gap: 0;
+ align-items: stretch;
+ border-radius: 34px;
+ background: rgba(255, 255, 255, 0.72);
+ border: 1px solid rgba(255, 255, 255, 0.72);
+ box-shadow: var(--shadow);
+ backdrop-filter: blur(18px);
+ overflow: hidden;
}
- .factory,
- .login-wrap {
- min-height: auto;
+ .page::before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ border-radius: inherit;
+ background: radial-gradient(
+ circle at 22% 22%,
+ rgba(var(--accent-rgb), 0.34),
+ transparent 58%
+ )
+ left center / 60% 100% no-repeat,
+ radial-gradient(
+ circle at 76% 12%,
+ rgba(56, 189, 248, 0.22),
+ transparent 50%
+ )
+ left center / 60% 100% no-repeat,
+ linear-gradient(
+ 135deg,
+ rgba(2, 6, 23, 0.96) 0%,
+ rgba(15, 35, 57, 0.94) 52%,
+ rgba(15, 35, 57, 0.88) 100%
+ )
+ left center / 60% 100% no-repeat;
+ pointer-events: none;
+ z-index: 0;
+ }
+
+ .page::after {
+ content: "";
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 60%;
+ width: 1px;
+ background: linear-gradient(
+ 180deg,
+ transparent,
+ rgba(15, 23, 42, 0.16),
+ transparent
+ );
+ pointer-events: none;
+ z-index: 0;
}
.factory {
- min-height: 760px;
+ position: relative;
+ z-index: 1;
+ padding: 44px 48px 40px;
+ color: rgba(255, 255, 255, 0.92);
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
}
- .time {
+ .brand {
+ position: relative;
+ z-index: 1;
+ display: inline-flex;
+ align-items: center;
+ }
+
+ .logo {
+ width: 52px;
+ height: 52px;
+ border-radius: 14px;
+ display: grid;
+ place-items: center;
+ background: rgba(var(--accent-rgb), 0.12);
+ border: 1px solid rgba(var(--accent-rgb), 0.22);
+ overflow: hidden;
+ }
+
+ .logo-image {
+ width: 80%;
+ height: 80%;
+ object-fit: contain;
+ }
+
+ .hero-brand {
+ display: block;
+ }
+
+ .hero-logo {
+ width: 260px;
+ height: 72px;
+ border-radius: 0;
+ background: transparent;
+ border: none;
+ place-items: center start;
+ }
+
+ .hero-logo-image {
+ width: 100%;
+ height: 100%;
+ object-fit: contain;
+ filter: drop-shadow(0 10px 24px rgba(0, 0, 0, 0.22));
+ }
+
+ .hero {
+ position: relative;
+ z-index: 1;
+ margin: 46px 0 0;
+ max-width: 640px;
+ }
+
+ .chip {
+ display: inline-flex;
+ align-items: center;
+ padding: 7px 12px;
+ border-radius: 999px;
+ border: 1px solid rgba(255, 255, 255, 0.16);
+ background: rgba(255, 255, 255, 0.08);
+ color: rgba(255, 255, 255, 0.78);
+ font-size: 13px;
+ letter-spacing: 0.04em;
+ text-transform: uppercase;
+ }
+
+ .hero h1 {
+ margin: 22px 0 14px;
+ font-size: clamp(44px, 5vw, 66px);
+ line-height: 1.06;
+ font-weight: 860;
+ letter-spacing: -0.02em;
+ color: #ffffff;
+ }
+
+ .hero p {
+ margin: 0;
+ max-width: 600px;
+ font-size: 16px;
+ line-height: 1.9;
+ color: rgba(255, 255, 255, 0.72);
+ }
+
+ .scene {
display: none;
}
.login-wrap {
- padding: 22px;
+ position: relative;
+ z-index: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 36px 44px;
+ }
+
+ .time {
+ position: absolute;
+ top: 18px;
+ right: 18px;
+ display: flex;
+ gap: 10px;
+ align-items: center;
+ color: rgba(15, 23, 42, 0.72);
+ font-size: 13px;
+ font-weight: 700;
+ }
+
+ .time span {
+ padding: 6px 10px;
+ border-radius: 999px;
+ border: 1px solid rgba(15, 23, 42, 0.12);
+ background: rgba(255, 255, 255, 0.7);
+ color: rgba(15, 23, 42, 0.6);
+ font-weight: 800;
}
.login-card {
+ width: min(420px, 100%);
+ padding: 38px 34px 34px;
+ border-radius: 22px;
+ border: 1px solid rgba(15, 23, 42, 0.12);
+ background: rgba(255, 255, 255, 0.86);
+ backdrop-filter: blur(14px);
+ box-shadow: var(--shadow);
+ position: relative;
+ overflow: hidden;
+ }
+
+ .login-card::before {
+ content: "";
+ position: absolute;
+ left: -120px;
+ top: -120px;
+ width: 240px;
+ height: 240px;
+ border-radius: 999px;
+ background: radial-gradient(
+ circle at 30% 30%,
+ rgba(var(--accent-rgb), 0.36),
+ transparent 60%
+ );
+ filter: blur(1px);
+ }
+
+ .login-card > * {
+ position: relative;
+ z-index: 1;
+ }
+
+ .card-brand {
+ margin-bottom: 18px;
+ gap: 12px;
+ }
+
+ .card-brand .logo {
+ width: 46px;
+ height: 46px;
+ border-radius: 14px;
+ background: rgba(var(--accent-rgb), 0.12);
+ border: 1px solid rgba(var(--accent-rgb), 0.22);
+ }
+
+ .card-brand-copy {
+ margin-left: 0;
+ }
+
+ .brand-title {
+ font-size: 15px;
+ font-weight: 900;
+ color: rgba(15, 23, 42, 0.92);
+ letter-spacing: 0.02em;
+ }
+
+ .card-brand-copy small {
+ display: block;
+ margin-top: 4px;
+ font-size: 12px;
+ color: rgba(15, 23, 42, 0.55);
+ font-weight: 700;
+ }
+
+ .login-card h2 {
+ margin: 10px 0 8px;
+ font-size: 28px;
+ line-height: 1.2;
+ color: rgba(15, 23, 42, 0.92);
+ font-weight: 900;
+ letter-spacing: -0.02em;
+ }
+
+ .sub {
+ margin: 0 0 22px;
+ color: var(--muted);
+ font-size: 13px;
+ font-weight: 700;
+ }
+
+ .form-row {
+ margin-bottom: 14px;
+ }
+
+ label {
+ display: block;
+ margin-bottom: 8px;
+ color: rgba(15, 23, 42, 0.72);
+ font-size: 12px;
+ font-weight: 800;
+ letter-spacing: 0.06em;
+ text-transform: uppercase;
+ }
+
+ .input {
+ position: relative;
+ }
+
+ .input svg {
+ position: absolute;
+ left: 14px;
+ top: 50%;
+ width: 18px;
+ height: 18px;
+ transform: translateY(-50%);
+ color: rgba(15, 23, 42, 0.45);
+ pointer-events: none;
+ }
+
+ input[type="text"],
+ input[type="password"] {
width: 100%;
- padding: 26px;
+ height: 50px;
+ padding: 0 14px 0 44px;
+ border: 1px solid var(--border);
+ border-radius: 14px;
+ outline: none;
+ background: rgba(255, 255, 255, 0.92);
+ color: var(--text);
+ font-size: 15px;
+ transition: box-shadow 0.16s ease, border-color 0.16s ease,
+ transform 0.16s ease;
+ }
+
+ input[type="text"]::placeholder,
+ input[type="password"]::placeholder {
+ color: rgba(100, 116, 139, 0.88);
+ }
+
+ input[type="text"]:hover,
+ input[type="password"]:hover {
+ border-color: rgba(var(--accent-rgb), 0.28);
+ }
+
+ input[type="text"]:focus,
+ input[type="password"]:focus {
+ border-color: rgba(var(--accent-rgb), 0.6);
+ box-shadow: 0 0 0 4px rgba(var(--accent-rgb), 0.14);
+ }
+
+ .options {
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ margin: 14px 0 22px;
+ font-size: 13px;
+ color: rgba(15, 23, 42, 0.62);
+ font-weight: 700;
+ }
+
+ .check {
+ display: inline-flex;
+ gap: 10px;
+ align-items: center;
+ cursor: pointer;
+ user-select: none;
+ }
+
+ .check input {
+ width: 16px;
+ height: 16px;
+ padding: 0;
+ accent-color: var(--accent);
}
.login-btn {
- font-size: 16px;
+ width: 100%;
+ height: 52px;
+ border: none;
+ border-radius: 14px;
+ cursor: pointer;
+ color: #ffffff;
+ font-size: 15px;
+ font-weight: 900;
+ letter-spacing: 0.02em;
+ background: var(--accent);
+ box-shadow: 0 18px 44px rgba(var(--accent-rgb), 0.22);
+ transition: transform 0.16s ease, box-shadow 0.16s ease, filter 0.16s ease;
}
-}
+ .login-btn:hover:not(:disabled) {
+ transform: translateY(-1px);
+ box-shadow: 0 20px 52px rgba(var(--accent-rgb), 0.28);
+ filter: saturate(1.02);
+ }
+
+ .login-btn:active:not(:disabled) {
+ transform: translateY(0);
+ }
+
+ .login-btn:disabled {
+ opacity: 0.72;
+ cursor: not-allowed;
+ }
+
+ .login-btn:focus-visible {
+ outline: none;
+ box-shadow: 0 0 0 4px rgba(var(--accent-rgb), 0.18),
+ 0 18px 44px rgba(var(--accent-rgb), 0.22);
+ }
+
+ :global(html.dark) .login-page {
+ --text: rgba(248, 250, 252, 0.92);
+ --muted: rgba(226, 232, 240, 0.62);
+ --border: rgba(226, 232, 240, 0.16);
+ background: radial-gradient(
+ circle at 14% 18%,
+ rgba(var(--accent-rgb), 0.22),
+ transparent 40%
+ ),
+ radial-gradient(
+ circle at 86% 12%,
+ rgba(56, 189, 248, 0.14),
+ transparent 42%
+ ),
+ conic-gradient(
+ from 220deg at 22% 16%,
+ rgba(var(--accent-rgb), 0.16),
+ rgba(56, 189, 248, 0.12),
+ rgba(99, 102, 241, 0.12),
+ rgba(var(--accent-rgb), 0.16)
+ ),
+ linear-gradient(180deg, #0b1220 0%, #070b13 100%);
+ }
+
+ :global(html.dark) .login-page::before {
+ background-image: radial-gradient(
+ rgba(226, 232, 240, 0.07) 1px,
+ transparent 1px
+ ),
+ linear-gradient(rgba(226, 232, 240, 0.06) 1px, transparent 1px),
+ linear-gradient(90deg, rgba(226, 232, 240, 0.06) 1px, transparent 1px),
+ repeating-linear-gradient(
+ 118deg,
+ transparent 0 84px,
+ rgba(var(--accent-rgb), 0.32) 84px 86px,
+ transparent 86px 168px
+ ),
+ repeating-linear-gradient(
+ 208deg,
+ transparent 0 132px,
+ rgba(56, 189, 248, 0.28) 132px 134px,
+ transparent 134px 264px
+ ),
+ repeating-linear-gradient(
+ 156deg,
+ transparent 0 112px,
+ rgba(99, 102, 241, 0.26) 112px 114px,
+ transparent 114px 224px
+ ),
+ repeating-linear-gradient(
+ 118deg,
+ transparent 0 84px,
+ rgba(var(--accent-rgb), 0.16) 83px 89px,
+ transparent 89px 168px
+ );
+ background-size: 22px 22px, 52px 52px, 52px 52px, auto, auto, auto, auto;
+ opacity: 0.96;
+ mix-blend-mode: screen;
+ }
+
+ :global(html.dark) .login-page::after {
+ opacity: 0.7;
+ filter: blur(46px) saturate(1.08);
+ background: radial-gradient(
+ circle at 18% 28%,
+ rgba(var(--accent-rgb), 0.28),
+ transparent 56%
+ ),
+ radial-gradient(
+ circle at 84% 18%,
+ rgba(56, 189, 248, 0.18),
+ transparent 52%
+ ),
+ radial-gradient(
+ circle at 70% 82%,
+ rgba(99, 102, 241, 0.14),
+ transparent 56%
+ ),
+ radial-gradient(circle at 30% 84%, rgba(244, 63, 94, 0.06), transparent 60%);
+ }
+
+ :global(html.dark) .time {
+ color: rgba(226, 232, 240, 0.68);
+ }
+
+ :global(html.dark) .time span {
+ background: rgba(15, 23, 42, 0.5);
+ border-color: rgba(226, 232, 240, 0.16);
+ color: rgba(226, 232, 240, 0.72);
+ }
+
+ :global(html.dark) .login-card {
+ background: rgba(2, 6, 23, 0.56);
+ border-color: rgba(226, 232, 240, 0.16);
+ box-shadow: 0 24px 70px rgba(0, 0, 0, 0.46);
+ }
+
+ :global(html.dark) .page {
+ background: rgba(2, 6, 23, 0.46);
+ border-color: rgba(226, 232, 240, 0.12);
+ box-shadow: 0 38px 96px rgba(0, 0, 0, 0.5);
+ }
+
+ :global(html.dark) .page::after {
+ background: linear-gradient(
+ 180deg,
+ transparent,
+ rgba(226, 232, 240, 0.14),
+ transparent
+ );
+ }
+
+ :global(html.dark) .brand-title {
+ color: rgba(248, 250, 252, 0.92);
+ }
+
+ :global(html.dark) .card-brand-copy small {
+ color: rgba(226, 232, 240, 0.62);
+ }
+
+ :global(html.dark) .login-card h2 {
+ color: rgba(248, 250, 252, 0.92);
+ }
+
+ :global(html.dark) label {
+ color: rgba(226, 232, 240, 0.72);
+ }
+
+ :global(html.dark) .input svg {
+ color: rgba(226, 232, 240, 0.55);
+ }
+
+ :global(html.dark) input[type="text"],
+ :global(html.dark) input[type="password"] {
+ background: rgba(2, 6, 23, 0.38);
+ color: rgba(248, 250, 252, 0.92);
+ }
+
+ :global(html.dark) input[type="text"]::placeholder,
+ :global(html.dark) input[type="password"]::placeholder {
+ color: rgba(226, 232, 240, 0.55);
+ }
+
+ :global(html.dark) .options {
+ color: rgba(226, 232, 240, 0.68);
+ }
+
+ @keyframes bgFloat {
+ 0% {
+ transform: translate3d(-1.8%, -1.2%, 0) scale(1.02);
+ }
+ 50% {
+ transform: translate3d(1.6%, 1.4%, 0) scale(1.06);
+ }
+ 100% {
+ transform: translate3d(-1.8%, -1.2%, 0) scale(1.02);
+ }
+ }
+
+ @keyframes lineDrift {
+ 0% {
+ background-position: 0 0, 0 0, 0 0, 0 0, -120px 140px, 120px 0, 0 0;
+ }
+ 100% {
+ background-position: 0 0, 220px 260px, -240px 210px, 760px -520px,
+ -980px 720px, 680px 860px, 760px -520px;
+ }
+ }
+
+ @media (prefers-reduced-motion: reduce) {
+ .login-page::before {
+ animation: none;
+ }
+
+ .login-page::after {
+ animation: none;
+ }
+ }
+
+ @media (max-width: 980px) {
+ .login-page {
+ overflow: auto;
+ }
+
+ .page {
+ grid-template-columns: 1fr;
+ gap: 18px;
+ margin: 18px auto;
+ width: calc(100% - 32px);
+ min-height: auto;
+ max-width: 560px;
+ }
+
+ .page::before,
+ .page::after {
+ display: none;
+ }
+
+ .factory {
+ display: none;
+ }
+
+ .login-wrap {
+ padding: 0;
+ }
+
+ .time {
+ display: none;
+ }
+
+ .login-card {
+ width: 100%;
+ padding: 30px 22px 22px;
+ }
+ }
</style>
--
Gitblit v1.9.3