Forráskód Böngészése

优化代码生成

SpringSunYY 5 hónapja
szülő
commit
4703d1466d

+ 97 - 75
ruoyi-ui/src/utils/ruoyi.js

@@ -1,9 +1,8 @@
-
-
 /**
  * 通用js方法封装处理
  * Copyright (c) 2019 ruoyi
  */
+const baseURL = process.env.VUE_APP_BASE_API
 
 // 日期格式化
 export function parseTime(time, pattern) {
@@ -18,7 +17,7 @@ export function parseTime(time, pattern) {
     if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
       time = parseInt(time)
     } else if (typeof time === 'string') {
-      time = time.replace(new RegExp(/-/gm), '/').replace('T', ' ').replace(new RegExp(/\.[\d]{3}/gm), '');
+      time = time.replace(new RegExp(/-/gm), '/').replace('T', ' ').replace(new RegExp(/\.[\d]{3}/gm), '')
     }
     if ((typeof time === 'number') && (time.toString().length === 10)) {
       time = time * 1000
@@ -37,7 +36,9 @@ export function parseTime(time, pattern) {
   const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
     let value = formatObj[key]
     // Note: getDay() returns 0 on Sunday
-    if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
+    if (key === 'a') {
+      return ['日', '一', '二', '三', '四', '五', '六'][value]
+    }
     if (result.length > 0 && value < 10) {
       value = '0' + value
     }
@@ -49,86 +50,86 @@ export function parseTime(time, pattern) {
 // 表单重置
 export function resetForm(refName) {
   if (this.$refs[refName]) {
-    this.$refs[refName].resetFields();
+    this.$refs[refName].resetFields()
   }
 }
 
 // 添加日期范围
 export function addDateRange(params, dateRange, propName) {
-  let search = params;
-  search.params = typeof (search.params) === 'object' && search.params !== null && !Array.isArray(search.params) ? search.params : {};
-  dateRange = Array.isArray(dateRange) ? dateRange : [];
+  let search = params
+  search.params = typeof (search.params) === 'object' && search.params !== null && !Array.isArray(search.params) ? search.params : {}
+  dateRange = Array.isArray(dateRange) ? dateRange : []
   if (typeof (propName) === 'undefined') {
-    search.params['beginTime'] = dateRange[0];
-    search.params['endTime'] = dateRange[1];
+    search.params['beginTime'] = dateRange[0]
+    search.params['endTime'] = dateRange[1]
   } else {
-    search.params['begin' + propName] = dateRange[0];
-    search.params['end' + propName] = dateRange[1];
+    search.params['begin' + propName] = dateRange[0]
+    search.params['end' + propName] = dateRange[1]
   }
-  return search;
+  return search
 }
 
-// 回显数据字典 
+// 回显数据字典
 export function selectDictLabel(datas, value) {
   if (value === undefined) {
-    return "";
+    return ''
   }
-  var actions = [];
+  var actions = []
   Object.keys(datas).some((key) => {
     if (datas[key].value == ('' + value)) {
-      actions.push(datas[key].label);
-      return true;
+      actions.push(datas[key].label)
+      return true
     }
   })
   if (actions.length === 0) {
-    actions.push(value);
+    actions.push(value)
   }
-  return actions.join('');
+  return actions.join('')
 }
 
 // 回显数据字典(字符串数组)
 export function selectDictLabels(datas, value, separator) {
   if (value === undefined) {
-    return "";
+    return ''
   }
-  var actions = [];
-  var currentSeparator = undefined === separator ? "," : separator;
-  var temp = value.split(currentSeparator);
+  var actions = []
+  var currentSeparator = undefined === separator ? ',' : separator
+  var temp = value.split(currentSeparator)
   Object.keys(value.split(currentSeparator)).some((val) => {
-    var match = false;
+    var match = false
     Object.keys(datas).some((key) => {
       if (datas[key].value == ('' + temp[val])) {
-        actions.push(datas[key].label + currentSeparator);
-        match = true;
+        actions.push(datas[key].label + currentSeparator)
+        match = true
       }
     })
     if (!match) {
-      actions.push(temp[val] + currentSeparator);
+      actions.push(temp[val] + currentSeparator)
     }
   })
-  return actions.join('').substring(0, actions.join('').length - 1);
+  return actions.join('').substring(0, actions.join('').length - 1)
 }
 
 // 字符串格式化(%s )
 export function sprintf(str) {
-  var args = arguments, flag = true, i = 1;
-  str = str.replace(/%s/g, function () {
-    var arg = args[i++];
+  var args = arguments, flag = true, i = 1
+  str = str.replace(/%s/g, function() {
+    var arg = args[i++]
     if (typeof arg === 'undefined') {
-      flag = false;
-      return '';
+      flag = false
+      return ''
     }
-    return arg;
-  });
-  return flag ? str : '';
+    return arg
+  })
+  return flag ? str : ''
 }
 
 // 转换字符串,undefined,null等转化为""
 export function parseStrEmpty(str) {
-  if (!str || str == "undefined" || str == "null") {
-    return "";
+  if (!str || str == 'undefined' || str == 'null') {
+    return ''
   }
-  return str;
+  return str
 }
 
 // 数据合并
@@ -136,16 +137,16 @@ export function mergeRecursive(source, target) {
   for (var p in target) {
     try {
       if (target[p].constructor == Object) {
-        source[p] = mergeRecursive(source[p], target[p]);
+        source[p] = mergeRecursive(source[p], target[p])
       } else {
-        source[p] = target[p];
+        source[p] = target[p]
       }
     } catch (e) {
-      source[p] = target[p];
+      source[p] = target[p]
     }
   }
-  return source;
-};
+  return source
+}
 
 /**
  * 构造树型结构数据
@@ -157,71 +158,72 @@ export function mergeRecursive(source, target) {
 export function handleTree(data, id, parentId, children) {
   // 容错:确保可迭代
   if (!Array.isArray(data)) {
-    data = [];
+    data = []
   }
   let config = {
     id: id || 'id',
     parentId: parentId || 'parentId',
     childrenList: children || 'children'
-  };
+  }
 
-  var childrenListMap = {};
-  var nodeIds = {};
-  var tree = [];
+  var childrenListMap = {}
+  var nodeIds = {}
+  var tree = []
 
   for (let d of data) {
-    let parentId = d[config.parentId];
+    let parentId = d[config.parentId]
     if (childrenListMap[parentId] == null) {
-      childrenListMap[parentId] = [];
+      childrenListMap[parentId] = []
     }
-    nodeIds[d[config.id]] = d;
-    childrenListMap[parentId].push(d);
+    nodeIds[d[config.id]] = d
+    childrenListMap[parentId].push(d)
   }
 
   for (let d of data) {
-    let parentId = d[config.parentId];
+    let parentId = d[config.parentId]
     if (nodeIds[parentId] == null) {
-      tree.push(d);
+      tree.push(d)
     }
   }
 
   for (let t of tree) {
-    adaptToChildrenList(t);
+    adaptToChildrenList(t)
   }
 
   function adaptToChildrenList(o) {
     if (childrenListMap[o[config.id]] !== null) {
-      o[config.childrenList] = childrenListMap[o[config.id]];
+      o[config.childrenList] = childrenListMap[o[config.id]]
     }
     if (o[config.childrenList]) {
       for (let c of o[config.childrenList]) {
-        adaptToChildrenList(c);
+        adaptToChildrenList(c)
       }
     }
   }
-  return tree;
+
+  return tree
 }
 
 /**
-* 参数处理
-* @param {*} params  参数
-*/
+ * 参数处理
+ * @param {*} params  参数
+ */
 export function tansParams(params) {
   let result = ''
   for (const propName of Object.keys(params)) {
-    const value = params[propName];
-    var part = encodeURIComponent(propName) + "=";
-    if (value !== null && typeof (value) !== "undefined") {
+    const value = params[propName]
+    var part = encodeURIComponent(propName) + '='
+    if (value !== null && typeof (value) !== 'undefined') {
       if (typeof value === 'object') {
         for (const key of Object.keys(value)) {
           if (value[key] !== null && typeof (value[key]) !== 'undefined') {
-            let params = propName + '[' + key + ']';
-            var subPart = encodeURIComponent(params) + "=";
-            result += subPart + encodeURIComponent(value[key]) + "&";
+            let params = propName + '[' + key + ']'
+            var subPart = encodeURIComponent(params) + '='
+            result += subPart + encodeURIComponent(value[key]) + '&'
           }
         }
       } else {
-        result += part + encodeURIComponent(value) + "&";
+        result += part + encodeURIComponent(value) + '&'
       }
     }
   }
@@ -231,10 +233,30 @@ export function tansParams(params) {
 // 验证是否为blob格式
 export async function blobValidate(data) {
   try {
-    const text = await data.text();
-    JSON.parse(text);
-    return false;
+    const text = await data.text()
+    JSON.parse(text)
+    return false
   } catch (error) {
-    return true;
+    return true
   }
-}
+}
+
+//获取文件名
+export function getFileName(filePath) {
+  if (filePath == null) {
+    return
+  }
+  // 提取文件名或根据需求生成文件名
+  return filePath.substring(filePath.lastIndexOf('/') + 1)
+}
+
+//获取文件路径
+export function getFilePath(filePath) {
+  if (filePath == null) {
+    return
+  }
+  if (filePath.startsWith('http')) {
+    return filePath
+  }
+  return baseURL + filePath
+}

+ 20 - 11
ruoyi_common/base/transformer.py

@@ -23,16 +23,21 @@ def ids_to_list(value:str) -> Optional[List[int]]:
     return [int(i) for i in value.split(',')]
 
 
-def to_datetime(format=DateUtil.YYYY_MM_DD_HH_MM_SS) \
-        -> Callable[[str|NoneType, ValidationInfo], datetime|NoneType]:
+def to_datetime(format=None) -> Callable[[str | NoneType, ValidationInfo], datetime | NoneType]:
     """
     根据指定格式,验证datetime
 
     Args:
         format (str): 日期格式. Defaults to '%Y-%m-%d %H:%M:%S'.
     """
-    def validate_datetime(value:str|NoneType, info:ValidationInfo) \
-            -> datetime|NoneType:
+    if format is None:
+        formats: List[str] = [DateUtil.YYYY_MM_DD_HH_MM_SS, DateUtil.YYYY_MM_DD]
+    elif isinstance(format, (list, tuple, set)):
+        formats = list(format)
+    else:
+        formats = [format]
+
+    def validate_datetime(value: str | NoneType, info: ValidationInfo) -> datetime | NoneType:
         """
         验证datetime
 
@@ -46,14 +51,18 @@ def to_datetime(format=DateUtil.YYYY_MM_DD_HH_MM_SS) \
         Returns:
             _type_: datetime
         """
-        if value:
-            if isinstance(value, str):
-                return datetime.strptime(value, format)
-            elif isinstance(value, datetime):
-                return value
-            raise ValueError(f"Invalid datetime format: {value}")
-        else:
+        if not value:
             return None
+        if isinstance(value, datetime):
+            return value
+        if isinstance(value, str):
+            for fmt in formats:
+                try:
+                    return datetime.strptime(value, fmt)
+                except ValueError:
+                    continue
+            raise ValueError(f"time data '{value}' does not match formats: {formats}")
+        raise ValueError(f"Invalid datetime format: {value}")
     return validate_datetime
 
 

+ 8 - 8
ruoyi_generator/util.py

@@ -536,9 +536,9 @@ class GenUtils:
                                 # PO 文件在 domain/po/ 目录下
                                 dir_files[dir_path].append(('po', f"{to_underscore(table.class_name)}_po", table))
                             elif '_service.py' in output_file_name:
-                                dir_files[dir_path].append(('service', f"{table.class_name}Service", table))
+                                dir_files[dir_path].append(('service', f"{to_underscore(table.class_name)}_service", table))
                             elif '_mapper.py' in output_file_name:
-                                dir_files[dir_path].append(('mapper', f"{table.class_name}Mapper", table))
+                                dir_files[dir_path].append(('mapper', f"{to_underscore(table.class_name)}_mapper", table))
                             elif '_controller.py' in output_file_name:
                                 dir_files[dir_path].append(('controller', 'gen', table))
                         
@@ -604,9 +604,9 @@ class GenUtils:
                                 po_file_name = class_name  # class_name 已经是 address_info_po
                                 imports.append(f"from .{po_file_name} import {class_name}")
                             elif file_type == 'service':
-                                imports.append(f"from .{to_underscore(class_name.replace('Service', ''))}_service import {class_name}")
+                                imports.append(f"from .{class_name} import {class_name}")
                             elif file_type == 'mapper':
-                                imports.append(f"from .{to_underscore(class_name.replace('Mapper', ''))}_mapper import {class_name}")
+                                imports.append(f"from .{class_name} import {class_name}")
                         
                         if imports:
                             init_lines.extend(sorted(set(imports)))
@@ -824,9 +824,9 @@ class GenUtils:
                                     # PO 文件在 domain/po/ 目录下
                                     dir_files[dir_path].append(('po', f"{to_underscore(table.class_name)}_po", table))
                                 elif '_service.py' in output_file_name:
-                                    dir_files[dir_path].append(('service', f"{table.class_name}Service", table))
+                                    dir_files[dir_path].append(('service', f"{to_underscore(table.class_name)}_service", table))
                                 elif '_mapper.py' in output_file_name:
-                                    dir_files[dir_path].append(('mapper', f"{table.class_name}Mapper", table))
+                                    dir_files[dir_path].append(('mapper', f"{to_underscore(table.class_name)}_mapper", table))
                                 elif '_controller.py' in output_file_name:
                                     dir_files[dir_path].append(('controller', 'gen', table))
                             
@@ -904,9 +904,9 @@ class GenUtils:
                                 po_file_name = class_name  # class_name 已经是 address_info_po
                                 imports.append(f"from .{po_file_name} import {class_name}")
                             elif file_type == 'service':
-                                imports.append(f"from .{to_underscore(class_name.replace('Service', ''))}_service import {class_name}")
+                                imports.append(f"from .{class_name} import {class_name}")
                             elif file_type == 'mapper':
-                                imports.append(f"from .{to_underscore(class_name.replace('Mapper', ''))}_mapper import {class_name}")
+                                imports.append(f"from .{class_name} import {class_name}")
                         
                         if imports:
                             init_lines.extend(sorted(set(imports)))

+ 37 - 22
ruoyi_generator/vm/py/controller.py.vm

@@ -1,3 +1,4 @@
+{%- set is_tree = table.tpl_category == 'tree' %}
 from flask import request
 
 from ruoyi_common.base.model import AjaxResponse, TableResponse
@@ -9,35 +10,43 @@ from ruoyi_framework.descriptor.permission import HasPerm, PreAuthorize
 from {{ get_import_path(table.package_name, table.module_name, 'controller') }} import {{ underscore(table.class_name) }} as {{ underscore(table.class_name) }}_bp
 from {{ get_import_path(table.package_name, table.module_name, 'domain', table.class_name) }} import {{ underscore(table.class_name) }}_po
 from {{ get_import_path(table.package_name, table.module_name, 'domain') }} import {{ table.class_name }}
-from {{ get_import_path(table.package_name, table.module_name, 'service') }}.{{ underscore(table.class_name) }}_service import {{ table.class_name }}Service
+from {{ get_import_path(table.package_name, table.module_name, 'service') }}.{{ underscore(table.class_name) }}_service import {{ underscore(table.class_name) }}_service as {{ underscore(table.class_name) }}_service_class
 
 # 使用 controller/__init__.py 中定义的蓝图
 gen = {{ underscore(table.class_name) }}_bp
 
-{{ table.class_name|lower }}_service = {{ table.class_name }}Service()
+{{ underscore(table.class_name) }}_service = {{ underscore(table.class_name) }}_service_class()
 
 @gen.route('/list', methods=["GET"])
+{%- if is_tree %}
+@QueryValidator()
+{%- else %}
 @QueryValidator(is_page=True)
+{%- endif %}
 @PreAuthorize(HasPerm('{{ table.module_name }}:{{ table.business_name }}:list'))
 @JsonSerializer()
-def {{ table.business_name }}_list(dto: {{ underscore(table.class_name) }}_po):
+def {{ underscore(table.business_name) }}_list(dto: {{ table.class_name }}):
     """查询{{ table.function_name }}列表"""
     {{ underscore(table.class_name) }}_entity = {{ table.class_name }}()
     # 转换PO到Entity对象
     for attr in dto.model_fields.keys():
         if hasattr({{ underscore(table.class_name) }}_entity, attr):
             setattr({{ underscore(table.class_name) }}_entity, attr, getattr(dto, attr))
-    {{ table.business_name }}s, total = {{ table.class_name|lower }}_service.select_{{ table.business_name }}_list({{ underscore(table.class_name) }}_entity)
-    return TableResponse(code=HttpStatus.SUCCESS, msg='查询成功', rows={{ table.business_name }}s, total=total)
+{%- if is_tree %}
+    {{ underscore(table.class_name) }}_entity.page_num = None
+    {{ underscore(table.class_name) }}_entity.page_size = None
+{%- endif %}
+    {{ underscore(table.business_name) }}s, total = {{ underscore(table.class_name) }}_service.select_{{ underscore(table.class_name) }}_list({{ underscore(table.class_name) }}_entity)
+    return TableResponse(code=HttpStatus.SUCCESS, msg='查询成功', rows={{ underscore(table.business_name) }}s, total=total)
 
 {% if table.pk_column %}
 @gen.route('/<int:{{ underscore(table.pk_column.java_field) }}>', methods=['GET'])
 @PathValidator()
 @PreAuthorize(HasPerm('{{ table.module_name }}:{{ table.business_name }}:query'))
 @JsonSerializer()
-def get_{{ table.business_name }}({{ underscore(table.pk_column.java_field) }}: int):
+def get_{{ underscore(table.business_name) }}({{ underscore(table.pk_column.java_field) }}: int):
     """获取{{ table.function_name }}详细信息"""
-    {{ underscore(table.class_name) }}_entity = {{ table.class_name|lower }}_service.select_{{ table.business_name }}_by_id({{ underscore(table.pk_column.java_field) }})
+    {{ underscore(table.class_name) }}_entity = {{ underscore(table.class_name) }}_service.select_{{ underscore(table.class_name) }}_by_id({{ underscore(table.pk_column.java_field) }})
     return AjaxResponse.from_success(data={{ underscore(table.class_name) }}_entity)
 {% endif %}
 
@@ -45,30 +54,34 @@ def get_{{ table.business_name }}({{ underscore(table.pk_column.java_field) }}:
 @BodyValidator()
 @PreAuthorize(HasPerm('{{ table.module_name }}:{{ table.business_name }}:add'))
 @JsonSerializer()
-def add_{{ table.business_name }}(dto: {{ underscore(table.class_name) }}_po):
+def add_{{ underscore(table.business_name) }}(dto: {{ table.class_name }}):
     """新增{{ table.function_name }}"""
     {{ underscore(table.class_name) }}_entity = {{ table.class_name }}()
     # 转换PO到Entity对象
     for attr in dto.model_fields.keys():
         if hasattr({{ underscore(table.class_name) }}_entity, attr):
             setattr({{ underscore(table.class_name) }}_entity, attr, getattr(dto, attr))
-    result = {{ table.class_name|lower }}_service.insert_{{ table.business_name }}({{ underscore(table.class_name) }}_entity)
-    return AjaxResponse.from_success(msg='新增成功' if result > 0 else '新增失败')
+    result = {{ underscore(table.class_name) }}_service.insert_{{ underscore(table.class_name) }}({{ underscore(table.class_name) }}_entity)
+    if result > 0:
+        return AjaxResponse.from_success(msg='新增成功')
+    return AjaxResponse.from_error(code=HttpStatus.ERROR, msg='新增失败')
 
 {% if table.pk_column %}
 @gen.route('', methods=['PUT'])
 @BodyValidator()
 @PreAuthorize(HasPerm('{{ table.module_name }}:{{ table.business_name }}:edit'))
 @JsonSerializer()
-def update_{{ table.business_name }}(dto: {{ underscore(table.class_name) }}_po):
+def update_{{ underscore(table.business_name) }}(dto: {{ table.class_name }}):
     """修改{{ table.function_name }}"""
     {{ underscore(table.class_name) }}_entity = {{ table.class_name }}()
     # 转换PO到Entity对象
     for attr in dto.model_fields.keys():
         if hasattr({{ underscore(table.class_name) }}_entity, attr):
             setattr({{ underscore(table.class_name) }}_entity, attr, getattr(dto, attr))
-    result = {{ table.class_name|lower }}_service.update_{{ table.business_name }}({{ underscore(table.class_name) }}_entity)
-    return AjaxResponse.from_success(msg='修改成功' if result > 0 else '修改失败')
+    result = {{ underscore(table.class_name) }}_service.update_{{ underscore(table.class_name) }}({{ underscore(table.class_name) }}_entity)
+    if result > 0:
+        return AjaxResponse.from_success(msg='修改成功')
+    return AjaxResponse.from_error(code=HttpStatus.ERROR, msg='修改失败')
 {% endif %}
 
 {% if table.pk_column %}
@@ -76,12 +89,14 @@ def update_{{ table.business_name }}(dto: {{ underscore(table.class_name) }}_po)
 @PathValidator()
 @PreAuthorize(HasPerm('{{ table.module_name }}:{{ table.business_name }}:remove'))
 @JsonSerializer()
-def delete_{{ table.business_name }}(ids: str):
+def delete_{{ underscore(table.business_name) }}(ids: str):
     """删除{{ table.function_name }}"""
     try:
         id_list = [int(id) for id in ids.split(',')]
-        result = {{ table.class_name|lower }}_service.delete_{{ table.business_name }}_by_ids(id_list)
-        return AjaxResponse.from_success(msg='删除成功' if result > 0 else '删除失败')
+        result = {{ underscore(table.class_name) }}_service.delete_{{ underscore(table.class_name) }}_by_ids(id_list)
+        if result > 0:
+            return AjaxResponse.from_success(msg='删除成功')
+        return AjaxResponse.from_error(code=HttpStatus.ERROR, msg='删除失败')
     except Exception as e:
         return AjaxResponse.from_error(msg=f'删除失败: {str(e)}')
 {% endif %}
@@ -90,17 +105,17 @@ def delete_{{ table.business_name }}(ids: str):
 @FileDownloadValidator()
 @QueryValidator()
 @PreAuthorize(HasPerm('{{ table.module_name }}:{{ table.business_name }}:export'))
-def export_{{ table.business_name }}(dto: {{ underscore(table.class_name) }}_po):
+def export_{{ underscore(table.business_name) }}(dto: {{ table.class_name }}):
     """导出{{ table.function_name }}列表"""
     {{ underscore(table.class_name) }}_entity = {{ table.class_name }}()
     # 转换PO到Entity对象
     for attr in dto.model_fields.keys():
         if hasattr({{ underscore(table.class_name) }}_entity, attr):
             setattr({{ underscore(table.class_name) }}_entity, attr, getattr(dto, attr))
-    {{ table.business_name }}s, total = {{ table.class_name|lower }}_service.select_{{ table.business_name }}_list({{ underscore(table.class_name) }}_entity)
+    {{ underscore(table.business_name) }}s, total = {{ underscore(table.class_name) }}_service.select_{{ underscore(table.class_name) }}_list({{ underscore(table.class_name) }}_entity)
     # 使用ExcelUtil导出Excel文件
     excel_util = ExcelUtil({{ underscore(table.class_name) }}_po)
-    return excel_util.export_response({{ table.business_name }}s, "{{ table.function_name }}数据")
+    return excel_util.export_response({{ underscore(table.business_name) }}s, "{{ table.function_name }}数据")
 
 @gen.route('/importTemplate', methods=['POST'])
 @FileDownloadValidator()
@@ -129,16 +144,16 @@ def import_data():
         po_list = excel_util.import_file(file, sheetname="{{ table.function_name }}数据")
         
         # 转换为Entity对象列表
-        {{ table.business_name }}_list = []
+        {{ underscore(table.business_name) }}_list = []
         for po in po_list:
             {{ underscore(table.class_name) }}_entity = {{ table.class_name }}()
             for attr in po.model_fields.keys():
                 if hasattr({{ underscore(table.class_name) }}_entity, attr):
                     setattr({{ underscore(table.class_name) }}_entity, attr, getattr(po, attr))
-            {{ table.business_name }}_list.append({{ underscore(table.class_name) }}_entity)
+            {{ underscore(table.business_name) }}_list.append({{ underscore(table.class_name) }}_entity)
         
         # 调用Service层处理导入逻辑
-        msg = {{ table.class_name|lower }}_service.import_{{ table.business_name }}({{ table.business_name }}_list, update_support)
+        msg = {{ underscore(table.class_name) }}_service.import_{{ underscore(table.class_name) }}({{ underscore(table.business_name) }}_list, update_support)
         return AjaxResponse.from_success(msg=msg)
     except Exception as e:
         return AjaxResponse.from_error(msg=f'导入失败: {str(e)}')

+ 9 - 4
ruoyi_generator/vm/py/entity.py.vm

@@ -3,10 +3,11 @@
 # @FileName: {{ table.class_name }}.py
 # @Time    : {{ datetime }}
 
-from typing import Optional
+from typing import Optional, Annotated
 from datetime import datetime
-from pydantic import Field
+from pydantic import Field, BeforeValidator
 from ruoyi_common.base.model import BaseEntity
+from ruoyi_common.base.transformer import to_datetime
 
 class {{ table.class_name }}(BaseEntity):
     """
@@ -30,9 +31,13 @@ class {{ table.class_name }}(BaseEntity):
     {{ underscore(column.java_field) }}: Optional[bool] = Field(default=None, description="{{ column.column_comment }}")
 {%- elif column.java_type == 'Date' or column.java_type == 'DateTime' %}
     # {{ column.column_comment }}
-    {{ underscore(column.java_field) }}: Optional[datetime] = Field(default=None, description="{{ column.column_comment }}")
+    {{ underscore(column.java_field) }}: Annotated[Optional[datetime], BeforeValidator(to_datetime())] = Field(default=None, description="{{ column.column_comment }}")
 {%- else %}
     # {{ column.column_comment }}
     {{ underscore(column.java_field) }}: Optional[str] = Field(default=None, description="{{ column.column_comment }}")
 {%- endif %}
-{%- endfor %}
+{%- endfor %}
+    # 页码
+    page_num: Optional[int] = Field(default=1, description="页码")
+    # 每页数量
+    page_size: Optional[int] = Field(default=10, description="每页数量")

+ 63 - 43
ruoyi_generator/vm/py/mapper.py.vm

@@ -10,77 +10,75 @@ from sqlalchemy import select, update, delete, func
 
 from ruoyi_admin.ext import db
 from {{ get_import_path(table.package_name, table.module_name, 'domain') }} import {{ table.class_name }}
+from {{ get_import_path(table.package_name, table.module_name, 'domain', table.class_name) }} import {{ underscore(table.class_name) }}_po
 
-class {{ table.class_name }}Mapper:
+class {{ underscore(table.class_name) }}_mapper:
     """{{ table.function_name }}Mapper"""
 
     @staticmethod
-    def select_list({{ table.business_name }}: {{ table.class_name }}) -> List[{{ table.class_name }}]:
+    def select_{{ underscore(table.class_name) }}_list({{ underscore(table.business_name) }}: {{ table.class_name }}) -> List[{{ table.class_name }}]:
         """
         查询{{ table.function_name }}列表
 
         Args:
-            {{ table.business_name }} ({{ table.class_name }}): {{ table.function_name }}对象
+            {{ underscore(table.business_name) }} ({{ table.class_name }}): {{ table.function_name }}对象
 
         Returns:
             List[{{ table.class_name }}]: {{ table.function_name }}列表
         """
         try:
             # 构建查询条件
-            stmt = select({{ table.class_name }})
+            stmt = select({{ underscore(table.class_name) }}_po)
 {% for column in table.columns %}
 {% if column.is_query and column.query_type == 'EQ' %}
-            if {{ table.business_name }}.{{ underscore(column.java_field) }} is not None:
-                stmt = stmt.where({{ table.class_name }}.{{ underscore(column.java_field) }} == {{ table.business_name }}.{{ underscore(column.java_field) }})
+            if {{ underscore(table.business_name) }}.{{ underscore(column.java_field) }} is not None:
+                stmt = stmt.where({{ underscore(table.class_name) }}_po.{{ underscore(column.java_field) }} == {{ underscore(table.business_name) }}.{{ underscore(column.java_field) }})
 {% elif column.is_query and column.query_type == 'LIKE' %}
-            if {{ table.business_name }}.{{ underscore(column.java_field) }}:
-                stmt = stmt.where({{ table.class_name }}.{{ underscore(column.java_field) }}.like("%" + str({{ table.business_name }}.{{ underscore(column.java_field) }}) + "%"))
+            if {{ underscore(table.business_name) }}.{{ underscore(column.java_field) }}:
+                stmt = stmt.where({{ underscore(table.class_name) }}_po.{{ underscore(column.java_field) }}.like("%" + str({{ underscore(table.business_name) }}.{{ underscore(column.java_field) }}) + "%"))
 {% endif %}
 {% endfor %}
-
             # 添加分页条件
-            if {{ table.business_name }}.page_num and {{ table.business_name }}.page_size:
-                offset = ({{ table.business_name }}.page_num - 1) * {{ table.business_name }}.page_size
-                stmt = stmt.offset(offset).limit({{ table.business_name }}.page_size)
+            if {{ underscore(table.business_name) }}.page_num and {{ underscore(table.business_name) }}.page_size:
+                offset = ({{ underscore(table.business_name) }}.page_num - 1) * {{ underscore(table.business_name) }}.page_size
+                stmt = stmt.offset(offset).limit({{ underscore(table.business_name) }}.page_size)
 
             result = db.session.execute(stmt).scalars().all()
-            return list(result) if result else []
+            return [{{ table.class_name }}.model_validate(item) for item in result] if result else []
         except Exception as e:
             print(f"查询{{ table.function_name }}列表出错: {e}")
             return []
 
     @staticmethod
-    def select_count({{ table.business_name }}: {{ table.class_name }}) -> int:
+    def select_{{ underscore(table.class_name) }}_count({{ underscore(table.business_name) }}: {{ table.class_name }}) -> int:
         """
         查询{{ table.function_name }}总数
 
         Args:
-            {{ table.business_name }} ({{ table.class_name }}): {{ table.function_name }}对象
+            {{ underscore(table.business_name) }} ({{ table.class_name }}): {{ table.function_name }}对象
 
         Returns:
             int: {{ table.function_name }}总数
         """
         try:
-            stmt = select(func.count({{ table.class_name }}.{{ underscore(table.pk_column.java_field) if table.pk_column }}))
+            stmt = select(func.count()).select_from({{ underscore(table.class_name) }}_po)
 {% for column in table.columns %}
 {% if column.is_query and column.query_type == 'EQ' %}
-            if {{ table.business_name }}.{{ underscore(column.java_field) }} is not None:
-                stmt = stmt.where({{ table.class_name }}.{{ underscore(column.java_field) }} == {{ table.business_name }}.{{ underscore(column.java_field) }})
+            if {{ underscore(table.business_name) }}.{{ underscore(column.java_field) }} is not None:
+                stmt = stmt.where({{ underscore(table.class_name) }}_po.{{ underscore(column.java_field) }} == {{ underscore(table.business_name) }}.{{ underscore(column.java_field) }})
 {% elif column.is_query and column.query_type == 'LIKE' %}
-            if {{ table.business_name }}.{{ underscore(column.java_field) }}:
-                stmt = stmt.where({{ table.class_name }}.{{ underscore(column.java_field) }}.like("%" + str({{ table.business_name }}.{{ underscore(column.java_field) }}) + "%"))
+            if {{ underscore(table.business_name) }}.{{ underscore(column.java_field) }}:
+                stmt = stmt.where({{ underscore(table.class_name) }}_po.{{ underscore(column.java_field) }}.like("%" + str({{ underscore(table.business_name) }}.{{ underscore(column.java_field) }}) + "%"))
 {% endif %}
 {% endfor %}
-
             result = db.session.execute(stmt).scalar()
             return result if result else 0
         except Exception as e:
             print(f"查询{{ table.function_name }}总数出错: {e}")
             return 0
-
     {% if table.pk_column %}
     @staticmethod
-    def select_by_id({{ underscore(table.pk_column.java_field) }}: int) -> {{ table.class_name }}:
+    def select_{{ underscore(table.class_name) }}_by_id({{ underscore(table.pk_column.java_field) }}: int) -> {{ table.class_name }}:
         """
         根据ID查询{{ table.function_name }}
 
@@ -91,33 +89,40 @@ class {{ table.class_name }}Mapper:
             {{ table.class_name }}: {{ table.function_name }}对象
         """
         try:
-            stmt = select({{ table.class_name }}).where({{ table.class_name }}.{{ underscore(table.pk_column.java_field) }} == {{ underscore(table.pk_column.java_field) }})
-            result = db.session.execute(stmt).scalar_one_or_none()
-            return result
+            result = db.session.get({{ underscore(table.class_name) }}_po, {{ underscore(table.pk_column.java_field) }})
+            return {{ table.class_name }}.model_validate(result) if result else None
         except Exception as e:
             print(f"根据ID查询{{ table.function_name }}出错: {e}")
             return None
     {% endif %}
 
     @staticmethod
-    def insert({{ table.business_name }}: {{ table.class_name }}) -> int:
+    def insert_{{ underscore(table.class_name) }}({{ underscore(table.business_name) }}: {{ table.class_name }}) -> int:
         """
         新增{{ table.function_name }}
 
         Args:
-            {{ table.business_name }} ({{ table.class_name }}): {{ table.function_name }}对象
+            {{ underscore(table.business_name) }} ({{ table.class_name }}): {{ table.function_name }}对象
 
         Returns:
             int: 插入的记录数
         """
         try:
-            # 设置创建时间和更新时间
             now = datetime.now()
-            {{ table.business_name }}.create_time = now
-            {{ table.business_name }}.update_time = now
-
-            db.session.add({{ table.business_name }})
+            new_po = {{ underscore(table.class_name) }}_po()
+{%- for column in table.columns %}
+{%- set attr = underscore(column.java_field) %}
+{%- if column.column_name in ['create_time', 'update_time'] %}
+            new_po.{{ attr }} = {{ underscore(table.business_name) }}.{{ attr }} or now
+{%- else %}
+            new_po.{{ attr }} = {{ underscore(table.business_name) }}.{{ attr }}
+{%- endif %}
+{%- endfor %}
+            db.session.add(new_po)
             db.session.commit()
+{%- if table.pk_column %}
+            {{ underscore(table.business_name) }}.{{ underscore(table.pk_column.java_field) }} = new_po.{{ underscore(table.pk_column.java_field) }}
+{%- endif %}
             return 1
         except Exception as e:
             db.session.rollback()
@@ -126,31 +131,46 @@ class {{ table.class_name }}Mapper:
 
     {% if table.pk_column %}
     @staticmethod
-    def update({{ table.business_name }}: {{ table.class_name }}) -> int:
+    def update_{{ underscore(table.class_name) }}({{ underscore(table.business_name) }}: {{ table.class_name }}) -> int:
         """
         修改{{ table.function_name }}
 
         Args:
-            {{ table.business_name }} ({{ table.class_name }}): {{ table.function_name }}对象
+            {{ underscore(table.business_name) }} ({{ table.class_name }}): {{ table.function_name }}对象
 
         Returns:
             int: 更新的记录数
         """
         try:
-            # 设置更新时间
-            {{ table.business_name }}.update_time = datetime.now()
-
-            # 使用ORM方式更新数据
-            db.session.merge({{ table.business_name }})
+            {% if table.pk_column %}
+            existing = db.session.get({{ underscore(table.class_name) }}_po, {{ underscore(table.business_name) }}.{{ underscore(table.pk_column.java_field) }})
+            if not existing:
+                return 0
+            now = datetime.now()
+{%- for column in table.columns %}
+{%- set attr = underscore(column.java_field) %}
+{%- if column.is_pk == '1' %}
+            # 主键不参与更新
+{%- elif column.column_name == 'update_time' %}
+            existing.{{ attr }} = {{ underscore(table.business_name) }}.{{ attr }} or now
+{%- else %}
+            existing.{{ attr }} = {{ underscore(table.business_name) }}.{{ attr }}
+{%- endif %}
+{%- endfor %}
+            db.session.commit()
+            return 1
+            {% else %}
+            db.session.merge({{ underscore(table.business_name) }})
             db.session.commit()
             return 1
+            {% endif %}
         except Exception as e:
             db.session.rollback()
             print(f"修改{{ table.function_name }}出错: {e}")
             return 0
 
     @staticmethod
-    def delete_by_ids(ids: List[int]) -> int:
+    def delete_{{ underscore(table.class_name) }}_by_ids(ids: List[int]) -> int:
         """
         批量删除{{ table.function_name }}
 
@@ -161,7 +181,7 @@ class {{ table.class_name }}Mapper:
             int: 删除的记录数
         """
         try:
-            stmt = delete({{ table.class_name }}).where({{ table.class_name }}.{{ underscore(table.pk_column.java_field) }}.in_(ids))
+            stmt = delete({{ underscore(table.class_name) }}_po).where({{ underscore(table.class_name) }}_po.{{ underscore(table.pk_column.java_field) }}.in_(ids))
             result = db.session.execute(stmt)
             db.session.commit()
             return result.rowcount
@@ -169,4 +189,4 @@ class {{ table.class_name }}Mapper:
             db.session.rollback()
             print(f"批量删除{{ table.function_name }}出错: {e}")
             return 0
-    {% endif %}
+    {% endif %}

+ 76 - 27
ruoyi_generator/vm/py/po.py.vm

@@ -3,41 +3,90 @@
 # @FileName: {{ underscore(table.class_name) }}_po.py
 # @Time    : {{ datetime }}
 
-from typing import Optional, Union
+from typing import Optional
 from datetime import datetime
 
-from pydantic import ConfigDict, Field
+from sqlalchemy import BigInteger, Boolean, Date, DateTime, Float, Integer, JSON, LargeBinary, Numeric, String, Text, Time
+from sqlalchemy.orm import Mapped, mapped_column
 
-from ruoyi_common.base.model import BaseEntity
-from ruoyi_common.utils.base import DateUtil
+from ruoyi_admin.ext import db
 
-class {{ underscore(table.class_name) }}_po(BaseEntity):
+class {{ underscore(table.class_name) }}_po(db.Model):
     """
     {{ table.table_comment }}PO对象
     """
-    model_config = ConfigDict(
-        from_attributes=True,
-        json_encoders = {
-            datetime: lambda v: v.strftime(DateUtil.YYYY_MM_DD_HH_MM_SS) if v else None
-        },
-        alias_generator = lambda field: ''.join(['_' + c.lower() if c.isupper() else c for c in field]).lstrip('_')
-    )
+    __tablename__ = '{{ table.table_name }}'
+    __table_args__ = {'comment': '{{ table.table_comment }}'}
 
 {%- for column in table.columns %}
-{%- if column.java_type == 'String' or column.java_type == 'str' %}
-    {{ underscore(column.java_field) }}: Optional[str] = Field(None, alias='{{ column.java_field }}')
-{%- elif column.java_type == 'Integer' or column.java_type == 'int' %}
-    {{ underscore(column.java_field) }}: Optional[int] = Field(None, alias='{{ column.java_field }}')
-{%- elif column.java_type == 'Long' %}
-    {{ underscore(column.java_field) }}: Optional[int] = Field(None, alias='{{ column.java_field }}')
-{%- elif column.java_type == 'Float' or column.java_type == 'Double' %}
-    {{ underscore(column.java_field) }}: Optional[float] = Field(None, alias='{{ column.java_field }}')
-{%- elif column.java_type == 'Boolean' or column.java_type == 'bool' %}
-    {{ underscore(column.java_field) }}: Optional[bool] = Field(None, alias='{{ column.java_field }}')
+{%- set raw_type = (column.column_type or 'varchar(255)')|lower %}
+{%- if '(' in raw_type %}
+{%- set base_type = raw_type.split('(')[0] %}
+{%- set arg_string = raw_type.split('(')[1].split(')')[0] %}
+{%- else %}
+{%- set base_type = raw_type %}
+{%- set arg_string = '' %}
+{%- endif %}
+{%- set args = arg_string.split(',') if arg_string else [] %}
+{%- set length = args[0].strip() if args and args[0] else '' %}
+{%- set precision = args[0].strip() if args and args[0] else '' %}
+{%- set scale = args[1].strip() if args|length > 1 else '' %}
+{%- set attr_name = underscore(column.java_field) %}
+{%- set nullable_flag = 'False' if column.is_required == '1' else 'True' %}
+{%- set py_type = 'Optional[str]' %}
+{%- if column.java_type in ['Integer', 'int'] %}
+{%- set py_type = 'Optional[int]' %}
+{%- elif column.java_type in ['Long'] %}
+{%- set py_type = 'Optional[int]' %}
+{%- elif column.java_type in ['Float', 'Double'] %}
+{%- set py_type = 'Optional[float]' %}
+{%- elif column.java_type in ['Boolean', 'bool'] %}
+{%- set py_type = 'Optional[bool]' %}
+{%- elif column.java_type in ['Date', 'DateTime'] %}
+{%- set py_type = 'Optional[datetime]' %}
+{%- endif %}
+{%- if column.is_pk == '1' %}
+{%- set py_type = 'int' %}
+{%- set nullable_flag = 'False' %}
+{%- endif %}
+{%- set type_expr = 'String(255)' %}
+{%- if base_type in ['varchar', 'char', 'nvarchar'] %}
+{%- set type_expr = 'String(' ~ (length or '255') ~ ')' %}
+{%- elif base_type in ['text', 'mediumtext', 'longtext'] %}
+{%- set type_expr = 'Text' %}
+{%- elif base_type in ['int', 'integer', 'smallint', 'mediumint'] %}
+{%- set type_expr = 'Integer' %}
+{%- elif base_type in ['tinyint'] %}
+{%- if column.java_type in ['Boolean', 'bool'] %}
+{%- set type_expr = 'Boolean' %}
 {%- else %}
-    {{ underscore(column.java_field) }}: Optional[str] = Field(None, alias='{{ column.java_field }}')
+{%- set type_expr = 'Integer' %}
+{%- endif %}
+{%- elif base_type in ['bigint'] %}
+{%- set type_expr = 'BigInteger' %}
+{%- elif base_type in ['float', 'double'] %}
+{%- set type_expr = 'Float' %}
+{%- elif base_type in ['decimal', 'numeric'] %}
+{%- set type_expr = 'Numeric(' ~ (precision or '10') ~ (', ' ~ scale if scale else ', 0') ~ ')' %}
+{%- elif base_type in ['date'] %}
+{%- set type_expr = 'Date' %}
+{%- elif base_type in ['datetime', 'timestamp'] %}
+{%- set type_expr = 'DateTime' %}
+{%- elif base_type in ['time'] %}
+{%- set type_expr = 'Time' %}
+{%- elif base_type in ['json'] %}
+{%- set type_expr = 'JSON' %}
+{%- elif base_type in ['blob', 'longblob', 'mediumblob'] %}
+{%- set type_expr = 'LargeBinary' %}
 {%- endif %}
-{%- endfor %}
-    # 分页参数
-    page_num: Optional[int] = Field(None, alias='pageNum')
-    page_size: Optional[int] = Field(None, alias='pageSize')
+    {{ attr_name }}: Mapped[{{ py_type }}] = mapped_column(
+        '{{ column.column_name }}',
+        {{ type_expr }},
+{%- if column.is_pk == '1' %}
+        primary_key=True,
+        autoincrement={{ 'True' if column.is_increment == '1' else 'False' }},
+{%- endif %}
+        nullable={{ nullable_flag }},
+        comment='{{ column.column_comment | replace("'", "\\'") if column.column_comment else '' }}'
+    )
+{%- endfor %}

+ 24 - 24
ruoyi_generator/vm/py/service.py.vm

@@ -6,27 +6,27 @@
 from typing import List, Tuple
 
 from {{ get_import_path(table.package_name, table.module_name, 'domain') }} import {{ table.class_name }}
-from {{ get_import_path(table.package_name, table.module_name, 'mapper') }}.{{ underscore(table.class_name) }}_mapper import {{ table.class_name }}Mapper
+from {{ get_import_path(table.package_name, table.module_name, 'mapper') }}.{{ underscore(table.class_name) }}_mapper import {{ underscore(table.class_name) }}_mapper
 
-class {{ table.class_name }}Service:
+class {{ underscore(table.class_name) }}_service:
     """{{ table.function_name }}服务类"""
 
-    def select_{{ table.business_name }}_list(self, {{ table.business_name }}: {{ table.class_name }}) -> Tuple[List[{{ table.class_name }}], int]:
+    def select_{{ underscore(table.class_name) }}_list(self, {{ underscore(table.business_name) }}: {{ table.class_name }}) -> Tuple[List[{{ table.class_name }}], int]:
         """
         查询{{ table.function_name }}列表
 
         Args:
-            {{ table.business_name }} ({{ table.class_name }}): {{ table.function_name }}对象
+            {{ underscore(table.business_name) }} ({{ table.class_name }}): {{ table.function_name }}对象
 
         Returns:
             Tuple[List[{{ table.class_name }}], int]: {{ table.function_name }}列表和总数
         """
-        list_result = {{ table.class_name }}Mapper.select_list({{ table.business_name }})
-        count_result = {{ table.class_name }}Mapper.select_count({{ table.business_name }})
+        list_result = {{ underscore(table.class_name) }}_mapper.select_{{ underscore(table.class_name) }}_list({{ underscore(table.business_name) }})
+        count_result = {{ underscore(table.class_name) }}_mapper.select_{{ underscore(table.class_name) }}_count({{ underscore(table.business_name) }})
         return list_result, count_result
 
     {% if table.pk_column %}
-    def select_{{ table.business_name }}_by_id(self, {{ underscore(table.pk_column.java_field) }}: int) -> {{ table.class_name }}:
+    def select_{{ underscore(table.class_name) }}_by_id(self, {{ underscore(table.pk_column.java_field) }}: int) -> {{ table.class_name }}:
         """
         根据ID查询{{ table.function_name }}
 
@@ -36,37 +36,37 @@ class {{ table.class_name }}Service:
         Returns:
             {{ table.class_name }}: {{ table.function_name }}对象
         """
-        return {{ table.class_name }}Mapper.select_by_id({{ underscore(table.pk_column.java_field) }})
+        return {{ underscore(table.class_name) }}_mapper.select_{{ underscore(table.class_name) }}_by_id({{ underscore(table.pk_column.java_field) }})
     {% endif %}
 
-    def insert_{{ table.business_name }}(self, {{ table.business_name }}: {{ table.class_name }}) -> int:
+    def insert_{{ underscore(table.class_name) }}(self, {{ underscore(table.business_name) }}: {{ table.class_name }}) -> int:
         """
         新增{{ table.function_name }}
 
         Args:
-            {{ table.business_name }} ({{ table.class_name }}): {{ table.function_name }}对象
+            {{ underscore(table.business_name) }} ({{ table.class_name }}): {{ table.function_name }}对象
 
         Returns:
             int: 插入的记录数
         """
-        return {{ table.class_name }}Mapper.insert({{ table.business_name }})
+        return {{ underscore(table.class_name) }}_mapper.insert_{{ underscore(table.class_name) }}({{ underscore(table.business_name) }})
 
     {% if table.pk_column %}
-    def update_{{ table.business_name }}(self, {{ table.business_name }}: {{ table.class_name }}) -> int:
+    def update_{{ underscore(table.class_name) }}(self, {{ underscore(table.business_name) }}: {{ table.class_name }}) -> int:
         """
         修改{{ table.function_name }}
 
         Args:
-            {{ table.business_name }} ({{ table.class_name }}): {{ table.function_name }}对象
+            {{ underscore(table.business_name) }} ({{ table.class_name }}): {{ table.function_name }}对象
 
         Returns:
             int: 更新的记录数
         """
-        return {{ table.class_name }}Mapper.update({{ table.business_name }})
+        return {{ underscore(table.class_name) }}_mapper.update_{{ underscore(table.class_name) }}({{ underscore(table.business_name) }})
     {% endif %}
 
     {% if table.pk_column %}
-    def delete_{{ table.business_name }}_by_ids(self, ids: List[int]) -> int:
+    def delete_{{ underscore(table.class_name) }}_by_ids(self, ids: List[int]) -> int:
         """
         批量删除{{ table.function_name }}
 
@@ -76,36 +76,36 @@ class {{ table.class_name }}Service:
         Returns:
             int: 删除的记录数
         """
-        return {{ table.class_name }}Mapper.delete_by_ids(ids)
+        return {{ underscore(table.class_name) }}_mapper.delete_{{ underscore(table.class_name) }}_by_ids(ids)
     {% endif %}
 
-    def import_{{ table.business_name }}(self, {{ table.business_name }}_list: List[{{ table.class_name }}], update_support: bool = False) -> str:
+    def import_{{ underscore(table.class_name) }}(self, {{ underscore(table.business_name) }}_list: List[{{ table.class_name }}], update_support: bool = False) -> str:
         """
         导入{{ table.function_name }}数据
 
         Args:
-            {{ table.business_name }}_list (List[{{ table.class_name }}]): {{ table.function_name }}列表
+            {{ underscore(table.business_name) }}_list (List[{{ table.class_name }}]): {{ table.function_name }}列表
             update_support (bool): 是否更新已存在的数据
 
         Returns:
             str: 导入结果消息
         """
-        if not {{ table.business_name }}_list:
+        if not {{ underscore(table.business_name) }}_list:
             raise Exception("导入{{ table.function_name }}数据不能为空")
         
         success_count = 0
         failure_count = 0
         failure_msg = []
         
-        for index, {{ table.business_name }} in enumerate({{ table.business_name }}_list):
+        for index, {{ underscore(table.business_name) }} in enumerate({{ underscore(table.business_name) }}_list):
             try:
                 {% if table.pk_column %}
                 # 检查是否已存在
-                existing = {{ table.class_name }}Mapper.select_by_id({{ table.business_name }}.{{ underscore(table.pk_column.java_field) }})
+                existing = {{ underscore(table.class_name) }}_mapper.select_{{ underscore(table.class_name) }}_by_id({{ underscore(table.business_name) }}.{{ underscore(table.pk_column.java_field) }})
                 if existing:
                     if update_support:
                         # 更新数据
-                        result = {{ table.class_name }}Mapper.update({{ table.business_name }})
+                        result = {{ underscore(table.class_name) }}_mapper.update_{{ underscore(table.class_name) }}({{ underscore(table.business_name) }})
                         if result > 0:
                             success_count += 1
                         else:
@@ -116,7 +116,7 @@ class {{ table.class_name }}Service:
                         failure_msg.append(f"第{index + 2}行数据已存在")
                 else:
                     # 新增数据
-                    result = {{ table.class_name }}Mapper.insert({{ table.business_name }})
+                    result = {{ underscore(table.class_name) }}_mapper.insert_{{ underscore(table.class_name) }}({{ underscore(table.business_name) }})
                     if result > 0:
                         success_count += 1
                     else:
@@ -124,7 +124,7 @@ class {{ table.class_name }}Service:
                         failure_msg.append(f"第{index + 2}行导入失败")
                 {% else %}
                 # 没有主键,直接插入
-                result = {{ table.class_name }}Mapper.insert({{ table.business_name }})
+                result = {{ underscore(table.class_name) }}_mapper.insert_{{ underscore(table.class_name) }}({{ underscore(table.business_name) }})
                 if result > 0:
                     success_count += 1
                 else:

+ 66 - 65
ruoyi_generator/vm/vue/index-tree.vue.vm

@@ -1,3 +1,8 @@
+{%- if table.pk_column %}
+{%- set pk_field = table.pk_column.java_field %}
+{%- else %}
+{%- set pk_field = 'id' %}
+{%- endif %}
 <template>
   <div class="app-container">
     <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
@@ -96,7 +101,7 @@
       v-if="refreshTable"
       :loading="loading"
       :data="{{ table.business_name }}List"
-      row-key="{% if table.tree_code %}{{ table.tree_code }}{% else %}id{% endif %}"
+      row-key="{{ pk_field }}"
       :default-expand-all="isExpandAll"
       :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
     >
@@ -126,7 +131,7 @@
   {%- elif column.is_list and column.list_index is not none and column.html_type == 'fileUpload' %}
       <el-table-column label="{{ comment }}" align="center" v-if="columns[{{ column.list_index }}].visible" prop="{{ java_field }}" width="100">
         <template slot-scope="scope">
-          <div v-if="scope.row.{{ underscore(java_field) }}">
+          <div v-if="scope.row.{{ java_field }}">
             <el-tooltip placement="top" effect="light">
               <div slot="content">
                   <div v-for="(file,index) in scope.row.{{ java_field }}.split(',')"
@@ -211,29 +216,29 @@
 {%- endif %}
 {%- endif %}
 {%- set dict_type = column.dict_type if column.dict_type else '' %}
-  {%- if table.tree_parent_code and (underscore(column.java_field) == underscore(table.tree_parent_code) or column.java_field == table.tree_parent_code) %}
-        <el-form-item label="{{ comment }}" prop="{{ underscore(table.tree_parent_code) }}">
-          <treeselect v-model="form.{{ underscore(table.tree_parent_code) }}" :options="{{ table.business_name }}Options" :normalizer="normalizer" placeholder="请选择{{ comment }}" />
+  {%- if column.java_field == tree_parent_field %}
+        <el-form-item label="{{ comment }}" prop="{{ tree_parent_field }}">
+          <treeselect v-model="form.{{ tree_parent_field }}" :options="{{ table.business_name }}Options" :normalizer="normalizer" placeholder="请选择{{ comment }}" />
         </el-form-item>
   {%- elif column.html_type == 'input' %}
-        <el-form-item label="{{ comment }}" prop="{{ underscore(field) }}">
-          <el-input v-model="form.{{ underscore(field) }}" placeholder="请输入{{ comment }}" />
+        <el-form-item label="{{ comment }}" prop="{{ field }}">
+          <el-input v-model="form.{{ field }}" placeholder="请输入{{ comment }}" />
         </el-form-item>
   {%- elif column.html_type == 'imageUpload' %}
-        <el-form-item label="{{ comment }}" prop="{{ underscore(field) }}">
-          <image-upload v-model="form.{{ underscore(field) }}"/>
+        <el-form-item label="{{ comment }}" prop="{{ field }}">
+          <image-upload v-model="form.{{ field }}"/>
         </el-form-item>
   {%- elif column.html_type == 'fileUpload' %}
-        <el-form-item label="{{ comment }}" prop="{{ underscore(field) }}">
-          <file-upload v-model="form.{{ underscore(field) }}"/>
+        <el-form-item label="{{ comment }}" prop="{{ field }}">
+          <file-upload v-model="form.{{ field }}"/>
         </el-form-item>
   {%- elif column.html_type == 'editor' %}
         <el-form-item label="{{ comment }}">
-          <editor v-model="form.{{ underscore(field) }}" :min-height="192"/>
+          <editor v-model="form.{{ field }}" :min-height="192"/>
         </el-form-item>
   {%- elif column.html_type == 'select' and dict_type != '' %}
-        <el-form-item label="{{ comment }}" prop="{{ underscore(field) }}">
-          <el-select v-model="form.{{ underscore(field) }}" placeholder="请选择{{ comment }}">
+        <el-form-item label="{{ comment }}" prop="{{ field }}">
+          <el-select v-model="form.{{ field }}" placeholder="请选择{{ comment }}">
             <el-option
               v-for="dict in dict.type.{{ dict_type }}"
               :key="dict.value"
@@ -247,14 +252,14 @@
           </el-select>
         </el-form-item>
   {%- elif column.html_type == 'select' and dict_type == '' %}
-        <el-form-item label="{{ comment }}" prop="{{ underscore(field) }}">
-          <el-select v-model="form.{{ underscore(field) }}" placeholder="请选择{{ comment }}">
+        <el-form-item label="{{ comment }}" prop="{{ field }}">
+          <el-select v-model="form.{{ field }}" placeholder="请选择{{ comment }}">
             <el-option label="请选择字典生成" value="" />
           </el-select>
         </el-form-item>
   {%- elif column.html_type == 'checkbox' and dict_type != '' %}
-        <el-form-item label="{{ comment }}" prop="{{ underscore(field) }}">
-          <el-checkbox-group v-model="form.{{ underscore(field) }}">
+        <el-form-item label="{{ comment }}" prop="{{ field }}">
+          <el-checkbox-group v-model="form.{{ field }}">
             <el-checkbox
               v-for="dict in dict.type.{{ dict_type }}"
               :key="dict.value"
@@ -264,14 +269,14 @@
           </el-checkbox-group>
         </el-form-item>
   {%- elif column.html_type == 'checkbox' and dict_type == '' %}
-        <el-form-item label="{{ comment }}" prop="{{ underscore(field) }}">
-          <el-checkbox-group v-model="form.{{ underscore(field) }}">
+        <el-form-item label="{{ comment }}" prop="{{ field }}">
+          <el-checkbox-group v-model="form.{{ field }}">
             <el-checkbox>请选择字典生成</el-checkbox>
           </el-checkbox-group>
         </el-form-item>
   {%- elif column.html_type == 'radio' and dict_type != '' %}
-        <el-form-item label="{{ comment }}" prop="{{ underscore(field) }}">
-          <el-radio-group v-model="form.{{ underscore(field) }}">
+        <el-form-item label="{{ comment }}" prop="{{ field }}">
+          <el-radio-group v-model="form.{{ field }}">
             <el-radio
               v-for="dict in dict.type.{{ dict_type }}"
               :key="dict.value"
@@ -284,23 +289,23 @@
           </el-radio-group>
         </el-form-item>
   {%- elif column.html_type == 'radio' and dict_type == '' %}
-        <el-form-item label="{{ comment }}" prop="{{ underscore(field) }}">
-          <el-radio-group v-model="form.{{ underscore(field) }}">
+        <el-form-item label="{{ comment }}" prop="{{ field }}">
+          <el-radio-group v-model="form.{{ field }}">
             <el-radio label="1">请选择字典生成</el-radio>
           </el-radio-group>
         </el-form-item>
   {%- elif column.html_type == 'datetime' %}
-        <el-form-item label="{{ comment }}" prop="{{ underscore(field) }}">
+        <el-form-item label="{{ comment }}" prop="{{ field }}">
           <el-date-picker clearable
-            v-model="form.{{ underscore(field) }}"
+            v-model="form.{{ field }}"
             type="date"
             value-format="yyyy-MM-dd"
             placeholder="选择{{ comment }}">
           </el-date-picker>
         </el-form-item>
   {%- elif column.html_type == 'textarea' %}
-        <el-form-item label="{{ comment }}" prop="{{ underscore(field) }}">
-          <el-input v-model="form.{{ underscore(field) }}" type="textarea" placeholder="请输入内容" />
+        <el-form-item label="{{ comment }}" prop="{{ field }}">
+          <el-input v-model="form.{{ field }}" type="textarea" placeholder="请输入内容" />
         </el-form-item>
   {%- endif %}
 {%- endif %}
@@ -315,23 +320,19 @@
 </template>
 
 <script>
-{# 使用后端工具函数生成接口前缀:
-   - apiName  : scheduleInfo
-   - ApiName  : ScheduleInfo(listScheduleInfo / getScheduleInfo 等) #}
 {% set apiName = to_camel_case(table.class_name, False) %}
 {% set ApiName = capitalize_first(apiName) %}
 import { list{{ ApiName }}, get{{ ApiName }}, del{{ ApiName }}, add{{ ApiName }}, update{{ ApiName }} } from "@/api/{{ table.module_name }}/{{ table.business_name }}";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
-{%- set has_file_upload = false %}
-{%- for column in table.columns %}
-{%- if column.is_list and column.html_type == 'fileUpload' %}
-{%- set has_file_upload = true %}
-{%- endif %}
-{%- endfor %}
-{%- if has_file_upload %}
+{%- set raw_tree_code = table.tree_code if table.tree_code else 'id' %}
+{%- set raw_tree_parent = table.tree_parent_code if table.tree_parent_code else 'parent_id' %}
+{%- set raw_tree_name = table.tree_name if table.tree_name else 'name' %}
+{%- set tree_code_field = to_camel_case(raw_tree_code, False) %}
+{%- set tree_parent_field = to_camel_case(raw_tree_parent, False) %}
+{%- set tree_name_field = to_camel_case(raw_tree_name, False) %}
 import { getFileName, getFilePath } from '@/utils/ruoyi'
-{%- endif %}
+
 export default {
   name: "{{ table.class_name }}",
 {%- set dicts_list = [] %}
@@ -459,7 +460,7 @@ export default {
 {%- endfor %}
       list{{ ApiName }}(this.queryParams).then(response => {
         const list = Array.isArray(response && response.data) ? response.data : (Array.isArray(response && response.rows) ? response.rows : []);
-        this.{{ table.business_name }}List = this.handleTree(list, "{% if table.tree_code %}{{ table.tree_code }}{% else %}id{% endif %}", "{% if table.tree_parent_code %}{{ table.tree_parent_code }}{% else %}parent_id{% endif %}");
+        this.{{ table.business_name }}List = this.handleTree(list, "{{ tree_code_field }}", "{{ tree_parent_field }}");
         this.loading = false;
       });
     },
@@ -473,8 +474,8 @@ export default {
         delete node.children;
       }
       return {
-        id: node.{% if table.tree_code %}{{ table.tree_code }}{% else %}id{% endif %},
-        label: node.{% if table.tree_name %}{{ table.tree_name }}{% else %}name{% endif %},
+        id: node.{{ tree_code_field }},
+        label: node.{{ tree_name_field }},
         children: node.children
       };
     },
@@ -482,9 +483,9 @@ export default {
     getTreeselect() {
       list{{ ApiName }}().then(response => {
         this.{{ table.business_name }}Options = [];
-        const data = { {% if table.tree_code %}{{ table.tree_code }}{% else %}id{% endif %}: 0, {% if table.tree_name %}{{ table.tree_name }}{% else %}name{% endif %}: '顶级节点', children: [] };
+        const data = { {{ tree_code_field }}: 0, {{ tree_name_field }}: '顶级节点', children: [] };
         const list = Array.isArray(response && response.data) ? response.data : (Array.isArray(response && response.rows) ? response.rows : []);
-        data.children = this.handleTree(list, "{% if table.tree_code %}{{ table.tree_code }}{% else %}id{% endif %}", "{% if table.tree_parent_code %}{{ table.tree_parent_code }}{% else %}parent_id{% endif %}");
+        data.children = this.handleTree(list, "{{ tree_code_field }}", "{{ tree_parent_field }}");
         this.{{ table.business_name }}Options.push(data);
       });
     },
@@ -525,10 +526,10 @@ export default {
     handleAdd(row) {
       this.reset();
       this.getTreeselect();
-      if (row != null && row.{% if table.tree_code %}{{ table.tree_code }}{% else %}id{% endif %}) {
-        this.form.{% if table.tree_parent_code %}{{ table.tree_parent_code }}{% else %}parentId{% endif %} = row.{% if table.tree_code %}{{ table.tree_code }}{% else %}id{% endif %};
+      if (row != null && row.{{ tree_code_field }}) {
+        this.form.{{ tree_parent_field }} = row.{{ tree_code_field }};
       } else {
-        this.form.{% if table.tree_parent_code %}{{ table.tree_parent_code }}{% else %}parentId{% endif %} = 0;
+        this.form.{{ tree_parent_field }} = 0;
       }
       this.open = true;
       this.title = "添加{{ table.function_name }}";
@@ -546,16 +547,16 @@ export default {
       this.reset();
       this.getTreeselect();
       if (row != null) {
-        this.form.{% if table.tree_parent_code %}{{ table.tree_parent_code }}{% else %}parentId{% endif %} = row.{% if table.tree_parent_code %}{{ table.tree_parent_code }}{% else %}parentId{% endif %};
+        this.form.{{ tree_parent_field }} = row.{{ tree_parent_field }};
       }
-      get{{ ApiName }}(row.{% if table.pk_column %}{{ underscore(table.pk_column.java_field) }}{% else %}id{% endif %}).then(response => {
+      get{{ ApiName }}(row.{{ pk_field }}).then(response => {
         this.form = response.data;
 {%- for column in table.columns %}
 {%- if column.html_type == 'checkbox' %}
-        if (this.form.{{ underscore(column.java_field) }}) {
-          this.form.{{ underscore(column.java_field) }} = this.form.{{ underscore(column.java_field) }}.split(",");
+        if (this.form.{{ column.java_field }}) {
+          this.form.{{ column.java_field }} = this.form.{{ column.java_field }}.split(",");
         } else {
-          this.form.{{ underscore(column.java_field) }} = [];
+          this.form.{{ column.java_field }} = [];
         }
 {%- endif %}
 {%- endfor %}
@@ -568,7 +569,7 @@ export default {
       this.$refs["form"].validate(valid => {
         if (valid) {
           const submitData = this.buildSubmitData();
-          if (submitData.{% if table.pk_column %}{{ underscore(table.pk_column.java_field) }}{% else %}id{% endif %} != null) {
+          if (submitData.{{ pk_field }} != null) {
             update{{ ApiName }}(submitData).then(response => {
               this.$modal.msgSuccess("修改成功");
               this.open = false;
@@ -588,23 +589,23 @@ export default {
       const data = { ...this.form };
 {%- for column in table.columns %}
 {%- if column.html_type == 'checkbox' %}
-      if (Array.isArray(data.{{ underscore(column.java_field) }})) {
-        data.{{ underscore(column.java_field) }} = data.{{ underscore(column.java_field) }}.join(",");
-      } else if (data.{{ underscore(column.java_field) }}) {
-        data.{{ underscore(column.java_field) }} = String(data.{{ underscore(column.java_field) }});
+      if (Array.isArray(data.{{ column.java_field }})) {
+        data.{{ column.java_field }} = data.{{ column.java_field }}.join(",");
+      } else if (data.{{ column.java_field }}) {
+        data.{{ column.java_field }} = String(data.{{ column.java_field }});
       }
 {%- endif %}
 {%- if column.java_type in ['Integer', 'Long', 'Short'] %}
-      if (data.{{ underscore(column.java_field) }} !== null && data.{{ underscore(column.java_field) }} !== undefined && data.{{ underscore(column.java_field) }} !== "") {
-        data.{{ underscore(column.java_field) }} = parseInt(data.{{ underscore(column.java_field) }}, 10);
+      if (data.{{ column.java_field }} !== null && data.{{ column.java_field }} !== undefined && data.{{ column.java_field }} !== "") {
+        data.{{ column.java_field }} = parseInt(data.{{ column.java_field }}, 10);
       } else {
-        data.{{ underscore(column.java_field) }} = null;
+        data.{{ column.java_field }} = null;
       }
 {%- elif column.java_type in ['Float', 'Double', 'BigDecimal', 'Decimal'] %}
-      if (data.{{ underscore(column.java_field) }} !== null && data.{{ underscore(column.java_field) }} !== undefined && data.{{ underscore(column.java_field) }} !== "") {
-        data.{{ underscore(column.java_field) }} = parseFloat(data.{{ underscore(column.java_field) }});
+      if (data.{{ column.java_field }} !== null && data.{{ column.java_field }} !== undefined && data.{{ column.java_field }} !== "") {
+        data.{{ column.java_field }} = parseFloat(data.{{ column.java_field }});
       } else {
-        data.{{ underscore(column.java_field) }} = null;
+        data.{{ column.java_field }} = null;
       }
 {%- endif %}
 {%- endfor %}
@@ -612,8 +613,8 @@ export default {
     },
     /** 删除按钮操作 */
     handleDelete(row) {
-      this.$modal.confirm('是否确认删除{{ table.function_name }}编号为"' + row.{% if table.pk_column %}{{ underscore(table.pk_column.java_field) }}{% else %}id{% endif %} + '"的数据项?').then(function() {
-        return del{{ ApiName }}(row.{% if table.pk_column %}{{ underscore(table.pk_column.java_field) }}{% else %}id{% endif %});
+      this.$modal.confirm('是否确认删除{{ table.function_name }}编号为"' + row.{{ pk_field }} + '"的数据项?').then(function() {
+        return del{{ ApiName }}(row.{{ pk_field }});
       }).then(() => {
         this.getList();
         this.$modal.msgSuccess("删除成功");

+ 1 - 3
ruoyi_generator/vm/vue/index.vue.vm

@@ -309,13 +309,11 @@
 </template>
 
 <script>
-{# 使用后端工具函数生成接口前缀:
-   - apiName  : scheduleInfo
-   - ApiName  : ScheduleInfo(listScheduleInfo / getScheduleInfo 等) #}
 {% set apiName = to_camel_case(table.class_name, False) %}
 {% set ApiName = capitalize_first(apiName) %}
 import { list{{ ApiName }}, get{{ ApiName }}, del{{ ApiName }}, add{{ ApiName }}, update{{ ApiName }}, export{{ ApiName }}, importTemplate, importData } from "@/api/{{ table.module_name }}/{{ table.business_name }}";
 import { getToken } from "@/utils/auth";
+import { getFileName, getFilePath } from '@/utils/ruoyi'
 
 export default {
   name: "{{ table.class_name }}",