9 次代碼提交 67f2cc3e71 ... 1f5d33b1b1

作者 SHA1 備註 提交日期
  simonlll 1f5d33b1b1 feat: 员工画像页面样式按设计稿全面调整 1 月之前
  simonlll be194775d4 feat: 卡片样式按设计稿实现 1 月之前
  simonlll 1a90cd3dbb feat: 员工姓名按设计稿字体属性实现 1 月之前
  simonlll 8ae31ad425 feat: 右侧边栏底色按原型图实现 1 月之前
  simonlll 66928eb3a0 feat: 员工画像底色按原型图实现 1 月之前
  simonlll e103832100 feat: 员工画像页面按原型图重新布局 1 月之前
  simonlll a91844314a fix: 雷达大屏跳转画像改用动态路由查找 1 月之前
  simonlll e813f40365 feat: 雷达大屏成员卡片点击跳转员工画像 1 月之前
  simonlll 7ecf4aa06e feat: 员工画像页面接入真实数据 1 月之前

+ 8 - 0
src/api/score/index.js

@@ -87,6 +87,14 @@ export function syncLedgerByType(type) {
87 87
   return request({ url: `/ledger/sync/${type}`, method: 'post' })
88 88
 }
89 89
 
90
+// ===== 员工画像 =====
91
+export function searchPortraitUsers(keyword) {
92
+  return request({ url: '/score/portrait/searchUsers', method: 'get', params: { keyword } })
93
+}
94
+export function getEmployeePortrait(params) {
95
+  return request({ url: '/score/portrait/employee', method: 'get', params })
96
+}
97
+
90 98
 // ===== 推送配置 =====
91 99
 export function listPushConfig(params) {
92 100
   return request({ url: '/score/pushConfig/list', method: 'get', params })

+ 9 - 1
src/assets/styles/index.scss

@@ -5,13 +5,21 @@
5 5
 @use './btn.scss';
6 6
 @use './ruoyi.scss';
7 7
 
8
+@font-face {
9
+  font-family: 'AlibabaPuHuiTi';
10
+  src: url('/fonts/AlibabaPuHuiTi-Regular.ttf') format('truetype');
11
+  font-weight: 100 900;
12
+  font-style: normal;
13
+  font-display: swap;
14
+}
15
+
8 16
 body {
9 17
   height: 100%;
10 18
   margin: 0;
11 19
   -moz-osx-font-smoothing: grayscale;
12 20
   -webkit-font-smoothing: antialiased;
13 21
   text-rendering: optimizeLegibility;
14
-  font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
22
+  font-family: 'AlibabaPuHuiTi', Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
15 23
 }
16 24
 
17 25
 label {

File diff suppressed because it is too large
+ 877 - 388
src/views/portraitManagement/employeeProfile/index.vue


+ 24 - 2
src/views/score/radar/index.vue

@@ -64,8 +64,9 @@
64 64
         <!-- 成员卡片 -->
65 65
         <div
66 66
           v-for="member in memberList" :key="member.personName"
67
-          class="member-card"
68
-          :class="getMemberBorderClass(member.totalScore)">
67
+          class="member-card clickable-card"
68
+          :class="getMemberBorderClass(member.totalScore)"
69
+          @click="goToPortrait(member.personName)">
69 70
           <div class="card-name" :class="getNameClass(member.totalScore)">
70 71
             {{ member.personName }}({{ member.totalScore }}分)
71 72
           </div>
@@ -81,10 +82,22 @@
81 82
 import { ref, reactive, onMounted, onBeforeUnmount, nextTick, computed, watch } from 'vue'
82 83
 import { ElMessage } from 'element-plus'
83 84
 import * as echarts from 'echarts'
85
+import { useRouter } from 'vue-router'
84 86
 import { radarTeamList, radarMemberScores, syncLedgerAll } from '@/api/score/index'
85 87
 
86 88
 defineOptions({ name: 'ScoreRadar' })
87 89
 
90
+const router = useRouter()
91
+
92
+function goToPortrait(personName) {
93
+  const target = router.getRoutes().find(r => /[/]employeeProfile$/.test(r.path))
94
+  if (target) {
95
+    router.push({ path: target.path, query: { personName } })
96
+  } else {
97
+    ElMessage.warning('未找到员工画像页面,请确认菜单中已配置该页面')
98
+  }
99
+}
100
+
88 101
 // ── 状态 ──────────────────────────────────────────────
89 102
 const loading = ref(false)
90 103
 const syncing = ref(false)
@@ -430,4 +443,13 @@ watch(compareNames, () => nextTick(renderCompareChart), { deep: true })
430 443
 .compare-table .col-person { min-width: 48px; }
431 444
 .score-green { color: #67C23A; font-weight: bold; }
432 445
 .score-red   { color: #F56C6C; font-weight: bold; }
446
+
447
+.clickable-card {
448
+  cursor: pointer;
449
+  transition: box-shadow 0.2s, transform 0.2s;
450
+}
451
+.clickable-card:hover {
452
+  box-shadow: 0 0 12px rgba(26, 106, 255, 0.6);
453
+  transform: translateY(-2px);
454
+}
433 455
 </style>