fix(socket): 玩家断开连接时增加保存锁,避免重复保存

在玩家断开连接时,使用 sync.Once 确保只保存一次玩家数据,
防止因并发或多次触发导致的数据异常。

feat(fight): 增加战斗资格判断与邀请取消功能

- 新增 Player.CanFight() 方法用于统一判断是否可以参与战斗
- 在多个战斗相关接口中加入 CanFight 检查
- 添加“取消战斗邀请”指令及处理逻辑(cmd: 2402)
- 修复部分错误码不准确的问题,提升提示一致性

refactor(login): 优化登录流程并增强健壮性

- 提前校验 session 合法性
- 增强获取玩家信息后的空指针检查
- 调整挖矿数据重置方式为 defer 执行
- 优化日志输出内容,便于调试追踪

docs(model): 更新部门、菜单等模型字段命名规范

将 orderNum 字段改为 ordernum,保持数据库列名风格一致,
同时更新了 base_sys_role 中 userId 为 userid。

perf(rate-limit): 提高登录接口的限流 Burst 容量

调整限流器配置,将请求 burst 容量从 2 提升至 5,
以应对短时间高频访问场景,改善用户体验。

chore(build): 忽略新增编译产物和临时文件

在 .gitignore 中添加 logic/logic2、login/login 等新生成文件路径,
避免误提交二进制文件到版本控制。
This commit is contained in:
2025-10-31 00:53:22 +08:00
parent 94e28e2601
commit cccf26788e
28 changed files with 237 additions and 191 deletions

3
.gitignore vendored
View File

@@ -34,3 +34,6 @@ login/login_linux_amd64
logic/logic
.gitignore
public/logic
logic/logic2
login/login
login/login

View File

@@ -169,7 +169,7 @@ func (s *Service) ServiceList(ctx context.Context, req *ListReq) (data interface
// 如果 req.Order 和 req.Sort 均不为空 则添加排序
if !r.Get("order").IsEmpty() && !r.Get("sort").IsEmpty() {
m.Order(r.Get("order").String() + " " + r.Get("sort").String())
// m.OrderDesc("orderNum")
// m.OrderDesc("ordernum")
}
// 如果 ListQueryOp 不为空 则使用 ListQueryOp 进行查询
if s.ListQueryOp != nil {

View File

@@ -56,12 +56,14 @@ func (s *Server) OnClose(c gnet.Conn, _ error) (action gnet.Action) {
s.workerPool.Submit(func() { //TODO 这里可能存在顺序执行问题,待修复
if v.Player != nil {
//cool.Loger.Info(context.TODO(), "准备保存", v.Player.Info.UserID)
v.Player.Save() //保存玩家数据
//cool.Loger.Info(context.TODO(), "保存完成", v.Player.Info.UserID)
if v.CloseChan != nil {
close(v.CloseChan)
}
v.SaveL.Do(func() { //使用保存锁,确保在踢人和掉线的时候只保存一次
//cool.Loger.Info(context.TODO(), "准备保存", v.Player.Info.UserID)
v.Player.Save() //保存玩家数据
//cool.Loger.Info(context.TODO(), "保存完成", v.Player.Info.UserID)
if v.CloseChan != nil {
close(v.CloseChan)
}
})
}
@@ -148,7 +150,7 @@ func (s *Server) OnTraffic(c gnet.Conn) (action gnet.Action) {
for _, msg := range messages {
t := c.Context().(*player.ClientData)
//client := conn.RemoteAddr().String()
err = s.workerPool.Submit(func() { //TODO 这里可能存在顺序执行问题,待修复
s.workerPool.Submit(func() { //TODO 这里可能存在顺序执行问题,待修复
t.OnEvent(msg.Payload)
})

View File

@@ -14,8 +14,8 @@ import (
// 挑战地图boss
func (h Controller) PlayerFightBoss(data *fight.ChallengeBossInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
if c.FightC != nil {
return nil, errorcode.ErrorCodes.ErrOnlineOver6HoursCannotFight
if !c.CanFight() {
return nil, errorcode.ErrorCodes.ErrPokemonNotEligible
}
var petid int
@@ -49,6 +49,9 @@ func (h Controller) PlayerFightBoss(data *fight.ChallengeBossInboundInfo, c *pla
if !ok {
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
}
if len(mdata.Bosses) == 0 {
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
}
for _, bc := range mdata.Bosses {
if bc.Id == nil {
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
@@ -85,7 +88,9 @@ func (h Controller) PlayerFightBoss(data *fight.ChallengeBossInboundInfo, c *pla
// 战斗野怪
func (h Controller) OnPlayerFightNpcMonster(data *fight.FightNpcMonsterInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
if !c.CanFight() {
return nil, errorcode.ErrorCodes.ErrPokemonNotEligible
}
refpet := c.OgreInfo.Data[data.Number]
if refpet.Id == 0 {
@@ -120,7 +125,9 @@ func (h Controller) OnReadyToFight(data *fight.ReadyToFightInboundInfo, c *playe
// 接收战斗或者取消战斗的包
func (h Controller) OnPlayerHandleFightInvite(data *fight.HandleFightInviteInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
if !c.CanFight() {
return nil, errorcode.ErrorCodes.ErrPokemonNotEligible
}
if ok, p1 := c.AgreeBattle(data.UserID, data.Flag, data.Mode); ok {
fight.NewFight(data.Mode, info.BattleStatus.FIGHT_WITH_PLAYER, c, p1) ///开始对战,房主方以及被邀请方
}
@@ -129,14 +136,28 @@ func (h Controller) OnPlayerHandleFightInvite(data *fight.HandleFightInviteInbou
// 邀请其他人进行战斗
func (h Controller) OnPlayerInviteOtherFight(data *fight.InviteToFightInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
if !c.CanFight() {
return nil, errorcode.ErrorCodes.ErrPokemonNotEligible
}
c.InvitePlayerToBattle(&info.PVPinfo{PlayerID: data.UserID, Mode: data.Mode})
return nil, 0
}
// 取消和他人战斗
func (h Controller) OnPlayerCanceledOtherInviteFight(data *fight.InviteFightCancelInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
c.CancelBattle()
return nil, 0
}
// 使用技能包
func (h Controller) UseSkill(data *fight.UseSkillInInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
c.FightC.UseSkill(c, int32(data.SkillId))
if c.FightC != nil {
c.FightC.UseSkill(c, int32(data.SkillId))
}
return nil, 0
}

View File

@@ -35,77 +35,80 @@ func IsToday(t time.Time) bool {
// 处理命令: 1001
func (h *Controller) Login(data *user.MAIN_LOGIN_IN, c gnet.Conn) (result *user.LoginMSInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
if tt := data.CheakSession(); tt { //说明sid正确
cool.Loger.Info(context.TODO(), "准备踢人")
err := h.RPCClient.Kick(data.Head.UserID) //先踢人
if err != nil {
fmt.Println("踢人失败", err)
}
//player.KickPlayer(data.Head.UserID)
cool.Loger.Info(context.TODO(), "踢人请求完成,继续登录流程")
// <-time.After(time.Millisecond * 3000)
share.ShareManager.SetUserOnline(data.Head.UserID, h.Port) //设置用户登录服务器
t := player.GetPlayer(c, data.Head.UserID)
t.Service = blservice.NewUserService(data.Head.UserID)
t.Info = t.Service.Person(data.Head.UserID)
t.Info.UserID = data.Head.UserID
t.Onlinetime = uint32(time.Now().Unix()) //保存时间戳
t.Changemap = true
cool.Loger.Info(context.Background(), "用户上次重置日期", t.Info.LastResetTime.String())
if !IsToday(t.Info.LastResetTime) { //判断是否是今天
t.Info.LastResetTime = gtime.Now().Time
//每天login时候检查重置时间然后把电池任务挖矿重置
//挖矿需要单独存,因为防止多开挖矿
t.Info.TimeToday = 0 //重置电池
for i := 400; i < 500; i++ { //每日任务区段
tttL, ok := xmlres.TaskMap[i]
if ok {
if tttL.Type == 1 { //日常任务
t.Info.TaskList[i-1] = 0 //重置每日任务
}
}
}
for i := 0; i < 50; i++ { //每日任务区段
t.Info.DailyResArr[i] = 0 //重置每日任务
}
go t.Service.Talk(func(m map[uint32]uint32) bool { //挖矿
m = map[uint32]uint32{}
return true
})
}
t.CompleteLogin() //通知客户端登录成功
result = user.NewOutInfo() //设置登录消息
result.PlayerInfo = *t.Info
defer func() {
tt := maps.NewOutInfo()
copier.CopyWithOption(tt, t.Info, copier.Option{DeepCopy: true})
//copier.Copy(t.Info, tt)
t1 := player.NewTomeeHeader(2001, t.Info.UserID)
space.GetSpace(t.Info.MapID).User.IterCb(func(playerID uint32, player common.PlayerI) {
player.SendPack(t1.Pack(tt))
})
space.GetSpace(t.Info.MapID).User.Set(t.Info.UserID, t)
}()
return result, 0
} else {
tt := data.CheakSession()
if !tt {
err = errorcode.ErrorCodes.ErrLoginServerError
return
}
cool.Loger.Info(context.TODO(), "准备踢人")
err1 := h.RPCClient.Kick(data.Head.UserID) //先踢人
if err1 != nil {
fmt.Println("踢人失败", err)
}
//player.KickPlayer(data.Head.UserID)
cool.Loger.Info(context.TODO(), "踢人请求完成,继续登录流程")
// <-time.After(time.Millisecond * 3000)
share.ShareManager.SetUserOnline(data.Head.UserID, h.Port) //设置用户登录服务器
t := player.GetPlayer(c, data.Head.UserID)
t.Service = blservice.NewUserService(data.Head.UserID)
t.Info = t.Service.Person(data.Head.UserID)
if t.Info == nil {
err = errorcode.ErrorCodes.ErrLoginServerError
return
}
t.Info.UserID = data.Head.UserID
t.Onlinetime = uint32(time.Now().Unix()) //保存时间戳
t.Changemap = true
cool.Loger.Info(context.Background(), "用户上次重置日期", t.Info.LastResetTime.String())
if !IsToday(t.Info.LastResetTime) { //判断是否是今天
t.Info.LastResetTime = gtime.Now().Time
//每天login时候检查重置时间然后把电池任务挖矿重置
//挖矿需要单独存,因为防止多开挖矿
t.Info.TimeToday = 0 //重置电池
for i := 400; i < 500; i++ { //每日任务区段
tttL, ok := xmlres.TaskMap[i]
if ok {
if tttL.Type == 1 { //日常任务
t.Info.TaskList[i-1] = 0 //重置每日任务
}
}
}
for i := 0; i < 50; i++ { //每日任务区段
t.Info.DailyResArr[i] = 0 //重置每日任务
}
defer t.Service.Talk(func(m map[uint32]uint32) bool { //挖矿
m = map[uint32]uint32{}
return true
})
}
return
t.CompleteLogin() //通知客户端登录成功
result = user.NewOutInfo() //设置登录消息
result.PlayerInfo = *t.Info
defer func() {
tt := maps.NewOutInfo()
copier.CopyWithOption(tt, t.Info, copier.Option{DeepCopy: true})
//copier.Copy(t.Info, tt)
t1 := player.NewTomeeHeader(2001, t.Info.UserID)
space.GetSpace(t.Info.MapID).User.IterCb(func(playerID uint32, player common.PlayerI) {
player.SendPack(t1.Pack(tt))
})
space.GetSpace(t.Info.MapID).User.Set(t.Info.UserID, t)
}()
return result, 0
}

View File

@@ -48,6 +48,9 @@ type InviteToFightInboundInfo struct {
Mode info.EnumBattleMode `codec:"true"`
}
type InviteFightCancelInboundInfo struct {
Head player.TomeeHeader `cmd:"2402" struc:"[0]pad"`
}
// 2502的回复包 PVP邀请消息
type NoteHandleFightInviteOutboundInfo struct {

View File

@@ -522,6 +522,8 @@ func (f *FightC) enterturn(fattack, sattack *action.SelectSkillAction) {
f.First, f.Second = f.Opp, f.Our // 攻击方为对方时,主攻击方是对方
}
} else {
f.First, f.Second = f.Our, f.Opp
}
f.First.InitAttackValue()

View File

@@ -17,7 +17,7 @@ type WalkInInfo struct {
Point model.Pos `fieldDesc:"直接给坐标xy"`
PathLen uint32 `struc:"sizeof=Path" `
Path string `struc:"[2]byte"`
Path string
}
func (t *WalkInInfo) Broadcast(mapid uint32, o WalkOutInfo) {
@@ -42,5 +42,5 @@ type WalkOutInfo struct {
Point model.Pos `fieldDesc:"直接给坐标xy"`
PathLen uint32 `struc:"sizeof=Path" `
Path string `struc:"[2]byte"`
Path string
}

View File

@@ -152,7 +152,7 @@ func (h *ClientData) Recv(data TomeeHeader) {
nameField.Set(reflect.ValueOf(data))
}
if data.CMD > 1000 { //if cmdlister.Type().In(1) == reflect.TypeOf(&Player{}) {
if data.CMD > 1001 { //if cmdlister.Type().In(1) == reflect.TypeOf(&Player{}) {
//t := GetPlayer(c, data.UserID)
// fmt.Println(data.CMD, "接收 变量的地址 ", &t.Info, t.Info.UserID)

View File

@@ -51,17 +51,7 @@ func (lw *Player) CancelBattle() {
lw.PVPinfo = nil
}
func (lw *Player) CanBattle() bool {
for _, v := range lw.Info.PetList {
if v.Hp > 0 {
return true
}
}
return false
}
func (p *Player) SendLoadPercent(b info.LoadPercentOutboundInfo) {
t1 := NewTomeeHeader(2441, p.Info.UserID)
@@ -98,7 +88,7 @@ func (lw *Player) AgreeBattle(userid, flag uint32, mode info.EnumBattleMode) (bo
return false, nil
}
if v.Info.UserID == userid && v.PVPinfo.Mode == mode { //成功找到,同意对战
if lw.CanBattle() {
if lw.CanFight() {
ret.Result = 1
v.SendPack(t1.Pack(ret))

View File

@@ -83,6 +83,19 @@ func WithConn(c gnet.Conn) PlayerOption {
func (p *Player) GetAction() {
}
func (p *Player) CanFight() bool {
if p.FightC != nil {
return false
}
for _, v := range p.Info.PetList {
if v.Hp > 0 { // 只要找到一个血量大于0的宠物就可以战斗
return true
}
}
// 遍历完所有宠物都没有血量大于0的才不能战斗
return false
}
// 刷怪具体实现

View File

@@ -201,6 +201,7 @@ type ClientData struct {
ERROR_CONNUT int
Wsmsg *WsCodec
Conn gnet.Conn
SaveL sync.Once //保存锁
CloseChan chan struct{}
}
@@ -231,16 +232,17 @@ func (h *ClientData) OnEvent(v []byte) {
header.Result, _ = tempdata.ReadUInt32()
header.Data = tempdata.BytesAvailable()
if header.CMD > 1000 {
if header.CMD > 1001 {
if h.Conn.Context().(*ClientData).Player == nil {
cool.Loger.Error(context.TODO(), "player is nil")
cool.Loger.Error(context.TODO(), header.UserID, "账号未注册")
return
}
if h.Conn.Context().(*ClientData).Player.Info == nil {
cool.Loger.Error(context.TODO(), "player info is nil")
cool.Loger.Error(context.TODO(), header.UserID, "未创建角色")
return
}
}
cool.Loger.Debug(context.TODO(), "接收数据", header.UserID, header.CMD)
h.Recv(header)
//fmt.Println("接收封包", header)
}

View File

@@ -57,7 +57,10 @@ func beforeServeHook(r *ghttp.Request) {
// Limiter is a middleware that implements rate limiting for all HTTP requests.
// It returns HTTP 429 (Too Many Requests) when the rate limit is exceeded.
func Limiter(r *ghttp.Request) {
rateLimiter := limiter.Get(r.GetClientIp(), rate.Limit(10), 2)
// 3. 为任意键 "some-key" 获取一个速率限制器
// - rate.Limit(2): 表示速率为 "每秒2个请求"
// - 2: 表示桶的容量 (Burst)允许瞬时处理2个请求
rateLimiter := limiter.Get(r.GetClientIp(), rate.Limit(10), 5)
if !rateLimiter.Allow() {
r.Response.WriteStatusExit(429) // Return 429 Too Many Requests

Binary file not shown.

View File

@@ -9,7 +9,7 @@ type BaseSysDepartment struct {
*cool.Model
Name string `gorm:"column:name;type:varchar(255);not null" json:"name"` // 部门名称
ParentID uint `gorm:"column:parentId;type:bigint" json:"parentId"` // 上级部门ID
OrderNum int32 `gorm:"column:orderNum;type:int;not null" json:"orderNum"` // 排序
ordernum int32 `gorm:"column:ordernum;type:int;not null" json:"ordernum"` // 排序
}
// TableName BaseSysDepartment's table name

View File

@@ -13,7 +13,7 @@ type BaseSysMenu struct {
Perms *string `gorm:"column:perms;type:text" json:"perms"` // 权限标识
Type int32 `gorm:"column:type;not null" json:"type"` // 类型 0目录 1菜单 2按钮
Icon *string `gorm:"column:icon;type:varchar(255)" json:"icon"` // 图标
OrderNum int32 `gorm:"column:orderNum;type:int;not null;default:0" json:"orderNum"` // 排序
ordernum int32 `gorm:"column:ordernum;type:int;not null;default:0" json:"ordernum"` // 排序
ViewPath *string `gorm:"column:viewPath;type:varchar(255)" json:"viewPath"` // 视图地址
KeepAlive bool `gorm:"column:keepAlive;not null;default:1" json:"keepAlive"` // 路由缓存
IsShow bool `gorm:"column:isShow;not null;default:1" json:"isShow"` // 是否显示

View File

@@ -7,7 +7,7 @@ const TableNameBaseSysRole = "base_sys_role"
// BaseSysRole mapped from table <base_sys_role>
type BaseSysRole struct {
*cool.Model
UserID string `gorm:"column:userId;type:varchar(255);not null" json:"userId"` // 用户ID
UserID string `gorm:"column:userid;type:varchar(255);not null" json:"userid"` // 用户ID
Name string `gorm:"column:name;type:varchar(255);not null;index:IDX_469d49a5998170e9550cf113da,priority:1" json:"name"` // 名称
Label *string `gorm:"column:label;type:varchar(50);index:IDX_f3f24fbbccf00192b076e549a7,priority:1" json:"label"` // 角色标签
Remark *string `gorm:"column:remark;type:varchar(255)" json:"remark"` // 备注

View File

@@ -6,7 +6,7 @@
"deleted_at": null,
"name": "SUN",
"parentId": null,
"orderNum": 0
"ordernum": 0
},
{
"id": 11,
@@ -15,7 +15,7 @@
"deleted_at": null,
"name": "开发",
"parentId": 1,
"orderNum": 0
"ordernum": 0
},
{
"id": 12,
@@ -24,7 +24,7 @@
"deleted_at": null,
"name": "测试",
"parentId": 1,
"orderNum": 0
"ordernum": 0
},
{
"id": 13,
@@ -33,6 +33,6 @@
"deleted_at": null,
"name": "游客",
"parentId": 1,
"orderNum": 0
"ordernum": 0
}
]

View File

@@ -10,7 +10,7 @@
"perms": null,
"type": 0,
"icon": "icon-workbench",
"orderNum": 1,
"ordernum": 1,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -26,7 +26,7 @@
"perms": null,
"type": 0,
"icon": "icon-system",
"orderNum": 2,
"ordernum": 2,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -42,7 +42,7 @@
"perms": null,
"type": 1,
"icon": "icon-menu",
"orderNum": 2,
"ordernum": 2,
"viewPath": "cool/modules/base/views/menu.vue",
"keepAlive": true,
"isShow": true
@@ -58,7 +58,7 @@
"perms": "base:sys:menu:add",
"type": 2,
"icon": null,
"orderNum": 1,
"ordernum": 1,
"viewPath": null,
"keepAlive": false,
"isShow": true
@@ -74,7 +74,7 @@
"perms": "base:sys:menu:delete",
"type": 2,
"icon": null,
"orderNum": 2,
"ordernum": 2,
"viewPath": null,
"keepAlive": false,
"isShow": true
@@ -90,7 +90,7 @@
"perms": "base:sys:menu:update",
"type": 2,
"icon": null,
"orderNum": 3,
"ordernum": 3,
"viewPath": null,
"keepAlive": false,
"isShow": true
@@ -106,7 +106,7 @@
"perms": "base:sys:menu:page,base:sys:menu:list,base:sys:menu:info",
"type": 2,
"icon": null,
"orderNum": 4,
"ordernum": 4,
"viewPath": null,
"keepAlive": false,
"isShow": true
@@ -122,7 +122,7 @@
"perms": null,
"type": 1,
"icon": "icon-common",
"orderNum": 3,
"ordernum": 3,
"viewPath": "cool/modules/base/views/role.vue",
"keepAlive": true,
"isShow": true
@@ -138,7 +138,7 @@
"perms": "base:sys:role:add",
"type": 2,
"icon": null,
"orderNum": 1,
"ordernum": 1,
"viewPath": null,
"keepAlive": false,
"isShow": true
@@ -154,7 +154,7 @@
"perms": "base:sys:role:delete",
"type": 2,
"icon": null,
"orderNum": 2,
"ordernum": 2,
"viewPath": null,
"keepAlive": false,
"isShow": true
@@ -170,7 +170,7 @@
"perms": "base:sys:role:update",
"type": 2,
"icon": null,
"orderNum": 3,
"ordernum": 3,
"viewPath": null,
"keepAlive": false,
"isShow": true
@@ -186,7 +186,7 @@
"perms": "base:sys:role:page,base:sys:role:list,base:sys:role:info",
"type": 2,
"icon": null,
"orderNum": 4,
"ordernum": 4,
"viewPath": null,
"keepAlive": false,
"isShow": true
@@ -202,7 +202,7 @@
"perms": null,
"type": 0,
"icon": "icon-auth",
"orderNum": 1,
"ordernum": 1,
"viewPath": null,
"keepAlive": false,
"isShow": true
@@ -218,7 +218,7 @@
"perms": null,
"type": 1,
"icon": "icon-log",
"orderNum": 1,
"ordernum": 1,
"viewPath": "cool/modules/base/views/log.vue",
"keepAlive": true,
"isShow": true
@@ -234,7 +234,7 @@
"perms": "base:sys:log:page,base:sys:log:clear,base:sys:log:getKeep,base:sys:log:setKeep",
"type": 2,
"icon": null,
"orderNum": 1,
"ordernum": 1,
"viewPath": null,
"keepAlive": false,
"isShow": true
@@ -250,7 +250,7 @@
"perms": null,
"type": 1,
"icon": "icon-favor",
"orderNum": 1,
"ordernum": 1,
"viewPath": "cool/modules/demo/views/crud.vue",
"keepAlive": true,
"isShow": true
@@ -266,7 +266,7 @@
"perms": null,
"type": 0,
"icon": "icon-common",
"orderNum": 2,
"ordernum": 2,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -282,7 +282,7 @@
"perms": null,
"type": 1,
"icon": "icon-log",
"orderNum": 0,
"ordernum": 0,
"viewPath": "https://cool-js.com",
"keepAlive": true,
"isShow": true
@@ -298,7 +298,7 @@
"perms": null,
"type": 1,
"icon": "icon-favor",
"orderNum": 2,
"ordernum": 2,
"viewPath": "cool/modules/demo/views/editor-quill.vue",
"keepAlive": true,
"isShow": true
@@ -314,7 +314,7 @@
"perms": "base:sys:department:list",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -330,7 +330,7 @@
"perms": "base:sys:department:add",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -346,7 +346,7 @@
"perms": "base:sys:department:update",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -362,7 +362,7 @@
"perms": "base:sys:department:delete",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -378,7 +378,7 @@
"perms": "base:sys:department:order",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -394,7 +394,7 @@
"perms": "base:sys:user:move",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -410,7 +410,7 @@
"perms": null,
"type": 0,
"icon": "icon-common",
"orderNum": 4,
"ordernum": 4,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -426,7 +426,7 @@
"perms": null,
"type": 1,
"icon": "icon-menu",
"orderNum": 0,
"ordernum": 0,
"viewPath": "cool/modules/base/views/param.vue",
"keepAlive": true,
"isShow": true
@@ -442,7 +442,7 @@
"perms": "base:sys:param:add",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -458,7 +458,7 @@
"perms": "base:sys:param:info,base:sys:param:update",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -474,7 +474,7 @@
"perms": "base:sys:param:delete",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -490,7 +490,7 @@
"perms": "base:sys:param:page,base:sys:param:list,base:sys:param:info",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -506,7 +506,7 @@
"perms": null,
"type": 0,
"icon": "icon-radioboxfill",
"orderNum": 99,
"ordernum": 99,
"viewPath": null,
"keepAlive": true,
"isShow": false
@@ -522,7 +522,7 @@
"perms": null,
"type": 1,
"icon": "icon-favor",
"orderNum": 3,
"ordernum": 3,
"viewPath": "cool/modules/demo/views/upload.vue",
"keepAlive": true,
"isShow": true
@@ -538,7 +538,7 @@
"perms": "base:app:im:message:read,base:app:im:message:page,base:app:im:session:page,base:app:im:session:list,base:app:im:session:unreadCount,base:app:im:session:delete",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -554,7 +554,7 @@
"perms": null,
"type": 1,
"icon": "icon-favor",
"orderNum": 0,
"ordernum": 0,
"viewPath": "cool/modules/demo/views/demo.vue",
"keepAlive": true,
"isShow": true
@@ -570,7 +570,7 @@
"perms": null,
"type": 1,
"icon": "icon-user",
"orderNum": 0,
"ordernum": 0,
"viewPath": "cool/modules/base/views/user.vue",
"keepAlive": true,
"isShow": true
@@ -586,7 +586,7 @@
"perms": "base:sys:user:add",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -602,7 +602,7 @@
"perms": "base:sys:user:delete",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -618,7 +618,7 @@
"perms": "base:sys:user:delete,base:sys:user:update",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -634,7 +634,7 @@
"perms": "base:sys:user:page,base:sys:user:list,base:sys:user:info",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -650,7 +650,7 @@
"perms": null,
"type": 0,
"icon": "icon-rank",
"orderNum": 6,
"ordernum": 6,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -666,7 +666,7 @@
"perms": null,
"type": 0,
"icon": "icon-activity",
"orderNum": 5,
"ordernum": 5,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -682,7 +682,7 @@
"perms": null,
"type": 1,
"icon": "icon-menu",
"orderNum": 0,
"ordernum": 0,
"viewPath": "cool/modules/task/views/task.vue",
"keepAlive": true,
"isShow": true
@@ -698,7 +698,7 @@
"perms": "task:info:page,task:info:list,task:info:info,task:info:add,task:info:delete,task:info:update,task:info:stop,task:info:start,task:info:once,task:info:log",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -714,7 +714,7 @@
"perms": null,
"type": 0,
"icon": "icon-log",
"orderNum": 3,
"ordernum": 3,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -730,7 +730,7 @@
"perms": null,
"type": 1,
"icon": "icon-menu",
"orderNum": 1,
"ordernum": 1,
"viewPath": "modules/dict/views/list.vue",
"keepAlive": true,
"isShow": true
@@ -746,7 +746,7 @@
"perms": "dict:info:delete",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -762,7 +762,7 @@
"perms": "dict:info:update,dict:info:info",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -778,7 +778,7 @@
"perms": "dict:info:data",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -794,7 +794,7 @@
"perms": "dict:info:info",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -810,7 +810,7 @@
"perms": "dict:info:list",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -826,7 +826,7 @@
"perms": "dict:info:page",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -842,7 +842,7 @@
"perms": "dict:info:add",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -858,7 +858,7 @@
"perms": "dict:type:list,dict:type:update,dict:type:delete,dict:type:add",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -874,7 +874,7 @@
"perms": null,
"type": 1,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": "modules/demo/views/seer/petbag.vue",
"keepAlive": true,
"isShow": true
@@ -890,7 +890,7 @@
"perms": null,
"type": 1,
"icon": "icon-discover",
"orderNum": 0,
"ordernum": 0,
"viewPath": "modules/demo/views/pinyin.vue",
"keepAlive": true,
"isShow": true
@@ -906,7 +906,7 @@
"perms": null,
"type": 1,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": "modules/demo/views/unzip.vue",
"keepAlive": true,
"isShow": true
@@ -922,7 +922,7 @@
"perms": null,
"type": 1,
"icon": "icon-hot",
"orderNum": 0,
"ordernum": 0,
"viewPath": "modules/demo/views/seer/game.vue",
"keepAlive": true,
"isShow": true
@@ -938,7 +938,7 @@
"perms": null,
"type": 0,
"icon": "icon-task",
"orderNum": 4,
"ordernum": 4,
"viewPath": null,
"keepAlive": true,
"isShow": false
@@ -954,7 +954,7 @@
"perms": "space:info:page,space:info:list,space:info:info,space:info:add,space:info:delete,space:info:update,space:type:page,space:type:list,space:type:info,space:type:add,space:type:delete,space:type:update,dict:type:list,dict:type:page,dict:type:info,dict:type:update,dict:type:delete,dict:type:add,dict:info:list,dict:info:page,dict:info:info,dict:info:update,dict:info:delete,dict:info:add,dict:info:data,base:sys:user:getSession",
"type": 2,
"icon": null,
"orderNum": 1,
"ordernum": 1,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -970,7 +970,7 @@
"perms": "monster:refresh:add",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -986,7 +986,7 @@
"perms": "monster:refresh:delete",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -1002,7 +1002,7 @@
"perms": "monster:refresh:info",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -1018,7 +1018,7 @@
"perms": "monster:refresh:list",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -1034,7 +1034,7 @@
"perms": "monster:refresh:page",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -1050,7 +1050,7 @@
"perms": "monster:refresh:update,monster:refresh:info",
"type": 2,
"icon": null,
"orderNum": 0,
"ordernum": 0,
"viewPath": null,
"keepAlive": true,
"isShow": true
@@ -1066,7 +1066,7 @@
"perms": null,
"type": 1,
"icon": "icon-emoji",
"orderNum": 0,
"ordernum": 0,
"viewPath": "modules/demo/views/monster_refresh.vue",
"keepAlive": true,
"isShow": true
@@ -1082,7 +1082,7 @@
"perms": null,
"type": 1,
"icon": "icon-auth",
"orderNum": 0,
"ordernum": 0,
"viewPath": "modules/crud/views/refresh.vue",
"keepAlive": false,
"isShow": true

View File

@@ -53,7 +53,7 @@ func (s *BaseSysDepartmentService) Order(ctx g.Ctx) (err error) {
type item struct {
Id uint32 `json:"id"`
ParentId *uint32 `json:"parentId,omitempty"`
OrderNum int32 `json:"orderNum"`
ordernum int32 `json:"ordernum"`
}
var data *item

View File

@@ -48,10 +48,10 @@ func (s *BaseSysMenuService) GetMenus(roleIds []string, isAdmin bool) (result gd
m := cool.DBM(s.Model).As("a").Fields("a.*")
var err error
if isAdmin {
result, err = m.Group("a.id").Order("a.orderNum", "asc").All()
result, err = m.Group("a.id").Order(`a.ordernum`, "asc").All()
fmt.Println(err)
} else {
result, _ = m.InnerJoin("base_sys_role_menu b", `a.id=b."menuId"`).Where(`b."roleId" IN (?)`, roleIds).Group("a.id").Order("a.orderNum asc").All()
result, _ = m.InnerJoin("base_sys_role_menu b", `a.id=b."menuId"`).Where(`b."roleId" IN (?)`, roleIds).Group("a.id").Order("a.ordernum asc").All()
}
return

View File

@@ -160,12 +160,12 @@ func NewBaseSysRoleService() *BaseSysRoleService {
)
return [][]interface{}{
{"label != ?", g.Slice{"admin"}, true},
{"(userId=? or id in (?))", g.Slice{userId, admin.RoleIds}, !roleIds.Contains(1)},
{"(userid=? or id in (?))", g.Slice{gconv.String(userId), admin.RoleIds}, !roleIds.Contains(1)},
}
},
},
InsertParam: func(ctx context.Context) map[string]interface{} {
return g.Map{"userId": cool.GetAdmin(ctx).UserId}
return g.Map{`"userid"`: cool.GetAdmin(ctx).UserId}
},
UniqueKey: map[string]string{
"name": "角色名称不能重复",

View File

@@ -287,6 +287,7 @@ func NewBaseSysUserService() *BaseSysUserService {
Where: func(ctx context.Context) []g.Array {
r := g.RequestFromCtx(ctx).GetMap()
return []g.Array{
{"id != ?", g.Slice{"10001"}, true}, //排除管理员
{`("departmentId" IN (?))`, gconv.SliceStr(r["departmentIds"])},
}
},

View File

@@ -304,7 +304,10 @@ func GenPetInfo(
}
}
p.SkillList = p.SkillList[:4]
if len(p.SkillList) > 4 {
p.SkillList = p.SkillList[:4]
}
// ---- 属性计算 ----
p.CalculatePetPane()
p.Hp = p.MaxHp

View File

@@ -58,7 +58,7 @@ func (s *UserService) Person(userid uint32) *model.PlayerInfo {
var tt model.PlayerEX
err := m.Scan(&tt)
if err != nil {
panic(err)
return nil
}
ret := tt.Data
return &ret

View File

@@ -11,7 +11,7 @@ type DictInfo struct {
*cool.Model
TypeID int32 `gorm:"column:typeId;type:int;not null" json:"typeId"` // 类型ID
Name string `gorm:"column:name;type:varchar(255);not null" json:"name"` // 名称
OrderNum int32 `gorm:"column:orderNum;type:int;not null" json:"orderNum"` // 排序
ordernum int32 `gorm:"column:ordernum;type:int;not null" json:"ordernum"` // 排序
Remark *string `gorm:"column:remark;type:varchar(255)" json:"remark"` // 备注
ParentID *int32 `gorm:"column:parentId;type:int" json:"parentId"` // 父ID
}

View File

@@ -5,7 +5,7 @@
"updateTime": "2022-07-06 14:19:10.954000",
"typeId": 1,
"name": "衣服",
"orderNum": 2,
"ordernum": 2,
"remark": null,
"parentId": null
},
@@ -15,7 +15,7 @@
"updateTime": "2022-07-06 14:18:59.834000",
"typeId": 1,
"name": "裤子",
"orderNum": 1,
"ordernum": 1,
"remark": null,
"parentId": null
},
@@ -25,7 +25,7 @@
"updateTime": "2022-07-06 14:19:15.251000",
"typeId": 1,
"name": "鞋子",
"orderNum": 3,
"ordernum": 3,
"remark": null,
"parentId": null
},
@@ -35,7 +35,7 @@
"updateTime": "2022-07-06 14:22:26.131000",
"typeId": 2,
"name": "闪酷",
"orderNum": 2,
"ordernum": 2,
"remark": null,
"parentId": null
},
@@ -45,7 +45,7 @@
"updateTime": "2022-07-06 14:22:18.309000",
"typeId": 2,
"name": "SUN",
"orderNum": 1,
"ordernum": 1,
"remark": null,
"parentId": null
}

View File

@@ -35,7 +35,7 @@ func (s *DictInfoService) Data(ctx context.Context, types []string) (data interf
data = g.Map{}
for _, v := range typeData {
m := cool.DBM(dictInfoModel)
result, err := m.Where("typeId", v["id"]).Fields("id", "name", "parentId", "typeId").Order("orderNum asc").All()
result, err := m.Where("typeId", v["id"]).Fields("id", "name", "parentId", "typeId").Order("ordernum asc").All()
if err != nil {
return nil, err
}