Explorar el Código

feat: 新增组织架构页面并优化员工详情页图表展示

1.  新增组织架构页面,支持部门人员树形浏览、搜索定位
2.  调整员工详情页雷达图图例位置和样式,简化图例文字
3.  更新成员岗位分布组件的图表配置和图例文案
huoyi hace 1 semana
padre
commit
f376f232b1

+ 6 - 0
src/pages.json

@@ -327,6 +327,12 @@
327 327
       }
328 328
     },
329 329
     {
330
+      "path": "pages/organizationStruct/index",
331
+      "style": {
332
+        "navigationBarTitleText": "组织架构"
333
+      }
334
+    },
335
+    {
330 336
       "path": "pages/inspectionChecklist/index",
331 337
       "style": {
332 338
         "navigationBarTitleText": "巡视检查列表"

+ 8 - 4
src/pages/components/MemberPositionDistribution.vue

@@ -74,7 +74,7 @@ export default {
74 74
           axisPointer: { type: 'shadow' }
75 75
         },
76 76
         legend: {
77
-          data: ['人数'],
77
+          data: ['职业资格等级'],
78 78
           textStyle: { color: '#666', fontSize: 10 },
79 79
           top: 0
80 80
         },
@@ -118,6 +118,7 @@ export default {
118 118
           }
119 119
         },
120 120
         series: [{
121
+          name: '职业资格等级',
121 122
           type: 'bar',
122 123
           data: this.chartsData.qualification.data,
123 124
           itemStyle: {
@@ -150,8 +151,9 @@ export default {
150 151
           axisPointer: { type: 'shadow' }
151 152
         },
152 153
         legend: {
153
-          data: ['人数'],
154
-          textStyle: { color: '#666', fontSize: 10 },
154
+          show: true,
155
+          data: ['开机年限'],
156
+          textStyle: { color: '#333', fontSize: 10 },
155 157
           top: 0
156 158
         },
157 159
         grid: {
@@ -194,6 +196,7 @@ export default {
194 196
           }
195 197
         },
196 198
         series: [{
199
+          name: '开机年限',
197 200
           type: 'bar',
198 201
           data: this.chartsData.experience.data,
199 202
           itemStyle: {
@@ -226,7 +229,7 @@ export default {
226 229
           axisPointer: { type: 'shadow' }
227 230
         },
228 231
         legend: {
229
-          data: ['人数'],
232
+          data: ['岗位资质'],
230 233
           textStyle: { color: '#666', fontSize: 10 },
231 234
           top: 0
232 235
         },
@@ -287,6 +290,7 @@ export default {
287 290
           // }
288 291
         }],
289 292
         series: [{
293
+          name: '岗位资质',
290 294
           type: 'bar',
291 295
           data: this.chartsData.position.data,
292 296
           itemStyle: {

+ 103 - 47
src/pages/components/ProfileRadar.vue

@@ -4,6 +4,12 @@
4 4
             <text>暂无数据</text>
5 5
         </view>
6 6
         <template v-else>
7
+            <div class="chart-legend">
8
+                <div class="legend-item legend-warning"><span></span>预警线(低于75分)</div>
9
+                <!-- <div class="legend-item legend-normal"><span></span>正常线(75~90分)</div> -->
10
+                <div class="legend-item legend-excellent"><span></span>优秀线(高于90分)</div>
11
+                <div class="legend-item legend-current"><span></span>当前分值</div>
12
+            </div>
7 13
             <div class="chart-container" ref="radarChart"></div>
8 14
             <view class="radar-list">
9 15
                 <view v-for="(item, index) in radarData" :key="index" class="radar-item">
@@ -92,73 +98,66 @@ export default {
92 98
                 this.chart.dispose()
93 99
                 this.chart = null
94 100
             }
95
-            
101
+
96 102
             // 没有数据时不渲染图表
97 103
             if (!this.radarData || this.radarData.length === 0) {
98 104
                 return
99 105
             }
100
-            
101
-            const values = this.radarData.map(item => {
102
-                if (typeof item === 'object' && item !== null) {
103
-                    return item.finalScore || item.score || 0
104
-                }
105
-                return 0
106
-            })
107
-            
106
+
107
+
108
+
109
+
108 110
             this.chart = echarts.init(this.$refs.radarChart)
109
-            
110
-            const option = {
111
-                responsive: true,
112
-                maintainAspectRatio: false,
113
-                radar: {
114
-                    indicator: this.indicators,
115
-                    center: ['50%', '50%'],
116
-                    radius: '60%',
117
-                    splitNumber: 5,
118
-                    axisLine: {
119
-                        lineStyle: {
120
-                            color: 'gray'
121
-                        }
111
+            const radarData = {
112
+                grounp: this.radarData.map(d => ({ name: d.name + '\n\n' + d.finalScore, max: 100 })),
113
+                data: [{
114
+                    name: '个人能力',
115
+                    value: this.radarData.map(item => item.finalScore || 0),
116
+                    symbolSize: 10,
117
+                    areaStyle: {
118
+                        show: false,
119
+                        opacity: 0
122 120
                     },
123
-                    splitLine: {
124
-                        lineStyle: {
125
-                            color: 'gray'
126
-                        }
121
+                    lineStyle: {
122
+                        color: '#4DC8FE',
123
+                        width: 1
127 124
                     },
125
+                    itemStyle: { color: '#fff', borderWidth: 1, borderColor: '#00C8DA', borderJoin: 'round' }
126
+                }]
127
+            }
128
+
129
+            const option = {
130
+                radar: {
131
+                    indicator: radarData.grounp,
132
+                    center: ['50%', '52%'],
133
+                    radius: '50%',
134
+                    splitNumber: 8,
135
+                    axisLine: { lineStyle: { color: '#ccc' } },
136
+                    splitLine: { lineStyle: { color: ['#ccc', '#ccc', '#ccc', '#ccc', '#ccc', '#ccc', '#fe4322', '#8EC742', '#ccc'], width: 1 } },
128 137
                     splitArea: { show: false },
129 138
                     axisName: {
130 139
                         color: '#333',
131
-                        fontSize: 10
140
+                        fontSize: 12
132 141
                     }
133 142
                 },
134 143
                 series: [
135 144
                     {
136 145
                         type: 'radar',
146
+                        data: radarData.data,
137 147
                         symbol: 'circle',
138
-                        symbolSize: 8,
139
-                        data: [
140
-                            {
141
-                                value: values,
142
-                                name: '综合得分',
143
-                                lineStyle: {
144
-                                    color: '#4DC8FE',
145
-                                    width: 2
146
-                                },
147
-                                itemStyle: {
148
-                                    color: '#fff',
149
-                                    borderWidth: 1,
150
-                                    borderColor: '#00C8DA'
151
-                                },
152
-                                areaStyle: {
153
-                                    color: 'rgba(77, 200, 254, 0.2)'
154
-                                }
155
-                            }
156
-                        ]
148
+                        symbolSize: 13,
149
+                        label: {
150
+                            show: false,
151
+                            formatter: (p) => p.value,
152
+                            color: '#333',
153
+                            fontSize: 16,
154
+                            fontWeight: 'bold'
155
+                        }
157 156
                     }
158 157
                 ],
159 158
                 tooltip: {
160 159
                     trigger: 'item',
161
-                   axisPointer: { type: 'shadow' }
160
+                    axisPointer: { type: 'shadow' }
162 161
                 }
163 162
             }
164 163
             this.chart.setOption(option)
@@ -191,6 +190,63 @@ export default {
191 190
         height: 350rpx;
192 191
     }
193 192
 
193
+    .chart-legend {
194
+        display: flex;
195
+        justify-content: center;
196
+        align-items: center;
197
+        flex-wrap: wrap;
198
+        gap: 10px 18px;
199
+        padding-top: 8px;
200
+        color: #fff;
201
+        font-size: 14px;
202
+
203
+    }
204
+
205
+    .legend-item {
206
+        display: flex;
207
+        align-items: center;
208
+        gap: 6rpx;
209
+
210
+        span {
211
+            width: 24rpx;
212
+            height: 10rpx;
213
+            border: 2rpx solid currentColor;
214
+            border-radius: 2rpx;
215
+        }
216
+    }
217
+
218
+    .legend-warning {
219
+        color: #fe4322;
220
+
221
+        span {
222
+            background-color: #fe4322;
223
+        }
224
+    }
225
+
226
+    .legend-normal {
227
+        color: black;
228
+
229
+        span {
230
+            background-color: gray;
231
+        }
232
+    }
233
+
234
+    .legend-excellent {
235
+        color: #8EC742;
236
+
237
+        span {
238
+            background-color: #8EC742;
239
+        }
240
+    }
241
+
242
+    .legend-current {
243
+        color: #1890ff;
244
+
245
+        span {
246
+            background-color: #1890ff;
247
+        }
248
+    }
249
+
194 250
     .radar-list {
195 251
         display: flex;
196 252
         flex-direction: column;

+ 1 - 1
src/pages/employeeProfile/index.vue

@@ -151,7 +151,7 @@
151 151
                         <div class="legend-item legend-warning"><span></span>预警线(低于75分)</div>
152 152
                         <!-- <div class="legend-item legend-normal"><span></span>正常线(75~90分)</div> -->
153 153
                         <div class="legend-item legend-excellent"><span></span>优秀线(高于90分)</div>
154
-                        <div class="legend-item legend-current"><span></span>当前员工分值</div>
154
+                        <div class="legend-item legend-current"><span></span>当前分值</div>
155 155
                     </div>
156 156
                     <div class="chart-container" ref="radarChart" ></div>
157 157
                 </SectionTitle>

+ 499 - 0
src/pages/organizationStruct/index.vue

@@ -0,0 +1,499 @@
1
+<template>
2
+    <view class="organization-struct">
3
+        <!-- 顶部搜索栏 -->
4
+        <view class="search-header">
5
+            <view class="search-box">
6
+                <u-icon name="search" color="#999" size="18" />
7
+                <input 
8
+                    v-model="searchKeyword" 
9
+                    class="search-input" 
10
+                    placeholder="搜索部门或人员" 
11
+                    @input="handleSearch"
12
+                />
13
+                <u-icon v-if="searchKeyword" name="close" color="#999" size="16" @click="clearSearch" />
14
+            </view>
15
+        </view>
16
+
17
+        <!-- 面包屑导航 -->
18
+        <view v-if="!searchKeyword && (breadcrumbs.length > 0 || currentNode)" class="breadcrumb">
19
+            <view class="back-btn" v-if="breadcrumbs.length > 0 || currentNode" @click="goBack">
20
+                <u-icon name="arrow-left" color="#666" size="20" />
21
+            </view>
22
+            <view 
23
+                v-for="(item, index) in breadcrumbs" 
24
+                :key="item.id"
25
+                class="breadcrumb-item"
26
+                @click="navigateToBreadcrumb(index)"
27
+            >
28
+                <text :class="['breadcrumb-text', { active: index === breadcrumbs.length - 1 }]">
29
+                    {{ item.label }}
30
+                </text>
31
+                <u-icon v-if="index < breadcrumbs.length - 1" name="arrow-right" color="#999" size="14" />
32
+            </view>
33
+        </view>
34
+
35
+        <!-- 内容区域 -->
36
+        <scroll-view class="content-area" scroll-y>
37
+            <!-- 搜索结果 -->
38
+            <view v-if="searchKeyword" class="search-results">
39
+                <view v-if="searchResults.length === 0" class="empty-state">
40
+                    <text>暂无搜索结果</text>
41
+                </view>
42
+                <view 
43
+                    v-for="item in searchResults" 
44
+                    :key="item.id || item.userId"
45
+                    :class="['result-item', { 'is-dept': item.nodeType === 'dept' || item.children }]"
46
+                    @click="handleResultClick(item)"
47
+                >
48
+                    <view class="result-icon">
49
+                        <u-icon :name="item.nodeType === 'dept' || item.children ? 'folder' : 'account'" 
50
+                            :color="item.nodeType === 'dept' || item.children ? '#A78BFA' : '#60A5FA'" size="20" />
51
+                    </view>
52
+                    <view class="result-info">
53
+                        <text class="result-name">{{ item.label || item.nickName || item.name }}</text>
54
+                        <text v-if="item.nodeType === 'dept' || item.children" class="result-path">
55
+                            {{ getSearchResultPath(item) }}
56
+                        </text>
57
+                    </view>
58
+                </view>
59
+            </view>
60
+
61
+            <!-- 正常浏览 -->
62
+            <view v-else class="dept-list">
63
+                <!-- 部门项 -->
64
+                <view 
65
+                    v-for="item in displayDepts" 
66
+                    :key="item.id"
67
+                    class="dept-item"
68
+                    @click="navigateToDept(item)"
69
+                >
70
+                    <view class="dept-icon">
71
+                        <u-icon name="folder" color="#A78BFA" size="40" />
72
+                    </view>
73
+                    <view class="dept-info">
74
+                        <text class="dept-name">{{ item.label || item.name }}</text>
75
+                        <text class="dept-count">{{ getNodeCount(item) }}</text>
76
+                    </view>
77
+                    <u-icon name="arrow-right" color="#ccc" size="20" />
78
+                </view>
79
+
80
+                <!-- 人员项 -->
81
+                <view 
82
+                    v-for="item in displayUsers" 
83
+                    :key="item.userId"
84
+                    class="user-item"
85
+                >
86
+                    <view class="user-avatar">
87
+                        <image v-if="item.avatar" :src="item.avatar" mode="aspectFill" class="avatar-img" />
88
+                        <view v-else class="avatar-placeholder">
89
+                            <text>{{ (item.label || item.nickName || item.userName || '').slice(-1) }}</text>
90
+                        </view>
91
+                    </view>
92
+                    <view class="user-info">
93
+                        <text class="user-name">{{ item.label  }}</text>
94
+                        <text v-if="item.postNames" class="user-post">{{ item.postNames }}</text>
95
+                    </view>
96
+                </view>
97
+
98
+                <!-- 空状态 -->
99
+                <view v-if="!displayDepts.length && !displayUsers.length && !loading" class="empty-state">
100
+                    <text>暂无数据</text>
101
+                </view>
102
+
103
+                <!-- 加载中 -->
104
+                <view v-if="loading" class="loading-state">
105
+                    <u-loading-icon text="加载中" textSize="14" />
106
+                </view>
107
+            </view>
108
+        </scroll-view>
109
+    </view>
110
+</template>
111
+
112
+<script>
113
+import { getDeptUserTree } from '@/api/system/user'
114
+
115
+export default {
116
+    name: 'OrganizationStruct',
117
+    data() {
118
+        return {
119
+            loading: false,
120
+            searchKeyword: '',
121
+            treeData: [],
122
+            currentNode: null,
123
+            breadcrumbs: [],
124
+            searchResults: []
125
+        }
126
+    },
127
+    computed: {
128
+        displayDepts() {
129
+            if (!this.currentNode) {
130
+                return this.treeData.filter(item => item.nodeType === 'dept' || (item.children && item.children.length > 0))
131
+            }
132
+            return (this.currentNode.children || []).filter(item => item.nodeType === 'dept' || (item.children && item.children.length > 0))
133
+        },
134
+        displayUsers() {
135
+            if (!this.currentNode) {
136
+                return this.treeData.filter(item => item.nodeType === 'user')
137
+            }
138
+            return (this.currentNode.children || []).filter(item => item.nodeType === 'user')
139
+        }
140
+    },
141
+    mounted() {
142
+        this.fetchTreeData()
143
+    },
144
+    methods: {
145
+        async fetchTreeData() {
146
+            this.loading = true
147
+            try {
148
+                const res = await getDeptUserTree()
149
+                this.treeData = res.data || []
150
+                this.currentNode = null
151
+                this.breadcrumbs = []
152
+            } catch (error) {
153
+                console.error('获取组织架构失败:', error)
154
+                uni.showToast({ title: '获取数据失败', icon: 'none' })
155
+            } finally {
156
+                this.loading = false
157
+            }
158
+        },
159
+        getNodeCount(node) {
160
+            const children = node.children || []
161
+            const deptCount = children.filter(c => c.nodeType === 'dept' || (c.children && c.children.length > 0)).length
162
+            const userCount = children.filter(c => c.nodeType === 'user').length
163
+            const parts = []
164
+            if (deptCount > 0) parts.push(`${deptCount}个部门`)
165
+            if (userCount > 0) parts.push(`${userCount}人`)
166
+            return parts.join('、')
167
+        },
168
+        navigateToDept(node) {
169
+            this.breadcrumbs.push({
170
+                id: node.id,
171
+                label: node.label || node.name
172
+            })
173
+            this.currentNode = node
174
+        },
175
+        goBack() {
176
+            if (this.breadcrumbs.length <= 1) {
177
+                this.currentNode = null
178
+                this.breadcrumbs = []
179
+            } else {
180
+                this.breadcrumbs.pop()
181
+                if (this.breadcrumbs.length === 0) {
182
+                    this.currentNode = null
183
+                } else {
184
+                    const targetId = this.breadcrumbs[this.breadcrumbs.length - 1].id
185
+                    this.currentNode = this.findNodeById(this.treeData, targetId)
186
+                }
187
+            }
188
+        },
189
+        navigateToBreadcrumb(index) {
190
+            if (index === 0) {
191
+                this.currentNode = null
192
+                this.breadcrumbs = []
193
+            } else {
194
+                const targetId = this.breadcrumbs[index].id
195
+                let targetNode = this.findNodeById(this.treeData, targetId)
196
+                if (targetNode) {
197
+                    this.currentNode = targetNode
198
+                    this.breadcrumbs = this.breadcrumbs.slice(0, index + 1)
199
+                }
200
+            }
201
+        },
202
+        findNodeById(nodes, id) {
203
+            for (const node of nodes) {
204
+                if (node.id === id) return node
205
+                if (node.children && node.children.length > 0) {
206
+                    const found = this.findNodeById(node.children, id)
207
+                    if (found) return found
208
+                }
209
+            }
210
+            return null
211
+        },
212
+        handleSearch() {
213
+            if (!this.searchKeyword.trim()) {
214
+                this.searchResults = []
215
+                return
216
+            }
217
+            const keyword = this.searchKeyword.trim().toLowerCase()
218
+            this.searchResults = this.searchTree(this.treeData, keyword)
219
+        },
220
+        searchTree(nodes, keyword, path = []) {
221
+            let results = []
222
+            for (const node of nodes) {
223
+                const name = (node.label || node.nickName || node.name || '').toLowerCase()
224
+                if (name.includes(keyword)) {
225
+                    results.push({
226
+                        ...node,
227
+                        searchPath: [...path]
228
+                    })
229
+                }
230
+                if (node.children && node.children.length > 0) {
231
+                    results = results.concat(
232
+                        this.searchTree(node.children, keyword, [...path, node.label || node.name])
233
+                    )
234
+                }
235
+            }
236
+            return results
237
+        },
238
+        getSearchResultPath(item) {
239
+            if (!item.searchPath || !item.searchPath.length) return ''
240
+            return item.searchPath.join(' > ')
241
+        },
242
+        handleResultClick(item) {
243
+            if (item.children || item.nodeType === 'dept') {
244
+                this.searchKeyword = ''
245
+                this.searchResults = []
246
+                const targetNode = this.findNodeById(this.treeData, item.id)
247
+                if (targetNode) {
248
+                    this.navigateToNodeFromRoot(targetNode)
249
+                }
250
+            }
251
+        },
252
+        navigateToNodeFromRoot(targetNode) {
253
+            const path = this.findPathToNode(this.treeData, targetNode.id)
254
+            if (path.length > 0) {
255
+                this.breadcrumbs = path.slice(0, -1).map(node => ({
256
+                    id: node.id,
257
+                    label: node.label || node.name
258
+                }))
259
+                this.currentNode = targetNode
260
+            }
261
+        },
262
+        findPathToNode(nodes, id, path = []) {
263
+            for (const node of nodes) {
264
+                const newPath = [...path, node]
265
+                if (node.id === id) {
266
+                    return newPath
267
+                }
268
+                if (node.children && node.children.length > 0) {
269
+                    const found = this.findPathToNode(node.children, id, newPath)
270
+                    if (found.length > 0) {
271
+                        return found
272
+                    }
273
+                }
274
+            }
275
+            return []
276
+        },
277
+        clearSearch() {
278
+            this.searchKeyword = ''
279
+            this.searchResults = []
280
+        }
281
+    }
282
+}
283
+</script>
284
+
285
+<style lang="scss" scoped>
286
+.organization-struct {
287
+    min-height: 100vh;
288
+    background-color: #f5f7fa;
289
+    display: flex;
290
+    flex-direction: column;
291
+}
292
+
293
+.search-header {
294
+    padding: 24rpx 32rpx;
295
+    background-color: #fff;
296
+}
297
+
298
+.search-box {
299
+    display: flex;
300
+    align-items: center;
301
+    gap: 16rpx;
302
+    padding: 16rpx 24rpx;
303
+    background-color: #f5f7fa;
304
+    border-radius: 48rpx;
305
+}
306
+
307
+.search-input {
308
+    flex: 1;
309
+    font-size: 28rpx;
310
+    color: #333;
311
+}
312
+
313
+.breadcrumb {
314
+    display: flex;
315
+    align-items: center;
316
+    padding: 20rpx 32rpx;
317
+    background-color: #fff;
318
+    overflow-x: auto;
319
+    white-space: nowrap;
320
+    border-bottom: 1rpx solid #eee;
321
+}
322
+
323
+.back-btn {
324
+    display: flex;
325
+    align-items: center;
326
+    justify-content: center;
327
+    padding-right: 16rpx;
328
+    flex-shrink: 0;
329
+}
330
+
331
+.breadcrumb-item {
332
+    display: flex;
333
+    align-items: center;
334
+    gap: 8rpx;
335
+    flex-shrink: 0;
336
+}
337
+
338
+.breadcrumb-text {
339
+    font-size: 28rpx;
340
+    color: #999;
341
+
342
+    &.active {
343
+        color: #333;
344
+        font-weight: 500;
345
+    }
346
+}
347
+
348
+.content-area {
349
+    flex: 1;
350
+    padding: 24rpx 32rpx;
351
+}
352
+
353
+.search-results {
354
+    background-color: #fff;
355
+    border-radius: 16rpx;
356
+    padding: 16rpx 0;
357
+}
358
+
359
+.result-item {
360
+    display: flex;
361
+    align-items: center;
362
+    padding: 24rpx 32rpx;
363
+    gap: 20rpx;
364
+    border-bottom: 1rpx solid #f5f5f5;
365
+}
366
+
367
+.result-icon {
368
+    width: 64rpx;
369
+    height: 64rpx;
370
+    display: flex;
371
+    align-items: center;
372
+    justify-content: center;
373
+}
374
+
375
+.result-info {
376
+    flex: 1;
377
+    display: flex;
378
+    flex-direction: column;
379
+    gap: 8rpx;
380
+}
381
+
382
+.result-name {
383
+    font-size: 30rpx;
384
+    color: #333;
385
+}
386
+
387
+.result-path {
388
+    font-size: 24rpx;
389
+    color: #999;
390
+}
391
+
392
+.dept-list {
393
+    display: flex;
394
+    flex-direction: column;
395
+    gap: 20rpx;
396
+}
397
+
398
+.dept-item {
399
+    display: flex;
400
+    align-items: center;
401
+    padding: 24rpx 32rpx;
402
+    background-color: #fff;
403
+    border-radius: 16rpx;
404
+    gap: 20rpx;
405
+}
406
+
407
+.dept-icon {
408
+    width: 80rpx;
409
+    height: 80rpx;
410
+    display: flex;
411
+    align-items: center;
412
+    justify-content: center;
413
+    background-color: #f5f5f5;
414
+    border-radius: 12rpx;
415
+}
416
+
417
+.dept-info {
418
+    flex: 1;
419
+    display: flex;
420
+    flex-direction: column;
421
+    gap: 8rpx;
422
+}
423
+
424
+.dept-name {
425
+    font-size: 32rpx;
426
+    color: #333;
427
+    font-weight: 500;
428
+}
429
+
430
+.dept-count {
431
+    font-size: 24rpx;
432
+    color: #999;
433
+}
434
+
435
+.user-item {
436
+    display: flex;
437
+    align-items: center;
438
+    padding: 24rpx 32rpx;
439
+    background-color: #fff;
440
+    border-radius: 16rpx;
441
+    gap: 20rpx;
442
+}
443
+
444
+.user-avatar {
445
+    width: 80rpx;
446
+    height: 80rpx;
447
+    flex-shrink: 0;
448
+}
449
+
450
+.avatar-img {
451
+    width: 100%;
452
+    height: 100%;
453
+    border-radius: 50%;
454
+}
455
+
456
+.avatar-placeholder {
457
+    width: 100%;
458
+    height: 100%;
459
+    border-radius: 50%;
460
+    background: linear-gradient(135deg, #60A5FA, #A78BFA);
461
+    display: flex;
462
+    align-items: center;
463
+    justify-content: center;
464
+
465
+    text {
466
+        font-size: 32rpx;
467
+        color: #fff;
468
+        font-weight: 500;
469
+    }
470
+}
471
+
472
+.user-info {
473
+    flex: 1;
474
+    display: flex;
475
+    flex-direction: column;
476
+    gap: 6rpx;
477
+}
478
+
479
+.user-name {
480
+    font-size: 32rpx;
481
+    color: #333;
482
+    font-weight: 500;
483
+}
484
+
485
+.user-post {
486
+    font-size: 24rpx;
487
+    color: #999;
488
+}
489
+
490
+.empty-state,
491
+.loading-state {
492
+    padding: 80rpx 32rpx;
493
+    display: flex;
494
+    align-items: center;
495
+    justify-content: center;
496
+    color: #999;
497
+    font-size: 28rpx;
498
+}
499
+</style>

+ 0 - 0
src/pages/organizationStruct/组织架构