1.初始化Minio
创建minio.js文件
import { getOssSign } from '@/api/upload'
// 初始化minioClient
var Minio = require('minio')
export function initMinio () {
return new Promise((resolve, reject) => {
let localMinio = JSON.parse(localStorage.getItem('os'))
if (localMinio) {
let minioObj = {
endPoint: 'oss.shlgbj.gov.cn',
// port: 9200,
useSSL: true,
accessKey: localMinio.accessid,
secretKey: localMinio.accesskey
}
var minioClient = newMinio(minioObj)
resolve(minioClient)
} else {
let param = { ossType: 'minio' }
getOssSign(param).then(response => {
let minioDeploy = response.data
let minioObj = {
endPoint: 'oss.shlgbj.gov.cn',
// endPoint: '10.0.51.96',
// port: 9200,
useSSL: true,
accessKey: minioDeploy.accessid,
secretKey: minioDeploy.accesskey
// accessKey: 'minioadmin',
// secretKey: 'minioadmin'
}
localStorage.setItem('os', JSON.stringify(minioDeploy))
var minioClient = newMinio(minioObj)
resolve(minioClient)
}).catch(error => {
console.log(error)
reject()
})
}
})
}
export const newMinio = (minioObj) => {
return new Minio.Client(minioObj)
}
2.fileUpload组件使用Minio
<template>
<div class="minioBox">
<section class="uploadBar">
<el-button
class="btn_upload"
icon="el-icon-plus"
@click="getFileName"
type="primary"
>{{uploadText}}</el-button>
<!-- <el-button v-if="fileList.length>0" style="marginRight:10px;" @click="upload" size="mini" type="success">上传</el-button> -->
<input
type="file"
id="minIoFile"
ref="minIoFile"
:accept="allowType"
v-show="false"
@change="getFileObj"
/>
<div class="attachmentsTips el-upload__tip" v-html="note"></div>
</section>
<section class="uploadFileList">
<div v-for="(item, index) in fileList" :key="index" class="fileItem">
<span class="name">{{item.name}}</span>
<!-- <span>({{(item.size/1024/1024).toFixed(2)}}M)</span> -->
<span class="progress_bar">
<el-progress
:percentage="item.uploadProgress"
:format="setItemText(item)"
v-if="item.showBar"
/>
</span>
<div class="btn_right">
<i class="el-icon-circle-check el-icon-upload-success" v-if="!item.showBar"></i>
<i class="el-icon-close" style="cursor: pointer;" @click="remove(item)"></i>
</div>
</div>
</section>
</div>
</template>
<script>
import { confirmOss, getFile } from '@/api/upload'
let stream = require('stream')
import { initMinio } from './minio'
export default {
props: {
uploadText: {
type: String,
default: '添加附件',
},
note: {
type: String,
default: () => ''
},
allowType: {
type: String,
default: () => ''
},
fileList: {
type: Array,
default: () => {
return []
}
},
fileSize: {
type: Number,
default: 20 // 0:表示没有限制
},
onSuccess: {
type: Function,
default: () => { }
},
onRemove: {
type: Function,
default: () => { }
},
},
data () {
return {
// fileList: [],
}
},
methods: {
setItemText (item) {
return () => {
return item.uploadProgress == 0 ? '解析中...' : item.uploadProgress + '%'
}
},
upload () {
this.fileList.map((item, index) => {
this.uploadMinIo(item, index)
})
},
remove (item) {
this.onRemove(item)
},
getFileName () {
let inputDOM = this.$refs.minIoFile
inputDOM.click()
},
getFileObj (event) {
let files = document.getElementById('minIoFile').files
let fileSwitch = true
if (files.length > 0) {
for (let i = 0; i < files.length; i++) {
const sizeLimit = this.fileSize !== 0 ? ((files[i].size / 1024 / 1024).toFixed(2) < this.fileSize) : true
const nameLength = files[i].name.length <= 100
if (!sizeLimit) {
this.$message.error(`上传文件大小不能超过 ${this.fileSize}MB`)
fileSwitch = false
return
}
if (!nameLength) {
this.$message.error(`附件名称过长,请重新上传`)
fileSwitch = false
return
}
}
if (fileSwitch) {
for (let i = 0; i < files.length; i++) {
console.log(files[i][File])
files[i].showBar = true
files[i].uploadProgress = 0
// this.$set(files[i], 'uploadProgress', 0)
this.fileList.push(files[i])
}
}
// this.upload() //多选上传
this.uploadMinIo(files[0])
}
},
//上传文件
async uploadMinIo (fileObj, index) {
let minioClient = await initMinio()
var localMinio = JSON.parse(localStorage.getItem('os'))
let vm = this
// 重置进度条
// vm.uploadProgress = 0
if (fileObj) {
let file = fileObj
//判断是否选择了文件
if (file == undefined) {
this.$message.error(`请上传文件`)
} else {
console.log(file)
//获取文件类型及大小
const filePath = file.name.split('.')
const fileType = filePath[filePath.length - 1].toLowerCase()
const fileNewName = `${filePath[0]}_${new Date().getTime()}.${fileType}`
// const fileName = `${localMinio.bucketName}/${localMinio.dir}/${fileNewName}`
const fileName = `${localMinio.dir}/${fileNewName}`
const mineType = file.type
const fileSize = file.size
//参数
let metadata = {
"content-type": mineType,
"content-length": fileSize
}
//判断储存桶是否存在
minioClient.bucketExists(localMinio.bucketName, function (err) {
if (err) {
console.log(err)
// if (err.code == 'NoSuchBucket') return console.log("bucket does not exist.")
vm.$message.error(err)
return
}
//存在
console.log('Bucket exists.')
//准备上传
let reader = new FileReader()
reader.readAsDataURL(file)
reader.onloadend = function (e) {
const dataurl = e.target.result
//base64转blob
const blob = vm.toBlob(dataurl)
//blob转arrayBuffer
let reader2 = new FileReader()
reader2.readAsArrayBuffer(blob)
reader2.onload = function (ex) {
//定义流
let bufferStream = new stream.PassThrough()
//将buffer写入
bufferStream.end(new Buffer(ex.target.result))
// 单个上传对象进度条控制
let newItem = vm.fileList[vm.fileList.length - 1]
var timer = setInterval(() => {
if (newItem.uploadProgress <= 98) {
newItem.uploadProgress++
vm.$set(vm.fileList, vm.fileList.length - 1, newItem)
}
}, 20)
//上传
minioClient.putObject(localMinio.bucketName, fileName, bufferStream, fileSize, metadata, function (err, etag) {
clearInterval(timer)
if (err == null) {
minioClient.presignedGetObject(localMinio.bucketName, fileName, 24 * 60 * 60, function (err, presignedUrl) {
if (err) {
this.$message.error(err)
return
}
//输出url
let curItem = vm.fileList[vm.fileList.length - 1]
curItem.showBar = false
curItem.uploadProgress = 100
vm.$set(vm.fileList, vm.fileList.length - 1, curItem)
vm.confirmOssUpload(fileObj, fileName)
console.log(presignedUrl)
})
}
})
}
}
})
}
}
},
//base64转blob
toBlob (base64Data) {
let byteString = base64Data
if (base64Data.split(',')[0].indexOf('base64') >= 0) {
byteString = atob(base64Data.split(',')[1]) // base64 解码
} else {
byteString = unescape(base64Data.split(',')[1])
}
// 获取文件类型
let mimeString = base64Data.split(';')[0].split(":")[1] // mime类型
// ArrayBuffer 对象用来表示通用的、固定长度的原始二进制数据缓冲区
// let arrayBuffer = new ArrayBuffer(byteString.length) // 创建缓冲数组
// let uintArr = new Uint8Array(arrayBuffer) // 创建视图
let uintArr = new Uint8Array(byteString.length) // 创建视图
for (let i = 0; i < byteString.length; i++) {
uintArr[i] = byteString.charCodeAt(i)
}
// 生成blob
const blob = new Blob([uintArr], {
type: mimeString
})
// 使用 Blob 创建一个指向类型化数组的URL, URL.createObjectURL是new Blob文件的方法,可以生成一个普通的url,可以直接使用,比如用在img.src上
return blob
},
confirmOssUpload (file, fileName) {
const paramsObj = [{
// moduleId: getMid(),
moduleId: '10102',
orgFileName: file.name,
postName: fileName,
size: file.size + '',
needTransferFormat: 'Y',
disableIdentify: 'N'
}]
confirmOss(paramsObj).then(res => {
res = res.data
getFile({ 'fileId': res[0].fileId }).then(res => {
this.fileList.pop() //删除上传时放入数组的file对象
this.onSuccess(res.data, file)
// this.onSuccess(res.data, file, fileList)
}).catch(error => {
console.log(error)
})
})
}
}
}
</script>
<style lang="scss" scoped>
.minioBox {
color: #000000;
// padding: 10px;
.uploadBar {
display: flex;
.attachmentsTips {
margin-top: 0;
padding-left: 10px;
font-size: 12px;
display: inline-block;
height: 30px;
vertical-align: middle;
line-height: 30px;
color: #aaa;
text-align: left;
}
}
.uploadFileList {
margin-top: 10px;
.fileItem {
display: flex;
align-items: center;
width: 100%;
height: 30px;
.name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.progress_bar {
flex: 1;
margin: 0 20px;
/deep/ .el-progress {
display: flex;
align-items: center;
.el-progress__text {
width: 80px;
}
}
}
.btn_right {
.el-icon-close {
display: none;
}
}
&:hover {
cursor: pointer;
background-color: #f5f7fa;
.el-icon-close {
display: block;
}
.el-icon-upload-success {
display: none;
}
}
i {
margin: 0 5px 0 0;
}
.el-icon-upload-success {
color: #67c23a;
}
.upload-fail {
color: red;
}
}
}
}
</style>
一些坑:
- 使用node的stream模块将file进行了可读流的转化,至今不知为啥可以用;
- 给每个上传附件自定义进度条的时候,set(vm.fileList, vm.fileList.length - 1, curItem)
- 上传中fileList展示区域,本质上是本地文件的进度状态,
成功之后展示已上传的文件信息,此处需要删除上传时放入数组的file对象 this.fileList.pop()
网友评论