Przeglądaj źródła

1、设备升级包服务页面实现暂存

liweimin 1 dzień temu
rodzic
commit
152d9c1ac1

+ 115 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/device/DeviceUpgradePackageController.java

@@ -0,0 +1,115 @@
+package com.ruoyi.web.controller.device;
+
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.device.domain.entity.DeviceUpgradePackage;
+import com.ruoyi.device.service.IDeviceUpgradePackageService;
+import jakarta.annotation.Resource;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 设备升级包管理 Controller
+ *
+ * @author lwm
+ */
+@RestController
+@RequestMapping("/tsb/upgradePackage")
+public class DeviceUpgradePackageController extends BaseController
+{
+    @Resource
+    private IDeviceUpgradePackageService deviceUpgradePackageService;
+
+    /**
+     * 分页查询升级包列表
+     */
+    @PreAuthorize("@ss.hasPermi('tsb:upgradePackage:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(DeviceUpgradePackage query)
+    {
+        startPage();
+        List<DeviceUpgradePackage> list = deviceUpgradePackageService.selectDeviceUpgradePackageList(query);
+        return getDataTable(list);
+    }
+
+    /**
+     * 根据ID获取升级包详情
+     */
+    @PreAuthorize("@ss.hasPermi('tsb:upgradePackage:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable Long id)
+    {
+        return success(deviceUpgradePackageService.selectDeviceUpgradePackageById(id));
+    }
+
+    /**
+     * 新增设备升级包
+     */
+    @PreAuthorize("@ss.hasPermi('tsb:upgradePackage:add')")
+    @Log(title = "设备升级包", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody DeviceUpgradePackage deviceUpgradePackage)
+    {
+        // 校验版本号唯一性
+        if (!deviceUpgradePackageService.checkAppVersionUnique(deviceUpgradePackage))
+        {
+            return error("该设备类型下相同固件类型的版本号已存在");
+        }
+        deviceUpgradePackage.setCreateBy(getUsername());
+        return toAjax(deviceUpgradePackageService.insertDeviceUpgradePackage(deviceUpgradePackage));
+    }
+
+    /**
+     * 修改设备升级包
+     */
+    @PreAuthorize("@ss.hasPermi('tsb:upgradePackage:edit')")
+    @Log(title = "设备升级包", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody DeviceUpgradePackage deviceUpgradePackage)
+    {
+        // 校验版本号唯一性
+        if (!deviceUpgradePackageService.checkAppVersionUnique(deviceUpgradePackage))
+        {
+            return error("该设备类型下相同固件类型的版本号已存在");
+        }
+        deviceUpgradePackage.setUpdateBy(getUsername());
+        return toAjax(deviceUpgradePackageService.updateDeviceUpgradePackage(deviceUpgradePackage));
+    }
+
+    /**
+     * 状态修改(列表开关)
+     */
+    @PreAuthorize("@ss.hasPermi('tsb:upgradePackage:edit')")
+    @Log(title = "设备升级包", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeStatus")
+    public AjaxResult changeStatus(@RequestBody DeviceUpgradePackage deviceUpgradePackage)
+    {
+        if (deviceUpgradePackage.getId() == null)
+        {
+            return error("ID不能为空");
+        }
+        if (deviceUpgradePackage.getStatus() == null)
+        {
+            return error("状态不能为空");
+        }
+        deviceUpgradePackage.setUpdateBy(getUsername());
+        return toAjax(deviceUpgradePackageService.updateDeviceUpgradePackageStatus(deviceUpgradePackage));
+    }
+
+    /**
+     * 删除设备升级包(逻辑删除,支持批量)
+     */
+    @PreAuthorize("@ss.hasPermi('tsb:upgradePackage:remove')")
+    @Log(title = "设备升级包", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(deviceUpgradePackageService.deleteDeviceUpgradePackageByIds(ids));
+    }
+}

+ 3 - 3
ruoyi-admin/src/main/java/com/ruoyi/web/controller/device/TsbDeviceController.java

@@ -11,8 +11,8 @@ import com.ruoyi.device.domain.entity.TsbDevice;
 import com.ruoyi.device.domain.model.TsbUserDeviceBind;
 import com.ruoyi.device.service.ITsbDeviceService;
 import com.ruoyi.device.service.ITsbUserDeviceService;
+import jakarta.annotation.Resource;
 import jakarta.servlet.http.HttpServletResponse;
-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.*;
@@ -28,10 +28,10 @@ import java.util.List;
 @RequestMapping("/tsb/device")
 public class TsbDeviceController extends BaseController
 {
-    @Autowired
+    @Resource
     private ITsbDeviceService tsbDeviceService;
 
-    @Autowired
+    @Resource
     private ITsbUserDeviceService tsbUserDeviceService;
 
     /**

+ 10 - 0
ruoyi-device/src/main/java/com/ruoyi/device/domain/entity/DeviceUpgradePackage.java

@@ -1,6 +1,9 @@
 package com.ruoyi.device.domain.entity;
 
 import com.ruoyi.common.core.domain.BaseEntity;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
 
@@ -51,6 +54,8 @@ public class DeviceUpgradePackage extends BaseEntity
         this.id = id;
     }
 
+    @NotBlank(message = "设备类型不能为空")
+    @Size(max = 32, message = "设备类型长度不能超过32个字符")
     public String getDeviceType()
     {
         return deviceType;
@@ -61,6 +66,8 @@ public class DeviceUpgradePackage extends BaseEntity
         this.deviceType = deviceType;
     }
 
+    @NotBlank(message = "软件版本号不能为空")
+    @Size(max = 32, message = "软件版本号长度不能超过32个字符")
     public String getAppVersion()
     {
         return appVersion;
@@ -71,6 +78,7 @@ public class DeviceUpgradePackage extends BaseEntity
         this.appVersion = appVersion;
     }
 
+    @NotBlank(message = "下载地址不能为空")
     public String getDownloadUrl()
     {
         return downloadUrl;
@@ -91,6 +99,7 @@ public class DeviceUpgradePackage extends BaseEntity
         this.status = status;
     }
 
+    @NotNull(message = "升级包类型不能为空")
     public Integer getType()
     {
         return type;
@@ -101,6 +110,7 @@ public class DeviceUpgradePackage extends BaseEntity
         this.type = type;
     }
 
+    @NotNull(message = "固件类型不能为空")
     public Integer getFirmwareType()
     {
         return firmwareType;

+ 27 - 0
ruoyi-device/src/main/java/com/ruoyi/device/mapper/DeviceUpgradePackageMapper.java

@@ -13,4 +13,31 @@ public interface DeviceUpgradePackageMapper
      * 按状态、设备类型、升级包类型、固件类型、版本号 查询升级包列表
      */
     List<DeviceUpgradePackage> selectDeviceUpgradePackageList(DeviceUpgradePackage query);
+
+    /**
+     * 按主键查询升级包
+     */
+    DeviceUpgradePackage selectDeviceUpgradePackageById(Long id);
+
+    /**
+     * 校验版本号唯一性(同一设备类型+固件类型+升级包类型下 是否存在相同版本号)
+     */
+    DeviceUpgradePackage checkAppVersionUnique(DeviceUpgradePackage deviceUpgradePackage);
+
+    /**
+     * 新增设备升级包
+     */
+    int insertDeviceUpgradePackage(DeviceUpgradePackage deviceUpgradePackage);
+
+    /**
+     * 修改设备升级包
+     */
+    int updateDeviceUpgradePackage(DeviceUpgradePackage deviceUpgradePackage);
+
+    /**
+     * 根据ID逻辑删除设备升级包
+     */
+    int deleteDeviceUpgradePackageByIds(Long[] ids);
+
+
 }

+ 55 - 1
ruoyi-device/src/main/java/com/ruoyi/device/service/IDeviceUpgradePackageService.java

@@ -6,12 +6,66 @@ import java.util.List;
 
 /**
  * 设备升级包服务(查询 tb_device_upgrade_package)
+ *
+ * @author lwm
  */
 public interface IDeviceUpgradePackageService
 {
     /**
-     * 查询升级包列表
+     * 根据条件分页查询升级包列表
+     *
+     * @param query 查询参数
+     * @return 升级包列表
      */
     List<DeviceUpgradePackage> selectDeviceUpgradePackageList(DeviceUpgradePackage query);
 
+    /**
+     * 根据ID查询升级包(未删除)
+     *
+     * @param id 升级包ID
+     * @return 升级包信息
+     */
+    DeviceUpgradePackage selectDeviceUpgradePackageById(Long id);
+
+    /**
+     * 校验版本号唯一性(未删除的记录范围内)
+     * (同一设备类型+固件类型+升级包类型下 版本号不能重复)
+     *
+     * @param deviceUpgradePackage 设备升级包信息
+     * @return 结果
+     */
+    boolean checkAppVersionUnique(DeviceUpgradePackage deviceUpgradePackage);
+
+    /**
+     * 新增设备升级包
+     *
+     * @param deviceUpgradePackage 设备升级包信息
+     * @return 结果
+     */
+    int insertDeviceUpgradePackage(DeviceUpgradePackage deviceUpgradePackage);
+
+    /**
+     * 修改设备升级包
+     *
+     * @param deviceUpgradePackage 设备升级包信息
+     * @return 结果
+     */
+    int updateDeviceUpgradePackage(DeviceUpgradePackage deviceUpgradePackage);
+
+    /**
+     * 修改升级包状态(列表开关,仅需 id、status)
+     *
+     * @param deviceUpgradePackage 设备升级包信息
+     * @return 结果
+     */
+    int updateDeviceUpgradePackageStatus(DeviceUpgradePackage deviceUpgradePackage);
+
+    /**
+     * 批量逻辑删除设备升级包
+     *
+     * @param ids 需要删除的设备升级包ID
+     * @return 结果
+     */
+    int deleteDeviceUpgradePackageByIds(Long[] ids);
+
 }

+ 59 - 0
ruoyi-device/src/main/java/com/ruoyi/device/service/impl/DeviceUpgradePackageServiceImpl.java

@@ -1,5 +1,7 @@
 package com.ruoyi.device.service.impl;
 
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.device.domain.entity.DeviceUpgradePackage;
 import com.ruoyi.device.mapper.DeviceUpgradePackageMapper;
 import com.ruoyi.device.service.IDeviceUpgradePackageService;
@@ -7,11 +9,14 @@ import jakarta.annotation.Resource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.util.List;
 
 /**
  * 设备升级包服务实现
+ *
+ * @author lwm
  */
 @Service
 public class DeviceUpgradePackageServiceImpl implements IDeviceUpgradePackageService
@@ -27,4 +32,58 @@ public class DeviceUpgradePackageServiceImpl implements IDeviceUpgradePackageSer
         return deviceUpgradePackageMapper.selectDeviceUpgradePackageList(query);
     }
 
+    @Override
+    public DeviceUpgradePackage selectDeviceUpgradePackageById(Long id)
+    {
+        return deviceUpgradePackageMapper.selectDeviceUpgradePackageById(id);
+    }
+
+    @Override
+    public boolean checkAppVersionUnique(DeviceUpgradePackage deviceUpgradePackage)
+    {
+        Long id = StringUtils.isNull(deviceUpgradePackage.getId()) ? -1L : deviceUpgradePackage.getId();
+        DeviceUpgradePackage info = deviceUpgradePackageMapper.checkAppVersionUnique(deviceUpgradePackage);
+        if (StringUtils.isNotNull(info) && info.getId().longValue() != id.longValue())
+        {
+            return UserConstants.NOT_UNIQUE;
+        }
+        return UserConstants.UNIQUE;
+    }
+
+    @Override
+    @Transactional
+    public int insertDeviceUpgradePackage(DeviceUpgradePackage deviceUpgradePackage)
+    {
+        if (deviceUpgradePackage.getStatus() == null)
+        {
+            deviceUpgradePackage.setStatus(0);
+        }
+        return deviceUpgradePackageMapper.insertDeviceUpgradePackage(deviceUpgradePackage);
+    }
+
+    @Override
+    @Transactional
+    public int updateDeviceUpgradePackage(DeviceUpgradePackage deviceUpgradePackage)
+    {
+        return deviceUpgradePackageMapper.updateDeviceUpgradePackage(deviceUpgradePackage);
+    }
+
+    @Override
+    @Transactional
+    public int updateDeviceUpgradePackageStatus(DeviceUpgradePackage deviceUpgradePackage)
+    {
+        return deviceUpgradePackageMapper.updateDeviceUpgradePackage(deviceUpgradePackage);
+    }
+
+    @Override
+    @Transactional
+    public int deleteDeviceUpgradePackageByIds(Long[] ids)
+    {
+        if (StringUtils.isEmpty(ids))
+        {
+            return 0;
+        }
+        return deviceUpgradePackageMapper.deleteDeviceUpgradePackageByIds(ids);
+    }
+
 }

+ 4 - 4
ruoyi-device/src/main/java/com/ruoyi/device/service/impl/TsbDeviceServiceImpl.java

@@ -12,7 +12,7 @@ import com.ruoyi.device.mqtt.enums.DeviceLineStatusEnum;
 import com.ruoyi.device.mqtt.handler.DeviceOnlineManager;
 import com.ruoyi.device.mqtt.vo.DeviceOnlineInfo;
 import com.ruoyi.device.service.ITsbDeviceService;
-import org.springframework.beans.factory.annotation.Autowired;
+import jakarta.annotation.Resource;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -26,13 +26,13 @@ import java.util.List;
 @Service
 public class TsbDeviceServiceImpl implements ITsbDeviceService
 {
-    @Autowired
+    @Resource
     private TsbDeviceMapper tsbDeviceMapper;
 
-    @Autowired
+    @Resource
     private TsbUserDeviceMapper tsbUserDeviceMapper;
 
-    @Autowired
+    @Resource
     private DeviceOnlineManager deviceOnlineManager;
 
     /**

+ 76 - 1
ruoyi-device/src/main/resources/mapper/device/DeviceUpgradePackageMapper.xml

@@ -11,13 +11,16 @@
         <result property="type" column="type"/>
         <result property="firmwareType" column="firmware_type"/>
         <result property="remark" column="remark"/>
+        <result property="createBy" column="create_by"/>
         <result property="createTime" column="create_time"/>
+        <result property="updateBy" column="update_by"/>
         <result property="updateTime" column="update_time"/>
     </resultMap>
 
     <select id="selectDeviceUpgradePackageList" parameterType="com.ruoyi.device.domain.entity.DeviceUpgradePackage"
             resultMap="DeviceUpgradePackageResult">
-        select id, device_type, app_version, download_url, status, type, firmware_type, remark, create_time, update_time
+        select id, device_type, app_version, download_url, status, type, firmware_type, remark,
+               create_by, create_time, update_by, update_time
         from tb_device_upgrade_package
         where del_flag = '0'
         <if test="status != null">
@@ -38,4 +41,76 @@
         order by create_time desc, id desc
     </select>
 
+    <select id="selectDeviceUpgradePackageById" parameterType="Long" resultMap="DeviceUpgradePackageResult">
+        select id, device_type, app_version, download_url, status, type, firmware_type, remark,
+               create_by, create_time, update_by, update_time
+        from tb_device_upgrade_package
+        where id = #{id} and del_flag = '0'
+    </select>
+
+    <select id="checkAppVersionUnique" parameterType="com.ruoyi.device.domain.entity.DeviceUpgradePackage"
+            resultMap="DeviceUpgradePackageResult">
+        select id, device_type, app_version, download_url, status, type, firmware_type, remark,
+                create_by, create_time, update_by, update_time
+        from tb_device_upgrade_package
+        where del_flag = '0'
+            and device_type = #{deviceType}
+            and type = #{type}
+            and firmware_type = #{firmwareType}
+            and app_version = #{appVersion}
+        limit 1
+    </select>
+
+    <insert id="insertDeviceUpgradePackage" parameterType="com.ruoyi.device.domain.entity.DeviceUpgradePackage"
+            useGeneratedKeys="true" keyProperty="id">
+        insert into tb_device_upgrade_package
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="deviceType != null and deviceType != ''">device_type,</if>
+            <if test="appVersion != null and appVersion != ''">app_version,</if>
+            <if test="downloadUrl != null and downloadUrl != ''">download_url,</if>
+            <if test="status != null">status,</if>
+            <if test="type != null">type,</if>
+            <if test="firmwareType != null">firmware_type,</if>
+            <if test="remark != null and remark != ''">remark,</if>
+            <if test="createBy != null and createBy != ''">create_by,</if>
+            create_time
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="deviceType != null and deviceType != ''">#{deviceType},</if>
+            <if test="appVersion != null and appVersion != ''">#{appVersion},</if>
+            <if test="downloadUrl != null and downloadUrl != ''">#{downloadUrl},</if>
+            <if test="status != null">#{status},</if>
+            <if test="type != null">#{type},</if>
+            <if test="firmwareType != null">#{firmwareType},</if>
+            <if test="remark != null and remark != ''">#{remark},</if>
+            <if test="createBy != null and createBy != ''">#{createBy},</if>
+            sysdate()
+        </trim>
+    </insert>
+
+    <update id="updateDeviceUpgradePackage" parameterType="com.ruoyi.device.domain.entity.DeviceUpgradePackage">
+        update tb_device_upgrade_package
+        <set>
+            <if test="deviceType != null and deviceType != ''">device_type = #{deviceType},</if>
+            <if test="appVersion != null and appVersion != ''">app_version = #{appVersion},</if>
+            <if test="downloadUrl != null and downloadUrl != ''">download_url = #{downloadUrl},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="type != null">type = #{type},</if>
+            <if test="firmwareType != null">firmware_type = #{firmwareType},</if>
+            <if test="remark != null and remark != ''">remark = #{remark},</if>
+            <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
+            update_time = sysdate()
+        </set>
+        where id = #{id} and del_flag = '0'
+    </update>
+
+    <update id="deleteDeviceUpgradePackageByIds">
+        update tb_device_upgrade_package set del_flag = '2', update_time = sysdate()
+        where id in
+        <foreach collection="array" item="id" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+        and del_flag = '0'
+    </update>
+
 </mapper>

+ 65 - 0
ruoyi-ui/src/api/tsb/upgradePackage.js

@@ -0,0 +1,65 @@
+import request from '@/utils/request'
+
+/**
+ * 分页查询设备升级包列表
+ */
+export function listUpgradePackage(query) {
+  return request({
+    url: '/tsb/upgradePackage/list',
+    method: 'get',
+    params: query
+  })
+}
+
+/**
+ * 根据ID获取升级包详情
+ */
+export function getUpgradePackage(id) {
+  return request({
+    url: '/tsb/upgradePackage/' + id,
+    method: 'get'
+  })
+}
+
+/**
+ * 新增设备升级包
+ */
+export function addUpgradePackage(data) {
+  return request({
+    url: '/tsb/upgradePackage',
+    method: 'post',
+    data: data
+  })
+}
+
+/**
+ * 修改设备升级包
+ */
+export function updateUpgradePackage(data) {
+  return request({
+    url: '/tsb/upgradePackage',
+    method: 'put',
+    data: data
+  })
+}
+
+/**
+ * 修改升级包状态(列表开关)
+ */
+export function changeUpgradePackageStatus(id, status) {
+  return request({
+    url: '/tsb/upgradePackage/changeStatus',
+    method: 'put',
+    data: { id, status }
+  })
+}
+
+/**
+ * 删除设备升级包(支持批量)
+ */
+export function delUpgradePackage(ids) {
+  return request({
+    url: '/tsb/upgradePackage/' + ids,
+    method: 'delete'
+  })
+}

+ 388 - 0
ruoyi-ui/src/views/tsb/upgradePackage/index.vue

@@ -0,0 +1,388 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="auto">
+      <el-form-item label="设备类型" prop="deviceType">
+        <el-input v-model="queryParams.deviceType" placeholder="设备类型" clearable @keyup.enter.native="handleQuery" />
+      </el-form-item>
+      <el-form-item label="软件版本" prop="appVersion">
+        <el-input v-model="queryParams.appVersion" placeholder="软件版本号" clearable @keyup.enter.native="handleQuery" />
+      </el-form-item>
+      <el-form-item label="升级包类型" prop="type">
+        <el-select v-model="queryParams.type" placeholder="升级包类型" clearable>
+          <el-option v-for="item in typeOptions" :key="item.value" :label="item.label" :value="item.value" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="固件类型" prop="firmwareType">
+        <el-select v-model="queryParams.firmwareType" placeholder="固件类型" clearable>
+          <el-option v-for="item in firmwareTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="状态" clearable>
+          <el-option label="启用" :value="1" />
+          <el-option label="停用" :value="0" />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['tsb:upgradePackage:add']">新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate()" v-hasPermi="['tsb:upgradePackage:edit']">修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['tsb:upgradePackage:remove']">删除</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="packageList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="ID" align="center" prop="id" width="60" />
+      <el-table-column label="设备类型" align="center" prop="deviceType" show-overflow-tooltip />
+      <el-table-column label="软件版本号" align="center" prop="appVersion" width="100" />
+      <el-table-column label="下载地址" align="center" prop="downloadUrl" show-overflow-tooltip>
+        <template slot-scope="scope">
+          <el-link type="primary" :underline="false" v-if="scope.row.downloadUrl">{{ scope.row.downloadUrl }}</el-link>
+        </template>
+      </el-table-column>
+      <el-table-column label="升级包类型" align="center" prop="type" width="100">
+        <template slot-scope="scope">
+          <el-tag :type="scope.row.type === 1 ? 'success' : 'warning'" size="small">
+            {{ scope.row.type === 1 ? '正式升级包' : '测试升级包' }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="固件类型" align="center" prop="firmwareType" width="120">
+        <template slot-scope="scope">
+          <span>{{ getFirmwareTypeLabel(scope.row.firmwareType) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="状态" align="center" prop="status" width="80">
+        <template slot-scope="scope">
+          <el-switch
+            v-model="scope.row.status"
+            :active-value="1"
+            :inactive-value="0"
+            @change="handleStatusChange(scope.row)"
+          />
+        </template>
+      </el-table-column>
+      <el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip />
+      <el-table-column label="创建时间" align="center" prop="createTime" width="160">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="180">
+        <template slot-scope="scope">
+          <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['tsb:upgradePackage:edit']">修改</el-button>
+          <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['tsb:upgradePackage:remove']">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
+
+    <!-- 新增/编辑 弹窗 -->
+    <el-dialog :title="title" :visible.sync="open" width="560px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="设备类型" prop="deviceType">
+          <el-input v-model="form.deviceType" placeholder="请输入设备类型" maxlength="32" />
+        </el-form-item>
+        <el-form-item label="固件类型" prop="firmwareType">
+          <el-select v-model="form.firmwareType" placeholder="请选择固件类型" style="width: 100%">
+            <el-option v-for="item in firmwareTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="升级包类型" prop="type">
+          <el-radio-group v-model="form.type">
+            <el-radio v-for="item in typeOptions" :key="item.value" :label="item.value">{{ item.label }}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="升级包上传">
+          <el-upload
+            ref="upload"
+            :action="uploadUrl"
+            :headers="uploadHeaders"
+            :before-upload="handleBeforeUpload"
+            :on-success="handleUploadSuccess"
+            :on-error="handleUploadError"
+            :show-file-list="false"
+            accept=".bin"
+          >
+            <el-button size="small" type="primary">上传升级包</el-button>
+          </el-upload>
+          <div class="el-upload__tip">请上传格式为 <b style="color: #f56c6c">.bin</b> 的文件</div>
+        </el-form-item>
+        <el-form-item label="下载地址" prop="downloadUrl">
+          <span v-if="form.downloadUrl" class="upload-result-text">{{ form.downloadUrl }}</span>
+          <span v-else style="color: #c0c4cc">请先上传升级包</span>
+        </el-form-item>
+        <el-form-item label="软件版本号" prop="appVersion">
+          <el-input v-model="form.appVersion" placeholder="请输入软件版本号" maxlength="32" />
+        </el-form-item>
+        <el-form-item label="状态" prop="status">
+          <el-radio-group v-model="form.status">
+            <el-radio :label="1">启用</el-radio>
+            <el-radio :label="0">停用</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="open = false">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  listUpgradePackage,
+  getUpgradePackage,
+  addUpgradePackage,
+  updateUpgradePackage,
+  changeUpgradePackageStatus,
+  delUpgradePackage
+} from '@/api/tsb/upgradePackage'
+import { getToken } from '@/utils/auth'
+
+export default {
+  name: 'UpgradePackage',
+  data() {
+    return {
+      // 搜索栏显隐
+      showSearch: true,
+      // 列表加载状态
+      loading: true,
+      // 列表数据
+      packageList: [],
+      // 选中ID数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 总条数
+      total: 0,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        deviceType: undefined,
+        appVersion: undefined,
+        type: undefined,
+        firmwareType: undefined,
+        status: undefined
+      },
+      // 弹窗控制
+      open: false,
+      title: '',
+      // 表单数据
+      form: {},
+      // 表单校验规则
+      rules: {
+        deviceType: [
+          { required: true, message: '设备类型不能为空', trigger: 'blur' }
+        ],
+        appVersion: [
+          { required: true, message: '软件版本号不能为空', trigger: 'blur' }
+        ],
+        downloadUrl: [
+          { required: true, message: '下载地址不能为空', trigger: 'blur' }
+        ],
+        firmwareType: [
+          { required: true, message: '固件类型不能为空', trigger: 'change' }
+        ]
+      },
+      // 升级包类型选项
+      typeOptions: [
+        { value: 1, label: '正式升级包' },
+        { value: 0, label: '测试升级包' }
+      ],
+      // 固件类型选项
+      firmwareTypeOptions: [
+        { value: 1, label: 'bootloader' },
+        { value: 2, label: '产测' },
+        { value: 3, label: 'app' },
+        { value: 4, label: 'lua' },
+        { value: 5, label: '调试宝显示屏' }
+      ],
+      // 文件上传地址
+      uploadUrl: process.env.VUE_APP_BASE_API + '/common/upload',
+      // 上传请求头
+      uploadHeaders: {
+        Authorization: 'Bearer ' + getToken()
+      }
+    }
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    /** 上传前校验 */
+    handleBeforeUpload(file) {
+      // 校验文件格式必须为.bin
+      const isBin = file.name.toLowerCase().endsWith('.bin')
+      if (!isBin) {
+        this.$modal.msgError('升级包文件格式必须为 .bin!')
+        return false
+      }
+      this.$modal.loading('正在上传升级包,请稍候...')
+      return true
+    },
+
+    /** 上传成功回调 */
+    handleUploadSuccess(res, file) {
+      this.$modal.closeLoading()
+      if (res.code === 200) {
+        this.form.downloadUrl = res.url
+        this.$modal.msgSuccess('上传成功')
+      } else {
+        this.$modal.msgError(res.msg || '上传失败')
+      }
+    },
+
+    /** 上传失败回调 */
+    handleUploadError() {
+      this.$modal.closeLoading()
+      this.$modal.msgError('上传失败,请重试')
+    },
+
+    /**
+     * 根据固件类型值获取显示文本
+     */
+    getFirmwareTypeLabel(value) {
+      const item = this.firmwareTypeOptions.find(o => o.value === value)
+      return item ? item.label : value
+    },
+
+    /**
+     * 查询升级包列表
+     */
+    getList() {
+      this.loading = true
+      listUpgradePackage(this.queryParams).then(response => {
+        this.packageList = response.rows
+        this.total = response.total
+        this.loading = false
+      })
+    },
+
+    /** 搜索按钮 */
+    handleQuery() {
+      this.queryParams.pageNum = 1
+      this.getList()
+    },
+
+    /** 重置按钮 */
+    resetQuery() {
+      this.resetForm('queryForm')
+      this.handleQuery()
+    },
+
+    /** 多选框选中数据 */
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length !== 1
+      this.multiple = !selection.length
+    },
+
+    /** 新增按钮 */
+    handleAdd() {
+      this.reset()
+      this.open = true
+      this.title = '新增升级包'
+    },
+
+    /** 修改按钮 */
+    handleUpdate(row) {
+      const id = row && row.id ? row.id : this.ids[0]
+      this.reset()
+      getUpgradePackage(id).then(response => {
+        this.form = response.data
+        this.open = true
+        this.title = '修改升级包'
+      })
+    },
+
+    /** 提交表单 */
+    submitForm() {
+      this.$refs['form'].validate(valid => {
+        if (!valid) return
+        if (this.form.id != null) {
+          updateUpgradePackage(this.form).then(() => {
+            this.$modal.msgSuccess('修改成功')
+            this.open = false
+            this.getList()
+          })
+        } else {
+          addUpgradePackage(this.form).then(() => {
+            this.$modal.msgSuccess('新增成功')
+            this.open = false
+            this.getList()
+          })
+        }
+      })
+    },
+
+    /** 状态开关 */
+    handleStatusChange(row) {
+      const text = row.status === 1 ? '启用' : '停用'
+      this.$modal.confirm('确认要"' + text + '""' + row.appVersion + '"升级包吗?').then(() => {
+        return changeUpgradePackageStatus(row.id, row.status)
+      }).then(() => {
+        this.$modal.msgSuccess(text + '成功')
+      }).catch(() => {
+        row.status = row.status === 1 ? 0 : 1
+      })
+    },
+
+    /** 删除按钮 */
+    handleDelete(row) {
+      const ids = row && row.id ? row.id : this.ids.join(',')
+      const label = row && row.appVersion ? row.appVersion : this.ids.join(',')
+      this.$modal.confirm('是否确认删除版本号为"' + label + '"的升级包数据项?').then(() => {
+        return delUpgradePackage(ids)
+      }).then(() => {
+        this.getList()
+        this.$modal.msgSuccess('删除成功')
+      }).catch(() => {})
+    },
+
+    /** 重置表单 */
+    reset() {
+      this.form = {
+        id: undefined,
+        deviceType: undefined,
+        appVersion: undefined,
+        downloadUrl: undefined,
+        type: 1,
+        firmwareType: undefined,
+        status: 1,
+        remark: undefined
+      }
+      this.resetForm('form')
+    }
+  }
+}
+</script>
+<style scoped>
+.upload-result-text {
+  display: block;
+  margin-top: 8px;
+  color: #606266;
+  font-size: 13px;
+  word-break: break-all;
+}
+</style>

+ 20 - 0
sql/tsb_3.0.sql

@@ -175,3 +175,23 @@ CREATE TABLE tb_device_upgrade_package (
 ) COMMENT='设备升级包表';
 
 
+-- ----------------------------
+-- 升级包管理 菜单与按钮(若依 sys_menu)
+-- 挂载在调试宝(3200)目录下
+-- ----------------------------
+
+-- 升级包管理页
+INSERT INTO sys_menu VALUES ('3211', '升级包管理', '3200', '2', 'upgradePackage', 'tsb/upgradePackage/index', '', '', 1, 0, 'C', '0', '0', 'tsb:upgradePackage:list', 'tree-table', 'admin', sysdate(), '', NULL, '调试宝升级包管理');
+
+-- 按钮
+INSERT INTO sys_menu VALUES ('3212', '升级包查询', '3211', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'tsb:upgradePackage:query', '#', 'admin', sysdate(), '', NULL, '');
+INSERT INTO sys_menu VALUES ('3213', '升级包新增', '3211', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'tsb:upgradePackage:add', '#', 'admin', sysdate(), '', NULL, '');
+INSERT INTO sys_menu VALUES ('3214', '升级包修改', '3211', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'tsb:upgradePackage:edit', '#', 'admin', sysdate(), '', NULL, '');
+INSERT INTO sys_menu VALUES ('3215', '升级包删除', '3211', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'tsb:upgradePackage:remove', '#', 'admin', sysdate(), '', NULL, '');
+
+-- 普通角色 role_id=2 授权
+INSERT INTO sys_role_menu VALUES ('2', '3211');
+INSERT INTO sys_role_menu VALUES ('2', '3212');
+INSERT INTO sys_role_menu VALUES ('2', '3213');
+INSERT INTO sys_role_menu VALUES ('2', '3214');
+INSERT INTO sys_role_menu VALUES ('2', '3215');