Просмотр исходного кода

feat: 新增导出选择数据、导出本页、导出全部功能

喵你个旺呀 1 год назад
Родитель
Сommit
ee8bcead92

+ 1 - 4
Admin.NET/Admin.NET.Core/Utils/XlsxFileResult.cs

@@ -91,10 +91,7 @@ public class XlsxFileResultBase : ActionResult
 
         downloadFileName ??= Guid.NewGuid().ToString("N") + ".xlsx";
 
-        if (string.IsNullOrEmpty(Path.GetExtension(downloadFileName)))
-        {
-            downloadFileName += ".xlsx";
-        }
+        if (string.IsNullOrEmpty(Path.GetExtension(downloadFileName))) downloadFileName += ".xlsx";
 
         context.HttpContext.Response.Headers.Append("Content-Disposition", new[] { "attachment; filename=" + HttpUtility.UrlEncode(downloadFileName) });
         await stream.CopyToAsync(context.HttpContext.Response.Body);

+ 7 - 0
Admin.NET/Admin.NET.Web.Entry/wwwroot/template/Input.cs.vm

@@ -51,6 +51,13 @@ public class Page@(Model.ClassName)Input : BasePageInput
     }
     @:
 }
+@if (Model.ImportFieldList.Count > 0){
+    var primaryKey = Model.PrimaryKeyFieldList.First();
+    @:/// <summary>
+    @:/// 选中主键列表
+    @:/// </summary>
+    @: public List<@(primaryKey.NetType)> SelectKeyList { get; set; }
+}
 }
 
 /// <summary>

+ 3 - 2
Admin.NET/Admin.NET.Web.Entry/wwwroot/template/Service.cs.vm

@@ -247,6 +247,7 @@ public class @(Model.ClassName)Service : IDynamicApiController, ITransient
     @:public async Task<IActionResult> Export(Page@(Model.ClassName)Input input)
     @:{
         @:var list = (await Page(input)).Items?.Adapt<List<Export@(Model.ClassName)Output>>() ?? new();
+        @:if (input.SelectKeyList?.Count > 0) list = list.Where(x => input.SelectKeyList.Contains(x.@(Model.PrimaryKeyFieldList.First().PropertyName))).ToList();
         @:return ExcelHelper.ExportTemplate(list, "@(Model.BusName)导出记录");
     @:}
     @:
@@ -299,7 +300,7 @@ public class @(Model.ClassName)Service : IDynamicApiController, ITransient
                         var columnList = column.FkDisplayColumnList.Select(n => $"{{u.{n}}}").ToList();
                         @:var @(column.LowerPropertyName)LinkMap = _@(Model.LowerClassName)Rep.Context.Queryable<@(column.FkEntityName)>().Where(u => @(column.LowerPropertyName)LabelList.Contains($"@(string.Join("-", columnList))")).ToList().ToDictionary(u => $"@(string.Join("-", columnList))", u => u.@(column.FkLinkColumnName));
                         @:pageItems.ForEach(e => {
-                            @:e.@(column.PropertyName) = @(column.LowerPropertyName)LinkMap?.GetValueOrDefault(e.@column.ExtendedPropertyName);
+                            @:e.@(column.PropertyName) = @(column.LowerPropertyName)LinkMap.GetValueOrDefault(e.@column.ExtendedPropertyName ?? "");
                             @:if (e.@(column.PropertyName) == null) e.Error = "@(column.ColumnComment)链接失败";
                         @:});
                     @:}
@@ -331,7 +332,7 @@ public class @(Model.ClassName)Service : IDynamicApiController, ITransient
                     @:}).Adapt<List<@(Model.ClassName)>>();
 
                     @:
-                    @:var storageable = _sqlSugarClient.Storageable(rows)
+                    @:var storageable = _@(Model.LowerClassName)Rep.Context.Storageable(rows)
                         foreach (var column in Model.ImportFieldList){
                         if (column.WhetherRequired == "Y"){
                         if(column.NetType.TrimEnd('?') == "string"){

+ 29 - 7
Admin.NET/Admin.NET.Web.Entry/wwwroot/template/index.vue.vm

@@ -30,7 +30,7 @@ const editDialogRef = ref();
 @:const importDataRef = ref();
 }
 const state = reactive({
-  loading: false,
+  exportLoading: false,
   tableLoading: false,
   stores: @(Model.HasDictField || Model.HasEnumField || Model.HasConstField ? "useUserInfo()" : "{}"),
   showAdvanceQueryUI: @(Model.HasLikeQuery ? "false" : "true"),
@@ -120,16 +120,29 @@ const batchDel@(Model.ClassName) = () => {
 
 @if (Model.ImportFieldList.Count > 0) {
 @:// 导出数据
-@:const export@(Model.ClassName)Data = async () => {
-  @:const params = Object.assign(state.tableQueryParams, state.tableParams, { page: 1, pageSize: 99999999 });
-  @:@(Model.LowerClassName)Api.exportData(params).then(res => downloadStreamFile(res));
+@:const export@(Model.ClassName)Data = async (type: string | undefined = undefined) => {
+  @:try {
+    @:state.exportLoading = true;
+    @:if (type === 'select') {
+      @:const params = Object.assign({}, state.tableQueryParams, state.tableParams, { selectKeyList: state.selectData.map(u => u.@(Model.PrimaryKeyFieldList.First().LowerPropertyName)) });
+      @:await @(Model.LowerClassName)Api.exportData(params).then(res => downloadStreamFile(res));
+    @:} else if (type === 'current') {
+      @:const params = Object.assign({}, state.tableQueryParams, state.tableParams);
+      @:await @(Model.LowerClassName)Api.exportData(params).then(res => downloadStreamFile(res));
+    @:} else {
+      @:const params = Object.assign({}, state.tableQueryParams, state.tableParams, { page: 1, pageSize: 99999999 });
+      @:await @(Model.LowerClassName)Api.exportData(params).then(res => downloadStreamFile(res));
+    @:}
+  @:} finally {
+    @:state.exportLoading = false;
+  @:}
 @:}
 }
 
 handleQuery();
 </script>
 <template>
-  <div class="@(Model.LowerClassName)-container">
+  <div class="@(Model.LowerClassName)-container" v-loading="state.exportLoading">
     <el-card shadow="hover" :body-style="{ paddingBottom: '0' }"> 
       <el-form :model="state.tableQueryParams" ref="queryForm" labelWidth="90">
         <el-row>
@@ -202,7 +215,16 @@ handleQuery();
                 <el-button type="danger" style="margin-left:5px;" icon="ele-Delete" @@click="batchDel@(Model.ClassName)" :disabled="state.selectData.length == 0" v-auth="'@(Model.LowerClassName):batchDelete'"> 删除 </el-button>
                 <el-button type="primary" style="margin-left:5px;" icon="ele-Plus" @@click="editDialogRef.openDialog(null, '新增@(Model.BusName)')" v-auth="'@(Model.LowerClassName):add'"> 新增 </el-button>
                 @if (Model.ImportFieldList.Count > 0) {
-                @:<el-button type="primary" style="margin-left:5px;" icon="ele-FolderOpened" @@click="export@(Model.ClassName)Data" v-reclick="20000" v-auth="'@(Model.LowerClassName):export'"> 导出 </el-button>
+                @:<el-dropdown>
+                  @:<el-button type="primary" style="margin-left:5px;" icon="ele-FolderOpened" v-reclick="20000" v-auth="'@(Model.LowerClassName):export'"> 导出 </el-button>
+                  @:<template #dropdown>
+                    @:<el-dropdown-menu>
+                      @:<el-dropdown-item @@click="export@(Model.ClassName)Data('select')" :disabled="state.selectData.length == 0">导出选中</el-dropdown-item>
+                      @:<el-dropdown-item @@click="export@(Model.ClassName)Data('current')">导出本页</el-dropdown-item>
+                      @:<el-dropdown-item @@click="export@(Model.ClassName)Data()">导出全部</el-dropdown-item>
+                    @:</el-dropdown-menu>
+                  @:</template>
+                @:</el-dropdown>
                 @:<el-button type="warning" style="margin-left:5px;" icon="ele-MostlyCloudy" @@click="importDataRef.openDialog()" v-auth="'@(Model.LowerClassName):import'"> 导入 </el-button>
                 }
               </el-button-group>
@@ -222,7 +244,7 @@ handleQuery();
     </el-card>
     <el-card class="full-table" shadow="hover" style="margin-top: 5px">
       <el-table :data="state.tableData" @@selection-change="(val: any[]) => { state.selectData = val; }" style="width: 100%" v-loading="state.tableLoading" tooltip-effect="light" row-key="@Model.PrimaryKeyFieldList.First().LowerPropertyName" @@sort-change="sortChange" border>
-        <el-table-column type="selection" width="40" align="center" v-auth="'@(Model.LowerClassName):batchDelete'" />
+        <el-table-column type="selection" width="40" align="center" v-if="auth('@(Model.LowerClassName):batchDelete') || auth('@(Model.LowerClassName):export')" />
         <el-table-column type="index" label="序号" width="55" align="center"/>
     @foreach (var column in Model.TableField.Where(u => u.WhetherTable == "Y")){
       if(column.EffectType == "DictSelector" || column.EffectType == "EnumSelector" || column.EffectType == "Upload" || @column.EffectType == "Switch") {

+ 9 - 15
Web/src/components/table/importData.vue

@@ -8,9 +8,9 @@
 				</div>
 			</template>
 			
-			<el-row :gutter="15">
+			<el-row :gutter="15" v-loading="state.loading">
 				<el-col :xs="12" :sm="12" :md="12" :lg="12" :xl="12">
-					<el-button class="ml10" type="info" icon="ele-Download" v-reclick="3000" @click="() => download()">模板</el-button>
+					<el-button class="ml10" type="info" icon="ele-Download" v-reclick="3000" @click="() => download()" :disabled="state.loading">模板</el-button>
 				</el-col>
 				<el-col :xs="12" :sm="12" :md="12" :lg="12" :xl="12">
 					<el-upload
@@ -21,7 +21,7 @@
 						ref="uploadRef"
 					>
 						<template #trigger>
-							<el-button type="primary" icon="ele-MostlyCloudy" v-reclick="3000">导入</el-button>
+							<el-button type="primary" icon="ele-MostlyCloudy" v-reclick="3000" :disabled="state.loading">导入</el-button>
 						</template>
 					</el-upload>
 				</el-col>
@@ -29,7 +29,7 @@
 
 			<template #footer>
 				<span class="dialog-footer">
-					<el-button @click="() => state.isShowDialog = false">取 消</el-button>
+					<el-button @click="() => state.isShowDialog = false" :disabled="state.loading">取 消</el-button>
 				</span>
 			</template>
 		</el-dialog>
@@ -66,21 +66,15 @@ const handleExceed: UploadProps['onExceed'] = (files) => {
 }
 
 // 数据导入
-const handleImportData = (opt: UploadRequestOptions) => {
+const handleImportData = (opt: UploadRequestOptions): any => {
   state.loading = true;
   props.import(opt.file).then((res: any) => {
-    try {
-      downloadStreamFile(res);
-	    state.isShowDialog = false;
-      emit('refresh');
-    } catch {
-      ElMessage.error(res.data.message || '上传失败');
-    }
-	  state.loading = false;
-  }).catch(() => {
-	  state.loading = false;
+    downloadStreamFile(res);
+    emit('refresh');
+    state.isShowDialog = false;
   }).finally(() => {
     uploadRef.value?.clearFiles();
+    state.loading = false;
   });
 }