package com.gxwebsoft.gxmu.openplat.controller; import cn.hutool.core.util.DesensitizedUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.gxwebsoft.common.core.annotation.OperationLog; import com.gxwebsoft.common.core.web.ApiResult; import com.gxwebsoft.common.core.web.BaseController; import com.gxwebsoft.common.core.web.PageResult; import com.gxwebsoft.common.system.entity.User; import com.gxwebsoft.gxmu.entity.ClassInfo; import com.gxwebsoft.gxmu.openplat.OpenplatSyncConstants; import com.gxwebsoft.gxmu.openplat.SyncSupport; import com.gxwebsoft.gxmu.openplat.claim.ClaimResult; import com.gxwebsoft.gxmu.openplat.claim.StudentClaimService; import com.gxwebsoft.gxmu.openplat.entity.GxmuStudent; import com.gxwebsoft.gxmu.openplat.mapper.GxmuStudentMapper; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.util.List; import java.util.Map; /** * 学生名册与认领控制器。 * *

响应中的手机号与身份证一律脱敏,原始值不出本控制器。 * * @author Codex * @since 2026-09-12 */ @Api(tags = "学生名册") @RestController @RequestMapping("/api/gxmu/student") public class GxmuStudentController extends BaseController { @Resource private GxmuStudentMapper studentMapper; @Resource private StudentClaimService studentClaimService; @Resource private SyncSupport syncSupport; @PreAuthorize("hasAuthority('gxmu:student:list')") @ApiOperation("学生名册分页查询") @GetMapping("/page") public ApiResult> page( @RequestParam(value = "page", defaultValue = "1") Integer page, @RequestParam(value = "limit", defaultValue = "20") Integer limit, @RequestParam(value = "collegeId", required = false) Integer collegeId, @RequestParam(value = "classId", required = false) Integer classId, @RequestParam(value = "xh", required = false) String xh, @RequestParam(value = "xm", required = false) String xm, @RequestParam(value = "pyccmc", required = false) String pyccmc, @RequestParam(value = "status", required = false) Integer status, @RequestParam(value = "claimed", required = false) Boolean claimed) { LambdaQueryWrapper wrapper = buildWrapper(collegeId, classId, xh, xm, pyccmc, status, claimed); Page pageParam = new Page<>(page, limit); IPage result = studentMapper.selectPage(pageParam, wrapper); List records = result.getRecords(); desensitize(records); enrich(records); return success(new PageResult<>(records, result.getTotal())); } @PreAuthorize("hasAuthority('gxmu:student:list')") @ApiOperation("学生名册详情") @GetMapping("/{id}") public ApiResult get(@PathVariable("id") Integer id) { GxmuStudent student = studentMapper.selectById(id); if (student == null) { return fail("记录不存在", null); } desensitize(java.util.Collections.singletonList(student)); enrich(java.util.Collections.singletonList(student)); return success(student); } @ApiOperation("导出学生名册(脱敏)") @PreAuthorize("hasAuthority('gxmu:student:export')") @OperationLog @PostMapping("/export") public ApiResult> export( @RequestParam(value = "collegeId", required = false) Integer collegeId, @RequestParam(value = "classId", required = false) Integer classId, @RequestParam(value = "status", required = false) Integer status) { LambdaQueryWrapper wrapper = buildWrapper(collegeId, classId, null, null, null, status, null); List records = studentMapper.selectList(wrapper); desensitize(records); enrich(records); return success(records); } @ApiOperation("自助认领(学号+姓名)") @PostMapping("/claim") public ApiResult claim(@RequestBody ClaimParam param) { User user = getLoginUser(); ClaimResult result = studentClaimService.claimByXhAndName(user, param == null ? null : param.getXh(), param == null ? null : param.getXm()); return result.isSuccess() ? success(result.getMessage(), result) : fail(result.getMessage(), result); } @OperationLog @PreAuthorize("hasAuthority('gxmu:student:list')") @ApiOperation("手动认领/改绑") @PutMapping("/{id}/claim") public ApiResult bind(@PathVariable("id") Integer id, @RequestBody ClaimParam param) { boolean ok = studentClaimService.bind(id, param == null ? null : param.getUserId(), param == null ? null : param.getPhone(), getTenantId()); return ok ? success("认领成功") : fail("认领失败:未找到匹配的账号"); } @OperationLog @PreAuthorize("hasAuthority('gxmu:student:list')") @ApiOperation("解除认领") @PutMapping("/{id}/unclaim") public ApiResult unbind(@PathVariable("id") Integer id) { return studentClaimService.unbind(id, getTenantId()) ? success("已解除认领") : fail("解除失败"); } private LambdaQueryWrapper buildWrapper(Integer collegeId, Integer classId, String xh, String xm, String pyccmc, Integer status, Boolean claimed) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(GxmuStudent::getTenantId, getTenantId()); wrapper.eq(collegeId != null, GxmuStudent::getCollegeId, collegeId); wrapper.eq(classId != null, GxmuStudent::getClassId, classId); wrapper.eq(StrUtil.isNotBlank(xh), GxmuStudent::getXh, StrUtil.trim(xh)); wrapper.like(StrUtil.isNotBlank(xm), GxmuStudent::getXm, StrUtil.trim(xm)); wrapper.eq(StrUtil.isNotBlank(pyccmc), GxmuStudent::getPyccmc, pyccmc); // 默认只看在校生 wrapper.eq(status != null, GxmuStudent::getStatus, status); wrapper.eq(status == null, GxmuStudent::getStatus, 1); if (claimed != null) { if (claimed) { wrapper.isNotNull(GxmuStudent::getUserId); } else { wrapper.isNull(GxmuStudent::getUserId); } } wrapper.orderByAsc(GxmuStudent::getCollegeId).orderByAsc(GxmuStudent::getXh); return wrapper; } /** * 脱敏:手机号与身份证明文绝不离开后端。 */ private void desensitize(List records) { for (GxmuStudent student : records) { if (StrUtil.isNotBlank(student.getSjh())) { student.setSjh(DesensitizedUtil.mobilePhone(student.getSjh())); } if (StrUtil.isNotBlank(student.getSfzjh()) && student.getSfzjh().length() >= 8) { student.setSfzjh(DesensitizedUtil.idCardNum(student.getSfzjh(), 4, 4)); } } } private void enrich(List records) { if (records.isEmpty()) { return; } Map orgNames = syncSupport.orgNameById(); Map classNames = syncSupport.classNameById(); for (GxmuStudent student : records) { if (student.getCollegeId() != null) { student.setCollegeName(orgNames.get(student.getCollegeId())); } if (student.getClassId() != null) { student.setClassName(classNames.get(student.getClassId())); } } } /** * 认领参数 */ @io.swagger.annotations.ApiModel("学生认领参数") public static class ClaimParam { @io.swagger.annotations.ApiModelProperty("学号") private String xh; @io.swagger.annotations.ApiModelProperty("姓名") private String xm; @io.swagger.annotations.ApiModelProperty("目标用户ID(手动认领时)") private Integer userId; @io.swagger.annotations.ApiModelProperty("目标用户手机号(手动认领时, 可不传则用名册手机号)") private String phone; public String getXh() { return xh; } public void setXh(String xh) { this.xh = xh; } public String getXm() { return xm; } public void setXm(String xm) { this.xm = xm; } public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } } }