封装文件上传分包
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
import { getProgress, postTask, getPartUrl, getMerge } from "/src/com/uploadApi";
|
||||
// import createOverallHase from '@/com/createOverallHase'
|
||||
import SparkMD5 from 'spark-md5'
|
||||
import axios from "axios";
|
||||
|
||||
const DEFAULT_SIZE = 20 * 1024 * 1024
|
||||
export function cutUpload (file, isFace = false, backUploadProgress){
|
||||
return new Promise((resolve, reject) => {
|
||||
const PART_SIZE = 1024 * 1024 * 20; // 20M
|
||||
// 计算上传进度
|
||||
const calculateProgress = (progressArr, total) => {
|
||||
let count = 0;
|
||||
progressArr.forEach((item) => {
|
||||
count += item;
|
||||
});
|
||||
if (count == total) {
|
||||
count = Math.floor(total * 0.9999);//如果上传进度为100%,伪造上传进度,为合并文件做准备
|
||||
}
|
||||
return count;
|
||||
};
|
||||
// 分片上传函数
|
||||
const requestUploadFun = async (url, fileData, uploadProgress) => {
|
||||
try {
|
||||
await axios.put(url, fileData, {
|
||||
headers: {
|
||||
"Content-Type": "application/octet-stream",
|
||||
},
|
||||
onUploadProgress: function (progressEvent) {
|
||||
uploadProgress(progressEvent.loaded);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
reject(error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const uploadChunks = async (file, identifier, progressData, uploadProgressFun) => {
|
||||
const progressEvent = { total: file.size, loaded: 0 };
|
||||
const progressArr = [];
|
||||
const partNumberSet = new Set(progressData.parts.map((item) => item.partNumber));
|
||||
const partCount = Math.ceil(file.size / PART_SIZE);
|
||||
let totalSize = 0;
|
||||
const partArr = [];
|
||||
for (let i = 0; i < partCount; i++) {
|
||||
let partNumber = i + 1;
|
||||
const start = PART_SIZE * (partNumber - 1);
|
||||
const end = Math.min(start + PART_SIZE, file.size);
|
||||
if (!partNumberSet.has(partNumber)) {
|
||||
const blob = file.slice(start, end);
|
||||
totalSize += blob.size;
|
||||
progressArr[partNumber] = 0;
|
||||
partArr.push({ partNumber, blob });
|
||||
} else {
|
||||
progressArr[partNumber] = end - start;
|
||||
progressEvent.loaded = calculateProgress(progressArr, progressEvent.total);
|
||||
uploadProgressFun(progressEvent);
|
||||
}
|
||||
}
|
||||
|
||||
const uploadUrlDataArr = await Promise.all(partArr.map(async item => {
|
||||
const urlData = await getPartUrl(identifier, item.partNumber);
|
||||
return {
|
||||
uploadUrl: urlData.uploadUrl,
|
||||
fileData: item.blob,
|
||||
partNumber: item.partNumber
|
||||
}
|
||||
}));
|
||||
|
||||
const uploadPromises = uploadUrlDataArr.map(async (uploadUrlData, i) => {
|
||||
return requestUploadFun(uploadUrlData.uploadUrl, uploadUrlData.fileData, function (loaded) {
|
||||
progressArr[uploadUrlData.partNumber] = loaded;
|
||||
progressEvent.loaded = calculateProgress(progressArr, progressEvent.total);
|
||||
uploadProgressFun(progressEvent);
|
||||
});
|
||||
});
|
||||
|
||||
await Promise.all(uploadPromises);
|
||||
};
|
||||
|
||||
// 获取hash
|
||||
const uploadFile = async (file, onUploadProgress = () => {}, checkFace, onCheckFace = () => {}) => {
|
||||
if (file) {
|
||||
const hashStr = await createOverallHase(file);
|
||||
const fileForm = {
|
||||
identifier: hashStr,
|
||||
fileName: file.name,
|
||||
fileSize: file.size.toString(),
|
||||
checkFace: checkFace,
|
||||
};
|
||||
uploadProgress(file, fileForm, onCheckFace, onUploadProgress)
|
||||
} else {
|
||||
console.log("文件为空");
|
||||
}
|
||||
};
|
||||
|
||||
let obj = {}
|
||||
uploadFile(file, function(Progress) {
|
||||
backUploadProgress(Progress)
|
||||
}, isFace, function(faceData){
|
||||
resolve({...obj, ...faceData})
|
||||
})
|
||||
|
||||
// 判断任务 是否存在
|
||||
const uploadProgress = async (file, fileForm, onCheckFace, onUploadProgressFun) => {
|
||||
try {
|
||||
const progressData = await getProgress(fileForm.identifier, fileForm.checkFace);
|
||||
if (progressData.errMessage === "文件上传任务不存在") {
|
||||
await postTask(fileForm);
|
||||
await uploadProgress(file, fileForm, onCheckFace, onUploadProgressFun);
|
||||
} else {
|
||||
if (!progressData.finished) {
|
||||
if (progressData.parts.length == progressData.totalPartNum) {
|
||||
await getMerge(fileForm.identifier);
|
||||
} else {
|
||||
//const chunksArr = await uploadFile(file);
|
||||
await uploadChunks(file, fileForm.identifier, progressData, onUploadProgressFun);
|
||||
}
|
||||
await uploadProgress(file, fileForm, onCheckFace, onUploadProgressFun);
|
||||
} else {
|
||||
let checkFaceMsg = progressData.checkFaceMsg
|
||||
|
||||
// onUploadProgressFun({ total: Number(file.size), loaded: Number(file.size) });
|
||||
onUploadProgressFun({ total: Number(file.size), loaded: Number(file.size), path: progressData.path })
|
||||
if (fileForm.checkFace) {
|
||||
// onCheckFace({ isFace: progressData.face, checkFaceMsg: progressData.checkFaceMsg });
|
||||
onCheckFace({ total: Number(file.size), loaded: Number(file.size), isFace: progressData.face, checkFaceMsg, path: progressData.path })
|
||||
}
|
||||
// let checkFaceMsg = progressData.checkFaceMsg
|
||||
// resolve({ total: Number(file.size), loaded: Number(file.size), isFace: progressData.face, checkFaceMsg, path: progressData.path });
|
||||
// console.log(progressData.path);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
};
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
// md5
|
||||
const createOverallHase = (file, chunkSize = DEFAULT_SIZE) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const startMs = new Date().getTime();
|
||||
let blobSlice =
|
||||
File.prototype.slice ||
|
||||
File.prototype.mozSlice ||
|
||||
File.prototype.webkitSlice;
|
||||
let chunks = Math.ceil(file.size / chunkSize);
|
||||
let currentChunk = 0;
|
||||
let spark = new SparkMD5.ArrayBuffer(); //追加数组缓冲区。
|
||||
let fileReader = new FileReader(); //读取文件
|
||||
fileReader.onload = function (e) {
|
||||
spark.append(e.target.result);
|
||||
currentChunk++;
|
||||
if (currentChunk < chunks) {
|
||||
loadNext();
|
||||
} else {
|
||||
const md5 = spark.end(); //完成md5的计算,返回十六进制结果。
|
||||
console.log('文件md5计算结束,总耗时:', (new Date().getTime() - startMs) / 1000, 's')
|
||||
resolve(md5);
|
||||
}
|
||||
};
|
||||
fileReader.onerror = function (e) {
|
||||
reject(e);
|
||||
};
|
||||
|
||||
function loadNext() {
|
||||
console.log('当前part number:', currentChunk, '总块数:', chunks);
|
||||
let start = currentChunk * chunkSize;
|
||||
let end = start + chunkSize;
|
||||
(end > file.size) && (end = file.size);
|
||||
fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
|
||||
}
|
||||
loadNext();
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import request from "/src/utils/request";
|
||||
|
||||
|
||||
// 查询分片上传进度
|
||||
export function getProgress(identifier,checkFace){
|
||||
return request({
|
||||
url: `/manager/file/task/${identifier}?checkFace=${checkFace}`,
|
||||
method: 'GET',
|
||||
})
|
||||
}
|
||||
|
||||
// 初始化分片上传
|
||||
export function postTask(data){
|
||||
return request({
|
||||
url: '/manager/file/task',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
||||
// 获取指定分片的上传地址
|
||||
export function getPartUrl(identifier, partNumber){
|
||||
return request({
|
||||
url: `/manager/file/task/part/${identifier}/${partNumber}`,
|
||||
method: 'GET',
|
||||
})
|
||||
}
|
||||
|
||||
// 完成上传时调用
|
||||
export function getMerge(identifier){
|
||||
return request({
|
||||
url: `/manager/file/task/merge/${identifier}`,
|
||||
method: 'GET',
|
||||
})
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<!-- <div v-else style="margin-right: 10px; font-size: 16px; line-height: 27px;font-weight: 700;">{{ classData.className}}</div> -->
|
||||
<el-button @click="onClickUpdate" v-if="nodeData.className" size="mini" type="warning" class="el-icon-edit">修改名称</el-button>
|
||||
<el-button @click="onClickRemove" v-if="nodeData.className" size="mini" type="danger" class="el-icon-delete">删除</el-button>
|
||||
<el-button @click="isRuleDialog = true" v-if="nodeData.className" size="mini" type="primary" class="el-icon-setting">设置规则</el-button>
|
||||
<el-button @click="onClickUpdateRule" v-if="nodeData.className && nodeData.superId === '0'" size="mini" type="primary" class="el-icon-setting">设置规则</el-button>
|
||||
|
||||
</div>
|
||||
</el-card>
|
||||
@@ -155,9 +155,14 @@
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-collapse-item>
|
||||
|
||||
</el-collapse>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="isRuleDialog = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onClickAffirmRule">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<input @change="onClickFile($event)" type="file">
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -165,14 +170,18 @@
|
||||
import columns from "./columns";
|
||||
import { getClass, getClassStudent, postManager, putManager, deleteManager, getGuardian } from "./api";
|
||||
import { getRuleGroup } from "../../regulation/api";
|
||||
|
||||
import { Loading } from 'element-ui';
|
||||
import { formatDate } from "@/com/index";
|
||||
import CommonHead from './components/CommonHead.vue'
|
||||
import { cutUpload } from "@/com/cutUpload";
|
||||
// import workerUrl from '@/com/worker.js';
|
||||
// import { cutFile } from '@/com/cutFile'
|
||||
const FlagEnum = {
|
||||
INTO: 0,// 进
|
||||
OUT: 1,// 出
|
||||
MORNING: 2, // 早上到校时间
|
||||
};
|
||||
let loading
|
||||
export default {
|
||||
name: "deviceManagement",
|
||||
data() {
|
||||
@@ -217,8 +226,9 @@ export default {
|
||||
/* 设置规则组 */
|
||||
isRuleDialog: false, // 进出校规则模态框
|
||||
activeName: '', // 展开的规则组
|
||||
radio: '',
|
||||
radio: '', // 校区选中的规则组
|
||||
ruleGroupArr: [], // 规则组数据
|
||||
loadingText: '打包中'
|
||||
};
|
||||
},
|
||||
components: {
|
||||
@@ -235,8 +245,62 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
// console.log(workerUrl)
|
||||
// let worker = new Worker(workerUrl);
|
||||
},
|
||||
methods: {
|
||||
|
||||
async onClickFile(e) {
|
||||
loading = Loading.service({
|
||||
lock: true,
|
||||
text: '打包上传中...',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
});
|
||||
const file = e.target.files[0]
|
||||
|
||||
cutUpload(file, true, (progressEvent) =>{
|
||||
let progressNum = (progressEvent.loaded / progressEvent.total) * 100
|
||||
loading.text = '上传进度' + progressNum.toFixed(2) + '%'
|
||||
if(progressNum == 100){
|
||||
console.log('完成')
|
||||
loading.text = '上传完成!'
|
||||
console.log(loading.text)
|
||||
setTimeout(() => {
|
||||
loading.close();
|
||||
}, 1000);
|
||||
}
|
||||
console.log(progressEvent.loaded + '/' + progressEvent.total);
|
||||
}).then(res =>{
|
||||
console.log(res)
|
||||
})
|
||||
|
||||
},
|
||||
// 点击确定修改小区规则
|
||||
onClickAffirmRule() {
|
||||
console.log(this.radio)
|
||||
if(!this.radio){
|
||||
this.$message.error('请选择需要设置的规则组')
|
||||
return
|
||||
}
|
||||
this.ruleGroupForm.ruleGroupId = this.radio
|
||||
putManager(this.ruleGroupForm).then(res =>{
|
||||
this.$message.success('修改成功')
|
||||
this.classList();
|
||||
this.nodeData = this.ruleGroupForm.ruleGroupId
|
||||
this.isRuleDialog = false
|
||||
|
||||
})
|
||||
|
||||
},
|
||||
// 点击设置规则组
|
||||
onClickUpdateRule () {
|
||||
this.isRuleDialog = true
|
||||
console.log(this.nodeData)
|
||||
this.ruleGroupForm = JSON.parse(JSON.stringify(this.nodeData))
|
||||
this.radio = this.ruleGroupForm.ruleGroupId
|
||||
|
||||
},
|
||||
// 规则组列表
|
||||
ruleList(){
|
||||
getRuleGroup().then( res =>{
|
||||
|
||||
Reference in New Issue
Block a user