DengBiao hace 1 año
padre
commit
bd7d2bd38b
Se han modificado 15 ficheros con 225 adiciones y 441 borrados
  1. +1
    -0
      app/cfg/init_cfg.go
  2. +32
    -0
      app/db/gim/db_sys_cfg.go
  3. +8
    -0
      app/db/gim/model/sys_cfg.go
  4. +0
    -73
      app/svc/svc_auth.go
  5. +0
    -58
      app/svc/svc_domain_info.go
  6. +0
    -18
      app/svc/svc_file_domain.go
  7. +0
    -71
      app/svc/svc_file_img_format.go
  8. +0
    -46
      app/svc/svc_file_save.go
  9. +43
    -0
      app/svc/svc_send_red_package.go
  10. +0
    -171
      app/svc/svc_sys_cfg_get.go
  11. +16
    -0
      app/utils/random.go
  12. +10
    -0
      app/utils/time.go
  13. +5
    -4
      consume/dou_shen_user_register_for_official_consume.go
  14. +66
    -0
      consume/dou_shen_user_register_for_operation_center.go
  15. +44
    -0
      consume/md/md_red_package.go

+ 1
- 0
app/cfg/init_cfg.go Ver fichero

@@ -56,6 +56,7 @@ func InitCfg() {
Log = &conf.Log
RedisAddr = conf.RedisAddr
Admin = &conf.Admin
AppComm = &conf.AppComm
MQ = &conf.MQ
ES = &conf.ES
ImBusinessRpc = &conf.ImBusinessRpc


+ 32
- 0
app/db/gim/db_sys_cfg.go Ver fichero

@@ -0,0 +1,32 @@
package db

import (
"applet/app/db"
"applet/app/db/gim/model"
)

type dbSysCfg struct{}

var DbSysCfg = new(dbSysCfg)

// SysCfgGetAll 获取系统配置
func (*dbSysCfg) SysCfgGetAll(masterId int64) (*[]model.SysCfg, error) {
var cfgList []model.SysCfg
if err := db.ImDb.Where("`master_id`=?", masterId).Find(&cfgList); err != nil {
return nil, err
}
return &cfgList, nil
}

// SysCfgGetOne 获取一条记录
func (*dbSysCfg) SysCfgGetOne(key string, masterId string) (*model.SysCfg, error) {
var cfgList model.SysCfg
isHas, err := db.ImDb.Where("`key` = ? and `master_id` = ?", key, masterId).Get(&cfgList)
if err != nil {
return nil, err
}
if !isHas {
return nil, nil
}
return &cfgList, nil
}

+ 8
- 0
app/db/gim/model/sys_cfg.go Ver fichero

@@ -0,0 +1,8 @@
package model

type SysCfg struct {
Key string // 键
Val string // 值
Memo string // 备注
MasterId int64 // 站长id
}

+ 0
- 73
app/svc/svc_auth.go Ver fichero

@@ -1,73 +0,0 @@
package svc

import (
"applet/app/db"
"applet/app/md"
"applet/app/utils"
"errors"
"strings"

"github.com/gin-gonic/gin"
)

// 因为在mw_auth已经做完所有校验, 因此在此不再做任何校验
//GetUser is get user model
func GetUser(c *gin.Context) *md.User {
user, _ := c.Get("user")
return user.(*md.User)
}

func GetUid(c *gin.Context) string {
user, _ := c.Get("user")
u := user.(*md.User)
return utils.IntToStr(u.Info.Uid)
}

func CheckUser(c *gin.Context) (*md.User, error) {
token := c.GetHeader("Authorization")
if token == "" {
return nil, errors.New("token not exist")
}
// 按空格分割
parts := strings.SplitN(token, " ", 2)
if !(len(parts) == 2 && parts[0] == "Bearer") {
return nil, errors.New("token format error")
}
// parts[1]是获取到的tokenString,我们使用之前定义好的解析JWT的函数来解析它
mc, err := utils.ParseToken(parts[1])
if err != nil {
return nil, err
}

// 获取user
u, err := db.UserFindByID(db.DBs[c.GetString("mid")], mc.UID)
if err != nil {
return nil, err
}
if u == nil {
return nil, errors.New("token can not find user")
}
// 获取user profile
up, err := db.UserProfileFindByID(db.DBs[c.GetString("mid")], mc.UID)
if err != nil {
return nil, err
}
// 获取user 等级
ul, err := db.UserLevelByID(db.DBs[c.GetString("mid")], u.Level)
if err != nil {
return nil, err
}

// 获取用户标签
tags, err := db.UserTagsByUid(db.DBs[c.GetString("mid")], mc.UID)
if err != nil {
return nil, err
}
user := &md.User{
Info: u,
Profile: up,
Level: ul,
Tags: tags,
}
return user, nil
}

+ 0
- 58
app/svc/svc_domain_info.go Ver fichero

@@ -1,58 +0,0 @@
package svc

import (
"applet/app/db"
"applet/app/db/model"
"applet/app/utils"
"applet/app/utils/logx"
"github.com/gin-gonic/gin"
"github.com/tidwall/gjson"
"strings"
)

// 获取指定类型的域名:admin、wap、api
func GetWebSiteDomainInfo(c *gin.Context, domainType string) string {
if domainType == "" {
domainType = "wap"
}

domainSetting := SysCfgGet(c, "domain_setting")

domainTypePath := domainType + ".type"
domainSslPath := domainType + ".isOpenHttps"
domainPath := domainType + ".domain"

domainTypeValue := gjson.Get(domainSetting, domainTypePath).String()
domainSslValue := gjson.Get(domainSetting, domainSslPath).String()
domain := gjson.Get(domainSetting, domainPath).String()

scheme := "http://"
if domainSslValue == "1" {
scheme = "https://"
}

// 有自定义域名 返回自定义的
if domainTypeValue == "own" && domain != "" {
return scheme + domain
}
// 否则返回官方的
official, err := db.GetOfficialDomainInfoByType(db.Db, c.GetString("mid"), domainType)
if err != nil {
_ = logx.Errorf("Get Official Domain Fail! %s", err)
return ""
}
if strings.Contains(official, "http") {
return official
}
return scheme + official
}

// 获取指定类型的域名对应的masterId:admin、wap、api
func GetWebSiteDomainMasterId(domainType string, host string) string {
obj := new(model.UserAppDomain)
has, err := db.Db.Where("domain=? and type=?", host, domainType).Get(obj)
if err != nil || !has {
return ""
}
return utils.AnyToString(obj.Uuid)
}

+ 0
- 18
app/svc/svc_file_domain.go Ver fichero

@@ -1,18 +0,0 @@
package svc

import (
"applet/app/md"

"github.com/gin-gonic/gin"
)

// 文件host
func FileImgHost(c *gin.Context) string {
res := SysCfgFind(c, md.KEY_CFG_FILE_SCHEME, md.KEY_CFG_FILE_HOST)
return res[md.KEY_CFG_FILE_SCHEME] + "://" + res[md.KEY_CFG_FILE_HOST] + "/"
}

// 获取缩略图参数
func FileImgThumbnail(c *gin.Context) string {
return SysCfgGet(c, md.KEY_CFG_FILE_AVATAR_THUMBNAIL)
}

+ 0
- 71
app/svc/svc_file_img_format.go Ver fichero

@@ -1,71 +0,0 @@
package svc

import (
"applet/app/utils"
"fmt"
"strings"

"github.com/gin-gonic/gin"
)

//ImageFormat is 格式化 图片
func ImageFormat(c *gin.Context, name string) string {
if strings.Contains(name, "https:") || strings.Contains(name, "http:") {
return name
}
scheme := SysCfgGet(c, "file_bucket_scheme")
domain := SysCfgGet(c, "file_bucket_host")
return fmt.Sprintf("%s://%s/%s", scheme, domain, name)
}

//OffImageFormat is 格式化官方 图片
func OffImageFormat(c *gin.Context, name string) string {
if strings.Contains(name, "https:") || strings.Contains(name, "http:") {
return name
}
return fmt.Sprintf("%s://%s/%s", "http", "ossq.izhyin.cn", name)
}

// ImageBucket is 获取域名
func ImageBucket(c *gin.Context) (string, string) {
return SysCfgGet(c, "file_bucket_scheme"), SysCfgGet(c, "file_bucket_host")
}

// ImageBucketNew is 获取域名
func ImageBucketNew(c *gin.Context) (string, string, string, map[string]string) {
var list = make(map[string]string, 0)
for i := 1; i < 10; i++ {
keys := "file_bucket_sub_host" + utils.IntToStr(i)
list[keys] = SysCfgGet(c, keys)
}
return SysCfgGet(c, "file_bucket_scheme"), SysCfgGet(c, "file_bucket_host"), SysCfgGet(c, "file_bucket_sub_host"), list
}

// ImageFormatWithBucket is 格式化成oss 域名
func ImageFormatWithBucket(scheme, domain, name string) string {
if strings.Contains(name, "http") {
return name
}
return fmt.Sprintf("%s://%s/%s", scheme, domain, name)
}

// ImageFormatWithBucket is 格式化成oss 域名
func ImageFormatWithBucketNew(scheme, domain, subDomain string, moreSubDomain map[string]string, name string) string {
if strings.Contains(name, "http") {
return name
}
if strings.Contains(name, "{{subhost}}") && subDomain != "" { //读副域名 有可能是其他平台的
domain = subDomain
}
//为了兼容一些客户自营商城导到不同系统 并且七牛云不一样
for i := 1; i < 10; i++ {
keys := "file_bucket_sub_host" + utils.IntToStr(i)
if strings.Contains(name, "{{subhost"+utils.IntToStr(i)+"}}") && moreSubDomain[keys] != "" {
domain = moreSubDomain[keys]
}
name = strings.ReplaceAll(name, "{{subhost"+utils.IntToStr(i)+"}}", "")
}
name = strings.ReplaceAll(name, "{{host}}", "")
name = strings.ReplaceAll(name, "{{subhost}}", "")
return fmt.Sprintf("%s://%s/%s", scheme, domain, name)
}

+ 0
- 46
app/svc/svc_file_save.go Ver fichero

@@ -1,46 +0,0 @@
package svc

import (
"time"

"applet/app/db"
"applet/app/db/model"
"applet/app/e"
"applet/app/lib/qiniu"
"applet/app/md"
"applet/app/utils"

"github.com/gin-gonic/gin"
)

func FileSave(c *gin.Context, f *md.FileCallback) error {
// todo 校验时间是否超时, 目前没必要做时间校验,如果已经上传,但超时,那么会造成三方存储存在,可我方表不存在,导致冗余
// 校验签名是否正确
if qiniu.Sign(f.Time) != f.Sign {
return e.NewErrCode(e.ERR_SIGN)
}
newFile := &model.SysFile{
ParentFid: utils.StrToInt64(f.DirId),
FileType: 1,
ShowName: f.FileName,
SaveName: f.FileName,
Uid: utils.StrToInt(f.Uid),
Ext: utils.FileExt(f.FileName),
Hash: f.Hash,
Mime: f.Mime,
Provider: f.Provider,
Width: utils.StrToInt(f.Width),
Height: utils.StrToInt(f.Height),
Bucket: f.Bucket,
FileSize: utils.StrToInt64(f.FileSize),
CreateAt: int(time.Now().Unix()),
}

file, _ := db.FileGetByPFidAndName(db.DBs[c.GetString("mid")], f.DirId, f.FileName)
if file != nil {
newFile.Fid = file.Fid
// 更新数据
return db.FileUpdate(db.DBs[c.GetString("mid")], newFile)
}
return db.FileInsert(db.DBs[c.GetString("mid")], newFile)
}

+ 43
- 0
app/svc/svc_send_red_package.go Ver fichero

@@ -0,0 +1,43 @@
package svc

import (
"applet/app/cfg"
"applet/app/utils"
"applet/consume/md"
"encoding/json"
"errors"
)

// CurlSendRedPackage 发送专属红包
func CurlSendRedPackage(args md.SendRedPackageReq, masterId, userId string) (error, map[string]interface{}) {
url := cfg.AppComm.URL + "/api/v1/comm/pay/balance_pay/im_send_red_package"
utils.FilePutContents("CurlSendRedPackage", utils.SerializeStr(map[string]interface{}{
"data": args,
}))
bytes, err := utils.CurlPost(url, utils.Serialize(args), map[string]string{
"master_id": masterId,
"mid": masterId,
"Request-uid": userId,
"Request-Type": "mq_consume",
})
if err != nil {
return err, nil
}
var result struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data map[string]interface{} `json:"data"`
}
utils.FilePutContents("CurlSendRedPackage", utils.SerializeStr(result))
err = json.Unmarshal(bytes, &result)
if err != nil {
return err, nil
}
if result.Code != 1 {
if result.Msg != "" {
return errors.New(result.Msg), nil
}
return errors.New("请求comm发送红包 异常/失败"), nil
}
return nil, result.Data
}

+ 0
- 171
app/svc/svc_sys_cfg_get.go Ver fichero

@@ -1,171 +0,0 @@
package svc

import (
"errors"
"fmt"
"github.com/gin-gonic/gin"
"strings"
"xorm.io/xorm"

"applet/app/cfg"
"applet/app/db"
"applet/app/md"
"applet/app/utils"
"applet/app/utils/cache"
)

// 单挑记录获取
func SysCfgGet(c *gin.Context, key string) string {
mid := c.GetString("mid")
eg := db.DBs[mid]
return db.SysCfgGetWithDb(eg, mid, key)
}

// 多条记录获取
func SysCfgFind(c *gin.Context, keys ...string) map[string]string {
e := db.DBs[c.GetString("mid")]
res := map[string]string{}
cacheKey := fmt.Sprintf(md.AppCfgCacheKey, c.GetString("mid"))
err := cache.GetJson(cacheKey, &res)
if err != nil || len(res) == 0 {
cfgList, _ := db.SysCfgGetAll(e)
if cfgList == nil {
return nil
}
for _, v := range *cfgList {
res[v.Key] = v.Val
}
// 先不设置缓存
cache.SetJson(cacheKey, res, md.CfgCacheTime)
}
if len(keys) == 0 {
return res
}
tmp := map[string]string{}
for _, v := range keys {
if val, ok := res[v]; ok {
tmp[v] = val
} else {
tmp[v] = ""
}
}
return tmp
}

// 多条记录获取
func EgSysCfgFind(keys ...string) map[string]string {
var e *xorm.Engine
res := map[string]string{}
if len(res) == 0 {
cfgList, _ := db.SysCfgGetAll(e)
if cfgList == nil {
return nil
}
for _, v := range *cfgList {
res[v.Key] = v.Val
}
// 先不设置缓存
// cache.SetJson(md.KEY_SYS_CFG_CACHE, res, 60)
}
if len(keys) == 0 {
return res
}
tmp := map[string]string{}
for _, v := range keys {
if val, ok := res[v]; ok {
tmp[v] = val
} else {
tmp[v] = ""
}
}
return tmp
}

// 清理系统配置信息
func SysCfgCleanCache() {
cache.Del(md.KEY_SYS_CFG_CACHE)
}

// 写入系统设置
func SysCfgSet(c *gin.Context, key, val, memo string) bool {
cfg, err := db.SysCfgGetOne(db.DBs[c.GetString("mid")], key)
if err != nil || cfg == nil {
return db.SysCfgInsert(db.DBs[c.GetString("mid")], key, val, memo)
}
if memo != "" && cfg.Memo != memo {
cfg.Memo = memo
}
SysCfgCleanCache()
return db.SysCfgUpdate(db.DBs[c.GetString("mid")], key, val, cfg.Memo)
}

// 多条记录获取
func SysCfgFindByIds(eg *xorm.Engine, keys ...string) map[string]string {
key := utils.Md5(eg.DataSourceName() + md.KEY_SYS_CFG_CACHE)
res := map[string]string{}
c, ok := cfg.MemCache.Get(key).(map[string]string)
if !ok || len(c) == 0 {
cfgList, _ := db.DbsSysCfgGetAll(eg)
if cfgList == nil {
return nil
}
for _, v := range *cfgList {
res[v.Key] = v.Val
}
cfg.MemCache.Put(key, res, 10)
} else {
res = c
}
if len(keys) == 0 {
return res
}
tmp := map[string]string{}
for _, v := range keys {
if val, ok := res[v]; ok {
tmp[v] = val
} else {
tmp[v] = ""
}
}
return tmp
}

// 支付配置
func SysCfgFindPayment(c *gin.Context) ([]map[string]string, error) {
platform := c.GetHeader("platform")
payCfg := SysCfgFind(c, "pay_wx_pay_img", "pay_ali_pay_img", "pay_balance_img", "pay_type")
if payCfg["pay_wx_pay_img"] == "" || payCfg["pay_ali_pay_img"] == "" || payCfg["pay_balance_img"] == "" || payCfg["pay_type"] == "" {
return nil, errors.New("lack of payment config")
}
payCfg["pay_wx_pay_img"] = ImageFormat(c, payCfg["pay_wx_pay_img"])
payCfg["pay_ali_pay_img"] = ImageFormat(c, payCfg["pay_ali_pay_img"])
payCfg["pay_balance_img"] = ImageFormat(c, payCfg["pay_balance_img"])

var result []map[string]string

if strings.Contains(payCfg["pay_type"], "aliPay") && platform != md.PLATFORM_WX_APPLET {
item := make(map[string]string)
item["pay_channel"] = "alipay"
item["img"] = payCfg["pay_ali_pay_img"]
item["name"] = "支付宝支付"
result = append(result, item)
}

if strings.Contains(payCfg["pay_type"], "wxPay") {
item := make(map[string]string)
item["pay_channel"] = "wx"
item["img"] = payCfg["pay_wx_pay_img"]
item["name"] = "微信支付"
result = append(result, item)
}

if strings.Contains(payCfg["pay_type"], "walletPay") {
item := make(map[string]string)
item["pay_channel"] = "fin"
item["img"] = payCfg["pay_balance_img"]
item["name"] = "余额支付"
result = append(result, item)
}

return result, nil
}

+ 16
- 0
app/utils/random.go Ver fichero

@@ -0,0 +1,16 @@
package utils

import (
"math/rand"
"time"
)

func RandFloats(min, max float64) float64 {
rand.Seed(time.Now().UnixNano())
return min + rand.Float64()*(max-min)
}

func RandInt(max int) int {
rand.Seed(time.Now().UnixNano()) // seed后随机数可变
return rand.Intn(max) // 0-100的随机数
}

+ 10
- 0
app/utils/time.go Ver fichero

@@ -224,3 +224,13 @@ func GetLastDateOfMonth(d time.Time) time.Time {
func GetZeroTime(d time.Time) time.Time {
return time.Date(d.Year(), d.Month(), d.Day(), 0, 0, 0, 0, d.Location())
}

// UnixMilliTime 将时间转化为毫秒数
func UnixMilliTime(t time.Time) int64 {
return t.UnixNano() / 1000000
}

// UnunixMilliTime 将毫秒数转为为时间
func UnunixMilliTime(unix int64) time.Time {
return time.Unix(0, unix*1000000)
}

+ 5
- 4
consume/dou_shen_user_register_for_official_consume.go Ver fichero

@@ -127,10 +127,11 @@ func handleDouShenUserRegisterConsumeForOfficial(msgData []byte) error {
return errors.New("当前官方群暂未设置群主,请联系管理员!!!")
}
//加入群
_, err = utils.GetLogicExtClient(cfg.ImLogicRpc.URL, cfg.ImLogicRpc.PORT).AddGroupMembers(utils.GetCtx("", strconv.FormatInt(userGroup.UserId, 10), "", msg.MasterId), &pb.AddGroupMembersReq{
GroupId: int64(officialGroup.GroupId),
UserIds: []int64{gimUser.Id},
})
_, err = utils.GetLogicExtClient(cfg.ImLogicRpc.URL, cfg.ImLogicRpc.PORT).AddGroupMembers(
utils.GetCtx("", strconv.FormatInt(userGroup.UserId, 10), "", msg.MasterId), &pb.AddGroupMembersReq{
GroupId: int64(officialGroup.GroupId),
UserIds: []int64{gimUser.Id},
})
}
return nil
}

+ 66
- 0
consume/dou_shen_user_register_for_operation_center.go Ver fichero

@@ -4,6 +4,8 @@ import (
"applet/app/cfg"
"applet/app/db"
db2 "applet/app/db/gim"
"applet/app/svc"
utils2 "applet/app/utils"
"applet/app/utils/logx"
utils "applet/app/utils/rpc"
"applet/consume/md"
@@ -106,6 +108,70 @@ func handleDouShenUserRegisterConsumeForOperationCenter(msgData []byte) error {
GroupId: int64(OperationGroup.GroupId),
UserIds: []int64{gimUser.Id},
})

//发送专属红包
gimSendSpeciallyRedPackageUser, err := db2.DbSysCfg.SysCfgGetOne("send_specially_red_package_user", msg.MasterId)
if err != nil {
return err
}
if gimSendSpeciallyRedPackageUser == nil {
return errors.New("暂未设置专属红包发送用户")
}
sendSpeciallyRedPackageUser, err := db.SysCfgGetOne(db.DBs[msg.MasterId], "send_specially_red_package_user")
if err != nil {
return err
}
amount, err := getSendAmount(msg.MasterId)
if err != nil {
return err
}
args := md.SendRedPackageReq{
UserId: strconv.FormatInt(gimUser.Id, 10),
DeviceId: "",
Token: "",
Amount: amount,
RedPacketType: 4,
RedPacketNums: 1,
RedPacketContent: "恭喜发财",
RedPacketSmallContent: "大吉大利",
ReceiverType: 2,
ReceiverId: int64(OperationGroup.GroupId),
SendTime: utils2.UnixMilliTime(time.Now()),
ToUserIds: []int64{gimUser.Id},
RedPackageCover: "",
}
err, _ = svc.CurlSendRedPackage(args, msg.MasterId, sendSpeciallyRedPackageUser.Val)
if err != nil {
return err
}
}
return nil
}

func getSendAmount(masterId string) (string, error) {
speciallyRedPackageAmountRadio, err := db.SysCfgGetOne(db.DBs[masterId], "specially_red_package_amount_radio")
if err != nil {
return "", err
}
var speciallyRedPackageAmountRadioData []*md.SpeciallyRedPackageAmountRadio
err = json.Unmarshal([]byte(speciallyRedPackageAmountRadio.Val), &speciallyRedPackageAmountRadioData)
if err != nil {
return "", err
}

var tempSpeciallyRedPackageAmountRadioData []*md.SpeciallyRedPackageAmountRadio
for _, v := range speciallyRedPackageAmountRadioData {
for i := 0; i < utils2.StrToInt(v.Value); i++ {
tempSpeciallyRedPackageAmountRadioData = append(tempSpeciallyRedPackageAmountRadioData, v)
}
}
if len(tempSpeciallyRedPackageAmountRadioData) < 100 {
return "", errors.New("红包金额比例设置有误!")
}

randInt := utils2.RandInt(99)
min := tempSpeciallyRedPackageAmountRadioData[randInt].From
max := tempSpeciallyRedPackageAmountRadioData[randInt].To
amount := utils2.AnyToString(utils2.RandFloats(utils2.AnyToFloat64(min), utils2.AnyToFloat64(max)))
return amount, nil
}

+ 44
- 0
consume/md/md_red_package.go Ver fichero

@@ -0,0 +1,44 @@
package md

type SendRedPackageReq struct {
UserId string `json:"user_id"` //im用户id
DeviceId string `json:"device_id"` //设备id
Token string `json:"token"` //im-token
Amount string `json:"amount"` //红包金额
RedPacketType int `json:"red_packet_type"` //红包类型(0:未知 1:好友红包 2:群组普通红包 3:群组手气红包 4:群组专属红包 5:系统红包)
RedPacketNums int `json:"red_packet_nums"` //红包数量
RedPacketContent string `json:"red_packet_content"` //红包文字内容
RedPacketSmallContent string `json:"red_packet_small_content"` //红包文字内容
ReceiverType int `json:"receiver_type"` //接收者类型,1:user;2:group
ReceiverId int64 `json:"receiver_id"` //用户id或者群组id
SendTime int64 `json:"send_time"` //消息发送时间戳,精确到毫秒
ToUserIds []int64 `json:"to_user_ids"` //红包给到哪些用户(专属红包)
RedPackageCover string `json:"red_package_cover"` //红包封面
}

type GrabRedPackageReq struct {
UserId string `json:"user_id"` //im用户id
SendRedPackageUserNikeName string `json:"send_red_package_user_nike_name"` //红包发送者-im用户昵称
SendRedPacketAvatarUrl string `json:"send_red_packet_avatar_url"` //红包发送者-im用户头像
DeviceId string `json:"device_id"` //设备id
Token string `json:"token"` //im-token
ReceiverType int `json:"receiver_type"` //接收者类型,1:user;2:group
ReceiverId int64 `json:"receiver_id"` //用户id或者群组id
SendTime int64 `json:"send_time"` //消息发送时间戳,精确到毫秒
RedPackageId int `json:"red_package_id"` //红包id
RedPackageCover string `json:"red_package_cover"` //红包封面
}

type RedPackageDetailResp struct {
ImUserId string `json:"im_user_id"` //im用户id
UserNickName string `json:"user_nick_name"` //im用户昵称
UserAvatarUrl string `json:"user_avatar_url"` //im用户昵称
Amount string `json:"amount"` //金额
ReceiveAt string `json:"received_at"` //领取时间
}

type SpeciallyRedPackageAmountRadio struct {
From string `json:"form"`
To string `json:"to"`
Value string `json:"value"`
}

Cargando…
Cancelar
Guardar