186 lines
5.5 KiB
Python
186 lines
5.5 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
DictItem Service - 字典项服务层
|
|
"""
|
|
from io import BytesIO
|
|
from typing import Tuple, Dict, Any, Optional, List
|
|
|
|
from sqlalchemy import select, or_
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.base_service import BaseService
|
|
from core.dict_item.model import DictItem
|
|
from core.dict_item.schema import DictItemCreate, DictItemUpdate
|
|
|
|
|
|
class DictItemService(BaseService[DictItem, DictItemCreate, DictItemUpdate]):
|
|
"""
|
|
字典项服务层
|
|
继承BaseService,自动获得增删改查功能
|
|
"""
|
|
|
|
model = DictItem
|
|
|
|
# Excel导入导出配置
|
|
excel_columns = {
|
|
"label": "显示名称",
|
|
"value": "实际值",
|
|
"icon": "图标",
|
|
"status": "状态",
|
|
"remark": "备注",
|
|
}
|
|
excel_sheet_name = "字典项列表"
|
|
|
|
@classmethod
|
|
def _export_converter(cls, item: Any) -> Dict[str, Any]:
|
|
"""导出数据转换器"""
|
|
return {
|
|
"label": item.label or "",
|
|
"value": item.value or "",
|
|
"icon": item.icon or "",
|
|
"status": "启用" if item.status else "禁用",
|
|
"remark": item.remark or "",
|
|
}
|
|
|
|
@classmethod
|
|
def _import_processor(cls, row: Dict[str, Any]) -> Optional[DictItem]:
|
|
"""导入数据处理器"""
|
|
label = row.get("label")
|
|
value = row.get("value")
|
|
if not label and not value:
|
|
return None
|
|
|
|
status_str = row.get("status", "启用")
|
|
status = status_str in ("启用", "true", "True", "1", True)
|
|
|
|
return DictItem(
|
|
label=str(label) if label else None,
|
|
value=str(value) if value else None,
|
|
icon=str(row.get("icon") or "") if row.get("icon") else None,
|
|
status=status,
|
|
remark=str(row.get("remark") or "") if row.get("remark") else None,
|
|
)
|
|
|
|
@classmethod
|
|
async def export_to_excel(
|
|
cls,
|
|
db: AsyncSession,
|
|
data_converter: Any = None
|
|
) -> BytesIO:
|
|
"""导出到Excel"""
|
|
return await super().export_to_excel(db, cls._export_converter)
|
|
|
|
@classmethod
|
|
async def import_from_excel(
|
|
cls,
|
|
db: AsyncSession,
|
|
file_content: bytes,
|
|
row_processor: Any = None
|
|
) -> Tuple[int, int]:
|
|
"""从Excel导入"""
|
|
return await super().import_from_excel(db, file_content, cls._import_processor)
|
|
|
|
@classmethod
|
|
async def get_by_dict_id(cls, db: AsyncSession, dict_id: str) -> List[DictItem]:
|
|
"""根据字典ID获取字典项列表"""
|
|
result = await db.execute(
|
|
select(DictItem).where(
|
|
DictItem.dict_id == dict_id,
|
|
DictItem.is_deleted == False # noqa: E712
|
|
).order_by(DictItem.sort)
|
|
)
|
|
return list(result.scalars().all())
|
|
|
|
@classmethod
|
|
async def get_by_dict_code(cls, db: AsyncSession, dict_code: str) -> List[DictItem]:
|
|
"""根据字典编码获取字典项列表"""
|
|
from core.dict.model import Dict as DictModel
|
|
|
|
# 先获取字典
|
|
dict_result = await db.execute(
|
|
select(DictModel).where(
|
|
DictModel.code == dict_code,
|
|
DictModel.is_deleted == False # noqa: E712
|
|
)
|
|
)
|
|
dict_obj = dict_result.scalar_one_or_none()
|
|
|
|
if not dict_obj:
|
|
return []
|
|
|
|
# 获取字典项
|
|
return await cls.get_by_dict_id(db, dict_obj.id)
|
|
|
|
@classmethod
|
|
async def get_all_active(cls, db: AsyncSession) -> List[DictItem]:
|
|
"""获取所有启用的字典项"""
|
|
result = await db.execute(
|
|
select(DictItem).where(
|
|
DictItem.status == True, # noqa: E712
|
|
DictItem.is_deleted == False # noqa: E712
|
|
).order_by(DictItem.sort)
|
|
)
|
|
return list(result.scalars().all())
|
|
|
|
@classmethod
|
|
async def search(
|
|
cls,
|
|
db: AsyncSession,
|
|
keyword: str,
|
|
page: int = 1,
|
|
page_size: int = 20
|
|
) -> Tuple[List[DictItem], int]:
|
|
"""搜索字典项"""
|
|
filters = [
|
|
or_(
|
|
DictItem.label.ilike(f"%{keyword}%"),
|
|
DictItem.value.ilike(f"%{keyword}%"),
|
|
)
|
|
]
|
|
return await cls.get_list(db, page=page, page_size=page_size, filters=filters)
|
|
|
|
@classmethod
|
|
async def batch_delete(
|
|
cls,
|
|
db: AsyncSession,
|
|
ids: List[str],
|
|
hard: bool = False
|
|
) -> Tuple[int, List[str]]:
|
|
"""
|
|
批量删除字典项
|
|
|
|
:return: (成功数量, 失败的ID列表)
|
|
"""
|
|
success_count = 0
|
|
failed_ids = []
|
|
|
|
for item_id in ids:
|
|
try:
|
|
success = await cls.delete(db, record_id=item_id, hard=hard)
|
|
if success:
|
|
success_count += 1
|
|
else:
|
|
failed_ids.append(item_id)
|
|
except Exception:
|
|
failed_ids.append(item_id)
|
|
|
|
return success_count, failed_ids
|
|
|
|
@classmethod
|
|
async def batch_update_status(
|
|
cls,
|
|
db: AsyncSession,
|
|
ids: List[str],
|
|
status: bool
|
|
) -> int:
|
|
"""批量更新字典项状态"""
|
|
count = 0
|
|
for item_id in ids:
|
|
item = await cls.get_by_id(db, item_id)
|
|
if item:
|
|
item.status = status
|
|
await db.commit()
|
|
count += 1
|
|
return count
|