流程设计
This commit is contained in:
+47
-4
@@ -57,6 +57,7 @@ const admin = createClient();
|
||||
const schoolAdmin = createClient();
|
||||
const schoolAdmin2 = createClient();
|
||||
const classAdmin = createClient();
|
||||
const classAdmin2 = createClient();
|
||||
const candidate = createClient();
|
||||
const selfCandidate = createClient();
|
||||
const batchCandidate = createClient();
|
||||
@@ -112,6 +113,7 @@ try {
|
||||
assert.equal((await schoolAdmin.request('/api/auth/login', { method: 'POST', body: { username: 'school_admin', password: 'School123!' } })).data.user.adminLevel, 'school');
|
||||
assert.equal((await schoolAdmin2.request('/api/auth/login', { method: 'POST', body: { username: 'school_admin_2', password: 'School123!' } })).data.user.adminLevel, 'school');
|
||||
assert.equal((await classAdmin.request('/api/auth/login', { method: 'POST', body: { username: 'class_admin', password: 'Class123!' } })).data.user.adminLevel, 'class');
|
||||
assert.equal((await classAdmin2.request('/api/auth/login', { method: 'POST', body: { username: 'class_admin_2', password: 'Class123!' } })).data.user.adminLevel, 'class');
|
||||
|
||||
assert.equal((await admin.request('/api/admin/candidate-accounts', { method: 'POST', body: {} })).response.status, 404, '超级管理员不得再从旧入口直接生成报名号');
|
||||
const singleAccountBatch = await schoolAdmin.request('/api/admin/candidate-account-batches', { method: 'POST', body: { quotas: [
|
||||
@@ -359,9 +361,12 @@ try {
|
||||
const schoolFlows = await schoolAdmin.request('/api/admin/workflow-instances');
|
||||
const registrationFlow = schoolFlows.data.instances.find(item => item.businessId === registrationId && item.status === 'pending');
|
||||
assert.ok(registrationFlow, '报名应建立可追踪的审批实例');
|
||||
const transfer = await schoolAdmin.request(`/api/admin/workflow-instances/${registrationFlow.id}/transfer`, { method: 'PATCH', body: { assigneeId: 'usr_school_admin_2', note: '同级管理员协办' } });
|
||||
assert.equal(transfer.data.workflow.assignee.id, 'usr_school_admin_2', '同级管理员之间应可转交流程');
|
||||
const schoolApproveRegistration = await schoolAdmin2.request(`/api/admin/registrations/${registrationId}`, { method: 'PATCH', body: { status: 'approved', reviewNote: '学校报名初审通过' } });
|
||||
const assignedSchoolClient = registrationFlow.assignee.id === 'usr_school_admin_2' ? schoolAdmin2 : schoolAdmin;
|
||||
const transferTargetId = registrationFlow.assignee.id === 'usr_school_admin_2' ? 'usr_school_admin' : 'usr_school_admin_2';
|
||||
const transferTargetClient = transferTargetId === 'usr_school_admin_2' ? schoolAdmin2 : schoolAdmin;
|
||||
const transfer = await assignedSchoolClient.request(`/api/admin/workflow-instances/${registrationFlow.id}/transfer`, { method: 'PATCH', body: { assigneeId: transferTargetId, note: '同级管理员协办' } });
|
||||
assert.equal(transfer.data.workflow.assignee.id, transferTargetId, '同级管理员之间应可转交流程');
|
||||
const schoolApproveRegistration = await transferTargetClient.request(`/api/admin/registrations/${registrationId}`, { method: 'PATCH', body: { status: 'approved', reviewNote: '学校报名初审通过' } });
|
||||
assert.equal(schoolApproveRegistration.data.registration.status, 'pending', '校级初审后报名仍应待终审');
|
||||
|
||||
const allFlows = await admin.request('/api/admin/workflow-instances');
|
||||
@@ -399,7 +404,9 @@ try {
|
||||
const futureExam = futureExamResponse.data.exam;
|
||||
const futureRegistration = await candidate.request('/api/candidate/registrations', { method: 'POST', body: { examId: futureExam.id, subjectIds: [futureExam.subjects[0].id] } });
|
||||
const futureRegistrationId = futureRegistration.data.registration.id;
|
||||
await schoolAdmin.request(`/api/admin/registrations/${futureRegistrationId}`, { method: 'PATCH', body: { status: 'approved', reviewNote: '学校通过' } });
|
||||
const futureFlow = (await schoolAdmin.request('/api/admin/workflow-instances')).data.instances.find(item => item.businessId === futureRegistrationId && item.status === 'pending');
|
||||
const futureSchoolClient = futureFlow.assignee.id === 'usr_school_admin_2' ? schoolAdmin2 : schoolAdmin;
|
||||
await futureSchoolClient.request(`/api/admin/registrations/${futureRegistrationId}`, { method: 'PATCH', body: { status: 'approved', reviewNote: '学校通过' } });
|
||||
const approvedFutureRegistration = await admin.request(`/api/admin/registrations/${futureRegistrationId}`, { method: 'PATCH', body: { status: 'approved', reviewNote: '通过' } });
|
||||
assert.equal(approvedFutureRegistration.data.registration.registrationNumber, candidateNumber, '同一考生参加不同考试必须保持相同报名号');
|
||||
await admin.request(`/api/admin/registrations/${futureRegistrationId}/admit-card`, { method: 'POST', body: { testCenter: '海州市测试中学' } });
|
||||
@@ -425,10 +432,45 @@ try {
|
||||
assert.ok(classResults.data.results.some(item => item.score === 126 && item.candidateName === '测试考生新名'), '班级管理员应可查看本班成绩');
|
||||
assert.equal((await classAdmin.request('/api/admin/results', { method: 'POST', body: { registrationId, subjectId: exam.subjects[0].id, score: 1 } })).response.status, 403, '班级管理员不得录入或发布成绩');
|
||||
|
||||
const appealResults = results.data.results.filter(item => [exam.subjects[0].id, exam.subjects[2].id].includes(item.subjectId));
|
||||
assert.equal(appealResults.length, 2, '测试考生应有两科可提交成绩复议');
|
||||
const submittedAppeals = [];
|
||||
for (const result of appealResults) {
|
||||
const submitted = await candidate.request(`/api/candidate/results/${result.id}/appeals`, { method: 'POST', body: { reason: `${result.subjectName}成绩与个人估分差异较大,请复核答卷计分。` } });
|
||||
assert.equal(submitted.response.status, 201, '考生应能对已发布成绩提交复议');
|
||||
submittedAppeals.push({ result, workflow: submitted.data.workflow });
|
||||
}
|
||||
assert.deepEqual(new Set(submittedAppeals.map(item => item.workflow.assignee.id)), new Set(['usr_class_admin', 'usr_class_admin_2']), '同班多位班级管理员的新增复议应均分');
|
||||
const classFlows = await classAdmin.request('/api/admin/workflow-instances');
|
||||
assert.equal(classFlows.response.status, 200, '班级管理员应有流程中心和审批权限');
|
||||
assert.ok(classFlows.data.instances.filter(item => item.businessType === 'score_appeal' && item.status === 'pending').every(item => item.assignee.classId === 'class_hz1_302' && item.assignee.schoolId === 'school_hz1'), '班级步骤只能分配给该校该班管理员');
|
||||
const schoolAppeals = [];
|
||||
for (const appeal of submittedAppeals) {
|
||||
const classClient = appeal.workflow.assignee.id === 'usr_class_admin_2' ? classAdmin2 : classAdmin;
|
||||
const classApproved = await classClient.request(`/api/admin/score-appeals/${appeal.result.id}`, { method: 'PATCH', body: { status: 'approved', reviewNote: '班级已核验考生身份与科目' } });
|
||||
assert.equal(classApproved.response.status, 200, '班级管理员应能审批分配给自己的成绩复议');
|
||||
assert.equal(classApproved.data.workflow.currentStepDetail.adminLevel, 'school', '班级审批后应进入本校管理员步骤');
|
||||
assert.equal(classApproved.data.workflow.assignee.schoolId, 'school_hz1', '校级步骤必须匹配考生所属学校');
|
||||
schoolAppeals.push({ result: appeal.result, workflow: classApproved.data.workflow });
|
||||
}
|
||||
assert.deepEqual(new Set(schoolAppeals.map(item => item.workflow.assignee.id)), new Set(['usr_school_admin', 'usr_school_admin_2']), '同校多位校级管理员的复议任务应均分');
|
||||
for (const appeal of schoolAppeals) {
|
||||
const schoolClient = appeal.workflow.assignee.id === 'usr_school_admin_2' ? schoolAdmin2 : schoolAdmin;
|
||||
const schoolApproved = await schoolClient.request(`/api/admin/score-appeals/${appeal.result.id}`, { method: 'PATCH', body: { status: 'approved', reviewNote: '学校完成成绩复核' } });
|
||||
assert.equal(schoolApproved.response.status, 200);
|
||||
assert.equal(schoolApproved.data.workflow.currentStepDetail.adminLevel, 'super', '校级复核后应进入考试中心终审');
|
||||
const finalApproved = await admin.request(`/api/admin/score-appeals/${appeal.result.id}`, { method: 'PATCH', body: { status: 'approved', reviewNote: '考试中心终审完成' } });
|
||||
assert.equal(finalApproved.data.workflow.status, 'approved', '成绩复议应可完整走完班级、学校和考试中心流程');
|
||||
}
|
||||
const appealedResults = await candidate.request('/api/candidate/results');
|
||||
assert.ok(appealedResults.data.results.filter(item => appealResults.some(result => result.id === item.id)).every(item => item.appeal?.status === 'approved'), '考生端应显示每科复议结果');
|
||||
|
||||
const workflowDefinitions = await admin.request('/api/admin/workflows');
|
||||
const profileWorkflow = workflowDefinitions.data.workflows.find(item => item.businessType === 'profile_change');
|
||||
assert.ok(workflowDefinitions.data.workflows.some(item => item.businessType === 'center_change'), '流程设计应包含考点考场变更审批');
|
||||
assert.ok(workflowDefinitions.data.workflows.some(item => item.businessType === 'candidate_account_batch'), '流程设计应包含批量报名号申领审批');
|
||||
assert.ok(workflowDefinitions.data.workflows.some(item => item.businessType === 'score_appeal'), '流程设计应包含考生成绩复议');
|
||||
assert.match(appSource, /renderAdmin, workflowStepEditor/, '添加流程步骤事件必须取得视图模块导出的编辑器,避免未定义错误');
|
||||
const updateWorkflow = await admin.request('/api/admin/workflows/profile_change', { method: 'PUT', body: { name: profileWorkflow.name, steps: profileWorkflow.steps.map(item => ({ name: item.name, adminLevel: item.adminLevel })) } });
|
||||
assert.equal(updateWorkflow.response.status, 200, '超级管理员应可设计考生信息修改审批流程');
|
||||
|
||||
@@ -442,6 +484,7 @@ try {
|
||||
console.log('✓ 结构化考点考场档案、变更审批与班级只读边界');
|
||||
console.log('✓ 本校班级/班级管理员管理与多资源 Excel 导入导出');
|
||||
console.log('✓ 成绩录入、发布与考生查询');
|
||||
console.log('✓ 成绩复议、班级审批、范围匹配与多人均分');
|
||||
} finally {
|
||||
server.kill('SIGTERM');
|
||||
await new Promise(resolveWait => server.once('exit', resolveWait));
|
||||
|
||||
Reference in New Issue
Block a user