Merge branch 'master' of http://47.99.164.66:3000/hzdyjs-xg/all-project
This commit is contained in:
commit
c9f3687c70
20 files changed
+3322
-2
No files matched your search
+24
-1
@@ -157,7 +157,7 @@ public class InternshipInfoController extends BaseController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改实习信息
|
||||
* 33
|
||||
*/
|
||||
@Operation(summary = "修改实习信息", description = "修改学生实习信息")
|
||||
@SaCheckPermission("zsjy:internship:edit")
|
||||
@@ -202,4 +202,27 @@ public class InternshipInfoController extends BaseController {
|
||||
return R.fail("删除实习信息失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前学生的实习信息
|
||||
*/
|
||||
@Operation(summary = "获取当前学生实习信息", description = "获取当前登录学生的实习信息,用于月度总结等功能")
|
||||
@SaCheckPermission("zsjy:internship:query")
|
||||
@GetMapping("/current")
|
||||
public R<InternshipInfoVO> getCurrentStudentInternship() {
|
||||
try {
|
||||
log.info("=== 获取当前学生实习信息接口被调用 ===");
|
||||
InternshipInfoVO result = internshipInfoService.getCurrentStudentInternship();
|
||||
if (result != null) {
|
||||
log.info("成功获取当前学生实习信息,实习ID:{}", result.getInternshipId());
|
||||
return R.ok(result);
|
||||
} else {
|
||||
log.info("当前学生没有实习信息");
|
||||
return R.ok(); // 返回空数据,前端需要处理这种情况
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("获取当前学生实习信息失败:{}", e.getMessage(), e);
|
||||
return R.fail("获取实习信息失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
+238
@@ -0,0 +1,238 @@
|
||||
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.core.validate.EditGroup;
|
||||
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.ZsjyInternshipMonthlyAddBo;
|
||||
import org.dromara.zsjy.domain.bo.ZsjyInternshipMonthlyQueryBo;
|
||||
import org.dromara.zsjy.domain.vo.ZsjyInternshipMonthlyVo;
|
||||
import org.dromara.zsjy.service.IZsjyInternshipMonthlyService;
|
||||
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-03
|
||||
*/
|
||||
@Slf4j
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/zsjy/internship/monthly")
|
||||
@Tag(name = "学生月度实习总结", description = "学生月度实习总结填写管理")
|
||||
public class ZsjyInternshipMonthlyController extends BaseController {
|
||||
|
||||
private final IZsjyInternshipMonthlyService monthlyService;
|
||||
|
||||
/**
|
||||
* 查询学生月度实习总结列表
|
||||
*/
|
||||
@Operation(summary = "查询学生月度实习总结列表", description = "学生查看自己的月度总结列表")
|
||||
@SaCheckPermission("zsjy:internshipmonthly:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<ZsjyInternshipMonthlyVo> list(@Validated ZsjyInternshipMonthlyQueryBo queryBo, PageQuery pageQuery) {
|
||||
log.info("=== Controller层调试 ===");
|
||||
log.info("接口被调用: /zsjy/internship/monthly/list");
|
||||
log.info("查询参数: {}", queryBo);
|
||||
log.info("分页参数: {}", pageQuery);
|
||||
|
||||
return monthlyService.queryPageList(queryBo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询学生月度实习总结详细信息
|
||||
*/
|
||||
@Operation(summary = "查询学生月度实习总结详细信息", description = "根据ID查询月度总结详情")
|
||||
@SaCheckPermission("zsjy:internshipmonthly:query")
|
||||
@GetMapping("/{monthlyId}")
|
||||
public R<ZsjyInternshipMonthlyVo> getInfo(@Parameter(description = "月度总结ID")
|
||||
@PathVariable Long monthlyId) {
|
||||
log.info("查询月度总结详情, ID: {}", monthlyId);
|
||||
return R.ok(monthlyService.queryById(monthlyId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增学生月度实习总结
|
||||
*/
|
||||
@Operation(summary = "新增学生月度实习总结", description = "学生创建新的月度总结")
|
||||
@SaCheckPermission("zsjy:internshipmonthly:add")
|
||||
@PostMapping
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody ZsjyInternshipMonthlyAddBo addBo) {
|
||||
log.info("新增月度总结: {}", addBo);
|
||||
|
||||
if (!monthlyService.insertByBo(addBo)) {
|
||||
return R.fail("新增月度总结失败");
|
||||
}
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改学生月度实习总结
|
||||
*/
|
||||
@Operation(summary = "修改学生月度实习总结", description = "学生编辑自己的月度总结")
|
||||
@SaCheckPermission("zsjy:internshipmonthly:edit")
|
||||
@PutMapping
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ZsjyInternshipMonthlyAddBo addBo) {
|
||||
log.info("修改月度总结: {}", addBo);
|
||||
|
||||
if (!monthlyService.updateByBo(addBo)) {
|
||||
return R.fail("修改月度总结失败");
|
||||
}
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除学生月度实习总结
|
||||
*/
|
||||
@Operation(summary = "删除学生月度实习总结", description = "学生删除自己的草稿状态月度总结")
|
||||
@SaCheckPermission("zsjy:internshipmonthly:remove")
|
||||
@DeleteMapping("/{monthlyIds}")
|
||||
public R<Void> remove(@Parameter(description = "月度总结ID串")
|
||||
@PathVariable Long[] monthlyIds) {
|
||||
log.info("删除月度总结, IDs: {}", (Object) monthlyIds);
|
||||
|
||||
if (!monthlyService.deleteByIds(List.of(monthlyIds))) {
|
||||
return R.fail("删除月度总结失败");
|
||||
}
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交月度总结审批
|
||||
*/
|
||||
@Operation(summary = "提交月度总结审批", description = "学生提交月度总结给班主任审批")
|
||||
@SaCheckPermission("zsjy:internshipmonthly:submit")
|
||||
@PutMapping("/submit/{monthlyId}")
|
||||
public R<Void> submit(@Parameter(description = "月度总结ID")
|
||||
@PathVariable Long monthlyId) {
|
||||
log.info("提交月度总结审批, ID: {}", monthlyId);
|
||||
|
||||
if (!monthlyService.submitForApproval(monthlyId)) {
|
||||
return R.fail("提交月度总结失败");
|
||||
}
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动保存草稿
|
||||
*/
|
||||
@Operation(summary = "自动保存草稿", description = "学生编辑时自动保存草稿")
|
||||
@SaCheckPermission("zsjy:internshipmonthly:autosave")
|
||||
@PostMapping("/autosave")
|
||||
public R<Void> autoSave(@RequestBody ZsjyInternshipMonthlyAddBo addBo) {
|
||||
log.info("自动保存草稿: {}", addBo);
|
||||
|
||||
if (!monthlyService.autoSaveDraft(addBo)) {
|
||||
return R.fail("自动保存失败");
|
||||
}
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查月份是否存在总结
|
||||
*/
|
||||
@Operation(summary = "检查月份是否存在总结", description = "检查学生某月是否已有总结记录")
|
||||
@SaCheckPermission("zsjy:internshipmonthly:check")
|
||||
@GetMapping("/check/{summaryMonth}")
|
||||
public R<Boolean> checkMonth(@Parameter(description = "总结月份")
|
||||
@PathVariable String summaryMonth,
|
||||
@Parameter(description = "排除的总结ID")
|
||||
@RequestParam(required = false) Long monthlyId) {
|
||||
log.info("检查月份总结, 月份: {}, 排除ID: {}", summaryMonth, monthlyId);
|
||||
|
||||
Boolean exists = monthlyService.checkMonthExists(null, summaryMonth, monthlyId);
|
||||
return R.ok(exists);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取月度总结模板
|
||||
*/
|
||||
@Operation(summary = "获取月度总结模板", description = "获取指定月份的总结模板信息")
|
||||
@SaCheckPermission("zsjy:internshipmonthly:template")
|
||||
@GetMapping("/template/{summaryMonth}")
|
||||
public R<ZsjyInternshipMonthlyVo> getTemplate(@Parameter(description = "总结月份")
|
||||
@PathVariable String summaryMonth) {
|
||||
log.info("获取月度总结模板, 月份: {}", summaryMonth);
|
||||
|
||||
ZsjyInternshipMonthlyVo template = monthlyService.getMonthlyTemplate(summaryMonth);
|
||||
return R.ok(template);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询学生指定实习的月度总结列表
|
||||
*/
|
||||
@Operation(summary = "查询学生指定实习的月度总结列表", description = "查询学生某个实习的所有月度总结")
|
||||
@SaCheckPermission("zsjy:internshipmonthly:list")
|
||||
@GetMapping("/internship/{internshipId}")
|
||||
public R<List<ZsjyInternshipMonthlyVo>> listByInternship(@Parameter(description = "实习ID")
|
||||
@PathVariable Long internshipId) {
|
||||
log.info("查询实习月度总结列表, 实习ID: {}", internshipId);
|
||||
|
||||
List<ZsjyInternshipMonthlyVo> list = monthlyService.queryByStudentAndInternship(null, internshipId);
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计学生各状态的总结数量
|
||||
*/
|
||||
@Operation(summary = "统计学生各状态的总结数量", description = "统计学生草稿、待审核、已审核等状态的总结数量")
|
||||
@SaCheckPermission("zsjy:internshipmonthly:statistics")
|
||||
@GetMapping("/statistics")
|
||||
public R<List<Object>> statistics() {
|
||||
log.info("统计学生月度总结状态");
|
||||
|
||||
List<Object> statistics = monthlyService.countByStatus(null);
|
||||
return R.ok(statistics);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取学生当前实习信息
|
||||
*/
|
||||
@Operation(summary = "获取学生当前实习信息", description = "获取当前登录学生的进行中实习信息")
|
||||
@SaCheckPermission("zsjy:internshipmonthly:add")
|
||||
@GetMapping("/current-internship")
|
||||
public R<Map<String, Object>> getCurrentInternship() {
|
||||
log.info("获取学生当前实习信息");
|
||||
|
||||
Map<String, Object> internshipInfo = monthlyService.getCurrentInternshipInfo();
|
||||
if (internshipInfo == null || internshipInfo.isEmpty()) {
|
||||
return R.fail("您当前没有进行中的实习记录");
|
||||
}
|
||||
|
||||
return R.ok(internshipInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出学生月度实习总结
|
||||
*/
|
||||
@Operation(summary = "导出学生月度实习总结", description = "导出学生的月度总结数据")
|
||||
@SaCheckPermission("zsjy:internshipmonthly:export")
|
||||
@Log(title = "学生月度实习总结", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(@RequestBody ZsjyInternshipMonthlyQueryBo queryBo, HttpServletResponse response) {
|
||||
log.info("导出月度总结: {}", queryBo);
|
||||
|
||||
List<ZsjyInternshipMonthlyVo> list = monthlyService.queryList(queryBo);
|
||||
ExcelUtil.exportExcel(list, "学生月度实习总结", ZsjyInternshipMonthlyVo.class, response);
|
||||
}
|
||||
|
||||
}
|
||||
+7
@@ -1,6 +1,7 @@
|
||||
package org.dromara.zsjy.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@@ -159,5 +160,11 @@ public class ZsjyInternshipInfo extends BaseEntity {
|
||||
* 实习状态(1进行中 2已完成 3中断)
|
||||
*/
|
||||
private String internshipStatus;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
@TableLogic(value = "0", delval = "1")
|
||||
private Long deleted;
|
||||
}
|
||||
|
||||
+191
@@ -0,0 +1,191 @@
|
||||
package org.dromara.zsjy.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 学生月度实习总结实体对象 zsjy_internship_monthly
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("zsjy_internship_monthly")
|
||||
public class ZsjyInternshipMonthly extends BaseEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 月度总结ID (对应数据库monthly_id字段)
|
||||
*/
|
||||
@TableId(value = "monthly_id", type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
@TableField("tenant_id")
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 实习ID
|
||||
*/
|
||||
@TableField("internship_id")
|
||||
private Long internshipId;
|
||||
|
||||
/**
|
||||
* 学生ID
|
||||
*/
|
||||
@TableField("student_id")
|
||||
private Long studentId;
|
||||
|
||||
/**
|
||||
* 总结月份 (格式: 2025-01)
|
||||
*/
|
||||
@TableField("summary_month")
|
||||
private String summaryMonth;
|
||||
|
||||
/**
|
||||
* 月份序号 (1-12)
|
||||
*/
|
||||
@TableField("month_number")
|
||||
private Integer monthNumber;
|
||||
|
||||
/**
|
||||
* 工作内容 (必填,500字以内)
|
||||
*/
|
||||
@TableField("work_content")
|
||||
private String workContent;
|
||||
|
||||
/**
|
||||
* 主要成果
|
||||
*/
|
||||
@TableField("achievements")
|
||||
private String achievements;
|
||||
|
||||
/**
|
||||
* 学习收获
|
||||
*/
|
||||
@TableField("learning_gains")
|
||||
private String learningGains;
|
||||
|
||||
/**
|
||||
* 遇到的问题
|
||||
*/
|
||||
@TableField("problems_encountered")
|
||||
private String problemsEncountered;
|
||||
|
||||
/**
|
||||
* 自我评价
|
||||
*/
|
||||
@TableField("self_evaluation")
|
||||
private String selfEvaluation;
|
||||
|
||||
/**
|
||||
* 下月工作计划
|
||||
*/
|
||||
@TableField("next_month_plan")
|
||||
private String nextMonthPlan;
|
||||
|
||||
/**
|
||||
* 专业技能自评 (1-10分)
|
||||
*/
|
||||
@TableField("professional_skills")
|
||||
private Integer professionalSkills;
|
||||
|
||||
/**
|
||||
* 沟通技能自评 (1-10分)
|
||||
*/
|
||||
@TableField("communication_skills")
|
||||
private Integer communicationSkills;
|
||||
|
||||
/**
|
||||
* 团队协作自评 (1-10分) - 修正字段映射
|
||||
*/
|
||||
@TableField("teamwork_ability")
|
||||
private Integer teamworkAbility;
|
||||
|
||||
/**
|
||||
* 学习能力自评 (1-10分)
|
||||
*/
|
||||
@TableField("learning_ability")
|
||||
private Integer learningAbility;
|
||||
|
||||
/**
|
||||
* 工作态度自评 (1-10分)
|
||||
*/
|
||||
@TableField("work_attitude")
|
||||
private Integer workAttitude;
|
||||
|
||||
/**
|
||||
* 审核状态 (0:待审核 1:已审核 2:审核拒绝 3:草稿) - 修正字段映射
|
||||
*/
|
||||
@TableField("review_status")
|
||||
private Integer reviewStatus;
|
||||
|
||||
/**
|
||||
* 审核人ID - 修正字段映射
|
||||
*/
|
||||
@TableField("review_by")
|
||||
private Long reviewBy;
|
||||
|
||||
/**
|
||||
* 审核时间
|
||||
*/
|
||||
@TableField("review_time")
|
||||
private Date reviewTime;
|
||||
|
||||
/**
|
||||
* 审核评分 (百分制)
|
||||
*/
|
||||
@TableField("review_score")
|
||||
private BigDecimal reviewScore;
|
||||
|
||||
/**
|
||||
* 审核意见 - 修正字段映射
|
||||
*/
|
||||
@TableField("review_comment")
|
||||
private String reviewComment;
|
||||
|
||||
/**
|
||||
* 提交时间
|
||||
*/
|
||||
@TableField("submit_time")
|
||||
private Date submitTime;
|
||||
|
||||
/**
|
||||
* 字数统计
|
||||
*/
|
||||
@TableField("word_count")
|
||||
private Integer wordCount;
|
||||
|
||||
/**
|
||||
* 是否逾期 (0:未逾期 1:已逾期)
|
||||
*/
|
||||
@TableField("is_overdue")
|
||||
private Integer isOverdue;
|
||||
|
||||
/**
|
||||
* 提交截止日期 - 修正字段映射
|
||||
*/
|
||||
@TableField("submit_deadline")
|
||||
private Date submitDeadline;
|
||||
|
||||
/**
|
||||
* 附件信息 (JSON格式存储)
|
||||
*/
|
||||
@TableField("attachments")
|
||||
private String attachments;
|
||||
|
||||
}
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
package org.dromara.zsjy.domain.bo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
import jakarta.validation.constraints.*;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 学生月度实习总结新增/编辑对象 ZsjyInternshipMonthlyAddBo
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "学生月度实习总结新增/编辑对象")
|
||||
public class ZsjyInternshipMonthlyAddBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 月度总结ID
|
||||
*/
|
||||
@Schema(description = "月度总结ID")
|
||||
@NotNull(message = "月度总结ID不能为空", groups = { EditGroup.class })
|
||||
private Long monthlyId;
|
||||
|
||||
/**
|
||||
* 实习ID
|
||||
*/
|
||||
@Schema(description = "实习ID")
|
||||
@NotNull(message = "实习ID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long internshipId;
|
||||
|
||||
/**
|
||||
* 总结月份 (格式: 2025-01)
|
||||
*/
|
||||
@Schema(description = "总结月份")
|
||||
@NotBlank(message = "总结月份不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@Pattern(regexp = "^\\d{4}-\\d{2}$", message = "月份格式应为 YYYY-MM", groups = { AddGroup.class, EditGroup.class })
|
||||
private String summaryMonth;
|
||||
|
||||
/**
|
||||
* 工作内容 (必填,500字以内)
|
||||
*/
|
||||
@Schema(description = "工作内容")
|
||||
@NotBlank(message = "工作内容不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@Size(max = 500, message = "工作内容不能超过500字", groups = { AddGroup.class, EditGroup.class })
|
||||
private String workContent;
|
||||
|
||||
/**
|
||||
* 主要成果
|
||||
*/
|
||||
@Schema(description = "主要成果")
|
||||
@Size(max = 500, message = "主要成果不能超过500字", groups = { AddGroup.class, EditGroup.class })
|
||||
private String achievements;
|
||||
|
||||
/**
|
||||
* 学习收获
|
||||
*/
|
||||
@Schema(description = "学习收获")
|
||||
@Size(max = 500, message = "学习收获不能超过500字", groups = { AddGroup.class, EditGroup.class })
|
||||
private String learningGains;
|
||||
|
||||
/**
|
||||
* 遇到的问题(包含解决方案,按2-A方案合并)
|
||||
*/
|
||||
@Schema(description = "遇到的问题")
|
||||
@Size(max = 1000, message = "遇到的问题不能超过1000字", groups = { AddGroup.class, EditGroup.class })
|
||||
private String problemsEncountered;
|
||||
|
||||
/**
|
||||
* 自我评价
|
||||
*/
|
||||
@Schema(description = "自我评价")
|
||||
@Size(max = 500, message = "自我评价不能超过500字", groups = { AddGroup.class, EditGroup.class })
|
||||
private String selfEvaluation;
|
||||
|
||||
/**
|
||||
* 下月工作计划
|
||||
*/
|
||||
@Schema(description = "下月工作计划")
|
||||
@Size(max = 500, message = "下月工作计划不能超过500字", groups = { AddGroup.class, EditGroup.class })
|
||||
private String nextMonthPlan;
|
||||
|
||||
/**
|
||||
* 专业技能自评 (1-10分)
|
||||
*/
|
||||
@Schema(description = "专业技能自评")
|
||||
@Min(value = 1, message = "专业技能自评最小值为1", groups = { AddGroup.class, EditGroup.class })
|
||||
@Max(value = 10, message = "专业技能自评最大值为10", groups = { AddGroup.class, EditGroup.class })
|
||||
private Integer professionalSkills;
|
||||
|
||||
/**
|
||||
* 沟通技能自评 (1-10分)
|
||||
*/
|
||||
@Schema(description = "沟通技能自评")
|
||||
@Min(value = 1, message = "沟通技能自评最小值为1", groups = { AddGroup.class, EditGroup.class })
|
||||
@Max(value = 10, message = "沟通技能自评最大值为10", groups = { AddGroup.class, EditGroup.class })
|
||||
private Integer communicationSkills;
|
||||
|
||||
/**
|
||||
* 团队协作自评 (1-10分) - 修正字段映射
|
||||
*/
|
||||
@Schema(description = "团队协作自评")
|
||||
@Min(value = 1, message = "团队协作自评最小值为1", groups = { AddGroup.class, EditGroup.class })
|
||||
@Max(value = 10, message = "团队协作自评最大值为10", groups = { AddGroup.class, EditGroup.class })
|
||||
private Integer teamworkAbility;
|
||||
|
||||
/**
|
||||
* 学习能力自评 (1-10分)
|
||||
*/
|
||||
@Schema(description = "学习能力自评")
|
||||
@Min(value = 1, message = "学习能力自评最小值为1", groups = { AddGroup.class, EditGroup.class })
|
||||
@Max(value = 10, message = "学习能力自评最大值为10", groups = { AddGroup.class, EditGroup.class })
|
||||
private Integer learningAbility;
|
||||
|
||||
/**
|
||||
* 工作态度自评 (1-10分)
|
||||
*/
|
||||
@Schema(description = "工作态度自评")
|
||||
@Min(value = 1, message = "工作态度自评最小值为1", groups = { AddGroup.class, EditGroup.class })
|
||||
@Max(value = 10, message = "工作态度自评最大值为10", groups = { AddGroup.class, EditGroup.class })
|
||||
private Integer workAttitude;
|
||||
|
||||
/**
|
||||
* 附件信息 (JSON格式存储)
|
||||
*/
|
||||
@Schema(description = "附件信息")
|
||||
private String attachments;
|
||||
|
||||
/**
|
||||
* 审核状态 (0-待审核 1-已审核 2-审核拒绝 3-草稿)
|
||||
*/
|
||||
@Schema(description = "审核状态")
|
||||
private Integer reviewStatus;
|
||||
|
||||
/**
|
||||
* 提交时间
|
||||
*/
|
||||
@Schema(description = "提交时间")
|
||||
private Date submitTime;
|
||||
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* 学生月度实习总结查询对象 ZsjyInternshipMonthlyQueryBo
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "学生月度实习总结查询对象")
|
||||
public class ZsjyInternshipMonthlyQueryBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 学生ID
|
||||
*/
|
||||
@Schema(description = "学生ID")
|
||||
private Long studentId;
|
||||
|
||||
/**
|
||||
* 总结月份 (格式: 2025-01)
|
||||
*/
|
||||
@Schema(description = "总结月份")
|
||||
private String summaryMonth;
|
||||
|
||||
/**
|
||||
* 审核状态 (0:待审核 1:已审核 2:审核拒绝 3:草稿)
|
||||
*/
|
||||
@Schema(description = "审核状态")
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 实习ID
|
||||
*/
|
||||
@Schema(description = "实习ID")
|
||||
private Long internshipId;
|
||||
|
||||
/**
|
||||
* 是否逾期 (0:未逾期 1:已逾期)
|
||||
*/
|
||||
@Schema(description = "是否逾期")
|
||||
private Integer isOverdue;
|
||||
|
||||
/**
|
||||
* 开始月份
|
||||
*/
|
||||
@Schema(description = "开始月份")
|
||||
private String startMonth;
|
||||
|
||||
/**
|
||||
* 结束月份
|
||||
*/
|
||||
@Schema(description = "结束月份")
|
||||
private String endMonth;
|
||||
|
||||
}
|
||||
+253
@@ -0,0 +1,253 @@
|
||||
package org.dromara.zsjy.domain.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 学生月度实习总结视图对象 ZsjyInternshipMonthlyVo
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "学生月度实习总结视图对象")
|
||||
public class ZsjyInternshipMonthlyVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 月度总结ID
|
||||
*/
|
||||
@Schema(description = "月度总结ID")
|
||||
private Long monthlyId;
|
||||
|
||||
/**
|
||||
* 实习ID
|
||||
*/
|
||||
@Schema(description = "实习ID")
|
||||
private Long internshipId;
|
||||
|
||||
/**
|
||||
* 学生ID
|
||||
*/
|
||||
@Schema(description = "学生ID")
|
||||
private Long studentId;
|
||||
|
||||
/**
|
||||
* 学生姓名 - 通过关联查询获取
|
||||
*/
|
||||
@Schema(description = "学生姓名")
|
||||
private String studentName;
|
||||
|
||||
/**
|
||||
* 学生学号 - 通过关联查询获取
|
||||
*/
|
||||
@Schema(description = "学生学号")
|
||||
private String studentNumber;
|
||||
|
||||
/**
|
||||
* 总结月份 (格式: 2025-01)
|
||||
*/
|
||||
@Schema(description = "总结月份")
|
||||
private String summaryMonth;
|
||||
|
||||
/**
|
||||
* 月份序号 (1-12)
|
||||
*/
|
||||
@Schema(description = "月份序号")
|
||||
private Integer monthNumber;
|
||||
|
||||
/**
|
||||
* 工作内容
|
||||
*/
|
||||
@Schema(description = "工作内容")
|
||||
private String workContent;
|
||||
|
||||
/**
|
||||
* 主要成果
|
||||
*/
|
||||
@Schema(description = "主要成果")
|
||||
private String achievements;
|
||||
|
||||
/**
|
||||
* 学习收获
|
||||
*/
|
||||
@Schema(description = "学习收获")
|
||||
private String learningGains;
|
||||
|
||||
/**
|
||||
* 遇到的问题(包含解决方案,按2-A方案合并)
|
||||
*/
|
||||
@Schema(description = "遇到的问题")
|
||||
private String problemsEncountered;
|
||||
|
||||
/**
|
||||
* 自我评价
|
||||
*/
|
||||
@Schema(description = "自我评价")
|
||||
private String selfEvaluation;
|
||||
|
||||
/**
|
||||
* 下月工作计划
|
||||
*/
|
||||
@Schema(description = "下月工作计划")
|
||||
private String nextMonthPlan;
|
||||
|
||||
/**
|
||||
* 专业技能自评 (1-10分)
|
||||
*/
|
||||
@Schema(description = "专业技能自评")
|
||||
private Integer professionalSkills;
|
||||
|
||||
/**
|
||||
* 沟通技能自评 (1-10分)
|
||||
*/
|
||||
@Schema(description = "沟通技能自评")
|
||||
private Integer communicationSkills;
|
||||
|
||||
/**
|
||||
* 团队协作自评 (1-10分) - 修正字段映射
|
||||
*/
|
||||
@Schema(description = "团队协作自评")
|
||||
private Integer teamworkAbility;
|
||||
|
||||
/**
|
||||
* 学习能力自评 (1-10分)
|
||||
*/
|
||||
@Schema(description = "学习能力自评")
|
||||
private Integer learningAbility;
|
||||
|
||||
/**
|
||||
* 工作态度自评 (1-10分)
|
||||
*/
|
||||
@Schema(description = "工作态度自评")
|
||||
private Integer workAttitude;
|
||||
|
||||
/**
|
||||
* 审核状态 (0:待审核 1:已审核 2:审核拒绝 3:草稿) - 修正字段映射
|
||||
*/
|
||||
@Schema(description = "审核状态")
|
||||
private Integer reviewStatus;
|
||||
|
||||
/**
|
||||
* 状态文本描述
|
||||
*/
|
||||
@Schema(description = "状态文本描述")
|
||||
private String statusText;
|
||||
|
||||
/**
|
||||
* 审核人ID - 修正字段映射
|
||||
*/
|
||||
@Schema(description = "审核人ID")
|
||||
private Long reviewBy;
|
||||
|
||||
/**
|
||||
* 审核人姓名 - 通过关联查询获取
|
||||
*/
|
||||
@Schema(description = "审核人姓名")
|
||||
private String reviewerName;
|
||||
|
||||
/**
|
||||
* 审核时间
|
||||
*/
|
||||
@Schema(description = "审核时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date reviewTime;
|
||||
|
||||
/**
|
||||
* 审核评分 (百分制)
|
||||
*/
|
||||
@Schema(description = "审核评分")
|
||||
private BigDecimal reviewScore;
|
||||
|
||||
/**
|
||||
* 审核意见 - 修正字段映射
|
||||
*/
|
||||
@Schema(description = "审核意见")
|
||||
private String reviewComment;
|
||||
|
||||
/**
|
||||
* 提交时间
|
||||
*/
|
||||
@Schema(description = "提交时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date submitTime;
|
||||
|
||||
/**
|
||||
* 字数统计
|
||||
*/
|
||||
@Schema(description = "字数统计")
|
||||
private Integer wordCount;
|
||||
|
||||
/**
|
||||
* 是否逾期 (0:未逾期 1:已逾期)
|
||||
*/
|
||||
@Schema(description = "是否逾期")
|
||||
private Integer isOverdue;
|
||||
|
||||
/**
|
||||
* 提交截止日期 - 修正字段映射
|
||||
*/
|
||||
@Schema(description = "提交截止日期")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date submitDeadline;
|
||||
|
||||
/**
|
||||
* 附件信息
|
||||
*/
|
||||
@Schema(description = "附件信息")
|
||||
private String attachments;
|
||||
|
||||
/**
|
||||
* 是否可编辑 (草稿状态才可编辑)
|
||||
*/
|
||||
@Schema(description = "是否可编辑")
|
||||
private Boolean editable;
|
||||
|
||||
/**
|
||||
* 是否可删除 (草稿状态才可删除)
|
||||
*/
|
||||
@Schema(description = "是否可删除")
|
||||
private Boolean deletable;
|
||||
|
||||
/**
|
||||
* 是否可提交 (草稿状态才可提交)
|
||||
*/
|
||||
@Schema(description = "是否可提交")
|
||||
private Boolean submittable;
|
||||
|
||||
// VO类基础字段规范 - 必须包含的四个字段
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
@Schema(description = "创建者")
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@Schema(description = "创建时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
@Schema(description = "更新者")
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@Schema(description = "更新时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
package org.dromara.zsjy.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
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.vo.ZsjyInternshipMonthlyVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 学生月度实习总结Mapper接口
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
public interface ZsjyInternshipMonthlyMapper extends BaseMapper<ZsjyInternshipMonthly> {
|
||||
|
||||
/**
|
||||
* 查询学生月度实习总结
|
||||
*
|
||||
* @param monthlyId 月度总结ID
|
||||
* @return 学生月度实习总结
|
||||
*/
|
||||
ZsjyInternshipMonthlyVo selectVoById(Long monthlyId);
|
||||
|
||||
/**
|
||||
* 查询学生月度实习总结列表
|
||||
*
|
||||
* @param queryBo 查询条件
|
||||
* @return 学生月度实习总结集合
|
||||
*/
|
||||
Page<ZsjyInternshipMonthlyVo> selectVoPage(Page<ZsjyInternshipMonthlyVo> page, @Param("bo") ZsjyInternshipMonthlyQueryBo queryBo);
|
||||
|
||||
/**
|
||||
* 查询学生月度实习总结列表
|
||||
*
|
||||
* @param queryBo 查询条件
|
||||
* @return 学生月度实习总结集合
|
||||
*/
|
||||
List<ZsjyInternshipMonthlyVo> selectVoList(@Param("bo") ZsjyInternshipMonthlyQueryBo queryBo);
|
||||
|
||||
/**
|
||||
* 检查学生某月是否已有总结
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @param summaryMonth 总结月份
|
||||
* @param monthlyId 排除的总结ID(用于编辑时检查)
|
||||
* @return 是否存在
|
||||
*/
|
||||
boolean existsByStudentAndMonth(@Param("studentId") Long studentId,
|
||||
@Param("summaryMonth") String summaryMonth,
|
||||
@Param("monthlyId") Long monthlyId);
|
||||
|
||||
/**
|
||||
* 批量删除学生月度实习总结
|
||||
*
|
||||
* @param monthlyIds 需要删除的数据ID
|
||||
* @return 影响行数
|
||||
*/
|
||||
int deleteByIds(@Param("monthlyIds") Long[] monthlyIds);
|
||||
|
||||
/**
|
||||
* 查询学生指定实习的月度总结列表
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @param internshipId 实习ID
|
||||
* @return 月度总结列表
|
||||
*/
|
||||
List<ZsjyInternshipMonthlyVo> selectByStudentAndInternship(@Param("studentId") Long studentId,
|
||||
@Param("internshipId") Long internshipId);
|
||||
|
||||
/**
|
||||
* 统计学生各状态的总结数量
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @return 状态统计结果
|
||||
*/
|
||||
List<Object> countByStatus(@Param("studentId") Long studentId);
|
||||
|
||||
}
|
||||
+7
@@ -98,4 +98,11 @@ public interface IInternshipInfoService {
|
||||
* @return 是否成功
|
||||
*/
|
||||
Boolean deleteInternshipInfo(Long[] internshipIds);
|
||||
|
||||
/**
|
||||
* 获取当前学生的实习信息
|
||||
*
|
||||
* @return 当前学生的实习信息,如果没有则返回null
|
||||
*/
|
||||
InternshipInfoVO getCurrentStudentInternship();
|
||||
}
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
package org.dromara.zsjy.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.zsjy.domain.bo.ZsjyInternshipMonthlyAddBo;
|
||||
import org.dromara.zsjy.domain.bo.ZsjyInternshipMonthlyQueryBo;
|
||||
import org.dromara.zsjy.domain.vo.ZsjyInternshipMonthlyVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 学生月度实习总结Service接口
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
public interface IZsjyInternshipMonthlyService {
|
||||
|
||||
/**
|
||||
* 查询学生月度实习总结
|
||||
*
|
||||
* @param monthlyId 月度总结ID
|
||||
* @return 学生月度实习总结
|
||||
*/
|
||||
ZsjyInternshipMonthlyVo queryById(Long monthlyId);
|
||||
|
||||
/**
|
||||
* 查询学生月度实习总结列表
|
||||
*
|
||||
* @param queryBo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 学生月度实习总结分页结果
|
||||
*/
|
||||
TableDataInfo<ZsjyInternshipMonthlyVo> queryPageList(ZsjyInternshipMonthlyQueryBo queryBo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询学生月度实习总结列表
|
||||
*
|
||||
* @param queryBo 查询条件
|
||||
* @return 学生月度实习总结集合
|
||||
*/
|
||||
List<ZsjyInternshipMonthlyVo> queryList(ZsjyInternshipMonthlyQueryBo queryBo);
|
||||
|
||||
/**
|
||||
* 新增学生月度实习总结
|
||||
*
|
||||
* @param addBo 学生月度实习总结
|
||||
* @return 新增结果
|
||||
*/
|
||||
Boolean insertByBo(ZsjyInternshipMonthlyAddBo addBo);
|
||||
|
||||
/**
|
||||
* 修改学生月度实习总结
|
||||
*
|
||||
* @param addBo 学生月度实习总结
|
||||
* @return 修改结果
|
||||
*/
|
||||
Boolean updateByBo(ZsjyInternshipMonthlyAddBo addBo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除学生月度实习总结信息
|
||||
*
|
||||
* @param ids 需要删除的学生月度实习总结ID
|
||||
* @return 删除结果
|
||||
*/
|
||||
Boolean deleteByIds(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 提交月度总结审批
|
||||
*
|
||||
* @param monthlyId 月度总结ID
|
||||
* @return 提交结果
|
||||
*/
|
||||
Boolean submitForApproval(Long monthlyId);
|
||||
|
||||
/**
|
||||
* 自动保存草稿
|
||||
*
|
||||
* @param addBo 学生月度实习总结
|
||||
* @return 保存结果
|
||||
*/
|
||||
Boolean autoSaveDraft(ZsjyInternshipMonthlyAddBo addBo);
|
||||
|
||||
/**
|
||||
* 检查学生某月是否已有总结
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @param summaryMonth 总结月份
|
||||
* @param monthlyId 排除的总结ID(用于编辑时检查)
|
||||
* @return 是否存在
|
||||
*/
|
||||
Boolean checkMonthExists(Long studentId, String summaryMonth, Long monthlyId);
|
||||
|
||||
/**
|
||||
* 获取月度总结模板信息
|
||||
*
|
||||
* @param summaryMonth 总结月份
|
||||
* @return 模板信息
|
||||
*/
|
||||
ZsjyInternshipMonthlyVo getMonthlyTemplate(String summaryMonth);
|
||||
|
||||
/**
|
||||
* 查询学生指定实习的月度总结列表
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @param internshipId 实习ID
|
||||
* @return 月度总结列表
|
||||
*/
|
||||
List<ZsjyInternshipMonthlyVo> queryByStudentAndInternship(Long studentId, Long internshipId);
|
||||
|
||||
/**
|
||||
* 统计学生各状态的总结数量
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @return 状态统计结果
|
||||
*/
|
||||
List<Object> countByStatus(Long studentId);
|
||||
|
||||
/**
|
||||
* 计算总结内容字数
|
||||
*
|
||||
* @param addBo 总结内容
|
||||
* @return 字数统计
|
||||
*/
|
||||
Integer calculateWordCount(ZsjyInternshipMonthlyAddBo addBo);
|
||||
|
||||
/**
|
||||
* 获取学生当前实习信息
|
||||
*
|
||||
* @return 当前实习信息
|
||||
*/
|
||||
Map<String, Object> getCurrentInternshipInfo();
|
||||
|
||||
}
|
||||
+49
@@ -459,4 +459,53 @@ public class InternshipInfoServiceImpl implements IInternshipInfoService {
|
||||
}
|
||||
return studentInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前学生的实习信息
|
||||
*
|
||||
* @return 当前学生的实习信息,如果没有则返回null
|
||||
*/
|
||||
@Override
|
||||
public InternshipInfoVO getCurrentStudentInternship() {
|
||||
log.info("开始获取当前学生的实习信息");
|
||||
|
||||
// 获取当前登录用户ID
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
log.info("当前登录用户ID:{}", currentUserId);
|
||||
|
||||
if (currentUserId == null) {
|
||||
log.error("当前用户未登录");
|
||||
throw new ServiceException("用户未登录");
|
||||
}
|
||||
|
||||
// 根据用户ID查询实习信息
|
||||
LambdaQueryWrapper<ZsjyInternshipInfo> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(ZsjyInternshipInfo::getStudentId, currentUserId)
|
||||
.eq(ZsjyInternshipInfo::getDeleted, 0)
|
||||
.orderByDesc(ZsjyInternshipInfo::getCreateTime)
|
||||
.last("LIMIT 1"); // 只取最新的一条记录
|
||||
|
||||
ZsjyInternshipInfo internshipInfo = zsjyInternshipInfoMapper.selectOne(wrapper);
|
||||
log.info("查询到的实习信息:{}", internshipInfo != null ? internshipInfo.getInternshipId() : "无");
|
||||
|
||||
if (internshipInfo == null) {
|
||||
log.info("当前学生没有实习信息");
|
||||
return null;
|
||||
}
|
||||
|
||||
// 转换为VO
|
||||
InternshipInfoVO vo = BeanUtil.toBean(internshipInfo, InternshipInfoVO.class);
|
||||
|
||||
// 查询学生信息并设置到VO中
|
||||
XgStudentMsgVo studentInfo = getStudentInfo(currentUserId);
|
||||
vo.setStudentName(studentInfo.getName());
|
||||
vo.setStudentNo(studentInfo.getStudentNo());
|
||||
vo.setClassName(studentInfo.getClassName());
|
||||
vo.setMajorName(studentInfo.getMajorName());
|
||||
vo.setCollegeName(studentInfo.getCollegeName());
|
||||
vo.setGrade(studentInfo.getGrade());
|
||||
|
||||
log.info("成功获取当前学生实习信息,实习ID:{}", vo.getInternshipId());
|
||||
return vo;
|
||||
}
|
||||
}
|
||||
+465
@@ -0,0 +1,465 @@
|
||||
package org.dromara.zsjy.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
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.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.zsjy.domain.ZsjyInternshipMonthly;
|
||||
import org.dromara.zsjy.domain.bo.ZsjyInternshipMonthlyAddBo;
|
||||
import org.dromara.zsjy.domain.bo.ZsjyInternshipMonthlyQueryBo;
|
||||
import org.dromara.zsjy.domain.vo.ZsjyInternshipMonthlyVo;
|
||||
import org.dromara.zsjy.mapper.ZsjyInternshipMonthlyMapper;
|
||||
import org.dromara.zsjy.mapper.ZsjyInternshipInfoMapper;
|
||||
import org.dromara.zsjy.domain.ZsjyInternshipInfo;
|
||||
import org.dromara.zsjy.service.IZsjyInternshipMonthlyService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.YearMonth;
|
||||
import java.util.*;
|
||||
import java.time.ZoneId;
|
||||
|
||||
/**
|
||||
* 学生月度实习总结Service业务层处理
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class ZsjyInternshipMonthlyServiceImpl implements IZsjyInternshipMonthlyService {
|
||||
|
||||
private final ZsjyInternshipMonthlyMapper baseMapper;
|
||||
private final ZsjyInternshipInfoMapper internshipInfoMapper;
|
||||
|
||||
/**
|
||||
* 查询学生月度实习总结
|
||||
*/
|
||||
@Override
|
||||
public ZsjyInternshipMonthlyVo queryById(Long monthlyId) {
|
||||
ZsjyInternshipMonthlyVo vo = baseMapper.selectVoById(monthlyId);
|
||||
if (ObjectUtil.isNull(vo)) {
|
||||
throw new ServiceException("月度总结不存在");
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询学生月度实习总结分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<ZsjyInternshipMonthlyVo> queryPageList(ZsjyInternshipMonthlyQueryBo queryBo, PageQuery pageQuery) {
|
||||
// 如果没有指定学生ID,则使用当前登录用户ID(学生端)
|
||||
if (ObjectUtil.isNull(queryBo.getStudentId())) {
|
||||
queryBo.setStudentId(LoginHelper.getUserId());
|
||||
}
|
||||
|
||||
Page<ZsjyInternshipMonthlyVo> result = baseMapper.selectVoPage(pageQuery.build(), queryBo);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询学生月度实习总结列表
|
||||
*/
|
||||
@Override
|
||||
public List<ZsjyInternshipMonthlyVo> queryList(ZsjyInternshipMonthlyQueryBo queryBo) {
|
||||
// 如果没有指定学生ID,则使用当前登录用户ID(学生端)
|
||||
if (ObjectUtil.isNull(queryBo.getStudentId())) {
|
||||
queryBo.setStudentId(LoginHelper.getUserId());
|
||||
}
|
||||
return baseMapper.selectVoList(queryBo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增学生月度实习总结
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean insertByBo(ZsjyInternshipMonthlyAddBo addBo) {
|
||||
Long studentId = LoginHelper.getUserId();
|
||||
|
||||
// 如果前端没有传递实习ID,则自动获取当前学生的实习ID
|
||||
if (ObjectUtil.isNull(addBo.getInternshipId())) {
|
||||
ZsjyInternshipInfo internshipInfo = internshipInfoMapper.selectOne(
|
||||
new LambdaQueryWrapper<ZsjyInternshipInfo>()
|
||||
.eq(ZsjyInternshipInfo::getStudentId, studentId)
|
||||
.eq(ZsjyInternshipInfo::getStatus, "1") // 查询进行中状态的实习
|
||||
.eq(ZsjyInternshipInfo::getDeleted, 0)
|
||||
.orderByDesc(ZsjyInternshipInfo::getCreateTime)
|
||||
.last("LIMIT 1")
|
||||
);
|
||||
|
||||
if (ObjectUtil.isNull(internshipInfo)) {
|
||||
throw new ServiceException("您当前没有进行中的实习记录,无法创建月度总结");
|
||||
}
|
||||
|
||||
addBo.setInternshipId(internshipInfo.getInternshipId());
|
||||
log.info("自动获取到学生实习ID:{}", internshipInfo.getInternshipId());
|
||||
}
|
||||
|
||||
// 检查该学生该月份是否已有总结
|
||||
if (checkMonthExists(studentId, addBo.getSummaryMonth(), null)) {
|
||||
throw new ServiceException("该月份已存在总结记录,请勿重复创建");
|
||||
}
|
||||
|
||||
// 手动转换BO到实体,解决字段映射问题
|
||||
ZsjyInternshipMonthly add = new ZsjyInternshipMonthly();
|
||||
add.setId(addBo.getMonthlyId()); // monthlyId -> id
|
||||
add.setInternshipId(addBo.getInternshipId());
|
||||
add.setSummaryMonth(addBo.getSummaryMonth());
|
||||
add.setWorkContent(addBo.getWorkContent());
|
||||
add.setAchievements(addBo.getAchievements());
|
||||
add.setLearningGains(addBo.getLearningGains());
|
||||
add.setProblemsEncountered(addBo.getProblemsEncountered());
|
||||
add.setSelfEvaluation(addBo.getSelfEvaluation());
|
||||
add.setNextMonthPlan(addBo.getNextMonthPlan());
|
||||
add.setProfessionalSkills(addBo.getProfessionalSkills());
|
||||
add.setCommunicationSkills(addBo.getCommunicationSkills());
|
||||
add.setTeamworkAbility(addBo.getTeamworkAbility());
|
||||
add.setLearningAbility(addBo.getLearningAbility());
|
||||
add.setWorkAttitude(addBo.getWorkAttitude());
|
||||
add.setAttachments(addBo.getAttachments());
|
||||
|
||||
add.setStudentId(studentId);
|
||||
add.setTenantId("000000"); // 默认租户
|
||||
|
||||
// 处理审核状态和提交时间
|
||||
if (addBo.getReviewStatus() != null) {
|
||||
add.setReviewStatus(addBo.getReviewStatus());
|
||||
// 如果状态为待审核(0),设置提交时间
|
||||
if (addBo.getReviewStatus() == 0) {
|
||||
add.setSubmitTime(addBo.getSubmitTime() != null ? addBo.getSubmitTime() : new Date());
|
||||
}
|
||||
} else {
|
||||
add.setReviewStatus(3); // 默认为草稿状态
|
||||
}
|
||||
|
||||
// 解析月份序号
|
||||
if (StringUtils.isNotBlank(addBo.getSummaryMonth())) {
|
||||
String[] parts = addBo.getSummaryMonth().split("-");
|
||||
if (parts.length == 2) {
|
||||
add.setMonthNumber(Integer.parseInt(parts[1]));
|
||||
}
|
||||
}
|
||||
|
||||
// 计算字数
|
||||
add.setWordCount(calculateWordCount(addBo));
|
||||
|
||||
// 设置默认截止日期(下月5号)
|
||||
try {
|
||||
YearMonth ym = YearMonth.parse(addBo.getSummaryMonth());
|
||||
add.setSubmitDeadline(Date.from(ym.plusMonths(1).atDay(5).atStartOfDay(ZoneId.systemDefault()).toInstant()));
|
||||
} catch (Exception e) {
|
||||
log.warn("解析月份失败: {}", addBo.getSummaryMonth());
|
||||
}
|
||||
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
addBo.setMonthlyId(add.getId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改学生月度实习总结
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean updateByBo(ZsjyInternshipMonthlyAddBo addBo) {
|
||||
Long studentId = LoginHelper.getUserId();
|
||||
|
||||
// 查询原记录,验证权限和状态
|
||||
ZsjyInternshipMonthly original = baseMapper.selectById(addBo.getMonthlyId());
|
||||
if (ObjectUtil.isNull(original)) {
|
||||
throw new ServiceException("月度总结不存在");
|
||||
}
|
||||
|
||||
// 权限检查:只能修改自己的总结
|
||||
if (!Objects.equals(original.getStudentId(), studentId)) {
|
||||
throw new ServiceException("您只能修改自己的月度总结");
|
||||
}
|
||||
|
||||
// 状态检查:只有草稿状态才能修改
|
||||
if (!Objects.equals(original.getReviewStatus(), 3)) {
|
||||
throw new ServiceException("只有草稿状态的总结才能修改");
|
||||
}
|
||||
|
||||
// 如果前端没有传递实习ID,则使用原记录的实习ID
|
||||
if (ObjectUtil.isNull(addBo.getInternshipId())) {
|
||||
addBo.setInternshipId(original.getInternshipId());
|
||||
log.info("使用原记录的实习ID:{}", original.getInternshipId());
|
||||
}
|
||||
|
||||
// 检查月份是否被其他记录占用
|
||||
if (!Objects.equals(original.getSummaryMonth(), addBo.getSummaryMonth())) {
|
||||
if (checkMonthExists(studentId, addBo.getSummaryMonth(), addBo.getMonthlyId())) {
|
||||
throw new ServiceException("该月份已存在其他总结记录");
|
||||
}
|
||||
}
|
||||
|
||||
// 手动转换BO到实体,解决字段映射问题
|
||||
ZsjyInternshipMonthly update = new ZsjyInternshipMonthly();
|
||||
update.setId(addBo.getMonthlyId()); // monthlyId -> id
|
||||
update.setInternshipId(addBo.getInternshipId());
|
||||
update.setSummaryMonth(addBo.getSummaryMonth());
|
||||
update.setWorkContent(addBo.getWorkContent());
|
||||
update.setAchievements(addBo.getAchievements());
|
||||
update.setLearningGains(addBo.getLearningGains());
|
||||
update.setProblemsEncountered(addBo.getProblemsEncountered());
|
||||
update.setSelfEvaluation(addBo.getSelfEvaluation());
|
||||
update.setNextMonthPlan(addBo.getNextMonthPlan());
|
||||
update.setProfessionalSkills(addBo.getProfessionalSkills());
|
||||
update.setCommunicationSkills(addBo.getCommunicationSkills());
|
||||
update.setTeamworkAbility(addBo.getTeamworkAbility());
|
||||
update.setLearningAbility(addBo.getLearningAbility());
|
||||
update.setWorkAttitude(addBo.getWorkAttitude());
|
||||
update.setAttachments(addBo.getAttachments());
|
||||
|
||||
// 处理审核状态和提交时间
|
||||
if (addBo.getReviewStatus() != null) {
|
||||
update.setReviewStatus(addBo.getReviewStatus());
|
||||
// 如果状态从草稿(3)变为待审核(0),设置提交时间
|
||||
if (addBo.getReviewStatus() == 0 && original.getReviewStatus() == 3) {
|
||||
update.setSubmitTime(addBo.getSubmitTime() != null ? addBo.getSubmitTime() : new Date());
|
||||
}
|
||||
// 如果状态变回草稿(3),清空提交时间
|
||||
else if (addBo.getReviewStatus() == 3) {
|
||||
update.setSubmitTime(null);
|
||||
}
|
||||
}
|
||||
|
||||
// 解析月份序号
|
||||
if (StringUtils.isNotBlank(addBo.getSummaryMonth())) {
|
||||
String[] parts = addBo.getSummaryMonth().split("-");
|
||||
if (parts.length == 2) {
|
||||
update.setMonthNumber(Integer.parseInt(parts[1]));
|
||||
}
|
||||
}
|
||||
|
||||
// 重新计算字数
|
||||
update.setWordCount(calculateWordCount(addBo));
|
||||
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除学生月度实习总结
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean deleteByIds(Collection<Long> ids) {
|
||||
Long studentId = LoginHelper.getUserId();
|
||||
|
||||
// 验证权限:只能删除自己的草稿状态总结
|
||||
for (Long id : ids) {
|
||||
ZsjyInternshipMonthly monthly = baseMapper.selectById(id);
|
||||
if (ObjectUtil.isNull(monthly)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Objects.equals(monthly.getStudentId(), studentId)) {
|
||||
throw new ServiceException("您只能删除自己的月度总结");
|
||||
}
|
||||
|
||||
if (!Objects.equals(monthly.getReviewStatus(), 3)) {
|
||||
throw new ServiceException("只有草稿状态的总结才能删除");
|
||||
}
|
||||
}
|
||||
|
||||
return baseMapper.deleteByIds(ids.toArray(new Long[0])) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交月度总结审批
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean submitForApproval(Long monthlyId) {
|
||||
Long studentId = LoginHelper.getUserId();
|
||||
|
||||
ZsjyInternshipMonthly monthly = baseMapper.selectById(monthlyId);
|
||||
if (ObjectUtil.isNull(monthly)) {
|
||||
throw new ServiceException("月度总结不存在");
|
||||
}
|
||||
|
||||
// 权限检查
|
||||
if (!Objects.equals(monthly.getStudentId(), studentId)) {
|
||||
throw new ServiceException("您只能提交自己的月度总结");
|
||||
}
|
||||
|
||||
// 状态检查
|
||||
if (!Objects.equals(monthly.getReviewStatus(), 3)) {
|
||||
throw new ServiceException("只有草稿状态的总结才能提交");
|
||||
}
|
||||
|
||||
// 必填字段检查
|
||||
if (StringUtils.isBlank(monthly.getWorkContent())) {
|
||||
throw new ServiceException("工作内容不能为空");
|
||||
}
|
||||
|
||||
// 更新状态为待审核
|
||||
ZsjyInternshipMonthly update = new ZsjyInternshipMonthly();
|
||||
update.setId(monthlyId);
|
||||
update.setReviewStatus(0); // 待审核
|
||||
update.setSubmitTime(new Date());
|
||||
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动保存草稿
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean autoSaveDraft(ZsjyInternshipMonthlyAddBo addBo) {
|
||||
try {
|
||||
if (ObjectUtil.isNull(addBo.getMonthlyId())) {
|
||||
// 新增草稿
|
||||
return insertByBo(addBo);
|
||||
} else {
|
||||
// 更新草稿
|
||||
return updateByBo(addBo);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("自动保存草稿失败: {}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查学生某月是否已有总结
|
||||
*/
|
||||
@Override
|
||||
public Boolean checkMonthExists(Long studentId, String summaryMonth, Long monthlyId) {
|
||||
return baseMapper.existsByStudentAndMonth(studentId, summaryMonth, monthlyId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取月度总结模板信息
|
||||
*/
|
||||
@Override
|
||||
public ZsjyInternshipMonthlyVo getMonthlyTemplate(String summaryMonth) {
|
||||
ZsjyInternshipMonthlyVo template = new ZsjyInternshipMonthlyVo();
|
||||
template.setSummaryMonth(summaryMonth);
|
||||
|
||||
// 解析月份序号
|
||||
if (StringUtils.isNotBlank(summaryMonth)) {
|
||||
String[] parts = summaryMonth.split("-");
|
||||
if (parts.length == 2) {
|
||||
template.setMonthNumber(Integer.parseInt(parts[1]));
|
||||
}
|
||||
}
|
||||
|
||||
// 设置默认截止日期(下月5号)
|
||||
try {
|
||||
YearMonth ym = YearMonth.parse(summaryMonth);
|
||||
template.setSubmitDeadline(Date.from(ym.plusMonths(1).atDay(5).atStartOfDay(ZoneId.systemDefault()).toInstant()));
|
||||
} catch (Exception e) {
|
||||
log.warn("解析月份失败: {}", summaryMonth);
|
||||
}
|
||||
|
||||
template.setReviewStatus(3); // 草稿
|
||||
template.setStatusText("草稿");
|
||||
template.setEditable(true);
|
||||
template.setDeletable(true);
|
||||
template.setSubmittable(true);
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询学生指定实习的月度总结列表
|
||||
*/
|
||||
@Override
|
||||
public List<ZsjyInternshipMonthlyVo> queryByStudentAndInternship(Long studentId, Long internshipId) {
|
||||
if (ObjectUtil.isNull(studentId)) {
|
||||
studentId = LoginHelper.getUserId();
|
||||
}
|
||||
return baseMapper.selectByStudentAndInternship(studentId, internshipId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计学生各状态的总结数量
|
||||
*/
|
||||
@Override
|
||||
public List<Object> countByStatus(Long studentId) {
|
||||
if (ObjectUtil.isNull(studentId)) {
|
||||
studentId = LoginHelper.getUserId();
|
||||
}
|
||||
return baseMapper.countByStatus(studentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算总结内容字数
|
||||
*/
|
||||
@Override
|
||||
public Integer calculateWordCount(ZsjyInternshipMonthlyAddBo addBo) {
|
||||
int wordCount = 0;
|
||||
|
||||
if (StringUtils.isNotBlank(addBo.getWorkContent())) {
|
||||
wordCount += addBo.getWorkContent().length();
|
||||
}
|
||||
if (StringUtils.isNotBlank(addBo.getAchievements())) {
|
||||
wordCount += addBo.getAchievements().length();
|
||||
}
|
||||
if (StringUtils.isNotBlank(addBo.getLearningGains())) {
|
||||
wordCount += addBo.getLearningGains().length();
|
||||
}
|
||||
if (StringUtils.isNotBlank(addBo.getProblemsEncountered())) {
|
||||
wordCount += addBo.getProblemsEncountered().length();
|
||||
}
|
||||
if (StringUtils.isNotBlank(addBo.getSelfEvaluation())) {
|
||||
wordCount += addBo.getSelfEvaluation().length();
|
||||
}
|
||||
if (StringUtils.isNotBlank(addBo.getNextMonthPlan())) {
|
||||
wordCount += addBo.getNextMonthPlan().length();
|
||||
}
|
||||
|
||||
return wordCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取学生当前实习信息
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> getCurrentInternshipInfo() {
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
log.info("获取学生当前实习信息, 用户ID: {}", currentUserId);
|
||||
|
||||
// 查询学生当前进行中的实习记录(与insertByBo方法保持一致)
|
||||
LambdaQueryWrapper<ZsjyInternshipInfo> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(ZsjyInternshipInfo::getStudentId, currentUserId)
|
||||
.eq(ZsjyInternshipInfo::getStatus, "1") // 查询进行中状态的实习
|
||||
.eq(ZsjyInternshipInfo::getDeleted, 0)
|
||||
.orderByDesc(ZsjyInternshipInfo::getCreateTime)
|
||||
.last("LIMIT 1");
|
||||
|
||||
ZsjyInternshipInfo internshipInfo = internshipInfoMapper.selectOne(wrapper);
|
||||
|
||||
if (internshipInfo == null) {
|
||||
log.warn("学生{}没有找到进行中的实习记录", currentUserId);
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("internshipId", internshipInfo.getInternshipId());
|
||||
result.put("companyName", internshipInfo.getCompanyName());
|
||||
result.put("position", internshipInfo.getPositionName());
|
||||
result.put("startDate", internshipInfo.getStartDate());
|
||||
result.put("endDate", internshipInfo.getEndDate());
|
||||
|
||||
log.info("找到学生实习信息: {}", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
+240
@@ -0,0 +1,240 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.zsjy.mapper.ZsjyInternshipMonthlyMapper">
|
||||
|
||||
<resultMap type="org.dromara.zsjy.domain.ZsjyInternshipMonthly" id="ZsjyInternshipMonthlyResult">
|
||||
<result property="id" column="monthly_id" />
|
||||
<result property="tenantId" column="tenant_id" />
|
||||
<result property="internshipId" column="internship_id" />
|
||||
<result property="studentId" column="student_id" />
|
||||
<result property="summaryMonth" column="summary_month" />
|
||||
<result property="monthNumber" column="month_number" />
|
||||
<result property="workContent" column="work_content" />
|
||||
<result property="achievements" column="achievements" />
|
||||
<result property="learningGains" column="learning_gains" />
|
||||
<result property="problemsEncountered" column="problems_encountered" />
|
||||
<result property="selfEvaluation" column="self_evaluation" />
|
||||
<result property="nextMonthPlan" column="next_month_plan" />
|
||||
<result property="professionalSkills" column="professional_skills" />
|
||||
<result property="communicationSkills" column="communication_skills" />
|
||||
<result property="teamworkAbility" column="teamwork_ability" />
|
||||
<result property="learningAbility" column="learning_ability" />
|
||||
<result property="workAttitude" column="work_attitude" />
|
||||
<result property="reviewStatus" column="review_status" />
|
||||
<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="submitTime" column="submit_time" />
|
||||
<result property="wordCount" column="word_count" />
|
||||
<result property="isOverdue" column="is_overdue" />
|
||||
<result property="submitDeadline" column="submit_deadline" />
|
||||
<result property="attachments" column="attachments" />
|
||||
<result property="createBy" column="create_by" />
|
||||
<result property="createTime" column="create_time" />
|
||||
<result property="updateBy" column="update_by" />
|
||||
<result property="updateTime" column="update_time" />
|
||||
<result property="deleted" column="deleted" />
|
||||
</resultMap>
|
||||
|
||||
<resultMap type="org.dromara.zsjy.domain.vo.ZsjyInternshipMonthlyVo" id="ZsjyInternshipMonthlyVoResult">
|
||||
<result property="monthlyId" column="monthly_id" />
|
||||
<result property="internshipId" column="internship_id" />
|
||||
<result property="studentId" column="student_id" />
|
||||
<result property="studentName" column="student_name" />
|
||||
<result property="studentNumber" column="student_number" />
|
||||
<result property="summaryMonth" column="summary_month" />
|
||||
<result property="monthNumber" column="month_number" />
|
||||
<result property="workContent" column="work_content" />
|
||||
<result property="achievements" column="achievements" />
|
||||
<result property="learningGains" column="learning_gains" />
|
||||
<result property="problemsEncountered" column="problems_encountered" />
|
||||
<result property="selfEvaluation" column="self_evaluation" />
|
||||
<result property="nextMonthPlan" column="next_month_plan" />
|
||||
<result property="professionalSkills" column="professional_skills" />
|
||||
<result property="communicationSkills" column="communication_skills" />
|
||||
<result property="teamworkAbility" column="teamwork_ability" />
|
||||
<result property="learningAbility" column="learning_ability" />
|
||||
<result property="workAttitude" column="work_attitude" />
|
||||
<result property="reviewStatus" column="review_status" />
|
||||
<result property="statusText" column="status_text" />
|
||||
<result property="reviewBy" column="review_by" />
|
||||
<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="submitTime" column="submit_time" />
|
||||
<result property="wordCount" column="word_count" />
|
||||
<result property="isOverdue" column="is_overdue" />
|
||||
<result property="submitDeadline" column="submit_deadline" />
|
||||
<result property="attachments" column="attachments" />
|
||||
<result property="editable" column="editable" />
|
||||
<result property="deletable" column="deletable" />
|
||||
<result property="submittable" column="submittable" />
|
||||
<result property="createBy" column="create_by" />
|
||||
<result property="createTime" column="create_time" />
|
||||
<result property="updateBy" column="update_by" />
|
||||
<result property="updateTime" column="update_time" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectZsjyInternshipMonthlyVo">
|
||||
SELECT
|
||||
m.monthly_id,
|
||||
m.internship_id,
|
||||
m.student_id,
|
||||
u.nick_name as student_name,
|
||||
ui.student_no as student_number,
|
||||
m.summary_month,
|
||||
m.month_number,
|
||||
m.work_content,
|
||||
m.achievements,
|
||||
m.learning_gains,
|
||||
m.problems_encountered,
|
||||
m.self_evaluation,
|
||||
m.next_month_plan,
|
||||
m.professional_skills,
|
||||
m.communication_skills,
|
||||
m.teamwork_ability,
|
||||
m.learning_ability,
|
||||
m.work_attitude,
|
||||
m.review_status,
|
||||
CASE m.review_status
|
||||
WHEN 0 THEN '待审核'
|
||||
WHEN 1 THEN '已审核'
|
||||
WHEN 2 THEN '审核拒绝'
|
||||
WHEN 3 THEN '草稿'
|
||||
ELSE '未知状态'
|
||||
END as status_text,
|
||||
m.review_by,
|
||||
r.nick_name as reviewer_name,
|
||||
m.review_time,
|
||||
m.review_score,
|
||||
m.review_comment as review_comments,
|
||||
m.submit_time,
|
||||
m.word_count,
|
||||
m.is_overdue,
|
||||
m.submit_deadline,
|
||||
m.attachments,
|
||||
CASE WHEN m.review_status = 3 THEN 1 ELSE 0 END as editable,
|
||||
CASE WHEN m.review_status = 3 THEN 1 ELSE 0 END as deletable,
|
||||
CASE WHEN m.review_status = 3 THEN 1 ELSE 0 END as submittable,
|
||||
m.create_by,
|
||||
m.create_time,
|
||||
m.update_by,
|
||||
m.update_time
|
||||
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
|
||||
LEFT JOIN sys_user r ON r.user_id = m.review_by
|
||||
WHERE m.deleted = 0
|
||||
</sql>
|
||||
|
||||
<select id="selectVoById" parameterType="Long" resultMap="ZsjyInternshipMonthlyVoResult">
|
||||
<include refid="selectZsjyInternshipMonthlyVo"/>
|
||||
AND m.monthly_id = #{monthlyId}
|
||||
</select>
|
||||
|
||||
<select id="selectVoPage" resultMap="ZsjyInternshipMonthlyVoResult">
|
||||
<include refid="selectZsjyInternshipMonthlyVo"/>
|
||||
<if test="bo.studentId != null">
|
||||
AND m.student_id = #{bo.studentId}
|
||||
</if>
|
||||
<if test="bo.internshipId != null">
|
||||
AND m.internship_id = #{bo.internshipId}
|
||||
</if>
|
||||
<if test="bo.summaryMonth != null and bo.summaryMonth != ''">
|
||||
AND m.summary_month = #{bo.summaryMonth}
|
||||
</if>
|
||||
<if test="bo.status != null">
|
||||
AND m.review_status = #{bo.status}
|
||||
</if>
|
||||
<if test="bo.isOverdue != null">
|
||||
AND m.is_overdue = #{bo.isOverdue}
|
||||
</if>
|
||||
<if test="bo.startMonth != null and bo.startMonth != ''">
|
||||
AND m.summary_month >= #{bo.startMonth}
|
||||
</if>
|
||||
<if test="bo.endMonth != null and bo.endMonth != ''">
|
||||
AND m.summary_month <= #{bo.endMonth}
|
||||
</if>
|
||||
ORDER BY m.summary_month DESC, m.create_time DESC
|
||||
</select>
|
||||
|
||||
<select id="selectVoList" resultMap="ZsjyInternshipMonthlyVoResult">
|
||||
<include refid="selectZsjyInternshipMonthlyVo"/>
|
||||
<if test="bo.studentId != null">
|
||||
AND m.student_id = #{bo.studentId}
|
||||
</if>
|
||||
<if test="bo.internshipId != null">
|
||||
AND m.internship_id = #{bo.internshipId}
|
||||
</if>
|
||||
<if test="bo.summaryMonth != null and bo.summaryMonth != ''">
|
||||
AND m.summary_month = #{bo.summaryMonth}
|
||||
</if>
|
||||
<if test="bo.status != null">
|
||||
AND m.review_status = #{bo.status}
|
||||
</if>
|
||||
<if test="bo.isOverdue != null">
|
||||
AND m.is_overdue = #{bo.isOverdue}
|
||||
</if>
|
||||
<if test="bo.startMonth != null and bo.startMonth != ''">
|
||||
AND m.summary_month >= #{bo.startMonth}
|
||||
</if>
|
||||
<if test="bo.endMonth != null and bo.endMonth != ''">
|
||||
AND m.summary_month <= #{bo.endMonth}
|
||||
</if>
|
||||
ORDER BY m.summary_month DESC, m.create_time DESC
|
||||
</select>
|
||||
|
||||
<select id="existsByStudentAndMonth" resultType="boolean">
|
||||
SELECT COUNT(1) > 0
|
||||
FROM zsjy_internship_monthly
|
||||
WHERE deleted = 0
|
||||
AND student_id = #{studentId}
|
||||
AND summary_month = #{summaryMonth}
|
||||
<if test="monthlyId != null">
|
||||
AND monthly_id != #{monthlyId}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<delete id="deleteByIds" parameterType="Long">
|
||||
UPDATE zsjy_internship_monthly SET deleted = 1
|
||||
WHERE monthly_id IN
|
||||
<foreach item="monthlyId" collection="monthlyIds" open="(" separator="," close=")">
|
||||
#{monthlyId}
|
||||
</foreach>
|
||||
AND review_status = 3
|
||||
</delete>
|
||||
|
||||
<select id="selectByStudentAndInternship" resultMap="ZsjyInternshipMonthlyVoResult">
|
||||
<include refid="selectZsjyInternshipMonthlyVo"/>
|
||||
<if test="studentId != null">
|
||||
AND m.student_id = #{studentId}
|
||||
</if>
|
||||
<if test="internshipId != null">
|
||||
AND m.internship_id = #{internshipId}
|
||||
</if>
|
||||
ORDER BY m.summary_month DESC, m.create_time DESC
|
||||
</select>
|
||||
|
||||
<select id="countByStatus" resultType="map">
|
||||
SELECT
|
||||
review_status,
|
||||
CASE review_status
|
||||
WHEN 0 THEN '待审核'
|
||||
WHEN 1 THEN '已审核'
|
||||
WHEN 2 THEN '审核拒绝'
|
||||
WHEN 3 THEN '草稿'
|
||||
ELSE '未知状态'
|
||||
END as status_text,
|
||||
COUNT(1) as count
|
||||
FROM zsjy_internship_monthly
|
||||
WHERE deleted = 0
|
||||
AND student_id = #{studentId}
|
||||
GROUP BY review_status
|
||||
ORDER BY review_status
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -28,6 +28,17 @@ export const getStudentInternshipInfo = () => {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取当前学生实习信息(新版API)
|
||||
* @returns Promise
|
||||
*/
|
||||
export const getCurrentStudentInternship = () => {
|
||||
return request({
|
||||
url: '/zsjy/internship/current',
|
||||
method: 'GET'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 学生签到打卡
|
||||
* @param {Object} data 签到数据
|
||||
|
||||
@@ -170,7 +170,7 @@
|
||||
</ServiceItem>
|
||||
<ServiceItem
|
||||
v-if="hasPermi(['student:visit:list'])"
|
||||
title="班主任走访1"
|
||||
title="班主任走访"
|
||||
@click="gotoVisitManage"
|
||||
>
|
||||
<template #icon>
|
||||
|
||||
@@ -33,6 +33,17 @@ export const getInternshipInfo = (studentId: string | number): AxiosPromise<R<In
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取当前学生实习信息
|
||||
* @returns 当前登录学生的实习信息
|
||||
*/
|
||||
export const getCurrentStudentInternship = (): AxiosPromise<R<InternshipInfoVO>> => {
|
||||
return request({
|
||||
url: '/zsjy/internship/current',
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 导出实习信息列表
|
||||
* @param query 查询参数
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询学生月度总结列表
|
||||
export function listInternshipMonthly(query: any) {
|
||||
return request({
|
||||
url: '/zsjy/internship/monthly/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 获取学生月度总结详细信息
|
||||
export function getInternshipMonthly(monthlyId: string | number) {
|
||||
return request({
|
||||
url: '/zsjy/internship/monthly/' + monthlyId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增学生月度总结
|
||||
export function addInternshipMonthly(data: any) {
|
||||
return request({
|
||||
url: '/zsjy/internship/monthly',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改学生月度总结
|
||||
export function updateInternshipMonthly(data: any) {
|
||||
return request({
|
||||
url: '/zsjy/internship/monthly',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除学生月度总结
|
||||
export function delInternshipMonthly(monthlyIds: string | number | Array<string | number>) {
|
||||
return request({
|
||||
url: '/zsjy/internship/monthly/' + monthlyIds,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 提交月度总结审批
|
||||
export function submitInternshipMonthly(monthlyId: string | number) {
|
||||
return request({
|
||||
url: '/zsjy/internship/monthly/submit/' + monthlyId,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
// 自动保存草稿
|
||||
export function autosaveInternshipMonthly(data: any) {
|
||||
return request({
|
||||
url: '/zsjy/internship/monthly/autosave',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 检查月份重复
|
||||
export function checkSummaryMonth(summaryMonth: string) {
|
||||
return request({
|
||||
url: '/zsjy/internship/monthly/check/' + summaryMonth,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取月度总结模板
|
||||
export function getMonthlyTemplate(summaryMonth: string) {
|
||||
return request({
|
||||
url: '/zsjy/internship/monthly/template/' + summaryMonth,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取状态统计
|
||||
export function getMonthlyStatistics() {
|
||||
return request({
|
||||
url: '/zsjy/internship/monthly/statistics',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 导出月度总结数据
|
||||
export function exportInternshipMonthly(query: any) {
|
||||
return request({
|
||||
url: '/zsjy/internship/monthly/export',
|
||||
method: 'post',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 获取学生当前实习信息
|
||||
export function getCurrentInternshipInfo() {
|
||||
return request({
|
||||
url: '/zsjy/internship/monthly/current-internship',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,318 @@
|
||||
<template>
|
||||
<div class="monthly-detail">
|
||||
<el-row :gutter="20">
|
||||
<!-- 左侧详情内容 -->
|
||||
<el-col :span="16">
|
||||
<el-card shadow="never" class="mb-4">
|
||||
<template #header>
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="font-medium">基本信息</span>
|
||||
<dict-tag :options="internship_monthly_status" :value="detail.reviewStatus" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="总结月份">
|
||||
{{ detail.summaryMonth }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="技能评分" span="2">
|
||||
<div class="flex gap-4 flex-wrap">
|
||||
<el-tag v-if="detail.professionalSkills" :type="getScoreTagType(detail.professionalSkills)">
|
||||
专业技能: {{ detail.professionalSkills }}分
|
||||
</el-tag>
|
||||
<el-tag v-if="detail.communicationSkills" :type="getScoreTagType(detail.communicationSkills)">
|
||||
沟通技能: {{ detail.communicationSkills }}分
|
||||
</el-tag>
|
||||
<el-tag v-if="detail.teamworkAbility" :type="getScoreTagType(detail.teamworkAbility)">
|
||||
团队协作: {{ detail.teamworkAbility }}分
|
||||
</el-tag>
|
||||
<el-tag v-if="detail.learningAbility" :type="getScoreTagType(detail.learningAbility)">
|
||||
学习能力: {{ detail.learningAbility }}分
|
||||
</el-tag>
|
||||
<el-tag v-if="detail.workAttitude" :type="getScoreTagType(detail.workAttitude)">
|
||||
工作态度: {{ detail.workAttitude }}分
|
||||
</el-tag>
|
||||
</div>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="总字数">
|
||||
<el-tag :type="getWordCountTagType(detail.wordCount)">{{ detail.wordCount || 0 }}字</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="是否逾期">
|
||||
<el-tag v-if="detail.isOverdue === 1" type="danger">逾期</el-tag>
|
||||
<el-tag v-else type="success">正常</el-tag>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<span class="font-medium">总结内容</span>
|
||||
</template>
|
||||
|
||||
<div class="space-y-6">
|
||||
<div v-if="detail.workContent">
|
||||
<h4 class="text-base font-medium mb-2 text-gray-800">工作内容</h4>
|
||||
<div class="bg-gray-50 p-4 rounded-md">
|
||||
<p class="text-gray-700 leading-relaxed whitespace-pre-wrap">{{ detail.workContent }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="detail.achievements">
|
||||
<h4 class="text-base font-medium mb-2 text-gray-800">成果成就</h4>
|
||||
<div class="bg-blue-50 p-4 rounded-md">
|
||||
<p class="text-gray-700 leading-relaxed whitespace-pre-wrap">{{ detail.achievements }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="detail.learningGains">
|
||||
<h4 class="text-base font-medium mb-2 text-gray-800">学习收获</h4>
|
||||
<div class="bg-green-50 p-4 rounded-md">
|
||||
<p class="text-gray-700 leading-relaxed whitespace-pre-wrap">{{ detail.learningGains }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="detail.problemsEncountered">
|
||||
<h4 class="text-base font-medium mb-2 text-gray-800">问题困难</h4>
|
||||
<div class="bg-yellow-50 p-4 rounded-md">
|
||||
<p class="text-gray-700 leading-relaxed whitespace-pre-wrap">{{ detail.problemsEncountered }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="detail.solutions">
|
||||
<h4 class="text-base font-medium mb-2 text-gray-800">解决方案</h4>
|
||||
<div class="bg-purple-50 p-4 rounded-md">
|
||||
<p class="text-gray-700 leading-relaxed whitespace-pre-wrap">{{ detail.solutions }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="detail.nextMonthPlan">
|
||||
<h4 class="text-base font-medium mb-2 text-gray-800">下月计划</h4>
|
||||
<div class="bg-indigo-50 p-4 rounded-md">
|
||||
<p class="text-gray-700 leading-relaxed whitespace-pre-wrap">{{ detail.nextMonthPlan }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="detail.remark">
|
||||
<h4 class="text-base font-medium mb-2 text-gray-800">备注说明</h4>
|
||||
<div class="bg-gray-50 p-4 rounded-md">
|
||||
<p class="text-gray-700 leading-relaxed whitespace-pre-wrap">{{ detail.remark }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<!-- 右侧信息面板 -->
|
||||
<el-col :span="8">
|
||||
<el-card shadow="never" class="mb-4">
|
||||
<template #header>
|
||||
<span class="font-medium">审批信息</span>
|
||||
</template>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div class="flex justify-between">
|
||||
<span>审核状态:</span>
|
||||
<dict-tag :options="internship_monthly_status" :value="detail.status" />
|
||||
</div>
|
||||
|
||||
<div v-if="detail.submitTime" class="flex justify-between">
|
||||
<span>提交时间:</span>
|
||||
<span class="text-sm">{{ parseTime(detail.submitTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
||||
</div>
|
||||
|
||||
<div v-if="detail.auditTime" class="flex justify-between">
|
||||
<span>审核时间:</span>
|
||||
<span class="text-sm">{{ parseTime(detail.auditTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
||||
</div>
|
||||
|
||||
<div v-if="detail.auditBy" class="flex justify-between">
|
||||
<span>审核人:</span>
|
||||
<span class="text-sm">{{ detail.auditByName || detail.auditBy }}</span>
|
||||
</div>
|
||||
|
||||
<div v-if="detail.auditScore" class="flex justify-between">
|
||||
<span>审核评分:</span>
|
||||
<el-tag :type="getScoreTagType(detail.auditScore)">{{ detail.auditScore }}分</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-card v-if="detail.auditComment" shadow="never" class="mb-4">
|
||||
<template #header>
|
||||
<span class="font-medium">审核意见</span>
|
||||
</template>
|
||||
|
||||
<div class="bg-blue-50 p-3 rounded-md">
|
||||
<p class="text-gray-700 leading-relaxed whitespace-pre-wrap">{{ detail.auditComment }}</p>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="mb-4">
|
||||
<template #header>
|
||||
<span class="font-medium">时间记录</span>
|
||||
</template>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div class="flex justify-between">
|
||||
<span>创建时间:</span>
|
||||
<span class="text-sm">{{ parseTime(detail.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
||||
</div>
|
||||
|
||||
<div v-if="detail.updateTime" class="flex justify-between">
|
||||
<span>最后更新:</span>
|
||||
<span class="text-sm">{{ parseTime(detail.updateTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
||||
</div>
|
||||
|
||||
<div v-if="detail.createByName" class="flex justify-between">
|
||||
<span>创建人:</span>
|
||||
<span class="text-sm">{{ detail.createByName }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<span class="font-medium">统计数据</span>
|
||||
</template>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div class="flex justify-between">
|
||||
<span>总字数:</span>
|
||||
<el-tag :type="getWordCountTagType(detail.wordCount)">{{ detail.wordCount || 0 }}字</el-tag>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between">
|
||||
<span>自评分数:</span>
|
||||
<el-tag :type="getScoreTagType(detail.selfScore)">{{ detail.selfScore }}分</el-tag>
|
||||
</div>
|
||||
|
||||
<div v-if="detail.auditScore" class="flex justify-between">
|
||||
<span>审核评分:</span>
|
||||
<el-tag :type="getScoreTagType(detail.auditScore)">{{ detail.auditScore }}分</el-tag>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between">
|
||||
<span>逾期状态:</span>
|
||||
<el-tag v-if="detail.isOverdue === 1" type="danger">逾期</el-tag>
|
||||
<el-tag v-else type="success">正常</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<el-row class="mt-6">
|
||||
<el-col :span="24" class="text-center">
|
||||
<el-button @click="handleClose">关闭</el-button>
|
||||
<el-button
|
||||
v-if="detail.reviewStatus === 3"
|
||||
type="primary"
|
||||
@click="handleEdit"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="detail.reviewStatus === 3"
|
||||
type="success"
|
||||
@click="handleSubmit"
|
||||
>
|
||||
提交审核
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getInternshipMonthly, submitInternshipMonthly } from '@/api/zsjy/internshipMonthly'
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance
|
||||
const { internship_monthly_status } = toRefs<any>(proxy?.useDict('internship_monthly_status'))
|
||||
|
||||
const emit = defineEmits(['edit', 'close'])
|
||||
|
||||
// 详情数据
|
||||
const detail = ref<any>({})
|
||||
const loading = ref(false)
|
||||
|
||||
/** 重置表单 */
|
||||
const resetForm = async (monthlyId: string | number) => {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await getInternshipMonthly(monthlyId)
|
||||
detail.value = res.data || {}
|
||||
} catch (error) {
|
||||
console.error('获取月度总结详情失败:', error)
|
||||
proxy?.$modal.msgError('获取详情失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 根据分数获取标签类型 */
|
||||
const getScoreTagType = (score: number) => {
|
||||
if (!score) return 'info'
|
||||
if (score >= 9) return 'success'
|
||||
if (score >= 7) return 'warning'
|
||||
if (score >= 5) return ''
|
||||
return 'danger'
|
||||
}
|
||||
|
||||
/** 获取字数标签类型 */
|
||||
const getWordCountTagType = (count: number) => {
|
||||
if (!count) return 'info'
|
||||
if (count < 100) return 'info'
|
||||
if (count < 500) return 'warning'
|
||||
if (count < 1000) return 'success'
|
||||
return 'danger'
|
||||
}
|
||||
|
||||
/** 编辑操作 */
|
||||
const handleEdit = () => {
|
||||
emit('edit', detail.value.monthlyId)
|
||||
}
|
||||
|
||||
/** 提交审核操作 */
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
await proxy?.$modal.confirm('确认提交该月度总结?提交后将无法再次编辑')
|
||||
await submitInternshipMonthly(detail.value.monthlyId)
|
||||
proxy?.$modal.msgSuccess('提交成功')
|
||||
// 重新加载详情
|
||||
await resetForm(detail.value.monthlyId)
|
||||
} catch {}
|
||||
}
|
||||
|
||||
/** 关闭操作 */
|
||||
const handleClose = () => {
|
||||
emit('close')
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
resetForm
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.monthly-detail {
|
||||
max-height: 70vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.space-y-6 > :not([hidden]) ~ :not([hidden]) {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.space-y-4 > :not([hidden]) ~ :not([hidden]) {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.space-y-3 > :not([hidden]) ~ :not([hidden]) {
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
|
||||
.whitespace-pre-wrap {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,590 @@
|
||||
<template>
|
||||
<el-form ref="monthlyFormRef" :model="form" :rules="rules" label-width="120px">
|
||||
<el-row :gutter="20">
|
||||
<!-- 左侧表单 -->
|
||||
<el-col :span="16">
|
||||
<el-card shadow="never" class="mb-4">
|
||||
<template #header>
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="font-medium">基本信息</span>
|
||||
<el-button
|
||||
v-if="form.monthlyId && form.reviewStatus === 3"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="handleAutoSave"
|
||||
:loading="autoSaving"
|
||||
>
|
||||
{{ autoSaving ? '保存中...' : '保存草稿' }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-form-item label="总结月份" prop="summaryMonth">
|
||||
<el-date-picker
|
||||
v-model="form.summaryMonth"
|
||||
type="month"
|
||||
value-format="YYYY-MM"
|
||||
placeholder="请选择总结月份"
|
||||
:disabled="form.reviewStatus !== undefined && form.reviewStatus !== 3"
|
||||
style="width: 300px"
|
||||
@change="checkMonthDuplicate"
|
||||
/>
|
||||
<el-text class="ml-2" size="small" type="info">选择要总结的月份</el-text>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="mb-4">
|
||||
<template #header>
|
||||
<span class="font-medium">能力自评(1-10分)</span>
|
||||
</template>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="专业技能" prop="professionalSkills">
|
||||
<el-input-number
|
||||
v-model="form.professionalSkills"
|
||||
:min="1"
|
||||
:max="10"
|
||||
:precision="0"
|
||||
placeholder="1-10分"
|
||||
:disabled="form.reviewStatus !== undefined && form.reviewStatus !== 3"
|
||||
style="width: 150px"
|
||||
/>
|
||||
<el-text class="ml-2" size="small" type="info">专业技能掌握程度</el-text>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="沟通技能" prop="communicationSkills">
|
||||
<el-input-number
|
||||
v-model="form.communicationSkills"
|
||||
:min="1"
|
||||
:max="10"
|
||||
:precision="0"
|
||||
placeholder="1-10分"
|
||||
:disabled="form.reviewStatus !== undefined && form.reviewStatus !== 3"
|
||||
style="width: 150px"
|
||||
/>
|
||||
<el-text class="ml-2" size="small" type="info">沟通表达能力</el-text>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="团队协作" prop="teamworkAbility">
|
||||
<el-input-number
|
||||
v-model="form.teamworkAbility"
|
||||
:min="1"
|
||||
:max="10"
|
||||
:precision="0"
|
||||
placeholder="1-10分"
|
||||
:disabled="form.reviewStatus !== undefined && form.reviewStatus !== 3"
|
||||
style="width: 150px"
|
||||
/>
|
||||
<el-text class="ml-2" size="small" type="info">团队合作能力</el-text>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="学习能力" prop="learningAbility">
|
||||
<el-input-number
|
||||
v-model="form.learningAbility"
|
||||
:min="1"
|
||||
:max="10"
|
||||
:precision="0"
|
||||
placeholder="1-10分"
|
||||
:disabled="form.reviewStatus !== undefined && form.reviewStatus !== 3"
|
||||
style="width: 150px"
|
||||
/>
|
||||
<el-text class="ml-2" size="small" type="info">学习新知识能力</el-text>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="工作态度" prop="workAttitude">
|
||||
<el-input-number
|
||||
v-model="form.workAttitude"
|
||||
:min="1"
|
||||
:max="10"
|
||||
:precision="0"
|
||||
placeholder="1-10分"
|
||||
:disabled="form.reviewStatus !== undefined && form.reviewStatus !== 3"
|
||||
style="width: 150px"
|
||||
/>
|
||||
<el-text class="ml-2" size="small" type="info">工作认真负责程度</el-text>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<span class="font-medium">工作总结内容</span>
|
||||
</template>
|
||||
|
||||
<el-form-item label="工作内容" prop="workContent">
|
||||
<el-input
|
||||
v-model="form.workContent"
|
||||
type="textarea"
|
||||
:rows="6"
|
||||
placeholder="请详细描述本月的主要工作内容和任务完成情况(必填,最多500字)"
|
||||
:disabled="form.reviewStatus !== undefined && form.reviewStatus !== 3"
|
||||
show-word-limit
|
||||
:maxlength="500"
|
||||
@input="updateWordCount"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="成果成就" prop="achievements">
|
||||
<el-input
|
||||
v-model="form.achievements"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
placeholder="请描述本月取得的主要成果和成就(最多300字)"
|
||||
:disabled="form.reviewStatus !== undefined && form.reviewStatus !== 3"
|
||||
show-word-limit
|
||||
:maxlength="300"
|
||||
@input="updateWordCount"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="学习收获" prop="learningGains">
|
||||
<el-input
|
||||
v-model="form.learningGains"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
placeholder="请分享本月的学习心得和收获(最多300字)"
|
||||
:disabled="form.reviewStatus !== undefined && form.reviewStatus !== 3"
|
||||
show-word-limit
|
||||
:maxlength="300"
|
||||
@input="updateWordCount"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="问题困难" prop="problemsEncountered">
|
||||
<el-input
|
||||
v-model="form.problemsEncountered"
|
||||
type="textarea"
|
||||
:rows="6"
|
||||
placeholder="请描述遇到的问题、困难以及解决方案(包含问题和解决办法,最多1000字)"
|
||||
:disabled="form.reviewStatus !== undefined && form.reviewStatus !== 3"
|
||||
show-word-limit
|
||||
:maxlength="1000"
|
||||
@input="updateWordCount"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="自我评价" prop="selfEvaluation">
|
||||
<el-input
|
||||
v-model="form.selfEvaluation"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
placeholder="请对本月的工作表现进行自我评价(最多300字)"
|
||||
:disabled="form.reviewStatus !== undefined && form.reviewStatus !== 3"
|
||||
show-word-limit
|
||||
:maxlength="300"
|
||||
@input="updateWordCount"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="下月计划" prop="nextMonthPlan">
|
||||
<el-input
|
||||
v-model="form.nextMonthPlan"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
placeholder="请制定下个月的工作计划和目标(最多300字)"
|
||||
:disabled="form.reviewStatus !== undefined && form.reviewStatus !== 3"
|
||||
show-word-limit
|
||||
:maxlength="300"
|
||||
@input="updateWordCount"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="备注说明" prop="remark">
|
||||
<el-input
|
||||
v-model="form.remark"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="其他需要说明的内容(最多200字)"
|
||||
:disabled="form.reviewStatus !== undefined && form.reviewStatus !== 3"
|
||||
show-word-limit
|
||||
:maxlength="200"
|
||||
@input="updateWordCount"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<!-- 右侧信息面板 -->
|
||||
<el-col :span="8">
|
||||
<el-card shadow="never" class="mb-4">
|
||||
<template #header>
|
||||
<span class="font-medium">统计信息</span>
|
||||
</template>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div class="flex justify-between">
|
||||
<span>总字数:</span>
|
||||
<el-tag :type="getWordCountTagType(form.wordCount)">{{ form.wordCount || 0 }}字</el-tag>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span>状态:</span>
|
||||
<dict-tag :options="internship_monthly_status" :value="form.reviewStatus" />
|
||||
</div>
|
||||
<div v-if="form.submitTime" class="flex justify-between">
|
||||
<span>提交时间:</span>
|
||||
<span class="text-sm">{{ parseTime(form.submitTime, '{y}-{m}-{d} {h}:{i}') }}</span>
|
||||
</div>
|
||||
<div v-if="form.createTime" class="flex justify-between">
|
||||
<span>创建时间:</span>
|
||||
<span class="text-sm">{{ parseTime(form.createTime, '{y}-{m}-{d} {h}:{i}') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="mb-4">
|
||||
<template #header>
|
||||
<span class="font-medium">填写提示</span>
|
||||
</template>
|
||||
|
||||
<div class="text-sm text-gray-600 space-y-2">
|
||||
<div>• 工作内容为必填项,最多500字</div>
|
||||
<div>• 其他项目选填,建议填写完整</div>
|
||||
<div>• 自评分数范围:1-10分</div>
|
||||
<div>• 支持自动保存草稿功能</div>
|
||||
<div>• 提交后将无法再次编辑</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-card v-if="monthDuplicateCheck.show" shadow="never">
|
||||
<template #header>
|
||||
<span class="font-medium">月份检查</span>
|
||||
</template>
|
||||
|
||||
<el-alert
|
||||
:type="monthDuplicateCheck.type"
|
||||
:title="monthDuplicateCheck.message"
|
||||
show-icon
|
||||
:closable="false"
|
||||
/>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row class="mt-6">
|
||||
<el-col :span="24" class="text-center">
|
||||
<el-button @click="handleCancel">取消</el-button>
|
||||
<el-button
|
||||
v-if="form.reviewStatus === undefined || form.reviewStatus === 3"
|
||||
type="primary"
|
||||
@click="handleSubmit('draft')"
|
||||
:loading="submitting"
|
||||
>
|
||||
保存草稿
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="form.reviewStatus === undefined || form.reviewStatus === 3"
|
||||
type="success"
|
||||
@click="handleSubmit('submit')"
|
||||
:loading="submitting"
|
||||
>
|
||||
提交审核
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
getInternshipMonthly,
|
||||
addInternshipMonthly,
|
||||
updateInternshipMonthly,
|
||||
autosaveInternshipMonthly,
|
||||
checkSummaryMonth,
|
||||
getMonthlyTemplate,
|
||||
getCurrentInternshipInfo
|
||||
} from '@/api/zsjy/internshipMonthly'
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance
|
||||
const { internship_monthly_status } = toRefs<any>(proxy?.useDict('internship_monthly_status'))
|
||||
|
||||
const emit = defineEmits(['success'])
|
||||
|
||||
const monthlyFormRef = ref<ElFormInstance>()
|
||||
const submitting = ref(false)
|
||||
const autoSaving = ref(false)
|
||||
|
||||
// 表单数据
|
||||
const initFormData = {
|
||||
monthlyId: undefined,
|
||||
internshipId: undefined,
|
||||
summaryMonth: '',
|
||||
workContent: '',
|
||||
achievements: '',
|
||||
learningGains: '',
|
||||
problemsEncountered: '',
|
||||
selfEvaluation: '',
|
||||
nextMonthPlan: '',
|
||||
professionalSkills: undefined,
|
||||
communicationSkills: undefined,
|
||||
teamworkAbility: undefined,
|
||||
learningAbility: undefined,
|
||||
workAttitude: undefined,
|
||||
wordCount: 0,
|
||||
remark: '',
|
||||
reviewStatus: undefined,
|
||||
submitTime: undefined,
|
||||
createTime: undefined
|
||||
}
|
||||
|
||||
const form = ref({ ...initFormData })
|
||||
|
||||
// 表单验证规则
|
||||
const rules = ref({
|
||||
summaryMonth: [
|
||||
{ required: true, message: '总结月份不能为空', trigger: 'change' }
|
||||
],
|
||||
workContent: [
|
||||
{ required: true, message: '工作内容不能为空', trigger: 'blur' },
|
||||
{ min: 10, message: '工作内容至少需要10个字符', trigger: 'blur' },
|
||||
{ max: 500, message: '工作内容不能超过500个字符', trigger: 'blur' }
|
||||
],
|
||||
professionalSkills: [
|
||||
{ required: true, message: '专业技能不能为空', trigger: 'blur' },
|
||||
{ type: 'number', min: 1, max: 10, message: '专业技能必须在1-10之间', trigger: 'blur' }
|
||||
],
|
||||
communicationSkills: [
|
||||
{ required: true, message: '沟通技能不能为空', trigger: 'blur' },
|
||||
{ type: 'number', min: 1, max: 10, message: '沟通技能必须在1-10之间', trigger: 'blur' }
|
||||
],
|
||||
teamworkAbility: [
|
||||
{ required: true, message: '团队协作不能为空', trigger: 'blur' },
|
||||
{ type: 'number', min: 1, max: 10, message: '团队协作必须在1-10之间', trigger: 'blur' }
|
||||
],
|
||||
learningAbility: [
|
||||
{ required: true, message: '学习能力不能为空', trigger: 'blur' },
|
||||
{ type: 'number', min: 1, max: 10, message: '学习能力必须在1-10之间', trigger: 'blur' }
|
||||
],
|
||||
workAttitude: [
|
||||
{ required: true, message: '工作态度不能为空', trigger: 'blur' },
|
||||
{ type: 'number', min: 1, max: 10, message: '工作态度必须在1-10之间', trigger: 'blur' }
|
||||
],
|
||||
problemsEncountered: [
|
||||
{ required: true, message: '问题困难不能为空', trigger: 'blur' },
|
||||
{ min: 10, message: '问题困难至少需要10个字符', trigger: 'blur' },
|
||||
{ max: 1000, message: '问题困难不能超过1000个字符', trigger: 'blur' }
|
||||
],
|
||||
selfEvaluation: [
|
||||
{ required: true, message: '自我评价不能为空', trigger: 'blur' },
|
||||
{ max: 300, message: '自我评价不能超过300个字符', trigger: 'blur' }
|
||||
],
|
||||
nextMonthPlan: [
|
||||
{ max: 300, message: '下月计划不能超过300个字符', trigger: 'blur' }
|
||||
],
|
||||
remark: [
|
||||
{ max: 200, message: '备注说明不能超过200个字符', trigger: 'blur' }
|
||||
]
|
||||
})
|
||||
|
||||
// 月份重复检查
|
||||
const monthDuplicateCheck = ref({
|
||||
show: false,
|
||||
type: 'info',
|
||||
message: ''
|
||||
})
|
||||
|
||||
// 自动保存定时器
|
||||
let autoSaveTimer: NodeJS.Timeout | null = null
|
||||
|
||||
/** 重置表单 */
|
||||
const resetForm = async (monthlyId?: string | number) => {
|
||||
form.value = { ...initFormData }
|
||||
monthDuplicateCheck.value.show = false
|
||||
|
||||
if (monthlyId) {
|
||||
try {
|
||||
const res = await getInternshipMonthly(monthlyId)
|
||||
form.value = { ...res.data }
|
||||
updateWordCount()
|
||||
} catch (error) {
|
||||
console.error('获取月度总结详情失败:', error)
|
||||
}
|
||||
} else {
|
||||
// 新增时获取当前月份模板和学生实习信息
|
||||
const currentMonth = new Date().toISOString().substring(0, 7)
|
||||
form.value.summaryMonth = currentMonth
|
||||
await loadMonthlyTemplate(currentMonth)
|
||||
|
||||
// 获取学生当前实习信息
|
||||
try {
|
||||
const internshipRes = await getCurrentInternshipInfo()
|
||||
if (internshipRes.code === 200 && internshipRes.data) {
|
||||
form.value.internshipId = internshipRes.data.internshipId
|
||||
} else {
|
||||
// 如果没有进行中的实习记录,提示用户
|
||||
proxy?.$modal.msgError('您当前没有进行中的实习记录,无法创建月度总结')
|
||||
emit('success') // 关闭对话框
|
||||
return
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取学生实习信息失败:', error)
|
||||
proxy?.$modal.msgError('获取实习信息失败,请稍后重试')
|
||||
emit('success') // 关闭对话框
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
monthlyFormRef.value?.clearValidate()
|
||||
})
|
||||
}
|
||||
|
||||
/** 加载月份模板 */
|
||||
const loadMonthlyTemplate = async (month: string) => {
|
||||
try {
|
||||
const res = await getMonthlyTemplate(month)
|
||||
if (res.data) {
|
||||
// 如果有模板数据,可以预填充一些内容
|
||||
// form.value.nextMonthPlan = res.data.suggestedPlan || ''
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('获取月份模板失败,将使用空模板')
|
||||
}
|
||||
}
|
||||
|
||||
/** 检查月份重复 */
|
||||
const checkMonthDuplicate = async () => {
|
||||
if (!form.value.summaryMonth) return
|
||||
|
||||
try {
|
||||
const res = await checkSummaryMonth(form.value.summaryMonth)
|
||||
if (res.data.exists && (!form.value.monthlyId || res.data.monthlyId !== form.value.monthlyId)) {
|
||||
monthDuplicateCheck.value = {
|
||||
show: true,
|
||||
type: 'warning',
|
||||
message: '该月份已存在总结记录,请选择其他月份'
|
||||
}
|
||||
} else {
|
||||
monthDuplicateCheck.value = {
|
||||
show: true,
|
||||
type: 'success',
|
||||
message: '该月份可以创建总结'
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
monthDuplicateCheck.value = {
|
||||
show: true,
|
||||
type: 'error',
|
||||
message: '检查月份失败,请重试'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 更新字数统计 */
|
||||
const updateWordCount = () => {
|
||||
const content = [
|
||||
form.value.workContent,
|
||||
form.value.achievements,
|
||||
form.value.learningGains,
|
||||
form.value.problemsEncountered,
|
||||
form.value.selfEvaluation,
|
||||
form.value.nextMonthPlan,
|
||||
form.value.remark
|
||||
].join('')
|
||||
|
||||
form.value.wordCount = content.length
|
||||
|
||||
// 设置自动保存定时器
|
||||
if (form.value.monthlyId && form.value.reviewStatus === 3) {
|
||||
if (autoSaveTimer) {
|
||||
clearTimeout(autoSaveTimer)
|
||||
}
|
||||
autoSaveTimer = setTimeout(() => {
|
||||
handleAutoSave()
|
||||
}, 5000) // 5秒后自动保存
|
||||
}
|
||||
}
|
||||
|
||||
/** 获取字数标签类型 */
|
||||
const getWordCountTagType = (count: number) => {
|
||||
if (count < 100) return 'info'
|
||||
if (count < 500) return 'warning'
|
||||
if (count < 1000) return 'success'
|
||||
return 'danger'
|
||||
}
|
||||
|
||||
/** 自动保存草稿 */
|
||||
const handleAutoSave = async () => {
|
||||
if (!form.value.monthlyId || form.value.reviewStatus !== 3) return
|
||||
|
||||
autoSaving.value = true
|
||||
try {
|
||||
await autosaveInternshipMonthly(form.value)
|
||||
proxy?.$message.success('草稿已自动保存')
|
||||
} catch (error) {
|
||||
console.error('自动保存失败:', error)
|
||||
} finally {
|
||||
autoSaving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 提交表单 */
|
||||
const handleSubmit = async (type: 'draft' | 'submit') => {
|
||||
if (!monthlyFormRef.value) return
|
||||
|
||||
const valid = await monthlyFormRef.value.validate().catch(() => false)
|
||||
if (!valid) return
|
||||
|
||||
submitting.value = true
|
||||
try {
|
||||
updateWordCount()
|
||||
|
||||
const formData = {
|
||||
...form.value,
|
||||
reviewStatus: type === 'draft' ? 3 : 0, // 草稿=3,待审核=0
|
||||
submitTime: type === 'submit' ? new Date() : undefined
|
||||
}
|
||||
|
||||
if (form.value.monthlyId) {
|
||||
await updateInternshipMonthly(formData)
|
||||
} else {
|
||||
await addInternshipMonthly(formData)
|
||||
}
|
||||
|
||||
proxy?.$modal.msgSuccess(type === 'draft' ? '保存成功' : '提交成功')
|
||||
emit('success')
|
||||
} catch (error) {
|
||||
console.error('提交失败:', error)
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 取消操作 */
|
||||
const handleCancel = () => {
|
||||
emit('success')
|
||||
}
|
||||
|
||||
// 清理定时器
|
||||
onUnmounted(() => {
|
||||
if (autoSaveTimer) {
|
||||
clearTimeout(autoSaveTimer)
|
||||
}
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
resetForm
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.space-y-3 > :not([hidden]) ~ :not([hidden]) {
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
|
||||
.space-y-2 > :not([hidden]) ~ :not([hidden]) {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,388 @@
|
||||
<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="reviewStatus">
|
||||
<el-select v-model="queryParams.reviewStatus" placeholder="请选择审核状态" clearable style="width: 100%">
|
||||
<el-option label="草稿" value="3" />
|
||||
<el-option label="待审核" value="0" />
|
||||
<el-option label="已审核" value="1" />
|
||||
<el-option label="审核拒绝" value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="专业技能" prop="professionalSkills">
|
||||
<el-input-number
|
||||
v-model="queryParams.professionalSkills"
|
||||
:min="1"
|
||||
:max="10"
|
||||
placeholder="请输入专业技能评分"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<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>
|
||||
|
||||
<!-- 操作按钮区域 -->
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['zsjy:internshipmonthly:add']">新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['zsjy:internshipmonthly:edit']">修改</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['zsjy:internshipmonthly:remove']">删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['zsjy:internshipmonthly:export']">导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<el-table v-loading="loading" :data="monthlyList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="总结月份" align="center" prop="summaryMonth" width="120" />
|
||||
<el-table-column label="工作内容" align="center" prop="workContent" :show-overflow-tooltip="true" min-width="200" />
|
||||
<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">
|
||||
<dict-tag :options="internship_monthly_status" :value="scope.row.reviewStatus" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="是否逾期" align="center" prop="isOverdue" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.isOverdue === 1" type="danger">逾期</el-tag>
|
||||
<el-tag v-else type="success">正常</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="提交时间" align="center" prop="submitTime" width="180">
|
||||
<template #default="scope">
|
||||
<span>{{ parseTime(scope.row.submitTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||
<template #default="scope">
|
||||
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200" fixed="right">
|
||||
<template #default="scope">
|
||||
<!-- 查看详情 -->
|
||||
<el-tooltip content="查看详情" placement="top">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
icon="View"
|
||||
@click="handleDetail(scope.row)"
|
||||
v-hasPermi="['zsjy:internshipmonthly:list']"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
|
||||
<!-- 编辑(只有草稿状态才能编辑) -->
|
||||
<el-tooltip content="编辑" placement="top" v-if="scope.row.reviewStatus === 3">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
icon="Edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['zsjy:internshipmonthly:edit']"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
|
||||
<!-- 提交(只有草稿状态才能提交) -->
|
||||
<el-tooltip content="提交" placement="top" v-if="scope.row.reviewStatus === 3">
|
||||
<el-button
|
||||
link
|
||||
type="success"
|
||||
icon="Check"
|
||||
@click="handleSubmit(scope.row)"
|
||||
v-hasPermi="['zsjy:internshipmonthly:submit']"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
|
||||
<!-- 删除(只有草稿状态才能删除) -->
|
||||
<el-tooltip content="删除" placement="top" v-if="scope.row.reviewStatus === 3">
|
||||
<el-button
|
||||
link
|
||||
type="danger"
|
||||
icon="Delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
v-hasPermi="['zsjy:internshipmonthly:remove']"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
</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="dialog.title" v-model="dialog.visible" width="1000px" append-to-body>
|
||||
<MonthlyForm ref="monthlyFormRef" @success="getList" />
|
||||
</el-dialog>
|
||||
|
||||
<!-- 月度总结详情对话框 -->
|
||||
<el-dialog title="月度总结详情" v-model="detailDialog.visible" width="1000px" append-to-body>
|
||||
<MonthlyDetail ref="monthlyDetailRef" />
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="InternshipMonthly" lang="ts">
|
||||
import {
|
||||
listInternshipMonthly,
|
||||
getInternshipMonthly,
|
||||
delInternshipMonthly,
|
||||
submitInternshipMonthly,
|
||||
exportInternshipMonthly
|
||||
} from '@/api/zsjy/internshipMonthly'
|
||||
import MonthlyForm from './form.vue'
|
||||
import MonthlyDetail from './detail.vue'
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance
|
||||
const { internship_monthly_status } = toRefs<any>(proxy?.useDict('internship_monthly_status'))
|
||||
|
||||
const monthlyList = ref<any[]>([])
|
||||
const loading = ref(true)
|
||||
const showSearch = ref(true)
|
||||
const ids = ref<Array<string | number>>([])
|
||||
const single = ref(true)
|
||||
const multiple = ref(true)
|
||||
const total = ref(0)
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
})
|
||||
|
||||
const detailDialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
})
|
||||
|
||||
const initFormData: any = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
summaryMonth: undefined,
|
||||
reviewStatus: undefined,
|
||||
professionalSkills: undefined
|
||||
}
|
||||
const data = reactive<PageData<any, any>>({
|
||||
form: {},
|
||||
queryParams: { ...initFormData },
|
||||
rules: {}
|
||||
})
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data)
|
||||
|
||||
const queryFormRef = ref<ElFormInstance>()
|
||||
const monthlyFormRef = ref<ComponentRef<typeof MonthlyForm>>()
|
||||
const monthlyDetailRef = ref<ComponentRef<typeof MonthlyDetail>>()
|
||||
|
||||
/** 查询月度总结列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
const res = await listInternshipMonthly(queryParams.value)
|
||||
monthlyList.value = res.rows
|
||||
total.value = res.total
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields()
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection: any) => {
|
||||
ids.value = selection.map((item: any) => item.monthlyId)
|
||||
single.value = selection.length !== 1
|
||||
multiple.value = !selection.length
|
||||
}
|
||||
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = () => {
|
||||
dialog.visible = true
|
||||
dialog.title = '添加月度总结'
|
||||
nextTick(() => {
|
||||
monthlyFormRef.value?.resetForm()
|
||||
})
|
||||
}
|
||||
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = async (row?: any) => {
|
||||
dialog.visible = true
|
||||
dialog.title = '修改月度总结'
|
||||
nextTick(() => {
|
||||
const monthlyId = row?.monthlyId || ids.value[0]
|
||||
monthlyFormRef.value?.resetForm(monthlyId)
|
||||
})
|
||||
}
|
||||
|
||||
/** 查看详情操作 */
|
||||
const handleDetail = async (row: any) => {
|
||||
detailDialog.visible = true
|
||||
nextTick(() => {
|
||||
monthlyDetailRef.value?.resetForm(row.monthlyId)
|
||||
})
|
||||
}
|
||||
|
||||
/** 提交审批操作 */
|
||||
const handleSubmit = async (row: any) => {
|
||||
try {
|
||||
await proxy?.$modal.confirm('确认提交该月度总结?提交后将无法再次编辑')
|
||||
await submitInternshipMonthly(row.monthlyId)
|
||||
await getList()
|
||||
proxy?.$modal.msgSuccess('提交成功')
|
||||
} catch {}
|
||||
}
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (row?: any) => {
|
||||
const monthlyIds = row?.monthlyId || ids.value
|
||||
try {
|
||||
await proxy?.$modal.confirm('是否确认删除月度总结编号为"' + monthlyIds + '"的数据项?')
|
||||
await delInternshipMonthly(monthlyIds)
|
||||
await getList()
|
||||
proxy?.$modal.msgSuccess('删除成功')
|
||||
} catch {}
|
||||
}
|
||||
|
||||
/** 导出按钮操作 */
|
||||
const handleExport = () => {
|
||||
proxy?.$download('zsjy/internship/monthly/export', {
|
||||
...queryParams.value
|
||||
}, `月度总结_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
|
||||
/** 计算五项技能的平均分 */
|
||||
const getAverageScore = (row: any) => {
|
||||
const scores = [
|
||||
row.professionalSkills || 0,
|
||||
row.communicationSkills || 0,
|
||||
row.teamworkAbility || 0,
|
||||
row.learningAbility || 0,
|
||||
row.workAttitude || 0
|
||||
].filter(score => score > 0)
|
||||
|
||||
if (scores.length === 0) return 0
|
||||
return scores.reduce((sum, score) => sum + score, 0) / scores.length
|
||||
}
|
||||
|
||||
/** 根据分数获取标签类型 */
|
||||
const getScoreTagType = (score: number) => {
|
||||
if (score >= 9) return 'success'
|
||||
if (score >= 7) return 'warning'
|
||||
if (score >= 5) return ''
|
||||
return 'danger'
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 操作按钮样式优化 - 参考后勤管理页面 */
|
||||
:deep(.el-table__fixed-right) {
|
||||
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
:deep(.el-table__fixed-right .el-table__cell) {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
:deep(.el-table__row:hover .el-table__cell) {
|
||||
background-color: #f5f7fa !important;
|
||||
}
|
||||
|
||||
/* 操作列按钮间距优化 */
|
||||
.small-padding .el-button + .el-button {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
/* 确保操作按钮在固定列中居中对齐 */
|
||||
.small-padding {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.small-padding .el-tooltip {
|
||||
display: inline-block;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.small-padding .el-tooltip:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
/* 分页容器样式 */
|
||||
.pagination-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 16px 20px 0 0 !important;
|
||||
background-color: #fff;
|
||||
margin-top: 0px !important;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user