This commit is contained in:
likun 2025-06-06 18:30:12 +08:00
parent 07d379eae1
commit 0e95de298e
40 changed files with 401 additions and 26 deletions

View File

@ -23,6 +23,8 @@ import (
type CommonResourceService struct {
projectRepo repo.IProjectRepo
serverRepo repo.IServerRepo
noticeRepo repo.INoticeRepo
}
func initCommonResourcesRepo(db *gorm.DB) {
@ -33,6 +35,8 @@ func initCommonResourcesRepo(db *gorm.DB) {
serverRepo.GlobalBtns = []*api.ResourceBtnInfo{
{Key: consts.BtnKeyGlobal_Server_DownAll, Name: "一键停服", BtnColorType: "info"},
{Key: consts.BtnKeyGlobal_Server_UpAll, Name: "一键起服", BtnColorType: "warning"},
{Key: consts.BtnKeyGlobal_Server_ExportCdn, Name: "一键导出cdn", BtnColorType: "danger"},
{Key: consts.BtnKeyGlobal_Server_ExportCdn, Name: "预览导出cdn", BtnColorType: "default"},
}
serverRepo.RowBtns = []*api.ResourceBtnInfo{
{Key: consts.BtnKeyRow_Server_Down, Name: "停服", BtnColorType: "info"},
@ -54,7 +58,16 @@ func initCommonResourcesRepo(db *gorm.DB) {
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)
{
noticeRepo := r(consts.ResourcesName_Notice, "公告", repo.NewCommonResourceRepo(db, &model.Notice{}), ShowMethod_Get|ShowMethod_Post|ShowMethod_Put|ShowMethod_Delete)
noticeRepo.GlobalBtns = []*api.ResourceBtnInfo{
{Key: consts.BtnKeyGlobal_Server_DownAll, Name: "一键禁用所有", BtnColorType: "info"},
}
noticeRepo.RowBtns = []*api.ResourceBtnInfo{
{Key: consts.BtnKeyRow_Server_Down, Name: "禁用", BtnColorType: "info"},
{Key: consts.BtnKeyRow_Server_Up, Name: "启用", BtnColorType: "warning"},
}
}
r(consts.ResourcesName_DevicePush, "设备推送(暂无)", repo.NewCommonResourceRepo(db, &model.DevicePush{}), ShowMethod_Get)
}
@ -62,6 +75,8 @@ func NewCommonResourceService(db *gorm.DB) *CommonResourceService {
initCommonResourcesRepo(db)
svc := &CommonResourceService{
projectRepo: repo.NewProjectRepo(db),
serverRepo: repo.NewServerRepo(db),
noticeRepo: repo.NewNoticeRepo(db),
}
svc.startEventSubscriber()
svc.startLoadAllDelayInvokeDbData()
@ -289,10 +304,33 @@ func (svc *CommonResourceService) RowsSelection(projectId int, resourceName stri
if resourceName != consts.ResourcesName_Project && !find {
return projectEt, nil, errcode.New(errcode.ServerError, "not found project %v db data", projectId)
}
if hook, ok := projects.GetProjectResourceHook(projectEt, resourceName).(projects.IPostResourceOpRowsHook); ok {
rsp, err := hook.RowsSelection(projectEt, resourceName, params.BtnKey, params.Rows)
return projectEt, rsp, err
if params.BtnKey == consts.BtnKeyGlobal_Server_ExportCdn {
// 导出cdn聚合公告信息一起导
serverList, err := svc.serverRepo.List(projectId)
if err != nil {
return projectEt, nil, err
}
noticeList, err := svc.noticeRepo.List(projectId)
if err != nil {
return projectEt, nil, err
}
content, err := genCdnServerListContent(serverList, noticeList)
if err != nil {
return projectEt, nil, err
}
return projectEt, &dto2.CommonRowsSelectionRsp{
Msg: content,
NeedRefresh: false,
FileName: projectEt.GetProjectPo().Name + "-区服公告信息.txt",
}, nil
} else {
if hook, ok := projects.GetProjectResourceHook(projectEt, resourceName).(projects.IPostResourceOpRowsHook); ok {
rsp, err := hook.RowsSelection(projectEt, resourceName, params.BtnKey, params.Rows)
return projectEt, rsp, err
}
}
return projectEt, nil, nil
}

View File

@ -50,6 +50,7 @@ func (hook *ServerHook) List(projectInfo *entity.Project, resource string, param
row["IsServerDown"] = "否"
}
} else {
row["IsServerDown"] = "否"
row["RunningStatus"] = "未知"
row["Ccu"] = 0
row["TotalRoleCount"] = 0

View File

@ -0,0 +1,36 @@
package repo
import (
"admin/apps/game/domain/entity"
"admin/apps/game/model"
"admin/internal/errcode"
"gorm.io/gorm"
)
var NoticeRepoInstance INoticeRepo
type INoticeRepo interface {
List(projectId int) ([]*entity.CommonResource, error)
}
func NewNoticeRepo(db *gorm.DB) INoticeRepo {
return &noticeRepoImpl{db: db}
}
type noticeRepoImpl struct {
db *gorm.DB
}
func (impl *noticeRepoImpl) List(projectId int) ([]*entity.CommonResource, error) {
list := make([]*model.Notice, 0)
err := impl.db.Where("project_id = ?", projectId).Find(&list).Error
if err != nil {
return nil, errcode.New(errcode.DBError, "list server error:%v", err)
}
list1 := make([]*entity.CommonResource, 0, len(list))
for _, v := range list {
list1 = append(list1, (&entity.CommonResource{}).FromPo(v))
}
return list1, nil
}

View File

@ -0,0 +1,131 @@
package domain
import (
"admin/apps/game/domain/entity"
"admin/apps/game/model"
"admin/internal/errcode"
"bytes"
"strings"
"text/template"
"time"
)
type CdnServerInfo struct {
Properties [8]struct {
Key string
Value string
}
}
type CdnNoticeInfo struct {
Sn int
UpdataMod string
Title string
Content string
}
type CdnServerNoticeInfo struct {
ServerList []*CdnServerInfo
NoticeVersion string
NoticeList []*CdnNoticeInfo
}
func genCdnServerListContent(serverList, noticeList []*entity.CommonResource) (string, error) {
info := &CdnServerNoticeInfo{}
for _, server := range serverList {
serverDbInfo := server.Po.(*model.Server)
serverInfo := &CdnServerInfo{}
serverInfo.Properties[0].Key = "id"
serverInfo.Properties[0].Value = serverDbInfo.ServerConfID
addr := strings.Split(serverDbInfo.ClientConnAddr, ":")
serverInfo.Properties[1].Key = "ip"
serverInfo.Properties[1].Value = ""
if len(addr) == 2 {
serverInfo.Properties[1].Value = addr[0]
}
serverInfo.Properties[2].Key = "name"
serverInfo.Properties[2].Value = serverDbInfo.Desc
serverInfo.Properties[3].Key = "port"
serverInfo.Properties[3].Value = ""
if len(addr) == 2 {
serverInfo.Properties[3].Value = addr[1]
}
serverInfo.Properties[4].Key = "recommend"
serverInfo.Properties[4].Value = "0"
serverInfo.Properties[5].Key = "status"
serverInfo.Properties[5].Value = "0"
serverInfo.Properties[6].Key = "area"
serverInfo.Properties[6].Value = "1区"
serverInfo.Properties[7].Key = "type"
serverInfo.Properties[7].Value = "1"
info.ServerList = append(info.ServerList, serverInfo)
}
info.NoticeVersion = time.Now().Format("200601021504")
for i, notice := range noticeList {
noticeDbInfo := notice.Po.(*model.Notice)
noticeInfo := &CdnNoticeInfo{}
noticeInfo.Sn = i + 1
noticeInfo.UpdataMod = noticeDbInfo.Mod
noticeInfo.Title = noticeDbInfo.Title
noticeInfo.Content = noticeDbInfo.Content
info.NoticeList = append(info.NoticeList, noticeInfo)
}
bytesBuffer := bytes.NewBufferString("")
tpl, err := template.New("").Parse(cdnServerListContentTemplate)
if err != nil {
return "", errcode.New(errcode.ServerError, "new render template error:%v", err)
}
err = tpl.Execute(bytesBuffer, info)
if err != nil {
return "", errcode.New(errcode.ServerError, "execute render template error:%v", err)
}
return bytesBuffer.String(), nil
}
var cdnServerListContentTemplate = `
local Data = {}
Data.versionCode = "2.2.2"
Data.typenName = "iOS服务器"
--测试服务器
Data.apptest = {}
Data.zhuboAcount ={}
--正式服务器
Data.appOnline = {}
{{ range .ServerList }}
table.insert(Data.appOnline,{
{{- range .Properties }}
{{ .Key }} = "{{ .Value }}",
{{- end }}
})
{{- end }}
Data.notice = {}
Data.notice.version = "{{ .NoticeVersion }}"
Data.notice.info = {
{{- range .NoticeList }}
{sn={{.Sn}},updataMod="{{.UpdataMod}}",title="{{.Title}}",updataTxt="{{.Content}}"},
{{- end }}
}
Data.loginResult = {
Code1 = 99989,
Content1 = "服务器正在维护中",
Code2 = 99988,
Content2 = "服务器正在维护中",
}
return Data
`

View File

@ -11,12 +11,15 @@ func init() {
}
type Notice struct {
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"`
EndAt time.Time `name:"结束时间" required:"true"`
ID int `gorm:"primarykey" readonly:"true"`
ProjectId int `gorm:"index:idx_project_id"`
//ServerIDs []string `gorm:"type:json;serializer:json" name:"公告生效服务器" desc:"为空表示所有服" choices:"GetChoiceServers"`
Mod string `name:"公告分栏标题" desc:"显示到公告弹窗左边的分栏标题" required:"true"` // 左边分栏标题
Title string `name:"公告标题" desc:"显示到公告内容区里的标题" required:"true"` // 公告内容上面的标题
Content string `name:"公告内容" desc:"仅支持<color=#xxx></color>颜色标签和\\n换行标签" type:"text" required:"true"` // 公告内容
//StartAt time.Time `name:"开始时间" required:"true"`
//EndAt time.Time `name:"结束时间" required:"true"`
Status bool `name:"是否启用" type:"tagStatus" choices:"GetStatusChoices" required:"true"`
CreatedAt time.Time `readonly:"true"`
UpdatedAt time.Time `readonly:"true"`
@ -33,3 +36,10 @@ func (m *Notice) GetId() int {
func (m *Notice) GetChoiceServers(project *Project) []*dto.CommonDtoFieldChoice {
return getChoiceServers(project)
}
func (m *Notice) GetStatusChoices(project *Project) []*dto.CommonDtoFieldChoice {
return []*dto.CommonDtoFieldChoice{
{Desc: "禁用", Value: false},
{Desc: "启动", Value: true},
}
}

View File

@ -17,7 +17,7 @@ type Role struct {
Account string `name:"账号" json:"account" where:"eq"`
RoleId string `name:"角色ID" json:"roleId" where:"eq"`
Name string `name:"名称" json:"roleName" where:"eq"`
Status string `name:"状态" desc:"离线|在线" json:"status"`
Status string `name:"状态" desc:"离线|在线" type:"boolStatus" choices:"" json:"status"`
Level int `name:"等级" json:"roleLevel"`
Profession string `name:"职业" json:"profession"`
LatestLoginTime time.Time `name:"最近登录时间" json:"latestLoginAt"`
@ -35,3 +35,10 @@ func (m *Role) GetId() int {
func (m *Role) GetServerConfIDChoices(project *Project) []*dto.CommonDtoFieldChoice {
return getChoiceServers(project)
}
func (m *Role) GetStatusChoices(project *Project) []*dto.CommonDtoFieldChoice {
return []*dto.CommonDtoFieldChoice{
{Desc: "离线", Value: "离线"},
{Desc: "在线", Value: "在线"},
}
}

View File

@ -16,6 +16,7 @@ type Server struct {
ProjectId int `gorm:"uniqueIndex:idx_server"`
ServerConfID string `gorm:"type:varchar(200);uniqueIndex:idx_server" name:"区服id" required:"true" uneditable:"true"`
Desc string `name:"描述"`
ClientConnAddr string `name:"客户端连接地址" desc:"填 公网ip:公网端口" required:"true"`
RunningStatus string `name:"进程运行状态" desc:"进程运行状态:未知、运行中、停止" readonly:"true" uneditable:"true"`
Ccu int `name:"实时在线" desc:"ccu" readonly:"true" uneditable:"true"`
TotalRoleCount int `name:"总角色数" desc:"" readonly:"true" uneditable:"true"`

View File

@ -71,6 +71,10 @@ func (ctl *controller) CommonRowsSelection(ctx *context.WebContext, params *dto.
if err != nil {
return err
}
//if result.FileName != "" {
// ctx.OkFile(result.FileName, result.Msg)
// return nil
//}
*rsp = *result
return nil
}

View File

@ -2,9 +2,11 @@ package repo
import (
"admin/apps/user/model"
"admin/internal/errcode"
"admin/lib/tokenlib"
"errors"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"time"
)
@ -51,14 +53,20 @@ func (impl *tokenRepoImpl) GetTokenByUserId(userId int) (*model.Token, bool, err
func (impl *tokenRepoImpl) CreateToken(userId int, dura time.Duration) (*model.Token, error) {
tokenStr, err := tokenlib.GenToken(userId, dura)
if err != nil {
return nil, err
return nil, errcode.New(errcode.ServerError, "gen token for user:%v error:%v", userId, err)
}
po := &model.Token{
Token: tokenStr,
UserId: userId,
ExpireAt: time.Now().Add(dura),
}
err = impl.db.Create(po).Error
err = impl.db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "user_id"}},
DoUpdates: clause.AssignmentColumns([]string{"token", "expire_at"}),
}).Create(po).Error
if err != nil {
return nil, errcode.New(errcode.DBError, "save token for user:%v error:%v", po, err)
}
return po, err
}

View File

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

View File

@ -0,0 +1,10 @@
FROM harbor.devops.u.niu/tools/alpine:3.21
RUN apk add libc6-compat && apk add tzdata
WORKDIR /data
COPY admin .
COPY docker_entrypoint.sh .
ENTRYPOINT ["/data/admin"]

BIN
admin/cmd/all_in_one/admin Executable file

Binary file not shown.

10
admin/cmd/all_in_one/build.sh Executable file
View File

@ -0,0 +1,10 @@
#!/bin/bash
app="admin"
img_prefix="harbor.devops.u.niu/mid-platform"
img_tag="1.0.0"
go build -tags netgo -ldflags "-s -w" -trimpath -buildvcs=false -o $app
echo "准备构建:$app"
docker build -t $img_prefix/$app:$img_tag --file Dockerfile .
docker push $img_prefix/$app:$img_tag

View File

@ -0,0 +1,3 @@
#!/bin/sh
exec /data/admin $@ >>/data/log/admin-stdout.log 2>>/data/log/admin-stderr.log

11
admin/cmd/all_in_one/run.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash
docker rm -f udniugm
docker run \
--name udniugm -d \
-p 11080:8080 \
--restart always \
-v /etc/localtime:/etc/localtime \
-v /etc/timezone:/etc/timezone \
harbor.devops.u.niu/mid-platform/admin:1.0.0 \
-api_port 8080 -db_type mysql -db_addr 192.168.6.83:13306 -db_name uniugm -db_user root -db_pass dev123

View File

@ -58,8 +58,9 @@ const (
)
const (
BtnKeyGlobal_Server_DownAll = "server:down:all" // 一键维护
BtnKeyGlobal_Server_UpAll = "server:up:all" // 一键维护结束
BtnKeyGlobal_Server_DownAll = "server:down:all" // 一键维护
BtnKeyGlobal_Server_UpAll = "server:up:all" // 一键维护结束
BtnKeyGlobal_Server_ExportCdn = "server:export:cdn" // 一键导出cdn
)

View File

@ -51,6 +51,7 @@ type CommonRowsSelectionReq struct {
type CommonRowsSelectionRsp struct {
Msg string `json:"msg"`
NeedRefresh bool `json:"need_refresh"`
FileName string `json:"file_name"`
ShortDesc string `json:"short_desc"`
}

View File

@ -5,10 +5,10 @@
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
<script type="module" crossorigin src="/static/js/index-Dmkcc1nA.js"></script>
<link rel="modulepreload" crossorigin href="/static/js/vendor-DM-0sFCW.js">
<script type="module" crossorigin src="/static/js/index-DeMa4Gf_.js"></script>
<link rel="modulepreload" crossorigin href="/static/js/vendor-yjVdc_EO.js">
<link rel="stylesheet" crossorigin href="/static/css/vendor-xHoP3d6v.css">
<link rel="stylesheet" crossorigin href="/static/css/index-BqsFNddQ.css">
<link rel="stylesheet" crossorigin href="/static/css/index-BVwr4Ijb.css">
</head>
<body>
<div id="app"></div>

View File

@ -0,0 +1 @@
.app-content[data-v-564218c2]{height:calc(100vh - 100px);display:flex}.app-content .table-content[data-v-564218c2]{display:flex;flex-direction:column;justify-content:space-between;height:100%;overflow:auto}.app-content .table-content .table[data-v-564218c2]{flex:1;position:relative}.app-content .table-content .table[data-v-564218c2] .el-table{flex:1;position:absolute}.app-content1[data-v-564218c2]{height:calc(100vh - 300px);display:flex}.app-content1 .table-content[data-v-564218c2]{display:flex;flex-direction:column;justify-content:space-between;overflow:auto}.app-content1 .table-content .table[data-v-564218c2]{flex:1;position:relative}.app-content1 .table-content .table[data-v-564218c2] .el-table{flex:1;position:absolute}.pagination-container .el-pagination[data-v-564218c2]{right:0;position:absolute;height:25px;margin-bottom:50px;margin-top:0;padding:10px 30px!important;z-index:2}.pagination-container.hidden[data-v-564218c2]{display:none}@media (max-width: 768px){.pagination-container .el-pagination>.el-pagination__jump[data-v-564218c2]{display:none!important}.pagination-container .el-pagination>.el-pagination__sizes[data-v-564218c2]{display:none!important}}

View File

@ -0,0 +1 @@
body{height:100%;margin:0;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;font-family:Helvetica Neue,Helvetica,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Arial,sans-serif;background:gray}label{font-weight:700}html{height:100%;box-sizing:border-box}#app{height:100%}*,*:before,*:after{box-sizing:inherit}h1[data-v-73cc4e85]{color:#333;text-align:center;margin-bottom:20px}.app-container[data-v-73cc4e85]{height:100vh;overflow:hidden}.app-container .app-sidebar[data-v-73cc4e85]{position:fixed;left:0;top:0;bottom:0;width:200px;z-index:1000;overflow-y:auto;box-shadow:2px 0 6px #0000001a;background-color:#4d4f52}.app-container .app-sidebar .sidebar-content[data-v-73cc4e85]{overflow-y:auto}.app-container .app-container-right[data-v-73cc4e85]{min-height:100vh;margin-left:200px;flex-direction:column}.app-container .app-container-right .app-header[data-v-73cc4e85]{height:60px;background:#fff;border-bottom:1px solid #e6e6e6;box-shadow:0 1px 4px #0000001a}.app-container .app-container-right .app-main[data-v-73cc4e85]{height:calc(100vh - 70px);flex:1;padding:20px;background:#f0f2f5}.sidebar-logo[data-v-73cc4e85]{display:flex;align-items:center;padding:20px 0;text-align:center;background:transparent;position:relative;z-index:1;cursor:pointer}.sidebar-logo .logo[data-v-73cc4e85]{width:50px;height:50px;margin-bottom:10px;filter:drop-shadow(0 0 2px rgba(255,255,255,.5))}.sidebar-logo .system-name[data-v-73cc4e85]{color:#ffffffe6;margin:0;font-size:15px;font-weight:500;letter-spacing:1px;text-shadow:1px 1px 2px rgba(0,0,0,.2)}.el-menu-vertical-demo[data-v-73cc4e85]{flex:1;background-color:#4d4f52}[data-v-73cc4e85] .el-menu-vertical-demo .el-menu-item,[data-v-73cc4e85] .el-menu-vertical-demo .el-sub-menu{color:#fff;background-color:#4d4f52}[data-v-73cc4e85] .el-menu-vertical-demo .el-sub-menu__title{color:#fff}[data-v-73cc4e85] .el-menu-vertical-demo .el-menu-item:hover,[data-v-73cc4e85] .el-menu-vertical-demo .el-sub-menu__title:hover{background-color:#1f2d3d}[data-v-73cc4e85] .el-menu-vertical-demo .el-menu-item.is-active,[data-v-73cc4e85] .el-menu-vertical-demo .el-sub-menu__title.is-active{background-color:#20b2aa;color:#fff}[data-v-73cc4e85] .el-menu-vertical-demo .el-sub-menu__title i,[data-v-73cc4e85] .el-menu-vertical-demo .el-menu-item i{margin-right:10px}.avatar-container[data-v-73cc4e85]{height:50px;overflow:hidden;position:relative;float:right;background:#fff;box-shadow:0 1px 4px #00152914;margin-right:40px}.avatar-container .avatar-wrapper[data-v-73cc4e85]{margin-top:5px;position:relative;align-items:center;cursor:pointer}.avatar-container .avatar-wrapper i[data-v-73cc4e85]{cursor:pointer;position:absolute;right:-20px;top:25px;font-size:12px}

View File

@ -0,0 +1 @@
.app-content[data-v-911d06e1]{height:100%;display:flex}.app-content .table-content[data-v-911d06e1]{display:flex;flex-direction:column;justify-content:space-between;height:100%;overflow:auto}.app-content .table-content .table[data-v-911d06e1]{flex:1;position:relative}.app-content .table-content .table[data-v-911d06e1] .el-table{flex:1;position:absolute}.pagination-container .el-pagination[data-v-911d06e1]{right:0;position:absolute;height:25px;margin-bottom:50px;margin-top:0;padding:10px 30px!important;z-index:2}.pagination-container.hidden[data-v-911d06e1]{display:none}@media (max-width: 768px){.pagination-container .el-pagination>.el-pagination__jump[data-v-911d06e1]{display:none!important}.pagination-container .el-pagination>.el-pagination__sizes[data-v-911d06e1]{display:none!important}}

View File

@ -0,0 +1 @@
.roleDetailList[data-v-5a8d8958] .el-table__header-wrapper th{word-break:break-word;background-color:#f8f8f9!important;color:#515a6e;height:40px!important;font-size:13px}.roleDetailList[data-v-5a8d8958] .el-table__header .el-table-column--selection .cell{width:60px!important}.roleDetailList[data-v-5a8d8958] .el-table .fixed-width .el-button--small{padding-left:0;padding-right:0;width:20px!important}.roleDetailList[data-v-5a8d8958] .el-table__header{background:#f5f7fa!important}.roleDetailList[data-v-5a8d8958] .el-table__row td{border-color:#ebeef5}.app-content[data-v-6841a646]{height:calc(100vh - 100px);display:flex}.app-content .table-content[data-v-6841a646]{display:flex;flex-direction:column;justify-content:space-between;height:100%;overflow:auto}.app-content .table-content .table[data-v-6841a646]{flex:1;position:relative}.app-content .table-content .table[data-v-6841a646] .el-table{flex:1;position:absolute}.pagination-container .el-pagination[data-v-6841a646]{right:0;position:absolute;height:25px;margin-bottom:50px;margin-top:0;padding:10px 30px!important;z-index:2}.pagination-container.hidden[data-v-6841a646]{display:none}@media (max-width: 768px){.pagination-container .el-pagination>.el-pagination__jump[data-v-6841a646]{display:none!important}.pagination-container .el-pagination>.el-pagination__sizes[data-v-6841a646]{display:none!important}}

View File

@ -0,0 +1 @@
.app-content[data-v-01390b3f]{height:100%;display:flex}.table-content[data-v-01390b3f]{display:flex;flex-direction:column;justify-content:space-between;height:calc(100vh - 200px);overflow:auto}.table-content .table[data-v-01390b3f]{flex:1;position:relative}.table-content .table[data-v-01390b3f] .el-table{flex:1;position:absolute}.pagination-container .el-pagination[data-v-01390b3f]{right:0;position:absolute;height:25px;margin-bottom:50px;margin-top:0;padding:10px 30px!important;z-index:2}.pagination-container.hidden[data-v-01390b3f]{display:none}@media (max-width: 768px){.pagination-container .el-pagination>.el-pagination__jump[data-v-01390b3f]{display:none!important}.pagination-container .el-pagination>.el-pagination__sizes[data-v-01390b3f]{display:none!important}}

View File

@ -0,0 +1 @@
import{r as e,a9 as a,a as s,o,d as r,b as l,w as n,_ as t,a1 as u,aa as d,U as i,y as p,Z as m,a7 as c,J as v}from"./vendor-yjVdc_EO.js";import{_ as f,u as _,r as g}from"./index-DeMa4Gf_.js";const y={class:"login-box"},h={class:c({container:!0,animate__animated:!0,animate__flipInX:!0})},w={class:"form-container sign-in-container"},b=f({__name:"Login",setup(c){e(void 0);const{proxy:f}=a(),b=e({user:"",password:""}),V={user:[{required:!0,trigger:"blur",message:"请输入您的账号"}],password:[{required:!0,trigger:"blur",message:"请输入您的密码"}]},x=e=>{e&&f.$refs.ruleFormRef.validate((e=>{if(!e)return console.log("error submit!"),!1;_().login(b.value.user,b.value.password).then((()=>{console.log("登录成功,推送首页。。"),g.push({path:"/welcome"})}),(e=>{})).catch((()=>{v.error("login response error")}))}))};return(e,a)=>{const c=u,v=t,f=i,_=m;return o(),s("div",y,[r("div",h,[r("div",w,[l(_,{ref:"ruleFormRef",model:b.value,"status-icon":"",rules:V,class:"form"},{default:n((()=>[l(v,{class:"form-item",prop:"username"},{default:n((()=>[l(c,{modelValue:b.value.user,"onUpdate:modelValue":a[0]||(a[0]=e=>b.value.user=e),placeholder:"用户名",autocomplete:"off",onKeyup:a[1]||(a[1]=d((e=>x(b.value)),["enter"]))},null,8,["modelValue"])])),_:1}),l(v,{class:"form-item",prop:"password"},{default:n((()=>[l(c,{modelValue:b.value.password,"onUpdate:modelValue":a[2]||(a[2]=e=>b.value.password=e),placeholder:"密码",type:"password",autocomplete:"off",onKeyup:a[3]||(a[3]=d((e=>x(b.value)),["enter"]))},null,8,["modelValue"])])),_:1}),l(f,{class:"theme-button",type:"primary",onClick:a[4]||(a[4]=e=>x(b.value)),onKeydown:a[5]||(a[5]=d((e=>{var a;13!==a.keyCode&&100!==a.keyCode||x(b.value)}),["enter"]))},{default:n((()=>a[6]||(a[6]=[p("登 陆 ")]))),_:1})])),_:1},8,["model"])]),a[7]||(a[7]=r("div",{class:"overlay_container"},[r("div",{class:"overlay"},[r("div",{class:"overlay_panel overlay_right_container"},[r("h2",{class:"container-title"},"hello friend!"),r("p",null,"输入您的个人信息,以便使用后台管理系统")])])],-1))])])}}},[["__scopeId","data-v-68d4afe9"]]);export{b as default};

View File

@ -0,0 +1 @@
import{t as e}from"./tableUser-DLusgzKc.js";import{u as r,l as t}from"./index-DeMa4Gf_.js";import{a as s,o as a,c as o,x as c}from"./vendor-yjVdc_EO.js";import"./resource-CRV-w0LR.js";import"./empty-C-RENPGO.js";const m={__name:"character",setup(m){let u={meta:{desc:"character",resource:"character",resource_url:"/resource/character",methods:{get:!0,post:!0,put:!0,delete:!0}}};return"admin"!==r().userInfo.character&&(u.meta.methods={}),t.setCache("resource",u),(r,t)=>(a(),s("div",null,[(a(),o(c(e)))]))}};export{m as default};

View File

@ -0,0 +1 @@
import{c as o,o as r,af as s}from"./vendor-yjVdc_EO.js";import{_ as n}from"./index-DeMa4Gf_.js";const e=n({},[["render",function(n,e){const t=s;return r(),o(t,{description:"没有权限!请联系管理员添加权限!"})}]]);export{e};

View File

@ -0,0 +1 @@
import{t as s}from"./history-Dm6kV19W.js";import{c as o,o as t,x as i}from"./vendor-yjVdc_EO.js";import"./index-DeMa4Gf_.js";import"./empty-C-RENPGO.js";const r={__name:"history",setup:r=>(r,a)=>(t(),o(i(s),{disableConditionInput:false}))};export{r as default};

View File

@ -0,0 +1 @@
import{r as e,S as a,a as l,o as t,c as o,u,x as n,F as s,T as p,w as d,b as r,A as i,a5 as v,a1 as m,a6 as c,U as y,y as f,G as g,d as h,V as x,W as V,X as b,z as w,a7 as I}from"./vendor-yjVdc_EO.js";import{_ as k,u as _,a as C}from"./index-DeMa4Gf_.js";import{e as U}from"./empty-C-RENPGO.js";const z={class:"table-content"},j={class:"table"},R={class:"pagination-container"},S=k({__name:"history",props:{rowInfo:{},disableConditionInput:!0},setup(k){const S=k;let A=!0;!1===S.disableConditionInput&&(A=!1);const D="admin"===_().userInfo.character,G=e(D),T=e(1),F=e(20),K=e(S.userId);S.rowInfo&&void 0!==S.rowInfo.ID&&(K.value=S.rowInfo.ID);const N=e(""),P=e(""),W=e(""),X=e(""),q=e(!1),B=[20,50,100],E=e(0),H=e([]),J=()=>{C(T.value,F.value,K.value,N.value,P.value,W.value,X.value).then((e=>{H.value=e.data.list,E.value=e.data.totalCount,q.value=!0}),(e=>{}))};a((()=>{J()}));const L=()=>{K.value="",N.value="",P.value="",W.value="",X.value=""},M=e=>{E.value<=0||F.value*T.value>E.value&&H.value.length>=E.value||J()},O=e=>{J()};return(e,a)=>{const k=m,_=y,C=v,S=i,D=V,Q=x,Y=b,Z=g,$=w;return t(),l("div",{class:I(u(A)?"app-content1":"app-content")},[u(G)?(t(),l(s,{key:1},[u(q)?(t(),o($,{key:0},{default:d((()=>[r(S,{style:{"margin-bottom":"10px"}},{default:d((()=>[r(C,null,{default:d((()=>[!1===u(A)?(t(),o(k,{key:0,modelValue:u(K),"onUpdate:modelValue":a[0]||(a[0]=e=>c(K)?K.value=e:null),placeholder:"用户id",style:{width:"150px","margin-left":"10px"}},null,8,["modelValue"])):p("",!0),!1===u(A)?(t(),o(k,{key:1,modelValue:u(N),"onUpdate:modelValue":a[1]||(a[1]=e=>c(N)?N.value=e:null),placeholder:"操作资源类型",style:{width:"150px","margin-left":"10px"}},null,8,["modelValue"])):p("",!0),!1===u(A)?(t(),o(k,{key:2,modelValue:u(P),"onUpdate:modelValue":a[2]||(a[2]=e=>c(P)?P.value=e:null),placeholder:"操作资源组",style:{width:"150px","margin-left":"10px"}},null,8,["modelValue"])):p("",!0),!1===u(A)?(t(),o(k,{key:3,modelValue:u(W),"onUpdate:modelValue":a[3]||(a[3]=e=>c(W)?W.value=e:null),placeholder:"操作对象",style:{width:"150px","margin-left":"10px"}},null,8,["modelValue"])):p("",!0),!1===u(A)?(t(),o(k,{key:4,modelValue:u(X),"onUpdate:modelValue":a[4]||(a[4]=e=>c(X)?X.value=e:null),placeholder:"操作方法",style:{width:"150px","margin-left":"10px"}},null,8,["modelValue"])):p("",!0),!1===u(A)?(t(),o(_,{key:5,onClick:J,type:"primary",style:{"margin-left":"10px"}},{default:d((()=>a[7]||(a[7]=[f("条件搜索 ")]))),_:1})):p("",!0),!1===u(A)?(t(),o(_,{key:6,onClick:L},{default:d((()=>a[8]||(a[8]=[f("清空条件")]))),_:1})):p("",!0)])),_:1})])),_:1}),r(Z,null,{default:d((()=>[h("div",z,[h("div",j,[r(Q,{data:u(H),style:{width:"100%"},"table-layout":"auto",stripe:"","tooltip-effect":"light"},{default:d((()=>[r(D,{prop:"userId",label:"用户id"}),r(D,{prop:"userName",label:"用户名"}),r(D,{prop:"opResourceType",label:"操作资源类型"}),r(D,{prop:"opResourceGroup",label:"操作资源组"}),r(D,{prop:"opResourceKey",label:"操作对象"}),r(D,{prop:"method",label:"操作方法"}),r(D,{prop:"createdAt",label:"创建时间"}),r(D,{prop:"detailInfo",label:"详情数据","show-overflow-tooltip":""})])),_:1},8,["data"])]),h("div",R,[r(Y,{"current-page":u(T),"onUpdate:currentPage":a[5]||(a[5]=e=>c(T)?T.value=e:null),"page-size":u(F),"onUpdate:pageSize":a[6]||(a[6]=e=>c(F)?F.value=e:null),"page-sizes":B,layout:"total, sizes, prev, pager, next, jumper",total:u(E),onSizeChange:M,onCurrentChange:O},null,8,["current-page","page-size","total"])])])])),_:1})])),_:1})):p("",!0)],64)):(t(),o(n(U),{key:0}))],2)}}},[["__scopeId","data-v-564218c2"]]);export{S as t};

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
import{t as e}from"./table-D1Kdvwhj.js";import{l as s,u as r,c as t}from"./index-DeMa4Gf_.js";import{i as a,a as o,o as m,c,x as i}from"./vendor-yjVdc_EO.js";import"./resource-CRV-w0LR.js";import"./empty-C-RENPGO.js";import"./string-C8RKaQUb.js";const p={__name:"project",setup(p){s.setCache("project",{}),a();let n=t;return"admin"!==r().userInfo.character&&(n.meta.methods={}),s.setCache("resource",n),(s,r)=>(m(),o("div",null,[(m(),c(i(e)))]))}};export{p as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
import{s as t}from"./index-DeMa4Gf_.js";function r(r,e){return t({url:r,method:"get",params:e})}function e(r,e){return t({url:r,method:"post",data:{dto:e}})}function o(r,e){return t({url:r,method:"put",data:{dto:e}})}function n(r,e){return t({url:r,method:"delete",data:e})}function u(r,e){return t({url:r+"/selection",method:"post",data:e})}function a(r){return t({url:"/project/"+r.toString()+"/items",method:"get"})}export{n as a,e as b,o as c,a as d,u as e,r};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
import{t as e}from"./tableUser-DLusgzKc.js";import{u as s,l as r}from"./index-DeMa4Gf_.js";import{t}from"./history-Dm6kV19W.js";import{a as o,o as a,c,x as m}from"./vendor-yjVdc_EO.js";import"./resource-CRV-w0LR.js";import"./empty-C-RENPGO.js";const u={__name:"user",setup(u){let n={meta:{desc:"user",resource:"user",resource_url:"/resource/user",methods:{get:!0,post:!0,put:!0,delete:!0}}};"admin"!==s().userInfo.character&&(n.meta.methods={}),r.setCache("resource",n);const p=[];return p.push({key:"user:exec:history",name:"执行记录",btn_color_type:"info",btn_type:1,btn_callback_component:t}),(s,r)=>(a(),o("div",null,[(a(),c(m(e),{rowClickDialogBtns:p}))]))}};export{u as default};

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
import{a as s,o as a,d as e,b as n,y as t,t as o,u as r,a8 as p,F as l}from"./vendor-yjVdc_EO.js";import{u}from"./index-DeMa4Gf_.js";const f={style:{"font-size":"40px"}},i={style:{color:"darkslategrey","font-size":"50px"}},m={__name:"welcome",setup(m){const c=u().userInfo;return(u,m)=>{const d=p;return a(),s(l,null,[e("span",f,[m[0]||(m[0]=t("亲爱的")),e("span",i,o(r(c).nick_name),1),m[1]||(m[1]=t("!欢迎使用本公司后台管理系统!"))]),n(d),m[2]||(m[2]=e("span",{style:{"font-size":"40px"}},"硬盘有价,数据无价,操作不规范,亲人两行泪。",-1))],64)}}};export{m as default};

View File

@ -208,8 +208,30 @@ const handleTableSelectRowsSendToServer = (btnInfo, rows) => {
ElMessageBox.confirm("确定要操作吗?").then(() => {
resourceRowsSelectionPost(resource_url, {btn_key: btnInfo.key, rows: rows}).then((res) => {
const resultMsg = res.data.msg
let fileName = res.data.file_name
const needRefresh = res.data.need_refresh
if (fileName !== "") {
//
const filenameRegex = /filename\*?=(?:UTF-8'')?"?([^";]+)"?/i;
const matches = fileName.match(filenameRegex);
if (matches && matches[1]) {
fileName = decodeURIComponent(matches[1]); //
}
//
const blob = new Blob([resultMsg]);
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = fileName;
link.click();
//
window.URL.revokeObjectURL(link.href);
return
}
ElNotification({
title: "操作行数据返回",
message: h('i', {style: 'color: teal'}, resultMsg),
@ -543,10 +565,10 @@ const handlePaginationCurChange = (val) => {
v-if="(fieldDescInfo.type === 'items')"></el-table-column>
<!-- 角色状态 -->
<el-table-column prop="jsonValue" :label="fieldDescInfo.name"
v-else-if="(fieldDescInfo.key === 'Status' && cachedResource.meta.resource === 'role' )">
v-else-if="(fieldDescInfo.type === 'boolStatus')">
<template #default="scope">
<el-tag type="info" v-if="scope.row.Status === '离线'">离线</el-tag>
<el-tag type="success" v-else-if="scope.row.Status === '在线'">在线</el-tag>
<el-tag type="info" v-if="scope.row.Status === '离线'">{{ scope.row.Status }}</el-tag>
<el-tag type="success" v-else-if="scope.row.Status === '在线'">{{ scope.row.Status }}</el-tag>
</template>
</el-table-column>
<!-- 其它普通字段 -->
@ -701,7 +723,12 @@ const handlePaginationCurChange = (val) => {
<template v-else>
<el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
<el-input v-model="dialogObjectForm[fieldDescInfo.key]"
:placeholder="fieldDescInfo.help_text"></el-input>
:placeholder="fieldDescInfo.help_text" type="textarea"
:autosize="{minRows: 2, maxRows: 10}"
v-if="(fieldDescInfo.type === 'text')"></el-input>
<el-input v-model="dialogObjectForm[fieldDescInfo.key]"
:placeholder="fieldDescInfo.help_text"
v-else></el-input>
</el-form-item>
</template>
</template>
@ -797,7 +824,11 @@ const handlePaginationCurChange = (val) => {
<template v-else>
<el-form-item :label="fieldDescInfo.name" :prop="fieldDescInfo.key">
<el-input v-model="dialogObjectForm[fieldDescInfo.key]"
:placeholder="fieldDescInfo.help_text"></el-input>
:placeholder="fieldDescInfo.help_text" type="textarea"
:autosize="{minRows: 2, maxRows: 10}"
v-if="(fieldDescInfo.type === 'text')"></el-input>
<el-input v-model="dialogObjectForm[fieldDescInfo.key]"
:placeholder="fieldDescInfo.help_text" v-else></el-input>
</el-form-item>
</template>
</template>

View File

@ -43,7 +43,7 @@ const reqInterceptor = (config) => {
config.headers.Token = token;
config.headers['Authorization'] = 'Bearer ' + token;
console.log("获取缓存token:", tokenInfo, " 获取缓存用户数据:", user, " 发送http头", config.headers)
// console.log("获取缓存token:", tokenInfo, " 获取缓存用户数据:", user, " 发送http头", config.headers)
// const token = ExpireCache.getCache('token')
// if(token){