""" Review Card Repository 审核卡片持久化仓储 - JSON文件存储 """ from pathlib import Path from typing import List, Optional import json import uuid from datetime import datetime from app.models.review_card import ( ReviewCard, ReviewCardCreate, ReviewCardUpdate, ReviewCardStatus ) from app.utils.logger import get_logger logger = get_logger(__name__) # 数据文件路径 DATA_DIR = Path(__file__).parent.parent.parent / "data" REVIEW_CARDS_FILE = DATA_DIR / "review_cards.json" class ReviewCardRepository: """审核卡片仓储 - JSON文件持久化""" def __init__(self): self.file_path = REVIEW_CARDS_FILE self._cards: Dict[str, ReviewCard] = {} self._ensure_data_dir() self._load() def _ensure_data_dir(self): """确保数据目录存在""" self.file_path.parent.mkdir(parents=True, exist_ok=True) def _load(self): """从文件加载""" if self.file_path.exists(): try: content = self.file_path.read_text(encoding="utf-8") if content.strip(): data = json.loads(content) for card_id, card_data in data.items(): # 确保created_at和updated_at是datetime对象 if isinstance(card_data.get("created_at"), str): card_data["created_at"] = datetime.fromisoformat( card_data["created_at"].replace('Z', '+00:00') ) if isinstance(card_data.get("updated_at"), str): card_data["updated_at"] = datetime.fromisoformat( card_data["updated_at"].replace('Z', '+00:00') ) if isinstance(card_data.get("completed_at"), str): card_data["completed_at"] = datetime.fromisoformat( card_data["completed_at"].replace('Z', '+00:00') ) self._cards[card_id] = ReviewCard(**card_data) except Exception as e: logger.error(f"加载审核卡片失败: {e}") self._cards = {} def _save(self): """保存到文件""" try: data = {} for card_id, card in self._cards.items(): card_dict = card.dict() # 确保datetime正确序列化 if isinstance(card_dict.get("created_at"), datetime): card_dict["created_at"] = card_dict["created_at"].isoformat() if isinstance(card_dict.get("updated_at"), datetime): card_dict["updated_at"] = card_dict["updated_at"].isoformat() if isinstance(card_dict.get("completed_at"), datetime): card_dict["completed_at"] = card_dict["completed_at"].isoformat() data[card_id] = card_dict self.file_path.write_text( json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8" ) except Exception as e: logger.error(f"保存审核卡片失败: {e}") raise async def create(self, data: ReviewCardCreate) -> ReviewCard: """创建审核卡片""" card_id = str(uuid.uuid4()) card = ReviewCard( id=card_id, **data.dict(), created_at=datetime.now(), updated_at=datetime.now() ) self._cards[card_id] = card self._save() logger.info(f"创建审核卡片: {card_id}") return card async def get(self, card_id: str) -> Optional[ReviewCard]: """获取单个卡片""" return self._cards.get(card_id) async def list_by_project( self, project_id: str, status: Optional[ReviewCardStatus] = None, limit: int = 100 ) -> List[ReviewCard]: """列出项目的审核卡片""" cards = [ card for card in self._cards.values() if card.project_id == project_id ] if status: cards = [c for c in cards if c.status == status] # 按创建时间倒序 cards = sorted(cards, key=lambda c: c.created_at, reverse=True) return cards[:limit] async def update(self, card_id: str, data: ReviewCardUpdate) -> Optional[ReviewCard]: """更新审核卡片""" card = self._cards.get(card_id) if not card: return None # 更新字段 update_data = data.dict(exclude_unset=True, exclude_none=True) for field, value in update_data.items(): setattr(card, field, value) card.updated_at = datetime.now() if data.status == ReviewCardStatus.COMPLETED: card.completed_at = datetime.now() self._cards[card_id] = card self._save() logger.info(f"更新审核卡片: {card_id}") return card async def delete(self, card_id: str) -> bool: """删除审核卡片""" if card_id in self._cards: del self._cards[card_id] self._save() return True return False async def count_by_project(self, project_id: str) -> int: """统计项目的审核卡片数量""" return sum(1 for card in self._cards.values() if card.project_id == project_id) async def count_by_status(self, project_id: str, status: ReviewCardStatus) -> int: """统计项目特定状态的审核卡片数量""" return sum( 1 for card in self._cards.values() if card.project_id == project_id and card.status == status ) # 全局单例 _review_card_repo = None def get_review_card_repo() -> ReviewCardRepository: """获取审核卡片仓储单例""" global _review_card_repo if _review_card_repo is None: _review_card_repo = ReviewCardRepository() return _review_card_repo # 导入Dict类型 from typing import Dict