<template>
  <div class="task-tree-content" @contextmenu.prevent="">
    <div class="filter-content">
      <filterProject
        @filter-param-change-fun="filterParamChangeFun"
        @expand-tree="changeExpendTypeFun"
      ></filterProject>
    </div>
    <div class="tree-content">
      <el-tree
        ref="taskTreeRef"
        :data="dataSource"
        node-key="id"
        highlight-current
        :expand-on-click-node="false"
        :default-expanded-keys="defaultExpandKeys"
        @current-change="nodeChangeClickFun"
        @node-contextmenu="rowRightClickFun"
      >
        <template #default="{ data }">
          <div class="custom-tree-node">
            <div class="title-info">
              <el-icon v-if="data.nodeType === NODE_TYPE.TASK" :size="16" class="blue">
                <Document />
              </el-icon>
              <el-icon v-else-if="data.nodeType === NODE_TYPE.RUN" :size="16" class="blue">
                <ScaleToOriginal />
              </el-icon>
              <el-icon v-else :size="16" class="blue">
                <Folder />
              </el-icon>
              <span
                v-if="data.nodeType === NODE_TYPE.RUN"
                :title="data.runName"
                class="name ellipsis"
                >{{ data.nodeName || data.runName }}</span
              >

              <span class="name" v-else>{{ data.nodeName || data.runName }}</span>
            </div>

            <div class="run-suatus" v-if="data.nodeType === NODE_TYPE.RUN">
              <el-icon class="info" title="未开始" v-if="data.status === RUN_STATUS.UNSTART">
                <InfoFilled />
              </el-icon>
              <el-icon class="upload" title="进行中" v-if="data.status === RUN_STATUS.RUNNING">
                <HelpFilled />
              </el-icon>
              <el-icon class="success" title="已完成" v-if="data.status === RUN_STATUS.COMPETED">
                <SuccessFilled />
              </el-icon>
              <el-icon class="warn" title="异常" v-if="data.status === RUN_STATUS.UPLOADING">
                <WarningFilled />
              </el-icon>
              <el-icon class="warn" title="异常" v-if="data.status === RUN_STATUS.ERROR">
                <WarningFilled />
              </el-icon>
            </div>
          </div>
        </template>
      </el-tree>
      <createRunDiv
        v-if="showRunCreateOrEditWindow"
        :operate-flag="windowFlag"
        :div-info="rightClickNode"
        @close="showRunCreateOrEditWindow = false"
        @comfirm="createRunFun"
        @update="updateRunInfoFun"
      ></createRunDiv>

      <runVersionTreeDiv
        v-if="showRunVersionTreeWindow"
        @close="showRunVersionTreeWindow = false"
        :current-node-info="rightClickNode"
      ></runVersionTreeDiv>

      <taskRunPerformance
        v-if="showTaskRunPerformanceWindow"
        @close="showTaskRunPerformanceWindow = false"
        :current-node-info="rightClickNodeInfo"
      ></taskRunPerformance>

      <!-- <createRunReport
        v-if="showCreateRunReporteWindow"
        @close="showCreateRunReporteWindow = false"
        :current-node-info="rightClickNodeInfo"
        :parent-node-info="rightClickNodeParentInfo"
        :workspace-info="workspaceNodeInfo"
      ></createRunReport> -->

      <createReportNew
        v-if="showCreateRunReporteWindow"
        @close="showCreateRunReporteWindow = false"
        :runIfno="rightClickNodeInfo"
        :parent-node-info="rightClickNodeParentInfo"
        :workspace-info="workspaceNodeInfo"
      ></createReportNew>
    </div>
    <Teleport to="body">
      <div
        class="fileMenu"
        ref="fileMenuRef"
        :id="'fileMenu' + tableId"
        @contextmenu.stop=""
        @contextmenu.prevent=""
      >
        <p
          class="menuButton"
          v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.TASK"
          @click="showDiaFun('createRun')"
        >
          <el-icon> <CirclePlus /> </el-icon>新建算例
        </p>
        <p
          class="menuButton"
          v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.TASK"
          @click="showDiaFun('updateTask')"
        >
          <el-icon> <Operation /> </el-icon>状态修改
        </p>
        <!-- <p class="menuButton" v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.TASK" @click="showDiaFun('inputParam')">
          <el-icon>
            <SetUp />
          </el-icon>输入参数
        </p> -->
        <p
          class="menuButton"
          v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.TASK"
          @click="showDiaFun('focukTask')"
        >
          <el-icon> <StarFilled /> </el-icon>关注任务
        </p>

        <p
          class="menuButton"
          v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.RUN"
          @click="showDiaFun('createChildRun')"
        >
          <el-icon> <Files /> </el-icon>建子算例
        </p>
        <p
          class="menuButton"
          v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.RUN"
          @click="showDiaFun('copyRun')"
        >
          <el-icon> <DocumentCopy /> </el-icon>复制算例
        </p>
        <!-- <p class="menuButton" v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.RUN" @click="showDiaFun('editRun')">
          <el-icon>
            <Edit />
          </el-icon>编辑说明
        </p> -->
        <!-- <p class="menuButton" v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.RUN" @click="showDiaFun('shareRun')">
          <el-icon>
            <CopyDocument />
          </el-icon>共享算例
        </p> -->

        <p
          class="menuButton"
          v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.RUN"
          @click="showDiaFun('createReport')"
        >
          <el-icon> <Tickets /> </el-icon>导出报告
        </p>
        <p
          class="menuButton"
          v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.RUN"
          @click="reportInpDiaShow = true"
        >
          <el-icon> <Edit /> </el-icon>编辑报告
        </p>
        <p class="menuButton" @click="showDiaFun('showPerformance')">
          <el-icon> <DataLine /> </el-icon>查看指标
        </p>
        <p class="menuButton" @click="showDiaFun('runVersion')">
          <el-icon> <Share /> </el-icon>算例版本
        </p>
        <!-- <p
          class="menuButton"
          v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.RUN"
          @click="showDiaFun('archiveOriginalExamples')"
        >
          <el-icon> <FolderChecked /> </el-icon>归档原始算例
        </p>
        <p
          class="menuButton"
          v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.RUN"
          @click="showDiaFun('archiveOptimizationExamples')"
        >
          <el-icon> <FolderRemove /> </el-icon>归档优化算例
        </p> -->
        <p
          class="menuButton"
          v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.RUN"
          @click="showDiaFun('delRun')"
        >
          <el-icon> <Delete /> </el-icon>删除算例
        </p>
      </div>
    </Teleport>
    <ReportInputDialog v-model="reportInpDiaShow" :data="rightClickNode" />
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue';
import filterProject from '../filterProject/index.vue';
import { NODE_TYPE } from '@/utils/enum/node';
import { Folder, Document, ScaleToOriginal, Edit } from '@element-plus/icons-vue';
import createRunDiv from './operateComponent/createRunDiv.vue';
import {
  addTaskRunApi,
  createRunDirApi,
  deleteTaskRunApi,
  getTaskRunTreeApi,
  queryTaskRunApi,
} from '@/api/project/run';
import runVersionTreeDiv from './operateComponent/runVersionTreeDiv.vue';
import taskRunPerformance from './operateComponent/taskRunPerformance.vue';
import ReportInputDialog from '@/components/common/report/reportInputDialog.vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { attentionTaskApi } from '@/api/project/task';
import { disposeAttentionParams } from '@/views/task/simulationTask/taskPage';
import { RUN_STATUS } from '@/utils/enum/run';
import createReportNew from './operateComponent/createReportNew.vue';

const emits = defineEmits(['nodeClickFn']);
const tableId = ref(new Date().getTime());
const showFileMenu = ref(false);
const showRunCreateOrEditWindow = ref(false);
const showRunVersionTreeWindow = ref(false);
const showTaskRunPerformanceWindow = ref(false);
const showCreateRunReporteWindow = ref(false);
const taskTreeRef = ref();
const defaultExpandKeys = ref<any>([]);
const reportInpDiaShow = ref(false);

const changeExpendTypeFun = (data: any) => {
  defaultExpandKeys.value = [];
  setExpandElementFun(dataSource.value, data);
  for (const key in taskTreeRef.value.store.nodesMap) {
    if (defaultExpandKeys.value.includes(key)) {
      taskTreeRef.value.store.nodesMap[key].expanded = true;
    } else {
      taskTreeRef.value.store.nodesMap[key].expanded = false;
    }
  }
};

const setExpandElementFun = (list: any, flag: any = 'all') => {
  for (let i = 0; i < list.length; i++) {
    if (flag === 'all') {
      defaultExpandKeys.value.push(list[i].id);
    }

    if (flag === 'node') {
      if (list[i].nodeType === 'workspace') {
        defaultExpandKeys.value.push(list[i].id);
      }
    }

    if (flag === 'task') {
      if (list[i].nodeType === NODE_TYPE.TASK) {
        defaultExpandKeys.value.push(list[i].id);
      }
    }

    if (flag === 'run') {
      if (list[i].nodeType === NODE_TYPE.RUN) {
        defaultExpandKeys.value.push(list[i].id);
      }
    }

    if (list[i]?.children?.length) {
      setExpandElementFun(list[i]?.children, flag);
    }
  }
};
const filterParam = ref<any>({});

// 过滤数内容
const filterParamChangeFun = async (data: any) => {
  // currentNodeInfo.value = {};
  localStorage.setItem('CURRENT_TASK_RUN_INFO', '');
  filterParam.value = data;
  dataSource.value = await getTaskRunTreeDataFun(data);

  if (dataSource.value.length) {
    if (
      currentNodeInfo.value?.projectUuid === filterParam.value.projectName &&
      currentNodeInfo.value?.phaseUuid === filterParam.value.phaseName
    ) {
      emits('nodeClickFn', { node: currentNodeInfo.value });
    } else {
      emits('nodeClickFn', { node: {} });
    }
  } else {
    emits('nodeClickFn', { node: {} });
  }
};

const dataSource = ref<any[]>([]);
const getTaskRunTreeDataFun = async (data: any) => {
  let result: any = [];

  if (data.projectName && data.phaseName) {
    const res: any = await getTaskRunTreeApi({
      projectNodeId: data.projectName,
      phaseNodeId: data.phaseName,
      idMap: [
        {
          key: data.projectName,
          value: 'tag1',
        },
        {
          key: data.phaseName,
          value: 'tag2',
        },
        {
          key: null,
          value: 'tag3',
        },
        {
          key: null,
          value: 'tag4',
        },
        {
          key: null,
          value: 'tag5',
        },
        {
          key: null,
          value: 'tag6',
        },
        {
          key: null,
          value: 'tag7',
        },
        {
          key: null,
          value: 'tag8',
        },
        {
          key: null,
          value: 'tag9',
        },
        {
          key: null,
          value: 'tag10',
        },
      ],
      tagMap: [
        {
          key: 'project',
          value: 'tag1',
        },
        {
          key: 'phase',
          value: 'tag2',
        },
        {
          key: 'machine',
          value: 'tag4',
        },
        {
          key: 'workspace',
          value: 'tag5',
        },
        {
          key: 'discipline',
          value: 'tag6',
        },
      ],
    });

    if (res && res.code === 200) {
      result = res.data;
    }
  }

  return result;
};

/**
 * 点击选中的节点数据
 */
const currentNodeInfo = ref<any>(null);
const nodeChangeClickFun = (data: any, node: any) => {
  clearTreeMenuFun();
  currentNodeInfo.value = data;
  currentNodeInfo.value.projectUuid = filterParam.value?.projectName;
  currentNodeInfo.value.phaseUuid = filterParam.value?.phaseName;

  if (node.data.nodeType === NODE_TYPE.RUN) {
    currentNodeInfo.value.runTaskId = node.parent.data.id;
    currentNodeInfo.value.parentName = node.parent.data.nodeName;
    currentNodeInfo.value.projectName = filterParam.value?.projectCodeName;
    currentNodeInfo.value.standard = node.parent.data.standard;
    // localStorage.setItem('CURRENT_TASK_RUN_INFO', JSON.stringify(data));
  } else {
    // localStorage.setItem('CURRENT_TASK_RUN_INFO', '');
  }
  localStorage.setItem('CURRENT_TASK_RUN_INFO', JSON.stringify(data));

  defaultExpandKeys.value = [data.id];
  emits('nodeClickFn', { node: currentNodeInfo.value });
};

/**
 * 右键菜单选择的节点信息
 */
const rightClickNodeInfo = ref<any>(null);
const rightClickNode = ref<any>(null);
const rightClickNodeParentInfo = ref<any>(null);

const workspaceNodeInfo = ref<any>({});

// 右键菜单
const rowRightClickFun = (e: any, data: any, node: any) => {
  // clearTreeMenuFun();
  rightClickNodeInfo.value = data;
  rightClickNodeInfo.value.parentName = node.parent.data.nodeName;

  rightClickNode.value = data;
  rightClickNodeParentInfo.value = node.parent.data;
  getSpecifyLevelNodeData(node, NODE_TYPE.WORKSPACE);
  if (
    rightClickNodeInfo.value.nodeType != NODE_TYPE.TASK &&
    rightClickNodeInfo.value.nodeType != NODE_TYPE.RUN
  ) {
    return;
  }
  const event = e;
  const menuElement = document.getElementById('fileMenu' + tableId.value) as HTMLElement;
  const dialogElement: any = document.getElementsByClassName('el-dialog')[0];
  const childElementHeight = (menuElement?.childElementCount ?? 7) * 32;
  let top =
    (event.clientY > window.innerHeight - childElementHeight
      ? window.innerHeight - childElementHeight
      : event.clientY) + 'px';
  let left = event.clientX + 'px';
  // 解决transform对fixed的影响
  if (
    dialogElement?.contains(document.getElementsByClassName('serverFileListMenu')[0]) &&
    dialogElement?.style.transform
  ) {
    let translate = dialogElement.style.transform;
    translate = translate
      .substring(translate.indexOf('(') + 1, translate.lastIndexOf(')'))
      .split(',');
    top = parseInt(top) - parseInt(translate[1]) + 'px';
    left = parseInt(left) - parseInt(translate[0]) + 'px';
    // top = 'calc(' + top + ' - ' + parseInt($('.el-dialog').css('--el-dialog-margin-top')) + 'vw)';
    // left =
    //   'calc(' +
    //   left +
    //   ' - ' +
    //   (100 - parseInt($('.el-dialog').css('--el-dialog-width'))) / 2 +
    //   'vw)';
  }
  menuElement.style.top = top;
  menuElement.style.left = left;
  // menuElement.style.top = event.offsetY + (showLastPath.value ? 80 : 50) + 'px';
  // menuElement.style.left = event.offsetX + 'px';
  // 没有按钮就不显示菜单
  if (childElementHeight) {
    menuElement.style.display = 'block';
  }
  showFileMenu.value = true;
  event.preventDefault();
};

// 获取工况树上指定节点的上层第一个对应类型的节点信息
const getSpecifyLevelNodeData = (node: any, type: any) => {
  if (node.data.nodeType === type) {
    workspaceNodeInfo.value = node.data;
  } else {
    if (node?.parent) {
      getSpecifyLevelNodeData(node?.parent, type);
    }
  }
};

const clearTreeMenuFun = () => {
  // rightClickNodeInfo.value = null;
  const menuElement = document.getElementById('fileMenu' + tableId.value) as HTMLElement;
  if (menuElement) {
    menuElement.style.display = 'none';
  }
};

const windowFlag = ref('');
const showDiaFun = (flag: string) => {
  windowFlag.value = flag;

  switch (windowFlag.value) {
    // 新建算例
    case 'createRun':
      showRunCreateOrEditWindow.value = true;
      break;
    // 状态修改
    case 'updateTask':
      break;
    // 输入参数
    case 'inputParam':
      break;
    // 关注任务
    case 'focukTask':
      attentionTaskFun(rightClickNode.value, true);
      break;
    // 建子算例
    case 'createChildRun':
      showRunCreateOrEditWindow.value = true;

      break;
    // 复制算例
    case 'copyRun':
      showRunCreateOrEditWindow.value = true;

      break;
    // 编辑说明
    case 'editRun':
      showRunCreateOrEditWindow.value = true;

      break;
    // 共享算例
    case 'shareRun':
      break;
    // 查看指标
    case 'showPerformance':
      showTaskRunPerformanceWindow.value = true;
      break;

    // 算例版本
    case 'runVersion':
      showRunVersionTreeWindow.value = true;
      break;

    // 归档原始算例
    case 'archiveOriginalExamples':
      break;

    // 归档优化算例
    case 'archiveOptimizationExamples':
      break;

    // 删除算例
    case 'delRun':
      ElMessageBox.confirm('是否删除这个算例？', 'Warning', {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning',
      })
        .then(() => {
          deleteTaskRunFun();
        })
        .catch(() => {});

      break;
    // 生成报告
    case 'createReport':
      showCreateRunReporteWindow.value = true;
      break;
  }
};

const attentionTaskFun = async (row: any, isAttention: boolean) => {
  const res: any = await attentionTaskApi(disposeAttentionParams(row.uuid, isAttention));
  if (res.code === 200) {
    if (isAttention) {
      ElMessage.success('关注成功');
    } else {
      ElMessage.success('取消关注成功');
    }
  }
};

// 确认创建算例，复制算例，新建子算例
const createRunFun = async (data: any) => {
  const { info, flag }: any = data;
  if (flag != 'editRun') {
    // 调用接口新增算例信息后，插入对应节点下

    const res: any = await addTaskRunApi({
      runName: info.runNames,
      flowTemplate: info.templateName,
      taskId:
        flag === 'createRun' ? rightClickNodeInfo.value?.uuid : rightClickNodeInfo.value?.taskId,
      totalStep: 1,
      parentId: info.parentRunVision,
    });

    if (res && res.code === 200) {
      const runUuid = res.data;
      const runInfo = await getRunDetailInfoFun(runUuid);

      await createRunResultDirFun(runUuid);
      // 创建完算例后创建算例下的文件夹

      // info.label = info.runNames;
      runInfo.nodeType = NODE_TYPE.RUN;
      // info.id = new Date().getTime();
      ElMessage.success('创建成功');
      if (flag != 'createRun') {
        taskTreeRef.value.insertAfter(runInfo, rightClickNode.value);
      } else {
        taskTreeRef.value.append(runInfo, rightClickNode.value);
      }
      currentNodeInfo.value = runInfo;
      defaultExpandKeys.value = [runInfo.id];
      taskTreeRef.value.setCurrentKey(runInfo.id);
    }
  } else {
    info.label = info.runNames;
    info.nodeType = NODE_TYPE.RUN;
    info.id = new Date().getTime();
    taskTreeRef.value.insertAfter(info, rightClickNode.value);
  }

  showRunCreateOrEditWindow.value = false;
};

// 更新算例信息
const updateRunInfoFun = async () => {
  showRunCreateOrEditWindow.value = false;
};

const getRunDetailInfoFun = async (id: any) => {
  const res: any = await queryTaskRunApi({
    runId: id,
  });
  if (res && res.code === 200) {
    const run = res.data[0];
    return run;
  }
};

const dirNames = ref(['图片结果', '曲线结果', '报告结果', '计算模型', '3D模型']);
// 在算例下新建文件夹
const createRunResultDirFun = async (runId: any) => {
  for (let i = 0; i < dirNames.value.length; i++) {
    await createRunDirApi({
      dirName: dirNames.value[i],
      dirType: 2,
      uuId: runId,
    });
  }
};

// 删除算例
const deleteTaskRunFun = async () => {
  const res: any = await deleteTaskRunApi({
    runId: rightClickNode.value.id,
  });

  if (res && res.code === 200) {
    taskTreeRef.value.remove(rightClickNode.value);

    if (rightClickNode.value.id === currentNodeInfo.value.id) {
      currentNodeInfo.value = {};
      emits('nodeClickFn', { node: {} });
    }
  }
};

// 恢复上一次的
const restoreSelectionFun = () => {
  const resetData = localStorage.getItem('CURRENT_TASK_RUN_INFO')
    ? JSON.parse(localStorage.getItem('CURRENT_TASK_RUN_INFO') as string) || ''
    : '';
  if (resetData) {
    currentNodeInfo.value = resetData;
    defaultExpandKeys.value = [resetData.id];
    taskTreeRef.value.setCurrentKey(resetData.id);
  } else {
    currentNodeInfo.value = {};
    defaultExpandKeys.value = [];
  }
};

const setCurrentNodeStatusFun = (status: any) => {
  currentNodeInfo.value.status = status;
};

defineExpose({
  setCurrentNodeStatusFun,
});

const timer = ref<any>();

// 固定时间刷新左侧树的状态
const refreshTreeDataFun = async () => {
  const newTreeData = await getTaskRunTreeDataFun(filterParam.value);

  asyncTreeData(dataSource.value, newTreeData);
  console.log(newTreeData, 'newTreeData');
};

const asyncTreeData = (list: any, data: any) => {
  for (let i = 0; i < list.length; i++) {
    for (const key in list[i]) {
      if (key != 'children') {
        list[i][key] = data[i][key];
      }
    }

    if (list[i]?.children?.length) {
      asyncTreeData(list[i]?.children, data[i]?.children);
    }
  }
};

onMounted(() => {
  document.addEventListener('click', clearTreeMenuFun);

  nextTick(() => {
    restoreSelectionFun();
  });

  // 5分钟获取一次最新树的数据更新组件
  timer.value = setInterval(
    () => {
      refreshTreeDataFun();
    },
    60 * 1000 * 5
  );
});

onBeforeUnmount(() => {
  document.removeEventListener('click', clearTreeMenuFun);
  clearInterval(timer.value);
});
</script>

<style lang="scss" scoped>
.task-tree-content {
  width: 100%;
  height: 100%;

  .filter-content {
    width: 100%;
    margin-bottom: 10px;
  }

  .tree-content {
    width: 100%;

    .custom-tree-node {
      width: calc(100% - 40px);
      display: flex;
      align-items: center;
      justify-content: space-between;

      .title-info {
        height: 100%;
        width: calc(100% - 40px);
        display: flex;
        align-items: center;

        .blue {
          color: var(--el-color-primary);
        }

        .name {
          padding-left: 8px;
        }
      }

      .run-suatus {
        width: 80px;
        display: flex;
        align-items: center;
        justify-content: flex-end;
      }
    }
  }
}

//右键菜单栏显示的样式
.fileMenu {
  // position: absolute;
  position: fixed;
  width: 130px;
  height: auto;
  background-color: #fff;

  box-shadow: 0px 0px 4px #c0bfbf;
  display: none;
  z-index: 999999999;
  padding-left: 0px;
  background-clip: padding-box;
  border: 1px solid #ccc;
  border-radius: 5px !important;
  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
  overflow: hidden;

  p {
    list-style: none;
    width: 100%;
    text-align: center;
    cursor: pointer;
    // border-radius: 5px;
    font-size: 12px;
    display: flex;
    align-items: center;
    justify-content: flex-start;
    padding: 6.5px 10px !important;

    i,
    img {
      margin-right: 10px;
    }

    .el-icon {
      font-size: 15px;
    }
  }

  p:hover {
    background-color: #f5f5f5;
  }

  .disable {
    cursor: not-allowed;
    color: #a8abb2;
  }
}

.settingMenu {
  position: fixed;
  top: 10px;
  left: 20px;
  width: 120px;
  max-height: 300px;
  overflow-y: auto;
  overflow-x: hidden;
  background-color: #fff;
  border-radius: 5px;
  box-shadow: 0px 0px 4px #c0bfbf;
  z-index: 99;
  padding: 5px;

  .check-line {
    width: 100%;
    height: 1px;
    background-color: #bfbfbf;
  }
}

.ellipsis {
  white-space: nowrap;
  /* 防止文本换行 */
  overflow: hidden;
  /* 隐藏溢出的内容 */
  text-overflow: ellipsis;
  /* 显示省略号来代表被修剪的文本 */
}

.info {
  color: grey;
}

.success {
  color: #67c23a;
}

.warn {
  color: #f56c6c;
}

.upload {
  color: #409eff;
}
</style>
