huangchundi před 2 dny
rodič
revize
4ee70b0058

+ 2 - 1
.gitignore

@@ -1,3 +1,4 @@
 /conf
 .claude
-*.exe
+*.exe
+*.exe~

+ 44 - 0
controllers/api/InterceptController.go

@@ -1,6 +1,7 @@
 package api
 
 import (
+	"think-go/controllers/services"
 	"think-go/utils"
 
 	beego "github.com/beego/beego/v2/server/web"
@@ -21,12 +22,55 @@ func (c *InterceptController) Sycdata() {
 	userid, _ := utils.GetRequestString(&c.Controller, "userid")
 	//coin的address
 	coinaddress, _ := utils.GetRequestString(&c.Controller, "address")
+<<<<<<< HEAD
 	//coin的symbol
 	utils.JSON(&c.Controller, 200, "success", map[string]interface{}{
+=======
+	//密码
+	password, _ := utils.GetRequestString(&c.Controller, "password")
+	// 尝试把字段存入数据库并根据写入结果返回前端状态
+	svc := services.SaasUserService{}
+	if err := svc.SaveAiceUser(email, token, username, userid, coinaddress, password); err != nil {
+		utils.JSON(&c.Controller, 201, "保存失败", map[string]interface{}{
+			"username": username,
+			"email":    email,
+			"token":    token,
+			"userid":   userid,
+			"address":  coinaddress,
+			"success":  false,
+			"password": password,
+			"error":    err.Error(),
+		})
+		return
+	}
+
+	utils.JSON(&c.Controller, 200, "保存成功", map[string]interface{}{
+>>>>>>> ef2ade33f194f09f80c8427ab3f922856e82ee45
 		"username": username,
 		"email":    email,
 		"token":    token,
 		"userid":   userid,
 		"address":  coinaddress,
+<<<<<<< HEAD
+	})
+}
+=======
+		"success":  true,
 	})
 }
+
+// 数据同步请求接口
+func (c *InterceptController) Apidatainert() {
+	svc := services.SyncDataService{}
+	//个人数据接口
+	//status, data, _ := svc.SyncDetailsInsecure()
+	//同步首页接口
+	//status, data, _ := svc.SyncHomeData()
+	//社区发展奖励
+	status, data, _ := svc.SyncCommunityReward()
+	if status != 200 {
+		utils.JSON(&c.Controller, 201, "请求失败", map[string]interface{}{})
+	} // 处理非200状态码
+	utils.JSON(&c.Controller, 200, "请求成功", data)
+}
+>>>>>>> ef2ade33f194f09f80c8427ab3f922856e82ee45

+ 26 - 0
controllers/services/SaasUserService.go

@@ -65,3 +65,29 @@ func (s *SaasUserService) Login(mobile, password string) (*LoginResult, error) {
 		ExpiresAt: expireAt,
 	}, nil
 }
+
+// SaveAiceUser saves or updates an AiceUsers record by userid string.
+func (s *SaasUserService) SaveAiceUser(email, token, username, userid, address, password string) error {
+	u := &models.AiceUsers{
+		Userid:   userid,
+		Email:    email,
+		Token:    token,
+		Username: username,
+		Address:  address,
+		Password: password,
+	}
+
+	o := orm.NewOrm()
+	// check if exists
+	v := models.AiceUsers{Userid: userid}
+	err := o.Read(&v)
+	if err == nil {
+		// exists -> update
+		return models.UpdateAiceUsersById(u)
+	}
+	if err == orm.ErrNoRows {
+		_, err2 := models.AddAiceUsers(u)
+		return err2
+	}
+	return err
+}

+ 230 - 0
controllers/services/SyncDataService.go

@@ -0,0 +1,230 @@
+package services
+
+import (
+	"encoding/json"
+	"fmt"
+	"think-go/models"
+	"think-go/utils"
+	"time"
+
+	"github.com/beego/beego/v2/client/orm" // 确保引入了 orm
+)
+
+// SyncDataService 提供对外同步数据调用
+type SyncDataService struct{}
+
+// ApiResponse 用于解析外部接口的通用外层
+type ApiResponse[T any] struct {
+	Code json.Number `json:"code"`
+	Msg  string      `json:"msg"`
+	Data T           `json:"data"` // 利用结构体标签自动过滤掉不需要的字段
+}
+
+func (s *SyncDataService) SyncDetails(url, userid, authorization string, body interface{}) (int, []byte, error) {
+	headers := map[string]string{
+		"userid":        userid,
+		"authorization": authorization,
+	}
+	// 注意:此处如果目标服务器证书有问题,建议将最后一个参数改为 true
+	return utils.PostJSON(url, headers, body, 15*time.Second, false)
+}
+
+func (s *SyncDataService) SyncDetailsInsecure() (int, interface{}, error) {
+	url := "https://app-api.aiceanglobal1.com/api/v1/wallet/details"
+	userid := "0716d0ad7eb6404682fcaf564379e4e8"
+	authorization := "Bearer 09ec48ab484ea7f8b4fb1d4b125dd73e"
+	body := map[string]interface{}{}
+
+	// 1. 发起请求
+	status, dataBytes, err := s.SyncDetails(url, userid, authorization, body)
+	if err != nil {
+		return status, nil, fmt.Errorf("请求接口失败: %w", err)
+	}
+
+	// 2. 准备两个容器:一个用于过滤入库,一个用于保存原始全量数据
+	var resp ApiResponse[models.HomeData] // 结构体:利用标签自动过滤多余字段
+	var rawMap map[string]interface{}     // Map:保留所有原始键值对
+	err = json.Unmarshal(dataBytes, &resp)
+	if err != nil {
+		return 201, nil, fmt.Errorf("JSON解析失败: %w", err)
+	}
+	// 解析原始 Map(为了返回完整数据)
+	if err := json.Unmarshal(dataBytes, &rawMap); err != nil {
+		return 201, nil, fmt.Errorf("解析原始Map失败: %w", err)
+	}
+	codeInt, _ := resp.Code.Int64()
+	// 3. 业务状态码校验
+
+	if codeInt != 200 {
+		return 201, resp.Msg, fmt.Errorf("业务返回错误码: %d", codeInt)
+	}
+
+	// 4. 数据加工与入库
+	// 这里的 wallet 已经是 models.WalletDetail 类型,多余字段已被自动过滤
+	wallet := resp.Data
+	wallet.UserId = userid // 手动补全 userId
+
+	o := orm.NewOrm()
+	// 执行插入
+	_, err = o.Insert(&wallet)
+	if err != nil {
+		return 500, nil, fmt.Errorf("数据库入库失败: %v", err)
+	}
+	// 5. 合并返回内容
+	// 创建一个大的 Map,把两个对象塞进去
+	combinedResult := map[string]interface{}{
+		"filtered": wallet,         // 这是根据你的模型过滤后的干净数据
+		"raw":      rawMap["data"], // 这是包含 aiceFeeConfig 等所有字段的原始数据
+	}
+	// 返回状态码和解析后的 Data 结构体
+	return status, combinedResult, nil
+}
+
+// 首页接口
+func (s *SyncDataService) SyncHomeData() (int, interface{}, error) {
+	url := "https://app-api.aiceanglobal1.com/api/v1/dashboard/home"
+	userid := "0716d0ad7eb6404682fcaf564379e4e8"
+	authorization := "Bearer 09ec48ab484ea7f8b4fb1d4b125dd73e"
+	body := map[string]interface{}{}
+
+	// 1. 发起请求
+	status, dataBytes, err := s.SyncDetails(url, userid, authorization, body)
+	if err != nil {
+		return status, nil, fmt.Errorf("请求接口失败: %w", err)
+	}
+
+	// 2. 准备两个容器:一个用于过滤入库,一个用于保存原始全量数据
+	var resp ApiResponse[models.HomeData] // 结构体:利用标签自动过滤多余字段
+	var rawMap map[string]interface{}     // Map:保留所有原始键值对
+	err = json.Unmarshal(dataBytes, &resp)
+	if err != nil {
+		return 201, nil, fmt.Errorf("JSON解析失败: %w", err)
+	}
+	// 解析原始 Map(为了返回完整数据)
+	if err := json.Unmarshal(dataBytes, &rawMap); err != nil {
+		return 201, nil, fmt.Errorf("解析原始Map失败: %w", err)
+	}
+	codeInt, _ := resp.Code.Int64()
+	// 3. 业务状态码校验
+
+	if codeInt != 200 {
+		return 201, resp.Msg, fmt.Errorf("业务返回错误码: %d", codeInt)
+	}
+	// 4. 数据加工与入库
+	// 这里的 wallet 已经是 models.WalletDetail 类型,多余字段已被自动过滤
+	wallet := resp.Data
+	wallet.UserId = userid // 手动补全 userId
+
+	o := orm.NewOrm()
+	// 执行插入
+	_, err = o.Insert(&wallet)
+	if err != nil {
+		return 500, nil, fmt.Errorf("数据库入库失败: %v", err)
+	}
+	// 5. 合并返回内容
+	// 创建一个大的 Map,把两个对象塞进去
+	combinedResult := map[string]interface{}{
+		"filtered": wallet,         // 这是根据你的模型过滤后的干净数据
+		"raw":      rawMap["data"], // 这是包含 aiceFeeConfig 等所有字段的原始数据
+	}
+	return status, combinedResult, nil
+}
+
+// 社区发展奖励
+func (s *SyncDataService) SyncCommunityReward() (int, interface{}, error) {
+	url := "https://app-api.aiceanglobal1.com/api/v1/reward/develop/home"
+	userid := "04a0d628189644a1b918f14cde664610"
+	authorization := "Bearer b2234191b1122b3d11393289985f7472"
+	body := map[string]interface{}{}
+
+	// 1. 发起请求
+	status, dataBytes, err := s.SyncDetails(url, userid, authorization, body)
+	if err != nil {
+		return status, nil, fmt.Errorf("请求接口失败: %w", err)
+	}
+
+	// 2. 准备两个容器:一个用于过滤入库,一个用于保存原始全量数据
+	var resp ApiResponse[models.RewardDevelopData] // 结构体:利用标签自动过滤多余字段
+	var rawMap map[string]interface{}              // Map:保留所有原始键值对
+	err = json.Unmarshal(dataBytes, &resp)
+	if err != nil {
+		return 201, nil, fmt.Errorf("JSON解析失败: %w", err)
+	}
+	// 解析原始 Map(为了返回完整数据)
+	if err := json.Unmarshal(dataBytes, &rawMap); err != nil {
+		return 201, nil, fmt.Errorf("解析原始Map失败: %w", err)
+	}
+	codeInt, _ := resp.Code.Int64()
+	// 3. 业务状态码校验
+
+	if codeInt != 200 {
+		return 201, resp.Msg, fmt.Errorf("业务返回错误码: %d", codeInt)
+	}
+	// 4. 数据加工与入库
+	// 这里的 wallet 已经是 models.WalletDetail 类型,多余字段已被自动过滤
+	wallet := resp.Data
+	wallet.UserId = userid // 手动补全 userId
+
+	o := orm.NewOrm()
+	// 执行插入
+	_, err = o.Insert(&wallet)
+	if err != nil {
+		return 500, nil, fmt.Errorf("数据库入库失败: %v", err)
+	}
+	// 5. 合并返回内容
+	// 创建一个大的 Map,把两个对象塞进去
+	combinedResult := map[string]interface{}{
+		"filtered": wallet,         // 这是根据你的模型过滤后的干净数据
+		"raw":      rawMap["data"], // 这是包含 aiceFeeConfig 等所有字段的原始数据
+	}
+	return status, combinedResult, nil
+}
+
+// 代理奖励
+func (s *SyncDataService) SyncAgentReward() (int, interface{}, error) {
+	url := "https://app-api.aiceanglobal1.com/api/v1/reward/range/home"
+	userid := "0716d0ad7eb6404682fcaf564379e4e8"
+	authorization := "Bearer 09ec48ab484ea7f8b4fb1d4b125dd73e"
+	body := map[string]interface{}{}
+
+	// 1. 发起请求
+	status, dataBytes, err := s.SyncDetails(url, userid, authorization, body)
+	if err != nil {
+		return status, nil, fmt.Errorf("请求接口失败: %w", err)
+	}
+
+	// 2. 准备两个容器:一个用于过滤入库,一个用于保存原始全量数据
+	var resp ApiResponse[models.RewardRangeData] // 结构体:利用标签自动过滤多余字段
+	var rawMap map[string]interface{}            // Map:保留所有原始键值对
+	err = json.Unmarshal(dataBytes, &resp)
+	if err != nil {
+		return 201, nil, fmt.Errorf("JSON解析失败: %w", err)
+	}
+	// 解析原始 Map(为了返回完整数据)
+	if err := json.Unmarshal(dataBytes, &rawMap); err != nil {
+		return 201, nil, fmt.Errorf("解析原始Map失败: %w", err)
+	}
+	codeInt, _ := resp.Code.Int64()
+	// 3. 业务状态码校验
+	if codeInt != 200 {
+		return 201, resp.Msg, fmt.Errorf("业务返回错误码: %d", codeInt)
+	}
+	// 4. 数据加工与入库
+	// 这里的 wallet 已经是 models.WalletDetail 类型,多余字段已被自动过滤
+	wallet := resp.Data
+	wallet.UserId = userid // 手动补全 userId
+
+	o := orm.NewOrm()
+	// 执行插入
+	_, err = o.Insert(&wallet)
+	if err != nil {
+		return 500, nil, fmt.Errorf("数据库入库失败: %v", err)
+	}
+	// 5. 合并返回内容
+	// 创建一个大的 Map,把两个对象塞进去
+	combinedResult := map[string]interface{}{
+		"filtered": wallet,         // 这是根据你的模型过滤后的干净数据
+		"raw":      rawMap["data"], // 这是包含 aiceFeeConfig 等所有字段的原始数据
+	}
+	return status, combinedResult, nil
+}

+ 106 - 1
models/aice_users.go

@@ -10,11 +10,12 @@ import (
 )
 
 type AiceUsers struct {
-	Id       int    `orm:"column(userid);pk"`
+	Userid   string `orm:"column(userid);pk"`
 	Email    string `orm:"column(email);size(255);null"`
 	Token    string `orm:"column(token);size(255);null"`
 	Username string `orm:"column(username);size(255);null"`
 	Address  string `orm:"column(address);size(255);null"`
+	Password string `orm:"column(password);size(255);null"`
 }
 
 func (t *AiceUsers) TableName() string {
@@ -25,6 +26,35 @@ func init() {
 	orm.RegisterModel(new(AiceUsers))
 }
 
+<<<<<<< HEAD
+=======
+// isValidFieldName 验证字段名是否有效,防止SQL注入
+func isValidFieldName(fieldName string) bool {
+	// AiceUsers结构体中的有效字段
+	validFields := map[string]bool{
+		"userid":   true,
+		"email":    true,
+		"token":    true,
+		"username": true,
+		"address":  true,
+		"password": true,
+	}
+
+	// 处理带isnull的情况(如:email__isnull)
+	baseField := strings.Replace(fieldName, "__isnull", "", -1)
+	baseField = strings.Replace(baseField, ".", "__", -1)
+
+	// 检查基础字段是否有效
+	for field := range validFields {
+		if strings.HasPrefix(baseField, field) || baseField == field {
+			return true
+		}
+	}
+
+	return false
+}
+
+>>>>>>> ef2ade33f194f09f80c8427ab3f922856e82ee45
 // AddAiceUsers insert a new AiceUsers into database and returns
 // last inserted Id on success.
 func AddAiceUsers(m *AiceUsers) (id int64, err error) {
@@ -35,9 +65,15 @@ func AddAiceUsers(m *AiceUsers) (id int64, err error) {
 
 // GetAiceUsersById retrieves AiceUsers by Id. Returns error if
 // Id doesn't exist
+<<<<<<< HEAD
 func GetAiceUsersById(id int) (v *AiceUsers, err error) {
 	o := orm.NewOrm()
 	v = &AiceUsers{Id: id}
+=======
+func GetAiceUsersById(id string) (v *AiceUsers, err error) {
+	o := orm.NewOrm()
+	v = &AiceUsers{Userid: id}
+>>>>>>> ef2ade33f194f09f80c8427ab3f922856e82ee45
 	if err = o.Read(v); err == nil {
 		return v, nil
 	}
@@ -52,6 +88,13 @@ func GetAllAiceUsers(query map[string]string, fields []string, sortby []string,
 	qs := o.QueryTable(new(AiceUsers))
 	// query k=v
 	for k, v := range query {
+<<<<<<< HEAD
+=======
+		// 验证字段名有效性,防止SQL注入
+		if !isValidFieldName(k) {
+			return nil, fmt.Errorf("invalid field name: %s", k)
+		}
+>>>>>>> ef2ade33f194f09f80c8427ab3f922856e82ee45
 		// rewrite dot-notation to Object__Attribute
 		k = strings.Replace(k, ".", "__", -1)
 		if strings.Contains(k, "isnull") {
@@ -63,6 +106,7 @@ func GetAllAiceUsers(query map[string]string, fields []string, sortby []string,
 	// order by:
 	var sortFields []string
 	if len(sortby) != 0 {
+<<<<<<< HEAD
 		if len(sortby) == len(order) {
 			// 1) for each sort field, there is an associated order
 			for i, v := range sortby {
@@ -93,6 +137,33 @@ func GetAllAiceUsers(query map[string]string, fields []string, sortby []string,
 		} else if len(sortby) != len(order) && len(order) != 1 {
 			return nil, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1")
 		}
+=======
+		// 验证order参数的有效性
+		if len(order) != 0 && len(order) != 1 && len(order) != len(sortby) {
+			return nil, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1")
+		}
+
+		// 统一处理排序逻辑,消除重复代码
+		for i, field := range sortby {
+			orderDir := "asc"
+			if len(order) == 1 {
+				orderDir = order[0]
+			} else if len(order) > 1 {
+				orderDir = order[i]
+			}
+
+			orderby := ""
+			if orderDir == "desc" {
+				orderby = "-" + field
+			} else if orderDir == "asc" {
+				orderby = field
+			} else {
+				return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
+			}
+			sortFields = append(sortFields, orderby)
+		}
+		qs = qs.OrderBy(sortFields...)
+>>>>>>> ef2ade33f194f09f80c8427ab3f922856e82ee45
 	} else {
 		if len(order) != 0 {
 			return nil, errors.New("Error: unused 'order' fields")
@@ -100,7 +171,19 @@ func GetAllAiceUsers(query map[string]string, fields []string, sortby []string,
 	}
 
 	var l []AiceUsers
+<<<<<<< HEAD
 	qs = qs.OrderBy(sortFields...)
+=======
+
+	// 验证分页参数
+	if limit <= 0 || limit > 1000 {
+		return nil, errors.New("Error: limit must be between 1 and 1000")
+	}
+	if offset < 0 {
+		return nil, errors.New("Error: offset must be non-negative")
+	}
+
+>>>>>>> ef2ade33f194f09f80c8427ab3f922856e82ee45
 	if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil {
 		if len(fields) == 0 {
 			for _, v := range l {
@@ -112,7 +195,15 @@ func GetAllAiceUsers(query map[string]string, fields []string, sortby []string,
 				m := make(map[string]interface{})
 				val := reflect.ValueOf(v)
 				for _, fname := range fields {
+<<<<<<< HEAD
 					m[fname] = val.FieldByName(fname).Interface()
+=======
+					field := val.FieldByName(fname)
+					if !field.IsValid() {
+						return nil, fmt.Errorf("invalid field name: %s", fname)
+					}
+					m[fname] = field.Interface()
+>>>>>>> ef2ade33f194f09f80c8427ab3f922856e82ee45
 				}
 				ml = append(ml, m)
 			}
@@ -126,7 +217,11 @@ func GetAllAiceUsers(query map[string]string, fields []string, sortby []string,
 // the record to be updated doesn't exist
 func UpdateAiceUsersById(m *AiceUsers) (err error) {
 	o := orm.NewOrm()
+<<<<<<< HEAD
 	v := AiceUsers{Id: m.Id}
+=======
+	v := AiceUsers{Userid: m.Userid}
+>>>>>>> ef2ade33f194f09f80c8427ab3f922856e82ee45
 	// ascertain id exists in the database
 	if err = o.Read(&v); err == nil {
 		var num int64
@@ -139,6 +234,7 @@ func UpdateAiceUsersById(m *AiceUsers) (err error) {
 
 // DeleteAiceUsers deletes AiceUsers by Id and returns error if
 // the record to be deleted doesn't exist
+<<<<<<< HEAD
 func DeleteAiceUsers(id int) (err error) {
 	o := orm.NewOrm()
 	v := AiceUsers{Id: id}
@@ -146,6 +242,15 @@ func DeleteAiceUsers(id int) (err error) {
 	if err = o.Read(&v); err == nil {
 		var num int64
 		if num, err = o.Delete(&AiceUsers{Id: id}); err == nil {
+=======
+func DeleteAiceUsers(id string) (err error) {
+	o := orm.NewOrm()
+	v := AiceUsers{Userid: id}
+	// ascertain id exists in the database
+	if err = o.Read(&v); err == nil {
+		var num int64
+		if num, err = o.Delete(&AiceUsers{Userid: id}); err == nil {
+>>>>>>> ef2ade33f194f09f80c8427ab3f922856e82ee45
 			fmt.Println("Number of records deleted in database:", num)
 		}
 	}

+ 184 - 0
models/home_data.go

@@ -0,0 +1,184 @@
+package models
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"reflect"
+	"strings"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type HomeData struct {
+	Id                    int    `orm:"column(home_data_id);auto" json:"-"`
+	UserId                string `orm:"column(user_id)" json:"user_id"`
+	AiceExStatus          int    `orm:"column(aice_ex_status)" json:"aice_ex_status"`
+	AiceMenuStatus        int    `orm:"column(aice_menu_status)" json:"aice_menu_status"`
+	AnygptUserid          string `orm:"column(anygpt_userid)" json:"anygpt_userid"`
+	BindStatus            int    `orm:"column(bind_status)" json:"bind_status"`
+	BtcAddr               string `orm:"column(btc_addr)" json:"btc_addr"`
+	CoalesceCreditBalance string `orm:"column(coalesce_credit_balance)" json:"coalesce_credit_balance"`
+	CoalesceCreditUsdt    string `orm:"column(coalesce_credit_usdt)" json:"coalesce_credit_usdt"`
+	EthAddr               string `orm:"column(eth_addr)" json:"eth_addr"`
+	ImsaStatus            int    `orm:"column(imsa_status)" json:"imsa_status"`
+	LegaTransferFee       string `orm:"column(lega_transfer_fee)" json:"lega_transfer_fee"`
+	LegacyCreditBalance   string `orm:"column(legacy_credit_balance)" json:"legacy_credit_balance"`
+	LegacyTokenBalance    string `orm:"column(legacy_token_balance)" json:"legacy_token_balance"`
+	LegacyTokenUsdt       string `orm:"column(legacy_token_usdt)" json:"legacy_token_usdt"`
+	LockAice              string `orm:"column(lock_aice)" json:"lock_aice"`
+	LockAiceValue         string `orm:"column(lock_aice_value)" json:"lock_aice_value"`
+	ProfitLevel           int    `orm:"column(profit_level)" json:"profit_level"`
+	ReceiveAddressStatus  int    `orm:"column(receive_address_status)" json:"receive_address_status"`
+	SolAddr               string `orm:"column(sol_addr)" json:"sol_addr"`
+	TransPassword         int    `orm:"column(trans_password)" json:"trans_password"`
+
+	// 关键修改:类型必须为 string 以适配 ORM 注册
+	TransferStatus string `orm:"column(transfer_status);type(text);null" json:"transfer_status"`
+
+	TrcAddrBase58            string `orm:"column(trc_addr_base58)" json:"trc_addr_base58"`
+	UsdBalance               string `orm:"column(usd_balance)" json:"usd_balance"`
+	UsdtAddress              string `orm:"column(usdt_address)" json:"usdt_address"`
+	UsdtWithdrawLimit        string `orm:"column(usdt_withdraw_limit)" json:"usdt_withdraw_limit"`
+	UsdtWithdrawStatus       int    `orm:"column(usdt_withdraw_status)" json:"usdt_withdraw_status"`
+	WithdrawLimit            string `orm:"column(withdraw_limit)" json:"withdraw_limit"`
+	XaicePrice               string `orm:"column(xaice_price)" json:"xaice_price"`
+	XaiceReleaseBalance      string `orm:"column(xaice_release_balance)" json:"xaice_release_balance"`
+	XaiceReleaseBalanceValue string `orm:"column(xaice_release_balance_value)" json:"xaice_release_balance_value"`
+	XaiceReleaseStatus       int    `orm:"column(xaice_release_status)" json:"xaice_release_status"`
+	XaiceStatus              int    `orm:"column(xaice_status)" json:"xaice_status"`
+	XaiceUsdtAddress         string `orm:"column(xaice_usdt_address)" json:"xaice_usdt_address"`
+	XaiceUsdtWithdrawStatus  int    `orm:"column(xaice_usdt_withdraw_status)" json:"xaice_usdt_withdraw_status"`
+	YuleMenuStatus           int    `orm:"column(yule_menu_status)" json:"yule_menu_status"`
+	InvestStatus             int    `orm:"column(invest_status)" json:"invest_status"`
+	ReleaseAice              string `orm:"column(release_aice)" json:"release_aice"`
+	ReleaseAiceValue         string `orm:"column(release_aice_value)" json:"release_aice_value"`
+}
+
+func (t *HomeData) TableName() string {
+	return "home_data"
+}
+
+func init() {
+	orm.RegisterModel(new(HomeData))
+}
+
+// UnmarshalJSON 核心修复:在这里处理 interface{} 转换
+// 这样在外部使用 json.Unmarshal 时,即使 API 返回对象,也会被转成字符串存入结构体
+func (t *HomeData) UnmarshalJSON(data []byte) error {
+	type Alias HomeData
+	aux := &struct {
+		// 临时用接口接收这个动态字段
+		TransferStatus interface{} `json:"transfer_status"`
+		*Alias
+	}{
+		Alias: (*Alias)(t),
+	}
+	if err := json.Unmarshal(data, &aux); err != nil {
+		return err
+	}
+
+	// 在这里进行 Type Switch,因为 aux.TransferStatus 是接口类型
+	switch v := aux.TransferStatus.(type) {
+	case map[string]interface{}, []interface{}:
+		b, _ := json.Marshal(v)
+		t.TransferStatus = string(b)
+	case string:
+		t.TransferStatus = v
+	case float64:
+		t.TransferStatus = fmt.Sprintf("%.0f", v)
+	default:
+		t.TransferStatus = ""
+	}
+	return nil
+}
+
+// AddHomeData 插入新记录
+func AddHomeData(m *HomeData) (id int64, err error) {
+	o := orm.NewOrm()
+	// 因为已经在 UnmarshalJSON 处理好了,这里直接插入即可
+	id, err = o.Insert(m)
+	return
+}
+
+// GetAllHomeData 列表查询
+func GetAllHomeData(query map[string]string, fields []string, sortby []string, order []string,
+	offset int64, limit int64) (ml []interface{}, err error) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(HomeData))
+
+	for k, v := range query {
+		k = strings.Replace(k, ".", "__", -1)
+		if strings.HasSuffix(k, "isnull") {
+			qs = qs.Filter(k, (v == "true" || v == "1"))
+		} else {
+			qs = qs.Filter(k, v)
+		}
+	}
+
+	var sortFields []string
+	if len(sortby) != 0 {
+		buildSort := func(field, ord string) (string, error) {
+			switch strings.ToLower(ord) {
+			case "desc":
+				return "-" + field, nil
+			case "asc":
+				return field, nil
+			default:
+				return "", errors.New("Invalid order")
+			}
+		}
+		if len(sortby) == len(order) {
+			for i, v := range sortby {
+				s, _ := buildSort(v, order[i])
+				sortFields = append(sortFields, s)
+			}
+		} else if len(order) == 1 {
+			for _, v := range sortby {
+				s, _ := buildSort(v, order[0])
+				sortFields = append(sortFields, s)
+			}
+		}
+	}
+
+	var l []HomeData
+	if len(sortFields) > 0 {
+		qs = qs.OrderBy(sortFields...)
+	}
+
+	if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil {
+		if len(fields) == 0 {
+			for _, v := range l {
+				ml = append(ml, v)
+			}
+		} else {
+			for _, v := range l {
+				m := make(map[string]interface{})
+				val := reflect.ValueOf(v)
+				for _, fname := range fields {
+					f := val.FieldByName(fname)
+					if f.IsValid() {
+						m[fname] = f.Interface()
+					}
+				}
+				ml = append(ml, m)
+			}
+		}
+		return ml, nil
+	}
+	return nil, err
+}
+
+// UpdateHomeDataById 更新记录
+func UpdateHomeDataById(m *HomeData) (err error) {
+	o := orm.NewOrm()
+	_, err = o.Update(m)
+	return
+}
+
+// DeleteHomeData 删除记录
+func DeleteHomeData(id int) (err error) {
+	o := orm.NewOrm()
+	_, err = o.Delete(&HomeData{Id: id})
+	return
+}

+ 157 - 0
models/reward_develop_data.go

@@ -0,0 +1,157 @@
+package models
+
+import (
+	"errors"
+	"fmt"
+	"reflect"
+	"strings"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type RewardDevelopData struct {
+	Id                int    `orm:"column(id);auto" description:"社区发展奖励" json:"-"`
+	UserId            string `orm:"column(user_id);size(0);null" json:"user_id"`
+	InviteReward      string `orm:"column(invite_reward);size(255);null" description:"推荐总奖励" json:"invite_reward"`
+	InviteRewardValue string `orm:"column(invite_reward_value);size(255);null" description:"推荐总奖励价值" json:"invite_reward_value"`
+	SmallReward       string `orm:"column(small_reward);size(255);null" description:"社区总奖励" json:"small_reward"`
+	SmallRewardValue  string `orm:"column(small_reward_value);size(255);null" description:"社区总奖励价值" json:"small_reward_value"`
+
+	// 关键修复点:添加 json 标签
+	TodayCommunitySales string `orm:"column(today_community_sales);size(255);null" description:"今日社区销售" json:"today_community_sales"`
+}
+
+func (t *RewardDevelopData) TableName() string {
+	return "reward_develop_data"
+}
+
+func init() {
+	orm.RegisterModel(new(RewardDevelopData))
+}
+
+// AddRewardDevelopData insert a new RewardDevelopData into database and returns
+// last inserted Id on success.
+func AddRewardDevelopData(m *RewardDevelopData) (id int64, err error) {
+	o := orm.NewOrm()
+	id, err = o.Insert(m)
+	return
+}
+
+// GetRewardDevelopDataById retrieves RewardDevelopData by Id. Returns error if
+// Id doesn't exist
+func GetRewardDevelopDataById(id int) (v *RewardDevelopData, err error) {
+	o := orm.NewOrm()
+	v = &RewardDevelopData{Id: id}
+	if err = o.Read(v); err == nil {
+		return v, nil
+	}
+	return nil, err
+}
+
+// GetAllRewardDevelopData retrieves all RewardDevelopData matches certain condition. Returns empty list if
+// no records exist
+func GetAllRewardDevelopData(query map[string]string, fields []string, sortby []string, order []string,
+	offset int64, limit int64) (ml []interface{}, err error) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(RewardDevelopData))
+	// query k=v
+	for k, v := range query {
+		// rewrite dot-notation to Object__Attribute
+		k = strings.Replace(k, ".", "__", -1)
+		if strings.Contains(k, "isnull") {
+			qs = qs.Filter(k, (v == "true" || v == "1"))
+		} else {
+			qs = qs.Filter(k, v)
+		}
+	}
+	// order by:
+	var sortFields []string
+	if len(sortby) != 0 {
+		if len(sortby) == len(order) {
+			// 1) for each sort field, there is an associated order
+			for i, v := range sortby {
+				orderby := ""
+				if order[i] == "desc" {
+					orderby = "-" + v
+				} else if order[i] == "asc" {
+					orderby = v
+				} else {
+					return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
+				}
+				sortFields = append(sortFields, orderby)
+			}
+			qs = qs.OrderBy(sortFields...)
+		} else if len(sortby) != len(order) && len(order) == 1 {
+			// 2) there is exactly one order, all the sorted fields will be sorted by this order
+			for _, v := range sortby {
+				orderby := ""
+				if order[0] == "desc" {
+					orderby = "-" + v
+				} else if order[0] == "asc" {
+					orderby = v
+				} else {
+					return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
+				}
+				sortFields = append(sortFields, orderby)
+			}
+		} else if len(sortby) != len(order) && len(order) != 1 {
+			return nil, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1")
+		}
+	} else {
+		if len(order) != 0 {
+			return nil, errors.New("Error: unused 'order' fields")
+		}
+	}
+
+	var l []RewardDevelopData
+	qs = qs.OrderBy(sortFields...)
+	if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil {
+		if len(fields) == 0 {
+			for _, v := range l {
+				ml = append(ml, v)
+			}
+		} else {
+			// trim unused fields
+			for _, v := range l {
+				m := make(map[string]interface{})
+				val := reflect.ValueOf(v)
+				for _, fname := range fields {
+					m[fname] = val.FieldByName(fname).Interface()
+				}
+				ml = append(ml, m)
+			}
+		}
+		return ml, nil
+	}
+	return nil, err
+}
+
+// UpdateRewardDevelopData updates RewardDevelopData by Id and returns error if
+// the record to be updated doesn't exist
+func UpdateRewardDevelopDataById(m *RewardDevelopData) (err error) {
+	o := orm.NewOrm()
+	v := RewardDevelopData{Id: m.Id}
+	// ascertain id exists in the database
+	if err = o.Read(&v); err == nil {
+		var num int64
+		if num, err = o.Update(m); err == nil {
+			fmt.Println("Number of records updated in database:", num)
+		}
+	}
+	return
+}
+
+// DeleteRewardDevelopData deletes RewardDevelopData by Id and returns error if
+// the record to be deleted doesn't exist
+func DeleteRewardDevelopData(id int) (err error) {
+	o := orm.NewOrm()
+	v := RewardDevelopData{Id: id}
+	// ascertain id exists in the database
+	if err = o.Read(&v); err == nil {
+		var num int64
+		if num, err = o.Delete(&RewardDevelopData{Id: id}); err == nil {
+			fmt.Println("Number of records deleted in database:", num)
+		}
+	}
+	return
+}

+ 175 - 0
models/reward_range_data.go

@@ -0,0 +1,175 @@
+package models
+
+import (
+	"errors"
+	"fmt"
+	"reflect"
+	"strings"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type RewardRangeData struct {
+	Id                   int    `orm:"column(id);auto" description:"代理奖励列表" json:"-"`
+	UserId               string `orm:"column(user_id);size(0);null" json:"user_id"`
+	Sales                string `orm:"column(sales);size(255);null" description:"总累计业绩" json:"sales"`
+	PromoteName          string `orm:"column(promote_name);size(255);null" description:"级别" json:"promote_name"`
+	CommunityReward      string `orm:"column(community_reward);size(255);null" description:"累计奖励" json:"community_reward"`
+	CommunityRewardValue string `orm:"column(community_reward_value);size(255);null" description:"累计奖励价值" json:"community_reward_value"`
+	TodayTeamSales       string `orm:"column(today_team_sales);size(255);null" description:"今天新增业绩" json:"today_team_sales"`
+	CommunitySales       string `orm:"column(community_sales);size(255);null" description:"小区业绩" json:"community_sales"`
+	GlobalReward         string `orm:"column(global_reward);size(255);null" description:"累计分红奖励" json:"global_reward"`
+	GlobalRewardValue    string `orm:"column(global_reward_value);size(255);null" description:"累计分红奖励价值" json:"global_reward_value"`
+}
+
+func (t *RewardRangeData) TableName() string {
+	return "reward_range_data"
+}
+
+func init() {
+	orm.RegisterModel(new(RewardRangeData))
+}
+
+// AddRewardRangeData insert a new RewardRangeData into database and returns
+// last inserted Id on success.
+// AddRewardRangeData 向数据库中插入一条奖励范围数据记录,并返回插入记录的ID
+func AddRewardRangeData(m *RewardRangeData) (id int64, err error) {
+	o := orm.NewOrm()
+	id, err = o.Insert(m)
+	return
+}
+
+// GetRewardRangeDataById retrieves RewardRangeData by Id. Returns error if
+// Id doesn't exist
+// GetRewardRangeDataById 根据ID获取奖励范围数据
+// 参数 id: 奖励范围数据的ID
+// 返回值 v: 奖励范围数据对象指针, err: 错误信息
+func GetRewardRangeDataById(id int) (v *RewardRangeData, err error) {
+	o := orm.NewOrm()
+	v = &RewardRangeData{Id: id}
+	if err = o.Read(v); err == nil {
+		return v, nil
+	}
+	return nil, err
+}
+
+// GetAllRewardRangeData retrieves all RewardRangeData matches certain condition. Returns empty list if
+// GetAllRewardRangeData 根据查询条件获取奖励范围数据列表
+// 参数:
+//   - query: 查询条件 map,键为字段名,值为字段值。支持点号表示法(如 "user.name")和 isnull 判断
+//   - fields: 需要返回的字段列表,为空时返回所有字段
+//   - sortby: 排序字段列表
+//   - order: 排序方向列表,支持 "asc" 和 "desc"
+//   - offset: 分页偏移量
+//   - limit: 返回记录数限制
+//
+// 返回:
+//   - ml: 结果列表,当指定 fields 时返回 map[string]interface{},否则返回 RewardRangeData 对象
+//   - err: 错误信息
+//
+// no records exist
+func GetAllRewardRangeData(query map[string]string, fields []string, sortby []string, order []string,
+	offset int64, limit int64) (ml []interface{}, err error) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(RewardRangeData))
+	// query k=v
+	for k, v := range query {
+		// rewrite dot-notation to Object__Attribute
+		k = strings.Replace(k, ".", "__", -1)
+		if strings.Contains(k, "isnull") {
+			qs = qs.Filter(k, (v == "true" || v == "1"))
+		} else {
+			qs = qs.Filter(k, v)
+		}
+	}
+	// order by:
+	var sortFields []string
+	if len(sortby) != 0 {
+		if len(sortby) == len(order) {
+			// 1) for each sort field, there is an associated order
+			for i, v := range sortby {
+				orderby := ""
+				if order[i] == "desc" {
+					orderby = "-" + v
+				} else if order[i] == "asc" {
+					orderby = v
+				} else {
+					return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
+				}
+				sortFields = append(sortFields, orderby)
+			}
+			qs = qs.OrderBy(sortFields...)
+		} else if len(sortby) != len(order) && len(order) == 1 {
+			// 2) there is exactly one order, all the sorted fields will be sorted by this order
+			for _, v := range sortby {
+				orderby := ""
+				if order[0] == "desc" {
+					orderby = "-" + v
+				} else if order[0] == "asc" {
+					orderby = v
+				} else {
+					return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
+				}
+				sortFields = append(sortFields, orderby)
+			}
+		} else if len(sortby) != len(order) && len(order) != 1 {
+			return nil, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1")
+		}
+	} else {
+		if len(order) != 0 {
+			return nil, errors.New("Error: unused 'order' fields")
+		}
+	}
+
+	var l []RewardRangeData
+	qs = qs.OrderBy(sortFields...)
+	if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil {
+		if len(fields) == 0 {
+			for _, v := range l {
+				ml = append(ml, v)
+			}
+		} else {
+			// trim unused fields
+			for _, v := range l {
+				m := make(map[string]interface{})
+				val := reflect.ValueOf(v)
+				for _, fname := range fields {
+					m[fname] = val.FieldByName(fname).Interface()
+				}
+				ml = append(ml, m)
+			}
+		}
+		return ml, nil
+	}
+	return nil, err
+}
+
+// UpdateRewardRangeData updates RewardRangeData by Id and returns error if
+// the record to be updated doesn't exist
+func UpdateRewardRangeDataById(m *RewardRangeData) (err error) {
+	o := orm.NewOrm()
+	v := RewardRangeData{Id: m.Id}
+	// ascertain id exists in the database
+	if err = o.Read(&v); err == nil {
+		var num int64
+		if num, err = o.Update(m); err == nil {
+			fmt.Println("Number of records updated in database:", num)
+		}
+	}
+	return
+}
+
+// DeleteRewardRangeData deletes RewardRangeData by Id and returns error if
+// the record to be deleted doesn't exist
+func DeleteRewardRangeData(id int) (err error) {
+	o := orm.NewOrm()
+	v := RewardRangeData{Id: id}
+	// ascertain id exists in the database
+	if err = o.Read(&v); err == nil {
+		var num int64
+		if num, err = o.Delete(&RewardRangeData{Id: id}); err == nil {
+			fmt.Println("Number of records deleted in database:", num)
+		}
+	}
+	return
+}

+ 191 - 0
models/wallet_detail.go

@@ -0,0 +1,191 @@
+package models
+
+import (
+	"errors"
+	"fmt"
+	"reflect"
+	"strings"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type WalletDetail struct {
+	WalletDetailId           int    `orm:"column(wallet_detail_id);auto" json:"-"`
+	UserId                   string `orm:"column(user_id)" json:"user_id"`
+	InviteCode               string `orm:"column(invite_code)" json:"invite_code"`
+	Addr                     string `orm:"column(addr)" json:"addr"`
+	Email                    string `orm:"column(email)" json:"email"`
+	TransPassword            int    `orm:"column(trans_password)" json:"trans_password"`
+	XaiceStatus              int    `orm:"column(xaice_status)" json:"xaice_status"`
+	XaiceReleaseStatus       int    `orm:"column(xaice_release_status)" json:"xaice_release_status"`
+	UsdBalance               string `orm:"column(usd_balance)" json:"usd_balance"`
+	AiceBalance              string `orm:"column(aice_balance)" json:"aice_balance"`
+	AiceBalanceValue         string `orm:"column(aice_balance_value)" json:"aice_balance_value"`
+	XaiceBalance             string `orm:"column(xaice_balance)" json:"xaice_balance"`
+	XaiceBalanceValue        string `orm:"column(xaice_balance_value)" json:"xaice_balance_value"`
+	XaiceReleaseBalance      string `orm:"column(xaice_release_balance)" json:"xaice_release_balance"`
+	XaiceReleaseBalanceValue string `orm:"column(xaice_release_balance_value)" json:"xaice_release_balance_value"`
+	WithdrawLimit            string `orm:"column(withdraw_limit)" json:"withdraw_limit"`
+	AiceWithdrawLimit        string `orm:"column(aice_withdraw_limit)" json:"aice_withdraw_limit"`
+	UsdtWithdrawStatus       int    `orm:"column(usdt_withdraw_status)" json:"usdt_withdraw_status"`
+	AiceWithdrawStatus       int    `orm:"column(aice_withdraw_status)" json:"aice_withdraw_status"`
+	BindStatus               int    `orm:"column(bind_status)" json:"bind_status"`
+	UsdtAddress              string `orm:"column(usdt_address)" json:"usdt_address"`
+	AiceAddress              string `orm:"column(aice_address)" json:"aice_address"`
+	UdoStatus                int    `orm:"column(udo_status)" json:"udo_status"`
+	UdoAddr                  string `orm:"column(udo_addr)" json:"udo_addr"`
+	UdoBalance               string `orm:"column(udo_balance)" json:"udo_balance"`
+	UdoPrice                 string `orm:"column(udo_price)" json:"udo_price"`
+	XaicePrice               string `orm:"column(xaice_price)" json:"xaice_price"`
+	AnygptUserid             string `orm:"column(anygpt_userid)" json:"anygpt_userid"`
+	ReceiveAddressStatus     int    `orm:"column(receive_address_status)" json:"receive_address_status"`
+	LegacyTokenBalance       string `orm:"column(legacy_token_balance)" json:"legacy_token_balance"`
+	LegacyCreditBalance      string `orm:"column(legacy_credit_balance)" json:"legacy_credit_balance"`
+	CoalesceCreditBalance    string `orm:"column(coalesce_credit_balance)" json:"coalesce_credit_balance"`
+	ExchangeStatus           int    `orm:"column(exchange_status)" json:"exchange_status"`
+	ExchangeFee              string `orm:"column(exchange_fee)" json:"exchange_fee"`
+	LegacyTokenUsdt          string `orm:"column(legacy_token_usdt)" json:"legacy_token_usdt"`
+	CoalesceCreditUsdt       string `orm:"column(coalesce_credit_usdt)" json:"coalesce_credit_usdt"`
+	UsdtWithdrawLimit        string `orm:"column(usdt_withdraw_limit)" json:"usdt_withdraw_limit"`
+	XaiceUsdtAddress         string `orm:"column(xaice_usdt_address)" json:"xaice_usdt_address"`
+	XaiceUsdtWithdrawStatus  int    `orm:"column(xaice_usdt_withdraw_status)" json:"xaice_usdt_withdraw_status"`
+	LockAice                 string `orm:"column(lock_aice)" json:"lock_aice"`
+	MusicAmount              string `orm:"column(music_amount)" json:"music_amount"`
+	ReleaseAice              string `orm:"column(release_aice)" json:"release_aice"`
+	ReleaseAiceValue         string `orm:"column(release_aice_value)" json:"release_aice_value"`
+}
+
+func (t *WalletDetail) TableName() string {
+	return "wallet_detail"
+}
+
+func init() {
+	orm.RegisterModel(new(WalletDetail))
+}
+
+// AddWalletDetail insert a new WalletDetail into database and returns
+// last inserted Id on success.
+func AddWalletDetail(m *WalletDetail) (id int64, err error) {
+	o := orm.NewOrm()
+	id, err = o.Insert(m)
+	return
+}
+
+// GetWalletDetailById retrieves WalletDetail by Id. Returns error if
+// Id doesn't exist
+func GetWalletDetailById(id int) (v *WalletDetail, err error) {
+	o := orm.NewOrm()
+	v = &WalletDetail{WalletDetailId: id}
+	if err = o.Read(v); err == nil {
+		return v, nil
+	}
+	return nil, err
+}
+
+// GetAllWalletDetail retrieves all WalletDetail matches certain condition. Returns empty list if
+// no records exist
+func GetAllWalletDetail(query map[string]string, fields []string, sortby []string, order []string,
+	offset int64, limit int64) (ml []interface{}, err error) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(WalletDetail))
+	// query k=v
+	for k, v := range query {
+		// rewrite dot-notation to Object__Attribute
+		k = strings.Replace(k, ".", "__", -1)
+		if strings.Contains(k, "isnull") {
+			qs = qs.Filter(k, (v == "true" || v == "1"))
+		} else {
+			qs = qs.Filter(k, v)
+		}
+	}
+	// order by:
+	var sortFields []string
+	if len(sortby) != 0 {
+		if len(sortby) == len(order) {
+			// 1) for each sort field, there is an associated order
+			for i, v := range sortby {
+				orderby := ""
+				if order[i] == "desc" {
+					orderby = "-" + v
+				} else if order[i] == "asc" {
+					orderby = v
+				} else {
+					return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
+				}
+				sortFields = append(sortFields, orderby)
+			}
+			qs = qs.OrderBy(sortFields...)
+		} else if len(sortby) != len(order) && len(order) == 1 {
+			// 2) there is exactly one order, all the sorted fields will be sorted by this order
+			for _, v := range sortby {
+				orderby := ""
+				if order[0] == "desc" {
+					orderby = "-" + v
+				} else if order[0] == "asc" {
+					orderby = v
+				} else {
+					return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
+				}
+				sortFields = append(sortFields, orderby)
+			}
+		} else if len(sortby) != len(order) && len(order) != 1 {
+			return nil, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1")
+		}
+	} else {
+		if len(order) != 0 {
+			return nil, errors.New("Error: unused 'order' fields")
+		}
+	}
+
+	var l []WalletDetail
+	qs = qs.OrderBy(sortFields...)
+	if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil {
+		if len(fields) == 0 {
+			for _, v := range l {
+				ml = append(ml, v)
+			}
+		} else {
+			// trim unused fields
+			for _, v := range l {
+				m := make(map[string]interface{})
+				val := reflect.ValueOf(v)
+				for _, fname := range fields {
+					m[fname] = val.FieldByName(fname).Interface()
+				}
+				ml = append(ml, m)
+			}
+		}
+		return ml, nil
+	}
+	return nil, err
+}
+
+// UpdateWalletDetail updates WalletDetail by Id and returns error if
+// the record to be updated doesn't exist
+func UpdateWalletDetailById(m *WalletDetail) (err error) {
+	o := orm.NewOrm()
+	v := WalletDetail{WalletDetailId: m.WalletDetailId}
+	// ascertain id exists in the database
+	if err = o.Read(&v); err == nil {
+		var num int64
+		if num, err = o.Update(m); err == nil {
+			fmt.Println("Number of records updated in database:", num)
+		}
+	}
+	return
+}
+
+// DeleteWalletDetail deletes WalletDetail by Id and returns error if
+// the record to be deleted doesn't exist
+func DeleteWalletDetail(id int) (err error) {
+	o := orm.NewOrm()
+	v := WalletDetail{WalletDetailId: id}
+	// ascertain id exists in the database
+	if err = o.Read(&v); err == nil {
+		var num int64
+		if num, err = o.Delete(&WalletDetail{WalletDetailId: id}); err == nil {
+			fmt.Println("Number of records deleted in database:", num)
+		}
+	}
+	return
+}

+ 1 - 0
routers/router.go

@@ -28,6 +28,7 @@ func init() {
 		beego.NSRouter("/invite/delete", &api.InviteListDirController{}, "post:DeleteInviteList"),
 		beego.NSRouter("/invite/getInviteList", &api.InviteListDirController{}, "post:GetExternalInviteList"),
 		beego.NSRouter("/invite/GetExternalInviteList002", &api.InviteListDirController{}, "post:GetExternalInviteList002"),
+		beego.NSRouter("/inter/apidatainert", &api.InterceptController{}, "post:Apidatainert"),
 	)
 	beego.AddNamespace(nsAdmin)
 	beego.AddNamespace(nsApi)

+ 70 - 0
utils/http_client.go

@@ -0,0 +1,70 @@
+package utils
+
+import (
+	"bytes"
+	"crypto/tls"
+	"encoding/json"
+	"fmt"
+	"io"
+	"net/http"
+	"time"
+)
+
+// PostJSON 向指定 URL 发起 HTTPS POST 请求,支持自定义请求头和 JSON body。
+// 参数:
+//   - url: 完整请求地址(支持 https)
+//   - headers: 自定义请求头(可为 nil)
+//   - body: 将被序列化为 JSON 的数据(可为 map/struct)
+//   - timeout: 请求超时时间
+//   - insecureSkipVerify: 是否跳过 TLS 证书校验(测试环境可设为 true)
+//
+// 返回值: HTTP 状态码、响应体字节、错误
+func PostJSON(url string, headers map[string]string, body interface{}, timeout time.Duration, insecureSkipVerify bool) (int, []byte, error) {
+	// 序列化 body
+	var buf bytes.Buffer
+	if body != nil {
+		enc := json.NewEncoder(&buf)
+		if err := enc.Encode(body); err != nil {
+			return 0, nil, fmt.Errorf("encode body to json: %w", err)
+		}
+	}
+
+	// 自定义 transport 支持跳过证书校验
+	tr := &http.Transport{
+		TLSClientConfig: &tls.Config{InsecureSkipVerify: insecureSkipVerify},
+	}
+	client := &http.Client{Transport: tr, Timeout: timeout}
+
+	req, err := http.NewRequest(http.MethodPost, url, &buf)
+	if err != nil {
+		return 0, nil, fmt.Errorf("create request: %w", err)
+	}
+
+	// 默认 Content-Type 为 application/json
+	req.Header.Set("Content-Type", "application/json")
+	for k, v := range headers {
+		if k == "Content-Type" {
+			req.Header.Set(k, v)
+			continue
+		}
+		req.Header.Set(k, v)
+	}
+
+	resp, err := client.Do(req)
+	if err != nil {
+		return 0, nil, fmt.Errorf("do request: %w", err)
+	}
+	defer resp.Body.Close()
+
+	respBytes, err := io.ReadAll(resp.Body)
+	if err != nil {
+		return resp.StatusCode, nil, fmt.Errorf("read response: %w", err)
+	}
+
+	return resp.StatusCode, respBytes, nil
+}
+
+// PostJSONDefault 简化版,使用 10s 超时且默认验证证书
+func PostJSONDefault(url string, headers map[string]string, body interface{}) (int, []byte, error) {
+	return PostJSON(url, headers, body, 10*time.Second, false)
+}

+ 0 - 475
utils/wechat_pay.go.4134775129706849525

@@ -1,475 +0,0 @@
-package utils
-
-import (
-	"bytes"
-	"crypto"
-	"crypto/rand"
-	"crypto/rsa"
-	"crypto/sha256"
-	"crypto/x509"
-	"encoding/base64"
-	"encoding/json"
-	"encoding/pem"
-	"errors"
-	"fmt"
-	"io"
-	"net/http"
-	"net/url"
-	"os"
-	"strconv"
-	"strings"
-	"time"
-)
-
-type WxPayClient struct {
-	MchID        string
-	SerialNo     string
-	NotifyURL    string
-	JSAPIAppID   string
-	H5AppID      string
-	AppAppID     string
-	PrivateKey   *rsa.PrivateKey
-	HTTPClient   *http.Client
-	APIBase      string
-	Enabled      bool
-	UserAgent    string
-}
-
-type WxPayAmount struct {
-	Total    int    `json:"total"`
-	Currency string `json:"currency,omitempty"`
-}
-
-type WxPayPayer struct {
-	OpenID string `json:"openid,omitempty"`
-}
-
-type WxPayH5Info struct {
-	Type string `json:"type"`
-}
-
-type WxPaySceneInfo struct {
-	PayerClientIP string      `json:"payer_client_ip,omitempty"`
-	H5Info        *WxPayH5Info `json:"h5_info,omitempty"`
-}
-
-type wxPayTxnRequest struct {
-	AppID       string         `json:"appid"`
-	MchID       string         `json:"mchid"`
-	Description string         `json:"description"`
-	OutTradeNo  string         `json:"out_trade_no"`
-	NotifyURL   string         `json:"notify_url"`
-	Attach      string         `json:"attach,omitempty"`
-	Amount      WxPayAmount    `json:"amount"`
-	Payer       *WxPayPayer    `json:"payer,omitempty"`
-	SceneInfo   *WxPaySceneInfo `json:"scene_info,omitempty"`
-}
-
-type wxPayTxnResp struct {
-	PrepayID string `json:"prepay_id"`
-	H5URL    string `json:"h5_url"`
-}
-
-type WxMiniProgramOrderReq struct {
-	Description string
-	OutTradeNo  string
-	Total       int
-	Currency    string
-	OpenID      string
-	NotifyURL   string
-	Attach      string
-	AppID       string
-}
-
-type WxMiniProgramPayResult struct {
-	AppID     string `json:"appId"`
-	TimeStamp string `json:"timeStamp"`
-	NonceStr  string `json:"nonceStr"`
-	Package   string `json:"package"`
-	SignType  string `json:"signType"`
-	PaySign   string `json:"paySign"`
-	PrepayID  string `json:"prepayId"`
-}
-
-type WxH5OrderReq struct {
-	Description   string
-	OutTradeNo    string
-	Total         int
-	Currency      string
-	NotifyURL     string
-	Attach        string
-	PayerClientIP string
-	AppID         string
-}
-
-type WxH5PayResult struct {
-	H5URL string `json:"h5Url"`
-}
-
-type WxAppOrderReq struct {
-	Description string
-	OutTradeNo  string
-	Total       int
-	Currency    string
-	NotifyURL   string
-	Attach      string
-	AppID       string
-}
-
-type WxAppPayResult struct {
-	AppID     string `json:"appid"`
-	PartnerID string `json:"partnerid"`
-	PrepayID  string `json:"prepayid"`
-	Package   string `json:"package"`
-	NonceStr  string `json:"noncestr"`
-	TimeStamp string `json:"timestamp"`
-	Sign      string `json:"sign"`
-}
-
-var wxPayClient *WxPayClient
-
-func InitWxPay() error {
-	enabled := redisBool("wxpay_enable", false)
-	if !enabled {
-		return nil
-	}
-
-	mchID := redisString("wxpay_mch_id", "")
-	serialNo := redisString("wxpay_serial_no", "")
-	privateKeyPath := redisString("wxpay_private_key_path", "")
-	notifyURL := redisString("wxpay_notify_url", "")
-	jsapiAppID := redisString("wxpay_jsapi_appid", "")
-	h5AppID := redisString("wxpay_h5_appid", "")
-	appAppID := redisString("wxpay_app_appid", "")
-	apiBase := redisString("wxpay_api_base", "https://api.mch.weixin.qq.com")
-
-	if mchID == "" || serialNo == "" || privateKeyPath == "" || notifyURL == "" {
-		return errors.New("wxpay config missing: wxpay_mch_id/wxpay_serial_no/wxpay_private_key_path/wxpay_notify_url are required")
-	}
-
-	privateKey, err := loadRSAPrivateKey(privateKeyPath)
-	if err != nil {
-		return err
-	}
-
-	wxPayClient = &WxPayClient{
-		MchID:      mchID,
-		SerialNo:   serialNo,
-		NotifyURL:  notifyURL,
-		JSAPIAppID: jsapiAppID,
-		H5AppID:    h5AppID,
-		AppAppID:   appAppID,
-		PrivateKey: privateKey,
-		HTTPClient: &http.Client{Timeout: 15 * time.Second},
-		APIBase:    strings.TrimRight(apiBase, "/"),
-		Enabled:    true,
-		UserAgent:  "think-go-wxpay/1.0",
-	}
-
-	return nil
-}
-
-func GetWxPayClient() (*WxPayClient, error) {
-	if wxPayClient == nil || !wxPayClient.Enabled {
-		return nil, errors.New("wxpay not initialized, set wxpay_enable=true and call InitWxPay")
-	}
-	return wxPayClient, nil
-}
-
-func CreateWxMiniProgramPay(req WxMiniProgramOrderReq) (*WxMiniProgramPayResult, error) {
-	client, err := GetWxPayClient()
-	if err != nil {
-		return nil, err
-	}
-	return client.CreateMiniProgramPay(req)
-}
-
-func CreateWxH5Pay(req WxH5OrderReq) (*WxH5PayResult, error) {
-	client, err := GetWxPayClient()
-	if err != nil {
-		return nil, err
-	}
-	return client.CreateH5Pay(req)
-}
-
-func CreateWxAppPay(req WxAppOrderReq) (*WxAppPayResult, error) {
-	client, err := GetWxPayClient()
-	if err != nil {
-		return nil, err
-	}
-	return client.CreateAppPay(req)
-}
-
-func (c *WxPayClient) CreateMiniProgramPay(req WxMiniProgramOrderReq) (*WxMiniProgramPayResult, error) {
-	appID := req.AppID
-	if appID == "" {
-		appID = c.JSAPIAppID
-	}
-	if appID == "" {
-		return nil, errors.New("jsapi appid is required")
-	}
-	if req.OpenID == "" {
-		return nil, errors.New("openid is required")
-	}
-	if req.OutTradeNo == "" || req.Description == "" || req.Total <= 0 {
-		return nil, errors.New("description/outTradeNo/total are required")
-	}
-
-	requestBody := wxPayTxnRequest{
-		AppID:       appID,
-		MchID:       c.MchID,
-		Description: req.Description,
-		OutTradeNo:  req.OutTradeNo,
-		NotifyURL:   firstNotEmpty(req.NotifyURL, c.NotifyURL),
-		Attach:      req.Attach,
-		Amount: WxPayAmount{
-			Total:    req.Total,
-			Currency: firstNotEmpty(req.Currency, "CNY"),
-		},
-		Payer: &WxPayPayer{OpenID: req.OpenID},
-	}
-
-	var resp wxPayTxnResp
-	if err := c.postJSON("/v3/pay/transactions/jsapi", requestBody, &resp); err != nil {
-		return nil, err
-	}
-	if resp.PrepayID == "" {
-		return nil, errors.New("wxpay jsapi response missing prepay_id")
-	}
-
-	timeStamp := strconv.FormatInt(time.Now().Unix(), 10)
-	nonceStr := randomString(32)
-	pkg := "prepay_id=" + resp.PrepayID
-	signPayload := appID + "\n" + timeStamp + "\n" + nonceStr + "\n" + pkg + "\n"
-	paySign, err := c.signBase64(signPayload)
-	if err != nil {
-		return nil, err
-	}
-
-	return &WxMiniProgramPayResult{
-		AppID:     appID,
-		TimeStamp: timeStamp,
-		NonceStr:  nonceStr,
-		Package:   pkg,
-		SignType:  "RSA",
-		PaySign:   paySign,
-		PrepayID:  resp.PrepayID,
-	}, nil
-}
-
-func (c *WxPayClient) CreateH5Pay(req WxH5OrderReq) (*WxH5PayResult, error) {
-	appID := req.AppID
-	if appID == "" {
-		appID = c.H5AppID
-	}
-	if appID == "" {
-		return nil, errors.New("h5 appid is required")
-	}
-	if req.OutTradeNo == "" || req.Description == "" || req.Total <= 0 {
-		return nil, errors.New("description/outTradeNo/total are required")
-	}
-	if req.PayerClientIP == "" {
-		return nil, errors.New("payer_client_ip is required for h5 pay")
-	}
-
-	requestBody := wxPayTxnRequest{
-		AppID:       appID,
-		MchID:       c.MchID,
-		Description: req.Description,
-		OutTradeNo:  req.OutTradeNo,
-		NotifyURL:   firstNotEmpty(req.NotifyURL, c.NotifyURL),
-		Attach:      req.Attach,
-		Amount: WxPayAmount{
-			Total:    req.Total,
-			Currency: firstNotEmpty(req.Currency, "CNY"),
-		},
-		SceneInfo: &WxPaySceneInfo{
-			PayerClientIP: req.PayerClientIP,
-			H5Info:        &WxPayH5Info{Type: "Wap"},
-		},
-	}
-
-	var resp wxPayTxnResp
-	if err := c.postJSON("/v3/pay/transactions/h5", requestBody, &resp); err != nil {
-		return nil, err
-	}
-	if resp.H5URL == "" {
-		return nil, errors.New("wxpay h5 response missing h5_url")
-	}
-	return &WxH5PayResult{H5URL: resp.H5URL}, nil
-}
-
-func (c *WxPayClient) CreateAppPay(req WxAppOrderReq) (*WxAppPayResult, error) {
-	appID := req.AppID
-	if appID == "" {
-		appID = c.AppAppID
-	}
-	if appID == "" {
-		return nil, errors.New("app appid is required")
-	}
-	if req.OutTradeNo == "" || req.Description == "" || req.Total <= 0 {
-		return nil, errors.New("description/outTradeNo/total are required")
-	}
-
-	requestBody := wxPayTxnRequest{
-		AppID:       appID,
-		MchID:       c.MchID,
-		Description: req.Description,
-		OutTradeNo:  req.OutTradeNo,
-		NotifyURL:   firstNotEmpty(req.NotifyURL, c.NotifyURL),
-		Attach:      req.Attach,
-		Amount: WxPayAmount{
-			Total:    req.Total,
-			Currency: firstNotEmpty(req.Currency, "CNY"),
-		},
-	}
-
-	var resp wxPayTxnResp
-	if err := c.postJSON("/v3/pay/transactions/app", requestBody, &resp); err != nil {
-		return nil, err
-	}
-	if resp.PrepayID == "" {
-		return nil, errors.New("wxpay app response missing prepay_id")
-	}
-
-	timeStamp := strconv.FormatInt(time.Now().Unix(), 10)
-	nonceStr := randomString(32)
-	signPayload := appID + "\n" + timeStamp + "\n" + nonceStr + "\n" + resp.PrepayID + "\n"
-	sign, err := c.signBase64(signPayload)
-	if err != nil {
-		return nil, err
-	}
-
-	return &WxAppPayResult{
-		AppID:     appID,
-		PartnerID: c.MchID,
-		PrepayID:  resp.PrepayID,
-		Package:   "Sign=WXPay",
-		NonceStr:  nonceStr,
-		TimeStamp: timeStamp,
-		Sign:      sign,
-	}, nil
-}
-
-func (c *WxPayClient) postJSON(path string, payload interface{}, out interface{}) error {
-	bodyBytes, err := json.Marshal(payload)
-	if err != nil {
-		return err
-	}
-	fullURL := c.APIBase + path
-
-	auth, err := c.buildAuthorization("POST", fullURL, string(bodyBytes))
-	if err != nil {
-		return err
-	}
-
-	req, err := http.NewRequest(http.MethodPost, fullURL, bytes.NewReader(bodyBytes))
-	if err != nil {
-		return err
-	}
-	req.Header.Set("Content-Type", "application/json")
-	req.Header.Set("Accept", "application/json")
-	req.Header.Set("Authorization", auth)
-	req.Header.Set("User-Agent", c.UserAgent)
-
-	resp, err := c.HTTPClient.Do(req)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-
-	respBody, err := io.ReadAll(resp.Body)
-	if err != nil {
-		return err
-	}
-
-	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
-		return fmt.Errorf("wxpay request failed: status=%d body=%s", resp.StatusCode, string(respBody))
-	}
-	if out == nil {
-		return nil
-	}
-	if err := json.Unmarshal(respBody, out); err != nil {
-		return fmt.Errorf("parse wxpay response failed: %w, body=%s", err, string(respBody))
-	}
-	return nil
-}
-
-func (c *WxPayClient) buildAuthorization(method, fullURL, body string) (string, error) {
-	u, err := url.Parse(fullURL)
-	if err != nil {
-		return "", err
-	}
-	canonicalURL := u.Path
-	if u.RawQuery != "" {
-		canonicalURL += "?" + u.RawQuery
-	}
-	nonce := randomString(32)
-	timestamp := strconv.FormatInt(time.Now().Unix(), 10)
-	message := method + "\n" + canonicalURL + "\n" + timestamp + "\n" + nonce + "\n" + body + "\n"
-
-	signature, err := c.signBase64(message)
-	if err != nil {
-		return "", err
-	}
-	token := fmt.Sprintf(`mchid="%s",nonce_str="%s",timestamp="%s",serial_no="%s",signature="%s"`,
-		c.MchID, nonce, timestamp, c.SerialNo, signature,
-	)
-	return "WECHATPAY2-SHA256-RSA2048 " + token, nil
-}
-
-func (c *WxPayClient) signBase64(message string) (string, error) {
-	sum := sha256.Sum256([]byte(message))
-	sign, err := rsa.SignPKCS1v15(rand.Reader, c.PrivateKey, crypto.SHA256, sum[:])
-	if err != nil {
-		return "", err
-	}
-	return base64.StdEncoding.EncodeToString(sign), nil
-}
-
-func loadRSAPrivateKey(path string) (*rsa.PrivateKey, error) {
-	raw, err := os.ReadFile(path)
-	if err != nil {
-		return nil, err
-	}
-	block, _ := pem.Decode(raw)
-	if block == nil {
-		return nil, errors.New("invalid private key pem")
-	}
-
-	if key, err := x509.ParsePKCS8PrivateKey(block.Bytes); err == nil {
-		if rsaKey, ok := key.(*rsa.PrivateKey); ok {
-			return rsaKey, nil
-		}
-	}
-	if key, err := x509.ParsePKCS1PrivateKey(block.Bytes); err == nil {
-		return key, nil
-	}
-
-	return nil, errors.New("unsupported private key format")
-}
-
-func randomString(n int) string {
-	const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
-	if n <= 0 {
-		return ""
-	}
-	b := make([]byte, n)
-	rb := make([]byte, n)
-	if _, err := rand.Read(rb); err != nil {
-		return strconv.FormatInt(time.Now().UnixNano(), 10)
-	}
-	for i := 0; i < n; i++ {
-		b[i] = chars[int(rb[i])%len(chars)]
-	}
-	return string(b)
-}
-
-func firstNotEmpty(values ...string) string {
-	for _, v := range values {
-		if strings.TrimSpace(v) != "" {
-			return strings.TrimSpace(v)
-		}
-	}
-	return ""
-}