From 03e8aca3ad6201c0d74e00d4c8d7367cdaaa54f9 Mon Sep 17 00:00:00 2001 From: Jay <csj123456> Date: 星期五, 01 十一月 2024 11:49:51 +0800 Subject: [PATCH] tag新增导入导出功能 --- iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/http/entity/HttpTagEntity.java | 2 iailab-framework/iailab-common-excel/src/main/java/com/iailab/framework/excel/core/util/ExcelUtils.java | 15 iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/tag/vo/TagExportExcelVO.java | 55 ++ iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/service/impl/ChannelModbusTagServiceImpl.java | 53 ++ iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/service/ChannelModbusTagService.java | 13 iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/http/service/HttpTagService.java | 4 iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/service/impl/ChannelOPCDATagServiceImpl.java | 54 ++ iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/vo/OpcDaTagExportExcelVO.java | 51 ++ iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/vo/OpcUaTagRespVO.java | 2 iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/kio/controller/admin/ChannelKioTagController.java | 52 ++ iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/controller/admin/ChannelModbusTagController.java | 60 +++ iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/vo/OpcDaTagRespVO.java | 2 iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/http/service/impl/HttpTagServiceImpl.java | 52 ++ iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/kio/entity/ChannelKioTagEntity.java | 2 iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/kio/vo/KioTagRespVO.java | 2 iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/service/ChannelOPCDATagService.java | 7 iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/vo/OpcDaTagImportExcelVO.java | 53 ++ iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/controller/admin/ChannelOPCUATagController.java | 65 ++ iailab-framework/iailab-common-excel/src/main/java/com/iailab/framework/excel/core/handler/SelectSheetWriteHandler.java | 77 ++- iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/entity/ChannelModBusTagEntity.java | 2 iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/vo/ModBusTagImportExcelVO.java | 31 + iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/entity/ChannelOPCDATagEntity.java | 2 iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/vo/OpcUaTagExportExcelVO.java | 59 +++ iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/entity/ChannelOPCUATagEntity.java | 2 iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/tag/vo/TagImportExcelVO.java | 56 ++ iailab-module-data/iailab-module-data-api/src/main/java/com/iailab/module/data/enums/ErrorCodeConstants.java | 5 iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/http/controller/admin/HttpTagController.java | 53 ++ iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/kio/service/impl/ChannelKioTagServiceImpl.java | 52 ++ iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/http/vo/HttpTagRespVO.java | 2 iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/vo/ModBusTagExportExcelVO.java | 28 + iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/service/impl/ChannelOPCUATagServiceImpl.java | 54 ++ iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/kio/service/ChannelKioTagService.java | 5 iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/vo/ModBusTagRespVO.java | 2 iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/tag/vo/TagImportRespVO.java | 26 + iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/service/ChannelOPCUATagService.java | 4 iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/controller/admin/ChannelOPCDATagController.java | 64 +++ iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/vo/OpcUaTagImportExcelVO.java | 61 +++ 37 files changed, 1,046 insertions(+), 83 deletions(-) diff --git a/iailab-framework/iailab-common-excel/src/main/java/com/iailab/framework/excel/core/handler/SelectSheetWriteHandler.java b/iailab-framework/iailab-common-excel/src/main/java/com/iailab/framework/excel/core/handler/SelectSheetWriteHandler.java index 7efdc0a..9e5e3df 100644 --- a/iailab-framework/iailab-common-excel/src/main/java/com/iailab/framework/excel/core/handler/SelectSheetWriteHandler.java +++ b/iailab-framework/iailab-common-excel/src/main/java/com/iailab/framework/excel/core/handler/SelectSheetWriteHandler.java @@ -7,24 +7,21 @@ import cn.hutool.core.util.StrUtil; import cn.hutool.extra.spring.SpringUtil; import cn.hutool.poi.excel.ExcelUtil; -import com.iailab.framework.common.core.KeyValue; -import com.iailab.framework.dict.core.DictFrameworkUtils; -import com.iailab.framework.excel.core.annotations.ExcelColumnSelect; -import com.iailab.framework.excel.core.function.ExcelColumnSelectFunction; import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.write.handler.SheetWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; +import com.iailab.framework.common.core.KeyValue; +import com.iailab.framework.dict.core.DictFrameworkUtils; +import com.iailab.framework.excel.core.annotations.ExcelColumnSelect; +import com.iailab.framework.excel.core.function.ExcelColumnSelectFunction; import lombok.extern.slf4j.Slf4j; import org.apache.poi.hssf.usermodel.HSSFDataValidation; import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.CellRangeAddressList; import java.lang.reflect.Field; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import static com.iailab.framework.common.util.collection.CollectionUtils.convertList; @@ -38,7 +35,6 @@ /** * 数据起始行从 0 开始 - * * 约定:本项目第一行有标题所以从 1 开始如果您的 Excel 有多行标题请自行更改 */ public static final int FIRST_ROW = 1; @@ -54,22 +50,29 @@ */ private final Map<Integer, List<String>> selectMap = new HashMap<>(); - public SelectSheetWriteHandler(Class<?> head) { + private static Boolean ifSetSelect; + + public SelectSheetWriteHandler(Class<?> head, Boolean selectFlag) { + ifSetSelect = selectFlag; // 加载下拉数据获取接口 Map<String, ExcelColumnSelectFunction> beansMap = SpringUtil.getBeanFactory().getBeansOfType(ExcelColumnSelectFunction.class); if (MapUtil.isEmpty(beansMap)) { return; } - + List<Field> fields = new ArrayList<>(); + for (Class<?> c = head; c != null; c = c.getSuperclass()) { + Collections.addAll(fields, c.getDeclaredFields()); + } // 解析下拉数据 int colIndex = 0; - for (Field field : head.getDeclaredFields()) { + for (Field field : fields) { if (field.isAnnotationPresent(ExcelColumnSelect.class)) { ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class); if (excelProperty != null && excelProperty.index() != -1) { - colIndex = excelProperty.index(); + getSelectDataList(excelProperty.index(), field); + }else{ + getSelectDataList(colIndex, field); } - getSelectDataList(colIndex, field); } colIndex++; } @@ -106,27 +109,45 @@ if (CollUtil.isEmpty(selectMap)) { return; } - // 1. 获取相应操作对象 DataValidationHelper helper = writeSheetHolder.getSheet().getDataValidationHelper(); // 需要设置下拉框的 sheet 页的数据验证助手 Workbook workbook = writeWorkbookHolder.getWorkbook(); // 获得工作簿 List<KeyValue<Integer, List<String>>> keyValues = convertList(selectMap.entrySet(), entry -> new KeyValue<>(entry.getKey(), entry.getValue())); keyValues.sort(Comparator.comparing(item -> item.getValue().size())); // 升序不然创建下拉会报错 - - // 2. 创建数据字典的 sheet 页 - Sheet dictSheet = workbook.createSheet(DICT_SHEET_NAME); - for (KeyValue<Integer, List<String>> keyValue : keyValues) { - int rowLength = keyValue.getValue().size(); - // 2.1 设置字典 sheet 页的值,每一列一个字典项 - for (int i = 0; i < rowLength; i++) { - Row row = dictSheet.getRow(i); - if (row == null) { - row = dictSheet.createRow(i); + if (ifSetSelect){ + for (KeyValue<Integer, List<String>> keyValue : keyValues) { + /*起始行、终止行、起始列、终止列 起始行为1即表示表头不设置**/ + CellRangeAddressList addressList = new CellRangeAddressList(FIRST_ROW, LAST_ROW, keyValue.getKey(), keyValue.getKey()); + /*设置下拉框数据**/ + DataValidationConstraint constraint = helper.createExplicitListConstraint(keyValue.getValue().toArray(new String[0])); + DataValidation dataValidation = helper.createValidation(constraint, addressList); + if (dataValidation instanceof HSSFDataValidation) { + dataValidation.setSuppressDropDownArrow(false); + } else { + dataValidation.setSuppressDropDownArrow(true); + dataValidation.setShowErrorBox(true); } - row.createCell(keyValue.getKey()).setCellValue(keyValue.getValue().get(i)); + // 2.2 阻止输入非下拉框的值 + dataValidation.setErrorStyle(DataValidation.ErrorStyle.STOP); + dataValidation.createErrorBox("提示", "此值不存在于下拉选择中!"); + writeSheetHolder.getSheet().addValidationData(dataValidation); } - // 2.2 设置单元格下拉选择 - setColumnSelect(writeSheetHolder, workbook, helper, keyValue); + }else{ + // 2. 创建数据字典的 sheet 页 + Sheet dictSheet = workbook.createSheet(DICT_SHEET_NAME); + for (KeyValue<Integer, List<String>> keyValue : keyValues) { + int rowLength = keyValue.getValue().size(); + // 2.1 设置字典 sheet 页的值,每一列一部字典项 + for (int i = 0; i < rowLength; i++) { + Row row = dictSheet.getRow(i); + if (row == null) { + row = dictSheet.createRow(i); + } + row.createCell(keyValue.getKey()).setCellValue(keyValue.getValue().get(i)); + } + // 2.2 设置单元格下拉选择 + setColumnSelect(writeSheetHolder, workbook, helper, keyValue); + } } } diff --git a/iailab-framework/iailab-common-excel/src/main/java/com/iailab/framework/excel/core/util/ExcelUtils.java b/iailab-framework/iailab-common-excel/src/main/java/com/iailab/framework/excel/core/util/ExcelUtils.java index 0eb35ac..f16434e 100644 --- a/iailab-framework/iailab-common-excel/src/main/java/com/iailab/framework/excel/core/util/ExcelUtils.java +++ b/iailab-framework/iailab-common-excel/src/main/java/com/iailab/framework/excel/core/util/ExcelUtils.java @@ -36,7 +36,7 @@ EasyExcel.write(response.getOutputStream(), head) .autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理 .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 基于 column 长度,自动适配。最大 255 宽度 - .registerWriteHandler(new SelectSheetWriteHandler(head)) // 基于固定 sheet 实现下拉框 + .registerWriteHandler(new SelectSheetWriteHandler(head,false)) // 基于固定 sheet 实现下拉框 .registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度 .sheet(sheetName).doWrite(data); // 设置 header 和 contentType。写在最后的原因是,避免报错时,响应 contentType 已经被修改了 @@ -50,4 +50,17 @@ .doReadAllSync(); } + public static <T> void write(HttpServletResponse response, String filename, String sheetName, + Class<T> head, List<T> data, boolean selectFlag) throws IOException { + // 输出 Excel + EasyExcel.write(response.getOutputStream(), head) + .autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理 + .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 基于 column 长度,自动适配。最大 255 宽度 + .registerWriteHandler(new SelectSheetWriteHandler(head,selectFlag)) // 基于固定 sheet 实现下拉框 + .registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度 + .sheet(sheetName).doWrite(data); + // 设置 header 和 contentType。写在最后的原因是,避免报错时,响应 contentType 已经被修改了 + response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, StandardCharsets.UTF_8.name())); + response.setContentType("application/vnd.ms-excel;charset=UTF-8"); + } } diff --git a/iailab-module-data/iailab-module-data-api/src/main/java/com/iailab/module/data/enums/ErrorCodeConstants.java b/iailab-module-data/iailab-module-data-api/src/main/java/com/iailab/module/data/enums/ErrorCodeConstants.java index 59b3717..aa886b6 100644 --- a/iailab-module-data/iailab-module-data-api/src/main/java/com/iailab/module/data/enums/ErrorCodeConstants.java +++ b/iailab-module-data/iailab-module-data-api/src/main/java/com/iailab/module/data/enums/ErrorCodeConstants.java @@ -7,4 +7,9 @@ ErrorCode POINT_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_001_001_001, "导入测点数据不能为空!"); ErrorCode POINT_NOT_EXISTS = new ErrorCode(1_002_001_000, "测点配置不存在"); ErrorCode POINT_EXISTS = new ErrorCode(1_002_002_000, "测点配置已经存在"); + + ErrorCode TAG_IMPORT_LIST_IS_EMPTY = new ErrorCode(2_001_001_001, "导入Tag数据不能为空!"); + + ErrorCode TAG_EXISTS = new ErrorCode(2_002_002_001, "Tag已经存在"); + } diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/http/controller/admin/HttpTagController.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/http/controller/admin/HttpTagController.java index c014183..ceeac7b 100644 --- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/http/controller/admin/HttpTagController.java +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/http/controller/admin/HttpTagController.java @@ -1,21 +1,37 @@ package com.iailab.module.data.channel.http.controller.admin; +import com.iailab.framework.apilog.core.annotation.ApiAccessLog; import com.iailab.framework.common.pojo.CommonResult; +import com.iailab.framework.common.pojo.PageParam; import com.iailab.framework.common.pojo.PageResult; import com.iailab.framework.common.util.object.BeanUtils; +import com.iailab.framework.common.util.object.ConvertUtils; +import com.iailab.framework.excel.core.util.ExcelUtils; import com.iailab.module.data.channel.http.entity.HttpTagEntity; import com.iailab.module.data.channel.http.service.HttpTagService; import com.iailab.module.data.channel.http.vo.HttpTagPageReqVO; import com.iailab.module.data.channel.http.vo.HttpTagRespVO; +import com.iailab.module.data.channel.tag.vo.TagExportExcelVO; +import com.iailab.module.data.channel.tag.vo.TagImportExcelVO; +import com.iailab.module.data.channel.tag.vo.TagImportRespVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; +import java.io.IOException; +import java.util.Collections; import java.util.Date; import java.util.List; import java.util.UUID; +import static com.iailab.framework.apilog.core.enums.OperateTypeEnum.EXPORT; import static com.iailab.framework.common.pojo.CommonResult.success; @@ -75,4 +91,41 @@ tagService.delete(id); return success(true); } + + @GetMapping("/export") + @Operation(summary = "导出modbus tag列表") + @PreAuthorize("@ss.hasPermission('data:channel-http-tag:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportPointList(@Validated HttpTagPageReqVO reqVO, HttpServletResponse response) throws IOException { + reqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + PageResult<HttpTagEntity> page = tagService.queryPage(reqVO); + List<TagExportExcelVO> list = ConvertUtils.sourceToTarget(page.getList(), TagExportExcelVO.class); + ExcelUtils.write(response, "tag列表.xls", "数据", TagExportExcelVO.class, list, true); + } + + @GetMapping("/get-import-template") + @Operation(summary = "获得tag导入模板") + public void importTemplate(HttpServletResponse response) throws IOException { + // 手动创建导出 demo + List<TagImportExcelVO> list = Collections.singletonList( + TagImportExcelVO.builder().tagName("Tag名称").tagDesc("Tag描述").dataType("String").enabled(1) + .build() + ); + // 输出 + ExcelUtils.write(response, "tag导入模板.xls", "tag列表", TagImportExcelVO.class, list,true); + } + + @PostMapping("/import") + @Operation(summary = "导入tag") + @Parameters({ + @Parameter(name = "file", description = "Excel 文件", required = true), + @Parameter(name = "updateSupport", description = "是否支持更新,默认为 false", example = "true") + }) + @PreAuthorize("@ss.hasPermission('data:channel-http-tag:import')") + public CommonResult<TagImportRespVO> importExcel(@RequestParam("file") MultipartFile file, + @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport, + @RequestParam("device") String device) throws Exception { + List<TagImportExcelVO> list = ExcelUtils.read(file, TagImportExcelVO.class); + return success(tagService.importHttpTagList(list, updateSupport, device)); + } } diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/http/entity/HttpTagEntity.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/http/entity/HttpTagEntity.java index 4ab81e1..4df9344 100644 --- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/http/entity/HttpTagEntity.java +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/http/entity/HttpTagEntity.java @@ -49,7 +49,7 @@ /** * 是否启用 */ - private Boolean enabled; + private Integer enabled; /** * 创建时间 diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/http/service/HttpTagService.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/http/service/HttpTagService.java index 2cd7521..9adccbb 100644 --- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/http/service/HttpTagService.java +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/http/service/HttpTagService.java @@ -3,6 +3,8 @@ import com.iailab.framework.common.pojo.PageResult; import com.iailab.module.data.channel.http.entity.HttpTagEntity; import com.iailab.module.data.channel.http.vo.HttpTagPageReqVO; +import com.iailab.module.data.channel.tag.vo.TagImportExcelVO; +import com.iailab.module.data.channel.tag.vo.TagImportRespVO; import java.util.List; import java.util.Map; @@ -23,4 +25,6 @@ List<HttpTagEntity> selectList(Map<String, Object> params); List<HttpTagEntity> getApiId(String code); + + TagImportRespVO importHttpTagList(List<TagImportExcelVO> importTags, boolean isUpdateSupport, String apiId); } diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/http/service/impl/HttpTagServiceImpl.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/http/service/impl/HttpTagServiceImpl.java index 9825c91..841706d 100644 --- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/http/service/impl/HttpTagServiceImpl.java +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/http/service/impl/HttpTagServiceImpl.java @@ -1,20 +1,28 @@ package com.iailab.module.data.channel.http.service.impl; +import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.iailab.framework.common.pojo.PageResult; +import com.iailab.framework.common.util.object.BeanUtils; +import com.iailab.framework.common.util.object.ConvertUtils; import com.iailab.module.data.channel.http.dao.HttpTagDao; import com.iailab.module.data.channel.http.entity.HttpApiEntity; import com.iailab.module.data.channel.http.entity.HttpTagEntity; import com.iailab.module.data.channel.http.service.HttpApiService; import com.iailab.module.data.channel.http.service.HttpTagService; import com.iailab.module.data.channel.http.vo.HttpTagPageReqVO; +import com.iailab.module.data.channel.tag.vo.TagImportExcelVO; +import com.iailab.module.data.channel.tag.vo.TagImportRespVO; +import com.iailab.module.data.common.enums.CommonConstant; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import javax.annotation.Resource; -import java.util.List; -import java.util.Map; +import java.util.*; + +import static com.iailab.framework.common.exception.util.ServiceExceptionUtil.exception; +import static com.iailab.module.data.enums.ErrorCodeConstants.*; @Slf4j @Service @@ -73,4 +81,44 @@ .orderByDesc("create_time")); } + @Override + public TagImportRespVO importHttpTagList(List<TagImportExcelVO> importTags, boolean isUpdateSupport, String apiId) { + // 1.1 参数校验 + if (CollUtil.isEmpty(importTags)) { + throw exception(TAG_IMPORT_LIST_IS_EMPTY); + } + // 2. 遍历,逐个创建 or 更新 + TagImportRespVO respVO = TagImportRespVO.builder().createTagNames(new ArrayList<>()) + .updateTagNames(new ArrayList<>()).failureTagNames(new LinkedHashMap<>()).build(); + importTags.forEach(importTag -> { + // 判断如果不存在,再进行插入 + HttpTagEntity existTag = httpTagDao.selectOne(new QueryWrapper<HttpTagEntity>() + .eq("api_id", apiId) + .eq("tag_name",importTag.getTagName())); + if (existTag == null) { + HttpTagEntity httpTagEntity = ConvertUtils.sourceToTarget(importTag, HttpTagEntity.class); + httpTagEntity.setId(UUID.randomUUID().toString()); + httpTagEntity.setEnabled(CommonConstant.IS_ENABLE); + httpTagEntity.setApiId(apiId); + httpTagEntity.setCreateTime(new Date()); + httpTagDao.insert(httpTagEntity); + + respVO.getCreateTagNames().add(httpTagEntity.getTagName()); + return; + } + + // 如果存在,判断是否允许更新 + if (!isUpdateSupport) { + respVO.getFailureTagNames().put(importTag.getTagName(), TAG_EXISTS.getMsg()); + return; + } + + HttpTagEntity updateTag = BeanUtils.toBean(importTag, HttpTagEntity.class); + updateTag.setId(existTag.getId()); + baseMapper.updateById(updateTag); + respVO.getUpdateTagNames().add(importTag.getTagName()); + }); + return respVO; + } + } diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/http/vo/HttpTagRespVO.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/http/vo/HttpTagRespVO.java index c8a3d5a..fbac91a 100644 --- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/http/vo/HttpTagRespVO.java +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/http/vo/HttpTagRespVO.java @@ -39,7 +39,7 @@ @Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") @ExcelProperty("是否启用") - private Boolean enabled; + private Integer enabled; @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") @ExcelProperty("创建时间") diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/kio/controller/admin/ChannelKioTagController.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/kio/controller/admin/ChannelKioTagController.java index 6122d90..b4ed847 100644 --- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/kio/controller/admin/ChannelKioTagController.java +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/kio/controller/admin/ChannelKioTagController.java @@ -1,21 +1,37 @@ package com.iailab.module.data.channel.kio.controller.admin; +import com.iailab.framework.apilog.core.annotation.ApiAccessLog; import com.iailab.framework.common.pojo.CommonResult; +import com.iailab.framework.common.pojo.PageParam; import com.iailab.framework.common.pojo.PageResult; import com.iailab.framework.common.util.object.BeanUtils; +import com.iailab.framework.common.util.object.ConvertUtils; +import com.iailab.framework.excel.core.util.ExcelUtils; import com.iailab.module.data.channel.kio.entity.ChannelKioTagEntity; import com.iailab.module.data.channel.kio.service.ChannelKioTagService; import com.iailab.module.data.channel.kio.vo.KioTagPageReqVO; import com.iailab.module.data.channel.kio.vo.KioTagRespVO; +import com.iailab.module.data.channel.tag.vo.TagExportExcelVO; +import com.iailab.module.data.channel.tag.vo.TagImportExcelVO; +import com.iailab.module.data.channel.tag.vo.TagImportRespVO; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; +import java.io.IOException; +import java.util.Collections; import java.util.Date; +import java.util.List; import java.util.UUID; +import static com.iailab.framework.apilog.core.enums.OperateTypeEnum.EXPORT; import static com.iailab.framework.common.pojo.CommonResult.success; /** @@ -70,4 +86,40 @@ return success(true); } + @GetMapping("/export") + @Operation(summary = "导出modbus tag列表") + @PreAuthorize("@ss.hasPermission('data:channel-kio-tag:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportPointList(@Validated KioTagPageReqVO reqVO, HttpServletResponse response) throws IOException { + reqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + PageResult<ChannelKioTagEntity> page = channelKioTagService.queryPage(reqVO); + List<TagExportExcelVO> list = ConvertUtils.sourceToTarget(page.getList(), TagExportExcelVO.class); + ExcelUtils.write(response, "tag列表.xls", "数据", TagExportExcelVO.class, list, true); + } + + @GetMapping("/get-import-template") + @Operation(summary = "获得tag导入模板") + public void importTemplate(HttpServletResponse response) throws IOException { + // 手动创建导出 demo + List<TagImportExcelVO> list = Collections.singletonList( + TagImportExcelVO.builder().tagName("Tag名称").tagDesc("Tag描述").dataType("String").enabled(1) + .build() + ); + // 输出 + ExcelUtils.write(response, "tag导入模板.xls", "tag列表", TagImportExcelVO.class, list,true); + } + + @PostMapping("/import") + @Operation(summary = "导入tag") + @Parameters({ + @Parameter(name = "file", description = "Excel 文件", required = true), + @Parameter(name = "updateSupport", description = "是否支持更新,默认为 false", example = "true") + }) + @PreAuthorize("@ss.hasPermission('data:channel-kio-tag:import')") + public CommonResult<TagImportRespVO> importExcel(@RequestParam("file") MultipartFile file, + @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport, + @RequestParam("device") String device) throws Exception { + List<TagImportExcelVO> list = ExcelUtils.read(file, TagImportExcelVO.class); + return success(channelKioTagService.importKioTagList(list, updateSupport, device)); + } } diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/kio/entity/ChannelKioTagEntity.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/kio/entity/ChannelKioTagEntity.java index 1a89990..3ab3f14 100644 --- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/kio/entity/ChannelKioTagEntity.java +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/kio/entity/ChannelKioTagEntity.java @@ -50,7 +50,7 @@ /** * 是否可以tag */ - private Boolean enabled; + private Integer enabled; /** * 关联设备 diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/kio/service/ChannelKioTagService.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/kio/service/ChannelKioTagService.java index 179fbbe..fdc91f0 100644 --- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/kio/service/ChannelKioTagService.java +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/kio/service/ChannelKioTagService.java @@ -3,6 +3,8 @@ import com.iailab.framework.common.pojo.PageResult; import com.iailab.module.data.channel.kio.entity.ChannelKioTagEntity; import com.iailab.module.data.channel.kio.vo.KioTagPageReqVO; +import com.iailab.module.data.channel.tag.vo.TagImportExcelVO; +import com.iailab.module.data.channel.tag.vo.TagImportRespVO; import java.util.List; @@ -28,4 +30,7 @@ ChannelKioTagEntity getByTagName(String tagName); void deleteByDeviceName(String name); + + TagImportRespVO importKioTagList(List<TagImportExcelVO> importTags, boolean isUpdateSupport, String device); + } \ No newline at end of file diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/kio/service/impl/ChannelKioTagServiceImpl.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/kio/service/impl/ChannelKioTagServiceImpl.java index de8c47d..bb8034b 100644 --- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/kio/service/impl/ChannelKioTagServiceImpl.java +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/kio/service/impl/ChannelKioTagServiceImpl.java @@ -1,18 +1,26 @@ package com.iailab.module.data.channel.kio.service.impl; +import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.iailab.framework.common.pojo.PageResult; +import com.iailab.framework.common.util.object.BeanUtils; +import com.iailab.framework.common.util.object.ConvertUtils; import com.iailab.module.data.channel.kio.dao.ChannelKioTagDao; import com.iailab.module.data.channel.kio.entity.ChannelKioTagEntity; import com.iailab.module.data.channel.kio.service.ChannelKioTagService; import com.iailab.module.data.channel.kio.vo.KioTagPageReqVO; +import com.iailab.module.data.channel.tag.vo.TagImportExcelVO; +import com.iailab.module.data.channel.tag.vo.TagImportRespVO; +import com.iailab.module.data.common.enums.CommonConstant; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import javax.annotation.Resource; -import java.util.Date; -import java.util.List; +import java.util.*; + +import static com.iailab.framework.common.exception.util.ServiceExceptionUtil.exception; +import static com.iailab.module.data.enums.ErrorCodeConstants.*; /** * @author lirm @@ -71,4 +79,44 @@ public void deleteByDeviceName(String name) { channelKioTagDao.delete(new QueryWrapper<ChannelKioTagEntity>().eq("device",name)); } + + @Override + public TagImportRespVO importKioTagList(List<TagImportExcelVO> importTags, boolean isUpdateSupport, String device) { + // 1.1 参数校验 + if (CollUtil.isEmpty(importTags)) { + throw exception(TAG_IMPORT_LIST_IS_EMPTY); + } + // 2. 遍历,逐个创建 or 更新 + TagImportRespVO respVO = TagImportRespVO.builder().createTagNames(new ArrayList<>()) + .updateTagNames(new ArrayList<>()).failureTagNames(new LinkedHashMap<>()).build(); + importTags.forEach(importTag -> { + // 判断如果不存在,再进行插入 + ChannelKioTagEntity existTag = channelKioTagDao.selectOne(new QueryWrapper<ChannelKioTagEntity>() + .eq("device", device) + .eq("tag_name",importTag.getTagName())); + if (existTag == null) { + ChannelKioTagEntity channelKioTagEntity = ConvertUtils.sourceToTarget(importTag, ChannelKioTagEntity.class); + channelKioTagEntity.setId(UUID.randomUUID().toString()); + channelKioTagEntity.setEnabled(CommonConstant.IS_ENABLE); + channelKioTagEntity.setDevice(device); + channelKioTagEntity.setCreateTime(new Date()); + channelKioTagDao.insert(channelKioTagEntity); + + respVO.getCreateTagNames().add(channelKioTagEntity.getTagName()); + return; + } + + // 如果存在,判断是否允许更新 + if (!isUpdateSupport) { + respVO.getFailureTagNames().put(importTag.getTagName(), TAG_EXISTS.getMsg()); + return; + } + + ChannelKioTagEntity updateTag = BeanUtils.toBean(importTag, ChannelKioTagEntity.class); + updateTag.setId(existTag.getId()); + baseMapper.updateById(updateTag); + respVO.getUpdateTagNames().add(importTag.getTagName()); + }); + return respVO; + } } \ No newline at end of file diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/kio/vo/KioTagRespVO.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/kio/vo/KioTagRespVO.java index 35fb5eb..a1db769 100644 --- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/kio/vo/KioTagRespVO.java +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/kio/vo/KioTagRespVO.java @@ -39,7 +39,7 @@ @Schema(description = "是否可以tag", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") @ExcelProperty("是否可以tag") - private Boolean enabled; + private Integer enabled; @Schema(description = "关联设备", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") @ExcelProperty("关联设备") diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/controller/admin/ChannelModbusTagController.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/controller/admin/ChannelModbusTagController.java index 38b5a98..16f7080 100644 --- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/controller/admin/ChannelModbusTagController.java +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/controller/admin/ChannelModbusTagController.java @@ -1,20 +1,37 @@ package com.iailab.module.data.channel.modbus.controller.admin; +import com.iailab.framework.apilog.core.annotation.ApiAccessLog; import com.iailab.framework.common.pojo.CommonResult; +import com.iailab.framework.common.pojo.PageParam; import com.iailab.framework.common.pojo.PageResult; import com.iailab.framework.common.util.object.BeanUtils; -import com.iailab.module.data.channel.modbus.entity.ChannelModBusTagEntity; +import com.iailab.framework.common.util.object.ConvertUtils; +import com.iailab.framework.excel.core.util.ExcelUtils; import com.iailab.module.data.channel.modbus.entity.ChannelModBusTagEntity; import com.iailab.module.data.channel.modbus.service.ChannelModbusTagService; +import com.iailab.module.data.channel.modbus.vo.ModBusTagExportExcelVO; +import com.iailab.module.data.channel.modbus.vo.ModBusTagImportExcelVO; import com.iailab.module.data.channel.modbus.vo.ModBusTagPageReqVO; import com.iailab.module.data.channel.modbus.vo.ModBusTagRespVO; +import com.iailab.module.data.channel.tag.vo.TagImportRespVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; +import java.io.IOException; +import java.util.Collections; import java.util.Date; +import java.util.List; import java.util.UUID; +import static com.iailab.framework.apilog.core.enums.OperateTypeEnum.EXPORT; import static com.iailab.framework.common.pojo.CommonResult.success; /** @@ -31,7 +48,6 @@ @GetMapping("/page") public CommonResult<PageResult<ModBusTagRespVO>> list(@Valid ModBusTagPageReqVO reqVO) { PageResult<ChannelModBusTagEntity> page = channelModbusTagService.queryPage(reqVO); - return success(BeanUtils.toBean(page, ModBusTagRespVO.class)); } @@ -82,4 +98,44 @@ channelModbusTagService.delete(id); return success(true); } + + @GetMapping("/export") + @Operation(summary = "导出modbus tag列表") + @PreAuthorize("@ss.hasPermission('data:channel-modbus-tag:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportPointList(@Validated ModBusTagPageReqVO reqVO, HttpServletResponse response) throws IOException { + reqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + PageResult<ChannelModBusTagEntity> page = channelModbusTagService.queryPage(reqVO); + + List<ModBusTagExportExcelVO> list = ConvertUtils.sourceToTarget(page.getList(), ModBusTagExportExcelVO.class); + ExcelUtils.write(response, "tag列表.xls", "数据", ModBusTagExportExcelVO.class, list, true); + } + + + @GetMapping("/get-import-template") + @Operation(summary = "获得tag导入模板") + public void importTemplate(HttpServletResponse response) throws IOException { + // 手动创建导出 demo + List<ModBusTagImportExcelVO> list = Collections.singletonList( + ModBusTagImportExcelVO.builder().tagName("Tag名称").tagDesc("Tag描述").dataType("String"). + address("123").format("1").samplingRate(1000).enabled(1) + .build() + ); + // 输出 + ExcelUtils.write(response, "tag导入模板.xls", "tag列表", ModBusTagImportExcelVO.class, list,true); + } + + @PostMapping("/import") + @Operation(summary = "导入tag") + @Parameters({ + @Parameter(name = "file", description = "Excel 文件", required = true), + @Parameter(name = "updateSupport", description = "是否支持更新,默认为 false", example = "true") + }) + @PreAuthorize("@ss.hasPermission('data:channel-modbus-tag:import')") + public CommonResult<TagImportRespVO> importExcel(@RequestParam("file") MultipartFile file, + @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport, + @RequestParam("device") String device) throws Exception { + List<ModBusTagImportExcelVO> list = ExcelUtils.read(file, ModBusTagImportExcelVO.class); + return success(channelModbusTagService.importModBusTagList(list, updateSupport,device)); + } } diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/entity/ChannelModBusTagEntity.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/entity/ChannelModBusTagEntity.java index b2a1bca..194e1fd 100644 --- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/entity/ChannelModBusTagEntity.java +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/entity/ChannelModBusTagEntity.java @@ -39,7 +39,7 @@ /** * 是否启用 */ - private Boolean enabled; + private Integer enabled; /** * 大小端 diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/service/ChannelModbusTagService.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/service/ChannelModbusTagService.java index 6ec084c..6548e13 100644 --- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/service/ChannelModbusTagService.java +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/service/ChannelModbusTagService.java @@ -3,7 +3,9 @@ import com.iailab.framework.common.pojo.PageResult; import com.iailab.module.data.channel.modbus.dto.ChannelModbusTagDTO; import com.iailab.module.data.channel.modbus.entity.ChannelModBusTagEntity; +import com.iailab.module.data.channel.modbus.vo.ModBusTagImportExcelVO; import com.iailab.module.data.channel.modbus.vo.ModBusTagPageReqVO; +import com.iailab.module.data.channel.tag.vo.TagImportRespVO; import java.util.List; @@ -18,7 +20,7 @@ * * @param reqVO */ - PageResult queryPage(ModBusTagPageReqVO reqVO); + PageResult<ChannelModBusTagEntity> queryPage(ModBusTagPageReqVO reqVO); /** * 查询tag详情 @@ -70,12 +72,5 @@ */ void deleteByDeviceName(String name); -// /** -// * 导入Tag -// * -// * @param device -// * @param file -// * @throws Exception -// */ -// void importTag(String device, MultipartFile file) throws Exception; + TagImportRespVO importModBusTagList(List<ModBusTagImportExcelVO> importTags, boolean isUpdateSupport, String device); } diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/service/impl/ChannelModbusTagServiceImpl.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/service/impl/ChannelModbusTagServiceImpl.java index 7e80908..64d3084 100644 --- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/service/impl/ChannelModbusTagServiceImpl.java +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/service/impl/ChannelModbusTagServiceImpl.java @@ -1,21 +1,28 @@ package com.iailab.module.data.channel.modbus.service.impl; +import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.iailab.framework.common.pojo.PageResult; +import com.iailab.framework.common.util.object.BeanUtils; import com.iailab.framework.common.util.object.ConvertUtils; import com.iailab.module.data.channel.modbus.dao.ChannelModBusTagDao; import com.iailab.module.data.channel.modbus.dto.ChannelModbusTagDTO; import com.iailab.module.data.channel.modbus.entity.ChannelModBusTagEntity; import com.iailab.module.data.channel.modbus.service.ChannelModbusTagService; +import com.iailab.module.data.channel.modbus.vo.ModBusTagImportExcelVO; import com.iailab.module.data.channel.modbus.vo.ModBusTagPageReqVO; +import com.iailab.module.data.channel.tag.vo.TagImportRespVO; +import com.iailab.module.data.common.enums.CommonConstant; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import javax.annotation.Resource; -import java.util.Date; -import java.util.List; +import java.util.*; + +import static com.iailab.framework.common.exception.util.ServiceExceptionUtil.exception; +import static com.iailab.module.data.enums.ErrorCodeConstants.*; /** * @author lirm @@ -82,4 +89,46 @@ baseMapper.delete(new QueryWrapper<ChannelModBusTagEntity>().eq("device", name)); } + @Override + public TagImportRespVO importModBusTagList(List<ModBusTagImportExcelVO> importTags, boolean isUpdateSupport, String device) { + // 1.1 参数校验 + if (CollUtil.isEmpty(importTags)) { + throw exception(TAG_IMPORT_LIST_IS_EMPTY); + } + + // 2. 遍历,逐个创建 or 更新 + TagImportRespVO respVO = TagImportRespVO.builder().createTagNames(new ArrayList<>()) + .updateTagNames(new ArrayList<>()).failureTagNames(new LinkedHashMap<>()).build(); + importTags.forEach(importTag -> { + + // 判断如果不存在,再进行插入 + ChannelModBusTagEntity existTag = channelModBusTagDao.selectOne(new QueryWrapper<ChannelModBusTagEntity>() + .eq("device", device) + .eq("tag_name",importTag.getTagName())); + if (existTag == null) { + ChannelModBusTagEntity channelModBusTagEntity = ConvertUtils.sourceToTarget(importTag, ChannelModBusTagEntity.class); + channelModBusTagEntity.setId(UUID.randomUUID().toString()); + channelModBusTagEntity.setEnabled(CommonConstant.IS_ENABLE); + channelModBusTagEntity.setDevice(device); + channelModBusTagEntity.setCreateTime(new Date()); + channelModBusTagDao.insert(channelModBusTagEntity); + + respVO.getCreateTagNames().add(channelModBusTagEntity.getTagName()); + return; + } + + // 如果存在,判断是否允许更新 + if (!isUpdateSupport) { + respVO.getFailureTagNames().put(importTag.getTagName(), TAG_EXISTS.getMsg()); + return; + } + + ChannelModBusTagEntity updateTag = BeanUtils.toBean(importTag, ChannelModBusTagEntity.class); + updateTag.setId(existTag.getId()); + baseMapper.updateById(updateTag); + respVO.getUpdateTagNames().add(importTag.getTagName()); + }); + return respVO; + } + } diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/vo/ModBusTagExportExcelVO.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/vo/ModBusTagExportExcelVO.java new file mode 100644 index 0000000..a4f0566 --- /dev/null +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/vo/ModBusTagExportExcelVO.java @@ -0,0 +1,28 @@ +package com.iailab.module.data.channel.modbus.vo; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.iailab.module.data.channel.tag.vo.TagExportExcelVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * @author PanZhibao + * @Description + * @createTime 2024年08月22日 + */ +@Schema(description = "导出 - ModBusTag信息") +@Data +public class ModBusTagExportExcelVO extends TagExportExcelVO { + + @Schema(description = "地址") + @ExcelProperty(value = "地址",index = 3) + private String address; + + @Schema(description = "大小端") + @ExcelProperty(value = "大小端",index = 4) + private String format; + + @Schema(description = "采集频率") + @ExcelProperty(value = "采集频率",index = 5) + private Integer samplingRate; +} \ No newline at end of file diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/vo/ModBusTagImportExcelVO.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/vo/ModBusTagImportExcelVO.java new file mode 100644 index 0000000..09edccf --- /dev/null +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/vo/ModBusTagImportExcelVO.java @@ -0,0 +1,31 @@ +package com.iailab.module.data.channel.modbus.vo; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.iailab.module.data.channel.tag.vo.TagImportExcelVO; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import lombok.experimental.SuperBuilder; + +/** + * 用户 Excel 导入 VO + * @author Jay + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Accessors(chain = false) // 设置 chain = false,避免用户导入有问题 +@SuperBuilder +public class ModBusTagImportExcelVO extends TagImportExcelVO { + + @ExcelProperty(value = "地址", index = 3) + private String address; + + @ExcelProperty(value = "大小端", index = 4) + private String format; + + @ExcelProperty(value = "采集频率", index = 5) + private Integer samplingRate; + +} diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/vo/ModBusTagRespVO.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/vo/ModBusTagRespVO.java index 2486441..ef9c2a0 100644 --- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/vo/ModBusTagRespVO.java +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/modbus/vo/ModBusTagRespVO.java @@ -31,7 +31,7 @@ @Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") @ExcelProperty("是否启用") - private Boolean enabled; + private Integer enabled; @Schema(description = "大小端", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") @ExcelProperty("大小端") diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/controller/admin/ChannelOPCDATagController.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/controller/admin/ChannelOPCDATagController.java index 2a6fb45..d3e5a94 100644 --- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/controller/admin/ChannelOPCDATagController.java +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/controller/admin/ChannelOPCDATagController.java @@ -1,22 +1,38 @@ package com.iailab.module.data.channel.opcda.controller.admin; +import com.iailab.framework.apilog.core.annotation.ApiAccessLog; import com.iailab.framework.common.pojo.CommonResult; +import com.iailab.framework.common.pojo.PageParam; import com.iailab.framework.common.pojo.PageResult; import com.iailab.framework.common.util.object.BeanUtils; +import com.iailab.framework.common.util.object.ConvertUtils; +import com.iailab.framework.excel.core.util.ExcelUtils; import com.iailab.module.data.channel.opcda.entity.ChannelOPCDATagEntity; import com.iailab.module.data.channel.opcda.service.ChannelOPCDATagService; +import com.iailab.module.data.channel.opcda.vo.OpcDaTagExportExcelVO; +import com.iailab.module.data.channel.opcda.vo.OpcDaTagImportExcelVO; import com.iailab.module.data.channel.opcda.vo.OpcDaTagPageReqVO; import com.iailab.module.data.channel.opcda.vo.OpcDaTagRespVO; +import com.iailab.module.data.channel.tag.vo.TagImportRespVO; import com.iailab.module.data.common.exception.RRException; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; +import java.io.IOException; +import java.util.Collections; import java.util.Date; +import java.util.List; import java.util.UUID; +import static com.iailab.framework.apilog.core.enums.OperateTypeEnum.EXPORT; import static com.iailab.framework.common.pojo.CommonResult.success; /** @@ -31,21 +47,21 @@ @Autowired private ChannelOPCDATagService channelOPCDATagService; - @PreAuthorize("@ss.hasPermission('data:channel-opcua:query')") + @PreAuthorize("@ss.hasPermission('data:channel-opcda:query')") @GetMapping("page") public CommonResult<PageResult<OpcDaTagRespVO>> list(@Valid OpcDaTagPageReqVO reqVO) { PageResult<ChannelOPCDATagEntity> page = channelOPCDATagService.queryPage(reqVO); return success(BeanUtils.toBean(page, OpcDaTagRespVO.class)); } - @PreAuthorize("@ss.hasPermission('data:channel-opcua:query')") + @PreAuthorize("@ss.hasPermission('data:channel-opcda:query')") @GetMapping("/info/{id}") public CommonResult<ChannelOPCDATagEntity> info(@PathVariable("id") String id) { ChannelOPCDATagEntity info = channelOPCDATagService.info(id); return success(info); } - @PreAuthorize("@ss.hasPermission('data:channel-opcua:create')") + @PreAuthorize("@ss.hasPermission('data:channel-opcda:create')") @PostMapping("/create") public CommonResult<Boolean> create(@RequestBody ChannelOPCDATagEntity channelOPCDATagEntity) { String id = UUID.randomUUID().toString(); @@ -55,7 +71,7 @@ return success(true); } - @PreAuthorize("@ss.hasPermission('data:channel-opcua:update')") + @PreAuthorize("@ss.hasPermission('data:channel-opcda:update')") @PutMapping("/update") public CommonResult<Boolean> update(@RequestBody ChannelOPCDATagEntity channelOPCDATagEntity) { channelOPCDATagEntity.setUpdateTime(new Date()); @@ -63,7 +79,7 @@ return success(true); } - @PreAuthorize("@ss.hasPermission('data:channel-opcua:delete')") + @PreAuthorize("@ss.hasPermission('data:channel-opcda:delete')") @DeleteMapping("/delete") public CommonResult<Boolean> delete(@RequestParam("id") String id) { channelOPCDATagService.delete(id); @@ -82,4 +98,42 @@ } return success("上传成功"); } + + @GetMapping("/export") + @Operation(summary = "导出modbus tag列表") + @PreAuthorize("@ss.hasPermission('data:channel-opcda-tag:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportPointList(@Validated OpcDaTagPageReqVO reqVO, HttpServletResponse response) throws IOException { + reqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + PageResult<ChannelOPCDATagEntity> page = channelOPCDATagService.queryPage(reqVO); + List<OpcDaTagExportExcelVO> list = ConvertUtils.sourceToTarget(page.getList(), OpcDaTagExportExcelVO.class); + ExcelUtils.write(response, "tag列表.xls", "数据", OpcDaTagExportExcelVO.class, list, true); + } + + + @GetMapping("/get-import-template") + @Operation(summary = "获得tag导入模板") + public void importTemplate(HttpServletResponse response) throws IOException { + // 手动创建导出 demo + List<OpcDaTagImportExcelVO> list = Collections.singletonList( + OpcDaTagImportExcelVO.builder().tagName("Tag名称").dataType("String").enabled(1) + .build() + ); + // 输出 + ExcelUtils.write(response, "tag导入模板.xls", "tag列表", OpcDaTagImportExcelVO.class, list,true); + } + + @PostMapping("/import") + @Operation(summary = "导入tag") + @Parameters({ + @Parameter(name = "file", description = "Excel 文件", required = true), + @Parameter(name = "updateSupport", description = "是否支持更新,默认为 false", example = "true") + }) + @PreAuthorize("@ss.hasPermission('data:channel-opcda-tag:import')") + public CommonResult<TagImportRespVO> importExcel(@RequestParam("file") MultipartFile file, + @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport, + @RequestParam("device") String device) throws Exception { + List<OpcDaTagImportExcelVO> list = ExcelUtils.read(file, OpcDaTagImportExcelVO.class); + return success(channelOPCDATagService.importOpcDaTagList(list, updateSupport,device)); + } } diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/entity/ChannelOPCDATagEntity.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/entity/ChannelOPCDATagEntity.java index 9a4cf85..fe1c54a 100644 --- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/entity/ChannelOPCDATagEntity.java +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/entity/ChannelOPCDATagEntity.java @@ -42,7 +42,7 @@ /** * 是否可以tag,如果为false,即使定义了但是runtime不会读取该数据 */ - private Boolean enabled; + private Integer enabled; /** * itemId diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/service/ChannelOPCDATagService.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/service/ChannelOPCDATagService.java index c0594a6..09f9810 100644 --- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/service/ChannelOPCDATagService.java +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/service/ChannelOPCDATagService.java @@ -3,12 +3,12 @@ import com.iailab.framework.common.pojo.PageResult; import com.iailab.module.data.channel.opcda.dto.ChannelOPCDATagDTO; import com.iailab.module.data.channel.opcda.entity.ChannelOPCDATagEntity; +import com.iailab.module.data.channel.opcda.vo.OpcDaTagImportExcelVO; import com.iailab.module.data.channel.opcda.vo.OpcDaTagPageReqVO; -import com.iailab.module.data.common.utils.PageUtils; +import com.iailab.module.data.channel.tag.vo.TagImportRespVO; import org.springframework.web.multipart.MultipartFile; import java.util.List; -import java.util.Map; /** * @author lirm @@ -36,4 +36,7 @@ void update(ChannelOPCDATagEntity channelOPCDATagEntity); void delete(String id); + + TagImportRespVO importOpcDaTagList(List<OpcDaTagImportExcelVO> importTags, boolean isUpdateSupport, String serverId); + } diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/service/impl/ChannelOPCDATagServiceImpl.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/service/impl/ChannelOPCDATagServiceImpl.java index 875faec..30e1aea 100644 --- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/service/impl/ChannelOPCDATagServiceImpl.java +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/service/impl/ChannelOPCDATagServiceImpl.java @@ -1,16 +1,21 @@ package com.iailab.module.data.channel.opcda.service.impl; +import cn.hutool.core.collection.CollUtil; import com.baomidou.dynamic.datasource.annotation.DSTransactional; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.iailab.framework.common.pojo.PageResult; +import com.iailab.framework.common.util.object.BeanUtils; import com.iailab.framework.common.util.object.ConvertUtils; import com.iailab.module.data.channel.opcda.dao.ChannelOPCDATagDao; import com.iailab.module.data.channel.opcda.dto.ChannelOPCDATagDTO; import com.iailab.module.data.channel.opcda.entity.ChannelOPCDATagEntity; import com.iailab.module.data.channel.opcda.service.ChannelOPCDATagService; +import com.iailab.module.data.channel.opcda.vo.OpcDaTagImportExcelVO; import com.iailab.module.data.channel.opcda.vo.OpcDaTagPageReqVO; +import com.iailab.module.data.channel.tag.vo.TagImportRespVO; +import com.iailab.module.data.common.enums.CommonConstant; import lombok.extern.slf4j.Slf4j; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.xssf.usermodel.XSSFRow; @@ -23,9 +28,10 @@ import javax.annotation.Resource; import java.io.File; import java.io.FileInputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; +import java.util.*; + +import static com.iailab.framework.common.exception.util.ServiceExceptionUtil.exception; +import static com.iailab.module.data.enums.ErrorCodeConstants.*; /** * @author lirm @@ -116,7 +122,7 @@ tagEntity.setTagName(row.getCell(1).getStringCellValue()); tagEntity.setDataType(row.getCell(2).getStringCellValue()); tagEntity.setItemId(row.getCell(3).getStringCellValue()); - tagEntity.setEnabled(true); + tagEntity.setEnabled(CommonConstant.IS_ENABLE); tagEntity.setServerId(serverId); dangerList.add(tagEntity); } @@ -138,4 +144,44 @@ } } + @Override + public TagImportRespVO importOpcDaTagList(List<OpcDaTagImportExcelVO> importTags, boolean isUpdateSupport, String serverId) { + // 1.1 参数校验 + if (CollUtil.isEmpty(importTags)) { + throw exception(TAG_IMPORT_LIST_IS_EMPTY); + } + // 2. 遍历,逐个创建 or 更新 + TagImportRespVO respVO = TagImportRespVO.builder().createTagNames(new ArrayList<>()) + .updateTagNames(new ArrayList<>()).failureTagNames(new LinkedHashMap<>()).build(); + importTags.forEach(importTag -> { + // 判断如果不存在,再进行插入 + ChannelOPCDATagEntity existTag = channelOPCDATagDao.selectOne(new QueryWrapper<ChannelOPCDATagEntity>() + .eq("server_id", serverId) + .eq("tag_name",importTag.getTagName())); + if (existTag == null) { + ChannelOPCDATagEntity channelOPCDATagEntity = ConvertUtils.sourceToTarget(importTag, ChannelOPCDATagEntity.class); + channelOPCDATagEntity.setId(UUID.randomUUID().toString()); + channelOPCDATagEntity.setEnabled(CommonConstant.IS_ENABLE); + channelOPCDATagEntity.setServerId(serverId); + channelOPCDATagEntity.setCreateTime(new Date()); + channelOPCDATagDao.insert(channelOPCDATagEntity); + + respVO.getCreateTagNames().add(channelOPCDATagEntity.getTagName()); + return; + } + + // 如果存在,判断是否允许更新 + if (!isUpdateSupport) { + respVO.getFailureTagNames().put(importTag.getTagName(), TAG_EXISTS.getMsg()); + return; + } + + ChannelOPCDATagEntity updateTag = BeanUtils.toBean(importTag, ChannelOPCDATagEntity.class); + updateTag.setId(existTag.getId()); + baseMapper.updateById(updateTag); + respVO.getUpdateTagNames().add(importTag.getTagName()); + }); + return respVO; + } + } diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/vo/OpcDaTagExportExcelVO.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/vo/OpcDaTagExportExcelVO.java new file mode 100644 index 0000000..6d895cf --- /dev/null +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/vo/OpcDaTagExportExcelVO.java @@ -0,0 +1,51 @@ +package com.iailab.module.data.channel.opcda.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.iailab.framework.excel.core.annotations.DictFormat; +import com.iailab.framework.excel.core.annotations.ExcelColumnSelect; +import com.iailab.framework.excel.core.convert.DictConvert; +import com.iailab.framework.excel.core.function.ExcelColumnSelectFunction; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @author PanZhibao + * @Description + * @createTime 2024年08月22日 + */ +@Schema(description = "导出 - Tag信息") +@Data +@ExcelIgnoreUnannotated +@Component +public class OpcDaTagExportExcelVO implements ExcelColumnSelectFunction { + + @Schema(description = "Tag名称") + @ExcelProperty(value = "Tag名称") + private String tagName; + + @Schema(description = "数据类型") + @ExcelProperty(value = "数据类型", converter = DictConvert.class) + @ExcelColumnSelect(dictType = "tag_data_type") + @DictFormat("tag_data_type") + private String dataType; + + @Schema(description = "是否启用") + @ExcelProperty(value = "是否启用", converter = DictConvert.class) + @ExcelColumnSelect(dictType = "com_is_int") + @DictFormat("com_is_int") + private Integer enabled; + + @Override + public String getName() { + return null; + } + + @Override + public List<String> getOptions() { + return null; + } +} \ No newline at end of file diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/vo/OpcDaTagImportExcelVO.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/vo/OpcDaTagImportExcelVO.java new file mode 100644 index 0000000..846ff70 --- /dev/null +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/vo/OpcDaTagImportExcelVO.java @@ -0,0 +1,53 @@ +package com.iailab.module.data.channel.opcda.vo; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.iailab.framework.excel.core.annotations.DictFormat; +import com.iailab.framework.excel.core.annotations.ExcelColumnSelect; +import com.iailab.framework.excel.core.convert.DictConvert; +import com.iailab.framework.excel.core.function.ExcelColumnSelectFunction; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import lombok.experimental.SuperBuilder; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 用户 Excel 导入 VO + * @author Jay + */ +@Data +@SuperBuilder +@AllArgsConstructor +@NoArgsConstructor +@Accessors(chain = false) // 设置 chain = false,避免用户导入有问题 +@Component +public class OpcDaTagImportExcelVO implements ExcelColumnSelectFunction { + + @ExcelProperty(value = "Tag名称") + private String tagName; + + @ExcelProperty(value = "数据类型") + @ExcelColumnSelect(dictType = "tag_data_type") + @DictFormat("tag_data_type") + private String dataType; + + @Schema(description = "是否启用") + @ExcelProperty(value = "是否启用", converter = DictConvert.class) + @ExcelColumnSelect(dictType = "com_is_int") + @DictFormat("com_is_int") + private Integer enabled; + + @Override + public String getName() { + return null; + } + + @Override + public List<String> getOptions() { + return null; + } +} diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/vo/OpcDaTagRespVO.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/vo/OpcDaTagRespVO.java index 89709db..c4a263a 100644 --- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/vo/OpcDaTagRespVO.java +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcda/vo/OpcDaTagRespVO.java @@ -35,7 +35,7 @@ @Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") @ExcelProperty("是否启用") - private Boolean enabled; + private Integer enabled; @Schema(description = "itemID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") @ExcelProperty("itemID") diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/controller/admin/ChannelOPCUATagController.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/controller/admin/ChannelOPCUATagController.java index 981ef30..365bcc2 100644 --- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/controller/admin/ChannelOPCUATagController.java +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/controller/admin/ChannelOPCUATagController.java @@ -1,20 +1,37 @@ package com.iailab.module.data.channel.opcua.controller.admin; +import com.iailab.framework.apilog.core.annotation.ApiAccessLog; import com.iailab.framework.common.pojo.CommonResult; +import com.iailab.framework.common.pojo.PageParam; import com.iailab.framework.common.pojo.PageResult; import com.iailab.framework.common.util.object.BeanUtils; +import com.iailab.framework.common.util.object.ConvertUtils; +import com.iailab.framework.excel.core.util.ExcelUtils; import com.iailab.module.data.channel.opcua.entity.ChannelOPCUATagEntity; import com.iailab.module.data.channel.opcua.service.ChannelOPCUATagService; +import com.iailab.module.data.channel.opcua.vo.OpcUaTagExportExcelVO; +import com.iailab.module.data.channel.opcua.vo.OpcUaTagImportExcelVO; import com.iailab.module.data.channel.opcua.vo.OpcUaTagPageReqVO; import com.iailab.module.data.channel.opcua.vo.OpcUaTagRespVO; +import com.iailab.module.data.channel.tag.vo.TagImportRespVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; +import java.io.IOException; +import java.util.Collections; import java.util.Date; +import java.util.List; import java.util.UUID; +import static com.iailab.framework.apilog.core.enums.OperateTypeEnum.EXPORT; import static com.iailab.framework.common.pojo.CommonResult.success; /** @@ -68,16 +85,40 @@ return success(true); } -// @PostMapping("/import/{device}") -// public R importTag(@PathVariable("device") String device, @RequestParam("file") MultipartFile file) { -// try { -// if (file.isEmpty()) { -// throw new RRException("上传文件不能为空"); -// } -// channelOpcuaTagService.importTag(device, file); -// } catch (Exception ex) { -// return R.error(ex.getMessage()); -// } -// return R.ok(); -// } + @GetMapping("/export") + @Operation(summary = "导出modbus tag列表") + @PreAuthorize("@ss.hasPermission('data:channel-opcua-tag:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportPointList(@Validated OpcUaTagPageReqVO reqVO, HttpServletResponse response) throws IOException { + reqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + PageResult<ChannelOPCUATagEntity> page = channelOpcuaTagService.queryPage(reqVO); + List<OpcUaTagExportExcelVO> list = ConvertUtils.sourceToTarget(page.getList(), OpcUaTagExportExcelVO.class); + ExcelUtils.write(response, "tag列表.xls", "数据", OpcUaTagExportExcelVO.class, list, true); + } + + @GetMapping("/get-import-template") + @Operation(summary = "获得tag导入模板") + public void importTemplate(HttpServletResponse response) throws IOException { + // 手动创建导出 demo + List<OpcUaTagImportExcelVO> list = Collections.singletonList( + OpcUaTagImportExcelVO.builder().tagName("Tag名称").dataType("String").address("123").samplingRate(1000).enabled(1) + .build() + ); + // 输出 + ExcelUtils.write(response, "tag导入模板.xls", "tag列表", OpcUaTagImportExcelVO.class, list,true); + } + + @PostMapping("/import") + @Operation(summary = "导入tag") + @Parameters({ + @Parameter(name = "file", description = "Excel 文件", required = true), + @Parameter(name = "updateSupport", description = "是否支持更新,默认为 false", example = "true") + }) + @PreAuthorize("@ss.hasPermission('data:channel-opcua-tag:import')") + public CommonResult<TagImportRespVO> importExcel(@RequestParam("file") MultipartFile file, + @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport, + @RequestParam("device") String device) throws Exception { + List<OpcUaTagImportExcelVO> list = ExcelUtils.read(file, OpcUaTagImportExcelVO.class); + return success(channelOpcuaTagService.importOpcUaTagList(list, updateSupport,device)); + } } diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/entity/ChannelOPCUATagEntity.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/entity/ChannelOPCUATagEntity.java index 857c0b4..b555614 100644 --- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/entity/ChannelOPCUATagEntity.java +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/entity/ChannelOPCUATagEntity.java @@ -38,7 +38,7 @@ /** * 是否可以tag,如果为false,即使定义了但是runtime不会读取该数据 */ - private Boolean enabled; + private Integer enabled; /** * 关联设备 diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/service/ChannelOPCUATagService.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/service/ChannelOPCUATagService.java index d8e2627..a689227 100644 --- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/service/ChannelOPCUATagService.java +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/service/ChannelOPCUATagService.java @@ -3,7 +3,9 @@ import com.iailab.framework.common.pojo.PageResult; import com.iailab.module.data.channel.opcua.dto.ChannelOPCUATagDTO; import com.iailab.module.data.channel.opcua.entity.ChannelOPCUATagEntity; +import com.iailab.module.data.channel.opcua.vo.OpcUaTagImportExcelVO; import com.iailab.module.data.channel.opcua.vo.OpcUaTagPageReqVO; +import com.iailab.module.data.channel.tag.vo.TagImportRespVO; import org.springframework.web.multipart.MultipartFile; import java.util.List; @@ -34,4 +36,6 @@ void importTag(String device, MultipartFile file) throws Exception; + TagImportRespVO importOpcUaTagList(List<OpcUaTagImportExcelVO> importTags, boolean isUpdateSupport, String device); + } diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/service/impl/ChannelOPCUATagServiceImpl.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/service/impl/ChannelOPCUATagServiceImpl.java index 97562b0..074aae8 100644 --- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/service/impl/ChannelOPCUATagServiceImpl.java +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/service/impl/ChannelOPCUATagServiceImpl.java @@ -1,16 +1,21 @@ package com.iailab.module.data.channel.opcua.service.impl; +import cn.hutool.core.collection.CollUtil; import com.baomidou.dynamic.datasource.annotation.DSTransactional; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.iailab.framework.common.pojo.PageResult; +import com.iailab.framework.common.util.object.BeanUtils; import com.iailab.framework.common.util.object.ConvertUtils; import com.iailab.module.data.channel.opcua.dao.ChannelOPCUATagDao; import com.iailab.module.data.channel.opcua.dto.ChannelOPCUATagDTO; import com.iailab.module.data.channel.opcua.entity.ChannelOPCUATagEntity; import com.iailab.module.data.channel.opcua.service.ChannelOPCUATagService; +import com.iailab.module.data.channel.opcua.vo.OpcUaTagImportExcelVO; import com.iailab.module.data.channel.opcua.vo.OpcUaTagPageReqVO; +import com.iailab.module.data.channel.tag.vo.TagImportRespVO; +import com.iailab.module.data.common.enums.CommonConstant; import lombok.extern.slf4j.Slf4j; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.xssf.usermodel.XSSFRow; @@ -23,9 +28,10 @@ import javax.annotation.Resource; import java.io.File; import java.io.FileInputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; +import java.util.*; + +import static com.iailab.framework.common.exception.util.ServiceExceptionUtil.exception; +import static com.iailab.module.data.enums.ErrorCodeConstants.*; /** * @author lirm @@ -122,7 +128,7 @@ }else if(row.getCell(3).getStringCellValue().equals("3")){ tagEntity.setAddress(String.format("4%04d",Integer.parseInt(row.getCell(4).getStringCellValue()))); } - tagEntity.setEnabled(true); + tagEntity.setEnabled(1); tagEntity.setDevice(device); tagEntity.setSamplingRate(1); dangerList.add(tagEntity); @@ -144,4 +150,44 @@ throw ex; } } + + @Override + public TagImportRespVO importOpcUaTagList(List<OpcUaTagImportExcelVO> importTags, boolean isUpdateSupport, String device) { + // 1.1 参数校验 + if (CollUtil.isEmpty(importTags)) { + throw exception(TAG_IMPORT_LIST_IS_EMPTY); + } + // 2. 遍历,逐个创建 or 更新 + TagImportRespVO respVO = TagImportRespVO.builder().createTagNames(new ArrayList<>()) + .updateTagNames(new ArrayList<>()).failureTagNames(new LinkedHashMap<>()).build(); + importTags.forEach(importTag -> { + // 判断如果不存在,再进行插入 + ChannelOPCUATagEntity existTag = channelOPCUATagDao.selectOne(new QueryWrapper<ChannelOPCUATagEntity>() + .eq("device", device) + .eq("tag_name",importTag.getTagName())); + if (existTag == null) { + ChannelOPCUATagEntity channelOpCuaTagEntity = ConvertUtils.sourceToTarget(importTag, ChannelOPCUATagEntity.class); + channelOpCuaTagEntity.setId(UUID.randomUUID().toString()); + channelOpCuaTagEntity.setEnabled(CommonConstant.IS_ENABLE); + channelOpCuaTagEntity.setDevice(device); + channelOpCuaTagEntity.setCreateTime(new Date()); + channelOPCUATagDao.insert(channelOpCuaTagEntity); + + respVO.getCreateTagNames().add(channelOpCuaTagEntity.getTagName()); + return; + } + + // 如果存在,判断是否允许更新 + if (!isUpdateSupport) { + respVO.getFailureTagNames().put(importTag.getTagName(), TAG_EXISTS.getMsg()); + return; + } + + ChannelOPCUATagEntity updateTag = BeanUtils.toBean(importTag, ChannelOPCUATagEntity.class); + updateTag.setId(existTag.getId()); + baseMapper.updateById(updateTag); + respVO.getUpdateTagNames().add(importTag.getTagName()); + }); + return respVO; + } } diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/vo/OpcUaTagExportExcelVO.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/vo/OpcUaTagExportExcelVO.java new file mode 100644 index 0000000..f531c10 --- /dev/null +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/vo/OpcUaTagExportExcelVO.java @@ -0,0 +1,59 @@ +package com.iailab.module.data.channel.opcua.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.iailab.framework.excel.core.annotations.DictFormat; +import com.iailab.framework.excel.core.annotations.ExcelColumnSelect; +import com.iailab.framework.excel.core.convert.DictConvert; +import com.iailab.framework.excel.core.function.ExcelColumnSelectFunction; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @author PanZhibao + * @Description + * @createTime 2024年08月22日 + */ +@Schema(description = "导出 - Tag信息") +@Data +@ExcelIgnoreUnannotated +@Component +public class OpcUaTagExportExcelVO implements ExcelColumnSelectFunction { + + @Schema(description = "Tag名称") + @ExcelProperty(value = "Tag名称") + private String tagName; + + @Schema(description = "数据类型") + @ExcelProperty(value = "数据类型", converter = DictConvert.class) + @ExcelColumnSelect(dictType = "tag_data_type") + @DictFormat("tag_data_type") + private String dataType; + + @Schema(description = "地址") + @ExcelProperty(value = "地址") + private String address; + + @Schema(description = "采集频率") + @ExcelProperty(value = "采集频率") + private Integer samplingRate; + + @Schema(description = "是否启用") + @ExcelProperty(value = "是否启用", converter = DictConvert.class) + @ExcelColumnSelect(dictType = "com_is_int") + @DictFormat("com_is_int") + private Integer enabled; + + @Override + public String getName() { + return null; + } + + @Override + public List<String> getOptions() { + return null; + } +} \ No newline at end of file diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/vo/OpcUaTagImportExcelVO.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/vo/OpcUaTagImportExcelVO.java new file mode 100644 index 0000000..df1a247 --- /dev/null +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/vo/OpcUaTagImportExcelVO.java @@ -0,0 +1,61 @@ +package com.iailab.module.data.channel.opcua.vo; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.iailab.framework.excel.core.annotations.DictFormat; +import com.iailab.framework.excel.core.annotations.ExcelColumnSelect; +import com.iailab.framework.excel.core.convert.DictConvert; +import com.iailab.framework.excel.core.function.ExcelColumnSelectFunction; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import lombok.experimental.SuperBuilder; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 用户 Excel 导入 VO + * @author Jay + */ +@Data +@SuperBuilder +@AllArgsConstructor +@NoArgsConstructor +@Accessors(chain = false) // 设置 chain = false,避免用户导入有问题 +@Component +public class OpcUaTagImportExcelVO implements ExcelColumnSelectFunction { + + @ExcelProperty(value = "Tag名称") + private String tagName; + + @ExcelProperty(value = "数据类型") + @ExcelColumnSelect(dictType = "tag_data_type") + @DictFormat("tag_data_type") + private String dataType; + + @Schema(description = "地址") + @ExcelProperty(value = "地址") + private String address; + + @Schema(description = "采集频率") + @ExcelProperty(value = "采集频率") + private Integer samplingRate; + + @Schema(description = "是否启用") + @ExcelProperty(value = "是否启用", converter = DictConvert.class) + @ExcelColumnSelect(dictType = "com_is_int") + @DictFormat("com_is_int") + private Integer enabled; + + @Override + public String getName() { + return null; + } + + @Override + public List<String> getOptions() { + return null; + } +} diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/vo/OpcUaTagRespVO.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/vo/OpcUaTagRespVO.java index 2da2f1b..feeac98 100644 --- a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/vo/OpcUaTagRespVO.java +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/opcua/vo/OpcUaTagRespVO.java @@ -31,7 +31,7 @@ @Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") @ExcelProperty("是否启用") - private Boolean enabled; + private Integer enabled; @Schema(description = "关联设备", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") @ExcelProperty("关联设备") diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/tag/vo/TagExportExcelVO.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/tag/vo/TagExportExcelVO.java new file mode 100644 index 0000000..cd6076e --- /dev/null +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/tag/vo/TagExportExcelVO.java @@ -0,0 +1,55 @@ +package com.iailab.module.data.channel.tag.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.iailab.framework.excel.core.annotations.DictFormat; +import com.iailab.framework.excel.core.annotations.ExcelColumnSelect; +import com.iailab.framework.excel.core.convert.DictConvert; +import com.iailab.framework.excel.core.function.ExcelColumnSelectFunction; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @author PanZhibao + * @Description + * @createTime 2024年08月22日 + */ +@Schema(description = "导出 - Tag信息") +@Data +@ExcelIgnoreUnannotated +@Component +public class TagExportExcelVO implements ExcelColumnSelectFunction { + + @Schema(description = "Tag名称") + @ExcelProperty(value = "Tag名称", index = 0) + private String tagName; + + @Schema(description = "Tag描述") + @ExcelProperty(value = "Tag描述", index = 1) + private String tagDesc; + + @Schema(description = "数据类型") + @ExcelProperty(value = "数据类型", index = 2, converter = DictConvert.class) + @ExcelColumnSelect(dictType = "tag_data_type") + @DictFormat("tag_data_type") + private String dataType; + + @Schema(description = "是否启用") + @ExcelProperty(value = "是否启用", converter = DictConvert.class) + @ExcelColumnSelect(dictType = "com_is_int") + @DictFormat("com_is_int") + private Integer enabled; + + @Override + public String getName() { + return null; + } + + @Override + public List<String> getOptions() { + return null; + } +} \ No newline at end of file diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/tag/vo/TagImportExcelVO.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/tag/vo/TagImportExcelVO.java new file mode 100644 index 0000000..cf24ea4 --- /dev/null +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/tag/vo/TagImportExcelVO.java @@ -0,0 +1,56 @@ +package com.iailab.module.data.channel.tag.vo; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.iailab.framework.excel.core.annotations.DictFormat; +import com.iailab.framework.excel.core.annotations.ExcelColumnSelect; +import com.iailab.framework.excel.core.convert.DictConvert; +import com.iailab.framework.excel.core.function.ExcelColumnSelectFunction; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import lombok.experimental.SuperBuilder; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 用户 Excel 导入 VO + * @author Jay + */ +@Data +@SuperBuilder +@AllArgsConstructor +@NoArgsConstructor +@Accessors(chain = false) // 设置 chain = false,避免用户导入有问题 +@Component +public class TagImportExcelVO implements ExcelColumnSelectFunction { + + @ExcelProperty(value = "Tag名称", index = 0) + private String tagName; + + @ExcelProperty(value = "Tag描述", index = 1) + private String tagDesc; + + @ExcelProperty(value = "数据类型", index = 2) + @ExcelColumnSelect(dictType = "tag_data_type") + @DictFormat("tag_data_type") + private String dataType; + + @Schema(description = "是否启用") + @ExcelProperty(value = "是否启用", converter = DictConvert.class) + @ExcelColumnSelect(dictType = "com_is_int") + @DictFormat("com_is_int") + private Integer enabled; + + @Override + public String getName() { + return null; + } + + @Override + public List<String> getOptions() { + return null; + } +} diff --git a/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/tag/vo/TagImportRespVO.java b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/tag/vo/TagImportRespVO.java new file mode 100644 index 0000000..a3c269c --- /dev/null +++ b/iailab-module-data/iailab-module-data-biz/src/main/java/com/iailab/module/data/channel/tag/vo/TagImportRespVO.java @@ -0,0 +1,26 @@ +package com.iailab.module.data.channel.tag.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +/** + * @author Jay + */ +@Schema(description = "管理后台 - 用户导入 Response VO") +@Data +@Builder +public class TagImportRespVO { + + @Schema(description = "创建成功的Tag名称数组", requiredMode = Schema.RequiredMode.REQUIRED) + private List<String> createTagNames; + + @Schema(description = "更新成功的Tag名称数组", requiredMode = Schema.RequiredMode.REQUIRED) + private List<String> updateTagNames; + + @Schema(description = "导入失败的Tag集合,key 为Tag名称,value 为失败原因", requiredMode = Schema.RequiredMode.REQUIRED) + private Map<String, String> failureTagNames; +} -- Gitblit v1.9.3