diff --git a/backend/app/api/v1/auth.py b/backend/app/api/v1/auth.py index d1d2394..452e659 100644 --- a/backend/app/api/v1/auth.py +++ b/backend/app/api/v1/auth.py @@ -82,7 +82,7 @@ async def login( @router.post("/login/guest") async def guest_login(): - guest_id = f"guest_{uuid.uuid4().hex[:12]}" + guest_id = str(uuid.uuid4()) access_token = create_access_token( {"sub": guest_id, "tier": "guest", "role": "guest", "is_guest": True}, expires_delta=timedelta(hours=24) @@ -109,8 +109,18 @@ async def refresh(data: RefreshRequest): if not payload or payload.get("type") != "refresh": raise HTTPException(status_code=401, detail="Invalid refresh token") + # 保留游客/角色等信息 + extra = {} + if payload.get("is_guest"): + extra = {"is_guest": True, "tier": "guest", "role": "guest"} + else: + extra = { + "tier": payload.get("tier", "free"), + "role": payload.get("role", "user"), + } + return { - "access_token": create_access_token({"sub": payload["sub"]}), + "access_token": create_access_token({"sub": payload["sub"], **extra}), "token_type": "bearer", } @@ -127,6 +137,18 @@ async def get_me( if not payload: raise HTTPException(status_code=401, detail="Invalid token") + if payload.get("is_guest"): + return { + "id": payload["sub"], + "phone": None, + "username": "游客用户", + "tier": "guest", + "role": "guest", + "is_guest": True, + "settings": {}, + "created_at": None, + } + result = await db.execute(select(User).where(User.id == payload["sub"])) user = result.scalar_one_or_none() if not user: diff --git a/backend/app/api/v1/deps.py b/backend/app/api/v1/deps.py index 2771ab7..9fb9fb3 100644 --- a/backend/app/api/v1/deps.py +++ b/backend/app/api/v1/deps.py @@ -2,6 +2,7 @@ from fastapi import HTTPException, Depends, Header from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials from app.core.security import decode_token from typing import Optional +import uuid security = HTTPBearer(auto_error=False) @@ -23,7 +24,16 @@ async def get_current_user_id( if not payload: raise HTTPException(status_code=401, detail="Invalid or expired token") - return payload.get("sub") + user_id = payload.get("sub") + if not user_id: + raise HTTPException(status_code=401, detail="Invalid token payload") + + try: + uuid.UUID(user_id) + except (ValueError, AttributeError): + raise HTTPException(status_code=401, detail="Token expired, please login again") + + return user_id async def get_current_user( diff --git a/backend/app/main.py b/backend/app/main.py index f954b7f..031da08 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -31,11 +31,12 @@ app = FastAPI( version="1.0.0", docs_url="/docs", redoc_url="/redoc", + debug=settings.DEBUG, ) app.add_middleware( CORSMiddleware, - allow_origins=[settings.FRONTEND_URL, "*"], + allow_origins=[settings.FRONTEND_URL], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], diff --git a/uni-app/src/App.vue b/uni-app/src/App.vue index 5ad713b..5ec656c 100644 --- a/uni-app/src/App.vue +++ b/uni-app/src/App.vue @@ -20,26 +20,12 @@ html, body, #app { width: 100%; } -/* Fix: make uni-page scrollable and properly sized for fixed tabbar */ +/* Let uni-app framework manage layout for native tabbar */ uni-page { - height: calc(100% - 50px) !important; overflow-y: auto !important; - overflow-x: hidden !important; - -webkit-overflow-scrolling: touch !important; } -uni-page-body, uni-page-wrapper { +uni-page-body { overflow-y: auto !important; - overflow-x: hidden !important; - -webkit-overflow-scrolling: touch !important; -} - -/* Ensure the page head doesn't block scrolling */ -uni-page-head { - flex-shrink: 0; -} - -/* The uni-tabbar is already position:fixed by the framework */ -uni-tabbar { - z-index: 999 !important; + min-height: 100% !important; } diff --git a/uni-app/src/pages.json b/uni-app/src/pages.json index 12297b4..c2ef0c4 100644 --- a/uni-app/src/pages.json +++ b/uni-app/src/pages.json @@ -105,7 +105,7 @@ "backgroundColor": "#f5f5f5" }, "tabBar": { - "custom": true, + "custom": false, "color": "#666666", "selectedColor": "#1890ff", "backgroundColor": "#ffffff", diff --git a/uni-app/src/pages/index/index.vue b/uni-app/src/pages/index/index.vue index 77530b7..d572556 100644 --- a/uni-app/src/pages/index/index.vue +++ b/uni-app/src/pages/index/index.vue @@ -94,20 +94,28 @@ - 🔤 - 翻译 + + + + 智能翻译 - 👥 - 客户 + + + + 客户管理 - 📢 - 营销 + + + + 营销文案 - 📄 - 报价 + + + + 报价单 @@ -716,39 +724,6 @@ const copyTryResult = () => { padding: 40rpx; } -.quick-actions { - display: flex; - justify-content: space-around; - background: #fff; - border-radius: 16rpx; - padding: 30rpx; -} - -.action-item { - display: flex; - flex-direction: column; - align-items: center; -} - -.action-icon { - width: 80rpx; - height: 80rpx; - background: #e6f7ff; - color: #1890ff; - border-radius: 16rpx; - display: flex; - align-items: center; - justify-content: center; - font-size: 32rpx; - font-weight: 600; - margin-bottom: 12rpx; -} - -.action-text { - font-size: 24rpx; - color: #666; -} - .followup-card { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 16rpx; @@ -776,6 +751,42 @@ const copyTryResult = () => { margin-top: 12rpx; } +.quick-actions { + display: flex; + background: #fff; + border-radius: 16rpx; + padding: 20rpx 16rpx; + margin-bottom: 20rpx; + justify-content: space-around; +} + +.action-item { + display: flex; + flex-direction: column; + align-items: center; + gap: 8rpx; + cursor: pointer; +} + +.action-icon-wrap { + width: 72rpx; + height: 72rpx; + border-radius: 36rpx; + display: flex; + align-items: center; + justify-content: center; +} + +.action-icon-text { + font-size: 30rpx; + font-weight: bold; +} + +.action-label { + font-size: 22rpx; + color: #666; +} + .more-section { background: #fff; border-radius: 16rpx; diff --git a/uni-app/src/pages/login/login.vue b/uni-app/src/pages/login/login.vue index ab7ee13..20981e1 100644 --- a/uni-app/src/pages/login/login.vue +++ b/uni-app/src/pages/login/login.vue @@ -83,13 +83,13 @@ {{ isRegister ? '已有账号?立即登录' : '没有账号?立即注册' }} - + - @@ -120,6 +120,11 @@ const isRegister = ref(false) const loading = ref(false) const error = ref('') const showForm = ref(false) +const isWechatAvailable = ref(false) + +// #ifdef MP-WEIXIN +isWechatAvailable.value = true +// #endif const toggleMode = () => { isRegister.value = !isRegister.value diff --git a/uni-app/src/utils/api.js b/uni-app/src/utils/api.js index 4f20461..edaf92e 100644 --- a/uni-app/src/utils/api.js +++ b/uni-app/src/utils/api.js @@ -1,4 +1,4 @@ -export const BASE_URL = 'http://localhost:8000/api/v1' +export const BASE_URL = '/api/v1' const getAuthHeader = () => { const token = uni.getStorageSync('token')