# 情绪博物馆Web端技术方案 ## 技术选型说明 ### WebSocket通信方案选择 本方案选择 **STOMP + 原生WebSocket** 而非 Socket.io 的原因: 1. **后端集成优势**: 项目后端使用Spring Boot,STOMP是Spring WebSocket的原生支持协议 2. **标准化协议**: STOMP是标准的消息传递协议,不依赖特定实现 3. **消息队列支持**: 天然支持点对点和发布订阅模式,适合聊天和通知场景 4. **轻量级**: 相比Socket.io更轻量,减少前端包体积 5. **Token认证支持**: 原生WebSocket支持在握手时传递自定义请求头进行Token认证 ### 技术栈版本策略 - **稳定性优先**: 选择经过验证的稳定版本 - **生态兼容**: 确保各组件间良好兼容 - **长期支持**: 优先选择有LTS支持的版本 - **性能考虑**: 新版本的性能优化和bug修复 ## 1. 核心技术栈(推荐版本) ### 1.1 前端框架 - **Vue.js**: `3.4.21` (最新稳定版) - **TypeScript**: `5.4.2` (最新稳定版) - **Vite**: `5.1.6` (最新稳定版,更好的构建性能) ### 1.2 UI框架与样式 - **Element Plus**: `2.6.1` (最新稳定版,更好的Vue3支持) - **Tailwind CSS**: `3.4.1` (最新稳定版) - **@tailwindcss/forms**: `0.5.7` (表单样式增强) - **@tailwindcss/typography**: `0.5.10` (文本排版增强) ### 1.3 状态管理与路由 - **Pinia**: `2.1.7` (保持现有版本,稳定可靠) - **Vue Router**: `4.3.0` (最新稳定版) - **@pinia/nuxt**: `0.5.1` (如果需要SSR支持) ### 1.4 HTTP客户端与实时通信 - **Axios**: `1.6.8` (最新稳定版) - **@stomp/stompjs**: `7.1.1` (WebSocket通信,与Spring Boot后端集成,支持Token认证) ### 1.5 数据可视化 - **ECharts**: `5.5.0` (最新稳定版) - **vue-echarts**: `6.7.3` (Vue3专用ECharts组件) - **@antv/g2**: `5.1.15` (备选图表库,更现代化) ### 1.6 工具库 - **Day.js**: `1.11.10` (最新稳定版) - **Lodash-es**: `4.17.21` (ES模块版本) - **Zod**: `3.22.4` (数据验证) - **VueUse**: `10.9.0` (Vue组合式API工具集) ### 1.7 开发工具 - **@vitejs/plugin-vue**: `5.0.4` - **@vue/tsconfig**: `0.5.1` - **vue-tsc**: `2.0.6` - **unplugin-auto-import**: `0.17.5` (自动导入) - **unplugin-vue-components**: `0.26.0` (组件自动导入) ## 2. 新增推荐技术栈 ### 2.1 表单处理 - **@vuelidate/core**: `2.0.3` (表单验证) - **@vuelidate/validators**: `2.0.4` - **vue-hooks-form**: `0.8.6` (表单状态管理) ### 2.2 动画与交互 - **@vueuse/motion**: `2.0.0` (动画库) - **vue-toastification**: `2.0.0-rc.5` (通知组件) - **nprogress**: `0.2.0` (页面加载进度条) ### 2.3 文件处理 - **vue-upload-component**: `3.1.4` (文件上传) - **cropperjs**: `1.6.1` (图片裁剪) - **file-saver**: `2.0.5` (文件下载) ### 2.4 富文本编辑 - **@tiptap/vue-3**: `2.2.4` (现代富文本编辑器) - **@tiptap/starter-kit**: `2.2.4` - **@tiptap/extension-image**: `2.2.4` ### 2.5 PWA支持 - **vite-plugin-pwa**: `0.19.2` (PWA支持) - **workbox-window**: `7.0.0` (Service Worker管理) ## 3. 开发工具与代码质量 ### 3.1 代码规范 - **ESLint**: `8.57.0` - **@vue/eslint-config-typescript**: `12.0.0` - **@vue/eslint-config-prettier**: `9.0.0` - **Prettier**: `3.2.5` - **lint-staged**: `15.2.2` - **husky**: `9.0.11` ### 3.2 测试框架 - **Vitest**: `1.4.0` (单元测试) - **@vue/test-utils**: `2.4.5` (Vue组件测试) - **jsdom**: `24.0.0` (DOM环境模拟) - **Cypress**: `13.7.1` (E2E测试) ### 3.3 构建优化 - **rollup-plugin-visualizer**: `5.12.0` (构建分析) - **vite-plugin-compression**: `0.5.1` (Gzip压缩) - **vite-plugin-mock**: `3.0.1` (Mock数据) ## 4. 项目结构设计 ``` src/ ├── api/ # API接口定义 │ ├── auth.ts # 认证相关接口 │ ├── chat.ts # 聊天相关接口 │ ├── diary.ts # 日记相关接口 │ └── user.ts # 用户相关接口 ├── assets/ # 静态资源 │ ├── images/ # 图片资源 │ ├── icons/ # 图标资源 │ └── styles/ # 全局样式 ├── components/ # 公共组件 │ ├── common/ # 通用组件 │ ├── forms/ # 表单组件 │ ├── charts/ # 图表组件 │ └── layout/ # 布局组件 ├── composables/ # 组合式API │ ├── useAuth.ts # 认证逻辑 │ ├── useChat.ts # 聊天逻辑 │ ├── useWebSocket.ts # WebSocket逻辑 │ └── useApi.ts # API调用逻辑 ├── config/ # 配置文件 │ ├── env.ts # 环境配置 │ ├── constants.ts # 常量定义 │ └── routes.ts # 路由配置 ├── layouts/ # 页面布局 │ ├── DefaultLayout.vue # 默认布局 │ ├── AuthLayout.vue # 认证布局 │ └── ChatLayout.vue # 聊天布局 ├── pages/ # 页面组件 │ ├── auth/ # 认证页面 │ ├── chat/ # 聊天页面 │ ├── diary/ # 日记页面 │ └── dashboard/ # 仪表盘页面 ├── stores/ # 状态管理 │ ├── auth.ts # 认证状态 │ ├── chat.ts # 聊天状态 │ ├── user.ts # 用户状态 │ └── app.ts # 应用状态 ├── types/ # 类型定义 │ ├── api.ts # API类型 │ ├── user.ts # 用户类型 │ ├── chat.ts # 聊天类型 │ └── global.d.ts # 全局类型 ├── utils/ # 工具函数 │ ├── request.ts # HTTP请求工具 │ ├── websocket.ts # WebSocket工具 │ ├── storage.ts # 存储工具 │ ├── validation.ts # 验证工具 │ └── format.ts # 格式化工具 └── views/ # 页面视图 ├── Home.vue # 首页 ├── Login.vue # 登录页 ├── Chat.vue # 聊天页 └── Dashboard.vue # 仪表盘 ``` ## 5. 核心功能实现方案 ### 5.1 认证系统 - **JWT Token管理**: 使用Pinia存储,自动刷新机制 - **路由守卫**: 基于Vue Router的权限控制 - **第三方登录**: 支持微信、QQ、GitHub等 - **验证码**: 图形验证码 + 短信验证码 ### 5.2 实时通信 - **STOMP协议**: 基于@stomp/stompjs,与Spring Boot WebSocket集成 - **原生WebSocket**: 支持Token认证,无需降级方案 - **连接管理**: 自动重连、心跳检测、连接状态监控 - **消息队列**: 支持点对点和发布订阅模式 - **Token认证**: 在WebSocket握手时传递Authorization头部 - **消息类型**: 文本、图片、表情、文件、系统通知 - **离线处理**: 离线消息缓存和同步机制 ### 5.3 数据可视化 - **情绪趋势图**: 基于ECharts的时间序列图 - **情绪雷达图**: 多维度情绪分析 - **成长轨迹**: 交互式时间轴 - **数据导出**: 支持PDF、Excel导出 ### 5.4 响应式设计 - **移动端适配**: 基于Tailwind CSS的响应式布局 - **触摸手势**: 支持滑动、缩放等手势操作 - **PWA支持**: 离线缓存、桌面安装 - **性能优化**: 虚拟滚动、懒加载 ## 6. 环境配置优化 ### 6.1 多环境配置 ```typescript // config/env.ts export const envConfigs = { local: { name: '本地环境', apiBaseUrl: 'http://localhost:19089/api', wsBaseUrl: 'ws://localhost:19089', uploadUrl: 'http://localhost:19089/api/upload', debug: true, mock: false }, dev: { name: '开发环境', apiBaseUrl: 'https://dev-api.emotion-museum.com/api', wsBaseUrl: 'wss://dev-api.emotion-museum.com', uploadUrl: 'https://dev-api.emotion-museum.com/api/upload', debug: true, mock: false }, test: { name: '测试环境', apiBaseUrl: 'https://test-api.emotion-museum.com/api', wsBaseUrl: 'wss://test-api.emotion-museum.com', uploadUrl: 'https://test-api.emotion-museum.com/api/upload', debug: false, mock: false }, prod: { name: '生产环境', apiBaseUrl: 'https://api.emotion-museum.com/api', wsBaseUrl: 'wss://api.emotion-museum.com', uploadUrl: 'https://api.emotion-museum.com/api/upload', debug: false, mock: false } } ``` ### 6.2 构建优化配置 ```typescript // vite.config.ts export default defineConfig({ plugins: [ vue(), AutoImport({ imports: ['vue', 'vue-router', 'pinia', '@vueuse/core'], dts: true }), Components({ resolvers: [ElementPlusResolver()], dts: true }), VitePWA({ registerType: 'autoUpdate', workbox: { globPatterns: ['**/*.{js,css,html,ico,png,svg}'] } }) ], build: { rollupOptions: { output: { manualChunks: { vendor: ['vue', 'vue-router', 'pinia'], elementPlus: ['element-plus'], echarts: ['echarts'], utils: ['axios', 'dayjs', 'lodash-es'] } } } } }) ``` ## 7. 部署方案 ### 7.1 Docker部署 ```dockerfile # Dockerfile FROM node:18-alpine as builder WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . RUN npm run build FROM nginx:alpine COPY --from=builder /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/nginx.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] ``` ### 7.2 CI/CD配置 ```yaml # .github/workflows/deploy.yml name: Deploy on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '18' - run: npm ci - run: npm run build - run: npm run test - name: Deploy to server run: | # 部署脚本 ``` ### 7.3 Nginx配置 ```nginx # nginx.conf server { listen 80; server_name localhost; root /usr/share/nginx/html; index index.html; # 处理Vue Router的history模式 location / { try_files $uri $uri/ /index.html; } # 静态资源缓存 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 1y; add_header Cache-Control "public, immutable"; } # API代理 location /api/ { proxy_pass http://backend:19089/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # WebSocket代理 location /ws/ { proxy_pass http://backend:19089/ws/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } } ``` ## 8. 性能优化策略 ### 8.1 代码分割 - **路由级别懒加载**: 使用动态import() - **组件级别动态导入**: 按需加载大型组件 - **第三方库按需加载**: Tree-shaking优化 - **图片懒加载**: Intersection Observer API ### 8.2 缓存策略 - **HTTP缓存配置**: 静态资源长期缓存 - **Service Worker缓存**: 离线访问支持 - **本地存储优化**: IndexedDB存储大量数据 - **CDN加速**: 静态资源CDN分发 ### 8.3 监控与分析 - **Sentry**: `7.108.0` (错误监控) - **Google Analytics**: `gtag` (用户行为分析) - **Web Vitals**: `3.5.2` (性能指标监控) - **Bundle Analyzer**: 构建分析工具 ### 8.4 性能指标 - **首屏加载时间**: < 2秒 - **交互响应时间**: < 100ms - **代码分割**: 单个chunk < 250KB - **图片优化**: WebP格式,响应式图片 ## 9. 安全考虑 ### 9.1 前端安全 - **XSS防护**: 内容安全策略(CSP) - **CSRF防护**: Token验证 - **敏感信息加密**: 本地存储加密 - **依赖安全**: 定期更新依赖包 ### 9.2 API安全 - **Token自动刷新**: JWT令牌管理 - **请求签名验证**: HMAC签名 - **接口限流**: 防止恶意请求 - **数据加密传输**: HTTPS强制 ### 9.3 内容安全策略 ```html ``` ## 10. 开发规范 ### 10.1 代码规范 - **命名规范**: - 组件: PascalCase (UserProfile.vue) - 文件: kebab-case (user-profile.ts) - 变量: camelCase (userName) - 常量: UPPER_SNAKE_CASE (API_BASE_URL) ### 10.2 Git提交规范 ``` feat: 新功能 fix: 修复bug docs: 文档更新 style: 代码格式调整 refactor: 代码重构 test: 测试相关 chore: 构建工具或辅助工具的变动 ``` ### 10.3 组件开发规范 ```vue ``` ### 10.4 API接口规范 ```typescript // api/user.ts import type { User, UserProfile, UpdateUserRequest } from '@/types/user' import { request } from '@/utils/request' export const userApi = { // 获取用户信息 getProfile(): Promise { return request.get('/user/profile') }, // 更新用户信息 updateProfile(data: UpdateUserRequest): Promise { return request.put('/user/profile', data) }, // 上传头像 uploadAvatar(file: File): Promise<{ url: string }> { const formData = new FormData() formData.append('avatar', file) return request.post('/user/avatar/upload', formData, { headers: { 'Content-Type': 'multipart/form-data' } }) } } ``` ### 10.5 WebSocket实现方案 #### 为什么选择STOMP而不是Socket.io? 1. **后端集成**: 项目后端使用Spring Boot,STOMP是Spring WebSocket的标准协议 2. **消息队列**: STOMP天然支持消息队列模式,适合聊天和通知场景 3. **标准化**: STOMP是标准协议,不依赖特定实现 4. **轻量级**: 相比Socket.io更轻量,减少包体积 #### WebSocket工具类实现 ```typescript // utils/websocket.ts import { Client } from '@stomp/stompjs' import { envConfig } from '@/config/env' export class WebSocketService { private client: Client private connected = false private reconnectAttempts = 0 private maxReconnectAttempts = 5 private currentToken = '' constructor() { this.client = new Client({ // 使用原生WebSocket,支持Token认证 brokerURL: `${envConfig.wsBaseUrl}/ws`, // 心跳检测 heartbeatIncoming: 4000, heartbeatOutgoing: 4000, // 重连配置 reconnectDelay: 5000, // 调试模式 debug: envConfig.debug ? console.log : undefined, onConnect: () => { this.connected = true this.reconnectAttempts = 0 console.log('WebSocket连接成功') }, onDisconnect: () => { this.connected = false console.log('WebSocket连接断开') }, onStompError: (frame) => { console.error('STOMP错误:', frame) this.handleReconnect() }, // WebSocket连接前的配置 beforeConnect: () => { // 在WebSocket握手时添加Token if (this.currentToken) { this.client.configure({ connectHeaders: { Authorization: `Bearer ${this.currentToken}`, 'X-Requested-With': 'XMLHttpRequest' } }) } } }) } // 连接WebSocket connect(token: string) { this.currentToken = token this.client.configure({ connectHeaders: { Authorization: `Bearer ${token}`, 'X-Requested-With': 'XMLHttpRequest' } }) this.client.activate() } // 更新Token(用于Token刷新场景) updateToken(newToken: string) { this.currentToken = newToken if (this.connected) { // 断开当前连接 this.disconnect() // 使用新Token重新连接 setTimeout(() => { this.connect(newToken) }, 1000) } } // 断开连接 disconnect() { this.client.deactivate() } // 订阅消息 subscribe(destination: string, callback: (message: any) => void) { if (!this.connected) { console.warn('WebSocket未连接') return } return this.client.subscribe(destination, (message) => { try { const data = JSON.parse(message.body) callback(data) } catch (error) { console.error('消息解析失败:', error) } }) } // 发送消息 send(destination: string, body: any) { if (!this.connected) { console.warn('WebSocket未连接,消息将被缓存') // 这里可以实现消息缓存逻辑 return } this.client.publish({ destination, body: JSON.stringify(body) }) } // 处理重连 private handleReconnect() { if (this.reconnectAttempts < this.maxReconnectAttempts) { this.reconnectAttempts++ setTimeout(() => { console.log(`尝试重连 (${this.reconnectAttempts}/${this.maxReconnectAttempts})`) this.client.activate() }, 5000 * this.reconnectAttempts) } } } ``` #### 聊天功能使用示例 ```typescript // composables/useChat.ts import { ref, onMounted, onUnmounted } from 'vue' import { WebSocketService } from '@/utils/websocket' import { useAuthStore } from '@/stores/auth' export function useChat() { const authStore = useAuthStore() const wsService = new WebSocketService() const messages = ref([]) const isConnected = ref(false) // 连接WebSocket const connect = () => { if (authStore.token) { wsService.connect(authStore.token) // 订阅个人消息 wsService.subscribe(`/user/${authStore.user.id}/queue/messages`, (message) => { messages.value.push(message) }) // 订阅聊天室消息 wsService.subscribe('/topic/chat', (message) => { messages.value.push(message) }) isConnected.value = true } } // 发送消息 const sendMessage = (content: string, type: 'text' | 'image' = 'text') => { const message = { content, type, timestamp: Date.now(), userId: authStore.user.id } wsService.send('/app/chat.send', message) } // 组件挂载时连接 onMounted(() => { connect() }) // 组件卸载时断开连接 onUnmounted(() => { wsService.disconnect() }) return { messages, isConnected, sendMessage, connect } } ``` ### 10.6 WebSocket Token认证详解 #### Token传递方式 原生WebSocket + STOMP协议支持Token认证: 1. **WebSocket握手时传递** (推荐) ```typescript // 在WebSocket连接建立时传递Token brokerURL: `${envConfig.wsBaseUrl}/ws`, connectHeaders: { Authorization: `Bearer ${token}`, 'X-Requested-With': 'XMLHttpRequest' } ``` 2. **URL参数传递** (备选方案) ```typescript // 如果后端不支持连接头部,可以通过URL传递 brokerURL: `${envConfig.wsBaseUrl}/ws?token=${token}` ``` **为什么移除SockJS?** - ❌ SockJS不支持在WebSocket握手时传递自定义请求头 - ❌ 无法在连接建立时进行Token认证 - ❌ 只能通过URL参数传递Token,安全性较低 - ✅ 原生WebSocket完全支持Token认证 - ✅ 现代浏览器WebSocket支持度已经很好 #### WebSocket方案对比 | 特性 | 原生WebSocket + STOMP | SockJS + STOMP | Socket.io | |------|---------------------|----------------|-----------| | **Token认证** | ✅ 支持请求头传递 | ❌ 不支持请求头 | ✅ 支持 | | **浏览器兼容** | ✅ 现代浏览器完全支持 | ✅ 兼容性最好 | ✅ 兼容性好 | | **包体积** | ✅ 最小 | ⚠️ 中等 | ❌ 最大 | | **Spring Boot集成** | ✅ 原生支持 | ✅ 原生支持 | ❌ 需要额外配置 | | **标准化** | ✅ 标准协议 | ✅ 标准协议 | ❌ 私有协议 | | **安全性** | ✅ 握手时认证 | ⚠️ URL参数认证 | ✅ 握手时认证 | **最终选择:原生WebSocket + STOMP** - 🎯 **安全性优先**: 支持在握手时进行Token认证 - 🎯 **性能最优**: 无额外协议层,直接使用WebSocket - 🎯 **标准化**: 基于标准STOMP协议 - 🎯 **轻量级**: 最小的包体积 - 🎯 **兼容性**: 现代浏览器支持度已经足够 #### Token刷新处理 ```typescript // stores/auth.ts - 认证状态管理 import { defineStore } from 'pinia' import { ref, watch } from 'vue' import { WebSocketService } from '@/utils/websocket' export const useAuthStore = defineStore('auth', () => { const token = ref('') const user = ref(null) const wsService = ref(null) // 监听Token变化,自动更新WebSocket连接 watch(token, (newToken, oldToken) => { if (newToken && newToken !== oldToken && wsService.value) { wsService.value.updateToken(newToken) } }) // 登录 const login = async (credentials: LoginRequest) => { try { const response = await authApi.login(credentials) token.value = response.token user.value = response.user // 登录成功后建立WebSocket连接 if (!wsService.value) { wsService.value = new WebSocketService() } wsService.value.connect(token.value) return response } catch (error) { throw error } } // 登出 const logout = () => { // 断开WebSocket连接 if (wsService.value) { wsService.value.disconnect() wsService.value = null } token.value = '' user.value = null } // Token刷新 const refreshToken = async () => { try { const response = await authApi.refreshToken() token.value = response.token // watch会自动处理WebSocket重连 return response } catch (error) { // Token刷新失败,执行登出 logout() throw error } } return { token, user, wsService, login, logout, refreshToken } }) ``` #### 后端WebSocket安全配置 对应的Spring Boot后端配置示例: ```java // WebSocketConfig.java @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/topic", "/queue"); config.setApplicationDestinationPrefixes("/app"); config.setUserDestinationPrefix("/user"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/ws") .setAllowedOriginPatterns("*"); // 移除.withSockJS(),使用原生WebSocket支持Token认证 } @Override public void configureClientInboundChannel(ChannelRegistration registration) { registration.interceptors(new AuthChannelInterceptor()); } } // AuthChannelInterceptor.java - Token验证拦截器 @Component public class AuthChannelInterceptor implements ChannelInterceptor { @Override public Message preSend(Message message, MessageChannel channel) { StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message); if (StompCommand.CONNECT.equals(accessor.getCommand())) { String token = accessor.getFirstNativeHeader("Authorization"); if (token != null && token.startsWith("Bearer ")) { String jwt = token.substring(7); // 验证JWT Token if (jwtTokenProvider.validateToken(jwt)) { String userId = jwtTokenProvider.getUserIdFromToken(jwt); accessor.setUser(new StompPrincipal(userId)); } else { throw new IllegalArgumentException("Invalid token"); } } else { throw new IllegalArgumentException("Missing token"); } } return message; } } ``` #### 错误处理和重连机制 ```typescript // 增强的WebSocket错误处理 export class WebSocketService { private tokenExpiredCallback?: () => void constructor(onTokenExpired?: () => void) { this.tokenExpiredCallback = onTokenExpired // ... 其他初始化代码 } private handleStompError(frame: any) { console.error('STOMP错误:', frame) // 检查是否是Token相关错误 if (frame.headers && frame.headers.message) { const errorMessage = frame.headers.message.toLowerCase() if (errorMessage.includes('unauthorized') || errorMessage.includes('invalid token') || errorMessage.includes('token expired')) { console.warn('Token认证失败,触发重新登录') this.tokenExpiredCallback?.() return } } // 其他错误进行重连 this.handleReconnect() } } // 在应用中使用 const authStore = useAuthStore() const wsService = new WebSocketService(() => { // Token过期回调 authStore.logout() router.push('/login') }) ``` #### 安全最佳实践 1. **Token验证**: 每次WebSocket连接都验证Token有效性 2. **权限控制**: 基于用户角色限制订阅和发送权限 3. **连接限制**: 限制单用户的并发连接数 4. **消息加密**: 敏感消息内容加密传输 5. **审计日志**: 记录WebSocket连接和消息日志 这个方案完全支持Token认证,并且提供了完整的Token生命周期管理,包括刷新、过期处理和安全重连机制。 ## 11. 测试策略 ### 11.1 单元测试 ```typescript // tests/components/UserProfile.test.ts import { mount } from '@vue/test-utils' import { describe, it, expect } from 'vitest' import UserProfile from '@/components/UserProfile.vue' describe('UserProfile', () => { it('renders user information correctly', () => { const user = { id: '1', username: 'testuser', nickname: 'Test User', avatar: 'https://example.com/avatar.jpg' } const wrapper = mount(UserProfile, { props: { user } }) expect(wrapper.text()).toContain('Test User') expect(wrapper.find('img').attributes('src')).toBe(user.avatar) }) }) ``` ### 11.2 E2E测试 ```typescript // cypress/e2e/auth.cy.ts describe('Authentication', () => { it('should login successfully', () => { cy.visit('/login') cy.get('[data-cy=username]').type('testuser') cy.get('[data-cy=password]').type('password123') cy.get('[data-cy=login-btn]').click() cy.url().should('include', '/dashboard') cy.get('[data-cy=user-menu]').should('be.visible') }) }) ``` ### 11.3 测试配置 ```typescript // vitest.config.ts import { defineConfig } from 'vitest/config' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], test: { environment: 'jsdom', globals: true, setupFiles: ['./tests/setup.ts'] }, resolve: { alias: { '@': '/src' } } }) ``` ## 12. 国际化支持 ### 12.1 i18n配置 - **vue-i18n**: `9.10.2` (国际化支持) - **@intlify/unplugin-vue-i18n**: `4.0.0` (构建时优化) ```typescript // i18n/index.ts import { createI18n } from 'vue-i18n' import zh from './locales/zh.json' import en from './locales/en.json' export const i18n = createI18n({ legacy: false, locale: 'zh', fallbackLocale: 'en', messages: { zh, en } }) ``` ### 12.2 语言文件结构 ```json // i18n/locales/zh.json { "common": { "confirm": "确认", "cancel": "取消", "save": "保存", "delete": "删除" }, "auth": { "login": "登录", "register": "注册", "logout": "退出登录" }, "chat": { "sendMessage": "发送消息", "typing": "正在输入...", "offline": "离线" } } ``` ## 13. 移动端适配 ### 13.1 响应式断点 ```css /* tailwind.config.js */ module.exports = { theme: { screens: { 'xs': '475px', 'sm': '640px', 'md': '768px', 'lg': '1024px', 'xl': '1280px', '2xl': '1536px', } } } ``` ### 13.2 移动端优化 - **触摸优化**: 44px最小触摸目标 - **手势支持**: 滑动、缩放、长按 - **性能优化**: 虚拟滚动、图片懒加载 - **离线支持**: Service Worker缓存 ### 13.3 PWA配置 ```typescript // vite.config.ts PWA配置 VitePWA({ registerType: 'autoUpdate', includeAssets: ['favicon.ico', 'apple-touch-icon.png'], manifest: { name: '情绪博物馆', short_name: '情绪博物馆', description: '记录情绪,分享心情的温暖空间', theme_color: '#4A90E2', background_color: '#ffffff', display: 'standalone', icons: [ { src: 'pwa-192x192.png', sizes: '192x192', type: 'image/png' }, { src: 'pwa-512x512.png', sizes: '512x512', type: 'image/png' } ] } }) ``` ## 14. 总结 本技术方案基于现代化的Vue3生态系统,采用TypeScript提供类型安全,使用Vite构建工具提升开发体验。方案涵盖了: ### 14.1 技术优势 - **现代化技术栈**: Vue3 + TypeScript + Vite - **完整的工具链**: 从开发到部署的全流程支持 - **性能优化**: 代码分割、懒加载、缓存策略 - **开发体验**: 热更新、自动导入、类型检查 ### 14.2 可扩展性 - **模块化设计**: 清晰的项目结构和职责分离 - **组件化开发**: 可复用的UI组件库 - **插件系统**: 支持功能扩展和第三方集成 - **国际化支持**: 多语言适配能力 ### 14.3 维护性 - **代码规范**: ESLint + Prettier统一代码风格 - **测试覆盖**: 单元测试 + E2E测试 - **文档完善**: 组件文档和API文档 - **版本管理**: 语义化版本控制 ### 14.4 部署方案 - **多环境支持**: local/dev/test/prod环境配置 - **容器化部署**: Docker + Nginx部署方案 - **CI/CD流程**: 自动化构建和部署 - **监控告警**: 错误监控和性能分析 这个技术方案能够很好地支持情绪博物馆Web端的所有功能需求,同时具备良好的可维护性和扩展性,为项目的长期发展奠定坚实基础。