From 73fab0ad909909bcee385c6545be46d35b096b6c Mon Sep 17 00:00:00 2001 From: XMnhwj_BackTechnologyDevelopment <3512363680@qq.com> Date: Fri, 12 May 2023 11:47:18 +0800 Subject: [PATCH] =?UTF-8?q?2023-05-12=2011:23:36=20=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=E7=AE=A1=E7=90=86=E7=9A=84=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E3=80=81=E6=A8=A1=E6=9D=BF=E4=B8=8B=E8=BD=BD=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/psdc/entity/PsdcDevice.java | 27 +++- .../com/psdc/mapper/PsdcDeviceMapper.java | 2 + .../com/psdc/service/IPsdcDeviceService.java | 3 + .../service/impl/PsdcDeviceServiceImpl.java | 126 +++++++++++++----- .../mapper/business/PsdcDeviceMapper.xml | 11 ++ .../manager/PsdcDeviceController.java | 91 +++++++++++-- .../resources/template/AllDevicesData.xlsx | Bin 0 -> 9113 bytes 7 files changed, 218 insertions(+), 42 deletions(-) create mode 100644 psdc-web/src/main/resources/template/AllDevicesData.xlsx diff --git a/psdc-business/src/main/java/com/psdc/entity/PsdcDevice.java b/psdc-business/src/main/java/com/psdc/entity/PsdcDevice.java index 2b1e570..71fc46e 100644 --- a/psdc-business/src/main/java/com/psdc/entity/PsdcDevice.java +++ b/psdc-business/src/main/java/com/psdc/entity/PsdcDevice.java @@ -1,5 +1,6 @@ package com.psdc.entity; +import com.psdc.annotation.Excel; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -17,25 +18,43 @@ import java.util.Date; public class PsdcDevice { /** 设备id */ + @Excel(name = "设备Id", cellType = Excel.ColumnType.NUMERIC) private Integer deviceId ; /** 用户id */ private Integer userId ; + /** 用户名称 */ + @Excel(name = "用户名称") + private String userName ; + /** 设备类型:1-监测设备,2-运行设备 */ private Integer deviceType ; - /** 设备sn */ - private String deviceSn ; + /** 设备类型:1-监测设备,2-运行设备 */ + @Excel(name = "设备类型") + private String devType ; /** 设备名称 */ + @Excel(name = "设备名称") private String deviceName ; + /** 设备sn */ + @Excel(name = "设备Sn") + private String deviceSn ; /** 硬件版本 */ + @Excel(name = "硬件版本") private String hardVersion ; /** 软件版本 */ + @Excel(name = "软件版本") private String softVersion ; /** 安装地址 */ + @Excel(name = "安装地址") private String deviceAddress ; /** 启用时间 */ + @Excel(name = "启用时间") private String startTime ; + /** 设备状态:1-未激活,2-禁用,3-在线,4-离线 */ private Integer deviceStatus ; + /** 设备状态:1-未激活,2-禁用,3-在线,4-离线 */ + @Excel(name = "设备状态") + private String devStatus ; /** 图片地址 */ private String photoUrl ; /** 创建者 */ @@ -46,8 +65,12 @@ public class PsdcDevice { private String updateBy ; /** 修改时间 */ private Date updateTime ; + /** 设备运行状态:1-开启,2-关闭 */ private Integer deviceRunstatus ; + /** 设备运行状态:1-开启,2-关闭 */ + @Excel(name = "设备运行状态") + private String devRunstatus ; } diff --git a/psdc-business/src/main/java/com/psdc/mapper/PsdcDeviceMapper.java b/psdc-business/src/main/java/com/psdc/mapper/PsdcDeviceMapper.java index f52cab9..a1610ca 100644 --- a/psdc-business/src/main/java/com/psdc/mapper/PsdcDeviceMapper.java +++ b/psdc-business/src/main/java/com/psdc/mapper/PsdcDeviceMapper.java @@ -82,4 +82,6 @@ public interface PsdcDeviceMapper{ */ int updateDevRunStatusByDevId(@Param(value = "deviceId") Integer deviceId, @Param(value = "runStatus") Integer runStatus); + + void saveDevicesData(@Param(value = "devRecord") List devRecord); } \ No newline at end of file diff --git a/psdc-business/src/main/java/com/psdc/service/IPsdcDeviceService.java b/psdc-business/src/main/java/com/psdc/service/IPsdcDeviceService.java index 22e4d30..fee64de 100644 --- a/psdc-business/src/main/java/com/psdc/service/IPsdcDeviceService.java +++ b/psdc-business/src/main/java/com/psdc/service/IPsdcDeviceService.java @@ -2,6 +2,7 @@ package com.psdc.service; import com.psdc.entity.PsdcDevice; import com.psdc.entity.vo.DeviceStatusVo; +import org.springframework.web.multipart.MultipartFile; import java.util.HashMap; import java.util.List; @@ -63,6 +64,8 @@ public interface IPsdcDeviceService { */ boolean deleteById(Long[] deviceIds); + boolean daoruDevicesData(MultipartFile file); + /** * 更新设备状态 * @param deviceId diff --git a/psdc-business/src/main/java/com/psdc/service/impl/PsdcDeviceServiceImpl.java b/psdc-business/src/main/java/com/psdc/service/impl/PsdcDeviceServiceImpl.java index f5529da..264b392 100644 --- a/psdc-business/src/main/java/com/psdc/service/impl/PsdcDeviceServiceImpl.java +++ b/psdc-business/src/main/java/com/psdc/service/impl/PsdcDeviceServiceImpl.java @@ -13,16 +13,21 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; +import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; +import static org.springframework.transaction.annotation.Propagation.REQUIRES_NEW; + @Service @Slf4j -public class PsdcDeviceServiceImpl implements IPsdcDeviceService{ +public class PsdcDeviceServiceImpl implements IPsdcDeviceService { @Autowired private PsdcDeviceMapper psdcDeviceMapper; @@ -36,21 +41,21 @@ public class PsdcDeviceServiceImpl implements IPsdcDeviceService{ * @param deviceId 主键 * @return 实例对象 */ - public PsdcDevice queryById(Integer deviceId){ + public PsdcDevice queryById(Integer deviceId) { return psdcDeviceMapper.queryById(deviceId); } - /** * 根据用户id查询设备列表 + * * @return */ - public List queryByUserId(){ + public List queryByUserId() { return psdcDeviceMapper.queryByUserId(SecurityUtils.getUserId()); } - public List queryDeviceStatus(){ + public List queryDeviceStatus() { List psdcDevices = psdcDeviceMapper.queryByUserId(SecurityUtils.getUserId()); return psdcDevices.stream().map(psdcDevice -> { DeviceStatusVo deviceStatusVo = new DeviceStatusVo(); @@ -70,13 +75,20 @@ public class PsdcDeviceServiceImpl implements IPsdcDeviceService{ * @param psdcDevice 实例对象 * @return 实例对象 */ - public Integer insert(PsdcDevice psdcDevice){ + public Integer insert(PsdcDevice psdcDevice) { return psdcDeviceMapper.insert(psdcDevice); } @Override public List queryAllByLimit(PsdcDevice psdcDevice) { - return psdcDeviceMapper.queryAllByLimit(psdcDevice); + List list = psdcDeviceMapper.queryAllByLimit(psdcDevice); + for (PsdcDevice dev : list){ + dev.setDevType(s("t", dev.getDeviceType())); + dev.setDevStatus(s("s", dev.getDeviceStatus())); + dev.setDevRunstatus(s("r", dev.getDeviceRunstatus())); + } + + return list; } /** @@ -85,7 +97,7 @@ public class PsdcDeviceServiceImpl implements IPsdcDeviceService{ * @param psdcDevice 实例对象 * @return 实例对象 */ - public Integer update(PsdcDevice psdcDevice){ + public Integer update(PsdcDevice psdcDevice) { return psdcDeviceMapper.update(psdcDevice); } @@ -95,42 +107,59 @@ public class PsdcDeviceServiceImpl implements IPsdcDeviceService{ * @param deviceIds 主键 * @return 是否成功 */ - public boolean deleteById(Long[] deviceIds){ + public boolean deleteById(Long[] deviceIds) { int total = psdcDeviceMapper.deleteById(deviceIds); return total > 0; } + @Override + @Transactional(propagation = REQUIRES_NEW) + public boolean daoruDevicesData(MultipartFile file) { + try { + //需要将上传文件转成Stream流 + InputStream in = file.getInputStream(); + // EasyExcel.read(in, PsdcDevice.class, new DevicesDataListener(psdcDeviceMapper)).sheet().sheetNo(0).doRead(); + return true; + } catch (Exception e) { + e.printStackTrace(); + log.info("Sorry,导入设备数据失败!+ 错误原因: {}", e.getMessage()); + return false; + } + } + /** * 更新设备状态 + * * @param deviceId * @param runStatus * @return */ @Override public int updateDeviceRunStatus(Integer deviceId, Integer runStatus) { - return psdcDeviceMapper.updateDevRunStatusByDevId(deviceId,runStatus); + return psdcDeviceMapper.updateDevRunStatusByDevId(deviceId, runStatus); } /** * 控制设备启动停止 + * * @param deviceId * @param runStatus * @return */ @Override - public int controlDeviceStartAndStop(Integer deviceId, Integer runStatus,String controlBy,Integer controlMethod) { + public int controlDeviceStartAndStop(Integer deviceId, Integer runStatus, String controlBy, Integer controlMethod) { String value = ""; - if(runStatus == 1){ + if (runStatus == 1) { value = "启动"; - } else if ( runStatus == 2 ) { + } else if (runStatus == 2) { value = "停止"; } - log.info("设备id:{}",deviceId); + log.info("设备id:{}", deviceId); PsdcDevice psdcDevice = psdcDeviceMapper.queryById(deviceId); - if(psdcDevice == null){ - psdcControlLogMapper.insert(new PsdcControlLog(deviceId,null,null,"设备启停",value,controlMethod,3,"未找到该设备",controlBy)); + if (psdcDevice == null) { + psdcControlLogMapper.insert(new PsdcControlLog(deviceId, null, null, "设备启停", value, controlMethod, 3, "未找到该设备", controlBy)); throw new ControlException("控制失败,未找到该设备"); } @@ -138,27 +167,27 @@ public class PsdcDeviceServiceImpl implements IPsdcDeviceService{ // psdcControlLogMapper.insert(new PsdcControlLog(deviceId,psdcDevice.getDeviceName(),psdcDevice.getDeviceSn(),"设备启停",value,controlMethod,3,"手动控制,等待终端响应超时",controlBy)); //发送成功 - psdcControlLogMapper.insert(new PsdcControlLog(deviceId,psdcDevice.getDeviceName(),psdcDevice.getDeviceSn(),"设备启停",value,controlMethod,2,"手动控制,控制成功",controlBy)); - return psdcDeviceMapper.updateDevRunStatusByDevId(deviceId,runStatus); + psdcControlLogMapper.insert(new PsdcControlLog(deviceId, psdcDevice.getDeviceName(), psdcDevice.getDeviceSn(), "设备启停", value, controlMethod, 2, "手动控制,控制成功", controlBy)); + return psdcDeviceMapper.updateDevRunStatusByDevId(deviceId, runStatus); } @Override - public int setTemperature(Integer deviceId, List data, String controlBy,Integer controlMethod) { + public int setTemperature(Integer deviceId, List data, String controlBy, Integer controlMethod) { - log.info("设备id:{}",deviceId); - log.info("控制指令:{}",data); + log.info("设备id:{}", deviceId); + log.info("控制指令:{}", data); PsdcDevice psdcDevice = psdcDeviceMapper.queryById(deviceId); - if(psdcDevice == null){ - psdcControlLogMapper.insert(new PsdcControlLog(deviceId,null,null,"设定温度",null,controlMethod,3,"未找到该设备",controlBy)); + if (psdcDevice == null) { + psdcControlLogMapper.insert(new PsdcControlLog(deviceId, null, null, "设定温度", null, controlMethod, 3, "未找到该设备", controlBy)); throw new ControlException("控制失败,未找到该设备"); } AtomicInteger atomicInteger = new AtomicInteger(0); - for (Map map: data) { + for (Map map : data) { String controlKey = map.get("controlKey").toString(); String controlValue = map.get("controlValue").toString(); @@ -168,7 +197,7 @@ public class PsdcDeviceServiceImpl implements IPsdcDeviceService{ // psdcControlLogMapper.insert(new PsdcControlLog(deviceId,psdcDevice.getDeviceName(),psdcDevice.getDeviceSn(),controlContext,controlValue,controlMethod,3,"等待终端响应超时",controlBy)); //发送成功 - psdcControlLogMapper.insert(new PsdcControlLog(deviceId,psdcDevice.getDeviceName(),psdcDevice.getDeviceSn(),controlContext,controlValue,controlMethod,2,"控制成功",controlBy)); + psdcControlLogMapper.insert(new PsdcControlLog(deviceId, psdcDevice.getDeviceName(), psdcDevice.getDeviceSn(), controlContext, controlValue, controlMethod, 2, "控制成功", controlBy)); atomicInteger.incrementAndGet(); } return atomicInteger.get(); @@ -176,6 +205,7 @@ public class PsdcDeviceServiceImpl implements IPsdcDeviceService{ /** * 单条控制指令 + * * @param deviceId * @param key * @param value @@ -184,17 +214,17 @@ public class PsdcDeviceServiceImpl implements IPsdcDeviceService{ * @return */ @Override - public int setTemperature(Integer deviceId, String key,String value, String controlBy,Integer controlMethod) { + public int setTemperature(Integer deviceId, String key, String value, String controlBy, Integer controlMethod) { - log.info("设备id:{}",deviceId); - log.info("控制指令:{}",key); - log.info("控制内容:{}",value); + log.info("设备id:{}", deviceId); + log.info("控制指令:{}", key); + log.info("控制内容:{}", value); String controlContext = ControlKeyEnum.getControlContext(key); PsdcDevice psdcDevice = psdcDeviceMapper.queryById(deviceId); - if(psdcDevice == null){ - psdcControlLogMapper.insert(new PsdcControlLog(deviceId,null,null,controlContext,null,controlMethod,3,"未找到该设备",controlBy)); + if (psdcDevice == null) { + psdcControlLogMapper.insert(new PsdcControlLog(deviceId, null, null, controlContext, null, controlMethod, 3, "未找到该设备", controlBy)); throw new ControlException("控制失败,未找到该设备"); } @@ -204,7 +234,39 @@ public class PsdcDeviceServiceImpl implements IPsdcDeviceService{ // psdcControlLogMapper.insert(new PsdcControlLog(deviceId,psdcDevice.getDeviceName(),psdcDevice.getDeviceSn(),controlContext,value,controlMethod,3,"等待终端响应超时",controlBy)); //发送成功 - return psdcControlLogMapper.insert(new PsdcControlLog(deviceId,psdcDevice.getDeviceName(),psdcDevice.getDeviceSn(),controlContext,value,controlMethod,2,"控制成功",controlBy)); + return psdcControlLogMapper.insert(new PsdcControlLog(deviceId, psdcDevice.getDeviceName(), psdcDevice.getDeviceSn(), controlContext, value, controlMethod, 2, "控制成功", controlBy)); } + + private String s(String s, int i) { + switch (s) { + case "s": + switch (i) { + case 1: + return "未激活"; + case 2: + return "禁用"; + case 3: + return "在线"; + case 4: + return "离线"; + } + case "t": + switch (i) { + case 1: + return "监测设备"; + case 2: + return "运行设备"; + } + case "r": + switch (i) { + case 1: + return "开启"; + case 2: + return "关闭"; + } + default: + return s; + } + } } \ No newline at end of file diff --git a/psdc-business/src/main/resources/mapper/business/PsdcDeviceMapper.xml b/psdc-business/src/main/resources/mapper/business/PsdcDeviceMapper.xml index eea3970..a257fcc 100644 --- a/psdc-business/src/main/resources/mapper/business/PsdcDeviceMapper.xml +++ b/psdc-business/src/main/resources/mapper/business/PsdcDeviceMapper.xml @@ -213,6 +213,17 @@ #{updateTime}) + + Insert into psdc_device(user_id, device_type, device_sn, device_name, hard_version, soft_version, + device_address, start_time, device_status, device_runstatus, photo_url, create_by, + create_time, update_by, update_time) + Values + + (NULL, #{entity.deviceType}, #{entity.deviceSn}, #{entity.deviceName}, #{entity.hardVersion}, #{entity.softVersion}, #{entity.deviceAddress}, + #{entity.startTime}, #{entity.deviceStatus}, #{entity.deviceRunstatus}, #{entity.photoUrl}, #{entity.createBy}, #{entity.createTime}, NULL, NULL) + + + update psdc_device diff --git a/psdc-web/src/main/java/com/psdc/controller/manager/PsdcDeviceController.java b/psdc-web/src/main/java/com/psdc/controller/manager/PsdcDeviceController.java index 906acea..6fa3511 100644 --- a/psdc-web/src/main/java/com/psdc/controller/manager/PsdcDeviceController.java +++ b/psdc-web/src/main/java/com/psdc/controller/manager/PsdcDeviceController.java @@ -1,25 +1,34 @@ package com.psdc.controller.manager; -import com.alibaba.fastjson2.JSON; + import com.alibaba.fastjson2.JSONObject; -import com.github.pagehelper.page.PageMethod; import com.psdc.annotation.Log; import com.psdc.core.controller.BaseController; import com.psdc.core.domain.AjaxResult; import com.psdc.core.domain.entity.SysUser; import com.psdc.core.page.TableDataInfo; -import com.psdc.entity.PsdcControlLog; import com.psdc.entity.PsdcDevice; import com.psdc.enums.BusinessType; import com.psdc.service.IPsdcDeviceService; import com.psdc.service.ISysUserService; import com.psdc.utils.SecurityUtils; -import org.apache.commons.lang3.ArrayUtils; +import com.psdc.utils.poi.ExcelUtil; +import org.apache.poi.xssf.usermodel.XSSFCell; +import org.apache.poi.xssf.usermodel.XSSFRow; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletResponse; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.util.*; /** @@ -80,17 +89,83 @@ public class PsdcDeviceController extends BaseController { map.put("value", dd.getUserId()); maps.add(map); } - return AjaxResult.success("用户下来列表", maps); + return AjaxResult.success("用户下拉列表", maps); } @PreAuthorize("@ss.hasPermi('manager:device:list')") - @PostMapping("/devicesList") + @RequestMapping(value = "/devicesList", method = RequestMethod.POST) public TableDataInfo controlLogList(@RequestBody JSONObject jsonObject) { - // PageMethod.startPage(jsonObject.getInteger("pageNum"),jsonObject.getInteger("pageSize")); - // PsdcDevice deviceVo = JSON.parseObject(String.valueOf(jsonObject), PsdcDevice.class); + // PageMethod.startPage(jsonObject.getInteger("pageNum"),jsonObject.getInteger("pageSize")); + // PsdcDevice deviceVo = JSON.parseObject(String.valueOf(jsonObject), PsdcDevice.class); PsdcDevice deviceVo = myPage(jsonObject, PsdcDevice.class); List list = psdcDeviceService.queryAllByLimit(deviceVo); return getDataTable(list); } + /** + excel文件的下载 + */ + @PreAuthorize("@ss.hasPermi('manager:device:list')") + @Log(title = "设备管理", businessType = BusinessType.EXPORT) + @RequestMapping(value = "/daochuDevs", method = RequestMethod.POST) + public void daochuDevDta(HttpServletResponse response, @RequestBody PsdcDevice pd) { + List list = psdcDeviceService.queryAllByLimit(pd); + for (PsdcDevice dev : list){ + dev.setUserName(sysUserService.selectUserById(Long.valueOf(dev.getUserId())).getUserName()); + } + ExcelUtil util = new ExcelUtil<>(PsdcDevice.class); + util.exportExcel(response, list, "角色数据"); + } + + /** + * 下载设备信息模板 + * @param response + */ + @PreAuthorize("@ss.hasPermi('manager:device:list')") + @Log(title = "设备管理", businessType = BusinessType.EXPORT) + @RequestMapping(value = "/downloadDevTemplate", method = RequestMethod.GET) + public void downloadTemplate(HttpServletResponse response) { + // 获取要下载的模板名称 + String fileName = "devTemplate.xlsx"; + // 设置要下载的文件的名称 + response.setHeader("Content-Disposition", "attachment;fileName=" + fileName); + // 通知客服文件的MIME类型 + response.setContentType("application/vnd.ms-template;charset=UTF-8"); + // 获取文件的路径 + try (InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("template/AllDevicesData.xlsx")) { + //读取excel模板 + XSSFWorkbook wb = new XSSFWorkbook(inputStream); + wb.setSelectedTab(1); + XSSFSheet sheet = wb.createSheet("设备类型表"); + XSSFRow row0 = sheet.createRow(0); + XSSFRow row1 = sheet.createRow(1); + XSSFRow row2 = sheet.createRow(2); + row0.createCell(0).setCellValue("设备类型Id"); + row0.createCell(1).setCellValue("设备类型名称"); + row1.createCell(0).setCellValue("1"); + row1.createCell(1).setCellValue("监测设备"); + row2.createCell(0).setCellValue("2"); + row2.createCell(1).setCellValue("运行设备"); + + + OutputStream os = new BufferedOutputStream(response.getOutputStream()); + wb.write(os); + os.flush(); + os.close(); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException("下载设备模板出错"); + } + } + + /** + excel文件的读取 + */ + @RequestMapping("/daoruDevData") + @PreAuthorize("hasAuthority('addevice')") + @Transactional(rollbackFor = Exception.class) + public AjaxResult daoruDevData(@RequestPart("file") MultipartFile file) { + return toAjax(psdcDeviceService.daoruDevicesData(file)); + } + } diff --git a/psdc-web/src/main/resources/template/AllDevicesData.xlsx b/psdc-web/src/main/resources/template/AllDevicesData.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..71c6db9475b3985b6c78d2822492982d820bfa9c GIT binary patch literal 9113 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