Files
FastapiAdmin/frontend/web/src/components/forms/fa-excel-import/index.vue
T
zhangtao d34d4a4c50 chore: 完成多批次代码优化与重构
- 重构工作流模块目录结构,迁移代码文件
- 修复类型断言空值安全问题,添加 ! 操作符
- 优化样式类名,替换 flex-cc 为标准 flex 工具类
- 更新路由标签简化文案,移除冗余注释
- 调整 ruff 配置,放宽行长度限制
- 更新 README 与多语言文案,优化项目描述
- 修复表单、图表组件的类型与样式问题
- 简化搜索表单、数据卡片的布局代码
2026-06-20 05:31:46 +08:00

236 lines
5.6 KiB
Vue

<!-- 导入 Excel 文件 -->
<template>
<div class="inline-block">
<ElUpload
:auto-upload="false"
:accept="accept"
:show-file-list="false"
:disabled="disabled"
@change="handleFileChange"
>
<ElButton type="primary" v-ripple :loading="loading">
<slot>{{ buttonText }}</slot>
</ElButton>
</ElUpload>
</div>
</template>
<script setup lang="ts">
import * as XLSX from "xlsx";
import type { UploadFile } from "element-plus";
defineOptions({ name: "FaExcelImport" });
interface Props {
/** 接受的文件类型 */
accept?: string;
/** 按钮文本 */
buttonText?: string;
/** 加载状态 */
loading?: boolean;
/** 是否禁用 */
disabled?: boolean;
}
withDefaults(defineProps<Props>(), {
accept: ".xlsx, .xls",
buttonText: "导入 Excel",
loading: false,
disabled: false,
});
// Excel 导入工具函数
async function importExcel(file: File): Promise<Array<Record<string, unknown>>> {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (e) => {
try {
const data = e.target?.result;
const workbook = XLSX.read(data, { type: "array" });
const firstSheetName = workbook.SheetNames[0]!;
const worksheet = workbook.Sheets[firstSheetName]!;
const results = XLSX.utils.sheet_to_json(worksheet);
resolve(results as Array<Record<string, unknown>>);
} catch (error) {
reject(error);
}
};
reader.onerror = (error) => reject(error);
reader.readAsArrayBuffer(file);
});
}
// 定义 emits
interface Emits {
"import-success": [data: Array<Record<string, unknown>>];
"import-error": [error: Error];
}
const emit = defineEmits<Emits>();
// 处理文件导入
const handleFileChange = async (uploadFile: UploadFile) => {
try {
if (!uploadFile.raw) return;
const results = await importExcel(uploadFile.raw);
emit("import-success", results);
} catch (error) {
emit("import-error", error as Error);
}
};
</script>
<!-- <template>
<div class="page-content">
<FaExcelImport @import-success="handleImportSuccess" @import-error="handleImportError">
<template #import-text>上传 Excel</template>
</FaExcelImport>
<FaExcelExport
:style="'margin-left: 10px'"
:data="tableData"
filename="用户数据-1"
sheetName="用户列表"
type="success"
:headers="headers"
auto-index
:columns="columnConfig"
@export-success="handleExportSuccess"
@export-error="handleExportError"
@export-progress="handleProgress"
>
导出 Excel
</FaExcelExport>
<ElButton type="danger" @click="handleClear" v-ripple>清除数据</ElButton>
<FaTable :data="tableData" :style="'margin-top: 10px'">
<ElTableColumn type="index" label="序号" width="60" />
<ElTableColumn
v-for="key in Object.keys(headers)"
:key="key"
:prop="key"
:label="headers[key as keyof typeof headers]"
/>
</FaTable>
</div>
</template>
<script setup lang="ts">
defineOptions({ name: "FaExcelImportDemo" });
/**
* 表格数据类型定义
*/
interface TableData {
name: string;
age: number;
city: string;
}
/**
* 表格数据
*/
const tableData = ref<TableData[]>([
{ name: "李四", age: 20, city: "上海" },
{ name: "张三", age: 25, city: "北京" },
{ name: "王五", age: 30, city: "广州" },
{ name: "赵六", age: 35, city: "深圳" },
{ name: "孙七", age: 28, city: "杭州" },
{ name: "周八", age: 32, city: "成都" },
{ name: "吴九", age: 27, city: "武汉" },
{ name: "郑十", age: 40, city: "南京" },
{ name: "刘一", age: 22, city: "重庆" },
{ name: "陈二", age: 33, city: "西安" },
]);
/**
* 表头映射配置
* 用于 Excel 导入导出时的字段映射
*/
const headers = {
name: "姓名",
age: "年龄",
city: "城市",
};
/**
* 列配置
* 用于 Excel 导出时的列宽和格式化
*/
const columnConfig = {
name: {
title: "姓名",
width: 20,
formatter: (value: unknown) => (value ? String(value) : "未知"),
},
age: {
title: "年龄",
width: 10,
formatter: (value: unknown) => (value ? `${value}岁` : "0岁"),
},
city: {
title: "城市",
width: 12,
formatter: (value: unknown) => (value ? `${value}市` : "未知"),
},
};
/**
* 处理 Excel 导入成功
* 将导入的数据转换为表格数据格式
* @param data 导入的原始数据
*/
const handleImportSuccess = (data: Array<Record<string, unknown>>) => {
const formattedData: TableData[] = data.map((item) => ({
name: String(item["姓名"] || ""),
age: Number(item["年龄"]) || 0,
city: String(item["城市"] || ""),
}));
tableData.value = formattedData;
ElMessage.success(`成功导入 ${formattedData.length} 条数据`);
};
/**
* 处理 Excel 导入错误
* @param error 错误对象
*/
const handleImportError = (error: Error) => {
console.error("导入失败:", error);
ElMessage.error(`导入失败: ${error.message}`);
};
/**
* 处理 Excel 导出成功
*/
const handleExportSuccess = () => {
ElMessage.success("Excel 导出成功");
};
/**
* 处理 Excel 导出错误
* @param error 错误对象
*/
const handleExportError = (error: Error) => {
ElMessage.error(`导出失败: ${error.message}`);
};
/**
* 处理导出进度
* @param progress 导出进度百分比
*/
const handleProgress = (progress: number) => {
// 进度由进度条 UI 实时显示
};
/**
* 清空表格数据
*/
const handleClear = () => {
tableData.value = [];
ElMessage.info("已清空数据");
};
</script> -->