Files
hfb_sys/backend/internal/modules/withdrawal/presenter.go
T

208 lines
6.5 KiB
Go

package withdrawal
import (
"context"
"encoding/json"
"net/url"
"strings"
"hfb_sys/backend/internal/model"
)
// 转换为用户DTO
func toDTO(w model.WithdrawalRequest) WithdrawalDTO {
return WithdrawalDTO{
ID: w.ID,
WithdrawNo: w.WithdrawNo,
UserID: w.UserID,
DistributionSiteID: w.DistributionSiteID,
AmountCent: w.AmountCent,
FeeCent: w.FeeCent,
ActualAmountCent: w.ActualAmountCent,
AccountType: w.AccountType,
AccountName: w.AccountName,
AccountNo: w.AccountNo,
BankName: w.BankName,
Status: w.Status,
ReviewRemark: w.ReviewRemark,
CreatedAt: w.CreatedAt,
UpdatedAt: w.UpdatedAt,
ReviewedAt: w.ReviewedAt,
PaidAt: w.PaidAt,
}
}
// toAdminListItems 批量装配提现分页列表依赖的用户和站点信息,避免每条记录分别查库。
func (r *Repository) toAdminListItems(ctx context.Context, withdrawals []model.WithdrawalRequest) ([]WithdrawalListItemDTO, error) {
items := make([]WithdrawalListItemDTO, 0, len(withdrawals))
if len(withdrawals) == 0 {
return items, nil
}
userIDs := make([]uint64, 0, len(withdrawals))
siteIDs := make([]uint64, 0, len(withdrawals))
seenUsers := make(map[uint64]struct{}, len(withdrawals))
seenSites := make(map[uint64]struct{}, len(withdrawals))
for _, withdrawal := range withdrawals {
if _, ok := seenUsers[withdrawal.UserID]; !ok {
seenUsers[withdrawal.UserID] = struct{}{}
userIDs = append(userIDs, withdrawal.UserID)
}
if withdrawal.DistributionSiteID > 0 {
if _, ok := seenSites[withdrawal.DistributionSiteID]; !ok {
seenSites[withdrawal.DistributionSiteID] = struct{}{}
siteIDs = append(siteIDs, withdrawal.DistributionSiteID)
}
}
}
usersByID := make(map[uint64]model.User, len(userIDs))
var users []model.User
if err := r.db.WithContext(ctx).Select("id, nickname, phone").Where("id IN ?", userIDs).Find(&users).Error; err != nil {
return nil, err
}
for _, user := range users {
usersByID[user.ID] = user
}
sitesByID := make(map[uint64]model.DistributionSite, len(siteIDs))
if len(siteIDs) > 0 {
var sites []model.DistributionSite
if err := r.db.WithContext(ctx).Select("id, site_name").Where("id IN ?", siteIDs).Find(&sites).Error; err != nil {
return nil, err
}
for _, site := range sites {
sitesByID[site.ID] = site
}
}
for _, withdrawal := range withdrawals {
user := usersByID[withdrawal.UserID]
site := sitesByID[withdrawal.DistributionSiteID]
items = append(items, WithdrawalListItemDTO{
ID: withdrawal.ID,
WithdrawNo: withdrawal.WithdrawNo,
UserID: withdrawal.UserID,
DistributionSiteID: withdrawal.DistributionSiteID,
DistributionSiteName: site.SiteName,
UserNickname: user.Nickname,
UserPhone: user.Phone,
AmountCent: withdrawal.AmountCent,
FeeCent: withdrawal.FeeCent,
ActualAmountCent: withdrawal.ActualAmountCent,
AccountType: withdrawal.AccountType,
AccountName: withdrawal.AccountName,
AccountNo: withdrawal.AccountNo,
BankName: withdrawal.BankName,
Status: withdrawal.Status,
CreatedAt: withdrawal.CreatedAt,
})
}
return items, nil
}
// 转换为管理员详细DTO
// 转换为管理员详细DTO
func (r *Repository) toDetailDTO(ctx context.Context, w model.WithdrawalRequest) (*WithdrawalDetailDTO, error) {
db := r.db.WithContext(ctx)
// 查询用户信息
var user model.User
db.Select("nickname, phone").First(&user, w.UserID)
// 查询审核人信息
var reviewedByName string
if w.ReviewedBy != nil {
var admin model.AdminUser
if err := db.Select("nickname").First(&admin, *w.ReviewedBy).Error; err == nil {
reviewedByName = admin.Nickname
}
}
// 查询打款人信息
var paidByName string
if w.PaidBy != nil {
var admin model.AdminUser
if err := db.Select("nickname").First(&admin, *w.PaidBy).Error; err == nil {
paidByName = admin.Nickname
}
}
// 获取完整账号和收款二维码(管理员可见)
fullAccountNo := w.AccountNo
var certificateURLs []string
if w.PaymentAccountID != nil {
var paymentAccount model.UserPaymentAccount
if err := db.First(&paymentAccount, *w.PaymentAccountID).Error; err == nil {
// 解密账号
decrypted, err := r.encryptor.Decrypt(paymentAccount.AccountNo)
if err == nil {
fullAccountNo = decrypted
}
// 解析收款二维码
if paymentAccount.CertificateURLs != nil {
json.Unmarshal(paymentAccount.CertificateURLs, &certificateURLs)
}
certificateURLs = privateCertificateURLs(certificateURLs)
}
}
var siteName, siteCode string
if w.DistributionSiteID > 0 {
var site model.DistributionSite
if err := db.Select("site_name, site_code").First(&site, w.DistributionSiteID).Error; err == nil {
siteName = site.SiteName
siteCode = site.SiteCode
}
}
return &WithdrawalDetailDTO{
ID: w.ID,
WithdrawNo: w.WithdrawNo,
UserID: w.UserID,
DistributionSiteID: w.DistributionSiteID,
DistributionSiteName: siteName,
DistributionSiteCode: siteCode,
UserNickname: user.Nickname,
UserPhone: user.Phone,
AmountCent: w.AmountCent,
FeeCent: w.FeeCent,
ActualAmountCent: w.ActualAmountCent,
PaymentAccountID: w.PaymentAccountID,
AccountType: w.AccountType,
AccountName: w.AccountName,
AccountNo: fullAccountNo,
BankName: w.BankName,
BankBranch: w.BankBranch,
CertificateURLs: certificateURLs,
Status: w.Status,
ReviewedBy: w.ReviewedBy,
ReviewedByName: reviewedByName,
ReviewedAt: w.ReviewedAt,
ReviewRemark: w.ReviewRemark,
PaidBy: w.PaidBy,
PaidByName: paidByName,
PaidAt: w.PaidAt,
PaymentProofURL: w.PaymentProofURL,
PaymentRemark: w.PaymentRemark,
CreatedAt: w.CreatedAt,
UpdatedAt: w.UpdatedAt,
}, nil
}
// privateCertificateURLs 兼容历史公开收款凭证 URL,统一经私有对象接口读取。
func privateCertificateURLs(values []string) []string {
for index, value := range values {
parsed, err := url.Parse(value)
if err != nil || parsed.Path != "/api/public/files/object" {
continue
}
if !strings.HasPrefix(parsed.Query().Get("key"), "payment-cert/") {
continue
}
parsed.Path = "/api/files/object"
values[index] = parsed.String()
}
return values
}