import { IAppState, type ISystemConfig, type ILaunchData, type IBaseData, type IRecommendData, IUnread } from '@/types/app.uts' import userState, { isLoggedIn } from './user.uts' import Api from '@/common/api-service.uts' import messageService from '@/services/websocket/message-service.uts' import httpApi from '@/utlis/http-api.uts' const initialAppState : IAppState = { baseURL: '', timeout: 15000, enableCache: true, cacheExpire: 5 * 60 * 1000, enableLog: true, systemConf: null, launchData: null, baseData: null, recommendData: null, unread: null, initialized: false, // 时间信息 startTime: 0, endTime: 0, lastInitTime: 0, // 网络状态 networkType: 'none', isConnected: false } const appState = reactive(initialAppState) /** * 初始化应用 * 注意:系统配置/启动数据/基础数据每次启动都需加载(提供 socketUrl、功能开关、cdn 等), * 不再依赖 isInitialUse 闸门,避免配置永远不加载。 */ export const initApp = async function () : Promise { try { appState.startTime = Date.now() startNetworkListen() // 1. 系统配置(socketUrl / 功能开关 / cdn 等) await loadSystemConfig() // 2. 启动数据(广告/轮播/快捷入口/新手引导) await loadLaunchData() // 3. 基础数据(城市/标签/礼物/等级等) await loadBaseData() // 已登录:连接实时消息通道并加载用户态数据 if (isLoggedIn.value) { connectWebSocket() await loadRecommendData() await syncUnreadCounts() } appState.initialized = true appState.endTime = Date.now() appState.lastInitTime = Date.now() return true } catch (error : any) { console.error('应用初始化失败:', error) return false } } /** * 已登录时按需连接 WebSocket 实时消息通道 */ export const connectWebSocket = function () : void { messageService.connectIfNeeded(appState.systemConf?.socketUrl ?? null) } export const startNetworkListen = async function () { uni.onNetworkStatusChange((result) => { console.log('网络状态变化:', result) appState.networkType = result.networkType //网络类型 appState.isConnected = result.isConnected //是否已连接 }) } /** * 加载系统配置 */ export const loadSystemConfig = async function () : Promise { try { const data = await Api.app.appConf() const result = data.parse() if (result != null) { appState.systemConf = result setCacheData('system_config', data) } else { appState.systemConf = getAppDefaultConf() } } catch (error) { console.warn('加载系统配置失败,使用缓存或默认配置', error) const cachedConfig = getCachedSystemConfig('system_config') appState.systemConf = cachedConfig != null ? cachedConfig : getAppDefaultConf() } // 将后端下发的 apiUrl 同步为 HTTP 客户端基础域名(接口 URL 已含 /wxchat/api 前缀) applyApiBaseURL(appState.systemConf?.apiUrl) } /** * 设置 HTTP 客户端基础域名(去除末尾斜杠,避免拼接出 //wxchat) */ export const applyApiBaseURL = function (apiUrl : string | null | undefined) : void { if (apiUrl == null || apiUrl.length == 0) { return } const base = apiUrl.replace(/\/+$/, '') if (base.length > 0) { httpApi.setBaseURL(base) console.log('[app] HTTP baseURL 已设置为:', base) } } /** * 加载启动数据 */ const loadLaunchData = async function () : Promise { try { const data = await Api.app.launchData() const result = data.parse() if (result != null) { appState.launchData = result setCacheData('launch_data', data) } else { appState.launchData = getDefaultLaunchData() } } catch (error) { console.warn('加载启动数据失败,使用默认启动数据 :', error) const cachedData = getCachedLaunchData('launch_data') appState.launchData = cachedData != null ? cachedData : getDefaultLaunchData() } } /** * 加载基础数据 */ const loadBaseData = async function () : Promise { try { const data = await Api.app.baseData() const result = data.parse() if (result != null) { appState.baseData = result setCacheData('base_data', data) console.log('基础数据加载成功') } else { appState.baseData = getDefaultBaseData() console.log('基础数据为空,使用默认基础数据') } } catch (error) { console.warn('加载基础数据失败,使用缓存或默认基础数据', error) const cachedData = getCachedBaseData('base_data') appState.baseData = cachedData != null ? cachedData : getDefaultBaseData() } } /** * 加载推荐数据 */ const loadRecommendData = async function () : Promise { if (isLoggedIn.value == false) { appState.recommendData = null console.log('当前未登录,跳过推荐数据加载') return } try { const data = await Api.recommend.index() const result = data.parse() if (result != null) { appState.recommendData = result setCacheData('recommend_data', data) console.log('推荐数据加载成功') } } catch (error) { console.warn('加载推荐数据失败,尝试使用缓存数据', error) const cachedData = getCachedRecommendData('recommend_data') if (cachedData != null) { appState.recommendData = cachedData console.log('使用缓存的推荐数据') } } } /** * 同步未读消息 */ const syncUnreadCounts = async function () : Promise { try { const data = await Api.message.unread() const result = data.parse() if (result != null) { appState.unread = result console.log('未读消息同步成功') } } catch (error) { console.warn('同步未读消息失败:', error) } } /** * 获取缓存数据 */ export const getCachedData = function (key : string) : UTSJSONObject | null { try { const cached = uni.getStorageSync(key) as string | null const cachedTime = uni.getStorageSync(`${key}_time`) as string | null if (cached == null || cachedTime == null) { return null } const cacheAge = Date.now() - parseInt(cachedTime) if (cacheAge < appState.cacheExpire) { const parsed = JSON.parse(cached) as UTSJSONObject return parsed } return null } catch (error) { return null } } export const getCachedSystemConfig = function (key : string) : ISystemConfig | null { const cached = getCachedData(key) if (cached == null) { return null } return cached.parse() } export const getCachedLaunchData = function (key : string) : ILaunchData | null { const cached = getCachedData(key) if (cached == null) { return null } return cached.parse() } export const getCachedBaseData = function (key : string) : IBaseData | null { const cached = getCachedData(key) if (cached == null) { return null } return cached.parse() } export const getCachedRecommendData = function (key : string) : IRecommendData | null { const cached = getCachedData(key) if (cached == null) { return null } return cached.parse() } /** * 缓存数据 */ export const setCacheData = function (key : string, data : any) : void { try { uni.setStorageSync(key, JSON.stringify(data)) uni.setStorageSync(`${key}_time`, Date.now().toString()) } catch (error) { console.error('缓存数据失败:', error) } } /** * 获取默认加载数据 */ export const getDefaultLaunchData = () : ILaunchData{ const launchData : ILaunchData = { splashAds: [], banners: [ { id: 1, image: 'https://example.com/banner1.jpg', title: '欢迎使用', link: '', type: 'page', order: 1 } ], // announcements: [], activities: [], quickActions: [ { id: 1, name: '匹配', icon: 'heart', color: '#FF6B6B', route: '/pages/match/match', visible: true }, { id: 2, name: '聊天', icon: 'message', color: '#007AFF', route: '/pages/chat/chat', visible: true }, { id: 3, name: '动态', icon: 'image', color: '#34C759', route: '/pages/moment/moment', visible: true }, { id: 4, name: '房间', icon: 'mic', color: '#5856D6', route: '/pages/room/room', visible: true } ], newbieGuide: { enabled: true, steps: [ { id: 1, title: '欢迎来到心遇', content: '遇见美好,遇见你', image: 'https://example.com/guide1.png' }, { id: 2, title: '智能匹配', content: '根据你的兴趣和喜好,智能推荐合适的伙伴', image: 'https://example.com/guide2.png' }, { id: 3, title: '实时聊天', content: '文字、语音、视频,多种方式畅聊无阻', image: 'https://example.com/guide3.png' } ] } } return launchData } /** * 获取默认系统配置 */ export const getAppDefaultConf = () : ISystemConfig { const defaultConf : ISystemConfig = { dailyMatchLimit: 50, dailyMessageLimit: 100, maxFriends: 500, maxMomentImages: 9, maxChatImageSize: 10 * 1024 * 1024, // 10MB maxVideoDuration: 300, // 5分钟 maxVoiceDuration: 60 // 1分钟 enableAd: false, splashAdId: '', bannerAdId: '', interstitialAdId: '', rewardAdId: '', adFrequency: 3 uploadUrl: 'https://upload.example.com', cdnUrl: 'https://cdn.example.com', socketUrl: 'wss://socket.example.com', apiVersion: 'v1' wechatAppId: '', qqAppId: '', appleServiceId: '', pushService: '', mapService: 'amap' minIosVersion: '11.0', minAndroidVersion: '5.0', supportedPlatforms: ['ios', 'android', 'web'] } return defaultConf } /** * 获取默认基础数据 */ export const getDefaultBaseData = () : IBaseData { const baseData : IBaseData = { cities: [ { id: 1, name: '北京', code: '110000', parentId: 0, level: 1, pinyin: 'beijing', hot: true }, { id: 2, name: '上海', code: '310000', parentId: 0, level: 1, pinyin: 'shanghai', hot: true }, { id: 3, name: '广州', code: '440100', parentId: 0, level: 1, pinyin: 'guangzhou', hot: true }, { id: 4, name: '深圳', code: '440300', parentId: 0, level: 1, pinyin: 'shenzhen', hot: true }, { id: 5, name: '成都', code: '510100', parentId: 0, level: 1, pinyin: 'chengdu', hot: true } ], tags: [ { id: 1, name: '旅行', type: 'hobby', hot: true, count: 1000 }, { id: 2, name: '美食', type: 'hobby', hot: true, count: 1500 }, { id: 3, name: '音乐', type: 'hobby', hot: false, count: 800 }, { id: 4, name: '运动', type: 'hobby', hot: true, count: 1200 }, { id: 5, name: '游戏', type: 'hobby', hot: true, count: 2000 } ], gifts: [ { id: 1, name: '玫瑰花', description: '代表爱意', image: '🌹', price: 10, coinType: 'coin', category: 'love', isHot: true, isNew: false, isVipOnly: false, isLimited: false, sortOrder: 1 }, { id: 2, name: '棒棒糖', description: '甜甜蜜蜜', image: '🍭', price: 20, coinType: 'coin', category: 'sweet', isHot: true, isNew: false, isVipOnly: false, isLimited: false, sortOrder: 2 }, { id: 3, name: '爱心', description: '表达心意', image: '❤️', price: 50, coinType: 'coin', category: 'love', isHot: true, isNew: true, isVipOnly: false, isLimited: false, sortOrder: 3 }, { id: 4, name: '钻戒', description: '永恒的爱', image: '💍', price: 999, coinType: 'diamond', category: 'luxury', isHot: false, isNew: false, isVipOnly: true, isLimited: false, sortOrder: 4 } ], levels: [ { level: 1, minExp: 0, maxExp: 100, name: '新手', icon: '🌟', color: '#999999', privileges: ['基础功能'] }, { level: 2, minExp: 100, maxExp: 300, name: '入门', icon: '🌟', color: '#666666', privileges: ['每日匹配+5'] }, { level: 3, minExp: 300, maxExp: 600, name: '活跃', icon: '🌟', color: '#FF9500', privileges: ['去广告', '高级筛选'] }, { level: 4, minExp: 600, maxExp: 1000, name: '资深', icon: '🌟', color: '#FF3B30', privileges: ['VIP标识', '优先展示'] }, { level: 5, minExp: 1000, maxExp: 2000, name: '大神', icon: '🌟', color: '#5856D6', privileges: ['专属客服', '特权标识'] } ], vipPackages: [ { id: 1, name: '月卡', duration: 30, durationUnit: 'day', price: 30, benefits: ['去广告', '每日匹配+20', '聊天背景+5'], isHot: true, isRecommend: true }, { id: 2, name: '季卡', duration: 90, durationUnit: 'day', price: 80, originalPrice: 90, benefits: ['月卡所有特权', '专属标识', '优先匹配'], isHot: false, isRecommend: true }, { id: 3, name: '年卡', duration: 365, durationUnit: 'day', price: 288, originalPrice: 360, benefits: ['季卡所有特权', '专属客服', '无限匹配'], isHot: true, isRecommend: false } ], rechargePackages: [ { id: 1, name: '小试牛刀', coinAmount: 60, diamondAmount: 6, price: 6, currency: 'CNY', discount: 0, isHot: false, isRecommend: false }, { id: 2, name: '日常所需', coinAmount: 300, diamondAmount: 30, price: 30, currency: 'CNY', discount: 0, isHot: true, isRecommend: true }, { id: 3, name: '土豪专享', coinAmount: 980, diamondAmount: 98, price: 98, currency: 'CNY', discount: 10, isHot: true, isRecommend: false }, { id: 4, name: '至尊VIP', coinAmount: 2980, diamondAmount: 298, price: 298, currency: 'CNY', discount: 20, isHot: false, isRecommend: true } ], verifications: [ { id: 1, name: '实名认证', description: '提高信任度', icon: '✅', price: 0, benefits: ['认证标识', '提高匹配率'] }, { id: 2, name: '学历认证', description: '展示教育背景', icon: '🎓', price: 9.9, benefits: ['学历标识', '优先展示'] }, { id: 3, name: '职业认证', description: '验证职业信息', icon: '💼', price: 9.9, benefits: ['职业标识', '增加可信度'] } ], chatBackgrounds: [ { id: 1, name: '默认背景', image: 'https://example.com/bg1.jpg', price: 0, isFree: true }, { id: 2, name: '星空', image: 'https://example.com/bg2.jpg', price: 10, isFree: false }, { id: 3, name: '海洋', image: 'https://example.com/bg3.jpg', price: 10, isFree: false }, { id: 4, name: '森林', image: 'https://example.com/bg4.jpg', price: 20, isFree: false } ], emojis: [ { id: 1, name: '微笑', emoji: '😊', category: '表情' }, { id: 2, name: '爱心', emoji: '❤️', category: '表情' }, { id: 3, name: '笑哭', emoji: '😂', category: '表情' }, { id: 4, name: '点赞', emoji: '👍', category: '手势' }, { id: 5, name: '加油', emoji: '💪', category: '手势' } ] } return baseData } export { appState } export default appState