用户设置

dev
truthhun 2 years ago
parent 5cfe9eb906
commit 92162d4fa6

@ -38,14 +38,15 @@ message User {
}
message RegisterAndLoginRequest {
string username = 1 [ (gogoproto.moretags) = "validate:\"min=4,max=32\"" ];
string username = 1 [ (gogoproto.moretags) = "validate:\"min=3,max=32\"" ];
string password = 2 [ (gogoproto.moretags) = "validate:\"min=6\"" ];
string captcha = 3;
string captcha_id = 4;
}
message GetUserCaptchaRequest {
string type = 1; // registerlogincommentfind_passwordupload
string type =
1; // registerlogincommentfind_passwordupload
}
message LoginReply {
@ -83,11 +84,17 @@ message GetUserCaptchaReply {
message UpdateUserPasswordRequest {
int64 id = 1;
string old_password = 2;
string new_password = 3 [ (gogoproto.moretags) = "validate:\"min=6\"" ];
string new_password = 3 [ (gogoproto.moretags) = "validate:\"min=6\"" ];
}
message GetUserPermissionsReply{
repeated Permission permission = 1;
message GetUserPermissionsReply { repeated Permission permission = 1; }
message SetUserRequest {
int64 id = 1;
string username = 2 [ (gogoproto.moretags) = "validate:\"min=3,max=32\"" ];
string password = 3 [ (gogoproto.moretags) = "validate:\"min=6\"" ];
;
repeated int64 group_id = 4;
}
service UserAPI {
@ -123,7 +130,8 @@ service UserAPI {
// ID
// 穿ID
rpc UpdateUserPassword(UpdateUserPasswordRequest) returns (google.protobuf.Empty) {
rpc UpdateUserPassword(UpdateUserPasswordRequest)
returns (google.protobuf.Empty) {
option (google.api.http) = {
put : '/api/v1/user/password',
body : '*',
@ -132,9 +140,9 @@ service UserAPI {
// ID
// 穿ID
rpc UpdateUser(User) returns (google.protobuf.Empty) {
rpc UpdateUserProfile(User) returns (google.protobuf.Empty) {
option (google.api.http) = {
put : '/api/v1/user',
put : '/api/v1/user/profile',
body : '*',
};
}
@ -146,6 +154,22 @@ service UserAPI {
};
}
//
rpc AddUser(SetUserRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
post : '/api/v1/user',
body : '*',
};
}
//
rpc SetUser(SetUserRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
put : '/api/v1/user',
body : '*',
};
}
//
//
rpc ListUser(ListUserRequest) returns (ListUserReply) {
@ -162,7 +186,8 @@ service UserAPI {
}
// GetUserCaptcha
rpc GetUserPermissions(google.protobuf.Empty) returns (GetUserPermissionsReply) {
rpc GetUserPermissions(google.protobuf.Empty)
returns (GetUserPermissionsReply) {
option (google.api.http) = {
get : '/api/v1/user/permission',
};

@ -45,6 +45,10 @@ func (s *UserAPIService) getValidFieldMap() map[string]string {
return map[string]string{"Username": "用户名", "Password": "密码"}
}
func (s *UserAPIService) checkPermission(ctx context.Context) (*auth.UserClaims, error) {
return checkGRPCPermission(s.dbModel, ctx)
}
// Register 用户注册
func (s *UserAPIService) Register(ctx context.Context, req *pb.RegisterAndLoginRequest) (*emptypb.Empty, error) {
err := validate.ValidateStruct(req, s.getValidFieldMap())
@ -151,10 +155,28 @@ func (s *UserAPIService) GetUser(ctx context.Context, req *pb.GetUserRequest) (*
return &pb.User{}, nil
}
// UpdateUser 更改用户信息
func (s *UserAPIService) SetUser(ctx context.Context, req *pb.SetUserRequest) (*emptypb.Empty, error) {
_, err := s.checkPermission(ctx)
if err != nil {
return nil, err
}
if len(req.GroupId) == 0 {
return nil, status.Errorf(codes.InvalidArgument, "用户组不能为空")
}
err = s.dbModel.SetUserGroupAndPassword(req.Id, req.GroupId, req.Password)
if err != nil {
return nil, status.Errorf(codes.Internal, err.Error())
}
return &emptypb.Empty{}, nil
}
// UpdateUserProfile 更改用户信息
// 1. 用户更改自身信息
// 2. 管理员更改用户信息
func (s *UserAPIService) UpdateUser(ctx context.Context, req *pb.User) (*emptypb.Empty, error) {
func (s *UserAPIService) UpdateUserProfile(ctx context.Context, req *pb.User) (*emptypb.Empty, error) {
userClaims, ok := ctx.Value(auth.CtxKeyUserClaims).(*auth.UserClaims)
if !ok || s.dbModel.IsInvalidToken(userClaims.UUID) {
return nil, status.Errorf(codes.Unauthenticated, ErrorMessageInvalidToken)
@ -308,16 +330,36 @@ func (s *UserAPIService) ListUser(ctx context.Context, req *pb.ListUserRequest)
}
opt.SelectFields = limitFileds
var pbUser []*pb.User
var pbUsers []*pb.User
userList, total, err := s.dbModel.GetUserList(opt)
if err == gorm.ErrRecordNotFound {
err = nil
return &pb.ListUserReply{}, nil
}
util.CopyStruct(&userList, &pbUsers)
// 查询用户ID
var (
userIds []interface{}
userIndex = make(map[int64]int)
)
for index, pbUser := range pbUsers {
userIds = append(userIds, pbUser.Id)
userIndex[pbUser.Id] = index
}
userGroups, _, _ := s.dbModel.GetUserGroupList(&model.OptionGetUserGroupList{
QueryIn: map[string][]interface{}{"user_id": userIds},
})
for _, userGroup := range userGroups {
index := userIndex[userGroup.UserId]
pbUsers[index].GroupId = append(pbUsers[index].GroupId, userGroup.GroupId)
}
util.CopyStruct(&userList, &pbUser)
s.logger.Debug("ListUser", zap.Any("userList", userList), zap.Any("pbUser", pbUser), zap.Int64("total", total))
return &pb.ListUserReply{Total: total, User: pbUser}, nil
s.logger.Debug("ListUser", zap.Any("userList", userList), zap.Any("pbUser", pbUsers), zap.Int64("total", total))
return &pb.ListUserReply{Total: total, User: pbUsers}, nil
}
// GetUserCaptcha 获取用户验证码
@ -370,3 +412,36 @@ func (s *UserAPIService) GetUserPermissions(ctx context.Context, req *emptypb.Em
return &pb.GetUserPermissionsReply{Permission: pbPermissions}, nil
}
// AddUser 新增用户
func (s *UserAPIService) AddUser(ctx context.Context, req *pb.SetUserRequest) (*emptypb.Empty, error) {
s.logger.Debug("AddUser", zap.Any("req", req))
_, err := s.checkPermission(ctx)
if err != nil {
return nil, err
}
err = validate.ValidateStruct(req, s.getValidFieldMap())
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, err.Error())
}
if len(req.GroupId) == 0 {
return nil, status.Errorf(codes.InvalidArgument, "用户组不能为空")
}
existUser, _ := s.dbModel.GetUserByUsername(req.Username, "id")
if existUser.Id > 0 {
return nil, status.Errorf(codes.InvalidArgument, "用户名已存在")
}
// 新增用户
user := &model.User{Username: req.Username, Password: req.Password}
err = s.dbModel.CreateUser(user, req.GroupId...)
if err != nil {
return nil, status.Errorf(codes.Internal, err.Error())
}
return &emptypb.Empty{}, nil
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -82,7 +82,7 @@ func (User) TableName() string {
// CreateUser 创建User
// TODO: 创建成功之后,注意相关表统计字段数值的增减
func (m *DBModel) CreateUser(user *User, groupId int64) (err error) {
func (m *DBModel) CreateUser(user *User, groupIds ...int64) (err error) {
user.Password, _ = unchained.MakePassword(user.Password, unchained.GetRandomString(4), "md5")
sess := m.db.Begin()
@ -102,30 +102,38 @@ func (m *DBModel) CreateUser(user *User, groupId int64) (err error) {
}
// 2. 添加用户组
group := &UserGroup{
UserId: user.Id,
GroupId: groupId,
}
err = sess.Create(group).Error
if err != nil {
m.logger.Error("CreateUser", zap.Error(err))
return
}
for _, groupId := range groupIds {
group := &UserGroup{
UserId: user.Id,
GroupId: groupId,
}
err = sess.Create(group).Error
if err != nil {
m.logger.Error("CreateUser", zap.Error(err))
return
}
// 3. 添加用户统计
err = sess.Model(&Group{}).Where("id = ?", groupId).Update("user_count", gorm.Expr("user_count + ?", 1)).Error
if err != nil {
m.logger.Error("CreateUser", zap.Error(err))
return
// 3. 添加用户统计
err = sess.Model(&Group{}).Where("id = ?", groupId).Update("user_count", gorm.Expr("user_count + ?", 1)).Error
if err != nil {
m.logger.Error("CreateUser", zap.Error(err))
return
}
}
return
}
// UpdateUserPassword 更新User密码
func (m *DBModel) UpdateUserPassword(id interface{}, newPassword string) (err error) {
func (m *DBModel) UpdateUserPassword(id interface{}, newPassword string, tx ...*gorm.DB) (err error) {
newPassword, _ = unchained.MakePassword(newPassword, unchained.GetRandomString(4), "md5")
err = m.db.Model(&User{}).Where("id = ?", id).Update("password", newPassword).Error
user := &User{}
sess := m.db.Model(user)
if len(tx) > 0 {
sess = tx[0].Model(user)
}
err = sess.Where("id = ?", id).Update("password", newPassword).Error
if err != nil {
m.logger.Error("UpdateUserPassword", zap.Error(err))
}
@ -283,8 +291,8 @@ func (m *DBModel) initUser() (err error) {
// 初始化一个用户
user := &User{Username: "admin", Password: "123456"}
groupId := 1 // ID==1的用户组为管理员组
err = m.CreateUser(user, int64(groupId))
var groupId int64 = 1 // ID==1的用户组为管理员组
err = m.CreateUser(user, groupId)
if err != nil {
m.logger.Error("initUser", zap.Error(err))
}
@ -318,3 +326,66 @@ func (m *DBModel) GetUserPermissinsByUserId(userId int64) (permissions []*Permis
err = nil
return
}
// SetUserGroupAndPassword 设置用户组和密码
func (m *DBModel) SetUserGroupAndPassword(userId int64, groupId []int64, password ...string) (err error) {
tx := m.db.Begin()
defer func() {
if err != nil {
tx.Rollback()
} else {
tx.Commit()
}
}()
var (
existUsersGroups []UserGroup
userGroups []UserGroup
)
tx.Where("user_id = ?", userId).Find(&existUsersGroups)
// 删除旧的关联用户组
err = tx.Where("user_id = ?", userId).Delete(&UserGroup{}).Error
if err != nil {
m.logger.Error("SetUserGroupAndPassword", zap.Error(err))
return
}
// 设置用户组统计数据
for _, existUsersGroup := range existUsersGroups {
err = tx.Model(&Group{}).Where("id = ?", existUsersGroup.GroupId).Update("user_count", gorm.Expr("user_count - ?", 1)).Error
if err != nil {
m.logger.Error("SetUserGroupAndPassword", zap.Error(err))
return
}
}
// 设置用户组统计数据
for _, groupId := range groupId {
userGroups = append(userGroups, UserGroup{UserId: userId, GroupId: groupId})
err = tx.Model(&Group{}).Where("id = ?", groupId).Update("user_count", gorm.Expr("user_count + ?", 1)).Error
if err != nil {
m.logger.Error("SetUserGroupAndPassword", zap.Error(err))
return
}
}
if len(userGroups) > 0 {
err = tx.Create(&userGroups).Error
if err != nil {
m.logger.Error("SetUserGroupAndPassword", zap.Error(err))
return
}
}
if len(password) > 0 {
err = m.UpdateUserPassword(userId, password[0], tx)
if err != nil {
m.logger.Error("UpdateUserPassword", zap.Error(err))
return
}
}
return
}

@ -1,8 +1,6 @@
package model
import (
"fmt"
"strings"
"time"
"go.uber.org/zap"
@ -73,47 +71,18 @@ func (m *DBModel) GetUserGroup(id interface{}, fields ...string) (userGroup User
type OptionGetUserGroupList struct {
Page int
Size int
WithCount bool // 是否返回总数
Ids []interface{} // id列表
SelectFields []string // 查询字段
QueryRange map[string][2]interface{} // map[field][]{min,max}
QueryIn map[string][]interface{} // map[field][]{value1,value2,...}
QueryLike map[string][]interface{} // map[field][]{value1,value2,...}
WithCount bool // 是否返回总数
Ids []interface{} // id列表
SelectFields []string // 查询字段
QueryIn map[string][]interface{} // map[field][]{value1,value2,...}
Sort []string
}
// GetUserGroupList 获取UserGroup列表
func (m *DBModel) GetUserGroupList(opt OptionGetUserGroupList) (userGroupList []UserGroup, total int64, err error) {
func (m *DBModel) GetUserGroupList(opt *OptionGetUserGroupList) (userGroupList []UserGroup, total int64, err error) {
db := m.db.Model(&UserGroup{})
for field, rangeValue := range opt.QueryRange {
fields := m.FilterValidFields(UserGroup{}.TableName(), field)
if len(fields) == 0 {
continue
}
if rangeValue[0] != nil {
db = db.Where(fmt.Sprintf("%s >= ?", field), rangeValue[0])
}
if rangeValue[1] != nil {
db = db.Where(fmt.Sprintf("%s <= ?", field), rangeValue[1])
}
}
for field, values := range opt.QueryIn {
fields := m.FilterValidFields(UserGroup{}.TableName(), field)
if len(fields) == 0 {
continue
}
db = db.Where(fmt.Sprintf("%s in (?)", field), values)
}
for field, values := range opt.QueryLike {
fields := m.FilterValidFields(UserGroup{}.TableName(), field)
if len(fields) == 0 {
continue
}
db = db.Where(strings.TrimSuffix(fmt.Sprintf(strings.Join(make([]string, len(values)+1), "%s like ? or"), field), "or"), values...)
}
tableName := UserGroup{}.TableName()
db = m.generateQueryIn(db, tableName, opt.QueryIn)
if len(opt.Ids) > 0 {
db = db.Where("id in (?)", opt.Ids)
@ -132,27 +101,6 @@ func (m *DBModel) GetUserGroupList(opt OptionGetUserGroupList) (userGroupList []
db = db.Select(opt.SelectFields)
}
if len(opt.Sort) > 0 {
var sorts []string
for _, sort := range opt.Sort {
slice := strings.Split(sort, " ")
if len(m.FilterValidFields(UserGroup{}.TableName(), slice[0])) == 0 {
continue
}
if len(slice) == 2 {
sorts = append(sorts, fmt.Sprintf("%s %s", slice[0], slice[1]))
} else {
sorts = append(sorts, fmt.Sprintf("%s desc", slice[0]))
}
}
if len(sorts) > 0 {
db = db.Order(strings.Join(sorts, ","))
}
}
db = db.Offset((opt.Page - 1) * opt.Size).Limit(opt.Size)
err = db.Find(&userGroupList).Error
if err != nil && err != gorm.ErrRecordNotFound {
m.logger.Error("GetUserGroupList", zap.Error(err))

@ -40,9 +40,9 @@ export const updateUserPassword = (data) => {
})
}
export const updateUser = (data) => {
export const updateUserProfile = (data) => {
return service({
url: '/api/v1/user',
url: '/api/v1/user/profile',
method: 'put',
data,
})
@ -56,6 +56,22 @@ export const deleteUser = (params) => {
})
}
export const addUser = (data) => {
return service({
url: '/api/v1/user',
method: 'post',
data,
})
}
export const setUser = (data) => {
return service({
url: '/api/v1/user',
method: 'put',
data,
})
}
export const listUser = (params) => {
return service({
url: '/api/v1/user/list',

@ -58,7 +58,6 @@
<el-form-item>
<el-button
type="primary"
class="btn-block"
icon="el-icon-check"
:loading="loading"
@click="onSubmit"

@ -67,9 +67,9 @@ export default {
}
},
methods: {
...mapActions('user', ['updateUser']),
...mapActions('user', ['updateUserProfile']),
async setProfile() {
const res = await this.updateUser(this.profile)
const res = await this.updateUserProfile(this.profile)
if (res.status === 200) {
this.$emit('success', res)
}

@ -0,0 +1,146 @@
<template>
<div class="com-form-user">
<el-form ref="user" label-position="top" label-width="80px" :model="user">
<el-form-item
label="用户名"
prop="username"
:rules="[{ required: true, message: '请输入用户名', trigger: 'blur' }]"
>
<el-input
v-model="user.username"
placeholder="请输入用户名"
:disabled="user.id > 0 ? true : false"
></el-input>
</el-form-item>
<el-form-item
label="密码"
prop="password"
:rules="
user.id > 0
? []
: [{ required: true, message: '请输入用户密码', trigger: 'blur' }]
"
>
<el-input
v-model="user.password"
:placeholder="
user.id > 0 ? '输入密码表示修改用户密码' : '请输入用户密码'
"
type="password"
clearable
></el-input>
</el-form-item>
<el-form-item
label="角色"
prop="group_id"
:rules="[{ required: true, message: '请选择角色', trigger: 'blur' }]"
>
<el-select
v-model="user.group_id"
multiple
filterable
placeholder="请选择角色"
>
<el-option
v-for="group in groups"
:key="'group-' + group.id"
:label="group.title"
:value="group.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button
type="primary"
class="btn-block"
icon="el-icon-check"
@click="setUser"
>提交</el-button
>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { addUser, setUser } from '~/api/user'
export default {
name: 'FormUser',
props: {
groups: {
type: Array,
default: () => {
return []
},
},
initUser: {
type: Object,
default: () => {
return {
id: 0,
username: '',
password: '',
group_id: [],
}
},
},
},
data() {
return {
user: { id: 0 },
}
},
watch: {
initUser: {
handler(val) {
this.user = val
},
immediate: true,
},
},
created() {
this.user = this.initUser
},
methods: {
setUser() {
this.$refs.user.validate(async (valid) => {
if (valid) {
if (this.user.id > 0) {
const res = await setUser({
id: this.user.id,
username: this.user.username,
password: this.user.password,
group_id: this.user.group_id,
})
if (res.status === 200) {
this.$message.success('设置成功')
this.$emit('success')
} else {
this.$message.error(res.data.message)
}
} else {
const res = await addUser(this.user)
if (res.status === 200) {
this.$message.success('新增成功')
this.$emit('success')
} else {
this.$message.error(res.data.message)
}
}
}
})
},
reset() {
this.user = { id: 0 }
this.$refs.user.resetFields()
this.$refs.user.clearValidate()
},
},
}
</script>
<style lang="scss">
.com-form-user {
.el-select {
width: 100%;
}
}
</style>

@ -80,6 +80,7 @@
fixed="right"
label="操作"
:min-width="actionsMinWidth"
class="com-table-list-actions"
>
<template slot-scope="scope">
<slot :row="scope.row" name="actions"></slot>
@ -176,3 +177,11 @@ export default {
},
}
</script>
<style lang="scss">
.com-table-list {
.el-button {
margin-left: 0;
margin-right: 10px;
}
}
</style>

@ -21,6 +21,7 @@
:show-edit="true"
:show-delete="true"
:show-select="true"
:actions-min-width="80"
@selectRow="selectRow"
@editRow="editRow"
@deleteRow="deleteRow"

@ -31,6 +31,7 @@
<el-button
type="text"
icon="el-icon-coordinate"
size="small"
@click="setGroupPermission(scope.row)"
>授权</el-button
>

@ -20,7 +20,18 @@
:show-edit="true"
:show-delete="true"
:show-select="true"
/>
:actions-min-width="140"
>
<template slot="actions" slot-scope="scope">
<el-button
type="text"
size="small"
icon="el-icon-setting"
@click="setUser(scope.row)"
>设置</el-button
>
</template>
</TableList>
</el-card>
<el-card shadow="never" class="mgt-20px">
@ -38,6 +49,19 @@
</el-pagination>
</div>
</el-card>
<el-dialog
:title="user.id ? '设置用户' : '新增用户'"
:visible.sync="formUserVisible"
width="640px"
>
<FormUser
ref="formUser"
:init-user="user"
:groups="groups"
@success="success"
/>
</el-dialog>
</div>
</template>
@ -47,8 +71,9 @@ import { listGroup } from '~/api/group'
import { userStatusOptions } from '~/utils/enum'
import TableList from '~/components/TableList.vue'
import FormSearch from '~/components/FormSearch.vue'
import FormUser from '~/components/FormUser.vue'
export default {
components: { TableList, FormSearch },
components: { TableList, FormSearch, FormUser },
layout: 'admin',
data() {
return {
@ -61,8 +86,10 @@ export default {
group_id: [],
size: 10,
},
formUserVisible: false,
groups: [],
users: [],
user: { id: 0 },
total: 100,
searchFormFields: [],
listFields: [],
@ -109,7 +136,21 @@ export default {
this.listUser()
},
onCreate() {
console.log('onCreate')
this.formUserVisible = true
this.$nextTick(() => {
this.$refs.formUser.reset()
})
},
setUser(row) {
this.formUserVisible = true
this.$nextTick(() => {
this.$refs.formUser.reset()
this.user = { ...row }
})
},
success() {
this.formUserVisible = false
this.listUser()
},
batchDelete() {
console.log('batchDelete')

@ -19,7 +19,7 @@
:show-edit="true"
:show-delete="false"
:show-select="false"
:actions-min-width="70"
:actions-min-width="80"
@editRow="editRow"
/>
</el-card>

@ -1,5 +1,5 @@
import { Message } from 'element-ui'
import { login, getUser, updateUser, logout } from '~/api/user'
import { login, getUser, updateUserProfile, logout } from '~/api/user'
export const user = {
namespaced: true,
state: {
@ -40,8 +40,8 @@ export const user = {
}
return res
},
async updateUser({ commit }, profile) {
const res = await updateUser(profile)
async updateUserProfile({ commit }, profile) {
const res = await updateUserProfile(profile)
if (res.status === 200) {
commit('mergeUser', profile)
} else {

@ -30,6 +30,11 @@ const cumstomPermissionMap = {
path: 'ListPermission',
children: [],
},
'api.v1.ConfigAPI': {
label: '系统设置',
path: 'ListConfig',
children: [],
},
upload: {
id: 0,
label: '上传管理',
@ -55,7 +60,7 @@ export const permissionsToTree = (permissions) => {
}
permissionMap[slice[1]].children.push({
...permission,
label: permission.title,
label: permission.title || permission.path,
})
} else {
if (!permissionMap[slice[3]]) {
@ -64,7 +69,10 @@ export const permissionsToTree = (permissions) => {
label: slice[3],
}
}
permissionMap[slice[3]].children.push(permission)
permissionMap[slice[3]].children.push({
...permission,
label: permission.title || permission.path,
})
}
})
Object.keys(permissionMap).forEach((key) => {

Loading…
Cancel
Save