浏览代码

Merge branch 'master' of http://116.63.33.55/git/industry-data-platform

ws 1 年之前
父节点
当前提交
fad30b1740

+ 213 - 62
industry-admin/src/views/source/dataQuery/index.vue

@@ -3,9 +3,10 @@
         <el-row>
             <el-col>
                 <!-- 搜索信息 -->
-                <el-form ref="chartForm" :model="chartForm" :rules="chartFormRules" size="small" :inline="true">
+                <el-form ref="chartForm" :model="chartForm" :rules="chartFormRules" size="small" :inline="true"
+                    label-width="78px">
                     <el-row>
-                        <el-col :span="4" :xs="8" :sm="6" :md="4" :lg="3" :xl="4">
+                        <el-col :xl="4">
                             <el-form-item prop="trendType">
                                 <el-radio-group v-model="chartForm.trendType">
                                     <el-radio :label="0">实时趋势</el-radio>
@@ -13,42 +14,43 @@
                                 </el-radio-group>
                             </el-form-item>
                         </el-col>
-                        <el-col v-if="chartForm.trendType == 0" :span="4">
+                        <el-col v-if="chartForm.trendType == 0" :xl="3">
                             <el-form-item label="更新频率" prop="frequencyValue">
-                                <el-input v-model="chartForm.frequencyValue"></el-input>
+                                <el-input style="width: 115px;" v-model="chartForm.frequencyValue"
+                                    @change="changeFrequency"></el-input>
                             </el-form-item>
                         </el-col>
-                        <el-col v-if="chartForm.trendType == 0" :span="1" :xl="2">
-                            <el-form-item prop="frequencyType">
-                                <el-select v-model="chartForm.frequencyType">
+                        <el-col v-if="chartForm.trendType == 0" :xl="2">
+                            <el-form-item prop="frequencyType" style="width: 70px;">
+                                <el-select v-model="chartForm.frequencyType" @change="changeFrequencyType">
                                     <el-option v-for="timeType in timeTypeList" :key="timeType.value"
                                         :label="timeType.label" :value="timeType.value">
                                     </el-option>
                                 </el-select>
                             </el-form-item>
                         </el-col>
-                        <el-col v-if="chartForm.trendType == 0" :span="4">
+                        <el-col v-if="chartForm.trendType == 0" :xl="3">
                             <el-form-item label="时间长度" prop="timeValue">
-                                <el-input v-model="chartForm.timeValue"></el-input>
+                                <el-input style="width: 115px;" v-model="chartForm.timeValue"></el-input>
                             </el-form-item>
                         </el-col>
                         <el-col v-if="chartForm.trendType == 0" :span="2">
                             <el-form-item prop="timeType">
-                                <el-select v-model="chartForm.timeType">
+                                <el-select v-model="chartForm.timeType" style="width: 70px;">
                                     <el-option v-for="timeType in timeTypeList" :key="timeType.value"
                                         :label="timeType.label" :value="timeType.value">
                                     </el-option>
                                 </el-select>
                             </el-form-item>
                         </el-col>
-                        <el-col v-if="chartForm.trendType == 1" :span="6">
+                        <el-col v-if="chartForm.trendType == 1" :span="5">
                             <el-form-item label="开始时间" prop="startTime">
                                 <el-date-picker value-format="yyyy-MM-dd HH:mm:ss" v-model="chartForm.startTime"
                                     type="datetime" placeholder="选择日期">
                                 </el-date-picker>
                             </el-form-item>
                         </el-col>
-                        <el-col v-if="chartForm.trendType == 1" :span="6">
+                        <el-col v-if="chartForm.trendType == 1" :span="5">
                             <el-form-item label="结束时间" prop="endTime">
                                 <el-date-picker value-format="yyyy-MM-dd HH:mm:ss" v-model="chartForm.endTime"
                                     type="datetime" placeholder="选择日期">
@@ -57,24 +59,31 @@
                         </el-col>
                     </el-row>
                     <el-row>
-                        <el-form-item label="数据项" prop="itemListTitile">
-                            <el-input :title="chartForm.itemListTitile" v-model="chartForm.itemListTitile" disabled
-                                placeholder="请选择数据项" maxlength="10">
-                                <el-button type="primary" slot="append" icon="el-icon-search"
-                                    @click="chooseItemEvent">选择</el-button>
-                            </el-input>
-                        </el-form-item>
-                        <el-form-item label="小数位" prop="decimalPlaces">
-                            <el-input v-model="chartForm.decimalPlaces"></el-input>
-                        </el-form-item>
-                        <el-form-item label="量程" prop="range">
-                            <el-input v-model="chartForm.range"></el-input>
-                        </el-form-item>
+                        <el-col :xl="6">
+                            <el-form-item label="数据项" prop="itemListTitile">
+                                <el-input :title="chartForm.itemListTitile" v-model="chartForm.itemListTitile" disabled
+                                    placeholder="请选择数据项" maxlength="10">
+                                    <el-button size="mini" type="primary" slot="append" icon="el-icon-search"
+                                        @click="chooseItemEvent">选择</el-button>
+                                </el-input>
+                            </el-form-item>
+                        </el-col>
+                        <el-col :xl="4">
+                            <el-form-item label="小数位" prop="decimalPlaces">
+                                <el-input style="width: 115px;" v-model="chartForm.decimalPlaces"></el-input>
+                            </el-form-item>
+                        </el-col>
+                        <el-col :xl="4">
+                            <el-form-item label="量程" prop="range">
+                                <el-input style="width: 115px;" v-model="chartForm.range"></el-input>
+                            </el-form-item>
+                        </el-col>
                         <el-form-item>
                             <el-button type="primary" plain icon="el-icon-search" size="mini"
                                 @click="queryData">查询</el-button>
+                            <el-button ref="btn" icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
                             <el-button type="primary" plain icon="el-icon-folder-opened" size="mini"
-                                @click="exportData">导出</el-button>
+                                @click="exportItemListData">导出</el-button>
                         </el-form-item>
                     </el-row>
                 </el-form>
@@ -94,9 +103,15 @@
 import { showLoading } from '@/utils/cqcy'
 import { parseTime } from "@/utils/index";
 import ChooseItem from './chooseItem.vue'
-import { getItemListValue } from '@/api/source/itemGroup'
+import { getItemListValue, exportItemListData } from '@/api/source/itemGroup'
 import qs from 'qs'
 import echarts from 'echarts'
+import axios from 'axios'
+import { getToken } from '@/utils/auth'
+axios.defaults.headers['Authorization'] = 'Bearer ' + getToken()
+axios.defaults.headers['token'] = getToken()
+axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
+axios.defaults.baseURL = process.env.VUE_APP_BASE_API
 
 export default {
     created() {
@@ -221,15 +236,37 @@ export default {
                 containLabel: true
             },
             //缩放组件
-            dataZoom: [{
-                type: 'inside', // 放大和缩小
-                orient: 'vertical',
-            }, {
-                type: 'inside',
-            }],
+            // dataZoom: [{
+            //     type: 'inside', // 放大和缩小
+            //     orient: 'vertical',
+            // }, {
+            //     type: 'inside',
+            // }],
+            dataZoom: [
+                {
+                    show: true,
+                    //拖动时,实时刷新数据
+                    realtime: true,
+                    textStyle: {
+                        color: '#99ffff'
+                    },
+                    start: 0,
+                    end: 100,
+                    //缩小最小值1%比例
+                    // minSpan: 1
+                },
+                {
+                    type: 'inside',
+                    realtime: true
+                }
+            ],
             //x轴
             xAxis: {
                 type: 'category',
+                // type: 'time',
+                // splitLine: {
+                //     show: false
+                // },
                 boundaryGap: false,
                 axisLine: {
                     lineStyle: {
@@ -241,25 +278,25 @@ export default {
             yAxis: [{
                 type: 'value',
                 //是否显示坐标轴刻度。
-                axisTick: {
-                    show: true
-                },
-                axisLine: {
-                    lineStyle: {
-                        color: '#FFFFFF'
-                    }
-                },
-                axisLabel: {
-                    margin: 10,
-                    textStyle: {
-                        fontSize: 14
-                    }
-                },
-                splitLine: {
-                    lineStyle: {
-                        color: '#57617B'
-                    }
-                }
+                // axisTick: {
+                //     show: true
+                // },
+                // axisLine: {
+                //     lineStyle: {
+                //         color: '#FFFFFF'
+                //     }
+                // },
+                // axisLabel: {
+                //     margin: 10,
+                //     textStyle: {
+                //         fontSize: 14
+                //     }
+                // },
+                // splitLine: {
+                //     lineStyle: {
+                //         color: '#57617B'
+                //     }
+                // }
             }],
             //数据列
             series: []
@@ -283,6 +320,20 @@ export default {
             this.chartForm.idList = arr
             this.chartForm.itemListTitile = b
         },
+        /** 频率更改事件 */
+        changeFrequency() {
+            if (this.chart && this.state) {
+                this.stopTimer()
+                this.startTimer()
+            }
+        },
+        /** 频率类型改变事件 */
+        changeFrequencyType() {
+            if (this.chart && this.state) {
+                this.stopTimer()
+                this.startTimer()
+            }
+        },
         /** 选择数据项事件 */
         chooseItemEvent() {
             this.$refs.chooseItem.selectedItemList = this.itemList
@@ -348,6 +399,12 @@ export default {
                 this.initChart()
             }
         },
+        /** 重置统计图,这里只重置统计图的缩放组件 */
+        resetQuery() {
+            if (this.chart) {
+                this.chart.setOption({ dataZoom: this.dataZoom })
+            }
+        },
         /** 通过数据项id,开始结束时间获取相应的数据 */
         getItemListValue(callback) {
             if (this.chooseStartTime == this.chooseEndTime) {
@@ -371,19 +428,22 @@ export default {
                 let data = res.data
                 this.chart = echarts.init(this.$refs.chart)
                 let legendData = []
+                let xAxisData = []
                 let seriesData = []
-                for (let a of data) {
+                for (let n in data) {
+                    let a = data[n]
                     legendData.push(a.describe ? a.describe : a.itemReadName)
                     let b = {
-                        name: a.unit ? ((a.describe ? a.describe : a.itemReadName) + '(' + a.unit + ')') :
-                            (a.describe ? a.describe : a.itemReadName),
+                        name: a.describe ? a.describe : a.itemReadName,
                         type: 'line',
+                        //是否平滑曲线
                         smooth: true,
                         symbol: 'circle',
                         symbolSize: 5,
-                        showSymbol: false,
+                        //是否显示线上点
+                        showSymbol: true,
                         itemStyle: {
-                            color: this.getColor()
+                            color: this.getColor(n)
                         },
                         lineStyle: {
                             normal: {
@@ -394,6 +454,7 @@ export default {
                     }
                     let c = []
                     if (a.dataTimeList) {
+                        xAxisData = xAxisData.concat(a.dataTimeList)
                         for (let i in a.dataTimeList) {
                             const d = []
                             d.push(a.dataTimeList[i])
@@ -405,7 +466,7 @@ export default {
                     seriesData.push(b)
                 }
                 let decimalPlaces = parseInt(this.chartForm.decimalPlaces)
-                this.tooltip.formatter = function (params, ticket, callback) {
+                this.tooltip.formatter = function (params) {
                     let b = '<div style="display:inline;">'
                     for (let a of params) {
                         b += '<div><span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:' + a.color + ';"></span><span style="color:' + a.color + '">'
@@ -415,6 +476,7 @@ export default {
                     return b
                 }
                 this.legend.data = legendData
+                this.xAxis.data = xAxisData.filter((item, index) => xAxisData.indexOf(item) === index).sort()
                 this.yAxis[0].max = null
                 if (this.chartForm.range) {
                     this.yAxis[0].max = parseInt(this.chartForm.range)
@@ -439,7 +501,12 @@ export default {
             })
         },
         /** 生成颜色方法 */
-        getColor() {
+        getColor(i) {
+            const arr = ['#ff33cc', '#ff3333', '#99ffff', '#66ff33', '#FFFF00',
+                '#00FFFF', '#A0522D', '#F0FFFF', '#FF6EB4', '#33ccff']
+            if (i <= 10) {
+                return arr[i]
+            }
             const r = this.colorRandom(128, 255)
             const g = this.colorRandom(0, 63)
             const b = this.colorRandom(128, 255)
@@ -498,10 +565,12 @@ export default {
         updateChartData() {
             this.getItemListValue((res) => {
                 let data = res.data
+                let xArr = this.xAxis.data
                 for (let i in data) {
                     let a = data[i]
                     let arr = this.series[i].data
                     if (a.dataTimeList) {
+                        xArr = xArr.concat(a.dataTimeList)
                         for (let j in a.dataTimeList) {
                             const b = []
                             b.push(a.dataTimeList[j])
@@ -509,8 +578,9 @@ export default {
                             arr.push(b)
                         }
                     }
-                    //删除多余数据
+                    //排序,并删除多余数据
                     if (arr) {
+                        // arr.sort((c, d) => c[0] - d[0])
                         let count = new Date(arr[arr.length - 1][0]).getTime() - this.count
                         let num = 0
                         for (let j in arr) {
@@ -522,6 +592,10 @@ export default {
                         this.series[i].data = arr.splice(num)
                     }
                 }
+                //更新x轴全部数据
+                xArr = xArr.filter((item, index) => xArr.indexOf(item) === index).sort()
+                this.xAxis.data = xArr.filter((i) =>
+                    new Date(i).getTime() >= (new Date(xArr[xArr.length - 1]).getTime() - this.count))
                 //更新统计图
                 if (this.chart) {
                     this.chart.setOption({ xAxis: this.xAxis, series: this.series })
@@ -529,8 +603,85 @@ export default {
             })
         },
         /** 导出统计图数据 */
-        exportData() {
-            console.log("---导出统计图-----")
+        exportItemListData() {
+            if (this.chartForm.idList.length == 0) {
+                this.$message({
+                    message: '请选择数据项',
+                    type: 'warning'
+                })
+                return
+            }
+            let startTime;
+            let endTime;
+            if (this.chartForm.trendType == 0) {
+                if (!this.chartForm.frequencyValue) {
+                    this.$message({
+                        message: '频率不能为空',
+                        type: 'warning'
+                    })
+                    return
+                }
+                if (!this.chartForm.timeValue) {
+                    this.$message({
+                        message: '时间长度不能为空',
+                        type: 'warning'
+                    })
+                    return
+                }
+
+                let currentTime = new Date().getTime()
+                let count = this.timeCalculation(this.chartForm.timeValue, this.chartForm.timeType)
+                startTime = parseTime(new Date(currentTime - count))
+                endTime = parseTime(currentTime)
+                //如果为历史趋势
+            } else if (this.chartForm.trendType == 1) {
+                if (!this.chartForm.startTime) {
+                    this.$message({
+                        message: '请选择开始时间',
+                        type: 'warning'
+                    })
+                    return
+                }
+                if (!this.chartForm.endTime) {
+                    this.$message({
+                        message: '请选择结束时间',
+                        type: 'warning'
+                    })
+                    return
+                }
+                startTime = this.chartForm.startTime
+                endTime = this.chartForm.endTime
+            }
+            let param = {
+                itemGroupId: this.chartForm.itemGroupId,
+                idList: this.chartForm.idList,
+                startTime: startTime,
+                endTime: endTime
+            }
+            let params = qs.stringify(param, { arrayFormat: 'repeat' })
+            axios({
+                method: 'get',
+                url: '/itemGroup/exportItemListData?' + params,
+                responseType: 'blob'
+            }).then((res) => {
+                // 文件流
+                const blob = new Blob([res.data])
+                let url = window.URL.createObjectURL(blob)
+                let link = document.createElement("a")
+                link.style.display = "none"
+                link.href = url
+
+                // 取后端给前端返的请求头中的文件名称
+                const fileName = res.headers["content-disposition"].split(";")[1].split("filename=")[1];
+
+                link.download = fileName
+                document.body.appendChild(link);
+                link.click();
+                document.body.removeChild(link); //下载完成移除元素
+                window.URL.revokeObjectURL(url); //释放掉blob对象
+            }, (error) => {
+                return Promise.reject(error)
+            })
         }
     },
     destroyed: function () {

+ 53 - 74
industry-system/cqcy-ei-ua/src/main/java/com/example/opc_ua/util/OpcUaUtil.java

@@ -13,24 +13,22 @@ import com.example.opc_common.util.MathUtil;
 import com.example.opc_common.util.Result;
 import lombok.extern.slf4j.Slf4j;
 import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
-import org.eclipse.milo.opcua.sdk.client.api.config.OpcUaClientConfig;
 import org.eclipse.milo.opcua.sdk.client.api.identity.AnonymousProvider;
 import org.eclipse.milo.opcua.sdk.client.api.identity.UsernameProvider;
 import org.eclipse.milo.opcua.sdk.client.nodes.UaNode;
-import org.eclipse.milo.opcua.stack.client.DiscoveryClient;
 import org.eclipse.milo.opcua.stack.core.AttributeId;
 import org.eclipse.milo.opcua.stack.core.BuiltinDataType;
 import org.eclipse.milo.opcua.stack.core.Identifiers;
 import org.eclipse.milo.opcua.stack.core.UaException;
+import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy;
 import org.eclipse.milo.opcua.stack.core.types.builtin.*;
 import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
 import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UShort;
-import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned;
 import org.eclipse.milo.opcua.stack.core.types.enumerated.MonitoringMode;
 import org.eclipse.milo.opcua.stack.core.types.enumerated.NodeClass;
 import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn;
 import org.eclipse.milo.opcua.stack.core.types.structured.*;
-import org.eclipse.milo.opcua.stack.core.util.EndpointUtil;
+import org.springframework.beans.factory.annotation.Value;
 
 import java.math.BigDecimal;
 import java.nio.file.Files;
@@ -44,7 +42,8 @@ import java.util.stream.Collectors;
 @Slf4j
 public class OpcUaUtil {
 
-    private static final String certPath = "D:/opc/";
+    @Value("${certPath}")
+    private static String certPath;
 
     /**
      * 创建OPC UA客户端
@@ -52,48 +51,27 @@ public class OpcUaUtil {
      * @return
      */
     public static OpcUaClient createClient(DataSource dataSource) throws Exception {
-        String endpointUrl = "opc.tcp://" + dataSource.getIpAddress() + ":" + dataSource.getIpPort();
+        String endPointUrl = "opc.tcp://" + dataSource.getIpAddress() + ":" + dataSource.getIpPort();
         Path securityTempDir = Paths.get(certPath, "security");
 
         Files.createDirectories(securityTempDir);
         if (!Files.exists(securityTempDir)) {
-            log.info("无法创建安全目录: " + securityTempDir);
-            return null;
+            throw new Exception("无法创建安全目录: " + securityTempDir);
         }
-        KeyStoreLoader keyStoreLoader = new KeyStoreLoader();
-        KeyStoreLoader loader = keyStoreLoader.load(securityTempDir);
-        // 搜索OPC节点
-        List<EndpointDescription> endpoints = null;
-        EndpointDescription endpoint = null;
-        try {
-            endpoints = DiscoveryClient.getEndpoints(endpointUrl).get();
+        return OpcUaClient.create(endPointUrl,
+                endpoints ->
+                        endpoints.stream()
+                                .filter(e -> e.getSecurityPolicyUri().equals(SecurityPolicy.None.getUri()))
+                                .findFirst(),
+                configBuilder ->
+                        configBuilder
+                                .setApplicationName(LocalizedText.english(""))
+                                //如果不是匿名则获取账号和密码
+                                .setIdentityProvider(dataSource.getIsAnonymous() == ConstantStr.NOT_ANONYMOUS ? new UsernameProvider(dataSource.getDataSourceName(), dataSource.getIpPassword()) : new AnonymousProvider())
+                                .setRequestTimeout(UInteger.valueOf(5000))
+                                .build()
+        );
 
-//            endpoint = endpoints.stream()
-//                    .filter(e -> e.getSecurityPolicyUri().equals(SecurityPolicy.None.getUri())).filter(endpointFilter())
-//                    .findFirst().orElseThrow(() -> new Exception("no desired endpoints returned"));
-            endpoint = EndpointUtil.updateUrl(endpoints.get(0), dataSource.getIpAddress(), Integer.valueOf(dataSource.getIpPort()));
-        } catch (Throwable e) {
-            String discoveryUrl = endpointUrl;
-            if (!discoveryUrl.endsWith("/")) {
-                discoveryUrl += "/";
-            }
-            discoveryUrl += "discovery";
-            endpoints = DiscoveryClient.getEndpoints(discoveryUrl).get();
-            e.printStackTrace();
-        }
-//        EndpointDescription endpoint = endpoints.stream()
-//                .filter(e -> e.getSecurityPolicyUri().equals(SecurityPolicy.None.getUri())).filter(endpointFilter())
-//                .findFirst().orElseThrow(() -> new Exception("no desired endpoints returned"));
-        OpcUaClientConfig config = OpcUaClientConfig.builder()
-                .setApplicationName(LocalizedText.english("my"))
-                .setApplicationUri("urn:Jellyleo:UnifiedAutomation:UaExpert@Jellyleo")
-                .setCertificate(loader.getClientCertificate()).setKeyPair(loader.getClientKeyPair())
-                .setEndpoint(endpoint)
-                //如果不是匿名则获取账号和密码
-                .setIdentityProvider(dataSource.getIsAnonymous() == ConstantStr.NOT_ANONYMOUS ? new UsernameProvider(dataSource.getDataSourceName(), dataSource.getIpPassword()) : new AnonymousProvider())
-                .setRequestTimeout(Unsigned.uint(5000)).build();
-
-        return OpcUaClient.create(config);
     }
 
     private static Predicate<EndpointDescription> endpointFilter() {
@@ -119,6 +97,7 @@ public class OpcUaUtil {
             log.info("连接耗费时间为:" + (finish - start) + "毫秒");
             return Result.ok("测试连接成功");
         } catch (Exception e) {
+            e.printStackTrace();
             throw new CustomException(ResultEnum.REQUEST_TIME_OUT.getRespCode(), OpcUaUtil.genException(e.getMessage()));
         } finally {
             if (Blank.isNotEmpty(opcUaClient)) {
@@ -184,8 +163,9 @@ public class OpcUaUtil {
         List<JSONObject> jsonList = new ArrayList<>();
         List<? extends UaNode> nodes;
         if (uaNode == null) {
+            nodes = client.getAddressSpace().browseNodes(Identifiers.RootFolder);//从根目录
 //            nodes = client.getAddressSpace().browseNodes(Identifiers.ObjectsFolder);//从根目录
-            nodes = client.getAddressSpace().browseNodes(Identifiers.ViewsFolder);
+//            nodes = client.getAddressSpace().browseNodes(Identifiers.ViewsFolder);
         } else {
             nodes = client.getAddressSpace().browseNodes(uaNode);
         }
@@ -416,11 +396,6 @@ public class OpcUaUtil {
                 String itemId = split[i];
                 if (i == split.length - 1) {
                     for (UaNode nd : nodes) {
-//                        if (itemId.equals(nd.getNodeId().getIdentifier())) {
-//                            nodes = browserTree(client, nd);
-//                            jsonObject = genUaNode(nodes, itemStr.replace("!@", "."));
-//                            break;
-//                        }
                         if (itemId.equals(nd.getBrowseName().getName())) {
                             nodes = browserTree(client, nd);
                             jsonObject = genUaNode(nodes, itemStr.replace("!@", "."));
@@ -429,10 +404,6 @@ public class OpcUaUtil {
                     }
                 } else {
                     for (UaNode nd : nodes) {
-//                        if (itemId.equals(nd.getNodeId().getIdentifier())) {
-//                            nodes = browserTree(client, nd);
-//                            break;
-//                        }
                         if (itemId.equals(nd.getBrowseName().getName())) {
                             nodes = browserTree(client, nd);
                             break;
@@ -457,8 +428,6 @@ public class OpcUaUtil {
 //            return client.getAddressSpace().browseNodes(Identifiers.ViewsFolder);
             return client.getAddressSpace().browseNodes(Identifiers.ObjectsFolder);
         } else {
-//            List<? extends UaNode> uaNodes = client.getAddressSpace().browseNodes(uaNode);
-//            return uaNodes;
             return client.getAddressSpace().browseNodes(uaNode);
         }
     }
@@ -475,28 +444,38 @@ public class OpcUaUtil {
             NodeId nodeId = nd.getNodeId();
             UShort namespaceIndex = nodeId.getNamespaceIndex();
             if (nodeClass == NodeClass.Variable) {
-                if (namespaceIndex.intValue() == UShort.MIN_VALUE) {
-                    //是枝节点
-                    Map<String, Object> map = new HashMap<>();
-                    map.put("itemName", nd.getBrowseName().getName());
-                    map.put("nodeId", nd.getNodeId());
-                    map.put("nodeIndex", nd.getNodeId().getNamespaceIndex().intValue());
-                    map.put("dataType", nd.getNodeId().getType());
-                    map.put("description", nd.getDescription());
-                    mapList.add(map);
-                } else {
-                    //是叶节点,且叶节点才有数值类型,dataType
-                    Map<String, Object> map = new HashMap<>();
-                    String name = nd.getBrowseName().getName();
-                    map.put("fullPath", str + "." + name);
-                    map.put("itemName", name);
-                    map.put("itemReadName", str + "." + name);
+                Map<String, Object> map = new HashMap<>();
+                String name = nd.getBrowseName().getName();
+                map.put("fullPath", str + "." + name);
+                map.put("itemName", name);
+                map.put("itemReadName", str + "." + name);
 //                map.put("nodeId", nd.getNodeId());
-                    map.put("nodeIndex", nd.getNodeId().getNamespaceIndex().intValue());
-                    map.put("dataType", nd.getNodeId().getType());
-                    map.put("description", nd.getDescription());
-                    mapLeaveList.add(map);
-                }
+                map.put("nodeIndex", nd.getNodeId().getNamespaceIndex().intValue());
+                map.put("dataType", nd.getNodeId().getType());
+                map.put("description", nd.getDescription());
+                mapLeaveList.add(map);
+//                if (namespaceIndex.intValue() == UShort.MIN_VALUE) {
+//                    //是枝节点
+//                    Map<String, Object> map = new HashMap<>();
+//                    map.put("itemName", nd.getBrowseName().getName());
+//                    map.put("nodeId", nd.getNodeId());
+//                    map.put("nodeIndex", nd.getNodeId().getNamespaceIndex().intValue());
+//                    map.put("dataType", nd.getNodeId().getType());
+//                    map.put("description", nd.getDescription());
+//                    mapList.add(map);
+//                } else {
+//                    //是叶节点,且叶节点才有数值类型,dataType
+//                    Map<String, Object> map = new HashMap<>();
+//                    String name = nd.getBrowseName().getName();
+//                    map.put("fullPath", str + "." + name);
+//                    map.put("itemName", name);
+//                    map.put("itemReadName", str + "." + name);
+////                map.put("nodeId", nd.getNodeId());
+//                    map.put("nodeIndex", nd.getNodeId().getNamespaceIndex().intValue());
+//                    map.put("dataType", nd.getNodeId().getType());
+//                    map.put("description", nd.getDescription());
+//                    mapLeaveList.add(map);
+//                }
             } else {
                 //是枝节点
                 Map<String, Object> map = new HashMap<>();

+ 2 - 0
industry-system/cqcy-ei-ua/src/main/resources/application-dev.yml

@@ -1,6 +1,8 @@
 server:
   port: 8082
 
+certPath: D:/opc/
+
 spring:
   jackson:
     date-format: yyyy-MM-dd HH:mm:ss

+ 2 - 0
industry-system/cqcy-ei-ua/src/main/resources/application-prod.yml

@@ -1,6 +1,8 @@
 server:
   port: 8082
 
+certPath: D:/opc/
+
 spring:
   jackson:
     date-format: yyyy-MM-dd HH:mm:ss

+ 35 - 0
industry-system/cqcy-ei-ua/src/main/resources/application-test.yml

@@ -0,0 +1,35 @@
+server:
+  port: 8082
+
+certPath: /home/opc/
+
+spring:
+  jackson:
+    date-format: yyyy-MM-dd HH:mm:ss
+    time-zone: GMT+8
+  servlet:
+    multipart:
+      max-file-size: 100MB
+      max-request-size: 500MB
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://localhost:3306/in_data_db?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=GMT%2B8
+    username: root
+    password: root
+  resources:
+    static-locations: classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,file:${file.path},file:${file.location}
+  redis:
+    database: 0
+    host: 127.0.0.1
+    port: 6379
+    #    password: 123456
+    jedis:
+      pool:
+        max-active: 50
+        max-idle: 20
+        min-idle: 5
+    #        max-wait: 5
+
+#mybatis:
+#  configuration:
+#    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

+ 2 - 0
industry-system/industry-da/src/main/java/com/example/opc_da/config/InterceptorConfig.java

@@ -42,6 +42,8 @@ public class InterceptorConfig implements WebMvcConfigurer {
                 .excludePathPatterns("/influxdb/saveInFluxDBInfo")
                 .excludePathPatterns("/itemGroup/uploadModBusModel")
                 //针对大屏界面放行的请求
+                .excludePathPatterns("/itemGroup/getItemListLastValue")
+                .excludePathPatterns("/itemGroup/getItemListValue")
                 .excludePathPatterns("/mainRun/getMainRunPage")
                 .excludePathPatterns("/mainRun/getMainRunDataById")
                 .excludePathPatterns("/deviceRun/getDeviceRunPage")

+ 25 - 0
industry-system/industry-da/src/main/java/com/example/opc_da/controller/ItemGroupController.java

@@ -232,6 +232,17 @@ public class ItemGroupController {
     }
 
     /**
+     * 通过数据项id,获取相应的实时数据
+     *
+     * @param idList
+     * @return
+     */
+    @RequestMapping(value = "/getItemListLastValue", method = RequestMethod.GET)
+    public Result getItemListLastValue(@RequestParam List<Integer> idList) {
+        return itemGroupService.getItemListLastValue(idList);
+    }
+
+    /**
      * 通过数据项id,开始结束时间获取相应的数据
      *
      * @param idList
@@ -246,6 +257,20 @@ public class ItemGroupController {
     }
 
     /**
+     * 通过数据项id,开始结束时间获取相应的数据,并导出
+     *
+     * @param idList
+     * @param startTime
+     * @param endTime
+     * @return
+     */
+    @RequestMapping(value = "/exportItemListData", method = RequestMethod.GET)
+    public void exportItemListData(@RequestParam List<Integer> idList, @RequestParam String startTime,
+                                   @RequestParam String endTime, HttpServletResponse response) {
+        itemGroupService.exportItemListData(idList, startTime, endTime, response);
+    }
+
+    /**
      * 下载modbus导入模板
      */
     @GetMapping("uploadModBusModel")

+ 6 - 0
industry-system/industry-da/src/main/java/com/example/opc_da/service/ItemGroupService.java

@@ -4,6 +4,7 @@ import com.example.opc_common.entity.Item;
 import com.example.opc_common.entity.ItemGroup;
 import com.example.opc_common.util.Result;
 
+import javax.servlet.http.HttpServletResponse;
 import java.util.List;
 
 public interface ItemGroupService {
@@ -33,5 +34,10 @@ public interface ItemGroupService {
 
     Result getAllItemGroups();
 
+    Result getItemListLastValue(List<Integer> idList);
+
     Result getItemListValue(List<Integer> idList, String startTime, String endTime);
+
+    void exportItemListData(List<Integer> idList, String startTime, String endTime, HttpServletResponse response);
+
 }

+ 61 - 1
industry-system/industry-da/src/main/java/com/example/opc_da/service/impl/ItemGroupServiceImpl.java

@@ -1,5 +1,9 @@
 package com.example.opc_da.service.impl;
 
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.poi.excel.ExcelUtil;
+import cn.hutool.poi.excel.ExcelWriter;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.example.opc_common.entity.*;
@@ -19,7 +23,11 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.client.RestTemplate;
 
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
 import java.math.BigDecimal;
+import java.net.URLEncoder;
 import java.util.*;
 
 @Service
@@ -203,7 +211,7 @@ public class ItemGroupServiceImpl implements ItemGroupService {
         allItemList = (List<Item>) queryServiceUtil.exchangeData(allItemList);
         for (Item item : allItemList) {
             String dataValue = item.getDataValue();
-            if(Blank.isNotEmpty(dataValue)){
+            if (Blank.isNotEmpty(dataValue)) {
                 Integer itemId = item.getId();
                 DataModel dm = dmMap.get(itemId);
                 if (Blank.isNotEmpty(dm) && dm.getModelType().equals(ConstantStr.VALUE_REPLACE)) {
@@ -394,6 +402,14 @@ public class ItemGroupServiceImpl implements ItemGroupService {
     }
 
     @Override
+    public Result getItemListLastValue(List<Integer> idList) {
+        List<Item> itemList = itemGroupDao.getItemsParentByIdList(idList);
+        //从工具类中组装对应数据项的数据到集合中
+        itemList = (List<Item>) queryServiceUtil.exchangeData(itemList);
+        return Result.ok(itemList);
+    }
+
+    @Override
     public Result getItemListValue(List<Integer> idList, String startTime, String endTime) {
         List<Item> itemList = itemGroupDao.getItemsParentByIdList(idList);
         //从工具类中组装对应数据项的数据到集合中
@@ -404,4 +420,48 @@ public class ItemGroupServiceImpl implements ItemGroupService {
         );
         return Result.ok(itemList);
     }
+
+    @Override
+    public void exportItemListData(List<Integer> idList, String startTime, String endTime, HttpServletResponse response) {
+        List<Item> itemList = itemGroupDao.getItemsParentByIdList(idList);
+        //从工具类中组装对应数据项的数据到集合中
+        itemList = (List<Item>) queryServiceUtil.exchangeDatas(
+                DateUtil.strYmdhmsChangeDate(startTime),
+                DateUtil.strYmdhmsChangeDate(endTime),
+                itemList
+        );
+        List<List<String>> rows = new ArrayList<>();
+        List<String> header = CollUtil.newArrayList("时间", "数据项名称", "值");
+        rows.add(header);
+        if (Blank.isNotEmpty(itemList)) {
+            for (Item item : itemList) {
+                List<String> dataTimeList = item.getDataTimeList();
+                List<String> dataValueList = item.getDataValueList();
+                if (Blank.isNotEmpty(dataTimeList)) {
+                    for (int i = 0; i < dataTimeList.size() - 1; i++) {
+                        List<String> row = CollUtil.newArrayList(dataTimeList.get(i), item.getItemReadName(), dataValueList.get(i));
+                        rows.add(row);
+                    }
+                }
+            }
+        }
+        ServletOutputStream out = null;
+        ExcelWriter writer = null;
+        try {
+            writer = ExcelUtil.getWriter(true);
+            writer.write(rows, true);
+            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
+            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(new Date().getTime() + ".xlsx", "UTF-8"));
+            response.setHeader("Access-Control-Expose-Headers", "Content-disposition");
+            out = response.getOutputStream();
+            writer.flush(out, true);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        } finally {
+            if (writer != null) {
+                writer.close();
+            }
+            IoUtil.close(out);
+        }
+    }
 }

+ 1 - 1
industry-system/industry-da/src/main/resources/mapper/ItemGroupDao.xml

@@ -25,7 +25,7 @@
         <foreach collection="itemList" item="item" index="index" separator=",">
             (#{itemGroupId},#{item.itemName},#{item.itemReadName},if(#{item.itemType} is null, 1,
             #{item.itemType}),#{item.nodeIndex},#{item.dataType},
-            #{item.describe},#{item.dataModelId},#{item.isDriverItem}, #{item.modbusConfig})
+            #{item.describe},#{item.unit},#{item.dataModelId},#{item.isDriverItem}, #{item.modbusConfig})
         </foreach>
     </insert>
 

文件差异内容过多而无法显示
+ 1 - 1
industry-system/industry-da/src/main/resources/static/page/index.html


文件差异内容过多而无法显示
+ 0 - 0
industry-system/industry-da/src/main/resources/static/page/static/js/app.577b7abb.js


文件差异内容过多而无法显示
+ 0 - 0
industry-system/industry-da/src/main/resources/static/page/static/js/chunk-48625d50.02c45c15.js


文件差异内容过多而无法显示
+ 0 - 0
industry-system/industry-da/src/main/resources/static/page/static/js/chunk-4af4ab82.9cc116ec.js


文件差异内容过多而无法显示
+ 0 - 0
industry-system/industry-da/src/main/resources/static/page/static/js/chunk-6e808086.718d54d6.js


部分文件因为文件数量过多而无法显示