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;
}
}
}