Procházet zdrojové kódy

员工档案组织树放开为全公司 + 所属机构数据源切换 orgVO + 表格自适应铺满页面

组织树与范围裁剪:
- 删除 scopeOrganizationTree 裁剪逻辑,树直接展示 getGroupListWithUserCount 全量返回
- 初始视图选中「全部员工」(selectedOrganizationId=''),不再默认定位到登录机构
- selectAllOrganizations 改为真正清空选择(不传 groupId)
- metricsTotal 改取组织树顶层节点 userCount 之和(原登录机构节点口径随之作废)

所属机构数据源切换(2026-10-26 用户指定):
- current-org.js:从 loginChangeGroupVOList(只回部门)切到 orgVO(单条公司级机构)
- getLoginGroups / getLoginOrgs 合并为 getLoginOrgs,getOrgOptions / getCurrentOrgId 同步改读 orgVO.id
- login-org-cache.js:镜像升级为登录接口全量 info(原来只存机构列表),readLoginOrgs 保留兼容旧格式

员工档案页面调整:
- 表格高度自适应:mounted/resize/treeCollapsed 动态计算,视口铺满,原固定 520px 作废
- 新增 affiDeptId: 1 固定传参(用户指定)
- 勾选列宽 56→30、操作列 140→100,工具栏去掉 min-height/padding
- cacheKey bump 到 v4(列宽/工具栏变更)

样式:
- 外层 .el-card__body padding 归零,左树右表间距 18→8px

其他:
- 薪资档案总览删除「接口返回但匹配不上」口径提示(分页匹配必然误报)
- vue.config.js 代理目标改 192.168.1.113:18086
lihaiting před 1 týdnem
rodič
revize
646053b866

+ 11 - 4
src/styles/views/employeeArchive/index.scss

@@ -7,6 +7,9 @@
   color: var(--ink);
   background: transparent;
 }
+/* 外层 el-card 的 body 留白归零:内层组织/表格面板自带边框圆角,
+   外面再包 20px 会形成双重留白(办理入职是内容直接放 body 里,没有这层) */
+.employee-archive-page ::v-deep .el-card__body { padding: 0; }
 .metric-grid { position: relative; z-index: 2; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; margin-bottom: 18px; }
 .metric-card { position: relative; min-height: 96px; display: flex; align-items: center; gap: 14px; padding: 18px 20px; overflow: hidden; border: 1px solid rgba(211, 221, 235, .78); border-radius: 15px; background: rgba(255, 255, 255, .96); box-shadow: 0 10px 26px rgba(37, 67, 111, .07); transition: transform .2s ease, box-shadow .2s ease; }
 .metric-card:hover { transform: translateY(-2px); box-shadow: 0 15px 30px rgba(37, 67, 111, .11); }
@@ -23,7 +26,8 @@
 .filter-panel { position: relative; z-index: 3; margin-bottom: 18px; padding: 15px 17px; border: 1px solid #e0e7f1; border-radius: 14px; background: #fff; box-shadow: 0 8px 24px rgba(40, 67, 106, .05); }
 .filter-grid { display: grid; grid-template-columns: minmax(210px, 1.4fr) 130px 110px minmax(260px, 1fr) auto auto; gap: 9px; }
 .hire-range { width: 260px !important; }
-.archive-workspace { display: grid; grid-template-columns: 286px minmax(0, 1fr); align-items: stretch; gap: 18px; }
+/* 左树与右表之间的间距收窄(2026-10-26 用户要求):18px → 8px */
+.archive-workspace { display: grid; grid-template-columns: 286px minmax(0, 1fr); align-items: stretch; gap: 8px; }
 .organization-panel {
   overflow: hidden;
   border: 1px solid #e0e7f1;
@@ -68,7 +72,7 @@
 .collapsed .panel-heading { justify-content: center; border: 0; padding-bottom: 8px; }
 .collapsed-tree-button { width: 40px; min-height: 90px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; border: 0; border-radius: 4px; color: #607087; background: #f4f6f9; cursor: pointer; }
 .collapsed-tree-button span { writing-mode: vertical-rl; font-size: 14px; }
-.table-panel { min-width: 0; overflow: hidden; padding-top: 0; }
+.table-panel { min-width: 0; overflow: hidden; padding: 14px 0 0; }
 .table-toolbar-actions { display: flex; align-items: center; justify-content: flex-start; flex-wrap: nowrap; gap: 8px; margin-right: 12px; white-space: nowrap; }
 .selected-count { color: #1890ff; font-size: 14px; }
 .active-filters { min-height: 41px; display: flex; align-items: center; flex-wrap: wrap; gap: 7px; margin: 0 20px 12px; padding: 8px 12px; border: 1px solid #dfebfa; border-radius: 8px; background: #f7faff; }
@@ -76,7 +80,9 @@
 .active-filters button { margin-left: auto; border: 0; color: #1890ff; font-size: 14px; background: none; cursor: pointer; }
 .employee-table { width: 100%; }
 .employee-table::before { display: none; }
-.employee-table ::v-deep .ele-table-tool { min-height: 70px; padding: 13px 20px; border-bottom: 1px solid #e8edf3; }
+/* 工具栏不加 min-height / padding(2026-10-26 用户在 DevTools 里对比后拍板去掉,
+   保留组件库默认高度即可),只留下分隔线 */
+.employee-table ::v-deep .ele-table-tool { border-bottom: 1px solid #e8edf3; }
 .employee-table ::v-deep .ele-table-tool-title { min-width: 0; align-items: center; }
 /* 工具栏按钮之间留出间距(导入/导出被 el-dropdown 包裹,默认的 el-button 相邻间距不生效) */
 .employee-table ::v-deep .ele-table-tool-title-content { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
@@ -89,7 +95,8 @@
 .employee-table ::v-deep .el-table__row:hover > td.el-table__cell { background: #f2f7ff !important; }
 .employee-table ::v-deep td.el-table__cell, .employee-table ::v-deep th.el-table__cell { border-bottom-color: #edf0f3; }
 .employee-table ::v-deep .el-table__row { cursor: default; }
-.employee-table ::v-deep .el-table-column--selection .cell { padding-left: 13px; padding-right: 13px; text-align: center; }
+/* 勾选列宽 30(2026-10-26 用户要求减半):内边距同步收紧,否则 13px 左右 padding 会挤掉复选框 */
+.employee-table ::v-deep .el-table-column--selection .cell { padding-left: 4px; padding-right: 4px; text-align: center; }
 .employee-table ::v-deep .el-table-column--selection .el-checkbox { margin: 0; }
 .employee-cell { min-width: 0; display: flex; align-items: center; gap: 10px; padding: 0; border: 0; color: inherit; text-align: left; background: none; cursor: pointer; }
 .table-avatar { width: 38px; height: 38px; flex: 0 0 auto; display: grid; place-items: center; overflow: hidden; border: 2px solid #fff; border-radius: 11px; box-shadow: 0 5px 12px rgba(35, 91, 160, .16); color: #fff; font-size: 14px; font-weight: 600; background: var(--avatar-color); }

+ 30 - 26
src/utils/current-org.js

@@ -1,22 +1,24 @@
 /**
  * 登录用户所属机构(统一口径:读登录缓存,不调组织列表接口)
  *
- * 数据来源:登录接口返回的 loginChangeGroupVOList,
+ * 数据来源:登录接口返回的 orgVO(公司级机构,2026-10-26 用户指定),
  * 由 vuex-persistedstate 写入 sessionStorage(key 对齐 store/index.js):
- *   { user: { info: { loginChangeGroupVOList: [{ groupId, groupName, loginChangeRoleVOList }] } } }
+ *   { user: { info: { orgVO: { id, name, code, type } } } }
  * 独立运行:private-vuex-hr;乾坤子应用:vuex-hr
  *
  * 兜底:sessionStorage / localStorage 都没有时,读 utils/login-org-cache.js 的
- * localStorage 镜像(同一次登录时写入),避免新标签页出现「机构只剩 1 个」的半登录态。
+ * localStorage 镜像(同一次登录时写入的全量 info),避免新标签页出现「机构为空」的半登录态。
  *
  * 约定:
- * 1. 所有「所属机构」下拉选项一律取 loginChangeGroupVOList,不再调 /main/group/getGroupList;
- * 2. 接口需要的所属机构 id 默认取缓存机构列表第一条(用户所属机构有多个时默认第一个),
- *    缓存机构列表缺失时才回落到 currentUser.currentGroupId(登录/顶栏切换机构写入)。
+ * 1. 所有「所属机构」下拉选项一律取缓存 orgVO(单条,包成数组对外),不再调
+ *    /main/group/getGroupList;原 loginChangeGroupVOList 口径作废(其后端只回部门,
+ *    且 2026-10-26 起不再承担「所属机构」语义)。
+ * 2. 接口需要的所属机构 id 取 orgVO.id;orgVO 缺失时才回落到
+ *    currentUser.currentGroupId(登录/顶栏切换机构写入)。
  */
 import { SYSTEM_NAME } from '@/config/setting';
 import { getCurrentUser } from '@/utils/token-util';
-import { readLoginOrgs } from '@/utils/login-org-cache';
+import { readLoginUserInfo } from '@/utils/login-org-cache';
 
 /** vuex 持久化缓存键(顺序即读取优先级) */
 function vuexCacheKeys() {
@@ -29,7 +31,7 @@ function isValidId(value) {
   return value !== undefined && value !== null && value !== '' && Number(value) !== 0;
 }
 
-/** 读取 vuex 持久化缓存中的登录用户信息(含 loginChangeGroupVOList) */
+/** 读取 vuex 持久化缓存中的登录用户信息(含 orgVO) */
 export function getLoginUserInfo() {
   for (const key of vuexCacheKeys()) {
     const raw = sessionStorage.getItem(key) || localStorage.getItem(key);
@@ -44,36 +46,38 @@ export function getLoginUserInfo() {
   return {};
 }
 
-/** 登录缓存中的可选机构列表(loginChangeGroupVOList 原始结构) */
-export function getLoginGroups() {
-  const cached = getLoginUserInfo().loginChangeGroupVOList;
-  /* 缓存列表缺失(如新标签页 sessionStorage 为空)时,用 localStorage 镜像兜底 */
-  const list =
-    Array.isArray(cached) && cached.length ? cached : readLoginOrgs();
-  if (!Array.isArray(list)) return [];
-  return list.filter((item) => item && isValidId(item.groupId));
+/** 读取缓存中的 orgVO:vuex 缓存优先,缺失时用 localStorage 镜像兜底 */
+function readOrgVO() {
+  const cached = getLoginUserInfo().orgVO;
+  if (cached && typeof cached === 'object') return cached;
+  return readLoginUserInfo()?.orgVO || null;
 }
 
-/** 机构下拉选项:[{ id, name }](id 即 groupId,name 兼容 groupName / name / organName) */
+/** 登录缓存中的所属机构(orgVO 包成单元素数组;orgVO 缺失返回空数组,由空暴露后端缺口) */
+export function getLoginOrgs() {
+  const org = readOrgVO();
+  return org && isValidId(org.id) ? [org] : [];
+}
+
+/** 机构下拉选项:[{ id, name }](id 即 orgVO.id,name 即 orgVO.name) */
 export function getOrgOptions() {
-  const options = getLoginGroups().map((item) => ({
-    id: item.groupId,
-    name: item.groupName || item.name || item.organName || item.orgName || '',
+  const options = getLoginOrgs().map((org) => ({
+    id: org.id,
+    name: org.name || '',
   }));
   if (options.length) return options;
-  /* 兜底:缓存机构列表缺失时至少保留当前登录机构,避免下拉与默认筛选值为空 */
+  /* 兜底:缓存机构缺失时至少保留当前登录机构,避免下拉与默认筛选值为空 */
   const currentGroupId = getCurrentOrgId();
   return isValidId(currentGroupId) ? [{ id: currentGroupId, name: '' }] : options;
 }
 
 /**
- * 当前登录用户所属机构 id:
- * 优先取登录缓存机构列表(loginChangeGroupVOList)第一条——用户所属多个机构时默认第一个;
- * 缓存机构列表缺失时回落到登录/顶栏切换机构写入的 currentGroupId。
+ * 当前登录用户所属机构 id:取登录缓存 orgVO.id;
+ * orgVO 缺失时回落到登录/顶栏切换机构写入的 currentUser.currentGroupId。
  */
 export function getCurrentOrgId() {
-  const first = getLoginGroups()[0];
-  if (first) return first.groupId;
+  const org = getLoginOrgs()[0];
+  if (org) return org.id;
   const current = getCurrentUser() || {};
   return isValidId(current.currentGroupId) ? current.currentGroupId : undefined;
 }

+ 24 - 14
src/utils/login-org-cache.js

@@ -1,5 +1,5 @@
 /**
- * 「所属机构」列表的持久化镜像(localStorage)
+ * 登录用户信息的持久化镜像(localStorage,2026-10-26 起为登录返回的**全量 info**)
  *
  * 背景:
  * 「所属机构」下拉的数据源是 user.info.loginChangeGroupVOList,由 vuex-persistedstate
@@ -25,37 +25,47 @@
 const STORE_KEY = 'hr-login-orgs';
 
 /**
- * 写入机构列表镜像
- * @param {object} info 登录用户信息(含 loginChangeGroupVOList)
+ * 写入登录信息镜像
+ *
+ * 2026-10-26 起镜像升级为登录接口返回的**全量 info**(原来只存 loginChangeGroupVOList),
+ * 跨标签页 / 半登录态时组织机构等所有登录数据都可用。仍要求机构列表非空才写入,
+ * 避免半空数据覆盖旧镜像。
+ * @param {object} info 登录接口返回的完整 data(含 token、loginChangeGroupVOList、groupVos 等)
  */
 export function saveLoginOrgs(info) {
   const list = info && info.loginChangeGroupVOList;
   if (!Array.isArray(list) || !list.length) return;
   try {
-    localStorage.setItem(
-      STORE_KEY,
-      JSON.stringify({ loginChangeGroupVOList: list }),
-    );
+    localStorage.setItem(STORE_KEY, JSON.stringify(info));
   } catch (error) {
     // 隐私模式 / 存储配额满:镜像写不进去不影响主流程
   }
 }
 
 /**
- * 读取机构列表镜像
- * @returns {Array} loginChangeGroupVOList 原始结构;没有则空数组
+ * 读取全量登录信息镜像
+ * @returns {object|null} 登录接口返回的完整 data;没有则 null
  */
-export function readLoginOrgs() {
+export function readLoginUserInfo() {
   try {
     const raw = localStorage.getItem(STORE_KEY);
-    if (!raw) return [];
-    const list = JSON.parse(raw)?.loginChangeGroupVOList;
-    return Array.isArray(list) ? list : [];
+    if (!raw) return null;
+    const parsed = JSON.parse(raw);
+    return parsed && typeof parsed === 'object' ? parsed : null;
   } catch (error) {
-    return [];
+    return null;
   }
 }
 
+/**
+ * 读取机构列表镜像
+ * @returns {Array} loginChangeGroupVOList 原始结构(兼容旧格式镜像,只存过机构列表);没有则空数组
+ */
+export function readLoginOrgs() {
+  const list = readLoginUserInfo()?.loginChangeGroupVOList;
+  return Array.isArray(list) ? list : [];
+}
+
 /** 清除机构列表镜像(登出时调用) */
 export function clearLoginOrgs() {
   try {

+ 69 - 45
src/views/hrManagement/employeeArchive/index.vue

@@ -84,7 +84,7 @@
             </el-row>
           </el-form>
           <ele-pro-table ref="table" row-key="id" :columns="columns" :datasource="fetchPage" :need-page="true"
-            :init-load="false" :page-size="20" :height="520" :cache-key="$tableCacheKey(cacheKeyUrl)" stripe
+            :init-load="false" :page-size="20" :height="tableHeight" :cache-key="$tableCacheKey(cacheKeyUrl)" stripe
             class="employee-table" @selection-change="selectedRows = $event">
             <template v-slot:toolbar>
               <el-button v-if="$hasPermission('main:hrEmployee:save')" type="primary" icon="el-icon-plus"
@@ -217,6 +217,8 @@ export default {
       treeProps: { children: 'children', label: 'name' },
       treeKeyword: '',
       treeCollapsed: false,
+      /* 表格高度自适应:初始给个兜底值,mounted 后按视口剩余空间动态计算(见 computeTableHeight) */
+      tableHeight: 520,
       selectedOrganizationId: '',
       /* 可见机构范围:登录缓存所属机构列表(员工档案只能看自己所属机构的人) */
       scopedOrgs: [],
@@ -224,7 +226,7 @@ export default {
       defaultOrganizationId: '',
       filters: { keyword: '', status: '', gender: '', hireRange: [] },
       appliedFilters: { keyword: '', status: '', gender: '', hireRange: [] },
-      cacheKeyUrl: 'hr-pc-employee-archive-v3',
+      cacheKeyUrl: 'hr-pc-employee-archive-v4',
       selectedRows: [],
       formVisible: false,
       editingEmployee: null,
@@ -245,7 +247,10 @@ export default {
     styleResponsive() {
       return this.$store.state.theme?.styleResponsive !== false;
     },
-    /** 登录机构 id:不受组织树选择影响(「全部员工」人数、工号池范围都用它) */
+    /**
+     * 登录机构 id:不受组织树选择影响(工号池范围用它)。
+     * 2026-10-26 起「全部员工」人数不再取登录机构节点(组织树已放开为全公司),改见 metricsTotal。
+     */
     loginOrgId() {
       return this.defaultOrganizationId || this.scopedOrgIds[0] || '';
     },
@@ -254,13 +259,19 @@ export default {
       return this.loginOrgId ? { groupId: this.loginOrgId } : {};
     },
     /**
-     * 「全部员工」人数:取组织列表接口(getGroupListWithUserCount)下发的 userCount,
-     * 与左树节点同一个后端字段,前端不做统计。列表未就绪时返回 null,模板显示「—」。
+     * 「全部员工」人数:组织树顶层节点(公司)下发的 userCount 之和;
+     * 顶层节点缺 userCount 时返回 null(模板显示「—」),前端不做人数统计。
+     * 2026-10-26 组织树放开为全公司后,原「登录机构节点 userCount」口径随之作废。
      */
     metricsTotal() {
-      const node = this.orgById[String(this.loginOrgId)] || null;
-      const count = node?.userCount;
-      return count == null || count === '' ? null : Number(count);
+      const roots = this.organizationTree || [];
+      if (!roots.length) return null;
+      let total = 0;
+      for (const node of roots) {
+        if (node.userCount == null || node.userCount === '') return null;
+        total += Number(node.userCount) || 0;
+      }
+      return total;
     },
     /**
      * 列结构对齐另一套系统的员工列表(2026-10-21 用户拍板):
@@ -270,7 +281,7 @@ export default {
      */
     columns() {
       return [
-        { type: 'selection', width: 56, fixed: 'left', align: 'center', headerAlign: 'center' },
+        { type: 'selection', width: 30, fixed: 'left', align: 'center', headerAlign: 'center' },
         { type: 'index', label: '序号', width: 60, fixed: 'left', align: 'center', headerAlign: 'center' },
         { prop: 'name', label: '姓名', minWidth: 120, fixed: 'left', slot: 'name' },
         { prop: 'company', label: '所属机构', minWidth: 160, showOverflowTooltip: true },
@@ -284,7 +295,7 @@ export default {
         { prop: 'statusName', label: '状态', width: 100, align: 'center', slot: 'status' },
         { prop: 'enabled', label: '是否启用', width: 90, align: 'center', slot: 'enabled' },
         { prop: 'createTime', label: '创建时间', width: 100, align: 'center' },
-        { columnKey: 'action', label: '操作', width: 140, fixed: 'right', align: 'left', resizable: false, slot: 'action' }
+        { columnKey: 'action', label: '操作', width: 100, fixed: 'right', align: 'left', resizable: false, slot: 'action' }
       ];
     },
     currentOrganizationName() {
@@ -310,6 +321,10 @@ export default {
   watch: {
     treeKeyword(value) {
       this.$refs.organizationTree?.filter(value);
+    },
+    /* 收起/展开组织树会改变筛选区布局,表格可用高度要重算 */
+    treeCollapsed() {
+      this.$nextTick(() => this.computeTableHeight());
     }
   },
   created() {
@@ -317,9 +332,39 @@ export default {
     this.bootstrap();
     // 字典不阻塞首屏(首屏仍是「组织列表 + 一页员工」两个请求),异步补齐筛选项
     this.loadFilterStatusOptions();
+    this.handleWindowResize = () => this.computeTableHeight();
+    window.addEventListener('resize', this.handleWindowResize);
+  },
+  mounted() {
+    /* 首帧 + 延迟各算一次:等筛选区/工具栏布局稳定(权限按钮、日期控件渲染会改变顶部偏移) */
+    this.$nextTick(() => this.computeTableHeight());
+    this.tableHeightTimer = setTimeout(() => this.computeTableHeight(), 300);
+  },
+  beforeDestroy() {
+    window.removeEventListener('resize', this.handleWindowResize);
+    clearTimeout(this.tableHeightTimer);
   },
   methods: {
-    /** 可见机构范围:只取登录缓存所属机构列表,默认定位到当前登录机构 */
+    /**
+     * 表格高度自适应(2026-10-26 用户要求铺满页面):
+     * 表格顶部偏移(顶栏+面包屑+筛选+工具栏)是稳定的,
+     * 可用高度 = 视口高度 - 表格顶部偏移 - 分页条高度 - 底部留白。
+     * 树面板与表格同处一行 grid(align stretch),表格变高树跟着铺满。
+     */
+    computeTableHeight() {
+      const root = this.$refs.table?.$el;
+      if (!root) return;
+      /* ★ 必须量 .el-table 本体的顶部:ele-pro-table 根节点还包含工具栏,
+         量根节点会把工具栏高度多算进去,分页条被顶出屏幕 */
+      const tableEl = root.querySelector('.el-table');
+      const top = (tableEl || root).getBoundingClientRect().top;
+      if (!top) return;
+      const pagination = root.querySelector('.el-pagination');
+      const reserve = (pagination ? pagination.offsetHeight : 48) + 14;
+      this.tableHeight = Math.max(window.innerHeight - top - reserve, 360);
+    },
+    /** 可见机构范围:登录缓存所属机构(现在只用于工号池等固定登录机构口径);
+        初始不选中任何组织,「全部员工」即全公司 */
     syncOrgScope() {
       this.scopedOrgs = getOrgOptions();
       this.scopedOrgIds = this.scopedOrgs
@@ -327,7 +372,9 @@ export default {
         .filter(Boolean);
       const currentId = getCurrentOrgId();
       this.defaultOrganizationId = currentId == null ? '' : String(currentId);
-      this.selectedOrganizationId = this.defaultOrganizationId;
+      /* 2026-10-26 用户拍板:组织树放开为全公司,初始视图就是「全部员工」,
+         不再默认定位到登录机构 */
+      this.selectedOrganizationId = '';
     },
     async bootstrap() {
       this.loading = true;
@@ -422,8 +469,8 @@ export default {
         const map = {};
         records.forEach((item) => { map[String(item.id)] = item; });
         this.orgById = map;
-        // 组织树只保留登录机构(连同其下级部门),避免看到其他机构的人员
-        this.organizationTree = this.scopeOrganizationTree(buildOrganizationTree(records));
+        /* 2026-10-26 用户拍板:去掉登录缓存裁剪,树直接展示接口返回的全公司组织 */
+        this.organizationTree = buildOrganizationTree(records);
         this.$nextTick(() => {
           if (this.selectedOrganizationId) {
             this.$refs.organizationTree?.setCurrentKey(this.selectedOrganizationId);
@@ -435,26 +482,7 @@ export default {
         this.$message.error(error.message || '组织架构加载失败');
       }
     },
-    /** 裁剪组织树:只保留登录缓存所属机构节点(命中节点连同其子树整体保留) */
-    scopeOrganizationTree(tree) {
-      const ids = this.scopedOrgIds || [];
-      if (!ids.length) return [];
-      const scoped = [];
-      const walk = (nodes) => {
-        (nodes || []).forEach((node) => {
-          if (ids.includes(String(node.id))) {
-            scoped.push(node);
-            return;
-          }
-          walk(node.children || []);
-        });
-      };
-      walk(tree || []);
-      /* 2026-10-23 用户指出:树里出现「前桥部/研发部」等接口不存在的节点 ——
-         原来这里用登录缓存(scopedOrgs)补接口缺失的节点,属于前端兜底拼数据,
-         已删除:树只展示 getGroupListWithUserCount 实际返回的组织 */
-      return scoped;
-    },
+    /** 2026-10-26 组织树放开为全公司,原 scopeOrganizationTree(按登录缓存裁剪)已删除 */
     /**
      * 员工数据变更后刷新组织列表:人数(userCount)随之更新。
      * 「全部员工」总人数 = 登录机构节点的 userCount,跟着本方法一起刷新,不需要额外请求。
@@ -494,14 +522,9 @@ export default {
         || (keyword && keyword.trim())
       );
     },
-    /** 当前可见机构 id:员工数据的默认查询范围(登录机构,未选中时回落到第一个) */
+    /** 当前选中组织 id:空串 = 「全部员工」(不传 groupId,全公司口径) */
     scopeGroupId() {
-      return (
-        this.selectedOrganizationId ||
-        this.defaultOrganizationId ||
-        this.scopedOrgIds[0] ||
-        ''
-      );
+      return this.selectedOrganizationId || '';
     },
     /** 机构查询参数:所有员工取数都带上,避免返回其他机构的人 */
     scopeParams() {
@@ -512,6 +535,8 @@ export default {
       const { status } = this.appliedFilters;
       const params = {
         ...this.scopeParams(),
+        /* affiDeptId:归属部门 id(2026-10-26 用户指定固定传 1) */
+        affiDeptId: 1,
         // isQueryLZ=1 才会返回离职员工:选中字典里的「离职」项时必须带上,否则筛出来是空的
         isQueryLZ: this.isLeaveStatusValue(status) ? 1 : 0
       };
@@ -654,10 +679,9 @@ export default {
       this.$refs.table?.reload({ page: 1 });
     },
     selectAllOrganizations() {
-      // 可见范围仅限登录机构:这里回到当前登录机构,而不是查全部机构的人
-      const nextOrg = this.defaultOrganizationId || this.scopedOrgIds[0] || '';
-      this.selectedOrganizationId = nextOrg;
-      this.$refs.organizationTree?.setCurrentKey(nextOrg || null);
+      /* 2026-10-26 组织树放开为全公司:「全部员工」真正清空选择(不传 groupId) */
+      this.selectedOrganizationId = '';
+      this.$refs.organizationTree?.setCurrentKey(null);
       this.$refs.table?.reload({ page: 1 });
     },
     applyFilters() {

+ 4 - 6
src/views/salary/employeeArchive/index.vue

@@ -398,15 +398,13 @@ export default {
       this.pricedCount = priced;
       this.unpricedCount = rows.length - priced;
       /*
-       * 空白的成因要能自证:接口正常返回但一条都没匹配上时,必须区分
-       * ① 该机构/基准日下确实没有生效档案(还没定薪);
-       * ② 接口返回了档案,但 userId 与员工列表对不上(字段口径问题,需后端确认)。
-       * 否则用户只会看到一片「—」,无法判断是数据没录还是前端取错了。
+       * 空白成因只需区分一种情况:接口返回 0 条 = 该机构/基准日下确实没有生效档案。
+       * 2026-10-26 用户拍板删除「有档案但当前页没匹配上」的口径提示:
+       * 档案总览是全公司口径、员工列表是分页口径,两者本来就可能匹配不上
+       * (已定薪员工在其他页),按页提示必然误报(实测 12/12 userId 全量可命中)。
        */
       if (!overviewMap.size) {
         this.profileHint = `当前基准日(${this.where.effectiveDate || '今天'})下该机构没有生效中的薪资档案(接口返回 0 条),因此金额/版本列为「—」。如已定薪,请确认生效日期是否晚于基准日。`;
-      } else if (priced === 0) {
-        this.profileHint = `薪资档案接口返回 ${overviewMap.size} 条,但没有任何一条能与当前员工列表的 userId 对上,请检查接口 userId 口径(需后端确认)。`;
       } else {
         this.profileHint = '';
       }

+ 2 - 1
vue.config.js

@@ -42,7 +42,8 @@ function stripProxyCacheHeaders(proxyRes) {
 const apiProxy = resolveApiProxyTarget(
   process.env.VUE_APP_PROXY_TARGET ||
     // "http://192.168.1.147:18086",
-    "http://aiot.zoomwin.com.cn:51001",
+    "http://192.168.1.113:18086",
+    // "http://aiot.zoomwin.com.cn:51001",
 );
 
 // element-ui / ele-admin 仍使用 Sass @import,静音 Dart Sass 弃用警告