Merge pull request '代码生成的List支持导入导出' (#384) from HJ202507025 into v2

Reviewed-on: https://code.adminnet.top/Admin.NET/Admin.NET.Pro/pulls/384
This commit is contained in:
zuohuaijun 2025-07-25 17:06:41 +08:00
commit 78a7b3fcb0
4 changed files with 155 additions and 5 deletions

View File

@ -36,7 +36,7 @@ public partial class @(@Model.ClassName)Mid
/// <param name="_@(@Model.LowerClassName)Rep"></param>
/// <param name="input"></param>
/// <returns></returns>
public static ISugarQueryable<@(@Model.ClassName)Output> GetQuery(SqlSugarRepository<@(@Model.ClassName)> _@(@Model.LowerClassName)Rep,Page@(@Model.ClassName)Input input)
public static ISugarQueryable<@(@Model.ClassName)> GetQuery(SqlSugarRepository<@(@Model.ClassName)> _@(@Model.LowerClassName)Rep,Page@(@Model.ClassName)Input input)
{
var sysCacheService = App.GetRequiredService<SysCacheService>();
var db = App.GetRequiredService<ISqlSugarClient>();
@ -80,7 +80,6 @@ public partial class @(@Model.ClassName)Mid
@:.OrderBy(u => u.OrderNo)
}
.Select<@(@Model.ClassName)Output>()
@if(!string.IsNullOrEmpty(Model.TreeName)){
@:.Mapper(c => c.Name= c.@(@Model.TreeName).ToString())
}

View File

@ -10,7 +10,7 @@ namespace @Model.NameSpace;
/// HJ:这里做优化 如果是富文本不传入
/// @(@Model.BusName)输出参数
/// </summary>
public partial class @(@Model.ClassName)Output
public partial class Page@(@Model.ClassName)Output
{
@foreach (var column in Model.TableField){
@ -74,5 +74,27 @@ if (@column.EffectType == "ApiTreeSelector"){
}
/// <summary>
/// HJ:这里用的标准的Dto,如果有特殊需要可以在Dto中添加
/// @(@Model.BusName)导入导出输出参数
/// </summary>
public partial class @(@Model.ClassName)Dto
{
@foreach (var column in Model.TableField){
@:/// <summary>
@:/// @column.ColumnComment
@:/// </summary>
@:[ImporterHeader(Name = "@(column.ColumnComment)")]
@:[ExporterHeader(DisplayName = "@(column.ColumnComment)", IsBold = true)]
@:public @column.NetType @column.PropertyName { get; set; }
@:
}
}

View File

@ -84,9 +84,9 @@ public partial class @(@Model.ClassName)Service : IDynamicApiController, ITransi
/// <returns></returns>
[ApiDescriptionSettings(Name = "Page", Description = "分页查询", Order = 1000), HttpPost]
[DisplayName("分页查询@(@Model.BusName)")]
public async Task<SqlSugarPagedList<@(@Model.ClassName)Output>> Page(Page@(@Model.ClassName)Input input)
public async Task<SqlSugarPagedList<Page@(@Model.ClassName)Output>> Page(Page@(@Model.ClassName)Input input)
{
var list = await @(@Model.ClassName)Mid.GetQuery(_@(@Model.LowerClassName)Rep, input).OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize);
var list = await @(@Model.ClassName)Mid.GetQuery(_@(@Model.LowerClassName)Rep, input).Select<Page@(@Model.ClassName)Output>().OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize);
return list;
}
@ -175,6 +175,57 @@ if (@column.ColumnKey == "True"){
}
}
}
/// <summary>
/// 导入@(@Model.BusName)
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
[DisplayName("导入@(@Model.BusName)")]
public async Task Import([Required] IFormFile file)
{
using MemoryStream stream = new();
await file.CopyToAsync(stream);
var res = await new ExcelImporter().Import<@(@Model.ClassName)Dto>(stream);
if (res == null || res.Exception != null)
throw Oops.Oh(res.Exception);
var importData = res.Data.ToList();
// 按照编码条件进行批量更新或者新增
await _@(@Model.LowerClassName)Rep.Context.Storageable(importData.Adapt<List<@(@Model.ClassName)>>()).WhereColumns(u => u.Id).ExecuteCommandAsync();
}
/// <summary>
/// 导出@(@Model.BusName)
/// </summary>
/// <returns></returns>
[DisplayName("导出@(@Model.BusName)")]
public async Task<IActionResult> Export(PageMonkeyArticleInput input)
{
var list = await @(@Model.ClassName)Mid.GetQuery(_monkeyArticleRep, input).Select<@(@Model.ClassName)Dto>().OrderBuilder(input).ToListAsync();
if (list == null || list.Count < 1)
throw Oops.Oh("数据为空,导出已取消");
var res = await new ExcelExporter().ExportAsByteArray(list);
return new FileStreamResult(new MemoryStream(res), "application/octet-stream") { FileDownloadName = DateTime.Now.ToString("yyyyMMddHHmm") + "@(@Model.BusName)列表.xlsx" };
}
/// <summary>
/// 下载导入@(@Model.BusName)模板
/// </summary>
/// <returns></returns>
[DisplayName("下载导入@(@Model.BusName)模板")]
public async Task<IActionResult> DownloadTemplate()
{
var res = await new ExcelImporter().GenerateTemplateBytes<@(@Model.ClassName)Dto>();
return new FileStreamResult(new MemoryStream(res), "application/octet-stream") { FileDownloadName = "@(@Model.BusName)导入模板.xlsx" };
}
/*HJ:不要,有分页了,列表多余的
/// <summary>
/// 获取@(@Model.BusName)列表

View File

@ -116,6 +116,12 @@
<vxe-grid ref="xGrid" class="xGrid-style" v-bind="options" v-on="gridEvents">
<template #toolbar_buttons>
<el-button type="primary" icon="ele-Plus" @@click="handleAdd" v-auth="'@(@Model.LowerClassName)/add'"> {{ $t('message.codegen.add') }} </el-button>
<el-button-group type="primary" style="padding-left: 12px">
<el-button plain icon="ele-Upload" @@click="importData" v-auth="'@(@Model.LowerClassName)/import'"> {{ $t('message.list.import') }} </el-button>
<el-button plain icon="ele-Download" @@click="exportData" v-auth="'@(@Model.LowerClassName)/export'"> {{ $t('message.list.export') }} </el-button>
<el-button plain icon="ele-FolderOpened" @@click="downloadTemplate"> {{ $t('message.list.downloadTemplate') }} </el-button>
</el-button-group>
</template>
<template #toolbar_tools> </template>
<template #empty>
@ -195,6 +201,33 @@
@if(@Model.PrintType != "off"){
@:<PrintDialog ref="printDialogRef" :title="state.title" @@reloadTable="handleQuery" />
}
<el-dialog v-model="state.uploadVisible" :lock-scroll="false" draggable width="400px">
<template #header>
<div style="color: #fff">
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-UploadFilled /> </el-icon>
<span> {{ $t('message.list.import') }} </span>
</div>
</template>
<div>
<el-upload ref="uploadRef" drag :auto-upload="false" :limit="1" :file-list="state.fileList" action="" :on-change="handleChange" accept=".xlsx">
<el-icon class="el-icon--upload">
<ele-UploadFilled />
</el-icon>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<template #tip>
<div class="el-upload__tip">请上传大小不超过 10MB 的文件</div>
</template>
</el-upload>
</div>
<template #footer>
<span class="dialog-footer">
<el-button icon="ele-CircleCloseFilled" @@click="state.uploadVisible = false">{{ $t('message.list.cancelButtonText') }}</el-button>
<el-button type="primary" icon="ele-CircleCheckFilled" @@click="uploadFile">{{ $t('message.list.confirmButtonText') }}</el-button>
</span>
</template>
</el-dialog>
<EditDialog ref="editDialogRef" :title="state.title" @@reloadTable="handleQuery" />
</template>
@ -209,6 +242,7 @@ import { auth } from '/@@/utils/authFunction';
import EditDialog from '/@@/views/@(@Model.PagePath)/@(@Model.LowerClassName)/component/edit.vue';
import ModifyRecord from '/@@/components/table/modifyRecord.vue';
import { useI18n } from 'vue-i18n';
import { downloadByData, getFileName } from '/@@/utils/download';
@if(@Model.TableField.Any(x=>x.EffectType == "DatePicker")){
@:// 日历控件
@ -283,6 +317,9 @@ const state = reactive({
totalSum:[] as any,
visible: false,
title: '',
uploadVisible: false,
fileList: [] as any,
});
// 本地存储参数
@ -558,6 +595,47 @@ const handleDelete = (row: any) => {
}
}
// 通过onChanne方法获得文件列表
const handleChange = (file: any, fileList: []) => {
state.fileList = fileList;
};
// 上传
const uploadFile = async () => {
if (state.fileList.length < 1) return;
state.uploadVisible = false;
options.loading = true;
await getAPI(@(@Model.ClassName)Api).api@(@Model.ClassName)ImportPostForm(state.fileList[0].raw);
handleQuery();
ElMessage.success('上传成功');
state.fileList = [];
options.loading = false;
};
// 导入
const importData = () => {
state.uploadVisible = true;
};
// 导出
const exportData = async () => {
options.loading = true;
var res = await getAPI(@(@Model.ClassName)Api).api@(@Model.ClassName)ExportPost(state.queryParams, { responseType: 'blob' });
options.loading = false;
var fileName = getFileName(res.headers);
downloadByData(res.data as any, fileName);
};
// 下载模板
const downloadTemplate = async () => {
var res = await getAPI(@(@Model.ClassName)Api).api@(@Model.ClassName)DownloadTemplatePost({ responseType: 'blob' });
var fileName = getFileName(res.headers);
downloadByData(res.data as any, fileName);
};
// 与父组件的交互逻辑
const emits = defineEmits(['list-click']);
const listClick = (row: any,column:any) => {