增加用户系统界面管理、用户可以设置关联集群

This commit is contained in:
GoEdgeLab
2020-12-16 15:49:15 +08:00
parent 041ead3d7f
commit ee549b945d
30 changed files with 411 additions and 312 deletions
@@ -9,17 +9,17 @@ import (
"reflect"
)
var sharedUIConfig *systemconfigs.AdminUIConfig = nil
var sharedAdminUIConfig *systemconfigs.AdminUIConfig = nil
const (
UISettingName = "adminUIConfig"
AdminUISettingName = "adminUIConfig"
)
func LoadUIConfig() (*systemconfigs.AdminUIConfig, error) {
func LoadAdminUIConfig() (*systemconfigs.AdminUIConfig, error) {
locker.Lock()
defer locker.Unlock()
config, err := loadUIConfig()
config, err := loadAdminUIConfig()
if err != nil {
return nil, err
}
@@ -28,7 +28,7 @@ func LoadUIConfig() (*systemconfigs.AdminUIConfig, error) {
return &v, nil
}
func UpdateUIConfig(uiConfig *systemconfigs.AdminUIConfig) error {
func UpdateAdminUIConfig(uiConfig *systemconfigs.AdminUIConfig) error {
locker.Lock()
defer locker.Unlock()
@@ -41,48 +41,48 @@ func UpdateUIConfig(uiConfig *systemconfigs.AdminUIConfig) error {
return err
}
_, err = rpcClient.SysSettingRPC().UpdateSysSetting(rpcClient.Context(0), &pb.UpdateSysSettingRequest{
Code: UISettingName,
Code: AdminUISettingName,
ValueJSON: valueJSON,
})
if err != nil {
return err
}
sharedUIConfig = uiConfig
sharedAdminUIConfig = uiConfig
return nil
}
func loadUIConfig() (*systemconfigs.AdminUIConfig, error) {
if sharedUIConfig != nil {
return sharedUIConfig, nil
func loadAdminUIConfig() (*systemconfigs.AdminUIConfig, error) {
if sharedAdminUIConfig != nil {
return sharedAdminUIConfig, nil
}
var rpcClient, err = rpc.SharedRPC()
if err != nil {
return nil, err
}
resp, err := rpcClient.SysSettingRPC().ReadSysSetting(rpcClient.Context(0), &pb.ReadSysSettingRequest{
Code: UISettingName,
Code: AdminUISettingName,
})
if err != nil {
return nil, err
}
if len(resp.ValueJSON) == 0 {
sharedUIConfig = defaultUIConfig()
return sharedUIConfig, nil
sharedAdminUIConfig = defaultAdminUIConfig()
return sharedAdminUIConfig, nil
}
config := &systemconfigs.AdminUIConfig{}
err = json.Unmarshal(resp.ValueJSON, config)
if err != nil {
logs.Println("[UI_MANAGER]" + err.Error())
sharedUIConfig = defaultUIConfig()
return sharedUIConfig, nil
sharedAdminUIConfig = defaultAdminUIConfig()
return sharedAdminUIConfig, nil
}
sharedUIConfig = config
return sharedUIConfig, nil
sharedAdminUIConfig = config
return sharedAdminUIConfig, nil
}
func defaultUIConfig() *systemconfigs.AdminUIConfig {
func defaultAdminUIConfig() *systemconfigs.AdminUIConfig {
return &systemconfigs.AdminUIConfig{
ProductName: "GoEdge",
AdminSystemName: "GoEdge管理员系统",
+92
View File
@@ -0,0 +1,92 @@
package configloaders
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
"github.com/iwind/TeaGo/logs"
"reflect"
)
var sharedUserUIConfig *systemconfigs.UserUIConfig = nil
const (
UserUISettingName = "userUIConfig"
)
func LoadUserUIConfig() (*systemconfigs.UserUIConfig, error) {
locker.Lock()
defer locker.Unlock()
config, err := loadUserUIConfig()
if err != nil {
return nil, err
}
v := reflect.Indirect(reflect.ValueOf(config)).Interface().(systemconfigs.UserUIConfig)
return &v, nil
}
func UpdateUserUIConfig(uiConfig *systemconfigs.UserUIConfig) error {
locker.Lock()
defer locker.Unlock()
var rpcClient, err = rpc.SharedRPC()
if err != nil {
return err
}
valueJSON, err := json.Marshal(uiConfig)
if err != nil {
return err
}
_, err = rpcClient.SysSettingRPC().UpdateSysSetting(rpcClient.Context(0), &pb.UpdateSysSettingRequest{
Code: UserUISettingName,
ValueJSON: valueJSON,
})
if err != nil {
return err
}
sharedUserUIConfig = uiConfig
return nil
}
func loadUserUIConfig() (*systemconfigs.UserUIConfig, error) {
if sharedUserUIConfig != nil {
return sharedUserUIConfig, nil
}
var rpcClient, err = rpc.SharedRPC()
if err != nil {
return nil, err
}
resp, err := rpcClient.SysSettingRPC().ReadSysSetting(rpcClient.Context(0), &pb.ReadSysSettingRequest{
Code: UserUISettingName,
})
if err != nil {
return nil, err
}
if len(resp.ValueJSON) == 0 {
sharedUserUIConfig = defaultUserUIConfig()
return sharedUserUIConfig, nil
}
config := &systemconfigs.UserUIConfig{}
err = json.Unmarshal(resp.ValueJSON, config)
if err != nil {
logs.Println("[UI_MANAGER]" + err.Error())
sharedUserUIConfig = defaultUserUIConfig()
return sharedUserUIConfig, nil
}
sharedUserUIConfig = config
return sharedUserUIConfig, nil
}
func defaultUserUIConfig() *systemconfigs.UserUIConfig {
return &systemconfigs.UserUIConfig{
ProductName: "GoEdge",
UserSystemName: "GoEdge用户系统",
ShowOpenSourceInfo: true,
ShowVersion: true,
}
}
@@ -17,6 +17,12 @@ func init() {
GetPost("/create", new(CreateAction)).
Post("/sync", new(SyncAction)).
Post("/checkChange", new(CheckChangeAction)).
// 只要登录即可访问的Action
EndHelpers().
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeCommon)).
Post("/options", new(OptionsAction)).
EndAll()
})
}
@@ -0,0 +1,30 @@
package clusters
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
)
type OptionsAction struct {
actionutils.ParentAction
}
func (this *OptionsAction) RunPost(params struct{}) {
clustersResp, err := this.RPC().NodeClusterRPC().FindAllEnabledNodeClusters(this.AdminContext(), &pb.FindAllEnabledNodeClustersRequest{})
if err != nil {
this.ErrorPage(err)
return
}
clusterMaps := []maps.Map{}
for _, cluster := range clustersResp.Clusters {
clusterMaps = append(clusterMaps, maps.Map{
"id": cluster.Id,
"name": cluster.Name,
})
}
this.Data["clusters"] = clusterMaps
this.Success()
}
@@ -78,7 +78,7 @@ func (this *PricesAction) formatBits(bits int64) string {
} else if bits < 1_000_000_000_000_000 {
sizeHuman = fmt.Sprintf("%.2fTBPS", float64(bits)/1000/1000/1000/1000)
} else {
sizeHuman = fmt.Sprintf("%.2fPTBPS", float64(bits)/1000/1000/1000/1000/1000)
sizeHuman = fmt.Sprintf("%.2fPBPS", float64(bits)/1000/1000/1000/1000/1000)
}
return sizeHuman
}
@@ -13,6 +13,4 @@ func (this *IndexAction) Init() {
func (this *IndexAction) RunGet(params struct{}) {
// TODO 暂时先跳转到账单页,将来做成Dashboard
this.RedirectURL("/finance/bills")
this.Show()
}
+1 -1
View File
@@ -50,7 +50,7 @@ func (this *IndexAction) RunGet(params struct {
this.Data["token"] = stringutil.Md5(TokenSalt+timestamp) + timestamp
this.Data["from"] = params.From
config, err := configloaders.LoadUIConfig()
config, err := configloaders.LoadAdminUIConfig()
if err != nil {
this.ErrorPage(err)
return
@@ -30,7 +30,8 @@ func (this *Helper) BeforeAction(actionPtr actions.ActionWrapper) (goNext bool)
var adminId = session.GetInt64("adminId")
if configloaders.AllowModule(adminId, configloaders.AdminModuleCodeSetting) {
tabbar.Add("Web服务", "", "/settings/server", "", this.tab == "server")
tabbar.Add("界面设置", "", "/settings/ui", "", this.tab == "ui")
tabbar.Add("管理界面设置", "", "/settings/ui", "", this.tab == "ui")
tabbar.Add("用户界面设置", "", "/settings/user-ui", "", this.tab == "userUI")
tabbar.Add("安全设置", "", "/settings/security", "", this.tab == "security")
tabbar.Add("IP库", "", "/settings/ip-library", "", this.tab == "ipLibrary")
tabbar.Add("备份", "", "/settings/backup", "", this.tab == "backup")
@@ -1,4 +1,4 @@
package server
package ui
import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
@@ -15,7 +15,7 @@ func (this *IndexAction) Init() {
}
func (this *IndexAction) RunGet(params struct{}) {
config, err := configloaders.LoadUIConfig()
config, err := configloaders.LoadAdminUIConfig()
if err != nil {
this.ErrorPage(err)
return
@@ -41,7 +41,7 @@ func (this *IndexAction) RunPost(params struct {
Field("adminSystemName", params.AdminSystemName).
Require("请输入管理员系统名称")
config, err := configloaders.LoadUIConfig()
config, err := configloaders.LoadAdminUIConfig()
if err != nil {
this.ErrorPage(err)
return
@@ -51,7 +51,7 @@ func (this *IndexAction) RunPost(params struct {
config.ShowOpenSourceInfo = params.ShowOpenSourceInfo
config.ShowVersion = params.ShowVersion
config.Version = params.Version
err = configloaders.UpdateUIConfig(config)
err = configloaders.UpdateAdminUIConfig(config)
if err != nil {
this.ErrorPage(err)
return
@@ -1,4 +1,4 @@
package server
package ui
import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
@@ -0,0 +1,61 @@
package userui
import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/iwind/TeaGo/actions"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "", "")
}
func (this *IndexAction) RunGet(params struct{}) {
config, err := configloaders.LoadUserUIConfig()
if err != nil {
this.ErrorPage(err)
return
}
this.Data["config"] = config
this.Show()
}
func (this *IndexAction) RunPost(params struct {
ProductName string
UserSystemName string
ShowOpenSourceInfo bool
ShowVersion bool
Version string
Must *actions.Must
CSRF *actionutils.CSRF
}) {
params.Must.
Field("productName", params.ProductName).
Require("请输入产品名称").
Field("userSystemName", params.UserSystemName).
Require("请输入管理员系统名称")
config, err := configloaders.LoadUserUIConfig()
if err != nil {
this.ErrorPage(err)
return
}
config.ProductName = params.ProductName
config.UserSystemName = params.UserSystemName
config.ShowOpenSourceInfo = params.ShowOpenSourceInfo
config.ShowVersion = params.ShowVersion
config.Version = params.Version
err = configloaders.UpdateUserUIConfig(config)
if err != nil {
this.ErrorPage(err)
return
}
this.Success()
}
@@ -0,0 +1,19 @@
package userui
import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/settingutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/iwind/TeaGo"
)
func init() {
TeaGo.BeforeStart(func(server *TeaGo.Server) {
server.
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeCommon)).
Helper(settingutils.NewHelper("userUI")).
Prefix("/settings/user-ui").
GetPost("", new(IndexAction)).
EndAll()
})
}
@@ -20,14 +20,15 @@ func (this *CreatePopupAction) RunGet(params struct{}) {
}
func (this *CreatePopupAction) RunPost(params struct {
Username string
Pass1 string
Pass2 string
Fullname string
Mobile string
Tel string
Email string
Remark string
Username string
Pass1 string
Pass2 string
Fullname string
Mobile string
Tel string
Email string
Remark string
ClusterId int64
Must *actions.Must
CSRF *actionutils.CSRF
@@ -60,6 +61,10 @@ func (this *CreatePopupAction) RunPost(params struct {
Field("fullname", params.Fullname).
Require("请输入全名")
if params.ClusterId <= 0 {
this.Fail("请选择关联集群")
}
if len(params.Mobile) > 0 {
params.Must.
Field("mobile", params.Mobile).
@@ -72,14 +77,15 @@ func (this *CreatePopupAction) RunPost(params struct {
}
createResp, err := this.RPC().UserRPC().CreateUser(this.AdminContext(), &pb.CreateUserRequest{
Username: params.Username,
Password: params.Pass1,
Fullname: params.Fullname,
Mobile: params.Mobile,
Tel: params.Tel,
Email: params.Email,
Remark: params.Remark,
Source: "admin:" + numberutils.FormatInt64(this.AdminId()),
Username: params.Username,
Password: params.Pass1,
Fullname: params.Fullname,
Mobile: params.Mobile,
Tel: params.Tel,
Email: params.Email,
Remark: params.Remark,
Source: "admin:" + numberutils.FormatInt64(this.AdminId()),
ClusterId: params.ClusterId,
})
if err != nil {
this.ErrorPage(err)
@@ -34,6 +34,13 @@ func (this *IndexAction) RunGet(params struct {
}
userMaps := []maps.Map{}
for _, user := range usersResp.Users {
var clusterMap maps.Map = nil
if user.Cluster != nil {
clusterMap = maps.Map{
"id": user.Cluster.Id,
"name": user.Cluster.Name,
}
}
userMaps = append(userMaps, maps.Map{
"id": user.Id,
"username": user.Username,
@@ -43,6 +50,7 @@ func (this *IndexAction) RunGet(params struct {
"mobile": user.Mobile,
"tel": user.Tel,
"createdTime": timeutil.FormatTime("Y-m-d H:i:s", user.CreatedAt),
"cluster": clusterMap,
})
}
this.Data["users"] = userMaps
+26 -19
View File
@@ -47,20 +47,26 @@ func (this *UpdateAction) RunGet(params struct {
"isOn": user.IsOn,
}
this.Data["clusterId"] = 0
if user.Cluster != nil {
this.Data["clusterId"] = user.Cluster.Id
}
this.Show()
}
func (this *UpdateAction) RunPost(params struct {
UserId int64
Username string
Pass1 string
Pass2 string
Fullname string
Mobile string
Tel string
Email string
Remark string
IsOn bool
UserId int64
Username string
Pass1 string
Pass2 string
Fullname string
Mobile string
Tel string
Email string
Remark string
IsOn bool
ClusterId int64
Must *actions.Must
CSRF *actionutils.CSRF
@@ -109,15 +115,16 @@ func (this *UpdateAction) RunPost(params struct {
}
_, err = this.RPC().UserRPC().UpdateUser(this.AdminContext(), &pb.UpdateUserRequest{
UserId: params.UserId,
Username: params.Username,
Password: params.Pass1,
Fullname: params.Fullname,
Mobile: params.Mobile,
Tel: params.Tel,
Email: params.Email,
Remark: params.Remark,
IsOn: params.IsOn,
UserId: params.UserId,
Username: params.Username,
Password: params.Pass1,
Fullname: params.Fullname,
Mobile: params.Mobile,
Tel: params.Tel,
Email: params.Email,
Remark: params.Remark,
IsOn: params.IsOn,
ClusterId: params.ClusterId,
})
if err != nil {
this.ErrorPage(err)
@@ -35,6 +35,14 @@ func (this *UserAction) RunGet(params struct {
return
}
var clusterMap maps.Map = nil
if user.Cluster != nil {
clusterMap = maps.Map{
"id": user.Cluster.Id,
"name": user.Cluster.Name,
}
}
this.Data["user"] = maps.Map{
"id": user.Id,
"username": user.Username,
@@ -44,6 +52,7 @@ func (this *UserAction) RunGet(params struct {
"remark": user.Remark,
"mobile": user.Mobile,
"isOn": user.IsOn,
"cluster": clusterMap,
}
this.Show()
+1 -1
View File
@@ -74,7 +74,7 @@ func (this *userMustAuth) BeforeAction(actionPtr actions.ActionWrapper, paramNam
return true
}
config, err := configloaders.LoadUIConfig()
config, err := configloaders.LoadAdminUIConfig()
if err != nil {
action.WriteString(err.Error())
return false
+1
View File
@@ -86,6 +86,7 @@ import (
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/ui"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/upgrade"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/user-nodes"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/user-ui"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/setup"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ui"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/users"
@@ -0,0 +1,28 @@
Vue.component("cluster-selector", {
mounted: function () {
let that = this
Tea.action("/clusters/options")
.post()
.success(function (resp) {
that.clusters = resp.data.clusters
})
},
props: ["v-cluster-id"],
data: function () {
let clusterId = this.vClusterId
if (clusterId == null) {
clusterId = 0
}
return {
clusters: [],
clusterId: clusterId
}
},
template: `<div>
<select class="ui dropdown auto-width" name="clusterId" v-model="clusterId">
<option value="0">[选择集群]</option>
<option v-for="cluster in clusters" :value="cluster.id">{{cluster.name}}</option>
</select>
</div>`
})
+3 -110
View File
@@ -213,9 +213,6 @@ body .ui.menu .item .blink {
body.expanded .main-menu {
display: none;
}
body.expanded .sub-menu {
display: none;
}
body.expanded .main {
left: 1em;
}
@@ -226,6 +223,7 @@ body.expanded .main {
width: 100%;
z-index: 1000;
overflow-x: auto;
border: 0 !important;
background: #276ac6 !important;
}
.top-nav::-webkit-scrollbar {
@@ -362,6 +360,8 @@ body.expanded .main {
}
.main-menu .menu {
background: #276ac6 !important;
border: 0 !important;
box-shadow: none !important;
}
.main-menu::-webkit-scrollbar {
width: 2px;
@@ -401,113 +401,6 @@ body.expanded .main {
z-index: 999999;
background: white;
}
/** 子菜单 **/
.main.without-menu .sub-menu {
display: none;
}
.sub-menu {
position: fixed;
left: 8em;
width: 12.5em;
top: 3em;
bottom: 2.8em;
}
.sub-menu .menus-box {
overflow-y: auto;
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
padding-right: 0.4em !important;
}
.sub-menu .menus-box::-webkit-scrollbar {
width: 4px;
height: 4px;
}
.sub-menu .menu {
max-width: 12em !important;
border-right: 0 !important;
}
@media screen and (max-width: 512px) {
.sub-menu {
position: relative;
width: 100%;
left: 0;
top: 0;
}
.sub-menu .menus-box {
position: relative !important;
}
.sub-menu .menu {
width: 100% !important;
max-width: 30em !important;
}
.sub-menu .menus-box .menu .item {
width: 100% !important;
max-width: 30em !important;
}
}
.sub-menu .menu .item.active {
font-weight: normal !important;
outline: none !important;
}
.sub-menu .menu .item:not(.header) {
padding-top: 0.7em !important;
padding-bottom: 0.7em !important;
}
.sub-menu .menu .item:not(.header) span {
font-size: 0.8em;
display: block;
margin-top: 0.6em !important;
line-height: 1.5;
}
.sub-menu .menu .item:not(.active):hover {
background: rgba(0, 0, 0, 0.05) !important;
border-top: 1px white solid !important;
border-bottom: 1px white solid !important;
margin-top: -1px !important;
margin-bottom: -1px !important;
}
.sub-menu .menu .item.active {
background: rgba(0, 0, 0, 0.05) !important;
}
.sub-menu .menu .item var {
font-style: normal;
}
.sub-menu .menu .item:not(.active) var.grey {
color: grey;
}
.sub-menu .menu .item span:not(.green) {
color: grey;
}
.sub-menu .menu .item span.red {
color: #db2828 !important;
}
.sub-menu .menus-box .menu .item.header {
padding-right: 0.2em !important;
cursor: pointer;
}
.sub-menu .menus-box .menu .item.header span {
font-weight: normal;
color: grey;
font-size: 0.8em;
}
.sub-menu .menus-box .menu a {
display: block;
word-break: break-all;
line-height: 1.6 !important;
}
.sub-menu .menus-box .menu .item .menu {
margin-top: 0 !important;
}
.sub-menu .fourth-menu {
margin-left: 1.2em;
}
.sub-menu .fourth-menu .icon,
.sub-menu .third-menu .icon {
float: left !important;
}
/** 右侧文本子菜单 **/
.text.menu {
overflow-x: auto;
File diff suppressed because one or more lines are too long
+6 -137
View File
@@ -171,10 +171,6 @@ body.expanded .main-menu {
display: none;
}
body.expanded .sub-menu {
display: none;
}
body.expanded .main {
left: 1em;
}
@@ -186,6 +182,7 @@ body.expanded .main {
width: 100%;
z-index: 1000;
overflow-x: auto;
border: 0 !important;
background: #276ac6 !important;
}
@@ -349,10 +346,12 @@ body.expanded .main {
overflow-y: auto;
background: #276ac6 !important;
z-index: 10;
}
.main-menu .menu {
background: #276ac6 !important;
.menu {
background: #276ac6 !important;
border: 0 !important;
box-shadow: none !important;
}
}
.main-menu::-webkit-scrollbar {
@@ -405,136 +404,6 @@ body.expanded .main {
background: white;
}
/** 子菜单 **/
.main.without-menu .sub-menu {
display: none;
}
.sub-menu {
position: fixed;
left: 8em;
width: 12.5em;
top: 3em;
bottom: 2.8em;
}
.sub-menu .menus-box {
overflow-y: auto;
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
padding-right: 0.4em !important;
}
.sub-menu .menus-box::-webkit-scrollbar {
width: 4px;
height: 4px;
}
.sub-menu .menu {
max-width: 12em !important;
border-right: 0 !important;
}
@media screen and (max-width: 512px) {
.sub-menu {
position: relative;
width: 100%;
left: 0;
top: 0;
}
.sub-menu .menus-box {
position: relative !important;
}
.sub-menu .menu {
width: 100% !important;
max-width: 30em !important;
}
.sub-menu .menus-box .menu .item {
width: 100% !important;
max-width: 30em !important;
}
}
.sub-menu .menu .item.active {
font-weight: normal !important;
outline: none !important;
}
.sub-menu .menu .item:not(.header) {
padding-top: 0.7em !important;
padding-bottom: 0.7em !important;
}
.sub-menu .menu .item:not(.header) span {
font-size: 0.8em;
display: block;
margin-top: 0.6em !important;
line-height: 1.5;
}
.sub-menu .menu .item:not(.active):hover {
background: rgba(0, 0, 0, 0.05) !important;
border-top: 1px white solid !important;
border-bottom: 1px white solid !important;
margin-top: -1px !important;
margin-bottom: -1px !important;
}
.sub-menu .menu .item.active {
background: rgba(0, 0, 0, 0.05) !important;
}
.sub-menu .menu .item var {
font-style: normal;
}
.sub-menu .menu .item:not(.active) var.grey {
color: grey;
}
.sub-menu .menu .item span:not(.green) {
color: grey;
}
.sub-menu .menu .item span.red {
color: #db2828 !important;
}
.sub-menu .menus-box .menu .item.header {
padding-right: 0.2em !important;
cursor: pointer;
}
.sub-menu .menus-box .menu .item.header span {
font-weight: normal;
color: grey;
font-size: 0.8em;
}
.sub-menu .menus-box .menu a {
display: block;
word-break: break-all;
line-height: 1.6 !important;
}
.sub-menu .menus-box .menu .item .menu {
margin-top: 0 !important;
}
.sub-menu .fourth-menu {
margin-left: 1.2em;
}
.sub-menu .fourth-menu .icon, .sub-menu .third-menu .icon {
float: left !important;
}
/** 右侧文本子菜单 **/
.text.menu {
overflow-x: auto;
@@ -0,0 +1,41 @@
{$layout}
<form class="ui form" method="post" data-tea-action="$" data-tea-success="success">
<csrf-token></csrf-token>
<table class="ui table definition selectable">
<tr>
<td class="title">产品名称 *</td>
<td>
<input type="text" name="productName" v-model="config.productName" maxlength="100"/>
</td>
</tr>
<tr>
<td>用户系统名称 *</td>
<td>
<input type="text" name="userSystemName" v-model="config.userSystemName" maxlength="100"/>
</td>
</tr>
<tr>
<td>是否显示底部开源信息</td>
<td>
<checkbox name="showOpenSourceInfo" v-model="config.showOpenSourceInfo"></checkbox>
</td>
</tr>
<tr>
<td>是否显示版本号</td>
<td>
<checkbox name="showVersion" v-model="config.showVersion"></checkbox>
</td>
</tr>
<tr v-show="config.showVersion">
<td>定制版本号</td>
<td>
<input type="text" name="version" v-model="config.version" maxlength="100"/>
<p class="comment">定制自己的版本号,留空表示使用系统自带的版本号。</p>
</td>
</tr>
</table>
<submit-btn></submit-btn>
</form>
@@ -0,0 +1,3 @@
Tea.context(function () {
this.success = NotifyReloadSuccess("保存成功")
})
@@ -31,6 +31,13 @@
<p class="comment">用户姓名或者公司名称等等。</p>
</td>
</tr>
<tr>
<td>关联集群 *</td>
<td>
<cluster-selector></cluster-selector>
<p class="comment">用户发布的网站服务会自动部署到此集群。</p>
</td>
</tr>
<tr>
<td colspan="2"><more-options-indicator></more-options-indicator></td>
</tr>
+5
View File
@@ -10,6 +10,7 @@
<tr>
<th>用户名</th>
<th>全名</th>
<th>关联集群</th>
<th>手机号</th>
<th>注册时间</th>
<th class="center width10">状态</th>
@@ -19,6 +20,10 @@
<tr v-for="user in users">
<td :class="{disabled:!user.isOn}">{{user.username}}</td>
<td :class="{disabled:!user.isOn}">{{user.fullname}}</td>
<td>
<span v-if="user.cluster != null">{{user.cluster.name}} <link-icon :href="'/clusters/cluster?clusterId=' + user.cluster.id"></link-icon></span>
<span v-else class="disabled">-</span>
</td>
<td :class="{disabled:!user.isOn}">
<span v-if="user.mobile.length > 0">{{user.mobile}}</span>
<span v-else class="disabled">-</span>
+1
View File
@@ -1,6 +1,7 @@
Tea.context(function () {
this.createUser = function () {
teaweb.popup(Tea.url(".createPopup"), {
height: "30em",
callback: function () {
teaweb.success("保存成功", function () {
teaweb.reload()
+7
View File
@@ -38,6 +38,13 @@
<p class="comment">用户姓名或者公司名称等等。</p>
</td>
</tr>
<tr>
<td>关联集群 *</td>
<td>
<cluster-selector :v-cluster-id="clusterId"></cluster-selector>
<p class="comment">用户发布的网站服务会自动部署到此集群。</p>
</td>
</tr>
<tr>
<td colspan="2"><more-options-indicator></more-options-indicator></td>
</tr>
+7
View File
@@ -20,6 +20,13 @@
{{user.fullname}}
</td>
</tr>
<tr>
<td>关联集群</td>
<td>
<span v-if="user.cluster != null">{{user.cluster.name}} <link-icon :href="'/clusters/cluster?clusterId=' + user.cluster.id"></link-icon></span>
<span v-else class="disabled">-</span>
</td>
</tr>
<tr>
<td>手机号</td>
<td>