Ver Fonte

feat: 代码生成前端数据导入

喵你个旺呀 há 1 ano atrás
pai
commit
28ee9de6eb

+ 27 - 0
Admin.NET/Admin.NET.Web.Entry/wwwroot/template/Manage.js.vm

@@ -6,6 +6,10 @@ enum Api {
   Update@(@Model.ClassName) = '/api/@(@Model.LowerClassName)/update',
   Page@(@Model.ClassName) = '/api/@(@Model.LowerClassName)/page',
   Detail@(@Model.ClassName) = '/api/@(@Model.LowerClassName)/detail',
+@if (Model.TableField.Any(x => x.WhetherImport == "Y")) {
+  @:Import@(@Model.ClassName)Data = '/api/@(@Model.LowerClassName)/import',
+  @:Download@(@Model.ClassName)Template = '/api/@(@Model.LowerClassName)/import',
+}
   @foreach (var column in Model.TableField){
 if(@column.EffectType == "fk" && (@column.WhetherAddUpdate == "Y" || column.QueryWhether == "Y")){
   @:Get@(@column.FkEntityName)@(@column.PropertyName)Dropdown = '/api/@(@Model.LowerClassName)/@(@column.FkEntityName)@(@column.PropertyName)Dropdown',
@@ -58,6 +62,29 @@ export const detail@(@Model.ClassName) = (id: any) =>
 			data: { id },
 		});
 
+@if (Model.TableField.Any(x => x.WhetherImport == "Y")) {
+@:// 下载@(@Model.BusName)数据导入模板
+@:export const download@(@Model.ClassName)Template = () =>
+	@:request({
+		@:url: Api.Download@(@Model.ClassName)Template,
+		@:responseType: 'arraybuffer',
+		@:method: 'get',
+	@:});
+@:
+@:// 导入@(@Model.BusName)记录
+@:export const import@(@Model.ClassName)Data = (file: any) => {
+	@:const formData = new FormData();
+	@:formData.append('file', file);
+	@:return request({
+		@:headers: { 'Content-Type': 'multipart/form-data' },
+		@:url: Api.Import@(@Model.ClassName)Data,
+		@:responseType: 'arraybuffer',
+		@:method: 'post',
+		@:data: formData,
+	@:});
+@:}
+}
+
 @foreach (var column in Model.TableField){
 	if(@column.EffectType == "fk" && (@column.WhetherAddUpdate == "Y" || column.QueryWhether == "Y")){
 @:export const get@(@column.FkEntityName)@(@column.PropertyName)Dropdown = () =>

+ 15 - 1
Admin.NET/Admin.NET.Web.Entry/wwwroot/template/index.vue.vm

@@ -12,13 +12,14 @@
           haveLikeCdt = true;
       }
   }
+  bool hasImport = Model.TableField.Any(x => x.WhetherImport == "Y");
 }
 <template>
   <div class="@(@Model.LowerClassName)-container">
     <el-card shadow="hover" :body-style="{ paddingBottom: '0' }"> 
       @<el-form :model="queryParams" ref="queryForm" labelWidth="90">
         @<el-row>
-              @if(Model.QueryWhetherList.Count > 0){
+          @if(Model.QueryWhetherList.Count > 0){
           @if(haveLikeCdt){
           @:<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="4" class="mb10">
             @:<el-form-item label="关键字">
@@ -95,6 +96,9 @@
                     }
                 @<el-button type="primary" style="margin-left:5px;" icon="ele-Plus" @@click="openAdd@(@Model.ClassName)" v-auth="'@(@Model.LowerClassName):add'"> 新增 </el-button>
                 @
+                @if (hasImport) {
+                @:<el-button type="warning" icon="ele-MostlyCloudy" @@click="importDataRef.openDialog" v-auth="'@(@Model.LowerClassName):import'"> 导入 </el-button>
+                }
               </el-button-group>
             </el-form-item>
             @
@@ -209,6 +213,9 @@
       />
     </el-card>
   </div>
+  @if (hasImport) {
+  @:<ImportData ref="importDataRef" :import="import@(@Model.ClassName)Data" :download="download@(@Model.ClassName)Template" v-auth="'@(@Model.LowerClassName):import'" @@refresh="handleQuery" />
+  }
 </template>
 
 <script lang="ts" setup="" name="@(@Model.LowerClassName)">
@@ -240,6 +247,10 @@
   import printDialog from '/@@/views/system/print/component/hiprint/preview.vue'
   import editDialog from '/@@/views/@(@Model.PagePath)/@(@Model.LowerClassName)/component/editDialog.vue'
   import { page@(@Model.ClassName), delete@(@Model.ClassName) } from '/@@/api/@(@Model.PagePath)/@(@Model.LowerClassName)';
+  @if (hasImport) {
+  @:import { ImportData } from "/@@/components/table/importData.vue";
+  @:import { download@(@Model.ClassName)Template, import@(@Model.ClassName)Data } from '/@@/api/@(@Model.PagePath)/@(@Model.LowerClassName)';
+  }
   @foreach (var column in Model.QueryWhetherList){
   if(@column.EffectType == "fk"){
   @:import { get@(@column.FkEntityName)@(@column.PropertyName)Dropdown } from '/@@/api/@(@Model.PagePath)/@(@Model.LowerClassName)';
@@ -257,6 +268,9 @@
   }
   const printDialogRef = ref();
   const editDialogRef = ref();
+  @if (hasImport) {
+  @:const importDataRef = ref();
+  }
   const loading = ref(false);
   const tableData = ref<any>([]);
   const queryParams = ref<any>({});

+ 101 - 0
Web/src/components/table/importData.vue

@@ -0,0 +1,101 @@
+<template v-loading="state.loading">
+	<div class="sys-import-data-container" v-loading="state.loading">
+		<el-dialog v-model="state.isShowDialog" draggable :close-on-click-modal="false" width="300px" v-loading="state.loading">
+			<template #header>
+				<div style="color: #fff">
+					<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"> <ele-UploadFilled /> </el-icon>
+					<span> 数据导入 </span>
+				</div>
+			</template>
+			
+			<el-row :gutter="15">
+				<el-col :xs="12" :sm="12" :md="12" :lg="12" :xl="12">
+					<el-button class="ml10" type="info" icon="ele-Download" @click="() => download()">模板</el-button>
+				</el-col>
+				<el-col :xs="12" :sm="12" :md="12" :lg="12" :xl="12">
+					<el-upload
+						:limit="1"
+						:show-file-list="false"
+						:on-exceed="handleExceed"
+						:http-request="handleImportData"
+						ref="uploadRef"
+					>
+						<template #trigger>
+							<el-button type="primary" icon="ele-MostlyCloudy">导入</el-button>
+						</template>
+					</el-upload>
+				</el-col>
+			</el-row>
+
+			<template #footer>
+				<span class="dialog-footer">
+					<el-button @click="() => state.isShowDialog = false">取 消</el-button>
+				</span>
+			</template>
+		</el-dialog>
+	</div>
+</template>
+
+<script lang="ts" setup name="sysImportData">
+import type {UploadInstance, UploadProps, UploadRawFile, UploadRequestOptions} from 'element-plus'
+import { ElUpload, ElMessage, genFileId } from 'element-plus';
+import { downloadFile } from '/@/utils/downloadFile';
+import { reactive, ref } from 'vue';
+
+const uploadRef = ref<UploadInstance>();
+const state = reactive({
+	isShowDialog: false,
+	loading: false,
+});
+
+// 定义子组件向父组件传值/事件
+const props = defineProps(['import', 'download']);
+const emit = defineEmits(['refresh']);
+
+// 打开弹窗
+const openDialog = () => {
+	state.isShowDialog = true;
+};
+
+// 选择文件超出上限事件
+const handleExceed: UploadProps['onExceed'] = (files) => {
+  uploadRef.value!.clearFiles();
+  const file = files[0] as UploadRawFile;
+  file.uid = genFileId();
+  uploadRef.value!.handleStart(file);
+}
+
+// 数据导入
+const handleImportData = (opt: UploadRequestOptions) => {
+  state.loading = true;
+  props.import(opt.file).then((res: any) => {
+    try {
+      handleFileStream(res);
+	  state.isShowDialog = false;
+      emit('refresh');
+    } catch (err) {
+      ElMessage.error(res.data.message || '上传失败');
+    }
+  }).finally(() => {
+    state.loading = false;
+    uploadRef.value?.clearFiles();
+  });
+}
+
+// 下载模板
+const download = () => {
+	props.download().then((res: any) => handleFileStream(res)).catch((res: any) => ElMessage.error('下载错误: ' + res));
+}
+
+// 下载文件流
+const handleFileStream = (res: any) => {
+  const contentType = res.headers['content-type'];
+  const contentDisposition = res.headers['content-disposition'];
+  const filename = decodeURIComponent(contentDisposition.split('; ')[1].split('=')[1])
+  const blob = res.data instanceof Blob ? res.data : new Blob([res.data], { type: contentType });
+  downloadFile(window.URL.createObjectURL(blob), filename);
+}
+
+// 导出对象
+defineExpose({ openDialog });
+</script>

+ 19 - 0
Web/src/utils/downloadFile.ts

@@ -0,0 +1,19 @@
+/**
+ * 下载文件
+ * @param url 下载链接
+ * @param filename 文件名
+ */
+export function downloadFile(url: string, filename: string | undefined = undefined) {
+    const urlSplit = url.split('/');
+    filename = filename || urlSplit[urlSplit.length - 1];
+
+    const link = document.createElement('a');
+    link.setAttribute('download', filename);
+    link.href = url;
+
+    document.body.appendChild(link);
+    link.click();
+
+    document.body.removeChild(link);
+    window.URL.revokeObjectURL(url);
+}