feat(mes): 新增工序工单统计与计划查询功能

- 新增工序工单统计分页接口(按工序聚合)
- 新增工序工单统计导出接口(按工序聚合)
- 新增按工序查询计划列表接口(不分页)
- 扩展统计SQL支持多表union查询与复杂条件过滤
- 新增ProcessWorkOrderStatsVo用于导出数据封装
-优化统计逻辑支持按processId聚合及完成率计算
- 增加物料编码查询条件支持
- 提供完整的分页与导出功能实现- 支持按计划开始时间、工序、设备、班次等多维度查询
- 实现工序生产统计总数查询用于分页处理
master
zangch@mesnac.com 2 months ago
parent b3910bff35
commit a4dceb819c

@ -202,7 +202,25 @@ public class ProdReportController extends BaseController {
}
/**
* plan_code + process_id
*
*/
@GetMapping("/processWorkOrderStats/page")
public TableDataInfo<HashMap<String, Object>> processWorkOrderStatsPage(@RequestParam(required = false) Map hashMap, PageQuery pageQuery) {
return prodReportService.processWorkOrderStatsPage(hashMap, pageQuery);
}
/**
*
*/
@RepeatSubmit()
@PostMapping("/processWorkOrderStats/export")
public void processWorkOrderStatsExport(@RequestParam(required = false) Map hashMap, HttpServletResponse response) {
List<ProcessWorkOrderStatsVo> list = prodReportService.processWorkOrderStatsExport(hashMap);
ExcelUtil.exportExcel(list, "工序生产统计", ProcessWorkOrderStatsVo.class, response);
}
/**
* plan_code + process_id
*/
@GetMapping("/planProcessChildren")
public R<List<HashMap<String, Object>>> planProcessChildren(@RequestParam(required = false) Map hashMap) {
@ -210,4 +228,13 @@ public class ProdReportController extends BaseController {
return R.ok(vos);
}
/**
*
*/
@GetMapping("/processPlanList")
public R<List<HashMap<String, Object>>> processPlanList(@RequestParam(required = false) Map hashMap) {
List<HashMap<String, Object>> list = prodReportService.listPlansByProcess(hashMap);
return R.ok(list);
}
}

@ -0,0 +1,30 @@
package org.dromara.mes.domain.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
* VO
*/
@Data
public class ProcessWorkOrderStatsVo {
@ExcelProperty("工序ID")
private Long processId;
@ExcelProperty("工序名称")
private String processName;
@ExcelProperty("计划数量")
private BigDecimal planQty;
@ExcelProperty("已完成数量")
private BigDecimal completedQty;
@ExcelProperty("未完成数量")
private BigDecimal uncompletedQty;
@ExcelProperty("完成率%")
private BigDecimal completionRateNum;
}

@ -28,12 +28,19 @@ public class WipTrackingReportVo implements Serializable {
* ID
*/
private Long productOrderId;
private String planCode;
/**
* ID
*/
private Long tenantId;
/**
*
*/
@ExcelProperty(value = "派工单号")
private String dispatchCode;
/**
*
*/
@ -154,4 +161,12 @@ public class WipTrackingReportVo implements Serializable {
* Excel
*/
private List<ProcessProgressVo> processProgressList;
// public String getPlanCode() {
// return planCode;
// }
// public void setPlanCode(String planCode) {
// this.planCode = planCode;
// }
}

@ -132,6 +132,19 @@ public interface ProdReportMapper {
@Param("planTableName") String planTableName,
@Param("tenantId") String tenantId);
/**
* processId
*/
Page<HashMap<String, Object>> processWorkOrderStatsPage(@Param("map") Map hashMap,
@Param("page") Page<HashMap<String, Object>> page,
@Param("planTableName") String planTableName);
/**
* processId
*/
Long processWorkOrderStatsCount(@Param("map") Map hashMap,
@Param("planTableName") String planTableName);
/**
* planCode
*/
@ -160,4 +173,10 @@ public interface ProdReportMapper {
*/
List<HashMap<String, Object>> processWorkOrderStats(@Param("map") Map hashMap,
@Param("planTableName") String planTableName);
/**
*
*/
List<HashMap<String, Object>> listPlansByProcess(@Param("map") Map hashMap,
@Param("planTableName") String planTableName);
}

@ -143,6 +143,21 @@ public interface IProdReportService {
*/
List<HashMap<String, Object>> processWorkOrderStats(Map hashMap);
/**
*
* @param hashMap
* @param pageQuery
* @return
*/
TableDataInfo<HashMap<String, Object>> processWorkOrderStatsPage(Map hashMap, PageQuery pageQuery);
/**
*
* @param hashMap
* @return
*/
List<ProcessWorkOrderStatsVo> processWorkOrderStatsExport(Map hashMap);
/**
* plan_code + process_id
* @param hashMap planCodeprocessId
@ -150,4 +165,11 @@ public interface IProdReportService {
*/
List<HashMap<String, Object>> planProcessDetailChildren(Map hashMap);
/**
*
* @param hashMap beginDate/endDateprocessIdmachineIdshiftIdclassTeamIdplanCodematerialNamematerialCode
* @return
*/
List<HashMap<String, Object>> listPlansByProcess(Map hashMap);
}

@ -625,9 +625,83 @@ public class ProdReportServiceImpl implements IProdReportService {
*/
@Override
public List<HashMap<String, Object>> processWorkOrderStats(Map hashMap) {
try {
String tenantId = org.dromara.common.satoken.utils.LoginHelper.getTenantId();
if (tenantId != null && !tenantId.isEmpty()) {
hashMap.put("tenantId", tenantId);
}
} catch (Exception ignore) {}
Long processId = parseProcessId(hashMap.get("processId"));
String planTable = getPlanInfoTableNameByProcessId(processId);
return prodReportMapper.processWorkOrderStats(hashMap, planTable);
}
/**
*
*/
@Override
public TableDataInfo<HashMap<String, Object>> processWorkOrderStatsPage(Map hashMap, PageQuery pageQuery) {
try {
String tenantId = org.dromara.common.satoken.utils.LoginHelper.getTenantId();
if (tenantId != null && !tenantId.isEmpty()) {
hashMap.put("tenantId", tenantId);
}
} catch (Exception ignore) {}
Long processId = parseProcessId(hashMap.get("processId"));
String planTable = getPlanInfoTableNameByProcessId(processId);
Page<HashMap<String, Object>> mpPage = pageQuery.build();
// 复杂聚合SQL手动count更稳妥
mpPage.setSearchCount(false);
Page<HashMap<String, Object>> page = prodReportMapper.processWorkOrderStatsPage(hashMap, mpPage, planTable);
try {
Long total = prodReportMapper.processWorkOrderStatsCount(hashMap, planTable);
if (total != null) {
page.setTotal(total);
}
} catch (Exception ignore) {
}
return TableDataInfo.build(page);
}
/**
*
*/
@Override
public List<ProcessWorkOrderStatsVo> processWorkOrderStatsExport(Map hashMap) {
Long processId = parseProcessId(hashMap.get("processId"));
String planTable = getPlanInfoTableNameByProcessId(processId);
List<HashMap<String, Object>> rows = prodReportMapper.processWorkOrderStats(hashMap, planTable);
List<ProcessWorkOrderStatsVo> list = new ArrayList<>();
for (HashMap<String, Object> r : rows) {
ProcessWorkOrderStatsVo vo = new ProcessWorkOrderStatsVo();
vo.setProcessId(asLong(r.get("processId")));
vo.setProcessName(String.valueOf(r.get("processName")));
vo.setPlanQty(asBigDecimal(r.get("planQty")));
vo.setCompletedQty(asBigDecimal(r.get("completedQty")));
vo.setUncompletedQty(asBigDecimal(r.get("uncompletedQty")));
vo.setCompletionRateNum(asBigDecimal(r.get("completionRateNum")));
list.add(vo);
}
return list;
}
private Long asLong(Object o) {
if (o == null) return null;
try { return Long.parseLong(String.valueOf(o)); } catch (Exception e) { return null; }
}
private BigDecimal asBigDecimal(Object o) {
if (o == null) return BigDecimal.ZERO;
try { return new BigDecimal(String.valueOf(o)); } catch (Exception e) { return BigDecimal.ZERO; }
}
/**
*
*/
@Override
public List<HashMap<String, Object>> listPlansByProcess(Map hashMap) {
Long processId = parseProcessId(hashMap.get("processId"));
String planTable = getPlanInfoTableNameByProcessId(processId);
return prodReportMapper.listPlansByProcess(hashMap, planTable);
}
}

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8" ?>
<?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">
@ -702,16 +702,15 @@
ORDER BY productionDate, DATEPART(HOUR, t.create_time)
</select>
<!-- 工序生产统计(按工序聚合):完成数量、未完成数量与完成率 -->
<!-- 工序生产统计(按工序聚合):完成数量、未完成数量与完成率(按 processId 聚合) -->
<select id="processWorkOrderStats" resultType="java.util.HashMap">
<![CDATA[
SELECT
p.process_id AS processId,
ISNULL(pproc.process_name, N'未知工序') AS processName,
-- 汇总计划与完成数量
CAST(SUM(ISNULL(p.plan_amount, 0)) AS DECIMAL(18,4)) AS planQty,
CAST(SUM(ISNULL(p.complete_amount, 0)) AS DECIMAL(18,4)) AS completedQty,
CAST(SUM(ISNULL(p.plan_amount, 0) - ISNULL(p.complete_amount, 0)) AS DECIMAL(18,4)) AS uncompletedQty,
-- 完成率(数值 & 展示)
CAST(
CASE WHEN SUM(ISNULL(p.plan_amount, 0)) > 0
THEN (CAST(SUM(ISNULL(p.complete_amount, 0)) AS DECIMAL(18,6)) / CAST(SUM(ISNULL(p.plan_amount, 0)) AS DECIMAL(18,6))) * 100
@ -724,10 +723,177 @@
ELSE 0 END
AS DECIMAL(10,2)
), '%') AS completionRate
FROM ${planTableName} AS p
FROM (
SELECT plan_id, plan_code, process_id, plan_amount, complete_amount, material_id, plan_begin_time, release_id, shift_id, class_team_id, tenant_id FROM prod_plan_info_2
UNION ALL
SELECT plan_id, plan_code, process_id, plan_amount, complete_amount, material_id, plan_begin_time, release_id, shift_id, class_team_id, tenant_id FROM prod_plan_info_3
UNION ALL
SELECT plan_id, plan_code, process_id, plan_amount, complete_amount, material_id, plan_begin_time, release_id, shift_id, class_team_id, tenant_id FROM prod_plan_info_4
) AS p
LEFT JOIN prod_base_process_info AS pproc ON pproc.process_id = p.process_id
LEFT JOIN base_material_info AS bmi ON bmi.material_id = p.material_id
]]>
<where>
<if test="map.tenantId != null and map.tenantId != ''">
AND p.tenant_id = #{map.tenantId}
</if>
<if test="map.beginDate != null and map.beginDate != '' and map.endDate != null and map.endDate != ''">
AND FORMAT(p.plan_begin_time, 'yyyy-MM-dd') BETWEEN #{map.beginDate} AND #{map.endDate}
</if>
<if test="map.processId != null and map.processId != ''">
AND p.process_id = #{map.processId}
</if>
<if test="map.machineId != null and map.machineId != ''">
AND p.release_id = #{map.machineId}
</if>
<if test="map.shiftId != null and map.shiftId != ''">
AND p.shift_id = #{map.shiftId}
</if>
<if test="map.classTeamId != null and map.classTeamId != ''">
AND p.class_team_id = #{map.classTeamId}
</if>
<if test="map.planCode != null and map.planCode != ''">
AND p.plan_code LIKE CONCAT('%', #{map.planCode}, '%')
</if>
<if test="map.materialName != null and map.materialName != ''">
AND bmi.material_name LIKE CONCAT('%', #{map.materialName}, '%')
</if>
</where>
<![CDATA[
GROUP BY p.process_id, ISNULL(pproc.process_name, N'未知工序')
ORDER BY completionRateNum DESC, processName
]]>
</select>
<!-- 工序生产统计(分页,按 processId 聚合) -->
<select id="processWorkOrderStatsPage" resultType="java.util.HashMap">
<![CDATA[
SELECT
p.process_id AS processId,
ISNULL(pproc.process_name, N'未知工序') AS processName,
CAST(SUM(ISNULL(p.plan_amount, 0)) AS DECIMAL(18,4)) AS planQty,
CAST(SUM(ISNULL(p.complete_amount, 0)) AS DECIMAL(18,4)) AS completedQty,
CAST(SUM(ISNULL(p.plan_amount, 0) - ISNULL(p.complete_amount, 0)) AS DECIMAL(18,4)) AS uncompletedQty,
CAST(
CASE WHEN SUM(ISNULL(p.plan_amount, 0)) > 0
THEN (CAST(SUM(ISNULL(p.complete_amount, 0)) AS DECIMAL(18,6)) / CAST(SUM(ISNULL(p.plan_amount, 0)) AS DECIMAL(18,6))) * 100
ELSE 0 END
AS DECIMAL(10,2)) AS completionRateNum,
CONCAT(
CAST(
CASE WHEN SUM(ISNULL(p.plan_amount, 0)) > 0
THEN (CAST(SUM(ISNULL(p.complete_amount, 0)) AS DECIMAL(18,6)) / CAST(SUM(ISNULL(p.plan_amount, 0)) AS DECIMAL(18,6))) * 100
ELSE 0 END
AS DECIMAL(10,2)
), '%') AS completionRate
FROM (
SELECT plan_id, plan_code, process_id, plan_amount, complete_amount, material_id, plan_begin_time, release_id, shift_id, class_team_id, tenant_id FROM prod_plan_info_2
UNION ALL
SELECT plan_id, plan_code, process_id, plan_amount, complete_amount, material_id, plan_begin_time, release_id, shift_id, class_team_id, tenant_id FROM prod_plan_info_3
UNION ALL
SELECT plan_id, plan_code, process_id, plan_amount, complete_amount, material_id, plan_begin_time, release_id, shift_id, class_team_id, tenant_id FROM prod_plan_info_4
) AS p
LEFT JOIN prod_base_process_info AS pproc ON pproc.process_id = p.process_id
LEFT JOIN base_material_info AS bmi ON bmi.material_id = p.material_id
]]>
<where>
<if test="map.tenantId != null and map.tenantId != ''">
AND p.tenant_id = #{map.tenantId}
</if>
<if test="map.beginDate != null and map.beginDate != '' and map.endDate != null and map.endDate != ''">
AND FORMAT(p.plan_begin_time, 'yyyy-MM-dd') BETWEEN #{map.beginDate} AND #{map.endDate}
</if>
<if test="map.processId != null and map.processId != ''">
AND p.process_id = #{map.processId}
</if>
<if test="map.machineId != null and map.machineId != ''">
AND p.release_id = #{map.machineId}
</if>
<if test="map.shiftId != null and map.shiftId != ''">
AND p.shift_id = #{map.shiftId}
</if>
<if test="map.classTeamId != null and map.classTeamId != ''">
AND p.class_team_id = #{map.classTeamId}
</if>
<if test="map.planCode != null and map.planCode != ''">
AND p.plan_code LIKE CONCAT('%', #{map.planCode}, '%')
</if>
<if test="map.materialName != null and map.materialName != ''">
AND bmi.material_name LIKE CONCAT('%', #{map.materialName}, '%')
</if>
<if test="map.materialCode != null and map.materialCode != ''">
AND bmi.material_code LIKE CONCAT('%', #{map.materialCode}, '%')
</if>
</where>
<![CDATA[
GROUP BY p.process_id, ISNULL(pproc.process_name, N'未知工序')
ORDER BY completionRateNum DESC, processName
]]>
</select>
<!-- 工序统计总数(按 processId 聚合) -->
<select id="processWorkOrderStatsCount" resultType="long">
SELECT COUNT(1) FROM (
SELECT p.process_id
FROM (
SELECT plan_id, plan_code, process_id, plan_amount, complete_amount, material_id, plan_begin_time, release_id, shift_id, class_team_id, tenant_id FROM prod_plan_info_2
UNION ALL
SELECT plan_id, plan_code, process_id, plan_amount, complete_amount, material_id, plan_begin_time, release_id, shift_id, class_team_id, tenant_id FROM prod_plan_info_3
UNION ALL
SELECT plan_id, plan_code, process_id, plan_amount, complete_amount, material_id, plan_begin_time, release_id, shift_id, class_team_id, tenant_id FROM prod_plan_info_4
) AS p
LEFT JOIN base_material_info AS bmi ON bmi.material_id = p.material_id
<where>
<if test="map.tenantId != null and map.tenantId != ''">
AND p.tenant_id = #{map.tenantId}
</if>
<if test="map.beginDate != null and map.beginDate != '' and map.endDate != null and map.endDate != ''">
AND FORMAT(p.plan_begin_time, 'yyyy-MM-dd') BETWEEN #{map.beginDate} AND #{map.endDate}
</if>
<if test="map.processId != null and map.processId != ''">
AND p.process_id = #{map.processId}
</if>
<if test="map.machineId != null and map.machineId != ''">
AND p.release_id = #{map.machineId}
</if>
<if test="map.shiftId != null and map.shiftId != ''">
AND p.shift_id = #{map.shiftId}
</if>
<if test="map.classTeamId != null and map.classTeamId != ''">
AND p.class_team_id = #{map.classTeamId}
</if>
<if test="map.planCode != null and map.planCode != ''">
AND p.plan_code LIKE CONCAT('%', #{map.planCode}, '%')
</if>
<if test="map.materialName != null and map.materialName != ''">
AND bmi.material_name LIKE CONCAT('%', #{map.materialName}, '%')
</if>
<if test="map.materialCode != null and map.materialCode != ''">
AND bmi.material_code LIKE CONCAT('%', #{map.materialCode}, '%')
</if>
</where>
GROUP BY p.process_id
) t
</select>
<!-- 按工序查询计划列表(不分页) -->
<select id="listPlansByProcess" resultType="java.util.HashMap">
<![CDATA[
SELECT
p.plan_id AS planId,
p.plan_code AS planCode,
p.process_id AS processId,
ISNULL(p.process_order, 0) AS processOrder,
CAST(ISNULL(p.plan_amount, 0) AS DECIMAL(18,4)) AS planAmount,
CAST(ISNULL(p.complete_amount, 0) AS DECIMAL(18,4)) AS completeAmount,
p.real_begin_time AS realBeginTime,
p.real_end_time AS realEndTime,
ISNULL(p.plan_status, '0') AS planStatus,
ISNULL(bmi.material_name, '') AS materialName,
ISNULL(bmi.material_code, '') AS materialCode
FROM ${planTableName} AS p
LEFT JOIN base_material_info AS bmi ON bmi.material_id = p.material_id
]]>
<where>
<if test="map.beginDate != null and map.beginDate != '' and map.endDate != null and map.endDate != ''">
AND FORMAT(p.plan_begin_time, 'yyyy-MM-dd') BETWEEN #{map.beginDate} AND #{map.endDate}
@ -750,10 +916,12 @@
<if test="map.materialName != null and map.materialName != ''">
AND bmi.material_name LIKE CONCAT('%', #{map.materialName}, '%')
</if>
<if test="map.materialCode != null and map.materialCode != ''">
AND bmi.material_code LIKE CONCAT('%', #{map.materialCode}, '%')
</if>
</where>
<![CDATA[
GROUP BY ISNULL(pproc.process_name, N'未知工序')
ORDER BY completionRateNum DESC, processName
ORDER BY p.real_begin_time DESC, p.plan_id DESC
]]>
</select>

@ -0,0 +1,734 @@
<?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.mes.mapper.ProdReportMapper">
<select id="planCompletionRateReportVoList" resultType="org.dromara.mes.domain.vo.PlanCompletionRateReportVo">
SELECT bmi.material_name materialName,
CAST(SUM(t.plan_amount) AS DECIMAL(10, 2)) planNumber,
CAST(SUM(t.complete_amount) AS DECIMAL(10, 2)) actualNumber,
CAST(SUM(t.complete_amount - t.plan_amount) AS DECIMAL(10, 2)) deviationNumber,
CONCAT(CAST((SUM(t.complete_amount) / SUM(t.plan_amount))
* 100 AS DECIMAL(10, 2)), '%') completionRate
FROM ${tableName} t
LEFT JOIN base_material_info bmi on bmi.material_id = t.material_id
<where>
<if test="map.beginDate != null and map.beginDate != '' and map.endDate != null and map.endDate != ''">
AND FORMAT(t.plan_begin_time, 'yyyy-MM-dd') BETWEEN #{map.beginDate} AND #{map.endDate}
</if>
<if test="map.processId != null and map.processId != ''">
AND t.process_id = #{map.processId}
</if>
<if test="map.machineId != null and map.machineId != ''">
AND t.release_id = #{map.machineId}
</if>
<if test="map.shiftId != null and map.shiftId != ''">
AND t.shift_id = #{map.shiftId}
</if>
<if test="map.classTeamId != null and map.classTeamId != ''">
AND t.class_team_id = #{map.classTeamId}
</if>
<if test="map.planCode != null and map.planCode != ''">
AND t.plan_code LIKE CONCAT('%', #{map.planCode}, '%')
</if>
<if test="map.materialName != null and map.materialName != ''">
AND bmi.material_name LIKE CONCAT('%', #{map.materialName}, '%')
</if>
</where>
GROUP BY bmi.material_name
ORDER BY materialName
</select>
<select id="planCompletionContrastReportVoList"
resultType="org.dromara.mes.domain.vo.PlanCompletionContrastReportVo">
WITH aggregated_data AS (SELECT t.tenant_id, bmi.material_name AS materialName,
SUM(IIF(FORMAT(t.plan_begin_time, 'yyyy-MM-dd') = FORMAT(CAST(#{map.beginDate} AS DATETIME), 'yyyy-MM-dd'), t.plan_amount, 0)) AS
dayPlanNumber,
SUM(IIF(FORMAT(t.plan_begin_time, 'yyyy-MM-dd') = FORMAT(CAST(#{map.beginDate} AS DATETIME), 'yyyy-MM-dd'), t.complete_amount, 0))
AS dayActualNumber,
SUM(IIF(FORMAT(t.plan_begin_time, 'yyyy-MM') = FORMAT(CAST(#{map.beginDate} AS DATETIME), 'yyyy-MM'), t.plan_amount, 0)) AS
monthPlanNumber,
SUM(IIF(FORMAT(t.plan_begin_time, 'yyyy-MM') = FORMAT(CAST(#{map.beginDate} AS DATETIME), 'yyyy-MM'), t.complete_amount, 0)) AS
monthActualNumber,
SUM(IIF(FORMAT(t.plan_begin_time, 'yyyy') = FORMAT(CAST(#{map.beginDate} AS DATETIME), 'yyyy'), t.plan_amount, 0)) AS
yearPlanNumber,
SUM(IIF(FORMAT(t.plan_begin_time, 'yyyy') = FORMAT(CAST(#{map.beginDate} AS DATETIME), 'yyyy'), t.complete_amount, 0)) AS
yearActualNumber
FROM ${tableName} t
LEFT JOIN base_material_info bmi ON bmi.material_id = t.material_id
<where>
<if test="map.beginDate != null and map.beginDate != ''">
AND FORMAT(t.plan_begin_time, 'yyyy-MM-dd') BETWEEN #{map.beginDate} AND #{map.beginDate}
</if>
<if test="map.processId != null and map.processId != ''">
AND t.process_id = #{map.processId}
</if>
<if test="map.machineId != null and map.machineId != ''">
AND t.release_id = #{map.machineId}
</if>
<if test="map.shiftId != null and map.shiftId != ''">
AND t.shift_id = #{map.shiftId}
</if>
<if test="map.classTeamId != null and map.classTeamId != ''">
AND t.class_team_id = #{map.classTeamId}
</if>
<if test="map.planCode != null and map.planCode != ''">
AND t.plan_code LIKE CONCAT('%', #{map.planCode}, '%')
</if>
<if test="map.materialName != null and map.materialName != ''">
AND bmi.material_name LIKE CONCAT('%', #{map.materialName}, '%')
</if>
</where>
GROUP BY t.tenant_id, bmi.material_name)
SELECT materialName,
-- 当天数据
CAST(dayPlanNumber AS DECIMAL(10, 2)) AS dayPlanNumber,
CAST(dayActualNumber AS DECIMAL(10, 2)) AS dayActualNumber,
CAST(dayActualNumber - dayPlanNumber AS DECIMAL(10, 2)) AS dayDeviationNumber,
CONCAT(CAST(IIF(dayPlanNumber = 0, 0, (dayActualNumber * 100.0 / dayPlanNumber)) AS DECIMAL(10, 2)),
'%') AS dayCompletionRate,
-- 当月数据
CAST(monthPlanNumber AS DECIMAL(10, 2)) AS monthPlanNumber,
CAST(monthActualNumber AS DECIMAL(10, 2)) AS monthActualNumber,
CAST(monthActualNumber - monthPlanNumber AS DECIMAL(10, 2)) AS monthDeviationNumber,
CONCAT(CAST(IIF(monthPlanNumber = 0, 0, (monthActualNumber * 100.0 / monthPlanNumber)) AS DECIMAL(10, 2)),
'%') AS monthCompletionRate,
-- 当年数据
CAST(yearPlanNumber AS DECIMAL(10, 2)) AS yearPlanNumber,
CAST(yearActualNumber AS DECIMAL(10, 2)) AS yearActualNumber,
CAST(yearActualNumber - yearPlanNumber AS DECIMAL(10, 2)) AS yearDeviationNumber,
CONCAT(CAST(IIF(yearPlanNumber = 0, 0, (yearActualNumber * 100.0 / yearPlanNumber)) AS DECIMAL(10, 2)),
'%') AS yearCompletionRate
FROM aggregated_data
ORDER BY materialName
</select>
<select id="designDailyOutputInformation" resultType="java.util.HashMap">
SELECT CONVERT(DATE, t.real_end_time) productionDate,
COUNT(*) completeAmount
FROM ${tableName} t
LEFT JOIN base_material_info bmi ON bmi.material_id = t.material_id
WHERE real_end_time IS NOT NULL
<if test="map.beginDate != null and map.beginDate != '' and map.endDate != null and map.endDate != ''">
AND FORMAT(t.real_end_time, 'yyyy-MM-dd') BETWEEN #{map.beginDate} AND #{map.endDate}
</if>
GROUP BY CONVERT(DATE, t.real_end_time)
ORDER BY productionDate
</select>
<select id="yieldSummaryByMachine" resultType="java.util.HashMap">
SELECT bm.machine_name AS machineName,
COUNT(1) AS totalCount,
SUM(CASE WHEN (UPPER(t.scan_result) IN ('OK','PASS') OR t.scan_result IN (N'通过')) THEN 1 ELSE 0 END) AS okCount,
SUM(CASE WHEN t.scan_result IS NULL THEN 0 WHEN (UPPER(t.scan_result) IN ('OK','PASS') OR t.scan_result IN (N'通过')) THEN 0 ELSE 1 END) AS ngCount,
CAST(IIF(COUNT(1) = 0, 0, (SUM(CASE WHEN (UPPER(t.scan_result) IN ('OK','PASS') OR t.scan_result IN (N'通过')) THEN 1 ELSE 0 END) * 100.0 / COUNT(1))) AS DECIMAL(10,2)) AS yieldRateNum,
CONCAT(CAST(IIF(COUNT(1) = 0, 0, (SUM(CASE WHEN (UPPER(t.scan_result) IN ('OK','PASS') OR t.scan_result IN (N'通过')) THEN 1 ELSE 0 END) * 100.0 / COUNT(1))) AS DECIMAL(10,2)), '%') AS yieldRate
FROM prod_output_scan_info t
LEFT JOIN prod_base_machine_info bm ON bm.machine_id = t.machine_id
LEFT JOIN prod_base_process_info pi ON pi.process_id = t.process_id
LEFT JOIN base_material_info bmi ON bmi.material_id = t.materiel_id
<where>
<if test="map.beginDate != null and map.beginDate != '' and map.endDate != null and map.endDate != ''">
AND FORMAT(t.create_time, 'yyyy-MM-dd') BETWEEN #{map.beginDate} AND #{map.endDate}
</if>
<if test="map.processId != null and map.processId != ''">
AND t.process_id = #{map.processId}
</if>
<if test="map.machineId != null and map.machineId != ''">
AND t.machine_id = #{map.machineId}
</if>
<if test="map.materialName != null and map.materialName != ''">
AND bmi.material_name LIKE CONCAT('%', #{map.materialName}, '%')
</if>
</where>
GROUP BY bm.machine_name
ORDER BY yieldRateNum DESC, machineName
</select>
<select id="yieldTrendByDate" resultType="java.util.HashMap">
SELECT CONVERT(DATE, t.create_time) AS productionDate,
COUNT(1) AS totalCount,
SUM(CASE WHEN (UPPER(t.scan_result) IN ('OK','PASS') OR t.scan_result IN (N'通过')) THEN 1 ELSE 0 END) AS okCount,
SUM(CASE WHEN t.scan_result IS NULL THEN 0 WHEN (UPPER(t.scan_result) IN ('OK','PASS') OR t.scan_result IN (N'通过')) THEN 0 ELSE 1 END) AS ngCount,
CAST(IIF(COUNT(1) = 0, 0, (SUM(CASE WHEN (UPPER(t.scan_result) IN ('OK','PASS') OR t.scan_result IN (N'通过')) THEN 1 ELSE 0 END) * 100.0 / COUNT(1))) AS DECIMAL(10,2)) AS yieldRateNum,
CONCAT(CAST(IIF(COUNT(1) = 0, 0, (SUM(CASE WHEN (UPPER(t.scan_result) IN ('OK','PASS') OR t.scan_result IN (N'通过')) THEN 1 ELSE 0 END) * 100.0 / COUNT(1))) AS DECIMAL(10,2)), '%') AS yieldRate
FROM prod_output_scan_info t
LEFT JOIN prod_base_machine_info bm ON bm.machine_id = t.machine_id
LEFT JOIN prod_base_process_info pi ON pi.process_id = t.process_id
LEFT JOIN base_material_info bmi ON bmi.material_id = t.materiel_id
<where>
<if test="map.beginDate != null and map.beginDate != '' and map.endDate != null and map.endDate != ''">
AND FORMAT(t.create_time, 'yyyy-MM-dd') BETWEEN #{map.beginDate} AND #{map.endDate}
</if>
<if test="map.processId != null and map.processId != ''">
AND t.process_id = #{map.processId}
</if>
<if test="map.machineId != null and map.machineId != ''">
AND t.machine_id = #{map.machineId}
</if>
<if test="map.materialName != null and map.materialName != ''">
AND bmi.material_name LIKE CONCAT('%', #{map.materialName}, '%')
</if>
</where>
GROUP BY CONVERT(DATE, t.create_time)
ORDER BY productionDate
</select>
<!-- 班组作业情况报表 -->
<select id="teamWorkReportList" resultType="org.dromara.mes.domain.vo.TeamWorkReportVo">
SELECT
bct.team_name AS teamName,
pbsi.station_name AS stationName,
ppd.user_name AS operatorName,
bmi.material_name AS productName,
pproc.process_name AS processName,
CAST(ppd.complete_amount AS DECIMAL(18,4)) AS productionQuantity,
CAST(ISNULL(qc.qualified_qty, 0) AS DECIMAL(18,4)) AS qualifiedQuantity,
CAST(ISNULL(qc.unqualified_qty, 0) AS DECIMAL(18,4)) AS unqualifiedQuantity,
CAST(
CASE WHEN ISNULL(ppd.complete_amount,0) > 0
THEN (ISNULL(qc.qualified_qty,0) + 0.0) / (ppd.complete_amount + 0.0) * 100
ELSE NULL END
AS DECIMAL(18,4)
) AS qualifiedRate,
ppd.real_begin_time AS startTime,
ppd.real_end_time AS endTime,
CAST(DATEDIFF(SECOND, ppd.real_begin_time, ppd.real_end_time) / 3600.0 AS DECIMAL(18,4)) AS workHours,
COALESCE(ppd.remark, ppi.remark) AS remark
FROM ${detailTableName} AS ppd
INNER JOIN ${planTableName} AS ppi ON ppi.plan_id = ppd.plan_id
LEFT JOIN base_class_team_info AS bct ON bct.class_team_id = ppd.class_team_id
LEFT JOIN prod_base_station_info AS pbsi ON pbsi.station_id = bct.station_id
LEFT JOIN prod_base_process_info AS pproc ON pproc.process_id = ppi.process_id
LEFT JOIN base_material_info AS bmi ON bmi.material_id = ppi.material_id
LEFT JOIN (
SELECT
plan_detail_id,
SUM(ISNULL(qualified_qty, 0)) AS qualified_qty,
SUM(ISNULL(unqualified_qty, 0)) AS unqualified_qty
FROM qc_inspection_main
WHERE del_flag = '0'
GROUP BY plan_detail_id
) AS qc ON qc.plan_detail_id = ppd.plan_detail_id
<where>
-- ppd.real_begin_time IS NOT NULL AND ppd.real_end_time IS NOT NULL
<if test="map.beginDate != null and map.beginDate != '' and map.endDate != null and map.endDate != ''">
FORMAT(ppd.create_time, 'yyyy-MM-dd') BETWEEN #{map.beginDate} AND #{map.endDate}
</if>
<!-- <if test="map.processId != null and map.processId != ''">
AND ppi.process_id = #{map.processId}
</if>-->
<if test="map.machineId != null and map.machineId != ''">
AND ppi.release_id = #{map.machineId}
</if>
<if test="map.shiftId != null and map.shiftId != ''">
AND ppi.shift_id = #{map.shiftId}
</if>
<if test="map.classTeamId != null and map.classTeamId != ''">
AND ppd.class_team_id = #{map.classTeamId}
</if>
<if test="map.planCode != null and map.planCode != ''">
AND ppi.dispatch_code LIKE CONCAT('%', #{map.planCode}, '%')
</if>
<if test="map.materialName != null and map.materialName != ''">
AND bmi.material_name LIKE CONCAT('%', #{map.materialName}, '%')
</if>
<if test="map.operatorName != null and map.operatorName != ''">
AND ppd.user_name LIKE CONCAT('%', #{map.operatorName}, '%')
</if>
</where>
ORDER BY ppd.real_begin_time DESC, ppi.plan_id DESC
</select>
<select id="workHourReportList" resultType="org.dromara.mes.domain.vo.WorkHourReportVo">
SELECT
ppi.dispatch_code AS dispatchCode,
bct.team_name AS teamName,
pbsi.station_name AS stationName,
bmi.material_name AS materialName,
pproc.process_name AS processName,
CAST(ppd.complete_amount AS DECIMAL(18,4)) AS completeAmount,
CAST(ppd.complete_amount * ISNULL(pproc.production_time, 0) / 3600.0 AS DECIMAL(18,4)) AS standardWorkHour,
CAST(DATEDIFF(SECOND, ppd.real_begin_time, ppd.real_end_time) / 3600.0 AS DECIMAL(18,4)) AS reportWorkHour,
CAST(
CASE
WHEN DATEDIFF(SECOND, ppd.real_begin_time, ppd.real_end_time) > 0
THEN (ppd.complete_amount + 0.0) / (DATEDIFF(SECOND, ppd.real_begin_time, ppd.real_end_time) / 3600.0)
ELSE NULL
END
AS DECIMAL(18,4)
) AS productionEfficiency,
ppi.plan_status AS planStatus,
COALESCE(ppd.remark, ppi.remark) AS remark
FROM ${detailTableName} AS ppd
INNER JOIN ${planTableName} AS ppi ON ppi.plan_id = ppd.plan_id
LEFT JOIN base_class_team_info AS bct ON bct.class_team_id = ppd.class_team_id
LEFT JOIN prod_base_station_info AS pbsi ON pbsi.station_id = bct.station_id
LEFT JOIN prod_base_process_info AS pproc ON pproc.process_id = ppi.process_id
LEFT JOIN base_material_info AS bmi ON bmi.material_id = ppi.material_id
<where>
<!-- ppd.real_begin_time IS NOT NULL AND ppd.real_end_time IS NOT NULL -->
<!-- ppd.real_begin_time IS NOT NULL AND ppd.real_end_time IS NOT NULL -->
<if test="map.beginDate != null and map.beginDate != '' and map.endDate != null and map.endDate != ''">
AND FORMAT(ppd.create_time, 'yyyy-MM-dd') BETWEEN #{map.beginDate} AND #{map.endDate}
</if>
<!-- <if test="map.processId != null and map.processId != ''">
AND ppi.process_id = #{map.processId}
</if>-->
<if test="map.machineId != null and map.machineId != ''">
AND ppi.release_id = #{map.machineId}
</if>
<if test="map.shiftId != null and map.shiftId != ''">
AND ppi.shift_id = #{map.shiftId}
</if>
<if test="map.classTeamId != null and map.classTeamId != ''">
AND ppd.class_team_id = #{map.classTeamId}
</if>
<if test="map.planCode != null and map.planCode != ''">
AND ppi.dispatch_code LIKE CONCAT('%', #{map.planCode}, '%')
</if>
<if test="map.materialName != null and map.materialName != ''">
AND bmi.material_name LIKE CONCAT('%', #{map.materialName}, '%')
</if>
</where>
ORDER BY ppd.real_begin_time DESC, ppi.plan_id DESC
</select>
<!-- 在制品跟踪报表 - 高性能优化版本(进一步优化:限制工序统计范围到已过滤订单,避免全表扫描) -->
<select id="wipTrackingReportList" resultType="org.dromara.mes.domain.vo.WipTrackingReportVo">
WITH Plans AS (
SELECT p.plan_code, p.tenant_id
FROM (
SELECT product_order_id, tenant_id, material_id, plan_begin_time, plan_code FROM prod_plan_info_2
UNION ALL
SELECT product_order_id, tenant_id, material_id, plan_begin_time, plan_code FROM prod_plan_info_3
UNION ALL
SELECT product_order_id, tenant_id, material_id, plan_begin_time, plan_code FROM prod_plan_info_4
) p
INNER JOIN base_material_info m ON m.material_id = p.material_id
WHERE m.del_flag = '0'
<if test="map.tenantId != null and map.tenantId != ''">
AND p.tenant_id = #{map.tenantId}
</if>
<if test="map.beginDate != null and map.beginDate != '' and map.endDate != null and map.endDate != ''">
AND p.plan_begin_time &gt;= CAST(#{map.beginDate} AS DATETIME)
AND p.plan_begin_time &lt; DATEADD(day, 1, CAST(#{map.endDate} AS DATETIME))
</if>
<if test="map.planCode != null and map.planCode != ''">
AND p.plan_code LIKE CONCAT('%', #{map.planCode}, '%')
</if>
<if test="map.materialName != null and map.materialName != ''">
AND m.material_name LIKE CONCAT('%', #{map.materialName}, '%')
</if>
<if test="map.materialCode != null and map.materialCode != ''">
AND m.material_code LIKE CONCAT('%', #{map.materialCode}, '%')
</if>
GROUP BY p.plan_code, p.tenant_id
),
ProcessRows AS (
-- 订单范围内的所有工序计划行UNION ALL 提升性能)
SELECT p2.plan_code, p2.tenant_id, p2.process_id, p2.process_order, p2.plan_status,
p2.plan_amount, p2.complete_amount, pr2.process_name
FROM prod_plan_info_2 p2
LEFT JOIN prod_base_process_info pr2 ON pr2.process_id = p2.process_id
INNER JOIN Plans pl ON pl.plan_code = p2.plan_code AND pl.tenant_id = p2.tenant_id
UNION ALL
SELECT p3.plan_code, p3.tenant_id, p3.process_id, p3.process_order, p3.plan_status,
p3.plan_amount, p3.complete_amount, pr3.process_name
FROM prod_plan_info_3 p3
LEFT JOIN prod_base_process_info pr3 ON pr3.process_id = p3.process_id
INNER JOIN Plans pl ON pl.plan_code = p3.plan_code AND pl.tenant_id = p3.tenant_id
UNION ALL
SELECT p4.plan_code, p4.tenant_id, p4.process_id, p4.process_order, p4.plan_status,
p4.plan_amount, p4.complete_amount, pr4.process_name
FROM prod_plan_info_4 p4
LEFT JOIN prod_base_process_info pr4 ON pr4.process_id = p4.process_id
INNER JOIN Plans pl ON pl.plan_code = p4.plan_code AND pl.tenant_id = p4.tenant_id
),
DistinctProcess AS (
-- 按计划+工序聚合为唯一工序,避免同一工序多行导致工序数偏大
SELECT
plan_code,
tenant_id,
process_id,
MAX(ISNULL(process_order,0)) AS process_order,
MAX(CASE WHEN plan_status = '3' THEN 1 ELSE 0 END) AS isCompleted,
MAX(CASE WHEN plan_status = '2' THEN 1 ELSE 0 END) AS isInProgress,
SUM(ISNULL(plan_amount,0)) AS plan_amount,
SUM(ISNULL(complete_amount,0)) AS complete_amount,
MAX(process_name) AS process_name
FROM ProcessRows
GROUP BY plan_code, tenant_id, process_id
),
ProcessStats AS (
-- 统计每个订单的工序进度(以唯一工序为单位)
SELECT
dp.plan_code,
dp.tenant_id,
COUNT(*) AS totalProcessCount,
SUM(dp.isCompleted) AS completedProcessCount,
SUM(dp.isInProgress) AS wipProcessCount,
MAX(CASE WHEN dp.isCompleted = 1 THEN dp.process_order ELSE 0 END) AS maxCompletedOrder,
STRING_AGG(CASE WHEN dp.isInProgress = 1 THEN dp.process_name END, ',') AS wipProcessNames,
STRING_AGG(CASE WHEN dp.isCompleted = 0 AND dp.isInProgress = 0 THEN dp.process_name END, ',') AS remainingProcessNames,
SUM(CASE WHEN dp.isInProgress = 1 THEN ISNULL(dp.plan_amount - dp.complete_amount, 0) * dp.process_order ELSE 0 END) AS wipWeightedSum
FROM DistinctProcess dp
GROUP BY dp.plan_code, dp.tenant_id
),
PlanAgg AS (
-- 按计划聚合计划信息(按 plan_code 维度)
SELECT
p.plan_code,
p.tenant_id,
MIN(p.plan_begin_time) AS plan_begin_time,
MIN(p.real_begin_time) AS real_begin_time,
MAX(p.plan_end_time) AS plan_end_time,
SUM(ISNULL(p.plan_amount,0)) AS plan_amount,
SUM(ISNULL(p.complete_amount,0)) AS complete_amount,
MAX(p.material_id) AS material_id
FROM (
SELECT plan_code, tenant_id, plan_begin_time, real_begin_time, plan_end_time, plan_amount, complete_amount, material_id
FROM prod_plan_info_2
UNION ALL
SELECT plan_code, tenant_id, plan_begin_time, real_begin_time, plan_end_time, plan_amount, complete_amount, material_id
FROM prod_plan_info_3
UNION ALL
SELECT plan_code, tenant_id, plan_begin_time, real_begin_time, plan_end_time, plan_amount, complete_amount, material_id
FROM prod_plan_info_4
) p
INNER JOIN Plans pl ON pl.plan_code = p.plan_code AND pl.tenant_id = p.tenant_id
GROUP BY p.plan_code, p.tenant_id
)
SELECT
NULL AS productOrderId,
'' AS orderCode,
oa.plan_code AS planCode,
m.material_code AS materialCode,
m.material_name AS materialName,
ISNULL(m.material_spec, '') AS materialSpec,
CAST(oa.plan_amount AS DECIMAL(18,2)) AS planAmount,
CAST(ISNULL(oa.plan_amount,0) - ISNULL(oa.complete_amount,0) AS DECIMAL(18,2)) AS wipAmount,
CAST(ISNULL(oa.complete_amount,0) AS DECIMAL(18,2)) AS completeAmount,
oa.plan_begin_time AS planBeginTime,
oa.real_begin_time AS realBeginTime,
oa.plan_end_time AS planEndTime,
GETDATE() AS currentTime,
CAST(ISNULL(ps.totalProcessCount, 0) AS VARCHAR(10)) + '道' AS totalProcessCount,
LTRIM(RTRIM(REPLACE(REPLACE(ISNULL(ps.wipProcessNames, ''), ',,', ','), ',', ','))) AS wipProcesses,
LTRIM(RTRIM(REPLACE(REPLACE(ISNULL(ps.remainingProcessNames, ''), ',,', ','), ',', ','))) AS remainingProcesses,
-- 整体进度计算:已完成数量 / 计划总数量
CONCAT(
CAST(
CASE
WHEN oa.plan_amount > 0
THEN (CAST(ISNULL(oa.complete_amount,0) AS DECIMAL(18,6)) / CAST(oa.plan_amount AS DECIMAL(18,6))) * 100
ELSE 0
END
AS DECIMAL(10,2)), '%'
) AS overallProgress,
-- 进度状态判断:延期或正常
CASE
WHEN oa.plan_end_time IS NOT NULL AND GETDATE() > oa.plan_end_time AND ISNULL(oa.complete_amount,0) &lt; oa.plan_amount
THEN '延期'
ELSE '正常'
END AS progressStatus,
ISNULL(ps.totalProcessCount, 0) AS totalProcessCountNum,
CAST(ISNULL(ps.wipWeightedSum, 0) AS DECIMAL(18,2)) AS wipWeightedSum,
-- 数值型整体进度(不带百分号)
CAST(
CASE
WHEN oa.plan_amount > 0
THEN (CAST(ISNULL(oa.complete_amount,0) AS DECIMAL(18,6)) / CAST(oa.plan_amount AS DECIMAL(18,6))) * 100
ELSE 0
END
AS DECIMAL(10,2)) AS overallProgressNum
FROM PlanAgg oa
INNER JOIN base_material_info m ON m.material_id = oa.material_id
LEFT JOIN ProcessStats ps ON ps.plan_code = oa.plan_code AND ps.tenant_id = oa.tenant_id
<where>
<!-- 进度状态过滤单独保留在最终结果上 -->
<if test="map.progressStatus != null and map.progressStatus != ''">
AND CASE
WHEN oa.plan_end_time IS NOT NULL AND GETDATE() > oa.plan_end_time AND ISNULL(oa.complete_amount,0) &lt; oa.plan_amount
THEN '延期'
ELSE '正常'
END = #{map.progressStatus}
</if>
</where>
-- 为避免首屏仅出现以 'PLAN' 开头的计划编号(字符串排序导致),
-- 改为按时间优先降序,其次按计划编号升序,确保不同编码规则的计划均能出现在第一页
ORDER BY oa.plan_begin_time DESC, oa.real_begin_time DESC, oa.plan_code ASC
</select>
<!-- 在制品跟踪报表总数(简化版 count避免复杂 CTE/聚合,保持与筛选条件一致 -->
<select id="wipTrackingReportCount" resultType="java.lang.Long">
WITH Plans AS (
SELECT p.plan_code, p.tenant_id
FROM (
SELECT product_order_id, tenant_id, material_id, plan_begin_time, plan_code FROM prod_plan_info_2
UNION ALL
SELECT product_order_id, tenant_id, material_id, plan_begin_time, plan_code FROM prod_plan_info_3
UNION ALL
SELECT product_order_id, tenant_id, material_id, plan_begin_time, plan_code FROM prod_plan_info_4
) p
INNER JOIN base_material_info m ON m.material_id = p.material_id
WHERE m.del_flag = '0'
<if test="map.tenantId != null and map.tenantId != ''">
AND p.tenant_id = #{map.tenantId}
</if>
<if test="map.beginDate != null and map.beginDate != '' and map.endDate != null and map.endDate != ''">
AND p.plan_begin_time <![CDATA[>=]]> CAST(#{map.beginDate} AS DATETIME)
AND p.plan_begin_time <![CDATA[<]]> DATEADD(day, 1, CAST(#{map.endDate} AS DATETIME))
</if>
<if test="map.planCode != null and map.planCode != ''">
AND p.plan_code LIKE CONCAT('%', #{map.planCode}, '%')
</if>
<if test="map.materialName != null and map.materialName != ''">
AND m.material_name LIKE CONCAT('%', #{map.materialName}, '%')
</if>
<if test="map.materialCode != null and map.materialCode != ''">
AND m.material_code LIKE CONCAT('%', #{map.materialCode}, '%')
</if>
GROUP BY p.plan_code, p.tenant_id
),
PlanAgg AS (
SELECT
p.plan_code,
p.tenant_id,
MAX(p.plan_code) AS plan_code,
MAX(p.material_id) AS material_id,
MAX(p.plan_end_time) AS plan_end_time,
SUM(ISNULL(p.plan_amount,0)) AS plan_amount,
SUM(ISNULL(p.complete_amount,0)) AS complete_amount
FROM (
SELECT plan_code, tenant_id, plan_end_time, plan_amount, complete_amount, material_id FROM prod_plan_info_2
UNION ALL
SELECT plan_code, tenant_id, plan_end_time, plan_amount, complete_amount, material_id FROM prod_plan_info_3
UNION ALL
SELECT plan_code, tenant_id, plan_end_time, plan_amount, complete_amount, material_id FROM prod_plan_info_4
) p
INNER JOIN Plans pl ON pl.plan_code = p.plan_code AND pl.tenant_id = p.tenant_id
GROUP BY p.plan_code, p.tenant_id
)
SELECT COUNT(*)
FROM PlanAgg oa
INNER JOIN base_material_info m ON m.material_id = oa.material_id
WHERE m.del_flag = '0'
<if test="map.progressStatus != null and map.progressStatus != ''">
AND CASE
WHEN oa.plan_end_time IS NOT NULL AND GETDATE() > oa.plan_end_time AND ISNULL(oa.complete_amount,0) <![CDATA[<]]> oa.plan_amount THEN '延期'
ELSE '正常'
END = #{map.progressStatus}
</if>
</select>
<!-- (已清理)订单维度的工序进度查询已移除,统一按 plan_code 维度处理 -->
<!-- 获取计划的工序进度详情按planCode单条 -->
<select id="getPlanProcessProgress" resultType="org.dromara.mes.domain.vo.ProcessProgressVo">
SELECT
p.plan_code AS planCode,
p.process_id AS processId,
ISNULL(pr.process_name, '未知工序') AS processName,
ISNULL(p.process_order, 0) AS processOrder,
ISNULL(p.plan_status, '0') AS planStatus,
CASE ISNULL(p.plan_status, '0')
WHEN '0' THEN '未派工'
WHEN '1' THEN '已派工'
WHEN '2' THEN '进行中'
WHEN '3' THEN '已完成'
ELSE '未知'
END AS statusDesc,
CASE WHEN p.plan_status = '3' THEN 1 ELSE 0 END AS isCompleted,
CASE WHEN p.plan_status = '2' THEN 1 ELSE 0 END AS isInProgress,
CAST(ISNULL(p.plan_amount, 0) AS DECIMAL(18,2)) AS planAmount,
CAST(ISNULL(p.complete_amount, 0) AS DECIMAL(18,2)) AS completeAmount,
CAST(ISNULL(p.plan_amount, 0) - ISNULL(p.complete_amount, 0) AS DECIMAL(18,2)) AS remainingAmount,
CAST(
CASE WHEN ISNULL(p.plan_amount, 0) > 0
THEN (CAST(ISNULL(p.complete_amount, 0) AS DECIMAL(18,6)) / CAST(p.plan_amount AS DECIMAL(18,6))) * 100
ELSE 0
END
AS DECIMAL(10,2)) AS processProgress,
p.plan_begin_time AS planBeginTime,
p.plan_end_time AS planEndTime,
p.real_begin_time AS realBeginTime,
p.real_end_time AS realEndTime,
bmi.material_name AS materialName,
bmi.material_code AS materialCode
FROM ${planTableName} p
LEFT JOIN prod_base_process_info pr ON pr.process_id = p.process_id
LEFT JOIN base_material_info bmi ON bmi.material_id = p.material_id
WHERE p.plan_code = #{planCode}
ORDER BY p.process_order
</select>
<!-- 批量获取计划的工序进度详情按planCode批量 -->
<select id="getPlansProcessProgressBatch" resultType="org.dromara.mes.domain.vo.ProcessProgressVo">
SELECT
p.plan_code AS planCode,
p.process_id AS processId,
ISNULL(pr.process_name, '未知工序') AS processName,
ISNULL(p.process_order, 0) AS processOrder,
ISNULL(p.plan_status, '0') AS planStatus,
CASE ISNULL(p.plan_status, '0')
WHEN '0' THEN '未派工'
WHEN '1' THEN '已派工'
WHEN '2' THEN '进行中'
WHEN '3' THEN '已完成'
ELSE '未知'
END AS statusDesc,
CASE WHEN p.plan_status = '3' THEN 1 ELSE 0 END AS isCompleted,
CASE WHEN p.plan_status = '2' THEN 1 ELSE 0 END AS isInProgress,
CAST(ISNULL(p.plan_amount, 0) AS DECIMAL(18,2)) AS planAmount,
CAST(ISNULL(p.complete_amount, 0) AS DECIMAL(18,2)) AS completeAmount,
CAST(ISNULL(p.plan_amount, 0) - ISNULL(p.complete_amount, 0) AS DECIMAL(18,2)) AS remainingAmount,
CAST(
CASE WHEN ISNULL(p.plan_amount, 0) > 0
THEN (CAST(ISNULL(p.complete_amount, 0) AS DECIMAL(18,6)) / CAST(p.plan_amount AS DECIMAL(18,6))) * 100
ELSE 0
END
AS DECIMAL(10,2)) AS processProgress,
p.plan_begin_time AS planBeginTime,
p.plan_end_time AS planEndTime,
p.real_begin_time AS realBeginTime,
p.real_end_time AS realEndTime,
bmi.material_name AS materialName,
bmi.material_code AS materialCode
FROM ${planTableName} p
LEFT JOIN prod_base_process_info pr ON pr.process_id = p.process_id
LEFT JOIN base_material_info bmi ON bmi.material_id = p.material_id
WHERE p.plan_code IN
<foreach collection="planCodes" item="code" open="(" separator="," close=")">
#{code}
</foreach>
<if test="tenantId != null"> AND p.tenant_id = #{tenantId} </if>
ORDER BY p.plan_code, p.process_order
</select>
<!-- 工序下的计划子节点查询:按 plan_code + process_id 过滤,计划级视图(不关联明细表) -->
<select id="getPlanProcessDetailChildren" resultType="java.util.HashMap">
SELECT
ppi.plan_id AS planId,
ppi.plan_code AS planCode,
ppi.process_id AS processId,
ppi.process_order AS processOrder,
ISNULL(ppi.plan_amount, 0) AS planAmount,
ISNULL(ppi.complete_amount, 0) AS completeAmount,
ppi.real_begin_time AS realBeginTime,
ppi.real_end_time AS realEndTime,
ISNULL(bct.team_name, '') AS teamName,
ISNULL(pbsi.station_name, '') AS stationName,
ISNULL(ppi.plan_status, '0') AS planStatus
FROM ${planTableName} ppi
LEFT JOIN base_class_team_info bct ON bct.class_team_id = ppi.class_team_id
LEFT JOIN prod_base_station_info pbsi ON pbsi.station_id = bct.station_id
WHERE ppi.plan_code = #{planCode}
<if test="processId != null"> AND ppi.process_id = #{processId} </if>
<if test="tenantId != null"> AND ppi.tenant_id = #{tenantId} </if>
ORDER BY ppi.real_begin_time, ppi.plan_id
</select>
<!-- 小时产量统计按扫描时间小时分桶来源于生产产出扫描表不依赖QC质检表 -->
<select id="hourlyOutputByHour" resultType="java.util.HashMap">
SELECT
CONVERT(DATE, t.create_time) AS productionDate,
RIGHT('00' + CAST(DATEPART(HOUR, t.create_time) AS VARCHAR(2)), 2) + ':00' AS hourSlot,
CAST(COUNT(1) AS DECIMAL(18,4)) AS productionQuantity,
CAST(SUM(CASE WHEN (UPPER(t.scan_result) IN ('OK','PASS') OR t.scan_result IN (N'通过')) THEN 1 ELSE 0 END) AS DECIMAL(18,4)) AS qualifiedQuantity,
CAST(SUM(CASE WHEN t.scan_result IS NULL THEN 0 WHEN (UPPER(t.scan_result) IN ('OK','PASS') OR t.scan_result IN (N'通过')) THEN 0 ELSE 1 END) AS DECIMAL(18,4)) AS unqualifiedQuantity
FROM prod_output_scan_info t
LEFT JOIN ${planTableName} ppi
ON ppi.process_id = t.process_id
AND ppi.release_id = t.machine_id
AND t.create_time &gt;= COALESCE(ppi.real_begin_time, ppi.plan_begin_time)
AND t.create_time &lt; COALESCE(ppi.real_end_time, ppi.plan_end_time, DATEADD(day, 1, COALESCE(ppi.real_begin_time, ppi.plan_begin_time)))
LEFT JOIN base_material_info bmi ON bmi.material_id = t.materiel_id
<where>
<if test="map.beginDate != null and map.beginDate != '' and map.endDate != null and map.endDate != ''">
AND t.create_time &gt;= CAST(#{map.beginDate} AS DATETIME)
AND t.create_time &lt; DATEADD(day, 1, CAST(#{map.endDate} AS DATETIME))
</if>
<if test="map.processId != null and map.processId != ''">
AND t.process_id = #{map.processId}
</if>
<if test="map.machineId != null and map.machineId != ''">
AND t.machine_id = #{map.machineId}
</if>
<if test="map.shiftId != null and map.shiftId != ''">
AND ppi.shift_id = #{map.shiftId}
</if>
<if test="map.classTeamId != null and map.classTeamId != ''">
AND ppi.class_team_id = #{map.classTeamId}
</if>
<if test="map.materialName != null and map.materialName != ''">
AND bmi.material_name LIKE CONCAT('%', #{map.materialName}, '%')
</if>
</where>
GROUP BY CONVERT(DATE, t.create_time), DATEPART(HOUR, t.create_time)
ORDER BY productionDate, DATEPART(HOUR, t.create_time)
</select>
<!-- 工序生产统计(按工序聚合):完成数量、未完成数量与完成率 -->
<select id="processWorkOrderStats" resultType="java.util.HashMap">
<![CDATA[
SELECT
ISNULL(pproc.process_name, N'未知工序') AS processName,
-- 汇总计划与完成数量
CAST(SUM(ISNULL(p.plan_amount, 0)) AS DECIMAL(18,4)) AS planQty,
CAST(SUM(ISNULL(p.complete_amount, 0)) AS DECIMAL(18,4)) AS completedQty,
CAST(SUM(ISNULL(p.plan_amount, 0) - ISNULL(p.complete_amount, 0)) AS DECIMAL(18,4)) AS uncompletedQty,
-- 完成率(数值 & 展示)
CAST(
CASE WHEN SUM(ISNULL(p.plan_amount, 0)) > 0
THEN (CAST(SUM(ISNULL(p.complete_amount, 0)) AS DECIMAL(18,6)) / CAST(SUM(ISNULL(p.plan_amount, 0)) AS DECIMAL(18,6))) * 100
ELSE 0 END
AS DECIMAL(10,2)) AS completionRateNum,
CONCAT(
CAST(
CASE WHEN SUM(ISNULL(p.plan_amount, 0)) > 0
THEN (CAST(SUM(ISNULL(p.complete_amount, 0)) AS DECIMAL(18,6)) / CAST(SUM(ISNULL(p.plan_amount, 0)) AS DECIMAL(18,6))) * 100
ELSE 0 END
AS DECIMAL(10,2)
), '%') AS completionRate
FROM ${planTableName} AS p
LEFT JOIN prod_base_process_info AS pproc ON pproc.process_id = p.process_id
LEFT JOIN base_material_info AS bmi ON bmi.material_id = p.material_id
]]>
<where>
<if test="map.beginDate != null and map.beginDate != '' and map.endDate != null and map.endDate != ''">
AND FORMAT(p.plan_begin_time, 'yyyy-MM-dd') BETWEEN #{map.beginDate} AND #{map.endDate}
</if>
<if test="map.processId != null and map.processId != ''">
AND p.process_id = #{map.processId}
</if>
<if test="map.machineId != null and map.machineId != ''">
AND p.release_id = #{map.machineId}
</if>
<if test="map.shiftId != null and map.shiftId != ''">
AND p.shift_id = #{map.shiftId}
</if>
<if test="map.classTeamId != null and map.classTeamId != ''">
AND p.class_team_id = #{map.classTeamId}
</if>
<if test="map.planCode != null and map.planCode != ''">
AND p.plan_code LIKE CONCAT('%', #{map.planCode}, '%')
</if>
<if test="map.materialName != null and map.materialName != ''">
AND bmi.material_name LIKE CONCAT('%', #{map.materialName}, '%')
</if>
</where>
<![CDATA[
GROUP BY ISNULL(pproc.process_name, N'未知工序')
ORDER BY completionRateNum DESC, processName
]]>
</select>
</mapper>
Loading…
Cancel
Save