diff --git a/backend/app/routers/purchase.py b/backend/app/routers/purchase.py index a5478da..22c9322 100644 --- a/backend/app/routers/purchase.py +++ b/backend/app/routers/purchase.py @@ -36,17 +36,19 @@ class PurchaseGroupResponse(BaseModel): total_collections: int total_confirmed: int total_amount: float - avg_price: float + avg_price: Optional[float] = None created_at: Optional[datetime] class PurchaseCollectionCreate(BaseModel): - collection_name: str - number: str - grading: str - boss_name: str - price: float - source: str - paid: bool = False + collection_name: Optional[str] = None + collection_code: Optional[str] = None + number: Optional[str] = None + collection_code: Optional[str] = None + grading: Optional[str] = None + boss_name: Optional[str] = None + price: Optional[float] = None + source: Optional[str] = None + paid: Optional[bool] = False class PurchaseCollectionUpdate(BaseModel): collection_name: Optional[str] = None @@ -65,11 +67,12 @@ class PurchaseCollectionResponse(BaseModel): user_name: Optional[str] collection_name: Optional[str] collection_code: Optional[str] - number: str - grading: str - boss_name: str - price: float - source: str + number: Optional[str] = None + collection_code: Optional[str] = None + grading: Optional[str] = None + boss_name: Optional[str] = None + price: Optional[float] = None + source: Optional[str] = None paid: bool status: str submit_date: Optional[datetime] @@ -123,12 +126,18 @@ def get_my_groups( db: Session = Depends(get_db) ): """获取我参与的认购群""" + if not current_user: + return [] + member_groups = db.query(PurchaseMember).filter( PurchaseMember.user_id == current_user.f99_90_id, PurchaseMember.status == "approved" ).all() group_ids = [m.group_id for m in member_groups] + if not group_ids: + return [] + groups = db.query(PurchaseGroup).filter( PurchaseGroup.id.in_(group_ids) ).all() @@ -370,16 +379,8 @@ def add_collection( if not current_user: 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="来源必填") + # All fields now optional - frontend will send what it has + # No validation needed as all fields are Optional in schema group = db.query(PurchaseGroup).filter(PurchaseGroup.id == group_id).first() if not group: diff --git a/config/VERSION.json b/config/VERSION.json index 6b8738e..2facab0 100644 --- a/config/VERSION.json +++ b/config/VERSION.json @@ -6,7 +6,7 @@ "version": "0.1.1", "pages": { "Home": "0.1.0", - "Purchase": "0.1.1" + "Purchase": "0.1.2" } }, "backend": { diff --git a/frontend/src/pages/Purchase.jsx b/frontend/src/pages/Purchase.jsx index f0ec259..84b2dfc 100644 --- a/frontend/src/pages/Purchase.jsx +++ b/frontend/src/pages/Purchase.jsx @@ -15,11 +15,12 @@ function Purchase() { const [allGroups, setAllGroups] = useState([]) const [showCreate, setShowCreate] = useState(false) const [selectedGroup, setSelectedGroup] = useState(null) + const [editCollection, setEditCollection] = useState(null) const [groupMembers, setGroupMembers] = useState([]) const [groupCollections, setGroupCollections] = useState([]) const [showCollectionForm, setShowCollectionForm] = useState(false) const [newGroup, setNewGroup] = useState({ name: '', description: '' }) - const [newCollection, setNewCollection] = useState({ collection_name: '', collection_code: '', number: '', price: '' }) + const [newCollection, setNewCollection] = useState({ number: 'J0________', price: '' }) const [loading, setLoading] = useState(true) const [activeTab, setActiveTab] = useState('my') // my/all @@ -132,12 +133,43 @@ function Purchase() { } } + const updateCollection = async () => { + const token = localStorage.getItem('token') + if (!token || !editCollection) { return } + + try { + const res = await fetch(`${API_BASE}/api/purchase/groups/${selectedGroup.id}/collections/${editCollection.id}`, { + method: 'PUT', + headers: { + 'Authorization': `Bearer ${token}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + grading: editCollection.grading, + boss_name: editCollection.boss_name, + price: editCollection.price ? parseFloat(editCollection.price) : null, + source: editCollection.source, + paid: editCollection.paid + }) + }) + if (res.ok) { + alert('更新成功!') + setEditCollection(null) + viewGroupDetail(selectedGroup.id) + } else { + alert('更新失败') + } + } 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 + if (!newCollection.number || !newCollection.price) { + alert('请填写完整信息'); return } try { @@ -148,16 +180,18 @@ function Purchase() { 'Content-Type': 'application/json' }, body: JSON.stringify({ - collection_name: newCollection.collection_name, - collection_code: newCollection.collection_code, number: newCollection.number, - price: parseFloat(newCollection.price) + grading: newCollection.grading, + boss_name: newCollection.boss_name, + price: parseFloat(newCollection.price), + source: newCollection.source, + paid: newCollection.paid || false }) }) const data = await res.json() if (res.ok) { alert('提交成功!') - setNewCollection({ collection_name: '', collection_code: '', number: '', price: '' }) + setNewCollection({ number: 'J0________', price: '' }) viewGroupDetail(selectedGroup.id) fetchGroups() } else { @@ -362,19 +396,33 @@ function Purchase() { background: 'rgba(255,255,255,0.05)', borderRadius: '8px', padding: '12px', - marginBottom: '8px', - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center' + marginBottom: '8px' }}> -