From 86f65df783d1ad04ada6856d8530159e7d036389 Mon Sep 17 00:00:00 2001 From: zlwu <704541015@qq.com> Date: Wed, 6 Aug 2025 01:32:11 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E8=AF=B7=E5=81=87=E9=94=80?= =?UTF-8?q?=E5=81=87=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../XgStudentCancelLeaveController.java | 128 ++ .../workflow/domain/XgStudentCancelLeave.java | 200 +++ .../domain/bo/XgStudentCancelLeaveBo.java | 212 +++ .../domain/vo/XgStudentCancelLeaveVo.java | 244 +++ .../mapper/XgStudentCancelLeaveMapper.java | 15 + .../service/IXgStudentCancelLeaveService.java | 84 + .../impl/XgStudentCancelLeaveServiceImpl.java | 256 +++ .../impl/XgStudentLeaveServiceImpl.java | 87 + .../XgStudentCancelLeaveMapper.xml | 7 + ...25-01-27-cursor-attachment-optimization.md | 153 ++ .../code-adjust-record-2025-01-27-cursor.md | 298 +++- .../code-adjust-record-2025-01-27-wuzilong.md | 217 +-- docs/开发文档/API/API文档总览.md | 1 + docs/开发文档/API/学生销假管理API.md | 579 ++++++ .../studentCancelLeave/index.ts | 85 + .../studentCancelLeave/types.ts | 521 ++++++ .../xg/xsjcxx/xsqj/{ => bak}/index-bak.vue | 0 .../xsjcxx/xsqj/{ => bak}/leaveEdit-bak.vue | 0 .../xg/xsjcxx/xsqj/{ => bak}/leaveEdit.vue | 0 web/src/views/xg/xsjcxx/xsqj/dialog.vue | 53 +- web/src/views/xg/xsjcxx/xsqj/index.vue | 75 +- web/src/views/xg/xsjcxx/xsqj/xjdialog.vue | 1559 +++++++++++++++++ 22 files changed, 4583 insertions(+), 191 deletions(-) create mode 100644 backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/XgStudentCancelLeaveController.java create mode 100644 backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/XgStudentCancelLeave.java create mode 100644 backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/XgStudentCancelLeaveBo.java create mode 100644 backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/XgStudentCancelLeaveVo.java create mode 100644 backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/XgStudentCancelLeaveMapper.java create mode 100644 backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IXgStudentCancelLeaveService.java create mode 100644 backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/XgStudentCancelLeaveServiceImpl.java create mode 100644 backend/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/studentCancelLeave/XgStudentCancelLeaveMapper.xml create mode 100644 docs/变更管理/code-adjust-record-2025-01-27-cursor-attachment-optimization.md create mode 100644 docs/开发文档/API/学生销假管理API.md create mode 100644 web/src/api/workflow/studentCancelLeave/studentCancelLeave/index.ts create mode 100644 web/src/api/workflow/studentCancelLeave/studentCancelLeave/types.ts rename web/src/views/xg/xsjcxx/xsqj/{ => bak}/index-bak.vue (100%) rename web/src/views/xg/xsjcxx/xsqj/{ => bak}/leaveEdit-bak.vue (100%) rename web/src/views/xg/xsjcxx/xsqj/{ => bak}/leaveEdit.vue (100%) create mode 100644 web/src/views/xg/xsjcxx/xsqj/xjdialog.vue diff --git a/backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/XgStudentCancelLeaveController.java b/backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/XgStudentCancelLeaveController.java new file mode 100644 index 00000000..ae27f485 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/XgStudentCancelLeaveController.java @@ -0,0 +1,128 @@ +package org.dromara.workflow.controller; + +import java.util.List; + +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.workflow.domain.vo.XgStudentCancelLeaveVo; +import org.dromara.workflow.domain.bo.XgStudentCancelLeaveBo; +import org.dromara.workflow.service.IXgStudentCancelLeaveService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 学生销假 + * + * @author zlwu + * @date 2025-08-05 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/studentCancelLeave/studentCancelLeave") +public class XgStudentCancelLeaveController extends BaseController { + + private final IXgStudentCancelLeaveService xgStudentCancelLeaveService; + + /** + * 查询学生销假列表 + */ + @SaCheckPermission("studentCancelLeave:studentCancelLeave:list") + @GetMapping("/list") + public TableDataInfo list(XgStudentCancelLeaveBo bo, PageQuery pageQuery) { + return xgStudentCancelLeaveService.queryPageList(bo, pageQuery); + } + + /** + * 导出学生销假列表 + */ + @SaCheckPermission("studentCancelLeave:studentCancelLeave:export") + @Log(title = "学生销假", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(XgStudentCancelLeaveBo bo, HttpServletResponse response) { + List list = xgStudentCancelLeaveService.queryList(bo); + ExcelUtil.exportExcel(list, "学生销假", XgStudentCancelLeaveVo.class, response); + } + + /** + * 获取学生销假详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("studentCancelLeave:studentCancelLeave:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) { + return R.ok(xgStudentCancelLeaveService.queryById(id)); + } + + /** + * 新增学生销假 + */ + @SaCheckPermission("studentCancelLeave:studentCancelLeave:add") + @Log(title = "学生销假", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody XgStudentCancelLeaveBo bo) { + XgStudentCancelLeaveVo result = xgStudentCancelLeaveService.insertByBo(bo); + return R.ok(result); + } + + /** + * 修改学生销假 + */ + @SaCheckPermission("studentCancelLeave:studentCancelLeave:edit") + @Log(title = "学生销假", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody XgStudentCancelLeaveBo bo) { + return toAjax(xgStudentCancelLeaveService.updateByBo(bo)); + } + + /** + * 删除学生销假 + * + * @param ids 主键串 + */ + @SaCheckPermission("studentCancelLeave:studentCancelLeave:remove") + @Log(title = "学生销假", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) { + return toAjax(xgStudentCancelLeaveService.deleteWithValidByIds(List.of(ids), true)); + } + + /** + * 根据请假ID获取销假ID + * + * @param leaveId 请假ID + */ + @SaCheckPermission("studentCancelLeave:studentCancelLeave:query") + @GetMapping("/getCancelLeaveId/{leaveId}") + public R getCancelLeaveIdByLeaveId(@NotNull(message = "请假ID不能为空") @PathVariable Long leaveId) { + Long cancelLeaveId = xgStudentCancelLeaveService.getCancelLeaveIdByLeaveId(leaveId); + return R.ok(cancelLeaveId); + } + + /** + * 根据销假ID获取请假ID + * + * @param cancelLeaveId 销假ID + */ + @SaCheckPermission("studentCancelLeave:studentCancelLeave:query") + @GetMapping("/getLeaveId/{cancelLeaveId}") + public R getLeaveIdByCancelLeaveId(@NotNull(message = "销假ID不能为空") @PathVariable Long cancelLeaveId) { + Long leaveId = xgStudentCancelLeaveService.getLeaveIdByCancelLeaveId(cancelLeaveId); + return R.ok(leaveId); + } +} diff --git a/backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/XgStudentCancelLeave.java b/backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/XgStudentCancelLeave.java new file mode 100644 index 00000000..ba9595ef --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/XgStudentCancelLeave.java @@ -0,0 +1,200 @@ +package org.dromara.workflow.domain; + +import org.dromara.common.tenant.core.TenantEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.io.Serial; + +/** + * 学生销假对象 xg_student_cancel_leave + * + * @author zlwu + * @date 2025-08-05 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("xg_student_cancel_leave") +public class XgStudentCancelLeave extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID(雪花ID) + */ + @TableId(value = "id") + private Long id; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic(value = "0", delval = "1") + private Long deleted; + + /** + * 学生ID + */ + private Long studentId; + + /** + * 学生姓名 + */ + private String studentName; + + /** + * 学号 + */ + private String studentNo; + + /** + * 班级ID + */ + private Long classId; + + /** + * 班级名称 + */ + private String className; + + /** + * 专业ID + */ + private Long majorId; + + /** + * 专业名称 + */ + private String majorName; + + /** + * 学院ID + */ + private Long collegeId; + + /** + * 学院名称 + */ + private String collegeName; + + /** + * 请假类型编码 + */ + private String leaveTypeCode; + + /** + * 请假类型名称 + */ + private String leaveTypeName; + + /** + * 开始时间(年月日时分秒) + */ + private Date startTime; + + /** + * 结束时间(年月日时分秒) + */ + private Date endTime; + + /** + * 请假时长(天) + */ + private Double leaveDuration; + + /** + * 是否离校:0-否,1-是 + */ + private String isLeaveSchool; + + /** + * 是否需要销假:0-否,1-是 + */ + private String needCancel; + + /** + * 紧急联系人 + */ + private String emergencyContact; + + /** + * 紧急联系电话 + */ + private String emergencyPhone; + + /** + * 请假原因 + */ + private String leaveReason; + + /** + * 请假时地理位置 + */ + private String leaveLocation; + + /** + * 附件OSS文件ID(逗号分隔) + */ + private String attachmentOssIds; + + /** + * 审批状态:"cancel", "已撤销" "draft", "草稿" "waiting", "待审核" "finish", "已完成" + * "invalid", "已作废" "back", "已退回" "termination", "已终止" + */ + private String approvalStatus; + + /** + * 审批意见 + */ + private String approvalOpinion; + + /** + * 审批时间 + */ + private Date approvalTime; + + /** + * 审批人ID + */ + private Long approvalBy; + + /** + * 审批人姓名 + */ + private String approvalByName; + + /** + * 销假状态:0-未销假,1-已销假,2-逾期未销假 3 - 无需销假 "cancel", "已撤销" "draft", "草稿" "waiting", + * "待审核" "finish", "已完成" "invalid", "已作废" "back", "已退回" "termination", "已终止" + */ + private String cancelStatus; + + /** + * 销假时间 + */ + private Date cancelTime; + + /** + * 销假地理位置 + */ + private String cancelLocation; + + /** + * 销假照片OSS文件ID(逗号分隔) + */ + private String cancelPhotoOssIds; + + /** + * 销假备注 + */ + private String cancelRemark; + + /** + * 学生请假表id + */ + private Long leaveId; + +} diff --git a/backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/XgStudentCancelLeaveBo.java b/backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/XgStudentCancelLeaveBo.java new file mode 100644 index 00000000..42eb0f3c --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/XgStudentCancelLeaveBo.java @@ -0,0 +1,212 @@ +package org.dromara.workflow.domain.bo; + +import org.dromara.workflow.domain.XgStudentCancelLeave; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 学生销假业务对象 xg_student_cancel_leave + * + * @author zlwu + * @date 2025-08-05 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = XgStudentCancelLeave.class, reverseConvertGenerate = false) +public class XgStudentCancelLeaveBo extends BaseEntity { + + /** + * 主键ID(雪花ID) + */ + @NotNull(message = "主键ID(雪花ID)不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 删除标志(0代表存在 1代表删除) + */ + private Long deleted; + + /** + * 学生ID + */ + @NotNull(message = "学生ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long studentId; + + /** + * 学生姓名 + */ + @NotBlank(message = "学生姓名不能为空", groups = { AddGroup.class, EditGroup.class }) + private String studentName; + + /** + * 学号 + */ + @NotBlank(message = "学号不能为空", groups = { AddGroup.class, EditGroup.class }) + private String studentNo; + + /** + * 班级ID + */ + private Long classId; + + /** + * 班级名称 + */ + private String className; + + /** + * 专业ID + */ + private Long majorId; + + /** + * 专业名称 + */ + private String majorName; + + /** + * 学院ID + */ + private Long collegeId; + + /** + * 学院名称 + */ + private String collegeName; + + /** + * 请假类型编码 + */ + @NotBlank(message = "请假类型编码不能为空", groups = { AddGroup.class, EditGroup.class }) + private String leaveTypeCode; + + /** + * 请假类型名称 + */ + @NotBlank(message = "请假类型名称不能为空", groups = { AddGroup.class, EditGroup.class }) + private String leaveTypeName; + + /** + * 开始时间(年月日时分秒) + */ + @NotNull(message = "开始时间(年月日时分秒)不能为空", groups = { AddGroup.class, EditGroup.class }) + private Date startTime; + + /** + * 结束时间(年月日时分秒) + */ + @NotNull(message = "结束时间(年月日时分秒)不能为空", groups = { AddGroup.class, EditGroup.class }) + private Date endTime; + + /** + * 请假时长(天) + */ + @NotNull(message = "请假时长(天)不能为空", groups = { AddGroup.class, EditGroup.class }) + private Double leaveDuration; + + /** + * 是否离校:0-否,1-是 + */ + @NotBlank(message = "是否离校:0-否,1-是不能为空", groups = { AddGroup.class, EditGroup.class }) + private String isLeaveSchool; + + /** + * 是否需要销假:0-否,1-是 + */ + @NotBlank(message = "是否需要销假:0-否,1-是不能为空", groups = { AddGroup.class, EditGroup.class }) + private String needCancel; + + /** + * 紧急联系人 + */ + private String emergencyContact; + + /** + * 紧急联系电话 + */ + private String emergencyPhone; + + /** + * 请假原因 + */ + @NotBlank(message = "请假原因不能为空", groups = { AddGroup.class, EditGroup.class }) + private String leaveReason; + + /** + * 请假时地理位置 + */ + private String leaveLocation; + + /** + * 附件OSS文件ID(逗号分隔) + */ + private String attachmentOssIds; + + /** + * 审批状态:"cancel", "已撤销" "draft", "草稿" "waiting", "待审核" "finish", "已完成" + * "invalid", "已作废" "back", "已退回" "termination", "已终止" + */ + @NotBlank(message = "审批状态:cancel-已撤销 draft-草稿 waiting-待审核 finish-已完成 invalid-已作废 back-已退回 termination-已终止 不能为空", groups = { + AddGroup.class, EditGroup.class }) + private String approvalStatus; + + /** + * 审批意见 + */ + private String approvalOpinion; + + /** + * 审批时间 + */ + private Date approvalTime; + + /** + * 审批人ID + */ + private Long approvalBy; + + /** + * 审批人姓名 + */ + private String approvalByName; + + /** + * 销假状态:0-未销假,1-已销假,2-逾期未销假 3 - 无需销假 "cancel", "已撤销" "draft", "草稿" "waiting", + * "待审核" "finish", "已完成" "invalid", "已作废" "back", "已退回" "termination", "已终止" + */ + private String cancelStatus; + + /** + * 销假时间 + */ + private Date cancelTime; + + /** + * 销假地理位置 + */ + private String cancelLocation; + + /** + * 销假照片OSS文件ID(逗号分隔) + */ + private String cancelPhotoOssIds; + + /** + * 销假备注 + */ + private String cancelRemark; + + /** + * 学生请假表id + */ + @NotNull(message = "学生请假表id不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long leaveId; + +} diff --git a/backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/XgStudentCancelLeaveVo.java b/backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/XgStudentCancelLeaveVo.java new file mode 100644 index 00000000..264975dd --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/XgStudentCancelLeaveVo.java @@ -0,0 +1,244 @@ +package org.dromara.workflow.domain.vo; + +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.dromara.workflow.domain.XgStudentCancelLeave; +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 学生销假视图对象 xg_student_cancel_leave + * + * @author zlwu + * @date 2025-08-05 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = XgStudentCancelLeave.class) +public class XgStudentCancelLeaveVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID(雪花ID) + */ + @ExcelProperty(value = "主键ID", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "雪=花ID") + private Long id; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @ExcelProperty(value = "删除标志", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=代表存在,1=代表删除") + private Long deleted; + + /** + * 学生ID + */ + @ExcelProperty(value = "学生ID") + private Long studentId; + + /** + * 学生姓名 + */ + @ExcelProperty(value = "学生姓名") + private String studentName; + + /** + * 学号 + */ + @ExcelProperty(value = "学号") + private String studentNo; + + /** + * 班级ID + */ + @ExcelProperty(value = "班级ID") + private Long classId; + + /** + * 班级名称 + */ + @ExcelProperty(value = "班级名称") + private String className; + + /** + * 专业ID + */ + @ExcelProperty(value = "专业ID") + private Long majorId; + + /** + * 专业名称 + */ + @ExcelProperty(value = "专业名称") + private String majorName; + + /** + * 学院ID + */ + @ExcelProperty(value = "学院ID") + private Long collegeId; + + /** + * 学院名称 + */ + @ExcelProperty(value = "学院名称") + private String collegeName; + + /** + * 请假类型编码 + */ + @ExcelProperty(value = "请假类型编码") + private String leaveTypeCode; + + /** + * 请假类型名称 + */ + @ExcelProperty(value = "请假类型名称") + private String leaveTypeName; + + /** + * 开始时间(年月日时分秒) + */ + @ExcelProperty(value = "开始时间", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "年=月日时分秒") + private Date startTime; + + /** + * 结束时间(年月日时分秒) + */ + @ExcelProperty(value = "结束时间", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "年=月日时分秒") + private Date endTime; + + /** + * 请假时长(天) + */ + @ExcelProperty(value = "请假时长", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "天=") + private Double leaveDuration; + + /** + * 是否离校:0-否,1-是 + */ + @ExcelProperty(value = "是否离校:0-否,1-是") + private String isLeaveSchool; + + /** + * 是否需要销假:0-否,1-是 + */ + @ExcelProperty(value = "是否需要销假:0-否,1-是") + private String needCancel; + + /** + * 紧急联系人 + */ + @ExcelProperty(value = "紧急联系人") + private String emergencyContact; + + /** + * 紧急联系电话 + */ + @ExcelProperty(value = "紧急联系电话") + private String emergencyPhone; + + /** + * 请假原因 + */ + @ExcelProperty(value = "请假原因") + private String leaveReason; + + /** + * 请假时地理位置 + */ + @ExcelProperty(value = "请假时地理位置") + private String leaveLocation; + + /** + * 附件OSS文件ID(逗号分隔) + */ + @ExcelProperty(value = "附件OSS文件ID", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "逗=号分隔") + private String attachmentOssIds; + + /** + * 审批状态:"cancel", "已撤销" "draft", "草稿" "waiting", "待审核" "finish", "已完成" + * "invalid", "已作废" "back", "已退回" "termination", "已终止" + */ + @ExcelProperty(value = "审批状态:cancel-已撤销 draft-草稿 waiting-待审核 finish-已完成 invalid-已作废 back-已退回 termination-已终止") + private String approvalStatus; + + /** + * 审批意见 + */ + @ExcelProperty(value = "审批意见") + private String approvalOpinion; + + /** + * 审批时间 + */ + @ExcelProperty(value = "审批时间") + private Date approvalTime; + + /** + * 审批人ID + */ + @ExcelProperty(value = "审批人ID") + private Long approvalBy; + + /** + * 审批人姓名 + */ + @ExcelProperty(value = "审批人姓名") + private String approvalByName; + + /** + * 销假状态:0-未销假,1-已销假,2-逾期未销假 3 - 无需销假 "cancel", "已撤销" "draft", "草稿" "waiting", + * "待审核" "finish", "已完成" "invalid", "已作废" "back", "已退回" "termination", "已终止" + */ + @ExcelProperty(value = "销假状态:0-未销假,1-已销假,2-逾期未销假 3 - 无需销假 cancel-已撤销 draft-草稿 waiting-待审核 finish-已完成 invalid-已作废 back-已退回 termination-已终止 ") + private String cancelStatus; + + /** + * 销假时间 + */ + @ExcelProperty(value = "销假时间") + private Date cancelTime; + + /** + * 销假地理位置 + */ + @ExcelProperty(value = "销假地理位置") + private String cancelLocation; + + /** + * 销假照片OSS文件ID(逗号分隔) + */ + @ExcelProperty(value = "销假照片OSS文件ID", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "逗=号分隔") + private String cancelPhotoOssIds; + + /** + * 销假备注 + */ + @ExcelProperty(value = "销假备注") + private String cancelRemark; + + /** + * 学生请假表id + */ + @ExcelProperty(value = "学生请假表id") + private Long leaveId; + +} diff --git a/backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/XgStudentCancelLeaveMapper.java b/backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/XgStudentCancelLeaveMapper.java new file mode 100644 index 00000000..caab78f9 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/XgStudentCancelLeaveMapper.java @@ -0,0 +1,15 @@ +package org.dromara.workflow.mapper; + +import org.dromara.workflow.domain.XgStudentCancelLeave; +import org.dromara.workflow.domain.vo.XgStudentCancelLeaveVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 学生销假Mapper接口 + * + * @author zlwu + * @date 2025-08-05 + */ +public interface XgStudentCancelLeaveMapper extends BaseMapperPlus { + +} diff --git a/backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IXgStudentCancelLeaveService.java b/backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IXgStudentCancelLeaveService.java new file mode 100644 index 00000000..53e9a1da --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IXgStudentCancelLeaveService.java @@ -0,0 +1,84 @@ +package org.dromara.workflow.service; + +import org.dromara.workflow.domain.vo.XgStudentCancelLeaveVo; +import org.dromara.workflow.domain.bo.XgStudentCancelLeaveBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 学生销假Service接口 + * + * @author zlwu + * @date 2025-08-05 + */ +public interface IXgStudentCancelLeaveService { + + /** + * 查询学生销假 + * + * @param id 主键 + * @return 学生销假 + */ + XgStudentCancelLeaveVo queryById(Long id); + + /** + * 分页查询学生销假列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 学生销假分页列表 + */ + TableDataInfo queryPageList(XgStudentCancelLeaveBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的学生销假列表 + * + * @param bo 查询条件 + * @return 学生销假列表 + */ + List queryList(XgStudentCancelLeaveBo bo); + + /** + * 新增学生销假 + * + * @param bo 学生销假 + * @return 新增成功的学生销假信息 + */ + XgStudentCancelLeaveVo insertByBo(XgStudentCancelLeaveBo bo); + + /** + * 修改学生销假 + * + * @param bo 学生销假 + * @return 是否修改成功 + */ + Boolean updateByBo(XgStudentCancelLeaveBo bo); + + /** + * 校验并批量删除学生销假信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 根据请假ID获取销假ID + * + * @param leaveId 请假ID + * @return 销假ID,如果不存在则返回null + */ + Long getCancelLeaveIdByLeaveId(Long leaveId); + + /** + * 根据销假ID获取请假ID + * + * @param cancelLeaveId 销假ID + * @return 请假ID,如果不存在则返回null + */ + Long getLeaveIdByCancelLeaveId(Long cancelLeaveId); +} diff --git a/backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/XgStudentCancelLeaveServiceImpl.java b/backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/XgStudentCancelLeaveServiceImpl.java new file mode 100644 index 00000000..48ae1d71 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/XgStudentCancelLeaveServiceImpl.java @@ -0,0 +1,256 @@ +package org.dromara.workflow.service.impl; + +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.dromara.workflow.domain.bo.XgStudentCancelLeaveBo; +import org.dromara.workflow.domain.vo.XgStudentCancelLeaveVo; +import org.dromara.workflow.domain.XgStudentCancelLeave; +import org.dromara.workflow.mapper.XgStudentCancelLeaveMapper; +import org.dromara.workflow.service.IXgStudentCancelLeaveService; +import org.dromara.workflow.service.IXgStudentLeaveService; +import org.dromara.workflow.domain.bo.XgStudentLeaveBo; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 学生销假Service业务层处理 + * + * @author zlwu + * @date 2025-08-05 + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class XgStudentCancelLeaveServiceImpl implements IXgStudentCancelLeaveService { + + private final XgStudentCancelLeaveMapper baseMapper; + private final IXgStudentLeaveService xgStudentLeaveService; + + /** + * 查询学生销假 + * + * @param id 主键 + * @return 学生销假 + */ + @Override + public XgStudentCancelLeaveVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + /** + * 分页查询学生销假列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 学生销假分页列表 + */ + @Override + public TableDataInfo queryPageList(XgStudentCancelLeaveBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的学生销假列表 + * + * @param bo 查询条件 + * @return 学生销假列表 + */ + @Override + public List queryList(XgStudentCancelLeaveBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(XgStudentCancelLeaveBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(XgStudentCancelLeave::getId); + lqw.eq(bo.getDeleted() != null, XgStudentCancelLeave::getDeleted, bo.getDeleted()); + lqw.eq(bo.getStudentId() != null, XgStudentCancelLeave::getStudentId, bo.getStudentId()); + lqw.like(StringUtils.isNotBlank(bo.getStudentName()), XgStudentCancelLeave::getStudentName, + bo.getStudentName()); + lqw.eq(StringUtils.isNotBlank(bo.getStudentNo()), XgStudentCancelLeave::getStudentNo, + bo.getStudentNo()); + lqw.eq(bo.getClassId() != null, XgStudentCancelLeave::getClassId, bo.getClassId()); + lqw.like(StringUtils.isNotBlank(bo.getClassName()), XgStudentCancelLeave::getClassName, + bo.getClassName()); + lqw.eq(bo.getMajorId() != null, XgStudentCancelLeave::getMajorId, bo.getMajorId()); + lqw.like(StringUtils.isNotBlank(bo.getMajorName()), XgStudentCancelLeave::getMajorName, + bo.getMajorName()); + lqw.eq(bo.getCollegeId() != null, XgStudentCancelLeave::getCollegeId, bo.getCollegeId()); + lqw.like(StringUtils.isNotBlank(bo.getCollegeName()), XgStudentCancelLeave::getCollegeName, + bo.getCollegeName()); + lqw.eq(StringUtils.isNotBlank(bo.getLeaveTypeCode()), XgStudentCancelLeave::getLeaveTypeCode, + bo.getLeaveTypeCode()); + lqw.like(StringUtils.isNotBlank(bo.getLeaveTypeName()), XgStudentCancelLeave::getLeaveTypeName, + bo.getLeaveTypeName()); + lqw.eq(bo.getStartTime() != null, XgStudentCancelLeave::getStartTime, bo.getStartTime()); + lqw.eq(bo.getEndTime() != null, XgStudentCancelLeave::getEndTime, bo.getEndTime()); + lqw.eq(bo.getLeaveDuration() != null, XgStudentCancelLeave::getLeaveDuration, bo.getLeaveDuration()); + lqw.eq(StringUtils.isNotBlank(bo.getIsLeaveSchool()), XgStudentCancelLeave::getIsLeaveSchool, + bo.getIsLeaveSchool()); + lqw.eq(StringUtils.isNotBlank(bo.getNeedCancel()), XgStudentCancelLeave::getNeedCancel, + bo.getNeedCancel()); + lqw.eq(StringUtils.isNotBlank(bo.getEmergencyContact()), XgStudentCancelLeave::getEmergencyContact, + bo.getEmergencyContact()); + lqw.eq(StringUtils.isNotBlank(bo.getEmergencyPhone()), XgStudentCancelLeave::getEmergencyPhone, + bo.getEmergencyPhone()); + lqw.eq(StringUtils.isNotBlank(bo.getLeaveReason()), XgStudentCancelLeave::getLeaveReason, + bo.getLeaveReason()); + lqw.eq(StringUtils.isNotBlank(bo.getLeaveLocation()), XgStudentCancelLeave::getLeaveLocation, + bo.getLeaveLocation()); + lqw.eq(StringUtils.isNotBlank(bo.getAttachmentOssIds()), XgStudentCancelLeave::getAttachmentOssIds, + bo.getAttachmentOssIds()); + lqw.eq(StringUtils.isNotBlank(bo.getApprovalStatus()), XgStudentCancelLeave::getApprovalStatus, + bo.getApprovalStatus()); + lqw.eq(StringUtils.isNotBlank(bo.getApprovalOpinion()), XgStudentCancelLeave::getApprovalOpinion, + bo.getApprovalOpinion()); + lqw.eq(bo.getApprovalTime() != null, XgStudentCancelLeave::getApprovalTime, bo.getApprovalTime()); + lqw.eq(bo.getApprovalBy() != null, XgStudentCancelLeave::getApprovalBy, bo.getApprovalBy()); + lqw.like(StringUtils.isNotBlank(bo.getApprovalByName()), XgStudentCancelLeave::getApprovalByName, + bo.getApprovalByName()); + lqw.eq(StringUtils.isNotBlank(bo.getCancelStatus()), XgStudentCancelLeave::getCancelStatus, + bo.getCancelStatus()); + lqw.eq(bo.getCancelTime() != null, XgStudentCancelLeave::getCancelTime, bo.getCancelTime()); + lqw.eq(StringUtils.isNotBlank(bo.getCancelLocation()), XgStudentCancelLeave::getCancelLocation, + bo.getCancelLocation()); + lqw.eq(StringUtils.isNotBlank(bo.getCancelPhotoOssIds()), XgStudentCancelLeave::getCancelPhotoOssIds, + bo.getCancelPhotoOssIds()); + lqw.eq(StringUtils.isNotBlank(bo.getCancelRemark()), XgStudentCancelLeave::getCancelRemark, + bo.getCancelRemark()); + lqw.eq(bo.getLeaveId() != null, XgStudentCancelLeave::getLeaveId, bo.getLeaveId()); + return lqw; + } + + /** + * 新增学生销假 + * + * @param bo 学生销假 + * @return 新增成功的学生销假信息 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public XgStudentCancelLeaveVo insertByBo(XgStudentCancelLeaveBo bo) { + XgStudentCancelLeave add = MapstructUtils.convert(bo, XgStudentCancelLeave.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + + // 更新学生请假表中的销假相关字段 + if (bo.getLeaveId() != null) { + XgStudentLeaveBo leaveBo = new XgStudentLeaveBo(); + leaveBo.setId(bo.getLeaveId()); + leaveBo.setCancelStatus(bo.getCancelStatus()); + leaveBo.setCancelTime(bo.getCancelTime()); + leaveBo.setCancelLocation(bo.getCancelLocation()); + leaveBo.setCancelPhotoOssIds(bo.getCancelPhotoOssIds()); + leaveBo.setCancelRemark(bo.getCancelRemark()); + + xgStudentLeaveService.updateByBo(leaveBo); + } + + // 返回新增成功的记录信息 + return MapstructUtils.convert(add, XgStudentCancelLeaveVo.class); + } + return null; + } + + /** + * 修改学生销假 + * + * @param bo 学生销假 + * @return 是否修改成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean updateByBo(XgStudentCancelLeaveBo bo) { + XgStudentCancelLeave update = MapstructUtils.convert(bo, XgStudentCancelLeave.class); + validEntityBeforeSave(update); + boolean flag = baseMapper.updateById(update) > 0; + + if (flag) { + // 同步更新学生请假表中的销假相关字段 + if (bo.getLeaveId() != null) { + XgStudentLeaveBo leaveBo = new XgStudentLeaveBo(); + leaveBo.setId(bo.getLeaveId()); + leaveBo.setCancelStatus(bo.getCancelStatus()); + leaveBo.setCancelTime(bo.getCancelTime()); + leaveBo.setCancelLocation(bo.getCancelLocation()); + leaveBo.setCancelPhotoOssIds(bo.getCancelPhotoOssIds()); + leaveBo.setCancelRemark(bo.getCancelRemark()); + + xgStudentLeaveService.updateByBo(leaveBo); + } + } + + return flag; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(XgStudentCancelLeave entity) { + // TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除学生销假信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + // TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } + + /** + * 根据请假ID获取销假ID + * + * @param leaveId 请假ID + * @return 销假ID,如果不存在则返回null + */ + @Override + public Long getCancelLeaveIdByLeaveId(Long leaveId) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(XgStudentCancelLeave::getLeaveId, leaveId); + lqw.eq(XgStudentCancelLeave::getDeleted, 0L); // 只查询未删除的记录 + lqw.select(XgStudentCancelLeave::getId); + XgStudentCancelLeave cancelLeave = baseMapper.selectOne(lqw); + return cancelLeave != null ? cancelLeave.getId() : null; + } + + /** + * 根据销假ID获取请假ID + * + * @param cancelLeaveId 销假ID + * @return 请假ID,如果不存在则返回null + */ + @Override + public Long getLeaveIdByCancelLeaveId(Long cancelLeaveId) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(XgStudentCancelLeave::getId, cancelLeaveId); + lqw.eq(XgStudentCancelLeave::getDeleted, 0L); // 只查询未删除的记录 + lqw.select(XgStudentCancelLeave::getLeaveId); + XgStudentCancelLeave cancelLeave = baseMapper.selectOne(lqw); + return cancelLeave != null ? cancelLeave.getLeaveId() : null; + } +} diff --git a/backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/XgStudentLeaveServiceImpl.java b/backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/XgStudentLeaveServiceImpl.java index 7d8dde78..571b449a 100644 --- a/backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/XgStudentLeaveServiceImpl.java +++ b/backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/XgStudentLeaveServiceImpl.java @@ -17,10 +17,13 @@ import org.dromara.workflow.mapper.XgStudentLeaveMapper; import org.dromara.workflow.service.IXgStudentLeaveService; import org.dromara.workflow.common.ConditionalOnEnable; import org.dromara.workflow.domain.TestLeave; +import org.dromara.workflow.domain.XgStudentCancelLeave; import org.dromara.workflow.domain.bo.TestLeaveBo; import org.dromara.workflow.domain.vo.TestLeaveVo; import org.dromara.workflow.mapper.TestLeaveMapper; +import org.dromara.workflow.mapper.XgStudentCancelLeaveMapper; import org.dromara.workflow.service.ITestLeaveService; +import org.dromara.workflow.service.IXgStudentCancelLeaveService; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -57,6 +60,7 @@ public class XgStudentLeaveServiceImpl implements IXgStudentLeaveService { private final XgStudentLeaveMapper baseMapper; private final WorkflowService workflowService; + private final XgStudentCancelLeaveMapper xgStudentCancelLeaveMapper; /** * 查询学生请假 - 记录学生的请假申请、审批和销假信息 @@ -226,6 +230,43 @@ public class XgStudentLeaveServiceImpl implements IXgStudentLeaveService { baseMapper.updateById(xgStudentLeave); } + /** + * 销假流程 + * 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成,单任务完成等) + * 正常使用只需#processEvent.flowCode=='leave1' + * 示例为了方便则使用startsWith匹配了全部示例key + * + * @param processEvent 参数 + */ + @Transactional(rollbackFor = Exception.class) + @EventListener(condition = "#processEvent.flowCode.startsWith('hzdyjs-xj')") + public void processHandl_xj(ProcessEvent processEvent) { + // 更新了销假表 + log.info("当前任务执行了{}", processEvent.toString()); + XgStudentCancelLeave xgStudentCancelLeave = xgStudentCancelLeaveMapper + .selectById(Long.valueOf(processEvent.getBusinessId())); + // 更新了请假表 + XgStudentLeave xgStudentLeave = baseMapper.selectById(xgStudentCancelLeave.getLeaveId()); + xgStudentCancelLeave.setCancelStatus(processEvent.getStatus()); + xgStudentLeave.setCancelStatus(processEvent.getStatus()); + // 用于例如审批附件 审批意见等 存储到业务表内 自行根据业务实现存储流程 + Map params = processEvent.getParams(); + if (MapUtil.isNotEmpty(params)) { + // 历史任务扩展(通常为附件) + String hisTaskExt = Convert.toStr(params.get("hisTaskExt")); + // 办理人 + String handler = Convert.toStr(params.get("handler")); + // 办理意见 + String message = Convert.toStr(params.get("message")); + } + if (processEvent.getSubmit()) { + xgStudentCancelLeave.setCancelStatus(BusinessStatusEnum.WAITING.getStatus()); + xgStudentLeave.setCancelStatus(BusinessStatusEnum.WAITING.getStatus()); + } + xgStudentCancelLeaveMapper.updateById(xgStudentCancelLeave); + baseMapper.updateById(xgStudentLeave); + } + /** * 执行任务创建监听 * 示例:也可通过 @EventListener(condition = @@ -242,6 +283,23 @@ public class XgStudentLeaveServiceImpl implements IXgStudentLeaveService { log.info("当前任务创建了{}", processTaskEvent.toString()); } + /** + * 销假 + * 执行任务创建监听 + * 示例:也可通过 @EventListener(condition = + * "#processTaskEvent.flowCode=='leave1'")进行判断 + * 在方法中判断流程节点key + * if ("xxx".equals(processTaskEvent.getNodeCode())) { + * //执行业务逻辑 + * } + * + * @param processTaskEvent 参数 + */ + @EventListener(condition = "#processTaskEvent.flowCode.startsWith('hzdyjs-xj')") + public void processTaskHandler_xj(ProcessTaskEvent processTaskEvent) { + log.info("当前任务创建了{}", processTaskEvent.toString()); + } + /** * 监听删除流程事件 * 正常使用只需#processDeleteEvent.flowCode=='leave1' @@ -259,4 +317,33 @@ public class XgStudentLeaveServiceImpl implements IXgStudentLeaveService { baseMapper.deleteById(xgStudentLeave.getId()); } + /** + * 销假 + * 监听删除流程事件 + * 正常使用只需#processDeleteEvent.flowCode=='leave1' + * 示例为了方便则使用startsWith匹配了全部示例key + * + * @param processDeleteEvent 参数 + */ + @Transactional(rollbackFor = Exception.class) + @EventListener(condition = "#processDeleteEvent.flowCode.startsWith('hzdyjs-xj')") + public void processDeleteHandler_xj(ProcessDeleteEvent processDeleteEvent) { + log.info("监听删除流程事件,当前任务执行了{}", processDeleteEvent.toString()); + // 删除销假表数据 + XgStudentCancelLeave xgStudentCancelLeave = xgStudentCancelLeaveMapper + .selectById(Long.valueOf(processDeleteEvent.getBusinessId())); + if (ObjectUtil.isNull(xgStudentCancelLeave)) { + return; + } + xgStudentCancelLeaveMapper.deleteById(xgStudentCancelLeave.getId()); + // 更新了请假表 + XgStudentLeave xgStudentLeave = baseMapper.selectById(xgStudentCancelLeave.getLeaveId()); + xgStudentLeave.setCancelStatus("0"); + xgStudentLeave.setCancelTime(null); + xgStudentLeave.setCancelLocation(null); + xgStudentLeave.setCancelPhotoOssIds(null); + xgStudentLeave.setCancelRemark(null); + baseMapper.updateById(xgStudentLeave); + } + } diff --git a/backend/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/studentCancelLeave/XgStudentCancelLeaveMapper.xml b/backend/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/studentCancelLeave/XgStudentCancelLeaveMapper.xml new file mode 100644 index 00000000..a488de9e --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/studentCancelLeave/XgStudentCancelLeaveMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/docs/变更管理/code-adjust-record-2025-01-27-cursor-attachment-optimization.md b/docs/变更管理/code-adjust-record-2025-01-27-cursor-attachment-optimization.md new file mode 100644 index 00000000..60361bea --- /dev/null +++ b/docs/变更管理/code-adjust-record-2025-01-27-cursor-attachment-optimization.md @@ -0,0 +1,153 @@ +# 销假表单附件上传区域优化变更记录 + +**变更时间**: 2025-01-27 14:30:00 +**变更人员**: Cursor AI +**变更文件**: `web/src/views/xg/xsjcxx/xsqj/xjdialog.vue` +**变更类型**: 功能优化 + +## 🎯 变更目标 + +解决销假表单中附件上传区域当上传很多附件时,附件区域信息显示不完整的问题。 + +## 🔧 具体变更内容 + +### 1. 附件容器高度优化 +- **原高度**: `max-height: 600px` +- **新高度**: `max-height: 800px` +- **优化效果**: 增加200px高度,支持更多附件显示 + +### 2. 滚动条样式优化 +```css +/* 新增滚动条样式 */ +.attachment-upload-container::-webkit-scrollbar { + width: 8px; +} + +.attachment-upload-container::-webkit-scrollbar-track { + background: #f1f1f1; + border-radius: 4px; +} + +.attachment-upload-container::-webkit-scrollbar-thumb { + background: #c1c1c1; + border-radius: 4px; +} + +.attachment-upload-container::-webkit-scrollbar-thumb:hover { + background: #a8a8a8; +} +``` +**优化效果**: 滚动条更明显,用户体验更好 + +### 3. 响应式布局优化 +```css +/* 支持响应式布局 */ +.attachment-upload-container :deep(.el-upload-list--picture-card) { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); + gap: 12px; + margin-top: 12px; + padding-bottom: 20px; + min-height: 200px; +} + +/* 大屏幕:5列布局 */ +@media (min-width: 1200px) { + grid-template-columns: repeat(5, 1fr); +} + +/* 中等屏幕:4列布局 */ +@media (min-width: 768px) and (max-width: 1199px) { + grid-template-columns: repeat(4, 1fr); +} + +/* 小屏幕:3列布局 */ +@media (max-width: 767px) { + grid-template-columns: repeat(3, 1fr); +} +``` +**优化效果**: 不同屏幕尺寸下都有最佳显示效果 + +### 4. 附件数量提示功能 +```vue + +
+ + 已上传 {{ cancelAttachmentList.length }} 个附件 + (可滚动查看更多) +
+``` +**优化效果**: 用户清楚知道已上传的附件数量,当附件较多时提示可滚动 + +### 5. 附件卡片布局优化 +- **卡片高度**: 从 `180px` 增加到 `200px` +- **文件名区域**: 从 `32px` 增加到 `40px` +- **字体大小**: 从 `11px` 增加到 `12px` +- **字体粗细**: 增加 `font-weight: 500` + +**优化效果**: 附件信息显示更清晰,可读性更好 + +### 6. 附件数量提示样式 +```css +.attachment-count-tip { + display: flex; + align-items: center; + gap: 6px; + padding: 8px 12px; + background: #e6f7ff; + border: 1px solid #91d5ff; + border-radius: 4px; + margin-bottom: 8px; + font-size: 13px; + color: #1890ff; +} + +.scroll-tip { + color: #52c41a; + font-weight: 500; +} +``` +**优化效果**: 美观的提示样式,用户友好 + +## 📊 优化效果对比 + +### 优化前 +- ❌ 附件容器高度限制600px,附件多时显示不全 +- ❌ 滚动条不明显,用户可能不知道可以滚动 +- ❌ 固定5列布局,小屏幕显示效果差 +- ❌ 没有附件数量提示 +- ❌ 附件卡片信息显示空间有限 + +### 优化后 +- ✅ 附件容器高度增加到800px,支持更多附件 +- ✅ 滚动条样式优化,更明显易用 +- ✅ 响应式布局,适配不同屏幕尺寸 +- ✅ 附件数量提示,用户清楚了解状态 +- ✅ 附件卡片布局优化,信息显示更清晰 + +## 🎯 用户体验提升 + +1. **信息完整性**: 附件多时也能完整显示所有信息 +2. **操作便利性**: 明显的滚动条和提示信息 +3. **视觉友好性**: 响应式布局和优化的卡片设计 +4. **状态清晰性**: 附件数量提示让用户了解当前状态 + +## 📝 技术要点 + +1. **CSS Grid布局**: 使用 `grid-template-columns: repeat(auto-fit, minmax(160px, 1fr))` 实现响应式 +2. **媒体查询**: 针对不同屏幕尺寸优化列数 +3. **滚动条定制**: 使用 `::-webkit-scrollbar` 伪元素定制滚动条样式 +4. **Vue响应式**: 利用 `cancelAttachmentList.length` 动态显示提示信息 + +## 🔄 后续建议 + +1. **性能优化**: 当附件数量特别多时,可考虑虚拟滚动 +2. **交互优化**: 可添加附件预览功能 +3. **批量操作**: 可添加批量删除、批量下载功能 +4. **拖拽排序**: 可添加附件拖拽排序功能 + +--- + +**变更状态**: ✅ 已完成 +**测试状态**: 🔄 待测试 +**文档状态**: ✅ 已更新 \ No newline at end of file diff --git a/docs/变更管理/code-adjust-record-2025-01-27-cursor.md b/docs/变更管理/code-adjust-record-2025-01-27-cursor.md index 89b45b99..a565ce3e 100644 --- a/docs/变更管理/code-adjust-record-2025-01-27-cursor.md +++ b/docs/变更管理/code-adjust-record-2025-01-27-cursor.md @@ -1,5 +1,204 @@ # 代码调整记录 - 2025-01-27 - cursor +## 🔧 前端销假API调用优化 (2025-01-27 14:30:00) + +### 功能概述 +修改前端销假对话框(`xjdialog.vue`)中的`submitForm`方法,将`addStudentCancelLeave` API调用改为调用后端`XgStudentCancelLeaveController.java`中的`add`方法,主要针对出参处理进行了优化。 + +### 详细变更 + +#### 1. 前端API类型定义优化 +**文件**: `web/src/api/workflow/studentCancelLeave/studentCancelLeave/index.ts` + +**修改内容**: +- 为`addStudentCancelLeave`方法添加了返回类型定义:`AxiosPromise` +- 为`getCancelLeaveIdByLeaveId`方法添加了返回类型定义:`AxiosPromise` + +**修改前**: +```typescript +export const addStudentCancelLeave = (data: StudentCancelLeaveForm) => { + return request({ + url: '/studentCancelLeave/studentCancelLeave', + method: 'post', + data: data + }); +}; +``` + +**修改后**: +```typescript +export const addStudentCancelLeave = (data: StudentCancelLeaveForm): AxiosPromise => { + return request({ + url: '/studentCancelLeave/studentCancelLeave', + method: 'post', + data: data + }); +}; +``` + +#### 2. 前端业务逻辑优化 +**文件**: `web/src/views/xg/xsjcxx/xsqj/xjdialog.vue` + +**修改内容**: + +1. **新增销假记录处理优化**: + ```javascript + // 调用后端 XgStudentCancelLeaveController 的 add 方法 + res = await addStudentCancelLeave(updateData).finally(() => (buttonLoading.value = false)); + // 从返回结果中获取新创建的销假记录ID + if (res && res.data && res.data.id) { + cancelLeaveId = res.data.id; + } + ``` + +2. **销假信息获取优化**: + ```javascript + // 根据id 获取销假的信息 传给流程启动的函数 + const cancelInfoResponse = await getStudentCancelLeave(cancelLeaveId); + const cancelInfo = cancelInfoResponse?.data; + ``` + +### 修改原因 + +1. **API返回类型统一**: 确保前端API调用与后端控制器返回类型一致 +2. **数据处理优化**: 正确处理后端`R`类型的返回数据 +3. **业务逻辑完善**: 确保新增销假记录后能正确获取新创建的记录ID + +### 影响范围 + +- 前端销假功能的新增操作 +- 工作流启动时的数据传递 +- API类型定义的完整性 + +### 测试建议 + +1. 测试新增销假记录功能 +2. 验证工作流启动时数据传递的正确性 +3. 检查API返回数据的处理是否正确 + +### 相关文件 + +- `web/src/views/xg/xsjcxx/xsqj/xjdialog.vue` +- `web/src/api/workflow/studentCancelLeave/studentCancelLeave/index.ts` +- `backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/XgStudentCancelLeaveController.java` + +--- + +## 🔧 学生销假控制器新增根据请假ID获取销假ID功能 (2025-01-27 17:00:00) + +### 功能概述 +在 `XgStudentCancelLeaveController.java` 中新增了根据请假ID获取销假ID的功能,支持通过请假记录快速查找对应的销假记录。 + +### 详细变更 + +#### 1. Service接口扩展 +**文件**: `backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IXgStudentCancelLeaveService.java` + +**新增方法**: +```java +/** + * 根据请假ID获取销假ID + * + * @param leaveId 请假ID + * @return 销假ID,如果不存在则返回null + */ +Long getCancelLeaveIdByLeaveId(Long leaveId); +``` + +#### 2. Service实现类 +**文件**: `backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/XgStudentCancelLeaveServiceImpl.java` + +**新增实现方法**: +```java +/** + * 根据请假ID获取销假ID + * + * @param leaveId 请假ID + * @return 销假ID,如果不存在则返回null + */ +@Override +public Long getCancelLeaveIdByLeaveId(Long leaveId) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(XgStudentCancelLeave::getLeaveId, leaveId); + lqw.eq(XgStudentCancelLeave::getDeleted, 0L); // 只查询未删除的记录 + lqw.select(XgStudentCancelLeave::getId); + XgStudentCancelLeave cancelLeave = baseMapper.selectOne(lqw); + return cancelLeave != null ? cancelLeave.getId() : null; +} +``` + +#### 3. Controller接口 +**文件**: `backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/XgStudentCancelLeaveController.java` + +**新增接口方法**: +```java +/** + * 根据请假ID获取销假ID + * + * @param leaveId 请假ID + */ +@SaCheckPermission("studentCancelLeave:studentCancelLeave:query") +@GetMapping("/getCancelLeaveId/{leaveId}") +public R getCancelLeaveIdByLeaveId(@NotNull(message = "请假ID不能为空") + @PathVariable Long leaveId) { + Long cancelLeaveId = xgStudentCancelLeaveService.getCancelLeaveIdByLeaveId(leaveId); + return R.ok(cancelLeaveId); +} +``` + +### 技术实现要点 + +#### 1. 数据库查询优化 +- 使用 `LambdaQueryWrapper` 构建查询条件 +- 通过 `leaveId` 字段进行精确匹配 +- 使用 `select()` 方法只查询需要的 `id` 字段,提高查询效率 + +#### 2. 权限控制 +- 使用 `@SaCheckPermission("studentCancelLeave:studentCancelLeave:query")` 注解 +- 复用现有的查询权限,无需额外配置 + +#### 3. 参数验证 +- 使用 `@NotNull` 注解确保请假ID不为空 +- 提供清晰的错误提示信息 + +#### 4. 返回值处理 +- 返回 `R` 类型,符合项目统一响应格式 +- 如果不存在对应的销假记录,返回 `null` + +### API接口信息 + +**接口路径**: `GET /studentCancelLeave/studentCancelLeave/getCancelLeaveId/{leaveId}` + +**请求参数**: +- `leaveId` (Long, 必填): 请假ID + +**响应格式**: +```json +{ + "code": 200, + "msg": "操作成功", + "data": 123456 +} +``` + +**权限要求**: `studentCancelLeave:studentCancelLeave:query` + +### 变更时间 +2025-01-27 17:00:00 + +### 变更人员 +Cursor AI + +### 备注 +此功能为请假管理模块的重要补充,支持根据请假记录快速查找对应的销假记录,提升系统查询效率。 + +### 🔧 重要修复 (2025-01-27 17:15:00) +**问题**: 查询条件缺少 `deleted = 0` 过滤条件,可能导致查询到已删除的记录 +**修复**: 在 `getCancelLeaveIdByLeaveId` 方法中添加 `lqw.eq(XgStudentCancelLeave::getDeleted, 0L)` 条件 +**影响**: 确保只查询未删除的有效销假记录,避免数据污染 + +--- + ## 🔧 前端金额格式化函数修复 (2025-01-27 16:30:00) ### 问题描述 @@ -9301,5 +9500,102 @@ public XgStudentLeaveVo insertByBo(XgStudentLeaveBo bo) { **记录人**: cursor **记录时间**: 2025-01-27 14:30:00 -======= +--- + +# 代码调整记录 - 2025-01-27 (续) + +## 修改时间 +2025-01-27 15:30:00 + +## 修改内容 + +### 销假界面getStudentLeaveInfo方法优化 + +**修改原因**: 用户需求 - 在销假界面中根据销假ID获取请假ID,以便正确显示请假信息 + +#### 涉及文件 +1. `web/src/api/workflow/studentCancelLeave/studentCancelLeave/index.ts` +2. `web/src/views/xg/xsjcxx/xsqj/xjdialog.vue` + +#### 具体修改 + +**1. 前端API接口新增** +- 文件: `web/src/api/workflow/studentCancelLeave/studentCancelLeave/index.ts` +- 新增方法: `getLeaveIdByCancelLeaveId` +- 功能: 根据销假ID获取请假ID +- 调用后端接口: `XgStudentCancelLeaveController.getLeaveIdByCancelLeaveId` + +```typescript +/** + * 根据销假ID获取请假ID + * @param cancelLeaveId + */ +export const getLeaveIdByCancelLeaveId = (cancelLeaveId: string | number): AxiosPromise => { + return request({ + url: `/studentCancelLeave/studentCancelLeave/getLeaveId/${cancelLeaveId}`, + method: 'get' + }); +}; +``` + +**2. 销假界面方法修改** +- 文件: `web/src/views/xg/xsjcxx/xsqj/xjdialog.vue` +- 修改方法: `getStudentLeaveInfo` +- 修改内容: + - 导入新增的API方法 + - 修改逻辑,使用 `getLeaveIdByCancelLeaveId` 替代 `getCancelLeaveIdByLeaveId` + +```typescript +// 导入语句修改 +import { + getStudentCancelLeave, + updateStudentCancelLeave, + getCancelLeaveIdByLeaveId, + getLeaveIdByCancelLeaveId, // 新增 + addStudentCancelLeave +} from '@/api/workflow/studentCancelLeave/studentCancelLeave'; + +// getStudentLeaveInfo方法修改 +const getStudentLeaveInfo = async (id: string | number) => { + try { + //通过销假id获取请假id + const leaveIdResp = await getLeaveIdByCancelLeaveId(id); // 修改:使用新的API方法 + let leaveId = leaveIdResp?.data; + console.log('通过销假ID获取到的请假ID:', leaveId); + id = leaveId || id; + + // ... 后续逻辑保持不变 + } catch (error) { + // ... 错误处理 + } +}; +``` + +#### 修改效果 + +**修改前**: +- 销假界面使用 `getCancelLeaveIdByLeaveId` 方法(根据请假ID获取销假ID) +- 逻辑错误,无法正确获取请假信息 + +**修改后**: +- 销假界面使用 `getLeaveIdByCancelLeaveId` 方法(根据销假ID获取请假ID) +- 逻辑正确,能够根据销假ID正确获取对应的请假信息 + +#### 涉及的后端接口 +- `XgStudentCancelLeaveController.getLeaveIdByCancelLeaveId` - 根据销假ID获取请假ID + +#### 测试建议 +1. 在销假界面中打开一个销假记录 +2. 验证是否正确获取到对应的请假信息 +3. 检查控制台日志,确认API调用正常 + +#### 影响范围 +- 销假界面 (`xjdialog.vue`) 的数据获取逻辑 +- 前端API接口层新增方法 +- 不影响请假界面 (`dialog.vue`) 的功能 + +--- + +**记录人**: cursor +**记录时间**: 2025-01-27 15:30:00 diff --git a/docs/变更管理/code-adjust-record-2025-01-27-wuzilong.md b/docs/变更管理/code-adjust-record-2025-01-27-wuzilong.md index 95ebb7b4..e9e1ec71 100644 --- a/docs/变更管理/code-adjust-record-2025-01-27-wuzilong.md +++ b/docs/变更管理/code-adjust-record-2025-01-27-wuzilong.md @@ -1,171 +1,82 @@ -# 文件下载缓存机制实现 - 变更记录 +# 代码调整记录 - 2025-01-27 -**变更时间**: 2025-01-27 15:30:00 -**变更人员**: wuzilong -**变更类型**: 功能增强 -**影响范围**: 文件下载服务 +## 学生销假编辑功能同步更新学生请假信息 -## 📋 变更概述 +### 修改时间 +2025-01-27 10:30:00 -为提升文件下载性能,减少对MinIO存储的重复请求,在 `SysOssServiceImpl` 中实现了基于内存的文件缓存机制。 +### 修改内容 -## 🔧 技术实现 +#### 1. 修改学生销假服务实现类 +**文件**: `backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/XgStudentCancelLeaveServiceImpl.java` -### 1. 核心组件 +**修改内容**: +- 在 `updateByBo` 方法中添加了 `@Transactional(rollbackFor = Exception.class)` 事务注解 +- 添加了同步更新学生请假表中销假相关字段的逻辑 +- 当销假信息更新成功后,根据 `leaveId` 关联更新学生请假表中的以下字段: + - `cancelStatus` - 销假状态 + - `cancelTime` - 销假时间 + - `cancelLocation` - 销假地理位置 + - `cancelPhotoOssIds` - 销假照片OSS文件ID + - `cancelRemark` - 销假备注 -#### 缓存条目类 (CacheEntry) -- 位置: `SysOssServiceImpl.java` (第67-120行) -- 功能: 存储文件数据、大小、创建时间、访问时间、内容类型 -- 特性: 支持过期时间检查 +**修改原因**: +- 确保学生销假信息的修改能够同步更新到学生请假表中 +- 保持两个表之间销假信息的一致性 +- 避免数据不一致的问题 -#### LRU缓存实现 -- 存储: `ConcurrentHashMap` -- 并发安全: `ReentrantReadWriteLock` -- 统计: `AtomicLong` 计数器 +### 技术实现 -### 2. 配置管理 +#### 事务管理 +- 使用 `@Transactional(rollbackFor = Exception.class)` 确保数据一致性 +- 如果销假表更新失败或请假表更新失败,都会回滚整个事务 -#### 配置类 -- 文件: `FileCacheConfig.java` -- 功能: 管理所有缓存参数 -- 配置前缀: `system.file-cache` +#### 同步逻辑 +```java +if (flag) { + // 同步更新学生请假表中的销假相关字段 + if (bo.getLeaveId() != null) { + XgStudentLeaveBo leaveBo = new XgStudentLeaveBo(); + leaveBo.setId(bo.getLeaveId()); + leaveBo.setCancelStatus(bo.getCancelStatus()); + leaveBo.setCancelTime(bo.getCancelTime()); + leaveBo.setCancelLocation(bo.getCancelLocation()); + leaveBo.setCancelPhotoOssIds(bo.getCancelPhotoOssIds()); + leaveBo.setCancelRemark(bo.getCancelRemark()); -#### 配置参数 -```yaml -system: - file-cache: - enabled: true # 是否启用缓存 - max-cache-size: 100 # 最大文件数量 - max-cache-size-bytes: 524288000 # 最大缓存大小(500MB) - expire-time-ms: 1800000 # 过期时间(30分钟) - max-single-file-size: 52428800 # 单文件最大大小(50MB) - evict-ratio: 20 # LRU淘汰比例(20%) - enable-stats: true # 启用统计 - cleanup-interval-ms: 300000 # 清理间隔(5分钟) + xgStudentLeaveService.updateByBo(leaveBo); + } +} ``` -### 3. API接口 +### 影响范围 +- **学生销假管理**: 编辑销假信息时会同步更新请假表 +- **数据一致性**: 确保销假信息在两个表中保持一致 +- **业务流程**: 不影响现有的销假业务流程 -#### 新增接口 -1. **获取缓存统计**: `GET /resource/oss/cache/stats` -2. **清空缓存**: `DELETE /resource/oss/cache/clear` -3. **移除指定缓存**: `DELETE /resource/oss/cache/{ossId}` +### 测试建议 +1. 测试编辑学生销假信息功能 +2. 验证学生请假表中的销假字段是否正确更新 +3. 测试事务回滚功能(模拟更新失败场景) -#### 权限配置 -- `system:oss:cache:stats` - 查看缓存统计 -- `system:oss:cache:clear` - 清空缓存 -- `system:oss:cache:remove` - 移除指定缓存 +### 相关文件 +- `backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/XgStudentCancelLeaveController.java` +- `backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IXgStudentCancelLeaveService.java` +- `backend/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/XgStudentCancelLeaveBo.java` -## 📁 修改文件清单 +#### 2. 创建学生销假管理API文档 +**文件**: `docs/开发文档/API/学生销假管理API.md` -### 1. 核心实现文件 -- `backend/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java` - - 新增缓存相关字段和方法 - - 修改 `secureDownload` 方法支持缓存 - - 新增缓存管理方法 +**创建内容**: +- 完整的学生销假管理API接口文档 +- 包含7个主要接口的详细说明 +- 重点说明修改销假接口的同步更新功能 +- 提供技术实现说明和使用示例 +- 包含数据字典和注意事项 -### 2. 接口定义文件 -- `backend/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssService.java` - - 新增缓存管理接口方法 +#### 3. 更新API文档总览 +**文件**: `docs/开发文档/API/API文档总览.md` -### 3. 控制器文件 -- `backend/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java` - - 新增缓存管理API接口 - -### 4. 配置类文件 -- `backend/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/config/FileCacheConfig.java` - - 新增文件缓存配置类 - -### 5. 配置文件 -- `backend/ruoyi-modules/ruoyi-system/src/main/resources/application-file-cache.yml` - - 新增配置示例文件 - -### 6. 文档文件 -- `docs/开发文档/文件下载缓存机制说明.md` - - 新增详细的功能说明文档 - -## 🚀 功能特性 - -### 1. 智能缓存策略 -- **大小控制**: 只缓存小于50MB的文件 -- **LRU淘汰**: 空间不足时淘汰最久未访问的文件 -- **过期管理**: 30分钟自动过期 -- **并发安全**: 读写锁保证数据一致性 - -### 2. 性能优化 -- **缓存命中**: 直接从内存返回,响应时间减少80-90% -- **流式传输**: 支持大文件分块下载 -- **统计监控**: 实时监控缓存命中率和大小 - -### 3. 管理功能 -- **统计信息**: 缓存大小、命中率、访问次数 -- **手动管理**: 支持清空和移除指定缓存 -- **配置化**: 所有参数可通过配置文件调整 - -## 📊 性能提升 - -### 预期效果 -- **响应时间**: 缓存命中时减少80-90% -- **MinIO压力**: 显著减少重复请求 -- **并发性能**: 支持多用户同时访问 -- **整体性能**: 平均下载速度提升60-80% - -### 监控指标 -- 缓存命中率 > 70% -- 内存使用率合理控制 -- 响应时间显著提升 - -## ⚠️ 注意事项 - -### 1. 内存管理 -- 缓存占用JVM堆内存,需要合理配置大小 -- 建议监控应用内存使用情况 -- 大文件不会被缓存,避免内存溢出 - -### 2. 数据一致性 -- 缓存数据可能与MinIO不同步 -- 文件更新后建议清除相关缓存 -- 可通过API手动管理缓存 - -### 3. 配置建议 -- 根据服务器内存调整缓存大小 -- 根据访问模式优化过期时间 -- 定期监控缓存统计信息 - -## 🔧 测试建议 - -### 1. 功能测试 -- 测试文件下载缓存机制 -- 验证LRU淘汰策略 -- 检查过期时间管理 - -### 2. 性能测试 -- 对比缓存命中前后的响应时间 -- 测试并发下载性能 -- 监控内存使用情况 - -### 3. 压力测试 -- 模拟大量文件下载请求 -- 测试缓存满时的淘汰机制 -- 验证系统稳定性 - -## 📝 后续优化 - -### 1. 功能增强 -- 支持缓存预热 -- 添加缓存压缩 -- 实现分布式缓存 - -### 2. 监控完善 -- 集成Prometheus监控 -- 添加缓存告警 -- 完善日志记录 - -### 3. 性能优化 -- 优化LRU算法 -- 支持缓存分片 -- 添加缓存预热 - ---- - -**📋 变更确认**: 本次变更已完成代码实现、文档编写和配置管理,建议在测试环境验证后部署到生产环境。 \ No newline at end of file +**更新内容**: +- 在API模块列表中添加学生销假管理API的链接 +- 保持文档结构的一致性 \ No newline at end of file diff --git a/docs/开发文档/API/API文档总览.md b/docs/开发文档/API/API文档总览.md index d2d63f81..16fa7c02 100644 --- a/docs/开发文档/API/API文档总览.md +++ b/docs/开发文档/API/API文档总览.md @@ -15,6 +15,7 @@ - [宿舍管理员信息API](./宿舍管理员信息API.md) - [宿舍管理员授权API](./宿舍管理员授权API.md) - [学生管理员授权关系API](./学生管理员授权关系API.md) +- [学生销假管理API](./学生销假管理API.md) ### 1. 用户认证登录 diff --git a/docs/开发文档/API/学生销假管理API.md b/docs/开发文档/API/学生销假管理API.md new file mode 100644 index 00000000..f13a105a --- /dev/null +++ b/docs/开发文档/API/学生销假管理API.md @@ -0,0 +1,579 @@ +# 学生销假管理 API 接口文档 + +## 模块概述 + +**模块名称**:Student Cancel Leave / 学生销假管理 +**基础路径**:`/studentCancelLeave/studentCancelLeave` +**版本**:v1.0 +**负责人**:zlwu +**更新时间**:2025-01-27 + +### 模块功能 + +学生销假管理模块负责处理学生的销假申请和审批流程,包括销假信息的录入、修改、查询和删除。该模块与学生请假管理模块紧密关联,确保销假信息在两个表之间保持同步。 + +**核心特性**: +- 销假信息的完整生命周期管理 +- 与学生请假表的自动同步更新 +- 支持销假状态跟踪和地理位置记录 +- 提供照片上传和备注功能 + +### 权限说明 + +- **权限前缀**:`studentCancelLeave:studentCancelLeave:` +- **权限列表**: + - `studentCancelLeave:studentCancelLeave:list` - 查询销假列表 + - `studentCancelLeave:studentCancelLeave:query` - 查询销假详情 + - `studentCancelLeave:studentCancelLeave:add` - 新增销假 + - `studentCancelLeave:studentCancelLeave:edit` - 编辑销假 + - `studentCancelLeave:studentCancelLeave:remove` - 删除销假 + - `studentCancelLeave:studentCancelLeave:export` - 导出销假数据 + +--- + +## 📊 接口概览 + +### 接口分类 + +#### 基础 CRUD 接口 + +| 接口名称 | HTTP 方法 | 路径 | 权限要求 | 功能描述 | +| -------------- | --------- | --------------------------------------- | ------------------------------------------- | ---------------------- | +| 查询销假列表 | GET | `/studentCancelLeave/studentCancelLeave/list` | `studentCancelLeave:studentCancelLeave:list` | 分页查询销假列表 | +| 查询销假详情 | GET | `/studentCancelLeave/studentCancelLeave/{id}` | `studentCancelLeave:studentCancelLeave:query` | 根据 ID 查询销假详情 | +| 新增销假 | POST | `/studentCancelLeave/studentCancelLeave` | `studentCancelLeave:studentCancelLeave:add` | 创建新的销假记录 | +| 修改销假 | PUT | `/studentCancelLeave/studentCancelLeave` | `studentCancelLeave:studentCancelLeave:edit` | 更新销假信息 | +| 删除销假 | DELETE | `/studentCancelLeave/studentCancelLeave/{ids}` | `studentCancelLeave:studentCancelLeave:remove` | 批量删除销假记录 | + +#### 业务逻辑接口 + +| 接口名称 | HTTP 方法 | 路径 | 权限要求 | 功能描述 | +| ------------------ | --------- | ------------------------------------------------------- | ------------------------------------------- | ---------------------- | +| 导出销假数据 | POST | `/studentCancelLeave/studentCancelLeave/export` | `studentCancelLeave:studentCancelLeave:export` | 导出销假数据到Excel | +| 根据请假ID获取销假ID | GET | `/studentCancelLeave/studentCancelLeave/getCancelLeaveId/{leaveId}` | `studentCancelLeave:studentCancelLeave:query` | 根据请假ID查询对应的销假ID | + +### 通用响应格式 + +#### 成功响应 + +```json +{ + "code": 200, + "msg": "操作成功", + "data": { + // 响应数据 + } +} +``` + +#### 分页响应 + +```json +{ + "code": 200, + "msg": "查询成功", + "rows": [ + // 数据列表 + ], + "total": 100 +} +``` + +#### 错误响应 + +```json +{ + "code": 400001, + "msg": "参数错误", + "data": null +} +``` + +--- + +## 🔌 详细接口说明 + +### 1. 查询销假列表 + +- **接口路径**:`GET /studentCancelLeave/studentCancelLeave/list` +- **权限标识**:`studentCancelLeave:studentCancelLeave:list` +- **功能描述**:分页查询学生销假列表,支持多条件筛选 + +#### 请求参数 + +| 参数名 | 类型 | 必填 | 说明 | +| ---------------- | ------ | ---- | ------------------------ | +| pageNum | int | 否 | 页码,默认1 | +| pageSize | int | 否 | 每页大小,默认10 | +| studentName | string | 否 | 学生姓名(模糊查询) | +| studentNo | string | 否 | 学号 | +| className | string | 否 | 班级名称(模糊查询) | +| collegeName | string | 否 | 学院名称(模糊查询) | +| leaveTypeCode | string | 否 | 请假类型编码 | +| approvalStatus | string | 否 | 审批状态 | +| cancelStatus | string | 否 | 销假状态 | +| startTime | date | 否 | 开始时间 | +| endTime | date | 否 | 结束时间 | + +#### 响应数据 + +```json +{ + "code": 200, + "msg": "查询成功", + "rows": [ + { + "id": 1, + "studentId": 1001, + "studentName": "张三", + "studentNo": "2023001001", + "className": "计算机2023-1班", + "collegeName": "计算机学院", + "leaveTypeName": "事假", + "startTime": "2025-01-20 08:00:00", + "endTime": "2025-01-22 18:00:00", + "leaveDuration": 3.0, + "approvalStatus": "finish", + "cancelStatus": "1", + "cancelTime": "2025-01-22 16:30:00", + "cancelLocation": "北京市朝阳区", + "cancelRemark": "已按时返校", + "leaveId": 2001 + } + ], + "total": 1 +} +``` + +### 2. 查询销假详情 + +- **接口路径**:`GET /studentCancelLeave/studentCancelLeave/{id}` +- **权限标识**:`studentCancelLeave:studentCancelLeave:query` +- **功能描述**:根据ID查询销假详细信息 + +#### 请求参数 + +| 参数名 | 类型 | 必填 | 说明 | +| ------ | ---- | ---- | ------ | +| id | long | 是 | 销假ID | + +#### 响应数据 + +```json +{ + "code": 200, + "msg": "查询成功", + "data": { + "id": 1, + "studentId": 1001, + "studentName": "张三", + "studentNo": "2023001001", + "classId": 101, + "className": "计算机2023-1班", + "majorId": 1, + "majorName": "计算机科学与技术", + "collegeId": 1, + "collegeName": "计算机学院", + "leaveTypeCode": "SJ", + "leaveTypeName": "事假", + "startTime": "2025-01-20 08:00:00", + "endTime": "2025-01-22 18:00:00", + "leaveDuration": 3.0, + "isLeaveSchool": "1", + "needCancel": "1", + "emergencyContact": "张父", + "emergencyPhone": "13900139000", + "leaveReason": "家中有事需要处理", + "leaveLocation": "北京市朝阳区", + "attachmentOssIds": "123,456", + "approvalStatus": "finish", + "approvalOpinion": "同意请假", + "approvalTime": "2025-01-19 14:30:00", + "approvalBy": 1001, + "approvalByName": "李老师", + "cancelStatus": "1", + "cancelTime": "2025-01-22 16:30:00", + "cancelLocation": "北京市朝阳区", + "cancelPhotoOssIds": "789,101", + "cancelRemark": "已按时返校", + "leaveId": 2001 + } +} +``` + +### 3. 新增销假 + +- **接口路径**:`POST /studentCancelLeave/studentCancelLeave` +- **权限标识**:`studentCancelLeave:studentCancelLeave:add` +- **功能描述**:新增学生销假记录,并同步更新学生请假表的销假信息 + +#### 请求参数 + +```json +{ + "studentId": 1001, + "studentName": "张三", + "studentNo": "2023001001", + "classId": 101, + "className": "计算机2023-1班", + "majorId": 1, + "majorName": "计算机科学与技术", + "collegeId": 1, + "collegeName": "计算机学院", + "leaveTypeCode": "SJ", + "leaveTypeName": "事假", + "startTime": "2025-01-20 08:00:00", + "endTime": "2025-01-22 18:00:00", + "leaveDuration": 3.0, + "isLeaveSchool": "1", + "needCancel": "1", + "emergencyContact": "张父", + "emergencyPhone": "13900139000", + "leaveReason": "家中有事需要处理", + "leaveLocation": "北京市朝阳区", + "attachmentOssIds": "123,456", + "approvalStatus": "finish", + "approvalOpinion": "同意请假", + "approvalTime": "2025-01-19 14:30:00", + "approvalBy": 1001, + "approvalByName": "李老师", + "cancelStatus": "1", + "cancelTime": "2025-01-22 16:30:00", + "cancelLocation": "北京市朝阳区", + "cancelPhotoOssIds": "789,101", + "cancelRemark": "已按时返校", + "leaveId": 2001 +} +``` + +#### 响应数据 + +```json +{ + "code": 200, + "msg": "新增成功", + "data": { + "id": 1, + "studentName": "张三", + "studentNo": "2023001001", + "cancelStatus": "1", + "cancelTime": "2025-01-22 16:30:00" + } +} +``` + +### 4. 修改销假 ⭐ + +- **接口路径**:`PUT /studentCancelLeave/studentCancelLeave` +- **权限标识**:`studentCancelLeave:studentCancelLeave:edit` +- **功能描述**:修改学生销假信息,并同步更新学生请假表中的销假相关字段 + +**⚠️ 重要说明**:此接口会自动同步更新学生请假表中的销假信息,确保数据一致性。 + +#### 请求参数 + +```json +{ + "id": 1, + "cancelStatus": "1", + "cancelTime": "2025-01-22 16:30:00", + "cancelLocation": "北京市朝阳区", + "cancelPhotoOssIds": "789,101", + "cancelRemark": "已按时返校,状态良好", + "leaveId": 2001 +} +``` + +#### 响应数据 + +```json +{ + "code": 200, + "msg": "修改成功" +} +``` + +#### 同步更新说明 + +当修改销假信息时,系统会自动同步更新学生请假表中的以下字段: + +| 字段名 | 说明 | 来源 | +| ------------------- | ------------ | ----------------------- | +| `cancel_status` | 销假状态 | 销假表的 `cancelStatus` | +| `cancel_time` | 销假时间 | 销假表的 `cancelTime` | +| `cancel_location` | 销假地理位置 | 销假表的 `cancelLocation` | +| `cancel_photo_oss_ids` | 销假照片 | 销假表的 `cancelPhotoOssIds` | +| `cancel_remark` | 销假备注 | 销假表的 `cancelRemark` | + +**事务保证**:使用 `@Transactional` 注解确保两个表的更新操作要么全部成功,要么全部回滚。 + +### 5. 删除销假 + +- **接口路径**:`DELETE /studentCancelLeave/studentCancelLeave/{ids}` +- **权限标识**:`studentCancelLeave:studentCancelLeave:remove` +- **功能描述**:批量删除销假记录 + +#### 请求参数 + +| 参数名 | 类型 | 必填 | 说明 | +| ------ | ------ | ---- | ------------------------ | +| ids | string | 是 | 销假ID列表,多个用逗号分隔 | + +#### 响应数据 + +```json +{ + "code": 200, + "msg": "删除成功" +} +``` + +### 6. 导出销假数据 + +- **接口路径**:`POST /studentCancelLeave/studentCancelLeave/export` +- **权限标识**:`studentCancelLeave:studentCancelLeave:export` +- **功能描述**:导出销假数据到Excel文件 + +#### 请求参数 + +| 参数名 | 类型 | 必填 | 说明 | +| ---------------- | ------ | ---- | ------------------------ | +| studentName | string | 否 | 学生姓名(模糊查询) | +| studentNo | string | 否 | 学号 | +| className | string | 否 | 班级名称(模糊查询) | +| collegeName | string | 否 | 学院名称(模糊查询) | +| leaveTypeCode | string | 否 | 请假类型编码 | +| approvalStatus | string | 否 | 审批状态 | +| cancelStatus | string | 否 | 销假状态 | +| startTime | date | 否 | 开始时间 | +| endTime | date | 否 | 结束时间 | + +#### 响应数据 + +返回Excel文件流,文件名格式:`学生销假_yyyyMMddHHmmss.xlsx` + +### 7. 根据请假ID获取销假ID + +- **接口路径**:`GET /studentCancelLeave/studentCancelLeave/getCancelLeaveId/{leaveId}` +- **权限标识**:`studentCancelLeave:studentCancelLeave:query` +- **功能描述**:根据请假ID查询对应的销假ID + +#### 请求参数 + +| 参数名 | 类型 | 必填 | 说明 | +| ------- | ---- | ---- | ------ | +| leaveId | long | 是 | 请假ID | + +#### 响应数据 + +```json +{ + "code": 200, + "msg": "查询成功", + "data": 1 +} +``` + +--- + +## 📋 数据字典 + +### 销假状态 (cancelStatus) + +| 值 | 说明 | +| --- | -------- | +| 0 | 未销假 | +| 1 | 已销假 | +| 2 | 逾期未销假 | +| 3 | 无需销假 | + +### 审批状态 (approvalStatus) + +| 值 | 说明 | +| --------- | -------- | +| draft | 草稿 | +| waiting | 待审核 | +| finish | 已完成 | +| cancel | 已撤销 | +| invalid | 已作废 | +| back | 已退回 | +| termination | 已终止 | + +### 是否离校 (isLeaveSchool) + +| 值 | 说明 | +| --- | ---- | +| 0 | 否 | +| 1 | 是 | + +### 是否需要销假 (needCancel) + +| 值 | 说明 | +| --- | ---- | +| 0 | 否 | +| 1 | 是 | + +--- + +## 🔧 技术实现 + +### 数据同步机制 + +#### 1. 新增销假同步 + +在 `insertByBo` 方法中,新增销假记录成功后,会自动更新学生请假表的销假字段: + +```java +@Transactional(rollbackFor = Exception.class) +public XgStudentCancelLeaveVo insertByBo(XgStudentCancelLeaveBo bo) { + // 新增销假记录 + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + // 同步更新学生请假表中的销假相关字段 + if (bo.getLeaveId() != null) { + XgStudentLeaveBo leaveBo = new XgStudentLeaveBo(); + leaveBo.setId(bo.getLeaveId()); + leaveBo.setCancelStatus(bo.getCancelStatus()); + leaveBo.setCancelTime(bo.getCancelTime()); + leaveBo.setCancelLocation(bo.getCancelLocation()); + leaveBo.setCancelPhotoOssIds(bo.getCancelPhotoOssIds()); + leaveBo.setCancelRemark(bo.getCancelRemark()); + + xgStudentLeaveService.updateByBo(leaveBo); + } + } +} +``` + +#### 2. 修改销假同步 + +在 `updateByBo` 方法中,修改销假记录成功后,也会同步更新学生请假表: + +```java +@Transactional(rollbackFor = Exception.class) +public Boolean updateByBo(XgStudentCancelLeaveBo bo) { + // 修改销假记录 + boolean flag = baseMapper.updateById(update) > 0; + + if (flag) { + // 同步更新学生请假表中的销假相关字段 + if (bo.getLeaveId() != null) { + XgStudentLeaveBo leaveBo = new XgStudentLeaveBo(); + leaveBo.setId(bo.getLeaveId()); + leaveBo.setCancelStatus(bo.getCancelStatus()); + leaveBo.setCancelTime(bo.getCancelTime()); + leaveBo.setCancelLocation(bo.getCancelLocation()); + leaveBo.setCancelPhotoOssIds(bo.getCancelPhotoOssIds()); + leaveBo.setCancelRemark(bo.getCancelRemark()); + + xgStudentLeaveService.updateByBo(leaveBo); + } + } + + return flag; +} +``` + +### 事务管理 + +- 使用 `@Transactional(rollbackFor = Exception.class)` 确保数据一致性 +- 如果销假表更新失败或请假表更新失败,都会回滚整个事务 +- 保证两个表的数据始终保持同步 + +### 关联关系 + +- 销假表通过 `leave_id` 字段关联学生请假表 +- 一个请假记录只能对应一个销假记录 +- 销假记录必须关联到有效的请假记录 + +--- + +## 🚀 使用示例 + +### 前端调用示例 + +```javascript +// 修改销假信息 +const updateCancelLeave = async (data) => { + try { + const response = await request({ + url: '/studentCancelLeave/studentCancelLeave', + method: 'put', + data: { + id: 1, + cancelStatus: '1', + cancelTime: '2025-01-22 16:30:00', + cancelLocation: '北京市朝阳区', + cancelPhotoOssIds: '789,101', + cancelRemark: '已按时返校', + leaveId: 2001 + } + }); + + if (response.code === 200) { + console.log('销假信息修改成功,已同步更新请假表'); + } + } catch (error) { + console.error('修改失败:', error); + } +}; +``` + +### 后端调用示例 + +```java +// 修改销假信息 +XgStudentCancelLeaveBo bo = new XgStudentCancelLeaveBo(); +bo.setId(1L); +bo.setCancelStatus("1"); +bo.setCancelTime(new Date()); +bo.setCancelLocation("北京市朝阳区"); +bo.setCancelRemark("已按时返校"); +bo.setLeaveId(2001L); + +boolean result = xgStudentCancelLeaveService.updateByBo(bo); +if (result) { + log.info("销假信息修改成功,已同步更新请假表"); +} +``` + +--- + +## ⚠️ 注意事项 + +### 1. 数据一致性 + +- 销假信息修改时会自动同步更新学生请假表 +- 确保 `leaveId` 字段正确关联到有效的请假记录 +- 使用事务保证数据一致性 + +### 2. 权限控制 + +- 所有接口都需要相应的权限标识 +- 建议在业务层面进行权限验证 +- 注意数据访问范围的控制 + +### 3. 性能考虑 + +- 大量数据查询时建议使用分页 +- 导出功能可能耗时较长,建议异步处理 +- 注意缓存策略的使用 + +### 4. 错误处理 + +- 接口调用失败时会返回相应的错误码和错误信息 +- 建议在前端进行适当的错误处理 +- 记录详细的错误日志便于问题排查 + +--- + +## 📝 更新日志 + +| 版本 | 日期 | 更新内容 | 更新人 | +| ------ | ---------- | ---------------------------------- | ------ | +| v1.0 | 2025-01-27 | 初始版本,包含完整的CRUD接口 | zlwu | +| v1.1 | 2025-01-27 | 新增同步更新学生请假表功能 | zlwu | + +--- + +**📋 文档维护**:本文档会随着接口的更新而持续维护,如有疑问请联系开发团队。 \ No newline at end of file diff --git a/web/src/api/workflow/studentCancelLeave/studentCancelLeave/index.ts b/web/src/api/workflow/studentCancelLeave/studentCancelLeave/index.ts new file mode 100644 index 00000000..cf54dbe2 --- /dev/null +++ b/web/src/api/workflow/studentCancelLeave/studentCancelLeave/index.ts @@ -0,0 +1,85 @@ +import request from '@/utils/request'; +import { AxiosPromise } from 'axios'; +import { StudentCancelLeaveVO, StudentCancelLeaveForm, StudentCancelLeaveQuery } from '@/api/workflow/studentCancelLeave/studentCancelLeave/types'; + +/** + * 查询学生销假列表 + * @param query + * @returns {*} + */ + +export const listStudentCancelLeave = (query?: StudentCancelLeaveQuery): AxiosPromise => { + return request({ + url: '/studentCancelLeave/studentCancelLeave/list', + method: 'get', + params: query + }); +}; + +/** + * 查询学生销假详细 + * @param id + */ +export const getStudentCancelLeave = (id: string | number): AxiosPromise => { + return request({ + url: '/studentCancelLeave/studentCancelLeave/' + id, + method: 'get' + }); +}; + +/** + * 新增学生销假 + * @param data + */ +export const addStudentCancelLeave = (data: StudentCancelLeaveForm): AxiosPromise => { + return request({ + url: '/studentCancelLeave/studentCancelLeave', + method: 'post', + data: data + }); +}; + +/** + * 修改学生销假 + * @param data + */ +export const updateStudentCancelLeave = (data: StudentCancelLeaveForm) => { + return request({ + url: '/studentCancelLeave/studentCancelLeave', + method: 'put', + data: data + }); +}; + +/** + * 删除学生销假 + * @param id + */ +export const delStudentCancelLeave = (id: string | number | Array) => { + return request({ + url: '/studentCancelLeave/studentCancelLeave/' + id, + method: 'delete' + }); +}; + +/** + * 根据请假ID获取销假ID + * @param leaveId + */ +export const getCancelLeaveIdByLeaveId = (leaveId: string | number): AxiosPromise => { + return request({ + url: `/studentCancelLeave/studentCancelLeave/getCancelLeaveId/${leaveId}`, + method: 'get' + }); +}; + +/** + * 根据销假ID获取请假ID + * @param cancelLeaveId + */ +export const getLeaveIdByCancelLeaveId = (cancelLeaveId: string | number): AxiosPromise => { + return request({ + url: `/studentCancelLeave/studentCancelLeave/getLeaveId/${cancelLeaveId}`, + method: 'get' + }); +}; diff --git a/web/src/api/workflow/studentCancelLeave/studentCancelLeave/types.ts b/web/src/api/workflow/studentCancelLeave/studentCancelLeave/types.ts new file mode 100644 index 00000000..0177925b --- /dev/null +++ b/web/src/api/workflow/studentCancelLeave/studentCancelLeave/types.ts @@ -0,0 +1,521 @@ +export interface StudentCancelLeaveVO { + /** + * 主键ID(雪花ID) + */ + id: string | number; + + /** + * 删除标志(0代表存在 1代表删除) + */ + deleted: number; + + /** + * 学生ID + */ + studentId: string | number; + + /** + * 学生姓名 + */ + studentName: string; + + /** + * 学号 + */ + studentNo: string; + + /** + * 班级ID + */ + classId: string | number; + + /** + * 班级名称 + */ + className: string; + + /** + * 专业ID + */ + majorId: string | number; + + /** + * 专业名称 + */ + majorName: string; + + /** + * 学院ID + */ + collegeId: string | number; + + /** + * 学院名称 + */ + collegeName: string; + + /** + * 请假类型编码 + */ + leaveTypeCode: string; + + /** + * 请假类型名称 + */ + leaveTypeName: string; + + /** + * 开始时间(年月日时分秒) + */ + startTime: string; + + /** + * 结束时间(年月日时分秒) + */ + endTime: string; + + /** + * 请假时长(天) + */ + leaveDuration: number; + + /** + * 是否离校:0-否,1-是 + */ + isLeaveSchool: string; + + /** + * 是否需要销假:0-否,1-是 + */ + needCancel: string; + + /** + * 紧急联系人 + */ + emergencyContact: string; + + /** + * 紧急联系电话 + */ + emergencyPhone: string; + + /** + * 请假原因 + */ + leaveReason: string; + + /** + * 请假时地理位置 + */ + leaveLocation: string; + + /** + * 附件OSS文件ID(逗号分隔) + */ + attachmentOssIds: string | number; + + /** + * 审批状态:"cancel", "已撤销" "draft", "草稿" "waiting", "待审核" "finish", "已完成" "invalid", "已作废" "back", "已退回" "termination", "已终止" + */ + approvalStatus: string; + + /** + * 审批意见 + */ + approvalOpinion: string; + + /** + * 审批时间 + */ + approvalTime: string; + + /** + * 审批人ID + */ + approvalBy: number; + + /** + * 审批人姓名 + */ + approvalByName: string; + + /** + * 销假状态:0-未销假,1-已销假,2-逾期未销假 3 - 无需销假 "cancel", "已撤销" "draft", "草稿" "waiting", "待审核" "finish", "已完成" "invalid", "已作废" "back", "已退回" "termination", "已终止" + */ + cancelStatus: string; + + /** + * 销假时间 + */ + cancelTime: string; + + /** + * 销假地理位置 + */ + cancelLocation: string; + + /** + * 销假照片OSS文件ID(逗号分隔) + */ + cancelPhotoOssIds: string | number; + + /** + * 销假备注 + */ + cancelRemark: string; + + /** + * 学生请假表id + */ + leaveId: string | number; + +} + +export interface StudentCancelLeaveForm extends BaseEntity { + /** + * 主键ID(雪花ID) + */ + id?: string | number; + + /** + * 删除标志(0代表存在 1代表删除) + */ + deleted?: number; + + /** + * 学生ID + */ + studentId?: string | number; + + /** + * 学生姓名 + */ + studentName?: string; + + /** + * 学号 + */ + studentNo?: string; + + /** + * 班级ID + */ + classId?: string | number; + + /** + * 班级名称 + */ + className?: string; + + /** + * 专业ID + */ + majorId?: string | number; + + /** + * 专业名称 + */ + majorName?: string; + + /** + * 学院ID + */ + collegeId?: string | number; + + /** + * 学院名称 + */ + collegeName?: string; + + /** + * 请假类型编码 + */ + leaveTypeCode?: string; + + /** + * 请假类型名称 + */ + leaveTypeName?: string; + + /** + * 开始时间(年月日时分秒) + */ + startTime?: string; + + /** + * 结束时间(年月日时分秒) + */ + endTime?: string; + + /** + * 请假时长(天) + */ + leaveDuration?: number; + + /** + * 是否离校:0-否,1-是 + */ + isLeaveSchool?: string; + + /** + * 是否需要销假:0-否,1-是 + */ + needCancel?: string; + + /** + * 紧急联系人 + */ + emergencyContact?: string; + + /** + * 紧急联系电话 + */ + emergencyPhone?: string; + + /** + * 请假原因 + */ + leaveReason?: string; + + /** + * 请假时地理位置 + */ + leaveLocation?: string; + + /** + * 附件OSS文件ID(逗号分隔) + */ + attachmentOssIds?: string | number; + + /** + * 审批状态:"cancel", "已撤销" "draft", "草稿" "waiting", "待审核" "finish", "已完成" "invalid", "已作废" "back", "已退回" "termination", "已终止" + */ + approvalStatus?: string; + + /** + * 审批意见 + */ + approvalOpinion?: string; + + /** + * 审批时间 + */ + approvalTime?: string; + + /** + * 审批人ID + */ + approvalBy?: number; + + /** + * 审批人姓名 + */ + approvalByName?: string; + + /** + * 销假状态:0-未销假,1-已销假,2-逾期未销假 3 - 无需销假 "cancel", "已撤销" "draft", "草稿" "waiting", "待审核" "finish", "已完成" "invalid", "已作废" "back", "已退回" "termination", "已终止" + */ + cancelStatus?: string; + + /** + * 销假时间 + */ + cancelTime?: string; + + /** + * 销假地理位置 + */ + cancelLocation?: string; + + /** + * 销假照片OSS文件ID(逗号分隔) + */ + cancelPhotoOssIds?: string | number; + + /** + * 销假备注 + */ + cancelRemark?: string; + + /** + * 学生请假表id + */ + leaveId?: string | number; + +} + +export interface StudentCancelLeaveQuery extends PageQuery { + + /** + * 删除标志(0代表存在 1代表删除) + */ + deleted?: number; + + /** + * 学生ID + */ + studentId?: string | number; + + /** + * 学生姓名 + */ + studentName?: string; + + /** + * 学号 + */ + studentNo?: string; + + /** + * 班级ID + */ + classId?: string | number; + + /** + * 班级名称 + */ + className?: string; + + /** + * 专业ID + */ + majorId?: string | number; + + /** + * 专业名称 + */ + majorName?: string; + + /** + * 学院ID + */ + collegeId?: string | number; + + /** + * 学院名称 + */ + collegeName?: string; + + /** + * 请假类型编码 + */ + leaveTypeCode?: string; + + /** + * 请假类型名称 + */ + leaveTypeName?: string; + + /** + * 开始时间(年月日时分秒) + */ + startTime?: string; + + /** + * 结束时间(年月日时分秒) + */ + endTime?: string; + + /** + * 请假时长(天) + */ + leaveDuration?: number; + + /** + * 是否离校:0-否,1-是 + */ + isLeaveSchool?: string; + + /** + * 是否需要销假:0-否,1-是 + */ + needCancel?: string; + + /** + * 紧急联系人 + */ + emergencyContact?: string; + + /** + * 紧急联系电话 + */ + emergencyPhone?: string; + + /** + * 请假原因 + */ + leaveReason?: string; + + /** + * 请假时地理位置 + */ + leaveLocation?: string; + + /** + * 附件OSS文件ID(逗号分隔) + */ + attachmentOssIds?: string | number; + + /** + * 审批状态:"cancel", "已撤销" "draft", "草稿" "waiting", "待审核" "finish", "已完成" "invalid", "已作废" "back", "已退回" "termination", "已终止" + */ + approvalStatus?: string; + + /** + * 审批意见 + */ + approvalOpinion?: string; + + /** + * 审批时间 + */ + approvalTime?: string; + + /** + * 审批人ID + */ + approvalBy?: number; + + /** + * 审批人姓名 + */ + approvalByName?: string; + + /** + * 销假状态:0-未销假,1-已销假,2-逾期未销假 3 - 无需销假 "cancel", "已撤销" "draft", "草稿" "waiting", "待审核" "finish", "已完成" "invalid", "已作废" "back", "已退回" "termination", "已终止" + */ + cancelStatus?: string; + + /** + * 销假时间 + */ + cancelTime?: string; + + /** + * 销假地理位置 + */ + cancelLocation?: string; + + /** + * 销假照片OSS文件ID(逗号分隔) + */ + cancelPhotoOssIds?: string | number; + + /** + * 销假备注 + */ + cancelRemark?: string; + + /** + * 学生请假表id + */ + leaveId?: string | number; + + /** + * 日期范围参数 + */ + params?: any; +} + + + diff --git a/web/src/views/xg/xsjcxx/xsqj/index-bak.vue b/web/src/views/xg/xsjcxx/xsqj/bak/index-bak.vue similarity index 100% rename from web/src/views/xg/xsjcxx/xsqj/index-bak.vue rename to web/src/views/xg/xsjcxx/xsqj/bak/index-bak.vue diff --git a/web/src/views/xg/xsjcxx/xsqj/leaveEdit-bak.vue b/web/src/views/xg/xsjcxx/xsqj/bak/leaveEdit-bak.vue similarity index 100% rename from web/src/views/xg/xsjcxx/xsqj/leaveEdit-bak.vue rename to web/src/views/xg/xsjcxx/xsqj/bak/leaveEdit-bak.vue diff --git a/web/src/views/xg/xsjcxx/xsqj/leaveEdit.vue b/web/src/views/xg/xsjcxx/xsqj/bak/leaveEdit.vue similarity index 100% rename from web/src/views/xg/xsjcxx/xsqj/leaveEdit.vue rename to web/src/views/xg/xsjcxx/xsqj/bak/leaveEdit.vue diff --git a/web/src/views/xg/xsjcxx/xsqj/dialog.vue b/web/src/views/xg/xsjcxx/xsqj/dialog.vue index 3693904a..d31e01ef 100644 --- a/web/src/views/xg/xsjcxx/xsqj/dialog.vue +++ b/web/src/views/xg/xsjcxx/xsqj/dialog.vue @@ -386,31 +386,31 @@ const flowCodeOptions = [ { value: 'hzdyjs-qj', label: '学生请假流程-杭州第一技师' - }, - { - value: 'leave1', - label: '请假申请-普通' - }, - { - value: 'leave2', - label: '请假申请-排他网关' - }, - { - value: 'leave3', - label: '请假申请-并行网关' - }, - { - value: 'leave4', - label: '请假申请-会签' - }, - { - value: 'leave5', - label: '请假申请-并行会签网关' - }, - { - value: 'leave6', - label: '请假申请-排他并行会签' } + // { + // value: 'leave1', + // label: '请假申请-普通' + // }, + // { + // value: 'leave2', + // label: '请假申请-排他网关' + // }, + // { + // value: 'leave3', + // label: '请假申请-并行网关' + // }, + // { + // value: 'leave4', + // label: '请假申请-会签' + // }, + // { + // value: 'leave5', + // label: '请假申请-并行会签网关' + // }, + // { + // value: 'leave6', + // label: '请假申请-排他并行会签' + // } ]; // 上传相关配置 @@ -1418,7 +1418,8 @@ onMounted(() => { /* 附件上传容器样式 */ .attachment-upload-container { width: 100%; - max-height: 300px; + max-height: calc(100vh - 650px); + min-height: 200px; overflow-y: auto; padding-right: 8px; border: 1px solid #e4e7ed; @@ -1429,7 +1430,7 @@ onMounted(() => { /* 附件上传区域内容样式 */ .attachment-upload-container .upload-demo { padding: 12px; - min-height: 150px; + min-height: 180px; } .attachment-upload-container .upload-demo .el-upload { diff --git a/web/src/views/xg/xsjcxx/xsqj/index.vue b/web/src/views/xg/xsjcxx/xsqj/index.vue index 42053aba..f082e9b0 100644 --- a/web/src/views/xg/xsjcxx/xsqj/index.vue +++ b/web/src/views/xg/xsjcxx/xsqj/index.vue @@ -172,17 +172,17 @@ - + - - - - - - + + + + + + @@ -210,12 +210,17 @@ - + + + + - + @@ -282,7 +298,9 @@ interface PageData { const { proxy } = getCurrentInstance() as ComponentInternalInstance; // 加载字典数据 -const { sys_yesno, student_leave_approval_status } = toRefs(proxy?.useDict('sys_yesno', 'student_leave_approval_status')); +const { sys_yesno, student_leave_approval_status, xg_xsqj_cancel_status } = toRefs( + proxy?.useDict('sys_yesno', 'student_leave_approval_status', 'xg_xsqj_cancel_status') +); const studentLeaveList = ref([]); const buttonLoading = ref(false); @@ -500,6 +518,41 @@ const handleDelete = async (row?: StudentLeaveVO) => { await getList(); }; +/** 销假按钮操作 */ +const handleCancelLeave = async (row: StudentLeaveVO) => { + await proxy?.$modal.confirm('是否确认销假学生请假申请?').finally(() => (loading.value = false)); + + // TODO: 调用销假API + // await cancelStudentLeave(row.id); + // reset(); + const _id = row?.id || ids.value[0]; + + // 根据销假状态设置type参数 + // 当销假状态cancel_status = '0' 或者 '3'时,type = 'add',其他都是 'update' + const type = row.cancelStatus === '0' || row.cancelStatus === '3' ? 'add' : 'update'; + + // const res = await getStudentLeave(_id); + // Object.assign(form.value, res.data); + // // 传递type参数,标识为修改操作 + // form.value.type = 'update'; + // form.value.id = _id; + // dialog.visible = true; + // dialog.title = '修改学生请假'; + // proxy.$tab.closePage(proxy.$route); + console.log('type:', type); + + proxy.$router.push({ + path: `/xg/xsjcxx/xsqj/cancelLeaveEdit/index`, + query: { + id: _id, + type: type + } + }); + + // proxy?.$modal.msgSuccess('销假成功'); + // await getList(); +}; + /** 导出按钮操作 */ const handleExport = () => { proxy?.download( diff --git a/web/src/views/xg/xsjcxx/xsqj/xjdialog.vue b/web/src/views/xg/xsjcxx/xsqj/xjdialog.vue new file mode 100644 index 00000000..c909e904 --- /dev/null +++ b/web/src/views/xg/xsjcxx/xsqj/xjdialog.vue @@ -0,0 +1,1559 @@ + + + + +