diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workrecord/MesProWorkrecordController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workrecord/MesProWorkrecordController.java new file mode 100644 index 0000000..3da9ca8 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workrecord/MesProWorkrecordController.java @@ -0,0 +1,154 @@ +package cn.iocoder.yudao.module.mes.controller.admin.pro.workrecord; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.mes.controller.admin.pro.workrecord.vo.MesProWorkRecordLogPageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.pro.workrecord.vo.MesProWorkRecordLogRespVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workrecord.MesProWorkRecordDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workrecord.MesProWorkRecordLogDO; +import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationService; +import cn.iocoder.yudao.module.mes.service.pro.workrecord.MesProWorkRecordService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - MES 工作记录") +@RestController +@RequestMapping("/mes/pro/workrecord") +@Validated +public class MesProWorkRecordController { + + @Resource + private MesProWorkRecordService workRecordService; + @Resource + private MesMdWorkstationService workstationService; + + @Resource + private AdminUserApi adminUserApi; + + @GetMapping("/log/page") + @Operation(summary = "获得工作记录流水分页") + @PreAuthorize("@ss.hasPermission('mes:pro-workrecord:query')") + public CommonResult> getWorkRecordLogPage( + @Valid MesProWorkRecordLogPageReqVO pageReqVO) { + PageResult pageResult = workRecordService.getWorkRecordLogPage(pageReqVO); + return success(new PageResult<>(buildWorkRecordLogRespVOList(pageResult.getList()), pageResult.getTotal())); + } + + @GetMapping("/log/get") + @Operation(summary = "获得工作记录流水") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('mes:pro-workrecord:query')") + public CommonResult getWorkRecordLog(@RequestParam("id") Long id) { + MesProWorkRecordLogDO log = workRecordService.getWorkRecordLog(id); + return success(buildWorkRecordLogRespVO(log)); + } + + @GetMapping("/log/export-excel") + @Operation(summary = "导出工作记录 Excel") + @PreAuthorize("@ss.hasPermission('mes:pro-workrecord:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportWorkRecordLogExcel(@Valid MesProWorkRecordLogPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = workRecordService.getWorkRecordLogPage(pageReqVO).getList(); + List voList = buildWorkRecordLogRespVOList(list); + ExcelUtils.write(response, "工作记录.xls", "数据", MesProWorkRecordLogRespVO.class, voList); + } + + @PutMapping("/clock-in") + @Operation(summary = "上线(绑定工作站)") + @Parameter(name = "workstationId", description = "工作站编号", required = true) + @PreAuthorize("@ss.hasPermission('mes:pro-workrecord:clock')") + public CommonResult clockInWorkRecord(@RequestParam("workstationId") Long workstationId) { + return success(workRecordService.clockInWorkRecord(getLoginUserId(), workstationId)); + } + + @PutMapping("/clock-out") + @Operation(summary = "下线(解绑工作站)") + @PreAuthorize("@ss.hasPermission('mes:pro-workrecord:clock')") + public CommonResult clockOutWorkRecord() { + return success(workRecordService.clockOutWorkRecord(getLoginUserId())); + } + + @GetMapping("/get-my") + @Operation(summary = "获取当前用户绑定的工作站状态") + @PreAuthorize("@ss.hasPermission('mes:pro-workrecord:query')") + public CommonResult getMyWorkRecord() { + MesProWorkRecordDO record = workRecordService.getWorkRecord(getLoginUserId()); + return success(buildWorkRecordRespVO(record)); + } + + // ==================== 拼接 VO ==================== + + private MesProWorkRecordLogRespVO buildWorkRecordLogRespVO(MesProWorkRecordLogDO log) { + if (log == null) { + return null; + } + return buildWorkRecordLogRespVOList(Collections.singletonList(log)).get(0); + } + + private List buildWorkRecordLogRespVOList(List list) { + if (CollUtil.isEmpty(list)) { + return Collections.emptyList(); + } + // 1. 查询相关数据 + Map userMap = adminUserApi.getUserMap( + convertSet(list, MesProWorkRecordLogDO::getUserId)); + Map workstationMap = workstationService.getWorkstationMap( + convertSet(list, MesProWorkRecordLogDO::getWorkstationId)); + // 2. 拼接 VO + return BeanUtils.toBean(list, MesProWorkRecordLogRespVO.class, vo -> { + findAndThen(userMap, vo.getUserId(), user -> + vo.setUserNickname(user.getNickname())); + findAndThen(workstationMap, vo.getWorkstationId(), ws -> + vo.setWorkstationCode(ws.getCode()).setWorkstationName(ws.getName())); + }); + } + + private MesProWorkRecordLogRespVO buildWorkRecordRespVO(MesProWorkRecordDO record) { + if (record == null) { + return null; + } + MesProWorkRecordLogRespVO vo = new MesProWorkRecordLogRespVO() + .setUserId(record.getUserId()).setWorkstationId(record.getWorkstationId()) + .setCreateTime(record.getClockInTime()); // 前端显示为上工时间 + // 拼接工作站信息 + MesMdWorkstationDO ws = workstationService.getWorkstation(record.getWorkstationId()); + if (ws != null) { + vo.setWorkstationCode(ws.getCode()).setWorkstationName(ws.getName()); + } + // 拼接用户信息 + AdminUserRespDTO user = adminUserApi.getUser(record.getUserId()); + if (user != null) { + vo.setUserNickname(user.getNickname()); + } + return vo; + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workrecord/vo/MesProWorkRecordLogPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workrecord/vo/MesProWorkRecordLogPageReqVO.java new file mode 100644 index 0000000..10d69ea --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workrecord/vo/MesProWorkRecordLogPageReqVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.mes.controller.admin.pro.workrecord.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - MES 上下工记录流水分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MesProWorkRecordLogPageReqVO extends PageParam { + + @Schema(description = "用户编号", example = "1") + private Long userId; + + @Schema(description = "工作站编号", example = "1") + private Long workstationId; + + @Schema(description = "操作类型(1=上工 2=下工)", example = "1") + private Integer type; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workrecord/vo/MesProWorkRecordLogRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workrecord/vo/MesProWorkRecordLogRespVO.java new file mode 100644 index 0000000..3177790 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workrecord/vo/MesProWorkRecordLogRespVO.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.mes.controller.admin.pro.workrecord.vo; + +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import cn.iocoder.yudao.module.mes.enums.DictTypeConstants; +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - MES 上下工记录流水 Response VO") +@Data +@Accessors(chain = true) +@ExcelIgnoreUnannotated +public class MesProWorkRecordLogRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "用户编号", example = "1") + private Long userId; + + @Schema(description = "用户昵称", example = "张三") + @ExcelProperty("用户昵称") + private String userNickname; + + @Schema(description = "工作站编号", example = "1") + private Long workstationId; + + @Schema(description = "工作站编码", example = "WS-001") + @ExcelProperty("工作站编码") + private String workstationCode; + + @Schema(description = "工作站名称", example = "注塑工作站") + @ExcelProperty("工作站名称") + private String workstationName; + + @Schema(description = "操作类型(1=上工 2=下工)", example = "1") + @ExcelProperty(value = "操作类型", converter = DictConvert.class) + @DictFormat(DictTypeConstants.MES_PRO_WORK_RECORD_TYPE) + private Integer type; + + @Schema(description = "备注", example = "备注") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workrecord/MesProWorkRecordLogDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workrecord/MesProWorkRecordLogDO.java new file mode 100644 index 0000000..84cfcd9 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workrecord/MesProWorkRecordLogDO.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.mes.dal.dataobject.pro.workrecord; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO; +import cn.iocoder.yudao.module.mes.enums.pro.MesProWorkRecordTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * MES 上下工记录流水 DO + * + * @author 芋道源码 + */ +@TableName("mes_pro_work_record_log") +@KeySequence("mes_pro_work_record_log_seq") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MesProWorkRecordLogDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 用户编号 + * + * 关联 AdminUserDO#getId() + */ + private Long userId; + /** + * 工作站编号 + * + * 关联 {@link MesMdWorkstationDO#getId()} + */ + private Long workstationId; + /** + * 操作类型 + * + * 枚举 {@link MesProWorkRecordTypeEnum} + */ + private Integer type; + /** + * 备注 + */ + private String remark; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workrecord/MesProWorkrecordDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workrecord/MesProWorkrecordDO.java new file mode 100644 index 0000000..b10c5e8 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/workrecord/MesProWorkrecordDO.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.mes.dal.dataobject.pro.workrecord; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkstationDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.time.LocalDateTime; + +/** + * MES 用户工作站绑定关系(当前快照) DO + * + * @author 芋道源码 + */ +@TableName("mes_pro_work_record") +@KeySequence("mes_pro_work_record_seq") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MesProWorkRecordDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 用户编号 + * + * 关联 AdminUserDO#getId() + */ + private Long userId; + /** + * 工作站编号 + * + * 关联 {@link MesMdWorkstationDO#getId()} + */ + private Long workstationId; + /** + * 当前状态 + * + * 枚举 {@link cn.iocoder.yudao.module.mes.enums.pro.MesProWorkRecordTypeEnum} + */ + private Integer type; + /** + * 上工时间 + */ + private LocalDateTime clockInTime; + /** + * 下工时间 + */ + private LocalDateTime clockOutTime; + /** + * 备注 + */ + private String remark; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workrecord/MesProWorkRecordLogMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workrecord/MesProWorkRecordLogMapper.java new file mode 100644 index 0000000..487736a --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workrecord/MesProWorkRecordLogMapper.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.mes.dal.mysql.pro.workrecord; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.mes.controller.admin.pro.workrecord.vo.MesProWorkRecordLogPageReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workrecord.MesProWorkRecordLogDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * MES 上下工记录流水 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface MesProWorkRecordLogMapper extends BaseMapperX { + + default PageResult selectPage(MesProWorkRecordLogPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(MesProWorkRecordLogDO::getUserId, reqVO.getUserId()) + .eqIfPresent(MesProWorkRecordLogDO::getWorkstationId, reqVO.getWorkstationId()) + .eqIfPresent(MesProWorkRecordLogDO::getType, reqVO.getType()) + .betweenIfPresent(MesProWorkRecordLogDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(MesProWorkRecordLogDO::getId)); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workrecord/MesProWorkrecordMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workrecord/MesProWorkrecordMapper.java new file mode 100644 index 0000000..43e5bfc --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workrecord/MesProWorkrecordMapper.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.mes.dal.mysql.pro.workrecord; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workrecord.MesProWorkRecordDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * MES 当前绑定状态(快照) Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface MesProWorkRecordMapper extends BaseMapperX { + + default MesProWorkRecordDO selectByUserId(Long userId) { + return selectOne(new LambdaQueryWrapperX() + .eq(MesProWorkRecordDO::getUserId, userId)); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/DictTypeConstants.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/DictTypeConstants.java index cc28487..b4d518c 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/DictTypeConstants.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/DictTypeConstants.java @@ -43,6 +43,7 @@ public interface DictTypeConstants { String MES_DV_REPAIR_RESULT = "mes_dv_repair_result"; // MES 维修结果 String MES_PRO_ANDON_STATUS = "mes_pro_andon_status"; // MES 安灯处置状态 String MES_PRO_ANDON_LEVEL = "mes_pro_andon_level"; // MES 安灯级别 + String MES_PRO_WORK_RECORD_TYPE = "mes_pro_work_record_type"; // MES 上下工状态类型 String MES_PRO_FEEDBACK_STATUS = "mes_pro_feedback_status"; // MES 生产报工状态 String MES_PRO_FEEDBACK_TYPE = "mes_pro_feedback_type"; // MES 生产报工类型 String MES_PRO_FEEDBACK_CHANNEL = "mes_pro_feedback_channel"; // MES 生产报工途径 diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java index 3744ef3..8742f0c 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java @@ -281,6 +281,10 @@ public interface ErrorCodeConstants { // ========== MES 生产管理-流转卡工序(1-040-507-100) ========== ErrorCode PRO_CARD_PROCESS_NOT_EXISTS = new ErrorCode(1_040_507_100, "流转卡工序记录不存在"); + // ========== MES 生产管理-工作记录(1-040-508-000) ========== + ErrorCode WORK_RECORD_WORKSTATION_NOT_EXISTS = new ErrorCode(1_040_508_000, "工作站不存在"); + ErrorCode WORK_RECORD_NOT_CLOCK_IN = new ErrorCode(1_040_508_001, "当前用户未上工,无法下工"); + // ========== MES 质量管理-质检方案(1-040-600-000) ========== ErrorCode QC_TEMPLATE_NOT_EXISTS = new ErrorCode(1_040_600_000, "质检方案不存在"); ErrorCode QC_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1_040_600_001, "质检方案编号已存在"); diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkRecordTypeEnum.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkRecordTypeEnum.java new file mode 100644 index 0000000..1629a0e --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkRecordTypeEnum.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.mes.enums.pro; + +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * MES 上下工操作类型枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum MesProWorkRecordTypeEnum implements ArrayValuable { + + CLOCK_IN(1, "上工"), + CLOCK_OUT(2, "下工"); + + public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesProWorkRecordTypeEnum::getType).toArray(Integer[]::new); + + /** + * 操作类型 + */ + private final Integer type; + /** + * 操作名 + */ + private final String name; + + @Override + public Integer[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workrecord/MesProWorkrecordService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workrecord/MesProWorkrecordService.java new file mode 100644 index 0000000..a69a888 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workrecord/MesProWorkrecordService.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.mes.service.pro.workrecord; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mes.controller.admin.pro.workrecord.vo.MesProWorkRecordLogPageReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workrecord.MesProWorkRecordDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workrecord.MesProWorkRecordLogDO; + +/** + * MES 工作记录 Service 接口 + * + * @author 芋道源码 + */ +public interface MesProWorkRecordService { + + /** + * 获得上下工记录流水分页 + * + * @param pageReqVO 分页查询 + * @return 上下工记录流水分页 + */ + PageResult getWorkRecordLogPage(MesProWorkRecordLogPageReqVO pageReqVO); + + /** + * 获得上下工记录流水 + * + * @param id 编号 + * @return 上下工记录流水 + */ + MesProWorkRecordLogDO getWorkRecordLog(Long id); + + /** + * 上线(绑定工作站) + * + * @param userId 用户编号 + * @param workstationId 工作站编号 + * @return 记录编号 + */ + Long clockInWorkRecord(Long userId, Long workstationId); + + /** + * 下线(解绑工作站) + * + * @param userId 用户编号 + * @return 记录编号 + */ + Long clockOutWorkRecord(Long userId); + + /** + * 获取指定用户当前的绑定状态 + * + * @param userId 用户编号 + * @return 绑定关系,如果未绑定则返回 null + */ + MesProWorkRecordDO getWorkRecord(Long userId); + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workrecord/MesProWorkrecordServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workrecord/MesProWorkrecordServiceImpl.java new file mode 100644 index 0000000..2dde653 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workrecord/MesProWorkrecordServiceImpl.java @@ -0,0 +1,99 @@ +package cn.iocoder.yudao.module.mes.service.pro.workrecord; + +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mes.controller.admin.pro.workrecord.vo.MesProWorkRecordLogPageReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workrecord.MesProWorkRecordDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workrecord.MesProWorkRecordLogDO; +import cn.iocoder.yudao.module.mes.dal.mysql.pro.workrecord.MesProWorkRecordLogMapper; +import cn.iocoder.yudao.module.mes.dal.mysql.pro.workrecord.MesProWorkRecordMapper; +import cn.iocoder.yudao.module.mes.enums.pro.MesProWorkRecordTypeEnum; +import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationService; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WORK_RECORD_NOT_CLOCK_IN; + +/** + * MES 工作记录 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class MesProWorkRecordServiceImpl implements MesProWorkRecordService { + + @Resource + private MesProWorkRecordLogMapper workRecordLogMapper; + @Resource + private MesProWorkRecordMapper workRecordMapper; + @Resource + private MesMdWorkstationService workstationService; + + @Override + public PageResult getWorkRecordLogPage(MesProWorkRecordLogPageReqVO pageReqVO) { + return workRecordLogMapper.selectPage(pageReqVO); + } + + @Override + public MesProWorkRecordLogDO getWorkRecordLog(Long id) { + return workRecordLogMapper.selectById(id); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Long clockInWorkRecord(Long userId, Long workstationId) { + // 1. 校验工作站是否存在 + workstationService.validateWorkstationExists(workstationId); + + // 2. 写入上线流水 + MesProWorkRecordLogDO log = MesProWorkRecordLogDO.builder().userId(userId) + .workstationId(workstationId).type(MesProWorkRecordTypeEnum.CLOCK_IN.getType()).build(); + workRecordLogMapper.insert(log); + + // 3. 更新用户工作站状态:如果没有记录,或先删除旧记录 + MesProWorkRecordDO record = workRecordMapper.selectByUserId(userId); + if (record == null) { + record = MesProWorkRecordDO.builder().userId(userId).workstationId(workstationId) + .type(MesProWorkRecordTypeEnum.CLOCK_IN.getType()).clockInTime(LocalDateTime.now()).build(); + workRecordMapper.insert(record); + } else { + workRecordMapper.updateById(new MesProWorkRecordDO().setId(record.getId()) + .setWorkstationId(workstationId).setType(MesProWorkRecordTypeEnum.CLOCK_IN.getType()) + .setClockInTime(LocalDateTime.now())); + } + return log.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Long clockOutWorkRecord(Long userId) { + // 1. 校验是否有状态 + MesProWorkRecordDO record = workRecordMapper.selectByUserId(userId); + if (record == null || ObjUtil.notEqual(MesProWorkRecordTypeEnum.CLOCK_IN.getType(), record.getType())) { + throw exception(WORK_RECORD_NOT_CLOCK_IN); + } + + // 2. 写入下线流水 + MesProWorkRecordLogDO log = MesProWorkRecordLogDO.builder().userId(userId) + .workstationId(record.getWorkstationId()).type(MesProWorkRecordTypeEnum.CLOCK_OUT.getType()) + .build(); + workRecordLogMapper.insert(log); + + // 3. 更新用户状态 + workRecordMapper.updateById(new MesProWorkRecordDO().setId(record.getId()) + .setType(MesProWorkRecordTypeEnum.CLOCK_OUT.getType()).setClockOutTime(LocalDateTime.now())); + return log.getId(); + } + + @Override + public MesProWorkRecordDO getWorkRecord(Long userId) { + return workRecordMapper.selectByUserId(userId); + } + +}