封装文件上传分包
This commit is contained in:
@@ -21,11 +21,13 @@
|
|||||||
"dingtalk-jsapi": "^3.0.20",
|
"dingtalk-jsapi": "^3.0.20",
|
||||||
"echarts": "5.2.2",
|
"echarts": "5.2.2",
|
||||||
"element-ui": "2.15.6",
|
"element-ui": "2.15.6",
|
||||||
|
"js-sha3": "^0.9.3",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"nprogress": "0.2.0",
|
"nprogress": "0.2.0",
|
||||||
"screenfull": "5.2.0",
|
"screenfull": "5.2.0",
|
||||||
"serve": "^14.2.0",
|
"serve": "^14.2.0",
|
||||||
"sign-canvas": "1.1.4",
|
"sign-canvas": "1.1.4",
|
||||||
|
"spark-md5": "^3.0.2",
|
||||||
"vue": "^2.6.14",
|
"vue": "^2.6.14",
|
||||||
"vue-cropper": "^0.6.2",
|
"vue-cropper": "^0.6.2",
|
||||||
"vue-cropperjs": "^2.2.2",
|
"vue-cropperjs": "^2.2.2",
|
||||||
|
|||||||
@@ -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> -->
|
<!-- <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="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="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>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
@@ -155,9 +155,14 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-collapse-item>
|
</el-collapse-item>
|
||||||
|
|
||||||
</el-collapse>
|
</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>
|
</el-dialog>
|
||||||
|
<input @change="onClickFile($event)" type="file">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -165,14 +170,18 @@
|
|||||||
import columns from "./columns";
|
import columns from "./columns";
|
||||||
import { getClass, getClassStudent, postManager, putManager, deleteManager, getGuardian } from "./api";
|
import { getClass, getClassStudent, postManager, putManager, deleteManager, getGuardian } from "./api";
|
||||||
import { getRuleGroup } from "../../regulation/api";
|
import { getRuleGroup } from "../../regulation/api";
|
||||||
|
import { Loading } from 'element-ui';
|
||||||
import { formatDate } from "@/com/index";
|
import { formatDate } from "@/com/index";
|
||||||
import CommonHead from './components/CommonHead.vue'
|
import CommonHead from './components/CommonHead.vue'
|
||||||
|
import { cutUpload } from "@/com/cutUpload";
|
||||||
|
// import workerUrl from '@/com/worker.js';
|
||||||
|
// import { cutFile } from '@/com/cutFile'
|
||||||
const FlagEnum = {
|
const FlagEnum = {
|
||||||
INTO: 0,// 进
|
INTO: 0,// 进
|
||||||
OUT: 1,// 出
|
OUT: 1,// 出
|
||||||
MORNING: 2, // 早上到校时间
|
MORNING: 2, // 早上到校时间
|
||||||
};
|
};
|
||||||
|
let loading
|
||||||
export default {
|
export default {
|
||||||
name: "deviceManagement",
|
name: "deviceManagement",
|
||||||
data() {
|
data() {
|
||||||
@@ -217,8 +226,9 @@ export default {
|
|||||||
/* 设置规则组 */
|
/* 设置规则组 */
|
||||||
isRuleDialog: false, // 进出校规则模态框
|
isRuleDialog: false, // 进出校规则模态框
|
||||||
activeName: '', // 展开的规则组
|
activeName: '', // 展开的规则组
|
||||||
radio: '',
|
radio: '', // 校区选中的规则组
|
||||||
ruleGroupArr: [], // 规则组数据
|
ruleGroupArr: [], // 规则组数据
|
||||||
|
loadingText: '打包中'
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
@@ -235,8 +245,62 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
|
// console.log(workerUrl)
|
||||||
|
// let worker = new Worker(workerUrl);
|
||||||
},
|
},
|
||||||
methods: {
|
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(){
|
ruleList(){
|
||||||
getRuleGroup().then( res =>{
|
getRuleGroup().then( res =>{
|
||||||
|
|||||||
@@ -5665,6 +5665,11 @@ js-message@1.0.7:
|
|||||||
resolved "https://registry.npmmirror.com/js-message/-/js-message-1.0.7.tgz"
|
resolved "https://registry.npmmirror.com/js-message/-/js-message-1.0.7.tgz"
|
||||||
integrity sha512-efJLHhLjIyKRewNS9EGZ4UpI8NguuL6fKkhRxVuMmrGV2xN/0APGdQYwLFky5w9naebSZ0OwAGp0G6/2Cg90rA==
|
integrity sha512-efJLHhLjIyKRewNS9EGZ4UpI8NguuL6fKkhRxVuMmrGV2xN/0APGdQYwLFky5w9naebSZ0OwAGp0G6/2Cg90rA==
|
||||||
|
|
||||||
|
js-sha3@^0.9.3:
|
||||||
|
version "0.9.3"
|
||||||
|
resolved "https://registry.npmmirror.com/js-sha3/-/js-sha3-0.9.3.tgz#f0209432b23a66a0f6c7af592c26802291a75c2a"
|
||||||
|
integrity sha512-BcJPCQeLg6WjEx3FE591wVAevlli8lxsxm9/FzV4HXkV49TmBH38Yvrpce6fjbADGMKFrBMGTqrVz3qPIZ88Gg==
|
||||||
|
|
||||||
js-tokens@^4.0.0:
|
js-tokens@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz"
|
resolved "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz"
|
||||||
@@ -8336,6 +8341,11 @@ source-map@^0.7.3:
|
|||||||
resolved "https://registry.npmmirror.com/source-map/-/source-map-0.7.4.tgz"
|
resolved "https://registry.npmmirror.com/source-map/-/source-map-0.7.4.tgz"
|
||||||
integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==
|
integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==
|
||||||
|
|
||||||
|
spark-md5@^3.0.2:
|
||||||
|
version "3.0.2"
|
||||||
|
resolved "https://registry.npmmirror.com/spark-md5/-/spark-md5-3.0.2.tgz#7952c4a30784347abcee73268e473b9c0167e3fc"
|
||||||
|
integrity sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw==
|
||||||
|
|
||||||
spdx-correct@^3.0.0:
|
spdx-correct@^3.0.0:
|
||||||
version "3.2.0"
|
version "3.2.0"
|
||||||
resolved "https://registry.npmmirror.com/spdx-correct/-/spdx-correct-3.2.0.tgz"
|
resolved "https://registry.npmmirror.com/spdx-correct/-/spdx-correct-3.2.0.tgz"
|
||||||
|
|||||||
Reference in New Issue
Block a user