# 解班客小程序架构文档 ## 1. 项目概述 ### 1.1 项目简介 解班客小程序是一个基于微信生态的社交旅行平台,融合了结伴旅行、动物认领、商家服务等核心功能。采用微信小程序原生开发框架,提供流畅的用户体验和丰富的社交功能。 ### 1.2 业务目标 - **社交旅行**:为用户提供结伴旅行的平台,增强旅行体验 - **动物认领**:创新的动物认领功能,增加用户粘性 - **商家服务**:为商家提供服务展示和预订平台 - **用户增长**:通过微信生态实现用户快速增长 ### 1.3 技术目标 - **性能优化**:快速加载,流畅交互 - **用户体验**:符合微信设计规范,操作简单直观 - **功能完整**:覆盖核心业务场景 - **扩展性强**:支持功能快速迭代和扩展 ## 2. 技术选型 ### 2.1 开发框架 #### 2.1.1 微信小程序原生框架 ```javascript // 选型理由 { "框架": "微信小程序原生", "版本": "最新稳定版", "优势": [ "官方支持,稳定性高", "性能最优,启动速度快", "API完整,功能丰富", "调试工具完善" ], "适用场景": [ "复杂业务逻辑", "高性能要求", "深度集成微信能力" ] } ``` #### 2.1.2 状态管理 ```javascript // Mobx-miniprogram { "库": "mobx-miniprogram", "版本": "^4.13.2", "优势": [ "响应式状态管理", "简单易用", "性能优秀", "支持计算属性" ] } ``` ### 2.2 UI组件库 #### 2.2.1 Vant Weapp ```javascript { "组件库": "Vant Weapp", "版本": "^1.11.2", "优势": [ "组件丰富", "设计规范", "文档完善", "社区活跃" ], "使用组件": [ "Button", "Cell", "Form", "Popup", "Dialog", "Toast", "Tab", "NavBar", "Search" ] } ``` ### 2.3 工具库 #### 2.3.1 网络请求 ```javascript // 自定义HTTP库 { "库": "自研HTTP库", "特性": [ "请求拦截器", "响应拦截器", "错误处理", "Loading管理", "Token自动刷新" ] } ``` #### 2.3.2 工具函数 ```javascript { "日期处理": "dayjs", "数据验证": "async-validator", "图片处理": "自研工具", "地理位置": "微信API", "支付": "微信支付API" } ``` ## 3. 架构设计 ### 3.1 整体架构 ```mermaid graph TB subgraph "小程序架构" A[用户界面层 UI Layer] B[业务逻辑层 Business Layer] C[数据管理层 Data Layer] D[服务层 Service Layer] E[工具层 Utils Layer] end subgraph "外部服务" F[后端API] G[微信API] H[第三方服务] end A --> B B --> C B --> D D --> F D --> G D --> H B --> E C --> E ``` ### 3.2 分层架构详解 #### 3.2.1 用户界面层 (UI Layer) ```javascript // 页面组件结构 pages/ ├── index/ // 首页 ├── travel/ // 结伴旅行 │ ├── list/ // 旅行列表 │ ├── detail/ // 旅行详情 │ └── create/ // 创建旅行 ├── animal/ // 动物认领 │ ├── list/ // 动物列表 │ ├── detail/ // 动物详情 │ └── adopt/ // 认领页面 ├── merchant/ // 商家服务 ├── user/ // 用户中心 └── common/ // 通用页面 ``` #### 3.2.2 业务逻辑层 (Business Layer) ```javascript // 业务模块结构 business/ ├── user/ // 用户业务 │ ├── auth.js // 认证逻辑 │ ├── profile.js // 用户资料 │ └── settings.js // 用户设置 ├── travel/ // 旅行业务 │ ├── list.js // 列表逻辑 │ ├── detail.js // 详情逻辑 │ └── booking.js // 预订逻辑 ├── animal/ // 动物业务 └── merchant/ // 商家业务 ``` #### 3.2.3 数据管理层 (Data Layer) ```javascript // 状态管理结构 store/ ├── index.js // Store入口 ├── user.js // 用户状态 ├── travel.js // 旅行状态 ├── animal.js // 动物状态 └── common.js // 通用状态 // 本地存储管理 storage/ ├── index.js // 存储管理器 ├── user.js // 用户数据 ├── cache.js // 缓存管理 └── config.js // 配置数据 ``` #### 3.2.4 服务层 (Service Layer) ```javascript // API服务结构 services/ ├── http.js // HTTP客户端 ├── user.js // 用户API ├── travel.js // 旅行API ├── animal.js // 动物API ├── merchant.js // 商家API ├── payment.js // 支付API └── upload.js // 文件上传 ``` #### 3.2.5 工具层 (Utils Layer) ```javascript // 工具函数结构 utils/ ├── index.js // 工具入口 ├── date.js // 日期工具 ├── format.js // 格式化工具 ├── validate.js // 验证工具 ├── location.js // 位置工具 ├── image.js // 图片工具 └── wechat.js // 微信API封装 ``` ## 4. 核心模块设计 ### 4.1 用户模块 #### 4.1.1 用户认证 ```javascript // 用户认证流程 class AuthService { // 微信登录 async wxLogin() { try { // 1. 获取微信授权码 const { code } = await wx.login(); // 2. 获取用户信息 const userInfo = await this.getUserProfile(); // 3. 后端验证登录 const result = await api.user.login({ code, userInfo }); // 4. 保存用户信息 await this.saveUserInfo(result); return result; } catch (error) { throw new Error('登录失败'); } } // 获取用户资料 async getUserProfile() { return new Promise((resolve, reject) => { wx.getUserProfile({ desc: '用于完善用户资料', success: resolve, fail: reject }); }); } } ``` #### 4.1.2 用户状态管理 ```javascript // 用户Store import { observable, action, computed } from 'mobx-miniprogram'; export const userStore = observable({ // 用户信息 userInfo: null, token: '', isLogin: false, // 用户设置 settings: { notifications: true, location: true, privacy: 'public' }, // 计算属性 get isVip() { return this.userInfo?.vipLevel > 0; }, // 动作 setUserInfo: action(function(userInfo) { this.userInfo = userInfo; this.isLogin = true; }), setToken: action(function(token) { this.token = token; }), logout: action(function() { this.userInfo = null; this.token = ''; this.isLogin = false; }) }); ``` ### 4.2 旅行模块 #### 4.2.1 旅行列表 ```javascript // 旅行列表组件 Component({ data: { travelList: [], loading: false, hasMore: true, page: 1, filters: { city: '', date: '', type: '' } }, lifetimes: { attached() { this.loadTravelList(); } }, methods: { // 加载旅行列表 async loadTravelList(refresh = false) { if (this.data.loading) return; this.setData({ loading: true }); try { const page = refresh ? 1 : this.data.page; const result = await api.travel.getList({ page, ...this.data.filters }); const travelList = refresh ? result.list : [...this.data.travelList, ...result.list]; this.setData({ travelList, hasMore: result.hasMore, page: page + 1, loading: false }); } catch (error) { this.setData({ loading: false }); wx.showToast({ title: '加载失败', icon: 'error' }); } }, // 筛选 onFilter(e) { const filters = e.detail; this.setData({ filters }); this.loadTravelList(true); }, // 下拉刷新 onRefresh() { this.loadTravelList(true); }, // 上拉加载 onLoadMore() { if (this.data.hasMore) { this.loadTravelList(); } } } }); ``` #### 4.2.2 旅行详情 ```javascript // 旅行详情页面 Page({ data: { travelId: '', travelDetail: null, loading: true, joined: false, participants: [] }, onLoad(options) { this.setData({ travelId: options.id }); this.loadTravelDetail(); }, // 加载旅行详情 async loadTravelDetail() { try { const result = await api.travel.getDetail(this.data.travelId); this.setData({ travelDetail: result.travel, participants: result.participants, joined: result.joined, loading: false }); } catch (error) { this.setData({ loading: false }); wx.showToast({ title: '加载失败', icon: 'error' }); } }, // 加入旅行 async joinTravel() { try { await api.travel.join(this.data.travelId); this.setData({ joined: true }); wx.showToast({ title: '加入成功', icon: 'success' }); // 刷新参与者列表 this.loadTravelDetail(); } catch (error) { wx.showToast({ title: error.message || '加入失败', icon: 'error' }); } } }); ``` ### 4.3 动物认领模块 #### 4.3.1 动物列表 ```javascript // 动物列表组件 Component({ data: { animalList: [], categories: [], selectedCategory: '', loading: false }, lifetimes: { attached() { this.loadCategories(); this.loadAnimalList(); } }, methods: { // 加载动物分类 async loadCategories() { try { const categories = await api.animal.getCategories(); this.setData({ categories }); } catch (error) { console.error('加载分类失败', error); } }, // 加载动物列表 async loadAnimalList() { this.setData({ loading: true }); try { const result = await api.animal.getList({ category: this.data.selectedCategory }); this.setData({ animalList: result.list, loading: false }); } catch (error) { this.setData({ loading: false }); wx.showToast({ title: '加载失败', icon: 'error' }); } }, // 切换分类 onCategoryChange(e) { const category = e.detail; this.setData({ selectedCategory: category }); this.loadAnimalList(); }, // 认领动物 async adoptAnimal(e) { const animalId = e.currentTarget.dataset.id; try { await api.animal.adopt(animalId); wx.showToast({ title: '认领成功', icon: 'success' }); // 刷新列表 this.loadAnimalList(); } catch (error) { wx.showToast({ title: error.message || '认领失败', icon: 'error' }); } } } }); ``` ### 4.4 支付模块 #### 4.4.1 支付服务 ```javascript // 支付服务 class PaymentService { // 微信支付 async wxPay(orderInfo) { try { // 1. 创建支付订单 const paymentData = await api.payment.createOrder(orderInfo); // 2. 调用微信支付 const result = await this.requestPayment(paymentData); // 3. 支付成功处理 await this.handlePaymentSuccess(result); return result; } catch (error) { throw new Error('支付失败'); } } // 调用微信支付API requestPayment(paymentData) { return new Promise((resolve, reject) => { wx.requestPayment({ timeStamp: paymentData.timeStamp, nonceStr: paymentData.nonceStr, package: paymentData.package, signType: paymentData.signType, paySign: paymentData.paySign, success: resolve, fail: reject }); }); } // 支付成功处理 async handlePaymentSuccess(result) { // 更新订单状态 await api.payment.confirmPayment(result); // 更新本地状态 // ... } } ``` ## 5. 数据架构 ### 5.1 状态管理架构 ```mermaid graph TB subgraph "Store架构" A[RootStore] B[UserStore] C[TravelStore] D[AnimalStore] E[CommonStore] end subgraph "页面组件" F[Page Components] G[Custom Components] end subgraph "本地存储" H[Storage Manager] I[Cache Manager] end A --> B A --> C A --> D A --> E F --> A G --> A A --> H A --> I ``` ### 5.2 数据流设计 #### 5.2.1 数据流向 ```javascript // 数据流管理 class DataFlow { // 数据获取流程 async fetchData(type, params) { // 1. 检查缓存 const cached = await this.checkCache(type, params); if (cached && !this.isExpired(cached)) { return cached.data; } // 2. 请求API const data = await this.requestAPI(type, params); // 3. 更新缓存 await this.updateCache(type, params, data); // 4. 更新Store this.updateStore(type, data); return data; } // 缓存管理 async checkCache(type, params) { const key = this.generateCacheKey(type, params); return await storage.get(key); } async updateCache(type, params, data) { const key = this.generateCacheKey(type, params); await storage.set(key, { data, timestamp: Date.now(), expiry: this.getCacheExpiry(type) }); } } ``` ### 5.3 本地存储设计 #### 5.3.1 存储结构 ```javascript // 存储管理器 class StorageManager { constructor() { this.prefix = 'jiebanke_'; this.version = '1.0.0'; } // 用户数据存储 async setUserData(data) { await this.set('user_data', { ...data, version: this.version, timestamp: Date.now() }); } // 缓存数据存储 async setCacheData(key, data, expiry = 3600000) { await this.set(`cache_${key}`, { data, expiry: Date.now() + expiry, version: this.version }); } // 基础存储方法 async set(key, value) { try { await wx.setStorage({ key: this.prefix + key, data: value }); } catch (error) { console.error('存储失败', error); } } async get(key) { try { const result = await wx.getStorage({ key: this.prefix + key }); return result.data; } catch (error) { return null; } } } ``` ## 6. 网络架构 ### 6.1 HTTP客户端设计 ```javascript // HTTP客户端 class HttpClient { constructor() { this.baseURL = 'https://api.jiebanke.com'; this.timeout = 10000; this.interceptors = { request: [], response: [] }; } // 请求拦截器 addRequestInterceptor(interceptor) { this.interceptors.request.push(interceptor); } // 响应拦截器 addResponseInterceptor(interceptor) { this.interceptors.response.push(interceptor); } // 发送请求 async request(config) { // 应用请求拦截器 for (const interceptor of this.interceptors.request) { config = await interceptor(config); } try { const response = await this.wxRequest(config); // 应用响应拦截器 for (const interceptor of this.interceptors.response) { response = await interceptor(response); } return response; } catch (error) { throw this.handleError(error); } } // 微信请求封装 wxRequest(config) { return new Promise((resolve, reject) => { wx.request({ url: this.baseURL + config.url, method: config.method || 'GET', data: config.data, header: { 'Content-Type': 'application/json', ...config.headers }, timeout: this.timeout, success: resolve, fail: reject }); }); } } ``` ### 6.2 API服务设计 #### 6.2.1 用户API ```javascript // 用户API服务 class UserAPI { constructor(http) { this.http = http; } // 用户登录 async login(data) { return await this.http.request({ url: '/user/login', method: 'POST', data }); } // 获取用户信息 async getProfile() { return await this.http.request({ url: '/user/profile', method: 'GET' }); } // 更新用户信息 async updateProfile(data) { return await this.http.request({ url: '/user/profile', method: 'PUT', data }); } } ``` #### 6.2.2 旅行API ```javascript // 旅行API服务 class TravelAPI { constructor(http) { this.http = http; } // 获取旅行列表 async getList(params) { return await this.http.request({ url: '/travel/list', method: 'GET', data: params }); } // 获取旅行详情 async getDetail(id) { return await this.http.request({ url: `/travel/${id}`, method: 'GET' }); } // 创建旅行 async create(data) { return await this.http.request({ url: '/travel', method: 'POST', data }); } // 加入旅行 async join(id) { return await this.http.request({ url: `/travel/${id}/join`, method: 'POST' }); } } ``` ## 7. 性能优化 ### 7.1 启动性能优化 #### 7.1.1 代码分包 ```javascript // app.json 分包配置 { "pages": [ "pages/index/index", "pages/user/index" ], "subPackages": [ { "root": "packages/travel", "name": "travel", "pages": [ "list/index", "detail/index", "create/index" ] }, { "root": "packages/animal", "name": "animal", "pages": [ "list/index", "detail/index", "adopt/index" ] } ], "preloadRule": { "pages/index/index": { "network": "all", "packages": ["travel"] } } } ``` #### 7.1.2 资源优化 ```javascript // 图片懒加载组件 Component({ properties: { src: String, placeholder: String }, data: { loaded: false, error: false }, lifetimes: { attached() { this.observer = wx.createIntersectionObserver(this); this.observer.relativeToViewport().observe('.lazy-image', (res) => { if (res.intersectionRatio > 0) { this.loadImage(); this.observer.disconnect(); } }); }, detached() { if (this.observer) { this.observer.disconnect(); } } }, methods: { loadImage() { const img = wx.createImage(); img.onload = () => { this.setData({ loaded: true }); }; img.onerror = () => { this.setData({ error: true }); }; img.src = this.properties.src; } } }); ``` ### 7.2 运行时性能优化 #### 7.2.1 数据缓存策略 ```javascript // 缓存策略管理 class CacheStrategy { constructor() { this.strategies = { // 用户数据 - 长期缓存 user: { expiry: 24 * 60 * 60 * 1000, // 24小时 storage: 'local' }, // 旅行列表 - 短期缓存 travelList: { expiry: 5 * 60 * 1000, // 5分钟 storage: 'memory' }, // 动物列表 - 中期缓存 animalList: { expiry: 30 * 60 * 1000, // 30分钟 storage: 'local' } }; } // 获取缓存策略 getStrategy(type) { return this.strategies[type] || { expiry: 5 * 60 * 1000, storage: 'memory' }; } // 检查缓存是否过期 isExpired(cacheData, type) { const strategy = this.getStrategy(type); return Date.now() - cacheData.timestamp > strategy.expiry; } } ``` #### 7.2.2 列表虚拟化 ```javascript // 虚拟列表组件 Component({ properties: { items: Array, itemHeight: Number, containerHeight: Number }, data: { visibleItems: [], scrollTop: 0, startIndex: 0, endIndex: 0 }, observers: { 'items, containerHeight, itemHeight': function() { this.updateVisibleItems(); } }, methods: { // 更新可见项目 updateVisibleItems() { const { items, itemHeight, containerHeight } = this.properties; const { scrollTop } = this.data; const visibleCount = Math.ceil(containerHeight / itemHeight); const startIndex = Math.floor(scrollTop / itemHeight); const endIndex = Math.min(startIndex + visibleCount + 1, items.length); const visibleItems = items.slice(startIndex, endIndex).map((item, index) => ({ ...item, index: startIndex + index, top: (startIndex + index) * itemHeight })); this.setData({ visibleItems, startIndex, endIndex }); }, // 滚动事件 onScroll(e) { const scrollTop = e.detail.scrollTop; this.setData({ scrollTop }); this.updateVisibleItems(); } } }); ``` ## 8. 安全架构 ### 8.1 数据安全 #### 8.1.1 敏感数据加密 ```javascript // 数据加密工具 class CryptoUtil { constructor() { this.algorithm = 'AES-256-GCM'; this.keyLength = 32; } // 生成密钥 generateKey() { const array = new Uint8Array(this.keyLength); wx.getRandomValues(array); return Array.from(array).map(b => b.toString(16).padStart(2, '0')).join(''); } // 加密数据 encrypt(data, key) { try { const jsonString = JSON.stringify(data); const encrypted = this.aesEncrypt(jsonString, key); return encrypted; } catch (error) { throw new Error('加密失败'); } } // 解密数据 decrypt(encryptedData, key) { try { const decrypted = this.aesDecrypt(encryptedData, key); return JSON.parse(decrypted); } catch (error) { throw new Error('解密失败'); } } } ``` #### 8.1.2 Token管理 ```javascript // Token管理器 class TokenManager { constructor() { this.tokenKey = 'access_token'; this.refreshTokenKey = 'refresh_token'; } // 保存Token async saveToken(tokenData) { await storage.set(this.tokenKey, { token: tokenData.accessToken, expiry: Date.now() + tokenData.expiresIn * 1000 }); await storage.set(this.refreshTokenKey, tokenData.refreshToken); } // 获取Token async getToken() { const tokenData = await storage.get(this.tokenKey); if (!tokenData) { return null; } // 检查是否过期 if (Date.now() > tokenData.expiry) { return await this.refreshToken(); } return tokenData.token; } // 刷新Token async refreshToken() { try { const refreshToken = await storage.get(this.refreshTokenKey); if (!refreshToken) { throw new Error('Refresh token not found'); } const result = await api.user.refreshToken(refreshToken); await this.saveToken(result); return result.accessToken; } catch (error) { // 刷新失败,清除所有Token await this.clearTokens(); throw error; } } // 清除Token async clearTokens() { await storage.remove(this.tokenKey); await storage.remove(this.refreshTokenKey); } } ``` ### 8.2 接口安全 #### 8.2.1 请求签名 ```javascript // 请求签名工具 class RequestSigner { constructor(secretKey) { this.secretKey = secretKey; } // 生成签名 generateSignature(params, timestamp, nonce) { // 1. 参数排序 const sortedParams = this.sortParams(params); // 2. 构建签名字符串 const signString = this.buildSignString(sortedParams, timestamp, nonce); // 3. 生成签名 const signature = this.hmacSha256(signString, this.secretKey); return signature; } // 参数排序 sortParams(params) { return Object.keys(params) .sort() .reduce((result, key) => { result[key] = params[key]; return result; }, {}); } // 构建签名字符串 buildSignString(params, timestamp, nonce) { const paramString = Object.keys(params) .map(key => `${key}=${params[key]}`) .join('&'); return `${paramString}×tamp=${timestamp}&nonce=${nonce}&secret=${this.secretKey}`; } } ``` ## 9. 测试架构 ### 9.1 单元测试 #### 9.1.1 工具函数测试 ```javascript // 工具函数测试 describe('DateUtil', () => { test('formatDate should format date correctly', () => { const date = new Date('2023-12-25'); const formatted = DateUtil.formatDate(date, 'YYYY-MM-DD'); expect(formatted).toBe('2023-12-25'); }); test('isValidDate should validate date correctly', () => { expect(DateUtil.isValidDate('2023-12-25')).toBe(true); expect(DateUtil.isValidDate('invalid-date')).toBe(false); }); }); // API服务测试 describe('UserAPI', () => { let userAPI; let mockHttp; beforeEach(() => { mockHttp = { request: jest.fn() }; userAPI = new UserAPI(mockHttp); }); test('login should call correct endpoint', async () => { const loginData = { code: 'test-code' }; const expectedResponse = { token: 'test-token' }; mockHttp.request.mockResolvedValue(expectedResponse); const result = await userAPI.login(loginData); expect(mockHttp.request).toHaveBeenCalledWith({ url: '/user/login', method: 'POST', data: loginData }); expect(result).toEqual(expectedResponse); }); }); ``` ### 9.2 集成测试 #### 9.2.1 页面测试 ```javascript // 页面集成测试 describe('Travel List Page', () => { let page; beforeEach(() => { page = new TravelListPage(); // Mock API responses jest.spyOn(api.travel, 'getList').mockResolvedValue({ list: [ { id: 1, title: 'Test Travel 1' }, { id: 2, title: 'Test Travel 2' } ], hasMore: false }); }); test('should load travel list on page load', async () => { await page.onLoad(); expect(api.travel.getList).toHaveBeenCalled(); expect(page.data.travelList).toHaveLength(2); expect(page.data.loading).toBe(false); }); test('should handle filter changes', async () => { const filters = { city: 'Beijing', date: '2023-12-25' }; await page.onFilter({ detail: filters }); expect(api.travel.getList).toHaveBeenCalledWith( expect.objectContaining(filters) ); }); }); ``` ### 9.3 端到端测试 #### 9.3.1 用户流程测试 ```javascript // E2E测试 describe('User Journey', () => { test('complete travel booking flow', async () => { // 1. 用户登录 await page.goto('/pages/user/login'); await page.tap('.login-btn'); await page.waitFor('.user-info'); // 2. 浏览旅行列表 await page.goto('/pages/travel/list'); await page.waitFor('.travel-item'); // 3. 查看旅行详情 await page.tap('.travel-item:first-child'); await page.waitFor('.travel-detail'); // 4. 加入旅行 await page.tap('.join-btn'); await page.waitFor('.success-toast'); // 5. 验证结果 const joinedStatus = await page.$('.joined-status'); expect(joinedStatus).toBeTruthy(); }); }); ``` ## 10. 部署架构 ### 10.1 构建配置 #### 10.1.1 环境配置 ```javascript // 环境配置 const config = { development: { apiBaseURL: 'https://dev-api.jiebanke.com', debug: true, logLevel: 'debug' }, testing: { apiBaseURL: 'https://test-api.jiebanke.com', debug: true, logLevel: 'info' }, production: { apiBaseURL: 'https://api.jiebanke.com', debug: false, logLevel: 'error' } }; // 获取当前环境配置 function getConfig() { const env = process.env.NODE_ENV || 'development'; return config[env]; } module.exports = getConfig(); ``` #### 10.1.2 构建脚本 ```json { "scripts": { "dev": "cross-env NODE_ENV=development miniprogram-cli dev", "build:test": "cross-env NODE_ENV=testing miniprogram-cli build", "build:prod": "cross-env NODE_ENV=production miniprogram-cli build", "preview": "miniprogram-cli preview", "upload": "miniprogram-cli upload", "test": "jest", "lint": "eslint . --ext .js", "lint:fix": "eslint . --ext .js --fix" } } ``` ### 10.2 CI/CD流程 #### 10.2.1 GitHub Actions配置 ```yaml # .github/workflows/miniprogram.yml name: MiniProgram CI/CD on: push: branches: [ main, develop ] pull_request: branches: [ main ] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: '16' cache: 'npm' - name: Install dependencies run: npm ci - name: Run tests run: npm test - name: Run linting run: npm run lint build-and-deploy: needs: test runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: '16' cache: 'npm' - name: Install dependencies run: npm ci - name: Build for production run: npm run build:prod - name: Upload to WeChat run: npm run upload env: WECHAT_APPID: ${{ secrets.WECHAT_APPID }} WECHAT_PRIVATE_KEY: ${{ secrets.WECHAT_PRIVATE_KEY }} ``` ## 11. 监控与分析 ### 11.1 性能监控 #### 11.1.1 性能指标收集 ```javascript // 性能监控工具 class PerformanceMonitor { constructor() { this.metrics = {}; this.init(); } init() { // 监听页面性能 wx.onAppRoute((res) => { this.trackPagePerformance(res); }); // 监听网络请求 this.interceptNetworkRequests(); } // 页面性能追踪 trackPagePerformance(route) { const startTime = Date.now(); // 页面加载完成后记录 setTimeout(() => { const loadTime = Date.now() - startTime; this.recordMetric('page_load_time', { route: route.path, loadTime, timestamp: Date.now() }); }, 0); } // 网络请求拦截 interceptNetworkRequests() { const originalRequest = wx.request; wx.request = (options) => { const startTime = Date.now(); const originalSuccess = options.success; const originalFail = options.fail; options.success = (res) => { const duration = Date.now() - startTime; this.recordMetric('api_request', { url: options.url, method: options.method, duration, status: res.statusCode, success: true }); if (originalSuccess) { originalSuccess(res); } }; options.fail = (err) => { const duration = Date.now() - startTime; this.recordMetric('api_request', { url: options.url, method: options.method, duration, success: false, error: err.errMsg }); if (originalFail) { originalFail(err); } }; return originalRequest(options); }; } // 记录指标 recordMetric(type, data) { if (!this.metrics[type]) { this.metrics[type] = []; } this.metrics[type].push(data); // 定期上报 this.reportMetrics(); } // 上报指标 async reportMetrics() { if (Object.keys(this.metrics).length === 0) { return; } try { await api.analytics.reportMetrics(this.metrics); this.metrics = {}; // 清空已上报的指标 } catch (error) { console.error('指标上报失败', error); } } } ``` ### 11.2 错误监控 #### 11.2.1 错误捕获和上报 ```javascript // 错误监控工具 class ErrorMonitor { constructor() { this.errors = []; this.init(); } init() { // 全局错误监听 wx.onError((error) => { this.captureError('global_error', error); }); // 未处理的Promise拒绝 wx.onUnhandledRejection((res) => { this.captureError('unhandled_rejection', res.reason); }); // HTTP错误监听 this.interceptHttpErrors(); } // 捕获错误 captureError(type, error) { const errorInfo = { type, message: error.message || error, stack: error.stack, timestamp: Date.now(), userAgent: wx.getSystemInfoSync(), route: getCurrentPages().pop()?.route }; this.errors.push(errorInfo); // 立即上报严重错误 if (this.isCriticalError(error)) { this.reportErrors(); } } // 判断是否为严重错误 isCriticalError(error) { const criticalKeywords = ['network', 'payment', 'auth']; const message = (error.message || error).toLowerCase(); return criticalKeywords.some(keyword => message.includes(keyword) ); } // 上报错误 async reportErrors() { if (this.errors.length === 0) { return; } try { await api.analytics.reportErrors(this.errors); this.errors = []; // 清空已上报的错误 } catch (error) { console.error('错误上报失败', error); } } } ``` ## 12. 总结 ### 12.1 架构优势 #### 12.1.1 技术优势 - **原生性能**:使用微信小程序原生框架,性能最优 - **开发效率**:组件化开发,代码复用率高 - **用户体验**:符合微信设计规范,用户学习成本低 - **生态集成**:深度集成微信生态,功能丰富 #### 12.1.2 业务优势 - **快速迭代**:模块化架构,支持功能快速开发和上线 - **数据驱动**:完善的数据收集和分析体系 - **用户增长**:利用微信社交关系链,促进用户增长 - **商业变现**:多样化的商业模式支持 ### 12.2 扩展性设计 #### 12.2.1 功能扩展 - **插件化架构**:支持功能模块插件化扩展 - **配置化管理**:业务规则配置化,灵活调整 - **API版本管理**:支持API平滑升级 - **多端适配**:架构支持多端扩展 #### 12.2.2 性能扩展 - **分包加载**:支持功能分包,按需加载 - **缓存策略**:多级缓存,提高响应速度 - **虚拟化列表**:支持大数据量列表展示 - **图片优化**:懒加载和压缩优化 ### 12.3 运维保障 #### 12.3.1 监控体系 - **性能监控**:全方位性能指标监控 - **错误监控**:实时错误捕获和告警 - **用户行为分析**:用户行为数据收集和分析 - **业务指标监控**:关键业务指标实时监控 #### 12.3.2 质量保障 - **自动化测试**:单元测试、集成测试、E2E测试 - **代码质量**:ESLint代码规范检查 - **CI/CD流程**:自动化构建和部署 - **版本管理**:规范的版本发布流程 本小程序架构文档为解班客项目提供了完整的前端架构指导,通过合理的架构设计和技术选型,确保小程序的高性能、高可用性和良好的用户体验,为业务发展提供坚实的技术基础。