feat(volunteer): 新增志愿服务证明材料识别及年度证明功能

- 新增志愿证明材料识别功能,支持自动识别材料并回填关键信息
- 在志愿时长编辑页面添加材料识别按钮及识别结果展示
- 新增志愿服务证明模块,支持查询、生成及下载年度志愿服务证明PDF
- 志愿时长列表及审核详情中新增“服务地点”字段显示
- 志愿时长导入功能支持“服务地点”字段,完善导入表头与数据映射
- 志愿时长详情、审核流程等界面优化,增加识别材料公章状态及流程节点提示
- 志愿时长待审核项支持用户撤回操作,撤回后记录被删除需重新录入
- 社团年度报告相关接口新增,实现社团年度报告生成及分页查询
- 调整相关样式与界面布局,提升用户体验与信息展示完整性
This commit is contained in:
2026-11-06 12:04:32 +08:00
parent d82a3b5426
commit d8e7e2a2a8
21 changed files with 1980 additions and 103 deletions
+56
View File
@@ -81,6 +81,62 @@ export interface ClubActivityParam extends PageParam {
startTimeEnd?: string;
}
/** 社团年度数据报告 */
export interface ClubReport {
id?: number;
clubId?: number;
clubName?: string;
year?: number;
summary?: string;
narrative?: string;
fileId?: number;
fileUrl?: string;
downloadUrl?: string;
status?: number;
createTime?: string;
updateTime?: string;
}
/** 社团年度报告数据预览 */
export async function getClubReportPreview(params: { clubId: number; year?: number }) {
const res = await request.get<ApiResult<Record<string, any>>>(
MODULES_API_URL + '/gxmu/club/report/preview',
{ params }
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/** 生成社团年度数据报告 PDF */
export async function generateClubReport(data: {
clubId?: number;
year: number;
narrative?: string;
}) {
const res = await request.post<ApiResult<ClubReport>>(
MODULES_API_URL + '/gxmu/club/report/generate',
data
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/** 分页查询社团年度报告 */
export async function pageClubReports(params?: Record<string, any>) {
const res = await request.get<ApiResult<PageResult<ClubReport>>>(
MODULES_API_URL + '/gxmu/club/report/page',
{ params }
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/** 场地 */
export interface Venue {
id?: number;
+140
View File
@@ -15,11 +15,19 @@ export interface VolunteerRecord {
externalId?: string;
projectName?: string;
orgName?: string;
servicePlace?: string;
hours?: number;
serviceDate?: string;
serviceEndDate?: string;
content?: string;
proofFiles?: string;
ocrStatus?: number;
ocrOrg?: string;
ocrProjectName?: string;
ocrPlace?: string;
ocrHours?: number;
ocrHasSeal?: number;
ocrRaw?: string;
status?: number;
reviewRemark?: string;
reviewerId?: number;
@@ -53,6 +61,17 @@ export async function pageVolunteerRecords(params: VolunteerRecordParam) {
return Promise.reject(new Error(res.data.message));
}
/** 按 id 查询志愿时长详情 */
export async function getVolunteerRecord(id: number) {
const res = await request.get<ApiResult<VolunteerRecord>>(
MODULES_API_URL + '/gxmu/volunteer/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/** 个人录入志愿时长 */
export async function submitVolunteerRecord(data: VolunteerRecord) {
const res = await request.post<ApiResult<unknown>>(
@@ -134,3 +153,124 @@ export async function getMyVolunteerProjectStats(year?: number) {
}
return Promise.reject(new Error(res.data.message));
}
/** 已生成的年度志愿服务证明 */
export interface VolunteerCertificate {
id?: number;
userId?: number;
studentNo?: string;
studentName?: string;
year?: number;
totalHours?: number;
serialNo?: string;
fileId?: number;
fileUrl?: string;
downloadUrl?: string;
status?: number;
createTime?: string;
updateTime?: string;
}
/** 年度志愿服务证明数据核对 */
export async function getVolunteerCertificateSummary(params: {
year?: number;
studentNo?: string;
}) {
const res = await request.get<ApiResult<Record<string, any>>>(
MODULES_API_URL + '/gxmu/volunteer/certificate/summary',
{ params }
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/** 生成年度志愿服务证明 PDF */
export async function generateVolunteerCertificate(data: {
year: number;
studentNo?: string;
}) {
const res = await request.post<ApiResult<VolunteerCertificate>>(
MODULES_API_URL + '/gxmu/volunteer/certificate/generate',
data
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/** 分页查询已生成的志愿证明 */
export async function pageVolunteerCertificates(params: Record<string, any>) {
const res = await request.get<ApiResult<PageResult<VolunteerCertificate>>>(
MODULES_API_URL + '/gxmu/volunteer/certificate/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 getMyVolunteerCertificates() {
const res = await request.get<ApiResult<VolunteerCertificate[]>>(
MODULES_API_URL + '/gxmu/volunteer/certificate/my'
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/** 审核进度节点 */
export interface VolunteerReviewNode {
id?: number;
nodeName?: string;
reviewerId?: number;
reviewerName?: string;
status?: number;
content?: string;
parallelGroup?: number;
passMode?: string;
createTime?: string;
updateTime?: string;
}
/** 志愿记录审核进度 */
export async function getVolunteerProgress(id: number) {
const res = await request.get<ApiResult<Record<string, any>>>(
MODULES_API_URL + '/gxmu/volunteer/' + id + '/progress'
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/** 撤回本人待审核的志愿时长 */
export async function withdrawVolunteerRecord(id: number) {
const res = await request.put<ApiResult<unknown>>(
MODULES_API_URL + '/gxmu/volunteer/' + id + '/withdraw'
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/** 识别证明材料并回填关键信息 */
export async function recognizeVolunteerProof(data: {
fileUrl: string;
fileName?: string;
}) {
const res = await request.post<ApiResult<Record<string, any>>>(
MODULES_API_URL + '/gxmu/volunteer/proof/recognize',
data
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}