提交
This commit is contained in:
1 parent
8b6d1e5be8
commit
9e6cccf846
23 files changed
+2658
-67
No files matched your search
+111
@@ -0,0 +1,111 @@
|
||||
package org.dromara.xg.controller;
|
||||
|
||||
import java.util.List;
|
||||
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.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
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.xg.domain.vo.XgConductScoreAuditVo;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreAuditQueryBo;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreAuditApproveBo;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreAuditRejectBo;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreAuditBatchBo;
|
||||
import org.dromara.xg.service.IXgConductScoreAuditService;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 操行分审核
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-01-16
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/xg/conduct-score-audit")
|
||||
public class XgConductScoreAuditController extends BaseController {
|
||||
|
||||
private final IXgConductScoreAuditService xgConductScoreAuditService;
|
||||
|
||||
/**
|
||||
* 查询操行分审核列表
|
||||
*/
|
||||
// @SaCheckPermission("xg:conductScoreAudit:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<XgConductScoreAuditVo> list(XgConductScoreAuditQueryBo bo, PageQuery pageQuery) {
|
||||
return xgConductScoreAuditService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取操行分审核详细信息
|
||||
*
|
||||
* @param id 主键
|
||||
*/
|
||||
// @SaCheckPermission("xg:conductScoreAudit:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<XgConductScoreAuditVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
|
||||
return R.ok(xgConductScoreAuditService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 审核通过
|
||||
*/
|
||||
// @SaCheckPermission("xg:conductScoreAudit:approve")
|
||||
@Log(title = "操行分审核", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/approve/{id}")
|
||||
public R<Void> approve(@NotNull(message = "审核ID不能为空") @PathVariable Long id,
|
||||
@Validated @RequestBody XgConductScoreAuditApproveBo bo) {
|
||||
return toAjax(xgConductScoreAuditService.approveAudit(id, bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 审核驳回
|
||||
*/
|
||||
// @SaCheckPermission("xg:conductScoreAudit:reject")
|
||||
@Log(title = "操行分审核", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/reject/{id}")
|
||||
public R<Void> reject(@NotNull(message = "审核ID不能为空") @PathVariable Long id,
|
||||
@Validated @RequestBody XgConductScoreAuditRejectBo bo) {
|
||||
return toAjax(xgConductScoreAuditService.rejectAudit(id, bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量审核通过
|
||||
*/
|
||||
// @SaCheckPermission("xg:conductScoreAudit:batchApprove")
|
||||
@Log(title = "操行分审核", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/batch-approve")
|
||||
public R<Void> batchApprove(@Validated @RequestBody XgConductScoreAuditBatchBo bo) {
|
||||
return toAjax(xgConductScoreAuditService.batchApproveAudit(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量审核驳回
|
||||
*/
|
||||
// @SaCheckPermission("xg:conductScoreAudit:batchReject")
|
||||
@Log(title = "操行分审核", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/batch-reject")
|
||||
public R<Void> batchReject(@Validated @RequestBody XgConductScoreAuditBatchBo bo) {
|
||||
return toAjax(xgConductScoreAuditService.batchRejectAudit(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除操行分审核
|
||||
*/
|
||||
// @SaCheckPermission("xg:conductScoreAudit:remove")
|
||||
@Log(title = "操行分审核", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
|
||||
return toAjax(xgConductScoreAuditService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
|
||||
}
|
||||
+12
@@ -29,6 +29,7 @@ import org.dromara.xg.domain.vo.XgConductScoreSemesterAverageExportVo;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreBo;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreQueryBo;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreBatchBo;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreBatchUpdateBo;
|
||||
import org.dromara.xg.domain.vo.XgConductScoreBatchResultVo;
|
||||
import org.dromara.xg.domain.vo.XgConductScoreClassSummaryVo;
|
||||
import org.dromara.xg.domain.vo.XgConductScoreSemesterAverageVo;
|
||||
@@ -105,6 +106,17 @@ public class XgConductScoreController extends BaseController {
|
||||
return R.ok(xgConductScoreService.batchInsertConductScores(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量提交修改审核
|
||||
*/
|
||||
// @SaCheckPermission("xg:conductScore:batchUpdate")
|
||||
@RepeatSubmit()
|
||||
@Log(title = "学生操行分", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/batch-update")
|
||||
public R<XgConductScoreBatchResultVo> batchUpdate(@Validated @RequestBody XgConductScoreBatchUpdateBo bo) {
|
||||
return R.ok(xgConductScoreService.batchUpdateConductScores(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询学生操行分列表
|
||||
*/
|
||||
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
package org.dromara.xg.domain;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 操行分审核对象 xg_conduct_score_audit
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-01-16
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class XgConductScoreAudit extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 主键ID */
|
||||
private Long id;
|
||||
|
||||
/** 租户ID */
|
||||
private String tenantId;
|
||||
|
||||
/** 学生ID */
|
||||
private Long studentId;
|
||||
|
||||
/** 学年 */
|
||||
private Integer academicYear;
|
||||
|
||||
/** 学期:1-第一学期,2-第二学期 */
|
||||
private Integer semester;
|
||||
|
||||
/** 月份 */
|
||||
private Integer month;
|
||||
|
||||
/** 班级ID */
|
||||
private Long classId;
|
||||
|
||||
/** 原分数 */
|
||||
private BigDecimal oldScore;
|
||||
|
||||
/** 原备注 */
|
||||
private String oldRemark;
|
||||
|
||||
/** 新分数 */
|
||||
private BigDecimal newScore;
|
||||
|
||||
/** 新备注 */
|
||||
private String newRemark;
|
||||
|
||||
/** 申请人ID */
|
||||
private Long applyUserId;
|
||||
|
||||
/** 申请人姓名 */
|
||||
private String applyUserName;
|
||||
|
||||
/** 申请时间 */
|
||||
private Date applyTime;
|
||||
|
||||
/** 申请理由 */
|
||||
private String applyReason;
|
||||
|
||||
/** 审核状态:0-待审核,1-审核通过,2-审核驳回 */
|
||||
private Integer auditStatus;
|
||||
|
||||
/** 审核人ID */
|
||||
private Long auditUserId;
|
||||
|
||||
/** 审核人姓名 */
|
||||
private String auditUserName;
|
||||
|
||||
/** 审核时间 */
|
||||
private Date auditTime;
|
||||
|
||||
/** 审核备注 */
|
||||
private String auditRemark;
|
||||
|
||||
/** 删除标志 */
|
||||
private Integer deleted;
|
||||
|
||||
/** 创建部门(审核表不需要此字段) */
|
||||
@TableField(exist = false)
|
||||
private Long createDept;
|
||||
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package org.dromara.xg.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
* 操行分审核审批业务对象
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-01-16
|
||||
*/
|
||||
@Data
|
||||
public class XgConductScoreAuditApproveBo {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 审核备注
|
||||
*/
|
||||
@Size(max = 200, message = "审核备注不能超过200个字符")
|
||||
private String auditRemark;
|
||||
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package org.dromara.xg.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 操行分批量审核业务对象
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-01-16
|
||||
*/
|
||||
@Data
|
||||
public class XgConductScoreAuditBatchBo {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 审核记录ID列表
|
||||
*/
|
||||
@NotEmpty(message = "审核记录ID不能为空")
|
||||
private List<Long> ids;
|
||||
|
||||
/**
|
||||
* 审核备注
|
||||
*/
|
||||
@Size(max = 200, message = "审核备注不能超过200个字符")
|
||||
private String auditRemark;
|
||||
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
package org.dromara.xg.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
/**
|
||||
* 操行分审核查询业务对象
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-01-16
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class XgConductScoreAuditQueryBo extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 学生ID
|
||||
*/
|
||||
private Long studentId;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
private String studentName;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
private String studentNo;
|
||||
|
||||
|
||||
/**
|
||||
* 班级ID
|
||||
*/
|
||||
private Long classId;
|
||||
|
||||
/**
|
||||
* 班级名称
|
||||
*/
|
||||
private String className;
|
||||
|
||||
/**
|
||||
* 申请人ID
|
||||
*/
|
||||
private Long applyUserId;
|
||||
|
||||
/**
|
||||
* 申请人姓名
|
||||
*/
|
||||
private String applyUserName;
|
||||
|
||||
/**
|
||||
* 审核状态:0-待审核,1-审核通过,2-审核驳回
|
||||
*/
|
||||
private Integer auditStatus;
|
||||
|
||||
/**
|
||||
* 审核人ID
|
||||
*/
|
||||
private Long auditUserId;
|
||||
|
||||
/**
|
||||
* 审核人姓名
|
||||
*/
|
||||
private String auditUserName;
|
||||
|
||||
/**
|
||||
* 申请开始时间
|
||||
*/
|
||||
private String applyBeginTime;
|
||||
|
||||
/**
|
||||
* 申请结束时间
|
||||
*/
|
||||
private String applyEndTime;
|
||||
|
||||
/**
|
||||
* 审核开始时间
|
||||
*/
|
||||
private String auditBeginTime;
|
||||
|
||||
/**
|
||||
* 审核结束时间
|
||||
*/
|
||||
private String auditEndTime;
|
||||
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package org.dromara.xg.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
* 操行分审核驳回业务对象
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-01-16
|
||||
*/
|
||||
@Data
|
||||
public class XgConductScoreAuditRejectBo {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 审核备注
|
||||
*/
|
||||
@Size(max = 200, message = "审核备注不能超过200个字符")
|
||||
private String auditRemark;
|
||||
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package org.dromara.xg.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 学生操行分批量修改审核业务对象
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-01-16
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class XgConductScoreBatchUpdateBo {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 学年
|
||||
*/
|
||||
@NotNull(message = "学年不能为空")
|
||||
private Integer academicYear;
|
||||
|
||||
/**
|
||||
* 学期
|
||||
*/
|
||||
@NotNull(message = "学期不能为空")
|
||||
private Integer semester;
|
||||
|
||||
/**
|
||||
* 月份
|
||||
*/
|
||||
@NotNull(message = "月份不能为空")
|
||||
private Integer month;
|
||||
|
||||
/**
|
||||
* 班级ID(前端传递字符串避免精度问题)
|
||||
*/
|
||||
private String classId;
|
||||
|
||||
/**
|
||||
* 修改分数列表
|
||||
*/
|
||||
private List<XgConductScoreBatchUpdateItemBo> scores;
|
||||
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package org.dromara.xg.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import jakarta.validation.constraints.*;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 学生操行分批量修改审核项业务对象
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-01-16
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class XgConductScoreBatchUpdateItemBo {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 学生ID
|
||||
*/
|
||||
@NotNull(message = "学生ID不能为空")
|
||||
private Long studentId;
|
||||
|
||||
/**
|
||||
* 新分数
|
||||
*/
|
||||
@NotNull(message = "分数不能为空")
|
||||
@DecimalMin(value = "0", message = "分数不能小于0")
|
||||
@DecimalMax(value = "100", message = "分数不能大于100")
|
||||
private BigDecimal score;
|
||||
|
||||
/**
|
||||
* 新备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
package org.dromara.xg.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import org.dromara.xg.domain.XgConductScoreAudit;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
|
||||
/**
|
||||
* 操行分审核视图对象
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-01-16
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = XgConductScoreAudit.class)
|
||||
public class XgConductScoreAuditVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 学生ID
|
||||
*/
|
||||
private Long studentId;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
private String studentName;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 学年
|
||||
*/
|
||||
private Integer academicYear;
|
||||
|
||||
/**
|
||||
* 学期
|
||||
*/
|
||||
private Integer semester;
|
||||
|
||||
/**
|
||||
* 月份
|
||||
*/
|
||||
private Integer month;
|
||||
|
||||
/**
|
||||
* 班级ID
|
||||
*/
|
||||
private Long classId;
|
||||
|
||||
/**
|
||||
* 班级名称
|
||||
*/
|
||||
private String className;
|
||||
|
||||
/**
|
||||
* 原分数
|
||||
*/
|
||||
private BigDecimal oldScore;
|
||||
|
||||
/**
|
||||
* 原备注
|
||||
*/
|
||||
private String oldRemark;
|
||||
|
||||
/**
|
||||
* 新分数
|
||||
*/
|
||||
private BigDecimal newScore;
|
||||
|
||||
/**
|
||||
* 新备注
|
||||
*/
|
||||
private String newRemark;
|
||||
|
||||
/**
|
||||
* 申请人ID
|
||||
*/
|
||||
private Long applyUserId;
|
||||
|
||||
/**
|
||||
* 申请人姓名
|
||||
*/
|
||||
private String applyUserName;
|
||||
|
||||
/**
|
||||
* 申请时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date applyTime;
|
||||
|
||||
/**
|
||||
* 申请理由
|
||||
*/
|
||||
private String applyReason;
|
||||
|
||||
/**
|
||||
* 审核状态:0-待审核,1-审核通过,2-审核驳回
|
||||
*/
|
||||
private Integer auditStatus;
|
||||
|
||||
/**
|
||||
* 审核人ID
|
||||
*/
|
||||
private Long auditUserId;
|
||||
|
||||
/**
|
||||
* 审核人姓名
|
||||
*/
|
||||
private String auditUserName;
|
||||
|
||||
/**
|
||||
* 审核时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date auditTime;
|
||||
|
||||
/**
|
||||
* 审核备注
|
||||
*/
|
||||
private String auditRemark;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
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;
|
||||
|
||||
}
|
||||
+55
-17
@@ -71,7 +71,8 @@ public class XgConductScoreImportListener extends AnalysisEventListener<XgConduc
|
||||
List<XgStudentMsgVo> students = studentMsgService.queryList(queryBo);
|
||||
if (students == null || students.isEmpty()) {
|
||||
failureNum++;
|
||||
failureMsg.append("<br/>").append(failureNum).append("、学号 ").append(importVo.getStudentNo()).append(" 不存在");
|
||||
failureMsg.append("<br/>").append(failureNum).append("、学号 ").append(importVo.getStudentNo())
|
||||
.append(" 不存在");
|
||||
return;
|
||||
}
|
||||
XgStudentMsgVo student = students.get(0);
|
||||
@@ -80,34 +81,70 @@ public class XgConductScoreImportListener extends AnalysisEventListener<XgConduc
|
||||
if (!importVo.getStudentName().equals(student.getName())) {
|
||||
failureNum++;
|
||||
failureMsg.append("<br/>").append(failureNum).append("、学号 ").append(importVo.getStudentNo())
|
||||
.append(" 姓名不匹配,Excel中:").append(importVo.getStudentName())
|
||||
.append(",系统中:").append(student.getName());
|
||||
.append(" 姓名不匹配,Excel中:").append(importVo.getStudentName())
|
||||
.append(",系统中:").append(student.getName());
|
||||
return;
|
||||
}
|
||||
|
||||
// 4. 验证班级权限(如果指定了班级)
|
||||
if (StringUtils.isNotBlank(classId) && !classId.equals(student.getClassId())) {
|
||||
failureNum++;
|
||||
failureMsg.append("<br/>").append(failureNum).append("、学号 ").append(importVo.getStudentNo()).append(" 不属于指定班级");
|
||||
failureMsg.append("<br/>").append(failureNum).append("、学号 ").append(importVo.getStudentNo())
|
||||
.append(" 不属于指定班级");
|
||||
return;
|
||||
}
|
||||
|
||||
// 5. 检查是否已有记录
|
||||
XgConductScoreVo existingRecord = conductScoreService.selectByStudentAndTime(
|
||||
student.getId(), academicYear, semester, month);
|
||||
student.getId(), academicYear, semester, month);
|
||||
|
||||
if (existingRecord != null) {
|
||||
// 更新现有记录
|
||||
XgConductScoreBo updateBo = new XgConductScoreBo();
|
||||
updateBo.setId(existingRecord.getId());
|
||||
updateBo.setScore(java.math.BigDecimal.valueOf(importVo.getScore()));
|
||||
updateBo.setRemark(importVo.getRemark());
|
||||
updateBo.setUpdateBy(operUserId);
|
||||
conductScoreService.updateByBo(updateBo);
|
||||
// 检查数据是否发生变化
|
||||
boolean scoreChanged = !java.math.BigDecimal.valueOf(importVo.getScore())
|
||||
.equals(existingRecord.getScore());
|
||||
boolean remarkChanged = !StringUtils.equals(StringUtils.trim(importVo.getRemark()),
|
||||
StringUtils.trim(existingRecord.getRemark()));
|
||||
|
||||
successNum++;
|
||||
successMsg.append("<br/>").append(successNum).append("、学号 ").append(importVo.getStudentNo())
|
||||
.append(" 更新成功(覆盖原有分数 ").append(existingRecord.getScore()).append(" → ").append(importVo.getScore()).append(")");
|
||||
if (scoreChanged || remarkChanged) {
|
||||
// 数据有变化:提交审核
|
||||
try {
|
||||
// 构造审核数据
|
||||
org.dromara.xg.domain.bo.XgConductScoreBatchUpdateItemBo updateItem = new org.dromara.xg.domain.bo.XgConductScoreBatchUpdateItemBo()
|
||||
.setStudentId(student.getId())
|
||||
.setScore(java.math.BigDecimal.valueOf(importVo.getScore()))
|
||||
.setRemark(importVo.getRemark());
|
||||
|
||||
org.dromara.xg.domain.bo.XgConductScoreBatchUpdateBo batchUpdateBo = new org.dromara.xg.domain.bo.XgConductScoreBatchUpdateBo()
|
||||
.setAcademicYear(academicYear)
|
||||
.setSemester(semester)
|
||||
.setMonth(month)
|
||||
.setClassId(student.getClassId())
|
||||
.setScores(java.util.Arrays.asList(updateItem));
|
||||
|
||||
// 调用审核接口
|
||||
conductScoreService.batchUpdateConductScores(batchUpdateBo);
|
||||
|
||||
successNum++;
|
||||
successMsg.append("<br/>").append(successNum).append("、学号 ").append(importVo.getStudentNo())
|
||||
.append(" 提交审核(数据有变化)");
|
||||
} catch (Exception e) {
|
||||
failureNum++;
|
||||
failureMsg.append("<br/>").append(failureNum).append("、学号 ").append(importVo.getStudentNo())
|
||||
.append(" 提交审核失败:").append(e.getMessage());
|
||||
}
|
||||
} else {
|
||||
// 数据无变化:直接更新
|
||||
XgConductScoreBo updateBo = new XgConductScoreBo();
|
||||
updateBo.setId(existingRecord.getId());
|
||||
updateBo.setScore(java.math.BigDecimal.valueOf(importVo.getScore()));
|
||||
updateBo.setRemark(importVo.getRemark());
|
||||
updateBo.setUpdateBy(operUserId);
|
||||
conductScoreService.updateByBo(updateBo);
|
||||
|
||||
successNum++;
|
||||
successMsg.append("<br/>").append(successNum).append("、学号 ").append(importVo.getStudentNo())
|
||||
.append(" 更新成功(数据无变化)");
|
||||
}
|
||||
} else {
|
||||
// 插入新记录
|
||||
XgConductScoreBo insertBo = new XgConductScoreBo();
|
||||
@@ -124,7 +161,8 @@ public class XgConductScoreImportListener extends AnalysisEventListener<XgConduc
|
||||
conductScoreService.insertByBo(insertBo);
|
||||
|
||||
successNum++;
|
||||
successMsg.append("<br/>").append(successNum).append("、学号 ").append(importVo.getStudentNo()).append(" 导入成功");
|
||||
successMsg.append("<br/>").append(successNum).append("、学号 ").append(importVo.getStudentNo())
|
||||
.append(" 导入成功");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
@@ -197,4 +235,4 @@ public class XgConductScoreImportListener extends AnalysisEventListener<XgConduc
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package org.dromara.xg.mapper;
|
||||
|
||||
import org.dromara.xg.domain.XgConductScoreAudit;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreAuditQueryBo;
|
||||
import org.dromara.xg.domain.vo.XgConductScoreAuditVo;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 操行分审核Mapper接口
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-01-16
|
||||
*/
|
||||
public interface IXgConductScoreAuditMapper extends BaseMapperPlus<XgConductScoreAudit, XgConductScoreAuditVo> {
|
||||
|
||||
/**
|
||||
* 查询操行分审核列表(包含关联数据)
|
||||
*
|
||||
* @param queryBo 查询条件
|
||||
* @return 操行分审核列表
|
||||
*/
|
||||
List<XgConductScoreAuditVo> selectXgConductScoreAuditList(XgConductScoreAuditQueryBo queryBo);
|
||||
|
||||
/**
|
||||
* 根据审核ID列表批量更新审核状态
|
||||
*
|
||||
* @param ids 审核ID列表
|
||||
* @param auditStatus 审核状态
|
||||
* @param auditUserId 审核人ID
|
||||
* @param auditUserName 审核人姓名
|
||||
* @param auditRemark 审核备注
|
||||
* @return 影响行数
|
||||
*/
|
||||
int updateBatchAuditStatus(@Param("ids") List<Long> ids,
|
||||
@Param("auditStatus") Integer auditStatus,
|
||||
@Param("auditUserId") Long auditUserId,
|
||||
@Param("auditUserName") String auditUserName,
|
||||
@Param("auditRemark") String auditRemark);
|
||||
|
||||
/**
|
||||
* 根据审核ID将数据同步到正式表
|
||||
*
|
||||
* @param auditId 审核ID
|
||||
* @return 影响行数
|
||||
*/
|
||||
int syncToFormalTable(@Param("auditId") Long auditId);
|
||||
|
||||
}
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
package org.dromara.xg.service;
|
||||
|
||||
import org.dromara.xg.domain.XgConductScoreAudit;
|
||||
import org.dromara.xg.domain.vo.XgConductScoreAuditVo;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreAuditQueryBo;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreAuditApproveBo;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreAuditRejectBo;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreAuditBatchBo;
|
||||
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 Lion Li
|
||||
* @date 2025-01-16
|
||||
*/
|
||||
public interface IXgConductScoreAuditService {
|
||||
|
||||
/**
|
||||
* 查询操行分审核
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 操行分审核
|
||||
*/
|
||||
XgConductScoreAuditVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 分页查询操行分审核列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 操行分审核分页列表
|
||||
*/
|
||||
TableDataInfo<XgConductScoreAuditVo> queryPageList(XgConductScoreAuditQueryBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询符合条件的操行分审核列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 操行分审核列表
|
||||
*/
|
||||
List<XgConductScoreAuditVo> queryList(XgConductScoreAuditQueryBo bo);
|
||||
|
||||
/**
|
||||
* 新增操行分审核
|
||||
*
|
||||
* @param bo 操行分审核
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean insertByBo(Object bo);
|
||||
|
||||
/**
|
||||
* 修改操行分审核
|
||||
*
|
||||
* @param bo 操行分审核
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean updateByBo(Object bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除操行分审核信息
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否校验,true-删除前校验,false-直接删除
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 审核通过
|
||||
*
|
||||
* @param id 审核ID
|
||||
* @param bo 审核参数
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean approveAudit(Long id, XgConductScoreAuditApproveBo bo);
|
||||
|
||||
/**
|
||||
* 审核驳回
|
||||
*
|
||||
* @param id 审核ID
|
||||
* @param bo 审核参数
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean rejectAudit(Long id, XgConductScoreAuditRejectBo bo);
|
||||
|
||||
/**
|
||||
* 批量审核通过
|
||||
*
|
||||
* @param bo 批量审核参数
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean batchApproveAudit(XgConductScoreAuditBatchBo bo);
|
||||
|
||||
/**
|
||||
* 批量审核驳回
|
||||
*
|
||||
* @param bo 批量审核参数
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean batchRejectAudit(XgConductScoreAuditBatchBo bo);
|
||||
|
||||
/**
|
||||
* 批量提交修改审核
|
||||
*
|
||||
* @param auditList 审核记录列表
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean batchInsertAudits(List<XgConductScoreAudit> auditList);
|
||||
|
||||
}
|
||||
+9
@@ -4,6 +4,7 @@ import org.dromara.xg.domain.vo.XgConductScoreVo;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreBo;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreQueryBo;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreBatchBo;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreBatchUpdateBo;
|
||||
import org.dromara.xg.domain.vo.XgConductScoreBatchResultVo;
|
||||
import org.dromara.xg.domain.vo.XgConductScoreClassSummaryVo;
|
||||
import org.dromara.xg.domain.vo.XgConductScoreSemesterAverageVo;
|
||||
@@ -101,6 +102,14 @@ public interface IXgConductScoreService {
|
||||
*/
|
||||
XgConductScoreBatchResultVo batchInsertConductScores(XgConductScoreBatchBo bo);
|
||||
|
||||
/**
|
||||
* 批量提交修改审核
|
||||
*
|
||||
* @param bo 批量修改审核参数
|
||||
* @return 审核结果
|
||||
*/
|
||||
XgConductScoreBatchResultVo batchUpdateConductScores(XgConductScoreBatchUpdateBo bo);
|
||||
|
||||
/**
|
||||
* 获取班主任负责的班级学生列表
|
||||
*
|
||||
|
||||
+328
@@ -0,0 +1,328 @@
|
||||
package org.dromara.xg.service.impl;
|
||||
|
||||
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.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.ObjectUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.common.tenant.helper.TenantHelper;
|
||||
import org.dromara.xg.domain.XgConductScoreAudit;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreAuditQueryBo;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreAuditApproveBo;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreAuditRejectBo;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreAuditBatchBo;
|
||||
import org.dromara.xg.domain.vo.XgConductScoreAuditVo;
|
||||
import org.dromara.xg.mapper.IXgConductScoreAuditMapper;
|
||||
import org.dromara.xg.service.IXgConductScoreAuditService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 操行分审核Service业务层处理
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2025-01-16
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class XgConductScoreAuditServiceImpl implements IXgConductScoreAuditService {
|
||||
|
||||
private final IXgConductScoreAuditMapper xgConductScoreAuditMapper;
|
||||
|
||||
/**
|
||||
* 查询操行分审核
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 操行分审核
|
||||
*/
|
||||
@Override
|
||||
public XgConductScoreAuditVo queryById(Long id) {
|
||||
return xgConductScoreAuditMapper.selectVoById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询操行分审核列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 操行分审核分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<XgConductScoreAuditVo> queryPageList(XgConductScoreAuditQueryBo bo, PageQuery pageQuery) {
|
||||
// 设置租户ID
|
||||
if (StringUtils.isBlank(bo.getTenantId())) {
|
||||
bo.setTenantId(TenantHelper.getTenantId());
|
||||
}
|
||||
|
||||
// 设置默认审核状态为待审核
|
||||
if (bo.getAuditStatus() == null) {
|
||||
bo.setAuditStatus(0);
|
||||
}
|
||||
|
||||
// 使用自定义查询方法,支持关联查询
|
||||
List<XgConductScoreAuditVo> list = xgConductScoreAuditMapper.selectXgConductScoreAuditList(bo);
|
||||
|
||||
// 手动分页(因为使用了自定义SQL查询)
|
||||
int total = list.size();
|
||||
int startIndex = (pageQuery.getPageNum() - 1) * pageQuery.getPageSize();
|
||||
int endIndex = Math.min(startIndex + pageQuery.getPageSize(), total);
|
||||
|
||||
List<XgConductScoreAuditVo> pageList = new ArrayList<>();
|
||||
if (startIndex < total) {
|
||||
pageList = list.subList(startIndex, endIndex);
|
||||
}
|
||||
|
||||
return new TableDataInfo<>(pageList, total);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询符合条件的操行分审核列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 操行分审核列表
|
||||
*/
|
||||
@Override
|
||||
public List<XgConductScoreAuditVo> queryList(XgConductScoreAuditQueryBo bo) {
|
||||
return xgConductScoreAuditMapper.selectXgConductScoreAuditList(bo);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 新增操行分审核
|
||||
*
|
||||
* @param bo 操行分审核
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(Object bo) {
|
||||
XgConductScoreAudit audit = MapstructUtils.convert(bo, XgConductScoreAudit.class);
|
||||
validEntityBeforeSave(audit);
|
||||
return xgConductScoreAuditMapper.insert(audit) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改操行分审核
|
||||
*
|
||||
* @param bo 操行分审核
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(Object bo) {
|
||||
XgConductScoreAudit audit = MapstructUtils.convert(bo, XgConductScoreAudit.class);
|
||||
validEntityBeforeSave(audit);
|
||||
return xgConductScoreAuditMapper.updateById(audit) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验并批量删除操行分审核信息
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否校验,true-删除前校验,false-直接删除
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// 只能删除待审核状态的记录
|
||||
LambdaQueryWrapper<XgConductScoreAudit> lqw = Wrappers.lambdaQuery();
|
||||
lqw.in(XgConductScoreAudit::getId, ids);
|
||||
lqw.ne(XgConductScoreAudit::getAuditStatus, 0);
|
||||
if (xgConductScoreAuditMapper.exists(lqw)) {
|
||||
throw new ServiceException("只能删除待审核状态的记录");
|
||||
}
|
||||
}
|
||||
return xgConductScoreAuditMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 审核通过
|
||||
*
|
||||
* @param id 审核ID
|
||||
* @param bo 审核参数
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean approveAudit(Long id, XgConductScoreAuditApproveBo bo) {
|
||||
// 1. 更新审核记录状态
|
||||
XgConductScoreAudit audit = new XgConductScoreAudit();
|
||||
audit.setId(id);
|
||||
audit.setAuditStatus(1); // 审核通过
|
||||
audit.setAuditUserId(LoginHelper.getUserId());
|
||||
audit.setAuditUserName(LoginHelper.getUsername());
|
||||
audit.setAuditTime(new Date());
|
||||
audit.setAuditRemark(bo.getAuditRemark());
|
||||
audit.setUpdateBy(LoginHelper.getUserId());
|
||||
audit.setUpdateTime(new Date());
|
||||
|
||||
int updateCount = xgConductScoreAuditMapper.updateById(audit);
|
||||
if (updateCount <= 0) {
|
||||
throw new ServiceException("审核记录不存在或状态已变更");
|
||||
}
|
||||
|
||||
// 2. 同步数据到正式表
|
||||
int syncCount = xgConductScoreAuditMapper.syncToFormalTable(id);
|
||||
if (syncCount <= 0) {
|
||||
throw new ServiceException("同步数据到正式表失败");
|
||||
}
|
||||
|
||||
log.info("审核通过成功,审核ID: {}, 同步记录数: {}", id, syncCount);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 审核驳回
|
||||
*
|
||||
* @param id 审核ID
|
||||
* @param bo 审核参数
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public Boolean rejectAudit(Long id, XgConductScoreAuditRejectBo bo) {
|
||||
XgConductScoreAudit audit = new XgConductScoreAudit();
|
||||
audit.setId(id);
|
||||
audit.setAuditStatus(2); // 审核驳回
|
||||
audit.setAuditUserId(LoginHelper.getUserId());
|
||||
audit.setAuditUserName(LoginHelper.getUsername());
|
||||
audit.setAuditTime(new Date());
|
||||
audit.setAuditRemark(bo.getAuditRemark());
|
||||
audit.setUpdateBy(LoginHelper.getUserId());
|
||||
audit.setUpdateTime(new Date());
|
||||
|
||||
int updateCount = xgConductScoreAuditMapper.updateById(audit);
|
||||
if (updateCount <= 0) {
|
||||
throw new ServiceException("审核记录不存在或状态已变更");
|
||||
}
|
||||
|
||||
log.info("审核驳回成功,审核ID: {}", id);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量审核通过
|
||||
*
|
||||
* @param bo 批量审核参数
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean batchApproveAudit(XgConductScoreAuditBatchBo bo) {
|
||||
Long auditUserId = LoginHelper.getUserId();
|
||||
String auditUserName = LoginHelper.getUsername();
|
||||
String auditRemark = bo.getAuditRemark();
|
||||
|
||||
// 批量更新审核状态
|
||||
int updateCount = xgConductScoreAuditMapper.updateBatchAuditStatus(
|
||||
bo.getIds(), 1, auditUserId, auditUserName, auditRemark);
|
||||
|
||||
if (updateCount != bo.getIds().size()) {
|
||||
throw new ServiceException("部分审核记录不存在或状态已变更");
|
||||
}
|
||||
|
||||
// 批量同步数据到正式表
|
||||
for (Long auditId : bo.getIds()) {
|
||||
int syncCount = xgConductScoreAuditMapper.syncToFormalTable(auditId);
|
||||
if (syncCount <= 0) {
|
||||
throw new ServiceException("同步数据到正式表失败,审核ID: " + auditId);
|
||||
}
|
||||
}
|
||||
|
||||
log.info("批量审核通过成功,审核ID数量: {}", bo.getIds().size());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量审核驳回
|
||||
*
|
||||
* @param bo 批量审核参数
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public Boolean batchRejectAudit(XgConductScoreAuditBatchBo bo) {
|
||||
Long auditUserId = LoginHelper.getUserId();
|
||||
String auditUserName = LoginHelper.getUsername();
|
||||
String auditRemark = bo.getAuditRemark();
|
||||
|
||||
int updateCount = xgConductScoreAuditMapper.updateBatchAuditStatus(
|
||||
bo.getIds(), 2, auditUserId, auditUserName, auditRemark);
|
||||
|
||||
if (updateCount != bo.getIds().size()) {
|
||||
throw new ServiceException("部分审核记录不存在或状态已变更");
|
||||
}
|
||||
|
||||
log.info("批量审核驳回成功,审核ID数量: {}", bo.getIds().size());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量提交修改审核
|
||||
*
|
||||
* @param auditList 审核记录列表
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public Boolean batchInsertAudits(List<XgConductScoreAudit> auditList) {
|
||||
if (auditList == null || auditList.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 批量验证
|
||||
for (XgConductScoreAudit audit : auditList) {
|
||||
validEntityBeforeSave(audit);
|
||||
}
|
||||
|
||||
// 批量插入
|
||||
xgConductScoreAuditMapper.insertBatch(auditList);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(XgConductScoreAudit entity) {
|
||||
// 基础字段校验
|
||||
if (entity.getStudentId() == null) {
|
||||
throw new ServiceException("学生ID不能为空");
|
||||
}
|
||||
if (entity.getAcademicYear() == null) {
|
||||
throw new ServiceException("学年不能为空");
|
||||
}
|
||||
if (entity.getSemester() == null) {
|
||||
throw new ServiceException("学期不能为空");
|
||||
}
|
||||
if (entity.getMonth() == null) {
|
||||
throw new ServiceException("月份不能为空");
|
||||
}
|
||||
if (entity.getClassId() == null) {
|
||||
throw new ServiceException("班级ID不能为空");
|
||||
}
|
||||
if (entity.getNewScore() == null) {
|
||||
throw new ServiceException("新分数不能为空");
|
||||
}
|
||||
if (entity.getApplyUserId() == null) {
|
||||
throw new ServiceException("申请人ID不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(entity.getApplyUserName())) {
|
||||
throw new ServiceException("申请人姓名不能为空");
|
||||
}
|
||||
|
||||
// 分数范围校验
|
||||
if (entity.getNewScore().compareTo(BigDecimal.ZERO) < 0 ||
|
||||
entity.getNewScore().compareTo(new BigDecimal("100")) > 0) {
|
||||
throw new ServiceException("分数必须在0-100之间");
|
||||
}
|
||||
}
|
||||
}
|
||||
+110
@@ -17,10 +17,12 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.common.tenant.helper.TenantHelper;
|
||||
import org.dromara.xg.domain.XgConductScore;
|
||||
import org.dromara.xg.domain.XgConductScoreAudit;
|
||||
import org.dromara.xg.domain.XgClassMsg;
|
||||
import org.dromara.xg.domain.XgStudentManager;
|
||||
import org.dromara.xg.domain.XgStudentManagerSource;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreBatchBo;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreBatchUpdateBo;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreQueryBo;
|
||||
import org.dromara.xg.domain.bo.XgConductScoreBo;
|
||||
import org.dromara.xg.domain.vo.XgConductScoreBatchResultVo;
|
||||
@@ -38,6 +40,7 @@ import org.dromara.xg.mapper.XgClassMsgMapper;
|
||||
import org.dromara.xg.mapper.XgStudentManagerMapper;
|
||||
import org.dromara.xg.mapper.XgStudentManagerSourceMapper;
|
||||
import org.dromara.xg.service.IXgConductScoreService;
|
||||
import org.dromara.xg.service.IXgConductScoreAuditService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -69,6 +72,7 @@ public class XgConductScoreServiceImpl implements IXgConductScoreService {
|
||||
private final XgStudentManagerSourceMapper xgStudentManagerSourceMapper;
|
||||
private final XgClassMsgMapper xgClassMsgMapper;
|
||||
private final SysDeptMapper sysDeptMapper;
|
||||
private final IXgConductScoreAuditService auditService;
|
||||
|
||||
/**
|
||||
* 查询学生操行分
|
||||
@@ -383,6 +387,112 @@ public class XgConductScoreServiceImpl implements IXgConductScoreService {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量提交修改审核
|
||||
*
|
||||
* @param bo 批量修改审核参数
|
||||
* @return 审核结果
|
||||
*/
|
||||
@Override
|
||||
public XgConductScoreBatchResultVo batchUpdateConductScores(XgConductScoreBatchUpdateBo bo) {
|
||||
Long teacherId = LoginHelper.getUserId();
|
||||
String tenantId = TenantHelper.getTenantId();
|
||||
|
||||
// 将String类型的classId转换为Long
|
||||
Long classId = Long.valueOf(bo.getClassId());
|
||||
|
||||
// 校验班主任权限
|
||||
if (!checkTeacherPermission(classId, teacherId)) {
|
||||
throw new ServiceException("您不是该班级的班主任,无权修改操行分");
|
||||
}
|
||||
|
||||
List<String> failList = new ArrayList<>();
|
||||
int successCount = 0;
|
||||
int failCount = 0;
|
||||
|
||||
List<XgConductScoreAudit> auditList = new ArrayList<>();
|
||||
|
||||
for (var item : bo.getScores()) {
|
||||
try {
|
||||
// 校验分数范围
|
||||
if (item.getScore().compareTo(BigDecimal.ZERO) < 0
|
||||
|| item.getScore().compareTo(new BigDecimal("100.00")) > 0) {
|
||||
failList.add("学生ID:" + item.getStudentId() + " - 分数范围错误");
|
||||
failCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查学生是否已存在当月记录
|
||||
if (!existsByStudentAndMonth(item.getStudentId(), bo.getAcademicYear(), bo.getSemester(), bo.getMonth(),
|
||||
tenantId)) {
|
||||
failList.add("学生ID:" + item.getStudentId() + " - 当月无历史分数记录,无法提交修改审核");
|
||||
failCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 查询现有的分数记录,获取原分数和备注
|
||||
XgConductScoreVo existingRecord = selectByStudentAndTime(item.getStudentId(),
|
||||
bo.getAcademicYear(), bo.getSemester(), bo.getMonth());
|
||||
|
||||
if (existingRecord == null) {
|
||||
failList.add("学生ID:" + item.getStudentId() + " - 未找到历史记录");
|
||||
failCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查是否有实际的修改(分数或备注不同)
|
||||
boolean hasScoreChange = !item.getScore().equals(existingRecord.getScore());
|
||||
boolean hasRemarkChange = !ObjectUtils.equals(item.getRemark(), existingRecord.getRemark());
|
||||
|
||||
if (!hasScoreChange && !hasRemarkChange) {
|
||||
failList.add("学生ID:" + item.getStudentId() + " - 无实际修改内容");
|
||||
failCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 创建审核记录
|
||||
XgConductScoreAudit audit = new XgConductScoreAudit();
|
||||
audit.setTenantId(tenantId);
|
||||
audit.setStudentId(item.getStudentId());
|
||||
audit.setAcademicYear(bo.getAcademicYear());
|
||||
audit.setSemester(bo.getSemester());
|
||||
audit.setMonth(bo.getMonth());
|
||||
audit.setClassId(classId);
|
||||
audit.setOldScore(existingRecord.getScore());
|
||||
audit.setOldRemark(existingRecord.getRemark());
|
||||
audit.setNewScore(item.getScore());
|
||||
audit.setNewRemark(item.getRemark());
|
||||
audit.setApplyUserId(teacherId);
|
||||
audit.setApplyUserName(LoginHelper.getUsername());
|
||||
audit.setApplyTime(new Date());
|
||||
audit.setApplyReason("班主任修改操行分");
|
||||
audit.setAuditStatus(0); // 待审核
|
||||
audit.setCreateBy(teacherId);
|
||||
audit.setCreateTime(new Date());
|
||||
|
||||
auditList.add(audit);
|
||||
successCount++;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("处理学生操行分修改审核失败,学生ID: {}", item.getStudentId(), e);
|
||||
failList.add("学生ID:" + item.getStudentId() + " - 处理失败: " + e.getMessage());
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// 批量提交审核
|
||||
if (!auditList.isEmpty()) {
|
||||
auditService.batchInsertAudits(auditList);
|
||||
}
|
||||
|
||||
XgConductScoreBatchResultVo result = new XgConductScoreBatchResultVo();
|
||||
result.setSuccessCount(successCount);
|
||||
result.setFailCount(failCount);
|
||||
result.setFailList(failList);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取班主任负责的班级学生列表
|
||||
*
|
||||
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
<?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.IXgConductScoreAuditMapper">
|
||||
|
||||
<resultMap type="org.dromara.xg.domain.vo.XgConductScoreAuditVo" id="XgConductScoreAuditResult">
|
||||
<result property="id" column="id"/>
|
||||
<result property="tenantId" column="tenant_id"/>
|
||||
<result property="studentId" column="student_id"/>
|
||||
<result property="studentName" column="student_name"/>
|
||||
<result property="studentNo" column="student_no"/>
|
||||
<result property="academicYear" column="academic_year"/>
|
||||
<result property="semester" column="semester"/>
|
||||
<result property="month" column="month"/>
|
||||
<result property="classId" column="class_id"/>
|
||||
<result property="className" column="class_name"/>
|
||||
<result property="oldScore" column="old_score"/>
|
||||
<result property="oldRemark" column="old_remark"/>
|
||||
<result property="newScore" column="new_score"/>
|
||||
<result property="newRemark" column="new_remark"/>
|
||||
<result property="applyUserId" column="apply_user_id"/>
|
||||
<result property="applyUserName" column="apply_user_name"/>
|
||||
<result property="applyTime" column="apply_time"/>
|
||||
<result property="applyReason" column="apply_reason"/>
|
||||
<result property="auditStatus" column="audit_status"/>
|
||||
<result property="auditUserId" column="audit_user_id"/>
|
||||
<result property="auditUserName" column="audit_user_name"/>
|
||||
<result property="auditTime" column="audit_time"/>
|
||||
<result property="auditRemark" column="audit_remark"/>
|
||||
<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>
|
||||
|
||||
<!-- 查询审核列表(包含关联数据) -->
|
||||
<select id="selectXgConductScoreAuditList" parameterType="org.dromara.xg.domain.bo.XgConductScoreAuditQueryBo" resultMap="XgConductScoreAuditResult">
|
||||
SELECT
|
||||
a.id,
|
||||
a.tenant_id,
|
||||
a.student_id,
|
||||
sm.name AS student_name,
|
||||
sm.student_no,
|
||||
a.academic_year,
|
||||
a.semester,
|
||||
a.month,
|
||||
a.class_id,
|
||||
cm.class_name,
|
||||
a.old_score,
|
||||
a.old_remark,
|
||||
a.new_score,
|
||||
a.new_remark,
|
||||
a.apply_user_id,
|
||||
a.apply_user_name,
|
||||
a.apply_time,
|
||||
a.apply_reason,
|
||||
a.audit_status,
|
||||
a.audit_user_id,
|
||||
a.audit_user_name,
|
||||
a.audit_time,
|
||||
a.audit_remark,
|
||||
a.create_by,
|
||||
a.create_time,
|
||||
a.update_by,
|
||||
a.update_time
|
||||
FROM xg_conduct_score_audit a
|
||||
LEFT JOIN xg_student_msg sm ON a.student_id = sm.id AND sm.deleted = 0
|
||||
LEFT JOIN xg_class_msg cm ON a.class_id = cm.id AND cm.deleted = 0
|
||||
<where>
|
||||
a.deleted = 0
|
||||
<if test="tenantId != null">
|
||||
AND a.tenant_id = #{tenantId}
|
||||
</if>
|
||||
<if test="studentId != null">
|
||||
AND a.student_id = #{studentId}
|
||||
</if>
|
||||
<if test="studentName != null and studentName != ''">
|
||||
AND sm.name LIKE CONCAT('%', #{studentName}, '%')
|
||||
</if>
|
||||
<if test="studentNo != null and studentNo != ''">
|
||||
AND sm.student_no LIKE CONCAT('%', #{studentNo}, '%')
|
||||
</if>
|
||||
<if test="classId != null">
|
||||
AND a.class_id = #{classId}
|
||||
</if>
|
||||
<if test="className != null and className != ''">
|
||||
AND cm.class_name LIKE CONCAT('%', #{className}, '%')
|
||||
</if>
|
||||
<if test="applyUserId != null">
|
||||
AND a.apply_user_id = #{applyUserId}
|
||||
</if>
|
||||
<if test="applyUserName != null and applyUserName != ''">
|
||||
AND a.apply_user_name LIKE CONCAT('%', #{applyUserName}, '%')
|
||||
</if>
|
||||
<if test="auditStatus != null">
|
||||
AND a.audit_status = #{auditStatus}
|
||||
</if>
|
||||
<if test="auditUserId != null">
|
||||
AND a.audit_user_id = #{auditUserId}
|
||||
</if>
|
||||
<if test="auditUserName != null and auditUserName != ''">
|
||||
AND a.audit_user_name LIKE CONCAT('%', #{auditUserName}, '%')
|
||||
</if>
|
||||
<if test="applyBeginTime != null and applyEndTime != null">
|
||||
AND a.apply_time BETWEEN #{applyBeginTime} AND #{applyEndTime}
|
||||
</if>
|
||||
<if test="auditBeginTime != null and auditEndTime != null">
|
||||
AND a.audit_time BETWEEN #{auditBeginTime} AND #{auditEndTime}
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY a.apply_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 批量更新审核状态 -->
|
||||
<update id="updateBatchAuditStatus">
|
||||
UPDATE xg_conduct_score_audit
|
||||
SET
|
||||
audit_status = #{auditStatus},
|
||||
audit_user_id = #{auditUserId},
|
||||
audit_user_name = #{auditUserName},
|
||||
audit_time = NOW(),
|
||||
audit_remark = #{auditRemark},
|
||||
update_by = #{auditUserId},
|
||||
update_time = NOW()
|
||||
WHERE id IN
|
||||
<foreach item="id" collection="ids" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</update>
|
||||
|
||||
<!-- 同步审核数据到正式表 -->
|
||||
<update id="syncToFormalTable">
|
||||
UPDATE xg_conduct_score cs
|
||||
INNER JOIN xg_conduct_score_audit audit ON
|
||||
cs.student_id = audit.student_id
|
||||
AND cs.academic_year = audit.academic_year
|
||||
AND cs.semester = audit.semester
|
||||
AND cs.month = audit.month
|
||||
AND cs.tenant_id = audit.tenant_id
|
||||
AND cs.deleted = 0
|
||||
SET
|
||||
cs.score = audit.new_score,
|
||||
cs.remark = audit.new_remark,
|
||||
cs.update_by = audit.audit_user_id,
|
||||
cs.update_time = NOW()
|
||||
WHERE audit.id = #{auditId}
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,66 @@
|
||||
-- ----------------------------
|
||||
-- 操行分审核表
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `xg_conduct_score_audit`;
|
||||
CREATE TABLE `xg_conduct_score_audit` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`tenant_id` varchar(20) DEFAULT '000000' COMMENT '租户ID',
|
||||
`student_id` bigint(20) NOT NULL COMMENT '学生ID',
|
||||
`academic_year` int(11) NOT NULL COMMENT '学年',
|
||||
`semester` tinyint(1) NOT NULL COMMENT '学期:1-第一学期,2-第二学期',
|
||||
`month` tinyint(2) NOT NULL COMMENT '月份',
|
||||
`class_id` bigint(20) NOT NULL COMMENT '班级ID',
|
||||
`old_score` decimal(5,2) DEFAULT NULL COMMENT '原分数',
|
||||
`old_remark` varchar(500) DEFAULT NULL COMMENT '原备注',
|
||||
`new_score` decimal(5,2) NOT NULL COMMENT '新分数',
|
||||
`new_remark` varchar(500) DEFAULT NULL COMMENT '新备注',
|
||||
`apply_user_id` bigint(20) NOT NULL COMMENT '申请人ID',
|
||||
`apply_user_name` varchar(50) NOT NULL COMMENT '申请人姓名',
|
||||
`apply_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '申请时间',
|
||||
`apply_reason` varchar(200) DEFAULT NULL COMMENT '申请理由',
|
||||
`audit_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '审核状态:0-待审核,1-审核通过,2-审核驳回',
|
||||
`audit_user_id` bigint(20) DEFAULT NULL COMMENT '审核人ID',
|
||||
`audit_user_name` varchar(50) DEFAULT NULL COMMENT '审核人姓名',
|
||||
`audit_time` datetime DEFAULT NULL COMMENT '审核时间',
|
||||
`audit_remark` varchar(200) DEFAULT NULL COMMENT '审核备注',
|
||||
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`deleted` tinyint(1) DEFAULT '0' COMMENT '删除标志',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_student_period` (`student_id`,`academic_year`,`semester`,`month`,`deleted`),
|
||||
KEY `idx_class_period` (`class_id`,`academic_year`,`semester`,`month`),
|
||||
KEY `idx_audit_status` (`audit_status`,`apply_time`),
|
||||
KEY `idx_apply_user` (`apply_user_id`,`apply_time`),
|
||||
KEY `idx_audit_user` (`audit_user_id`,`audit_time`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='操行分审核表';
|
||||
|
||||
-- ----------------------------
|
||||
-- 为审核表添加必要的索引和约束
|
||||
-- ----------------------------
|
||||
ALTER TABLE `xg_conduct_score_audit`
|
||||
ADD CONSTRAINT `fk_audit_student` FOREIGN KEY (`student_id`) REFERENCES `xg_student_manager` (`student_id`) ON DELETE CASCADE,
|
||||
ADD CONSTRAINT `fk_audit_class` FOREIGN KEY (`class_id`) REFERENCES `xg_class_msg` (`class_id`) ON DELETE CASCADE,
|
||||
ADD CONSTRAINT `fk_audit_apply_user` FOREIGN KEY (`apply_user_id`) REFERENCES `sys_user` (`user_id`),
|
||||
ADD CONSTRAINT `fk_audit_user` FOREIGN KEY (`audit_user_id`) REFERENCES `sys_user` (`user_id`);
|
||||
|
||||
-- ----------------------------
|
||||
-- 初始化审核表数据(可选)
|
||||
-- ----------------------------
|
||||
-- 将现有操行分数据标记为已审核状态(如果需要)
|
||||
-- INSERT INTO xg_conduct_score_audit (
|
||||
-- tenant_id, student_id, academic_year, semester, month, class_id,
|
||||
-- old_score, old_remark, new_score, new_remark,
|
||||
-- apply_user_id, apply_user_name, apply_time, apply_reason,
|
||||
-- audit_status, audit_user_id, audit_user_name, audit_time, audit_remark,
|
||||
-- create_by, create_time, update_by, update_time, deleted
|
||||
-- )
|
||||
-- SELECT
|
||||
-- s.tenant_id, s.student_id, s.academic_year, s.semester, s.month, s.class_id,
|
||||
-- NULL as old_score, NULL as old_remark, s.score as new_score, s.remark as new_remark,
|
||||
-- s.class_teacher_id as apply_user_id, '系统导入' as apply_user_name, s.create_time as apply_time, '系统初始化' as apply_reason,
|
||||
-- 1 as audit_status, s.class_teacher_id as audit_user_id, '系统导入' as audit_user_name, s.create_time as audit_time, '系统初始化审核' as audit_remark,
|
||||
-- s.create_by, s.create_time, s.update_by, s.update_time, s.deleted
|
||||
-- FROM xg_conduct_score s
|
||||
-- WHERE s.deleted = 0;
|
||||
@@ -70,6 +70,15 @@ export function conductScoreBatchAdd(data: any) {
|
||||
});
|
||||
}
|
||||
|
||||
// 批量提交操行分修改审核
|
||||
export function conductScoreBatchUpdate(data: any) {
|
||||
return request({
|
||||
url: '/xg/conduct-score/batch-update',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 获取班主任负责的班级学生列表
|
||||
export function conductScoreClassStudents(query: any) {
|
||||
return request({
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import request from '@/utils/request';
|
||||
|
||||
// 查询操行分审核列表
|
||||
export function conductScoreAuditList(query: any) {
|
||||
return request({
|
||||
url: '/xg/conduct-score-audit/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
// 查询操行分审核详细
|
||||
export function conductScoreAuditInfo(id: any) {
|
||||
return request({
|
||||
url: '/xg/conduct-score-audit/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 审核通过
|
||||
export function conductScoreAuditApprove(id: any, data: any) {
|
||||
return request({
|
||||
url: '/xg/conduct-score-audit/approve/' + id,
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 审核驳回
|
||||
export function conductScoreAuditReject(id: any, data: any) {
|
||||
return request({
|
||||
url: '/xg/conduct-score-audit/reject/' + id,
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 批量审核通过
|
||||
export function conductScoreAuditBatchApprove(data: any) {
|
||||
return request({
|
||||
url: '/xg/conduct-score-audit/batch-approve',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 批量审核驳回
|
||||
export function conductScoreAuditBatchReject(data: any) {
|
||||
return request({
|
||||
url: '/xg/conduct-score-audit/batch-reject',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 导出操行分审核
|
||||
export function conductScoreAuditExport(query: any) {
|
||||
return request({
|
||||
url: '/xg/conduct-score-audit/export',
|
||||
method: 'post',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
// 获取审核统计
|
||||
export function conductScoreAuditStatistics(query: any) {
|
||||
return request({
|
||||
url: '/xg/conduct-score-audit/statistics',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,394 @@
|
||||
<template>
|
||||
<el-dialog v-model="visible" :title="dialogTitle" width="600px" append-to-body :before-close="handleClose">
|
||||
<div class="audit-dialog-content">
|
||||
<!-- 审核详情 -->
|
||||
<div v-if="dialogMode === 'view'" class="audit-detail">
|
||||
<div class="detail-section">
|
||||
<h4>学生信息</h4>
|
||||
<div class="info-grid">
|
||||
<div class="info-item">
|
||||
<label>学生姓名:</label>
|
||||
<span>{{ auditData.studentName }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>学号:</label>
|
||||
<span>{{ auditData.studentNo }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>班级:</label>
|
||||
<span>{{ auditData.className }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>学年学期:</label>
|
||||
<span>{{ auditData.academicYear - 1 }}-{{ auditData.academicYear }}学年 {{ auditData.semester === 1 ? '第一学期' : '第二学期' }} {{ auditData.month }}月</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-section">
|
||||
<h4>分数信息</h4>
|
||||
<div class="score-comparison">
|
||||
<div class="score-item old-score">
|
||||
<label>原分数:</label>
|
||||
<span class="score-value">{{ auditData.oldScore || 0 }}</span>
|
||||
</div>
|
||||
<div class="score-arrow">→</div>
|
||||
<div class="score-item new-score">
|
||||
<label>新分数:</label>
|
||||
<span class="score-value">{{ auditData.newScore || 0 }}</span>
|
||||
</div>
|
||||
<div class="score-change" v-if="auditData.newScore != null && auditData.oldScore != null">
|
||||
<el-tag :type="auditData.newScore > auditData.oldScore ? 'success' : auditData.newScore < auditData.oldScore ? 'danger' : 'info'" size="small">
|
||||
{{ auditData.newScore > auditData.oldScore ? '+' : '' }}{{ auditData.newScore - auditData.oldScore }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="remark-section" v-if="auditData.oldRemark || auditData.newRemark">
|
||||
<div class="remark-item" v-if="auditData.oldRemark">
|
||||
<label>原备注:</label>
|
||||
<span>{{ auditData.oldRemark }}</span>
|
||||
</div>
|
||||
<div class="remark-item" v-if="auditData.newRemark">
|
||||
<label>新备注:</label>
|
||||
<span>{{ auditData.newRemark }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-section">
|
||||
<h4>审核信息</h4>
|
||||
<div class="info-grid">
|
||||
<div class="info-item">
|
||||
<label>申请人:</label>
|
||||
<span>{{ auditData.applyUserName }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>申请时间:</label>
|
||||
<span>{{ parseTime(auditData.applyTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
||||
</div>
|
||||
<div class="info-item" v-if="auditData.applyReason">
|
||||
<label>申请理由:</label>
|
||||
<span>{{ auditData.applyReason }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>审核状态:</label>
|
||||
<el-tag :type="getAuditStatusType(auditData.auditStatus)" size="small">
|
||||
{{ getAuditStatusLabel(auditData.auditStatus) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="info-item" v-if="auditData.auditUserName">
|
||||
<label>审核人:</label>
|
||||
<span>{{ auditData.auditUserName }}</span>
|
||||
</div>
|
||||
<div class="info-item" v-if="auditData.auditTime">
|
||||
<label>审核时间:</label>
|
||||
<span>{{ parseTime(auditData.auditTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
||||
</div>
|
||||
<div class="info-item" v-if="auditData.auditRemark" style="grid-column: 1 / -1;">
|
||||
<label>审核意见:</label>
|
||||
<span>{{ auditData.auditRemark }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 审核操作 -->
|
||||
<div v-else-if="dialogMode === 'audit'" class="audit-form">
|
||||
<div class="audit-info">
|
||||
<div class="student-info">
|
||||
<strong>{{ auditData.studentName }} ({{ auditData.studentNo }})</strong>
|
||||
<span class="class-info">{{ auditData.className }}</span>
|
||||
</div>
|
||||
<div class="score-change-info">
|
||||
分数修改:{{ auditData.oldScore }} → <strong>{{ auditData.newScore }}</strong>
|
||||
<el-tag :type="auditData.newScore > auditData.oldScore ? 'success' : auditData.newScore < auditData.oldScore ? 'danger' : 'info'" size="small" style="margin-left: 10px;">
|
||||
{{ auditData.newScore > auditData.oldScore ? '+' : '' }}{{ auditData.newScore - auditData.oldScore }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="remark-info" v-if="auditData.newRemark">
|
||||
新备注:{{ auditData.newRemark }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-divider />
|
||||
|
||||
<el-form :model="auditForm" label-width="80px">
|
||||
<el-form-item label="审核意见" prop="auditRemark">
|
||||
<el-input
|
||||
v-model="auditForm.auditRemark"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入审核意见(可选)"
|
||||
maxlength="200"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="handleClose">取消</el-button>
|
||||
<template v-if="dialogMode === 'audit'">
|
||||
<el-button type="danger" @click="handleReject" :loading="submitting">驳回</el-button>
|
||||
<el-button type="success" @click="handleApprove" :loading="submitting">通过</el-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-button type="primary" @click="handleClose">确定</el-button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="AuditDialog">
|
||||
import { ref, reactive, getCurrentInstance } from 'vue';
|
||||
import ElMessage from 'element-plus/es/components/message/index';
|
||||
|
||||
// API接口
|
||||
import { conductScoreAuditApprove, conductScoreAuditReject } from '@/api/xg/conductScoreAudit';
|
||||
|
||||
// 获取当前实例
|
||||
const { proxy } = getCurrentInstance() as any;
|
||||
|
||||
// 定义事件
|
||||
const emit = defineEmits(['success']);
|
||||
|
||||
// 响应式数据
|
||||
const visible = ref(false);
|
||||
const dialogMode = ref<'view' | 'audit'>('view');
|
||||
const dialogTitle = ref('审核详情');
|
||||
const auditData = ref<any>({});
|
||||
const auditForm = reactive({
|
||||
auditRemark: ''
|
||||
});
|
||||
const submitting = ref(false);
|
||||
|
||||
// 方法
|
||||
const openDialog = (data: any, mode: 'view' | 'audit' = 'view') => {
|
||||
auditData.value = data;
|
||||
dialogMode.value = mode;
|
||||
|
||||
if (mode === 'view') {
|
||||
dialogTitle.value = '审核详情';
|
||||
} else {
|
||||
dialogTitle.value = '审核操行分修改';
|
||||
}
|
||||
|
||||
auditForm.auditRemark = '';
|
||||
visible.value = true;
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
visible.value = false;
|
||||
};
|
||||
|
||||
const handleApprove = async () => {
|
||||
await performAudit('approve');
|
||||
};
|
||||
|
||||
const handleReject = async () => {
|
||||
await performAudit('reject');
|
||||
};
|
||||
|
||||
const performAudit = async (action: 'approve' | 'reject') => {
|
||||
if (!auditData.value) return;
|
||||
|
||||
submitting.value = true;
|
||||
try {
|
||||
const auditRemark = auditForm.auditRemark.trim();
|
||||
|
||||
if (action === 'approve') {
|
||||
await conductScoreAuditApprove(auditData.value.id, { auditRemark });
|
||||
ElMessage.success('审核通过成功');
|
||||
} else {
|
||||
await conductScoreAuditReject(auditData.value.id, { auditRemark });
|
||||
ElMessage.success('审核驳回成功');
|
||||
}
|
||||
|
||||
emit('success');
|
||||
handleClose();
|
||||
} catch (error) {
|
||||
ElMessage.error(`${action === 'approve' ? '审核通过' : '审核驳回'}失败`);
|
||||
} finally {
|
||||
submitting.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 状态标签方法
|
||||
const getAuditStatusType = (status: number) => {
|
||||
switch (status) {
|
||||
case 0: return 'warning';
|
||||
case 1: return 'success';
|
||||
case 2: return 'danger';
|
||||
default: return 'info';
|
||||
}
|
||||
};
|
||||
|
||||
const getAuditStatusLabel = (status: number) => {
|
||||
switch (status) {
|
||||
case 0: return '待审核';
|
||||
case 1: return '审核通过';
|
||||
case 2: return '审核驳回';
|
||||
default: return '未知';
|
||||
}
|
||||
};
|
||||
|
||||
// 暴露方法
|
||||
defineExpose({
|
||||
openDialog
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.audit-dialog-content {
|
||||
max-height: 70vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.detail-section {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.detail-section h4 {
|
||||
margin: 0 0 12px 0;
|
||||
color: #303133;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.info-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.info-item label {
|
||||
min-width: 80px;
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.info-item span {
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.score-comparison {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 20px 0;
|
||||
padding: 16px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.score-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.score-item label {
|
||||
font-size: 14px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.score-value {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.old-score .score-value {
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.new-score .score-value {
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.score-arrow {
|
||||
margin: 0 20px;
|
||||
font-size: 20px;
|
||||
color: #c0c4cc;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.score-change {
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
.remark-section {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.remark-item {
|
||||
display: flex;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.remark-item label {
|
||||
min-width: 60px;
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.remark-item span {
|
||||
color: #303133;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.audit-form {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.audit-info {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.student-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.student-info strong {
|
||||
font-size: 16px;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.class-info {
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.score-change-info {
|
||||
color: #606266;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.remark-info {
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.dialog-footer .el-button {
|
||||
margin-left: 8px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,381 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div v-show="showSearch" class="mb-[10px]">
|
||||
<el-card shadow="hover">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<el-form-item label="学生姓名" prop="studentName">
|
||||
<el-input v-model="queryParams.studentName" placeholder="请输入学生姓名" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="学号" prop="studentNo">
|
||||
<el-input v-model="queryParams.studentNo" placeholder="请输入学号" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="审核状态" prop="auditStatus">
|
||||
<el-select v-model="queryParams.auditStatus" placeholder="审核状态" clearable>
|
||||
<el-option label="待审核" :value="0" />
|
||||
<el-option label="审核通过" :value="1" />
|
||||
<el-option label="审核驳回" :value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
icon="Check"
|
||||
:disabled="!hasSelected"
|
||||
@click="handleBatchApprove"
|
||||
v-hasPermi="['xg:conductScoreAudit:batchApprove']"
|
||||
>
|
||||
批量通过
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="Close"
|
||||
:disabled="!hasSelected"
|
||||
@click="handleBatchReject"
|
||||
v-hasPermi="['xg:conductScoreAudit:batchReject']"
|
||||
>
|
||||
批量驳回
|
||||
</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
border
|
||||
:data="auditList || []"
|
||||
row-key="id"
|
||||
@selection-change="handleSelectionChange"
|
||||
@sort-change="handleSortChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="学年" align="center" prop="academicYear" width="100">
|
||||
<template #default="scope">
|
||||
{{ scope.row && scope.row.academicYear ? scope.row.academicYear - 1 + '-' + scope.row.academicYear + '学年' : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="学期" align="center" prop="semester" width="80">
|
||||
<template #default="scope">
|
||||
{{ scope.row.semester === 1 ? '第一学期' : '第二学期' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="月份" align="center" prop="month" width="60">
|
||||
<template #default="scope"> {{ scope.row.month }}月 </template>
|
||||
</el-table-column>
|
||||
<el-table-column label="学生姓名" align="center" prop="studentName" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="学号" align="center" prop="studentNo" width="120" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="班级" align="center" prop="className" :show-overflow-tooltip="true" width="150" />
|
||||
<el-table-column label="原分数" align="center" prop="oldScore" width="80" />
|
||||
<el-table-column label="原备注" align="center" prop="oldRemark" :show-overflow-tooltip="true" width="120">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.oldRemark || '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="新分数" align="center" prop="newScore" width="80">
|
||||
<template #default="scope">
|
||||
<span class="text-primary font-medium">{{ scope.row.newScore }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="新备注" align="center" prop="newRemark" :show-overflow-tooltip="true" width="120">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.newRemark || '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="分数变化" align="center" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag
|
||||
v-if="scope.row && scope.row.newScore != null && scope.row.oldScore != null"
|
||||
:type="scope.row.newScore > scope.row.oldScore ? 'success' : scope.row.newScore < scope.row.oldScore ? 'danger' : 'info'"
|
||||
size="small"
|
||||
>
|
||||
{{ scope.row.newScore > scope.row.oldScore ? '+' : '' }}{{ scope.row.newScore - scope.row.oldScore }}
|
||||
</el-tag>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="申请人" align="center" prop="applyUserName" width="100" />
|
||||
<el-table-column label="申请时间" align="center" prop="applyTime" width="160">
|
||||
<template #default="scope">
|
||||
<span>{{ parseTime(scope.row.applyTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="审核状态" align="center" prop="auditStatus" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row && scope.row.auditStatus != null" :type="getAuditStatusType(scope.row.auditStatus)" size="small">
|
||||
{{ getAuditStatusLabel(scope.row.auditStatus) }}
|
||||
</el-tag>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="审核人" align="center" prop="auditUserName" width="100" />
|
||||
<el-table-column label="审核时间" align="center" prop="auditTime" width="160">
|
||||
<template #default="scope">
|
||||
<span>{{ parseTime(scope.row.auditTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="200" class-name="small-padding fixed-width" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-tooltip v-if="scope.row && scope.row.auditStatus === 0" content="审核通过" placement="top">
|
||||
<el-button link type="success" icon="Check" @click="handleApprove(scope.row)" v-hasPermi="['xg:conductScoreAudit:approve']"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip v-if="scope.row && scope.row.auditStatus === 0" content="审核驳回" placement="top">
|
||||
<el-button link type="danger" icon="Close" @click="handleReject(scope.row)" v-hasPermi="['xg:conductScoreAudit:reject']"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip v-if="scope.row" content="查看详情" placement="top">
|
||||
<el-button link type="primary" icon="View" @click="handleViewDetail(scope.row)"></el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
|
||||
</el-card>
|
||||
|
||||
<!-- 审核弹窗 -->
|
||||
<AuditDialog ref="auditDialogRef" @success="getList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="ConductScoreAudit">
|
||||
import { ref, reactive, onMounted, computed, getCurrentInstance, nextTick } from 'vue';
|
||||
import ElMessage from 'element-plus/es/components/message/index';
|
||||
import ElMessageBox from 'element-plus/es/components/message-box/index';
|
||||
import { ArrowDown } from '@element-plus/icons-vue';
|
||||
|
||||
// API接口
|
||||
import {
|
||||
conductScoreAuditList,
|
||||
conductScoreAuditApprove,
|
||||
conductScoreAuditReject,
|
||||
conductScoreAuditBatchApprove,
|
||||
conductScoreAuditBatchReject
|
||||
} from '@/api/xg/conductScoreAudit';
|
||||
|
||||
// 组件
|
||||
import AuditDialog from './components/AuditDialog.vue';
|
||||
|
||||
// 获取当前实例
|
||||
const { proxy } = getCurrentInstance() as any;
|
||||
|
||||
// 响应式数据
|
||||
const queryParams = reactive({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
studentName: '',
|
||||
studentNo: '',
|
||||
auditStatus: 0 // 默认显示待审核
|
||||
});
|
||||
|
||||
// 数据列表
|
||||
const auditList = ref([]);
|
||||
const loading = ref(true); // 初始设置为true,避免DOM渲染问题
|
||||
const total = ref(0);
|
||||
|
||||
// 选择相关
|
||||
const selectedAudits = ref([]);
|
||||
|
||||
// 搜索显示控制
|
||||
const showSearch = ref(true);
|
||||
|
||||
// 表单引用
|
||||
const queryFormRef = ref();
|
||||
const auditDialogRef = ref();
|
||||
|
||||
// 选项数据
|
||||
|
||||
// 计算属性
|
||||
const hasSelected = computed(() => selectedAudits.value && selectedAudits.value.length > 0);
|
||||
|
||||
// 方法
|
||||
const handleQuery = () => {
|
||||
queryParams.pageNum = 1;
|
||||
getList();
|
||||
};
|
||||
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields();
|
||||
queryParams.auditStatus = 0; // 重置为待审核
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const response = await conductScoreAuditList(queryParams);
|
||||
if (response.code === 200) {
|
||||
// 确保数据总是数组格式,避免DOM渲染问题
|
||||
auditList.value = Array.isArray(response.rows) ? response.rows : [];
|
||||
total.value = response.total || 0;
|
||||
} else {
|
||||
auditList.value = [];
|
||||
total.value = 0;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取审核列表失败:', error);
|
||||
auditList.value = [];
|
||||
total.value = 0;
|
||||
} finally {
|
||||
// 使用nextTick确保DOM更新完成
|
||||
nextTick(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectionChange = (selection) => {
|
||||
selectedAudits.value = selection;
|
||||
};
|
||||
|
||||
const handleSortChange = ({ prop, order }) => {
|
||||
queryParams.orderByColumn = prop;
|
||||
queryParams.isAsc = order === 'ascending' ? 'asc' : 'desc';
|
||||
getList();
|
||||
};
|
||||
|
||||
// 单个审核操作
|
||||
const handleApprove = async (row) => {
|
||||
ElMessageBox.confirm(`确定要通过 ${row.studentName} 的分数修改申请吗?\n新分数:${row.newScore}`, '审核确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'success'
|
||||
}).then(async () => {
|
||||
try {
|
||||
await conductScoreAuditApprove(row.id, { auditRemark: '审核通过' });
|
||||
ElMessage.success('审核通过成功');
|
||||
getList();
|
||||
} catch (error) {
|
||||
ElMessage.error('审核失败');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleReject = async (row) => {
|
||||
ElMessageBox.confirm(`确定要驳回 ${row.studentName} 的分数修改申请吗?`, '审核确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(async () => {
|
||||
try {
|
||||
await conductScoreAuditReject(row.id, { auditRemark: '审核驳回' });
|
||||
ElMessage.success('审核驳回成功');
|
||||
getList();
|
||||
} catch (error) {
|
||||
ElMessage.error('审核失败');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 批量审核操作
|
||||
const handleBatchApprove = async () => {
|
||||
if (!selectedAudits.value || selectedAudits.value.length === 0) {
|
||||
ElMessage.warning('请先选择要审核的记录');
|
||||
return;
|
||||
}
|
||||
|
||||
ElMessageBox.confirm(`确定要批量通过 ${selectedAudits.value.length} 条审核申请吗?`, '批量审核确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'success'
|
||||
}).then(async () => {
|
||||
try {
|
||||
const ids = selectedAudits.value.map((item) => item.id);
|
||||
await conductScoreAuditBatchApprove({ ids, auditRemark: '批量审核通过' });
|
||||
ElMessage.success('批量审核通过成功');
|
||||
selectedAudits.value = [];
|
||||
getList();
|
||||
} catch (error) {
|
||||
ElMessage.error('批量审核失败');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleBatchReject = async () => {
|
||||
if (!selectedAudits.value || selectedAudits.value.length === 0) {
|
||||
ElMessage.warning('请先选择要审核的记录');
|
||||
return;
|
||||
}
|
||||
|
||||
ElMessageBox.confirm(`确定要批量驳回 ${selectedAudits.value.length} 条审核申请吗?`, '批量审核确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(async () => {
|
||||
try {
|
||||
const ids = selectedAudits.value.map((item) => item.id);
|
||||
await conductScoreAuditBatchReject({ ids, auditRemark: '批量审核驳回' });
|
||||
ElMessage.success('批量审核驳回成功');
|
||||
selectedAudits.value = [];
|
||||
getList();
|
||||
} catch (error) {
|
||||
ElMessage.error('批量审核失败');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 查看详情
|
||||
const handleViewDetail = (row) => {
|
||||
auditDialogRef.value?.openDialog(row, 'view');
|
||||
};
|
||||
|
||||
// 状态标签方法
|
||||
const getAuditStatusType = (status) => {
|
||||
switch (status) {
|
||||
case 0:
|
||||
return 'warning';
|
||||
case 1:
|
||||
return 'success';
|
||||
case 2:
|
||||
return 'danger';
|
||||
default:
|
||||
return 'info';
|
||||
}
|
||||
};
|
||||
|
||||
const getAuditStatusLabel = (status) => {
|
||||
switch (status) {
|
||||
case 0:
|
||||
return '待审核';
|
||||
case 1:
|
||||
return '审核通过';
|
||||
case 2:
|
||||
return '审核驳回';
|
||||
default:
|
||||
return '未知';
|
||||
}
|
||||
};
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
// 确保组件完全加载后再获取数据
|
||||
nextTick(() => {
|
||||
getList();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.text-primary {
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.font-medium {
|
||||
font-weight: 500;
|
||||
}
|
||||
</style>
|
||||
@@ -290,11 +290,9 @@
|
||||
<el-input v-model="scope.row.remark" size="small" placeholder="输入备注(可选)" maxlength="500" show-word-limit />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="columns[6].visible" key="status" label="状态" align="center" width="100">
|
||||
<el-table-column v-if="columns[6].visible" key="status" label="状态" align="center" width="120">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.existingScore" type="success" size="small">已录入</el-tag>
|
||||
<el-tag v-else-if="scope.row.score" type="warning" size="small">待保存</el-tag>
|
||||
<el-tag v-else type="info" size="small">未录入</el-tag>
|
||||
<el-tag :type="getStudentStatusTagType(scope.row)" size="small">{{ getStudentStatus(scope.row) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="columns[7].visible" key="lastScore" label="上月分数" align="center" width="100">
|
||||
@@ -330,7 +328,7 @@ import { ArrowDown, InfoFilled } from '@element-plus/icons-vue';
|
||||
import { globalHeaders } from '@/utils/request';
|
||||
|
||||
// API接口
|
||||
import { conductScoreClassStudents, conductScoreBatchAdd } from '@/api/xg/conductScore';
|
||||
import { conductScoreClassStudents, conductScoreBatchAdd, conductScoreBatchUpdate } from '@/api/xg/conductScore';
|
||||
|
||||
// 获取当前实例
|
||||
const { proxy } = getCurrentInstance() as any;
|
||||
@@ -506,6 +504,55 @@ const getStudentStatusType = (status) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 获取学生录入状态
|
||||
const getStudentStatus = (student) => {
|
||||
const hasExistingScore = student.existingScore !== null && student.existingScore !== undefined;
|
||||
const hasCurrentScore = student.score !== null && student.score !== undefined;
|
||||
|
||||
if (!hasExistingScore && !hasCurrentScore) {
|
||||
return '未录入';
|
||||
}
|
||||
|
||||
if (!hasExistingScore && hasCurrentScore) {
|
||||
return '待保存';
|
||||
}
|
||||
|
||||
if (hasExistingScore && !hasCurrentScore) {
|
||||
return '已录入';
|
||||
}
|
||||
|
||||
if (hasExistingScore && hasCurrentScore) {
|
||||
// 比较分数和备注是否变化
|
||||
const scoreChanged = Number(student.score) !== Number(student.existingScore.score);
|
||||
const remarkChanged = String(student.remark || '').trim() !== String(student.existingScore.remark || '').trim();
|
||||
|
||||
if (scoreChanged || remarkChanged) {
|
||||
return '待审核';
|
||||
} else {
|
||||
return '已录入';
|
||||
}
|
||||
}
|
||||
|
||||
return '未录入';
|
||||
};
|
||||
|
||||
// 获取学生录入状态的标签类型
|
||||
const getStudentStatusTagType = (student) => {
|
||||
const status = getStudentStatus(student);
|
||||
switch (status) {
|
||||
case '未录入':
|
||||
return 'info';
|
||||
case '待保存':
|
||||
return 'primary';
|
||||
case '已录入':
|
||||
return 'success';
|
||||
case '待审核':
|
||||
return 'warning';
|
||||
default:
|
||||
return 'info';
|
||||
}
|
||||
};
|
||||
|
||||
// 方法
|
||||
const handleQuery = () => {
|
||||
getList();
|
||||
@@ -623,7 +670,7 @@ const getList = async () => {
|
||||
|
||||
// 批量操作方法
|
||||
const handleBatchInput = () => {
|
||||
// 打开批量录入弹窗(弹窗中输入分数和备注,保存时应用到所选学生)
|
||||
// 批量录入:根据分数变化情况智能处理
|
||||
console.log('handleBatchInput selectedStudents:', selectedStudents.value);
|
||||
if (!selectedStudents.value || selectedStudents.value.length === 0) {
|
||||
ElMessage.warning('请先选择要批量录入的学生');
|
||||
@@ -634,30 +681,108 @@ const handleBatchInput = () => {
|
||||
batchModalForm.score = null;
|
||||
batchModalForm.remark = '';
|
||||
batchModalVisible.value = true;
|
||||
// debug info for users to see modal opening
|
||||
ElMessage.info('已打开批量录入弹窗');
|
||||
|
||||
// 显示操作提示
|
||||
ElMessage.info(`已选择 ${selectedStudents.value.length} 个学生进行批量录入。系统将根据分数变化情况自动判断是否需要审核。`);
|
||||
};
|
||||
|
||||
const handleSaveAll = () => {
|
||||
const validStudents = filteredStudents.value.filter(
|
||||
(student) => student.score !== null && student.score !== undefined && student.existingScore === null
|
||||
);
|
||||
// 获取所有有分值的学生
|
||||
const studentsWithScore = filteredStudents.value.filter((student) => student.score !== null && student.score !== undefined);
|
||||
|
||||
if (validStudents.length === 0) {
|
||||
if (studentsWithScore.length === 0) {
|
||||
ElMessage.warning('没有需要保存的数据');
|
||||
return;
|
||||
}
|
||||
|
||||
ElMessageBox.confirm(`确定要保存当前班级的 ${validStudents.length} 个学生的操行分吗?`, '保存确认', {
|
||||
// 区分需要审核和不需要审核的学生
|
||||
const directSaveStudents = []; // 直接保存的学生
|
||||
const auditStudents = []; // 需要审核的学生
|
||||
|
||||
studentsWithScore.forEach((student) => {
|
||||
const hasExistingScore = student.existingScore !== null && student.existingScore !== undefined;
|
||||
|
||||
if (!hasExistingScore) {
|
||||
// 第一次录入:直接保存
|
||||
directSaveStudents.push(student);
|
||||
} else {
|
||||
// 有历史记录:检查分数和备注是否都相同
|
||||
// 确保数据类型一致进行比较
|
||||
const currentScore = Number(student.score);
|
||||
const originalScore = Number(student.existingScore.score);
|
||||
const currentRemark = String(student.remark || '').trim();
|
||||
const originalRemark = String(student.existingScore.remark || '').trim();
|
||||
|
||||
const scoreChanged = currentScore !== originalScore;
|
||||
const remarkChanged = currentRemark !== originalRemark;
|
||||
|
||||
// 调试信息:检查每个学生的比较结果
|
||||
console.log(`学生 ${student.studentName}:`, {
|
||||
studentId: student.studentId,
|
||||
hasExistingScore,
|
||||
currentScore,
|
||||
originalScore,
|
||||
scoreChanged,
|
||||
currentRemark: `"${currentRemark}"`,
|
||||
originalRemark: `"${originalRemark}"`,
|
||||
remarkChanged,
|
||||
existingScore: student.existingScore,
|
||||
studentRemark: student.remark,
|
||||
existingScoreRemark: student.existingScore?.remark
|
||||
});
|
||||
|
||||
if (!scoreChanged && !remarkChanged) {
|
||||
// 分数和备注都没有变化:直接保存
|
||||
directSaveStudents.push(student);
|
||||
} else {
|
||||
// 分数或备注发生了变化:需要审核
|
||||
console.log(`学生 ${student.studentName} 需要审核,原因:`, {
|
||||
scoreChanged,
|
||||
remarkChanged,
|
||||
reason: scoreChanged ? '分数变化' : remarkChanged ? '备注变化' : '未知'
|
||||
});
|
||||
auditStudents.push(student);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (directSaveStudents.length === 0 && auditStudents.length === 0) {
|
||||
ElMessage.warning('没有需要保存的数据');
|
||||
return;
|
||||
}
|
||||
|
||||
// 构建确认消息
|
||||
let confirmMessage = '确定要';
|
||||
const actions = [];
|
||||
if (directSaveStudents.length > 0) {
|
||||
actions.push(`保存 ${directSaveStudents.length} 个学生`);
|
||||
}
|
||||
if (auditStudents.length > 0) {
|
||||
actions.push(`提交 ${auditStudents.length} 个修改学生审核`);
|
||||
}
|
||||
confirmMessage += actions.join(' 和 ') + '的操行分吗?';
|
||||
|
||||
if (auditStudents.length > 0) {
|
||||
confirmMessage += '\n\n注意:分数或备注发生变化的学生需要管理员审核才能生效。';
|
||||
}
|
||||
|
||||
ElMessageBox.confirm(confirmMessage, '保存确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
type: auditStudents.length > 0 ? 'warning' : 'success',
|
||||
dangerouslyUseHTMLString: true
|
||||
}).then(() => {
|
||||
saveBatchData(validStudents);
|
||||
// 分批处理直接保存和审核
|
||||
if (directSaveStudents.length > 0) {
|
||||
saveBatchData(directSaveStudents, 'add');
|
||||
}
|
||||
if (auditStudents.length > 0) {
|
||||
saveBatchData(auditStudents, 'update');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const saveBatchData = async (students) => {
|
||||
const saveBatchData = async (students, operationType = 'add') => {
|
||||
try {
|
||||
const batchData = {
|
||||
academicYear: queryParams.academicYear,
|
||||
@@ -671,18 +796,32 @@ const saveBatchData = async (students) => {
|
||||
}))
|
||||
};
|
||||
|
||||
const response = await conductScoreBatchAdd(batchData);
|
||||
|
||||
if (response.code === 200) {
|
||||
ElMessage.success(`成功保存 ${response.data.successCount} 条记录`);
|
||||
if (response.data.failCount > 0) {
|
||||
ElMessage.warning(`失败 ${response.data.failCount} 条记录`);
|
||||
let response;
|
||||
if (operationType === 'update') {
|
||||
// 修改操作:提交审核
|
||||
response = await conductScoreBatchUpdate(batchData);
|
||||
if (response.code === 200) {
|
||||
ElMessage.success(`成功提交 ${response.data.successCount} 条审核申请`);
|
||||
if (response.data.failCount > 0) {
|
||||
ElMessage.warning(`失败 ${response.data.failCount} 条记录`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 新增操作:直接保存
|
||||
response = await conductScoreBatchAdd(batchData);
|
||||
if (response.code === 200) {
|
||||
ElMessage.success(`成功保存 ${response.data.successCount} 条记录`);
|
||||
if (response.data.failCount > 0) {
|
||||
ElMessage.warning(`失败 ${response.data.failCount} 条记录`);
|
||||
}
|
||||
}
|
||||
getList();
|
||||
}
|
||||
|
||||
getList();
|
||||
} catch (error) {
|
||||
console.error('保存数据失败:', error);
|
||||
ElMessage.error('保存失败');
|
||||
const operationName = operationType === 'update' ? '提交审核' : '保存';
|
||||
ElMessage.error(`${operationName}失败`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -703,7 +842,7 @@ const importUpload = reactive({
|
||||
});
|
||||
|
||||
const confirmBatchModalSave = () => {
|
||||
// 批量录入弹窗填写的分数/备注将应用到所有已勾选的学生(包含已录入的,视为覆盖)
|
||||
// 批量录入弹窗:根据分数变化情况决定是否需要审核
|
||||
const targets = selectedStudents.value || [];
|
||||
|
||||
if (targets.length === 0) {
|
||||
@@ -717,15 +856,66 @@ const confirmBatchModalSave = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const studentsToSave = targets.map((stu) => ({
|
||||
studentId: stu.studentId,
|
||||
score: batchModalForm.score,
|
||||
remark: batchModalForm.remark || ''
|
||||
}));
|
||||
// 区分需要审核和不需要审核的学生
|
||||
const directSaveStudents = [];
|
||||
const auditStudents = [];
|
||||
|
||||
targets.forEach((stu) => {
|
||||
const hasExistingScore = stu.existingScore !== null && stu.existingScore !== undefined;
|
||||
|
||||
if (!hasExistingScore) {
|
||||
// 第一次录入:直接保存
|
||||
directSaveStudents.push(stu);
|
||||
} else {
|
||||
// 有历史记录:检查分数和备注是否都相同
|
||||
const currentScore = Number(batchModalForm.score);
|
||||
const originalScore = Number(stu.existingScore.score);
|
||||
const currentRemark = String(batchModalForm.remark || '').trim();
|
||||
const originalRemark = String(stu.existingScore.remark || '').trim();
|
||||
|
||||
const scoreChanged = currentScore !== originalScore;
|
||||
const remarkChanged = currentRemark !== originalRemark;
|
||||
|
||||
if (!scoreChanged && !remarkChanged) {
|
||||
// 分数和备注都没有变化:直接保存
|
||||
directSaveStudents.push(stu);
|
||||
} else {
|
||||
// 分数或备注发生了变化:需要审核
|
||||
auditStudents.push(stu);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
batchModalVisible.value = false;
|
||||
// 保存时会覆盖已有分数(后端应支持更新)
|
||||
saveBatchData(studentsToSave);
|
||||
|
||||
// 分批处理
|
||||
if (directSaveStudents.length > 0) {
|
||||
const directSaveData = directSaveStudents.map((stu) => ({
|
||||
studentId: stu.studentId,
|
||||
score: batchModalForm.score,
|
||||
remark: batchModalForm.remark || ''
|
||||
}));
|
||||
saveBatchData(directSaveData, 'add');
|
||||
}
|
||||
|
||||
if (auditStudents.length > 0) {
|
||||
const auditData = auditStudents.map((stu) => ({
|
||||
studentId: stu.studentId,
|
||||
score: batchModalForm.score,
|
||||
remark: batchModalForm.remark || ''
|
||||
}));
|
||||
saveBatchData(auditData, 'update');
|
||||
}
|
||||
|
||||
// 显示操作结果
|
||||
let message = '批量操作完成:';
|
||||
if (directSaveStudents.length > 0) {
|
||||
message += `保存 ${directSaveStudents.length} 个学生`;
|
||||
}
|
||||
if (auditStudents.length > 0) {
|
||||
message += `${directSaveStudents.length > 0 ? ',' : ''}提交 ${auditStudents.length} 个修改学生审核`;
|
||||
}
|
||||
ElMessage.success(message);
|
||||
};
|
||||
|
||||
const handleRefresh = () => {
|
||||
@@ -733,30 +923,66 @@ const handleRefresh = () => {
|
||||
};
|
||||
|
||||
const handleSingleInput = (row) => {
|
||||
// 单条保存:支持覆盖已录入的分数。根据是否已有分数,调整提示文案。
|
||||
// 单条保存:根据分数和备注变化情况决定是否需要审核
|
||||
if (row.score === null || row.score === undefined) {
|
||||
ElMessage.warning('请先输入分数');
|
||||
return;
|
||||
}
|
||||
|
||||
const confirmMessage = row.existingScore
|
||||
? `该学生已有分数,确定要覆盖 ${row.studentName} 的分数为 ${row.score} 吗?`
|
||||
: `确定保存 ${row.studentName} 的分数 ${row.score} 吗?`;
|
||||
const hasExistingScore = row.existingScore !== null && row.existingScore !== undefined;
|
||||
|
||||
ElMessageBox.confirm(confirmMessage, '保存确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
// 传入简化对象以避免多余字段
|
||||
saveBatchData([
|
||||
{
|
||||
studentId: row.studentId,
|
||||
score: row.score,
|
||||
remark: row.remark || ''
|
||||
}
|
||||
]);
|
||||
});
|
||||
if (!hasExistingScore) {
|
||||
// 第一次录入:直接保存
|
||||
const confirmMessage = `确定保存 ${row.studentName} 的分数 ${row.score} 吗?`;
|
||||
ElMessageBox.confirm(confirmMessage, '保存确认', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'success'
|
||||
}).then(() => {
|
||||
saveBatchData(
|
||||
[
|
||||
{
|
||||
studentId: row.studentId,
|
||||
score: row.score,
|
||||
remark: row.remark || ''
|
||||
}
|
||||
],
|
||||
'add'
|
||||
);
|
||||
});
|
||||
} else {
|
||||
// 有历史记录:检查分数和备注是否都相同
|
||||
const currentScore = Number(row.score);
|
||||
const originalScore = Number(row.existingScore.score);
|
||||
const currentRemark = String(row.remark || '').trim();
|
||||
const originalRemark = String(row.existingScore.remark || '').trim();
|
||||
|
||||
const scoreChanged = currentScore !== originalScore;
|
||||
const remarkChanged = currentRemark !== originalRemark;
|
||||
const needsAudit = scoreChanged || remarkChanged;
|
||||
|
||||
const operationName = needsAudit ? '修改审核' : '保存';
|
||||
const confirmMessage = needsAudit
|
||||
? `该学生${scoreChanged ? '分数' : ''}${scoreChanged && remarkChanged ? '和' : ''}${remarkChanged ? '备注' : ''}发生变化,修改后需要管理员审核。确定要提交 ${row.studentName} 的修改吗?`
|
||||
: `该学生信息没有变化,确定要保存吗?`;
|
||||
|
||||
ElMessageBox.confirm(confirmMessage, `${operationName}确认`, {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: needsAudit ? 'warning' : 'success'
|
||||
}).then(() => {
|
||||
saveBatchData(
|
||||
[
|
||||
{
|
||||
studentId: row.studentId,
|
||||
score: row.score,
|
||||
remark: row.remark || ''
|
||||
}
|
||||
],
|
||||
needsAudit ? 'update' : 'add'
|
||||
);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectionChange = (selection) => {
|
||||
|
||||
Reference in new issue
Block a user