from fastapi import APIRouter, Depends from sqlalchemy.orm import Session from typing import List, Optional from app.models.community import ( CommunityDB, CommunityCreate, CommunityUpdate, CommunityInfo, CommunityStatus ) from app.models.database import get_db from app.api.deps import get_admin_user from app.models.user import UserDB from app.core.response import success_response, error_response, ResponseModel router = APIRouter() @router.post("/", response_model=ResponseModel) async def create_community( community: CommunityCreate, db: Session = Depends(get_db), admin: UserDB = Depends(get_admin_user) ): """创建社区""" db_community = CommunityDB(**community.model_dump()) db.add(db_community) db.commit() db.refresh(db_community) return success_response(data=CommunityInfo.model_validate(db_community)) @router.get("", response_model=ResponseModel) async def get_communities( latitude: Optional[float] = None, longitude: Optional[float] = None, status: Optional[CommunityStatus] = None, skip: int = 0, limit: int = 10, db: Session = Depends(get_db) ): """获取社区列表""" # 构建查询 query = db.query(CommunityDB) # 状态过滤 if status: query = query.filter(CommunityDB.status == status) # 获取总数 total = query.count() # 查询数据 communities = query.offset(skip).limit(limit).all() community_list = [] for community in communities: community_info = CommunityInfo.model_validate(community) # 如果提供了经纬度,则计算距离 if latitude is not None and longitude is not None: distance = calculate_distance( latitude, longitude, community.latitude, community.longitude ) community_info.distance = distance community_list.append(community_info) # 如果计算了距离,则按距离排序 if latitude is not None and longitude is not None: community_list.sort(key=lambda x: x.distance) return success_response(data={ "total": total, "items": community_list }) def calculate_distance(lat1: float, lon1: float, lat2: float, lon2: float) -> float: """计算两点之间的距离(米)""" from math import radians, sin, cos, sqrt, atan2 R = 6371000 # 地球半径(米) # 转换为弧度 lat1, lon1, lat2, lon2 = map(radians, [lat1, lon1, lat2, lon2]) # Haversine 公式 dlat = lat2 - lat1 dlon = lon2 - lon1 a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2 c = 2 * atan2(sqrt(a), sqrt(1-a)) distance = R * c return round(distance, 2) # 保留2位小数 @router.get("/{community_id}", response_model=ResponseModel) async def get_community( community_id: int, db: Session = Depends(get_db) ): """获取社区详情""" community = db.query(CommunityDB).filter(CommunityDB.id == community_id).first() if not community: return error_response(code=404, message="社区不存在") return success_response(data=CommunityInfo.model_validate(community)) @router.put("/{community_id}", response_model=ResponseModel) async def update_community( community_id: int, community: CommunityUpdate, db: Session = Depends(get_db), admin: UserDB = Depends(get_admin_user) ): """更新社区信息""" db_community = db.query(CommunityDB).filter(CommunityDB.id == community_id).first() if not db_community: return error_response(code=404, message="社区不存在") update_data = community.model_dump(exclude_unset=True) for key, value in update_data.items(): setattr(db_community, key, value) db.commit() db.refresh(db_community) return success_response(data=CommunityInfo.model_validate(db_community)) @router.delete("/{community_id}", response_model=ResponseModel) async def delete_community( community_id: int, db: Session = Depends(get_db), admin: UserDB = Depends(get_admin_user) ): """删除社区""" result = db.query(CommunityDB).filter(CommunityDB.id == community_id).delete() if not result: return error_response(code=404, message="社区不存在") db.commit() return success_response(message="社区已删除")