Uniapp自动更新

   本文介绍了基于rouyi-uniapp的更新包版本自动推送更新。结合minio和网址下载地址两种方式,计算版本号大小后,可选是否强制更新。

一、表结构和后端版本号检测设计

1、版本更新控制表结构

主要字段和设计思路:

fileUrl:直接下载地址,用于网址直接下载,uniapp可直接访问(isUrlDownload=”Y“)

filePath:minio下载地址, 存储minio文件管理系统表的关键字,uniapp走本地minio文件下载地址(isUrlDownload=”N“)

version:版本号3位,eg:4.0.1,与uniapp的manifest.Json的versionName对应。

versionValue:版本号值,类似于二进制值转化,在更新版本时,比价用户当前版本信息和发布的有效最高版本号,如果当前版本号低于发布的最高版本号,进行更新提示。

Eg:Version=4.0.1; versionValue = 1*Math.power(10,0)+0*Math.power(10,1)+1*Math.power(10,2)。平方基数值不得小于10,否则值计算的最终大小会不符合。

isUrlDownload:是否使用直接地址下载还是minio,更加灵活

Status:版本是否可用。‘Y’为可用,即使用户安装的是旧版本,也可以不更新。‘N’为版本停用,如果用户当前安装的版本状态为停用,则强制更新到最新版(状态为‘Y’,且版本号值最高)

package com.inspur.factory.factoryAppManage.domain;

import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.inspur.common.annotation.Excel;
import com.inspur.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

/**
 * app版本管理对象 factory_app_manage
 *
 */
@TableName("factory_app_manage")

@Data
public class FactoryAppManage extends BaseEntity
{
    private static final long serialVersionUID = 1L;

    /** 主键 */
    @TableId
    private Long id;

    /** 版本号名称 */
    @Excel(name = "版本号名称")
    private String version;

    /** 版本号值 */
    @Excel(name = "版本号值")
    private Long versionValue;

    /** 手机品牌 */
    @Excel(name = "手机品牌")
    private String phoneBrand;

    /** 文件名(安装包名称) */
    @Excel(name = "文件名(安装包名称)")
    private String fileName;

    /** 安装包地址 */
    @Excel(name = "安装包地址")
    private String filePath;

    /** 下载地址 */
    @Excel(name = "下载地址")
    private String fileUrl;

    /** 上传时间 */
//    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @Excel(name = "上传时间", width = 30, dateFormat = "yyyy-MM-dd")
    private Date fileTime;

    /** 状态 */
    @Excel(name = "状态")
    private String status;

    /** 更新说明 */
    @Excel(name = "更新说明")
    private String upgradeDescription;

    /** 文件大小 */
    @Excel(name = "文件大小")
    private String fileSize;

    /** 使用临时地址 */
    @Excel(name = "使用临时地址",readConverterExp = "Y=是,N=否")
    private String isUrlDownload;

    }


    @Override
    public String toString() {
        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
            .append("id", getId())
            .append("version", getVersion())
            .append("versionValue", getVersionValue())
            .append("phoneBrand", getPhoneBrand())
            .append("fileName", getFileName())
            .append("filePath", getFilePath())
            .append("fileUrl", getFileUrl())
            .append("fileTime", getFileTime())
            .append("status", getStatus())
            .append("upgradeDescription", getUpgradeDescription())
            .append("fileSize", getFileSize())
            .append("createTime", getCreateTime())
            .append("createBy", getCreateBy())
            .append("updateTime", getUpdateTime())
            .append("updateBy", getUpdateBy())
            .append("remark", getRemark())
            .toString();
    }
}

2、检查版本更新

    检查用户当前的版本是否可用。‘Y’为可用,即使用户安装的是旧版本,也可以不更新。‘N’为版本停用,如果用户当前安装的版本状态为停用,则强制更新到最新版(状态为‘Y’,且版本号值最高)。

//获取应当安装的app版本

@Override
public FactoryAppManage getAppVersion(FactoryAppManage factoryAppManage){
    //传入版本号、手机系统类型
    List<FactoryAppManage> oldVersion = factoryAppManageMapper.selectFactoryAppManageList(factoryAppManage);
    if(oldVersion!=null && oldVersion.size()!=0){
        //如果当前版本还可使用,返回当前版本
        if(oldVersion.get(0).getStatus().equals("Y")){
            return oldVersion.get(0);
        }else{
            //如果当前版本不可使用强制更新,返回最新版本
            FactoryAppManage factoryAppManageQuery = new FactoryAppManage();
            factoryAppManageQuery.setStatus("Y");
            factoryAppManageQuery.setPhoneBrand(factoryAppManage.getPhoneBrand());
            List<FactoryAppManage> newVersion = factoryAppManageMapper.selectFactoryAppManageList(factoryAppManageQuery);
            if(newVersion!=null){
                return newVersion.get(0);
            }
        }
    }
    return null;
}

二、前端uniapp设计

版本号比较后,更新包安装提示弹窗,点击确认下载文件。

文件下载和打开主要方法如下:

1、主要应用技术

(1)直接地址下载:

uni.saveFile({})

(2)Minio下载:

Url为本地接口地址

plus.downloader.createDownload(url, {})

plus.io.convertLocalFileSystemURL

plus.runtime.openFile(d.filename); //选择软件打开文件

(3)H5平台下载:

主要用于电脑调试,BLOB转化,具体不做解释

(4)软件信息获取

uni.getSystemInfoSync()

获取:phoneBrand(版本)version(版本号)

2、实现方法(***重点***)

App.vue根组件,每次打开任何页面都会执行到,在此文件下检测版本和更新包安装。

(1)版本检测

当前版本号为参数,后台请求对比最新版本号(版本号值最大为最新版本),返回应当安装的版本。

如果需要更新,则弹窗显示,点击确定进行安装。

根据web前台配置的是否用直接地址下载,进入安装包下载安装。

      checkUploadVersion(){
        //检测更新
        let server = config.baseUrl +'/factory/factoryAppManage/getAppVersion'; //检查更新地址(minio检测地址)
        let info = uni.getSystemInfoSync()
        uni.request({
          url: server,
          data: {
            phoneBrand: info.platform,
            version: info.appVersion
          },
          success: (res) => {
            if (res.data.data.version != info.appVersion) {
            // if (1) {
              let upgradeDescription = res.data.data.upgradeDescription
              uni.showModal({ //提醒用户更新
                title: "更新提示",
                content: '版本更新内容:'+ upgradeDescription,
                showCancel:false,
                success: (e) => {
                  if (e.confirm) {
                    if(info.uniPlatform=='web'){
                      //h5平台调用后端minio接口下载
                      this.downloadApp2(res.data.data)
                    }else if(info.platform!='windows' && info.uniPlatform!='web' && res.data.data.isUrlDownload == 'Y'){
                      //app手机端使用临时地址下载
                      this.downloadApp1(res.data.data)
                    }else if(info.platform!='windows' && info.uniPlatform!='web' && res.data.data.isUrlDownload == 'N'){
                      //app手机端调用后端minio接口下载
                      this.downloadApp3(res.data.data)
                    }
                  }
                }
              })
            }
          }
        })
      },

(2) minio下载

此方式具有参考意义,可以不用购买云空间存放安装包文件,直接使用minio文件存储。


   

   /** app安装包下载-(下载方式3-APP调用后端minio下载接口下载)*/
      downloadApp3(appVersionInfo) {

        var url = config.baseUrl +'/fileManage/downloadFile'+'?filePath=' + appVersionInfo.filePath+'&fileName=' + appVersionInfo.fileName; //请求下载接口地址
        var name = appVersionInfo.fileName;
        // console.log('method', reqMethod)
        uni.showLoading({
          title: '正在下载'
        });
// 本地路径开头使用file://,跟上手机文件本地目录storage/emulated/0,
// 这时用户文件管理器能看到的了,之后创建 京唐港app 作为文件夹,
        let dtask = plus.downloader.createDownload(url, {
          filename: "file://storage/emulated/0/京唐港app/" + name //利用保存路径,实现下载文件的重命名
        },(d, status)=> {
          //d为下载的文件对象
          if (status == 200) {
            uni.hideLoading();
            uni.showToast({
              icon: 'none',
              mask: true,
              title: '已保存到文件夹:/京唐港app/' + name, //保存路径
              duration: 3000,
            });
            //下载成功,d.filename是文件在保存在本地的相对路径,使用下面的API可转为平台绝对路径
            let fileSaveUrl = plus.io.convertLocalFileSystemURL(d.filename);
            setTimeout(()=>{
              plus.runtime.openFile(d.filename); //选择软件打开文件
            },1500)
          } else {
            //下载失败
            uni.hideLoading();
            plus.downloader.clear(); //清除下载任务
            uni.showToast({
              icon:'none',
              mask:true,
              title: '下载失败,请稍后重试',
            });
          }
        })
        dtask.start();
      },

(3)直接地址下载

此方式需要云空间

  

    /** app安装包下载-(下载方式1-APP指定url下载)*/
      downloadApp1(appVersionInfo){
        //下载方式1:指定url下载
        let downloadUrl = appVersionInfo.fileUrl
        // let downloadUrl = 'https://mp-fdbd529e-1d38-4f4a-bf37-72ba880de14a.cdn.bspapp.com/cloudstorage/00b0e017-b375-4758-88c8-4acfab810d7a.apk'
         uni.downloadFile({
          url: downloadUrl,
/*          data:{
            filePath:'mnQ0lCrayctz3TkHxB4rB0PeVTD7fbXNhULFZo4g+iPK0KXkzzzYJWCIJ5vxfiu1a8fzsYOb07weXbcXd92dkw==',
            fileName: '3.jpg'
          },
          method: 'POST',*/
          success: (res) => {
            console.log('downloadFile success, res is', res)
            //文件保存到本地
            uni.saveFile({
              tempFilePath: res.tempFilePath, //临时路径
              success: function(re) {
                uni.showToast({
                  icon: 'none',
                  mask: true,
                  title: '文件已保存:' + re.savedFilePath, //保存路径
                  duration: 3000,
                });
                setTimeout(() => {
                  //打开查看
                  uni.openDocument({
                    filePath: re.savedFilePath,
                    success: function(res) {
                      // console.log('打开成功');
                    }
                  });
                }, 3000)
              }
            });

            uni.hideLoading();
          },
          fail: (err) => {
            console.log('downloadFile fail, err is:', err)
            uni.hideLoading();
          }
        })
      },

(4) H5平台电脑端下载

      /** app安装包下载-(下载方式2-h5平台web使用后端minio后端接口下载)*/
      downloadApp2(appVersionInfo){
        //下载方式2:请求接口下载
        let server = config.baseUrl +'/fileManage/downloadFile'+'?filePath=' + appVersionInfo.filePath+'&fileName=' + appVersionInfo.fileName; //请求下载接口地址
        uni.request({
          url: server,
          method: 'post',
          success: (res) => {
            /** h5 平台下载*/
            try {
              // const res = await exportOrderById({ id });//获取返回的二进制数据
              const blob = new Blob([res.data]); // 通过返回的流数据 手动构建blob 流
              const reader = new FileReader();
              reader.readAsDataURL(blob); // 转换为base64,可以直接放入a标签的href
              reader.onload = (e) => {
                // 转换完成,创建一个a标签用于下载
                const a = document.createElement("a");
                a.download = appVersionInfo.fileName; // 构建 下载的文件名称以及下载的文件格式(可通过传值输入)
                if (typeof e.target.result === "string") {
                  a.href = e.target.result;
                }
                a.click();
              };
            } catch (err) {
              this.$message.error("遇到错误!");
            }
          }
        })
      },

三、前端web设计

1、版本页面展示

<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="90px" style="margin-bottom: 5px">
      <div class="con-container">
        <div class="lab-container">
              <label class="condition-item-title">版本号名称</label>
              <el-form-item label="" prop="version" class="custom-el-form-item">
                <el-input
                    v-model="queryParams.version" class="query-param"
                    placeholder="请输入版本号名称"
                    clearable
                    size="small"
                    @keyup.enter.native="handleQuery"
                />
              </el-form-item>
        </div>

        <div class="btn-container">
          <el-form-item>
            <el-button type="primary" icon="el-icon-setting" size="mini" @click="conditionToggle">高级查询
            </el-button>
            <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
            <el-button type="primary" icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
            <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd"
                       v-hasPermi="['factory:factoryAppManage:add']">新增
            </el-button>
            <el-button type="primary" icon="el-icon-download" size="mini" @click="handleExport"
                       v-hasPermi="['factory:factoryAppManage:export']">导出
            </el-button>
            <el-button type="primary" icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete"
                       v-hasPermi="['factory:factoryAppManage:remove']"
            >删除</el-button>
          </el-form-item>
        </div>
      </div>


    <div class="toggle-container" ref="toggle-container" style="display: none;">
    <div class="condition-item">
      <label class="condition-item-title">手机品牌</label>
      <el-form-item label="" prop="phoneBrand">
        <el-input
          v-model="queryParams.phoneBrand"
          placeholder="请输入手机品牌"
          clearable
          size="small" class="query-param"
          @keyup.enter.native="handleQuery"
        />
      </el-form-item>
    </div>
    <div class="condition-item">
      <label class="condition-item-title">状态</label>
      <el-form-item label="" prop="status">
        <el-select v-model="queryParams.status" placeholder="请选择状态" clearable size="small" class="query-param">
          <el-option
            v-for="item in statusOptions"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          />
        </el-select>
      </el-form-item>
    </div>
      </div>
    </el-form>
    <el-table v-loading="loading" ref="table" border
    :height="tableHeight" :header-cell-style="{fontSize:'14px', fontWeight:'500'}"
    :data="factoryAppManageList" @selection-change="handleSelectionChange">
      <el-table-column type="selection" width="55" align="center" />
      <el-table-column label="序号" type="index" width="60" align="left">
        <template slot-scope="scope">
          <span>{{(queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1}}</span>
        </template>
      </el-table-column>
<!--      <el-table-column label="主键" align="center" prop="id" />-->
      <el-table-column label="手机品牌" align="center" prop="phoneBrand">
        <template slot-scope="scope">
          <dict-tag :options="dict.type.phone_brand" :value="scope.row.phoneBrand"/>
        </template>
      </el-table-column>
      <el-table-column label="版本号名称" align="center" prop="version" />
      <el-table-column label="版本号值" align="center" prop="versionValue" />
      <el-table-column label="安装包名称" :show-overflow-tooltip="true" align="center" prop="fileName" />
      <el-table-column label="安装包地址" :show-overflow-tooltip="true" align="center" prop="filePath" />
<!--      <el-table-column label="下载地址" align="center" prop="fileUrl" />-->
      <el-table-column label="上传时间" align="center" prop="fileTime" width="180">
        <template slot-scope="scope">
          <span>{{ parseTime(scope.row.fileTime) }}</span>
        </template>
      </el-table-column>
      <el-table-column label="状态" align="center" prop="status">
        <template slot-scope="scope">
          <el-tag type="warning" v-if="scope.row.status=='N'">停用</el-tag>
          <el-tag type="success" v-if="scope.row.status=='Y'">启用</el-tag>
        </template>
      </el-table-column>
<!--      <el-table-column label="更新说明" align="center" prop="upgradeDescription" />-->
      <el-table-column label="文件大小(MB)" align="center" prop="fileSize" />
<!--      <el-table-column label="备注" align="center" prop="remark" />-->
      <el-table-column label="操作" min-width="200" align="center" class-name="small-padding fixed-width">
        <template slot-scope="scope">
          <el-button
            size="mini"
            type="text"
            icon="el-icon-download"
            @click="handleDownload(scope.row.filePath,scope.row.fileName)"
          >下载
          </el-button>
          <el-button
              size="mini"
              type="text"
              icon="el-icon-tickets"
              @click="handleView(scope.row)"
              v-hasPermi="['factory:factoryAppManage:query']"
          >详情</el-button>

          <el-button
            size="mini"
            type="text"
            icon="el-icon-edit"
            @click="handleUpdate(scope.row)"
            v-hasPermi="['factory:factoryAppManage:edit']"
          >修改</el-button>
          <el-button
            size="mini"
            type="text"
            icon="el-icon-delete"
            @click="handleDelete(scope.row)"
            v-hasPermi="['factory:factoryAppManage: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"
    />

    <!-- 添加或修改app版本管理对话框 -->
    <el-dialog :visible.sync="open" @opened="openDialog">
      <div slot="title">
        <span>{{ title }}</span>
      </div>
      <div class="factoryAppManage-body"></div>
      <el-form ref="form" :model="form" :rules="rules" label-width="120px">

      <div class="sub-project">
        <div class="sub-title">
          <div class="sub-title-name">app版本管理信息</div>
        </div>
        <div class="sub-body">
          <el-row>
            <el-col :span="8" v-if="!readOnly">
              <el-form-item label="安装包">
                <up-record @sendRecordData="getRecordData"></up-record>
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="上传时间" prop="fileTime" v-show="!readOnly">
                <el-date-picker clearable size="small"
                                v-model="form.fileTime"
                                type="date"
                                value-format="yyyy-MM-dd"
                                disabled
                                style="width:100%"
                                placeholder="选择上传时间">
                </el-date-picker>
              </el-form-item>
              <el-form-item label="上传时间:" prop="fileTime" v-show="readOnly" class="custom-form-item">
                {{form.fileTime}}
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="手机品牌" prop="phoneBrand" v-show="!readOnly">
                <el-select v-model="form.phoneBrand" placeholder="请选择手机品牌" class="custom-form-item">
                  <el-option
                    v-for="dict in dict.type.phone_brand"
                    :key="dict.value"
                    :label="dict.label"
                    :value="dict.value"
                  ></el-option>
                </el-select>
              </el-form-item>
              <el-form-item label="手机品牌:" prop="phoneBrand" v-show="readOnly" class="custom-form-item">
                {{form.phoneBrand}}
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="安装包名称" prop="fileName" v-show="!readOnly">
                <el-input v-model="form.fileName" placeholder="安装包名称" class="form-item" disabled/>
              </el-form-item>
              <el-form-item label="安装包名称:" prop="fileName" v-show="readOnly" class="custom-form-item">
                {{form.fileName}}
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="安装包地址" prop="filePath" v-show="!readOnly">
                <el-input v-model="form.filePath" placeholder="请输入安装包地址" class="form-item" disabled/>
              </el-form-item>
              <el-form-item label="安装包地址:" prop="filePath" v-show="readOnly" class="custom-form-item">
                {{form.filePath}}
              </el-form-item>
            </el-col>
        <el-col :span="8">
        <el-form-item label="版本号名称" prop="version" v-show="!readOnly">
          <el-input v-model="form.version" placeholder="四位,如(4.0.0.0)" class="form-item"/>
        </el-form-item>
        <el-form-item label="版本号名称:" prop="version" v-show="readOnly" class="custom-form-item">
          {{form.version}}
        </el-form-item>
        </el-col>
        <el-col :span="8">
        <el-form-item label="版本号值" prop="versionValue" v-show="!readOnly">
          <div v-if="!versionValueShow" @click="generateVersionValue" style="align-items: center"><el-link type="primary">计算版本号值</el-link></div>
          <el-input v-model="form.versionValue" placeholder="请输入版本号值" disabled class="form-item" v-if="versionValueShow"/>
        </el-form-item>
        <el-form-item label="版本号值:" prop="versionValue" v-show="readOnly" class="custom-form-item">
          {{form.versionValue}}
        </el-form-item>
        </el-col>
        <el-col :span="8">
        <el-form-item label="直接下载地址" prop="fileUrl" v-show="!readOnly">
          <el-input v-model="form.fileUrl" placeholder="请输入下载地址" class="form-item"/>
        </el-form-item>
        <el-form-item label="直接下载地址:" prop="fileUrl" v-show="readOnly" class="custom-form-item">
          {{form.fileUrl}}
        </el-form-item>
        </el-col>
            <el-col :span="24">
              <el-form-item label="更新说明" prop="upgradeDescription" v-show="!readOnly">
                <el-input type="textarea" :autosize="{ minRows: 4, maxRows: 4 }" v-model="form.upgradeDescription" placeholder="请输入更新说明" maxlength="85" show-word-limit class="form-item"/>
              </el-form-item>
              <el-form-item label="更新说明:" prop="upgradeDescription" v-show="readOnly" class="custom-form-item">
                {{form.upgradeDescription}}
              </el-form-item>
            </el-col>
        <el-col :span="24">
        <el-form-item label="状态" v-if="!readOnly">
          <el-radio-group v-model="form.status" class="form-item">
            <el-radio
              v-for="dict in statusOptions"
              :key="dict.value"
              :label="dict.value"
            >{{ dict.label }}
            </el-radio>
          </el-radio-group>
        </el-form-item>
          <el-form-item label="状态" v-if="readOnly">
            <el-tag type="warning" v-if="form.status=='N'">停用</el-tag>
            <el-tag type="success" v-if="form.status=='Y'">启用</el-tag>
        </el-form-item>
        </el-col>
          </el-row>
        </div>
      </div>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm" v-show="!readOnly">确 定</el-button>
        <el-button @click="cancel">取 消</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { listFactoryAppManage, getFactoryAppManage, countFactoryAppManage, delFactoryAppManage, addFactoryAppManage, updateFactoryAppManage, exportFactoryAppManage } from "@/api/factory/factoryAppManage";
import upRecord from "@/components/FileUpload/upRecord";
import $ from 'jquery'
import selectSingleDevice from "@/components/esis/selectSingleDevice";
import {addFactoryDeviceFile} from "@/api/factory/factoryDeviceFile";
export default {
  name: "FactoryAppManage",
  dicts: ['phone_brand'],
  components: {upRecord},
  data() {
    // 唯一字段校验
    const validateUnique = (comment, rule, value, callback) => {
      let param = {}
      value =  value.trim()
      if (!value || value.length === 0) {
        callback(new Error(comment + "不能为空"));
        return;
      }
      this.$set(param, rule.field, value)
      let id =  this.form.id
      if(!id){ // 新增唯一校验
        countFactoryAppManage(param).then(res => {
          if(res.code === 200){
            if(res.data > 0){
              callback(new Error(comment + "已存在"));
            }else{
              callback()
            }
          }else{
            callback()
          }
        })
      }else { // 修改唯一校验
        this.$set(param, "id", id)
        countFactoryAppManage(param).then(res => {
          if(res.code === 200){
            if(res.data > 0){
              callback(new Error(comment + "已存在"));
            }else{
              callback()
            }
          }else{
            callback()
          }
        })
      }
    };
    return {
      // 遮罩层
      loading: true,
      // 导出遮罩层
      exportLoading: false,
      // 选中数组
      ids: [],
      // 非单个禁用
      single: true,
      // 非多个禁用
      multiple: true,
      // 显示搜索条件
      showSearch: true,
      versionValueShow: false,
      // 总条数
      total: 0,
      tableHeight: 450,
      // app版本管理表格数据
      factoryAppManageList: [],
      recordFileSucc: [],

      statusOptions:[
        {value:'Y',label: '启用'},
        {value:'N',label: '停用'}
      ],
      // 弹出层标题
      title: "",
      // 是否显示弹出层
      open: false,
      //查看按钮默认不能编辑
      readOnly: false,
              // 查询参数
      queryParams: {
        pageNum: 1,
        pageSize: 10,
        version: null,
        versionValue: null,
        phoneBrand: null,
        fileName: null,
        filePath: null,
        fileUrl: null,
        fileTime: null,
        status: null,
        upgradeDescription: null,
        fileSize: null,
      },
      // 表单参数
      form: {},
      // 表单校验
      rules: {
                                                                                                                                                                                                                                                                                                              }
    };
  },
  watch: {
      '$store.state.app.screenHeight': function() { //监听屏幕高度变化
          if (this.$refs.table.$el.offsetTop) {
              this.tableHeight = window.innerHeight - this.$refs.table.$el.offsetTop - 160
          } else {
              this.tableHeight = window.innerHeight - 62 - 160
          }
          this.openDialog()
      }
  },
  created() {
    this.getList();
  },

  methods: {
    openDialog() {
        $('.factoryAppManage-body').css('top', 0).css('overflow-y', 'auto')
    },

    generateVersionValue(){
      debugger
      let dotVal = this.form.version.split('.')
      this.form.versionValue = 4*Number(dotVal[0]) + 3*Number(dotVal[1])+ 2*Number(dotVal[2])+ 1*Number(dotVal[3])
      this.versionValueShow = true

    },
    /** 查询app版本管理列表 */
    getList() {
      this.loading = true;
      listFactoryAppManage(this.queryParams).then(response => {
        this.factoryAppManageList = response.rows;
        this.total = response.total;
        this.loading = false;
      });
    },

    /** 文件下载处理*/
    getRecordData(val) {
      this.recordFileSucc = val

        this.form.fileName = val[0].appendixName
        this.form.filePath = val[0].appendixPath
        this.form.fileTime = new Date()
        this.form.createBy = val[0].createBy
        this.form.fileSize = val[0].fileSize.toFixed(2)

    },
    conditionToggle() {
        if(this.$refs['toggle-container'].style.display === 'none'){
            this.$refs['toggle-container'].style.display = 'inline-block';
            this.tableHeight = window.innerHeight - this.$refs.table.$el.offsetTop -  160
        }else{
            this.$refs['toggle-container'].style.display = 'none';
            this.tableHeight = window.innerHeight - this.$refs.table.$el.offsetTop -  160
        }
    },
    // 取消按钮
    cancel() {
      this.open = false;
      this.reset();
    },

    // 表单重置
    reset() {
      this.form = {
        id: null,
        version: null,
        versionValue: null,
        phoneBrand: null,
        fileName: null,
        filePath: null,
        fileUrl: null,
        fileTime: null,
        status: "Y",
        upgradeDescription: null,
        fileSize: null,
        createTime: null,
        createBy: null,
        updateTime: null,
        updateBy: null,
        remark: null
      };
      this.resetForm("form");
    },

    /** 搜索按钮操作 */
    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.recordFileSucc = []
      this.open = true;
      this.readOnly = false
      this.title = "添加";
    },

    /** 修改按钮操作 */
    handleUpdate(row) {
      this.reset();
      const id = row.id || this.ids
      getFactoryAppManage(id).then(response => {
        this.form = response.data;
        this.open = true;
        this.readOnly = false
        this.title = "修改";
      });
    },

    //下载按钮操作
    handleDownload(url,name){
      // window.location.href = process.env.VUE_APP_BASE_API + '/fileManage/downloadFile?url=' + url + '&name=' + name
      this.$minio.downloadFile(url,name)
    },

    /** 详情按钮操作 */
    handleView(row) {
      this.reset();
      const id = row.id || this.ids
      getFactoryAppManage(id).then(response => {
        this.form = response.data;
        this.open = true;
        this.readOnly = true
        this.title = "详情";
      });
    },

    /** 提交按钮 */
    submitForm() {
      this.$refs["form"].validate(valid => {
        if (valid) {
          if (this.form.id != null) {
            updateFactoryAppManage(this.form).then(response => {
              this.msgSuccess("修改成功");
              this.open = false;
              this.getList();
            });
          } else {
            this.recordFileSucc.filter(res => {
              let obj = {
                version: this.form.version,
                versionValue: this.form.versionValue,
                phoneBrand: this.form.phoneBrand,
                fileName: res.appendixName,
                filePath: res.appendixPath,
                status: this.form.status,
                upgradeDescription: this.form.upgradeDescription,
                // fileId: res.fileId,
                // fileType: res.appendixName.substring(res.appendixName.lastIndexOf(".") + 1, res.appendixName.length),
                fileTime: new Date(),
                createBy: res.createBy,
                fileSize: res.fileSize.toFixed(2),
              }
              addFactoryAppManage(obj).then(response => {
                this.msgSuccess("新增成功");
                this.open = false;
                this.getList();
              });
            })

          }
        }
      });
    },

    /** 删除按钮操作 */
    handleDelete(row) {
      const ids = row.id || this.ids;
      this.$confirm('是否确认删除?', "警告", {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        }).then(function() {
          return delFactoryAppManage(ids);
        }).then(() => {
          this.getList();
          this.msgSuccess("删除成功");
        }).catch(() => {});
    },

    /** 导出按钮操作 */
    handleExport() {
      const queryParams = this.queryParams;
      this.$confirm('是否确认导出所有app版本管理数据项?', "警告", {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        }).then(() => {
          this.exportLoading = true;
          return exportFactoryAppManage(queryParams);
        }).then(response => {
          this.download(response.msg);
          this.exportLoading = false;
        }).catch(() => {});
    }
  },
  mounted() {

      this.$nextTick(function() {
          this.tableHeight = window.innerHeight - this.$refs.table.$el.offsetTop - 160
      })
  }
};

</script>

<style scoped>
  .form-item{
    width: 100%;
  }
</style>

2、文件上传组件

<!--文件上传组件(限制1个)-->
<template>
  <div>
    <el-upload
      class="upload-demo"
      ref="recordUpload"
      :headers="headers"
      :action="uploadUrl"
      :on-remove="handleRemoveRecord"
      :on-progress="uploadProcess"
      :before-upload="beforeUpload"
      :on-success="handleUpFileSuccess"
      :file-list="recordFileList"
    >
      <el-button size="small" type="primary" style="width: 100%">点击上传</el-button>
    </el-upload>

<!--    <div class="el-upload__tip" slot="tip">
      <template>
        最多上传一个文件,每个文件最大不能超过20MB!!!
      </template>
    </div>-->
    <!--    文件上传遮罩-->
    <el-dialog :visible.sync="uploadFlag" :show-close="false">
      <div class="sysFolderManage-body"></div>
      <el-progress v-if="uploadFlag == true" :percentage="videoUploadPercent">
      </el-progress>
    </el-dialog>
  </div>
</template>

<script>
import {getToken} from "@/utils/auth";

export default {
  name: "upRecord",
  data() {
    return {
      uploadUrl: process.env.VUE_APP_BASE_API + "/fileManage/uploadWithManage",
      headers: {
        Authorization: "Bearer " + getToken(),
      },
      uploadFlag: false,
      videoUploadPercent: 0,
      recordFileList: [],
      recordFileSucc: []
    }
  },
  methods: {
    beforeUpload(file) {
      if (this.recordFileSucc.length === 1) {
        this.msgError("单次最多上传3个文件!")
        return false
      }
      //判断文件大小
      var limitFileSize = file.size / 1024 / 1024 < 30
      if (!limitFileSize) {
        this.msgError("上传文件大小不能超过 30MB!")
        return limitFileSize
      }
    },
    /**文件上传遮罩 进度条*/
    uploadProcess(event, file, fileList) {
      this.uploadFlag = true;
      this.videoUploadPercent = parseInt(event.percent);
    },
    //文件上传处理
    handleUpFileSuccess(res, file, recordList) {
      if (res.code != 200) {
        this.msgError(res.msg);
      } else {
        this.uploadFlag = false;
        this.recordFileSucc = []
        this.handleFileList(recordList)
        this.$emit('sendRecordData', this.recordFileSucc);
      }
    },
    //文件删除处理
    handleRemoveRecord(file, recordList) {
      this.recordFileSucc = []
      this.handleFileList(recordList)
      this.$emit('sendRecordData', this.recordFileSucc);
    },
    //数据转换
    handleFileList(recordList) {
      recordList.filter(a => {
        this.recordFileSucc.push({
          fileId: a.response.appendix.id,
          fileSize: a.size / 1024 / 1024,
          appendixName: a.response.appendix.appendixName,
          appendixPath: a.response.appendix.appendixPath,
          createBy: a.response.appendix.createBy
        })
      })
    }
  }
}
</script>
09-05 02:24