2026-08-10 536c6fbd1f42ea335abdce561451a6ee87d71465
src/views/hrm/employee/index.vue
@@ -5,7 +5,9 @@
import { Page, useVbenModal } from '#/packages/effects/common-ui/src';
import { downloadFileFromBlobPart } from '#/packages/utils/src';
import { Button, message, Tag } from 'ant-design-vue';
import { Button, message, Progress, Tag } from 'ant-design-vue';
import { ref } from 'vue';
import { DICT_TYPE } from '#/packages/constants/src';
import { getDictLabel } from '#/packages/effects/hooks/src';
@@ -16,9 +18,15 @@
import { useGridColumns, useGridFormSchema } from './data';
import Form from './modules/form.vue';
import ImportForm from './modules/import-form.vue';
const [FormModal, formModalApi] = useVbenModal({
  connectedComponent: Form,
  destroyOnClose: true,
});
const [ImportModal, importModalApi] = useVbenModal({
  connectedComponent: ImportForm,
  destroyOnClose: true,
});
@@ -57,10 +65,55 @@
  }
}
const exporting = ref(false);
const exportPercent = ref(0);
let exportTimer: ReturnType<typeof setInterval> | undefined;
/** 模拟进度条:请求期间从 0 走到 90% */
function startExportProgress() {
  exportPercent.value = 0;
  exportTimer = setInterval(() => {
    if (exportPercent.value < 90) {
      exportPercent.value = Math.min(
        90,
        exportPercent.value + Math.random() * 12,
      );
    }
  }, 300);
}
function stopExportProgress() {
  if (exportTimer) {
    clearInterval(exportTimer);
    exportTimer = undefined;
  }
}
function delay(ms: number) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}
/** 导出员工 */
async function handleExport() {
  const data = await exportEmployee(await gridApi.formApi.getValues());
  downloadFileFromBlobPart({ fileName: '员工列表.xls', source: data });
  if (exporting.value) return;
  exporting.value = true;
  startExportProgress();
  try {
    const data = await exportEmployee(await gridApi.formApi.getValues());
    // 完成:进度条走满后触发下载
    stopExportProgress();
    exportPercent.value = 100;
    await delay(500);
    downloadFileFromBlobPart({ fileName: '员工列表.xls', source: data });
  } finally {
    stopExportProgress();
    exporting.value = false;
  }
}
/** 导入员工 */
function handleImport() {
  importModalApi.open();
}
const [Grid, gridApi] = useVbenVxeGrid({
@@ -95,6 +148,7 @@
<template>
  <Page auto-content-height>
    <ImportModal @success="handleRefresh" />
    <FormModal @success="handleRefresh" />
    <Grid table-title="员工列表">
      <template #toolbar-tools>
@@ -106,6 +160,13 @@
              icon: ACTION_ICON.ADD,
              auth: ['hrm:employee:create'],
              onClick: handleCreate,
            },
            {
              label: '导入',
              type: 'primary',
              icon: ACTION_ICON.UPLOAD,
              auth: ['hrm:employee:import'],
              onClick: handleImport,
            },
            {
              label: $t('ui.actionTitle.export'),
@@ -156,4 +217,16 @@
      </template>
    </Grid>
  </Page>
  <!-- 导出进度条遮罩 -->
  <div
    v-if="exporting"
    class="fixed inset-0 z-[9999] flex items-center justify-center bg-black/40"
  >
    <div class="w-80 rounded-lg bg-white p-6 shadow-lg">
      <div class="mb-3 text-center text-sm text-gray-600">
        正在导出员工列表...
      </div>
      <Progress :percent="exportPercent" status="active" />
    </div>
  </div>
</template>