Compare commits

..

4 Commits

@ -115,7 +115,7 @@ public class BaogongRecordController {
@GetMapping("/page")
@Operation(summary = "获得报工分页")
@PreAuthorize("@ss.hasPermission('mes:baogong-record:query')")
public CommonResult<PageResult<BaogongRecordRespVO>> getBaogongRecordPage(@Valid BaogongRecordPageReqVO pageReqVO) {
public CommonResult<PageResult<BaogongRecordRespVO>> getBaogongRecordPage(@Valid BaogongRecordPageReqVO pageReqVO) {
PageResult<BaogongRecordDO> pageResult = baogongRecordService.getBaogongRecordPage(pageReqVO);
return success(new PageResult<>(buildVOList(pageResult.getList()), pageResult.getTotal()));
}
@ -145,4 +145,30 @@ public class BaogongRecordController {
BeanUtils.toBean(list, BaogongRecordRespVO.class));
}
@GetMapping("/stat-page")
@Operation(summary = "报工统计分页")
@PreAuthorize("@ss.hasPermission('mes:baogong-record:query')")
public CommonResult<PageResult<BaogongRecordStatRespVO>> getBaogongRecordStatPage(@Valid BaogongRecordStatPageReqVO reqVO) {
return success(baogongRecordService.getBaogongRecordStatPage(reqVO));
}
@GetMapping("/stat-export-excel")
@Operation(summary = "导出报工统计 Excel")
@PreAuthorize("@ss.hasPermission('mes:baogong-record:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportBaogongRecordStatExcel(@Valid BaogongRecordStatPageReqVO reqVO,
HttpServletResponse response) throws IOException {
reqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<BaogongRecordStatRespVO> list = baogongRecordService.getBaogongRecordStatPage(reqVO).getList();
ExcelUtils.write(response, "报工统计.xls", "数据", BaogongRecordStatRespVO.class, list);
}
@GetMapping("/trend")
@Operation(summary = "报工趋势统计")
@PreAuthorize("@ss.hasPermission('mes:baogong-record:query')")
public CommonResult<BaogongRecordTrendRespVO> getBaogongRecordTrend(@Valid BaogongRecordTrendReqVO reqVO) {
return success(baogongRecordService.getBaogongRecordTrend(reqVO));
}
}

@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.mes.controller.admin.baogongrecord.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import java.util.List;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 报工统计分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class BaogongRecordStatPageReqVO extends PageParam {
@Schema(description = "开始时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime beginBaogongTime;
@Schema(description = "结束时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime endBaogongTime;
@Schema(description = "报工记录ID集合用于多选导出")
private List<Long> ids;
}

@ -0,0 +1,69 @@
package cn.iocoder.yudao.module.mes.controller.admin.baogongrecord.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 报工统计 Response VO")
@Data
public class BaogongRecordStatRespVO {
@Schema(description = "报工记录Id")
private String id;
@Schema(description = "任务单编码")
@ExcelProperty("任务单编码")
private String taskCode;
@Schema(description = "计划单编码")
@ExcelProperty("计划单编码")
private String planCode;
@Schema(description = "员工ID")
@ExcelProperty("员工ID")
private String employeeId;
@Schema(description = "员工姓名")
@ExcelProperty("员工姓名")
private String employeeName;
@Schema(description = "产品名称")
@ExcelProperty("产品名称")
private String productName;
@Schema(description = "产品编码")
@ExcelProperty("产品编码")
private String productCode;
@Schema(description = "报工数量")
@ExcelProperty("报工数量")
private Long baogongNum;
@Schema(description = "合格数量")
@ExcelProperty("合格数量")
private Long passNum;
@Schema(description = "不合格数量")
@ExcelProperty("不合格数量")
private Long noPassNum;
@Schema(description = "合格率(%)")
@ExcelProperty("合格率(%)")
private BigDecimal passRate;
@Schema(description = "原因")
@ExcelProperty("原因")
private String reason;
@Schema(description = "报工时间")
@ExcelProperty("报工时间")
@ColumnWidth(20)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime baogongTime;
}

@ -0,0 +1,22 @@
package cn.iocoder.yudao.module.mes.controller.admin.baogongrecord.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
@Schema(description = "管理后台 - 报工趋势按天 Response VO")
@Data
public class BaogongRecordTrendDayRespVO {
@Schema(description = "日期yyyy-MM-dd")
private String day;
@Schema(description = "报工数量(合格+不合格)")
private Long baogongNum;
@Schema(description = "合格率(百分比)")
private BigDecimal passRate;
}

@ -0,0 +1,24 @@
package cn.iocoder.yudao.module.mes.controller.admin.baogongrecord.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
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 = "管理后台 - 报工趋势 Request VO")
@Data
public class BaogongRecordTrendReqVO {
@Schema(description = "开始时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime beginBaogongTime;
@Schema(description = "结束时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime endBaogongTime;
}

@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.mes.controller.admin.baogongrecord.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
@Schema(description = "管理后台 - 报工趋势汇总 Response VO")
@Data
public class BaogongRecordTrendRespVO {
@Schema(description = "报工数量(合格+不合格)")
private Long baogongNum;
@Schema(description = "合格数量")
private Long passNum;
@Schema(description = "不合格数量")
private Long noPassNum;
@Schema(description = "合格率(百分比)")
private BigDecimal passRate;
@Schema(description = "按天趋势数据")
private List<BaogongRecordTrendDayRespVO> dayTrend;
}

@ -293,61 +293,70 @@ public class PlanController {
@PreAuthorize("@ss.hasPermission('mes:plan:update')")
public CommonResult<Boolean> updatePlanStatus(@Valid @RequestBody PlanStatusUpdateVO statusUpdateVO) {
PlanDO planDO = planMapper.selectById(statusUpdateVO.getId());
// 试产
if ("pre".equals(statusUpdateVO.getCode())) {
planDO.setStatus(PlanStatusEnum..getValue());
if (planDO == null) {
return success(false);
}
//开工
if ("start".equals(statusUpdateVO.getCode())) {
String code = statusUpdateVO.getCode();
// 1) 先处理计划状态
if ("pre".equals(code)) {
planDO.setStatus(PlanStatusEnum..getValue());
} else if ("start".equals(code)) {
planDO.setStatus(PlanStatusEnum..getValue());
}
//暂停
else if ("pause".equals(statusUpdateVO.getCode())) {
} else if ("pause".equals(code)) {
planDO.setStatus(PlanStatusEnum..getValue());
}
//完工
else if ("end".equals(statusUpdateVO.getCode())) {
} else if ("end".equals(code)) {
planDO.setStatus(PlanStatusEnum..getValue());
}
// 入库
else if ("store".equals(statusUpdateVO.getCode())) {
} else if ("store".equals(code)) {
planDO.setStatus(PlanStatusEnum..getValue());
} else if ("commence".equals(code)) {
planDO.setStatus(PlanStatusEnum..getValue());
}
// 2) 先落库计划状态store 最后一条判断依赖这个)
planMapper.updateById(planDO);
// 3) 入库后创建入库单
if ("store".equals(code)) {
planService.createPlanStockIn(statusUpdateVO, planDO);
}
// 4) 任务状态联动
if (planDO.getTaskId() != null) {
TaskDO taskDO = taskService.getTask(planDO.getTaskId());
if (taskDO != null) {
// 条件1任务单已完成排产按你的字段通常 isScheduled == 1
boolean scheduledFinished = Integer.valueOf(1).equals(taskDO.getIsScheduled());
// 条件2任务单下所有计划都为入库
List<PlanDO> planList = planMapper.selectList(
Wrappers.<PlanDO>lambdaQuery()
.eq(PlanDO::getTaskId, planDO.getTaskId())
);
boolean allPlanFinished = !planList.isEmpty() && planList.stream()
.allMatch(p -> Integer.valueOf(PlanStatusEnum..getValue()).equals(p.getStatus()));
if (scheduledFinished && allPlanFinished) {
taskDO.setStatus(TaskStatusEnum..getValue()); // 10-已完成
// commence -> 生产中
if ("commence".equals(code)) {
taskDO.setStatus(TaskStatusEnum..getValue());
taskService.updateTask(taskDO);
}
}
}
else if ("commence".equals(statusUpdateVO.getCode())) {
planDO.setStatus(PlanStatusEnum..getValue());
// store -> 满足条件则已完成
if ("store".equals(code)) {
boolean scheduledFinished = Integer.valueOf(1).equals(taskDO.getIsScheduled());
// 修改任务单状态为生产中
TaskDO taskDO = taskService.getTask(planDO.getTaskId());
if (taskDO != null) {
taskDO.setStatus(TaskStatusEnum..getValue());
taskService.updateTask(taskDO);
List<PlanDO> planList = planMapper.selectList(
Wrappers.<PlanDO>lambdaQuery()
.eq(PlanDO::getTaskId, planDO.getTaskId())
);
boolean allPlanStored = !planList.isEmpty() && planList.stream()
.allMatch(p -> Integer.valueOf(PlanStatusEnum..getValue()).equals(p.getStatus()));
if (scheduledFinished && allPlanStored) {
taskDO.setStatus(TaskStatusEnum..getValue());
taskService.updateTask(taskDO);
}
}
}
}
planMapper.updateById(planDO);
return success(true);
}
@PutMapping("/updatePlanZjStatus")
@Operation(summary = "更新生产计划质检状态")
@PreAuthorize("@ss.hasPermission('mes:plan:update')")

@ -22,6 +22,15 @@ public class DevicePlanGanttRespVO {
@Schema(description = "该设备计划列表")
private List<PlanItem> plans;
@Schema(description = "额定产能")
private Integer ratedCapacity;
@Schema(description = "每日报工平均值(根据工单报工计算)")
private Integer dailyAverageValue;
@Schema(description = "数据采集产能")
private Integer dataCollectionCapacity;
@Data
public static class PlanItem {
@Schema(description = "计划ID")

@ -6,8 +6,11 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.mes.dal.dataobject.baogongrecord.BaogongRecordDO;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.mes.controller.admin.baogongrecord.vo.*;
import org.apache.ibatis.annotations.Param;
/**
* Mapper
@ -26,4 +29,12 @@ public interface BaogongRecordMapper extends BaseMapperX<BaogongRecordDO> {
.orderByDesc(BaogongRecordDO::getId));
}
IPage<BaogongRecordStatRespVO> selectStatPage(Page<BaogongRecordStatRespVO> page,
@Param("reqVO") BaogongRecordStatPageReqVO reqVO);
BaogongRecordTrendRespVO selectTrendSummary(@Param("reqVO") BaogongRecordTrendReqVO reqVO);
List<BaogongRecordTrendDayRespVO> selectTrendByDay(@Param("reqVO") BaogongRecordTrendReqVO reqVO);
}

@ -52,4 +52,21 @@ public interface BaogongRecordService {
*/
PageResult<BaogongRecordDO> getBaogongRecordPage(BaogongRecordPageReqVO pageReqVO);
/**
*
*
* @param reqVO
* @return
*/
PageResult<BaogongRecordStatRespVO> getBaogongRecordStatPage(BaogongRecordStatPageReqVO reqVO);
/**
* app--
*
* @param reqVO
* @return
*/
BaogongRecordTrendRespVO getBaogongRecordTrend(BaogongRecordTrendReqVO reqVO);
}

@ -1,10 +1,13 @@
package cn.iocoder.yudao.module.mes.service.baogongrecord;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.*;
import cn.iocoder.yudao.module.mes.controller.admin.baogongrecord.vo.*;
import cn.iocoder.yudao.module.mes.dal.dataobject.baogongrecord.BaogongRecordDO;
@ -71,4 +74,29 @@ public class BaogongRecordServiceImpl implements BaogongRecordService {
return baogongRecordMapper.selectPage(pageReqVO);
}
@Override
public PageResult<BaogongRecordStatRespVO> getBaogongRecordStatPage(BaogongRecordStatPageReqVO reqVO) {
Page<BaogongRecordStatRespVO> page = new Page<>(reqVO.getPageNo(), reqVO.getPageSize());
IPage<BaogongRecordStatRespVO> result = baogongRecordMapper.selectStatPage(page, reqVO);
return new PageResult<>(result.getRecords(), result.getTotal());
}
@Override
public BaogongRecordTrendRespVO getBaogongRecordTrend(BaogongRecordTrendReqVO reqVO) {
BaogongRecordTrendRespVO respVO = baogongRecordMapper.selectTrendSummary(reqVO);
if (respVO == null) {
respVO = new BaogongRecordTrendRespVO();
respVO.setBaogongNum(0L);
respVO.setPassNum(0L);
respVO.setNoPassNum(0L);
respVO.setPassRate(BigDecimal.ZERO);
}
List<BaogongRecordTrendDayRespVO> dayTrend = baogongRecordMapper.selectTrendByDay(reqVO);
respVO.setDayTrend(dayTrend);
return respVO;
}
}

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.mes.service.plan;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.erp.controller.admin.autocode.util.AutoCodeUtil;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO;
@ -205,20 +206,21 @@ public class PlanServiceImpl implements PlanService {
TaskDO task = taskService.getTask(plan.getTaskId());
if (task != null) {
// 9-生产中:不改状态
if (!TaskStatusEnum..getValue().equals(task.getStatus())) {
// 先默认改为 7-部分排产
Integer newStatus = TaskStatusEnum..getValue();
boolean fullyScheduled = totalNeed > 0 && totalPlanned >= totalNeed;
// 满足条件则改为 8-待生产
if (totalNeed > 0 && totalPlanned >= totalNeed) {
newStatus = TaskStatusEnum..getValue();
task.setIsScheduled(1); // 你原有逻辑保留
}
// 1) 完成排产标记:满足条件就更新(与是否生产中无关)
if (fullyScheduled) {
task.setIsScheduled(1);
}
task.setStatus(newStatus);
taskService.updateTask(task);
// 2) 状态:生产中(9)不改否则按条件改为7/8
if (!TaskStatusEnum..getValue().equals(task.getStatus())) {
task.setStatus(fullyScheduled
? TaskStatusEnum..getValue()
: TaskStatusEnum..getValue());
}
taskService.updateTask(task);
}
@ -614,9 +616,11 @@ public class PlanServiceImpl implements PlanService {
vo.setDeviceId(deviceId);
vo.setDeviceName(device == null ? null : device.getDeviceName());
vo.setDeviceCode(device == null ? null : device.getDeviceCode());
vo.setRatedCapacity(device == null ? null : device.getRatedCapacity());
vo.setDailyAverageValue(device == null ? null : device.getDailyAverageValue());
vo.setDataCollectionCapacity(device == null ? null : device.getDataCollectionCapacity());
List<DevicePlanGanttRespVO.PlanItem> plans = new ArrayList<>();
DateTimeFormatter DATETIME_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
for (PlanDO plan : entry.getValue()) {
DevicePlanGanttRespVO.PlanItem item = new DevicePlanGanttRespVO.PlanItem();
@ -633,9 +637,10 @@ public class PlanServiceImpl implements PlanService {
item.setProductCode(product == null ? null : product.getBarCode());
item.setDeviceCode(device == null ? null : device.getDeviceCode());
item.setSourceType("HISTORY");
item.setPlanStartTimeStr(plan.getPlanStartTime().format(DATETIME_FMT));
item.setPlanEndTimeStr(plan.getPlanEndTime().format(DATETIME_FMT));
item.setLatestStartTimeStr(plan.getLatestStartTime().format(DATETIME_FMT));
item.setDeliveryDateStr(plan.getDeliveryDate() == null ? null : plan.getDeliveryDate().format(DateTimeFormatter.ofPattern(DateUtils.FORMAT_YEAR_MONTH_DAY)));
item.setPlanStartTimeStr(plan.getPlanStartTime().format(DateTimeFormatter.ofPattern(DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)));
item.setPlanEndTimeStr(plan.getPlanEndTime().format(DateTimeFormatter.ofPattern(DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)));
item.setLatestStartTimeStr(plan.getLatestStartTime().format(DateTimeFormatter.ofPattern(DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)));
plans.add(item);
}

@ -9,4 +9,92 @@
文档可见https://www.iocoder.cn/MyBatis/x-plugins/
-->
<select id="selectStatPage"
resultType="cn.iocoder.yudao.module.mes.controller.admin.baogongrecord.vo.BaogongRecordStatRespVO">
SELECT
r.id,
t.code AS taskCode,
p.code AS planCode,
r.creator AS employeeId,
u.nickname AS employeeName,
pr.name AS productName,
pr.bar_code AS productCode,
(IFNULL(r.num, 0) + IFNULL(r.no_pass_num, 0)) AS baogongNum,
IFNULL(r.num, 0) AS passNum,
IFNULL(r.no_pass_num, 0) AS noPassNum,
CASE
WHEN (IFNULL(r.num, 0) + IFNULL(r.no_pass_num, 0)) = 0 THEN 0
ELSE ROUND(IFNULL(r.num, 0) / (IFNULL(r.num, 0) + IFNULL(r.no_pass_num, 0)) * 100, 2)
END AS passRate,
r.remark AS reason,
r.baogong_time AS baogongTime
FROM mes_baogong_record r
LEFT JOIN mes_plan p ON p.id = r.plan_id AND p.deleted = b'0'
LEFT JOIN mes_task t ON t.id = p.task_id AND t.deleted = b'0'
LEFT JOIN erp_product pr ON pr.id = p.product_id AND pr.deleted = b'0'
LEFT JOIN system_users u ON u.id = CAST(r.creator AS UNSIGNED)
WHERE r.deleted = b'0'
<if test="reqVO.beginBaogongTime != null">
AND r.baogong_time &gt;= #{reqVO.beginBaogongTime}
</if>
<if test="reqVO.endBaogongTime != null">
AND r.baogong_time &lt;= #{reqVO.endBaogongTime}
</if>
<if test="reqVO.ids != null and reqVO.ids.size() > 0">
AND r.id IN
<foreach collection="reqVO.ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</if>
ORDER BY r.baogong_time DESC
</select>
<select id="selectTrendSummary"
resultType="cn.iocoder.yudao.module.mes.controller.admin.baogongrecord.vo.BaogongRecordTrendRespVO">
SELECT
IFNULL(SUM(IFNULL(r.num, 0) + IFNULL(r.no_pass_num, 0)), 0) AS baogongNum,
IFNULL(SUM(IFNULL(r.num, 0)), 0) AS passNum,
IFNULL(SUM(IFNULL(r.no_pass_num, 0)), 0) AS noPassNum,
CASE
WHEN IFNULL(SUM(IFNULL(r.num, 0) + IFNULL(r.no_pass_num, 0)), 0) = 0 THEN 0
ELSE ROUND(
IFNULL(SUM(IFNULL(r.num, 0)), 0) /
IFNULL(SUM(IFNULL(r.num, 0) + IFNULL(r.no_pass_num, 0)), 0) * 100, 2
)
END AS passRate
FROM mes_baogong_record r
WHERE r.deleted = b'0'
<if test="reqVO.beginBaogongTime != null">
AND r.baogong_time &gt;= #{reqVO.beginBaogongTime}
</if>
<if test="reqVO.endBaogongTime != null">
AND r.baogong_time &lt;= #{reqVO.endBaogongTime}
</if>
</select>
<select id="selectTrendByDay"
resultType="cn.iocoder.yudao.module.mes.controller.admin.baogongrecord.vo.BaogongRecordTrendDayRespVO">
SELECT
DATE_FORMAT(r.baogong_time, '%Y-%m-%d') AS day,
IFNULL(SUM(IFNULL(r.num, 0) + IFNULL(r.no_pass_num, 0)), 0) AS baogongNum,
CASE
WHEN IFNULL(SUM(IFNULL(r.num, 0) + IFNULL(r.no_pass_num, 0)), 0) = 0 THEN 0
ELSE ROUND(
IFNULL(SUM(IFNULL(r.num, 0)), 0) /
IFNULL(SUM(IFNULL(r.num, 0) + IFNULL(r.no_pass_num, 0)), 0) * 100, 2
)
END AS passRate
FROM mes_baogong_record r
WHERE r.deleted = b'0'
<if test="reqVO.beginBaogongTime != null">
AND r.baogong_time &gt;= #{reqVO.beginBaogongTime}
</if>
<if test="reqVO.endBaogongTime != null">
AND r.baogong_time &lt;= #{reqVO.endBaogongTime}
</if>
GROUP BY DATE_FORMAT(r.baogong_time, '%Y-%m-%d')
ORDER BY day ASC
</select>
</mapper>
Loading…
Cancel
Save