添加nacos配置中心,可动态更新mes导入工程接口;修改Excel表数据转json格式
| | |
| | | <artifactId>serverBase</artifactId> |
| | | <version>1.0.0</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.alibaba.cloud</groupId> |
| | | <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> |
| | | <version>2.1.4.RELEASE</version> |
| | | </dependency> |
| | | </dependencies> |
| | | |
| | | </project> |
| | |
| | | import com.mes.device.service.GlassInfoService; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | import org.springframework.http.HttpStatus; |
| | | import org.springframework.http.ResponseEntity; |
| | | import org.springframework.util.CollectionUtils; |
| | | import org.springframework.web.bind.annotation.*; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | import org.springframework.web.client.RestTemplate; |
| | | |
| | | import java.util.List; |
| | |
| | | private final GlassInfoService glassInfoService; |
| | | private final RestTemplate restTemplate = new RestTemplate(); |
| | | |
| | | @Value("${mes.engineering.import-url}") |
| | | private String mesEngineeringImportUrl; |
| | | |
| | | /** |
| | | * 导入工程 |
| | | * 前端入参示例: |
| | | * { |
| | | * "excelRows": [ |
| | | * {"glassId":"GL001","width":"1000","height":"2000","thickness":"5","quantity":"2","orderNumber":"NG25082101","filmsId":"白玻"} |
| | | * {"glassId":"GL001","width":"1000","height":"2000","thickness":"5","quantity":"2","flowCardId":"NG25082101","filmsId":"白玻"} |
| | | * ] |
| | | * } |
| | | */ |
| | |
| | | Map<String, Object> payload = glassInfoService.buildEngineerImportPayload(excelRows); |
| | | log.info("构建的 MES 导入数据: {}", payload); |
| | | |
| | | String mesEngineeringImportUrl = glassInfoService.getMesEngineeringImportUrl(); |
| | | |
| | | try { |
| | | ResponseEntity<Map> mesResp = restTemplate.postForEntity(mesEngineeringImportUrl, payload, Map.class); |
| | | // 直接返回 MES 的响应,让前端根据响应体中的 code 字段判断是否成功 |
| | | return ResponseEntity.status(mesResp.getStatusCode()).body(mesResp.getBody()); |
| | | } catch (org.springframework.web.client.ResourceAccessException e) { |
| | | // 连接超时或无法连接 |
| | | log.error("转发 MES 导入接口失败(连接问题) url={}, error={}", mesEngineeringImportUrl, e.getMessage(), e); |
| | | Map<String, Object> errorResponse = new java.util.HashMap<>(); |
| | | errorResponse.put("code", 500); |
| | | errorResponse.put("message", "无法连接到 MES 接口,请检查网络连接或联系管理员"); |
| | | errorResponse.put("data", false); |
| | | return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse); |
| | | } catch (Exception e) { |
| | | // 其他异常 |
| | | log.error("转发 MES 导入接口失败 url={}, error={}", mesEngineeringImportUrl, e.getMessage(), e); |
| | | return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("转发 MES 失败: " + e.getMessage()); |
| | | Map<String, Object> errorResponse = new java.util.HashMap<>(); |
| | | errorResponse.put("code", 500); |
| | | errorResponse.put("message", "转发 MES 失败: " + e.getMessage()); |
| | | errorResponse.put("data", false); |
| | | return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse); |
| | | } |
| | | } |
| | | } |
| | |
| | | */ |
| | | boolean updateGlassStatus(List<String> glassIds, String status); |
| | | |
| | | /** |
| | | * 获取 MES 工程导入 URL |
| | | * |
| | | * @return MES 工程导入 URL |
| | | */ |
| | | String getMesEngineeringImportUrl(); |
| | | |
| | | /** |
| | | * 将前端上传的 Excel 行数据转换为 MES 导入工程所需的 JSON 结构 |
| | | * |
| | |
| | | import com.mes.device.mapper.DeviceGlassInfoMapper; |
| | | import com.mes.device.service.GlassInfoService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | import org.springframework.cloud.context.config.annotation.RefreshScope; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.util.CollectionUtils; |
| | | |
| | |
| | | * @since 2024-11-20 |
| | | */ |
| | | @Slf4j |
| | | @RefreshScope |
| | | @Service("deviceGlassInfoService") |
| | | public class GlassInfoServiceImpl extends ServiceImpl<DeviceGlassInfoMapper, GlassInfo> implements GlassInfoService { |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | @Value("${mes.engineering.import-url}") |
| | | private String mesEngineeringImportUrl; |
| | | |
| | | @Override |
| | | public String getMesEngineeringImportUrl() { |
| | | return mesEngineeringImportUrl; |
| | | } |
| | | |
| | | @Override |
| | | public Map<String, Object> buildEngineerImportPayload(List<Map<String, Object>> excelRows) { |
| | | Map<String, Object> result = new HashMap<>(); |
| | |
| | | int qty = (int) parseDouble(row.getOrDefault("quantity", 1), 1); |
| | | if (qty <= 0) qty = 1; |
| | | String glassId = str(row.get("glassId")); |
| | | Integer orderNumber = Integer.parseInt(str(row.get("orderNumber"))); |
| | | String filmsId = strOrDefault(row.get("filmsId"), filmsIdDefaultFinal); |
| | | String flowCardId = str(row.get("flowCardId")); |
| | | String productName = str(row.get("productName")); |
| | |
| | | m.put("glassId", finalGlassId); |
| | | m.put("engineerId", engineerIdFinal); |
| | | m.put("flowCardId", finalFlowCardId); |
| | | m.put("orderNumber", orderNumber); |
| | | m.put("productSortNumber", idx + 1); |
| | | m.put("hollowCombineDirection", "0"); |
| | | m.put("width", width); |
| | |
| | | m.put("combine", 0); |
| | | m.put("markIcon", ""); |
| | | m.put("filmRemove", 0); |
| | | m.put("flowCardSequence", String.valueOf(idx + 1)); |
| | | m.put("flowCardSequence", flowCardId + "/" + (idx + 1)); |
| | | m.put("process", ""); |
| | | m.put("rawAngle", 0); |
| | | m.put("graphNo", 0); |
| | |
| | | double height = parseDouble(row.get("height"), 0d); |
| | | double thickness = parseDouble(row.get("thickness"), thicknessDefaultFinal); |
| | | String filmsId = strOrDefault(row.get("filmsId"), filmsIdDefaultFinal); |
| | | Integer orderNumber = Integer.parseInt(str(row.get("orderNumber"))); |
| | | |
| | | String productName = str(row.get("productName")); |
| | | String customerName = str(row.get("customerName")); |
| | | |
| | |
| | | m.put("totalLayer", 0); |
| | | m.put("layer", 0); |
| | | m.put("glassTotal", 1); |
| | | m.put("orderNumber", orderNumber); |
| | | m.put("productName", productName); |
| | | m.put("customerName", customerName); |
| | | flowCardMap.put(flowCardId, m); |
| | |
| | | max-target: 100 |
| | | min-glass-count: 1 |
| | | max-glass-count: 50 |
| | | |
| | | mes: |
| | | width: 2800 |
| | | height: 5000 |
| New file |
| | |
| | | # bootstrap.yml 优先级高于 application.yml,仅配置Nacos核心连接 |
| | | spring: |
| | | application: |
| | | name: plcSend # 必须和application.yml中的name完全一致 |
| | | cloud: |
| | | nacos: |
| | | config: |
| | | server-addr: 127.0.0.1:8848 # 替换为你的Nacos服务端IP+端口(运维提供) |
| | | file-extension: yml # 配置文件格式(和本地保持一致) |
| | | group: DEFAULT_GROUP # 默认分组,无需修改(可按环境改如DEV_GROUP) |
| | | profiles: |
| | | active: dev |
| | | |
| | | # 可选:关闭Nacos配置缓存(开发环境用,生产默认即可) |
| | | # nacos: |
| | | # config: |
| | | # refresh-enabled: true |
| | | # cache-time: 5000 # 配置拉取间隔(毫秒) |
| | |
| | | const ip = '127.0.0.1' |
| | | // const ip = '10.153.19.6' |
| | | // const ip = '127.0.0.1' |
| | | const ip = '10.153.19.192' |
| | | // const ip = '10.100.0.183' |
| | | // const ip = '192.168.2.8' |
| | | window.ipConfig = { |
| | |
| | | // export const WebSocketHost = "10.153.19.150"; |
| | | // export const WebSocketHost = "172.17.2.7"; |
| | | export const WebSocketHost = "10.153.19.225";//hxl |
| | | export const WebSocketHost = "10.153.19.166";//hxl |
| | | // export const WebSocketHost = "10.153.19.2";//zt |
| | | //export const WebSocketHost = "10.153.19.20";//wsx |
| | | // export const WebSocketHost = "127.0.0.1"; |
| | |
| | | return |
| | | } |
| | | |
| | | // 发送数据到 MES 接口 |
| | | // 发送数据 |
| | | submitGlassData(parsedData) |
| | | |
| | | } catch (error) { |
| | |
| | | headerStr.includes('qty') || headerStr === '数量') { |
| | | headerMap.quantity = index |
| | | } |
| | | // 订单号 |
| | | else if (headerStr.includes('订单') || headerStr.includes('order') || |
| | | headerStr.includes('orderno') || headerStr === '订单号') { |
| | | headerMap.orderNumber = index |
| | | } |
| | | // 膜系 |
| | | else if (headerStr.includes('膜系') || headerStr.includes('films') || |
| | | headerStr.includes('film') || headerStr === '膜系id') { |
| | |
| | | const height = row[headerMap.height] ? String(row[headerMap.height]).trim() : '' |
| | | const thickness = row[headerMap.thickness] ? String(row[headerMap.thickness]).trim() : '' |
| | | const quantity = row[headerMap.quantity] ? String(row[headerMap.quantity]).trim() : '' |
| | | // 订单序号(接口要求整数,这里尝试解析为整数,不可解析则置空) |
| | | const orderNumber = parseInt(row[headerMap.orderNumber]) || '' |
| | | const filmsId = row[headerMap.filmsId] ? String(row[headerMap.filmsId]).trim() : '' |
| | | const flowCardId = row[headerMap.flowCardId] ? String(row[headerMap.flowCardId]).trim() : '' |
| | | const productName = row[headerMap.productName] ? String(row[headerMap.productName]).trim() : '' |
| | |
| | | height: parseNumber(height), |
| | | thickness: parseNumber(thickness), |
| | | quantity: '1', // 每条记录数量为1 |
| | | orderNumber: orderNumber, |
| | | filmsId: filmsId, |
| | | flowCardId: flowCardId || finalGlassId, |
| | | productName: productName, |
| | |
| | | |
| | | const response = await engineeringApi.importEngineer(requestData) |
| | | |
| | | if (response?.code === 200 || response?.code === 0 || response?.data) { |
| | | ElMessage.success(`成功导入 ${glassDataList.length} 条玻璃数据,工程号:${requestData.engineerId}`) |
| | | // 检查 MES 接口是否调用成功 |
| | | // MES 接口成功时返回格式:{ code: 200/0, data: true/false, message: "..." } |
| | | if (response?.code === 200 || response?.code === 0) { |
| | | // MES 接口调用成功 |
| | | const engineerId = response?.data?.engineerId || response?.engineerId || '' |
| | | const successMsg = engineerId |
| | | ? `成功导入 ${glassDataList.length} 条玻璃数据,工程号:${engineerId}` |
| | | : `成功导入 ${glassDataList.length} 条玻璃数据` |
| | | ElMessage.success(successMsg) |
| | | |
| | | // 将导入的玻璃ID填充到输入框,方便用户查看和编辑 |
| | | const glassIds = glassDataList.map(item => item.glassId).filter(id => id) |
| | |
| | | glassIdsInput.value = glassIds.join('\n') |
| | | } |
| | | } else { |
| | | throw new Error(response?.message || '导入失败') |
| | | // MES 接口返回失败 |
| | | throw new Error(response?.message || 'MES 接口返回失败') |
| | | } |
| | | } catch (error) { |
| | | console.error('提交玻璃数据失败:', error) |
| | | |
| | | // 显示错误信息 |
| | | const errorMsg = error?.response?.data?.message || error?.message || '未知错误' |
| | | // 判断错误类型,给出更友好的提示 |
| | | let errorMsg = '未知错误' |
| | | |
| | | // 检查是否是后端返回的错误响应(后端转发 MES 失败) |
| | | if (error?.response?.status === 500 && error?.response?.data) { |
| | | // 后端返回的统一错误格式 |
| | | errorMsg = error.response.data.message || error.response.data || '转发 MES 接口失败' |
| | | } else if (error?.response?.data?.message) { |
| | | // MES 接口返回的错误 |
| | | errorMsg = error.response.data.message |
| | | } else if (error?.message) { |
| | | errorMsg = error.message |
| | | } |
| | | |
| | | ElMessage.error('提交数据失败: ' + errorMsg) |
| | | |
| | | // 即使失败,也尝试填充玻璃ID到输入框 |