feat(model): 添加status字段表示启用状态

- 在myapp模块的ApplicationModel中新增status字段,标识应用是否启用
- 在demo模块的DemoModel中新增status字段,标识示例条目是否启用
- 修改代码生成模块相关模型,替换BaseMixin为CreatorMixin
- 删除代码生成模块中Python模板相关文件与Vue前端代码模板,优化代码结构和清理无用模板文件
This commit is contained in:
zhangtao
2025-09-17 01:33:53 +08:00
parent d36b86e446
commit 700d76ad5a
41 changed files with 1463 additions and 91 deletions
@@ -1,36 +1,18 @@
# -*- coding: utf-8 -*-
from datetime import datetime
from sqlalchemy import Column, DateTime, ForeignKey, Integer, String
from sqlalchemy.orm import relationship
from config.database import Base
from sqlalchemy import Boolean, Column, ForeignKey, String, Integer, Text, DateTime
from app.core.base_model import BaseMixin
from sqlalchemy import Boolean, Column, ForeignKey, String, Integer, Text, DateTime
from sqlalchemy.orm import relationship
from app.core.base_model import BaseMixin
from sqlalchemy import Boolean, Column, ForeignKey, String, Integer, Text, DateTime
from app.core.base_model import BaseMixin
from app.core.base_model import CreatorMixin
class PageModel(BaseMixin):
__tablename__ = "gen_page"
page_name = Column(String(length=255), comment='页面名称')
keywords = Column(String(length=500), comment='页面关键词')
title = Column(String(length=500), comment='页面title标题')
class GenTable(Base):
class GenTable(CreatorMixin):
"""
代码生成业务
代码生成表
"""
__tablename__ = 'gen_table'
__table_args__ = ({'comment': '代码生成表'})
table_id = Column(Integer, primary_key=True, autoincrement=True, comment='编号')
table_name = Column(String(200), nullable=True, default='', comment='表名称')
@@ -39,9 +21,7 @@ class GenTable(Base):
sub_table_fk_name = Column(String(64), nullable=True, comment='子表关联的外键名')
class_name = Column(String(100), nullable=True, default='', comment='实体类名称')
tpl_category = Column(String(200), nullable=True, default='crud', comment='使用的模板(crud单表操作 tree树表操作)')
tpl_web_type = Column(
String(30), nullable=True, default='', comment='前端模板类型(element-ui模版 element-plus模版)'
)
tpl_web_type = Column(String(30), nullable=True, default='', comment='前端模板类型(element-ui模版 element-plus模版)')
package_name = Column(String(100), nullable=True, comment='生成包路径')
module_name = Column(String(30), nullable=True, comment='生成模块名')
business_name = Column(String(30), nullable=True, comment='生成业务名')
@@ -59,7 +39,7 @@ class GenTable(Base):
columns = relationship('GenTableColumn', order_by='GenTableColumn.sort', back_populates='tables')
class GenTableColumn(Base):
class GenTableColumn(CreatorMixin):
"""
代码生成业务表字段
"""
@@ -0,0 +1,109 @@
# -*- coding:utf-8 -*-
from fastapi import APIRouter, Depends, Form
from sqlalchemy.ext.asyncio import AsyncSession
from starlette.requests import Request
from typing import List
from config.enums import BusinessType
from config.get_db import get_db
from module_admin.entity.vo.import_vo import ImportModel
from module_admin.service.import_service import ImportService
from module_admin.service.login_service import LoginService
from module_admin.aspect.data_scope import GetDataScope
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.annotation.log_annotation import Log
from utils.response_util import ResponseUtil
from utils.common_util import bytes2file_response
from {{ packageName }}.entity.vo.{{ tableName }}_vo import {{ tableName|snake_to_pascal_case }}PageModel, {{ tableName|snake_to_pascal_case }}Model
from {{ packageName }}.service.{{ tableName }}_service import {{ tableName|snake_to_pascal_case }}Service
{{ tableName|snake_to_camel }}Controller = APIRouter(prefix='/{{ moduleName }}/{{ businessName }}', dependencies=[Depends(LoginService.get_current_user)])
@{{ tableName|snake_to_camel }}Controller.get('/list', dependencies=[Depends(CheckUserInterfaceAuth('{{ permissionPrefix }}:query'))])
async def get_{{ tableName }}_list(
request: Request,
query_db: AsyncSession = Depends(get_db),
page_query: {{ tableName|snake_to_pascal_case }}PageModel = Depends( {{ tableName|snake_to_pascal_case }}PageModel.as_query),
data_scope_sql: str = Depends(GetDataScope('{{ tableName|snake_to_pascal_case }}'))
):
{{ tableName }}_result = await {{ tableName|snake_to_pascal_case }}Service.get_{{ tableName }}_list(query_db, page_query, data_scope_sql)
return ResponseUtil.success(model_content={{ tableName }}_result)
@{{ tableName|snake_to_camel }}Controller.get('/getById/{{ '{' }}{{ tableName|snake_to_camel }}Id{{ '}' }}', dependencies=[Depends(CheckUserInterfaceAuth('{{ permissionPrefix }}:query'))])
async def get_{{ tableName }}_by_id(
request: Request,
{{ tableName|snake_to_camel }}Id: int,
query_db: AsyncSession = Depends(get_db),
data_scope_sql: str = Depends(GetDataScope('{{ tableName|snake_to_pascal_case }}'))
):
{{ tableName }} = await {{ tableName|snake_to_pascal_case }}Service.get_{{ tableName }}_by_id(query_db, {{ tableName|snake_to_camel }}Id)
return ResponseUtil.success(data={{ tableName }})
@{{ tableName|snake_to_camel }}Controller.post('/add', dependencies=[Depends(CheckUserInterfaceAuth('{{ permissionPrefix }}:add'))])
@Log(title='{{ tableName }}', business_type=BusinessType.INSERT)
async def add_{{ tableName }} (
request: Request,
add_model: {{ tableName|snake_to_pascal_case }}Model,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
add_model.create_by = current_user.user.user_id
add_model.dept_id = current_user.user.dept_id
add_dict_type_result = await {{ tableName|snake_to_pascal_case }}Service.add_{{ tableName }}(query_db, add_model)
return ResponseUtil.success(data=add_dict_type_result)
@{{ tableName|snake_to_camel }}Controller.put('/update', dependencies=[Depends(CheckUserInterfaceAuth('{{ permissionPrefix }}:edit'))])
@Log(title='{{ tableName }}', business_type=BusinessType.UPDATE)
async def update_{{ tableName }}(
request: Request,
edit_model: {{ tableName|snake_to_pascal_case }}Model,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
add_dict_type_result = await {{ tableName|snake_to_pascal_case }}Service.update_{{ tableName }}(query_db, edit_model)
return ResponseUtil.success(data=add_dict_type_result)
@{{ tableName|snake_to_camel }}Controller.delete('/delete/{{ '{' }}{{ tableName|snake_to_camel }}Ids{{ '}' }}', dependencies=[Depends(CheckUserInterfaceAuth('{{ permissionPrefix }}:remove'))])
@Log(title='{{ tableName }}', business_type=BusinessType.DELETE)
async def del_{{ tableName }}(
request: Request,
{{ tableName|snake_to_camel }}Ids: str,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
ids = {{ tableName|snake_to_camel }}Ids.split(',')
del_result = await {{ tableName|snake_to_pascal_case }}Service.del_{{ tableName }}(query_db, ids)
return ResponseUtil.success(data=del_result)
@{{ tableName|snake_to_camel }}Controller.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('{{ permissionPrefix }}:export'))])
@Log(title='{{ tableName }}', business_type=BusinessType.EXPORT)
async def export_{{ tableName }}(
request: Request,
{{ tableName }}_form: {{ tableName|snake_to_pascal_case }}PageModel = Form(),
query_db: AsyncSession = Depends(get_db),
data_scope_sql: str = Depends(GetDataScope('{{ tableName|snake_to_pascal_case }}')),
):
# 获取全量数据
export_result = await {{ tableName|snake_to_pascal_case }}Service.export_{{ tableName }}_list(
query_db, {{ tableName }}_form, data_scope_sql
)
return ResponseUtil.streaming(data=bytes2file_response(export_result))
@{{ tableName|snake_to_camel }}Controller.post('/import', dependencies=[Depends(CheckUserInterfaceAuth('{{ permissionPrefix }}:import'))])
async def import_{{ tableName }}(request: Request,
import_model: ImportModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user)
):
"""
导入数据
"""
await ImportService.import_data(query_db, import_model, current_user)
return ResponseUtil.success()
@@ -0,0 +1,112 @@
# -*- coding:utf-8 -*-
from typing import List
from datetime import datetime, time
from module_admin.entity.do.role_do import SysRoleDept
from sqlalchemy import and_, delete, desc, func, or_, select, update
from sqlalchemy.ext.asyncio import AsyncSession
from module_gen.constants.gen_constants import GenConstants
{% if subTable %}
from sqlalchemy.orm import selectinload
{% endif %}
from {{ packageName }}.entity.do.{{ tableName }}_do import {{ tableName|snake_to_pascal_case }}
from {{ packageName }}.entity.vo.{{ tableName }}_vo import {{ tableName|snake_to_pascal_case }}PageModel, {{ tableName|snake_to_pascal_case }}Model
from utils.page_util import PageUtil, PageResponseModel
from utils.common_util import CamelCaseUtil
class {{ tableName|snake_to_pascal_case }}Dao:
@classmethod
async def get_by_id(cls, db: AsyncSession, {{ tableName }}_id: int) -> {{ tableName|snake_to_pascal_case }}:
"""根据主键获取单条记录"""
{{ tableName }} = (((await db.execute(
select({{ tableName|snake_to_pascal_case }})
.where({{ tableName|snake_to_pascal_case }}.id == {{ tableName }}_id)))
.scalars())
.first())
return {{ tableName }}
"""
查询
"""
@classmethod
async def get_{{ tableName }}_list(cls, db: AsyncSession,
query_object: {{ tableName|snake_to_pascal_case }}PageModel,
data_scope_sql: str = None,
is_page: bool = False) -> [list | PageResponseModel]:
query = (
select({{ tableName|snake_to_pascal_case }})
{% if subTable %}
.options(selectinload({{ tableName|snake_to_pascal_case }}.{{ subTable.table_name }}_list))
{% endif %}
.where(
{% for column in columns %}
{% if column.isQuery == "1" %}
{% if column.queryType == "LIKE" %}
{{ tableName|snake_to_pascal_case }}.{{ column.columnName }}.like(f"%{query_object.{{ column.columnName }}}%") if query_object.{{ column.columnName }} else True,
{% elif column.queryType == "EQ" %}
{{ tableName|snake_to_pascal_case }}.{{ column.columnName }} == query_object.{{ column.columnName }} if query_object.{{ column.columnName }} else True,
{% elif column.queryType == "GT" %}
{{ tableName|snake_to_pascal_case }}.{{ column.columnName }} > query_object.{{ column.columnName }} if query_object.{{ column.columnName }} else True,
{% elif column.queryType == "GTE" %}
{{ tableName|snake_to_pascal_case }}.{{ column.columnName }} >= query_object.{{ column.columnName }} if query_object.{{ column.columnName }} else True,
{% elif column.queryType == "NE" %}
{{ tableName|snake_to_pascal_case }}.{{ column.columnName }} != query_object.{{ column.columnName }} if query_object.{{ column.columnName }} else True,
{% elif column.queryType == "LT" %}
{{ tableName|snake_to_pascal_case }}.{{ column.columnName }} < query_object.{{ column.columnName }} if query_object.{{ column.columnName }} else True,
{% elif column.queryType == "LTE" %}
{{ tableName|snake_to_pascal_case }}.{{ column.columnName }} <= query_object.{{ column.columnName }} if query_object.{{ column.columnName }} else True,
{% elif column.queryType == "BETWEEN" %}
{{ tableName|snake_to_pascal_case }}.{{ column.columnName }}.between(query_object.begin_{{ column.columnName }}, query_object.end_{{ column.columnName }}) if query_object.{{ column.columnName }} else True,
{% endif %}
{% endif %}
{% endfor %}
{{ tableName|snake_to_pascal_case }}.del_flag == '0',
eval(data_scope_sql) if data_scope_sql else True,
)
.order_by(desc({{ tableName|snake_to_pascal_case }}.create_time))
.distinct()
)
{{ tableName }}_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page)
return {{ tableName }}_list
@classmethod
async def add_{{ tableName }}(cls, db: AsyncSession, add_model: {{ tableName|snake_to_pascal_case }}Model, auto_commit: bool = True) -> {{ tableName|snake_to_pascal_case }}Model:
"""
增加
"""
{{ tableName }} = {{ tableName|snake_to_pascal_case }}(**add_model.model_dump(exclude_unset=True, {% if subTable %}exclude={'{{ subTable.table_name }}_list',}{% endif %}))
db.add({{ tableName }})
await db.flush()
{{ tableName }}_model = {{ tableName|snake_to_pascal_case }}Model(**CamelCaseUtil.transform_result({{ tableName }}))
if auto_commit:
await db.commit()
return {{ tableName }}_model
@classmethod
async def edit_{{ tableName }}(cls, db: AsyncSession, edit_model: {{ tableName|snake_to_pascal_case }}Model, auto_commit: bool = True) -> {{ tableName|snake_to_pascal_case }}:
"""
修改
"""
edit_dict_data = edit_model.model_dump(exclude_unset=True, exclude={ {% if subTable %}'{{ subTable.table_name }}_list', {% endif %}*GenConstants.DAO_COLUMN_NOT_EDIT })
await db.execute(update({{ tableName|snake_to_pascal_case }}), [edit_dict_data])
await db.flush()
if auto_commit:
await db.commit()
return await cls.get_by_id(db, edit_model.{{ pkColumn.pythonField }})
@classmethod
async def del_{{ tableName }}(cls, db: AsyncSession, {{ tableName }}_ids: List[str], soft_del: bool = True, auto_commit: bool = True):
"""
删除
"""
if soft_del:
await db.execute(update({{ tableName|snake_to_pascal_case }}).where({{ tableName|snake_to_pascal_case }}.id.in_({{ tableName }}_ids)).values(del_flag='2'))
else:
await db.execute(delete({{ tableName|snake_to_pascal_case }}).where({{ tableName|snake_to_pascal_case }}.id.in_({{ tableName }}_ids)))
await db.flush()
if auto_commit:
await db.commit()
@@ -0,0 +1,41 @@
# -*- coding:utf-8 -*-
from sqlalchemy import Column, ForeignKey, {{ importList }}
from config.database import BaseMixin, Base
{% if subTable %}
from sqlalchemy.orm import relationship
{% endif %}
class {{ tableName|snake_to_pascal_case }}(Base, BaseMixin):
"""
{{ functionName }}表
"""
__tablename__ = "{{ tableName }}"
{% for column in columns %}
{% if not column.columnName | is_base_column %}
{{ column.columnName }} = Column({{ column.columnType|get_sqlalchemy_type }}, {{ column | get_column_options }})
{% endif %}
{% endfor %}
{% if subTable %}
{{ subTable.table_name }}_list = relationship('{{ subClassName }}', back_populates='{{ tableName }}')
{% endif %}
{% if subTable %}
class {{ subClassName }}(Base, BaseMixin):
"""
{{ functionName }}表
"""
__tablename__ = '{{ subTableName }}'
{% for column in subTable.columns %}
{% if not column.column_name | is_base_column %}
{{ column.column_name }} = Column({{ column.column_type | get_sqlalchemy_type }}, {% if column.column_name == subTableFkName %}ForeignKey('{{ tableName }}.id'), {% endif %}{% if column.pk %}primary_key=True, {% endif %}{% if column.increment %}autoincrement=True, {% endif %}{% if column.required %}nullable=True{% else %}nullable=False{% endif %}, comment='{{ column.column_comment }}')
{% endif %}
{% endfor %}
{% if subTable %}
{{ tableName }} = relationship('{{ ClassName }}', back_populates='{{ subTable.table_name }}_list')
{% endif %}
{% endif %}
@@ -0,0 +1,63 @@
# -*- coding:utf-8 -*-
from datetime import datetime
from pydantic import BaseModel, ConfigDict, Field
from pydantic.alias_generators import to_camel
from typing import List, Literal, Optional, Union
from module_admin.annotation.pydantic_annotation import as_query
class {{ tableName|snake_to_pascal_case }}{% if subTable %}Base{% endif %}Model(BaseModel):
"""
表对应pydantic模型
"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True)
{% for column in columns %}
{{ column.columnName }}: Optional[{{ column.pythonType }}] = Field(default=None, description='{{ column.columnComment }}')
{% if column.queryType == 'BETWEEN' %}
begin_{{ column.columnName }}: Optional[{{ column.pythonType }}] = Field(default=None, description='{{ column.columnComment }}最小值')
{% endif %}
{% if column.queryType == 'BETWEEN' %}
end_{{ column.columnName }}: Optional[{{ column.pythonType }}] = Field(default=None, description='{{ column.columnComment }}最大值')
{% endif %}
{% endfor %}
{% if subTable %}
class {{ tableName|snake_to_pascal_case }}Model({{ tableName|snake_to_pascal_case }}BaseModel):
{{ subTableName }}_list: Optional[List['{{ subTable.table_name | snake_to_pascal_case }}Model']] = Field(default=None, description='子表列信息')
{% endif %}
@as_query
class {{ tableName|snake_to_pascal_case }}PageModel({{ tableName|snake_to_pascal_case }}{% if subTable %}Base{% endif %}Model):
"""
分页查询模型
"""
page_num: int = Field(default=1, description='当前页码')
page_size: int = Field(default=10, description='每页记录数')
{% if subTable %}
class {{ subTable.table_name | snake_to_pascal_case }}Model(BaseModel):
"""
{{ subTable.function_name }}表对应pydantic模型
"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True)
{% for sub_column in subTable.columns %}
{{ sub_column.column_name }}: Optional[{{ sub_column.python_type }}] = Field(default=None, description='{{ sub_column.column_comment}}')
{% endfor %}
{% for sub_column in subTable.columns %}
{% if sub_column.required %}
{% set parentheseIndex = sub_column.column_comment.find("") %}
{% set comment = sub_column.column_comment[:parentheseIndex] if parentheseIndex != -1 else sub_column.column_comment %}
@NotBlank(field_name='{{ sub_column.column_name }}', message='{{ comment }}不能为空')
def get_{{ sub_column.column_name }}(self):
return self.{{ sub_column.column_name }}
{% if not loop.last %}{{ "\n" }}{% endif %}
{% endif %}
{% endfor %}
{% endif %}
@@ -0,0 +1,62 @@
# -*- coding:utf-8 -*-
from typing import List
from sqlalchemy.ext.asyncio import AsyncSession
from utils.common_util import CamelCaseUtil, export_list2excel
from module_admin.entity.vo.sys_table_vo import SysTablePageModel
from module_admin.service.sys_table_service import SysTableService
from utils.page_util import PageResponseModel
from {{ packageName }}.dao.{{ tableName }}_dao import {{ tableName|snake_to_pascal_case }}Dao
from {{ packageName }}.entity.do.{{ tableName }}_do import {{ tableName|snake_to_pascal_case }}
from {{ packageName }}.entity.vo.{{ tableName }}_vo import {{ tableName|snake_to_pascal_case }}PageModel, {{ tableName|snake_to_pascal_case }}Model
class {{ tableName|snake_to_pascal_case }}Service:
"""
用户管理模块服务层
"""
@classmethod
async def get_{{ tableName }}_list(cls, query_db: AsyncSession, query_object: {{ tableName|snake_to_pascal_case }}PageModel, data_scope_sql: str) -> [list | PageResponseModel]:
{{ tableName }}_list = await {{ tableName|snake_to_pascal_case }}Dao.get_{{ tableName }}_list(query_db, query_object, data_scope_sql, is_page=True)
return {{ tableName }}_list
@classmethod
async def get_{{ tableName }}_by_id(cls, query_db: AsyncSession, {{ tableName }}_id: int) -> {{ tableName|snake_to_pascal_case }}Model:
{{ tableName }} = await {{ tableName|snake_to_pascal_case }}Dao.get_by_id(query_db, {{ tableName }}_id)
{{ tableName }}_model = {{ tableName|snake_to_pascal_case }}Model(**CamelCaseUtil.transform_result({{ tableName }}))
return {{ tableName }}_model
@classmethod
async def add_{{ tableName }}(cls, query_db: AsyncSession, query_object: {{ tableName|snake_to_pascal_case }}Model) -> {{ tableName|snake_to_pascal_case }}Model:
{{ tableName }}_model = await {{ tableName|snake_to_pascal_case }}Dao.add_{{ tableName }}(query_db, query_object)
return {{ tableName }}_model
@classmethod
async def update_{{ tableName }}(cls, query_db: AsyncSession, query_object: {{ tableName|snake_to_pascal_case }}Model) -> {{ tableName|snake_to_pascal_case }}Model:
{{ tableName }} = await {{ tableName|snake_to_pascal_case }}Dao.edit_{{ tableName }}(query_db, query_object)
{{ tableName }}_model = {{ tableName|snake_to_pascal_case }}Model(**CamelCaseUtil.transform_result({{ tableName }}))
return {{ tableName }}_model
@classmethod
async def del_{{ tableName }}(cls, query_db: AsyncSession, {{ tableName }}_ids: List[str]):
await {{ tableName|snake_to_pascal_case }}Dao.del_{{ tableName }}(query_db, {{ tableName }}_ids)
@classmethod
async def export_{{ tableName }}_list(cls, query_db: AsyncSession, query_object: {{ tableName|snake_to_pascal_case }}PageModel, data_scope_sql) -> bytes:
{{ tableName }}_list = await {{ tableName|snake_to_pascal_case }}Dao.get_{{ tableName }}_list(query_db, query_object, data_scope_sql, is_page=False)
filed_list = await SysTableService.get_sys_table_list(query_db, SysTablePageModel(tableName='{{ tableName }}'), is_page=False)
filtered_filed = sorted(filter(lambda x: x["show"] == '1', filed_list), key=lambda x: x["sequence"])
new_data = []
for item in {{ tableName }}_list:
mapping_dict = {}
for fild in filtered_filed:
if fild["prop"] in item:
mapping_dict[fild["label"]] = item[fild["prop"]]
new_data.append(mapping_dict)
binary_data = export_list2excel(new_data)
return binary_data
@@ -0,0 +1,36 @@
-- 菜单 SQL
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('{{functionName}}', '{{parentMenuId}}', '1', '{{moduleName}}_{{businessName}}', '{{moduleName}}/{{businessName}}/index', 1, 0, 'C', '0', '0', '{{permissionPrefix}}:list', '#', 'admin', sysdate(), '', null, '{{functionName}}菜单');
-- 按钮父菜单ID
SELECT @parentId := LAST_INSERT_ID();
-- 按钮 SQL
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('{{functionName}}查询', @parentId, '1', '#', '', 1, 0, 'F', '0', '0', '{{permissionPrefix}}:query', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('{{functionName}}新增', @parentId, '2', '#', '', 1, 0, 'F', '0', '0', '{{permissionPrefix}}:add', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('{{functionName}}修改', @parentId, '3', '#', '', 1, 0, 'F', '0', '0', '{{permissionPrefix}}:edit', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('{{functionName}}删除', @parentId, '4', '#', '', 1, 0, 'F', '0', '0', '{{permissionPrefix}}:remove', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('{{functionName}}导出', @parentId, '5', '#', '', 1, 0, 'F', '0', '0', '{{permissionPrefix}}:export', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('{{functionName}}导入', @parentId, '6', '#', '', 1, 0, 'F', '0', '0', '{{permissionPrefix}}:import', '#', 'admin', sysdate(), '', null, '');
{% for column in columns %}
{% set pythonField = column.pythonField | snake_to_camel %}
{% set parentheseIndex = column.columnComment.find("") %}
{% set comment = column.columnComment[:parentheseIndex] if parentheseIndex != -1 else column.columnComment %}
{% if column.isList %}
INSERT INTO `sys_table` (`table_name`, `field_name`, `prop`, `label`, `sequence`) VALUES ('{{ tableName }}', '{{ column.pythonField }}', '{{ pythonField }}', '{{ comment }}', {{ loop.index0 }});
{% endif %}
{% endfor %}
INSERT INTO `sys_table` (`table_name`, `field_name`, `prop`, `label`, `sequence`, `fixed`) VALUES ('{{ tableName }}', 'operate', 'operate', '操作', {{ columns|length }}, '2');
@@ -0,0 +1,53 @@
import request from '@/utils/request'
// 查询{{functionName}}列表
export function list{{BusinessName}}(query) {
return request({
url: '/{{moduleName}}/{{businessName}}/list',
method: 'get',
params: query
})
}
// 查询{{functionName}}详细
export function get{{BusinessName}}({{pkColumn.pythonField | snake_to_camel}}) {
return request({
url: '/{{moduleName}}/{{businessName}}/getById/' + {{pkColumn.pythonField | snake_to_camel}},
method: 'get'
})
}
// 新增{{functionName}}
export function add{{BusinessName}}(data) {
return request({
url: '/{{moduleName}}/{{businessName}}/add',
method: 'post',
data: data
})
}
// 修改{{functionName}}
export function update{{BusinessName}}(data) {
return request({
url: '/{{moduleName}}/{{businessName}}/update',
method: 'put',
data: data
})
}
// 删除{{functionName}}
export function del{{BusinessName}}({{pkColumn.pythonField | snake_to_camel}}) {
return request({
url: '/{{moduleName}}/{{businessName}}/delete/' + {{pkColumn.pythonField | snake_to_camel}},
method: 'delete'
})
}
// 导入{{functionName}}
export function import{{BusinessName}}(data) {
return request({
url: '/{{moduleName}}/{{businessName}}/import',
method: 'post',
data: data
})
}
@@ -0,0 +1,628 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
{% for column in columns %}
{% if column.isQuery == "1" %}
{% set dictType = column.dictType %}
{% set parentheseIndex = column.columnComment.find("") %}
{% set comment = column.columnComment[:parentheseIndex] if parentheseIndex != -1 else column.columnComment %}
{% if column.htmlType == "input" %}
<el-form-item label="{{ comment }}" prop="{{ column.pythonField | snake_to_camel }}">
<el-input
v-model="queryParams.{{ column.pythonField | snake_to_camel }}"
placeholder="请输入{{ comment }}"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
{% elif (column.htmlType == "select" or column.htmlType == "radio") and dictType != "" %}
<el-form-item label="{{ comment }}" prop="{{ column.pythonField | snake_to_camel }}">
<el-select
v-model="queryParams.{{ column.pythonField | snake_to_camel }}"
placeholder="请选择{{ comment }}"
style="width: 180px"
clearable>
<el-option
v-for="dict in {{ dictType }}"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
{% elif (column.htmlType == "select" or column.htmlType == "radio") and dictType %}
<el-form-item label="{{ comment }}" prop="{{ column.pythonField | snake_to_camel }}">
<el-select v-model="queryParams.{{ column.pythonField | snake_to_camel }}" placeholder="请选择{{ comment }}" clearable>
<el-option label="请选择字典生成" value="" />
</el-select>
</el-form-item>
{% elif column.htmlType == "datetime" and column.queryType != "BETWEEN" %}
<el-form-item label="{{ comment }}" prop="{{ column.pythonField | snake_to_camel }}">
<el-date-picker clearable
v-model="queryParams.{{ column.pythonField | snake_to_camel }}"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择{{ comment }}">
</el-date-picker>
</el-form-item>
{% elif column.htmlType == "datetime" and column.queryType == "BETWEEN" %}
<el-form-item label="{{ comment }}" style="width: 308px">
<el-date-picker
v-model="daterange{{ column.pythonField | snake_to_pascal_case }}"
value-format="YYYY-MM-DD"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
></el-date-picker>
</el-form-item>
{% endif %}
{% endif %}
{% endfor %}
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-card class="base-table" ref="fullTable">
<TableSetup
ref="tSetup"
@onStripe="onStripe"
@onRefresh="onRefresh"
@onChange="onChange"
@onfullTable="onfullTable"
@onSearchChange="onSearchChange"
:columns="columns"
:isTable="isTable"
>
<template v-slot:operate>
<el-button
type="primary"
plain
icon="Plus"
@click="handleAdd"
v-hasPermi="['{{ moduleName }}:{{ businessName }}:add']"
>新增</el-button>
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['{{ moduleName }}:{{ businessName }}:edit']"
>修改</el-button>
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['{{ moduleName }}:{{ businessName }}:remove']"
>删除</el-button>
<el-button
type="primary"
plain
icon="Upload"
@click="handleImport"
v-hasPermi="['{{ moduleName }}:{{ businessName }}:import']"
>导入</el-button
>
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['{{ moduleName }}:{{ businessName }}:export']"
>导出</el-button>
</template>
</TableSetup>
<auto-table
ref="multipleTable"
class="mytable"
:tableData="{{ businessName }}List"
:columns="columns"
:loading="loading"
:stripe="stripe"
:tableHeight="tableHeight"
@onColumnWidthChange="onColumnWidthChange"
@onSelectionChange="handleSelectionChange"
>
{% for column in columns %}
{% set pythonField = column.pythonField | snake_to_camel %}
{% set parentheseIndex = column.columnComment.find("") %}
{% set comment = column.columnComment[:parentheseIndex] if parentheseIndex != -1 else column.columnComment %}
{% if column.isList and column.htmlType == "datetime" %}
<template #{{ pythonField }}="{ row }">
<span>{% raw %}{{{% endraw %} parseTime(row.{{ pythonField }}, '{y}-{m}-{d}') {% raw %}}}{% endraw %}</span>
</template>
{% elif column.isList == "1" and column.htmlType == "imageUpload" %}
<template #{{ pythonField }}="{ row }">
<image-preview :src="fullUrl(row.{{ pythonField }})" v-if="row.{{ pythonField }}" :width="50" :height="50"/>
</template>
{% elif column.isList == "1" and column.dictType != "" %}
<template #{{ pythonField }}="{ row }">
{% if column.htmlType == "checkbox" %}
<dict-tag :options="{{ column.dictType }}" :value="row.{{ pythonField }} ? row.{{ pythonField }}.split(',') : []"/>
{% else %}
<dict-tag :options="{{ column.dictType }}" :value="row.{{ pythonField }}"/>
{% endif %}
</template>
{% endif %}
{% endfor %}
<template #operate="{ row }">
<el-button link type="primary" icon="Edit" @click="handleUpdate(row)" v-hasPermi="['{{ moduleName }}:{{ businessName }}:edit']">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(row)" v-hasPermi="['{{ moduleName }}:{{ businessName }}:remove']">删除</el-button>
</template>
</auto-table>
<div class="table-pagination">
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</div>
</el-card>
<!-- 添加或修改{{ functionName }}对话框 -->
<el-dialog :title="title" v-model="open" width="800px" append-to-body>
<el-form ref="{{ businessName }}Ref" :model="form" :rules="rules" label-width="80px">
{% for column in columns %}
{% set field = column.pythonField | snake_to_camel %}
{% if column.isInsert == "1" and not column.isPk == "1" %}
{% if column.usableColumn or not column.superColumn %}
{% set parentheseIndex = column.columnComment.find("") %}
{% set comment = column.columnComment[:parentheseIndex] if parentheseIndex != -1 else column.columnComment %}
{% set dictType = column.dictType %}
{% if column.htmlType == "input" %}
<el-form-item label="{{ comment }}" prop="{{ field }}">
<el-input v-model="form.{{ field }}" placeholder="请输入{{ comment }}" />
</el-form-item>
{% elif column.htmlType == "imageUpload" %}
<el-form-item label="{{ comment }}" prop="{{ field }}">
<image-upload v-model="form.{{ field }}"/>
</el-form-item>
{% elif column.htmlType == "fileUpload" %}
<el-form-item label="{{ comment }}" prop="{{ field }}">
<file-upload v-model="form.{{ field }}"/>
</el-form-item>
{% elif column.htmlType == "editor" %}
<el-form-item label="{{ comment }}">
<editor v-model="form.{{ field }}" :min-height="192"/>
</el-form-item>
{% elif column.htmlType == "select" and dictType != "" %}
<el-form-item label="{{ comment }}" prop="{{ field }}">
<el-select v-model="form.{{ field }}" placeholder="请选择{{ comment }}">
<el-option
v-for="dict in {{ dictType }}"
:key="dict.value"
:label="dict.label"
{% if column.pythonType == "int" %}
:value="parseInt(dict.value)"
{% else %}
:value="dict.value"
{% endif %}
></el-option>
</el-select>
</el-form-item>
{% elif column.htmlType == "select" and dictType %}
<el-form-item label="{{ comment }}" prop="{{ field }}">
<el-select v-model="form.{{ field }}" placeholder="请选择{{ comment }}">
<el-option label="请选择字典生成" value="" />
</el-select>
</el-form-item>
{% elif column.htmlType == "checkbox" and dictType != "" %}
<el-form-item label="{{ comment }}" prop="{{ field }}">
<el-checkbox-group v-model="form.{{ field }}">
<el-checkbox
v-for="dict in {{ dictType }}"
:key="dict.value"
:label="dict.value">
{{ dict.label }}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
{% elif column.htmlType == "checkbox" and dictType %}
<el-form-item label="{{ comment }}" prop="{{ field }}">
<el-checkbox-group v-model="form.{{ field }}">
<el-checkbox>请选择字典生成</el-checkbox>
</el-checkbox-group>
</el-form-item>
{% elif column.htmlType == "radio" and dictType != "" %}
<el-form-item label="{{ comment }}" prop="{{ field }}">
<el-radio-group v-model="form.{{ field }}">
<el-radio
v-for="dict in {{ dictType }}"
:key="dict.value"
{% if column.pythonType == "int" %}
:label="parseInt(dict.value)"
{% else %}
:label="dict.value"
{% endif %}
>{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
{% elif column.htmlType == "radio" and dictType %}
<el-form-item label="{{ comment }}" prop="{{ field }}">
<el-radio-group v-model="form.{{ field }}">
<el-radio label="1">请选择字典生成</el-radio>
</el-radio-group>
</el-form-item>
{% elif column.htmlType == "datetime" %}
<el-form-item label="{{ comment }}" prop="{{ field }}">
<el-date-picker clearable
v-model="form.{{ field }}"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择{{ comment }}">
</el-date-picker>
</el-form-item>
{% elif column.htmlType == "textarea" %}
<el-form-item label="{{ comment }}" prop="{{ field }}">
<el-input v-model="form.{{ field }}" type="textarea" placeholder="请输入内容" />
</el-form-item>
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</template>
</el-dialog>
<!-- 导入数据对话框 -->
<ImportData
v-if="openImport"
v-model="openImport"
tableName="{{ tableName }}"
@success="handleImportSuccess"
/>
</div>
</template>
<script setup name="{{ tableName|snake_to_pascal_case }}">
import { list{{ BusinessName }}, get{{ BusinessName }}, del{{ BusinessName }}, add{{ BusinessName }}, update{{ BusinessName }}, import{{ BusinessName }} } from "@/api/{{ moduleName }}/{{ businessName }}";
import { listAllTable } from '@/api/system/table'
import TableSetup from '@/components/TableSetup'
import AutoTable from '@/components/AutoTable'
import ImportData from '@/components/ImportData'
const { proxy } = getCurrentInstance();
{% if dicts != '' %}
{% set dictsNoSymbol = dicts.replace("'", "") %}
const { {{ dictsNoSymbol }} } = proxy.useDict({{ dicts }});
{% endif %}
const {{ businessName }}List = ref([]);
{#{% if table.sub %}#}
{# const {{ subclassName }}List = ref([]);#}
{#{% endif %}#}
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
{#{% if table.sub %}#}
{# const checked{{ subClassName }} = ref([]);#}
{#{% endif %}#}
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
{% for column in columns %}
{% if column.htmlType == "datetime" and column.queryType == "BETWEEN" %}
const daterange{{ column.pythonField | snake_to_pascal_case }} = ref([]);
{% endif %}
{% endfor %}
const columns = ref([])
const stripe = ref(true)
const isTable = ref(true)
const tableHeight = ref(500)
const fullScreen = ref(false)
const openImport = ref(false)
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
{% for column in columns %}
{% if column.isQuery == "1" %}
{{ column.pythonField | snake_to_camel }}: null{% if not loop.last %},{% endif %}
{% endif %}
{% endfor %}
},
rules: {
{% for column in columns %}
{% if column.isRequired == "1" %}
{% set parentheseIndex = column.columnComment.find("") %}
{% set comment = column.columnComment[:parentheseIndex] if parentheseIndex != -1 else column.columnComment %}
{{ column.pythonField | snake_to_camel }}: [
{ required: true, message: "{{ comment }}不能为空", trigger: "{% if column.htmlType == "select" or column.htmlType == "radio" %}change{% else %}blur{% endif %}" }
]{% if not loop.last %},{% endif %}
{% endif %}
{% endfor %}
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询{{ functionName }}列表 */
function getList() {
loading.value = true;
{% for column in columns %}
{% if column.htmlType == "datetime" and column.queryType == "BETWEEN" %}
queryParams.value.params = {};
{% endif %}
{% endfor %}
{% for column in columns %}
{% if column.htmlType == "datetime" and column.queryType == "BETWEEN" %}
if (null != daterange{{ column.pythonField | snake_to_pascal_case }} && '' != daterange{{ column.pythonField | snake_to_pascal_case }}) {
queryParams.value.params["begin{{ column.pythonField | snake_to_pascal_case }}"] = daterange{{ column.pythonField | snake_to_pascal_case }}.value[0];
queryParams.value.params["end{{ column.pythonField | snake_to_pascal_case }}"] = daterange{{ column.pythonField | snake_to_pascal_case }}.value[1];
}
{% endif %}
{% endfor %}
list{{ BusinessName }}(queryParams.value).then(response => {
{{ businessName }}List.value = response.rows;
total.value = response.total;
loading.value = false;
});
}
function getColumns() {
listAllTable({ tableName: '{{ tableName }}' })
.then((response) => {
columns.value = response.data
})
.then(() => {
getList()
})
}
// 取消按钮
function cancel() {
open.value = false;
reset();
}
// 表单重置
function reset() {
form.value = {
{% for column in columns %}
{% if column.htmlType == "checkbox" %}
{{ column.pythonField | snake_to_camel }}: []{% if not loop.last %},{% endif %}
{% else %}
{{ column.pythonField | snake_to_camel }}: null{% if not loop.last %},{% endif %}
{% endif %}
{% endfor %}
};
{# {% if table.sub %}#}
{# {{ subclassName }}List.value = [];#}
{# {% endif %}#}
proxy.resetForm("{{ businessName }}Ref");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
{% for column in columns %}
{% if column.htmlType == "datetime" and column.queryType == "BETWEEN" %}
daterange{{ column.pythonField | snake_to_pascal_case }}.value = [];
{% endif %}
{% endfor %}
proxy.resetForm("queryRef");
handleQuery();
}
// 多选框选中数据
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.{{ pkColumn.pythonField }});
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加{{ functionName }}";
}
/** 新增按钮操作 */
function handleImport() {
openImport.value = true
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const {{ tableName | snake_to_camel }}{{ pkColumn.pythonField | snake_to_pascal_case }} = row.{{ pkColumn.pythonField | snake_to_camel }} || ids.value
get{{ BusinessName }}({{ tableName | snake_to_camel }}{{ pkColumn.pythonField | snake_to_pascal_case }}).then(response => {
form.value = response.data;
{% for column in columns %}
{% if column.htmlType == "checkbox" %}
form.value.{{ column.pythonField | snake_to_camel }} = form.value.{{ column.pythonField | snake_to_camel }}.split(",");
{% endif %}
{% endfor %}
{# {% if table.sub %}#}
{# {{ subclassName }}List.value = response.data.{{ subclassName }}List;#}
{# {% endif %}#}
open.value = true;
title.value = "修改{{ functionName }}";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["{{ businessName }}Ref"].validate(valid => {
if (valid) {
{% for column in columns %}
{% if column.htmlType == "checkbox" %}
form.value.{{ column.pythonField | snake_to_camel }} = form.value.{{ column.pythonField | snake_to_camel }}.join(",");
{% endif %}
{% endfor %}
{# {% if table.sub %}#}
{# form.value.{{ subclassName }}List = {{ subclassName }}List.value;#}
{# {% endif %}#}
if (form.value.{{ pkColumn.pythonField }} != null) {
update{{ BusinessName }}(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
add{{ BusinessName }}(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const _{{ pkColumn.pythonField }}s = row.{{ pkColumn.pythonField }} || ids.value;
proxy.$modal.confirm('是否确认删除{{ functionName }}编号为"' + _{{ pkColumn.pythonField }}s + '"的数据项?').then(function() {
return del{{ BusinessName }}(_{{ pkColumn.pythonField }}s);
}).then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
}).catch(() => {});
}
{#{% if table.sub %}#}
{# /** {{ subTable.functionName }}序号 */#}
{# function row{{ subClassName }}Index({ row, rowIndex }) {#}
{# row.index = rowIndex + 1;#}
{# }#}
{##}
{# /** {{ subTable.functionName }}添加按钮操作 */#}
{# function handleAdd{{ subClassName }}() {#}
{# let obj = {};#}
{# {% for column in subTable.columns %}#}
{# {% if column.pk or column.pythonField == subTableFkclassName %}#}
{# {% elif column.list and pythonField != "" %}#}
{# obj.{{ column.pythonField }} = "";#}
{# {% endif %}#}
{# {% endfor %}#}
{# {{ subclassName }}List.value.push(obj);#}
{# }#}
{##}
{# /** {{ subTable.functionName }}删除按钮操作 */#}
{# function handleDelete{{ subClassName }}() {#}
{# if (checked{{ subClassName }}.value.length == 0) {#}
{# proxy.$modal.msgError("请先选择要删除的{{ subTable.functionName }}数据");#}
{# } else {#}
{# const {{ subclassName }}s = {{ subclassName }}List.value;#}
{# const checked{{ subClassName }}s = checked{{ subClassName }}.value;#}
{# {{ subclassName }}List.value = {{ subclassName }}s.filter(function(item) {#}
{# return checked{{ subClassName }}s.indexOf(item.index) == -1#}
{# });#}
{# }#}
{# }#}
{##}
{# /** 复选框选中数据 */#}
{# function handle{{ subClassName }}SelectionChange(selection) {#}
{# checked{{ subClassName }}.value = selection.map(item => item.index)#}
{# }#}
{#{% endif %}#}
/** 导出按钮操作 */
function handleExport() {
proxy.download('{{ moduleName }}/{{ businessName }}/export', {
...queryParams.value
}, `{{ businessName }}_${new Date().getTime()}.xlsx`)
}
//表格全屏
function onfullTable() {
proxy.$refs.tSetup.onFull(proxy.$refs.fullTable.$el)
fullScreen.value = !fullScreen.value
updateTableHeight()
}
//表格刷新
function onRefresh() {
getList()
}
//搜索框显示隐藏
function onSearchChange() {
showSearch.value = !showSearch.value
}
function onStripe(val) {
stripe.value = val
}
//改变表头数据
function onChange(val) {
columns.value = val
}
//改变表格宽度
function onColumnWidthChange(column) {
proxy.$refs.tSetup.tableWidth(column)
}
//更新表格高度
function updateTableHeight() {
if (
proxy.$refs.tSetup &&
proxy.$refs.queryRef &&
document.querySelector('.table-pagination')
) {
if (fullScreen.value) {
tableHeight.value = window.innerHeight - 145
} else {
tableHeight.value =
window.innerHeight -
proxy.$refs.tSetup.$el.clientHeight -
proxy.$refs.queryRef.$el.clientHeight -
document.querySelector('.table-pagination').clientHeight -
220
}
}
}
//导入成功
function handleImportSuccess(sheetName, filedInfo, fileName) {
let data = {
tableName: '{{ tableName }}',
filedInfo: filedInfo,
fileName: fileName,
sheetName: sheetName
}
import{{ BusinessName }}(data).then(() => {
proxy.$modal.msgSuccess('导入成功')
openImport.value = false
getList()
})
getList()
}
onMounted(() => {
updateTableHeight() // 初始化计算高度
window.addEventListener('resize', updateTableHeight) // 监听窗口大小变化
})
onUnmounted(() => {
window.removeEventListener('resize', updateTableHeight) // 销毁监听
})
getColumns()
</script>