feat(appSubscription): 实现Dashboard订阅到期显示及扫码支付功能
- dashboard订阅到期时间信息支持三态渲染:激活显示剩余天数和已激活标签、待支付显示金额及去支付按钮、无订阅显示立即订阅按钮 - 通过租户ID查询应用产品,实现按租户过滤的订阅展示逻辑 - 新增appProduct分页接口及类型定义,提供应用列表获取能力 - 实现「立即订阅」流程,支持免费应用直接激活,付费应用生成微信扫码支付二维码及轮询订单状态 - 实现待支付订阅复用支付接口生成支付二维码,避免重复创建订阅 - 小程序端扫码支付流程支持订单号查询及支付确认,后端使用Redis标记支付成功状态 - 修复后端generatePayQrcode接口缺少priceType字段导致的数据库报错,前端兼容现有逻辑无需修改 - 移除dashboard中siteInfo旧的expirationTime字段相关代码,改为读订阅expireTime - 新增订阅及支付相关样式,优化界面体验 - 支付状态轮询实现超时提示及自动停止机制,提升用户支付体验 - 组件卸载时确保支付轮询停止,避免内存泄漏 - 独立加载订阅信息,不影响其他数据请求,避免页面加载失败影响订阅展示
This commit is contained in:
43
src/api/app/appProduct/index.ts
Normal file
43
src/api/app/appProduct/index.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import request from '@/utils/request';
|
||||
import type { ApiResult, PageResult } from '@/api';
|
||||
import type { AppProduct, AppProductQueryParam } from './model';
|
||||
|
||||
/**
|
||||
* websopy 特殊接口域名
|
||||
* 后端 Controller: com.gxwebsoft.app.controller.AppProductController
|
||||
* @RequestMapping("/api/app/product"),后端无 context-path
|
||||
* 完整 URL = https://websopy-api.websoft.top/api/app/product/xxx
|
||||
*/
|
||||
const WEBSOPY_API_BASE = 'https://websopy-api.websoft.top/api';
|
||||
const BASE = `${WEBSOPY_API_BASE}/app/product`;
|
||||
|
||||
/**
|
||||
* 分页查询应用列表
|
||||
* GET /app/product/page
|
||||
* 支持按 tenantId 过滤(管理后台按租户查询应用)
|
||||
* 注意:分页参数为 current/size(非 page/limit)
|
||||
*/
|
||||
export async function pageProducts(
|
||||
params: AppProductQueryParam
|
||||
): Promise<PageResult<AppProduct>> {
|
||||
const res = await request.get<ApiResult<PageResult<AppProduct>>>(
|
||||
`${BASE}/page`,
|
||||
{ params }
|
||||
);
|
||||
if (res.data.code === 0) {
|
||||
return res.data.data || { list: [], count: 0 };
|
||||
}
|
||||
return Promise.reject(new Error(res.data.message));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用详情
|
||||
* GET /app/product/detail/{id}
|
||||
*/
|
||||
export async function getProductDetail(id: number): Promise<AppProduct> {
|
||||
const res = await request.get<ApiResult<AppProduct>>(`${BASE}/detail/${id}`);
|
||||
if (res.data.code === 0) {
|
||||
return res.data.data as AppProduct;
|
||||
}
|
||||
return Promise.reject(new Error(res.data.message));
|
||||
}
|
||||
143
src/api/app/appProduct/model.ts
Normal file
143
src/api/app/appProduct/model.ts
Normal file
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* 应用产品实体(对应表 app_product)
|
||||
* 字段对照后端 com.gxwebsoft.app.entity.AppProduct
|
||||
*/
|
||||
export interface AppProduct {
|
||||
// 应用ID(主键)
|
||||
productId?: number;
|
||||
// 应用名称
|
||||
productName?: string;
|
||||
// 应用标识(唯一)
|
||||
productCode?: string;
|
||||
// 应用密钥
|
||||
productSecret?: string;
|
||||
// 应用类型: 10网站 20微信小程序 30抖音小程序 40百度小程序 50支付宝小程序 60Android 70iOS 80macOS 90Windows 100插件
|
||||
appType?: number;
|
||||
// 应用类型名称(关联查询)
|
||||
appTypeName?: string;
|
||||
// 分类ID
|
||||
categoryId?: number;
|
||||
// 行业类型(父级)
|
||||
industryParent?: string;
|
||||
// 行业类型(子级)
|
||||
industryChild?: string;
|
||||
// 应用Logo
|
||||
logo?: string;
|
||||
// 应用图标
|
||||
icon?: string;
|
||||
// 二维码
|
||||
qrcode?: string;
|
||||
// 应用截图(JSON数组)
|
||||
screenshots?: string;
|
||||
// 应用简介
|
||||
description?: string;
|
||||
// 详细说明
|
||||
content?: string;
|
||||
// 关键词
|
||||
keywords?: string;
|
||||
// 域名
|
||||
domain?: string;
|
||||
// 域名前缀
|
||||
prefix?: string;
|
||||
// 包名/AppID
|
||||
packageName?: string;
|
||||
// 后台地址
|
||||
adminUrl?: string;
|
||||
// API地址
|
||||
apiUrl?: string;
|
||||
// 下载地址
|
||||
downloadUrl?: string;
|
||||
// 版本号
|
||||
version?: string;
|
||||
// 版本: standard标准版 professional专业版 perpetual永久授权
|
||||
edition?: string;
|
||||
// 最低版本要求
|
||||
minVersion?: string;
|
||||
// 定价: free免费 one_time一次性 subscription订阅
|
||||
priceType?: string;
|
||||
// 价格(元)
|
||||
price?: number;
|
||||
// 划线价格
|
||||
linePrice?: number;
|
||||
// 续费价格
|
||||
renewPrice?: number;
|
||||
// 交付方式: 1源码 2托管 3授权
|
||||
deliveryMethod?: number;
|
||||
// 计费方式: 1按年 2按月 3一次性
|
||||
chargingMethod?: number;
|
||||
// 订阅周期: month/year
|
||||
subscriptionPeriod?: string;
|
||||
// 发布状态: developing pending_review published rejected deprecated
|
||||
publishStatus?: string;
|
||||
// 发布时间
|
||||
publishTime?: string;
|
||||
// 审核时间
|
||||
reviewTime?: string;
|
||||
// 审核人ID
|
||||
reviewerId?: number;
|
||||
// 拒绝原因
|
||||
rejectReason?: string;
|
||||
// 浏览次数
|
||||
clicks?: number;
|
||||
// 安装次数
|
||||
installs?: number;
|
||||
// 下载次数
|
||||
downloads?: number;
|
||||
// 评分(1-5)
|
||||
rating?: number;
|
||||
// 点赞数
|
||||
likes?: number;
|
||||
// 开发者
|
||||
developer?: string;
|
||||
// 开发者电话
|
||||
developerPhone?: string;
|
||||
// 开发者邮箱
|
||||
developerEmail?: string;
|
||||
// 是否推荐: 0否 1是
|
||||
recommend?: number;
|
||||
// 是否官方: 0否 1是
|
||||
official?: number;
|
||||
// 是否上架市场: 0否 1是
|
||||
market?: number;
|
||||
// 是否显示首页: 0否 1是
|
||||
showIndex?: number;
|
||||
// 是否可搜索: 0否 1是
|
||||
searchEnabled?: number;
|
||||
// 模板ID
|
||||
templateId?: number;
|
||||
// 租户ID
|
||||
tenantId?: number;
|
||||
// 创建时间
|
||||
createTime?: string;
|
||||
// 更新时间
|
||||
updateTime?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用产品分页查询参数
|
||||
* 注意:后端 AppProductController.page 的分页参数为 current/size(非 page/limit)
|
||||
*/
|
||||
export interface AppProductQueryParam {
|
||||
// 页码
|
||||
current?: number;
|
||||
// 每页条数
|
||||
size?: number;
|
||||
// 应用名称
|
||||
productName?: string;
|
||||
// 应用标识
|
||||
productCode?: string;
|
||||
// 应用类型
|
||||
appType?: number;
|
||||
// 分类ID
|
||||
categoryId?: number;
|
||||
// 发布状态
|
||||
publishStatus?: string;
|
||||
// 状态
|
||||
status?: number;
|
||||
// 用户ID
|
||||
userId?: number;
|
||||
// 租户ID(按租户查询应用)
|
||||
tenantId?: number;
|
||||
// 关键词搜索(同时搜索应用名称和应用标识)
|
||||
keywords?: string;
|
||||
}
|
||||
Reference in New Issue
Block a user