diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelMultipleSheetsUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelMultipleSheetsUtil.java new file mode 100644 index 00000000..5400e5d4 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelMultipleSheetsUtil.java @@ -0,0 +1,240 @@ +package com.ruoyi.common.utils.poi; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.ruoyi.common.annotation.Excel; +import com.ruoyi.common.utils.DictUtils; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Field; +import java.net.URLEncoder; +import java.util.Date; +import java.util.List; +import java.util.Map; + +public class ExcelMultipleSheetsUtil { + + /** + * 导出excel:可多个sheet页 + * + * @param data 数据:Map 集合【key == 每一个sheet页的名称,value == sheet页数据】 + * @param excelFileName excel文件名 + * @param suffixName 后缀名 + * @param response 响应 + * @throws IOException 异常 + */ + public static void excelMultipleSheets(Map data, String excelFileName, String suffixName, HttpServletResponse response) throws IOException { + // 创建工作簿 + try (Workbook workbook = new XSSFWorkbook()) { + for (Map.Entry entry : data.entrySet()) { + String sheetName = entry.getKey(); + Object sheetData = entry.getValue(); + Sheet sheet = workbook.createSheet(sheetName); + if (ObjectUtil.isNotEmpty(sheetData)) { + createSheetWithData(sheet, sheetData); + } + } + + setResponseHeader(response, excelFileName, suffixName); + // 写出文件 + workbook.write(response.getOutputStream()); + } + } + + /** + * 创建表单并填充数据 + * + * @param sheet 表单 + * @param data 数据 + */ + private static void createSheetWithData(Sheet sheet, Object data) { + if (data instanceof List) { + createSheetWithListData(sheet, (List) data); + } else { + createSheetWithObjectData(sheet, data); + } + } + + /** + * 创建列表类型数据对应的Excel表单 + * + * @param sheet 表单 + * @param dataList 数据列表 + */ + private static void createSheetWithListData(Sheet sheet, List dataList) { + if (CollUtil.isNotEmpty(dataList)) { + Object firstItem = dataList.get(0); + createHeaderRow(sheet, firstItem.getClass()); + int rowIndex = 1; + for (Object item : dataList) { + createDataRow(sheet, item, rowIndex++); + } + } + } + + /** + * 创建对象类型数据对应的Excel表单 + * + * @param sheet 表单 + * @param data 数据 + */ + private static void createSheetWithObjectData(Sheet sheet, Object data) { + createHeaderRow(sheet, data.getClass()); + createDataRow(sheet, data, 1); + } + + /** + * 创建表头行 + * + * @param sheet 表单 + * @param clazz 数据类 + */ + private static void createHeaderRow(Sheet sheet, Class clazz) { + // 创建单元格样式 + CellStyle headerCellStyle = createCellStyle(sheet.getWorkbook()); + + // 创建标题行 + Row headerRow = sheet.createRow(0); + Field[] fields = clazz.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + createHeaderCell(sheet, headerCellStyle, fields, headerRow, i); + } + } + + /** + * 创建数据行 + * + * @param sheet 表单 + * @param data 数据 + * @param rowIndex 行号 + */ + private static void createDataRow(Sheet sheet, Object data, int rowIndex) { + // 创建单元格样式 + CellStyle dataCellStyle = createCellStyle(sheet.getWorkbook()); + + // 创建数据行 + Row dataRow = sheet.createRow(rowIndex); + Field[] fields = data.getClass().getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + createDataCell(dataCellStyle, fields, dataRow, i, data); + } + } + + /** + * 创建单元格样式 + * + * @param workbook 工作簿 + * @return 单元格样式 + */ + private static CellStyle createCellStyle(Workbook workbook) { + CellStyle cellStyle = workbook.createCellStyle(); + + // 设置 水平和垂直 居中对齐 + cellStyle.setAlignment(HorizontalAlignment.CENTER); + cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); + + // 设置 上 下 左 右 边框及颜色 + cellStyle.setBorderTop(BorderStyle.THIN); + cellStyle.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + cellStyle.setBorderBottom(BorderStyle.THIN); + cellStyle.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + cellStyle.setBorderLeft(BorderStyle.THIN); + cellStyle.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + cellStyle.setBorderRight(BorderStyle.THIN); + cellStyle.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + + // 设置字体 + Font dataFont = workbook.createFont(); + dataFont.setFontName("Arial"); + dataFont.setFontHeightInPoints((short) 10); + cellStyle.setFont(dataFont); + + return cellStyle; + } + + /** + * 创建Excel表头单元格 + * + * @param sheet 表单 + * @param headerCellStyle 单元格样式 + * @param fields 字段 + * @param headerRow 标题行 + * @param i 序号 + */ + private static void createHeaderCell(Sheet sheet, CellStyle headerCellStyle, Field[] fields, Row headerRow, int i) { + // 默认宽度 + double width = 16; + Excel excelAnnotation = fields[i].getAnnotation(Excel.class); + if (excelAnnotation != null && !ObjectUtil.isEmpty(excelAnnotation.width())) { + width = excelAnnotation.width(); + } + + // 设置宽度 + sheet.setColumnWidth(i, (int) ((width + 0.72) * 256)); + + if (excelAnnotation != null) { + Cell cell = headerRow.createCell(i); + cell.setCellValue(excelAnnotation.name()); + cell.setCellStyle(headerCellStyle); + } + } + + /** + * 创建Excel数据单元格 + * + * @param dataCellStyle 单元格样式 + * @param fields 字段 + * @param dataRow 数据行 + * @param i 序号 + * @param data 数据 + */ + private static void createDataCell(CellStyle dataCellStyle, Field[] fields, Row dataRow, int i, Object data) { + Cell cell = dataRow.createCell(i); + cell.setCellStyle(dataCellStyle); + + try { + fields[i].setAccessible(true); + Object value = fields[i].get(data); + handleAnnotationAndSetValue(cell, fields[i], value); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + + /** + * 处理注解并设置单元格值 + * + * @param cell 单元格 + * @param field 字段 + * @param value 值 + */ + private static void handleAnnotationAndSetValue(Cell cell, Field field, Object value) { + if (field.isAnnotationPresent(Excel.class) && field.getAnnotation(Excel.class).dictType().length() > 0) { + value = DictUtils.getDictLabel(field.getAnnotation(Excel.class).dictType(), String.valueOf(value)); + } + if (field.isAnnotationPresent(Excel.class) && StrUtil.isNotEmpty(field.getAnnotation(Excel.class).dateFormat())) { + value = DateUtil.format(Convert.convert(Date.class, value), field.getAnnotation(Excel.class).dateFormat()); + } + cell.setCellValue(ObjectUtil.isEmpty(value) ? null : value.toString()); + } + + /** + * 设置响应头 + * + * @param response 响应 + * @param excelFileName 文件名 + * @param suffixName 后缀名 + * @throws UnsupportedEncodingException 编码异常 + */ + private static void setResponseHeader(HttpServletResponse response, String excelFileName, String suffixName) throws UnsupportedEncodingException { + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(excelFileName + suffixName, "utf-8")); + } + +} diff --git a/ruoyi-ui/src/api/deviceManage/device.js b/ruoyi-ui/src/api/deviceManage/device.js new file mode 100644 index 00000000..5d310ecc --- /dev/null +++ b/ruoyi-ui/src/api/deviceManage/device.js @@ -0,0 +1,53 @@ +import request from '@/utils/request' + +// 查询【请填写功能名称】列表 +export function listDevice(query) { + return request({ + url: '/business/device/list', + method: 'get', + params: query + }) +} + +// 查询【请填写功能名称】详细 +export function getDevice(id) { + return request({ + url: '/business/device/' + id, + method: 'get' + }) +} + +// 新增【请填写功能名称】 +export function addDevice(data) { + return request({ + url: '/business/device', + method: 'post', + data: data + }) +} + +// 修改【请填写功能名称】 +export function updateDevice(data) { + return request({ + url: '/business/device', + method: 'put', + data: data + }) +} + +// 删除【请填写功能名称】 +export function delDevice(id) { + return request({ + url: '/business/device/' + id, + method: 'delete' + }) +} + +// 导出【请填写功能名称】 +export function exportDevice(query) { + return request({ + url: '/business/device/export', + method: 'get', + params: query + }) +} diff --git a/ruoyi-ui/src/api/deviceManage/deviceOnline.js b/ruoyi-ui/src/api/deviceManage/deviceOnline.js new file mode 100644 index 00000000..0f7191b5 --- /dev/null +++ b/ruoyi-ui/src/api/deviceManage/deviceOnline.js @@ -0,0 +1,35 @@ +import request from '@/utils/request' + +export function deviceOnlineChart(query) { + return request({ + url: '/system/status/list', + method: 'get', + params: query + }) +} +// 查询产品列表 +export function deviceOnlineTable(query) { + return request({ + url: '/system/status/tablist', + method: 'get', + params: query + }) +} + +export function networkLogTable(query) { + return request({ + url: '/system/status//networkLogTable', + method: 'get', + params: query + }) +} + +export function networkLogEcharts(query){ + return request({ + url: '/system/status/networkLogEcharts', + method: 'get', + params: query + }) +} + + diff --git a/ruoyi-ui/src/api/deviceManage/product.js b/ruoyi-ui/src/api/deviceManage/product.js new file mode 100644 index 00000000..eb735f92 --- /dev/null +++ b/ruoyi-ui/src/api/deviceManage/product.js @@ -0,0 +1,53 @@ +import request from '@/utils/request' + +// 查询产品列表 +export function listProduct(query) { + return request({ + url: '/business/product/list', + method: 'get', + params: query + }) +} + +// 查询产品详细 +export function getProduct(id) { + return request({ + url: '/business/product/' + id, + method: 'get' + }) +} + +// 新增产品 +export function addProduct(data) { + return request({ + url: '/business/product', + method: 'post', + data: data + }) +} + +// 修改产品 +export function updateProduct(data) { + return request({ + url: '/business/product', + method: 'put', + data: data + }) +} + +// 删除产品 +export function delProduct(id) { + return request({ + url: '/business/product/' + id, + method: 'delete' + }) +} + +// 导出产品 +export function exportProduct(query) { + return request({ + url: '/business/product/export', + method: 'get', + params: query + }) +} diff --git a/ruoyi-ui/src/enum/deviceEnum.js b/ruoyi-ui/src/enum/deviceEnum.js new file mode 100644 index 00000000..f532a335 --- /dev/null +++ b/ruoyi-ui/src/enum/deviceEnum.js @@ -0,0 +1,185 @@ +let type =[ + { + name: '摄像机', + value: '1' + }, + { + name: '可变信息标志', + value: '2' + }, + { + name: '气象监测器', + value: '3' + }, + { + name: '出口诱导灯', + value: '4' + }, + { + name: '路段语音广播', + value: '5' + }, + { + name: '护栏碰撞', + value: '6' + }, + { + name: '毫米波雷达', + value: '7' + }, + { + name: '合流区预警', + value: '8' + }, + { + name: '智慧锥桶', + value: '9' + }, + { + name: '激光疲劳唤醒', + value: '10' + }, + { + name: '一类交通量调查站', + value: '11' + }, + { + name: '行车诱导', + value: '12' + }, + { + name: '智能设备箱', + value: '13' + }, + { + name: '光线在线监测', + value: '14' + } +] +let direction =[ + { + name: '菏泽方向', + value: '1' + }, + { + name: '双向', + value: '2' + }, + { + name: '济南方向', + value: '3' + } +] +let useState = [ + { + name: '停用', + value: 0 + }, + { + name: '在用', + value: 1 + } +] +let deviceState = [ + { + name: '异常', + value: '0' + }, + { + name: '正常', + value: '1' + } +] +let facilitiesTypeList = [ + { + label: '主干道', + value: '0' + }, + { + label: '服务区', + value: '1' + }, + { + label: '收费站', + value: '3' + } +] +let typeTree = [ + { + label: '高清网络枪型固定摄像机', + value: '1-1' + },{ + label: '高清网络球形摄像机', + value: '1-2' + }, { + label: '桥下高清网络球形摄像机', + value: '1-3' + }, { + label: '360°全景摄像机', + value: '1-4' + },{ + label: '180°全景摄像机', + value: '1-5' + },{ + label: '门架式可变信息标志', + value: '2-1' + }, { + label: '站前可变信息标志', + value: '2-2' + },{ + label: '雨棚可变信息标志', + value: '2-3' + }, { + label: '站前悬臂式可变信息标志', + value: '2-4' + }, { + label: '气象监测器', + value: '3' +},{ + label: '出口诱导灯', + value: '4' +}, { + label: '路段语音广播', + value: '5' +},{ + label: '护栏碰撞', + value: '6' +}, { + label: '毫米波雷达', + value: '7' +}, { + label: '合流区预警', + value: '8' +}, { + label: '智慧锥桶', + value: '9' +}, { + label: '激光疲劳唤醒', + value: '10' +},{ + label: '一类交通量调查站', + value: '11' +}, { + label: '行车诱导', + value: '12' +},{ + label: '智能设备箱', + value: '13' +}, { + label: '光线在线监测', + value: '14' +},{ + label: '太阳能板', + value: '15' +}, { + label: '远端机', + value: '16' +}] +export { + type, + direction, + useState, + deviceState, + facilitiesTypeList, + typeTree +} diff --git a/ruoyi-ui/src/views/deviceManage/device/index.vue b/ruoyi-ui/src/views/deviceManage/device/index.vue new file mode 100644 index 00000000..c60292a0 --- /dev/null +++ b/ruoyi-ui/src/views/deviceManage/device/index.vue @@ -0,0 +1,619 @@ + + + + diff --git a/ruoyi-ui/src/views/deviceManage/deviceOnline/index.vue b/ruoyi-ui/src/views/deviceManage/deviceOnline/index.vue new file mode 100644 index 00000000..aa840c25 --- /dev/null +++ b/ruoyi-ui/src/views/deviceManage/deviceOnline/index.vue @@ -0,0 +1,325 @@ + + + + + diff --git a/ruoyi-ui/src/views/deviceManage/deviceOnline/indexLine.vue b/ruoyi-ui/src/views/deviceManage/deviceOnline/indexLine.vue new file mode 100644 index 00000000..51496df7 --- /dev/null +++ b/ruoyi-ui/src/views/deviceManage/deviceOnline/indexLine.vue @@ -0,0 +1,177 @@ + + + + + diff --git a/ruoyi-ui/src/views/deviceManage/lineChart.vue b/ruoyi-ui/src/views/deviceManage/lineChart.vue new file mode 100644 index 00000000..1686e39a --- /dev/null +++ b/ruoyi-ui/src/views/deviceManage/lineChart.vue @@ -0,0 +1,172 @@ + + + + diff --git a/ruoyi-ui/src/views/deviceManage/mixins/resize.js b/ruoyi-ui/src/views/deviceManage/mixins/resize.js new file mode 100644 index 00000000..b1e76e94 --- /dev/null +++ b/ruoyi-ui/src/views/deviceManage/mixins/resize.js @@ -0,0 +1,56 @@ +import { debounce } from '@/utils' + +export default { + data() { + return { + $_sidebarElm: null, + $_resizeHandler: null + } + }, + mounted() { + this.initListener() + }, + activated() { + if (!this.$_resizeHandler) { + // avoid duplication init + this.initListener() + } + + // when keep-alive chart activated, auto resize + this.resize() + }, + beforeDestroy() { + this.destroyListener() + }, + deactivated() { + this.destroyListener() + }, + methods: { + // use $_ for mixins properties + // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential + $_sidebarResizeHandler(e) { + if (e.propertyName === 'width') { + this.$_resizeHandler() + } + }, + initListener() { + this.$_resizeHandler = debounce(() => { + this.resize() + }, 100) + window.addEventListener('resize', this.$_resizeHandler) + + this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0] + this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler) + }, + destroyListener() { + window.removeEventListener('resize', this.$_resizeHandler) + this.$_resizeHandler = null + + this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler) + }, + resize() { + const { chart } = this + chart && chart.resize() + } + } +} diff --git a/ruoyi-ui/src/views/deviceManage/product/index.vue b/ruoyi-ui/src/views/deviceManage/product/index.vue new file mode 100644 index 00000000..997f254f --- /dev/null +++ b/ruoyi-ui/src/views/deviceManage/product/index.vue @@ -0,0 +1,320 @@ + + + diff --git a/ruoyi-ui/src/views/deviceManage/typeTree.vue b/ruoyi-ui/src/views/deviceManage/typeTree.vue new file mode 100644 index 00000000..95cfebcd --- /dev/null +++ b/ruoyi-ui/src/views/deviceManage/typeTree.vue @@ -0,0 +1,229 @@ + + + + + diff --git a/zc-business/src/main/java/com/zc/business/controller/DcDeviceOnlineController.java b/zc-business/src/main/java/com/zc/business/controller/DcDeviceOnlineController.java index e48beea5..a86778a0 100644 --- a/zc-business/src/main/java/com/zc/business/controller/DcDeviceOnlineController.java +++ b/zc-business/src/main/java/com/zc/business/controller/DcDeviceOnlineController.java @@ -1,5 +1,6 @@ package com.zc.business.controller; +import cn.hutool.core.date.DateUtil; import cn.hutool.core.lang.tree.Tree; import com.alibaba.excel.util.DateUtils; import com.github.pagehelper.util.StringUtil; @@ -10,6 +11,7 @@ import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.poi.ExcelMultipleSheetsUtil; import com.ruoyi.common.utils.poi.ExcelUtil; import com.zc.business.constant.RedisKeyConstants; import com.zc.business.controller.queryParams.OnlineQueryParams; @@ -20,6 +22,7 @@ import com.zc.business.service.IOnlineLogService; import com.zc.business.service.IOnlineSumService; import com.zc.business.service.impl.DcDeviceServiceImpl; import com.zc.business.utils.MathUtil; +import eu.bitwalker.useragentutils.DeviceType; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.checkerframework.checker.units.qual.A; @@ -30,6 +33,7 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; +import java.io.IOException; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDate; @@ -56,21 +60,35 @@ public class DcDeviceOnlineController extends BaseController { private static final String ORDERRULE = "orderRule";//排序策略key - /*@ApiOperation("设备状态导出") + @ApiOperation("设备状态导出") @Log(title = "【设备状态导出】", businessType = BusinessType.EXPORT) @PostMapping("/export") - public void export(HttpServletResponse response, Status status) { - if (status.getDeviceName() != null) { - status.setDeviceName(status.getDeviceName().replaceAll(UniversalEnum.BLANK_SPACE.getValue(), UniversalEnum.PLUS_SIGN.getValue())); + public void export(HttpServletResponse response, OnlineQueryParams params) { + if(ObjectUtils.isEmpty(params.getType())) { + return; } - String type = status.getType(); - if (type != null) { - status.setTypes(type.split(UniversalEnum.COMMA.getValue())); + if(StringUtil.isEmpty(params.getOrderByField()) ||"time".equals(params.getOrderByField())) { + params.setOrderByField("online_rate"); + } + List sums = onlineSumService.queryByDeviceTypesOfToday(params); + Map> sumsMap = sums.stream().collect(Collectors.groupingBy(OnlineSum::getDeviceType)); + /*Map map = new HashMap<>(); + for(String deviceType:params.getType()){ + List list = sumsMap.getOrDefault(deviceType,new ArrayList<>()); + String typeName = DeviceType.getDescriptionByValue(deviceType); + if(StringUtil.isNotEmpty(typeName)) { + map.put(DeviceType.getDescriptionByValue(deviceType),list); + } } - List listStatus = statusService.export(status); - ExcelUtil util = new ExcelUtil<>(Status.class); - util.exportExcel(response, listStatus, UniversalEnum.DEVICE_STATUS_LIST.getValue()); - }*/ + try { + ExcelMultipleSheetsUtil.excelMultipleSheets(map,UniversalEnum.DEVICE_STATUS_LIST.getValue()+ DateUtil.format(new Date(), "yyyyMMddHHmmss"), + "xlsx", response); + } catch (IOException e) { + e.printStackTrace(); + }*/ + ExcelUtil util = new ExcelUtil<>(OnlineSum.class); + util.exportExcel(response, sums, UniversalEnum.DEVICE_STATUS_LIST.getValue()); + } @ApiOperation("设备状态列表按时间和类型") @GetMapping("/tablist") @@ -182,7 +200,7 @@ public class DcDeviceOnlineController extends BaseController { Map useCounts = useDeviceList.stream() .collect(Collectors.groupingBy(DcDevice::getRealType, Collectors.counting())); Map> typeSumGroup = onlineSums.stream().collect(Collectors.groupingBy(OnlineSum::getDeviceType)); - DeviceType.toMap().forEach((k,v) -> { + DeviceType.toMap().forEach((k, v) -> { Map itemMap = new HashMap<>(); itemMap.put(SUM,totalCounts.getOrDefault(k,0L).toString());//总数 itemMap.put(SUM_USE_STATE,useCounts.getOrDefault(k,0L).toString());//在用数 @@ -342,6 +360,14 @@ public class DcDeviceOnlineController extends BaseController { } return stringBuilder.toString(); } + static String getDescriptionByValue(String value) { + for (DeviceType type : DeviceType.values()) { + if (type.value.equals(value)) { + return type.description; + } + } + return ""; + } } } diff --git a/zc-business/src/main/java/com/zc/business/domain/OnlineSum.java b/zc-business/src/main/java/com/zc/business/domain/OnlineSum.java index 761997f0..3bc7c0b9 100644 --- a/zc-business/src/main/java/com/zc/business/domain/OnlineSum.java +++ b/zc-business/src/main/java/com/zc/business/domain/OnlineSum.java @@ -1,6 +1,7 @@ package com.zc.business.domain; import com.fasterxml.jackson.annotation.JsonFormat; +import com.ruoyi.common.annotation.Excel; import com.zc.business.enums.NetworkQuality; import org.springframework.format.annotation.DateTimeFormat; import java.math.BigDecimal; @@ -13,13 +14,19 @@ public class OnlineSum implements java.io.Serializable { private Long id;//id private Long deviceId;//设备ID private int totalCount;//当天总次数 + @Excel(name = "在线率") private double onlineRate;//在线率 + @Excel(name = "离线率") private double offlineRate;//离线率 + @Excel(name = "丢包率") private double lossRate;//丢包率 + @Excel(name = "平均时延") private double rttAvg;//平均往返时延 + @Excel(name = "网络质量") private String networkQuality;//网络质量 @DateTimeFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "统计日期", width = 30, dateFormat = "yyyy-MM-dd") private LocalDate statisticalDate;//统计日期 private int sendCount;//发送数据包总数 @@ -28,12 +35,17 @@ public class OnlineSum implements java.io.Serializable { private int totalOnlineCount;//当天总在线次数 private int totalOfflineCount;//当天总离线次数 private Long roadId; + @Excel(name = "设备名称") private String deviceName;//设备名称 + @Excel(name = "IP") private String deviceIp;//设备IP + @Excel(name = "桩号") private String stakeMark;//设备桩号 private String direction;//方向 private String deviceType;//设备类型 + @Excel(name = "设备状态") private String deviceStatus;//当前设备状态? + @Excel(name = "使用状态") private String useState; @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")