Merge remote-tracking branch 'origin/master'

This commit is contained in:
chy
2025-07-05 15:13:13 +08:00
16 changed files with 514 additions and 189 deletions

20
internal/consts/emqx.go Normal file
View File

@ -0,0 +1,20 @@
package consts
// UP 上行消息 cmd 常量
const (
CmdMemberLevels = 1 // 会员等级数据
CmdClientList = 2 // 客户机列表数据
CmdClientUp = 104 // 上机记录
CmdClientDown = 106 // 下机记录
)
// DOWN 下行消息 cmd 常量
const (
CmdDesktopSetting = 10001 // 桌面组件显示设置
CmdUserFee = 10002 // 用户网费下发
)
const (
UPDataTopic = "/+/up"
DOWNDataTopic = "/%d/down"
)

View File

@ -0,0 +1,5 @@
package consts
const (
NetfeeCode = "internet_fee"
)

View File

@ -0,0 +1,17 @@
package reward
import (
"context"
"server/internal/model"
"server/internal/service"
"server/api/reward/v1"
)
func (c *ControllerV1) NetfeeCallback(ctx context.Context, req *v1.NetfeeCallbackReq) (res *v1.NetfeeCallbackRes, err error) {
out, err := service.Reward().NetfeeCallback(ctx, &model.NetfeeCallbackIn{OrderId: req.OrderId})
if err != nil {
return
}
return &v1.NetfeeCallbackRes{Success: out.Success}, nil
}

View File

@ -37,6 +37,7 @@ type UsersColumns struct {
RoleId string // 角色ID
LastLoginStoreId string // 上次登录门店ID
Quan8Uuid string // 8圈使用的 uuid
XyUserId string // 系统唯一用户ID
}
// usersColumns holds the columns for the table users.
@ -58,6 +59,7 @@ var usersColumns = UsersColumns{
RoleId: "role_id",
LastLoginStoreId: "last_login_store_id",
Quan8Uuid: "quan8_uuid",
XyUserId: "xy_user_id",
}
// NewUsersDao creates and returns a new DAO object for table data access.

View File

@ -7,6 +7,7 @@ import (
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/os/glog"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/guid"
"server/internal/consts"
"server/internal/dao"
@ -15,6 +16,8 @@ import (
"server/internal/service"
"server/utility/ecode"
"server/utility/gamelife"
"server/utility/mqtt"
"server/utility/mqtt/emqx"
"strconv"
"time"
)
@ -657,7 +660,7 @@ func (s *sReward) GetLift(ctx context.Context, in *model.GetRewardIn) (out *mode
}
}
if in.Source == 1 && in.RewradTypeId == 37 || in.Source == 2 {
if in.Source == 1 && in.RewradTypeId == 37 {
// 增加奖励已领取数量
_, err = dao.Rewards.Ctx(ctx).Where(do.Rewards{Id: in.RewardId}).Increment(dao.Rewards.Columns().ReceivedNum, 1)
if err != nil {
@ -704,6 +707,63 @@ func (s *sReward) GetLift(ctx context.Context, in *model.GetRewardIn) (out *mode
}
} else {
// 门店奖励处理
value, err := dao.RewardTypes.Ctx(ctx).WherePri(in.RewradTypeId).Value()
if err != nil {
return nil, ecode.Fail.Sub("获取奖励类型失败")
}
if value.IsEmpty() {
return nil, ecode.Params.Sub("奖励类型不存在")
}
switch value.String() {
case consts.NetfeeCode:
dao.UserTaskRewards.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
xyUserId, err := dao.Users.Ctx(ctx).WherePri(in.UserId).Fields(dao.Users.Columns().XyUserId).Value()
if err != nil {
return err
}
if xyUserId.IsEmpty() {
return ecode.Params.Sub("该用户暂未绑定8圈账号无法发放网费奖励")
}
// 增加奖励已领取数量
_, err = dao.Rewards.Ctx(ctx).Where(do.Rewards{Id: in.RewardId}).Increment(dao.Rewards.Columns().ReceivedNum, 1)
if err != nil {
return ecode.Fail.Sub("获取奖励领取记录异常")
}
// 修改用户任务奖励记录状态
_, err = dao.UserTaskRewards.Ctx(ctx).Where(do.UserTaskRewards{Id: in.Id}).Data(do.UserTaskRewards{
Status: consts.RewardExchangeStatus,
}).Update()
if err != nil {
return ecode.Fail.Sub("修改用户任务奖励记录状态异常")
}
client, b := mqtt.GetClient("emqx")
if !b {
return ecode.Fail.Sub("获取mqtt客户端异常")
}
downData := emqx.DownData{CMD: consts.CmdUserFee, Data: struct {
XyUserId string `json:"xy_user_id"`
Money int `json:"money"`
Note string `json:"note"`
OrderId string `json:"order_id"`
}{
XyUserId: xyUserId.String(),
Money: in.GrantQuantity,
Note: fmt.Sprintf("用户领取 id 为 %d下发记录 id 为 %d 的网费", in.RewardId, in.Id),
OrderId: gconv.String(in.Id),
}}
marshal, err := json.Marshal(downData)
if err != nil {
return ecode.Fail.Sub("json.Marshal异常")
}
if err = client.Publish(fmt.Sprintf(consts.DOWNDataTopic, in.StoreId), marshal); err != nil {
return ecode.Fail.Sub("Publish异常")
}
return nil
})
}
}
return out, err
}
@ -1115,3 +1175,41 @@ func (s *sReward) GetUserClaimList(ctx context.Context, in *model.GetUserClaimLi
Total: total,
}, nil
}
func (s *sReward) NetfeeCallback(ctx context.Context, in *model.NetfeeCallbackIn) (out *model.NetfeeCallbackOut, err error) {
if err = dao.UserTaskRewards.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
value, err := dao.UserTaskRewards.Ctx(ctx).WherePri(in.OrderId).Fields(dao.UserTaskRewards.Columns().UserTaskId).Value()
if err != nil {
return ecode.Fail.Sub("查询用户任务奖励失败")
}
if value.IsEmpty() {
return ecode.Fail.Sub("查询用户任务奖励失败")
}
count, err := dao.UserTaskRewards.Ctx(ctx).Where(do.UserTaskRewards{UserTaskId: value.Int64()}).WhereIn(dao.UserTaskRewards.Columns().Status, []int{2, 3, 5}).Count()
if err != nil {
return ecode.Fail.Sub("查询用户任务奖励失败")
}
if count == 1 {
// 修改任务记录状态2
_, err = dao.UserTasks.Ctx(ctx).Where(do.UserTasks{Id: value.Int64()}).Data(do.UserTasks{
Status: 2,
}).Update()
if err != nil {
return ecode.Fail.Sub("修改用户任务状态失败")
}
}
if _, err := dao.UserTaskRewards.Ctx(ctx).Data(do.UserTaskRewards{
Status: consts.RewardSuccessStatus,
}).Update(); err != nil {
return ecode.Fail.Sub("修改用户任务奖励状态失败")
}
return nil
}); err != nil {
return nil, err
}
return &model.NetfeeCallbackOut{Success: true}, nil
}

View File

@ -5,11 +5,13 @@ import (
"encoding/json"
"fmt"
"github.com/gogf/gf/v2/errors/gerror"
"server/internal/consts"
"server/internal/dao"
"server/internal/model"
"server/internal/model/do"
"server/internal/service"
"server/utility/mqtt"
"server/utility/mqtt/emqx"
)
type sStoreDesktopSetting struct {
@ -63,15 +65,26 @@ func (s *sStoreDesktopSetting) Save(ctx context.Context, in model.SaveDesktopSet
if err != nil {
return nil, err
}
marshal, err := json.Marshal(in)
if err != nil {
return nil, err
}
client, b := mqtt.GetClient("emqx")
if !b {
return nil, gerror.New("获取MQTT客户端失败")
}
err = client.Publish(fmt.Sprintf("/desktop/%d", in.StoreId), marshal)
downData := emqx.DownData{
CMD: consts.CmdDesktopSetting,
StoreId: int(in.StoreId),
Data: struct {
RightComponentVisible int `json:"rightComponentVisible"`
TopComponentVisible int `json:"topComponentVisible"`
}{
RightComponentVisible: in.RightComponentVisible,
TopComponentVisible: in.TopComponentVisible,
},
}
marshal, err := json.Marshal(downData)
if err != nil {
return nil, err
}
err = client.Publish(fmt.Sprintf("/%d/down", in.StoreId), marshal)
if err != nil {
return nil, err
}

View File

@ -679,6 +679,7 @@ func (s *sTask) GetTaskList(ctx context.Context, in *model.GetTaskListV2In) (out
}
if int(v.UserTimes) >= v.TargetTimes {
completedTime := gtime.Now()
// 判断当前用户完成情况,已完成根据任务、用户,任务类型检查是否存在用户任务记录
orm := dao.UserTasks.Ctx(ctx).Where(do.UserTasks{UserId: in.UserId, TaskId: v.TaskID})
if v.GameTaskConfig.TimeType == 1 {
@ -741,12 +742,17 @@ func (s *sTask) GetTaskList(ctx context.Context, in *model.GetTaskListV2In) (out
// 拼装门店奖励数据
if len(result.TaskList[i].Rewards) > 0 {
for _, reward := range result.TaskList[i].Rewards {
var quantity uint64
quantity, err = CalculateNetfeeRewardQuantity(ctx, in.UserId, in.StoreId, &reward, completedTime)
if err != nil {
quantity = reward.GrantQuantity
}
in := do.UserTaskRewards{
RewardId: reward.Id,
UserTaskId: id,
RewardName: reward.Name,
Status: consts.RewardPendingStatus,
IssueQuantity: reward.GrantQuantity,
IssueQuantity: quantity,
Source: 2,
RewardTypeId: reward.RewardTypeId,
}
@ -936,3 +942,95 @@ func (s *sTask) SyncTaskFromGamelife(ctx context.Context) (out *model.SyncTaskOu
wg.Wait()
return
}
func CalculateNetfeeRewardQuantity(ctx context.Context, userId int64, storeId int64, reward *model.SimpleReward, completedTime *gtime.Time) (uint64, error) {
const rewardTypeCode = consts.NetfeeCode
// 判断是否是门店网费奖励
exist, err := dao.RewardTypes.Ctx(ctx).
WherePri(reward.RewardTypeId).
Where(do.RewardTypes{Code: rewardTypeCode}).
Exist()
if err != nil {
return 0, ecode.Fail.Sub("获取奖励类型失败")
}
if !exist {
// 不是网费奖励,返回当前奖励默认值
return reward.GrantQuantity, nil
}
// 获取当前小时 & 星期几0=周日)
hour := completedTime.Hour()
weekday := int(completedTime.Weekday())
// 获取上机记录
areaLevel, err := dao.StoreClientSessions.Ctx(ctx).
Where(do.StoreClientSessions{UserId: userId}).
WhereLTE(dao.StoreClientSessions.Columns().StartTime, completedTime).
Where("end_time IS NULL OR end_time >= ?", completedTime).
Fields("area_name,level_id").
OrderDesc(dao.StoreClientSessions.Columns().StartTime).
One()
if err != nil {
return 0, ecode.Fail.Sub("获取用户上机记录失败")
}
// 获取会员等级ID内部ID
levelId, err := dao.StoreMemberLevels.Ctx(ctx).
Where(do.StoreMemberLevels{LevelId: areaLevel["level_id"].Int64()}).
Fields("id").
Value()
if err != nil {
return 0, ecode.Fail.Sub("获取会员等级失败")
}
if levelId.IsEmpty() {
return reward.GrantQuantity, nil
}
// 获取区域ID
areaId, err := dao.StoreAreas.Ctx(ctx).
Where(do.StoreAreas{AreaName: areaLevel["area_name"].String()}).
Fields("id").
Value()
if err != nil {
return 0, ecode.Fail.Sub("获取区域失败")
}
if areaId.IsEmpty() {
return reward.GrantQuantity, nil
}
// 获取门店该区域、等级、奖励配置
priceDataStr, err := dao.StoreNetfeeAreaLevel.Ctx(ctx).
Where(do.StoreNetfeeAreaLevel{
StoreId: storeId,
AreaId: areaId.Int(),
MemberLevelId: levelId.Int(),
RewardId: reward.Id,
}).
Fields(dao.StoreNetfeeAreaLevel.Columns().PriceData).
Value()
if err != nil {
return 0, ecode.Fail.Sub("获取网费奖励价格配置失败")
}
// 若配置为空,返回默认值
if priceDataStr.IsEmpty() {
return reward.GrantQuantity, nil
}
// 解析 priceData
var priceData [][]int
if err := json.Unmarshal([]byte(priceDataStr.String()), &priceData); err != nil {
return 0, ecode.Fail.Sub("网费价格配置解析失败")
}
// 防止越界
if weekday >= len(priceData) || hour >= len(priceData[weekday]) {
return 0, ecode.Fail.Sub("网费奖励价格配置不完整")
}
grant := uint64(priceData[weekday][hour])
glog.Infof(ctx, "网费奖励金额为 %d来源于门店配置", grant)
return grant, nil
}

View File

@ -29,4 +29,5 @@ type Users struct {
RoleId interface{} // 角色ID
LastLoginStoreId interface{} // 上次登录门店ID
Quan8Uuid interface{} // 8圈使用的 uuid
XyUserId interface{} // 系统唯一用户ID
}

View File

@ -27,4 +27,5 @@ type Users struct {
RoleId int64 `json:"roleId" orm:"role_id" description:"角色ID"` // 角色ID
LastLoginStoreId int64 `json:"lastLoginStoreId" orm:"last_login_store_id" description:"上次登录门店ID"` // 上次登录门店ID
Quan8Uuid string `json:"quan8Uuid" orm:"quan8_uuid" description:"8圈使用的 uuid"` // 8圈使用的 uuid
XyUserId string `json:"xyUserId" orm:"xy_user_id" description:"系统唯一用户ID"` // 系统唯一用户ID
}

View File

@ -196,19 +196,21 @@ type CallbackData struct {
}
type GetRewardIn struct {
Id int
AreaId int
GameId int
GameCode string
RewradTypeId int
RewardId int
RoleIdx string
TaskId string
PopenId string
Source int
BindType int
UserTaskId int
UserId int
Id int
AreaId int
GameId int
GameCode string
RewradTypeId int
RewardId int
RoleIdx string
TaskId string
PopenId string
Source int
BindType int
UserTaskId int
UserId int
GrantQuantity int
StoreId int
}
type GetRewardOut struct {
//List []GetRewardNewOut `json:"list"`

View File

@ -44,3 +44,9 @@ type UserClaimReward struct {
RewardName string `json:"rewardName" orm:"reward_name"`
SimpleReward SimpleReward `json:"reward" orm:"with:id=reward_id"`
}
type NetfeeCallbackIn struct {
OrderId string
}
type NetfeeCallbackOut struct {
Success bool
}

View File

@ -4,7 +4,7 @@ import (
_ "github.com/gogf/gf/contrib/drivers/mysql/v2"
_ "github.com/gogf/gf/contrib/nosql/redis/v2"
_ "server/utility/gamelife"
//_ "server/utility/mqtt/emqx"
_ "server/utility/mqtt/emqx"
_ "server/utility/myCasbin"
_ "server/utility/oss/aliyun"
_ "server/utility/rsa"

View File

@ -337,6 +337,7 @@ type (
// }
CallBack(ctx context.Context, in *model.RewardCallbackIn) (out *model.RewardCallbackOut, err error)
GetUserClaimList(ctx context.Context, in *model.GetUserClaimListIn) (out *model.GetUserClaimListOut, err error)
NetfeeCallback(ctx context.Context, in *model.NetfeeCallbackIn) (out *model.NetfeeCallbackOut, err error)
}
)