zhou zhou
6 小时以前 7c2bffa1a495cc4a3a263f654c08c231009c5c4e
rsf-design/src/components/core/forms/art-excel-export/index.vue
@@ -1,4 +1,3 @@
<!-- 导出 Excel 文件 -->
<template>
  <ElButton
    :type="type"
@@ -12,19 +11,22 @@
      <ElIcon class="is-loading">
        <Loading />
      </ElIcon>
      {{ loadingText }}
      {{ resolvedLoadingText }}
    </template>
    <slot>{{ buttonText }}</slot>
    <slot>{{ resolvedButtonText }}</slot>
  </ElButton>
</template>
<script setup>
  import * as XLSX from 'xlsx'
  import FileSaver from 'file-saver'
  import { ref, computed, nextTick } from 'vue'
  import { ElMessage } from 'element-plus'
  import { ref, computed, nextTick, readonly } from 'vue'
  import { Loading } from '@element-plus/icons-vue'
  import { useThrottleFn } from '@vueuse/core'
  import { useI18n } from 'vue-i18n'
  defineOptions({ name: 'ArtExcelExport' })
  const { t } = useI18n()
  const props = defineProps({
    filename: {
      required: false,
@@ -34,10 +36,10 @@
    type: { required: false, default: 'primary' },
    size: { required: false, default: 'default' },
    disabled: { required: false, default: false },
    buttonText: { required: false, default: '导出 Excel' },
    loadingText: { required: false, default: '导出中...' },
    buttonText: { required: false, default: '' },
    loadingText: { required: false, default: '' },
    autoIndex: { required: false, default: false },
    indexColumnTitle: { required: false, default: '序号' },
    indexColumnTitle: { required: false, default: '' },
    columns: { required: false, default: () => ({}) },
    headers: { required: false, default: () => ({}) },
    maxRows: { required: false, default: 1e5 },
@@ -56,15 +58,18 @@
  }
  const isExporting = ref(false)
  const hasData = computed(() => Array.isArray(props.data) && props.data.length > 0)
  const resolvedButtonText = computed(() => props.buttonText || t('common.actions.export'))
  const resolvedLoadingText = computed(() => props.loadingText || t('common.actions.exporting'))
  const resolvedIndexColumnTitle = computed(() => props.indexColumnTitle || t('table.index'))
  const validateData = (data) => {
    if (!Array.isArray(data)) {
      throw new ExportError('数据必须是数组格式', 'INVALID_DATA_TYPE')
      throw new ExportError(t('message.exportInvalidDataType'), 'INVALID_DATA_TYPE')
    }
    if (data.length === 0) {
      throw new ExportError('没有可导出的数据', 'NO_DATA')
      throw new ExportError(t('message.exportNoData'), 'NO_DATA')
    }
    if (data.length > props.maxRows) {
      throw new ExportError(`数据行数超过限制(${props.maxRows}行)`, 'EXCEED_MAX_ROWS', {
      throw new ExportError(t('message.exportExceedMaxRows', { maxRows: props.maxRows }), 'EXCEED_MAX_ROWS', {
        currentRows: data.length,
        maxRows: props.maxRows
      })
@@ -82,7 +87,7 @@
      return value.toLocaleDateString('zh-CN')
    }
    if (typeof value === 'boolean') {
      return value ? '是' : '否'
      return value ? t('common.status.yes') : t('common.status.no')
    }
    return String(value)
  }
@@ -90,7 +95,7 @@
    const processedData = data.map((item, index) => {
      const processedItem = {}
      if (props.autoIndex) {
        processedItem[props.indexColumnTitle] = String(index + 1)
        processedItem[resolvedIndexColumnTitle.value] = String(index + 1)
      }
      Object.entries(item).forEach(([key, value]) => {
        let columnTitle = key
@@ -131,13 +136,13 @@
      if (props.workbookOptions) {
        workbook.Props = {
          Title: filename,
          Subject: '数据导出',
          Subject: t('message.exportWorkbookSubject'),
          Author: props.workbookOptions.creator || 'Art Design Pro',
          Manager: props.workbookOptions.lastModifiedBy || '',
          Company: '系统导出',
          Category: '数据',
          Keywords: 'excel,export,data',
          Comments: '由系统自动生成',
          Company: t('message.exportWorkbookCompany'),
          Category: t('message.exportWorkbookCategory'),
          Keywords: t('message.exportWorkbookKeywords'),
          Comments: t('message.exportWorkbookComments'),
          CreatedDate: props.workbookOptions.created || /* @__PURE__ */ new Date(),
          ModifiedDate: props.workbookOptions.modified || /* @__PURE__ */ new Date()
        }
@@ -164,7 +169,11 @@
      await nextTick()
      return Promise.resolve()
    } catch (error) {
      throw new ExportError(`Excel 导出失败: ${error.message}`, 'EXPORT_FAILED', error)
      throw new ExportError(
        t('message.exportExcelFailed', { message: error.message }),
        'EXPORT_FAILED',
        error
      )
    }
  }
  const handleExport = useThrottleFn(async () => {
@@ -177,7 +186,7 @@
      emit('export-success', props.filename, props.data.length)
      if (props.showSuccessMessage) {
        ElMessage.success({
          message: `成功导出 ${props.data.length} 条数据`,
          message: t('message.exportSuccessWithCount', { count: props.data.length }),
          duration: 3e3
        })
      }
@@ -185,7 +194,11 @@
      const exportError =
        error instanceof ExportError
          ? error
          : new ExportError(`导出失败: ${error.message}`, 'UNKNOWN_ERROR', error)
          : new ExportError(
              t('message.exportFailedUnknown', { message: error.message }),
              'UNKNOWN_ERROR',
              error
            )
      emit('export-error', exportError)
      if (props.showErrorMessage) {
        ElMessage.error({