refactor(module): 重构模块结构和代码生成模板

- 删除废弃的ticket和version模块相关代码
- 将resource模块从system迁移到monitor
- 移除前端资源管理相关配置
- 重构代码生成模板路径和配置
- 修复CRUD基类初始化参数问题
- 优化模板工具类路径处理
- 更新基础模型字段和配置
This commit is contained in:
zhangtao
2025-09-24 01:39:44 +08:00
parent 4a7533325a
commit d30d2faf6e
59 changed files with 663 additions and 2823 deletions
@@ -1,71 +0,0 @@
# -*- coding: utf-8 -*-
from fastapi import APIRouter, Body, Depends, Path
from fastapi.responses import JSONResponse
from app.common.response import SuccessResponse
from app.common.request import PaginationService
from app.core.router_class import OperationLogRoute
from app.core.base_params import PaginationQueryParam
from app.core.dependencies import AuthPermission
from app.core.logger import logger
from app.api.v1.module_system.auth.schema import AuthSchema
from .param import TicketQueryParam
from .service import TicketService
from .schema import TicketCreateSchema, TicketUpdateSchema
TicketRouter = APIRouter(route_class=OperationLogRoute, prefix="/ticket", tags=["工单管理"])
@TicketRouter.get("/detail/{id}", summary="获取工单详情", description="获取工单详情")
async def get_ticket_detail_controller(
id: int = Path(..., description="工单ID"),
auth: AuthSchema = Depends(AuthPermission(permissions=["system:ticket:query"]))
) -> JSONResponse:
result_dict = await TicketService.get_ticket_detail_service(auth=auth, id=id)
logger.info(f"获取工单详情成功 {id}")
return SuccessResponse(data=result_dict, msg="获取工单详情成功")
@TicketRouter.get("/list", summary="查询工单列表", description="查询工单列表")
async def get_ticket_list_controller(
page: PaginationQueryParam = Depends(),
search: TicketQueryParam = Depends(),
auth: AuthSchema = Depends(AuthPermission(permissions=["system:ticket:query"]))
) -> JSONResponse:
result_dict_list = await TicketService.get_ticket_list_service(auth=auth, search=search, order_by=page.order_by)
result_dict = await PaginationService.paginate(data_list=result_dict_list, page_no=page.page_no, page_size=page.page_size)
logger.info("查询工单列表成功")
return SuccessResponse(data=result_dict, msg="查询工单列表成功")
@TicketRouter.post("/create", summary="创建工单", description="创建工单")
async def create_ticket_controller(
data: TicketCreateSchema,
auth: AuthSchema = Depends(AuthPermission(permissions=["system:ticket:create"]))
) -> JSONResponse:
result_dict = await TicketService.create_ticket_service(auth=auth, data=data)
logger.info(f"创建工单成功: {result_dict}")
return SuccessResponse(data=result_dict, msg="创建工单成功")
@TicketRouter.put("/update/{id}", summary="修改工单", description="修改工单")
async def update_ticket_controller(
data: TicketUpdateSchema,
id: int = Path(..., description="工单ID"),
auth: AuthSchema = Depends(AuthPermission(permissions=["system:ticket:update"]))
) -> JSONResponse:
result_dict = await TicketService.update_ticket_service(auth=auth, id=id, data=data)
logger.info(f"修改工单成功: {result_dict}")
return SuccessResponse(data=result_dict, msg="修改工单成功")
@TicketRouter.delete("/delete", summary="删除工单", description="删除工单")
async def delete_ticket_controller(
ids: list[int] = Body(..., description="ID列表"),
auth: AuthSchema = Depends(AuthPermission(permissions=["system:ticket:delete"]))
) -> JSONResponse:
await TicketService.delete_ticket_service(auth=auth, ids=ids)
logger.info(f"删除工单成功: {ids}")
return SuccessResponse(msg="删除工单成功")
@@ -1,56 +0,0 @@
from typing import Dict, List, Optional, Sequence
from app.core.base_crud import CRUDBase
from app.api.v1.module_system.auth.schema import AuthSchema
from .model import TicketModel
from .schema import TicketCreateSchema, TicketUpdateSchema
class TicketCRUD(CRUDBase[TicketModel, TicketCreateSchema, TicketUpdateSchema]):
"""工单 CRUD 操作"""
def __init__(self, auth: AuthSchema) -> None:
"""初始化工单CRUD"""
self.auth = auth
super().__init__(model=TicketModel, auth=auth)
async def get_by_id_crud(self, id: int) -> Optional[TicketModel]:
"""根据id获取工单信息
:param id: 工单ID
:return: 工单信息
"""
return await self.get(id=id)
async def get_list_crud(self, search: Optional[Dict] = None, order_by: Optional[List[Dict[str, str]]] = None) -> Sequence[TicketModel]:
"""获取工单列表
:param search: 搜索条件
:param order_by: 排序字段
:return: 工单列表
"""
return await self.list(search=search or {}, order_by=order_by or [])
async def create_crud(self, data: TicketCreateSchema) -> Optional[TicketModel]:
"""创建工单
:param data: 工单创建数据
:return: 创建的工单
"""
return await self.create(data=data)
async def update_crud(self, id: int, data: TicketUpdateSchema) -> Optional[TicketModel]:
"""更新工单
:param id: 工单ID
:param data: 工单更新数据
:return: 更新的工单
"""
return await self.update(id=id, data=data)
async def delete_crud(self, ids: List[int]) -> None:
"""批量删除工单
:param ids: 工单ID列表
"""
return await self.delete(ids=ids)
@@ -1,30 +0,0 @@
# -*- coding: utf-8 -*-
from typing import Optional
from sqlalchemy import String, Text, DateTime, ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship
from datetime import datetime
from app.core.base_model import CreatorMixin
class TicketModel(CreatorMixin):
"""
工单模型 - SQLAlchemy 2.0 语法
兼容 MySQL 和 PostgreSQL
"""
__tablename__ = 'system_ticket'
__table_args__ = ({'comment': '工单表'})
title: Mapped[str] = mapped_column(String(255), nullable=False, comment='工单标题')
status: Mapped[str] = mapped_column(String(50), default='pending', comment='工单状态(pending:待处理 progress:处理中 resolved:已解决 closed:已关闭)')
priority: Mapped[str] = mapped_column(String(50), default='medium', comment='优先级(low:低, medium:中, high:高, urgent:紧急)')
type: Mapped[Optional[str]] = mapped_column(String(50), comment='工单类型(bug:缺陷, feature:功能, task:任务)')
assignee_id: Mapped[Optional[int]] = mapped_column(ForeignKey('system_users.id'), comment='指派给用户ID')
reporter_id: Mapped[Optional[int]] = mapped_column(ForeignKey('system_users.id'), comment='报告人ID')
project: Mapped[Optional[str]] = mapped_column(String(100), comment='所属项目或模块')
version: Mapped[Optional[str]] = mapped_column(String(50), comment='版本号')
# 关系
assignee = relationship('UserModel', foreign_keys=[assignee_id])
reporter = relationship('UserModel', foreign_keys=[reporter_id])
@@ -1,36 +0,0 @@
# -*- coding: utf-8 -*-
from datetime import datetime
from typing import Optional
from fastapi import Query
from app.core.validator import DateTimeStr
class TicketQueryParam:
"""工单管理查询参数"""
def __init__(
self,
title: Optional[str] = Query(None, description="工单标题"),
status: Optional[bool] = Query(None, description="工单状态"),
priority: Optional[str] = Query(None, description="优先级"),
creator: Optional[int] = Query(None, description="创建人"),
start_time: Optional[DateTimeStr] = Query(None, description="开始时间", example="2023-01-01 00:00:00"),
end_time: Optional[DateTimeStr] = Query(None, description="结束时间", example="2023-12-31 23:59:59"),
) -> None:
super().__init__()
# 模糊查询字段
self.title = ("like", title)
# 精确查询字段
self.creator_id = creator
self.status = status
self.priority = priority
# 时间范围查询
if start_time and end_time:
start_datetime = datetime.strptime(str(start_time), '%Y-%m-%d %H:%M:%S')
end_datetime = datetime.strptime(str(end_time), '%Y-%m-%d %H:%M:%S')
self.created_at = ("between", (start_datetime, end_datetime))
@@ -1,31 +0,0 @@
# -*- coding: utf-8 -*-
from typing import Optional
from pydantic import BaseModel, ConfigDict, Field
from datetime import datetime
from app.core.base_schema import BaseSchema
class TicketCreateSchema(BaseModel):
"""创建工单"""
title: str = Field(..., max_length=255, description='工单标题')
description: Optional[str] = Field(default=None, description='工单描述')
status: Optional[str] = Field(default='pending', description='工单处理状态(pending:待处理 progress:处理中 resolved:已解决 closed:已关闭)')
priority: Optional[str] = Field(default='medium', description='优先级(low, medium, high, urgent)')
type: Optional[str] = Field(default='bug', description='工单类型(bug, feature, task)')
assignee_id: Optional[int] = Field(default=None, description='指派给用户ID')
reporter_id: int = Field(..., description='报告人ID')
project: Optional[str] = Field(default=None, max_length=100, description='所属项目')
version: Optional[str] = Field(default=None, max_length=50, description='版本号')
class TicketUpdateSchema(TicketCreateSchema):
"""更新工单"""
...
class TicketOutSchema(TicketCreateSchema, BaseSchema):
"""工单输出"""
model_config = ConfigDict(from_attributes=True)
...
@@ -1,60 +0,0 @@
# -*- coding: utf-8 -*-
from typing import Dict, List, Optional, Union
from app.api.v1.module_system.auth.schema import AuthSchema
from app.core.exceptions import CustomException
from .crud import TicketCRUD
from .schema import TicketCreateSchema, TicketUpdateSchema, TicketOutSchema
from .param import TicketQueryParam
class TicketService:
"""工单模块服务层"""
@classmethod
async def get_ticket_detail_service(cls, auth: AuthSchema, id: int) -> Dict:
"""获取工单详情"""
obj = await TicketCRUD(auth).get_by_id_crud(id=id)
return TicketOutSchema.model_validate(obj).model_dump()
@classmethod
async def get_ticket_list_service(cls, auth: AuthSchema, search: Optional[TicketQueryParam] = None, order_by: Optional[Union[str, List[Dict[str, str]]]] = None) -> List[Dict]:
"""获取工单列表"""
# 处理排序参数
processed_order_by = None
if order_by:
if isinstance(order_by, str):
processed_order_by = eval(order_by)
else:
processed_order_by = order_by
obj_list = await TicketCRUD(auth).get_list_crud(search=search.__dict__ if search else None, order_by=processed_order_by)
return [TicketOutSchema.model_validate(obj).model_dump() for obj in obj_list]
@classmethod
async def create_ticket_service(cls, auth: AuthSchema, data: TicketCreateSchema) -> Dict:
"""创建工单"""
obj = await TicketCRUD(auth).create_crud(data=data)
return TicketOutSchema.model_validate(obj).model_dump()
@classmethod
async def update_ticket_service(cls, auth: AuthSchema, id: int, data: TicketUpdateSchema) -> Dict:
"""更新工单"""
# 检查工单是否存在
obj = await TicketCRUD(auth).get_by_id_crud(id=id)
if not obj:
raise CustomException(msg='更新失败,该工单不存在')
obj = await TicketCRUD(auth).update_crud(id=id, data=data)
return TicketOutSchema.model_validate(obj).model_dump()
@classmethod
async def delete_ticket_service(cls, auth: AuthSchema, ids: List[int]) -> None:
"""删除工单"""
if len(ids) < 1:
raise CustomException(msg='删除失败,删除对象不能为空')
for id in ids:
obj = await TicketCRUD(auth).get_by_id_crud(id=id)
if not obj:
raise CustomException(msg='删除失败,该工单不存在')
await TicketCRUD(auth).delete_crud(ids=ids)