小程序虚拟支付

This commit is contained in:
李琦
2026-09-17 17:38:45 +08:00
parent 7c106b69d2
commit 7ea8cdd982
32 changed files with 3499 additions and 88 deletions

107
api/user/v1/member.go Normal file
View File

@@ -0,0 +1,107 @@
package v1
import "github.com/gogf/gf/v2/frame/g"
// ============================================================================
// 会员购买(微信小程序虚拟支付 · 道具直购)
// ============================================================================
// MemberPlanOut 可购买的会员套餐
type MemberPlanOut struct {
PlanKey string `json:"plan_key"`
Name string `json:"name"`
Subtitle string `json:"subtitle"`
LevelKey string `json:"level_key"`
DurationDays int `json:"duration_days"`
PriceCents int64 `json:"price_cents"` // 单位:分
ProductId string `json:"product_id"`
Badge string `json:"badge"`
}
// MemberLevelOut 等级权益(用于前端渲染权益对比)
type MemberLevelOut struct {
LevelKey string `json:"level_key"`
Name string `json:"name"`
Modules []string `json:"modules"`
ModuleNames []string `json:"module_names"`
IsCurrent bool `json:"is_current"`
}
// MemberStateOut 我的会员状态
type MemberStateOut struct {
IsMember bool `json:"is_member"`
LevelKey string `json:"level_key"`
LevelName string `json:"level_name"`
ExpireAt string `json:"expire_at"` // 空串表示永久或未开通
DaysLeft int `json:"days_left"`
Modules []string `json:"modules"`
}
// MemberCenterReq 会员中心
type MemberCenterReq struct {
g.Meta `path:"/member/center" method:"get" tags:"member" summary:"会员中心(套餐 + 会员状态 + 权益)"`
}
type MemberCenterRes struct {
Plans []MemberPlanOut `json:"plans"`
Levels []MemberLevelOut `json:"levels"`
State MemberStateOut `json:"state"`
Notices []string `json:"notices"`
XpayReady bool `json:"xpay_ready"` // 服务端虚拟支付参数是否已配置
Quotas []QuotaToolOut `json:"quotas"` // 各工具额度(会员权益页据此展示提升幅度)
Packs []QuotaPackOut `json:"packs"` // 次数包通用档位
PeriodDays int `json:"period_days"` // 当前生效的额度重置周期
}
// MemberOrderCreateReq 创建会员订单
//
// Code 为 wx.login 获取的临时登录凭证 —— 服务端用它换 session_key,
// session_key 是「用户态签名 signature」的密钥;同时校验支付人与登录人一致。
type MemberOrderCreateReq struct {
g.Meta `path:"/member/order" method:"post" tags:"member" summary:"创建会员订单(返回支付参数)"`
PlanKey string `v:"required#请选择会员套餐" json:"plan_key"`
Code string `json:"code"`
}
type MemberOrderCreateRes struct {
OutTradeNo string `json:"out_trade_no"`
Mode string `json:"mode"` // 固定 short_series_goods
SignData string `json:"signData"` // JSON 字符串,必须原样传给 wx.requestVirtualPayment
PaySig string `json:"paySig"`
Signature string `json:"signature"`
Env int `json:"env"`
}
// MemberOrderCheckReq 查询订单状态(前端支付成功回调后轮询;同时承担兜底发货)
type MemberOrderCheckReq struct {
g.Meta `path:"/member/order/check" method:"post" tags:"member" summary:"查询会员订单状态"`
OutTradeNo string `v:"required#订单号不能为空" json:"out_trade_no"`
}
type MemberOrderCheckRes struct {
Status int `json:"status"`
Delivered bool `json:"delivered"`
State MemberStateOut `json:"state"`
}
// MemberOrdersReq 我的会员订单
type MemberOrdersReq struct {
g.Meta `path:"/member/orders" method:"get" tags:"member" summary:"我的会员订单"`
Limit int `json:"limit"`
}
type MemberOrderOut struct {
OutTradeNo string `json:"out_trade_no"`
OrderType int `json:"order_type"` // 1=会员套餐 2=次数包
PlanKey string `json:"plan_key"`
PlanName string `json:"plan_name"`
Title string `json:"title"` // 统一展示标题(套餐名 / 次数包名)
ToolKey string `json:"tool_key"`
ToolName string `json:"tool_name"`
Times int `json:"times"`
PriceCents int64 `json:"price_cents"`
Status int `json:"status"`
StatusText string `json:"status_text"`
PayChannel string `json:"pay_channel"`
CreatedAt string `json:"created_at"`
DeliveredAt string `json:"delivered_at"`
}
type MemberOrdersRes struct {
List []MemberOrderOut `json:"list"`
}

108
api/user/v1/quota.go Normal file
View File

@@ -0,0 +1,108 @@
package v1
import "github.com/gogf/gf/v2/frame/g"
// ============================================================================
// 工具额度与次数包
//
// 额度三池:免费 / 会员 / 付费(次数包),扣减顺序 免费 → 会员 → 付费。
// 周期为滚动窗口,默认 7 天,后台可给「全局 / 会员套餐 / 单个用户」分别调整。
// ============================================================================
// QuotaToolOut 单个工具的额度状态
type QuotaToolOut struct {
ToolKey string `json:"tool_key"`
Name string `json:"name"`
Icon string `json:"icon"`
FreeTotal int `json:"free_total"`
FreeUsed int `json:"free_used"`
FreeLeft int `json:"free_left"`
MemberTotal int `json:"member_total"`
MemberUsed int `json:"member_used"`
MemberLeft int `json:"member_left"`
PaidLeft int `json:"paid_left"` // 付费额度余额(次数)
PaidExpireAt string `json:"paid_expire_at"` // 付费额度到期日 yyyy-MM-dd
PayCost int `json:"pay_cost"` // 每次使用消耗的付费额度系数
IsMember bool `json:"is_member"`
PeriodDays int `json:"period_days"`
PeriodEnd string `json:"period_end"` // 当前周期结束时间
// Source 下一次扣减会命中的池:free / member / paid / none
Source string `json:"source"`
CanUse bool `json:"can_use"`
TotalLeft int `json:"total_left"` // 本周期内还能用几次(付费额度按系数折算)
Message string `json:"message"` // 额度用尽时的可读原因
}
// QuotaPackOut 次数包档位
type QuotaPackOut struct {
PackKey string `json:"pack_key"`
Name string `json:"name"`
Times int `json:"times"`
PriceCents int64 `json:"price_cents"`
ValidDays int `json:"valid_days"`
Badge string `json:"badge"`
ToolKey string `json:"tool_key"` // 空 = 通用档位(购买时选择工具)
UnitPriceCents int64 `json:"unit_price_cents"` // 每 100 次的均价(分),服务端算好避免前端浮点误差
}
// QuotaMyReq 我的额度总览
type QuotaMyReq struct {
g.Meta `path:"/quota/my" method:"get" tags:"quota" summary:"我的工具额度总览"`
}
type QuotaMyRes struct {
PeriodDays int `json:"period_days"`
IsMember bool `json:"is_member"`
LevelKey string `json:"level_key"`
LevelName string `json:"level_name"`
LevelExpireAt string `json:"level_expire_at"`
Tools []QuotaToolOut `json:"tools"`
TotalLeft int `json:"total_left"`
Packs []QuotaPackOut `json:"packs"`
}
// QuotaToolReq 单工具额度(进入工具页时查询,用于额度条与拦截提示)
type QuotaToolReq struct {
g.Meta `path:"/quota/tool" method:"get" tags:"quota" summary:"单个工具的额度状态"`
ToolKey string `v:"required#工具标识不能为空" json:"tool_key"`
}
type QuotaToolRes struct {
Tool *QuotaToolOut `json:"tool"`
}
// QuotaConsumeReq 扣减一次额度(在「产出结果」时调用,而不是打开页面时)
type QuotaConsumeReq struct {
g.Meta `path:"/quota/consume" method:"post" tags:"quota" summary:"扣减工具额度"`
ToolKey string `v:"required#工具标识不能为空" json:"tool_key"`
}
type QuotaConsumeRes struct {
Tool *QuotaToolOut `json:"tool"`
}
// QuotaPacksReq 某工具可购买的次数包档位
type QuotaPacksReq struct {
g.Meta `path:"/quota/packs" method:"get" tags:"quota" summary:"次数包档位(按工具)"`
ToolKey string `json:"tool_key"`
}
type QuotaPacksRes struct {
List []QuotaPackOut `json:"list"`
}
// QuotaOrderCreateReq 创建次数包订单(支付参数与会员套餐完全同构)
type QuotaOrderCreateReq struct {
g.Meta `path:"/quota/order" method:"post" tags:"quota" summary:"创建次数包订单(返回支付参数)"`
PackKey string `v:"required#请选择次数包" json:"pack_key"`
ToolKey string `v:"required#请选择要购买的次数包工具" json:"tool_key"`
Code string `json:"code"`
}
type QuotaOrderCreateRes struct {
OutTradeNo string `json:"out_trade_no"`
Mode string `json:"mode"`
SignData string `json:"signData"`
PaySig string `json:"paySig"`
Signature string `json:"signature"`
Env int `json:"env"`
PackKey string `json:"pack_key"`
ToolKey string `json:"tool_key"`
Times int `json:"times"`
ValidDays int `json:"valid_days"`
}

View File

@@ -100,13 +100,14 @@ type ModuleOut struct {
}
type ToolOut struct {
ToolKey string `json:"tool_key"`
ModuleKey string `json:"module_key"`
Name string `json:"name"`
Icon string `json:"icon"`
Description string `json:"description"`
IsHot bool `json:"is_hot"`
Locked bool `json:"locked"`
ToolKey string `json:"tool_key"`
ModuleKey string `json:"module_key"`
Name string `json:"name"`
Icon string `json:"icon"`
Description string `json:"description"`
IsHot bool `json:"is_hot"`
Locked bool `json:"locked"`
Quota *QuotaToolOut `json:"quota"` // 额度状态(免费/会员/付费),未登录或查询失败时为 null
}
type ToolsListReq struct {