/** * 应用入口文件 * 初始化应用、注册插件、配置全局设置 */ import { createSSRApp } from 'vue' import App from './App.vue' import { createPinia } from 'pinia' // 导入配置 import { CONFIG, FEATURE_FLAGS } from '@/common/config/app.config.js' // 导入插件 import pluginManager, { RequestInterceptorPlugin, RouteInterceptorPlugin, ErrorHandlerPlugin, PerformancePlugin, CachePlugin } from '@/common/plugins/index.js' // 导入工具类 import { createLogger } from '@/common/utils/logger.js' import { permission } from '@/common/utils/permission.js' import { storage } from '@/common/utils/storage.js' // 导入API import api from '@/common/api/index.js' // 导入样式 import '@/common/styles/index.scss' const logger = createLogger('Main') export function createApp() { const app = createSSRApp(App) // 创建 Pinia 状态管理 const pinia = createPinia() app.use(pinia) // 初始化权限管理 permission.init?.() // 注册插件 registerPlugins(app) // 配置全局属性 setupGlobalProperties(app) // 配置全局错误处理 setupErrorHandling(app) // 初始化应用 initializeApp() logger.info('Application created successfully', { version: CONFIG.APP_VERSION, environment: CONFIG.NODE_ENV }) return { app, Pinia: pinia } } /** * 注册插件 */ function registerPlugins(app) { // 请求拦截器插件 pluginManager.register(new RequestInterceptorPlugin({ request: (config) => { // 添加认证头 const token = storage.get('token') if (token) { config.header = config.header || {} config.header.Authorization = `Bearer ${token}` } // 添加公共参数 config.header = { ...config.header, 'Content-Type': 'application/json', 'X-App-Version': CONFIG.APP_VERSION || '1.0.0', 'X-Platform': 'miniprogram' } logger.api(config.method || 'GET', config.url, config.data, 0, 0) return config }, response: (response) => { // 统一处理响应 if (response.statusCode === 401) { // 清除登录信息 storage.remove('token') storage.remove('userInfo') // 跳转到登录页 uni.reLaunch({ url: '/pages/login/login' }) return Promise.reject(new Error('登录已过期')) } if (response.statusCode >= 400) { const error = new Error(response.data?.message || '请求失败') error.code = response.statusCode error.data = response.data return Promise.reject(error) } return response }, error: (error) => { logger.error('Request error', null, error) uni.showToast({ title: error.message || '网络错误', icon: 'none', duration: 2000 }) } })) // 路由拦截器插件 pluginManager.register(new RouteInterceptorPlugin({ beforeEach: (to, method) => { logger.debug('Route before', { to, method }) // 检查页面权限 if (to.url && to.url.includes('/pages/admin/')) { if (!permission.checkRole(['admin', 'super_admin'], 'or')) { uni.showToast({ title: '权限不足', icon: 'none' }) return false } } return to }, afterEach: (result, method) => { logger.debug('Route after', { result, method }) } })) // 错误处理插件 pluginManager.register(new ErrorHandlerPlugin({ onError: (error, instance, info) => { logger.error('Application error', { info }, error) // 在开发环境显示错误详情 if (CONFIG.DEBUG) { console.error('Vue Error:', error) console.error('Component:', instance) console.error('Info:', info) } // 显示用户友好的错误信息 uni.showToast({ title: '应用出现错误', icon: 'none', duration: 2000 }) }, onUnhandledRejection: (event) => { logger.error('Unhandled promise rejection', { reason: event.reason }) if (CONFIG.DEBUG) { console.error('Unhandled Promise Rejection:', event.reason) } } })) // 性能监控插件 if (FEATURE_FLAGS.PERFORMANCE_MONITORING) { pluginManager.register(new PerformancePlugin({ enabled: true, sampleRate: CONFIG.NODE_ENV === 'production' ? 0.1 : 1.0 })) } // 缓存插件 pluginManager.register(new CachePlugin({ defaultExpire: 30 * 60 * 1000, // 30分钟 maxSize: 10 * 1024 * 1024, // 10MB cleanupInterval: 10 * 60 * 1000 // 10分钟 })) // 安装所有插件 pluginManager.installAll(app) } /** * 配置全局属性 */ function setupGlobalProperties(app) { // 全局配置 app.config.globalProperties.$config = CONFIG app.config.globalProperties.$features = FEATURE_FLAGS // 工具类 app.config.globalProperties.$logger = logger app.config.globalProperties.$permission = permission app.config.globalProperties.$storage = storage app.config.globalProperties.$api = api // 常用方法 app.config.globalProperties.$toast = (title, icon = 'none', duration = 2000) => { uni.showToast({ title, icon, duration }) } app.config.globalProperties.$loading = { show: (title = '加载中...') => uni.showLoading({ title }), hide: () => uni.hideLoading() } app.config.globalProperties.$modal = (options) => { return new Promise((resolve) => { uni.showModal({ title: options.title || '提示', content: options.content || '', confirmText: options.confirmText || '确定', cancelText: options.cancelText || '取消', success: (res) => resolve(res.confirm), fail: () => resolve(false) }) }) } // 格式化工具 app.config.globalProperties.$filters = { currency: (value) => { if (!value) return '0.00' return parseFloat(value).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) }, date: (value, format = 'YYYY-MM-DD') => { if (!value) return '' const date = new Date(value) const year = date.getFullYear() const month = String(date.getMonth() + 1).padStart(2, '0') const day = String(date.getDate()).padStart(2, '0') const hour = String(date.getHours()).padStart(2, '0') const minute = String(date.getMinutes()).padStart(2, '0') const second = String(date.getSeconds()).padStart(2, '0') return format .replace('YYYY', year) .replace('MM', month) .replace('DD', day) .replace('HH', hour) .replace('mm', minute) .replace('ss', second) }, fileSize: (bytes) => { if (!bytes) return '0 B' const k = 1024 const sizes = ['B', 'KB', 'MB', 'GB'] const i = Math.floor(Math.log(bytes) / Math.log(k)) return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i] }, truncate: (text, length = 50) => { if (!text) return '' return text.length > length ? text.substring(0, length) + '...' : text } } } /** * 配置全局错误处理 */ function setupErrorHandling(app) { // Vue 错误处理 app.config.errorHandler = (error, instance, info) => { logger.error('Vue error handler', { info }, error) } // 全局未捕获错误 if (typeof uni !== 'undefined') { uni.onError((error) => { logger.error('Global error handler', null, new Error(error)) }) uni.onUnhandledRejection((event) => { logger.error('Global unhandled rejection', { reason: event.reason }) }) } // 网络错误处理 uni.onNetworkStatusChange((res) => { if (!res.isConnected) { uni.showToast({ title: '网络连接已断开', icon: 'none', duration: 3000 }) } }) } /** * 初始化应用 */ function initializeApp() { // 检查更新 if (typeof uni !== 'undefined' && uni.getUpdateManager) { const updateManager = uni.getUpdateManager() updateManager.onCheckForUpdate((res) => { if (res.hasUpdate) { logger.info('New version available') } }) updateManager.onUpdateReady(() => { uni.showModal({ title: '更新提示', content: '新版本已经准备好,是否重启应用?', success: (res) => { if (res.confirm) { updateManager.applyUpdate() } } }) }) updateManager.onUpdateFailed(() => { logger.error('Update failed') }) } // 初始化用户信息 const token = storage.get('token') if (token) { // 验证 token 有效性 api.user.getCurrentUser().catch(() => { // token 无效,清除登录信息 storage.remove('token') storage.remove('userInfo') }) } // 初始化系统信息 try { const systemInfo = uni.getSystemInfoSync() logger.info('System info', { platform: systemInfo.platform, system: systemInfo.system, version: systemInfo.version, screenWidth: systemInfo.screenWidth, screenHeight: systemInfo.screenHeight }) // 设置全局系统信息 uni.$systemInfo = systemInfo } catch (error) { logger.error('Failed to get system info', null, error) } // 初始化网络状态 uni.getNetworkType({ success: (res) => { logger.info('Network type', { networkType: res.networkType }) uni.$networkType = res.networkType } }) logger.info('Application initialized successfully') }