v0.0.10 - 认购功能初版
This commit is contained in:
parent
d8aac9bc3e
commit
ee728a5f4e
|
|
@ -19,6 +19,7 @@ from app.routers import information as information_router
|
||||||
from app.routers import yichens as yichens_router
|
from app.routers import yichens as yichens_router
|
||||||
from app.routers import seek as seek_router
|
from app.routers import seek as seek_router
|
||||||
from app.routers import deal as deal_router
|
from app.routers import deal as deal_router
|
||||||
|
from app.routers import purchase as purchase_router
|
||||||
|
|
||||||
# 版本信息 - 从 config/VERSION 文件读取
|
# 版本信息 - 从 config/VERSION 文件读取
|
||||||
def get_version():
|
def get_version():
|
||||||
|
|
@ -88,6 +89,7 @@ app.include_router(information_router.router)
|
||||||
app.include_router(yichens_router.router) # 一尘看板
|
app.include_router(yichens_router.router) # 一尘看板
|
||||||
app.include_router(seek_router.router) # 寻配号
|
app.include_router(seek_router.router) # 寻配号
|
||||||
app.include_router(deal_router.router) # 成交行情
|
app.include_router(deal_router.router) # 成交行情
|
||||||
|
app.include_router(purchase_router.router) # 认购群
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
# purchase - 认购群模型
|
||||||
|
# Version: 0.0.1 (2026-04-24)
|
||||||
|
# 认购群、成员、藏品管理
|
||||||
|
|
||||||
|
from sqlalchemy import Column, String, Text, Integer, DECIMAL, DateTime, ForeignKey
|
||||||
|
from sqlalchemy.sql import func
|
||||||
|
from app.core.database import Base
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
def generate_uuid():
|
||||||
|
return str(uuid.uuid4())
|
||||||
|
|
||||||
|
class PurchaseGroup(Base):
|
||||||
|
"""认购群表"""
|
||||||
|
__tablename__ = "purchase_group"
|
||||||
|
|
||||||
|
id = Column(String(36), primary_key=True, default=generate_uuid)
|
||||||
|
name = Column(String(100), nullable=False) # 认购群名称
|
||||||
|
description = Column(Text, nullable=True) # 描述
|
||||||
|
creator_id = Column(String(36), nullable=False) # 创建者ID
|
||||||
|
creator_name = Column(String(50), nullable=True) # 创建者名字
|
||||||
|
status = Column(String(20), default="active") # active/closed
|
||||||
|
total_members = Column(Integer, default=0) # 总参与人数
|
||||||
|
total_collections = Column(Integer, default=0) # 总藏品数
|
||||||
|
total_amount = Column(DECIMAL(12,2), default=0) # 总金额
|
||||||
|
avg_price = Column(DECIMAL(10,2), default=0) # 均价
|
||||||
|
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||||
|
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
|
||||||
|
|
||||||
|
class PurchaseMember(Base):
|
||||||
|
"""认购成员表"""
|
||||||
|
__tablename__ = "purchase_member"
|
||||||
|
|
||||||
|
id = Column(String(36), primary_key=True, default=generate_uuid)
|
||||||
|
group_id = Column(String(36), ForeignKey("purchase_group.id"), nullable=False)
|
||||||
|
user_id = Column(String(36), nullable=False)
|
||||||
|
user_name = Column(String(50), nullable=True)
|
||||||
|
user_avatar = Column(String(255), nullable=True)
|
||||||
|
role = Column(String(20), default="member") # creator/admin/member
|
||||||
|
joined_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||||
|
|
||||||
|
class PurchaseCollection(Base):
|
||||||
|
"""认购藏品表"""
|
||||||
|
__tablename__ = "purchase_collection"
|
||||||
|
|
||||||
|
id = Column(String(36), primary_key=True, default=generate_uuid)
|
||||||
|
group_id = Column(String(36), ForeignKey("purchase_group.id"), nullable=False)
|
||||||
|
user_id = Column(String(36), nullable=False)
|
||||||
|
user_name = Column(String(50), nullable=True)
|
||||||
|
collection_name = Column(String(100), nullable=True) # 藏品名称
|
||||||
|
collection_code = Column(String(50), nullable=True) # 藏品编号
|
||||||
|
number = Column(String(50), nullable=True) # 冠字号
|
||||||
|
price = Column(DECIMAL(10,2), nullable=False) # 认购价格
|
||||||
|
status = Column(String(20), default="pending") # pending/confirmed
|
||||||
|
submitted_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||||
|
|
@ -0,0 +1,276 @@
|
||||||
|
# purchase - 认购群API路由
|
||||||
|
# Version: 0.0.1 (2026-04-24)
|
||||||
|
# 认购群、成员、藏品管理
|
||||||
|
|
||||||
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from typing import Optional, List
|
||||||
|
from datetime import datetime
|
||||||
|
from app.core.database import get_db
|
||||||
|
from app.core.auth import get_current_user
|
||||||
|
from app.models.models import User
|
||||||
|
from app.models.purchase import PurchaseGroup, PurchaseMember, PurchaseCollection
|
||||||
|
|
||||||
|
router = APIRouter(prefix="/api/purchase", tags=["认购"])
|
||||||
|
|
||||||
|
# ============ Schema ============
|
||||||
|
class PurchaseGroupCreate(BaseModel):
|
||||||
|
name: str
|
||||||
|
description: Optional[str] = None
|
||||||
|
|
||||||
|
class PurchaseGroupResponse(BaseModel):
|
||||||
|
id: str
|
||||||
|
name: str
|
||||||
|
description: Optional[str]
|
||||||
|
creator_id: str
|
||||||
|
creator_name: Optional[str]
|
||||||
|
status: str
|
||||||
|
total_members: int
|
||||||
|
total_collections: int
|
||||||
|
total_amount: float
|
||||||
|
avg_price: float
|
||||||
|
created_at: Optional[datetime]
|
||||||
|
|
||||||
|
class PurchaseCollectionCreate(BaseModel):
|
||||||
|
collection_name: str
|
||||||
|
collection_code: Optional[str] = None
|
||||||
|
number: Optional[str] = None
|
||||||
|
price: float
|
||||||
|
|
||||||
|
# ============ 认购群API ============
|
||||||
|
|
||||||
|
@router.get("/groups", response_model=List[PurchaseGroupResponse])
|
||||||
|
def get_groups(
|
||||||
|
status: str = Query("active", description="过滤状态"),
|
||||||
|
db: Session = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""获取所有认购群列表"""
|
||||||
|
query = db.query(PurchaseGroup)
|
||||||
|
if status:
|
||||||
|
query = query.filter(PurchaseGroup.status == status)
|
||||||
|
groups = query.order_by(PurchaseGroup.created_at.desc()).all()
|
||||||
|
return groups
|
||||||
|
|
||||||
|
@router.get("/my-groups", response_model=List[PurchaseGroupResponse])
|
||||||
|
def get_my_groups(
|
||||||
|
current_user = Depends(get_current_user),
|
||||||
|
db: Session = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""获取我参与的认购群"""
|
||||||
|
member_groups = db.query(PurchaseMember).filter(
|
||||||
|
PurchaseMember.user_id == current_user.f99_90_id
|
||||||
|
).all()
|
||||||
|
|
||||||
|
group_ids = [m.group_id for m in member_groups]
|
||||||
|
groups = db.query(PurchaseGroup).filter(
|
||||||
|
PurchaseGroup.id.in_(group_ids)
|
||||||
|
).all()
|
||||||
|
|
||||||
|
return groups
|
||||||
|
|
||||||
|
@router.post("/groups", response_model=PurchaseGroupResponse)
|
||||||
|
def create_group(
|
||||||
|
data: PurchaseGroupCreate,
|
||||||
|
current_user = Depends(get_current_user),
|
||||||
|
db: Session = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""创建认购群(创建者即为群主)"""
|
||||||
|
if not current_user:
|
||||||
|
raise HTTPException(status_code=401, detail="请先登录")
|
||||||
|
|
||||||
|
group = PurchaseGroup(
|
||||||
|
name=data.name,
|
||||||
|
description=data.description,
|
||||||
|
creator_id=current_user.f99_90_id,
|
||||||
|
creator_name=current_user.f01_01_name,
|
||||||
|
status="active"
|
||||||
|
)
|
||||||
|
db.add(group)
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
# 创建者自动加入并成为群主
|
||||||
|
member = PurchaseMember(
|
||||||
|
group_id=group.id,
|
||||||
|
user_id=current_user.f99_90_id,
|
||||||
|
user_name=current_user.f01_01_name,
|
||||||
|
user_avatar=current_user.avatar,
|
||||||
|
role="creator"
|
||||||
|
)
|
||||||
|
db.add(member)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(group)
|
||||||
|
|
||||||
|
return group
|
||||||
|
|
||||||
|
@router.get("/groups/{group_id}", response_model=PurchaseGroupResponse)
|
||||||
|
def get_group(
|
||||||
|
group_id: str,
|
||||||
|
db: Session = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""获取认购群详情"""
|
||||||
|
group = db.query(PurchaseGroup).filter(PurchaseGroup.id == group_id).first()
|
||||||
|
if not group:
|
||||||
|
raise HTTPException(status_code=404, detail="认购群不存在")
|
||||||
|
return group
|
||||||
|
|
||||||
|
@router.post("/groups/{group_id}/join")
|
||||||
|
def join_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="请先登录")
|
||||||
|
|
||||||
|
# 检查群是否存在
|
||||||
|
group = db.query(PurchaseGroup).filter(PurchaseGroup.id == group_id).first()
|
||||||
|
if not group:
|
||||||
|
raise HTTPException(status_code=404, detail="认购群不存在")
|
||||||
|
|
||||||
|
if group.status != "active":
|
||||||
|
raise HTTPException(status_code=400, detail="该认购群已结束")
|
||||||
|
|
||||||
|
# 检查是否已加入
|
||||||
|
existing = db.query(PurchaseMember).filter(
|
||||||
|
PurchaseMember.group_id == group_id,
|
||||||
|
PurchaseMember.user_id == current_user.f99_90_id
|
||||||
|
).first()
|
||||||
|
|
||||||
|
if existing:
|
||||||
|
raise HTTPException(status_code=400, detail="您已加入该认购群")
|
||||||
|
|
||||||
|
# 加入
|
||||||
|
member = PurchaseMember(
|
||||||
|
group_id=group_id,
|
||||||
|
user_id=current_user.f99_90_id,
|
||||||
|
user_name=current_user.f01_01_name,
|
||||||
|
user_avatar=current_user.avatar,
|
||||||
|
role="member"
|
||||||
|
)
|
||||||
|
db.add(member)
|
||||||
|
|
||||||
|
# 更新群成员数
|
||||||
|
group.total_members += 1
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
return {"message": "加入成功"}
|
||||||
|
|
||||||
|
@router.get("/groups/{group_id}/members")
|
||||||
|
def get_group_members(
|
||||||
|
group_id: str,
|
||||||
|
db: Session = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""获取认购群成员列表"""
|
||||||
|
members = db.query(PurchaseMember).filter(
|
||||||
|
PurchaseMember.group_id == group_id
|
||||||
|
).order_by(PurchaseMember.joined_at.asc()).all()
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"id": m.id,
|
||||||
|
"user_id": m.user_id,
|
||||||
|
"user_name": m.user_name,
|
||||||
|
"user_avatar": m.user_avatar,
|
||||||
|
"role": m.role,
|
||||||
|
"joined_at": m.joined_at
|
||||||
|
}
|
||||||
|
for m in members
|
||||||
|
]
|
||||||
|
|
||||||
|
@router.get("/groups/{group_id}/collections")
|
||||||
|
def get_group_collections(
|
||||||
|
group_id: str,
|
||||||
|
db: Session = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""获取认购群藏品列表"""
|
||||||
|
collections = db.query(PurchaseCollection).filter(
|
||||||
|
PurchaseCollection.group_id == group_id
|
||||||
|
).order_by(PurchaseCollection.submitted_at.desc()).all()
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"id": c.id,
|
||||||
|
"user_id": c.user_id,
|
||||||
|
"user_name": c.user_name,
|
||||||
|
"collection_name": c.collection_name,
|
||||||
|
"collection_code": c.collection_code,
|
||||||
|
"number": c.number,
|
||||||
|
"price": float(c.price),
|
||||||
|
"status": c.status,
|
||||||
|
"submitted_at": c.submitted_at
|
||||||
|
}
|
||||||
|
for c in collections
|
||||||
|
]
|
||||||
|
|
||||||
|
@router.post("/groups/{group_id}/collections")
|
||||||
|
def add_collection(
|
||||||
|
group_id: str,
|
||||||
|
data: PurchaseCollectionCreate,
|
||||||
|
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.group_id == group_id,
|
||||||
|
PurchaseMember.user_id == current_user.f99_90_id
|
||||||
|
).first()
|
||||||
|
|
||||||
|
if not member:
|
||||||
|
raise HTTPException(status_code=400, detail="请先加入该认购群")
|
||||||
|
|
||||||
|
# 添加藏品
|
||||||
|
collection = PurchaseCollection(
|
||||||
|
group_id=group_id,
|
||||||
|
user_id=current_user.f99_90_id,
|
||||||
|
user_name=current_user.f01_01_name,
|
||||||
|
collection_name=data.collection_name,
|
||||||
|
collection_code=data.collection_code,
|
||||||
|
number=data.number,
|
||||||
|
price=data.price
|
||||||
|
)
|
||||||
|
db.add(collection)
|
||||||
|
|
||||||
|
# 更新群统计
|
||||||
|
group.total_collections += 1
|
||||||
|
group.total_amount += float(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")
|
||||||
|
def close_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="请先登录")
|
||||||
|
|
||||||
|
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="只有群主可以结束认购群")
|
||||||
|
|
||||||
|
group.status = "closed"
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
return {"message": "认购群已结束"}
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
{
|
{
|
||||||
"version": "0.0.8",
|
"version": "0.0.9",
|
||||||
"updated": "2026-04-24",
|
"updated": "2026-04-24",
|
||||||
"modules": {
|
"modules": {
|
||||||
"frontend": {
|
"frontend": {
|
||||||
"version": "0.0.8",
|
"version": "0.0.9",
|
||||||
"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.1",
|
"Home": "0.0.4",
|
||||||
"List": "0.0.1",
|
"List": "0.0.1",
|
||||||
"Login": "0.0.1",
|
"Login": "0.0.1",
|
||||||
"News": "0.0.3",
|
"News": "0.0.8",
|
||||||
"News_YichensBoard": "0.0.1",
|
"News_YichensBoard": "0.0.1",
|
||||||
"Settings": "0.0.1",
|
"Settings": "0.0.1",
|
||||||
"Stats": "0.0.1",
|
"Stats": "0.0.1",
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"backend": {
|
"backend": {
|
||||||
"version": "0.0.8",
|
"version": "0.0.9",
|
||||||
"routers": {
|
"routers": {
|
||||||
"auth": "0.0.1",
|
"auth": "0.0.1",
|
||||||
"collections": "0.0.1",
|
"collections": "0.0.1",
|
||||||
|
|
@ -32,7 +32,7 @@
|
||||||
"news": "0.0.1",
|
"news": "0.0.1",
|
||||||
"ocr": "0.0.1",
|
"ocr": "0.0.1",
|
||||||
"operations": "0.0.1",
|
"operations": "0.0.1",
|
||||||
"seek": "0.0.4",
|
"seek": "0.0.9",
|
||||||
"users": "0.0.1",
|
"users": "0.0.1",
|
||||||
"yichens": "0.0.1"
|
"yichens": "0.0.1"
|
||||||
},
|
},
|
||||||
|
|
@ -44,5 +44,12 @@
|
||||||
"utils": "0.0.1"
|
"utils": "0.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"changelog": {
|
||||||
|
"0.0.9": [
|
||||||
|
"Home.jsx: 修复寻配号数据统计API",
|
||||||
|
"News.jsx: 寻配号功能稳定版(自有匹配+网络匹配缓存)",
|
||||||
|
"seek.py: 路由优化,留言功能迁移,缓存机制"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
<title>甲辰收藏 v=0.0.5</title>
|
<title>甲辰收藏 v=0.0.9</title>
|
||||||
|
|
||||||
<!-- Favicon -->
|
<!-- Favicon -->
|
||||||
<link rel="icon" type="image/png" href="/static/icons/favicon.png" />
|
<link rel="icon" type="image/png" href="/static/icons/favicon.png" />
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import List from './pages/List'
|
||||||
import Add from './pages/Add'
|
import Add from './pages/Add'
|
||||||
import Stats from './pages/Stats'
|
import Stats from './pages/Stats'
|
||||||
import News from './pages/News'
|
import News from './pages/News'
|
||||||
|
import Purchase from './pages/Purchase'
|
||||||
import Login from './pages/Login'
|
import Login from './pages/Login'
|
||||||
import Detail from './pages/Detail'
|
import Detail from './pages/Detail'
|
||||||
import Edit from './pages/Edit'
|
import Edit from './pages/Edit'
|
||||||
|
|
@ -30,6 +31,7 @@ export default function App() {
|
||||||
const basePath = path.split('?')[0]
|
const basePath = path.split('?')[0]
|
||||||
if (basePath === '/') return <Home />
|
if (basePath === '/') return <Home />
|
||||||
if (basePath === '/news') return <News />
|
if (basePath === '/news') return <News />
|
||||||
|
if (basePath === '/purchase') return <Purchase />
|
||||||
if (basePath === '/stats') return <Stats />
|
if (basePath === '/stats') return <Stats />
|
||||||
if (basePath === '/list') return <List />
|
if (basePath === '/list') return <List />
|
||||||
if (basePath === '/add') return <Add />
|
if (basePath === '/add') return <Add />
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,632 @@
|
||||||
|
/**
|
||||||
|
* Purchase - 我的认购/团购页面
|
||||||
|
* Version: 0.0.1 (2026-04-24)
|
||||||
|
* 认购群管理、加入、查看详情
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React, { useState, useEffect } from 'react'
|
||||||
|
import YichensBoard from './YichensBoard'
|
||||||
|
|
||||||
|
const API_BASE = ''
|
||||||
|
|
||||||
|
function Purchase() {
|
||||||
|
const [user, setUser] = useState(null)
|
||||||
|
const [myGroups, setMyGroups] = useState([])
|
||||||
|
const [allGroups, setAllGroups] = useState([])
|
||||||
|
const [showCreate, setShowCreate] = useState(false)
|
||||||
|
const [selectedGroup, setSelectedGroup] = useState(null)
|
||||||
|
const [groupMembers, setGroupMembers] = useState([])
|
||||||
|
const [groupCollections, setGroupCollections] = useState([])
|
||||||
|
const [newGroup, setNewGroup] = useState({ name: '', description: '' })
|
||||||
|
const [newCollection, setNewCollection] = useState({ collection_name: '', collection_code: '', number: '', price: '' })
|
||||||
|
const [loading, setLoading] = useState(true)
|
||||||
|
const [activeTab, setActiveTab] = useState('my') // my/all
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const userData = localStorage.getItem('user')
|
||||||
|
if (userData) {
|
||||||
|
try {
|
||||||
|
setUser(JSON.parse(userData))
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Parse user error:', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fetchGroups()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const fetchGroups = async () => {
|
||||||
|
setLoading(true)
|
||||||
|
const token = localStorage.getItem('token')
|
||||||
|
try {
|
||||||
|
// 获取我参与的认购群
|
||||||
|
const myRes = await fetch(`${API_BASE}/api/purchase/my-groups`, {
|
||||||
|
headers: token ? { 'Authorization': `Bearer ${token}` } : {}
|
||||||
|
})
|
||||||
|
const myData = await myRes.json()
|
||||||
|
setMyGroups(myData || [])
|
||||||
|
|
||||||
|
// 获取所有认购群
|
||||||
|
const allRes = await fetch(`${API_BASE}/api/purchase/groups`)
|
||||||
|
const allData = await allRes.json()
|
||||||
|
setAllGroups(allData || [])
|
||||||
|
} catch (e) {
|
||||||
|
console.error('获取认购群失败:', e)
|
||||||
|
}
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
const createGroup = async () => {
|
||||||
|
const token = localStorage.getItem('token')
|
||||||
|
if (!token) { alert('请先登录'); return }
|
||||||
|
if (!newGroup.name.trim()) { alert('请输入认购群名称'); return }
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${API_BASE}/api/purchase/groups`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${token}`,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(newGroup)
|
||||||
|
})
|
||||||
|
const data = await res.json()
|
||||||
|
if (res.ok) {
|
||||||
|
alert('创建成功!')
|
||||||
|
setShowCreate(false)
|
||||||
|
setNewGroup({ name: '', description: '' })
|
||||||
|
fetchGroups()
|
||||||
|
} else {
|
||||||
|
alert(data.detail || '创建失败')
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('创建失败:', e)
|
||||||
|
alert('创建失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const joinGroup = async (groupId) => {
|
||||||
|
const token = localStorage.getItem('token')
|
||||||
|
if (!token) { alert('请先登录'); return }
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${API_BASE}/api/purchase/groups/${groupId}/join`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Authorization': `Bearer ${token}` }
|
||||||
|
})
|
||||||
|
const data = await res.json()
|
||||||
|
if (res.ok) {
|
||||||
|
alert('加入成功!')
|
||||||
|
fetchGroups()
|
||||||
|
} else {
|
||||||
|
alert(data.detail || '加入失败')
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('加入失败:', e)
|
||||||
|
alert('加入失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const viewGroupDetail = async (groupId) => {
|
||||||
|
const token = localStorage.getItem('token')
|
||||||
|
try {
|
||||||
|
// 获取成员列表
|
||||||
|
const membersRes = await fetch(`${API_BASE}/api/purchase/groups/${groupId}/members`, {
|
||||||
|
headers: token ? { 'Authorization': `Bearer ${token}` } : {}
|
||||||
|
})
|
||||||
|
const membersData = await membersRes.json()
|
||||||
|
setGroupMembers(membersData || [])
|
||||||
|
|
||||||
|
// 获取藏品列表
|
||||||
|
const collectionsRes = await fetch(`${API_BASE}/api/purchase/groups/${groupId}/collections`, {
|
||||||
|
headers: token ? { 'Authorization': `Bearer ${token}` } : {}
|
||||||
|
})
|
||||||
|
const collectionsData = await collectionsRes.json()
|
||||||
|
setGroupCollections(collectionsData || [])
|
||||||
|
|
||||||
|
// 设置当前查看的群
|
||||||
|
const group = allGroups.find(g => g.id === groupId) || myGroups.find(g => g.id === groupId)
|
||||||
|
setSelectedGroup(group)
|
||||||
|
} catch (e) {
|
||||||
|
console.error('获取详情失败:', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const submitCollection = async () => {
|
||||||
|
const token = localStorage.getItem('token')
|
||||||
|
if (!token) { alert('请先登录'); return }
|
||||||
|
if (!selectedGroup) return
|
||||||
|
if (!newCollection.collection_name || !newCollection.price) {
|
||||||
|
alert('请填写藏品名称和价格'); return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${API_BASE}/api/purchase/groups/${selectedGroup.id}/collections`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${token}`,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
collection_name: newCollection.collection_name,
|
||||||
|
collection_code: newCollection.collection_code,
|
||||||
|
number: newCollection.number,
|
||||||
|
price: parseFloat(newCollection.price)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
const data = await res.json()
|
||||||
|
if (res.ok) {
|
||||||
|
alert('提交成功!')
|
||||||
|
setNewCollection({ collection_name: '', collection_code: '', number: '', price: '' })
|
||||||
|
viewGroupDetail(selectedGroup.id)
|
||||||
|
fetchGroups()
|
||||||
|
} else {
|
||||||
|
alert(data.detail || '提交失败')
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('提交失败:', e)
|
||||||
|
alert('提交失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeGroup = async () => {
|
||||||
|
const token = localStorage.getItem('token')
|
||||||
|
if (!token || !selectedGroup) return
|
||||||
|
|
||||||
|
if (!confirm('确定要结束该认购群吗?')) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${API_BASE}/api/purchase/groups/${selectedGroup.id}/close`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Authorization': `Bearer ${token}` }
|
||||||
|
})
|
||||||
|
const data = await res.json()
|
||||||
|
if (res.ok) {
|
||||||
|
alert('已结束认购群')
|
||||||
|
setSelectedGroup(null)
|
||||||
|
fetchGroups()
|
||||||
|
} else {
|
||||||
|
alert(data.detail || '操作失败')
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('操作失败:', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatMoney = (val) => {
|
||||||
|
if (!val || val === 0) return '¥0'
|
||||||
|
return '¥' + parseFloat(val).toLocaleString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 渲染认购群卡片
|
||||||
|
const renderGroupCard = (group, showJoin = false) => (
|
||||||
|
<div
|
||||||
|
key={group.id}
|
||||||
|
onClick={() => viewGroupDetail(group.id)}
|
||||||
|
style={{
|
||||||
|
background: 'linear-gradient(135deg, rgba(59,130,246,0.15) 0%, rgba(59,130,246,0.05) 100%)',
|
||||||
|
borderRadius: '12px',
|
||||||
|
padding: '16px',
|
||||||
|
border: '1px solid rgba(59,130,246,0.2)',
|
||||||
|
cursor: 'pointer',
|
||||||
|
marginBottom: '12px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||||
|
<div>
|
||||||
|
<div style={{ color: '#fff', fontSize: '16px', fontWeight: 'bold' }}>{group.name}</div>
|
||||||
|
<div style={{ color: 'rgba(255,255,255,0.5)', fontSize: '12px', marginTop: '4px' }}>
|
||||||
|
群主: {group.creator_name} · {group.total_members}人参与
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{showJoin && (
|
||||||
|
<button
|
||||||
|
onClick={(e) => { e.stopPropagation(); joinGroup(group.id) }}
|
||||||
|
style={{
|
||||||
|
background: '#3b82f6',
|
||||||
|
color: '#fff',
|
||||||
|
border: 'none',
|
||||||
|
borderRadius: '6px',
|
||||||
|
padding: '8px 16px',
|
||||||
|
fontSize: '13px',
|
||||||
|
cursor: 'pointer'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
加入
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div style={{ display: 'flex', gap: '16px', marginTop: '12px', color: 'rgba(255,255,255,0.7)', fontSize: '13px' }}>
|
||||||
|
<span>藏品: {group.total_collections}件</span>
|
||||||
|
<span>总价: {formatMoney(group.total_amount)}</span>
|
||||||
|
<span>均价: {formatMoney(group.avg_price)}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
// 群详情弹窗
|
||||||
|
if (selectedGroup) {
|
||||||
|
return (
|
||||||
|
<div style={{
|
||||||
|
minHeight: '100vh',
|
||||||
|
background: '#0f172a',
|
||||||
|
color: '#fff',
|
||||||
|
padding: '16px'
|
||||||
|
}}>
|
||||||
|
{/* 头部 */}
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', marginBottom: '20px' }}>
|
||||||
|
<button
|
||||||
|
onClick={() => setSelectedGroup(null)}
|
||||||
|
style={{
|
||||||
|
background: 'transparent',
|
||||||
|
border: 'none',
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: '24px',
|
||||||
|
cursor: 'pointer',
|
||||||
|
marginRight: '12px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
←
|
||||||
|
</button>
|
||||||
|
<div style={{ flex: 1 }}>
|
||||||
|
<div style={{ fontSize: '18px', fontWeight: 'bold' }}>{selectedGroup.name}</div>
|
||||||
|
<div style={{ fontSize: '12px', color: 'rgba(255,255,255,0.5)' }}>
|
||||||
|
群主: {selectedGroup.creator_name} · {selectedGroup.status === 'active' ? '进行中' : '已结束'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{selectedGroup.creator_id === user?.f99_90_id && selectedGroup.status === 'active' && (
|
||||||
|
<button
|
||||||
|
onClick={closeGroup}
|
||||||
|
style={{
|
||||||
|
background: '#ef4444',
|
||||||
|
color: '#fff',
|
||||||
|
border: 'none',
|
||||||
|
borderRadius: '6px',
|
||||||
|
padding: '8px 12px',
|
||||||
|
fontSize: '13px',
|
||||||
|
cursor: 'pointer'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
结束
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 统计卡片 */}
|
||||||
|
<div style={{
|
||||||
|
background: 'linear-gradient(135deg, rgba(245,158,11,0.15) 0%, rgba(245,158,11,0.05) 100%)',
|
||||||
|
borderRadius: '12px',
|
||||||
|
padding: '16px',
|
||||||
|
border: '1px solid rgba(245,158,11,0.2)',
|
||||||
|
marginBottom: '16px'
|
||||||
|
}}>
|
||||||
|
<div style={{ color: 'rgba(255,255,255,0.7)', fontSize: '13px', marginBottom: '8px' }}>统计</div>
|
||||||
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '12px', textAlign: 'center' }}>
|
||||||
|
<div>
|
||||||
|
<div style={{ color: '#fbbf24', fontSize: '20px', fontWeight: 'bold' }}>{selectedGroup.total_members}</div>
|
||||||
|
<div style={{ color: 'rgba(255,255,255,0.5)', fontSize: '11px' }}>参与人数</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div style={{ color: '#34d399', fontSize: '20px', fontWeight: 'bold' }}>{selectedGroup.total_collections}</div>
|
||||||
|
<div style={{ color: 'rgba(255,255,255,0.5)', fontSize: '11px' }}>认购数量</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div style={{ color: '#a78bfa', fontSize: '20px', fontWeight: 'bold' }}>{formatMoney(selectedGroup.avg_price)}</div>
|
||||||
|
<div style={{ color: 'rgba(255,255,255,0.5)', fontSize: '11px' }}>藏品均价</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style={{ marginTop: '12px', paddingTop: '12px', borderTop: '1px solid rgba(255,255,255,0.1)', textAlign: 'center' }}>
|
||||||
|
<span style={{ color: 'rgba(255,255,255,0.7)', fontSize: '13px' }}>总价: </span>
|
||||||
|
<span style={{ color: '#fff', fontSize: '16px', fontWeight: 'bold' }}>{formatMoney(selectedGroup.total_amount)}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 成员列表 */}
|
||||||
|
<div style={{ marginBottom: '16px' }}>
|
||||||
|
<div style={{ color: 'rgba(255,255,255,0.7)', fontSize: '14px', marginBottom: '12px' }}>参与成员</div>
|
||||||
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
|
||||||
|
{groupMembers.map(m => (
|
||||||
|
<div key={m.id} style={{
|
||||||
|
background: 'rgba(255,255,255,0.1)',
|
||||||
|
borderRadius: '20px',
|
||||||
|
padding: '6px 12px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: '6px'
|
||||||
|
}}>
|
||||||
|
<div style={{ width: '20px', height: '20px', borderRadius: '50%', background: '#3b82f6', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '10px' }}>
|
||||||
|
{m.user_name?.charAt(0) || '?'}
|
||||||
|
</div>
|
||||||
|
<span style={{ fontSize: '12px', color: '#fff' }}>{m.user_name}</span>
|
||||||
|
{m.role === 'creator' && <span style={{ fontSize: '10px', color: '#fbbf24' }}>👑</span>}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
{groupMembers.length === 0 && <div style={{ color: 'rgba(255,255,255,0.3)', fontSize: '13px' }}>暂无成员</div>}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 认购藏品列表 */}
|
||||||
|
<div>
|
||||||
|
<div style={{ color: 'rgba(255,255,255,0.7)', fontSize: '14px', marginBottom: '12px' }}>认购藏品</div>
|
||||||
|
{groupCollections.map(c => (
|
||||||
|
<div key={c.id} style={{
|
||||||
|
background: 'rgba(255,255,255,0.05)',
|
||||||
|
borderRadius: '8px',
|
||||||
|
padding: '12px',
|
||||||
|
marginBottom: '8px',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center'
|
||||||
|
}}>
|
||||||
|
<div>
|
||||||
|
<div style={{ color: '#fff', fontSize: '14px' }}>{c.collection_name}</div>
|
||||||
|
<div style={{ color: 'rgba(255,255,255,0.5)', fontSize: '12px' }}>
|
||||||
|
{c.number} · {c.user_name}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style={{ color: '#34d399', fontSize: '16px', fontWeight: 'bold' }}>
|
||||||
|
{formatMoney(c.price)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
{groupCollections.length === 0 && <div style={{ color: 'rgba(255,255,255,0.3)', fontSize: '13px', textAlign: 'center', padding: '20px' }}>暂无认购藏品</div>}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 提交认购藏品表单 */}
|
||||||
|
{selectedGroup.status === 'active' && (
|
||||||
|
<div style={{
|
||||||
|
position: 'fixed',
|
||||||
|
bottom: '20px',
|
||||||
|
left: '16px',
|
||||||
|
right: '16px',
|
||||||
|
background: '#1e293b',
|
||||||
|
borderRadius: '12px',
|
||||||
|
padding: '16px',
|
||||||
|
border: '1px solid rgba(255,255,255,0.1)'
|
||||||
|
}}>
|
||||||
|
<div style={{ color: '#fff', fontSize: '14px', marginBottom: '12px' }}>提交认购藏品</div>
|
||||||
|
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '8px', marginBottom: '12px' }}>
|
||||||
|
<input
|
||||||
|
value={newCollection.collection_name}
|
||||||
|
onChange={(e) => setNewCollection({...newCollection, collection_name: e.target.value})}
|
||||||
|
placeholder="藏品名称"
|
||||||
|
style={{
|
||||||
|
background: 'rgba(255,255,255,0.1)',
|
||||||
|
border: '1px solid rgba(255,255,255,0.2)',
|
||||||
|
borderRadius: '6px',
|
||||||
|
padding: '10px',
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: '13px'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
value={newCollection.number}
|
||||||
|
onChange={(e) => setNewCollection({...newCollection, number: e.target.value})}
|
||||||
|
placeholder="冠字号"
|
||||||
|
style={{
|
||||||
|
background: 'rgba(255,255,255,0.1)',
|
||||||
|
border: '1px solid rgba(255,255,255,0.2)',
|
||||||
|
borderRadius: '6px',
|
||||||
|
padding: '10px',
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: '13px'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '8px', marginBottom: '12px' }}>
|
||||||
|
<input
|
||||||
|
value={newCollection.collection_code}
|
||||||
|
onChange={(e) => setNewCollection({...newCollection, collection_code: e.target.value})}
|
||||||
|
placeholder="编号(可选)"
|
||||||
|
style={{
|
||||||
|
background: 'rgba(255,255,255,0.1)',
|
||||||
|
border: '1px solid rgba(255,255,255,0.2)',
|
||||||
|
borderRadius: '6px',
|
||||||
|
padding: '10px',
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: '13px'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
value={newCollection.price}
|
||||||
|
onChange={(e) => setNewCollection({...newCollection, price: e.target.value})}
|
||||||
|
placeholder="价格"
|
||||||
|
type="number"
|
||||||
|
style={{
|
||||||
|
background: 'rgba(255,255,255,0.1)',
|
||||||
|
border: '1px solid rgba(255,255,255,0.2)',
|
||||||
|
borderRadius: '6px',
|
||||||
|
padding: '10px',
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: '13px'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={submitCollection}
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
background: '#3b82f6',
|
||||||
|
color: '#fff',
|
||||||
|
border: 'none',
|
||||||
|
borderRadius: '8px',
|
||||||
|
padding: '12px',
|
||||||
|
fontSize: '14px',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
cursor: 'pointer'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
提交认购
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{
|
||||||
|
minHeight: '100vh',
|
||||||
|
background: '#0f172a',
|
||||||
|
color: '#fff',
|
||||||
|
padding: '16px'
|
||||||
|
}}>
|
||||||
|
{/* 头部 */}
|
||||||
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '20px' }}>
|
||||||
|
<div style={{ fontSize: '20px', fontWeight: 'bold' }}>我的认购/团购</div>
|
||||||
|
<button
|
||||||
|
onClick={() => setShowCreate(true)}
|
||||||
|
style={{
|
||||||
|
background: '#3b82f6',
|
||||||
|
color: '#fff',
|
||||||
|
border: 'none',
|
||||||
|
borderRadius: '8px',
|
||||||
|
padding: '10px 16px',
|
||||||
|
fontSize: '14px',
|
||||||
|
cursor: 'pointer'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
+ 创建认购群
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Tab切换 */}
|
||||||
|
<div style={{ display: 'flex', gap: '8px', marginBottom: '20px' }}>
|
||||||
|
<button
|
||||||
|
onClick={() => setActiveTab('my')}
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
background: activeTab === 'my' ? '#3b82f6' : 'rgba(255,255,255,0.1)',
|
||||||
|
color: '#fff',
|
||||||
|
border: 'none',
|
||||||
|
borderRadius: '8px',
|
||||||
|
padding: '12px',
|
||||||
|
fontSize: '14px',
|
||||||
|
cursor: 'pointer'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
我参与的 ({myGroups.length})
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setActiveTab('all')}
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
background: activeTab === 'all' ? '#3b82f6' : 'rgba(255,255,255,0.1)',
|
||||||
|
color: '#fff',
|
||||||
|
border: 'none',
|
||||||
|
borderRadius: '8px',
|
||||||
|
padding: '12px',
|
||||||
|
fontSize: '14px',
|
||||||
|
cursor: 'pointer'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
所有认购群 ({allGroups.length})
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 认购群列表 */}
|
||||||
|
{loading ? (
|
||||||
|
<div style={{ textAlign: 'center', padding: '40px', color: 'rgba(255,255,255,0.5)' }}>加载中...</div>
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
{(activeTab === 'my' ? myGroups : allGroups).map(group =>
|
||||||
|
renderGroupCard(group, activeTab === 'all')
|
||||||
|
)}
|
||||||
|
{(activeTab === 'my' ? myGroups : allGroups).length === 0 && (
|
||||||
|
<div style={{ textAlign: 'center', padding: '40px', color: 'rgba(255,255,255,0.3)' }}>
|
||||||
|
{activeTab === 'my' ? '您还没有参与任何认购群' : '暂无认购群'}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 创建认购群弹窗 */}
|
||||||
|
{showCreate && (
|
||||||
|
<div style={{
|
||||||
|
position: 'fixed',
|
||||||
|
top: 0, left: 0, right: 0, bottom: 0,
|
||||||
|
background: 'rgba(0,0,0,0.8)',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
zIndex: 100
|
||||||
|
}}>
|
||||||
|
<div style={{
|
||||||
|
background: '#1e293b',
|
||||||
|
borderRadius: '12px',
|
||||||
|
padding: '20px',
|
||||||
|
width: '90%',
|
||||||
|
maxWidth: '400px'
|
||||||
|
}}>
|
||||||
|
<div style={{ fontSize: '18px', fontWeight: 'bold', marginBottom: '16px' }}>创建认购群</div>
|
||||||
|
<input
|
||||||
|
value={newGroup.name}
|
||||||
|
onChange={(e) => setNewGroup({...newGroup, name: e.target.value})}
|
||||||
|
placeholder="认购群名称"
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
background: 'rgba(255,255,255,0.1)',
|
||||||
|
border: '1px solid rgba(255,255,255,0.2)',
|
||||||
|
borderRadius: '8px',
|
||||||
|
padding: '12px',
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: '14px',
|
||||||
|
marginBottom: '12px'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<textarea
|
||||||
|
value={newGroup.description}
|
||||||
|
onChange={(e) => setNewGroup({...newGroup, description: e.target.value})}
|
||||||
|
placeholder="描述(可选)"
|
||||||
|
rows={3}
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
background: 'rgba(255,255,255,0.1)',
|
||||||
|
border: '1px solid rgba(255,255,255,0.2)',
|
||||||
|
borderRadius: '8px',
|
||||||
|
padding: '12px',
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: '14px',
|
||||||
|
marginBottom: '16px',
|
||||||
|
resize: 'none'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div style={{ display: 'flex', gap: '8px' }}>
|
||||||
|
<button
|
||||||
|
onClick={() => setShowCreate(false)}
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
background: 'rgba(255,255,255,0.1)',
|
||||||
|
color: '#fff',
|
||||||
|
border: 'none',
|
||||||
|
borderRadius: '8px',
|
||||||
|
padding: '12px',
|
||||||
|
fontSize: '14px',
|
||||||
|
cursor: 'pointer'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
取消
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={createGroup}
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
background: '#3b82f6',
|
||||||
|
color: '#fff',
|
||||||
|
border: 'none',
|
||||||
|
borderRadius: '8px',
|
||||||
|
padding: '12px',
|
||||||
|
fontSize: '14px',
|
||||||
|
cursor: 'pointer'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
创建
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Purchase
|
||||||
Loading…
Reference in New Issue