diff --git a/frontend/components.d.ts b/frontend/components.d.ts index 70802f1..3785345 100644 --- a/frontend/components.d.ts +++ b/frontend/components.d.ts @@ -17,21 +17,14 @@ declare module 'vue' { VanCell: typeof import('vant/es')['Cell'] VanCellGroup: typeof import('vant/es')['CellGroup'] VanCheckbox: typeof import('vant/es')['Checkbox'] - VanDropdownItem: typeof import('vant/es')['DropdownItem'] - VanDropdownMenu: typeof import('vant/es')['DropdownMenu'] VanEmpty: typeof import('vant/es')['Empty'] VanField: typeof import('vant/es')['Field'] - VanGrid: typeof import('vant/es')['Grid'] - VanGridItem: typeof import('vant/es')['GridItem'] VanIcon: typeof import('vant/es')['Icon'] - VanImage: typeof import('vant/es')['Image'] VanLoading: typeof import('vant/es')['Loading'] VanNoticeBar: typeof import('vant/es')['NoticeBar'] VanPopup: typeof import('vant/es')['Popup'] VanPullRefresh: typeof import('vant/es')['PullRefresh'] VanSearch: typeof import('vant/es')['Search'] - VanTabbar: typeof import('vant/es')['Tabbar'] - VanTabbarItem: typeof import('vant/es')['TabbarItem'] VanTag: typeof import('vant/es')['Tag'] } } diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index dc6fbe5..9148212 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -14,3 +14,37 @@ apiClient.interceptors.request.use((config) => { } return config }) + +apiClient.interceptors.response.use( + (response) => response, + (error) => { + if (error?.response?.status !== 401) { + return Promise.reject(error) + } + + const requestUrl = error.config?.url || '' + const isAdminRequest = requestUrl.startsWith('/admin') + const currentPath = window.location.pathname + window.location.search + + if (isAdminRequest) { + localStorage.removeItem('admin_access_token') + localStorage.removeItem('admin_refresh_token') + if (!window.location.pathname.startsWith('/admin/login')) { + window.location.assign('/admin/login') + } + return Promise.reject(error) + } + + localStorage.removeItem('access_token') + localStorage.removeItem('refresh_token') + localStorage.removeItem('user_id') + + if (!window.location.pathname.startsWith('/m/login') && !window.location.pathname.startsWith('/m/register')) { + const redirect = encodeURIComponent(currentPath) + const loginPath = window.location.pathname.startsWith('/m') ? '/m/login' : '/login' + window.location.assign(`${loginPath}?redirect=${redirect}`) + } + + return Promise.reject(error) + }, +) diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index 8123e82..b746c69 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -40,32 +40,32 @@ const router = createRouter({ path: "/m/messages", name: "mobile-messages", component: () => import("@/views/mobile/MobileMessagesView.vue"), - meta: { layout: "blank" }, + meta: { layout: "blank", requiresAuth: true }, }, { path: "/m/realname", name: "mobile-realname", component: () => import("@/views/mobile/MobileRealnameView.vue"), - meta: { layout: "blank" }, + meta: { layout: "blank", requiresAuth: true }, }, { path: "/m/profile", name: "mobile-profile", component: () => import("@/views/mobile/MobileProfileView.vue"), - meta: { layout: "blank" }, + meta: { layout: "blank", requiresAuth: true }, }, { path: "/m/orders", name: "mobile-orders", component: () => import("@/views/mobile/MobileOrdersView.vue"), - meta: { layout: "blank" }, + meta: { layout: "blank", requiresAuth: true }, }, { path: "/m/seller/listings/create", name: "mobile-seller-listing-create", component: () => import("@/views/mobile/MobileSellerListingCreateView.vue"), - meta: { layout: "blank" }, + meta: { layout: "blank", requiresAuth: true }, }, { path: "/", @@ -217,6 +217,10 @@ router.beforeEach((to) => { return { path: toMobilePath(to.path), query: to.query, hash: to.hash }; } + if (to.meta.requiresAuth && !localStorage.getItem("access_token")) { + return { path: "/m/login", query: { redirect: to.fullPath } }; + } + if ( to.path === "/admin/login" && localStorage.getItem("admin_access_token") diff --git a/frontend/src/views/mobile/MobileLoginView.vue b/frontend/src/views/mobile/MobileLoginView.vue index 7a42c55..bef6ae9 100644 --- a/frontend/src/views/mobile/MobileLoginView.vue +++ b/frontend/src/views/mobile/MobileLoginView.vue @@ -1,12 +1,13 @@ - - - - 锤 - 登录大锤商行 - 登录后查看订单、管理发布、提现余额,并享受平台担保交易服务。 - - 立即登录 - - - 担保交易 - 订单留痕 - 安全交接 - - - - - + @@ -267,64 +247,6 @@ function goToLogin() { padding: 0 0 60px; } -/* ========== 未登录区 - 自定义卡片 ========== */ -.guest-card { - text-align: center; - padding: 34px 26px; - margin: 12px; - border-radius: 16px; - background: #fff; - box-shadow: 0 8px 26px rgba(24, 30, 45, 0.06); -} - -.guest-card h1 { - margin: 18px 0 0; - font-size: 22px; - font-weight: 900; - color: #1a202c; -} - -.guest-card p { - margin: 10px 0 0; - font-size: 14px; - color: #667386; - line-height: 1.7; -} - -.guest-logo { - display: grid; - width: 74px; - height: 74px; - margin: 0 auto; - place-items: center; - border-radius: 22px; - background: #1477ff; - color: #fff; - font-size: 30px; - font-weight: 900; -} - -.guest-login-btn { - margin-top: 20px; - border-radius: 13px; - background: #1477ff; - border-color: transparent; - font-size: 16px; - font-weight: 900; - height: 48px; -} - -.guest-benefits { - display: flex; - justify-content: center; - gap: 8px; - margin-top: 16px; -} - -.guest-benefits :deep(.van-tag) { - font-weight: 800; -} - /* ========== 已登录区 - Hero蓝色横幅 ========== */ .profile-hero { position: relative; diff --git a/frontend/src/views/mobile/MobileRegisterView.vue b/frontend/src/views/mobile/MobileRegisterView.vue index 949491b..9807f6b 100644 --- a/frontend/src/views/mobile/MobileRegisterView.vue +++ b/frontend/src/views/mobile/MobileRegisterView.vue @@ -1,12 +1,13 @@
登录后查看订单、管理发布、提现余额,并享受平台担保交易服务。