Merge branch 'master' of http://47.99.164.66:3000/hzdyjs-xg/all-project
This commit is contained in:
commit
465c284d4a
244 files changed
+28906
-5725
No files matched your search
+2
-1
@@ -326,4 +326,5 @@ docs/变更管理/
|
||||
查找界面中涉及到的权限字符.md
|
||||
docs/部署文档/nginx配置/hzdyjsweb.camasort.com.conf
|
||||
首页完善的提示词.md
|
||||
scripts/
|
||||
scripts/
|
||||
学生宿舍卫生检查、学生违纪记录统计.md
|
||||
@@ -85,6 +85,16 @@
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>prod-local</id>
|
||||
<properties>
|
||||
<!-- 生产环境本地配置 -->
|
||||
<profiles.active>prod-local</profiles.active>
|
||||
<logging.level>warn</logging.level>
|
||||
<monitor.username>ruoyi</monitor.username>
|
||||
<monitor.password>123456</monitor.password>
|
||||
</properties>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>prod</id>
|
||||
<properties>
|
||||
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
package org.dromara.cw.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import jakarta.validation.constraints.*;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.cw.domain.bo.CwCustomApprovalBo;
|
||||
import org.dromara.cw.domain.bo.CwApprovalActionBo;
|
||||
import org.dromara.cw.domain.vo.CwProjectApprovalProcessVo;
|
||||
import org.dromara.cw.domain.vo.CwApprovalRecordVo;
|
||||
import org.dromara.cw.service.ICwProjectApprovalService;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
|
||||
/**
|
||||
* 项目审批流程管理
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/cw/projectApproval")
|
||||
public class CwProjectApprovalController extends BaseController {
|
||||
|
||||
private final ICwProjectApprovalService projectApprovalService;
|
||||
|
||||
/**
|
||||
* 启动自定义审批流程
|
||||
*/
|
||||
@SaCheckPermission("cw:projectApproval:start")
|
||||
@Log(title = "启动审批流程", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/start")
|
||||
public R<Void> startApprovalProcess(@Validated @RequestBody CwCustomApprovalBo bo) {
|
||||
// 设置提交人信息
|
||||
bo.setSubmitterId(LoginHelper.getUserId());
|
||||
bo.setSubmitterName(LoginHelper.getUsername());
|
||||
return toAjax(projectApprovalService.startCustomApprovalProcess(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行审批操作
|
||||
*/
|
||||
@SaCheckPermission("cw:projectApproval:approve")
|
||||
@Log(title = "执行审批操作", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/approve")
|
||||
public R<Void> executeApproval(@Validated @RequestBody CwApprovalActionBo bo) {
|
||||
return toAjax(projectApprovalService.executeApproval(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取我的待审批列表
|
||||
*/
|
||||
@SaCheckPermission("cw:projectApproval:query")
|
||||
@GetMapping("/pending")
|
||||
public TableDataInfo<CwApprovalRecordVo> getMyPendingApprovals(PageQuery pageQuery) {
|
||||
return projectApprovalService.getMyPendingApprovals(pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取我的已审批列表
|
||||
*/
|
||||
@SaCheckPermission("cw:projectApproval:query")
|
||||
@GetMapping("/processed")
|
||||
public TableDataInfo<CwApprovalRecordVo> getMyProcessedApprovals(PageQuery pageQuery) {
|
||||
return projectApprovalService.getMyProcessedApprovals(pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询审批流程列表
|
||||
*/
|
||||
@SaCheckPermission("cw:projectApproval:query")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<CwProjectApprovalProcessVo> list(PageQuery pageQuery) {
|
||||
return projectApprovalService.queryProcessList(pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取审批流程详情
|
||||
*/
|
||||
@SaCheckPermission("cw:projectApproval:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<CwProjectApprovalProcessVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(projectApprovalService.getProcessDetail(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取审批记录列表
|
||||
*/
|
||||
@SaCheckPermission("cw:projectApproval:query")
|
||||
@GetMapping("/records/{applicationId}")
|
||||
public R<List<CwApprovalRecordVo>> getApprovalRecords(@PathVariable Long applicationId) {
|
||||
return R.ok(projectApprovalService.getApprovalRecords(applicationId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 终止审批流程
|
||||
*/
|
||||
@SaCheckPermission("cw:projectApproval:terminate")
|
||||
@Log(title = "终止审批流程", businessType = BusinessType.UPDATE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> terminate(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(projectApprovalService.terminateProcess(List.of(ids)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 审批流程验证
|
||||
*/
|
||||
@SaCheckPermission("cw:projectApproval:query")
|
||||
@PostMapping("/validate")
|
||||
public R<String> validateApprovalProcess(@RequestBody CwCustomApprovalBo bo) {
|
||||
// 简单验证逻辑
|
||||
if (bo.getAuditorIds() == null || bo.getAuditorIds().isEmpty()) {
|
||||
return R.fail("请选择审核人");
|
||||
}
|
||||
if (bo.getAuditorIds().size() > 10) {
|
||||
return R.fail("审核人数量不能超过10个");
|
||||
}
|
||||
return R.ok("验证通过");
|
||||
}
|
||||
|
||||
/**
|
||||
* 审批选项查询(用于下拉选择)
|
||||
*/
|
||||
@SaCheckPermission("cw:projectApproval:query")
|
||||
@GetMapping("/options")
|
||||
public R<Object> getApprovalOptions() {
|
||||
// 返回一些选项数据,比如审批动作选项等
|
||||
return R.ok(java.util.Map.of(
|
||||
"actions", java.util.List.of(
|
||||
java.util.Map.of("value", "approve", "label", "通过"),
|
||||
java.util.Map.of("value", "reject", "label", "拒绝")
|
||||
),
|
||||
"statuses", java.util.List.of(
|
||||
java.util.Map.of("value", "waiting", "label", "等待审批"),
|
||||
java.util.Map.of("value", "approved", "label", "已通过"),
|
||||
java.util.Map.of("value", "rejected", "label", "已拒绝")
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
package org.dromara.cw.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.*;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.cw.domain.vo.CwProjectAuditorVo;
|
||||
import org.dromara.cw.domain.bo.CwProjectAuditorBo;
|
||||
import org.dromara.cw.service.ICwProjectAuditorService;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
|
||||
/**
|
||||
* 项目审核人配置
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/cw/projectAuditor")
|
||||
public class CwProjectAuditorController extends BaseController {
|
||||
|
||||
private final ICwProjectAuditorService cwProjectAuditorService;
|
||||
|
||||
/**
|
||||
* 查询项目审核人配置列表
|
||||
*/
|
||||
@SaCheckPermission("cw:projectAuditor:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<CwProjectAuditorVo> list(CwProjectAuditorBo bo, PageQuery pageQuery) {
|
||||
return cwProjectAuditorService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出项目审核人配置列表
|
||||
*/
|
||||
@SaCheckPermission("cw:projectAuditor:export")
|
||||
@Log(title = "项目审核人配置", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(CwProjectAuditorBo bo, HttpServletResponse response) {
|
||||
List<CwProjectAuditorVo> list = cwProjectAuditorService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "项目审核人配置", CwProjectAuditorVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取项目审核人配置详细信息
|
||||
*/
|
||||
@SaCheckPermission("cw:projectAuditor:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<CwProjectAuditorVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(cwProjectAuditorService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增项目审核人配置
|
||||
*/
|
||||
@SaCheckPermission("cw:projectAuditor:add")
|
||||
@Log(title = "项目审核人配置", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody CwProjectAuditorBo bo) {
|
||||
// 设置配置人信息
|
||||
bo.setConfigBy(LoginHelper.getUserId());
|
||||
bo.setConfigByName(LoginHelper.getUsername());
|
||||
return toAjax(cwProjectAuditorService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改项目审核人配置
|
||||
*/
|
||||
@SaCheckPermission("cw:projectAuditor:edit")
|
||||
@Log(title = "项目审核人配置", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody CwProjectAuditorBo bo) {
|
||||
return toAjax(cwProjectAuditorService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除项目审核人配置
|
||||
*/
|
||||
@SaCheckPermission("cw:projectAuditor:remove")
|
||||
@Log(title = "项目审核人配置", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(cwProjectAuditorService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量添加审核人
|
||||
*/
|
||||
@SaCheckPermission("cw:projectAuditor:add")
|
||||
@Log(title = "批量添加审核人", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/batchAdd")
|
||||
public R<Void> batchAdd(@RequestBody BatchAddRequest request) {
|
||||
return toAjax(cwProjectAuditorService.batchAddAuditors(
|
||||
request.getUserIds(),
|
||||
LoginHelper.getUserId(),
|
||||
LoginHelper.getUsername(),
|
||||
request.getRemark()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可用审核人列表
|
||||
*/
|
||||
@SaCheckPermission("cw:projectAuditor:list")
|
||||
@GetMapping("/available")
|
||||
public R<List<CwProjectAuditorVo>> getAvailableAuditors() {
|
||||
return R.ok(cwProjectAuditorService.getAvailableAuditors());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据部门ID获取用户列表
|
||||
*/
|
||||
@SaCheckPermission("cw:projectAuditor:list")
|
||||
@GetMapping("/deptUsers/{deptId}")
|
||||
public R<List<Object>> getDeptUsers(@PathVariable Long deptId) {
|
||||
// 参数验证
|
||||
if (deptId == null || deptId <= 0) {
|
||||
return R.fail("部门ID参数无效");
|
||||
}
|
||||
return R.ok(cwProjectAuditorService.getDeptUsers(deptId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新状态
|
||||
*/
|
||||
@SaCheckPermission("cw:projectAuditor:edit")
|
||||
@Log(title = "批量更新审核人状态", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/status")
|
||||
public R<Void> updateStatus(@RequestBody StatusUpdateRequest request) {
|
||||
return toAjax(cwProjectAuditorService.updateStatus(request.getIds(), request.getStatus()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 我配置的审核人
|
||||
*/
|
||||
@SaCheckPermission("cw:projectAuditor:list")
|
||||
@GetMapping("/myConfig")
|
||||
public TableDataInfo<CwProjectAuditorVo> getMyConfig(CwProjectAuditorBo bo, PageQuery pageQuery) {
|
||||
bo.setConfigBy(LoginHelper.getUserId());
|
||||
return cwProjectAuditorService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取审核人选项(用于下拉选择)
|
||||
*/
|
||||
@SaCheckPermission("cw:projectAuditor:list")
|
||||
@GetMapping("/options")
|
||||
public R<List<CwProjectAuditorVo>> getAuditorOptions() {
|
||||
return R.ok(cwProjectAuditorService.getAvailableAuditors());
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量启用
|
||||
*/
|
||||
@SaCheckPermission("cw:projectAuditor:edit")
|
||||
@Log(title = "批量启用审核人", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/enable/{ids}")
|
||||
public R<Void> enable(@PathVariable Long[] ids) {
|
||||
return toAjax(cwProjectAuditorService.updateStatus(List.of(ids), "1"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量停用
|
||||
*/
|
||||
@SaCheckPermission("cw:projectAuditor:edit")
|
||||
@Log(title = "批量停用审核人", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/disable/{ids}")
|
||||
public R<Void> disable(@PathVariable Long[] ids) {
|
||||
return toAjax(cwProjectAuditorService.updateStatus(List.of(ids), "0"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取审核人统计数据
|
||||
*/
|
||||
@SaCheckPermission("cw:projectAuditor:list")
|
||||
@GetMapping("/statistics")
|
||||
public R<Object> getStatistics() {
|
||||
return R.ok(cwProjectAuditorService.getStatistics());
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量添加请求对象
|
||||
*/
|
||||
public static class BatchAddRequest {
|
||||
private List<Long> userIds;
|
||||
private String remark;
|
||||
|
||||
public List<Long> getUserIds() {
|
||||
return userIds;
|
||||
}
|
||||
|
||||
public void setUserIds(List<Long> userIds) {
|
||||
this.userIds = userIds;
|
||||
}
|
||||
|
||||
public String getRemark() {
|
||||
return remark;
|
||||
}
|
||||
|
||||
public void setRemark(String remark) {
|
||||
this.remark = remark;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 状态更新请求对象
|
||||
*/
|
||||
public static class StatusUpdateRequest {
|
||||
private List<Long> ids;
|
||||
private String status;
|
||||
|
||||
public List<Long> getIds() {
|
||||
return ids;
|
||||
}
|
||||
|
||||
public void setIds(List<Long> ids) {
|
||||
this.ids = ids;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+16
-1
@@ -124,4 +124,19 @@ public class CwApprovalRecord extends TenantEntity implements Serializable {
|
||||
*/
|
||||
private String configSnapshot;
|
||||
|
||||
}
|
||||
/**
|
||||
* 流程ID
|
||||
*/
|
||||
private Long processId;
|
||||
|
||||
/**
|
||||
* 自定义节点名称
|
||||
*/
|
||||
private String customNodeName;
|
||||
|
||||
/**
|
||||
* 是否自定义流程
|
||||
*/
|
||||
private Boolean isCustomProcess;
|
||||
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
package org.dromara.cw.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.tenant.core.TenantEntity;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 项目审批流程对象 cw_project_approval_process
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("cw_project_approval_process")
|
||||
public class CwProjectApprovalProcess extends TenantEntity implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID(雪花ID)
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 申报ID
|
||||
*/
|
||||
private Long applicationId;
|
||||
|
||||
/**
|
||||
* 申报编号
|
||||
*/
|
||||
private String applicationNo;
|
||||
|
||||
/**
|
||||
* 流程名称
|
||||
*/
|
||||
private String processName;
|
||||
|
||||
/**
|
||||
* 流程状态(waiting-等待开始 running-进行中 completed-已完成 terminated-已终止)
|
||||
*/
|
||||
private String processStatus;
|
||||
|
||||
/**
|
||||
* 总审批节点数
|
||||
*/
|
||||
private Integer totalNodes;
|
||||
|
||||
/**
|
||||
* 当前审批节点
|
||||
*/
|
||||
private Integer currentNode;
|
||||
|
||||
/**
|
||||
* 流程开始时间
|
||||
*/
|
||||
private Date startTime;
|
||||
|
||||
/**
|
||||
* 流程结束时间
|
||||
*/
|
||||
private Date endTime;
|
||||
|
||||
/**
|
||||
* 提交人ID
|
||||
*/
|
||||
private Long submitterId;
|
||||
|
||||
/**
|
||||
* 提交人姓名
|
||||
*/
|
||||
private String submitterName;
|
||||
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
package org.dromara.cw.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.tenant.core.TenantEntity;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 项目审核人配置对象 cw_project_auditor
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("cw_project_auditor")
|
||||
public class CwProjectAuditor extends TenantEntity implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID(雪花ID)
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 用户姓名
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String nickName;
|
||||
|
||||
/**
|
||||
* 所属部门ID
|
||||
*/
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 所属部门名称
|
||||
*/
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 联系电话
|
||||
*/
|
||||
private String phoneNumber;
|
||||
|
||||
/**
|
||||
* 邮箱地址
|
||||
*/
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 审核人状态(1正常 0停用)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 备注说明
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 配置人ID
|
||||
*/
|
||||
private Long configBy;
|
||||
|
||||
/**
|
||||
* 配置人姓名
|
||||
*/
|
||||
private String configByName;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
@TableLogic
|
||||
private Integer deleted;
|
||||
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package org.dromara.cw.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 用户和部门完整信息
|
||||
* 用于批量添加审核人时获取完整的用户数据
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
public class UserWithDeptInfo {
|
||||
|
||||
/** 用户ID */
|
||||
private Long userId;
|
||||
|
||||
/** 用户账号 */
|
||||
private String userName;
|
||||
|
||||
/** 用户昵称 */
|
||||
private String nickName;
|
||||
|
||||
/** 部门ID */
|
||||
private Long deptId;
|
||||
|
||||
/** 部门名称 */
|
||||
private String deptName;
|
||||
|
||||
/** 手机号码 */
|
||||
private String phonenumber;
|
||||
|
||||
/** 用户邮箱 */
|
||||
private String email;
|
||||
|
||||
/** 帐号状态(1正常 0停用) */
|
||||
private String status;
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package org.dromara.cw.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import jakarta.validation.constraints.*;
|
||||
|
||||
/**
|
||||
* 审批操作业务对象
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
public class CwApprovalActionBo {
|
||||
|
||||
/**
|
||||
* 审批记录ID
|
||||
*/
|
||||
@NotNull(message = "审批记录ID不能为空")
|
||||
private Long recordId;
|
||||
|
||||
/**
|
||||
* 审批操作(approve-通过 reject-拒绝)
|
||||
*/
|
||||
@NotBlank(message = "审批操作不能为空")
|
||||
private String action;
|
||||
|
||||
/**
|
||||
* 审批意见
|
||||
*/
|
||||
@NotBlank(message = "审批意见不能为空")
|
||||
private String opinion;
|
||||
|
||||
}
|
||||
+7
-2
@@ -132,13 +132,18 @@ public class CwApprovalRecordBo extends BaseEntity {
|
||||
private String configSnapshot;
|
||||
|
||||
// ========== 查询条件字段 ==========
|
||||
|
||||
|
||||
/**
|
||||
* 部门ID查询条件(用于部门审批页面过滤)
|
||||
* 支持具体部门ID或特殊值 'current'(当前用户部门)
|
||||
*/
|
||||
private String deptId;
|
||||
|
||||
/**
|
||||
* 部门ID(Long类型,用于数据库操作)
|
||||
*/
|
||||
private Long deptIdLong;
|
||||
|
||||
/**
|
||||
* 项目名称(查询条件)
|
||||
*/
|
||||
@@ -164,4 +169,4 @@ public class CwApprovalRecordBo extends BaseEntity {
|
||||
*/
|
||||
private String approvalStatus;
|
||||
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package org.dromara.cw.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import jakarta.validation.constraints.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 自定义审批流程业务对象
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
public class CwCustomApprovalBo {
|
||||
|
||||
/**
|
||||
* 申报ID
|
||||
*/
|
||||
@NotNull(message = "申报ID不能为空")
|
||||
private Long applicationId;
|
||||
|
||||
/**
|
||||
* 申报编号
|
||||
*/
|
||||
@NotBlank(message = "申报编号不能为空")
|
||||
private String applicationNo;
|
||||
|
||||
/**
|
||||
* 审核人ID列表
|
||||
*/
|
||||
@NotEmpty(message = "审核人列表不能为空")
|
||||
private List<Long> auditorIds;
|
||||
|
||||
/**
|
||||
* 流程名称
|
||||
*/
|
||||
@NotBlank(message = "流程名称不能为空")
|
||||
private String processName;
|
||||
|
||||
/**
|
||||
* 提交人ID
|
||||
*/
|
||||
@NotNull(message = "提交人ID不能为空")
|
||||
private Long submitterId;
|
||||
|
||||
/**
|
||||
* 提交人姓名
|
||||
*/
|
||||
@NotBlank(message = "提交人姓名不能为空")
|
||||
private String submitterName;
|
||||
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
package org.dromara.cw.domain.bo;
|
||||
|
||||
import org.dromara.cw.domain.CwProjectApprovalProcess;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import jakarta.validation.constraints.*;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 项目审批流程业务对象 cw_project_approval_process
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = CwProjectApprovalProcess.class, reverseConvertGenerate = false)
|
||||
public class CwProjectApprovalProcessBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键ID(雪花ID)
|
||||
*/
|
||||
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 申报ID
|
||||
*/
|
||||
@NotNull(message = "申报ID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long applicationId;
|
||||
|
||||
/**
|
||||
* 申报编号
|
||||
*/
|
||||
@NotBlank(message = "申报编号不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String applicationNo;
|
||||
|
||||
/**
|
||||
* 流程名称
|
||||
*/
|
||||
@NotBlank(message = "流程名称不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String processName;
|
||||
|
||||
/**
|
||||
* 流程状态(waiting-等待开始 running-进行中 completed-已完成 terminated-已终止)
|
||||
*/
|
||||
@NotBlank(message = "流程状态不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String processStatus;
|
||||
|
||||
/**
|
||||
* 总审批节点数
|
||||
*/
|
||||
@NotNull(message = "总审批节点数不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Integer totalNodes;
|
||||
|
||||
/**
|
||||
* 当前审批节点
|
||||
*/
|
||||
private Integer currentNode;
|
||||
|
||||
/**
|
||||
* 流程开始时间
|
||||
*/
|
||||
private Date startTime;
|
||||
|
||||
/**
|
||||
* 流程结束时间
|
||||
*/
|
||||
private Date endTime;
|
||||
|
||||
/**
|
||||
* 提交人ID
|
||||
*/
|
||||
@NotNull(message = "提交人ID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long submitterId;
|
||||
|
||||
/**
|
||||
* 提交人姓名
|
||||
*/
|
||||
@NotBlank(message = "提交人姓名不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String submitterName;
|
||||
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package org.dromara.cw.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import jakarta.validation.constraints.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 批量添加审核人业务对象
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
public class CwProjectAuditorBatchBo {
|
||||
|
||||
/**
|
||||
* 用户ID列表
|
||||
*/
|
||||
@NotEmpty(message = "用户ID列表不能为空")
|
||||
private List<Long> userIds;
|
||||
|
||||
/**
|
||||
* 配置人ID
|
||||
*/
|
||||
@NotNull(message = "配置人ID不能为空")
|
||||
private Long configBy;
|
||||
|
||||
/**
|
||||
* 配置人姓名
|
||||
*/
|
||||
@NotBlank(message = "配置人姓名不能为空")
|
||||
private String configByName;
|
||||
|
||||
/**
|
||||
* 备注说明
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
package org.dromara.cw.domain.bo;
|
||||
|
||||
import org.dromara.cw.domain.CwProjectAuditor;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import jakarta.validation.constraints.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 项目审核人配置业务对象 cw_project_auditor
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = CwProjectAuditor.class, reverseConvertGenerate = false)
|
||||
public class CwProjectAuditorBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键ID(雪花ID)
|
||||
*/
|
||||
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@NotNull(message = "用户ID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 用户姓名
|
||||
*/
|
||||
@NotBlank(message = "用户姓名不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String nickName;
|
||||
|
||||
/**
|
||||
* 所属部门ID
|
||||
*/
|
||||
@NotNull(message = "所属部门ID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 所属部门名称
|
||||
*/
|
||||
@NotBlank(message = "所属部门名称不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 联系电话
|
||||
*/
|
||||
private String phoneNumber;
|
||||
|
||||
/**
|
||||
* 邮箱地址
|
||||
*/
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 审核人状态(1正常 0停用)
|
||||
*/
|
||||
@NotBlank(message = "审核人状态不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 备注说明
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 配置人ID
|
||||
*/
|
||||
private Long configBy;
|
||||
|
||||
/**
|
||||
* 配置人姓名
|
||||
*/
|
||||
private String configByName;
|
||||
|
||||
}
|
||||
+35
-11
@@ -172,37 +172,37 @@ public class CwApprovalRecordVo implements Serializable {
|
||||
private Date updateTime;
|
||||
|
||||
// ================ 项目申报相关字段(通过关联查询获取) ================
|
||||
|
||||
|
||||
/**
|
||||
* 项目名称
|
||||
*/
|
||||
@ExcelProperty(value = "项目名称")
|
||||
private String projectName;
|
||||
|
||||
|
||||
/**
|
||||
* 申报人姓名
|
||||
*/
|
||||
@ExcelProperty(value = "申报人姓名")
|
||||
private String applicantName;
|
||||
|
||||
|
||||
/**
|
||||
* 申报部门名称
|
||||
*/
|
||||
@ExcelProperty(value = "申报部门")
|
||||
private String deptName;
|
||||
|
||||
|
||||
/**
|
||||
* 总投资(万元)
|
||||
*/
|
||||
@ExcelProperty(value = "总投资(万元)")
|
||||
private java.math.BigDecimal totalInvestment;
|
||||
|
||||
|
||||
/**
|
||||
* 项目负责人
|
||||
*/
|
||||
@ExcelProperty(value = "项目负责人")
|
||||
@ExcelProperty(value = "项目负责人")
|
||||
private String principal;
|
||||
|
||||
|
||||
/**
|
||||
* 部门名称(完整)
|
||||
*/
|
||||
@@ -213,23 +213,47 @@ public class CwApprovalRecordVo implements Serializable {
|
||||
*/
|
||||
@ExcelProperty(value = "当前审批人")
|
||||
private String currentApproverName;
|
||||
|
||||
|
||||
/**
|
||||
* 审批状态(前端表格需要)
|
||||
*/
|
||||
@ExcelProperty(value = "审批状态")
|
||||
private String approvalStatus;
|
||||
|
||||
|
||||
/**
|
||||
* 提交时间(前端表格需要)
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date submitTime;
|
||||
|
||||
|
||||
/**
|
||||
* 审批时间(前端表格需要)
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date approvalTime;
|
||||
|
||||
}
|
||||
/**
|
||||
* 总节点数(从流程表获取)
|
||||
*/
|
||||
@ExcelProperty(value = "总节点数")
|
||||
private Integer totalNodes;
|
||||
|
||||
/**
|
||||
* 当前节点数(从流程表获取)
|
||||
*/
|
||||
@ExcelProperty(value = "当前节点数")
|
||||
private Integer currentNode;
|
||||
|
||||
/**
|
||||
* 流程名称(从流程表获取)
|
||||
*/
|
||||
@ExcelProperty(value = "流程名称")
|
||||
private String processName;
|
||||
|
||||
/**
|
||||
* 流程状态(从流程表获取)
|
||||
*/
|
||||
@ExcelProperty(value = "流程状态")
|
||||
private String processStatus;
|
||||
|
||||
}
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
package org.dromara.cw.domain.vo;
|
||||
|
||||
import org.dromara.cw.domain.CwProjectApprovalProcess;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
|
||||
import org.dromara.common.excel.convert.ExcelDictConvert;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 项目审批流程视图对象 cw_project_approval_process
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = CwProjectApprovalProcess.class)
|
||||
public class CwProjectApprovalProcessVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID(雪花ID)
|
||||
*/
|
||||
@ExcelProperty(value = "主键ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 申报ID
|
||||
*/
|
||||
@ExcelProperty(value = "申报ID")
|
||||
private Long applicationId;
|
||||
|
||||
/**
|
||||
* 申报编号
|
||||
*/
|
||||
@ExcelProperty(value = "申报编号")
|
||||
private String applicationNo;
|
||||
|
||||
/**
|
||||
* 流程名称
|
||||
*/
|
||||
@ExcelProperty(value = "流程名称")
|
||||
private String processName;
|
||||
|
||||
/**
|
||||
* 流程状态(waiting-等待开始 running-进行中 completed-已完成 terminated-已终止)
|
||||
*/
|
||||
@ExcelProperty(value = "流程状态", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "cw_process_status")
|
||||
private String processStatus;
|
||||
|
||||
/**
|
||||
* 总审批节点数
|
||||
*/
|
||||
@ExcelProperty(value = "总审批节点数")
|
||||
private Integer totalNodes;
|
||||
|
||||
/**
|
||||
* 当前审批节点
|
||||
*/
|
||||
@ExcelProperty(value = "当前审批节点")
|
||||
private Integer currentNode;
|
||||
|
||||
/**
|
||||
* 流程开始时间
|
||||
*/
|
||||
@ExcelProperty(value = "流程开始时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date startTime;
|
||||
|
||||
/**
|
||||
* 流程结束时间
|
||||
*/
|
||||
@ExcelProperty(value = "流程结束时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date endTime;
|
||||
|
||||
/**
|
||||
* 提交人ID
|
||||
*/
|
||||
@ExcelProperty(value = "提交人ID")
|
||||
private Long submitterId;
|
||||
|
||||
/**
|
||||
* 提交人姓名
|
||||
*/
|
||||
@ExcelProperty(value = "提交人姓名")
|
||||
private String submitterName;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
|
||||
}
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
package org.dromara.cw.domain.vo;
|
||||
|
||||
import org.dromara.cw.domain.CwProjectAuditor;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
|
||||
import org.dromara.common.excel.convert.ExcelDictConvert;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 项目审核人配置视图对象 cw_project_auditor
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = CwProjectAuditor.class)
|
||||
public class CwProjectAuditorVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID(雪花ID)
|
||||
*/
|
||||
@ExcelProperty(value = "主键ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@ExcelProperty(value = "用户ID")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 用户姓名
|
||||
*/
|
||||
@ExcelProperty(value = "用户姓名")
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
@ExcelProperty(value = "用户昵称")
|
||||
private String nickName;
|
||||
|
||||
/**
|
||||
* 所属部门ID
|
||||
*/
|
||||
@ExcelProperty(value = "所属部门ID")
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 所属部门名称
|
||||
*/
|
||||
@ExcelProperty(value = "所属部门名称")
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 联系电话
|
||||
*/
|
||||
@ExcelProperty(value = "联系电话")
|
||||
private String phoneNumber;
|
||||
|
||||
/**
|
||||
* 邮箱地址
|
||||
*/
|
||||
@ExcelProperty(value = "邮箱地址")
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 审核人状态(1正常 0停用)
|
||||
*/
|
||||
@ExcelProperty(value = "审核人状态", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "sys_normal_disable")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 备注说明
|
||||
*/
|
||||
@ExcelProperty(value = "备注说明")
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 配置人ID
|
||||
*/
|
||||
@ExcelProperty(value = "配置人ID")
|
||||
private Long configBy;
|
||||
|
||||
/**
|
||||
* 配置人姓名
|
||||
*/
|
||||
@ExcelProperty(value = "配置人姓名")
|
||||
private String configByName;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package org.dromara.cw.mapper;
|
||||
|
||||
import org.dromara.cw.domain.CwProjectApprovalProcess;
|
||||
import org.dromara.cw.domain.vo.CwProjectApprovalProcessVo;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
|
||||
/**
|
||||
* 项目审批流程Mapper接口
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
public interface CwProjectApprovalProcessMapper extends BaseMapperPlus<CwProjectApprovalProcess, CwProjectApprovalProcessVo> {
|
||||
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package org.dromara.cw.mapper;
|
||||
|
||||
import org.dromara.cw.domain.CwProjectAuditor;
|
||||
import org.dromara.cw.domain.UserWithDeptInfo;
|
||||
import org.dromara.cw.domain.vo.CwProjectAuditorVo;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 项目审核人配置Mapper接口
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
public interface CwProjectAuditorMapper extends BaseMapperPlus<CwProjectAuditor, CwProjectAuditorVo> {
|
||||
|
||||
/**
|
||||
* 根据部门ID查询可用审核人
|
||||
*/
|
||||
List<CwProjectAuditorVo> selectAuditorsByDeptId(@Param("deptId") Long deptId);
|
||||
|
||||
/**
|
||||
* 查询审核人统计信息
|
||||
*/
|
||||
List<CwProjectAuditorVo> selectAuditorStatistics();
|
||||
|
||||
/**
|
||||
* 查询完整的用户信息(包含部门信息)用于批量添加
|
||||
*/
|
||||
List<UserWithDeptInfo> selectUsersWithDeptInfo(@Param("userIds") List<Long> userIds);
|
||||
|
||||
}
|
||||
+20
@@ -2,6 +2,7 @@ package org.dromara.cw.service;
|
||||
|
||||
import org.dromara.cw.domain.bo.CwApprovalRecordBo;
|
||||
import org.dromara.cw.domain.vo.CwApprovalRecordVo;
|
||||
import org.dromara.cw.domain.CwApprovalRecord;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
|
||||
@@ -119,6 +120,11 @@ public interface ICwApprovalRecordService {
|
||||
*/
|
||||
Boolean insertByBo(CwApprovalRecordBo bo);
|
||||
|
||||
/**
|
||||
* 批量新增审批记录
|
||||
*/
|
||||
Boolean batchInsert(List<CwApprovalRecord> records);
|
||||
|
||||
/**
|
||||
* 修改审批记录
|
||||
*/
|
||||
@@ -190,4 +196,18 @@ public interface ICwApprovalRecordService {
|
||||
*/
|
||||
List<Map<String, Object>> getAvailableApprovers(Long applicationId);
|
||||
|
||||
/**
|
||||
* 创建自定义审批流程
|
||||
* 根据用户选择的审批人列表创建自定义审批流程
|
||||
*
|
||||
* @param applicationId 申报ID
|
||||
* @param applicationNo 申报编号
|
||||
* @param auditorIds 审批人ID列表(按审批顺序排列)
|
||||
* @param submitterId 提交人ID
|
||||
* @param submitterName 提交人名称
|
||||
* @return 是否创建成功
|
||||
*/
|
||||
Boolean createCustomApprovalProcess(Long applicationId, String applicationNo,
|
||||
List<Long> auditorIds, Long submitterId, String submitterName);
|
||||
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
package org.dromara.cw.service;
|
||||
|
||||
import org.dromara.cw.domain.vo.CwProjectApprovalProcessVo;
|
||||
import org.dromara.cw.domain.bo.CwCustomApprovalBo;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 项目审批流程Service接口
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
public interface ICwProjectApprovalProcessService {
|
||||
|
||||
/**
|
||||
* 查询项目审批流程
|
||||
*/
|
||||
CwProjectApprovalProcessVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 查询项目审批流程列表
|
||||
*/
|
||||
TableDataInfo<CwProjectApprovalProcessVo> queryPageList(CwProjectApprovalProcessVo vo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询项目审批流程列表
|
||||
*/
|
||||
List<CwProjectApprovalProcessVo> queryList(CwProjectApprovalProcessVo vo);
|
||||
|
||||
/**
|
||||
* 根据申报ID查询审批流程
|
||||
*/
|
||||
CwProjectApprovalProcessVo queryByApplicationId(Long applicationId);
|
||||
|
||||
/**
|
||||
* 根据申报编号查询审批流程
|
||||
*/
|
||||
CwProjectApprovalProcessVo queryByApplicationNo(String applicationNo);
|
||||
|
||||
/**
|
||||
* 查询我提交的审批流程
|
||||
*/
|
||||
List<CwProjectApprovalProcessVo> queryMyProcesses(Long submitterId);
|
||||
|
||||
/**
|
||||
* 查询进行中的审批流程
|
||||
*/
|
||||
List<CwProjectApprovalProcessVo> queryRunningProcesses();
|
||||
|
||||
/**
|
||||
* 查询超时的审批流程
|
||||
*/
|
||||
List<CwProjectApprovalProcessVo> queryOvertimeProcesses(Integer hours);
|
||||
|
||||
/**
|
||||
* 启动自定义审批流程
|
||||
*/
|
||||
Boolean startCustomApprovalProcess(CwCustomApprovalBo bo);
|
||||
|
||||
/**
|
||||
* 终止审批流程
|
||||
*/
|
||||
Boolean terminateProcess(Long id, String reason);
|
||||
|
||||
/**
|
||||
* 校验并批量删除项目审批流程信息
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 推进流程到下一节点
|
||||
*/
|
||||
Boolean advanceToNextNode(Long processId);
|
||||
|
||||
/**
|
||||
* 完成审批流程
|
||||
*/
|
||||
Boolean completeProcess(Long processId);
|
||||
|
||||
/**
|
||||
* 更新流程当前节点
|
||||
*/
|
||||
Boolean updateCurrentNode(Long id, Integer currentNode);
|
||||
|
||||
/**
|
||||
* 更新流程状态
|
||||
*/
|
||||
Boolean updateProcessStatus(Long id, String status);
|
||||
|
||||
/**
|
||||
* 验证审批流程配置
|
||||
*/
|
||||
Boolean validateApprovalProcess(CwCustomApprovalBo bo);
|
||||
|
||||
/**
|
||||
* 统计审批流程状态
|
||||
*/
|
||||
List<Map<String, Object>> queryProcessStatistics(Long submitterId);
|
||||
|
||||
/**
|
||||
* 导出数据
|
||||
*/
|
||||
List<CwProjectApprovalProcessVo> exportList(CwProjectApprovalProcessVo vo);
|
||||
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package org.dromara.cw.service;
|
||||
|
||||
import org.dromara.cw.domain.bo.CwCustomApprovalBo;
|
||||
import org.dromara.cw.domain.bo.CwApprovalActionBo;
|
||||
import org.dromara.cw.domain.vo.CwProjectApprovalProcessVo;
|
||||
import org.dromara.cw.domain.vo.CwApprovalRecordVo;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 项目审批流程Service接口
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
public interface ICwProjectApprovalService {
|
||||
|
||||
/**
|
||||
* 启动自定义审批流程
|
||||
*/
|
||||
Boolean startCustomApprovalProcess(CwCustomApprovalBo bo);
|
||||
|
||||
/**
|
||||
* 执行审批操作
|
||||
*/
|
||||
Boolean executeApproval(CwApprovalActionBo bo);
|
||||
|
||||
/**
|
||||
* 获取我的待审批列表
|
||||
*/
|
||||
TableDataInfo<CwApprovalRecordVo> getMyPendingApprovals(PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 获取我的已审批列表
|
||||
*/
|
||||
TableDataInfo<CwApprovalRecordVo> getMyProcessedApprovals(PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询审批流程列表
|
||||
*/
|
||||
TableDataInfo<CwProjectApprovalProcessVo> queryProcessList(PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 获取审批流程详情
|
||||
*/
|
||||
CwProjectApprovalProcessVo getProcessDetail(Long processId);
|
||||
|
||||
/**
|
||||
* 获取审批记录列表
|
||||
*/
|
||||
List<CwApprovalRecordVo> getApprovalRecords(Long applicationId);
|
||||
|
||||
/**
|
||||
* 终止审批流程
|
||||
*/
|
||||
Boolean terminateProcess(List<Long> processIds);
|
||||
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
package org.dromara.cw.service;
|
||||
|
||||
import org.dromara.cw.domain.vo.CwProjectAuditorVo;
|
||||
import org.dromara.cw.domain.bo.CwProjectAuditorBo;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 项目审核人配置Service接口
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
public interface ICwProjectAuditorService {
|
||||
|
||||
/**
|
||||
* 查询项目审核人配置
|
||||
*/
|
||||
CwProjectAuditorVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 查询项目审核人配置列表
|
||||
*/
|
||||
TableDataInfo<CwProjectAuditorVo> queryPageList(CwProjectAuditorBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询项目审核人配置列表
|
||||
*/
|
||||
List<CwProjectAuditorVo> queryList(CwProjectAuditorBo bo);
|
||||
|
||||
/**
|
||||
* 新增项目审核人配置
|
||||
*/
|
||||
Boolean insertByBo(CwProjectAuditorBo bo);
|
||||
|
||||
/**
|
||||
* 修改项目审核人配置
|
||||
*/
|
||||
Boolean updateByBo(CwProjectAuditorBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除项目审核人配置信息
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 批量添加审核人(从部门用户中选择)
|
||||
*/
|
||||
Boolean batchAddAuditors(List<Long> userIds, Long configBy, String configByName, String remark);
|
||||
|
||||
/**
|
||||
* 获取可用审核人列表
|
||||
*/
|
||||
List<CwProjectAuditorVo> getAvailableAuditors();
|
||||
|
||||
/**
|
||||
* 根据部门ID获取用户列表
|
||||
*/
|
||||
List<Object> getDeptUsers(Long deptId);
|
||||
|
||||
/**
|
||||
* 批量更新状态
|
||||
*/
|
||||
Boolean updateStatus(List<Long> ids, String status);
|
||||
|
||||
/**
|
||||
* 获取审核人统计数据
|
||||
*/
|
||||
Object getStatistics();
|
||||
|
||||
/**
|
||||
* 根据用户ID查询项目审核人配置
|
||||
*/
|
||||
CwProjectAuditorVo queryByUserId(Long userId);
|
||||
|
||||
}
|
||||
+238
-24
@@ -5,13 +5,12 @@ import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.helper.DataPermissionHelper;
|
||||
import org.dromara.common.redis.utils.SequenceUtils;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
|
||||
import java.time.Duration;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -25,8 +24,10 @@ import org.dromara.cw.domain.CwApprovalRecord;
|
||||
import org.dromara.cw.mapper.CwApprovalRecordMapper;
|
||||
import org.dromara.cw.service.ICwApprovalRecordService;
|
||||
import org.dromara.cw.service.ICwProjectApplicationService;
|
||||
import org.dromara.cw.service.ICwProjectAuditorService;
|
||||
import org.dromara.cw.mapper.CwProjectApplicationMapper;
|
||||
import org.dromara.cw.domain.CwProjectApplication;
|
||||
import org.dromara.cw.domain.vo.CwProjectAuditorVo;
|
||||
import org.dromara.system.service.ISysUserService;
|
||||
import org.dromara.system.service.ISysDeptService;
|
||||
import org.dromara.system.domain.vo.SysUserVo;
|
||||
@@ -54,6 +55,7 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
private final CwProjectApplicationMapper applicationMapper;
|
||||
private final ISysUserService sysUserService;
|
||||
private final ISysDeptService sysDeptService;
|
||||
private final ICwProjectAuditorService projectAuditorService;
|
||||
|
||||
/**
|
||||
* 根据主键查询审批记录
|
||||
@@ -502,6 +504,17 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量新增审批记录
|
||||
*/
|
||||
@Override
|
||||
public Boolean batchInsert(List<CwApprovalRecord> records) {
|
||||
if (records == null || records.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return baseMapper.batchInsert(records) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改审批记录
|
||||
*/
|
||||
@@ -678,8 +691,8 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
Long currentDeptId, String currentTenantId) {
|
||||
CwApprovalRecord record = new CwApprovalRecord();
|
||||
|
||||
// 生成唯一ID(批量插入需要手动生成)
|
||||
record.setId(SequenceUtils.nextId("approval_record", Duration.ofDays(1)));
|
||||
// 移除手动ID设置,使用MyBatis-Plus自动生成雪花ID(符合项目规范)
|
||||
// record.setId() - 让MyBatis-Plus自动生成,避免主键冲突
|
||||
|
||||
// 设置申报相关信息
|
||||
record.setApplicationId(applicationId);
|
||||
@@ -979,27 +992,110 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
}
|
||||
|
||||
private Boolean updateApplicationStatusAndProcess(Long applicationId, String nodeCode, String approveAction) {
|
||||
if ("approve".equals(approveAction)) {
|
||||
// 审批通过,启动下一个节点或完成审批
|
||||
if ("dept_approve".equals(nodeCode)) {
|
||||
// 部门审批通过,启动财务审批
|
||||
return startNextApprovalNode(applicationId, "finance_approve");
|
||||
} else if ("finance_approve".equals(nodeCode)) {
|
||||
// 财务审批通过,启动领导审批
|
||||
return startNextApprovalNode(applicationId, "leader_approve");
|
||||
} else if ("leader_approve".equals(nodeCode)) {
|
||||
// 领导审批通过,整个审批流程完成
|
||||
return projectApplicationService.updateApprovalStatus(applicationId, "approved");
|
||||
}
|
||||
} else if ("reject".equals(approveAction)) {
|
||||
// 审批拒绝,整个流程结束
|
||||
return projectApplicationService.updateApprovalStatus(applicationId, "rejected");
|
||||
} else if ("return".equals(approveAction)) {
|
||||
// 退回修改,申报状态改为已退回
|
||||
return projectApplicationService.updateApprovalStatus(applicationId, "returned");
|
||||
}
|
||||
try {
|
||||
// 获取当前审批记录
|
||||
LambdaQueryWrapper<CwApprovalRecord> currentQuery = Wrappers.<CwApprovalRecord>lambdaQuery()
|
||||
.eq(CwApprovalRecord::getApplicationId, applicationId)
|
||||
.eq(CwApprovalRecord::getNodeCode, nodeCode);
|
||||
CwApprovalRecord currentRecord = baseMapper.selectOne(currentQuery);
|
||||
|
||||
return true;
|
||||
if (currentRecord == null) {
|
||||
log.error("❌ 当前审批记录不存在:applicationId={}, nodeCode={}", applicationId, nodeCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ("approve".equals(approveAction)) {
|
||||
// 🔧 基于node_order的顺序审批逻辑
|
||||
log.info("✅ 审批通过,查找下一级审批:applicationId={}, currentOrder={}",
|
||||
applicationId, currentRecord.getNodeOrder());
|
||||
|
||||
// 查找下一级审批记录(node_order + 1)
|
||||
LambdaQueryWrapper<CwApprovalRecord> nextQuery = Wrappers.<CwApprovalRecord>lambdaQuery()
|
||||
.eq(CwApprovalRecord::getApplicationId, applicationId)
|
||||
.eq(CwApprovalRecord::getNodeOrder, currentRecord.getNodeOrder() + 1);
|
||||
CwApprovalRecord nextRecord = baseMapper.selectOne(nextQuery);
|
||||
|
||||
if (nextRecord != null) {
|
||||
// 存在下一级审批,激活下一级
|
||||
log.info("📋 激活下一级审批:nextRecordId={}, nodeOrder={}, nodeCode={}, currentStatus={}",
|
||||
nextRecord.getId(), nextRecord.getNodeOrder(), nextRecord.getNodeCode(), nextRecord.getNodeStatus());
|
||||
|
||||
// 使用条件更新,确保只有在特定状态下才能激活
|
||||
LambdaUpdateWrapper<CwApprovalRecord> updateWrapper = Wrappers.<CwApprovalRecord>lambdaUpdate()
|
||||
.eq(CwApprovalRecord::getId, nextRecord.getId())
|
||||
.eq(CwApprovalRecord::getApplicationId, applicationId)
|
||||
.ne(CwApprovalRecord::getNodeStatus, "waiting") // 避免重复激活已经是waiting状态的记录
|
||||
.ne(CwApprovalRecord::getNodeStatus, "approved") // 避免激活已完成的记录
|
||||
.ne(CwApprovalRecord::getNodeStatus, "rejected") // 避免激活已拒绝的记录
|
||||
.set(CwApprovalRecord::getNodeStatus, "waiting")
|
||||
.set(CwApprovalRecord::getStartTime, new Date()) // 设置开始时间
|
||||
.set(CwApprovalRecord::getUpdateTime, new Date())
|
||||
.set(CwApprovalRecord::getUpdateBy, LoginHelper.getUserId());
|
||||
|
||||
int updateResult = baseMapper.update(null, updateWrapper);
|
||||
|
||||
if (updateResult <= 0) {
|
||||
log.error("❌ 激活下一级审批失败: applicationId={}, nextRecordId={}, nodeOrder={}, nodeCode={}",
|
||||
applicationId, nextRecord.getId(), nextRecord.getNodeOrder(), nextRecord.getNodeCode());
|
||||
|
||||
// 重新查询记录状态,分析失败原因
|
||||
CwApprovalRecord checkRecord = baseMapper.selectById(nextRecord.getId());
|
||||
if (checkRecord == null) {
|
||||
log.error("❌ 下一级审批记录已不存在: recordId={}", nextRecord.getId());
|
||||
} else {
|
||||
log.error("❌ 下一级审批记录状态不符合激活条件: recordId={}, currentStatus={}, 限制条件=不能是[waiting,approved,rejected]",
|
||||
nextRecord.getId(), checkRecord.getNodeStatus());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
log.info("✅ 下一级审批已激活成功: recordId={}, newStatus=waiting", nextRecord.getId());
|
||||
return true;
|
||||
} else {
|
||||
// 没有下一级审批,整个流程完成
|
||||
log.info("🎉 所有审批完成,更新申报状态为approved: applicationId={}, currentOrder={}",
|
||||
applicationId, currentRecord.getNodeOrder());
|
||||
|
||||
boolean statusUpdateResult = projectApplicationService.updateApprovalStatus(applicationId, "approved");
|
||||
if (!statusUpdateResult) {
|
||||
log.error("❌ 更新申报状态为approved失败: applicationId={}", applicationId);
|
||||
return false;
|
||||
}
|
||||
|
||||
log.info("✅ 申报状态已成功更新为approved: applicationId={}", applicationId);
|
||||
return true;
|
||||
}
|
||||
|
||||
} else if ("reject".equals(approveAction)) {
|
||||
// 审批拒绝,整个流程结束
|
||||
log.info("❌ 审批拒绝,更新申报状态为rejected: applicationId={}", applicationId);
|
||||
boolean rejectResult = projectApplicationService.updateApprovalStatus(applicationId, "rejected");
|
||||
if (!rejectResult) {
|
||||
log.error("❌ 更新申报状态为rejected失败: applicationId={}", applicationId);
|
||||
return false;
|
||||
}
|
||||
log.info("✅ 申报状态已更新为rejected: applicationId={}", applicationId);
|
||||
return true;
|
||||
|
||||
} else if ("return".equals(approveAction)) {
|
||||
// 退回修改,申报状态改为已退回,保留历史审批记录
|
||||
log.info("↩️ 审批退回,更新申报状态为returned: applicationId={}", applicationId);
|
||||
boolean returnResult = projectApplicationService.updateApprovalStatus(applicationId, "returned");
|
||||
if (!returnResult) {
|
||||
log.error("❌ 更新申报状态为returned失败: applicationId={}", applicationId);
|
||||
return false;
|
||||
}
|
||||
log.info("✅ 申报状态已更新为returned: applicationId={}", applicationId);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("❌ 更新申报状态和流程失败:applicationId={}, nodeCode={}, action={}, error={}",
|
||||
applicationId, nodeCode, approveAction, e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private Boolean startNextApprovalNode(Long applicationId, String nextNodeCode) {
|
||||
@@ -1450,4 +1546,122 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
|
||||
throw new RuntimeException("指定院领导审批人失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建自定义审批流程
|
||||
* 根据用户选择的审批人列表创建自定义审批流程
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean createCustomApprovalProcess(Long applicationId, String applicationNo,
|
||||
List<Long> auditorIds, Long submitterId, String submitterName) {
|
||||
|
||||
log.info("🚀 创建自定义审批流程:applicationId={}, auditorIds={}", applicationId, auditorIds);
|
||||
|
||||
try {
|
||||
// 1. 验证参数
|
||||
if (applicationId == null) {
|
||||
throw new RuntimeException("申报ID不能为空");
|
||||
}
|
||||
if (auditorIds == null || auditorIds.isEmpty()) {
|
||||
throw new RuntimeException("审批人列表不能为空");
|
||||
}
|
||||
|
||||
// 2. 验证审批人是否有效
|
||||
List<CwProjectAuditorVo> validAuditors = validateAuditors(auditorIds);
|
||||
if (validAuditors.size() != auditorIds.size()) {
|
||||
throw new RuntimeException("包含无效的审批人,请重新选择");
|
||||
}
|
||||
|
||||
// 3. 创建自定义审批记录
|
||||
List<CwApprovalRecord> records = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < auditorIds.size(); i++) {
|
||||
Long auditorId = auditorIds.get(i);
|
||||
CwProjectAuditorVo auditor = validAuditors.get(i);
|
||||
|
||||
CwApprovalRecord record = new CwApprovalRecord();
|
||||
// 移除手动ID设置,使用MyBatis-Plus自动生成雪花ID(符合项目规范)
|
||||
// record.setId() - 让MyBatis-Plus自动生成,避免主键冲突
|
||||
record.setApplicationId(applicationId);
|
||||
record.setApplicationNo(applicationNo);
|
||||
record.setNodeCode("custom_node_" + (i + 1));
|
||||
record.setNodeName("自定义审批节点" + (i + 1));
|
||||
record.setNodeOrder(i + 1);
|
||||
record.setApproverId(auditorId);
|
||||
record.setApproverName(auditor.getUserName());
|
||||
record.setNodeStatus(i == 0 ? "waiting" : "pending"); // 第一个waiting,其他pending
|
||||
|
||||
// 设置基础字段
|
||||
Date now = new Date();
|
||||
record.setCreateBy(submitterId);
|
||||
record.setCreateTime(now);
|
||||
record.setUpdateBy(submitterId);
|
||||
record.setUpdateTime(now);
|
||||
record.setTenantId(LoginHelper.getTenantId());
|
||||
record.setIsDelegate(false);
|
||||
record.setIsOvertime(false);
|
||||
|
||||
// 🔧 修复:设置startTime字段(数据库NOT NULL约束)
|
||||
if (i == 0) {
|
||||
// 第一个节点:waiting状态,立即开始
|
||||
record.setStartTime(now);
|
||||
log.info("设置自定义审批第一个节点开始时间:{} -> {}", record.getNodeCode(), now);
|
||||
} else {
|
||||
// 后续节点:pending状态,也需要设置startTime满足数据库约束
|
||||
record.setStartTime(now);
|
||||
log.info("设置自定义审批后续节点开始时间:{} -> {} (满足数据库约束)", record.getNodeCode(), now);
|
||||
}
|
||||
|
||||
records.add(record);
|
||||
}
|
||||
|
||||
// 4. 批量插入审批记录
|
||||
boolean result = false;
|
||||
if (!records.isEmpty()) {
|
||||
for (CwApprovalRecord record : records) {
|
||||
result = baseMapper.insert(record) > 0;
|
||||
if (!result) {
|
||||
throw new RuntimeException("创建审批记录失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 同步更新项目申报状态为"审批中"
|
||||
// 这是关键步骤:启动审批流程的同时提交申报
|
||||
ICwProjectApplicationService applicationService = SpringUtils.getBean(ICwProjectApplicationService.class);
|
||||
boolean statusUpdateResult = applicationService.updateApprovalStatus(applicationId, "approving");
|
||||
if (!statusUpdateResult) {
|
||||
throw new RuntimeException("更新申报状态失败,审批流程创建失败");
|
||||
}
|
||||
|
||||
log.info("✅ 自定义审批流程创建成功:共创建{}个审批节点", records.size());
|
||||
log.info("✅ 申报状态已更新为审批中:applicationId={}", applicationId);
|
||||
return result;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("❌ 创建自定义审批流程失败:{}", e.getMessage(), e);
|
||||
throw new RuntimeException("创建审批流程失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证审批人列表
|
||||
*/
|
||||
private List<CwProjectAuditorVo> validateAuditors(List<Long> auditorIds) {
|
||||
List<CwProjectAuditorVo> validAuditors = new ArrayList<>();
|
||||
|
||||
for (Long auditorId : auditorIds) {
|
||||
CwProjectAuditorVo auditor = projectAuditorService.queryByUserId(auditorId);
|
||||
if (auditor == null) {
|
||||
throw new RuntimeException("审批人不存在:" + auditorId);
|
||||
}
|
||||
if (!"1".equals(auditor.getStatus())) {
|
||||
throw new RuntimeException("审批人已停用:" + auditor.getUserName());
|
||||
}
|
||||
validAuditors.add(auditor);
|
||||
}
|
||||
|
||||
return validAuditors;
|
||||
}
|
||||
}
|
||||
+68
-15
@@ -19,8 +19,8 @@ import org.dromara.cw.domain.CwProjectApplication;
|
||||
import org.dromara.cw.mapper.CwProjectApplicationMapper;
|
||||
import org.dromara.cw.service.ICwProjectApplicationService;
|
||||
import org.dromara.cw.service.ICwPerformanceIndicatorService;
|
||||
import org.dromara.cw.event.ApprovalProcessCreatedEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.dromara.cw.service.ICwApprovalRecordService;
|
||||
import org.dromara.common.core.utils.SpringUtils;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
@@ -41,7 +41,6 @@ public class CwProjectApplicationServiceImpl implements ICwProjectApplicationSer
|
||||
|
||||
private final CwProjectApplicationMapper baseMapper;
|
||||
private final ICwPerformanceIndicatorService performanceIndicatorService;
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
|
||||
/**
|
||||
* 查询项目预算申报
|
||||
@@ -584,30 +583,34 @@ public class CwProjectApplicationServiceImpl implements ICwProjectApplicationSer
|
||||
}
|
||||
|
||||
if (updateResult) {
|
||||
// 异步发布审批流程创建事件(避免阻塞主流程)
|
||||
// 直接同步创建审批流程(确保事务一致性)
|
||||
try {
|
||||
log.info("🚀 准备异步发布审批流程创建事件:applicationId={}, applicationNo={}", id, application.getApplicationNo());
|
||||
log.info("🚀 开始同步创建审批流程:applicationId={}, applicationNo={}", id, application.getApplicationNo());
|
||||
|
||||
// 在主线程中收集用户上下文信息(异步线程中无法获取)
|
||||
// 收集用户上下文信息
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
String currentUserName = LoginHelper.getUsername();
|
||||
Long currentDeptId = LoginHelper.getDeptId();
|
||||
String currentTenantId = LoginHelper.getTenantId();
|
||||
|
||||
log.info("📋 收集用户上下文:userId={}, userName={}, deptId={}, tenantId={}",
|
||||
log.info("📋 用户上下文:userId={}, userName={}, deptId={}, tenantId={}",
|
||||
currentUserId, currentUserName, currentDeptId, currentTenantId);
|
||||
|
||||
ApprovalProcessCreatedEvent event = new ApprovalProcessCreatedEvent(
|
||||
this, id, application.getApplicationNo(),
|
||||
// 使用SpringUtils动态获取服务,避免循环依赖
|
||||
ICwApprovalRecordService approvalRecordService = SpringUtils.getBean(ICwApprovalRecordService.class);
|
||||
Boolean createResult = approvalRecordService.createApprovalProcess(
|
||||
id, application.getApplicationNo(),
|
||||
currentUserId, currentUserName, currentDeptId, currentTenantId);
|
||||
|
||||
log.info("📤 异步发布事件(不阻塞主流程)...");
|
||||
eventPublisher.publishEvent(event);
|
||||
log.info("✅ 审批流程创建事件发布完成(异步处理中):applicationId={}, applicationNo={}",
|
||||
id, application.getApplicationNo());
|
||||
if (createResult) {
|
||||
log.info("✅ 审批流程创建成功:applicationId={}, applicationNo={}", id, application.getApplicationNo());
|
||||
} else {
|
||||
log.error("❌ 审批流程创建失败:applicationId={}, applicationNo={}", id, application.getApplicationNo());
|
||||
throw new RuntimeException("审批流程创建失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("💥 发布审批流程创建事件失败:applicationId={}, error={}", id, e.getMessage(), e);
|
||||
// 事件发布失败不影响提交,审批流程会在后台异步创建
|
||||
log.error("💥 创建审批流程异常:applicationId={}, error={}", id, e.getMessage(), e);
|
||||
throw new RuntimeException("创建审批流程失败:" + e.getMessage(), e);
|
||||
}
|
||||
} else {
|
||||
log.error("❌ 申报提交失败,数据库更新返回false:applicationId={}", id);
|
||||
@@ -667,16 +670,66 @@ public class CwProjectApplicationServiceImpl implements ICwProjectApplicationSer
|
||||
throw new RuntimeException("申报记录不存在");
|
||||
}
|
||||
|
||||
// 验证状态转换的合法性
|
||||
String currentStatus = application.getApprovalStatus();
|
||||
log.info("更新申报状态:applicationId={}, {} -> {}", id, currentStatus, approvalStatus);
|
||||
|
||||
// 当从草稿状态提交到审批中时,进行数据完整性验证和字段设置
|
||||
if ("draft".equals(currentStatus) && "approving".equals(approvalStatus)) {
|
||||
// 验证申报数据完整性
|
||||
validateApplicationForSubmission(application);
|
||||
|
||||
// 设置提交时间(第一次提交)
|
||||
if (application.getSubmitTime() == null) {
|
||||
application.setSubmitTime(new Date());
|
||||
log.info("设置申报提交时间:applicationId={}", id);
|
||||
}
|
||||
|
||||
// 生成申报编号(如果还没有)
|
||||
if (StringUtils.isBlank(application.getApplicationNo())) {
|
||||
String applicationNo = generateApplicationNo();
|
||||
application.setApplicationNo(applicationNo);
|
||||
log.info("生成申报编号:applicationId={}, applicationNo={}", id, applicationNo);
|
||||
}
|
||||
|
||||
log.info("✅ 申报正式提交:从草稿状态提交到审批中");
|
||||
}
|
||||
|
||||
// 更新审批状态
|
||||
application.setApprovalStatus(approvalStatus);
|
||||
|
||||
// 如果是最终通过或拒绝状态,设置审批完成时间
|
||||
if ("approved".equals(approvalStatus) || "rejected".equals(approvalStatus)) {
|
||||
application.setApproveTime(new Date());
|
||||
log.info("设置审批完成时间:applicationId={}, status={}", id, approvalStatus);
|
||||
}
|
||||
|
||||
return baseMapper.updateById(application) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证申报数据完整性(提交时验证)
|
||||
*/
|
||||
private void validateApplicationForSubmission(CwProjectApplication application) {
|
||||
if (StringUtils.isBlank(application.getProjectName())) {
|
||||
throw new RuntimeException("项目名称不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(application.getPrincipal())) {
|
||||
throw new RuntimeException("项目负责人不能为空");
|
||||
}
|
||||
if (application.getTotalInvestment() == null || application.getTotalInvestment().compareTo(BigDecimal.ZERO) <= 0) {
|
||||
throw new RuntimeException("项目总投资必须大于0");
|
||||
}
|
||||
if (application.getYear() == null) {
|
||||
throw new RuntimeException("预算年度不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(application.getApplicationReason())) {
|
||||
throw new RuntimeException("项目申请原因不能为空");
|
||||
}
|
||||
|
||||
log.info("✅ 申报数据完整性验证通过:applicationId={}", application.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成申报编号
|
||||
*/
|
||||
|
||||
+289
@@ -0,0 +1,289 @@
|
||||
package org.dromara.cw.service.impl;
|
||||
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.dromara.cw.domain.bo.CwProjectApprovalProcessBo;
|
||||
import org.dromara.cw.domain.bo.CwCustomApprovalBo;
|
||||
import org.dromara.cw.domain.vo.CwProjectApprovalProcessVo;
|
||||
import org.dromara.cw.domain.CwProjectApprovalProcess;
|
||||
import org.dromara.cw.mapper.CwProjectApprovalProcessMapper;
|
||||
import org.dromara.cw.service.ICwProjectApprovalProcessService;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 项目审批流程Service业务层处理
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class CwProjectApprovalProcessServiceImpl implements ICwProjectApprovalProcessService {
|
||||
|
||||
private final CwProjectApprovalProcessMapper baseMapper;
|
||||
|
||||
/**
|
||||
* 查询项目审批流程
|
||||
*/
|
||||
@Override
|
||||
public CwProjectApprovalProcessVo queryById(Long id){
|
||||
return baseMapper.selectVoById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询项目审批流程列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<CwProjectApprovalProcessVo> queryPageList(CwProjectApprovalProcessVo vo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<CwProjectApprovalProcess> lqw = buildQueryWrapper(vo);
|
||||
Page<CwProjectApprovalProcessVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询项目审批流程列表
|
||||
*/
|
||||
@Override
|
||||
public List<CwProjectApprovalProcessVo> queryList(CwProjectApprovalProcessVo vo) {
|
||||
LambdaQueryWrapper<CwProjectApprovalProcess> lqw = buildQueryWrapper(vo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<CwProjectApprovalProcess> buildQueryWrapper(CwProjectApprovalProcessVo vo) {
|
||||
LambdaQueryWrapper<CwProjectApprovalProcess> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(vo.getApplicationId() != null, CwProjectApprovalProcess::getApplicationId, vo.getApplicationId());
|
||||
lqw.like(StringUtils.isNotBlank(vo.getApplicationNo()), CwProjectApprovalProcess::getApplicationNo, vo.getApplicationNo());
|
||||
lqw.like(StringUtils.isNotBlank(vo.getProcessName()), CwProjectApprovalProcess::getProcessName, vo.getProcessName());
|
||||
lqw.eq(StringUtils.isNotBlank(vo.getProcessStatus()), CwProjectApprovalProcess::getProcessStatus, vo.getProcessStatus());
|
||||
lqw.eq(vo.getTotalNodes() != null, CwProjectApprovalProcess::getTotalNodes, vo.getTotalNodes());
|
||||
lqw.eq(vo.getCurrentNode() != null, CwProjectApprovalProcess::getCurrentNode, vo.getCurrentNode());
|
||||
lqw.eq(vo.getSubmitterId() != null, CwProjectApprovalProcess::getSubmitterId, vo.getSubmitterId());
|
||||
lqw.like(StringUtils.isNotBlank(vo.getSubmitterName()), CwProjectApprovalProcess::getSubmitterName, vo.getSubmitterName());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(CwProjectApprovalProcess entity){
|
||||
// 检查申报ID是否已存在流程
|
||||
if (entity.getApplicationId() != null) {
|
||||
LambdaQueryWrapper<CwProjectApprovalProcess> wrapper = Wrappers.lambdaQuery();
|
||||
wrapper.eq(CwProjectApprovalProcess::getApplicationId, entity.getApplicationId());
|
||||
if (entity.getId() != null) {
|
||||
wrapper.ne(CwProjectApprovalProcess::getId, entity.getId());
|
||||
}
|
||||
if (baseMapper.exists(wrapper)) {
|
||||
throw new RuntimeException("该申报已存在审批流程");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除项目审批流程
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if(isValid){
|
||||
//TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据申报ID查询审批流程
|
||||
*/
|
||||
@Override
|
||||
public CwProjectApprovalProcessVo queryByApplicationId(Long applicationId) {
|
||||
LambdaQueryWrapper<CwProjectApprovalProcess> wrapper = Wrappers.lambdaQuery();
|
||||
wrapper.eq(CwProjectApprovalProcess::getApplicationId, applicationId);
|
||||
return baseMapper.selectVoOne(wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据申报编号查询审批流程
|
||||
*/
|
||||
@Override
|
||||
public CwProjectApprovalProcessVo queryByApplicationNo(String applicationNo) {
|
||||
LambdaQueryWrapper<CwProjectApprovalProcess> wrapper = Wrappers.lambdaQuery();
|
||||
wrapper.eq(CwProjectApprovalProcess::getApplicationNo, applicationNo);
|
||||
return baseMapper.selectVoOne(wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询我提交的流程
|
||||
*/
|
||||
@Override
|
||||
public List<CwProjectApprovalProcessVo> queryMyProcesses(Long submitterId) {
|
||||
LambdaQueryWrapper<CwProjectApprovalProcess> wrapper = Wrappers.lambdaQuery();
|
||||
wrapper.eq(CwProjectApprovalProcess::getSubmitterId, submitterId);
|
||||
wrapper.orderByDesc(CwProjectApprovalProcess::getCreateTime);
|
||||
return baseMapper.selectVoList(wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询运行中的流程
|
||||
*/
|
||||
@Override
|
||||
public List<CwProjectApprovalProcessVo> queryRunningProcesses() {
|
||||
LambdaQueryWrapper<CwProjectApprovalProcess> wrapper = Wrappers.lambdaQuery();
|
||||
wrapper.eq(CwProjectApprovalProcess::getProcessStatus, "running");
|
||||
wrapper.orderByDesc(CwProjectApprovalProcess::getCreateTime);
|
||||
return baseMapper.selectVoList(wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询超时流程
|
||||
*/
|
||||
@Override
|
||||
public List<CwProjectApprovalProcessVo> queryOvertimeProcesses(Integer hours) {
|
||||
// 这里可以根据需要实现超时查询逻辑
|
||||
LambdaQueryWrapper<CwProjectApprovalProcess> wrapper = Wrappers.lambdaQuery();
|
||||
wrapper.eq(CwProjectApprovalProcess::getProcessStatus, "running");
|
||||
wrapper.orderByDesc(CwProjectApprovalProcess::getCreateTime);
|
||||
return baseMapper.selectVoList(wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动自定义审批流程
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public Boolean startCustomApprovalProcess(CwCustomApprovalBo bo) {
|
||||
try {
|
||||
// 1. 创建审批流程
|
||||
CwProjectApprovalProcess process = new CwProjectApprovalProcess();
|
||||
process.setApplicationId(bo.getApplicationId());
|
||||
process.setApplicationNo(bo.getApplicationNo());
|
||||
process.setProcessName(bo.getProcessName());
|
||||
process.setProcessStatus("running");
|
||||
process.setTotalNodes(bo.getAuditorIds().size());
|
||||
process.setCurrentNode(1);
|
||||
process.setStartTime(new Date());
|
||||
process.setSubmitterId(bo.getSubmitterId());
|
||||
process.setSubmitterName(bo.getSubmitterName());
|
||||
|
||||
boolean result = baseMapper.insert(process) > 0;
|
||||
|
||||
// TODO: 这里可以创建对应的审批记录
|
||||
// 由于CwApprovalRecord相关的实现比较复杂,这里先简化处理
|
||||
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("启动审批流程失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 终止审批流程
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public Boolean terminateProcess(Long id, String reason) {
|
||||
CwProjectApprovalProcess update = new CwProjectApprovalProcess();
|
||||
update.setId(id);
|
||||
update.setProcessStatus("terminated");
|
||||
update.setEndTime(new Date());
|
||||
update.setUpdateBy(LoginHelper.getUserId());
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 推进流程到下一节点
|
||||
*/
|
||||
@Override
|
||||
public Boolean advanceToNextNode(Long processId) {
|
||||
CwProjectApprovalProcess process = baseMapper.selectById(processId);
|
||||
if (process != null && process.getCurrentNode() < process.getTotalNodes()) {
|
||||
return updateCurrentNode(processId, process.getCurrentNode() + 1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 完成审批流程
|
||||
*/
|
||||
@Override
|
||||
public Boolean completeProcess(Long processId) {
|
||||
return updateProcessStatus(processId, "completed");
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新流程当前节点
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateCurrentNode(Long id, Integer currentNode) {
|
||||
CwProjectApprovalProcess update = new CwProjectApprovalProcess();
|
||||
update.setId(id);
|
||||
update.setCurrentNode(currentNode);
|
||||
update.setUpdateBy(LoginHelper.getUserId());
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新流程状态
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateProcessStatus(Long id, String status) {
|
||||
CwProjectApprovalProcess update = new CwProjectApprovalProcess();
|
||||
update.setId(id);
|
||||
update.setProcessStatus(status);
|
||||
update.setUpdateBy(LoginHelper.getUserId());
|
||||
if ("completed".equals(status) || "terminated".equals(status)) {
|
||||
update.setEndTime(new Date());
|
||||
}
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证审批流程配置
|
||||
*/
|
||||
@Override
|
||||
public Boolean validateApprovalProcess(CwCustomApprovalBo bo) {
|
||||
// 验证基本参数
|
||||
if (bo.getApplicationId() == null ||
|
||||
StringUtils.isBlank(bo.getApplicationNo()) ||
|
||||
bo.getAuditorIds() == null || bo.getAuditorIds().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
// TODO: 可以添加更多验证逻辑
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计审批流程状态
|
||||
*/
|
||||
@Override
|
||||
public List<Map<String, Object>> queryProcessStatistics(Long submitterId) {
|
||||
// 这里可以根据需要实现统计逻辑
|
||||
return List.of(Map.of(
|
||||
"totalProcesses", 0,
|
||||
"runningProcesses", 0,
|
||||
"completedProcesses", 0,
|
||||
"terminatedProcesses", 0
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出数据
|
||||
*/
|
||||
@Override
|
||||
public List<CwProjectApprovalProcessVo> exportList(CwProjectApprovalProcessVo vo) {
|
||||
return queryList(vo);
|
||||
}
|
||||
}
|
||||
+258
@@ -0,0 +1,258 @@
|
||||
package org.dromara.cw.service.impl;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.dromara.cw.domain.bo.CwCustomApprovalBo;
|
||||
import org.dromara.cw.domain.bo.CwApprovalActionBo;
|
||||
import org.dromara.cw.domain.vo.CwProjectApprovalProcessVo;
|
||||
import org.dromara.cw.domain.vo.CwApprovalRecordVo;
|
||||
import org.dromara.cw.service.ICwProjectApprovalService;
|
||||
import org.dromara.cw.service.ICwProjectApprovalProcessService;
|
||||
import org.dromara.cw.service.ICwApprovalRecordService;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.dromara.cw.domain.CwApprovalRecord;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* 项目审批流程Service业务层处理
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class CwProjectApprovalServiceImpl implements ICwProjectApprovalService {
|
||||
|
||||
private final ICwProjectApprovalProcessService processService;
|
||||
private final ICwApprovalRecordService recordService;
|
||||
|
||||
/**
|
||||
* 启动自定义审批流程
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean startCustomApprovalProcess(CwCustomApprovalBo bo) {
|
||||
try {
|
||||
log.info("🚀 启动自定义审批流程: applicationId={}, auditorIds={}",
|
||||
bo.getApplicationId(), bo.getAuditorIds());
|
||||
|
||||
// 1. 验证参数
|
||||
if (bo.getApplicationId() == null) {
|
||||
throw new RuntimeException("申报ID不能为空");
|
||||
}
|
||||
if (bo.getAuditorIds() == null || bo.getAuditorIds().isEmpty()) {
|
||||
throw new RuntimeException("审批人列表不能为空");
|
||||
}
|
||||
|
||||
// 2. 调用审批记录服务创建自定义审批流程
|
||||
Boolean result = recordService.createCustomApprovalProcess(
|
||||
bo.getApplicationId(),
|
||||
bo.getApplicationNo(),
|
||||
bo.getAuditorIds(),
|
||||
bo.getSubmitterId(),
|
||||
bo.getSubmitterName()
|
||||
);
|
||||
|
||||
if (result) {
|
||||
log.info("✅ 自定义审批流程启动成功: applicationId={}", bo.getApplicationId());
|
||||
} else {
|
||||
log.error("❌ 自定义审批流程启动失败: applicationId={}", bo.getApplicationId());
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("❌ 启动自定义审批流程失败: applicationId={}, error={}",
|
||||
bo.getApplicationId(), e.getMessage(), e);
|
||||
throw new RuntimeException("启动审批流程失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行审批操作
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean executeApproval(CwApprovalActionBo bo) {
|
||||
try {
|
||||
log.info("执行审批操作: recordId={}, action={}, opinion={}",
|
||||
bo.getRecordId(), bo.getAction(), bo.getOpinion());
|
||||
|
||||
// 🔧 修复:先通过recordId获取审批记录信息
|
||||
CwApprovalRecordVo record = recordService.queryById(bo.getRecordId());
|
||||
if (record == null) {
|
||||
throw new RuntimeException("审批记录不存在:" + bo.getRecordId());
|
||||
}
|
||||
|
||||
// 🔧 修复:调用现有的审批记录服务执行审批
|
||||
Boolean result = recordService.processApproval(
|
||||
record.getApplicationId(),
|
||||
record.getNodeCode(),
|
||||
bo.getAction(),
|
||||
bo.getOpinion()
|
||||
);
|
||||
|
||||
log.info("✅ 审批操作执行完成:recordId={}, action={}, result={}",
|
||||
bo.getRecordId(), bo.getAction(), result);
|
||||
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
log.error("执行审批操作失败: recordId={}, action={}, error={}",
|
||||
bo.getRecordId(), bo.getAction(), e.getMessage(), e);
|
||||
throw new RuntimeException("审批操作失败:" + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取我的待审批列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<CwApprovalRecordVo> getMyPendingApprovals(PageQuery pageQuery) {
|
||||
try {
|
||||
Long userId = LoginHelper.getUserId();
|
||||
log.info("获取用户{}的待审批列表", userId);
|
||||
|
||||
// 🔧 修复:调用现有的审批记录服务查询方法
|
||||
List<CwApprovalRecordVo> list = recordService.queryPendingByApproverId(userId);
|
||||
|
||||
// 应用分页
|
||||
int total = list.size();
|
||||
int start = Math.max(0, (pageQuery.getPageNum() - 1) * pageQuery.getPageSize());
|
||||
int end = Math.min(start + pageQuery.getPageSize(), total);
|
||||
|
||||
List<CwApprovalRecordVo> pagedList = start < total ?
|
||||
list.subList(start, end) : new ArrayList<>();
|
||||
|
||||
log.info("✅ 查询待审批列表成功:总数={}, 当前页={}, 返回数量={}",
|
||||
total, pageQuery.getPageNum(), pagedList.size());
|
||||
|
||||
// 🔧 修复:使用正确的TableDataInfo构造方法
|
||||
TableDataInfo<CwApprovalRecordVo> result = new TableDataInfo<>(pagedList, total);
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
log.error("获取待审批列表失败: {}", e.getMessage(), e);
|
||||
return TableDataInfo.build(new ArrayList<>());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取我的已审批列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<CwApprovalRecordVo> getMyProcessedApprovals(PageQuery pageQuery) {
|
||||
try {
|
||||
Long userId = LoginHelper.getUserId();
|
||||
log.info("获取用户{}的已审批列表", userId);
|
||||
|
||||
// 🔧 修复:直接查询已审批记录,然后手动分页
|
||||
List<CwApprovalRecordVo> allList = recordService.queryApprovedByCurrentUser();
|
||||
|
||||
// 应用分页
|
||||
int total = allList.size();
|
||||
int start = Math.max(0, (pageQuery.getPageNum() - 1) * pageQuery.getPageSize());
|
||||
int end = Math.min(start + pageQuery.getPageSize(), total);
|
||||
|
||||
List<CwApprovalRecordVo> pagedList = start < total ?
|
||||
allList.subList(start, end) : new ArrayList<>();
|
||||
|
||||
log.info("✅ 查询已审批列表成功:总数={}, 当前页={}, 返回数量={}",
|
||||
total, pageQuery.getPageNum(), pagedList.size());
|
||||
|
||||
// 🔧 修复:使用正确的TableDataInfo构造方法
|
||||
TableDataInfo<CwApprovalRecordVo> result = new TableDataInfo<>(pagedList, total);
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
log.error("获取已审批列表失败: {}", e.getMessage(), e);
|
||||
return TableDataInfo.build(new ArrayList<>());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询审批流程列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<CwProjectApprovalProcessVo> queryProcessList(PageQuery pageQuery) {
|
||||
try {
|
||||
log.info("查询审批流程列表");
|
||||
|
||||
// 这里应该查询具体的流程数据
|
||||
// 由于缺少具体的业务逻辑,这里返回空列表
|
||||
// 实际项目中需要根据具体业务需求实现
|
||||
|
||||
List<CwProjectApprovalProcessVo> list = new ArrayList<>();
|
||||
return TableDataInfo.build(list);
|
||||
} catch (Exception e) {
|
||||
log.error("查询审批流程列表失败: {}", e.getMessage(), e);
|
||||
return TableDataInfo.build(new ArrayList<>());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取审批流程详情
|
||||
*/
|
||||
@Override
|
||||
public CwProjectApprovalProcessVo getProcessDetail(Long processId) {
|
||||
try {
|
||||
log.info("获取审批流程详情: {}", processId);
|
||||
|
||||
// 这里应该查询具体的流程详情
|
||||
// 由于缺少具体的业务逻辑,这里返回null
|
||||
// 实际项目中需要根据具体业务需求实现
|
||||
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
log.error("获取审批流程详情失败: {}", e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取审批记录列表
|
||||
*/
|
||||
@Override
|
||||
public List<CwApprovalRecordVo> getApprovalRecords(Long applicationId) {
|
||||
try {
|
||||
log.info("获取审批记录列表: {}", applicationId);
|
||||
|
||||
// 这里应该查询具体的审批记录
|
||||
// 由于缺少具体的业务逻辑,这里返回空列表
|
||||
// 实际项目中需要根据具体业务需求实现
|
||||
|
||||
return new ArrayList<>();
|
||||
} catch (Exception e) {
|
||||
log.error("获取审批记录列表失败: {}", e.getMessage(), e);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 终止审批流程
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean terminateProcess(List<Long> processIds) {
|
||||
try {
|
||||
log.info("终止审批流程: {}", processIds);
|
||||
|
||||
// 这里应该实现具体的流程终止逻辑
|
||||
// 由于缺少具体的业务逻辑,这里返回成功状态
|
||||
// 实际项目中需要根据具体业务需求实现
|
||||
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("终止审批流程失败: {}", e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
+344
@@ -0,0 +1,344 @@
|
||||
package org.dromara.cw.service.impl;
|
||||
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.dromara.cw.domain.bo.CwProjectAuditorBo;
|
||||
import org.dromara.cw.domain.vo.CwProjectAuditorVo;
|
||||
import org.dromara.cw.domain.CwProjectAuditor;
|
||||
import org.dromara.cw.domain.UserWithDeptInfo;
|
||||
import org.dromara.cw.mapper.CwProjectAuditorMapper;
|
||||
import org.dromara.cw.service.ICwProjectAuditorService;
|
||||
import org.dromara.system.service.ISysUserService;
|
||||
import org.dromara.system.domain.vo.SysUserVo;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.stream.Collectors;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.temporal.TemporalAdjusters;
|
||||
|
||||
/**
|
||||
* 项目审核人配置Service业务层处理
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class CwProjectAuditorServiceImpl implements ICwProjectAuditorService {
|
||||
|
||||
private final CwProjectAuditorMapper baseMapper;
|
||||
private final ISysUserService sysUserService;
|
||||
|
||||
/**
|
||||
* 查询项目审核人配置
|
||||
*/
|
||||
@Override
|
||||
public CwProjectAuditorVo queryById(Long id){
|
||||
return baseMapper.selectVoById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询项目审核人配置列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<CwProjectAuditorVo> queryPageList(CwProjectAuditorBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<CwProjectAuditor> lqw = buildQueryWrapper(bo);
|
||||
Page<CwProjectAuditorVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询项目审核人配置列表
|
||||
*/
|
||||
@Override
|
||||
public List<CwProjectAuditorVo> queryList(CwProjectAuditorBo bo) {
|
||||
LambdaQueryWrapper<CwProjectAuditor> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<CwProjectAuditor> buildQueryWrapper(CwProjectAuditorBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<CwProjectAuditor> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(bo.getUserId() != null, CwProjectAuditor::getUserId, bo.getUserId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getUserName()), CwProjectAuditor::getUserName, bo.getUserName());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getNickName()), CwProjectAuditor::getNickName, bo.getNickName());
|
||||
lqw.eq(bo.getDeptId() != null, CwProjectAuditor::getDeptId, bo.getDeptId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getDeptName()), CwProjectAuditor::getDeptName, bo.getDeptName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getPhoneNumber()), CwProjectAuditor::getPhoneNumber, bo.getPhoneNumber());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getEmail()), CwProjectAuditor::getEmail, bo.getEmail());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), CwProjectAuditor::getStatus, bo.getStatus());
|
||||
lqw.eq(bo.getConfigBy() != null, CwProjectAuditor::getConfigBy, bo.getConfigBy());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getConfigByName()), CwProjectAuditor::getConfigByName, bo.getConfigByName());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增项目审核人配置
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(CwProjectAuditorBo bo) {
|
||||
CwProjectAuditor add = MapstructUtils.convert(bo, CwProjectAuditor.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setId(add.getId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改项目审核人配置
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(CwProjectAuditorBo bo) {
|
||||
CwProjectAuditor update = MapstructUtils.convert(bo, CwProjectAuditor.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(CwProjectAuditor entity){
|
||||
// 检查用户是否已存在
|
||||
if (entity.getUserId() != null) {
|
||||
LambdaQueryWrapper<CwProjectAuditor> wrapper = Wrappers.lambdaQuery();
|
||||
wrapper.eq(CwProjectAuditor::getUserId, entity.getUserId());
|
||||
if (entity.getId() != null) {
|
||||
wrapper.ne(CwProjectAuditor::getId, entity.getId());
|
||||
}
|
||||
if (baseMapper.exists(wrapper)) {
|
||||
throw new RuntimeException("该用户已经是审核人,不能重复添加");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除项目审核人配置
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if(isValid){
|
||||
//TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量添加审核人
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public Boolean batchAddAuditors(List<Long> userIds, Long configBy, String configByName, String remark) {
|
||||
if (userIds == null || userIds.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 1. 获取完整的用户信息(包含部门信息)
|
||||
List<UserWithDeptInfo> users = baseMapper.selectUsersWithDeptInfo(userIds);
|
||||
if (users.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 过滤已存在的审核人
|
||||
List<Long> existingUserIds = baseMapper.selectList(Wrappers.<CwProjectAuditor>lambdaQuery()
|
||||
.in(CwProjectAuditor::getUserId, userIds))
|
||||
.stream().map(CwProjectAuditor::getUserId).collect(Collectors.toList());
|
||||
|
||||
// 3. 构建新增审核人列表
|
||||
List<CwProjectAuditor> auditors = new ArrayList<>();
|
||||
for (UserWithDeptInfo user : users) {
|
||||
if (!existingUserIds.contains(user.getUserId())) {
|
||||
CwProjectAuditor auditor = new CwProjectAuditor();
|
||||
auditor.setUserId(user.getUserId());
|
||||
auditor.setUserName(user.getUserName());
|
||||
auditor.setNickName(user.getNickName());
|
||||
auditor.setDeptId(user.getDeptId());
|
||||
auditor.setDeptName(user.getDeptName() != null ? user.getDeptName() : "");
|
||||
auditor.setPhoneNumber(user.getPhonenumber());
|
||||
auditor.setEmail(user.getEmail());
|
||||
auditor.setStatus("1"); // 默认正常状态
|
||||
auditor.setConfigBy(configBy);
|
||||
auditor.setConfigByName(configByName);
|
||||
auditor.setRemark(remark);
|
||||
auditors.add(auditor);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 批量保存
|
||||
if (!auditors.isEmpty()) {
|
||||
return baseMapper.insertBatch(auditors);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可用的审核人列表
|
||||
*/
|
||||
@Override
|
||||
public List<CwProjectAuditorVo> getAvailableAuditors() {
|
||||
LambdaQueryWrapper<CwProjectAuditor> wrapper = Wrappers.lambdaQuery();
|
||||
wrapper.eq(CwProjectAuditor::getStatus, "1"); // 只查询正常状态的审核人
|
||||
wrapper.orderByAsc(CwProjectAuditor::getDeptId, CwProjectAuditor::getUserName);
|
||||
return baseMapper.selectVoList(wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据部门ID获取用户列表
|
||||
*/
|
||||
@Override
|
||||
public List<Object> getDeptUsers(Long deptId) {
|
||||
try {
|
||||
// 参数验证
|
||||
if (deptId == null || deptId <= 0) {
|
||||
log.warn("无效的部门ID: {}", deptId);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 调用系统用户服务获取部门用户
|
||||
List<SysUserVo> users = sysUserService.selectUserListByDept(deptId);
|
||||
if (users == null || users.isEmpty()) {
|
||||
log.info("部门 {} 下没有找到用户", deptId);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return users.stream().map(user -> {
|
||||
Map<String, Object> userMap = Map.of(
|
||||
"userId", user.getUserId(),
|
||||
"userName", user.getUserName(),
|
||||
"nickName", user.getNickName() != null ? user.getNickName() : user.getUserName(),
|
||||
"deptId", user.getDeptId(),
|
||||
"deptName", user.getDeptName() != null ? user.getDeptName() : "",
|
||||
"phonenumber", user.getPhonenumber() != null ? user.getPhonenumber() : "",
|
||||
"email", user.getEmail() != null ? user.getEmail() : ""
|
||||
);
|
||||
return (Object) userMap;
|
||||
}).collect(Collectors.toList());
|
||||
} catch (Exception e) {
|
||||
log.error("获取部门 {} 的用户列表失败: {}", deptId, e.getMessage(), e);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新审核人状态
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateStatus(List<Long> ids, String status) {
|
||||
if (ids == null || ids.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LambdaQueryWrapper<CwProjectAuditor> wrapper = Wrappers.lambdaQuery();
|
||||
wrapper.in(CwProjectAuditor::getId, ids);
|
||||
|
||||
CwProjectAuditor update = new CwProjectAuditor();
|
||||
update.setStatus(status);
|
||||
update.setUpdateBy(LoginHelper.getUserId());
|
||||
|
||||
return baseMapper.update(update, wrapper) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getStatistics() {
|
||||
// 获取总审核人数
|
||||
long totalAuditors = baseMapper.selectCount(Wrappers.<CwProjectAuditor>lambdaQuery()
|
||||
.eq(CwProjectAuditor::getDeleted, 0));
|
||||
|
||||
// 获取正常状态审核人数
|
||||
long activeAuditors = baseMapper.selectCount(Wrappers.<CwProjectAuditor>lambdaQuery()
|
||||
.eq(CwProjectAuditor::getDeleted, 0)
|
||||
.eq(CwProjectAuditor::getStatus, "1"));
|
||||
|
||||
// 获取停用状态审核人数
|
||||
long inactiveAuditors = baseMapper.selectCount(Wrappers.<CwProjectAuditor>lambdaQuery()
|
||||
.eq(CwProjectAuditor::getDeleted, 0)
|
||||
.eq(CwProjectAuditor::getStatus, "0"));
|
||||
|
||||
// 获取部门数量(去重)
|
||||
List<CwProjectAuditor> auditors = baseMapper.selectList(Wrappers.<CwProjectAuditor>lambdaQuery()
|
||||
.eq(CwProjectAuditor::getDeleted, 0)
|
||||
.select(CwProjectAuditor::getDeptId));
|
||||
long totalDepts = auditors.stream().map(CwProjectAuditor::getDeptId).distinct().count();
|
||||
|
||||
// 获取今日新增
|
||||
LocalDateTime startOfDay = LocalDateTime.now().with(LocalTime.MIN);
|
||||
LocalDateTime endOfDay = LocalDateTime.now().with(LocalTime.MAX);
|
||||
long todayAdded = baseMapper.selectCount(Wrappers.<CwProjectAuditor>lambdaQuery()
|
||||
.eq(CwProjectAuditor::getDeleted, 0)
|
||||
.ge(CwProjectAuditor::getCreateTime, startOfDay)
|
||||
.le(CwProjectAuditor::getCreateTime, endOfDay));
|
||||
|
||||
// 获取本月新增
|
||||
LocalDateTime startOfMonth = LocalDateTime.now().with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
|
||||
LocalDateTime endOfMonth = LocalDateTime.now().with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX);
|
||||
long monthlyAdded = baseMapper.selectCount(Wrappers.<CwProjectAuditor>lambdaQuery()
|
||||
.eq(CwProjectAuditor::getDeleted, 0)
|
||||
.ge(CwProjectAuditor::getCreateTime, startOfMonth)
|
||||
.le(CwProjectAuditor::getCreateTime, endOfMonth));
|
||||
|
||||
// 获取我配置的审核人数
|
||||
long myConfigured = baseMapper.selectCount(Wrappers.<CwProjectAuditor>lambdaQuery()
|
||||
.eq(CwProjectAuditor::getDeleted, 0)
|
||||
.eq(CwProjectAuditor::getConfigBy, LoginHelper.getUserId()));
|
||||
|
||||
// 获取最近活跃数(近7天有更新的)
|
||||
LocalDateTime sevenDaysAgo = LocalDateTime.now().minusDays(7);
|
||||
long recentActive = baseMapper.selectCount(Wrappers.<CwProjectAuditor>lambdaQuery()
|
||||
.eq(CwProjectAuditor::getDeleted, 0)
|
||||
.ge(CwProjectAuditor::getUpdateTime, sevenDaysAgo));
|
||||
|
||||
// 构建统计结果
|
||||
Map<String, Object> statistics = new HashMap<>();
|
||||
statistics.put("totalAuditors", totalAuditors);
|
||||
statistics.put("activeAuditors", activeAuditors);
|
||||
statistics.put("inactiveAuditors", inactiveAuditors);
|
||||
statistics.put("totalDepts", totalDepts);
|
||||
statistics.put("todayAdded", todayAdded);
|
||||
statistics.put("monthlyAdded", monthlyAdded);
|
||||
statistics.put("myConfigured", myConfigured);
|
||||
statistics.put("recentActive", recentActive);
|
||||
|
||||
return statistics;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID查询项目审核人配置
|
||||
*/
|
||||
@Override
|
||||
public CwProjectAuditorVo queryByUserId(Long userId) {
|
||||
if (userId == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
LambdaQueryWrapper<CwProjectAuditor> wrapper = Wrappers.<CwProjectAuditor>lambdaQuery()
|
||||
.eq(CwProjectAuditor::getUserId, userId)
|
||||
.eq(CwProjectAuditor::getDeleted, 0)
|
||||
.orderByDesc(CwProjectAuditor::getCreateTime)
|
||||
.last("LIMIT 1");
|
||||
|
||||
CwProjectAuditor entity = baseMapper.selectOne(wrapper);
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return MapstructUtils.convert(entity, CwProjectAuditorVo.class);
|
||||
}
|
||||
}
|
||||
+24
-1
@@ -72,6 +72,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="approvalStatus" column="approval_status" />
|
||||
<result property="submitTime" column="submit_time" />
|
||||
<result property="approvalTime" column="approval_time" />
|
||||
<!-- 流程相关字段 -->
|
||||
<result property="totalNodes" column="total_nodes" />
|
||||
<result property="currentNode" column="current_node" />
|
||||
<result property="processName" column="process_name" />
|
||||
<result property="processStatus" column="process_status" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectCwApprovalRecordVo">
|
||||
@@ -90,7 +95,25 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
ar.approver_name as current_approver_name,
|
||||
ar.node_status as approval_status,
|
||||
pa.create_time as submit_time,
|
||||
ar.end_time as approval_time
|
||||
ar.end_time as approval_time,
|
||||
-- 流程相关字段(通过审批记录计算)
|
||||
(SELECT COUNT(DISTINCT ar2.node_order)
|
||||
FROM cw_approval_record ar2
|
||||
WHERE ar2.application_id = ar.application_id
|
||||
AND ar2.deleted = 0) as total_nodes,
|
||||
ar.node_order as current_node,
|
||||
'项目审批' as process_name,
|
||||
(CASE
|
||||
WHEN EXISTS(SELECT 1 FROM cw_approval_record ar3
|
||||
WHERE ar3.application_id = ar.application_id
|
||||
AND ar3.node_status = 'rejected'
|
||||
AND ar3.deleted = 0) THEN 'rejected'
|
||||
WHEN NOT EXISTS(SELECT 1 FROM cw_approval_record ar4
|
||||
WHERE ar4.application_id = ar.application_id
|
||||
AND ar4.node_status IN ('waiting', 'processing')
|
||||
AND ar4.deleted = 0) THEN 'completed'
|
||||
ELSE 'processing'
|
||||
END) as process_status
|
||||
from cw_approval_record ar
|
||||
left join cw_project_application pa on ar.application_id = pa.id
|
||||
left join sys_user u on pa.create_by = u.user_id
|
||||
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.cw.mapper.CwProjectApprovalProcessMapper">
|
||||
|
||||
<resultMap type="org.dromara.cw.domain.vo.CwProjectApprovalProcessVo" id="CwProjectApprovalProcessResult">
|
||||
<result property="id" column="id" />
|
||||
<result property="applicationId" column="application_id" />
|
||||
<result property="applicationNo" column="application_no" />
|
||||
<result property="processName" column="process_name" />
|
||||
<result property="processStatus" column="process_status" />
|
||||
<result property="totalNodes" column="total_nodes" />
|
||||
<result property="currentNode" column="current_node" />
|
||||
<result property="startTime" column="start_time" />
|
||||
<result property="endTime" column="end_time" />
|
||||
<result property="submitterId" column="submitter_id" />
|
||||
<result property="submitterName" column="submitter_name" />
|
||||
<result property="createBy" column="create_by" />
|
||||
<result property="createTime" column="create_time" />
|
||||
<result property="updateBy" column="update_by" />
|
||||
<result property="updateTime" column="update_time" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectCwProjectApprovalProcessVo">
|
||||
select
|
||||
p.id, p.application_id, p.application_no, p.process_name, p.process_status,
|
||||
p.total_nodes, p.current_node, p.start_time, p.end_time,
|
||||
p.submitter_id, p.submitter_name,
|
||||
p.create_by, p.create_time, p.update_by, p.update_time,
|
||||
a.project_name,
|
||||
u.nick_name as submitter_nick_name
|
||||
from cw_project_approval_process p
|
||||
left join cw_project_application a on p.application_id = a.id
|
||||
left join sys_user u on p.submitter_id = u.user_id
|
||||
</sql>
|
||||
|
||||
<select id="selectProcessList" parameterType="org.dromara.cw.domain.CwProjectApprovalProcess" resultMap="CwProjectApprovalProcessResult">
|
||||
<include refid="selectCwProjectApprovalProcessVo"/>
|
||||
<where>
|
||||
p.deleted = 0
|
||||
<if test="applicationId != null"> and p.application_id = #{applicationId}</if>
|
||||
<if test="applicationNo != null and applicationNo != ''"> and p.application_no like concat('%', #{applicationNo}, '%')</if>
|
||||
<if test="processName != null and processName != ''"> and p.process_name like concat('%', #{processName}, '%')</if>
|
||||
<if test="processStatus != null and processStatus != ''"> and p.process_status = #{processStatus}</if>
|
||||
<if test="submitterId != null"> and p.submitter_id = #{submitterId}</if>
|
||||
<if test="submitterName != null and submitterName != ''"> and p.submitter_name like concat('%', #{submitterName}, '%')</if>
|
||||
<if test="params.beginCreateTime != null and params.beginCreateTime != ''"> and p.create_time >= #{params.beginCreateTime}</if>
|
||||
<if test="params.endCreateTime != null and params.endCreateTime != ''"> and p.create_time <= #{params.endCreateTime}</if>
|
||||
<if test="params.beginStartTime != null and params.beginStartTime != ''"> and p.start_time >= #{params.beginStartTime}</if>
|
||||
<if test="params.endStartTime != null and params.endStartTime != ''"> and p.start_time <= #{params.endStartTime}</if>
|
||||
</where>
|
||||
order by p.create_time desc
|
||||
</select>
|
||||
|
||||
<select id="selectByApplicationId" resultMap="CwProjectApprovalProcessResult">
|
||||
<include refid="selectCwProjectApprovalProcessVo"/>
|
||||
where p.application_id = #{applicationId} and p.deleted = 0
|
||||
</select>
|
||||
|
||||
<select id="selectByApplicationNo" resultMap="CwProjectApprovalProcessResult">
|
||||
<include refid="selectCwProjectApprovalProcessVo"/>
|
||||
where p.application_no = #{applicationNo} and p.deleted = 0
|
||||
</select>
|
||||
|
||||
<select id="selectMyProcesses" resultMap="CwProjectApprovalProcessResult">
|
||||
<include refid="selectCwProjectApprovalProcessVo"/>
|
||||
where p.submitter_id = #{submitterId} and p.deleted = 0
|
||||
order by p.create_time desc
|
||||
</select>
|
||||
|
||||
<select id="selectRunningProcesses" resultMap="CwProjectApprovalProcessResult">
|
||||
<include refid="selectCwProjectApprovalProcessVo"/>
|
||||
where p.process_status = 'running' and p.deleted = 0
|
||||
order by p.start_time
|
||||
</select>
|
||||
|
||||
<select id="selectOvertimeProcesses" resultMap="CwProjectApprovalProcessResult">
|
||||
<include refid="selectCwProjectApprovalProcessVo"/>
|
||||
where p.process_status = 'running'
|
||||
and p.start_time < date_sub(now(), interval #{hours} hour)
|
||||
and p.deleted = 0
|
||||
order by p.start_time
|
||||
</select>
|
||||
|
||||
<select id="selectProcessStatistics" resultType="map">
|
||||
select
|
||||
p.process_status as status,
|
||||
count(*) as count
|
||||
from cw_project_approval_process p
|
||||
where p.deleted = 0
|
||||
<if test="submitterId != null"> and p.submitter_id = #{submitterId}</if>
|
||||
group by p.process_status
|
||||
order by count desc
|
||||
</select>
|
||||
|
||||
<update id="updateCurrentNode">
|
||||
update cw_project_approval_process
|
||||
set current_node = #{currentNode}, update_by = #{updateBy}, update_time = now()
|
||||
where id = #{id} and deleted = 0
|
||||
</update>
|
||||
|
||||
<update id="updateProcessStatus">
|
||||
update cw_project_approval_process
|
||||
set process_status = #{status},
|
||||
end_time = case when #{status} in ('completed', 'terminated') then now() else end_time end,
|
||||
update_by = #{updateBy},
|
||||
update_time = now()
|
||||
where id = #{id} and deleted = 0
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,135 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.cw.mapper.CwProjectAuditorMapper">
|
||||
|
||||
<resultMap type="org.dromara.cw.domain.vo.CwProjectAuditorVo" id="CwProjectAuditorResult">
|
||||
<result property="id" column="id" />
|
||||
<result property="userId" column="user_id" />
|
||||
<result property="userName" column="user_name" />
|
||||
<result property="nickName" column="nick_name" />
|
||||
<result property="deptId" column="dept_id" />
|
||||
<result property="deptName" column="dept_name" />
|
||||
<result property="phoneNumber" column="phone_number" />
|
||||
<result property="email" column="email" />
|
||||
<result property="status" column="status" />
|
||||
<result property="remark" column="remark" />
|
||||
<result property="configBy" column="config_by" />
|
||||
<result property="configByName" column="config_by_name" />
|
||||
<result property="createBy" column="create_by" />
|
||||
<result property="createTime" column="create_time" />
|
||||
<result property="updateBy" column="update_by" />
|
||||
<result property="updateTime" column="update_time" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectCwProjectAuditorVo">
|
||||
select
|
||||
a.id, a.user_id, a.user_name, a.nick_name, a.dept_id, a.dept_name,
|
||||
a.phone_number, a.email, a.status, a.remark, a.config_by, a.config_by_name,
|
||||
a.create_by, a.create_time, a.update_by, a.update_time,
|
||||
u.user_name as sys_user_name,
|
||||
d.dept_name as sys_dept_name
|
||||
from cw_project_auditor a
|
||||
left join sys_user u on a.user_id = u.user_id
|
||||
left join sys_dept d on a.dept_id = d.dept_id
|
||||
</sql>
|
||||
|
||||
<select id="selectAuditorList" parameterType="org.dromara.cw.domain.CwProjectAuditor" resultMap="CwProjectAuditorResult">
|
||||
<include refid="selectCwProjectAuditorVo"/>
|
||||
<where>
|
||||
a.deleted = 0
|
||||
<if test="userId != null"> and a.user_id = #{userId}</if>
|
||||
<if test="userName != null and userName != ''"> and a.user_name like concat('%', #{userName}, '%')</if>
|
||||
<if test="nickName != null and nickName != ''"> and a.nick_name like concat('%', #{nickName}, '%')</if>
|
||||
<if test="deptId != null"> and a.dept_id = #{deptId}</if>
|
||||
<if test="deptName != null and deptName != ''"> and a.dept_name like concat('%', #{deptName}, '%')</if>
|
||||
<if test="status != null and status != ''"> and a.status = #{status}</if>
|
||||
<if test="configBy != null"> and a.config_by = #{configBy}</if>
|
||||
<if test="configByName != null and configByName != ''"> and a.config_by_name like concat('%', #{configByName}, '%')</if>
|
||||
<if test="params.beginCreateTime != null and params.beginCreateTime != ''"> and a.create_time >= #{params.beginCreateTime}</if>
|
||||
<if test="params.endCreateTime != null and params.endCreateTime != ''"> and a.create_time <= #{params.endCreateTime}</if>
|
||||
</where>
|
||||
order by a.create_time desc
|
||||
</select>
|
||||
|
||||
<select id="selectAuditorsByDeptId" resultMap="CwProjectAuditorResult">
|
||||
<include refid="selectCwProjectAuditorVo"/>
|
||||
where a.dept_id = #{deptId} and a.status = '1' and a.deleted = 0
|
||||
order by a.create_time desc
|
||||
</select>
|
||||
|
||||
<select id="selectAvailableAuditors" resultMap="CwProjectAuditorResult">
|
||||
<include refid="selectCwProjectAuditorVo"/>
|
||||
where a.status = '1' and a.deleted = 0
|
||||
order by a.dept_id, a.create_time desc
|
||||
</select>
|
||||
|
||||
<select id="selectMyConfigAuditors" resultMap="CwProjectAuditorResult">
|
||||
<include refid="selectCwProjectAuditorVo"/>
|
||||
where a.config_by = #{configBy} and a.deleted = 0
|
||||
order by a.create_time desc
|
||||
</select>
|
||||
|
||||
<select id="selectAuditorsByUserIds" resultMap="CwProjectAuditorResult">
|
||||
<include refid="selectCwProjectAuditorVo"/>
|
||||
where a.user_id in
|
||||
<foreach item="userId" collection="userIds" open="(" separator="," close=")">
|
||||
#{userId}
|
||||
</foreach>
|
||||
and a.status = '1' and a.deleted = 0
|
||||
order by a.create_time desc
|
||||
</select>
|
||||
|
||||
<select id="selectAuditorStatistics" resultType="map">
|
||||
select
|
||||
d.dept_name,
|
||||
count(*) as total_count,
|
||||
count(case when a.status = '1' then 1 end) as active_count,
|
||||
count(case when a.status = '0' then 1 end) as inactive_count
|
||||
from cw_project_auditor a
|
||||
left join sys_dept d on a.dept_id = d.dept_id
|
||||
where a.deleted = 0
|
||||
<if test="deptId != null"> and a.dept_id = #{deptId}</if>
|
||||
<if test="status != null and status != ''"> and a.status = #{status}</if>
|
||||
group by a.dept_id, d.dept_name
|
||||
order by total_count desc
|
||||
</select>
|
||||
|
||||
<select id="selectByUserId" resultMap="CwProjectAuditorResult">
|
||||
<include refid="selectCwProjectAuditorVo"/>
|
||||
where a.user_id = #{userId} and a.deleted = 0
|
||||
</select>
|
||||
|
||||
<update id="batchUpdateStatus">
|
||||
update cw_project_auditor
|
||||
set status = #{status}, update_by = #{updateBy}, update_time = now()
|
||||
where id in
|
||||
<foreach item="id" collection="ids" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
and deleted = 0
|
||||
</update>
|
||||
|
||||
<!-- 查询完整的用户信息(包含部门信息)用于批量添加 -->
|
||||
<select id="selectUsersWithDeptInfo" resultType="org.dromara.cw.domain.UserWithDeptInfo">
|
||||
select
|
||||
u.user_id as userId,
|
||||
u.user_name as userName,
|
||||
u.nick_name as nickName,
|
||||
u.dept_id as deptId,
|
||||
d.dept_name as deptName,
|
||||
u.phonenumber as phonenumber,
|
||||
u.email as email,
|
||||
u.status as status
|
||||
from sys_user u
|
||||
left join sys_dept d on u.dept_id = d.dept_id
|
||||
where u.status = '0'
|
||||
and u.user_id in
|
||||
<foreach item="userId" collection="userIds" open="(" separator="," close=")">
|
||||
#{userId}
|
||||
</foreach>
|
||||
order by u.dept_id, u.user_name
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
+1
-1
@@ -297,7 +297,7 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
|
||||
@Override
|
||||
public List<SysUserVo> selectUserByIds(List<Long> userIds, Long deptId) {
|
||||
return baseMapper.selectUserList(new LambdaQueryWrapper<SysUser>()
|
||||
.select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName)
|
||||
.select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName, SysUser::getPhonenumber)
|
||||
.eq(SysUser::getStatus, SystemConstants.NORMAL)
|
||||
.eq(ObjectUtil.isNotNull(deptId), SysUser::getDeptId, deptId)
|
||||
.in(CollUtil.isNotEmpty(userIds), SysUser::getUserId, userIds));
|
||||
|
||||
@@ -104,6 +104,13 @@
|
||||
<artifactId>ruoyi-workflow</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 学生考核模块 -->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-xskh</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
+2
-2
@@ -157,7 +157,7 @@ public class XgDormBedStudentController extends BaseController {
|
||||
|
||||
/**
|
||||
* 获取当前用户二级学院的宿舍楼树形结构
|
||||
* 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择
|
||||
* 校区-宿舍楼二级结构,校区不可选,只有宿舍楼可以选择
|
||||
*/
|
||||
@SaCheckPermission("dormBedStudent:dormBedStudent:list")
|
||||
@GetMapping("/currentUserCollegeDormTree")
|
||||
@@ -168,7 +168,7 @@ public class XgDormBedStudentController extends BaseController {
|
||||
|
||||
/**
|
||||
* 获取班主任管理的班级宿舍楼树形结构
|
||||
* 只显示班主任管理班级分配到的宿舍楼
|
||||
* 校区-宿舍楼二级结构,只显示班主任管理班级分配到的宿舍楼
|
||||
*/
|
||||
@SaCheckPermission("dormBedStudent:dormBedStudent:list")
|
||||
@GetMapping("/getClassTeacherDormTree")
|
||||
|
||||
+23
-1
@@ -18,6 +18,7 @@ import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.xg.domain.vo.XgDormBuildingVo;
|
||||
import org.dromara.xg.domain.vo.XgDormBuildingSimplifiedVo;
|
||||
import org.dromara.xg.domain.bo.XgDormBuildingBo;
|
||||
import org.dromara.xg.domain.vo.BuildingTreeSelectVo;
|
||||
import org.dromara.xg.service.IXgDormBuildingService;
|
||||
@@ -104,7 +105,7 @@ public class XgDormBuildingController extends BaseController {
|
||||
|
||||
/**
|
||||
* 获取宿舍楼树形结构数据
|
||||
* 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择
|
||||
* 校区-宿舍楼二级结构,校区不可选,只有宿舍楼可以选择
|
||||
*/
|
||||
@SaCheckPermission("sslxx:dormBuilding:list")
|
||||
@GetMapping("/buildingTree")
|
||||
@@ -112,4 +113,25 @@ public class XgDormBuildingController extends BaseController {
|
||||
List<BuildingTreeSelectVo> treeData = xgDormBuildingService.getBuildingTreeData();
|
||||
return R.ok(treeData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询宿舍楼信息简化列表
|
||||
* 用于简化界面显示,隐藏宿舍区层级,直接显示校区→宿舍楼结构
|
||||
*/
|
||||
@SaCheckPermission("sslxx:dormBuilding:list")
|
||||
@GetMapping("/simplifiedList")
|
||||
public TableDataInfo<XgDormBuildingSimplifiedVo> getSimplifiedList(XgDormBuildingBo bo, PageQuery pageQuery) {
|
||||
return xgDormBuildingService.querySimplifiedPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询宿舍楼信息简化列表(不分页)
|
||||
* 用于下拉选择等场景
|
||||
*/
|
||||
@SaCheckPermission("sslxx:dormBuilding:list")
|
||||
@GetMapping("/simplifiedListAll")
|
||||
public R<List<XgDormBuildingSimplifiedVo>> getSimplifiedListAll(XgDormBuildingBo bo) {
|
||||
List<XgDormBuildingSimplifiedVo> list = xgDormBuildingService.querySimplifiedList(bo);
|
||||
return R.ok(list);
|
||||
}
|
||||
}
|
||||
+52
-5
@@ -9,6 +9,7 @@ import org.springframework.validation.annotation.Validated;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.xg.domain.vo.DormBuildingTreeVo;
|
||||
import org.dromara.xg.domain.vo.DormBuildingTreeSimplifiedVo;
|
||||
import org.dromara.xg.domain.bo.DormBuildingTreeBo;
|
||||
import org.dromara.xg.service.IXgDormBuildingTreeService;
|
||||
|
||||
@@ -28,24 +29,70 @@ public class XgDormBuildingTreeController extends BaseController {
|
||||
|
||||
/**
|
||||
* 获取宿舍楼树形结构数据
|
||||
* 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择
|
||||
* 校区-宿舍楼二级结构,校区不可选,只有宿舍楼可以选择
|
||||
*/
|
||||
@SaCheckPermission("xgss:dormBuildingTree:list")
|
||||
@GetMapping("/list")
|
||||
public R<List<DormBuildingTreeVo>> getDormBuildingTree(DormBuildingTreeBo bo) {
|
||||
List<DormBuildingTreeVo> treeData = xgDormBuildingTreeService.getDormBuildingTree(bo);
|
||||
public R<List<DormBuildingTreeSimplifiedVo>> getDormBuildingTree(DormBuildingTreeBo bo) {
|
||||
List<DormBuildingTreeSimplifiedVo> treeData = xgDormBuildingTreeService.getSimplifiedDormBuildingTree(bo);
|
||||
return R.ok(treeData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有宿舍楼树形结构数据(不考虑权限)
|
||||
* 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择
|
||||
* 校区-宿舍楼二级结构,校区不可选,只有宿舍楼可以选择
|
||||
*/
|
||||
@SaCheckPermission("xgss:dormBuildingTree:list")
|
||||
@GetMapping("/listAll")
|
||||
public R<List<DormBuildingTreeVo>> getAllDormBuildingTree(DormBuildingTreeBo bo) {
|
||||
public R<List<DormBuildingTreeSimplifiedVo>> getAllDormBuildingTree(DormBuildingTreeBo bo) {
|
||||
List<DormBuildingTreeSimplifiedVo> treeData = xgDormBuildingTreeService.getAllSimplifiedDormBuildingTree(bo);
|
||||
return R.ok(treeData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取宿舍楼树形结构完整数据(包含宿舍区层级)
|
||||
* 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择
|
||||
* 注意:此接口仅用于特殊需求,一般情况请使用/list接口
|
||||
*/
|
||||
@SaCheckPermission("xgss:dormBuildingTree:list")
|
||||
@GetMapping("/fullList")
|
||||
public R<List<DormBuildingTreeVo>> getFullDormBuildingTree(DormBuildingTreeBo bo) {
|
||||
List<DormBuildingTreeVo> treeData = xgDormBuildingTreeService.getDormBuildingTree(bo);
|
||||
return R.ok(treeData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有宿舍楼树形结构完整数据(不考虑权限,包含宿舍区层级)
|
||||
* 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择
|
||||
* 注意:此接口仅用于特殊需求,一般情况请使用/listAll接口
|
||||
*/
|
||||
@SaCheckPermission("xgss:dormBuildingTree:list")
|
||||
@GetMapping("/fullListAll")
|
||||
public R<List<DormBuildingTreeVo>> getAllFullDormBuildingTree(DormBuildingTreeBo bo) {
|
||||
List<DormBuildingTreeVo> treeData = xgDormBuildingTreeService.getAllDormBuildingTree(bo);
|
||||
return R.ok(treeData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取宿舍楼树形结构简化数据
|
||||
* 校区-宿舍楼二级结构,隐藏宿舍区层级,校区不可选,只有宿舍楼可以选择
|
||||
*/
|
||||
@SaCheckPermission("xgss:dormBuildingTree:list")
|
||||
@GetMapping("/simplifiedList")
|
||||
public R<List<DormBuildingTreeSimplifiedVo>> getSimplifiedDormBuildingTree(DormBuildingTreeBo bo) {
|
||||
List<DormBuildingTreeSimplifiedVo> treeData = xgDormBuildingTreeService.getSimplifiedDormBuildingTree(bo);
|
||||
return R.ok(treeData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有宿舍楼树形结构简化数据(不考虑权限)
|
||||
* 校区-宿舍楼二级结构,隐藏宿舍区层级,校区不可选,只有宿舍楼可以选择
|
||||
*/
|
||||
@SaCheckPermission("xgss:dormBuildingTree:list")
|
||||
@GetMapping("/simplifiedListAll")
|
||||
public R<List<DormBuildingTreeSimplifiedVo>> getAllSimplifiedDormBuildingTree(DormBuildingTreeBo bo) {
|
||||
List<DormBuildingTreeSimplifiedVo> treeData = xgDormBuildingTreeService.getAllSimplifiedDormBuildingTree(bo);
|
||||
return R.ok(treeData);
|
||||
}
|
||||
|
||||
}
|
||||
+43
@@ -23,6 +23,7 @@ import org.dromara.xg.domain.bo.XgDormHygieneCheckBo;
|
||||
import org.dromara.xg.domain.bo.XgDormHygieneCheckCompleteBo;
|
||||
import org.dromara.xg.service.IXgDormHygieneCheckService;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.xg.domain.vo.XgHygieneCheckViolationVo;
|
||||
|
||||
/**
|
||||
* 宿舍卫生检查
|
||||
@@ -164,4 +165,46 @@ public class XgDormHygieneCheckController extends BaseController {
|
||||
return xgDormHygieneCheckService.queryPageListByStudentId(studentId, bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存完整的宿舍卫生检查数据(包含学生评分和违纪记录)
|
||||
*/
|
||||
@SaCheckPermission("dormHygieneCheck:dormHygieneCheck:add")
|
||||
@Log(title = "宿舍卫生检查", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/saveCompleteData")
|
||||
public R<Long> saveCompleteData(@Validated(AddGroup.class) @RequestBody XgDormHygieneCheckCompleteBo bo) {
|
||||
Long hygieneCheckId = xgDormHygieneCheckService.saveCompleteData(bo);
|
||||
if (hygieneCheckId != null) {
|
||||
return R.ok(hygieneCheckId);
|
||||
} else {
|
||||
return R.fail("保存宿舍卫生检查数据失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新完整的宿舍卫生检查数据(包含学生评分和违纪记录)
|
||||
*/
|
||||
@SaCheckPermission("dormHygieneCheck:dormHygieneCheck:edit")
|
||||
@Log(title = "宿舍卫生检查", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/updateCompleteData")
|
||||
public R<Void> updateCompleteData(@Validated(EditGroup.class) @RequestBody XgDormHygieneCheckCompleteBo bo) {
|
||||
return toAjax(xgDormHygieneCheckService.updateCompleteData(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据卫生检查ID查询相关的违纪记录
|
||||
*
|
||||
* @param hygieneCheckId 卫生检查ID
|
||||
* @return 违纪记录列表
|
||||
*/
|
||||
@SaCheckPermission("dormHygieneCheck:dormHygieneCheck:query")
|
||||
@GetMapping("/getViolations/{hygieneCheckId}")
|
||||
public R<List<XgHygieneCheckViolationVo>> getViolations(
|
||||
@NotNull(message = "卫生检查ID不能为空") @PathVariable Long hygieneCheckId) {
|
||||
List<XgHygieneCheckViolationVo> violations = xgDormHygieneCheckService
|
||||
.getViolationsByHygieneCheckId(hygieneCheckId);
|
||||
return R.ok(violations);
|
||||
}
|
||||
|
||||
}
|
||||
+29
@@ -1,6 +1,7 @@
|
||||
package org.dromara.xg.controller;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
@@ -21,6 +22,7 @@ import org.dromara.xg.domain.vo.XgDormRoomVo;
|
||||
import org.dromara.xg.domain.bo.XgDormRoomBo;
|
||||
import org.dromara.xg.service.IXgDormRoomService;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 宿舍房间信息
|
||||
@@ -77,6 +79,33 @@ public class XgDormRoomController extends BaseController {
|
||||
ExcelUtil.exportExcel(list, "宿舍房间信息", XgDormRoomVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出住宿清单(宿舍卡片式布局)
|
||||
*/
|
||||
@SaCheckPermission("xgss:dormRoom:export")
|
||||
@Log(title = "住宿清单", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/exportAccommodationList")
|
||||
public void exportAccommodationList(
|
||||
@RequestParam(required = false) Long buildingId,
|
||||
@RequestParam(required = false) String buildingName,
|
||||
@RequestParam(required = false) String buildingType,
|
||||
@RequestParam(required = false) String accommodationData,
|
||||
HttpServletResponse response) {
|
||||
|
||||
// 构建参数Map
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
if (buildingId != null)
|
||||
params.put("buildingId", buildingId);
|
||||
if (buildingName != null)
|
||||
params.put("buildingName", buildingName);
|
||||
if (buildingType != null)
|
||||
params.put("buildingType", buildingType);
|
||||
if (accommodationData != null)
|
||||
params.put("accommodationData", accommodationData);
|
||||
|
||||
xgDormRoomService.exportAccommodationList(params, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取宿舍房间信息详细信息
|
||||
*
|
||||
|
||||
+11
@@ -111,4 +111,15 @@ public class XgHolidayStayController extends BaseController {
|
||||
public TableDataInfo<StudentOptionVo> getStudentOptions(StudentOptionBo bo, PageQuery pageQuery) {
|
||||
return xgHolidayStayService.getStudentOptions(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询单人留宿有效数据
|
||||
* 获取所有有效的假期留宿数据,筛选出在同一时间段内该宿舍只有一个学生留宿的记录
|
||||
*/
|
||||
@SaCheckPermission("holidayStay:holidayStay:list")
|
||||
@GetMapping("/singlePersonValidStay")
|
||||
public R<List<XgHolidayStayVo>> getSinglePersonValidStay() {
|
||||
List<XgHolidayStayVo> result = xgHolidayStayService.querySinglePersonValidStay();
|
||||
return R.ok(result);
|
||||
}
|
||||
}
|
||||
+28
@@ -1,6 +1,8 @@
|
||||
package org.dromara.xg.controller;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
@@ -101,4 +103,30 @@ public class XgStudentLeaveController extends BaseController {
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
|
||||
return toAjax(xgStudentLeaveService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据学生ID列表和检查日期查询学生请假信息
|
||||
*
|
||||
* @param studentIds 学生ID列表(逗号分隔)
|
||||
* @param checkDate 检查日期
|
||||
*/
|
||||
@SaCheckPermission("studentLeave:studentLeave:query")
|
||||
@GetMapping("/queryByCheckDate")
|
||||
public R<Map<Long, XgStudentLeaveVo>> queryByCheckDate(
|
||||
@RequestParam String studentIds,
|
||||
@RequestParam String checkDate) {
|
||||
try {
|
||||
List<Long> studentIdList = List.of(studentIds.split(","))
|
||||
.stream()
|
||||
.map(String::trim)
|
||||
.map(Long::valueOf)
|
||||
.toList();
|
||||
LocalDateTime checkDateTime = LocalDateTime.parse(checkDate.replace(" ", "T"));
|
||||
Map<Long, XgStudentLeaveVo> result = xgStudentLeaveService.queryStudentLeavesByCheckDate(studentIdList,
|
||||
checkDateTime);
|
||||
return R.ok(result);
|
||||
} catch (Exception e) {
|
||||
return R.fail("参数格式错误:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
package org.dromara.xg.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import jakarta.validation.constraints.*;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.xg.domain.bo.XgStudentStatisticsBo;
|
||||
import org.dromara.xg.domain.vo.XgStudentStatisticsVo;
|
||||
import org.dromara.xg.domain.vo.XgCascadeOptionVo;
|
||||
import org.dromara.xg.service.IXgStudentStatisticsService;
|
||||
|
||||
/**
|
||||
* 学生宿舍卫生检查、违纪记录统计
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-14
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/xg/studentStatistics")
|
||||
public class XgStudentStatisticsController extends BaseController {
|
||||
|
||||
private final IXgStudentStatisticsService studentStatisticsService;
|
||||
|
||||
/**
|
||||
* 查询学生宿舍卫生检查、违纪记录统计数据
|
||||
*/
|
||||
@SaCheckPermission("xg:studentStatistics:query")
|
||||
@PostMapping("/statistics")
|
||||
public R<XgStudentStatisticsVo> getStatistics(@Validated @RequestBody XgStudentStatisticsBo bo) {
|
||||
return R.ok(studentStatisticsService.getStatistics(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出学生宿舍卫生检查、违纪记录统计数据
|
||||
*/
|
||||
@SaCheckPermission("xg:studentStatistics:export")
|
||||
@Log(title = "学生统计数据", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void exportStatistics(@Validated @RequestBody XgStudentStatisticsBo bo,
|
||||
jakarta.servlet.http.HttpServletResponse response) {
|
||||
studentStatisticsService.exportStatistics(bo, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取二级学院列表
|
||||
*/
|
||||
@SaCheckPermission("xg:studentStatistics:query")
|
||||
@GetMapping("/colleges")
|
||||
public R<List<XgCascadeOptionVo>> getColleges() {
|
||||
return R.ok(studentStatisticsService.getColleges());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据学院ID获取专业列表
|
||||
*/
|
||||
@SaCheckPermission("xg:studentStatistics:query")
|
||||
@GetMapping("/majors/{collegeId}")
|
||||
public R<List<XgCascadeOptionVo>> getMajorsByCollegeId(
|
||||
@NotNull(message = "学院ID不能为空") @PathVariable Long collegeId) {
|
||||
return R.ok(studentStatisticsService.getMajorsByCollegeId(collegeId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据专业ID获取班级列表
|
||||
*/
|
||||
@SaCheckPermission("xg:studentStatistics:query")
|
||||
@GetMapping("/classes/{majorId}")
|
||||
public R<List<XgCascadeOptionVo>> getClassesByMajorId(
|
||||
@NotNull(message = "专业ID不能为空") @PathVariable Long majorId) {
|
||||
return R.ok(studentStatisticsService.getClassesByMajorId(majorId));
|
||||
}
|
||||
|
||||
}
|
||||
+11
-1
@@ -111,7 +111,7 @@ public class XgDormHygieneCheck extends TenantEntity {
|
||||
private String campusName;
|
||||
|
||||
/**
|
||||
* 宿舍总分(0-100分)
|
||||
* 宿舍扣分(0-100分)
|
||||
*/
|
||||
private Double totalScore;
|
||||
|
||||
@@ -140,4 +140,14 @@ public class XgDormHygieneCheck extends TenantEntity {
|
||||
*/
|
||||
private String checkRemarks;
|
||||
|
||||
/**
|
||||
* 违纪类型ID,关联xskh_discipline_type.id
|
||||
*/
|
||||
private Long disciplineTypeId;
|
||||
|
||||
/**
|
||||
* 违纪类型名称
|
||||
*/
|
||||
private String disciplineTypeName;
|
||||
|
||||
}
|
||||
+1
-1
@@ -94,7 +94,7 @@ public class XgDormHygieneStudentScore extends TenantEntity {
|
||||
private String bedCode;
|
||||
|
||||
/**
|
||||
* 学生个人得分(0-100分)
|
||||
* 学生个人扣分(0-100分)
|
||||
*/
|
||||
private Double studentScore;
|
||||
|
||||
|
||||
@@ -67,6 +67,11 @@ public class XgDormRoom extends TenantEntity {
|
||||
*/
|
||||
private String roomStatus;
|
||||
|
||||
/**
|
||||
* 排序号
|
||||
*/
|
||||
private Long sort;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
package org.dromara.xg.domain;
|
||||
|
||||
import org.dromara.common.tenant.core.TenantEntity;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* 宿舍卫生检查违纪关联对象 xg_hygiene_check_violation
|
||||
*
|
||||
* @author 吴自龙
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("xg_hygiene_check_violation")
|
||||
public class XgHygieneCheckViolation extends TenantEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 宿舍卫生检查ID,关联xg_dorm_hygiene_check.id
|
||||
*/
|
||||
private Long hygieneCheckId;
|
||||
|
||||
/**
|
||||
* 违纪记录ID,关联xskh_discipline_record.id
|
||||
*/
|
||||
private Long disciplineRecordId;
|
||||
|
||||
/**
|
||||
* 学生ID,关联xg_student_msg.id
|
||||
*/
|
||||
private Long studentId;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
private String studentName;
|
||||
|
||||
/**
|
||||
* 违纪类型ID,关联xskh_discipline_type.id
|
||||
*/
|
||||
private Long disciplineTypeId;
|
||||
|
||||
/**
|
||||
* 违纪类型名称
|
||||
*/
|
||||
private String disciplineTypeName;
|
||||
|
||||
/**
|
||||
* 违纪来源(1宿舍卫生检查 2其他)
|
||||
*/
|
||||
private String violationSource;
|
||||
|
||||
/**
|
||||
* 状态(1生效 2已撤销)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
@TableLogic(value = "0", delval = "1")
|
||||
private Long deleted;
|
||||
|
||||
}
|
||||
+2
-1
@@ -41,7 +41,8 @@ public class XgDormBuildingBo extends BaseEntity {
|
||||
/**
|
||||
* 所属宿舍区ID
|
||||
*/
|
||||
@NotNull(message = "所属宿舍区ID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
// @NotNull(message = "所属宿舍区ID不能为空", groups = { AddGroup.class, EditGroup.class
|
||||
// }) // 宿舍区轻量化改造:移除必填验证
|
||||
private Long areaId;
|
||||
|
||||
/**
|
||||
|
||||
+9
@@ -147,5 +147,14 @@ public class XgDormHygieneCheckBo extends BaseEntity {
|
||||
*/
|
||||
private String checkRemarks;
|
||||
|
||||
/**
|
||||
* 违纪类型ID,关联xskh_discipline_type.id
|
||||
*/
|
||||
private Long disciplineTypeId;
|
||||
|
||||
/**
|
||||
* 违纪类型名称
|
||||
*/
|
||||
private String disciplineTypeName;
|
||||
|
||||
}
|
||||
+17
-1
@@ -149,6 +149,16 @@ public class XgDormHygieneCheckCompleteBo {
|
||||
*/
|
||||
private String checkRemarks;
|
||||
|
||||
/**
|
||||
* 违纪类型ID,关联xskh_discipline_type.id
|
||||
*/
|
||||
private Long disciplineTypeId;
|
||||
|
||||
/**
|
||||
* 违纪类型名称
|
||||
*/
|
||||
private String disciplineTypeName;
|
||||
|
||||
/**
|
||||
* 学生评分数据列表
|
||||
*/
|
||||
@@ -156,6 +166,12 @@ public class XgDormHygieneCheckCompleteBo {
|
||||
@NotEmpty(message = "学生评分数据不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private List<XgDormHygieneStudentScoreBo> studentScores;
|
||||
|
||||
/**
|
||||
* 违纪记录数据列表
|
||||
*/
|
||||
@Valid
|
||||
private List<XgViolationDataBo> violationData;
|
||||
|
||||
// 基础字段(用于VO类映射)
|
||||
private Long createBy;
|
||||
|
||||
@@ -166,4 +182,4 @@ public class XgDormHygieneCheckCompleteBo {
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
}
|
||||
}
|
||||
+5
-1
@@ -70,6 +70,11 @@ public class XgDormRoomBo extends BaseEntity {
|
||||
*/
|
||||
private String roomStatus;
|
||||
|
||||
/**
|
||||
* 排序号
|
||||
*/
|
||||
private Long sort;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
@@ -80,5 +85,4 @@ public class XgDormRoomBo extends BaseEntity {
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
package org.dromara.xg.domain.bo;
|
||||
|
||||
import org.dromara.xg.domain.XgHygieneCheckViolation;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import jakarta.validation.constraints.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
/**
|
||||
* 宿舍卫生检查违纪关联业务对象 xg_hygiene_check_violation
|
||||
*
|
||||
* @author 吴自龙
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = XgHygieneCheckViolation.class, reverseConvertGenerate = false)
|
||||
public class XgHygieneCheckViolationBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 宿舍卫生检查ID,关联xg_dorm_hygiene_check.id
|
||||
*/
|
||||
private Long hygieneCheckId;
|
||||
|
||||
/**
|
||||
* 违纪记录ID,关联xskh_discipline_record.id
|
||||
*/
|
||||
private Long disciplineRecordId;
|
||||
|
||||
/**
|
||||
* 学生ID,关联xg_student_msg.id
|
||||
*/
|
||||
@NotNull(message = "学生ID不能为空")
|
||||
private Long studentId;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
@NotBlank(message = "学号不能为空")
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
@NotBlank(message = "学生姓名不能为空")
|
||||
private String studentName;
|
||||
|
||||
/**
|
||||
* 违纪类型ID,关联xskh_discipline_type.id
|
||||
*/
|
||||
@NotNull(message = "违纪类型ID不能为空")
|
||||
private Long disciplineTypeId;
|
||||
|
||||
/**
|
||||
* 违纪类型名称
|
||||
*/
|
||||
@NotBlank(message = "违纪类型名称不能为空")
|
||||
private String disciplineTypeName;
|
||||
|
||||
/**
|
||||
* 违纪来源(1宿舍卫生检查 2其他)
|
||||
*/
|
||||
private String violationSource;
|
||||
|
||||
/**
|
||||
* 状态(1生效 2已撤销)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 分页大小
|
||||
*/
|
||||
@JsonIgnore
|
||||
private Integer pageSize;
|
||||
|
||||
/**
|
||||
* 当前页数
|
||||
*/
|
||||
@JsonIgnore
|
||||
private Integer pageNum;
|
||||
|
||||
/**
|
||||
* 排序列
|
||||
*/
|
||||
@JsonIgnore
|
||||
private String orderByColumn;
|
||||
|
||||
/**
|
||||
* 排序的方向desc或者asc
|
||||
*/
|
||||
@JsonIgnore
|
||||
private String isAsc;
|
||||
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package org.dromara.xg.domain.bo;
|
||||
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import jakarta.validation.constraints.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 学生宿舍卫生检查、违纪记录统计查询业务对象
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-14
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class XgStudentStatisticsBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 统计开始时间
|
||||
*/
|
||||
@NotNull(message = "统计开始时间不能为空")
|
||||
private LocalDateTime startTime;
|
||||
|
||||
/**
|
||||
* 统计结束时间
|
||||
*/
|
||||
@NotNull(message = "统计结束时间不能为空")
|
||||
private LocalDateTime endTime;
|
||||
|
||||
/**
|
||||
* 二级学院ID
|
||||
*/
|
||||
private Long collegeId;
|
||||
|
||||
/**
|
||||
* 专业ID
|
||||
*/
|
||||
private Long majorId;
|
||||
|
||||
/**
|
||||
* 班级ID
|
||||
*/
|
||||
private Long classId;
|
||||
|
||||
}
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
package org.dromara.xg.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 违纪数据业务对象(用于前端传输)
|
||||
*
|
||||
* @author 吴自龙
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
public class XgViolationDataBo {
|
||||
|
||||
/**
|
||||
* 违纪记录ID(用于更新操作,新增时为null)
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 违纪记录ID,关联xskh_discipline_record.id(用于更新违纪记录)
|
||||
*/
|
||||
private Long disciplineRecordId;
|
||||
|
||||
/**
|
||||
* 学生ID,关联xg_student_msg.id
|
||||
*/
|
||||
@NotNull(message = "学生ID不能为空")
|
||||
private Long studentId;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
@NotBlank(message = "学号不能为空")
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
@NotBlank(message = "学生姓名不能为空")
|
||||
private String studentName;
|
||||
|
||||
/**
|
||||
* 班级ID
|
||||
*/
|
||||
private Long classId;
|
||||
|
||||
/**
|
||||
* 班级名称
|
||||
*/
|
||||
private String className;
|
||||
|
||||
/**
|
||||
* 专业ID
|
||||
*/
|
||||
private Long majorId;
|
||||
|
||||
/**
|
||||
* 专业名称
|
||||
*/
|
||||
private String majorName;
|
||||
|
||||
/**
|
||||
* 学院ID
|
||||
*/
|
||||
private Long collegeId;
|
||||
|
||||
/**
|
||||
* 学院名称
|
||||
*/
|
||||
private String collegeName;
|
||||
|
||||
/**
|
||||
* 违纪类型ID,关联xskh_discipline_type.id
|
||||
*/
|
||||
@NotNull(message = "违纪类型ID不能为空")
|
||||
private Long disciplineTypeId;
|
||||
|
||||
/**
|
||||
* 违纪类型名称
|
||||
*/
|
||||
@NotBlank(message = "违纪类型名称不能为空")
|
||||
private String disciplineTypeName;
|
||||
|
||||
/**
|
||||
* 违纪日期
|
||||
*/
|
||||
private String disciplineDate;
|
||||
|
||||
/**
|
||||
* 违纪原因
|
||||
*/
|
||||
@NotBlank(message = "违纪原因不能为空")
|
||||
private String disciplineReason;
|
||||
|
||||
/**
|
||||
* 违纪内容
|
||||
*/
|
||||
private String disciplineContent;
|
||||
|
||||
/**
|
||||
* 扣分分值
|
||||
*/
|
||||
private BigDecimal scoreDeduction;
|
||||
|
||||
/**
|
||||
* 违纪来源(1宿舍卫生检查 2其他)
|
||||
*/
|
||||
private String violationSource;
|
||||
|
||||
/**
|
||||
* 状态(1生效 2已撤销)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 附件OSS ID列表,逗号分隔
|
||||
*/
|
||||
private String attachmentOssIds;
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
package org.dromara.xg.domain.vo;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 宿舍楼树形结构简化VO
|
||||
* 用于简化界面显示,只显示校区→宿舍楼的二级结构,隐藏宿舍区层级
|
||||
*
|
||||
* @author wuzilong
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
public class DormBuildingTreeSimplifiedVo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 节点ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 节点名称
|
||||
*/
|
||||
private String label;
|
||||
|
||||
/**
|
||||
* 节点类型 (campus:校区, building:宿舍楼)
|
||||
* 注意:简化版本中移除了 area:宿舍区 类型
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 是否禁用节点(校区节点禁用点击,宿舍楼节点可点击)
|
||||
*/
|
||||
private Boolean disabled;
|
||||
|
||||
/**
|
||||
* 宿舍楼层数(仅宿舍楼节点有此字段)
|
||||
*/
|
||||
private Integer buildingFloors;
|
||||
|
||||
/**
|
||||
* 宿舍楼类型(1男生楼 2女生楼 3混合楼)(仅宿舍楼节点有此字段)
|
||||
*/
|
||||
private String buildingType;
|
||||
|
||||
/**
|
||||
* 子节点
|
||||
*/
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
private List<DormBuildingTreeSimplifiedVo> children;
|
||||
|
||||
/**
|
||||
* 从完整树形VO转换为简化树形VO
|
||||
* 将三级结构(校区→宿舍区→宿舍楼)转换为二级结构(校区→宿舍楼)
|
||||
*/
|
||||
public static DormBuildingTreeSimplifiedVo fromFullTreeVo(DormBuildingTreeVo fullTreeVo) {
|
||||
if (fullTreeVo == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
DormBuildingTreeSimplifiedVo simplified = new DormBuildingTreeSimplifiedVo();
|
||||
simplified.setId(fullTreeVo.getId());
|
||||
simplified.setLabel(fullTreeVo.getLabel());
|
||||
simplified.setBuildingFloors(fullTreeVo.getBuildingFloors());
|
||||
simplified.setBuildingType(fullTreeVo.getBuildingType());
|
||||
|
||||
// 根据节点类型进行转换
|
||||
if ("campus".equals(fullTreeVo.getType())) {
|
||||
// 校区节点:保持不变
|
||||
simplified.setType("campus");
|
||||
simplified.setDisabled(true);
|
||||
// 处理子节点:跳过宿舍区层级,直接提取宿舍楼
|
||||
simplified.setChildren(flattenAreaChildren(fullTreeVo.getChildren()));
|
||||
} else if ("building".equals(fullTreeVo.getType())) {
|
||||
// 宿舍楼节点:保持不变
|
||||
simplified.setType("building");
|
||||
simplified.setDisabled(false);
|
||||
}
|
||||
|
||||
return simplified;
|
||||
}
|
||||
|
||||
/**
|
||||
* 扁平化宿舍区子节点,将宿舍区下的宿舍楼直接提升为校区的子节点
|
||||
*/
|
||||
private static List<DormBuildingTreeSimplifiedVo> flattenAreaChildren(List<DormBuildingTreeVo> areaNodes) {
|
||||
if (areaNodes == null || areaNodes.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return areaNodes.stream()
|
||||
.filter(node -> "area".equals(node.getType())) // 找到宿舍区节点
|
||||
.flatMap(areaNode -> areaNode.getChildren() != null ? areaNode.getChildren().stream()
|
||||
: java.util.stream.Stream.empty()) // 提取宿舍楼
|
||||
.filter(buildingNode -> "building".equals(buildingNode.getType())) // 确保是宿舍楼节点
|
||||
.map(DormBuildingTreeSimplifiedVo::fromFullTreeVo) // 转换为简化VO
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package org.dromara.xg.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 级联选择器选项视图对象
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-14
|
||||
*/
|
||||
@Data
|
||||
public class XgCascadeOptionVo {
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 显示名称
|
||||
*/
|
||||
private String label;
|
||||
|
||||
/**
|
||||
* 值
|
||||
*/
|
||||
private String value;
|
||||
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
private Integer sort;
|
||||
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
package org.dromara.xg.domain.vo;
|
||||
|
||||
import org.dromara.xg.domain.XgDormBuilding;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
|
||||
import org.dromara.common.excel.convert.ExcelDictConvert;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 宿舍楼信息简化视图对象 xg_dorm_building
|
||||
* 用于简化界面显示,隐藏宿舍区层级,直接显示校区→宿舍楼结构
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = XgDormBuilding.class)
|
||||
public class XgDormBuildingSimplifiedVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@ExcelProperty(value = "主键ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 宿舍楼编码
|
||||
*/
|
||||
@ExcelProperty(value = "宿舍楼编码")
|
||||
private String buildingCode;
|
||||
|
||||
/**
|
||||
* 宿舍楼名称
|
||||
*/
|
||||
@ExcelProperty(value = "宿舍楼名称")
|
||||
private String buildingName;
|
||||
|
||||
/**
|
||||
* 所属校区ID
|
||||
*/
|
||||
@ExcelProperty(value = "所属校区ID")
|
||||
private Long campusId;
|
||||
|
||||
/**
|
||||
* 校区名称
|
||||
*/
|
||||
@ExcelProperty(value = "校区名称")
|
||||
private String campusName;
|
||||
|
||||
/**
|
||||
* 宿舍楼类型(1男生楼 2女生楼 3混合楼)
|
||||
*/
|
||||
@ExcelProperty(value = "宿舍楼类型(1男生楼 2女生楼 3混合楼)", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "dorm_type")
|
||||
private String buildingType;
|
||||
|
||||
/**
|
||||
* 宿舍楼描述
|
||||
*/
|
||||
@ExcelProperty(value = "宿舍楼描述")
|
||||
private String buildingDescription;
|
||||
|
||||
/**
|
||||
* 排序号
|
||||
*/
|
||||
@ExcelProperty(value = "排序号")
|
||||
private Long sortOrder;
|
||||
|
||||
/**
|
||||
* 总楼层数
|
||||
*/
|
||||
@ExcelProperty(value = "总楼层数")
|
||||
private Integer floors;
|
||||
|
||||
// 基础字段
|
||||
private Long createBy; // 创建者
|
||||
private Date createTime; // 创建时间
|
||||
private Long updateBy; // 更新者
|
||||
private Date updateTime; // 更新时间
|
||||
|
||||
/**
|
||||
* 从完整VO转换为简化VO
|
||||
*/
|
||||
public static XgDormBuildingSimplifiedVo fromFullVo(XgDormBuildingVo fullVo) {
|
||||
if (fullVo == null) {
|
||||
return null;
|
||||
}
|
||||
XgDormBuildingSimplifiedVo simplified = new XgDormBuildingSimplifiedVo();
|
||||
BeanUtils.copyProperties(fullVo, simplified);
|
||||
return simplified;
|
||||
}
|
||||
}
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
package org.dromara.xg.domain.vo;
|
||||
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import org.dromara.xg.domain.XgDormHygieneCheck;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
|
||||
import org.dromara.common.excel.convert.ExcelDictConvert;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 宿舍卫生检查简化视图对象 xg_dorm_hygiene_check
|
||||
* 用于简化界面显示,隐藏宿舍区层级,直接显示校区→宿舍楼→房间结构
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = XgDormHygieneCheck.class)
|
||||
public class XgDormHygieneCheckSimplifiedVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@ExcelProperty(value = "主键ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
@ExcelProperty(value = "删除标志", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "0=代表存在,1=代表删除")
|
||||
private Long deleted;
|
||||
|
||||
/**
|
||||
* 检查标题
|
||||
*/
|
||||
@ExcelProperty(value = "检查标题")
|
||||
private String checkTitle;
|
||||
|
||||
/**
|
||||
* 检查日期
|
||||
*/
|
||||
@ExcelProperty(value = "检查日期")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date checkDate;
|
||||
|
||||
/**
|
||||
* 检查员ID,关联sys_user.id
|
||||
*/
|
||||
@ExcelProperty(value = "检查员ID,关联sys_user.id")
|
||||
private Long checkerId;
|
||||
|
||||
/**
|
||||
* 检查员姓名
|
||||
*/
|
||||
@ExcelProperty(value = "检查员姓名")
|
||||
private String checkerName;
|
||||
|
||||
/**
|
||||
* 检查类型(1日常检查 2专项检查 3突击检查 4复查)
|
||||
*/
|
||||
@ExcelProperty(value = "检查类型", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "xg_dorm_hygiene_check_type")
|
||||
private String checkType;
|
||||
|
||||
/**
|
||||
* 检查级别(1宿管员 2学院 3学校)
|
||||
*/
|
||||
@ExcelProperty(value = "检查级别", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "xg_dorm_hygiene_check_level")
|
||||
private String checkLevel;
|
||||
|
||||
/**
|
||||
* 宿舍房间ID,关联xg_dorm_room.id
|
||||
*/
|
||||
@ExcelProperty(value = "宿舍房间ID,关联xg_dorm_room.id")
|
||||
private Long roomId;
|
||||
|
||||
/**
|
||||
* 房间编号
|
||||
*/
|
||||
@ExcelProperty(value = "房间编号")
|
||||
private String roomCode;
|
||||
|
||||
/**
|
||||
* 房间名称
|
||||
*/
|
||||
@ExcelProperty(value = "房间名称")
|
||||
private String roomName;
|
||||
|
||||
/**
|
||||
* 宿舍楼ID,关联xg_dorm_building.id
|
||||
*/
|
||||
@ExcelProperty(value = "宿舍楼ID,关联xg_dorm_building.id")
|
||||
private Long buildingId;
|
||||
|
||||
/**
|
||||
* 宿舍楼名称
|
||||
*/
|
||||
@ExcelProperty(value = "宿舍楼名称")
|
||||
private String buildingName;
|
||||
|
||||
/**
|
||||
* 校区ID,关联xg_dorm_campus.id
|
||||
*/
|
||||
@ExcelProperty(value = "校区ID,关联xg_dorm_campus.id")
|
||||
private Long campusId;
|
||||
|
||||
/**
|
||||
* 校区名称
|
||||
*/
|
||||
@ExcelProperty(value = "校区名称")
|
||||
private String campusName;
|
||||
|
||||
/**
|
||||
* 宿舍总分(0-100分)
|
||||
*/
|
||||
@ExcelProperty(value = "宿舍总分", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "0=-100分")
|
||||
private Double totalScore;
|
||||
|
||||
/**
|
||||
* 卫生等级(A优秀 B良好 C合格 D不合格)
|
||||
*/
|
||||
@ExcelProperty(value = "卫生等级", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "xg_dorm_hygiene_grade")
|
||||
private String hygieneGrade;
|
||||
|
||||
/**
|
||||
* 附件OSS ID列表,逗号分隔
|
||||
*/
|
||||
@ExcelProperty(value = "附件OSS ID列表,逗号分隔")
|
||||
private String attachmentIds;
|
||||
|
||||
/**
|
||||
* 检查总结
|
||||
*/
|
||||
@ExcelProperty(value = "检查总结")
|
||||
private String checkSummary;
|
||||
|
||||
/**
|
||||
* 整改建议
|
||||
*/
|
||||
@ExcelProperty(value = "整改建议")
|
||||
private String improvementSuggestions;
|
||||
|
||||
/**
|
||||
* 检查备注
|
||||
*/
|
||||
@ExcelProperty(value = "检查备注")
|
||||
private String checkRemarks;
|
||||
|
||||
// 基础字段
|
||||
private Long createBy; // 创建者
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime; // 创建时间
|
||||
private Long updateBy; // 更新者
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime; // 更新时间
|
||||
|
||||
/**
|
||||
* 从完整VO转换为简化VO
|
||||
*/
|
||||
public static XgDormHygieneCheckSimplifiedVo fromFullVo(XgDormHygieneCheckVo fullVo) {
|
||||
if (fullVo == null) {
|
||||
return null;
|
||||
}
|
||||
XgDormHygieneCheckSimplifiedVo simplified = new XgDormHygieneCheckSimplifiedVo();
|
||||
BeanUtils.copyProperties(fullVo, simplified);
|
||||
return simplified;
|
||||
}
|
||||
}
|
||||
+11
-2
@@ -14,8 +14,6 @@ import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 宿舍卫生检查视图对象 xg_dorm_hygiene_check
|
||||
*
|
||||
@@ -173,5 +171,16 @@ public class XgDormHygieneCheckVo implements Serializable {
|
||||
@ExcelProperty(value = "检查备注")
|
||||
private String checkRemarks;
|
||||
|
||||
/**
|
||||
* 违纪类型ID,关联xskh_discipline_type.id
|
||||
*/
|
||||
@ExcelProperty(value = "违纪类型ID")
|
||||
private Long disciplineTypeId;
|
||||
|
||||
/**
|
||||
* 违纪类型名称
|
||||
*/
|
||||
@ExcelProperty(value = "违纪类型名称")
|
||||
private String disciplineTypeName;
|
||||
|
||||
}
|
||||
+28
-2
@@ -11,8 +11,7 @@ import lombok.Data;
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
/**
|
||||
* 宿舍房间信息视图对象 xg_dorm_room
|
||||
@@ -82,6 +81,12 @@ public class XgDormRoomVo implements Serializable {
|
||||
@ExcelProperty(value = "房间状态(0可用 1维修中 2停用)")
|
||||
private String roomStatus;
|
||||
|
||||
/**
|
||||
* 排序号
|
||||
*/
|
||||
@ExcelProperty(value = "排序号")
|
||||
private Long sort;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
@@ -94,5 +99,26 @@ public class XgDormRoomVo implements Serializable {
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
|
||||
}
|
||||
+1
-12
@@ -14,8 +14,6 @@ import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 假期留宿管理视图对象 xg_holiday_stay
|
||||
*
|
||||
@@ -39,8 +37,6 @@ public class XgHolidayStayVo implements Serializable {
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
@ExcelProperty(value = "删除标志", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "0=代表存在,1=代表删除")
|
||||
private Long deleted;
|
||||
|
||||
/**
|
||||
@@ -179,8 +175,7 @@ public class XgHolidayStayVo implements Serializable {
|
||||
/**
|
||||
* 留宿原因(必填)
|
||||
*/
|
||||
@ExcelProperty(value = "留宿原因", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "必=填")
|
||||
@ExcelProperty(value = "留宿原因")
|
||||
private String stayReason;
|
||||
|
||||
/**
|
||||
@@ -218,26 +213,21 @@ public class XgHolidayStayVo implements Serializable {
|
||||
/**
|
||||
* 附件OSS文件ID,多个用逗号分隔(申请材料、证明文件等)
|
||||
*/
|
||||
@ExcelProperty(value = "附件OSS文件ID,多个用逗号分隔", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "申=请材料、证明文件等")
|
||||
private String attachmentOssIds;
|
||||
|
||||
/**
|
||||
* 扩展字段1
|
||||
*/
|
||||
@ExcelProperty(value = "扩展字段1")
|
||||
private String extField1;
|
||||
|
||||
/**
|
||||
* 扩展字段2
|
||||
*/
|
||||
@ExcelProperty(value = "扩展字段2")
|
||||
private String extField2;
|
||||
|
||||
/**
|
||||
* 扩展字段3
|
||||
*/
|
||||
@ExcelProperty(value = "扩展字段3")
|
||||
private String extField3;
|
||||
|
||||
/**
|
||||
@@ -246,5 +236,4 @@ public class XgHolidayStayVo implements Serializable {
|
||||
@ExcelProperty(value = "备注信息")
|
||||
private String remark;
|
||||
|
||||
|
||||
}
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
package org.dromara.xg.domain.vo;
|
||||
|
||||
import org.dromara.xg.domain.XgHygieneCheckViolation;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.time.LocalDate;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 宿舍卫生检查违纪关联视图对象 xg_hygiene_check_violation
|
||||
*
|
||||
* @author 吴自龙
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
@AutoMapper(target = XgHygieneCheckViolation.class)
|
||||
public class XgHygieneCheckViolationVo {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 宿舍卫生检查ID
|
||||
*/
|
||||
private Long hygieneCheckId;
|
||||
|
||||
/**
|
||||
* 违纪记录ID
|
||||
*/
|
||||
private Long disciplineRecordId;
|
||||
|
||||
/**
|
||||
* 学生ID
|
||||
*/
|
||||
private Long studentId;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
private String studentName;
|
||||
|
||||
/**
|
||||
* 违纪类型ID
|
||||
*/
|
||||
private Long disciplineTypeId;
|
||||
|
||||
/**
|
||||
* 违纪类型名称
|
||||
*/
|
||||
private String disciplineTypeName;
|
||||
|
||||
/**
|
||||
* 违纪来源
|
||||
*/
|
||||
private String violationSource;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
private String status;
|
||||
|
||||
// ============ 新增违纪详情字段 ============
|
||||
|
||||
/**
|
||||
* 违纪处分日期
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private LocalDate disciplineDate;
|
||||
|
||||
/**
|
||||
* 违纪处分原因
|
||||
*/
|
||||
private String disciplineReason;
|
||||
|
||||
/**
|
||||
* 违纪处分内容
|
||||
*/
|
||||
private String disciplineContent;
|
||||
|
||||
/**
|
||||
* 扣分分值
|
||||
*/
|
||||
private BigDecimal scoreDeduction;
|
||||
|
||||
/**
|
||||
* 附件OSS ID列表,逗号分隔
|
||||
*/
|
||||
private String attachmentOssIds;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
|
||||
}
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
package org.dromara.xg.domain.vo;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 学生宿舍卫生检查、违纪记录统计视图对象
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-14
|
||||
*/
|
||||
@Data
|
||||
public class XgStudentStatisticsVo {
|
||||
|
||||
/**
|
||||
* 统计维度 (college-学院, major-专业, class-班级, classDetail-班级详情)
|
||||
*/
|
||||
private String dimension;
|
||||
|
||||
/**
|
||||
* 统计图表数据
|
||||
*/
|
||||
private List<StatisticsChartData> chartData;
|
||||
|
||||
/**
|
||||
* 明细数据
|
||||
*/
|
||||
private List<StatisticsDetailData> detailData;
|
||||
|
||||
/**
|
||||
* 图表数据内部类
|
||||
*/
|
||||
@Data
|
||||
public static class StatisticsChartData {
|
||||
/**
|
||||
* 名称 (学院名、专业名、班级名)
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 宿舍扣分总数
|
||||
*/
|
||||
private Integer dormDeductionCount;
|
||||
|
||||
/**
|
||||
* 宿舍违纪记录总数
|
||||
*/
|
||||
private Integer dormViolationCount;
|
||||
|
||||
/**
|
||||
* 宿舍违纪记录扣分总数
|
||||
*/
|
||||
private Double dormViolationDeduction;
|
||||
|
||||
/**
|
||||
* 教学区违纪记录总数
|
||||
*/
|
||||
private Integer teachingViolationCount;
|
||||
|
||||
/**
|
||||
* 教学区违纪记录扣分总数
|
||||
*/
|
||||
private Double teachingViolationDeduction;
|
||||
}
|
||||
|
||||
/**
|
||||
* 明细数据内部类
|
||||
*/
|
||||
@Data
|
||||
public static class StatisticsDetailData {
|
||||
/**
|
||||
* ID (不导出到Excel)
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
@ExcelProperty(value = "名称")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 上级名称(如学院下的专业名称显示学院名)
|
||||
*/
|
||||
@ExcelProperty(value = "上级")
|
||||
private String parentName;
|
||||
|
||||
/**
|
||||
* 宿舍扣分总数
|
||||
*/
|
||||
@ExcelProperty(value = "宿舍扣分总数")
|
||||
private Integer dormDeductionCount;
|
||||
|
||||
/**
|
||||
* 宿舍违纪记录总数
|
||||
*/
|
||||
@ExcelProperty(value = "宿舍违纪记录总数")
|
||||
private Integer dormViolationCount;
|
||||
|
||||
/**
|
||||
* 宿舍违纪记录扣分总数
|
||||
*/
|
||||
@ExcelProperty(value = "宿舍违纪记录扣分总数")
|
||||
private Double dormViolationDeduction;
|
||||
|
||||
/**
|
||||
* 教学区违纪记录总数
|
||||
*/
|
||||
@ExcelProperty(value = "教学区违纪记录总数")
|
||||
private Integer teachingViolationCount;
|
||||
|
||||
/**
|
||||
* 教学区违纪记录扣分总数
|
||||
*/
|
||||
@ExcelProperty(value = "教学区违纪记录扣分总数")
|
||||
private Double teachingViolationDeduction;
|
||||
|
||||
/**
|
||||
* 合计扣分
|
||||
*/
|
||||
@ExcelProperty(value = "违纪合计扣分")
|
||||
private Double totalDeduction;
|
||||
}
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package org.dromara.xg.mapper;
|
||||
|
||||
import org.dromara.xg.domain.XgHygieneCheckViolation;
|
||||
import org.dromara.xg.domain.vo.XgHygieneCheckViolationVo;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 宿舍卫生检查违纪记录Mapper接口
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-29
|
||||
*/
|
||||
public interface XgHygieneCheckViolationMapper
|
||||
extends BaseMapperPlus<XgHygieneCheckViolation, XgHygieneCheckViolationVo> {
|
||||
|
||||
/**
|
||||
* 根据卫生检查ID查询违纪记录(包含详情)
|
||||
*
|
||||
* @param hygieneCheckId 卫生检查ID
|
||||
* @return 违纪记录列表(包含详情)
|
||||
*/
|
||||
List<XgHygieneCheckViolationVo> selectViolationsByHygieneCheckId(@Param("hygieneCheckId") Long hygieneCheckId);
|
||||
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package org.dromara.xg.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.dromara.xg.domain.bo.XgStudentStatisticsBo;
|
||||
import org.dromara.xg.domain.vo.XgStudentStatisticsVo;
|
||||
import org.dromara.xg.domain.vo.XgCascadeOptionVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 学生宿舍卫生检查、违纪记录统计Mapper接口
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-14
|
||||
*/
|
||||
public interface XgStudentStatisticsMapper {
|
||||
|
||||
/**
|
||||
* 按学院维度统计图表数据
|
||||
*/
|
||||
List<XgStudentStatisticsVo.StatisticsChartData> getCollegeStatistics(@Param("bo") XgStudentStatisticsBo bo);
|
||||
|
||||
/**
|
||||
* 按学院维度统计明细数据
|
||||
*/
|
||||
List<XgStudentStatisticsVo.StatisticsDetailData> getCollegeDetailStatistics(@Param("bo") XgStudentStatisticsBo bo);
|
||||
|
||||
/**
|
||||
* 按专业维度统计图表数据
|
||||
*/
|
||||
List<XgStudentStatisticsVo.StatisticsChartData> getMajorStatistics(@Param("bo") XgStudentStatisticsBo bo);
|
||||
|
||||
/**
|
||||
* 按专业维度统计明细数据
|
||||
*/
|
||||
List<XgStudentStatisticsVo.StatisticsDetailData> getMajorDetailStatistics(@Param("bo") XgStudentStatisticsBo bo);
|
||||
|
||||
/**
|
||||
* 按班级维度统计图表数据
|
||||
*/
|
||||
List<XgStudentStatisticsVo.StatisticsChartData> getClassStatistics(@Param("bo") XgStudentStatisticsBo bo);
|
||||
|
||||
/**
|
||||
* 按班级维度统计明细数据
|
||||
*/
|
||||
List<XgStudentStatisticsVo.StatisticsDetailData> getClassDetailStatistics(@Param("bo") XgStudentStatisticsBo bo);
|
||||
|
||||
/**
|
||||
* 获取二级学院列表
|
||||
*/
|
||||
List<XgCascadeOptionVo> getColleges();
|
||||
|
||||
/**
|
||||
* 根据学院ID获取专业列表
|
||||
*/
|
||||
List<XgCascadeOptionVo> getMajorsByCollegeId(@Param("collegeId") Long collegeId);
|
||||
|
||||
/**
|
||||
* 根据专业ID获取班级列表
|
||||
*/
|
||||
List<XgCascadeOptionVo> getClassesByMajorId(@Param("majorId") Long majorId);
|
||||
|
||||
}
|
||||
+1
-1
@@ -107,7 +107,7 @@ public interface IXgDormBedStudentService {
|
||||
|
||||
/**
|
||||
* 获取当前用户二级学院的宿舍楼树形结构
|
||||
* 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择
|
||||
* 校区-宿舍楼二级结构,校区不可选,只有宿舍楼可以选择
|
||||
*
|
||||
* @return 宿舍楼树形结构数据
|
||||
*/
|
||||
|
||||
+20
@@ -1,6 +1,7 @@
|
||||
package org.dromara.xg.service;
|
||||
|
||||
import org.dromara.xg.domain.vo.XgDormBuildingVo;
|
||||
import org.dromara.xg.domain.vo.XgDormBuildingSimplifiedVo;
|
||||
import org.dromara.xg.domain.bo.XgDormBuildingBo;
|
||||
import org.dromara.xg.domain.vo.BuildingTreeSelectVo;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
@@ -74,4 +75,23 @@ public interface IXgDormBuildingService {
|
||||
* @return 树形结构数据
|
||||
*/
|
||||
List<BuildingTreeSelectVo> getBuildingTreeData();
|
||||
|
||||
/**
|
||||
* 分页查询宿舍楼信息简化列表
|
||||
* 用于简化界面显示,隐藏宿舍区层级,直接显示校区→宿舍楼结构
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 宿舍楼信息简化分页列表
|
||||
*/
|
||||
TableDataInfo<XgDormBuildingSimplifiedVo> querySimplifiedPageList(XgDormBuildingBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询符合条件的宿舍楼信息简化列表
|
||||
* 用于简化界面显示,隐藏宿舍区层级,直接显示校区→宿舍楼结构
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 宿舍楼信息简化列表
|
||||
*/
|
||||
List<XgDormBuildingSimplifiedVo> querySimplifiedList(XgDormBuildingBo bo);
|
||||
}
|
||||
+19
@@ -2,6 +2,7 @@ package org.dromara.xg.service;
|
||||
|
||||
import java.util.List;
|
||||
import org.dromara.xg.domain.vo.DormBuildingTreeVo;
|
||||
import org.dromara.xg.domain.vo.DormBuildingTreeSimplifiedVo;
|
||||
import org.dromara.xg.domain.bo.DormBuildingTreeBo;
|
||||
|
||||
/**
|
||||
@@ -28,4 +29,22 @@ public interface IXgDormBuildingTreeService {
|
||||
*/
|
||||
List<DormBuildingTreeVo> getAllDormBuildingTree(DormBuildingTreeBo bo);
|
||||
|
||||
/**
|
||||
* 获取宿舍楼树形结构简化数据
|
||||
* 校区-宿舍楼二级结构,隐藏宿舍区层级
|
||||
*
|
||||
* @param bo 查询参数
|
||||
* @return 简化树形结构数据
|
||||
*/
|
||||
List<DormBuildingTreeSimplifiedVo> getSimplifiedDormBuildingTree(DormBuildingTreeBo bo);
|
||||
|
||||
/**
|
||||
* 获取所有宿舍楼树形结构简化数据(不考虑权限)
|
||||
* 校区-宿舍楼二级结构,隐藏宿舍区层级
|
||||
*
|
||||
* @param bo 查询参数
|
||||
* @return 简化树形结构数据
|
||||
*/
|
||||
List<DormBuildingTreeSimplifiedVo> getAllSimplifiedDormBuildingTree(DormBuildingTreeBo bo);
|
||||
|
||||
}
|
||||
+25
@@ -2,6 +2,7 @@ package org.dromara.xg.service;
|
||||
|
||||
import org.dromara.xg.domain.vo.DormHygieneCheckExportVo;
|
||||
import org.dromara.xg.domain.vo.XgDormHygieneCheckVo;
|
||||
import org.dromara.xg.domain.vo.XgHygieneCheckViolationVo;
|
||||
import org.dromara.xg.domain.bo.XgDormHygieneCheckBo;
|
||||
import org.dromara.xg.domain.bo.XgDormHygieneCheckCompleteBo;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
@@ -111,4 +112,28 @@ public interface IXgDormHygieneCheckService {
|
||||
TableDataInfo<XgDormHygieneCheckVo> queryPageListByStudentId(Long studentId, XgDormHygieneCheckBo bo,
|
||||
PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 保存完整的宿舍卫生检查数据(包含学生评分和违纪记录)
|
||||
*
|
||||
* @param bo 完整的宿舍卫生检查数据
|
||||
* @return 检查记录ID,保存失败返回null
|
||||
*/
|
||||
Long saveCompleteData(XgDormHygieneCheckCompleteBo bo);
|
||||
|
||||
/**
|
||||
* 更新完整的宿舍卫生检查数据(包含学生评分和违纪记录)
|
||||
*
|
||||
* @param bo 完整的宿舍卫生检查数据
|
||||
* @return 是否更新成功
|
||||
*/
|
||||
Boolean updateCompleteData(XgDormHygieneCheckCompleteBo bo);
|
||||
|
||||
/**
|
||||
* 根据卫生检查ID查询相关的违纪记录
|
||||
*
|
||||
* @param hygieneCheckId 卫生检查ID
|
||||
* @return 违纪记录列表
|
||||
*/
|
||||
List<XgHygieneCheckViolationVo> getViolationsByHygieneCheckId(Long hygieneCheckId);
|
||||
|
||||
}
|
||||
+10
@@ -7,6 +7,8 @@ import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* 宿舍房间信息Service接口
|
||||
@@ -84,4 +86,12 @@ public interface IXgDormRoomService {
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 导出住宿清单(宿舍卡片式布局)
|
||||
*
|
||||
* @param params 导出参数
|
||||
* @param response HTTP响应对象
|
||||
*/
|
||||
void exportAccommodationList(Map<String, Object> params, HttpServletResponse response);
|
||||
}
|
||||
+8
@@ -77,4 +77,12 @@ public interface IXgHolidayStayService {
|
||||
*/
|
||||
TableDataInfo<StudentOptionVo> getStudentOptions(StudentOptionBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询单人留宿有效数据
|
||||
* 获取所有有效的假期留宿数据,筛选出在同一时间段内该宿舍只有一个学生留宿的记录
|
||||
*
|
||||
* @return 单人留宿有效数据列表
|
||||
*/
|
||||
List<XgHolidayStayVo> querySinglePersonValidStay();
|
||||
|
||||
}
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
package org.dromara.xg.service;
|
||||
|
||||
import org.dromara.xg.domain.vo.XgHygieneCheckViolationVo;
|
||||
import org.dromara.xg.domain.bo.XgHygieneCheckViolationBo;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 宿舍卫生检查违纪记录Service接口
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-29
|
||||
*/
|
||||
public interface IXgHygieneCheckViolationService {
|
||||
|
||||
/**
|
||||
* 查询宿舍卫生检查违纪记录
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 宿舍卫生检查违纪记录
|
||||
*/
|
||||
XgHygieneCheckViolationVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 分页查询宿舍卫生检查违纪记录列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 宿舍卫生检查违纪记录分页列表
|
||||
*/
|
||||
TableDataInfo<XgHygieneCheckViolationVo> queryPageList(XgHygieneCheckViolationBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询符合条件的宿舍卫生检查违纪记录列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 宿舍卫生检查违纪记录列表
|
||||
*/
|
||||
List<XgHygieneCheckViolationVo> queryList(XgHygieneCheckViolationBo bo);
|
||||
|
||||
/**
|
||||
* 新增宿舍卫生检查违纪记录
|
||||
*
|
||||
* @param bo 宿舍卫生检查违纪记录
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
Boolean insertByBo(XgHygieneCheckViolationBo bo);
|
||||
|
||||
/**
|
||||
* 修改宿舍卫生检查违纪记录
|
||||
*
|
||||
* @param bo 宿舍卫生检查违纪记录
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
Boolean updateByBo(XgHygieneCheckViolationBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除宿舍卫生检查违纪记录信息
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 批量新增宿舍卫生检查违纪记录
|
||||
*
|
||||
* @param bos 违纪记录列表
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
Boolean insertBatch(List<XgHygieneCheckViolationBo> bos);
|
||||
|
||||
/**
|
||||
* 根据卫生检查ID查询违纪记录列表
|
||||
*
|
||||
* @param hygieneCheckId 卫生检查ID
|
||||
* @return 违纪记录列表
|
||||
*/
|
||||
List<XgHygieneCheckViolationVo> queryByHygieneCheckId(Long hygieneCheckId);
|
||||
|
||||
/**
|
||||
* 根据卫生检查ID删除违纪关联记录
|
||||
*
|
||||
* @param hygieneCheckId 卫生检查ID
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
Boolean deleteByHygieneCheckId(Long hygieneCheckId);
|
||||
|
||||
}
|
||||
+11
@@ -5,8 +5,10 @@ import org.dromara.xg.domain.bo.XgStudentLeaveBo;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 学生请假 - 记录学生的请假申请、审批和销假信息Service接口
|
||||
@@ -65,4 +67,13 @@ public interface IXgStudentLeaveService {
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 根据学生ID列表和检查日期查询学生请假信息
|
||||
*
|
||||
* @param studentIds 学生ID列表
|
||||
* @param checkDate 检查日期
|
||||
* @return 学生ID -> 请假信息的映射
|
||||
*/
|
||||
Map<Long, XgStudentLeaveVo> queryStudentLeavesByCheckDate(List<Long> studentIds, LocalDateTime checkDate);
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package org.dromara.xg.service;
|
||||
|
||||
import java.util.List;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.dromara.xg.domain.bo.XgStudentStatisticsBo;
|
||||
import org.dromara.xg.domain.vo.XgStudentStatisticsVo;
|
||||
import org.dromara.xg.domain.vo.XgCascadeOptionVo;
|
||||
|
||||
/**
|
||||
* 学生宿舍卫生检查、违纪记录统计Service接口
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-14
|
||||
*/
|
||||
public interface IXgStudentStatisticsService {
|
||||
|
||||
/**
|
||||
* 获取统计数据
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 统计结果
|
||||
*/
|
||||
XgStudentStatisticsVo getStatistics(XgStudentStatisticsBo bo);
|
||||
|
||||
/**
|
||||
* 导出统计数据
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param response HTTP响应
|
||||
*/
|
||||
void exportStatistics(XgStudentStatisticsBo bo, HttpServletResponse response);
|
||||
|
||||
/**
|
||||
* 获取二级学院列表
|
||||
*
|
||||
* @return 学院列表
|
||||
*/
|
||||
List<XgCascadeOptionVo> getColleges();
|
||||
|
||||
/**
|
||||
* 根据学院ID获取专业列表
|
||||
*
|
||||
* @param collegeId 学院ID
|
||||
* @return 专业列表
|
||||
*/
|
||||
List<XgCascadeOptionVo> getMajorsByCollegeId(Long collegeId);
|
||||
|
||||
/**
|
||||
* 根据专业ID获取班级列表
|
||||
*
|
||||
* @param majorId 专业ID
|
||||
* @return 班级列表
|
||||
*/
|
||||
List<XgCascadeOptionVo> getClassesByMajorId(Long majorId);
|
||||
|
||||
}
|
||||
+59
-4
@@ -983,7 +983,8 @@ public class XgDormBedStudentServiceImpl implements IXgDormBedStudentService {
|
||||
Long roomId = entry.getKey();
|
||||
List<Long> roomUnallocatedBeds = entry.getValue();
|
||||
String roomCode = roomCodeMap.get(roomId);
|
||||
log.error("房间{}({})有{}个床位未分配:{}", roomCode, roomId, roomUnallocatedBeds.size(), roomUnallocatedBeds);
|
||||
log.error("房间{}({})有{}个床位未分配:{}", roomCode, roomId, roomUnallocatedBeds.size(),
|
||||
roomUnallocatedBeds);
|
||||
}
|
||||
|
||||
throw new RuntimeException("床位分配不完整,存在" + (totalExpectedBeds - totalAllocatedBeds) + "个床位未分配");
|
||||
@@ -1008,7 +1009,7 @@ public class XgDormBedStudentServiceImpl implements IXgDormBedStudentService {
|
||||
|
||||
/**
|
||||
* 获取当前用户二级学院的宿舍楼树形结构
|
||||
* 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择
|
||||
* 校区-宿舍楼二级结构,校区不可选,只有宿舍楼可以选择
|
||||
*
|
||||
* @return 宿舍楼树形结构数据
|
||||
*/
|
||||
@@ -1159,8 +1160,8 @@ public class XgDormBedStudentServiceImpl implements IXgDormBedStudentService {
|
||||
.orderByAsc(XgDormCampus::getSortOrder, XgDormCampus::getId);
|
||||
List<XgDormCampus> campuses = xgDormCampusMapper.selectList(campusWrapper);
|
||||
|
||||
// 构建树形结构
|
||||
return buildTreeStructure(campuses, areas, buildings);
|
||||
// 构建简化版树形结构(校区-宿舍楼,去除宿舍区层级)
|
||||
return buildSimplifiedTreeStructure(campuses, areas, buildings);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("构建宿舍楼树形结构失败", e);
|
||||
@@ -1232,6 +1233,60 @@ public class XgDormBedStudentServiceImpl implements IXgDormBedStudentService {
|
||||
return new ArrayList<>(campusMap.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建简化树形结构:校区-宿舍楼(去除宿舍区层级)
|
||||
*/
|
||||
private List<DormBuildingTreeVo> buildSimplifiedTreeStructure(List<XgDormCampus> campuses,
|
||||
List<XgDormArea> areas,
|
||||
List<XgDormBuilding> buildings) {
|
||||
|
||||
// 构建校区节点(第一层)
|
||||
Map<Long, DormBuildingTreeVo> campusMap = new LinkedHashMap<>();
|
||||
for (XgDormCampus campus : campuses) {
|
||||
// 检查该校区下是否有宿舍楼(通过宿舍区关联)
|
||||
boolean hasBuildings = buildings.stream().anyMatch(building -> areas.stream().anyMatch(
|
||||
area -> area.getId().equals(building.getAreaId()) && area.getCampusId().equals(campus.getId())));
|
||||
|
||||
if (hasBuildings) {
|
||||
DormBuildingTreeVo campusNode = new DormBuildingTreeVo();
|
||||
campusNode.setId(campus.getId());
|
||||
campusNode.setLabel(campus.getCampusName());
|
||||
campusNode.setType("campus");
|
||||
campusNode.setDisabled(true); // 校区节点禁止点击
|
||||
campusNode.setChildren(new ArrayList<>());
|
||||
campusMap.put(campus.getId(), campusNode);
|
||||
}
|
||||
}
|
||||
|
||||
// 直接构建宿舍楼节点(第二层),跳过宿舍区
|
||||
for (XgDormBuilding building : buildings) {
|
||||
// 通过宿舍区找到对应的校区
|
||||
XgDormArea area = areas.stream()
|
||||
.filter(a -> a.getId().equals(building.getAreaId()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
if (area != null) {
|
||||
DormBuildingTreeVo buildingNode = new DormBuildingTreeVo();
|
||||
buildingNode.setId(building.getId());
|
||||
buildingNode.setLabel(building.getBuildingName());
|
||||
buildingNode.setType("building");
|
||||
buildingNode.setDisabled(false); // 宿舍楼节点可以点击
|
||||
buildingNode.setBuildingFloors(building.getFloors());
|
||||
buildingNode.setBuildingType(building.getBuildingType());
|
||||
buildingNode.setChildren(new ArrayList<>());
|
||||
|
||||
// 直接添加到校区下,跳过宿舍区层级
|
||||
DormBuildingTreeVo campusNode = campusMap.get(area.getCampusId());
|
||||
if (campusNode != null) {
|
||||
campusNode.getChildren().add(buildingNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayList<>(campusMap.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取班主任管理的班级宿舍楼树
|
||||
* 通过当前用户所在的班级,获取该班级分配的宿舍楼
|
||||
|
||||
+71
-46
@@ -12,6 +12,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.dromara.xg.domain.bo.XgDormBuildingBo;
|
||||
import org.dromara.xg.domain.vo.XgDormBuildingVo;
|
||||
import org.dromara.xg.domain.vo.XgDormBuildingSimplifiedVo;
|
||||
import org.dromara.xg.domain.XgDormBuilding;
|
||||
import org.dromara.xg.domain.XgDormArea;
|
||||
import org.dromara.xg.domain.XgDormCampus;
|
||||
@@ -145,7 +146,7 @@ public class XgDormBuildingServiceImpl implements IXgDormBuildingService {
|
||||
|
||||
/**
|
||||
* 获取宿舍楼树形结构数据
|
||||
* 校区-宿舍区-宿舍楼三级结构,校区和宿舍区不可选,只有宿舍楼可以选择
|
||||
* 校区-宿舍楼二级结构,校区不可选,只有宿舍楼可以选择
|
||||
*
|
||||
* @return 宿舍楼树形结构数据
|
||||
*/
|
||||
@@ -156,59 +157,41 @@ public class XgDormBuildingServiceImpl implements IXgDormBuildingService {
|
||||
Wrappers.<XgDormCampus>lambdaQuery()
|
||||
.orderByAsc(XgDormCampus::getSortOrder, XgDormCampus::getId));
|
||||
|
||||
// 2. 获取所有宿舍区数据
|
||||
List<XgDormArea> areaList = areaMapper.selectList(
|
||||
Wrappers.<XgDormArea>lambdaQuery()
|
||||
.orderByAsc(XgDormArea::getSortOrder, XgDormArea::getId));
|
||||
|
||||
// 3. 获取所有宿舍楼数据
|
||||
// 2. 获取所有宿舍楼数据
|
||||
List<XgDormBuilding> buildingList = baseMapper.selectList(
|
||||
Wrappers.<XgDormBuilding>lambdaQuery()
|
||||
.orderByAsc(XgDormBuilding::getSortOrder, XgDormBuilding::getId));
|
||||
|
||||
// 4. 构建树形结构
|
||||
// 3. 构建树形结构
|
||||
List<BuildingTreeSelectVo> treeList = new ArrayList<>();
|
||||
|
||||
// 5. 先构建校区节点
|
||||
// 4. 先构建校区节点
|
||||
for (XgDormCampus campus : campusList) {
|
||||
BuildingTreeSelectVo campusNode = new BuildingTreeSelectVo();
|
||||
campusNode.setId(campus.getId());
|
||||
campusNode.setLabel(campus.getCampusName());
|
||||
campusNode.setNodeType("campus");
|
||||
campusNode.setDisabled(true); // 校区不可选
|
||||
campusNode.setChildren(new ArrayList<>());
|
||||
|
||||
// 设置创建者和更新者字段
|
||||
campusNode.setCreateBy(campus.getCreateBy());
|
||||
campusNode.setCreateTime(campus.getCreateTime());
|
||||
campusNode.setUpdateBy(campus.getUpdateBy());
|
||||
campusNode.setUpdateTime(campus.getUpdateTime());
|
||||
|
||||
// 添加该校区下的宿舍区
|
||||
List<XgDormArea> campusAreas = areaList.stream()
|
||||
.filter(area -> area.getCampusId().equals(campus.getId()))
|
||||
// 检查该校区下是否有宿舍楼
|
||||
List<XgDormBuilding> campusBuildings = buildingList.stream()
|
||||
.filter(building -> {
|
||||
// 通过宿舍区找到校区
|
||||
XgDormArea area = areaMapper.selectById(building.getAreaId());
|
||||
return area != null && area.getCampusId().equals(campus.getId());
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (XgDormArea area : campusAreas) {
|
||||
BuildingTreeSelectVo areaNode = new BuildingTreeSelectVo();
|
||||
areaNode.setId(area.getId());
|
||||
areaNode.setLabel(area.getAreaName());
|
||||
areaNode.setNodeType("area");
|
||||
areaNode.setDisabled(true); // 宿舍区不可选
|
||||
areaNode.setChildren(new ArrayList<>());
|
||||
if (!campusBuildings.isEmpty()) {
|
||||
BuildingTreeSelectVo campusNode = new BuildingTreeSelectVo();
|
||||
campusNode.setId(campus.getId());
|
||||
campusNode.setLabel(campus.getCampusName());
|
||||
campusNode.setNodeType("campus");
|
||||
campusNode.setDisabled(true); // 校区不可选
|
||||
campusNode.setChildren(new ArrayList<>());
|
||||
|
||||
// 设置创建者和更新者字段
|
||||
areaNode.setCreateBy(area.getCreateBy());
|
||||
areaNode.setCreateTime(area.getCreateTime());
|
||||
areaNode.setUpdateBy(area.getUpdateBy());
|
||||
areaNode.setUpdateTime(area.getUpdateTime());
|
||||
campusNode.setCreateBy(campus.getCreateBy());
|
||||
campusNode.setCreateTime(campus.getCreateTime());
|
||||
campusNode.setUpdateBy(campus.getUpdateBy());
|
||||
campusNode.setUpdateTime(campus.getUpdateTime());
|
||||
|
||||
// 添加该宿舍区下的宿舍楼
|
||||
List<XgDormBuilding> areaBuildings = buildingList.stream()
|
||||
.filter(building -> building.getAreaId().equals(area.getId()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (XgDormBuilding building : areaBuildings) {
|
||||
// 直接添加该校区下的宿舍楼,跳过宿舍区层级
|
||||
for (XgDormBuilding building : campusBuildings) {
|
||||
BuildingTreeSelectVo buildingNode = new BuildingTreeSelectVo();
|
||||
buildingNode.setId(building.getId());
|
||||
buildingNode.setLabel(building.getBuildingName());
|
||||
@@ -222,15 +205,57 @@ public class XgDormBuildingServiceImpl implements IXgDormBuildingService {
|
||||
buildingNode.setUpdateBy(building.getUpdateBy());
|
||||
buildingNode.setUpdateTime(building.getUpdateTime());
|
||||
|
||||
areaNode.getChildren().add(buildingNode);
|
||||
campusNode.getChildren().add(buildingNode);
|
||||
}
|
||||
|
||||
campusNode.getChildren().add(areaNode);
|
||||
treeList.add(campusNode);
|
||||
}
|
||||
|
||||
treeList.add(campusNode);
|
||||
}
|
||||
|
||||
return treeList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询宿舍楼信息简化列表
|
||||
* 用于简化界面显示,隐藏宿舍区层级,直接显示校区→宿舍楼结构
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 宿舍楼信息简化分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<XgDormBuildingSimplifiedVo> querySimplifiedPageList(XgDormBuildingBo bo, PageQuery pageQuery) {
|
||||
// 先查询完整的分页数据
|
||||
TableDataInfo<XgDormBuildingVo> fullPageList = queryPageList(bo, pageQuery);
|
||||
|
||||
// 转换为简化版VO
|
||||
List<XgDormBuildingSimplifiedVo> simplifiedList = fullPageList.getRows().stream()
|
||||
.map(XgDormBuildingSimplifiedVo::fromFullVo)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 创建简化版分页结果
|
||||
TableDataInfo<XgDormBuildingSimplifiedVo> simplifiedPageList = new TableDataInfo<>();
|
||||
simplifiedPageList.setRows(simplifiedList);
|
||||
simplifiedPageList.setTotal(fullPageList.getTotal());
|
||||
|
||||
return simplifiedPageList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询符合条件的宿舍楼信息简化列表
|
||||
* 用于简化界面显示,隐藏宿舍区层级,直接显示校区→宿舍楼结构
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 宿舍楼信息简化列表
|
||||
*/
|
||||
@Override
|
||||
public List<XgDormBuildingSimplifiedVo> querySimplifiedList(XgDormBuildingBo bo) {
|
||||
// 先查询完整的数据
|
||||
List<XgDormBuildingVo> fullList = queryList(bo);
|
||||
|
||||
// 转换为简化版VO
|
||||
return fullList.stream()
|
||||
.map(XgDormBuildingSimplifiedVo::fromFullVo)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
+39
@@ -8,6 +8,7 @@ import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.xg.service.IXgDormBuildingTreeService;
|
||||
import org.dromara.xg.mapper.XgDormBuildingTreeMapper;
|
||||
import org.dromara.xg.domain.vo.DormBuildingTreeVo;
|
||||
import org.dromara.xg.domain.vo.DormBuildingTreeSimplifiedVo;
|
||||
import org.dromara.xg.domain.vo.DormBuildingInfoVo;
|
||||
import org.dromara.xg.domain.bo.DormBuildingTreeBo;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
@@ -231,4 +232,42 @@ public class XgDormBuildingTreeServiceImpl implements IXgDormBuildingTreeService
|
||||
return new ArrayList<>(campusMap.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取宿舍楼树形结构简化数据
|
||||
* 校区-宿舍楼二级结构,隐藏宿舍区层级
|
||||
*
|
||||
* @param bo 查询参数
|
||||
* @return 简化树形结构数据
|
||||
*/
|
||||
@Override
|
||||
public List<DormBuildingTreeSimplifiedVo> getSimplifiedDormBuildingTree(DormBuildingTreeBo bo) {
|
||||
// 先获取完整的树形结构数据
|
||||
List<DormBuildingTreeVo> fullTreeData = getDormBuildingTree(bo);
|
||||
|
||||
// 转换为简化版树形结构
|
||||
return fullTreeData.stream()
|
||||
.map(DormBuildingTreeSimplifiedVo::fromFullTreeVo)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有宿舍楼树形结构简化数据(不考虑权限)
|
||||
* 校区-宿舍楼二级结构,隐藏宿舍区层级
|
||||
*
|
||||
* @param bo 查询参数
|
||||
* @return 简化树形结构数据
|
||||
*/
|
||||
@Override
|
||||
public List<DormBuildingTreeSimplifiedVo> getAllSimplifiedDormBuildingTree(DormBuildingTreeBo bo) {
|
||||
// 先获取完整的树形结构数据(不考虑权限)
|
||||
List<DormBuildingTreeVo> fullTreeData = getAllDormBuildingTree(bo);
|
||||
|
||||
// 转换为简化版树形结构
|
||||
return fullTreeData.stream()
|
||||
.map(DormBuildingTreeSimplifiedVo::fromFullTreeVo)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
+769
-2
@@ -14,6 +14,8 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import org.dromara.xg.domain.bo.XgDormHygieneCheckBo;
|
||||
import org.dromara.xg.domain.bo.XgDormHygieneCheckCompleteBo;
|
||||
import org.dromara.xg.domain.bo.XgDormHygieneStudentScoreBo;
|
||||
import org.dromara.xg.domain.bo.XgHygieneCheckViolationBo;
|
||||
import org.dromara.xg.domain.bo.XgViolationDataBo;
|
||||
import org.dromara.xg.domain.vo.DormHygieneCheckExportVo;
|
||||
import org.dromara.xg.domain.vo.XgDormHygieneCheckVo;
|
||||
import org.dromara.xg.domain.XgDormHygieneCheck;
|
||||
@@ -22,11 +24,23 @@ import org.dromara.xg.mapper.XgDormHygieneCheckMapper;
|
||||
import org.dromara.xg.mapper.XgDormHygieneStudentScoreMapper;
|
||||
import org.dromara.xg.service.IXgDormHygieneCheckService;
|
||||
import org.dromara.xg.service.IXgStudentMsgService;
|
||||
import org.dromara.xg.service.IXgHygieneCheckViolationService;
|
||||
import org.dromara.xg.service.IXgDormHygieneStudentScoreService;
|
||||
import org.dromara.xg.mapper.XgHygieneCheckViolationMapper;
|
||||
import org.dromara.system.service.ISysDictDataService;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import org.dromara.xg.domain.vo.XgHygieneCheckViolationVo;
|
||||
import org.dromara.xg.domain.XgHygieneCheckViolation;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* 宿舍卫生检查Service业务层处理
|
||||
@@ -43,6 +57,10 @@ public class XgDormHygieneCheckServiceImpl implements IXgDormHygieneCheckService
|
||||
private final XgDormHygieneStudentScoreMapper studentScoreMapper;
|
||||
private final IXgStudentMsgService xgStudentMsgService;
|
||||
private final ISysDictDataService sysDictDataService;
|
||||
private final IXgHygieneCheckViolationService violationService;
|
||||
private final IXgDormHygieneStudentScoreService studentScoreService;
|
||||
private final XgHygieneCheckViolationMapper violationMapper;
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
/**
|
||||
* 查询宿舍卫生检查
|
||||
@@ -154,18 +172,60 @@ public class XgDormHygieneCheckServiceImpl implements IXgDormHygieneCheckService
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验并批量删除宿舍卫生检查信息
|
||||
* 校验并批量删除宿舍卫生检查信息(级联删除四个表)
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return baseMapper.deleteByIds(ids) > 0;
|
||||
|
||||
try {
|
||||
// 逐个处理每个卫生检查记录的级联删除
|
||||
for (Long checkId : ids) {
|
||||
log.info("开始级联删除宿舍卫生检查记录,检查ID: {}", checkId);
|
||||
|
||||
// 1. 查询并删除关联的违纪记录
|
||||
List<XgHygieneCheckViolationVo> violations = violationService.queryByHygieneCheckId(checkId);
|
||||
if (!violations.isEmpty()) {
|
||||
log.info("发现 {} 条违纪关联记录需要删除,检查ID: {}", violations.size(), checkId);
|
||||
|
||||
// 1.1 删除统一违纪记录 (xskh_discipline_record)
|
||||
for (XgHygieneCheckViolationVo violation : violations) {
|
||||
if (violation.getDisciplineRecordId() != null) {
|
||||
deleteDisciplineRecord(violation.getDisciplineRecordId());
|
||||
}
|
||||
}
|
||||
|
||||
// 1.2 删除违纪关联记录 (xg_hygiene_check_violation)
|
||||
violationService.deleteByHygieneCheckId(checkId);
|
||||
log.info("删除违纪关联记录完成,检查ID: {}", checkId);
|
||||
}
|
||||
|
||||
// 2. 删除学生评分记录 (xg_dorm_hygiene_student_score)
|
||||
Boolean studentScoreDeleted = studentScoreService.deleteByHygieneCheckId(checkId);
|
||||
if (studentScoreDeleted) {
|
||||
log.info("删除学生评分记录完成,检查ID: {}", checkId);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 删除主检查记录 (xg_dorm_hygiene_check)
|
||||
Boolean mainDeleted = baseMapper.deleteByIds(ids) > 0;
|
||||
if (mainDeleted) {
|
||||
log.info("删除宿舍卫生检查主记录完成,删除数量: {}", ids.size());
|
||||
}
|
||||
|
||||
return mainDeleted;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("级联删除宿舍卫生检查记录失败,检查IDs: {}, 错误: {}", ids, e.getMessage(), e);
|
||||
throw new RuntimeException("删除宿舍卫生检查记录失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -574,4 +634,711 @@ public class XgDormHygieneCheckServiceImpl implements IXgDormHygieneCheckService
|
||||
return "1".equals(isResponsiblePerson) ? "是" : "否";
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存完整的宿舍卫生检查数据(包含学生评分和违纪记录)
|
||||
*
|
||||
* @param bo 完整的宿舍卫生检查数据
|
||||
* @return 检查记录ID,保存失败返回null
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long saveCompleteData(XgDormHygieneCheckCompleteBo bo) {
|
||||
try {
|
||||
// 1. 转换并保存主表数据
|
||||
XgDormHygieneCheck add = MapstructUtils.convert(bo, XgDormHygieneCheck.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
log.info("保存宿舍卫生检查主表数据: {}", add);
|
||||
|
||||
if (!flag) {
|
||||
log.error("保存宿舍卫生检查主表数据失败");
|
||||
return null;
|
||||
}
|
||||
|
||||
Long hygieneCheckId = add.getId();
|
||||
|
||||
// 2. 保存学生评分数据
|
||||
if (bo.getStudentScores() != null && !bo.getStudentScores().isEmpty()) {
|
||||
for (XgDormHygieneStudentScoreBo studentScoreBo : bo.getStudentScores()) {
|
||||
XgDormHygieneStudentScore studentScore = MapstructUtils.convert(studentScoreBo,
|
||||
XgDormHygieneStudentScore.class);
|
||||
studentScore.setHygieneCheckId(hygieneCheckId);
|
||||
|
||||
// 根据学生ID查询学生完整信息,补充学院、专业、班级信息
|
||||
if (studentScoreBo.getStudentId() != null) {
|
||||
try {
|
||||
var studentInfo = xgStudentMsgService.queryById(studentScoreBo.getStudentId());
|
||||
if (studentInfo != null) {
|
||||
// 补充学院信息
|
||||
if (studentScore.getCollegeId() == null
|
||||
&& StringUtils.isNotBlank(studentInfo.getCollegeId())) {
|
||||
try {
|
||||
studentScore.setCollegeId(Long.valueOf(studentInfo.getCollegeId()));
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("学院ID转换失败,学生ID: {}, 学院ID: {}", studentScoreBo.getStudentId(),
|
||||
studentInfo.getCollegeId());
|
||||
}
|
||||
}
|
||||
if (StringUtils.isBlank(studentScore.getCollegeName())) {
|
||||
studentScore.setCollegeName(studentInfo.getCollegeName());
|
||||
}
|
||||
|
||||
// 补充专业信息
|
||||
if (studentScore.getMajorId() == null
|
||||
&& StringUtils.isNotBlank(studentInfo.getMajorId())) {
|
||||
try {
|
||||
studentScore.setMajorId(Long.valueOf(studentInfo.getMajorId()));
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("专业ID转换失败,学生ID: {}, 专业ID: {}", studentScoreBo.getStudentId(),
|
||||
studentInfo.getMajorId());
|
||||
}
|
||||
}
|
||||
if (StringUtils.isBlank(studentScore.getMajorName())) {
|
||||
studentScore.setMajorName(studentInfo.getMajorName());
|
||||
}
|
||||
|
||||
// 补充班级信息
|
||||
if (studentScore.getClassId() == null
|
||||
&& StringUtils.isNotBlank(studentInfo.getClassId())) {
|
||||
try {
|
||||
studentScore.setClassId(Long.valueOf(studentInfo.getClassId()));
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("班级ID转换失败,学生ID: {}, 班级ID: {}", studentScoreBo.getStudentId(),
|
||||
studentInfo.getClassId());
|
||||
}
|
||||
}
|
||||
if (StringUtils.isBlank(studentScore.getClassName())) {
|
||||
studentScore.setClassName(studentInfo.getClassName());
|
||||
}
|
||||
|
||||
log.info("补充学生信息 - 学生ID: {}, 学院: {}, 专业: {}, 班级: {}",
|
||||
studentScoreBo.getStudentId(),
|
||||
studentInfo.getCollegeName(),
|
||||
studentInfo.getMajorName(),
|
||||
studentInfo.getClassName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("查询学生信息失败,学生ID: {}, 错误: {}", studentScoreBo.getStudentId(), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
log.info("保存学生评分数据: {}", studentScore);
|
||||
studentScoreMapper.insert(studentScore);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 保存违纪记录数据(兼容架构:优先保存到统一表,失败时保存关联关系)
|
||||
if (bo.getViolationData() != null && !bo.getViolationData().isEmpty()) {
|
||||
for (XgViolationDataBo violationBo : bo.getViolationData()) {
|
||||
try {
|
||||
log.info("处理违纪记录数据: {}", violationBo);
|
||||
|
||||
// 3.1 尝试创建违纪记录到统一的xskh_discipline_record表
|
||||
Long disciplineRecordId = createDisciplineRecord(violationBo);
|
||||
|
||||
// 3.2 仅当违纪记录创建成功时才创建关联记录
|
||||
if (disciplineRecordId != null) {
|
||||
XgHygieneCheckViolationBo relationBo = new XgHygieneCheckViolationBo();
|
||||
relationBo.setHygieneCheckId(hygieneCheckId);
|
||||
relationBo.setDisciplineRecordId(disciplineRecordId);
|
||||
relationBo.setStudentId(violationBo.getStudentId());
|
||||
relationBo.setStudentNo(violationBo.getStudentNo());
|
||||
relationBo.setStudentName(violationBo.getStudentName());
|
||||
relationBo.setDisciplineTypeId(violationBo.getDisciplineTypeId());
|
||||
relationBo.setDisciplineTypeName(violationBo.getDisciplineTypeName());
|
||||
relationBo.setViolationSource("1"); // 1-宿舍卫生检查
|
||||
relationBo.setStatus("1"); // 1-生效
|
||||
|
||||
boolean relationResult = violationService.insertByBo(relationBo);
|
||||
if (!relationResult) {
|
||||
log.warn("创建卫生检查违纪关联记录失败,学生ID: {}", violationBo.getStudentId());
|
||||
} else {
|
||||
log.info("创建卫生检查违纪关联记录成功,学生ID: {},违纪记录ID: {}",
|
||||
violationBo.getStudentId(), disciplineRecordId);
|
||||
}
|
||||
} else {
|
||||
log.warn("违纪记录创建失败,跳过关联记录创建,学生ID: {}", violationBo.getStudentId());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("处理违纪数据失败,学生ID: {}, 错误: {}", violationBo.getStudentId(), e.getMessage(), e);
|
||||
throw new RuntimeException(
|
||||
"处理违纪数据失败,学生ID: " + violationBo.getStudentId() + ", 错误: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.info("完整保存宿舍卫生检查数据成功,检查ID: {}", hygieneCheckId);
|
||||
return hygieneCheckId;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("保存宿舍卫生检查数据失败", e);
|
||||
throw new RuntimeException("保存宿舍卫生检查数据失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建学生违纪记录
|
||||
*
|
||||
* @param violationBo 违纪数据
|
||||
* @return 违纪记录ID
|
||||
*/
|
||||
private Long createDisciplineRecord(XgViolationDataBo violationBo) {
|
||||
try {
|
||||
// 通过接口类型动态获取IXskhDisciplineRecordService,避免硬依赖
|
||||
Class<?> serviceInterface = Class.forName("org.dromara.xskh.service.IXskhDisciplineRecordService");
|
||||
Object disciplineRecordService = applicationContext.getBean(serviceInterface);
|
||||
|
||||
if (disciplineRecordService != null) {
|
||||
// 创建XskhDisciplineRecordBo对象
|
||||
Object disciplineRecordBo = createDisciplineRecordBo(violationBo);
|
||||
if (disciplineRecordBo != null) {
|
||||
// 反射调用insertByBo方法 - 使用具体的Bo类型而不是Object
|
||||
Class<?> disciplineRecordBoClass = Class
|
||||
.forName("org.dromara.xskh.domain.bo.XskhDisciplineRecordBo");
|
||||
var insertMethod = disciplineRecordService.getClass().getMethod("insertByBo",
|
||||
disciplineRecordBoClass);
|
||||
Boolean result = (Boolean) insertMethod.invoke(disciplineRecordService, disciplineRecordBo);
|
||||
|
||||
if (result) {
|
||||
// 获取插入后的ID
|
||||
var field = disciplineRecordBo.getClass().getDeclaredField("id");
|
||||
field.setAccessible(true);
|
||||
Long id = (Long) field.get(disciplineRecordBo);
|
||||
log.info("创建学生违纪记录成功,学生ID: {}, 违纪记录ID: {}", violationBo.getStudentId(), id);
|
||||
return id;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
log.warn("学生考核管理模块(xskh)未启用,跳过违纪记录创建");
|
||||
} catch (Exception e) {
|
||||
log.error("创建学生违纪记录失败: {}", e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建学生违纪记录Bo对象
|
||||
*
|
||||
* @param violationBo 违纪数据
|
||||
* @return 学生违纪记录Bo对象
|
||||
*/
|
||||
private Object createDisciplineRecordBo(XgViolationDataBo violationBo) {
|
||||
try {
|
||||
// 通过反射创建XskhDisciplineRecordBo对象
|
||||
Class<?> disciplineRecordBoClass = Class.forName("org.dromara.xskh.domain.bo.XskhDisciplineRecordBo");
|
||||
Object disciplineRecordBo = disciplineRecordBoClass.getDeclaredConstructor().newInstance();
|
||||
|
||||
// 设置基本字段
|
||||
setFieldValue(disciplineRecordBo, "studentId", violationBo.getStudentId());
|
||||
setFieldValue(disciplineRecordBo, "studentNo", violationBo.getStudentNo());
|
||||
setFieldValue(disciplineRecordBo, "studentName", violationBo.getStudentName());
|
||||
|
||||
// 修复:确保collegeId、majorId、classId不为null
|
||||
// 如果ID为空,尝试通过学生ID查询完整信息
|
||||
Long collegeId = violationBo.getCollegeId();
|
||||
Long majorId = violationBo.getMajorId();
|
||||
Long classId = violationBo.getClassId();
|
||||
String collegeName = violationBo.getCollegeName();
|
||||
String majorName = violationBo.getMajorName();
|
||||
String className = violationBo.getClassName();
|
||||
|
||||
// 如果ID字段为空,尝试从学生信息中获取
|
||||
if ((collegeId == null || collegeId == 0) && violationBo.getStudentId() != null) {
|
||||
try {
|
||||
// 查询学生详细信息以获取缺失的ID字段
|
||||
Map<String, Object> studentDetail = getStudentDetailInfo(violationBo.getStudentId());
|
||||
if (studentDetail != null) {
|
||||
// 修复:安全地获取Long类型的ID字段
|
||||
Object collegeIdObj = studentDetail.get("collegeId");
|
||||
Object majorIdObj = studentDetail.get("majorId");
|
||||
Object classIdObj = studentDetail.get("classId");
|
||||
|
||||
collegeId = (collegeIdObj instanceof Long) ? (Long) collegeIdObj
|
||||
: (collegeIdObj != null ? Long.valueOf(collegeIdObj.toString()) : null);
|
||||
majorId = (majorIdObj instanceof Long) ? (Long) majorIdObj
|
||||
: (majorIdObj != null ? Long.valueOf(majorIdObj.toString()) : null);
|
||||
classId = (classIdObj instanceof Long) ? (Long) classIdObj
|
||||
: (classIdObj != null ? Long.valueOf(classIdObj.toString()) : null);
|
||||
|
||||
// 如果名称为空,也从查询结果中获取
|
||||
if (StringUtils.isBlank(collegeName)) {
|
||||
collegeName = (String) studentDetail.getOrDefault("collegeName", "未知学院");
|
||||
}
|
||||
if (StringUtils.isBlank(majorName)) {
|
||||
majorName = (String) studentDetail.getOrDefault("majorName", "未知专业");
|
||||
}
|
||||
if (StringUtils.isBlank(className)) {
|
||||
className = (String) studentDetail.getOrDefault("className", "未知班级");
|
||||
}
|
||||
|
||||
log.info("从学生信息中补充ID字段,学生ID: {}, 学院ID: {}, 专业ID: {}, 班级ID: {}",
|
||||
violationBo.getStudentId(), collegeId, majorId, classId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("查询学生详细信息失败,使用默认值,学生ID: {}, 错误: {}", violationBo.getStudentId(), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
setFieldValue(disciplineRecordBo, "collegeId", collegeId != null ? collegeId : 0L);
|
||||
setFieldValue(disciplineRecordBo, "collegeName",
|
||||
StringUtils.isNotBlank(collegeName) ? collegeName : "未知学院");
|
||||
setFieldValue(disciplineRecordBo, "majorId", majorId != null ? majorId : 0L);
|
||||
setFieldValue(disciplineRecordBo, "majorName",
|
||||
StringUtils.isNotBlank(majorName) ? majorName : "未知专业");
|
||||
setFieldValue(disciplineRecordBo, "classId", classId != null ? classId : 0L);
|
||||
setFieldValue(disciplineRecordBo, "className",
|
||||
StringUtils.isNotBlank(className) ? className : "未知班级");
|
||||
|
||||
setFieldValue(disciplineRecordBo, "disciplineTypeId", violationBo.getDisciplineTypeId());
|
||||
setFieldValue(disciplineRecordBo, "disciplineTypeName", violationBo.getDisciplineTypeName());
|
||||
|
||||
// 设置违纪日期
|
||||
if (StringUtils.isNotBlank(violationBo.getDisciplineDate())) {
|
||||
setFieldValue(disciplineRecordBo, "disciplineDate",
|
||||
java.time.LocalDate.parse(violationBo.getDisciplineDate()));
|
||||
} else {
|
||||
setFieldValue(disciplineRecordBo, "disciplineDate", java.time.LocalDate.now());
|
||||
}
|
||||
|
||||
// 设置违纪原因和内容
|
||||
setFieldValue(disciplineRecordBo, "disciplineReason", violationBo.getDisciplineReason());
|
||||
setFieldValue(disciplineRecordBo, "disciplineContent", violationBo.getDisciplineContent());
|
||||
|
||||
// 设置扣分分值
|
||||
if (violationBo.getScoreDeduction() != null) {
|
||||
setFieldValue(disciplineRecordBo, "scoreDeduction", violationBo.getScoreDeduction());
|
||||
}
|
||||
|
||||
// 设置状态和违纪来源
|
||||
setFieldValue(disciplineRecordBo, "status",
|
||||
StringUtils.isNotBlank(violationBo.getStatus()) ? violationBo.getStatus() : "1");
|
||||
setFieldValue(disciplineRecordBo, "violationSource", "1"); // 1-宿舍卫生检查
|
||||
|
||||
// 设置附件信息(如果有)
|
||||
if (StringUtils.isNotBlank(violationBo.getAttachmentOssIds())) {
|
||||
setFieldValue(disciplineRecordBo, "attachmentOssIds", violationBo.getAttachmentOssIds());
|
||||
}
|
||||
|
||||
log.info("创建学生违纪记录Bo对象成功,学生ID: {}, 违纪类型: {}",
|
||||
violationBo.getStudentId(), violationBo.getDisciplineTypeName());
|
||||
|
||||
return disciplineRecordBo;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("创建学生违纪记录Bo对象失败: {}", e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过反射设置对象字段值
|
||||
*
|
||||
* @param target 目标对象
|
||||
* @param fieldName 字段名
|
||||
* @param value 字段值
|
||||
*/
|
||||
private void setFieldValue(Object target, String fieldName, Object value) {
|
||||
try {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var field = target.getClass().getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
field.set(target, value);
|
||||
} catch (Exception e) {
|
||||
log.warn("设置字段值失败,字段名: {}, 值: {}, 错误: {}", fieldName, value, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取学生详细信息(包含学院、专业、班级ID)
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @return 学生详细信息Map
|
||||
*/
|
||||
private Map<String, Object> getStudentDetailInfo(Long studentId) {
|
||||
try {
|
||||
var studentInfo = xgStudentMsgService.queryById(studentId);
|
||||
if (studentInfo != null) {
|
||||
Map<String, Object> detailMap = new HashMap<>();
|
||||
|
||||
// 修复:安全地将String类型的ID转换为Long类型
|
||||
detailMap.put("collegeId", parseStringToLong(studentInfo.getCollegeId()));
|
||||
detailMap.put("collegeName", studentInfo.getCollegeName());
|
||||
detailMap.put("majorId", parseStringToLong(studentInfo.getMajorId()));
|
||||
detailMap.put("majorName", studentInfo.getMajorName());
|
||||
detailMap.put("classId", parseStringToLong(studentInfo.getClassId()));
|
||||
detailMap.put("className", studentInfo.getClassName());
|
||||
|
||||
log.debug("获取学生详细信息成功,学生ID: {}, 学院ID: {}, 专业ID: {}, 班级ID: {}",
|
||||
studentId, detailMap.get("collegeId"), detailMap.get("majorId"), detailMap.get("classId"));
|
||||
|
||||
return detailMap;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("查询学生详细信息失败,学生ID: {}", studentId, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全地将String类型转换为Long类型
|
||||
*
|
||||
* @param str 字符串值
|
||||
* @return Long值,转换失败时返回null
|
||||
*/
|
||||
private Long parseStringToLong(String str) {
|
||||
if (StringUtils.isBlank(str)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return Long.valueOf(str.trim());
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("字符串转Long失败,原值: {}", str);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean updateCompleteData(XgDormHygieneCheckCompleteBo bo) {
|
||||
try {
|
||||
// 1. 更新主表数据
|
||||
XgDormHygieneCheck update = MapstructUtils.convert(bo, XgDormHygieneCheck.class);
|
||||
validEntityBeforeSave(update);
|
||||
boolean flag = baseMapper.updateById(update) > 0;
|
||||
log.info("更新宿舍卫生检查主表数据: {}", update);
|
||||
|
||||
if (!flag) {
|
||||
log.error("更新宿舍卫生检查主表数据失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
Long hygieneCheckId = update.getId();
|
||||
|
||||
// 2. 更新学生评分数据 - 先删除旧数据,再插入新数据
|
||||
LambdaQueryWrapper<XgDormHygieneStudentScore> scoreWrapper = Wrappers.lambdaQuery();
|
||||
scoreWrapper.eq(XgDormHygieneStudentScore::getHygieneCheckId, hygieneCheckId);
|
||||
studentScoreMapper.delete(scoreWrapper);
|
||||
log.info("删除旧的学生评分数据,检查ID: {}", hygieneCheckId);
|
||||
|
||||
if (bo.getStudentScores() != null && !bo.getStudentScores().isEmpty()) {
|
||||
for (XgDormHygieneStudentScoreBo studentScoreBo : bo.getStudentScores()) {
|
||||
XgDormHygieneStudentScore studentScore = MapstructUtils.convert(studentScoreBo,
|
||||
XgDormHygieneStudentScore.class);
|
||||
studentScore.setHygieneCheckId(hygieneCheckId);
|
||||
studentScore.setId(null); // 确保是新插入
|
||||
|
||||
// 根据学生ID查询学生完整信息,补充学院、专业、班级信息
|
||||
if (studentScoreBo.getStudentId() != null) {
|
||||
try {
|
||||
var studentInfo = xgStudentMsgService.queryById(studentScoreBo.getStudentId());
|
||||
if (studentInfo != null) {
|
||||
// 补充学院信息
|
||||
if (studentScore.getCollegeId() == null
|
||||
&& StringUtils.isNotBlank(studentInfo.getCollegeId())) {
|
||||
try {
|
||||
studentScore.setCollegeId(Long.valueOf(studentInfo.getCollegeId()));
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("学院ID转换失败,学生ID: {}, 学院ID: {}", studentScoreBo.getStudentId(),
|
||||
studentInfo.getCollegeId());
|
||||
}
|
||||
}
|
||||
if (StringUtils.isBlank(studentScore.getCollegeName())) {
|
||||
studentScore.setCollegeName(studentInfo.getCollegeName());
|
||||
}
|
||||
|
||||
// 补充专业信息
|
||||
if (studentScore.getMajorId() == null
|
||||
&& StringUtils.isNotBlank(studentInfo.getMajorId())) {
|
||||
try {
|
||||
studentScore.setMajorId(Long.valueOf(studentInfo.getMajorId()));
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("专业ID转换失败,学生ID: {}, 专业ID: {}", studentScoreBo.getStudentId(),
|
||||
studentInfo.getMajorId());
|
||||
}
|
||||
}
|
||||
if (StringUtils.isBlank(studentScore.getMajorName())) {
|
||||
studentScore.setMajorName(studentInfo.getMajorName());
|
||||
}
|
||||
|
||||
// 补充班级信息
|
||||
if (studentScore.getClassId() == null
|
||||
&& StringUtils.isNotBlank(studentInfo.getClassId())) {
|
||||
try {
|
||||
studentScore.setClassId(Long.valueOf(studentInfo.getClassId()));
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("班级ID转换失败,学生ID: {}, 班级ID: {}", studentScoreBo.getStudentId(),
|
||||
studentInfo.getClassId());
|
||||
}
|
||||
}
|
||||
if (StringUtils.isBlank(studentScore.getClassName())) {
|
||||
studentScore.setClassName(studentInfo.getClassName());
|
||||
}
|
||||
|
||||
log.info("补充学生信息 - 学生ID: {}, 学院: {}, 专业: {}, 班级: {}",
|
||||
studentScoreBo.getStudentId(),
|
||||
studentInfo.getCollegeName(),
|
||||
studentInfo.getMajorName(),
|
||||
studentInfo.getClassName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("查询学生信息失败,学生ID: {}, 错误: {}", studentScoreBo.getStudentId(), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
log.info("保存学生评分数据: {}", studentScore);
|
||||
studentScoreMapper.insert(studentScore);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 处理违纪记录数据 - 完整的增删改逻辑
|
||||
handleViolationRecords(hygieneCheckId, bo.getViolationData());
|
||||
|
||||
log.info("完整更新宿舍卫生检查数据成功,检查ID: {}", hygieneCheckId);
|
||||
return true;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("更新宿舍卫生检查数据失败", e);
|
||||
throw new RuntimeException("更新宿舍卫生检查数据失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理违纪记录数据 - 完整的增删改逻辑
|
||||
*
|
||||
* @param hygieneCheckId 卫生检查ID
|
||||
* @param newViolationData 新的违纪记录数据列表
|
||||
*/
|
||||
private void handleViolationRecords(Long hygieneCheckId, List<XgViolationDataBo> newViolationData) {
|
||||
try {
|
||||
// 1. 查询数据库中现有的违纪记录
|
||||
List<XgHygieneCheckViolationVo> existingViolations = getViolationsByHygieneCheckId(hygieneCheckId);
|
||||
log.info("数据库中现有违纪记录数量: {}", existingViolations.size());
|
||||
|
||||
// 2. 收集现有记录的违纪记录ID(disciplineRecordId)
|
||||
Set<Long> existingDisciplineIds = existingViolations.stream()
|
||||
.map(XgHygieneCheckViolationVo::getDisciplineRecordId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
log.info("现有违纪记录ID集合: {}", existingDisciplineIds);
|
||||
|
||||
// 3. 收集新数据中的违纪记录ID(优先使用disciplineRecordId字段,兼容旧版本的id字段)
|
||||
Set<Long> newDisciplineIds = new HashSet<>();
|
||||
if (newViolationData != null) {
|
||||
newDisciplineIds = newViolationData.stream()
|
||||
.map(violationBo -> {
|
||||
// 优先使用disciplineRecordId字段,如果为空则使用id字段(向后兼容)
|
||||
return violationBo.getDisciplineRecordId() != null
|
||||
? violationBo.getDisciplineRecordId()
|
||||
: violationBo.getId();
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
log.info("新数据中的违纪记录ID集合: {}", newDisciplineIds);
|
||||
|
||||
// 4. 找出需要删除的记录(在数据库中存在,但不在新数据中)
|
||||
Set<Long> toDeleteIds = new HashSet<>(existingDisciplineIds);
|
||||
toDeleteIds.removeAll(newDisciplineIds);
|
||||
log.info("需要删除的违纪记录ID集合: {}", toDeleteIds);
|
||||
|
||||
// 5. 删除不再存在的记录
|
||||
for (Long deleteId : toDeleteIds) {
|
||||
deleteViolationRecord(hygieneCheckId, deleteId);
|
||||
}
|
||||
|
||||
// 6. 处理新数据中的记录(新增或更新)
|
||||
if (newViolationData != null && !newViolationData.isEmpty()) {
|
||||
for (XgViolationDataBo violationBo : newViolationData) {
|
||||
try {
|
||||
log.info("处理违纪记录数据: {}", violationBo);
|
||||
|
||||
// 如果是已存在的违纪记录(有违纪记录ID且在现有记录中),更新统一表中的记录
|
||||
Long currentDisciplineRecordId = violationBo.getDisciplineRecordId() != null
|
||||
? violationBo.getDisciplineRecordId()
|
||||
: violationBo.getId();
|
||||
if (currentDisciplineRecordId != null
|
||||
&& existingDisciplineIds.contains(currentDisciplineRecordId)) {
|
||||
log.info("更新现有违纪记录,违纪记录ID: {}", currentDisciplineRecordId);
|
||||
updateDisciplineRecord(violationBo);
|
||||
} else {
|
||||
// 新增违纪记录
|
||||
log.info("新增违纪记录,学生ID: {}", violationBo.getStudentId());
|
||||
Long disciplineRecordId = createDisciplineRecord(violationBo);
|
||||
|
||||
if (disciplineRecordId != null && violationService != null) {
|
||||
XgHygieneCheckViolationBo relationBo = new XgHygieneCheckViolationBo();
|
||||
relationBo.setHygieneCheckId(hygieneCheckId);
|
||||
relationBo.setDisciplineRecordId(disciplineRecordId);
|
||||
relationBo.setStudentId(violationBo.getStudentId());
|
||||
relationBo.setStudentNo(violationBo.getStudentNo());
|
||||
relationBo.setStudentName(violationBo.getStudentName());
|
||||
relationBo.setDisciplineTypeId(violationBo.getDisciplineTypeId());
|
||||
relationBo.setDisciplineTypeName(violationBo.getDisciplineTypeName());
|
||||
relationBo.setViolationSource("1"); // 1-宿舍卫生检查
|
||||
relationBo.setStatus("1"); // 1-生效
|
||||
|
||||
boolean relationResult = violationService.insertByBo(relationBo);
|
||||
if (!relationResult) {
|
||||
log.warn("创建卫生检查违纪关联记录失败,学生ID: {}", violationBo.getStudentId());
|
||||
} else {
|
||||
log.info("创建卫生检查违纪关联记录成功,学生ID: {},违纪记录ID: {}",
|
||||
violationBo.getStudentId(), disciplineRecordId);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("处理违纪数据失败,学生ID: {}, 错误: {}", violationBo.getStudentId(), e.getMessage(), e);
|
||||
throw new RuntimeException(
|
||||
"处理违纪数据失败,学生ID: " + violationBo.getStudentId() + ", 错误: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.info("违纪记录处理完成,卫生检查ID: {}", hygieneCheckId);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("处理违纪记录数据失败,卫生检查ID: {}, 错误: {}", hygieneCheckId, e.getMessage(), e);
|
||||
throw new RuntimeException("处理违纪记录数据失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除违纪记录(同时删除关联表和统一表中的记录)
|
||||
*
|
||||
* @param hygieneCheckId 卫生检查ID
|
||||
* @param disciplineRecordId 违纪记录ID
|
||||
*/
|
||||
private void deleteViolationRecord(Long hygieneCheckId, Long disciplineRecordId) {
|
||||
try {
|
||||
log.info("开始逻辑删除违纪记录,卫生检查ID: {}, 违纪记录ID: {}", hygieneCheckId, disciplineRecordId);
|
||||
|
||||
// 1. 逻辑删除关联表中的记录 (xg_hygiene_check_violation)
|
||||
if (violationMapper != null) {
|
||||
LambdaQueryWrapper<XgHygieneCheckViolation> wrapper = Wrappers.lambdaQuery();
|
||||
wrapper.eq(XgHygieneCheckViolation::getHygieneCheckId, hygieneCheckId)
|
||||
.eq(XgHygieneCheckViolation::getDisciplineRecordId, disciplineRecordId);
|
||||
|
||||
// 使用逻辑删除
|
||||
int deleteCount = violationMapper.delete(wrapper);
|
||||
if (deleteCount > 0) {
|
||||
log.info("逻辑删除卫生检查违纪关联记录成功,违纪记录ID: {}, 删除数量: {}", disciplineRecordId, deleteCount);
|
||||
} else {
|
||||
log.warn("逻辑删除卫生检查违纪关联记录失败,违纪记录ID: {}", disciplineRecordId);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 逻辑删除统一表中的记录 (xskh_discipline_record)
|
||||
deleteDisciplineRecord(disciplineRecordId);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("逻辑删除违纪记录失败,违纪记录ID: {}, 错误: {}", disciplineRecordId, e.getMessage(), e);
|
||||
throw new RuntimeException("逻辑删除违纪记录失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 逻辑删除统一表中的违纪记录
|
||||
*
|
||||
* @param disciplineRecordId 违纪记录ID
|
||||
*/
|
||||
private void deleteDisciplineRecord(Long disciplineRecordId) {
|
||||
try {
|
||||
// 通过接口类型动态获取IXskhDisciplineRecordService,避免硬依赖
|
||||
Class<?> serviceInterface = Class.forName("org.dromara.xskh.service.IXskhDisciplineRecordService");
|
||||
Object disciplineRecordService = applicationContext.getBean(serviceInterface);
|
||||
|
||||
if (disciplineRecordService != null) {
|
||||
// 使用deleteWithValidByIds方法进行逻辑删除
|
||||
var deleteMethod = disciplineRecordService.getClass().getMethod("deleteWithValidByIds",
|
||||
Collection.class, Boolean.class);
|
||||
Boolean result = (Boolean) deleteMethod.invoke(disciplineRecordService,
|
||||
Collections.singletonList(disciplineRecordId), false);
|
||||
|
||||
if (result) {
|
||||
log.info("逻辑删除统一违纪记录成功,违纪记录ID: {}", disciplineRecordId);
|
||||
} else {
|
||||
log.error("逻辑删除统一违纪记录失败,违纪记录ID: {}", disciplineRecordId);
|
||||
}
|
||||
} else {
|
||||
log.error("未找到违纪记录服务,无法删除统一违纪记录,违纪记录ID: {}", disciplineRecordId);
|
||||
}
|
||||
|
||||
} catch (ClassNotFoundException e) {
|
||||
log.warn("学生考核管理模块(xskh)未启用,跳过统一违纪记录删除");
|
||||
} catch (Exception e) {
|
||||
log.error("逻辑删除统一违纪记录失败,违纪记录ID: {}, 错误: {}", disciplineRecordId, e.getMessage(), e);
|
||||
throw new RuntimeException("逻辑删除统一违纪记录失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新学生违纪记录
|
||||
*
|
||||
* @param violationBo 违纪数据
|
||||
*/
|
||||
private void updateDisciplineRecord(XgViolationDataBo violationBo) {
|
||||
try {
|
||||
// 通过接口类型动态获取IXskhDisciplineRecordService,避免硬依赖
|
||||
Class<?> serviceInterface = Class.forName("org.dromara.xskh.service.IXskhDisciplineRecordService");
|
||||
Object disciplineRecordService = applicationContext.getBean(serviceInterface);
|
||||
|
||||
if (disciplineRecordService != null) {
|
||||
// 创建XskhDisciplineRecordBo对象
|
||||
Object disciplineRecordBo = createDisciplineRecordBo(violationBo);
|
||||
if (disciplineRecordBo != null) {
|
||||
// 设置ID用于更新
|
||||
setFieldValue(disciplineRecordBo, "id", violationBo.getId());
|
||||
|
||||
// 反射调用updateByBo方法
|
||||
Class<?> disciplineRecordBoClass = Class
|
||||
.forName("org.dromara.xskh.domain.bo.XskhDisciplineRecordBo");
|
||||
var updateMethod = disciplineRecordService.getClass().getMethod("updateByBo",
|
||||
disciplineRecordBoClass);
|
||||
Boolean result = (Boolean) updateMethod.invoke(disciplineRecordService, disciplineRecordBo);
|
||||
|
||||
if (result) {
|
||||
log.info("更新学生违纪记录成功,学生ID: {}, 违纪记录ID: {}",
|
||||
violationBo.getStudentId(), violationBo.getId());
|
||||
} else {
|
||||
log.warn("更新学生违纪记录失败,学生ID: {}", violationBo.getStudentId());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
log.warn("学生考核管理模块(xskh)未启用,跳过违纪记录更新");
|
||||
} catch (Exception e) {
|
||||
log.error("更新学生违纪记录失败: {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据卫生检查ID查询相关的违纪记录(包含详情)
|
||||
*
|
||||
* @param hygieneCheckId 卫生检查ID
|
||||
* @return 违纪记录列表(包含详情)
|
||||
*/
|
||||
@Override
|
||||
public List<XgHygieneCheckViolationVo> getViolationsByHygieneCheckId(Long hygieneCheckId) {
|
||||
if (hygieneCheckId == null) {
|
||||
log.warn("卫生检查ID为空,无法查询违纪记录");
|
||||
return List.of();
|
||||
}
|
||||
|
||||
try {
|
||||
// 使用自定义查询方法,关联查询违纪详情
|
||||
List<XgHygieneCheckViolationVo> violations = violationMapper
|
||||
.selectViolationsByHygieneCheckId(hygieneCheckId);
|
||||
|
||||
log.info("卫生检查ID: {} 查询到 {} 条违纪记录(包含详情)", hygieneCheckId, violations.size());
|
||||
return violations;
|
||||
} catch (Exception e) {
|
||||
log.error("查询卫生检查违纪记录失败,检查ID: {}, 错误: {}", hygieneCheckId, e.getMessage(), e);
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+284
-2
@@ -26,6 +26,24 @@ import java.util.Map;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
||||
import org.apache.poi.xssf.usermodel.XSSFRow;
|
||||
import org.apache.poi.xssf.usermodel.XSSFCell;
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.Font;
|
||||
import org.apache.poi.ss.usermodel.BorderStyle;
|
||||
import org.apache.poi.ss.usermodel.HorizontalAlignment;
|
||||
import org.apache.poi.ss.usermodel.VerticalAlignment;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.dromara.xg.domain.XgDormBed;
|
||||
import org.dromara.xg.mapper.XgDormBedMapper;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* 宿舍房间信息Service业务层处理
|
||||
@@ -41,6 +59,7 @@ public class XgDormRoomServiceImpl implements IXgDormRoomService {
|
||||
private final XgDormRoomMapper baseMapper;
|
||||
private final XgDormBedStudentMapper xgDormBedStudentMapper;
|
||||
private final XgSysDeptMapper xgSysDeptMapper;
|
||||
private final XgDormBedMapper xgDormBedMapper;
|
||||
|
||||
/**
|
||||
* 查询宿舍房间信息
|
||||
@@ -144,8 +163,9 @@ public class XgDormRoomServiceImpl implements IXgDormRoomService {
|
||||
private LambdaQueryWrapper<XgDormRoom> buildQueryWrapper(XgDormRoomBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<XgDormRoom> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByAsc(XgDormRoom::getFloorNum); // 优先按楼层排序
|
||||
lqw.orderByAsc(XgDormRoom::getRoomName); // 其次按房间名称排序
|
||||
lqw.orderByAsc(XgDormRoom::getFloorNum); // 第一优先级:按楼层升序
|
||||
lqw.orderByAsc(XgDormRoom::getSort); // 第二优先级:按排序号升序
|
||||
lqw.orderByAsc(XgDormRoom::getRoomName); // 第三优先级:按房间名称升序
|
||||
lqw.like(StringUtils.isNotBlank(bo.getRoomCode()), XgDormRoom::getRoomCode, bo.getRoomCode());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getRoomName()), XgDormRoom::getRoomName, bo.getRoomName());
|
||||
lqw.eq(bo.getBuildingId() != null, XgDormRoom::getBuildingId, bo.getBuildingId());
|
||||
@@ -154,6 +174,7 @@ public class XgDormRoomServiceImpl implements IXgDormRoomService {
|
||||
lqw.eq(bo.getActualBeds() != null, XgDormRoom::getActualBeds, bo.getActualBeds());
|
||||
lqw.eq(bo.getRoomArea() != null, XgDormRoom::getRoomArea, bo.getRoomArea());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getRoomStatus()), XgDormRoom::getRoomStatus, bo.getRoomStatus());
|
||||
lqw.eq(bo.getSort() != null, XgDormRoom::getSort, bo.getSort());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getDeleted()), XgDormRoom::getDeleted, bo.getDeleted());
|
||||
return lqw;
|
||||
}
|
||||
@@ -310,4 +331,265 @@ public class XgDormRoomServiceImpl implements IXgDormRoomService {
|
||||
return Set.of();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出住宿清单(宿舍卡片式布局)
|
||||
*
|
||||
* @param params 导出参数
|
||||
* @param response HTTP响应对象
|
||||
*/
|
||||
@Override
|
||||
public void exportAccommodationList(Map<String, Object> params, HttpServletResponse response) {
|
||||
try {
|
||||
// 解析参数
|
||||
Long buildingId = Long.valueOf(params.get("buildingId").toString());
|
||||
String buildingName = params.get("buildingName").toString();
|
||||
String buildingType = params.get("buildingType").toString();
|
||||
String buildingTypeText = "1".equals(buildingType) ? "男生楼" : "女生楼";
|
||||
|
||||
// 解析JSON字符串
|
||||
String accommodationDataJson = params.get("accommodationData").toString();
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> accommodationData = objectMapper.readValue(accommodationDataJson, Map.class);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> buildingInfo = (Map<String, Object>) accommodationData.get("buildingInfo");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> floorDataList = (List<Map<String, Object>>) accommodationData.get("floorData");
|
||||
|
||||
// 创建Excel工作簿
|
||||
try (XSSFWorkbook workbook = new XSSFWorkbook()) {
|
||||
XSSFSheet sheet = workbook.createSheet(buildingName + "住宿清单");
|
||||
|
||||
// 创建样式
|
||||
CellStyle titleStyle = createTitleStyle(workbook);
|
||||
CellStyle headerStyle = createHeaderStyle(workbook);
|
||||
CellStyle dataStyle = createDataStyle(workbook);
|
||||
CellStyle roomNameStyle = createRoomNameStyle(workbook);
|
||||
|
||||
int currentRow = 0;
|
||||
|
||||
// 添加标题
|
||||
XSSFRow titleRow = sheet.createRow(currentRow++);
|
||||
XSSFCell titleCell = titleRow.createCell(0);
|
||||
titleCell.setCellValue(buildingName + " " + buildingTypeText + " 住宿清单");
|
||||
titleCell.setCellStyle(titleStyle);
|
||||
sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 19)); // 合并20列
|
||||
currentRow++; // 空行
|
||||
|
||||
// 处理每个楼层
|
||||
for (Map<String, Object> floorData : floorDataList) {
|
||||
Integer floorNum = (Integer) floorData.get("floorNum");
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> rooms = (List<Map<String, Object>>) floorData.get("rooms");
|
||||
|
||||
if (rooms == null || rooms.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 添加楼层标题
|
||||
XSSFRow floorRow = sheet.createRow(currentRow++);
|
||||
XSSFCell floorCell = floorRow.createCell(0);
|
||||
floorCell.setCellValue("第" + floorNum + "层");
|
||||
floorCell.setCellStyle(headerStyle);
|
||||
sheet.addMergedRegion(new CellRangeAddress(currentRow - 1, currentRow - 1, 0, 19));
|
||||
currentRow++; // 空行
|
||||
|
||||
// 按4个宿舍一行进行分组处理
|
||||
for (int i = 0; i < rooms.size(); i += 4) {
|
||||
int endIndex = Math.min(i + 4, rooms.size());
|
||||
List<Map<String, Object>> roomGroup = rooms.subList(i, endIndex);
|
||||
|
||||
// 处理当前组的宿舍
|
||||
currentRow = processRoomGroup(sheet, roomGroup, currentRow, roomNameStyle, headerStyle,
|
||||
dataStyle);
|
||||
currentRow += 2; // 组间空行
|
||||
}
|
||||
}
|
||||
|
||||
// 设置列宽 (4个宿舍,每个宿舍4列,宿舍间3个空列,共19列)
|
||||
for (int i = 0; i < 20; i++) {
|
||||
sheet.setColumnWidth(i, 15 * 256); // 15个字符宽度
|
||||
}
|
||||
|
||||
// 设置响应头
|
||||
String fileName = buildingName + "_住宿清单_" + System.currentTimeMillis() + ".xlsx";
|
||||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
response.setHeader("Content-Disposition",
|
||||
"attachment; filename=\"" + new String(fileName.getBytes("UTF-8"), "ISO-8859-1") + "\"");
|
||||
|
||||
// 输出Excel文件
|
||||
try (OutputStream outputStream = response.getOutputStream()) {
|
||||
workbook.write(outputStream);
|
||||
outputStream.flush();
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("导出住宿清单失败", e);
|
||||
throw new RuntimeException("导出住宿清单失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理一组宿舍(最多4个)
|
||||
*/
|
||||
private int processRoomGroup(XSSFSheet sheet, List<Map<String, Object>> roomGroup, int startRow,
|
||||
CellStyle roomNameStyle, CellStyle headerStyle, CellStyle dataStyle) {
|
||||
int currentRow = startRow;
|
||||
|
||||
// 宿舍名称行
|
||||
XSSFRow roomNameRow = sheet.createRow(currentRow++);
|
||||
for (int i = 0; i < roomGroup.size(); i++) {
|
||||
Map<String, Object> room = roomGroup.get(i);
|
||||
String roomName = (String) room.get("roomName");
|
||||
|
||||
// 每个宿舍占4列,宿舍之间增加1列间隔 (i * 5)
|
||||
int startCol = i * 5;
|
||||
|
||||
// 为整个合并区域的所有单元格创建并设置样式
|
||||
for (int col = startCol; col <= startCol + 3; col++) {
|
||||
XSSFCell cell = roomNameRow.createCell(col);
|
||||
cell.setCellStyle(roomNameStyle);
|
||||
if (col == startCol) {
|
||||
cell.setCellValue(roomName); // 只在第一个单元格设置值
|
||||
}
|
||||
}
|
||||
|
||||
sheet.addMergedRegion(new CellRangeAddress(currentRow - 1, currentRow - 1, startCol, startCol + 3));
|
||||
}
|
||||
|
||||
// 表头行
|
||||
XSSFRow headerRow = sheet.createRow(currentRow++);
|
||||
String[] headers = { "床位", "姓名", "班级", "备注" };
|
||||
for (int i = 0; i < roomGroup.size(); i++) {
|
||||
for (int j = 0; j < headers.length; j++) {
|
||||
// 每个宿舍占4列,宿舍之间增加1列间隔 (i * 5)
|
||||
XSSFCell headerCell = headerRow.createCell(i * 5 + j);
|
||||
headerCell.setCellValue(headers[j]);
|
||||
headerCell.setCellStyle(headerStyle);
|
||||
}
|
||||
}
|
||||
|
||||
// 计算最大床位数
|
||||
int maxBeds = roomGroup.stream()
|
||||
.mapToInt(room -> {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> beds = (List<Map<String, Object>>) room.get("beds");
|
||||
return beds != null ? beds.size() : 0;
|
||||
})
|
||||
.max()
|
||||
.orElse(0);
|
||||
|
||||
// 床位数据行
|
||||
for (int bedIndex = 0; bedIndex < maxBeds; bedIndex++) {
|
||||
XSSFRow dataRow = sheet.createRow(currentRow++);
|
||||
|
||||
for (int roomIndex = 0; roomIndex < roomGroup.size(); roomIndex++) {
|
||||
Map<String, Object> room = roomGroup.get(roomIndex);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> beds = (List<Map<String, Object>>) room.get("beds");
|
||||
|
||||
if (beds != null && bedIndex < beds.size()) {
|
||||
Map<String, Object> bed = beds.get(bedIndex);
|
||||
|
||||
// 每个宿舍占4列,宿舍之间增加1列间隔 (roomIndex * 5)
|
||||
// 床位
|
||||
XSSFCell bedNameCell = dataRow.createCell(roomIndex * 5);
|
||||
bedNameCell.setCellValue((String) bed.get("bedName"));
|
||||
bedNameCell.setCellStyle(dataStyle);
|
||||
|
||||
// 姓名
|
||||
XSSFCell studentNameCell = dataRow.createCell(roomIndex * 5 + 1);
|
||||
studentNameCell.setCellValue((String) bed.get("studentName"));
|
||||
studentNameCell.setCellStyle(dataStyle);
|
||||
|
||||
// 班级
|
||||
XSSFCell classNameCell = dataRow.createCell(roomIndex * 5 + 2);
|
||||
classNameCell.setCellValue((String) bed.get("className"));
|
||||
classNameCell.setCellStyle(dataStyle);
|
||||
|
||||
// 备注
|
||||
XSSFCell remarkCell = dataRow.createCell(roomIndex * 5 + 3);
|
||||
remarkCell.setCellValue((String) bed.get("bedRemark"));
|
||||
remarkCell.setCellStyle(dataStyle);
|
||||
} else {
|
||||
// 空床位
|
||||
for (int j = 0; j < 4; j++) {
|
||||
XSSFCell emptyCell = dataRow.createCell(roomIndex * 5 + j);
|
||||
emptyCell.setCellValue("");
|
||||
emptyCell.setCellStyle(dataStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return currentRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建标题样式
|
||||
*/
|
||||
private CellStyle createTitleStyle(XSSFWorkbook workbook) {
|
||||
CellStyle style = workbook.createCellStyle();
|
||||
Font font = workbook.createFont();
|
||||
font.setBold(true);
|
||||
font.setFontHeightInPoints((short) 16);
|
||||
style.setFont(font);
|
||||
style.setAlignment(HorizontalAlignment.CENTER);
|
||||
style.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
return style;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建表头样式
|
||||
*/
|
||||
private CellStyle createHeaderStyle(XSSFWorkbook workbook) {
|
||||
CellStyle style = workbook.createCellStyle();
|
||||
Font font = workbook.createFont();
|
||||
font.setBold(true);
|
||||
font.setFontHeightInPoints((short) 12);
|
||||
style.setFont(font);
|
||||
style.setAlignment(HorizontalAlignment.CENTER);
|
||||
style.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
style.setBorderTop(BorderStyle.THIN);
|
||||
style.setBorderBottom(BorderStyle.THIN);
|
||||
style.setBorderLeft(BorderStyle.THIN);
|
||||
style.setBorderRight(BorderStyle.THIN);
|
||||
return style;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建数据样式
|
||||
*/
|
||||
private CellStyle createDataStyle(XSSFWorkbook workbook) {
|
||||
CellStyle style = workbook.createCellStyle();
|
||||
style.setAlignment(HorizontalAlignment.CENTER);
|
||||
style.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
style.setBorderTop(BorderStyle.THIN);
|
||||
style.setBorderBottom(BorderStyle.THIN);
|
||||
style.setBorderLeft(BorderStyle.THIN);
|
||||
style.setBorderRight(BorderStyle.THIN);
|
||||
return style;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建宿舍名称样式
|
||||
*/
|
||||
private CellStyle createRoomNameStyle(XSSFWorkbook workbook) {
|
||||
CellStyle style = workbook.createCellStyle();
|
||||
Font font = workbook.createFont();
|
||||
font.setBold(true);
|
||||
font.setFontHeightInPoints((short) 14);
|
||||
style.setFont(font);
|
||||
style.setAlignment(HorizontalAlignment.CENTER);
|
||||
style.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
style.setBorderTop(BorderStyle.THIN);
|
||||
style.setBorderBottom(BorderStyle.THIN);
|
||||
style.setBorderLeft(BorderStyle.THIN);
|
||||
style.setBorderRight(BorderStyle.THIN);
|
||||
return style;
|
||||
}
|
||||
}
|
||||
+552
-11
@@ -21,6 +21,16 @@ import org.dromara.xg.service.IXgHolidayStayService;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Calendar;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
/**
|
||||
* 假期留宿管理Service业务层处理
|
||||
@@ -90,15 +100,42 @@ public class XgHolidayStayServiceImpl implements IXgHolidayStayService {
|
||||
lqw.like(StringUtils.isNotBlank(bo.getCampusName()), XgHolidayStay::getCampusName, bo.getCampusName());
|
||||
lqw.eq(bo.getAreaId() != null, XgHolidayStay::getAreaId, bo.getAreaId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getAreaName()), XgHolidayStay::getAreaName, bo.getAreaName());
|
||||
lqw.eq(bo.getBuildingId() != null, XgHolidayStay::getBuildingId, bo.getBuildingId());
|
||||
|
||||
// 楼栋ID过滤逻辑:支持单个楼栋ID和多个楼栋ID的查询
|
||||
if (bo.getBuildingId() != null) {
|
||||
// 单个楼栋ID查询
|
||||
lqw.eq(XgHolidayStay::getBuildingId, bo.getBuildingId());
|
||||
} else if (params != null && params.containsKey("buildingIds")) {
|
||||
// 多个楼栋ID查询,从params中获取buildingIds(逗号分隔的字符串)
|
||||
String buildingIdsStr = (String) params.get("buildingIds");
|
||||
if (StringUtils.isNotBlank(buildingIdsStr)) {
|
||||
String[] buildingIdArray = buildingIdsStr.split(",");
|
||||
if (buildingIdArray.length > 0) {
|
||||
List<Long> buildingIds = new ArrayList<>();
|
||||
for (String buildingIdStr : buildingIdArray) {
|
||||
try {
|
||||
Long buildingId = Long.parseLong(buildingIdStr.trim());
|
||||
buildingIds.add(buildingId);
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("无效的楼栋ID: {}", buildingIdStr);
|
||||
}
|
||||
}
|
||||
if (!buildingIds.isEmpty()) {
|
||||
lqw.in(XgHolidayStay::getBuildingId, buildingIds);
|
||||
log.debug("添加多楼栋ID过滤条件: {}", buildingIds);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lqw.like(StringUtils.isNotBlank(bo.getBuildingName()), XgHolidayStay::getBuildingName, bo.getBuildingName());
|
||||
lqw.eq(bo.getRoomId() != null, XgHolidayStay::getRoomId, bo.getRoomId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getRoomName()), XgHolidayStay::getRoomName, bo.getRoomName());
|
||||
lqw.eq(bo.getBedId() != null, XgHolidayStay::getBedId, bo.getBedId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getBedName()), XgHolidayStay::getBedName, bo.getBedName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getHolidayType()), XgHolidayStay::getHolidayType, bo.getHolidayType());
|
||||
lqw.ge(bo.getApplyStartDate() != null, XgHolidayStay::getApplyStartDate, bo.getApplyStartDate());
|
||||
lqw.le(bo.getApplyEndDate() != null, XgHolidayStay::getApplyEndDate, bo.getApplyEndDate());
|
||||
lqw.eq(bo.getApplyStartDate() != null, XgHolidayStay::getApplyStartDate, bo.getApplyStartDate());
|
||||
lqw.eq(bo.getApplyEndDate() != null, XgHolidayStay::getApplyEndDate, bo.getApplyEndDate());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getStayReason()), XgHolidayStay::getStayReason, bo.getStayReason());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getStayReasonType()), XgHolidayStay::getStayReasonType,
|
||||
bo.getStayReasonType());
|
||||
@@ -110,9 +147,12 @@ public class XgHolidayStayServiceImpl implements IXgHolidayStayService {
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getParentConsent()), XgHolidayStay::getParentConsent, bo.getParentConsent());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getAttachmentOssIds()), XgHolidayStay::getAttachmentOssIds,
|
||||
bo.getAttachmentOssIds());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getExtField1()), XgHolidayStay::getExtField1, bo.getExtField1());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getExtField2()), XgHolidayStay::getExtField2, bo.getExtField2());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getExtField3()), XgHolidayStay::getExtField3, bo.getExtField3());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getExtField1()), XgHolidayStay::getExtField1, bo.getExtField1());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getExtField2()), XgHolidayStay::getExtField2, bo.getExtField2());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getExtField3()), XgHolidayStay::getExtField3, bo.getExtField3());
|
||||
|
||||
// 添加创建人过滤条件 - 实现班主任权限控制,只能查看自己创建的数据
|
||||
lqw.eq(bo.getCreateBy() != null, XgHolidayStay::getCreateBy, bo.getCreateBy());
|
||||
|
||||
// 添加状态过滤逻辑
|
||||
addStatusFilter(lqw, bo);
|
||||
@@ -122,7 +162,7 @@ public class XgHolidayStayServiceImpl implements IXgHolidayStayService {
|
||||
|
||||
/**
|
||||
* 添加状态过滤条件
|
||||
*
|
||||
*
|
||||
* @param lqw 查询条件构造器
|
||||
* @param bo 查询参数对象
|
||||
*/
|
||||
@@ -134,17 +174,19 @@ public class XgHolidayStayServiceImpl implements IXgHolidayStayService {
|
||||
|
||||
if (StringUtils.isNotBlank(statusType) && StringUtils.isNotBlank(currentTime)) {
|
||||
if ("valid".equals(statusType)) {
|
||||
// 有效状态:结束时间 >= 当前时间 AND 结束时间不为空
|
||||
// 有效状态:当前时间还没有超过留宿结束时间(包括预约状态)
|
||||
// 条件:applyEndDate >= currentTime AND applyEndDate IS NOT NULL
|
||||
lqw.ge(XgHolidayStay::getApplyEndDate, currentTime)
|
||||
.isNotNull(XgHolidayStay::getApplyEndDate);
|
||||
log.debug("添加有效状态过滤条件: apply_end_date >= {} AND apply_end_date IS NOT NULL", currentTime);
|
||||
log.debug("添加有效状态过滤条件: apply_end_date >= {} AND end_date is not null", currentTime);
|
||||
} else if ("invalid".equals(statusType)) {
|
||||
// 失效状态:结束时间 < 当前时间 OR 结束时间为空
|
||||
// 失效状态:当前时间已超过留宿结束时间
|
||||
// 条件:applyEndDate < currentTime OR applyEndDate IS NULL
|
||||
lqw.and(wrapper -> wrapper
|
||||
.lt(XgHolidayStay::getApplyEndDate, currentTime)
|
||||
.or()
|
||||
.isNull(XgHolidayStay::getApplyEndDate));
|
||||
log.debug("添加失效状态过滤条件: apply_end_date < {} OR apply_end_date IS NULL", currentTime);
|
||||
log.debug("添加失效状态过滤条件: apply_end_date < {} OR end_date is null", currentTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -214,4 +256,503 @@ public class XgHolidayStayServiceImpl implements IXgHolidayStayService {
|
||||
Page<StudentOptionVo> result = baseMapper.selectStudentOptions(pageQuery.build(), bo);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询单人留宿有效数据
|
||||
* 获取所有有效的假期留宿数据,筛选出在同一时间段内该宿舍只有一个学生留宿的记录
|
||||
*
|
||||
* @return 单人留宿有效数据列表
|
||||
*/
|
||||
@Override
|
||||
public List<XgHolidayStayVo> querySinglePersonValidStay() {
|
||||
// 1. 获取所有有效的假期留宿数据
|
||||
XgHolidayStayBo bo = new XgHolidayStayBo();
|
||||
Map<String, Object> params = bo.getParams();
|
||||
if (params == null) {
|
||||
params = new HashMap<>();
|
||||
bo.setParams(params);
|
||||
}
|
||||
|
||||
// 设置查询有效状态的留宿数据
|
||||
String currentTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
|
||||
params.put("statusType", "valid");
|
||||
params.put("currentTime", currentTime);
|
||||
|
||||
List<XgHolidayStayVo> validStayList = queryList(bo);
|
||||
log.info("查询到有效的假期留宿数据总数: {}", validStayList.size());
|
||||
|
||||
if (validStayList.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 2. 按房间分组,筛选出单人留宿的数据
|
||||
List<XgHolidayStayVo> singlePersonStayList = new ArrayList<>();
|
||||
|
||||
// 按房间ID分组
|
||||
Map<Long, List<XgHolidayStayVo>> roomGroupMap = validStayList.stream()
|
||||
.filter(stay -> stay.getRoomId() != null)
|
||||
.collect(Collectors.groupingBy(XgHolidayStayVo::getRoomId));
|
||||
|
||||
log.info("按房间分组后,涉及房间数量: {}", roomGroupMap.size());
|
||||
|
||||
// 遍历每个房间的留宿数据
|
||||
for (Map.Entry<Long, List<XgHolidayStayVo>> entry : roomGroupMap.entrySet()) {
|
||||
Long roomId = entry.getKey();
|
||||
List<XgHolidayStayVo> roomStayList = entry.getValue();
|
||||
|
||||
log.debug("处理房间ID: {}, 该房间留宿人数: {}", roomId, roomStayList.size());
|
||||
|
||||
// 3. 对于每个房间,检查是否存在单人留宿的时间段
|
||||
List<XgHolidayStayVo> singlePersonInRoom = findSinglePersonPeriodsInRoom(roomStayList);
|
||||
singlePersonStayList.addAll(singlePersonInRoom);
|
||||
}
|
||||
|
||||
log.info("筛选出单人留宿有效数据总数: {}", singlePersonStayList.size());
|
||||
|
||||
// 按ID倒序排序(作为时间排序的替代)
|
||||
return singlePersonStayList.stream()
|
||||
.sorted((a, b) -> {
|
||||
if (a.getId() == null && b.getId() == null)
|
||||
return 0;
|
||||
if (a.getId() == null)
|
||||
return 1;
|
||||
if (b.getId() == null)
|
||||
return -1;
|
||||
return b.getId().compareTo(a.getId());
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查房间内是否存在单人留宿的时间段
|
||||
*
|
||||
* @param roomStayList 同一房间内的留宿数据列表
|
||||
* @return 单人留宿的数据列表
|
||||
*/
|
||||
private List<XgHolidayStayVo> findSinglePersonPeriodsInRoom(List<XgHolidayStayVo> roomStayList) {
|
||||
List<XgHolidayStayVo> singlePersonList = new ArrayList<>();
|
||||
|
||||
if (roomStayList == null || roomStayList.isEmpty()) {
|
||||
return singlePersonList;
|
||||
}
|
||||
|
||||
// 如果房间内只有一个人留宿,直接返回
|
||||
if (roomStayList.size() == 1) {
|
||||
singlePersonList.add(roomStayList.get(0));
|
||||
log.debug("房间 {} 只有一个人留宿: {}", roomStayList.get(0).getRoomName(), roomStayList.get(0).getStudentName());
|
||||
return singlePersonList;
|
||||
}
|
||||
|
||||
// 按学生分组,处理每个学生的多个留宿记录
|
||||
Map<Long, List<XgHolidayStayVo>> studentStaysMap = roomStayList.stream()
|
||||
.collect(Collectors.groupingBy(XgHolidayStayVo::getStudentId));
|
||||
|
||||
// 为每个学生创建时间段
|
||||
Map<Long, List<TimeSegment>> studentTimeSegments = new HashMap<>();
|
||||
for (Map.Entry<Long, List<XgHolidayStayVo>> entry : studentStaysMap.entrySet()) {
|
||||
Long studentId = entry.getKey();
|
||||
List<XgHolidayStayVo> stays = entry.getValue();
|
||||
|
||||
List<TimeSegment> segments = new ArrayList<>();
|
||||
for (XgHolidayStayVo stay : stays) {
|
||||
if (stay.getApplyStartDate() != null && stay.getApplyEndDate() != null) {
|
||||
segments.add(new TimeSegment(stay.getApplyStartDate(), stay.getApplyEndDate(), studentId, stay));
|
||||
}
|
||||
}
|
||||
|
||||
// 合并同一学生的重叠时间段
|
||||
List<TimeSegment> mergedSegments = mergeTimeSegments(segments);
|
||||
studentTimeSegments.put(studentId, mergedSegments);
|
||||
}
|
||||
|
||||
// 收集所有关键时间点
|
||||
Set<Date> keyTimePoints = new TreeSet<>();
|
||||
for (List<TimeSegment> segments : studentTimeSegments.values()) {
|
||||
for (TimeSegment segment : segments) {
|
||||
keyTimePoints.add(segment.getStartTime());
|
||||
keyTimePoints.add(segment.getEndTime());
|
||||
}
|
||||
}
|
||||
|
||||
List<Date> sortedTimePoints = new ArrayList<>(keyTimePoints);
|
||||
log.debug("房间 {} 关键时间点数量: {}", roomStayList.get(0).getRoomName(), sortedTimePoints.size());
|
||||
|
||||
// 分析每个时间段内的留宿人数
|
||||
for (int i = 0; i < sortedTimePoints.size() - 1; i++) {
|
||||
Date segmentStart = sortedTimePoints.get(i);
|
||||
Date segmentEnd = sortedTimePoints.get(i + 1);
|
||||
|
||||
// 找出在这个时间段内留宿的所有学生
|
||||
List<Long> studentsInSegment = new ArrayList<>();
|
||||
Map<Long, XgHolidayStayVo> studentStayMap = new HashMap<>();
|
||||
|
||||
for (Map.Entry<Long, List<TimeSegment>> entry : studentTimeSegments.entrySet()) {
|
||||
Long studentId = entry.getKey();
|
||||
List<TimeSegment> segments = entry.getValue();
|
||||
|
||||
for (TimeSegment segment : segments) {
|
||||
// 检查时间段是否重叠(注意边界条件)
|
||||
if (segment.getStartTime().compareTo(segmentEnd) < 0 &&
|
||||
segment.getEndTime().compareTo(segmentStart) > 0) {
|
||||
studentsInSegment.add(studentId);
|
||||
studentStayMap.put(studentId, segment.getOriginalStay());
|
||||
break; // 一个学生在同一时间段内只能有一个记录
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果只有一个学生,这是单人留宿时间段
|
||||
if (studentsInSegment.size() == 1) {
|
||||
Long singleStudentId = studentsInSegment.get(0);
|
||||
XgHolidayStayVo originalStay = studentStayMap.get(singleStudentId);
|
||||
|
||||
// 创建单人留宿记录
|
||||
XgHolidayStayVo singlePersonStay = createSinglePersonStayFromSegment(
|
||||
originalStay, segmentStart, segmentEnd);
|
||||
singlePersonList.add(singlePersonStay);
|
||||
|
||||
log.debug("找到单人留宿时间段: {} ({} - {}) 学生: {}",
|
||||
originalStay.getRoomName(),
|
||||
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(segmentStart),
|
||||
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(segmentEnd),
|
||||
originalStay.getStudentName());
|
||||
}
|
||||
}
|
||||
|
||||
// 合并同一学生的连续单人留宿时间段
|
||||
return mergeConsecutiveSinglePersonStays(singlePersonList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取两个日期之间的所有日期(包含起始和结束日期)
|
||||
*
|
||||
* @param startDate 开始日期
|
||||
* @param endDate 结束日期
|
||||
* @param dateFormat 日期格式化器
|
||||
* @return 日期字符串列表
|
||||
*/
|
||||
private List<String> getDatesBetween(Date startDate, Date endDate, SimpleDateFormat dateFormat) {
|
||||
List<String> dates = new ArrayList<>();
|
||||
|
||||
if (startDate == null || endDate == null) {
|
||||
return dates;
|
||||
}
|
||||
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(startDate);
|
||||
|
||||
// 只取日期部分,忽略时间
|
||||
calendar.set(Calendar.HOUR_OF_DAY, 0);
|
||||
calendar.set(Calendar.MINUTE, 0);
|
||||
calendar.set(Calendar.SECOND, 0);
|
||||
calendar.set(Calendar.MILLISECOND, 0);
|
||||
|
||||
Calendar endCalendar = Calendar.getInstance();
|
||||
endCalendar.setTime(endDate);
|
||||
endCalendar.set(Calendar.HOUR_OF_DAY, 0);
|
||||
endCalendar.set(Calendar.MINUTE, 0);
|
||||
endCalendar.set(Calendar.SECOND, 0);
|
||||
endCalendar.set(Calendar.MILLISECOND, 0);
|
||||
|
||||
// 生成日期列表
|
||||
while (!calendar.after(endCalendar)) {
|
||||
dates.add(dateFormat.format(calendar.getTime()));
|
||||
calendar.add(Calendar.DAY_OF_MONTH, 1);
|
||||
}
|
||||
|
||||
return dates;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建单人留宿记录,调整时间范围为单人留宿的日期范围
|
||||
*
|
||||
* @param originalStay 原始留宿记录
|
||||
* @param singlePersonDates 单人留宿的日期列表
|
||||
* @param dateFormat 日期格式化器
|
||||
* @return 调整后的单人留宿记录
|
||||
*/
|
||||
private XgHolidayStayVo createSinglePersonStayRecord(XgHolidayStayVo originalStay, List<String> singlePersonDates,
|
||||
SimpleDateFormat dateFormat) {
|
||||
if (singlePersonDates.isEmpty()) {
|
||||
return originalStay;
|
||||
}
|
||||
|
||||
try {
|
||||
// 排序日期列表
|
||||
singlePersonDates.sort(String::compareTo);
|
||||
|
||||
// 获取单人留宿的开始和结束日期
|
||||
String startDateStr = singlePersonDates.get(0);
|
||||
String endDateStr = singlePersonDates.get(singlePersonDates.size() - 1);
|
||||
|
||||
// 克隆原始记录
|
||||
XgHolidayStayVo singlePersonStay = new XgHolidayStayVo();
|
||||
BeanUtils.copyProperties(originalStay, singlePersonStay);
|
||||
|
||||
// 调整时间范围为单人留宿的日期范围
|
||||
Date adjustedStartDate = dateFormat.parse(startDateStr);
|
||||
Date adjustedEndDate = dateFormat.parse(endDateStr);
|
||||
|
||||
// 结束日期设置为当天的23:59:59
|
||||
Calendar endCalendar = Calendar.getInstance();
|
||||
endCalendar.setTime(adjustedEndDate);
|
||||
endCalendar.set(Calendar.HOUR_OF_DAY, 23);
|
||||
endCalendar.set(Calendar.MINUTE, 59);
|
||||
endCalendar.set(Calendar.SECOND, 59);
|
||||
adjustedEndDate = endCalendar.getTime();
|
||||
|
||||
singlePersonStay.setApplyStartDate(adjustedStartDate);
|
||||
singlePersonStay.setApplyEndDate(adjustedEndDate);
|
||||
|
||||
// 在备注中添加单人留宿信息
|
||||
String originalRemark = singlePersonStay.getRemark() == null ? "" : singlePersonStay.getRemark();
|
||||
String singlePersonInfo = String.format("【单人留宿】%s天(%s至%s)",
|
||||
singlePersonDates.size(), startDateStr, endDateStr);
|
||||
singlePersonStay
|
||||
.setRemark(originalRemark.isEmpty() ? singlePersonInfo : originalRemark + " " + singlePersonInfo);
|
||||
|
||||
log.debug("为学生 {} 创建单人留宿记录: {} 天 ({} - {})",
|
||||
singlePersonStay.getStudentName(), singlePersonDates.size(), startDateStr, endDateStr);
|
||||
|
||||
return singlePersonStay;
|
||||
} catch (Exception e) {
|
||||
log.error("创建单人留宿记录失败", e);
|
||||
return originalStay;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查两个留宿时间段是否重叠
|
||||
*
|
||||
* @param stay1 留宿记录1
|
||||
* @param stay2 留宿记录2
|
||||
* @return 是否重叠
|
||||
*/
|
||||
private boolean isTimeOverlap(XgHolidayStayVo stay1, XgHolidayStayVo stay2) {
|
||||
if (stay1.getApplyStartDate() == null || stay1.getApplyEndDate() == null ||
|
||||
stay2.getApplyStartDate() == null || stay2.getApplyEndDate() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Date start1 = stay1.getApplyStartDate();
|
||||
Date end1 = stay1.getApplyEndDate();
|
||||
Date start2 = stay2.getApplyStartDate();
|
||||
Date end2 = stay2.getApplyEndDate();
|
||||
|
||||
// 检查时间段是否重叠:两个时间段重叠当且仅当 start1 <= end2 && start2 <= end1
|
||||
boolean overlap = start1.compareTo(end2) <= 0 && start2.compareTo(end1) <= 0;
|
||||
|
||||
if (overlap) {
|
||||
log.debug("时间段重叠: {} ({} - {}) 与 {} ({} - {})",
|
||||
stay1.getStudentName(), start1, end1,
|
||||
stay2.getStudentName(), start2, end2);
|
||||
}
|
||||
|
||||
return overlap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并同一学生的重叠时间段
|
||||
*/
|
||||
private List<TimeSegment> mergeTimeSegments(List<TimeSegment> segments) {
|
||||
if (segments.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 按开始时间排序
|
||||
segments.sort(Comparator.comparing(TimeSegment::getStartTime));
|
||||
|
||||
List<TimeSegment> merged = new ArrayList<>();
|
||||
TimeSegment current = segments.get(0);
|
||||
|
||||
for (int i = 1; i < segments.size(); i++) {
|
||||
TimeSegment next = segments.get(i);
|
||||
|
||||
// 如果时间段重叠或相邻,合并它们
|
||||
if (current.getEndTime().compareTo(next.getStartTime()) >= 0) {
|
||||
// 扩展当前时间段
|
||||
if (next.getEndTime().compareTo(current.getEndTime()) > 0) {
|
||||
current = new TimeSegment(
|
||||
current.getStartTime(),
|
||||
next.getEndTime(),
|
||||
current.getStudentId(),
|
||||
current.getOriginalStay()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// 不重叠,添加当前时间段到结果中
|
||||
merged.add(current);
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
|
||||
// 添加最后一个时间段
|
||||
merged.add(current);
|
||||
return merged;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从时间段创建单人留宿记录
|
||||
*/
|
||||
private XgHolidayStayVo createSinglePersonStayFromSegment(XgHolidayStayVo template, Date startTime, Date endTime) {
|
||||
XgHolidayStayVo singlePersonStay = new XgHolidayStayVo();
|
||||
|
||||
// 复制基本信息
|
||||
BeanUtils.copyProperties(template, singlePersonStay);
|
||||
|
||||
// 设置ID为null,表示这是计算出来的记录
|
||||
singlePersonStay.setId(null);
|
||||
|
||||
// 设置单人留宿的时间段
|
||||
singlePersonStay.setApplyStartDate(startTime);
|
||||
singlePersonStay.setApplyEndDate(endTime);
|
||||
|
||||
// 计算单人留宿天数
|
||||
long timeDiff = endTime.getTime() - startTime.getTime();
|
||||
long days = Math.max(1, timeDiff / (24 * 60 * 60 * 1000) + 1); // 至少1天
|
||||
|
||||
// 设置备注信息
|
||||
String originalRemark = template.getRemark() != null ? template.getRemark() : "";
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
String singlePersonRemark = String.format("单人留宿%d天 (%s至%s)",
|
||||
days,
|
||||
sdf.format(startTime),
|
||||
sdf.format(endTime)
|
||||
);
|
||||
|
||||
if (!originalRemark.isEmpty()) {
|
||||
singlePersonStay.setRemark(originalRemark + " | " + singlePersonRemark);
|
||||
} else {
|
||||
singlePersonStay.setRemark(singlePersonRemark);
|
||||
}
|
||||
|
||||
return singlePersonStay;
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并同一学生的连续单人留宿时间段
|
||||
*/
|
||||
private List<XgHolidayStayVo> mergeConsecutiveSinglePersonStays(List<XgHolidayStayVo> singlePersonStays) {
|
||||
if (singlePersonStays.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 按学生ID和开始时间分组排序
|
||||
Map<Long, List<XgHolidayStayVo>> studentStaysMap = singlePersonStays.stream()
|
||||
.collect(Collectors.groupingBy(XgHolidayStayVo::getStudentId));
|
||||
|
||||
List<XgHolidayStayVo> mergedStays = new ArrayList<>();
|
||||
|
||||
for (Map.Entry<Long, List<XgHolidayStayVo>> entry : studentStaysMap.entrySet()) {
|
||||
List<XgHolidayStayVo> stays = entry.getValue();
|
||||
|
||||
// 按开始时间排序
|
||||
stays.sort(Comparator.comparing(XgHolidayStayVo::getApplyStartDate));
|
||||
|
||||
XgHolidayStayVo current = stays.get(0);
|
||||
|
||||
for (int i = 1; i < stays.size(); i++) {
|
||||
XgHolidayStayVo next = stays.get(i);
|
||||
|
||||
// 如果时间段连续或重叠,合并它们
|
||||
if (current.getApplyEndDate().compareTo(next.getApplyStartDate()) >= 0) {
|
||||
// 扩展当前时间段
|
||||
if (next.getApplyEndDate().compareTo(current.getApplyEndDate()) > 0) {
|
||||
current.setApplyEndDate(next.getApplyEndDate());
|
||||
}
|
||||
|
||||
// 更新备注信息
|
||||
updateMergedRemark(current, next);
|
||||
} else {
|
||||
// 不连续,添加当前时间段到结果中
|
||||
mergedStays.add(current);
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
|
||||
// 添加最后一个时间段
|
||||
mergedStays.add(current);
|
||||
}
|
||||
|
||||
return mergedStays;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新合并后的备注信息
|
||||
*/
|
||||
private void updateMergedRemark(XgHolidayStayVo current, XgHolidayStayVo next) {
|
||||
// 重新计算合并后的天数
|
||||
long timeDiff = current.getApplyEndDate().getTime() - current.getApplyStartDate().getTime();
|
||||
long totalDays = Math.max(1, timeDiff / (24 * 60 * 60 * 1000) + 1);
|
||||
|
||||
// 更新备注
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
String mergedRemark = String.format("单人留宿%d天 (%s至%s)",
|
||||
totalDays,
|
||||
sdf.format(current.getApplyStartDate()),
|
||||
sdf.format(current.getApplyEndDate())
|
||||
);
|
||||
|
||||
// 保留原始备注的非单人留宿信息
|
||||
String originalPart = extractOriginalRemark(current.getRemark());
|
||||
if (!originalPart.isEmpty()) {
|
||||
current.setRemark(originalPart + " | " + mergedRemark);
|
||||
} else {
|
||||
current.setRemark(mergedRemark);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取原始备注信息(去除单人留宿相关的备注)
|
||||
*/
|
||||
private String extractOriginalRemark(String remark) {
|
||||
if (remark == null || remark.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// 如果包含单人留宿标记,提取原始部分
|
||||
if (remark.contains(" | 单人留宿")) {
|
||||
return remark.split(" \\| 单人留宿")[0].trim();
|
||||
}
|
||||
|
||||
// 如果以单人留宿开头,返回空
|
||||
if (remark.startsWith("单人留宿")) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return remark;
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间段内部类
|
||||
*/
|
||||
private static class TimeSegment {
|
||||
private Date startTime;
|
||||
private Date endTime;
|
||||
private Long studentId;
|
||||
private XgHolidayStayVo originalStay;
|
||||
|
||||
public TimeSegment(Date startTime, Date endTime, Long studentId, XgHolidayStayVo originalStay) {
|
||||
this.startTime = startTime;
|
||||
this.endTime = endTime;
|
||||
this.studentId = studentId;
|
||||
this.originalStay = originalStay;
|
||||
}
|
||||
|
||||
public Date getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public Date getEndTime() {
|
||||
return endTime;
|
||||
}
|
||||
|
||||
public Long getStudentId() {
|
||||
return studentId;
|
||||
}
|
||||
|
||||
public XgHolidayStayVo getOriginalStay() {
|
||||
return originalStay;
|
||||
}
|
||||
}
|
||||
}
|
||||
+193
@@ -0,0 +1,193 @@
|
||||
package org.dromara.xg.service.impl;
|
||||
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.dromara.xg.domain.bo.XgHygieneCheckViolationBo;
|
||||
import org.dromara.xg.domain.vo.XgHygieneCheckViolationVo;
|
||||
import org.dromara.xg.domain.XgHygieneCheckViolation;
|
||||
import org.dromara.xg.mapper.XgHygieneCheckViolationMapper;
|
||||
import org.dromara.xg.service.IXgHygieneCheckViolationService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 宿舍卫生检查违纪记录Service业务层处理
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-29
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class XgHygieneCheckViolationServiceImpl implements IXgHygieneCheckViolationService {
|
||||
|
||||
private final XgHygieneCheckViolationMapper baseMapper;
|
||||
|
||||
/**
|
||||
* 查询宿舍卫生检查违纪记录
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 宿舍卫生检查违纪记录
|
||||
*/
|
||||
@Override
|
||||
public XgHygieneCheckViolationVo queryById(Long id) {
|
||||
return baseMapper.selectVoById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询宿舍卫生检查违纪记录列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 宿舍卫生检查违纪记录分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<XgHygieneCheckViolationVo> queryPageList(XgHygieneCheckViolationBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<XgHygieneCheckViolation> lqw = buildQueryWrapper(bo);
|
||||
Page<XgHygieneCheckViolationVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询符合条件的宿舍卫生检查违纪记录列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 宿舍卫生检查违纪记录列表
|
||||
*/
|
||||
@Override
|
||||
public List<XgHygieneCheckViolationVo> queryList(XgHygieneCheckViolationBo bo) {
|
||||
LambdaQueryWrapper<XgHygieneCheckViolation> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<XgHygieneCheckViolation> buildQueryWrapper(XgHygieneCheckViolationBo bo) {
|
||||
LambdaQueryWrapper<XgHygieneCheckViolation> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(bo.getHygieneCheckId() != null, XgHygieneCheckViolation::getHygieneCheckId, bo.getHygieneCheckId());
|
||||
lqw.eq(bo.getStudentId() != null, XgHygieneCheckViolation::getStudentId, bo.getStudentId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getStudentNo()), XgHygieneCheckViolation::getStudentNo, bo.getStudentNo());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getStudentName()), XgHygieneCheckViolation::getStudentName,
|
||||
bo.getStudentName());
|
||||
lqw.eq(bo.getDisciplineTypeId() != null, XgHygieneCheckViolation::getDisciplineTypeId,
|
||||
bo.getDisciplineTypeId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getDisciplineTypeName()), XgHygieneCheckViolation::getDisciplineTypeName,
|
||||
bo.getDisciplineTypeName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getViolationSource()), XgHygieneCheckViolation::getViolationSource,
|
||||
bo.getViolationSource());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), XgHygieneCheckViolation::getStatus, bo.getStatus());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增宿舍卫生检查违纪记录
|
||||
*
|
||||
* @param bo 宿舍卫生检查违纪记录
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean insertByBo(XgHygieneCheckViolationBo bo) {
|
||||
XgHygieneCheckViolation add = MapstructUtils.convert(bo, XgHygieneCheckViolation.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setId(add.getId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改宿舍卫生检查违纪记录
|
||||
*
|
||||
* @param bo 宿舍卫生检查违纪记录
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean updateByBo(XgHygieneCheckViolationBo bo) {
|
||||
XgHygieneCheckViolation update = MapstructUtils.convert(bo, XgHygieneCheckViolation.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*
|
||||
* @param entity 实体类数据
|
||||
*/
|
||||
private void validEntityBeforeSave(XgHygieneCheckViolation entity) {
|
||||
// TODO 做一些数据校验,如唯一约束
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验并批量删除宿舍卫生检查违纪记录信息
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量新增宿舍卫生检查违纪记录
|
||||
*
|
||||
* @param bos 违纪记录列表
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean insertBatch(List<XgHygieneCheckViolationBo> bos) {
|
||||
if (bos == null || bos.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
List<XgHygieneCheckViolation> entities = MapstructUtils.convert(bos, XgHygieneCheckViolation.class);
|
||||
for (XgHygieneCheckViolation entity : entities) {
|
||||
validEntityBeforeSave(entity);
|
||||
}
|
||||
|
||||
return baseMapper.insertBatch(entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据卫生检查ID查询违纪记录列表
|
||||
*
|
||||
* @param hygieneCheckId 卫生检查ID
|
||||
* @return 违纪记录列表
|
||||
*/
|
||||
@Override
|
||||
public List<XgHygieneCheckViolationVo> queryByHygieneCheckId(Long hygieneCheckId) {
|
||||
LambdaQueryWrapper<XgHygieneCheckViolation> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(XgHygieneCheckViolation::getHygieneCheckId, hygieneCheckId);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据卫生检查ID删除违纪关联记录
|
||||
*
|
||||
* @param hygieneCheckId 卫生检查ID
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteByHygieneCheckId(Long hygieneCheckId) {
|
||||
LambdaQueryWrapper<XgHygieneCheckViolation> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(XgHygieneCheckViolation::getHygieneCheckId, hygieneCheckId);
|
||||
return baseMapper.delete(lqw) > 0;
|
||||
}
|
||||
}
|
||||
+34
@@ -51,6 +51,7 @@ import org.dromara.xg.domain.XgStudentManager;
|
||||
import org.dromara.xg.domain.XgStudentManagerSource;
|
||||
import org.dromara.xg.domain.XgClassMsg;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
@@ -582,4 +583,37 @@ public class XgStudentLeaveServiceImpl implements IXgStudentLeaveService {
|
||||
baseMapper.updateById(xgStudentLeave);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据学生ID列表和检查日期查询学生请假信息
|
||||
*
|
||||
* @param studentIds 学生ID列表
|
||||
* @param checkDate 检查日期
|
||||
* @return 学生ID -> 请假信息的映射
|
||||
*/
|
||||
@Override
|
||||
public Map<Long, XgStudentLeaveVo> queryStudentLeavesByCheckDate(List<Long> studentIds, LocalDateTime checkDate) {
|
||||
if (studentIds == null || studentIds.isEmpty() || checkDate == null) {
|
||||
return Map.of();
|
||||
}
|
||||
|
||||
LambdaQueryWrapper<XgStudentLeave> lqw = Wrappers.lambdaQuery();
|
||||
lqw.in(XgStudentLeave::getStudentId, studentIds);
|
||||
// 查询审核状态为"waiting"(待审核)或"finish"(已完成)的请假记录
|
||||
lqw.in(XgStudentLeave::getApprovalStatus, "waiting", "finish");
|
||||
// 检查日期在请假时间段内
|
||||
lqw.le(XgStudentLeave::getStartTime, checkDate);
|
||||
lqw.ge(XgStudentLeave::getEndTime, checkDate);
|
||||
lqw.orderByDesc(XgStudentLeave::getCreateTime);
|
||||
|
||||
List<XgStudentLeave> leaveList = baseMapper.selectList(lqw);
|
||||
|
||||
// 转换为VO并按学生ID分组,每个学生只取最新的一条请假记录
|
||||
return leaveList.stream()
|
||||
.collect(Collectors.toMap(
|
||||
XgStudentLeave::getStudentId,
|
||||
leave -> MapstructUtils.convert(leave, XgStudentLeaveVo.class),
|
||||
(existing, replacement) -> existing // 保留第一条(最新的)
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
package org.dromara.xg.service.impl;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.xg.service.IXgStudentStatisticsService;
|
||||
import org.dromara.xg.domain.bo.XgStudentStatisticsBo;
|
||||
import org.dromara.xg.domain.vo.XgStudentStatisticsVo;
|
||||
import org.dromara.xg.domain.vo.XgCascadeOptionVo;
|
||||
import org.dromara.xg.mapper.XgStudentStatisticsMapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 学生宿舍卫生检查、违纪记录统计Service业务层处理
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-14
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class XgStudentStatisticsServiceImpl implements IXgStudentStatisticsService {
|
||||
|
||||
private final XgStudentStatisticsMapper statisticsMapper;
|
||||
|
||||
@Override
|
||||
public XgStudentStatisticsVo getStatistics(XgStudentStatisticsBo bo) {
|
||||
XgStudentStatisticsVo result = new XgStudentStatisticsVo();
|
||||
|
||||
// 确定统计维度
|
||||
String dimension = determineDimension(bo);
|
||||
result.setDimension(dimension);
|
||||
|
||||
// 获取图表数据和明细数据
|
||||
switch (dimension) {
|
||||
case "college":
|
||||
result.setChartData(statisticsMapper.getCollegeStatistics(bo));
|
||||
result.setDetailData(statisticsMapper.getCollegeDetailStatistics(bo));
|
||||
break;
|
||||
case "major":
|
||||
result.setChartData(statisticsMapper.getMajorStatistics(bo));
|
||||
result.setDetailData(statisticsMapper.getMajorDetailStatistics(bo));
|
||||
break;
|
||||
case "class":
|
||||
result.setChartData(statisticsMapper.getClassStatistics(bo));
|
||||
result.setDetailData(statisticsMapper.getClassDetailStatistics(bo));
|
||||
break;
|
||||
case "classDetail":
|
||||
// 班级详情统计:图表数据和明细数据都只显示指定班级
|
||||
List<XgStudentStatisticsVo.StatisticsDetailData> detailData = statisticsMapper
|
||||
.getClassDetailStatistics(bo);
|
||||
result.setDetailData(detailData);
|
||||
// 将明细数据转换为图表数据格式
|
||||
result.setChartData(convertDetailToChartData(detailData));
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exportStatistics(XgStudentStatisticsBo bo, HttpServletResponse response) {
|
||||
XgStudentStatisticsVo statistics = getStatistics(bo);
|
||||
ExcelUtil.exportExcel(statistics.getDetailData(), "学生统计数据", XgStudentStatisticsVo.StatisticsDetailData.class,
|
||||
response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<XgCascadeOptionVo> getColleges() {
|
||||
return statisticsMapper.getColleges();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<XgCascadeOptionVo> getMajorsByCollegeId(Long collegeId) {
|
||||
return statisticsMapper.getMajorsByCollegeId(collegeId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<XgCascadeOptionVo> getClassesByMajorId(Long majorId) {
|
||||
return statisticsMapper.getClassesByMajorId(majorId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 确定统计维度
|
||||
*/
|
||||
private String determineDimension(XgStudentStatisticsBo bo) {
|
||||
if (bo.getClassId() != null) {
|
||||
return "classDetail";
|
||||
} else if (bo.getMajorId() != null) {
|
||||
return "class";
|
||||
} else if (bo.getCollegeId() != null) {
|
||||
return "major";
|
||||
} else {
|
||||
return "college";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将明细数据转换为图表数据格式
|
||||
*/
|
||||
private List<XgStudentStatisticsVo.StatisticsChartData> convertDetailToChartData(
|
||||
List<XgStudentStatisticsVo.StatisticsDetailData> detailData) {
|
||||
return detailData.stream().map(detail -> {
|
||||
XgStudentStatisticsVo.StatisticsChartData chartData = new XgStudentStatisticsVo.StatisticsChartData();
|
||||
chartData.setName(detail.getName());
|
||||
chartData.setDormDeductionCount(detail.getDormDeductionCount());
|
||||
chartData.setDormViolationCount(detail.getDormViolationCount());
|
||||
chartData.setDormViolationDeduction(detail.getDormViolationDeduction());
|
||||
chartData.setTeachingViolationCount(detail.getTeachingViolationCount());
|
||||
chartData.setTeachingViolationDeduction(detail.getTeachingViolationDeduction());
|
||||
return chartData;
|
||||
}).collect(java.util.stream.Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.xg.mapper.XgHygieneCheckViolationMapper">
|
||||
|
||||
<resultMap type="org.dromara.xg.domain.vo.XgHygieneCheckViolationVo" id="XgHygieneCheckViolationResult">
|
||||
<result property="id" column="id" />
|
||||
<result property="hygieneCheckId" column="hygiene_check_id" />
|
||||
<result property="disciplineRecordId" column="discipline_record_id" />
|
||||
<result property="studentId" column="student_id" />
|
||||
<result property="studentNo" column="student_no" />
|
||||
<result property="studentName" column="student_name" />
|
||||
<result property="disciplineTypeId" column="discipline_type_id" />
|
||||
<result property="disciplineTypeName" column="discipline_type_name" />
|
||||
<result property="violationSource" column="violation_source" />
|
||||
<result property="status" column="status" />
|
||||
<!-- 违纪详情字段 -->
|
||||
<result property="disciplineDate" column="discipline_date" />
|
||||
<result property="disciplineReason" column="discipline_reason" />
|
||||
<result property="disciplineContent" column="discipline_content" />
|
||||
<result property="scoreDeduction" column="score_deduction" />
|
||||
<result property="attachmentOssIds" column="attachment_oss_ids" />
|
||||
<result property="createBy" column="create_by" />
|
||||
<result property="createTime" column="create_time" />
|
||||
<result property="updateBy" column="update_by" />
|
||||
<result property="updateTime" column="update_time" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectXgHygieneCheckViolationVo">
|
||||
SELECT
|
||||
hcv.id,
|
||||
hcv.hygiene_check_id,
|
||||
hcv.discipline_record_id,
|
||||
hcv.student_id,
|
||||
hcv.student_no,
|
||||
hcv.student_name,
|
||||
hcv.discipline_type_id,
|
||||
hcv.discipline_type_name,
|
||||
hcv.violation_source,
|
||||
hcv.status,
|
||||
hcv.create_by,
|
||||
hcv.create_time,
|
||||
hcv.update_by,
|
||||
hcv.update_time,
|
||||
-- 关联违纪详情
|
||||
dr.discipline_date,
|
||||
dr.discipline_reason,
|
||||
dr.discipline_content,
|
||||
dr.score_deduction,
|
||||
dr.attachment_oss_ids
|
||||
FROM xg_hygiene_check_violation hcv
|
||||
LEFT JOIN xskh_discipline_record dr ON hcv.discipline_record_id = dr.id AND dr.deleted = 0
|
||||
</sql>
|
||||
|
||||
<select id="selectVoList" parameterType="com.baomidou.mybatisplus.core.conditions.Wrapper" resultMap="XgHygieneCheckViolationResult">
|
||||
<include refid="selectXgHygieneCheckViolationVo"/>
|
||||
<where>
|
||||
hcv.deleted = 0
|
||||
${ew.customSqlSegment}
|
||||
</where>
|
||||
ORDER BY hcv.create_time DESC
|
||||
</select>
|
||||
|
||||
<select id="selectVoById" parameterType="Long" resultMap="XgHygieneCheckViolationResult">
|
||||
<include refid="selectXgHygieneCheckViolationVo"/>
|
||||
WHERE hcv.id = #{id} AND hcv.deleted = 0
|
||||
</select>
|
||||
|
||||
<!-- 根据卫生检查ID查询违纪记录(包含详情) -->
|
||||
<select id="selectViolationsByHygieneCheckId" parameterType="Long" resultMap="XgHygieneCheckViolationResult">
|
||||
<include refid="selectXgHygieneCheckViolationVo"/>
|
||||
WHERE hcv.hygiene_check_id = #{hygieneCheckId}
|
||||
AND hcv.deleted = 0
|
||||
ORDER BY hcv.create_time DESC
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
+504
@@ -0,0 +1,504 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.xg.mapper.XgStudentStatisticsMapper">
|
||||
|
||||
<!-- 按学院维度统计图表数据 -->
|
||||
<select id="getCollegeStatistics" resultType="org.dromara.xg.domain.vo.XgStudentStatisticsVo$StatisticsChartData">
|
||||
SELECT
|
||||
d.dept_name as name,
|
||||
COALESCE(dorm_stats.dormDeductionCount, 0) as dormDeductionCount,
|
||||
COALESCE(dorm_violation_stats.dormViolationCount, 0) as dormViolationCount,
|
||||
COALESCE(dorm_violation_stats.dormViolationDeduction, 0) as dormViolationDeduction,
|
||||
COALESCE(teaching_violation_stats.teachingViolationCount, 0) as teachingViolationCount,
|
||||
COALESCE(teaching_violation_stats.teachingViolationDeduction, 0) as teachingViolationDeduction
|
||||
FROM sys_dept d
|
||||
LEFT JOIN (
|
||||
-- 宿舍卫生检查扣分统计
|
||||
SELECT
|
||||
c.college_id,
|
||||
COUNT(h.id) as dormDeductionCount
|
||||
FROM xg_dorm_hygiene_check h
|
||||
INNER JOIN xg_class_msg c ON h.room_id IN (
|
||||
SELECT DISTINCT bs.room_id
|
||||
FROM xg_dorm_bed_student bs
|
||||
INNER JOIN xg_student_msg s ON bs.student_id = s.id
|
||||
WHERE s.class_id = c.id AND s.deleted = 0
|
||||
)
|
||||
WHERE h.deleted = 0
|
||||
AND h.check_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
AND h.total_score > 0
|
||||
GROUP BY c.college_id
|
||||
) dorm_stats ON d.dept_id = dorm_stats.college_id
|
||||
LEFT JOIN (
|
||||
-- 宿舍区违纪记录统计
|
||||
SELECT
|
||||
dr.college_id,
|
||||
COUNT(dr.id) as dormViolationCount,
|
||||
COALESCE(SUM(dr.score_deduction), 0) as dormViolationDeduction
|
||||
FROM xskh_discipline_record dr
|
||||
WHERE dr.deleted = 0
|
||||
AND dr.violation_source = '1'
|
||||
AND dr.status = '1'
|
||||
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
GROUP BY dr.college_id
|
||||
) dorm_violation_stats ON d.dept_id = dorm_violation_stats.college_id
|
||||
LEFT JOIN (
|
||||
-- 教学区违纪记录统计
|
||||
SELECT
|
||||
dr.college_id,
|
||||
COUNT(dr.id) as teachingViolationCount,
|
||||
COALESCE(SUM(dr.score_deduction), 0) as teachingViolationDeduction
|
||||
FROM xskh_discipline_record dr
|
||||
WHERE dr.deleted = 0
|
||||
AND dr.violation_source = '2'
|
||||
AND dr.status = '1'
|
||||
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
GROUP BY dr.college_id
|
||||
) teaching_violation_stats ON d.dept_id = teaching_violation_stats.college_id
|
||||
WHERE d.parent_id = 101 AND d.del_flag = '0'
|
||||
ORDER BY d.order_num ASC, d.dept_name ASC
|
||||
</select>
|
||||
|
||||
<!-- 按学院维度统计明细数据 -->
|
||||
<select id="getCollegeDetailStatistics" resultType="org.dromara.xg.domain.vo.XgStudentStatisticsVo$StatisticsDetailData">
|
||||
SELECT
|
||||
d.dept_id as id,
|
||||
d.dept_name as name,
|
||||
'' as parentName,
|
||||
COALESCE(dorm_stats.dormDeductionCount, 0) as dormDeductionCount,
|
||||
COALESCE(dorm_violation_stats.dormViolationCount, 0) as dormViolationCount,
|
||||
COALESCE(dorm_violation_stats.dormViolationDeduction, 0) as dormViolationDeduction,
|
||||
COALESCE(teaching_violation_stats.teachingViolationCount, 0) as teachingViolationCount,
|
||||
COALESCE(teaching_violation_stats.teachingViolationDeduction, 0) as teachingViolationDeduction,
|
||||
COALESCE(dorm_violation_stats.dormViolationDeduction, 0) + COALESCE(teaching_violation_stats.teachingViolationDeduction, 0) as totalDeduction
|
||||
FROM sys_dept d
|
||||
LEFT JOIN (
|
||||
-- 宿舍卫生检查扣分统计
|
||||
SELECT
|
||||
c.college_id,
|
||||
COUNT(h.id) as dormDeductionCount
|
||||
FROM xg_dorm_hygiene_check h
|
||||
INNER JOIN xg_class_msg c ON h.room_id IN (
|
||||
SELECT DISTINCT bs.room_id
|
||||
FROM xg_dorm_bed_student bs
|
||||
INNER JOIN xg_student_msg s ON bs.student_id = s.id
|
||||
WHERE s.class_id = c.id AND s.deleted = 0
|
||||
)
|
||||
WHERE h.deleted = 0
|
||||
AND h.check_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
AND h.total_score > 0
|
||||
GROUP BY c.college_id
|
||||
) dorm_stats ON d.dept_id = dorm_stats.college_id
|
||||
LEFT JOIN (
|
||||
-- 宿舍区违纪记录统计
|
||||
SELECT
|
||||
dr.college_id,
|
||||
COUNT(dr.id) as dormViolationCount,
|
||||
COALESCE(SUM(dr.score_deduction), 0) as dormViolationDeduction
|
||||
FROM xskh_discipline_record dr
|
||||
WHERE dr.deleted = 0
|
||||
AND dr.violation_source = '1'
|
||||
AND dr.status = '1'
|
||||
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
GROUP BY dr.college_id
|
||||
) dorm_violation_stats ON d.dept_id = dorm_violation_stats.college_id
|
||||
LEFT JOIN (
|
||||
-- 教学区违纪记录统计
|
||||
SELECT
|
||||
dr.college_id,
|
||||
COUNT(dr.id) as teachingViolationCount,
|
||||
COALESCE(SUM(dr.score_deduction), 0) as teachingViolationDeduction
|
||||
FROM xskh_discipline_record dr
|
||||
WHERE dr.deleted = 0
|
||||
AND dr.violation_source = '2'
|
||||
AND dr.status = '1'
|
||||
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
GROUP BY dr.college_id
|
||||
) teaching_violation_stats ON d.dept_id = teaching_violation_stats.college_id
|
||||
WHERE d.parent_id = 101 AND d.del_flag = '0'
|
||||
ORDER BY d.order_num ASC, d.dept_name ASC
|
||||
</select>
|
||||
|
||||
<!-- 按专业维度统计图表数据 -->
|
||||
<select id="getMajorStatistics" resultType="org.dromara.xg.domain.vo.XgStudentStatisticsVo$StatisticsChartData">
|
||||
SELECT
|
||||
d.dept_name as name,
|
||||
COALESCE(dorm_stats.dormDeductionCount, 0) as dormDeductionCount,
|
||||
COALESCE(dorm_violation_stats.dormViolationCount, 0) as dormViolationCount,
|
||||
COALESCE(dorm_violation_stats.dormViolationDeduction, 0) as dormViolationDeduction,
|
||||
COALESCE(teaching_violation_stats.teachingViolationCount, 0) as teachingViolationCount,
|
||||
COALESCE(teaching_violation_stats.teachingViolationDeduction, 0) as teachingViolationDeduction
|
||||
FROM sys_dept d
|
||||
LEFT JOIN (
|
||||
-- 宿舍卫生检查扣分统计
|
||||
SELECT
|
||||
c.major_id,
|
||||
COUNT(h.id) as dormDeductionCount
|
||||
FROM xg_dorm_hygiene_check h
|
||||
INNER JOIN xg_class_msg c ON h.room_id IN (
|
||||
SELECT DISTINCT bs.room_id
|
||||
FROM xg_dorm_bed_student bs
|
||||
INNER JOIN xg_student_msg s ON bs.student_id = s.id
|
||||
WHERE s.class_id = c.id AND s.deleted = 0
|
||||
)
|
||||
WHERE h.deleted = 0
|
||||
AND h.check_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
AND h.total_score > 0
|
||||
AND c.college_id = #{bo.collegeId}
|
||||
GROUP BY c.major_id
|
||||
) dorm_stats ON d.dept_id = dorm_stats.major_id
|
||||
LEFT JOIN (
|
||||
-- 宿舍区违纪记录统计
|
||||
SELECT
|
||||
dr.major_id,
|
||||
COUNT(dr.id) as dormViolationCount,
|
||||
COALESCE(SUM(dr.score_deduction), 0) as dormViolationDeduction
|
||||
FROM xskh_discipline_record dr
|
||||
WHERE dr.deleted = 0
|
||||
AND dr.violation_source = '1'
|
||||
AND dr.status = '1'
|
||||
AND dr.college_id = #{bo.collegeId}
|
||||
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
GROUP BY dr.major_id
|
||||
) dorm_violation_stats ON d.dept_id = dorm_violation_stats.major_id
|
||||
LEFT JOIN (
|
||||
-- 教学区违纪记录统计
|
||||
SELECT
|
||||
dr.major_id,
|
||||
COUNT(dr.id) as teachingViolationCount,
|
||||
COALESCE(SUM(dr.score_deduction), 0) as teachingViolationDeduction
|
||||
FROM xskh_discipline_record dr
|
||||
WHERE dr.deleted = 0
|
||||
AND dr.violation_source = '2'
|
||||
AND dr.status = '1'
|
||||
AND dr.college_id = #{bo.collegeId}
|
||||
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
GROUP BY dr.major_id
|
||||
) teaching_violation_stats ON d.dept_id = teaching_violation_stats.major_id
|
||||
WHERE d.parent_id = #{bo.collegeId} AND d.dept_category LIKE 'zy-%' AND d.del_flag = '0'
|
||||
ORDER BY d.order_num ASC, d.dept_name ASC
|
||||
</select>
|
||||
|
||||
<!-- 按专业维度统计明细数据 -->
|
||||
<select id="getMajorDetailStatistics" resultType="org.dromara.xg.domain.vo.XgStudentStatisticsVo$StatisticsDetailData">
|
||||
SELECT
|
||||
d.dept_id as id,
|
||||
d.dept_name as name,
|
||||
p.dept_name as parentName,
|
||||
COALESCE(dorm_stats.dormDeductionCount, 0) as dormDeductionCount,
|
||||
COALESCE(dorm_violation_stats.dormViolationCount, 0) as dormViolationCount,
|
||||
COALESCE(dorm_violation_stats.dormViolationDeduction, 0) as dormViolationDeduction,
|
||||
COALESCE(teaching_violation_stats.teachingViolationCount, 0) as teachingViolationCount,
|
||||
COALESCE(teaching_violation_stats.teachingViolationDeduction, 0) as teachingViolationDeduction,
|
||||
COALESCE(dorm_violation_stats.dormViolationDeduction, 0) + COALESCE(teaching_violation_stats.teachingViolationDeduction, 0) as totalDeduction
|
||||
FROM sys_dept d
|
||||
INNER JOIN sys_dept p ON d.parent_id = p.dept_id
|
||||
LEFT JOIN (
|
||||
-- 宿舍卫生检查扣分统计
|
||||
SELECT
|
||||
c.major_id,
|
||||
COUNT(h.id) as dormDeductionCount
|
||||
FROM xg_dorm_hygiene_check h
|
||||
INNER JOIN xg_class_msg c ON h.room_id IN (
|
||||
SELECT DISTINCT bs.room_id
|
||||
FROM xg_dorm_bed_student bs
|
||||
INNER JOIN xg_student_msg s ON bs.student_id = s.id
|
||||
WHERE s.class_id = c.id AND s.deleted = 0
|
||||
)
|
||||
WHERE h.deleted = 0
|
||||
AND h.check_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
AND h.total_score > 0
|
||||
AND c.college_id = #{bo.collegeId}
|
||||
GROUP BY c.major_id
|
||||
) dorm_stats ON d.dept_id = dorm_stats.major_id
|
||||
LEFT JOIN (
|
||||
-- 宿舍区违纪记录统计
|
||||
SELECT
|
||||
dr.major_id,
|
||||
COUNT(dr.id) as dormViolationCount,
|
||||
COALESCE(SUM(dr.score_deduction), 0) as dormViolationDeduction
|
||||
FROM xskh_discipline_record dr
|
||||
WHERE dr.deleted = 0
|
||||
AND dr.violation_source = '1'
|
||||
AND dr.status = '1'
|
||||
AND dr.college_id = #{bo.collegeId}
|
||||
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
GROUP BY dr.major_id
|
||||
) dorm_violation_stats ON d.dept_id = dorm_violation_stats.major_id
|
||||
LEFT JOIN (
|
||||
-- 教学区违纪记录统计
|
||||
SELECT
|
||||
dr.major_id,
|
||||
COUNT(dr.id) as teachingViolationCount,
|
||||
COALESCE(SUM(dr.score_deduction), 0) as teachingViolationDeduction
|
||||
FROM xskh_discipline_record dr
|
||||
WHERE dr.deleted = 0
|
||||
AND dr.violation_source = '2'
|
||||
AND dr.status = '1'
|
||||
AND dr.college_id = #{bo.collegeId}
|
||||
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
GROUP BY dr.major_id
|
||||
) teaching_violation_stats ON d.dept_id = teaching_violation_stats.major_id
|
||||
WHERE d.parent_id = #{bo.collegeId} AND d.dept_category LIKE 'zy-%' AND d.del_flag = '0'
|
||||
ORDER BY d.order_num ASC, d.dept_name ASC
|
||||
</select>
|
||||
|
||||
<!-- 按班级维度统计图表数据 -->
|
||||
<select id="getClassStatistics" resultType="org.dromara.xg.domain.vo.XgStudentStatisticsVo$StatisticsChartData">
|
||||
SELECT
|
||||
c.class_name as name,
|
||||
(SELECT COUNT(h.id)
|
||||
FROM xg_dorm_hygiene_check h
|
||||
WHERE h.deleted = 0
|
||||
AND h.check_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
AND h.total_score > 0
|
||||
AND h.room_id IN (
|
||||
SELECT DISTINCT bs.room_id
|
||||
FROM xg_dorm_bed_student bs
|
||||
INNER JOIN xg_student_msg s ON bs.student_id = s.id
|
||||
WHERE s.class_id = c.id AND s.deleted = 0
|
||||
)
|
||||
) as dormDeductionCount,
|
||||
(SELECT COUNT(dr.id)
|
||||
FROM xskh_discipline_record dr
|
||||
WHERE dr.deleted = 0
|
||||
AND dr.violation_source = '1'
|
||||
AND dr.status = '1'
|
||||
AND dr.class_id = c.id
|
||||
AND dr.college_id = #{bo.collegeId}
|
||||
AND dr.major_id = #{bo.majorId}
|
||||
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
) as dormViolationCount,
|
||||
(SELECT COALESCE(SUM(dr.score_deduction), 0)
|
||||
FROM xskh_discipline_record dr
|
||||
WHERE dr.deleted = 0
|
||||
AND dr.violation_source = '1'
|
||||
AND dr.status = '1'
|
||||
AND dr.class_id = c.id
|
||||
AND dr.college_id = #{bo.collegeId}
|
||||
AND dr.major_id = #{bo.majorId}
|
||||
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
) as dormViolationDeduction,
|
||||
(SELECT COUNT(dr.id)
|
||||
FROM xskh_discipline_record dr
|
||||
WHERE dr.deleted = 0
|
||||
AND dr.violation_source = '2'
|
||||
AND dr.status = '1'
|
||||
AND dr.class_id = c.id
|
||||
AND dr.college_id = #{bo.collegeId}
|
||||
AND dr.major_id = #{bo.majorId}
|
||||
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
) as teachingViolationCount,
|
||||
(SELECT COALESCE(SUM(dr.score_deduction), 0)
|
||||
FROM xskh_discipline_record dr
|
||||
WHERE dr.deleted = 0
|
||||
AND dr.violation_source = '2'
|
||||
AND dr.status = '1'
|
||||
AND dr.class_id = c.id
|
||||
AND dr.college_id = #{bo.collegeId}
|
||||
AND dr.major_id = #{bo.majorId}
|
||||
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
) as teachingViolationDeduction
|
||||
FROM xg_class_msg c
|
||||
WHERE c.college_id = #{bo.collegeId} AND c.major_id = #{bo.majorId} AND c.deleted = 0
|
||||
ORDER BY c.class_name ASC
|
||||
</select>
|
||||
|
||||
<!-- 按班级维度统计明细数据 -->
|
||||
<select id="getClassDetailStatistics" resultType="org.dromara.xg.domain.vo.XgStudentStatisticsVo$StatisticsDetailData">
|
||||
<choose>
|
||||
<when test="bo.classId != null">
|
||||
<!-- 班级详情统计 -->
|
||||
SELECT
|
||||
c.id as id,
|
||||
c.class_name as name,
|
||||
CONCAT(c.college_name, '-', c.major_name) as parentName,
|
||||
(SELECT COUNT(h.id)
|
||||
FROM xg_dorm_hygiene_check h
|
||||
WHERE h.deleted = 0
|
||||
AND h.check_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
AND h.total_score > 0
|
||||
AND h.room_id IN (
|
||||
SELECT DISTINCT bs.room_id
|
||||
FROM xg_dorm_bed_student bs
|
||||
INNER JOIN xg_student_msg s ON bs.student_id = s.id
|
||||
WHERE s.class_id = c.id AND s.deleted = 0
|
||||
)
|
||||
) as dormDeductionCount,
|
||||
(SELECT COUNT(dr.id)
|
||||
FROM xskh_discipline_record dr
|
||||
WHERE dr.deleted = 0
|
||||
AND dr.violation_source = '1'
|
||||
AND dr.status = '1'
|
||||
AND dr.class_id = #{bo.classId}
|
||||
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
) as dormViolationCount,
|
||||
(SELECT COALESCE(SUM(dr.score_deduction), 0)
|
||||
FROM xskh_discipline_record dr
|
||||
WHERE dr.deleted = 0
|
||||
AND dr.violation_source = '1'
|
||||
AND dr.status = '1'
|
||||
AND dr.class_id = #{bo.classId}
|
||||
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
) as dormViolationDeduction,
|
||||
(SELECT COUNT(dr.id)
|
||||
FROM xskh_discipline_record dr
|
||||
WHERE dr.deleted = 0
|
||||
AND dr.violation_source = '2'
|
||||
AND dr.status = '1'
|
||||
AND dr.class_id = #{bo.classId}
|
||||
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
) as teachingViolationCount,
|
||||
(SELECT COALESCE(SUM(dr.score_deduction), 0)
|
||||
FROM xskh_discipline_record dr
|
||||
WHERE dr.deleted = 0
|
||||
AND dr.violation_source = '2'
|
||||
AND dr.status = '1'
|
||||
AND dr.class_id = #{bo.classId}
|
||||
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
) as teachingViolationDeduction,
|
||||
((SELECT COALESCE(SUM(dr.score_deduction), 0)
|
||||
FROM xskh_discipline_record dr
|
||||
WHERE dr.deleted = 0
|
||||
AND dr.violation_source = '1'
|
||||
AND dr.status = '1'
|
||||
AND dr.class_id = #{bo.classId}
|
||||
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
) +
|
||||
(SELECT COALESCE(SUM(dr.score_deduction), 0)
|
||||
FROM xskh_discipline_record dr
|
||||
WHERE dr.deleted = 0
|
||||
AND dr.violation_source = '2'
|
||||
AND dr.status = '1'
|
||||
AND dr.class_id = #{bo.classId}
|
||||
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
)) as totalDeduction
|
||||
FROM xg_class_msg c
|
||||
WHERE c.id = #{bo.classId} AND c.deleted = 0
|
||||
</when>
|
||||
<otherwise>
|
||||
<!-- 班级列表统计 -->
|
||||
SELECT
|
||||
c.id as id,
|
||||
c.class_name as name,
|
||||
c.major_name as parentName,
|
||||
(SELECT COUNT(h.id)
|
||||
FROM xg_dorm_hygiene_check h
|
||||
WHERE h.deleted = 0
|
||||
AND h.check_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
AND h.total_score > 0
|
||||
AND h.room_id IN (
|
||||
SELECT DISTINCT bs.room_id
|
||||
FROM xg_dorm_bed_student bs
|
||||
INNER JOIN xg_student_msg s ON bs.student_id = s.id
|
||||
WHERE s.class_id = c.id AND s.deleted = 0
|
||||
)
|
||||
) as dormDeductionCount,
|
||||
(SELECT COUNT(dr.id)
|
||||
FROM xskh_discipline_record dr
|
||||
WHERE dr.deleted = 0
|
||||
AND dr.violation_source = '1'
|
||||
AND dr.status = '1'
|
||||
AND dr.class_id = c.id
|
||||
AND dr.college_id = #{bo.collegeId}
|
||||
AND dr.major_id = #{bo.majorId}
|
||||
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
) as dormViolationCount,
|
||||
(SELECT COALESCE(SUM(dr.score_deduction), 0)
|
||||
FROM xskh_discipline_record dr
|
||||
WHERE dr.deleted = 0
|
||||
AND dr.violation_source = '1'
|
||||
AND dr.status = '1'
|
||||
AND dr.class_id = c.id
|
||||
AND dr.college_id = #{bo.collegeId}
|
||||
AND dr.major_id = #{bo.majorId}
|
||||
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
) as dormViolationDeduction,
|
||||
(SELECT COUNT(dr.id)
|
||||
FROM xskh_discipline_record dr
|
||||
WHERE dr.deleted = 0
|
||||
AND dr.violation_source = '2'
|
||||
AND dr.status = '1'
|
||||
AND dr.class_id = c.id
|
||||
AND dr.college_id = #{bo.collegeId}
|
||||
AND dr.major_id = #{bo.majorId}
|
||||
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
) as teachingViolationCount,
|
||||
(SELECT COALESCE(SUM(dr.score_deduction), 0)
|
||||
FROM xskh_discipline_record dr
|
||||
WHERE dr.deleted = 0
|
||||
AND dr.violation_source = '2'
|
||||
AND dr.status = '1'
|
||||
AND dr.class_id = c.id
|
||||
AND dr.college_id = #{bo.collegeId}
|
||||
AND dr.major_id = #{bo.majorId}
|
||||
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
) as teachingViolationDeduction,
|
||||
((SELECT COALESCE(SUM(dr.score_deduction), 0)
|
||||
FROM xskh_discipline_record dr
|
||||
WHERE dr.deleted = 0
|
||||
AND dr.violation_source = '1'
|
||||
AND dr.status = '1'
|
||||
AND dr.class_id = c.id
|
||||
AND dr.college_id = #{bo.collegeId}
|
||||
AND dr.major_id = #{bo.majorId}
|
||||
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
) +
|
||||
(SELECT COALESCE(SUM(dr.score_deduction), 0)
|
||||
FROM xskh_discipline_record dr
|
||||
WHERE dr.deleted = 0
|
||||
AND dr.violation_source = '2'
|
||||
AND dr.status = '1'
|
||||
AND dr.class_id = c.id
|
||||
AND dr.college_id = #{bo.collegeId}
|
||||
AND dr.major_id = #{bo.majorId}
|
||||
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
|
||||
)) as totalDeduction
|
||||
FROM xg_class_msg c
|
||||
WHERE c.college_id = #{bo.collegeId} AND c.major_id = #{bo.majorId} AND c.deleted = 0
|
||||
ORDER BY c.class_name ASC
|
||||
</otherwise>
|
||||
</choose>
|
||||
</select>
|
||||
|
||||
<!-- 获取二级学院列表 -->
|
||||
<select id="getColleges" resultType="org.dromara.xg.domain.vo.XgCascadeOptionVo">
|
||||
SELECT
|
||||
dept_id as id,
|
||||
dept_name as label,
|
||||
CAST(dept_id AS CHAR) as value,
|
||||
order_num as sort
|
||||
FROM sys_dept
|
||||
WHERE parent_id = 101 AND del_flag = '0'
|
||||
ORDER BY order_num ASC, dept_name ASC
|
||||
</select>
|
||||
|
||||
<!-- 根据学院ID获取专业列表 -->
|
||||
<select id="getMajorsByCollegeId" resultType="org.dromara.xg.domain.vo.XgCascadeOptionVo">
|
||||
SELECT
|
||||
dept_id as id,
|
||||
dept_name as label,
|
||||
CAST(dept_id AS CHAR) as value,
|
||||
order_num as sort
|
||||
FROM sys_dept
|
||||
WHERE parent_id = #{collegeId}
|
||||
AND dept_category LIKE 'zy-%'
|
||||
AND del_flag = '0'
|
||||
ORDER BY order_num ASC, dept_name ASC
|
||||
</select>
|
||||
|
||||
<!-- 根据专业ID获取班级列表 -->
|
||||
<select id="getClassesByMajorId" resultType="org.dromara.xg.domain.vo.XgCascadeOptionVo">
|
||||
SELECT
|
||||
id,
|
||||
class_name as label,
|
||||
CAST(id AS CHAR) as value,
|
||||
0 as sort
|
||||
FROM xg_class_msg
|
||||
WHERE major_id = #{majorId} AND deleted = 0
|
||||
ORDER BY class_name ASC
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
+44
-14
@@ -134,17 +134,6 @@ public class XskhDisciplineRevokeController extends BaseController {
|
||||
return toAjax(xskhDisciplineRevokeService.applyRevoke(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 审核撤销申请
|
||||
*/
|
||||
@SaCheckPermission("disciplineRevoke:disciplineRevoke:approve")
|
||||
@Log(title = "审核撤销申请", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/approve")
|
||||
public R<Void> approveRevoke(@Validated(EditGroup.class) @RequestBody XskhDisciplineRevokeBo bo) {
|
||||
return toAjax(xskhDisciplineRevokeService.approveRevoke(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询班主任班级的违纪撤销申请列表(班主任专用)
|
||||
*/
|
||||
@@ -155,15 +144,56 @@ public class XskhDisciplineRevokeController extends BaseController {
|
||||
return xskhDisciplineRevokeService.queryClassTeacherPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询班主任已审核的违纪撤销申请列表(根据审核人查询历史记录)
|
||||
*/
|
||||
@SaCheckPermission("disciplineRevoke:classTeacher:list")
|
||||
@GetMapping("/classTeacherReviewedList")
|
||||
public TableDataInfo<XskhDisciplineRevokeVo> getClassTeacherReviewedRevokeApplications(XskhDisciplineRevokeBo bo,
|
||||
PageQuery pageQuery) {
|
||||
return xskhDisciplineRevokeService.queryClassTeacherReviewedPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 班主任审核撤销申请
|
||||
*/
|
||||
@SaCheckPermission("disciplineRevoke:classTeacher:approve")
|
||||
@Log(title = "班主任审核撤销申请", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/classTeacherApprove")
|
||||
public R<Void> classTeacherApproveRevoke(@Validated(EditGroup.class) @RequestBody XskhDisciplineRevokeBo bo) {
|
||||
return toAjax(xskhDisciplineRevokeService.classTeacherApproveRevoke(bo));
|
||||
@PutMapping("/teacherApprove")
|
||||
public R<Void> teacherApproveRevoke(@Validated(EditGroup.class) @RequestBody XskhDisciplineRevokeBo bo) {
|
||||
return toAjax(xskhDisciplineRevokeService.teacherApproveRevoke(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询学工处待审核的撤销申请列表(学工处专用)
|
||||
*/
|
||||
@SaCheckPermission("disciplineRevoke:studentAffairs:list")
|
||||
@GetMapping("/studentAffairsList")
|
||||
public TableDataInfo<XskhDisciplineRevokeVo> getStudentAffairsRevokeApplications(XskhDisciplineRevokeBo bo,
|
||||
PageQuery pageQuery) {
|
||||
return xskhDisciplineRevokeService.queryStudentAffairsPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 学工处审核撤销申请
|
||||
*/
|
||||
@SaCheckPermission("disciplineRevoke:studentAffairs:approve")
|
||||
@Log(title = "学工处审核撤销申请", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/studentAffairsApprove")
|
||||
public R<Void> studentAffairsApproveRevoke(@Validated(EditGroup.class) @RequestBody XskhDisciplineRevokeBo bo) {
|
||||
return toAjax(xskhDisciplineRevokeService.studentAffairsApproveRevoke(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询学工处已审核的撤销申请列表(学工处专用)
|
||||
*/
|
||||
@SaCheckPermission("disciplineRevoke:studentAffairs:list")
|
||||
@GetMapping("/studentAffairsReviewedList")
|
||||
public TableDataInfo<XskhDisciplineRevokeVo> getStudentAffairsReviewedRevokeApplications(XskhDisciplineRevokeBo bo,
|
||||
PageQuery pageQuery) {
|
||||
return xskhDisciplineRevokeService.queryStudentAffairsReviewedPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
}
|
||||
+22
-4
@@ -63,8 +63,7 @@ public class XskhDisciplineTypeController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("disciplineType:disciplineType:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<XskhDisciplineTypeVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
public R<XskhDisciplineTypeVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
|
||||
return R.ok(xskhDisciplineTypeService.queryById(id));
|
||||
}
|
||||
|
||||
@@ -98,8 +97,27 @@ public class XskhDisciplineTypeController extends BaseController {
|
||||
@SaCheckPermission("disciplineType:disciplineType:remove")
|
||||
@Log(title = "学生违纪处分类型", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
|
||||
return toAjax(xskhDisciplineTypeService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据区域类型查询学生违纪处分类型列表
|
||||
*
|
||||
* @param areaType 区域类型(1-宿舍区违纪 2-教学区违纪)
|
||||
* @param status 状态(0-正常 1-停用)
|
||||
* @return 学生违纪处分类型列表
|
||||
*/
|
||||
@SaCheckPermission("disciplineType:disciplineType:list")
|
||||
@GetMapping("/listByAreaType")
|
||||
public R<List<XskhDisciplineTypeVo>> listByAreaType(@RequestParam String areaType,
|
||||
@RequestParam(required = false) String status) {
|
||||
XskhDisciplineTypeBo bo = new XskhDisciplineTypeBo();
|
||||
bo.setAreaType(areaType);
|
||||
if (status != null) {
|
||||
bo.setStatus(status);
|
||||
}
|
||||
List<XskhDisciplineTypeVo> list = xskhDisciplineTypeService.queryList(bo);
|
||||
return R.ok(list);
|
||||
}
|
||||
}
|
||||
+5
@@ -110,6 +110,11 @@ public class XskhDisciplineRecord extends TenantEntity {
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 违纪来源(1-宿舍卫生检查 2-教学区违纪)
|
||||
*/
|
||||
private String violationSource;
|
||||
|
||||
/**
|
||||
* 附件OSS ID列表,逗号分隔
|
||||
*/
|
||||
|
||||
+19
-4
@@ -59,22 +59,37 @@ public class XskhDisciplineRevoke extends TenantEntity {
|
||||
private Date applyTime;
|
||||
|
||||
/**
|
||||
* 状态(1-待审核 2-审核通过 3-审核拒绝)
|
||||
* 状态(1-待班主任审核 2-待学工处审核 3-审核通过 4-班主任审核拒绝 5-学工处审核拒绝)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 审核人ID
|
||||
* 班主任审核人ID
|
||||
*/
|
||||
private Long teacherApprovalBy;
|
||||
|
||||
/**
|
||||
* 班主任审核时间
|
||||
*/
|
||||
private Date teacherApprovalTime;
|
||||
|
||||
/**
|
||||
* 班主任审核备注
|
||||
*/
|
||||
private String teacherApprovalRemark;
|
||||
|
||||
/**
|
||||
* 学工处审核人ID
|
||||
*/
|
||||
private Long approvalBy;
|
||||
|
||||
/**
|
||||
* 审核时间
|
||||
* 学工处审核时间
|
||||
*/
|
||||
private Date approvalTime;
|
||||
|
||||
/**
|
||||
* 审核备注
|
||||
* 学工处审核备注
|
||||
*/
|
||||
private String approvalRemark;
|
||||
|
||||
|
||||
+25
-1
@@ -42,6 +42,31 @@ public class XskhDisciplineType extends TenantEntity {
|
||||
*/
|
||||
private String typeCategory;
|
||||
|
||||
/**
|
||||
* 区域类型(1-宿舍区违纪 2-教学区违纪)
|
||||
*/
|
||||
private String areaType;
|
||||
|
||||
/**
|
||||
* 最低扣分
|
||||
*/
|
||||
private java.math.BigDecimal minScore;
|
||||
|
||||
/**
|
||||
* 最高扣分
|
||||
*/
|
||||
private java.math.BigDecimal maxScore;
|
||||
|
||||
/**
|
||||
* 是否均化(0-否 1-是)
|
||||
*/
|
||||
private String isEqualized;
|
||||
|
||||
/**
|
||||
* 均化阈值
|
||||
*/
|
||||
private java.math.BigDecimal equalizedThreshold;
|
||||
|
||||
/**
|
||||
* 类型说明
|
||||
*/
|
||||
@@ -63,5 +88,4 @@ public class XskhDisciplineType extends TenantEntity {
|
||||
@TableLogic(value = "0", delval = "1")
|
||||
private Long deleted;
|
||||
|
||||
|
||||
}
|
||||
+10
@@ -42,6 +42,16 @@ public class XskhRewardType extends TenantEntity {
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 是否均化(0-否 1-是)
|
||||
*/
|
||||
private String isEqualized;
|
||||
|
||||
/**
|
||||
* 均化阈值
|
||||
*/
|
||||
private java.math.BigDecimal equalizedThreshold;
|
||||
|
||||
/**
|
||||
* 状态(0-正常 1-停用)
|
||||
*/
|
||||
|
||||
+5
@@ -128,6 +128,11 @@ public class XskhDisciplineRecordBo extends BaseEntity {
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 违纪来源(1-宿舍卫生检查 2-教学区违纪)
|
||||
*/
|
||||
private String violationSource;
|
||||
|
||||
/**
|
||||
* 附件OSS ID列表,逗号分隔
|
||||
*/
|
||||
|
||||
+28
-4
@@ -68,24 +68,48 @@ public class XskhDisciplineRevokeBo extends BaseEntity {
|
||||
private Date applyTime;
|
||||
|
||||
/**
|
||||
* 状态(1-待审核 2-审核通过 3-审核拒绝)
|
||||
* 状态(1-待班主任审核 2-待学工处审核 3-审核通过 4-班主任审核拒绝 5-学工处审核拒绝)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 审核人ID
|
||||
* 班主任审核人ID
|
||||
*/
|
||||
private Long teacherApprovalBy;
|
||||
|
||||
/**
|
||||
* 班主任审核时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date teacherApprovalTime;
|
||||
|
||||
/**
|
||||
* 班主任审核备注
|
||||
*/
|
||||
private String teacherApprovalRemark;
|
||||
|
||||
/**
|
||||
* 学工处审核人ID
|
||||
*/
|
||||
private Long approvalBy;
|
||||
|
||||
/**
|
||||
* 审核时间
|
||||
* 学工处审核时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date approvalTime;
|
||||
|
||||
/**
|
||||
* 审核备注
|
||||
* 学工处审核备注
|
||||
*/
|
||||
private String approvalRemark;
|
||||
|
||||
// VO类基础字段规范(避免MyBatis映射错误)
|
||||
private Long createBy; // 创建者
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime; // 创建时间
|
||||
private Long updateBy; // 更新者
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime; // 更新时间
|
||||
|
||||
}
|
||||
+34
-1
@@ -8,6 +8,7 @@ import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import jakarta.validation.constraints.*;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 学生违纪处分类型业务对象 xskh_discipline_type
|
||||
@@ -44,6 +45,39 @@ public class XskhDisciplineTypeBo extends BaseEntity {
|
||||
@NotBlank(message = "类型分类(1-违纪类型 2-处分类型)不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String typeCategory;
|
||||
|
||||
/**
|
||||
* 区域类型(1-宿舍区违纪 2-教学区违纪)
|
||||
*/
|
||||
@NotBlank(message = "区域类型不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String areaType;
|
||||
|
||||
/**
|
||||
* 最低扣分
|
||||
*/
|
||||
@NotNull(message = "最低扣分不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@DecimalMin(value = "0.00", message = "最低扣分不能小于0", groups = { AddGroup.class, EditGroup.class })
|
||||
@DecimalMax(value = "100.00", message = "最低扣分不能大于100", groups = { AddGroup.class, EditGroup.class })
|
||||
private java.math.BigDecimal minScore;
|
||||
|
||||
/**
|
||||
* 最高扣分
|
||||
*/
|
||||
@NotNull(message = "最高扣分不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@DecimalMin(value = "0.00", message = "最高扣分不能小于0", groups = { AddGroup.class, EditGroup.class })
|
||||
@DecimalMax(value = "100.00", message = "最高扣分不能大于100", groups = { AddGroup.class, EditGroup.class })
|
||||
private java.math.BigDecimal maxScore;
|
||||
|
||||
/**
|
||||
* 是否均化(0-否 1-是)
|
||||
*/
|
||||
private String isEqualized;
|
||||
|
||||
/**
|
||||
* 均化阈值
|
||||
*/
|
||||
@DecimalMin(value = "0.00", message = "均化阈值不能小于0", groups = { AddGroup.class, EditGroup.class })
|
||||
private java.math.BigDecimal equalizedThreshold;
|
||||
|
||||
/**
|
||||
* 类型说明
|
||||
*/
|
||||
@@ -64,5 +98,4 @@ public class XskhDisciplineTypeBo extends BaseEntity {
|
||||
*/
|
||||
private Long deleted;
|
||||
|
||||
|
||||
}
|
||||
+11
@@ -43,6 +43,17 @@ public class XskhRewardTypeBo extends BaseEntity {
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 是否均化(0-否 1-是)
|
||||
*/
|
||||
private String isEqualized;
|
||||
|
||||
/**
|
||||
* 均化阈值
|
||||
*/
|
||||
@DecimalMin(value = "0.00", message = "均化阈值不能小于0", groups = { AddGroup.class, EditGroup.class })
|
||||
private java.math.BigDecimal equalizedThreshold;
|
||||
|
||||
/**
|
||||
* 状态(0-正常 1-停用)
|
||||
*/
|
||||
|
||||
+10
-1
@@ -131,11 +131,20 @@ public class XskhDisciplineRecordVo implements Serializable {
|
||||
* 状态(1-生效 2-已撤销)
|
||||
*/
|
||||
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "student_discipline_status")
|
||||
@ExcelDictFormat(dictType = "xskh_discipline_status")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 违纪来源(1-宿舍卫生检查 2-教学区违纪)
|
||||
*/
|
||||
@ExcelProperty(value = "违纪来源", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "xskh_violation_source")
|
||||
private String violationSource;
|
||||
|
||||
/**
|
||||
* 附件OSS ID列表,逗号分隔
|
||||
*/
|
||||
@ExcelProperty(value = "附件OSS ID列表")
|
||||
private String attachmentOssIds;
|
||||
|
||||
/**
|
||||
|
||||
+34
-9
@@ -90,35 +90,60 @@ public class XskhDisciplineRevokeVo implements Serializable {
|
||||
private Date applyTime;
|
||||
|
||||
/**
|
||||
* 状态(1-待审核 2-审核通过 3-审核拒绝)
|
||||
* 状态(1-待班主任审核 2-待学工处审核 3-审核通过 4-班主任审核拒绝 5-学工处审核拒绝)
|
||||
*/
|
||||
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "student_revoke_status")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 审核人ID
|
||||
* 班主任审核人ID
|
||||
*/
|
||||
@ExcelProperty(value = "审核人ID")
|
||||
@ExcelProperty(value = "班主任审核人ID")
|
||||
private Long teacherApprovalBy;
|
||||
|
||||
/**
|
||||
* 班主任审核人姓名(关联查询)
|
||||
*/
|
||||
@ExcelProperty(value = "班主任审核人姓名")
|
||||
private String teacherApprovalByName;
|
||||
|
||||
/**
|
||||
* 班主任审核时间
|
||||
*/
|
||||
@ExcelProperty(value = "班主任审核时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date teacherApprovalTime;
|
||||
|
||||
/**
|
||||
* 班主任审核备注
|
||||
*/
|
||||
@ExcelProperty(value = "班主任审核备注")
|
||||
private String teacherApprovalRemark;
|
||||
|
||||
/**
|
||||
* 学工处审核人ID
|
||||
*/
|
||||
@ExcelProperty(value = "学工处审核人ID")
|
||||
private Long approvalBy;
|
||||
|
||||
/**
|
||||
* 审核人姓名(关联查询)
|
||||
* 学工处审核人姓名(关联查询)
|
||||
*/
|
||||
@ExcelProperty(value = "审核人姓名")
|
||||
@ExcelProperty(value = "学工处审核人姓名")
|
||||
private String approvalByName;
|
||||
|
||||
/**
|
||||
* 审核时间
|
||||
* 学工处审核时间
|
||||
*/
|
||||
@ExcelProperty(value = "审核时间")
|
||||
@ExcelProperty(value = "学工处审核时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date approvalTime;
|
||||
|
||||
/**
|
||||
* 审核备注
|
||||
* 学工处审核备注
|
||||
*/
|
||||
@ExcelProperty(value = "审核备注")
|
||||
@ExcelProperty(value = "学工处审核备注")
|
||||
private String approvalRemark;
|
||||
|
||||
/**
|
||||
|
||||
+32
-3
@@ -12,8 +12,6 @@ import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 学生违纪处分类型视图对象 xskh_discipline_type
|
||||
*
|
||||
@@ -53,6 +51,38 @@ public class XskhDisciplineTypeVo implements Serializable {
|
||||
@ExcelDictFormat(dictType = "student_discipline_category")
|
||||
private String typeCategory;
|
||||
|
||||
/**
|
||||
* 区域类型(1-宿舍区违纪 2-教学区违纪)
|
||||
*/
|
||||
@ExcelProperty(value = "区域类型", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "discipline_area_type")
|
||||
private String areaType;
|
||||
|
||||
/**
|
||||
* 最低扣分
|
||||
*/
|
||||
@ExcelProperty(value = "最低扣分")
|
||||
private java.math.BigDecimal minScore;
|
||||
|
||||
/**
|
||||
* 最高扣分
|
||||
*/
|
||||
@ExcelProperty(value = "最高扣分")
|
||||
private java.math.BigDecimal maxScore;
|
||||
|
||||
/**
|
||||
* 是否均化(0-否 1-是)
|
||||
*/
|
||||
@ExcelProperty(value = "是否均化", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "sys_yes_no")
|
||||
private String isEqualized;
|
||||
|
||||
/**
|
||||
* 均化阈值
|
||||
*/
|
||||
@ExcelProperty(value = "均化阈值")
|
||||
private java.math.BigDecimal equalizedThreshold;
|
||||
|
||||
/**
|
||||
* 类型说明
|
||||
*/
|
||||
@@ -78,5 +108,4 @@ public class XskhDisciplineTypeVo implements Serializable {
|
||||
@ExcelProperty(value = "删除标志(0-未删除 1-已删除)")
|
||||
private Long deleted;
|
||||
|
||||
|
||||
}
|
||||
+13
-3
@@ -12,8 +12,6 @@ import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 学生奖励类型视图对象 xskh_reward_type
|
||||
*
|
||||
@@ -52,6 +50,19 @@ public class XskhRewardTypeVo implements Serializable {
|
||||
@ExcelProperty(value = "类型说明")
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 是否均化(0-否 1-是)
|
||||
*/
|
||||
@ExcelProperty(value = "是否均化", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "sys_yes_no")
|
||||
private String isEqualized;
|
||||
|
||||
/**
|
||||
* 均化阈值
|
||||
*/
|
||||
@ExcelProperty(value = "均化阈值")
|
||||
private java.math.BigDecimal equalizedThreshold;
|
||||
|
||||
/**
|
||||
* 状态(0-正常 1-停用)
|
||||
*/
|
||||
@@ -71,5 +82,4 @@ public class XskhRewardTypeVo implements Serializable {
|
||||
@ExcelProperty(value = "删除标志(0-未删除 1-已删除)")
|
||||
private Long deleted;
|
||||
|
||||
|
||||
}
|
||||
+46
-38
@@ -19,46 +19,54 @@ import java.util.Map;
|
||||
*/
|
||||
public interface XskhDisciplineRecordMapper extends BaseMapperPlus<XskhDisciplineRecord, XskhDisciplineRecordVo> {
|
||||
|
||||
/**
|
||||
* 查询学生选项列表(用于下拉框)
|
||||
*
|
||||
* @param keyword 搜索关键词(学号或姓名)
|
||||
* @return 学生选项列表
|
||||
*/
|
||||
List<XskhStudentOptionVo> selectStudentOptions(String keyword);
|
||||
/**
|
||||
* 查询学生选项列表(用于下拉框)
|
||||
*
|
||||
* @param keyword 搜索关键词(学号或姓名)
|
||||
* @return 学生选项列表
|
||||
*/
|
||||
List<XskhStudentOptionVo> selectStudentOptions(String keyword);
|
||||
|
||||
/**
|
||||
* 查询班主任班级的违纪处分记录列表(班主任专用)
|
||||
*
|
||||
* @param page 分页参数
|
||||
* @param bo 查询条件
|
||||
* @param classTeacherId 班主任ID
|
||||
* @return 分页查询结果
|
||||
*/
|
||||
Page<XskhDisciplineRecordVo> selectClassTeacherVoPage(@Param("page") Page<XskhDisciplineRecordVo> page,
|
||||
@Param("bo") XskhDisciplineRecordBo bo,
|
||||
@Param("classTeacherId") Long classTeacherId);
|
||||
/**
|
||||
* 查询班主任班级的违纪处分记录列表(班主任专用)
|
||||
*
|
||||
* @param page 分页参数
|
||||
* @param bo 查询条件
|
||||
* @param classTeacherId 班主任ID
|
||||
* @return 分页查询结果
|
||||
*/
|
||||
Page<XskhDisciplineRecordVo> selectClassTeacherVoPage(@Param("page") Page<XskhDisciplineRecordVo> page,
|
||||
@Param("bo") XskhDisciplineRecordBo bo,
|
||||
@Param("classTeacherId") Long classTeacherId);
|
||||
|
||||
/**
|
||||
* 获取指标关联的违纪处分类型和奖励类型
|
||||
*
|
||||
* @param indicatorId 指标ID
|
||||
* @return 包含disciplineTypeIds和rewardTypeIds的Map
|
||||
*/
|
||||
Map<String, String> selectIndicatorTypes(@Param("indicatorId") Long indicatorId);
|
||||
/**
|
||||
* 获取指标关联的违纪处分类型和奖励类型
|
||||
*
|
||||
* @param indicatorId 指标ID
|
||||
* @return 包含disciplineTypeIds和rewardTypeIds的Map
|
||||
*/
|
||||
Map<String, String> selectIndicatorTypes(@Param("indicatorId") Long indicatorId);
|
||||
|
||||
/**
|
||||
* 获取学生在指定时间范围内的违纪处分记录
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @param disciplineTypeIds 违纪处分类型ID列表
|
||||
* @param startTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
* @return 违纪处分记录列表
|
||||
*/
|
||||
List<XskhDisciplineRecordVo> selectStudentDisciplineRecords(@Param("studentId") Long studentId,
|
||||
@Param("disciplineTypeIds") List<Long> disciplineTypeIds,
|
||||
@Param("startTime") String startTime,
|
||||
@Param("endTime") String endTime);
|
||||
/**
|
||||
* 获取学生在指定时间范围内的违纪处分记录
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @param disciplineTypeIds 违纪处分类型ID列表
|
||||
* @param startTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
* @return 违纪处分记录列表
|
||||
*/
|
||||
List<XskhDisciplineRecordVo> selectStudentDisciplineRecords(@Param("studentId") Long studentId,
|
||||
@Param("disciplineTypeIds") List<Long> disciplineTypeIds,
|
||||
@Param("startTime") String startTime,
|
||||
@Param("endTime") String endTime);
|
||||
|
||||
/**
|
||||
* 根据违纪记录ID逻辑删除宿舍卫生检查违纪关联记录
|
||||
*
|
||||
* @param disciplineRecordId 违纪记录ID
|
||||
* @return 删除的记录数量
|
||||
*/
|
||||
int deleteHygieneCheckViolationByDisciplineRecordId(@Param("disciplineRecordId") Long disciplineRecordId);
|
||||
|
||||
}
|
||||
+52
-18
@@ -15,24 +15,58 @@ import org.dromara.xskh.domain.vo.XskhDisciplineRevokeVo;
|
||||
*/
|
||||
public interface XskhDisciplineRevokeMapper extends BaseMapperPlus<XskhDisciplineRevoke, XskhDisciplineRevokeVo> {
|
||||
|
||||
/**
|
||||
* 根据违纪记录ID查询撤销申请记录
|
||||
*
|
||||
* @param disciplineRecordId 违纪记录ID
|
||||
* @return 撤销申请记录
|
||||
*/
|
||||
XskhDisciplineRevokeVo selectByDisciplineRecordId(Long disciplineRecordId);
|
||||
/**
|
||||
* 根据违纪记录ID查询撤销申请记录
|
||||
*
|
||||
* @param disciplineRecordId 违纪记录ID
|
||||
* @return 撤销申请记录
|
||||
*/
|
||||
XskhDisciplineRevokeVo selectByDisciplineRecordId(Long disciplineRecordId);
|
||||
|
||||
/**
|
||||
* 查询班主任班级的违纪撤销申请列表(班主任专用)
|
||||
*
|
||||
* @param page 分页参数
|
||||
* @param bo 查询条件
|
||||
* @param classTeacherId 班主任ID
|
||||
* @return 分页查询结果
|
||||
*/
|
||||
Page<XskhDisciplineRevokeVo> selectClassTeacherVoPage(@Param("page") Page<XskhDisciplineRevokeVo> page,
|
||||
@Param("bo") XskhDisciplineRevokeBo bo,
|
||||
@Param("classTeacherId") Long classTeacherId);
|
||||
/**
|
||||
* 查询班主任班级的违纪撤销申请列表(班主任专用)
|
||||
*
|
||||
* @param page 分页参数
|
||||
* @param bo 查询条件
|
||||
* @param classTeacherId 班主任ID
|
||||
* @return 分页查询结果
|
||||
*/
|
||||
Page<XskhDisciplineRevokeVo> selectClassTeacherVoPage(@Param("page") Page<XskhDisciplineRevokeVo> page,
|
||||
@Param("bo") XskhDisciplineRevokeBo bo,
|
||||
@Param("classTeacherId") Long classTeacherId);
|
||||
|
||||
/**
|
||||
* 查询学工处待审核的违纪撤销申请列表(学工处专用)
|
||||
*
|
||||
* @param page 分页参数
|
||||
* @param bo 查询条件
|
||||
* @return 分页查询结果
|
||||
*/
|
||||
Page<XskhDisciplineRevokeVo> selectStudentAffairsVoPage(@Param("page") Page<XskhDisciplineRevokeVo> page,
|
||||
@Param("bo") XskhDisciplineRevokeBo bo);
|
||||
|
||||
/**
|
||||
* 查询学工处已审核的违纪撤销申请列表(学工处专用)
|
||||
*
|
||||
* @param page 分页参数
|
||||
* @param bo 查询条件
|
||||
* @return 分页查询结果
|
||||
*/
|
||||
Page<XskhDisciplineRevokeVo> selectStudentAffairsReviewedVoPage(
|
||||
@Param("page") Page<XskhDisciplineRevokeVo> page,
|
||||
@Param("bo") XskhDisciplineRevokeBo bo);
|
||||
|
||||
/**
|
||||
* 查询班主任已审核的违纪撤销申请列表(根据审核人查询历史记录)
|
||||
*
|
||||
* @param page 分页参数
|
||||
* @param bo 查询条件
|
||||
* @param classTeacherId 班主任ID
|
||||
* @return 分页查询结果
|
||||
*/
|
||||
Page<XskhDisciplineRevokeVo> selectClassTeacherReviewedVoPage(
|
||||
@Param("page") Page<XskhDisciplineRevokeVo> page,
|
||||
@Param("bo") XskhDisciplineRevokeBo bo,
|
||||
@Param("classTeacherId") Long classTeacherId);
|
||||
|
||||
}
|
||||
+23
-6
@@ -61,19 +61,36 @@ public interface IXskhDisciplineRevokeService {
|
||||
*/
|
||||
Boolean applyRevoke(XskhDisciplineRevokeBo bo);
|
||||
|
||||
/**
|
||||
* 审核撤销申请
|
||||
*/
|
||||
Boolean approveRevoke(XskhDisciplineRevokeBo bo);
|
||||
|
||||
/**
|
||||
* 查询班主任班级的违纪撤销申请列表(班主任专用)
|
||||
*/
|
||||
TableDataInfo<XskhDisciplineRevokeVo> queryClassTeacherPageList(XskhDisciplineRevokeBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询班主任已审核的违纪撤销申请列表(根据审核人查询历史记录)
|
||||
*/
|
||||
TableDataInfo<XskhDisciplineRevokeVo> queryClassTeacherReviewedPageList(XskhDisciplineRevokeBo bo,
|
||||
PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 班主任审核撤销申请
|
||||
*/
|
||||
Boolean classTeacherApproveRevoke(XskhDisciplineRevokeBo bo);
|
||||
Boolean teacherApproveRevoke(XskhDisciplineRevokeBo bo);
|
||||
|
||||
/**
|
||||
* 查询学工处待审核的撤销申请列表(学工处专用)
|
||||
*/
|
||||
TableDataInfo<XskhDisciplineRevokeVo> queryStudentAffairsPageList(XskhDisciplineRevokeBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 学工处审核撤销申请
|
||||
*/
|
||||
Boolean studentAffairsApproveRevoke(XskhDisciplineRevokeBo bo);
|
||||
|
||||
/**
|
||||
* 查询学工处已审核的撤销申请列表(学工处专用)
|
||||
*/
|
||||
TableDataInfo<XskhDisciplineRevokeVo> queryStudentAffairsReviewedPageList(XskhDisciplineRevokeBo bo,
|
||||
PageQuery pageQuery);
|
||||
|
||||
}
|
||||
Loaded 100 of 244 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user