diff --git a/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/controller/ZsjyInternshipDailyController.java b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/controller/ZsjyInternshipDailyController.java new file mode 100644 index 00000000..2c11b2fe --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/controller/ZsjyInternshipDailyController.java @@ -0,0 +1,101 @@ +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.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.zsjy.domain.bo.ZsjyInternshipDailyAddBo; +import org.dromara.zsjy.domain.bo.ZsjyInternshipDailyQueryBo; +import org.dromara.zsjy.domain.vo.ZsjyInternshipDailyVo; +import org.dromara.zsjy.service.IZsjyInternshipDailyService; +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/daily") +@Tag(name = "实习日常管理", description = "学生实习日常打卡签到管理") +public class ZsjyInternshipDailyController extends BaseController { + + private final IZsjyInternshipDailyService dailyService; + + /** + * 查询实习日常记录列表 + */ + @Operation(summary = "查询实习日常记录列表", description = "班主任查看学生实习日常记录") + @SaCheckPermission("zsjy:internshipdaily:list") + @GetMapping("/list") + public TableDataInfo list(@Validated ZsjyInternshipDailyQueryBo queryBo, PageQuery pageQuery) { + log.info("=== Controller层调试 ==="); + log.info("接口被调用: /zsjy/internship/daily/list"); + log.info("查询参数: {}", queryBo); + log.info("分页参数: {}", pageQuery); + + return dailyService.queryPageList(queryBo, pageQuery); + } + + /** + * 学生签到打卡 + */ + @Operation(summary = "学生签到打卡", description = "学生进行实习日常签到打卡") + @SaCheckPermission("zsjy:internshipdaily:checkin") + @PostMapping("/checkin") + public R checkIn(@Validated(AddGroup.class) @RequestBody ZsjyInternshipDailyAddBo addBo) { + log.info("=== Controller层调试 ==="); + log.info("接口被调用: /zsjy/internship/daily/checkin"); + log.info("签到参数: {}", addBo); + + return dailyService.checkIn(addBo); + } + + /** + * 获取学生考勤日历 + */ + @Operation(summary = "获取学生考勤日历", description = "查看指定学生的考勤日历数据") + @SaCheckPermission("zsjy:internshipdaily:calendar") + @GetMapping("/calendar/{studentId}") + public R>> getCalendar( + @Parameter(description = "学生ID", required = true) @PathVariable Long studentId, + @Parameter(description = "年份") @RequestParam(required = false) Integer year, + @Parameter(description = "月份") @RequestParam(required = false) Integer month) { + + log.info("=== Controller层调试 ==="); + log.info("接口被调用: /zsjy/internship/daily/calendar/{}", studentId); + log.info("查询年月: {}-{}", year, month); + + return dailyService.getCalendarData(studentId, year, month); + } + + /** + * 获取考勤统计数据 + */ + @Operation(summary = "获取考勤统计数据", description = "查看实习生考勤统计分析") + @SaCheckPermission("zsjy:internshipdaily:statistics") + @GetMapping("/statistics") + public R> getStatistics(@Validated ZsjyInternshipDailyQueryBo queryBo) { + log.info("=== Controller层调试 ==="); + log.info("接口被调用: /zsjy/internship/daily/statistics"); + log.info("统计参数: {}", queryBo); + + return dailyService.getStatistics(queryBo); + } + +} diff --git a/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/ZsjyInternshipDaily.java b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/ZsjyInternshipDaily.java new file mode 100644 index 00000000..38a5c471 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/ZsjyInternshipDaily.java @@ -0,0 +1,99 @@ +package org.dromara.zsjy.domain; + +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.sql.Time; +import java.util.Date; + +/** + * 实习日常管理实体对象 zsjy_internship_daily + * + * @author system + * @date 2025-01-03 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("zsjy_internship_daily") +public class ZsjyInternshipDaily extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 日常记录ID + */ + @TableId(value = "daily_id") + private Long dailyId; + + /** + * 实习ID + */ + private Long internshipId; + + /** + * 学生ID + */ + private Long studentId; + + /** + * 打卡日期 + */ + private Date checkDate; + + /** + * 签到时间 + */ + private Time checkInTime; + + /** + * 签到位置 + */ + private String checkInLocation; + + /** + * 纬度 + */ + private BigDecimal latitude; + + /** + * 经度 + */ + private BigDecimal longitude; + + /** + * 日总结 + */ + private String dailySummary; + + /** + * 图片附件(JSON格式) + */ + private String images; + + /** + * 是否异常(0正常 1异常) + */ + private String isException; + + /** + * 异常原因 + */ + private String exceptionReason; + + /** + * 异常处理状态(0待处理 1已处理) + */ + private String exceptionStatus; + + /** + * 状态(0正常 1停用) + */ + private String status; + +} diff --git a/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/ZsjyInternshipInfo.java b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/ZsjyInternshipInfo.java new file mode 100644 index 00000000..ab08c3b3 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/ZsjyInternshipInfo.java @@ -0,0 +1,163 @@ +package org.dromara.zsjy.domain; + +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_info + * + * @author system + * @date 2025-01-03 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("zsjy_internship_info") +public class ZsjyInternshipInfo extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 实习信息ID + */ + @TableId(value = "internship_id") + private Long internshipId; + + /** + * 学生ID + */ + private Long studentId; + + /** + * 学号 + */ + private String studentNo; + + /** + * 学生姓名 + */ + private String studentName; + + /** + * 性别 + */ + private String gender; + + /** + * 学院ID + */ + private Long collegeId; + + /** + * 专业ID + */ + private Long majorId; + + /** + * 班级ID + */ + private Long classId; + + /** + * 联系电话 + */ + private String phone; + + /** + * 实习单位名称 + */ + private String companyName; + + /** + * 实习单位地址 + */ + private String companyAddress; + + /** + * 行业类型 + */ + private String companyIndustry; + + /** + * 单位规模 + */ + private String companyScale; + + /** + * 单位联系人 + */ + private String companyContact; + + /** + * 联系人电话 + */ + private String companyPhone; + + /** + * 岗位名称 + */ + private String positionName; + + /** + * 岗位职责 + */ + private String positionDuties; + + /** + * 实习津贴 + */ + private BigDecimal internshipAllowance; + + /** + * 工作时长 + */ + private String workHours; + + /** + * 住宿地址 + */ + private String accommodationAddress; + + /** + * 住宿类型 + */ + private String accommodationType; + + /** + * 住宿费用 + */ + private BigDecimal accommodationCost; + + /** + * 实习开始日期 + */ + private Date startDate; + + /** + * 实习结束日期 + */ + private Date endDate; + + /** + * 实际结束日期 + */ + private Date actualEndDate; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 实习状态(1进行中 2已完成 3中断) + */ + private String internshipStatus; +} + \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/bo/InternshipInfoAddBO.java b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/bo/InternshipInfoAddBO.java new file mode 100644 index 00000000..752666cd --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/bo/InternshipInfoAddBO.java @@ -0,0 +1,167 @@ +package org.dromara.zsjy.domain.bo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Positive; +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 实习信息新增业务对象 InternshipInfoAddBO + * + * @author system + * @date 2025-01-03 + */ +@Data +@Schema(description = "实习信息新增业务对象") +public class InternshipInfoAddBO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 学生ID + */ + @Schema(description = "学生ID") + @NotNull(message = "学生ID不能为空", groups = {AddGroup.class}) + private Long studentId; + + /** + * 实习状态:1-进行中,2-已完成,3-已暂停,4-已终止 + */ + @Schema(description = "实习状态:1-进行中,2-已完成,3-已暂停,4-已终止") + @NotBlank(message = "实习状态不能为空", groups = {AddGroup.class}) + @Pattern(regexp = "^[1-4]$", message = "实习状态只能是1-进行中,2-已完成,3-已暂停,4-已终止", groups = {AddGroup.class}) + private String internshipStatus; + + /** + * 实习单位名称 + */ + @Schema(description = "实习单位名称") + @NotBlank(message = "实习单位名称不能为空", groups = {AddGroup.class}) + private String companyName; + + /** + * 实习单位地址 + */ + @Schema(description = "实习单位地址") + private String companyAddress; + + /** + * 单位联系人 + */ + @Schema(description = "单位联系人") + private String companyContact; + + /** + * 联系人电话 + */ + @Schema(description = "联系人电话") + @Pattern(regexp = "^1[3-9]\\d{9}$", message = "联系人电话格式不正确", groups = {AddGroup.class}) + private String companyPhone; + + /** + * 行业类型 + */ + @Schema(description = "行业类型") + private String companyIndustry; + + /** + * 单位规模 + */ + @Schema(description = "单位规模") + private String companyScale; + + /** + * 实习岗位 + */ + @Schema(description = "实习岗位") + @NotBlank(message = "实习岗位不能为空", groups = {AddGroup.class}) + private String internshipPosition; + + /** + * 实习薪资 + */ + @Schema(description = "实习薪资") + @Positive(message = "实习薪资必须大于0", groups = {AddGroup.class}) + private BigDecimal internshipAllowance; + + /** + * 实习开始时间 + */ + @Schema(description = "实习开始时间") + @JsonFormat(pattern = "yyyy-MM-dd") + @NotNull(message = "实习开始时间不能为空", groups = {AddGroup.class}) + private Date internshipStartDate; + + /** + * 实习结束时间 + */ + @Schema(description = "实习结束时间") + @JsonFormat(pattern = "yyyy-MM-dd") + private Date internshipEndDate; + + /** + * 联系人姓名 + */ + @Schema(description = "联系人姓名") + private String contactPersonName; + + /** + * 联系人电话 + */ + @Schema(description = "联系人电话") + @Pattern(regexp = "^1[3-9]\\d{9}$", message = "联系人电话格式不正确", groups = {AddGroup.class}) + private String contactPersonPhone; + + /** + * 岗位职责 + */ + @Schema(description = "岗位职责") + private String positionDuties; + + /** + * 工作时长 + */ + @Schema(description = "工作时长") + private String workHours; + + /** + * 住宿地址 + */ + @Schema(description = "住宿地址") + private String accommodationAddress; + + /** + * 住宿类型 + */ + @Schema(description = "住宿类型") + private String accommodationType; + + /** + * 住宿费用 + */ + @Schema(description = "住宿费用") + private BigDecimal accommodationCost; + + /** + * 实习协议状态:1-已签署,2-未签署 + */ + @Schema(description = "实习协议状态:1-已签署,2-未签署") + @Pattern(regexp = "^[1-2]$", message = "实习协议状态只能是1-已签署,2-未签署", groups = {AddGroup.class}) + private String agreementStatus; + + /** + * 备注信息 + */ + @Schema(description = "备注信息") + private String remark; +} diff --git a/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/bo/InternshipInfoEditBO.java b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/bo/InternshipInfoEditBO.java new file mode 100644 index 00000000..ca56629d --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/bo/InternshipInfoEditBO.java @@ -0,0 +1,174 @@ +package org.dromara.zsjy.domain.bo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.dromara.common.core.validate.EditGroup; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Positive; +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 实习信息修改业务对象 InternshipInfoEditBO + * + * @author system + * @date 2025-01-03 + */ +@Data +@Schema(description = "实习信息修改业务对象") +public class InternshipInfoEditBO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 实习信息ID + */ + @Schema(description = "实习信息ID") + @NotNull(message = "实习信息ID不能为空", groups = {EditGroup.class}) + private Long internshipId; + + /** + * 学生ID + */ + @Schema(description = "学生ID") + @NotNull(message = "学生ID不能为空", groups = {EditGroup.class}) + private Long studentId; + + /** + * 实习状态:1-进行中,2-已完成,3-已暂停,4-已终止 + */ + @Schema(description = "实习状态:1-进行中,2-已完成,3-已暂停,4-已终止") + @NotBlank(message = "实习状态不能为空", groups = {EditGroup.class}) + @Pattern(regexp = "^[1-4]$", message = "实习状态只能是1-进行中,2-已完成,3-已暂停,4-已终止", groups = {EditGroup.class}) + private String internshipStatus; + + /** + * 实习单位名称 + */ + @Schema(description = "实习单位名称") + @NotBlank(message = "实习单位名称不能为空", groups = {EditGroup.class}) + private String companyName; + + /** + * 实习单位地址 + */ + @Schema(description = "实习单位地址") + private String companyAddress; + + /** + * 单位联系人 + */ + @Schema(description = "单位联系人") + private String companyContact; + + /** + * 联系人电话 + */ + @Schema(description = "联系人电话") + @Pattern(regexp = "^1[3-9]\\d{9}$", message = "联系人电话格式不正确", groups = {EditGroup.class}) + private String companyPhone; + + /** + * 行业类型 + */ + @Schema(description = "行业类型") + private String companyIndustry; + + /** + * 单位规模 + */ + @Schema(description = "单位规模") + private String companyScale; + + /** + * 实习岗位 + */ + @Schema(description = "实习岗位") + @NotBlank(message = "实习岗位不能为空", groups = {EditGroup.class}) + private String internshipPosition; + + /** + * 实习薪资 + */ + @Schema(description = "实习薪资") + @Positive(message = "实习薪资必须大于0", groups = {EditGroup.class}) + private BigDecimal internshipAllowance; + + /** + * 实习开始时间 + */ + @Schema(description = "实习开始时间") + @JsonFormat(pattern = "yyyy-MM-dd") + @NotNull(message = "实习开始时间不能为空", groups = {EditGroup.class}) + private Date internshipStartDate; + + /** + * 实习结束时间 + */ + @Schema(description = "实习结束时间") + @JsonFormat(pattern = "yyyy-MM-dd") + private Date internshipEndDate; + + /** + * 联系人姓名 + */ + @Schema(description = "联系人姓名") + private String contactPersonName; + + /** + * 联系人电话 + */ + @Schema(description = "联系人电话") + @Pattern(regexp = "^1[3-9]\\d{9}$", message = "联系人电话格式不正确", groups = {EditGroup.class}) + private String contactPersonPhone; + + /** + * 岗位职责 + */ + @Schema(description = "岗位职责") + private String positionDuties; + + /** + * 工作时长 + */ + @Schema(description = "工作时长") + private String workHours; + + /** + * 住宿地址 + */ + @Schema(description = "住宿地址") + private String accommodationAddress; + + /** + * 住宿类型 + */ + @Schema(description = "住宿类型") + private String accommodationType; + + /** + * 住宿费用 + */ + @Schema(description = "住宿费用") + private BigDecimal accommodationCost; + + /** + * 实习协议状态:1-已签署,2-未签署 + */ + @Schema(description = "实习协议状态:1-已签署,2-未签署") + @Pattern(regexp = "^[1-2]$", message = "实习协议状态只能是1-已签署,2-未签署", groups = {EditGroup.class}) + private String agreementStatus; + + /** + * 备注信息 + */ + @Schema(description = "备注信息") + private String remark; +} diff --git a/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/bo/ZsjyInternshipDailyAddBo.java b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/bo/ZsjyInternshipDailyAddBo.java new file mode 100644 index 00000000..49e037d7 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/bo/ZsjyInternshipDailyAddBo.java @@ -0,0 +1,119 @@ +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.mybatis.core.domain.BaseEntity; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.io.Serial; +import java.math.BigDecimal; +import java.sql.Time; +import java.util.Date; + +/** + * 实习日常管理新增业务对象 ZsjyInternshipDailyAddBo + * + * @author system + * @date 2025-01-03 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Schema(description = "实习日常管理新增业务对象") +public class ZsjyInternshipDailyAddBo extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 实习ID + */ + @Schema(description = "实习ID", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "实习ID不能为空", groups = {AddGroup.class}) + private Long internshipId; + + /** + * 学生ID + */ + @Schema(description = "学生ID", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "学生ID不能为空", groups = {AddGroup.class}) + private Long studentId; + + /** + * 打卡日期 + */ + @Schema(description = "打卡日期", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "打卡日期不能为空", groups = {AddGroup.class}) + private Date checkDate; + + /** + * 签到时间 + */ + @Schema(description = "签到时间") + private Time checkInTime; + + /** + * 签到位置 + */ + @Schema(description = "签到位置") + @Size(max = 200, message = "签到位置长度不能超过200个字符") + private String checkInLocation; + + /** + * 纬度 + */ + @Schema(description = "纬度") + private BigDecimal latitude; + + /** + * 经度 + */ + @Schema(description = "经度") + private BigDecimal longitude; + + /** + * 日总结 + */ + @Schema(description = "日总结") + private String dailySummary; + + /** + * 图片附件(JSON格式) + */ + @Schema(description = "图片附件") + private String images; + + /** + * 是否异常(0正常 1异常) + */ + @Schema(description = "是否异常") + private String isException; + + /** + * 异常原因 + */ + @Schema(description = "异常原因") + @Size(max = 500, message = "异常原因长度不能超过500个字符") + private String exceptionReason; + + /** + * 异常处理状态(0待处理 1已处理) + */ + @Schema(description = "异常处理状态") + private String exceptionStatus; + + /** + * 状态(0正常 1停用) + */ + @Schema(description = "状态") + private String status; + + /** + * 备注 + */ + @Schema(description = "备注") + private String remark; + +} diff --git a/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/bo/ZsjyInternshipDailyQueryBo.java b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/bo/ZsjyInternshipDailyQueryBo.java new file mode 100644 index 00000000..6f0f040c --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/bo/ZsjyInternshipDailyQueryBo.java @@ -0,0 +1,85 @@ +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; + +import java.io.Serial; +import java.util.Date; + +/** + * 实习日常管理查询业务对象 ZsjyInternshipDailyQueryBo + * + * @author system + * @date 2025-01-03 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Schema(description = "实习日常管理查询业务对象") +public class ZsjyInternshipDailyQueryBo extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 学生ID + */ + @Schema(description = "学生ID") + private Long studentId; + + /** + * 学号 + */ + @Schema(description = "学号") + private String studentNo; + + /** + * 学生姓名 + */ + @Schema(description = "学生姓名") + private String studentName; + + /** + * 实习ID + */ + @Schema(description = "实习ID") + private Long internshipId; + + /** + * 打卡开始日期 + */ + @Schema(description = "打卡开始日期") + private Date checkDateStart; + + /** + * 打卡结束日期 + */ + @Schema(description = "打卡结束日期") + private Date checkDateEnd; + + /** + * 是否异常(0正常 1异常) + */ + @Schema(description = "是否异常") + private String isException; + + /** + * 异常处理状态(0待处理 1已处理) + */ + @Schema(description = "异常处理状态") + private String exceptionStatus; + + /** + * 状态(0正常 1停用) + */ + @Schema(description = "状态") + private String status; + + /** + * 公司名称 + */ + @Schema(description = "公司名称") + private String companyName; + +} diff --git a/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/vo/ZsjyInternshipDailyVo.java b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/vo/ZsjyInternshipDailyVo.java new file mode 100644 index 00000000..8f7e4844 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/domain/vo/ZsjyInternshipDailyVo.java @@ -0,0 +1,164 @@ +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.sql.Time; +import java.util.Date; + +/** + * 实习日常管理视图对象 ZsjyInternshipDailyVo + * + * @author system + * @date 2025-01-03 + */ +@Data +@Schema(description = "实习日常管理视图对象") +public class ZsjyInternshipDailyVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 日常记录ID + */ + @Schema(description = "日常记录ID") + private Long dailyId; + + /** + * 实习ID + */ + @Schema(description = "实习ID") + private Long internshipId; + + /** + * 学生ID + */ + @Schema(description = "学生ID") + private Long studentId; + + /** + * 打卡日期 + */ + @Schema(description = "打卡日期") + @JsonFormat(pattern = "yyyy-MM-dd") + private Date checkDate; + + /** + * 签到时间 + */ + @Schema(description = "签到时间") + @JsonFormat(pattern = "HH:mm:ss") + private Time checkInTime; + + /** + * 签到位置 + */ + @Schema(description = "签到位置") + private String checkInLocation; + + /** + * 纬度 + */ + @Schema(description = "纬度") + private BigDecimal latitude; + + /** + * 经度 + */ + @Schema(description = "经度") + private BigDecimal longitude; + + /** + * 日总结 + */ + @Schema(description = "日总结") + private String dailySummary; + + /** + * 图片附件(JSON格式) + */ + @Schema(description = "图片附件") + private String images; + + /** + * 是否异常(0正常 1异常) + */ + @Schema(description = "是否异常") + private String isException; + + /** + * 异常原因 + */ + @Schema(description = "异常原因") + private String exceptionReason; + + /** + * 异常处理状态(0待处理 1已处理) + */ + @Schema(description = "异常处理状态") + private String exceptionStatus; + + /** + * 状态(0正常 1停用) + */ + @Schema(description = "状态") + private String status; + + /** + * 备注 + */ + @Schema(description = "备注") + private String remark; + + // ============ 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; + + // ============ 扩展字段(用于页面显示) ============ + /** + * 学生姓名 + */ + @Schema(description = "学生姓名") + private String studentName; + + /** + * 学号 + */ + @Schema(description = "学号") + private String studentNo; + + /** + * 公司名称 + */ + @Schema(description = "公司名称") + private String companyName; + +} diff --git a/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/mapper/ZsjyInternshipDailyMapper.java b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/mapper/ZsjyInternshipDailyMapper.java new file mode 100644 index 00000000..7af7458d --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/mapper/ZsjyInternshipDailyMapper.java @@ -0,0 +1,64 @@ +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.Mapper; +import org.apache.ibatis.annotations.Param; +import org.dromara.zsjy.domain.ZsjyInternshipDaily; +import org.dromara.zsjy.domain.bo.ZsjyInternshipDailyQueryBo; +import org.dromara.zsjy.domain.vo.ZsjyInternshipDailyVo; + +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * 实习日常管理Mapper接口 + * + * @author system + * @date 2025-01-03 + */ +@Mapper +public interface ZsjyInternshipDailyMapper extends BaseMapper { + + /** + * 查询实习日常记录列表 + * + * @param page 分页参数(可选) + * @param queryBo 查询条件 + * @return 实习日常记录列表 + */ + List selectDailyList(@Param("page") Page page, + @Param("queryBo") ZsjyInternshipDailyQueryBo queryBo); + + /** + * 根据学生ID获取考勤日历数据 + * + * @param studentId 学生ID + * @param startDate 开始日期 + * @param endDate 结束日期 + * @return 考勤日历数据 + */ + List> selectCalendarData(@Param("studentId") Long studentId, + @Param("startDate") Date startDate, + @Param("endDate") Date endDate); + + /** + * 获取考勤统计数据 + * + * @param queryBo 查询条件 + * @return 统计数据 + */ + Map selectStatistics(@Param("queryBo") ZsjyInternshipDailyQueryBo queryBo); + + /** + * 检查学生当日是否已签到 + * + * @param studentId 学生ID + * @param checkDate 打卡日期 + * @return 是否已签到 + */ + boolean existsByStudentAndDate(@Param("studentId") Long studentId, + @Param("checkDate") Date checkDate); + +} diff --git a/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/mapper/ZsjyInternshipInfoMapper.java b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/mapper/ZsjyInternshipInfoMapper.java new file mode 100644 index 00000000..f04bce61 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/mapper/ZsjyInternshipInfoMapper.java @@ -0,0 +1,16 @@ +package org.dromara.zsjy.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.dromara.zsjy.domain.ZsjyInternshipInfo; +import org.apache.ibatis.annotations.Mapper; + +/** + * 实习信息Mapper接口 + * + * @author system + * @date 2025-01-03 + */ +@Mapper +public interface ZsjyInternshipInfoMapper extends BaseMapper { + +} diff --git a/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/service/IZsjyInternshipDailyService.java b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/service/IZsjyInternshipDailyService.java new file mode 100644 index 00000000..a5d0dbed --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/service/IZsjyInternshipDailyService.java @@ -0,0 +1,64 @@ +package org.dromara.zsjy.service; + +import org.dromara.common.core.domain.R; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.zsjy.domain.bo.ZsjyInternshipDailyAddBo; +import org.dromara.zsjy.domain.bo.ZsjyInternshipDailyQueryBo; +import org.dromara.zsjy.domain.vo.ZsjyInternshipDailyVo; + +import java.util.List; +import java.util.Map; + +/** + * 实习日常管理Service接口 + * + * @author system + * @date 2025-01-03 + */ +public interface IZsjyInternshipDailyService { + + /** + * 查询实习日常记录分页列表 + * + * @param queryBo 查询条件 + * @param pageQuery 分页参数 + * @return 实习日常记录分页列表 + */ + TableDataInfo queryPageList(ZsjyInternshipDailyQueryBo queryBo, PageQuery pageQuery); + + /** + * 查询实习日常记录列表(不分页) + * + * @param queryBo 查询条件 + * @return 实习日常记录列表 + */ + List queryList(ZsjyInternshipDailyQueryBo queryBo); + + /** + * 学生签到打卡 + * + * @param addBo 签到信息 + * @return 签到结果 + */ + R checkIn(ZsjyInternshipDailyAddBo addBo); + + /** + * 根据学生ID获取考勤日历数据 + * + * @param studentId 学生ID + * @param year 年份 + * @param month 月份 + * @return 考勤日历数据 + */ + R>> getCalendarData(Long studentId, Integer year, Integer month); + + /** + * 获取考勤统计数据 + * + * @param queryBo 查询条件 + * @return 统计数据 + */ + R> getStatistics(ZsjyInternshipDailyQueryBo queryBo); + +} diff --git a/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/service/impl/ZsjyInternshipDailyServiceImpl.java b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/service/impl/ZsjyInternshipDailyServiceImpl.java new file mode 100644 index 00000000..20ba3a91 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/service/impl/ZsjyInternshipDailyServiceImpl.java @@ -0,0 +1,164 @@ +package org.dromara.zsjy.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.MapstructUtils; +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.ZsjyInternshipDaily; +import org.dromara.zsjy.domain.bo.ZsjyInternshipDailyAddBo; +import org.dromara.zsjy.domain.bo.ZsjyInternshipDailyQueryBo; +import org.dromara.zsjy.domain.vo.ZsjyInternshipDailyVo; +import org.dromara.zsjy.mapper.ZsjyInternshipDailyMapper; +import org.dromara.zsjy.service.IZsjyInternshipDailyService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.sql.Time; +import java.time.LocalDateTime; +import java.time.YearMonth; +import java.util.*; + +/** + * 实习日常管理Service业务层处理 + * + * @author system + * @date 2025-01-03 + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class ZsjyInternshipDailyServiceImpl implements IZsjyInternshipDailyService { + + private final ZsjyInternshipDailyMapper baseMapper; + + /** + * 查询实习日常记录分页列表 + */ + @Override + public TableDataInfo queryPageList(ZsjyInternshipDailyQueryBo queryBo, PageQuery pageQuery) { + Page page = pageQuery.build(); + List list = baseMapper.selectDailyList(page, queryBo); + return TableDataInfo.build(page); + } + + /** + * 查询实习日常记录列表(不分页) + */ + @Override + public List queryList(ZsjyInternshipDailyQueryBo queryBo) { + return baseMapper.selectDailyList(null, queryBo); + } + + /** + * 学生签到打卡 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public R checkIn(ZsjyInternshipDailyAddBo addBo) { + try { + // 1. 验证学生当日是否已签到 + boolean exists = baseMapper.existsByStudentAndDate(addBo.getStudentId(), addBo.getCheckDate()); + if (exists) { + return R.fail("今日已签到,请勿重复签到"); + } + + // 2. 构建实体对象 + ZsjyInternshipDaily entity = MapstructUtils.convert(addBo, ZsjyInternshipDaily.class); + + // 3. 设置签到时间为当前时间 + if (ObjectUtil.isNull(entity.getCheckInTime())) { + entity.setCheckInTime(Time.valueOf(DateUtil.format(new Date(), "HH:mm:ss"))); + } + + // 4. 设置默认值 + if (ObjectUtil.isNull(entity.getIsException())) { + entity.setIsException("0"); // 默认正常 + } + if (ObjectUtil.isNull(entity.getExceptionStatus())) { + entity.setExceptionStatus("0"); // 默认待处理 + } + if (ObjectUtil.isNull(entity.getStatus())) { + entity.setStatus("0"); // 默认正常 + } + + // 5. 保存签到记录 + boolean result = baseMapper.insert(entity) > 0; + if (!result) { + return R.fail("签到失败,请稍后重试"); + } + + log.info("学生[{}]于{}成功签到", addBo.getStudentId(), addBo.getCheckDate()); + return R.ok("签到成功"); + + } catch (Exception e) { + log.error("学生签到失败: {}", e.getMessage(), e); + throw new ServiceException("签到失败: " + e.getMessage()); + } + } + + /** + * 根据学生ID获取考勤日历数据 + */ + @Override + public R>> getCalendarData(Long studentId, Integer year, Integer month) { + try { + // 1. 参数校验 + if (ObjectUtil.isNull(studentId)) { + return R.fail("学生ID不能为空"); + } + if (ObjectUtil.isNull(year) || ObjectUtil.isNull(month)) { + return R.fail("年份和月份不能为空"); + } + + // 2. 计算日期范围 + YearMonth yearMonth = YearMonth.of(year, month); + Date startDate = DateUtil.beginOfMonth(DateUtil.parse(yearMonth + "-01")); + Date endDate = DateUtil.endOfMonth(startDate); + + // 3. 查询考勤数据 + List> calendarData = baseMapper.selectCalendarData(studentId, startDate, endDate); + + return R.ok(calendarData); + + } catch (Exception e) { + log.error("获取考勤日历数据失败: {}", e.getMessage(), e); + return R.fail("获取考勤日历数据失败: " + e.getMessage()); + } + } + + /** + * 获取考勤统计数据 + */ + @Override + public R> getStatistics(ZsjyInternshipDailyQueryBo queryBo) { + try { + // 1. 查询统计数据 + Map statistics = baseMapper.selectStatistics(queryBo); + + // 2. 补充统计信息 + if (ObjectUtil.isNull(statistics)) { + statistics = new HashMap<>(); + statistics.put("totalDays", 0); + statistics.put("attendanceDays", 0); + statistics.put("exceptionDays", 0); + statistics.put("pendingExceptions", 0); + statistics.put("attendanceRate", 0.0); + } + + return R.ok(statistics); + + } catch (Exception e) { + log.error("获取考勤统计数据失败: {}", e.getMessage(), e); + return R.fail("获取考勤统计数据失败: " + e.getMessage()); + } + } + +} diff --git a/backend/ruoyi-modules/ruoyi-zsjy/src/main/resources/mapper/ZsjyInternshipDailyMapper.xml b/backend/ruoyi-modules/ruoyi-zsjy/src/main/resources/mapper/ZsjyInternshipDailyMapper.xml new file mode 100644 index 00000000..55e10ec7 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-zsjy/src/main/resources/mapper/ZsjyInternshipDailyMapper.xml @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SELECT + d.daily_id, + d.internship_id, + d.student_id, + d.check_date, + d.check_in_time, + d.check_in_location, + d.latitude, + d.longitude, + d.daily_summary, + d.images, + d.is_exception, + d.exception_reason, + d.exception_status, + d.status, + d.remark, + d.create_by, + d.create_time, + d.update_by, + d.update_time, + -- 关联查询扩展字段 + i.student_name, + i.student_no, + i.company_name + FROM zsjy_internship_daily d + LEFT JOIN zsjy_internship_info i ON d.internship_id = i.internship_id + + + + + + + + + + + + + + + diff --git a/web/src/api/zsjy/internshipDaily.js b/web/src/api/zsjy/internshipDaily.js new file mode 100644 index 00000000..2772d03d --- /dev/null +++ b/web/src/api/zsjy/internshipDaily.js @@ -0,0 +1,46 @@ +import request from '@/utils/request' + +// 查询实习日常记录列表 +export function listInternshipDaily(query) { + return request({ + url: '/zsjy/internship/daily/list', + method: 'get', + params: query + }) +} + +// 学生签到打卡 +export function checkIn(data) { + return request({ + url: '/zsjy/internship/daily/checkin', + method: 'post', + data: data + }) +} + +// 新增实习日常记录 +export function addInternshipDaily(data) { + return request({ + url: '/zsjy/internship/daily', + method: 'post', + data: data + }) +} + +// 获取学生考勤日历 +export function getCalendar(studentId, params) { + return request({ + url: `/zsjy/internship/daily/calendar/${studentId}`, + method: 'get', + params: params + }) +} + +// 获取考勤统计数据 +export function getStatistics(query) { + return request({ + url: '/zsjy/internship/daily/statistics', + method: 'get', + params: query + }) +} diff --git a/web/src/views/zsjy/internship/daily/checkin.vue b/web/src/views/zsjy/internship/daily/checkin.vue new file mode 100644 index 00000000..0c736d48 --- /dev/null +++ b/web/src/views/zsjy/internship/daily/checkin.vue @@ -0,0 +1,695 @@ + + + + + diff --git a/web/src/views/zsjy/internship/daily/index.vue b/web/src/views/zsjy/internship/daily/index.vue new file mode 100644 index 00000000..5a132e2b --- /dev/null +++ b/web/src/views/zsjy/internship/daily/index.vue @@ -0,0 +1,899 @@ + + + + + diff --git a/web/src/views/zsjy/internship/msgmanage/components/AddDialog.vue b/web/src/views/zsjy/internship/msgmanage/components/AddDialog.vue new file mode 100644 index 00000000..fa6cbe23 --- /dev/null +++ b/web/src/views/zsjy/internship/msgmanage/components/AddDialog.vue @@ -0,0 +1,366 @@ + + + + + + \ No newline at end of file diff --git a/web/src/views/zsjy/internship/msgmanage/components/EditDialog.vue b/web/src/views/zsjy/internship/msgmanage/components/EditDialog.vue new file mode 100644 index 00000000..ed0071c3 --- /dev/null +++ b/web/src/views/zsjy/internship/msgmanage/components/EditDialog.vue @@ -0,0 +1,437 @@ + + + + + + \ No newline at end of file