*企业微信推送

*bom Jiaoyan日志
This commit is contained in:
tzy 2025-11-05 16:43:57 +08:00
parent 6abb92c321
commit 5a3739b2bc
49 changed files with 2671 additions and 330 deletions

View File

@ -167,6 +167,12 @@
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15to18</artifactId>
</dependency>
<dependency>
<groupId>com.hierynomus</groupId>
<artifactId>smbj</artifactId>
<version>0.14.0</version>
</dependency>
<!-- PDF -->
<dependency>
<groupId>com.itextpdf</groupId>

View File

@ -34,6 +34,8 @@ public class SecurityConfig {
.antMatchers("/system/proPlan/**").anonymous()
.antMatchers("/system/mrp/**").anonymous()
.antMatchers("/system/orderPro/**").anonymous()
.antMatchers("/system/cost/**").anonymous()
.antMatchers("/dev-api/system/cost/**").anonymous()
// .antMatchers("/dev-api/system/proPlan/overdue").anonymous()
// .antMatchers("/dev-api/system/proPlan/expiryProjects").anonymous()
.antMatchers("/dev-api/system/material/list/").anonymous()

View File

@ -6,7 +6,7 @@
<artifactId>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId>
<version>4.7.0</version>
</parent>
</parent><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>8</source><target>8</target></configuration></plugin></plugins></build>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-system</artifactId>

View File

@ -21,21 +21,20 @@ import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.result.BOMUploadResult;
import com.ruoyi.system.domain.dto.BOMItem;
import com.ruoyi.system.domain.dto.BOMUploadResult;
import com.ruoyi.common.utils.JdUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.domain.BomDetails;
import com.ruoyi.system.domain.FigureSave;
import com.ruoyi.system.domain.MaterialProperties;
import com.ruoyi.system.domain.ProcessOrderPro;
import com.ruoyi.system.domain.bo.BomDetailsBo;
import com.ruoyi.system.domain.bo.ProcessOrderProBo;
import com.ruoyi.system.domain.dto.JdValidateBomDTO;
import com.ruoyi.system.domain.dto.JdChildDTO;
import com.ruoyi.system.domain.dto.KindegeeLogDTO;
import com.ruoyi.system.domain.vo.BomDetailsVo;
import com.ruoyi.system.domain.vo.ElectricalMaterialBomVO;
import com.ruoyi.system.mapper.FigureSaveMapper;
import com.ruoyi.system.mapper.BomDetailsMapper;
import com.ruoyi.system.mapper.ProcessOrderProMapper;
import com.ruoyi.system.runner.JdUtil;
import com.ruoyi.system.service.*;
@ -45,8 +44,6 @@ import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@ -84,8 +81,10 @@ public class BomDetailsController extends BaseController {
private final IProcessOrderProService iProcessOrderProService;
private final IFigureSaveService iFigureSaveService;
private final ProcessOrderProMapper processOrderProMapper;
private final BomDetailsMapper bomDetailsMapper;
/**
* 查询bom明细列表
*/
@ -382,27 +381,38 @@ public class BomDetailsController extends BaseController {
for (BomDetails material : bomDetails) {
// 获取工艺表中的非委外工时
Double fbWorkTime = iProcessRouteService.getFbWorkTime(material);
if (material.getPartNumber() != null && material.getName() != null && material.getUnitWeight().equals("")) {
String state = determineState(material);
log.info("开始新增不存在的物料 ==> 物料图号: {}, 物料名称: {}", material.getPartNumber(), material.getName());
try {
int result = loadMaterialPreservation(material, state, fbWorkTime);
if (result == 1) {
log.info("新增物料成功 ==> 物料图号: {}, 物料名称: {}", material.getPartNumber(), material.getName());
material.setUnitWeight("新增成功");
} else {
log.error("新增物料失败 ==> 物料图号: {}, 物料名称: {}", material.getPartNumber(), material.getName());
//判断bom类型是生产还是电气
if (material.getBomType().equals("0")) {
try {
int result = loadMaterialPreservation(material, state, fbWorkTime);
if (result == 1) {
material.setUnitWeight("新增成功");
} else {
failedMaterials.add(material.getPartNumber());
}
// 更新物料状态
iBomDetailsService.updateByBo(BeanUtil.toBean(material, BomDetailsBo.class));
} catch (Exception e) {
failedMaterials.add(material.getPartNumber());
}
} else {
try {
int result = loadMaterialToDQ(material, state);
if (result == 1) {
material.setUnitWeight("新增成功");
} else {
failedMaterials.add(material.getPartNumber());
}
// 更新物料状态
iBomDetailsService.updateByBo(BeanUtil.toBean(material, BomDetailsBo.class));
} catch (Exception e) {
failedMaterials.add(material.getPartNumber());
}
// 更新物料状态
iBomDetailsService.updateByBo(BeanUtil.toBean(material, BomDetailsBo.class));
} catch (Exception e) {
log.error("处理物料时发生异常: {}", e.getMessage());
failedMaterials.add(material.getPartNumber());
}
} else {
log.error("物料信息不完整,无法新增物料");
failedMaterials.add(material.getPartNumber());
}
}
@ -411,22 +421,20 @@ public class BomDetailsController extends BaseController {
boolean needUpload = !validateBOM(fnumber, bomDetails);
if (needUpload) {
try {
// 物料清单保存方法
// 物料清单保存方法,判断是电气还是生产
BOMUploadResult bomUploadResult = FBloadBillOfMaterialsPreservation(bomDetails, bo);
if (bomUploadResult.isSuccess()) {
KindegeeLogDTO logDTO = new KindegeeLogDTO();
logDTO.setProjectCode(bo.getProductionOrderNo());
logDTO.setMaterialCode(fnumber); // 使用物料编码而不是单个物料的编码
logDTO.setMaterialName(fname);
logDTO.setCode(bomUploadResult.getNumber());
logDTO.setReason(bomUploadResult.getNumber()+"OK");
logDTO.setCode("200");
logDTO.setReason("成功上传"+"版本号:"+bomUploadResult.getNumber());
logDTOS.add(logDTO);
} else {
KindegeeLogDTO logDTO = new KindegeeLogDTO();
logDTO.setProjectCode(bo.getProductionOrderNo());
logDTO.setMaterialCode(fnumber);
logDTO.setMaterialName(fname);
logDTO.setCode(bomUploadResult.getNumber());
logDTO.setCode("300");
logDTO.setReason(bomUploadResult.getErrorMessage());
logDTOS.add(logDTO);
}
@ -439,8 +447,7 @@ public class BomDetailsController extends BaseController {
KindegeeLogDTO logDTO = new KindegeeLogDTO();
logDTO.setProjectCode(bo.getProductionOrderNo());
logDTO.setMaterialCode(fnumber);
logDTO.setMaterialName(fname);
logDTO.setCode("200");
logDTO.setCode("100");
logDTO.setReason("BOM已存在且一致");
logDTOS.add(logDTO);
log.info("BOM已存在且一致物料编码: {},跳过保存", fnumber);
@ -450,13 +457,14 @@ public class BomDetailsController extends BaseController {
//更新项目进度
ProcessOrderPro processOrderProBo = iProcessOrderProService.selectByProjectNumber(totalWeight);
processOrderProBo.setDrawingType( JSONUtil.toJsonStr(logDTOS));
processOrderProBo.setDrawingType(JSONUtil.toJsonStr(logDTOS));
processOrderProBo.setBomStatus(2L);
processOrderProMapper.updateById(processOrderProBo);
// 返回处理结果
return R.ok("成功", bomDetailsList);
}
private boolean validateBOM(String fnumber, List<BomDetails> bomDetails) {
List<JdValidateBomDTO> JDBomList = JdUtil.getSelectBomList(fnumber);
@ -701,7 +709,7 @@ public class BomDetailsController extends BaseController {
}
// FBOM物料清单保存
public BOMUploadResult FBloadBillOfMaterialsPreservation(List<BomDetails> bomlist, ProcessOrderPro bo) {
public BOMUploadResult FBloadBillOfMaterialsPreservation(List<BomDetails> bomlist, ProcessOrderPro bo) {
BomDetails bomDetails1 = bomlist.get(0);
int verification = isMaterialVerification(bomDetails1.getFNumber(), bomDetails1.getFName());
@ -805,9 +813,7 @@ public class BomDetailsController extends BaseController {
fTreeEntityItem.addProperty("F_HBYT_BJBM", details.getPartdiagramCode());
fTreeEntityItem.addProperty("F_HBYT_BJMC", details.getPartdiagramName());
fTreeEntityItem.addProperty("FDOSAGETYPE", "2");
//判断这个在原材料表中单位如果是根,的话 那分子就是1 分母就是分子
fTreeEntityItem.addProperty("FNUMERATOR", details.getQuantity());
fTreeEntityItem.addProperty("FNUMERATOR", details.getQuantity()); // 分子
fTreeEntityItem.addProperty("FDENOMINATOR", details.getDenominator());
// 添加货主信息 查看这个bom中是否符合货主信息
@ -1724,7 +1730,10 @@ public class BomDetailsController extends BaseController {
return 1;
}
// 创建电气物料
/**
* / 创建电气物料
*/
public int loadMaterialToDQ(BomDetails bomDetails1, String states) {
K3CloudApi client = new K3CloudApi();
// 创建一个空的JsonObject
@ -1738,7 +1747,8 @@ public class BomDetailsController extends BaseController {
// 添加Model字段
model.addProperty("FMATERIALID", 0);
model.addProperty("FSpecification", bomDetails1.getRemarks());// 备注仓库
model.addProperty("FSpecification", bomDetails1.getMaterial());// 规格 为存入的材质字段
model.addProperty("F_HBYT_PP", bomDetails1.getWareHouse());// 品牌 为存入的仓库字段
model.addProperty("FNumber", bomDetails1.getPartNumber());
model.addProperty("FName", bomDetails1.getName());
MaterialProperties materialProperties = iMaterialPropertiesService.selectByAttribute(bomDetails1.getMaterial());
@ -2108,10 +2118,9 @@ public class BomDetailsController extends BaseController {
subHeadEntity1.add("FPickStockId", fPickStockId);
subHeadEntity5.addProperty("FOverControlMode", "1");
subHeadEntity5.addProperty("FStandHourUnitId", "3600");
subHeadEntity5.addProperty("FStandHourUnitId", "60");
subHeadEntity5.addProperty("FBackFlushType", "1");
String jsonData = json.toString();
System.out.println(jsonData);
try {
// 业务对象标识
String formId = "BD_MATERIAL";
@ -2135,6 +2144,7 @@ public class BomDetailsController extends BaseController {
}
return 1;
}
public BOMUploadResult parseK3Response(String jsonResponse) {
try {
ObjectMapper mapper = new ObjectMapper();
@ -2166,20 +2176,61 @@ public class BomDetailsController extends BaseController {
* @param file 导入文件
*/
@Log(title = "明细导入", businessType = BusinessType.IMPORT)
@SaCheckPermission("system:details:import")
@PostMapping(value = "/importData21", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public R<Void> importData21(@RequestPart("file") MultipartFile file) throws Exception {
@Log(title = "导入电气bom", businessType = BusinessType.IMPORT)
@SaCheckPermission("system:details:importElectricalBom")
@PostMapping(value = "/importElectricalBom", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public void importElectricalBom(@RequestPart("file") MultipartFile file) throws Exception {
List<ElectricalMaterialBomVO> electricalMaterialBomVOS = ExcelUtil.importExcel(file.getInputStream(), ElectricalMaterialBomVO.class);
List<BomDetails> list = new ArrayList<>();
for (ElectricalMaterialBomVO bomVO : electricalMaterialBomVOS) {
BomDetails bomDetails = new BomDetails();
bomDetails.setTotalWeight(bomVO.getProductionOrderNo());
bomDetails.setFNumber(bomVO.getDrawingNo());
bomDetails.setFName(bomVO.getDrawingName());
bomDetails.setPartdiagramCode(bomVO.getParentDrawingNo());
bomDetails.setPartdiagramName(bomVO.getParentPart());
bomDetails.setFNumber(bomVO.getParentDrawingNo());
bomDetails.setFName(bomVO.getParentPart());
bomDetails.setPartNumber(bomVO.getDrawingNo());
bomDetails.setName(bomVO.getDrawingName());
bomDetails.setMaterial(bomVO.getModel());//
bomDetails.setWareHouse(bomVO.getBrand());
bomDetails.setStats("外购");
String quantity = bomVO.getQuantity().toString();
bomDetails.setQuantity(quantity);
bomDetails.setRemarks(bomVO.getUnit());
bomDetails.setUpdateTime(new Date());
bomDetails.setBomType("1");//0 是生产bom 1 是电气bom
list.add(bomDetails);
}
return null;
List<BomDetailsVo> bomDetailsVos1 = BeanUtil.copyToList(list, BomDetailsVo.class);
List<BomDetails> bomDetails = saveBomDetails(bomDetailsVos1);
bomDetailsMapper.insertBatch(bomDetails);
}
// 保存到 BomDetails 表中
//TODO: 使用本地库加速
private List<BomDetails> saveBomDetails(List<BomDetailsVo> bomDetailsVos) {
List<BomDetails> materialsToAdd = new ArrayList<>();
for (BomDetailsVo bomDetailsVo : bomDetailsVos) {
BomDetails bomDetails = BeanUtil.toBean(bomDetailsVo, BomDetails.class);
// 验证物料是否存在
int materialVerification = isMaterialVerification(bomDetails.getPartNumber(), bomDetails.getName());
if (materialVerification == 1) {
bomDetails.setUnitWeight("");
materialsToAdd.add(bomDetails);
} else if (materialVerification == 2) {
bomDetails.setUnitWeight("");
materialsToAdd.add(bomDetails);
} else if (materialVerification == 3) {
bomDetails.setUnitWeight("编码名称不符");
materialsToAdd.add(bomDetails);
}
}
return materialsToAdd;
}
@Log(title = "推送工艺工序")
@SaCheckPermission("system:route:viewGetBomUploadStatus")
@PostMapping("/viewGetBomUploadStatus")
public R<BOMItem> viewGetBomUploadStatus(@RequestParam String rooteProdet) {
return iProcessRouteService.viewGetBomUploadStatus(rooteProdet);
}
}

View File

@ -267,7 +267,7 @@ public class BomVariableController extends BaseController {
if (decimalIndex != -1) {
quantityStr = quantityStr.substring(0, decimalIndex);
}
bomDetails.setQuantity(Double.valueOf(quantityStr));
bomDetails.setQuantity(quantityStr);
}
// 检查并转换单重
if (!rowData.get(5).isEmpty()) {

View File

@ -271,7 +271,7 @@ public class ImMaterialController extends BaseController {
@XxlJob("updateMaterials")
public Boolean updateMaterials() throws Exception {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
List<ImMaterial> imMaterials = updateJdMaterial(sdf.format(date));
Boolean result = iImMaterialService.updateByFMid(imMaterials);
return result;

View File

@ -2,8 +2,10 @@ package com.ruoyi.system.controller;
import java.io.File;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
@ -19,12 +21,14 @@ import com.ruoyi.common.utils.HttpRequestUtil;
import com.ruoyi.common.utils.WxRobotUtil;
import com.ruoyi.common.poi.ExcelTemplateProc;
import com.ruoyi.common.poi.DynamicDataMapping;
import com.ruoyi.system.domain.ProcessRoute;
import com.ruoyi.system.domain.SafetyStock;
import com.ruoyi.system.domain.WlStockData;
import com.ruoyi.system.domain.dto.*;
import com.ruoyi.system.domain.vo.WlStockDataVo;
import com.ruoyi.system.mapper.WlStockDataMapper;
import com.ruoyi.system.runner.JdUtil;
import com.ruoyi.system.service.IProcessRouteService;
import com.ruoyi.system.service.ISafetyStockService;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.RequiredArgsConstructor;
@ -39,6 +43,7 @@ import cn.hutool.core.collection.CollUtil;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import com.ruoyi.common.annotation.RepeatSubmit;
@ -74,7 +79,8 @@ public class KingdeeWorkCenterDataController extends BaseController {
private static final Logger log = LoggerFactory.getLogger(KingdeeWorkCenterDataController.class);
private final WlStockDataMapper baseMapper;
private final ISafetyStockService iSafetyStockService;
@Autowired
IProcessRouteService iProcessRouteService;
/**
* 查询金蝶工段数据列表
*/
@ -381,8 +387,9 @@ public class KingdeeWorkCenterDataController extends BaseController {
msg.append("- ").append(workCenter).append(" (无数据)\n");
continue;
}
List<KingdeeWorkCenterDataBo> dataList = result.getData();
//加入暂停项目的过滤
List<KingdeeWorkCenterDataBo> dataList = result.getData().stream().filter(item -> item.getMoOrderNo() != null && !item.getMoOrderNo().contains("暂停"))
.collect(Collectors.toList());
msg.append("- ").append(workCenter).append(" (共").append(dataList.size()).append("条数据)\n");
// 生成Excel文件
@ -433,10 +440,8 @@ public class KingdeeWorkCenterDataController extends BaseController {
List<KingdeeWorkCenterDataBo> kingdeeWorkCenterDataVos = new ArrayList<>();
parameter.addProperty("FWorkCenterName", workCenter);
Object[] parameters = new Object[]{parameter.toString()};
String execute = client.execute(
"Ljint.Kingdee.YiTe.KanBan.WebApi.ProduceWebApi.ExecuteService,Ljint.Kingdee.YiTe.KanBan.WebApi",
parameters);
log.info("金蝶接口返回数据: {}", execute);
String execute = client.execute("Ljint.Kingdee.YiTe.KanBan.WebApi.ProduceWebApi.ExecuteService,Ljint.Kingdee.YiTe.KanBan.WebApi121303", parameters);
log.info("金蝶接口:" + workCenter + "===> 返回数据: {}", execute);
// 解析响应
JSONObject response = JSONObject.parseObject(execute);
@ -444,7 +449,6 @@ public class KingdeeWorkCenterDataController extends BaseController {
String errorMsg = response.getString("Message");
return R.fail("获取工段数据失败:" + errorMsg);
}
// 获取明天的日期字符串 (格式: yyyy-MM-dd)
String yesterday = DateUtil.format(DateUtil.yesterday(), "yyyy-MM-dd");
@ -518,26 +522,30 @@ public class KingdeeWorkCenterDataController extends BaseController {
public R<Void> getMassageDelayDate() {
try {
// String robotId = "4d2f037d-0cee-493a-a4ff-1758f67b8069";
String robotId = "483489b2-b219-468c-851f-f56a34a62d91";
String robotId = "483489b2-b219-468c-851f-f56a34a62d91";
// String robotId = "8af8abea-3f21-4ca7-ad0a-5b7a2cf4d78e";
List<String> workCenters = Arrays.asList("机一工段", "机二工段", "机三工段", "装一工段", "装二工段", "委外中心", "电钳工段", "铆焊工段");
String currentTime = DateUtil.format(new Date(), "yyyy年MM月dd日 HH:mm:ss");
StringBuilder msg = new StringBuilder();
msg.append("🏭 延期数据更新提醒\n\n")
.append("更新时间:").append(currentTime).append("\n\n")
.append("🔧 工作中心数据统计:\n");
// 构建Markdown消息
StringBuilder markdownMsg = new StringBuilder();
markdownMsg.append("# 生产延期数据更新提醒\n\n")
.append("> **统计时间:** <font color=\"info\">").append(currentTime).append("</font>\n\n")
.append("## 🔧 工作中心数据统计:\n");
// 获取并统计每个工段的数据
for (String workCenter : workCenters) {
try {
R<List<KingdeeWorkCenterDataBo>> result = getKingdeeDelayData(workCenter);
List<KingdeeWorkCenterDataBo> data = result.getData();
if (R.isError(result) || CollUtil.isEmpty(result.getData())) {
msg.append("- ").append(workCenter).append(" (无数据)\n");
markdownMsg.append("- ").append(workCenter).append("<font color=\"comment\">无数据</font>\n");
continue;
}
List<KingdeeWorkCenterDataBo> dataList = result.getData().stream().filter(item -> item.getMoOrderNo() != null && !item.getMoOrderNo().contains("暂停"))
.collect(Collectors.toList());
List<KingdeeWorkCenterDataBo> dataList = result.getData();
msg.append("- ").append(workCenter).append(" (共").append(dataList.size()).append("条数据)\n");
markdownMsg.append("- ").append(workCenter).append(":共 <font color=\"warning\">").append(dataList.size()).append("</font> 条\n");
// 生成Excel文件
String fileName = String.format("%s生产延期数据_%s.xlsx", workCenter,
@ -558,12 +566,18 @@ public class KingdeeWorkCenterDataController extends BaseController {
} catch (Exception e) {
log.error("获取工段{}数据失败", workCenter, e);
msg.append("- ").append(workCenter).append(" (获取失败: ").append(e.getMessage()).append(")\n");
markdownMsg.append("- ").append(workCenter).append("<font color=\"warning\">获取失败: ").append(e.getMessage()).append("</font>\n");
}
}
msg.append("\n详细数据请查看发送的Excel文件");
wxRobotUtil.sendMsgToWeChatGroup(msg.toString(), robotId, true); // @所有人
// 结尾提示与分段发送
markdownMsg.append("\n> **📊 详细数据请查看发送的Excel文件**");
String messageContent = markdownMsg.toString();
int maxLength = 4096;
for (int i = 0; i < messageContent.length(); i += maxLength) {
String part = messageContent.substring(i, Math.min(i + maxLength, messageContent.length()));
wxRobotUtil.sendMarkdownMsgToWeChatGroup(part, robotId);
}
return R.ok();
@ -916,6 +930,7 @@ public class KingdeeWorkCenterDataController extends BaseController {
map.put("FDate", item.getFDate());
map.put("FDeliveryDate", item.getFDeliveryDate());
map.put("FUCHNText2", item.getFUCHNText2());
map.put("FCreateDate", item.getFCreateDate());
mapList.add(map);
index++;
}
@ -944,6 +959,7 @@ public class KingdeeWorkCenterDataController extends BaseController {
map.put("FApplicationDate", item.getFApplicationDate());
map.put("FUCHNText", item.getFUCHNText());
map.put("FCreatorIdFName", item.getFCreatorIdFName());
map.put("FCreateDate", item.getFCreateDate());
mapList.add(map);
index++;
}
@ -956,7 +972,6 @@ public class KingdeeWorkCenterDataController extends BaseController {
*/
private List<PurchaseOrderExcelDTO> filterPurchaseOrders(List<PurchaseOrderExcelDTO> allOrders) {
LocalDate today = LocalDate.now();
DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
log.info("开始过滤采购订单,总数: {}, 当前日期: {}", allOrders.size(), today.format(outputFormatter));
@ -966,30 +981,45 @@ public class KingdeeWorkCenterDataController extends BaseController {
String productionOrderNo = allOrder.getFUCHNText2();
String deliveryDate = allOrder.getFDeliveryDate();
// 条件3: 交货日期不能为空并且必须早于今天
// 条件1: 暂停项目过滤
if (productionOrderNo != null && productionOrderNo.contains("暂停")) {
log.debug("过滤掉: 暂停项目: {}", productionOrderNo);
continue;
}
// 条件2: 交货日期不能为空
if (deliveryDate == null || deliveryDate.trim().isEmpty()) {
log.debug("过滤掉: 交货日期为空");
continue;
}
try {
String dateStr = deliveryDate.split("T")[0]; // yyyy-MM-dd 部分
LocalDate delivery = LocalDate.parse(dateStr, inputFormatter);
// 格式化交货日期
LocalDate delivery = parseDate(deliveryDate);
if (delivery == null) {
log.warn("解析交货日期失败: {}", deliveryDate);
continue;
}
// 转换格式
String formatted = delivery.format(outputFormatter);
allOrder.setFDeliveryDate(formatted);
// 条件3: 只保留交货日期早于今天的
if (!delivery.isBefore(today)) {
log.debug("过滤掉: 交货日期未过期: {}", formatted);
continue;
}
} catch (Exception e) {
log.warn("解析交货日期失败: {}", deliveryDate, e);
continue;
}
allOrder.setFQty(formatQty(allOrder.getFQty()));
// 顺便格式化其他日期字段
allOrder.setFDate(formatDate(allOrder.getFDate()));
allOrder.setFDeliveryDate(formatDate(allOrder.getFDeliveryDate()));
allOrder.setFCreateDate(formatDate(allOrder.getFCreateDate()));
filteredOrders.add(allOrder);
filteredOrders.add(allOrder);
} catch (Exception e) {
log.warn("处理订单异常: {}", productionOrderNo, e);
}
}
log.info("过滤完成,剩余数量: {}", filteredOrders.size());
@ -1002,7 +1032,6 @@ public class KingdeeWorkCenterDataController extends BaseController {
*/
private List<PurchaseRequestExcelDTO> filterReqPurchaseOrders(List<PurchaseRequestExcelDTO> allOrders) {
LocalDate today = LocalDate.now();
DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
log.info("开始过滤采购申请订单,总数: {}, 当前日期: {}", allOrders.size(), today.format(outputFormatter));
@ -1010,39 +1039,54 @@ public class KingdeeWorkCenterDataController extends BaseController {
for (PurchaseRequestExcelDTO allOrder : allOrders) {
String productionOrderNo = allOrder.getFUCHNText();
String deliveryDate = allOrder.getFArrivalDate();
if (allOrder.getFCloseStatus().equals("A")) {
String arrivalDate = allOrder.getFArrivalDate();
// 状态转换
if ("A".equals(allOrder.getFCloseStatus())) {
allOrder.setFCloseStatus("未关闭");
}
if (allOrder.getFDocumentStatus().equals("C")) {
if ("C".equals(allOrder.getFDocumentStatus())) {
allOrder.setFDocumentStatus("已审核");
}
// 暂停项目过滤
if (productionOrderNo != null && productionOrderNo.contains("暂停")) {
log.debug("过滤掉: 暂停项目: {}", productionOrderNo);
continue;
}
// 条件3: 交货日期不能为空并且必须早于今天
if (deliveryDate == null || deliveryDate.trim().isEmpty()) {
log.debug("过滤掉: 交货日期为空");
// 到货日期不能为空
if (arrivalDate == null || arrivalDate.trim().isEmpty()) {
log.debug("过滤掉: 货日期为空");
continue;
}
try {
String dateStr = deliveryDate.split("T")[0]; // yyyy-MM-dd 部分
LocalDate delivery = LocalDate.parse(dateStr, inputFormatter);
LocalDate delivery = parseDate(arrivalDate);
if (delivery == null) {
log.warn("解析到货日期失败: {}", arrivalDate);
continue;
}
// 转换格式
// 转换为中文日期格式
String formatted = delivery.format(outputFormatter);
allOrder.setFArrivalDate(formatted);
// 只保留已过期的日期
if (!delivery.isBefore(today)) {
log.debug("过滤掉: 货日期未过期: {}", formatted);
log.debug("过滤掉: 货日期未过期: {}", formatted);
continue;
}
} catch (Exception e) {
log.warn("解析交货日期失败: {}", deliveryDate, e);
continue;
}
allOrder.setFReqQty(formatQty(allOrder.getFReqQty()));
allOrder.setFCreateDate(formatDate(allOrder.getFCreateDate()));
allOrder.setFApplicationDate(formatDate(allOrder.getFApplicationDate()));
allOrder.setFArrivalDate(formatDate(allOrder.getFArrivalDate()));
filteredOrders.add(allOrder);
filteredOrders.add(allOrder);
} catch (Exception e) {
log.warn("处理订单异常: {}", productionOrderNo, e);
}
}
log.info("过滤完成,剩余数量: {}", filteredOrders.size());
@ -1123,4 +1167,499 @@ public class KingdeeWorkCenterDataController extends BaseController {
}
}
/**
* 将日期字符串 "2025-09-22T10:52:03.6" "2025-09-22"格式化为 "yyyy年MM月dd日"
*/
private String formatDate(String dateStr) {
if (dateStr == null || dateStr.isEmpty()) {
return null;
}
try {
LocalDate date = parseDate(dateStr);
if (date != null) {
return date.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日"));
}
} catch (Exception ignored) {
}
return dateStr; // 解析失败则返回原值
}
/**
* 解析日期字符串支持带 T ISO 格式或普通 yyyy-MM-dd 格式
*/
private LocalDate parseDate(String dateStr) {
if (dateStr == null || dateStr.trim().isEmpty()) {
return null;
}
try {
// 先取出 T 之前的部分
String clean = dateStr.split("T")[0];
return LocalDate.parse(clean, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
} catch (Exception e) {
log.debug("日期解析失败: {}", dateStr, e);
return null;
}
}
/**
* 单据状态编码到中文的映射
* A -> 创建B -> 审核中C -> 已审核其它原样返回
*/
private String mapDocumentStatus(String status) {
if (status == null || status.trim().isEmpty()) {
return "";
}
switch (status) {
case "A":
return "创建";
case "B":
return "审核中";
case "C":
return "已审核";
default:
return status;
}
}
/**
* 格式化数量为两位小数
*/
private String formatQty(String qtyStr) {
if (qtyStr == null || qtyStr.trim().isEmpty()) {
return "0.00";
}
try {
double value = Double.parseDouble(qtyStr);
return String.format("%.2f", value);
} catch (NumberFormatException e) {
log.debug("数量格式化失败: {}", qtyStr, e);
return qtyStr;
}
}
@Log(title = "获取开工延时的生产订单")
@XxlJob("getConstructionDelay")
@PostMapping("/getConstructionDelay")
public R<Void> getConstructionDelay() {
try {
// String robotId = "4d2f037d-0cee-493a-a4ff-1758f67b8069";
String robotId = "8af8abea-3f21-4ca7-ad0a-5b7a2cf4d78e";
String currentTime = DateUtil.format(new Date(), "yyyy年MM月dd日 HH:mm:ss");
StringBuilder msg = new StringBuilder();
msg.append("🏭 生产订单未开工的延期通知\n\n").append("更新时间:").append(currentTime).append("\n\n").append("🔧 订单数据统计:\n");
// 获取生产订单数据
List<ConstructionDelayDTO> purchaseOrderList1 = JdUtil.getConstructionDelay();
List<ConstructionDelayDTO> purchaseOrderList = filterConstructionDel(purchaseOrderList1);
msg.append("- 到期未开工:").append(purchaseOrderList.size()).append("\n");
// 生成Excel文件使用采购模板
String fileName = String.format("生产订单未开工的延期数据_%s.xlsx", DateUtil.format(new Date(), "yyyyMMddHHmmss"));
String filePath = FileUtils.getTempDirectoryPath() + File.separator + fileName;
// 准备模板数据
Map<String, Object> staticDataMap = new HashMap<>();
staticDataMap.put("currentTime", DateUtil.format(new Date(), "yyyy年MM月dd日 HH:mm:ss"));
staticDataMap.put("purchaseOrderCount", purchaseOrderList.size());
List<DynamicDataMapping> dynamicDataMappingList = new ArrayList<>();
// 添加数据仅在此方法内映射避免对已格式化日期再次格式化
if (!purchaseOrderList.isEmpty()) {
List<Map<String, Object>> orderDataList = new ArrayList<>();
// 为避免循环中重复远程查询增加简单的单号级缓存
Map<String, OperationPlannDTO> plannCache = new HashMap<>();
int index = 1;
for (ConstructionDelayDTO item : purchaseOrderList) {
String billNo = item.getFBillNo();
OperationPlannDTO plann = plannCache.get(billNo);
if (plann == null) {
try {
plann = JdUtil.getOperationPlann(billNo);
} catch (Exception ex) {
log.warn("获取工序汇报单失败,单号:{},原因:{}", billNo, ex.getMessage());
}
plannCache.put(billNo, plann); // 即便为 null 也缓存避免重复失败调用
}
Map<String, Object> map = new HashMap<>();
map.put("index", index++);
map.put("F_HBYT_SCLH", item.getF_HBYT_SCLH());
map.put("FBillNo", item.getFBillNo());
map.put("FPickMtrlStatus", item.getFPickMtrlStatus());
map.put("FWorkShopIDFName", item.getFWorkShopIDFName());
map.put("FMaterialIdFNumber", item.getFMaterialIdFNumber());
map.put("FMaterialName", item.getFMaterialName());
// 工序号/数量/工序名称做空值保护避免因远程返回空导致 NPE
String operNumber = (plann != null && StringUtils.hasText(plann.getFOperNumber())) ? plann.getFOperNumber() : "-";
String operQty = (plann != null && StringUtils.hasText(plann.getFOperQty())) ? formatQty(plann.getFOperQty()) : "-";
String processName = (plann != null && StringUtils.hasText(plann.getFProcessIdFName())) ? plann.getFProcessIdFName() : "-";
map.put("FOperNumber", operNumber);
map.put("FOperQty", operQty);
map.put("FProcessIdFName", processName);
map.put("FPlanStartDate", item.getFPlanStartDate());
map.put("FPlanFinishDate", item.getFPlanFinishDate());
map.put("Deydays", item.getDeydays());
map.put("createTime", new Date());
orderDataList.add(map);
}
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("ConstructionDelayDTO", orderDataList));
}
// 使用采购模板生成Excel
String templatePath = "EXCEL模板/生产开工未领料模板.xlsx";
ExcelTemplateProc.doExportExcelByTemplateProc(templatePath, filePath, staticDataMap, dynamicDataMappingList);
// 发送Excel文件
File excelFile = new File(filePath);
if (excelFile.exists()) {
wxRobotUtil.sendFileToWeChatGroup(excelFile, robotId);
FileUtils.deleteQuietly(excelFile);
}
msg.append("\n详细数据请查看发送的Excel文件");
wxRobotUtil.sendMsgToWeChatGroup(msg.toString(), robotId, true); // @所有人
return R.ok();
} catch (Exception e) {
log.error("发送工段数据失败", e);
return R.fail("发送工段数据失败:" + e.getMessage());
}
}
@Log(title = "工序汇报单订单-未入库")
@XxlJob("getProductionOrder")
@PostMapping("/getProductionOrder")
public R<Void> getProductionOrder() {
//TO DO:
try {
String robotId = "8af8abea-3f21-4ca7-ad0a-5b7a2cf4d78e";
String currentTime = DateUtil.format(new Date(), "yyyy年MM月dd日 HH:mm:ss");
StringBuilder msg = new StringBuilder();
msg.append("🏭 工序汇报未入库\n\n").append("更新时间:").append(currentTime).append("\n\n").append("🔧 订单数据统计:\n");
//工序汇报单,未入库列表
List<ProcessReportDTO> processReportDTOList = JdUtil.getProcessReport();
msg.append("- 到期未开工:").append(processReportDTOList.size()).append("\n");
// 生成Excel文件使用采购模板
String fileName = String.format("工序汇报未入库的延期数据_%s.xlsx", DateUtil.format(new Date(), "yyyyMMddHHmmss"));
String filePath = FileUtils.getTempDirectoryPath() + File.separator + fileName;
// 准备模板数据
Map<String, Object> staticDataMap = new HashMap<>();
staticDataMap.put("currentTime", DateUtil.format(new Date(), "yyyy年MM月dd日 HH:mm:ss"));
staticDataMap.put("purchaseOrderCount", processReportDTOList.size());
List<DynamicDataMapping> dynamicDataMappingList = new ArrayList<>();
// 添加数据仅在此方法内映射避免对已格式化日期再次格式化
if (!processReportDTOList.isEmpty()) {
List<Map<String, Object>> reportList = new ArrayList<>();
int index = 1;
for (ProcessReportDTO item : processReportDTOList) {
Map<String, Object> map = new HashMap<>();
map.put("index", index++);
map.put("FSCLH", item.getFSCLH());
map.put("FBillNo", item.getFBillNo());
map.put("FWorkShopID", item.getFWorkShopID());
map.put("FMoNumber", item.getFMoNumber());
map.put("FOperNumber", item.getFOperNumber());
map.put("FOperDescription", item.getFOperDescription());
map.put("FQuaQty", formatQty(item.getFQuaQty()));
map.put("FFinishQty", formatQty(item.getFFinishQty()));
map.put("FStockInQuaAuxQty", formatQty(item.getFStockInQuaAuxQty()));
map.put("FStockInFailAuxQty", formatQty(item.getFStockInFailAuxQty()));
map.put("FRKD", item.getFRKD());
map.put("FDate", parseDate(item.getFDate()));
map.put("createTime", new Date());
reportList.add(map);
}
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("ProcessReportDTO", reportList));
}
// 使用采购模板生成Excel
String templatePath = "EXCEL模板/工序汇报未入库.xlsx";
ExcelTemplateProc.doExportExcelByTemplateProc(templatePath, filePath, staticDataMap, dynamicDataMappingList);
// 发送Excel文件
File excelFile = new File(filePath);
if (excelFile.exists()) {
wxRobotUtil.sendFileToWeChatGroup(excelFile, robotId);
FileUtils.deleteQuietly(excelFile);
}
msg.append("\n详细数据请查看发送的Excel文件");
wxRobotUtil.sendMsgToWeChatGroup(msg.toString(), robotId, true); // @所有人
return R.ok();
} catch (Exception e) {
log.error("发送工段数据失败", e);
return R.fail("发送工段数据失败:" + e.getMessage());
}
}
@Log(title = "工序转移未及时转移")
@XxlJob("getProcessTransferForm")
@PostMapping("/getProcessTransferForm")
public R<Void> getProcessTransferForm() {
//TO D0:需要查询工序计划的时间是否在今日
try {
String robotId = "8af8abea-3f21-4ca7-ad0a-5b7a2cf4d78e";
String currentTime = DateUtil.format(new Date(), "yyyy年MM月dd日 HH:mm:ss");
// 构建 Markdown 消息
StringBuilder markdownMsg = new StringBuilder();
markdownMsg.append("🏭 **工序转移**\n\n");
markdownMsg.append("- 📊 统计时间:").append(currentTime).append("\n");
markdownMsg.append("- 📋 订单数据统计:\n");
//工序汇报单,未入库列表
List<ProcessTransferFormDTO> processReportDTOList = JdUtil.getProcessTransferForm();
markdownMsg.append(" - 工序转移数据:").append(processReportDTOList.size()).append("\n");
// 追加Excel文件提示
if (processReportDTOList.size() > 0) {
markdownMsg.append("\n📄 详细数据请查看发送的 Excel 文件\n");
}
// 生成Excel文件使用采购模板
String fileName = String.format("工序转移数据_%s.xlsx", DateUtil.format(new Date(), "yyyyMMddHHmmss"));
String filePath = FileUtils.getTempDirectoryPath() + File.separator + fileName;
// 准备模板数据
Map<String, Object> staticDataMap = new HashMap<>();
staticDataMap.put("currentTime", DateUtil.format(new Date(), "yyyy年MM月dd日 HH:mm:ss"));
staticDataMap.put("purchaseOrderCount", processReportDTOList.size());
List<DynamicDataMapping> dynamicDataMappingList = new ArrayList<>();
// 添加数据仅在此方法内映射避免对已格式化日期再次格式化
if (!processReportDTOList.isEmpty()) {
List<Map<String, Object>> reportList = new ArrayList<>();
int index = 1;
for (ProcessTransferFormDTO item : processReportDTOList) {
//ProcessRoute routes = iProcessRouteService.getProcessRoutesXuTime(item.getFSCLH(), item.getFProductIdNumber(), item.getFInOperNumber());
/* Date inStart = (routes == null ? null : routes.getXuStartTime());
Date createDate = null;
if (StringUtils.hasText(item.getFCreateDate())) {
try {
createDate = DateUtil.parse(item.getFCreateDate());
} catch (Exception ignored) { }
}
// 当两者时间均可用时仅过滤未晚于转入序开始的记录即不延迟
if (inStart != null && createDate != null && createDate.before(inStart)) {
continue;
}*/
Map<String, Object> map = new HashMap<>();
map.put("index", index++);
map.put("FSCLH", item.getFSCLH());
map.put("FProductIdNumber", item.getFProductIdNumber());
map.put("FDocumentStatus", mapDocumentStatus(item.getFDocumentStatus()));
map.put("FMOBillNo", item.getFMOBillNo());
map.put("FBillNo", item.getFBillNo());
map.put("FProductName", item.getFProductName());
map.put("FOutDeptIdFName", item.getFOutDeptIdFName());
map.put("FOutOperNumber", item.getFOutOperNumber());
map.put("FOutProcessIdName", item.getFOutProcessIdName());
map.put("FInDeptIdFName", item.getFInDeptIdFName());
map.put("FInOperNumber", item.getFInOperNumber());
map.put("FInProcessIdFName", item.getFInProcessIdFName());
map.put("FOperUnit", item.getFOperUnit());
map.put("FOperTransferQty", formatQty(item.getFOperTransferQty()));
map.put("FOperQualifiedQty", formatQty(item.getFOperQualifiedQty()));
map.put("FOperProFailQty", formatQty(item.getFOperProFailQty()));
map.put("FCreateDate", parseDate(item.getFCreateDate()));
map.put("createTime", new Date());
reportList.add(map);
}
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("ProcessTransferFormDTO", reportList));
}
// 使用采购模板生成Excel
String templatePath = "EXCEL模板/工序转移数据.xlsx";
ExcelTemplateProc.doExportExcelByTemplateProc(templatePath, filePath, staticDataMap, dynamicDataMappingList);
// 发送消息
wxRobotUtil.sendMarkdownMsgToWeChatGroup(markdownMsg.toString(), robotId);
// 发送Excel文件
File excelFile = new File(filePath);
if (excelFile.exists()) {
wxRobotUtil.sendFileToWeChatGroup(excelFile, robotId);
FileUtils.deleteQuietly(excelFile);
}
return R.ok();
} catch (Exception e) {
log.error("发送工段数据失败", e);
return R.fail("发送工段数据失败:" + e.getMessage());
}
}
private List<Map<String, Object>> convertConstructionDelayToMapList(List<ConstructionDelayDTO> purchaseOrderList) {
List<Map<String, Object>> mapList = new ArrayList<>();
int index = 1;
for (ConstructionDelayDTO item : purchaseOrderList) {
Map<String, Object> map = new HashMap<>();
map.put("index", index);
// 按照 ConstructionDelayDTO 字段
map.put("F_HBYT_SCLH", item.getF_HBYT_SCLH()); // 生产令号
map.put("FBillNo", item.getFBillNo()); // 单据编码若有
map.put("FWorkShopIDFName", item.getFWorkShopIDFName()); // 车间名称
map.put("FMaterialIdFNumber", item.getFMaterialIdFNumber()); // 物料编码
map.put("FMaterialName", item.getFMaterialName()); // 物料名称
map.put("FPlanStartDate", formatDate(item.getFPlanStartDate())); // 计划开工时间格式化
map.put("FPlanFinishDate", formatDate(item.getFPlanFinishDate())); // 计划完工时间格式化
map.put("Deydays", item.getDeydays()); // 超期天数
mapList.add(map);
index++;
}
return mapList;
}
private List<ConstructionDelayDTO> filterConstructionDel(List<ConstructionDelayDTO> allPurchaseOrderList) {
LocalDate today = LocalDate.now();
DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
log.info("开始过滤生产订单,总数: {}, 当前日期: {}", allPurchaseOrderList.size(), today.format(outputFormatter));
List<ConstructionDelayDTO> filteredOrders = new ArrayList<>();
for (ConstructionDelayDTO allOrder : allPurchaseOrderList) {
String productionOrderNo = allOrder.getF_HBYT_SCLH();
String deliveryDate = allOrder.getFPlanFinishDate();
// 条件1: 暂停项目过滤
if (productionOrderNo != null && productionOrderNo.contains("暂停")) {
log.debug("过滤掉: 暂停项目: {}", productionOrderNo);
continue;
} // 条件1: 暂停项目过滤
if (productionOrderNo == null || productionOrderNo.isEmpty()) {
log.debug("过滤掉: 无令号项目: {}", productionOrderNo);
continue;
}
try {
// 格式化交货日期
LocalDate delivery = parseDate(deliveryDate);
if (delivery == null) {
log.warn("解析交货日期失败: {}", deliveryDate);
continue;
}
String formatted = delivery.format(outputFormatter);
allOrder.setFPlanFinishDate(formatted);
// 顺便格式化其他日期字段
LocalDate planStart = parseDate(allOrder.getFPlanStartDate());
if (planStart == null) {
log.warn("解析开工日期失败: {}", allOrder.getFPlanStartDate());
continue;
}
// 计算过期天数今天减去开工时间
long delayDays = ChronoUnit.DAYS.between(planStart, today);
if (delayDays > 2) {
allOrder.setDeydays((int) delayDays);
allOrder.setFPlanStartDate(planStart.format(outputFormatter));
allOrder.setFPlanFinishDate(formatted);
filteredOrders.add(allOrder);
} else {
log.debug("订单{} 延期{}天,不满足>2天条件过滤", productionOrderNo, delayDays);
}
} catch (Exception e) {
log.warn("处理订单异常: {}", productionOrderNo, e);
}
}
log.info("过滤完成,剩余数量: {}", filteredOrders.size());
return filteredOrders;
}
/**
* 质检不及时数据
*/
@XxlJob("getUninspectedData")
@Log(title = "质检不及时数据", businessType = BusinessType.DELETE)
@PostMapping("/getUninspectedData")
public R<List<ProcessInspectionDTO>> getUninspectedData() {
try {
String robotId = "8af8abea-3f21-4ca7-ad0a-5b7a2cf4d78e";
String currentTime = DateUtil.format(new Date(), "yyyy年MM月dd日 HH:mm:ss");
//工序汇报单,未入库列表
List<ProcessInspectionDTO> processReportDTOList = JdUtil.getUninspectedData();
// 构建Markdown消息
StringBuilder markdownMsg = new StringBuilder();
markdownMsg.append("# 工序质检不及时告警通知\n\n")
.append("> **统计时间:** <font color=\"info\">").append(currentTime).append("</font>\n")
.append("> **未质检工序数量:** <font color=\"warning\">").append(processReportDTOList.size()).append("</font> 条\n\n");
// 如果有未质检数据显示前N条详细信息默认3条
if (!processReportDTOList.isEmpty()) {
markdownMsg.append("## 🔍 未质检工序详情前2条\n\n");
int displayCount = Math.min(2, processReportDTOList.size());
for (int i = 0; i < displayCount; i++) {
ProcessInspectionDTO item = processReportDTOList.get(i);
markdownMsg.append("### ").append(i + 1).append(". ").append(item.getFMaterialName()).append("\n")
.append("> **生产订单号:** <font color=\"comment\">").append(item.getMoOrderNo()).append("</font>\n")
.append("> **工序名称:** <font color=\"info\">").append(item.getFProcessName()).append("</font>\n")
.append("> **工作中心:** <font color=\"comment\">").append(item.getFWorkCenterName()).append("</font>\n")
.append("> **检验状态:** <font color=\"warning\">").append(item.getFInspectStatus()).append("</font>\n")
.append("> **待检数量:** <font color=\"warning\">").append(item.getFWaitInspectQty()).append("</font>\n")
.append("> **已检数量:** <font color=\"info\">").append(item.getFFinishInspectQty()).append("</font>\n")
.append("> **合格数量:** <font color=\"info\">").append(item.getFQuaQty()).append("</font>\n")
.append("> **提交检验时间:** ").append(item.getFSubmitInspectTime()).append("\n\n");
}
if (processReportDTOList.size() > displayCount) {
markdownMsg.append("> **注意:** 还有 ").append(processReportDTOList.size() - displayCount).append(" 条未质检记录详细信息请查看Excel文件\n\n");
}
} else {
markdownMsg.append("## ✅ 暂无未质检工序\n\n");
}
markdownMsg.append("> **创建时间:** ").append(DateUtil.formatDateTime(new Date())).append("\n");
// 追加Excel提示到Markdown消息
markdownMsg.append("\n> **📊 详细数据请查看发送的Excel文件**");
// 生成Excel文件使用采购模板
String fileName = String.format("工序未质检数据_%s.xlsx", DateUtil.format(new Date(), "yyyyMMddHHmmss"));
String filePath = FileUtils.getTempDirectoryPath() + File.separator + fileName;
// 准备模板数据
Map<String, Object> staticDataMap = new HashMap<>();
staticDataMap.put("currentTime", DateUtil.format(new Date(), "yyyy年MM月dd日 HH:mm:ss"));
staticDataMap.put("purchaseOrderCount", processReportDTOList.size());
List<DynamicDataMapping> dynamicDataMappingList = new ArrayList<>();
// 添加数据仅在此方法内映射避免对已格式化日期再次格式化
if (!processReportDTOList.isEmpty()) {
List<Map<String, Object>> reportList = new ArrayList<>();
int index = 1;
for (ProcessInspectionDTO item : processReportDTOList) {
Map<String, Object> map = new HashMap<>();
map.put("index", index++);
map.put("moBillNo", item.getMoBillNo());
map.put("moOrderNo", item.getMoOrderNo());
map.put("fMaterialName", item.getFMaterialName());
map.put("fProcessName", item.getFProcessName());
map.put("fWorkCenterName", item.getFWorkCenterName());
map.put("fInspectStatus", item.getFInspectStatus());
map.put("fWaitInspectQty", item.getFWaitInspectQty());
map.put("fFinishInspectQty", item.getFFinishInspectQty());
map.put("fQuaQty", item.getFQuaQty());
map.put("fReworkQty", item.getFReworkQty());
map.put("fFailQty", item.getFFailQty());
map.put("fSubmitInspectTime", item.getFSubmitInspectTime());
map.put("fFinishInspectTime", item.getFFinishInspectTime());
map.put("fDescription", parseDate(item.getFDescription()));
reportList.add(map);
}
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("ProcessInspectionDTO", reportList));
}
// 使用采购模板生成Excel
String templatePath = "EXCEL模板/质检模板.xlsx";
ExcelTemplateProc.doExportExcelByTemplateProc(templatePath, filePath, staticDataMap, dynamicDataMappingList);
// 发送Excel文件
File excelFile = new File(filePath);
if (excelFile.exists()) {
wxRobotUtil.sendFileToWeChatGroup(excelFile, robotId);
FileUtils.deleteQuietly(excelFile);
}
// 发送Markdown消息企业微信要求使用 msgtype=markdown并按长度分段
String messageContent = markdownMsg.toString();
int maxLength = 4096;
for (int i = 0; i < messageContent.length(); i += maxLength) {
String part = messageContent.substring(i, Math.min(i + maxLength, messageContent.length()));
wxRobotUtil.sendMarkdownMsgToWeChatGroup(part, robotId);
}
return R.ok();
} catch (Exception e) {
log.error("发送工段数据失败", e);
return R.fail("发送工段数据失败:" + e.getMessage());
}
}
}

View File

@ -0,0 +1,119 @@
package com.ruoyi.system.controller;
import java.util.List;
import java.util.Arrays;
import lombok.RequiredArgsConstructor;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.domain.vo.PartCostVo;
import com.ruoyi.system.domain.bo.PartCostBo;
import com.ruoyi.system.service.IPartCostService;
import com.ruoyi.common.core.page.TableDataInfo;
/**
* 零件成本
*
* @author 田志阳
* @date 2025-10-24
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/system/cost")
public class PartCostController extends BaseController {
private final IPartCostService iPartCostService;
/**
* 查询零件成本列表
*/
@SaCheckPermission("system:cost:list")
@GetMapping("/list")
public TableDataInfo<PartCostVo> list(PartCostBo bo, PageQuery pageQuery) {
return iPartCostService.queryPageList(bo, pageQuery);
}
/**
* 导出零件成本列表
*/
@SaCheckPermission("system:cost:export")
@Log(title = "零件成本", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(PartCostBo bo, HttpServletResponse response) {
List<PartCostVo> list = iPartCostService.queryList(bo);
ExcelUtil.exportExcel(list, "零件成本", PartCostVo.class, response);
}
/**
* 获取零件成本详细信息
*
* @param id 主键
*/
@SaCheckPermission("system:cost:query")
@GetMapping("/{id}")
public R<PartCostVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(iPartCostService.queryById(id));
}
/**
* 新增零件成本
*/
@SaCheckPermission("system:cost:add")
@Log(title = "零件成本", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody PartCostBo bo) {
return toAjax(iPartCostService.insertByBo(bo));
}
/**
* 修改零件成本
*/
@SaCheckPermission("system:cost:edit")
@Log(title = "零件成本", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody PartCostBo bo) {
return toAjax(iPartCostService.updateByBo(bo));
}
/**
* 删除零件成本
*
* @param ids 主键串
*/
@SaCheckPermission("system:cost:remove")
@Log(title = "零件成本", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(iPartCostService.deleteWithValidByIds(Arrays.asList(ids), true));
}
/**
* 在金蝶获取成本价
*/
@SaCheckPermission("system:cost:getObtainPartData")
@Log(title = "在金蝶获取成本价", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/getObtainPartData")
public R<Void> getObtainPartData() {
return toAjax(iPartCostService.getObtainPartData());
}
}

View File

@ -170,9 +170,8 @@ public class PcRigidChainController extends BaseController {
DefaultExcelListener<PcRigidChainVo> excelListener = new DefaultExcelListener<>(true);
EasyExcel.read(new ByteArrayInputStream(fileBytes), PcRigidChainVo.class, excelListener)
.excelType(ExcelTypeEnum.XLS)
.sheet(readSheet.getSheetNo())
.headRowNumber(4)
.headRowNumber(3)
.doRead();
List<PcRigidChainVo> list = excelListener.getExcelResult().getList();
@ -214,38 +213,6 @@ public class PcRigidChainController extends BaseController {
PcRigidChain dbChain = chainMap.get(searchKey);
if (dbChain != null) {
matchedCount++;
log.info("找到匹配记录: {}", typeName);
// 记录修改前的关键字段值
log.info("修改前字段值:");
log.info(" - ID: {}", dbChain.getId());
log.info(" - Journey: {} -> {}", dbChain.getJourney(), vOne);
log.info(" - TypeName: {} -> {}", dbChain.getTypeName(), typeName);
log.info(" - Type: {} -> {}", dbChain.getType(), type);
log.info(" - Box: {} -> {}", dbChain.getBox(), box);
log.info(" - AxialDirection: {} -> {}", dbChain.getAxialDirection(), s);
// 记录Excel中的关键字段值
log.info("Excel数据关键字段:");
log.info(" - VOne: {}", pcRigidChainVO.getVOne());
log.info(" - VTwo: {}", pcRigidChainVO.getVTwo());
log.info(" - VThree: {}", pcRigidChainVO.getVThree());
log.info(" - LOne: {}", pcRigidChainVO.getLOne());
log.info(" - LTwo: {}", pcRigidChainVO.getLTwo());
log.info(" - LThree: {}", pcRigidChainVO.getLThree());
log.info(" - SumWeight: {}", pcRigidChainVO.getSumWeight());
log.info(" - ChainWeight: {}", pcRigidChainVO.getChainWeight());
log.info(" - DynamicLoad: {}", pcRigidChainVO.getDynamicLoad());
log.info(" - DeadLoad: {}", pcRigidChainVO.getDeadLoad());
log.info(" - Speed: {}", pcRigidChainVO.getSpeed());
log.info(" - Efficiency: {}", pcRigidChainVO.getEfficiency());
log.info(" - ChainPitch: {}", pcRigidChainVO.getChainPitch());
log.info(" - PitchRadius: {}", pcRigidChainVO.getPitchRadius());
log.info(" - MinimumAltitude: {}", pcRigidChainVO.getMinimumAltitude());
log.info(" - SingleMeterChainWeight: {}", pcRigidChainVO.getSingleMeterChainWeight());
log.info(" - DrivingBoxWeight: {}", pcRigidChainVO.getDrivingBoxWeight());
log.info(" - ChainBoxWeight: {}", pcRigidChainVO.getChainBoxWeight());
log.info(" - Univalence: {}", pcRigidChainVO.getUnivalence());
// 执行字段复制和更新
BeanUtil.copyProperties(pcRigidChainVO, dbChain, "id");
@ -254,34 +221,8 @@ public class PcRigidChainController extends BaseController {
dbChain.setType(type);
dbChain.setBox(box);
dbChain.setAxialDirection(s);
dbChain.setCreateTime(new Date());
dbChain.setUpdateTime(new Date());
// 记录修改后的关键字段值
log.info("修改后字段值:");
log.info(" - Journey: {}", dbChain.getJourney());
log.info(" - TypeName: {}", dbChain.getTypeName());
log.info(" - Type: {}", dbChain.getType());
log.info(" - Box: {}", dbChain.getBox());
log.info(" - AxialDirection: {}", dbChain.getAxialDirection());
log.info(" - LOne: {}", dbChain.getLOne());
log.info(" - LTwo: {}", dbChain.getLTwo());
log.info(" - LThree: {}", dbChain.getLThree());
log.info(" - SumWeight: {}", dbChain.getSumWeight());
log.info(" - ChainWeight: {}", dbChain.getChainWeight());
log.info(" - DynamicLoad: {}", dbChain.getDynamicLoad());
log.info(" - DeadLoad: {}", dbChain.getDeadLoad());
log.info(" - Speed: {}", dbChain.getSpeed());
log.info(" - Efficiency: {}", dbChain.getEfficiency());
log.info(" - ChainPitch: {}", dbChain.getChainPitch());
log.info(" - PitchRadius: {}", dbChain.getPitchRadius());
log.info(" - MinimumAltitude: {}", dbChain.getMinimumAltitude());
log.info(" - SingleMeterChainWeight: {}", dbChain.getSingleMeterChainWeight());
log.info(" - DrivingBoxWeight: {}", dbChain.getDrivingBoxWeight());
log.info(" - ChainBoxWeight: {}", dbChain.getChainBoxWeight());
log.info(" - Univalence: {}", dbChain.getUnivalence());
log.info(" - CreateTime: {}", dbChain.getCreateTime());
log.info(" - UpdateTime: {}", dbChain.getUpdateTime());
pcRigidChainsToUpdate.add(dbChain);
log.info("物料: {} 已添加到更新列表", typeName);
@ -301,27 +242,7 @@ public class PcRigidChainController extends BaseController {
int failCount = 0;
for (PcRigidChain pcRigidChain : pcRigidChainsToUpdate) {
log.info("正在更新物料: {}, ID: {}", pcRigidChain.getTypeName(), pcRigidChain.getId());
// 记录更新前的关键字段值
log.info("更新前数据库字段值:");
log.info(" - Journey: {}", pcRigidChain.getJourney());
log.info(" - LOne: {}", pcRigidChain.getLOne());
log.info(" - LTwo: {}", pcRigidChain.getLTwo());
log.info(" - LThree: {}", pcRigidChain.getLThree());
log.info(" - SumWeight: {}", pcRigidChain.getSumWeight());
log.info(" - ChainWeight: {}", pcRigidChain.getChainWeight());
log.info(" - DynamicLoad: {}", pcRigidChain.getDynamicLoad());
log.info(" - DeadLoad: {}", pcRigidChain.getDeadLoad());
log.info(" - Speed: {}", pcRigidChain.getSpeed());
log.info(" - Efficiency: {}", pcRigidChain.getEfficiency());
log.info(" - ChainPitch: {}", pcRigidChain.getChainPitch());
log.info(" - PitchRadius: {}", pcRigidChain.getPitchRadius());
log.info(" - MinimumAltitude: {}", pcRigidChain.getMinimumAltitude());
log.info(" - SingleMeterChainWeight: {}", pcRigidChain.getSingleMeterChainWeight());
log.info(" - DrivingBoxWeight: {}", pcRigidChain.getDrivingBoxWeight());
log.info(" - ChainBoxWeight: {}", pcRigidChain.getChainBoxWeight());
log.info(" - Univalence: {}", pcRigidChain.getUnivalence());
pcRigidChain.setUpdateTime(new Date());
int i = pcRigidChainMapper.updateById(pcRigidChain);
if (i > 0) {
successCount++;

View File

@ -236,10 +236,14 @@ public class ProcessOrderProController extends BaseController {
*/
@SaCheckPermission("system:processOrderPro:uploadPDF")
@Log(title = "上传PDF", businessType = BusinessType.UPDATE)
@Log(title = "下载PDF", businessType = BusinessType.UPDATE)
@CrossOrigin(origins = "*", allowedHeaders = "*", exposedHeaders = {"Content-Disposition", "Content-Length"})
@GetMapping("/uploadPDF")
public void uploadPDF(@RequestParam Long id, HttpServletResponse response) {
try {
// CORS headers for all responses (success and error)
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition, Content-Length");
// 调用service方法获取文件路径
R<String> result = iProcessOrderProService.uploadPDF(id);
if (result.getCode() != 200) {
@ -264,6 +268,7 @@ public class ProcessOrderProController extends BaseController {
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(file.getName(), "UTF-8") + "\"");
response.setHeader("Content-Length", String.valueOf(file.length()));
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition, Content-Length");
// 写入文件流
try (FileInputStream fis = new FileInputStream(file);
@ -343,6 +348,7 @@ public class ProcessOrderProController extends BaseController {
public List<OverdueProjectVo> getOverdueProjects() {
return iProcessOrderProService.getOverdueProjects();
}
@SaCheckPermission("system:orderPro:geMRPResults")
@Log(title = "获取MRP复核结果", businessType = BusinessType.OTHER)
@PostMapping("/getMRPResults/{id}")
@ -423,7 +429,6 @@ public class ProcessOrderProController extends BaseController {
}
}
// 电气外包分类条件物料编码开头空格/特定前缀 备注包含"外购"
if (materialCode.startsWith(" ")
|| materialCode.startsWith("009301") || materialCode.startsWith("009999")
@ -541,11 +546,11 @@ public class ProcessOrderProController extends BaseController {
// 总装部件优先
boolean isTotal1 = "总装部件".equals(m1);
boolean isTotal2 = "总装部件".equals(m2);
if (isTotal1 && !isTotal2) return -1;
if (!isTotal1 && isTotal2) return 1;
if (isTotal1 && isTotal2) return 0;
// 其他材质按字母顺序排序
if (m1 == null && m2 == null) return 0;
if (m1 == null) return 1;
@ -652,7 +657,6 @@ public class ProcessOrderProController extends BaseController {
if (row == null) {
continue;
}
ProcessRoute vo = new ProcessRoute();
// 根据列索引读取数据保留原始空格
@ -747,9 +751,7 @@ public class ProcessOrderProController extends BaseController {
if (row == null) {
continue;
}
ProductionOrderVo vo = new ProductionOrderVo();
// 根据列索引读取数据保留原始空格
vo.setId(getCellValueAsLong(row.getCell(0)));
vo.setDrawingNo(getCellValueAsString(row.getCell(1))); // 图号

View File

@ -443,7 +443,7 @@ public class ProcessRouteController extends BaseController {
@Log(title = "推送工艺工序")
@SaCheckPermission("system:route:pushRouteBom")
@PostMapping("/pushRouteBom")
public ProcessRoutePushResultDTO pushRouteBom(@RequestParam String rooteProdet) {
public R<ProcessRoutePushResultDTO> pushRouteBom(@RequestParam String rooteProdet) {
return iProcessRouteService.pushRouteBom(rooteProdet);
}
@ -644,7 +644,7 @@ public class ProcessRouteController extends BaseController {
materialBom.setUnit(materialUsageDTO.getChildUnit());
materialBom.setMaterialType(materialUsageDTO.getCaizhi());
//保留四位小数
materialBom.setQuantity(String.valueOf(new BigDecimal(materialUsageDTO.getFenzi()).divide(new BigDecimal(materialUsageDTO.getFenmu()),4, RoundingMode.HALF_UP)));
materialBom.setQuantity(String.valueOf(BigDecimal.valueOf(materialUsageDTO.getFenzi()).divide(new BigDecimal(materialUsageDTO.getFenmu()),4, RoundingMode.HALF_UP)));
return materialBom;
}
@ -658,7 +658,7 @@ public class ProcessRouteController extends BaseController {
bomDetails.setUnitWeight("");
bomDetails.setWareHouse(materialUsageDTO.getChildUnit());
//子项分子
bomDetails.setQuantity(materialUsageDTO.getFenzi());
bomDetails.setQuantity(String.valueOf(materialUsageDTO.getFenzi()));
//子项分母
bomDetails.setDenominator(Double.valueOf(materialUsageDTO.getFenmu()));
bomDetails.setName(materialUsageDTO.getMaterialName());
@ -801,7 +801,7 @@ public class ProcessRouteController extends BaseController {
bomDetails.setUnitWeight("");
bomDetails.setWareHouse(materialUsageDTO.getUnit());
//子项分子
bomDetails.setQuantity(materialUsageDTO.getFNumerator());
bomDetails.setQuantity(String.valueOf(materialUsageDTO.getFNumerator()));
//子项分母
bomDetails.setDenominator(materialUsageDTO.getFDenominator());
bomDetails.setName(materialUsageDTO.getMaterialName());

View File

@ -76,7 +76,7 @@ public class BomDetails extends BaseEntity {
* 子项分子
*/
@JsonProperty("FNUMERATOR")
private Double quantity;
private String quantity;
/**
* 子项分母
*/
@ -106,4 +106,8 @@ public class BomDetails extends BaseEntity {
* 子项单重
*/
private Double singleWeghit;
/**
*bom类型
*/
private String bomType;
}

View File

@ -0,0 +1,72 @@
package com.ruoyi.system.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* 零件成本对象 part_cost
*
* @author 田志阳
* @date 2025-10-24
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("part_cost")
public class PartCost extends BaseEntity {
private static final long serialVersionUID=1L;
/**
* ID
*/
@TableId(value = "id")
private Long id;
/**
* 物料编码
*/
@JsonProperty("FMaterialId.FNumber")
private String materialCode;
/**
* 物料名称
*/
@JsonProperty("FMaterialName")
private String materialName;
/**
* 成本价
*/
@JsonProperty("FPrice")
private BigDecimal costPrice;
/**
* 创建日期
*/
@JsonProperty("FCreateDate")
private Date createDate;
/**
* 车间
*/
@JsonProperty("FEntryWorkShopId.FName")
private String workshop;
/**
* 单位
*/
@JsonProperty("FUnitID.FName")
private String unit;
/**
* 仓库
*/
@JsonProperty("FStockId.FName")
private String warehouse;
/**
* 规格型号
*/
@JsonProperty("FSpecification")
private String specificationModel;
}

View File

@ -79,4 +79,8 @@ public class BomDetailsBo extends BaseEntity {
* 单重
*/
private Double danzhong;
/**
*bom类型
*/
private String bomType;
}

View File

@ -0,0 +1,88 @@
package com.ruoyi.system.domain.bo;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.*;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* 零件成本业务对象 part_cost
*
* @author 田志阳
* @date 2025-10-24
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class PartCostBo extends BaseEntity {
/**
* ID
*/
@NotNull(message = "ID不能为空", groups = { EditGroup.class })
private Long id;
/**
* 物料编码
*/
@NotBlank(message = "物料编码不能为空", groups = { AddGroup.class, EditGroup.class })
@JsonProperty("FMaterialId.FNumber")
private String materialCode;
/**
* 物料名称
*/
@NotBlank(message = "物料名称不能为空", groups = { AddGroup.class, EditGroup.class })
@JsonProperty("FMaterialName")
private String materialName;
/**
* 成本价
*/
@NotNull(message = "成本价不能为空", groups = { AddGroup.class, EditGroup.class })
@JsonProperty("FPrice")
private BigDecimal costPrice;
/**
* 创建日期
*/
@NotNull(message = "创建日期不能为空", groups = { AddGroup.class, EditGroup.class })
@JsonProperty("FCreateDate")
private Date createDate;
/**
* 车间
*/
@NotBlank(message = "车间不能为空", groups = { AddGroup.class, EditGroup.class })
@JsonProperty("FEntryWorkShopId.FName")
private String workshop;
/**
* 单位
*/
@NotBlank(message = "单位不能为空", groups = { AddGroup.class, EditGroup.class })
@JsonProperty("FUnitID.FName")
private String unit;
/**
* 仓库
*/
@NotBlank(message = "仓库不能为空", groups = { AddGroup.class, EditGroup.class })
@JsonProperty("FStockId.FName")
private String warehouse;
/**
* 规格型号
*/
@NotBlank(message = "规格型号", groups = { AddGroup.class, EditGroup.class })
@JsonProperty("FSpecification")
private String specificationModel;
}

View File

@ -0,0 +1,10 @@
package com.ruoyi.system.domain.dto;
import lombok.Data;
import java.util.List;
@Data
public class BOMItem {
int id;
private List<KindegeeLogDTO> items;
}

View File

@ -1,4 +1,4 @@
package com.ruoyi.common.result;
package com.ruoyi.system.domain.dto;
import lombok.Data;

View File

@ -0,0 +1,48 @@
package com.ruoyi.system.domain.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.Date;
@Data
public class ConstructionDelayDTO {
//生产令号
@JsonProperty("F_HBYT_SCLH")
private String F_HBYT_SCLH;
//单据编码
@JsonProperty("FBillNo")
private String FBillNo;
//车间名称
@JsonProperty("FWorkShopID.FName")
private String FWorkShopIDFName;
//物料编码
@JsonProperty("FMaterialId.FNumber")
private String FMaterialIdFNumber;
//物料名称
@JsonProperty("FMaterialName")
private String FMaterialName;
//计划开工时间
@JsonProperty("FPlanStartDate")
private String FPlanStartDate;
//计划完工时间
@JsonProperty("FPlanFinishDate")
private String FPlanFinishDate;
//计划完工时间
@JsonProperty("FPickMtrlStatus")
private String FPickMtrlStatus;
//超期天数
private int Deydays;
@JsonProperty("FOperNumber")
private String FOperNumber;
@JsonProperty("FOperQty")
private String FOperQty;
@JsonProperty("FOutProcessId.FName")
private String FProcessIdFName;
}

View File

@ -0,0 +1,64 @@
package com.ruoyi.system.domain.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 质检检验单数据
* @author tzy
* @date 2025-10-26
*/
@Data
public class InspectionSheetDTO {
//生产令号
@JsonProperty("F_UCHN_Text")
private String productionOrderNumber;
//单据编码
@JsonProperty("FBillNo")
private String FBillNo;
//单据状态
@JsonProperty("FDocumentStatus")
private String DocumentStatus;
//物料编码
@JsonProperty("FMaterialId.FNumber")
private String FMaterialIdFNumber;
//物料名称
@JsonProperty("FMaterialName")
private String FMaterialName;
//规格型号
@JsonProperty("FMaterialModel")
private String FMaterialModel;
//质检状态
@JsonProperty("FQCStatus")
private String FQCStatus;
// 检验结果
@JsonProperty("FInspectResult")
private String FInspectResult;
// 单位
@JsonProperty("FUnitID.FName")
private String FUnitIDFName;
// 检验数量
@JsonProperty("FInspectQty")
private String FInspectQty;
// 合格数
@JsonProperty("FQualifiedQty")
private String FQualifiedQty;
// 不合格数
@JsonProperty("FUnqualifiedQty")
private String FUnqualifiedQty;
//超期天数
private int Deydays;
}

View File

@ -0,0 +1,18 @@
package com.ruoyi.system.domain.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class OperationPlannDTO {
@JsonProperty("FOperNumber")
private String FOperNumber;
@JsonProperty("FOperQty")
private String FOperQty;
@JsonProperty("FOutProcessId.FName")
private String FProcessIdFName;
}

View File

@ -0,0 +1,51 @@
package com.ruoyi.system.domain.dto;
import lombok.Data;
@Data
public class ProcessInspectionDTO {
/** 单编号 */
private String moBillNo;
/** 生产订单号 */
private String moOrderNo;
/** 子订单号 */
private String subOrderNo;
/** 物料名称 */
private String fMaterialName;
/** 工序名称 */
private String fProcessName;
/** 工作中心(工段)名称 */
private String fWorkCenterName;
/** 检验状态(如:未完成、已完成) */
private String fInspectStatus;
/** 待检数量 */
private Integer fWaitInspectQty;
/** 已检验数量 */
private Integer fFinishInspectQty;
/** 合格数量 */
private Integer fQuaQty;
/** 返工数量 */
private Integer fReworkQty;
/** 报废数量 */
private Integer fFailQty;
/** 提交检验时间(字符串格式,如 "12-24" */
private String fSubmitInspectTime;
/** 完成检验时间(字符串格式) */
private String fFinishInspectTime;
/** 备注或描述 */
private String fDescription;
}

View File

@ -0,0 +1,60 @@
package com.ruoyi.system.domain.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 工序汇报单实体
* @author tzy
* @date 2025-10-28
*/
@Data
public class ProcessReportDTO {
//生产令号
@JsonProperty("F_HBYT_SCLH")
private String FSCLH;
//单据编号
@JsonProperty("FBillNo")
private String FBillNo;
//加工车间
@JsonProperty("FWorkShopID.FName")
private String FWorkShopID;
//工序号
@JsonProperty("FOperNumber")
private String FOperNumber;
//工序说明
@JsonProperty("FOperDescription")
private String FOperDescription;
//合格数量
@JsonProperty("FQuaQty")
private String FQuaQty;
//合格数量
@JsonProperty("FMoNumber")
private String FMoNumber;
// 完工数量
@JsonProperty("FFinishQty")
private String FFinishQty;
// 合格品入库数量
@JsonProperty("FStockInQuaAuxQty")
private String FStockInQuaAuxQty;
//不合格品入库数量
@JsonProperty("FStockInFailAuxQty")
private String FStockInFailAuxQty;
//入库点
@JsonProperty("F_HBYT_RKD")
private String FRKD;
//单据日期
@JsonProperty("FDate")
private String FDate;
}

View File

@ -19,6 +19,11 @@ public class ProcessRouteXuDTO {
* 工序路线描述
*/
private String processDescription;
/**
*
*/
private String errorMessage;
/**
* 工艺路线
*/

View File

@ -0,0 +1,77 @@
package com.ruoyi.system.domain.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 工序转移单
* @author tzy
* @date 2025-10-28
*/
@Data
public class ProcessTransferFormDTO {
//生产令号
@JsonProperty("F_HBYT_SCLH")
private String FSCLH;
//单据编码
@JsonProperty("FBillNo")
private String FBillNo;
//单据编码
@JsonProperty("FDocumentStatus")
private String FDocumentStatus;
//单据编码
@JsonProperty("FMOBillNo")
private String FMOBillNo;
//产品编码
@JsonProperty("FProductId.FNumber")
private String FProductIdNumber;
//产品名称
@JsonProperty("FProductName")
private String FProductName;
//转出加工车间
@JsonProperty("FOutDeptId.FName")
private String FOutDeptIdFName;
//转出工序计划号
@JsonProperty("FOutOperNumber")
private String FOutOperNumber;
//转出作业
@JsonProperty("FOutProcessId.FName")
private String FOutProcessIdName;
//转入加工车间
@JsonProperty("FInDeptId.FName")
private String FInDeptIdFName;
//转入工序计划号
@JsonProperty("FInOperNumber")
private String FInOperNumber;
//转入作业
@JsonProperty("FInProcessId.FName")
private String FInProcessIdFName;
//工序单位
@JsonProperty("FOperUnitId.FName")
private String FOperUnit;
//转移数量
@JsonProperty("FOperTransferQty")
private String FOperTransferQty;
//合格数量
@JsonProperty("FOperQualifiedQty")
private String FOperQualifiedQty;
//工废数量
@JsonProperty("FOperProFailQty")
private String FOperProFailQty;
//创建日期
@JsonProperty("FCreateDate")
private String FCreateDate;
}

View File

@ -0,0 +1,70 @@
package com.ruoyi.system.domain.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 生产订单开工未领料数据
* @author tzy
* @date 2025-10-26
*/
@Data
public class ProductionOrderDTO {
//生产令号
@JsonProperty("F_HBYT_SCLH")
private String productionOrderNumber;
//单据编码
@JsonProperty("FBillNo")
private String FBillNo;
//单据状态
@JsonProperty("FDocumentStatus")
private String DocumentStatus;
//物料编码
@JsonProperty("FMaterialId.FNumber")
private String FMaterialIdFNumber;
//物料名称
@JsonProperty("FMaterialName")
private String FMaterialName;
//材质
@JsonProperty("F_UCHN_BaseProperty_qtr")
private String material;
//单位
@JsonProperty("FUnitId.FName")
private String unit;
//生产车间
@JsonProperty("FWorkShopID.FName")
private String productionWorkshop;
//数量
@JsonProperty("FQty")
private String quantity;
//业务状态
@JsonProperty("FStatus")
private String businessStatus;
//领料状态
@JsonProperty("FPickMtrlStatus")
private String materialRequisitionStatus;
//计划开工时间
@JsonProperty("FPlanStartDate")
private String FPlanStartDate;
//计划完工时间
@JsonProperty("FPlanFinishDate")
private String FPlanFinishDate;
//超期天数
private int Deydays;
}

View File

@ -52,5 +52,10 @@ public class PurchaseOrderExcelDTO {
*/
@JsonProperty("F_UCHN_Text2")
private String FUCHNText2;
/**
* 创建日期
*/
@JsonProperty("FCreateDate")
private String FCreateDate;
}

View File

@ -79,11 +79,17 @@ public class PurchaseRequestExcelDTO {
* 生产令号
*/
@JsonProperty("F_UCHN_Text")
private String FUCHNText;/**
private String FUCHNText;
/**
* 生产令号
*/
@JsonProperty("FCreatorId.FName")
private String FCreatorIdFName;
/**
* 创建日期
*/
@JsonProperty("FCreateDate")
private String FCreateDate;
}

View File

@ -103,5 +103,8 @@ public class BomDetailsVo {
private Double danZhong;
private Double singleWeghit;
/**
*bom类型
*/
private String bomType;
}

View File

@ -41,7 +41,7 @@ public class ElectricalMaterialBomVO {
* 品牌
*/
@ExcelProperty(value = "品牌")
private Double Brand;
private String Brand;
/**
* 单台数量
@ -58,7 +58,7 @@ public class ElectricalMaterialBomVO {
* 单位
*/
@ExcelProperty(value = "单位")
private Double unit;
private String unit;
/**
* 备注

View File

@ -0,0 +1,79 @@
package com.ruoyi.system.domain.vo;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.ruoyi.common.annotation.ExcelDictFormat;
import com.ruoyi.common.convert.ExcelDictConvert;
import lombok.Data;
/**
* 零件成本视图对象 part_cost
*
* @author 田志阳
* @date 2025-10-24
*/
@Data
@ExcelIgnoreUnannotated
public class PartCostVo {
private static final long serialVersionUID = 1L;
/**
* ID
*/
@ExcelProperty(value = "ID")
private Long id;
/**
* 物料编码
*/
@ExcelProperty(value = "物料编码")
private String materialCode;
/**
* 物料名称
*/
@ExcelProperty(value = "物料名称")
private String materialName;
/**
* 成本价
*/
@ExcelProperty(value = "成本价")
private BigDecimal costPrice;
/**
* 创建日期
*/
@ExcelProperty(value = "创建日期")
private Date createDate;
/**
* 车间
*/
@ExcelProperty(value = "车间")
private String workshop;
/**
* 单位
*/
@ExcelProperty(value = "单位")
private String unit;
/**
* 仓库
*/
@ExcelProperty(value = "仓库")
private String warehouse;
/**
* 规格型号
*/
@ExcelProperty(value = "规格型号")
private String specificationModel;
}

View File

@ -0,0 +1,15 @@
package com.ruoyi.system.mapper;
import com.ruoyi.system.domain.PartCost;
import com.ruoyi.system.domain.vo.PartCostVo;
import com.ruoyi.common.core.mapper.BaseMapperPlus;
/**
* 零件成本Mapper接口
*
* @author 田志阳
* @date 2025-10-24
*/
public interface PartCostMapper extends BaseMapperPlus<PartCostMapper, PartCost, PartCostVo> {
}

View File

@ -18,10 +18,9 @@ import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
@ -104,14 +103,24 @@ public class PDFGenerator {
throw new RuntimeException("无法创建目录: " + directoryPath);
}
} else {
// 如果目录存在删除其中的所有文件
File[] files = directory.listFiles();
if (files != null) {
for (File file : files) {
if (!file.delete()) {
System.err.println("无法删除文件: " + file.getAbsolutePath());
// 目录存在使用NIO递归清理目录内容不删除根目录本身
try {
Path root = Paths.get(directoryPath);
if (java.nio.file.Files.exists(root)) {
try (java.util.stream.Stream<java.nio.file.Path> walk = java.nio.file.Files.walk(root)) {
walk.filter(p -> !p.equals(root))
.sorted(java.util.Comparator.reverseOrder()) // 先删子路径再删父路径
.forEach(p -> {
try {
java.nio.file.Files.deleteIfExists(p);
} catch (IOException e) {
System.err.println("删除失败: " + p.toString() + ": " + e.getMessage());
}
});
}
}
} catch (IOException e) {
throw new RuntimeException("清理目录失败: " + directoryPath + ", " + e.getMessage(), e);
}
}
for (CombinedDTO combinedVo : combinedVoList) {
@ -125,10 +134,12 @@ public class PDFGenerator {
String materialCode;
Long fmoQty;
String fDepartmentName;
// 获取第一序的工序名称
String OrderNumber = "";
// 获取第一序的工序名称
List<PlannedProcessVo> processes = combinedVo.getProcesses();
if (!processes.isEmpty()) {
fProcessName = processes.get(0).getFProcessName();
OrderNumber = combinedVo.getOrderNumber();
productionOrderNumber = String.valueOf(combinedVo.getProcesses().get(0).getFBillNo());
starttime = combinedVo.getProcesses().get(0).getFPlanStartTime();
endtime = combinedVo.getProcesses().get(0).getFPlanFinishTime();
@ -166,11 +177,11 @@ public class PDFGenerator {
// 获取当前时间的毫秒时间戳
long timestamp = System.currentTimeMillis();
String pdfPath = departmentFolder.getAbsolutePath() + "\\" + fDepartmentName + "_"
+ materialCode1.replace("/", "_") + "_" + productionOrderNumber + ".pdf";
String pdfPath = departmentFolder.getAbsolutePath() + "\\" + fDepartmentName + "_" + materialCode1.replace("/", "_") + "_" + productionOrderNumber + ".pdf";
PDDocument document = null;
try {
// 创建 PDF 文件并写入内容
PDDocument document = new PDDocument();
document = new PDDocument();
PDPage page = new PDPage();
document.addPage(page);
PDType0Font font = PDType0Font.load(document, new File(fontPath));
@ -223,14 +234,15 @@ public class PDFGenerator {
float[] processColWidths = { 35, 78, 35, 55, 45, 170, 55, 60, 60 };
yStart = processTableStartY;
drawTableRow(contentStream, font, margin, yStart, tableWidth, processColWidths, new String[] {
// 使用支持换行的方法绘制表头
yStart = drawTableRowWithWrap(contentStream, font, margin, yStart, tableWidth, processColWidths, new String[] {
"工序号", "工序名称", "数量", "工作中心", "工时(分)", "工序说明", "控制码", "开始时间", "结束时间" }, document, page,
rowHeight, pageHeight);
for (PlannedProcessVo process : combinedVo.getProcesses()) {
SimpleDateFormat formatte1r = new SimpleDateFormat("yyyy-MM-dd");
yStart -= rowHeight;
drawTableRow(contentStream, font, margin, yStart, tableWidth, processColWidths, new String[] {
// 使用支持换行的方法绘制数据行特别是工序说明字段
yStart = drawTableRowWithWrap(contentStream, font, margin, yStart, tableWidth, processColWidths, new String[] {
String.valueOf(process.getFOperNumber()), process.getFProcessName(),
String.valueOf(process.getFOperQty()),
process.getFWorkCenterName(), String.format("%.2f", process.getFActivity1BaseQty()),
@ -309,6 +321,14 @@ public class PDFGenerator {
pdfPaths.add(pdfPath);
} catch (IOException | WriterException e) {
e.printStackTrace();
} finally {
if (document != null) {
try {
document.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
}
}
@ -478,4 +498,122 @@ public class PDFGenerator {
}
}
// ... 其他代码 ...
// Java 8兼容的文本换行处理方法
private static List<String> wrapText(String text, PDType0Font font, float fontSize, float maxWidth) throws IOException {
List<String> lines = new ArrayList<String>();
if (text == null || text.trim().isEmpty()) {
lines.add("");
return lines;
}
// 去除换行符用空格替换
text = text.replace("\n", " ").replace("\r", " ").trim();
// 增加边距确保文本不会超出边界
float effectiveWidth = maxWidth - 20; // 增加边距到20个单位
StringBuilder currentLine = new StringBuilder();
// 逐字符处理更好地支持中文
for (int i = 0; i < text.length(); i++) {
char currentChar = text.charAt(i);
String testLine = currentLine.toString() + currentChar;
float textWidth = font.getStringWidth(testLine) / 1000 * fontSize;
if (textWidth <= effectiveWidth) {
currentLine.append(currentChar);
} else {
// 当前行已满开始新行
if (currentLine.length() > 0) {
lines.add(currentLine.toString().trim());
currentLine = new StringBuilder();
currentLine.append(currentChar);
} else {
// 单个字符就超宽极少见情况强制添加
lines.add(String.valueOf(currentChar));
}
}
}
// 添加最后一行
if (currentLine.length() > 0) {
lines.add(currentLine.toString().trim());
}
// 如果没有任何内容至少返回一个空行
if (lines.isEmpty()) {
lines.add("");
}
return lines;
}
// Java 8兼容的改进表格绘制方法支持自动换行
private static float drawTableRowWithWrap(PDPageContentStream contentStream, PDType0Font font, float margin,
float yStart, float tableWidth, float[] colWidths, String[] cells, PDDocument document,
PDPage page, float baseRowHeight, float pageHeight) throws IOException {
float nextX = margin;
float nextY = yStart;
float fontSize = 10;
int maxColumns = Math.min(cells.length, colWidths.length);
// 计算每列的文本行数确定实际行高
List<List<String>> allCellLines = new ArrayList<List<String>>();
int maxLines = 1;
for (int i = 0; i < maxColumns; i++) {
String cellText = cells[i] != null ? cells[i] : "";
List<String> lines = wrapText(cellText, font, fontSize, colWidths[i]);
allCellLines.add(lines);
maxLines = Math.max(maxLines, lines.size());
}
float actualRowHeight = baseRowHeight * maxLines;
// 检查是否需要分页
if (nextY - actualRowHeight < margin) {
contentStream.close();
// 创建新页面
page = new PDPage();
document.addPage(page);
contentStream = new PDPageContentStream(document, page);
// 重置Y坐标为新页面顶部
nextY = pageHeight - margin;
}
// 绘制表格边框和内容
nextX = margin;
for (int i = 0; i < maxColumns; i++) {
List<String> lines = allCellLines.get(i);
// 绘制单元格边框
contentStream.moveTo(nextX, nextY);
contentStream.lineTo(nextX, nextY - actualRowHeight);
contentStream.lineTo(nextX + colWidths[i], nextY - actualRowHeight);
contentStream.lineTo(nextX + colWidths[i], nextY);
contentStream.closeAndStroke();
// 绘制文本内容
for (int lineIndex = 0; lineIndex < lines.size(); lineIndex++) {
String line = lines.get(lineIndex);
if (!line.isEmpty()) {
contentStream.beginText();
contentStream.setFont(font, fontSize);
float textY = nextY - 15 - (lineIndex * (fontSize + 2));
contentStream.newLineAtOffset(nextX + 8, textY); // 增加左边距到8个单位
contentStream.showText(line);
contentStream.endText();
}
}
nextX += colWidths[i];
}
return nextY - actualRowHeight; // 返回下一行的Y坐标
}
}

View File

@ -70,7 +70,6 @@ public class updatePcessPlanConver {
String formId = "SFC_OperationPlanning";
//调用接口
String resultJson = client.save(formId, jsonOutput);
System.out.println("调用接口:+++++" + jsonOutput);
//用于记录结果
Gson gson = new Gson();
//对返回结果进行解析和校验
@ -108,7 +107,6 @@ public class updatePcessPlanConver {
//业务对象标识工序计划表
String formId = "SFC_OperationPlanning";
//调用接口
System.out.println("调用接口:"+model.getFProcessId_number()+"+++++" + jsonOutput);
String resultJson = client.save(formId, jsonOutput);
//用于记录结果
Gson gson = new Gson();

View File

@ -0,0 +1,50 @@
package com.ruoyi.system.service;
import com.ruoyi.system.domain.vo.PartCostVo;
import com.ruoyi.system.domain.bo.PartCostBo;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.domain.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 零件成本Service接口
*
* @author 田志阳
* @date 2025-10-24
*/
public interface IPartCostService {
/**
* 查询零件成本
*/
PartCostVo queryById(Long id);
/**
* 查询零件成本列表
*/
TableDataInfo<PartCostVo> queryPageList(PartCostBo bo, PageQuery pageQuery);
/**
* 查询零件成本列表
*/
List<PartCostVo> queryList(PartCostBo bo);
/**
* 新增零件成本
*/
Boolean insertByBo(PartCostBo bo);
/**
* 修改零件成本
*/
Boolean updateByBo(PartCostBo bo);
/**
* 校验并批量删除零件成本信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
boolean getObtainPartData();
}

View File

@ -3,6 +3,7 @@ package com.ruoyi.system.service;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.system.domain.dto.BOMItem;
import com.ruoyi.system.domain.BomDetails;
import com.ruoyi.system.domain.MaterialBom;
import com.ruoyi.system.domain.ProcessRoute;
@ -84,7 +85,7 @@ public interface IProcessRouteService {
* 推送工艺路线
*/
ProcessRoutePushResultDTO pushRouteBom(String rooteProdet);
R<ProcessRoutePushResultDTO> pushRouteBom(String rooteProdet);
/**
* 获取所有的项目令号
*/
@ -143,4 +144,9 @@ public interface IProcessRouteService {
String getRouteCode(String materialCode,String code);
List<ProcessRoute> selectByProjectNumber(String productionOrderNo);
R<BOMItem> viewGetBomUploadStatus(String rooteProdet);
//根据令号和物料编码 查询工艺路线
ProcessRoute getProcessRoutesXuTime(String productionOrderNo, String materialCode,String xu);
}

View File

@ -107,6 +107,7 @@ public class BomDetailsServiceImpl implements IBomDetailsService {
lqw.like(StringUtils.isNotBlank(bo.getFName()), BomDetails::getFName, bo.getFName());
lqw.eq(StringUtils.isNotBlank(bo.getStats()), BomDetails::getStats, bo.getStats());
lqw.eq(StringUtils.isNotBlank(bo.getWareHouse()), BomDetails::getWareHouse, bo.getWareHouse());
lqw.eq(StringUtils.isNotBlank(bo.getBomType()), BomDetails::getBomType, bo.getBomType());
lqw.orderByAsc(BomDetails::getTotalWeight);
return lqw;
}
@ -222,11 +223,10 @@ public class BomDetailsServiceImpl implements IBomDetailsService {
MaterialBom matchedMaterialBom = materialBomMap.get(key);
if (matchedMaterialBom != null) {
if (matchedMaterialBom.getUnit().equals("")) {
bomDetail.setQuantity(Double.valueOf(String.valueOf(matchedMaterialBom.getQuantity()).split("/")[0]));
bomDetail.setQuantity(String.valueOf(matchedMaterialBom.getQuantity()).split("/")[0]);
bomDetail.setDenominator(Double.valueOf(String.valueOf(matchedMaterialBom.getQuantity()).split("/")[1]));
} else {
bomDetail.setQuantity(Double.valueOf(String.valueOf(matchedMaterialBom.getQuantity())));
bomDetail.setQuantity(String.valueOf(matchedMaterialBom.getQuantity()));
}
}
}

View File

@ -179,21 +179,6 @@ public class ImMaterialServiceImpl implements IImMaterialService {
try {
LambdaQueryWrapper<ImMaterial> lqw = buildQueryWrapper(bo);
lqw.like(StringUtils.isNotBlank(bo.getMaterialCode()), ImMaterial::getMaterialCode, bo.getMaterialCode());
lqw.like(StringUtils.isNotBlank(bo.getMaterialName()), ImMaterial::getMaterialName, bo.getMaterialName());
lqw.like(StringUtils.isNotBlank(bo.getClassificationName()), ImMaterial::getClassificationName, bo.getClassificationName());
lqw.like(StringUtils.isNotBlank(bo.getImCategory()), ImMaterial::getImCategory, bo.getImCategory());
lqw.like(StringUtils.isNotBlank(bo.getMaterialQuality()), ImMaterial::getMaterialQuality, bo.getMaterialQuality());
lqw.eq(bo.getSingleWeight() != null, ImMaterial::getSingleWeight, bo.getSingleWeight());
lqw.eq( ImMaterial::getForbidStatus, "A");
lqw.like(StringUtils.isNotBlank(bo.getUnit()), ImMaterial::getUnit, bo.getUnit());
lqw.like(bo.getFlag() != null, ImMaterial::getFlag, bo.getFlag());
lqw.orderBy(true, false, ImMaterial::getModifyDate);
System.out.println("+++++++++++++++++++++++++++++++++++++++"+lqw.getSqlSegment());
// 执行查询
Page<ImMaterialVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
if (CollectionUtils.isEmpty(result.getRecords())) {
return TableDataInfo.build(result); // 如果结果为空直接返回
@ -414,11 +399,10 @@ public class ImMaterialServiceImpl implements IImMaterialService {
lqw.like(StringUtils.isNotBlank(bo.getImCategory()), ImMaterial::getImCategory, bo.getImCategory());
lqw.like(StringUtils.isNotBlank(bo.getMaterialQuality()), ImMaterial::getMaterialQuality, bo.getMaterialQuality());
lqw.eq(bo.getSingleWeight() != null, ImMaterial::getSingleWeight, bo.getSingleWeight());
lqw.eq(bo.getForbidStatus() != null, ImMaterial::getForbidStatus, "");
lqw.like(bo.getUnitPrice() != null, ImMaterial::getUnitPrice, bo.getUnitPrice());
lqw.eq( ImMaterial::getForbidStatus, "A");
lqw.like(StringUtils.isNotBlank(bo.getUnit()), ImMaterial::getUnit, bo.getUnit());
lqw.like(bo.getFlag() != null, ImMaterial::getFlag, bo.getFlag());
lqw.orderBy(true, false, ImMaterial::getUnit);
lqw.orderBy(true, false, ImMaterial::getModifyDate);
return lqw;
}
@ -745,9 +729,11 @@ public class ImMaterialServiceImpl implements IImMaterialService {
// 根据 materialId 查询是否存在
ImMaterial existing = baseMapper.selectByMid(imMaterial.getMaterialId());
if (imMaterial.getForbidStatus().equals("A")){
imMaterial.setForbidStatus("");
imMaterial.setForbidStatus("A");
imMaterial.setUpdateTime(new Date());
}else {
imMaterial.setForbidStatus("");
imMaterial.setForbidStatus("B");
imMaterial.setUpdateTime(new Date());
}
if (existing != null) {

View File

@ -145,7 +145,7 @@ public class MaterialBomServiceImpl implements IMaterialBomService {
bomDetails.setName(bo.getMaterialName());
bomDetails.setName(bo.getMaterialName());
bomDetails.setDenominator(1.0);
bomDetails.setQuantity(Double.valueOf(bo.getQuantity()));
bomDetails.setQuantity(bo.getQuantity());
bomDetails.setStats("外购");
bomDetails.setMaterial(bo.getMaterialType());
int flag = bomDetailsMapper.insert(bomDetails);

View File

@ -0,0 +1,166 @@
package com.ruoyi.system.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.runner.JdUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.ruoyi.system.domain.bo.PartCostBo;
import com.ruoyi.system.domain.vo.PartCostVo;
import com.ruoyi.system.domain.PartCost;
import com.ruoyi.system.mapper.PartCostMapper;
import com.ruoyi.system.service.IPartCostService;
import java.math.BigDecimal;
import java.util.*;
/**
* 零件成本Service业务层处理
*
* @author 田志阳
* @date 2025-10-24
*/
@RequiredArgsConstructor
@Service
public class PartCostServiceImpl implements IPartCostService {
private final PartCostMapper baseMapper;
/**
* 查询零件成本
*/
@Override
public PartCostVo queryById(Long id){
return baseMapper.selectVoById(id);
}
/**
* 查询零件成本列表
*/
@Override
public TableDataInfo<PartCostVo> queryPageList(PartCostBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<PartCost> lqw = buildQueryWrapper(bo);
Page<PartCostVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询零件成本列表
*/
@Override
public List<PartCostVo> queryList(PartCostBo bo) {
LambdaQueryWrapper<PartCost> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<PartCost> buildQueryWrapper(PartCostBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<PartCost> lqw = Wrappers.lambdaQuery();
lqw.like(StringUtils.isNotBlank(bo.getMaterialCode()), PartCost::getMaterialCode, bo.getMaterialCode());
lqw.like(StringUtils.isNotBlank(bo.getMaterialName()), PartCost::getMaterialName, bo.getMaterialName());
lqw.eq(bo.getCostPrice() != null, PartCost::getCostPrice, bo.getCostPrice());
lqw.eq(bo.getCreateDate() != null, PartCost::getCreateDate, bo.getCreateDate());
lqw.eq(StringUtils.isNotBlank(bo.getWorkshop()), PartCost::getWorkshop, bo.getWorkshop());
lqw.eq(StringUtils.isNotBlank(bo.getUnit()), PartCost::getUnit, bo.getUnit());
lqw.eq(StringUtils.isNotBlank(bo.getWarehouse()), PartCost::getWarehouse, bo.getWarehouse());
lqw.eq(StringUtils.isNotBlank(bo.getSpecificationModel()), PartCost::getSpecificationModel, bo.getSpecificationModel());
return lqw;
}
/**
* 新增零件成本
*/
@Override
public Boolean insertByBo(PartCostBo bo) {
PartCost add = BeanUtil.toBean(bo, PartCost.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改零件成本
*/
@Override
public Boolean updateByBo(PartCostBo bo) {
PartCost update = BeanUtil.toBean(bo, PartCost.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(PartCost entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 批量删除零件成本
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
@Override
public boolean getObtainPartData() {
List<PartCost> list = JdUtil.getObtainPartData();
if (list == null || list.isEmpty()) {
return false;
}
Map<String, PartCost> uniq = new LinkedHashMap<>();
for (PartCost pc : list) {
if (pc == null) continue;
String code = pc.getMaterialCode();
String name = pc.getMaterialName();
BigDecimal cost = pc.getCostPrice();
// 过滤无效数据
if (StringUtils.isBlank(code) || StringUtils.isBlank(name) || cost == null || cost.compareTo(BigDecimal.ZERO) == 0) {
continue;
}
// 物料编码 + 名称 为唯一键
String key = code + "|" + name;
PartCost existing = uniq.get(key);
// 保留 createDate 最新的
if (existing == null ||
(pc.getCreateDate() != null &&
(existing.getCreateDate() == null || pc.getCreateDate().after(existing.getCreateDate())))) {
uniq.put(key, pc);
}
}
List<PartCost> deduped = new ArrayList<>(uniq.values());
if (deduped.isEmpty()) {
return false;
}
// 删除旧记录
for (PartCost pc : deduped) {
LambdaQueryWrapper<PartCost> delWrapper = Wrappers.lambdaQuery();
delWrapper.eq(PartCost::getMaterialCode, pc.getMaterialCode())
.eq(PartCost::getMaterialName, pc.getMaterialName());
baseMapper.delete(delWrapper);
}
// 批量插入最新记录
return baseMapper.insertBatch(deduped);
}
}

View File

@ -538,7 +538,7 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService {
log.info("出图接口响应=====>{}", response);
// 2. 开始轮询状态接口直到完成
boolean finished = false;
int maxRetry = 60; // 最多轮询 60 根据需求调整比如 60*5s=5分钟
int maxRetry = 360; // 最多轮询 60 根据需求调整比如 60*5s=5分钟
int count = 0;
while (!finished && count < maxRetry) {
@ -968,9 +968,7 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService {
FigureSave figureSave = figureSaveMapper.selectById(id);
ProcessOrderPro processOrderPro = baseMapper.selectById(figureSave);
if (figureSave == null) return "图纸信息不存在";
String code = figureSave.getProductionCode();
// 2. 拼接本地路径和FTP路径
String localPath = Constants.BASIC_URL;
String ftpPath = "";
@ -1252,7 +1250,7 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService {
dto.setRawMaterialName(bom.getMaterialName());
dto.setBomMaterial(bom.getMaterialType());
dto.setBomUnit(bom.getUnit());
// 单位转换如果单位为mm则数值乘以1000
String quantity = bom.getQuantity();
if ("mm".equals(bom.getUnit()) && quantity != null) {

View File

@ -19,11 +19,12 @@ import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.system.domain.dto.BOMItem;
import com.ruoyi.system.domain.dto.BOMUploadResult;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.controller.ProcessRouteController;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.domain.bo.MaterialBomBo;
import com.ruoyi.system.domain.bo.ProcessOrderProBo;
import com.ruoyi.system.domain.bo.ProcessRouteBo;
import com.ruoyi.system.domain.dto.*;
import com.ruoyi.system.domain.vo.*;
@ -265,7 +266,6 @@ public class ProcessRouteServiceImpl implements IProcessRouteService {
}
/**
* @param materialCode
* @return
@ -291,8 +291,40 @@ public class ProcessRouteServiceImpl implements IProcessRouteService {
@Override
public List<ProcessRoute> selectByProjectNumber(String productionOrderNo) {
LambdaQueryWrapper<ProcessRoute> war = new LambdaQueryWrapper<>();
war.eq(ProcessRoute::getRouteDescription,productionOrderNo);
return baseMapper.selectList(war);
war.eq(ProcessRoute::getRouteDescription, productionOrderNo);
return baseMapper.selectList(war);
}
/**
* 获取bom的上传状态
*/
@Override
public R<BOMItem> viewGetBomUploadStatus(String rooteProdet) {
ProcessOrderPro processOrderPro = processOrderProMapper.selectByProjectNumber(rooteProdet);
String drawingType = processOrderPro.getDrawingType(); // 这里就是 JSON
// 转换 JSON 数组 -> List<BOMItem>
List<KindegeeLogDTO> bomItems = JSONUtil.toList(drawingType, KindegeeLogDTO.class);
BOMItem result = new BOMItem();
result.setItems(bomItems);
return R.ok(result);
}
/**
* @param productionOrderNo
* @param materialCode
* @param xu
* @return
*/
@Override
public ProcessRoute getProcessRoutesXuTime(String productionOrderNo, String materialCode, String xu) {
LambdaQueryWrapper<ProcessRoute> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(ProcessRoute::getRouteDescription, productionOrderNo)
.eq(ProcessRoute::getMaterialCode, materialCode)
.eq(ProcessRoute::getProcessNo,xu);
if (baseMapper.selectOne(wrapper) != null) {
return baseMapper.selectOne(wrapper);
}
return null;
}
@ -569,8 +601,7 @@ public class ProcessRouteServiceImpl implements IProcessRouteService {
saveBomDetails(bomDetailsVos);
List<ProcessRoute> routeArrayList = new ArrayList<>();
Map<String, Double> inventoryCache = new HashMap<>();
// 批量查询所有需要的库存信息
boolean allEmpty = processRoutes.stream().allMatch(route -> route.getProcessNo() == null && route.getProcessName() == null);
//获取工艺中所有的时间 挑选出最早的时间和最晚的时间
// 获取最早的开始时间
@ -585,13 +616,13 @@ public class ProcessRouteServiceImpl implements IProcessRouteService {
.max(Comparator.comparing(ProcessRoute::getXuEndTime))
.map(ProcessRoute::getXuEndTime)
.orElse(null);
//更新至计划模块中
//更新至计划模块中
if (earliestStartTime != null && latestEndTime != null) {
ProcessOrderPro processOrderPro = processOrderProMapper.selectByProjectNumber(processRoutes.get(0).getRouteDescription());
ProcessOrderPro processOrderPro = processOrderProMapper.selectByProjectNumber(processRoutes.get(0).getRouteDescription());
processOrderPro.setPlanStartTime(earliestStartTime);
processOrderPro.setPlanEndTime(latestEndTime);
processOrderPro.setUpdateTime(new Date());
log.info("更新计划生成令号为:{},计划开始时间:{},计划结束时间:{}",processRoutes.get(0).getRouteDescription(), earliestStartTime, latestEndTime);
log.info("更新计划生成令号为:{},计划开始时间:{},计划结束时间:{}", processRoutes.get(0).getRouteDescription(), earliestStartTime, latestEndTime);
processOrderProMapper.updateById(processOrderPro);
}
@ -681,23 +712,42 @@ public class ProcessRouteServiceImpl implements IProcessRouteService {
}
}
} else {
for (ProcessRoute processRoute : processRoutes) {
if (processRoute.getProcessNo() != null
||processRoute.getWorkCenter()!= null
||processRoute.getProcessName() != null
||processRoute.getMaterial().equals("总装部件")) {
processRoute.setActivityUnit("");
processRoute.setCreateTime(new Date());
processRoute.setUpdateTime(new Date());
processRoute.setBatchQuantity(processRoute.getBatchQuantity());
processRoute.setUnitQuantity(processRoute.getUnitQuantity());
routeArrayList.add(processRoute);
}
Date now = new Date();
// 先组装 routeArrayList
routeArrayList = processRoutes.stream()
.filter(pr -> pr.getProcessNo() != null
|| pr.getWorkCenter() != null
|| pr.getProcessName() != null)
.map(pr -> {
// 如果描述为空则用工序控制码
if (pr.getProcessDescription() == null || pr.getProcessDescription().isEmpty()) {
pr.setProcessDescription(pr.getProcessName());
}
// 公共逻辑
pr.setActivityUnit("");
pr.setCreateTime(now);
pr.setUpdateTime(now);
return pr;
})
.collect(Collectors.toList());
// 校验是否存在相同物料编码 + 相同工序号
Set<String> duplicateKeys = routeArrayList.stream()
.map(pr -> pr.getMaterialCode() + "-" + pr.getProcessNo())
.filter(Objects::nonNull)
.collect(Collectors.groupingBy(key -> key, Collectors.counting()))
.entrySet().stream()
.filter(e -> e.getValue() > 1)
.map(Map.Entry::getKey)
.collect(Collectors.toSet());
if (!duplicateKeys.isEmpty()) {
log.error("发现重复的物料编码+工序号组合: {}", duplicateKeys);
throw new RuntimeException("存在重复的物料编码和工序号组合: " + duplicateKeys);
}
}
try {
return baseMapper.insertBatch(routeArrayList);
} catch (Exception e) {
log.error("批量插入工艺路线失败", e);
@ -733,10 +783,10 @@ public class ProcessRouteServiceImpl implements IProcessRouteService {
if ("mm".equals(unit)) {
// 将毫米转换为米并保留4位小数
materialBom.setQuantity(String.valueOf(new BigDecimal(quantity).divide(BigDecimal.valueOf(1000), 4, RoundingMode.HALF_UP)));
} else if("".equals(unit) && quantity.contains("/")){
} else if ("".equals(unit) && quantity.contains("/")) {
//写入工艺表时分数的体现 直接取分母 "/"为分割符,取第二个字符串
materialBom.setQuantity(quantity);
}else {
} else {
// 其他单位直接使用原值保留2位小数
materialBom.setQuantity(String.valueOf(new BigDecimal(quantity).setScale(2, RoundingMode.HALF_UP)));
}
@ -777,6 +827,7 @@ public class ProcessRouteServiceImpl implements IProcessRouteService {
bomDetails.setPartdiagramName(productionOrderVo.getParentPart());
bomDetails.setPartNumber(productionOrderVo.getDrawingNo());
bomDetails.setName(productionOrderVo.getDrawingName());
bomDetails.setBomType("0");
Double quantity = productionOrderVo.getQuantity();
bomDetails.setQuantity(quantity != null ? quantity : 0.0);
@ -830,6 +881,7 @@ public class ProcessRouteServiceImpl implements IProcessRouteService {
bomDetails.setFName(processRoute.getMaterialName());
bomDetails.setPartNumber(processRoute.getRawMaterialCode());
bomDetails.setName(processRoute.getRawMaterialName());
bomDetails.setBomType("0");
// 添加单重验证和日志
Double discWeight = processRoute.getDiscWeight();
bomDetails.setDanZhong(discWeight);
@ -838,7 +890,7 @@ public class ProcessRouteServiceImpl implements IProcessRouteService {
// 处理单位换算
if ("mm".equals(processRoute.getBomUnit())) {
bomDetails.setQuantity(Double.parseDouble(processRoute.getDiscUsage())/ 1000.0); // 转换为米
bomDetails.setQuantity(Double.parseDouble(processRoute.getDiscUsage()) / 1000.0); // 转换为米
bomDetails.setDenominator(1.0); // 转换为米
} else if ("".equals(processRoute.getBomUnit())) {
// 写入工艺表时分数的体现 直接取分母 "/"为分割符,取第二个字符串
@ -846,7 +898,7 @@ public class ProcessRouteServiceImpl implements IProcessRouteService {
String quanity2 = processRoute.getDiscUsage().split("/")[1];
bomDetails.setQuantity(Double.parseDouble(quanity));
bomDetails.setDenominator(Double.parseDouble(quanity2));
bomDetails.setDenominator( Double.parseDouble(processRoute.getDiscUsage().split("/")[1]));
bomDetails.setDenominator(Double.parseDouble(processRoute.getDiscUsage().split("/")[1]));
bomDetails.setQuantity(Double.parseDouble(processRoute.getDiscUsage().split("/")[0]));
} else {
bomDetails.setQuantity(Double.parseDouble(processRoute.getDiscUsage()));
@ -1072,12 +1124,12 @@ public class ProcessRouteServiceImpl implements IProcessRouteService {
// 验证物料是否存在
int materialVerification = isMaterialVerification(bomDetails.getPartNumber(), bomDetails.getName());
if (materialVerification ==1) {
if (materialVerification == 1) {
bomDetails.setUnitWeight("");
} else if(materialVerification ==2){
} else if (materialVerification == 2) {
bomDetails.setUnitWeight("");
materialsToAdd.add(bomDetails);
}else if(materialVerification ==3){
} else if (materialVerification == 3) {
bomDetails.setUnitWeight("编码名称不符");
}
@ -1206,7 +1258,7 @@ public class ProcessRouteServiceImpl implements IProcessRouteService {
}
@Override
public ProcessRoutePushResultDTO pushRouteBom(String rooteProdet) {
public R<ProcessRoutePushResultDTO> pushRouteBom(String rooteProdet) {
List<ProcessRouteXuDTO> rawBomList = getProcessRoute(rooteProdet);
List<ProcessRouteXuDTO> successfulRoutes = new ArrayList<>();
List<ProcessRouteXuDTO> failedRoutes = new ArrayList<>();
@ -1217,6 +1269,14 @@ public class ProcessRouteServiceImpl implements IProcessRouteService {
Map<String, List<ProcessRouteSelectDTO>> groupedByFNumber = jdProcessRoute.stream().collect(Collectors.groupingBy(ProcessRouteSelectDTO::getFNumber));
// 当前物料的工艺路线
List<ProcessRouteDTO> processRouteDT = processRouteXuDTO.getProcessRouteDT();
/*boolean hasDuplicate = processRouteDT.stream()
.map(ProcessRouteDTO::getProcessNo) // 取出所有 processNo
.filter(Objects::nonNull) // 避免空指针
.collect(Collectors.toSet()) // 放进 Set
.size() < processRouteDT.size();
if (hasDuplicate){
return R.fail("工序号重复请检查!");
}*/
// 比较工艺路线
boolean isDifferent = compareProcessRoutes(processRouteDT, groupedByFNumber);
if (isDifferent) {
@ -1229,6 +1289,7 @@ public class ProcessRouteServiceImpl implements IProcessRouteService {
successfulRoutes.add(processRouteXuDTO);
} else {
log.info("工艺路线保存失败: " + processRouteXuDTO.getMaterialCode() + result.getMessage());
processRouteXuDTO.setErrorMessage( result.getMessage());
failedRoutes.add(processRouteXuDTO);
}
} else {
@ -1246,7 +1307,7 @@ public class ProcessRouteServiceImpl implements IProcessRouteService {
//更新项目状态 推送工艺
processOrderPro.setBomStatus(3L);
processOrderProMapper.updateById(processOrderPro);
return resultDTO;
return R.ok(resultDTO);
}
public ProcessRoutePushResultDTO pushRouteQBBom(String rooteProdet) {
@ -1566,6 +1627,8 @@ public class ProcessRouteServiceImpl implements IProcessRouteService {
K3CloudApi client = new K3CloudApi();
ProcessModel processModel = createProcessModel(rawBomList);
String jsonStr = JSONUtil.toJsonStr(processModel);
log.debug("推送工艺报文=====》{}",JSONUtil.toJsonStr(jsonStr));
try {
// 业务对象标识
String formId = "ENG_Route";

View File

@ -26,6 +26,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="wareHouse" column="ware_house"/>
<result property="danZhong" column="dan_zhong"/>
<result property="singleWeghit" column="single_weghit"/>
<result property="bomType" column="bom_type"/>
</resultMap>

View File

@ -0,0 +1,24 @@
<?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.ruoyi.system.mapper.PartCostMapper">
<resultMap type="com.ruoyi.system.domain.PartCost" id="PartCostResult">
<result property="id" column="id"/>
<result property="materialCode" column="material_code"/>
<result property="materialName" column="material_name"/>
<result property="costPrice" column="cost_price"/>
<result property="createDate" column="create_date"/>
<result property="workshop" column="workshop"/>
<result property="unit" column="unit"/>
<result property="warehouse" column="warehouse"/>
<result property="createBy" column="create_by"/>
<result property="updateBy" column="update_by"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
<result property="specificationModel" column="specification_model"/>
</resultMap>
</mapper>

View File

@ -27,7 +27,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<!-- 根据项目编号查询 -->
<select id="selectByProjectNumber" resultType="com.ruoyi.system.domain.ProcessOrderPro">
SELECT id, production_order_no, production_name, drawing_no, drawing_name,
SELECT id, production_order_no, production_name, drawing_no, drawing_name,drawing_type,
plan_end_time, plan_start_time, create_by, create_time, update_by, update_time
FROM process_order_pro
WHERE production_order_no = #{routeDescription}