From 1c829f9177eab675b22be4d20ef2761ed1bbb423 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期二, 15 九月 2026 16:15:48 +0800
Subject: [PATCH] refactor(layout): 调整布局样式并优化轮播卡片组件
---
src/views/reportAnalysis/dataDashboard/components/basic/center-top.vue | 372 ++++++++++++++++++++++++++++------------------------
1 files changed, 199 insertions(+), 173 deletions(-)
diff --git a/src/views/reportAnalysis/dataDashboard/components/basic/center-top.vue b/src/views/reportAnalysis/dataDashboard/components/basic/center-top.vue
index 950038e..d5b7f2e 100644
--- a/src/views/reportAnalysis/dataDashboard/components/basic/center-top.vue
+++ b/src/views/reportAnalysis/dataDashboard/components/basic/center-top.vue
@@ -3,38 +3,60 @@
<!-- 椤堕儴缁熻鍗$墖 -->
<div class="stats-cards">
<div class="stat-card">
- <img src="@/assets/BI/icon@2x.png" alt="鍥炬爣" class="card-icon" />
+ <div class="card-icon" style="color: #4a6cf0">
+ <!-- 鍛樺伐 -->
+ <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
+ <circle cx="12" cy="8" r="4" />
+ <path d="M4 21v-1a8 8 0 0 1 16 0v1" />
+ </svg>
+ </div>
<div class="card-content">
<span class="card-label">鍛樺伐鎬绘暟</span>
<span class="card-value">{{ totalStaff }}</span>
<div class="card-compare" :class="compareClass(staffYoY)">
<span>鍚屾瘮</span>
<span class="compare-value">{{ formatPercent(staffYoY) }}</span>
- <span class="compare-icon">{{ staffYoY >= 0 ? '鈫�' : '鈫�' }}</span>
+ <span v-if="!isZero(staffYoY)" class="compare-icon">{{ staffYoY > 0 ? '鈫�' : '鈫�' }}</span>
</div>
</div>
</div>
<div class="stat-card">
- <img src="@/assets/BI/icon@2x.png" alt="鍥炬爣" class="card-icon" />
+ <div class="card-icon" style="color: #35c6d6">
+ <!-- 瀹㈡埛 -->
+ <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
+ <circle cx="9" cy="8" r="3.5" />
+ <path d="M2.5 20v-1a6.5 6.5 0 0 1 13 0v1" />
+ <path d="M16 5a3.5 3.5 0 0 1 0 6.5" />
+ <path d="M17.5 13.5A6.5 6.5 0 0 1 21.5 20" />
+ </svg>
+ </div>
<div class="card-content">
<span class="card-label">瀹㈡埛鎬绘暟</span>
<span class="card-value">{{ totalCustomers }}</span>
<div class="card-compare" :class="compareClass(customersYoY)">
<span>鍚屾瘮</span>
<span class="compare-value">{{ formatPercent(customersYoY) }}</span>
- <span class="compare-icon">{{ customersYoY >= 0 ? '鈫�' : '鈫�' }}</span>
+ <span v-if="!isZero(customersYoY)" class="compare-icon">{{ customersYoY > 0 ? '鈫�' : '鈫�' }}</span>
</div>
</div>
</div>
<div class="stat-card">
- <img src="@/assets/BI/icon@2x.png" alt="鍥炬爣" class="card-icon" />
+ <div class="card-icon" style="color: #8e7ce6">
+ <!-- 渚涘簲鍟� -->
+ <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
+ <rect x="1.5" y="5" width="13" height="11" rx="1.5" />
+ <path d="M14.5 9h4l3 3.5v3.5h-2" />
+ <circle cx="6" cy="18.5" r="1.8" />
+ <circle cx="17.5" cy="18.5" r="1.8" />
+ </svg>
+ </div>
<div class="card-content">
<span class="card-label">渚涘簲鍟嗘�绘暟</span>
<span class="card-value">{{ totalSuppliers }}</span>
<div class="card-compare" :class="compareClass(suppliersYoY)">
<span>鍚屾瘮</span>
<span class="compare-value">{{ formatPercent(suppliersYoY) }}</span>
- <span class="compare-icon">{{ suppliersYoY >= 0 ? '鈫�' : '鈫�' }}</span>
+ <span v-if="!isZero(suppliersYoY)" class="compare-icon">{{ suppliersYoY > 0 ? '鈫�' : '鈫�' }}</span>
</div>
</div>
</div>
@@ -42,13 +64,12 @@
<!-- 璁惧缁熻 -->
<div class="equipment-stats">
- <div class="equipment-header">
- <img
- src="@/assets/BI/shujutongjiicon@2x.png"
- alt="鍥炬爣"
- class="equipment-icon"
- />
- <span class="equipment-title">璁惧缁熻</span>
+ <div class="section-header">
+ <svg class="section-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
+ <circle cx="12" cy="12" r="3" />
+ <path d="M19.4 15a1.7 1.7 0 0 0 .34 1.87l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.7 1.7 0 0 0-1.87-.34 1.7 1.7 0 0 0-1.03 1.55V21a2 2 0 1 1-4 0v-.09a1.7 1.7 0 0 0-1.11-1.55 1.7 1.7 0 0 0-1.87.34l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.7 1.7 0 0 0 .34-1.87 1.7 1.7 0 0 0-1.55-1.03H3a2 2 0 1 1 0-4h.09a1.7 1.7 0 0 0 1.55-1.11 1.7 1.7 0 0 0-.34-1.87l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.7 1.7 0 0 0 1.87.34h.08A1.7 1.7 0 0 0 10.31 3.1V3a2 2 0 1 1 4 0v.09a1.7 1.7 0 0 0 1.03 1.55 1.7 1.7 0 0 0 1.87-.34l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.7 1.7 0 0 0-.34 1.87v.08a1.7 1.7 0 0 0 1.55 1.03H21a2 2 0 1 1 0 4h-.09a1.7 1.7 0 0 0-1.55 1.03z" />
+ </svg>
+ <span class="section-title">璁惧缁熻</span>
</div>
<div class="equipment-items">
<div class="equipment-item">
@@ -70,40 +91,28 @@
</div>
</div>
- <!-- 浜嬩欢鍚嶇О -->
+ <!-- 寰呭姙浜嬩欢 -->
<div class="event-info">
- <div class="event-header">
- <img
- src="@/assets/BI/shijianmingxiicon@2x.png"
- alt="鍥炬爣"
- class="event-icon"
- />
- <span class="event-title">浜嬩欢鍚嶇О</span>
+ <div class="section-header">
+ <svg class="section-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
+ <rect x="4" y="4" width="16" height="17" rx="2" />
+ <path d="M9 2.5h6v3H9z" />
+ <path d="M8.5 11h7M8.5 15.5h5" />
+ </svg>
+ <span class="section-title">浜嬩欢鍚嶇О</span>
</div>
<div class="event-content">
<ul class="todo-list" v-if="todoList.length > 0" ref="refTodoList">
<li v-for="item in todoList" :key="item.id">
- <div
- style="
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- width: 100%;
- gap: 20px;
- "
- >
- <div class="todo-division">寰呭姙浜嬬敱锛歿{ item.approveReason }}</div>
- <div style="display: flex;justify-content: space-between;align-items: center;"
- >
- <div class="todo-title">鐢宠绫诲瀷锛歿{ item.approveTypeName }}</div>
- <div class="todo-division">鐢宠閮ㄩ棬锛歿{ item.approveDeptName }}</div>
- <div class="todo-time">{{ item.approveTime }}</div>
- </div>
-
+ <div class="todo-row">
+ <span class="todo-division todo-reason">寰呭姙浜嬬敱锛歿{ item.approveReason || '-' }}</span>
+ <span class="todo-title">鐢宠绫诲瀷锛歿{ item.approveTypeName || '-' }}</span>
+ <span class="todo-division">鐢宠閮ㄩ棬锛歿{ item.approveDeptName || '-' }}</span>
+ <span class="todo-time">{{ item.approveTime || '-' }}</span>
</div>
</li>
</ul>
- <div v-else style="text-align: center">鏆傛棤鏁版嵁</div>
+ <div v-else class="event-empty">鏆傛棤鏁版嵁</div>
</div>
</div>
</div>
@@ -139,17 +148,25 @@
return `${Math.abs(num).toFixed(2)}%`
}
-const compareClass = (val) => (val >= 0 ? 'compare-up' : 'compare-down')
+const isZero = (val) => !(Number(val) || 0)
+
+const compareClass = (val) => {
+ const num = Number(val) || 0
+ if (num > 0) return 'compare-up'
+ if (num < 0) return 'compare-down'
+ return 'compare-flat'
+}
// 鑾峰彇鍛樺伐銆佸鎴枫�佷緵搴斿晢鏁伴噺
const getNum = () => {
summaryStatistics().then((res) => {
- totalStaff.value = res.data.totalStaff
- staffYoY.value = res.data.staffGrowthRate
- totalCustomers.value = res.data.totalCustomer
- customersYoY.value = res.data.customerGrowthRate
- totalSuppliers.value = res.data.totalSupplier
- suppliersYoY.value = res.data.supplierGrowthRate
+ const d = res.data || {}
+ totalStaff.value = Number(d.totalStaff) || 0
+ staffYoY.value = Number(d.staffGrowthRate) || 0
+ totalCustomers.value = Number(d.totalCustomer) || 0
+ customersYoY.value = Number(d.customerGrowthRate) || 0
+ totalSuppliers.value = Number(d.totalSupplier) || 0
+ suppliersYoY.value = Number(d.supplierGrowthRate) || 0
}).catch(err => {
console.error('鑾峰彇鍩虹缁熻鏁版嵁澶辫触:', err)
})
@@ -162,16 +179,16 @@
pageSize: -1,
}
getLedgerPage(params).then((res) => {
- equipmentNum.value = res.data.total
+ equipmentNum.value = Number(res.data?.total) || 0
})
getRepairPage({ ...params, status: 0 }).then((res) => {
- equipmentRepair.value = res.data.total
+ equipmentRepair.value = Number(res.data?.total) || 0
})
getUpkeepPage({ ...params, status: 0 }).then((res) => {
- equipmentMaintain.value = res.data.total
+ equipmentMaintain.value = Number(res.data?.total) || 0
})
measuringInstrumentListPage(params).then((res) => {
- totalMeasuring.value = res.data.total
+ totalMeasuring.value = Number(res.data?.total) || 0
})
}
@@ -260,11 +277,14 @@
// 寰呭姙浜嬮」
const todoInfoS = () => {
homeTodos().then((res) => {
- todoList.value = res.data
+ todoList.value = res.data || []
// 鍦ㄨ幏鍙栧埌寰呭姙浜嬮」鏁版嵁鍚庯紝鍒濆鍖栨粴鍔ㄥ姛鑳�
nextTick(() => {
initTodoListScroll()
})
+ }).catch(err => {
+ console.error('鑾峰彇寰呭姙浜嬮」澶辫触:', err)
+ todoList.value = []
})
}
@@ -300,38 +320,56 @@
flex: 1;
display: flex;
align-items: center;
- background-image: url('@/assets/BI/border@2x.png');
- background-size: 100% 100%;
- background-position: center;
- background-repeat: no-repeat;
+ background: var(--bi-panel-bg);
+ border: 1px solid var(--bi-panel-border);
+ border-radius: 8px;
+ position: relative;
+ overflow: hidden;
height: 142px;
}
+/* 椤堕儴鍝佺墝钃濅寒绾匡紝鏇夸唬鍥剧墖鎻忚竟 */
+.stat-card::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 2px;
+ background: linear-gradient(90deg, var(--bi-accent) 0%, transparent 70%);
+}
+
.card-icon {
- width: 100px;
- height: 100px;
- margin: 20px 20px 0 10px;
+ width: 52px;
+ height: 52px;
+ margin: 0 16px 0 20px;
+ border-radius: 8px;
+ background: rgba(74, 108, 240, 0.12);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-shrink: 0;
}
.card-content {
display: flex;
flex-direction: column;
- gap: 10px;
+ gap: 8px;
+ min-width: 0;
}
.card-value {
- font-weight: 500;
- font-size: 40px;
- background: linear-gradient(360deg, #008bfd 0%, #ffffff 100%);
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- background-clip: text;
+ font-weight: 600;
+ font-size: 36px;
+ color: var(--bi-text-strong);
+ font-variant-numeric: tabular-nums;
+ line-height: 1.1;
}
.card-label {
font-weight: 400;
- font-size: 19px;
- color: rgba(208, 231, 255, 0.7);
+ font-size: 16px;
+ color: var(--bi-text);
}
.card-compare {
@@ -339,16 +377,17 @@
align-items: center;
gap: 6px;
font-size: 15px;
- color: #d0e7ff;
}
.card-compare > span:first-child {
font-size: 13px;
- opacity: 0.8;
+ color: var(--bi-text);
}
.compare-value {
font-weight: 600;
+ color: var(--bi-text);
+ font-variant-numeric: tabular-nums;
}
.compare-icon {
@@ -359,163 +398,150 @@
.compare-up .compare-value,
.compare-up .compare-icon {
- color: #00c853;
+ color: var(--bi-up, #34c77b);
}
.compare-down .compare-value,
.compare-down .compare-icon {
- color: #ff5252;
+ color: var(--bi-down, #ff6b6b);
+}
+
+/* 鎸佸钩锛氫笉鏄剧ず绠ご锛岄鑹蹭腑鎬� */
+.compare-flat .compare-value {
+ color: var(--bi-text);
+}
+
+.equipment-stats,
+.event-info {
+ background: var(--bi-panel-bg);
+ border: 1px solid var(--bi-panel-border);
+ border-radius: 8px;
+ padding: 14px 18px;
}
.equipment-stats {
- border: 1px solid #1a58b0;
- padding: 18px;
height: 240px;
- padding-top: 0px;
+ margin-top: 20px;
+ box-sizing: border-box;
}
-.equipment-header {
- font-weight: 500;
- font-size: 21px;
+.event-info {
+ height: 186px;
+ margin-top: 20px;
+ box-sizing: border-box;
+}
+
+.section-header {
display: flex;
- border-bottom: 1px solid;
- border-image: linear-gradient(
- 270deg,
- rgba(0, 126, 255, 0) 0%,
- rgba(0, 126, 255, 0.4549) 35%,
- #007eff 78%,
- #007eff 100%
- )
- 1;
- padding-bottom: 2px;
+ align-items: center;
+ gap: 8px;
+ color: var(--bi-accent-bright);
+ border-bottom: 1px solid rgba(143, 163, 200, 0.15);
+ padding-bottom: 10px;
}
-.equipment-title {
+.section-icon {
+ flex-shrink: 0;
+}
+
+.section-title {
font-weight: 500;
- font-size: 18px;
- background: linear-gradient(360deg, #056dff 0%, #43e8fc 100%);
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- background-clip: text;
- line-height: 50px;
-}
-
-.equipment-icon {
- width: 50px;
- height: 50px;
+ font-size: 16px;
+ color: var(--bi-text-strong);
+ letter-spacing: 1px;
}
.equipment-items {
display: flex;
justify-content: space-around;
- gap: 30px;
+ gap: 20px;
+ padding-top: 22px;
}
.equipment-item {
text-align: center;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
}
.equipment-value {
- display: block;
- font-weight: 500;
- font-size: 40px;
- color: #ffffff;
- width: 120px;
- height: 110px;
- line-height: 110px;
- background-image: url('@/assets/BI/shujutongji@2x.png');
- background-size: 100% 100%;
- background-position: center;
- background-repeat: no-repeat;
- margin-bottom: 8px;
+ font-weight: 600;
+ font-size: 36px;
+ color: var(--bi-text-strong);
+ font-variant-numeric: tabular-nums;
+ line-height: 1.1;
}
.equipment-label {
- font-weight: 500;
- font-size: 16px;
- color: #fffffe;
+ font-weight: 400;
+ font-size: 14px;
+ color: var(--bi-text);
}
-.event-info {
- background-image: url('@/assets/BI/shijianmingchengbeijing@2x.png');
- background-size: 100% 100%;
- background-position: center;
- background-repeat: no-repeat;
- padding: 20px;
- padding-top: 10px;
- height: 186px;
-}
-
-.event-header {
- display: flex;
- align-items: center;
-}
-
-.event-icon {
- width: 40px;
- height: 40px;
-}
-
-.event-title {
- font-weight: 500;
- font-size: 18px;
- color: #fffffe;
- line-height: 30px;
+.event-content {
+ padding-top: 8px;
}
.todo-list {
list-style: none;
padding: 0;
margin: 0;
- height: 120px; /* 鎸夌敤鎴疯姹傝皟鏁撮珮搴� */
+ height: 96px;
overflow: hidden;
- font-size: 15px;
+ font-size: 14px;
}
.todo-list li {
- border-radius: 8px;
- margin-bottom: 12px;
- padding: 12px 40px;
- height: 74px;
+ margin-bottom: 8px;
+}
+
+.todo-row {
display: flex;
- justify-content: space-between;
align-items: center;
+ gap: 24px;
+ padding: 9px 14px;
+ background: rgba(13, 24, 52, 0.6);
+ border: 1px solid rgba(30, 49, 96, 0.8);
+ border-radius: 6px;
}
.todo-title {
- font-weight: 400;
- font-size: 16px;
- color: #fffffe;
- position: relative;
+ font-size: 14px;
+ color: var(--bi-text);
+ white-space: nowrap;
}
-
-
.todo-division {
- font-weight: 400;
- font-size: 16px;
- color: #fffffe;
- position: relative;
+ font-size: 14px;
+ color: var(--bi-text);
+ white-space: nowrap;
}
-.todo-division::before {
- content: '';
- position: absolute;
- left: -20px;
- top: 50%;
- transform: translateY(-50%);
- width: 6px;
- height: 6px;
- background: #498ceb;
- border-radius: 50%;
+.todo-reason {
+ color: var(--bi-text-strong);
+ overflow: hidden;
+ text-overflow: ellipsis;
+ min-width: 0;
+ flex: 1;
}
.todo-time {
- font-weight: 400;
- font-size: 16px;
- color: #fffffe;
- background: rgba(24, 93, 190, 0.4);
-border-radius: 5px 5px 5px 5px;
-padding: 5px 10px;
+ font-size: 13px;
+ color: var(--bi-text);
+ background: rgba(74, 108, 240, 0.15);
+ border-radius: 4px;
+ padding: 3px 10px;
+ font-variant-numeric: tabular-nums;
+}
+
+.event-empty {
+ height: 96px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: var(--bi-text);
+ font-size: 14px;
+ letter-spacing: 1px;
}
</style>
--
Gitblit v1.9.3