废品情况分析——报表接口开发

分享一个1000行代码的报表接口

1 controller

package cn.cncommdata.report.controller;

import cn.cncommdata.form.vo.BaseVO;
import cn.cncommdata.report.service.IWasteAnalysisService;
import cn.cncommdata.report.service.IXianFengScreenService;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @author meihongliang
 * @since 2020/4/10 10:13 下午
 * 险峰大屏展示需要接口
 */
@RestController
public class ScreenController {

    /**
     * 引入service 接口
     */
    @Resource
    private IWasteAnalysisService wasteAnalysisService;
    /**
     * 废品情况分析——hour/kg
     * <p>
     * 数据来源
     * 工票信息:工票号、计量单位、车间完成工时
     * 不合格品通知单:工票号、生产项目、废品原因分析(10大原因)、综合回用量、责任回用量
     * 不合格品指标管理:废品率-指标、责任废品率-指标、综合回用率-指标、责任回用率-指标
     * <p>
     * 201测试数据
     * tenantId//1189773091425882112
     * grantId//1192291334245978112
     * formIds//{"工票信息": 1237569872439939104,"不合格品通知单": 1237569872439939100,"不合格品指标管理": 1255764697836294144}
     *
     *  202测试数据
     *  tenantId//1189773091425882112
     *  grantId//1192291334245978112
     *  formIds//{"工票信息": 1237569872439939104,"不合格品通知单": 1237569872439939100,"不合格品指标管理": 1257869474644758528}
     *
     * @param tenantId 企业id
     * @param grantId  操作员
     * @param formIds  所需表单id的json对象字符串(内部研发项目、外部研发项目、生产技术准备、产品安装调试、进度计划维护)
     * @return 查询结果
     * @author leimin
     */
    @ApiOperation("废品情况分析——工时/重量")
    @PostMapping("/scm/screen/loss")
    public BaseVO<List<Map<String, Object>>> getLossAnalysis(
            @ApiParam(value = "租户Id", required = true) @RequestHeader("tenant_id") Long tenantId,
            @ApiParam(value = "操作者Id", required = true) @RequestHeader("grant_id") Long grantId,
            @ApiParam(value = "表单id的json对象字符串", required = true) @RequestParam("form_ids") String formIds) {

        return wasteAnalysisService.getLossAnalysis(tenantId, grantId, formIds);
    }
}

2 service

package cn.cncommdata.report.service;

import cn.cncommdata.form.vo.BaseVO;

import java.util.List;
import java.util.Map;

/**
 * @author: leimin
 * @description: 废品分析接口方法
 * @date: 2020-04-28
 */
public interface IWasteAnalysisService {
    /**
     * 工时损失废品分析——小时(hour)
     * <p>
     * 数据来源
     * 工票信息:工票号、计量单位、车间完成工时
     * 不合格品通知单:工票号、生产项目、废品原因分析(10大原因)、综合回用量、责任回用量
     * 各种指标:废品率-指标、责任废品率-指标、综合回用率-指标、责任回用率-指标
     *
     * @param tenantId 企业id
     * @param grantId  操作员
     * @param formIds  所需表单id的json对象字符串(内部研发项目、外部研发项目、生产技术准备、产品安装调试、进度计划维护)
     * @return 查询结果
     * @author leimin
     */
    BaseVO<List<Map<String, Object>>> getLossAnalysis(Long tenantId, Long grantId, String formIds);
}

3 serviceImpl

package cn.cncommdata.report.service.impl;

import cn.cncommdata.form.vo.BaseVO;
import cn.cncommdata.form.vo.FormDataVO;
import cn.cncommdata.form.vo.fielddata.CommonDataVO;
import cn.cncommdata.form.vo.fielddata.DataBaseVO;
import cn.cncommdata.form.vo.fielddata.SelectDataVO;
import cn.cncommdata.form.vo.fielddata.TableDataVO;
import cn.cncommdata.form.vo.fielddata.TableRowVO;
import cn.cncommdata.report.service.IWasteAnalysisService;
import cn.cncommdata.report.util.ReportUtil;
import cn.cncommdata.report.util.TimeUtil;
import cn.cncommdata.report.util.constant.Const;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

/**
 * @author: leimin
 * @description: 废品分析实现方法
 * @date: 2020-04-28
 */
@Slf4j
@Service
public class WasteAnalysisServiceImpl implements IWasteAnalysisService {
    /**
     * 引入表单工具
     */
    @Resource
    private ReportUtil reportUtil;

    /**
     * 工时损失废品分析——小时(hour)
     * <p>
     * 数据来源
     * 工票信息:工票号、计量单位、车间完成工时
     * 不合格品通知单:工票号、生产项目、废品原因分析(10大原因)、综合回用量、责任回用量
     * 各种指标:废品率-指标、责任废品率-指标、综合回用率-指标、责任回用率-指标
     *
     * @param tenantId 企业id
     * @param grantId  操作员
     * @param formIds  所需表单id的json对象字符串(内部研发项目、外部研发项目、生产技术准备、产品安装调试、进度计划维护)
     * @return 查询结果
     * @author leimin
     */
    @Override
    public BaseVO<List<Map<String, Object>>> getLossAnalysis(Long tenantId, Long grantId, String formIds) {

        // 查询所有,按年分,再按月分
        // 1。表单有不合格品通知单、工票信息
        // 2。查询所有的不合格品通知单、工票,塞选不匹配的数据(不合格品通知单.工票号 不为空)
        // 3。按yyyy-mm-生产项目作为数据的键,然后获取可以直接获取到的数据,同键的数据累加;
        // 4。通过计算规则计算其余的字段;

        // 1。查询表单数据
        List<Object> unqualifiedList, workTicketList, indexList;

        JSONObject metadataIds = JSONObject.parseObject(formIds);
        if (CollectionUtils.isEmpty(metadataIds)) {
            return new BaseVO<>(BaseVO.ILLEGAL_PARAM_CODE, "参数错误!");
        }

        Long unqualifiedFormId = metadataIds.getLong(Const.NOTICE_OF_UNQUALIFIED_PRODUCT);
        Long workTicketFormId = metadataIds.getLong(Const.WORK_ORDER);
        if (unqualifiedFormId == null || workTicketFormId == null) {
            return new BaseVO<>(BaseVO.ILLEGAL_PARAM_CODE, "参数错误!");
        }

        unqualifiedList = reportUtil.getDataList(tenantId, grantId, unqualifiedFormId);
        if (CollectionUtils.isEmpty(unqualifiedList)) {
            return new BaseVO<>(BaseVO.ILLEGAL_PARAM_CODE, "参数错误!");
        }
        workTicketList = reportUtil.getDataList(tenantId, grantId, workTicketFormId);
        if (CollectionUtils.isEmpty(workTicketList)) {
            return new BaseVO<>(BaseVO.ILLEGAL_PARAM_CODE, "参数错误!");
        }

        Long indexFormId = metadataIds.getLong(Const.INDEX_OF_UNQUALIFIED_PRODUCT);
        if (indexFormId == null) {
            new BaseVO<>(BaseVO.SUCCESS_CODE, "校验成功!");
        }
        indexList = reportUtil.getDataList(tenantId, grantId, indexFormId);


        // 2。筛选数据
        List<FormDataVO> defects = new ArrayList<>();
        List<FormDataVO> workTickets = new ArrayList<>();

        BaseVO baseVo = filterData(unqualifiedList, workTicketList, defects, workTickets);
        if (BaseVO.SUCCESS_CODE != baseVo.getCode()) {
            return baseVo;
        }
        // 组合为所需的数据结构
        HashMap map = new HashMap(Const.SIXTEEN);
        range(defects, workTickets, map);


        // 3。按yyyy-mm-生产项目,作为数据的键,然后获取可以直接获取到的数据,同键的数据累加;
        Map<String, Map<String, Object>> result = new HashMap<>(Const.SIXTEEN);
        middleAnalysis(result, map);

        // 4。计算最终的数据
        lastAnalysis(result, indexList);
        List<Map<String, Object>> list = sortMap(result);
        return new BaseVO<>(BaseVO.SUCCESS_CODE, "校验成功!", list);
    }

    /**
     * 按照给出的顺序排序
     *
     * @param result 排序前
     * @return 排序后
     */
    private List<Map<String, Object>> sortMap(Map<String, Map<String, Object>> result) {

        // 1。找出所有的月分;set
        // 2。然后可以先对所有的月份排序,重新封装
        // 3。遍历月份,解析项目名称和该条数据,加入同类的list;
        // 4。合并

        Set<String> sortSet = new TreeSet<String>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);//降序排列
            }
        });
        Set<String> intKeys = getYearMonth(result, "");
        sortSet.addAll(intKeys);


        List<Map<String, Object>> list = new ArrayList<>();
        for (String key : sortSet) {

            // 生成key
            String yearMonth = key.substring(0, 4) + "-" + key.substring(4);
            for (String project : Const.SORTED_LIST) {
                String finalKey = yearMonth + "-" + project;

                Map<String, Object> map = result.get(finalKey);
                if (CollectionUtils.isEmpty(map)) {
                    continue;
                }
                map.put("key", finalKey);
                list.add(map);
            }

        }
        return list;
    }

    /**
     * 计算最终的数据
     * 1。合并行
     * 2。注入单元格公式计算
     * 3。注入指标
     *
     * @param middle 半成品数据
     */
    private void lastAnalysis(Map<String, Map<String, Object>> middle, List<Object> indexList) {

        if (CollectionUtils.isEmpty(middle)) {
            return;
        }

        // 1。合并行
        mergeRows(middle);
        // 2。注入单元格公式计算
        calculateByCell(middle);
        // 3。注入指标
        setStandard(middle, indexList);

    }

    /**
     * 给数据中的每一行注入指标
     *
     * @param middle    数据
     * @param indexList 指标对象
     */
    private void setStandard(Map<String, Map<String, Object>> middle, List<Object> indexList) {

        if (CollectionUtils.isEmpty(indexList)) {
            return;
        }

        // 每年的指标必须对应
        // 解析指标,每年,的指标
        Map<String, Map<String, Object>> allIndex = setAllYearIndex(indexList);

        // 遍历每一行:
        // 获取每一行对应的指标
        // 给每一行注入指标
        for (Map.Entry<String, Map<String, Object>> entry : middle.entrySet()) {

            Map<String, Object> row = entry.getValue();
            if (StringUtils.isEmpty(row)) {
                continue;
            }

            String indexKey = intelligenceMatch(row);
            if (StringUtils.isEmpty(indexKey)) {
                continue;
            }

            row.putAll(allIndex.get(indexKey));

        }

    }

    /**
     * 只能获取目标指标的key
     *
     * @param row 当前行数据
     * @return 目标指标的key
     */
    private String intelligenceMatch(Map<String, Object> row) {

        //
        String projectName = (String) row.get(Const.PROJECT);
        String year = (String) row.get(Const.YEAR);

        for (String indexName : Const.PROJECTS) {
            if (indexName.substring(0, 2).equals(projectName.substring(0, 2))) {
                return year + "-" + indexName;
            }
        }
        return null;
    }

    /**
     * 解析每一年的指标,采用健值对形式存储,key=年+行名称,value =每一行的指标
     *
     * @param indexList 所有的指标原属数据
     * @return 解析后的指标,便于读取
     */
    private Map<String, Map<String, Object>> setAllYearIndex(List<Object> indexList) {

        Map<String, Map<String, Object>> allIndex = new HashMap<>(Const.SIXTEEN);

        for (Object object : indexList) {
            if (object == null) {
                continue;
            }

            FormDataVO formDataVO = (FormDataVO) object;
            String timestamp = reportUtil.getStringFromData(formDataVO, Const.YEAR_NUMBER);
            String yearDate = TimeUtil.getStringYear(timestamp);

            //遍历注入指标
            for (String firstField : Const.PROJECTS) {
                Map<String, Object> row = new HashMap<>(Const.SIXTEEN);
                String rowKey = yearDate + "-" + firstField;

                TableDataVO tableDataVO = (TableDataVO) formDataVO.getData().get(firstField);
                TableRowVO tableRowVO = tableDataVO.getValue().get(0);
                for (Map.Entry<String, DataBaseVO> entry : tableRowVO.getValue().entrySet()) {

                    CommonDataVO commonDataVO = (CommonDataVO) entry.getValue();
                    String value = commonDataVO.getValue();

                    row.put(entry.getKey(), stob(value));
                }

                allIndex.put(rowKey, row);
            }

        }

        return allIndex;
    }

    /**
     * 注入单元格公式计算,更具单元格之间的计算规则,计算未知的单元格的值
     *
     * @param middle 已知的单于格
     */
    private void calculateByCell(Map<String, Map<String, Object>> middle) {

        for (Map.Entry<String, Map<String, Object>> entry : middle.entrySet()) {

            Map<String, Object> row = entry.getValue();
            if (CollectionUtils.isEmpty(row)) {
                continue;
            }

            String projectName = (String) row.get(Const.PROJECT);
            boolean isWeight = isWeight(projectName);

            // 1。责任废品量(21)
            // 2。废品量(4)
            // 3。实际工作量(5)
            // 4。实际 废品率(7)

            setResponseWasteAmount(isWeight, row);
            setWasteAmount(isWeight, row);
            setActualWorkAmount(row);
            setDivideValue(row, Const.ACTUAL_WASTE_RATE, Const.WASTE_NUMBER, Const.ACTUAL_WORK_AMOUNT);

            // 5。实际 责任废品率(23)
            // 6。实际 综合回用率(26)
            // 7。实际 责任回用率(29)

            setDivideValue(row, Const.ACTUAL_RESPONSIBLE_WASTE_RATE, Const.RESPONSIBLE_WASTE_AMOUNT, Const.ACTUAL_WORK_AMOUNT);
            setDivideValue(row, Const.ACTUAL_COMPREHENSIVE_REUSE_RATE, Const.COMPREHENSIVE_AMOUNT, Const.ACTUAL_WORK_AMOUNT);
            setDivideValue(row, Const.ACTUAL_RESPONSIBLE_REUSE_RATE, Const.RESPONSIBLE_AMOUNT, Const.ACTUAL_WORK_AMOUNT);

        }
    }

    /**
     * 计算son/mom的结果,再放入row,target健对应的值
     *
     * @param row    map
     * @param target 健
     * @param son    分子的健
     * @param mom    分母的健
     */
    private void setDivideValue(Map<String, Object> row, String target, String son, String mom) {

        // 计算需要的子数据
        // 计算主数据
        // 封装主数据
        BigDecimal sonValue = getRowValue(row, son);
        BigDecimal momValue = getRowValue(row, mom);
        if (BigDecimal.ZERO.equals(momValue)) {

            if (BigDecimal.ZERO.equals(sonValue)) {
                row.put(target, BigDecimal.ZERO);
            } else {
                row.put(target, BigDecimal.ONE);
            }
        } else {
            row.put(target, sonValue.divide(momValue, 2, RoundingMode.UP));
        }

    }

    /**
     * 计算并封装实际工作量
     *
     * @param row 封装数据对象
     */
    private void setActualWorkAmount(Map<String, Object> row) {


        // 计算需要的子数据
        // 计算主数据
        // 封装主数据
        BigDecimal workAmount = getRowValue(row, Const.WORKSHOP_TASK);
        BigDecimal wasteAmount = getRowValue(row, Const.WASTE_NUMBER);

        row.put(Const.ACTUAL_WORK_AMOUNT, workAmount.add(wasteAmount));
    }

    /**
     * 获取健值对的值
     *
     * @param row map
     * @param key 健
     * @return 值
     */
    private BigDecimal getRowValue(Map<String, Object> row, String key) {

        Object o = row.get(key);
        if (o == null) {
            return BigDecimal.ZERO;
        } else {
            String valueString = o.toString();
            if (StringUtils.isEmpty(valueString)) {
                return BigDecimal.ZERO;
            } else {
                return new BigDecimal(valueString);
            }
        }
    }

    /**
     * 计算并封装责任废品量
     *
     * @param isWeight 操作类型
     * @param row      封装对象
     */
    private void setWasteAmount(boolean isWeight, Map<String, Object> row) {

        // 计算需要的子数据
        // 计算主数据
        // 封装主数据

        BigDecimal wasteAmount;
        if (isWeight) {
            wasteAmount = getRowValue(row, Const.RESPONSIBLE_WASTE_AMOUNT);
        } else {
            BigDecimal badDesign = getRowValue(row, Const.POOR_DESIGNER);
            BigDecimal poorSpecif = getRowValue(row, Const.POOR_SPECIFICATION);
            BigDecimal poorFix = getRowValue(row, Const.POOR_FIXTURE);
            BigDecimal poorHeatTreat = getRowValue(row, Const.POOR_HEAT_TREATMENT);
            BigDecimal improperInspect = getRowValue(row, Const.IMPROPER_INSPECTION);

            BigDecimal equipmentFail = getRowValue(row, Const.EQUIPMENT_FAILURE);
            BigDecimal poorRaw = getRowValue(row, Const.POOR_RAW_MATERIAL);
            BigDecimal poorForge = getRowValue(row, Const.POOR_FORGING_BLANK);
            BigDecimal others = getRowValue(row, Const.OTHER_ELSE);
            BigDecimal poorCast = getRowValue(row, Const.POOR_CASTING_BLANK);

            BigDecimal responseAmount = getRowValue(row, Const.RESPONSIBLE_WASTE_AMOUNT);

            wasteAmount = badDesign.add(poorSpecif).add(poorFix).add(poorHeatTreat).add(improperInspect).
                    add(equipmentFail).add(poorRaw).add(poorForge).add(others).add(poorCast).add(responseAmount);

        }

        row.put(Const.WASTE_NUMBER, wasteAmount);
    }

    /**
     * 计算并封装责任废品量
     *
     * @param isWeight 操作类型
     * @param row      封装对象
     */
    private void setResponseWasteAmount(boolean isWeight, Map<String, Object> row) {

        // 计算需要的子数据
        // 计算主数据
        // 封装主数据

        BigDecimal responseWasteAmount;
        if (isWeight) {
            //内废/外废求和
            BigDecimal in = getRowValue(row, Const.INTERNAL_WASTE);
            BigDecimal out = getRowValue(row, Const.EXTERNAL_WASTE);
            responseWasteAmount = in.add(out);
        } else {

            BigDecimal careless = getRowValue(row, Const.CARELESS);
            BigDecimal orderViolate = getRowValue(row, Const.SPECIFICATION_VIOLATION);
            BigDecimal poorLeader = getRowValue(row, Const.POOR_LEADER);

            responseWasteAmount = careless.add(orderViolate).add(poorLeader);
        }

        row.put(Const.RESPONSIBLE_WASTE_AMOUNT, responseWasteAmount);
    }

    /**
     * 获取年月
     *
     * @param middle 数据源
     * @return 结果
     */
    private Set<String> getYearMonth(Map<String, Map<String, Object>> middle, String tag) {

        Set<String> yearMonth = new HashSet<>(Const.SIXTEEN);
        if (CollectionUtils.isEmpty(middle)) {
            return yearMonth;
        }

        for (Map.Entry<String, Map<String, Object>> entry : middle.entrySet()) {

            if (CollectionUtils.isEmpty(entry.getValue())) {
                continue;
            }
            Object yObj = entry.getValue().get(Const.YEAR);
            Object mObj = entry.getValue().get(Const.MONTH);
            if (yObj == null && mObj == null) {
                continue;
            }
            String year = yObj == null ? "0000" : (String) yObj;
            String month = mObj == null ? "00" : (String) mObj;
            String key = "-".equals(tag) ? year + "-" + month : year + month;
            yearMonth.add(key);
        }
        return yearMonth;
    }

    /**
     * 合并 每个月的金一、金二
     *
     * @param middle 数据
     */
    private void mergeRows(Map<String, Map<String, Object>> middle) {

        // 1。先找出所有的月
        // 2。找出每个月中的厂,及他们的数据
        // 3。合并每个月对应的厂,重新封装
        // 4。返回
        Set<String> yearMonth = getYearMonth(middle, "-");

        for (String key : yearMonth) {

            // 生成key
            String keyOne = key + "-" + Const.METAL_WORKSHOP_ONE;
            String keyTwo = key + "-" + Const.METAL_WORKSHOP_TWO;

            // 取出来
            Map<String, Object> rowOne = middle.get(keyOne);
            Map<String, Object> rowTwo = middle.get(keyTwo);
            if (CollectionUtils.isEmpty(rowOne) && CollectionUtils.isEmpty(rowTwo)) {
                continue;
            }
            // 组合
            Map<String, Object> rowLast = mergeTwo(rowOne, rowTwo);
            // 放回去
            middle.put(key + "-" + Const.REJECT_RATE_OF_MECHINING, rowLast);
        }

    }

    /**
     * 合并两行数据
     *
     * @param rowOne 第一行
     * @param rowTwo 第二行
     * @return 合并后的数据
     */
    private Map<String, Object> mergeTwo(Map<String, Object> rowOne, Map<String, Object> rowTwo) {


        // 深度复制
        if (CollectionUtils.isEmpty(rowOne) && !CollectionUtils.isEmpty(rowTwo)) {

            return deepCopy(rowTwo);
        }
        if (!CollectionUtils.isEmpty(rowOne) && CollectionUtils.isEmpty(rowTwo)) {

            return deepCopy(rowOne);
        }

        // 深度复制
        Map<String, Object> rowLast = new HashMap<>(Const.SIXTEEN);
        for (Map.Entry<String, Object> entry : rowOne.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();

            if (Const.ONCE_LIST.contains(key)) {

                String valueString = value == null ? "" : value.toString();
                rowLast.put(key, valueString);

            } else {
                BigDecimal valueOne;
                if (value == null) {
                    valueOne = BigDecimal.ZERO;
                } else {
                    valueOne = new BigDecimal(value.toString());
                }

                BigDecimal valueTwo;
                if (rowTwo.get(key) == null) {
                    valueTwo = BigDecimal.ZERO;
                } else {
                    valueTwo = new BigDecimal(rowTwo.get(key).toString());
                }

                if (valueOne.equals(BigDecimal.ZERO) && valueTwo.equals(BigDecimal.ZERO)) {
                    continue;
                }

                rowLast.put(key, valueOne.add(valueTwo));
            }
        }

        rowLast.put(Const.PROJECT, Const.REJECT_RATE_OF_MECHINING);
        return rowLast;
    }

    /**
     * 深度复制map
     *
     * @param rowOne 原始的map
     * @return 复制的对象
     */
    private Map<String, Object> deepCopy(Map<String, Object> rowOne) {

        //
        Map<String, Object> rowNew = new HashMap<>(Const.SIXTEEN);
        for (Map.Entry<String, Object> entry : rowOne.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();

            if (Const.ONCE_LIST.contains(key)) {
                // new string
                String valueString = value == null ? "" : value.toString();
                rowNew.put(key, valueString);

            } else {
                // new BigDecimal
                BigDecimal valueOne;
                if (value == null) {
                    valueOne = BigDecimal.ZERO;
                } else {
                    valueOne = new BigDecimal(value.toString());
                }
                rowNew.put(key, valueOne);
            }
        }

        rowNew.put(Const.PROJECT, Const.REJECT_RATE_OF_MECHINING);
        return rowNew;
    }

    /**
     * 初步解析数据
     * <p>
     * 工时损失废品分析——小时(hour)
     * <p>
     * 数据来源
     * 工票信息:工票号、计量单位、车间完成工时
     * 不合格品通知单:工票号、生产项目、废品原因分析(10大原因)、综合回用量、责任回用量
     * 各种指标:废品率-指标、责任废品率-指标、综合回用率-指标、责任回用率-指标
     *
     * @param middle  结果封装
     * @param results 工票信息和不合格品数据
     */
    private void middleAnalysis(Map<String, Map<String, Object>> middle, Map<String, Map<String, FormDataVO>> results) {

        if (CollectionUtils.isEmpty(results)) {
            return;
        }

        // 需要计算的数据
        // 1。总工时=准备工时+加工工时*生产数量
        // 2。综合回用量(h)=总工时/派工数量*车间总回用数量(四个回用数求和)-责任回用工时(不合格品通知单)
        //    综合回用量(kg)=加工工时*车间总回用数量(截图包括的回用数)-责任回用重量
        // 3。责任回用量(h)=责任回用工时
        //    责任回用重量(kg)=责任回用数*加工工时
        // 4。内废/外废(kg) = 报废数量*工票上加工工时


        //封装数据类型
        for (Map.Entry<String, Map<String, FormDataVO>> entry : results.entrySet()) {


            FormDataVO defectData = entry.getValue().get(Const.NOTICE_OF_UNQUALIFIED_PRODUCT);
            FormDataVO ticketData = entry.getValue().get(Const.WORK_ORDER);
            String projectName = reportUtil.getStringFromData(defectData, Const.PROJECT);
            if (StringUtils.isEmpty(projectName)) {
                continue;
            }

            boolean isWeight = isWeight(projectName);

            String timeStamp = reportUtil.getStringFromData(defectData, Const.CREATE_DATE);
            String year = TimeUtil.getStringYear(timeStamp);
            String month = TimeUtil.getStringMonth(timeStamp);
            String finalKey = year + "-" + month + "-" + projectName;


            Map<String, Object> map = middle.get(finalKey);
            boolean isEmpty = false;
            if (CollectionUtils.isEmpty(map)) {
                isEmpty = true;
                map = new HashMap<>(Const.SIXTEEN);

                map.put(Const.YEAR, year);
                map.put(Const.MONTH, month);
                map.put(Const.PROJECT, projectName);
                map.put(Const.UNIT, isWeight ? Const.KG : Const.HOUR);
            }

            // 1。总工时=准备工时+加工工时*派工数量
            BigDecimal totalHour = countAndSetWorkHour(ticketData, isEmpty, map);
            // 2。设置综合回用量
            setComprehensiveAmount(defectData, ticketData, isEmpty, map, isWeight, totalHour);
            // 3。责任回用工时;责任回用重量=“责任回用数”*加工工时
            setResponseAmount(defectData, ticketData, isEmpty, map, isWeight);

            // 4。
            if (isWeight) {
                //内废/外废(kg) = 报废数量*工票上加工工时
                setWeight(defectData, ticketData, isEmpty, map);

            } else {
                // 十大原因
                for (String fieldName : Const.HOUR_WASTE_CASE) {
                    setSecondDataIntoMap(isEmpty, map, fieldName, defectData);
                }
            }

            middle.put(finalKey, map);
        }

    }

    /**
     * 计算并设置责任回用量
     *
     * @param defectData 不合格品数据
     * @param ticketData 工票信息
     * @param isEmpty    唯一主键是否有值,true 有值,增量操作,false全量操作
     * @param map        数据封装对象
     * @param isWeight   重量计算还是工时计算,true 重量
     */
    private void setResponseAmount(FormDataVO defectData, FormDataVO ticketData, boolean isEmpty, Map<String, Object> map,
                                   boolean isWeight) {

        BigDecimal workDecimal = getBigDecimalFromData(ticketData, Const.MAN_HOUR);

        BigDecimal responseAmount;

        if (isWeight) {
            responseAmount = getResponseReuseWeight(workDecimal, defectData);
        } else {
            responseAmount = getBigDecimalFromData(defectData, Const.RESPONSIBLE_REUSE_HOUR);

        }

        setMap(isEmpty, map, Const.RESPONSIBLE_AMOUNT, responseAmount);

    }

    /**
     * 获取数字类型的值
     *
     * @param formDataVO 所有数据
     * @param fieldName  字段名称
     * @return 数字类型的值
     */
    private BigDecimal getBigDecimalFromData(FormDataVO formDataVO, String fieldName) {

        String responseReuseHour = reportUtil.getStringFromData(formDataVO, fieldName);
        return stob(responseReuseHour);
    }

    /**
     * 计算并设置综合回用量
     *
     * @param defectData 不合格品数据
     * @param ticketData 工票信息
     * @param isEmpty    唯一主键是否有值,true 有值,增量操作,false全量操作
     * @param map        数据封装对象
     * @param isWeight   重量计算还是工时计算,true 重量
     * @param totalHour  当前工票的总工时
     */
    private void setComprehensiveAmount(FormDataVO defectData, FormDataVO ticketData, boolean isEmpty, Map<String, Object> map,
                                        boolean isWeight, BigDecimal totalHour) {

        // 重量计算时:综合回用量=总工时/派工数量*车间总回用数量(四个回用数求和)-责任回用工时(不合格品通知单)
        // 以公斤为单位时,综合回用量=加工工时*车间总回用数量(截图包括的回用数)-责任回用重量

        BigDecimal workNum = getBigDecimalFromData(ticketData, Const.TASK_NUMBER);

        BigDecimal directReuseNum = getBigDecimalFromData(defectData, Const.DIRECT_REUSE_NUMBER);
        BigDecimal applyReuseNum = getBigDecimalFromData(defectData, Const.APPLY_REUSE_NUMBER);
        BigDecimal partReuseNum = getBigDecimalFromData(defectData, Const.PART_REUSE_NUMBER);
        BigDecimal repairReuseNum = getBigDecimalFromData(defectData, Const.REPAIR_REUSE_NUMBER);

        BigDecimal totalReuseNumber = directReuseNum.add(applyReuseNum).add(partReuseNum).add(repairReuseNum);

        BigDecimal comprehensiveAmount;
        if (isWeight) {
            BigDecimal responseNum = getBigDecimalFromData(defectData, Const.RESPONSIBLE_REUSE_HOUR);

            comprehensiveAmount = totalHour.divide(workNum, 2, RoundingMode.HALF_UP).multiply(totalReuseNumber).subtract(responseNum);
        } else {
            BigDecimal workDecimal = getBigDecimalFromData(ticketData, Const.MAN_HOUR);

            comprehensiveAmount = workDecimal.multiply(totalReuseNumber).
                    subtract(getResponseReuseWeight(workDecimal, defectData));
        }

        setMap(isEmpty, map, Const.COMPREHENSIVE_AMOUNT, comprehensiveAmount);
    }

    /**
     * 获取责任回用重量
     *
     * @param workDecimal 加工工时
     * @param defectData  不合格品通知单
     * @return 责任回用重量
     */
    private BigDecimal getResponseReuseWeight(BigDecimal workDecimal, FormDataVO defectData) {

        BigDecimal responseNum = getBigDecimalFromData(defectData, Const.RESPONSIBLE_REUSE_NUMBER);

        return workDecimal.multiply(responseNum);
    }

    /**
     * 计算并新增总工时
     *
     * @param ticketData 工票数据
     * @param isEmpty    之前是否有key相同的数据,true没有
     * @param map        封装的数据对象
     * @return 当前工票总工时
     */
    private BigDecimal countAndSetWorkHour(FormDataVO ticketData, boolean isEmpty, Map<String, Object> map) {

        // 总工时=准备工时+加工工时*派工数量

        BigDecimal prepareTime = getBigDecimalFromData(ticketData, Const.PREPARE_HOUR);
        BigDecimal workTime = getBigDecimalFromData(ticketData, Const.MAN_HOUR);
        BigDecimal workNum = getBigDecimalFromData(ticketData, Const.TASK_NUMBER);


        BigDecimal totalTime = workTime.multiply(workNum).add(prepareTime);

        setMap(isEmpty, map, Const.TOTAL_WORK_HOUR, totalTime);

        return totalTime;
    }

    /**
     * 设置内废外废重量
     *
     * @param defectData 不合格品通知单
     * @param ticketData 工票
     * @param isEmpty    之前是否有key相同的数据,true没有
     * @param map        封装的数据对象
     */
    private void setWeight(FormDataVO defectData, FormDataVO ticketData, boolean isEmpty, Map<String, Object> map) {

        String occurrenceWorkshop = reportUtil.getStringFromData(defectData, Const.OCCURRENCE_WORKSHOP);
        String responsibleWorkshop = reportUtil.getStringFromData(defectData, Const.RESPONSIBLE_WORKSHOP);

        BigDecimal number = getBigDecimalFromData(defectData, Const.WASTE_AMOUNT);
        BigDecimal singleWeight = getBigDecimalFromData(ticketData, Const.MAN_HOUR);
        BigDecimal wasteWeight = singleWeight.multiply(number);

        // 外废
        if (occurrenceWorkshop.equals(responsibleWorkshop)) {
            if (isEmpty) {
                // 加入操作
                map.put(Const.INTERNAL_WASTE, BigDecimal.ZERO);
                map.put(Const.EXTERNAL_WASTE, wasteWeight);
            } else {
                // 增量操作
                BigDecimal out = getRowValue(map, Const.EXTERNAL_WASTE);

                map.put(Const.EXTERNAL_WASTE, wasteWeight.add(out));
            }

            // 内废
        } else {
            if (isEmpty) {
                // 加入操作
                map.put(Const.INTERNAL_WASTE, wasteWeight);
                map.put(Const.EXTERNAL_WASTE, BigDecimal.ZERO);
            } else {
                // 增量操作
                BigDecimal out = getRowValue(map, Const.INTERNAL_WASTE);
                map.put(Const.INTERNAL_WASTE, wasteWeight.add(out));
            }
        }
    }

    /**
     * 判断操作类型
     *
     * @param projectName 项目类型
     * @return true 按kg计算,false 按小时计算
     */
    private Boolean isWeight(String projectName) {

        for (String project : Const.WEIGHT_LIST) {
            if (project.contains(projectName)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 向map中加入数据
     *
     * @param isEmpty    是否已经存在数据,(指定key的数据)
     * @param map        数据对象
     * @param key        数据的键
     * @param formDataVO 数据对象
     */
    private void setSecondDataIntoMap(boolean isEmpty, Map<String, Object> map, String key, FormDataVO formDataVO) {

        if (Const.ONCE_LIST.contains(key)) {
            return;
        }

        TableDataVO tableDataVO = (TableDataVO) formDataVO.getData().get(Const.WASTE_REASON_ANALYSIS);
        if (tableDataVO == null) {
            setMap(isEmpty, map, key, BigDecimal.ZERO);
            return;
        }

        String value = "0";
        for (TableRowVO tableRowVO : tableDataVO.getValue()) {

            SelectDataVO selectData = (SelectDataVO) tableRowVO.getValue().get(Const.WASTE_REASON);
            List<String> oneItemList = selectData.getValue();
            if (CollectionUtils.isEmpty(oneItemList)) {
                continue;
            }
            if (key.equals(oneItemList.get(0))) {

                CommonDataVO hour = (CommonDataVO) tableRowVO.getValue().get(Const.WORK_HOUR);
                value = hour.getValue();
                break;
            }
        }

        BigDecimal outValue = stob(value);
        setMap(isEmpty, map, key, outValue);
    }

    /**
     * 方法名称:StringToBigDecimal,简写stob
     * 字符串转BigDecimal
     *
     * @param str 字符串
     * @return 数字类型的值
     */
    private BigDecimal stob(String str) {

        if (StringUtils.isEmpty(str)) {
            return BigDecimal.ZERO;
        } else {
            if (str.contains(Const.HOUR)) {
                return new BigDecimal(str.substring(0, str.length() - 2));
            } else {
                return new BigDecimal(str);
            }
        }
    }

    /**
     * 直接设置数据到map
     *
     * @param isEmpty 唯一主键是否有值,true 有值,增量操作,false全量操作
     * @param map     数据封装map对象
     * @param key     健
     * @param value   值
     */
    private void setMap(boolean isEmpty, Map<String, Object> map, String key, BigDecimal value) {

        if (isEmpty) {
            map.put(key, value);
        } else {
            // 增量操作
            BigDecimal out = getRowValue(map, key);

            map.put(key, value.add(out));
        }
    }

    /**
     * 重新组织数据结构
     *
     * @param defects     不合格品通知单
     * @param workTickets 工票信息
     * @param results     组织结果
     * @return 整理后的数据
     */
    private BaseVO<Map<String, Long>> range(List<FormDataVO> defects, List<FormDataVO> workTickets, Map<String, Map<String, FormDataVO>> results) {

        if (CollectionUtils.isEmpty(workTickets) || CollectionUtils.isEmpty(defects)) {
            return new BaseVO<>(BaseVO.ILLEGAL_PARAM_CODE, "参数错误!");
        }

        for (FormDataVO formDataVO : defects) {
            String temp = reportUtil.getStringFromData(formDataVO, Const.TICKET);
            if (StringUtils.isEmpty(temp)) {
                continue;
            }
            Map<String, FormDataVO> defMap = new HashMap<>(Const.FOUR);
            for (FormDataVO vo : workTickets) {
                String ticket = reportUtil.getStringFromData(vo, Const.TICKET);
                if (StringUtils.isEmpty(ticket) || !temp.equals(ticket)) {
                    continue;
                }
                defMap.put(Const.NOTICE_OF_UNQUALIFIED_PRODUCT, formDataVO);
                defMap.put(Const.WORK_ORDER, vo);
                break;

            }

            if (CollectionUtils.isEmpty(defMap)) {
                continue;
            }
            results.put(temp, defMap);
        }

        return new BaseVO<>(BaseVO.SUCCESS_CODE, "校验成功!");
    }

    /**
     * 检验参数,并获取原始数据
     *
     * @param unqualifiedList 所有的不合格品通知单
     * @param workTicketList  所有的工票数据
     * @param defects         过滤后的不合格品通知单
     * @param workTickets     过滤后的工票信息
     * @return 校验结果
     */
    private BaseVO<String> filterData(List<Object> unqualifiedList, List<Object> workTicketList,
                                      List<FormDataVO> defects, List<FormDataVO> workTickets) {

        if (CollectionUtils.isEmpty(unqualifiedList) || CollectionUtils.isEmpty(workTicketList)) {
            return new BaseVO<>(BaseVO.ILLEGAL_PARAM_CODE, "参数错误!");
        }

        Set<String> tickets = new HashSet<>(Const.SIXTEEN);
        for (Object object : unqualifiedList) {
            FormDataVO formDataVO = (FormDataVO) object;
            String temp = reportUtil.getStringFromData(formDataVO, Const.TICKET);
            if (StringUtils.isEmpty(temp)) {
                continue;
            }
            tickets.add(temp);
            defects.add(formDataVO);
        }

        if (CollectionUtils.isEmpty(tickets) || CollectionUtils.isEmpty(defects)) {
            return new BaseVO<>(BaseVO.ILLEGAL_PARAM_CODE, "参数错误!");
        }

        for (Object object : workTicketList) {
            FormDataVO formDataVO = (FormDataVO) object;
            String temp = reportUtil.getStringFromData(formDataVO, Const.TICKET);
            if (StringUtils.isEmpty(temp) || !tickets.contains(temp)) {
                continue;
            }
            workTickets.add(formDataVO);
        }

        if (CollectionUtils.isEmpty(workTickets)) {
            return new BaseVO<>(BaseVO.ILLEGAL_PARAM_CODE, "参数错误!");
        }

        return new BaseVO<>(BaseVO.SUCCESS_CODE, "校验成功!");
    }

}

4 util

package cn.cncommdata.report.util;

import cn.cncommdata.FormClient;
import cn.cncommdata.form.vo.FormDataVO;
import cn.cncommdata.form.vo.Page;
import cn.cncommdata.form.vo.fielddata.CommonDataVO;
import cn.cncommdata.form.vo.fielddata.DataBaseVO;
import cn.cncommdata.form.vo.fielddata.QuoteDataVO;
import cn.cncommdata.form.vo.fielddata.SelectDataVO;
import cn.cncommdata.metadata.MetadataClient;
import cn.cncommdata.metadata.vo.FormVO;
import cn.cncommdata.report.util.constant.Const;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 物料统计报表需求form_id
 *
 * @author weihong.zhu
 */
@Component
public class ReportUtil {

    /**
     * 引入元数据
     */
    @Autowired
    private MetadataClient metadataClient;
    /**
     * 引入FormId的Cache
     */
    @Resource
    private FormIdCache idCache;
    /**
     * 导入form客户端
     */
    @Resource
    private FormClient formClient;


    /**
     * 获取表单id
     *
     * @param tenantId     企业id
     * @param formName     表单名称
     * @param reportFormId 报表的formId
     * @return formId
     */
    public Long getFormId(Long tenantId, String formName, Long reportFormId) {

        Long formId = idCache.get(tenantId, formName, reportFormId);
        if (!Objects.isNull(formId)) {
            return formId;
        }
        FormVO formVO = metadataClient.getForm(tenantId, 0L, reportFormId);
        if (Objects.isNull(formVO)) {
            return null;
        }

        Map<String, Long> source = formVO.getSource();
        if (!CollectionUtils.isEmpty(source)) {
            Long sourceFormId = source.get(formName);
            // 存入缓存
            idCache.put(tenantId, formName, reportFormId, sourceFormId);
            return sourceFormId;
        }
        return null;
    }

    /**
     * 获取数据列表
     *
     * @param tenantId 企业id
     * @param grantId  操作员 id
     * @param formId   表单id
     * @return 数据列表
     */
    public List<Object> getDataList(Long tenantId, Long grantId, Long formId) {

        Page<Object> dataList = formClient.getDataList(tenantId, grantId, Const.ALL, formId, null,
                null, null, null, null, Const.ZERO, Const.ZERO, null);
        List<Object> rowsData = dataList.getRows();
        if (StringUtils.isEmpty(rowsData)) {
            return null;
        }

        return rowsData;
    }
    /**
     * 获取数据对象的值
     *
     * @param formDataVO 数据
     * @param fieldName  字段名称
     * @return 字段值
     */
    public String getStringFromData(FormDataVO formDataVO, String fieldName) {
        if (formDataVO.getData().get(fieldName) == null) {
            return "";
        }
        DataBaseVO dataBaseVO = formDataVO.getData().get(fieldName);

        String deliveryTime = "交货时间";
        if (deliveryTime.equals(fieldName)) {
            CommonDataVO commonDataVO = (CommonDataVO) dataBaseVO;
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(Long.parseLong(commonDataVO.getValue()));

            int month = calendar.get(Calendar.MONTH) + 1;
            String monthStr = month < 10 ? "0" + month : "" + month;
            int day = calendar.get(Calendar.DAY_OF_MONTH);
            String dayStr = day < 10 ? "0" + day : "" + day;

            String dateStr = calendar.get(Calendar.YEAR) + "-" + monthStr + "-" + dayStr;
            return dateStr.substring(2);
        }
        if (Const.SELECT.equals(dataBaseVO.getType())) {
            SelectDataVO selectData = (SelectDataVO) dataBaseVO;
            List<String> oneItemList = selectData.getValue();
            if (!CollectionUtils.isEmpty(oneItemList)) {
                return oneItemList.get(0);
            }else{
                return "";
            }

        } else if (Const.QUOTE.equals(dataBaseVO.getType())) {
            QuoteDataVO quoteData = (QuoteDataVO) dataBaseVO;
            return quoteData.getValue();

        } else {
            CommonDataVO commonDataVO = (CommonDataVO) dataBaseVO;
            return commonDataVO.getValue();
        }
    }

}

5 const

package cn.cncommdata.report.util.constant;

import java.util.Arrays;
import java.util.List;

/**
 * @author LiuLuhao
 * @since 2019/10/22 18:12
 */
public final class Const {

    /**
     * 常量0
     */
    public static final int ZERO = 0;
    /**
     * 常量1
     */
    public static final int ONE = 1;
    /**
     * 常量2
     */
    public static final int TWO = 2;
    /**
     * 常量4
     */
    public static final int FOUR = 4;
    /**
     * 常量9
     */
    public static final int NINE = 9;
    /**
     * 常量10
     */
    public static final int TEN = 10;
    /**
     * 常量12
     */
    public static final int TWELVE = 12;
    /**
     * 常量16
     */
    public static final int SIXTEEN = 16;

    /**
     * 工票信息:工票号、计量单位、车间完成工时
     */
    public static final String WORK_ORDER = "工票信息";
    public static final String TICKET = "工票号";
    public static final String UNIT = "工时单位";
    public static final String WORKSHOP_TASK = "车间完成任务";
    public static final String HOUR = "小时";
    public static final String KG = "kg";

    /**
     * 不合格品指标管理:
     */
    public static final String INDEX_OF_UNQUALIFIED_PRODUCT = "不合格品指标管理";

    /**
     * 不合格品通知单:工票号、生产项目、废品原因分析(10大原因)、综合回用量、责任回用量
     */
    public static final String NOTICE_OF_UNQUALIFIED_PRODUCT = "不合格品通知单";
    public static final String PROJECT = "生产项目";
    public static final String COMPREHENSIVE_AMOUNT = "综合回用量";
    public static final String ACTUAL_COMPREHENSIVE_REUSE_RATE = "实际综合回用率";
    public static final String ACTUAL_RESPONSIBLE_REUSE_RATE = "实际责任回用率";

    public static final String RESPONSIBLE_AMOUNT = "责任回用量";
    public static final String RESPONSIBLE_REUSE_NUMBER = "责任回用数";

    public static final String WASTE_REASON_ANALYSIS = "废品原因分析";
    public static final String WASTE_REASON = "废品原因";

    public static final String WORK_HOUR = "工时";
    public static final String MAN_HOUR = "加工工时";
    public static final String PREPARE_HOUR = "准备工时";
    public static final String TOTAL_WORK_HOUR = "总工时";
    public static final String RESPONSIBLE_REUSE_HOUR = "责任回用工时";

    public static final String TASK_NUMBER = "派工数量";
    public static final String DIRECT_REUSE_NUMBER = "直接回用数";
    public static final String APPLY_REUSE_NUMBER = "申请回用数";
    public static final String PART_REUSE_NUMBER = "配件回用数";
    public static final String REPAIR_REUSE_NUMBER = "返修回用数";
    public static final String WASTE_AMOUNT = "报废数量";
    public static final String WASTE_NUMBER = "废品量";

    public static final String ACTUAL_WORK_AMOUNT = "实际工作量";
    public static final String ACTUAL_WASTE_RATE = "实际废品率";
    public static final String ACTUAL_RESPONSIBLE_WASTE_RATE = "实际责任废品率";

    public static final String OCCURRENCE_WORKSHOP = "发生车间";
    public static final String RESPONSIBLE_WORKSHOP = "责任车间";
    public static final String INTERNAL_WASTE = "内废";
    public static final String EXTERNAL_WASTE = "外废";
    public static final String REJECT_RATE_OF_MECHINING = "机加工工废品率";

    public static final String METAL_WORKSHOP_ONE = "金一";
    public static final String METAL_WORKSHOP_TWO = "金二";
    public static final String RESPONSIBLE_WASTE_AMOUNT = "责任废品量";

    public static final String CARELESS = "粗心大意";
    public static final String SPECIFICATION_VIOLATION = "违反工艺规程";
    public static final String POOR_LEADER = "不真确的指导工作";
    public static final String POOR_DESIGNER = "设计不真确及更改不及时";
    public static final String POOR_SPECIFICATION = "工艺规程不真确";
    public static final String POOR_FIXTURE = "工夹具不良";
    public static final String POOR_HEAT_TREATMENT = "热处理不良";
    public static final String IMPROPER_INSPECTION = "前步检查失当";
    public static final String EQUIPMENT_FAILURE = "设备故障精度不良";
    public static final String POOR_RAW_MATERIAL = "原材料半成品不良";
    public static final String POOR_FORGING_BLANK = "锻件毛坯不良";
    public static final String OTHER_ELSE = "其他";
    public static final String POOR_CASTING_BLANK = "铸件毛坯不良";

    public static final String CREATE_DATE = "创建时间";
    public static final String YEAR = "year";
    public static final String YEAR_NUMBER = "年份";

    public static final String MONTH = "month";

    public static final List<String> PROJECTS = Arrays.asList("机加工工废指标", "金一指标", "金二指标", "机修指标", "工具指标",
            "铆焊指标", "热处理指标", "总铸铁指标", "产铸铁指标", "有色指标", "锻钢指标");
    public static final List<String> WEIGHT_LIST = Arrays.asList("热处理废品率", "总铸铁废品率", "产铸铁废品率", "有色废品率", "锻钢件废品率");
    public static final List<String> SORTED_LIST = Arrays.asList(
            "机加工工废品率", "金一", "金二", "机修废品率", "工具废品率", "铆焊废品率",
            "热处理废品率", "总铸铁废品率", "产铸铁废品率", "有色废品率", "锻钢件废品率");

    public static final List<String> ONCE_LIST = Arrays.asList(Const.YEAR, Const.MONTH, Const.PROJECT, Const.UNIT);

    /**
     * 十大原因
     */
    public static final List<String> HOUR_WASTE_CASE = Arrays.asList(
            Const.CARELESS, Const.SPECIFICATION_VIOLATION, Const.POOR_LEADER, Const.POOR_DESIGNER, Const.POOR_SPECIFICATION,
            Const.POOR_FIXTURE, Const.POOR_HEAT_TREATMENT, Const.IMPROPER_INSPECTION, Const.EQUIPMENT_FAILURE, Const.POOR_RAW_MATERIAL,
            Const.POOR_FORGING_BLANK, Const.OTHER_ELSE, Const.POOR_CASTING_BLANK);

    private Const() {
    }
}

原创文章 122 获赞 25 访问量 6万+

猜你喜欢

转载自blog.csdn.net/leinminna/article/details/106016516