Jelajahi Sumber

add: 添加菜单权限管理,及部分遗漏功能

zqbao 11 bulan lalu
induk
melakukan
0b0f3623c1

+ 21 - 0
controllers/error.go

@@ -0,0 +1,21 @@
+package controllers
+
+import "eta/eta_mini_crm/models"
+
+// ErrorController
+// @Description: 该控制器处理页面错误请求
+type ErrorController struct {
+	BaseCommonController
+}
+
+func (c *ErrorController) Error404() {
+	c.Data["content"] = "很抱歉您访问的地址或者方法不存在"
+	//c.TplName = "error/404.html"
+
+	br := new(models.BaseResponse).Init()
+
+	br.Msg = "您访问的资源不存在"
+	br.Ret = 404
+	c.Data["json"] = br
+	c.ServeJSON()
+}

+ 183 - 0
controllers/sys_role.go

@@ -5,6 +5,7 @@ import (
 	"eta/eta_mini_crm/models"
 	"eta/eta_mini_crm/models/request"
 	"eta/eta_mini_crm/models/response"
+	"eta/eta_mini_crm/services"
 	"eta/eta_mini_crm/utils"
 	"time"
 
@@ -235,3 +236,185 @@ func (this *SysRoleController) Edit() {
 	br.Success = true
 	br.Msg = "编辑成功"
 }
+
+// ButtonList
+// @Title 角色-按钮权限列表
+// @Description 角色-按钮权限列表
+// @Param   RoleId   query   int  true       "角色Id"
+// @Success 200 {object} system.SysRoleListResp
+// @router /menu/buttons [get]
+func (this *SysRoleController) ButtonList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	roleId := sysUser.SysRoleId
+	list, e := models.GetMenuButtonsByRoleId(roleId)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取角色按钮权限失败, Err: " + e.Error()
+		return
+	}
+
+	buttonList := make([]*response.SysMenuButtonResp, 0)
+	for _, v := range list {
+		tmp := new(response.SysMenuButtonResp)
+		tmp.SysMenuId = v.SysMenuId
+		tmp.ParentId = v.ParentId
+		tmp.Name = v.Name
+		tmp.ButtonCode = v.ButtonCode
+		buttonList = append(buttonList, tmp)
+	}
+
+	br.Data = buttonList
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// SysRoleMenuAuthSave
+// @Title 角色设置权限-保存
+// @Description 角色设置权限-保存
+// @Param	request	body RoleMenusSaveReq true "type json string"
+// @Success 200 {object} system.SysRoleListResp
+// @router /menu/auth_save [post]
+func (this *SysRoleController) SysRoleMenuAuthSave() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req request.RoleMenusSaveReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.SysRoleId <= 0 {
+		br.Msg = "参数有误"
+		return
+	}
+	if len(req.SysMenuIds) == 0 {
+		br.Msg = "请选择菜单"
+		return
+	}
+
+	items := make([]*models.SysRoleMenuMapping, 0)
+	for _, v := range req.SysMenuIds {
+		t := new(models.SysRoleMenuMapping)
+		t.SysMenuId = v
+		t.SysRoleId = req.SysRoleId
+		items = append(items, t)
+	}
+	for _, v := range req.HalfMenuIds {
+		t := new(models.SysRoleMenuMapping)
+		t.SysMenuId = v
+		t.Type = 1
+		t.SysRoleId = req.SysRoleId
+		items = append(items, t)
+	}
+	if e := models.CreateMultiSysRoleMenu(req.SysRoleId, items); e != nil {
+		br.Msg = "保存失败"
+		br.ErrMsg = "保存角色菜单权限失败, Err: " + e.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "设置成功"
+}
+
+// SysRoleMenuAuthList
+// @Title 角色设置权限-菜单列表
+// @Description 角色设置权限-菜单列表
+// @Param   RoleId   query   int  true       "角色Id"
+// @Success 200 {object} system.SysRoleListResp
+// @router /menu/auth_list [get]
+func (this *SysRoleController) SysRoleMenuAuthList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	resp := new(response.SysMenuListResp)
+	resp.ChoiceList = make([]int, 0)
+	resp.HalfChoiceList = make([]int, 0)
+	resp.List = make([]*models.SysMenuItem, 0)
+
+	// 角色勾选的权限
+	roleId, _ := this.GetInt("SysRoleId", 0)
+	if roleId > 0 {
+		relates, e := models.GetSysRoleMenuByRoleId(roleId)
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取角色关联菜单失败, Err: " + e.Error()
+			return
+		}
+		for _, r := range relates {
+			if r.Type == 1 {
+				resp.HalfChoiceList = append(resp.HalfChoiceList, r.SysMenuId)
+				continue
+			}
+			resp.ChoiceList = append(resp.ChoiceList, r.SysMenuId)
+		}
+	}
+
+	sysRole, err := models.GetSysRoleById(roleId)
+	if err == nil {
+		if sysRole.SysRoleName == "admin" {
+			br.Ret = 200
+			br.Success = true
+			br.Msg = "获取成功"
+			return
+		}
+	}
+
+	order := `sort ASC, create_time DESC, sys_menu_id DESC`
+	list, e := models.GetSysMenuItemsByCondition(``, make([]interface{}, 0), []string{}, order)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取菜单列表失败, Err: " + e.Error()
+		return
+	}
+
+	items := make([]*models.SysMenuItem, 0)
+	for _, v := range list {
+		t := &models.SysMenuItem{
+			MenuId:     v.SysMenuId,
+			ParentId:   v.ParentId,
+			Name:       v.Name,
+			Sort:       v.Sort,
+			Path:       v.Path,
+			IconPath:   v.IconPath,
+			ButtonCode: v.ButtonCode,
+			Children:   make([]*models.SysMenuItem, 0),
+		}
+		items = append(items, t)
+	}
+
+	// 递归返回树形结构
+	items = services.GetMenuTreeRecursive(items, 0)
+
+	resp.List = items
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}

+ 70 - 0
controllers/sys_user.go

@@ -479,7 +479,77 @@ func (this *SysUserController) ResetPass() {
 	br.Ret = 200
 	br.Msg = "重置密码成功"
 	br.Success = true
+}
+
+// ResetMyPass
+// @Title 重置密码
+// @Description 重置密码
+// @Param	request	body system.SysUserResetPassReq true "type json string"
+// @Success 200 编辑成功
+// @router /reset_my_pass [post]
+func (this *SysUserController) ResetMyPass() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req request.ResetMyPasswordReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.Password != req.RePassword {
+		br.Msg = "两次密码输入不一致"
+		return
+	}
+
+	sysUser := this.SysUser
+	// 校验系统用户的密码
+	var pwd string
+	{
+		pwdByte, err := base64.StdEncoding.DecodeString(req.Password)
+		if err != nil {
+			br.Msg = "解析数据失败"
+			br.ErrMsg = "解析数据失败,Err:" + err.Error()
+			return
+		}
+		originPwd := string(pwdByte)
+		if !utils.CheckPwd(originPwd) {
+			br.Msg = "密码格式错误,请重新输入"
+			return
+		}
+		pwd = utils.MD5(originPwd)
 
+		originPwdByte, err := base64.StdEncoding.DecodeString(req.OriginPassword)
+		if err != nil {
+			br.Msg = "解析数据失败"
+			br.ErrMsg = "解析数据失败,Err:" + err.Error()
+			return
+		}
+		stringPwd := string(originPwdByte)
+		if sysUser.Password != utils.MD5(stringPwd) {
+			br.Msg = "原密码错误"
+			return
+		}
+	}
+
+	sysUser.Password = pwd
+	sysUser.ModifyTime = time.Now()
+	err = sysUser.Update([]string{"password", "modify_time"})
+	if err != nil {
+		br.Msg = "密码修改失败"
+		br.ErrMsg = "密码修改失败,系统错误,Err:" + err.Error()
+		return
+	}
+	//将用户对应的token给过期
+	services.LogoutSysUser(sysUser.SysUserId)
+
+	br.Msg = "重置密码成功"
+	br.Success = true
+	br.Ret = 200
 }
 
 // @Title 开启/禁用系统用户

+ 148 - 8
controllers/user.go

@@ -5,6 +5,7 @@ import (
 	"eta/eta_mini_crm/models"
 	"eta/eta_mini_crm/models/request"
 	"eta/eta_mini_crm/models/response"
+	"eta/eta_mini_crm/services"
 	"eta/eta_mini_crm/utils"
 	"strings"
 	"time"
@@ -128,20 +129,27 @@ func (this *UserController) Add() {
 		br.Msg = "邮箱已存在,请重新输入"
 		return
 	}
+
 	user := &models.User{}
+	curTime := time.Now()
 	if userByPhone == nil && userByEmail == nil {
-		user.CreateTime = time.Now()
-		user.ModifyTime = time.Now()
+		user.CreateTime = curTime
+		user.ModifyTime = curTime
+	}
+	if userByEmail != nil {
+		user = userByEmail
+	}
+	if userByPhone != nil {
+		user = userByPhone
 	}
-
 	validStartTime = validStartTime.Local().Add(-time.Hour * 8)
 	validEndTime = validEndTime.Local().Add(-time.Hour*8 + time.Hour*24)
-	curTime := time.Now()
-	if curTime.Before(validEndTime) && curTime.After(validStartTime) {
+	if curTime.Before(validEndTime) {
 		user.Status = 2
 	} else {
 		user.Status = 0
 	}
+
 	user.RealName = req.RealName
 	user.AreaCode = req.AreaCode
 	user.Phone = req.Phone
@@ -150,7 +158,7 @@ func (this *UserController) Add() {
 	user.ValidStartTime = validStartTime
 	user.ValidEndTime = validEndTime
 	user.Company = req.Company
-	user.ModifyTime = time.Now()
+	user.ModifyTime = curTime
 	err = models.SaveUser(user, req.ChartPermission)
 	if err != nil {
 		br.Msg = "添加客户失败"
@@ -158,6 +166,12 @@ func (this *UserController) Add() {
 		return
 	}
 
+	if user.Status == 2 {
+		userRecord := &models.UserChangeRecord{}
+		userRecord.Content = this.SysUser.SysRealName + "新增用户"
+		userRecord.Insert()
+	}
+
 	br.Msg = "添加成功"
 	br.Success = true
 	br.Ret = 200
@@ -273,7 +287,7 @@ func (this *UserController) Edit() {
 	curTime := time.Now()
 	if !req.IsEnabled {
 		user.Status = 0
-	} else if curTime.After(validStartTime) && curTime.Before(validEndTime) {
+	} else if curTime.Before(validEndTime) {
 		user.Status = 2
 	} else {
 		user.Status = 1
@@ -284,6 +298,13 @@ func (this *UserController) Edit() {
 		br.ErrMsg = "添加客户失败,系统错误,Err:" + err.Error()
 		return
 	}
+	record := &models.UserChangeRecord{}
+	if user.Status == 2 {
+		record.Content = this.SysUser.SysRealName + "新增用户"
+	} else {
+		record.Content = this.SysUser.SysRealName + "编辑用户"
+	}
+	record.Insert()
 
 	br.Msg = "编辑成功"
 	br.Success = true
@@ -582,10 +603,23 @@ func (this *UserController) Detail() {
 		br.Msg = "用户不存在或已删除,请刷新页面"
 		return
 	}
+	permissionList, err := services.GetUserPermissionById(UserId)
+	if err != nil {
+		br.Msg = "用户权限获取失败,请重新尝试"
+		return
+	}
+	permissionMap := make(map[string][]string)
+	for _, pm := range permissionList {
+		permissionMap[pm.ParentName] = append(permissionMap[pm.ParentName], pm.PermissionName)
+	}
+	resp := new(response.UserDetailResp)
+	resp.Detail = user
+	resp.Permission = permissionMap
+
 	br.Msg = "查询成功"
 	br.Ret = 200
 	br.Success = true
-	br.Data = user
+	br.Data = resp
 }
 
 // Delete
@@ -619,3 +653,109 @@ func (this *UserController) Delete() {
 	br.Success = true
 	br.Ret = 200
 }
+
+// @Title 开启/禁用用户
+// @Description 开启/禁用用户接口
+// @Param	request	body system.SysuserEditReq true "type json string"
+// @Success 200 操作成功
+// @router /editEnabled [post]
+func (this *UserController) EditEnabled() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req request.UserEditEnabledReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	user, err := models.GetUserById(req.UserId)
+	if err != nil {
+		br.Msg = "获取数据失败"
+		br.ErrMsg = "获取系统用户数据失败,Err:" + err.Error()
+		return
+	}
+	// 修改系统用户禁用状态
+	curTime := time.Now()
+	if req.IsEnabled && curTime.Before(user.ValidEndTime) && curTime.After(user.ValidStartTime) {
+		user.Status = 2
+	}
+	if !req.IsEnabled {
+		user.Status = 0
+	} else {
+		user.Status = 1
+
+	}
+	user.ModifyTime = curTime
+	err = user.Update([]string{"status", "modify_time"})
+	if err != nil {
+		br.Msg = "修改失败"
+		br.ErrMsg = "修改系统用户数据失败,Err:" + err.Error()
+		return
+	}
+	// 记录操作
+	record := &models.UserChangeRecord{}
+	if user.Status == 0 {
+		record.Content = this.SysUser.SysRealName + "禁用用户"
+	} else {
+		record.Content = this.SysUser.SysRealName + "启用用户"
+	}
+	record.Insert()
+
+	br.Ret = 200
+	br.Success = true
+	br.IsAddLog = true
+	br.Msg = "操作成功"
+}
+
+// @Title 用户信息变更记录
+// @Description 用户信息变更记录
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Success 200 操作成功
+// @router /change_list [get]
+func (this *UserController) ChangeList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	} else if pageSize > utils.PageSize100 {
+		pageSize = utils.PageSize100
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	startSize := utils.StartIndex(currentIndex, pageSize)
+
+	total, err := models.GetUserChangeRecordCount()
+	if err != nil {
+		br.Msg = "用户信息变更查询失败"
+		br.ErrMsg = "用户信息变更查询失败,系统错误,Err:" + err.Error()
+		return
+	}
+	userRcord, err := models.GetUserChangeRecordList(startSize, pageSize)
+	if err != nil {
+		br.Msg = "用户信息变更查询失败"
+		br.ErrMsg = "用户信息变更查询失败,系统错误,Err:" + err.Error()
+		return
+	}
+	page := paging.GetPaging(currentIndex, pageSize, total)
+	resp := new(response.UserChangeRecordResp)
+	resp.List = userRcord
+	resp.Paging = page
+
+	br.Data = resp
+	br.Msg = "查询成功"
+	br.Success = true
+	br.Ret = 200
+}

+ 33 - 4
controllers/user_login.go

@@ -99,11 +99,40 @@ func (this *UserLoginController) Login() {
 }
 
 // AreaCodeList
-// @Title 用户登录
-// @Description 用户登录
-// @Param	request	body UserLoginReq true "type json string"
-// @Success 200 {object} models.LoginResp
+// @Title 手机号区号列表
+// @Description 手机号区号列表
+// @Success 200 Ret=200 获取成功
 // @router /area_code/list [get]
 func (this *UserLoginController) AreaCodeList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
 
+	resp := make([]response.AreaCodeListResp, 0)
+	confAuth, e := models.GetConfigDetailByCode(models.ConfAreaCodeListKey)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取手机号区号配置失败, Err: " + e.Error()
+		return
+	}
+	if confAuth.ConfigValue == "" {
+		br.Msg = "获取失败"
+		br.ErrMsg = "手机号区号配置为空"
+		return
+	}
+	if e := json.Unmarshal([]byte(confAuth.ConfigValue), &resp); e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "手机号区号配置有误"
+		return
+	}
+
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
 }

+ 49 - 0
main.go

@@ -1,13 +1,62 @@
 package main
 
 import (
+	"eta/eta_mini_crm/controllers"
 	_ "eta/eta_mini_crm/routers"
 	"eta/eta_mini_crm/scheduler"
+	"fmt"
+	"runtime"
 
+	"github.com/beego/beego/v2/core/logs"
 	"github.com/beego/beego/v2/server/web"
+	"github.com/beego/beego/v2/server/web/context"
 )
 
 func main() {
+	if web.BConfig.RunMode == "dev" {
+		web.BConfig.WebConfig.DirectoryIndex = true
+		web.BConfig.WebConfig.StaticDir["/swagger"] = "swagger"
+	}
+
+	// 启动定时任务
 	go scheduler.InitJob()
+
+	web.ErrorController(&controllers.ErrorController{})
+	// 内存调整
+	web.BConfig.MaxMemory = 1024 * 1024 * 128
+
+	web.BConfig.RecoverFunc = Recover
 	web.Run()
 }
+
+func Recover(ctx *context.Context, conf *web.Config) {
+	if err := recover(); err != nil {
+		if err == web.ErrAbort {
+			return
+		}
+		if !web.BConfig.RecoverPanic {
+			panic(err)
+		}
+		stack := ""
+		msg := fmt.Sprintf("The request url is  %v", ctx.Input.URL())
+		stack += msg + "</br>"
+		logs.Critical(msg)
+		msg = fmt.Sprintf("The request data is %v", string(ctx.Input.RequestBody))
+		stack += msg + "</br>"
+		logs.Critical(msg)
+		msg = fmt.Sprintf("Handler crashed with error %v", err)
+		stack += msg + "</br>"
+		logs.Critical(msg)
+		for i := 1; ; i++ {
+			_, file, line, ok := runtime.Caller(i)
+			if !ok {
+				break
+			}
+			logs.Critical(fmt.Sprintf("%s:%d", file, line))
+			stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d</br>", file, line))
+		}
+		//go utils.SendEmail(utils.APPNAME+"崩了"+time.Now().Format("2006-01-02 15:04:05"), stack, utils.EmailSendToUsers)
+		// go alarm_msg.SendAlarmMsg(utils.APPNAME+"崩了"+time.Now().Format("2006-01-02 15:04:05")+"<br/>"+stack, 3)
+	}
+	return
+}

+ 28 - 2
models/chart_permission.go

@@ -1,6 +1,8 @@
 package models
 
 import (
+	"fmt"
+	"strings"
 	"time"
 
 	"github.com/beego/beego/v2/client/orm"
@@ -61,6 +63,11 @@ type ChartPermissionList struct {
 	Child                 []*ChartPermissionList `description:"子权限"`
 }
 
+type ChartPermissionView struct {
+	ParentName     string `description:"父权限名称" json:"parent_name"`
+	PermissionName string `description:"权限名" json:"permission_name"`
+}
+
 func GetChartPermissionList(condition string, pars []interface{}) (items []*ChartPermission, err error) {
 	o := orm.NewOrmUsingDB("rddp")
 	sql := `SELECT * FROM chart_permission WHERE enabled=1 `
@@ -71,10 +78,29 @@ func GetChartPermissionList(condition string, pars []interface{}) (items []*Char
 	return
 }
 
-func GetChildChartPermissionListById(ChartPermissionId int) (items []*ChartPermissionList, err error) {
+func GetChartPermissionListByIds(chartPermissionIds []int) (items []*ChartPermissionView, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT c.permission_name AS permission_name, lc.permission_name AS parent_name FROM chart_permission c
+		LEFT JOIN chart_permission lc
+		ON c.parent_id=lc.chart_permission_id 
+		WHERE c.chart_permission_id in (%s)
+	`
+	// 构建 IN 子句的占位符
+	placeholders := make([]string, len(chartPermissionIds))
+	args := make([]interface{}, len(chartPermissionIds))
+	for i, id := range chartPermissionIds {
+		placeholders[i] = "?"
+		args[i] = id
+	}
+	sql = fmt.Sprintf(sql, strings.Join(placeholders, ","))
+	_, err = o.Raw(sql, chartPermissionIds).QueryRows(&items)
+	return
+}
+
+func GetChildChartPermissionListById(chartPermissionId int) (items []*ChartPermissionList, err error) {
 	o := orm.NewOrmUsingDB("rddp")
 	sql := `SELECT * FROM chart_permission WHERE enabled=1 AND parent_id=?`
-	_, err = o.Raw(sql, ChartPermissionId).QueryRows(&items)
+	_, err = o.Raw(sql, chartPermissionId).QueryRows(&items)
 	return
 }
 

+ 16 - 0
models/crm_config.go

@@ -0,0 +1,16 @@
+package models
+
+import "github.com/beego/beego/v2/client/orm"
+
+const ConfAreaCodeListKey = "area_code_list" // 手机号区号列表
+
+type CrmConfig struct {
+	ConfigValue string `description:"详情"`
+}
+
+func GetConfigDetailByCode(configCode string) (item CrmConfig, err error) {
+	o := orm.NewOrmUsingDB("master")
+	sql := ` SELECT config_value FROM crm_config WHERE config_code=? `
+	err = o.Raw(sql, configCode).QueryRow(&item)
+	return
+}

+ 2 - 0
models/db.go

@@ -37,5 +37,7 @@ func init() {
 		new(UserChartPermissionMapping),
 		new(User),
 		new(SysMessageReport),
+		new(CrmConfig),
+		new(UserChangeRecord),
 	)
 }

+ 6 - 0
models/request/sys_role.go

@@ -12,3 +12,9 @@ type SysRoleEditReq struct {
 	SysRoleId   int    `description:"角色ID"`
 	SysRoleName string `description:"角色名称"`
 }
+
+type RoleMenusSaveReq struct {
+	SysRoleId   int   `description:"角色ID"`
+	SysMenuIds  []int `description:"菜单IDs"`
+	HalfMenuIds []int `description:"半选菜单IDs-仅供前端回显用的"`
+}

+ 6 - 0
models/request/sys_user.go

@@ -21,6 +21,12 @@ type ResetPasswordReq struct {
 	RePassword string `description:"重复密码"`
 }
 
+type ResetMyPasswordReq struct {
+	OriginPassword string `description:"旧密码"`
+	Password       string `description:"新密码"`
+	RePassword     string `description:"重复密码"`
+}
+
 type SysUserEditEnabledReq struct {
 	SysUserId int  `description:"用户id"`
 	IsEnabled bool `description:"是否启用"`

+ 5 - 0
models/request/user.go

@@ -35,3 +35,8 @@ type UserCheckReq struct {
 type UserDeleteReq struct {
 	UserId int `description:"用户id"`
 }
+
+type UserEditEnabledReq struct {
+	UserId    int  `description:"用户id"`
+	IsEnabled bool `description:"是否启用"`
+}

+ 18 - 0
models/response/sys_menu.go

@@ -0,0 +1,18 @@
+package response
+
+import "eta/eta_mini_crm/models"
+
+type SysMenuButtonResp struct {
+	SysMenuId  int    `description:"菜单ID"`
+	ParentId   int    `description:"父级菜单ID"`
+	Name       string `description:"菜单名称或者按钮名称"`
+	MenuType   int    `description:"菜单类型: 0-菜单; 1-按钮"`
+	ButtonCode string `description:"按钮唯一标识"`
+}
+
+// SysMenuListResp ETA商家菜单列表响应体
+type SysMenuListResp struct {
+	ChoiceList     []int                 `description:"已选菜单"`
+	HalfChoiceList []int                 `description:"半选菜单-方便前端回显用的"`
+	List           []*models.SysMenuItem `description:"菜单列表"`
+}

+ 10 - 0
models/response/user.go

@@ -14,3 +14,13 @@ type UserListResp struct {
 type UserCheckResp struct {
 	UserId int
 }
+
+type UserChangeRecordResp struct {
+	List   []*models.UserChangeRecord
+	Paging *paging.PagingItem `description:"分页数据"`
+}
+
+type UserDetailResp struct {
+	Detail     *models.User
+	Permission map[string][]string
+}

+ 6 - 0
models/response/user_login.go

@@ -0,0 +1,6 @@
+package response
+
+type AreaCodeListResp struct {
+	Name  string `description:"地区"`
+	Value string `description:"区号"`
+}

+ 74 - 0
models/sys_menu.go

@@ -0,0 +1,74 @@
+package models
+
+import (
+	"fmt"
+	"strings"
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type SysMenu struct {
+	SysMenuId  int       `orm:"pk" description:"菜单id"`
+	ParentId   int       `description:"父级id"`
+	Sort       int       `description:"排序id"`
+	ButtonCode string    `description:"按钮唯一编码"`
+	Name       string    `description:"按钮名称"`
+	Path       string    `description:"路径"`
+	IconPath   string    `description:"图标路径"`
+	Level      int       `description:"层级"`
+	CreateTime time.Time `description:"创建时间"`
+	ModifyTime time.Time `description:"修改时间"`
+}
+
+type SysRoleMenuMapping struct {
+	SysRoleMenuMappingId int `orm:"pk" description:"id"`
+	SysRoleId            int `description:"角色id"`
+	SysMenuId            int `description:"菜单id"`
+	Type                 int `description:"类型"`
+}
+
+// SysMenuItem 角色菜单
+type SysMenuItem struct {
+	MenuId     int
+	ParentId   int            `description:"父级菜单ID"`
+	Name       string         `description:"菜单名称或者按钮名称"`
+	Sort       int            `description:"排序"`
+	Path       string         `description:"路由地址"`
+	IconPath   string         `description:"菜单图标地址"`
+	ButtonCode string         `description:"按钮/菜单唯一标识"`
+	Children   []*SysMenuItem `description:"子菜单"`
+}
+
+// GetMenuButtonsByRoleId 获取角色按钮
+func GetMenuButtonsByRoleId(roleId int) (items []*SysMenu, err error) {
+	sql := `SELECT
+				r.*
+			FROM
+				sys_menu AS r
+			JOIN sys_role_menu_mapping AS rm ON r.sys_menu_id = rm.sys_menu_id AND rm.type = 0
+			WHERE
+				rm.sys_role_id = ? 
+			ORDER BY
+				r.sort ASC,
+				r.create_time DESC`
+	o := orm.NewOrmUsingDB("master")
+	_, err = o.Raw(sql, roleId).QueryRows(&items)
+	return
+}
+
+// GetSysMenuItemsByCondition 获取菜单列表
+func GetSysMenuItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*SysMenu, err error) {
+	o := orm.NewOrmUsingDB("master")
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := `ORDER BY create_time DESC`
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM sys_menu WHERE 1=1 %s %s`, fields, condition, order)
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}

+ 28 - 2
models/sys_role.go

@@ -73,8 +73,34 @@ func GetSysRoleList(startSize, pageSize int) (items []*SysRole, err error) {
 	return
 }
 
-type SysMenu struct {
+// CreateMultiSysRoleMenu 删除并新增角色权限
+func CreateMultiSysRoleMenu(roleId int, items []*SysRoleMenuMapping) (err error) {
+	if roleId == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("master")
+	err = o.DoTx(func(ctx context.Context, txOrm orm.TxOrmer) error {
+		sql := `DELETE FROM sys_role_menu_mapping WHERE sys_role_id = ?`
+		_, e := txOrm.Raw(sql, roleId).Exec()
+		if e != nil {
+			return e
+		}
+
+		if len(items) > 0 {
+			_, e = txOrm.InsertMulti(len(items), items)
+			if e != nil {
+				return e
+			}
+		}
+		return nil
+	})
+	return
 }
 
-type SysRoleMenuMapping struct {
+// GetSysRoleMenuByRoleId 获取角色关联菜单
+func GetSysRoleMenuByRoleId(roleId int) (items []*SysRoleMenuMapping, err error) {
+	o := orm.NewOrmUsingDB("master")
+	sql := `SELECT * FROM sys_role_menu_mapping WHERE sys_role_id = ?`
+	_, err = o.Raw(sql, roleId).QueryRows(&items)
+	return
 }

+ 29 - 2
models/user.go

@@ -31,6 +31,22 @@ func (u *User) Save() (err error) {
 	return
 }
 
+func (u *User) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("master")
+	_, err = o.Update(u, cols...)
+	return
+}
+
+func UpdateUserStatus(condition string, pars []interface{}) (err error) {
+	o := orm.NewOrmUsingDB("master")
+	sql := ` UPDATE user SET status=0 WHERE 1=1 `
+	if condition != "" {
+		sql += condition
+	}
+	_, err = o.Raw(sql, pars).Exec()
+	return
+}
+
 func SaveUser(user *User, chartPermissionIds []int) (err error) {
 	o := orm.NewOrmUsingDB("master")
 	err = o.DoTx(func(ctx context.Context, txOrm orm.TxOrmer) error {
@@ -105,8 +121,19 @@ func GetUserCount(condition string, pars []interface{}) (count int, err error) {
 }
 
 func DeleteUserById(userId int) (err error) {
-	sql := `DELETE FROM user WHERE user_id=?`
 	o := orm.NewOrmUsingDB("master")
-	_, err = o.Raw(sql, userId).Exec()
+	err = o.DoTx(func(ctx context.Context, txOrm orm.TxOrmer) error {
+		sql := `DELETE FROM user WHERE user_id=?`
+		_, e := txOrm.Raw(sql, userId).Exec()
+		if e != nil {
+			return e
+		}
+		sql = `DELETE FROM user_chart_permission_mapping WHERE user_id=?`
+		_, e = txOrm.Raw(sql, userId).Exec()
+		if e != nil {
+			return e
+		}
+		return nil
+	})
 	return
 }

+ 34 - 0
models/user_change_record.go

@@ -0,0 +1,34 @@
+package models
+
+import (
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type UserChangeRecord struct {
+	UserChangeRecordId int       `orm:"pk" description:"id"`
+	Content            string    `description:"内容"`
+	CreateTime         time.Time `description:"创建时间"`
+}
+
+func (u *UserChangeRecord) Insert() (err error) {
+	u.CreateTime = time.Now()
+	o := orm.NewOrmUsingDB("master")
+	_, err = o.Insert(u)
+	return
+}
+
+func GetUserChangeRecordList(startSize, pageSize int) (items []*UserChangeRecord, err error) {
+	sql := `SELECT * FROM user_change_record ORDER BY create_time DESC LIMIT ?,?`
+	o := orm.NewOrmUsingDB("master")
+	_, err = o.Raw(sql, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+func GetUserChangeRecordCount() (count int, err error) {
+	sql := `SELECT COUNT(*) AS count FROM user_change_record `
+	o := orm.NewOrmUsingDB("master")
+	err = o.Raw(sql).QueryRow(&count)
+	return
+}

+ 54 - 0
routers/commentsRouter.go

@@ -115,6 +115,33 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mini_crm/controllers:SysRoleController"] = append(beego.GlobalControllerRouter["eta/eta_mini_crm/controllers:SysRoleController"],
+        beego.ControllerComments{
+            Method: "SysRoleMenuAuthList",
+            Router: `/menu/auth_list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_crm/controllers:SysRoleController"] = append(beego.GlobalControllerRouter["eta/eta_mini_crm/controllers:SysRoleController"],
+        beego.ControllerComments{
+            Method: "SysRoleMenuAuthSave",
+            Router: `/menu/auth_save`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_crm/controllers:SysRoleController"] = append(beego.GlobalControllerRouter["eta/eta_mini_crm/controllers:SysRoleController"],
+        beego.ControllerComments{
+            Method: "ButtonList",
+            Router: `/menu/buttons`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mini_crm/controllers:SysUserController"] = append(beego.GlobalControllerRouter["eta/eta_mini_crm/controllers:SysUserController"],
         beego.ControllerComments{
             Method: "Add",
@@ -169,6 +196,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mini_crm/controllers:SysUserController"] = append(beego.GlobalControllerRouter["eta/eta_mini_crm/controllers:SysUserController"],
+        beego.ControllerComments{
+            Method: "ResetMyPass",
+            Router: `/reset_my_pass`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mini_crm/controllers:SysUserController"] = append(beego.GlobalControllerRouter["eta/eta_mini_crm/controllers:SysUserController"],
         beego.ControllerComments{
             Method: "ResetPass",
@@ -187,6 +223,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mini_crm/controllers:UserController"] = append(beego.GlobalControllerRouter["eta/eta_mini_crm/controllers:UserController"],
+        beego.ControllerComments{
+            Method: "ChangeList",
+            Router: `/change_list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mini_crm/controllers:UserController"] = append(beego.GlobalControllerRouter["eta/eta_mini_crm/controllers:UserController"],
         beego.ControllerComments{
             Method: "Check",
@@ -223,6 +268,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mini_crm/controllers:UserController"] = append(beego.GlobalControllerRouter["eta/eta_mini_crm/controllers:UserController"],
+        beego.ControllerComments{
+            Method: "EditEnabled",
+            Router: `/editEnabled`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mini_crm/controllers:UserController"] = append(beego.GlobalControllerRouter["eta/eta_mini_crm/controllers:UserController"],
         beego.ControllerComments{
             Method: "List",

+ 34 - 2
scheduler/task.go

@@ -14,10 +14,15 @@ func InitJob() {
 	fmt.Println("消息推送任务开启。。。")
 	c := cron.New(cron.WithSeconds())
 
-	// 每天凌晨1点检测
+	// 每天凌晨1点检测, 发送消息
 	_, err := c.AddFunc("0 0 1 * * *", CheckUserTime)
 	if err != nil {
-		utils.ApiLog.Info("cron task err: %s", err.Error())
+		utils.ApiLog.Info("cron CheckUserTime task err: %s", err.Error())
+	}
+	// 每天凌晨1点检测, 修改用户状态
+	_, err = c.AddFunc("0 0 1 * * *", ModifyUser)
+	if err != nil {
+		utils.ApiLog.Info("cron ModifyUser task err: %s", err.Error())
 	}
 	c.Start()
 }
@@ -38,6 +43,33 @@ func CheckUserTime() {
 	}
 }
 
+func ModifyUser() {
+	retryCount := 10
+	var err error
+	defer func() {
+		if err != nil {
+			utils.ApiLog.Warn("userPermission 定时任务出错,Err: %s", err.Error())
+		}
+	}()
+	for i := 0; i <= retryCount; i++ {
+		err = ModifyUserStatus()
+		if err == nil {
+			break
+		}
+	}
+}
+
+func ModifyUserStatus() (err error) {
+	curTime := time.Now()
+	condition := ` AND valid_end_time<?`
+	var pars []interface{}
+	pars = append(pars, curTime)
+	condition += ` AND status=? `
+	pars = append(pars, 2)
+	err = models.UpdateUserStatus(condition, pars)
+	return
+}
+
 func CheckUserPermissionTime() (err error) {
 	var condition string
 	var pars []interface{}

+ 15 - 0
services/sys_menu.go

@@ -0,0 +1,15 @@
+package services
+
+import "eta/eta_mini_crm/models"
+
+// GetMenuTreeRecursive 递归菜单树
+func GetMenuTreeRecursive(list []*models.SysMenuItem, parentId int) []*models.SysMenuItem {
+	res := make([]*models.SysMenuItem, 0)
+	for _, v := range list {
+		if v.ParentId == parentId {
+			v.Children = GetMenuTreeRecursive(list, v.MenuId)
+			res = append(res, v)
+		}
+	}
+	return res
+}

+ 9 - 1
services/user.go

@@ -2,7 +2,15 @@ package services
 
 import "eta/eta_mini_crm/models"
 
-func SaveUser(user models.User) (err error) {
+func GetUserPermissionById(userId int) (items []*models.ChartPermissionView, err error) {
+	permissionIds, err := models.GetChartPermissionIdByUserId(userId)
+	if err != nil {
+		return
+	}
+	items, err = models.GetChartPermissionListByIds(permissionIds)
+	if err != nil {
+		return
+	}
 
 	return
 }