最近更新时间:5/23/2023, 2:50:09 PM
owner: owenlai(赖文彬)

# @xiaoe/basic-material

# 说明

由于有多类型上传工具为了统一进行维护和对资源今天统一管理,需要使用当前组件进行上传,内置了同步素材中心、上传到多个云的功能。 注意:接入前需要后端同学和jchen进行对接,获取当前场景的场景值并提供接口给到上传对象的 getMarkReq 参数。前端直接接入即可。

文档链接: 接口文档 (opens new window)

# 接入方式

# 微组件接入

# 依赖安装

cnpm i @xiaoe/mimir -S
1

# 初始化


 







import Vue from 'vue';
window.Vue = Vue;
import Mimir from '@xiaoe/mimir';
const MaterialCenterBoxGenerator = Mimir({
   section: 'basic-material',
   project: 'admin_common_fe'
}).get('uploadTool');

1
2
3
4
5
6
7
8

# NPM 包接入

cnpm i @xiaoe/basic-material -S
1

# 使用示例

# Js 使用示例

import UploadTool from "@xiaoe/basic_material";
import axios from 'axios'

// 需要业务后端提供,用于获取上传凭证。
function getMarkReq(params) {
  return new Promise((reslove, reject) => {
    // 需要和owen、jchen对接获取场景值
    axios.post('/xe.material-center.*****/1.0.0', params)
      .then(res => {
        const data = res.data
        if (data.code == 0 && data.data) {
          reslove(data.data)
        }
        reject(res)
      }).catch((err) => {
        reject(err)
      })
  })
}


//实例化上传对象
const uploadTool = new UploadTool({
    fileType,
    getMarkReq,
    onSuccess: (fileObj,res) => { console.log(fileObj,res) },
    onError: (fileObj,err) => { console.log(fileObj,err) },
    onProgress:(fileObj,data) => { console.log(fileObj,data) },
    onStateChange:(fileObj, status, beforeStatus) => {console.log(fileObj, status, beforeStatus)},
});
// 只有当 initDone.then 之后才能调用方法,可以维护loading 进行 toast 提示
uploadTool.initDone().then(() => {
  //选择需要上传的 file 文件到 fileList 中
  const fileList = uploadTool.addNewFilesToList([]<file>);
  //开始上传fileList中的文件
  uploadTool.uploadFiles();
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# Vue 使用示例

<template>
  <div class="upload-tool" v-loading='loading'>
    <div>======================文件类型修改======================</div>
    <div class="upload-tool__item">
      <span class="upload-tool__item-label"> 文件类型:</span>
      <select class="upload-tool__item-input" v-model="fileType">
        <option :value="item.value" v-for="item in fileMap" :key="item.value">
          {{ item.label }}({{ item.value }})
        </option>
      </select>
    </div>
    <div>========================通用上传========================</div>
    <div class="upload-tool__item">
      <input type="file" name="file" multiple @change="onChange" :accept="accept" />
    </div>
    <div class="upload-tool__item">
      <button @click="upload">确认上传</button>
    </div>
    <div class="upload-tool__item" v-if="uploadTool">
      <div>上传成功数量:{{ uploadTool.successCount }}</div>
      <div>上传完成数量:{{ uploadTool.completeCount }}</div>
      <div>
        上传失败数量:{{ uploadTool.completeCount - uploadTool.successCount }}
      </div>
      <div>上传中数量:{{ uploadTool.uploadingCount }}</div>
    </div>
    <div class="upload-tool__item">
      <ul class="upload-tool__item-ul">
        <li class="upload-tool__item-li" v-for="(item, idx) in fileList" :key="idx">
          <div>
            文件名:{{ item.fileName || "--" }}
            <button @click="cancel(item)">取消</button>
            <button @click="handleDelete(item)">列表中删除</button>
          </div>
          <div>CDN:{{ item.accessUrl || "--" }}</div>
          <div>文件路径:{{ item.folder || "--" }}</div>
          <div>上传路径:{{ item.fileUniqueName || "--" }}</div>
          <div>文件状态:{{ item.status || "--" }}</div>
          <div>进度:{{ item.percent || "--" }}</div>
          <div>速度:{{ item.speed || "--" }}</div>
          <div>已下载大小:{{ item.loaded || "--" }}</div>
          <div>总大小:{{ item.total || "--" }}</div>
          <div>-----自定义属性-----</div>
          <div>进度*:{{ item.__progress || "--" }}</div>
          <div>速度*:{{ item.__speed || "--" }}</div>
          <div>大小*:{{ item.__size || "--" }}</div>
          <div>状态*:{{ item.__status || "--" }}</div>
        </li>
      </ul>
    </div>
  </div>
</template>

<script>
import UploadTool from "@xiaoe/basic-material/lib/upload-tool/index";
import axios from 'axios'
function format(suffixList) {
  let res = ",";
  suffixList.map((suffix) => (res += `.${suffix},`));
  return res;
}

export default {
  data() {
    return {
      loading:true,
      uploadTool: null,
      fileType: 1,
      fileMap: [
        { label: "图片", value: 1,suffix: ["png", "jpg", "bmp", "gif", "jpeg"]},
        { label: "音频", value: 2, suffix: ["m4a", "mp3"] },
        { label: "视频", value: 3, suffix: ["mp4","avi","wmv","mov","flv","rmvb","3gp","m4v","mkv","webm",]},
        { label: "电子书", value: 4, suffix: ["pdf", "epub"] },
        { label: "文件", value: 5, suffix: ["pptx","ppt","docx","doc","xls","xlsx","pdf","csv","xlsm","txt",]},
      ],
    };
  },
  computed: {
    accept({ fileMap, fileType }) {
      const suffix = fileMap.find(({ value }) => value === fileType).suffix;
      return format(suffix);
    },
    fileList: ({ uploadTool }) => {
      return uploadTool ? uploadTool.fileList : [];
    },
  },
  watch: {
    fileType: {
      handler(type) {
        if (!this.uploadTool || this.uploadTool.fileType !== type) {
          this.loading = true;
          this.uploadTool = new UploadTool({
            getMarkReq: this.getMarkReq,
            sycnMaterialCenter: true,
            maxUploadingFiles: 2,
            fileType: this.fileType,
            onProgress: (fileObj, data) => {
              if (fileObj.__status == "beforeUploading") {
                fileObj.__status = "uploading";
              }
              fileObj.__progress = (data.percent * 100).toFixed(2) + "%";
              fileObj.__speed = this.bytesToSize(data.speed) + "/s";

              console.log("【进度变化】", fileObj, data);
            },
            onSuccess: (fileObj, data) => {
              fileObj.__status = "success";
              console.log("【成功】", fileObj, data);
            },
            onError(fileObj, error) {
              fileObj.__status = "error";
              alert(error.msg);
            },

            onStateChage: (fileObj, status, beforeStatus) => {
              // 如果是取消从列表中删除
              console.log("【状态变化】", fileObj, status, beforeStatus);
            },
          });

          this.uploadTool.initDone().catch((err) => {
            alert(`初始化失败`, err);
          }).finally(_ => this.loading = false);

        }
      },
      immediate: true,
    },
  },
  methods: {
    cancel(fileObj, isCustom) {
      if (isCustom) {
        fileObj.status = "cancel";
        fileObj = fileObj.fileObj;
      }

      this.uploadTool.cancelTask(fileObj);
    },
    handleDelete(fileObj) {
      this.uploadTool.deleteInFileList(fileObj);
    },
    onChange(res) {
      const files = res.srcElement.files;
      const fileList = this.uploadTool.addNewFilesToList(Array.from(files));
      // 初始化fileObj对象
      fileList.forEach((fileObj) => {
        this.$set(fileObj, "__status", "beforeUploading");
        this.$set(fileObj, "__progress", "0%");
        this.$set(fileObj, "__speed", "0K/s");
        this.$set(fileObj, "__size", this.bytesToSize(fileObj.file.size));
      });
    },
    getMarkReq(params) {
      return new Promise((reslove, reject) => {
        // 需要和owen、jchen对接获取场景值
        axios.post('/xe.material-center.*****/1.0.0', params)
          .then(res => {
            const data = res.data
            if (data.code == 0 && data.data) {
              reslove(data.data)
            }
            reject(res)
          }).catch((err) => {
            reject(err)
          })
      })
    },
    // 批量上传文件
    upload() {
      // 进行初始化
      this.uploadTool.uploadFiles();
    },
    // 容量转换
    bytesToSize(bytes, size = 3) {
      bytes = Number(bytes);
      if (bytes === 0) return "0 B";
      var k = 1000, // or 1024
        sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"],
        i = Math.floor(Math.log(bytes) / Math.log(k));

      return (bytes / Math.pow(k, i)).toPrecision(size) + " " + sizes[i];
    },
  },
};
</script>

<style lang="scss" scoped>
.upload-tool {
  &__item {
    margin-top: 20px;
    line-height: 1.5;

    &-label {
      width: 100px;
      margin-right: 10px;
    }

    &-li {
      margin-top: 20px;
      border-bottom: 1px dashed #bbb;
    }
  }
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204

# 参数说明

参数 说明 类型 默认值
fileType 文件类型 number 详见FILETYPE
sycnMaterialCenter 是否同步到素材中心 boolean false
customReq 自定义请求 url {} 详见CUSTOM_REQ
maxUploadingFiles 最大同时上传数量 number 1
getMarkReq 获取uploadMark的请求,请求业务后端接口,通过 Promise.resove({uploadMark})方式给到。详见demo ()=> Promise ()=> Promise.reject('没有 uploadMark 方法')
customUploadMark 自定义使用 uploadMark,为 true时 需要配合 resetUploadMar,uploadMark 详见 uplaodTool.uploadMark boolean false
onSuccess 成功回调 function fileObj, res
onProgress 进度回调 function fileObj,{ percent,speed,loaded,total }
onStateChange 状态变化回调 function fileObj, status, beforeStatus
onError 失败回调 function fileObj, error(详见ERROR_CODE)

# 文件类型 FILETYPE

const IMAGE = 1;
const AUDIO = 2;
const VEDIO = 3;
const BOOK = 4;
const FILE = 5;
1
2
3
4
5

# 自定义请求 CUSTOM_REQ

{
  getConfig: {
    url: '/xe.material-center.upload/getUploadConf',
  },
  getSign: {
    url: '/xe.material-center.upload/getUploadSign',
  },
  checkHwVodSource: {
    url: '/xe.material-center.upload/asset.details.get'
  },
  uploadError: {
    url: '/xe.merchant-serve.feedback.fe/1.0.0'
  },
  saveFileToMaterialCenter: {
    url: '/xe.material-center.upload/upload'
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 错误码 ERROR_CODE

const INIT_COMMON_SDK_ERROR = 0 // 当前SDK初始化失败
const INIT_SDK_ERROR = 1; //第三方云SDK初始化失败;
const GET_SIGN_ERROR = 2; //获取签名失败;
const SDK_UPLOAD_ERROR = 3; //SDK上传失败;
const CHECK_VOD_RESOURCE_ERROR = 4; //查询VOD资源失败
const SYNC_MATERIAL_ERROR = 5; //同步素材中心失败(单个文件)
const UPLOAD_REQUEST_ERROR = 6 //同步素材中心接口失败
1
2
3
4
5
6
7

# 上传对象实例说明

# 实例参数

参数 说明 类型 默认值
fileType 文件类型 详见FILETYPE number 1
uploadMark 上传标识,用于请求方法,当uploadMark对应的signMark消费完一分钟后当前标识会被销毁,无法继续请求接口 string ''
sdkConfig SDK配置,从接口中请求 object null
platform 云平台 详见PLATFORM number ''
sycnMaterialCenter 是否同步到素材中心 boolean false
customReq 自定义请求 url {} 详见CUSTOM_REQ
maxUploadingFiles 最大同时上传数量 number 1
getMarkReq 文件名 string 参数
customUploadMark 自定义使用 uploadMark 不推荐使用 boolean false
sdk 多云上传SDK object null
isUploading 多云上传SDK object null
successCount 成功数量 number 0
completeCount 完成数量 = 成功数量 + 失败数量 number 0
uploadingCount 上传中的数量 number 0
fileList 文件列表Array<fileObj> array []
waitingUploadFileList 等待上传文件列表Array<fileObj> array []
onSuccess 成功回调 function fileObj, res
onProgress 进度回调 function fileObj,{ percent,speed,loaded,total }
onStateChange 状态变化回调 function fileObj, status, beforeStatus
onError 失败回调 function fileObj, error(详见ERROR_CODE)

# 实例方法

事件 说明 参数 返回
initDone 初始化SDK Promise -- 返回Promise then说明初始化完成、否则失败
addNewFilesToList 添加file到文件列表中 files Array<file>, loc(start加到队头,加到队尾) fileListArray<fileObj>
deleteInFileList 从列表中删除一个文件 fileObj --
uploadFiles 上传列表中的文件,需要先通过 addNewFilesToList 添加到文件列表中,再进行上传(注意如果再初始化完成后,再次调用uploadFiles 会重置文件列表 ) -- --
cancelTask 取消某个任务 fileObj, needDelete(是否需要从列表中删除,默认为true) fileObj
cancelAllTask 取消所有任务、不会从列表中删除任务 fileListArray<fileObje>默认是当前fileList 取消的文件列表
resetUploadMark customUploadMark 为 true 时需要自行维护这个值,uploadMark 详见 uplaodTool.uploadMark -- --
resetUpload 初始化上传列表和数量等信息,恢复到initDone.then以后的状态 -- --
handleSaveToMaterial 同步到素材中心 fileObjListArray<fileObject>, callback(uploadSuccesList, uploadFailList, failInfo), categoryId(分组ID) --

# 云平台 PLATFORM

"TX_COS" //腾讯 COS
"TX_VOD" //腾讯 VOD
"ZJ_VOD" //字节 VOD
"HW_VOD" //华为 VOD
1
2
3
4

# fileObj 对象

为sdk内部维护的文件对象,通过 uploadFile 或者 addNewFilesToList 获得,可以直接展示文件对象内容。推荐使用 __xxx 双下划线进行命名,避免命名冲突。

参数 说明 类型 默认值
fileName 文件名 string --
type 文件对象类型 详见FILEOBJ_TYPE number 1
file 文件对象 file file
fileType 文件类型 详见FILETYPE number 1
materialProperty 素材属性 { tempUrl: 图片临时地址 width: 图片宽度 ,height: 图片高度 ,duration: 音频长度 } object { tempUrl: '', width: 0, height: 0,duration: ''}
materialInfo 同步素材中心后保存的关联信息,参数见文档http://doc.xiaoeknow.com/web/#/308?page_id=5238&keyword=upload object { material_id: '' // 素材ID }
taskId 上传任务 id 用于对上传任务的操作 string ''
fileId Vod文件 id string ''
url 对象存储源链接 string ''
accessUrl CDN 链接 string ''
status 文件状态 详见STATUS number 1
signMark 签名标识 string ''
uploadMark 上传的签名标识 string ''
percent 上传进度 number 0
speed 上传速度 number 0
loaded 已加载大小 number 0
total 总大小 number 0
useTime 上传到云所用的时间(只有华为云、字节云使用) number 0
sdk 对应云的上传 SDK object null
STATUS 详见STATUS number 上传状态 STATUS
FILE_TYPE 详见FILE_TYPE number 1
FILEOBJ_TYPE 详见FILEOBJ_TYPE number 1

# 上传状态 STATUS

const BEFORE_UPLOAD = 1; // 等待上传
const UPLOADING = 2; // 上传中
const UPLOAD_MATERIAL_SUCCESS = 3; // 上传素材中心成功
const UPLOAD_CLOUD_FAIL = 4; // 上传云端失败
const UPLOAD_CLOUD_SUCCESS = 5; // 上传云端成功
const CANCEL_TASK = 6; //取消
const UPLOAD_MATERIAL_FAIL = 8; // 上传素材中心失败
const CHECK_HW_VOD_RESOURCE_FAIL = 10 // 查询华为VOD资源失败
1
2
3
4
5
6
7
8

# 文件类型 FILETYPE

const IMAGE = 1;
const AUDIO = 2;
const VEDIO = 3;
const BOOK = 4;
const FILE = 5;
1
2
3
4
5

# 文件对象类型 FILEOBJ_TYPE

const CUSTOM_UPLOAD = 1 // 自定义上传
const COMMON_UPLOAD = 2 // 通用上传
1
2

# 更新日志

# 1.0.1

owenlai | Apr 20, 2023 | 合并链接 (opens new window)

  1、添加错误日志
1

# 1.0.0

owenlai | Apr 18, 2023 | 合并链接 (opens new window)

  1、上传添加uplaodMark、signMark标识
  2、返回签名进行加解密
  3、cos上传使用预签名上传
  4、完善错误上报和改造同步素材中心配置的获取参数和请求的方法
1
2
3
4