mirror of
				https://github.com/continew-org/continew-admin.git
				synced 2025-10-31 10:57:13 +08:00 
			
		
		
		
	refactor: 适配 3.0 前端代码生成模板,代码预览及生成
This commit is contained in:
		| @@ -16,6 +16,7 @@ | ||||
|  | ||||
| package top.charles7c.continew.admin.generator.config.properties; | ||||
|  | ||||
| import cn.hutool.core.io.file.FileNameUtil; | ||||
| import cn.hutool.core.map.MapUtil; | ||||
| import lombok.Data; | ||||
| import org.springframework.boot.context.properties.ConfigurationProperties; | ||||
| @@ -71,5 +72,15 @@ public class GeneratorProperties { | ||||
|          * 排除字段 | ||||
|          */ | ||||
|         private String[] excludeFields; | ||||
|  | ||||
|         /** | ||||
|          * 扩展名 | ||||
|          */ | ||||
|         private String extension = FileNameUtil.EXT_JAVA; | ||||
|  | ||||
|         /** | ||||
|          * 是否为后端模板 | ||||
|          */ | ||||
|         private boolean backend = true; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -21,7 +21,6 @@ import cn.hutool.core.collection.CollUtil; | ||||
| import cn.hutool.core.convert.Convert; | ||||
| import cn.hutool.core.date.DateUtil; | ||||
| import cn.hutool.core.io.FileUtil; | ||||
| import cn.hutool.core.io.file.FileNameUtil; | ||||
| import cn.hutool.core.util.ClassUtil; | ||||
| import cn.hutool.core.util.StrUtil; | ||||
| import cn.hutool.core.util.ZipUtil; | ||||
| @@ -227,7 +226,7 @@ public class GeneratorServiceImpl implements GeneratorService { | ||||
|             .lastIndexOfIgnoreCase(packageName, StringConstants.DOT) + 1); | ||||
|         genConfigMap.put("apiModuleName", apiModuleName); | ||||
|         genConfigMap.put("apiName", StrUtil.lowerFirst(genConfig.getClassNamePrefix())); | ||||
|         // 渲染后端代码 | ||||
|         // 渲染代码 | ||||
|         String classNamePrefix = genConfig.getClassNamePrefix(); | ||||
|         Map<String, TemplateConfig> templateConfigMap = generatorProperties.getTemplateConfigs(); | ||||
|         for (Map.Entry<String, TemplateConfig> templateConfigEntry : templateConfigMap.entrySet()) { | ||||
| @@ -235,27 +234,22 @@ public class GeneratorServiceImpl implements GeneratorService { | ||||
|             String className = classNamePrefix + StrUtil.nullToEmpty(templateConfigEntry.getKey()); | ||||
|             genConfigMap.put("className", className); | ||||
|             TemplateConfig templateConfig = templateConfigEntry.getValue(); | ||||
|             String content = TemplateUtils.render(templateConfig.getTemplatePath(), genConfigMap); | ||||
|             boolean isBackend = templateConfig.isBackend(); | ||||
|             String extension = templateConfig.getExtension(); | ||||
|             GeneratePreviewResp generatePreview = new GeneratePreviewResp(); | ||||
|             generatePreview.setFileName(className + FileNameUtil.EXT_JAVA); | ||||
|             generatePreview.setContent(content); | ||||
|             generatePreview.setBackend(true); | ||||
|             generatePreview.setBackend(isBackend); | ||||
|             generatePreviewList.add(generatePreview); | ||||
|             if (isBackend) { | ||||
|                 generatePreview.setFileName(className + extension); | ||||
|                 generatePreview.setContent(TemplateUtils.render(templateConfig.getTemplatePath(), genConfigMap)); | ||||
|             } else { | ||||
|                 generatePreview.setFileName(".vue".equals(extension) && "index".equals(templateConfigEntry.getKey()) | ||||
|                     ? "index.vue" | ||||
|                     : this.getFrontendFileName(classNamePrefix, className, extension)); | ||||
|                 genConfigMap.put("fieldConfigs", fieldConfigList); | ||||
|                 generatePreview.setContent(TemplateUtils.render(templateConfig.getTemplatePath(), genConfigMap)); | ||||
|             } | ||||
|         } | ||||
|         // 渲染前端代码 | ||||
|         // api 代码 | ||||
|         genConfigMap.put("fieldConfigs", fieldConfigList); | ||||
|         String apiContent = TemplateUtils.render("api.ftl", genConfigMap); | ||||
|         GeneratePreviewResp apiGeneratePreview = new GeneratePreviewResp(); | ||||
|         apiGeneratePreview.setFileName(classNamePrefix.toLowerCase() + ".ts"); | ||||
|         apiGeneratePreview.setContent(apiContent); | ||||
|         generatePreviewList.add(apiGeneratePreview); | ||||
|         // view 代码 | ||||
|         String viewContent = TemplateUtils.render("index.ftl", genConfigMap); | ||||
|         GeneratePreviewResp viewGeneratePreview = new GeneratePreviewResp(); | ||||
|         viewGeneratePreview.setFileName("index.vue"); | ||||
|         viewGeneratePreview.setContent(viewContent); | ||||
|         generatePreviewList.add(viewGeneratePreview); | ||||
|         return generatePreviewList; | ||||
|     } | ||||
|  | ||||
| @@ -265,45 +259,12 @@ public class GeneratorServiceImpl implements GeneratorService { | ||||
|             String tempDir = SystemUtil.getUserInfo().getTempDir(); | ||||
|             // 删除旧代码 | ||||
|             FileUtil.del(tempDir + projectProperties.getAppName()); | ||||
|  | ||||
|             tableNames.forEach(tableName -> { | ||||
|                 // 初始化配置及数据 | ||||
|                 List<GeneratePreviewResp> generatePreviewList = this.preview(tableName); | ||||
|                 GenConfigDO genConfig = genConfigMapper.selectById(tableName); | ||||
|                 // 生成后端代码 | ||||
|                 Map<Boolean, List<GeneratePreviewResp>> generatePreviewListMap = generatePreviewList.stream() | ||||
|                     .collect(Collectors.groupingBy(GeneratePreviewResp::isBackend)); | ||||
|                 this.generateBackendCode(generatePreviewListMap.get(true), genConfig); | ||||
|                 // 生成前端代码 | ||||
|                 List<GeneratePreviewResp> frontendGeneratePreviewList = generatePreviewListMap.get(false); | ||||
|                 String packageName = genConfig.getPackageName(); | ||||
|                 String moduleName = StrUtil.subSuf(packageName, StrUtil | ||||
|                     .lastIndexOfIgnoreCase(packageName, StringConstants.DOT) + 1); | ||||
|  | ||||
|                 // 例如:continew-admin-ui/src | ||||
|                 String frontendBasicPackagePath = tempDir + String.join(File.separator, projectProperties | ||||
|                     .getAppName(), projectProperties.getAppName() + "-ui", "src"); | ||||
|                 // 1、生成 api 代码 | ||||
|                 GeneratePreviewResp apiGeneratePreview = frontendGeneratePreviewList.get(0); | ||||
|                 // 例如:continew-admin-ui/src/src/api/system | ||||
|                 String apiPath = String.join(File.separator, frontendBasicPackagePath, "api", moduleName); | ||||
|                 // 例如:continew-admin-ui/src/api/system/user.ts | ||||
|                 File apiFile = new File(apiPath, apiGeneratePreview.getFileName()); | ||||
|                 if (!apiFile.exists() || Boolean.TRUE.equals(genConfig.getIsOverride())) { | ||||
|                     FileUtil.writeUtf8String(apiGeneratePreview.getContent(), apiFile); | ||||
|                 } | ||||
|                 // 2、生成 view 代码 | ||||
|                 GeneratePreviewResp viewGeneratePreview = frontendGeneratePreviewList.get(1); | ||||
|                 // 例如:continew-admin-ui/src/views/system | ||||
|                 String vuePath = String.join(File.separator, frontendBasicPackagePath, "views", moduleName, StrUtil | ||||
|                     .lowerFirst(genConfig.getClassNamePrefix())); | ||||
|                 // 例如:continew-admin-ui/src/views/system/user/index.vue | ||||
|                 File vueFile = new File(vuePath, viewGeneratePreview.getFileName()); | ||||
|                 if (!vueFile.exists() || Boolean.TRUE.equals(genConfig.getIsOverride())) { | ||||
|                     FileUtil.writeUtf8String(viewGeneratePreview.getContent(), vueFile); | ||||
|                 } | ||||
|                 // 生成代码 | ||||
|                 this.generateCode(generatePreviewList, genConfigMapper.selectById(tableName)); | ||||
|             }); | ||||
|  | ||||
|             // 打包下载 | ||||
|             File tempDirFile = new File(tempDir, projectProperties.getAppName()); | ||||
|             String zipFilePath = tempDirFile.getPath() + jodd.io.ZipUtil.ZIP_EXT; | ||||
| @@ -316,27 +277,46 @@ public class GeneratorServiceImpl implements GeneratorService { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 生成后端代码 | ||||
|      * 生成代码 | ||||
|      * | ||||
|      * @param generatePreviewList 生成预览列表 | ||||
|      * @param genConfig           生成配置 | ||||
|      */ | ||||
|     private void generateBackendCode(List<GeneratePreviewResp> generatePreviewList, GenConfigDO genConfig) { | ||||
|     private void generateCode(List<GeneratePreviewResp> generatePreviewList, GenConfigDO genConfig) { | ||||
|         // 获取前后端基础路径 | ||||
|         String backendBasicPackagePath = this.buildBackendBasicPackagePath(genConfig); | ||||
|         String frontendBasicPackagePath = SystemUtil.getUserInfo().getTempDir() + String | ||||
|             .join(File.separator, projectProperties.getAppName(), projectProperties.getAppName() + "-ui"); | ||||
|         String packageName = genConfig.getPackageName(); | ||||
|         String moduleName = StrUtil.subSuf(packageName, StrUtil | ||||
|             .lastIndexOfIgnoreCase(packageName, StringConstants.DOT) + 1); | ||||
|         // 生成代码 | ||||
|         Map<String, TemplateConfig> templateConfigMap = generatorProperties.getTemplateConfigs(); | ||||
|         for (GeneratePreviewResp generatePreview : generatePreviewList) { | ||||
|             // 获取对应模板配置 | ||||
|             TemplateConfig templateConfig = templateConfigMap.get(generatePreview.getFileName() | ||||
|                 .replace(genConfig.getClassNamePrefix(), StringConstants.EMPTY) | ||||
|                 .replace(FileNameUtil.EXT_JAVA, StringConstants.EMPTY)); | ||||
|             // 例如:continew-admin/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/service/impl | ||||
|             String packagePath = String.join(File.separator, backendBasicPackagePath, templateConfig.getPackageName() | ||||
|                 .replace(StringConstants.DOT, File.separator)); | ||||
|             // 例如:continew-admin/continew-admin-system/src/main/java/top/charles7c/continew/admin/system/service/impl/XxxServiceImpl.java | ||||
|             File classFile = new File(packagePath, generatePreview.getFileName()); | ||||
|             TemplateConfig templateConfig = templateConfigMap.getOrDefault(StrUtil.subBefore(generatePreview | ||||
|                 .getFileName(), StringConstants.DOT, true) | ||||
|                 .replace(genConfig.getClassNamePrefix(), StringConstants.EMPTY), templateConfigMap.get("api")); | ||||
|             String packagePath; | ||||
|             if (generatePreview.isBackend()) { | ||||
|                 // 例如:continew-admin/continew-system/src/main/java/top/continew/admin/system/service/impl | ||||
|                 packagePath = String.join(File.separator, backendBasicPackagePath, templateConfig.getPackageName() | ||||
|                     .replace(StringConstants.DOT, File.separator)); | ||||
|             } else { | ||||
|                 // 例如:continew-admin/continew-admin-ui/src/views/system | ||||
|                 packagePath = String.join(File.separator, frontendBasicPackagePath, templateConfig.getPackageName() | ||||
|                     .replace(StringConstants.SLASH, File.separator), moduleName); | ||||
|                 // 例如:continew-admin/continew-admin-ui/src/views/system/user | ||||
|                 packagePath = ".vue".equals(templateConfig.getExtension()) | ||||
|                     ? packagePath + File.separator + StrUtil.lowerFirst(genConfig.getClassNamePrefix()) | ||||
|                     : packagePath; | ||||
|             } | ||||
|             // 后端:continew-admin/continew-system/src/main/java/top/continew/admin/system/service/impl/XxxServiceImpl.java | ||||
|             // 前端:continew-admin/continew-admin-ui/src/views/system/user/index.vue | ||||
|             File file = new File(packagePath, generatePreview.getFileName()); | ||||
|             // 如果已经存在,且不允许覆盖,则跳过 | ||||
|             if (!classFile.exists() || Boolean.TRUE.equals(genConfig.getIsOverride())) { | ||||
|                 FileUtil.writeUtf8String(generatePreview.getContent(), classFile); | ||||
|             if (!file.exists() || Boolean.TRUE.equals(genConfig.getIsOverride())) { | ||||
|                 FileUtil.writeUtf8String(generatePreview.getContent(), file); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -348,13 +328,25 @@ public class GeneratorServiceImpl implements GeneratorService { | ||||
|      * @return 后端包路径 | ||||
|      */ | ||||
|     private String buildBackendBasicPackagePath(GenConfigDO genConfig) { | ||||
|         // 例如:continew-admin/continew-admin-system/src/main/java/top/charles7c/continew/admin/system | ||||
|         // 例如:continew-admin/continew-system/src/main/java/top/continew/admin/system | ||||
|         return SystemUtil.getUserInfo().getTempDir() + String.join(File.separator, projectProperties | ||||
|             .getAppName(), projectProperties.getAppName(), genConfig.getModuleName(), "src", "main", "java", genConfig | ||||
|                 .getPackageName() | ||||
|                 .replace(StringConstants.DOT, File.separator)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取前端文件名 | ||||
|      * | ||||
|      * @param classNamePrefix 类名前缀 | ||||
|      * @param className       类名 | ||||
|      * @param extension       扩展名 | ||||
|      * @return 前端文件名 | ||||
|      */ | ||||
|     private String getFrontendFileName(String classNamePrefix, String className, String extension) { | ||||
|         return (".ts".equals(extension) ? StrUtil.lowerFirst(classNamePrefix) : className) + extension; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 预处理生成配置 | ||||
|      * | ||||
|   | ||||
| @@ -1,57 +0,0 @@ | ||||
| import axios from 'axios'; | ||||
| import qs from 'query-string'; | ||||
|  | ||||
| const BASE_URL = '/${apiModuleName}/${apiName}'; | ||||
|  | ||||
| export interface DataRecord { | ||||
| <#if fieldConfigs??> | ||||
| <#list fieldConfigs as fieldConfig> | ||||
|   ${fieldConfig.fieldName}?: string; | ||||
| </#list> | ||||
|   createUserString?: string; | ||||
|   updateUserString?: string; | ||||
| </#if> | ||||
| } | ||||
|  | ||||
| export interface ListParam { | ||||
| <#if fieldConfigs??> | ||||
| <#list fieldConfigs as fieldConfig> | ||||
|   <#if fieldConfig.showInQuery> | ||||
|   ${fieldConfig.fieldName}?: string; | ||||
|   </#if> | ||||
| </#list> | ||||
| </#if> | ||||
|   page?: number; | ||||
|   size?: number; | ||||
|   sort?: Array<string>; | ||||
| } | ||||
|  | ||||
| export interface ListRes { | ||||
|   list: DataRecord[]; | ||||
|   total: number; | ||||
| } | ||||
|  | ||||
| export function list(params: ListParam) { | ||||
|   return axios.get<ListRes>(`${'$'}{BASE_URL}`, { | ||||
|     params, | ||||
|     paramsSerializer: (obj) => { | ||||
|       return qs.stringify(obj); | ||||
|     }, | ||||
|   }); | ||||
| } | ||||
|  | ||||
| export function get(id: string) { | ||||
|   return axios.get<DataRecord>(`${'$'}{BASE_URL}/${'$'}{id}`); | ||||
| } | ||||
|  | ||||
| export function add(req: DataRecord) { | ||||
|   return axios.post(BASE_URL, req); | ||||
| } | ||||
|  | ||||
| export function update(req: DataRecord, id: string) { | ||||
|   return axios.put(`${'$'}{BASE_URL}/${'$'}{id}`, req); | ||||
| } | ||||
|  | ||||
| export function del(ids: string | Array<string>) { | ||||
|   return axios.delete(`${'$'}{BASE_URL}/${'$'}{ids}`); | ||||
| } | ||||
| @@ -0,0 +1,103 @@ | ||||
| <template> | ||||
|   <a-modal | ||||
|     v-model:visible="visible" | ||||
|     :title="title" | ||||
|     :mask-closable="false" | ||||
|     :esc-to-close="false" | ||||
|     :modal-style="{ maxWidth: '520px' }" | ||||
|     width="90%" | ||||
|     @before-ok="save" | ||||
|     @close="reset" | ||||
|   > | ||||
|     <GiForm ref="formRef" v-model="form" :options="options" :columns="columns" /> | ||||
|   </a-modal> | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import { get${classNamePrefix}, add${classNamePrefix}, update${classNamePrefix} } from '@/apis' | ||||
| import { Message } from '@arco-design/web-vue' | ||||
| import { GiForm, type Columns } from '@/components/GiForm' | ||||
| import { useForm } from '@/hooks' | ||||
|  | ||||
| const dataId = ref('') | ||||
| const isUpdate = computed(() => !!dataId.value) | ||||
| const title = computed(() => (isUpdate.value ? '修改${businessName}' : '新增${businessName}')) | ||||
| const formRef = ref<InstanceType<typeof GiForm>>() | ||||
|  | ||||
| const options: Options = { | ||||
|   form: {}, | ||||
|   col: { xs: 24, sm: 24, md: 24, lg: 24, xl: 24, xxl: 24 }, | ||||
|   btns: { hide: true } | ||||
| } | ||||
|  | ||||
| const columns: Columns = [ | ||||
| <#list fieldConfigs as fieldConfig> | ||||
|   <#if fieldConfig.showInForm> | ||||
|   { | ||||
|     label: '${fieldConfig.comment}', | ||||
|     field: '${fieldConfig.fieldName}', | ||||
|     <#if fieldConfig.formType = 'TEXT'> | ||||
|     type: 'input', | ||||
|     <#elseif fieldConfig.formType = 'TEXT_AREA'> | ||||
|     type: 'textarea', | ||||
|     </#if> | ||||
|     <#if fieldConfig.isRequired> | ||||
|     rules: [{ required: true, message: '请输入${fieldConfig.comment}' }] | ||||
|     </#if> | ||||
|   }, | ||||
|   </#if> | ||||
| </#list> | ||||
| ] | ||||
|  | ||||
| const { form, resetForm } = useForm<({ | ||||
|     // todo 待补充 | ||||
| }) | ||||
|  | ||||
| // 重置 | ||||
| const reset = () => { | ||||
|   formRef.value?.formRef?.resetFields() | ||||
|   resetForm() | ||||
| } | ||||
|  | ||||
| const visible = ref(false) | ||||
| // 新增 | ||||
| const onAdd = () => { | ||||
|   reset() | ||||
|   dataId.value = '' | ||||
|   visible.value = true | ||||
| } | ||||
|  | ||||
| // 修改 | ||||
| const onUpdate = async (id: string) => { | ||||
|   reset() | ||||
|   dataId.value = id | ||||
|   const res = await get${classNamePrefix}(id) | ||||
|   Object.assign(form, res.data) | ||||
|   visible.value = true | ||||
| } | ||||
|  | ||||
| // 保存 | ||||
| const save = async () => { | ||||
|   try { | ||||
|     const isInvalid = await formRef.value?.formRef?.validate() | ||||
|     if (isInvalid) return false | ||||
|     if (isUpdate.value) { | ||||
|       await update${classNamePrefix}(form, dataId.value) | ||||
|       Message.success('修改成功') | ||||
|     } else { | ||||
|       await add${classNamePrefix}(form) | ||||
|       Message.success('新增成功') | ||||
|     } | ||||
|     emit('save-success') | ||||
|     return true | ||||
|   } catch (error) { | ||||
|     return false | ||||
|   } | ||||
| } | ||||
|  | ||||
| const emit = defineEmits<{ | ||||
|   (e: 'save-success'): void | ||||
| }>() | ||||
|  | ||||
| defineExpose({ onAdd, onUpdate }) | ||||
| </script> | ||||
| @@ -0,0 +1,41 @@ | ||||
| <template> | ||||
|   <a-drawer v-model:visible="visible" title="${businessName}详情" :width="width >= 580 ? 580 : '100%'" :footer="false"> | ||||
|     <a-descriptions :column="2" size="large" class="general-description"> | ||||
|       <#list fieldConfigs as fieldConfig> | ||||
|       <a-descriptions-item label="${fieldConfig.comment}">{{ dataDetail?.${fieldConfig.fieldName} }}</a-descriptions-item> | ||||
|       <#if fieldConfig.fieldName = 'createUser'> | ||||
|       <a-descriptions-item label="创建人">{{ dataDetail?.createUserString }}</a-descriptions-item> | ||||
|       <#elseif fieldConfig.fieldName = 'updateUser'> | ||||
|       <a-descriptions-item label="修改人">{{ dataDetail?.updateUserString }}</a-descriptions-item> | ||||
|       </#if> | ||||
|       </#list> | ||||
|     </a-descriptions> | ||||
|   </a-drawer> | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { get${classNamePrefix}, type ${classNamePrefix}DetailResp } from '@/apis' | ||||
| import { useWindowSize } from '@vueuse/core' | ||||
|  | ||||
| const { width } = useWindowSize() | ||||
|  | ||||
| const visible = ref(false) | ||||
| const dataId = ref('') | ||||
| const dataDetail = ref<${classNamePrefix}DetailResp>() | ||||
| // 查询详情 | ||||
| const getDataDetail = async () => { | ||||
|   const res = await get${classNamePrefix}(dataId.value) | ||||
|   dataDetail.value = res.data | ||||
| } | ||||
|  | ||||
| // 打开详情 | ||||
| const onDetail = async (id: string) => { | ||||
|   dataId.value = id | ||||
|   await getDataDetail() | ||||
|   visible.value = true | ||||
| } | ||||
|  | ||||
| defineExpose({ onDetail }) | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped></style> | ||||
| @@ -0,0 +1,58 @@ | ||||
| import http from '@/utils/http' | ||||
|  | ||||
| const BASE_URL = '/${apiModuleName}/${apiName}' | ||||
|  | ||||
| export interface ${classNamePrefix}Resp { | ||||
| <#if fieldConfigs??> | ||||
| <#list fieldConfigs as fieldConfig> | ||||
|   <#if fieldConfig.showInList> | ||||
|   ${fieldConfig.fieldName}: string | ||||
|   </#if> | ||||
| </#list> | ||||
|   createUserString: string | ||||
|   updateUserString: string | ||||
| </#if> | ||||
| } | ||||
| export interface ${classNamePrefix}DetailResp { | ||||
| <#if fieldConfigs??> | ||||
| <#list fieldConfigs as fieldConfig> | ||||
|   ${fieldConfig.fieldName}: string | ||||
| </#list> | ||||
|   createUserString: string | ||||
|   updateUserString: string | ||||
| </#if> | ||||
| } | ||||
| export interface ${classNamePrefix}Query extends PageQuery { | ||||
| <#if fieldConfigs??> | ||||
| <#list fieldConfigs as fieldConfig> | ||||
|   <#if fieldConfig.showInQuery> | ||||
|   ${fieldConfig.fieldName}: string | ||||
|   </#if> | ||||
| </#list> | ||||
| </#if> | ||||
| } | ||||
|  | ||||
| /** @desc 查询${businessName}列表 */ | ||||
| export function list${classNamePrefix}(query: ${classNamePrefix}Query) { | ||||
|   return http.get<PageRes<${classNamePrefix}Resp[]>>(`${'$'}{BASE_URL}`, query) | ||||
| } | ||||
|  | ||||
| /** @desc 查询${businessName}详情 */ | ||||
| export function get${classNamePrefix}(id: string) { | ||||
|   return http.get<${classNamePrefix}DetailResp>(`${'$'}{BASE_URL}/${'$'}{id}`) | ||||
| } | ||||
|  | ||||
| /** @desc 新增${businessName} */ | ||||
| export function add${classNamePrefix}(data: any) { | ||||
|   return http.post(`${'$'}{BASE_URL}`, data) | ||||
| } | ||||
|  | ||||
| /** @desc 修改${businessName} */ | ||||
| export function update${classNamePrefix}(data: any, id: string) { | ||||
|   return http.put(`${'$'}{BASE_URL}/${'$'}{id}`, data) | ||||
| } | ||||
|  | ||||
| /** @desc 删除${businessName} */ | ||||
| export function delete${classNamePrefix}(id: string) { | ||||
|   return http.del(`${'$'}{BASE_URL}/${'$'}{id}`) | ||||
| } | ||||
| @@ -0,0 +1,148 @@ | ||||
| <template> | ||||
|   <div class="gi_page"> | ||||
|     <a-card title="${businessName}管理" class="general-card"> | ||||
|       <GiTable | ||||
|         ref="tableRef" | ||||
|         row-key="id" | ||||
|         :data="dataList" | ||||
|         :columns="columns" | ||||
|         :loading="loading" | ||||
|         :scroll="{ x: '100%', y: '100%', minWidth: 1000 }" | ||||
|         :pagination="pagination" | ||||
|         :disabledColumnKeys="['name']" | ||||
|         @refresh="search" | ||||
|       > | ||||
|         <template #custom-left> | ||||
|           <#list fieldConfigs as fieldConfig> | ||||
|           <#if fieldConfig.showInQuery> | ||||
|           <a-input v-model="queryForm.${fieldConfig.fieldName}" placeholder="请输入${fieldConfig.comment}" allow-clear @change="search"> | ||||
|             <template #prefix><icon-search /></template> | ||||
|           </a-input> | ||||
|           </#if> | ||||
|           </#list> | ||||
|           <a-button @click="reset">重置</a-button> | ||||
|         </template> | ||||
|         <template #custom-right> | ||||
|           <a-button v-permission="['${apiModuleName}:${apiName}:add']" type="primary" @click="onAdd"> | ||||
|             <template #icon><icon-plus /></template> | ||||
|             <span>新增</span> | ||||
|           </a-button> | ||||
|           <a-tooltip content="导出"> | ||||
|             <a-button v-permission="['${apiModuleName}:${apiName}:export']" @click="onExport"> | ||||
|               <template #icon> | ||||
|                 <icon-download /> | ||||
|               </template> | ||||
|             </a-button> | ||||
|           </a-tooltip> | ||||
|         </template> | ||||
|         <template #action="{ record }"> | ||||
|           <a-space> | ||||
|             <a-link v-permission="['${apiModuleName}:${apiName}:update']" @click="onUpdate(record)">修改</a-link> | ||||
|             <a-link | ||||
|               v-permission="['${apiModuleName}:${apiName}:delete']" | ||||
|               status="danger" | ||||
|               :disabled="record.disabled" | ||||
|               @click="onDelete(record)" | ||||
|             > | ||||
|               删除 | ||||
|             </a-link> | ||||
|           </a-space> | ||||
|         </template> | ||||
|       </GiTable> | ||||
|     </a-card> | ||||
|  | ||||
|     <${classNamePrefix}AddModal ref="${classNamePrefix}AddModalRef" @save-success="search" /> | ||||
|     <${classNamePrefix}DetailDrawer ref="${classNamePrefix}DetailDrawerRef" /> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import { list${classNamePrefix}, delete${classNamePrefix}, export${classNamePrefix}, type ${classNamePrefix}Resp, type ${classNamePrefix}Query } from '@/apis' | ||||
| import ${classNamePrefix}AddModal from './${classNamePrefix}AddModal.vue' | ||||
| import ${classNamePrefix}DetailDrawer from './${classNamePrefix}DetailDrawer.vue' | ||||
| import { Message } from '@arco-design/web-vue' | ||||
| import type { TreeInstance } from '@arco-design/web-vue' | ||||
| import type { TableInstanceColumns } from '@/components/GiTable/type' | ||||
| import { useTable, useDownload } from '@/hooks' | ||||
| import { isMobile } from '@/utils' | ||||
| import has from '@/utils/has' | ||||
|  | ||||
| defineOptions({ name: '${classNamePrefix}' }) | ||||
|  | ||||
| const columns: TableInstanceColumns[] = [ | ||||
| <#if fieldConfigs??> | ||||
|   <#list fieldConfigs as fieldConfig> | ||||
|   <#if fieldConfig.showInList> | ||||
|   { title: '${fieldConfig.comment}', dataIndex: '${fieldConfig.fieldName}' }, | ||||
|   </#if> | ||||
|   </#list> | ||||
| </#if> | ||||
|   { | ||||
|     title: '操作', | ||||
|     slotName: 'action', | ||||
|     width: 130, | ||||
|     align: 'center', | ||||
|     fixed: !isMobile() ? 'right' : undefined, | ||||
|     show: has.hasPermOr(['${apiModuleName}:${apiName}:update', '${apiModuleName}:${apiName}:delete']) | ||||
|   } | ||||
| ] | ||||
|  | ||||
| const queryForm: ${classNamePrefix}Query = reactive({ | ||||
| <#list fieldConfigs as fieldConfig> | ||||
| <#if fieldConfig.showInQuery> | ||||
|   ${fieldConfig.fieldName}: undefined, | ||||
| </#if> | ||||
| </#list> | ||||
|   sort: ['createTime,desc'] | ||||
| }) | ||||
|  | ||||
| const { | ||||
|   tableData: dataList, | ||||
|   loading, | ||||
|   pagination, | ||||
|   search, | ||||
|   handleDelete | ||||
| } = useTable((p) => list${classNamePrefix}({ ...queryForm, page: p.page, size: p.size }), { immediate: true }) | ||||
|  | ||||
| // 重置 | ||||
| const reset = () => { | ||||
| <#list fieldConfigs as fieldConfig> | ||||
| <#if fieldConfig.showInQuery> | ||||
|   queryForm.${fieldConfig.fieldName} = undefined | ||||
| </#if> | ||||
| </#list> | ||||
|   search() | ||||
| } | ||||
|  | ||||
| // 删除 | ||||
| const onDelete = (item: ${classNamePrefix}Resp) => { | ||||
|   return handleDelete(() => delete${classNamePrefix}(item.id), { | ||||
|     content: `是否确定删除该条数据?`, | ||||
|     showModal: true | ||||
|   }) | ||||
| } | ||||
|  | ||||
| // 导出 | ||||
| const onExport = () => { | ||||
|   useDownload(() => export${classNamePrefix}(queryForm)) | ||||
| } | ||||
|  | ||||
| const ${classNamePrefix}AddModalRef = ref<InstanceType<typeof ${classNamePrefix}AddModal>>() | ||||
| // 新增 | ||||
| const onAdd = () => { | ||||
|   ${classNamePrefix}AddModalRef.value?.onAdd() | ||||
| } | ||||
|  | ||||
| // 修改 | ||||
| const onUpdate = (item: ${classNamePrefix}Resp) => { | ||||
|   ${classNamePrefix}AddModalRef.value?.onUpdate(item.id) | ||||
| } | ||||
|  | ||||
| const ${classNamePrefix}DetailDrawerRef = ref<InstanceType<typeof ${classNamePrefix}DetailDrawer>>() | ||||
| // 详情 | ||||
| const onDetail = (item: ${classNamePrefix}Resp) => { | ||||
|   ${classNamePrefix}DetailDrawerRef.value?.onDetail(item.id) | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped></style> | ||||
| @@ -1,511 +0,0 @@ | ||||
| <script lang="ts" setup> | ||||
|   import { | ||||
|     DataRecord, | ||||
|     ListParam, | ||||
|     list, | ||||
|     get, | ||||
|     add, | ||||
|     update, | ||||
|     del, | ||||
|   } from '@/api/${apiModuleName}/${apiName}'; | ||||
|   import checkPermission from '@/utils/permission'; | ||||
|  | ||||
|   const { proxy } = getCurrentInstance() as any; | ||||
|   // const { dis_enable_status_enum } = proxy.useDict('dis_enable_status_enum'); | ||||
|  | ||||
|   const queryFormRef = ref(); | ||||
|   const formRef = ref(); | ||||
|   const dataList = ref<DataRecord[]>([]); | ||||
|   const dataDetail = ref<DataRecord>({ | ||||
|     // TODO 待补充详情字段默认值 | ||||
|   }); | ||||
|   const total = ref(0); | ||||
|   const ids = ref<Array<string>>([]); | ||||
|   const title = ref(''); | ||||
|   const single = ref(true); | ||||
|   const multiple = ref(true); | ||||
|   const showQuery = ref(true); | ||||
|   const loading = ref(false); | ||||
|   const detailLoading = ref(false); | ||||
|   const exportLoading = ref(false); | ||||
|   const visible = ref(false); | ||||
|   const detailVisible = ref(false); | ||||
|  | ||||
|   const data = reactive({ | ||||
|     // 查询参数 | ||||
|     queryParams: { | ||||
|       <#list fieldConfigs as fieldConfig> | ||||
|       <#if fieldConfig.showInQuery> | ||||
|       ${fieldConfig.fieldName}: undefined, | ||||
|       </#if> | ||||
|       </#list> | ||||
|       page: 1, | ||||
|       size: 10, | ||||
|       sort: ['createTime,desc'], | ||||
|     }, | ||||
|     // 表单数据 | ||||
|     form: {} as DataRecord, | ||||
|     // 表单验证规则 | ||||
|     rules: { | ||||
|       <#list fieldConfigs as fieldConfig> | ||||
|       <#if fieldConfig.showInForm && fieldConfig.isRequired> | ||||
|       ${fieldConfig.fieldName}: [{ required: true, message: '${fieldConfig.comment}不能为空' }], | ||||
|       </#if> | ||||
|       </#list> | ||||
|     }, | ||||
|   }); | ||||
|   const { queryParams, form, rules } = toRefs(data); | ||||
|  | ||||
|   /** | ||||
|    * 查询列表 | ||||
|    * | ||||
|    * @param params 查询参数 | ||||
|    */ | ||||
|   const getList = (params: ListParam = { ...queryParams.value }) => { | ||||
|     loading.value = true; | ||||
|     list(params) | ||||
|       .then((res) => { | ||||
|         dataList.value = res.data.list; | ||||
|         total.value = res.data.total; | ||||
|       }) | ||||
|       .finally(() => { | ||||
|         loading.value = false; | ||||
|       }); | ||||
|   }; | ||||
|   getList(); | ||||
|  | ||||
|   /** | ||||
|    * 打开新增对话框 | ||||
|    */ | ||||
|   const toAdd = () => { | ||||
|     reset(); | ||||
|     title.value = '新增${businessName}'; | ||||
|     visible.value = true; | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * 打开修改对话框 | ||||
|    * | ||||
|    * @param id ID | ||||
|    */ | ||||
|   const toUpdate = (id: string) => { | ||||
|     reset(); | ||||
|     get(id).then((res) => { | ||||
|       form.value = res.data; | ||||
|       title.value = '修改${businessName}'; | ||||
|       visible.value = true; | ||||
|     }); | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * 重置表单 | ||||
|    */ | ||||
|   const reset = () => { | ||||
|     form.value = { | ||||
|       // TODO 待补充需要重置的字段默认值,详情请参考其他模块 index.vue | ||||
|     }; | ||||
|     formRef.value.resetFields(); | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * 取消 | ||||
|    */ | ||||
|   const handleCancel = () => { | ||||
|     visible.value = false; | ||||
|     formRef.value.resetFields(); | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * 确定 | ||||
|    */ | ||||
|   const handleOk = () => { | ||||
|     formRef.value.validate((valid: any) => { | ||||
|       if (!valid) { | ||||
|         if (form.value.id !== undefined) { | ||||
|           update(form.value, form.value.id).then((res) => { | ||||
|             handleCancel(); | ||||
|             getList(); | ||||
|             proxy.$message.success(res.msg); | ||||
|           }); | ||||
|         } else { | ||||
|           add(form.value).then((res) => { | ||||
|             handleCancel(); | ||||
|             getList(); | ||||
|             proxy.$message.success(res.msg); | ||||
|           }); | ||||
|         } | ||||
|       } | ||||
|     }); | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * 查看详情 | ||||
|    * | ||||
|    * @param id ID | ||||
|    */ | ||||
|   const toDetail = async (id: string) => { | ||||
|     if (detailLoading.value) return; | ||||
|     detailLoading.value = true; | ||||
|     detailVisible.value = true; | ||||
|     get(id) | ||||
|       .then((res) => { | ||||
|         dataDetail.value = res.data; | ||||
|       }) | ||||
|       .finally(() => { | ||||
|         detailLoading.value = false; | ||||
|       }); | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * 关闭详情 | ||||
|    */ | ||||
|   const handleDetailCancel = () => { | ||||
|     detailVisible.value = false; | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * 批量删除 | ||||
|    */ | ||||
|   const handleBatchDelete = () => { | ||||
|     if (ids.value.length === 0) { | ||||
|       proxy.$message.info('请选择要删除的数据'); | ||||
|     } else { | ||||
|       proxy.$modal.warning({ | ||||
|         title: '警告', | ||||
|         titleAlign: 'start', | ||||
|         content: `是否确定删除所选的${r'${ids.value.length}'}条数据?`, | ||||
|         hideCancel: false, | ||||
|         onOk: () => { | ||||
|           handleDelete(ids.value); | ||||
|         }, | ||||
|       }); | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * 删除 | ||||
|    * | ||||
|    * @param ids ID 列表 | ||||
|    */ | ||||
|   const handleDelete = (ids: Array<string>) => { | ||||
|     del(ids).then((res) => { | ||||
|       proxy.$message.success(res.msg); | ||||
|       getList(); | ||||
|     }); | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * 已选择的数据行发生改变时触发 | ||||
|    * | ||||
|    * @param rowKeys ID 列表 | ||||
|    */ | ||||
|   const handleSelectionChange = (rowKeys: Array<any>) => { | ||||
|     ids.value = rowKeys; | ||||
|     single.value = rowKeys.length !== 1; | ||||
|     multiple.value = !rowKeys.length; | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * 导出 | ||||
|    */ | ||||
|   const handleExport = () => { | ||||
|     if (exportLoading.value) return; | ||||
|     exportLoading.value = true; | ||||
|     proxy | ||||
|       .download('/${apiModuleName}/${apiName}/export', { ...queryParams.value }, '${businessName}数据') | ||||
|       .finally(() => { | ||||
|         exportLoading.value = false; | ||||
|       }); | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * 查询 | ||||
|    */ | ||||
|   const handleQuery = () => { | ||||
|     getList(); | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * 重置 | ||||
|    */ | ||||
|   const resetQuery = () => { | ||||
|     queryFormRef.value.resetFields(); | ||||
|     handleQuery(); | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * 切换页码 | ||||
|    * | ||||
|    * @param current 页码 | ||||
|    */ | ||||
|   const handlePageChange = (current: number) => { | ||||
|     queryParams.value.page = current; | ||||
|     getList(); | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|    * 切换每页条数 | ||||
|    * | ||||
|    * @param pageSize 每页条数 | ||||
|    */ | ||||
|   const handlePageSizeChange = (pageSize: number) => { | ||||
|     queryParams.value.size = pageSize; | ||||
|     getList(); | ||||
|   }; | ||||
| </script> | ||||
|  | ||||
| <script lang="ts"> | ||||
|   export default { | ||||
|     name: '${classNamePrefix}', | ||||
|   }; | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <div class="app-container"> | ||||
|     <Breadcrumb :items="['menu.${apiModuleName}', 'menu.${apiModuleName}.${apiName}.list']" /> | ||||
|     <a-card class="general-card" :title="$t('menu.${apiModuleName}.${apiName}.list')"> | ||||
|       <!-- 头部区域 --> | ||||
|       <div class="header"> | ||||
|         <!-- 搜索栏 --> | ||||
|         <div v-if="showQuery" class="header-query"> | ||||
|           <a-form ref="queryFormRef" :model="queryParams" layout="inline"> | ||||
|             <#list fieldConfigs as fieldConfig> | ||||
|             <#if fieldConfig.showInQuery> | ||||
|             <a-form-item field="${fieldConfig.fieldName}" hide-label> | ||||
|               <a-input | ||||
|                 v-model="queryParams.${fieldConfig.fieldName}" | ||||
|                 placeholder="输入${fieldConfig.comment}搜索" | ||||
|                 allow-clear | ||||
|                 style="width: 150px" | ||||
|                 @press-enter="handleQuery" | ||||
|               /> | ||||
|             </a-form-item> | ||||
|             </#if> | ||||
|             </#list> | ||||
|             <a-form-item hide-label> | ||||
|               <a-space> | ||||
|                 <a-button type="primary" @click="handleQuery"> | ||||
|                   <template #icon><icon-search /></template>查询 | ||||
|                 </a-button> | ||||
|                 <a-button @click="resetQuery"> | ||||
|                   <template #icon><icon-refresh /></template>重置 | ||||
|                 </a-button> | ||||
|               </a-space> | ||||
|             </a-form-item> | ||||
|           </a-form> | ||||
|         </div> | ||||
|         <!-- 操作栏 --> | ||||
|         <div class="header-operation"> | ||||
|           <a-row> | ||||
|             <a-col :span="12"> | ||||
|               <a-space> | ||||
|                 <a-button | ||||
|                   v-permission="['${apiModuleName}:${apiName}:add']" | ||||
|                   type="primary" | ||||
|                   @click="toAdd" | ||||
|                 > | ||||
|                   <template #icon><icon-plus /></template>新增 | ||||
|                 </a-button> | ||||
|                 <a-button | ||||
|                   v-permission="['${apiModuleName}:${apiName}:update']" | ||||
|                   type="primary" | ||||
|                   status="success" | ||||
|                   :disabled="single" | ||||
|                   :title="single ? '请选择一条要修改的数据' : ''" | ||||
|                   @click="toUpdate(ids[0])" | ||||
|                 > | ||||
|                   <template #icon><icon-edit /></template>修改 | ||||
|                 </a-button> | ||||
|                 <a-button | ||||
|                   v-permission="['${apiModuleName}:${apiName}:delete']" | ||||
|                   type="primary" | ||||
|                   status="danger" | ||||
|                   :disabled="multiple" | ||||
|                   :title="multiple ? '请选择要删除的数据' : ''" | ||||
|                   @click="handleBatchDelete" | ||||
|                 > | ||||
|                   <template #icon><icon-delete /></template>删除 | ||||
|                 </a-button> | ||||
|                 <a-button | ||||
|                   v-permission="['${apiModuleName}:${apiName}:export']" | ||||
|                   :loading="exportLoading" | ||||
|                   type="primary" | ||||
|                   status="warning" | ||||
|                   @click="handleExport" | ||||
|                 > | ||||
|                   <template #icon><icon-download /></template>导出 | ||||
|                 </a-button> | ||||
|               </a-space> | ||||
|             </a-col> | ||||
|             <a-col :span="12"> | ||||
|               <right-toolbar | ||||
|                 v-model:show-query="showQuery" | ||||
|                 @refresh="getList" | ||||
|               /> | ||||
|             </a-col> | ||||
|           </a-row> | ||||
|         </div> | ||||
|       </div> | ||||
|  | ||||
|       <!-- 列表区域 --> | ||||
|       <a-table | ||||
|         row-key="id" | ||||
|         :data="dataList" | ||||
|         :loading="loading" | ||||
|         :row-selection="{ | ||||
|           type: 'checkbox', | ||||
|           showCheckedAll: true, | ||||
|           onlyCurrent: false, | ||||
|         }" | ||||
|         :pagination="{ | ||||
|           showTotal: true, | ||||
|           showPageSize: true, | ||||
|           total: total, | ||||
|           current: queryParams.page, | ||||
|         }" | ||||
|         :bordered="false" | ||||
|         column-resizable | ||||
|         stripe | ||||
|         size="large" | ||||
|         @page-change="handlePageChange" | ||||
|         @page-size-change="handlePageSizeChange" | ||||
|         @selection-change="handleSelectionChange" | ||||
|       > | ||||
|         <template #columns> | ||||
|           <#list fieldConfigs as fieldConfig> | ||||
|           <#if fieldConfig_index = 0> | ||||
|           <a-table-column title="${fieldConfig.comment}" data-index="${fieldConfig.fieldName}"> | ||||
|             <template #cell="{ record }"> | ||||
|               <a-link @click="toDetail(record.id)">{{ record.${fieldConfig.fieldName} }}</a-link> | ||||
|             </template> | ||||
|           </a-table-column> | ||||
|           <#else> | ||||
|           <#if fieldConfig.showInList> | ||||
|           <a-table-column title="${fieldConfig.comment}" data-index="${fieldConfig.fieldName}" /> | ||||
|           </#if> | ||||
|           </#if> | ||||
|           </#list> | ||||
|           <a-table-column | ||||
|             v-if="checkPermission(['${apiModuleName}:${apiName}:update', '${apiModuleName}:${apiName}:delete'])" | ||||
|             title="操作" | ||||
|             align="center" | ||||
|           > | ||||
|             <template #cell="{ record }"> | ||||
|               <a-button | ||||
|                 v-permission="['${apiModuleName}:${apiName}:update']" | ||||
|                 type="text" | ||||
|                 size="small" | ||||
|                 title="修改" | ||||
|                 @click="toUpdate(record.id)" | ||||
|               > | ||||
|                 <template #icon><icon-edit /></template>修改 | ||||
|               </a-button> | ||||
|               <a-popconfirm | ||||
|                 content="是否确定删除该数据?" | ||||
|                 type="warning" | ||||
|                 @ok="handleDelete([record.id])" | ||||
|               > | ||||
|                 <a-button | ||||
|                   v-permission="['${apiModuleName}:${apiName}:delete']" | ||||
|                   type="text" | ||||
|                   size="small" | ||||
|                   title="删除" | ||||
|                   :disabled="record.disabled" | ||||
|                 > | ||||
|                   <template #icon><icon-delete /></template>删除 | ||||
|                 </a-button> | ||||
|               </a-popconfirm> | ||||
|             </template> | ||||
|           </a-table-column> | ||||
|         </template> | ||||
|       </a-table> | ||||
|  | ||||
|       <!-- 表单区域 --> | ||||
|       <a-modal | ||||
|         :title="title" | ||||
|         :visible="visible" | ||||
|         :mask-closable="false" | ||||
|         :esc-to-close="false" | ||||
|         unmount-on-close | ||||
|         render-to-body | ||||
|         @ok="handleOk" | ||||
|         @cancel="handleCancel" | ||||
|       > | ||||
|         <a-form ref="formRef" :model="form" :rules="rules" size="large"> | ||||
|           <#list fieldConfigs as fieldConfig> | ||||
|           <#if fieldConfig.showInForm> | ||||
|           <a-form-item label="${fieldConfig.comment}" field="${fieldConfig.fieldName}"> | ||||
|             <#if fieldConfig.formType = 'TEXT'> | ||||
|             <a-input v-model="form.${fieldConfig.fieldName}" placeholder="请输入${fieldConfig.comment}" /> | ||||
|             <#elseif fieldConfig.formType = 'TEXT_AREA'> | ||||
|             <a-textarea | ||||
|               v-model="form.${fieldConfig.fieldName}" | ||||
|               :max-length="200" | ||||
|               placeholder="请输入${fieldConfig.comment}" | ||||
|               :auto-size="{ | ||||
|                 minRows: 3, | ||||
|               }" | ||||
|               show-word-limit | ||||
|             /> | ||||
|             <#elseif fieldConfig.formType = 'SELECT'> | ||||
|               <#--<a-select | ||||
|                 v-model="form.${fieldConfig.fieldName}" | ||||
|                 :options="${apiName}Options" | ||||
|                 placeholder="请选择${fieldConfig.comment}" | ||||
|                 :loading="${apiName}Loading" | ||||
|                 multiple | ||||
|                 allow-clear | ||||
|                 :allow-search="{ retainInputValue: true }" | ||||
|                 style="width: 416px" | ||||
|               />--> | ||||
|             <#elseif fieldConfig.formType = 'RADIO'> | ||||
|             <#--<a-radio-group v-model="form.${fieldConfig.fieldName}" type="button"> | ||||
|             </a-radio-group>--> | ||||
|             <#elseif fieldConfig.formType = 'DATE'> | ||||
|             <a-date-picker v-model="form.${fieldConfig.fieldName}" placeholder="请选择${fieldConfig.comment}"/> | ||||
|             <#elseif fieldConfig.formType = 'DATE_TIME'> | ||||
|             <a-date-picker | ||||
|               v-model="form.${fieldConfig.fieldName}" | ||||
|               placeholder="请选择${fieldConfig.comment}" | ||||
|               show-time | ||||
|               format="YYYY-MM-DD HH:mm:ss" | ||||
|             /> | ||||
|             </#if> | ||||
|           </a-form-item> | ||||
|           </#if> | ||||
|           </#list> | ||||
|         </a-form> | ||||
|       </a-modal> | ||||
|  | ||||
|       <!-- 详情区域 --> | ||||
|       <a-drawer | ||||
|         title="${businessName}详情" | ||||
|         :visible="detailVisible" | ||||
|         :width="580" | ||||
|         :footer="false" | ||||
|         unmount-on-close | ||||
|         render-to-body | ||||
|         @cancel="handleDetailCancel" | ||||
|       > | ||||
|         <a-descriptions :column="2" bordered size="large"> | ||||
|           <#list fieldConfigs as fieldConfig> | ||||
|           <a-descriptions-item label="${fieldConfig.comment}"> | ||||
|             <a-skeleton v-if="detailLoading" :animation="true"> | ||||
|               <a-skeleton-line :rows="1" /> | ||||
|             </a-skeleton> | ||||
|             <#if fieldConfig.fieldName = 'createUser'> | ||||
|             <span v-else>{{ dataDetail.createUserString }}</span> | ||||
|             <#elseif fieldConfig.fieldName = 'updateUser'> | ||||
|             <span v-else>{{ dataDetail.updateUserString }}</span> | ||||
|             <#else> | ||||
|             <span v-else>{{ dataDetail.${fieldConfig.fieldName} }}</span> | ||||
|             </#if> | ||||
|           </a-descriptions-item> | ||||
|           </#list> | ||||
|         </a-descriptions> | ||||
|       </a-drawer> | ||||
|     </a-card> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="less"></style> | ||||
		Reference in New Issue
	
	Block a user