v0.1.0 - 认购功能完善版
This commit is contained in:
parent
ee728a5f4e
commit
1fef5177f3
|
|
@ -1,8 +1,8 @@
|
||||||
# purchase - 认购群模型
|
# purchase - 认购群模型
|
||||||
# Version: 0.0.1 (2026-04-24)
|
# Version: 0.0.2 (2026-04-29)
|
||||||
# 认购群、成员、藏品管理
|
# 认购群、成员、藏品管理
|
||||||
|
|
||||||
from sqlalchemy import Column, String, Text, Integer, DECIMAL, DateTime, ForeignKey
|
from sqlalchemy import Column, String, Text, Integer, DECIMAL, DateTime, ForeignKey, Boolean
|
||||||
from sqlalchemy.sql import func
|
from sqlalchemy.sql import func
|
||||||
from app.core.database import Base
|
from app.core.database import Base
|
||||||
import uuid
|
import uuid
|
||||||
|
|
@ -15,14 +15,19 @@ class PurchaseGroup(Base):
|
||||||
__tablename__ = "purchase_group"
|
__tablename__ = "purchase_group"
|
||||||
|
|
||||||
id = Column(String(36), primary_key=True, default=generate_uuid)
|
id = Column(String(36), primary_key=True, default=generate_uuid)
|
||||||
|
group_code = Column(String(20), nullable=False, unique=True) # 年+序号,如 26001
|
||||||
name = Column(String(100), nullable=False) # 认购群名称
|
name = Column(String(100), nullable=False) # 认购群名称
|
||||||
description = Column(Text, nullable=True) # 描述
|
description = Column(Text, nullable=True) # 描述
|
||||||
creator_id = Column(String(36), nullable=False) # 创建者ID
|
creator_id = Column(String(36), nullable=False) # 创建者ID
|
||||||
creator_name = Column(String(50), nullable=True) # 创建者名字
|
creator_name = Column(String(50), nullable=True) # 创建者名字
|
||||||
status = Column(String(20), default="active") # active/closed
|
status = Column(String(20), default="active") # active/closed
|
||||||
total_members = Column(Integer, default=0) # 总参与人数
|
total_members = Column(Integer, default=0) # 总参与人数
|
||||||
|
total_pending = Column(Integer, default=0) # 待审批人数
|
||||||
total_collections = Column(Integer, default=0) # 总藏品数
|
total_collections = Column(Integer, default=0) # 总藏品数
|
||||||
|
total_confirmed = Column(Integer, default=0) # 已确认数
|
||||||
total_amount = Column(DECIMAL(12,2), default=0) # 总金额
|
total_amount = Column(DECIMAL(12,2), default=0) # 总金额
|
||||||
|
cycle_months = Column(Integer, nullable=True) # 认购周期(月)
|
||||||
|
start_date = Column(DateTime(timezone=True), nullable=True) # 开始日期
|
||||||
avg_price = Column(DECIMAL(10,2), default=0) # 均价
|
avg_price = Column(DECIMAL(10,2), default=0) # 均价
|
||||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||||
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
||||||
|
|
@ -37,6 +42,13 @@ class PurchaseMember(Base):
|
||||||
user_name = Column(String(50), nullable=True)
|
user_name = Column(String(50), nullable=True)
|
||||||
user_avatar = Column(String(255), nullable=True)
|
user_avatar = Column(String(255), nullable=True)
|
||||||
role = Column(String(20), default="member") # creator/admin/member
|
role = Column(String(20), default="member") # creator/admin/member
|
||||||
|
status = Column(String(20), default="pending") # pending/approved/rejected
|
||||||
|
# 成员扩展信息
|
||||||
|
wechat_name = Column(String(50), nullable=True) # 微信名
|
||||||
|
contact = Column(String(50), nullable=True) # 联系方式
|
||||||
|
purchase_count = Column(Integer, default=0) # 认购数量
|
||||||
|
paid_amount = Column(DECIMAL(12,2), default=0) # 已付认购款
|
||||||
|
notes = Column(Text, nullable=True) # 备注
|
||||||
joined_at = Column(DateTime(timezone=True), server_default=func.now())
|
joined_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||||
|
|
||||||
class PurchaseCollection(Base):
|
class PurchaseCollection(Base):
|
||||||
|
|
@ -48,8 +60,13 @@ class PurchaseCollection(Base):
|
||||||
user_id = Column(String(36), nullable=False)
|
user_id = Column(String(36), nullable=False)
|
||||||
user_name = Column(String(50), nullable=True)
|
user_name = Column(String(50), nullable=True)
|
||||||
collection_name = Column(String(100), nullable=True) # 藏品名称
|
collection_name = Column(String(100), nullable=True) # 藏品名称
|
||||||
collection_code = Column(String(50), nullable=True) # 藏品编号
|
collection_code = Column(String(50), nullable=True) # 藏品编号 (自动生成001开始)
|
||||||
number = Column(String(50), nullable=True) # 冠字号
|
number = Column(String(50), nullable=False) # 冠字号 (必填)
|
||||||
price = Column(DECIMAL(10,2), nullable=False) # 认购价格
|
grading = Column(String(50), nullable=False) # 评级 (必填)
|
||||||
|
boss_name = Column(String(50), nullable=False) # 认购老板 (必填,从成员中选择)
|
||||||
|
price = Column(DECIMAL(10,2), nullable=False) # 认购价格 (必填)
|
||||||
|
source = Column(String(20), nullable=False) # 来源: yichen/live/friend/other (必填)
|
||||||
|
paid = Column(Boolean, default=False) # 认购款是否结清
|
||||||
|
submit_date = Column(DateTime(timezone=True), server_default=func.now()) # 提交日期
|
||||||
status = Column(String(20), default="pending") # pending/confirmed
|
status = Column(String(20), default="pending") # pending/confirmed
|
||||||
submitted_at = Column(DateTime(timezone=True), server_default=func.now())
|
submitted_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# purchase - 认购群API路由
|
# purchase - 认购群API路由
|
||||||
# Version: 0.0.1 (2026-04-24)
|
# Version: 0.0.5 (2026-04-29)
|
||||||
# 认购群、成员、藏品管理
|
# 认购群、成员、藏品管理
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||||
|
|
@ -16,27 +16,92 @@ router = APIRouter(prefix="/api/purchase", tags=["认购"])
|
||||||
|
|
||||||
# ============ Schema ============
|
# ============ Schema ============
|
||||||
class PurchaseGroupCreate(BaseModel):
|
class PurchaseGroupCreate(BaseModel):
|
||||||
|
cycle_months: Optional[int] = None
|
||||||
|
start_date: Optional[str] = None
|
||||||
name: str
|
name: str
|
||||||
description: Optional[str] = None
|
description: Optional[str] = None
|
||||||
|
|
||||||
class PurchaseGroupResponse(BaseModel):
|
class PurchaseGroupResponse(BaseModel):
|
||||||
|
cycle_months: Optional[int] = None
|
||||||
|
start_date: Optional[datetime] = None
|
||||||
id: str
|
id: str
|
||||||
|
group_code: str
|
||||||
name: str
|
name: str
|
||||||
description: Optional[str]
|
description: Optional[str]
|
||||||
creator_id: str
|
creator_id: str
|
||||||
creator_name: Optional[str]
|
creator_name: Optional[str]
|
||||||
status: str
|
status: str
|
||||||
total_members: int
|
total_members: int
|
||||||
|
total_pending: int
|
||||||
total_collections: int
|
total_collections: int
|
||||||
|
total_confirmed: int
|
||||||
total_amount: float
|
total_amount: float
|
||||||
avg_price: float
|
avg_price: float
|
||||||
created_at: Optional[datetime]
|
created_at: Optional[datetime]
|
||||||
|
|
||||||
class PurchaseCollectionCreate(BaseModel):
|
class PurchaseCollectionCreate(BaseModel):
|
||||||
collection_name: str
|
collection_name: str
|
||||||
collection_code: Optional[str] = None
|
number: str
|
||||||
number: Optional[str] = None
|
grading: str
|
||||||
|
boss_name: str
|
||||||
price: float
|
price: float
|
||||||
|
source: str
|
||||||
|
paid: bool = False
|
||||||
|
|
||||||
|
class PurchaseCollectionUpdate(BaseModel):
|
||||||
|
collection_name: Optional[str] = None
|
||||||
|
number: Optional[str] = None
|
||||||
|
grading: Optional[str] = None
|
||||||
|
boss_name: Optional[str] = None
|
||||||
|
price: Optional[float] = None
|
||||||
|
source: Optional[str] = None
|
||||||
|
paid: Optional[bool] = None
|
||||||
|
status: Optional[str] = None
|
||||||
|
|
||||||
|
class PurchaseCollectionResponse(BaseModel):
|
||||||
|
id: str
|
||||||
|
group_id: str
|
||||||
|
user_id: str
|
||||||
|
user_name: Optional[str]
|
||||||
|
collection_name: Optional[str]
|
||||||
|
collection_code: Optional[str]
|
||||||
|
number: str
|
||||||
|
grading: str
|
||||||
|
boss_name: str
|
||||||
|
price: float
|
||||||
|
source: str
|
||||||
|
paid: bool
|
||||||
|
status: str
|
||||||
|
submit_date: Optional[datetime]
|
||||||
|
submitted_at: Optional[datetime]
|
||||||
|
|
||||||
|
class MemberResponse(BaseModel):
|
||||||
|
id: str
|
||||||
|
user_id: str
|
||||||
|
user_name: Optional[str]
|
||||||
|
user_avatar: Optional[str]
|
||||||
|
role: str
|
||||||
|
status: str
|
||||||
|
joined_at: Optional[datetime]
|
||||||
|
|
||||||
|
# ============ 工具函数 ============
|
||||||
|
def generate_group_code(db: Session) -> str:
|
||||||
|
"""生成群编码:年+序号,如 26001"""
|
||||||
|
year = datetime.now().year % 100 # 26
|
||||||
|
# 查找当前年份最大的编号
|
||||||
|
last = db.query(PurchaseGroup).filter(
|
||||||
|
PurchaseGroup.group_code.like(f"{year}%")
|
||||||
|
).order_by(PurchaseGroup.group_code.desc()).first()
|
||||||
|
|
||||||
|
if last and last.group_code:
|
||||||
|
try:
|
||||||
|
num = int(last.group_code) + 1
|
||||||
|
except:
|
||||||
|
num = 1
|
||||||
|
else:
|
||||||
|
num = 1
|
||||||
|
|
||||||
|
return f"{year}{num:03d}" # 26001
|
||||||
|
|
||||||
# ============ 认购群API ============
|
# ============ 认购群API ============
|
||||||
|
|
||||||
|
|
@ -59,7 +124,8 @@ def get_my_groups(
|
||||||
):
|
):
|
||||||
"""获取我参与的认购群"""
|
"""获取我参与的认购群"""
|
||||||
member_groups = db.query(PurchaseMember).filter(
|
member_groups = db.query(PurchaseMember).filter(
|
||||||
PurchaseMember.user_id == current_user.f99_90_id
|
PurchaseMember.user_id == current_user.f99_90_id,
|
||||||
|
PurchaseMember.status == "approved"
|
||||||
).all()
|
).all()
|
||||||
|
|
||||||
group_ids = [m.group_id for m in member_groups]
|
group_ids = [m.group_id for m in member_groups]
|
||||||
|
|
@ -69,45 +135,123 @@ def get_my_groups(
|
||||||
|
|
||||||
return groups
|
return groups
|
||||||
|
|
||||||
|
@router.get("/groups/{group_id}/pending-members", response_model=List[MemberResponse])
|
||||||
|
def get_pending_members(
|
||||||
|
group_id: str,
|
||||||
|
current_user = Depends(get_current_user),
|
||||||
|
db: Session = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""获取待审批成员列表"""
|
||||||
|
group = db.query(PurchaseGroup).filter(PurchaseGroup.id == group_id).first()
|
||||||
|
if not group:
|
||||||
|
raise HTTPException(status_code=404, detail="认购群不存在")
|
||||||
|
|
||||||
|
if group.creator_id != current_user.f99_90_id:
|
||||||
|
raise HTTPException(status_code=403, detail="只有群主可以查看")
|
||||||
|
|
||||||
|
members = db.query(PurchaseMember).filter(
|
||||||
|
PurchaseMember.group_id == group_id,
|
||||||
|
PurchaseMember.status == "pending"
|
||||||
|
).order_by(PurchaseMember.joined_at.asc()).all()
|
||||||
|
|
||||||
|
return members
|
||||||
|
|
||||||
|
@router.post("/groups/{group_id}/members/{member_id}/approve")
|
||||||
|
def approve_member(
|
||||||
|
group_id: str,
|
||||||
|
member_id: str,
|
||||||
|
action: str = Query(..., description="approve/reject"),
|
||||||
|
current_user = Depends(get_current_user),
|
||||||
|
db: Session = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""审批或拒绝成员"""
|
||||||
|
group = db.query(PurchaseGroup).filter(PurchaseGroup.id == group_id).first()
|
||||||
|
if not group:
|
||||||
|
raise HTTPException(status_code=404, detail="认购群不存在")
|
||||||
|
|
||||||
|
if group.creator_id != current_user.f99_90_id:
|
||||||
|
raise HTTPException(status_code=403, detail="只有群主可以审批")
|
||||||
|
|
||||||
|
member = db.query(PurchaseMember).filter(
|
||||||
|
PurchaseMember.id == member_id,
|
||||||
|
PurchaseMember.group_id == group_id
|
||||||
|
).first()
|
||||||
|
|
||||||
|
if not member:
|
||||||
|
raise HTTPException(status_code=404, detail="成员不存在")
|
||||||
|
|
||||||
|
if action == "approve":
|
||||||
|
member.status = "approved"
|
||||||
|
group.total_members += 1
|
||||||
|
group.total_pending -= 1
|
||||||
|
db.commit()
|
||||||
|
return {"message": "已批准加入"}
|
||||||
|
elif action == "reject":
|
||||||
|
member.status = "rejected"
|
||||||
|
group.total_pending -= 1
|
||||||
|
db.commit()
|
||||||
|
return {"message": "已拒绝加入"}
|
||||||
|
else:
|
||||||
|
raise HTTPException(status_code=400, detail="无效操作")
|
||||||
|
|
||||||
@router.post("/groups", response_model=PurchaseGroupResponse)
|
@router.post("/groups", response_model=PurchaseGroupResponse)
|
||||||
def create_group(
|
def create_group(
|
||||||
data: PurchaseGroupCreate,
|
data: PurchaseGroupCreate,
|
||||||
current_user = Depends(get_current_user),
|
current_user = Depends(get_current_user),
|
||||||
db: Session = Depends(get_db)
|
db: Session = Depends(get_db)
|
||||||
):
|
):
|
||||||
"""创建认购群(创建者即为群主)"""
|
"""创建认购群"""
|
||||||
if not current_user:
|
if not current_user:
|
||||||
raise HTTPException(status_code=401, detail="请先登录")
|
raise HTTPException(status_code=401, detail="请先登录")
|
||||||
|
|
||||||
|
# 普通用户最多创建3个认购群
|
||||||
|
if current_user.role not in ["admin", "superadmin"]:
|
||||||
|
existing_count = db.query(PurchaseGroup).filter(
|
||||||
|
PurchaseGroup.creator_id == current_user.f99_90_id
|
||||||
|
).count()
|
||||||
|
if existing_count >= 3:
|
||||||
|
raise HTTPException(status_code=400, detail="普通用户最多创建3个认购群")
|
||||||
|
|
||||||
|
group_code = generate_group_code(db)
|
||||||
|
|
||||||
|
# 处理日期
|
||||||
|
start_date = None
|
||||||
|
if data.start_date:
|
||||||
|
try:
|
||||||
|
start_date = datetime.fromisoformat(data.start_date.replace('Z', '+08:00'))
|
||||||
|
except:
|
||||||
|
start_date = datetime.now()
|
||||||
|
|
||||||
group = PurchaseGroup(
|
group = PurchaseGroup(
|
||||||
|
group_code=group_code,
|
||||||
name=data.name,
|
name=data.name,
|
||||||
description=data.description,
|
description=data.description,
|
||||||
creator_id=current_user.f99_90_id,
|
creator_id=current_user.f99_90_id,
|
||||||
creator_name=current_user.f01_01_name,
|
creator_name=current_user.f01_01_name,
|
||||||
status="active"
|
status="active",
|
||||||
|
cycle_months=data.cycle_months,
|
||||||
|
start_date=start_date
|
||||||
)
|
)
|
||||||
db.add(group)
|
db.add(group)
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
# 创建者自动加入并成为群主
|
|
||||||
member = PurchaseMember(
|
member = PurchaseMember(
|
||||||
group_id=group.id,
|
group_id=group.id,
|
||||||
user_id=current_user.f99_90_id,
|
user_id=current_user.f99_90_id,
|
||||||
user_name=current_user.f01_01_name,
|
user_name=current_user.f01_01_name,
|
||||||
user_avatar=current_user.avatar,
|
user_avatar=current_user.avatar,
|
||||||
role="creator"
|
role="creator",
|
||||||
|
status="approved"
|
||||||
)
|
)
|
||||||
db.add(member)
|
db.add(member)
|
||||||
|
group.total_members = 1
|
||||||
db.commit()
|
db.commit()
|
||||||
db.refresh(group)
|
db.refresh(group)
|
||||||
|
|
||||||
return group
|
return group
|
||||||
|
|
||||||
@router.get("/groups/{group_id}", response_model=PurchaseGroupResponse)
|
@router.get("/groups/{group_id}", response_model=PurchaseGroupResponse)
|
||||||
def get_group(
|
def get_group(group_id: str, db: Session = Depends(get_db)):
|
||||||
group_id: str,
|
|
||||||
db: Session = Depends(get_db)
|
|
||||||
):
|
|
||||||
"""获取认购群详情"""
|
"""获取认购群详情"""
|
||||||
group = db.query(PurchaseGroup).filter(PurchaseGroup.id == group_id).first()
|
group = db.query(PurchaseGroup).filter(PurchaseGroup.id == group_id).first()
|
||||||
if not group:
|
if not group:
|
||||||
|
|
@ -120,11 +264,10 @@ def join_group(
|
||||||
current_user = Depends(get_current_user),
|
current_user = Depends(get_current_user),
|
||||||
db: Session = Depends(get_db)
|
db: Session = Depends(get_db)
|
||||||
):
|
):
|
||||||
"""加入认购群"""
|
"""申请加入认购群"""
|
||||||
if not current_user:
|
if not current_user:
|
||||||
raise HTTPException(status_code=401, detail="请先登录")
|
raise HTTPException(status_code=401, detail="请先登录")
|
||||||
|
|
||||||
# 检查群是否存在
|
|
||||||
group = db.query(PurchaseGroup).filter(PurchaseGroup.id == group_id).first()
|
group = db.query(PurchaseGroup).filter(PurchaseGroup.id == group_id).first()
|
||||||
if not group:
|
if not group:
|
||||||
raise HTTPException(status_code=404, detail="认购群不存在")
|
raise HTTPException(status_code=404, detail="认购群不存在")
|
||||||
|
|
@ -132,39 +275,47 @@ def join_group(
|
||||||
if group.status != "active":
|
if group.status != "active":
|
||||||
raise HTTPException(status_code=400, detail="该认购群已结束")
|
raise HTTPException(status_code=400, detail="该认购群已结束")
|
||||||
|
|
||||||
# 检查是否已加入
|
|
||||||
existing = db.query(PurchaseMember).filter(
|
existing = db.query(PurchaseMember).filter(
|
||||||
PurchaseMember.group_id == group_id,
|
PurchaseMember.group_id == group_id,
|
||||||
PurchaseMember.user_id == current_user.f99_90_id
|
PurchaseMember.user_id == current_user.f99_90_id
|
||||||
).first()
|
).first()
|
||||||
|
|
||||||
if existing:
|
if existing:
|
||||||
raise HTTPException(status_code=400, detail="您已加入该认购群")
|
if existing.status == "approved":
|
||||||
|
raise HTTPException(status_code=400, detail="您已加入该认购群")
|
||||||
|
elif existing.status == "pending":
|
||||||
|
raise HTTPException(status_code=400, detail="您已申请加入,等待审批")
|
||||||
|
elif existing.status == "rejected":
|
||||||
|
existing.status = "pending"
|
||||||
|
existing.joined_at = datetime.now()
|
||||||
|
group.total_pending += 1
|
||||||
|
db.commit()
|
||||||
|
return {"message": "已重新申请,等待审批"}
|
||||||
|
|
||||||
# 加入
|
|
||||||
member = PurchaseMember(
|
member = PurchaseMember(
|
||||||
group_id=group_id,
|
group_id=group_id,
|
||||||
user_id=current_user.f99_90_id,
|
user_id=current_user.f99_90_id,
|
||||||
user_name=current_user.f01_01_name,
|
user_name=current_user.f01_01_name,
|
||||||
user_avatar=current_user.avatar,
|
user_avatar=current_user.avatar,
|
||||||
role="member"
|
role="member",
|
||||||
|
status="pending"
|
||||||
)
|
)
|
||||||
db.add(member)
|
db.add(member)
|
||||||
|
group.total_pending += 1
|
||||||
# 更新群成员数
|
|
||||||
group.total_members += 1
|
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
return {"message": "加入成功"}
|
return {"message": "申请成功,等待群主审批"}
|
||||||
|
|
||||||
@router.get("/groups/{group_id}/members")
|
@router.get("/groups/{group_id}/members", response_model=List[MemberResponse])
|
||||||
def get_group_members(
|
def get_group_members(
|
||||||
group_id: str,
|
group_id: str,
|
||||||
|
current_user = Depends(get_current_user),
|
||||||
db: Session = Depends(get_db)
|
db: Session = Depends(get_db)
|
||||||
):
|
):
|
||||||
"""获取认购群成员列表"""
|
"""获取认购群成员列表"""
|
||||||
members = db.query(PurchaseMember).filter(
|
members = db.query(PurchaseMember).filter(
|
||||||
PurchaseMember.group_id == group_id
|
PurchaseMember.group_id == group_id,
|
||||||
|
PurchaseMember.status == "approved"
|
||||||
).order_by(PurchaseMember.joined_at.asc()).all()
|
).order_by(PurchaseMember.joined_at.asc()).all()
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
@ -174,16 +325,14 @@ def get_group_members(
|
||||||
"user_name": m.user_name,
|
"user_name": m.user_name,
|
||||||
"user_avatar": m.user_avatar,
|
"user_avatar": m.user_avatar,
|
||||||
"role": m.role,
|
"role": m.role,
|
||||||
|
"status": m.status,
|
||||||
"joined_at": m.joined_at
|
"joined_at": m.joined_at
|
||||||
}
|
}
|
||||||
for m in members
|
for m in members
|
||||||
]
|
]
|
||||||
|
|
||||||
@router.get("/groups/{group_id}/collections")
|
@router.get("/groups/{group_id}/collections", response_model=List[PurchaseCollectionResponse])
|
||||||
def get_group_collections(
|
def get_group_collections(group_id: str, db: Session = Depends(get_db)):
|
||||||
group_id: str,
|
|
||||||
db: Session = Depends(get_db)
|
|
||||||
):
|
|
||||||
"""获取认购群藏品列表"""
|
"""获取认购群藏品列表"""
|
||||||
collections = db.query(PurchaseCollection).filter(
|
collections = db.query(PurchaseCollection).filter(
|
||||||
PurchaseCollection.group_id == group_id
|
PurchaseCollection.group_id == group_id
|
||||||
|
|
@ -192,19 +341,25 @@ def get_group_collections(
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
"id": c.id,
|
"id": c.id,
|
||||||
|
"group_id": c.group_id,
|
||||||
"user_id": c.user_id,
|
"user_id": c.user_id,
|
||||||
"user_name": c.user_name,
|
"user_name": c.user_name,
|
||||||
"collection_name": c.collection_name,
|
"collection_name": c.collection_name,
|
||||||
"collection_code": c.collection_code,
|
"collection_code": c.collection_code,
|
||||||
"number": c.number,
|
"number": c.number,
|
||||||
|
"grading": c.grading,
|
||||||
|
"boss_name": c.boss_name,
|
||||||
"price": float(c.price),
|
"price": float(c.price),
|
||||||
|
"source": c.source,
|
||||||
|
"paid": c.paid,
|
||||||
"status": c.status,
|
"status": c.status,
|
||||||
|
"submit_date": c.submit_date,
|
||||||
"submitted_at": c.submitted_at
|
"submitted_at": c.submitted_at
|
||||||
}
|
}
|
||||||
for c in collections
|
for c in collections
|
||||||
]
|
]
|
||||||
|
|
||||||
@router.post("/groups/{group_id}/collections")
|
@router.post("/groups/{group_id}/collections", response_model=PurchaseCollectionResponse)
|
||||||
def add_collection(
|
def add_collection(
|
||||||
group_id: str,
|
group_id: str,
|
||||||
data: PurchaseCollectionCreate,
|
data: PurchaseCollectionCreate,
|
||||||
|
|
@ -215,35 +370,63 @@ def add_collection(
|
||||||
if not current_user:
|
if not current_user:
|
||||||
raise HTTPException(status_code=401, detail="请先登录")
|
raise HTTPException(status_code=401, detail="请先登录")
|
||||||
|
|
||||||
# 检查群是否存在
|
if not data.number:
|
||||||
|
raise HTTPException(status_code=400, detail="冠字号必填")
|
||||||
|
if not data.grading:
|
||||||
|
raise HTTPException(status_code=400, detail="评级必填")
|
||||||
|
if not data.boss_name:
|
||||||
|
raise HTTPException(status_code=400, detail="认购老板必填")
|
||||||
|
if not data.price:
|
||||||
|
raise HTTPException(status_code=400, detail="价格必填")
|
||||||
|
if not data.source:
|
||||||
|
raise HTTPException(status_code=400, detail="来源必填")
|
||||||
|
|
||||||
group = db.query(PurchaseGroup).filter(PurchaseGroup.id == group_id).first()
|
group = db.query(PurchaseGroup).filter(PurchaseGroup.id == group_id).first()
|
||||||
if not group:
|
if not group:
|
||||||
raise HTTPException(status_code=404, detail="认购群不存在")
|
raise HTTPException(status_code=404, detail="认购群不存在")
|
||||||
|
|
||||||
# 检查是否已加入
|
|
||||||
member = db.query(PurchaseMember).filter(
|
member = db.query(PurchaseMember).filter(
|
||||||
PurchaseMember.group_id == group_id,
|
PurchaseMember.group_id == group_id,
|
||||||
PurchaseMember.user_id == current_user.f99_90_id
|
PurchaseMember.user_id == current_user.f99_90_id,
|
||||||
|
PurchaseMember.status == "approved"
|
||||||
).first()
|
).first()
|
||||||
|
|
||||||
if not member:
|
if not member:
|
||||||
raise HTTPException(status_code=400, detail="请先加入该认购群")
|
raise HTTPException(status_code=400, detail="请先加入该认购群并通过审批")
|
||||||
|
|
||||||
|
max_code = db.query(PurchaseCollection).filter(
|
||||||
|
PurchaseCollection.group_id == group_id
|
||||||
|
).order_by(PurchaseCollection.collection_code.desc()).first()
|
||||||
|
|
||||||
|
if max_code and max_code.collection_code:
|
||||||
|
try:
|
||||||
|
next_num = int(max_code.collection_code) + 1
|
||||||
|
except:
|
||||||
|
next_num = 1
|
||||||
|
else:
|
||||||
|
next_num = 1
|
||||||
|
|
||||||
|
collection_code = f"{next_num:03d}"
|
||||||
|
|
||||||
# 添加藏品
|
|
||||||
collection = PurchaseCollection(
|
collection = PurchaseCollection(
|
||||||
group_id=group_id,
|
group_id=group_id,
|
||||||
user_id=current_user.f99_90_id,
|
user_id=current_user.f99_90_id,
|
||||||
user_name=current_user.f01_01_name,
|
user_name=current_user.f01_01_name,
|
||||||
collection_name=data.collection_name,
|
collection_name=data.collection_name,
|
||||||
collection_code=data.collection_code,
|
collection_code=collection_code,
|
||||||
number=data.number,
|
number=data.number,
|
||||||
price=data.price
|
grading=data.grading,
|
||||||
|
boss_name=data.boss_name,
|
||||||
|
price=data.price,
|
||||||
|
source=data.source,
|
||||||
|
paid=data.paid,
|
||||||
|
status="pending"
|
||||||
)
|
)
|
||||||
db.add(collection)
|
db.add(collection)
|
||||||
|
|
||||||
# 更新群统计
|
|
||||||
group.total_collections += 1
|
group.total_collections += 1
|
||||||
group.total_amount += float(data.price)
|
from decimal import Decimal
|
||||||
|
group.total_amount += Decimal(str(data.price))
|
||||||
if group.total_collections > 0:
|
if group.total_collections > 0:
|
||||||
group.avg_price = group.total_amount / group.total_collections
|
group.avg_price = group.total_amount / group.total_collections
|
||||||
|
|
||||||
|
|
@ -252,13 +435,77 @@ def add_collection(
|
||||||
|
|
||||||
return collection
|
return collection
|
||||||
|
|
||||||
|
@router.put("/groups/{group_id}/collections/{collection_id}", response_model=PurchaseCollectionResponse)
|
||||||
|
def update_collection(
|
||||||
|
group_id: str,
|
||||||
|
collection_id: str,
|
||||||
|
data: PurchaseCollectionUpdate,
|
||||||
|
current_user = Depends(get_current_user),
|
||||||
|
db: Session = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""编辑认购藏品 (仅群主可操作)"""
|
||||||
|
if not current_user:
|
||||||
|
raise HTTPException(status_code=401, detail="请先登录")
|
||||||
|
|
||||||
|
group = db.query(PurchaseGroup).filter(PurchaseGroup.id == group_id).first()
|
||||||
|
if not group:
|
||||||
|
raise HTTPException(status_code=404, detail="认购群不存在")
|
||||||
|
|
||||||
|
if group.creator_id != current_user.f99_90_id:
|
||||||
|
raise HTTPException(status_code=403, detail="只有群主可以编辑")
|
||||||
|
|
||||||
|
collection = db.query(PurchaseCollection).filter(
|
||||||
|
PurchaseCollection.id == collection_id,
|
||||||
|
PurchaseCollection.group_id == group_id
|
||||||
|
).first()
|
||||||
|
|
||||||
|
if not collection:
|
||||||
|
raise HTTPException(status_code=404, detail="藏品不存在")
|
||||||
|
|
||||||
|
old_price = float(collection.price)
|
||||||
|
|
||||||
|
# 更新字段
|
||||||
|
if data.collection_name is not None:
|
||||||
|
collection.collection_name = data.collection_name
|
||||||
|
if data.number is not None:
|
||||||
|
collection.number = data.number
|
||||||
|
if data.grading is not None:
|
||||||
|
collection.grading = data.grading
|
||||||
|
if data.boss_name is not None:
|
||||||
|
collection.boss_name = data.boss_name
|
||||||
|
if data.source is not None:
|
||||||
|
collection.source = data.source
|
||||||
|
if data.paid is not None:
|
||||||
|
collection.paid = data.paid
|
||||||
|
|
||||||
|
# 处理状态变化
|
||||||
|
new_status = data.status
|
||||||
|
if new_status and new_status != collection.status:
|
||||||
|
if new_status == "confirmed" and collection.status != "confirmed":
|
||||||
|
group.total_confirmed += 1
|
||||||
|
elif collection.status == "confirmed" and new_status != "confirmed":
|
||||||
|
group.total_confirmed -= 1
|
||||||
|
collection.status = new_status
|
||||||
|
|
||||||
|
# 处理价格变化
|
||||||
|
if data.price is not None and data.price != old_price:
|
||||||
|
from decimal import Decimal
|
||||||
|
group.total_amount = group.total_amount - Decimal(str(old_price)) + Decimal(str(data.price))
|
||||||
|
if group.total_collections > 0:
|
||||||
|
group.avg_price = group.total_amount / group.total_collections
|
||||||
|
|
||||||
|
db.commit()
|
||||||
|
db.refresh(collection)
|
||||||
|
|
||||||
|
return collection
|
||||||
|
|
||||||
@router.post("/groups/{group_id}/close")
|
@router.post("/groups/{group_id}/close")
|
||||||
def close_group(
|
def close_group(
|
||||||
group_id: str,
|
group_id: str,
|
||||||
current_user = Depends(get_current_user),
|
current_user = Depends(get_current_user),
|
||||||
db: Session = Depends(get_db)
|
db: Session = Depends(get_db)
|
||||||
):
|
):
|
||||||
"""结束认购群(仅群主可操作)"""
|
"""结束认购群"""
|
||||||
if not current_user:
|
if not current_user:
|
||||||
raise HTTPException(status_code=401, detail="请先登录")
|
raise HTTPException(status_code=401, detail="请先登录")
|
||||||
|
|
||||||
|
|
@ -266,11 +513,130 @@ def close_group(
|
||||||
if not group:
|
if not group:
|
||||||
raise HTTPException(status_code=404, detail="认购群不存在")
|
raise HTTPException(status_code=404, detail="认购群不存在")
|
||||||
|
|
||||||
# 检查是否为群主
|
|
||||||
if group.creator_id != current_user.f99_90_id:
|
if group.creator_id != current_user.f99_90_id:
|
||||||
raise HTTPException(status_code=403, detail="只有群主可以结束认购群")
|
raise HTTPException(status_code=403, detail="只有群主可以结束认购群")
|
||||||
|
|
||||||
group.status = "closed"
|
group.status = "closed"
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
return {"message": "认购群已结束"}
|
return {"message": "认购群已结束"}
|
||||||
|
@router.delete("/groups/{group_id}")
|
||||||
|
def delete_group(
|
||||||
|
group_id: str,
|
||||||
|
current_user = Depends(get_current_user),
|
||||||
|
db: Session = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""删除认购群 (仅管理员可操作)"""
|
||||||
|
if not current_user:
|
||||||
|
raise HTTPException(status_code=401, detail="请先登录")
|
||||||
|
|
||||||
|
# 管理员权限检查
|
||||||
|
if current_user.role not in ["admin", "superadmin"]:
|
||||||
|
raise HTTPException(status_code=403, detail="只有管理员可以删除认购群")
|
||||||
|
|
||||||
|
group = db.query(PurchaseGroup).filter(PurchaseGroup.id == group_id).first()
|
||||||
|
if not group:
|
||||||
|
raise HTTPException(status_code=404, detail="认购群不存在")
|
||||||
|
|
||||||
|
# 删除相关成员和藏品
|
||||||
|
db.query(PurchaseMember).filter(PurchaseMember.group_id == group_id).delete()
|
||||||
|
db.query(PurchaseCollection).filter(PurchaseCollection.group_id == group_id).delete()
|
||||||
|
db.delete(group)
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
return {"message": "认购群已删除"}
|
||||||
|
|
||||||
|
class MemberUpdate(BaseModel):
|
||||||
|
wechat_name: Optional[str] = None
|
||||||
|
contact: Optional[str] = None
|
||||||
|
purchase_count: Optional[int] = None
|
||||||
|
paid_amount: Optional[float] = None
|
||||||
|
notes: Optional[str] = None
|
||||||
|
|
||||||
|
class GroupUpdate(BaseModel):
|
||||||
|
name: Optional[str] = None
|
||||||
|
description: Optional[str] = None
|
||||||
|
cycle_months: Optional[int] = None
|
||||||
|
start_date: Optional[str] = None
|
||||||
|
|
||||||
|
# 更新成员信息
|
||||||
|
@router.put("/groups/{group_id}/members/{member_id}")
|
||||||
|
def update_member(
|
||||||
|
group_id: str,
|
||||||
|
member_id: str,
|
||||||
|
data: MemberUpdate,
|
||||||
|
current_user = Depends(get_current_user),
|
||||||
|
db: Session = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""更新成员信息 (成员自己或群主可编辑)"""
|
||||||
|
if not current_user:
|
||||||
|
raise HTTPException(status_code=401, detail="请先登录")
|
||||||
|
|
||||||
|
group = db.query(PurchaseGroup).filter(PurchaseGroup.id == group_id).first()
|
||||||
|
if not group:
|
||||||
|
raise HTTPException(status_code=404, detail="认购群不存在")
|
||||||
|
|
||||||
|
member = db.query(PurchaseMember).filter(
|
||||||
|
PurchaseMember.id == member_id,
|
||||||
|
PurchaseMember.group_id == group_id
|
||||||
|
).first()
|
||||||
|
|
||||||
|
if not member:
|
||||||
|
raise HTTPException(status_code=404, detail="成员不存在")
|
||||||
|
|
||||||
|
# 只有成员自己或群主可以修改
|
||||||
|
if member.user_id != current_user.f99_90_id and group.creator_id != current_user.f99_90_id:
|
||||||
|
raise HTTPException(status_code=403, detail="无权修改")
|
||||||
|
|
||||||
|
if data.wechat_name is not None:
|
||||||
|
member.wechat_name = data.wechat_name
|
||||||
|
if data.contact is not None:
|
||||||
|
member.contact = data.contact
|
||||||
|
if data.purchase_count is not None:
|
||||||
|
member.purchase_count = data.purchase_count
|
||||||
|
if data.paid_amount is not None:
|
||||||
|
from decimal import Decimal
|
||||||
|
member.paid_amount = Decimal(str(data.paid_amount))
|
||||||
|
if data.notes is not None:
|
||||||
|
member.notes = data.notes
|
||||||
|
|
||||||
|
db.commit()
|
||||||
|
db.refresh(member)
|
||||||
|
|
||||||
|
return {"message": "更新成功", "member_id": member.id}
|
||||||
|
|
||||||
|
# 更新群信息
|
||||||
|
@router.put("/groups/{group_id}", response_model=PurchaseGroupResponse)
|
||||||
|
def update_group(
|
||||||
|
group_id: str,
|
||||||
|
data: GroupUpdate,
|
||||||
|
current_user = Depends(get_current_user),
|
||||||
|
db: Session = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""更新群信息 (仅群主可编辑)"""
|
||||||
|
if not current_user:
|
||||||
|
raise HTTPException(status_code=401, detail="请先登录")
|
||||||
|
|
||||||
|
group = db.query(PurchaseGroup).filter(PurchaseGroup.id == group_id).first()
|
||||||
|
if not group:
|
||||||
|
raise HTTPException(status_code=404, detail="认购群不存在")
|
||||||
|
|
||||||
|
if group.creator_id != current_user.f99_90_id:
|
||||||
|
raise HTTPException(status_code=403, detail="只有群主可以修改")
|
||||||
|
|
||||||
|
if data.name is not None:
|
||||||
|
group.name = data.name
|
||||||
|
if data.description is not None:
|
||||||
|
group.description = data.description
|
||||||
|
if data.cycle_months is not None:
|
||||||
|
group.cycle_months = data.cycle_months
|
||||||
|
if data.start_date is not None:
|
||||||
|
try:
|
||||||
|
group.start_date = datetime.fromisoformat(data.start_date.replace('Z', '+08:00'))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
db.commit()
|
||||||
|
db.refresh(group)
|
||||||
|
|
||||||
|
return group
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,28 @@
|
||||||
# 版本更新记录
|
# 版本更新记录
|
||||||
|
|
||||||
|
## v0.0.12 (2026-04-29)
|
||||||
|
|
||||||
|
### 前端更新
|
||||||
|
- **Purchase.jsx**
|
||||||
|
- 完善:入群申请审批流程 (待审批成员列表)
|
||||||
|
- 完善:新增认购藏品字段
|
||||||
|
- 编号:自动生成001开始
|
||||||
|
- 冠字号:必填
|
||||||
|
- 评级:必填 (下拉选择)
|
||||||
|
- 认购老板:必填 (从成员中选择)
|
||||||
|
- 价格:必填
|
||||||
|
- 来源:必填 (一尘/直播/群友/其他)
|
||||||
|
- 认购款结清:checkbox
|
||||||
|
- 优化:表单布局
|
||||||
|
|
||||||
|
### 后端更新
|
||||||
|
- **purchase.py**
|
||||||
|
- 新增:入群审批接口 /approve
|
||||||
|
- 新增:待审批成员列表 /pending-members
|
||||||
|
- 新增:认购藏品新字段 (grading, boss_name, source, paid, submit_date)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## v0.0.7 (2026-04-24)
|
## v0.0.7 (2026-04-24)
|
||||||
|
|
||||||
### 代码清理
|
### 代码清理
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
{
|
{
|
||||||
"version": "0.0.9",
|
"version": "0.0.12",
|
||||||
"updated": "2026-04-24",
|
"updated": "2026-04-24",
|
||||||
"modules": {
|
"modules": {
|
||||||
"frontend": {
|
"frontend": {
|
||||||
"version": "0.0.9",
|
"version": "0.0.12",
|
||||||
"pages": {
|
"pages": {
|
||||||
"Add": "0.0.1",
|
"Add": "0.0.1",
|
||||||
"Admin": "0.0.1",
|
"Admin": "0.0.1",
|
||||||
"Detail": "0.0.1",
|
"Detail": "0.0.1",
|
||||||
"Edit": "0.0.1",
|
"Edit": "0.0.1",
|
||||||
"Home": "0.0.4",
|
"Home": "0.0.7",
|
||||||
"List": "0.0.1",
|
"List": "0.0.1",
|
||||||
"Login": "0.0.1",
|
"Login": "0.0.1",
|
||||||
"News": "0.0.8",
|
"News": "0.0.8",
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"backend": {
|
"backend": {
|
||||||
"version": "0.0.9",
|
"version": "0.0.12",
|
||||||
"routers": {
|
"routers": {
|
||||||
"auth": "0.0.1",
|
"auth": "0.0.1",
|
||||||
"collections": "0.0.1",
|
"collections": "0.0.1",
|
||||||
|
|
|
||||||
|
|
@ -226,7 +226,7 @@ export default function Home() {
|
||||||
<div style={{ color: '#f59e0b', fontSize: '18px', fontWeight: '600', whiteSpace: 'nowrap' }}>发布寻号</div>
|
<div style={{ color: '#f59e0b', fontSize: '18px', fontWeight: '600', whiteSpace: 'nowrap' }}>发布寻号</div>
|
||||||
<div style={{ color: 'rgba(255,255,255,0.5)', fontSize: '10px', marginTop: '2px' }}>发布寻配需求</div>
|
<div style={{ color: 'rgba(255,255,255,0.5)', fontSize: '10px', marginTop: '2px' }}>发布寻配需求</div>
|
||||||
</div>
|
</div>
|
||||||
<div onClick={() => window.location.hash = '#/add?mode=manual'} style={{
|
<div onClick={() => window.location.hash = '#/purchase'} style={{
|
||||||
background: 'linear-gradient(135deg, rgba(255,255,255,0.08) 0%, rgba(255,255,255,0.02) 100%)',
|
background: 'linear-gradient(135deg, rgba(255,255,255,0.08) 0%, rgba(255,255,255,0.02) 100%)',
|
||||||
borderRadius: '12px',
|
borderRadius: '12px',
|
||||||
padding: '12px 16px',
|
padding: '12px 16px',
|
||||||
|
|
@ -238,8 +238,8 @@ export default function Home() {
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
textAlign: 'center'
|
textAlign: 'center'
|
||||||
}}>
|
}}>
|
||||||
<div style={{ color: '#3b82f6', fontSize: '18px', fontWeight: '600', whiteSpace: 'nowrap' }}>发布藏品</div>
|
<div style={{ color: '#ec4899', fontSize: '18px', fontWeight: '600', whiteSpace: 'nowrap' }}>我的认购</div>
|
||||||
<div style={{ color: 'rgba(255,255,255,0.5)', fontSize: '10px', marginTop: '2px' }}>手动发布</div>
|
<div style={{ color: 'rgba(255,255,255,0.5)', fontSize: '10px', marginTop: '2px' }}>认购群入口</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -407,14 +407,16 @@ export default function Home() {
|
||||||
{(isAdmin ? [
|
{(isAdmin ? [
|
||||||
{ icon: '🏠', label: '首页', hash: '#/', idx: 0 },
|
{ icon: '🏠', label: '首页', hash: '#/', idx: 0 },
|
||||||
{ icon: '📚', label: '藏品', hash: '#/list', idx: 1 },
|
{ icon: '📚', label: '藏品', hash: '#/list', idx: 1 },
|
||||||
{ icon: '➕', label: '录入', hash: '#/ocr', idx: 2 },
|
{ icon: '🎯', label: '认购', hash: '#/purchase', idx: 2 },
|
||||||
{ icon: '📊', label: '统计', hash: '#/stats', idx: 3 },
|
{ icon: '➕', label: '录入', hash: '#/ocr', idx: 3 },
|
||||||
{ icon: '⚙️', label: '管理', hash: '#/admin', idx: 4 }
|
{ icon: '📊', label: '统计', hash: '#/stats', idx: 4 },
|
||||||
|
{ icon: '⚙️', label: '管理', hash: '#/admin', idx: 5 }
|
||||||
] : [
|
] : [
|
||||||
{ icon: '🏠', label: '首页', hash: '#/', idx: 0 },
|
{ icon: '🏠', label: '首页', hash: '#/', idx: 0 },
|
||||||
{ icon: '📚', label: '藏品', hash: '#/list', idx: 1 },
|
{ icon: '📚', label: '藏品', hash: '#/list', idx: 1 },
|
||||||
{ icon: '➕', label: '录入', hash: '#/ocr', idx: 2 },
|
{ icon: '🎯', label: '认购', hash: '#/purchase', idx: 2 },
|
||||||
{ icon: '📊', label: '统计', hash: '#/stats', idx: 3 }
|
{ icon: '➕', label: '录入', hash: '#/ocr', idx: 3 },
|
||||||
|
{ icon: '📊', label: '统计', hash: '#/stats', idx: 4 }
|
||||||
]).map((item) => (
|
]).map((item) => (
|
||||||
<div key={item.idx} onClick={() => window.location.hash = item.hash} style={{
|
<div key={item.idx} onClick={() => window.location.hash = item.hash} style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ function Purchase() {
|
||||||
const [selectedGroup, setSelectedGroup] = useState(null)
|
const [selectedGroup, setSelectedGroup] = useState(null)
|
||||||
const [groupMembers, setGroupMembers] = useState([])
|
const [groupMembers, setGroupMembers] = useState([])
|
||||||
const [groupCollections, setGroupCollections] = useState([])
|
const [groupCollections, setGroupCollections] = useState([])
|
||||||
|
const [showCollectionForm, setShowCollectionForm] = useState(false)
|
||||||
const [newGroup, setNewGroup] = useState({ name: '', description: '' })
|
const [newGroup, setNewGroup] = useState({ name: '', description: '' })
|
||||||
const [newCollection, setNewCollection] = useState({ collection_name: '', collection_code: '', number: '', price: '' })
|
const [newCollection, setNewCollection] = useState({ collection_name: '', collection_code: '', number: '', price: '' })
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
|
|
@ -247,7 +248,7 @@ function Purchase() {
|
||||||
if (selectedGroup) {
|
if (selectedGroup) {
|
||||||
return (
|
return (
|
||||||
<div style={{
|
<div style={{
|
||||||
minHeight: '100vh',
|
minHeight: '100vh', overflowY: 'auto', WebkitOverflowScrolling: 'touch',
|
||||||
background: '#0f172a',
|
background: '#0f172a',
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
padding: '16px'
|
padding: '16px'
|
||||||
|
|
@ -369,15 +370,16 @@ function Purchase() {
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
{groupCollections.length === 0 && <div style={{ color: 'rgba(255,255,255,0.3)', fontSize: '13px', textAlign: 'center', padding: '20px' }}>暂无认购藏品</div>}
|
{groupCollections.length === 0 && <div style={{ color: 'rgba(255,255,255,0.3)', fontSize: '13px', textAlign: 'center', padding: '20px' }}>暂无认购藏品</div>}
|
||||||
|
{selectedGroup && user && selectedGroup.creator_id === user.id && selectedGroup.status === 'active' && (
|
||||||
|
<button onClick={() => setShowCollectionForm(!showCollectionForm)} style={{ marginTop: '12px', width: '100%', background: showCollectionForm ? '#ef4444' : '#3b82f6', color: '#fff', border: 'none', borderRadius: '8px', padding: '12px', fontSize: '14px', fontWeight: 'bold', cursor: 'pointer' }}>{showCollectionForm ? '收起' : '录入认购藏品'}</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 提交认购藏品表单 */}
|
{/* 提交认购藏品表单 - 仅群主可提交 */}
|
||||||
{selectedGroup.status === 'active' && (
|
{selectedGroup && user && selectedGroup.creator_id === user.id && selectedGroup.status === 'active' && showCollectionForm && (
|
||||||
<div style={{
|
<div style={{
|
||||||
position: 'fixed',
|
marginTop: '16px',
|
||||||
bottom: '20px',
|
marginBottom: '80px',
|
||||||
left: '16px',
|
|
||||||
right: '16px',
|
|
||||||
background: '#1e293b',
|
background: '#1e293b',
|
||||||
borderRadius: '12px',
|
borderRadius: '12px',
|
||||||
padding: '16px',
|
padding: '16px',
|
||||||
|
|
@ -459,13 +461,20 @@ function Purchase() {
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* 非群主提示 */}
|
||||||
|
{selectedGroup && user && !(selectedGroup.creator_id === user.id) && selectedGroup.status === 'active' && (
|
||||||
|
<div style={{ marginTop: '16px', marginBottom: '80px', background: '#1e293b', borderRadius: '12px', padding: '16px', textAlign: 'center', color: 'rgba(255,255,255,0.5)' }}>
|
||||||
|
仅群主可提交认购藏品
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{
|
<div style={{
|
||||||
minHeight: '100vh',
|
minHeight: '100vh', overflowY: 'auto', WebkitOverflowScrolling: 'touch',
|
||||||
background: '#0f172a',
|
background: '#0f172a',
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
padding: '16px'
|
padding: '16px'
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue