optimize and add cdkey

This commit is contained in:
likun 2025-05-07 15:03:19 +08:00
parent a2897f288e
commit bc368e96cf
26 changed files with 749 additions and 71 deletions

View File

@ -27,7 +27,7 @@ func initCommonResourcesRepo(db *gorm.DB) {
r(consts.ResourcesName_MailRole, "个人邮件", repo.NewCommonResourceRepo(db, &model.RoleMail{}), ShowMethod_Get|ShowMethod_Post) // 个人邮件发放就没法撤回?
r(consts.ResourcesName_MailGlobal, "全服邮件", repo.NewCommonResourceRepo(db, &model.GlobalMail{}), ShowMethod_Get|ShowMethod_Post) // 直接删除,别修改了,玩家收到的更乱
r(consts.ResourcesName_Notice, "公告", repo.NewCommonResourceRepo(db, &model.Notice{}), ShowMethod_Get|ShowMethod_Post|ShowMethod_Put|ShowMethod_Delete)
r(consts.ResourcesName_RewardCode, "奖励码", repo.NewCommonResourceRepo(db, &model.RewardCode{}), ShowMethod_Get)
r(consts.ResourcesName_RewardCode, "奖励码", repo.NewCommonResourceRepo(db, &model.CDKey{}), ShowMethod_Get)
r(consts.ResourcesName_DevicePush, "设备推送", repo.NewCommonResourceRepo(db, &model.DevicePush{}), ShowMethod_Get)
}

View File

@ -0,0 +1,22 @@
package entity
import (
"admin/apps/game/model"
"admin/lib/cdkey"
)
var MaxKeyNum = 100000 // 每个批次直接搞10w个不然运营想补加码算法又要一开始定好数量
type CDKey struct {
Po *model.CDKey
}
func NewCDKey(po *model.CDKey) *CDKey {
return &CDKey{
Po: po,
}
}
func (c *CDKey) GenerateKeys() []string {
return cdkey.GenerateAll(c.Po.ID, MaxKeyNum)[:c.Po.CodeNum]
}

View File

@ -16,6 +16,7 @@ var projectsResourceHookMgr = map[string]map[string]any{
consts.ResourcesName_Ban: &smdl.BanHook{}, // 所有角色走神魔大陆api直接获取
consts.ResourcesName_MailGlobal: &smdl.MailGlobalHook{}, // 所有角色走神魔大陆api直接获取
consts.ResourcesName_MailRole: &smdl.MailRoleHook{}, // 所有角色走神魔大陆api直接获取
consts.ResourcesName_WhiteList: &smdl.WhitelistHook{}, // 所有角色走神魔大陆api直接获取
},
}

View File

@ -11,12 +11,12 @@ type Items struct {
}
func (items *Items) GetItems(projectInfo *entity.Project) ([]*dto.CommonDtoFieldChoice, error) {
return []*dto.CommonDtoFieldChoice{
{Desc: "黄金战甲", Value: 123, Type: 1},
{Desc: "黄金头盔", Value: 234, Type: 1},
{Desc: "黄金大刀", Value: 346, Type: 1},
{Desc: "白银大刀", Value: 346, Type: 1},
}, nil
//return []*dto.CommonDtoFieldChoice{
// {Desc: "黄金战甲", Value: 123, Type: 1},
// {Desc: "黄金头盔", Value: 234, Type: 1},
// {Desc: "黄金大刀", Value: 346, Type: 1},
// {Desc: "白银大刀", Value: 346, Type: 1},
//}, nil
alisrvAddr := projectInfo.GetApiAddr()
if alisrvAddr == "" {
return nil, errcode.New(errcode.ServerError, "项目%v没有配置api服务器地址", projectInfo.Po.Name)

View File

@ -0,0 +1,63 @@
package smdl
import (
"admin/apps/game/domain/entity"
"admin/apps/game/model"
"admin/apps/game/model/dto"
"admin/internal/errcode"
"admin/lib/httpclient"
"net/url"
)
type WhitelistHook struct {
}
func (hook *WhitelistHook) Create(projectInfo *entity.Project, resource string, dtoObj dto.CommonDtoValues) error {
alisrvAddr := projectInfo.GetApiAddr()
if alisrvAddr == "" {
return errcode.New(errcode.ServerError, "项目%v没有配置api服务器地址", projectInfo.Po.Name)
}
et := (&entity.CommonResource{}).FromPo(&model.RoleMail{}).FromDto(dtoObj)
whiteInfo := et.ToPo().(*model.WhiteList)
params := &url.Values{}
params.Add("cmd_data", "OpWhitelist")
params.Add("type", whiteInfo.WType)
params.Add("value", whiteInfo.Value)
params.Add("op", "add")
params.Add("server", whiteInfo.ServerConfID)
rsp := make(map[string]any)
err := httpclient.Request(alisrvAddr+"/gm", "get", params, &rsp)
if err != nil {
return errcode.New(errcode.ServerError, "发送新增白名单请求:%+v错误:%v", whiteInfo, err)
}
return nil
}
func (hook *WhitelistHook) Delete(projectInfo *entity.Project, resource string, dtoObj dto.CommonDtoValues) error {
alisrvAddr := projectInfo.GetApiAddr()
if alisrvAddr == "" {
return errcode.New(errcode.ServerError, "项目%v没有配置api服务器地址", projectInfo.Po.Name)
}
et := (&entity.CommonResource{}).FromPo(&model.RoleMail{}).FromDto(dtoObj)
whiteInfo := et.ToPo().(*model.WhiteList)
params := &url.Values{}
params.Add("cmd_data", "OpWhitelist")
params.Add("type", whiteInfo.WType)
params.Add("value", whiteInfo.Value)
params.Add("op", "remove")
params.Add("server", whiteInfo.ServerConfID)
rsp := make(map[string]any)
err := httpclient.Request(alisrvAddr+"/gm", "get", params, &rsp)
if err != nil {
return errcode.New(errcode.ServerError, "发送删除白名单请求:%+v错误:%v", whiteInfo, err)
}
return nil
}

View File

@ -11,7 +11,7 @@ func init() {
// Account 空表就是用来兼容资源增删改查公共操作的实际列举账号等都是走各个项目api拉取
type Account struct {
ProjectId int
ProjectId int `gorm:"index:idx_project_id"`
Account string `name:"账号" json:"account" where:"eq"`
ServerConfId string `name:"区服id" json:"serveId" where:"eq"`
RoleIds []string `gorm:"type:json;serializer:json" name:"角色id列表" json:"roleIds"`

View File

@ -0,0 +1,41 @@
package model
import (
"admin/apps/game/model/dto"
"admin/internal/db"
"time"
)
func init() {
db.RegisterTableModels(CDKey{})
}
type CDKey struct {
ID int `gorm:"primarykey" readonly:"true"`
ProjectId int `gorm:"index:idx_project_id"`
Desc string `name:"礼包说明" required:"true"`
ServerIDs []string `gorm:"type:json;serializer:json" name:"区服" type:"[]string" choices:"GetChoiceServers" multi_choice:"true"`
CodeType int `name:"礼包类型" required:"true" choices:"GetCodeTypeChoices"`
Code string `name:"礼包码" desc:"一码通用才配置"`
CodeNum int `name:"礼包数量" desc:"一码一用才配置"`
ValidStartTime time.Time `name:"生效起始时间"`
ValidEndTime time.Time `name:"生效结束时间"`
RewardList []*MailAttachItem `gorm:"type:json;serializer:json" name:"邮件附件" type:"items" desc:"搜索道具并点击添加"`
CreatedAt time.Time `readonly:"true"`
}
func (lm *CDKey) TableName() string {
return "cdkey"
}
func (m *CDKey) GetId() int {
return m.ID
}
func (m *CDKey) GetCodeTypeChoices() []*dto.CommonDtoFieldChoice {
return []*dto.CommonDtoFieldChoice{
{Desc: "一码通用", Value: 0},
{Desc: "一码一用", Value: 1},
}
}

View File

@ -0,0 +1,29 @@
package model
import (
"admin/internal/db"
"time"
)
func init() {
db.RegisterTableModels(CDKeyUsed{})
}
type CDKeyUsed struct {
ID int `gorm:"primarykey" readonly:"true"`
ProjectId int `gorm:"index:idx_project_id"`
ServerID string `name:"所属区服" choices:"GetChoiceServers" required:"true" where:"eq"`
Account string `gorm:"type:varchar(255);index:idx_account"`
RoleID string `gorm:"type:varchar(255);index:idx_role_id"`
RoleName string `gorm:"type:varchar(255)"`
Key string `gorm:"type:varchar(255);index:idx_key"`
CreatedAt time.Time `readonly:"true"`
}
func (lm *CDKeyUsed) TableName() string {
return "cdkey_used"
}
func (m *CDKeyUsed) GetId() int {
return m.ID
}

View File

@ -11,8 +11,8 @@ func init() {
}
type GlobalMail struct {
ID int `gorm:"primarykey" readonly:"true"`
ProjectId int
ID int `gorm:"primarykey" readonly:"true"`
ProjectId int `gorm:"index:idx_project_id"`
ServerIDs []string `gorm:"type:json;serializer:json" name:"区服" type:"[]string" choices:"GetChoiceServers" multi_choice:"true"`
Title string `name:"邮件标题" required:"true"`
Content string `name:"邮件内容" required:"true"`

View File

@ -11,8 +11,8 @@ func init() {
}
type Notice struct {
ID int `gorm:"primarykey" readonly:"true"`
ProjectId int
ID int `gorm:"primarykey" readonly:"true"`
ProjectId int `gorm:"index:idx_project_id"`
ServerIDs []int `gorm:"type:json;serializer:json" name:"公告生效服务器" desc:"为空表示所有服" choices:"GetChoiceServers"`
Content string `name:"公告内容" required:"true"`
StartAt time.Time `name:"开始时间" required:"true"`

View File

@ -1,27 +0,0 @@
package model
import (
"admin/internal/db"
"time"
)
func init() {
db.RegisterTableModels(RewardCode{})
}
type RewardCode struct {
ID int `gorm:"primarykey" readonly:"true"`
ProjectId int
Group int `name:"奖励码组"`
Code int `name:"奖励码"`
CreatedAt time.Time `readonly:"true"`
}
func (lm *RewardCode) TableName() string {
return "reward_code"
}
func (m *RewardCode) GetId() int {
return m.ID
}

View File

@ -17,8 +17,8 @@ type MailAttachItem struct {
}
type RoleMail struct {
ID int `gorm:"primarykey" readonly:"true"`
ProjectId int
ID int `gorm:"primarykey" readonly:"true"`
ProjectId int `gorm:"index:idx_project_id"`
RoleIDs []string `gorm:"type:json;serializer:json" name:"生效的角色id" desc:"生效的角色id逗号分隔多个" required:"true"`
ServerID string `name:"所属区服" choices:"GetChoiceServers" required:"true" where:"eq"`
Title string `name:"邮件标题" required:"true"`

View File

@ -13,9 +13,9 @@ func init() {
type WhiteList struct {
ID int `gorm:"primarykey" readonly:"true"`
ProjectId int `gorm:"uniqueIndex:idx_whitelist"`
ServerConfID string `gorm:"type:varchar(200);uniqueIndex:idx_server" name:"区服id" required:"true" choices:"GetChoiceServers" where:"eq"`
Account string `gorm:"type:varchar(128);uniqueIndex:idx_whitelist" name:"账户" required:"true"`
Desc string `name:"描述"`
ServerConfID string `gorm:"type:varchar(200);uniqueIndex:idx_whitelist;index:idx_server" name:"区服id" required:"true" choices:"GetChoiceServers" where:"eq"`
WType string `name:"白名单类型" desc:"账号或者ip" required:"true" choices:"GetWhitelistTypeChoices"`
Value string `gorm:"type:varchar(128);uniqueIndex:idx_whitelist" name:"账户" required:"true"`
CreatedAt time.Time `readonly:"true" where:"range"`
}
@ -31,3 +31,10 @@ func (m *WhiteList) GetId() int {
func (m *WhiteList) GetChoiceServers(project *Project) []*dto.CommonDtoFieldChoice {
return getChoiceServers(project)
}
func (m *WhiteList) GetWhitelistTypeChoices(project *Project) []*dto.CommonDtoFieldChoice {
return []*dto.CommonDtoFieldChoice{
{Desc: "IP", Value: "ip"},
{Desc: "账号", Value: "account"},
}
}

View File

@ -8,7 +8,11 @@ import (
func (ctl *controller) CommonList(ctx *context.WebContext, params *dto.CommonListReq, rsp *dto.CommonListRsp) error {
projectId, resource := getCtxURIProjectIdAndResource(ctx)
list, err := ctl.svc.CommonList(ctx, projectId, resource, params)
ctx1 := stdContext.WithValue(ctx.Context, "user_id", ctx.Header.UserId)
ctx1 = stdContext.WithValue(ctx1, "user_name", ctx.Header.UserName)
list, err := ctl.svc.CommonList(ctx1, projectId, resource, params)
if err != nil {
return err
}
@ -20,7 +24,7 @@ func (ctl *controller) CommonPost(ctx *context.WebContext, params *dto.CommonPos
projectId, resource := getCtxURIProjectIdAndResource(ctx)
ctx1 := stdContext.WithValue(ctx.Context, "user_id", ctx.Header.UserId)
ctx1 = stdContext.WithValue(ctx1, "user_name", ctx.Header.UserId)
ctx1 = stdContext.WithValue(ctx1, "user_name", ctx.Header.UserName)
newObj, err := ctl.svc.CommonPost(ctx1, projectId, resource, *params.Dto)
if err != nil {
@ -32,7 +36,11 @@ func (ctl *controller) CommonPost(ctx *context.WebContext, params *dto.CommonPos
func (ctl *controller) CommonPut(ctx *context.WebContext, params *dto.CommonPutReq, rsp *dto.CommonPutRsp) error {
projectId, resource := getCtxURIProjectIdAndResource(ctx)
err := ctl.svc.CommonPut(ctx, projectId, resource, *params.Dto)
ctx1 := stdContext.WithValue(ctx.Context, "user_id", ctx.Header.UserId)
ctx1 = stdContext.WithValue(ctx1, "user_name", ctx.Header.UserName)
err := ctl.svc.CommonPut(ctx1, projectId, resource, *params.Dto)
if err != nil {
return err
}
@ -42,7 +50,11 @@ func (ctl *controller) CommonPut(ctx *context.WebContext, params *dto.CommonPutR
func (ctl *controller) CommonDelete(ctx *context.WebContext, params *dto.CommonDeleteReq, rsp *dto.CommonDeleteRsp) error {
projectId, resource := getCtxURIProjectIdAndResource(ctx)
err := ctl.svc.CommonDelete(ctx, projectId, resource, params.Id)
ctx1 := stdContext.WithValue(ctx.Context, "user_id", ctx.Header.UserId)
ctx1 = stdContext.WithValue(ctx1, "user_name", ctx.Header.UserName)
err := ctl.svc.CommonDelete(ctx1, projectId, resource, params.Id)
if err != nil {
return err
}

View File

@ -12,14 +12,14 @@ func init() {
// History 用户执行历史
type History struct {
ID int `gorm:"primarykey" readonly:"true"`
UserId int
UserName string
ProjectId int
Resource string
Method string
Data string `gorm:"type:longtext"`
CreateTime time.Time
ID int `gorm:"primarykey" readonly:"true"`
UserId int
UserName string
ProjectId int
Resource string
Method string
Data string `gorm:"type:longtext"`
CreatedAt time.Time
}
func (m *History) TableName() string {

View File

@ -14,10 +14,12 @@ type Server struct {
}
func New(svc *service.Service) *Server {
return &Server{
srv := &Server{
svc: svc,
ctl: newController(svc),
}
srv.jobsSubscribe()
return srv
}
func (srv *Server) jobsSubscribe() {
@ -30,6 +32,7 @@ func (srv *Server) subscriberHandlerUserExecute(msg *event.Msg) {
err := json.Unmarshal(msg.Payload, msgHistory)
if err != nil {
xlog.Errorf("unmarshal msg(%+v) err:%v", string(msg.Payload), err)
return
}
po.UserId = msgHistory.UserId

View File

@ -23,7 +23,7 @@ type WebContext struct {
}
func NewWebContext(rawCtx *gin.Context) web.IContext {
return &WebContext{rawCtx: rawCtx}
return &WebContext{Context: context.Background(), rawCtx: rawCtx}
}
func (ctx *WebContext) ExtractHeader() error {

57
admin/lib/cdkey/bitmap.go Normal file
View File

@ -0,0 +1,57 @@
package cdkey
import "fmt"
type bitmap struct {
size int
set int64
}
func newBitmap(size int, set int64) *bitmap {
if size < 0 || size > 63 {
panic("size must be between 0 and 63")
}
if size == 0 {
size = 32
}
m := &bitmap{size: size, set: set}
return m
}
func (m *bitmap) Get(index int) bool {
return m.GetInt(index) != 0
}
func (m *bitmap) GetInt(index int) int64 {
if index < 0 || index >= m.size {
panic(fmt.Errorf("index out of range:%v", index))
}
if m.set&(1<<uint(index)) != 0 {
return 1
}
return 0
}
func (m *bitmap) Set(index int, value bool) {
if index < 0 || index >= m.size {
panic(fmt.Errorf("index out of range:%v", index))
}
if value {
m.set |= 1 << uint(index)
} else {
m.set &^= 1 << uint(index)
}
}
func (m *bitmap) Clear() {
m.set = 0
}
func (m *bitmap) toInt64() int64 {
return m.set
}
func (m *bitmap) GetSize() int {
return m.size
}

124
admin/lib/cdkey/cdkey.go Normal file
View File

@ -0,0 +1,124 @@
package cdkey
/*
* 奖励码模块从神魔大陆java代码移植过来的
*/
func GenerateAll(batch int, totalCount int) []string {
keyList := make([]string, 0, totalCount)
for i := 0; i < totalCount; i++ {
codeKey := GenerateOne(batch, totalCount, i)
keyList = append(keyList, codeKey)
}
return keyList
}
func GenerateOne(batch int, totalCount int, curNo int) string {
base := MAXNUM / totalCount
numId := curNo
num := base + numId*base
mainKeyBitSet := newBitmap(MAIN_KEY_LENGTH, 0)
numKeyIndex := int((num + batch) % NUM_KEY_LENGTH_BINARY)
temp := newEncode(int64(num), numKeyIndex)
for i := 0; i < MAIN_KEY_NUM_LENGTH; i++ {
mainKeyBitSet.Set(i, (temp&1) == 1)
temp >>= 1
}
for i := 0; i < NUM_KEY_LENGTH; i++ {
mainKeyBitSet.Set(i+MAIN_KEY_NUM_LENGTH, toNumBitSet[numKeyIndex].Get(i))
}
var beCheckNum int64
if mainKeyBitSet.toInt64() > 0 {
beCheckNum = mainKeyBitSet.toInt64()
} else {
beCheckNum = -mainKeyBitSet.toInt64()
}
checkNum := int32(beCheckNum % 32)
checkNumBitSet := toBitSet32[checkNum]
for i := 0; i < CHECK_LENGTH; i++ {
mainKeyBitSet.Set(i+MAIN_KEY_NUM_LENGTH+NUM_KEY_LENGTH, checkNumBitSet.Get(i))
}
batchBitSet := newBitmap(BATCH_LENGTH, 0)
temp = int64(batch)
for i := 0; i < BATCH_LENGTH; i++ {
batchBitSet.Set(i, (temp&1) == 1)
temp >>= 1
}
batchKeyIndex := (num + batch) % BATCH_KEY_LENGTH_BINARY
batchStr := base32Encode(fakeRC4Encode(batchBitSet, batchKey[batchKeyIndex]))
temp1 := fakeRC4Encode(mainKeyBitSet, getMainKey(batchBitSet))
mainKeyStr := base32Encode(temp1)
cdKeyType := 1
typeIndex := (num + cdKeyType) % TYPE_LENGTH_BINARY
codeKey := mainKeyStr + batchStr + string(toBase32[batchKeyIndex]) + string(toBase32[typeIndex])
return shuffleCDKey(codeKey, batchKeyIndex)
}
type CDKeyInfo struct {
Batch int
Num int64
}
func DecodeCDKey(cdKey string) (*CDKeyInfo, bool) {
if len(cdKey) != CDKEY_LENGTH {
return nil, false
}
index := toBase32CToI[rune(cdKey[SHUFFLE_INDEX])]
cdKey1 := recoverCDKey(cdKey[0:SHUFFLE_INDEX], index)
if cdKey1 == "" {
return nil, false
}
typeCheck, find := toBase32CToI[rune(cdKey1[TYPE_INDEX])]
if !find {
return nil, false
}
batchKeyIndex, find := toBase32CToI[rune(cdKey1[BATCH_NUM_BEGIN])]
if !find {
return nil, false
}
if !(batchKeyIndex == index) {
return nil, false
}
batch := base32Decode(cdKey1[BATCH_BEGIN:BATCH_END])
if batch == nil {
return nil, false
}
batchBitSet := fakeRC4Encode(batch, batchKey[batchKeyIndex])
if batchBitSet == nil {
return nil, false
}
mainKey := base32Decode(cdKey1[MAIN_KEY_BEGIN:MAIN_KEY_END])
if mainKey == nil {
return nil, false
}
mainKey2 := getMainKey(batchBitSet)
if mainKey2 == nil {
return nil, false
}
mainKeyBitSet := fakeRC4Encode(mainKey, mainKey2)
if mainKeyBitSet == nil {
return nil, false
}
if !(check(mainKeyBitSet)) {
return nil, false
}
numKeyIndex := getNumKeyIndex(mainKeyBitSet)
numInt := numEncode(mainKeyBitSet.toInt64()&intFormat, numKeyIndex)
batchInt := int(batchBitSet.toInt64() & intFormat)
if !(checkIndex(numInt, batchInt, batchKeyIndex, numKeyIndex)) {
return nil, false
}
cdkeyInfo := &CDKeyInfo{
Batch: batchInt,
Num: numInt,
// Type: typeCheck,
}
if typeCheck > 0 {
}
return cdkeyInfo, true
}

View File

@ -0,0 +1,19 @@
package cdkey
import (
"fmt"
"testing"
)
func TestCDKey(t *testing.T) {
for i, key := range GenerateAll(2, 100000) {
if i > 10 {
continue
}
info, ok := DecodeCDKey(key)
if !ok {
panic(key)
}
fmt.Printf("%s, info:%+v\n", key, info)
}
}

311
admin/lib/cdkey/utils.go Normal file
View File

@ -0,0 +1,311 @@
package cdkey
import (
"math"
"math/rand"
)
const (
MAXNUM = math.MaxInt32 - 20000000
CDKEY_LENGTH = 15
MAIN_KEY_LENGTH = 40
NUM_KEY_LENGTH_BINARY = 8
MAIN_KEY_NUM_LENGTH = 32
NUM_KEY_LENGTH = 3
CHECK_LENGTH = 5
BATCH_LENGTH = 20
BATCH_KEY_LENGTH_BINARY = 32
TYPE_LENGTH_BINARY = 32
shuffleLength = 32
exceptShuffleSeedTotalLength = 70
SHUFFLE_INDEX = 14
TYPE_INDEX = 13
BATCH_NUM_BEGIN = 12
BATCH_BEGIN = 8
BATCH_END = 12
MAIN_KEY_BEGIN = 0
MAIN_KEY_END = 8
mainKeyFormat int64 = 34359738367
checkNumFormat int64 = 1065151889408
CHECK_LENGTH_BINARY = 32
)
var toBase32 = []rune{'2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}
var toBase32CToI map[rune]int
var mainKeyBatchKey = newBitmap(20, 1918215104086)
var intFormat int64 = 4294967295
var key = newBitmap(20, 1209617303503)
var shuffleMap = make(map[int][]int)
var numKey = []int64{
3000669867,
3671239387,
2526368469,
2493864681,
3604110165,
3567998377,
2763216037,
2863360677,
}
var batchKey = []*bitmap{
newBitmap(20, 31511741981182095),
newBitmap(20, 3664122353341979125),
newBitmap(20, 3024789513220408272),
newBitmap(20, 7614911559402769357),
newBitmap(20, 2108459002177461007),
newBitmap(20, -3779584974404014377),
newBitmap(20, -4708816669881919040),
newBitmap(20, -6362362468306307184),
newBitmap(20, 5237470582631498811),
newBitmap(20, 5507680150663927504),
newBitmap(20, -533592023685287698),
newBitmap(20, 5175063634818869382),
newBitmap(20, -8744795741519816883),
newBitmap(20, -4080090257317771786),
newBitmap(20, -8036132546007449313),
newBitmap(20, 202953352259602475),
newBitmap(20, 1095317292689077154),
newBitmap(20, 2991873574004670411),
newBitmap(20, -6707239314758981218),
newBitmap(20, 7712241472074747715),
newBitmap(20, -8133590642362246474),
newBitmap(20, -4968343163714505661),
newBitmap(20, -6905628074578549760),
newBitmap(20, 5195681389062354029),
newBitmap(20, -5910830154906229288),
newBitmap(20, -1676518468791541432),
newBitmap(20, -7994149653806568719),
newBitmap(20, -7378005837432330374),
newBitmap(20, 1068884024847281324),
newBitmap(20, 1945505497196485942),
newBitmap(20, -3492268017556027220),
newBitmap(20, 7364928014934311923),
}
var toNumBitSet [NUM_KEY_LENGTH_BINARY]*bitmap
var toBitSet32 [32]*bitmap
func init() {
for i := 0; i < 32; i++ {
temp := i
toBitSet32[i] = newBitmap(5, 0)
for j := 0; j < 5; j++ {
toBitSet32[i].Set(j, (temp&1) == 1)
temp >>= 1
}
}
for i := 0; i < NUM_KEY_LENGTH_BINARY; i++ {
temp := i
toNumBitSet[i] = newBitmap(NUM_KEY_LENGTH, 0)
for j := 0; j < NUM_KEY_LENGTH; j++ {
toNumBitSet[i].Set(j, (temp&1) == 1)
temp >>= 1
}
}
toBase32CToI = make(map[rune]int)
for i := 0; i < len(toBitSet32); i++ {
toBase32CToI[toBase32[i]] = i
}
for seed := 0; seed < shuffleLength; seed++ {
array := make([]int, exceptShuffleSeedTotalLength)
for i := 0; i < exceptShuffleSeedTotalLength; i++ {
array[i] = i
}
shuffle(array, rand.New(rand.NewSource(int64(seed))))
shuffleMap[seed] = array
}
}
func checkIndex(num int64, batch int, batchKeyIndex int, numKeyIndex int) bool {
return (num+int64(batch))%BATCH_KEY_LENGTH_BINARY == int64(batchKeyIndex) && (num+int64(batch))%NUM_KEY_LENGTH_BINARY == int64(numKeyIndex)
}
func numEncode(num int64, index int) int64 {
return numKey[index] ^ num
}
func getNumKeyIndex(mainKeyBitSet *bitmap) int {
bitset := newBitmap(NUM_KEY_LENGTH, 0)
for i := 0; i < bitset.GetSize(); i++ {
bitset.Set(i, mainKeyBitSet.Get(MAIN_KEY_NUM_LENGTH+i))
}
return int(bitset.toInt64())
}
func check(mainkeyBitSet *bitmap) bool {
mainkey := mainkeyBitSet.toInt64()
if mainkey <= 0 {
mainkey = -mainkey
}
beCheckNum := mainkey & mainKeyFormat
checkNum := mainkey & checkNumFormat
checkNum >>= (MAIN_KEY_NUM_LENGTH + NUM_KEY_LENGTH)
return beCheckNum%CHECK_LENGTH_BINARY == checkNum
}
func base32Decode(data string) *bitmap {
if len(data) > 63/5 {
return nil
}
bitset := newBitmap(len(data)*5, 0)
i := 0
for _, c := range data {
if _, find := toBase32CToI[c]; !find {
return nil
}
index := toBase32CToI[c]
letterBitSet := toBitSet32[index]
for j := 0; j < 5; j++ {
bitset.Set(i, letterBitSet.Get(j))
i++
}
}
return bitset
}
func recoverCDKey(cdKey string, index int) string {
array := shuffleMap[index]
if array == nil {
return ""
}
bytes := base32DecodeReturnByteArray(cdKey)
if bytes == nil {
return ""
}
if len(array) != len(bytes) {
return ""
}
resultByte := make([]byte, len(bytes))
for i := 0; i < len(array); i++ {
resultByte[array[i]] = bytes[i]
}
return base32Encode1(resultByte)
}
func shuffleCDKey(key string, index int) string {
array := shuffleMap[index]
bytes := base32DecodeReturnByteArray(key)
resultByte := make([]byte, len(bytes))
for i := 0; i < len(array); i++ {
resultByte[i] = bytes[array[i]]
}
return base32Encode1(resultByte) + string(toBase32[index])
}
func shuffle(array []int, rander *rand.Rand) {
for i := len(array); i > 1; i-- {
swap(array, i-1, rander.Intn(i))
}
}
func swap(array []int, i, j int) {
array[i], array[j] = array[j], array[i]
}
func newEncode(num int64, index int) int64 {
return numKey[index] ^ num
}
func base32Encode(m *bitmap) string {
if m.GetSize()%5 != 0 {
return ""
}
stringBuilder := ""
for i := 0; i < m.GetSize(); i += 5 {
bitset1 := newBitmap(5, 0)
for j := 0; j < 5; j++ {
bitset1.Set(j, m.Get(i+j))
}
if bitset1.toInt64() >= int64(len(toBase32)) {
return ""
}
letter := toBase32[int(bitset1.toInt64())]
stringBuilder += string(letter)
}
return stringBuilder
}
func base32Encode1(bytes []byte) string {
if len(bytes)%5 != 0 {
return ""
}
stringBuilder := ""
for i := 0; i < len(bytes); i += 5 {
bitset1 := newBitmap(5, 0)
for j := 0; j < 5; j++ {
bitset1.Set(j, bytes[i+j] > 0)
}
if bitset1.toInt64() >= int64(len(toBase32)) {
return ""
}
letter := toBase32[int(bitset1.toInt64())]
stringBuilder += string(letter)
}
return stringBuilder
}
func fakeRC4Encode(data, key *bitmap) *bitmap {
if data.GetSize() != key.GetSize() {
return nil
}
bitSet := newBitmap(data.GetSize(), 0)
for i := 0; i < data.GetSize(); i++ {
bitSet.Set(i, data.GetInt(i)^key.GetInt(i) == 1)
}
return bitSet
}
func getMainKey(batch *bitmap) *bitmap {
bitSet := newBitmap(MAIN_KEY_LENGTH, 0)
batchKey := fakeRC4Encode(batch, mainKeyBatchKey)
if batchKey == nil {
return nil
}
index := (int)(batchKey.toInt64()&intFormat) % key.GetSize()
count := 0
for i := 0; i < index; i++ {
bitSet.Set(count, key.Get(i))
count++
}
for i := 0; i < batchKey.GetSize(); i++ {
bitSet.Set(count, batchKey.Get(i))
count++
}
for i := index; i < key.GetSize(); i++ {
bitSet.Set(count, key.Get(i))
count++
}
return bitSet
}
func base32DecodeReturnByteArray(data string) []byte {
bytes := make([]byte, len(data)*5)
i := 0
for _, c := range data {
if _, find := toBase32CToI[c]; !find {
return nil
}
index := toBase32CToI[c]
letterBitSet := toBitSet32[index]
for j := 0; j < 5; j++ {
bitValue := letterBitSet.Get(j)
if bitValue {
bytes[i] = 1
} else {
bytes[i] = 0
}
i++
}
}
return bytes
}

View File

@ -1,2 +1,2 @@
VITE_APP_BASE_API = '/api'
VITE_APP_BASE_URL = 'http://localhost:8080/api'
VITE_APP_BASE_URL = 'http://192.168.78.128:8080/api'

View File

@ -98,7 +98,7 @@ const listData = async () => {
calcElColSpan.value = 0
// el-col24span
let calcElColSpanTmp = 1
let calcElColSpanTmp = 2
whereFieldsDescInfo.value.forEach((field) => {
if (field.where === "range") {
calcElColSpanTmp += 2
@ -106,9 +106,9 @@ const listData = async () => {
calcElColSpanTmp += 1
}
})
calcElColSpan.value = 24/calcElColSpanTmp
calcElColSpan.value = 24 / calcElColSpanTmp
console.log("where fields:", whereFieldsDescInfo.value)
// console.log("where fields:", whereFieldsDescInfo.value)
// console.log('await list rsp:', listRsp.value, fieldsDescInfo.value, toRaw(rows.value), toRaw(rules.value))
listDataOK.value = true
@ -270,7 +270,7 @@ const handleQueryItem = (itemQueryStr) => {
itemQueryStr = itemQueryStr.replace(/[\s\u3000]/g, "")
resourceGetAllItems(projectId).then((res) => {
console.log("获取所有道具返回:", res.data)
console.log("查询字符串:[" + itemQueryStr + "]")
console.log("查询字符串:[" + itemQueryStr + "]")
itemChoices.value = res.data.items.filter((item) => {
return item.desc.includes(itemQueryStr)
})
@ -280,6 +280,14 @@ const handleQueryItem = (itemQueryStr) => {
})
}
const resetConditionSearch = () => {
for (let i = 0; i < whereFieldsDescInfo.value.length; i++) {
let field = whereFieldsDescInfo.value[i]
field.value1 = null
field.value2 = null
}
}
</script>
<template>
@ -299,13 +307,14 @@ const handleQueryItem = (itemQueryStr) => {
</el-col>
<el-col :span="calcElColSpan">
<el-date-picker v-model="fieldDescInfo.value2" type="datetime"
:placeholder="(fieldDescInfo.name + '结束')" format="YYYY/MM/DD HH:mm:ss"
value-format="YYYY/MM/DD HH:mm:ss"></el-date-picker>
:placeholder="(fieldDescInfo.name + '结束')" format="YYYY/MM/DD HH:mm:ss"
value-format="YYYY/MM/DD HH:mm:ss"></el-date-picker>
</el-col>
</template>
<template v-else>
<el-col :span="calcElColSpan">
<el-select v-model="fieldDescInfo.value1" :placeholder="(fieldDescInfo.multi_choice === true ? '--多选--' : '--单选--')"
<el-select v-model="fieldDescInfo.value1"
:placeholder="(fieldDescInfo.multi_choice === true ? '--' + fieldDescInfo.name + '--' : '--' + fieldDescInfo.name + '--')"
style="width: 150px"
filterable v-if="(fieldDescInfo.choices.length > 0)">
<el-option v-for="choice in fieldDescInfo.choices" :key="choice.value" :label="choice.desc"
@ -320,6 +329,9 @@ const handleQueryItem = (itemQueryStr) => {
<el-col :span="calcElColSpan">
<el-button @click="listData" type="primary">条件搜索</el-button>
</el-col>
<el-col :span="calcElColSpan">
<el-button @click="resetConditionSearch">清空条件</el-button>
</el-col>
</el-row>
<el-row style="margin-top: 10px">

View File

@ -49,7 +49,7 @@ router.beforeEach((to, from, next) => {
LocalCache.deleteCache("projectsRoute")
})
} else {
// console.log("访问页面" + to.path + "已经请求过用户数据,跳过获取")
console.log("访问页面" + to.path + "已经请求过用户数据,跳过获取")
// console.log("op tree routes length valid:", projectOpTreeRoutes.value.length)
next()
}

View File

@ -18,7 +18,7 @@ const activeMenu = computed(() => route.path)
const hasClickedMenu = ref(false)
router.push("/welcome")
// router.push("/welcome")
const handleEnterIndex = () => {
router.push("/welcome")

View File

@ -1,7 +1,11 @@
# todo列表
- [x] 道具列表选择支持远程搜索(避免道具列表太长卡顿)
- [ ] 表格各种项目支持分页(难点是账户、角色、订单如何分)
- [ ] 表格各种项目支持分页(难点是账户、角色、订单这种来自各个游戏区服数据如何分)
- [ ] 表格字段排序
- [ ] 表格字段搜索
- [x] 表格字段搜索
- [ ] 表格定制化按钮,比如服务器列表支持单个服务器维护、一键维护(难点是带页面跳转的比如角色列表快速封禁)
- [ ] 执行历史记录
- [x] 执行历史记录
- [ ] 执行历史查看和条件检索
- [ ] 公告发送游戏
- [ ] 奖励码接入