Przeglądaj źródła

新增代码生成详情页功能

RuoYi 2 miesięcy temu
rodzic
commit
290f7b4cd9

+ 3 - 0
ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java

@@ -31,6 +31,9 @@ public class GenConstants
     /** 上级菜单名称字段 */
     public static final String PARENT_MENU_NAME = "parentMenuName";
 
+    /** 生成详情页开关 */
+    public static final String GEN_VIEW = "genView";
+
     /** 数据库字符串类型 */
     public static final String[] COLUMNTYPE_STR = { "char", "varchar", "nvarchar", "varchar2" };
 

+ 13 - 0
ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java

@@ -101,6 +101,9 @@ public class GenTable extends BaseEntity
     /** 上级菜单名称字段 */
     private String parentMenuName;
 
+    /** 是否生成详情页 */
+    private boolean isView;
+
     public Long getTableId()
     {
         return tableId;
@@ -351,6 +354,16 @@ public class GenTable extends BaseEntity
         this.parentMenuName = parentMenuName;
     }
 
+    public boolean isView()
+    {
+        return isView;
+    }
+
+    public void setView(boolean isView)
+    {
+        this.isView = isView;
+    }
+
     public boolean isSub()
     {
         return isSub(this.tplCategory);

+ 6 - 4
ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java

@@ -219,7 +219,7 @@ public class GenTableServiceImpl implements IGenTableService
         VelocityContext context = VelocityUtils.prepareContext(table);
 
         // 获取模板列表
-        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory(), table.getTplWebType());
+        List<String> templates = VelocityUtils.getTemplateList(table);
         for (String template : templates)
         {
             // 渲染模板
@@ -263,10 +263,10 @@ public class GenTableServiceImpl implements IGenTableService
         VelocityContext context = VelocityUtils.prepareContext(table);
 
         // 获取模板列表
-        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory(), table.getTplWebType());
+        List<String> templates = VelocityUtils.getTemplateList(table);
         for (String template : templates)
         {
-            if (!StringUtils.containsAny(template, "sql.vm", "api.js.vm", "index.vue.vm", "index-tree.vue.vm"))
+            if (!StringUtils.containsAny(template, "sql.vm", "api.js.vm", "api.ts.vm", "type.ts.vm", "index.ts.vm", "index.vue.vm", "index-tree.vue.vm", "view.vue.vm"))
             {
                 // 渲染模板
                 StringWriter sw = new StringWriter();
@@ -381,7 +381,7 @@ public class GenTableServiceImpl implements IGenTableService
         VelocityContext context = VelocityUtils.prepareContext(table);
 
         // 获取模板列表
-        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory(), table.getTplWebType());
+        List<String> templates = VelocityUtils.getTemplateList(table);
         for (String template : templates)
         {
             // 渲染模板
@@ -534,12 +534,14 @@ public class GenTableServiceImpl implements IGenTableService
             String treeName = paramsObj.getString(GenConstants.TREE_NAME);
             Long parentMenuId = paramsObj.getLongValue(GenConstants.PARENT_MENU_ID);
             String parentMenuName = paramsObj.getString(GenConstants.PARENT_MENU_NAME);
+            boolean isView = paramsObj.getBooleanValue(GenConstants.GEN_VIEW);
 
             genTable.setTreeCode(treeCode);
             genTable.setTreeParentCode(treeParentCode);
             genTable.setTreeName(treeName);
             genTable.setParentMenuId(parentMenuId);
             genTable.setParentMenuName(parentMenuName);
+            genTable.setView(isView);
         }
     }
 

+ 36 - 1
ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java

@@ -68,6 +68,7 @@ public class VelocityUtils
         velocityContext.put("columns", genTable.getColumns());
         velocityContext.put("table", genTable);
         velocityContext.put("dicts", getDicts(genTable));
+        setExtensionsContext(velocityContext, genTable.getOptions());
         setMenuVelocityContext(velocityContext, genTable);
         if (GenConstants.TPL_TREE.equals(tplCategory))
         {
@@ -80,6 +81,13 @@ public class VelocityUtils
         return velocityContext;
     }
 
+    public static void setExtensionsContext(VelocityContext context, String options)
+    {
+        JSONObject paramsObj = JSONObject.parseObject(options);
+        boolean genView = genView(paramsObj);
+        context.put("genView", genView);
+    }
+
     public static void setMenuVelocityContext(VelocityContext context, GenTable genTable)
     {
         String options = genTable.getOptions();
@@ -134,8 +142,12 @@ public class VelocityUtils
      * @param tplWebType 前端类型
      * @return 模板列表
      */
-    public static List<String> getTemplateList(String tplCategory, String tplWebType)
+    public static List<String> getTemplateList(GenTable table)
     {
+        String tplWebType = table.getTplWebType();
+        String tplCategory = table.getTplCategory();
+        JSONObject paramsObj = JSONObject.parseObject(table.getOptions());
+        boolean isView = genView(paramsObj);
         String useWebType = "vm/vue";
         String apiTemplate = "vm/js/api.js.vm";
         if (StringUtils.equals(ELEMENT_PLUS, tplWebType))
@@ -174,6 +186,10 @@ public class VelocityUtils
             templates.add(useWebType + "/index.vue.vm");
             templates.add("vm/java/sub-domain.java.vm");
         }
+        if (isView)
+        {
+            templates.add(useWebType + "/view.vue.vm");
+        }
         return templates;
     }
 
@@ -253,6 +269,10 @@ public class VelocityUtils
         {
             fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName);
         }
+        else if (template.contains("view.vue.vm"))
+        {
+            fileName = StringUtils.format("{}/views/{}/{}/view.vue", vuePath, moduleName, businessName);
+        }
         return fileName;
     }
 
@@ -395,6 +415,21 @@ public class VelocityUtils
     }
 
     /**
+     * 扩展功能/生成详情页
+     * 
+     * @param paramsObj 生成其他选项
+     * @return 是否生成详细页
+     */
+    public static boolean genView(JSONObject paramsObj)
+    {
+        if (StringUtils.isNotNull(paramsObj) && paramsObj.containsKey(GenConstants.GEN_VIEW))
+        {
+            return paramsObj.getBoolean(GenConstants.GEN_VIEW);
+        }
+        return false;
+    }
+
+    /**
      * 获取树名称
      *
      * @param paramsObj 生成其他选项

+ 25 - 0
ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm

@@ -139,6 +139,15 @@
 #end
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
+#if($genView)
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-view"
+            @click="handleViewData(scope.row)"
+            v-hasPermi="['${permissionPrefix}:query']"
+          >详情</el-button>
+#end
           <el-button
             size="mini"
             type="text"
@@ -164,6 +173,10 @@
       </el-table-column>
     </el-table>
 
+#if($genView)
+    <!-- ${functionName}详情抽屉 -->
+    <${businessName}-view-drawer ref="${businessName}ViewRef" />
+#end
     <!-- 添加或修改${functionName}对话框 -->
 #if($table.formColNum == 2)
 #set($dialogWidth = "800px")
@@ -319,6 +332,9 @@
 
 <script>
 import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"
+#if($genView)
+import ${BusinessName}ViewDrawer from "./view"
+#end
 import Treeselect from "@riophae/vue-treeselect"
 import "@riophae/vue-treeselect/dist/vue-treeselect.css"
 
@@ -328,6 +344,9 @@ export default {
   dicts: [${dicts}],
 #end
   components: {
+#if($genView)
+    ${BusinessName}ViewDrawer,
+#end
     Treeselect
   },
   data() {
@@ -483,6 +502,12 @@ export default {
         this.refreshTable = true
       })
     },
+#if($genView)
+    /** 详情按钮操作 */
+    handleViewData(row) {
+      this.#[[$]]#refs["${businessName}ViewRef"].open(row.${pkColumn.javaField})
+    },
+#end
     /** 修改按钮操作 */
     handleUpdate(row) {
       this.reset()

+ 25 - 0
ruoyi-generator/src/main/resources/vm/vue/index.vue.vm

@@ -153,6 +153,15 @@
 #end
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
+#if($genView)
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-view"
+            @click="handleViewData(scope.row)"
+            v-hasPermi="['${permissionPrefix}:query']"
+          >详情</el-button>
+#end
           <el-button
             size="mini"
             type="text"
@@ -179,6 +188,10 @@
       @pagination="getList"
     />
 
+#if($genView)
+    <!-- ${functionName}详情抽屉 -->
+    <${businessName}-view-drawer ref="${businessName}ViewRef" />
+#end
     <!-- 添加或修改${functionName}对话框 -->
 #if($table.formColNum == 2)
 #set($dialogWidth = "800px")
@@ -387,9 +400,15 @@
 
 <script>
 import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"
+#if($genView)
+import ${BusinessName}ViewDrawer from "./view"
+#end
 
 export default {
   name: "${BusinessName}",
+#if($genView)
+  components: { ${BusinessName}ViewDrawer },
+#end
 #if(${dicts} != '')
   dicts: [${dicts}],
 #end
@@ -624,6 +643,12 @@ export default {
       this.checked${subClassName} = selection.map(item => item.index)
     },
 #end
+#if($genView)
+    /** 详情按钮操作 */
+    handleViewData(row) {
+      this.#[[$]]#refs["${businessName}ViewRef"].open(row.${pkColumn.javaField})
+    },
+#end
     /** 导出按钮操作 */
     handleExport() {
       this.download('${moduleName}/${businessName}/export', {

+ 20 - 3
ruoyi-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm

@@ -136,6 +136,9 @@
 #end
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template #default="scope">
+#if($genView)
+          <el-button link type="primary" icon="View" @click="handleViewData(scope.row)" v-hasPermi="['${permissionPrefix}:query']">详情</el-button>
+#end
           <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['${permissionPrefix}:edit']">修改</el-button>
           <el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['${permissionPrefix}:add']">新增</el-button>
           <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['${permissionPrefix}:remove']">删除</el-button>
@@ -143,6 +146,10 @@
       </el-table-column>
     </el-table>
 
+#if($genView)
+    <!-- ${functionName}详情抽屉 -->
+    <${businessName}-view-drawer ref="${businessName}ViewRef" />
+#end
     <!-- 添加或修改${functionName}对话框 -->
 #if($table.formColNum == 2)
 #set($dialogWidth = "800px")
@@ -307,6 +314,9 @@
 
 <script setup name="${BusinessName}">
 import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"
+#if($genView)
+import ${BusinessName}ViewDrawer from "./view"
+#end
 
 const { proxy } = getCurrentInstance()
 #if(${dicts} != '')
@@ -334,7 +344,7 @@ const data = reactive({
   queryParams: {
     #foreach ($column in $columns)
 #if($column.query)
-    $column.javaField: null#if($foreach.count != $columns.size()),#end
+    $column.javaField: undefined#if($foreach.count != $columns.size()),#end
 #end
 #end
   },
@@ -391,13 +401,13 @@ function getTreeselect() {
   })
 }
 	
-// 取消按钮
+/** 取消按钮 */
 function cancel() {
   open.value = false
   reset()
 }
 
-// 表单重置
+/** 表单重置 */
 function reset() {
   form.value = {
 #foreach ($column in $columns)
@@ -449,6 +459,13 @@ function toggleExpandAll() {
     refreshTable.value = true
   })
 }
+#if($genView)
+
+/** 详情按钮操作 */
+function handleViewData(row) {
+  proxy.#[[$]]#refs["${businessName}ViewRef"].open(row.${pkColumn.javaField})
+}
+#end
 
 /** 修改按钮操作 */
 async function handleUpdate(row) {

+ 22 - 5
ruoyi-generator/src/main/resources/vm/vue/v3/index.vue.vm

@@ -148,6 +148,9 @@
 #end
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template #default="scope">
+#if($genView)
+          <el-button link type="primary" icon="View" @click="handleViewData(scope.row)" v-hasPermi="['${permissionPrefix}:query']">详情</el-button>
+#end
           <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['${permissionPrefix}:edit']">修改</el-button>
           <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['${permissionPrefix}:remove']">删除</el-button>
         </template>
@@ -162,6 +165,10 @@
       @pagination="getList"
     />
 
+#if($genView)
+    <!-- ${functionName}详情抽屉 -->
+    <${businessName}-view-drawer ref="${businessName}ViewRef" />
+#end
     <!-- 添加或修改${functionName}对话框 -->
 #if($table.formColNum == 2)
 #set($dialogWidth = "800px")
@@ -381,6 +388,9 @@
 
 <script setup name="${BusinessName}">
 import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"
+#if($genView)
+import ${BusinessName}ViewDrawer from "./view"
+#end
 
 const { proxy } = getCurrentInstance()
 #if(${dicts} != '')
@@ -417,7 +427,7 @@ const data = reactive({
     pageSize: 10,
     #foreach ($column in $columns)
 #if($column.query)
-    $column.javaField: null#if($foreach.count != $columns.size()),#end
+    $column.javaField: undefined#if($foreach.count != $columns.size()),#end
 #end
 #end
   },
@@ -465,13 +475,13 @@ function getList() {
   })
 }
 
-// 取消按钮
+/** 取消按钮 */
 function cancel() {
   open.value = false
   reset()
 }
 
-// 表单重置
+/** 表单重置 */
 function reset() {
   form.value = {
 #foreach ($column in $columns)
@@ -506,7 +516,7 @@ function resetQuery() {
   handleQuery()
 }
 
-// 多选框选中数据
+/** 多选框选中数据 */
 function handleSelectionChange(selection) {
   ids.value = selection.map(item => item.${pkColumn.javaField})
   single.value = selection.length != 1
@@ -586,7 +596,7 @@ function handleAdd${subClassName}() {
 #foreach($column in $subTable.columns)
 #if($column.pk || $column.javaField == ${subTableFkclassName})
 #elseif($column.list && "" != $javaField)
-  obj.$column.javaField = ""
+  obj.$column.javaField = undefined
 #end
 #end
   ${subclassName}List.value.push(obj)
@@ -611,6 +621,13 @@ function handle${subClassName}SelectionChange(selection) {
 }
 
 #end
+#if($genView)
+/** 详情按钮操作 */
+function handleViewData(row) {
+  proxy.#[[$]]#refs["${businessName}ViewRef"].open(row.${pkColumn.javaField})
+}
+
+#end
 /** 导出按钮操作 */
 function handleExport() {
   proxy.download('${moduleName}/${businessName}/export', {

+ 83 - 0
ruoyi-generator/src/main/resources/vm/vue/v3/view.vue.vm

@@ -0,0 +1,83 @@
+<template>
+  <el-drawer title="${functionName}详情" v-model="visible" direction="rtl" size="60%" append-to-body :before-close="handleClose" class="detail-drawer">
+    <div v-loading="loading" class="drawer-content">
+      <h4 class="section-header">基本信息</h4>
+#set($i = 0)
+#foreach($column in $columns)
+#if(!$column.pk && $column.list)
+#set($dictType=$column.dictType)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($i % 2 == 0)
+      <el-row :gutter="20" class="mb8">
+#end
+        <el-col :span="12">
+          <div class="info-item">
+            <label class="info-label">${comment}:</label>
+            <span class="info-value plaintext">
+#if("" != $dictType)
+#if($column.htmlType == "checkbox")
+              <dict-tag :options="${dictType}" :value="info.${javaField} ? info.${javaField}.split(',') : []" />
+#else
+              <dict-tag :options="${dictType}" :value="info.${javaField}" />
+#end
+#elseif($column.htmlType == "datetime")
+              {{ parseTime(info.${javaField}, '{y}-{m}-{d}') }}
+#elseif($column.htmlType == "imageUpload")
+              <image-preview :src="info.${javaField}" :width="60" :height="60" />
+#else
+              {{ info.${javaField} }}
+#end
+            </span>
+          </div>
+        </el-col>
+#set($i = $i + 1)
+#if($i % 2 == 0)
+      </el-row>
+#end
+#end
+#end
+#if($i % 2 != 0)
+      </el-row>
+#end
+    </div>
+  </el-drawer>
+</template>
+
+<script setup name="${BusinessName}ViewDrawer">
+import { get${BusinessName} } from '@/api/${moduleName}/${businessName}'
+
+#if(${dicts} != '')
+#set($dictsNoSymbol=$dicts.replace("'", ""))
+const { ${dictsNoSymbol} } = useDict(${dicts})
+#end
+
+const visible = ref(false)
+const loading = ref(false)
+const info = reactive({})
+
+const open = async (${pkColumn.javaField}) => {
+  visible.value = true
+  loading.value = true
+  try {
+    const res = await get${BusinessName}(${pkColumn.javaField})
+    Object.assign(info, res.data || {})
+  } catch (error) {
+    console.error('获取${functionName}信息失败:', error)
+  } finally {
+    loading.value = false
+  }
+}
+
+function handleClose() {
+  visible.value = false
+  Object.keys(info).forEach(key => delete info[key])
+}
+
+defineExpose({ open })
+</script>

+ 19 - 2
ruoyi-generator/src/main/resources/vm/vue/v3ts/index-tree.vue.vm

@@ -136,6 +136,9 @@
 #end
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template #default="scope">
+#if($genView)
+          <el-button link type="primary" icon="View" @click="handleViewData(scope.row)" v-hasPermi="['${permissionPrefix}:query']">详情</el-button>
+#end
           <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['${permissionPrefix}:edit']">修改</el-button>
           <el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['${permissionPrefix}:add']">新增</el-button>
           <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['${permissionPrefix}:remove']">删除</el-button>
@@ -143,6 +146,10 @@
       </el-table-column>
     </el-table>
 
+#if($genView)
+    <!-- ${functionName}详情抽屉 -->
+    <${businessName}-view-drawer ref="${businessName}ViewRef" />
+#end
     <!-- 添加或修改${functionName}对话框 -->
 #if($table.formColNum == 2)
 #set($dialogWidth = "800px")
@@ -307,6 +314,9 @@
 
 <script setup lang="ts" name="${BusinessName}">
 import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"
+#if($genView)
+import ${BusinessName}ViewDrawer from "./view"
+#end
 import type { ${ClassName}, ${BusinessName}QueryParams } from "@/types/api/${moduleName}/${businessName}"
 import type { TreeSelect } from '@/types/api/common'
 
@@ -393,13 +403,13 @@ function getTreeselect() {
   })
 }
 	
-// 取消按钮
+/** 取消按钮 */
 function cancel() {
   open.value = false
   reset()
 }
 
-// 表单重置
+/** 表单重置 */
 function reset() {
   form.value = {
 #foreach ($column in $columns)
@@ -451,6 +461,13 @@ function toggleExpandAll() {
     refreshTable.value = true
   })
 }
+#if($genView)
+
+/** 详情按钮操作 */
+function handleViewData(row: ${ClassName}) {
+  proxy.#[[$]]#refs["${businessName}ViewRef"].open(row.${pkColumn.javaField})
+}
+#end
 
 /** 修改按钮操作 */
 async function handleUpdate(row: ${ClassName}) {

+ 21 - 4
ruoyi-generator/src/main/resources/vm/vue/v3ts/index.vue.vm

@@ -148,6 +148,9 @@
 #end
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template #default="scope">
+#if($genView)
+          <el-button link type="primary" icon="View" @click="handleViewData(scope.row)" v-hasPermi="['${permissionPrefix}:query']">详情</el-button>
+#end
           <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['${permissionPrefix}:edit']">修改</el-button>
           <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['${permissionPrefix}:remove']">删除</el-button>
         </template>
@@ -162,6 +165,10 @@
       @pagination="getList"
     />
 
+#if($genView)
+    <!-- ${functionName}详情抽屉 -->
+    <${businessName}-view-drawer ref="${businessName}ViewRef" />
+#end
     <!-- 添加或修改${functionName}对话框 -->
 #if($table.formColNum == 2)
 #set($dialogWidth = "800px")
@@ -379,13 +386,16 @@
   </div>
 </template>
 
-<script setup lang="ts" name="Config">
+<script setup lang="ts" name="${BusinessName}">
 #if($table.sub)
 import type { ${ClassName}, ${subClassName}, ${BusinessName}QueryParams } from "@/types/api/${moduleName}/${businessName}"
 #else
 import type { ${ClassName}, ${BusinessName}QueryParams } from "@/types/api/${moduleName}/${businessName}"
 #end
 import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"
+#if($genView)
+import ${BusinessName}ViewDrawer from "./view"
+#end
 
 const { proxy } = getCurrentInstance()
 #if(${dicts} != '')
@@ -470,13 +480,13 @@ function getList() {
   })
 }
 
-// 取消按钮
+/** 取消按钮 */
 function cancel() {
   open.value = false
   reset()
 }
 
-// 表单重置
+/** 表单重置 */
 function reset() {
   form.value = {
 #foreach ($column in $columns)
@@ -511,7 +521,7 @@ function resetQuery() {
   handleQuery()
 }
 
-// 多选框选中数据
+/** 多选框选中数据 */
 function handleSelectionChange(selection: ${ClassName}[]) {
   ids.value = selection.map(item => item.${pkColumn.javaField})
   single.value = selection.length != 1
@@ -616,6 +626,13 @@ function handle${subClassName}SelectionChange(selection: any[]) {
 }
 
 #end
+#if($genView)
+/** 详情按钮操作 */
+function handleViewData(row: ${ClassName}) {
+  proxy.#[[$]]#refs["${businessName}ViewRef"].open(row.${pkColumn.javaField})
+}
+
+#end
 /** 导出按钮操作 */
 function handleExport() {
   proxy.download('${moduleName}/${businessName}/export', {

+ 84 - 0
ruoyi-generator/src/main/resources/vm/vue/v3ts/view.vue.vm

@@ -0,0 +1,84 @@
+<template>
+  <el-drawer title="${functionName}详情" v-model="visible" direction="rtl" size="60%" append-to-body :before-close="handleClose" class="detail-drawer">
+    <div v-loading="loading" class="drawer-content">
+      <h4 class="section-header">基本信息</h4>
+#set($i = 0)
+#foreach($column in $columns)
+#if(!$column.pk && $column.list)
+#set($dictType=$column.dictType)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($i % 2 == 0)
+      <el-row :gutter="20" class="mb8">
+#end
+        <el-col :span="12">
+          <div class="info-item">
+            <label class="info-label">${comment}:</label>
+            <span class="info-value plaintext">
+#if("" != $dictType)
+#if($column.htmlType == "checkbox")
+              <dict-tag :options="${dictType}" :value="info.${javaField} ? info.${javaField}.split(',') : []" />
+#else
+              <dict-tag :options="${dictType}" :value="info.${javaField}" />
+#end
+#elseif($column.htmlType == "datetime")
+              {{ parseTime(info.${javaField}, '{y}-{m}-{d}') }}
+#elseif($column.htmlType == "imageUpload")
+              <image-preview :src="info.${javaField}" :width="60" :height="60" />
+#else
+              {{ info.${javaField} }}
+#end
+            </span>
+          </div>
+        </el-col>
+#set($i = $i + 1)
+#if($i % 2 == 0)
+      </el-row>
+#end
+#end
+#end
+#if($i % 2 != 0)
+      </el-row>
+#end
+    </div>
+  </el-drawer>
+</template>
+
+<script setup lang="ts" name="${BusinessName}ViewDrawer">
+import type { ${ClassName} } from "@/types/api/${moduleName}/${businessName}"
+import { get${BusinessName} } from '@/api/${moduleName}/${businessName}'
+#if(${dicts} != '')
+#set($dictsNoSymbol=$dicts.replace("'", ""))
+
+const { ${dictsNoSymbol} } = useDict(${dicts})
+#end
+
+const visible = ref<boolean>(false)
+const loading = ref<boolean>(false)
+const info = reactive<Partial<${ClassName}>>({})
+
+const open = async (#if($pkColumn.javaType == "Long" || $pkColumn.javaType == "Integer")${pkColumn.javaField}: number#else${pkColumn.javaField}: string#end): Promise<void> => {
+  visible.value = true
+  loading.value = true
+  try {
+    const res = await get${BusinessName}(${pkColumn.javaField})
+    Object.assign(info, res.data ?? {})
+  } catch (error) {
+    console.error('获取${functionName}信息失败:', error)
+  } finally {
+    loading.value = false
+  }
+}
+
+const handleClose = (): void => {
+  visible.value = false
+  Object.keys(info).forEach(key => delete (info as any)[key])
+}
+
+defineExpose({ open })
+</script>

+ 86 - 0
ruoyi-generator/src/main/resources/vm/vue/view.vue.vm

@@ -0,0 +1,86 @@
+<template>
+  <el-drawer title="${functionName}详情" :visible.sync="visible" direction="rtl" size="60%" append-to-body :before-close="handleClose" custom-class="detail-drawer">
+    <div v-loading="loading" class="drawer-content">
+      <h4 class="section-header">基本信息</h4>
+#set($i = 0)
+#foreach($column in $columns)
+#if(!$column.pk && $column.list)
+#set($dictType=$column.dictType)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($i % 2 == 0)
+      <el-row :gutter="20" class="mb8">
+#end
+        <el-col :span="12">
+          <div class="info-item">
+            <label class="info-label">${comment}:</label>
+            <span class="info-value plaintext">
+#if("" != $dictType)
+#if($column.htmlType == "checkbox")
+              <dict-tag :options="dict.type.${dictType}" :value="info.${javaField} ? info.${javaField}.split(',') : []" />
+#else
+              <dict-tag :options="dict.type.${dictType}" :value="info.${javaField}" />
+#end
+#elseif($column.htmlType == "datetime")
+              {{ parseTime(info.${javaField}, '{y}-{m}-{d}') }}
+#else
+              {{ info.${javaField} }}
+#end
+            </span>
+          </div>
+        </el-col>
+#set($i = $i + 1)
+#if($i % 2 == 0)
+      </el-row>
+#end
+#end
+#end
+#if($i % 2 != 0)
+      </el-row>
+#end
+    </div>
+  </el-drawer>
+</template>
+
+<script>
+import { get${BusinessName} } from '@/api/${moduleName}/${businessName}'
+
+export default {
+  name: '${BusinessName}ViewDrawer',
+#foreach($column in $columns)
+#if("" != $column.dictType)
+#set($hasDicts = true)
+#break
+#end
+#end
+#if($hasDicts)
+  dicts: [#foreach($column in $columns)#if("" != $column.dictType)'${column.dictType}'#if($foreach.hasNext), #end#end#end],
+#end
+  data() {
+    return {
+      visible: false,
+      loading: false,
+      info: {}
+    }
+  },
+  methods: {
+    open(${pkColumn.javaField}) {
+      this.visible = true
+      this.loading = true
+      get${BusinessName}(${pkColumn.javaField}).then(res => {
+        this.info = res.data || {}
+      }).finally(() => {
+        this.loading = false
+      })
+    },
+    handleClose() {
+      this.visible = false
+    }
+  }
+}
+</script>

+ 1 - 0
ruoyi-ui/src/views/tool/gen/editTable.vue

@@ -183,6 +183,7 @@ export default {
           const genTable = Object.assign({}, basicForm.model, genForm.model)
           genTable.columns = this.columns
           genTable.params = {
+            genView: genTable.view ? '1' : '0',
             treeCode: genTable.treeCode,
             treeName: genTable.treeName,
             treeParentCode: genTable.treeParentCode,

+ 8 - 1
ruoyi-ui/src/views/tool/gen/genInfoForm.vue

@@ -69,7 +69,7 @@
         </el-form-item>
       </el-col>
 
-      <el-col :span="24">
+      <el-col :span="12">
         <el-form-item prop="formColNum">
           <span slot="label">
             表单布局
@@ -86,6 +86,13 @@
       </el-col>
 
       <el-col :span="12">
+        <el-form-item prop="genView">
+          <span slot="label">扩展功能</span>
+          <el-checkbox v-model="info.view">生成详情页</el-checkbox>
+        </el-form-item>
+      </el-col>
+
+      <el-col :span="12">
         <el-form-item prop="genType">
           <span slot="label">
             生成代码方式