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 ? '已有账号?立即登录' : '没有账号?立即注册' }}
-
+
或
-