2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 05:31:44 +08:00

feat: 支持修改用户名,close #803

This commit is contained in:
2025-07-07 17:28:40 +08:00
parent d5ee789a61
commit c50a33f323
8 changed files with 53 additions and 2 deletions

View File

@@ -24,6 +24,7 @@ type UserRepo interface {
List(page, limit uint) ([]*User, int64, error)
Get(id uint) (*User, error)
Create(username, password, email string) (*User, error)
UpdateUsername(id uint, username string) error
UpdatePassword(id uint, password string) error
UpdateEmail(id uint, email string) error
Delete(id uint) error

View File

@@ -62,6 +62,16 @@ func (r *userRepo) Create(username, password, email string) (*biz.User, error) {
return user, nil
}
func (r *userRepo) UpdateUsername(id uint, username string) error {
user, err := r.Get(id)
if err != nil {
return err
}
user.Username = username
return r.db.Save(user).Error
}
func (r *userRepo) UpdatePassword(id uint, password string) error {
value, err := r.hasher.Make(password)
if err != nil {

View File

@@ -227,7 +227,7 @@ func (r *websiteRepo) List(page, limit uint) ([]*biz.Website, int64, error) {
for _, website := range websites {
crt, _ := io.Read(filepath.Join(app.Root, "server/vhost/cert", website.Name+".pem"))
if decode, err := cert.ParseCert(crt); err == nil {
hours := decode.NotAfter.Sub(time.Now()).Hours()
hours := time.Until(decode.NotAfter).Hours()
website.CertExpire = fmt.Sprintf("%.2f", hours/24)
}
}

View File

@@ -21,6 +21,11 @@ type UserCreate struct {
Email string `json:"email" validate:"required|email"`
}
type UserUpdateUsername struct {
ID uint `json:"id" validate:"required|exists:users,id"`
Username string `json:"username" validate:"required|notExists:users,username"`
}
type UserUpdatePassword struct {
ID uint `json:"id" validate:"required|exists:users,id"`
Password string `json:"password" validate:"required|password"`

View File

@@ -127,6 +127,7 @@ func (route *Http) Register(r *chi.Mux) {
r.Route("/users", func(r chi.Router) {
r.Get("/", route.user.List)
r.Post("/", route.user.Create)
r.Post("/{id}/username", route.user.UpdateUsername)
r.Post("/{id}/password", route.user.UpdatePassword)
r.Post("/{id}/email", route.user.UpdateEmail)
r.Get("/{id}/2fa", route.user.GenerateTwoFA)

View File

@@ -208,6 +208,21 @@ func (s *UserService) Create(w http.ResponseWriter, r *http.Request) {
Success(w, user)
}
func (s *UserService) UpdateUsername(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.UserUpdateUsername](r)
if err != nil {
Error(w, http.StatusUnprocessableEntity, "%v", err)
return
}
if err = s.userRepo.UpdateUsername(req.ID, req.Username); err != nil {
Error(w, http.StatusInternalServerError, "%v", err)
return
}
Success(w, nil)
}
func (s *UserService) UpdatePassword(w http.ResponseWriter, r *http.Request) {
req, err := Bind[request.UserUpdatePassword](r)
if err != nil {

View File

@@ -26,6 +26,9 @@ export default {
http.Post('/users', { username, password, email }),
// 删除用户
delete: (id: number): any => http.Delete(`/users/${id}`),
// 更新用户用户名
updateUsername: (id: number, username: string): any =>
http.Post(`/users/${id}/username`, { username }),
// 更新用户邮箱
updateEmail: (id: number, email: string): any => http.Post(`/users/${id}/email`, { email }),
// 更新用户密码

View File

@@ -20,7 +20,17 @@ const columns: any = [
key: 'username',
minWidth: 100,
resizable: true,
ellipsis: { tooltip: true }
ellipsis: { tooltip: true },
render(row: any) {
return h(NInput, {
size: 'small',
value: row.username,
onBlur: () => handleUsername(row),
onUpdateValue(v) {
row.username = v
}
})
}
},
{
title: $gettext('Email'),
@@ -151,6 +161,12 @@ const { loading, data, page, total, pageSize, pageCount, refresh } = usePaginati
}
)
const handleUsername = (row: any) => {
useRequest(user.updateUsername(row.id, row.username)).onSuccess(() => {
window.$message.success($gettext('Modified successfully'))
})
}
const handleEmail = (row: any) => {
useRequest(user.updateEmail(row.id, row.email)).onSuccess(() => {
window.$message.success($gettext('Modified successfully'))