index.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  1. <template>
  2. <Page @click="visible = false" v-loading="loading" element-loading-background="rgba(22, 22, 22, 0.8)">
  3. <div class="content">
  4. <div class="content-search">
  5. <SearchBar v-model:visible="visible" @search="searchHandler" :deptType="'user'" />
  6. </div>
  7. <div v-show="portrait.personName" class="content-info">
  8. <Card title="个人基本信息">
  9. <div class="userInfo">
  10. <div class="userInfo-name">
  11. <div class="avatar-area">
  12. <img v-if="portrait.avatar" :src="portrait.avatar" class="avatar" alt="头像" />
  13. <div v-else class="avatar">{{ portrait.personName?.charAt(0) }}</div>
  14. </div>
  15. <div class="basic-name">
  16. <div class="basic-label">姓名:</div>
  17. <div class="basic-value">{{ portrait.personName }}</div>
  18. </div>
  19. </div>
  20. <div class="userInfo-info">
  21. <div class="info-item">
  22. <div class="info-item-icon">
  23. <img src="/src/assets/dataBigScreen/img01.png" alt="" />
  24. </div>
  25. <div class="info-item-content">
  26. <div class="info-item-label">所属部门及队室:</div>
  27. <div class="info-item-value">{{ portrait.deptPath || '-' }}</div>
  28. </div>
  29. </div>
  30. <div class="info-item">
  31. <div class="info-item-icon">
  32. <img src="/src/assets/dataBigScreen/img04.png" alt="" />
  33. </div>
  34. <div class="info-item-content">
  35. <div class="info-item-label">学历:</div>
  36. <div class="info-item-value">{{ getSchooling(portrait.schooling) }}</div>
  37. </div>
  38. </div>
  39. </div>
  40. <div class="userInfo-info">
  41. <div class="info-item">
  42. <div class="info-item-icon">
  43. <img src="/src/assets/dataBigScreen/img02.png" alt="" />
  44. </div>
  45. <div class="info-item-content">
  46. <div class="info-item-label">出生日期:</div>
  47. <div class="info-item-value">{{ portrait.birthday || '-' }}</div>
  48. </div>
  49. </div>
  50. <div class="info-item">
  51. <div class="info-item-icon">
  52. <img src="/src/assets/dataBigScreen/img05.png" alt="" />
  53. </div>
  54. <div class="info-item-content">
  55. <div class="info-item-label">专业:</div>
  56. <div class="info-item-value">{{ portrait.major || '-' }}</div>
  57. </div>
  58. </div>
  59. </div>
  60. <div class="userInfo-info">
  61. <div class="info-item">
  62. <div class="info-item-icon">
  63. <img src="/src/assets/dataBigScreen/img03.png" alt="" />
  64. </div>
  65. <div class="info-item-content">
  66. <div class="info-item-label">技能等级:</div>
  67. <div class="info-item-value">{{ portrait.qualificationLevelText || '-' }}</div>
  68. </div>
  69. </div>
  70. <div class="info-item">
  71. <div class="info-item-icon">
  72. <img src="/src/assets/dataBigScreen/img06.png" alt="" />
  73. </div>
  74. <div class="info-item-content">
  75. <div class="info-item-label">标签:</div>
  76. <div class="info-item-value">
  77. <span class="info-item-tag" v-if="portrait.roleNames">{{ portrait.roleNames }}</span>
  78. </div>
  79. </div>
  80. </div>
  81. </div>
  82. <div class="userInfo-score">
  83. <div class="score-progress">
  84. <el-progress type="circle" :width="160" :stroke-width="18" color="#5BE39E" :percentage="(portrait.totalScore || -2) + 2">
  85. <div class="percentage-content">
  86. <span class="percentage-value">{{ (portrait.totalScore || -2) + 2 }}</span>
  87. <span class="percentage-text">综合得分</span>
  88. </div>
  89. </el-progress>
  90. </div>
  91. <div class="score-box">
  92. <div class="score-row">
  93. <span class="score-col">评分:</span>
  94. <span class="score-col-2">{{ portrait.totalScore || 0 }}</span>
  95. </div>
  96. <div class="score-row">
  97. <span class="score-col">标签得分:</span>
  98. <span class="score-col-2">{{ portrait.totalScore || portrait.totalScore == 0 ? 2 : 0 }}</span>
  99. </div>
  100. </div>
  101. </div>
  102. </div>
  103. </Card>
  104. </div>
  105. <div v-show="portrait.personName" class="content-bottom">
  106. <div class="content-bottom-left">
  107. <Card title="工作履历">
  108. <div class="work-history">
  109. <span v-if="portrait.startWorkingDate">
  110. {{ formatWorkDate(portrait.startWorkingDate) }}入职 | 司龄{{ portrait.workYears != null ? portrait.workYears : '-' }}年 | 开机年限{{ portrait.securityCheckYears != null ? portrait.securityCheckYears : '-'
  111. }}年 | 现任职{{ portrait.roleNames || '-' }}
  112. </span>
  113. <span v-else>暂无数据</span>
  114. </div>
  115. </Card>
  116. <Card title="获奖记录">
  117. <div class="honor-item" v-for="(value, index) in portrait.awards" :key="index">
  118. <div :style="{'--indexBgColor': value.color}">
  119. <div :data-index="index + 1"></div>
  120. {{ value.level2Name }} {{ value.level4Name }}
  121. </div>
  122. <div>{{ value.score || '-' }}分</div>
  123. </div>
  124. </Card>
  125. </div>
  126. <div class="content-bottom-center">
  127. <Card title="个人能力">
  128. <div ref="abilityChart" class="chart-box" />
  129. </Card>
  130. </div>
  131. <div class="content-bottom-right">
  132. <Card title="补充信息">
  133. <div class="supp-item">
  134. <span class="s-lbl">政治面貌:</span>
  135. <span class="s-val">{{ portrait.politicalStatusText || '-' }}</span>
  136. </div>
  137. <div class="supp-item supp-item-2">
  138. <span class="s-lbl">性别:</span>
  139. <span class="s-val">{{ portrait.sexText || '-' }}</span>
  140. </div>
  141. <div class="supp-item">
  142. <span class="s-lbl">籍贯:</span>
  143. <span class="s-val">{{ portrait.nativePlace || '-' }}</span>
  144. </div>
  145. <div class="supp-item supp-item-2">
  146. <span class="s-lbl">民族:</span>
  147. <span class="s-val">{{ portrait.nation || '-' }}</span>
  148. </div>
  149. <div class="supp-item">
  150. <span class="s-lbl">年龄:</span>
  151. <span class="s-val">{{ getAge(portrait.birthday) }}</span>
  152. </div>
  153. <div class="supp-item supp-item-2">
  154. <span class="s-lbl">司龄:</span>
  155. <span class="s-val">{{ portrait.workYears != null ? portrait.workYears+'年' : '-' }}</span>
  156. </div>
  157. <div class="supp-item">
  158. <span class="s-lbl">性格特征:</span>
  159. <span class="s-val">{{ portrait.characterCharacteristics || '-' }}</span>
  160. </div>
  161. <div class="supp-item supp-item-2">
  162. <span class="s-lbl">工作风格:</span>
  163. <span class="s-val">{{ portrait.workingStyle || '-' }}</span>
  164. </div>
  165. <div :class="i % 2 ? 'supp-item' : 'supp-item supp-item-2'" v-for="(p, i) in (portrait.postNames || '').split('、')" :key="i">
  166. <span class="s-lbl">{{ i === 0 ? '业务岗位:' : ''}}</span>
  167. <span class="s-val">{{ p }}</span>
  168. </div>
  169. </Card>
  170. </div>
  171. </div>
  172. <div v-show="!portrait.personName" class="ep-empty">
  173. <el-empty description="搜索员工姓名以查看画像" />
  174. </div>
  175. </div>
  176. <div class="radar-tooltip" ref="tipRef">
  177. <Card>
  178. <!-- 标题 -->
  179. <div class="tooltip-title">{{ activeDimName }}</div>
  180. <!-- 加分区域 -->
  181. <div class="tooltip-section">
  182. <div class="section-list">
  183. <div v-if="addList.length" class="list-item" v-for="(item, i) in addList" :key="i">
  184. <span>{{ item.level3Name }}:</span>
  185. <span class="add-text">{{ item.totalScore }}分</span>
  186. </div>
  187. <div v-else class="p-empty">暂无加分记录</div>
  188. </div>
  189. <div class="section-total add">
  190. <span>合计加分:</span>
  191. <span>{{ addTotal }}分</span>
  192. </div>
  193. </div>
  194. <!-- 扣分区域 -->
  195. <div class="tooltip-section">
  196. <div class="section-list">
  197. <div v-if="deductList.length" class="list-item" v-for="(item, i) in deductList" :key="i">
  198. <span>{{ item.level3Name }}:</span>
  199. <span class="deduct-text">{{ item.totalScore }}分</span>
  200. </div>
  201. <div v-if="!deductList.length" class="p-empty">暂无扣分记录</div>
  202. </div>
  203. <div class="section-total deduct">
  204. <span>合计扣分:</span>
  205. <span>{{ deductTotal }}分</span>
  206. </div>
  207. </div>
  208. </Card>
  209. </div>
  210. </Page>
  211. </template>
  212. <script setup>
  213. import Page from '../components/page.vue'
  214. import Card from '../components/card.vue'
  215. import SearchBar from '../components/SearchBar.vue'
  216. import { getEmployeePortrait } from '@/api/score/index'
  217. import { onMounted, reactive, ref } from 'vue'
  218. import { useDict } from '@/utils/dict'
  219. import { useECharts } from '@/hooks/useEcharts'
  220. const { sys_user_schooling } = useDict('sys_user_schooling')
  221. const visible = ref(false)
  222. const loading = ref(false)
  223. const portrait = ref({ dimensions: [] })
  224. const abilityChart = ref(null)
  225. const activeDimName = ref(null)
  226. const scoreDetails = computed(() => portrait.value?.scoreDetails || [])
  227. const addList = computed(() => {
  228. const all = scoreDetails.value.filter(d => d.totalScore != null && Number(d.totalScore) > 0)
  229. return activeDimName.value ? all.filter(d => d.dimensionName === activeDimName.value) : all
  230. })
  231. const deductList = computed(() => {
  232. const all = scoreDetails.value.filter(d => d.totalScore != null && Number(d.totalScore) < 0)
  233. return activeDimName.value ? all.filter(d => d.dimensionName === activeDimName.value) : all
  234. })
  235. const addTotal = computed(() => {
  236. const s = addList.value.reduce((acc, d) => acc + Number(d.totalScore), 0)
  237. return (s > 0 ? '+' : '') + s.toFixed(2)
  238. })
  239. const deductTotal = computed(() => {
  240. const s = deductList.value.reduce((acc, d) => acc + Number(d.totalScore), 0)
  241. return s.toFixed(2)
  242. })
  243. const getSchooling = (schooling) => {
  244. const result = (sys_user_schooling.value || []).find(item => item.value === schooling) || { label: schooling }
  245. return result.label || '-'
  246. }
  247. const getAge = (birthday) => {
  248. const birthDate = new Date(birthday);
  249. if (isNaN(birthDate.getTime())) {
  250. return '-'
  251. }
  252. const today = new Date();
  253. // 计算年份差
  254. let age = today.getFullYear() - birthDate.getFullYear();
  255. // 计算月份差
  256. const monthDiff = today.getMonth() - birthDate.getMonth();
  257. // 如果还没到今年生日,年龄减1
  258. if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
  259. age--;
  260. }
  261. return `${age}岁`;
  262. }
  263. const getRandomHexColor = () => {
  264. return '#' + Math.floor(Math.random() * 0xffffff).toString(16).padStart(6, '0');
  265. }
  266. const formatWorkDate = (d) => {
  267. if (!d) return '-'
  268. const str = String(d)
  269. const parts = str.substring(0, 10).split('-')
  270. if (parts.length < 3) return str
  271. return `${parts[0]}.${Number(parts[1])}.${Number(parts[2])}`
  272. }
  273. const invokerEmployeePortrait = (query) => {
  274. loading.value = true
  275. return getEmployeePortrait(query).then(res => {
  276. portrait.value = res.data || { dimensions: [], awards: [] }
  277. portrait.value.awards.forEach(item => {
  278. item.color = getRandomHexColor()
  279. })
  280. permutationRadarDataHandler(res.data.dimensions)
  281. }).finally(() => {
  282. loading.value = false
  283. })
  284. }
  285. const searchHandler = (query) => {
  286. visible.value = false
  287. invokerEmployeePortrait(query)
  288. }
  289. const radarData = reactive({
  290. grounp: [],
  291. data: []
  292. })
  293. const permutationRadarDataHandler = (result = []) => {
  294. radarData.grounp = result.map(d => ({ name: d.name + '\n\n' + d.score, max: 100 })),
  295. radarData.data = [{
  296. name: '个人能力',
  297. value: result.map(attr => attr.score),
  298. symbolSize: 10,
  299. areaStyle: {
  300. show: false,
  301. opacity: 0,
  302. color: {
  303. type: 'linear',
  304. x: 0,
  305. y: 0,
  306. x2: 0,
  307. y2: 1,
  308. colorStops: [{
  309. offset: 0, color: '#4DC8FE'
  310. }, {
  311. offset: 1, color: '#6C26F3'
  312. }],
  313. global: false
  314. },
  315. },
  316. lineStyle: {
  317. color: {
  318. type: 'linear',
  319. x: 0,
  320. y: 0,
  321. x2: 0,
  322. y2: 1,
  323. colorStops: [{
  324. offset: 0, color: '#4DC8FE'
  325. }, {
  326. offset: 1, color: '#6C26F3'
  327. }],
  328. global: false
  329. },
  330. width: 5
  331. },
  332. itemStyle: { color: '#fff', borderWidth: 1, borderColor: '#00C8DA', borderJoin: 'round' }
  333. }]
  334. }
  335. const setRadarOptions = computed(() => {
  336. return {
  337. radar: {
  338. indicator: radarData.grounp,
  339. center: ['50%', '52%'],
  340. radius: '65%',
  341. splitNumber: 8,
  342. axisLine: { lineStyle: { color: '#ccc' } },
  343. splitLine: { lineStyle: { color: ['#ccc', '#ccc', '#ccc', '#ccc', '#ccc', '#ccc', '#fe4322', '#8EC742', '#ccc'], width: 3 } },
  344. splitArea: { show: false },
  345. axisName: {
  346. color: '#fff',
  347. fontSize: 18
  348. },
  349. },
  350. series: [
  351. {
  352. type: 'radar',
  353. data: radarData.data,
  354. symbol: 'circle',
  355. symbolSize: 6,
  356. label: {
  357. show: false,
  358. formatter: (p) => p.value,
  359. color: '#fff',
  360. fontSize: 16,
  361. fontWeight: 'bold'
  362. }
  363. }
  364. ]
  365. }
  366. })
  367. let pisition = {
  368. x: 0,
  369. y: 0
  370. }
  371. const tipRef = ref(null)
  372. useECharts(abilityChart, setRadarOptions).bindEvent('mousemove', (e) => {
  373. if (!Array.isArray(portrait.value.dimensions) || !portrait.value.dimensions.length) return
  374. const rect = abilityChart.value.getBoundingClientRect()
  375. if (!tipRef.value) return
  376. const cx = rect.width / 2
  377. const cy = rect.height / 2
  378. const dx = e.offsetX - cx
  379. const dy = e.offsetY - cy
  380. const distance = Math.sqrt(dx * dx + dy * dy)
  381. const radarRadius = rect.width * 0.35 // 对应 radius: 65%
  382. if (distance > radarRadius) {
  383. tipRef.value.style.display = 'none'
  384. return
  385. }
  386. // 角度计算
  387. let angle = Math.atan2(dx, -dy) * (180 / Math.PI)
  388. if (angle < 0) angle += 360
  389. const count = portrait.value.dimensions.length
  390. const step = 360 / count
  391. let idx = Math.abs(Math.round(angle / step) % count - count)
  392. if (idx < 0) idx += count
  393. if (idx >= count) idx = 0
  394. // 显示 tooltip
  395. tipRef.value.style.display = 'block'
  396. tipRef.value.style.left = pisition.x + 30 + 'px'
  397. tipRef.value.style.top = pisition.y + 'px'
  398. activeDimName.value = portrait.value.dimensions[idx].name
  399. }).bindEvent('mouseout', () => {
  400. if (tipRef.value) tipRef.value.style.display = 'none'
  401. })
  402. onMounted(() => {
  403. window.addEventListener('mousemove', (eve) => {
  404. pisition.x = eve.pageX
  405. pisition.y = eve.pageY
  406. })
  407. })
  408. </script>
  409. <style lang="scss" scoped>
  410. .content {
  411. height: calc(100vh - 90px);
  412. display: flex;
  413. flex-direction: column;
  414. row-gap: 15px;
  415. padding: 15px;
  416. box-sizing: border-box;
  417. overflow: hidden;
  418. .ep-empty {
  419. background: #fff;
  420. height: 100%;
  421. display: flex;
  422. align-items: center;
  423. justify-content: center;
  424. background: #21213a;
  425. opacity: 0.8;
  426. border-radius: 30px;
  427. }
  428. .content-search {}
  429. .content-info {
  430. & > * {
  431. height: 100%;
  432. }
  433. .userInfo {
  434. display: flex;
  435. width: 100%;
  436. height: 180px;
  437. box-sizing: border-box;
  438. column-gap: 5px;
  439. .userInfo-name {
  440. flex: 1;
  441. position: relative;
  442. display: flex;
  443. align-items: center;
  444. justify-content: center;
  445. column-gap: 30px;
  446. &::after {
  447. content: '';
  448. display: block;
  449. width: 1px;
  450. background:linear-gradient(180deg, transparent, #6f6c98, transparent);
  451. height: 100%;
  452. position: absolute;
  453. top: 0;
  454. right: -2px;
  455. }
  456. .avatar-area {
  457. height: 140px;
  458. width: 140px;
  459. background: #fff;
  460. border-radius: 50%;
  461. display: flex;
  462. align-items: center;
  463. justify-content: center;
  464. .avatar {
  465. width: 100%;
  466. height: 100%;
  467. display: flex;
  468. align-items: center;
  469. justify-content: center;
  470. color: #6f6c98;
  471. font-size: 48px;
  472. font-weight: 900;
  473. }
  474. }
  475. .basic-name {
  476. display: flex;
  477. flex-direction: column;
  478. justify-content: center;
  479. row-gap: 10px;
  480. font-weight: 500;
  481. .basic-label {
  482. font-size: 18px;
  483. color: #8675AE;
  484. }
  485. .basic-value {
  486. font-size: 26px;
  487. color: #fff;
  488. }
  489. }
  490. }
  491. .userInfo-info {
  492. flex: 1;
  493. position: relative;
  494. display: flex;
  495. flex-direction: column;
  496. justify-content: space-between;
  497. padding: 10px 15px;
  498. padding-right: 0px;
  499. box-sizing: border-box;
  500. &::after {
  501. content: '';
  502. display: block;
  503. width: 1px;
  504. background:linear-gradient(180deg, transparent, #6f6c98, transparent);
  505. height: 100%;
  506. position: absolute;
  507. top: 0;
  508. right: -2px;
  509. }
  510. .info-item {
  511. display: flex;
  512. column-gap: 15px;
  513. .info-item-content {
  514. display: flex;
  515. flex-direction: column;
  516. justify-content: space-between;
  517. font-weight: 500;
  518. .info-item-label {
  519. font-size: 18px;
  520. color: #8675AE;
  521. }
  522. .info-item-value {
  523. font-size: 18px;
  524. color: #fff;
  525. display: flex;
  526. align-items: center;
  527. flex-wrap: wrap;
  528. }
  529. .info-item-tag {
  530. font-size: 14px;
  531. display: block;
  532. padding: 3px 15px;
  533. background: linear-gradient(125deg, #2AB3E6, #9605FC);
  534. border-radius: 20px;
  535. }
  536. }
  537. }
  538. }
  539. .userInfo-score {
  540. :deep(.el-progress-circle) {
  541. width: 160px;
  542. height: 160px;
  543. --el-fill-color-light: #004970;
  544. transform: rotate(0.5turn);
  545. }
  546. flex: 1;
  547. display: flex;
  548. align-items: center;
  549. padding-left: 15px;
  550. column-gap: 25px;
  551. .score-progress {
  552. .percentage-content {
  553. display: flex;
  554. flex-direction: column;
  555. align-items: center;
  556. row-gap: 6px;
  557. font-weight: 500;
  558. .percentage-value {
  559. font-size: 48px;
  560. color: #02E5CC;
  561. }
  562. .percentage-text {
  563. font-size: 16px;
  564. color: #fff;
  565. }
  566. }
  567. }
  568. .score-box {
  569. display: flex;
  570. flex-direction: column;
  571. font-weight: 500;
  572. row-gap: 15px;
  573. font-size: 18px;
  574. .score-col {
  575. display: inline-block;
  576. width: 5em;
  577. }
  578. .score-col-2 {
  579. font-size: 24px;
  580. }
  581. }
  582. }
  583. }
  584. }
  585. .content-bottom {
  586. flex: 1;
  587. display: flex;
  588. column-gap: 15px;
  589. .content-bottom-left {
  590. width: 380px;
  591. display: flex;
  592. flex-direction: column;
  593. row-gap: 15px;
  594. & > *:nth-child(1) {
  595. flex: 1;
  596. .work-history {
  597. font-size: 18px;
  598. }
  599. }
  600. & > *:nth-child(2) {
  601. flex: 1.6;
  602. .honor-item {
  603. height: 48px;
  604. padding-right: 15px;
  605. box-sizing: border-box;
  606. font-weight: 500;
  607. font-size: 18px;
  608. display: flex;
  609. align-items: center;
  610. justify-content: space-between;
  611. position: relative;
  612. & > div:nth-child(1) {
  613. display: flex;
  614. align-items: center;
  615. column-gap: 15px;
  616. & > div {
  617. width: 26px;
  618. height: 20px;
  619. position: relative;
  620. font-size: 18px;
  621. text-align: center;
  622. line-height: 20px;
  623. color: #222;
  624. &::before {
  625. position: absolute;
  626. inset: 0;
  627. content: '';
  628. display: block;
  629. background: var(--indexBgColor);
  630. width: 100%;
  631. height: 100%;
  632. transform: skew(-25deg);
  633. }
  634. &::after {
  635. position: absolute;
  636. inset: 0;
  637. content: attr(data-index);
  638. display: block;
  639. width: 100%;
  640. height: 100%;
  641. z-index: 100;
  642. }
  643. }
  644. }
  645. & > div:nth-child(2) {
  646. color: #02E5CC;
  647. }
  648. &::after {
  649. content: '';
  650. display: block;
  651. position: absolute;
  652. bottom: 0;
  653. left: 0;
  654. height: 1px;
  655. width: 100%;
  656. background:linear-gradient(45deg, transparent 0%, transparent 30%, #6f6c98 100%);
  657. }
  658. }
  659. }
  660. }
  661. .content-bottom-center {
  662. flex: 1;
  663. & > * {
  664. height: 100%;
  665. }
  666. .chart-box {
  667. width: 100%;
  668. height: 100%;
  669. overflow: hidden;
  670. }
  671. }
  672. .content-bottom-right {
  673. width: 380px;
  674. & > * {
  675. height: 100%;
  676. }
  677. .supp-item {
  678. display: flex;
  679. justify-content: space-between;
  680. align-items: center;
  681. height: 42px;
  682. padding: 0 15px;
  683. font-weight: 500;
  684. font-size: 18px;
  685. .s-lbl {
  686. color: #8675AE;
  687. }
  688. .s-val {
  689. color: #fff;
  690. }
  691. }
  692. .supp-item-2 {
  693. background: #261C48;
  694. }
  695. }
  696. }
  697. }
  698. /* Tooltip 样式(全部放这里) */
  699. .radar-tooltip {
  700. position: fixed;
  701. min-width: 300px;
  702. z-index: 999;
  703. pointer-events: none;
  704. transform: translateY(-80%);
  705. display: none;
  706. .p-empty {
  707. text-align: center;
  708. margin-top: 5px;
  709. }
  710. .tooltip-title {
  711. font-size: 18px;
  712. font-weight: bold;
  713. color: #fff;
  714. padding: 0 10px;
  715. }
  716. .tooltip-section {
  717. padding: 0 10px;
  718. }
  719. .list-item {
  720. margin-top: 4px;
  721. display: flex;
  722. align-items: center;
  723. justify-content: space-between;
  724. color: #fff;
  725. .deduct-text {
  726. color: #ff4d4f;
  727. }
  728. .add-text {
  729. color: #00b42a;
  730. }
  731. }
  732. .section-total {
  733. margin-top: 4px;
  734. display: flex;
  735. align-items: center;
  736. justify-content: space-between;
  737. font-weight: 500;
  738. font-size: 16px;
  739. &.deduct {
  740. color: #ff4d4f;
  741. }
  742. &.add {
  743. color: #00b42a;
  744. }
  745. }
  746. }
  747. </style>