9571229a2013472dc701ecf5767f2873b36d8f90..9dcde5b27b70a4b0c0885347af5405eb2d1ef089
昨天 huang
修改前端状态显示变更,保持前端实时更新
9dcde5 对比 | 目录
昨天 huang
修改导入工程json格式
0dfdc8 对比 | 目录
6个文件已修改
179 ■■■■ 已修改文件
mes-processes/mes-plcSend/src/main/java/com/mes/device/controller/GlassInfoImportController.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/GlassInfoServiceImpl.java 119 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/scanner/handler/HorizontalScannerLogicHandler.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
mes-processes/mes-plcSend/src/main/java/com/mes/task/service/TaskExecutionEngine.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
mes-web/src/views/plcTest/components/MultiDeviceTest/ExecutionMonitor.vue 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
mes-web/src/views/plcTest/components/MultiDeviceTest/TaskOrchestration.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
mes-processes/mes-plcSend/src/main/java/com/mes/device/controller/GlassInfoImportController.java
@@ -12,9 +12,7 @@
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
/**
@@ -135,12 +133,19 @@
            List<EngineeringSequence> list = engineeringSequenceService.list();
            List<Map<String, Object>> result = list.stream()
                    .map(seq -> {
                        Map<String, Object> map = new HashMap<>();
                        Map<String, Object> map = new LinkedHashMap<>();
                        map.put("engineeringId", seq.getEngineeringId());
                        map.put("date", seq.getDate());
                        map.put("sequence", seq.getSequence());
                        return map;
                    })
                    .sorted(Comparator.comparing(
                            (Map<String, Object> map) -> (Date) map.get("date"),
                            Comparator.nullsLast(Comparator.reverseOrder())
                    ).thenComparing(
                            map -> (Integer) map.get("sequence"),
                            Comparator.nullsLast(Comparator.reverseOrder())
                    ))
                    .collect(Collectors.toList());
            return ResponseEntity.ok(result);
        } catch (Exception e) {
mes-processes/mes-plcSend/src/main/java/com/mes/device/service/impl/GlassInfoServiceImpl.java
@@ -16,6 +16,7 @@
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import static java.util.stream.IntStream.range;
@@ -241,6 +242,27 @@
        final String filmsIdDefaultFinal = filmsIdDefault;
        final double thicknessDefaultFinal = thicknessDefault;
        // 用于按 flowCardId 全局计数序号
        Map<String, Integer> flowCardSequenceCounter = new HashMap<>();
        // 用于按 flowCardId 计数 temperingFeedSequence
        Map<String, Integer> temperingFeedSequenceCounter = new HashMap<>();
        // 用于按 flowCardId 分配 temperingLayoutId
        Map<String, Integer> temperingLayoutIdMap = new HashMap<>();
        AtomicInteger nextTemperingLayoutId = new AtomicInteger(1);
        // 先建立原片映射,用于后续匹配 rawSequence
        Map<String, Integer> rawSequenceMap = new HashMap<>();
        for (Map<String, Object> row : excelRows) {
            double width = parseDouble(row.get("width"), 0d);
            double height = parseDouble(row.get("height"), 0d);
            double thickness = parseDouble(row.get("thickness"), thicknessDefaultFinal);
            String filmsId = strOrDefault(row.get("filmsId"), filmsIdDefaultFinal);
            String key = width + "_" + height + "_" + thickness + "_" + filmsId;
            if (!rawSequenceMap.containsKey(key)) {
                rawSequenceMap.put(key, rawSequenceMap.size() + 1);
            }
        }
        List<Map<String, Object>> glassInfolList = excelRows.stream()
                .flatMap(row -> {
                    Object qtyObj = row.getOrDefault("quantity", 1);
@@ -249,21 +271,41 @@
                    String glassId = str(row.get("glassId"));
                    String filmsId = strOrDefault(row.get("filmsId"), filmsIdDefaultFinal);
                    String flowCardId = str(row.get("flowCardId"));
                    // orderNumber 是整型(玻璃类型),从 Excel 读取或使用默认值 1
                    Object orderNumberObj = row.get("orderNumber");
                    final Integer finalOrderNumber = orderNumberObj != null
                            ? (int) parseDouble(orderNumberObj, 1)
                            : 1;
                    String productName = str(row.get("productName"));
                    String customerName = str(row.get("customerName"));
                    double width = parseDouble(row.get("width"), 0d);
                    double height = parseDouble(row.get("height"), 0d);
                    double thickness = parseDouble(row.get("thickness"), thicknessDefaultFinal);
                    // 计算 rawSequence
                    String rawKey = width + "_" + height + "_" + thickness + "_" + filmsId;
                    Integer rawSequence = rawSequenceMap.get(rawKey);
                    int finalQty = qty;
                    log.info("解析到数量:row={}, quantity={}, 最终qty={}", row, qtyObj, finalQty);
                    return range(0, qty).mapToObj(idx -> {
                        String baseGlassId = engineerIdFinal + glassId;
                        String finalGlassId = finalQty > 1 ? baseGlassId + "_" + (idx + 1) : baseGlassId;
                        String finalGlassId = finalQty > 1 ? baseGlassId + (idx + 1) : baseGlassId;
                        String baseFlowCardId = flowCardId.isEmpty() ? baseGlassId : flowCardId;
                        String finalFlowCardSequence = baseFlowCardId + "/" + (idx + 1);
                        String finalFlowCardId = baseFlowCardId;
                        // 如果 baseFlowCardId 已经包含尾部 "/数字",先去掉,再由后端统一追加序号
                        baseFlowCardId = baseFlowCardId.replaceFirst("/\\d+$", "");
                        // 按 flowCardId 全局递增序号
                        int sequenceNum = flowCardSequenceCounter.compute(baseFlowCardId, (k, v) -> (v == null ? 0 : v) + 1);
                        String finalFlowCardSequence = baseFlowCardId + "/" + 1;
                        // 按 flowCardId 分配 temperingLayoutId
                        Integer temperingLayoutId = temperingLayoutIdMap.computeIfAbsent(baseFlowCardId, k -> nextTemperingLayoutId.getAndIncrement());
                        // 按 flowCardId 递增 temperingFeedSequence
                        int temperingFeedSequence = temperingFeedSequenceCounter.compute(baseFlowCardId, (k, v) -> (v == null ? 0 : v) + 1);
                        log.debug("生成flowCardSequence: idx={}, baseFlowCardId={}, sequenceNum={}, finalFlowCardSequence={}, temperingLayoutId={}, temperingFeedSequence={}",
                                idx, baseFlowCardId, sequenceNum, finalFlowCardSequence, temperingLayoutId, temperingFeedSequence);
                        Map<String, Object> m = new HashMap<>();
                        m.put("xAxis", 0);
@@ -272,24 +314,25 @@
                        m.put("yCoordinate", 0);
                        m.put("glassId", finalGlassId);
                        m.put("engineerId", engineerIdFinal);
                        m.put("flowCardId", finalFlowCardId);
                        m.put("productSortNumber", idx + 1);
                        m.put("hollowCombineDirection", "0");
                        m.put("flowCardId", baseFlowCardId);
                        m.put("orderNumber", finalOrderNumber);
                        m.put("productSortNumber", 1); // 统一为1
                        m.put("hollowCombineDirection", "");
                        m.put("width", width);
                        m.put("height", height);
                        m.put("thickness", thickness);
                        m.put("filmsId", filmsId);
                        m.put("layer", 0);
                        m.put("totalLayer", 0);
                        m.put("layer", 1);
                        m.put("totalLayer", 1);
                        m.put("edgWidth", width);
                        m.put("edgHeight", height);
                        m.put("isMultiple", 0);
                        m.put("isMultiple", finalQty > 1 ? 1 : 0); // 数量>1时为1
                        m.put("maxWidth", width);
                        m.put("maxHeight", height);
                        m.put("isHorizontal", 0);
                        m.put("rawSequence", 0);
                        m.put("temperingLayoutId", 0);
                        m.put("temperingFeedSequence", 0);
                        m.put("rawSequence", rawSequence != null ? rawSequence : 0);
                        m.put("temperingLayoutId", temperingLayoutId);
                        m.put("temperingFeedSequence", temperingFeedSequence);
                        m.put("angle", 0);
                        m.put("ruleId", 0);
                        m.put("combine", 0);
@@ -328,19 +371,27 @@
        List<Map<String, Object>> engineeringRawQueueList = rawGlassMap.values().stream().collect(Collectors.toList());
        // 流程卡信息
        // 流程卡信息(需要统计每个 flowCardId 的实际玻璃数量,考虑 quantity)
        Map<String, Map<String, Object>> flowCardMap = new HashMap<>();
        for (Map<String, Object> row : excelRows) {
            String glassId = str(row.get("glassId"));
            String flowCardId = str(row.get("flowCardId"));
            if (flowCardId.isEmpty()) {
                flowCardId = glassId;
                flowCardId = engineerIdFinal + glassId;
            }
            // 去掉尾部 "/数字"(如果有)
            flowCardId = flowCardId.replaceFirst("/\\d+$", "");
            // orderNumber 是整型(玻璃类型),从 Excel 读取或使用默认值 1
            Object orderNumberObj = row.get("orderNumber");
            Integer orderNumber = orderNumberObj != null
                    ? (int) parseDouble(orderNumberObj, 1)
                    : 1;
            Object qtyObj = row.getOrDefault("quantity", 1);
            int qty = parseDouble(qtyObj, 1) > 0 ? (int) parseDouble(qtyObj, 1) : 1;
            double width = parseDouble(row.get("width"), 0d);
            double height = parseDouble(row.get("height"), 0d);
            double thickness = parseDouble(row.get("thickness"), thicknessDefaultFinal);
            String filmsId = strOrDefault(row.get("filmsId"), filmsIdDefaultFinal);
            String productName = str(row.get("productName"));
            String customerName = str(row.get("customerName"));
@@ -352,15 +403,16 @@
                m.put("height", height);
                m.put("thickness", thickness);
                m.put("filmsId", filmsId);
                m.put("totalLayer", 0);
                m.put("layer", 0);
                m.put("glassTotal", 1);
                m.put("totalLayer", 1);
                m.put("layer", 1);
                m.put("glassTotal", qty); // 使用实际数量
                m.put("orderNumber", orderNumber);
                m.put("productName", productName);
                m.put("customerName", customerName);
                flowCardMap.put(flowCardId, m);
            } else {
                int count = (int) exist.getOrDefault("glassTotal", 1);
                exist.put("glassTotal", count + 1);
                int count = (int) exist.getOrDefault("glassTotal", 0);
                exist.put("glassTotal", count + qty); // 累加数量
            }
        }
        List<Map<String, Object>> flowCardInfoList = flowCardMap.values().stream().collect(Collectors.toList());
@@ -374,8 +426,33 @@
                .mapToDouble(m -> parseDouble(m.get("rawGlassWidth"), 0d) * parseDouble(m.get("rawGlassHeight"), 0d) / 1_000_000d)
                .sum();
        // 计算最大负载尺寸(用于钢化参数)
        double maxLoadWidth = glassInfolList.stream()
                .mapToDouble(m -> parseDouble(m.get("width"), 0d))
                .max().orElse(2000);
        double maxLoadLength = glassInfolList.stream()
                .mapToDouble(m -> parseDouble(m.get("height"), 0d))
                .max().orElse(3000);
        // 生成钢化参数
        List<Map<String, Object>> temperingParameterList = new ArrayList<>();
        Map<String, Object> temperingParam = new HashMap<>();
        temperingParam.put("engineerId", engineerIdFinal);
        temperingParam.put("heatMode", 1);
        temperingParam.put("chaosPct", 50);
        temperingParam.put("maxLoadPct", 100);
        temperingParam.put("loadWidth", (int) Math.round(maxLoadWidth));
        temperingParam.put("loadLength", (int) Math.round(maxLoadLength));
        temperingParam.put("xSpace", 50);
        temperingParam.put("ySpace", 50);
        temperingParam.put("rotateMode", 0);
        temperingParam.put("allowRotate", 0);
        temperingParam.put("tempering", 1);
        temperingParam.put("curtainWall", 0);
        temperingParameterList.add(temperingParam);
        result.put("engineerId", engineerIdFinal);
        result.put("engineerName", "工程_" + engineerIdFinal);
        result.put("engineerName", thicknessDefaultFinal + "mm" + filmsIdDefaultFinal);
        result.put("avgAvailability", "90");
        result.put("validAvailability", "90");
        result.put("lastAvailability", "90");
mes-processes/mes-plcSend/src/main/java/com/mes/interaction/workstation/scanner/handler/HorizontalScannerLogicHandler.java
@@ -125,7 +125,7 @@
            clearPlcRequestFields(deviceConfig, serializer);
            return buildResult(deviceConfig, "scanOnce", false, "MES写区未提供玻璃ID", null);
        }
        // 读取MES尺寸数据:mesWidth=表宽,mesHeight=长
        // 读取MES尺寸数据:mesWidth=宽,mesHeight=长
        Integer rawWidth = parseInteger(mesData.get("mesWidth"));
        Integer rawHeight = parseInteger(mesData.get("mesHeight"));
        Integer workLine = parseInteger(mesData.get("workLine"));
@@ -144,7 +144,7 @@
        saveScannedGlassId(params, glassId);
        Integer intervalMs = config != null ? config.getScanIntervalMs() : null;
        String msg = String.format("玻璃[%s] 尺寸[表宽:%s x 长:%s] 已接收,workLine=%s,扫描间隔=%s",
        String msg = String.format("玻璃[%s] 尺寸[宽:%s x 长:%s] 已接收,workLine=%s,扫描间隔=%s",
                glassId,
                rawWidth != null ? rawWidth + "mm" : "-",
                rawHeight != null ? rawHeight + "mm" : "-",
@@ -272,7 +272,7 @@
    private GlassInfo buildGlassInfo(String glassId, Integer width, Integer height, Integer workLine) {
        GlassInfo glassInfo = new GlassInfo();
        glassInfo.setGlassId(glassId.trim());
        // mesWidth=表宽 -> glassWidth, mesHeight=长 -> glassLength
        // mesWidth=宽 -> glassWidth, mesHeight=长 -> glassLength
        if (width != null) {
            glassInfo.setGlassWidth(width);
        }
mes-processes/mes-plcSend/src/main/java/com/mes/task/service/TaskExecutionEngine.java
@@ -1208,7 +1208,17 @@
                    Long processStartTime = getProcessStartTime(context);
                    if (processStartTime == null) {
                        // 第一次检测到玻璃,记录开始处理时间
                        setProcessStartTime(context, System.currentTimeMillis());
                        long now = System.currentTimeMillis();
                        setProcessStartTime(context, now);
                        // 补齐步骤的开始时间与状态,确保前端耗时正常显示
                        if (!TaskStepDetail.Status.RUNNING.name().equals(step.getStatus())) {
                            step.setStatus(TaskStepDetail.Status.RUNNING.name());
                        }
                        if (step.getStartTime() == null) {
                            step.setStartTime(new Date(now));
                        }
                        taskStepDetailMapper.updateById(step);
                        notificationService.notifyStepUpdate(task.getTaskId(), step);
                        log.debug("大理片笼设备开始处理: taskId={}, deviceId={}, glassCount={}, processTime={}s",
                                task.getTaskId(), device.getId(), loadedGlassIds.size(), processTimeSeconds);
                        return;
@@ -1234,6 +1244,17 @@
                    // 更新步骤状态
                    step.setStatus(TaskStepDetail.Status.COMPLETED.name());
                    step.setErrorMessage(null);
                    // 记录结束时间与耗时
                    if (step.getEndTime() == null) {
                        step.setEndTime(new Date());
                    }
                    if (step.getStartTime() == null) {
                        // 如果开始时间缺失,用处理开始时间或结束时间兜底
                        step.setStartTime(new Date(processStartTime));
                    }
                    if (step.getStartTime() != null && step.getEndTime() != null) {
                        step.setDurationMs(step.getEndTime().getTime() - step.getStartTime().getTime());
                    }
                    step.setOutputData(toJson(Collections.singletonMap("glassIds", loadedGlassIds)));
                    taskStepDetailMapper.updateById(step);
                    // 大理片笼完成后尝试自动收尾整个任务
mes-web/src/views/plcTest/components/MultiDeviceTest/ExecutionMonitor.vue
@@ -179,6 +179,12 @@
let eventSource = null
const baseURL = import.meta.env.VITE_API_BASE_URL || ''
// 统一的ID比较,避免数字/字符串不一致导致SSE更新被忽略
const isSameId = (a, b) => {
  if (a == null || b == null) return false
  return String(a) === String(b)
}
const fetchTasks = async () => {
  try {
    loading.value = true
@@ -262,9 +268,11 @@
    // 监听步骤更新
    eventSource.addEventListener('stepUpdate', (event) => {
      try {
        const data = JSON.parse(event.data)
        const raw = JSON.parse(event.data)
        // 后端全量监听时的数据结构为 { taskId, step: { ... } },需要展开 step
        const data = raw?.step ? { ...raw.step, taskId: raw.taskId || raw.step.taskId } : raw
        // 如果数据中包含 taskId,检查是否匹配当前查看的任务
        if (data.taskId && data.taskId === currentTaskId.value) {
        if (data.taskId && isSameId(data.taskId, currentTaskId.value)) {
          updateStepFromSSE(data)
        } else if (!data.taskId) {
          // 如果没有 taskId,可能是步骤数据直接传递
@@ -311,7 +319,7 @@
    return
  }
  const taskIndex = tasks.value.findIndex(t => t.taskId === data.taskId)
  const taskIndex = tasks.value.findIndex(t => isSameId(t.taskId, data.taskId))
  if (taskIndex >= 0) {
    // 更新任务 - 保留原有字段,只更新SSE传来的字段
    const existingTask = tasks.value[taskIndex]
@@ -344,7 +352,7 @@
  if (!data) return
  
  // 如果数据中包含 taskId,检查是否匹配当前查看的任务
  if (data.taskId && data.taskId !== currentTaskId.value) {
  if (data.taskId && !isSameId(data.taskId, currentTaskId.value)) {
    return
  }
mes-web/src/views/plcTest/components/MultiDeviceTest/TaskOrchestration.vue
@@ -616,7 +616,7 @@
    const qty = parseInt(quantity) || 1
    for (let j = 0; j < qty; j++) {
      // 如果数量大于1,为每条记录生成唯一的玻璃ID(追加序号)
      const finalGlassId = qty > 1 ? `${glassId}_${j + 1}` : glassId
      const finalGlassId = qty > 1 ? `${glassId}${j + 1}` : glassId
      result.push({
        glassId: finalGlassId,