|
|
@@ -7,7 +7,7 @@ import com.jeesite.common.service.CrudService;
|
|
|
import com.jeesite.common.web.CookieUtils;
|
|
|
import com.jeesite.modules.file.utils.FileUploadUtils;
|
|
|
import com.jeesite.modules.mes.dao.MesScrapDao;
|
|
|
-import com.jeesite.modules.mes.entity.MesProduct;
|
|
|
+import com.jeesite.modules.mes.entity.MesProductBfrk;
|
|
|
import com.jeesite.modules.mes.entity.MesScrap;
|
|
|
import org.apache.poi.ss.usermodel.Cell;
|
|
|
import org.apache.poi.ss.usermodel.Row;
|
|
|
@@ -22,15 +22,11 @@ import org.springframework.transaction.annotation.Transactional;
|
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
import java.io.InputStream;
|
|
|
import java.io.OutputStream;
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.math.RoundingMode;
|
|
|
import java.net.URLEncoder;
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
-import java.util.ArrayList;
|
|
|
-import java.util.HashMap;
|
|
|
-import java.util.HashSet;
|
|
|
-import java.util.LinkedHashMap;
|
|
|
import java.util.List;
|
|
|
-import java.util.Map;
|
|
|
-import java.util.Set;
|
|
|
|
|
|
/**
|
|
|
* 报废记录Service
|
|
|
@@ -42,17 +38,15 @@ public class MesScrapService extends CrudService<MesScrapDao, MesScrap> {
|
|
|
|
|
|
/** 生产报废数据库模板列数 */
|
|
|
private static final int COL_COUNT = 53;
|
|
|
- /** 缺陷列(不含报废数/比例/汇总列) */
|
|
|
- private static final int[] DEFECT_COLS = {
|
|
|
- 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
|
|
|
- 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
|
|
|
- 41, 42, 43, 44, 45, 46
|
|
|
- };
|
|
|
- /** 未匹配原因时默认归入精加工-其它 */
|
|
|
- private static final int DEFAULT_OTHER_COL = 38;
|
|
|
+ /** 压铸车间缺陷列 */
|
|
|
+ private static final int[] DEFECT_COLS_TYPE1 = {9, 10, 11, 12, 13, 14, 15, 16, 17, 18};
|
|
|
+ /** 精加工缺陷列 */
|
|
|
+ private static final int[] DEFECT_COLS_TYPE2 = {21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38};
|
|
|
+ /** 装配全检包装缺陷列 */
|
|
|
+ private static final int[] DEFECT_COLS_TYPE3 = {41, 42, 43, 44, 45, 46};
|
|
|
|
|
|
@Autowired
|
|
|
- private MesProductService mesProductService;
|
|
|
+ private MesProductBfrkService mesProductBfrkService;
|
|
|
|
|
|
/**
|
|
|
* 获取单条数据
|
|
|
@@ -131,7 +125,7 @@ public class MesScrapService extends CrudService<MesScrapDao, MesScrap> {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 按「生产报废数据库」模板导出报废统计
|
|
|
+ * 按「生产报废数据库」模板导出报废统计(一行汇总各报废原因数量)
|
|
|
*/
|
|
|
public void exportScrapDatabase(List<MesScrap> list, HttpServletResponse response, String fileName) {
|
|
|
try (InputStream in = new ClassPathResource("templates/mes/scrap_export.xls").getInputStream();
|
|
|
@@ -151,47 +145,36 @@ public class MesScrapService extends CrudService<MesScrapDao, MesScrap> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- Map<String, MesProduct> productBySn = loadProducts(list);
|
|
|
- Map<String, double[]> rows = new LinkedHashMap<>();
|
|
|
-
|
|
|
- for (MesScrap scrap : list) {
|
|
|
- String productName = resolveProductName(scrap, productBySn);
|
|
|
- double[] values = rows.computeIfAbsent(productName, k -> new double[COL_COUNT]);
|
|
|
- int col = matchDefectColumn(scrap.getReason(), headers);
|
|
|
- if (col < 0) {
|
|
|
- col = DEFAULT_OTHER_COL;
|
|
|
+ // 汇总到一行:各报废原因列累计数量
|
|
|
+ double[] values = new double[COL_COUNT];
|
|
|
+ if (list != null) {
|
|
|
+ for (MesScrap scrap : list) {
|
|
|
+ int col = matchDefectColumn(scrap.getProductCate(), scrap.getReason(), headers);
|
|
|
+ if (col >= 0) {
|
|
|
+ values[col] += 1;
|
|
|
+ }
|
|
|
}
|
|
|
- values[col] += 1;
|
|
|
}
|
|
|
|
|
|
- int rowIndex = 2;
|
|
|
- for (Map.Entry<String, double[]> entry : rows.entrySet()) {
|
|
|
- double[] values = entry.getValue();
|
|
|
- // 各车间报废数
|
|
|
- values[19] = sumRange(values, 9, 18);
|
|
|
- values[39] = sumRange(values, 21, 38);
|
|
|
- values[47] = sumRange(values, 41, 46);
|
|
|
- // 成品报废总数
|
|
|
- values[4] = values[19] + values[39] + values[47];
|
|
|
- // 毛坯报废总数按压铸合计
|
|
|
- values[7] = values[19];
|
|
|
- // 料工报废:工=精加工+装配,料=压铸
|
|
|
- values[49] = values[39] + values[47];
|
|
|
- values[51] = values[19];
|
|
|
+ // 各车间报废数
|
|
|
+ values[19] = sumRange(values, 9, 18);
|
|
|
+ values[39] = sumRange(values, 21, 38);
|
|
|
+ values[47] = sumRange(values, 41, 46);
|
|
|
+ // 料工报废:工=精加工+装配,料=压铸
|
|
|
+ values[49] = values[39] + values[47];
|
|
|
+ values[51] = values[19];
|
|
|
|
|
|
- Row row = sheet.createRow(rowIndex++);
|
|
|
- setCellString(row, 1, entry.getKey());
|
|
|
- setCellString(row, 2, "/");
|
|
|
- for (int c = 0; c < COL_COUNT; c++) {
|
|
|
- if (c == 1 || c == 2) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (c == 0) {
|
|
|
- setCellString(row, 0, "");
|
|
|
- continue;
|
|
|
- }
|
|
|
- setCellNumber(row, c, values[c]);
|
|
|
+ Row row = sheet.createRow(2);
|
|
|
+ setCellString(row, 0, "");
|
|
|
+ setCellString(row, 1, "合计");
|
|
|
+ setCellString(row, 2, "/");
|
|
|
+ // 成品/毛坯入库与报废、报废率:来自 MesProductBfrk 汇总,不按报废原因计数
|
|
|
+ fillBfrkSummary(row);
|
|
|
+ for (int c = 3; c < COL_COUNT; c++) {
|
|
|
+ if (c >= 3 && c <= 8) {
|
|
|
+ continue;
|
|
|
}
|
|
|
+ setCellNumber(row, c, values[c]);
|
|
|
}
|
|
|
|
|
|
response.reset();
|
|
|
@@ -208,97 +191,104 @@ public class MesScrapService extends CrudService<MesScrapDao, MesScrap> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private Map<String, MesProduct> loadProducts(List<MesScrap> list) {
|
|
|
- Map<String, MesProduct> map = new HashMap<>();
|
|
|
- if (list == null || list.isEmpty()) {
|
|
|
- return map;
|
|
|
- }
|
|
|
- Set<String> sns = new HashSet<>();
|
|
|
- for (MesScrap scrap : list) {
|
|
|
- if (StringUtils.isNotBlank(scrap.getSn())) {
|
|
|
- sns.add(scrap.getSn().trim());
|
|
|
- }
|
|
|
- }
|
|
|
- if (sns.isEmpty()) {
|
|
|
- return map;
|
|
|
- }
|
|
|
- MesProduct query = new MesProduct();
|
|
|
- query.getSqlMap().getWhere().and("sn", QueryType.IN, new ArrayList<>(sns));
|
|
|
- List<MesProduct> products = mesProductService.findList(query);
|
|
|
- if (products != null) {
|
|
|
- for (MesProduct product : products) {
|
|
|
- if (product != null && StringUtils.isNotBlank(product.getSn())) {
|
|
|
- map.put(product.getSn(), product);
|
|
|
+ /**
|
|
|
+ * 从 MesProductBfrk 汇总并填入:
|
|
|
+ * 成品入库数、成品报废总数、成品总报废率、毛坯入库数、毛坯报废总数、毛坯总报废率
|
|
|
+ * 报废率 = (报废总数 / 入库总数) * 100%,保留两位小数
|
|
|
+ */
|
|
|
+ private void fillBfrkSummary(Row row) {
|
|
|
+ double cpQty = 0; // 成品入库数
|
|
|
+ double cpBfQty = 0; // 成品报废总数
|
|
|
+ double bcpQty = 0; // 毛坯(半成品)入库数
|
|
|
+ double bcpBfQty = 0; // 毛坯(半成品)报废总数
|
|
|
+ List<MesProductBfrk> bfrkList = mesProductBfrkService.findList(new MesProductBfrk());
|
|
|
+ if (bfrkList != null) {
|
|
|
+ for (MesProductBfrk item : bfrkList) {
|
|
|
+ if (item == null) {
|
|
|
+ continue;
|
|
|
}
|
|
|
+ cpQty += parseQty(item.getCpQty());
|
|
|
+ cpBfQty += parseQty(item.getCpBfQty());
|
|
|
+ bcpQty += parseQty(item.getBcpQty());
|
|
|
+ bcpBfQty += parseQty(item.getBcpBfQty());
|
|
|
}
|
|
|
}
|
|
|
- return map;
|
|
|
+ setCellNumber(row, 3, cpQty);
|
|
|
+ setCellNumber(row, 4, cpBfQty);
|
|
|
+ setCellString(row, 5, calcScrapRate(cpBfQty, cpQty));
|
|
|
+ setCellNumber(row, 6, bcpQty);
|
|
|
+ setCellNumber(row, 7, bcpBfQty);
|
|
|
+ setCellString(row, 8, calcScrapRate(bcpBfQty, bcpQty));
|
|
|
}
|
|
|
|
|
|
- private String resolveProductName(MesScrap scrap, Map<String, MesProduct> productBySn) {
|
|
|
- if (scrap != null && StringUtils.isNotBlank(scrap.getSn())) {
|
|
|
- MesProduct product = productBySn.get(scrap.getSn().trim());
|
|
|
- if (product != null && StringUtils.isNotBlank(product.getTitle())) {
|
|
|
- return product.getTitle().trim();
|
|
|
- }
|
|
|
+ private double parseQty(String qty) {
|
|
|
+ if (StringUtils.isBlank(qty)) {
|
|
|
+ return 0;
|
|
|
}
|
|
|
- if (scrap != null && StringUtils.isNotBlank(scrap.getProductCate())) {
|
|
|
- return scrap.getProductCate().trim();
|
|
|
+ try {
|
|
|
+ return Double.parseDouble(qty.trim());
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ return 0;
|
|
|
}
|
|
|
- if (scrap != null && StringUtils.isNotBlank(scrap.getSn())) {
|
|
|
- return scrap.getSn().trim();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * (报废数 / 入库数) * 100%,保留两位小数;入库为0时返回空
|
|
|
+ */
|
|
|
+ private String calcScrapRate(double scrapQty, double inboundQty) {
|
|
|
+ if (inboundQty <= 0) {
|
|
|
+ return "";
|
|
|
}
|
|
|
- return "未知产品";
|
|
|
+ BigDecimal rate = BigDecimal.valueOf(scrapQty)
|
|
|
+ .multiply(BigDecimal.valueOf(100))
|
|
|
+ .divide(BigDecimal.valueOf(inboundQty), 2, RoundingMode.HALF_UP);
|
|
|
+ return rate.toPlainString() + "%";
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 按报废原因匹配模板缺陷列:精确匹配优先,其次包含匹配;同名列按精加工 > 压铸 > 装配顺序。
|
|
|
+ * 按报废类型 + 报废原因匹配模板缺陷列
|
|
|
+ * productCate: 1=压铸车间, 2=精加工, 3=装配全检包装
|
|
|
*/
|
|
|
- private int matchDefectColumn(String reason, String[] headers) {
|
|
|
+ private int matchDefectColumn(String productCate, String reason, String[] headers) {
|
|
|
+ int[] cols = defectColsByType(productCate);
|
|
|
+ int defaultOther = defaultOtherCol(productCate);
|
|
|
if (StringUtils.isBlank(reason)) {
|
|
|
- return -1;
|
|
|
+ return defaultOther;
|
|
|
}
|
|
|
String target = reason.trim();
|
|
|
- List<Integer> exact = new ArrayList<>();
|
|
|
- List<Integer> contains = new ArrayList<>();
|
|
|
- for (int col : DEFECT_COLS) {
|
|
|
+ for (int col : cols) {
|
|
|
String header = headers[col];
|
|
|
- if (StringUtils.isBlank(header)) {
|
|
|
- continue;
|
|
|
+ if (StringUtils.isNotBlank(header) && header.equals(target)) {
|
|
|
+ return col;
|
|
|
}
|
|
|
- if (header.equals(target)) {
|
|
|
- exact.add(col);
|
|
|
- } else if (header.contains(target) || target.contains(header)) {
|
|
|
- contains.add(col);
|
|
|
+ }
|
|
|
+ for (int col : cols) {
|
|
|
+ String header = headers[col];
|
|
|
+ if (StringUtils.isNotBlank(header) && (header.contains(target) || target.contains(header))) {
|
|
|
+ return col;
|
|
|
}
|
|
|
}
|
|
|
- if (!exact.isEmpty()) {
|
|
|
- return preferColumn(exact);
|
|
|
+ return defaultOther;
|
|
|
+ }
|
|
|
+
|
|
|
+ private int[] defectColsByType(String productCate) {
|
|
|
+ if ("1".equals(productCate)) {
|
|
|
+ return DEFECT_COLS_TYPE1;
|
|
|
}
|
|
|
- if (!contains.isEmpty()) {
|
|
|
- return preferColumn(contains);
|
|
|
+ if ("3".equals(productCate)) {
|
|
|
+ return DEFECT_COLS_TYPE3;
|
|
|
}
|
|
|
- return -1;
|
|
|
+ return DEFECT_COLS_TYPE2;
|
|
|
}
|
|
|
|
|
|
- private int preferColumn(List<Integer> cols) {
|
|
|
- Integer best = null;
|
|
|
- int bestScore = -1;
|
|
|
- for (Integer col : cols) {
|
|
|
- int score;
|
|
|
- if (col >= 21 && col <= 38) {
|
|
|
- score = 3; // 精加工
|
|
|
- } else if (col >= 9 && col <= 18) {
|
|
|
- score = 2; // 压铸
|
|
|
- } else {
|
|
|
- score = 1; // 装配
|
|
|
- }
|
|
|
- if (score > bestScore) {
|
|
|
- bestScore = score;
|
|
|
- best = col;
|
|
|
- }
|
|
|
+ private int defaultOtherCol(String productCate) {
|
|
|
+ if ("1".equals(productCate)) {
|
|
|
+ return 18;
|
|
|
+ }
|
|
|
+ if ("3".equals(productCate)) {
|
|
|
+ return 46;
|
|
|
}
|
|
|
- return best == null ? cols.get(0) : best;
|
|
|
+ return 38;
|
|
|
}
|
|
|
|
|
|
private double sumRange(double[] values, int from, int to) {
|