Sfoglia il codice sorgente

refactor(portraitManagement): 优化组织画像及预警页面UI和组件结构

- 修正搜索栏中人员ID字段名称为userId
- 调整员工画像页面对X射线岗位字段的访问安全性(增加可选链)
- 组织画像页面中指标卡片颜色和背景色统一调整
- 替换右侧排行榜为复用RankList组件,提升代码复用和样式一致性
- 新增RankList组件,统一排行榜样式与结构
- 白卡组件标题点样式调整,移除冗余span
- 预警管理相关表格字段名称和数据源名修正,修正维度及指标字段名称
- 预警工作台页面UI细节优化,按钮行内样式调整,表格列项及排序修正
- 优化员工综合预警表格显示,添加综合评估得分和预警等级颜色区分
- 统一部分样式格式,清理多余空行及缩进不一致问题
- 组织画像页面背景颜色设为#F2F3F7
- 预警工作台页面卡片背景色及字体颜色微调,提升界面视觉效果
huoyi 20 ore fa
parent
commit
507336941c

+ 3 - 1
src/views/portraitManagement/components/SearchBar.vue

@@ -143,7 +143,8 @@ const handleSelect = (item) => {
143 143
     const name = item.nickName
144 144
 
145 145
     personName.value = path.length > 0 ? `${path.join(' / ')} / ${name}` : name
146
-    curQuery.value = { personName: item.nickName,id:item.id }
146
+    
147
+    curQuery.value = { personName: item.nickName,id:item.userId }
147 148
     searchHandler(curQuery.value)
148 149
   } else {
149 150
     const path = item.path && item.path.length > 0 ? item.path : ((item.id || item.deptId) ? buildPathForNode(departments.value, item.deptId || item.id) || [] : [])
@@ -215,6 +216,7 @@ const selectTime = (t) => {
215 216
 
216 217
 const searchHandler = (query = {}) => {
217 218
   const queryParams = { ...getTimeRange(), ...query }
219
+  
218 220
   if (props.deptType === 'user') {
219 221
     if (queryParams.personName) {
220 222
       emit('search', queryParams)

+ 0 - 1
src/views/portraitManagement/components/whiteCard.vue

@@ -1,7 +1,6 @@
1 1
 <template>
2 2
   <div class="white-card" :style="{ background: bgColor }">
3 3
     <div class="card-title" v-if="title">
4
-      <span class="title-dot"></span>
5 4
       <span class="title-text">{{ title }}</span>
6 5
     </div>
7 6
     <div class="card-body">

+ 1 - 1
src/views/portraitManagement/employeeProfile/index.vue

@@ -68,7 +68,7 @@
68 68
                   <div class="info-item-value">
69 69
                     {{ portrait.qualificationLevelText || '-' }}
70 70
                     <span class="info-item-tag" style="margin-left: 10px;margin-top: 2px;"
71
-                      v-if="!!portrait.xrayOperatorStarttime || portrait.postNames.includes('X射线安检仪操作岗位')">X射线安检仪操作岗位</span>
71
+                      v-if="!!portrait.xrayOperatorStarttime || portrait?.postNames?.includes('X射线安检仪操作岗位')">X射线安检仪操作岗位</span>
72 72
                   </div>
73 73
                 </div>
74 74
               </div>

+ 150 - 0
src/views/portraitManagement/organProfile/components/RankList.vue

@@ -0,0 +1,150 @@
1
+<template>
2
+  <div class="rank-list">
3
+    <div class="rank-avatar-row">
4
+      <div class="rank-avatar-item" v-for="item in podiumOrder" :key="item.rank">
5
+        <div class="rank-avatar-wrapper" :class="'rank-pos-' + item.rank">
6
+          <div class="rank-avatar" :style="{ background: item.color }">{{ item.name.slice(-2) }}</div>
7
+          <span class="rank-badge">{{ item.rank }}</span>
8
+        </div>
9
+        <div class="rank-name">{{ item.name }}</div>
10
+        <div class="rank-num">{{ item.num }}</div>
11
+      </div>
12
+    </div>
13
+    <div class="rank-table">
14
+      <div class="rank-tr rank-th">
15
+        <span>排名</span><span>姓名</span><span>{{ numLabel }}</span>
16
+      </div>
17
+      <div class="rank-tr" v-for="(item, i) in list" :key="i">
18
+        <span>{{ i + 1 }}</span>
19
+        <span>{{ item.name }}</span>
20
+        <span>{{ item.num }}</span>
21
+      </div>
22
+    </div>
23
+  </div>
24
+</template>
25
+
26
+<script setup>
27
+import { computed } from 'vue'
28
+
29
+const props = defineProps({
30
+  top3: { type: Array, default: () => [] },
31
+  list: { type: Array, default: () => [] },
32
+  numLabel: { type: String, default: '问题数' }
33
+})
34
+
35
+// 领奖台顺序:第2名(左)、第1名(中)、第3名(右)
36
+const podiumOrder = computed(() => {
37
+  if (props.top3.length < 3) return props.top3
38
+  return [
39
+    { ...props.top3[1], rank: 2 },
40
+    { ...props.top3[0], rank: 1 },
41
+    { ...props.top3[2], rank: 3 }
42
+  ]
43
+})
44
+</script>
45
+
46
+<style lang="scss" scoped>
47
+.rank-list {
48
+  .rank-avatar-row {
49
+    display: flex;
50
+    justify-content: center;
51
+    gap: 20px;
52
+    margin-top: 15px;
53
+    margin-bottom: 12px;
54
+
55
+    .rank-avatar-item {
56
+      display: flex;
57
+      flex-direction: column;
58
+      align-items: center;
59
+      gap: 6px;
60
+
61
+      &:nth-child(2) {
62
+        transform: translateY(-10px);
63
+      }
64
+
65
+      .rank-avatar-wrapper {
66
+        position: relative;
67
+        display: inline-flex;
68
+        align-items: center;
69
+        justify-content: center;
70
+        border-radius: 50%;
71
+
72
+        &.rank-pos-1 {
73
+          border: 3px solid #fbbf24;
74
+          .rank-badge { background: #fbbf24; }
75
+        }
76
+
77
+        &.rank-pos-2 {
78
+          border: 3px solid #94a3b8;
79
+          .rank-badge { background: #94a3b8; }
80
+        }
81
+
82
+        &.rank-pos-3 {
83
+          border: 3px solid #fb923c;
84
+          .rank-badge { background: #fb923c; }
85
+        }
86
+
87
+        .rank-avatar {
88
+          width: 44px;
89
+          height: 44px;
90
+          border-radius: 50%;
91
+          display: flex;
92
+          align-items: center;
93
+          justify-content: center;
94
+          color: #fff;
95
+          font-size: 16px;
96
+          font-weight: bold;
97
+        }
98
+
99
+        .rank-badge {
100
+          position: absolute;
101
+          bottom: -8px;
102
+          left: 50%;
103
+          transform: translateX(-50%);
104
+          width: 12px;
105
+          height: 12px;
106
+          border-radius: 50%;
107
+          display: flex;
108
+          align-items: center;
109
+          justify-content: center;
110
+          font-size: 11px;
111
+          font-weight: bold;
112
+          color: #fff;
113
+        }
114
+      }
115
+
116
+      .rank-name {
117
+        font-size: 12px;
118
+        color: #475569;
119
+      }
120
+
121
+      .rank-num {
122
+        font-size: 18px;
123
+        color: #1e293b;
124
+        font-weight: bold;
125
+      }
126
+    }
127
+  }
128
+
129
+  .rank-table {
130
+    .rank-tr {
131
+      display: flex;
132
+      padding: 5px 0;
133
+      font-size: 12px;
134
+      color: #64748b;
135
+      border-bottom: 1px solid #e2e8f0;
136
+
137
+      span {
138
+        flex: 1;
139
+        text-align: center;
140
+      }
141
+    }
142
+
143
+    .rank-th {
144
+      color: #1e293b;
145
+      font-weight: bold;
146
+      border-bottom: 2px solid #cbd5e1;
147
+    }
148
+  }
149
+}
150
+</style>

+ 39 - 235
src/views/portraitManagement/organProfile/index.vue

@@ -4,7 +4,7 @@
4 4
     <!-- 顶部指标卡片 -->
5 5
     <div class="metric-row">
6 6
       <div class="metric-card" v-for="(m, i) in metricCards" :key="i" :style="{ background: m.bg }">
7
-        <div class="metric-title">{{ m.title }}</div>
7
+        <div class="metric-title" :style="{ color: m.color }">{{ m.title }}</div>
8 8
         <div class="metric-value" :style="{ color: m.color }">{{ m.value }}</div>
9 9
         <div class="metric-change-row">
10 10
           <div class="metric-change-info">
@@ -18,12 +18,12 @@
18 18
       </div>
19 19
       <div class="metric-side-cards">
20 20
         <div class="metric-card metric-warning-top">
21
-          <div class="metric-title">锐甲安语—自愿报告系统</div>
22
-          <div class="metric-value" style="color:#fff">3</div>
21
+          <div class="metric-title" style="color:#507AFC">锐甲安语—自愿报告系统</div>
22
+          <div class="metric-value" style="color:#507AFC">3</div>
23 23
         </div>
24 24
         <div class="metric-card metric-warning-bottom">
25
-          <div class="metric-title">部门亚健康人员</div>
26
-          <div class="metric-value" style="color:#fff">147</div>
25
+          <div class="metric-title" style="color:#E41754">部门亚健康人员</div>
26
+          <div class="metric-value" style="color:#E41754">147</div>
27 27
         </div>
28 28
       </div>
29 29
     </div>
@@ -33,80 +33,80 @@
33 33
       <div class="charts-col charts-col-main">
34 34
         <!-- 第一行 -->
35 35
         <div class="charts-grid charts-grid-2">
36
-          <WhiteCard title="监察问题统计" bgColor="#dbeafe">
36
+          <WhiteCard title="监察问题统计" bgColor="#FFF4E4">
37 37
             <div ref="supervisionLineRef" class="chart-box" />
38 38
           </WhiteCard>
39
-          <WhiteCard title="问题类型分布" bgColor="#dbeafe">
39
+          <WhiteCard title="问题类型分布" bgColor="#FFF4E4">
40 40
             <div ref="problemTypeRef" class="chart-box" />
41 41
           </WhiteCard>
42 42
         </div>
43 43
         <!-- 第二行 -->
44 44
         <div class="charts-grid charts-grid-2">
45
-          <WhiteCard title="班组问题统计(监察)" bgColor="#dcfce7">
45
+          <WhiteCard title="班组问题统计(监察)" bgColor="#FFF4E4">
46 46
             <div ref="teamSupervisionRef" class="chart-box" />
47 47
           </WhiteCard>
48
-          <WhiteCard title="区域问题占比(监察)" bgColor="#fef3c7">
48
+          <WhiteCard title="区域问题占比(监察)" bgColor="#FFF4E4">
49 49
             <div ref="areaPieRef" class="chart-box" />
50 50
           </WhiteCard>
51 51
         </div>
52 52
         <!-- 第三行 -->
53 53
         <div class="charts-grid charts-grid-2">
54
-          <WhiteCard title="班组问题统计(实时)" bgColor="#dcfce7">
54
+          <WhiteCard title="班组问题统计(实时)" bgColor="#E4F0E5">
55 55
             <div ref="teamRealtimeRef" class="chart-box" />
56 56
           </WhiteCard>
57
-          <WhiteCard title="实时质控拦截情况" bgColor="#dcfce7">
57
+          <WhiteCard title="实时质控拦截情况" bgColor="#E4F0E5">
58 58
             <div ref="realtimeLineRef" class="chart-box" />
59 59
           </WhiteCard>
60 60
         </div>
61 61
         <!-- 第四行 -->
62 62
         <div class="charts-grid charts-grid-2">
63
-          <WhiteCard title="实时质控开机年龄分布" bgColor="#dbeafe">
63
+          <WhiteCard title="实时质控开机年龄分布" bgColor="#E4F0E5">
64 64
             <div ref="yearRingRef" class="chart-box" />
65 65
           </WhiteCard>
66
-          <WhiteCard title="实时质控围难易度" bgColor="#dbeafe">
66
+          <WhiteCard title="实时质控图像难易度" bgColor="#E4F0E5">
67 67
             <div ref="difficultyRef" class="chart-box" />
68 68
           </WhiteCard>
69 69
         </div>
70 70
         <!-- 实时质控开机年限分布 -->
71 71
         <div class="charts-grid charts-grid-2">
72
-          <WhiteCard title="实时质控开机年限分布" bgColor="#dcfce7">
72
+          <WhiteCard title="实时质控开机年限分布" bgColor="#E4F0E5">
73 73
             <div ref="yearLimitRef" class="chart-box" />
74 74
           </WhiteCard>
75
-          <WhiteCard title="实时拦截物品汇总" bgColor="#dbeafe">
75
+          <WhiteCard title="实时拦截物品汇总" bgColor="#E4F0E5">
76 76
             <div ref="interceptItemsRef" class="chart-box" />
77 77
           </WhiteCard>
78 78
         </div>
79 79
         <!-- 第五行 -->
80 80
         <div class="charts-grid charts-grid-2">
81 81
 
82
-          <WhiteCard title="服务巡查" bgColor="#dbeafe">
82
+          <WhiteCard title="服务巡查" bgColor="#E4EBFF">
83 83
             <div ref="servicePatrolRef" class="chart-box" />
84 84
           </WhiteCard>
85
-          <WhiteCard title="服务巡查" bgColor="#e8eaf6">
85
+          <WhiteCard title="服务巡查" bgColor="#E4EBFF">
86 86
             <div ref="servicePatrolLineRef" class="chart-box" />
87 87
           </WhiteCard>
88 88
         </div>
89 89
         <!-- 第六行 -->
90 90
         <div class="charts-grid charts-grid-2">
91
-          <WhiteCard title="投诉涉及班组情况" bgColor="#fce4ec">
91
+          <WhiteCard title="投诉涉及班组情况" bgColor="#F0ACA1">
92 92
             <div ref="complaintTeamRef" class="chart-box" />
93 93
           </WhiteCard>
94
-          <WhiteCard title="不安全事件发生对比" bgColor="#dbeafe">
94
+          <WhiteCard title="不安全事件发生对比" bgColor="#DCDCDF">
95 95
             <div ref="unsafeCompareRef" class="chart-box" />
96 96
           </WhiteCard>
97 97
         </div>
98 98
         <!-- 第七行 -->
99 99
         <div class="charts-grid charts-grid-2">
100
-          <WhiteCard title="亚健康人数占比" bgColor="#fef3c7">
100
+          <WhiteCard title="亚健康人数占比" bgColor="#FFDBA1">
101 101
             <div ref="subhealthPieRef" class="chart-box" />
102 102
           </WhiteCard>
103
-          <WhiteCard title="各班组健康与亚健康比例" bgColor="#fef3c7">
103
+          <WhiteCard title="各班组健康与亚健康比例" bgColor="#FFDBA1">
104 104
             <div ref="healthRatioRef" class="chart-box" />
105 105
           </WhiteCard>
106 106
         </div>
107 107
         <!-- 第八行 -->
108 108
         <div class="charts-grid charts-grid-1">
109
-          <WhiteCard title="旅检三部人员年龄分布表" bgColor="#dbeafe">
109
+          <WhiteCard title="旅检三部人员年龄分布表" bgColor="#FFFFFF">
110 110
             <div ref="ageDistRef" class="chart-box-wide" />
111 111
           </WhiteCard>
112 112
         </div>
@@ -114,101 +114,17 @@
114 114
 
115 115
       <!-- 右侧排行榜 -->
116 116
       <div class="charts-col-side">
117
-        <WhiteCard title="监察问题(总)" bgColor="#f0f4ff">
118
-          <div class="rank-list">
119
-            <div class="rank-avatar-row">
120
-              <div class="rank-avatar-item" v-for="(item, i) in superVisionTop3" :key="i">
121
-                <div class="rank-avatar-wrapper" :class="'rank-pos-' + (i + 1)">
122
-                  <div class="rank-avatar" :style="{ background: item.color }">{{ item.name.slice(-2) }}</div>
123
-                  <span class="rank-badge">{{ i + 1 }}</span>
124
-                </div>
125
-                <div class="rank-name">{{ item.name }}</div>
126
-                <div class="rank-num">{{ item.num }}</div>
127
-              </div>
128
-            </div>
129
-            <div class="rank-table">
130
-              <div class="rank-tr rank-th">
131
-                <span>排名</span><span>姓名</span><span>问题数</span>
132
-              </div>
133
-              <div class="rank-tr" v-for="(item, i) in superVisionList" :key="i">
134
-                <span>{{ i + 1 }}</span>
135
-                <span>{{ item.name }}</span>
136
-                <span>{{ item.num }}</span>
137
-              </div>
138
-            </div>
139
-          </div>
117
+        <WhiteCard title="监察问题(总)" bgColor="#FFF4E4">
118
+          <RankList :top3="superVisionTop3" :list="superVisionList" num-label="问题数" />
140 119
         </WhiteCard>
141
-        <WhiteCard title="实时漏洞检情况(总)" bgColor="#f0fdf4">
142
-          <div class="rank-list">
143
-            <div class="rank-avatar-row">
144
-              <div class="rank-avatar-item" v-for="(item, i) in vulnTop3" :key="i">
145
-                <div class="rank-avatar-wrapper" :class="'rank-pos-' + (i + 1)">
146
-                  <div class="rank-avatar" :style="{ background: item.color }">{{ item.name.slice(-2) }}</div>
147
-                  <span class="rank-badge">{{ i + 1 }}</span>
148
-                </div>
149
-                <div class="rank-name">{{ item.name }}</div>
150
-                <div class="rank-num">{{ item.num }}</div>
151
-              </div>
152
-            </div>
153
-            <div class="rank-table">
154
-              <div class="rank-tr rank-th">
155
-                <span>排名</span><span>姓名</span><span>问题数</span>
156
-              </div>
157
-              <div class="rank-tr" v-for="(item, i) in vulnList" :key="i">
158
-                <span>{{ i + 1 }}</span>
159
-                <span>{{ item.name }}</span>
160
-                <span>{{ item.num }}</span>
161
-              </div>
162
-            </div>
163
-          </div>
120
+        <WhiteCard title="实时漏检情况(总)" bgColor="#E4F0E5">
121
+          <RankList :top3="vulnTop3" :list="vulnList" num-label="问题数" />
164 122
         </WhiteCard>
165
-        <WhiteCard title="航站楼加分" bgColor="#eff6ff">
166
-          <div class="rank-list">
167
-            <div class="rank-avatar-row">
168
-              <div class="rank-avatar-item" v-for="(item, i) in bonusTop3" :key="i">
169
-                <div class="rank-avatar-wrapper" :class="'rank-pos-' + (i + 1)">
170
-                  <div class="rank-avatar" :style="{ background: item.color }">{{ item.name.slice(-2) }}</div>
171
-                  <span class="rank-badge">{{ i + 1 }}</span>
172
-                </div>
173
-                <div class="rank-name">{{ item.name }}</div>
174
-                <div class="rank-num">{{ item.num }}</div>
175
-              </div>
176
-            </div>
177
-            <div class="rank-table">
178
-              <div class="rank-tr rank-th">
179
-                <span>排名</span><span>姓名</span><span>加分</span>
180
-              </div>
181
-              <div class="rank-tr" v-for="(item, i) in bonusList" :key="i">
182
-                <span>{{ i + 1 }}</span>
183
-                <span>{{ item.name }}</span>
184
-                <span>{{ item.num }}</span>
185
-              </div>
186
-            </div>
187
-          </div>
123
+        <WhiteCard title="航站楼加分" bgColor="#E4EBFF">
124
+          <RankList :top3="bonusTop3" :list="bonusList" num-label="加分" />
188 125
         </WhiteCard>
189
-        <WhiteCard title="查获数量" bgColor="#f0f4ff">
190
-          <div class="rank-list">
191
-            <div class="rank-avatar-row">
192
-              <div class="rank-avatar-item" v-for="(item, i) in seizureTop3" :key="i">
193
-                <div class="rank-avatar-wrapper" :class="'rank-pos-' + (i + 1)">
194
-                  <div class="rank-avatar" :style="{ background: item.color }">{{ item.name.slice(-2) }}</div>
195
-                  <span class="rank-badge">{{ i + 1 }}</span>
196
-                </div>
197
-                <div class="rank-name">{{ item.name }}</div>
198
-                <div class="rank-num">{{ item.num }}</div>
199
-              </div>
200
-            </div>
201
-            <div class="rank-table">
202
-              <div class="rank-tr rank-th">
203
-                <span>排名</span><span>姓名</span><span>查获数</span>
204
-              </div>
205
-              <div class="rank-tr" v-for="(item, i) in seizureList" :key="i">
206
-                <span>{{ i + 1 }}</span>
207
-                <span>{{ item.name }}</span>
208
-                <span>{{ item.num }}</span>
209
-              </div>
210
-            </div>
211
-          </div>
126
+        <WhiteCard title="查获数量" bgColor="#FFFFFF">
127
+          <RankList :top3="seizureTop3" :list="seizureList" num-label="查获数" />
212 128
         </WhiteCard>
213 129
       </div>
214 130
     </div>
@@ -221,15 +137,16 @@ import { ref, computed, onMounted } from 'vue'
221 137
 import { useECharts } from '@/hooks/useEcharts'
222 138
 import WhiteCard from '../components/whiteCard.vue'
223 139
 import Page from '../components/page.vue'
140
+import RankList from './components/RankList.vue'
224 141
 import * as echarts from 'echarts'
225 142
 
226 143
 // ─── 顶部指标卡片 ───────────────────────────────
227 144
 const metricCards = ref([
228
-  { title: '监察问题数(本月)', value: '11', change: '57.69%', changeType: 'down', changeColor: '#ef4444', color: '#f59e0b', bg: '#dbeafe', sparkColor: '#3b82f6' },
229
-  { title: '实时质控数(本月)', value: '21', change: '56.25%', changeType: 'down', changeColor: '#ef4444', color: '#22c55e', bg: '#dcfce7', sparkColor: '#22c55e' },
230
-  { title: '服务巡查(本月)', value: '4', change: '0%', changeType: 'flat', changeColor: '#6b7280', color: '#3b82f6', bg: '#dbeafe', sparkColor: '#3b82f6' },
231
-  { title: '投诉情况(本月)', value: '1', change: '88.89%', changeType: 'down', changeColor: '#ef4444', color: '#ef4444', bg: '#fce4ec', sparkColor: '#ef4444' },
232
-  { title: '不安全事件发生次数(今年)', value: '3', change: '57.14%', changeType: 'down', changeColor: '#ef4444', color: '#ffffff', bg: '#6b7280', sparkColor: '#9ca3af' },
145
+  { title: '监察问题数(本月)', value: '11', change: '57.69%', changeType: 'down', changeColor: '#ef4444', color: '#f59e0b', bg: '#FFF4E4', sparkColor: '#3b82f6' },
146
+  { title: '实时质控数(本月)', value: '21', change: '56.25%', changeType: 'down', changeColor: '#ef4444', color: '#22c55e', bg: '#E4F0E5', sparkColor: '#22c55e' },
147
+  { title: '服务巡查(本月)', value: '4', change: '0%', changeType: 'flat', changeColor: '#6b7280', color: '#3b82f6', bg: '#E6E8FF', sparkColor: '#3b82f6' },
148
+  { title: '投诉情况(本月)', value: '1', change: '88.89%', changeType: 'down', changeColor: '#ef4444', color: '#ef4444', bg: '#F0ACA1', sparkColor: '#ef4444' },
149
+  { title: '不安全事件发生次数(今年)', value: '3', change: '57.14%', changeType: 'down', changeColor: '#ef4444', color: '#ffffff', bg: '#A5A5A5', sparkColor: '#9ca3af' },
233 150
 ])
234 151
 
235 152
 // ─── 图表 ref ────────────────────────────────────
@@ -519,6 +436,7 @@ onMounted(() => {
519 436
 
520 437
 <style lang="scss" scoped>
521 438
 .org-profile {
439
+  background-color: #F2F3F7;
522 440
   padding: 15px;
523 441
   box-sizing: border-box;
524 442
   min-height: calc(100vh - 90px);
@@ -635,11 +553,11 @@ onMounted(() => {
635 553
     }
636 554
 
637 555
     .metric-warning-top {
638
-      background: linear-gradient(135deg, #f59e0b, #d97706) !important;
556
+      background: #F2E5FF !important;
639 557
     }
640 558
 
641 559
     .metric-warning-bottom {
642
-      background: linear-gradient(135deg, #fbbf24, #f59e0b) !important;
560
+      background: #FFDBA1 !important;
643 561
     }
644 562
   }
645 563
 
@@ -688,120 +606,6 @@ onMounted(() => {
688 606
     }
689 607
   }
690 608
 
691
-  // ── 排行榜 ──
692
-  .rank-list {
693
-    .rank-avatar-row {
694
-      display: flex;
695
-      justify-content: center;
696
-      gap: 20px;
697
-      margin-top: 15px;
698
-      margin-bottom: 12px;
699
-
700
-      .rank-avatar-item {
701
-        display: flex;
702
-        flex-direction: column;
703
-        align-items: center;
704
-        gap: 6px;
705
-
706
-        &:nth-child(2) {
707
-          transform: translateY(-10px);
708
-        }
709
-
710
-        .rank-avatar-wrapper {
711
-          position: relative;
712
-          display: inline-flex;
713
-          align-items: center;
714
-          justify-content: center;
715
-          border-radius: 50%;
716
-
717
-
718
-          &.rank-pos-1 {
719
-            border: 3px solid #94a3b8;
720
-
721
-            .rank-badge {
722
-              background: #94a3b8;
723
-            }
724
-
725
-          }
726
-
727
-          &.rank-pos-2 {
728
-            border: 3px solid #fbbf24;
729
-
730
-            .rank-badge {
731
-              background: #fbbf24;
732
-            }
733
-          }
734
-
735
-          &.rank-pos-3 {
736
-            border: 3px solid #fb923c;
737
-
738
-            .rank-badge {
739
-              background: #fb923c;
740
-            }
741
-          }
742
-
743
-          .rank-avatar {
744
-            width: 44px;
745
-            height: 44px;
746
-            border-radius: 50%;
747
-            display: flex;
748
-            align-items: center;
749
-            justify-content: center;
750
-            color: #fff;
751
-            font-size: 16px;
752
-            font-weight: bold;
753
-          }
754
-
755
-          .rank-badge {
756
-            position: absolute;
757
-            bottom: -8px;
758
-            left: 50%;
759
-            transform: translateX(-50%);
760
-            width: 12px;
761
-            height: 12px;
762
-            border-radius: 50%;
763
-            display: flex;
764
-            align-items: center;
765
-            justify-content: center;
766
-            font-size: 11px;
767
-            font-weight: bold;
768
-            color: #fff;
769
-          }
770
-        }
771
-
772
-        .rank-name {
773
-          font-size: 12px;
774
-          color: #475569;
775
-        }
776 609
 
777
-        .rank-num {
778
-          font-size: 18px;
779
-          color: '#1e293b';
780
-          font-weight: bold;
781
-        }
782
-      }
783
-    }
784
-
785
-    .rank-table {
786
-      .rank-tr {
787
-        display: flex;
788
-        padding: 5px 0;
789
-        font-size: 12px;
790
-        color: #64748b;
791
-        border-bottom: 1px solid #e2e8f0;
792
-
793
-        span {
794
-          flex: 1;
795
-          text-align: center;
796
-        }
797
-      }
798
-
799
-      .rank-th {
800
-        color: '#1e293b';
801
-        font-weight: bold;
802
-        border-bottom: 2px solid #cbd5e1;
803
-      }
804
-    }
805
-  }
806 610
 }
807 611
 </style>

+ 6 - 21
src/views/warningManage/redLineWarning/index.vue

@@ -62,9 +62,9 @@
62 62
                         </el-table-column>
63 63
                         <el-table-column prop="deptName" label="所属部门" />
64 64
                         <el-table-column prop="eventTime" label="事件时间" sortable width="180" />
65
-                        <el-table-column prop="dimName" label="维度名称" />
66
-                        <el-table-column prop="secondIndicator" label="二级指标名称" />
67
-                        <el-table-column prop="deductionTotal" label="扣分分值合计" sortable />
65
+                        <el-table-column prop="dimensionName" label="维度名称" />
66
+                        <el-table-column prop="level2Name" label="二级指标名称" />
67
+                        <el-table-column prop="totalScore" label="扣分分值合计" sortable />
68 68
                         <el-table-column prop="occurrenceCount" label="发生次数" sortable />
69 69
                         <el-table-column prop="overallScore" label="预警等级">
70 70
                             <template #default="{ row }">
@@ -77,7 +77,7 @@
77 77
                                 <span v-else class="status-warning">正常范围</span>
78 78
                             </template>
79 79
                         </el-table-column>
80
-                        <el-table-column prop="coreRisk" label="核心风险" />
80
+                        <el-table-column prop="coreRisks" label="核心风险" />
81 81
                         <el-table-column prop="statusLabel" label="状态标签">
82 82
                             <template #default="{ row }">
83 83
                                 <span v-if="row.overallScore < 75" style="color:#b91c1c;"><i class="fas fa-bell"></i>
@@ -151,7 +151,7 @@ const coreRisksOrOutstandingAchievementsList = [
151 151
     "临近预警线,服务巡查扣分1次"
152 152
 ]
153 153
 
154
-const dimNames = ["安全管理", "服务质量", "运行效率", "队伍建设"]
154
+
155 155
 const indicatorNames = ["安全违规次数", "旅客投诉率", "安检差错率", "培训合格率", "操作规范度"]
156 156
 const deductionScores = [2, 5, 3, 1, 4]
157 157
 const occurrenceCounts = [1, 2, 3, 1, 2]
@@ -162,21 +162,6 @@ const queryParams = reactive({
162 162
     pageSize: 10
163 163
 })
164 164
 
165
-for (let i = 0; i < newNames.length; i++) {
166
-    employeesData.value.push({
167
-        userId: String(10021 + i),
168
-        nickName: newNames[i],
169
-        deptName: deptList[i % deptList.length],
170
-        eventTime: `2026-0${(i % 9) + 1}-${String((i * 3 + 10) % 28 + 1).padStart(2, '0')}`,
171
-        overallScore: scores[i % scores.length],
172
-        dimName: dimNames[i % dimNames.length],
173
-        secondIndicator: indicatorNames[i % indicatorNames.length],
174
-        deductionTotal: deductionScores[i % deductionScores.length],
175
-        occurrenceCount: occurrenceCounts[i % occurrenceCounts.length],
176
-        coreRisk: coreRisksOrOutstandingAchievementsList[i % coreRisksOrOutstandingAchievementsList.length],
177
-        statusLabel: scores[i % scores.length] < 75 ? '1' : scores[i % scores.length] >= 90 ? '2' : '3'
178
-    })
179
-}
180 165
 
181 166
 // 将组织架构数据转换为树形数据
182 167
 const transformCascadeData = (nodes) => {
@@ -226,7 +211,7 @@ const getSelectedInfo = (selectedValue) => {
226 211
 }
227 212
 
228 213
 const allFilteredEmployees = computed(() => {
229
-    let result = employeesData.value.ledgerWarningDetailItemList || []
214
+    let result = employeesData.value || []
230 215
 
231 216
     // 预警等级筛选
232 217
     if (selectedAlertLevel.value) {

+ 87 - 164
src/views/warningManage/warningPage/index.vue

@@ -3,8 +3,7 @@
3 3
     <div class="header">
4 4
       <div class="title-section">
5 5
         <h1>
6
-          <i class="fas fa-shield-alt" style="color: #2c5282; margin-right: 8px"></i
7
-          >综合预警工作台
6
+          <i class="fas fa-shield-alt" style="color: #2c5282; margin-right: 8px"></i>综合预警工作台
8 7
         </h1>
9 8
         <p>员工综合评估(<75分红色预警 | ≥90分优秀)</p>
10 9
       </div>
@@ -20,75 +19,31 @@
20 19
 
21 20
     <div class="filter-bar">
22 21
       <div class="time-range">
23
-        <button
24
-          class="time-btn"
25
-          :class="{ active: activeRange === 'week' }"
26
-          @click="setActiveRange('week')"
27
-        >
22
+        <button class="time-btn" :class="{ active: activeRange === 'week' }" @click="setActiveRange('week')">
28 23
           近一周
29 24
         </button>
30
-        <button
31
-          class="time-btn"
32
-          :class="{ active: activeRange === 'month' }"
33
-          @click="setActiveRange('month')"
34
-        >
25
+        <button class="time-btn" :class="{ active: activeRange === 'month' }" @click="setActiveRange('month')">
35 26
           近一月
36 27
         </button>
37
-        <button
38
-          class="time-btn"
39
-          :class="{ active: activeRange === 'quarter' }"
40
-          @click="setActiveRange('quarter')"
41
-        >
28
+        <button class="time-btn" :class="{ active: activeRange === 'quarter' }" @click="setActiveRange('quarter')">
42 29
           近三月
43 30
         </button>
44
-        <button
45
-          class="time-btn"
46
-          :class="{ active: activeRange === 'year' }"
47
-          @click="setActiveRange('year')"
48
-        >
31
+        <button class="time-btn" :class="{ active: activeRange === 'year' }" @click="setActiveRange('year')">
49 32
           近一年
50 33
         </button>
51 34
         <div class="custom-date">
52
-          <el-date-picker
53
-            v-model="startDate"
54
-            type="date"
55
-            placeholder="开始日期"
56
-            style="width: 150px"
57
-          />
35
+          <el-date-picker v-model="startDate" type="date" placeholder="开始日期" style="width: 150px" />
58 36
           <span style="margin: 0 8px">至</span>
59
-          <el-date-picker
60
-            v-model="endDate"
61
-            type="date"
62
-            placeholder="结束日期"
63
-            style="width: 150px"
64
-          />
37
+          <el-date-picker v-model="endDate" type="date" placeholder="结束日期" style="width: 150px" />
65 38
         </div>
66
-        <el-tree-select
67
-          v-model="selectedOrg"
68
-          :data="cascadeOptions"
69
-          :props="{ label: 'label', value: 'value', children: 'children' }"
70
-          node-key="value"
71
-          placeholder="组织架构/员工"
72
-          clearable
73
-          filterable
74
-          check-strictly
75
-          style="width: 480px"
76
-        />
39
+        <el-tree-select v-model="selectedOrg" :data="cascadeOptions"
40
+          :props="{ label: 'label', value: 'value', children: 'children' }" node-key="value" placeholder="组织架构/员工"
41
+          clearable filterable check-strictly style="width: 480px" />
77 42
       </div>
78 43
       <div class="filter-group">
79
-        <el-select
80
-          v-model="selectedAlertLevel"
81
-          placeholder="预警等级"
82
-          clearable
83
-          style="width: 250px"
84
-        >
44
+        <el-select v-model="selectedAlertLevel" placeholder="预警等级" clearable style="width: 250px">
85 45
           <el-option label="全部" value=""></el-option>
86
-          <el-option
87
-            v-for="item in alert_level"
88
-            :key="item.value"
89
-            :label="item.label"
90
-            :value="item.value"
91
-          />
46
+          <el-option v-for="item in alert_level" :key="item.value" :label="item.label" :value="item.value" />
92 47
         </el-select>
93 48
         <el-button type="primary" @click="handleSearch">搜索</el-button>
94 49
         <el-button @click="handleReset">重置</el-button>
@@ -97,12 +52,8 @@
97 52
 
98 53
     <div class="cards-container">
99 54
       <div class="cards-grid" style="overflow-x: auto; white-space: nowrap">
100
-        <div
101
-          class="card"
102
-          v-for="(item, index) in summaryCards"
103
-          :key="index"
104
-          style="display: inline-block; width: 200px; flex-shrink: 0"
105
-        >
55
+        <div class="card" v-for="(item, index) in summaryCards" :key="index"
56
+          style="display: inline-block; width: 200px; flex-shrink: 0">
106 57
           <div class="card-header">
107 58
             <i :class="item.icon"></i>
108 59
             <h3>{{ item.title }}</h3>
@@ -116,28 +67,20 @@
116 67
     <div class="employee-section">
117 68
       <div class="section-title">
118 69
         <i class="fas fa-users" style="color: #dc2626"></i> 员工综合预警
119
-        <span
120
-          style="
70
+        <span style="
121 71
             font-size: 0.7rem;
122 72
             background: #eef2ff;
123 73
             padding: 4px 12px;
124 74
             border-radius: 30px;
125 75
             margin-left: 12px;
126
-          "
127
-        >
76
+          ">
128 77
           评分依据:员工配分表
129 78
         </span>
130 79
       </div>
131 80
       <div class="employee-card">
132 81
         <div style="overflow-x: auto">
133
-          <el-table
134
-            :data="filteredEmployees"
135
-            :row-class-name="getRowClass"
136
-            style="width: 100%"
137
-            border
138
-            stripe
139
-            @sort-change="handleSortChange"
140
-          >
82
+          <el-table :data="filteredEmployees" :row-class-name="getRowClass" style="width: 100%" border stripe
83
+            @sort-change="handleSortChange">
141 84
             <el-table-column prop="userId" label="员工ID" />
142 85
             <el-table-column prop="nickName" label="姓名">
143 86
               <template #default="{ row }">
@@ -145,46 +88,32 @@
145 88
               </template>
146 89
             </el-table-column>
147 90
             <el-table-column prop="deptName" label="所属部门" />
148
-            <el-table-column
149
-              prop="eventTime"
150
-              label="事件时间"
151
-              sortable="custom"
152
-              width="180"
153
-            />
154
-            <el-table-column prop="dimName" label="维度名称" />
155
-            <el-table-column prop="secondIndicator" label="二级指标名称" />
156
-            <el-table-column
157
-              prop="deductionTotal"
158
-              label="扣分分值合计"
159
-              sortable="custom"
160
-            />
161
-            <el-table-column prop="occurrenceCount" label="发生次数" sortable="custom" />
91
+            <el-table-column prop="eventTime" label="事件时间" sortable width="180" />
92
+            <el-table-column prop="overallScore" label="综合评估得分" sortable>
93
+              <template #default="{ row }">
94
+                <span v-if="row.overallScore < 75" class="score-danger">{{ row.overallScore }} 分</span>
95
+                <span v-else-if="row.overallScore >= 90" class="score-excellent">{{ row.overallScore }}
96
+                  分</span>
97
+                <span v-else style="font-weight:600;">{{ row.overallScore }} 分</span>
98
+              </template>
99
+            </el-table-column>
162 100
             <el-table-column prop="overallScore" label="预警等级">
163 101
               <template #default="{ row }">
164
-                <span
165
-                  v-if="row.overallScore < 75"
166
-                  class="status-badge"
167
-                  style="animation: subtlePulse 1s infinite"
168
-                  ><i class="fas fa-exclamation-triangle"></i> 红色预警</span
169
-                >
170
-                <span
171
-                  v-else-if="row.overallScore >= 90"
172
-                  class="status-excellent"
173
-                  style="background: #d1fae5; color: #065f46"
174
-                  ><i class="fas fa-star"></i> 优秀标杆</span
175
-                >
102
+                <span v-if="row.overallScore < 75" class="status-badge" style="animation: subtlePulse 1s infinite;"><i
103
+                    class="fas fa-exclamation-triangle"></i> 红色预警</span>
104
+                <span v-else-if="row.overallScore >= 90" class="status-excellent"
105
+                  style="background:#d1fae5; color:#065f46;"><i class="fas fa-star"></i>
106
+                  优秀标杆</span>
176 107
                 <span v-else class="status-warning">正常范围</span>
177 108
               </template>
178 109
             </el-table-column>
179
-            <el-table-column prop="coreRisk" label="核心风险" />
110
+            <el-table-column prop="coreRisksOrOutstandingAchievements" label="核心风险/优秀事迹" />
180 111
             <el-table-column prop="statusLabel" label="状态标签">
181 112
               <template #default="{ row }">
182
-                <span v-if="row.overallScore < 75" style="color: #b91c1c"
183
-                  ><i class="fas fa-bell"></i> {{ getAlertLabel(row.statusLabel) }}</span
184
-                >
185
-                <span v-else-if="row.overallScore >= 90" style="color: #15803d"
186
-                  ><i class="fas fa-crown"></i> {{ getAlertLabel(row.statusLabel) }}</span
187
-                >
113
+                <span v-if="row.overallScore < 75" style="color:#b91c1c;"><i class="fas fa-bell"></i>
114
+                  {{ getAlertLabel(row.statusLabel) }}</span>
115
+                <span v-else-if="row.overallScore >= 90" style="color:#15803d;"><i class="fas fa-crown"></i> {{
116
+                  getAlertLabel(row.statusLabel) }}</span>
188 117
                 <span v-else>{{ getAlertLabel(row.statusLabel) }}</span>
189 118
               </template>
190 119
             </el-table-column>
@@ -194,17 +123,10 @@
194 123
               </template>
195 124
             </el-table-column>
196 125
           </el-table>
197
-          <el-pagination
198
-            v-show="total > 0"
199
-            :total="total"
200
-            v-model:current-page="queryParams.pageNum"
201
-            v-model:page-size="queryParams.pageSize"
202
-            :page-sizes="[10, 20, 50, 100]"
203
-            layout="total, sizes, prev, pager, next, jumper"
204
-            @size-change="handleSizeChange"
205
-            @current-change="handlePageChange"
206
-            style="margin-top: 16px; justify-content: flex-end"
207
-          />
126
+          <el-pagination v-show="total > 0" :total="total" v-model:current-page="queryParams.pageNum"
127
+            v-model:page-size="queryParams.pageSize" :page-sizes="[10, 20, 50, 100]"
128
+            layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
129
+            @current-change="handlePageChange" style="margin-top: 16px; justify-content: flex-end" />
208 130
         </div>
209 131
         <div class="warning-summary">
210 132
           <div>
@@ -381,7 +303,7 @@ for (let i = 0; i < newNames.length; i++) {
381 303
     occurrenceCount: occurrenceCounts[i % occurrenceCounts.length],
382 304
     coreRisk:
383 305
       coreRisksOrOutstandingAchievementsList[
384
-        i % coreRisksOrOutstandingAchievementsList.length
306
+      i % coreRisksOrOutstandingAchievementsList.length
385 307
       ],
386 308
     statusLabel:
387 309
       scores[i % scores.length] < 75 ? "1" : scores[i % scores.length] >= 90 ? "2" : "3",
@@ -838,76 +760,77 @@ watch(
838 760
 .search-btn:hover {
839 761
   background: #1d4ed8;
840 762
 }
763
+
841 764
 .cards-container {
842
-    width: 100%;
843
-    margin-bottom: 36px;
844
-    overflow-x: auto;
765
+  width: 100%;
766
+  margin-bottom: 36px;
767
+  overflow-x: auto;
845 768
 }
846 769
 
847 770
 .cards-grid {
848
-    display: flex;
771
+  display: flex;
849 772
 
850
-    gap: 16px;
851
-    flex-wrap: nowrap;
852
-    min-width: max-content;
773
+  gap: 16px;
774
+  flex-wrap: nowrap;
775
+  min-width: max-content;
853 776
 }
854 777
 
855 778
 .card {
856
-    background: #ffffff;
857
-    border-radius: 20px;
858
-    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.03), 0 1px 2px rgba(0, 0, 0, 0.05);
859
-    transition: all 0.2s;
860
-    border: 1px solid #eef2f6;
861
-    padding: 1rem 0.5rem;
862
-    display: flex;
863
-    flex-direction: column;
864
-    text-align: center;
865
-    min-width: 280px;
866
-    flex-shrink: 0;
779
+  background: #ffffff;
780
+  border-radius: 20px;
781
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.03), 0 1px 2px rgba(0, 0, 0, 0.05);
782
+  transition: all 0.2s;
783
+  border: 1px solid #eef2f6;
784
+  padding: 1rem 0.5rem;
785
+  display: flex;
786
+  flex-direction: column;
787
+  text-align: center;
788
+  min-width: 280px;
789
+  flex-shrink: 0;
867 790
 }
868 791
 
869 792
 .card:hover {
870
-    transform: translateY(-3px);
871
-    box-shadow: 0 12px 20px -10px rgba(0, 0, 0, 0.1);
872
-    border-color: #cbd5e1;
793
+  transform: translateY(-3px);
794
+  box-shadow: 0 12px 20px -10px rgba(0, 0, 0, 0.1);
795
+  border-color: #cbd5e1;
873 796
 }
874 797
 
875 798
 .card-header {
876
-    display: flex;
877
-    flex-direction: column;
878
-    align-items: center;
879
-    gap: 6px;
880
-    border-bottom: none;
881
-    padding-bottom: 0;
882
-    margin-bottom: 12px;
799
+  display: flex;
800
+  flex-direction: column;
801
+  align-items: center;
802
+  gap: 6px;
803
+  border-bottom: none;
804
+  padding-bottom: 0;
805
+  margin-bottom: 12px;
883 806
 }
884 807
 
885 808
 .card-header i {
886
-    font-size: 1.5rem;
887
-    color: #2563eb;
809
+  font-size: 1.5rem;
810
+  color: #2563eb;
888 811
 }
889 812
 
890 813
 .card-header h3 {
891
-    font-size: 0.85rem;
892
-    font-weight: 700;
893
-    margin: 0;
894
-    white-space: nowrap;
814
+  font-size: 0.85rem;
815
+  font-weight: 700;
816
+  margin: 0;
817
+  white-space: nowrap;
895 818
 }
896 819
 
897 820
 .card-badge {
898
-    font-size: 0.6rem;
899
-    background: #f1f5f9;
900
-    padding: 2px 8px;
901
-    border-radius: 30px;
902
-    margin-top: 4px;
903
-    display: inline-block;
821
+  font-size: 0.6rem;
822
+  background: #f1f5f9;
823
+  padding: 2px 8px;
824
+  border-radius: 30px;
825
+  margin-top: 4px;
826
+  display: inline-block;
904 827
 }
905 828
 
906 829
 .value-large {
907
-    font-size: 1.8rem;
908
-    font-weight: 800;
909
-    line-height: 1.2;
910
-    margin: 8px 0 4px 0;
830
+  font-size: 1.8rem;
831
+  font-weight: 800;
832
+  line-height: 1.2;
833
+  margin: 8px 0 4px 0;
911 834
 }
912 835
 
913 836
 .employee-section {