<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>
    </BasicTable>
    <a-modal :visible="progress_show" :footer="null" :closable="false">
      <div class="upload-progress">
        <p><strong>文件上传中</strong></p>
        <a-progress :percent="percent" />
      </div>
    </a-modal>
  </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) => {
          console.log(`resolve`, resolve);
          console.log(`reject`, 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>
