mirror of
				https://github.com/TeaOSLab/EdgeAdmin.git
				synced 2025-11-04 21:50:28 +08:00 
			
		
		
		
	[用户]实现对平台用户的增删改查
This commit is contained in:
		@@ -13,7 +13,8 @@ const (
 | 
			
		||||
	AdminModuleCodeServer  AdminModuleCode = "server"
 | 
			
		||||
	AdminModuleCodeNode    AdminModuleCode = "node"
 | 
			
		||||
	AdminModuleCodeDNS     AdminModuleCode = "dns"
 | 
			
		||||
	AdminModuleCodeAdmin   AdminModuleCode = "admin"
 | 
			
		||||
	AdminModuleCodeAdmin   AdminModuleCode = "admin" // 系统用户
 | 
			
		||||
	AdminModuleCodeUser    AdminModuleCode = "user"  // 平台用户
 | 
			
		||||
	AdminModuleCodeLog     AdminModuleCode = "log"
 | 
			
		||||
	AdminModuleCodeSetting AdminModuleCode = "setting"
 | 
			
		||||
	AdminModuleCodeCommon  AdminModuleCode = "common" // 只要登录就可以访问的模块
 | 
			
		||||
@@ -118,6 +119,11 @@ func AllModuleMaps() []maps.Map {
 | 
			
		||||
			"code": AdminModuleCodeDNS,
 | 
			
		||||
			"url":  "/dns",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"name": "平台用户",
 | 
			
		||||
			"code": AdminModuleCodeUser,
 | 
			
		||||
			"url":  "/users",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"name": "系统用户",
 | 
			
		||||
			"code": AdminModuleCodeAdmin,
 | 
			
		||||
 
 | 
			
		||||
@@ -224,6 +224,10 @@ func (this *RPCClient) ACMETaskRPC() pb.ACMETaskServiceClient {
 | 
			
		||||
	return pb.NewACMETaskServiceClient(this.pickConn())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *RPCClient) UserRPC() pb.UserServiceClient {
 | 
			
		||||
	return pb.NewUserServiceClient(this.pickConn())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 构造Admin上下文
 | 
			
		||||
func (this *RPCClient) Context(adminId int64) context.Context {
 | 
			
		||||
	ctx := context.Background()
 | 
			
		||||
 
 | 
			
		||||
@@ -113,7 +113,7 @@ func (this *RequestCertPopupAction) RunPost(params struct {
 | 
			
		||||
			this.ErrorPage(err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		defer this.CreateLogInfo("创建ACME用户", createUserResp.AcmeUserId)
 | 
			
		||||
		defer this.CreateLogInfo("创建ACME用户 %d", createUserResp.AcmeUserId)
 | 
			
		||||
		acmeUserId = createUserResp.AcmeUserId
 | 
			
		||||
 | 
			
		||||
		this.Data["acmeUser"] = maps.Map{
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										91
									
								
								internal/web/actions/default/users/createPopup.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								internal/web/actions/default/users/createPopup.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,91 @@
 | 
			
		||||
package users
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/iwind/TeaGo/actions"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type CreatePopupAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *CreatePopupAction) Init() {
 | 
			
		||||
	this.Nav("", "", "")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *CreatePopupAction) RunGet(params struct{}) {
 | 
			
		||||
	this.Show()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *CreatePopupAction) RunPost(params struct {
 | 
			
		||||
	Username string
 | 
			
		||||
	Pass1    string
 | 
			
		||||
	Pass2    string
 | 
			
		||||
	Fullname string
 | 
			
		||||
	Mobile   string
 | 
			
		||||
	Tel      string
 | 
			
		||||
	Email    string
 | 
			
		||||
	Remark   string
 | 
			
		||||
 | 
			
		||||
	Must *actions.Must
 | 
			
		||||
	CSRF *actionutils.CSRF
 | 
			
		||||
}) {
 | 
			
		||||
	params.Must.
 | 
			
		||||
		Field("username", params.Username).
 | 
			
		||||
		Require("请输入用户名").
 | 
			
		||||
		Match(`^[a-zA-Z0-9_]+$`, "用户名中只能含有英文、数字和下划线")
 | 
			
		||||
 | 
			
		||||
	checkUsernameResp, err := this.RPC().UserRPC().CheckUsername(this.AdminContext(), &pb.CheckUsernameRequest{
 | 
			
		||||
		UserId:   0,
 | 
			
		||||
		Username: params.Username,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if checkUsernameResp.Exists {
 | 
			
		||||
		this.FailField("username", "此用户名已经被占用,请换一个")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	params.Must.
 | 
			
		||||
		Field("pass1", params.Pass1).
 | 
			
		||||
		Require("请输入密码").
 | 
			
		||||
		Field("pass2", params.Pass2).
 | 
			
		||||
		Require("请再次输入确认密码").
 | 
			
		||||
		Equal(params.Pass1, "两次输入的密码不一致")
 | 
			
		||||
 | 
			
		||||
	params.Must.
 | 
			
		||||
		Field("fullname", params.Fullname).
 | 
			
		||||
		Require("请输入全名")
 | 
			
		||||
 | 
			
		||||
	if len(params.Mobile) > 0 {
 | 
			
		||||
		params.Must.
 | 
			
		||||
			Field("mobile", params.Mobile).
 | 
			
		||||
			Mobile("请输入正确的手机号")
 | 
			
		||||
	}
 | 
			
		||||
	if len(params.Email) > 0 {
 | 
			
		||||
		params.Must.
 | 
			
		||||
			Field("email", params.Email).
 | 
			
		||||
			Email("请输入正确的电子邮箱")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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()),
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	defer this.CreateLogInfo("创建用户 %d", createResp.UserId)
 | 
			
		||||
 | 
			
		||||
	this.Success()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								internal/web/actions/default/users/delete.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								internal/web/actions/default/users/delete.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
package users
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type DeleteAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *DeleteAction) RunPost(params struct {
 | 
			
		||||
	UserId int64
 | 
			
		||||
}) {
 | 
			
		||||
	defer this.CreateLogInfo("删除用户 %d", params.UserId)
 | 
			
		||||
 | 
			
		||||
	// TODO 检查用户是否有未完成的业务
 | 
			
		||||
 | 
			
		||||
	_, err := this.RPC().UserRPC().DeleteUser(this.AdminContext(), &pb.DeleteUserRequest{UserId: params.UserId})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.Success()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										51
									
								
								internal/web/actions/default/users/index.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								internal/web/actions/default/users/index.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
package users
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/iwind/TeaGo/maps"
 | 
			
		||||
	timeutil "github.com/iwind/TeaGo/utils/time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type IndexAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *IndexAction) Init() {
 | 
			
		||||
	this.Nav("", "", "")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *IndexAction) RunGet(params struct {
 | 
			
		||||
	Keyword string
 | 
			
		||||
}) {
 | 
			
		||||
	countResp, err := this.RPC().UserRPC().CountAllEnabledUsers(this.AdminContext(), &pb.CountAllEnabledUsersRequest{Keyword: params.Keyword})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	count := countResp.Count
 | 
			
		||||
	page := this.NewPage(count)
 | 
			
		||||
	this.Data["page"] = page.AsHTML()
 | 
			
		||||
 | 
			
		||||
	usersResp, err := this.RPC().UserRPC().ListEnabledUsers(this.AdminContext(), &pb.ListEnabledUsersRequest{Keyword: params.Keyword})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	userMaps := []maps.Map{}
 | 
			
		||||
	for _, user := range usersResp.Users {
 | 
			
		||||
		userMaps = append(userMaps, maps.Map{
 | 
			
		||||
			"id":          user.Id,
 | 
			
		||||
			"username":    user.Username,
 | 
			
		||||
			"isOn":        user.IsOn,
 | 
			
		||||
			"fullname":    user.Fullname,
 | 
			
		||||
			"email":       user.Email,
 | 
			
		||||
			"mobile":      user.Mobile,
 | 
			
		||||
			"tel":         user.Tel,
 | 
			
		||||
			"createdTime": timeutil.FormatTime("Y-m-d H:i:s", user.CreatedAt),
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	this.Data["users"] = userMaps
 | 
			
		||||
 | 
			
		||||
	this.Show()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								internal/web/actions/default/users/init.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								internal/web/actions/default/users/init.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
package users
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
 | 
			
		||||
	"github.com/iwind/TeaGo"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	TeaGo.BeforeStart(func(server *TeaGo.Server) {
 | 
			
		||||
		server.
 | 
			
		||||
			Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeUser)).
 | 
			
		||||
			Data("teaMenu", "users").
 | 
			
		||||
			Prefix("/users").
 | 
			
		||||
			Get("", new(IndexAction)).
 | 
			
		||||
			GetPost("/createPopup", new(CreatePopupAction)).
 | 
			
		||||
			Get("/user", new(UserAction)).
 | 
			
		||||
			GetPost("/update", new(UpdateAction)).
 | 
			
		||||
			Post("/delete", new(DeleteAction)).
 | 
			
		||||
			EndAll()
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										128
									
								
								internal/web/actions/default/users/update.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								internal/web/actions/default/users/update.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,128 @@
 | 
			
		||||
package users
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/users/userutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/iwind/TeaGo/actions"
 | 
			
		||||
	"github.com/iwind/TeaGo/maps"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type UpdateAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *UpdateAction) Init() {
 | 
			
		||||
	this.Nav("", "", "update")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *UpdateAction) RunGet(params struct {
 | 
			
		||||
	UserId int64
 | 
			
		||||
}) {
 | 
			
		||||
	err := userutils.InitUser(this.Parent(), params.UserId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	userResp, err := this.RPC().UserRPC().FindEnabledUser(this.AdminContext(), &pb.FindEnabledUserRequest{UserId: params.UserId})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	user := userResp.User
 | 
			
		||||
	if user == nil {
 | 
			
		||||
		this.NotFound("user", params.UserId)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.Data["user"] = maps.Map{
 | 
			
		||||
		"id":       user.Id,
 | 
			
		||||
		"username": user.Username,
 | 
			
		||||
		"fullname": user.Fullname,
 | 
			
		||||
		"email":    user.Email,
 | 
			
		||||
		"tel":      user.Tel,
 | 
			
		||||
		"remark":   user.Remark,
 | 
			
		||||
		"mobile":   user.Mobile,
 | 
			
		||||
		"isOn":     user.IsOn,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
 | 
			
		||||
	Must *actions.Must
 | 
			
		||||
	CSRF *actionutils.CSRF
 | 
			
		||||
}) {
 | 
			
		||||
	defer this.CreateLogInfo("修改用户 %d", params.UserId)
 | 
			
		||||
 | 
			
		||||
	params.Must.
 | 
			
		||||
		Field("username", params.Username).
 | 
			
		||||
		Require("请输入用户名").
 | 
			
		||||
		Match(`^[a-zA-Z0-9_]+$`, "用户名中只能含有英文、数字和下划线")
 | 
			
		||||
 | 
			
		||||
	checkUsernameResp, err := this.RPC().UserRPC().CheckUsername(this.AdminContext(), &pb.CheckUsernameRequest{
 | 
			
		||||
		UserId:   params.UserId,
 | 
			
		||||
		Username: params.Username,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if checkUsernameResp.Exists {
 | 
			
		||||
		this.FailField("username", "此用户名已经被占用,请换一个")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(params.Pass1) > 0 {
 | 
			
		||||
		params.Must.
 | 
			
		||||
			Field("pass1", params.Pass1).
 | 
			
		||||
			Require("请输入密码").
 | 
			
		||||
			Field("pass2", params.Pass2).
 | 
			
		||||
			Require("请再次输入确认密码").
 | 
			
		||||
			Equal(params.Pass1, "两次输入的密码不一致")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	params.Must.
 | 
			
		||||
		Field("fullname", params.Fullname).
 | 
			
		||||
		Require("请输入全名")
 | 
			
		||||
 | 
			
		||||
	if len(params.Mobile) > 0 {
 | 
			
		||||
		params.Must.
 | 
			
		||||
			Field("mobile", params.Mobile).
 | 
			
		||||
			Mobile("请输入正确的手机号")
 | 
			
		||||
	}
 | 
			
		||||
	if len(params.Email) > 0 {
 | 
			
		||||
		params.Must.
 | 
			
		||||
			Field("email", params.Email).
 | 
			
		||||
			Email("请输入正确的电子邮箱")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, 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,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.Success()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										50
									
								
								internal/web/actions/default/users/user.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								internal/web/actions/default/users/user.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
package users
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/users/userutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/iwind/TeaGo/maps"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type UserAction struct {
 | 
			
		||||
	actionutils.ParentAction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *UserAction) Init() {
 | 
			
		||||
	this.Nav("", "", "index")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (this *UserAction) RunGet(params struct {
 | 
			
		||||
	UserId int64
 | 
			
		||||
}) {
 | 
			
		||||
	err := userutils.InitUser(this.Parent(), params.UserId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	userResp, err := this.RPC().UserRPC().FindEnabledUser(this.AdminContext(), &pb.FindEnabledUserRequest{UserId: params.UserId})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		this.ErrorPage(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	user := userResp.User
 | 
			
		||||
	if user == nil {
 | 
			
		||||
		this.NotFound("user", params.UserId)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.Data["user"] = maps.Map{
 | 
			
		||||
		"id":       user.Id,
 | 
			
		||||
		"username": user.Username,
 | 
			
		||||
		"fullname": user.Fullname,
 | 
			
		||||
		"email":    user.Email,
 | 
			
		||||
		"tel":      user.Tel,
 | 
			
		||||
		"remark":   user.Remark,
 | 
			
		||||
		"mobile":   user.Mobile,
 | 
			
		||||
		"isOn":     user.IsOn,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.Show()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								internal/web/actions/default/users/userutils/utils.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								internal/web/actions/default/users/userutils/utils.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
package userutils
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
			
		||||
	"github.com/iwind/TeaGo/maps"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 查找用户基本信息
 | 
			
		||||
func InitUser(p *actionutils.ParentAction, userId int64) error {
 | 
			
		||||
	resp, err := p.RPC().UserRPC().FindEnabledUser(p.AdminContext(), &pb.FindEnabledUserRequest{UserId: userId})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if resp.User == nil {
 | 
			
		||||
		return errors.New("not found user")
 | 
			
		||||
	}
 | 
			
		||||
	p.Data["user"] = maps.Map{
 | 
			
		||||
		"id":       userId,
 | 
			
		||||
		"fullname": resp.User.Fullname,
 | 
			
		||||
		"username": resp.User.Username,
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
@@ -215,11 +215,17 @@ func (this *userMustAuth) modules(adminId int64) []maps.Map {
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"code":   "users",
 | 
			
		||||
			"module": configloaders.AdminModuleCodeUser,
 | 
			
		||||
			"name":   "平台用户",
 | 
			
		||||
			"icon":   "users",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"code":   "admins",
 | 
			
		||||
			"module": configloaders.AdminModuleCodeAdmin,
 | 
			
		||||
			"name":   "系统用户",
 | 
			
		||||
			"icon":   "users",
 | 
			
		||||
			"icon":   "user secret",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"code":   "log",
 | 
			
		||||
 
 | 
			
		||||
@@ -83,4 +83,5 @@ import (
 | 
			
		||||
	_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/settings/upgrade"
 | 
			
		||||
	_ "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"
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								web/views/@default/users/@user_menu.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								web/views/@default/users/@user_menu.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
<first-menu>
 | 
			
		||||
    <menu-item href="/users">用户列表</menu-item>
 | 
			
		||||
    <span class="item">|</span>
 | 
			
		||||
    <menu-item :href="'/users/user?userId=' + user.id" code="index">{{user.fullname}}  <span class="small">({{user.username}})</span></menu-item>
 | 
			
		||||
    <menu-item :href="'/users/update?userId=' + user.id" code="update">修改</menu-item>
 | 
			
		||||
</first-menu>
 | 
			
		||||
							
								
								
									
										65
									
								
								web/views/@default/users/createPopup.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								web/views/@default/users/createPopup.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,65 @@
 | 
			
		||||
{$layout "layout_popup"}
 | 
			
		||||
 | 
			
		||||
<h3>创建用户</h3>
 | 
			
		||||
 | 
			
		||||
<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="username" maxlength="100" ref="focus"/>
 | 
			
		||||
                <p class="comment">用户名只能是英文、数字、下划线的组合。</p>
 | 
			
		||||
            </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr>
 | 
			
		||||
            <td>密码 *</td>
 | 
			
		||||
            <td>
 | 
			
		||||
                <input type="password" name="pass1" maxlength="100"/>
 | 
			
		||||
            </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr>
 | 
			
		||||
            <td>确认密码 *</td>
 | 
			
		||||
            <td>
 | 
			
		||||
                <input type="password" name="pass2" maxlength="100"/>
 | 
			
		||||
            </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr>
 | 
			
		||||
            <td>全名 *</td>
 | 
			
		||||
            <td>
 | 
			
		||||
                <input type="text" name="fullname" maxlength="100"/>
 | 
			
		||||
                <p class="comment">用户姓名或者公司名称等等。</p>
 | 
			
		||||
            </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr>
 | 
			
		||||
            <td colspan="2"><more-options-indicator></more-options-indicator></td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tbody v-show="moreOptionsVisible">
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>手机号</td>
 | 
			
		||||
                <td>
 | 
			
		||||
                    <input type="text" name="mobile" maxlength="11"/>
 | 
			
		||||
                </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>联系电话</td>
 | 
			
		||||
                <td>
 | 
			
		||||
                    <input type="text" name="tel" maxlength="100"/>
 | 
			
		||||
                </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>电子邮箱</td>
 | 
			
		||||
                <td>
 | 
			
		||||
                    <input type="text" name="email" maxlength="100"/>
 | 
			
		||||
                </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>备注</td>
 | 
			
		||||
                <td>
 | 
			
		||||
                    <textarea rows="3" name="remark"></textarea>
 | 
			
		||||
                </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
        </tbody>
 | 
			
		||||
	</table>
 | 
			
		||||
	<submit-btn></submit-btn>
 | 
			
		||||
</form>
 | 
			
		||||
							
								
								
									
										37
									
								
								web/views/@default/users/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								web/views/@default/users/index.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
{$layout}
 | 
			
		||||
 | 
			
		||||
<first-menu>
 | 
			
		||||
	<menu-item @click.prevent="createUser">创建</menu-item>
 | 
			
		||||
</first-menu>
 | 
			
		||||
 | 
			
		||||
<p class="comment" v-if="users.length == 0">暂时还没有用户。</p>
 | 
			
		||||
<table class="ui table selectable" v-if="users.length > 0">
 | 
			
		||||
	<thead>
 | 
			
		||||
		<tr>
 | 
			
		||||
			<th>用户名</th>
 | 
			
		||||
			<th>全名</th>
 | 
			
		||||
			<th>手机号</th>
 | 
			
		||||
			<th>注册时间</th>
 | 
			
		||||
			<th class="center width10">状态</th>
 | 
			
		||||
			<th class="two op">操作</th>
 | 
			
		||||
		</tr>
 | 
			
		||||
	</thead>
 | 
			
		||||
	<tr v-for="user in users">
 | 
			
		||||
        <td :class="{disabled:!user.isOn}">{{user.username}}</td>
 | 
			
		||||
        <td :class="{disabled:!user.isOn}">{{user.fullname}}</td>
 | 
			
		||||
        <td :class="{disabled:!user.isOn}">
 | 
			
		||||
            <span v-if="user.mobile.length > 0">{{user.mobile}}</span>
 | 
			
		||||
            <span v-else class="disabled">-</span>
 | 
			
		||||
        </td>
 | 
			
		||||
        <td :class="{disabled:!user.isOn}">{{user.createdTime}}</td>
 | 
			
		||||
        <td class="center">
 | 
			
		||||
            <label-on :v-is-on="user.isOn"></label-on>
 | 
			
		||||
        </td>
 | 
			
		||||
        <td>
 | 
			
		||||
            <a :href="'/users/user?userId=' + user.id">详情</a>  
 | 
			
		||||
            <a href="" @click.prevent="deleteUser(user.id)">删除</a>
 | 
			
		||||
        </td>
 | 
			
		||||
	</tr>
 | 
			
		||||
</table>
 | 
			
		||||
 | 
			
		||||
<div class="page" v-html="page"></div>
 | 
			
		||||
							
								
								
									
										22
									
								
								web/views/@default/users/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								web/views/@default/users/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
Tea.context(function () {
 | 
			
		||||
	this.createUser = function () {
 | 
			
		||||
		teaweb.popup(Tea.url(".createPopup"), {
 | 
			
		||||
			callback: function () {
 | 
			
		||||
				teaweb.success("保存成功", function () {
 | 
			
		||||
					teaweb.reload()
 | 
			
		||||
				})
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	this.deleteUser = function (userId) {
 | 
			
		||||
		let that = this
 | 
			
		||||
		teaweb.confirm("确定要删除这个用户吗?", function () {
 | 
			
		||||
			that.$post(".delete")
 | 
			
		||||
				.params({
 | 
			
		||||
					userId: userId
 | 
			
		||||
				})
 | 
			
		||||
				.refresh()
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
})
 | 
			
		||||
							
								
								
									
										78
									
								
								web/views/@default/users/update.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								web/views/@default/users/update.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
{$layout}
 | 
			
		||||
{$template "user_menu"}
 | 
			
		||||
 | 
			
		||||
<form class="ui form" method="post" data-tea-action="$" data-tea-success="success">
 | 
			
		||||
	<csrf-token></csrf-token>
 | 
			
		||||
    <input type="hidden" name="userId" :value="user.id"/>
 | 
			
		||||
	<table class="ui table definition selectable">
 | 
			
		||||
        <tr>
 | 
			
		||||
            <td class="title">用户名 *</td>
 | 
			
		||||
            <td>
 | 
			
		||||
                <input type="text" name="username" maxlength="100" ref="focus" v-model="user.username"/>
 | 
			
		||||
                <p class="comment">用户名只能是英文、数字、下划线的组合。</p>
 | 
			
		||||
            </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr>
 | 
			
		||||
            <td>密码</td>
 | 
			
		||||
            <td>
 | 
			
		||||
                <div>
 | 
			
		||||
                    <a href="" @click.prevent="changePasswordEditing">修改密码<i class="icon angle" :class="{down:!passwordEditing, up:passwordEditing}"></i></a>
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                <div v-show="passwordEditing" style="margin-top: 0.6em">
 | 
			
		||||
                    <input type="password" name="pass1" maxlength="100"/>
 | 
			
		||||
                    <p class="comment">留空表示不修改。</p>
 | 
			
		||||
                </div>
 | 
			
		||||
            </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr v-show="passwordEditing">
 | 
			
		||||
            <td>确认密码</td>
 | 
			
		||||
            <td>
 | 
			
		||||
                <input type="password" name="pass2" maxlength="100"/>
 | 
			
		||||
            </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr>
 | 
			
		||||
            <td>全名 *</td>
 | 
			
		||||
            <td>
 | 
			
		||||
                <input type="text" name="fullname" maxlength="100" v-model="user.fullname"/>
 | 
			
		||||
                <p class="comment">用户姓名或者公司名称等等。</p>
 | 
			
		||||
            </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr>
 | 
			
		||||
            <td colspan="2"><more-options-indicator></more-options-indicator></td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tbody v-show="moreOptionsVisible">
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>手机号</td>
 | 
			
		||||
                <td>
 | 
			
		||||
                    <input type="text" name="mobile" maxlength="11" v-model="user.mobile"/>
 | 
			
		||||
                </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>联系电话</td>
 | 
			
		||||
                <td>
 | 
			
		||||
                    <input type="text" name="tel" maxlength="100" v-model="user.tel"/>
 | 
			
		||||
                </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>电子邮箱</td>
 | 
			
		||||
                <td>
 | 
			
		||||
                    <input type="text" name="email" maxlength="100" v-model="user.email"/>
 | 
			
		||||
                </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>备注</td>
 | 
			
		||||
                <td>
 | 
			
		||||
                    <textarea rows="3" name="remark" v-model="user.remark"></textarea>
 | 
			
		||||
                </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>是否启用</td>
 | 
			
		||||
                <td>
 | 
			
		||||
                    <checkbox name="isOn" v-model="user.isOn"></checkbox>
 | 
			
		||||
                </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
        </tbody>
 | 
			
		||||
	</table>
 | 
			
		||||
	<submit-btn></submit-btn>
 | 
			
		||||
</form>
 | 
			
		||||
							
								
								
									
										9
									
								
								web/views/@default/users/update.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								web/views/@default/users/update.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
Tea.context(function () {
 | 
			
		||||
	this.success = NotifySuccess("保存成功", "/users/user?userId=" + this.user.id)
 | 
			
		||||
 | 
			
		||||
	this.passwordEditing = false
 | 
			
		||||
 | 
			
		||||
	this.changePasswordEditing = function () {
 | 
			
		||||
		this.passwordEditing = !this.passwordEditing
 | 
			
		||||
	}
 | 
			
		||||
})
 | 
			
		||||
							
								
								
									
										51
									
								
								web/views/@default/users/user.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								web/views/@default/users/user.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
{$layout}
 | 
			
		||||
{$template "user_menu"}
 | 
			
		||||
 | 
			
		||||
<table class="ui table definition selectable">
 | 
			
		||||
    <tr>
 | 
			
		||||
        <td>状态</td>
 | 
			
		||||
        <td>
 | 
			
		||||
            <label-on :v-is-on="user.isOn"></label-on>
 | 
			
		||||
        </td>
 | 
			
		||||
    </tr>
 | 
			
		||||
    <tr>
 | 
			
		||||
        <td class="title">用户名</td>
 | 
			
		||||
        <td>
 | 
			
		||||
            {{user.username}}
 | 
			
		||||
        </td>
 | 
			
		||||
    </tr>
 | 
			
		||||
    <tr>
 | 
			
		||||
        <td>全名</td>
 | 
			
		||||
        <td>
 | 
			
		||||
            {{user.fullname}}
 | 
			
		||||
        </td>
 | 
			
		||||
    </tr>
 | 
			
		||||
    <tr>
 | 
			
		||||
        <td>手机号</td>
 | 
			
		||||
        <td>
 | 
			
		||||
            <span v-if="user.mobile.length > 0">{{user.mobile}}</span>
 | 
			
		||||
            <span v-else class="disabled">-</span>
 | 
			
		||||
        </td>
 | 
			
		||||
    </tr>
 | 
			
		||||
    <tr>
 | 
			
		||||
        <td>联系电话</td>
 | 
			
		||||
        <td>
 | 
			
		||||
            <span v-if="user.tel.length > 0">{{user.tel}}</span>
 | 
			
		||||
            <span v-else class="disabled">-</span>
 | 
			
		||||
        </td>
 | 
			
		||||
    </tr>
 | 
			
		||||
    <tr>
 | 
			
		||||
        <td>电子邮箱</td>
 | 
			
		||||
        <td>
 | 
			
		||||
            <span v-if="user.email.length > 0">{{user.email}}</span>
 | 
			
		||||
            <span v-else class="disabled">-</span>
 | 
			
		||||
        </td>
 | 
			
		||||
    </tr>
 | 
			
		||||
    <tr>
 | 
			
		||||
        <td>备注</td>
 | 
			
		||||
        <td>
 | 
			
		||||
            <span v-if="user.remark.length > 0">{{user.remark}}</span>
 | 
			
		||||
            <span v-else class="disabled">-</span>
 | 
			
		||||
        </td>
 | 
			
		||||
    </tr>
 | 
			
		||||
</table>
 | 
			
		||||
		Reference in New Issue
	
	Block a user