wuzhen update
This commit is contained in:
1 parent
811fc00bcc
commit
a600627f4c
22 files changed
+3582
-3
No files matched your search
+1
@@ -236,3 +236,4 @@ public class ZsjyInternshipMonthlyController extends BaseController {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
package org.dromara.zsjy.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.dromara.zsjy.domain.bo.ZsjyInternshipMonthlyBatchReviewBo;
|
||||
import org.dromara.zsjy.domain.bo.ZsjyInternshipMonthlyReviewBo;
|
||||
import org.dromara.zsjy.domain.bo.ZsjyInternshipMonthlyReviewQueryBo;
|
||||
import org.dromara.zsjy.domain.vo.ZsjyInternshipMonthlyVo;
|
||||
import org.dromara.zsjy.service.IZsjyInternshipMonthlyReviewService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 学生月度实习总结审核Controller
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-01-27
|
||||
*/
|
||||
@Slf4j
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/zsjy/internship/monthly/review")
|
||||
@Tag(name = "学生月度实习总结审核", description = "班主任审核学生月度实习总结管理")
|
||||
public class ZsjyInternshipMonthlyReviewController extends BaseController {
|
||||
|
||||
private final IZsjyInternshipMonthlyReviewService reviewService;
|
||||
|
||||
/**
|
||||
* 查询待审核的学生月度实习总结列表
|
||||
*/
|
||||
@Operation(summary = "查询待审核的学生月度实习总结列表", description = "班主任查看待审核的月度总结列表")
|
||||
@SaCheckPermission("zsjy:internshipmonthly:review")
|
||||
@GetMapping("/pending")
|
||||
public TableDataInfo<ZsjyInternshipMonthlyVo> listPending(@Validated ZsjyInternshipMonthlyReviewQueryBo queryBo, PageQuery pageQuery) {
|
||||
log.info("=== 审核Controller层调试 ===");
|
||||
log.info("接口被调用: /zsjy/internship/monthly/review/pending");
|
||||
log.info("查询参数: {}", queryBo);
|
||||
log.info("分页参数: {}", pageQuery);
|
||||
|
||||
return reviewService.queryPendingPageList(queryBo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有审核记录列表 (包含已审核和待审核)
|
||||
*/
|
||||
@Operation(summary = "查询所有审核记录列表", description = "班主任查看所有审核记录")
|
||||
@SaCheckPermission("zsjy:internshipmonthly:review")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<ZsjyInternshipMonthlyVo> listAll(@Validated ZsjyInternshipMonthlyReviewQueryBo queryBo, PageQuery pageQuery) {
|
||||
log.info("=== 审核Controller层调试 ===");
|
||||
log.info("接口被调用: /zsjy/internship/monthly/review/list");
|
||||
log.info("查询参数: {}", queryBo);
|
||||
log.info("分页参数: {}", pageQuery);
|
||||
|
||||
return reviewService.queryReviewPageList(queryBo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询学生月度实习总结审核详情
|
||||
*/
|
||||
@Operation(summary = "查询学生月度实习总结审核详情", description = "根据ID查询月度总结审核详情")
|
||||
@SaCheckPermission("zsjy:internshipmonthly:review")
|
||||
@GetMapping("/{monthlyId}/detail")
|
||||
public R<ZsjyInternshipMonthlyVo> getReviewDetail(@Parameter(description = "月度总结ID")
|
||||
@PathVariable Long monthlyId) {
|
||||
log.info("查询月度总结审核详情, ID: {}", monthlyId);
|
||||
return R.ok(reviewService.queryReviewDetail(monthlyId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 单个审核学生月度实习总结
|
||||
*/
|
||||
@Operation(summary = "单个审核学生月度实习总结", description = "班主任对单个月度总结进行审核")
|
||||
@SaCheckPermission("zsjy:internshipmonthly:review")
|
||||
@Log(title = "学生月度实习总结审核", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/approve")
|
||||
public R<Void> approve(@Validated(AddGroup.class) @RequestBody ZsjyInternshipMonthlyReviewBo reviewBo) {
|
||||
log.info("审核月度总结: {}", reviewBo);
|
||||
|
||||
Boolean result = reviewService.approveMonthly(reviewBo);
|
||||
if (result) {
|
||||
return R.ok("审核成功");
|
||||
} else {
|
||||
return R.fail("审核失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量审核学生月度实习总结
|
||||
*/
|
||||
@Operation(summary = "批量审核学生月度实习总结", description = "班主任批量审核多个月度总结")
|
||||
@SaCheckPermission("zsjy:internshipmonthly:review")
|
||||
@Log(title = "学生月度实习总结批量审核", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/batch-approve")
|
||||
public R<Map<String, Object>> batchApprove(@Validated(AddGroup.class) @RequestBody ZsjyInternshipMonthlyBatchReviewBo batchReviewBo) {
|
||||
log.info("批量审核月度总结: {}", batchReviewBo);
|
||||
|
||||
Map<String, Object> result = reviewService.batchApproveMonthly(batchReviewBo);
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询审核统计信息
|
||||
*/
|
||||
@Operation(summary = "查询审核统计信息", description = "获取审核工作的统计数据")
|
||||
@SaCheckPermission("zsjy:internshipmonthly:review")
|
||||
@GetMapping("/statistics")
|
||||
public R<Map<String, Object>> getStatistics(@Validated ZsjyInternshipMonthlyReviewQueryBo queryBo) {
|
||||
log.info("查询审核统计信息: {}", queryBo);
|
||||
|
||||
Map<String, Object> statistics = reviewService.getReviewStatistics(queryBo);
|
||||
return R.ok(statistics);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询审核历史记录
|
||||
*/
|
||||
@Operation(summary = "查询审核历史记录", description = "查看已完成的审核记录")
|
||||
@SaCheckPermission("zsjy:internshipmonthly:review")
|
||||
@GetMapping("/history")
|
||||
public TableDataInfo<ZsjyInternshipMonthlyVo> getHistory(@Validated ZsjyInternshipMonthlyReviewQueryBo queryBo, PageQuery pageQuery) {
|
||||
log.info("查询审核历史记录: {}", queryBo);
|
||||
|
||||
return reviewService.queryHistoryPageList(queryBo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出审核记录
|
||||
*/
|
||||
@Operation(summary = "导出审核记录", description = "导出学生月度总结审核记录")
|
||||
@SaCheckPermission("zsjy:internshipmonthly:review")
|
||||
@Log(title = "学生月度实习总结审核记录", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(@RequestBody ZsjyInternshipMonthlyReviewQueryBo queryBo, HttpServletResponse response) {
|
||||
log.info("导出审核记录: {}", queryBo);
|
||||
|
||||
List<ZsjyInternshipMonthlyVo> list = reviewService.queryReviewList(queryBo);
|
||||
ExcelUtil.exportExcel(list, "学生月度实习总结审核记录", ZsjyInternshipMonthlyVo.class, response);
|
||||
}
|
||||
|
||||
}
|
||||
+6
@@ -158,6 +158,12 @@ public class ZsjyInternshipMonthly extends BaseEntity {
|
||||
@TableField("review_comment")
|
||||
private String reviewComment;
|
||||
|
||||
/**
|
||||
* 改进建议
|
||||
*/
|
||||
@TableField("review_suggestions")
|
||||
private String reviewSuggestions;
|
||||
|
||||
/**
|
||||
* 提交时间
|
||||
*/
|
||||
|
||||
+1
@@ -145,3 +145,4 @@ public class ZsjyInternshipMonthlyAddBo extends BaseEntity {
|
||||
private Date submitTime;
|
||||
|
||||
}
|
||||
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
package org.dromara.zsjy.domain.bo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 学生月度实习总结批量审核对象 ZsjyInternshipMonthlyBatchReviewBo
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-01-27
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "学生月度实习总结批量审核对象")
|
||||
public class ZsjyInternshipMonthlyBatchReviewBo {
|
||||
|
||||
/**
|
||||
* 批量审核项目列表
|
||||
*/
|
||||
@Schema(description = "批量审核项目列表")
|
||||
@NotEmpty(message = "批量审核列表不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@Valid
|
||||
private List<BatchReviewItem> reviewItems;
|
||||
|
||||
/**
|
||||
* 批量审核项目
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "批量审核项目")
|
||||
public static class BatchReviewItem {
|
||||
|
||||
/**
|
||||
* 月度总结ID
|
||||
*/
|
||||
@Schema(description = "月度总结ID")
|
||||
@NotNull(message = "月度总结ID不能为空")
|
||||
private Long monthlyId;
|
||||
|
||||
/**
|
||||
* 审核结果 (1通过/2拒绝)
|
||||
*/
|
||||
@Schema(description = "审核结果", allowableValues = {"1", "2"})
|
||||
@NotNull(message = "审核结果不能为空")
|
||||
@Min(value = 1, message = "审核结果值必须为1或2")
|
||||
@Max(value = 2, message = "审核结果值必须为1或2")
|
||||
private Integer reviewStatus;
|
||||
|
||||
/**
|
||||
* 评分(百分制)
|
||||
*/
|
||||
@Schema(description = "评分")
|
||||
@DecimalMin(value = "0", message = "评分不能小于0分")
|
||||
@DecimalMax(value = "100", message = "评分不能大于100分")
|
||||
@Digits(integer = 3, fraction = 1, message = "评分格式不正确")
|
||||
private BigDecimal reviewScore;
|
||||
|
||||
/**
|
||||
* 审核意见 (必填)
|
||||
*/
|
||||
@Schema(description = "审核意见")
|
||||
@NotBlank(message = "审核意见不能为空")
|
||||
@Size(max = 500, message = "审核意见不能超过500字")
|
||||
private String reviewComment;
|
||||
|
||||
/**
|
||||
* 改进建议 (选填)
|
||||
*/
|
||||
@Schema(description = "改进建议")
|
||||
@Size(max = 500, message = "改进建议不能超过500字")
|
||||
private String reviewSuggestions;
|
||||
}
|
||||
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package org.dromara.zsjy.domain.bo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
|
||||
import jakarta.validation.constraints.*;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 学生月度实习总结审核对象 ZsjyInternshipMonthlyReviewBo
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-01-27
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "学生月度实习总结审核对象")
|
||||
public class ZsjyInternshipMonthlyReviewBo {
|
||||
|
||||
/**
|
||||
* 月度总结ID
|
||||
*/
|
||||
@Schema(description = "月度总结ID")
|
||||
@NotNull(message = "月度总结ID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long monthlyId;
|
||||
|
||||
/**
|
||||
* 审核结果 (1通过/2拒绝)
|
||||
*/
|
||||
@Schema(description = "审核结果", allowableValues = {"1", "2"})
|
||||
@NotNull(message = "审核结果不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@Min(value = 1, message = "审核结果值必须为1或2", groups = { AddGroup.class, EditGroup.class })
|
||||
@Max(value = 2, message = "审核结果值必须为1或2", groups = { AddGroup.class, EditGroup.class })
|
||||
private Integer reviewStatus;
|
||||
|
||||
/**
|
||||
* 评分(百分制)
|
||||
*/
|
||||
@Schema(description = "评分")
|
||||
@DecimalMin(value = "0", message = "评分不能小于0分", groups = { AddGroup.class, EditGroup.class })
|
||||
@DecimalMax(value = "100", message = "评分不能大于100分", groups = { AddGroup.class, EditGroup.class })
|
||||
@Digits(integer = 3, fraction = 1, message = "评分格式不正确", groups = { AddGroup.class, EditGroup.class })
|
||||
private BigDecimal reviewScore;
|
||||
|
||||
/**
|
||||
* 审核意见 (必填)
|
||||
*/
|
||||
@Schema(description = "审核意见")
|
||||
@NotBlank(message = "审核意见不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@Size(max = 500, message = "审核意见不能超过500字", groups = { AddGroup.class, EditGroup.class })
|
||||
private String reviewComment;
|
||||
|
||||
/**
|
||||
* 改进建议 (选填)
|
||||
*/
|
||||
@Schema(description = "改进建议")
|
||||
@Size(max = 500, message = "改进建议不能超过500字", groups = { AddGroup.class, EditGroup.class })
|
||||
private String reviewSuggestions;
|
||||
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
package org.dromara.zsjy.domain.bo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
/**
|
||||
* 学生月度实习总结审核查询对象 ZsjyInternshipMonthlyReviewQueryBo
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-01-27
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "学生月度实习总结审核查询对象")
|
||||
public class ZsjyInternshipMonthlyReviewQueryBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
@Schema(description = "学生姓名")
|
||||
private String studentName;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
@Schema(description = "学号")
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 班级名称
|
||||
*/
|
||||
@Schema(description = "班级名称")
|
||||
private String className;
|
||||
|
||||
/**
|
||||
* 总结月份 (格式: 2025-01)
|
||||
*/
|
||||
@Schema(description = "总结月份")
|
||||
private String summaryMonth;
|
||||
|
||||
/**
|
||||
* 审核状态 (0待审核/1已审核通过/2审核拒绝)
|
||||
*/
|
||||
@Schema(description = "审核状态", allowableValues = {"0", "1", "2"})
|
||||
private Integer reviewStatus;
|
||||
|
||||
/**
|
||||
* 提交开始时间
|
||||
*/
|
||||
@Schema(description = "提交开始时间")
|
||||
private String submitTimeStart;
|
||||
|
||||
/**
|
||||
* 提交结束时间
|
||||
*/
|
||||
@Schema(description = "提交结束时间")
|
||||
private String submitTimeEnd;
|
||||
|
||||
/**
|
||||
* 实习单位名称
|
||||
*/
|
||||
@Schema(description = "实习单位名称")
|
||||
private String companyName;
|
||||
|
||||
/**
|
||||
* 学院名称
|
||||
*/
|
||||
@Schema(description = "学院名称")
|
||||
private String collegeName;
|
||||
|
||||
/**
|
||||
* 专业名称
|
||||
*/
|
||||
@Schema(description = "专业名称")
|
||||
private String majorName;
|
||||
|
||||
}
|
||||
+19
@@ -52,6 +52,18 @@ public class ZsjyInternshipMonthlyVo implements Serializable {
|
||||
@Schema(description = "学生学号")
|
||||
private String studentNumber;
|
||||
|
||||
/**
|
||||
* 班级名称 - 通过关联查询获取
|
||||
*/
|
||||
@Schema(description = "班级名称")
|
||||
private String className;
|
||||
|
||||
/**
|
||||
* 专业名称 - 通过关联查询获取
|
||||
*/
|
||||
@Schema(description = "专业名称")
|
||||
private String majorName;
|
||||
|
||||
/**
|
||||
* 总结月份 (格式: 2025-01)
|
||||
*/
|
||||
@@ -173,6 +185,12 @@ public class ZsjyInternshipMonthlyVo implements Serializable {
|
||||
@Schema(description = "审核意见")
|
||||
private String reviewComment;
|
||||
|
||||
/**
|
||||
* 改进建议
|
||||
*/
|
||||
@Schema(description = "改进建议")
|
||||
private String reviewSuggestions;
|
||||
|
||||
/**
|
||||
* 提交时间
|
||||
*/
|
||||
@@ -251,3 +269,4 @@ public class ZsjyInternshipMonthlyVo implements Serializable {
|
||||
private Date updateTime;
|
||||
|
||||
}
|
||||
|
||||
+54
@@ -5,9 +5,11 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.dromara.zsjy.domain.ZsjyInternshipMonthly;
|
||||
import org.dromara.zsjy.domain.bo.ZsjyInternshipMonthlyQueryBo;
|
||||
import org.dromara.zsjy.domain.bo.ZsjyInternshipMonthlyReviewQueryBo;
|
||||
import org.dromara.zsjy.domain.vo.ZsjyInternshipMonthlyVo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 学生月度实习总结Mapper接口
|
||||
@@ -79,4 +81,56 @@ public interface ZsjyInternshipMonthlyMapper extends BaseMapper<ZsjyInternshipMo
|
||||
*/
|
||||
List<Object> countByStatus(@Param("studentId") Long studentId);
|
||||
|
||||
/**
|
||||
* 查询审核分页列表
|
||||
*
|
||||
* @param page 分页参数
|
||||
* @param queryBo 查询条件
|
||||
* @param studentIds 学生ID列表
|
||||
* @return 审核分页结果
|
||||
*/
|
||||
Page<ZsjyInternshipMonthlyVo> selectReviewPage(Page<ZsjyInternshipMonthlyVo> page,
|
||||
@Param("bo") ZsjyInternshipMonthlyReviewQueryBo queryBo,
|
||||
@Param("studentIds") List<Long> studentIds);
|
||||
|
||||
/**
|
||||
* 查询审核列表
|
||||
*
|
||||
* @param queryBo 查询条件
|
||||
* @param studentIds 学生ID列表
|
||||
* @return 审核列表
|
||||
*/
|
||||
List<ZsjyInternshipMonthlyVo> selectReviewList(@Param("bo") ZsjyInternshipMonthlyReviewQueryBo queryBo,
|
||||
@Param("studentIds") List<Long> studentIds);
|
||||
|
||||
/**
|
||||
* 查询审核历史分页列表
|
||||
*
|
||||
* @param page 分页参数
|
||||
* @param queryBo 查询条件
|
||||
* @param studentIds 学生ID列表
|
||||
* @return 审核历史分页结果
|
||||
*/
|
||||
Page<ZsjyInternshipMonthlyVo> selectHistoryPage(Page<ZsjyInternshipMonthlyVo> page,
|
||||
@Param("bo") ZsjyInternshipMonthlyReviewQueryBo queryBo,
|
||||
@Param("studentIds") List<Long> studentIds);
|
||||
|
||||
/**
|
||||
* 查询审核统计信息
|
||||
*
|
||||
* @param queryBo 查询条件
|
||||
* @param studentIds 学生ID列表
|
||||
* @return 统计信息
|
||||
*/
|
||||
Map<String, Object> selectReviewStatistics(@Param("bo") ZsjyInternshipMonthlyReviewQueryBo queryBo,
|
||||
@Param("studentIds") List<Long> studentIds);
|
||||
|
||||
/**
|
||||
* 根据班主任ID查询管理的学生ID列表
|
||||
*
|
||||
* @param classTeacherId 班主任ID
|
||||
* @return 学生ID列表
|
||||
*/
|
||||
List<Long> selectStudentIdsByClassTeacher(@Param("classTeacherId") Long classTeacherId);
|
||||
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
package org.dromara.zsjy.service;
|
||||
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.zsjy.domain.bo.ZsjyInternshipMonthlyBatchReviewBo;
|
||||
import org.dromara.zsjy.domain.bo.ZsjyInternshipMonthlyReviewBo;
|
||||
import org.dromara.zsjy.domain.bo.ZsjyInternshipMonthlyReviewQueryBo;
|
||||
import org.dromara.zsjy.domain.vo.ZsjyInternshipMonthlyVo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 学生月度实习总结审核Service接口
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-01-27
|
||||
*/
|
||||
public interface IZsjyInternshipMonthlyReviewService {
|
||||
|
||||
/**
|
||||
* 查询待审核的学生月度实习总结分页列表
|
||||
*
|
||||
* @param queryBo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 待审核月度总结分页结果
|
||||
*/
|
||||
TableDataInfo<ZsjyInternshipMonthlyVo> queryPendingPageList(ZsjyInternshipMonthlyReviewQueryBo queryBo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询所有审核记录分页列表 (包含已审核和待审核)
|
||||
*
|
||||
* @param queryBo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 审核记录分页结果
|
||||
*/
|
||||
TableDataInfo<ZsjyInternshipMonthlyVo> queryReviewPageList(ZsjyInternshipMonthlyReviewQueryBo queryBo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询审核记录列表
|
||||
*
|
||||
* @param queryBo 查询条件
|
||||
* @return 审核记录集合
|
||||
*/
|
||||
List<ZsjyInternshipMonthlyVo> queryReviewList(ZsjyInternshipMonthlyReviewQueryBo queryBo);
|
||||
|
||||
/**
|
||||
* 查询学生月度实习总结审核详情
|
||||
*
|
||||
* @param monthlyId 月度总结ID
|
||||
* @return 月度总结审核详情
|
||||
*/
|
||||
ZsjyInternshipMonthlyVo queryReviewDetail(Long monthlyId);
|
||||
|
||||
/**
|
||||
* 单个审核学生月度实习总结
|
||||
*
|
||||
* @param reviewBo 审核参数
|
||||
* @return 审核结果
|
||||
*/
|
||||
Boolean approveMonthly(ZsjyInternshipMonthlyReviewBo reviewBo);
|
||||
|
||||
/**
|
||||
* 批量审核学生月度实习总结
|
||||
*
|
||||
* @param batchReviewBo 批量审核参数
|
||||
* @return 批量审核结果
|
||||
*/
|
||||
Map<String, Object> batchApproveMonthly(ZsjyInternshipMonthlyBatchReviewBo batchReviewBo);
|
||||
|
||||
/**
|
||||
* 获取审核统计信息
|
||||
*
|
||||
* @param queryBo 查询条件
|
||||
* @return 统计信息
|
||||
*/
|
||||
Map<String, Object> getReviewStatistics(ZsjyInternshipMonthlyReviewQueryBo queryBo);
|
||||
|
||||
/**
|
||||
* 查询审核历史记录分页列表
|
||||
*
|
||||
* @param queryBo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 审核历史分页结果
|
||||
*/
|
||||
TableDataInfo<ZsjyInternshipMonthlyVo> queryHistoryPageList(ZsjyInternshipMonthlyReviewQueryBo queryBo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 检查月度总结是否可以审核
|
||||
*
|
||||
* @param monthlyId 月度总结ID
|
||||
* @return 是否可以审核
|
||||
*/
|
||||
Boolean checkCanReview(Long monthlyId);
|
||||
|
||||
/**
|
||||
* 获取班主任管理的班级学生ID列表
|
||||
*
|
||||
* @return 学生ID集合
|
||||
*/
|
||||
List<Long> getClassTeacherStudentIds();
|
||||
|
||||
}
|
||||
+1
@@ -135,3 +135,4 @@ public interface IZsjyInternshipMonthlyService {
|
||||
Map<String, Object> getCurrentInternshipInfo();
|
||||
|
||||
}
|
||||
|
||||
+269
@@ -0,0 +1,269 @@
|
||||
package org.dromara.zsjy.service.impl;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
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.zsjy.domain.ZsjyInternshipMonthly;
|
||||
import org.dromara.zsjy.domain.bo.ZsjyInternshipMonthlyBatchReviewBo;
|
||||
import org.dromara.zsjy.domain.bo.ZsjyInternshipMonthlyReviewBo;
|
||||
import org.dromara.zsjy.domain.bo.ZsjyInternshipMonthlyReviewQueryBo;
|
||||
import org.dromara.zsjy.domain.vo.ZsjyInternshipMonthlyVo;
|
||||
import org.dromara.zsjy.mapper.ZsjyInternshipMonthlyMapper;
|
||||
import org.dromara.zsjy.service.IZsjyInternshipMonthlyReviewService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 学生月度实习总结审核Service业务层处理
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-01-27
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class ZsjyInternshipMonthlyReviewServiceImpl implements IZsjyInternshipMonthlyReviewService {
|
||||
|
||||
private final ZsjyInternshipMonthlyMapper baseMapper;
|
||||
|
||||
/**
|
||||
* 查询待审核的学生月度实习总结分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<ZsjyInternshipMonthlyVo> queryPendingPageList(ZsjyInternshipMonthlyReviewQueryBo queryBo, PageQuery pageQuery) {
|
||||
log.info("=== Service层调试 ===");
|
||||
log.info("查询待审核列表,参数: {}", queryBo);
|
||||
|
||||
// 设置查询条件:只查询待审核状态(0)
|
||||
queryBo.setReviewStatus(0);
|
||||
|
||||
// 获取班主任管理的学生ID列表
|
||||
List<Long> studentIds = getClassTeacherStudentIds();
|
||||
if (studentIds.isEmpty()) {
|
||||
log.warn("当前用户不是班主任或没有管理的学生");
|
||||
return TableDataInfo.build(new Page<>());
|
||||
}
|
||||
|
||||
Page<ZsjyInternshipMonthlyVo> result = baseMapper.selectReviewPage(pageQuery.build(), queryBo, studentIds);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有审核记录分页列表 (包含已审核和待审核)
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<ZsjyInternshipMonthlyVo> queryReviewPageList(ZsjyInternshipMonthlyReviewQueryBo queryBo, PageQuery pageQuery) {
|
||||
log.info("=== Service层调试 ===");
|
||||
log.info("查询所有审核记录,参数: {}", queryBo);
|
||||
|
||||
// 获取班主任管理的学生ID列表
|
||||
List<Long> studentIds = getClassTeacherStudentIds();
|
||||
if (studentIds.isEmpty()) {
|
||||
log.warn("当前用户不是班主任或没有管理的学生");
|
||||
return TableDataInfo.build(new Page<>());
|
||||
}
|
||||
|
||||
Page<ZsjyInternshipMonthlyVo> result = baseMapper.selectReviewPage(pageQuery.build(), queryBo, studentIds);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询审核记录列表
|
||||
*/
|
||||
@Override
|
||||
public List<ZsjyInternshipMonthlyVo> queryReviewList(ZsjyInternshipMonthlyReviewQueryBo queryBo) {
|
||||
// 获取班主任管理的学生ID列表
|
||||
List<Long> studentIds = getClassTeacherStudentIds();
|
||||
if (studentIds.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
return baseMapper.selectReviewList(queryBo, studentIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询学生月度实习总结审核详情
|
||||
*/
|
||||
@Override
|
||||
public ZsjyInternshipMonthlyVo queryReviewDetail(Long monthlyId) {
|
||||
ZsjyInternshipMonthlyVo vo = baseMapper.selectVoById(monthlyId);
|
||||
if (ObjectUtil.isNull(vo)) {
|
||||
throw new ServiceException("月度总结不存在");
|
||||
}
|
||||
|
||||
// 检查是否有权限查看
|
||||
List<Long> studentIds = getClassTeacherStudentIds();
|
||||
if (!studentIds.contains(vo.getStudentId())) {
|
||||
throw new ServiceException("无权查看该学生的总结");
|
||||
}
|
||||
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 单个审核学生月度实习总结
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean approveMonthly(ZsjyInternshipMonthlyReviewBo reviewBo) {
|
||||
log.info("=== 单个审核Service层调试 ===");
|
||||
log.info("审核参数: {}", reviewBo);
|
||||
|
||||
// 检查月度总结是否存在且可以审核
|
||||
if (!checkCanReview(reviewBo.getMonthlyId())) {
|
||||
throw new ServiceException("该月度总结不存在或不可审核");
|
||||
}
|
||||
|
||||
// 构建更新条件
|
||||
LambdaUpdateWrapper<ZsjyInternshipMonthly> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.eq(ZsjyInternshipMonthly::getId, reviewBo.getMonthlyId())
|
||||
.set(ZsjyInternshipMonthly::getReviewStatus, reviewBo.getReviewStatus())
|
||||
.set(ZsjyInternshipMonthly::getReviewScore, reviewBo.getReviewScore())
|
||||
.set(ZsjyInternshipMonthly::getReviewComment, reviewBo.getReviewComment())
|
||||
.set(ZsjyInternshipMonthly::getReviewSuggestions, reviewBo.getReviewSuggestions())
|
||||
.set(ZsjyInternshipMonthly::getReviewBy, LoginHelper.getUserId())
|
||||
.set(ZsjyInternshipMonthly::getReviewTime, new Date());
|
||||
|
||||
int result = baseMapper.update(null, updateWrapper);
|
||||
log.info("审核更新结果: {}", result);
|
||||
|
||||
return result > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量审核学生月度实习总结
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Map<String, Object> batchApproveMonthly(ZsjyInternshipMonthlyBatchReviewBo batchReviewBo) {
|
||||
log.info("=== 批量审核Service层调试 ===");
|
||||
log.info("批量审核参数: {}", batchReviewBo);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
int successCount = 0;
|
||||
int failCount = 0;
|
||||
List<String> errorMessages = new ArrayList<>();
|
||||
|
||||
for (ZsjyInternshipMonthlyBatchReviewBo.BatchReviewItem item : batchReviewBo.getReviewItems()) {
|
||||
try {
|
||||
// 检查是否可以审核
|
||||
if (!checkCanReview(item.getMonthlyId())) {
|
||||
failCount++;
|
||||
errorMessages.add("ID:" + item.getMonthlyId() + " 不存在或不可审核");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 构建更新条件
|
||||
LambdaUpdateWrapper<ZsjyInternshipMonthly> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.eq(ZsjyInternshipMonthly::getId, item.getMonthlyId())
|
||||
.set(ZsjyInternshipMonthly::getReviewStatus, item.getReviewStatus())
|
||||
.set(ZsjyInternshipMonthly::getReviewScore, item.getReviewScore())
|
||||
.set(ZsjyInternshipMonthly::getReviewComment, item.getReviewComment())
|
||||
.set(ZsjyInternshipMonthly::getReviewSuggestions, item.getReviewSuggestions())
|
||||
.set(ZsjyInternshipMonthly::getReviewBy, LoginHelper.getUserId())
|
||||
.set(ZsjyInternshipMonthly::getReviewTime, new Date());
|
||||
|
||||
int updateResult = baseMapper.update(null, updateWrapper);
|
||||
if (updateResult > 0) {
|
||||
successCount++;
|
||||
} else {
|
||||
failCount++;
|
||||
errorMessages.add("ID:" + item.getMonthlyId() + " 更新失败");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
failCount++;
|
||||
errorMessages.add("ID:" + item.getMonthlyId() + " 审核异常: " + e.getMessage());
|
||||
log.error("批量审核异常,月度总结ID: {}", item.getMonthlyId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
result.put("successCount", successCount);
|
||||
result.put("failCount", failCount);
|
||||
result.put("total", batchReviewBo.getReviewItems().size());
|
||||
result.put("errorMessages", errorMessages);
|
||||
|
||||
log.info("批量审核结果: {}", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取审核统计信息
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> getReviewStatistics(ZsjyInternshipMonthlyReviewQueryBo queryBo) {
|
||||
// 获取班主任管理的学生ID列表
|
||||
List<Long> studentIds = getClassTeacherStudentIds();
|
||||
if (studentIds.isEmpty()) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
return baseMapper.selectReviewStatistics(queryBo, studentIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询审核历史记录分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<ZsjyInternshipMonthlyVo> queryHistoryPageList(ZsjyInternshipMonthlyReviewQueryBo queryBo, PageQuery pageQuery) {
|
||||
// 设置查询条件:只查询已审核状态(1已通过/2已拒绝)
|
||||
if (ObjectUtil.isNull(queryBo.getReviewStatus())) {
|
||||
// 如果没有指定状态,则查询所有已审核的记录
|
||||
// 这里可以通过修改Mapper查询条件来实现,暂时不设置具体状态
|
||||
}
|
||||
|
||||
// 获取班主任管理的学生ID列表
|
||||
List<Long> studentIds = getClassTeacherStudentIds();
|
||||
if (studentIds.isEmpty()) {
|
||||
return TableDataInfo.build(new Page<>());
|
||||
}
|
||||
|
||||
Page<ZsjyInternshipMonthlyVo> result = baseMapper.selectHistoryPage(pageQuery.build(), queryBo, studentIds);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查月度总结是否可以审核
|
||||
*/
|
||||
@Override
|
||||
public Boolean checkCanReview(Long monthlyId) {
|
||||
ZsjyInternshipMonthlyVo vo = baseMapper.selectVoById(monthlyId);
|
||||
if (ObjectUtil.isNull(vo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否有权限审核(是否是班主任管理的学生)
|
||||
List<Long> studentIds = getClassTeacherStudentIds();
|
||||
if (!studentIds.contains(vo.getStudentId())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查状态是否为待审核(0)
|
||||
return Integer.valueOf(0).equals(vo.getReviewStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取班主任管理的班级学生ID列表
|
||||
* TODO: 这里需要根据实际的班主任-学生关系表来实现
|
||||
* 暂时返回空列表,需要补充具体的业务逻辑
|
||||
*/
|
||||
@Override
|
||||
public List<Long> getClassTeacherStudentIds() {
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
log.info("当前登录用户ID: {}", currentUserId);
|
||||
|
||||
// TODO: 这里需要查询班主任管理的学生ID列表
|
||||
// 可能需要关联班级表、学生表等
|
||||
// 暂时返回示例数据,实际需要根据业务补充
|
||||
return baseMapper.selectStudentIdsByClassTeacher(currentUserId);
|
||||
}
|
||||
|
||||
}
|
||||
+156
-3
@@ -26,7 +26,8 @@
|
||||
<result property="reviewBy" column="review_by" />
|
||||
<result property="reviewTime" column="review_time" />
|
||||
<result property="reviewScore" column="review_score" />
|
||||
<result property="reviewComments" column="review_comment" />
|
||||
<result property="reviewComment" column="review_comment" />
|
||||
<result property="reviewSuggestions" column="review_suggestions" />
|
||||
<result property="submitTime" column="submit_time" />
|
||||
<result property="wordCount" column="word_count" />
|
||||
<result property="isOverdue" column="is_overdue" />
|
||||
@@ -45,6 +46,8 @@
|
||||
<result property="studentId" column="student_id" />
|
||||
<result property="studentName" column="student_name" />
|
||||
<result property="studentNumber" column="student_number" />
|
||||
<result property="className" column="class_name" />
|
||||
<result property="majorName" column="major_name" />
|
||||
<result property="summaryMonth" column="summary_month" />
|
||||
<result property="monthNumber" column="month_number" />
|
||||
<result property="workContent" column="work_content" />
|
||||
@@ -64,7 +67,8 @@
|
||||
<result property="reviewerName" column="reviewer_name" />
|
||||
<result property="reviewTime" column="review_time" />
|
||||
<result property="reviewScore" column="review_score" />
|
||||
<result property="reviewComments" column="review_comment" />
|
||||
<result property="reviewComment" column="review_comment" />
|
||||
<result property="reviewSuggestions" column="review_suggestions" />
|
||||
<result property="submitTime" column="submit_time" />
|
||||
<result property="wordCount" column="word_count" />
|
||||
<result property="isOverdue" column="is_overdue" />
|
||||
@@ -86,6 +90,8 @@
|
||||
m.student_id,
|
||||
u.nick_name as student_name,
|
||||
ui.student_no as student_number,
|
||||
xsm.class_name,
|
||||
xsm.major_name,
|
||||
m.summary_month,
|
||||
m.month_number,
|
||||
m.work_content,
|
||||
@@ -111,7 +117,8 @@
|
||||
r.nick_name as reviewer_name,
|
||||
m.review_time,
|
||||
m.review_score,
|
||||
m.review_comment as review_comments,
|
||||
m.review_comment,
|
||||
m.review_suggestions,
|
||||
m.submit_time,
|
||||
m.word_count,
|
||||
m.is_overdue,
|
||||
@@ -128,6 +135,7 @@
|
||||
LEFT JOIN sys_user u ON u.user_id = m.student_id
|
||||
LEFT JOIN zsjy_internship_info ui ON ui.internship_id = m.internship_id AND ui.student_id = m.student_id
|
||||
LEFT JOIN sys_user r ON r.user_id = m.review_by
|
||||
LEFT JOIN xg_student_msg xsm ON xsm.student_no = ui.student_no
|
||||
WHERE m.deleted = 0
|
||||
</sql>
|
||||
|
||||
@@ -237,4 +245,149 @@
|
||||
ORDER BY review_status
|
||||
</select>
|
||||
|
||||
<!-- 查询审核分页列表 -->
|
||||
<select id="selectReviewPage" resultMap="ZsjyInternshipMonthlyVoResult">
|
||||
<include refid="selectZsjyInternshipMonthlyVo"/>
|
||||
AND m.review_status != 3 <!-- 过滤掉草稿状态,只显示已提交的记录 -->
|
||||
<if test="studentIds != null and studentIds.size() > 0">
|
||||
AND m.student_id IN
|
||||
<foreach collection="studentIds" item="studentId" open="(" close=")" separator=",">
|
||||
#{studentId}
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="bo.studentName != null and bo.studentName != ''">
|
||||
AND u.nick_name LIKE CONCAT('%', #{bo.studentName}, '%')
|
||||
</if>
|
||||
<if test="bo.studentNo != null and bo.studentNo != ''">
|
||||
AND ui.student_no LIKE CONCAT('%', #{bo.studentNo}, '%')
|
||||
</if>
|
||||
<if test="bo.summaryMonth != null and bo.summaryMonth != ''">
|
||||
AND m.summary_month = #{bo.summaryMonth}
|
||||
</if>
|
||||
<if test="bo.reviewStatus != null">
|
||||
AND m.review_status = #{bo.reviewStatus}
|
||||
</if>
|
||||
<if test="bo.submitTimeStart != null and bo.submitTimeStart != ''">
|
||||
AND m.submit_time >= #{bo.submitTimeStart}
|
||||
</if>
|
||||
<if test="bo.submitTimeEnd != null and bo.submitTimeEnd != ''">
|
||||
AND m.submit_time <= #{bo.submitTimeEnd}
|
||||
</if>
|
||||
ORDER BY m.review_status ASC, m.submit_time DESC, m.create_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 查询审核列表 -->
|
||||
<select id="selectReviewList" resultMap="ZsjyInternshipMonthlyVoResult">
|
||||
<include refid="selectZsjyInternshipMonthlyVo"/>
|
||||
AND m.review_status != 3 <!-- 过滤掉草稿状态,只显示已提交的记录 -->
|
||||
<if test="studentIds != null and studentIds.size() > 0">
|
||||
AND m.student_id IN
|
||||
<foreach collection="studentIds" item="studentId" open="(" close=")" separator=",">
|
||||
#{studentId}
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="bo.studentName != null and bo.studentName != ''">
|
||||
AND u.nick_name LIKE CONCAT('%', #{bo.studentName}, '%')
|
||||
</if>
|
||||
<if test="bo.studentNo != null and bo.studentNo != ''">
|
||||
AND ui.student_no LIKE CONCAT('%', #{bo.studentNo}, '%')
|
||||
</if>
|
||||
<if test="bo.summaryMonth != null and bo.summaryMonth != ''">
|
||||
AND m.summary_month = #{bo.summaryMonth}
|
||||
</if>
|
||||
<if test="bo.reviewStatus != null">
|
||||
AND m.review_status = #{bo.reviewStatus}
|
||||
</if>
|
||||
<if test="bo.submitTimeStart != null and bo.submitTimeStart != ''">
|
||||
AND m.submit_time >= #{bo.submitTimeStart}
|
||||
</if>
|
||||
<if test="bo.submitTimeEnd != null and bo.submitTimeEnd != ''">
|
||||
AND m.submit_time <= #{bo.submitTimeEnd}
|
||||
</if>
|
||||
ORDER BY m.review_status ASC, m.submit_time DESC, m.create_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 查询审核历史分页列表 -->
|
||||
<select id="selectHistoryPage" resultMap="ZsjyInternshipMonthlyVoResult">
|
||||
<include refid="selectZsjyInternshipMonthlyVo"/>
|
||||
AND m.review_status IN (1, 2)
|
||||
<if test="studentIds != null and studentIds.size() > 0">
|
||||
AND m.student_id IN
|
||||
<foreach collection="studentIds" item="studentId" open="(" close=")" separator=",">
|
||||
#{studentId}
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="bo.studentName != null and bo.studentName != ''">
|
||||
AND u.nick_name LIKE CONCAT('%', #{bo.studentName}, '%')
|
||||
</if>
|
||||
<if test="bo.studentNo != null and bo.studentNo != ''">
|
||||
AND ui.student_no LIKE CONCAT('%', #{bo.studentNo}, '%')
|
||||
</if>
|
||||
<if test="bo.summaryMonth != null and bo.summaryMonth != ''">
|
||||
AND m.summary_month = #{bo.summaryMonth}
|
||||
</if>
|
||||
<if test="bo.reviewStatus != null">
|
||||
AND m.review_status = #{bo.reviewStatus}
|
||||
</if>
|
||||
<if test="bo.submitTimeStart != null and bo.submitTimeStart != ''">
|
||||
AND m.submit_time >= #{bo.submitTimeStart}
|
||||
</if>
|
||||
<if test="bo.submitTimeEnd != null and bo.submitTimeEnd != ''">
|
||||
AND m.submit_time <= #{bo.submitTimeEnd}
|
||||
</if>
|
||||
ORDER BY m.review_time DESC, m.submit_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 查询审核统计信息 -->
|
||||
<select id="selectReviewStatistics" resultType="map">
|
||||
SELECT
|
||||
COUNT(*) as totalCount,
|
||||
COUNT(CASE WHEN m.review_status = 0 THEN 1 END) as pendingCount,
|
||||
COUNT(CASE WHEN m.review_status = 1 THEN 1 END) as approvedCount,
|
||||
COUNT(CASE WHEN m.review_status = 2 THEN 1 END) as rejectedCount,
|
||||
ROUND(AVG(CASE WHEN m.review_score IS NOT NULL THEN m.review_score END), 2) as averageScore,
|
||||
ROUND(COUNT(CASE WHEN m.review_status IN (1, 2) THEN 1 END) * 100.0 / COUNT(*), 2) as completionRate
|
||||
FROM zsjy_internship_monthly m
|
||||
LEFT JOIN sys_user u ON u.user_id = m.student_id
|
||||
LEFT JOIN zsjy_internship_info ui ON ui.internship_id = m.internship_id AND ui.student_id = m.student_id
|
||||
WHERE m.deleted = 0
|
||||
<if test="studentIds != null and studentIds.size() > 0">
|
||||
AND m.student_id IN
|
||||
<foreach collection="studentIds" item="studentId" open="(" close=")" separator=",">
|
||||
#{studentId}
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="bo.studentName != null and bo.studentName != ''">
|
||||
AND u.nick_name LIKE CONCAT('%', #{bo.studentName}, '%')
|
||||
</if>
|
||||
<if test="bo.studentNo != null and bo.studentNo != ''">
|
||||
AND ui.student_no LIKE CONCAT('%', #{bo.studentNo}, '%')
|
||||
</if>
|
||||
<if test="bo.summaryMonth != null and bo.summaryMonth != ''">
|
||||
AND m.summary_month = #{bo.summaryMonth}
|
||||
</if>
|
||||
<if test="bo.reviewStatus != null">
|
||||
AND m.review_status = #{bo.reviewStatus}
|
||||
</if>
|
||||
<if test="bo.submitTimeStart != null and bo.submitTimeStart != ''">
|
||||
AND m.submit_time >= #{bo.submitTimeStart}
|
||||
</if>
|
||||
<if test="bo.submitTimeEnd != null and bo.submitTimeEnd != ''">
|
||||
AND m.submit_time <= #{bo.submitTimeEnd}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<!-- 根据班主任ID查询管理的学生ID列表 -->
|
||||
<select id="selectStudentIdsByClassTeacher" resultType="Long">
|
||||
SELECT DISTINCT s.id
|
||||
FROM xg_student_msg s
|
||||
INNER JOIN xg_class_msg c ON s.class_id = c.id
|
||||
WHERE s.deleted = 0
|
||||
AND s.student_status = '1'
|
||||
AND c.deleted = 0
|
||||
AND c.class_teacher_id = #{classTeacherId}
|
||||
AND s.tenant_id = '000000'
|
||||
AND c.tenant_id = '000000'
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -100,3 +100,4 @@ export function getCurrentInternshipInfo() {
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
import request from '@/utils/request';
|
||||
|
||||
// 审核查询参数接口
|
||||
export interface MonthlyReviewQueryParams {
|
||||
summaryMonth?: string;
|
||||
studentName?: string;
|
||||
reviewStatus?: number;
|
||||
studentNumber?: string;
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
}
|
||||
|
||||
// 单个审核参数接口
|
||||
export interface MonthlyReviewParams {
|
||||
monthlyId: number;
|
||||
reviewStatus: number; // 1:通过 2:拒绝
|
||||
reviewScore?: number; // 0-100分
|
||||
reviewComment: string;
|
||||
reviewSuggestions?: string;
|
||||
}
|
||||
|
||||
// 批量审核项目接口
|
||||
export interface BatchReviewItem {
|
||||
monthlyId: number;
|
||||
reviewStatus: number;
|
||||
reviewScore?: number;
|
||||
reviewComment: string;
|
||||
reviewSuggestions?: string;
|
||||
}
|
||||
|
||||
// 批量审核参数接口
|
||||
export interface BatchReviewParams {
|
||||
reviewItems: BatchReviewItem[];
|
||||
}
|
||||
|
||||
// 审核统计信息接口
|
||||
export interface ReviewStatistics {
|
||||
totalCount: number;
|
||||
pendingCount: number;
|
||||
approvedCount: number;
|
||||
rejectedCount: number;
|
||||
averageScore: number;
|
||||
completionRate: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询待审核的月度总结列表
|
||||
*/
|
||||
export function getPendingReviewList(params: MonthlyReviewQueryParams) {
|
||||
return request({
|
||||
url: '/zsjy/internship/monthly/review/pending',
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有审核记录列表
|
||||
*/
|
||||
export function getReviewList(params: MonthlyReviewQueryParams) {
|
||||
return request({
|
||||
url: '/zsjy/internship/monthly/review/list',
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询审核详情
|
||||
*/
|
||||
export function getReviewDetail(monthlyId: number) {
|
||||
return request({
|
||||
url: `/zsjy/internship/monthly/review/${monthlyId}`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 单个审核月度总结
|
||||
*/
|
||||
export function approveMonthly(data: MonthlyReviewParams) {
|
||||
return request({
|
||||
url: '/zsjy/internship/monthly/review/approve',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 单个审核月度总结 (别名)
|
||||
*/
|
||||
export function reviewInternshipMonthly(data: MonthlyReviewParams) {
|
||||
return request({
|
||||
url: '/zsjy/internship/monthly/review/approve',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量审核月度总结
|
||||
*/
|
||||
export function batchApproveMonthly(data: BatchReviewParams) {
|
||||
return request({
|
||||
url: '/zsjy/internship/monthly/review/batch',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量审核月度总结 (别名)
|
||||
*/
|
||||
export function batchReviewInternshipMonthly(data: BatchReviewParams) {
|
||||
return request({
|
||||
url: '/zsjy/internship/monthly/review/batch',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取审核统计信息
|
||||
*/
|
||||
export function getReviewStatistics(params?: MonthlyReviewQueryParams) {
|
||||
return request({
|
||||
url: '/zsjy/internship/monthly/review/statistics',
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询审核历史记录
|
||||
*/
|
||||
export function getReviewHistory(params: MonthlyReviewQueryParams) {
|
||||
return request({
|
||||
url: '/zsjy/internship/monthly/review/history',
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出审核记录
|
||||
*/
|
||||
export function exportReviewData(params: MonthlyReviewQueryParams) {
|
||||
return request({
|
||||
url: '/zsjy/internship/monthly/review/export',
|
||||
method: 'post',
|
||||
data: params,
|
||||
responseType: 'blob'
|
||||
});
|
||||
}
|
||||
@@ -1551,3 +1551,198 @@ export interface InternshipVisitEditBO extends InternshipVisitAddBO {
|
||||
*/
|
||||
visitId?: string | number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 实习月度总结 VO
|
||||
*/
|
||||
export interface InternshipMonthlyVO {
|
||||
/**
|
||||
* 月度总结ID
|
||||
*/
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 学生ID
|
||||
*/
|
||||
studentId?: string | number;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
studentName?: string;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
studentNumber?: string;
|
||||
|
||||
/**
|
||||
* 班级名称
|
||||
*/
|
||||
className?: string;
|
||||
|
||||
/**
|
||||
* 专业名称
|
||||
*/
|
||||
majorName?: string;
|
||||
|
||||
/**
|
||||
* 学院名称
|
||||
*/
|
||||
collegeName?: string;
|
||||
|
||||
/**
|
||||
* 总结月份
|
||||
*/
|
||||
summaryMonth?: string;
|
||||
|
||||
/**
|
||||
* 工作内容
|
||||
*/
|
||||
workContent?: string;
|
||||
|
||||
/**
|
||||
* 学习收获
|
||||
*/
|
||||
learningGains?: string;
|
||||
|
||||
/**
|
||||
* 问题与困难
|
||||
*/
|
||||
problemsEncountered?: string;
|
||||
|
||||
/**
|
||||
* 改进计划
|
||||
*/
|
||||
improvementPlan?: string;
|
||||
|
||||
/**
|
||||
* 下月计划
|
||||
*/
|
||||
nextMonthPlan?: string;
|
||||
|
||||
/**
|
||||
* 专业技能评分 (1-10分)
|
||||
*/
|
||||
professionalSkills?: number;
|
||||
|
||||
/**
|
||||
* 沟通能力评分 (1-10分)
|
||||
*/
|
||||
communicationSkills?: number;
|
||||
|
||||
/**
|
||||
* 团队协作评分 (1-10分)
|
||||
*/
|
||||
teamworkAbility?: number;
|
||||
|
||||
/**
|
||||
* 学习能力评分 (1-10分)
|
||||
*/
|
||||
learningAbility?: number;
|
||||
|
||||
/**
|
||||
* 工作态度评分 (1-10分)
|
||||
*/
|
||||
workAttitude?: number;
|
||||
|
||||
/**
|
||||
* 字数统计
|
||||
*/
|
||||
wordCount?: number;
|
||||
|
||||
/**
|
||||
* 审核状态 (0-待审核 1-已通过 2-已拒绝 3-草稿)
|
||||
*/
|
||||
reviewStatus?: number;
|
||||
|
||||
/**
|
||||
* 审核人ID
|
||||
*/
|
||||
reviewerId?: string | number;
|
||||
|
||||
/**
|
||||
* 审核人姓名
|
||||
*/
|
||||
reviewerName?: string;
|
||||
|
||||
/**
|
||||
* 审核评分 (0-100分)
|
||||
*/
|
||||
reviewScore?: number;
|
||||
|
||||
/**
|
||||
* 审核意见
|
||||
*/
|
||||
reviewComment?: string;
|
||||
|
||||
/**
|
||||
* 改进建议
|
||||
*/
|
||||
reviewSuggestions?: string;
|
||||
|
||||
/**
|
||||
* 审核时间
|
||||
*/
|
||||
reviewTime?: string;
|
||||
|
||||
/**
|
||||
* 是否逾期
|
||||
*/
|
||||
isOverdue?: boolean;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
createTime?: string;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
createBy?: number;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
updateTime?: string;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
updateBy?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 实习月度总结审核统计 VO
|
||||
*/
|
||||
export interface InternshipMonthlyReviewStatisticsVO {
|
||||
/**
|
||||
* 总记录数
|
||||
*/
|
||||
totalCount?: number;
|
||||
|
||||
/**
|
||||
* 待审核数量
|
||||
*/
|
||||
pendingCount?: number;
|
||||
|
||||
/**
|
||||
* 已通过数量
|
||||
*/
|
||||
approvedCount?: number;
|
||||
|
||||
/**
|
||||
* 已拒绝数量
|
||||
*/
|
||||
rejectedCount?: number;
|
||||
|
||||
/**
|
||||
* 平均评分
|
||||
*/
|
||||
averageScore?: number;
|
||||
|
||||
/**
|
||||
* 完成率(百分比)
|
||||
*/
|
||||
completionRate?: number;
|
||||
}
|
||||
@@ -316,3 +316,4 @@ defineExpose({
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,546 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- 搜索区域 -->
|
||||
<el-card class="search-card" shadow="never">
|
||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="80px">
|
||||
<el-form-item label="总结月份" prop="summaryMonth">
|
||||
<el-date-picker
|
||||
v-model="queryParams.summaryMonth"
|
||||
type="month"
|
||||
value-format="YYYY-MM"
|
||||
placeholder="选择月份"
|
||||
clearable
|
||||
style="width: 150px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="学生姓名" prop="studentName">
|
||||
<el-input
|
||||
v-model="queryParams.studentName"
|
||||
placeholder="请输入学生姓名"
|
||||
clearable
|
||||
style="width: 150px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="学号" prop="studentNumber">
|
||||
<el-input
|
||||
v-model="queryParams.studentNumber"
|
||||
placeholder="请输入学号"
|
||||
clearable
|
||||
style="width: 150px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="审核状态" prop="reviewStatus">
|
||||
<el-select v-model="queryParams.reviewStatus" placeholder="请选择状态" clearable style="width: 150px">
|
||||
<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>
|
||||
|
||||
<!-- 统计卡片 -->
|
||||
<el-row :gutter="20" class="mb-4">
|
||||
<el-col :span="6">
|
||||
<el-card shadow="hover" class="stat-card">
|
||||
<div class="stat-item">
|
||||
<div class="stat-value text-primary">{{ statistics.totalCount || 0 }}</div>
|
||||
<div class="stat-label">总数</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-card shadow="hover" class="stat-card">
|
||||
<div class="stat-item">
|
||||
<div class="stat-value text-warning">{{ statistics.pendingCount || 0 }}</div>
|
||||
<div class="stat-label">待审核</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-card shadow="hover" class="stat-card">
|
||||
<div class="stat-item">
|
||||
<div class="stat-value text-success">{{ statistics.approvedCount || 0 }}</div>
|
||||
<div class="stat-label">已通过</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-card shadow="hover" class="stat-card">
|
||||
<div class="stat-item">
|
||||
<div class="stat-value text-danger">{{ statistics.rejectedCount || 0 }}</div>
|
||||
<div class="stat-label">已拒绝</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 操作栏 -->
|
||||
<el-card shadow="never">
|
||||
<div class="table-header">
|
||||
<div class="table-title">月度总结审核</div>
|
||||
<div class="table-actions">
|
||||
<el-button
|
||||
type="success"
|
||||
icon="Check"
|
||||
:disabled="!selections.length"
|
||||
@click="handleBatchApprove"
|
||||
>
|
||||
批量通过
|
||||
</el-button>
|
||||
<el-button
|
||||
type="warning"
|
||||
icon="Close"
|
||||
:disabled="!selections.length"
|
||||
@click="handleBatchReject"
|
||||
>
|
||||
批量拒绝
|
||||
</el-button>
|
||||
<el-button type="info" icon="Download" @click="handleExport">导出</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="reviewList"
|
||||
@selection-change="handleSelectionChange"
|
||||
border
|
||||
stripe
|
||||
>
|
||||
<el-table-column type="selection" width="50" align="center" />
|
||||
<el-table-column label="学生信息" width="200" fixed="left">
|
||||
<template #default="scope">
|
||||
<div>
|
||||
<div class="font-bold">{{ scope.row.studentName }}</div>
|
||||
<div class="text-sm text-gray-500">{{ scope.row.studentNumber }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="summaryMonth" label="总结月份" width="120" align="center" />
|
||||
<el-table-column prop="monthNumber" label="第几个月" width="100" align="center" />
|
||||
<el-table-column label="状态" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag
|
||||
:type="getStatusType(scope.row.reviewStatus)"
|
||||
size="small"
|
||||
>
|
||||
{{ getStatusText(scope.row.reviewStatus) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="reviewScore" label="评分" width="80" align="center">
|
||||
<template #default="scope">
|
||||
{{ scope.row.reviewScore || '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="submitTime" label="提交时间" width="160" align="center" />
|
||||
<el-table-column prop="reviewTime" label="审核时间" width="160" align="center">
|
||||
<template #default="scope">
|
||||
{{ scope.row.reviewTime || '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="200" align="center" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" link size="small" @click="handleDetail(scope.row)">
|
||||
查看详情
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="scope.row.reviewStatus === 0"
|
||||
type="success"
|
||||
link
|
||||
size="small"
|
||||
@click="handleApprove(scope.row)"
|
||||
>
|
||||
审核
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="scope.row.reviewStatus !== 0"
|
||||
type="warning"
|
||||
link
|
||||
size="small"
|
||||
@click="handleReReview(scope.row)"
|
||||
>
|
||||
重新审核
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<!-- 审核对话框 -->
|
||||
<el-dialog
|
||||
:title="reviewForm.monthlyId ? '审核月度总结' : '批量审核'"
|
||||
v-model="reviewVisible"
|
||||
width="600px"
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<el-form :model="reviewForm" :rules="reviewRules" ref="reviewFormRef" label-width="100px">
|
||||
<el-form-item label="审核结果" prop="reviewStatus">
|
||||
<el-radio-group v-model="reviewForm.reviewStatus">
|
||||
<el-radio :label="1">
|
||||
<el-icon><Check /></el-icon>
|
||||
通过
|
||||
</el-radio>
|
||||
<el-radio :label="2">
|
||||
<el-icon><Close /></el-icon>
|
||||
拒绝
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="评分" prop="reviewScore">
|
||||
<el-input-number
|
||||
v-model="reviewForm.reviewScore"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:precision="1"
|
||||
placeholder="请输入评分(0-100)"
|
||||
style="width: 200px"
|
||||
/>
|
||||
<span class="ml-2 text-gray-500">分</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="审核意见" prop="reviewComment">
|
||||
<el-input
|
||||
v-model="reviewForm.reviewComment"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
placeholder="请输入审核意见"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="改进建议" prop="reviewSuggestions">
|
||||
<el-input
|
||||
v-model="reviewForm.reviewSuggestions"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入改进建议(选填)"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="reviewVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submitReview" :loading="reviewLoading">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 详情对话框 -->
|
||||
<monthly-detail
|
||||
v-if="detailVisible"
|
||||
:monthly-id="currentMonthlyId"
|
||||
:visible="detailVisible"
|
||||
@close="detailVisible = false"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="MonthlyReview">
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Check, Close, Search, Refresh, Download } from '@element-plus/icons-vue'
|
||||
import {
|
||||
getPendingReviewList,
|
||||
getReviewList,
|
||||
approveMonthly,
|
||||
batchApproveMonthly,
|
||||
getReviewStatistics,
|
||||
exportReviewData,
|
||||
type MonthlyReviewQueryParams,
|
||||
type MonthlyReviewParams,
|
||||
type BatchReviewParams,
|
||||
type ReviewStatistics
|
||||
} from '@/api/zsjy/internshipMonthlyReview'
|
||||
import MonthlyDetail from './detail.vue'
|
||||
|
||||
// 响应式数据
|
||||
const loading = ref(false)
|
||||
const reviewLoading = ref(false)
|
||||
const reviewVisible = ref(false)
|
||||
const detailVisible = ref(false)
|
||||
const currentMonthlyId = ref<number | null>(null)
|
||||
const selections = ref<any[]>([])
|
||||
const total = ref(0)
|
||||
const reviewList = ref<any[]>([])
|
||||
|
||||
// 查询参数
|
||||
const queryParams = reactive<MonthlyReviewQueryParams & { pageNum: number; pageSize: number }>({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
summaryMonth: '',
|
||||
studentName: '',
|
||||
studentNumber: '',
|
||||
reviewStatus: undefined
|
||||
})
|
||||
|
||||
// 统计数据
|
||||
const statistics = ref<ReviewStatistics>({
|
||||
totalCount: 0,
|
||||
pendingCount: 0,
|
||||
approvedCount: 0,
|
||||
rejectedCount: 0,
|
||||
averageScore: 0,
|
||||
completionRate: 0
|
||||
})
|
||||
|
||||
// 审核表单
|
||||
const reviewForm = reactive<MonthlyReviewParams & { isBatch?: boolean; monthlyIds?: number[] }>({
|
||||
monthlyId: 0,
|
||||
reviewStatus: 1,
|
||||
reviewScore: undefined,
|
||||
reviewComment: '',
|
||||
reviewSuggestions: '',
|
||||
isBatch: false,
|
||||
monthlyIds: []
|
||||
})
|
||||
|
||||
// 表单校验规则
|
||||
const reviewRules = {
|
||||
reviewStatus: [{ required: true, message: '请选择审核结果', trigger: 'change' }],
|
||||
reviewComment: [{ required: true, message: '请输入审核意见', trigger: 'blur' }]
|
||||
}
|
||||
|
||||
// ref引用
|
||||
const queryFormRef = ref()
|
||||
const reviewFormRef = ref()
|
||||
|
||||
// 获取列表数据
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const response = await getReviewList(queryParams)
|
||||
reviewList.value = response.rows
|
||||
total.value = response.total
|
||||
} catch (error) {
|
||||
console.error('获取审核列表失败:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 获取统计数据
|
||||
const getStatistics = async () => {
|
||||
try {
|
||||
const response = await getReviewStatistics(queryParams)
|
||||
statistics.value = response.data
|
||||
} catch (error) {
|
||||
console.error('获取统计数据失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索
|
||||
const handleQuery = () => {
|
||||
queryParams.pageNum = 1
|
||||
getList()
|
||||
getStatistics()
|
||||
}
|
||||
|
||||
// 重置搜索
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields()
|
||||
queryParams.pageNum = 1
|
||||
getList()
|
||||
getStatistics()
|
||||
}
|
||||
|
||||
// 选择变化
|
||||
const handleSelectionChange = (selection: any[]) => {
|
||||
selections.value = selection
|
||||
}
|
||||
|
||||
// 查看详情
|
||||
const handleDetail = (row: any) => {
|
||||
currentMonthlyId.value = row.monthlyId
|
||||
detailVisible.value = true
|
||||
}
|
||||
|
||||
// 单个审核
|
||||
const handleApprove = (row: any) => {
|
||||
reviewForm.monthlyId = row.monthlyId
|
||||
reviewForm.isBatch = false
|
||||
reviewForm.reviewStatus = 1
|
||||
reviewForm.reviewScore = undefined
|
||||
reviewForm.reviewComment = ''
|
||||
reviewForm.reviewSuggestions = ''
|
||||
reviewVisible.value = true
|
||||
}
|
||||
|
||||
// 重新审核
|
||||
const handleReReview = (row: any) => {
|
||||
reviewForm.monthlyId = row.monthlyId
|
||||
reviewForm.isBatch = false
|
||||
reviewForm.reviewStatus = row.reviewStatus
|
||||
reviewForm.reviewScore = row.reviewScore
|
||||
reviewForm.reviewComment = row.reviewComment || ''
|
||||
reviewForm.reviewSuggestions = row.reviewSuggestions || ''
|
||||
reviewVisible.value = true
|
||||
}
|
||||
|
||||
// 批量通过
|
||||
const handleBatchApprove = () => {
|
||||
const pendingItems = selections.value.filter(item => item.reviewStatus === 0)
|
||||
if (pendingItems.length === 0) {
|
||||
ElMessage.warning('请选择待审核的记录')
|
||||
return
|
||||
}
|
||||
|
||||
reviewForm.isBatch = true
|
||||
reviewForm.reviewStatus = 1
|
||||
reviewForm.reviewScore = 85 // 默认分数
|
||||
reviewForm.reviewComment = ''
|
||||
reviewForm.reviewSuggestions = ''
|
||||
reviewForm.monthlyIds = pendingItems.map(item => item.monthlyId)
|
||||
reviewVisible.value = true
|
||||
}
|
||||
|
||||
// 批量拒绝
|
||||
const handleBatchReject = () => {
|
||||
const pendingItems = selections.value.filter(item => item.reviewStatus === 0)
|
||||
if (pendingItems.length === 0) {
|
||||
ElMessage.warning('请选择待审核的记录')
|
||||
return
|
||||
}
|
||||
|
||||
reviewForm.isBatch = true
|
||||
reviewForm.reviewStatus = 2
|
||||
reviewForm.reviewScore = undefined
|
||||
reviewForm.reviewComment = ''
|
||||
reviewForm.reviewSuggestions = ''
|
||||
reviewForm.monthlyIds = pendingItems.map(item => item.monthlyId)
|
||||
reviewVisible.value = true
|
||||
}
|
||||
|
||||
// 提交审核
|
||||
const submitReview = async () => {
|
||||
try {
|
||||
await reviewFormRef.value?.validate()
|
||||
reviewLoading.value = true
|
||||
|
||||
if (reviewForm.isBatch) {
|
||||
// 批量审核
|
||||
const batchData: BatchReviewParams = {
|
||||
reviewItems: reviewForm.monthlyIds!.map(monthlyId => ({
|
||||
monthlyId,
|
||||
reviewStatus: reviewForm.reviewStatus,
|
||||
reviewScore: reviewForm.reviewScore,
|
||||
reviewComment: reviewForm.reviewComment,
|
||||
reviewSuggestions: reviewForm.reviewSuggestions
|
||||
}))
|
||||
}
|
||||
await batchApproveMonthly(batchData)
|
||||
ElMessage.success('批量审核成功')
|
||||
} else {
|
||||
// 单个审核
|
||||
await approveMonthly({
|
||||
monthlyId: reviewForm.monthlyId,
|
||||
reviewStatus: reviewForm.reviewStatus,
|
||||
reviewScore: reviewForm.reviewScore,
|
||||
reviewComment: reviewForm.reviewComment,
|
||||
reviewSuggestions: reviewForm.reviewSuggestions
|
||||
})
|
||||
ElMessage.success('审核成功')
|
||||
}
|
||||
|
||||
reviewVisible.value = false
|
||||
getList()
|
||||
getStatistics()
|
||||
} catch (error) {
|
||||
console.error('审核失败:', error)
|
||||
} finally {
|
||||
reviewLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 导出数据
|
||||
const handleExport = async () => {
|
||||
try {
|
||||
await exportReviewData(queryParams)
|
||||
ElMessage.success('导出成功')
|
||||
} catch (error) {
|
||||
console.error('导出失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取状态类型
|
||||
const getStatusType = (status: number) => {
|
||||
const statusMap: Record<number, string> = {
|
||||
0: 'warning',
|
||||
1: 'success',
|
||||
2: 'danger'
|
||||
}
|
||||
return statusMap[status] || 'info'
|
||||
}
|
||||
|
||||
// 获取状态文本
|
||||
const getStatusText = (status: number) => {
|
||||
const statusMap: Record<number, string> = {
|
||||
0: '待审核',
|
||||
1: '已审核',
|
||||
2: '审核拒绝'
|
||||
}
|
||||
return statusMap[status] || '未知'
|
||||
}
|
||||
|
||||
// 组件挂载
|
||||
onMounted(() => {
|
||||
getList()
|
||||
getStatistics()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.search-card {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
text-align: center;
|
||||
.stat-item {
|
||||
.stat-value {
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.stat-label {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.table-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.text-primary { color: #409eff; }
|
||||
.text-success { color: #67c23a; }
|
||||
.text-warning { color: #e6a23c; }
|
||||
.text-danger { color: #f56c6c; }
|
||||
.text-gray-500 { color: #9ca3af; }
|
||||
.font-bold { font-weight: bold; }
|
||||
.text-sm { font-size: 12px; }
|
||||
.mb-4 { margin-bottom: 16px; }
|
||||
.ml-2 { margin-left: 8px; }
|
||||
</style>
|
||||
@@ -0,0 +1,395 @@
|
||||
<template>
|
||||
<div class="batch-review-form">
|
||||
<!-- 批量设置区域 -->
|
||||
<el-card shadow="never" class="mb-4">
|
||||
<template #header>
|
||||
<span class="card-title">批量设置</span>
|
||||
<el-button type="text" @click="showBatchSetting = !showBatchSetting">
|
||||
{{ showBatchSetting ? '收起' : '展开' }}
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
<div v-show="showBatchSetting">
|
||||
<el-form :model="batchForm" label-width="120px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="统一审核结果">
|
||||
<el-radio-group v-model="batchForm.reviewStatus">
|
||||
<el-radio :label="1">通过</el-radio>
|
||||
<el-radio :label="2">拒绝</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="统一评分">
|
||||
<el-input-number
|
||||
v-model="batchForm.reviewScore"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:step="5"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-form-item label="统一审核意见">
|
||||
<el-input
|
||||
v-model="batchForm.reviewComment"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="输入统一的审核意见"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="统一改进建议">
|
||||
<el-input
|
||||
v-model="batchForm.reviewSuggestions"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
placeholder="输入统一的改进建议"
|
||||
maxlength="300"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="applyBatchSettings">应用到所有</el-button>
|
||||
<el-button @click="clearBatchSettings">清空设置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 个别审核区域 -->
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<span class="card-title">个别审核 ({{ selectedRows.length }}项)</span>
|
||||
</template>
|
||||
|
||||
<div class="review-list">
|
||||
<div v-for="(item, index) in reviewItems" :key="item.monthlyId" class="review-item">
|
||||
<el-card shadow="hover" class="item-card">
|
||||
<template #header>
|
||||
<div class="item-header">
|
||||
<span class="student-info">
|
||||
<strong>{{ item.studentName }}</strong>
|
||||
({{ item.studentNumber }}) - {{ item.summaryMonth }}
|
||||
</span>
|
||||
<span class="class-info">{{ item.className }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-form :model="item" label-width="100px" size="small">
|
||||
<el-row :gutter="15">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="审核结果" :prop="`reviewItems.${index}.reviewStatus`" required>
|
||||
<el-radio-group v-model="item.reviewStatus">
|
||||
<el-radio :label="1">
|
||||
<el-icon color="#67c23a"><SuccessFilled /></el-icon>
|
||||
通过
|
||||
</el-radio>
|
||||
<el-radio :label="2">
|
||||
<el-icon color="#f56c6c"><CircleCloseFilled /></el-icon>
|
||||
拒绝
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="审核评分" :prop="`reviewItems.${index}.reviewScore`">
|
||||
<el-input-number
|
||||
v-model="item.reviewScore"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:step="5"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="等级">
|
||||
<el-tag :type="getScoreTagType(item.reviewScore)">
|
||||
{{ getScoreLevel(item.reviewScore) }}
|
||||
</el-tag>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-form-item label="审核意见" :prop="`reviewItems.${index}.reviewComment`" required>
|
||||
<el-input
|
||||
v-model="item.reviewComment"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
placeholder="请输入审核意见"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="改进建议" :prop="`reviewItems.${index}.reviewSuggestions`">
|
||||
<el-input
|
||||
v-model="item.reviewSuggestions"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
placeholder="请输入改进建议"
|
||||
maxlength="300"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 快速操作 -->
|
||||
<el-form-item label="快速设置">
|
||||
<el-button-group>
|
||||
<el-button size="small" @click="setQuickReview(index, 1, 95, '总结内容详实,表现优秀')">优秀</el-button>
|
||||
<el-button size="small" @click="setQuickReview(index, 1, 85, '总结内容较好,符合要求')">良好</el-button>
|
||||
<el-button size="small" @click="setQuickReview(index, 1, 75, '总结内容基本符合要求')">中等</el-button>
|
||||
<el-button size="small" @click="setQuickReview(index, 2, 60, '总结内容需要改进')">需改进</el-button>
|
||||
</el-button-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="handleCancel">取消</el-button>
|
||||
<el-button type="primary" @click="submitBatchReview" :loading="submitting">
|
||||
<el-icon><Check /></el-icon>
|
||||
确认批量审核
|
||||
</el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, defineProps, defineEmits } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import {
|
||||
SuccessFilled,
|
||||
CircleCloseFilled,
|
||||
Check
|
||||
} from '@element-plus/icons-vue'
|
||||
import { batchReviewInternshipMonthly } from '@/api/zsjy/internshipMonthlyReview'
|
||||
|
||||
interface Props {
|
||||
selectedRows: any[]
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits(['refresh'])
|
||||
|
||||
// 状态管理
|
||||
const submitting = ref(false)
|
||||
const showBatchSetting = ref(true)
|
||||
|
||||
// 批量设置表单
|
||||
const batchForm = reactive({
|
||||
reviewStatus: 1,
|
||||
reviewScore: 85,
|
||||
reviewComment: '',
|
||||
reviewSuggestions: ''
|
||||
})
|
||||
|
||||
// 审核项目列表
|
||||
const reviewItems = ref(props.selectedRows.map(row => ({
|
||||
monthlyId: row.monthlyId,
|
||||
studentName: row.studentName,
|
||||
studentNumber: row.studentNumber,
|
||||
summaryMonth: row.summaryMonth,
|
||||
className: row.className,
|
||||
reviewStatus: 1,
|
||||
reviewScore: 85,
|
||||
reviewComment: '',
|
||||
reviewSuggestions: ''
|
||||
})))
|
||||
|
||||
/** 获取分数等级 */
|
||||
function getScoreLevel(score: number) {
|
||||
if (score >= 90) return '优秀'
|
||||
if (score >= 80) return '良好'
|
||||
if (score >= 70) return '中等'
|
||||
if (score >= 60) return '及格'
|
||||
return '不及格'
|
||||
}
|
||||
|
||||
/** 获取分数标签类型 */
|
||||
function getScoreTagType(score: number) {
|
||||
if (score >= 90) return 'success'
|
||||
if (score >= 80) return 'warning'
|
||||
if (score >= 70) return 'primary'
|
||||
return 'danger'
|
||||
}
|
||||
|
||||
/** 应用批量设置 */
|
||||
function applyBatchSettings() {
|
||||
ElMessageBox.confirm('确认将批量设置应用到所有选中的记录?', '确认操作', {
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
reviewItems.value.forEach(item => {
|
||||
if (batchForm.reviewStatus) {
|
||||
item.reviewStatus = batchForm.reviewStatus
|
||||
}
|
||||
if (batchForm.reviewScore !== null) {
|
||||
item.reviewScore = batchForm.reviewScore
|
||||
}
|
||||
if (batchForm.reviewComment) {
|
||||
item.reviewComment = batchForm.reviewComment
|
||||
}
|
||||
if (batchForm.reviewSuggestions) {
|
||||
item.reviewSuggestions = batchForm.reviewSuggestions
|
||||
}
|
||||
})
|
||||
ElMessage.success('批量设置已应用')
|
||||
})
|
||||
}
|
||||
|
||||
/** 清空批量设置 */
|
||||
function clearBatchSettings() {
|
||||
batchForm.reviewStatus = 1
|
||||
batchForm.reviewScore = 85
|
||||
batchForm.reviewComment = ''
|
||||
batchForm.reviewSuggestions = ''
|
||||
}
|
||||
|
||||
/** 快速设置审核结果 */
|
||||
function setQuickReview(index: number, status: number, score: number, comment: string) {
|
||||
const item = reviewItems.value[index]
|
||||
item.reviewStatus = status
|
||||
item.reviewScore = score
|
||||
item.reviewComment = comment
|
||||
}
|
||||
|
||||
/** 验证表单 */
|
||||
function validateForm() {
|
||||
for (let i = 0; i < reviewItems.value.length; i++) {
|
||||
const item = reviewItems.value[i]
|
||||
if (!item.reviewStatus) {
|
||||
ElMessage.error(`请为 ${item.studentName} 选择审核结果`)
|
||||
return false
|
||||
}
|
||||
if (!item.reviewComment || item.reviewComment.trim().length < 10) {
|
||||
ElMessage.error(`请为 ${item.studentName} 输入审核意见(至少10个字符)`)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/** 提交批量审核 */
|
||||
function submitBatchReview() {
|
||||
if (!validateForm()) {
|
||||
return
|
||||
}
|
||||
|
||||
ElMessageBox.confirm(`确认批量审核 ${reviewItems.value.length} 条记录?`, '确认批量审核', {
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
submitting.value = true
|
||||
|
||||
const reviewData = {
|
||||
reviewItems: reviewItems.value.map(item => ({
|
||||
monthlyId: item.monthlyId,
|
||||
reviewStatus: item.reviewStatus,
|
||||
reviewScore: item.reviewScore,
|
||||
reviewComment: item.reviewComment,
|
||||
reviewSuggestions: item.reviewSuggestions
|
||||
}))
|
||||
}
|
||||
|
||||
batchReviewInternshipMonthly(reviewData).then(() => {
|
||||
ElMessage.success('批量审核完成')
|
||||
emit('refresh')
|
||||
}).catch(() => {
|
||||
ElMessage.error('批量审核失败')
|
||||
}).finally(() => {
|
||||
submitting.value = false
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/** 取消操作 */
|
||||
function handleCancel() {
|
||||
emit('refresh')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.batch-review-form {
|
||||
max-height: 70vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.review-list {
|
||||
max-height: 50vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.review-item {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.item-card {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.item-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.student-info {
|
||||
font-weight: bold;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.class-info {
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
text-align: center;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.mb-4 {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
/* 滚动条样式 */
|
||||
.review-list::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.review-list::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.review-list::-webkit-scrollbar-thumb {
|
||||
background: #c1c1c1;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.review-list::-webkit-scrollbar-thumb:hover {
|
||||
background: #a8a8a8;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,330 @@
|
||||
<template>
|
||||
<div class="review-detail">
|
||||
<!-- 基本信息 -->
|
||||
<el-card shadow="never" class="mb-4">
|
||||
<template #header>
|
||||
<span class="card-title">基本信息</span>
|
||||
</template>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="学生姓名">{{ monthlyData.studentName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="学号">{{ monthlyData.studentNumber }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班级">{{ monthlyData.className }}</el-descriptions-item>
|
||||
<el-descriptions-item label="专业">{{ monthlyData.majorName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="总结月份">{{ monthlyData.summaryMonth }}</el-descriptions-item>
|
||||
<el-descriptions-item label="字数统计">{{ monthlyData.wordCount || 0 }}字</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">{{ monthlyData.createTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="审核状态">
|
||||
<el-tag :type="getReviewStatusTagType(monthlyData.reviewStatus)">
|
||||
{{ getReviewStatusText(monthlyData.reviewStatus) }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
|
||||
<!-- 总结内容 -->
|
||||
<el-card shadow="never" class="mb-4">
|
||||
<template #header>
|
||||
<span class="card-title">总结内容</span>
|
||||
</template>
|
||||
|
||||
<!-- 工作内容 -->
|
||||
<div class="content-section">
|
||||
<h4 class="section-title">工作内容</h4>
|
||||
<div class="content-text">{{ monthlyData.workContent || '暂无内容' }}</div>
|
||||
</div>
|
||||
|
||||
<!-- 学习收获 -->
|
||||
<div class="content-section">
|
||||
<h4 class="section-title">学习收获</h4>
|
||||
<div class="content-text">{{ monthlyData.learningGains || '暂无内容' }}</div>
|
||||
</div>
|
||||
|
||||
<!-- 问题与困难 -->
|
||||
<div class="content-section">
|
||||
<h4 class="section-title">问题与困难</h4>
|
||||
<div class="content-text">{{ monthlyData.problemsEncountered || '暂无内容' }}</div>
|
||||
</div>
|
||||
|
||||
<!-- 改进计划 -->
|
||||
<div class="content-section">
|
||||
<h4 class="section-title">改进计划</h4>
|
||||
<div class="content-text">{{ monthlyData.improvementPlan || '暂无内容' }}</div>
|
||||
</div>
|
||||
|
||||
<!-- 下月计划 -->
|
||||
<div class="content-section">
|
||||
<h4 class="section-title">下月计划</h4>
|
||||
<div class="content-text">{{ monthlyData.nextMonthPlan || '暂无内容' }}</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 自我评分 -->
|
||||
<el-card shadow="never" class="mb-4">
|
||||
<template #header>
|
||||
<span class="card-title">自我评分</span>
|
||||
</template>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<div class="score-item">
|
||||
<span class="score-label">专业技能:</span>
|
||||
<el-rate
|
||||
:model-value="monthlyData.professionalSkills"
|
||||
disabled
|
||||
show-score
|
||||
text-color="#ff9900"
|
||||
/>
|
||||
<span class="score-value">{{ monthlyData.professionalSkills || 0 }}分</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="score-item">
|
||||
<span class="score-label">沟通能力:</span>
|
||||
<el-rate
|
||||
:model-value="monthlyData.communicationSkills"
|
||||
disabled
|
||||
show-score
|
||||
text-color="#ff9900"
|
||||
/>
|
||||
<span class="score-value">{{ monthlyData.communicationSkills || 0 }}分</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="score-item">
|
||||
<span class="score-label">团队协作:</span>
|
||||
<el-rate
|
||||
:model-value="monthlyData.teamworkAbility"
|
||||
disabled
|
||||
show-score
|
||||
text-color="#ff9900"
|
||||
/>
|
||||
<span class="score-value">{{ monthlyData.teamworkAbility || 0 }}分</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="score-item">
|
||||
<span class="score-label">学习能力:</span>
|
||||
<el-rate
|
||||
:model-value="monthlyData.learningAbility"
|
||||
disabled
|
||||
show-score
|
||||
text-color="#ff9900"
|
||||
/>
|
||||
<span class="score-value">{{ monthlyData.learningAbility || 0 }}分</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="score-item">
|
||||
<span class="score-label">工作态度:</span>
|
||||
<el-rate
|
||||
:model-value="monthlyData.workAttitude"
|
||||
disabled
|
||||
show-score
|
||||
text-color="#ff9900"
|
||||
/>
|
||||
<span class="score-value">{{ monthlyData.workAttitude || 0 }}分</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="score-item">
|
||||
<span class="score-label">综合评分:</span>
|
||||
<el-tag :type="getScoreTagType(getAverageScore())" size="large">
|
||||
{{ getAverageScore().toFixed(1) }}分
|
||||
</el-tag>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<!-- 审核信息 -->
|
||||
<el-card v-if="monthlyData.reviewStatus !== 0" shadow="never" class="mb-4">
|
||||
<template #header>
|
||||
<span class="card-title">审核信息</span>
|
||||
</template>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="审核状态">
|
||||
<el-tag :type="getReviewStatusTagType(monthlyData.reviewStatus)">
|
||||
{{ getReviewStatusText(monthlyData.reviewStatus) }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="审核评分">
|
||||
<el-tag v-if="monthlyData.reviewScore !== null && monthlyData.reviewScore !== undefined"
|
||||
:type="getReviewScoreTagType(monthlyData.reviewScore)">
|
||||
{{ monthlyData.reviewScore }}分
|
||||
</el-tag>
|
||||
<span v-else class="text-gray-400">未评分</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="审核人">{{ monthlyData.reviewerName || '暂无' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="审核时间">{{ monthlyData.reviewTime || '暂无' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<!-- 审核意见 -->
|
||||
<div v-if="monthlyData.reviewComment" class="mt-4">
|
||||
<h4 class="section-title">审核意见</h4>
|
||||
<div class="content-text review-comment">{{ monthlyData.reviewComment }}</div>
|
||||
</div>
|
||||
|
||||
<!-- 改进建议 -->
|
||||
<div v-if="monthlyData.reviewSuggestions" class="mt-4">
|
||||
<h4 class="section-title">改进建议</h4>
|
||||
<div class="content-text review-suggestions">{{ monthlyData.reviewSuggestions }}</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="dialog-footer" v-if="monthlyData.reviewStatus === 0">
|
||||
<el-button type="success" @click="handleReview">立即审核</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineProps, defineEmits } from 'vue'
|
||||
|
||||
interface Props {
|
||||
monthlyData: any
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits(['refresh', 'review'])
|
||||
|
||||
/** 获取平均分 */
|
||||
function getAverageScore() {
|
||||
const scores = [
|
||||
props.monthlyData.professionalSkills || 0,
|
||||
props.monthlyData.communicationSkills || 0,
|
||||
props.monthlyData.teamworkAbility || 0,
|
||||
props.monthlyData.learningAbility || 0,
|
||||
props.monthlyData.workAttitude || 0
|
||||
]
|
||||
const total = scores.reduce((sum, score) => sum + score, 0)
|
||||
return total / scores.length
|
||||
}
|
||||
|
||||
/** 获取评分标签类型 */
|
||||
function getScoreTagType(score: number) {
|
||||
if (score >= 9) return 'success'
|
||||
if (score >= 8) return 'warning'
|
||||
if (score >= 7) return 'primary'
|
||||
return 'danger'
|
||||
}
|
||||
|
||||
/** 获取审核状态文本 */
|
||||
function getReviewStatusText(status: number) {
|
||||
switch (status) {
|
||||
case 0: return '待审核'
|
||||
case 1: return '已通过'
|
||||
case 2: return '已拒绝'
|
||||
default: return '未知'
|
||||
}
|
||||
}
|
||||
|
||||
/** 获取审核状态标签类型 */
|
||||
function getReviewStatusTagType(status: number) {
|
||||
switch (status) {
|
||||
case 0: return 'warning'
|
||||
case 1: return 'success'
|
||||
case 2: return 'danger'
|
||||
default: return 'info'
|
||||
}
|
||||
}
|
||||
|
||||
/** 获取审核评分标签类型 */
|
||||
function getReviewScoreTagType(score: number) {
|
||||
if (score >= 90) return 'success'
|
||||
if (score >= 80) return 'warning'
|
||||
if (score >= 70) return 'primary'
|
||||
return 'danger'
|
||||
}
|
||||
|
||||
/** 审核按钮点击 */
|
||||
function handleReview() {
|
||||
emit('review', props.monthlyData)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.review-detail {
|
||||
max-height: 70vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.content-section {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #606266;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 5px;
|
||||
border-bottom: 2px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.content-text {
|
||||
background-color: #f8f9fa;
|
||||
padding: 15px;
|
||||
border-radius: 6px;
|
||||
line-height: 1.6;
|
||||
color: #606266;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
min-height: 60px;
|
||||
}
|
||||
|
||||
.review-comment {
|
||||
background-color: #f0f9ff;
|
||||
border-left: 4px solid #409eff;
|
||||
}
|
||||
|
||||
.review-suggestions {
|
||||
background-color: #f9f9f9;
|
||||
border-left: 4px solid #67c23a;
|
||||
}
|
||||
|
||||
.score-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
padding: 10px;
|
||||
background-color: #fafafa;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.score-label {
|
||||
font-weight: bold;
|
||||
color: #606266;
|
||||
width: 80px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.score-value {
|
||||
margin-left: 10px;
|
||||
font-weight: bold;
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
text-align: center;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.mb-4 {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.mt-4 {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.text-gray-400 {
|
||||
color: #909399;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,383 @@
|
||||
<template>
|
||||
<div class="review-form">
|
||||
<!-- 学生信息展示 -->
|
||||
<el-card shadow="never" class="mb-4">
|
||||
<template #header>
|
||||
<span class="card-title">审核对象</span>
|
||||
</template>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="学生姓名">{{ monthlyData.studentName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="学号">{{ monthlyData.studentNumber }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班级">{{ monthlyData.className }}</el-descriptions-item>
|
||||
<el-descriptions-item label="总结月份">{{ monthlyData.summaryMonth }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
|
||||
<!-- 审核表单 -->
|
||||
<el-form ref="reviewFormRef" :model="reviewForm" :rules="reviewRules" label-width="100px">
|
||||
<!-- 审核结果 -->
|
||||
<el-form-item label="审核结果" prop="reviewStatus" required>
|
||||
<el-radio-group v-model="reviewForm.reviewStatus">
|
||||
<el-radio :label="1">
|
||||
<el-icon color="#67c23a"><SuccessFilled /></el-icon>
|
||||
通过
|
||||
</el-radio>
|
||||
<el-radio :label="2">
|
||||
<el-icon color="#f56c6c"><CircleCloseFilled /></el-icon>
|
||||
拒绝
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 审核评分 -->
|
||||
<el-form-item label="审核评分" prop="reviewScore">
|
||||
<div class="score-container">
|
||||
<el-slider
|
||||
v-model="reviewForm.reviewScore"
|
||||
:min="0"
|
||||
:max="100"
|
||||
show-stops
|
||||
:step="5"
|
||||
show-input
|
||||
:format-tooltip="formatTooltip"
|
||||
style="width: 80%"
|
||||
/>
|
||||
<span class="score-text">{{ getScoreLevel(reviewForm.reviewScore) }}</span>
|
||||
</div>
|
||||
<div class="score-description">
|
||||
<span class="desc-item">优秀(90-100)</span>
|
||||
<span class="desc-item">良好(80-89)</span>
|
||||
<span class="desc-item">中等(70-79)</span>
|
||||
<span class="desc-item">及格(60-69)</span>
|
||||
<span class="desc-item">不及格(0-59)</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 审核意见 -->
|
||||
<el-form-item label="审核意见" prop="reviewComment" required>
|
||||
<el-input
|
||||
v-model="reviewForm.reviewComment"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
placeholder="请输入审核意见,客观评价学生的月度总结质量和内容..."
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 改进建议 -->
|
||||
<el-form-item label="改进建议" prop="reviewSuggestions">
|
||||
<el-input
|
||||
v-model="reviewForm.reviewSuggestions"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入改进建议,为学生后续的实习和总结提供指导意见..."
|
||||
maxlength="300"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 快速评语模板 -->
|
||||
<el-form-item label="快速评语">
|
||||
<div class="template-container">
|
||||
<el-tag
|
||||
v-for="template in commentTemplates"
|
||||
:key="template.type"
|
||||
:type="template.type"
|
||||
effect="plain"
|
||||
class="template-tag"
|
||||
@click="insertTemplate(template.content)"
|
||||
>
|
||||
{{ template.label }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="template-tip">
|
||||
<el-icon><InfoFilled /></el-icon>
|
||||
点击上方标签可快速插入评语模板
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitReview" :loading="submitting">
|
||||
<el-icon><Check /></el-icon>
|
||||
确认审核
|
||||
</el-button>
|
||||
<el-button @click="resetForm">
|
||||
<el-icon><Refresh /></el-icon>
|
||||
重置
|
||||
</el-button>
|
||||
<el-button @click="previewReview">
|
||||
<el-icon><View /></el-icon>
|
||||
预览
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 预览对话框 -->
|
||||
<el-dialog v-model="previewOpen" title="审核预览" width="500px" append-to-body>
|
||||
<div class="preview-content">
|
||||
<el-descriptions :column="1" border>
|
||||
<el-descriptions-item label="审核结果">
|
||||
<el-tag :type="reviewForm.reviewStatus === 1 ? 'success' : 'danger'">
|
||||
{{ reviewForm.reviewStatus === 1 ? '通过' : '拒绝' }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="审核评分">
|
||||
<el-tag :type="getScoreTagType(reviewForm.reviewScore)">
|
||||
{{ reviewForm.reviewScore }}分 ({{ getScoreLevel(reviewForm.reviewScore) }})
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="审核意见">
|
||||
<div class="preview-text">{{ reviewForm.reviewComment || '暂无' }}</div>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="改进建议">
|
||||
<div class="preview-text">{{ reviewForm.reviewSuggestions || '暂无' }}</div>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="previewOpen = false">关闭</el-button>
|
||||
<el-button type="primary" @click="confirmSubmit">确认提交</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, defineProps, defineEmits } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import {
|
||||
SuccessFilled,
|
||||
CircleCloseFilled,
|
||||
InfoFilled,
|
||||
Check,
|
||||
Refresh,
|
||||
View
|
||||
} from '@element-plus/icons-vue'
|
||||
import { reviewInternshipMonthly } from '@/api/zsjy/internshipMonthlyReview'
|
||||
|
||||
interface Props {
|
||||
monthlyData: any
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits(['refresh'])
|
||||
|
||||
// 表单引用
|
||||
const reviewFormRef = ref()
|
||||
|
||||
// 表单数据
|
||||
const reviewForm = reactive({
|
||||
monthlyId: props.monthlyData.monthlyId,
|
||||
reviewStatus: 1, // 默认通过
|
||||
reviewScore: 85, // 默认85分
|
||||
reviewComment: '',
|
||||
reviewSuggestions: ''
|
||||
})
|
||||
|
||||
// 表单验证规则
|
||||
const reviewRules = {
|
||||
reviewStatus: [
|
||||
{ required: true, message: '请选择审核结果', trigger: 'change' }
|
||||
],
|
||||
reviewScore: [
|
||||
{ required: true, message: '请输入审核评分', trigger: 'blur' },
|
||||
{ type: 'number', min: 0, max: 100, message: '评分范围为0-100分', trigger: 'blur' }
|
||||
],
|
||||
reviewComment: [
|
||||
{ required: true, message: '请输入审核意见', trigger: 'blur' },
|
||||
{ min: 10, max: 500, message: '审核意见长度在10到500个字符', trigger: 'blur' }
|
||||
],
|
||||
reviewSuggestions: [
|
||||
{ max: 300, message: '改进建议长度不能超过300个字符', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
|
||||
// 状态管理
|
||||
const submitting = ref(false)
|
||||
const previewOpen = ref(false)
|
||||
|
||||
// 评语模板
|
||||
const commentTemplates = [
|
||||
{
|
||||
type: 'success',
|
||||
label: '优秀评语',
|
||||
content: '总结内容详实,逻辑清晰,能够很好地反映实习期间的工作情况和学习收获。自我评价客观,对遇到的问题有深入思考,改进计划切实可行。'
|
||||
},
|
||||
{
|
||||
type: 'warning',
|
||||
label: '良好评语',
|
||||
content: '总结内容较为完整,基本能够反映实习情况。部分内容需要进一步完善,建议在今后的总结中更加注重细节描述和深度思考。'
|
||||
},
|
||||
{
|
||||
type: 'primary',
|
||||
label: '中等评语',
|
||||
content: '总结内容基本符合要求,但在深度和完整性方面还有提升空间。建议多关注工作中的具体细节和个人成长感悟。'
|
||||
},
|
||||
{
|
||||
type: 'danger',
|
||||
label: '需改进',
|
||||
content: '总结内容过于简单,缺乏具体的工作描述和深入的思考。请重新整理总结内容,确保内容的完整性和深度。'
|
||||
}
|
||||
]
|
||||
|
||||
/** 格式化滑块提示 */
|
||||
function formatTooltip(value: number) {
|
||||
return `${value}分`
|
||||
}
|
||||
|
||||
/** 获取分数等级 */
|
||||
function getScoreLevel(score: number) {
|
||||
if (score >= 90) return '优秀'
|
||||
if (score >= 80) return '良好'
|
||||
if (score >= 70) return '中等'
|
||||
if (score >= 60) return '及格'
|
||||
return '不及格'
|
||||
}
|
||||
|
||||
/** 获取分数标签类型 */
|
||||
function getScoreTagType(score: number) {
|
||||
if (score >= 90) return 'success'
|
||||
if (score >= 80) return 'warning'
|
||||
if (score >= 70) return 'primary'
|
||||
return 'danger'
|
||||
}
|
||||
|
||||
/** 插入评语模板 */
|
||||
function insertTemplate(template: string) {
|
||||
if (reviewForm.reviewComment) {
|
||||
reviewForm.reviewComment += '\n\n' + template
|
||||
} else {
|
||||
reviewForm.reviewComment = template
|
||||
}
|
||||
}
|
||||
|
||||
/** 重置表单 */
|
||||
function resetForm() {
|
||||
reviewFormRef.value?.resetFields()
|
||||
reviewForm.reviewStatus = 1
|
||||
reviewForm.reviewScore = 85
|
||||
reviewForm.reviewComment = ''
|
||||
reviewForm.reviewSuggestions = ''
|
||||
}
|
||||
|
||||
/** 预览审核 */
|
||||
function previewReview() {
|
||||
reviewFormRef.value?.validate((valid: boolean) => {
|
||||
if (valid) {
|
||||
previewOpen.value = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** 提交审核 */
|
||||
function submitReview() {
|
||||
reviewFormRef.value?.validate((valid: boolean) => {
|
||||
if (valid) {
|
||||
const message = reviewForm.reviewStatus === 1 ? '确认通过此月度总结?' : '确认拒绝此月度总结?'
|
||||
ElMessageBox.confirm(message, '确认审核', {
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
confirmSubmit()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** 确认提交 */
|
||||
function confirmSubmit() {
|
||||
submitting.value = true
|
||||
previewOpen.value = false
|
||||
|
||||
reviewInternshipMonthly(reviewForm).then(() => {
|
||||
ElMessage.success('审核完成')
|
||||
emit('refresh')
|
||||
}).catch(() => {
|
||||
ElMessage.error('审核失败')
|
||||
}).finally(() => {
|
||||
submitting.value = false
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.review-form {
|
||||
max-height: 70vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.score-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.score-text {
|
||||
font-weight: bold;
|
||||
color: #409eff;
|
||||
min-width: 60px;
|
||||
}
|
||||
|
||||
.score-description {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.desc-item {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
padding: 2px 8px;
|
||||
background-color: #f5f7fa;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.template-container {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.template-tag {
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.template-tag:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.template-tip {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.preview-content {
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.preview-text {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.mb-4 {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,589 @@
|
||||
<template>
|
||||
<div class="p-2 page-container">
|
||||
<!-- 搜索区域 -->
|
||||
<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" label-width="100px">
|
||||
<!-- 第一行:搜索条件 -->
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="6">
|
||||
<el-form-item label="总结月份" prop="summaryMonth">
|
||||
<el-date-picker
|
||||
v-model="queryParams.summaryMonth"
|
||||
type="month"
|
||||
value-format="YYYY-MM"
|
||||
placeholder="请选择总结月份"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="学生姓名" prop="studentName">
|
||||
<el-input v-model="queryParams.studentName" placeholder="请输入学生姓名" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="学号" prop="studentNumber">
|
||||
<el-input v-model="queryParams.studentNumber" placeholder="请输入学号" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="审核状态" prop="reviewStatus">
|
||||
<el-select v-model="queryParams.reviewStatus" placeholder="请选择审核状态" clearable style="width: 100%">
|
||||
<el-option label="待审核" :value="0" />
|
||||
<el-option label="已通过" :value="1" />
|
||||
<el-option label="已拒绝" :value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 第二行:时间范围 + 操作按钮 -->
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="6">
|
||||
<el-form-item label="创建时间">
|
||||
<el-date-picker
|
||||
v-model="daterangeCreateTime"
|
||||
value-format="YYYY-MM-DD"
|
||||
type="daterange"
|
||||
range-separator="-"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
@change="handleQuery"
|
||||
style="width: 100%"
|
||||
></el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="18">
|
||||
<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-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<!-- 统计卡片区域 -->
|
||||
<div class="mb-[10px]">
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="6">
|
||||
<el-card shadow="hover" class="stat-card stat-card-primary">
|
||||
<div class="stat-content">
|
||||
<div class="stat-icon">
|
||||
<el-icon><DocumentChecked /></el-icon>
|
||||
</div>
|
||||
<div class="stat-info">
|
||||
<div class="stat-value">{{ statistics.totalCount }}</div>
|
||||
<div class="stat-label">总记录数</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-card shadow="hover" class="stat-card stat-card-warning">
|
||||
<div class="stat-content">
|
||||
<div class="stat-icon">
|
||||
<el-icon><Clock /></el-icon>
|
||||
</div>
|
||||
<div class="stat-info">
|
||||
<div class="stat-value">{{ statistics.pendingCount }}</div>
|
||||
<div class="stat-label">待审核</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-card shadow="hover" class="stat-card stat-card-success">
|
||||
<div class="stat-content">
|
||||
<div class="stat-icon">
|
||||
<el-icon><SuccessFilled /></el-icon>
|
||||
</div>
|
||||
<div class="stat-info">
|
||||
<div class="stat-value">{{ statistics.approvedCount }}</div>
|
||||
<div class="stat-label">已通过</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-card shadow="hover" class="stat-card stat-card-danger">
|
||||
<div class="stat-content">
|
||||
<div class="stat-icon">
|
||||
<el-icon><CircleCloseFilled /></el-icon>
|
||||
</div>
|
||||
<div class="stat-info">
|
||||
<div class="stat-value">{{ statistics.rejectedCount }}</div>
|
||||
<div class="stat-label">已拒绝</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<!-- 表格区域 -->
|
||||
<el-card shadow="never" class="button-card table-card">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
icon="Check"
|
||||
:disabled="multiple"
|
||||
@click="handleBatchReview"
|
||||
v-hasPermi="['zsjy:internshipmonthly:review']"
|
||||
>批量审核</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<div class="table-container">
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
border
|
||||
:data="reviewList"
|
||||
@selection-change="handleSelectionChange"
|
||||
@row-dblclick="handleDetail"
|
||||
style="width: 100%"
|
||||
:scroll-x="true"
|
||||
class="scroll-table"
|
||||
>
|
||||
<el-table-column type="selection" width="55" align="center" fixed="left" />
|
||||
<el-table-column label="学生姓名" align="center" prop="studentName" width="120" show-overflow-tooltip fixed="left" />
|
||||
<el-table-column label="学号" align="center" prop="studentNumber" width="140" show-overflow-tooltip />
|
||||
<el-table-column label="总结月份" align="center" prop="summaryMonth" width="120" />
|
||||
<el-table-column label="班级" align="center" prop="className" width="150" show-overflow-tooltip />
|
||||
<el-table-column label="专业" align="center" prop="majorName" width="150" show-overflow-tooltip />
|
||||
<el-table-column label="工作内容" align="center" prop="workContent" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column label="自我评分" align="center" width="120">
|
||||
<template #default="scope">
|
||||
<el-tooltip content="专业/沟通/团队/学习/态度" placement="top">
|
||||
<el-tag :type="getScoreTagType(getAverageScore(scope.row))">
|
||||
{{ getAverageScore(scope.row).toFixed(1) }}分
|
||||
</el-tag>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="字数统计" align="center" width="100">
|
||||
<template #default="scope">
|
||||
{{ scope.row.wordCount || 0 }}字
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="审核状态" align="center" prop="reviewStatus" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag :type="getReviewStatusTagType(scope.row.reviewStatus)">
|
||||
{{ getReviewStatusText(scope.row.reviewStatus) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="审核评分" align="center" prop="reviewScore" width="100">
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.reviewScore !== null && scope.row.reviewScore !== undefined">
|
||||
<el-tag :type="getReviewScoreTagType(scope.row.reviewScore)">
|
||||
{{ scope.row.reviewScore }}分
|
||||
</el-tag>
|
||||
</span>
|
||||
<span v-else class="text-gray-400">未评分</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="审核时间" align="center" prop="reviewTime" width="150" />
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="150" />
|
||||
<el-table-column label="操作" align="center" width="200" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" icon="View" @click="handleDetail(scope.row)">查看</el-button>
|
||||
<el-button
|
||||
v-if="scope.row.reviewStatus === 0"
|
||||
link
|
||||
type="success"
|
||||
icon="Check"
|
||||
@click="handleReview(scope.row)"
|
||||
v-hasPermi="['zsjy:internshipmonthly:review']"
|
||||
>审核</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<!-- 审核详情对话框 -->
|
||||
<el-dialog v-model="detailOpen" :title="detailTitle" width="1200px" append-to-body>
|
||||
<ReviewDetail ref="reviewDetailRef" :monthly-data="currentMonthlyData" @refresh="getList" />
|
||||
</el-dialog>
|
||||
|
||||
<!-- 单个审核对话框 -->
|
||||
<el-dialog v-model="reviewOpen" title="审核月度总结" width="600px" append-to-body>
|
||||
<ReviewForm ref="reviewFormRef" :monthly-data="currentMonthlyData" @refresh="handleReviewSuccess" />
|
||||
</el-dialog>
|
||||
|
||||
<!-- 批量审核对话框 -->
|
||||
<el-dialog v-model="batchReviewOpen" title="批量审核" width="800px" append-to-body>
|
||||
<BatchReviewForm ref="batchReviewFormRef" :selected-rows="multipleSelection" @refresh="handleBatchReviewSuccess" />
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="InternshipMonthlyReview" lang="ts">
|
||||
import { onMounted, reactive, ref, toRefs, getCurrentInstance } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import {
|
||||
DocumentChecked,
|
||||
Clock,
|
||||
SuccessFilled,
|
||||
CircleCloseFilled,
|
||||
Search,
|
||||
Refresh,
|
||||
Check,
|
||||
View
|
||||
} from '@element-plus/icons-vue'
|
||||
import { getReviewList, getReviewStatistics } from '@/api/zsjy/internshipMonthlyReview'
|
||||
import type { InternshipMonthlyVO, InternshipMonthlyReviewStatisticsVO } from '@/api/zsjy/types'
|
||||
import ReviewDetail from './components/ReviewDetail.vue'
|
||||
import ReviewForm from './components/ReviewForm.vue'
|
||||
import BatchReviewForm from './components/BatchReviewForm.vue'
|
||||
|
||||
const { proxy } = getCurrentInstance() as any
|
||||
|
||||
// 数据状态
|
||||
const data = reactive({
|
||||
loading: true,
|
||||
showSearch: true,
|
||||
reviewList: [] as any[],
|
||||
multipleSelection: [] as any[],
|
||||
single: true,
|
||||
multiple: true,
|
||||
total: 0,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
summaryMonth: undefined,
|
||||
studentName: undefined,
|
||||
studentNumber: undefined,
|
||||
reviewStatus: undefined,
|
||||
startDate: undefined,
|
||||
endDate: undefined
|
||||
},
|
||||
// 日期范围
|
||||
daterangeCreateTime: [] as any[],
|
||||
// 统计数据
|
||||
statistics: {
|
||||
totalCount: 0,
|
||||
pendingCount: 0,
|
||||
approvedCount: 0,
|
||||
rejectedCount: 0,
|
||||
averageScore: 0,
|
||||
completionRate: 0
|
||||
}
|
||||
})
|
||||
|
||||
const {
|
||||
loading,
|
||||
showSearch,
|
||||
reviewList,
|
||||
multipleSelection,
|
||||
single,
|
||||
multiple,
|
||||
total,
|
||||
queryParams,
|
||||
daterangeCreateTime,
|
||||
statistics
|
||||
} = toRefs(data)
|
||||
|
||||
// 对话框状态
|
||||
const detailOpen = ref(false)
|
||||
const reviewOpen = ref(false)
|
||||
const batchReviewOpen = ref(false)
|
||||
const detailTitle = ref('')
|
||||
const currentMonthlyData = ref({})
|
||||
|
||||
// 表单引用
|
||||
const queryFormRef = ref()
|
||||
const reviewDetailRef = ref()
|
||||
const reviewFormRef = ref()
|
||||
const batchReviewFormRef = ref()
|
||||
|
||||
/** 查询列表 */
|
||||
function getList() {
|
||||
data.loading = true
|
||||
|
||||
// 处理时间范围
|
||||
if (data.daterangeCreateTime && data.daterangeCreateTime.length === 2) {
|
||||
data.queryParams.startDate = data.daterangeCreateTime[0]
|
||||
data.queryParams.endDate = data.daterangeCreateTime[1]
|
||||
} else {
|
||||
data.queryParams.startDate = undefined
|
||||
data.queryParams.endDate = undefined
|
||||
}
|
||||
|
||||
getReviewList(data.queryParams).then((response: any) => {
|
||||
data.reviewList = response.rows
|
||||
data.total = response.total
|
||||
data.loading = false
|
||||
}).catch(() => {
|
||||
data.loading = false
|
||||
})
|
||||
}
|
||||
|
||||
/** 获取统计数据 */
|
||||
function getStatistics() {
|
||||
getReviewStatistics().then((response: any) => {
|
||||
data.statistics = response.data
|
||||
})
|
||||
}
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
function handleQuery() {
|
||||
data.queryParams.pageNum = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
/** 重置按钮操作 */
|
||||
function resetQuery() {
|
||||
data.daterangeCreateTime = []
|
||||
queryFormRef.value?.resetFields()
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
/** 多选框选中数据 */
|
||||
function handleSelectionChange(selection: any[]) {
|
||||
data.multipleSelection = selection
|
||||
data.single = selection.length !== 1
|
||||
data.multiple = !selection.length
|
||||
}
|
||||
|
||||
/** 查看详情 */
|
||||
function handleDetail(row: any) {
|
||||
currentMonthlyData.value = { ...row }
|
||||
detailTitle.value = `${row.studentName}的月度总结详情`
|
||||
detailOpen.value = true
|
||||
}
|
||||
|
||||
/** 单个审核 */
|
||||
function handleReview(row: any) {
|
||||
currentMonthlyData.value = { ...row }
|
||||
reviewOpen.value = true
|
||||
}
|
||||
|
||||
/** 批量审核 */
|
||||
function handleBatchReview() {
|
||||
if (data.multipleSelection.length === 0) {
|
||||
ElMessage.warning('请选择要审核的数据')
|
||||
return
|
||||
}
|
||||
|
||||
// 检查是否都是待审核状态
|
||||
const pendingRows = data.multipleSelection.filter(row => row.reviewStatus === 0)
|
||||
if (pendingRows.length === 0) {
|
||||
ElMessage.warning('选择的数据中没有待审核的记录')
|
||||
return
|
||||
}
|
||||
|
||||
if (pendingRows.length !== data.multipleSelection.length) {
|
||||
ElMessage.warning('只能审核状态为"待审核"的记录,请重新选择')
|
||||
return
|
||||
}
|
||||
|
||||
batchReviewOpen.value = true
|
||||
}
|
||||
|
||||
/** 审核成功回调 */
|
||||
function handleReviewSuccess() {
|
||||
reviewOpen.value = false
|
||||
getList()
|
||||
getStatistics()
|
||||
ElMessage.success('审核完成')
|
||||
}
|
||||
|
||||
/** 批量审核成功回调 */
|
||||
function handleBatchReviewSuccess() {
|
||||
batchReviewOpen.value = false
|
||||
getList()
|
||||
getStatistics()
|
||||
ElMessage.success('批量审核完成')
|
||||
}
|
||||
|
||||
/** 获取平均分 */
|
||||
function getAverageScore(row: any) {
|
||||
const scores = [
|
||||
row.professionalSkills || 0,
|
||||
row.communicationSkills || 0,
|
||||
row.teamworkSkills || 0,
|
||||
row.learningAbility || 0,
|
||||
row.workAttitude || 0
|
||||
]
|
||||
const total = scores.reduce((sum, score) => sum + score, 0)
|
||||
return total / scores.length
|
||||
}
|
||||
|
||||
/** 获取评分标签类型 */
|
||||
function getScoreTagType(score: number) {
|
||||
if (score >= 9) return 'success'
|
||||
if (score >= 8) return 'warning'
|
||||
if (score >= 7) return 'primary'
|
||||
return 'danger'
|
||||
}
|
||||
|
||||
/** 获取审核状态文本 */
|
||||
function getReviewStatusText(status: number) {
|
||||
switch (status) {
|
||||
case 0: return '待审核'
|
||||
case 1: return '已通过'
|
||||
case 2: return '已拒绝'
|
||||
default: return '未知'
|
||||
}
|
||||
}
|
||||
|
||||
/** 获取审核状态标签类型 */
|
||||
function getReviewStatusTagType(status: number) {
|
||||
switch (status) {
|
||||
case 0: return 'warning'
|
||||
case 1: return 'success'
|
||||
case 2: return 'danger'
|
||||
default: return 'info'
|
||||
}
|
||||
}
|
||||
|
||||
/** 获取审核评分标签类型 */
|
||||
function getReviewScoreTagType(score: number) {
|
||||
if (score >= 90) return 'success'
|
||||
if (score >= 80) return 'warning'
|
||||
if (score >= 70) return 'primary'
|
||||
return 'danger'
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
getStatistics()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page-container {
|
||||
background-color: #f5f7fa;
|
||||
min-height: calc(100vh - 50px);
|
||||
}
|
||||
|
||||
.search-btn-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
/* 统计卡片样式 */
|
||||
.stat-card {
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.stat-card:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.stat-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.stat-icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 20px;
|
||||
font-size: 24px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.stat-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
line-height: 1;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.stat-card-primary .stat-icon {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
}
|
||||
|
||||
.stat-card-primary .stat-value {
|
||||
color: #667eea;
|
||||
}
|
||||
|
||||
.stat-card-success .stat-icon {
|
||||
background: linear-gradient(135deg, #4ecdc4 0%, #44a08d 100%);
|
||||
}
|
||||
|
||||
.stat-card-success .stat-value {
|
||||
color: #4ecdc4;
|
||||
}
|
||||
|
||||
.stat-card-warning .stat-icon {
|
||||
background: linear-gradient(135deg, #ffeaa7 0%, #fab1a0 100%);
|
||||
}
|
||||
|
||||
.stat-card-warning .stat-value {
|
||||
color: #e17055;
|
||||
}
|
||||
|
||||
.stat-card-danger .stat-icon {
|
||||
background: linear-gradient(135deg, #fd79a8 0%, #e84393 100%);
|
||||
}
|
||||
|
||||
.stat-card-danger .stat-value {
|
||||
color: #e84393;
|
||||
}
|
||||
|
||||
/* 表格样式 */
|
||||
.table-card {
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.scroll-table {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
/* 按钮卡片样式 */
|
||||
.button-card {
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.mb8 {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user