Просмотр исходного кода

修复在wt项目中左侧空白的问题

ZGC4846 4 дней назад
Родитель
Сommit
488e3f98d8

+ 1 - 1
src/App.vue

@@ -1,5 +1,5 @@
 <template>
-  <div id="page-hr-app">
+  <div id="app">
     <router-view />
   </div>
 </template>

+ 3 - 5
src/config/setting.js

@@ -1,5 +1,3 @@
-import { DEFAULT_MENUS } from './menus';
-
 /** 接口基础地址 */
 export const API_BASE_URL = process.env.VUE_APP_API_BASE_URL;
 
@@ -29,10 +27,10 @@ export const WHITE_LIST = ['/login'];
 export const KEEP_ALIVE_EXCLUDES = [];
 
 /**
- * 菜单数据:优先接口 /page-hr;接口未配置时用本地 DEFAULT_MENUS 兜底
- * 门户菜单配置好后,可将此处改回 undefined,仅走接口
+ * 菜单数据:与 EOM 一致默认 undefined(走接口 /page-hr)
+ * 独立运行且接口无菜单时,由 store 回退 DEFAULT_MENUS
  */
-export const USER_MENUS = DEFAULT_MENUS;
+export const USER_MENUS = undefined;
 
 /** 首页名称 / 路径 */
 export const HOME_TITLE = '首页';

+ 5 - 0
src/main.js

@@ -23,6 +23,11 @@ import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css';
 import 'nprogress/nprogress.css';
 import './styles/index.scss';
 
+// 独立运行标记:样式仅在该 class 下接管 html/body,避免乾坤冲掉主应用侧栏
+if (!window.__POWERED_BY_QIANKUN__) {
+  document.documentElement.classList.add('hr-standalone');
+}
+
 Vue.config.productionTip = false;
 Vue.directive('click-once', clickOnce);
 Vue.component('HeaderTitle', HeaderTitle);

+ 7 - 2
src/router/index.js

@@ -90,11 +90,16 @@ router.beforeEach((to, from, next) => {
       return;
     }
 
-    if (!store.state.user.menus?.length) {
+    if (store.state.user.menus == null) {
       store
         .dispatch('user/fetchUserInfo')
         .then(({ menus, homePath, authoritiesRouter }) => {
-          registerMenuRoutes(menus, homePath, authoritiesRouter);
+          // 与 EOM 一致:有菜单则注册;无菜单也要挂布局+首页,并标记已加载避免死循环
+          registerMenuRoutes(
+            menus || [],
+            homePath || HOME_PATH || '/home',
+            authoritiesRouter || [],
+          );
           next({ ...to, replace: true });
         })
         .catch((e) => {

+ 61 - 52
src/store/modules/user.js

@@ -1,5 +1,5 @@
 /**
- * 登录用户 / 菜单 / 权限
+ * 登录用户 / 菜单 / 权限(对齐 EOM)
  */
 import { formatMenus, toTreeData, formatTreeData } from 'ele-admin';
 import { USER_MENUS, SYSTEM_NAME, HOME_PATH } from '@/config/setting';
@@ -34,8 +34,7 @@ const formatRouter = (list = []) => {
 };
 
 function buildLocalMenus() {
-  const source = USER_MENUS || DEFAULT_MENUS;
-  return formatMenus(JSON.parse(JSON.stringify(source)));
+  return formatMenus(JSON.parse(JSON.stringify(DEFAULT_MENUS)));
 }
 
 export default {
@@ -66,7 +65,6 @@ export default {
     setRoles(state, roles) {
       state.roles = roles;
     },
-    /** 清理 session 里残留的旧菜单标题/路径 */
     sanitizeMenus(state) {
       if (state.menus?.length) {
         state.menus = rewriteLegacyHrMenus(state.menus);
@@ -79,64 +77,75 @@ export default {
     },
   },
   actions: {
+    /**
+     * 请求用户菜单:与 EOM 一致,按 `/page-{SYSTEM_NAME}` 过滤资源树
+     */
     async fetchUserInfo({ commit }) {
-      const currentUser = getCurrentUser();
-      let menus;
-      let homePath;
-      let authoritiesRouter = [];
-
+      const currentUser = getCurrentUser() || {};
+      let result = [];
       try {
-        if (currentUser?.currentGroupId && currentUser?.currentRoleId) {
-          const result = await getResourcesTree({
-            groupId: currentUser.currentGroupId,
-            roleId: currentUser.currentRoleId,
-          });
-          const list = result?.filter((item) => item.path === APP_MENU_PATH);
-          if (list?.length) {
-            const { menuList, authorities } = formatRouter(list[0].children || []);
-            commit('setAuthorities', authorities);
-            const formatted = formatMenus(
-              toTreeData({
-                data: menuList,
-                idField: 'id',
-                parentIdField: 'parentId',
-              }),
-            );
-            menus = formatted.menus;
-            homePath = formatted.homePath;
-            const authFormatted = formatMenus(
-              toTreeData({
-                data: authorities.filter((item) => item.path),
-                idField: 'id',
-                parentIdField: 'parentId',
-              }),
-            );
-            authoritiesRouter = authFormatted.menus || [];
-          }
+        if (currentUser.currentGroupId && currentUser.currentRoleId) {
+          result =
+            (await getResourcesTree({
+              groupId: currentUser.currentGroupId,
+              roleId: currentUser.currentRoleId,
+            })) || [];
         }
       } catch (e) {
-        console.warn('[hr] 菜单接口不可用,使用本地菜单', e);
+        console.warn('[hr] 菜单接口不可用', e);
+        result = [];
+      }
+
+      const list = (Array.isArray(result) ? result : []).filter(
+        (item) => item.path === APP_MENU_PATH,
+      );
+
+      // 与 EOM 一致:有 /page-hr 节点时走接口菜单
+      if (list?.length) {
+        const { menuList, authorities } = formatRouter(list[0].children || []);
+        commit('setAuthorities', authorities);
+        const { menus, homePath } = formatMenus(
+          USER_MENUS ??
+            toTreeData({
+              data: menuList,
+              idField: 'id',
+              parentIdField: 'parentId',
+            }),
+        );
+        const { menus: authoritiesRouter } = formatMenus(
+          USER_MENUS ??
+            toTreeData({
+              data: authorities.filter((item) => item.path),
+              idField: 'id',
+              parentIdField: 'parentId',
+            }),
+        );
+        const nextMenus = rewriteLegacyHrMenus(menus || []);
+        const nextAuth = rewriteLegacyHrMenus(authoritiesRouter || []);
+        commit('setMenus', nextMenus);
+        commit('setAuthoritiesRouter', nextAuth);
+        return {
+          menus: nextMenus,
+          homePath: HOME_PATH || homePath || '/home',
+          authoritiesRouter: nextAuth,
+        };
       }
 
-      // 接口无 /page-hr 或失败时,回退本地菜单(恢复改造前侧栏)
-      if (!menus?.length) {
+      // 独立运行且接口无 /page-hr 时本地兜底;乾坤下侧栏由主应用菜单树提供
+      if (!window.__POWERED_BY_QIANKUN__) {
         const local = buildLocalMenus();
-        menus = local.menus;
-        homePath = local.homePath || '/home';
-        authoritiesRouter = [];
+        const nextMenus = rewriteLegacyHrMenus(local.menus || []);
+        commit('setMenus', nextMenus);
         commit('setAuthorities', []);
+        commit('setAuthoritiesRouter', []);
+        return {
+          menus: nextMenus,
+          homePath: HOME_PATH || local.homePath || '/home',
+          authoritiesRouter: [],
+        };
       }
 
-      // 首页路径固定,避免接口 homePath 落到岗位序列等业务页
-      homePath = HOME_PATH || homePath || '/home';
-
-      commit('setMenus', menus);
-      commit('setAuthoritiesRouter', authoritiesRouter);
-      return {
-        menus: rewriteLegacyHrMenus(menus),
-        homePath,
-        authoritiesRouter: rewriteLegacyHrMenus(authoritiesRouter),
-      };
+      return {};
     },
     setInfo({ commit }, value) {
       commit('setUserInfo', value);

+ 9 - 4
src/styles/App.css

@@ -1,12 +1,17 @@
-html,
-body,
-#app,
-#page-hr-app {
+/* 仅独立运行时撑满视口,避免乾坤嵌入污染主应用布局(与 EOM 一致) */
+html.hr-standalone,
+html.hr-standalone body,
+html.hr-standalone #app {
   height: 100%;
   min-height: 100vh;
   margin: 0;
 }
 
+#app {
+  height: 100%;
+  margin: 0;
+}
+
 * {
   box-sizing: border-box;
 }

+ 8 - 14
src/styles/index.scss

@@ -3,28 +3,22 @@ $--ele-font-path: '~ele-admin/es/style/fonts';
 @import '~ele-admin/es/style/themes/dynamic.scss';
 @import '~ele-admin/es/style/index.scss';
 
-html,
-body {
+/*
+ * 仅独立运行时接管 html/body。
+ * 乾坤嵌入时若改主应用滚动根节点,会把 WT 左侧菜单冲掉(与 EOM 一致:嵌入不污染全局)。
+ */
+html.hr-standalone,
+html.hr-standalone body {
   width: 100%;
   height: 100%;
 }
 
-/*
- * EleAdmin 只给 body 设置 overflow-x: hidden。按照 CSS 规范,当另一轴为
- * visible 时,这会让 body 的 overflow-y 计算为 auto,最终由 body 承担页面
- * 滚动。Element UI 的 Popper 默认挂载到 body,并按照 document 的滚动坐标
- * 定位,因此页面滚动后会把 body.scrollTop 重复计算,导致下拉层整体错位。
- *
- * 统一让 html 作为页面滚动根节点;横向裁剪也放到 html 上,body 本身不再
- * 创建滚动容器。这样 Select、Dropdown、DatePicker 等所有 Popper 弹层都能
- * 使用同一坐标系。
- */
-html {
+html.hr-standalone {
   overflow-x: hidden;
   overflow-y: auto;
 }
 
-body {
+html.hr-standalone body {
   overflow-x: visible;
   overflow-y: visible;
 }

+ 64 - 51
src/styles/views/personnelStructureDashboard/index.scss

@@ -57,7 +57,7 @@
   height: calc(100vh - 72px);
   min-height: 0;
   padding: 14px 16px 16px;
-  overflow: hidden;
+  overflow: auto;
   color: var(--text);
   background:
     radial-gradient(ellipse 70% 42% at 50% -8%, rgba(0, 150, 220, 0.26), transparent 58%),
@@ -112,7 +112,7 @@ button {
 }
 
 .dashboard-header {
-  overflow: hidden;
+  overflow: visible;
   border: 1px solid rgba(0, 210, 255, 0.28);
   background: linear-gradient(135deg, rgba(0, 50, 85, 0.45), rgba(0, 16, 34, 0.78));
   box-shadow:
@@ -159,9 +159,10 @@ button {
 .header-toolbar {
   position: relative;
   justify-content: flex-end;
-  gap: 14px;
-  min-height: 54px;
-  padding: 8px 16px;
+  flex-wrap: wrap;
+  gap: 12px 14px;
+  min-height: 58px;
+  padding: 10px 16px;
   background: linear-gradient(90deg, rgba(0, 40, 70, 0.35), rgba(0, 20, 40, 0.15));
 }
 
@@ -175,13 +176,13 @@ button {
 .header-brand .board-tag,
 .board-heading .board-tag {
   color: rgba(120, 220, 255, 0.75);
-  font-size: 10px;
+  font-size: 11px;
   letter-spacing: 0.28em;
 }
 
 .header-brand strong {
   color: #eaf9ff;
-  font-size: 16px;
+  font-size: 20px;
   font-weight: 650;
   letter-spacing: 0.12em;
   text-shadow: 0 0 12px rgba(0, 200, 255, 0.35);
@@ -203,9 +204,9 @@ button {
 }
 
 .analysis-nav button {
-  min-width: 84px;
-  padding: 8px 15px;
-  font-size: 12px;
+  min-width: 92px;
+  padding: 8px 16px;
+  font-size: 14px;
 }
 
 .analysis-nav button:hover:not(.active) {
@@ -233,7 +234,7 @@ button {
 .filter-item {
   gap: 7px;
   color: #8ebfd8;
-  font-size: 11px;
+  font-size: 13px;
   white-space: nowrap;
 }
 
@@ -243,16 +244,17 @@ button {
 }
 
 .filter-item ::v-deep .el-select {
-  width: 112px;
+  width: 128px;
 }
 
 .organization-filter ::v-deep .el-select {
-  width: 150px;
+  width: 168px;
 }
 
 .filter-item ::v-deep .el-input__inner {
   height: 34px;
   color: #d5f1ff;
+  font-size: 13px;
   border-color: rgba(0, 210, 255, 0.35);
   border-radius: 0;
   background: linear-gradient(180deg, rgba(0, 40, 70, 0.9), rgba(0, 18, 36, 0.95));
@@ -293,8 +295,8 @@ button {
   position: relative;
   display: flex;
   align-items: flex-start;
-  min-height: 100px;
-  padding: 14px 15px;
+  min-height: 108px;
+  padding: 14px 15px 28px;
   overflow: hidden;
   color: var(--text);
   text-align: left;
@@ -385,7 +387,7 @@ button {
   display: block;
   margin: 1px 0 3px;
   color: #8fc4de;
-  font-size: 11px;
+  font-size: 13px;
 }
 
 .metric-value {
@@ -395,7 +397,7 @@ button {
 
 .metric-copy strong {
   color: #f5fcff;
-  font-size: 24px;
+  font-size: 28px;
   font-weight: 700;
   line-height: 1.1;
   text-shadow: 0 0 12px rgba(0, 220, 255, 0.4);
@@ -404,7 +406,7 @@ button {
 .metric-copy em {
   margin-left: 5px;
   color: #7eb2cd;
-  font-size: 10px;
+  font-size: 13px;
   font-style: normal;
 }
 
@@ -412,10 +414,10 @@ button {
   display: block;
   margin-top: 5px;
   color: #7aa8c2;
-  font-size: 11px;
+  font-size: 12px;
   font-weight: 500;
-  line-height: 16px;
-  white-space: nowrap;
+  line-height: 18px;
+  white-space: normal;
 }
 
 .metric-link {
@@ -423,7 +425,7 @@ button {
   right: 13px;
   bottom: 10px;
   color: var(--cyan);
-  font-size: 9px;
+  font-size: 12px;
   opacity: 0;
   transform: translateX(-3px);
   transition: 0.2s;
@@ -503,8 +505,8 @@ button {
   display: flex;
   justify-content: space-between;
   flex: 0 0 auto;
-  min-height: 42px;
-  padding-bottom: 8px;
+  min-height: 48px;
+  padding-bottom: 10px;
   border-bottom: 1px solid rgba(0, 180, 255, 0.14);
 }
 
@@ -512,7 +514,7 @@ button {
   position: relative;
   padding-left: 12px;
   color: #eaf9ff;
-  font-size: 14px;
+  font-size: 16px;
   font-weight: 650;
   letter-spacing: 0.06em;
   text-shadow: 0 0 10px rgba(0, 200, 255, 0.3);
@@ -522,7 +524,7 @@ button {
   content: "";
   position: absolute;
   left: 0;
-  top: 1px;
+  top: 3px;
   width: 3px;
   height: 16px;
   background: linear-gradient(180deg, #7af6ff, rgba(0, 180, 255, 0.15));
@@ -532,7 +534,7 @@ button {
 .panel-header p {
   margin: 5px 0 0 12px;
   color: #6f97b0;
-  font-size: 10px;
+  font-size: 12px;
 }
 
 .panel-unit {
@@ -542,7 +544,7 @@ button {
   gap: 5px;
   padding: 4px 8px;
   color: #8ebfd8;
-  font-size: 10px;
+  font-size: 12px;
   border: 1px solid rgba(0, 200, 255, 0.22);
   background: rgba(0, 30, 55, 0.55);
 }
@@ -577,7 +579,7 @@ button {
 .summary-grid button {
   position: relative;
   min-height: 0;
-  padding: 10px;
+  padding: 12px 12px 14px;
   overflow: hidden;
   color: var(--text);
   text-align: left;
@@ -601,11 +603,11 @@ button {
 .summary-grid .summary-icon {
   display: grid;
   place-items: center;
-  width: 26px;
-  height: 26px;
+  width: 28px;
+  height: 28px;
   margin-bottom: 8px;
   color: var(--cyan);
-  font-size: 13px;
+  font-size: 14px;
   border: 1px solid rgba(0, 220, 255, 0.35);
   background: rgba(0, 180, 255, 0.12);
 }
@@ -620,12 +622,13 @@ button {
   display: block;
   margin-bottom: 4px;
   color: #8ebfd8;
-  font-size: 10px;
+  font-size: 12px;
+  line-height: 1.4;
 }
 
 .summary-grid strong {
   color: #f5fcff;
-  font-size: 20px;
+  font-size: 22px;
   font-weight: 700;
   text-shadow: 0 0 10px rgba(0, 220, 255, 0.35);
 }
@@ -633,7 +636,7 @@ button {
 .summary-grid em {
   margin-left: 4px;
   color: #7ea9c2;
-  font-size: 9px;
+  font-size: 12px;
   font-style: normal;
 }
 
@@ -642,7 +645,7 @@ button {
   right: 9px;
   bottom: 11px;
   color: rgba(0, 220, 255, 0.45);
-  font-size: 10px;
+  font-size: 12px;
   opacity: 0;
   transition: 0.2s;
 }
@@ -655,10 +658,13 @@ button {
 
 .inline-header {
   justify-content: space-between;
+  align-items: flex-start;
+  gap: 10px;
 }
 
 .mini-tabs {
   display: flex;
+  flex-shrink: 0;
   align-items: flex-start;
   padding: 3px;
   border: 1px solid rgba(0, 180, 255, 0.2);
@@ -666,9 +672,9 @@ button {
 }
 
 .mini-tabs button {
-  min-width: 46px;
-  padding: 6px 9px;
-  font-size: 10px;
+  min-width: 56px;
+  padding: 6px 10px;
+  font-size: 12px;
 }
 
 .mini-tabs button:hover:not(.active) {
@@ -682,15 +688,21 @@ button {
   box-shadow: 0 0 12px rgba(0, 220, 255, 0.3);
 }
 
+.quality-tabs {
+  flex-wrap: wrap;
+  justify-content: flex-end;
+  max-width: 280px;
+}
+
 .quality-tabs button {
-  min-width: 0;
-  padding-left: 7px;
-  padding-right: 7px;
+  min-width: 72px;
+  padding-left: 10px;
+  padding-right: 10px;
 }
 
 .legend-dot {
   color: #8ebfd8;
-  font-size: 10px;
+  font-size: 12px;
 }
 
 .legend-dot i {
@@ -769,17 +781,18 @@ button {
   }
   .header-toolbar {
     gap: 10px;
-    min-height: 48px;
-    padding: 7px 12px;
+    min-height: 52px;
+    padding: 8px 12px;
   }
   .analysis-nav button {
-    min-width: 72px;
-    padding-right: 10px;
-    padding-left: 10px;
+    min-width: 80px;
+    padding-right: 12px;
+    padding-left: 12px;
+    font-size: 13px;
   }
   .metric-card {
-    min-height: 90px;
-    padding: 11px 10px;
+    min-height: 98px;
+    padding: 12px 12px 26px;
   }
   .metric-icon {
     flex-basis: 34px;
@@ -788,7 +801,7 @@ button {
     font-size: 16px;
   }
   .metric-copy strong {
-    font-size: 22px;
+    font-size: 24px;
   }
   .panel {
     padding: 11px 12px 6px;

+ 88 - 56
src/views/hrAnalysis/personnelStructureDashboard/index.vue

@@ -421,12 +421,15 @@ export default {
         backgroundColor: "rgba(4, 18, 36, .94)",
         borderColor: "rgba(0, 210, 255, .35)",
         borderWidth: 1,
-        padding: [10, 12],
-        textStyle: { color: "#e8f7ff", fontSize: 12, lineHeight: 20 },
+        padding: [10, 14],
+        textStyle: { color: "#e8f7ff", fontSize: 13, lineHeight: 22 },
         extraCssText:
           "box-shadow: 0 0 18px rgba(0,180,255,.18); border-radius: 4px;",
       };
     },
+    axisLabel(extra = {}) {
+      return { color: TEXT, fontSize: 12, ...extra };
+    },
     renderTrendChart() {
       const chart = this.charts.trend;
       if (!chart) return;
@@ -446,26 +449,30 @@ export default {
                 items[0].value
               }${isEfficiency ? "%" : " 人"}</b>`,
           },
-          grid: { left: 44, right: 18, top: 30, bottom: 38 },
+          grid: {
+            left: 12,
+            right: 16,
+            top: 28,
+            bottom: 8,
+            containLabel: true,
+          },
           xAxis: {
             type: "category",
             boundaryGap: false,
             data: this.dashboard.trend.months,
             axisLine: { lineStyle: { color: AXIS } },
             axisTick: { show: false },
-            axisLabel: {
-              color: TEXT,
-              fontSize: 10,
-              rotate: 25,
+            axisLabel: this.axisLabel({
               margin: 12,
-            },
+              formatter: (value) => String(value).slice(2).replace("-", "/"),
+            }),
           },
           yAxis: {
             type: "value",
             min: isEfficiency ? 70 : null,
             axisLine: { show: false },
             axisTick: { show: false },
-            axisLabel: { color: TEXT, fontSize: 10 },
+            axisLabel: this.axisLabel(),
             splitLine: { lineStyle: { color: GRID, type: "dashed" } },
           },
           series: [
@@ -518,23 +525,27 @@ export default {
           },
           legend: {
             orient: "vertical",
-            right: 4,
-            top: "center",
+            right: 8,
+            top: "middle",
             icon: "circle",
-            itemWidth: 8,
-            itemHeight: 8,
+            itemWidth: 10,
+            itemHeight: 10,
             itemGap: 14,
-            textStyle: { color: TEXT, fontSize: 11 },
+            textStyle: { color: TEXT, fontSize: 13, lineHeight: 20 },
+            formatter: (name) => {
+              const hit = data.find((item) => item.name === name);
+              return hit ? `${name}  ${hit.value}人` : name;
+            },
           },
           series: [
             {
               type: "pie",
-              radius: ["50%", "69%"],
-              center: ["39%", "54%"],
+              radius: ["42%", "66%"],
+              center: ["34%", "52%"],
               avoidLabelOverlap: true,
-              minAngle: 5,
-              label: { color: LABEL, fontSize: 10, formatter: "{b}\n{c}" },
-              labelLine: { length: 8, length2: 5, lineStyle: { color: "rgba(0,200,255,.35)" } },
+              minAngle: 8,
+              label: { show: false },
+              labelLine: { show: false },
               itemStyle: {
                 borderColor: "#041222",
                 borderWidth: 3,
@@ -572,38 +583,47 @@ export default {
             formatter: (items) =>
               `${items[0].axisValue}<br/>实际人数:<b>${items[0].value} 人</b>`,
           },
-          grid: { left: 43, right: 14, top: 18, bottom: 62 },
-          xAxis: {
-            type: "category",
-            data: this.dashboard.departments.map((item) => item.name),
-            axisTick: { show: false },
-            axisLine: { lineStyle: { color: AXIS } },
-            axisLabel: {
-              color: TEXT,
-              fontSize: 9,
-              interval: 0,
-              rotate: 30,
-            },
+          grid: {
+            left: 8,
+            right: 40,
+            top: 8,
+            bottom: 8,
+            containLabel: true,
           },
-          yAxis: {
+          xAxis: {
             type: "value",
             axisLine: { show: false },
             axisTick: { show: false },
-            axisLabel: { color: TEXT, fontSize: 10 },
+            axisLabel: this.axisLabel(),
             splitLine: { lineStyle: { color: GRID } },
           },
+          yAxis: {
+            type: "category",
+            inverse: true,
+            data: this.dashboard.departments.map((item) => item.name),
+            axisTick: { show: false },
+            axisLine: { lineStyle: { color: AXIS } },
+            axisLabel: this.axisLabel({ interval: 0, margin: 10 }),
+          },
           series: [
             {
               type: "bar",
               data,
-              barMaxWidth: 24,
+              barMaxWidth: 16,
+              label: {
+                show: true,
+                position: "right",
+                color: LABEL,
+                fontSize: 12,
+                distance: 6,
+              },
               itemStyle: {
-                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
-                  { offset: 0, color: "#7af6ff" },
-                  { offset: 0.45, color: "#1ec8ff" },
-                  { offset: 1, color: "#0a5f9e" },
+                color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
+                  { offset: 0, color: "#0a5f9e" },
+                  { offset: 0.55, color: "#1ec8ff" },
+                  { offset: 1, color: "#7af6ff" },
                 ]),
-                borderRadius: [3, 3, 0, 0],
+                borderRadius: [0, 3, 3, 0],
                 shadowBlur: 12,
                 shadowColor: "rgba(30,200,255,.4)",
               },
@@ -649,19 +669,25 @@ export default {
             formatter: (items) =>
               `${items[0].axisValue}<br/>人数:<b>${items[0].value} 人</b>`,
           },
-          grid: { left: 42, right: 80, top: 18, bottom: 42 },
+          grid: {
+            left: 8,
+            right: 12,
+            top: 36,
+            bottom: 8,
+            containLabel: true,
+          },
           xAxis: {
             type: "category",
             data: this.dashboard.talent.map((item) => item.name),
             axisTick: { show: false },
             axisLine: { lineStyle: { color: AXIS } },
-            axisLabel: { color: TEXT, fontSize: 10 },
+            axisLabel: this.axisLabel(),
           },
           yAxis: {
             type: "value",
             axisLine: { show: false },
             axisTick: { show: false },
-            axisLabel: { color: TEXT, fontSize: 10 },
+            axisLabel: this.axisLabel(),
             splitLine: { lineStyle: { color: GRID } },
           },
           series: [
@@ -674,7 +700,8 @@ export default {
                 show: true,
                 position: "top",
                 color: LABEL,
-                fontSize: 10,
+                fontSize: 12,
+                distance: 6,
                 textShadowColor: "rgba(0,180,255,.7)",
                 textShadowBlur: 6,
               },
@@ -708,24 +735,28 @@ export default {
           },
           legend: {
             orient: "vertical",
-            right: 2,
-            top: "center",
+            right: 8,
+            top: "middle",
             icon: "circle",
-            itemWidth: 8,
-            itemHeight: 8,
-            itemGap: 10,
-            textStyle: { color: TEXT, fontSize: 10 },
+            itemWidth: 10,
+            itemHeight: 10,
+            itemGap: 12,
+            textStyle: { color: TEXT, fontSize: 13, lineHeight: 20 },
+            formatter: (name) => {
+              const hit = data.find((item) => item.name === name);
+              return hit ? `${name}  ${hit.value}人` : name;
+            },
           },
           graphic: [
             {
               type: "text",
-              left: "36%",
+              left: "34%",
               top: "48%",
               style: {
                 text: `${data.reduce((sum, item) => sum + item.value, 0)} 人`,
                 textAlign: "center",
                 fill: "#b7e9ff",
-                font: "600 15px sans-serif",
+                font: "600 16px sans-serif",
                 textShadowColor: "rgba(0,200,255,.6)",
                 textShadowBlur: 8,
               },
@@ -734,9 +765,12 @@ export default {
           series: [
             {
               type: "pie",
-              radius: ["53%", "70%"],
-              center: ["39%", "55%"],
-              minAngle: 4,
+              radius: ["42%", "66%"],
+              center: ["34%", "50%"],
+              minAngle: 8,
+              avoidLabelOverlap: true,
+              label: { show: false },
+              labelLine: { show: false },
               itemStyle: {
                 borderColor: "#041222",
                 borderWidth: 3,
@@ -750,8 +784,6 @@ export default {
                   shadowColor: "rgba(0,220,255,.45)",
                 },
               },
-              label: { color: LABEL, fontSize: 10, formatter: "{b}\n{c}" },
-              labelLine: { length: 8, length2: 5, lineStyle: { color: "rgba(0,200,255,.35)" } },
               data,
             },
           ],