RuoYi
2026-04-12 790736c98d8a7d6d1194d1e642946bc8219edcfb
新增代码生成详情页功能
3 files added
12 files modified
474 ■■■■■ changed files
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/GenConstants.java 3 ●●●●● patch | view | raw | blame | history
ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/domain/GenTable.java 13 ●●●●● patch | view | raw | blame | history
ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/GenTableServiceImpl.java 10 ●●●●● patch | view | raw | blame | history
ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/VelocityUtils.java 39 ●●●●● patch | view | raw | blame | history
ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index-tree.vue.vm 25 ●●●●● patch | view | raw | blame | history
ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index.vue.vm 25 ●●●●● patch | view | raw | blame | history
ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/index-tree.vue.vm 23 ●●●● patch | view | raw | blame | history
ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/index.vue.vm 27 ●●●● patch | view | raw | blame | history
ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/view.vue.vm 83 ●●●●● patch | view | raw | blame | history
ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3ts/index-tree.vue.vm 21 ●●●●● patch | view | raw | blame | history
ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3ts/index.vue.vm 25 ●●●● patch | view | raw | blame | history
ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3ts/view.vue.vm 84 ●●●●● patch | view | raw | blame | history
ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/view.vue.vm 86 ●●●●● patch | view | raw | blame | history
ruoyi-ui/src/views/tool/gen/editTable.vue 1 ●●●● patch | view | raw | blame | history
ruoyi-ui/src/views/tool/gen/genInfoForm.vue 9 ●●●● patch | view | raw | blame | history
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/GenConstants.java
@@ -31,6 +31,9 @@
    /** 上级菜单名称字段 */
    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" };
ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/domain/GenTable.java
@@ -101,6 +101,9 @@
    /** 上级菜单名称字段 */
    private String parentMenuName;
    /** 是否生成详情页 */
    private boolean isView;
    public Long getTableId()
    {
        return tableId;
@@ -351,6 +354,16 @@
        this.parentMenuName = parentMenuName;
    }
    public boolean isView()
    {
        return isView;
    }
    public void setView(boolean isView)
    {
        this.isView = isView;
    }
    public boolean isSub()
    {
        return isSub(this.tplCategory);
ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/GenTableServiceImpl.java
@@ -209,7 +209,7 @@
        VelocityContext context = VelocityUtils.prepareContext(table);
        // 获取模板列表
        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory(), table.getTplWebType());
        List<String> templates = VelocityUtils.getTemplateList(table);
        for (String template : templates)
        {
            // 渲染模板
@@ -253,10 +253,10 @@
        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();
@@ -371,7 +371,7 @@
        VelocityContext context = VelocityUtils.prepareContext(table);
        // 获取模板列表
        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory(), table.getTplWebType());
        List<String> templates = VelocityUtils.getTemplateList(table);
        for (String template : templates)
        {
            // 渲染模板
@@ -524,12 +524,14 @@
            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);
        }
    }
ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/VelocityUtils.java
@@ -14,7 +14,7 @@
import com.ruoyi.gen.domain.GenTableColumn;
/**
 * 模板工具类
 * 模板处理工具类
 * 
 * @author ruoyi
 */
@@ -68,6 +68,7 @@
        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))
        {
@@ -78,6 +79,13 @@
            setSubVelocityContext(velocityContext, genTable);
        }
        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)
@@ -134,8 +142,12 @@
     * @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))
@@ -173,6 +185,10 @@
        {
            templates.add(useWebType + "/index.vue.vm");
            templates.add("vm/java/sub-domain.java.vm");
        }
        if (isView)
        {
            templates.add(useWebType + "/view.vue.vm");
        }
        return templates;
    }
@@ -252,6 +268,10 @@
        else if (template.contains("index-tree.vue.vm"))
        {
            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 @@
    }
    /**
     * 扩展功能/生成详情页
     *
     * @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 生成其他选项
ruoyi-modules/ruoyi-gen/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 @@
  dicts: [${dicts}],
#end
  components: {
#if($genView)
    ${BusinessName}ViewDrawer,
#end
    Treeselect
  },
  data() {
@@ -483,6 +502,12 @@
        this.refreshTable = true
      })
    },
#if($genView)
    /** 详情按钮操作 */
    handleViewData(row) {
      this.#[[$]]#refs["${businessName}ViewRef"].open(row.${pkColumn.javaField})
    },
#end
    /** 修改按钮操作 */
    handleUpdate(row) {
      this.reset()
ruoyi-modules/ruoyi-gen/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 @@
      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', {
ruoyi-modules/ruoyi-gen/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 @@
  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 cancel() {
  open.value = false
  reset()
}
// 表单重置
/** 表单重置 */
function reset() {
  form.value = {
#foreach ($column in $columns)
@@ -449,6 +459,13 @@
    refreshTable.value = true
  })
}
#if($genView)
/** 详情按钮操作 */
function handleViewData(row) {
  proxy.#[[$]]#refs["${businessName}ViewRef"].open(row.${pkColumn.javaField})
}
#end
/** 修改按钮操作 */
async function handleUpdate(row) {
ruoyi-modules/ruoyi-gen/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 @@
    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 cancel() {
  open.value = false
  reset()
}
// 表单重置
/** 表单重置 */
function reset() {
  form.value = {
#foreach ($column in $columns)
@@ -506,7 +516,7 @@
  handleQuery()
}
// 多选框选中数据
/** 多选框选中数据 */
function handleSelectionChange(selection) {
  ids.value = selection.map(item => item.${pkColumn.javaField})
  single.value = selection.length != 1
@@ -586,7 +596,7 @@
#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 @@
}
#end
#if($genView)
/** 详情按钮操作 */
function handleViewData(row) {
  proxy.#[[$]]#refs["${businessName}ViewRef"].open(row.${pkColumn.javaField})
}
#end
/** 导出按钮操作 */
function handleExport() {
  proxy.download('${moduleName}/${businessName}/export', {
ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/view.vue.vm
New file
@@ -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>
ruoyi-modules/ruoyi-gen/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 cancel() {
  open.value = false
  reset()
}
// 表单重置
/** 表单重置 */
function reset() {
  form.value = {
#foreach ($column in $columns)
@@ -451,6 +461,13 @@
    refreshTable.value = true
  })
}
#if($genView)
/** 详情按钮操作 */
function handleViewData(row: ${ClassName}) {
  proxy.#[[$]]#refs["${businessName}ViewRef"].open(row.${pkColumn.javaField})
}
#end
/** 修改按钮操作 */
async function handleUpdate(row: ${ClassName}) {
ruoyi-modules/ruoyi-gen/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 cancel() {
  open.value = false
  reset()
}
// 表单重置
/** 表单重置 */
function reset() {
  form.value = {
#foreach ($column in $columns)
@@ -511,7 +521,7 @@
  handleQuery()
}
// 多选框选中数据
/** 多选框选中数据 */
function handleSelectionChange(selection: ${ClassName}[]) {
  ids.value = selection.map(item => item.${pkColumn.javaField})
  single.value = selection.length != 1
@@ -616,6 +626,13 @@
}
#end
#if($genView)
/** 详情按钮操作 */
function handleViewData(row: ${ClassName}) {
  proxy.#[[$]]#refs["${businessName}ViewRef"].open(row.${pkColumn.javaField})
}
#end
/** 导出按钮操作 */
function handleExport() {
  proxy.download('${moduleName}/${businessName}/export', {
ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3ts/view.vue.vm
New file
@@ -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>
ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/view.vue.vm
New file
@@ -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>
ruoyi-ui/src/views/tool/gen/editTable.vue
@@ -183,6 +183,7 @@
          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,
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">
            生成代码方式