From eb99deb8038344a2a26e5633803db9af537862ae Mon Sep 17 00:00:00 2001 From: bootx Date: Wed, 24 Jun 2026 12:02:57 +0800 Subject: [PATCH] =?UTF-8?q?refactor(h5):=20=E9=87=8D=E6=9E=84=E4=B8=BA=20m?= =?UTF-8?q?obile/pc/shared=20=E4=B8=89=E5=B1=82=E7=9B=AE=E5=BD=95=E5=B9=B6?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E5=8F=8C=E7=AB=AF=E5=85=A5=E5=8F=A3=E5=88=86?= =?UTF-8?q?=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 目录三层化:移动端代码集中 src/mobile/(App.vue/router/layout/views), PC 端 src/pc/,公共层 src/shared/(api/components/store/utils/styles 等); 批量改写 @/<共享目录> → @/shared/<共享目录> - 双端入口:index.html 内联脚本探测设备写 window.__DEVICE__,main.ts 据此 挂载移动端(#app) 或 PC(#pc-app),零闪烁;PC 走 scoped px, postcss-mobile-forever 排除 src/pc/ - 路由切 history 模式,两端首页统一 /,/home* 兼容重定向; PC catch-all 渲染独立 NotFound 组件(非 redirect) - 构建配置同步:svg iconDirs、less additionalData、Components dirs、warmup 路径 --- build/vite/plugin/index.ts | 2 + build/vite/plugin/svgSprite.ts | 2 +- index.html | 18 ++++ postcss.config.js | 5 +- src/main.ts | 47 ++++------ src/{ => mobile}/App.vue | 8 +- src/mobile/app.ts | 36 ++++++++ src/{ => mobile}/layout/index.vue | 4 +- src/{ => mobile}/router/base.ts | 16 +--- src/{ => mobile}/router/index.ts | 12 ++- src/{ => mobile}/router/modules.ts | 10 +-- src/{ => mobile}/router/router-guards.ts | 2 +- src/{ => mobile}/views/exception/404.vue | 2 +- src/{ => mobile}/views/home/index.vue | 2 +- src/pc/App.vue | 7 ++ src/pc/app.ts | 32 +++++++ src/pc/layout/index.vue | 51 +++++++++++ src/pc/router/index.ts | 32 +++++++ src/pc/views/Home.vue | 89 +++++++++++++++++++ src/pc/views/NotFound.vue | 80 +++++++++++++++++ .../assets/icons/exception/403.svg | 0 .../assets/icons/exception/404.svg | 0 .../assets/icons/exception/500.svg | 0 src/{ => shared}/assets/icons/logo.svg | 0 src/{ => shared}/components/Logo.vue | 6 +- src/{ => shared}/components/SvgIcon.vue | 0 src/{ => shared}/enums/httpEnum.ts | 0 src/{ => shared}/enums/pageEnum.ts | 4 +- src/{ => shared}/hooks/setting/index.ts | 4 +- .../hooks/setting/useDesignSetting.ts | 2 +- src/{ => shared}/settings/animateSetting.ts | 0 src/{ => shared}/settings/designSetting.ts | 0 src/{ => shared}/store/index.ts | 0 .../store/modules/designSetting.ts | 6 +- src/{ => shared}/store/modules/route.ts | 2 +- src/{ => shared}/styles/common.less | 0 src/{ => shared}/styles/entry.css | 0 src/{ => shared}/styles/index.less | 0 src/{ => shared}/styles/transition/base.less | 0 src/{ => shared}/styles/transition/fade.less | 0 src/{ => shared}/styles/transition/index.less | 0 src/{ => shared}/styles/transition/scale.less | 0 .../styles/transition/scroll.less | 0 src/{ => shared}/styles/transition/slide.less | 0 src/{ => shared}/styles/transition/zoom.less | 0 src/{ => shared}/styles/vant.less | 0 src/{ => shared}/styles/var.less | 0 src/{ => shared}/utils/Storage.ts | 0 src/{ => shared}/utils/env.ts | 6 +- src/{ => shared}/utils/http/axios/Axios.ts | 4 +- .../utils/http/axios/axiosCancel.ts | 2 +- .../utils/http/axios/axiosTransform.ts | 0 .../utils/http/axios/checkStatus.ts | 0 src/{ => shared}/utils/http/axios/helper.ts | 2 +- src/{ => shared}/utils/http/axios/index.ts | 12 +-- src/{ => shared}/utils/http/axios/types.ts | 0 src/{ => shared}/utils/index.ts | 0 src/{ => shared}/utils/is/index.ts | 0 src/{ => shared}/utils/log.ts | 0 src/{ => shared}/utils/urlUtils.ts | 0 types/global.d.ts | 8 ++ vite.config.ts | 6 +- 62 files changed, 424 insertions(+), 97 deletions(-) rename src/{ => mobile}/App.vue (91%) create mode 100644 src/mobile/app.ts rename src/{ => mobile}/layout/index.vue (86%) rename src/{ => mobile}/router/base.ts (54%) rename src/{ => mobile}/router/index.ts (66%) rename src/{ => mobile}/router/modules.ts (67%) rename src/{ => mobile}/router/router-guards.ts (96%) rename src/{ => mobile}/views/exception/404.vue (91%) rename src/{ => mobile}/views/home/index.vue (96%) create mode 100644 src/pc/App.vue create mode 100644 src/pc/app.ts create mode 100644 src/pc/layout/index.vue create mode 100644 src/pc/router/index.ts create mode 100644 src/pc/views/Home.vue create mode 100644 src/pc/views/NotFound.vue rename src/{ => shared}/assets/icons/exception/403.svg (100%) rename src/{ => shared}/assets/icons/exception/404.svg (100%) rename src/{ => shared}/assets/icons/exception/500.svg (100%) rename src/{ => shared}/assets/icons/logo.svg (100%) rename src/{ => shared}/components/Logo.vue (94%) rename src/{ => shared}/components/SvgIcon.vue (100%) rename src/{ => shared}/enums/httpEnum.ts (100%) rename src/{ => shared}/enums/pageEnum.ts (70%) rename src/{ => shared}/hooks/setting/index.ts (90%) rename src/{ => shared}/hooks/setting/useDesignSetting.ts (89%) rename src/{ => shared}/settings/animateSetting.ts (100%) rename src/{ => shared}/settings/designSetting.ts (100%) rename src/{ => shared}/store/index.ts (100%) rename src/{ => shared}/store/modules/designSetting.ts (94%) rename src/{ => shared}/store/modules/route.ts (95%) rename src/{ => shared}/styles/common.less (100%) rename src/{ => shared}/styles/entry.css (100%) rename src/{ => shared}/styles/index.less (100%) rename src/{ => shared}/styles/transition/base.less (100%) rename src/{ => shared}/styles/transition/fade.less (100%) rename src/{ => shared}/styles/transition/index.less (100%) rename src/{ => shared}/styles/transition/scale.less (100%) rename src/{ => shared}/styles/transition/scroll.less (100%) rename src/{ => shared}/styles/transition/slide.less (100%) rename src/{ => shared}/styles/transition/zoom.less (100%) rename src/{ => shared}/styles/vant.less (100%) rename src/{ => shared}/styles/var.less (100%) rename src/{ => shared}/utils/Storage.ts (100%) rename src/{ => shared}/utils/env.ts (92%) rename src/{ => shared}/utils/http/axios/Axios.ts (98%) rename src/{ => shared}/utils/http/axios/axiosCancel.ts (97%) rename src/{ => shared}/utils/http/axios/axiosTransform.ts (100%) rename src/{ => shared}/utils/http/axios/checkStatus.ts (100%) rename src/{ => shared}/utils/http/axios/helper.ts (95%) rename src/{ => shared}/utils/http/axios/index.ts (95%) rename src/{ => shared}/utils/http/axios/types.ts (100%) rename src/{ => shared}/utils/index.ts (100%) rename src/{ => shared}/utils/is/index.ts (100%) rename src/{ => shared}/utils/log.ts (100%) rename src/{ => shared}/utils/urlUtils.ts (100%) diff --git a/build/vite/plugin/index.ts b/build/vite/plugin/index.ts index c3da978..71bf858 100644 --- a/build/vite/plugin/index.ts +++ b/build/vite/plugin/index.ts @@ -20,6 +20,8 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) { vue(), // 按需引入VantUi且自动创建组件声明 Components({ + // 共享组件目录(移动端使用;PC 端独立,不扫描此处) + dirs: ['src/shared/components'], dts: true, resolvers: [VantResolver()], types: [], diff --git a/build/vite/plugin/svgSprite.ts b/build/vite/plugin/svgSprite.ts index 3e2680a..7598be4 100644 --- a/build/vite/plugin/svgSprite.ts +++ b/build/vite/plugin/svgSprite.ts @@ -9,7 +9,7 @@ import { createSvgIconsPlugin } from 'vite-plugin-svg-icons' export function configSvgIconsPlugin(isBuild: boolean) { // 指定需要缓存的图标文件夹 const svgIconsPlugin = createSvgIconsPlugin({ - iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')], + iconDirs: [path.resolve(process.cwd(), 'src/shared/assets/icons')], // 是否压缩 svgoOptions: isBuild, // 指定symbolId格式 diff --git a/index.html b/index.html index df28d73..c9ed537 100644 --- a/index.html +++ b/index.html @@ -10,6 +10,22 @@
diff --git a/postcss.config.js b/postcss.config.js index 1fbbd19..6e5cc47 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -45,8 +45,9 @@ export default { autoprefixer(), viewport({ ...baseViewportOpts, - // 只将 vant 转为 375 设计稿的 viewport,其它样式的视图宽度为 750 - // viewportWidth: file => (file.includes('node_modules/vant/') ? 375 : 750), + // PC 端源码不转 vw:PC 页面用 scoped 原生 px + 媒体查询写样式 + // 见 AGENTS.md「PC/移动端双端支持」约束 + exclude: [/src\/pc\//], }), ], } diff --git a/src/main.ts b/src/main.ts index f8cd5d0..f90d027 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,40 +1,23 @@ -import { createApp } from 'vue' -import { setupStore } from '@/store' -import { useDesignSettingWithOut } from '@/store/modules/designSetting' -import App from './App.vue' -import router, { setupRouter } from './router' +import { createMobileApp } from '@/mobile/app' +import { createPCApp } from '@/pc/app' +// UnoCSS 全局样式与重置在入口统一导入一次,PC/移动端共用 import 'virtual:uno.css' - -import 'vant/es/toast/style' - -import 'vant/es/dialog/style' -import 'vant/es/notify/style' -import 'vant/es/image-preview/style' // https://unocss.dev/guide/style-reset#tailwind-compat -// 此重置基于 Tailwind 重置,减去按钮的背景颜色覆盖,以避免与 UI 框架发生冲突。请参阅链接的问题。 +// 此重置基于 Tailwind 重置,减去按钮的背景颜色覆盖,以避免与 UI 框架发生冲突。 import '@unocss/reset/tailwind-compat.css' -// Register icon sprite -import 'virtual:svg-icons-register' - -// 开发环境启用 vconsole 移动端调试面板(由 VITE_V_CONSOLE 控制,默认开启) -if (import.meta.env.DEV && import.meta.env.VITE_V_CONSOLE !== 'false') { - import('vconsole').then(({ default: VConsole }) => { - // eslint-disable-next-line no-new -- vconsole 以副作用方式实例化以挂载调试面板 - new VConsole() - }) -} +/** + * 应用入口分发器 + * + * 由 index.html 内联脚本在 Vue 挂载前写入 window.__DEVICE__('pc' | 'mobile'), + * 此处据此挂载对应应用,首屏即为正确设备 UI,无重定向、无布局闪烁。 + * - mobile → 挂载到 #app(受 postcss-mobile-forever 限宽 600px 居中) + * - pc → 挂载到 #pc-app(全宽,px 不被转 vw) + */ async function bootstrap() { - const app = createApp(App) - // 挂载状态管理 - setupStore(app) - // 初始化全局主题:跟随系统 prefers-color-scheme(不支持手动修改) - useDesignSettingWithOut().initSystemListener() - // 挂载路由 - setupRouter(app) - await router.isReady() - // 路由准备就绪后挂载APP实例 - app.mount('#app', true) + const isPC = window.__DEVICE__ === 'pc' + const app = isPC ? await createPCApp() : await createMobileApp() + app.mount(isPC ? '#pc-app' : '#app', true) } void bootstrap() diff --git a/src/App.vue b/src/mobile/App.vue similarity index 91% rename from src/App.vue rename to src/mobile/App.vue index 445958a..e4c478a 100644 --- a/src/App.vue +++ b/src/mobile/App.vue @@ -1,7 +1,7 @@ + + diff --git a/src/pc/app.ts b/src/pc/app.ts new file mode 100644 index 0000000..cf618be --- /dev/null +++ b/src/pc/app.ts @@ -0,0 +1,32 @@ +import type { App } from 'vue' +import { createPinia } from 'pinia' +import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' +import { createApp } from 'vue' +import PcApp from '@/pc/App.vue' +import { pcRouter, setupPCRouter } from '@/pc/router' + +// PC 端独立的 pinia 实例(与移动端状态隔离,同一时刻仅一套应用运行) +const pcStore = createPinia() +pcStore.use(piniaPluginPersistedstate) + +function setupPCStore(app: App) { + app.use(pcStore) +} + +/** + * 创建 PC 端应用实例 + * + * 挂载点:#pc-app(独立于 #app,不受 postcss-mobile-forever 的 appSelector 限宽影响) + * + * 样式约束:PC 页面所有尺寸用 scoped diff --git a/src/pc/router/index.ts b/src/pc/router/index.ts new file mode 100644 index 0000000..4743538 --- /dev/null +++ b/src/pc/router/index.ts @@ -0,0 +1,32 @@ +import type { App } from 'vue' +import type { RouteRecordRaw } from 'vue-router' +import { createRouter, createWebHistory } from 'vue-router' + +// PC 端路由树(独立于移动端,按需在此扩展业务路由,例如收银台 PC 版) +// 内页(收银台等)建议套 PcLayout;首页为全屏独立页,贴合移动端首页视觉 +const routes: RouteRecordRaw[] = [ + { + path: '/', + name: 'PcHome', + component: () => import('@/pc/views/Home.vue'), + }, + // 兜底:移动端专属路径(如 /home/index)或任何未匹配路径,渲染 PC 404 页 + // 用 component 而非 redirect——vue-router 5 下 catch-all + redirect 在初始导航不触发 + { + path: '/:pathMatch(.*)*', + name: 'PcNotFound', + component: () => import('@/pc/views/NotFound.vue'), + }, +] + +const pcRouter = createRouter({ + history: createWebHistory(import.meta.env.BASE_URL), + routes, + scrollBehavior: () => ({ left: 0, top: 0 }), +}) + +export function setupPCRouter(app: App) { + app.use(pcRouter) +} + +export { pcRouter } diff --git a/src/pc/views/Home.vue b/src/pc/views/Home.vue new file mode 100644 index 0000000..acc565f --- /dev/null +++ b/src/pc/views/Home.vue @@ -0,0 +1,89 @@ + + + + + diff --git a/src/pc/views/NotFound.vue b/src/pc/views/NotFound.vue new file mode 100644 index 0000000..d1ebad2 --- /dev/null +++ b/src/pc/views/NotFound.vue @@ -0,0 +1,80 @@ + + + + + diff --git a/src/assets/icons/exception/403.svg b/src/shared/assets/icons/exception/403.svg similarity index 100% rename from src/assets/icons/exception/403.svg rename to src/shared/assets/icons/exception/403.svg diff --git a/src/assets/icons/exception/404.svg b/src/shared/assets/icons/exception/404.svg similarity index 100% rename from src/assets/icons/exception/404.svg rename to src/shared/assets/icons/exception/404.svg diff --git a/src/assets/icons/exception/500.svg b/src/shared/assets/icons/exception/500.svg similarity index 100% rename from src/assets/icons/exception/500.svg rename to src/shared/assets/icons/exception/500.svg diff --git a/src/assets/icons/logo.svg b/src/shared/assets/icons/logo.svg similarity index 100% rename from src/assets/icons/logo.svg rename to src/shared/assets/icons/logo.svg diff --git a/src/components/Logo.vue b/src/shared/components/Logo.vue similarity index 94% rename from src/components/Logo.vue rename to src/shared/components/Logo.vue index 6e379ee..4dc5fbd 100644 --- a/src/components/Logo.vue +++ b/src/shared/components/Logo.vue @@ -1,7 +1,7 @@