对接口进行调整。
This commit is contained in:
parent
038a2df3da
commit
d80555bbad
@ -1,7 +1,10 @@
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import List
|
||||
from app.models.community import CommunityDB, CommunityCreate, CommunityUpdate, CommunityInfo
|
||||
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
|
||||
@ -22,32 +25,51 @@ async def create_community(
|
||||
db.refresh(db_community)
|
||||
return success_response(data=CommunityInfo.model_validate(db_community))
|
||||
|
||||
@router.get("/", response_model=ResponseModel)
|
||||
@router.get("", response_model=ResponseModel)
|
||||
async def get_communities(
|
||||
latitude: float,
|
||||
longitude: float,
|
||||
latitude: Optional[float] = None,
|
||||
longitude: Optional[float] = None,
|
||||
status: Optional[CommunityStatus] = None,
|
||||
skip: int = 0,
|
||||
limit: int = 10,
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""获取社区列表"""
|
||||
communities = db.query(CommunityDB).all()
|
||||
# 构建查询
|
||||
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:
|
||||
# 使用 Haversine 公式计算两点之间的距离
|
||||
distance = calculate_distance(
|
||||
latitude, longitude,
|
||||
community.latitude, community.longitude
|
||||
)
|
||||
|
||||
community_info = CommunityInfo.model_validate(community)
|
||||
community_info.distance = distance
|
||||
|
||||
# 如果提供了经纬度,则计算距离
|
||||
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)
|
||||
|
||||
# 按距离排序
|
||||
community_list.sort(key=lambda x: x.distance)
|
||||
# 如果计算了距离,则按距离排序
|
||||
if latitude is not None and longitude is not None:
|
||||
community_list.sort(key=lambda x: x.distance)
|
||||
|
||||
return success_response(data=community_list)
|
||||
return success_response(data={
|
||||
"total": total,
|
||||
"items": community_list
|
||||
})
|
||||
|
||||
def calculate_distance(lat1: float, lon1: float, lat2: float, lon2: float) -> float:
|
||||
"""计算两点之间的距离(米)"""
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import List
|
||||
from typing import List, Optional
|
||||
from app.models.community_building import (
|
||||
CommunityBuildingDB,
|
||||
CommunityBuildingCreate,
|
||||
@ -14,23 +14,28 @@ from app.core.response import success_response, error_response, ResponseModel
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.get("/list/{community_id}", response_model=ResponseModel)
|
||||
async def get_community_buildings(
|
||||
community_id: int,
|
||||
@router.get("/list", response_model=ResponseModel)
|
||||
async def get_buildings(
|
||||
community_id: Optional[int] = None,
|
||||
skip: int = 0,
|
||||
limit: int = 20,
|
||||
limit: int = 10,
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""获取小区的楼栋列表"""
|
||||
buildings = db.query(CommunityBuildingDB).filter(
|
||||
CommunityBuildingDB.community_id == community_id
|
||||
).order_by(
|
||||
CommunityBuildingDB.building_number
|
||||
).offset(skip).limit(limit).all()
|
||||
"""获取楼栋列表"""
|
||||
query = db.query(CommunityBuildingDB)
|
||||
if community_id:
|
||||
query = query.filter(CommunityBuildingDB.community_id == community_id)
|
||||
|
||||
return success_response(data=[
|
||||
CommunityBuildingInfo.model_validate(b) for b in buildings
|
||||
])
|
||||
# 获取总数
|
||||
total = query.count()
|
||||
|
||||
# 查询数据
|
||||
buildings = query.offset(skip).limit(limit).all()
|
||||
|
||||
return success_response(data={
|
||||
"total": total,
|
||||
"items": [CommunityBuildingInfo.model_validate(b) for b in buildings]
|
||||
})
|
||||
|
||||
@router.post("", response_model=ResponseModel)
|
||||
async def create_building(
|
||||
|
||||
@ -24,9 +24,9 @@ async def create_station(
|
||||
|
||||
@router.get("/", response_model=ResponseModel)
|
||||
async def get_stations(
|
||||
community_id: Optional[int] = None,
|
||||
skip: int = 0,
|
||||
limit: int = 10,
|
||||
community_id: Optional[int] = None,
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""获取驿站列表"""
|
||||
@ -34,8 +34,16 @@ async def get_stations(
|
||||
if community_id:
|
||||
query = query.filter(StationDB.community_id == community_id)
|
||||
|
||||
# 获取总数
|
||||
total = query.count()
|
||||
|
||||
# 查询数据
|
||||
stations = query.offset(skip).limit(limit).all()
|
||||
return success_response(data=[StationInfo.model_validate(s) for s in stations])
|
||||
|
||||
return success_response(data={
|
||||
"total": total,
|
||||
"items": [StationInfo.model_validate(s) for s in stations]
|
||||
})
|
||||
|
||||
@router.get("/{station_id}", response_model=ResponseModel)
|
||||
async def get_station(
|
||||
|
||||
@ -35,6 +35,10 @@ client = UniSMS(settings.UNI_APP_ID)
|
||||
class MockLoginRequest(BaseModel):
|
||||
phone: str = Field(..., pattern="^1[3-9]\d{9}$")
|
||||
|
||||
class ResetPasswordRequest(BaseModel):
|
||||
user_id: int
|
||||
new_password: str = Field(..., min_length=6, max_length=20)
|
||||
|
||||
@router.post("/send-code")
|
||||
async def send_verify_code(request: VerifyCodeRequest):
|
||||
"""发送验证码"""
|
||||
@ -251,7 +255,7 @@ async def update_user_roles(
|
||||
db.rollback()
|
||||
return error_response(code=500, message=f"更新失败: {str(e)}")
|
||||
|
||||
@router.post("/password_login", response_model=ResponseModel)
|
||||
@router.post("/password-login", response_model=ResponseModel)
|
||||
async def password_login(
|
||||
login_data: UserPasswordLogin,
|
||||
db: Session = Depends(get_db)
|
||||
@ -269,11 +273,12 @@ async def password_login(
|
||||
return error_response(code=401, message="密码错误")
|
||||
|
||||
# 生成访问令牌
|
||||
access_token = create_access_token(user.phone)
|
||||
access_token = create_access_token(data={"sub": user.phone})
|
||||
|
||||
return success_response(
|
||||
data={
|
||||
"access_token": f"Bearer {access_token}",
|
||||
"access_token": access_token,
|
||||
"token_type": "bearer",
|
||||
"user": UserInfo.model_validate(user)
|
||||
}
|
||||
)
|
||||
@ -328,4 +333,66 @@ def issue_register_coupons(db: Session, user_id: int):
|
||||
expire_time=expire_time,
|
||||
status="unused"
|
||||
)
|
||||
db.add(user_coupon)
|
||||
db.add(user_coupon)
|
||||
|
||||
@router.get("/list", response_model=ResponseModel)
|
||||
async def get_user_list(
|
||||
skip: int = 0,
|
||||
limit: int = 10,
|
||||
db: Session = Depends(get_db),
|
||||
admin: UserDB = Depends(get_admin_user) # 仅管理员可访问
|
||||
):
|
||||
"""获取用户列表(管理员)
|
||||
Args:
|
||||
skip: 跳过记录数
|
||||
limit: 返回记录数
|
||||
"""
|
||||
total = db.query(UserDB).count()
|
||||
users = db.query(UserDB).order_by(
|
||||
UserDB.create_time.desc()
|
||||
).offset(skip).limit(limit).all()
|
||||
|
||||
# 处理手机号脱敏
|
||||
def mask_phone(phone: str) -> str:
|
||||
return f"{phone[:3]}****{phone[7:]}"
|
||||
|
||||
user_list = []
|
||||
for user in users:
|
||||
user_info = UserInfo.model_validate(user)
|
||||
user_info.phone = mask_phone(user_info.phone) # 手机号脱敏
|
||||
user_list.append(user_info)
|
||||
|
||||
return success_response(data={
|
||||
"total": total,
|
||||
"items": user_list
|
||||
})
|
||||
|
||||
@router.post("/reset-password", response_model=ResponseModel)
|
||||
async def reset_password(
|
||||
request: ResetPasswordRequest,
|
||||
db: Session = Depends(get_db),
|
||||
admin: UserDB = Depends(get_admin_user) # 仅管理员可操作
|
||||
):
|
||||
"""重置用户密码(管理员)"""
|
||||
# 查找用户
|
||||
user = db.query(UserDB).filter(UserDB.userid == request.user_id).first()
|
||||
if not user:
|
||||
return error_response(code=404, message="用户不存在")
|
||||
|
||||
# 重置密码
|
||||
hashed_password = get_password_hash(request.new_password)
|
||||
user.password = hashed_password
|
||||
|
||||
try:
|
||||
db.commit()
|
||||
return success_response(
|
||||
message="密码重置成功",
|
||||
data={
|
||||
"userid": user.userid,
|
||||
"username": user.username,
|
||||
"phone": f"{user.phone[:3]}****{user.phone[7:]}" # 手机号脱敏
|
||||
}
|
||||
)
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
return error_response(code=500, message=f"密码重置失败: {str(e)}")
|
||||
@ -1,9 +1,14 @@
|
||||
from typing import Optional
|
||||
from sqlalchemy import Column, Integer, String, DECIMAL, DateTime
|
||||
import enum
|
||||
from sqlalchemy import Column, Integer, String, DECIMAL, DateTime, Enum
|
||||
from sqlalchemy.sql import func
|
||||
from pydantic import BaseModel, Field
|
||||
from .database import Base
|
||||
|
||||
class CommunityStatus(str, enum.Enum):
|
||||
UNOPEN = "UNOPEN" # 未运营
|
||||
OPENING = "OPENING" # 已运营
|
||||
|
||||
# 数据库模型
|
||||
class CommunityDB(Base):
|
||||
__tablename__ = "communities"
|
||||
@ -13,6 +18,7 @@ class CommunityDB(Base):
|
||||
address = Column(String(200), nullable=False)
|
||||
longitude = Column(DECIMAL(9,6), nullable=False) # 经度,精确到小数点后6位
|
||||
latitude = Column(DECIMAL(9,6), nullable=False) # 纬度,精确到小数点后6位
|
||||
status = Column(Enum(CommunityStatus), nullable=False, default=CommunityStatus.UNOPEN)
|
||||
create_time = Column(DateTime(timezone=True), server_default=func.now())
|
||||
update_time = Column(DateTime(timezone=True), onupdate=func.now())
|
||||
|
||||
@ -22,12 +28,14 @@ class CommunityCreate(BaseModel):
|
||||
address: str = Field(..., max_length=200)
|
||||
longitude: float = Field(..., ge=-180, le=180)
|
||||
latitude: float = Field(..., ge=-90, le=90)
|
||||
status: CommunityStatus = Field(default=CommunityStatus.UNOPEN)
|
||||
|
||||
class CommunityUpdate(BaseModel):
|
||||
name: Optional[str] = Field(None, max_length=100)
|
||||
address: Optional[str] = Field(None, max_length=200)
|
||||
longitude: Optional[float] = Field(None, ge=-180, le=180)
|
||||
latitude: Optional[float] = Field(None, ge=-90, le=90)
|
||||
status: Optional[CommunityStatus] = None
|
||||
|
||||
class CommunityInfo(BaseModel):
|
||||
id: int
|
||||
@ -35,6 +43,7 @@ class CommunityInfo(BaseModel):
|
||||
address: str
|
||||
latitude: float
|
||||
longitude: float
|
||||
status: CommunityStatus
|
||||
distance: Optional[float] = None # 距离,单位:米
|
||||
|
||||
class Config:
|
||||
|
||||
@ -47,11 +47,12 @@ class UserInfo(BaseModel):
|
||||
username: str
|
||||
phone: str
|
||||
user_code: str
|
||||
referral_code: Optional[str]
|
||||
referral_code: Optional[str] = None
|
||||
avatar: Optional[str] = None
|
||||
gender: Gender
|
||||
points: float
|
||||
gender: Gender = Gender.UNKNOWN
|
||||
points: int = 0
|
||||
roles: List[UserRole]
|
||||
create_time: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
@ -10,4 +10,5 @@ redis==5.0.1
|
||||
pymysql==1.1.0
|
||||
SQLAlchemy==2.0.27
|
||||
unisms
|
||||
cos-python-sdk-v5==1.9.25
|
||||
cos-python-sdk-v5==1.9.25
|
||||
bcrypt
|
||||
Loading…
Reference in New Issue
Block a user