From 4ae29eb4bffcde086662e00a8b5c4f7662912b92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B2=E8=BE=B0=E7=94=9F=E4=BA=A7?= Date: Wed, 15 Apr 2026 17:48:30 +0800 Subject: [PATCH] =?UTF-8?q?v1.2.97=20-=20=E5=AE=8C=E6=95=B4=E5=90=8C?= =?UTF-8?q?=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 - VERSION | 2 +- backend/app/routers/deal.py | 7 +- backend/app/routers/seek.py | 7 +- env.conf | 8 +++ frontend/VERSION | 1 + frontend/index.html | 2 +- frontend/src/pages/Add.jsx | 22 +++---- frontend/src/pages/List.jsx | 2 +- frontend/src/pages/news.py | 128 ++++++++++++++++++++++++++++++++++++ start.sh | 13 ++++ 11 files changed, 176 insertions(+), 19 deletions(-) create mode 100644 env.conf create mode 100644 frontend/VERSION create mode 100644 frontend/src/pages/news.py create mode 100755 start.sh 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后端服务已启动'