diff --git a/app/main/api/desc/admin/admin_agent.api b/app/main/api/desc/admin/admin_agent.api index 15f9bef..380c381 100644 --- a/app/main/api/desc/admin/admin_agent.api +++ b/app/main/api/desc/admin/admin_agent.api @@ -83,9 +83,9 @@ service main { @handler AdminGetInviteCodeList get /invite_code/list (AdminGetInviteCodeListReq) returns (AdminGetInviteCodeListResp) - // 平台升级代理等级(免费升级,遵守代理系统逻辑规则) + // 平台升级代理等级 @handler AdminUpgradeAgent - post /upgrade (AdminUpgradeAgentReq) returns (AdminUpgradeAgentResp) + post /upgrade/agent (AdminUpgradeAgentReq) returns (AdminUpgradeAgentResp) } type ( @@ -128,14 +128,6 @@ type ( AdminAuditAgentResp { Success bool `json:"success"` } - // 平台升级代理等级 - AdminUpgradeAgentReq { - AgentId string `json:"agent_id"` // 代理ID - ToLevel int64 `json:"to_level"` // 目标等级:2=黄金,3=钻石 - } - AdminUpgradeAgentResp { - Success bool `json:"success"` - } // 推广链接分页查询 AdminGetAgentLinkListReq { Page int64 `form:"page"` // 页码 @@ -165,6 +157,7 @@ type ( AgentId *string `form:"agent_id,optional"` // 代理ID(可选) OrderId *string `form:"order_id,optional"` // 订单ID(可选) ProcessStatus *int64 `form:"process_status,optional"` // 处理状态(可选) + OrderStatus *string `form:"order_status,optional"` // 订单状态(可选):pending-待支付,paid-已支付,refunded-已退款,closed-已关闭,failed-支付失败 } AgentOrderListItem { Id string `json:"id"` // 主键 @@ -177,7 +170,8 @@ type ( ActualBasePrice float64 `json:"actual_base_price"` // 实际底价 PriceCost float64 `json:"price_cost"` // 提价成本 AgentProfit float64 `json:"agent_profit"` // 代理收益 - ProcessStatus int64 `json:"process_status"` // 处理状态 + ProcessStatus int64 `json:"process_status"` // 处理状态(保留用于筛选,前端不显示) + OrderStatus string `json:"order_status"` // 订单状态:pending-待支付,paid-已支付,refunded-已退款,closed-已关闭,failed-支付失败 CreateTime string `json:"create_time"` // 创建时间 } AdminGetAgentOrderListResp { @@ -212,6 +206,7 @@ type ( AgentId *string `form:"agent_id,optional"` // 代理ID(可选) SourceAgentId *string `form:"source_agent_id,optional"` // 来源代理ID(可选) RebateType *int64 `form:"rebate_type,optional"` // 返佣类型(可选) + Status *int64 `form:"status,optional"` // 状态(可选):1=已发放,2=已冻结,3=已取消(已退款) } AgentRebateListItem { Id string `json:"id"` // 主键 @@ -220,6 +215,7 @@ type ( OrderId string `json:"order_id"` // 订单ID RebateType int64 `json:"rebate_type"` // 返佣类型 Amount float64 `json:"amount"` // 金额 + Status int64 `json:"status"` // 状态:1=已发放,2=已冻结,3=已取消(已退款) CreateTime string `json:"create_time"` // 创建时间 } AdminGetAgentRebateListResp { @@ -258,17 +254,20 @@ type ( WithdrawNo *string `form:"withdraw_no,optional"` // 提现单号(可选) } AgentWithdrawalListItem { - Id string `json:"id"` // 主键 - AgentId string `json:"agent_id"` // 代理ID - WithdrawNo string `json:"withdraw_no"` // 提现单号 - Amount float64 `json:"amount"` // 金额 - TaxAmount float64 `json:"tax_amount"` // 税费金额 - ActualAmount float64 `json:"actual_amount"` // 实际到账金额 - Status int64 `json:"status"` // 状态 - PayeeAccount string `json:"payee_account"` // 收款账户 - PayeeName string `json:"payee_name"` // 收款人姓名 - Remark string `json:"remark"` // 备注 - CreateTime string `json:"create_time"` // 创建时间 + Id string `json:"id"` // 主键 + AgentId string `json:"agent_id"` // 代理ID + WithdrawNo string `json:"withdraw_no"` // 提现单号 + Amount float64 `json:"amount"` // 金额 + TaxAmount float64 `json:"tax_amount"` // 税费金额 + ActualAmount float64 `json:"actual_amount"` // 实际到账金额 + Status int64 `json:"status"` // 状态 + WithdrawalType int64 `json:"withdrawal_type"` // 提现方式:1=支付宝,2=银行卡 + PayeeAccount string `json:"payee_account"` // 收款账户(支付宝账号或银行卡号) + PayeeName string `json:"payee_name"` // 收款人姓名 + BankCardNo string `json:"bank_card_no"` // 银行卡号(银行卡提现时使用) + BankName string `json:"bank_name"` // 开户行名称(银行卡提现时使用) + Remark string `json:"remark"` // 备注 + CreateTime string `json:"create_time"` // 创建时间 } AdminGetAgentWithdrawalListResp { Total int64 `json:"total"` // 总数 @@ -434,5 +433,13 @@ type ( Total int64 `json:"total"` // 总数 Items []InviteCodeListItem `json:"items"` // 列表数据 } + // 平台升级代理等级 + AdminUpgradeAgentReq { + AgentId string `json:"agent_id"` // 代理ID + ToLevel int64 `json:"to_level"` // 目标等级:2=黄金,3=钻石 + } + AdminUpgradeAgentResp { + Success bool `json:"success"` // 是否成功 + } ) diff --git a/app/main/api/desc/front/agent.api b/app/main/api/desc/front/agent.api index 3c7b068..87585cb 100644 --- a/app/main/api/desc/front/agent.api +++ b/app/main/api/desc/front/agent.api @@ -1,5 +1,7 @@ syntax = "v1" +import "product.api" + info ( title: "代理服务" desc: "新代理系统接口" @@ -224,6 +226,10 @@ service main { @handler ApplyWithdrawal post /withdrawal/apply (ApplyWithdrawalReq) returns (ApplyWithdrawalResp) + // 获取上次提现信息(用于前端预填) + @handler GetLastWithdrawalInfo + get /withdrawal/last_info (GetLastWithdrawalInfoReq) returns (GetLastWithdrawalInfoResp) + // 实名认证 @handler RealNameAuth post /real_name (RealNameAuthReq) returns (RealNameAuthResp) @@ -251,6 +257,32 @@ service main { // 获取推广查询报告列表 @handler GetPromotionQueryList get /promotion/query/list (GetPromotionQueryListReq) returns (GetPromotionQueryListResp) + + // ============================================ + // 用户模块白名单相关接口 + // ============================================ + @handler GetWhitelistFeatures + get /whitelist/features (GetWhitelistFeaturesReq) returns (GetWhitelistFeaturesResp) + + // 创建白名单订单 + @handler CreateWhitelistOrder + post /whitelist/order/create (CreateWhitelistOrderReq) returns (CreateWhitelistOrderResp) + + // 获取用户白名单列表 + @handler GetWhitelistList + get /whitelist/list (GetWhitelistListReq) returns (GetWhitelistListResp) + + // 检查模块是否已下架(用于显示下架按钮状态) + @handler CheckFeatureWhitelistStatus + get /whitelist/check (CheckFeatureWhitelistStatusReq) returns (CheckFeatureWhitelistStatusResp) + + // 下架单个模块(创建订单并支付) + @handler OfflineFeature + post /whitelist/offline (OfflineFeatureReq) returns (OfflineFeatureResp) + + // 检查订单是否属于当前代理推广 + @handler CheckOrderAgent + get /order/agent (CheckOrderAgentReq) returns (CheckOrderAgentResp) } type ( @@ -413,28 +445,30 @@ type ( LevelName string `json:"level_name"` // 等级名称 Mobile string `json:"mobile"` // 手机号 CreateTime string `json:"create_time"` // 加入团队时间 - TotalRebateAmount float64 `json:"total_rebate_amount"` // 返佣给我的总金额 - TodayRebateAmount float64 `json:"today_rebate_amount"` // 返佣给我的今日金额 - TodayInvites int64 `json:"today_invites"` // 邀请加入团队的今日人数 - MonthInvites int64 `json:"month_invites"` // 邀请加入团队的本月人数 - TotalInvites int64 `json:"total_invites"` // 邀请加入团队的总人数 TodayQueries int64 `json:"today_queries"` // 当日查询量 MonthQueries int64 `json:"month_queries"` // 本月查询量 TotalQueries int64 `json:"total_queries"` // 总查询量 + TotalRebateAmount float64 `json:"total_rebate_amount"` // 返佣给我的总金额 + TodayRebateAmount float64 `json:"today_rebate_amount"` // 返佣给我的今日金额 + TotalInvites int64 `json:"total_invites"` // 邀请加入团队的总人数 + TodayInvites int64 `json:"today_invites"` // 邀请加入团队的今日人数 + MonthInvites int64 `json:"month_invites"` // 邀请加入团队的本月人数 IsDirect bool `json:"is_direct"` // 是否直接下级 } // 收益信息 GetRevenueInfoResp { - Balance float64 `json:"balance"` // 可用余额 - FrozenBalance float64 `json:"frozen_balance"` // 冻结余额 - TotalEarnings float64 `json:"total_earnings"` // 累计收益(钱包总收益) - WithdrawnAmount float64 `json:"withdrawn_amount"` // 累计提现 - CommissionTotal float64 `json:"commission_total"` // 佣金累计总收益(推广订单获得的佣金) - CommissionToday float64 `json:"commission_today"` // 佣金今日收益 - CommissionMonth float64 `json:"commission_month"` // 佣金本月收益 - RebateTotal float64 `json:"rebate_total"` // 返佣累计总收益(包括推广返佣和升级返佣) - RebateToday float64 `json:"rebate_today"` // 返佣今日收益 - RebateMonth float64 `json:"rebate_month"` // 返佣本月收益 + Balance float64 `json:"balance"` // 可用余额 + FrozenBalance float64 `json:"frozen_balance"` // 冻结余额 + TotalEarnings float64 `json:"total_earnings"` // 累计收益(钱包总收益) + WithdrawnAmount float64 `json:"withdrawn_amount"` // 累计提现 + CommissionTotal float64 `json:"commission_total"` // 佣金累计总收益(推广订单获得的佣金) + CommissionToday float64 `json:"commission_today"` // 佣金今日收益 + CommissionMonth float64 `json:"commission_month"` // 佣金本月收益 + RebateTotal float64 `json:"rebate_total"` // 返佣累计总收益(包括推广返佣和升级返佣) + RebateToday float64 `json:"rebate_today"` // 返佣今日收益 + RebateMonth float64 `json:"rebate_month"` // 返佣本月收益 + AlipayMonthQuota float64 `json:"alipay_month_quota"` // 支付宝每月提现总额度 + AlipayMonthUsed float64 `json:"alipay_month_used"` // 本月已使用的支付宝提现额度 } // 佣金记录 GetCommissionListReq { @@ -473,6 +507,7 @@ type ( OrderNo string `json:"order_no"` // 订单号 RebateType int64 `json:"rebate_type"` // 返佣类型:1=直接上级,2=钻石上级,3=黄金上级 Amount float64 `json:"amount"` // 返佣金额 + Status int64 `json:"status"` // 状态:1=已发放,2=已冻结,3=已取消(已退款) CreateTime string `json:"create_time"` // 创建时间 } // 升级返佣记录 @@ -539,28 +574,46 @@ type ( Total int64 `json:"total"` // 总数 List []WithdrawalItem `json:"list"` // 列表 } + // 提现记录 WithdrawalItem { - Id string `json:"id"` // 记录ID - WithdrawalNo string `json:"withdrawal_no"` // 提现单号 - Amount float64 `json:"amount"` // 提现金额 - TaxAmount float64 `json:"tax_amount"` // 税费金额 - ActualAmount float64 `json:"actual_amount"` // 实际到账金额 - Status int64 `json:"status"` // 状态:1=待审核,2=审核通过,3=审核拒绝,4=提现中,5=提现成功,6=提现失败 - PayeeAccount string `json:"payee_account"` // 收款账户 - PayeeName string `json:"payee_name"` // 收款人姓名 - Remark string `json:"remark"` // 备注 - CreateTime string `json:"create_time"` // 创建时间 + Id string `json:"id"` // 记录ID + WithdrawalNo string `json:"withdrawal_no"` // 提现单号 + Amount float64 `json:"amount"` // 提现金额 + TaxAmount float64 `json:"tax_amount"` // 税费金额 + ActualAmount float64 `json:"actual_amount"` // 实际到账金额 + Status int64 `json:"status"` // 状态:1=待审核,2=审核通过,3=审核拒绝,4=提现中,5=提现成功,6=提现失败 + WithdrawalType int64 `json:"withdrawal_type"` // 提现方式:1=支付宝,2=银行卡 + PayeeAccount string `json:"payee_account"` // 收款账户(支付宝账号或银行卡号) + PayeeName string `json:"payee_name"` // 收款人姓名 + BankCardNo string `json:"bank_card_no"` // 银行卡号(银行卡提现时填写) + BankName string `json:"bank_name"` // 开户行名称(银行卡提现时填写) + Remark string `json:"remark"` // 备注 + CreateTime string `json:"create_time"` // 创建时间 } // 申请提现 ApplyWithdrawalReq { - Amount float64 `json:"amount"` // 提现金额 - PayeeAccount string `json:"payee_account"` // 收款账户 - PayeeName string `json:"payee_name"` // 收款人姓名 + Amount float64 `json:"amount"` // 提现金额 + WithdrawalType int64 `json:"withdrawal_type"` // 提现方式:1=支付宝,2=银行卡 + PayeeAccount string `json:"payee_account"` // 收款账户(支付宝账号或银行卡号) + PayeeName string `json:"payee_name"` // 收款人姓名 + BankCardNo string `json:"bank_card_no,optional"` // 银行卡号(银行卡提现必填) + BankName string `json:"bank_name,optional"` // 开户行名称(银行卡提现必填) } ApplyWithdrawalResp { WithdrawalId string `json:"withdrawal_id"` // 提现记录ID WithdrawalNo string `json:"withdrawal_no"` // 提现单号 } + // 获取上次提现信息(用于前端预填) + GetLastWithdrawalInfoReq { + WithdrawalType int64 `form:"withdrawal_type"` // 提现方式:1=支付宝,2=银行卡 + } + GetLastWithdrawalInfoResp { + WithdrawalType int64 `json:"withdrawal_type"` // 提现方式 + PayeeAccount string `json:"payee_account"` // 收款账户(支付宝账号或银行卡号) + PayeeName string `json:"payee_name"` // 收款人姓名 + BankCardNo string `json:"bank_card_no"` // 银行卡号 + BankName string `json:"bank_name"` // 开户行名称 + } // 实名认证 RealNameAuthReq { Name string `json:"name"` // 姓名 @@ -581,11 +634,88 @@ type ( List []PromotionQueryItem `json:"list"` // 列表 } PromotionQueryItem { - Id string `json:"id"` // 查询ID - OrderId string `json:"order_id"` // 订单ID - ProductName string `json:"product_name"` // 产品名称 - CreateTime string `json:"create_time"` // 创建时间 - QueryState string `json:"query_state"` // 查询状态 + Id string `json:"id"` // 查询ID + OrderId string `json:"order_id"` // 订单ID + ProductName string `json:"product_name"` // 产品名称 + CreateTime string `json:"create_time"` // 创建时间 + QueryState string `json:"query_state"` // 查询状态 + Params map[string]interface{} `json:"params"` // 查询参数(已脱敏) + Price float64 `json:"price"` // 查询价格 + } + // ============================================ + // 用户模块白名单相关类型 + // ============================================ + GetWhitelistFeaturesReq {} + GetWhitelistFeaturesResp { + List []WhitelistFeatureItem `json:"list"` // 可屏蔽的feature列表 + } + WhitelistFeatureItem { + FeatureId string `json:"feature_id"` // Feature的UUID + FeatureApiId string `json:"feature_api_id"` // Feature的API标识 + FeatureName string `json:"feature_name"` // Feature的名称 + WhitelistPrice float64 `json:"whitelist_price"` // 屏蔽价格(单位:元) + } + CreateWhitelistOrderReq { + IdCard string `json:"id_card"` // 身份证号(查询对象标识) + FeatureIds []string `json:"feature_ids"` // 要屏蔽的feature ID列表 + OrderId string `json:"order_id,optional"` // 关联的查询订单ID(可选) + } + CreateWhitelistOrderResp { + OrderId string `json:"order_id"` // 订单ID + OrderNo string `json:"order_no"` // 订单号 + TotalAmount float64 `json:"total_amount"` // 总金额 + } + GetWhitelistListReq { + Page int64 `form:"page"` // 页码 + PageSize int64 `form:"page_size"` // 每页数量 + IdCard string `form:"id_card,optional"` // 身份证号(可选,用于筛选) + } + GetWhitelistListResp { + Total int64 `json:"total"` // 总数 + List []WhitelistItem `json:"list"` // 列表 + } + WhitelistItem { + Id string `json:"id"` // 白名单记录ID + IdCard string `json:"id_card"` // 身份证号 + FeatureId string `json:"feature_id"` // Feature的UUID + FeatureApiId string `json:"feature_api_id"` // Feature的API标识 + FeatureName string `json:"feature_name"` // Feature的名称 + Amount float64 `json:"amount"` // 费用 + Status int64 `json:"status"` // 状态:1=生效,2=已失效 + StatusText string `json:"status_text"` // 状态文本 + CreateTime string `json:"create_time"` // 创建时间 + } + // 检查模块白名单状态请求 + CheckFeatureWhitelistStatusReq { + IdCard string `form:"id_card"` // 身份证号 + FeatureApiId string `form:"feature_api_id"` // Feature的API标识 + QueryId string `form:"query_id,optional"` // 查询记录ID(可选,用于检查报告数据是否已删除) + } + // 检查模块白名单状态响应 + CheckFeatureWhitelistStatusResp { + IsWhitelisted bool `json:"is_whitelisted"` // 是否在白名单中 + WhitelistPrice float64 `json:"whitelist_price"` // 屏蔽价格(单位:元),如果为0表示不支持下架 + FeatureId string `json:"feature_id"` // Feature的UUID + DataDeleted bool `json:"data_deleted"` // 报告数据是否已删除(仅当提供了query_id时有效) + } + // 下架单个模块请求 + OfflineFeatureReq { + FeatureApiId string `json:"feature_api_id"` // Feature的API标识 + QueryId string `json:"query_id"` // 查询记录ID(Query表的ID,必选) + } + // 下架单个模块响应 + OfflineFeatureResp { + Success bool `json:"success"` // 是否已完成下架 + NeedPay bool `json:"need_pay"` // 是否需要发起支付 + Amount float64 `json:"amount"` // 需要支付的金额(单位:元),0表示无需支付 + } + // 检查订单是否属于当前代理请求 + CheckOrderAgentReq { + OrderId string `form:"order_id"` // 订单ID + } + // 检查订单是否属于当前代理响应 + CheckOrderAgentResp { + IsAgentOrder bool `json:"is_agent_order"` // 是否是当前代理推广的订单 } ) diff --git a/app/main/api/internal/handler/agent/checkfeaturewhiteliststatushandler.go b/app/main/api/internal/handler/agent/checkfeaturewhiteliststatushandler.go new file mode 100644 index 0000000..a236c40 --- /dev/null +++ b/app/main/api/internal/handler/agent/checkfeaturewhiteliststatushandler.go @@ -0,0 +1,29 @@ +package agent + +import ( + "net/http" + + "github.com/zeromicro/go-zero/rest/httpx" + "qnc-server/app/main/api/internal/logic/agent" + "qnc-server/app/main/api/internal/svc" + "qnc-server/app/main/api/internal/types" + "qnc-server/common/result" + "qnc-server/pkg/lzkit/validator" +) + +func CheckFeatureWhitelistStatusHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.CheckFeatureWhitelistStatusReq + if err := httpx.Parse(r, &req); err != nil { + result.ParamErrorResult(r, w, err) + return + } + if err := validator.Validate(req); err != nil { + result.ParamValidateErrorResult(r, w, err) + return + } + l := agent.NewCheckFeatureWhitelistStatusLogic(r.Context(), svcCtx) + resp, err := l.CheckFeatureWhitelistStatus(&req) + result.HttpResult(r, w, resp, err) + } +} diff --git a/app/main/api/internal/handler/agent/checkorderagenthandler.go b/app/main/api/internal/handler/agent/checkorderagenthandler.go new file mode 100644 index 0000000..48afc63 --- /dev/null +++ b/app/main/api/internal/handler/agent/checkorderagenthandler.go @@ -0,0 +1,29 @@ +package agent + +import ( + "net/http" + + "github.com/zeromicro/go-zero/rest/httpx" + "qnc-server/app/main/api/internal/logic/agent" + "qnc-server/app/main/api/internal/svc" + "qnc-server/app/main/api/internal/types" + "qnc-server/common/result" + "qnc-server/pkg/lzkit/validator" +) + +func CheckOrderAgentHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.CheckOrderAgentReq + if err := httpx.Parse(r, &req); err != nil { + result.ParamErrorResult(r, w, err) + return + } + if err := validator.Validate(req); err != nil { + result.ParamValidateErrorResult(r, w, err) + return + } + l := agent.NewCheckOrderAgentLogic(r.Context(), svcCtx) + resp, err := l.CheckOrderAgent(&req) + result.HttpResult(r, w, resp, err) + } +} diff --git a/app/main/api/internal/handler/agent/createwhitelistorderhandler.go b/app/main/api/internal/handler/agent/createwhitelistorderhandler.go new file mode 100644 index 0000000..d4d6579 --- /dev/null +++ b/app/main/api/internal/handler/agent/createwhitelistorderhandler.go @@ -0,0 +1,29 @@ +package agent + +import ( + "net/http" + + "github.com/zeromicro/go-zero/rest/httpx" + "qnc-server/app/main/api/internal/logic/agent" + "qnc-server/app/main/api/internal/svc" + "qnc-server/app/main/api/internal/types" + "qnc-server/common/result" + "qnc-server/pkg/lzkit/validator" +) + +func CreateWhitelistOrderHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.CreateWhitelistOrderReq + if err := httpx.Parse(r, &req); err != nil { + result.ParamErrorResult(r, w, err) + return + } + if err := validator.Validate(req); err != nil { + result.ParamValidateErrorResult(r, w, err) + return + } + l := agent.NewCreateWhitelistOrderLogic(r.Context(), svcCtx) + resp, err := l.CreateWhitelistOrder(&req) + result.HttpResult(r, w, resp, err) + } +} diff --git a/app/main/api/internal/handler/agent/getlastwithdrawalinfohandler.go b/app/main/api/internal/handler/agent/getlastwithdrawalinfohandler.go new file mode 100644 index 0000000..71b1624 --- /dev/null +++ b/app/main/api/internal/handler/agent/getlastwithdrawalinfohandler.go @@ -0,0 +1,30 @@ +package agent + +import ( + "net/http" + + "qnc-server/app/main/api/internal/logic/agent" + "qnc-server/app/main/api/internal/svc" + "qnc-server/app/main/api/internal/types" + "qnc-server/common/result" + "qnc-server/pkg/lzkit/validator" + + "github.com/zeromicro/go-zero/rest/httpx" +) + +func GetLastWithdrawalInfoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.GetLastWithdrawalInfoReq + if err := httpx.Parse(r, &req); err != nil { + result.ParamErrorResult(r, w, err) + return + } + if err := validator.Validate(req); err != nil { + result.ParamValidateErrorResult(r, w, err) + return + } + l := agent.NewGetLastWithdrawalInfoLogic(r.Context(), svcCtx) + resp, err := l.GetLastWithdrawalInfo(&req) + result.HttpResult(r, w, resp, err) + } +} diff --git a/app/main/api/internal/handler/agent/getwhitelistfeatureshandler.go b/app/main/api/internal/handler/agent/getwhitelistfeatureshandler.go new file mode 100644 index 0000000..c4437c9 --- /dev/null +++ b/app/main/api/internal/handler/agent/getwhitelistfeatureshandler.go @@ -0,0 +1,29 @@ +package agent + +import ( + "net/http" + + "github.com/zeromicro/go-zero/rest/httpx" + "qnc-server/app/main/api/internal/logic/agent" + "qnc-server/app/main/api/internal/svc" + "qnc-server/app/main/api/internal/types" + "qnc-server/common/result" + "qnc-server/pkg/lzkit/validator" +) + +func GetWhitelistFeaturesHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.GetWhitelistFeaturesReq + if err := httpx.Parse(r, &req); err != nil { + result.ParamErrorResult(r, w, err) + return + } + if err := validator.Validate(req); err != nil { + result.ParamValidateErrorResult(r, w, err) + return + } + l := agent.NewGetWhitelistFeaturesLogic(r.Context(), svcCtx) + resp, err := l.GetWhitelistFeatures(&req) + result.HttpResult(r, w, resp, err) + } +} diff --git a/app/main/api/internal/handler/agent/getwhitelistlisthandler.go b/app/main/api/internal/handler/agent/getwhitelistlisthandler.go new file mode 100644 index 0000000..0b3ce7e --- /dev/null +++ b/app/main/api/internal/handler/agent/getwhitelistlisthandler.go @@ -0,0 +1,29 @@ +package agent + +import ( + "net/http" + + "github.com/zeromicro/go-zero/rest/httpx" + "qnc-server/app/main/api/internal/logic/agent" + "qnc-server/app/main/api/internal/svc" + "qnc-server/app/main/api/internal/types" + "qnc-server/common/result" + "qnc-server/pkg/lzkit/validator" +) + +func GetWhitelistListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.GetWhitelistListReq + if err := httpx.Parse(r, &req); err != nil { + result.ParamErrorResult(r, w, err) + return + } + if err := validator.Validate(req); err != nil { + result.ParamValidateErrorResult(r, w, err) + return + } + l := agent.NewGetWhitelistListLogic(r.Context(), svcCtx) + resp, err := l.GetWhitelistList(&req) + result.HttpResult(r, w, resp, err) + } +} diff --git a/app/main/api/internal/handler/agent/offlinefeaturehandler.go b/app/main/api/internal/handler/agent/offlinefeaturehandler.go new file mode 100644 index 0000000..9b1b874 --- /dev/null +++ b/app/main/api/internal/handler/agent/offlinefeaturehandler.go @@ -0,0 +1,29 @@ +package agent + +import ( + "net/http" + + "github.com/zeromicro/go-zero/rest/httpx" + "qnc-server/app/main/api/internal/logic/agent" + "qnc-server/app/main/api/internal/svc" + "qnc-server/app/main/api/internal/types" + "qnc-server/common/result" + "qnc-server/pkg/lzkit/validator" +) + +func OfflineFeatureHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.OfflineFeatureReq + if err := httpx.Parse(r, &req); err != nil { + result.ParamErrorResult(r, w, err) + return + } + if err := validator.Validate(req); err != nil { + result.ParamValidateErrorResult(r, w, err) + return + } + l := agent.NewOfflineFeatureLogic(r.Context(), svcCtx) + resp, err := l.OfflineFeature(&req) + result.HttpResult(r, w, resp, err) + } +} diff --git a/app/main/api/internal/handler/routes.go b/app/main/api/internal/handler/routes.go index 4e37745..59f6328 100644 --- a/app/main/api/internal/handler/routes.go +++ b/app/main/api/internal/handler/routes.go @@ -103,7 +103,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { }, { Method: http.MethodPost, - Path: "/upgrade", + Path: "/upgrade/agent", Handler: admin_agent.AdminUpgradeAgentHandler(serverCtx), }, { @@ -671,6 +671,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Path: "/level/privilege", Handler: agent.GetLevelPrivilegeHandler(serverCtx), }, + { + Method: http.MethodGet, + Path: "/order/agent", + Handler: agent.CheckOrderAgentHandler(serverCtx), + }, { Method: http.MethodGet, Path: "/product_config", @@ -736,11 +741,41 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Path: "/upgrade/subordinate", Handler: agent.UpgradeSubordinateHandler(serverCtx), }, + { + Method: http.MethodGet, + Path: "/whitelist/check", + Handler: agent.CheckFeatureWhitelistStatusHandler(serverCtx), + }, + { + Method: http.MethodGet, + Path: "/whitelist/features", + Handler: agent.GetWhitelistFeaturesHandler(serverCtx), + }, + { + Method: http.MethodGet, + Path: "/whitelist/list", + Handler: agent.GetWhitelistListHandler(serverCtx), + }, + { + Method: http.MethodPost, + Path: "/whitelist/offline", + Handler: agent.OfflineFeatureHandler(serverCtx), + }, + { + Method: http.MethodPost, + Path: "/whitelist/order/create", + Handler: agent.CreateWhitelistOrderHandler(serverCtx), + }, { Method: http.MethodPost, Path: "/withdrawal/apply", Handler: agent.ApplyWithdrawalHandler(serverCtx), }, + { + Method: http.MethodGet, + Path: "/withdrawal/last_info", + Handler: agent.GetLastWithdrawalInfoHandler(serverCtx), + }, { Method: http.MethodGet, Path: "/withdrawal/list", diff --git a/app/main/api/internal/logic/admin_agent/adminauditwithdrawallogic.go b/app/main/api/internal/logic/admin_agent/adminauditwithdrawallogic.go index 5628edb..02fd674 100644 --- a/app/main/api/internal/logic/admin_agent/adminauditwithdrawallogic.go +++ b/app/main/api/internal/logic/admin_agent/adminauditwithdrawallogic.go @@ -4,10 +4,10 @@ import ( "context" "database/sql" "fmt" - "time" - "qnc-server/common/globalkey" + "os" "qnc-server/common/xerr" "qnc-server/pkg/lzkit/lzUtils" + "time" "github.com/pkg/errors" "github.com/zeromicro/go-zero/core/stores/sqlx" @@ -32,6 +32,13 @@ func NewAdminAuditWithdrawalLogic(ctx context.Context, svcCtx *svc.ServiceContex } } +// parseFloat 解析配置中的浮点数 +func (l *AdminAuditWithdrawalLogic) parseFloat(s string) (float64, error) { + var result float64 + _, err := fmt.Sscanf(s, "%f", &result) + return result, err +} + func (l *AdminAuditWithdrawalLogic) AdminAuditWithdrawal(req *types.AdminAuditWithdrawalReq) (resp *types.AdminAuditWithdrawalResp, err error) { // 1. 查询提现记录 withdrawal, err := l.svcCtx.AgentWithdrawalModel.FindOne(l.ctx, req.WithdrawalId) @@ -46,39 +53,126 @@ func (l *AdminAuditWithdrawalLogic) AdminAuditWithdrawal(req *types.AdminAuditWi // 4. 使用事务处理审核 err = l.svcCtx.AgentWithdrawalModel.Trans(l.ctx, func(transCtx context.Context, session sqlx.Session) error { - if req.Status == 2 { // 审核通过 - // 4.1 更新提现记录状态为提现中 - withdrawal.Status = 4 // 提现中 - withdrawal.Remark = sql.NullString{String: req.Remark, Valid: true} - if err := l.svcCtx.AgentWithdrawalModel.UpdateWithVersion(transCtx, session, withdrawal); err != nil { - return errors.Wrapf(err, "更新提现记录失败") - } + switch req.Status { + case 2: // 审核通过 + // 4.1 根据提现方式处理 + switch withdrawal.WithdrawalType { + case 1: + // 支付宝提现:审核通过前再次校验月度额度,避免一次性通过多笔超限 + now := time.Now() + monthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) + nextMonthStart := monthStart.AddDate(0, 1, 0) - // 4.2 调用支付宝转账接口 - outBizNo := withdrawal.WithdrawNo - transferResp, err := l.svcCtx.AlipayService.AliTransfer(transCtx, withdrawal.PayeeAccount, withdrawal.PayeeName, withdrawal.ActualAmount, "代理提现", outBizNo) - if err != nil { - // 转账失败,更新状态为失败 - withdrawal.Status = 6 // 提现失败 - withdrawal.Remark = sql.NullString{String: fmt.Sprintf("转账失败: %v", err), Valid: true} - l.svcCtx.AgentWithdrawalModel.UpdateWithVersion(transCtx, session, withdrawal) - - // 解冻余额 - wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(transCtx, withdrawal.AgentId) - if err == nil { - wallet.FrozenBalance -= withdrawal.Amount - wallet.Balance += withdrawal.Amount - l.svcCtx.AgentWalletModel.UpdateWithVersion(transCtx, session, wallet) + // 获取支付宝月度额度配置(默认 800 元) + alipayQuota := 800.0 + if cfg, cfgErr := l.svcCtx.AgentConfigModel.FindOneByConfigKey(transCtx, "alipay_month_quota"); cfgErr == nil { + if parsed, parseErr := l.parseFloat(cfg.ConfigValue); parseErr == nil && parsed > 0 { + alipayQuota = parsed + } } - return errors.Wrapf(err, "支付宝转账失败") - } + // 统计本月已成功的支付宝提现金额(status=5) + withdrawBuilder := l.svcCtx.AgentWithdrawalModel.SelectBuilder(). + Where("agent_id = ? AND withdrawal_type = ? AND status = ? AND create_time >= ? AND create_time < ?", + withdrawal.AgentId, 1, 5, monthStart, nextMonthStart) + usedAmount, sumErr := l.svcCtx.AgentWithdrawalModel.FindSum(transCtx, withdrawBuilder, "amount") + if sumErr != nil { + return errors.Wrapf(sumErr, "查询本月支付宝提现额度使用情况失败") + } - // 4.3 根据转账结果更新状态 - switch transferResp.Status { - case "SUCCESS": - // 转账成功 + if usedAmount+withdrawal.Amount > alipayQuota { + // 超出额度,不允许通过,保持待审核状态并提示原因 + withdrawal.Status = 1 + withdrawal.Remark = sql.NullString{ + String: fmt.Sprintf("超过本月支付宝提现额度(限额:%.2f 元,已用:%.2f 元),请使用银行卡提现或调整金额", alipayQuota, usedAmount), + Valid: true, + } + if err := l.svcCtx.AgentWithdrawalModel.UpdateWithVersion(transCtx, session, withdrawal); err != nil { + return errors.Wrapf(err, "更新提现记录失败") + } + return errors.Wrapf(xerr.NewErrMsg("超过本月支付宝提现额度,无法通过该笔提现"), "") + } + + // 支付宝提现:开发环境下做模拟,不调用真实支付宝转账 + mockTransferStatus := "SUCCESS" + var transferResp struct { + Status string + SubCode string + } + + if os.Getenv("ENV") == "development" { + transferResp.Status = mockTransferStatus + logx.Infof("【DEV】模拟支付宝转账成功,withdrawNo=%s, amount=%.2f, payee=%s", + withdrawal.WithdrawNo, withdrawal.ActualAmount, withdrawal.PayeeAccount) + } else { + // 生产环境:同步调用支付宝转账接口 + outBizNo := withdrawal.WithdrawNo + resp, err := l.svcCtx.AlipayService.AliTransfer(transCtx, withdrawal.PayeeAccount, withdrawal.PayeeName, withdrawal.ActualAmount, "代理提现", outBizNo) + if err != nil { + // 调用失败:保持状态为待审核(1),只记录备注,方便管理员重试 + withdrawal.Status = 1 // 待审核 + withdrawal.Remark = sql.NullString{String: fmt.Sprintf("支付宝转账调用失败: %v", err), Valid: true} + _ = l.svcCtx.AgentWithdrawalModel.UpdateWithVersion(transCtx, session, withdrawal) + + return errors.Wrapf(err, "支付宝转账失败") + } + transferResp.Status = resp.Status + transferResp.SubCode = resp.SubCode + } + + // 4.2 根据转账结果更新状态 + switch transferResp.Status { + case "SUCCESS": + // 转账成功 + withdrawal.Status = 5 // 提现成功 + if err := l.svcCtx.AgentWithdrawalModel.UpdateWithVersion(transCtx, session, withdrawal); err != nil { + return errors.Wrapf(err, "更新提现记录失败") + } + + // 更新钱包(解冻并扣除) + wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(transCtx, withdrawal.AgentId) + if err != nil { + return errors.Wrapf(err, "查询钱包失败") + } + wallet.FrozenBalance -= withdrawal.Amount + wallet.WithdrawnAmount += withdrawal.Amount + if err := l.svcCtx.AgentWalletModel.UpdateWithVersion(transCtx, session, wallet); err != nil { + return errors.Wrapf(err, "更新钱包失败") + } + + // 更新扣税记录状态 + taxBuilder := l.svcCtx.AgentWithdrawalTaxModel.SelectBuilder(). + Where("withdrawal_id = ?", withdrawal.Id) + taxRecords, err := l.svcCtx.AgentWithdrawalTaxModel.FindAll(transCtx, taxBuilder, "") + if err == nil && len(taxRecords) > 0 { + taxRecord := taxRecords[0] + taxRecord.TaxStatus = 2 // 已扣税 + taxRecord.TaxTime = lzUtils.TimeToNullTime(time.Now()) + l.svcCtx.AgentWithdrawalTaxModel.UpdateWithVersion(transCtx, session, taxRecord) + } + + case "FAIL": + // 转账失败:保持待审核状态,方便人工处理或重试 + withdrawal.Status = 1 // 待审核 + errorMsg := l.mapAlipayError(transferResp.SubCode) + withdrawal.Remark = sql.NullString{String: errorMsg, Valid: true} + if err := l.svcCtx.AgentWithdrawalModel.UpdateWithVersion(transCtx, session, withdrawal); err != nil { + return errors.Wrapf(err, "更新提现记录失败") + } + + case "DEALING": + // 处理中:同样保持待审核状态(1),由管理员后续确认 + withdrawal.Status = 1 + withdrawal.Remark = sql.NullString{String: "支付宝处理中,请稍后重试或联系平台", Valid: true} + if err := l.svcCtx.AgentWithdrawalModel.UpdateWithVersion(transCtx, session, withdrawal); err != nil { + return errors.Wrapf(err, "更新提现记录失败") + } + } + + case 2: + // 银行卡提现:审核通过即视为提现成功(线下已/将立即打款) withdrawal.Status = 5 // 提现成功 + withdrawal.Remark = sql.NullString{String: req.Remark, Valid: true} if err := l.svcCtx.AgentWithdrawalModel.UpdateWithVersion(transCtx, session, withdrawal); err != nil { return errors.Wrapf(err, "更新提现记录失败") } @@ -96,7 +190,7 @@ func (l *AdminAuditWithdrawalLogic) AdminAuditWithdrawal(req *types.AdminAuditWi // 更新扣税记录状态 taxBuilder := l.svcCtx.AgentWithdrawalTaxModel.SelectBuilder(). - Where("withdrawal_id = ? AND del_state = ?", withdrawal.Id, globalkey.DelStateNo) + Where("withdrawal_id = ?", withdrawal.Id) taxRecords, err := l.svcCtx.AgentWithdrawalTaxModel.FindAll(transCtx, taxBuilder, "") if err == nil && len(taxRecords) > 0 { taxRecord := taxRecords[0] @@ -104,30 +198,9 @@ func (l *AdminAuditWithdrawalLogic) AdminAuditWithdrawal(req *types.AdminAuditWi taxRecord.TaxTime = lzUtils.TimeToNullTime(time.Now()) l.svcCtx.AgentWithdrawalTaxModel.UpdateWithVersion(transCtx, session, taxRecord) } - - case "FAIL": - // 转账失败 - withdrawal.Status = 6 // 提现失败 - errorMsg := l.mapAlipayError(transferResp.SubCode) - withdrawal.Remark = sql.NullString{String: errorMsg, Valid: true} - if err := l.svcCtx.AgentWithdrawalModel.UpdateWithVersion(transCtx, session, withdrawal); err != nil { - return errors.Wrapf(err, "更新提现记录失败") - } - - // 解冻余额 - wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(transCtx, withdrawal.AgentId) - if err == nil { - wallet.FrozenBalance -= withdrawal.Amount - wallet.Balance += withdrawal.Amount - l.svcCtx.AgentWalletModel.UpdateWithVersion(transCtx, session, wallet) - } - - case "DEALING": - // 处理中,保持提现中状态,后续通过轮询更新 - // 状态已经是4(提现中),无需更新 } - } else if req.Status == 3 { // 审核拒绝 + case 3: // 审核拒绝 // 4.1 更新提现记录状态为拒绝 withdrawal.Status = 3 // 审核拒绝 withdrawal.Remark = sql.NullString{String: req.Remark, Valid: true} diff --git a/app/main/api/internal/logic/admin_agent/admingetagentwithdrawallistlogic.go b/app/main/api/internal/logic/admin_agent/admingetagentwithdrawallistlogic.go index c74dafe..eb2cad9 100644 --- a/app/main/api/internal/logic/admin_agent/admingetagentwithdrawallistlogic.go +++ b/app/main/api/internal/logic/admin_agent/admingetagentwithdrawallistlogic.go @@ -49,6 +49,17 @@ func (l *AdminGetAgentWithdrawalListLogic) AdminGetAgentWithdrawalList(req *type item.Remark = v.Remark.String } item.CreateTime = v.CreateTime.Format("2006-01-02 15:04:05") + + // 如果是银行卡提现,填充银行卡信息 + if v.WithdrawalType == 2 { + if v.BankCardNo.Valid { + item.BankCardNo = v.BankCardNo.String + } + if v.BankName.Valid { + item.BankName = v.BankName.String + } + } + items = append(items, item) } resp = &types.AdminGetAgentWithdrawalListResp{ diff --git a/app/main/api/internal/logic/agent/applywithdrawallogic.go b/app/main/api/internal/logic/agent/applywithdrawallogic.go index 7f548e7..39619fc 100644 --- a/app/main/api/internal/logic/agent/applywithdrawallogic.go +++ b/app/main/api/internal/logic/agent/applywithdrawallogic.go @@ -3,12 +3,11 @@ package agent import ( "context" "fmt" - "time" "qnc-server/app/main/model" "qnc-server/common/ctxdata" - "qnc-server/common/globalkey" "qnc-server/common/xerr" "qnc-server/pkg/lzkit/lzUtils" + "time" "github.com/google/uuid" "github.com/pkg/errors" @@ -62,53 +61,138 @@ func (l *ApplyWithdrawalLogic) ApplyWithdrawal(req *types.ApplyWithdrawalReq) (r return nil, errors.Wrapf(xerr.NewErrMsg("请先完成实名认证"), "") } - // 3. 验证提现金额 + // 3. 验证提现方式 + if req.WithdrawalType != 1 && req.WithdrawalType != 2 { + return nil, errors.Wrapf(xerr.NewErrMsg("提现方式无效"), "") + } + + // 4. 验证提现信息 + if req.WithdrawalType == 1 { + // 支付宝提现:验证支付宝账号和姓名 + if req.PayeeAccount == "" { + return nil, errors.Wrapf(xerr.NewErrMsg("请输入支付宝账号"), "") + } + if req.PayeeName == "" { + return nil, errors.Wrapf(xerr.NewErrMsg("请输入收款人姓名"), "") + } + } else if req.WithdrawalType == 2 { + // 银行卡提现:验证银行卡号、开户行和姓名 + if req.BankCardNo == "" { + return nil, errors.Wrapf(xerr.NewErrMsg("请输入银行卡号"), "") + } + if req.BankName == "" { + return nil, errors.Wrapf(xerr.NewErrMsg("请输入开户行名称"), "") + } + if req.PayeeName == "" { + return nil, errors.Wrapf(xerr.NewErrMsg("请输入收款人姓名"), "") + } + } + + // 5. 验证提现金额 if req.Amount <= 0 { return nil, errors.Wrapf(xerr.NewErrMsg("提现金额必须大于0"), "") } - // 4. 获取钱包信息 + // 6. 获取钱包信息 wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(l.ctx, agent.Id) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询钱包失败, %v", err) } - // 5. 验证余额 + // 7. 验证余额(包括检查是否为负数) + if wallet.Balance < 0 { + return nil, errors.Wrapf(xerr.NewErrMsg(fmt.Sprintf("账户存在欠款,请先补足欠款后再申请提现,当前余额:%.2f", wallet.Balance)), "") + } if wallet.Balance < req.Amount { return nil, errors.Wrapf(xerr.NewErrMsg(fmt.Sprintf("余额不足,当前余额:%.2f", wallet.Balance)), "") } - // 6. 计算税费 + // 8. 支付宝月度提现额度校验(仅针对支付宝提现) + if req.WithdrawalType == 1 { + now := time.Now() + monthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) + nextMonthStart := monthStart.AddDate(0, 1, 0) + + // 8.1 获取支付宝月度额度配置(默认 800 元) + alipayQuota := 800.0 + if cfg, cfgErr := l.svcCtx.AgentConfigModel.FindOneByConfigKey(l.ctx, "alipay_month_quota"); cfgErr == nil { + if parsed, parseErr := l.parseFloat(cfg.ConfigValue); parseErr == nil && parsed > 0 { + alipayQuota = parsed + } + } + + // 8.2 统计本月已申请/成功的支付宝提现金额(status IN (1,5)),避免多次申请占用超额 + withdrawBuilder := l.svcCtx.AgentWithdrawalModel.SelectBuilder(). + Where("agent_id = ? AND withdrawal_type = ? AND status IN (1,5) AND create_time >= ? AND create_time < ?", + agent.Id, 1, monthStart, nextMonthStart) + usedAmount, sumErr := l.svcCtx.AgentWithdrawalModel.FindSum(l.ctx, withdrawBuilder, "amount") + if sumErr != nil { + return nil, errors.Wrapf(sumErr, "查询本月支付宝提现额度使用情况失败") + } + + remainQuota := alipayQuota - usedAmount + if remainQuota <= 0 { + return nil, errors.Wrapf( + xerr.NewErrMsg(fmt.Sprintf("本月支付宝提现额度已用完(额度:%.2f 元),请使用银行卡提现", alipayQuota)), + "", + ) + } + + if req.Amount > remainQuota { + return nil, errors.Wrapf( + xerr.NewErrMsg(fmt.Sprintf("本月支付宝最高可提现 %.2f 元,请调整提现金额或使用银行卡提现", remainQuota)), + "", + ) + } + } + + // 9. 计算税费 yearMonth := int64(time.Now().Year()*100 + int(time.Now().Month())) taxInfo, err := l.calculateTax(l.ctx, agent.Id, req.Amount, yearMonth) if err != nil { return nil, errors.Wrapf(err, "计算税费失败") } - // 7. 生成提现单号 - withdrawNo := fmt.Sprintf("WD%d%d", time.Now().Unix(), agent.Id) + // 10. 生成提现单号(WD开头 + GenerateOutTradeNo生成的订单号,确保总长度不超过32个字符) + orderNo := l.svcCtx.AlipayService.GenerateOutTradeNo() + withdrawNo := "WD" + orderNo + // 确保总长度不超过32个字符 + if len(withdrawNo) > 32 { + withdrawNo = withdrawNo[:32] + } - // 8. 使用事务处理提现申请 + // 11. 使用事务处理提现申请 var withdrawalId string err = l.svcCtx.AgentWalletModel.Trans(l.ctx, func(transCtx context.Context, session sqlx.Session) error { - // 8.1 冻结余额 + // 11.1 冻结余额 wallet.FrozenBalance += req.Amount wallet.Balance -= req.Amount if err := l.svcCtx.AgentWalletModel.UpdateWithVersion(transCtx, session, wallet); err != nil { return errors.Wrapf(err, "冻结余额失败") } - // 8.2 创建提现记录 + // 11.2 创建提现记录 withdrawal := &model.AgentWithdrawal{ - Id: uuid.New().String(), - AgentId: agent.Id, - WithdrawNo: withdrawNo, - PayeeAccount: req.PayeeAccount, - PayeeName: req.PayeeName, - Amount: req.Amount, - ActualAmount: taxInfo.ActualAmount, - TaxAmount: taxInfo.TaxAmount, - Status: 1, // 处理中(待审核) + Id: uuid.New().String(), + AgentId: agent.Id, + WithdrawNo: withdrawNo, + WithdrawalType: req.WithdrawalType, + PayeeAccount: req.PayeeAccount, + PayeeName: req.PayeeName, + Amount: req.Amount, + ActualAmount: taxInfo.ActualAmount, + TaxAmount: taxInfo.TaxAmount, + Status: 1, // 待审核 + } + + // 如果是银行卡提现,设置银行卡相关字段 + if req.WithdrawalType == 2 { + withdrawal.BankCardNo = lzUtils.StringToNullString(req.BankCardNo) + withdrawal.BankName = lzUtils.StringToNullString(req.BankName) + // 银行卡提现时,payee_account 可以存储银行卡号(便于查询),也可以留空 + if req.PayeeAccount == "" { + withdrawal.PayeeAccount = req.BankCardNo + } } _, err := l.svcCtx.AgentWithdrawalModel.Insert(transCtx, session, withdrawal) @@ -117,7 +201,7 @@ func (l *ApplyWithdrawalLogic) ApplyWithdrawal(req *types.ApplyWithdrawalReq) (r } withdrawalId = withdrawal.Id - // 8.3 创建扣税记录 + // 11.3 创建扣税记录 taxRecord := &model.AgentWithdrawalTax{ AgentId: agent.Id, WithdrawalId: withdrawalId, @@ -167,8 +251,10 @@ func (l *ApplyWithdrawalLogic) calculateTax(ctx context.Context, agentId string, } // 查询本月已提现金额 + // 注意:FindAll 方法会自动添加 del_state = ? 条件,所以这里不需要手动添加 + // 这里对 year_month 使用反引号包裹,避免与某些数据库版本/SQL 模式下的关键字冲突 builder := l.svcCtx.AgentWithdrawalTaxModel.SelectBuilder(). - Where("agent_id = ? AND year_month = ? AND del_state = ?", agentId, yearMonth, globalkey.DelStateNo) + Where("agent_id = ? AND `year_month` = ?", agentId, yearMonth) taxRecords, err := l.svcCtx.AgentWithdrawalTaxModel.FindAll(ctx, builder, "") if err != nil { return nil, errors.Wrapf(err, "查询月度提现记录失败") diff --git a/app/main/api/internal/logic/agent/checkfeaturewhiteliststatuslogic.go b/app/main/api/internal/logic/agent/checkfeaturewhiteliststatuslogic.go new file mode 100644 index 0000000..4ad3c98 --- /dev/null +++ b/app/main/api/internal/logic/agent/checkfeaturewhiteliststatuslogic.go @@ -0,0 +1,30 @@ +package agent + +import ( + "context" + + "qnc-server/app/main/api/internal/svc" + "qnc-server/app/main/api/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type CheckFeatureWhitelistStatusLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewCheckFeatureWhitelistStatusLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CheckFeatureWhitelistStatusLogic { + return &CheckFeatureWhitelistStatusLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *CheckFeatureWhitelistStatusLogic) CheckFeatureWhitelistStatus(req *types.CheckFeatureWhitelistStatusReq) (resp *types.CheckFeatureWhitelistStatusResp, err error) { + // todo: add your logic here and delete this line + + return +} diff --git a/app/main/api/internal/logic/agent/checkorderagentlogic.go b/app/main/api/internal/logic/agent/checkorderagentlogic.go new file mode 100644 index 0000000..9bc37de --- /dev/null +++ b/app/main/api/internal/logic/agent/checkorderagentlogic.go @@ -0,0 +1,30 @@ +package agent + +import ( + "context" + + "qnc-server/app/main/api/internal/svc" + "qnc-server/app/main/api/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type CheckOrderAgentLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewCheckOrderAgentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CheckOrderAgentLogic { + return &CheckOrderAgentLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *CheckOrderAgentLogic) CheckOrderAgent(req *types.CheckOrderAgentReq) (resp *types.CheckOrderAgentResp, err error) { + // todo: add your logic here and delete this line + + return +} diff --git a/app/main/api/internal/logic/agent/createwhitelistorderlogic.go b/app/main/api/internal/logic/agent/createwhitelistorderlogic.go new file mode 100644 index 0000000..57182b9 --- /dev/null +++ b/app/main/api/internal/logic/agent/createwhitelistorderlogic.go @@ -0,0 +1,30 @@ +package agent + +import ( + "context" + + "qnc-server/app/main/api/internal/svc" + "qnc-server/app/main/api/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type CreateWhitelistOrderLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewCreateWhitelistOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateWhitelistOrderLogic { + return &CreateWhitelistOrderLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *CreateWhitelistOrderLogic) CreateWhitelistOrder(req *types.CreateWhitelistOrderReq) (resp *types.CreateWhitelistOrderResp, err error) { + // todo: add your logic here and delete this line + + return +} diff --git a/app/main/api/internal/logic/agent/getlastwithdrawalinfologic.go b/app/main/api/internal/logic/agent/getlastwithdrawalinfologic.go new file mode 100644 index 0000000..14684ac --- /dev/null +++ b/app/main/api/internal/logic/agent/getlastwithdrawalinfologic.go @@ -0,0 +1,95 @@ +package agent + +import ( + "context" + "qnc-server/app/main/model" + "qnc-server/common/ctxdata" + "qnc-server/common/xerr" + + "github.com/pkg/errors" + + "qnc-server/app/main/api/internal/svc" + "qnc-server/app/main/api/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type GetLastWithdrawalInfoLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewGetLastWithdrawalInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetLastWithdrawalInfoLogic { + return &GetLastWithdrawalInfoLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *GetLastWithdrawalInfoLogic) GetLastWithdrawalInfo(req *types.GetLastWithdrawalInfoReq) (resp *types.GetLastWithdrawalInfoResp, err error) { + userID, err := ctxdata.GetUidFromCtx(l.ctx) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户信息失败, %v", err) + } + + // 1. 获取代理信息 + agent, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID) + if err != nil { + if errors.Is(err, model.ErrNotFound) { + return nil, errors.Wrapf(xerr.NewErrMsg("您不是代理"), "") + } + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理信息失败, %v", err) + } + + // 2. 验证提现方式 + if req.WithdrawalType != 1 && req.WithdrawalType != 2 { + return nil, errors.Wrapf(xerr.NewErrMsg("提现方式无效"), "") + } + + // 3. 查询该代理最近一次该类型的提现记录 + // 注意:FindAll 方法会自动添加 del_state = ? 条件,所以这里不需要手动添加 + builder := l.svcCtx.AgentWithdrawalModel.SelectBuilder(). + Where("agent_id = ? AND withdrawal_type = ?", agent.Id, req.WithdrawalType). + OrderBy("create_time DESC"). + Limit(1) + + withdrawals, err := l.svcCtx.AgentWithdrawalModel.FindAll(l.ctx, builder, "") + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询上次提现记录失败, %v", err) + } + + // 4. 如果没有找到记录,返回空信息 + if len(withdrawals) == 0 { + return &types.GetLastWithdrawalInfoResp{ + WithdrawalType: req.WithdrawalType, + PayeeAccount: "", + PayeeName: "", + BankCardNo: "", + BankName: "", + }, nil + } + + // 5. 组装响应 + lastWithdrawal := withdrawals[0] + resp = &types.GetLastWithdrawalInfoResp{ + WithdrawalType: lastWithdrawal.WithdrawalType, + PayeeAccount: lastWithdrawal.PayeeAccount, + PayeeName: lastWithdrawal.PayeeName, + BankCardNo: "", + BankName: "", + } + + // 如果是银行卡提现,填充银行卡信息 + if lastWithdrawal.WithdrawalType == 2 { + if lastWithdrawal.BankCardNo.Valid { + resp.BankCardNo = lastWithdrawal.BankCardNo.String + } + if lastWithdrawal.BankName.Valid { + resp.BankName = lastWithdrawal.BankName.String + } + } + + return resp, nil +} diff --git a/app/main/api/internal/logic/agent/getwhitelistfeatureslogic.go b/app/main/api/internal/logic/agent/getwhitelistfeatureslogic.go new file mode 100644 index 0000000..52b067b --- /dev/null +++ b/app/main/api/internal/logic/agent/getwhitelistfeatureslogic.go @@ -0,0 +1,30 @@ +package agent + +import ( + "context" + + "qnc-server/app/main/api/internal/svc" + "qnc-server/app/main/api/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type GetWhitelistFeaturesLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewGetWhitelistFeaturesLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetWhitelistFeaturesLogic { + return &GetWhitelistFeaturesLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *GetWhitelistFeaturesLogic) GetWhitelistFeatures(req *types.GetWhitelistFeaturesReq) (resp *types.GetWhitelistFeaturesResp, err error) { + // todo: add your logic here and delete this line + + return +} diff --git a/app/main/api/internal/logic/agent/getwhitelistlistlogic.go b/app/main/api/internal/logic/agent/getwhitelistlistlogic.go new file mode 100644 index 0000000..ddddbdb --- /dev/null +++ b/app/main/api/internal/logic/agent/getwhitelistlistlogic.go @@ -0,0 +1,30 @@ +package agent + +import ( + "context" + + "qnc-server/app/main/api/internal/svc" + "qnc-server/app/main/api/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type GetWhitelistListLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewGetWhitelistListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetWhitelistListLogic { + return &GetWhitelistListLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *GetWhitelistListLogic) GetWhitelistList(req *types.GetWhitelistListReq) (resp *types.GetWhitelistListResp, err error) { + // todo: add your logic here and delete this line + + return +} diff --git a/app/main/api/internal/logic/agent/getwithdrawallistlogic.go b/app/main/api/internal/logic/agent/getwithdrawallistlogic.go index 78531c7..cb0483f 100644 --- a/app/main/api/internal/logic/agent/getwithdrawallistlogic.go +++ b/app/main/api/internal/logic/agent/getwithdrawallistlogic.go @@ -81,18 +81,31 @@ func (l *GetWithdrawalListLogic) GetWithdrawalList(req *types.GetWithdrawalListR remark = withdrawal.Remark.String } - list = append(list, types.WithdrawalItem{ - Id: withdrawal.Id, - WithdrawalNo: withdrawal.WithdrawNo, - Amount: withdrawal.Amount, - TaxAmount: withdrawal.TaxAmount, - ActualAmount: withdrawal.ActualAmount, - Status: withdrawal.Status, - PayeeAccount: withdrawal.PayeeAccount, - PayeeName: withdrawal.PayeeName, - Remark: remark, - CreateTime: withdrawal.CreateTime.Format("2006-01-02 15:04:05"), - }) + item := types.WithdrawalItem{ + Id: withdrawal.Id, + WithdrawalNo: withdrawal.WithdrawNo, + WithdrawalType: withdrawal.WithdrawalType, + Amount: withdrawal.Amount, + TaxAmount: withdrawal.TaxAmount, + ActualAmount: withdrawal.ActualAmount, + Status: withdrawal.Status, + PayeeAccount: withdrawal.PayeeAccount, + PayeeName: withdrawal.PayeeName, + Remark: remark, + CreateTime: withdrawal.CreateTime.Format("2006-01-02 15:04:05"), + } + + // 如果是银行卡提现,填充银行卡信息 + if withdrawal.WithdrawalType == 2 { + if withdrawal.BankCardNo.Valid { + item.BankCardNo = withdrawal.BankCardNo.String + } + if withdrawal.BankName.Valid { + item.BankName = withdrawal.BankName.String + } + } + + list = append(list, item) } return &types.GetWithdrawalListResp{ diff --git a/app/main/api/internal/logic/agent/offlinefeaturelogic.go b/app/main/api/internal/logic/agent/offlinefeaturelogic.go new file mode 100644 index 0000000..86d72f9 --- /dev/null +++ b/app/main/api/internal/logic/agent/offlinefeaturelogic.go @@ -0,0 +1,30 @@ +package agent + +import ( + "context" + + "qnc-server/app/main/api/internal/svc" + "qnc-server/app/main/api/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type OfflineFeatureLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewOfflineFeatureLogic(ctx context.Context, svcCtx *svc.ServiceContext) *OfflineFeatureLogic { + return &OfflineFeatureLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *OfflineFeatureLogic) OfflineFeature(req *types.OfflineFeatureReq) (resp *types.OfflineFeatureResp, err error) { + // todo: add your logic here and delete this line + + return +} diff --git a/app/main/api/internal/types/types.go b/app/main/api/internal/types/types.go index 290e58c..0e6a4ca 100644 --- a/app/main/api/internal/types/types.go +++ b/app/main/api/internal/types/types.go @@ -282,6 +282,7 @@ type AdminGetAgentOrderListReq struct { AgentId *string `form:"agent_id,optional"` // 代理ID(可选) OrderId *string `form:"order_id,optional"` // 订单ID(可选) ProcessStatus *int64 `form:"process_status,optional"` // 处理状态(可选) + OrderStatus *string `form:"order_status,optional"` // 订单状态(可选):pending-待支付,paid-已支付,refunded-已退款,closed-已关闭,failed-支付失败 } type AdminGetAgentOrderListResp struct { @@ -319,6 +320,7 @@ type AdminGetAgentRebateListReq struct { AgentId *string `form:"agent_id,optional"` // 代理ID(可选) SourceAgentId *string `form:"source_agent_id,optional"` // 来源代理ID(可选) RebateType *int64 `form:"rebate_type,optional"` // 返佣类型(可选) + Status *int64 `form:"status,optional"` // 状态(可选):1=已发放,2=已冻结,3=已取消(已退款) } type AdminGetAgentRebateListResp struct { @@ -898,7 +900,7 @@ type AdminUpgradeAgentReq struct { } type AdminUpgradeAgentResp struct { - Success bool `json:"success"` + Success bool `json:"success"` // 是否成功 } type AdminUserInfoReq struct { @@ -1008,7 +1010,8 @@ type AgentOrderListItem struct { ActualBasePrice float64 `json:"actual_base_price"` // 实际底价 PriceCost float64 `json:"price_cost"` // 提价成本 AgentProfit float64 `json:"agent_profit"` // 代理收益 - ProcessStatus int64 `json:"process_status"` // 处理状态 + ProcessStatus int64 `json:"process_status"` // 处理状态(保留用于筛选,前端不显示) + OrderStatus string `json:"order_status"` // 订单状态:pending-待支付,paid-已支付,refunded-已退款,closed-已关闭,failed-支付失败 CreateTime string `json:"create_time"` // 创建时间 } @@ -1046,6 +1049,7 @@ type AgentRebateListItem struct { OrderId string `json:"order_id"` // 订单ID RebateType int64 `json:"rebate_type"` // 返佣类型 Amount float64 `json:"amount"` // 金额 + Status int64 `json:"status"` // 状态:1=已发放,2=已冻结,3=已取消(已退款) CreateTime string `json:"create_time"` // 创建时间 } @@ -1062,17 +1066,20 @@ type AgentUpgradeListItem struct { } type AgentWithdrawalListItem struct { - Id string `json:"id"` // 主键 - AgentId string `json:"agent_id"` // 代理ID - WithdrawNo string `json:"withdraw_no"` // 提现单号 - Amount float64 `json:"amount"` // 金额 - TaxAmount float64 `json:"tax_amount"` // 税费金额 - ActualAmount float64 `json:"actual_amount"` // 实际到账金额 - Status int64 `json:"status"` // 状态 - PayeeAccount string `json:"payee_account"` // 收款账户 - PayeeName string `json:"payee_name"` // 收款人姓名 - Remark string `json:"remark"` // 备注 - CreateTime string `json:"create_time"` // 创建时间 + Id string `json:"id"` // 主键 + AgentId string `json:"agent_id"` // 代理ID + WithdrawNo string `json:"withdraw_no"` // 提现单号 + Amount float64 `json:"amount"` // 金额 + TaxAmount float64 `json:"tax_amount"` // 税费金额 + ActualAmount float64 `json:"actual_amount"` // 实际到账金额 + Status int64 `json:"status"` // 状态 + WithdrawalType int64 `json:"withdrawal_type"` // 提现方式:1=支付宝,2=银行卡 + PayeeAccount string `json:"payee_account"` // 收款账户(支付宝账号或银行卡号) + PayeeName string `json:"payee_name"` // 收款人姓名 + BankCardNo string `json:"bank_card_no"` // 银行卡号(银行卡提现时使用) + BankName string `json:"bank_name"` // 开户行名称(银行卡提现时使用) + Remark string `json:"remark"` // 备注 + CreateTime string `json:"create_time"` // 创建时间 } type ApplyUpgradeReq struct { @@ -1085,9 +1092,12 @@ type ApplyUpgradeResp struct { } type ApplyWithdrawalReq struct { - Amount float64 `json:"amount"` // 提现金额 - PayeeAccount string `json:"payee_account"` // 收款账户 - PayeeName string `json:"payee_name"` // 收款人姓名 + Amount float64 `json:"amount"` // 提现金额 + WithdrawalType int64 `json:"withdrawal_type"` // 提现方式:1=支付宝,2=银行卡 + PayeeAccount string `json:"payee_account"` // 收款账户(支付宝账号或银行卡号) + PayeeName string `json:"payee_name"` // 收款人姓名 + BankCardNo string `json:"bank_card_no,optional"` // 银行卡号(银行卡提现必填) + BankName string `json:"bank_name,optional"` // 开户行名称(银行卡提现必填) } type ApplyWithdrawalResp struct { @@ -1133,6 +1143,27 @@ type BindMobileResp struct { RefreshAfter int64 `json:"refreshAfter"` } +type CheckFeatureWhitelistStatusReq struct { + IdCard string `form:"id_card"` // 身份证号 + FeatureApiId string `form:"feature_api_id"` // Feature的API标识 + QueryId string `form:"query_id,optional"` // 查询记录ID(可选,用于检查报告数据是否已删除) +} + +type CheckFeatureWhitelistStatusResp struct { + IsWhitelisted bool `json:"is_whitelisted"` // 是否在白名单中 + WhitelistPrice float64 `json:"whitelist_price"` // 屏蔽价格(单位:元),如果为0表示不支持下架 + FeatureId string `json:"feature_id"` // Feature的UUID + DataDeleted bool `json:"data_deleted"` // 报告数据是否已删除(仅当提供了query_id时有效) +} + +type CheckOrderAgentReq struct { + OrderId string `form:"order_id"` // 订单ID +} + +type CheckOrderAgentResp struct { + IsAgentOrder bool `json:"is_agent_order"` // 是否是当前代理推广的订单 +} + type CommissionFreezeConfig struct { Ratio float64 `json:"ratio"` // 佣金冻结比例(例如:0.1表示10%) Threshold float64 `json:"threshold"` // 佣金冻结阈值(订单单价达到此金额才触发冻结,单位:元) @@ -1189,6 +1220,18 @@ type CreateRoleResp struct { Id string `json:"id"` // 角色ID } +type CreateWhitelistOrderReq struct { + IdCard string `json:"id_card"` // 身份证号(查询对象标识) + FeatureIds []string `json:"feature_ids"` // 要屏蔽的feature ID列表 + OrderId string `json:"order_id,optional"` // 关联的查询订单ID(可选) +} + +type CreateWhitelistOrderResp struct { + OrderId string `json:"order_id"` // 订单ID + OrderNo string `json:"order_no"` // 订单号 + TotalAmount float64 `json:"total_amount"` // 总金额 +} + type DeleteInviteCodeReq struct { Id string `json:"id"` // 邀请码ID } @@ -1306,6 +1349,18 @@ type GetInviteLinkResp struct { InviteLink string `json:"invite_link"` // 邀请链接 } +type GetLastWithdrawalInfoReq struct { + WithdrawalType int64 `form:"withdrawal_type"` // 提现方式:1=支付宝,2=银行卡 +} + +type GetLastWithdrawalInfoResp struct { + WithdrawalType int64 `json:"withdrawal_type"` // 提现方式 + PayeeAccount string `json:"payee_account"` // 收款账户(支付宝账号或银行卡号) + PayeeName string `json:"payee_name"` // 收款人姓名 + BankCardNo string `json:"bank_card_no"` // 银行卡号 + BankName string `json:"bank_name"` // 开户行名称 +} + type GetLevelPrivilegeResp struct { Levels []LevelPrivilegeItem `json:"levels"` UpgradeToGoldFee float64 `json:"upgrade_to_gold_fee"` @@ -1404,16 +1459,18 @@ type GetRebateListResp struct { } type GetRevenueInfoResp struct { - Balance float64 `json:"balance"` // 可用余额 - FrozenBalance float64 `json:"frozen_balance"` // 冻结余额 - TotalEarnings float64 `json:"total_earnings"` // 累计收益(钱包总收益) - WithdrawnAmount float64 `json:"withdrawn_amount"` // 累计提现 - CommissionTotal float64 `json:"commission_total"` // 佣金累计总收益(推广订单获得的佣金) - CommissionToday float64 `json:"commission_today"` // 佣金今日收益 - CommissionMonth float64 `json:"commission_month"` // 佣金本月收益 - RebateTotal float64 `json:"rebate_total"` // 返佣累计总收益(包括推广返佣和升级返佣) - RebateToday float64 `json:"rebate_today"` // 返佣今日收益 - RebateMonth float64 `json:"rebate_month"` // 返佣本月收益 + Balance float64 `json:"balance"` // 可用余额 + FrozenBalance float64 `json:"frozen_balance"` // 冻结余额 + TotalEarnings float64 `json:"total_earnings"` // 累计收益(钱包总收益) + WithdrawnAmount float64 `json:"withdrawn_amount"` // 累计提现 + CommissionTotal float64 `json:"commission_total"` // 佣金累计总收益(推广订单获得的佣金) + CommissionToday float64 `json:"commission_today"` // 佣金今日收益 + CommissionMonth float64 `json:"commission_month"` // 佣金本月收益 + RebateTotal float64 `json:"rebate_total"` // 返佣累计总收益(包括推广返佣和升级返佣) + RebateToday float64 `json:"rebate_today"` // 返佣今日收益 + RebateMonth float64 `json:"rebate_month"` // 返佣本月收益 + AlipayMonthQuota float64 `json:"alipay_month_quota"` // 支付宝每月提现总额度 + AlipayMonthUsed float64 `json:"alipay_month_used"` // 本月已使用的支付宝提现额度 } type GetRoleDetailReq struct { @@ -1518,6 +1575,24 @@ type GetUpgradeRebateListResp struct { List []UpgradeRebateItem `json:"list"` // 列表 } +type GetWhitelistFeaturesReq struct { +} + +type GetWhitelistFeaturesResp struct { + List []WhitelistFeatureItem `json:"list"` // 可屏蔽的feature列表 +} + +type GetWhitelistListReq struct { + Page int64 `form:"page"` // 页码 + PageSize int64 `form:"page_size"` // 每页数量 + IdCard string `form:"id_card,optional"` // 身份证号(可选,用于筛选) +} + +type GetWhitelistListResp struct { + Total int64 `json:"total"` // 总数 + List []WhitelistItem `json:"list"` // 列表 +} + type GetWithdrawalListReq struct { Page int64 `form:"page"` // 页码 PageSize int64 `form:"page_size"` // 每页数量 @@ -1650,6 +1725,17 @@ type NotificationListItem struct { UpdateTime string `json:"update_time"` // 更新时间 } +type OfflineFeatureReq struct { + FeatureApiId string `json:"feature_api_id"` // Feature的API标识 + QueryId string `json:"query_id"` // 查询记录ID(Query表的ID,必选) +} + +type OfflineFeatureResp struct { + Success bool `json:"success"` // 是否已完成下架 + NeedPay bool `json:"need_pay"` // 是否需要发起支付 + Amount float64 `json:"amount"` // 需要支付的金额(单位:元),0表示无需支付 +} + type OrderItem struct { OrderNo string `json:"order_no"` // 订单号 ProductId string `json:"product_id"` // 产品ID @@ -1695,7 +1781,6 @@ type PaymentReq struct { Id string `json:"id"` PayMethod string `json:"pay_method"` // 支付方式: wechat, alipay, appleiap, test(仅开发环境), test_empty(仅开发环境-空报告模式) PayType string `json:"pay_type" validate:"required,oneof=query agent_vip agent_upgrade"` - Code string `json:"code,optional"` // 微信小程序/H5授权码,用于自动绑定微信账号(当用户未绑定微信时) } type PaymentResp struct { @@ -1767,11 +1852,13 @@ type ProductResponse struct { } type PromotionQueryItem struct { - Id string `json:"id"` // 查询ID - OrderId string `json:"order_id"` // 订单ID - ProductName string `json:"product_name"` // 产品名称 - CreateTime string `json:"create_time"` // 创建时间 - QueryState string `json:"query_state"` // 查询状态 + Id string `json:"id"` // 查询ID + OrderId string `json:"order_id"` // 订单ID + ProductName string `json:"product_name"` // 产品名称 + CreateTime string `json:"create_time"` // 创建时间 + QueryState string `json:"query_state"` // 查询状态 + Params map[string]interface{} `json:"params"` // 查询参数(已脱敏) + Price float64 `json:"price"` // 查询价格 } type Query struct { @@ -1931,6 +2018,7 @@ type RebateItem struct { OrderNo string `json:"order_no"` // 订单号 RebateType int64 `json:"rebate_type"` // 返佣类型:1=直接上级,2=钻石上级,3=黄金上级 Amount float64 `json:"amount"` // 返佣金额 + Status int64 `json:"status"` // 状态:1=已发放,2=已冻结,3=已取消(已退款) CreateTime string `json:"create_time"` // 创建时间 } @@ -1990,14 +2078,14 @@ type TeamMemberItem struct { LevelName string `json:"level_name"` // 等级名称 Mobile string `json:"mobile"` // 手机号 CreateTime string `json:"create_time"` // 加入团队时间 - TotalRebateAmount float64 `json:"total_rebate_amount"` // 返佣给我的总金额 - TodayRebateAmount float64 `json:"today_rebate_amount"` // 返佣给我的今日金额 - TodayInvites int64 `json:"today_invites"` // 邀请加入团队的今日人数 - MonthInvites int64 `json:"month_invites"` // 邀请加入团队的本月人数 - TotalInvites int64 `json:"total_invites"` // 邀请加入团队的总人数 TodayQueries int64 `json:"today_queries"` // 当日查询量 MonthQueries int64 `json:"month_queries"` // 本月查询量 TotalQueries int64 `json:"total_queries"` // 总查询量 + TotalRebateAmount float64 `json:"total_rebate_amount"` // 返佣给我的总金额 + TodayRebateAmount float64 `json:"today_rebate_amount"` // 返佣给我的今日金额 + TotalInvites int64 `json:"total_invites"` // 邀请加入团队的总人数 + TodayInvites int64 `json:"today_invites"` // 邀请加入团队的今日人数 + MonthInvites int64 `json:"month_invites"` // 邀请加入团队的本月人数 IsDirect bool `json:"is_direct"` // 是否直接下级 } @@ -2137,17 +2225,39 @@ type WXMiniAuthResp struct { RefreshAfter int64 `json:"refreshAfter"` } +type WhitelistFeatureItem struct { + FeatureId string `json:"feature_id"` // Feature的UUID + FeatureApiId string `json:"feature_api_id"` // Feature的API标识 + FeatureName string `json:"feature_name"` // Feature的名称 + WhitelistPrice float64 `json:"whitelist_price"` // 屏蔽价格(单位:元) +} + +type WhitelistItem struct { + Id string `json:"id"` // 白名单记录ID + IdCard string `json:"id_card"` // 身份证号 + FeatureId string `json:"feature_id"` // Feature的UUID + FeatureApiId string `json:"feature_api_id"` // Feature的API标识 + FeatureName string `json:"feature_name"` // Feature的名称 + Amount float64 `json:"amount"` // 费用 + Status int64 `json:"status"` // 状态:1=生效,2=已失效 + StatusText string `json:"status_text"` // 状态文本 + CreateTime string `json:"create_time"` // 创建时间 +} + type WithdrawalItem struct { - Id string `json:"id"` // 记录ID - WithdrawalNo string `json:"withdrawal_no"` // 提现单号 - Amount float64 `json:"amount"` // 提现金额 - TaxAmount float64 `json:"tax_amount"` // 税费金额 - ActualAmount float64 `json:"actual_amount"` // 实际到账金额 - Status int64 `json:"status"` // 状态:1=待审核,2=审核通过,3=审核拒绝,4=提现中,5=提现成功,6=提现失败 - PayeeAccount string `json:"payee_account"` // 收款账户 - PayeeName string `json:"payee_name"` // 收款人姓名 - Remark string `json:"remark"` // 备注 - CreateTime string `json:"create_time"` // 创建时间 + Id string `json:"id"` // 记录ID + WithdrawalNo string `json:"withdrawal_no"` // 提现单号 + Amount float64 `json:"amount"` // 提现金额 + TaxAmount float64 `json:"tax_amount"` // 税费金额 + ActualAmount float64 `json:"actual_amount"` // 实际到账金额 + Status int64 `json:"status"` // 状态:1=待审核,2=审核通过,3=审核拒绝,4=提现中,5=提现成功,6=提现失败 + WithdrawalType int64 `json:"withdrawal_type"` // 提现方式:1=支付宝,2=银行卡 + PayeeAccount string `json:"payee_account"` // 收款账户(支付宝账号或银行卡号) + PayeeName string `json:"payee_name"` // 收款人姓名 + BankCardNo string `json:"bank_card_no"` // 银行卡号(银行卡提现时填写) + BankName string `json:"bank_name"` // 开户行名称(银行卡提现时填写) + Remark string `json:"remark"` // 备注 + CreateTime string `json:"create_time"` // 创建时间 } type GetAppConfigResp struct { diff --git a/app/main/model/agentConfigModel_gen.go b/app/main/model/agentConfigModel_gen.go index c2ea5cb..94bfa85 100644 --- a/app/main/model/agentConfigModel_gen.go +++ b/app/main/model/agentConfigModel_gen.go @@ -11,8 +11,6 @@ import ( "reflect" "time" - "qnc-server/common/globalkey" - "github.com/Masterminds/squirrel" "github.com/google/uuid" "github.com/pkg/errors" @@ -21,6 +19,7 @@ import ( "github.com/zeromicro/go-zero/core/stores/sqlc" "github.com/zeromicro/go-zero/core/stores/sqlx" "github.com/zeromicro/go-zero/core/stringx" + "qnc-server/common/globalkey" ) var ( diff --git a/app/main/model/agentWithdrawalModel_gen.go b/app/main/model/agentWithdrawalModel_gen.go index b7aaa16..243fd16 100644 --- a/app/main/model/agentWithdrawalModel_gen.go +++ b/app/main/model/agentWithdrawalModel_gen.go @@ -59,21 +59,24 @@ type ( } AgentWithdrawal struct { - Id string `db:"id"` - AgentId string `db:"agent_id"` - WithdrawNo string `db:"withdraw_no"` // 提现单号 - PayeeAccount string `db:"payee_account"` // 收款账户 - PayeeName string `db:"payee_name"` // 收款人姓名 - Amount float64 `db:"amount"` // 提现金额 - ActualAmount float64 `db:"actual_amount"` // 实际到账金额(扣除税费后) - TaxAmount float64 `db:"tax_amount"` // 税费金额 - Status int64 `db:"status"` // 状态:1=处理中,2=成功,3=失败 - Remark sql.NullString `db:"remark"` // 备注 - CreateTime time.Time `db:"create_time"` // 创建时间 - UpdateTime time.Time `db:"update_time"` // 更新时间 - DeleteTime sql.NullTime `db:"delete_time"` // 删除时间 - DelState int64 `db:"del_state"` // 删除状态:0=未删除,1=已删除 - Version int64 `db:"version"` // 版本号(乐观锁) + Id string `db:"id"` + AgentId string `db:"agent_id"` + WithdrawalType int64 `db:"withdrawal_type"` // 提现方式:1=支付宝,2=银行卡 + WithdrawNo string `db:"withdraw_no"` // 提现单号 + PayeeAccount string `db:"payee_account"` // 收款账户 + BankCardNo sql.NullString `db:"bank_card_no"` // 银行卡号(银行卡提现时使用) + BankName sql.NullString `db:"bank_name"` // 开户行名称(银行卡提现时使用) + PayeeName string `db:"payee_name"` // 收款人姓名 + Amount float64 `db:"amount"` // 提现金额 + ActualAmount float64 `db:"actual_amount"` // 实际到账金额(扣除税费后) + TaxAmount float64 `db:"tax_amount"` // 税费金额 + Status int64 `db:"status"` // 状态:1=处理中,2=成功,3=失败 + Remark sql.NullString `db:"remark"` // 备注 + CreateTime time.Time `db:"create_time"` // 创建时间 + UpdateTime time.Time `db:"update_time"` // 更新时间 + DeleteTime sql.NullTime `db:"delete_time"` // 删除时间 + DelState int64 `db:"del_state"` // 删除状态:0=未删除,1=已删除 + Version int64 `db:"version"` // 版本号(乐观锁) } ) @@ -90,11 +93,11 @@ func (m *defaultAgentWithdrawalModel) Insert(ctx context.Context, session sqlx.S qncAgentWithdrawalIdKey := fmt.Sprintf("%s%v", cacheQncAgentWithdrawalIdPrefix, data.Id) qncAgentWithdrawalWithdrawNoKey := fmt.Sprintf("%s%v", cacheQncAgentWithdrawalWithdrawNoPrefix, data.WithdrawNo) return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { - query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, agentWithdrawalRowsExpectAutoSet) + query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, agentWithdrawalRowsExpectAutoSet) if session != nil { - return session.ExecCtx(ctx, query, data.Id, data.AgentId, data.WithdrawNo, data.PayeeAccount, data.PayeeName, data.Amount, data.ActualAmount, data.TaxAmount, data.Status, data.Remark, data.DeleteTime, data.DelState, data.Version) + return session.ExecCtx(ctx, query, data.Id, data.AgentId, data.WithdrawalType, data.WithdrawNo, data.PayeeAccount, data.BankCardNo, data.BankName, data.PayeeName, data.Amount, data.ActualAmount, data.TaxAmount, data.Status, data.Remark, data.DeleteTime, data.DelState, data.Version) } - return conn.ExecCtx(ctx, query, data.Id, data.AgentId, data.WithdrawNo, data.PayeeAccount, data.PayeeName, data.Amount, data.ActualAmount, data.TaxAmount, data.Status, data.Remark, data.DeleteTime, data.DelState, data.Version) + return conn.ExecCtx(ctx, query, data.Id, data.AgentId, data.WithdrawalType, data.WithdrawNo, data.PayeeAccount, data.BankCardNo, data.BankName, data.PayeeName, data.Amount, data.ActualAmount, data.TaxAmount, data.Status, data.Remark, data.DeleteTime, data.DelState, data.Version) }, qncAgentWithdrawalIdKey, qncAgentWithdrawalWithdrawNoKey) } func (m *defaultAgentWithdrawalModel) insertUUID(data *AgentWithdrawal) { @@ -161,9 +164,9 @@ func (m *defaultAgentWithdrawalModel) Update(ctx context.Context, session sqlx.S return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, agentWithdrawalRowsWithPlaceHolder) if session != nil { - return session.ExecCtx(ctx, query, newData.AgentId, newData.WithdrawNo, newData.PayeeAccount, newData.PayeeName, newData.Amount, newData.ActualAmount, newData.TaxAmount, newData.Status, newData.Remark, newData.DeleteTime, newData.DelState, newData.Version, newData.Id) + return session.ExecCtx(ctx, query, newData.AgentId, newData.WithdrawalType, newData.WithdrawNo, newData.PayeeAccount, newData.BankCardNo, newData.BankName, newData.PayeeName, newData.Amount, newData.ActualAmount, newData.TaxAmount, newData.Status, newData.Remark, newData.DeleteTime, newData.DelState, newData.Version, newData.Id) } - return conn.ExecCtx(ctx, query, newData.AgentId, newData.WithdrawNo, newData.PayeeAccount, newData.PayeeName, newData.Amount, newData.ActualAmount, newData.TaxAmount, newData.Status, newData.Remark, newData.DeleteTime, newData.DelState, newData.Version, newData.Id) + return conn.ExecCtx(ctx, query, newData.AgentId, newData.WithdrawalType, newData.WithdrawNo, newData.PayeeAccount, newData.BankCardNo, newData.BankName, newData.PayeeName, newData.Amount, newData.ActualAmount, newData.TaxAmount, newData.Status, newData.Remark, newData.DeleteTime, newData.DelState, newData.Version, newData.Id) }, qncAgentWithdrawalIdKey, qncAgentWithdrawalWithdrawNoKey) } @@ -184,9 +187,9 @@ func (m *defaultAgentWithdrawalModel) UpdateWithVersion(ctx context.Context, ses sqlResult, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { query := fmt.Sprintf("update %s set %s where `id` = ? and version = ? ", m.table, agentWithdrawalRowsWithPlaceHolder) if session != nil { - return session.ExecCtx(ctx, query, newData.AgentId, newData.WithdrawNo, newData.PayeeAccount, newData.PayeeName, newData.Amount, newData.ActualAmount, newData.TaxAmount, newData.Status, newData.Remark, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion) + return session.ExecCtx(ctx, query, newData.AgentId, newData.WithdrawalType, newData.WithdrawNo, newData.PayeeAccount, newData.BankCardNo, newData.BankName, newData.PayeeName, newData.Amount, newData.ActualAmount, newData.TaxAmount, newData.Status, newData.Remark, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion) } - return conn.ExecCtx(ctx, query, newData.AgentId, newData.WithdrawNo, newData.PayeeAccount, newData.PayeeName, newData.Amount, newData.ActualAmount, newData.TaxAmount, newData.Status, newData.Remark, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion) + return conn.ExecCtx(ctx, query, newData.AgentId, newData.WithdrawalType, newData.WithdrawNo, newData.PayeeAccount, newData.BankCardNo, newData.BankName, newData.PayeeName, newData.Amount, newData.ActualAmount, newData.TaxAmount, newData.Status, newData.Remark, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion) }, qncAgentWithdrawalIdKey, qncAgentWithdrawalWithdrawNoKey) if err != nil { return err diff --git a/deploy/script/gen_models.ps1 b/deploy/script/gen_models.ps1 index 9bccad0..b950a48 100644 --- a/deploy/script/gen_models.ps1 +++ b/deploy/script/gen_models.ps1 @@ -28,7 +28,7 @@ $tables = @( # "admin_user_role", # "agent", # "agent_commission", - "agent_config" + # "agent_config" # "agent_freeze_task", # "agent_invite_code", # "agent_invite_code_usage", @@ -41,8 +41,8 @@ $tables = @( # "agent_short_link", # "agent_upgrade", # "agent_wallet", - # "agent_withdrawal", - # "agent_withdrawal_tax", + "agent_withdrawal", + "agent_withdrawal_tax" # "authorization_document", # "example", # "feature", @@ -62,8 +62,9 @@ $tables = @( # 为每个表生成模型 foreach ($table in $tables) { Write-Host "正在生成表: $table" -ForegroundColor Green - goctl model mysql datasource -url="qnc:5vg67b3UNHu8@tcp(127.0.0.1:21001)/qnc" -table="$table" -dir="./model" --home="$HOME_DIR" -cache=true --style=goZero - + # goctl model mysql datasource -url="qnc:5vg67b3UNHu8@tcp(127.0.0.1:21001)/qnc" -table="$table" -dir="./model" --home="$HOME_DIR" -cache=true --style=goZero + goctl model mysql datasource -url="qnc:5vg67b3UNHu8@tcp(127.0.0.1:21201)/qnc" -table="$table" -dir="./model" --home="$HOME_DIR" -cache=true --style=goZero + # 移动生成的文件到目标目录 if (Test-Path $OUTPUT_DIR) { $sourceFiles = Get-ChildItem -Path $OUTPUT_DIR -File diff --git a/deploy/sql/withdrawal_alipay_quota_migration.sql b/deploy/sql/withdrawal_alipay_quota_migration.sql new file mode 100644 index 0000000..7956f1b --- /dev/null +++ b/deploy/sql/withdrawal_alipay_quota_migration.sql @@ -0,0 +1,26 @@ +-- ============================================ +-- 支付宝月度提现额度配置 +-- ============================================ +-- 说明:为代理系统增加支付宝每月提现额度配置,默认 800 元 +-- 执行时间:2026-01-06 +-- ============================================ + +INSERT INTO + `agent_config` ( + `id`, + `config_key`, + `config_value`, + `config_type`, + `description` + ) +VALUES ( + 'f47ac10b-58cc-4372-a567-0e02b2c3d479', + 'alipay_month_quota', + '800.00', + 'withdrawal', + '支付宝每月提现额度(单位:元)' + ) +ON DUPLICATE KEY UPDATE + `config_value` = VALUES(`config_value`), + `config_type` = VALUES(`config_type`), + `description` = VALUES(`description`); \ No newline at end of file diff --git a/deploy/sql/withdrawal_bank_card_migration.sql b/deploy/sql/withdrawal_bank_card_migration.sql new file mode 100644 index 0000000..b18fd36 --- /dev/null +++ b/deploy/sql/withdrawal_bank_card_migration.sql @@ -0,0 +1,36 @@ +-- ============================================ +-- 代理提现表 - 添加银行卡提现支持 +-- ============================================ +-- 说明:为 agent_withdrawal 表添加提现方式字段和银行卡相关字段 +-- 执行时间:2024-XX-XX +-- ============================================ + +-- 1. 添加提现方式字段(1=支付宝,2=银行卡) +ALTER TABLE `agent_withdrawal` +ADD COLUMN `withdrawal_type` tinyint NOT NULL DEFAULT 1 COMMENT '提现方式:1=支付宝,2=银行卡' AFTER `agent_id`; + +-- 2. 添加银行卡号字段(银行卡提现时使用) +ALTER TABLE `agent_withdrawal` +ADD COLUMN `bank_card_no` varchar(100) DEFAULT NULL COMMENT '银行卡号(银行卡提现时使用)' AFTER `payee_account`; + +-- 3. 添加开户行名称字段(银行卡提现时使用) +ALTER TABLE `agent_withdrawal` +ADD COLUMN `bank_name` varchar(100) DEFAULT NULL COMMENT '开户行名称(银行卡提现时使用)' AFTER `bank_card_no`; + +-- 4. 为提现方式字段添加索引(用于按提现方式查询) +ALTER TABLE `agent_withdrawal` +ADD INDEX `idx_withdrawal_type` (`withdrawal_type`); + +-- 5. 为提现方式和状态添加复合索引(用于后台审核查询) +ALTER TABLE `agent_withdrawal` +ADD INDEX `idx_type_status` (`withdrawal_type`, `status`); + + + +-- ============================================ +-- 说明: +-- 1. withdrawal_type 默认值为 1(支付宝),兼容历史数据 +-- 2. bank_card_no 和 bank_name 为可选字段,支付宝提现时为空 +-- 3. 对于支付宝提现,payee_account 存储支付宝账号 +-- 4. 对于银行卡提现,payee_account 可以存储银行卡号(与 bank_card_no 保持一致),或留空 +-- ============================================ \ No newline at end of file