新增后台「数据同步」与「学生名册」页
数据同步页 /gxmu/dataSync: - 分段手动同步(部门/教师/班级/学生)+ 全部同步 - 同步为异步:提交后立即返回批次号,每 2 秒轮询 /gxmu/sync/status 展示分段进度 (待执行/进行中/成功/失败 + 成功/失败/停用计数 + 错误摘要) - 页面挂载时先查一次状态,可接管定时任务或别处触发的同步 - 同步记录列表,支持按类型筛选 学生名册页 /gxmu/studentRoster: - 按学院(取组织树 parentId=24)/班级/学号/姓名/培养层次/状态/认领状态筛选 - 手机号与身份证由后端脱敏后返回 - 导出用 gxmu:student:export 单独授权,前端生成 CSV - 支持手动认领与解除认领 对应 api 模块 src/api/gxmu/sync 与 src/api/gxmu/student。
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
import request from '@/utils/request';
|
||||
import type { ApiResult, PageResult } from '@/api';
|
||||
import type { StudentRoster, StudentRosterParam } from './model';
|
||||
|
||||
/** 学生名册分页查询 */
|
||||
export async function pageStudentRoster(params: StudentRosterParam) {
|
||||
const res = await request.get<ApiResult<PageResult<StudentRoster>>>(
|
||||
'/gxmu/student/page',
|
||||
{ params }
|
||||
);
|
||||
if (res.data.code === 0 && res.data.data) {
|
||||
return res.data.data;
|
||||
}
|
||||
return Promise.reject(new Error(res.data.message));
|
||||
}
|
||||
|
||||
/** 学生名册详情 */
|
||||
export async function getStudentRoster(id: number) {
|
||||
const res = await request.get<ApiResult<StudentRoster>>(
|
||||
'/gxmu/student/' + id
|
||||
);
|
||||
if (res.data.code === 0 && res.data.data) {
|
||||
return res.data.data;
|
||||
}
|
||||
return Promise.reject(new Error(res.data.message));
|
||||
}
|
||||
|
||||
/** 导出名册(返回已脱敏列表,由前端生成文件) */
|
||||
export async function exportStudentRoster(params: StudentRosterParam) {
|
||||
const res = await request.post<ApiResult<StudentRoster[]>>(
|
||||
'/gxmu/student/export',
|
||||
null,
|
||||
{ params }
|
||||
);
|
||||
if (res.data.code === 0 && res.data.data) {
|
||||
return res.data.data;
|
||||
}
|
||||
return Promise.reject(new Error(res.data.message));
|
||||
}
|
||||
|
||||
/** 自助认领(学号 + 姓名) */
|
||||
export async function claimStudent(data: { xh: string; xm: string }) {
|
||||
const res = await request.post<ApiResult<unknown>>(
|
||||
'/gxmu/student/claim',
|
||||
data
|
||||
);
|
||||
if (res.data.code === 0) {
|
||||
return res.data.message;
|
||||
}
|
||||
return Promise.reject(new Error(res.data.message));
|
||||
}
|
||||
|
||||
/** 手动认领/改绑 */
|
||||
export async function bindStudent(
|
||||
id: number,
|
||||
data?: { userId?: number; phone?: string }
|
||||
) {
|
||||
const res = await request.put<ApiResult<unknown>>(
|
||||
`/gxmu/student/${id}/claim`,
|
||||
data || {}
|
||||
);
|
||||
if (res.data.code === 0) {
|
||||
return res.data.message;
|
||||
}
|
||||
return Promise.reject(new Error(res.data.message));
|
||||
}
|
||||
|
||||
/** 解除认领 */
|
||||
export async function unbindStudent(id: number) {
|
||||
const res = await request.put<ApiResult<unknown>>(
|
||||
`/gxmu/student/${id}/unclaim`
|
||||
);
|
||||
if (res.data.code === 0) {
|
||||
return res.data.message;
|
||||
}
|
||||
return Promise.reject(new Error(res.data.message));
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* 学生名册(开放平台同步)
|
||||
*/
|
||||
|
||||
/** 学生名册记录 */
|
||||
export interface StudentRoster {
|
||||
id: number;
|
||||
/** 学号 */
|
||||
xh: string;
|
||||
/** 姓名 */
|
||||
xm?: string;
|
||||
/** 性别码 */
|
||||
xbm?: string;
|
||||
/** 性别 */
|
||||
sex?: string;
|
||||
/** 民族码 */
|
||||
mzm?: string;
|
||||
/** 民族 */
|
||||
nation?: string;
|
||||
/** 政治面貌码 */
|
||||
zzmmm?: string;
|
||||
/** 政治面貌 */
|
||||
politics?: string;
|
||||
/** 身份证件号(后端已脱敏) */
|
||||
sfzjh?: string;
|
||||
/** 手机号(后端已脱敏) */
|
||||
sjh?: string;
|
||||
/** 平台班级码 */
|
||||
bjm?: string;
|
||||
/** 平台班号 */
|
||||
bh?: string;
|
||||
classId?: number;
|
||||
className?: string;
|
||||
collegeId?: number;
|
||||
collegeName?: string;
|
||||
dwh?: string;
|
||||
zyh?: string;
|
||||
zymc?: string;
|
||||
/** 培养层次 */
|
||||
pyccmc?: string;
|
||||
/** 状态:1在校 0毕业 */
|
||||
status?: number;
|
||||
/** 已认领的账号ID */
|
||||
userId?: number;
|
||||
claimTime?: string;
|
||||
syncTime?: string;
|
||||
}
|
||||
|
||||
/** 名册查询参数 */
|
||||
export interface StudentRosterParam {
|
||||
page?: number;
|
||||
limit?: number;
|
||||
collegeId?: number;
|
||||
classId?: number;
|
||||
xh?: string;
|
||||
xm?: string;
|
||||
pyccmc?: string;
|
||||
status?: number;
|
||||
claimed?: boolean;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import request from '@/utils/request';
|
||||
import type { ApiResult, PageResult } from '@/api';
|
||||
import type {
|
||||
SyncBatchStatus,
|
||||
SyncRecord,
|
||||
SyncRecordParam
|
||||
} from './model';
|
||||
|
||||
/** 提交类接口统一返回批次号 */
|
||||
async function submit(url: string) {
|
||||
const res = await request.post<ApiResult<string>>(url);
|
||||
if (res.data.code === 0 && res.data.data) {
|
||||
return res.data.data;
|
||||
}
|
||||
return Promise.reject(new Error(res.data.message));
|
||||
}
|
||||
|
||||
/** 提交全部同步,返回批次号 */
|
||||
export function syncAll() {
|
||||
return submit('/gxmu/sync/all');
|
||||
}
|
||||
|
||||
/** 提交部门同步,返回批次号 */
|
||||
export function syncDept() {
|
||||
return submit('/gxmu/sync/dept');
|
||||
}
|
||||
|
||||
/** 提交教师同步,返回批次号 */
|
||||
export function syncTeacher() {
|
||||
return submit('/gxmu/sync/teacher');
|
||||
}
|
||||
|
||||
/** 提交班级同步,返回批次号 */
|
||||
export function syncClass() {
|
||||
return submit('/gxmu/sync/class');
|
||||
}
|
||||
|
||||
/** 提交学生同步,返回批次号 */
|
||||
export function syncStudent() {
|
||||
return submit('/gxmu/sync/student');
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前(或最近一次)批次进度。
|
||||
*
|
||||
* 同步是异步的:学生全量约 9.8 万条、耗时 75~90 秒,提交后需轮询本接口看进度。
|
||||
*/
|
||||
export async function syncStatus() {
|
||||
const res = await request.get<ApiResult<SyncBatchStatus>>('/gxmu/sync/status');
|
||||
if (res.data.code === 0 && res.data.data) {
|
||||
return res.data.data;
|
||||
}
|
||||
return Promise.reject(new Error(res.data.message));
|
||||
}
|
||||
|
||||
/** 同步记录分页查询 */
|
||||
export async function pageSyncRecord(params: SyncRecordParam) {
|
||||
const res = await request.get<ApiResult<PageResult<SyncRecord>>>(
|
||||
'/gxmu/sync/record/page',
|
||||
{ params }
|
||||
);
|
||||
if (res.data.code === 0 && res.data.data) {
|
||||
return res.data.data;
|
||||
}
|
||||
return Promise.reject(new Error(res.data.message));
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* 开放平台数据同步
|
||||
*/
|
||||
|
||||
/** 单段同步结果(同步返回,异步改动后仅用于记录展示) */
|
||||
export interface SyncResult {
|
||||
/** 同步类型:dept/teacher/class/student */
|
||||
syncType: string;
|
||||
/** 成功条数 */
|
||||
successCount: number;
|
||||
/** 失败条数 */
|
||||
failCount: number;
|
||||
/** 跳过/停用条数 */
|
||||
skipCount: number;
|
||||
/** 是否成功 */
|
||||
success: boolean;
|
||||
/** 错误信息 */
|
||||
errorMsg?: string;
|
||||
}
|
||||
|
||||
/** 某一段的进度 */
|
||||
export interface SyncSectionStatus {
|
||||
/** 同步类型:dept/teacher/class/student */
|
||||
syncType: string;
|
||||
/** pending 待执行 / running 进行中 / success 成功 / fail 失败 */
|
||||
state: 'pending' | 'running' | 'success' | 'fail';
|
||||
successCount?: number;
|
||||
failCount?: number;
|
||||
skipCount?: number;
|
||||
startTime?: string;
|
||||
endTime?: string;
|
||||
errorMsg?: string;
|
||||
}
|
||||
|
||||
/** 批次进度 */
|
||||
export interface SyncBatchStatus {
|
||||
/** 是否有同步任务在执行 */
|
||||
running: boolean;
|
||||
batchId?: string;
|
||||
triggerType?: string;
|
||||
triggerUser?: string;
|
||||
startTime?: string;
|
||||
/** 正在执行的段 */
|
||||
currentSection?: string;
|
||||
/** 本次批次的各段状态 */
|
||||
sections?: SyncSectionStatus[];
|
||||
}
|
||||
|
||||
/** 同步记录 */
|
||||
export interface SyncRecord {
|
||||
id: number;
|
||||
/** 批次号 */
|
||||
batchId?: string;
|
||||
/** 同步类型 */
|
||||
syncType: string;
|
||||
/** 触发方式:schedule/manual */
|
||||
triggerType: string;
|
||||
/** 触发人 */
|
||||
triggerUser?: string;
|
||||
/** 开始时间 */
|
||||
startTime?: string;
|
||||
/** 结束时间 */
|
||||
endTime?: string;
|
||||
successCount: number;
|
||||
failCount: number;
|
||||
skipCount: number;
|
||||
/** 状态:0成功 1失败 2进行中 */
|
||||
status: number;
|
||||
/** 错误摘要 */
|
||||
errorMsg?: string;
|
||||
}
|
||||
|
||||
/** 同步记录查询参数 */
|
||||
export interface SyncRecordParam {
|
||||
page?: number;
|
||||
limit?: number;
|
||||
syncType?: string;
|
||||
batchId?: string;
|
||||
}
|
||||
Reference in New Issue
Block a user