fix(aihr): paginate org snapshot view

This commit is contained in:
2026-07-09 10:50:19 +08:00
parent 678543e8a5
commit 82f861542f
5 changed files with 37 additions and 9 deletions
@@ -30,7 +30,9 @@ public class AihrOrgSyncController {
@RequestParam(required = false) String projectCode, @RequestParam(required = false) String projectCode,
@RequestParam(required = false) String positionLevel, @RequestParam(required = false) String positionLevel,
@RequestParam(required = false) String status, @RequestParam(required = false) String status,
@RequestParam(required = false, defaultValue = "1") Integer pageNum,
@RequestParam(required = false) Integer pageSize,
@RequestParam(required = false, defaultValue = "200") Integer limit) { @RequestParam(required = false, defaultValue = "200") Integer limit) {
return R.ok(orgSyncService.snapshot(keyword, projectCode, positionLevel, status, limit)); return R.ok(orgSyncService.snapshot(keyword, projectCode, positionLevel, status, pageNum, pageSize, limit));
} }
} }
@@ -35,6 +35,8 @@ public final class AihrOrgSyncDto {
int total, int total,
int active, int active,
int departed, int departed,
int pageNum,
int pageSize,
List<OrgProjectOption> projects, List<OrgProjectOption> projects,
List<String> levels, List<String> levels,
List<OrgPersonRow> rows List<OrgPersonRow> rows
@@ -113,16 +113,20 @@ public class AihrOrgSyncService {
); );
} }
public OrgSnapshotResponse snapshot(String keyword, String projectCode, String positionLevel, String status, Integer limit) { public OrgSnapshotResponse snapshot(String keyword, String projectCode, String positionLevel, String status,
Integer pageNum, Integer pageSize, Integer limit) {
requireSnapshotTable(); requireSnapshotTable();
int safeLimit = clamp(limit, 200, 1, MAX_PAGE_SIZE); int safePageNum = clamp(pageNum, 1, 1, 100000);
int safePageSize = clamp(pageSize == null ? limit : pageSize, 20, 1, MAX_PAGE_SIZE);
int offset = (safePageNum - 1) * safePageSize;
List<Object> args = new ArrayList<>(); List<Object> args = new ArrayList<>();
String where = orgSnapshotWhere(keyword, projectCode, positionLevel, status, args); String where = orgSnapshotWhere(keyword, projectCode, positionLevel, status, args);
int total = countOrgRows("select count(*) from aihr_org_snapshot" + where, args); int total = countOrgRows("select count(*) from aihr_org_snapshot" + where, args);
int active = countOrgRows("select count(*) from aihr_org_snapshot" + where + " and employment_status = 'active'", args); int active = countOrgRows("select count(*) from aihr_org_snapshot" + where + " and employment_status = 'active'", args);
int departed = countOrgRows("select count(*) from aihr_org_snapshot" + where + " and employment_status = 'departed'", args); int departed = countOrgRows("select count(*) from aihr_org_snapshot" + where + " and employment_status = 'departed'", args);
List<Object> rowArgs = new ArrayList<>(args); List<Object> rowArgs = new ArrayList<>(args);
rowArgs.add(safeLimit); rowArgs.add(safePageSize);
rowArgs.add(offset);
List<OrgPersonRow> rows = jdbcTemplate.query(""" List<OrgPersonRow> rows = jdbcTemplate.query("""
select id, project_code, project_name, dept_name, ext_party_id, person_name, select id, project_code, project_name, dept_name, ext_party_id, person_name,
position_name, position_level, employment_status, position_name, position_level, employment_status,
@@ -130,7 +134,7 @@ public class AihrOrgSyncService {
from aihr_org_snapshot from aihr_org_snapshot
""" + where + """ """ + where + """
order by project_name, dept_name, position_level, person_name order by project_name, dept_name, position_level, person_name
limit ? limit ? offset ?
""", (rs, rowNum) -> new OrgPersonRow( """, (rs, rowNum) -> new OrgPersonRow(
rs.getLong("id"), rs.getLong("id"),
rs.getString("project_code"), rs.getString("project_code"),
@@ -143,7 +147,7 @@ public class AihrOrgSyncService {
rs.getString("employment_status"), rs.getString("employment_status"),
rs.getString("snapshot_date") rs.getString("snapshot_date")
), rowArgs.toArray()); ), rowArgs.toArray());
return new OrgSnapshotResponse(total, active, departed, orgProjects(), orgLevels(), rows); return new OrgSnapshotResponse(total, active, departed, safePageNum, safePageSize, orgProjects(), orgLevels(), rows);
} }
private List<JsonNode> fetchOptional(String baseUrl, String token, SyncRequest req, String resourceType, private List<JsonNode> fetchOptional(String baseUrl, String token, SyncRequest req, String resourceType,
+4
View File
@@ -138,6 +138,8 @@ export type OrgSnapshotParams = {
projectCode?: string; projectCode?: string;
positionLevel?: string; positionLevel?: string;
status?: string; status?: string;
pageNum?: number;
pageSize?: number;
limit?: number; limit?: number;
}; };
@@ -145,6 +147,8 @@ export type OrgSnapshotResponse = {
total: number; total: number;
active: number; active: number;
departed: number; departed: number;
pageNum: number;
pageSize: number;
projects: OrgProjectOption[]; projects: OrgProjectOption[];
levels: string[]; levels: string[];
rows: OrgPersonRow[]; rows: OrgPersonRow[];
+19 -3
View File
@@ -29,7 +29,7 @@
</div> </div>
</div> </div>
<div class="org-filters"> <div class="org-filters">
<el-input v-model="orgFilters.keyword" clearable placeholder="姓名/岗位/部门/外部ID" @keyup.enter="loadOrgSnapshot" /> <el-input v-model="orgFilters.keyword" clearable placeholder="姓名/岗位/部门/外部ID" @keyup.enter="searchOrgSnapshot" />
<el-select v-model="orgFilters.projectCode" clearable placeholder="项目"> <el-select v-model="orgFilters.projectCode" clearable placeholder="项目">
<el-option v-for="item in orgSnapshot?.projects || []" :key="item.projectCode" :label="item.projectName" :value="item.projectCode" /> <el-option v-for="item in orgSnapshot?.projects || []" :key="item.projectCode" :label="item.projectName" :value="item.projectCode" />
</el-select> </el-select>
@@ -40,7 +40,7 @@
<el-option label="在职" value="active" /> <el-option label="在职" value="active" />
<el-option label="离职" value="departed" /> <el-option label="离职" value="departed" />
</el-select> </el-select>
<el-button :icon="Refresh" :loading="orgLoading" @click="loadOrgSnapshot">查询</el-button> <el-button :icon="Refresh" :loading="orgLoading" @click="searchOrgSnapshot">查询</el-button>
</div> </div>
<el-table v-loading="orgLoading" :data="orgSnapshot?.rows || []" size="small" empty-text="暂无组织人员快照"> <el-table v-loading="orgLoading" :data="orgSnapshot?.rows || []" size="small" empty-text="暂无组织人员快照">
<el-table-column prop="projectName" label="项目" min-width="150" show-overflow-tooltip /> <el-table-column prop="projectName" label="项目" min-width="150" show-overflow-tooltip />
@@ -58,6 +58,13 @@
<el-table-column prop="extPartyId" label="外部主体ID" min-width="150" show-overflow-tooltip /> <el-table-column prop="extPartyId" label="外部主体ID" min-width="150" show-overflow-tooltip />
<el-table-column prop="snapshotDate" label="快照日期" width="110" /> <el-table-column prop="snapshotDate" label="快照日期" width="110" />
</el-table> </el-table>
<pagination
v-show="(orgSnapshot?.total || 0) > 0"
v-model:page="orgPage.pageNum"
v-model:limit="orgPage.pageSize"
:total="orgSnapshot?.total || 0"
@pagination="loadOrgSnapshot"
/>
</section> </section>
<section class="main-grid"> <section class="main-grid">
@@ -147,6 +154,10 @@ const orgFilters = reactive({
positionLevel: '', positionLevel: '',
status: 'active' status: 'active'
}); });
const orgPage = reactive({
pageNum: 1,
pageSize: 20
});
const metrics = [ const metrics = [
{ label: '权威组织源', value: '快照', note: '阶段三前用 aihr_org_snapshot' }, { label: '权威组织源', value: '快照', note: '阶段三前用 aihr_org_snapshot' },
@@ -180,7 +191,7 @@ const projectScopes = computed(() =>
const loadOrgSnapshot = async () => { const loadOrgSnapshot = async () => {
orgLoading.value = true; orgLoading.value = true;
try { try {
const result = await getOrgSnapshot({ ...orgFilters, limit: 200 }); const result = await getOrgSnapshot({ ...orgFilters, pageNum: orgPage.pageNum, pageSize: orgPage.pageSize });
orgSnapshot.value = result.data; orgSnapshot.value = result.data;
} catch (error) { } catch (error) {
ElMessage.error('组织人员快照加载失败'); ElMessage.error('组织人员快照加载失败');
@@ -189,6 +200,11 @@ const loadOrgSnapshot = async () => {
} }
}; };
const searchOrgSnapshot = () => {
orgPage.pageNum = 1;
loadOrgSnapshot();
};
const runSync = async () => { const runSync = async () => {
if (!dryRun.value) { if (!dryRun.value) {
await ElMessageBox.confirm('写入模式会覆盖当前租户组织快照,确认继续吗?', '组织同步', { type: 'warning' }); await ElMessageBox.confirm('写入模式会覆盖当前租户组织快照,确认继续吗?', '组织同步', { type: 'warning' });