MesScrapService.java 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. package com.jeesite.modules.mes.service;
  2. import com.jeesite.common.entity.Page;
  3. import com.jeesite.common.lang.StringUtils;
  4. import com.jeesite.common.mybatis.mapper.query.QueryType;
  5. import com.jeesite.common.service.CrudService;
  6. import com.jeesite.common.web.CookieUtils;
  7. import com.jeesite.modules.file.utils.FileUploadUtils;
  8. import com.jeesite.modules.mes.dao.MesScrapDao;
  9. import com.jeesite.modules.mes.entity.MesProductBfrk;
  10. import com.jeesite.modules.mes.entity.MesScrap;
  11. import org.apache.poi.ss.usermodel.Cell;
  12. import org.apache.poi.ss.usermodel.Row;
  13. import org.apache.poi.ss.usermodel.Sheet;
  14. import org.apache.poi.ss.usermodel.Workbook;
  15. import org.apache.poi.ss.usermodel.WorkbookFactory;
  16. import org.springframework.beans.factory.annotation.Autowired;
  17. import org.springframework.core.io.ClassPathResource;
  18. import org.springframework.stereotype.Service;
  19. import org.springframework.transaction.annotation.Transactional;
  20. import javax.servlet.http.HttpServletResponse;
  21. import java.io.InputStream;
  22. import java.io.OutputStream;
  23. import java.math.BigDecimal;
  24. import java.math.RoundingMode;
  25. import java.net.URLEncoder;
  26. import java.nio.charset.StandardCharsets;
  27. import java.util.List;
  28. /**
  29. * 报废记录Service
  30. * @author mes
  31. * @version 2023-11-27
  32. */
  33. @Service
  34. public class MesScrapService extends CrudService<MesScrapDao, MesScrap> {
  35. /** 生产报废数据库模板列数 */
  36. private static final int COL_COUNT = 53;
  37. /** 压铸车间缺陷列 */
  38. private static final int[] DEFECT_COLS_TYPE1 = {9, 10, 11, 12, 13, 14, 15, 16, 17, 18};
  39. /** 精加工缺陷列 */
  40. 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};
  41. /** 装配全检包装缺陷列 */
  42. private static final int[] DEFECT_COLS_TYPE3 = {41, 42, 43, 44, 45, 46};
  43. @Autowired
  44. private MesProductBfrkService mesProductBfrkService;
  45. /**
  46. * 获取单条数据
  47. * @param mesScrap
  48. * @return
  49. */
  50. @Override
  51. public MesScrap get(MesScrap mesScrap) {
  52. return super.get(mesScrap);
  53. }
  54. /**
  55. * 查询分页数据
  56. * @param mesScrap 查询条件
  57. * @param mesScrap.page 分页对象
  58. * @return
  59. */
  60. @Override
  61. public Page<MesScrap> findPage(MesScrap mesScrap) {
  62. return super.findPage(mesScrap);
  63. }
  64. /**
  65. * 查询列表数据
  66. * @param mesScrap
  67. * @return
  68. */
  69. @Override
  70. public List<MesScrap> findList(MesScrap mesScrap) {
  71. return super.findList(mesScrap);
  72. }
  73. /**
  74. * 保存数据(插入或更新)
  75. * @param mesScrap
  76. */
  77. @Override
  78. @Transactional
  79. public void save(MesScrap mesScrap) {
  80. super.save(mesScrap);
  81. // 保存上传图片
  82. FileUploadUtils.saveFileUpload(mesScrap, mesScrap.getId(), "mesScrap_image");
  83. // 保存上传附件
  84. FileUploadUtils.saveFileUpload(mesScrap, mesScrap.getId(), "mesScrap_file");
  85. }
  86. /**
  87. * 更新状态
  88. * @param mesScrap
  89. */
  90. @Override
  91. @Transactional
  92. public void updateStatus(MesScrap mesScrap) {
  93. super.updateStatus(mesScrap);
  94. }
  95. /**
  96. * 删除数据
  97. * @param mesScrap
  98. */
  99. @Override
  100. @Transactional
  101. public void delete(MesScrap mesScrap) {
  102. super.delete(mesScrap);
  103. }
  104. /**
  105. * 统计指定时间段内的报废记录数量
  106. */
  107. public Long countByDateRange(String sdate, String edate){
  108. MesScrap q = new MesScrap();
  109. q.getSqlMap().getWhere()
  110. .and("create_date", QueryType.GTE, sdate)
  111. .and("create_date", QueryType.LT, edate);
  112. return super.findCount(q);
  113. }
  114. /**
  115. * 按「生产报废数据库」模板导出报废统计(一行汇总各报废原因数量)
  116. */
  117. public void exportScrapDatabase(List<MesScrap> list, HttpServletResponse response, String fileName) {
  118. try (InputStream in = new ClassPathResource("templates/mes/scrap_export.xls").getInputStream();
  119. Workbook workbook = WorkbookFactory.create(in)) {
  120. Sheet sheet = workbook.getSheetAt(0);
  121. Row headerRow = sheet.getRow(1);
  122. String[] headers = new String[COL_COUNT];
  123. for (int c = 0; c < COL_COUNT; c++) {
  124. headers[c] = getCellString(headerRow, c);
  125. }
  126. // 清除模板示例数据,保留前两行表头
  127. for (int r = sheet.getLastRowNum(); r >= 2; r--) {
  128. Row row = sheet.getRow(r);
  129. if (row != null) {
  130. sheet.removeRow(row);
  131. }
  132. }
  133. // 汇总到一行:各报废原因列累计数量
  134. double[] values = new double[COL_COUNT];
  135. if (list != null) {
  136. for (MesScrap scrap : list) {
  137. int col = matchDefectColumn(scrap.getProductCate(), scrap.getReason(), headers);
  138. if (col >= 0) {
  139. values[col] += 1;
  140. }
  141. }
  142. }
  143. // 各车间报废数
  144. values[19] = sumRange(values, 9, 18);
  145. values[39] = sumRange(values, 21, 38);
  146. values[47] = sumRange(values, 41, 46);
  147. // 料工报废:工=精加工+装配,料=压铸
  148. values[49] = values[39] + values[47];
  149. values[51] = values[19];
  150. Row row = sheet.createRow(2);
  151. setCellString(row, 0, "");
  152. setCellString(row, 1, "合计");
  153. setCellString(row, 2, "/");
  154. // 成品/毛坯入库与报废、报废率:来自 MesProductBfrk 汇总,不按报废原因计数
  155. fillBfrkSummary(row);
  156. for (int c = 3; c < COL_COUNT; c++) {
  157. if (c >= 3 && c <= 8) {
  158. continue;
  159. }
  160. setCellNumber(row, c, values[c]);
  161. }
  162. response.reset();
  163. response.setContentType("application/vnd.ms-excel; charset=utf-8");
  164. String encodedName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()).replace("+", "%20");
  165. response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedName);
  166. CookieUtils.setCookie(response, "fileDownload", "true");
  167. try (OutputStream out = response.getOutputStream()) {
  168. workbook.write(out);
  169. out.flush();
  170. }
  171. } catch (Exception e) {
  172. throw new RuntimeException("导出生产报废数据库失败:" + e.getMessage(), e);
  173. }
  174. }
  175. /**
  176. * 从 MesProductBfrk 汇总并填入:
  177. * 成品入库数、成品报废总数、成品总报废率、毛坯入库数、毛坯报废总数、毛坯总报废率
  178. * 报废率 = (报废总数 / 入库总数) * 100%,保留两位小数
  179. */
  180. private void fillBfrkSummary(Row row) {
  181. double cpQty = 0; // 成品入库数
  182. double cpBfQty = 0; // 成品报废总数
  183. double bcpQty = 0; // 毛坯(半成品)入库数
  184. double bcpBfQty = 0; // 毛坯(半成品)报废总数
  185. List<MesProductBfrk> bfrkList = mesProductBfrkService.findList(new MesProductBfrk());
  186. if (bfrkList != null) {
  187. for (MesProductBfrk item : bfrkList) {
  188. if (item == null) {
  189. continue;
  190. }
  191. cpQty += parseQty(item.getCpQty());
  192. cpBfQty += parseQty(item.getCpBfQty());
  193. bcpQty += parseQty(item.getBcpQty());
  194. bcpBfQty += parseQty(item.getBcpBfQty());
  195. }
  196. }
  197. setCellNumber(row, 3, cpQty);
  198. setCellNumber(row, 4, cpBfQty);
  199. setCellString(row, 5, calcScrapRate(cpBfQty, cpQty));
  200. setCellNumber(row, 6, bcpQty);
  201. setCellNumber(row, 7, bcpBfQty);
  202. setCellString(row, 8, calcScrapRate(bcpBfQty, bcpQty));
  203. }
  204. private double parseQty(String qty) {
  205. if (StringUtils.isBlank(qty)) {
  206. return 0;
  207. }
  208. try {
  209. return Double.parseDouble(qty.trim());
  210. } catch (NumberFormatException e) {
  211. return 0;
  212. }
  213. }
  214. /**
  215. * (报废数 / 入库数) * 100%,保留两位小数;入库为0时返回空
  216. */
  217. private String calcScrapRate(double scrapQty, double inboundQty) {
  218. if (inboundQty <= 0) {
  219. return "";
  220. }
  221. BigDecimal rate = BigDecimal.valueOf(scrapQty)
  222. .multiply(BigDecimal.valueOf(100))
  223. .divide(BigDecimal.valueOf(inboundQty), 2, RoundingMode.HALF_UP);
  224. return rate.toPlainString() + "%";
  225. }
  226. /**
  227. * 按报废类型 + 报废原因匹配模板缺陷列
  228. * productCate: 1=压铸车间, 2=精加工, 3=装配全检包装
  229. */
  230. private int matchDefectColumn(String productCate, String reason, String[] headers) {
  231. int[] cols = defectColsByType(productCate);
  232. int defaultOther = defaultOtherCol(productCate);
  233. if (StringUtils.isBlank(reason)) {
  234. return defaultOther;
  235. }
  236. String target = reason.trim();
  237. for (int col : cols) {
  238. String header = headers[col];
  239. if (StringUtils.isNotBlank(header) && header.equals(target)) {
  240. return col;
  241. }
  242. }
  243. for (int col : cols) {
  244. String header = headers[col];
  245. if (StringUtils.isNotBlank(header) && (header.contains(target) || target.contains(header))) {
  246. return col;
  247. }
  248. }
  249. return defaultOther;
  250. }
  251. private int[] defectColsByType(String productCate) {
  252. if ("1".equals(productCate)) {
  253. return DEFECT_COLS_TYPE1;
  254. }
  255. if ("3".equals(productCate)) {
  256. return DEFECT_COLS_TYPE3;
  257. }
  258. return DEFECT_COLS_TYPE2;
  259. }
  260. private int defaultOtherCol(String productCate) {
  261. if ("1".equals(productCate)) {
  262. return 18;
  263. }
  264. if ("3".equals(productCate)) {
  265. return 46;
  266. }
  267. return 38;
  268. }
  269. private double sumRange(double[] values, int from, int to) {
  270. double sum = 0;
  271. for (int i = from; i <= to; i++) {
  272. sum += values[i];
  273. }
  274. return sum;
  275. }
  276. private String getCellString(Row row, int col) {
  277. if (row == null) {
  278. return "";
  279. }
  280. Cell cell = row.getCell(col);
  281. if (cell == null) {
  282. return "";
  283. }
  284. return StringUtils.trimToEmpty(cell.toString());
  285. }
  286. private void setCellString(Row row, int col, String value) {
  287. Cell cell = row.getCell(col);
  288. if (cell == null) {
  289. cell = row.createCell(col);
  290. }
  291. cell.setCellValue(value == null ? "" : value);
  292. }
  293. private void setCellNumber(Row row, int col, double value) {
  294. Cell cell = row.getCell(col);
  295. if (cell == null) {
  296. cell = row.createCell(col);
  297. }
  298. cell.setCellValue(value);
  299. }
  300. }