Files
easygoadmin-wiki/EasyGoAdmin_GoFrame_AntdVue/zh/tools/excel.md
T
2026-10-20 21:53:26 +08:00

107 lines
4.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 7.4 数据导入导出
:::tip 概述
Excel 导入导出基于 xuri/excelize/v2(utility/excel 封装):导入解析逐行校验写入并返回统计,导出走 ChunkQuery 分批查询防 OOM。启用模块:user / level / example。
:::
## utility/excel API
```text
ReadSheet(file FileOpener):首行表头,全单元格转字符串(TrimSpace),空行跳过;
FileOpener 接口兼容 *ghttp.UploadFile 与 *multipart.FileHeader
WriteSheet(dir, baseName, headers, rows [][]any):写文件返回 (fileName, filePath)
```
## 导入流程(Import,真实模式摘自 example)
```go
// Import 导入案例演示
// 表头为表单字段名,按列序写入
func (s *sExample) Import(ctx context.Context, req *v1.ExampleImportReq) (res *v1.ExampleImportRes, err error) {
_, rows, err := excel.ReadSheet(req.File)
if err != nil {
return nil, err
}
res = &v1.ExampleImportRes{Total: len(rows)}
for i, row := range rows {
if cellAt(row, 0) == "" {
res.Failed++
res.Reasons = append(res.Reasons, fmt.Sprintf("第%d行:案例名称为空", i+2))
continue
}
if _, e := dao.Example.Ctx(ctx).Data(map[string]any{
"name": cellAt(row, 0),
"avatar": cellAt(row, 1),
"type": cellInt(row, 2, 0),
"status": cellInt(row, 3, 0),
"sort": cellInt(row, 4, 0),
}).Insert(); e != nil {
res.Failed++
res.Reasons = append(res.Reasons, fmt.Sprintf("第%d行:写入失败 %v", i+2, e))
continue
}
res.Success++
}
return res, nil
}
```
要点:逐行独立成败(一行失败不影响后续);返回 Total/Success/Failed/Reasons(逐行原因);user 导入还含唯一校验/租户上限/默认密码 bcrypt 预计算/角色与城市解析(ResolveCityCodes)。
## 导出流程(Export,真实模式摘自 example)
```go
// Export 导出案例演示
// 与列表同套筛选条件,枚举列输出字典文本
func (s *sExample) Export(ctx context.Context, req *v1.ExampleExportReq) (res *v1.ExampleExportRes, err error) {
rows, err := exampleSpec.applyFilters(ctx, exampleSpec.Model(ctx), req).Order("sort, id").All()
if err != nil {
return nil, err
}
headers := []string{"案例名称", "案例图片", "案例类型", "案例状态", "案例排序"}
data := make([][]any, 0, len(rows))
for _, r := range rows {
data = append(data, []any{r["name"].String(), r["avatar"].String(), DictGetText(ctx, "example_type", r["type"]), DictGetText(ctx, "example_status", r["status"]), r["sort"].String()})
}
fileName, _, err := excel.WriteSheet(upload.BaseDir(ctx), "案例演示数据", headers, data)
if err != nil {
return nil, err
}
url := upload.GetFileUrl(ctx, fileName)
return &url, nil
}
```
要点:**导出统一走 `xxxSpec.applyFilters` 与列表同套筛选(导出=所见)**;枚举列 DictGetText 转文本;大结果集用 ChunkQuery 分批(user 导出 500/页)。
## 导入导出规范
| 项 | 规范 |
|----|------|
| 接口 | Import POST multipart(`p:"file"`);Export GET + 筛选参数 |
| 杅限 | sys:{module}:import / export |
| 日志 | logType import / export("模块名-导入数据/导出数据") |
| 模板 | 表头=表单字段名(导出文件即导入模板) |
| 文件位置 | 导出写临时文件返回 URL(/upload/temp/...,受 temp 清理回收) |
| 防 OOM | 大结果集 ChunkQuery 分批(默认 500/页) |
## 前端组件
```text
Excel 组件(components/Excel + importFile):
导入:选文件 → POST /api/{module}/import → 展示统计与失败原因
导出:调 /api/{module}/export → 拿 URL → downloadFile 下载
详见 9.11 Excel 导入导出组件
```
## 开发新模块的导入导出
```text
1. 请求结构:ExampleImportReq(gmeta + File 字段)/ ExampleExportReq(gmeta + 筛选字段)
2. 接口声明:service 接口加 Import/Export 方法
3. logic 实现:按上方真实模式(ReadSheet 逐行 / applyFilters + WriteSheet)
4. 权限节点:import/export(生成器 HasImport/HasExport 默认 true 自动建)
5. 前端:导入按钮 + 导出按钮(模板参照 example 页面)
```