|
|
@@ -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() {
|