# 创高家具官网 - 前端项目架构设计 ## 一、技术栈选型 | 层级 | 技术 | 版本 | 用途 | |------|------|------|------| | 框架 | Vue 3 | ^3.4.0 | 渐进式前端框架 | | 构建 | Vite | ^5.0.0 | 快速构建工具 | | 路由 | Vue Router | ^4.2.0 | 单页应用路由 | | 状态 | Pinia | ^2.1.0 | 状态管理 | | 国际化 | Vue I18n | ^9.0.0 | 中英文切换 | | UI组件 | Element Plus | ^2.5.0 | 基础组件库 | | 动画 | GSAP | ^3.12.0 | 高级动画效果 | | 图标 | Element Plus Icons | - | 图标库 | | CSS | SCSS | - | 预处理器 | --- ## 二、项目目录结构 ``` client/ ├── index.html # 入口HTML ├── package.json # 依赖配置 ├── vite.config.ts # Vite配置 ├── tsconfig.json # TypeScript配置 ├── .env # 环境变量(开发) ├── .env.production # 环境变量(生产) │ ├── public/ # 静态资源(不处理) │ ├── favicon.ico │ └── logo.png │ ├── src/ │ ├── main.ts # 应用入口 │ ├── App.vue # 根组件 │ │ │ ├── api/ # API接口层 │ │ ├── request.ts # axios封装 │ │ ├── portal/ # 前台接口 │ │ │ ├── company.ts │ │ │ ├── home.ts │ │ │ ├── product.ts │ │ │ ├── case.ts │ │ │ ├── news.ts │ │ │ └── contact.ts │ │ └── admin/ # 后台接口 │ │ ├── auth.ts │ │ ├── upload.ts │ │ ├── product.ts │ │ ├── case.ts │ │ ├── news.ts │ │ ├── pageBlock.ts │ │ └── media.ts │ │ │ ├── assets/ # 资源文件 │ │ ├── styles/ # 全局样式 │ │ │ ├── variables.scss # SCSS变量 │ │ │ ├── mixins.scss # SCSS混入 │ │ │ ├── global.scss # 全局样式 │ │ │ └── element-plus.scss # Element Plus主题覆盖 │ │ ├── images/ # 静态图片 │ │ └── fonts/ # 字体文件 │ │ │ ├── components/ # 公共组件 │ │ ├── common/ # 通用组件 │ │ │ ├── LangSwitch.vue # 语言切换 │ │ │ ├── PageLoading.vue # 页面加载 │ │ │ ├── ImageLazy.vue # 懒加载图片 │ │ │ └── Breadcrumb.vue # 面包屑 │ │ ├── layout/ # 布局组件 │ │ │ ├── AppHeader.vue # 顶部导航 │ │ │ ├── AppFooter.vue # 底部导航 │ │ │ ├── MobileMenu.vue # 移动端菜单 │ │ │ └── BackToTop.vue # 返回顶部 │ │ ├── home/ # 首页专用组件 │ │ │ ├── HeroBanner.vue # 首屏轮播 │ │ │ ├── ServiceSection.vue # 服务板块 │ │ │ ├── ProductSection.vue # 产品板块 │ │ │ ├── CaseSection.vue # 案例板块 │ │ │ └── StrengthSection.vue # 实力板块 │ │ └── product/ # 产品页组件 │ │ ├── ProductCard.vue │ │ ├── ProductFilter.vue │ │ └── ProductGallery.vue │ │ │ ├── composables/ # 组合式函数 │ │ ├── useLocale.ts # 语言相关 │ │ ├── useScroll.ts # 滚动监听 │ │ ├── useDevice.ts # 设备检测 │ │ └── useSEO.ts # SEO设置 │ │ │ ├── directives/ # 自定义指令 │ │ ├── lazyLoad.ts # 图片懒加载 │ │ └── parallax.ts # 视差滚动 │ │ │ ├── locales/ # 国际化文件 │ │ ├── index.ts # 配置入口 │ │ ├── zh-CN.ts # 中文 │ │ └── en-US.ts # 英文 │ │ │ ├── router/ # 路由配置 │ │ ├── index.ts # 路由入口 │ │ ├── routes.ts # 路由定义 │ │ ├── portal.ts # 前台路由 │ │ └── admin.ts # 后台路由 │ │ │ ├── stores/ # Pinia状态管理 │ │ ├── index.ts │ │ ├── app.ts # 应用状态 │ │ ├── user.ts # 用户状态 │ │ └── setting.ts # 设置状态 │ │ │ ├── types/ # TypeScript类型 │ │ ├── api.d.ts # API响应类型 │ │ ├── model.d.ts # 数据模型类型 │ │ └── global.d.ts # 全局类型 │ │ │ ├── utils/ # 工具函数 │ │ ├── storage.ts # 本地存储封装 │ │ ├── format.ts # 格式化 │ │ ├── validate.ts # 验证 │ │ └── constants.ts # 常量 │ │ │ └── views/ # 页面视图 │ ├── portal/ # 前台页面 │ │ ├── HomeView.vue │ │ ├── ProductView.vue │ │ ├── ProductDetailView.vue │ │ ├── CaseView.vue │ │ ├── CaseDetailView.vue │ │ ├── AboutView.vue │ │ ├── NewsView.vue │ │ ├── NewsDetailView.vue │ │ └── ContactView.vue │ └── admin/ # 后台管理页面 │ ├── LoginView.vue │ ├── DashboardView.vue │ ├── Layout.vue │ ├── company/ │ │ └── InfoManage.vue │ ├── content/ │ │ ├── CarouselManage.vue │ │ ├── PageBlockManage.vue │ │ └── MediaLibrary.vue │ ├── product/ │ │ ├── CategoryManage.vue │ │ └── ProductManage.vue │ ├── case/ │ │ ├── CaseCategoryManage.vue │ │ └── CaseManage.vue │ ├── news/ │ │ ├── NewsCategoryManage.vue │ │ └── NewsManage.vue │ ├── message/ │ │ └── MessageManage.vue │ └── system/ │ ├── UserManage.vue │ └── LogManage.vue ``` --- ## 三、核心配置文件 ### 3.1 vite.config.ts ```typescript import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import { resolve } from 'path' export default defineConfig({ plugins: [vue()], resolve: { alias: { '@': resolve(__dirname, 'src'), }, }, css: { preprocessorOptions: { scss: { additionalData: ` @use "@/assets/styles/variables.scss" as *; @use "@/assets/styles/mixins.scss" as *; `, }, }, }, server: { port: 3000, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true, }, }, }, build: { outDir: 'dist', assetsDir: 'assets', rollupOptions: { output: { chunkFileNames: 'js/[name]-[hash].js', entryFileNames: 'js/[name]-[hash].js', assetFileNames: (assetInfo) => { const info = assetInfo.name.split('.') const ext = info[info.length - 1] if (/\.(png|jpe?g|gif|svg|webp|ico)$/.test(assetInfo.name)) { return 'images/[name]-[hash][extname]' } if (/\.(woff2?|eot|ttf|otf)$/.test(assetInfo.name)) { return 'fonts/[name]-[hash][extname]' } return '[ext]/[name]-[hash][extname]' }, }, }, }, }) ``` ### 3.2 .env.production ``` # 站点代码 VITE_SITE_CODE=cg # API地址 VITE_API_BASE_URL=/api # 多语言默认 VITE_DEFAULT_LANG=zh-CN # MinIO配置 VITE_MINIO_ENDPOINT=http://localhost:9000 VITE_MINIO_BUCKET=chuanggao-images VITE_MINIO_PUBLIC_URL=http://localhost:9000/chuanggao-images ``` ### 3.3 tsconfig.json ```json { "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, "module": "ESNext", "lib": ["ESNext", "DOM", "DOM.Iterable"], "skipLibCheck": true, "moduleResolution": "bundler", "allowImportingTsExtensions": true, "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "preserve", "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, "noFallthroughCasesInSwitch": true, "baseUrl": ".", "paths": { "@/*": ["src/*"] } }, "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"], "references": [{ "path": "./tsconfig.node.json" }] } ``` --- ## 四、国际化配置 ### 4.1 locales/index.ts ```typescript import { createI18n } from 'vue-i18n' import zhCN from './zh-CN' import enUS from './en-US' const messages = { 'zh-CN': zhCN, 'en-US': enUS, } const i18n = createI18n({ legacy: false, locale: localStorage.getItem('lang') || import.meta.env.VITE_DEFAULT_LANG || 'zh-CN', fallbackLocale: 'zh-CN', messages, }) export default i18n ``` ### 4.2 locales/zh-CN.ts(节选) ```typescript export default { // 通用 common: { home: '首页', products: '产品中心', cases: '案例展示', about: '关于创高', contact: '联系我们', franchise: '招商加盟', more: '了解更多', viewAll: '查看全部', submit: '提交', cancel: '取消', confirm: '确认', loading: '加载中...', noData: '暂无数据', search: '搜索', hotline: '服务热线', }, // 首页 home: { hero: { title: '全屋定制 匠心之作', subtitle: '专注高端家具定制,为品质生活而生', btnContact: '立即咨询', btnProducts: '查看产品', }, services: { title: '核心业务', subtitle: '三大业务板块,全方位满足您的需求', custom: { title: '全屋定制', desc: '从客厅到卧室,从厨房到书房,一站式全屋定制解决方案', }, furniture: { title: '成品家具', desc: '精选全球优质原材料,打造舒适耐用的高端家具', }, project: { title: '工程项目', desc: '酒店、办公、精装房等专业工程家具配套服务', }, }, products: { title: '热门产品', subtitle: '精选系列,品质之选', }, cases: { title: '经典案例', subtitle: '实景呈现,见证品质', }, strength: { title: '品牌实力', subtitle: '二十年匠心积淀,铸就行业标杆', years: '年行业经验', factory: '㎡生产基地', clients: '家服务客户', patents: '项国家专利', }, }, // 产品中心 product: { title: '产品中心', filter: { all: '全部', category: '分类', style: '风格', scene: '场景', }, params: '产品参数', scene: '场景展示', inquiry: '立即咨询', similar: '相关产品', }, // 案例展示 case: { title: '案例展示', filter: '场景筛选', area: '项目面积', location: '项目地点', date: '完工时间', products: '使用产品', }, // 关于创高 about: { title: '关于创高', story: '品牌故事', factory: '工厂实力', honor: '荣誉资质', news: '新闻资讯', }, // 联系我们 contact: { title: '联系我们', form: { name: '您的姓名', phone: '联系电话', email: '电子邮箱', company: '公司名称', type: '咨询类型', message: '留言内容', placeholder: '请输入您的咨询内容...', }, types: { join: '加盟咨询', cooperate: '工程合作', feedback: '客户反馈', other: '其他', }, success: '提交成功,我们会尽快联系您!', }, // 招商加盟 franchise: { title: '招商加盟', subtitle: '携手创高,共创未来', policy: '加盟政策', process: '加盟流程', support: '六大支持', contact: '立即咨询', }, // 页脚 footer: { navigation: '快速导航', products: '产品中心', service: '客户服务', contact: '联系方式', follow: '关注我们', copyright: '© {year} 创高家具 版权所有', icp: '粤ICP备xxxxxxxx号', }, } ``` ### 4.3 locales/en-US.ts(结构同上,英文翻译) --- ## 五、路由设计 ### 5.1 router/portal.ts(前台路由) ```typescript import type { RouteRecordRaw } from 'vue-router' const portalRoutes: RouteRecordRaw[] = [ { path: '/', name: 'Home', component: () => import('@/views/portal/HomeView.vue'), meta: { title: '首页', titleEn: 'Home', }, }, { path: '/products', name: 'Products', component: () => import('@/views/portal/ProductView.vue'), meta: { title: '产品中心', titleEn: 'Products', }, }, { path: '/products/:id', name: 'ProductDetail', component: () => import('@/views/portal/ProductDetailView.vue'), meta: { title: '产品详情', titleEn: 'Product Detail', }, }, { path: '/cases', name: 'Cases', component: () => import('@/views/portal/CaseView.vue'), meta: { title: '案例展示', titleEn: 'Cases', }, }, { path: '/cases/:id', name: 'CaseDetail', component: () => import('@/views/portal/CaseDetailView.vue'), meta: { title: '案例详情', titleEn: 'Case Detail', }, }, { path: '/about', name: 'About', component: () => import('@/views/portal/AboutView.vue'), meta: { title: '关于创高', titleEn: 'About Us', }, }, { path: '/news', name: 'News', component: () => import('@/views/portal/NewsView.vue'), meta: { title: '新闻资讯', titleEn: 'News', }, }, { path: '/news/:id', name: 'NewsDetail', component: () => import('@/views/portal/NewsDetailView.vue'), meta: { title: '新闻详情', titleEn: 'News Detail', }, }, { path: '/contact', name: 'Contact', component: () => import('@/views/portal/ContactView.vue'), meta: { title: '联系我们', titleEn: 'Contact Us', }, }, ] export default portalRoutes ``` ### 5.2 router/admin.ts(后台路由) ```typescript import type { RouteRecordRaw } from 'vue-router' const adminRoutes: RouteRecordRaw[] = [ { path: '/admin/login', name: 'AdminLogin', component: () => import('@/views/admin/LoginView.vue'), meta: { public: true }, }, { path: '/admin', name: 'AdminLayout', component: () => import('@/views/admin/Layout.vue'), redirect: '/admin/dashboard', children: [ { path: 'dashboard', name: 'AdminDashboard', component: () => import('@/views/admin/DashboardView.vue'), }, { path: 'company/info', name: 'CompanyInfo', component: () => import('@/views/admin/company/InfoManage.vue'), }, { path: 'content/carousel', name: 'CarouselManage', component: () => import('@/views/admin/content/CarouselManage.vue'), }, { path: 'content/blocks', name: 'PageBlockManage', component: () => import('@/views/admin/content/PageBlockManage.vue'), }, { path: 'content/media', name: 'MediaLibrary', component: () => import('@/views/admin/content/MediaLibrary.vue'), }, { path: 'product/category', name: 'ProductCategory', component: () => import('@/views/admin/product/CategoryManage.vue'), }, { path: 'product/list', name: 'ProductList', component: () => import('@/views/admin/product/ProductManage.vue'), }, { path: 'case/category', name: 'CaseCategory', component: () => import('@/views/admin/case/CaseCategoryManage.vue'), }, { path: 'case/list', name: 'CaseList', component: () => import('@/views/admin/case/CaseManage.vue'), }, { path: 'news/category', name: 'NewsCategory', component: () => import('@/views/admin/news/NewsCategoryManage.vue'), }, { path: 'news/list', name: 'NewsList', component: () => import('@/views/admin/news/NewsManage.vue'), }, { path: 'message/list', name: 'MessageList', component: () => import('@/views/admin/message/MessageManage.vue'), }, { path: 'system/users', name: 'UserManage', component: () => import('@/views/admin/system/UserManage.vue'), }, ], }, ] export default adminRoutes ``` --- ## 六、核心组件设计 ### 6.1 AppHeader.vue(顶部导航) ```vue ``` --- ## 七、样式系统设计 ### 7.1 variables.scss(CSS变量) ```scss :root { // 品牌色 - 深色底+金属质感 --primary-color: #C9A962; // 金色(金属质感) --primary-light: #E8D5A3; // 浅金色 --primary-dark: #9A7B3D; // 深金色 // 背景色 --bg-dark: #1A1A1A; // 深色背景 --bg-dark-secondary: #242424; // 次级深色 --bg-light: #FFFFFF; // 浅色背景 --bg-gray: #F5F5F5; // 灰色背景 // 文字色 --text-primary: #1A1A1A; // 主文字(深色) --text-secondary: #666666; // 次级文字 --text-light: #999999; // 辅助文字 --text-white: #FFFFFF; // 白色文字 // 边框 --border-color: #E8E8E8; --border-dark: #333333; // 阴影 --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.08); --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.12); --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.16); // 间距 --spacing-xs: 4px; --spacing-sm: 8px; --spacing-md: 16px; --spacing-lg: 24px; --spacing-xl: 32px; --spacing-xxl: 48px; // 圆角 --radius-sm: 4px; --radius-md: 8px; --radius-lg: 16px; // 过渡 --transition-fast: 0.2s ease; --transition-normal: 0.3s ease; --transition-slow: 0.5s ease; // 布局 --header-height: 80px; --header-height-mobile: 64px; --container-max-width: 1400px; --container-padding: 24px; } // 响应式断点 $breakpoints: ( 'xs': 576px, 'sm': 768px, 'md': 992px, 'lg': 1200px, 'xl': 1400px, ); @mixin respond-to($breakpoint) { $value: map-get($breakpoints, $breakpoint); @media (max-width: $value) { @content; } } ``` --- ## 八、响应式断点策略 | 断点 | 宽度 | 布局调整 | |------|------|----------| | xl | ≥1400px | 最大容器宽度,完整导航 | | lg | 1200-1399px | 略窄容器 | | md | 992-1199px | 平板横屏,简化导航 | | sm | 768-991px | 平板竖屏,移动菜单 | | xs | <768px | 手机,单列布局 | --- ## 九、性能优化策略 ### 9.1 图片处理 - 使用 `loading="lazy"` 懒加载 - 多尺寸图片:pc端 / mobile端分离 - WebP 格式优先,JPEG 降级 - 响应式图片 `srcset` ### 9.2 代码分割 - 路由级别懒加载 - 组件异步加载 - vendors chunk 分离 ### 9.3 缓存策略 - 静态资源长期缓存(1年) - API 响应 Cache-Control - 图片 CDN 加速 --- ## 十、开发命令 ```bash # 安装依赖 npm install # 开发环境 npm run dev # 生产构建 npm run build # 预览生产构建 npm run preview # 类型检查 npm run type-check # 代码检查 npm run lint ```