签入版本
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
@@ -0,0 +1,82 @@
|
||||
# +======================================================================
|
||||
# | DjangoAdmin 企业数字化开发平台 [ 赋能开发者,助力企业发展 ]
|
||||
# +----------------------------------------------------------------------
|
||||
# | Copyright (c) 2021-2026 小蚂蚁云团队 版权所有
|
||||
# +----------------------------------------------------------------------
|
||||
# | 开源协议: Apache-2.0
|
||||
# | 重要声明: 未经书面许可,不得移除或修改本框架相关版权标识。
|
||||
# +----------------------------------------------------------------------
|
||||
# | 官方网站: https://www.djangoadmin.cn
|
||||
# +----------------------------------------------------------------------
|
||||
# | 研发团队: 小蚂蚁云团队 荣誉出品
|
||||
# +======================================================================
|
||||
# | 版权和免责声明:
|
||||
# | 一、知识产权声明
|
||||
# | 本团队对该软件框架产品(以下简称“本产品”)拥有完整知识产权,包括但不限于商标权、专利权、
|
||||
# | 著作权、商业秘密等。前述权利均受中华人民共和国及相关国际法律法规保护。未经本团队书面授权,
|
||||
# | 任何个人或单位不得基于本产品本身申请任何形式的知识产权。
|
||||
# | 二、使用限制与禁止条款
|
||||
# | 您理解并同意,禁止将本产品用于以下任何行为:
|
||||
# | 1. 任何违反中华人民共和国法律法规的用途;
|
||||
# | 2. 任何侵害他人合法权益(包括但不限于人身权、财产权、知识产权等)的行为;
|
||||
# | 3. 任何危害国家安全、公共利益及社会道德风尚的行为。
|
||||
# | 三、责任豁免
|
||||
# | 因使用本产品而产生的任何损失或法律纠纷(包括但不限于直接损失、间接损失、附带损失、衍生损失
|
||||
# | 以及因违约、侵权等引发的责任),本团队均不承担任何法律责任。若因违规使用本产品导致任何第三
|
||||
# | 方提起索赔或行政机关进行调查,您应独立承担全部责任。
|
||||
# | 四、违约与法律责任
|
||||
# | 如发现任何违反本声明的行为,本团队有权:
|
||||
# | 1. 无条件配合公安机关及其他有权机关的调查取证工作;
|
||||
# | 2. 依法追究相关方的民事责任,并要求赔偿全部损失;
|
||||
# | 3. 保留进一步采取刑事控告等法律措施的权利。
|
||||
# | 五、许可范围说明
|
||||
# | 1、被授权方应视本产品源代码为核心机密信息,负有最高标准的保密与保管义务。禁止以任何形式(包
|
||||
# | 括但不限于直接或间接的分享、复制、传播、分发、转售、出租、开源、反向工程、反编译、反汇编或通
|
||||
# | 过网络服务提供给任何第三方)泄露、披露或处置源代码的全部或部分内容。任何未经授权的复制、使用、
|
||||
# | 传播行为均构成对本团队知识产权的严重侵权,本团队有权依法追究其全部法律责任,并要求赔偿因此造
|
||||
# | 成的一切经济损失及商誉损害。
|
||||
# | 2、本产品仅限于公司或个人在法律允许范围内,用于内部且合规的软件产品研发。具体权利义务以《软件
|
||||
# | 许可协议》附件为准。
|
||||
# +======================================================================
|
||||
|
||||
"""
|
||||
{{ module_comment }}应用配置模块模板
|
||||
=============================================================
|
||||
|
||||
该模板用于生成{{ module_comment }}管理应用的配置类,用于Django应用注册和初始化。
|
||||
|
||||
模板变量说明:
|
||||
- module_comment: 模块注释,如"文章管理"
|
||||
- app_name: 应用名称,如"article"
|
||||
- model_class_name: 模型类名,如"Article"
|
||||
"""
|
||||
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class {{ model_class_name }}Config(AppConfig):
|
||||
"""
|
||||
{{ module_comment }}应用配置类
|
||||
|
||||
该类用于配置 'application.{{ app_name }}' 应用的基本属性和行为。
|
||||
继承自 Django 的 AppConfig 基类,在 Django 启动时自动加载。
|
||||
|
||||
主要功能:
|
||||
- 指定应用的默认主键字段类型
|
||||
- 定义应用的 Python 导入路径
|
||||
- 可在 ready() 方法中执行应用启动时的初始化操作
|
||||
"""
|
||||
|
||||
# 默认主键字段类型配置
|
||||
# BigAutoField:64位整数自增主键,范围更大(-9223372036854775808 到 9223372036854775807)
|
||||
# 相比默认的 AutoField(32位整数),BigAutoField 的优势:
|
||||
# 1. 支持更大的数据量,适合高并发、大数据量场景
|
||||
# 2. 避免主键溢出的风险,提高系统稳定性
|
||||
# 3. 与分布式系统兼容性更好
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
|
||||
# 应用导入路径配置
|
||||
# 指定该应用在项目中的 Python 导入路径,格式为 '模块名.应用名'
|
||||
# 该路径必须与 INSTALLED_APPS 设置中的路径完全一致
|
||||
# 例如:'application.{{ app_name }}' 表示应用位于 application/{{ app_name }} 目录下
|
||||
name = 'application.{{ app_name }}'
|
||||
@@ -0,0 +1,183 @@
|
||||
# +======================================================================
|
||||
# | DjangoAdmin 企业数字化开发平台 [ 赋能开发者,助力企业发展 ]
|
||||
# +----------------------------------------------------------------------
|
||||
# | Copyright (c) 2021-2026 小蚂蚁云团队 版权所有
|
||||
# +----------------------------------------------------------------------
|
||||
# | 开源协议: Apache-2.0
|
||||
# | 重要声明: 未经书面许可,不得移除或修改本框架相关版权标识。
|
||||
# +----------------------------------------------------------------------
|
||||
# | 官方网站: https://www.djangoadmin.cn
|
||||
# +----------------------------------------------------------------------
|
||||
# | 研发团队: 小蚂蚁云团队 荣誉出品
|
||||
# +======================================================================
|
||||
# | 版权和免责声明:
|
||||
# | 一、知识产权声明
|
||||
# | 本团队对该软件框架产品(以下简称“本产品”)拥有完整知识产权,包括但不限于商标权、专利权、
|
||||
# | 著作权、商业秘密等。前述权利均受中华人民共和国及相关国际法律法规保护。未经本团队书面授权,
|
||||
# | 任何个人或单位不得基于本产品本身申请任何形式的知识产权。
|
||||
# | 二、使用限制与禁止条款
|
||||
# | 您理解并同意,禁止将本产品用于以下任何行为:
|
||||
# | 1. 任何违反中华人民共和国法律法规的用途;
|
||||
# | 2. 任何侵害他人合法权益(包括但不限于人身权、财产权、知识产权等)的行为;
|
||||
# | 3. 任何危害国家安全、公共利益及社会道德风尚的行为。
|
||||
# | 三、责任豁免
|
||||
# | 因使用本产品而产生的任何损失或法律纠纷(包括但不限于直接损失、间接损失、附带损失、衍生损失
|
||||
# | 以及因违约、侵权等引发的责任),本团队均不承担任何法律责任。若因违规使用本产品导致任何第三
|
||||
# | 方提起索赔或行政机关进行调查,您应独立承担全部责任。
|
||||
# | 四、违约与法律责任
|
||||
# | 如发现任何违反本声明的行为,本团队有权:
|
||||
# | 1. 无条件配合公安机关及其他有权机关的调查取证工作;
|
||||
# | 2. 依法追究相关方的民事责任,并要求赔偿全部损失;
|
||||
# | 3. 保留进一步采取刑事控告等法律措施的权利。
|
||||
# | 五、许可范围说明
|
||||
# | 1、被授权方应视本产品源代码为核心机密信息,负有最高标准的保密与保管义务。禁止以任何形式(包
|
||||
# | 括但不限于直接或间接的分享、复制、传播、分发、转售、出租、开源、反向工程、反编译、反汇编或通
|
||||
# | 过网络服务提供给任何第三方)泄露、披露或处置源代码的全部或部分内容。任何未经授权的复制、使用、
|
||||
# | 传播行为均构成对本团队知识产权的严重侵权,本团队有权依法追究其全部法律责任,并要求赔偿因此造
|
||||
# | 成的一切经济损失及商誉损害。
|
||||
# | 2、本产品仅限于公司或个人在法律允许范围内,用于内部且合规的软件产品研发。具体权利义务以《软件
|
||||
# | 许可协议》附件为准。
|
||||
# +======================================================================
|
||||
|
||||
"""
|
||||
{{ module_comment }}表单验证模块模板
|
||||
=============================================================
|
||||
|
||||
该模板用于生成{{ module_comment }}管理功能中使用的表单验证类。
|
||||
用于对前端提交的{{ module_comment }}数据进行验证,确保数据符合业务规则和数据库约束。
|
||||
{{ module_comment }}用于{{ business_description }}。
|
||||
|
||||
模板变量说明:
|
||||
- module_comment: 模块注释,如"文章管理"
|
||||
- app_name: 应用名称,如"article"
|
||||
- model_class_name: 模型类名,如"Article"
|
||||
- form_fields: 表单字段列表
|
||||
- has_unique_code: 是否包含唯一编码字段
|
||||
- business_description: 业务描述
|
||||
- business_description_detail: 详细业务描述
|
||||
"""
|
||||
|
||||
from django import forms
|
||||
|
||||
from application.{{ app_name }} import models
|
||||
|
||||
|
||||
# =============================================================
|
||||
# {{ module_comment }}表单验证类
|
||||
# =============================================================
|
||||
|
||||
class {{ model_class_name }}Form(forms.ModelForm):
|
||||
"""
|
||||
{{ module_comment }}表单验证类
|
||||
|
||||
用于创建和更新{{ module_comment }}信息时的表单验证。
|
||||
{{ business_description_detail }}
|
||||
|
||||
验证字段包括:
|
||||
{% for field in form_fields %}
|
||||
- {{ field.camel_name }}: {{ field.comment }}
|
||||
{% endfor %}
|
||||
"""
|
||||
|
||||
{% for field in form_fields %}
|
||||
# ----------------------------------------------------------
|
||||
# {{ field.comment }}
|
||||
# ----------------------------------------------------------
|
||||
# 字段说明: {{ field.purpose }}
|
||||
# 字段类型: {{ field.type_display }}
|
||||
# 验证规则: {% if field.required %}必填(required=True){% else %}可选填(required=False){% endif %}{% if field.max_length %},最大长度{{ field.max_length }}字符{% endif %}{% if field.min_value != None %},最小值{{ field.min_value }}{% endif %}{% if field.max_value != None %},最大值{{ field.max_value }}{% endif %}
|
||||
# 业务说明: {{ field.purpose }}
|
||||
# 示例: {{ field.example }}
|
||||
{{ field.camel_name }} = forms.{{ field.form_field_type }}(
|
||||
{% if field.required %}
|
||||
required=True,
|
||||
{% else %}
|
||||
required=False,
|
||||
{% endif %}
|
||||
{% if field.max_length %}
|
||||
max_length={{ field.max_length }},
|
||||
{% endif %}
|
||||
{% if field.min_value != None %}
|
||||
min_value={{ field.min_value }},
|
||||
{% endif %}
|
||||
{% if field.max_value != None %}
|
||||
max_value={{ field.max_value }},
|
||||
{% endif %}
|
||||
error_messages={
|
||||
{% if field.required %}
|
||||
'required': '{{ field.label }}不能为空',
|
||||
{% endif %}
|
||||
{% if field.max_length %}
|
||||
'max_length': '{{ field.label }}长度不得超过{{ field.max_length }}个字符',
|
||||
{% endif %}
|
||||
{% if field.min_value != None %}
|
||||
'min_value': '{{ field.label }}不能小于{{ field.min_value }}',
|
||||
{% endif %}
|
||||
{% if field.max_value != None %}
|
||||
'max_value': '{{ field.label }}不能大于{{ field.max_value }}',
|
||||
{% endif %}
|
||||
}
|
||||
)
|
||||
|
||||
{% endfor %}
|
||||
# =============================================================
|
||||
# 表单元数据配置
|
||||
# =============================================================
|
||||
|
||||
class Meta:
|
||||
"""
|
||||
表单元数据配置类
|
||||
|
||||
定义表单绑定的模型和需要验证的字段。
|
||||
"""
|
||||
|
||||
# 绑定模型
|
||||
# 指定该表单对应的数据模型为 {{ model_class_name }}({{ module_comment }})
|
||||
model = models.{{ model_class_name }}
|
||||
|
||||
# 指定需要验证的字段
|
||||
# 只验证以下字段,其他字段不进行表单验证
|
||||
fields = [
|
||||
{% for field in form_fields %}
|
||||
'{{ field.camel_name }}',
|
||||
{% endfor %}
|
||||
]
|
||||
|
||||
{% if has_unique_code %}
|
||||
# =============================================================
|
||||
# 自定义验证方法
|
||||
# =============================================================
|
||||
|
||||
def clean_code(self):
|
||||
"""
|
||||
自定义编码唯一性验证
|
||||
|
||||
验证编码的唯一性,确保编码不重复。
|
||||
|
||||
Returns:
|
||||
str: 清洗后的编码
|
||||
|
||||
Raises:
|
||||
forms.ValidationError: 编码格式错误或编码已存在时抛出
|
||||
"""
|
||||
code = self.cleaned_data.get('code')
|
||||
|
||||
if code:
|
||||
# 验证编码格式:只允许大写字母、数字和下划线
|
||||
if not code.replace('_', '').isalnum() or not code.isupper():
|
||||
raise forms.ValidationError('编码只能包含大写字母、数字和下划线')
|
||||
|
||||
# 验证编码唯一性(排除当前实例)
|
||||
instance = getattr(self, 'instance', None)
|
||||
queryset = models.{{ model_class_name }}.objects.filter(code=code)
|
||||
|
||||
# 如果是更新操作,排除当前记录本身
|
||||
if instance and instance.pk:
|
||||
queryset = queryset.exclude(pk=instance.pk)
|
||||
|
||||
# 如果编码已存在,抛出验证错误
|
||||
if queryset.exists():
|
||||
raise forms.ValidationError('编码已存在,请使用其他编码')
|
||||
|
||||
return code
|
||||
{% endif %}
|
||||
@@ -0,0 +1,185 @@
|
||||
# +======================================================================
|
||||
# | DjangoAdmin 企业数字化开发平台 [ 赋能开发者,助力企业发展 ]
|
||||
# +----------------------------------------------------------------------
|
||||
# | Copyright (c) 2021-2026 小蚂蚁云团队 版权所有
|
||||
# +----------------------------------------------------------------------
|
||||
# | 开源协议: Apache-2.0
|
||||
# | 重要声明: 未经书面许可,不得移除或修改本框架相关版权标识。
|
||||
# +----------------------------------------------------------------------
|
||||
# | 官方网站: https://www.djangoadmin.cn
|
||||
# +----------------------------------------------------------------------
|
||||
# | 研发团队: 小蚂蚁云团队 荣誉出品
|
||||
# +======================================================================
|
||||
# | 版权和免责声明:
|
||||
# | 一、知识产权声明
|
||||
# | 本团队对该软件框架产品(以下简称“本产品”)拥有完整知识产权,包括但不限于商标权、专利权、
|
||||
# | 著作权、商业秘密等。前述权利均受中华人民共和国及相关国际法律法规保护。未经本团队书面授权,
|
||||
# | 任何个人或单位不得基于本产品本身申请任何形式的知识产权。
|
||||
# | 二、使用限制与禁止条款
|
||||
# | 您理解并同意,禁止将本产品用于以下任何行为:
|
||||
# | 1. 任何违反中华人民共和国法律法规的用途;
|
||||
# | 2. 任何侵害他人合法权益(包括但不限于人身权、财产权、知识产权等)的行为;
|
||||
# | 3. 任何危害国家安全、公共利益及社会道德风尚的行为。
|
||||
# | 三、责任豁免
|
||||
# | 因使用本产品而产生的任何损失或法律纠纷(包括但不限于直接损失、间接损失、附带损失、衍生损失
|
||||
# | 以及因违约、侵权等引发的责任),本团队均不承担任何法律责任。若因违规使用本产品导致任何第三
|
||||
# | 方提起索赔或行政机关进行调查,您应独立承担全部责任。
|
||||
# | 四、违约与法律责任
|
||||
# | 如发现任何违反本声明的行为,本团队有权:
|
||||
# | 1. 无条件配合公安机关及其他有权机关的调查取证工作;
|
||||
# | 2. 依法追究相关方的民事责任,并要求赔偿全部损失;
|
||||
# | 3. 保留进一步采取刑事控告等法律措施的权利。
|
||||
# | 五、许可范围说明
|
||||
# | 1、被授权方应视本产品源代码为核心机密信息,负有最高标准的保密与保管义务。禁止以任何形式(包
|
||||
# | 括但不限于直接或间接的分享、复制、传播、分发、转售、出租、开源、反向工程、反编译、反汇编或通
|
||||
# | 过网络服务提供给任何第三方)泄露、披露或处置源代码的全部或部分内容。任何未经授权的复制、使用、
|
||||
# | 传播行为均构成对本团队知识产权的严重侵权,本团队有权依法追究其全部法律责任,并要求赔偿因此造
|
||||
# | 成的一切经济损失及商誉损害。
|
||||
# | 2、本产品仅限于公司或个人在法律允许范围内,用于内部且合规的软件产品研发。具体权利义务以《软件
|
||||
# | 许可协议》附件为准。
|
||||
# +======================================================================
|
||||
|
||||
"""
|
||||
{{ module_comment }}模型模块模板
|
||||
=============================================================
|
||||
|
||||
该模板用于生成{{ module_comment }}相关的数据库模型。
|
||||
{{ module_comment }}用于{{ business_description }}。
|
||||
|
||||
模板变量说明:
|
||||
- module_comment: 模块注释,如"文章管理"
|
||||
- model_class_name: 模型类名,如"Article"
|
||||
- table_name: 数据表名,如"article"
|
||||
- fields: 字段列表
|
||||
- has_sort: 是否包含排序字段
|
||||
- display_field: 显示字段名
|
||||
- business_description: 业务描述
|
||||
- business_description_detail: 详细业务描述
|
||||
"""
|
||||
|
||||
from django.db import models
|
||||
|
||||
from application.models import BaseModel
|
||||
from utils.common import get_table_name
|
||||
|
||||
|
||||
# =============================================================
|
||||
# {{ module_comment }}模型类
|
||||
# =============================================================
|
||||
|
||||
class {{ model_class_name }}(BaseModel):
|
||||
"""
|
||||
{{ module_comment }}模型类
|
||||
|
||||
用于存储系统中的{{ module_comment }}信息。
|
||||
{{ business_description_detail }}
|
||||
继承自 BaseModel,自动包含:
|
||||
- id: 主键
|
||||
- is_delete: 逻辑删除标识
|
||||
- create_user: 创建人
|
||||
- create_time: 创建时间
|
||||
- update_user: 更新人
|
||||
- update_time: 更新时间
|
||||
|
||||
主要业务字段:
|
||||
{% for field in fields %}
|
||||
- {{ field.name }}: {{ field.comment }}
|
||||
{% endfor %}
|
||||
"""
|
||||
|
||||
{% for field in fields %}
|
||||
# ----------------------------------------------------------
|
||||
# {{ field.comment }}
|
||||
# ----------------------------------------------------------
|
||||
# 字段说明: {{ field.purpose }}
|
||||
# 字段类型: {{ field.type_display }}
|
||||
# 约束: {% if field.nullable %}允许为空(null=True){% else %}非空(null=False){% endif %}{% if field.max_length %},最大长度{{ field.max_length }}字符{% endif %}{% if field.is_unique %},唯一约束{% endif %}
|
||||
# 索引: {% if field.db_index %}添加了数据库索引(db_index=True)以提升查询效率{% else %}未添加索引{% endif %}
|
||||
# 示例: {{ field.example }}
|
||||
# 作用: {{ field.purpose }}
|
||||
{% if field.choices %}
|
||||
# 选项常量定义
|
||||
{{ field.name|upper }}_CHOICES = (
|
||||
{% for choice in field.choices %}
|
||||
({{ choice.value }}, "{{ choice.label }}"), # {{ choice.label }}状态
|
||||
{% endfor %}
|
||||
)
|
||||
{% endif %}
|
||||
|
||||
{{ field.name }} = models.{{ field.model_field_type }}(
|
||||
{% if field.nullable %}
|
||||
null=True,
|
||||
blank=True,
|
||||
{% else %}
|
||||
null=False,
|
||||
{% endif %}
|
||||
{% if field.max_length %}
|
||||
max_length={{ field.max_length }},
|
||||
{% endif %}
|
||||
{% if field.is_unique %}
|
||||
unique=True,
|
||||
{% endif %}
|
||||
{% if field.choices %}
|
||||
choices={{ field.name|upper }}_CHOICES,
|
||||
{% endif %}
|
||||
{% if field.default != None and field.default != 'None' %}
|
||||
{% if not field.nullable and field.default == 'None' %}
|
||||
default='',
|
||||
db_default='',
|
||||
{% else %}
|
||||
default={{ field.default }},
|
||||
db_default={{ field.default }},
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if field.db_index %}
|
||||
db_index=True,
|
||||
{% endif %}
|
||||
verbose_name="{{ field.comment }}",
|
||||
help_text="{{ field.comment }}",
|
||||
db_comment="{{ field.comment }}" # 数据库字段注释
|
||||
)
|
||||
|
||||
{% endfor %}
|
||||
# =============================================================
|
||||
# 模型元数据配置
|
||||
# =============================================================
|
||||
|
||||
class Meta:
|
||||
"""
|
||||
模型元数据配置类
|
||||
|
||||
定义模型在数据库中的表名、显示名称、默认排序规则等。
|
||||
"""
|
||||
|
||||
# 数据表名
|
||||
# 使用配置文件中的表前缀 + "{{ table_name }}",避免与其他应用表名冲突
|
||||
db_table = get_table_name('{{ table_name }}')
|
||||
|
||||
# 表注释(Django 3.2+ 支持)
|
||||
# 在数据库中生成 COMMENT 语句,便于数据库管理
|
||||
db_table_comment = "{{ module_comment }}表"
|
||||
|
||||
# 模型在admin后台显示的友好名称(单数)
|
||||
verbose_name = "{{ module_comment }}表"
|
||||
|
||||
# 模型在admin后台显示的友好名称(复数)
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
# 默认排序规则
|
||||
# 按照 {% if has_sort %}sort 字段升序排列(数值小的在前){% else %}创建时间倒序排列(最新的在前){% endif %},确保显示顺序可控
|
||||
ordering = ({% if has_sort %}"sort"{% else %}"-create_time"{% endif %},)
|
||||
|
||||
# =============================================================
|
||||
# 实例方法
|
||||
# =============================================================
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
模型的字符串表示方法
|
||||
|
||||
当需要将模型实例转换为字符串时调用,如admin后台显示、日志输出等。
|
||||
|
||||
Returns:
|
||||
str: 包含{{ module_comment }}标识信息的字符串
|
||||
"""
|
||||
return f"{{ module_comment }}{self.{{ display_field }}}"
|
||||
@@ -0,0 +1,524 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
{{ module_comment }}管理服务模块模板
|
||||
=============================================================
|
||||
|
||||
该模板用于生成{{ module_comment }}管理相关的所有业务逻辑。
|
||||
包括{{ module_comment }}的分页查询、详情查询、添加、更新、删除等功能。
|
||||
{{ business_description_detail }}
|
||||
|
||||
模板变量说明:
|
||||
- module_comment: 模块注释,如"文章管理"
|
||||
- app_name: 应用名称,如"article"
|
||||
- model_class_name: 模型类名,如"Article"
|
||||
- primary_key: 主键字段名,如"id"
|
||||
- filter_fields: 筛选字段列表
|
||||
- fields: 所有字段列表
|
||||
- form_fields: 表单字段列表
|
||||
- list_fields: 列表展示字段列表
|
||||
- has_status: 是否包含状态字段
|
||||
- has_sort: 是否包含排序字段
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
from django.core.paginator import Paginator, PageNotAnInteger, InvalidPage, EmptyPage
|
||||
|
||||
from application.{{ app_name }} import forms
|
||||
from application.{{ app_name }}.models import {{ model_class_name }}
|
||||
from config.env import DJANGO_FILE_URL
|
||||
from constant.constants import PAGE_SIZE
|
||||
from utils import R, regular
|
||||
from utils.common import get_file_url, format_datetime, parse_request_body, save_file, save_edit_content
|
||||
from utils.security import get_username
|
||||
|
||||
|
||||
# =============================================================
|
||||
# 分页查询服务
|
||||
# =============================================================
|
||||
|
||||
def get_{{ app_name }}_page(request):
|
||||
"""
|
||||
查询{{ module_comment }}分页数据
|
||||
|
||||
Args:
|
||||
request: HttpRequest对象,包含查询参数
|
||||
- pageNo: 当前页码(可选,默认为1)
|
||||
- pageSize: 每页记录数(可选,默认为PAGE_SIZE)
|
||||
{% for filter_field in filter_fields %}
|
||||
- {{ filter_field.name }}: {{ filter_field.comment }}(可选,{{ filter_field.filter_type }})
|
||||
{% endfor %}
|
||||
|
||||
Returns:
|
||||
R: 包含分页数据的JSON响应
|
||||
"""
|
||||
try:
|
||||
# 获取分页参数
|
||||
page_no = int(request.GET.get('pageNo', 1))
|
||||
page_size = int(request.GET.get('pageSize', PAGE_SIZE))
|
||||
|
||||
# 构建基础查询(只查询未删除的记录)
|
||||
query = {{ model_class_name }}.objects.filter(is_delete=False)
|
||||
|
||||
# 应用筛选条件
|
||||
query = _apply_filters(query, request)
|
||||
|
||||
# 按排序字段排列
|
||||
query = query.order_by({% if has_sort %}"sort"{% else %}"-create_time"{% endif %})
|
||||
|
||||
# 执行分页查询
|
||||
paginator = Paginator(query, page_size)
|
||||
try:
|
||||
page_list = paginator.page(page_no)
|
||||
except (PageNotAnInteger, InvalidPage, EmptyPage):
|
||||
# 页码无效时默认返回第一页
|
||||
page_list = paginator.page(1)
|
||||
page_no = 1
|
||||
|
||||
# 构建并返回分页数据
|
||||
page_data = _build_page_data(page_list, paginator, page_no, page_size)
|
||||
return R.ok(data=page_data)
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"查询{{ module_comment }}分页数据异常: {str(e)}")
|
||||
return R.failed(msg="查询失败,请稍后重试")
|
||||
|
||||
|
||||
def _apply_filters(queryset, request):
|
||||
"""
|
||||
应用查询筛选条件(私有辅助函数)
|
||||
|
||||
Args:
|
||||
queryset: 初始查询集
|
||||
request: HttpRequest对象,包含筛选参数
|
||||
|
||||
Returns:
|
||||
QuerySet: 应用筛选后的查询集
|
||||
"""
|
||||
{% for filter_field in filter_fields %}
|
||||
# {{ filter_field.comment }}筛选
|
||||
{{ filter_field.name }} = request.GET.get('{{ filter_field.name }}')
|
||||
if {{ filter_field.name }}:
|
||||
{% if filter_field.filter_type == '模糊查询' %}
|
||||
queryset = queryset.filter({{ filter_field.name }}__contains={{ filter_field.name }})
|
||||
{% else %}
|
||||
queryset = queryset.filter({{ filter_field.name }}={{ filter_field.name }})
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
return queryset
|
||||
|
||||
|
||||
def _build_page_data(page_list, paginator, page_no, page_size):
|
||||
"""
|
||||
构建分页返回数据(私有辅助函数)
|
||||
|
||||
Args:
|
||||
page_list: 当前页数据列表(Page对象)
|
||||
paginator: 分页器对象
|
||||
page_no: 当前页码
|
||||
page_size: 每页大小
|
||||
|
||||
Returns:
|
||||
dict: 标准格式的分页数据
|
||||
"""
|
||||
records = []
|
||||
for item in page_list:
|
||||
record = {
|
||||
'id': item.id,
|
||||
{% for field in list_fields %}
|
||||
'{{ field.camel_name }}': {% if field.is_image %}get_file_url(item.{{ field.name }}) if item.{{ field.name }} else ""{% else %}item.{{ field.name }}{% endif %},
|
||||
{% endfor %}
|
||||
'createUser': item.create_user,
|
||||
'createTime': format_datetime(item.create_time),
|
||||
'updateUser': item.update_user,
|
||||
'updateTime': format_datetime(item.update_time),
|
||||
}
|
||||
records.append(record)
|
||||
|
||||
return {
|
||||
'records': records,
|
||||
'total': paginator.count, # 总记录数
|
||||
'size': page_size, # 每页大小
|
||||
'current': page_no, # 当前页码
|
||||
'pages': paginator.num_pages # 总页数
|
||||
}
|
||||
|
||||
|
||||
# =============================================================
|
||||
# 列表查询服务(不分页)
|
||||
# =============================================================
|
||||
|
||||
def get_{{ app_name }}_list(request):
|
||||
"""
|
||||
获取{{ module_comment }}列表(不分页,支持筛选条件)
|
||||
|
||||
与分页查询的区别:返回所有符合条件的记录,不分页。
|
||||
通常用于导出数据或内部调用。
|
||||
|
||||
Args:
|
||||
request: HttpRequest对象,包含查询参数
|
||||
{% for filter_field in filter_fields %}
|
||||
- {{ filter_field.name }}: {{ filter_field.comment }}(可选,{{ filter_field.filter_type }})
|
||||
{% endfor %}
|
||||
|
||||
Returns:
|
||||
list: {{ module_comment }}列表,每个元素为{{ module_comment }}模型字典
|
||||
查询失败时返回空列表
|
||||
"""
|
||||
try:
|
||||
# 构建基础查询
|
||||
query = {{ model_class_name }}.objects.filter(is_delete=False)
|
||||
|
||||
# 应用筛选条件(复用 _apply_filters 方法)
|
||||
query = _apply_filters(query, request)
|
||||
|
||||
# 按排序字段排列
|
||||
query = query.order_by({% if has_sort %}"sort"{% else %}"-create_time"{% endif %})
|
||||
|
||||
# 构建返回数据
|
||||
records = []
|
||||
for item in query:
|
||||
record = {
|
||||
'id': item.id,
|
||||
{% for field in list_fields %}
|
||||
'{{ field.camel_name }}': {% if field.is_image %}get_file_url(item.{{ field.name }}) if item.{{ field.name }} else ""{% else %}item.{{ field.name }}{% endif %},
|
||||
{% endfor %}
|
||||
'createUser': item.create_user,
|
||||
'createTime': format_datetime(item.create_time),
|
||||
'updateUser': item.update_user,
|
||||
'updateTime': format_datetime(item.update_time),
|
||||
}
|
||||
records.append(record)
|
||||
|
||||
return records
|
||||
except Exception as e:
|
||||
logging.error(f"查询{{ module_comment }}列表异常: {str(e)}")
|
||||
return []
|
||||
|
||||
|
||||
# =============================================================
|
||||
# 详情查询服务
|
||||
# =============================================================
|
||||
|
||||
def get_{{ app_name }}_detail({{ primary_key }}):
|
||||
"""
|
||||
根据ID查询{{ module_comment }}详情
|
||||
|
||||
Args:
|
||||
{{ primary_key }}: {{ module_comment }}ID
|
||||
|
||||
Returns:
|
||||
dict/None: {{ module_comment }}详情字典,不存在时返回None
|
||||
"""
|
||||
try:
|
||||
# 查询未删除的{{ module_comment }}记录
|
||||
instance = {{ model_class_name }}.objects.filter(is_delete=False, id={{ primary_key }}).first()
|
||||
if not instance:
|
||||
return None
|
||||
|
||||
# 处理富文本字段
|
||||
{% for field in fields %}
|
||||
{% if field.is_rich_text %}
|
||||
{{ field.name }} = instance.{{ field.name }}
|
||||
if {{ field.name }}:
|
||||
{{ field.name }} = {{ field.name }}.replace("[IMG_URL]", DJANGO_FILE_URL)
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
# 返回详情数据
|
||||
return {
|
||||
'id': instance.id,
|
||||
{% for field in fields %}
|
||||
'{{ field.camel_name }}': {% if field.is_image %}get_file_url(instance.{{ field.name }}) if instance.{{ field.name }} else ""{% elif field.is_rich_text %}{{ field.name }}{% else %}instance.{{ field.name }}{% endif %},
|
||||
{% endfor %}
|
||||
}
|
||||
except Exception as e:
|
||||
logging.error(f"查询{{ module_comment }}详情异常,ID: { {{ primary_key }} }, 错误: {str(e)}")
|
||||
return None
|
||||
|
||||
|
||||
# =============================================================
|
||||
# 添加服务
|
||||
# =============================================================
|
||||
|
||||
def add_{{ app_name }}(request):
|
||||
"""
|
||||
添加{{ module_comment }}
|
||||
|
||||
处理流程:
|
||||
1. 解析请求体中的JSON数据
|
||||
2. 表单验证
|
||||
{% for field in form_fields %}{% if field.is_image %}3. 处理{{ field.comment }}(保存到 {{ app_name }} 目录){% endif %}{% endfor %}
|
||||
{% for field in form_fields %}{% if field.is_rich_text %}4. 处理{{ field.comment }}(保存富文本内容){% endif %}{% endfor %}
|
||||
5. 创建数据库记录
|
||||
|
||||
Args:
|
||||
request: HttpRequest对象,包含{{ module_comment }}信息的JSON数据
|
||||
|
||||
Returns:
|
||||
R: 操作结果(成功/失败)
|
||||
"""
|
||||
# 解析请求参数
|
||||
data, error = parse_request_body(request)
|
||||
if error:
|
||||
return R.failed(msg=error)
|
||||
|
||||
# 表单验证
|
||||
form = forms.{{ model_class_name }}Form(data)
|
||||
if not form.is_valid():
|
||||
return R.failed(msg=regular.get_err(form))
|
||||
|
||||
try:
|
||||
cleaned_data = form.cleaned_data
|
||||
|
||||
# 处理图片字段
|
||||
{% for field in form_fields %}
|
||||
{% if field.is_image %}
|
||||
{{ field.camel_name }} = cleaned_data.get('{{ field.camel_name }}')
|
||||
if {{ field.camel_name }}:
|
||||
{{ field.camel_name }} = save_file({{ field.camel_name }}, "{{ app_name }}")
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
# 处理富文本字段
|
||||
{% for field in form_fields %}
|
||||
{% if field.is_rich_text %}
|
||||
{{ field.camel_name }} = cleaned_data.get('{{ field.camel_name }}')
|
||||
if {{ field.camel_name }}:
|
||||
{{ field.camel_name }} = save_edit_content({{ field.camel_name }}, None, "{{ app_name }}")
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
# 创建{{ module_comment }}记录
|
||||
{{ model_class_name }}.objects.create(
|
||||
{% for field in form_fields %}
|
||||
{{ field.name }}={% if field.is_image %}{{ field.camel_name }}{% elif field.is_rich_text %}{{ field.camel_name }}{% else %}cleaned_data.get('{{ field.camel_name }}'){% endif %},
|
||||
{% endfor %}
|
||||
create_user=get_username(request),
|
||||
update_user=get_username(request)
|
||||
)
|
||||
return R.ok(msg="创建成功")
|
||||
except Exception as e:
|
||||
logging.error(f"添加{{ module_comment }}异常: {str(e)}")
|
||||
return R.failed(msg="添加失败,请稍后重试")
|
||||
|
||||
|
||||
# =============================================================
|
||||
# 更新服务
|
||||
# =============================================================
|
||||
|
||||
def update_{{ app_name }}(request):
|
||||
"""
|
||||
更新{{ module_comment }}
|
||||
|
||||
处理流程:
|
||||
1. 解析请求体中的JSON数据
|
||||
2. 验证{{ module_comment }}ID
|
||||
3. 表单验证
|
||||
4. 查询现有记录
|
||||
5. 处理图片字段(如有新图片则保存)
|
||||
6. 处理富文本字段
|
||||
7. 更新各字段
|
||||
8. 保存更新
|
||||
|
||||
Args:
|
||||
request: HttpRequest对象,包含{{ module_comment }}ID和更新信息的JSON数据
|
||||
|
||||
Returns:
|
||||
R: 操作结果(成功/失败)
|
||||
"""
|
||||
# 解析请求参数
|
||||
data, error = parse_request_body(request)
|
||||
if error:
|
||||
return R.failed(msg=error)
|
||||
|
||||
# 验证{{ module_comment }}ID
|
||||
instance_id = data.get('id')
|
||||
if not instance_id or not str(instance_id).isdigit() or int(instance_id) <= 0:
|
||||
return R.failed("{{ module_comment }}ID无效")
|
||||
instance_id = int(instance_id)
|
||||
|
||||
# 表单验证
|
||||
form = forms.{{ model_class_name }}Form(data)
|
||||
if not form.is_valid():
|
||||
return R.failed(msg=regular.get_err(form))
|
||||
|
||||
try:
|
||||
# 查询{{ module_comment }}记录
|
||||
instance = {{ model_class_name }}.objects.filter(id=instance_id, is_delete=False).first()
|
||||
if not instance:
|
||||
return R.failed("{{ module_comment }}不存在")
|
||||
|
||||
cleaned_data = form.cleaned_data
|
||||
|
||||
# 处理图片字段(仅当有新图片且与当前不同时保存)
|
||||
{% for field in form_fields %}
|
||||
{% if field.is_image %}
|
||||
{{ field.camel_name }} = cleaned_data.get('{{ field.camel_name }}')
|
||||
if {{ field.camel_name }} and {{ field.camel_name }} != instance.{{ field.name }}:
|
||||
{{ field.camel_name }} = save_file({{ field.camel_name }}, "{{ app_name }}")
|
||||
else:
|
||||
{{ field.camel_name }} = instance.{{ field.name }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
# 处理富文本字段
|
||||
{% for field in form_fields %}
|
||||
{% if field.is_rich_text %}
|
||||
{{ field.camel_name }} = cleaned_data.get('{{ field.camel_name }}')
|
||||
if {{ field.camel_name }}:
|
||||
{{ field.camel_name }} = save_edit_content({{ field.camel_name }}, None, "{{ app_name }}")
|
||||
else:
|
||||
{{ field.camel_name }} = instance.{{ field.name }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
# 更新各字段
|
||||
{% for field in form_fields %}
|
||||
{% if field.is_image %}
|
||||
instance.{{ field.name }} = {{ field.camel_name }}
|
||||
{% elif field.is_rich_text %}
|
||||
instance.{{ field.name }} = {{ field.camel_name }}
|
||||
{% else %}
|
||||
instance.{{ field.name }} = cleaned_data.get('{{ field.camel_name }}')
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
instance.update_user = get_username(request)
|
||||
instance.save()
|
||||
|
||||
return R.ok(msg="更新成功")
|
||||
except Exception as e:
|
||||
logging.error(f"更新{{ module_comment }}异常,ID: {instance_id}, 错误: {str(e)}")
|
||||
return R.failed(msg="更新失败,请稍后重试")
|
||||
|
||||
|
||||
# =============================================================
|
||||
# 删除服务(支持批量)
|
||||
# =============================================================
|
||||
|
||||
def delete_{{ app_name }}s(instance_ids):
|
||||
"""
|
||||
删除{{ module_comment }}(批量删除)
|
||||
|
||||
采用逻辑删除方式(is_delete=True),而非物理删除。
|
||||
支持逗号分隔的多个ID。
|
||||
|
||||
Args:
|
||||
instance_ids: {{ module_comment }}ID字符串,多个ID用逗号分隔
|
||||
例如: "1" 或 "1,2,3"
|
||||
|
||||
Returns:
|
||||
R: 操作结果,包含删除数量
|
||||
"""
|
||||
if not instance_ids:
|
||||
return R.failed("记录ID不存在")
|
||||
|
||||
try:
|
||||
# 解析ID列表
|
||||
id_list = [int(id_str.strip()) for id_str in instance_ids.split(',') if id_str.strip()]
|
||||
if not id_list:
|
||||
return R.failed("无效的记录ID")
|
||||
|
||||
# 批量更新删除标识(逻辑删除)
|
||||
updated_count = {{ model_class_name }}.objects.filter(
|
||||
id__in=id_list,
|
||||
is_delete=False
|
||||
).update(is_delete=True)
|
||||
|
||||
return R.ok(msg=f"本次共删除{updated_count}条数据")
|
||||
except ValueError:
|
||||
return R.failed("记录ID格式错误")
|
||||
except Exception as e:
|
||||
logging.error(f"删除{{ module_comment }}异常,IDs: {instance_ids}, 错误: {str(e)}")
|
||||
return R.failed(msg="删除失败,请稍后重试")
|
||||
|
||||
|
||||
{% if has_status %}
|
||||
# =============================================================
|
||||
# 状态更新服务
|
||||
# =============================================================
|
||||
|
||||
def update_{{ app_name }}_status(request):
|
||||
"""
|
||||
更新{{ module_comment }}状态
|
||||
|
||||
单独更新{{ module_comment }}的启用/禁用状态,不涉及其他字段。
|
||||
|
||||
Args:
|
||||
request: HttpRequest对象
|
||||
- id: {{ module_comment }}ID
|
||||
- status: 目标状态值(1=启用, 2=禁用)
|
||||
|
||||
Returns:
|
||||
R: 操作结果(成功/失败)
|
||||
"""
|
||||
# 解析请求参数
|
||||
data, error = parse_request_body(request)
|
||||
if error:
|
||||
return R.failed(msg=error)
|
||||
|
||||
# 验证{{ module_comment }}ID
|
||||
instance_id = data.get('id')
|
||||
if not instance_id or not str(instance_id).isdigit() or int(instance_id) <= 0:
|
||||
return R.failed("{{ module_comment }}ID无效")
|
||||
instance_id = int(instance_id)
|
||||
|
||||
# 验证状态值(1=启用, 2=禁用)
|
||||
status = data.get('status')
|
||||
if status is None:
|
||||
return R.failed("状态值不能为空")
|
||||
try:
|
||||
status = int(status)
|
||||
if status not in [1, 2]:
|
||||
return R.failed("状态值无效")
|
||||
except ValueError:
|
||||
return R.failed("状态值格式错误")
|
||||
|
||||
try:
|
||||
# 查询{{ module_comment }}记录
|
||||
instance = {{ model_class_name }}.objects.filter(id=instance_id, is_delete=False).first()
|
||||
if not instance:
|
||||
return R.failed("{{ module_comment }}不存在")
|
||||
|
||||
# 更新状态
|
||||
instance.status = status
|
||||
instance.update_user = get_username(request)
|
||||
instance.save()
|
||||
|
||||
return R.ok(msg="状态更新成功")
|
||||
except Exception as e:
|
||||
logging.error(f"更新{{ module_comment }}状态异常,ID: {instance_id}, 错误: {str(e)}")
|
||||
return R.failed(msg="状态更新失败,请稍后重试")
|
||||
{% endif %}
|
||||
|
||||
|
||||
# =============================================================
|
||||
# 数据下拉列表服务
|
||||
# =============================================================
|
||||
|
||||
def get_{{ app_name }}_data():
|
||||
"""
|
||||
获取所有启用的{{ module_comment }}列表
|
||||
|
||||
通常用于前端下拉选择框等场景。
|
||||
只返回 status=1(启用)且未删除的记录。
|
||||
|
||||
Returns:
|
||||
list: {{ module_comment }}列表,每个元素为{{ module_comment }}模型字典
|
||||
查询失败时返回空列表
|
||||
"""
|
||||
try:
|
||||
# 查询启用的{{ module_comment }}数据列表
|
||||
# status=1 表示启用,is_delete=False 表示未删除
|
||||
queryset = {{ model_class_name }}.objects.filter(
|
||||
is_delete=False,
|
||||
status=1
|
||||
).order_by({% if has_sort %}"sort"{% else %}"-create_time"{% endif %}).values()
|
||||
|
||||
return list(queryset)
|
||||
except Exception as e:
|
||||
logging.error(f"获取{{ module_comment }}列表异常: {str(e)}")
|
||||
return []
|
||||
@@ -0,0 +1,83 @@
|
||||
import { http } from '@/utils/http/axios';
|
||||
|
||||
/**
|
||||
* @description: {{ module_comment }}分页列表
|
||||
*/
|
||||
export function get{{ model_class_name }}Page(params?) {
|
||||
return http.request({
|
||||
url: '/{{ route_prefix }}/page',
|
||||
method: 'GET',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全部{{ module_comment }}列表
|
||||
* @param params 参数
|
||||
* @returns 返回结果
|
||||
*/
|
||||
export function get{{ model_class_name }}List(params?) {
|
||||
return http.request({
|
||||
url: '/{{ route_prefix }}/list',
|
||||
method: 'GET',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 根据ID获取{{ module_comment }}详情
|
||||
* @param {{ primary_key }} {{ module_comment }}ID
|
||||
*/
|
||||
export function get{{ model_class_name }}Detail({{ primary_key }}) {
|
||||
return http.request({
|
||||
url: '/{{ route_prefix }}/detail/' + {{ primary_key }},
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 添加{{ module_comment }}
|
||||
* @param data {{ module_comment }}数据
|
||||
*/
|
||||
export function {{ model_class_name_camel }}Add(data: any) {
|
||||
return http.request({
|
||||
url: '/{{ route_prefix }}/add',
|
||||
method: 'POST',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 更新{{ module_comment }}
|
||||
* @param data {{ module_comment }}数据
|
||||
*/
|
||||
export function {{ model_class_name_camel }}Update(data: any) {
|
||||
return http.request({
|
||||
url: '/{{ route_prefix }}/update',
|
||||
method: 'PUT',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 删除{{ module_comment }}
|
||||
* @param {{ primary_key }} {{ module_comment }}ID
|
||||
*/
|
||||
export function {{ model_class_name_camel }}Delete({{ primary_key }}) {
|
||||
return http.request({
|
||||
url: '/{{ route_prefix }}/delete/' + {{ primary_key }},
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 批量删除{{ module_comment }}
|
||||
* @param data {{ module_comment }}ID数组
|
||||
*/
|
||||
export function {{ model_class_name_camel }}BatchDelete(data: any) {
|
||||
return http.request({
|
||||
url: '/{{ route_prefix }}/batchDelete',
|
||||
method: 'DELETE',
|
||||
data,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
import { h } from 'vue';
|
||||
import { NTag, NAvatar, NImage } from 'naive-ui';
|
||||
|
||||
/**
|
||||
* 表格列配置
|
||||
* 定义表格显示的列
|
||||
*/
|
||||
export const columns = [
|
||||
{
|
||||
type: 'selection', // 多选框列
|
||||
width: 50,
|
||||
fixed: 'left',
|
||||
},
|
||||
{
|
||||
title: 'ID',
|
||||
key: 'id',
|
||||
fixed: 'left',
|
||||
width: 50,
|
||||
},
|
||||
{% for field in list_fields %}
|
||||
{
|
||||
title: '{{ field.label }}',
|
||||
key: '{{ field.camel_name }}',
|
||||
width: {% if field.type == 'CharField' %}150{% elif field.type == 'IntegerField' %}100{% elif field.type == 'DateTimeField' %}180{% else %}120{% endif %},
|
||||
{% if field.is_image %}
|
||||
// 图片渲染
|
||||
render(record) {
|
||||
return record.{{ field.camel_name }}
|
||||
? h(NAvatar, {
|
||||
src: record.{{ field.camel_name }},
|
||||
size: 48,
|
||||
shape: 'square',
|
||||
fit: 'cover',
|
||||
style: {
|
||||
borderRadius: '4px',
|
||||
},
|
||||
})
|
||||
: h('span', '-');
|
||||
},
|
||||
{% elif field.choices %}
|
||||
// 选项标签渲染
|
||||
render(record) {
|
||||
const statusMap = {
|
||||
{% for choice in field.choices %}
|
||||
{{ choice.value }}: { text: '{{ choice.label }}', type: {% if choice.value == 1 %}'success'{% elif choice.value == 2 %}'error'{% elif choice.value == 3 %}'warning'{% else %}'info'{% endif %} },
|
||||
{% endfor %}
|
||||
};
|
||||
const status = statusMap[record.{{ field.camel_name }}];
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
bordered: false,
|
||||
type: status?.type || 'info',
|
||||
},
|
||||
{
|
||||
default: () => status?.text || record.{{ field.camel_name }},
|
||||
},
|
||||
);
|
||||
},
|
||||
{% elif field.camel_name == 'status' %}
|
||||
// 状态标签渲染
|
||||
render(record) {
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
bordered: false,
|
||||
type: record.status == 1 ? 'success' : 'error',
|
||||
},
|
||||
{
|
||||
default: () => (record.status == 1 ? '正常' : '停用'),
|
||||
},
|
||||
);
|
||||
},
|
||||
{% elif field.type == 'CharField' and field.camel_name|lower in ['website', 'site', 'url', 'link'] %}
|
||||
// 链接渲染
|
||||
render(record) {
|
||||
const url = record.{{ field.camel_name }};
|
||||
return h(
|
||||
'a',
|
||||
{
|
||||
href: url,
|
||||
target: '_blank',
|
||||
rel: 'noopener noreferrer',
|
||||
},
|
||||
{
|
||||
default: () => url || '点击查看',
|
||||
},
|
||||
);
|
||||
},
|
||||
{% else %}
|
||||
// 普通文本渲染(无需额外配置)
|
||||
ellipsis: {
|
||||
tooltip: true,
|
||||
},
|
||||
{% endif %}
|
||||
},
|
||||
{% endfor %}
|
||||
{
|
||||
title: '创建人',
|
||||
key: 'createUser',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'createTime',
|
||||
width: 180,
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,216 @@
|
||||
<template>
|
||||
<basicModal
|
||||
@register="modalRegister"
|
||||
ref="modalRef"
|
||||
class="basicModal basicFormModal"
|
||||
>
|
||||
<template #default>
|
||||
<n-descriptions
|
||||
class="margin-top"
|
||||
:column="2"
|
||||
bordered
|
||||
:label-style="{ width: '120px' }"
|
||||
label-placement="left"
|
||||
>
|
||||
{% for field in form_fields %}
|
||||
<n-descriptions-item label="{{ field.label }}:">
|
||||
{% if field.is_image %}
|
||||
<n-image
|
||||
v-if="formData.{{ field.camel_name }}"
|
||||
:src="formData.{{ field.camel_name }}"
|
||||
width="80"
|
||||
height="80"
|
||||
fit="cover"
|
||||
:preview-disabled="false"
|
||||
/>
|
||||
<span v-else>-</span>
|
||||
{% elif field.is_rich_text %}
|
||||
<div class="rich-text-content" v-html="formData.{{ field.camel_name }}"></div>
|
||||
{% elif field.type == 'BooleanField' %}
|
||||
<n-tag :type="formData.{{ field.camel_name }} ? 'success' : 'error'" :bordered="false">
|
||||
{{ '{{ formData.' + field.camel_name + ' ? "是" : "否" }}' }}
|
||||
</n-tag>
|
||||
{% elif field.type == 'IntegerField' and field.choices %}
|
||||
<span>{{ '{{ getChoiceLabel(\'' + field.camel_name + '\', formData.' + field.camel_name + ') }}' }}</span>
|
||||
{% else %}
|
||||
<span>{{ '{{ formData.' + field.camel_name + ' || \'-\' }}' }}</span>
|
||||
{% endif %}
|
||||
</n-descriptions-item>
|
||||
{% endfor %}
|
||||
</n-descriptions>
|
||||
</template>
|
||||
<template #action>
|
||||
<n-button @click="dialogClose">关闭</n-button>
|
||||
</template>
|
||||
</basicModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { get{{ model_class_name }}Detail } from '@/api/{{ api_path }}';
|
||||
import { onMounted, reactive, watch } from 'vue';
|
||||
import { useModal } from '@/components/Modal';
|
||||
{% if has_image_field %}
|
||||
import { NImage } from 'naive-ui';
|
||||
{% endif %}
|
||||
|
||||
// 定义事件
|
||||
const emit = defineEmits(['update:visible']);
|
||||
|
||||
/**
|
||||
* 定义表单参数
|
||||
*/
|
||||
const formData = reactive({
|
||||
id: '',
|
||||
{% for field in form_fields %}
|
||||
{{ field.camel_name }}: {% if field.type == 'CharField' %}''{% elif field.type == 'IntegerField' %}0{% elif field.type == 'BooleanField' %}false{% elif field.type == 'FloatField' %}0{% else %}''{% endif %},
|
||||
{% endfor %}
|
||||
});
|
||||
|
||||
/**
|
||||
* 定义接收的参数
|
||||
*/
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
default: false,
|
||||
},
|
||||
{{ primary_key }}: {
|
||||
type: Number,
|
||||
required: true,
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* 定义模态框
|
||||
*/
|
||||
const [modalRegister, { openModal, closeModal }] = useModal({
|
||||
title: '{{ module_comment }}详情',
|
||||
width: 750,
|
||||
});
|
||||
|
||||
/**
|
||||
* 获取选项字段的标签
|
||||
*/
|
||||
const getChoiceLabel = (fieldName: string, value: any) => {
|
||||
const choiceMap: Record<string, Record<string, string>> = {
|
||||
{% for field in form_fields %}
|
||||
{% if field.type == 'IntegerField' and field.choices %}
|
||||
{{ field.camel_name }}: {
|
||||
{% for choice in field.choices %}
|
||||
{{ choice.value }}: '{{ choice.label }}',
|
||||
{% endfor %}
|
||||
},
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
};
|
||||
return choiceMap[fieldName]?.[value] || value || '-';
|
||||
};
|
||||
|
||||
/**
|
||||
* 关闭窗体
|
||||
*/
|
||||
const dialogClose = () => {
|
||||
closeModal();
|
||||
emit('update:visible', false);
|
||||
};
|
||||
|
||||
/**
|
||||
* 设置表单数据
|
||||
*/
|
||||
const setFormData = async () => {
|
||||
try {
|
||||
const data = await get{{ model_class_name }}Detail(props.{{ primary_key }});
|
||||
for (const key in formData) {
|
||||
if (data[key] != null && data[key] != undefined) {
|
||||
//@ts-ignore
|
||||
formData[key] = data[key];
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取{{ module_comment }}详情失败', error);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 重置表单数据
|
||||
*/
|
||||
const resetFormData = () => {
|
||||
for (const key in formData) {
|
||||
//@ts-ignore
|
||||
if (typeof formData[key] === 'string') {
|
||||
//@ts-ignore
|
||||
formData[key] = '';
|
||||
} else if (typeof formData[key] === 'number') {
|
||||
//@ts-ignore
|
||||
formData[key] = 0;
|
||||
} else if (typeof formData[key] === 'boolean') {
|
||||
//@ts-ignore
|
||||
formData[key] = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 监听visible变化,重新加载数据
|
||||
*/
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal && props.{{ primary_key }}) {
|
||||
setFormData();
|
||||
openModal();
|
||||
} else if (newVal && !props.{{ primary_key }}) {
|
||||
resetFormData();
|
||||
openModal();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* 钩子函数
|
||||
*/
|
||||
onMounted(() => {
|
||||
if (props.visible) {
|
||||
if (props.{{ primary_key }}) {
|
||||
setFormData();
|
||||
} else {
|
||||
resetFormData();
|
||||
}
|
||||
openModal();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 暴露openModal方法
|
||||
*/
|
||||
defineExpose({
|
||||
openModal,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.rich-text-content {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
border: 1px solid #e4e7ed;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
background-color: #f8f9fa;
|
||||
|
||||
:deep(img) {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.n-descriptions-table) {
|
||||
.n-descriptions-table-body {
|
||||
.n-descriptions-table-row {
|
||||
.n-descriptions-table-body-cell {
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,447 @@
|
||||
<template>
|
||||
<basicModal
|
||||
@register="modalRegister"
|
||||
ref="modalRef"
|
||||
class="basicModal basicFormModal"
|
||||
@on-ok="handleSubmit"
|
||||
@on-close="dialogClose"
|
||||
>
|
||||
<template #default>
|
||||
<n-form
|
||||
class="ls-form"
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
label-placement="left"
|
||||
label-width="80px"
|
||||
>
|
||||
{% for field in form_fields %}
|
||||
{% if field.is_image %}
|
||||
<!-- {{ field.comment }}(图片上传) -->
|
||||
<n-form-item
|
||||
label="{{ field.label }}"
|
||||
path="{{ field.camel_name }}"
|
||||
{% if field.required %}
|
||||
:rule="{ required: true, message: '请上传{{ field.comment }}', trigger: 'change' }"
|
||||
{% endif %}
|
||||
>
|
||||
<UploadImg
|
||||
@change-file-name="(name) => (formData.{{ field.camel_name }}ImgName = name)"
|
||||
:fileType="['image/jpeg', 'image/png', 'image/jpg', 'image/gif', 'image/webp']"
|
||||
name="{{ app_name }}"
|
||||
:fileSize="20"
|
||||
v-model:image-url="formData.{{ field.camel_name }}"
|
||||
>
|
||||
<template #tip>支持扩展名: jpg png jpeg gif webp; 文件大小不超过20M</template>
|
||||
</UploadImg>
|
||||
</n-form-item>
|
||||
{% elif field.is_rich_text %}
|
||||
<!-- {{ field.comment }}(富文本编辑器) -->
|
||||
<n-form-item
|
||||
label="{{ field.label }}"
|
||||
path="{{ field.camel_name }}"
|
||||
{% if field.required %}
|
||||
:rule="{ required: true, message: '请输入{{ field.comment }}', trigger: 'blur' }"
|
||||
{% endif %}
|
||||
>
|
||||
<div class="flex w-full">
|
||||
<Editor
|
||||
ref="{{ field.camel_name }}EditorRef"
|
||||
:height="editorHeight"
|
||||
class="flex-1"
|
||||
name="{{ app_name }}"
|
||||
/>
|
||||
</div>
|
||||
</n-form-item>
|
||||
{% elif field.type == 'CharField' and ('备注' in field.comment or '介绍' in field.comment or '描述' in field.comment or '说明' in field.comment) %}
|
||||
<!-- {{ field.comment }}(多行文本) -->
|
||||
<n-form-item
|
||||
label="{{ field.label }}"
|
||||
path="{{ field.camel_name }}"
|
||||
{% if field.required %}
|
||||
:rule="{ required: true, message: '请输入{{ field.comment }}', trigger: 'blur' }"
|
||||
{% endif %}
|
||||
>
|
||||
<n-input
|
||||
type="textarea"
|
||||
v-model:value="formData.{{ field.camel_name }}"
|
||||
placeholder="请输入{{ field.comment }}"
|
||||
:rows="3"
|
||||
clearable
|
||||
/>
|
||||
</n-form-item>
|
||||
{% elif field.type == 'CharField' %}
|
||||
<!-- {{ field.comment }} -->
|
||||
<n-form-item
|
||||
label="{{ field.label }}"
|
||||
path="{{ field.camel_name }}"
|
||||
{% if field.required %}
|
||||
:rule="{ required: true, message: '请输入{{ field.comment }}', trigger: 'blur' }"
|
||||
{% endif %}
|
||||
>
|
||||
<n-input
|
||||
class="ls-input"
|
||||
v-model:value="formData.{{ field.camel_name }}"
|
||||
placeholder="请输入{{ field.comment }}"
|
||||
clearable
|
||||
/>
|
||||
</n-form-item>
|
||||
{% elif field.type == 'IntegerField' and field.choices %}
|
||||
<!-- {{ field.comment }}({% if field.choices|length <= 2 %}单选{% else %}下拉选择{% endif %}) -->
|
||||
<n-form-item
|
||||
label="{{ field.label }}"
|
||||
path="{{ field.camel_name }}"
|
||||
{% if field.required %}
|
||||
:rule="{ type: 'number', required: true, message: '请选择{{ field.comment }}', trigger: 'change' }"
|
||||
{% endif %}
|
||||
>
|
||||
{% if field.choices|length <= 2 %}
|
||||
<n-radio-group v-model:value="formData.{{ field.camel_name }}">
|
||||
{% for choice in field.choices %}
|
||||
<n-radio :value="{{ choice.value }}">{{ choice.label }}</n-radio>
|
||||
{% endfor %}
|
||||
</n-radio-group>
|
||||
{% else %}
|
||||
<n-select
|
||||
v-model:value="formData.{{ field.camel_name }}"
|
||||
placeholder="请选择{{ field.comment }}"
|
||||
clearable
|
||||
filterable
|
||||
:options="optionsData.{{ field.camel_name }}List"
|
||||
/>
|
||||
{% endif %}
|
||||
</n-form-item>
|
||||
{% elif field.type == 'IntegerField' and not field.choices %}
|
||||
<!-- {{ field.comment }}(数字输入) -->
|
||||
<n-form-item
|
||||
label="{{ field.label }}"
|
||||
path="{{ field.camel_name }}"
|
||||
{% if field.required %}
|
||||
:rule="{ type: 'number', required: true, message: '请输入{{ field.comment }}', trigger: 'blur' }"
|
||||
{% endif %}
|
||||
>
|
||||
<n-input-number
|
||||
v-model:value="formData.{{ field.camel_name }}"
|
||||
:min="{{ field.min_value or 0 }}"
|
||||
:max="{{ field.max_value or 99999 }}"
|
||||
/>
|
||||
</n-form-item>
|
||||
{% elif field.type == 'BooleanField' %}
|
||||
<!-- {{ field.comment }}(开关) -->
|
||||
<n-form-item label="{{ field.label }}" path="{{ field.camel_name }}">
|
||||
<n-switch
|
||||
v-model:value="formData.{{ field.camel_name }}"
|
||||
:checked-value="1"
|
||||
:unchecked-value="0"
|
||||
/>
|
||||
</n-form-item>
|
||||
{% elif field.type == 'DateField' %}
|
||||
<!-- {{ field.comment }}(日期选择) -->
|
||||
<n-form-item
|
||||
label="{{ field.label }}"
|
||||
path="{{ field.camel_name }}"
|
||||
{% if field.required %}
|
||||
:rule="{ required: true, message: '请选择{{ field.comment }}', trigger: 'change' }"
|
||||
{% endif %}
|
||||
>
|
||||
<n-date-picker
|
||||
v-model:value="formData.{{ field.camel_name }}"
|
||||
type="date"
|
||||
placeholder="请选择{{ field.comment }}"
|
||||
format="yyyy-MM-dd"
|
||||
/>
|
||||
</n-form-item>
|
||||
{% elif field.type == 'DateTimeField' %}
|
||||
<!-- {{ field.comment }}(日期时间选择) -->
|
||||
<n-form-item
|
||||
label="{{ field.label }}"
|
||||
path="{{ field.camel_name }}"
|
||||
{% if field.required %}
|
||||
:rule="{ required: true, message: '请选择{{ field.comment }}', trigger: 'change' }"
|
||||
{% endif %}
|
||||
>
|
||||
<n-date-picker
|
||||
v-model:value="formData.{{ field.camel_name }}"
|
||||
type="datetime"
|
||||
placeholder="请选择{{ field.comment }}"
|
||||
format="yyyy-MM-dd HH:mm:ss"
|
||||
/>
|
||||
</n-form-item>
|
||||
{% elif field.type == 'TextField' %}
|
||||
<!-- {{ field.comment }}(文本域) -->
|
||||
<n-form-item
|
||||
label="{{ field.label }}"
|
||||
path="{{ field.camel_name }}"
|
||||
{% if field.required %}
|
||||
:rule="{ required: true, message: '请输入{{ field.comment }}', trigger: 'blur' }"
|
||||
{% endif %}
|
||||
>
|
||||
<n-input
|
||||
type="textarea"
|
||||
v-model:value="formData.{{ field.camel_name }}"
|
||||
placeholder="请输入{{ field.comment }}"
|
||||
:rows="3"
|
||||
/>
|
||||
</n-form-item>
|
||||
{% elif field.type == 'FloatField' or field.type == 'DecimalField' %}
|
||||
<!-- {{ field.comment }}(数字输入) -->
|
||||
<n-form-item
|
||||
label="{{ field.label }}"
|
||||
path="{{ field.camel_name }}"
|
||||
{% if field.required %}
|
||||
:rule="{ type: 'number', required: true, message: '请输入{{ field.comment }}', trigger: 'blur' }"
|
||||
{% endif %}
|
||||
>
|
||||
<n-input-number
|
||||
v-model:value="formData.{{ field.camel_name }}"
|
||||
:min="{{ field.min_value or 0 }}"
|
||||
:max="{{ field.max_value or 999999 }}"
|
||||
:precision="2"
|
||||
:step="0.1"
|
||||
/>
|
||||
</n-form-item>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</n-form>
|
||||
</template>
|
||||
</basicModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { get{{ model_class_name }}Detail, {{ model_class_name_camel }}Add, {{ model_class_name_camel }}Update } from '@/api/{{ api_path }}';
|
||||
import { onMounted, reactive, ref, watch } from 'vue';
|
||||
import { useMessage } from 'naive-ui';
|
||||
import { useModal } from '@/components/Modal';
|
||||
{% if has_image_field %}
|
||||
import UploadImg from '@/components/Upload/Image.vue';
|
||||
{% endif %}
|
||||
{% if has_rich_text_field %}
|
||||
import Editor from '@/components/Editor/tinymce.vue';
|
||||
{% endif %}
|
||||
|
||||
// 定义事件
|
||||
const emit = defineEmits(['success', 'update:visible']);
|
||||
|
||||
// 消息提示
|
||||
const message = useMessage();
|
||||
|
||||
// 表单引用
|
||||
const formRef = ref();
|
||||
|
||||
{% if has_rich_text_field %}
|
||||
// 富文本编辑器高度
|
||||
const editorHeight = document.body.clientHeight - 400;
|
||||
|
||||
// 富文本编辑器引用
|
||||
{% for field in form_fields %}
|
||||
{% if field.is_rich_text %}
|
||||
const {{ field.camel_name }}EditorRef = ref();
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
/**
|
||||
* 定义选项数据
|
||||
*/
|
||||
const optionsData = reactive({
|
||||
{% for field in form_fields %}
|
||||
{% if field.type == 'IntegerField' and field.choices and field.choices|length > 2 %}
|
||||
{{ field.camel_name }}List: [
|
||||
{% for choice in field.choices %}
|
||||
{
|
||||
label: '{{ choice.label }}',
|
||||
value: {% if choice.value_type == 'string' %}'{{ choice.value }}'{% else %}{{ choice.value }}{% endif %},
|
||||
},
|
||||
{% endfor %}
|
||||
],
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
});
|
||||
|
||||
/**
|
||||
* 定义表单数据
|
||||
* 初始化默认值
|
||||
*/
|
||||
const formData = reactive({
|
||||
id: '', // ID字段,新增时为0
|
||||
{% for field in form_fields %}
|
||||
{{ field.camel_name }}: {% if field.type == 'CharField' %}''{% elif field.type == 'IntegerField' %}{{ field.default or 0 }}{% elif field.type == 'BooleanField' %}{{ field.default or 0 }}{% elif field.type == 'FloatField' %}{{ field.default or 0 }}{% else %}''{% endif %},
|
||||
{% endfor %}
|
||||
{% for field in form_fields %}
|
||||
{% if field.is_image %}
|
||||
{{ field.camel_name }}ImgName: '', // {{ field.comment }}文件名
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
});
|
||||
|
||||
/**
|
||||
* 定义接收的参数
|
||||
*/
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
default: false,
|
||||
},
|
||||
{{ primary_key }}: {
|
||||
type: Number,
|
||||
required: true,
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* 定义模态框
|
||||
*/
|
||||
const [modalRegister, { openModal, setSubLoading, closeModal }] = useModal({
|
||||
title: props.{{ primary_key }} ? '编辑{{ module_comment }}' : '新增{{ module_comment }}',
|
||||
subBtuText: '确定',
|
||||
width: {% if has_rich_text_field %}850{% else %}500{% endif %},
|
||||
});
|
||||
|
||||
/**
|
||||
* 执行提交表单
|
||||
* 根据是否有ID判断是新增还是编辑
|
||||
*/
|
||||
const handleSubmit = async () => {
|
||||
// 获取富文本编辑器内容
|
||||
{% for field in form_fields %}
|
||||
{% if field.is_rich_text %}
|
||||
if ({{ field.camel_name }}EditorRef.value) {
|
||||
formData.{{ field.camel_name }} = {{ field.camel_name }}EditorRef.value.myValue;
|
||||
}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
formRef.value
|
||||
.validate()
|
||||
.then(async () => {
|
||||
try {
|
||||
props.{{ primary_key }}
|
||||
? await {{ model_class_name_camel }}Update(formData)
|
||||
: await {{ model_class_name_camel }}Add(formData);
|
||||
message.success('操作成功');
|
||||
setSubLoading(false);
|
||||
emit('update:visible', false);
|
||||
emit('success');
|
||||
} catch (error) {
|
||||
message.error('操作失败');
|
||||
setSubLoading(false);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
setSubLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 关闭窗体
|
||||
*/
|
||||
const dialogClose = () => {
|
||||
emit('update:visible', false);
|
||||
};
|
||||
|
||||
/**
|
||||
* 设置表单数据
|
||||
* 编辑时获取详情并填充表单
|
||||
*/
|
||||
const setFormData = async () => {
|
||||
try {
|
||||
const data = await get{{ model_class_name }}Detail(props.{{ primary_key }});
|
||||
for (const key in formData) {
|
||||
if (data[key] != null && data[key] != undefined) {
|
||||
// @ts-ignore
|
||||
formData[key] = data[key];
|
||||
}
|
||||
}
|
||||
// 设置富文本编辑器内容
|
||||
{% for field in form_fields %}
|
||||
{% if field.is_rich_text %}
|
||||
if ({{ field.camel_name }}EditorRef.value && formData.{{ field.camel_name }}) {
|
||||
{{ field.camel_name }}EditorRef.value.myValue = formData.{{ field.camel_name }};
|
||||
}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
} catch (error) {
|
||||
console.error('获取{{ module_comment }}详情失败', error);
|
||||
message.error('获取数据失败');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 重置表单
|
||||
*/
|
||||
const resetForm = () => {
|
||||
if (formRef.value) {
|
||||
formRef.value.restoreValidation();
|
||||
}
|
||||
// 重置表单数据
|
||||
for (const key in formData) {
|
||||
if (key === 'id') continue;
|
||||
// @ts-ignore
|
||||
if (typeof formData[key] === 'string') {
|
||||
// @ts-ignore
|
||||
formData[key] = '';
|
||||
} else if (typeof formData[key] === 'number') {
|
||||
// @ts-ignore
|
||||
formData[key] = 0;
|
||||
}
|
||||
}
|
||||
// 清空富文本编辑器内容
|
||||
{% for field in form_fields %}
|
||||
{% if field.is_rich_text %}
|
||||
if ({{ field.camel_name }}EditorRef.value) {
|
||||
{{ field.camel_name }}EditorRef.value.myValue = '';
|
||||
}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
/**
|
||||
* 监听visible变化,重新加载数据
|
||||
*/
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal && props.{{ primary_key }}) {
|
||||
setFormData();
|
||||
openModal();
|
||||
} else if (newVal && !props.{{ primary_key }}) {
|
||||
resetForm();
|
||||
openModal();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* 钩子函数
|
||||
*/
|
||||
onMounted(() => {
|
||||
if (props.visible) {
|
||||
if (props.{{ primary_key }}) {
|
||||
setFormData();
|
||||
} else {
|
||||
resetForm();
|
||||
}
|
||||
openModal();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 暴露openModal方法
|
||||
*/
|
||||
defineExpose({
|
||||
openModal,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
.flex-1 {
|
||||
flex: 1;
|
||||
}
|
||||
.w-full {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,322 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 搜索表单卡片 -->
|
||||
<n-card :bordered="false" class="pt-3 mb-3 proCard">
|
||||
<BasicForm @register="register" @submit="handleSubmit" @reset="handleReset" />
|
||||
</n-card>
|
||||
|
||||
<!-- 数据表格卡片 -->
|
||||
<n-card :bordered="false" class="proCard">
|
||||
<BasicTable
|
||||
:columns="columns"
|
||||
:request="loadDataTable"
|
||||
:row-key="(row) => row.id"
|
||||
ref="basicTableRef"
|
||||
:actionColumn="actionColumn"
|
||||
@update:checked-row-keys="onCheckedRow"
|
||||
:auto-scroll-x="true"
|
||||
>
|
||||
<!-- 表格顶部工具栏 -->
|
||||
<template #tableTitle>
|
||||
<n-space>
|
||||
<!-- 新增按钮 -->
|
||||
<n-button type="primary" @click="handleAdd" v-perm="['{{ permission_prefix }}:add']">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<PlusOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
添加{{ module_comment }}
|
||||
</n-button>
|
||||
|
||||
<!-- 批量删除按钮 -->
|
||||
<n-button
|
||||
type="error"
|
||||
@click="handleDelete()"
|
||||
:disabled="!rowKeys.length"
|
||||
v-perm="['{{ permission_prefix }}:batchDelete']"
|
||||
>
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<DeleteOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
批量删除
|
||||
</n-button>
|
||||
{% if has_export %}
|
||||
<!-- 导出按钮 -->
|
||||
<n-button
|
||||
type="success"
|
||||
@click="handleExport"
|
||||
v-perm="['{{ permission_prefix }}:export']"
|
||||
>
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<DownloadOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
导出
|
||||
</n-button>
|
||||
{% endif %}
|
||||
</n-space>
|
||||
</template>
|
||||
</BasicTable>
|
||||
</n-card>
|
||||
|
||||
<!-- 编辑对话框组件 -->
|
||||
<editDialog
|
||||
ref="editModalRef"
|
||||
v-if="editVisible"
|
||||
:{{ primary_key }}="currentId"
|
||||
v-model:visible="editVisible"
|
||||
@success="reloadTable('noRefresh')"
|
||||
/>
|
||||
<!-- 查看详情对话框组件 -->
|
||||
<detailDialog
|
||||
ref="detailModalRef"
|
||||
v-if="detailVisible"
|
||||
:{{ primary_key }}="currentId"
|
||||
v-model:visible="detailVisible"
|
||||
@success="reloadTable('noRefresh')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { h, nextTick, reactive, ref } from 'vue';
|
||||
import { useMessage, useDialog } from 'naive-ui';
|
||||
import { PlusOutlined, DeleteOutlined, EditOutlined, EyeOutlined } from '@vicons/antd';
|
||||
import { TableAction } from '@/components/Table';
|
||||
import { BasicForm, useForm } from '@/components/Form/index';
|
||||
import { get{{ model_class_name }}Page, {{ model_class_name_camel }}Delete, {{ model_class_name_camel }}BatchDelete } from '@/api/{{ api_path }}';
|
||||
import { renderIcon } from '@/utils';
|
||||
|
||||
import { columns } from './columns';
|
||||
import { schemas } from './querySchemas';
|
||||
|
||||
// 动态导入编辑对话框组件
|
||||
import editDialog from './edit.vue';
|
||||
// 动态导入详情对话框组件
|
||||
import detailDialog from './detail.vue';
|
||||
|
||||
// 消息提示和对话框
|
||||
const message = useMessage();
|
||||
const dialog = useDialog();
|
||||
|
||||
// 表格引用
|
||||
const basicTableRef = ref();
|
||||
const editModalRef = ref();
|
||||
const detailModalRef = ref();
|
||||
|
||||
// 响应式状态定义
|
||||
const currentId = ref(0); // 当前操作的ID
|
||||
const editVisible = ref(false); // 编辑对话框显示状态
|
||||
const detailVisible = ref(false); // 详情对话框显示状态
|
||||
const rowKeys = ref([]); // 表格选中行Key
|
||||
|
||||
/**
|
||||
* 定义查询参数
|
||||
* 用于存储搜索表单的值
|
||||
*/
|
||||
const formParams = reactive({
|
||||
{% for field in filter_fields %}
|
||||
{{ field.name }}: '',
|
||||
{% endfor %}
|
||||
});
|
||||
|
||||
/**
|
||||
* 定义操作栏配置
|
||||
* 包含编辑、详情和删除按钮
|
||||
*/
|
||||
const actionColumn = reactive({
|
||||
width: 280,
|
||||
title: '操作',
|
||||
align: 'center',
|
||||
key: 'action',
|
||||
fixed: 'right',
|
||||
render(record) {
|
||||
return h(TableAction as any, {
|
||||
style: 'button',
|
||||
actions: [
|
||||
{
|
||||
label: '编辑',
|
||||
icon: renderIcon(EditOutlined),
|
||||
type: 'info',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
auth: ['{{ permission_prefix }}:update'],
|
||||
},
|
||||
{
|
||||
label: '详情',
|
||||
icon: renderIcon(EyeOutlined),
|
||||
type: 'default',
|
||||
onClick: handleDetail.bind(null, record),
|
||||
auth: ['{{ permission_prefix }}:detail'],
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
icon: renderIcon(DeleteOutlined),
|
||||
type: 'error',
|
||||
onClick: handleDelete.bind(null, record),
|
||||
auth: ['{{ permission_prefix }}:delete'],
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* 加载数据列表
|
||||
* @param params 分页参数
|
||||
* @returns 表格数据
|
||||
*/
|
||||
const loadDataTable = async (params: any) => {
|
||||
// 清空选中行
|
||||
rowKeys.value = [];
|
||||
const result = await get{{ model_class_name }}Page({ ...formParams, ...params });
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* 刷新表格数据
|
||||
* @param noRefresh 是否重置页码
|
||||
*/
|
||||
function reloadTable(noRefresh = '') {
|
||||
basicTableRef.value.reload(noRefresh ? {} : { pageNo: 1 });
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册搜索表单
|
||||
* 配置表单布局和字段
|
||||
*/
|
||||
const [register, {}] = useForm({
|
||||
gridProps: { cols: '1 s:1 m:2 l:3 xl:4 2xl:4' },
|
||||
labelWidth: 80,
|
||||
schemas,
|
||||
});
|
||||
|
||||
/**
|
||||
* 提交搜索表单
|
||||
* @param values 表单值
|
||||
*/
|
||||
function handleSubmit(values: Recordable) {
|
||||
for (const key in formParams) {
|
||||
formParams[key] = '';
|
||||
}
|
||||
for (const key in values) {
|
||||
formParams[key] = values[key];
|
||||
}
|
||||
reloadTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置搜索表单
|
||||
*/
|
||||
function handleReset(values: Recordable) {
|
||||
for (const key in formParams) {
|
||||
formParams[key] = '';
|
||||
}
|
||||
for (const key in values) {
|
||||
formParams[key] = values[key];
|
||||
}
|
||||
reloadTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* 表格选择项变化时的回调
|
||||
* @param keys 选中的key数组
|
||||
*/
|
||||
function onCheckedRow(keys: (string | number)[]) {
|
||||
rowKeys.value = keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理新增按钮点击
|
||||
*/
|
||||
const handleAdd = async () => {
|
||||
currentId.value = 0;
|
||||
editVisible.value = true;
|
||||
await nextTick();
|
||||
editModalRef.value?.openModal();
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理编辑按钮点击
|
||||
* @param record 当前行数据
|
||||
*/
|
||||
const handleEdit = async (record: Recordable) => {
|
||||
currentId.value = record.id;
|
||||
editVisible.value = true;
|
||||
await nextTick();
|
||||
editModalRef.value?.openModal();
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理详情按钮点击
|
||||
* @param record 当前行数据
|
||||
*/
|
||||
const handleDetail = async (record: Recordable) => {
|
||||
currentId.value = record.id;
|
||||
detailVisible.value = true;
|
||||
await nextTick();
|
||||
detailModalRef.value?.openModal();
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理删除操作
|
||||
* @param record 当前行数据(可选,不传时表示批量删除)
|
||||
*/
|
||||
async function handleDelete(record?: Recordable) {
|
||||
let ids = [];
|
||||
if (!record) {
|
||||
// 批量删除:获取选中行的ID
|
||||
ids = rowKeys.value;
|
||||
if (!ids.length) {
|
||||
message.warning('请选择要删除的数据');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dialog.warning({
|
||||
title: '提示',
|
||||
content: '确定要删除选中的{{ module_comment }}吗?',
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: async () => {
|
||||
try {
|
||||
record
|
||||
? await {{ model_class_name_camel }}Delete(record.id)
|
||||
: await {{ model_class_name_camel }}BatchDelete(ids);
|
||||
message.success('删除成功');
|
||||
reloadTable();
|
||||
} catch (error) {
|
||||
message.error('删除失败');
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
{% if has_export %}
|
||||
/**
|
||||
* 处理导出操作
|
||||
*/
|
||||
async function handleExport() {
|
||||
dialog.warning({
|
||||
title: '提示',
|
||||
content: '确定要导出{{ module_comment }}数据吗?',
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: async () => {
|
||||
try {
|
||||
// TODO: 调用导出API
|
||||
message.success('导出成功');
|
||||
} catch (error) {
|
||||
message.error('导出失败');
|
||||
console.error('导出失败', error);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
{% endif %}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
@@ -0,0 +1,30 @@
|
||||
import { FormSchema } from '@/components/Form/index';
|
||||
|
||||
/**
|
||||
* 查询表单配置
|
||||
* 定义搜索区域的表单项
|
||||
*/
|
||||
export const schemas: FormSchema[] = [
|
||||
{% for field in filter_fields %}
|
||||
{
|
||||
field: '{{ field.name }}',
|
||||
component: '{% if field.type == 'CharField' %}NInput{% elif field.choices %}NSelect{% elif field.type == 'IntegerField' and not field.choices %}NInputNumber{% elif field.type == 'DateField' %}NDatePicker{% else %}NInput{% endif %}',
|
||||
label: '{{ field.label }}',
|
||||
componentProps: {
|
||||
placeholder: '请输入{{ field.label }}',
|
||||
clearable: true,
|
||||
filterable: {% if field.choices %}true{% else %}false{% endif %},
|
||||
{% if field.choices %}
|
||||
options: [
|
||||
{% for choice in field.choices %}
|
||||
{
|
||||
label: '{{ choice.label }}',
|
||||
value: {{ choice.value }},
|
||||
},
|
||||
{% endfor %}
|
||||
],
|
||||
{% endif %}
|
||||
},
|
||||
},
|
||||
{% endfor %}
|
||||
];
|
||||
@@ -0,0 +1,99 @@
|
||||
import { h } from 'vue';
|
||||
import { BasicColumn } from '@/components/Table';
|
||||
import { NTag, NSwitch, NImage } from 'naive-ui';
|
||||
import { renderIcon } from '@/utils';
|
||||
|
||||
{% for field in fields %}
|
||||
{% if field.choices %}
|
||||
/**
|
||||
* {{ field.label }} 选项映射
|
||||
*/
|
||||
const {{ field.name }}Map: Record<number, { text: string; type: string }> = {
|
||||
{% for choice in field.choices %}
|
||||
{{ choice.value }}: { text: '{{ choice.label }}', type: '{% if loop.index0 == 0 %}success{% elif loop.index0 == 1 %}error{% elif loop.index0 == 2 %}warning{% else %}info{% endif %}' },
|
||||
{% endfor %}
|
||||
};
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
export const columns: BasicColumn[] = [
|
||||
{% for field in list_fields %}
|
||||
{
|
||||
title: '{{ field.label }}',
|
||||
key: '{{ field.camel_name }}',
|
||||
width: {% if field.name == 'name' %}250{% elif field.name == 'sort' %}100{% elif field.type == 'DateTimeField' %}180{% else %}150{% endif %},
|
||||
align: 'left',
|
||||
{% if field.is_image %}
|
||||
// 图片渲染
|
||||
render(record) {
|
||||
return record.{{ field.camel_name }}
|
||||
? h(NImage, {
|
||||
src: record.{{ field.camel_name }},
|
||||
width: 40,
|
||||
height: 40,
|
||||
fit: 'cover',
|
||||
style: {
|
||||
borderRadius: '4px',
|
||||
},
|
||||
previewDisabled: false,
|
||||
})
|
||||
: h('span', '-');
|
||||
},
|
||||
{% elif field.choices %}
|
||||
// 选项标签渲染
|
||||
render(record) {
|
||||
const status = {{ field.name }}Map[record.{{ field.camel_name }}];
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
bordered: false,
|
||||
type: status?.type || 'info',
|
||||
},
|
||||
{
|
||||
default: () => status?.text || record.{{ field.camel_name }},
|
||||
},
|
||||
);
|
||||
},
|
||||
{% elif field.name == 'status' %}
|
||||
// 状态开关渲染
|
||||
render(record) {
|
||||
return h(NSwitch, {
|
||||
value: record.status == 1,
|
||||
onUpdateValue: (val: boolean) => {
|
||||
// 状态变更事件由父组件处理
|
||||
record.status = val ? 1 : 0;
|
||||
},
|
||||
});
|
||||
},
|
||||
{% elif field.type == 'CharField' and field.camel_name|lower in ['website', 'site', 'url', 'link'] %}
|
||||
// 链接渲染
|
||||
render(record) {
|
||||
const url = record.{{ field.camel_name }};
|
||||
return h(
|
||||
'a',
|
||||
{
|
||||
href: url,
|
||||
target: '_blank',
|
||||
rel: 'noopener noreferrer',
|
||||
},
|
||||
{
|
||||
default: () => url || '点击查看',
|
||||
},
|
||||
);
|
||||
},
|
||||
{% else %}
|
||||
// 普通文本渲染
|
||||
{% endif %}
|
||||
},
|
||||
{% endfor %}
|
||||
{
|
||||
title: '创建人',
|
||||
key: 'createUser',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'createTime',
|
||||
width: 180,
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,216 @@
|
||||
<template>
|
||||
<basicModal
|
||||
@register="modalRegister"
|
||||
ref="modalRef"
|
||||
class="basicModal basicFormModal"
|
||||
>
|
||||
<template #default>
|
||||
<n-descriptions
|
||||
class="margin-top"
|
||||
:column="2"
|
||||
bordered
|
||||
:label-style="{ width: '120px' }"
|
||||
label-placement="left"
|
||||
>
|
||||
{% for field in form_fields %}
|
||||
<n-descriptions-item label="{{ field.label }}:">
|
||||
{% if field.is_image %}
|
||||
<n-image
|
||||
v-if="formData.{{ field.camel_name }}"
|
||||
:src="formData.{{ field.camel_name }}"
|
||||
width="80"
|
||||
height="80"
|
||||
fit="cover"
|
||||
:preview-disabled="false"
|
||||
/>
|
||||
<span v-else>-</span>
|
||||
{% elif field.is_rich_text %}
|
||||
<div class="rich-text-content" v-html="formData.{{ field.camel_name }}"></div>
|
||||
{% elif field.type == 'BooleanField' %}
|
||||
<n-tag :type="formData.{{ field.camel_name }} ? 'success' : 'error'" :bordered="false">
|
||||
{{ '{{ formData.' + field.camel_name + ' ? "是" : "否" }}' }}
|
||||
</n-tag>
|
||||
{% elif field.type == 'IntegerField' and field.choices %}
|
||||
<span>{{ '{{ getChoiceLabel(\'' + field.camel_name + '\', formData.' + field.camel_name + ') }}' }}</span>
|
||||
{% else %}
|
||||
<span>{{ '{{ formData.' + field.camel_name + ' || \'-\' }}' }}</span>
|
||||
{% endif %}
|
||||
</n-descriptions-item>
|
||||
{% endfor %}
|
||||
</n-descriptions>
|
||||
</template>
|
||||
<template #action>
|
||||
<n-button @click="dialogClose">关闭</n-button>
|
||||
</template>
|
||||
</basicModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { get{{ model_class_name }}Detail } from '@/api/{{ api_path }}';
|
||||
import { onMounted, reactive, watch } from 'vue';
|
||||
import { useModal } from '@/components/Modal';
|
||||
{% if has_image_field %}
|
||||
import { NImage } from 'naive-ui';
|
||||
{% endif %}
|
||||
|
||||
// 定义事件
|
||||
const emit = defineEmits(['update:visible']);
|
||||
|
||||
/**
|
||||
* 定义表单参数
|
||||
*/
|
||||
const formData = reactive({
|
||||
id: '',
|
||||
{% for field in form_fields %}
|
||||
{{ field.camel_name }}: {% if field.type == 'CharField' %}''{% elif field.type == 'IntegerField' %}0{% elif field.type == 'BooleanField' %}false{% elif field.type == 'FloatField' %}0{% else %}''{% endif %},
|
||||
{% endfor %}
|
||||
});
|
||||
|
||||
/**
|
||||
* 定义接收的参数
|
||||
*/
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
default: false,
|
||||
},
|
||||
{{ primary_key }}: {
|
||||
type: Number,
|
||||
required: true,
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* 定义模态框
|
||||
*/
|
||||
const [modalRegister, { openModal, closeModal }] = useModal({
|
||||
title: '{{ module_comment }}详情',
|
||||
width: 750,
|
||||
});
|
||||
|
||||
/**
|
||||
* 获取选项字段的标签
|
||||
*/
|
||||
const getChoiceLabel = (fieldName: string, value: any) => {
|
||||
const choiceMap: Record<string, Record<string, string>> = {
|
||||
{% for field in form_fields %}
|
||||
{% if field.type == 'IntegerField' and field.choices %}
|
||||
{{ field.camel_name }}: {
|
||||
{% for choice in field.choices %}
|
||||
{{ choice.value }}: '{{ choice.label }}',
|
||||
{% endfor %}
|
||||
},
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
};
|
||||
return choiceMap[fieldName]?.[value] || value || '-';
|
||||
};
|
||||
|
||||
/**
|
||||
* 关闭窗体
|
||||
*/
|
||||
const dialogClose = () => {
|
||||
closeModal();
|
||||
emit('update:visible', false);
|
||||
};
|
||||
|
||||
/**
|
||||
* 设置表单数据
|
||||
*/
|
||||
const setFormData = async () => {
|
||||
try {
|
||||
const data = await get{{ model_class_name }}Detail(props.{{ primary_key }});
|
||||
for (const key in formData) {
|
||||
if (data[key] != null && data[key] != undefined) {
|
||||
//@ts-ignore
|
||||
formData[key] = data[key];
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取{{ module_comment }}详情失败', error);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 重置表单数据
|
||||
*/
|
||||
const resetFormData = () => {
|
||||
for (const key in formData) {
|
||||
//@ts-ignore
|
||||
if (typeof formData[key] === 'string') {
|
||||
//@ts-ignore
|
||||
formData[key] = '';
|
||||
} else if (typeof formData[key] === 'number') {
|
||||
//@ts-ignore
|
||||
formData[key] = 0;
|
||||
} else if (typeof formData[key] === 'boolean') {
|
||||
//@ts-ignore
|
||||
formData[key] = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 监听visible变化,重新加载数据
|
||||
*/
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal && props.{{ primary_key }}) {
|
||||
setFormData();
|
||||
openModal();
|
||||
} else if (newVal && !props.{{ primary_key }}) {
|
||||
resetFormData();
|
||||
openModal();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* 钩子函数
|
||||
*/
|
||||
onMounted(() => {
|
||||
if (props.visible) {
|
||||
if (props.{{ primary_key }}) {
|
||||
setFormData();
|
||||
} else {
|
||||
resetFormData();
|
||||
}
|
||||
openModal();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 暴露openModal方法
|
||||
*/
|
||||
defineExpose({
|
||||
openModal,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.rich-text-content {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
border: 1px solid #e4e7ed;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
background-color: #f8f9fa;
|
||||
|
||||
:deep(img) {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.n-descriptions-table) {
|
||||
.n-descriptions-table-body {
|
||||
.n-descriptions-table-row {
|
||||
.n-descriptions-table-body-cell {
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,436 @@
|
||||
<template>
|
||||
<basicModal
|
||||
@register="modalRegister"
|
||||
ref="modalRef"
|
||||
class="basicModal basicFormModal"
|
||||
@on-ok="handleSubmit"
|
||||
@on-close="dialogClose"
|
||||
>
|
||||
<template #default>
|
||||
<n-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
label-placement="left"
|
||||
label-width="80px"
|
||||
>
|
||||
{% for field in form_fields %}
|
||||
{% if field.camel_name == parent_id_field %}
|
||||
<!-- {{ field.comment }}(树形选择器) -->
|
||||
<n-form-item
|
||||
label="{{ field.label }}"
|
||||
path="{{ field.camel_name }}"
|
||||
{% if field.required %}
|
||||
:rule="{ type: 'number', required: true, message: '请选择{{ field.comment }}', trigger: 'change' }"
|
||||
{% endif %}
|
||||
>
|
||||
<n-tree-select
|
||||
class="flex-1"
|
||||
v-model:value="formData.{{ field.camel_name }}"
|
||||
:options="treeOptions"
|
||||
label-field="{{ display_field_camel }}"
|
||||
key-field="{{ primary_key }}"
|
||||
default-expand-all
|
||||
placeholder="请选择{{ field.comment }}"
|
||||
clearable
|
||||
/>
|
||||
</n-form-item>
|
||||
{% elif field.is_image %}
|
||||
<!-- {{ field.comment }}(图片上传) -->
|
||||
<n-form-item
|
||||
label="{{ field.label }}"
|
||||
path="{{ field.camel_name }}"
|
||||
{% if field.required %}
|
||||
:rule="{ required: true, message: '请上传{{ field.comment }}', trigger: 'change' }"
|
||||
{% endif %}
|
||||
>
|
||||
<UploadImg
|
||||
@change-file-name="(name) => (formData.{{ field.camel_name }}ImgName = name)"
|
||||
:fileType="['image/jpeg', 'image/png', 'image/jpg', 'image/gif', 'image/webp']"
|
||||
name="{{ app_name }}"
|
||||
:fileSize="20"
|
||||
v-model:image-url="formData.{{ field.camel_name }}"
|
||||
>
|
||||
<template #tip>支持扩展名: jpg png jpeg gif webp; 文件大小不超过20M</template>
|
||||
</UploadImg>
|
||||
</n-form-item>
|
||||
{% elif field.type == 'CharField' and ('备注' in field.comment or '介绍' in field.comment or '描述' in field.comment or '说明' in field.comment) %}
|
||||
<!-- {{ field.comment }}(多行文本) -->
|
||||
<n-form-item
|
||||
label="{{ field.label }}"
|
||||
path="{{ field.camel_name }}"
|
||||
{% if field.required %}
|
||||
:rule="{ required: true, message: '请输入{{ field.comment }}', trigger: 'blur' }"
|
||||
{% endif %}
|
||||
>
|
||||
<n-input
|
||||
type="textarea"
|
||||
v-model:value="formData.{{ field.camel_name }}"
|
||||
placeholder="请输入{{ field.comment }}"
|
||||
:rows="3"
|
||||
clearable
|
||||
/>
|
||||
</n-form-item>
|
||||
{% elif field.type == 'CharField' %}
|
||||
<!-- {{ field.comment }} -->
|
||||
<n-form-item
|
||||
label="{{ field.label }}"
|
||||
path="{{ field.camel_name }}"
|
||||
{% if field.required %}
|
||||
:rule="{ required: true, message: '请输入{{ field.comment }}', trigger: 'blur' }"
|
||||
{% endif %}
|
||||
>
|
||||
<n-input
|
||||
class="ls-input"
|
||||
v-model:value="formData.{{ field.camel_name }}"
|
||||
placeholder="请输入{{ field.comment }}"
|
||||
clearable
|
||||
/>
|
||||
</n-form-item>
|
||||
{% elif field.type == 'IntegerField' and field.choices %}
|
||||
<!-- {{ field.comment }}({% if field.choices|length <= 2 %}单选{% else %}下拉选择{% endif %}) -->
|
||||
<n-form-item
|
||||
label="{{ field.label }}"
|
||||
path="{{ field.camel_name }}"
|
||||
{% if field.required %}
|
||||
:rule="{ type: 'number', required: true, message: '请选择{{ field.comment }}', trigger: 'change' }"
|
||||
{% endif %}
|
||||
>
|
||||
{% if field.choices|length <= 2 %}
|
||||
<n-radio-group v-model:value="formData.{{ field.camel_name }}">
|
||||
{% for choice in field.choices %}
|
||||
<n-radio :value="{{ choice.value }}">{{ choice.label }}</n-radio>
|
||||
{% endfor %}
|
||||
</n-radio-group>
|
||||
{% else %}
|
||||
<n-select
|
||||
v-model:value="formData.{{ field.camel_name }}"
|
||||
placeholder="请选择{{ field.comment }}"
|
||||
clearable
|
||||
filterable
|
||||
:options="optionsData.{{ field.camel_name }}List"
|
||||
/>
|
||||
{% endif %}
|
||||
</n-form-item>
|
||||
{% elif field.type == 'IntegerField' and not field.choices %}
|
||||
<!-- {{ field.comment }}(数字输入) -->
|
||||
<n-form-item
|
||||
label="{{ field.label }}"
|
||||
path="{{ field.camel_name }}"
|
||||
{% if field.required %}
|
||||
:rule="{ type: 'number', required: true, message: '请输入{{ field.comment }}', trigger: 'blur' }"
|
||||
{% endif %}
|
||||
>
|
||||
<n-input-number
|
||||
v-model:value="formData.{{ field.camel_name }}"
|
||||
:min="{{ field.min_value or 0 }}"
|
||||
:max="{{ field.max_value or 99999 }}"
|
||||
/>
|
||||
</n-form-item>
|
||||
{% elif field.type == 'BooleanField' %}
|
||||
<!-- {{ field.comment }}(开关) -->
|
||||
<n-form-item label="{{ field.label }}" path="{{ field.camel_name }}">
|
||||
<n-switch
|
||||
v-model:value="formData.{{ field.camel_name }}"
|
||||
:checked-value="1"
|
||||
:unchecked-value="0"
|
||||
/>
|
||||
</n-form-item>
|
||||
{% elif field.type == 'DateField' %}
|
||||
<!-- {{ field.comment }}(日期选择) -->
|
||||
<n-form-item
|
||||
label="{{ field.label }}"
|
||||
path="{{ field.camel_name }}"
|
||||
{% if field.required %}
|
||||
:rule="{ required: true, message: '请选择{{ field.comment }}', trigger: 'change' }"
|
||||
{% endif %}
|
||||
>
|
||||
<n-date-picker
|
||||
v-model:value="formData.{{ field.camel_name }}"
|
||||
type="date"
|
||||
placeholder="请选择{{ field.comment }}"
|
||||
format="yyyy-MM-dd"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</n-form-item>
|
||||
{% elif field.type == 'DateTimeField' %}
|
||||
<!-- {{ field.comment }}(日期时间选择) -->
|
||||
<n-form-item
|
||||
label="{{ field.label }}"
|
||||
path="{{ field.camel_name }}"
|
||||
{% if field.required %}
|
||||
:rule="{ required: true, message: '请选择{{ field.comment }}', trigger: 'change' }"
|
||||
{% endif %}
|
||||
>
|
||||
<n-date-picker
|
||||
v-model:value="formData.{{ field.camel_name }}"
|
||||
type="datetime"
|
||||
placeholder="请选择{{ field.comment }}"
|
||||
format="yyyy-MM-dd HH:mm:ss"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</n-form-item>
|
||||
{% elif field.type == 'TextField' %}
|
||||
<!-- {{ field.comment }}(文本域) -->
|
||||
<n-form-item
|
||||
label="{{ field.label }}"
|
||||
path="{{ field.camel_name }}"
|
||||
{% if field.required %}
|
||||
:rule="{ required: true, message: '请输入{{ field.comment }}', trigger: 'blur' }"
|
||||
{% endif %}
|
||||
>
|
||||
<n-input
|
||||
type="textarea"
|
||||
v-model:value="formData.{{ field.camel_name }}"
|
||||
placeholder="请输入{{ field.comment }}"
|
||||
:rows="3"
|
||||
/>
|
||||
</n-form-item>
|
||||
{% elif field.type == 'FloatField' or field.type == 'DecimalField' %}
|
||||
<!-- {{ field.comment }}(数字输入) -->
|
||||
<n-form-item
|
||||
label="{{ field.label }}"
|
||||
path="{{ field.camel_name }}"
|
||||
{% if field.required %}
|
||||
:rule="{ type: 'number', required: true, message: '请输入{{ field.comment }}', trigger: 'blur' }"
|
||||
{% endif %}
|
||||
>
|
||||
<n-input-number
|
||||
v-model:value="formData.{{ field.camel_name }}"
|
||||
:min="{{ field.min_value or 0 }}"
|
||||
:max="{{ field.max_value or 999999 }}"
|
||||
:precision="2"
|
||||
:step="0.1"
|
||||
/>
|
||||
</n-form-item>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</n-form>
|
||||
</template>
|
||||
</basicModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { get{{ model_class_name }}List, get{{ model_class_name }}Detail, {{ model_class_name_camel }}Add, {{ model_class_name_camel }}Update } from '@/api/{{ api_path }}';
|
||||
import { onMounted, reactive, ref, watch } from 'vue';
|
||||
import { useMessage } from 'naive-ui';
|
||||
import { useModal } from '@/components/Modal';
|
||||
import { buildTree } from '@/utils/auth';
|
||||
{% if has_image_field %}
|
||||
import UploadImg from '@/components/Upload/Image.vue';
|
||||
{% endif %}
|
||||
|
||||
// 定义事件
|
||||
const emit = defineEmits(['success', 'update:visible']);
|
||||
|
||||
// 消息提示
|
||||
const message = useMessage();
|
||||
|
||||
// 表单引用
|
||||
const formRef = ref();
|
||||
|
||||
// 树形选项数据
|
||||
const treeOptions = ref<any[]>([]);
|
||||
|
||||
/**
|
||||
* 定义选项数据
|
||||
*/
|
||||
const optionsData = reactive({
|
||||
{% for field in form_fields %}
|
||||
{% if field.type == 'IntegerField' and field.choices and field.choices|length > 2 %}
|
||||
{{ field.camel_name }}List: [
|
||||
{% for choice in field.choices %}
|
||||
{
|
||||
label: '{{ choice.label }}',
|
||||
value: {% if choice.value_type == 'string' %}'{{ choice.value }}'{% else %}{{ choice.value }}{% endif %},
|
||||
},
|
||||
{% endfor %}
|
||||
],
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
});
|
||||
|
||||
/**
|
||||
* 定义表单数据
|
||||
* 初始化默认值
|
||||
*/
|
||||
const formData = reactive({
|
||||
id: '', // ID字段,新增时为0
|
||||
{% for field in form_fields %}
|
||||
{{ field.camel_name }}: {% if field.type == 'CharField' %}''{% elif field.type == 'IntegerField' %}{{ field.default or 0 }}{% elif field.type == 'BooleanField' %}{{ field.default or 0 }}{% elif field.type == 'FloatField' %}{{ field.default or 0 }}{% else %}''{% endif %},
|
||||
{% endfor %}
|
||||
{% for field in form_fields %}
|
||||
{% if field.is_image %}
|
||||
{{ field.camel_name }}ImgName: '', // {{ field.comment }}文件名
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
});
|
||||
|
||||
/**
|
||||
* 定义接收的参数
|
||||
*/
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
default: false,
|
||||
},
|
||||
{{ primary_key }}: {
|
||||
type: Number,
|
||||
required: true,
|
||||
default: 0,
|
||||
},
|
||||
// 新增时传入的父级ID(驼峰格式)
|
||||
parentId: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* 定义模态框
|
||||
*/
|
||||
const [modalRegister, { openModal, setSubLoading, closeModal }] = useModal({
|
||||
title: props.{{ primary_key }} ? '编辑{{ module_comment }}' : '新增{{ module_comment }}',
|
||||
subBtuText: '确定',
|
||||
width: 500,
|
||||
});
|
||||
|
||||
/**
|
||||
* 获取树形数据
|
||||
*/
|
||||
const get{{ model_class_name }}Tree = async () => {
|
||||
const data = await get{{ model_class_name }}List();
|
||||
// 构建顶级节点
|
||||
const tree: any = [{ id: 0, {{ display_field_camel }}: '顶级', children: [] }];
|
||||
const lists = buildTree(data);
|
||||
tree[0].children.push(...lists);
|
||||
treeOptions.value = tree;
|
||||
};
|
||||
|
||||
/**
|
||||
* 执行提交表单
|
||||
* 根据是否有ID判断是新增还是编辑
|
||||
*/
|
||||
const handleSubmit = async () => {
|
||||
formRef.value
|
||||
.validate()
|
||||
.then(async () => {
|
||||
try {
|
||||
props.{{ primary_key }}
|
||||
? await {{ model_class_name_camel }}Update(formData)
|
||||
: await {{ model_class_name_camel }}Add(formData);
|
||||
message.success('操作成功');
|
||||
setSubLoading(false);
|
||||
emit('update:visible', false);
|
||||
emit('success');
|
||||
} catch (error) {
|
||||
message.error('操作失败');
|
||||
setSubLoading(false);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
setSubLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 关闭窗体
|
||||
*/
|
||||
const dialogClose = () => {
|
||||
closeModal();
|
||||
emit('update:visible', false);
|
||||
};
|
||||
|
||||
/**
|
||||
* 设置表单数据
|
||||
* 编辑时获取详情并填充表单
|
||||
*/
|
||||
const setFormData = async () => {
|
||||
try {
|
||||
const data = await get{{ model_class_name }}Detail(props.{{ primary_key }});
|
||||
for (const key in formData) {
|
||||
if (data[key] != null && data[key] != undefined) {
|
||||
// @ts-ignore
|
||||
formData[key] = data[key];
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取{{ module_comment }}详情失败', error);
|
||||
message.error('获取数据失败');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 重置表单
|
||||
*/
|
||||
const resetForm = () => {
|
||||
if (formRef.value) {
|
||||
formRef.value.restoreValidation();
|
||||
}
|
||||
// 重置表单数据
|
||||
for (const key in formData) {
|
||||
if (key === 'id') continue;
|
||||
// @ts-ignore
|
||||
if (typeof formData[key] === 'string') {
|
||||
// @ts-ignore
|
||||
formData[key] = '';
|
||||
} else if (typeof formData[key] === 'number') {
|
||||
// @ts-ignore
|
||||
formData[key] = 0;
|
||||
}
|
||||
}
|
||||
// 设置父级ID默认值(使用驼峰格式)
|
||||
formData.{{ parent_id_field }} = props.parentId || 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* 监听visible变化,重新加载数据
|
||||
*/
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal && props.{{ primary_key }}) {
|
||||
setFormData();
|
||||
openModal();
|
||||
} else if (newVal && !props.{{ primary_key }}) {
|
||||
resetForm();
|
||||
get{{ model_class_name }}Tree();
|
||||
openModal();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* 钩子函数
|
||||
*/
|
||||
onMounted(() => {
|
||||
get{{ model_class_name }}Tree();
|
||||
if (props.visible) {
|
||||
if (props.{{ primary_key }}) {
|
||||
setFormData();
|
||||
} else {
|
||||
resetForm();
|
||||
}
|
||||
openModal();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 暴露openModal方法
|
||||
*/
|
||||
defineExpose({
|
||||
openModal,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.flex-1 {
|
||||
flex: 1;
|
||||
}
|
||||
.form-tips {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
line-height: 1.5;
|
||||
margin-top: 4px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,238 @@
|
||||
<template>
|
||||
<div class="{{ app_name }}-index">
|
||||
<n-card :bordered="false" class="pt-3 mb-3 proCard">
|
||||
<n-spin :show="loading">
|
||||
<BasicTable
|
||||
ref="tableRef"
|
||||
:columns="columns"
|
||||
:request="loadDataTable"
|
||||
:row-key="(row) => row.id"
|
||||
:auto-scroll-x="true"
|
||||
:action-column="actionColumn"
|
||||
v-model:expanded-row-keys="expandKeys"
|
||||
>
|
||||
<template #tableTitle>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="handleAdd()" v-perm="['{{ permission_prefix }}:add']">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<PlusOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
新增{{ module_comment }}
|
||||
</n-button>
|
||||
<n-button @click="handleExpand">展开/折叠</n-button>
|
||||
</n-space>
|
||||
</template>
|
||||
</BasicTable>
|
||||
</n-spin>
|
||||
</n-card>
|
||||
|
||||
<!-- 编辑对话框组件 -->
|
||||
<editDialog
|
||||
ref="editModalRef"
|
||||
v-if="editVisible"
|
||||
:{{ primary_key }}="{{ primary_key }}Value"
|
||||
:parent-id="parentId"
|
||||
v-model:visible="editVisible"
|
||||
@success="reloadTable"
|
||||
/>
|
||||
<!-- 查看详情对话框组件 -->
|
||||
<detailDialog
|
||||
ref="detailModalRef"
|
||||
v-if="detailVisible"
|
||||
:{{ primary_key }}="{{ primary_key }}Value"
|
||||
v-model:visible="detailVisible"
|
||||
@success="reloadTable"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup name="{{ model_class_name }}Index">
|
||||
import { defineAsyncComponent, nextTick, onMounted, ref, reactive, h } from 'vue';
|
||||
import { PlusOutlined, EditOutlined, DeleteOutlined, EyeOutlined } from '@vicons/antd';
|
||||
import { TableAction } from '@/components/Table';
|
||||
import { renderIcon } from '@/utils';
|
||||
import { get{{ model_class_name }}List, {{ model_class_name_camel }}Delete } from '@/api/{{ api_path }}';
|
||||
import { useMessage, useDialog } from 'naive-ui';
|
||||
import { columns } from './columns';
|
||||
import { buildTree } from '@/utils/auth';
|
||||
import { getTreeValues } from '@/utils/helper/treeHelper';
|
||||
|
||||
// 动态导入编辑对话框组件
|
||||
const editDialog = defineAsyncComponent(() => import('./edit.vue'));
|
||||
// 动态导入详情对话框组件
|
||||
const detailDialog = defineAsyncComponent(() => import('./detail.vue'));
|
||||
|
||||
// 消息提示和对话框
|
||||
const message = useMessage();
|
||||
const dialog = useDialog();
|
||||
|
||||
// 表格引用
|
||||
const tableRef = ref();
|
||||
const editModalRef = ref();
|
||||
const detailModalRef = ref();
|
||||
|
||||
// 响应式状态
|
||||
const loading = ref(false);
|
||||
const editVisible = ref(false);
|
||||
const detailVisible = ref(false);
|
||||
const {{ primary_key }}Value = ref(0);
|
||||
const parentId = ref(0);
|
||||
const expandKeys = ref<(string | number)[]>([]);
|
||||
|
||||
/**
|
||||
* 定义操作栏配置
|
||||
* 包含新增、编辑、详情和删除按钮
|
||||
*/
|
||||
const actionColumn = reactive({
|
||||
width: 280,
|
||||
title: '操作',
|
||||
align: 'center',
|
||||
key: 'action',
|
||||
fixed: 'right',
|
||||
render(record) {
|
||||
return h(TableAction as any, {
|
||||
style: 'button',
|
||||
actions: [
|
||||
{
|
||||
label: '新增',
|
||||
icon: renderIcon(PlusOutlined),
|
||||
type: 'primary',
|
||||
onClick: handleAdd.bind(null, record),
|
||||
auth: ['{{ permission_prefix }}:add'],
|
||||
},
|
||||
{
|
||||
label: '编辑',
|
||||
icon: renderIcon(EditOutlined),
|
||||
type: 'warning',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
auth: ['{{ permission_prefix }}:update'],
|
||||
},
|
||||
{
|
||||
label: '详情',
|
||||
icon: renderIcon(EyeOutlined),
|
||||
type: 'info',
|
||||
onClick: handleDetail.bind(null, record),
|
||||
auth: ['{{ permission_prefix }}:detail'],
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
icon: renderIcon(DeleteOutlined),
|
||||
type: 'error',
|
||||
onClick: handleDelete.bind(null, record),
|
||||
auth: ['{{ permission_prefix }}:delete'],
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* 加载数据列表
|
||||
*/
|
||||
const loadDataTable = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const data = await get{{ model_class_name }}List();
|
||||
const treeData = buildTree(data);
|
||||
const result = {
|
||||
records: treeData,
|
||||
total: 1,
|
||||
};
|
||||
loading.value = false;
|
||||
return result;
|
||||
} catch (error) {
|
||||
loading.value = false;
|
||||
return { records: [], total: 0 };
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 刷新表格数据
|
||||
*/
|
||||
const reloadTable = () => {
|
||||
tableRef.value?.reload();
|
||||
};
|
||||
|
||||
/**
|
||||
* 执行添加
|
||||
* @param record 当前行数据(用于获取父级ID)
|
||||
*/
|
||||
const handleAdd = async (record?: any) => {
|
||||
{{ primary_key }}Value.value = 0;
|
||||
parentId.value = record ? record.id : 0;
|
||||
editVisible.value = true;
|
||||
await nextTick();
|
||||
editModalRef.value?.openModal();
|
||||
};
|
||||
|
||||
/**
|
||||
* 执行编辑
|
||||
* @param record 当前行数据
|
||||
*/
|
||||
const handleEdit = async (record: any) => {
|
||||
{{ primary_key }}Value.value = record.id;
|
||||
editVisible.value = true;
|
||||
await nextTick();
|
||||
editModalRef.value?.openModal();
|
||||
};
|
||||
|
||||
/**
|
||||
* 执行查看详情
|
||||
* @param record 当前行数据
|
||||
*/
|
||||
const handleDetail = async (record: any) => {
|
||||
{{ primary_key }}Value.value = record.id;
|
||||
detailVisible.value = true;
|
||||
await nextTick();
|
||||
detailModalRef.value?.openModal();
|
||||
};
|
||||
|
||||
/**
|
||||
* 执行删除
|
||||
* @param record 当前行数据
|
||||
*/
|
||||
const handleDelete = (record: any) => {
|
||||
dialog.warning({
|
||||
title: '提示',
|
||||
content: '确定要删除选中的{{ module_comment }}吗?',
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
await {{ model_class_name_camel }}Delete(record.id);
|
||||
message.success('删除成功');
|
||||
reloadTable();
|
||||
} catch (error) {
|
||||
message.error('删除失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 执行展开/折叠
|
||||
*/
|
||||
const handleExpand = () => {
|
||||
loading.value = true;
|
||||
if (!expandKeys.value.length) {
|
||||
expandKeys.value = getTreeValues(tableRef.value?.getDataSource() || [], 'id');
|
||||
} else {
|
||||
expandKeys.value = [];
|
||||
}
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
onMounted(() => {
|
||||
loadDataTable();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,135 @@
|
||||
# +======================================================================
|
||||
# | DjangoAdmin 企业数字化开发平台 [ 赋能开发者,助力企业发展 ]
|
||||
# +----------------------------------------------------------------------
|
||||
# | Copyright (c) 2021-2026 小蚂蚁云团队 版权所有
|
||||
# +----------------------------------------------------------------------
|
||||
# | 开源协议: Apache-2.0
|
||||
# | 重要声明: 未经书面许可,不得移除或修改本框架相关版权标识。
|
||||
# +----------------------------------------------------------------------
|
||||
# | 官方网站: https://www.djangoadmin.cn
|
||||
# +----------------------------------------------------------------------
|
||||
# | 研发团队: 小蚂蚁云团队 荣誉出品
|
||||
# +======================================================================
|
||||
# | 版权和免责声明:
|
||||
# | 一、知识产权声明
|
||||
# | 本团队对该软件框架产品(以下简称“本产品”)拥有完整知识产权,包括但不限于商标权、专利权、
|
||||
# | 著作权、商业秘密等。前述权利均受中华人民共和国及相关国际法律法规保护。未经本团队书面授权,
|
||||
# | 任何个人或单位不得基于本产品本身申请任何形式的知识产权。
|
||||
# | 二、使用限制与禁止条款
|
||||
# | 您理解并同意,禁止将本产品用于以下任何行为:
|
||||
# | 1. 任何违反中华人民共和国法律法规的用途;
|
||||
# | 2. 任何侵害他人合法权益(包括但不限于人身权、财产权、知识产权等)的行为;
|
||||
# | 3. 任何危害国家安全、公共利益及社会道德风尚的行为。
|
||||
# | 三、责任豁免
|
||||
# | 因使用本产品而产生的任何损失或法律纠纷(包括但不限于直接损失、间接损失、附带损失、衍生损失
|
||||
# | 以及因违约、侵权等引发的责任),本团队均不承担任何法律责任。若因违规使用本产品导致任何第三
|
||||
# | 方提起索赔或行政机关进行调查,您应独立承担全部责任。
|
||||
# | 四、违约与法律责任
|
||||
# | 如发现任何违反本声明的行为,本团队有权:
|
||||
# | 1. 无条件配合公安机关及其他有权机关的调查取证工作;
|
||||
# | 2. 依法追究相关方的民事责任,并要求赔偿全部损失;
|
||||
# | 3. 保留进一步采取刑事控告等法律措施的权利。
|
||||
# | 五、许可范围说明
|
||||
# | 1、被授权方应视本产品源代码为核心机密信息,负有最高标准的保密与保管义务。禁止以任何形式(包
|
||||
# | 括但不限于直接或间接的分享、复制、传播、分发、转售、出租、开源、反向工程、反编译、反汇编或通
|
||||
# | 过网络服务提供给任何第三方)泄露、披露或处置源代码的全部或部分内容。任何未经授权的复制、使用、
|
||||
# | 传播行为均构成对本团队知识产权的严重侵权,本团队有权依法追究其全部法律责任,并要求赔偿因此造
|
||||
# | 成的一切经济损失及商誉损害。
|
||||
# | 2、本产品仅限于公司或个人在法律允许范围内,用于内部且合规的软件产品研发。具体权利义务以《软件
|
||||
# | 许可协议》附件为准。
|
||||
# +======================================================================
|
||||
|
||||
from django.urls import path
|
||||
from application.{{ app_name }} import views
|
||||
|
||||
"""
|
||||
{{ module_comment }}模块路由配置
|
||||
=============================================================
|
||||
|
||||
URL端点概览:
|
||||
------------------------------------------------------------------------
|
||||
| 功能说明 | 请求方法 | URL路径 | 视图类 |
|
||||
|-----------------|----------|-----------------------------|-------------------------|
|
||||
| 分页查询 | GET | /{{ route_prefix }}/page | {{ model_class_name }}PageView |
|
||||
| 列表查询 | GET | /{{ route_prefix }}/list | {{ model_class_name }}ListView |
|
||||
| 详情查询 | GET | /{{ route_prefix }}/detail/<id> | {{ model_class_name }}DetailView |
|
||||
| 添加{{ module_comment }} | POST | /{{ route_prefix }}/add | {{ model_class_name }}AddView |
|
||||
| 更新{{ module_comment }} | PUT | /{{ route_prefix }}/update | {{ model_class_name }}UpdateView |
|
||||
| 删除{{ module_comment }} | DELETE | /{{ route_prefix }}/delete/<ids>| {{ model_class_name }}DeleteView |
|
||||
{% if has_status %}
|
||||
| 设置状态 | PUT | /{{ route_prefix }}/status | {{ model_class_name }}StatusView |
|
||||
{% endif %}
|
||||
| 获取列表 | GET | /{{ route_prefix }}/data | {{ model_class_name }}DataView |
|
||||
------------------------------------------------------------------------
|
||||
|
||||
URL参数说明:
|
||||
- {{ primary_key }}: int类型,{{ module_comment }}ID(用于查询详情)
|
||||
- {{ primary_key }}: str类型,逗号分隔的{{ module_comment }}ID字符串(用于批量删除)
|
||||
|
||||
使用示例:
|
||||
1. 分页查询:GET /api/{{ route_prefix }}/page?pageNo=1&pageSize=10
|
||||
2. 列表查询:GET /api/{{ route_prefix }}/list
|
||||
3. 详情查询:GET /api/{{ route_prefix }}/detail/5
|
||||
4. 添加{{ module_comment }}:POST /api/{{ route_prefix }}/add
|
||||
5. 更新{{ module_comment }}:PUT /api/{{ route_prefix }}/update
|
||||
6. 删除{{ module_comment }}:DELETE /api/{{ route_prefix }}/delete/1,2,3
|
||||
{% if has_status %}
|
||||
7. 设置状态:PUT /api/{{ route_prefix }}/status
|
||||
{% endif %}
|
||||
8. 获取列表:GET /api/{{ route_prefix }}/data
|
||||
"""
|
||||
|
||||
# {{ module_comment }}模块路由配置
|
||||
urlpatterns = [
|
||||
# 查询{{ module_comment }}分页列表
|
||||
# URL: /{{ route_prefix }}/page
|
||||
# 请求方法: GET
|
||||
# 功能: 获取{{ module_comment }}分页数据,支持按{% for filter_field in filter_fields %}{{ filter_field.comment }}{% if not loop.last %}、{% endif %}{% endfor %}等条件筛选
|
||||
path('page', views.{{ model_class_name }}PageView.as_view()),
|
||||
|
||||
# 查询{{ module_comment }}数据列表(支持筛选)
|
||||
# URL: /{{ route_prefix }}/list
|
||||
# 请求方法: GET
|
||||
# 功能: 获取所有{{ module_comment }}的列表数据,支持按条件筛选,用于下拉选择等前端组件
|
||||
path('list', views.{{ model_class_name }}ListView.as_view()),
|
||||
|
||||
# 查询{{ module_comment }}详情
|
||||
# URL: /{{ route_prefix }}/detail/<int:{{ primary_key }}>
|
||||
# 请求方法: GET
|
||||
# URL参数: {{ primary_key }} - {{ module_comment }}ID(整数类型)
|
||||
# 功能: 根据ID获取指定{{ module_comment }}的详细信息
|
||||
path('detail/<int:{{ primary_key }}>', views.{{ model_class_name }}DetailView.as_view()),
|
||||
|
||||
# 添加{{ module_comment }}
|
||||
# URL: /{{ route_prefix }}/add
|
||||
# 请求方法: POST
|
||||
# 功能: 创建新的{{ module_comment }}记录,请求体需包含{{ module_comment }}信息({% for field in form_fields %}{{ field.name }}{% if not loop.last %}、{% endif %}{% endfor %}等)
|
||||
path('add', views.{{ model_class_name }}AddView.as_view()),
|
||||
|
||||
# 更新{{ module_comment }}
|
||||
# URL: /{{ route_prefix }}/update
|
||||
# 请求方法: PUT
|
||||
# 功能: 更新现有{{ module_comment }}信息,请求体需包含{{ module_comment }}ID和更新内容
|
||||
path('update', views.{{ model_class_name }}UpdateView.as_view()),
|
||||
|
||||
# 删除{{ module_comment }}
|
||||
# URL: /{{ route_prefix }}/delete/<str:{{ primary_key }}>
|
||||
# 请求方法: DELETE
|
||||
# URL参数: {{ primary_key }} - {{ module_comment }}ID字符串,支持单个ID或逗号分隔的多个ID(如 "1,2,3")
|
||||
# 功能: 删除指定{{ module_comment }}(逻辑删除,设置is_delete=True)
|
||||
path('delete/<str:{{ primary_key }}>', views.{{ model_class_name }}DeleteView.as_view()),
|
||||
|
||||
{% if has_status %}
|
||||
# 设置{{ module_comment }}状态
|
||||
# URL: /{{ route_prefix }}/status
|
||||
# 请求方法: PUT
|
||||
# 功能: 更新{{ module_comment }}的启用/禁用状态
|
||||
path('status', views.{{ model_class_name }}StatusView.as_view()),
|
||||
{% endif %}
|
||||
|
||||
# 查询{{ module_comment }}数据列表
|
||||
# URL: /{{ route_prefix }}/list
|
||||
# 请求方法: GET
|
||||
# 功能: 获取所有启用{{ module_comment }}的列表数据,用于下拉选择等前端组件
|
||||
path('data', views.{{ model_class_name }}DataView.as_view()),
|
||||
]
|
||||
@@ -0,0 +1,384 @@
|
||||
# +======================================================================
|
||||
# | DjangoAdmin 企业数字化开发平台 [ 赋能开发者,助力企业发展 ]
|
||||
# +----------------------------------------------------------------------
|
||||
# | Copyright (c) 2021-2026 小蚂蚁云团队 版权所有
|
||||
# +----------------------------------------------------------------------
|
||||
# | 开源协议: Apache-2.0
|
||||
# | 重要声明: 未经书面许可,不得移除或修改本框架相关版权标识。
|
||||
# +----------------------------------------------------------------------
|
||||
# | 官方网站: https://www.djangoadmin.cn
|
||||
# +----------------------------------------------------------------------
|
||||
# | 研发团队: 小蚂蚁云团队 荣誉出品
|
||||
# +======================================================================
|
||||
# | 版权和免责声明:
|
||||
# | 一、知识产权声明
|
||||
# | 本团队对该软件框架产品(以下简称“本产品”)拥有完整知识产权,包括但不限于商标权、专利权、
|
||||
# | 著作权、商业秘密等。前述权利均受中华人民共和国及相关国际法律法规保护。未经本团队书面授权,
|
||||
# | 任何个人或单位不得基于本产品本身申请任何形式的知识产权。
|
||||
# | 二、使用限制与禁止条款
|
||||
# | 您理解并同意,禁止将本产品用于以下任何行为:
|
||||
# | 1. 任何违反中华人民共和国法律法规的用途;
|
||||
# | 2. 任何侵害他人合法权益(包括但不限于人身权、财产权、知识产权等)的行为;
|
||||
# | 3. 任何危害国家安全、公共利益及社会道德风尚的行为。
|
||||
# | 三、责任豁免
|
||||
# | 因使用本产品而产生的任何损失或法律纠纷(包括但不限于直接损失、间接损失、附带损失、衍生损失
|
||||
# | 以及因违约、侵权等引发的责任),本团队均不承担任何法律责任。若因违规使用本产品导致任何第三
|
||||
# | 方提起索赔或行政机关进行调查,您应独立承担全部责任。
|
||||
# | 四、违约与法律责任
|
||||
# | 如发现任何违反本声明的行为,本团队有权:
|
||||
# | 1. 无条件配合公安机关及其他有权机关的调查取证工作;
|
||||
# | 2. 依法追究相关方的民事责任,并要求赔偿全部损失;
|
||||
# | 3. 保留进一步采取刑事控告等法律措施的权利。
|
||||
# | 五、许可范围说明
|
||||
# | 1、被授权方应视本产品源代码为核心机密信息,负有最高标准的保密与保管义务。禁止以任何形式(包
|
||||
# | 括但不限于直接或间接的分享、复制、传播、分发、转售、出租、开源、反向工程、反编译、反汇编或通
|
||||
# | 过网络服务提供给任何第三方)泄露、披露或处置源代码的全部或部分内容。任何未经授权的复制、使用、
|
||||
# | 传播行为均构成对本团队知识产权的严重侵权,本团队有权依法追究其全部法律责任,并要求赔偿因此造
|
||||
# | 成的一切经济损失及商誉损害。
|
||||
# | 2、本产品仅限于公司或个人在法律允许范围内,用于内部且合规的软件产品研发。具体权利义务以《软件
|
||||
# | 许可协议》附件为准。
|
||||
# +======================================================================
|
||||
|
||||
"""
|
||||
{{ module_comment }}视图模块模板
|
||||
=============================================================
|
||||
|
||||
该模板用于生成{{ module_comment }}管理功能中使用的所有视图类。
|
||||
用于处理{{ module_comment }}信息的HTTP请求,包括分页查询、详情查询、添加、更新、删除、获取列表等操作。
|
||||
{{ module_comment }}用于{{ business_description }}。
|
||||
每个视图类对应一个特定的API端点,处理相应的业务逻辑。
|
||||
|
||||
模板变量说明:
|
||||
- module_comment: 模块注释,如"文章管理"
|
||||
- app_name: 应用名称,如"article"
|
||||
- model_class_name: 模型类名,如"Article"
|
||||
- permission_prefix: 权限前缀,如"sys:article"
|
||||
- route_prefix: 路由前缀,如"article"
|
||||
- primary_key: 主键字段名,如"id"
|
||||
- filter_fields: 筛选字段列表
|
||||
- has_status: 是否包含状态字段
|
||||
- business_description: 业务描述
|
||||
- filter_fields_comment: 筛选字段注释
|
||||
"""
|
||||
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views import View
|
||||
|
||||
from application.{{ app_name }} import services
|
||||
from config.env import DJANGO_DEMO
|
||||
from middleware.login_middleware import check_login
|
||||
from middleware.permission_middleware import PermissionRequired
|
||||
from utils import R
|
||||
from application.operation_log.constants import LogType
|
||||
from application.operation_log.decorators import operation_log
|
||||
|
||||
|
||||
# =============================================================
|
||||
# 分页查询视图
|
||||
# =============================================================
|
||||
|
||||
@method_decorator(check_login, name="get")
|
||||
class {{ model_class_name }}PageView(PermissionRequired, View):
|
||||
"""
|
||||
{{ module_comment }}分页数据查询视图
|
||||
|
||||
处理GET请求,返回{{ module_comment }}列表的分页数据。
|
||||
支持按{{ filter_fields_comment }}等条件筛选。
|
||||
|
||||
URL: /{{ route_prefix }}/page
|
||||
请求方法: GET
|
||||
权限要求:{{ permission_prefix }}:page
|
||||
"""
|
||||
|
||||
# 方法权限标识
|
||||
permission_required = ("{{ permission_prefix }}:page",)
|
||||
|
||||
@operation_log(
|
||||
title="{{ module_comment }}管理-查询分页列表",
|
||||
log_type=LogType.QUERY
|
||||
)
|
||||
def get(self, request):
|
||||
"""
|
||||
处理GET请求,返回{{ module_comment }}分页数据
|
||||
|
||||
Args:
|
||||
request: HttpRequest对象,包含分页参数和筛选条件
|
||||
- pageNo: 当前页码
|
||||
- pageSize: 每页记录数
|
||||
{% for filter_field in filter_fields %}
|
||||
- {{ filter_field.name }}: {{ filter_field.comment }}(可选,{{ filter_field.filter_type }})
|
||||
{% endfor %}
|
||||
|
||||
Returns:
|
||||
JsonResponse: 包含分页数据的JSON响应
|
||||
"""
|
||||
result = services.get_{{ app_name }}_page(request)
|
||||
return result
|
||||
|
||||
|
||||
# =============================================================
|
||||
# 列表查询视图(不分页)
|
||||
# =============================================================
|
||||
|
||||
@method_decorator(check_login, name='get')
|
||||
class {{ model_class_name }}ListView(View):
|
||||
"""
|
||||
{{ module_comment }}列表获取视图(支持筛选,不分页)
|
||||
|
||||
处理GET请求,返回所有{{ module_comment }}的列表数据。
|
||||
支持按{% for filter_field in filter_fields %}{{ filter_field.comment }}{% if not loop.last %}、{% endif %}{% endfor %}等条件筛选。
|
||||
|
||||
URL: /{{ route_prefix }}/list
|
||||
请求方法: GET
|
||||
权限要求:需要登录
|
||||
"""
|
||||
|
||||
def get(self, request):
|
||||
"""
|
||||
处理GET请求,返回{{ module_comment }}列表
|
||||
|
||||
Args:
|
||||
request: HttpRequest对象
|
||||
|
||||
Returns:
|
||||
JsonResponse: 包含{{ module_comment }}列表的JSON响应
|
||||
"""
|
||||
result = services.get_{{ app_name }}_list(request)
|
||||
return R.ok(data=result)
|
||||
|
||||
|
||||
# =============================================================
|
||||
# 详情查询视图
|
||||
# =============================================================
|
||||
|
||||
@method_decorator(check_login, name="get")
|
||||
class {{ model_class_name }}DetailView(PermissionRequired, View):
|
||||
"""
|
||||
{{ module_comment }}详情查询视图
|
||||
|
||||
处理GET请求,根据{{ module_comment }}ID返回{{ module_comment }}详细信息。
|
||||
|
||||
URL: /{{ route_prefix }}/detail/<int:{{ primary_key }}>
|
||||
请求方法: GET
|
||||
URL参数: {{ primary_key }} - {{ module_comment }}ID
|
||||
权限要求:{{ permission_prefix }}:detail
|
||||
"""
|
||||
|
||||
# 方法权限标识
|
||||
permission_required = ("{{ permission_prefix }}:detail",)
|
||||
|
||||
@operation_log(
|
||||
title="{{ module_comment }}管理-查询记录详情",
|
||||
log_type=LogType.QUERY
|
||||
)
|
||||
def get(self, request, {{ primary_key }}):
|
||||
"""
|
||||
处理GET请求,返回{{ module_comment }}详情
|
||||
|
||||
Args:
|
||||
request: HttpRequest对象
|
||||
{{ primary_key }}: int, {{ module_comment }}ID(从URL中获取)
|
||||
|
||||
Returns:
|
||||
JsonResponse: 包含{{ module_comment }}详细信息的JSON响应
|
||||
"""
|
||||
data = services.get_{{ app_name }}_detail({{ primary_key }})
|
||||
return R.ok(data=data)
|
||||
|
||||
|
||||
# =============================================================
|
||||
# 添加视图
|
||||
# =============================================================
|
||||
|
||||
@method_decorator(check_login, name="post")
|
||||
class {{ model_class_name }}AddView(PermissionRequired, View):
|
||||
"""
|
||||
添加{{ module_comment }}视图
|
||||
|
||||
处理POST请求,创建新的{{ module_comment }}记录。
|
||||
|
||||
URL: /{{ route_prefix }}/add
|
||||
请求方法: POST
|
||||
权限要求:{{ permission_prefix }}:add
|
||||
"""
|
||||
|
||||
# 方法权限标识
|
||||
permission_required = ("{{ permission_prefix }}:add",)
|
||||
|
||||
@operation_log(
|
||||
title="{{ module_comment }}管理-添加记录",
|
||||
log_type=LogType.ADD
|
||||
)
|
||||
def post(self, request):
|
||||
"""
|
||||
处理POST请求,添加新{{ module_comment }}
|
||||
|
||||
Args:
|
||||
request: HttpRequest对象,包含{{ module_comment }}信息的JSON数据
|
||||
|
||||
Returns:
|
||||
JsonResponse: 包含操作结果的JSON响应
|
||||
"""
|
||||
# 演示环境禁止操作
|
||||
if DJANGO_DEMO:
|
||||
return R.failed("演示环境,暂无操作权限")
|
||||
|
||||
result = services.add_{{ app_name }}(request)
|
||||
return result
|
||||
|
||||
|
||||
# =============================================================
|
||||
# 更新视图
|
||||
# =============================================================
|
||||
|
||||
@method_decorator(check_login, name="put")
|
||||
class {{ model_class_name }}UpdateView(PermissionRequired, View):
|
||||
"""
|
||||
更新{{ module_comment }}视图
|
||||
|
||||
处理PUT请求,更新现有{{ module_comment }}信息。
|
||||
|
||||
URL: /{{ route_prefix }}/update
|
||||
请求方法: PUT
|
||||
权限要求:{{ permission_prefix }}:update
|
||||
"""
|
||||
|
||||
# 方法权限标识
|
||||
permission_required = ('{{ permission_prefix }}:update',)
|
||||
|
||||
@operation_log(
|
||||
title="{{ module_comment }}管理-更新记录",
|
||||
log_type=LogType.UPDATE
|
||||
)
|
||||
def put(self, request):
|
||||
"""
|
||||
处理PUT请求,更新{{ module_comment }}信息
|
||||
|
||||
Args:
|
||||
request: HttpRequest对象,包含{{ module_comment }}ID和更新信息的JSON数据
|
||||
|
||||
Returns:
|
||||
JsonResponse: 包含操作结果的JSON响应
|
||||
"""
|
||||
# 演示环境禁止操作
|
||||
if DJANGO_DEMO:
|
||||
return R.failed("演示环境,暂无操作权限")
|
||||
|
||||
result = services.update_{{ app_name }}(request)
|
||||
return result
|
||||
|
||||
|
||||
# =============================================================
|
||||
# 删除视图(支持批量)
|
||||
# =============================================================
|
||||
|
||||
@method_decorator(check_login, name="delete")
|
||||
class {{ model_class_name }}DeleteView(PermissionRequired, View):
|
||||
"""
|
||||
删除{{ module_comment }}视图
|
||||
|
||||
处理DELETE请求,删除指定{{ module_comment }}(支持批量删除)。
|
||||
|
||||
URL: /{{ route_prefix }}/delete/<str:{{ primary_key }}>
|
||||
请求方法: DELETE
|
||||
URL参数: {{ primary_key }} - {{ module_comment }}ID字符串,多个ID用逗号分隔
|
||||
权限要求:{{ permission_prefix }}:delete
|
||||
|
||||
注意: 删除{{ module_comment }}前请确认是否被其他数据关联
|
||||
"""
|
||||
|
||||
# 方法权限标识
|
||||
permission_required = ('{{ permission_prefix }}:delete',)
|
||||
|
||||
@operation_log(
|
||||
title="{{ module_comment }}管理-删除记录",
|
||||
log_type=LogType.DELETE
|
||||
)
|
||||
def delete(self, request, {{ primary_key }}):
|
||||
"""
|
||||
处理DELETE请求,删除{{ module_comment }}
|
||||
|
||||
Args:
|
||||
request: HttpRequest对象
|
||||
{{ primary_key }}: str, {{ module_comment }}ID字符串,多个ID用逗号分隔(从URL中获取)
|
||||
例如: "1" 或 "1,2,3"
|
||||
|
||||
Returns:
|
||||
JsonResponse: 包含操作结果的JSON响应
|
||||
"""
|
||||
# 演示环境禁止操作
|
||||
if DJANGO_DEMO:
|
||||
return R.failed("演示环境,暂无操作权限")
|
||||
|
||||
result = services.delete_{{ app_name }}s({{ primary_key }})
|
||||
return result
|
||||
|
||||
|
||||
{% if has_status %}
|
||||
# =============================================================
|
||||
# 状态更新视图
|
||||
# =============================================================
|
||||
|
||||
@method_decorator(check_login, name="put")
|
||||
class {{ model_class_name }}StatusView(PermissionRequired, View):
|
||||
"""
|
||||
设置{{ module_comment }}状态视图
|
||||
|
||||
处理PUT请求,更新{{ module_comment }}的启用/禁用状态。
|
||||
|
||||
URL: /{{ route_prefix }}/status
|
||||
请求方法: PUT
|
||||
权限要求:{{ permission_prefix }}:status
|
||||
"""
|
||||
|
||||
# 方法权限标识
|
||||
permission_required = ('{{ permission_prefix }}:status',)
|
||||
|
||||
def put(self, request):
|
||||
"""
|
||||
处理PUT请求,更新{{ module_comment }}状态
|
||||
|
||||
Args:
|
||||
request: HttpRequest对象,包含{{ module_comment }}ID和状态值的JSON数据
|
||||
|
||||
Returns:
|
||||
JsonResponse: 包含操作结果的JSON响应
|
||||
"""
|
||||
# 演示环境禁止操作
|
||||
if DJANGO_DEMO:
|
||||
return R.failed("演示环境,暂无操作权限")
|
||||
|
||||
result = services.update_{{ app_name }}_status(request)
|
||||
return result
|
||||
{% endif %}
|
||||
|
||||
|
||||
# =============================================================
|
||||
# 数据下拉列表视图
|
||||
# =============================================================
|
||||
|
||||
@method_decorator(check_login, name='get')
|
||||
class {{ model_class_name }}DataView(View):
|
||||
"""
|
||||
{{ module_comment }}列表获取视图
|
||||
|
||||
处理GET请求,返回所有启用{{ module_comment }}的列表数据。
|
||||
通常用于前端下拉选择框等场景。
|
||||
|
||||
URL: /{{ route_prefix }}/data
|
||||
请求方法: GET
|
||||
权限要求:需要登录
|
||||
"""
|
||||
|
||||
def get(self, request):
|
||||
"""
|
||||
处理GET请求,返回{{ module_comment }}列表
|
||||
|
||||
Args:
|
||||
request: HttpRequest对象
|
||||
|
||||
Returns:
|
||||
JsonResponse: 包含{{ module_comment }}列表的JSON响应
|
||||
"""
|
||||
result = services.get_{{ app_name }}_data()
|
||||
return R.ok(data=result)
|
||||
Reference in New Issue
Block a user