|
@@ -1,355 +0,0 @@
|
|
|
-<template>
|
|
|
- <CollapseContainer
|
|
|
- class="attachment-container"
|
|
|
- title="附件管理"
|
|
|
- :canExpan="false"
|
|
|
- helpMessage="主要用于管理上传到服务器或第三方存储的数据"
|
|
|
- >
|
|
|
- <a-button type="default" class="mr-2"> 全部 </a-button>
|
|
|
- <a-button type="default" class="mr-2"> 图片 </a-button>
|
|
|
- <a-button type="default" class="mr-2"> 音频 </a-button>
|
|
|
- <a-button type="default" class="mr-2"> 视频 </a-button>
|
|
|
- <a-button type="default" class="mr-2"> 文档 </a-button>
|
|
|
- <a-button type="default" class="mr-2"> 应用 </a-button>
|
|
|
- <a-button type="default" class="mr-2"> 压缩包 </a-button>
|
|
|
- <BasicTable ref="tableRef" :canResize="true" @register="registerTable">
|
|
|
- <template #action="{ record, column }">
|
|
|
- <TableAction :actions="createActions(record, column)" stopButtonPropagation />
|
|
|
- </template>
|
|
|
- <template #toolbar>
|
|
|
- <a-upload
|
|
|
- :showUploadList="false"
|
|
|
- :multiple="false"
|
|
|
- :before-upload="beforeUpload"
|
|
|
- @change="handleChange"
|
|
|
- >
|
|
|
- <a-button type="primary" :disabled="disabled">
|
|
|
- {{ t('component.upload.upload') }}
|
|
|
- </a-button>
|
|
|
- </a-upload>
|
|
|
- <a-button color="error" @click="deleteBatches">
|
|
|
- {{ t('common.delText') }}
|
|
|
- </a-button>
|
|
|
- </template>
|
|
|
- <a-modal :visible="progress_show" :footer="null" :closable="false">
|
|
|
- <div class="upload-progress">
|
|
|
- <p><strong>文件上传中</strong></p>
|
|
|
- <a-progress :percent="percent" />
|
|
|
- </div>
|
|
|
- </a-modal>
|
|
|
- </BasicTable>
|
|
|
- </CollapseContainer>
|
|
|
-</template>
|
|
|
-<script lang="ts">
|
|
|
- import { useMessage } from '/@/hooks/web/useMessage';
|
|
|
- import { defineComponent, nextTick, reactive, ref, toRefs, unref } from 'vue';
|
|
|
- // import Upload from '/@/components/customComponents/upload.vue';
|
|
|
- import { Upload, Progress, Modal } from 'ant-design-vue';
|
|
|
- import { CollapseContainer } from '/@/components/Container/index';
|
|
|
- import { adapt } from '/@/utils/adapt';
|
|
|
- import { useI18n } from '/@/hooks/web/useI18n';
|
|
|
- import md5 from 'crypto-js/md5';
|
|
|
- import {
|
|
|
- BasicTable,
|
|
|
- useTable,
|
|
|
- TableAction,
|
|
|
- ActionItem,
|
|
|
- EditRecordRow,
|
|
|
- TableActionType,
|
|
|
- } from '/@/components/Table';
|
|
|
- import { columns } from './data';
|
|
|
- import { getAttachmentList } from '/@/api/sys/general';
|
|
|
- import { uploadApi } from '/@/api/sys/upload';
|
|
|
-
|
|
|
- interface FileItem {
|
|
|
- uid: string;
|
|
|
- name?: string;
|
|
|
- status?: string;
|
|
|
- response?: string;
|
|
|
- url?: string;
|
|
|
- type?: string;
|
|
|
- size: number;
|
|
|
- originFileObj: any;
|
|
|
- }
|
|
|
-
|
|
|
- export default defineComponent({
|
|
|
- name: 'Attchment',
|
|
|
- components: {
|
|
|
- CollapseContainer,
|
|
|
- BasicTable,
|
|
|
- TableAction,
|
|
|
- [Upload.name]: Upload,
|
|
|
- [Modal.name]: Modal,
|
|
|
- [Progress.name]: Progress,
|
|
|
- },
|
|
|
- setup() {
|
|
|
- const { t } = useI18n();
|
|
|
- const { createMessage } = useMessage();
|
|
|
- const { success /*, error */ } = createMessage;
|
|
|
- const tableHeight = adapt().tableHeight;
|
|
|
- const state = reactive({
|
|
|
- groupList: [] as object[],
|
|
|
- group: 'basic',
|
|
|
- disabled: false,
|
|
|
- tempThreads: 5,
|
|
|
- progress_show: false,
|
|
|
- percent: 0,
|
|
|
- chunkRetry: 4, // 重试次数限制
|
|
|
- });
|
|
|
- const tableRef = ref<Nullable<TableActionType>>(null);
|
|
|
- const [registerTable] = useTable({
|
|
|
- columns: columns,
|
|
|
- maxHeight: tableHeight,
|
|
|
- afterFetch: afterFetch,
|
|
|
- api: getAttachmentList,
|
|
|
- actionColumn: {
|
|
|
- width: 160,
|
|
|
- title: '操作',
|
|
|
- dataIndex: 'action',
|
|
|
- slots: { customRender: 'action' },
|
|
|
- fixed: undefined,
|
|
|
- },
|
|
|
- showIndexColumn: false,
|
|
|
- pagination: true,
|
|
|
- });
|
|
|
- function afterFetch(res) {
|
|
|
- console.log(`res`, res);
|
|
|
- }
|
|
|
- function getTableAction() {
|
|
|
- // 获取组件
|
|
|
- const tableAction = unref(tableRef);
|
|
|
- if (!tableAction) {
|
|
|
- throw new Error('tableAction is null');
|
|
|
- }
|
|
|
- return tableAction;
|
|
|
- }
|
|
|
-
|
|
|
- function getFileMD5(file) {
|
|
|
- return md5(file.name + file.size + file.lastModifiedDate);
|
|
|
- }
|
|
|
-
|
|
|
- async function mergeRequest(fileMd5) {
|
|
|
- return new Promise((resolve, reject) => {
|
|
|
- const mergeFormData = new FormData();
|
|
|
- mergeFormData.append('fileMd5', fileMd5);
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- function createFileChunk(file, size) {
|
|
|
- const fileChunkList: object[] = [];
|
|
|
- let count = 0;
|
|
|
- let index = 0;
|
|
|
- while (count < file.size) {
|
|
|
- fileChunkList.push({
|
|
|
- file: file.slice(count, count + size),
|
|
|
- hash: file.name + '-' + index, // 生成切片名称
|
|
|
- });
|
|
|
- count += size;
|
|
|
- index += 1;
|
|
|
- }
|
|
|
- return fileChunkList;
|
|
|
- }
|
|
|
- // 判断文件是否上传过,获取fileId
|
|
|
- async function checkFile(file) {
|
|
|
- const md5 = getFileMD5(file);
|
|
|
- file.md5 = md5;
|
|
|
- const formData = new FormData();
|
|
|
- formData.append('fileMd5', md5);
|
|
|
- formData.append('fileName', file.name);
|
|
|
- formData.append('fileSize', file.size);
|
|
|
- await uploadChunks(file);
|
|
|
- }
|
|
|
- async function uploadChunks(file) {
|
|
|
- // let chunkSize = updateCchunkSize(file);
|
|
|
- let chunkSize = 64 * 1024;
|
|
|
- console.log(`chunkSize`, chunkSize);
|
|
|
- const fileChunkList = createFileChunk(file, chunkSize);
|
|
|
- console.log(`fileChunkList`, fileChunkList);
|
|
|
- file.chunkList = fileChunkList.map(({ file, hash }, index) => {
|
|
|
- console.log(`filessssss`, file);
|
|
|
- return {
|
|
|
- index,
|
|
|
- source: file,
|
|
|
- hash: hash,
|
|
|
- size: file.size,
|
|
|
- };
|
|
|
- });
|
|
|
- var chunkData = file.chunkList;
|
|
|
- console.log(`chunkData`, chunkData);
|
|
|
- return new Promise((resolve, reject) => {
|
|
|
- const requestDataList = chunkData.map((value) => {
|
|
|
- const formData = new FormData();
|
|
|
- formData.append('fileMd5', file.md5);
|
|
|
- formData.append('chunk', value.index);
|
|
|
- formData.append('hash', value.hash);
|
|
|
- formData.append('file', value.source);
|
|
|
- console.log(`formData`, formData);
|
|
|
- return { formData, index: value.index, md5: file.md5, file };
|
|
|
- });
|
|
|
- try {
|
|
|
- console.log(`requestDataList1111`, requestDataList);
|
|
|
- const ret = sendRequest(requestDataList);
|
|
|
- // console.log('上传结束,参数:', ret, chunkData, file.md5);
|
|
|
- resolve(ret);
|
|
|
- } catch (error) {
|
|
|
- // reject('sendRequest 失败', error);
|
|
|
- console.log(`error`, error);
|
|
|
- reject(error);
|
|
|
- }
|
|
|
- }).then(async (res) => {
|
|
|
- if (res == file.md5) {
|
|
|
- // console.log('--- ' + file.name + ' 文件开始合并----')
|
|
|
- await mergeRequest(file.md5);
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- function beforeUpload(file: FileItem) {
|
|
|
- file.status = 'uploading';
|
|
|
- checkFile(file);
|
|
|
- return false;
|
|
|
- }
|
|
|
- // 根据文件大小,分配上传分片大小
|
|
|
- function updateCchunkSize(file) {
|
|
|
- let chunkSize = 0;
|
|
|
- if (file.size > 2000 * 1024 * 1024) {
|
|
|
- chunkSize = 1024 * 1024 * 15;
|
|
|
- } else if (file.size > 1000 * 1024 * 1024) {
|
|
|
- chunkSize = 1024 * 1024 * 10;
|
|
|
- } else if (file.size > 500 * 1024 * 1024) {
|
|
|
- chunkSize = 1024 * 1024 * 8;
|
|
|
- } else {
|
|
|
- chunkSize = 2 * 1024 * 1024;
|
|
|
- }
|
|
|
- return chunkSize;
|
|
|
- }
|
|
|
-
|
|
|
- // 并发,重试请求
|
|
|
- async function sendRequest(list) {
|
|
|
- var finished = 0;
|
|
|
- const retryArr: any[] = []; // retryArr.length代表请求数,值代表重试次数
|
|
|
- var currentFileInfo;
|
|
|
- const total = list.length;
|
|
|
- // 所有请求都存放这个promise中
|
|
|
- console.log(`list`, list);
|
|
|
- console.log(`total`, total);
|
|
|
- state.progress_show = true;
|
|
|
- return new Promise((resolve, reject) => {
|
|
|
- const handler = () => {
|
|
|
- if (list.length) {
|
|
|
- const formInfo = list.shift();
|
|
|
- const index = formInfo.index;
|
|
|
- console.log(`list`, list);
|
|
|
- console.log(`formInfo`, formInfo);
|
|
|
- uploadApi(formInfo)
|
|
|
- .then((res) => {
|
|
|
- console.log(`res`, res);
|
|
|
- if (res) {
|
|
|
- state.percent = parseInt((finished / total) * 100);
|
|
|
- currentFileInfo = formInfo;
|
|
|
- finished++;
|
|
|
- console.log(`finished`, finished);
|
|
|
- console.log(`total`, total);
|
|
|
- handler();
|
|
|
- }
|
|
|
- return res;
|
|
|
- })
|
|
|
- .catch((err) => {
|
|
|
- console.log(`err`, err);
|
|
|
- if (typeof retryArr[index] !== 'number') {
|
|
|
- retryArr[index] = 1;
|
|
|
- }
|
|
|
- if (retryArr[index] >= state.chunkRetry) {
|
|
|
- return reject(retryArr);
|
|
|
- }
|
|
|
- retryArr[index]++; // 累加
|
|
|
- state.tempThreads++; // 释放当前占用的通道
|
|
|
- list.push(formInfo); // 将失败的重新加入队列
|
|
|
- handler();
|
|
|
- });
|
|
|
- }
|
|
|
- if (finished >= total) {
|
|
|
- state.progress_show = false;
|
|
|
- state.percent = 0;
|
|
|
- getTableAction().reload();
|
|
|
- success('文件上传成功');
|
|
|
- resolve(currentFileInfo.md5); // 输出当前完成上传的文件信息
|
|
|
- }
|
|
|
- };
|
|
|
- // 控制并发
|
|
|
- for (let i = 0; i < state.tempThreads; i++) {
|
|
|
- handler();
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- function handleChange(info) {
|
|
|
- console.log(`info`, info);
|
|
|
- }
|
|
|
-
|
|
|
- async function handleGroupBtn(group) {
|
|
|
- await nextTick();
|
|
|
- getTableAction().reload();
|
|
|
- state.group = group.toLowerCase();
|
|
|
- }
|
|
|
-
|
|
|
- function handleTableReset() {
|
|
|
- getTableAction().reload();
|
|
|
- }
|
|
|
-
|
|
|
- async function handleEdit(record: Recordable) {
|
|
|
- console.log(`record`, record);
|
|
|
- console.log('=====编辑');
|
|
|
- }
|
|
|
- async function handleDelete(record: Recordable) {
|
|
|
- console.log(`record`, record);
|
|
|
- console.log('删除=====');
|
|
|
- }
|
|
|
-
|
|
|
- function createActions(record: EditRecordRow): ActionItem[] {
|
|
|
- return [
|
|
|
- {
|
|
|
- label: '编辑',
|
|
|
- icon: 'ant-design:edit-outlined',
|
|
|
- color: 'warning',
|
|
|
- onClick: handleEdit.bind(null, record),
|
|
|
- },
|
|
|
- {
|
|
|
- label: '删除',
|
|
|
- color: 'error',
|
|
|
- icon: 'ic:outline-delete-outline',
|
|
|
- popConfirm: {
|
|
|
- title: '是否确认删除',
|
|
|
- confirm: handleDelete.bind(null, record),
|
|
|
- },
|
|
|
- },
|
|
|
- ];
|
|
|
- }
|
|
|
- return {
|
|
|
- t,
|
|
|
- createActions,
|
|
|
- tableRef,
|
|
|
- registerTable,
|
|
|
- beforeUpload,
|
|
|
- handleChange,
|
|
|
- handleGroupBtn,
|
|
|
- handleTableReset,
|
|
|
- ...toRefs(state),
|
|
|
- };
|
|
|
- },
|
|
|
- });
|
|
|
-</script>
|
|
|
-<style>
|
|
|
- .attachment-container {
|
|
|
- position: relative;
|
|
|
- }
|
|
|
-
|
|
|
- .vben-collapse-container__body > .mr-2 {
|
|
|
- margin-top: 5px;
|
|
|
- font-weight: 550 !important;
|
|
|
- }
|
|
|
-
|
|
|
- .upload-progress {
|
|
|
- padding: 20px 30px;
|
|
|
- }
|
|
|
-</style>
|