Files
FastapiAdmin/backend/templates/python/service.py.j2
T
zhangtao 0aeb77e0bd feat: 新增权限指令并集成到多个页面组件
refactor(backend): 重构数据库模型和初始化逻辑

fix(frontend): 修复权限指令在多个组件中的使用问题

perf(backend): 优化数据库连接和初始化性能

docs: 更新低代码生成器的README文档

style: 清理无用代码和注释

chore: 移除不再需要的依赖项

test: 更新用户权限相关测试用例

ci: 更新CI配置以支持新的权限检查

build: 更新依赖项版本
2025-09-28 23:42:26 +08:00

274 lines
10 KiB
Django/Jinja

# -*- coding:utf-8 -*-
import io
from datetime import datetime
from sqlalchemy.ext.asyncio import AsyncSession
from typing import Any, List, Dict, Optional
from fastapi import UploadFile
import pandas as pd
from app.core.exceptions import CustomException
from app.common.response import SuccessResponse
from app.api.v1.module_system.user.schema import UserOutSchema
from app.api.v1.module_system.auth.schema import AuthSchema
from app.utils.excel_util import ExcelUtil
from {{ packageName }}.crud.{{ tableName }}_crud import {{ tableName|snake_to_pascal_case }}Dao
from {{ packageName }}.schema import {{ tableName|snake_to_pascal_case }}CreateSchema, {{ tableName|snake_to_pascal_case }}UpdateSchema
from {{ packageName }}.param import {{ tableName|snake_to_pascal_case }}QueryParam
class {{ tableName|snake_to_pascal_case }}Service:
"""
{{ functionName }}服务层
"""
@classmethod
async def get_{{ tableName }}_list_service(
cls, auth: AuthSchema, search: {{ tableName|snake_to_pascal_case }}QueryParam = None, order_by: Optional[str] = None
):
"""
获取{{ functionName }}列表信息service
:param auth: 认证信息
:param search: 查询参数对象
:param order_by: 排序字段
:return: {{ functionName }}列表信息对象
"""
# 确保db是AsyncSession类型
if not isinstance(auth.db, AsyncSession):
raise CustomException(msg='数据库会话类型不正确')
{{ tableName }}_dao = {{ tableName|snake_to_pascal_case }}Dao(auth=auth)
{{ tableName }}_list_result = await {{ tableName }}_dao.get_{{ tableName }}_list(auth.db, search, order_by)
return {{ tableName }}_list_result
@classmethod
async def get_{{ tableName }}_by_id_service(cls, auth: AuthSchema, {{ tableName }}_id: int):
"""
根据{{ tableName }}id获取{{ functionName }}信息service
:param auth: 认证信息
:param {{ tableName }}_id: {{ tableName }}id
:return: {{ functionName }}信息对象
"""
# 确保db是AsyncSession类型
if not isinstance(auth.db, AsyncSession):
raise CustomException(msg='数据库会话类型不正确')
{{ tableName }}_dao = {{ tableName|snake_to_pascal_case }}Dao(auth=auth)
{{ tableName }} = await {{ tableName }}_dao.get_{{ tableName }}_by_id(auth.db, {{ tableName }}_id)
if {{ tableName }}:
return {{ tableName }}
else:
raise CustomException(msg='{{ functionName }}不存在')
@classmethod
async def add_{{ tableName }}_service(
cls, auth: AuthSchema, data: {{ tableName|snake_to_pascal_case }}CreateSchema
) -> SuccessResponse:
"""
新增{{ functionName }}service
:param auth: 认证信息
:param data: 新增{{ functionName }}对象
:return: 新增{{ functionName }}结果
"""
# 确保db是AsyncSession类型
if not isinstance(auth.db, AsyncSession):
raise CustomException(msg='数据库会话类型不正确')
{{ tableName }}_dao = {{ tableName|snake_to_pascal_case }}Dao(auth=auth)
try:
data_dict = data.model_dump()
data_dict['create_time'] = datetime.now()
await {{ tableName }}_dao.create(data=data_dict)
if isinstance(auth.db, AsyncSession):
await auth.db.commit()
return SuccessResponse(msg='新增成功')
except Exception as e:
if isinstance(auth.db, AsyncSession):
try:
await auth.db.rollback()
except:
pass # 忽略回滚错误
raise CustomException(msg=f'新增失败: {str(e)}')
@classmethod
async def update_{{ tableName }}_service(cls, auth: AuthSchema, id: int, data: {{ tableName|snake_to_pascal_case }}UpdateSchema) -> SuccessResponse:
"""
编辑{{ functionName }}service
:param auth: 认证信息
:param id: {{ functionName }}ID
:param data: 编辑{{ functionName }}对象
:return: 编辑{{ functionName }}结果
"""
# 确保db是AsyncSession类型
if not isinstance(auth.db, AsyncSession):
raise CustomException(msg='数据库会话类型不正确')
{{ tableName }}_dao = {{ tableName|snake_to_pascal_case }}Dao(auth=auth)
# 检查记录是否存在
{{ tableName }}_info = await cls.get_{{ tableName }}_by_id_service(auth, id)
if {{ tableName }}_info:
try:
data_dict = data.model_dump(exclude_unset=True)
data_dict['update_time'] = datetime.now()
await {{ tableName }}_dao.update(id=id, data=data_dict)
if isinstance(auth.db, AsyncSession):
await auth.db.commit()
return SuccessResponse(msg='更新成功')
except Exception as e:
if isinstance(auth.db, AsyncSession):
try:
await auth.db.rollback()
except:
pass # 忽略回滚错误
raise CustomException(msg=f'更新失败: {str(e)}')
else:
raise CustomException(msg='{{ functionName }}不存在')
@classmethod
async def del_{{ tableName }}_service(cls, auth: AuthSchema, ids: List[int]) -> SuccessResponse:
"""
删除{{ functionName }}service
:param auth: 认证信息
:param ids: {{ functionName }}id列表
:return: 删除{{ functionName }}结果
"""
# 确保db是AsyncSession类型
if not isinstance(auth.db, AsyncSession):
raise CustomException(msg='数据库会话类型不正确')
{{ tableName }}_dao = {{ tableName|snake_to_pascal_case }}Dao(auth=auth)
try:
await {{ tableName }}_dao.delete(ids=ids)
if isinstance(auth.db, AsyncSession):
await auth.db.commit()
return SuccessResponse(msg='删除成功')
except Exception as e:
if isinstance(auth.db, AsyncSession):
try:
await auth.db.rollback()
except:
pass # 忽略回滚错误
raise CustomException(msg=f'删除失败: {str(e)}')
@classmethod
async def export_{{ tableName }}_list_service(cls, {{ tableName }}_list: List[Dict[str, Any]]) -> bytes:
"""
导出{{ functionName }}列表service
:param {{ tableName }}_list: {{ functionName }}列表数据
:return: 导出的Excel文件二进制数据
"""
# 定义字段映射
mapping_dict = {
'id': '编号',
{% for column in columns %}
'{{ column.columnName }}': '{{ column.columnComment }}',
{% endfor %}
'create_by': '创建者',
'create_time': '创建时间',
'update_by': '更新者',
'update_time': '更新时间',
'remark': '备注'
}
# 复制数据并进行必要的转换
data = {{ tableName }}_list.copy()
for item in data:
# 在这里可以添加特定字段的转换逻辑
pass
return ExcelUtil.export_list2excel(list_data=data, mapping_dict=mapping_dict)
@classmethod
async def import_{{ tableName }}_service(cls, auth: AuthSchema, file: UploadFile, update_support: bool = False) -> str:
"""
导入{{ functionName }}service
:param auth: 认证信息
:param file: 上传的Excel文件
:param update_support: 是否支持更新
:return: 导入结果信息
"""
# 定义表头映射
header_dict = {
{% for column in columns %}
'{{ column.columnComment }}': '{{ column.columnName }}',
{% endfor %}
}
try:
# 读取Excel文件
contents = await file.read()
df = pd.read_excel(io.BytesIO(contents))
await file.close()
if df.empty:
raise CustomException(msg="导入文件为空")
# 检查表头是否完整
missing_headers = [header for header in header_dict.keys() if header not in df.columns]
if missing_headers:
raise CustomException(msg=f"导入文件缺少必要的列: {', '.join(missing_headers)}")
# 重命名列名
df.rename(columns=header_dict, inplace=True)
error_msgs = []
success_count = 0
# 处理每一行数据
for index, row in df.iterrows():
try:
# 构建数据对象
data = {}
{% for column in columns %}
data['{{ column.columnName }}'] = row['{{ column.columnName }}']
{% endfor %}
# 处理导入逻辑
# 这里需要根据实际情况调整,比如检查是否已存在相同记录
await {{ tableName|snake_to_pascal_case }}Dao(auth).create(data=data)
success_count += 1
except Exception as e:
error_msgs.append(f"第{index+1}行: {str(e)}")
continue
# 返回详细的导入结果
result = f"成功导入 {success_count} 条数据"
if error_msgs:
result += "\n错误信息:\n" + "\n".join(error_msgs)
return result
except Exception as e:
raise CustomException(msg=f"导入失败: {str(e)}")
@classmethod
async def get_import_template_{{ tableName }}_service(cls) -> bytes:
"""
获取{{ functionName }}导入模板service
:return: Excel模板文件二进制数据
"""
header_list = [
{% for column in columns %}
'{{ column.columnComment }}',
{% endfor %}
]
selector_header_list = [] # 需要下拉选择的列
option_list = [] # 下拉选项配置
return ExcelUtil.get_excel_template(
header_list=header_list,
selector_header_list=selector_header_list,
option_list=option_list
)