From 26ee082b959238df6a3b3dea70dcb258a6d8febe Mon Sep 17 00:00:00 2001 From: yml Date: Mon, 25 May 2026 09:10:08 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E8=87=AA=E9=80=82?= =?UTF-8?q?=E5=BA=94=E8=B7=AF=E7=94=B1=E5=88=87=E6=8D=A2=EF=BC=8C=E6=A0=B9?= =?UTF-8?q?=E6=8D=AE=20User-Agent=20=E5=8F=8A=E5=B1=8F=E5=B9=95=E5=A4=A7?= =?UTF-8?q?=E5=B0=8F=E8=87=AA=E5=8A=A8=E5=AF=BC=E8=88=AA=20PC/Mobile=20?= =?UTF-8?q?=E8=A7=86=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/router/index.ts | 16 ++++++-- frontend/src/router/mobileHost.ts | 66 +++++++++++++++++++++++++++++-- 2 files changed, 76 insertions(+), 6 deletions(-) diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index c0d34c4..91da7a9 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -5,7 +5,7 @@ import { useSessionStore } from '@/stores/session' import { getAccessToken, getLoginPath } from '@/utils/authStorage' import { accountRoutes } from './accountRoutes' import { adminRoutes } from './adminRoutes' -import { isMobileHost, toMobilePath } from './mobileHost' +import { isMobileHost, isMobileDevice, getMobilePath, getPcPath } from './mobileHost' import { mobileRoutes } from './mobileRoutes' import { publicRoutes } from './publicRoutes' import { sellerRoutes } from './sellerRoutes' @@ -22,8 +22,18 @@ const router = createRouter({ }) router.beforeEach(async (to) => { - if (isMobileHost() && to.path !== toMobilePath(to.path)) { - return { path: toMobilePath(to.path), query: to.query, hash: to.hash } + const isMobile = isMobileHost() || isMobileDevice() + + if (isMobile) { + const targetPath = getMobilePath(to.path) + if (to.path !== targetPath) { + return { path: targetPath, query: to.query, hash: to.hash } + } + } else { + const targetPath = getPcPath(to.path) + if (to.path !== targetPath) { + return { path: targetPath, query: to.query, hash: to.hash } + } } if (to.meta.requiresAuth) { diff --git a/frontend/src/router/mobileHost.ts b/frontend/src/router/mobileHost.ts index 27156fa..766adb8 100644 --- a/frontend/src/router/mobileHost.ts +++ b/frontend/src/router/mobileHost.ts @@ -2,12 +2,72 @@ export function isMobileHost(hostname = window.location.hostname) { return hostname === "m.localhost" || hostname.startsWith("m."); } -export function toMobilePath(path: string) { - if (path === "/") { +export function isMobileDevice() { + if (typeof window === "undefined" || !window.navigator) return false; + const ua = window.navigator.userAgent; + const isMobileUA = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua); + const isSmallScreen = window.innerWidth < 768; + return isMobileUA || isSmallScreen; +} + +export function getMobilePath(path: string): string { + if (path === "/" || path === "") { return "/m"; } - if (path === "/m" || path.startsWith("/m/") || path.startsWith("/admin")) { + if (path.startsWith("/m") || path.startsWith("/admin")) { return path; } + + if (path === "/listings" || path.startsWith("/listings/")) { + return `/m${path}`; + } + if (path === "/orders" || path.startsWith("/orders/")) { + return `/m${path}`; + } + if (path === "/realname") return "/m/realname"; + if (path === "/login") return "/m/login"; + if (path === "/register") return "/m/register"; + + if (path === "/seller/listings/create") { + return "/m/seller/listings/create"; + } + + // PC-only views that don't have mobile counterparts go to mobile profile as fallback + if (path === "/wallet" || path === "/notifications" || path.startsWith("/seller")) { + return "/m/profile"; + } + return `/m${path}`; } + +export function getPcPath(path: string): string { + if (!path.startsWith("/m") || path.startsWith("/admin")) { + return path; + } + + if (path === "/m" || path === "/m/") { + return "/"; + } + + const subPath = path.substring(2); + + if (subPath === "/listings" || subPath.startsWith("/listings/")) { + return subPath; + } + if (subPath === "/orders" || subPath.startsWith("/orders/")) { + return subPath; + } + if (subPath === "/login") return "/login"; + if (subPath === "/register") return "/login"; // PC uses /login for both auth actions + if (subPath === "/realname") return "/realname"; + if (subPath === "/seller/listings/create") return "/seller/listings/create"; + + if (subPath === "/messages") return "/"; + if (subPath === "/profile") return "/wallet"; + + return subPath || "/"; +} + +export function toMobilePath(path: string) { + return getMobilePath(path); +}