From 89079cd6f458c06b014d2609dcded95600be30a9 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期六, 16 五月 2026 14:18:44 +0800
Subject: [PATCH] 浪潮——客户 1.样式修改
---
src/views/index.vue | 920 ++++++++++++-----------------
src/store/modules/user.js | 8
src/assets/styles/sidebar.scss | 326 +++++-----
src/layout/index.vue | 1
src/settings.js | 4
src/assets/styles/variables.module.scss | 15
src/store/modules/settings.js | 21
src/utils/theme.js | 5
src/views/login.vue | 469 ++++++--------
src/layout/components/Sidebar/index.vue | 46 -
vite.config.js | 2
src/layout/components/Settings/index.vue | 7
src/App.vue | 30
13 files changed, 824 insertions(+), 1,030 deletions(-)
diff --git a/src/App.vue b/src/App.vue
index fd2b3d5..31839f2 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,15 +1,15 @@
-<template>
- <router-view />
-</template>
-
-<script setup>
-import useSettingsStore from '@/store/modules/settings'
-import { handleThemeStyle } from '@/utils/theme'
-
-onMounted(() => {
- nextTick(() => {
- // 鍒濆鍖栦富棰樻牱寮�
- handleThemeStyle(useSettingsStore().theme)
- })
-})
-</script>
+<template>
+ <router-view />
+</template>
+
+<script setup>
+import useSettingsStore from '@/store/modules/settings'
+import { handleThemeStyle } from '@/utils/theme'
+
+onMounted(() => {
+ nextTick(() => {
+ // 鍒濆鍖栦富棰樻牱寮�
+ handleThemeStyle(useSettingsStore().theme)
+ })
+})
+</script>
diff --git a/src/assets/styles/sidebar.scss b/src/assets/styles/sidebar.scss
index be7b7a7..fe2e525 100644
--- a/src/assets/styles/sidebar.scss
+++ b/src/assets/styles/sidebar.scss
@@ -1,104 +1,106 @@
-#app {
- .main-container {
- min-height: 100%;
- transition: margin-left 0.28s;
- margin-left: $base-sidebar-width;
- position: relative;
- background: transparent;
- }
-
- .sidebarHide {
- margin-left: 0 !important;
- }
-
- .sidebar-container {
- transition: width 0.28s;
- width: $base-sidebar-width !important;
- height: 100%;
- position: fixed;
- font-size: 0px;
- top: 0;
- bottom: 0;
- left: 0;
- z-index: 1001;
- overflow: hidden;
- padding: 12px 0 16px 16px;
- background: transparent;
- box-shadow: none;
-
- // reset element-ui css
- .horizontal-collapse-transition {
- transition: 0s width ease-in-out, 0s padding-left ease-in-out,
- 0s padding-right ease-in-out;
- }
-
- .scrollbar-wrapper {
- overflow-x: hidden !important;
- }
-
- .el-scrollbar__bar.is-vertical {
- right: 0px;
- }
-
- .el-scrollbar {
- height: 100%;
- }
-
- &.has-logo {
- .el-scrollbar {
- height: calc(100% - 72px);
- margin-top: 10px;
- }
- }
-
- .is-horizontal {
- display: none;
- }
-
- a {
- display: inline-block;
- width: 100%;
- overflow: hidden;
- }
-
- .svg-icon {
- margin-right: 16px;
- }
-
+#app {
+ .main-container {
+ min-height: 100%;
+ transition: margin-left 0.28s;
+ margin-left: $base-sidebar-width;
+ position: relative;
+ background: transparent;
+ }
+
+ .sidebarHide {
+ margin-left: 0 !important;
+ }
+
+ .sidebar-container {
+ transition: width 0.28s;
+ width: $base-sidebar-width !important;
+ height: 100%;
+ position: fixed;
+ font-size: 0px;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1001;
+ overflow: hidden;
+ padding: 12px 0 16px 16px;
+ background: transparent;
+ box-shadow: none;
+
+ // reset element-ui css
+ .horizontal-collapse-transition {
+ transition: 0s width ease-in-out, 0s padding-left ease-in-out,
+ 0s padding-right ease-in-out;
+ }
+
+ .scrollbar-wrapper {
+ overflow-x: hidden !important;
+ }
+
+ .el-scrollbar__bar.is-vertical {
+ right: 0px;
+ }
+
+ .el-scrollbar {
+ height: 100%;
+ }
+
+ &.has-logo {
+ .el-scrollbar {
+ height: calc(100% - 72px);
+ margin-top: 10px;
+ }
+ }
+
+ .is-horizontal {
+ display: none;
+ }
+
+ a {
+ display: inline-block;
+ width: 100%;
+ overflow: hidden;
+ }
+
+ .svg-icon {
+ margin-right: 16px;
+ }
+
.el-menu {
border: none;
height: 100%;
width: 100% !important;
padding: 10px 8px 18px;
border-radius: 22px;
- background: var(--menu-surface);
+ background-color: var(--el-menu-bg-color, var(--sidebar-bg)) !important;
backdrop-filter: blur(18px);
box-shadow: var(--shadow-sm);
}
-
- .el-menu-item,
- .menu-title {
- overflow: hidden !important;
- text-overflow: ellipsis !important;
- white-space: nowrap !important;
- }
-
- .el-menu-item .el-menu-tooltip__trigger {
- display: inline-block !important;
- }
-
+
+ .el-menu-item,
+ .menu-title {
+ overflow: hidden !important;
+ text-overflow: ellipsis !important;
+ white-space: nowrap !important;
+ color: var(--sidebar-text) !important;
+ }
+
+ .el-menu-item .el-menu-tooltip__trigger {
+ display: inline-block !important;
+ }
+
// menu hover
.submenu-title-noDropdown,
.el-sub-menu__title {
+ color: var(--sidebar-text) !important;
&:hover {
background-color: var(--menu-hover) !important;
border-radius: 14px;
}
}
- & .theme-light .is-active > .el-sub-menu__title {
- color: var(--current-color) !important;
- }
-
+ & .is-active > .el-sub-menu__title {
+ color: var(--sidebar-text) !important;
+ }
+
& .nest-menu .el-sub-menu > .el-sub-menu__title,
& .el-sub-menu .el-menu-item {
min-width: 0 !important;
@@ -116,18 +118,16 @@
border-radius: 14px;
}
}
-
- & .theme-light .nest-menu .el-sub-menu > .el-sub-menu__title,
- & .theme-light .el-sub-menu .el-menu-item {
- //background-color: transparent;
+ & .nest-menu .el-sub-menu > .el-sub-menu__title,
+ & .el-sub-menu .el-menu-item {
&:hover {
background-color: var(--menu-hover) !important;
border-radius: 14px;
}
}
}
-
+
.hideSidebar {
.sidebar-container {
width: 68px !important;
@@ -138,7 +138,7 @@
.main-container {
margin-left: 84px;
}
-
+
.submenu-title-noDropdown {
padding: 0 !important;
position: relative;
@@ -225,60 +225,60 @@
width: 0;
overflow: hidden;
visibility: hidden;
- display: inline-block;
- }
- & > i {
- height: 0;
- width: 0;
- overflow: hidden;
- visibility: hidden;
- display: inline-block;
+ display: inline-block;
+ }
+ & > i {
+ height: 0;
+ width: 0;
+ overflow: hidden;
+ visibility: hidden;
+ display: inline-block;
}
}
}
}
}
-
- .el-menu--collapse .el-menu .el-sub-menu {
- min-width: $base-sidebar-width !important;
- }
-
- // mobile responsive
- .mobile {
- .main-container {
- margin-left: 0px;
- }
-
- .sidebar-container {
- transition: transform 0.28s;
- width: $base-sidebar-width !important;
- }
-
- &.hideSidebar {
- .sidebar-container {
- pointer-events: none;
- transition-duration: 0.3s;
- transform: translate3d(-$base-sidebar-width, 0, 0);
- }
- }
- }
-
- .withoutAnimation {
- .main-container,
- .sidebar-container {
- transition: none;
- }
- }
-}
-
-// when menu collapsed
-.el-menu--vertical {
- & > .el-menu {
- .svg-icon {
- margin-right: 16px;
- }
- }
-
+
+ .el-menu--collapse .el-menu .el-sub-menu {
+ min-width: $base-sidebar-width !important;
+ }
+
+ // mobile responsive
+ .mobile {
+ .main-container {
+ margin-left: 0px;
+ }
+
+ .sidebar-container {
+ transition: transform 0.28s;
+ width: $base-sidebar-width !important;
+ }
+
+ &.hideSidebar {
+ .sidebar-container {
+ pointer-events: none;
+ transition-duration: 0.3s;
+ transform: translate3d(-$base-sidebar-width, 0, 0);
+ }
+ }
+ }
+
+ .withoutAnimation {
+ .main-container,
+ .sidebar-container {
+ transition: none;
+ }
+ }
+}
+
+// when menu collapsed
+.el-menu--vertical {
+ & > .el-menu {
+ .svg-icon {
+ margin-right: 16px;
+ }
+ }
+
.nest-menu .el-sub-menu > .el-sub-menu__title,
.el-menu-item {
min-width: 0 !important;
@@ -297,27 +297,27 @@
border-radius: 14px;
}
}
-
- // the scroll bar appears when the sub-menu is too long
- > .el-menu--popup {
- max-height: 100vh;
- overflow-y: auto;
- padding: 8px;
- border-radius: 18px;
- border: 1px solid var(--surface-border);
- box-shadow: var(--shadow-md);
-
- &::-webkit-scrollbar-track-piece {
- background: #dfe7e1;
- }
-
- &::-webkit-scrollbar {
- width: 6px;
- }
-
- &::-webkit-scrollbar-thumb {
- background: #9aa79e;
- border-radius: 20px;
- }
- }
-}
+
+ // the scroll bar appears when the sub-menu is too long
+ > .el-menu--popup {
+ max-height: 100vh;
+ overflow-y: auto;
+ padding: 8px;
+ border-radius: 18px;
+ border: 1px solid var(--surface-border);
+ box-shadow: var(--shadow-md);
+
+ &::-webkit-scrollbar-track-piece {
+ background: #dfe7e1;
+ }
+
+ &::-webkit-scrollbar {
+ width: 6px;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ background: #9aa79e;
+ border-radius: 20px;
+ }
+ }
+}
diff --git a/src/assets/styles/variables.module.scss b/src/assets/styles/variables.module.scss
index 55b3822..1da1da2 100644
--- a/src/assets/styles/variables.module.scss
+++ b/src/assets/styles/variables.module.scss
@@ -64,6 +64,7 @@
}
:root {
+ --el-menu-bg-color: var(--sidebar-bg, #{$menuBg});
--sidebar-bg: #{$menuBg};
--sidebar-text: #{$menuText};
--sidebar-muted: #93a0b1;
@@ -108,11 +109,7 @@
--el-text-color-regular: #d0d0d0;
--el-border-color: #434343;
--el-border-color-light: #434343;
-
- --sidebar-bg: #141414;
- --sidebar-text: #ffffff;
- --menu-hover: #2d2d2d;
- --menu-active-text: #{$menuActiveText};
+ /* 鑿滃崟鏍忚儗鏅壊鐢� JS 鍔ㄦ�佽缃紝璺熼殢涓婚鑹诧紝涓嶅湪杩欓噷瀹氫箟 */
--navbar-bg: #141414;
--navbar-text: #ffffff;
@@ -139,12 +136,12 @@
.sidebar-container {
.el-menu-item,
.menu-title {
- color: var(--el-text-color-regular);
+ color: var(--sidebar-text, #{$menuText});
}
- & .theme-dark .nest-menu .el-sub-menu > .el-sub-menu__title,
- & .theme-dark .el-sub-menu .el-menu-item {
- background-color: var(--el-bg-color) !important;
+ & .nest-menu .el-sub-menu > .el-sub-menu__title,
+ & .el-sub-menu .el-menu-item {
+ background-color: var(--sidebar-bg, #{$menuBg}) !important;
}
}
diff --git a/src/layout/components/Settings/index.vue b/src/layout/components/Settings/index.vue
index 917b28b..00de8ce 100644
--- a/src/layout/components/Settings/index.vue
+++ b/src/layout/components/Settings/index.vue
@@ -157,7 +157,6 @@
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",
@@ -193,10 +192,7 @@
settingsStore.setDarkMode(val);
}
-function handleTheme(val) {
- settingsStore.sideTheme = val;
- sideTheme.value = val;
-}
+
function saveSetting() {
proxy.$modal.loading("姝e湪淇濆瓨鍒版湰鍦帮紝璇风◢鍊�...");
@@ -206,7 +202,6 @@
fixedHeader: storeSettings.value.fixedHeader,
sidebarLogo: storeSettings.value.sidebarLogo,
dynamicTitle: storeSettings.value.dynamicTitle,
- sideTheme: storeSettings.value.sideTheme,
theme: storeSettings.value.theme,
darkMode: storeSettings.value.darkMode,
};
diff --git a/src/layout/components/Sidebar/index.vue b/src/layout/components/Sidebar/index.vue
index 0692dda..47db92b 100644
--- a/src/layout/components/Sidebar/index.vue
+++ b/src/layout/components/Sidebar/index.vue
@@ -1,18 +1,12 @@
<template>
- <div :class="{ 'has-logo': showLogo }"
- class="sidebar-container">
- <logo v-if="showLogo"
- :collapse="isCollapse" />
+ <div class="sidebar-container">
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu :default-active="activeMenu"
:collapse="isCollapse"
- :background-color="getMenuBackground"
- :text-color="getMenuTextColor"
:unique-opened="true"
:active-text-color="theme"
:collapse-transition="false"
- mode="vertical"
- :class="sideTheme">
+ mode="vertical">
<sidebar-item v-for="(route, index) in sidebarRouters"
:key="route.path + index"
:item="route"
@@ -23,9 +17,7 @@
</template>
<script setup>
- import Logo from "./Logo";
import SidebarItem from "./SidebarItem";
- import variables from "@/assets/styles/variables.module.scss";
import useAppStore from "@/store/modules/app";
import useSettingsStore from "@/store/modules/settings";
import usePermissionStore from "@/store/modules/permission";
@@ -36,21 +28,8 @@
const permissionStore = usePermissionStore();
const sidebarRouters = computed(() => permissionStore.sidebarRouters);
- const showLogo = computed(() => settingsStore.sidebarLogo);
- const sideTheme = computed(() => settingsStore.sideTheme);
const theme = computed(() => settingsStore.theme);
const isCollapse = computed(() => !appStore.sidebar.opened);
-
- const getMenuBackground = computed(() => "var(--sidebar-bg)");
-
- const getMenuTextColor = computed(() => {
- if (settingsStore.isDark) {
- return "var(--sidebar-text)";
- }
- return sideTheme.value === "theme-dark"
- ? variables.menuText
- : variables.menuLightText;
- });
const activeMenu = computed(() => {
const { meta, path } = route;
@@ -63,12 +42,14 @@
<style lang="scss" scoped>
.sidebar-container {
- background-color: v-bind(getMenuBackground);
+ background-color: var(--sidebar-bg);
border-radius: 22px;
overflow: hidden;
+ transition: background-color 0.3s ease;
.scrollbar-wrapper {
- background-color: v-bind(getMenuBackground);
+ background-color: var(--sidebar-bg);
+ transition: background-color 0.3s ease;
}
.el-menu {
@@ -76,12 +57,15 @@
height: 100%;
width: 100% !important;
border-radius: 22px;
+ background-color: var(--el-menu-bg-color, var(--sidebar-bg)) !important;
+ transition: background-color 0.3s ease;
.el-menu-item,
.el-sub-menu__title {
margin-bottom: 6px;
border-radius: 14px;
- color: v-bind(getMenuTextColor);
+ color: var(--sidebar-text);
+ transition: all 0.3s ease;
&:hover {
background-color: var(--menu-hover, rgba(0, 0, 0, 0.06)) !important;
@@ -90,24 +74,24 @@
}
.el-menu-item {
+ color: var(--sidebar-text);
&.is-active {
- color: v-bind(theme);
+ color: var(--sidebar-text);
background-color: var(--menu-active-bg, rgba(0, 0, 0, 0.06)) !important;
font-weight: 600;
}
}
.el-sub-menu__title {
- color: v-bind(getMenuTextColor);
+ color: var(--sidebar-text);
}
:deep(.el-sub-menu.is-active > .el-sub-menu__title) {
- color: v-bind(theme) !important;
+ color: var(--sidebar-text) !important;
font-weight: 600;
background-color: var(--menu-active-bg, rgba(0, 0, 0, 0.06)) !important;
border-radius: 14px;
margin: 0 10px 6px !important;
- // width: calc(100% - 20px) !important;
padding-left: 10px !important;
padding-right: 10px !important;
box-sizing: border-box;
@@ -130,7 +114,7 @@
:deep(.el-sub-menu.is-active > .el-sub-menu__title .svg-icon),
:deep(.el-menu-item.is-active .menu-title),
:deep(.el-menu-item.is-active .svg-icon) {
- color: v-bind(theme) !important;
+ color: var(--sidebar-text) !important;
}
:deep(.el-sub-menu__title:hover),
diff --git a/src/layout/index.vue b/src/layout/index.vue
index fc47afa..44ba966 100644
--- a/src/layout/index.vue
+++ b/src/layout/index.vue
@@ -36,7 +36,6 @@
const userStore = useUserStore();
const route = useRoute();
const theme = computed(() => settingsStore.theme);
- const sideTheme = computed(() => settingsStore.sideTheme);
const sidebar = computed(() => useAppStore().sidebar);
const device = computed(() => useAppStore().device);
const needTagsView = computed(() => settingsStore.tagsView);
diff --git a/src/settings.js b/src/settings.js
index 4a1c8bb..ad2d1d3 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -4,10 +4,6 @@
*/
title: import.meta.env.VITE_APP_TITLE,
/**
- * 渚ц竟鏍忎富棰� 娣辫壊涓婚theme-dark锛屾祬鑹蹭富棰榯heme-light
- */
- sideTheme: 'theme-light',
- /**
* 鏄惁绯荤粺甯冨眬閰嶇疆
*/
showSettings: true,
diff --git a/src/store/modules/settings.js b/src/store/modules/settings.js
index 3a5f6a2..4f00ead 100644
--- a/src/store/modules/settings.js
+++ b/src/store/modules/settings.js
@@ -4,11 +4,15 @@
const preferredDark = usePreferredDark();
const colorMode = useColorMode({
- emitAuto: true,
+ attribute: 'class',
+ selector: 'html',
+ modes: {
+ dark: 'dark',
+ light: '',
+ }
});
const {
- sideTheme,
showSettings,
topNav,
tagsView,
@@ -21,13 +25,15 @@
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 useSettingsStore = defineStore("settings", () => {
const title = ref("");
const theme = ref(storageSetting.theme || "#002fa7");
- const sideThemeValue = ref(storageSetting.sideTheme || sideTheme);
const showSettingsValue = ref(showSettings);
const topNavValue = ref(
storageSetting.topNav === undefined ? topNav : storageSetting.topNav
@@ -47,12 +53,18 @@
const darkModeValue = ref(initialDarkMode);
const isDark = computed(() => getIsDark(darkModeValue.value));
+ // 鐩戝惉绯荤粺涓婚鍙樺寲
+ watch(preferredDark, (newVal) => {
+ if (darkModeValue.value === 'auto') {
+ colorMode.value = 'auto';
+ }
+ });
+
function changeSetting(data) {
const { key, value } = data;
const settingMap = {
title,
theme,
- sideTheme: sideThemeValue,
showSettings: showSettingsValue,
topNav: topNavValue,
tagsView: tagsViewValue,
@@ -86,7 +98,6 @@
return {
title,
theme,
- sideTheme: sideThemeValue,
showSettings: showSettingsValue,
topNav: topNavValue,
tagsView: tagsViewValue,
diff --git a/src/store/modules/user.js b/src/store/modules/user.js
index ea358d1..e395463 100644
--- a/src/store/modules/user.js
+++ b/src/store/modules/user.js
@@ -56,15 +56,17 @@
} else {
this.roles = ['ROLE_DEFAULT']
}
- this.id = user.userId
- this.name = user.userName
- this.avatar = avatar
+ this.id = user.userId
+ this.name = user.userName
+ this.avatar = avatar
this.currentFactoryName = user.currentFactoryName
this.nickName = user.nickName
this.roleName = user.roles[0].roleName
this.currentDeptId = user.tenantId
this.currentLoginTime = this.getCurrentTime()
this.aiEnabled = Number(res.aiEnabled) === 1 ? 1 : 0
+ this.phonenumber = user.phonenumber
+ this.remark = user.remark
resolve(res)
}).catch(error => {
reject(error)
diff --git a/src/utils/theme.js b/src/utils/theme.js
index f4badc6..d9dcb51 100644
--- a/src/utils/theme.js
+++ b/src/utils/theme.js
@@ -7,6 +7,11 @@
for (let i = 1; i <= 9; i++) {
document.documentElement.style.setProperty(`--el-color-primary-dark-${i}`, `${getDarkColor(theme, i / 10)}`)
}
+ // 璁剧疆鑿滃崟鏍忚儗鏅壊涓轰富棰樿壊鐨勬祬鑹茬増鏈紙50%娴呭害锛夛紝鏂囧瓧鐢ㄧ櫧鑹�
+ document.documentElement.style.setProperty('--sidebar-bg', getLightColor(theme, 0.5))
+ document.documentElement.style.setProperty('--sidebar-text', '#ffffff')
+ document.documentElement.style.setProperty('--menu-hover', getLightColor(theme, 0.4))
+ document.documentElement.style.setProperty('--menu-active-bg', getLightColor(theme, 0.35))
}
// hex棰滆壊杞瑀gb棰滆壊
diff --git a/src/views/index.vue b/src/views/index.vue
index 6c0b729..5a72ff9 100644
--- a/src/views/index.vue
+++ b/src/views/index.vue
@@ -21,16 +21,17 @@
<div class="user-name">{{ userStore.name }}</div>
<div class="user-role">{{ userStore.roleName }}</div>
<div class="user-meta">
- <span>{{ userStore.phoneNumber || '123456789' }}</span>
+ <span>{{ userStore.phonenumber || '123456789' }}</span>
<span class="sep">|</span>
- <span>{{ userStore.deptName || '缁勭粐鏋舵瀯' }}</span>
+ <span>{{ userStore.currentFactoryName || '缁勭粐鏋舵瀯' }}</span>
<span class="sep">|</span>
- <span>{{ userStore.postName || '宀椾綅鍚�' }}</span>
+ <span>{{ userStore.remark || '宀椾綅鍚�' }}</span>
</div>
</div>
</div>
</div>
</div>
+ <!--
<div class="data-cards">
<div class="data-card sales">
<div class="data-title">閿�鍞暟鎹�</div>
@@ -73,7 +74,9 @@
</div>
</div>
</div>
+ -->
<!-- 鍙筹細寰呭姙浜嬮」 -->
+ <!--
<div class="todo-panel">
<div class="section-title">寰呭姙浜嬮」</div>
<ul class="todo-list" v-if="todoList.length > 0">
@@ -92,7 +95,9 @@
鏆傛棤鏁版嵁
</div>
</div>
+ -->
</div>
+ <!--
<div class="dashboard-row">
<div class="main-panel process-panel">
<div class="process-panel__header">
@@ -150,7 +155,6 @@
</div>
</div>
- <!-- 宸ュ簭閫夋嫨寮圭獥 -->
<el-dialog v-model="processDialogVisible" title="閫夋嫨宸ュ簭" width="500px" append-to-body>
<div class="process-selection-wrapper">
<el-checkbox-group v-model="tempProcessIds">
@@ -168,9 +172,10 @@
</span>
</template>
</el-dialog>
- <!-- 涓儴妯悜涓ゆ爮 -->
+ -->
+ <!-- 涓儴锛氬鎴峰悎鍚岄噾棰濆垎鏋� -->
<div class="dashboard-row">
- <div class="main-panel">
+ <div class="main-panel contract-panel">
<div class="section-title">瀹㈡埛鍚堝悓閲戦鍒嗘瀽</div>
<div class="contract-summary">
<div class="contract-info">
@@ -184,38 +189,27 @@
</div>
</div>
</div>
- <div
- style="display: flex;align-items: center;gap: 20px;justify-content: space-evenly;height: 180px;margin-top: 20px">
- <div>
- <Echarts ref="chart" :legend="pieLegend" :chartStyle="chartStylePie" :series="materialPieSeries"
+ <div class="contract-chart-wrapper">
+ <div class="chart-container">
+ <Echarts ref="chart" :legend="pieLegend" :chartStyle="{ width: '100%', height: '280px' }" :series="materialPieSeries"
:tooltip="pieTooltip"></Echarts>
</div>
<ul class="contract-list">
<li v-for="item in materialPieSeries[0].data" :key="item.name">
- <div style="display: flex;align-items: center;justify-content: space-between;width: 100%">
- <div class="line" :style="{ color: item.itemStyle.color }">鈼弡{ item.name }}</div>
- <div style="width: 70px">{{ item.rate }}%</div>
- <div>锟{ item.value }}</div>
+ <div class="contract-item">
+ <span class="contract-dot" :style="{ background: item.itemStyle?.color || '#999' }"></span>
+ <span class="contract-name">{{ item.name }}</span>
+ <span class="contract-rate">{{ item.rate }}%</span>
+ <span class="contract-value">锟{ item.value }}</span>
</div>
</li>
</ul>
</div>
</div>
- <div class="main-panel">
- <div style="display: flex;justify-content: space-between;">
- <div class="section-title">搴旀敹搴斾粯缁熻</div>
- <!-- <el-radio-group v-model="radio1" size="large" @change="statisticsReceivable">-->
- <!-- <el-radio-button label="鎸夊懆" :value="1" />-->
- <!-- <el-radio-button label="鎸夋湀" :value="2" />-->
- <!-- <el-radio-button label="鎸夊搴�" :value="3" />-->
- <!-- </el-radio-group>-->
- </div>
- <Echarts ref="chart" :color="barColors2" :chartStyle="chartStyle" :grid="grid" :series="barSeries"
- :tooltip="tooltip" :xAxis="xAxis" :yAxis="yAxis" style="height: 260px"></Echarts>
- </div>
</div>
<!-- 搴曢儴妯悜涓ゆ爮 -->
+ <!--
<div class="dashboard-row">
<div class="main-panel">
<div style="display: flex;justify-content: space-between;align-items: center;margin-bottom: 10px;">
@@ -241,6 +235,7 @@
:tooltip="tooltipLine" :xAxis="xAxis2" :yAxis="yAxis2" style="height: 270px;" />
</div>
</div>
+ -->
</div>
</template>
@@ -327,11 +322,11 @@
])
const chartStyle = {
width: '100%',
- height: '100%' // 璁剧疆鍥捐〃瀹瑰櫒鐨勯珮搴�
+ height: '100%'
}
const chartStylePie = {
width: '140%',
- height: '140%' // 璁剧疆鍥捐〃瀹瑰櫒鐨勯珮搴�
+ height: '140%'
}
const grid = {
left: '3%',
@@ -375,7 +370,6 @@
const pieTooltip = reactive({
trigger: 'item',
formatter: function (params) {
- // 鍔ㄦ�佺敓鎴愭彁绀轰俊鎭紝鍩轰簬鏁版嵁椤圭殑 name 灞炴��
const description = params.name === '鏈湀鍥炴閲戦' ? '鏈湀鍥炴閲戦' : '搴旀敹娆鹃噾棰�';
return `${description} ${formatNumber(params.value)}鍏� ${params.percent}%`;
},
@@ -403,7 +397,7 @@
label: {
show: true
},
- showSymbol: true, // 鏄剧ず鍦嗙偣
+ showSymbol: true,
},
])
const tooltipLine = {
@@ -427,17 +421,14 @@
}
])
-// 寰呭姙浜嬮」
const todoList = ref([])
const radio1 = ref(1)
const qualityRange = ref(1)
-// 鍥捐〃寮曠敤
const barChart = ref(null)
const lineChart = ref(null)
const barColors2 = ['#5181DB', '#D369E0', '#F2CA6D', '#60CCA8']
-// 闅忔満棰滆壊鐢熸垚鍑芥暟
const getRandomColor = () => {
return '#' + Math.floor(Math.random() * 0xffffff).toString(16).padStart(6, '0');
}
@@ -451,32 +442,31 @@
getAmountHalfYearNum()
getProcessList()
})
-// 鏁版嵁缁熻
+
const getBusinessData = () => {
getBusiness().then((res) => {
businessInfo.value = { ...res.data }
})
}
-// 鍚堝悓閲戦
+
const analysisCustomer = () => {
analysisCustomerContractAmounts().then((res) => {
sum.value = res.data.sum
yny.value = res.data.yny
chain.value = res.data.chain
- // 涓烘瘡涓暟鎹」鍒嗛厤闅忔満棰滆壊
materialPieSeries.value[0].data = res.data.item.map(item => ({
...item,
itemStyle: { color: getRandomColor() }
}))
})
}
-// 寰呭姙浜嬮」
+
const todoInfoS = () => {
homeTodos().then((res) => {
todoList.value = res.data
})
}
-// 鑾峰彇宸ュ簭鍒楄〃
+
const getProcessList = () => {
list().then(res => {
processOptions.value = res.data.records
@@ -505,18 +495,16 @@
activeProcessIndex.value = params.dataIndex
}
}
-// 搴斾粯搴旀敹缁熻
+
const statisticsReceivable = () => {
statisticsReceivablePayable({ type: radio1.value }).then((res) => {
barSeries.value[0].data = [
- // { value: res.data.prepayMoney, itemStyle: { color: barColors2[0] } },
{ value: res.data.payableMoney, itemStyle: { color: barColors2[0] } },
- // { value: res.data.advanceMoney, itemStyle: { color: barColors2[2] } },
{ value: res.data.receivableMoney, itemStyle: { color: barColors2[1] } }
]
})
}
-// 璐ㄦ缁熻
+
const qualityStatisticsInfo = () => {
qualityInspectionStatistics({ type: qualityRange.value }).then((res) => {
xAxis1.value[0].data = []
@@ -534,9 +522,9 @@
qualityStatisticsObject.value.factoryNum = res.data.factoryNum
})
}
+
const getAmountHalfYearNum = async () => {
const res = await getAmountHalfYear()
- console.log(res)
const monthName = []
const receiptAmount = []
const invoiceAmount = []
@@ -545,7 +533,6 @@
receiptAmount.push(item.receiptAmount)
invoiceAmount.push(item.invoiceAmount)
})
- // 姝g‘鍝嶅簲寮忚祴鍊硷細鍒涘缓鏂扮殑 xAxis 鍜� series 瀵硅薄
xAxis2.value[0].data = monthName
xAxis2.value[0].data = monthName.map(item => item.replace(/~/g, '\n~'));
lineSeries.value = [
@@ -610,7 +597,6 @@
]
}
-// 宸ュ簭鏁版嵁鐢熶骇缁熻鏄庣粏锛堝亣鏁版嵁 + 鍥捐〃锛�
const processRange = ref(1)
const processChartData = ref([])
@@ -625,356 +611,262 @@
const processYAxis = ref([
{
type: 'category',
- axisTick: { show: false },
+ axisLabel: { color: 'rgba(0,0,0,0.35)', fontSize: 12 },
axisLine: { show: false },
- axisLabel: { color: 'rgba(0,0,0,0.45)' },
+ axisTick: { show: false },
data: [],
},
])
-const processGrid = reactive({ left: 0, right: 100, top: 30, bottom: 20, containLabel: true })
-
-const processTooltip = reactive({
+const processTooltip = ref({
trigger: 'axis',
axisPointer: { type: 'shadow' },
- formatter: (params) => {
- const name = params?.[0]?.name ?? ''
- const list = Array.isArray(params) ? params : []
- const lines = list
- .map((p) => {
- const colorBox = `<span style="display:inline-block;margin-right:6px;border-radius:2px;width:10px;height:10px;background:${p.color}"></span>`
- return `${colorBox}${p.seriesName} <b style="float:right;">${Number(p.value || 0).toFixed(2)}</b>`
- })
- .join('<br/>')
- return `<div style="min-width:140px;"><div style="font-weight:700;margin-bottom:6px;">${name}</div>${lines}</div>`
- },
})
-const processSeries = computed(() => {
- const input = processChartData.value.map((i) => i.input)
- const scrap = processChartData.value.map((i) => i.scrap)
- const output = processChartData.value.map((i) => i.output)
+const processSeries = ref([
+ {
+ name: '鎶曞叆閲�',
+ type: 'bar',
+ stack: 'total',
+ barWidth: 16,
+ itemStyle: { color: '#2D99FF', borderRadius: [0, 4, 4, 0] },
+ data: [],
+ },
+ {
+ name: '鎶ュ簾閲�',
+ type: 'bar',
+ stack: 'total',
+ barWidth: 16,
+ itemStyle: { color: '#F2CA6D', borderRadius: [0, 4, 4, 0] },
+ data: [],
+ },
+ {
+ name: '浜у嚭閲�',
+ type: 'bar',
+ stack: 'total',
+ barWidth: 16,
+ itemStyle: { color: '#5EE9C0', borderRadius: [0, 4, 4, 0] },
+ data: [],
+ },
+])
- return [
- {
- name: '鎶曞叆閲�',
- type: 'bar',
- stack: 'total',
- barWidth: 22,
- itemStyle: { color: '#1E5BFF', borderRadius: [6, 0, 0, 6] },
- data: input,
- },
- {
- name: '鎶ュ簾閲�',
- type: 'bar',
- stack: 'total',
- barWidth: 22,
- itemStyle: { color: '#F7B500' },
- data: scrap,
- },
- {
- name: '浜у嚭閲�',
- type: 'bar',
- stack: 'total',
- barWidth: 22,
- itemStyle: { color: '#19C6C6', borderRadius: [0, 6, 6, 0] },
- data: output,
- },
- ]
+const processGrid = ref({
+ left: '3%',
+ right: '4%',
+ bottom: '3%',
+ top: '3%',
+ containLabel: true,
})
const processAside = computed(() => {
- const list = processChartData.value
- const item = list[activeProcessIndex.value] || {}
+ const idx = activeProcessIndex.value
+ const item = processChartData.value[idx] || {}
return {
- processName: item.name || '鏆傛棤鏁版嵁',
- totalInput: item.input || 0,
- totalScrap: item.scrap || 0,
- totalOutput: item.output || 0,
+ processName: item.processName || '-',
+ totalInput: item.inputNum || 0,
+ totalScrap: item.scrapNum || 0,
+ totalOutput: item.outputNum || 0,
}
})
-const formatAmount = (n) => {
- const num = Number(n || 0)
- return num.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })
+const refreshProcessStats = async () => {
+ const params = { type: processRange.value }
+ if (selectedProcessIds.value.length > 0) {
+ params.processIds = selectedProcessIds.value.join(',')
+ }
+ const res = await processDataProductionStatistics(params)
+ const list = res.data || []
+ processChartData.value = list
+ processYAxis.value[0].data = list.map(i => i.processName)
+ processSeries.value[0].data = list.map(i => i.inputNum)
+ processSeries.value[1].data = list.map(i => i.scrapNum)
+ processSeries.value[2].data = list.map(i => i.outputNum)
+ activeProcessIndex.value = 0
}
-const refreshProcessStats = () => {
- processDataProductionStatistics({
- type: processRange.value,
- processIds: selectedProcessIds.value.length > 0 ? selectedProcessIds.value.join(',') : null
- }).then(res => {
- processChartData.value = res.data.map(item => ({
- name: item.processName,
- input: item.totalInput,
- scrap: item.totalScrap,
- output: item.totalOutput
- }))
- processYAxis.value[0].data = processChartData.value.map((i) => i.name)
- activeProcessIndex.value = 0
- })
+const formatAmount = (num) => {
+ if (!num && num !== 0) return '-'
+ return Number(num).toLocaleString()
}
-onMounted(() => {
- getBusinessData()
- analysisCustomer()
- todoInfoS()
- statisticsReceivable()
- qualityStatisticsInfo()
- getAmountHalfYearNum()
- refreshProcessStats()
-})
+const formatNumber = (num) => {
+ if (!num) return '0'
+ return num.toLocaleString()
+}
</script>
-<style scoped>
+<style lang="scss" scoped>
.dashboard {
- min-height: 100vh;
padding: 20px;
- box-sizing: border-box;
+ background: #f5f7fa;
}
.dashboard-top {
- display: flex;
+ display: grid;
+ grid-template-columns: 2fr 1fr;
gap: 20px;
margin-bottom: 20px;
- align-items: flex-start;
- justify-content: space-evenly;
-}
-
-.company-info {
- padding: 0;
- overflow: hidden;
- border-radius: 12px;
- background: #fff;
- height: 100%;
-}
-
-.welcome-banner {
- padding: 10px 10px;
- background: linear-gradient(135deg, rgba(229, 240, 255, 0.9), rgba(214, 232, 255, 0.7), rgba(207, 236, 255, 0.9));
-}
-
-.welcome-title {
- font-size: 18px;
- font-weight: 700;
- color: #222;
- line-height: 1.3;
-}
-
-.welcome-user {
- margin-right: 6px;
-}
-
-.welcome-time {
- margin-top: 10px;
- font-size: 16px;
- color: rgba(0, 0, 0, 0.55);
-}
-
-.user-card {
- display: flex;
- align-items: center;
- gap: 10px;
- padding: 18px 22px;
-}
-
-.user-card-main {
- display: flex;
- flex-direction: column;
- gap: 5px;
- min-width: 0;
-}
-
-.user-name {
- font-size: 16px;
- font-weight: bold;
- color: #111;
- letter-spacing: 1px;
-}
-
-.user-role {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- height: 20px;
- padding: 5px 10px;
- background: rgba(245, 246, 248, 1);
- color: #333;
- width: fit-content;
- font-weight: 600;
-}
-
-.user-meta {
- font-size: 12px;
- color: rgba(0, 0, 0, 0.55);
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-
-.user-meta .sep {
- margin: 0 10px;
- color: rgba(0, 0, 0, 0.25);
-}
-
-.avatar {
- width: 90px;
- height: 90px;
- border-radius: 50%;
- object-fit: cover;
- flex: 0 0 auto;
-}
-
-.data-cards {
- width: 50%;
- display: flex;
- gap: 16px;
- justify-content: flex-start;
- background: #ffffff;
- border-radius: 12px;
- padding: 20px;
-}
-
-.data-title {
- font-weight: 700;
- font-size: 26px;
- color: #FFFFFF;
-}
-
-.data-num {
- display: flex;
- align-items: center;
- justify-content: space-between;
- margin-top: 20px;
-}
-
-.data-card {
- background: #fff;
- border-radius: 12px;
- padding: 14px 10px 10px 10px;
- min-width: 160px;
- box-shadow: 0 2px 8px #eee;
- display: flex;
- flex-direction: column;
- width: 32%;
- height: 140px;
-}
-
-.data-card.sales {
- background-image: url("../assets/images/xioashoushuju.png");
- background-size: cover;
- background-position: center;
- background-repeat: no-repeat;
-}
-
-.data-card.purchase {
- background-image: url("../assets/images/caigou.png");
- background-size: cover;
- background-position: center;
- background-repeat: no-repeat;
-}
-
-.data-card.inventory {
- background-image: url("../assets/images/kucun.png");
- background-size: cover;
- background-position: center;
- background-repeat: no-repeat;
-}
-
-.data-desc {
- font-weight: 500;
- font-size: 13px;
- color: #FFFFFF;
-}
-
-.data-value {
- font-size: 18px;
- font-weight: 500;
- margin: 10px 0;
- color: #FFFFFF;
}
.top-left {
display: flex;
flex-direction: column;
gap: 20px;
- height: 180px;
- width: 20%;
+}
+
+.company-info {
+ background: #fff;
+ border-radius: 12px;
+ padding: 20px;
+}
+
+.welcome-banner {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 20px;
+ padding-bottom: 16px;
+ border-bottom: 1px solid #ebeef5;
+}
+
+.welcome-title {
+ font-size: 18px;
+ color: #303133;
+
+ .welcome-user {
+ font-weight: 600;
+ color: var(--el-color-primary);
+ }
+}
+
+.welcome-time {
+ font-size: 13px;
+ color: #909399;
+}
+
+.user-card {
+ display: flex;
+ align-items: center;
+ gap: 16px;
+}
+
+.avatar {
+ width: 64px;
+ height: 64px;
+ border-radius: 50%;
+ object-fit: cover;
+ border: 3px solid var(--el-color-primary-light-8);
+}
+
+.user-card-main {
+ .user-name {
+ font-size: 18px;
+ font-weight: 600;
+ color: #303133;
+ margin-bottom: 4px;
+ }
+
+ .user-role {
+ font-size: 13px;
+ color: var(--el-color-primary);
+ background: var(--el-color-primary-light-9);
+ padding: 2px 10px;
+ border-radius: 4px;
+ display: inline-block;
+ margin-bottom: 8px;
+ }
+
+ .user-meta {
+ font-size: 13px;
+ color: #606266;
+
+ .sep {
+ margin: 0 8px;
+ color: #dcdfe6;
+ }
+ }
+}
+
+.data-cards {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 16px;
+}
+
+.data-card {
+ background: #fff;
+ border-radius: 12px;
+ padding: 16px;
+
+ .data-title {
+ font-size: 14px;
+ color: #606266;
+ margin-bottom: 12px;
+ }
+
+ .data-num {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ }
+
+ .data-desc {
+ font-size: 12px;
+ color: #909399;
+ }
+
+ .data-value {
+ font-size: 20px;
+ font-weight: 600;
+ color: #303133;
+ }
}
.todo-panel {
background: #fff;
border-radius: 12px;
padding: 20px;
- height: 180px;
- width: 30%;
+}
+
+.section-title {
+ font-size: 16px;
+ font-weight: 600;
+ color: #303133;
+ margin-bottom: 16px;
+ position: relative;
+ padding-left: 12px;
+
+ &::before {
+ content: '';
+ position: absolute;
+ left: 0;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 4px;
+ height: 16px;
+ background: var(--el-color-primary);
+ border-radius: 2px;
+ }
}
.todo-list {
- height: 100px;
list-style: none;
padding: 0;
margin: 0;
- font-size: 15px;
- overflow-y: auto;
-}
-.todo-list li {
- border-radius: 8px;
- margin-bottom: 12px;
- padding: 8px 20px;
- height: 74px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- background: rgba(225, 227, 250, 0.62);
-}
+ li {
+ padding: 12px 0;
+ border-bottom: 1px solid #ebeef5;
-.todo-title {
- font-weight: 400;
- font-size: 12px;
- color: #000000;
- position: relative;
-}
-
-.todo-title::before {
- content: '';
- /* 蹇呴渶锛岃〃绀鸿繖閲屾湁涓�涓唴瀹� */
- position: absolute;
- left: -10px;
- /* 瀹氫綅鍒板乏渚� */
- top: 50%;
- /* 鍨傜洿灞呬腑 */
- transform: translateY(-50%);
- /* 寰皟鍨傜洿灞呬腑 */
- width: 6px;
- /* 鍦嗙殑鐩村緞 */
- height: 6px;
- /* 鍦嗙殑鐩村緞 */
- background: #498CEB;
- border-radius: 50%;
- /* 璁╁叾鍙樻垚鍦嗗舰 */
-}
-
-.todo-division {
- font-weight: 400;
- font-size: 12px;
- color: #000000;
-}
-
-.todo-time {
- font-weight: 400;
- font-size: 12px;
- color: #000000;
-}
-
-.todo-meta {
- color: #888;
- font-size: 13px;
+ &:last-child {
+ border-bottom: none;
+ }
+ }
}
.dashboard-row {
- display: flex;
+ display: grid;
+ grid-template-columns: 1fr 1fr;
gap: 20px;
margin-bottom: 20px;
}
@@ -983,177 +875,131 @@
background: #fff;
border-radius: 12px;
padding: 20px;
- flex: 1;
- min-width: 0;
- display: flex;
- flex-direction: column;
}
-.section-title {
- position: relative;
- font-size: 18px;
- color: #333;
- padding-left: 10px;
- margin-bottom: 10px;
- font-weight: 700;
+.contract-panel {
+ grid-column: 1 / -1;
}
-.section-title::before {
- position: absolute;
- left: 0;
- top: 4px;
- content: '';
- width: 4px;
- height: 18px;
- background-color: #002FA7;
- border-radius: 2px;
+.contract-summary {
+ margin-bottom: 20px;
}
.contract-info {
display: flex;
align-items: center;
- gap: 20px;
- height: 90px;
- background: rgba(245, 245, 245, 0.59);
- width: 100%;
- border-radius: 10px;
- padding: 10px 30px;
-}
-
-.contract-summary {
- display: flex;
- align-items: center;
- gap: 30px;
+ gap: 16px;
}
.contract-card {
- display: flex;
- flex-direction: column;
- gap: 10px;
+ .contract-name {
+ font-size: 14px;
+ color: #909399;
+ margin-bottom: 8px;
+ }
+
+ .contract-meta {
+ .main-amount {
+ font-size: 28px;
+ font-weight: 700;
+ color: #303133;
+ margin-bottom: 8px;
+ }
+
+ .up {
+ color: #67c23a;
+ }
+ }
}
-.contract-name {
- font-weight: 400;
- font-size: 14px;
- color: #050505;
-}
-
-.contract-meta {
+.contract-chart-wrapper {
display: flex;
align-items: center;
- width: 100%;
- gap: 80px;
+ gap: 40px;
+ justify-content: center;
+ margin-top: 20px;
}
-.main-amount {
- font-size: 24px;
- color: rgba(51, 50, 50, 0.85);
-}
-
-.up {
- color: #e57373;
+.chart-container {
+ width: 320px;
+ height: 280px;
}
.contract-list {
- margin-top: 16px;
- font-size: 14px;
- color: #666;
list-style: none;
padding: 0;
- height: 190px;
- overflow-y: auto;
- width: 460px;
-}
+ margin: 0;
+ min-width: 300px;
-.line {
- position: relative;
- width: 230px;
-}
+ li {
+ margin-bottom: 12px;
-.line::after {
- content: '';
- position: absolute;
- right: 2px;
- top: 0;
- bottom: 0;
- width: 1px;
- background-color: #C9C5C5;
- border-radius: 2px;
-}
+ &:last-child {
+ margin-bottom: 0;
+ }
+ }
-.contract-list li {
- margin-top: 10px;
-}
+ .contract-item {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ padding: 10px 16px;
+ background: #f5f7fa;
+ border-radius: 8px;
-.quality-cards {
- display: flex;
- gap: 12px;
- margin-bottom: 12px;
-}
+ .contract-dot {
+ width: 10px;
+ height: 10px;
+ border-radius: 50%;
+ flex-shrink: 0;
+ }
-.quality-card {
- border-radius: 8px;
- padding: 15px 10px 10px 50px;
- font-weight: 400;
- font-size: 12px;
- color: rgba(0, 0, 0, 0.67);
- width: 236px;
- height: 49px;
- background-size: cover;
- background-position: center;
- background-repeat: no-repeat;
-}
+ .contract-name {
+ flex: 1;
+ font-size: 14px;
+ color: #303133;
+ }
-.quality-card.one {
- background-image: url("../assets/images/yuancailiao.png");
-}
+ .contract-rate {
+ font-size: 13px;
+ color: #909399;
+ min-width: 50px;
+ text-align: right;
+ }
-.quality-card.two {
- background-image: url("../assets/images/guocheng.png");
-}
-
-.quality-card.three {
- background-image: url("../assets/images/chuchang.png");
-
-}
-
-.quality-card span {
- color: #4fc3f7;
- font-weight: bold;
- margin-left: 6px;
-}
-
-.chart {
- width: 100%;
- height: 220px;
- margin-top: 10px;
+ .contract-value {
+ font-size: 14px;
+ font-weight: 600;
+ color: #303133;
+ min-width: 100px;
+ text-align: right;
+ }
+ }
}
.process-panel {
- padding-bottom: 10px;
+ grid-column: 1 / -1;
}
.process-panel__header {
display: flex;
justify-content: space-between;
align-items: center;
+ margin-bottom: 20px;
}
.process-panel__body {
- display: flex;
- gap: 24px;
- align-items: stretch;
- margin-top: 10px;
+ display: grid;
+ grid-template-columns: 1fr 280px;
+ gap: 20px;
+ height: 300px;
}
.process-panel__chart {
- flex: 1;
- min-width: 0;
- padding: 6px 0;
+ height: 100%;
}
.process-panel__aside {
- width: 260px;
display: flex;
flex-direction: column;
gap: 12px;
@@ -1161,102 +1007,118 @@
.process-legend {
display: flex;
- flex-direction: column;
- gap: 10px;
- align-items: flex-start;
- padding: 8px 6px;
+ gap: 16px;
+ margin-bottom: 8px;
}
.process-legend__item {
display: flex;
align-items: center;
- gap: 8px;
+ gap: 6px;
font-size: 13px;
- color: rgba(0, 0, 0, 0.55);
-}
+ color: #606266;
-.dot {
- width: 10px;
- height: 10px;
- border-radius: 2px;
- display: inline-block;
-}
+ .dot {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
-.dot-blue {
- background: #1E5BFF;
-}
+ &.dot-blue {
+ background: #2D99FF;
+ }
-.dot-yellow {
- background: #F7B500;
-}
+ &.dot-yellow {
+ background: #F2CA6D;
+ }
-.dot-teal {
- background: #19C6C6;
+ &.dot-teal {
+ background: #5EE9C0;
+ }
+ }
}
.process-card {
- background: rgba(245, 247, 250, 0.9);
- border-radius: 10px;
- padding: 16px 16px;
+ background: #f5f7fa;
+ border-radius: 8px;
+ padding: 12px 16px;
+
+ &--name {
+ font-weight: 600;
+ color: #303133;
+ background: var(--el-color-primary-light-9);
+ }
+
+ &__label {
+ font-size: 12px;
+ color: #909399;
+ margin-bottom: 4px;
+ }
+
+ &__value {
+ font-size: 18px;
+ font-weight: 600;
+ color: #303133;
+ }
}
-.process-card--name {
- background: rgba(235, 242, 255, 1);
- color: #1E5BFF;
- font-weight: 800;
- font-size: 14px;
+.quality-cards {
+ display: flex;
+ gap: 12px;
+ margin-bottom: 16px;
}
-.process-card__label {
+.quality-card {
+ flex: 1;
+ background: #f5f7fa;
+ border-radius: 8px;
+ padding: 12px;
font-size: 13px;
- color: rgba(0, 0, 0, 0.55);
- margin-bottom: 10px;
-}
+ color: #606266;
-.process-card__value {
- font-size: 24px;
- font-weight: 800;
- color: rgba(0, 0, 0, 0.8);
-}
-
-.process-card__value .unit {
- font-size: 12px;
- font-weight: 600;
- color: rgba(0, 0, 0, 0.45);
- margin-left: 6px;
-}
-
-@media (max-width: 1200px) {
- .process-panel__body {
- flex-direction: column;
+ span {
+ display: block;
+ font-size: 20px;
+ font-weight: 600;
+ color: #303133;
+ margin-top: 4px;
}
- .process-panel__aside {
- width: 100%;
- flex-direction: row;
- flex-wrap: wrap;
+ &.one {
+ background: #e6f7ff;
+ color: #1890ff;
+
+ span {
+ color: #1890ff;
+ }
}
- .process-card {
- flex: 1;
- min-width: 220px;
+ &.two {
+ background: #f6ffed;
+ color: #52c41a;
+
+ span {
+ color: #52c41a;
+ }
+ }
+
+ &.three {
+ background: #fff7e6;
+ color: #fa8c16;
+
+ span {
+ color: #fa8c16;
+ }
}
}
.process-selection-wrapper {
max-height: 400px;
overflow-y: auto;
- padding: 10px;
}
.process-grid {
display: grid;
- grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
+ grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
-
-:deep(.el-checkbox.is-bordered) {
- margin-left: 0 !important;
- width: 100%;
-}
-</style>
\ No newline at end of file
+</style>
diff --git a/src/views/login.vue b/src/views/login.vue
index 872537b..ecb9657 100644
--- a/src/views/login.vue
+++ b/src/views/login.vue
@@ -1,80 +1,63 @@
<template>
<div class="login-page">
- <div class="login-shell">
- <section class="login-brand">
- <div class="brand-badge">PRODUCT INVENTORY</div>
- <img :src="brandLogo" alt="brand logo" class="brand-logo" />
- <h1 class="brand-title">{{ title }}</h1>
- <p class="brand-copy">
- 缁熶竴绠$悊搴撳瓨銆佹祦绋嬩笌涓氬姟鏁版嵁锛岃绯荤粺鍏ュ彛鍜屽悗鍙颁富鐣岄潰淇濇寔鍚屼竴濂楃畝绾﹁瑙夎瑷�銆�
- </p>
- <div class="brand-points">
- <div class="brand-point">
- <span class="point-dot"></span>
- <span>娓呮櫚鐨勬暟鎹叆鍙�</span>
- </div>
- <div class="brand-point">
- <span class="point-dot"></span>
- <span>鏇磋交鐨勭晫闈㈠眰娆�</span>
- </div>
- <div class="brand-point">
- <span class="point-dot"></span>
- <span>绋冲畾鐨勪笟鍔″崗鍚屼綋楠�</span>
- </div>
+ <div class="login-card">
+ <div class="card-header">
+ <div class="logo">
+ <svg-icon icon-class="user" />
</div>
- </section>
+ <h1>瀹㈡埛鍏崇郴绠$悊绯荤粺</h1>
+ <p>楂樻晥绠$悊瀹㈡埛璧勬簮锛岄┍鍔ㄤ笟鍔″闀�</p>
+ </div>
- <section class="login-panel">
- <el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form">
- <div class="panel-head">
- <p class="panel-kicker">WELCOME BACK</p>
- <h2 class="panel-title">鐧诲綍绯荤粺</h2>
- <p class="panel-subtitle">杈撳叆璐﹀彿鍜屽瘑鐮佽繘鍏ュ伐浣滃彴銆�</p>
- </div>
-
- <el-form-item prop="username">
- <el-input
- v-model="loginForm.username"
- type="text"
- size="large"
- auto-complete="off"
- placeholder="璐﹀彿"
- >
- <template #prefix><el-icon><User /></el-icon></template>
- </el-input>
- </el-form-item>
-
- <el-form-item prop="password">
- <el-input
- v-model="loginForm.password"
- type="password"
- size="large"
- auto-complete="off"
- placeholder="瀵嗙爜"
- show-password
- @keyup.enter="handleLogin"
- >
- <template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
- </el-input>
- </el-form-item>
-
- <div class="login-options">
- <el-checkbox v-model="loginForm.rememberMe">璁颁綇瀵嗙爜</el-checkbox>
- <router-link v-if="register" class="register-link" :to="'/register'">绔嬪嵆娉ㄥ唽</router-link>
- </div>
-
- <el-button
- :loading="loading"
+ <el-form ref="loginRef" :model="loginForm" :rules="loginRules">
+ <el-form-item prop="username">
+ <el-input
+ v-model="loginForm.username"
+ type="text"
size="large"
- type="primary"
- class="login-submit"
- @click.prevent="handleLogin"
+ auto-complete="off"
+ placeholder="璇疯緭鍏ヨ处鍙�"
>
- <span v-if="!loading">鐧诲綍</span>
- <span v-else>鐧诲綍涓�...</span>
- </el-button>
- </el-form>
- </section>
+ <template #prefix><el-icon><User /></el-icon></template>
+ </el-input>
+ </el-form-item>
+
+ <el-form-item prop="password">
+ <el-input
+ v-model="loginForm.password"
+ type="password"
+ size="large"
+ auto-complete="off"
+ placeholder="璇疯緭鍏ュ瘑鐮�"
+ show-password
+ @keyup.enter="handleLogin"
+ >
+ <template #prefix><el-icon><Lock /></el-icon></template>
+ </el-input>
+ </el-form-item>
+
+ <div class="form-options">
+ <el-checkbox v-model="loginForm.rememberMe">璁颁綇瀵嗙爜</el-checkbox>
+ <router-link v-if="register" :to="'/register'">绔嬪嵆娉ㄥ唽</router-link>
+ </div>
+
+ <el-button
+ :loading="loading"
+ size="large"
+ type="primary"
+ class="login-btn"
+ @click.prevent="handleLogin"
+ >
+ <span v-if="!loading">鐧� 褰�</span>
+ <span v-else>鐧诲綍涓�...</span>
+ </el-button>
+ </el-form>
+ </div>
+
+ <div class="bg-pattern">
+ <div class="pattern-item"></div>
+ <div class="pattern-item"></div>
+ <div class="pattern-item"></div>
</div>
</div>
</template>
@@ -84,9 +67,7 @@
import Cookies from "js-cookie"
import { encrypt, decrypt } from "@/utils/jsencrypt"
import useUserStore from "@/store/modules/user"
-import brandLogo from "@/assets/logo/logo.png"
-const title = import.meta.env.VITE_APP_TITLE
const userStore = useUserStore()
const route = useRoute()
const router = useRouter()
@@ -99,11 +80,10 @@
})
const loginRules = {
- username: [{ required: true, trigger: "blur", message: "璇疯緭鍏ユ偍鐨勮处鍙�" }],
- password: [{ required: true, trigger: "blur", message: "璇疯緭鍏ユ偍鐨勫瘑鐮�" }],
+ username: [{ required: true, trigger: "blur", message: "璇疯緭鍏ヨ处鍙�" }],
+ password: [{ required: true, trigger: "blur", message: "璇疯緭鍏ュ瘑鐮�" }],
}
-const codeUrl = ref("")
const loading = ref(false)
const captchaEnabled = ref(true)
const register = ref(false)
@@ -150,7 +130,6 @@
getCodeImg().then((res) => {
captchaEnabled.value = res.captchaEnabled === undefined ? true : res.captchaEnabled
if (captchaEnabled.value) {
- codeUrl.value = "data:image/gif;base64," + res.img
loginForm.value.uuid = res.uuid
}
})
@@ -177,225 +156,189 @@
display: flex;
align-items: center;
justify-content: center;
- padding: 32px;
- background:
- radial-gradient(circle at top left, rgba(207, 223, 214, 0.95), transparent 30%),
- radial-gradient(circle at bottom right, rgba(222, 232, 227, 0.9), transparent 28%),
- linear-gradient(180deg, #f7faf8 0%, #eef2ee 100%);
-}
-
-.login-shell {
- width: min(1120px, 100%);
- min-height: 680px;
- display: grid;
- grid-template-columns: 1.1fr 0.9fr;
- border: 1px solid rgba(216, 225, 219, 0.9);
- border-radius: 32px;
- overflow: hidden;
- background: rgba(255, 255, 255, 0.76);
- box-shadow: 0 26px 80px rgba(31, 49, 38, 0.12);
- backdrop-filter: blur(24px);
-}
-
-.login-brand {
+ background: linear-gradient(135deg, var(--el-color-primary-light-9) 0%, var(--el-color-primary-light-8) 50%, var(--el-color-primary-light-9) 100%);
position: relative;
- display: flex;
- flex-direction: column;
- justify-content: center;
- padding: 56px 64px;
- background:
- linear-gradient(180deg, rgba(244, 248, 245, 0.9), rgba(233, 240, 236, 0.9)),
- linear-gradient(135deg, rgba(31, 122, 114, 0.05), rgba(255, 255, 255, 0));
+ overflow: hidden;
+}
- &::after {
- content: "";
+.bg-pattern {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ pointer-events: none;
+
+ .pattern-item {
position: absolute;
- inset: 28px;
- border: 1px solid rgba(31, 122, 114, 0.08);
- border-radius: 28px;
- pointer-events: none;
+ border-radius: 50%;
+ background: linear-gradient(135deg, var(--el-color-primary-light-7), var(--el-color-primary-light-9));
+ }
+
+ .pattern-item:nth-child(1) {
+ width: 500px;
+ height: 500px;
+ top: -150px;
+ right: -100px;
+ }
+
+ .pattern-item:nth-child(2) {
+ width: 350px;
+ height: 350px;
+ bottom: -100px;
+ left: -80px;
+ }
+
+ .pattern-item:nth-child(3) {
+ width: 200px;
+ height: 200px;
+ top: 40%;
+ left: 15%;
+ background: linear-gradient(135deg, var(--el-color-primary-light-8), var(--el-color-primary-light-9));
}
}
-.brand-badge {
- width: fit-content;
- padding: 8px 14px;
- border-radius: 999px;
- background: rgba(31, 122, 114, 0.1);
- color: #1f7a72;
- font-size: 12px;
- font-weight: 700;
- letter-spacing: 0.14em;
+.login-card {
+ width: 420px;
+ padding: 48px 40px;
+ background: rgba(255, 255, 255, 0.95);
+ border-radius: 20px;
+ box-shadow:
+ 0 4px 6px -1px rgba(0, 0, 0, 0.05),
+ 0 10px 15px -3px rgba(0, 0, 0, 0.08),
+ 0 20px 25px -5px rgba(0, 0, 0, 0.05);
+ backdrop-filter: blur(10px);
+ position: relative;
+ z-index: 1;
}
-.brand-logo {
- width: 160px;
- height: auto;
- margin: 30px 0 24px;
- object-fit: contain;
-}
+.card-header {
+ text-align: center;
+ margin-bottom: 36px;
-.brand-title {
- margin: 0;
- font-size: 42px;
- line-height: 1.12;
- color: #21313f;
- letter-spacing: -0.03em;
-}
+ .logo {
+ width: 72px;
+ height: 72px;
+ margin: 0 auto 20px;
+ background: linear-gradient(135deg, var(--el-color-primary) 0%, var(--el-color-primary-light-3) 100%);
+ border-radius: 18px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-shadow: 0 8px 20px var(--el-color-primary-light-5);
-.brand-copy {
- max-width: 460px;
- margin: 18px 0 0;
- font-size: 16px;
- line-height: 1.75;
- color: #5f6d7e;
-}
+ :deep(svg) {
+ width: 36px;
+ height: 36px;
+ color: #fff;
+ }
+ }
-.brand-points {
- margin-top: 34px;
- display: flex;
- flex-direction: column;
- gap: 14px;
-}
+ h1 {
+ font-size: 24px;
+ font-weight: 600;
+ color: #1f2937;
+ margin: 0 0 8px;
+ }
-.brand-point {
- display: flex;
- align-items: center;
- gap: 12px;
- color: #3d4b59;
- font-size: 15px;
- font-weight: 500;
-}
-
-.point-dot {
- width: 10px;
- height: 10px;
- border-radius: 50%;
- background: linear-gradient(135deg, #1f7a72, #5ca39c);
- box-shadow: 0 0 0 6px rgba(31, 122, 114, 0.08);
-}
-
-.login-panel {
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 40px;
- background: rgba(255, 255, 255, 0.7);
-}
-
-.login-form {
- width: min(420px, 100%);
- padding: 38px 34px 34px;
- border: 1px solid rgba(216, 225, 219, 0.92);
- border-radius: 28px;
- background: rgba(255, 255, 255, 0.88);
- box-shadow: 0 18px 52px rgba(31, 49, 38, 0.1);
-}
-
-.panel-head {
- margin-bottom: 28px;
-}
-
-.panel-kicker {
- margin: 0 0 10px;
- color: #8a98a8;
- font-size: 12px;
- font-weight: 700;
- letter-spacing: 0.16em;
-}
-
-.panel-title {
- margin: 0;
- color: #21313f;
- font-size: 30px;
- font-weight: 700;
-}
-
-.panel-subtitle {
- margin: 10px 0 0;
- color: #6b7888;
- font-size: 14px;
-}
-
-.login-options {
- margin: -4px 0 22px;
- display: flex;
- align-items: center;
- justify-content: space-between;
- color: #5f6d7e;
-}
-
-.register-link {
- color: var(--el-color-primary);
- font-weight: 600;
-}
-
-.login-submit {
- width: 100%;
- height: 48px;
-}
-
-.input-icon {
- width: 14px;
+ p {
+ font-size: 14px;
+ color: #6b7280;
+ margin: 0;
+ }
}
:deep(.el-form-item) {
- margin-bottom: 22px;
+ margin-bottom: 20px;
}
:deep(.el-input__wrapper) {
- min-height: 42px;
- height: 42px;
- padding-top: 0;
- padding-bottom: 0;
+ border-radius: 12px;
+ box-shadow: 0 0 0 1px #e5e7eb;
+ padding: 0 16px;
+ height: 48px;
+ transition: all 0.2s;
+
+ &:hover {
+ box-shadow: 0 0 0 1px var(--el-color-primary-light-5);
+ }
+
+ &:focus-within {
+ box-shadow: 0 0 0 2px var(--el-color-primary);
+ }
}
:deep(.el-input__inner) {
- height: 42px;
- line-height: 42px;
+ height: 48px;
+ font-size: 15px;
+ color: #374151;
+
+ &::placeholder {
+ color: #9ca3af;
+ }
}
-:deep(.el-checkbox) {
- color: #5f6d7e;
+:deep(.el-input__prefix) {
+ color: #9ca3af;
+ font-size: 18px;
}
-@media (max-width: 960px) {
- .login-page {
- padding: 18px;
- }
+.form-options {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin: 8px 0 24px;
- .login-shell {
- min-height: auto;
- grid-template-columns: 1fr;
- }
-
- .login-brand {
- padding: 40px 28px 22px;
- }
-
- .login-brand::after {
- inset: 16px;
- }
-
- .brand-title {
- font-size: 32px;
- }
-
- .brand-copy {
+ :deep(.el-checkbox__label) {
+ color: #6b7280;
font-size: 14px;
}
- .brand-points {
- margin-top: 24px;
+ :deep(.el-checkbox__input.is-checked .el-checkbox__inner) {
+ background-color: var(--el-color-primary);
+ border-color: var(--el-color-primary);
}
- .login-panel {
- padding: 12px 18px 24px;
+ a {
+ color: var(--el-color-primary);
+ font-size: 14px;
+ font-weight: 500;
+ text-decoration: none;
+ transition: color 0.2s;
+
+ &:hover {
+ color: var(--el-color-primary-light-3);
+ }
+ }
+}
+
+.login-btn {
+ width: 100%;
+ height: 48px;
+ border-radius: 12px;
+ font-size: 16px;
+ font-weight: 500;
+ background: linear-gradient(135deg, var(--el-color-primary) 0%, var(--el-color-primary-light-3) 100%);
+ border: none;
+ box-shadow: 0 4px 14px var(--el-color-primary-light-5);
+ transition: all 0.2s;
+
+ &:hover {
+ transform: translateY(-1px);
+ box-shadow: 0 6px 20px var(--el-color-primary-light-4);
+ }
+}
+
+@media (max-width: 480px) {
+ .login-card {
+ width: 90%;
+ padding: 36px 24px;
}
- .login-form {
- width: 100%;
- padding: 28px 22px 24px;
+ .card-header {
+ h1 {
+ font-size: 20px;
+ }
}
}
</style>
diff --git a/vite.config.js b/vite.config.js
index 03311be..4e185c8 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -8,7 +8,7 @@
const { VITE_APP_ENV } = env;
const baseUrl =
env.VITE_APP_ENV === "development"
- ? "http://1.15.17.182:9048"
+ ? "http://1.15.17.182:9055"
: env.VITE_BASE_API;
const javaUrl =
env.VITE_APP_ENV === "development"
--
Gitblit v1.9.3