修复好多

This commit is contained in:
likun 2025-05-14 18:09:20 +08:00
parent 647575c34d
commit 5f9156137f
27 changed files with 561 additions and 58 deletions

View File

@ -42,6 +42,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_CDKey, "礼包码", repo.NewCommonResourceRepo(db, &model.CDKey{}), ShowMethod_Get|ShowMethod_Post|ShowMethod_Put|ShowMethod_Delete)
r(consts.ResourcesName_ItemBag, "道具礼包", repo.NewCommonResourceRepo(db, &model.ItemBag{}), ShowMethod_Get|ShowMethod_Post|ShowMethod_Put|ShowMethod_Delete)
r(consts.ResourcesName_Notice, "公告(暂无)", repo.NewCommonResourceRepo(db, &model.Notice{}), ShowMethod_Get|ShowMethod_Post|ShowMethod_Put|ShowMethod_Delete)
r(consts.ResourcesName_DevicePush, "设备推送(暂无)", repo.NewCommonResourceRepo(db, &model.DevicePush{}), ShowMethod_Get)
}

View File

@ -11,6 +11,7 @@ import (
"math"
"net/url"
"strconv"
"time"
)
type AccountHook struct {
@ -98,16 +99,125 @@ func (hook *AccountHook) List(projectInfo *entity.Project, resource string, para
return totalCount, fields, rows, nil
}
type AccountDetailOrderInfo struct {
ServerId string `json:"server_id"`
AccountId string `json:"account_id"`
RoleId string `json:"role_id"`
RoleName string `json:"role_name"`
Sn string `json:"sn"`
ProductId string `json:"product_id"`
Price int `json:"price"`
PurchaseType string `json:"purchase_type"`
PurchaseAt int64 `json:"purchase_at"`
}
func (info *AccountDetailOrderInfo) toDto() *dto.AccountDetailOrderInfo {
return &dto.AccountDetailOrderInfo{
ServerId: info.ServerId,
AccountId: info.AccountId,
RoleId: info.RoleId,
RoleName: info.RoleName,
Sn: info.Sn,
ProductId: info.ProductId,
Price: info.Price,
PurchaseType: info.PurchaseType,
PurchaseAt: utils.ParseUnixTimestamp2LocalTime(info.PurchaseAt).Format(time.DateTime),
}
}
type AccountDetailRoleInfo struct {
Platform string `json:"platform"` // ios ad
ServerId string `json:"serverId"`
Name string `json:"name"`
RoleId string `json:"roleId"`
Level int `json:"level"`
CurrencyItems []*dto.ItemInfo `json:"item_list"`
Ip string `json:"ip"`
Channel string `json:"channel"`
CreatedAt int64 `json:"created_at"`
LastLoginTime int64 `json:"last_login_time"`
OrderList []*AccountDetailOrderInfo `json:"order_list"`
}
func (info *AccountDetailRoleInfo) toDto() *dto.AccountDetailRoleInfo {
retInfo := &dto.AccountDetailRoleInfo{
Platform: info.Platform,
ServerId: info.ServerId,
Name: info.Name,
RoleId: info.RoleId,
Level: info.Level,
CurrencyItems: info.CurrencyItems,
CreatedAt: utils.ParseUnixTimestamp2LocalTime(info.CreatedAt).Format(time.DateTime),
LastLoginTime: utils.ParseUnixTimestamp2LocalTime(info.LastLoginTime).Format(time.DateTime),
}
totalPayAmount := 0
for _, order := range info.OrderList {
totalPayAmount += order.Price
retInfo.OrderList = append(retInfo.OrderList, order.toDto())
}
retInfo.TotalPayAmount = totalPayAmount
retInfo.TotalPayTimes = len(info.OrderList)
return retInfo
}
type AccountDetailInfo struct {
AccountId string `json:"account_id"`
LoginDeviceCount int `json:"login_device_count"`
RoleList []*AccountDetailRoleInfo `json:"role_list"`
}
func (info *AccountDetailInfo) toDto() *dto.AccountDetailInfo {
retInfo := &dto.AccountDetailInfo{
AccountId: info.AccountId,
}
var earliestRole *AccountDetailRoleInfo
var totalPayAmount int
var totalPayCount int
var firstPayAt int64 = math.MaxInt64
var lastPayAt int64 = 0
var lastLoginTime int64 = 0
for _, r := range info.RoleList {
if earliestRole == nil || earliestRole.CreatedAt > r.CreatedAt {
earliestRole = r
}
retInfo.RoleList = append(retInfo.RoleList, r.toDto())
if lastLoginTime < r.LastLoginTime {
lastLoginTime = r.LastLoginTime
}
for _, o := range r.OrderList {
if firstPayAt > o.PurchaseAt {
firstPayAt = o.PurchaseAt
}
if lastPayAt < o.PurchaseAt {
lastPayAt = o.PurchaseAt
}
}
}
retInfo.TotalPayAmount = totalPayAmount
retInfo.TotalPayTimes = totalPayCount
retInfo.FirstPayAt = utils.ParseUnixTimestamp2LocalTime(firstPayAt).Format(time.DateTime)
retInfo.LastPayAt = utils.ParseUnixTimestamp2LocalTime(lastPayAt).Format(time.DateTime)
retInfo.LastLoginTime = utils.ParseUnixTimestamp2LocalTime(lastLoginTime).Format(time.DateTime)
if earliestRole != nil {
retInfo.Platform = earliestRole.Platform
retInfo.Channel = earliestRole.Channel
retInfo.CreatedAt = utils.ParseUnixTimestamp2LocalTime(earliestRole.CreatedAt).Format(time.DateTime)
retInfo.CreatedIp = earliestRole.Ip
retInfo.Platform = earliestRole.Platform
retInfo.Platform = earliestRole.Platform
retInfo.Platform = earliestRole.Platform
retInfo.Platform = earliestRole.Platform
}
return retInfo
}
func (hook *AccountHook) GetDetail(projectInfo *entity.Project, account string) (*dto.GetAccountDetailRsp, error) {
accountId := account
if accountId == "" {
return nil, errcode.New(errcode.ParamsInvalid, "not found account id:%v", accountId)
}
rsp := &dto.GetAccountDetailRsp{
AccountInfo: &dto.AccountDetailInfo{},
}
params := &url.Values{}
allRunningServers, err := getAllRunningServers(projectInfo)
@ -115,7 +225,7 @@ func (hook *AccountHook) GetDetail(projectInfo *entity.Project, account string)
return nil, err
}
roleList := make([]*dto.AccountDetailRoleInfo, 0)
roleList := make([]*AccountDetailRoleInfo, 0)
for _, runningServer := range allRunningServers {
params.Set("serverid", runningServer.ServerId)
params.Set("userId", accountId)
@ -127,7 +237,7 @@ func (hook *AccountHook) GetDetail(projectInfo *entity.Project, account string)
Msg string `json:"msg"`
} `json:"state"`
Data *dto.AccountDetailInfo `json:"data"`
Data *AccountDetailInfo `json:"data"`
}
detailRsp := &RspData{}
@ -140,14 +250,11 @@ func (hook *AccountHook) GetDetail(projectInfo *entity.Project, account string)
continue
}
rsp.AccountInfo = detailRsp.Data
roleList = append(roleList, detailRsp.Data.RoleList...)
}
rsp.AccountInfo.RoleCount = len(roleList)
rsp.AccountInfo.RoleList = roleList
return rsp, nil
accountDetailTotal := &AccountDetailInfo{AccountId: accountId, RoleList: roleList}
return &dto.GetAccountDetailRsp{AccountInfo: accountDetailTotal.toDto()}, nil
}
func getPaginationServerReqList(projectInfo *entity.Project, serverInfoList internal.ServerInfoList,

View File

@ -107,7 +107,9 @@ func (hook *BanHook) Edit(projectInfo *entity.Project, resource string, dtoObj d
dura := int64(expireAt.Time.Sub(time.Now()).Minutes()) // 神魔大陆封禁是分钟
if dura <= 0 {
// 解封
params.Add("forbidtime", "0")
params.Add("forbidtime", "-1")
params.Add("desc", "")
params.Add("notifytouser", "")
} else {
params.Add("forbidtime", strconv.FormatInt(int64(dura), 10))
params.Add("desc", banInfo.BanReason)

View File

@ -39,7 +39,7 @@ func (hook *MailGlobalHook) Create(projectInfo *entity.Project, resource string,
itemIdStr = strings.Join(itemWordList, "@")
itemNumStr = "-1"
} else {
itemIdStr = "0"
itemNumStr = "0"
}
var serverIds []string

View File

@ -38,7 +38,7 @@ func (hook *MailRoleHook) Create(projectInfo *entity.Project, resource string, d
itemIdStr = strings.Join(itemWordList, "@")
itemNumStr = "-1"
} else {
itemIdStr = "0"
itemNumStr = "0"
}
params := &url.Values{}

View File

@ -26,12 +26,31 @@ func (hook *WhitelistHook) Create(projectInfo *entity.Project, resource string,
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)
if len(whiteInfo.ServerConfID) == 0 {
// 所有区服
serverList, err := getAllRunningServers(projectInfo)
if err != nil {
return err
}
for _, v := range serverList {
params.Set("server", v.ServerId)
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)
}
}
} else {
// 指定区服
for _, v := range whiteInfo.ServerConfID {
params.Set("server", v)
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
@ -51,13 +70,32 @@ func (hook *WhitelistHook) Delete(projectInfo *entity.Project, resource string,
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)
if len(whiteInfo.ServerConfID) == 0 {
// 所有区服
serverList, err := getAllRunningServers(projectInfo)
if err != nil {
return err
}
for _, v := range serverList {
params.Set("server", v.ServerId)
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)
}
}
} else {
// 指定区服
for _, v := range whiteInfo.ServerConfID {
params.Set("server", v)
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

@ -114,7 +114,7 @@ func (repo *commonResourceRepoImpl) Create(projectEt *entity.Project, resource s
return et, err
}
}
err := repo.db.Create(et.Po).Error
if err != nil {
if strings.Contains(err.Error(), "Duplicate entry") || strings.Contains(err.Error(), "UNIQUE constraint") {
@ -191,8 +191,23 @@ func (repo *commonResourceRepoImpl) parseWhereConditions2Sql(conditions []*dto.G
whereClause = append(whereClause, fmt.Sprintf("`%v` like ?", dbFieldName))
whereArgs = append(whereArgs, cond.Value1)
case "range":
whereClause = append(whereClause, fmt.Sprintf("`%v` >= ? and `%v` <= ?", dbFieldName, dbFieldName))
whereArgs = append(whereArgs, cond.Value1, cond.Value2)
if t1, ok1 := cond.Value1.(time.Time); ok1 {
t2, _ := cond.Value2.(time.Time)
if t1.IsZero() && t2.IsZero() {
whereClause = append(whereClause, fmt.Sprintf("`%v` >= ? and `%v` <= ?", dbFieldName, dbFieldName))
whereArgs = append(whereArgs, cond.Value1, cond.Value2)
} else if !t1.IsZero() {
whereClause = append(whereClause, fmt.Sprintf("`%v` >= ? ", dbFieldName))
whereArgs = append(whereArgs, cond.Value1)
} else {
whereClause = append(whereClause, fmt.Sprintf("`%v` <= ? ", dbFieldName))
whereArgs = append(whereArgs, cond.Value2)
}
} else {
whereClause = append(whereClause, fmt.Sprintf("`%v` >= ? and `%v` <= ?", dbFieldName, dbFieldName))
whereArgs = append(whereArgs, cond.Value1, cond.Value2)
}
case "":
default:
panic(fmt.Errorf("unsupport where tag %v", field.Tag))

View File

@ -41,8 +41,16 @@ func (m *Ban) GetBanTypeChoices(project *Project) []*dto.CommonDtoFieldChoice {
switch project.ProjectType {
case consts.RegisteredProjectId_shenmodalu:
return []*dto.CommonDtoFieldChoice{
//{
// Desc: "账号",
// Value: consts.BanType_Account,
//},
//{
// Desc: "IP",
// Value: consts.BanType_Ip,
//},
{
Desc: "角色",
Desc: "角色登录",
Value: consts.BanType_Role,
},
{
@ -57,7 +65,7 @@ func (m *Ban) GetBanTypeChoices(project *Project) []*dto.CommonDtoFieldChoice {
Value: consts.BanType_Account,
},
{
Desc: "角色",
Desc: "角色登录",
Value: consts.BanType_Role,
},
{

View File

@ -15,8 +15,8 @@ func init() {
type CDKey struct {
ID int `gorm:"primarykey" readonly:"true"`
ProjectId int `gorm:"index:idx_project_id"`
Name string `gorm:"type:varchar(100);unique" name:"礼包说明" required:"true" uneditable:"true"`
ServerIDs []string `gorm:"type:json;serializer:json" name:"区服" desc:"不选就是全服通用" type:"[]string" choices:"GetChoiceServers" multi_choice:"true" uneditable:"true""`
Name string `gorm:"type:varchar(100);unique" name:"礼包说明" required:"true" uneditable:"true"`
CodeType int `name:"礼包类型" required:"true" choices:"GetCodeTypeChoices" uneditable:"true"`
Code string `gorm:"type:VARCHAR(50);index" name:"礼包码" desc:"一码通用才配置" uneditable:"true"`
CodeNum int `name:"礼包数量" desc:"一码一用才配置"`

View File

@ -13,7 +13,7 @@ func init() {
type GlobalMail struct {
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"`
ServerIDs []string `gorm:"type:json;serializer:json" desc:"不选就是默认所有区服" name:"区服" type:"[]string" choices:"GetChoiceServers" multi_choice:"true"`
Title string `name:"邮件标题" required:"true"`
Content string `name:"邮件内容" required:"true"`
Attach []*MailAttachItem `gorm:"type:json;serializer:json" name:"邮件附件" type:"items" desc:"搜索道具并点击添加"`

View File

@ -0,0 +1,40 @@
package model
import (
"admin/apps/game/model/dto"
"admin/internal/db"
"time"
)
func init() {
db.RegisterTableModels(ItemBag{})
}
// 道具包,配置一系列道具,供邮件、礼包码填写使用
type ItemBag struct {
ID int `gorm:"primarykey" readonly:"true"`
ProjectId int `gorm:"uniqueIndex:idx_whitelist"`
Name string `gorm:"type:varchar(255);uniqu" name:"礼包名称" desc:"请输入礼包名称,全项目唯一" required:"true" where:"eq"`
Attach []*MailAttachItem `gorm:"type:json;serializer:json" name:"邮件附件" type:"items" desc:"搜索道具并点击添加"`
CreatedAt time.Time `readonly:"true" where:"range"`
}
func (lm *ItemBag) TableName() string {
return "item_bag"
}
func (m *ItemBag) GetId() int {
return m.ID
}
func (m *ItemBag) GetChoiceServers(project *Project) []*dto.CommonDtoFieldChoice {
return getChoiceServers(project)
}
func (m *ItemBag) GetWhitelistTypeChoices(project *Project) []*dto.CommonDtoFieldChoice {
return []*dto.CommonDtoFieldChoice{
{Desc: "IP", Value: "ip"},
{Desc: "账号", Value: "account"},
}
}

View File

@ -20,8 +20,8 @@ type MailAttachItem struct {
type RoleMail struct {
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"`
RoleIDs []string `gorm:"type:json;serializer:json" name:"生效的角色id" desc:"生效的角色id逗号分隔多个" required:"true"`
Title string `name:"邮件标题" required:"true"`
Content string `name:"邮件内容" required:"true"`
Attach []*MailAttachItem `gorm:"type:json;serializer:json" name:"邮件附件" type:"items" desc:"搜索道具并点击添加"`

View File

@ -11,11 +11,11 @@ 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_whitelist;index:idx_server" name:"区服id" required:"true" choices:"GetChoiceServers" multi_choices:"true" where:"eq"`
WType string `name:"白名单类型" desc:"账号或者ip" required:"true" choices:"GetWhitelistTypeChoices"`
Value string `gorm:"type:varchar(128);uniqueIndex:idx_whitelist" name:"账号或者ip等值" required:"true"`
ID int `gorm:"primarykey" readonly:"true"`
ProjectId int `gorm:"uniqueIndex:idx_whitelist"`
ServerConfID []string `gorm:"type:json;serializer:json" type:"[]string" name:"区服id" desc:"不选就是默认所有区服" choices:"GetChoiceServers" multi_choice:"true" where:"eq"`
WType string `name:"白名单类型" desc:"账号或者ip" required:"true" choices:"GetWhitelistTypeChoices"`
Value string `gorm:"type:varchar(128);uniqueIndex:idx_whitelist" name:"账号或者ip等值" required:"true"`
CreatedAt time.Time `readonly:"true" where:"range"`
}

View File

@ -31,6 +31,7 @@ func (srv *Server) CheckToken(ctx *context.WebContext) {
ctx.Header.UserName = authRsp.User.NickName
ctx.GinCtx().Set("userInfo", authRsp)
ctx.GinCtx().Next()
return
}

View File

@ -46,7 +46,7 @@ func (svc *CommonResourceService) GetOrCreateToken(userId int) (*model.Token, er
if err != nil {
return nil, err
}
if !find {
if !find || tokenInfo.ExpireAt.Before(time.Now()) {
tokenInfo, err = svc.tokenRepo.CreateToken(userId, time.Hour*24*15) // 15天过期的token可以使用中加上token刷新功能
if err != nil {
return nil, err

View File

@ -17,7 +17,7 @@ func init() {
type Token struct {
ID int `gorm:"primarykey" readonly:"true"`
Token string `gorm:"type:varchar(256);unique" required:"true"`
UserId int `name:"用户id" readonly:"true"`
UserId int `gorm:"type:int(20);unique" name:"用户id" readonly:"true"`
ExpireAt time.Time `name:"到期时间" readonly:"true"`
CreatedAt time.Time `readonly:"true"`
}

View File

@ -8,6 +8,7 @@ import (
"admin/apps/user/model/dto"
"admin/internal/errcode"
"admin/lib/tokenlib"
"admin/lib/xlog"
"context"
)
@ -22,6 +23,8 @@ func (svc *Service) CheckToken(token string, userId int) error {
return err
}
if token != dbToken.Token {
xlog.Infof("user:%v token invalid:(%v)(%v)",
dbToken.UserId, token, dbToken.Token)
return errcode.New(errcode.TokenInvalid, "token not equal:%v,%v", token, dbToken.Token)
}
return nil

View File

@ -35,6 +35,7 @@ const (
ResourcesName_Notice = "notice"
ResourcesName_CDKey = "cdkey"
ResourcesName_DevicePush = "device_push"
ResourcesName_ItemBag = "item_bag"
)
const (

View File

@ -1,7 +1,7 @@
package utils
import (
"fmt"
"admin/lib/xlog"
"time"
)
@ -22,7 +22,8 @@ func ParseUnixTimestamp2LocalTime(ts int64) (local time.Time) {
sec = ts
nsec = 0
default:
panic(fmt.Errorf("ts:%v invalid parse to local time", ts))
xlog.Warnf("ParseUnixTimestamp2LocalTime:%v invalid", ts)
sec = int64((time.Time{}).Second())
}
t := time.Unix(sec, nsec)

View File

@ -1,6 +1,7 @@
<script setup>
import userDetailAccount from '@/components/game/userDetailAccount.vue';
import userDetailOrder from '@/components/game/userDetailOrder.vue';
import {accountGetDetail} from "@/api/account.js";
import LocalCache from "@/stores/localCache.js";
@ -18,8 +19,13 @@ console.log("进入用户详情:", props.rowInfo)
const account = props.rowInfo.Account
const serverId = props.rowInfo.ServerConfId
let loadAccountOk = ref(false)
let accountInfo = {}
accountGetDetail(resource_url, props.rowInfo).then((res) => {
console.log("获取账户详情返回:", res.data)
accountInfo = res.data.account_info
loadAccountOk.value = true
}, (err) => {
})
@ -42,12 +48,14 @@ const handleClick = (tab, event) => {
<template>
<div>
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick" v-if="loadAccountOk">
<el-tab-pane label="账号详情" name="detail">
<component :is="userDetailAccount"/>
<component :is="userDetailAccount" v-if="loadAccountOk" :accountInfo="accountInfo"/>
</el-tab-pane>
<el-tab-pane label="充值订单记录" name="order">充值订单子页面</el-tab-pane>
<el-tab-pane label="货币记录" name="currency">货币记录子页面</el-tab-pane>
<el-tab-pane label="充值订单记录" name="order" v-if="loadAccountOk" :accountInfo="accountInfo">
<component :is="userDetailOrder" v-if="loadAccountOk" :accountInfo="accountInfo"/>
</el-tab-pane>
<!-- <el-tab-pane label="货币记录" name="currency" v-if="accountInfo !== null">货币记录子页面</el-tab-pane>-->
</el-tabs>
</div>
</template>

View File

@ -1,13 +1,145 @@
<script setup>
const props = defineProps({
accountInfo: {},
})
const accountInfo = props.accountInfo
console.log("账户信息:", accountInfo)
let accountInfoFields = [{
"filedKey1": "账户id",
"filedValue1": accountInfo.account_id,
"filedKey2": "平台",
"filedValue2": accountInfo.platform,
}, {
"filedKey1": "角色数",
"filedValue1": accountInfo.role_list.length,
"filedKey2": "渠道",
"filedValue2": accountInfo.channel,
}, {
"filedKey1": "注册时间",
"filedValue1": accountInfo.created_at,
"filedKey2": "注册ip",
"filedValue2": accountInfo.created_ip,
}, {
"filedKey1": "总付费金额",
"filedValue1": accountInfo.total_pay_amount,
"filedKey2": "总付费次数",
"filedValue2": accountInfo.total_pay_times,
}, {
"filedKey1": "首次付费时间",
"filedValue1": accountInfo.first_pay_at,
"filedKey2": "最后付费时间",
"filedValue2": accountInfo.last_pay_at,
}, {
"filedKey1": "登录设备数(暂无)",
"filedValue1": 0,
"filedKey2": "最后登录时间",
"filedValue2": accountInfo.last_login_time,
},]
let accountRoleList = []
let currencyItemColList = []
let isFirstRole = true
accountInfo.role_list.forEach(role => {
let i = 0;
role.currency_items.forEach(item => {
i++
let fieldName = "currencyName" + i
let fieldValue = "currencyNum" + i
role[fieldName] = item.desc
role[fieldValue] = item.item_num
if (isFirstRole) {
currencyItemColList.push({colProp: fieldValue, colLabel: item.desc})
}
})
isFirstRole = false
accountRoleList.push(role)
})
// console.log("role list:", accountRoleList)
// console.log("currency item list:", currencyItemColList)
Object.keys((props.accountInfo)).forEach(key => {
const account = props.accountInfo[key]
})
const tableCellStyle = (row) => {
if (row.columnIndex === 0 || row.columnIndex === 2) {
// return 'background:#fde9d9 !import'
return {"font-weight": "bold", "color": "black"}
} else {
return {}
}
}
</script>
<template>
<div>
账号详情子页面
<el-row>
<el-table :data="accountInfoFields" style="width: 100%" table-layout="auto" border :cell-style="tableCellStyle"
:show-header="false">
<el-table-column prop="filedKey1" label="" width="180"/>
<el-table-column prop="filedValue1" label="" width="200"/>
<el-table-column prop="filedKey2" label="" width="180"/>
<el-table-column prop="filedValue2" label="" width="200"/>
</el-table>
</el-row>
<el-row>
<!-- <el-button disabled type="primary" style="margin-bottom: 5px;margin-top: 5px">角色详情</el-button>-->
<el-divider content-position="left">角色详情</el-divider>
<el-table class="roleDetailList" :data="accountRoleList" border :show-header="true"
style="width: 100%">
<el-table-column prop="platform" label="平台"/>
<el-table-column prop="server_id" label="区服"/>
<el-table-column prop="name" label="角色名称" width="100%"/>
<el-table-column prop="role_id" label="角色id"/>
<el-table-column prop="total_pay_amount" label="充值金额"/>
<el-table-column prop="level" label="等级"/>
<el-table-column prop="created_at" label="创建时间" width="100"/>
<el-table-column prop="last_login_time" label="最后登录时间" width="100"/>
<el-table-column v-for="colInfo in currencyItemColList" :prop="colInfo.colProp" :label="colInfo.colLabel"/>
</el-table>
</el-row>
</div>
</template>
<style scoped>
.roleDetailList :deep(.el-table__header-wrapper, .el-table__fixed-header-wrapper) {
th {
word-break: break-word;
background-color: #f8f8f9 !important;
color: #515a6e;
height: 40px !important;
font-size: 13px;
}
}
.roleDetailList :deep(.el-table__header .el-table-column--selection .cell) {
width: 60px !important; /* 选择器越具体优先级越高 */
}
.roleDetailList :deep(.el-table .fixed-width .el-button--small) {
padding-left: 0;
padding-right: 0;
width: 20px !important;
}
.roleDetailList :deep(.el-table__header) {
background: #f5f7fa !important;
}
.roleDetailList :deep(.el-table__row) td {
border-color: #ebeef5;
}
</style>

View File

@ -1,10 +1,31 @@
<script setup>
const props = defineProps({
accountInfo: {},
})
const accountInfo = props.accountInfo
let orderList = []
accountInfo.role_list.forEach(role => {
orderList.push(...role.order_list)
})
</script>
<template>
<div>
账号详情子页面
<el-table :data="orderList" style="width: 100%" table-layout="auto" border :show-header="true">
<el-table-column prop="server_id" label="区服"/>
<el-table-column prop="account_id" label="账户id"/>
<el-table-column prop="role_id" label="角色id"/>
<el-table-column prop="role_name" label="角色名"/>
<el-table-column prop="sn" label="订单号"/>
<el-table-column prop="product_id" label="商品id"/>
<el-table-column prop="price" label="金额"/>
<el-table-column prop="purchase_type" label="支付方式"/>
<el-table-column prop="purchase_at" label="订单时间"/>
</el-table>
</div>
</template>

View File

@ -32,8 +32,8 @@ rowClickBtns.push(...props.rowClickDialogBtns)
const rowClickBtnVisibleList = reactive(rowClickBtns.map(() => false))
const rowClickBtnSelectRow = ref(null)
console.log("global btns:", globalClickBtns)
console.log("row btns:", rowClickBtns)
// console.log("global btns:", globalClickBtns)
// console.log("row btns:", rowClickBtns)
const resource_url = cachedResource.meta.resource_url;
const fieldsDescInfo = ref([])
@ -62,7 +62,7 @@ const listData = async () => {
where_conditions: "",
}
console.log(`查询页:${listParams.page_no},查询页大小:${listParams.page_len}`)
// console.log(`${listParams.page_no}${listParams.page_len}`)
let whereReqConditions = {
conditions: []
@ -88,7 +88,7 @@ const listData = async () => {
for (let i = 0; i < fieldsDescInfo.value.length; i++) {
var field = fieldsDescInfo.value[i]
dialogObjectForm.value[field.key] = ''
// dialogObjectForm.value[field.key] = ''
if (field.required == true) {
rules.value[field.key] = [{required: true, message: field.name + "不能为空", trigger: "blur"}]
@ -159,6 +159,21 @@ const dialogObjectForm = ref({
Attach: [],
})
const route = useRoute()
if (route.query.from != undefined && route.query.from != "") {
Object.keys((route.query)).forEach(key => {
const value = route.query[key]
if (key === "from") {
return
}
dialogObjectForm.value[key] = value
console.log("进入页面,来自查询参数的数据:", key, value)
})
console.log("进入页面,来自查询参数的数据:", route.query)
dialogAddVisible.value = true
}
const tableSelectRows = ref([])
const handleTableSelectRowsSendToServer = (btnInfo, rows) => {
@ -206,6 +221,10 @@ const tableSelectRow3 = (i, row) => {
rowClickBtnVisibleList[i] = true
console.log("点击按钮:", rowClickBtnSelectRow)
}
const tableSelectRow4 = (btnInfo, row) => {
btnInfo.click_handler(row)
// console.log("", row)
}
const submitAdd = async () => {
try {
@ -489,7 +508,7 @@ const handlePaginationCurChange = (val) => {
<template v-else-if="btn.btn_type === 2">
<el-button size="default" :type="btn.btn_color_type"
@click="btn.btn_callback_visible = true">
@click="tableSelectRow4(btn, scope.row)">
{{ btn.name }}
</el-button>
</template>

View File

@ -81,6 +81,18 @@ const listData = async () => {
for (let j = 0; j < rows.value.length; j++) {
rows.value[j].jsonValue = JSON.stringify(rows.value[j][field.key])
}
rules.value[field.key] = [{
required: true,
validator: (rule, value, callback) => {
console.log("触发校验道具列表规则:", dialogObjectForm.value)
if (dialogObjectForm.value.Attach === undefined || dialogObjectForm.value.Attach.length === 0) {
callback(new Error("请至少填写一个奖励道具!"))
} else {
callback()
}
},
trigger: "blur",
}]
}
if (field.where !== "") {
@ -149,6 +161,7 @@ const submitAdd = async () => {
await dialogAddFormRef.value.validate(valid => {
if (valid) {
console.log("commit add form:", dialogObjectForm.value)
return
resourcePost(resource_url, dialogObjectForm.value).then((res) => {
ElNotification({
title: "添加结果通知",
@ -243,6 +256,8 @@ const handleEdit = (index, row) => {
dialogObjectForm.value = row
dialogObjectForm.value.oldData = row
dialogObjectForm.value.oldIndex = index
rules.value["Code"] = []
rules.value["CodeNum"] = []
console.log("edit data:", row)
dialogEditVisible.value = true
}
@ -284,12 +299,15 @@ function addItem() {
dialogObjectForm.value.Attach = [];
}
dialogObjectForm.value.Attach.push(d);
console.log("校验规则:", rules.value)
dialogAddFormRef.value.validateField("Attach");
}
function deleteItem(row) {
//
let number = dialogObjectForm.value.Attach.findIndex(item => item === row);
dialogObjectForm.value.Attach.splice(number, 1);
dialogAddFormRef.value.validateField("Attach");
}
const handleCloseDialog = () => {
@ -311,6 +329,24 @@ const handleItemOnSelect = (itemOption) => {
item.value.id = itemOption.value
item.value.desc = itemOption.desc
}
const cdkeyCodeInputDisabled = ref(true)
const cdkeyCodeNumInputDisabled = ref(true)
const handleCodeTypeOnSelect = (codeType) => {
console.log("选中:", codeType)
if (codeType === 0) {
cdkeyCodeInputDisabled.value = false
cdkeyCodeNumInputDisabled.value = true
rules.value["Code"] = [{required: true, message: "礼包码不能为空", trigger: "blur"}]
rules.value["CodeNum"] = []
} else {
cdkeyCodeInputDisabled.value = true
cdkeyCodeNumInputDisabled.value = false
rules.value["Code"] = []
rules.value["CodeNum"] = [{required: true, message: "礼包数量不能为空", trigger: "blur"}]
}
}
const handleQueryItem = (itemQueryStr) => {
if (!itemQueryStr) {
itemChoices.value = []
@ -520,11 +556,24 @@ const handlePaginationCurChange = (val) => {
<el-tooltip effect="light" :content="fieldDescInfo.help_text" placement="bottom-start">
<el-select :placeholder="(fieldDescInfo.multi_choice === true ? '--多选--' : '--单选--')"
v-model="dialogObjectForm[fieldDescInfo.key]" style="width: 150px"
:multiple="(fieldDescInfo.multi_choice === true)">
:multiple="(fieldDescInfo.multi_choice === true)"
v-if="fieldDescInfo.key === 'CodeType'"
@change="handleCodeTypeOnSelect"
>
<el-option v-for="info in fieldDescInfo.choices" :key="info.desc" :label="info.desc"
:value="info.value"></el-option>
</el-select>
<el-select :placeholder="(fieldDescInfo.multi_choice === true ? '--多选--' : '--单选--')"
v-model="dialogObjectForm[fieldDescInfo.key]" style="width: 150px"
:multiple="(fieldDescInfo.multi_choice === true)"
v-else
>
<el-option v-for="info in fieldDescInfo.choices" :key="info.desc" :label="info.desc"
:value="info.value"></el-option>
</el-select>
</el-tooltip>
</el-form-item>
</template>
@ -540,8 +589,13 @@ const handlePaginationCurChange = (val) => {
<!-- 否则就是普通字段 -->
<template v-else>
<el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
<el-input v-model="dialogObjectForm[fieldDescInfo.key]" :disabled="cdkeyCodeInputDisabled"
:placeholder="fieldDescInfo.help_text" v-if="fieldDescInfo.key === 'Code'"></el-input>
<el-input v-model="dialogObjectForm[fieldDescInfo.key]"
:placeholder="fieldDescInfo.help_text"></el-input>
:placeholder="fieldDescInfo.help_text" :disabled="cdkeyCodeNumInputDisabled"
v-else-if="fieldDescInfo.key === 'CodeNum'" type="number"></el-input>
<el-input v-model="dialogObjectForm[fieldDescInfo.key]"
:placeholder="fieldDescInfo.help_text" v-else></el-input>
</el-form-item>
</template>
</template>

View File

@ -6,6 +6,7 @@ import ExpireCache from "@/stores/expireCache.js";
router.beforeEach((to, from, next) => {
if (to.path === '/login') {
console.log("进入登录页面")
next()
} else {
const token = ExpireCache.getCache("token");

View File

@ -85,7 +85,7 @@ const router = createRouter({
export default router
export function setProjectOperationRoutes(projectList) {
console.log("resourceList:", projectList)
// console.log("resourceList:", projectList)
isGetUserInfo.value = true
projectOpTreeRoutes.value = []
@ -150,5 +150,6 @@ export function setProjectOperationRoutes(projectList) {
}
LocalCache.setCache("projectsRoute", projectList)
LocalCache.setCache("homeRoute", homeRoute)
// console.log("重新获取了用户数据,刷新路由表:", router.getRoutes())
}

View File

@ -3,8 +3,11 @@
import tableView from "@/components/restful/table.vue";
import LocalCache from "@/stores/localCache.js";
import userDetail from "@/components/game/userDetail.vue";
import router, {projectOpTreeRoutes} from '@/router/index.js'
const cachedResource = LocalCache.getCache("resource");
const homeRoutes = LocalCache.getCache("homeRoute");
const projectId = cachedResource.meta.projectId
const rowClickDialogBtns = []
@ -23,13 +26,60 @@ switch (cachedResource.meta.resource) {
}, {
key: "account:detail",
name: "白名单",
btn_color_type: "success",
btn_color_type: "default",
btn_type: 2,
}, {
click_handler: (row) => {
for (let i = 0; i < homeRoutes.children.length; i++) {
const curRecourseRoute = homeRoutes.children[i]
if (curRecourseRoute.meta === undefined) {
continue
}
if (curRecourseRoute.meta.projectId === projectId && curRecourseRoute.meta.resource === "whitelist") {
//
console.log("角色页面点击:", row, "跳转快速封禁")
LocalCache.setCache("resource", curRecourseRoute)
router.push({
path: curRecourseRoute.path, query: {
from: "account",
WType: "account",
Value: row.Account,
}
})
}
}
}
},)
break
case "role":
//
if (rowClickDialogBtns.length > 0) {
break
}
rowClickDialogBtns.push({
key: "account:detail",
name: "封禁",
btn_color_type: "info",
btn_type: 2,
click_handler: (row) => {
for (let i = 0; i < homeRoutes.children.length; i++) {
const curRecourseRoute = homeRoutes.children[i]
if (curRecourseRoute.meta === undefined) {
continue
}
if (curRecourseRoute.meta.projectId === projectId && curRecourseRoute.meta.resource === "ban") {
//
console.log("角色页面点击:", row, "跳转快速封禁")
LocalCache.setCache("resource", curRecourseRoute)
router.push({
path: curRecourseRoute.path, query: {
from: "role",
ServerConfID: row.ServerConfId,
Value: row.RoleId,
}
})
}
}
}
},)
break
}