diff --git a/.gitignore b/.gitignore
index fb26bf8..1fb5316 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,6 +32,3 @@ Thumbs.db
.vscode/
*.swp
*.swo
-
-# 版本文件
-VERSION
diff --git a/VERSION b/VERSION
index 6899847..ce6248b 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-VERSION=1.2.95
+VERSION=1.2.97
diff --git a/backend/app/routers/deal.py b/backend/app/routers/deal.py
index 29bcb3d..314f3ca 100644
--- a/backend/app/routers/deal.py
+++ b/backend/app/routers/deal.py
@@ -89,13 +89,18 @@ def get_deal_list(
status: str = Query("active"),
deal_date: Optional[str] = Query(None),
page: int = Query(1, ge=1),
- page_size: int = Query(20, ge=1, le=500),
+ page_size: int = Query(20, ge=1, le=1000),
+ user_only: bool = Query(False), # 是否只查看自己的
current_user: Optional = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""获取成交行情列表"""
query = db.query(DealInfo).filter(DealInfo.status == status)
+ # 我的行情:只查看自己的(管理员也只看自己的)
+ if user_only and current_user:
+ query = query.filter(DealInfo.user_id == current_user.f99_90_id)
+
# 成交日期过滤
if deal_date:
query = query.filter(DealInfo.deal_date == deal_date)
diff --git a/backend/app/routers/seek.py b/backend/app/routers/seek.py
index 77c5236..76ff298 100644
--- a/backend/app/routers/seek.py
+++ b/backend/app/routers/seek.py
@@ -59,13 +59,18 @@ class SeekInfoResponse(BaseModel):
def get_seek_list(
status: str = Query("active"),
page: int = Query(1, ge=1),
- page_size: int = Query(20, ge=1, le=100),
+ page_size: int = Query(20, ge=1, le=1000),
+ user_only: bool = Query(False),
current_user: Optional = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""获取寻配号列表"""
query = db.query(SeekInfo).filter(SeekInfo.status == status)
+ # 我的寻配号:只查看自己的
+ if user_only and current_user:
+ query = query.filter(SeekInfo.user_id == current_user.f99_90_id)
+
# 排序
query = query.order_by(SeekInfo.created_at.desc())
diff --git a/env.conf b/env.conf
new file mode 100644
index 0000000..3f35852
--- /dev/null
+++ b/env.conf
@@ -0,0 +1,8 @@
+DATABASE_URL=postgresql://jiachenlong:Passwd1%403@pgm-bp1t5w248t7s1pvr.pg.rds.aliyuncs.com:5432/jiachenlong
+SECRET_KEY=production-secret-key-b-env
+OSS_ACCESS_KEY_ID=LTAI5t6HUnpFBLEK9194kPVG
+OSS_ACCESS_KEY_SECRET=LEr4Q8yRxb8D5b24cKfCwlt4MMoke1
+SMS_ACCESS_KEY_ID=LTAI5tQAx5niD7JQVqGE5acE
+SMS_ACCESS_KEY_SECRET=QsQFAEKBkaNynIoKyvdIi3BUyWVZu1
+SMS_SIGN_NAME=苏州算力
+SMS_TEMPLATE_CODE=SMS_501590956
diff --git a/frontend/VERSION b/frontend/VERSION
new file mode 100644
index 0000000..ce6248b
--- /dev/null
+++ b/frontend/VERSION
@@ -0,0 +1 @@
+VERSION=1.2.97
diff --git a/frontend/index.html b/frontend/index.html
index e3a4d95..72cb774 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -4,7 +4,7 @@
-
甲辰收藏 v=1.2.81
+ 甲辰收藏 v=1.2.97
diff --git a/frontend/src/pages/Add.jsx b/frontend/src/pages/Add.jsx
index 5fde9a7..09a9208 100644
--- a/frontend/src/pages/Add.jsx
+++ b/frontend/src/pages/Add.jsx
@@ -844,20 +844,21 @@ export default function Add() {
const sizeType = (dealForm.packaging === '标十' && ['01','11','21','31','41','51','61','71','81','91'].includes(tailNumber)) ? '小号' :
(dealForm.packaging === '标百' && ['001','011','021','031','041','051','061','071','081','091'].includes(rawSerial.slice(-3))) ? '小号' : '大号'
- const response = await fetch(`${API_BASE}/api/information/`, {
+ const response = await fetch(`${API_BASE}/api/deal`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
- info_type: 'deal',
title: `${normalizedSerial}-¥${dealForm.price}`,
content: `分类: ${dealForm.category || '未分类'}\n尾号: ${tailNumber || '-'}\n大小号: ${sizeType || '-'}\n包装: ${dealForm.packaging}\n平台: ${dealForm.platform}\n价格: ¥${dealForm.price}\n出售者: ${dealForm.seller || '-'}\n购买者: ${dealForm.buyer || '-'}\n日期: ${dealForm.date}\n评级: ${dealForm.gradingCompany ? dealForm.gradingCompany + ' ' + dealForm.gradingScore : '未评级'}`,
deal_price: parseFloat(dealForm.price),
deal_date: dealForm.date,
packaging: dealForm.packaging,
category: dealForm.category,
- is_graded: !!dealForm.gradingCompany,
- grading_company: dealForm.gradingCompany || '',
- grading_score: dealForm.gradingScore || ''
+ tail_number: tailNumber,
+ size_type: sizeType,
+ platform: dealForm.platform,
+ seller: dealForm.seller || '',
+ buyer: dealForm.buyer || ''
})
})
if (response.ok) {
@@ -1045,21 +1046,20 @@ export default function Add() {
tail_number = item.packaging === '标十' ? digits.slice(-2) : digits.slice(-3)
size_type = (item.packaging === '标十' && ['01','11','21','31','41','51'].includes(tail_number)) || (item.packaging === '标百' && ['101','201','301','401','501'].includes(tail_number)) ? '小号' : '大号'
}
- await fetch(`${API_BASE}/api/information/`, {
+ await fetch(`${API_BASE}/api/deal`, {
method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
- info_type: 'deal',
title: `${item.serial}-¥${item.price}`,
content: `分类: ${item.category || '-'}\n尾号: ${tail_number || '-'}\n大小号: ${size_type || '-'}\n包装: ${item.packaging || '单张'}\n平台: ${item.platform || '-'}\n价格: ¥${item.price}\n出售者: ${item.seller || '-'}\n购买者: ${item.buyer || '-'}\n日期: ${item.deal_date || new Date().toISOString().split('T')[0]}`,
deal_price: parseFloat(item.price),
deal_date: item.deal_date || new Date().toISOString().split('T')[0],
packaging: item.packaging || '单张',
- is_graded: item.is_graded || false,
- grading_company: item.grading_company || '',
- grading_score: item.grade || '',
category: item.category || '',
tail_number: tail_number,
- size_type: size_type
+ size_type: size_type,
+ platform: item.platform || '-',
+ seller: item.seller || '',
+ buyer: item.buyer || ''
})
})
count++
diff --git a/frontend/src/pages/List.jsx b/frontend/src/pages/List.jsx
index a7deae7..b8b5ff8 100644
--- a/frontend/src/pages/List.jsx
+++ b/frontend/src/pages/List.jsx
@@ -79,7 +79,7 @@ export default function List() {
}
try {
const user = JSON.parse(userStr)
- const res = await fetch(`${API_BASE}/api/deal/list?page_size=500`, {
+ const res = await fetch(`${API_BASE}/api/deal/list?user_only=true&page_size=500`, {
headers: { 'Authorization': 'Bearer ' + token }
})
const data = await res.json()
diff --git a/frontend/src/pages/news.py b/frontend/src/pages/news.py
new file mode 100644
index 0000000..c969522
--- /dev/null
+++ b/frontend/src/pages/news.py
@@ -0,0 +1,128 @@
+from fastapi import APIRouter, Depends, HTTPException, Query
+from sqlalchemy import Table, MetaData
+from sqlalchemy.orm import Session
+from pydantic import BaseModel
+from typing import Optional, List
+from datetime import datetime, date
+from app.core.database import get_db, engine
+from app.models.models import User
+from app.routers.auth import get_current_user
+
+router = APIRouter(prefix="/api/news", tags=["资讯"])
+metadata = MetaData()
+
+# 分类表
+categories_table = Table('news_categories', metadata, autoload_with=engine)
+news_table = Table('news', metadata, autoload_with=engine)
+user_posts_table = Table('user_posts', metadata, autoload_with=engine)
+users_table = Table('users', metadata, autoload_with=engine)
+deals_table = Table('deals', metadata, autoload_with=engine)
+notifications_table = Table('notifications', metadata, autoload_with=engine)
+
+# ============ 获取分类 ============
+@router.get("/categories")
+def get_categories(db: Session = Depends(get_db)):
+ results = db.query(categories_table).order_by(categories_table.c.sort_order).all()
+ return [dict(r._mapping) for r in results]
+
+# ============ 获取资讯 ============
+@router.get("")
+def get_news(
+ category_id: Optional[int] = None,
+ page: int = 1,
+ limit: int = 20,
+ db: Session = Depends(get_db)
+):
+ query = db.query(news_table)
+ if category_id:
+ query = query.filter(news_table.c.category_id == category_id)
+ offset = (page - 1) * limit
+ results = query.order_by(news_table.c.created_at.desc()).offset(offset).limit(limit).all()
+ return [dict(r._mapping) for r in results]
+
+# ============ 获取用户发布 ============
+@router.get("/posts")
+def get_posts(
+ post_type: Optional[str] = None,
+ status: str = "active",
+ page: int = 1,
+ limit: int = 20,
+ db: Session = Depends(get_db)
+):
+ query = db.query(user_posts_table).filter(user_posts_table.c.status == status)
+ if post_type:
+ query = query.filter(user_posts_table.c.post_type == post_type)
+ offset = (page - 1) * limit
+ results = query.order_by(user_posts_table.c.created_at.desc()).offset(offset).limit(limit).all()
+ return [dict(r._mapping) for r in results]
+
+# ============ 创建发布 ============
+class PostCreate(BaseModel):
+ post_type: str
+ title: str
+ content: Optional[str] = None
+ zodiac_type: Optional[str] = None
+ packaging: Optional[str] = None
+
+@router.post("/posts")
+def create_post(
+ post: PostCreate,
+ current_user: User = Depends(get_current_user),
+ db: Session = Depends(get_db)
+):
+ result = db.execute(user_posts_table.insert().values(
+ user_id=current_user.f99_90_id,
+ post_type=post.post_type,
+ title=post.title,
+ content=post.content,
+ zodiac_type=post.zodiac_type,
+ packaging=post.packaging,
+ status="pending"
+ ))
+ db.commit()
+ return {"success": True, "id": result.inserted_primary_key[0]}
+
+# ============ 成交数据 ============
+@router.get("/deals")
+def get_deals(
+ zodiac_type: Optional[str] = None,
+ limit: int = 20,
+ db: Session = Depends(get_db)
+):
+ query = db.query(deals_table)
+ if zodiac_type:
+ query = query.filter(deals_table.c.zodiac_type == zodiac_type)
+ results = query.order_by(deals_table.c.deal_date.desc()).limit(limit).all()
+ return [dict(r._mapping) for r in results]
+
+# ============ 通知 ============
+@router.get("/notifications")
+def get_notifications(limit: int = 10, db: Session = Depends(get_db)):
+ results = db.query(notifications_table).filter(
+ notifications_table.c.is_published == True
+ ).order_by(notifications_table.c.created_at.desc()).limit(limit).all()
+ return [dict(r._mapping) for r in results]
+
+# ============ 首页数据 ============
+@router.get("/home")
+def get_home(db: Session = Depends(get_db)):
+ # 推荐发布
+ posts = db.query(user_posts_table).filter(
+ user_posts_table.c.status == "active"
+ ).order_by(user_posts_table.c.created_at.desc()).limit(10).all()
+
+ # 成交
+ deals = db.query(deals_table).order_by(
+ deals_table.c.deal_date.desc()
+ ).limit(10).all()
+
+ # 通知
+ notices = db.query(notifications_table).filter(
+ notifications_table.c.is_published == True
+ ).order_by(notifications_table.c.created_at.desc()).limit(5).all()
+
+ return {
+ "posts": [dict(p._mapping) for p in posts],
+ "deals": [dict(d._mapping) for d in deals],
+ "notices": [dict(n._mapping) for n in notices]
+ }
diff --git a/start.sh b/start.sh
new file mode 100755
index 0000000..70bca6b
--- /dev/null
+++ b/start.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+cd /root/jiachenlong/backend
+export DATABASE_URL='postgresql://jiachenlong:Passwd1%403@pgm-bp1t5w248t7s1pvr.pg.rds.aliyuncs.com:5432/jiachenlong'
+export SECRET_KEY=production-secret-key-b-env-20260401
+export OSS_ACCESS_KEY_ID=LTAI5t6HUnpFBLEK9194kPVG
+export OSS_ACCESS_KEY_SECRET=LEr4Q8yRxb8D5b24cKfCwlt4MMoke1
+export SMS_ACCESS_KEY_ID=LTAI5t86bc1nNKVNyYv4Af6x
+export SMS_ACCESS_KEY_SECRET=92EVAIE3GECr214c9UaSF6TSYJvDLY
+export SMS_SIGN_NAME=苏州双人旁
+export SMS_TEMPLATE_CODE=SMS_505015231
+export DASHSCOPE_API_KEY=sk-9389024a37da4f7bb455ac9a6b28776f
+nohup python3 -m uvicorn app.main:app --host 0.0.0.0 --port 3000 --workers 1 > /tmp/uvicorn.log 2>&1 &
+echo 'B后端服务已启动'