Browse Source

Merge branch 'dev' of github.com:pig-mesh/CGTM into dev

PIG AI 1 week ago
parent
commit
0fce01d6fa

+ 111 - 0
.cursor/rules/development-workflow.mdc

@@ -0,0 +1,111 @@
+---
+description: 
+globs: 
+alwaysApply: false
+---
+# Development Workflow
+
+## Using CGTM Templates
+
+### 1. Template Selection
+
+Choose the appropriate template group based on your needs:
+- **单表增删改查** - For simple CRUD operations on a single table
+- **主子表增删改查** - For parent-child relationships (e.g., Order-OrderItems)
+- **vform** - For visual form designer integration
+
+### 2. Configuration Setup
+
+Before generating code, ensure these variables are configured:
+
+**Basic Information:**
+- `author` - Developer name
+- `package` - Base package (e.g., com.pigx.app)
+- `moduleName` - Module identifier (e.g., system, business)
+- `functionName` - Feature name (e.g., user, product)
+
+**Database Configuration:**
+- `tableName` - Database table name
+- `tableComment` - Table description
+- `fieldList` - Field definitions from database
+
+**Path Configuration:**
+- `backendPath` - Backend project root path
+- `frontendPath` - Frontend project root path
+
+### 3. Code Generation Process
+
+1. **Analyze Database Schema**
+   - Primary keys are marked with `primaryPk = '1'`
+   - Auto-fill fields configured (INSERT, UPDATE, INSERT_UPDATE)
+   - Logical deletion field is `del_flag`
+
+2. **Generate Backend Code**
+   - Entity with proper annotations
+   - Mapper interface and XML
+   - Service interface and implementation
+   - Controller with REST endpoints
+
+3. **Generate Frontend Code**
+   - API client in TypeScript
+   - Table component for data display
+   - Form component for data entry
+   - i18n translations if needed
+
+4. **Generate SQL Scripts**
+   - Permission entries
+   - Menu configuration
+
+### 4. Post-Generation Tasks
+
+After code generation:
+
+1. **Review Generated Code**
+   - Check import statements
+   - Verify field mappings
+   - Ensure proper annotations
+
+2. **Customize Business Logic**
+   - Add validation rules
+   - Implement custom queries
+   - Add business-specific methods
+
+3. **Configure Permissions**
+   - Run generated SQL scripts
+   - Assign roles and permissions
+   - Test access control
+
+4. **Frontend Integration**
+   - Add routes
+   - Configure menu items
+   - Test CRUD operations
+
+### 5. Master-Detail Specifics
+
+For parent-child relationships:
+
+1. **Define Relationships**
+   - `mainField` - Parent table foreign key field
+   - `childField` - Child table reference field
+   - Configure cascade operations
+
+2. **Transaction Management**
+   - All operations wrapped in transactions
+   - Proper rollback on errors
+   - Batch operations for children
+
+3. **UI Considerations**
+   - Nested forms for data entry
+   - Inline editing for child records
+   - Proper validation across levels
+
+### 6. Best Practices
+
+- Always use logical deletion (`del_flag`) instead of physical deletion
+- Implement proper validation at both frontend and backend
+- Use dictionaries for standardized dropdowns
+- Follow RESTful conventions for APIs
+- Maintain consistent naming conventions
+- Add comprehensive API documentation with `@Schema` annotations
+- Use permission annotations for security
+- Implement audit logging with `@SysLog`

+ 100 - 0
.cursor/rules/java-templates.mdc

@@ -0,0 +1,100 @@
+---
+description: 
+globs: 
+alwaysApply: false
+---
+# Java Backend Template Patterns
+
+## Entity Template Pattern
+
+Entities follow the MyBatis-Plus active record pattern:
+
+```java
+@Data
+@TableName("${tableName}")
+@EqualsAndHashCode(callSuper = true)
+public class ${ClassName}Entity extends Model<${ClassName}Entity> {
+    // Fields with annotations
+}
+```
+
+Key annotations used:
+- `@TableId(type = IdType.ASSIGN_ID)` - For primary keys
+- `@TableField(fill = FieldFill.INSERT)` - Auto-fill on insert
+- `@TableLogic` - Logical deletion flag
+- `@Schema` - OpenAPI documentation
+
+## Controller Template Pattern
+
+Controllers follow RESTful conventions with Spring Boot:
+
+```java
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/${functionName}")
+@Tag(description = "${tableComment}", name = "${tableComment}管理")
+public class ${ClassName}Controller {
+    // CRUD endpoints
+}
+```
+
+Standard endpoints:
+- `GET /{id}` - Get by ID
+- `GET /page` - Paginated list
+- `POST` - Create new
+- `PUT` - Update existing
+- `DELETE` - Delete (logical or physical)
+
+## Service Layer Pattern
+
+Service interface:
+```java
+public interface ${ClassName}Service extends IService<${ClassName}Entity> {
+    // Custom business methods
+}
+```
+
+Implementation extends ServiceImpl:
+```java
+@Service
+@RequiredArgsConstructor
+public class ${ClassName}ServiceImpl extends ServiceImpl<${ClassName}Mapper, ${ClassName}Entity> 
+    implements ${ClassName}Service {
+    // Business logic implementation
+}
+```
+
+## Mapper Pattern
+
+MyBatis mapper interface:
+```java
+@Mapper
+public interface ${ClassName}Mapper extends BaseMapper<${ClassName}Entity> {
+    // Custom SQL methods
+}
+```
+
+## Multi-Tenant Support
+
+When `isTenant` is true:
+- Entity includes `@TenantTable` annotation
+- Automatic tenant filtering in queries
+- Tenant ID auto-fill on insert
+
+## Transaction Handling
+
+Master-detail operations use:
+```java
+@Transactional(rollbackFor = Exception.class)
+public Boolean save${ClassName}(${ClassName}Entity entity) {
+    // Parent save
+    // Children save/update/delete
+}
+```
+
+## Security Annotations
+
+Common security patterns:
+- `@PreAuthorize("@pms.hasPermission('${functionName}_add')")` - Permission check
+- `@SysLog("新增${tableComment}")` - Audit logging
+- `@Inner(false)` - Internal service access control

+ 52 - 0
.cursor/rules/project-overview.mdc

@@ -0,0 +1,52 @@
+---
+description: 
+globs: 
+alwaysApply: true
+---
+# CGTM Project Overview
+
+## What is CGTM?
+
+CGTM (Code Generation Template Market - 代码生成模板市场) is an online platform that provides various code generation templates to enhance developer experience. It's designed to work with the PIGX framework for rapid application development.
+
+## Project Purpose
+
+- Provide rich and diverse code generation templates
+- Enable easy template updates through "online update" functionality
+- Support community contributions via GitHub pull requests
+- Accelerate development workflow with pre-built templates
+
+## Core Technologies
+
+- **Template Engine**: Apache Velocity
+- **Backend**: Java with Spring Boot
+- **Frontend**: Vue.js with TypeScript
+- **Database Support**: Multiple database types through dynamic configuration
+- **Architecture**: Microservices with modular design
+
+## Template Categories
+
+1. **Single Table CRUD** (单表增删改查)
+   - Complete CRUD operations for single entities
+   - Includes Controller, Service, Mapper, Entity, and Vue components
+
+2. **Master-Detail CRUD** (主子表增删改查)
+   - Parent-child relationship management
+   - Complex form handling with nested data
+
+3. **VForm Templates**
+   - Visual form designer integration
+   - JSON-based form configuration
+
+## Key Features
+
+- Multi-tenant support (`isTenant` flag)
+- Internationalization (i18n) ready
+- Auto-fill fields support
+- Logical deletion support
+- Dynamic permission and menu generation
+- Modern UI with best UX practices
+
+## License
+
+AGPL 3.0 - Free for PIGX users only

+ 79 - 0
.cursor/rules/template-structure.mdc

@@ -0,0 +1,79 @@
+---
+description: 
+globs: 
+alwaysApply: true
+---
+# Template Structure Guide
+
+## Directory Organization
+
+```
+CGTM/
+├── single/              # Single table CRUD templates
+├── multiple/            # Master-detail table templates
+├── common/              # Shared templates across modules
+├── vform/               # Visual form designer templates
+└── config.json          # Template configuration mapping
+```
+
+## Template Configuration
+
+The [config.json](mdc:config.json) file defines template groups and their mappings:
+
+```json
+{
+  "单表增删改查": [...],     // Single table templates
+  "主子表增删改查": [...],   // Master-detail templates
+  "vform": [...]           // VForm templates
+}
+```
+
+Each template entry contains:
+- `templateName`: Display name of the template
+- `generatorPath`: Output path with variable substitution
+- `templateFile`: Source template file location
+
+## Single Table Templates
+
+Located in the [single/](mdc:single) directory:
+
+- [Controller.java](mdc:single/Controller.java) - REST API endpoints
+- [Service.java](mdc:single/Service.java) - Business logic interface
+- [ServiceImpl.java](mdc:single/ServiceImpl.java) - Service implementation
+- [实体.java](mdc:single/实体.java) - JPA/MyBatis entity
+- [Mapper.java](mdc:single/Mapper.java) - MyBatis mapper interface
+- [Mapper.xml](mdc:single/Mapper.xml) - SQL mappings
+- [表格.vue](mdc:single/表格.vue) - Data table component
+- [表单.vue](mdc:single/表单.vue) - Form component
+
+## Master-Detail Templates
+
+Located in the [multiple/](mdc:multiple) directory:
+
+- [主子Contoller.java](mdc:multiple/主子Contoller.java) - Parent-child REST APIs
+- [主子Service.java](mdc:multiple/主子Service.java) - Complex business logic
+- [主子ServiceImpl.java](mdc:multiple/主子ServiceImpl.java) - Implementation with transactions
+- [主实体.java](mdc:multiple/主实体.java) - Parent entity
+- [子实体.java](mdc:multiple/子实体.java) - Child entity
+- [子Mapper.java](mdc:multiple/子Mapper.java) - Child table mapper
+- [主子表格.vue](mdc:multiple/主子表格.vue) - Parent-child data display
+- [主子表单.vue](mdc:multiple/主子表单.vue) - Nested form handling
+
+## Common Templates
+
+Located in the [common/](mdc:common) directory:
+
+- [api.ts](mdc:common/api.ts) - TypeScript API client
+- [权限菜单.sql](mdc:common/权限菜单.sql) - Permission and menu SQL
+- [i18n中文模板.ts](mdc:common/i18n中文模板.ts) - Chinese translations
+- [i18n英文模板.ts](mdc:common/i18n英文模板.ts) - English translations
+
+## Path Variables
+
+Template paths support these variables:
+- `${backendPath}` - Backend project root
+- `${frontendPath}` - Frontend project root
+- `${packagePath}` - Java package path (com/example/app)
+- `${moduleName}` - Module name
+- `${ClassName}` - Entity class name
+- `${functionName}` - Function/feature name

+ 100 - 0
.cursor/rules/velocity.mdc

@@ -0,0 +1,100 @@
+---
+description: 
+globs: 
+alwaysApply: true
+---
+# Velocity Templates in CGTM
+
+This rule explains how Velocity templates are used for code generation in this project.
+
+## Basic Structure
+
+Velocity templates use a simple syntax with variables, directives, and references:
+- Variables start with `$` (e.g., `$ClassName`)
+- Directives start with `#` (e.g., `#foreach`, `#if`, `#end`)
+- Comments use `##`
+
+## Entity Template Example
+
+```java
+public class ${ClassName}Entity extends Model<${ClassName}Entity> {
+
+#foreach ($field in $fieldList)
+#if($field.primaryPk)
+    @TableId(type = IdType.ASSIGN_ID)
+#end
+    @Schema(description="$comment"#if($field.hidden),hidden=$field.hidden#end)
+    private $field.attrType $field.attrName;
+#end
+}
+```
+
+## Available Context Variables
+
+### Template Basic Properties
+| Variable | Description |
+|----------|-------------|
+| dbType | Database type |
+| package | Package name |
+| packagePath | Package path |
+| version | Version |
+| moduleName | Module name |
+| ModuleName | Module name (first letter capitalized) |
+| functionName | Function name |
+| FunctionName | Function name (first letter capitalized) |
+| formLayout | Form layout |
+| style | Style, corresponding template group |
+| author | Author |
+| datetime | Current date and time |
+| date | Current date |
+| importList | Import list |
+| tableName | Database table name |
+| tableComment | Database table comment |
+| className | Class name in lowercase |
+| ClassName | Class name |
+| fieldList | Field list |
+| backendPath | Backend path |
+| frontendPath | Frontend path |
+| childFieldList | Child table field list |
+| childTableName | Child table name |
+| mainField | Main table relation field name |
+| childField | Child table relation field name |
+| ChildClassName | Child class name (first letter capitalized) |
+| childClassName | Child class name in lowercase |
+| primaryList | Primary key field list |
+| formList | Form field list |
+| gridList | Grid field list |
+| queryList | Query field list |
+| pk | Primary key field |
+
+### Template Field Properties
+| Variable | Description |
+|----------|-------------|
+| dsName | Data source name |
+| tableName | Table name |
+| fieldName | SQL field name |
+| fieldType | SQL field type |
+| attrName | Java attribute name |
+| attrType | Java attribute type |
+| fieldComment | Field description |
+| sort | Sort |
+| packageName | Attribute package name |
+| autoFill | Auto fill |
+| primaryPk | Whether it's a primary key |
+| baseField | Whether it's a base class field |
+| formItem | Whether it's a form item |
+| formRequired | Form required |
+| formType | Form type |
+| formValidator | Form validator |
+| gridItem | Whether it's a list item |
+| gridSort | List sorting |
+| queryItem | Whether it's a query item |
+| queryType | Query method |
+| queryFormType | Query form type |
+| fieldDict | Field dictionary type |
+
+### Environment Variables
+| Variable | Description |
+|----------|-------------|
+| isSpringBoot3 | Whether it's SpringBoot 3 |
+| isTenant | Whether multi-tenant is supported |

+ 35 - 27
common/api.ts

@@ -1,9 +1,11 @@
 import request from "/@/utils/request"
 
+// ========== 基础CRUD接口 ==========
+
 /**
- * 根据分页查询参数获取列表数据。
- * @param {Object} [query] - 查询参数。
- * @returns {Promise} 请求的 Promise 分页对象。
+ * 分页查询列表数据
+ * @param query - 查询参数对象
+ * @returns Promise<分页数据>
  */
 export function fetchList(query?: Object) {
   return request({
@@ -14,9 +16,9 @@ export function fetchList(query?: Object) {
 }
 
 /**
- * 添加一个新对象。
- * @param {Object} [obj] - 要添加的对象。
- * @returns {Promise} 请求的 Promise 对象 (true/false)。
+ * 新增数据
+ * @param obj - 要新增的数据对象
+ * @returns Promise<boolean> - 操作结果
  */
 export function addObj(obj?: Object) {
   return request({
@@ -27,9 +29,9 @@ export function addObj(obj?: Object) {
 }
 
 /**
- * 根据查询参数获取对象详情。
- * @param {Object} [obj] - 查询参数。
- * @returns {Promise} 请求的 Promise 对象数组。
+ * 获取详情数据
+ * @param obj - 查询参数对象(包含ID等)
+ * @returns Promise<数据详情>
  */
 export function getObj(obj?: Object) {
   return request({
@@ -40,9 +42,9 @@ export function getObj(obj?: Object) {
 }
 
 /**
- * 根据 ID 删除对象。
- * @param {Object} [ids] - 要删除的对象 ID。
- * @returns {Promise} 请求的 Promise 对象。
+ * 批量删除数据
+ * @param ids - 要删除的ID数组
+ * @returns Promise<操作结果>
  */
 export function delObjs(ids?: Object) {
   return request({
@@ -53,9 +55,9 @@ export function delObjs(ids?: Object) {
 }
 
 /**
- * 更新一个已存在的对象。
- * @param {Object} [obj] - 要更新的对象
- * @returns {Promise} 请求的 Promise 对象。
+ * 更新数据
+ * @param obj - 要更新的数据对象
+ * @returns Promise<操作结果>
  */
 export function putObj(obj?: Object) {
   return request({
@@ -65,15 +67,18 @@ export function putObj(obj?: Object) {
   })
 }
 
+// ========== 工具函数 ==========
+
 /**
- * 验证某个字段的值是否已经存在。
- * @param {Object} rule - 验证规则对象
- * @param {*} value - 要验证的值
- * @param {Function} callback - 验证完成后的回调函数
- * @param {boolean} isEdit - 当前操作是否为编辑。
+ * 验证字段值唯一性
+ * @param rule - 验证规则对象
+ * @param value - 要验证的值
+ * @param callback - 验证回调函数
+ * @param isEdit - 是否为编辑模式
  * 
- * 示例用法:
- * 字段名: [
+ * @example
+ * // 在表单验证规则中使用
+ * fieldName: [
  *   {
  *     validator: (rule, value, callback) => {
  *       validateExist(rule, value, callback, form.${pk.attrName} !== '');
@@ -83,10 +88,12 @@ export function putObj(obj?: Object) {
  * ]
  */
 export function validateExist(rule: any, value: any, callback: any, isEdit: boolean) {
+  // 编辑模式下跳过验证
   if (isEdit) {
     return callback();
   }
 
+  // 查询是否存在相同值
   getObj({ [rule.field]: value }).then((response) => {
     const result = response.data;
     if (result !== null && result.length > 0) {
@@ -97,13 +104,14 @@ export function validateExist(rule: any, value: any, callback: any, isEdit: bool
   });
 }
 
-
 #if($ChildClassName)
+// ========== 子表相关接口 ==========
+
 /**
-* 删除子对象。
-* @param {Object} [ids] - 要删除的子对象 ID。
-* @returns {Promise} 请求的 Promise 对象。
-*/
+ * 删除子表数据
+ * @param ids - 要删除的子表数据ID数组
+ * @returns Promise<操作结果>
+ */
 export function delChildObj(ids?: Object) {
   return request({
     url: '/${moduleName}/${functionName}/child',

+ 6 - 0
common/i18n中文模板.ts

@@ -1,11 +1,17 @@
+/**
+ * ${tableComment}模块 - 中文语言包
+ */
 export default {
    ${functionName}: {
+        // 基础文本
         index: '#',
         import${className}Tip: '导入${tableComment}',
 #foreach($field in $fieldList)
+        // 字段名称
         ${field.attrName}: '#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end',
 #end
 #foreach($field in $fieldList)
+        // 输入提示
         input$str.pascalCase(${field.attrName})Tip: '请输入#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end',
 #end
     }

+ 8 - 2
common/i18n英文模板.ts

@@ -1,12 +1,18 @@
+/**
+ * ${tableComment} Module - English Language Pack
+ */
 export default {
    ${functionName}: {
+        // Basic Text
         index: '#',
-        import${className}Tip: 'import ${ClassName}',
+        import${className}Tip: 'Import ${ClassName}',
 #foreach($field in $fieldList)
+        // Field Names
         ${field.attrName}: '${field.attrName}',
 #end
 #foreach($field in $fieldList)
-        input$str.pascalCase(${field.attrName})Tip: 'input ${field.attrName}',
+        // Input Tips
+        input$str.pascalCase(${field.attrName})Tip: 'Please input ${field.attrName}',
 #end
     }
 }

+ 183 - 152
multiple/主子表单.vue

@@ -1,208 +1,239 @@
 <template>
   <el-drawer :title="form.${pk.attrName} ? (detail ? '详情' : '编辑') : '添加'" v-model="visible" size="50%">
-      <el-form ref="dataFormRef" :model="form" :rules="dataRules" label-width="90px" :disabled="detail" v-loading="loading">
-        <el-row :gutter="24">
+    <el-form ref="dataFormRef" :model="form" :rules="dataRules" label-width="90px" :disabled="detail" v-loading="loading">
+      <el-row :gutter="24">
 #foreach($field in $formList)
 #if($field.attrName != ${pk.attrName})
 #if($formLayout == 1)
-    <el-col :span="24" class="mb20">
+        <el-col :span="24" class="mb20">
 #elseif($formLayout == 2)
-    <el-col :span="12" class="mb20">
+        <el-col :span="12" class="mb20">
 #end
 #if($field.formType == 'text')
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
-        <el-input v-model="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end"/>
-      </el-form-item>
-      </el-col>
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <el-input v-model="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end"/>
+          </el-form-item>
+        </el-col>
 #elseif($field.formType == 'textarea')
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
-        <el-input type="textarea" v-model="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end"/>
-      </el-form-item>
-      </el-col>
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <el-input type="textarea" v-model="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end"/>
+          </el-form-item>
+        </el-col>
 #elseif($field.formType == 'select')
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
-          <el-select v-model="form.${field.attrName}" placeholder="请选择#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end">
-     #if($field.fieldDict)
-            <el-option :value="item.value" :label="item.label" v-for="(item, index) in ${field.fieldDict}" :key="index"></el-option>
-       #end
-     #if(!$field.fieldDict)
-            <el-option label="请选择">0</el-option>
-       #end
-          </el-select>
-        </el-form-item>
-      </el-col>
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <el-select v-model="form.${field.attrName}" placeholder="请选择#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end">
+#if($field.fieldDict)
+              <el-option :value="item.value" :label="item.label" v-for="(item, index) in ${field.fieldDict}" :key="index"></el-option>
+#else
+              <el-option label="请选择" value="0"></el-option>
+#end
+            </el-select>
+          </el-form-item>
+        </el-col>
 #elseif($field.formType == 'radio')
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
             <el-radio-group v-model="form.${field.attrName}">
-     #if($field.fieldDict)
-             <el-radio :label="item.value" v-for="(item, index) in ${field.fieldDict}" border :key="index">{{ item.label }}
-            </el-radio>
-       #else
-           <el-radio label="${field.fieldComment}" border>${field.fieldComment}</el-radio>
-       #end
+#if($field.fieldDict)
+              <el-radio :label="item.value" v-for="(item, index) in ${field.fieldDict}" border :key="index">{{ item.label }}</el-radio>
+#else
+              <el-radio label="${field.fieldComment}" border>${field.fieldComment}</el-radio>
+#end
             </el-radio-group>
-        </el-form-item>
-      </el-col>
+          </el-form-item>
+        </el-col>
 #elseif($field.formType == 'checkbox')
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
             <el-checkbox-group v-model="form.${field.attrName}">
-     #if($field.fieldDict)
-                <el-checkbox :label="item.value" v-for="(item, index) in ${field.fieldDict}" :key="index">{{ item.label }}</el-checkbox>
-       #end
-     #if(!$field.fieldDict)
-                <el-checkbox label="启用" name="type"></el-checkbox>
-                <el-checkbox label="禁用" name="type"></el-checkbox>
-       #end
+#if($field.fieldDict)
+              <el-checkbox :label="item.value" v-for="(item, index) in ${field.fieldDict}" :key="index">{{ item.label }}</el-checkbox>
+#else
+              <el-checkbox label="启用" name="type"></el-checkbox>
+              <el-checkbox label="禁用" name="type"></el-checkbox>
+#end
             </el-checkbox-group>
-        </el-form-item>
-      </el-col>
+          </el-form-item>
+        </el-col>
 #elseif($field.formType == 'date')
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
-      <el-date-picker type="date" placeholder="请选择#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" v-model="form.${field.attrName}" :value-format="dateStr"></el-date-picker>
-      </el-form-item>
-      </el-col>
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <el-date-picker type="date" placeholder="请选择#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" v-model="form.${field.attrName}" :value-format="dateStr"></el-date-picker>
+          </el-form-item>
+        </el-col>
 #elseif($field.formType == 'datetime')
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
-            <el-date-picker type="datetime" placeholder="请选择#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" v-model="form.${field.attrName}" :value-format="dateTimeStr"></el-date-picker>
-      </el-form-item>
-      </el-col>
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <el-date-picker type="datetime" placeholder="请选择#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" v-model="form.${field.attrName}" :value-format="dateTimeStr"></el-date-picker>
+          </el-form-item>
+        </el-col>
 #elseif($field.formType == 'number')
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
-        <el-input-number :min="1" :max="1000" v-model="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end"></el-input-number>
-      </el-form-item>
-    </el-col>
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <el-input-number :min="1" :max="1000" v-model="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end"></el-input-number>
+          </el-form-item>
+        </el-col>
 #elseif($field.formType == 'upload-file')
-  <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
-    <upload-file  v-model="form.${field.attrName}"></upload-file>
-  </el-form-item>
-  </el-col>
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <upload-file v-model="form.${field.attrName}"></upload-file>
+          </el-form-item>
+        </el-col>
 #elseif($field.formType == 'upload-img')
-  <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
-    <upload-img v-model:imageUrl="form.${field.attrName}"></upload-img>
-  </el-form-item>
-  </el-col>
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <upload-img v-model:imageUrl="form.${field.attrName}"></upload-img>
+          </el-form-item>
+        </el-col>
 #elseif($field.formType == 'editor')
-  <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
-    <editor v-model:get-html="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end"></editor>
-  </el-form-item>
-  </el-col>
-#end
-#if(!$field.formType)
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${column.attrName}">
-        <el-input v-model="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end"/>
-      </el-form-item>
-    </el-col>
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <editor v-model:get-html="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end"></editor>
+          </el-form-item>
+        </el-col>
+#else
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <el-input v-model="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end"/>
+          </el-form-item>
+        </el-col>
 #end
 #end
 #end
-    </el-row>
-  <el-row :gutter="24">
-    <sc-form-table
-      v-model="form.${childClassName}List"
-      :addTemplate="childTemp"
-      @delete="deleteChild"
-      placeholder="暂无数据"
-    >
+      </el-row>
+      <el-row :gutter="24">
+        <sc-form-table
+          v-model="form.${childClassName}List"
+          :addTemplate="childTemp"
+          @delete="deleteChild"
+          placeholder="暂无数据"
+        >
 #set($ignoreColumnList = ["create_by","create_time","update_by","update_time","del_flag","tenant_id"])
 #foreach($field in $childFieldList)
 #if($field.primaryPk == '1')
 #elseif($ignoreColumnList.contains(${field.fieldName}))
 #elseif($field.attrName == $childField)
 #else  
-      <el-table-column label="${field.fieldComment}" prop="${field.attrName}">
-        <template #default="{ row, $index }">
-          <el-form-item :prop="`${childClassName}List.${$index}.${field.attrName}`" :rules="[{ required: true, trigger: 'blur' }]">
-            <el-input v-model="row.${field.attrName}" style="width: 100%" />
-          </el-form-item>
-        </template>
-      </el-table-column>
+          <el-table-column label="${field.fieldComment}" prop="${field.attrName}">
+            <template #default="{ row, $index }">
+              <el-form-item :prop="`${childClassName}List.${$index}.${field.attrName}`" :rules="[{ required: true, trigger: 'blur' }]">
+                <el-input v-model="row.${field.attrName}" style="width: 100%" />
+              </el-form-item>
+            </template>
+          </el-table-column>
 #end
 #end
-    </sc-form-table>
-  </el-row>
-      </el-form>
-      <template #footer>
-        <span class="dialog-footer">
-          <el-button @click="visible = false">取 消</el-button>
-          <el-button type="primary" @click="onSubmit" :disabled="loading">确 认</el-button>
-        </span>
-      </template>
-    </el-drawer>
+        </sc-form-table>
+      </el-row>
+    </el-form>
+    <template #footer>
+      <span class="dialog-footer">
+        <el-button @click="visible = false">取 消</el-button>
+        <el-button type="primary" @click="onSubmit" :disabled="loading">确 认</el-button>
+      </span>
+    </template>
+  </el-drawer>
 </template>
 
 <script setup lang="ts" name="${ClassName}Dialog">
+// ========== 1. 导入语句 ==========
 import { useDict } from '/@/hooks/dict';
 import { rule } from '/@/utils/validate';
 import { useMessage } from "/@/hooks/message";
-import { getObj, addObj, putObj, delChildObj, validateExist } from '/@/api/${moduleName}/${functionName}'
+import { getObj, addObj, putObj, delChildObj, validateExist } from '/@/api/${moduleName}/${functionName}';
+
+// ========== 2. 组件定义 ==========
+// 异步加载表格组件
 const scFormTable = defineAsyncComponent(() => import('/@/components/FormTable/index.vue'));
-const emit = defineEmits(['refresh']);
 
-// 定义变量内容
-const dataFormRef = ref();
-const visible = ref(false);
-const loading = ref(false);
-const detail = ref(false);
+// 定义组件事件
+const emit = defineEmits(['refresh']);
 
-// 定义字典
-#set($fieldDict=[])
-#foreach($field in $gridList)
-	#if($field.fieldDict)
-		#set($void=$fieldDict.add($field.fieldDict))
-	#end
-#end
-#if($fieldDict)
-const { $dict.format($fieldDict) } = useDict($dict.quotation($fieldDict))
-#end
+// ========== 3. 响应式数据定义 ==========
+// 基础响应式变量
+const dataFormRef = ref(); // 表单引用
+const visible = ref(false); // 抽屉显示状态
+const loading = ref(false); // 加载状态
+const detail = ref(false); // 是否为详情模式
 
-// 提交表单数据
+// 表单数据对象
 const form = reactive({
 #if(!$formList.contains(${pk.attrName}))
-		${pk.attrName}:'',
+  ${pk.attrName}: '', // 主键
 #end
 #foreach($field in $formList)
 #if($field.formType == 'number')
-		${field.attrName}: 0,
+  ${field.attrName}: 0, // ${field.fieldComment}
 #elseif($field.formType == 'checkbox')
-    ${field.attrName}: [],
+  ${field.attrName}: [], // ${field.fieldComment}
 #else
-	  ${field.attrName}: '',
+  ${field.attrName}: '', // ${field.fieldComment}
 #end
 #end
-	  ${childClassName}List:[],
+  ${childClassName}List: [], // 子表数据列表
 });
 
+// 子表数据模板
 const childTemp = reactive({
-  #foreach($field in $childFieldList)
-    ${field.attrName}: '',
-  #end
-})
+#foreach($field in $childFieldList)
+  ${field.attrName}: '', // ${field.fieldComment}
+#end
+});
 
-// 定义校验规则
+// ========== 4. 字典数据处理 ==========
+#set($fieldDict=[])
+#foreach($field in $gridList)
+#if($field.fieldDict)
+#set($void=$fieldDict.add($field.fieldDict))
+#end
+#end
+#if($fieldDict && $fieldDict.size() > 0)
+// 加载字典数据
+const { $dict.format($fieldDict) } = useDict($dict.quotation($fieldDict));
+#end
+
+// ========== 5. 表单校验规则 ==========
 const dataRules = ref({
 #foreach($field in $formList)
 #if($field.formRequired == '1' && $field.formValidator == 'duplicate')
-    ${field.attrName}: [{required: true, message: '${field.fieldComment}不能为空', trigger: 'blur'}, {
+  ${field.attrName}: [
+    { required: true, message: '${field.fieldComment}不能为空', trigger: 'blur' },
+    {
       validator: (rule: any, value: any, callback: any) => {
+        // 重复性校验(编辑时跳过)
         validateExist(rule, value, callback, form.${pk.attrName} !== '');
       },
       trigger: 'blur',
-    }],
+    }
+  ],
 #elseif($field.formRequired == '1' && $field.formValidator)
-    ${field.attrName}: [{required: true, message: '${field.fieldComment}不能为空', trigger: 'blur'}, { validator: rule.${field.formValidator}, trigger: 'blur' }],
+  ${field.attrName}: [
+    { required: true, message: '${field.fieldComment}不能为空', trigger: 'blur' },
+    { validator: rule.${field.formValidator}, trigger: 'blur' }
+  ],
 #elseif($field.formRequired == '1')
-    ${field.attrName}: [{required: true, message: '${field.fieldComment}不能为空', trigger: 'blur'}],
+  ${field.attrName}: [
+    { required: true, message: '${field.fieldComment}不能为空', trigger: 'blur' }
+  ],
 #elseif($field.formValidator)
-    ${field.attrName}: [{ validator: rule.${field.formValidator}, trigger: 'blur' }],
+  ${field.attrName}: [
+    { validator: rule.${field.formValidator}, trigger: 'blur' }
+  ],
 #end
 #end
-})
+});
 
-// 打开弹窗
+// ========== 6. 方法定义 ==========
+// 获取主子表详情数据
+const get${ClassName}Data = async (id: string) => {
+  try {
+    loading.value = true;
+    const { data } = await getObj({ ${pk.attrName}: id });
+    // 直接将第一条数据赋值给表单
+    Object.assign(form, data[0]);
+  } catch (error) {
+    useMessage().error('获取数据失败');
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 打开抽屉方法
 const openDialog = (id: string, isDetail: boolean) => {
-  visible.value = true
-  detail.value = isDetail
-  form.${pk.attrName} = ''
+  visible.value = true;
+  detail.value = isDetail;
+  form.${pk.attrName} = '';
 
   // 重置表单数据
   nextTick(() => {
@@ -210,36 +241,43 @@ const openDialog = (id: string, isDetail: boolean) => {
     form.${childClassName}List = [];
   });
 
-  // 获取${className}信息
+  // 获取${ClassName}信息
   if (id) {
-    form.${pk.attrName} = id
-    get${ClassName}Data(id)
+    form.${pk.attrName} = id;
+    get${ClassName}Data(id);
   }
 };
 
-// 提交
+// 提交表单方法
 const onSubmit = async () => {
+  loading.value = true; // 防止重复提交
+  
+  // 表单校验
   const valid = await dataFormRef.value.validate().catch(() => {});
-  if (!valid) return false;
+  if (!valid) {
+    loading.value = false;
+    return false;
+  }
 
   try {
-    loading.value = true;
+    // 根据是否有ID判断是新增还是修改
     form.${pk.attrName} ? await putObj(form) : await addObj(form);
     useMessage().success(form.${pk.attrName} ? '修改成功' : '添加成功');
     visible.value = false;
-    emit('refresh');
+    emit('refresh'); // 通知父组件刷新列表
   } catch (err: any) {
     useMessage().error(err.msg);
   } finally {
     loading.value = false;
   }
 };
+
 #foreach ($field in $childFieldList)
 #if($field.primaryPk == '1')
 #set($childPkName=$field.attrName)
 #end
 #end
-// 删除子表数据
+// 删除子表数据方法
 const deleteChild = async (obj: { $childPkName: string }) => {
   if (obj.$childPkName) {
     try {
@@ -251,15 +289,8 @@ const deleteChild = async (obj: { $childPkName: string }) => {
   }
 };
 
-// 初始化表单数据
-const get${ClassName}Data = (id: string) => {
-  // 获取数据
-  getObj({${pk.attrName}: id}).then((res: any) => {
-    Object.assign(form, res.data[0])
-  })
-};
-
-// 暴露变量
+// ========== 7. 对外暴露 ==========
+// 暴露方法给父组件
 defineExpose({
   openDialog
 });

+ 144 - 75
multiple/主子表格.vue

@@ -6,38 +6,60 @@
         <el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
 #foreach($field in $queryList)
 #if($field.queryFormType == 'select')
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
-            <el-select v-model="state.queryForm.${field.attrName}" placeholder="请选择#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end">
-       #if($field.fieldDict)
-              <el-option :label="item.label" :value="item.value" v-for="(item, index) in ${field.fieldDict}" :key="index"></el-option>
-         #else
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <el-select v-model="state.queryForm.${field.attrName}" placeholder="请选择#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end">
+#if($field.fieldDict)
+              <el-option 
+                :label="item.label" 
+                :value="item.value" 
+                v-for="(item, index) in ${field.fieldDict}" 
+                :key="index">
+              </el-option>
+#else
               <el-option label="请选择">0</el-option>
-         #end
+#end
             </el-select>
-      </el-form-item>
+          </el-form-item>
 #elseif($field.queryFormType == 'date')
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
-      <el-date-picker type="date" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" v-model="state.queryForm.${field.attrName}"></el-date-picker>
-      </el-form-item>
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <el-date-picker 
+              type="date" 
+              placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" 
+              v-model="state.queryForm.${field.attrName}">
+            </el-date-picker>
+          </el-form-item>
 #elseif($field.queryFormType == 'datetime')
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}" >
-            <el-date-picker type="datetime" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" v-model="state.queryForm.${field.attrName}"></el-date-picker>
-      </el-form-item>
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <el-date-picker 
+              type="datetime" 
+              placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" 
+              v-model="state.queryForm.${field.attrName}">
+            </el-date-picker>
+          </el-form-item>
 #elseif($field.formType == 'radio')
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
             <el-radio-group v-model="state.queryForm.${field.attrName}">
-      #if($field.fieldDict)
-            <el-radio :label="item.value" v-for="(item, index) in ${field.fieldDict}" border :key="index">{{ item.label }}</el-radio>
-       #else
-            <el-radio label="${field.fieldComment}" border>${field.fieldComment}</el-radio>
-       #end
+#if($field.fieldDict)
+              <el-radio 
+                :label="item.value" 
+                v-for="(item, index) in ${field.fieldDict}" 
+                border 
+                :key="index">
+                {{ item.label }}
+              </el-radio>
+#else
+              <el-radio label="${field.fieldComment}" border>${field.fieldComment}</el-radio>
+#end
             </el-radio-group>
-     </el-form-item>
+          </el-form-item>
 #else
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}" >
-        <el-input placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" v-model="state.queryForm.${field.attrName}"
-          style="max-width: 180px" />
-      </el-form-item>
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <el-input 
+              placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" 
+              v-model="state.queryForm.${field.attrName}"
+              style="max-width: 180px" 
+            />
+          </el-form-item>
 #end
 #end
           <el-form-item>
@@ -51,54 +73,100 @@
 #end
       <el-row>
         <div class="mb8" style="width: 100%">
-          <el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()"
+          <el-button 
+            icon="folder-add" 
+            type="primary" 
+            class="ml10" 
+            @click="formDialogRef.openDialog()"
             v-auth="'${moduleName}_${functionName}_add'">
-            新 增
+            新增
           </el-button>
-          <el-button plain :disabled="multiple" icon="Delete" type="primary"
-            v-auth="'${moduleName}_${functionName}_del'" @click="handleDelete(selectObjs)">
+          <el-button 
+            plain 
+            :disabled="multiple" 
+            icon="Delete" 
+            type="primary"
+            v-auth="'${moduleName}_${functionName}_del'" 
+            @click="handleDelete(selectObjs)">
             删除
           </el-button>
-          <right-toolbar v-model:showSearch="showSearch" :export="'${moduleName}_${functionName}_export'"
-                @exportExcel="exportExcel" class="ml10 mr20" style="float: right;"
-            @queryTable="getDataList"></right-toolbar>
+          <right-toolbar 
+            v-model:showSearch="showSearch" 
+            :export="'${moduleName}_${functionName}_export'"
+            @exportExcel="exportExcel" 
+            class="ml10 mr20" 
+            style="float: right;"
+            @queryTable="getDataList">
+          </right-toolbar>
         </div>
       </el-row>
-      <el-table :data="state.dataList" v-loading="state.loading" border 
-        :cell-style="tableStyle.cellStyle" :header-cell-style="tableStyle.headerCellStyle"
-        @selection-change="selectionChangeHandle" @sort-change="sortChangeHandle">
+      <el-table 
+        :data="state.dataList" 
+        v-loading="state.loading" 
+        border 
+        :cell-style="tableStyle.cellStyle" 
+        :header-cell-style="tableStyle.headerCellStyle"
+        @selection-change="selectionChangeHandle" 
+        @sort-change="sortChangeHandle">
         <el-table-column type="selection" width="40" align="center" />
         <el-table-column type="index" label="#" width="40" />
-      #foreach($field in $gridList)
-        #if($field.fieldDict)
-          <el-table-column prop="${field.attrName}" label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" show-overflow-tooltip>
-      <template #default="scope">
-                <dict-tag :options="$field.fieldDict" :value="scope.row.${field.attrName}"></dict-tag>
-            </template>
-          </el-table-column>
-        #else
-          <el-table-column prop="${field.attrName}" label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" #if(${field.gridSort} == '1')sortable="custom"#end show-overflow-tooltip/>
-        #end
-     #end
+#foreach($field in $gridList)
+#if($field.fieldDict)
+        <el-table-column prop="${field.attrName}" label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" show-overflow-tooltip>
+          <template #default="scope">
+            <dict-tag :options="$field.fieldDict" :value="scope.row.${field.attrName}"></dict-tag>
+          </template>
+        </el-table-column>
+#else
+        <el-table-column 
+          prop="${field.attrName}" 
+          label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" 
+#if(${field.gridSort} == '1')
+          sortable="custom" 
+#end
+          show-overflow-tooltip
+        />
+#end
+#end
         <el-table-column label="操作" width="200">
           <template #default="scope">
-          #if($ChildClassName)
-            <el-button text type="primary" icon="view" v-auth="'sys_role_edit'" @click="formDialogRef.openDialog(scope.row.${pk.attrName}, true)">
+#if($ChildClassName)
+            <el-button 
+              text 
+              type="primary" 
+              icon="view" 
+              v-auth="'${moduleName}_${functionName}_view'" 
+              @click="formDialogRef.openDialog(scope.row.${pk.attrName}, true)">
               详情
             </el-button>
-          #end
-            <el-button icon="edit-pen" text type="primary" v-auth="'${moduleName}_${functionName}_edit'"
-              @click="formDialogRef.openDialog(scope.row.${pk.attrName})">编辑</el-button>
-            <el-button icon="delete" text type="primary" v-auth="'${moduleName}_${functionName}_del'" @click="handleDelete([scope.row.${pk.attrName}])">
+#end
+            <el-button 
+              icon="edit-pen" 
+              text 
+              type="primary" 
+              v-auth="'${moduleName}_${functionName}_edit'"
+              @click="formDialogRef.openDialog(scope.row.${pk.attrName})">
+              编辑
+            </el-button>
+            <el-button 
+              icon="delete" 
+              text 
+              type="primary" 
+              v-auth="'${moduleName}_${functionName}_del'" 
+              @click="handleDelete([scope.row.${pk.attrName}])">
               删除
             </el-button>
           </template>
         </el-table-column>
       </el-table>
-      <pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
+      <pagination 
+        @size-change="sizeChangeHandle" 
+        @current-change="currentChangeHandle" 
+        v-bind="state.pagination" 
+      />
     </div>
 
-    <!-- 编辑、新增  -->
+    <!-- 编辑、新增 -->
     <form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
   </div>
 </template>
@@ -108,40 +176,41 @@ import { BasicTableProps, useTable } from "/@/hooks/table";
 import { fetchList, delObjs } from "/@/api/${moduleName}/${functionName}";
 import { useMessage, useMessageBox } from "/@/hooks/message";
 import { useDict } from '/@/hooks/dict';
+
 // 引入组件
 const FormDialog = defineAsyncComponent(() => import('./form.vue'));
 
 // 定义查询字典
 #set($fieldDict=[])
 #foreach($field in $queryList)
-  #if($field.fieldDict)
-    #set($void=$fieldDict.add($field.fieldDict))
-  #end
+#if($field.fieldDict)
+#set($void=$fieldDict.add($field.fieldDict))
+#end
 #end
-
 #foreach($field in $gridList)
-  #if($field.fieldDict)
-    #set($void=$fieldDict.add($field.fieldDict))
-  #end
+#if($field.fieldDict)
+#set($void=$fieldDict.add($field.fieldDict))
+#end
 #end
 #if($fieldDict)
-const { $dict.format($fieldDict) } = useDict($dict.quotation($fieldDict))
+const { $dict.format($fieldDict) } = useDict($dict.quotation($fieldDict));
 #end
+
 // 定义变量内容
-const formDialogRef = ref()
+const formDialogRef = ref();
 // 搜索变量
-const queryRef = ref()
-const showSearch = ref(true)
+const queryRef = ref();
+const showSearch = ref(true);
 // 多选变量
-const selectObjs = ref([]) as any
-const multiple = ref(true)
+const selectObjs = ref([]) as any;
+const multiple = ref(true);
 
 const state: BasicTableProps = reactive<BasicTableProps>({
   queryForm: {},
   pageList: fetchList
-})
+});
 
-//  table hook
+// table hook
 const {
   getDataList,
   currentChangeHandle,
@@ -149,21 +218,21 @@ const {
   sortChangeHandle,
   downBlobFile,
   tableStyle
-} = useTable(state)
+} = useTable(state);
 
 // 清空搜索条件
 const resetQuery = () => {
   // 清空搜索条件
-  queryRef.value?.resetFields()
+  queryRef.value?.resetFields();
   // 清空多选
-  selectObjs.value = []
-  getDataList()
-}
+  selectObjs.value = [];
+  getDataList();
+};
 
 // 导出excel
 const exportExcel = () => {
-  downBlobFile('/${moduleName}/${functionName}/export', Object.assign(state.queryForm, { ids: selectObjs }), '${functionName}.xlsx')
-}
+  downBlobFile('/${moduleName}/${functionName}/export', Object.assign(state.queryForm, { ids: selectObjs }), '${functionName}.xlsx');
+};
 
 // 多选事件
 const selectionChangeHandle = (objs: { $pk.attrName: string }[]) => {

+ 170 - 148
single/表单.vue

@@ -1,221 +1,243 @@
 <template>
-    <el-dialog :title="form.${pk.attrName} ? '编辑' : '新增'" v-model="visible"
-      :close-on-click-modal="false" draggable>
-      <el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
-       <el-row :gutter="24">
+  <el-dialog :title="form.${pk.attrName} ? '编辑' : '新增'" v-model="visible"
+    :close-on-click-modal="false" draggable>
+    <el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
+      <el-row :gutter="24">
 #foreach($field in $formList)
 #if($field.attrName != ${pk.attrName})
 #if($formLayout == 1)
-    <el-col :span="24" class="mb20">
+        <el-col :span="24" class="mb20">
 #elseif($formLayout == 2)
-    <el-col :span="12" class="mb20">
+        <el-col :span="12" class="mb20">
 #end
 #if($field.formType == 'text')
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
-        <el-input v-model="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end"/>
-      </el-form-item>
-      </el-col>
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <el-input v-model="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end"/>
+          </el-form-item>
+        </el-col>
 #elseif($field.formType == 'textarea')
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
-        <el-input type="textarea" v-model="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end"/>
-      </el-form-item>
-      </el-col>
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <el-input type="textarea" v-model="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end"/>
+          </el-form-item>
+        </el-col>
 #elseif($field.formType == 'select')
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
-          <el-select v-model="form.${field.attrName}" placeholder="请选择#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end">
-     #if($field.fieldDict)
-            <el-option :value="item.value" :label="item.label" v-for="(item, index) in ${field.fieldDict}" :key="index"></el-option>
-       #end
-     #if(!$field.fieldDict)
-            <el-option label="请选择">0</el-option>
-       #end
-          </el-select>
-        </el-form-item>
-      </el-col>
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <el-select v-model="form.${field.attrName}" placeholder="请选择#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end">
+#if($field.fieldDict)
+              <el-option :value="item.value" :label="item.label" v-for="(item, index) in ${field.fieldDict}" :key="index"></el-option>
+#else
+              <el-option label="请选择" value="0"></el-option>
+#end
+            </el-select>
+          </el-form-item>
+        </el-col>
 #elseif($field.formType == 'radio')
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
             <el-radio-group v-model="form.${field.attrName}">
-     #if($field.fieldDict)
-             <el-radio :label="item.value" v-for="(item, index) in ${field.fieldDict}" border :key="index">{{ item.label }}
-            </el-radio>
-       #else
-           <el-radio label="${field.fieldComment}" border>${field.fieldComment}</el-radio>
-       #end
+#if($field.fieldDict)
+              <el-radio :label="item.value" v-for="(item, index) in ${field.fieldDict}" border :key="index">{{ item.label }}</el-radio>
+#else
+              <el-radio label="${field.fieldComment}" border>${field.fieldComment}</el-radio>
+#end
             </el-radio-group>
-        </el-form-item>
-      </el-col>
+          </el-form-item>
+        </el-col>
 #elseif($field.formType == 'checkbox')
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
             <el-checkbox-group v-model="form.${field.attrName}">
-     #if($field.fieldDict)
-						<el-checkbox :label="item.value" v-for="(item, index) in ${field.fieldDict}" :key="index">{{ item.label }}</el-checkbox>
-       #end
-     #if(!$field.fieldDict)
-                <el-checkbox label="启用" name="type"></el-checkbox>
-                <el-checkbox label="禁用" name="type"></el-checkbox>
-       #end
+#if($field.fieldDict)
+              <el-checkbox :label="item.value" v-for="(item, index) in ${field.fieldDict}" :key="index">{{ item.label }}</el-checkbox>
+#else
+              <el-checkbox label="启用" name="type"></el-checkbox>
+              <el-checkbox label="禁用" name="type"></el-checkbox>
+#end
             </el-checkbox-group>
-        </el-form-item>
-      </el-col>
+          </el-form-item>
+        </el-col>
 #elseif($field.formType == 'date')
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
-      <el-date-picker type="date" placeholder="请选择#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" v-model="form.${field.attrName}" :value-format="dateStr"></el-date-picker>
-      </el-form-item>
-      </el-col>
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <el-date-picker type="date" placeholder="请选择#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" v-model="form.${field.attrName}" :value-format="dateStr"></el-date-picker>
+          </el-form-item>
+        </el-col>
 #elseif($field.formType == 'datetime')
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
-            <el-date-picker type="datetime" placeholder="请选择#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" v-model="form.${field.attrName}" :value-format="dateTimeStr"></el-date-picker>
-      </el-form-item>
-      </el-col>
-
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <el-date-picker type="datetime" placeholder="请选择#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" v-model="form.${field.attrName}" :value-format="dateTimeStr"></el-date-picker>
+          </el-form-item>
+        </el-col>
 #elseif($field.formType == 'number')
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
-        <el-input-number :min="1" :max="1000" v-model="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end"></el-input-number>
-      </el-form-item>
-    </el-col>
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <el-input-number :min="1" :max="1000" v-model="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end"></el-input-number>
+          </el-form-item>
+        </el-col>
 #elseif($field.formType == 'upload-file')
-  <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
-    <upload-file v-model="form.${field.attrName}"></upload-file>
-  </el-form-item>
-  </el-col>
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <upload-file v-model="form.${field.attrName}"></upload-file>
+          </el-form-item>
+        </el-col>
 #elseif($field.formType == 'upload-img')
-  <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
-    <upload-img v-model:imageUrl="form.${field.attrName}"></upload-img>
-  </el-form-item>
-  </el-col>
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <upload-img v-model:imageUrl="form.${field.attrName}"></upload-img>
+          </el-form-item>
+        </el-col>
 #elseif($field.formType == 'editor')
-  <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
-    <editor v-if="visible" v-model:get-html="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end"></editor>
-  </el-form-item>
-  </el-col>
-#end
-
-#if(!$field.formType)
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${column.attrName}">
-        <el-input v-model="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end"/>
-      </el-form-item>
-    </el-col>
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <editor v-if="visible" v-model:get-html="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end"></editor>
+          </el-form-item>
+        </el-col>
+#else
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <el-input v-model="form.${field.attrName}" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end"/>
+          </el-form-item>
+        </el-col>
 #end
 #end
 #end
-			</el-row>
-      </el-form>
-      <template #footer>
-        <span class="dialog-footer">
-          <el-button @click="visible = false">取 消</el-button>
-          <el-button type="primary" @click="onSubmit" :disabled="loading">确 认</el-button>
-        </span>
-      </template>
-    </el-dialog>
+      </el-row>
+    </el-form>
+    <template #footer>
+      <span class="dialog-footer">
+        <el-button @click="visible = false">取 消</el-button>
+        <el-button type="primary" @click="onSubmit" :disabled="loading">确 认</el-button>
+      </span>
+    </template>
+  </el-dialog>
 </template>
 
 <script setup lang="ts" name="${ClassName}Dialog">
+// ========== 1. 导入语句 ==========
 import { useDict } from '/@/hooks/dict';
-import { useMessage } from "/@/hooks/message";
-import { getObj, addObj, putObj, validateExist } from '/@/api/${moduleName}/${functionName}'
 import { rule } from '/@/utils/validate';
+import { useMessage } from "/@/hooks/message";
+import { getObj, addObj, putObj, validateExist } from '/@/api/${moduleName}/${functionName}';
+
+// ========== 2. 组件定义 ==========
+// 定义组件事件
 const emit = defineEmits(['refresh']);
 
-// 定义变量内容
-const dataFormRef = ref();
-const visible = ref(false)
-const loading = ref(false)
-// 定义字典
-#set($fieldDict=[])
-#foreach($field in $gridList)
-	#if($field.fieldDict)
-		#set($void=$fieldDict.add($field.fieldDict))
-	#end
-#end
-#if($fieldDict)
-const { $dict.format($fieldDict) } = useDict($dict.quotation($fieldDict))
-#end
+// ========== 3. 响应式数据定义 ==========
+// 基础响应式变量
+const dataFormRef = ref(); // 表单引用
+const visible = ref(false); // 弹窗显示状态
+const loading = ref(false); // 加载状态
 
-// 提交表单数据
+// 表单数据对象
 const form = reactive({
 #if(!$formList.contains(${pk.attrName}))
-		${pk.attrName}:'',
+  ${pk.attrName}: '', // 主键
 #end
 #foreach($field in $formList)
 #if($field.formType == 'number')
-		${field.attrName}: 0,
+  ${field.attrName}: 0, // ${field.fieldComment}
 #elseif($field.formType == 'checkbox')
-    ${field.attrName}: [],
+  ${field.attrName}: [], // ${field.fieldComment}
 #else
-	  ${field.attrName}: '',
+  ${field.attrName}: '', // ${field.fieldComment}
 #end
 #end
 });
 
-// 定义校验规则
+// ========== 4. 字典数据处理 ==========
+#set($fieldDict=[])
+#foreach($field in $gridList)
+#if($field.fieldDict)
+#set($void=$fieldDict.add($field.fieldDict))
+#end
+#end
+#if($fieldDict && $fieldDict.size() > 0)
+// 加载字典数据
+const { $dict.format($fieldDict) } = useDict($dict.quotation($fieldDict));
+#end
+
+// ========== 5. 表单校验规则 ==========
 const dataRules = ref({
 #foreach($field in $formList)
 #if($field.formRequired == '1' && $field.formValidator == 'duplicate')
-    ${field.attrName}: [{required: true, message: '${field.fieldComment}不能为空', trigger: 'blur'}, {
+  ${field.attrName}: [
+    { required: true, message: '${field.fieldComment}不能为空', trigger: 'blur' },
+    {
       validator: (rule: any, value: any, callback: any) => {
+        // 重复性校验(编辑时跳过)
         validateExist(rule, value, callback, form.${pk.attrName} !== '');
       },
       trigger: 'blur',
-    }],
+    }
+  ],
 #elseif($field.formRequired == '1' && $field.formValidator)
-    ${field.attrName}: [{required: true, message: '${field.fieldComment}不能为空', trigger: 'blur'}, { validator: rule.${field.formValidator}, trigger: 'blur' }],
+  ${field.attrName}: [
+    { required: true, message: '${field.fieldComment}不能为空', trigger: 'blur' },
+    { validator: rule.${field.formValidator}, trigger: 'blur' }
+  ],
 #elseif($field.formRequired == '1')
-    ${field.attrName}: [{required: true, message: '${field.fieldComment}不能为空', trigger: 'blur'}],
+  ${field.attrName}: [
+    { required: true, message: '${field.fieldComment}不能为空', trigger: 'blur' }
+  ],
 #elseif($field.formValidator)
-    ${field.attrName}: [{ validator: rule.${field.formValidator}, trigger: 'blur' }],
+  ${field.attrName}: [
+    { validator: rule.${field.formValidator}, trigger: 'blur' }
+  ],
 #end
 #end
-})
+});
 
-// 打开弹窗
+// ========== 6. 方法定义 ==========
+// 获取详情数据
+const get${ClassName}Data = async (id: string) => {
+  try {
+    loading.value = true;
+    const { data } = await getObj({ ${pk.attrName}: id });
+    // 直接将第一条数据赋值给表单
+    Object.assign(form, data[0]);
+  } catch (error) {
+    useMessage().error('获取数据失败');
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 打开弹窗方法
 const openDialog = (id: string) => {
-  visible.value = true
-  form.${pk.attrName} = ''
+  visible.value = true;
+  form.${pk.attrName} = '';
 
   // 重置表单数据
-	nextTick(() => {
-		dataFormRef.value?.resetFields();
-	});
+  nextTick(() => {
+    dataFormRef.value?.resetFields();
+  });
 
-  // 获取${className}信息
+  // 获取${ClassName}信息
   if (id) {
-    form.${pk.attrName} = id
-    get${ClassName}Data(id)
+    form.${pk.attrName} = id;
+    get${ClassName}Data(id);
   }
 };
 
-// 提交
+// 提交表单方法
 const onSubmit = async () => {
-	const valid = await dataFormRef.value.validate().catch(() => {});
-	if (!valid) return false;
-
-	try {
-    loading.value = true;
-		form.${pk.attrName} ? await putObj(form) : await addObj(form);
-		useMessage().success(form.${pk.attrName} ? '修改成功' : '添加成功');
-		visible.value = false;
-		emit('refresh');
-	} catch (err: any) {
-		useMessage().error(err.msg);
-	} finally {
+  loading.value = true; // 防止重复提交
+  
+  // 表单校验
+  const valid = await dataFormRef.value.validate().catch(() => {});
+  if (!valid) {
     loading.value = false;
+    return false;
   }
-};
-
 
-// 初始化表单数据
-const get${ClassName}Data = (id: string) => {
-  // 获取数据
-  loading.value = true
-  getObj({${pk.attrName}: id}).then((res: any) => {
-    Object.assign(form, res.data[0])
-  }).finally(() => {
-    loading.value = false
-  })
+  try {
+    // 根据是否有ID判断是新增还是修改
+    form.${pk.attrName} ? await putObj(form) : await addObj(form);
+    useMessage().success(form.${pk.attrName} ? '修改成功' : '添加成功');
+    visible.value = false;
+    emit('refresh'); // 通知父组件刷新列表
+  } catch (err: any) {
+    useMessage().error(err.msg);
+  } finally {
+    loading.value = false;
+  }
 };
 
-// 暴露变量
+// ========== 7. 对外暴露 ==========
+// 暴露方法给父组件
 defineExpose({
   openDialog
 });
-</script>
+</script> 

+ 207 - 100
single/表格.vue

@@ -2,183 +2,290 @@
   <div class="layout-padding">
     <div class="layout-padding-auto layout-padding-view">
 #if($queryList)
+      <!-- 查询表单区域 -->
       <el-row v-show="showSearch">
         <el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
 #foreach($field in $queryList)
 #if($field.queryFormType == 'select')
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
-            <el-select v-model="state.queryForm.${field.attrName}" placeholder="请选择#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end">
-       #if($field.fieldDict)
-              <el-option :label="item.label" :value="item.value" v-for="(item, index) in ${field.fieldDict}" :key="index"></el-option>
-         #else
-              <el-option label="请选择">0</el-option>
-         #end
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <el-select v-model="state.queryForm.${field.attrName}" placeholder="请选择#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end">
+#if($field.fieldDict)
+              <el-option 
+                :label="item.label" 
+                :value="item.value" 
+                v-for="(item, index) in ${field.fieldDict}" 
+                :key="index"
+              />
+#else
+              <el-option label="请选择" value="0" />
+#end
             </el-select>
-      </el-form-item>
+          </el-form-item>
 #elseif($field.queryFormType == 'date')
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
-      <el-date-picker type="date" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" v-model="state.queryForm.${field.attrName}"></el-date-picker>
-      </el-form-item>
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <el-date-picker 
+              type="date" 
+              placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" 
+              v-model="state.queryForm.${field.attrName}"
+            />
+          </el-form-item>
 #elseif($field.queryFormType == 'datetime')
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}" >
-            <el-date-picker type="datetime" placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" v-model="state.queryForm.${field.attrName}"></el-date-picker>
-      </el-form-item>
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <el-date-picker 
+              type="datetime" 
+              placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" 
+              v-model="state.queryForm.${field.attrName}"
+            />
+          </el-form-item>
 #elseif($field.formType == 'radio')
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}">
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
             <el-radio-group v-model="state.queryForm.${field.attrName}">
-     #if($field.fieldDict)
-             <el-radio :label="item.value" v-for="(item, index) in ${field.fieldDict}" border :key="index">{{ item.label }}
-            </el-radio>
-       #else
-           <el-radio label="${field.fieldComment}" border>${field.fieldComment}</el-radio>
-       #end
+#if($field.fieldDict)
+              <el-radio 
+                :label="item.value" 
+                v-for="(item, index) in ${field.fieldDict}" 
+                border 
+                :key="index"
+              >
+                {{ item.label }}
+              </el-radio>
+#else
+              <el-radio label="${field.fieldComment}" border>
+                ${field.fieldComment}
+              </el-radio>
+#end
             </el-radio-group>
-     </el-form-item>
+          </el-form-item>
 #else
-      <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" prop="${field.attrName}" >
-        <el-input placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" v-model="state.queryForm.${field.attrName}" />
-      </el-form-item>
+          <el-form-item label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" prop="${field.attrName}">
+            <el-input 
+              placeholder="请输入#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" 
+              v-model="state.queryForm.${field.attrName}" 
+            />
+          </el-form-item>
 #end
 #end
           <el-form-item>
             <el-button icon="search" type="primary" @click="getDataList">
-              查 
+              查询
             </el-button>
-            <el-button icon="Refresh" @click="resetQuery">重 置</el-button>
+            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
           </el-form-item>
         </el-form>
       </el-row>
 #end
+
+      <!-- 操作按钮区域 -->
       <el-row>
         <div class="mb8" style="width: 100%">
-          <el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()"
-            v-auth="'${moduleName}_${functionName}_add'">
-            新 增
+          <el-button 
+            icon="folder-add" 
+            type="primary" 
+            class="ml10" 
+            @click="formDialogRef.openDialog()"
+            v-auth="'${moduleName}_${functionName}_add'"
+          >
+            新增
           </el-button>
-          <el-button plain icon="upload-filled" type="primary" class="ml10" @click="excelUploadRef.show()" v-auth="'sys_user_add'">
-						导 入
-					</el-button>
-          <el-button plain :disabled="multiple" icon="Delete" type="primary"
-            v-auth="'${moduleName}_${functionName}_del'" @click="handleDelete(selectObjs)">
-            删 除
+          <el-button 
+            plain 
+            icon="upload-filled" 
+            type="primary" 
+            class="ml10" 
+            @click="excelUploadRef.show()" 
+            v-auth="'${moduleName}_${functionName}_add'"
+          >
+            导入
           </el-button>
-          <right-toolbar v-model:showSearch="showSearch" :export="'${moduleName}_${functionName}_export'"
-                @exportExcel="exportExcel" class="ml10 mr20" style="float: right;"
-            @queryTable="getDataList"></right-toolbar>
+          <el-button 
+            plain 
+            :disabled="multiple" 
+            icon="Delete" 
+            type="primary"
+            v-auth="'${moduleName}_${functionName}_del'" 
+            @click="handleDelete(selectObjs)"
+          >
+            删除
+          </el-button>
+          <right-toolbar 
+            v-model:showSearch="showSearch" 
+            :export="'${moduleName}_${functionName}_export'"
+            @exportExcel="exportExcel" 
+            class="ml10 mr20" 
+            style="float: right;"
+            @queryTable="getDataList"
+          />
         </div>
       </el-row>
-      <el-table :data="state.dataList" v-loading="state.loading" border 
-        :cell-style="tableStyle.cellStyle" :header-cell-style="tableStyle.headerCellStyle"
-				@selection-change="selectionChangHandle"
-        @sort-change="sortChangeHandle">
+
+      <!-- 数据表格区域 -->
+      <el-table 
+        :data="state.dataList" 
+        v-loading="state.loading" 
+        border 
+        :cell-style="tableStyle.cellStyle" 
+        :header-cell-style="tableStyle.headerCellStyle"
+        @selection-change="selectionChangHandle"
+        @sort-change="sortChangeHandle"
+      >
         <el-table-column type="selection" width="40" align="center" />
         <el-table-column type="index" label="#" width="40" />
-      #foreach($field in $gridList)
-        #if($field.fieldDict)
-          <el-table-column prop="${field.attrName}" label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" show-overflow-tooltip>
-      <template #default="scope">
-                <dict-tag :options="$field.fieldDict" :value="scope.row.${field.attrName}"></dict-tag>
-            </template>
-          </el-table-column>
-        #else
-          <el-table-column prop="${field.attrName}" label="#if(${field.fieldComment})${field.fieldComment}#else ${field.attrName}#end" #if(${field.gridSort} == '1')sortable="custom"#end show-overflow-tooltip/>
-        #end
-     #end
+#foreach($field in $gridList)
+#if($field.fieldDict)
+        <el-table-column prop="${field.attrName}" label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" show-overflow-tooltip>
+          <template #default="scope">
+            <dict-tag :options="$field.fieldDict" :value="scope.row.${field.attrName}" />
+          </template>
+        </el-table-column>
+#else
+        <el-table-column 
+          prop="${field.attrName}" 
+          label="#if(${field.fieldComment})${field.fieldComment}#else${field.attrName}#end" 
+#if(${field.gridSort} == '1')
+          sortable="custom" 
+#end
+          show-overflow-tooltip
+        />
+#end
+#end
         <el-table-column label="操作" width="150">
           <template #default="scope">
-            <el-button icon="edit-pen" text type="primary" v-auth="'${moduleName}_${functionName}_edit'"
-              @click="formDialogRef.openDialog(scope.row.${pk.attrName})">编辑</el-button>
-            <el-button icon="delete" text type="primary" v-auth="'${moduleName}_${functionName}_del'" @click="handleDelete([scope.row.${pk.attrName}])">删除</el-button>
+            <el-button 
+              icon="edit-pen" 
+              text 
+              type="primary" 
+              v-auth="'${moduleName}_${functionName}_edit'"
+              @click="formDialogRef.openDialog(scope.row.${pk.attrName})"
+            >
+              编辑
+            </el-button>
+            <el-button 
+              icon="delete" 
+              text 
+              type="primary" 
+              v-auth="'${moduleName}_${functionName}_del'" 
+              @click="handleDelete([scope.row.${pk.attrName}])"
+            >
+              删除
+            </el-button>
           </template>
         </el-table-column>
       </el-table>
-      <pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
+
+      <!-- 分页组件 -->
+      <pagination 
+        @size-change="sizeChangeHandle" 
+        @current-change="currentChangeHandle" 
+        v-bind="state.pagination" 
+      />
     </div>
 
-    <!-- 编辑、新增  -->
+    <!-- 编辑、新增弹窗 -->
     <form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
 
-    <!-- 导入excel (需要在 upms-biz/resources/file 下维护模板) -->
+    <!-- 导入excel弹窗 (需要在 upms-biz/resources/file 下维护模板) -->
     <upload-excel
-			ref="excelUploadRef"
-			title="导入"
-			url="/${moduleName}/${functionName}/import"
+      ref="excelUploadRef"
+      title="导入"
+      url="/${moduleName}/${functionName}/import"
       temp-url="/admin/sys-file/local/file/${functionName}.xlsx"
-			@refreshDataList="getDataList"
-		/>
+      @refreshDataList="getDataList"
+    />
   </div>
 </template>
 
 <script setup lang="ts" name="system${ClassName}">
+// ========== 导入声明 ==========
 import { BasicTableProps, useTable } from "/@/hooks/table";
 import { fetchList, delObjs } from "/@/api/${moduleName}/${functionName}";
 import { useMessage, useMessageBox } from "/@/hooks/message";
 import { useDict } from '/@/hooks/dict';
 
-// 引入组件
+// ========== 组件声明 ==========
+// 异步加载表单弹窗组件
 const FormDialog = defineAsyncComponent(() => import('./form.vue'));
-// 定义查询字典
+
+// ========== 字典数据 ==========
 #set($fieldDict=[])
 #foreach($field in $queryList)
-  #if($field.fieldDict)
-    #set($void=$fieldDict.add($field.fieldDict))
-  #end
+#if($field.fieldDict)
+#set($void=$fieldDict.add($field.fieldDict))
+#end
 #end
-
 #foreach($field in $gridList)
-  #if($field.fieldDict)
-    #set($void=$fieldDict.add($field.fieldDict))
-  #end
+#if($field.fieldDict)
+#set($void=$fieldDict.add($field.fieldDict))
+#end
 #end
 #if($fieldDict)
-const { $dict.format($fieldDict) } = useDict($dict.quotation($fieldDict))
+// 加载字典数据
+const { $dict.format($fieldDict) } = useDict($dict.quotation($fieldDict));
 #end
-// 定义变量内容
-const formDialogRef = ref()
-const excelUploadRef = ref();
-// 搜索变量
-const queryRef = ref()
-const showSearch = ref(true)
-// 多选变量
-const selectObjs = ref([]) as any
-const multiple = ref(true)
 
+// ========== 组件引用 ==========
+const formDialogRef = ref();          // 表单弹窗引用
+const excelUploadRef = ref();         // Excel上传弹窗引用
+const queryRef = ref();               // 查询表单引用
+
+// ========== 响应式数据 ==========
+const showSearch = ref(true);         // 是否显示搜索区域
+const selectObjs = ref([]) as any;    // 表格多选数据
+const multiple = ref(true);           // 是否多选
+
+// ========== 表格状态 ==========
 const state: BasicTableProps = reactive<BasicTableProps>({
-  queryForm: {},
-  pageList: fetchList
-})
+  queryForm: {},    // 查询参数
+  pageList: fetchList // 分页查询方法
+});
 
-//  table hook
+// ========== Hook引用 ==========
+// 表格相关Hook
 const {
   getDataList,
   currentChangeHandle,
   sizeChangeHandle,
   sortChangeHandle,
   downBlobFile,
-	tableStyle
-} = useTable(state)
+  tableStyle
+} = useTable(state);
 
-// 清空搜索条件
+// ========== 方法定义 ==========
+/**
+ * 重置查询条件
+ */
 const resetQuery = () => {
   // 清空搜索条件
-  queryRef.value?.resetFields()
+  queryRef.value?.resetFields();
   // 清空多选
-  selectObjs.value = []
-  getDataList()
-}
+  selectObjs.value = [];
+  // 重新查询
+  getDataList();
+};
 
-// 导出excel
+/**
+ * 导出Excel文件
+ */
 const exportExcel = () => {
-  downBlobFile('/${moduleName}/${functionName}/export', Object.assign(state.queryForm, { ids: selectObjs }), '${functionName}.xlsx')
-}
+  downBlobFile(
+    '/${moduleName}/${functionName}/export',
+    Object.assign(state.queryForm, { ids: selectObjs }),
+    '${functionName}.xlsx'
+  );
+};
 
-// 多选事件
+/**
+ * 表格多选事件处理
+ * @param objs 选中的数据行
+ */
 const selectionChangHandle = (objs: { $pk.attrName: string }[]) => {
   selectObjs.value = objs.map(({ $pk.attrName }) => $pk.attrName);
   multiple.value = !objs.length;
 };
 
-// 删除操作
+/**
+ * 删除数据处理
+ * @param ids 要删除的数据ID数组
+ */
 const handleDelete = async (ids: string[]) => {
   try {
     await useMessageBox().confirm('此操作将永久删除');