feat: 新增生产日报报表模块及相关接口(TASK-xxx)

实现完整的生产日报业务功能,包含查询汇总、按日列表、工单明细、设备产出明细接口,配套Mapper、实体类和Controller层代码
master
zch 3 weeks ago
parent 2637ce278a
commit f785fa3cfd

@ -0,0 +1,64 @@
package com.aucma.report.controller;
import com.aucma.common.core.controller.BaseController;
import com.aucma.common.core.domain.AjaxResult;
import com.aucma.common.core.page.TableDataInfo;
import com.aucma.report.domain.vo.ProductionDailyReportDeviceVo;
import com.aucma.report.domain.vo.ProductionDailyReportOrderVo;
import com.aucma.report.domain.vo.ProductionDailyReportQuery;
import com.aucma.report.service.IProductionDailyReportService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* Controller
*
* @author Codex
*/
@RestController
@RequestMapping("/report/productionDailyReport")
public class ProductionDailyReportController extends BaseController {
@Autowired
private IProductionDailyReportService productionDailyReportService;
/**
*
*/
@GetMapping("/summary")
public AjaxResult summary(ProductionDailyReportQuery query) {
return success(productionDailyReportService.getSummary(query));
}
/**
*
*/
@GetMapping("/dailyList")
public AjaxResult dailyList(ProductionDailyReportQuery query) {
return success(productionDailyReportService.getDailyList(query));
}
/**
*
*/
@GetMapping("/orderList")
public TableDataInfo orderList(ProductionDailyReportQuery query) {
startPage();
List<ProductionDailyReportOrderVo> list = productionDailyReportService.getOrderList(query);
return getDataTable(list);
}
/**
*
*/
@GetMapping("/deviceList")
public TableDataInfo deviceList(ProductionDailyReportQuery query) {
startPage();
List<ProductionDailyReportDeviceVo> list = productionDailyReportService.getDeviceList(query);
return getDataTable(list);
}
}

@ -0,0 +1,54 @@
package com.aucma.report.domain.vo;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* /
* Java N+1 SQL
*
* @author Antigravity
*/
public class ParamRawPoint implements Serializable {
private static final long serialVersionUID = 1L;
/**
*
*/
private String deviceCode;
/**
*
*/
private Date collectTime;
/**
*
*/
private BigDecimal paramValue;
public String getDeviceCode() {
return deviceCode;
}
public void setDeviceCode(String deviceCode) {
this.deviceCode = deviceCode;
}
public Date getCollectTime() {
return collectTime;
}
public void setCollectTime(Date collectTime) {
this.collectTime = collectTime;
}
public BigDecimal getParamValue() {
return paramValue;
}
public void setParamValue(BigDecimal paramValue) {
this.paramValue = paramValue;
}
}

@ -0,0 +1,41 @@
package com.aucma.report.domain.vo;
import java.io.Serializable;
import java.math.BigDecimal;
/**
*
*
* @author Codex
*/
public class ProductionDailyReportDeviceVo implements Serializable {
private static final long serialVersionUID = 1L;
private String deviceCode;
private String deviceName;
private BigDecimal actualQty;
public String getDeviceCode() {
return deviceCode;
}
public void setDeviceCode(String deviceCode) {
this.deviceCode = deviceCode;
}
public String getDeviceName() {
return deviceName;
}
public void setDeviceName(String deviceName) {
this.deviceName = deviceName;
}
public BigDecimal getActualQty() {
return actualQty;
}
public void setActualQty(BigDecimal actualQty) {
this.actualQty = actualQty;
}
}

@ -0,0 +1,86 @@
package com.aucma.report.domain.vo;
import java.io.Serializable;
import java.math.BigDecimal;
/**
*
*
* @author Codex
*/
public class ProductionDailyReportOrderVo implements Serializable {
private static final long serialVersionUID = 1L;
private String orderCode;
private String materialCode;
private String materialName;
private String workCenterCode;
private String productLineName;
private BigDecimal planQty;
private String beginDate;
private String endDate;
public String getOrderCode() {
return orderCode;
}
public void setOrderCode(String orderCode) {
this.orderCode = orderCode;
}
public String getMaterialCode() {
return materialCode;
}
public void setMaterialCode(String materialCode) {
this.materialCode = materialCode;
}
public String getMaterialName() {
return materialName;
}
public void setMaterialName(String materialName) {
this.materialName = materialName;
}
public String getWorkCenterCode() {
return workCenterCode;
}
public void setWorkCenterCode(String workCenterCode) {
this.workCenterCode = workCenterCode;
}
public String getProductLineName() {
return productLineName;
}
public void setProductLineName(String productLineName) {
this.productLineName = productLineName;
}
public BigDecimal getPlanQty() {
return planQty;
}
public void setPlanQty(BigDecimal planQty) {
this.planQty = planQty;
}
public String getBeginDate() {
return beginDate;
}
public void setBeginDate(String beginDate) {
this.beginDate = beginDate;
}
public String getEndDate() {
return endDate;
}
public void setEndDate(String endDate) {
this.endDate = endDate;
}
}

@ -0,0 +1,78 @@
package com.aucma.report.domain.vo;
import java.io.Serializable;
/**
*
*
* @author Codex
*/
public class ProductionDailyReportQuery implements Serializable {
private static final long serialVersionUID = 1L;
/** 查询开始日期格式yyyy-MM-dd */
private String beginDate;
/** 查询结束日期格式yyyy-MM-dd */
private String endDate;
/** 工单号,可选 */
private String orderCode;
/** 物料编码,可选 */
private String materialCode;
/** 物料名称,可选 */
private String materialName;
/** 工作中心,可选 */
private String workCenterCode;
public String getBeginDate() {
return beginDate;
}
public void setBeginDate(String beginDate) {
this.beginDate = beginDate;
}
public String getEndDate() {
return endDate;
}
public void setEndDate(String endDate) {
this.endDate = endDate;
}
public String getOrderCode() {
return orderCode;
}
public void setOrderCode(String orderCode) {
this.orderCode = orderCode;
}
public String getMaterialCode() {
return materialCode;
}
public void setMaterialCode(String materialCode) {
this.materialCode = materialCode;
}
public String getMaterialName() {
return materialName;
}
public void setMaterialName(String materialName) {
this.materialName = materialName;
}
public String getWorkCenterCode() {
return workCenterCode;
}
public void setWorkCenterCode(String workCenterCode) {
this.workCenterCode = workCenterCode;
}
}

@ -0,0 +1,95 @@
package com.aucma.report.domain.vo;
import java.io.Serializable;
import java.math.BigDecimal;
/**
*
*
* @author Codex
*/
public class ProductionDailyReportRowVo implements Serializable {
private static final long serialVersionUID = 1L;
private String reportDate;
private Long orderCount;
private BigDecimal planQty;
private BigDecimal actualQty;
private BigDecimal goodQty;
private BigDecimal defectQty;
private BigDecimal completionRate;
private BigDecimal goodRate;
private Long producedDeviceCount;
public String getReportDate() {
return reportDate;
}
public void setReportDate(String reportDate) {
this.reportDate = reportDate;
}
public Long getOrderCount() {
return orderCount;
}
public void setOrderCount(Long orderCount) {
this.orderCount = orderCount;
}
public BigDecimal getPlanQty() {
return planQty;
}
public void setPlanQty(BigDecimal planQty) {
this.planQty = planQty;
}
public BigDecimal getActualQty() {
return actualQty;
}
public void setActualQty(BigDecimal actualQty) {
this.actualQty = actualQty;
}
public BigDecimal getGoodQty() {
return goodQty;
}
public void setGoodQty(BigDecimal goodQty) {
this.goodQty = goodQty;
}
public BigDecimal getDefectQty() {
return defectQty;
}
public void setDefectQty(BigDecimal defectQty) {
this.defectQty = defectQty;
}
public BigDecimal getCompletionRate() {
return completionRate;
}
public void setCompletionRate(BigDecimal completionRate) {
this.completionRate = completionRate;
}
public BigDecimal getGoodRate() {
return goodRate;
}
public void setGoodRate(BigDecimal goodRate) {
this.goodRate = goodRate;
}
public Long getProducedDeviceCount() {
return producedDeviceCount;
}
public void setProducedDeviceCount(Long producedDeviceCount) {
this.producedDeviceCount = producedDeviceCount;
}
}

@ -0,0 +1,104 @@
package com.aucma.report.domain.vo;
import java.io.Serializable;
import java.math.BigDecimal;
/**
*
*
* @author Codex
*/
public class ProductionDailyReportSummaryVo implements Serializable {
private static final long serialVersionUID = 1L;
private String beginDate;
private String endDate;
private Long orderCount;
private BigDecimal planQty;
private BigDecimal actualQty;
private BigDecimal goodQty;
private BigDecimal defectQty;
private BigDecimal completionRate;
private BigDecimal goodRate;
private Long producedDeviceCount;
public String getBeginDate() {
return beginDate;
}
public void setBeginDate(String beginDate) {
this.beginDate = beginDate;
}
public String getEndDate() {
return endDate;
}
public void setEndDate(String endDate) {
this.endDate = endDate;
}
public Long getOrderCount() {
return orderCount;
}
public void setOrderCount(Long orderCount) {
this.orderCount = orderCount;
}
public BigDecimal getPlanQty() {
return planQty;
}
public void setPlanQty(BigDecimal planQty) {
this.planQty = planQty;
}
public BigDecimal getActualQty() {
return actualQty;
}
public void setActualQty(BigDecimal actualQty) {
this.actualQty = actualQty;
}
public BigDecimal getGoodQty() {
return goodQty;
}
public void setGoodQty(BigDecimal goodQty) {
this.goodQty = goodQty;
}
public BigDecimal getDefectQty() {
return defectQty;
}
public void setDefectQty(BigDecimal defectQty) {
this.defectQty = defectQty;
}
public BigDecimal getCompletionRate() {
return completionRate;
}
public void setCompletionRate(BigDecimal completionRate) {
this.completionRate = completionRate;
}
public BigDecimal getGoodRate() {
return goodRate;
}
public void setGoodRate(BigDecimal goodRate) {
this.goodRate = goodRate;
}
public Long getProducedDeviceCount() {
return producedDeviceCount;
}
public void setProducedDeviceCount(Long producedDeviceCount) {
this.producedDeviceCount = producedDeviceCount;
}
}

@ -0,0 +1,39 @@
package com.aucma.report.mapper;
import com.aucma.report.domain.vo.ProductionDailyReportDeviceVo;
import com.aucma.report.domain.vo.ProductionDailyReportOrderVo;
import com.aucma.report.domain.vo.ProductionDailyReportQuery;
import com.aucma.report.domain.vo.ProductionDailyReportRowVo;
import com.aucma.report.domain.vo.ProductionDailyReportSummaryVo;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* Mapper
*
* @author Codex
*/
@Mapper
public interface ProductionDailyReportMapper {
/**
*
*/
ProductionDailyReportSummaryVo selectSummary(ProductionDailyReportQuery query);
/**
*
*/
List<ProductionDailyReportRowVo> selectDailyList(ProductionDailyReportQuery query);
/**
*
*/
List<ProductionDailyReportOrderVo> selectOrderList(ProductionDailyReportQuery query);
/**
*
*/
List<ProductionDailyReportDeviceVo> selectDeviceList(ProductionDailyReportQuery query);
}

@ -0,0 +1,37 @@
package com.aucma.report.service;
import com.aucma.report.domain.vo.ProductionDailyReportDeviceVo;
import com.aucma.report.domain.vo.ProductionDailyReportOrderVo;
import com.aucma.report.domain.vo.ProductionDailyReportQuery;
import com.aucma.report.domain.vo.ProductionDailyReportRowVo;
import com.aucma.report.domain.vo.ProductionDailyReportSummaryVo;
import java.util.List;
/**
* Service
*
* @author Codex
*/
public interface IProductionDailyReportService {
/**
*
*/
ProductionDailyReportSummaryVo getSummary(ProductionDailyReportQuery query);
/**
*
*/
List<ProductionDailyReportRowVo> getDailyList(ProductionDailyReportQuery query);
/**
*
*/
List<ProductionDailyReportOrderVo> getOrderList(ProductionDailyReportQuery query);
/**
*
*/
List<ProductionDailyReportDeviceVo> getDeviceList(ProductionDailyReportQuery query);
}

@ -0,0 +1,86 @@
package com.aucma.report.service.impl;
import com.aucma.report.domain.vo.ProductionDailyReportDeviceVo;
import com.aucma.report.domain.vo.ProductionDailyReportOrderVo;
import com.aucma.report.domain.vo.ProductionDailyReportQuery;
import com.aucma.report.domain.vo.ProductionDailyReportRowVo;
import com.aucma.report.domain.vo.ProductionDailyReportSummaryVo;
import com.aucma.report.mapper.ProductionDailyReportMapper;
import com.aucma.report.service.IProductionDailyReportService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
/**
* Service
*
* @author Codex
*/
@Service
public class ProductionDailyReportServiceImpl implements IProductionDailyReportService {
@Autowired
private ProductionDailyReportMapper productionDailyReportMapper;
@Override
public ProductionDailyReportSummaryVo getSummary(ProductionDailyReportQuery query) {
ProductionDailyReportQuery normalizedQuery = normalizeQuery(query);
ProductionDailyReportSummaryVo summary = productionDailyReportMapper.selectSummary(normalizedQuery);
if (summary != null) {
summary.setBeginDate(normalizedQuery.getBeginDate());
summary.setEndDate(normalizedQuery.getEndDate());
}
return summary;
}
@Override
public List<ProductionDailyReportRowVo> getDailyList(ProductionDailyReportQuery query) {
return productionDailyReportMapper.selectDailyList(normalizeQuery(query));
}
@Override
public List<ProductionDailyReportOrderVo> getOrderList(ProductionDailyReportQuery query) {
return productionDailyReportMapper.selectOrderList(normalizeQuery(query));
}
@Override
public List<ProductionDailyReportDeviceVo> getDeviceList(ProductionDailyReportQuery query) {
return productionDailyReportMapper.selectDeviceList(normalizeQuery(query));
}
private ProductionDailyReportQuery normalizeQuery(ProductionDailyReportQuery query) {
ProductionDailyReportQuery normalizedQuery = query == null ? new ProductionDailyReportQuery() : query;
String today = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
if (isBlank(normalizedQuery.getBeginDate())) {
normalizedQuery.setBeginDate(today);
}
if (isBlank(normalizedQuery.getEndDate())) {
normalizedQuery.setEndDate(normalizedQuery.getBeginDate());
}
validateDate(normalizedQuery.getBeginDate(), "beginDate");
validateDate(normalizedQuery.getEndDate(), "endDate");
if (normalizedQuery.getBeginDate().compareTo(normalizedQuery.getEndDate()) > 0) {
throw new IllegalArgumentException("开始日期不能大于结束日期");
}
return normalizedQuery;
}
private void validateDate(String value, String fieldName) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setLenient(false);
try {
dateFormat.parse(value);
} catch (ParseException e) {
// 报表日期是SQL范围条件必须Fail Fast避免无效字符串进入Oracle日期转换。
throw new IllegalArgumentException(fieldName + "日期格式必须为yyyy-MM-dd");
}
}
private boolean isBlank(String value) {
return value == null || value.trim().length() == 0;
}
}

@ -0,0 +1,146 @@
<?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="com.aucma.report.mapper.ProductionDailyReportMapper">
<sql id="orderFilter">
<if test="orderCode != null and orderCode != ''">
AND bo.order_code = #{orderCode}
</if>
<if test="materialCode != null and materialCode != ''">
AND bo.material_code = #{materialCode}
</if>
<if test="materialName != null and materialName != ''">
AND bo.material_name LIKE '%' || #{materialName} || '%'
</if>
<if test="workCenterCode != null and workCenterCode != ''">
AND bo.work_center_code = #{workCenterCode}
</if>
</sql>
<sql id="actualProductionSource">
SELECT d.prod_date AS report_date,
d.device_code,
d.daily_prod AS actual_qty
FROM DEVICE_DAILY_PRODUCTION d
WHERE d.prod_date &gt;= TO_DATE(#{beginDate}, 'YYYY-MM-DD')
AND d.prod_date &lt; TO_DATE(#{endDate}, 'YYYY-MM-DD') + 1
AND d.prod_date &lt; TRUNC(SYSDATE)
AND d.param_name = '机台状态-实际产出数量'
UNION ALL
SELECT r.prod_date AS report_date,
r.device_code,
r.current_total AS actual_qty
FROM RT_DAILY_PROD_STATE r
WHERE r.prod_date = TRUNC(SYSDATE)
AND r.prod_date &gt;= TO_DATE(#{beginDate}, 'YYYY-MM-DD')
AND r.prod_date &lt; TO_DATE(#{endDate}, 'YYYY-MM-DD') + 1
AND r.param_name = '机台状态-实际产出数量'
</sql>
<select id="selectSummary" parameterType="com.aucma.report.domain.vo.ProductionDailyReportQuery"
resultType="com.aucma.report.domain.vo.ProductionDailyReportSummaryVo">
WITH plan_summary AS (
SELECT COUNT(1) AS order_count,
NVL(SUM(bo.order_amount), 0) AS plan_qty
FROM BASE_ORDERINFO bo
WHERE bo.begin_date &gt;= TO_DATE(#{beginDate}, 'YYYY-MM-DD')
AND bo.begin_date &lt; TO_DATE(#{endDate}, 'YYYY-MM-DD') + 1
<include refid="orderFilter"/>
),
actual_summary AS (
SELECT NVL(SUM(actual_qty), 0) AS actual_qty,
COUNT(DISTINCT CASE WHEN actual_qty &gt; 0 THEN device_code END) AS produced_device_count
FROM (
<!-- 为什么这样做日报不依赖人工及时操作工单实际产出直接采用已修复的DAY/RT权威产量层。 -->
<include refid="actualProductionSource"/>
)
)
SELECT p.order_count AS orderCount,
p.plan_qty AS planQty,
a.actual_qty AS actualQty,
a.actual_qty AS goodQty,
0 AS defectQty,
CASE WHEN p.plan_qty &gt; 0 THEN ROUND(a.actual_qty / p.plan_qty * 100, 2) ELSE 0 END AS completionRate,
100 AS goodRate,
a.produced_device_count AS producedDeviceCount
FROM plan_summary p, actual_summary a
</select>
<select id="selectDailyList" parameterType="com.aucma.report.domain.vo.ProductionDailyReportQuery"
resultType="com.aucma.report.domain.vo.ProductionDailyReportRowVo">
WITH date_scope AS (
SELECT TO_DATE(#{beginDate}, 'YYYY-MM-DD') + LEVEL - 1 AS report_date
FROM dual
CONNECT BY LEVEL &lt;= TO_DATE(#{endDate}, 'YYYY-MM-DD') - TO_DATE(#{beginDate}, 'YYYY-MM-DD') + 1
),
plan_day AS (
SELECT TRUNC(bo.begin_date) AS report_date,
COUNT(1) AS order_count,
NVL(SUM(bo.order_amount), 0) AS plan_qty
FROM BASE_ORDERINFO bo
WHERE bo.begin_date &gt;= TO_DATE(#{beginDate}, 'YYYY-MM-DD')
AND bo.begin_date &lt; TO_DATE(#{endDate}, 'YYYY-MM-DD') + 1
<include refid="orderFilter"/>
GROUP BY TRUNC(bo.begin_date)
),
actual_day AS (
SELECT report_date,
NVL(SUM(actual_qty), 0) AS actual_qty,
COUNT(DISTINCT CASE WHEN actual_qty &gt; 0 THEN device_code END) AS produced_device_count
FROM (
<!-- 为什么这样做历史日取DAY、当天取RT和Board4月累计口径保持一致避免今日DAY误写造成重复。 -->
<include refid="actualProductionSource"/>
)
GROUP BY report_date
)
SELECT TO_CHAR(ds.report_date, 'YYYY-MM-DD') AS reportDate,
NVL(pd.order_count, 0) AS orderCount,
NVL(pd.plan_qty, 0) AS planQty,
NVL(ad.actual_qty, 0) AS actualQty,
NVL(ad.actual_qty, 0) AS goodQty,
0 AS defectQty,
CASE WHEN NVL(pd.plan_qty, 0) &gt; 0 THEN ROUND(NVL(ad.actual_qty, 0) / pd.plan_qty * 100, 2) ELSE 0 END AS completionRate,
100 AS goodRate,
NVL(ad.produced_device_count, 0) AS producedDeviceCount
FROM date_scope ds
LEFT JOIN plan_day pd ON pd.report_date = ds.report_date
LEFT JOIN actual_day ad ON ad.report_date = ds.report_date
ORDER BY ds.report_date DESC
</select>
<select id="selectOrderList" parameterType="com.aucma.report.domain.vo.ProductionDailyReportQuery"
resultType="com.aucma.report.domain.vo.ProductionDailyReportOrderVo">
SELECT bo.order_code AS orderCode,
bo.material_code AS materialCode,
bo.material_name AS materialName,
bo.work_center_code AS workCenterCode,
pl.product_line_name AS productLineName,
bo.order_amount AS planQty,
TO_CHAR(bo.begin_date, 'YYYY-MM-DD') AS beginDate,
TO_CHAR(bo.end_date, 'YYYY-MM-DD') AS endDate
FROM BASE_ORDERINFO bo
LEFT JOIN BASE_PRODUCTLINE pl
ON pl.work_center_code = bo.work_center_code
WHERE bo.begin_date &gt;= TO_DATE(#{beginDate}, 'YYYY-MM-DD')
AND bo.begin_date &lt; TO_DATE(#{endDate}, 'YYYY-MM-DD') + 1
<include refid="orderFilter"/>
ORDER BY bo.begin_date DESC, bo.order_code DESC
</select>
<select id="selectDeviceList" parameterType="com.aucma.report.domain.vo.ProductionDailyReportQuery"
resultType="com.aucma.report.domain.vo.ProductionDailyReportDeviceVo">
SELECT p.device_code AS deviceCode,
NVL(d.device_name, p.device_code) AS deviceName,
SUM(p.actual_qty) AS actualQty
FROM (
<include refid="actualProductionSource"/>
) p
LEFT JOIN BASE_DEVICELEDGER d
ON d.device_code = p.device_code
GROUP BY p.device_code, NVL(d.device_name, p.device_code)
HAVING SUM(p.actual_qty) &gt; 0
ORDER BY SUM(p.actual_qty) DESC, p.device_code
</select>
</mapper>
Loading…
Cancel
Save