فهرست منبع

基本完成代码生成器

YunaiV 4 سال پیش
والد
کامیت
0c8f92fa95
21فایلهای تغییر یافته به همراه411 افزوده شده و 105 حذف شده
  1. 2 2
      ruoyi-ui/src/api/tool/testDemo.js
  2. 1 1
      ruoyi-ui/src/utils/ruoyi.js
  3. 3 7
      ruoyi-ui/src/views/system/menu/index.vue
  4. 4 2
      ruoyi-ui/src/views/tool/gen/editTable.vue
  5. 15 21
      ruoyi-ui/src/views/tool/gen/genInfoForm.vue
  6. 294 0
      ruoyi-ui/src/views/tool/testDemo/index.vue
  7. 7 2
      src/main/java/cn/iocoder/dashboard/framework/excel/core/convert/DictConvert.java
  8. 0 1
      src/main/java/cn/iocoder/dashboard/framework/excel/core/package-info.java
  9. 4 3
      src/main/java/cn/iocoder/dashboard/modules/system/controller/permission/vo/menu/SysMenuBaseVO.java
  10. 0 1
      src/main/java/cn/iocoder/dashboard/modules/tool/controller/codegen/ToolCodegenController.java
  11. 3 4
      src/main/java/cn/iocoder/dashboard/modules/tool/controller/codegen/vo/table/ToolCodegenTableBaseVO.java
  12. 22 11
      src/main/java/cn/iocoder/dashboard/modules/tool/controller/test/ToolTestDemoController.java
  13. 5 4
      src/main/java/cn/iocoder/dashboard/modules/tool/controller/test/vo/ToolTestDemoExcelVO.java
  14. 0 8
      src/main/java/cn/iocoder/dashboard/modules/tool/dal/dataobject/codegen/ToolCodegenTableDO.java
  15. 0 1
      src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenBuilder.java
  16. 13 8
      src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenEngine.java
  17. 9 9
      src/main/resources/codegen/java/controller/controller.vm
  18. 4 1
      src/main/resources/codegen/java/controller/vo/excelVO.vm
  19. 4 3
      src/main/resources/codegen/sql/sql.vm
  20. 2 2
      src/main/resources/codegen/vue/api/api.js.vm
  21. 19 14
      src/main/resources/codegen/vue/views/index.vue.vm

+ 2 - 2
ruoyi-ui/src/api/tool/testDemo.js

@@ -22,7 +22,7 @@ export function updateTestDemo(data) {
 // 删除字典类型
 export function deleteTestDemo(id) {
   return request({
-    url: '/tool/test-demo/delelte?id=' + id,
+    url: '/tool/test-demo/delete?id=' + id,
     method: 'delete'
   })
 }
@@ -50,6 +50,6 @@ export function exportTestDemoExcel(query) {
     url: '/tool/test-demo/export-excel',
     method: 'get',
     params: query,
-    reponseBody: 'blob'
+    responseType: 'blob'
   })
 }

+ 1 - 1
ruoyi-ui/src/utils/ruoyi.js

@@ -93,7 +93,7 @@ export function addBeginAndEndTime(params, dateRange, propName) {
     params['begin' + propName] = dateRange[0] + ' 00:00:00';
   }
   if (dateRange[1]) {
-    params['end' + propName] = dateRange[0] + ' 23:59:59';
+    params['end' + propName] = dateRange[1] + ' 23:59:59';
   }
   return params;
 }

+ 3 - 7
ruoyi-ui/src/views/system/menu/index.vue

@@ -160,14 +160,10 @@
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item v-if="form.type != '3'" label="菜单状态">
+            <el-form-item label="菜单状态">
               <el-radio-group v-model="form.status">
-                <el-radio
-                    v-for="dict in statusDictDatas"
-                    :key="parseInt(dict.value)"
-                    :label="dict.label"
-                    :value="parseInt(dict.value)"
-                >{{dict.label}}</el-radio>
+                <el-radio v-for="dict in this.getDictDatas(DICT_TYPE.SYS_COMMON_STATUS)"
+                          :key="dict.value" :label="parseInt(dict.value)">{{dict.label}}</el-radio>
               </el-radio-group>
             </el-form-item>
           </el-col>

+ 4 - 2
ruoyi-ui/src/views/tool/gen/editTable.vue

@@ -129,6 +129,7 @@
 import { getCodegenDetail, updateCodegen } from "@/api/tool/codegen";
 import { listAllSimple as listAllSimpleDictType } from "@/api/system/dict/type";
 import { listMenu as getMenuTreeselect } from "@/api/system/menu";
+import { listSimpleMenus } from "@/api/system/menu";
 import basicInfoForm from "./basicInfoForm";
 import genInfoForm from "./genInfoForm";
 import Sortable from 'sortablejs'
@@ -170,8 +171,9 @@ export default {
         this.dictOptions = response.data;
       });
       /** 查询菜单下拉列表 */
-      getMenuTreeselect().then(response => {
-        this.menus = this.handleTree(response.data, "menuId");
+      listSimpleMenus().then(response => {
+        this.menus = [];
+        this.menus.push(...this.handleTree(response.data, "id"));
       });
     }
   },

+ 15 - 21
ruoyi-ui/src/views/tool/gen/genInfoForm.vue

@@ -51,17 +51,17 @@
         </el-form-item>
       </el-col>
 
-      <el-col :span="12">
-        <el-form-item prop="businessPackage">
-          <span slot="label">
-            业务包
-            <el-tooltip content="业务包,自定义二级目录。例如说,我们希望将 dictType 和 dictData 归类成 dict 业务" placement="top">
-              <i class="el-icon-question"></i>
-            </el-tooltip>
-          </span>
-          <el-input v-model="info.businessPackage" />
-        </el-form-item>
-      </el-col>
+<!--      <el-col :span="12">-->
+<!--        <el-form-item prop="businessPackage">-->
+<!--          <span slot="label">-->
+<!--            业务包-->
+<!--            <el-tooltip content="业务包,自定义二级目录。例如说,我们希望将 dictType 和 dictData 归类成 dict 业务" placement="top">-->
+<!--              <i class="el-icon-question"></i>-->
+<!--            </el-tooltip>-->
+<!--          </span>-->
+<!--          <el-input v-model="info.businessPackage" />-->
+<!--        </el-form-item>-->
+<!--      </el-col>-->
 
       <el-col :span="12">
         <el-form-item prop="className">
@@ -95,14 +95,8 @@
               <i class="el-icon-question"></i>
             </el-tooltip>
           </span>
-          <treeselect
-            :append-to-body="true"
-            v-model="info.parentMenuId"
-            :options="menus"
-            :normalizer="normalizer"
-            :show-count="true"
-            placeholder="请选择系统菜单"
-          />
+          <treeselect :append-to-body="true" v-model="info.parentMenuId" :options="menus"
+            :normalizer="normalizer" :show-count="true" placeholder="请选择系统菜单" />
         </el-form-item>
       </el-col>
 
@@ -289,8 +283,8 @@ export default {
         delete node.children;
       }
       return {
-        id: node.menuId,
-        label: node.menuName,
+        id: node.id,
+        label: node.name,
         children: node.children
       };
     },

+ 294 - 0
ruoyi-ui/src/views/tool/testDemo/index.vue

@@ -0,0 +1,294 @@
+<template>
+  <div class="app-container">
+
+    <!-- 搜索工作栏 -->
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="名字" prop="name">
+        <el-input v-model="queryParams.name" placeholder="请输入名字" clearable size="small" @keyup.enter.native="handleQuery"/>
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择状态" clearable size="small">
+          <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYS_COMMON_STATUS)"
+                     :key="dict.value" :label="dict.label" :value="dict.value"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="类型" prop="type">
+        <el-select v-model="queryParams.type" placeholder="请选择类型" clearable size="small">
+          <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYS_OPERATE_TYPE)"
+                     :key="dict.value" :label="dict.label" :value="dict.value"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="分类" prop="category">
+        <el-select v-model="queryParams.category" placeholder="请选择分类" clearable size="small">
+          <el-option v-for="dict in this.getDictDatas(DICT_TYPE.INF_REDIS_TIMEOUT_TYPE)"
+                     :key="dict.value" :label="dict.label" :value="dict.value"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input v-model="queryParams.remark" placeholder="请输入备注" clearable size="small" @keyup.enter.native="handleQuery"/>
+      </el-form-item>
+      <el-form-item label="创建时间">
+        <el-date-picker v-model="dateRangeCreateTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
+                        type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
+      </el-form-item>
+      <el-form-item label="是否删除" prop="deleted">
+        <el-select v-model="queryParams.deleted" placeholder="请选择是否删除" clearable size="small">
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- 操作工具栏 -->
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
+                   v-hasPermi="['tool:test-demo:create']">新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
+                   v-hasPermi="['tool:test-demo:export']">导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <!-- 列表 -->
+    <el-table v-loading="loading" :data="list">
+      <el-table-column label="编号" align="center" prop="id" />
+      <el-table-column label="名字" align="center" prop="name" />
+      <el-table-column label="状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <span>{{ getDictDataLabel(DICT_TYPE.SYS_COMMON_STATUS, scope.row.status) }}</span>
+        </template>
+      </el-table-column>>
+      <el-table-column label="类型" align="center" prop="type">
+        <template slot-scope="scope">
+          <span>{{ getDictDataLabel(DICT_TYPE.SYS_OPERATE_TYPE, scope.row.type) }}</span>
+        </template>
+      </el-table-column>>
+      <el-table-column label="分类" align="center" prop="category">
+        <template slot-scope="scope">
+          <span>{{ getDictDataLabel(DICT_TYPE.INF_REDIS_TIMEOUT_TYPE, scope.row.category) }}</span>
+        </template>
+      </el-table-column>>
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
+                     v-hasPermi="['tool:test-demo:update']">修改</el-button>
+          <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
+                     v-hasPermi="['tool:test-demo:delete']">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页组件 -->
+    <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
+                @pagination="getList"/>
+
+    <!-- 对话框(添加 / 修改) -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="名字" prop="name">
+          <el-input v-model="form.name" placeholder="请输入名字" />
+        </el-form-item>
+        <el-form-item label="状态">
+          <el-radio-group v-model="form.status">
+            <el-radio v-for="dict in this.getDictDatas(DICT_TYPE.SYS_COMMON_STATUS)"
+                      :key="dict.value" :label="parseInt(dict.value)">{{dict.label}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="类型" prop="type">
+          <el-select v-model="form.type" placeholder="请选择类型">
+            <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYS_OPERATE_TYPE)"
+                       :key="dict.value" :label="dict.label" :value="parseInt(dict.value)" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="分类">
+          <el-radio-group v-model="form.category">
+            <el-radio v-for="dict in this.getDictDatas(DICT_TYPE.INF_REDIS_TIMEOUT_TYPE)"
+                      :key="dict.value" :label="parseInt(dict.value)">{{dict.label}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" placeholder="请输入备注" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { createTestDemo, updateTestDemo, deleteTestDemo, getTestDemo, getTestDemoPage, exportTestDemoExcel } from "@/api/tool/testDemo";
+
+export default {
+  name: "TestDemo",
+  components: {
+  },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 测试示例列表
+      list: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      dateRangeCreateTime: [],
+      // 查询参数
+      queryParams: {
+        pageNo: 1,
+        pageSize: 10,
+        name: null,
+        status: null,
+        type: null,
+        category: null,
+        remark: null,
+        deleted: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        name: [{ required: true, message: "名字不能为空", trigger: "blur" }],
+        status: [{ required: true, message: "状态不能为空", trigger: "blur" }],
+        type: [{ required: true, message: "类型不能为空", trigger: "change" }],
+        category: [{ required: true, message: "分类不能为空", trigger: "blur" }],
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询列表 */
+    getList() {
+      this.loading = true;
+      let params = {...this.queryParams};
+      this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
+      // 执行查询
+      getTestDemoPage(params).then(response => {
+        this.list = response.data.list;
+        this.total = response.data.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: undefined,
+        name: undefined,
+        status: undefined,
+        type: undefined,
+        category: undefined,
+        remark: undefined,
+        createBy: undefined,
+        createTime: undefined,
+        updateBy: undefined,
+        updateTime: undefined,
+        deleted: undefined,
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNo = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.dateRangeCreateTime = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加测试示例";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id;
+      getTestDemo(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改测试示例";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (!valid) {
+          return;
+        }
+        // 修改的提交
+        if (this.form.id != null) {
+          updateTestDemo(this.form).then(response => {
+            this.msgSuccess("修改成功");
+            this.open = false;
+            this.getList();
+          });
+          return;
+        }
+        // 添加的提交
+        createTestDemo(this.form).then(response => {
+          this.msgSuccess("新增成功");
+          this.open = false;
+          this.getList();
+        });
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const id = row.id;
+      this.$confirm('是否确认删除测试示例编号为"' + id + '"的数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return deleteTestDemo(id);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      })
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      let params = {...this.queryParams};
+      this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
+      this.$confirm('是否确认导出所有测试示例数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return exportTestDemoExcel(params);
+      }).then(response => {
+        this.downloadExcel(response, '测试示例.xls');
+      })
+    }
+  }
+};
+</script>

+ 7 - 2
src/main/java/cn/iocoder/dashboard/framework/excel/core/convert/DictConvert.java

@@ -44,14 +44,19 @@ public class DictConvert implements Converter<Object> {
 
     @Override
     public CellData<String> convertToExcelData(Object object, ExcelContentProperty contentProperty,
-                                       GlobalConfiguration globalConfiguration) {
+                                               GlobalConfiguration globalConfiguration) {
+        // 空时,返回空
+        if (object == null) {
+            return new CellData<>("");
+        }
+
         // 使用字典格式化
         SysDictTypeEnum type = getType(contentProperty);
         String value = String.valueOf(object);
         SysDictDataDO dictData = DictUtils.getDictDataFromCache(type.getValue(), value);
         if (dictData == null) {
             log.error("[convertToExcelData][type({}) 转换不了 label({})]", type, value);
-            return null;
+            return new CellData<>("");
         }
         // 生成 Excel 小表格
         return new CellData<>(dictData.getLabel());

+ 0 - 1
src/main/java/cn/iocoder/dashboard/framework/excel/core/package-info.java

@@ -1 +0,0 @@
-package cn.iocoder.dashboard.framework.excel.core;

+ 4 - 3
src/main/java/cn/iocoder/dashboard/modules/system/controller/permission/vo/menu/SysMenuBaseVO.java

@@ -42,11 +42,12 @@ public class SysMenuBaseVO {
     @ApiModelProperty(value = "菜单图标", example = "/menu/list", notes = "仅菜单类型为菜单或者目录时,才需要传")
     private String icon;
 
-    /**
-     * 组件路径
-     */
     @ApiModelProperty(value = "组件路径", example = "system/post/index", notes = "仅菜单类型为菜单时,才需要传")
     @Size(max = 200, message = "组件路径不能超过255个字符")
     private String component;
 
+    @ApiModelProperty(value = "状态", required = true, example = "1", notes = "见 SysCommonStatusEnum 枚举")
+    @NotNull(message = "状态不能为空")
+    private Integer status;
+
 }

+ 0 - 1
src/main/java/cn/iocoder/dashboard/modules/tool/controller/codegen/ToolCodegenController.java

@@ -51,7 +51,6 @@ public class ToolCodegenController {
             @ApiImplicitParam(name = "tableName", required = true, example = "yudao", dataTypeClass = String.class),
             @ApiImplicitParam(name = "tableComment", required = true, example = "芋道", dataTypeClass = String.class)
     })
-//    @PreAuthorize("@ss.hasPermi('tool:gen:list')") TODO 权限
     public CommonResult<List<ToolSchemaTableRespVO>> getSchemaTableList(
             @RequestParam(value = "tableName", required = false) String tableName,
             @RequestParam(value = "tableComment", required = false) String tableComment) {

+ 3 - 4
src/main/java/cn/iocoder/dashboard/modules/tool/controller/codegen/vo/table/ToolCodegenTableBaseVO.java

@@ -31,10 +31,6 @@ public class ToolCodegenTableBaseVO {
     @NotNull(message = "业务名不能为空")
     private String businessName;
 
-    @ApiModelProperty(value = "业务包", required = true, example = "codegen")
-    @NotNull(message = "业务包不能为空")
-    private String businessPackage;
-
     @ApiModelProperty(value = "类名称", required = true, example = "ToolCodegenTable")
     @NotNull(message = "类名称不能为空")
     private String className;
@@ -51,4 +47,7 @@ public class ToolCodegenTableBaseVO {
     @NotNull(message = "模板类型不能为空")
     private Integer templateType;
 
+    @ApiModelProperty(value = "父菜单编号", example = "1024")
+    private Long parentMenuId;
+
 }

+ 22 - 11
src/main/java/cn/iocoder/dashboard/modules/tool/controller/test/ToolTestDemoController.java

@@ -3,6 +3,7 @@ package cn.iocoder.dashboard.modules.tool.controller.test;
 import cn.iocoder.dashboard.common.pojo.CommonResult;
 import cn.iocoder.dashboard.common.pojo.PageResult;
 import cn.iocoder.dashboard.framework.excel.core.util.ExcelUtils;
+import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog;
 import cn.iocoder.dashboard.modules.tool.controller.test.vo.*;
 import cn.iocoder.dashboard.modules.tool.convert.test.ToolTestDemoConvert;
 import cn.iocoder.dashboard.modules.tool.dal.dataobject.test.ToolTestDemoDO;
@@ -10,6 +11,7 @@ import cn.iocoder.dashboard.modules.tool.service.test.ToolTestDemoService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiOperation;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
@@ -21,8 +23,9 @@ import java.util.Collection;
 import java.util.List;
 
 import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
+import static cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateTypeEnum.EXPORT;
 
-@Api(tags = "字典类型")
+@Api(tags = "测试示例")
 @RestController
 @RequestMapping("/tool/test-demo")
 @Validated
@@ -31,58 +34,66 @@ public class ToolTestDemoController {
     @Resource
     private ToolTestDemoService testDemoService;
 
-    @ApiOperation("创建字典类型")
     @PostMapping("/create")
-    public CommonResult<Long> createTestDemo(@Valid ToolTestDemoCreateReqVO createReqVO) {
+    @ApiOperation("创建测试示例")
+    @PreAuthorize("@ss.hasPermission('tool:test-demo:create')")
+    public CommonResult<Long> createTestDemo(@Valid @RequestBody ToolTestDemoCreateReqVO createReqVO) {
         return success(testDemoService.createTestDemo(createReqVO));
     }
 
-    @ApiOperation("更新字典类型")
     @PutMapping("/update")
-    public CommonResult<Boolean> updateTestDemo(@Valid ToolTestDemoUpdateReqVO updateReqVO) {
+    @ApiOperation("更新测试示例")
+    @PreAuthorize("@ss.hasPermission('tool:test-demo:update')")
+    public CommonResult<Boolean> updateTestDemo(@Valid @RequestBody ToolTestDemoUpdateReqVO updateReqVO) {
         testDemoService.updateTestDemo(updateReqVO);
         return success(true);
     }
 
-    @ApiOperation("删除字典类型")
     @DeleteMapping("/delete")
+    @ApiOperation("删除测试示例")
     @ApiImplicitParam(name = "id", value = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('tool:test-demo:delete')")
     public CommonResult<Boolean> deleteTestDemo(@RequestParam("id") Long id) {
         testDemoService.deleteTestDemo(id);
         return success(true);
     }
 
     @GetMapping("/get")
-    @ApiOperation("获得字典类型")
+    @ApiOperation("获得测试示例")
     @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
+    @PreAuthorize("@ss.hasPermission('tool:test-demo:query')")
     public CommonResult<ToolTestDemoRespVO> getTestDemo(@RequestParam("id") Long id) {
         ToolTestDemoDO testDemo = testDemoService.getTestDemo(id);
         return success(ToolTestDemoConvert.INSTANCE.convert(testDemo));
     }
 
     @GetMapping("/list")
-    @ApiOperation("获得字典类型列表")
+    @ApiOperation("获得测试示例列表")
     @ApiImplicitParam(name = "ids", value = "编号列表", required = true, dataTypeClass = List.class)
+    @PreAuthorize("@ss.hasPermission('tool:test-demo:query')")
     public CommonResult<List<ToolTestDemoRespVO>> getTestDemoList(@RequestParam("ids") Collection<Long> ids) {
         List<ToolTestDemoDO> list = testDemoService.getTestDemoList(ids);
         return success(ToolTestDemoConvert.INSTANCE.convertList(list));
     }
 
-    @ApiOperation("获得字典类型分页")
     @GetMapping("/page")
+    @ApiOperation("获得测试示例分页")
+    @PreAuthorize("@ss.hasPermission('tool:test-demo:query')")
     public CommonResult<PageResult<ToolTestDemoRespVO>> getTestDemoPage(@Valid ToolTestDemoPageReqVO pageVO) {
         PageResult<ToolTestDemoDO> pageResult = testDemoService.getTestDemoPage(pageVO);
         return success(ToolTestDemoConvert.INSTANCE.convertPage(pageResult));
     }
 
     @GetMapping("/export-excel")
-    @ApiOperation("导出字典类型 Excel")
+    @ApiOperation("导出测试示例 Excel")
+    @PreAuthorize("@ss.hasPermission('tool:test-demo:export')")
+    @OperateLog(type = EXPORT)
     public void exportTestDemoExcel(@Valid ToolTestDemoExportReqVO exportReqVO,
                                     HttpServletResponse response) throws IOException {
         List<ToolTestDemoDO> list = testDemoService.getTestDemoList(exportReqVO);
         // 导出 Excel
         List<ToolTestDemoExcelVO> datas = ToolTestDemoConvert.INSTANCE.convertList02(list);
-        ExcelUtils.write(response, "字典类型.xls", "数据", ToolTestDemoExcelVO.class, datas);
+        ExcelUtils.write(response, "测试示例.xls", "数据", ToolTestDemoExcelVO.class, datas);
     }
 
 }

+ 5 - 4
src/main/java/cn/iocoder/dashboard/modules/tool/controller/test/vo/ToolTestDemoExcelVO.java

@@ -1,6 +1,7 @@
 package cn.iocoder.dashboard.modules.tool.controller.test.vo;
 
 import cn.iocoder.dashboard.framework.excel.core.annotations.DictFormat;
+import cn.iocoder.dashboard.framework.excel.core.convert.DictConvert;
 import com.alibaba.excel.annotation.ExcelProperty;
 import lombok.Data;
 
@@ -9,7 +10,7 @@ import java.util.Date;
 import static cn.iocoder.dashboard.modules.system.enums.dict.SysDictTypeEnum.*;
 
 /**
- * 字典类型 Excel VO
+ * 测试示例 Excel VO
  *
  * @author 芋艿
  */
@@ -22,15 +23,15 @@ public class ToolTestDemoExcelVO {
     @ExcelProperty("名字")
     private String name;
 
-    @ExcelProperty("状态")
+    @ExcelProperty(value = "状态", converter = DictConvert.class)
     @DictFormat(SYS_COMMON_STATUS)
     private Integer status;
 
-    @ExcelProperty("类型")
+    @ExcelProperty(value = "类型", converter = DictConvert.class)
     @DictFormat(SYS_OPERATE_TYPE)
     private Integer type;
 
-    @ExcelProperty("分类")
+    @ExcelProperty(value = "分类", converter = DictConvert.class)
     @DictFormat(INF_REDIS_TIMEOUT_TYPE)
     private Integer category;
 

+ 0 - 8
src/main/java/cn/iocoder/dashboard/modules/tool/dal/dataobject/codegen/ToolCodegenTableDO.java

@@ -53,14 +53,6 @@ public class ToolCodegenTableDO extends BaseDO {
      * 例如说,user、permission、dict 等等
      */
     private String businessName;
-    /**
-     * 业务包,自定义二级目录
-     *
-     * 例如说,我们希望将 dictType 和 dictData 归类成 dict 业务
-     *
-     * 如果不需要的情况下,businessName 和 businessPackage 是等价的
-     */
-    private String businessPackage;
     /**
      * 类名称(首字母大写)
      *

+ 0 - 1
src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenBuilder.java

@@ -128,7 +128,6 @@ public class ToolCodegenBuilder {
                 '_', false))); // 第一个 _ 前缀的前面,作为 module 名字
         table.setBusinessName(toCamelCase(subAfter(table.getTableName(),
                 '_', false))); // 第一步,第一个 _ 前缀的后面,作为 module 名字; 第二步,可能存在多个 _ 的情况,转换成驼峰
-        table.setBusinessPackage(table.getBusinessPackage());
         table.setClassName(upperFirst(toCamelCase(table.getTableName()))); // 驼峰 + 首字母大写
         table.setClassComment(subBefore(table.getTableComment(), // 去除结尾的表,作为类描述
                 '表', true));

+ 13 - 8
src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenEngine.java

@@ -11,6 +11,7 @@ import cn.iocoder.dashboard.common.pojo.PageParam;
 import cn.iocoder.dashboard.common.pojo.PageResult;
 import cn.iocoder.dashboard.framework.codegen.config.CodegenProperties;
 import cn.iocoder.dashboard.framework.excel.core.annotations.DictFormat;
+import cn.iocoder.dashboard.framework.excel.core.convert.DictConvert;
 import cn.iocoder.dashboard.framework.excel.core.util.ExcelUtils;
 import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog;
 import cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateTypeEnum;
@@ -27,11 +28,9 @@ import org.springframework.stereotype.Component;
 
 import javax.annotation.PostConstruct;
 import javax.annotation.Resource;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
+import static cn.hutool.core.map.MapUtil.getStr;
 import static cn.hutool.core.text.CharSequenceUtil.*;
 
 /**
@@ -82,7 +81,7 @@ public class ToolCodegenEngine {
                     javaFilePath("service/${table.businessName}/impl/${table.className}ServiceImpl"))
             // Vue
             .put(vueTemplatePath("views/index.vue"),
-                    vueFilePath("views/${table.moduleName}/${table.businessName}/index.vue"))
+                    vueFilePath("views/${table.moduleName}/${classNameVar}/index.vue"))
             .put(vueTemplatePath("api/api.js"),
                     vueFilePath("api/${table.moduleName}/${classNameVar}.js"))
             // SQL
@@ -131,6 +130,7 @@ public class ToolCodegenEngine {
         globalBindingMap.put("ServiceExceptionUtilClassName", ServiceExceptionUtil.class.getName());
         globalBindingMap.put("DateUtilsClassName", DateUtils.class.getName());
         globalBindingMap.put("ExcelUtilsClassName", ExcelUtils.class.getName());
+        globalBindingMap.put("DictConvertClassName", DictConvert.class.getName());
         globalBindingMap.put("OperateLogClassName", OperateLog.class.getName());
         globalBindingMap.put("OperateTypeEnumClassName", OperateTypeEnum.class.getName());
     }
@@ -167,13 +167,18 @@ public class ToolCodegenEngine {
     }
 
     private String formatFilePath(String filePath, Map<String, Object> bindingMap) {
-        filePath = StrUtil.replace(filePath, "${basePackage}", ((String) bindingMap.get("basePackage")).replaceAll("\\.", "/"));
+        filePath = StrUtil.replace(filePath, "${basePackage}",
+                getStr(bindingMap, "basePackage").replaceAll("\\.", "/"));
+        filePath = StrUtil.replace(filePath, "${simpleModuleName_upperFirst}",
+                getStr(bindingMap, "simpleModuleName_upperFirst"));
+        filePath = StrUtil.replace(filePath, "${classNameVar}",
+                getStr(bindingMap, "classNameVar"));
+
+        // table 包含的字段
         ToolCodegenTableDO table = (ToolCodegenTableDO) bindingMap.get("table");
-        filePath = StrUtil.replace(filePath, "${simpleModuleName_upperFirst}", (String) bindingMap.get("simpleModuleName_upperFirst"));
         filePath = StrUtil.replace(filePath, "${table.moduleName}", table.getModuleName());
         filePath = StrUtil.replace(filePath, "${table.businessName}", table.getBusinessName());
         filePath = StrUtil.replace(filePath, "${table.className}", table.getClassName());
-        filePath = StrUtil.replace(filePath, "${classNameVar}", (String) bindingMap.get("classNameVar"));
         return filePath;
     }
 

+ 9 - 9
src/main/resources/codegen/java/controller/controller.vm

@@ -39,15 +39,15 @@ public class ${table.className}Controller {
 
     @PostMapping("/create")
     @ApiOperation("创建${table.classComment}")
-    @PreAuthorize("@ss.hasPermi('${permissionPrefix}:create')")
-    public CommonResult<${primaryColumn.javaType}> create${simpleClassName}(@Valid ${table.className}CreateReqVO createReqVO) {
+    @PreAuthorize("@ss.hasPermission('${permissionPrefix}:create')")
+    public CommonResult<${primaryColumn.javaType}> create${simpleClassName}(@Valid @RequestBody ${table.className}CreateReqVO createReqVO) {
         return success(${classNameVar}Service.create${simpleClassName}(createReqVO));
     }
 
     @PutMapping("/update")
     @ApiOperation("更新${table.classComment}")
-    @PreAuthorize("@ss.hasPermi('${permissionPrefix}:update')")
-    public CommonResult<Boolean> update${simpleClassName}(@Valid ${table.className}UpdateReqVO updateReqVO) {
+    @PreAuthorize("@ss.hasPermission('${permissionPrefix}:update')")
+    public CommonResult<Boolean> update${simpleClassName}(@Valid @RequestBody ${table.className}UpdateReqVO updateReqVO) {
         ${classNameVar}Service.update${simpleClassName}(updateReqVO);
         return success(true);
     }
@@ -55,7 +55,7 @@ public class ${table.className}Controller {
 	@DeleteMapping("/delete")
     @ApiOperation("删除${table.classComment}")
     @ApiImplicitParam(name = "id", value = "编号", required = true)
-	@PreAuthorize("@ss.hasPermi('${permissionPrefix}:delete')")
+	@PreAuthorize("@ss.hasPermission('${permissionPrefix}:delete')")
     public CommonResult<Boolean> delete${simpleClassName}(@RequestParam("id") ${primaryColumn.javaType} id) {
         ${classNameVar}Service.delete${simpleClassName}(id);
         return success(true);
@@ -64,7 +64,7 @@ public class ${table.className}Controller {
     @GetMapping("/get")
     @ApiOperation("获得${table.classComment}")
     @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = ${primaryColumn.javaType}.class)
-    @PreAuthorize("@ss.hasPermi('${permissionPrefix}:query')")
+    @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')")
     public CommonResult<${table.className}RespVO> get${simpleClassName}(@RequestParam("id") ${primaryColumn.javaType} id) {
         ${table.className}DO ${classNameVar} = ${classNameVar}Service.get${simpleClassName}(id);
         return success(${table.className}Convert.INSTANCE.convert(${classNameVar}));
@@ -73,7 +73,7 @@ public class ${table.className}Controller {
     @GetMapping("/list")
     @ApiOperation("获得${table.classComment}列表")
     @ApiImplicitParam(name = "ids", value = "编号列表", required = true, dataTypeClass = List.class)
-    @PreAuthorize("@ss.hasPermi('${permissionPrefix}:query')")
+    @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')")
     public CommonResult<List<${table.className}RespVO>> get${simpleClassName}List(@RequestParam("ids") Collection<${primaryColumn.javaType}> ids) {
         List<${table.className}DO> list = ${classNameVar}Service.get${simpleClassName}List(ids);
         return success(${table.className}Convert.INSTANCE.convertList(list));
@@ -81,7 +81,7 @@ public class ${table.className}Controller {
 
     @GetMapping("/page")
     @ApiOperation("获得${table.classComment}分页")
-    @PreAuthorize("@ss.hasPermi('${permissionPrefix}:query')")
+    @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')")
     public CommonResult<PageResult<${table.className}RespVO>> get${simpleClassName}Page(@Valid ${table.className}PageReqVO pageVO) {
         PageResult<${table.className}DO> pageResult = ${classNameVar}Service.get${simpleClassName}Page(pageVO);
         return success(${table.className}Convert.INSTANCE.convertPage(pageResult));
@@ -89,7 +89,7 @@ public class ${table.className}Controller {
 
     @GetMapping("/export-excel")
     @ApiOperation("导出${table.classComment} Excel")
-    @PreAuthorize("@ss.hasPermi('${permissionPrefix}:export')")
+    @PreAuthorize("@ss.hasPermission('${permissionPrefix}:export')")
     @OperateLog(type = EXPORT)
     public void export${simpleClassName}Excel(@Valid ${table.className}ExportReqVO exportReqVO,
               HttpServletResponse response) throws IOException {

+ 4 - 1
src/main/resources/codegen/java/controller/vo/excelVO.vm

@@ -8,6 +8,7 @@ import com.alibaba.excel.annotation.ExcelProperty;
 #foreach ($column in $columns)
 #if ("$!column.dictType" != "")## 有设置数据字典
 import ${DictFormatClassName};
+import ${DictConvertClassName};
 
 import static ${SysDictTypeEnumClassName}.*;
 #break
@@ -24,9 +25,11 @@ public class ${table.className}ExcelVO {
 
 #foreach ($column in $columns)
     #if (${column.listOperationResult})##返回字段
-    @ExcelProperty("${column.columnComment}")
     #if ("$!column.dictType" != "")##处理枚举值
+    @ExcelProperty(value = "${column.columnComment}", converter = DictConvert.class)
     @DictFormat(${column.dictType.toUpperCase()})
+    #else
+    @ExcelProperty("${column.columnComment}")
     #end
     private ${column.javaType} ${column.javaField};
 

+ 4 - 3
src/main/resources/codegen/sql/sql.vm

@@ -4,8 +4,8 @@ INSERT INTO `sys_menu`(
     `path`, `icon`, `component`, `status`
 )
 VALUES (
-    '${table.tableComment}管理', '${permissionPrefix}:query', 2, 0, ${table.parentMenuId},
-    '${simpleClassName_strikeCase}', '', '${table.moduleName}/${table.businessName}/index', 1
+    '${table.classComment}管理', '${permissionPrefix}:query', 2, 0, ${table.parentMenuId},
+    '${simpleClassName_strikeCase}', '', '${table.moduleName}/${classNameVar}/index', 1
 );
 
 -- 按钮父菜单ID
@@ -15,12 +15,13 @@ SELECT @parentId := LAST_INSERT_ID();
 #set ($functionNames = ['创建', '更新', '删除', '导出'])
 #set ($functionOps = ['create', 'update', 'delete', 'export'])
 #foreach ($functionName in $functionNames)
+#set ($index = $foreach.count - 1)
 INSERT INTO `sys_menu`(
     `name`, `permission`, `menu_type`, `sort`, `parent_id`,
     `path`, `icon`, `component`, `status`
 )
 VALUES (
-    '${table.tableComment}${functionName}', '${permissionPrefix}:${functionOps[$velocityCount]}', 3, 0, @parentId,
+    '${table.tableComment}${functionName}', '${permissionPrefix}:${functionOps.get($index)}', 3, $foreach.count, @parentId,
     '', '', '', 1
 );
 #end

+ 2 - 2
src/main/resources/codegen/vue/api/api.js.vm

@@ -23,7 +23,7 @@ export function update${simpleClassName}(data) {
 // 删除${table.classComment}
 export function delete${simpleClassName}(id) {
   return request({
-    url: '${baseURL}/delelte?id=' + id,
+    url: '${baseURL}/delete?id=' + id,
     method: 'delete'
   })
 }
@@ -51,6 +51,6 @@ export function export${simpleClassName}Excel(query) {
     url: '${baseURL}/export-excel',
     method: 'get',
     params: query,
-    reponseBody: 'blob'
+    responseType: 'blob'
   })
 }

+ 19 - 14
src/main/resources/codegen/vue/views/index.vue.vm

@@ -18,14 +18,14 @@
         <el-select v-model="queryParams.${javaField}" placeholder="请选择${comment}" clearable size="small">
     #if ("" != $dictType)## 设置了 dictType 数据字典的情况
           <el-option v-for="dict in this.getDictDatas(DICT_TYPE.$dictType.toUpperCase())"
-                       :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue"/>
+                       :key="dict.value" :label="dict.label" :value="dict.value"/>
     #else## 未设置 dictType 数据字典的情况
           <el-option label="请选择字典生成" value="" />
     #end
         </el-select>
       </el-form-item>
 #elseif($column.htmlType == "datetime")
-    #if ($column.queryType != "BETWEEN")## 非范围
+    #if ($column.listOperationCondition != "BETWEEN")## 非范围
       <el-form-item label="${comment}" prop="${javaField}">
         <el-date-picker clearable size="small" v-model="queryParams.${javaField}" type="date" value-format="yyyy-MM-dd" placeholder="选择${comment}" />
       </el-form-item>
@@ -74,7 +74,7 @@
 #elseif("" != $column.dictType)## 数据字典
       <el-table-column label="${comment}" align="center" prop="${javaField}">
         <template slot-scope="scope">
-          <span>{{ getDictDataLabel(DICT_TYPE.$dictType.toUpperCase(), scope.row.javaField) }}</span>
+          <span>{{ getDictDataLabel(DICT_TYPE.$dictType.toUpperCase(), scope.row.${column.javaField}) }}</span>
         </template>
       </el-table-column>>
 #else
@@ -253,11 +253,12 @@ export default {
     /** 查询列表 */
     getList() {
       this.loading = true;
+      // 处理查询参数
       let params = {...this.queryParams};
       #foreach ($column in $columns)
       #if ($column.htmlType == "datetime" && $column.listOperationCondition == "BETWEEN")
       #set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
-      this.addBeginAndEndTime(params, this.dateRange${AttrName}, ${column.javaField});
+      this.addBeginAndEndTime(params, this.dateRange${AttrName}, '${column.javaField}');
       #end
       #end
       // 执行查询
@@ -279,7 +280,7 @@ export default {
         #if($column.htmlType == "checkbox")
         $column.javaField: [],
         #else
-        $column.javaField: null,
+        $column.javaField: undefined,
         #end
         #end
       };
@@ -325,7 +326,7 @@ export default {
     /** 提交按钮 */
     submitForm() {
       this.#[[$]]#refs["form"].validate(valid => {
-        if (valid) {
+        if (!valid) {
           return;
         }
         #foreach ($column in $columns)
@@ -366,19 +367,23 @@ export default {
     },
     /** 导出按钮操作 */
     handleExport() {
+      // 处理查询参数
+      let params = {...this.queryParams};
+      params.pageNo = undefined;
+      params.pageSize = undefined;
+      #foreach ($column in $columns)
+      #if ($column.htmlType == "datetime" && $column.listOperationCondition == "BETWEEN")
+      #set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+      this.addBeginAndEndTime(params, this.dateRange${AttrName}, '${column.javaField}');
+      #end
+      #end
+      // 执行导出
       this.$confirm('是否确认导出所有${table.classComment}数据项?', "警告", {
           confirmButtonText: "确定",
           cancelButtonText: "取消",
           type: "warning"
         }).then(function() {
-          let params = {...this.queryParams};
-          #foreach ($column in $columns)
-          #if ($column.htmlType == "datetime" && $column.listOperationCondition == "BETWEEN")
-          #set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
-          this.addBeginAndEndTime(params, this.dateRange${AttrName}, ${column.javaField});
-          #end
-          #end
-          return export${simpleClassName}(params);
+          return export${simpleClassName}Excel(params);
         }).then(response => {
           this.downloadExcel(response, '${table.classComment}.xls');
         })