yangys
8 天以前 f4c6e0e1308bccb943ca1cddfdf7f643b6b6a1aa
测试导出dnc
已修改7个文件
已添加9个文件
538 ■■■■■ 文件已修改
blade-service/blade-mdm/src/main/java/org/springblade/mdm/commons/contants/ParamContants.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
blade-service/blade-mdm/src/main/java/org/springblade/mdm/config/InitBean.java 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
blade-service/blade-mdm/src/main/java/org/springblade/mdm/config/ShutdownHook.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
blade-service/blade-mdm/src/main/java/org/springblade/mdm/machineback/controller/DirectoryWatcherController.java 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
blade-service/blade-mdm/src/main/java/org/springblade/mdm/machineback/entity/MachineBackFile.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
blade-service/blade-mdm/src/main/java/org/springblade/mdm/machineback/filewatch/DirectorLockService.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
blade-service/blade-mdm/src/main/java/org/springblade/mdm/machineback/filewatch/DynamicDirectoryWatcher.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
blade-service/blade-mdm/src/main/java/org/springblade/mdm/machineback/filewatch/FileLockChecker.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
blade-service/blade-mdm/src/main/java/org/springblade/mdm/machineback/filewatch/FileWatcherService.java 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
blade-service/blade-mdm/src/main/java/org/springblade/mdm/machineback/filewatch/MachineFileBackListener.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
blade-service/blade-mdm/src/main/java/org/springblade/mdm/program/controller/NcProgramController.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
blade-service/blade-mdm/src/main/java/org/springblade/mdm/program/controller/NcProgramExportDNCController.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
blade-service/blade-mdm/src/main/java/org/springblade/mdm/program/mapper/ProcessProgRefMapper.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
blade-service/blade-mdm/src/main/java/org/springblade/mdm/program/service/MdmProgramImportService.java 33 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
blade-service/blade-mdm/src/main/java/org/springblade/mdm/program/service/NcProgramExportDNCService.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
blade-service/blade-mdm/src/main/java/org/springblade/mdm/program/service/NcProgramService.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
blade-service/blade-mdm/src/main/java/org/springblade/mdm/commons/contants/ParamContants.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,13 @@
package org.springblade.mdm.commons.contants;
public class ParamContants {
    public static final String NETWORK_TYPE_KEY = "networkType";
    /**
     * æ¶‰å¯†ç½‘
     */
    public static final String NETWORK_TYPE_SHEMI = "0";
    /**
     * å·¥æŽ§ç½‘
     */
    public static final String NETWORK_TYPE_GONGKONG = "1";
}
blade-service/blade-mdm/src/main/java/org/springblade/mdm/config/InitBean.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,89 @@
package org.springblade.mdm.config;
import jakarta.annotation.PostConstruct;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springblade.core.tool.api.R;
import org.springblade.mdm.basesetting.machine.MachineService;
import org.springblade.mdm.basesetting.machine.entity.Machine;
import org.springblade.mdm.commons.contants.ParamContants;
import org.springblade.mdm.machineback.filewatch.DirectorLockService;
import org.springblade.mdm.machineback.filewatch.DynamicDirectoryWatcher;
import org.springblade.mdm.machineback.filewatch.FileWatcherService;
import org.springblade.mdm.machineback.filewatch.MachineFileBackListener;
import org.springblade.mdm.machineback.service.MachineBackFileService;
import org.springblade.mdm.program.service.NcProgramService;
import org.springblade.system.feign.ISysClient;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@AllArgsConstructor
@Component
public class InitBean {
    private final DirectorLockService directorLockService;
    private final MachineService machineService;
    private final FileWatcherService fileWatcherService;
    private final ISysClient sysClient;
    private final DynamicDirectoryWatcher directoryWatcher;
    private final MachineBackFileService machineBackFileService;
    private final NcProgramService ncProgramService;
    //private final FileWatcherService.FileChangeListener listener;
    @PostConstruct
    public void init() {
        System.out.println("应用启动时执行初始化操作 @PostConstruct");
        // åˆå§‹åŒ–逻辑
        R<String> networkTypeR = sysClient.getParamValue(ParamContants.NETWORK_TYPE_KEY);
        String networkType = networkTypeR.getData() == null ? ParamContants.NETWORK_TYPE_SHEMI : networkTypeR.getData();
        if (networkType.equals(ParamContants.NETWORK_TYPE_GONGKONG)) {
            initMachineDirMonitor();
        }
    }
    /**
     * åˆå§‹åŒ–监控目录
     */
    void initMachineDirMonitor() {
        boolean locked = directorLockService.acquireLock();
        if (!locked) {
            log.info("回传接收目录已经被其他部署点位锁定,直接返回");
            return;
        }
        List<Machine> machineList = machineService.list();
        List<String> monitorDirList = new ArrayList<String>();
        machineList.forEach(m -> {
            if (StringUtils.isNotEmpty(m.getProgReceiveDir())) {
                String dir = StringUtils.removeEnd(StringUtils.removeEnd(m.getProgReceiveDir(), "/"), "\\");
                if (!monitorDirList.contains(dir)) {
                    monitorDirList.add(dir);
                }
            }
        });
        for (String dir : monitorDirList) {
            Path dirPath = Paths.get(dir);
            try {
                if(!dirPath.toFile().exists()) {
                    dirPath.toFile().mkdirs();
                }
                directoryWatcher.addDirectory(dirPath,getListener());
            } catch (Exception e) {
                log.error("添加监控目录异常",e);
            }
        }
    }
    FileWatcherService.FileChangeListener getListener() {
        return new MachineFileBackListener(machineBackFileService,ncProgramService);
    }
}
blade-service/blade-mdm/src/main/java/org/springblade/mdm/config/ShutdownHook.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
package org.springblade.mdm.config;
import jakarta.annotation.PreDestroy;
import lombok.AllArgsConstructor;
import org.springblade.mdm.machineback.filewatch.DirectorLockService;
import org.springframework.stereotype.Component;
@AllArgsConstructor
@Component
public class ShutdownHook {
    private final DirectorLockService directorLockService;
    @PreDestroy
    public void onExit() {
        System.out.println("执行退出前清理操作...");
        // 1. å…³é—­æ–‡ä»¶ç›‘控
        // 2. é‡Šæ”¾èµ„源
        // 3. ä¿å­˜çŠ¶æ€
        // 4. é€šçŸ¥å…¶ä»–服务
        directorLockService.releaseLock();
    }
}
blade-service/blade-mdm/src/main/java/org/springblade/mdm/machineback/controller/DirectoryWatcherController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,78 @@
package org.springblade.mdm.machineback.controller;
import org.springblade.mdm.machineback.filewatch.DynamicDirectoryWatcher;
import org.springblade.mdm.machineback.filewatch.FileLockChecker;
import org.springblade.mdm.machineback.filewatch.FileWatcherService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
@RestController
@RequestMapping("/machineback/file")
public class DirectoryWatcherController {
    private final DynamicDirectoryWatcher directoryWatcher;
    @Autowired
    public DirectoryWatcherController(DynamicDirectoryWatcher directoryWatcher) {
        this.directoryWatcher = directoryWatcher;
    }
    @PostMapping("/watch")
    public String watchDirectory(@RequestParam String directoryPath) {
        try {
            Path path = Paths.get(directoryPath);
            directoryWatcher.addDirectory(path, new SimpleFileChangeListener());
            return "Started watching directory: " + directoryPath;
        } catch (Exception e) {
            return "Error: " + e.getMessage();
        }
    }
    @PostMapping("/unwatch")
    public String unwatchDirectory(@RequestParam String directoryPath) {
        try {
            Path path = Paths.get(directoryPath);
            directoryWatcher.removeDirectory(path);
            return "Stopped watching directory: " + directoryPath;
        } catch (Exception e) {
            return "Error: " + e.getMessage();
        }
    }
    @PostMapping("/canlock")
    public String canlock(@RequestParam String filePath) {
        try {
            Path path = Paths.get(filePath);
            boolean comp = FileLockChecker.isFileCompletelyWritten(path);
            return filePath+ " lock: " + comp;
        } catch (Exception e) {
            return "Error: " + e.getMessage();
        }
    }
    private static class SimpleFileChangeListener implements FileWatcherService.FileChangeListener {
        @Override
        public void onFileCreated(Path filePath) {
            System.out.println("File created: " + filePath);
        }
        @Override
        public void onFileModified(Path filePath) {
            System.out.println("File modified: " + filePath);
            //boolean comp = FileLockChecker.isFileCompletelyWritten(filePath);
            boolean comp = false;
            try {
                comp = FileLockChecker.isFileComplete(filePath);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            System.out.println("File FINISHED: " + comp);
        }
        @Override
        public void onFileDeleted(Path filePath) {
            System.out.println("File deleted: " + filePath);
        }
    }
}
blade-service/blade-mdm/src/main/java/org/springblade/mdm/machineback/entity/MachineBackFile.java
@@ -18,6 +18,7 @@
    public static int STATUS_REJECTED = 2;
    private String programId;
    private Long ncProgramId;
    /**
     * ç¡®è®¤æ—¶é—´
     */
blade-service/blade-mdm/src/main/java/org/springblade/mdm/machineback/filewatch/DirectorLockService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,40 @@
package org.springblade.mdm.machineback.filewatch;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import java.io.File;
import java.lang.management.ManagementFactory;
@Slf4j
@AllArgsConstructor
@Service
public class DirectorLockService {
    private final JdbcTemplate jdbcTemplate;
    public boolean acquireLock() {
        int affect = 0;
        try {
            affect = jdbcTemplate.update(
                "INSERT INTO mdm_file_locks (lock_id,locked_by, lock_time) " +
                    "VALUES (1,?, CURRENT_TIMESTAMP)",getInstanceId());
        } catch (Exception e) {
            log.info("文件锁定失败,不进行目录监控",e);
        }
        return affect > 0;
    }
    public void releaseLock() {
        jdbcTemplate.update(
            "DELETE FROM mdm_file_locks");
    }
    private String getInstanceId() {
        // è¿”回当前实例的唯一标识
        return ManagementFactory.getRuntimeMXBean().getName();
    }
}
blade-service/blade-mdm/src/main/java/org/springblade/mdm/machineback/filewatch/DynamicDirectoryWatcher.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
package org.springblade.mdm.machineback.filewatch;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.nio.file.Path;
import java.util.Set;
@Service
public class DynamicDirectoryWatcher {
    private final FileWatcherService fileWatcherService;
    @Autowired
    public DynamicDirectoryWatcher(FileWatcherService fileWatcherService) {
        this.fileWatcherService = fileWatcherService;
    }
    public void addDirectory(Path directory, FileWatcherService.FileChangeListener listener) throws Exception {
        fileWatcherService.watchDirectory(directory, listener);
    }
    public void removeDirectory(Path directory) throws Exception {
        fileWatcherService.stopWatching(directory);
    }
    public Set<Path> getWatchedDirectories() {
        return null;
        //return fileWatcherService.getWatchedDirectories();
    }
}
blade-service/blade-mdm/src/main/java/org/springblade/mdm/machineback/filewatch/FileLockChecker.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
package org.springblade.mdm.machineback.filewatch;
import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.file.Files;
import java.nio.file.Path;
/*
监控文件是否传输完成(使用可否锁定来判断)
 */
public class FileLockChecker {
    public static boolean isFileCompletelyWritten(Path file) {
        try (RandomAccessFile raf = new RandomAccessFile(file.toFile(), "rw");
             FileChannel channel = raf.getChannel()) {
            // å°è¯•获取独占锁
            FileLock lock = channel.tryLock();
            if (lock != null) {
                lock.release();
                // å¦‚果能获取锁,说明文件不再被写入
                return true;
            }
            return false;
        } catch (Exception e) {
            // å¦‚果发生异常,可能文件仍在被写入
            return false;
        }
    }
    /**
     * æ–‡ä»¶æ˜¯å¦ä¼ è¾“完成(采用前后文件大小比对方法)
     * @param file
     * @return
     * @throws IOException
     * @throws InterruptedException
     */
    public static boolean isFileComplete(Path file) throws IOException, InterruptedException {
        long initialSize = Files.size(file);
        Thread.sleep(3000); // ç­‰å¾…1秒
        long currentSize = Files.size(file);
        return initialSize == currentSize;
    }
}
blade-service/blade-mdm/src/main/java/org/springblade/mdm/machineback/filewatch/FileWatcherService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,97 @@
package org.springblade.mdm.machineback.filewatch;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.nio.file.*;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static java.nio.file.StandardWatchEventKinds.*;
@Service
public class FileWatcherService {
    private final ExecutorService executor = Executors.newCachedThreadPool();
    private final Map<Path, WatchService> watchServices = new HashMap<>();
    private final Map<Path, FileChangeListener> listeners = new HashMap<>();
    public interface FileChangeListener {
        void onFileCreated(Path filePath);
        void onFileModified(Path filePath);
        void onFileDeleted(Path filePath);
    }
    public void watchDirectory(Path directory, FileChangeListener listener) throws IOException {
        if (!Files.isDirectory(directory)) {
            throw new IllegalArgumentException("Path must be a directory: " + directory);
        }
        if (watchServices.containsKey(directory)) {
            throw new IllegalStateException("Directory is already being watched: " + directory);
        }
        WatchService watchService = FileSystems.getDefault().newWatchService();
        directory.register(watchService, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE);
        watchServices.put(directory, watchService);
        listeners.put(directory, listener);
        executor.submit(() -> {
            try {
                while (true) {
                    WatchKey key = watchService.take();
                    for (WatchEvent<?> event : key.pollEvents()) {
                        WatchEvent.Kind<?> kind = event.kind();
                        @SuppressWarnings("unchecked")
                        WatchEvent<Path> ev = (WatchEvent<Path>) event;
                        Path fileName = ev.context();
                        Path fullPath = directory.resolve(fileName);
                        FileChangeListener currentListener = listeners.get(directory);
                        if (currentListener == null) break;
                        if (kind == ENTRY_CREATE) {
                            currentListener.onFileCreated(fullPath);
                        } else if (kind == ENTRY_MODIFY) {
                            currentListener.onFileModified(fullPath);
                        } else if (kind == ENTRY_DELETE) {
                            currentListener.onFileDeleted(fullPath);
                        }
                    }
                    boolean valid = key.reset();
                    if (!valid) {
                        break;
                    }
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } catch (ClosedWatchServiceException e) {
                // Service was closed, exit normally
            }
        });
    }
    public void stopWatching(Path directory) throws IOException {
        WatchService watchService = watchServices.remove(directory);
        listeners.remove(directory);
        if (watchService != null) {
            watchService.close();
        }
    }
    public void shutdown() {
        executor.shutdownNow();
        watchServices.values().forEach(watchService -> {
            try {
                watchService.close();
            } catch (IOException e) {
                // Ignore on shutdown
            }
        });
        watchServices.clear();
        listeners.clear();
    }
}
blade-service/blade-mdm/src/main/java/org/springblade/mdm/machineback/filewatch/MachineFileBackListener.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,57 @@
package org.springblade.mdm.machineback.filewatch;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springblade.mdm.machineback.entity.MachineBackFile;
import org.springblade.mdm.machineback.service.MachineBackFileService;
import org.springblade.mdm.program.entity.NcProgram;
import org.springblade.mdm.program.service.NcProgramService;
import java.io.IOException;
import java.nio.file.Path;
@Slf4j
public class MachineFileBackListener  implements FileWatcherService.FileChangeListener{
    private final MachineBackFileService machineBackFileService;
    private final NcProgramService ncProgramService;
    public MachineFileBackListener(MachineBackFileService backService, NcProgramService aNcProgramService) {
        this.machineBackFileService = backService;
        this.ncProgramService = aNcProgramService;
    }
    @Override
    public void onFileCreated(Path filePath) {
        log.info("文件创建{}",filePath);
    }
    @Override
    public void onFileModified(Path filePath) {
        //文件修改
        try {
            if(FileLockChecker.isFileComplete(filePath)){
                log.info("文件传输完成{}",filePath);
                MachineBackFile backFile = new MachineBackFile();
                String programName = filePath.getFileName().toFile().getName();
                NcProgram prog = ncProgramService.getByName(programName);
                if(prog == null){
                    log.warn("更新的文件无法匹配到数控程序,{}",filePath);
                    return;
                }
                backFile.setNcProgramId(prog.getId());
                machineBackFileService.save(backFile);
            }else{
                log.warn("文件传输中,后续再操作{}",filePath);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (InterruptedException e) {
            log.error("sleep出错");
        }
    }
    @Override
    public void onFileDeleted(Path filePath) {
        log.info("文件删除{}",filePath);
    }
}
blade-service/blade-mdm/src/main/java/org/springblade/mdm/program/controller/NcProgramController.java
@@ -121,12 +121,12 @@
        return R.data(approveRecordService.listByNcProgramId(ncProgramId));
    }
    /*
    @PostMapping("/send")
    @Operation(summary = "程序下发", description = "工控网数控程序下发(发送到机床配置的下发目录)")
    @Operation(summary = "程序下发", description = "工控网数控程序下发(发送到机床配置的下发目录),根据id")
    public R<List<NcProgramVO>> send(@Parameter(description="所属节点ID")@RequestParam Long id) {
        return null;//R.data(ncProcessProgRefService.listByProcess(processInstanceId));
    }
    }*/
    @PostMapping("/send-to-machine-by-nodeid")
    @Operation(summary = "程序下发", description = "下发给机床设定的目录")
blade-service/blade-mdm/src/main/java/org/springblade/mdm/program/controller/NcProgramExportDNCController.java
@@ -11,6 +11,7 @@
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.tenant.annotation.NonDS;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.mdm.commons.vo.IdsVO;
import org.springblade.mdm.program.service.NcProgramApprovedService;
import org.springblade.mdm.program.service.NcProgramExportDNCService;
@@ -52,7 +53,8 @@
            throw new ServiceException("未选择文件导出");
        }
        try {
            response.setHeader("Content-Disposition", "attachment; filename=dnc-t.zip");
            String filename = "todncexp-"+ DateUtil.format(DateUtil.now(), "yyyyMMddHHmm")+".zip";
            response.setHeader("Content-Disposition", "attachment; filename="+filename);
            response.setContentType("application/octet-stream");
            ncProgramExportDNCService.exportDnc(vo.getIds(),response.getOutputStream());
        } catch (IOException e) {
blade-service/blade-mdm/src/main/java/org/springblade/mdm/program/mapper/ProcessProgRefMapper.xml
@@ -4,7 +4,7 @@
    <select id="listByProcess" resultType="org.springblade.mdm.program.vo.NcProgramVO">
        select p.id,p.name,url,code from mdm_process_prog_ref r join mdm_nc_program p on r.nc_program_id=p.id
        select p.id,p.name,p.machine_code,url,code from mdm_process_prog_ref r join mdm_nc_program p on r.nc_program_id=p.id
        where process_instance_id=#{processInstanceId} and p.is_deleted=0
    </select>
</mapper>
blade-service/blade-mdm/src/main/java/org/springblade/mdm/program/service/MdmProgramImportService.java
@@ -238,25 +238,25 @@
                            JSONArray jsonArray = JSONArray.parseArray(jsonStr);
                            for(int i=0;i<jsonArray.size();i++){
                                JSONObject jsonObject = jsonArray.getJSONObject(i);
                                NcProgram d = new NcProgram();
                                d.setId(jsonObject.getLong("id"));
                                d.setName(jsonObject.getString("name"));
                                NcProgram prog = new NcProgram();
                                prog.setId(jsonObject.getLong("id"));
                                prog.setName(jsonObject.getString("name"));
                                d.setCode(jsonObject.getString("code"));
                                d.setDescription(jsonObject.getString("description"));
                                d.setCategory(jsonObject.getString("category"));
                                d.setBindNcNodeId(jsonObject.getLong("bindNcNodeId"));
                                d.setIsLastEdition(jsonObject.getInteger("isLastEdition"));
                                d.setIsLocked(jsonObject.getInteger("isLocked"));
                                d.setIsTest(jsonObject.getInteger("isTest"));
                                d.setMachineCode(jsonObject.getString("machineCode"));
                                d.setNcNodeId(jsonObject.getLong("ncNodeId"));
                                d.setDrawingNo(jsonObject.getString("drawingNo"));
                                d.setProcessEdition(jsonObject.getString("processEdition"));
                                prog.setCode(jsonObject.getString("code"));
                                prog.setDescription(jsonObject.getString("description"));
                                prog.setCategory(jsonObject.getString("category"));
                                prog.setBindNcNodeId(jsonObject.getLong("bindNcNodeId"));
                                prog.setIsLastEdition(jsonObject.getInteger("isLastEdition"));
                                prog.setIsLocked(jsonObject.getInteger("isLocked"));
                                prog.setIsTest(jsonObject.getInteger("isTest"));
                                prog.setMachineCode(jsonObject.getString("machineCode"));
                                prog.setNcNodeId(jsonObject.getLong("ncNodeId"));
                                prog.setDrawingNo(jsonObject.getString("drawingNo"));
                                prog.setProcessEdition(jsonObject.getString("processEdition"));
                                setBaseProperties(d,jsonObject);
                                setBaseProperties(prog,jsonObject);
                                progList.add(d);
                                progList.add(prog);
                            }
                        }
@@ -296,6 +296,7 @@
                                record.setUserNickname(jsonObject.getString("userNickname"));
                                record.setOperateResult(jsonObject.getString("operateResult"));
                                record.setOperateTime(jsonObject.getDate("operateTime"));
                                record.setComment(jsonObject.getString("comment"));
                                setBaseProperties(record,jsonObject);
                                recordList.add(record);
blade-service/blade-mdm/src/main/java/org/springblade/mdm/program/service/NcProgramExportDNCService.java
@@ -130,6 +130,7 @@
            recObj.put("code", program.getCode());
            recObj.put("ossName",program.getOssName());
            recObj.put("isTextFile",program.getIsTextFile());
            recObj.put("isLastEdition",program.getIsLastEdition());
            recObj.put("category",program.getCategory());
            recObj.put("description",program.getDescription());
            recObj.put("name",program.getName());
@@ -196,11 +197,11 @@
        ArrayList<Long> exportNodeIdList     = new ArrayList<>();
        for(NcProgram program : programs){
            JSONObject recObj = new JSONObject();
            if(!exportNodeIdList.contains(program.getNcNodeId())){
                exportNodeIdList.add(program.getNcNodeId());
            //JSONObject recObj = new JSONObject();
            if(!exportNodeIdList.contains(program.getBindNcNodeId())){
                exportNodeIdList.add(program.getBindNcNodeId());
            }
            NcNode ncNode = ncNodeService.getById(program.getNcNodeId());
            NcNode ncNode = ncNodeService.getById(program.getBindNcNodeId());//从绑定的节点本身开始导出
            if(StringUtils.isNotEmpty(ncNode.getParentIds())){
                List<Long> pids = Func.toLongList(ncNode.getParentIds());
blade-service/blade-mdm/src/main/java/org/springblade/mdm/program/service/NcProgramService.java
@@ -159,6 +159,10 @@
        node.setDrawingNo(uploadVO.getDrawingNo());
        node.setProcessName(uploadVO.getProcessName());
        NcNode parentNode = nodeService.getById(uploadVO.getNodeId());
        node.setParentIds(parentNode.getParentIds()+","+uploadVO.getNodeId());
        //uploadVO.getre
        //node.setDescription(uploadVO.getDrawingNo());
        nodeService.save(node);
        prog.setBindNcNodeId(node.getId());
@@ -318,4 +322,17 @@
        return progOpt.orElse(null);
    }
    /**
     * æ ¹æ®ç¨‹åºåç§°èŽ·å–æœ€æ–°çš„ç¨‹åºæ•°æ®
     * @param name ç¨‹åºåç§°
     * @return
     */
    public NcProgram getByName(String name) {LambdaQueryWrapper<NcProgram> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(NcProgram::getName, name);
        wrapper.eq(NcProgram::getIsLastEdition,1);
        Optional<NcProgram> progOpt = this.getOneOpt(wrapper);
        return progOpt.orElse(null);
    }
}