mirror of
				https://github.com/TeaOSLab/EdgeAdmin.git
				synced 2025-11-04 21:50:28 +08:00 
			
		
		
		
	增加用户系统界面管理、用户可以设置关联集群
This commit is contained in:
		@@ -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
									
								
								internal/configloaders/user_ui_config.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								internal/configloaders/user_ui_config.go
									
									
									
									
									
										Normal 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()
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										30
									
								
								internal/web/actions/default/clusters/options.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								internal/web/actions/default/clusters/options.go
									
									
									
									
									
										Normal file
									
								
							@@ -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()
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										61
									
								
								internal/web/actions/default/settings/user-ui/index.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								internal/web/actions/default/settings/user-ui/index.go
									
									
									
									
									
										Normal file
									
								
							@@ -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()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								internal/web/actions/default/settings/user-ui/init.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								internal/web/actions/default/settings/user-ui/init.go
									
									
									
									
									
										Normal file
									
								
							@@ -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()
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
@@ -28,6 +28,7 @@ func (this *CreatePopupAction) RunPost(params struct {
 | 
			
		||||
	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).
 | 
			
		||||
@@ -80,6 +85,7 @@ func (this *CreatePopupAction) RunPost(params struct {
 | 
			
		||||
		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
 | 
			
		||||
 
 | 
			
		||||
@@ -47,6 +47,11 @@ 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()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -61,6 +66,7 @@ func (this *UpdateAction) RunPost(params struct {
 | 
			
		||||
	Email     string
 | 
			
		||||
	Remark    string
 | 
			
		||||
	IsOn      bool
 | 
			
		||||
	ClusterId int64
 | 
			
		||||
 | 
			
		||||
	Must *actions.Must
 | 
			
		||||
	CSRF *actionutils.CSRF
 | 
			
		||||
@@ -118,6 +124,7 @@ func (this *UpdateAction) RunPost(params struct {
 | 
			
		||||
		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()
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										28
									
								
								web/public/js/components/cluster/cluster-selector.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								web/public/js/components/cluster/cluster-selector.js
									
									
									
									
									
										Normal file
									
								
							@@ -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>`
 | 
			
		||||
})
 | 
			
		||||
@@ -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
											
										
									
								
							@@ -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 {
 | 
			
		||||
	.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;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										41
									
								
								web/views/@default/settings/user-ui/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								web/views/@default/settings/user-ui/index.html
									
									
									
									
									
										Normal file
									
								
							@@ -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>
 | 
			
		||||
							
								
								
									
										3
									
								
								web/views/@default/settings/user-ui/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								web/views/@default/settings/user-ui/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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,6 +1,7 @@
 | 
			
		||||
Tea.context(function () {
 | 
			
		||||
	this.createUser = function () {
 | 
			
		||||
		teaweb.popup(Tea.url(".createPopup"), {
 | 
			
		||||
			height: "30em",
 | 
			
		||||
			callback: function () {
 | 
			
		||||
				teaweb.success("保存成功", function () {
 | 
			
		||||
					teaweb.reload()
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user