/** * 应用订阅 store * 数据来源:websopy 特殊接口(db_websopy.app_subscription 表) * 接口域名:https://websopy-api.websoft.top/api * 后端:com.gxwebsoft.app.controller.AppSubscriptionController */ import { defineStore } from 'pinia'; import { pageMySubscriptions, getSubscriptionDetail, getSubscriptionDetailByNo, checkSubscriptionStatus, checkPurchased, getBalance, subscribe, generatePayQrcode, paySubscription, mpPrepay, mpConfirm, renewSubscription, cancelSubscription, toggleEnable } from '@/api/app/appSubscription'; import type { AppSubscription, AppSubscriptionQueryParam, SubscribeParam, SubscribeResult, GeneratePayQrcodeParam, GeneratePayQrcodeResult, CheckStatusResult, PayResult, WechatNativePayResult, MpPrepayResult } from '@/api/app/appSubscription/model'; import type { PageResult } from '@/api'; export interface AppSubscriptionState { // 我的订阅列表 subscriptionList: AppSubscription[]; // 总数量 total: number; // 当前查看的订阅详情 currentSubscription: AppSubscription | null; // 用户余额 balance: number; // 加载状态 loading: boolean; // 最后更新时间 lastUpdateTime: number | null; // 缓存有效期(毫秒) cacheExpiry: number; } export const useAppSubscriptionStore = defineStore('appSubscription', { state: (): AppSubscriptionState => ({ subscriptionList: [], total: 0, currentSubscription: null, balance: 0, loading: false, lastUpdateTime: null, // 默认缓存5分钟(订阅涉及支付状态,不宜过长) cacheExpiry: 5 * 60 * 1000 }), getters: { /** * 已激活订阅 */ activeSubscriptions: (state): AppSubscription[] => { return state.subscriptionList.filter((s) => s.status === 'active'); }, /** * 待支付订阅 */ pendingSubscriptions: (state): AppSubscription[] => { return state.subscriptionList.filter((s) => s.status === 'pending'); }, /** * 已过期订阅 */ expiredSubscriptions: (state): AppSubscription[] => { return state.subscriptionList.filter((s) => s.status === 'expired'); }, /** * 检查缓存是否有效 */ isCacheValid: (state): boolean => { if (!state.lastUpdateTime) return false; const now = Date.now(); return now - state.lastUpdateTime < state.cacheExpiry; } }, actions: { // ============================================================ // 查询类 // ============================================================ /** * 获取我的订阅列表(分页,带缓存) * @param params 查询参数(page/limit/status) * @param forceRefresh 是否强制刷新(切换 status 过滤时建议传 true) */ async fetchMySubscriptions( params: AppSubscriptionQueryParam = { page: 1, limit: 10 }, forceRefresh = false ): Promise> { // 缓存有效且不强制刷新,直接返回缓存列表 if (!forceRefresh && this.isCacheValid && this.subscriptionList.length > 0) { return { list: this.subscriptionList, count: this.total }; } this.loading = true; try { const data = await pageMySubscriptions(params); this.subscriptionList = data.list || []; this.total = data.count || 0; this.lastUpdateTime = Date.now(); return data; } catch (error) { console.error('获取我的订阅列表失败:', error); throw error; } finally { this.loading = false; } }, /** * 获取订阅详情(按ID) */ async fetchDetail(id: number): Promise { try { const data = await getSubscriptionDetail(id); this.currentSubscription = data; return data; } catch (error) { console.error('获取订阅详情失败:', error); throw error; } }, /** * 根据订阅编号查询详情(小程序入口用) */ async fetchDetailByNo(subscriptionNo: string): Promise { try { const data = await getSubscriptionDetailByNo(subscriptionNo); this.currentSubscription = data; return data; } catch (error) { console.error('根据订阅编号查询详情失败:', error); throw error; } }, /** * 查询支付状态(前端轮询用,强制实时请求,不走缓存) */ async checkStatus(subscriptionNo: string): Promise { return await checkSubscriptionStatus(subscriptionNo); }, /** * 检查是否已购买某应用(强制实时请求,不走缓存) */ async checkPurchased(productId: number): Promise { return await checkPurchased(productId); }, /** * 获取当前用户余额 */ async fetchBalance(): Promise { try { const data = await getBalance(); this.balance = data.balance; return data.balance; } catch (error) { console.error('获取用户余额失败:', error); throw error; } }, // ============================================================ // 订阅与支付操作 // ============================================================ /** * 创建订阅 * 免费应用直接激活,付费应用创建待支付记录 */ async subscribe(data: SubscribeParam): Promise { try { const result = await subscribe(data); // 订阅状态变化,失效缓存 this.invalidateCache(); return result; } catch (error) { console.error('创建订阅失败:', error); throw error; } }, /** * 生成支付小程序码(同时创建订阅记录) */ async generatePayQrcode( data: GeneratePayQrcodeParam ): Promise { try { const result = await generatePayQrcode(data); // 已创建订阅记录,失效缓存 this.invalidateCache(); return result; } catch (error) { console.error('生成支付小程序码失败:', error); throw error; } }, /** * 发起支付 * @param id 订阅ID * @param method 支付方式:balance-余额支付 / wechat-微信支付 * @param envVersion 小程序版本(微信支付时使用):develop/trial/release */ async pay( id: number, method: 'balance' | 'wechat' = 'wechat', envVersion?: string ): Promise { try { const result = await paySubscription(id, method, envVersion); // 支付成功后余额/订阅状态变化,失效缓存并刷新余额 this.invalidateCache(); if (method === 'balance') { const payResult = result as PayResult; if (typeof payResult.balance === 'number') { this.balance = payResult.balance; } } return result; } catch (error) { console.error('发起支付失败:', error); throw error; } }, /** * 小程序 JSAPI 预支付下单 */ async mpPrepay(id: number, openid: string): Promise { try { return await mpPrepay(id, { openid }); } catch (error) { console.error('小程序预支付失败:', error); throw error; } }, /** * 小程序支付成功确认 */ async mpConfirm( subscriptionNo: string, transactionId?: string ): Promise { try { const result = await mpConfirm(subscriptionNo, { transactionId }); // 支付确认后订阅状态变化,失效缓存 this.invalidateCache(); return result; } catch (error) { console.error('小程序支付确认失败:', error); throw error; } }, // ============================================================ // 订阅管理 // ============================================================ /** * 续费:基于已有订阅创建续费订单并生成支付码(一步完成,对齐后端 /renew-pay) * @param id 订阅ID * @param period 周期:month/year * @param method 支付方式:balance/wechat * @param envVersion 小程序版本(微信支付时使用) */ async renew( id: number, period: 'month' | 'year' = 'month', method: 'balance' | 'wechat' = 'wechat', envVersion?: string ): Promise { try { const result = await renewSubscription(id, period, method, envVersion); this.invalidateCache(); return result; } catch (error) { console.error('续费失败:', error); throw error; } }, /** * 退订/取消 */ async cancel(id: number): Promise { try { const msg = await cancelSubscription(id); this.invalidateCache(); return msg; } catch (error) { console.error('退订失败:', error); throw error; } }, /** * 启用/禁用 */ async toggleEnable(id: number, enabled: boolean): Promise { try { const msg = await toggleEnable(id, enabled); this.invalidateCache(); return msg; } catch (error) { console.error('启用/禁用失败:', error); throw error; } }, // ============================================================ // 缓存控制 // ============================================================ /** * 失效缓存(仅重置时间标记,保留已有数据,下次拉取时更新) * 用于订阅/支付/管理操作后,确保下次查询获取最新数据 */ invalidateCache() { this.lastUpdateTime = null; }, /** * 清除缓存(清空数据并重置时间标记) */ clearCache() { this.subscriptionList = []; this.total = 0; this.currentSubscription = null; this.lastUpdateTime = null; }, /** * 强制刷新订阅列表 */ async refresh() { return await this.fetchMySubscriptions({ page: 1, limit: 10 }, true); }, /** * 设置缓存有效期 */ setCacheExpiry(expiry: number) { this.cacheExpiry = expiry; } } });