package controller import ( "io" "math" "net/http" "strconv" "strings" "github.com/QuantumNous/new-api/common" "github.com/QuantumNous/new-api/model" "github.com/QuantumNous/new-api/service" "github.com/gin-gonic/gin" ) type createDistributorWithdrawalRequest struct { AccountType int `json:"account_type"` RealName string `json:"real_name"` BankName string `json:"bank_name"` BankAccount string `json:"bank_account"` WithdrawMonth string `json:"withdraw_month"` // 使用 float64 兼容前端 JSON 中的小数(如 InputNumber),再取整 QuotaAmount float64 `json:"quota_amount"` // 个人扩展 IdCardNo string `json:"id_card_no"` IdCardExpiry string `json:"id_card_expiry"` Mobile string `json:"mobile"` BankReservedPhone string `json:"bank_reserved_phone"` IdCardFrontUrl string `json:"id_card_front_url"` IdCardBackUrl string `json:"id_card_back_url"` BankCardPhotoUrl string `json:"bank_card_photo_url"` // 企业扩展 CreditCode string `json:"credit_code"` LegalPersonName string `json:"legal_person_name"` LegalPersonPhone string `json:"legal_person_phone"` BankBranchCode string `json:"bank_branch_code"` ContactPerson string `json:"contact_person"` BusinessLicenseUrl string `json:"business_license_url"` CorporateAccountProofUrl string `json:"corporate_account_proof_url"` InvoiceUrl string `json:"invoice_url"` } func distributorWithdrawalToJSON(w model.DistributorWithdrawal, username string) gin.H { profile := model.ParseDistributorWithdrawalProfile(w.ProfileData) return gin.H{ "id": w.Id, "user_id": w.UserId, "username": username, "account_type": w.AccountType, "real_name": w.RealName, "bank_name": w.BankName, "bank_account": w.BankAccount, "profile_data": profile, "voucher_urls": w.VoucherUrls, "withdraw_month": w.WithdrawMonth, "quota_amount": w.QuotaAmount, "status": w.Status, "reject_reason": w.RejectReason, "reviewer_id": w.ReviewerId, "reviewed_at": w.ReviewedAt, "cancelled_at": w.CancelledAt, "created_at": w.CreatedAt, "updated_at": w.UpdatedAt, "id_card_no": profile.IdCardNo, "id_card_expiry": profile.IdCardExpiry, "mobile": profile.Mobile, "bank_reserved_phone": profile.BankReservedPhone, "id_card_front_url": profile.IdCardFrontUrl, "id_card_back_url": profile.IdCardBackUrl, "bank_card_photo_url": profile.BankCardPhotoUrl, "credit_code": profile.CreditCode, "legal_person_name": profile.LegalPersonName, "legal_person_phone": profile.LegalPersonPhone, "bank_branch_code": profile.BankBranchCode, "contact_person": profile.ContactPerson, "business_license_url": profile.BusinessLicenseUrl, "corporate_account_proof_url": profile.CorporateAccountProofUrl, "invoice_url": profile.InvoiceUrl, } } func buildWithdrawalProfileJSON(req createDistributorWithdrawalRequest) (string, error) { accountType := req.AccountType if accountType == 0 { accountType = model.DistributorApplyTypePersonal } p := model.DistributorWithdrawalProfile{ IdCardNo: strings.TrimSpace(req.IdCardNo), IdCardExpiry: strings.TrimSpace(req.IdCardExpiry), Mobile: strings.TrimSpace(req.Mobile), BankReservedPhone: strings.TrimSpace(req.BankReservedPhone), IdCardFrontUrl: strings.TrimSpace(req.IdCardFrontUrl), IdCardBackUrl: strings.TrimSpace(req.IdCardBackUrl), BankCardPhotoUrl: strings.TrimSpace(req.BankCardPhotoUrl), CreditCode: strings.TrimSpace(req.CreditCode), LegalPersonName: strings.TrimSpace(req.LegalPersonName), LegalPersonPhone: strings.TrimSpace(req.LegalPersonPhone), BankBranchCode: strings.TrimSpace(req.BankBranchCode), ContactPerson: strings.TrimSpace(req.ContactPerson), BusinessLicenseUrl: strings.TrimSpace(req.BusinessLicenseUrl), CorporateAccountProofUrl: strings.TrimSpace(req.CorporateAccountProofUrl), InvoiceUrl: strings.TrimSpace(req.InvoiceUrl), } b, err := common.Marshal(p) if err != nil { return "", err } return string(b), nil } type submitDistributorApplicationRequest struct { ApplyType int `json:"apply_type"` RealName string `json:"real_name"` IdCardNo string `json:"id_card_no"` QualificationUrls []string `json:"qualification_urls"` Contact string `json:"contact"` } // PostDistributorApplication 提交/重新提交分销商申请 func PostDistributorApplication(c *gin.Context) { userId := c.GetInt("id") var req submitDistributorApplicationRequest if err := common.DecodeJson(c.Request.Body, &req); err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": "无效的请求"}) return } if req.ApplyType == 0 { req.ApplyType = model.DistributorApplyTypePersonal } urlsJSON, err := common.Marshal(req.QualificationUrls) if err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": "资料序列化失败"}) return } err = model.UpsertDistributorApplication(userId, req.ApplyType, req.RealName, req.IdCardNo, string(urlsJSON), req.Contact) if err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"success": true, "message": ""}) } // GetMyDistributorApplication 当前用户的申请状态 func GetMyDistributorApplication(c *gin.Context) { userId := c.GetInt("id") app, err := model.GetDistributorApplicationByUserId(userId) if err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"success": true, "message": "", "data": app}) } // GetDistributorCenterInfo 分销商中心汇总(邀请短链、默认比例等) func GetDistributorCenterInfo(c *gin.Context) { userId := c.GetInt("id") user, err := model.GetUserById(userId, true) if err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } if !model.UserIsDistributor(user) { c.JSON(http.StatusOK, gin.H{"success": false, "message": "您不是分销商"}) return } if user.AffCode == "" { user.AffCode = common.GetRandomString(4) if err := user.Update(false); err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } } bps := user.DistributorCommissionBps if bps <= 0 { bps = common.AffiliateDefaultCommissionBps } applyType, applicationRealName, err := model.GetDistributorWithdrawAccountType(userId) if err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", "data": gin.H{ "aff_code": user.AffCode, "aff_quota": user.AffQuota, "aff_history_quota": user.AffHistoryQuota, "aff_count": user.AffCount, "distributor_commission_bps": user.DistributorCommissionBps, "effective_commission_bps": bps, "default_commission_bps": common.AffiliateDefaultCommissionBps, "apply_type": applyType, "application_real_name": applicationRealName, }, }) } // GetDistributorInviteeCommissionLogs 分销商查看某一被邀请用户的充值分成明细(按笔:入账额度、当时比例、收益额度)。 func GetDistributorInviteeCommissionLogs(c *gin.Context) { userId := c.GetInt("id") u, err := model.GetUserById(userId, false) if err != nil || !model.UserIsDistributor(u) { c.JSON(http.StatusOK, gin.H{"success": false, "message": "仅分销商可查看"}) return } inviteeId, err := strconv.Atoi(c.Param("invitee_id")) if err != nil || inviteeId <= 0 { c.JSON(http.StatusOK, gin.H{"success": false, "message": "参数错误"}) return } invitee, err := model.GetUserById(inviteeId, false) if err != nil || invitee.InviterId != userId { c.JSON(http.StatusOK, gin.H{"success": false, "message": "无权查看或用户不存在"}) return } pageInfo := common.GetPageQuery(c) items, total, err := model.ListAffInviteCommissionLogs(userId, inviteeId, pageInfo) if err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } pageInfo.SetTotal(int(total)) pageInfo.SetItems(items) c.JSON(http.StatusOK, gin.H{"success": true, "message": "", "data": pageInfo}) } // GetDistributorInviteeProfitShareLogs 分销商查看某一被邀请用户的利润分成明细(按次结算)。 func GetDistributorInviteeProfitShareLogs(c *gin.Context) { userId := c.GetInt("id") u, err := model.GetUserById(userId, false) if err != nil || !model.UserIsDistributor(u) { c.JSON(http.StatusOK, gin.H{"success": false, "message": "仅分销商可查看"}) return } inviteeId, err := strconv.Atoi(c.Param("invitee_id")) if err != nil || inviteeId <= 0 { c.JSON(http.StatusOK, gin.H{"success": false, "message": "参数错误"}) return } invitee, err := model.GetUserById(inviteeId, false) if err != nil || invitee.InviterId != userId { c.JSON(http.StatusOK, gin.H{"success": false, "message": "无权查看或用户不存在"}) return } pageInfo := common.GetPageQuery(c) items, total, err := model.ListAffInviteProfitShareLogs(userId, inviteeId, pageInfo) if err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } pageInfo.SetTotal(int(total)) pageInfo.SetItems(items) c.JSON(http.StatusOK, gin.H{"success": true, "message": "", "data": pageInfo}) } type rejectApplicationRequest struct { Reason string `json:"reason"` } // ListDistributorApplicationsAdmin 管理端:申请列表 func ListDistributorApplicationsAdmin(c *gin.Context) { pageInfo := common.GetPageQuery(c) status, _ := strconv.Atoi(c.Query("status")) applyType, _ := strconv.Atoi(c.Query("apply_type")) q := model.DistributorApplicationListQuery{ Keyword: c.Query("keyword"), Status: status, ApplyType: applyType, DateFrom: parseInt64Query(c.Query("date_from")), DateTo: parseInt64Query(c.Query("date_to")), PageInfo: pageInfo, } rows, usernames, total, err := model.ListDistributorApplicationsAdmin(q) if err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } items := make([]gin.H, 0, len(rows)) for i := range rows { items = append(items, gin.H{ "id": rows[i].Id, "user_id": rows[i].UserId, "username": usernames[i], "apply_type": rows[i].ApplyType, "real_name": rows[i].RealName, "contact": rows[i].Contact, "status": rows[i].Status, "reject_reason": rows[i].RejectReason, "created_at": rows[i].CreatedAt, "id_card_no_mask": maskIdCard(rows[i].IdCardNo), "qualification_urls": rows[i].QualificationUrls, }) } pageInfo.SetTotal(int(total)) pageInfo.SetItems(items) c.JSON(http.StatusOK, gin.H{"success": true, "message": "", "data": pageInfo}) } func parseInt64Query(s string) int64 { s = strings.TrimSpace(s) if s == "" { return 0 } n, _ := strconv.ParseInt(s, 10, 64) return n } func maskIdCard(id string) string { id = strings.TrimSpace(id) if len(id) <= 8 { return "****" } return id[:4] + strings.Repeat("*", len(id)-8) + id[len(id)-4:] } // GetDistributorApplicationAdmin 申请详情(管理员) func GetDistributorApplicationAdmin(c *gin.Context) { id, err := strconv.Atoi(c.Param("id")) if err != nil || id <= 0 { c.JSON(http.StatusOK, gin.H{"success": false, "message": "invalid id"}) return } app, username, err := model.GetDistributorApplicationByIdAdmin(id) if err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", "data": gin.H{ "id": app.Id, "user_id": app.UserId, "username": username, "apply_type": app.ApplyType, "real_name": app.RealName, "id_card_no": app.IdCardNo, "qualification_urls": app.QualificationUrls, "contact": app.Contact, "status": app.Status, "reject_reason": app.RejectReason, "reviewer_id": app.ReviewerId, "reviewed_at": app.ReviewedAt, "created_at": app.CreatedAt, "updated_at": app.UpdatedAt, }, }) } type approveDistributorApplicationRequest struct { DistributorCommissionBps *int `json:"distributor_commission_bps"` } // ApproveDistributorApplicationAdmin 通过申请(可选 body:distributor_commission_bps 万分之一,0=跟随系统) func ApproveDistributorApplicationAdmin(c *gin.Context) { id, err := strconv.Atoi(c.Param("id")) if err != nil || id <= 0 { c.JSON(http.StatusOK, gin.H{"success": false, "message": "invalid id"}) return } var req approveDistributorApplicationRequest body, readErr := io.ReadAll(c.Request.Body) if readErr != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": "读取请求失败"}) return } if len(strings.TrimSpace(string(body))) > 0 { if err := common.Unmarshal(body, &req); err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": "无效的请求"}) return } } reviewerId := c.GetInt("id") if err := model.ApproveDistributorApplication(id, reviewerId, req.DistributorCommissionBps); err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } if app, _, err := model.GetDistributorApplicationByIdAdmin(id); err == nil && app != nil { service.NotifyDistributorApplicationApproved(app.UserId) } c.JSON(http.StatusOK, gin.H{"success": true, "message": ""}) } // RejectDistributorApplicationAdmin 驳回 func RejectDistributorApplicationAdmin(c *gin.Context) { id, err := strconv.Atoi(c.Param("id")) if err != nil || id <= 0 { c.JSON(http.StatusOK, gin.H{"success": false, "message": "invalid id"}) return } var req rejectApplicationRequest if err := common.DecodeJson(c.Request.Body, &req); err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": "无效的请求"}) return } reviewerId := c.GetInt("id") app, _, errApp := model.GetDistributorApplicationByIdAdmin(id) if err := model.RejectDistributorApplication(id, reviewerId, req.Reason); err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } if errApp == nil && app != nil { service.NotifyDistributorApplicationRejected(app.UserId, req.Reason) } c.JSON(http.StatusOK, gin.H{"success": true, "message": ""}) } // ListDistributorsAdmin 分销商人员列表 func ListDistributorsAdmin(c *gin.Context) { pageInfo := common.GetPageQuery(c) keyword := c.Query("keyword") applyType, _ := strconv.Atoi(c.Query("apply_type")) rows, total, err := model.ListDistributorsAdmin(model.DistributorListAdminQuery{ Keyword: keyword, ApplyType: applyType, PageInfo: pageInfo, }) if err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } items := make([]gin.H, 0, len(rows)) for _, it := range rows { u := it.User bps := u.DistributorCommissionBps if bps <= 0 { bps = common.AffiliateDefaultCommissionBps } items = append(items, gin.H{ "id": u.Id, "username": u.Username, "display_name": u.DisplayName, "application_real_name": it.ApplicationRealName, "application_apply_type": it.ApplicationApplyType, "needs_supplement": it.NeedsSupplement, "aff_code": u.AffCode, "aff_count": u.AffCount, "aff_quota": u.AffQuota, "aff_history_quota": u.AffHistoryQuota, "distributor_commission_bps": u.DistributorCommissionBps, "effective_commission_bps": bps, }) } pageInfo.SetTotal(int(total)) pageInfo.SetItems(items) c.JSON(http.StatusOK, gin.H{"success": true, "message": "", "data": pageInfo}) } type putDistributorCommissionRequest struct { DistributorCommissionBps int `json:"distributor_commission_bps"` } // PutDistributorCommissionAdmin 设置单个分销商默认分成比例 func PutDistributorCommissionAdmin(c *gin.Context) { id, err := strconv.Atoi(c.Param("id")) if err != nil || id <= 0 { c.JSON(http.StatusOK, gin.H{"success": false, "message": "invalid id"}) return } var req putDistributorCommissionRequest if err := common.DecodeJson(c.Request.Body, &req); err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": "无效的请求"}) return } if err := model.SetUserDistributorCommissionBps(id, req.DistributorCommissionBps); err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"success": true, "message": ""}) } // GetDistributorInviteesAdmin 某分销商名下邀请用户明细 func GetDistributorInviteesAdmin(c *gin.Context) { id, err := strconv.Atoi(c.Param("id")) if err != nil || id <= 0 { c.JSON(http.StatusOK, gin.H{"success": false, "message": "invalid id"}) return } u, err := model.GetUserById(id, false) if err != nil || !model.UserIsDistributor(u) { c.JSON(http.StatusOK, gin.H{"success": false, "message": "用户不是分销商"}) return } pageInfo := common.GetPageQuery(c) keyword := strings.TrimSpace(c.Query("keyword")) if len(keyword) > 120 { keyword = keyword[:120] } items, total, err := model.ListAffInvitees(id, keyword, pageInfo) if err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } pageInfo.SetTotal(int(total)) pageInfo.SetItems(items) c.JSON(http.StatusOK, gin.H{"success": true, "message": "", "data": pageInfo}) } // GetDistributorInviteeProfitSharesAdmin 管理端查看某分销商下某一被邀请用户的利润分成消费流水(分页)。 func GetDistributorInviteeProfitSharesAdmin(c *gin.Context) { distributorId, err := strconv.Atoi(c.Param("id")) if err != nil || distributorId <= 0 { c.JSON(http.StatusOK, gin.H{"success": false, "message": "invalid distributor id"}) return } inviteeId, err := strconv.Atoi(c.Param("invitee_id")) if err != nil || inviteeId <= 0 { c.JSON(http.StatusOK, gin.H{"success": false, "message": "invalid invitee id"}) return } if !common.IsDistributorProfitShareMode() { c.JSON(http.StatusOK, gin.H{"success": false, "message": "当前站点未启用利润分成模式"}) return } dist, err := model.GetUserById(distributorId, false) if err != nil || !model.UserIsDistributor(dist) { c.JSON(http.StatusOK, gin.H{"success": false, "message": "用户不是分销商"}) return } invitee, err := model.GetUserById(inviteeId, false) if err != nil || invitee == nil || invitee.InviterId != distributorId { c.JSON(http.StatusOK, gin.H{"success": false, "message": "该用户不是此分销商邀请的下级"}) return } pageInfo := common.GetPageQuery(c) items, total, err := model.ListAffInviteProfitShareLogs(distributorId, inviteeId, pageInfo) if err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } pageInfo.SetTotal(int(total)) pageInfo.SetItems(items) c.JSON(http.StatusOK, gin.H{"success": true, "message": "", "data": pageInfo}) } // PostDistributorWithdrawal 提交线下提现申请(暂扣 aff_quota) func PostDistributorWithdrawal(c *gin.Context) { userId := c.GetInt("id") var req createDistributorWithdrawalRequest if err := common.DecodeJson(c.Request.Body, &req); err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": "无效的请求"}) return } accountType, _, err := model.GetDistributorWithdrawAccountType(userId) if err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } profileJSON, err := buildWithdrawalProfileJSON(req) if err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } quotaAmt := int(math.Round(req.QuotaAmount)) if err := model.CreateDistributorWithdrawal( userId, accountType, strings.TrimSpace(req.RealName), strings.TrimSpace(req.BankName), strings.TrimSpace(req.BankAccount), profileJSON, "[]", strings.TrimSpace(req.WithdrawMonth), quotaAmt, ); err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } service.NotifyDistributorWithdrawalSubmitted(userId, quotaAmt) c.JSON(http.StatusOK, gin.H{"success": true, "message": ""}) } // GetDistributorWithdrawals 当前用户提现记录 func GetDistributorWithdrawals(c *gin.Context) { userId := c.GetInt("id") pageInfo := common.GetPageQuery(c) rows, total, err := model.ListDistributorWithdrawals(userId, pageInfo) if err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } items := make([]gin.H, 0, len(rows)) for i := range rows { items = append(items, distributorWithdrawalToJSON(rows[i], "")) } pageInfo.SetTotal(int(total)) pageInfo.SetItems(items) c.JSON(http.StatusOK, gin.H{"success": true, "message": "", "data": pageInfo}) } // PostDistributorWithdrawalCancel 取消待审核提现,退回 aff_quota func PostDistributorWithdrawalCancel(c *gin.Context) { userId := c.GetInt("id") id, err := strconv.Atoi(c.Param("id")) if err != nil || id <= 0 { c.JSON(http.StatusOK, gin.H{"success": false, "message": "invalid id"}) return } if err := model.CancelDistributorWithdrawal(userId, id); err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"success": true, "message": ""}) } // ListDistributorWithdrawalsAdmin 管理端提现审核列表 func ListDistributorWithdrawalsAdmin(c *gin.Context) { pageInfo := common.GetPageQuery(c) status, _ := strconv.Atoi(c.Query("status")) accountType, _ := strconv.Atoi(c.Query("account_type")) keyword := c.Query("keyword") rows, total, err := model.ListDistributorWithdrawalsAdmin(status, accountType, keyword, pageInfo) if err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } items := make([]gin.H, 0, len(rows)) for i := range rows { items = append(items, distributorWithdrawalToJSON(rows[i].DistributorWithdrawal, rows[i].Username)) } pageInfo.SetTotal(int(total)) pageInfo.SetItems(items) c.JSON(http.StatusOK, gin.H{"success": true, "message": "", "data": pageInfo}) } // ApproveDistributorWithdrawalAdmin 审核通过 func ApproveDistributorWithdrawalAdmin(c *gin.Context) { id, err := strconv.Atoi(c.Param("id")) if err != nil || id <= 0 { c.JSON(http.StatusOK, gin.H{"success": false, "message": "invalid id"}) return } reviewerId := c.GetInt("id") var wUserId int if w, err := model.GetDistributorWithdrawalByID(id); err == nil && w != nil { wUserId = w.UserId } if err := model.ApproveDistributorWithdrawalAdmin(id, reviewerId); err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } if wUserId > 0 { service.NotifyDistributorWithdrawalApproved(wUserId) } c.JSON(http.StatusOK, gin.H{"success": true, "message": ""}) } type rejectWithdrawalRequest struct { Reason string `json:"reason"` } // RejectDistributorWithdrawalAdmin 驳回并退回 aff_quota func RejectDistributorWithdrawalAdmin(c *gin.Context) { id, err := strconv.Atoi(c.Param("id")) if err != nil || id <= 0 { c.JSON(http.StatusOK, gin.H{"success": false, "message": "invalid id"}) return } var req rejectWithdrawalRequest if err := common.DecodeJson(c.Request.Body, &req); err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": "无效的请求"}) return } reviewerId := c.GetInt("id") var wUserId int if w, err := model.GetDistributorWithdrawalByID(id); err == nil && w != nil { wUserId = w.UserId } if err := model.RejectDistributorWithdrawalAdmin(id, reviewerId, req.Reason); err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } if wUserId > 0 { service.NotifyDistributorWithdrawalRejected(wUserId, req.Reason) } c.JSON(http.StatusOK, gin.H{"success": true, "message": ""}) } // PostDistributorSettleAdmin 结账:清空该分销商待结算 aff_quota func PostDistributorSettleAdmin(c *gin.Context) { id, err := strconv.Atoi(c.Param("id")) if err != nil || id <= 0 { c.JSON(http.StatusOK, gin.H{"success": false, "message": "invalid id"}) return } if err := model.AdminSettleDistributorAffQuota(id); err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"success": true, "message": ""}) } type adminUpsertDistributorApplicationRequest struct { ApplyType int `json:"apply_type"` RealName string `json:"real_name"` IdCardNo string `json:"id_card_no"` QualificationUrls []string `json:"qualification_urls"` Contact string `json:"contact"` } // GetDistributorApplicationByUserAdmin 管理端:查看某分销商的申请/认证资料(手工开通可能无记录) func GetDistributorApplicationByUserAdmin(c *gin.Context) { userId, err := strconv.Atoi(c.Param("id")) if err != nil || userId <= 0 { c.JSON(http.StatusOK, gin.H{"success": false, "message": "invalid id"}) return } username, app, needsManualEntry, err := model.GetDistributorApplicationProfileByUserIdAdmin(userId) if err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } data := gin.H{ "user_id": userId, "username": username, "needs_manual_entry": needsManualEntry, } if app != nil { data["application"] = app } else { data["application"] = nil } c.JSON(http.StatusOK, gin.H{"success": true, "message": "", "data": data}) } // PutDistributorApplicationByUserAdmin 管理端:补录或修改分销商申请资料 func PutDistributorApplicationByUserAdmin(c *gin.Context) { userId, err := strconv.Atoi(c.Param("id")) if err != nil || userId <= 0 { c.JSON(http.StatusOK, gin.H{"success": false, "message": "invalid id"}) return } var req adminUpsertDistributorApplicationRequest if err := common.DecodeJson(c.Request.Body, &req); err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": "无效的请求"}) return } urls := make([]string, 0, len(req.QualificationUrls)) for _, u := range req.QualificationUrls { u = strings.TrimSpace(u) if u != "" { urls = append(urls, u) } } urlsJSON, err := common.Marshal(urls) if err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": "资料序列化失败"}) return } applyType := req.ApplyType if applyType == 0 { applyType = model.DistributorApplyTypePersonal } reviewerId := c.GetInt("id") if err := model.AdminUpsertDistributorApplicationByUser(userId, reviewerId, applyType, req.RealName, req.IdCardNo, string(urlsJSON), req.Contact); err != nil { c.JSON(http.StatusOK, gin.H{"success": false, "message": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"success": true, "message": ""}) }