瀏覽代碼

add:增加部分系统用户管理,角色管理,部门管理的功能

zqbao 1 年之前
父節點
當前提交
14c16af6a4

+ 16 - 0
.vscode/launch.json

@@ -0,0 +1,16 @@
+{
+    // 使用 IntelliSense 了解相关属性。 
+    // 悬停以查看现有属性的描述。
+    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "name": "Launch Package",
+            "type": "go",
+            "request": "launch",
+            "mode": "auto",
+            "program": "${fileDirname}"
+        }
+
+    ]
+}

+ 107 - 0
controllers/base_auth1.go

@@ -0,0 +1,107 @@
+package controllers
+
+import (
+	"encoding/json"
+	"eta/eta_mini_crm/models"
+	"eta/eta_mini_crm/utils"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/beego/beego/v2/server/web"
+)
+
+type BaseAuthController struct {
+	web.Controller
+	SysUser *models.SysUser
+	Session *models.SysSession
+}
+
+func (c *BaseAuthController) Prepare() {
+	method := c.Ctx.Input.Method()
+	// uri := c.Ctx.Input.URI()
+	if method != "HEAD" {
+		if method == "POST" || method == "GET" {
+			authorization := c.Ctx.Input.Header("authorization")
+			if authorization == "" {
+				c.JSON(models.BaseResponse{Ret: 408, Msg: "请重新授权!", ErrMsg: "请重新授权:Token is empty or account is empty"})
+				c.StopRun()
+				return
+			}
+			tokenStr := authorization
+			tokenArr := strings.Split(tokenStr, "=")
+			token := tokenArr[1]
+
+			session, err := models.GetSysSessionByToken(token)
+			if err != nil {
+				if err == orm.ErrNoRows {
+					c.JSON(models.BaseResponse{Ret: 408, Msg: "信息已变更,请重新登陆!", ErrMsg: "Token 信息已变更:Token: " + token})
+					c.StopRun()
+					return
+				}
+				c.JSON(models.BaseResponse{Ret: 408, Msg: "网络异常,请稍后重试!", ErrMsg: "获取用户信息异常,Eerr:" + err.Error()})
+				c.StopRun()
+				return
+			}
+			if session == nil {
+				c.JSON(models.BaseResponse{Ret: 408, Msg: "网络异常,请稍后重试!", ErrMsg: "sesson is empty "})
+				c.StopRun()
+				return
+			}
+			account := utils.MD5(session.UserName)
+			if !utils.CheckToken(account, token) {
+				c.JSON(models.BaseResponse{Ret: 408, Msg: "鉴权失败,请重新登录!", ErrMsg: "登录失效,请重新登陆!,CheckToken Fail"})
+				c.StopRun()
+				return
+			}
+			if time.Now().After(session.ExpiredTime) {
+				c.JSON(models.BaseResponse{Ret: 408, Msg: "请重新登录!", ErrMsg: "获取用户信息异常"})
+				c.StopRun()
+				return
+			}
+			sysUser, err := models.GetSysUserById(session.SysUserId)
+			if err != nil {
+				if err == orm.ErrNoRows {
+					c.JSON(models.BaseResponse{Ret: 408, Msg: "信息已变更,请重新登陆!", ErrMsg: "获取sysUser信息失败: " + strconv.Itoa(session.SysUserId)})
+					c.StopRun()
+					return
+				}
+				c.JSON(models.BaseResponse{Ret: 408, Msg: "网络异常,请稍后重试!", ErrMsg: "获取sysUser信息异常,Err:" + err.Error()})
+				c.StopRun()
+				return
+			}
+			if sysUser == nil {
+				c.JSON(models.BaseResponse{Ret: 408, Msg: "网络异常,请稍后重试!", ErrMsg: "sysUser is empty"})
+				c.StopRun()
+				return
+			}
+			if !sysUser.IsEnabled {
+				c.JSON(models.BaseResponse{Ret: 408, Msg: "账户信息异常!", ErrMsg: "账户被禁用,不允许登陆!"})
+				c.StopRun()
+				return
+			}
+
+		}
+	}
+}
+
+func (c *BaseAuthController) JSON(data interface{}) error {
+	c.Ctx.Output.Header("Content-Type", "application/json; charset=utf-8")
+	desEncrypt := utils.DesBase64Encrypt([]byte(utils.DesKey), utils.DesKeySalt)
+	c.Ctx.Output.Header("Dk", string(desEncrypt)) // des3加解密key
+	// 设置Cookie为HTTPOnly
+	c.Ctx.SetCookie("", "", -1, "/", "", false, true, "")
+
+	content, err := json.Marshal(data)
+	if err != nil {
+		http.Error(c.Ctx.Output.Context.ResponseWriter, err.Error(), http.StatusInternalServerError)
+		return err
+	}
+	if utils.RunMode != "debug" {
+		content = utils.DesBase64Encrypt(content, utils.DesKey)
+		content = []byte(`"` + string(content) + `"`)
+	}
+	return c.Ctx.Output.Body(content)
+}

+ 25 - 0
controllers/base_common.go

@@ -0,0 +1,25 @@
+package controllers
+
+import (
+	"eta/eta_mini_crm/utils"
+	"net/url"
+
+	"github.com/beego/beego/v2/server/web"
+)
+
+type BaseCommonController struct {
+	web.Controller
+}
+
+func (c *BaseCommonController) Prepare() {
+	var requestBody string
+	method := c.Ctx.Input.Method()
+	if method == "GET" {
+		requestBody = c.Ctx.Request.RequestURI
+	} else {
+		requestBody, _ = url.QueryUnescape(string(c.Ctx.Input.RequestBody))
+	}
+
+	ip := c.Ctx.Input.IP()
+	utils.ApiLog.Info("uri:%s, requestBody:%s, ip:%s", c.Ctx.Input.URI(), requestBody, ip)
+}

+ 37 - 0
controllers/sys_department.go

@@ -0,0 +1,37 @@
+package controllers
+
+import (
+	"eta/eta_mini_crm/models"
+	"eta/eta_mini_crm/models/response"
+	"eta/eta_mini_crm/services"
+)
+
+type SysDepartmentController struct {
+	BaseAuthController
+}
+
+// @Title 获取部门列表
+// @Description 获取部门列表接口
+// @Success 200 {object} system.SysDepartmentListResp
+// @router /list [get]
+func (this *SysDepartmentController) List() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	list, err := services.GetSysDepartmentList()
+	if err != nil {
+		br.Msg = "获取部门列表失败"
+		br.ErrMsg = "获取部门列表失败,Err" + err.Error()
+		return
+	}
+
+	resp := new(response.SysDepartmentListResp)
+	resp.List = list
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}

+ 60 - 0
controllers/sys_role.go

@@ -0,0 +1,60 @@
+package controllers
+
+import (
+	"eta/eta_mini_crm/models"
+	"eta/eta_mini_crm/models/response"
+	"eta/eta_mini_crm/utils"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
+)
+
+type SysRoleController struct {
+	BaseAuthController
+}
+
+// List
+// @Title 系统角色列表
+// @Description 系统角色列表
+// @Param	request	body UserLoginReq true "type json string"
+// @Success 200 {object} response.SysRoleListResp
+// @router /list [get]
+func (this *SysRoleController) List() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+
+	var startSize int
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	startSize = utils.StartIndex(currentIndex, pageSize)
+
+	total, err := models.GetSysRoleListCount()
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		return
+	}
+	list, err := models.GetSysRoleList(startSize, pageSize)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		return
+	}
+	page := paging.GetPaging(currentIndex, pageSize, total)
+	resp := new(response.SysRoleListResp)
+	resp.List = list
+	resp.Paging = page
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}

+ 474 - 0
controllers/sys_user.go

@@ -0,0 +1,474 @@
+package controllers
+
+import (
+	"encoding/base64"
+	"encoding/json"
+	"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"
+	"fmt"
+	"strings"
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/rdlucklib/rdluck_tools/paging"
+)
+
+type SysUserController struct {
+	BaseAuthController
+}
+
+// Add
+// @Title 系统用户添加
+// @Description 系统用户添加
+// @Param	request	body request.UserLoginReq true "type json string"
+// @Success 200 {object} models.LoginResp
+// @router /add [post]
+func (this *SysUserController) Add() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req request.SysUserInfoReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.SysUserName == "" {
+		br.Msg = "请输入账号"
+		return
+	}
+	if req.Password == "" {
+		br.Msg = "请输入密码"
+		return
+	}
+	if req.RealName == "" {
+		br.Msg = "请输入姓名"
+		return
+	}
+	// 手机号和邮箱必填一个
+	req.Phone = strings.TrimSpace(req.Phone)
+	req.Email = strings.TrimSpace(req.Email)
+	if req.Phone == "" && req.Email == "" {
+		br.Msg = "至少输入一个手机号或邮箱"
+		return
+	}
+	if req.Phone != "" {
+		if req.AreaCode == "86" {
+			if !utils.ValidateMobileFormatat(req.Phone) {
+				br.Msg = "手机号格式有误, 请检查"
+				return
+			}
+		}
+	}
+	if req.Email != "" {
+		if !utils.ValidateEmailFormatat(req.Phone) {
+			br.Msg = "邮箱格式有误, 请检查"
+			return
+		}
+	}
+	if req.DepartmentId <= 0 {
+		br.Msg = "请选择部门"
+		return
+	}
+	_, err = models.GetSysDepartmentById(req.DepartmentId)
+	if err != nil {
+		if err == orm.ErrNoRows {
+			br.Msg = "所选部门不存在"
+			return
+		}
+		br.Msg = "获取数据失败"
+		br.ErrMsg = "获取部门数据失败,Err:" + err.Error()
+		return
+	}
+
+	_, err = models.GetSysRoleById(req.RoleId)
+	if err != nil {
+		if err == orm.ErrNoRows {
+			br.Msg = "所选角色不存在"
+			return
+		}
+		br.Msg = "获取数据失败"
+		br.ErrMsg = "获取角色数据失败,Err:" + err.Error()
+		return
+	}
+
+	// 校验系统用户的密码
+	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)
+	}
+
+	count, err := models.GetSysUserCountBySysUserName(req.SysUserName)
+	if err != nil && err != orm.ErrNoRows {
+		br.Msg = "添加用户失败,系统错误"
+		br.ErrMsg = "添加用户失败,系统错误 Err:" + err.Error()
+		return
+	}
+	if count > 0 {
+		br.Msg = "添加用户失败,用户已存在"
+		return
+	}
+	sysUser := &models.SysUser{}
+	sysUser.SysUserName = req.SysUserName
+	sysUser.SysRealName = req.RealName
+	sysUser.Password = pwd
+	sysUser.AreaCode = req.AreaCode
+	sysUser.Phone = req.Phone
+	sysUser.Email = req.Email
+	sysUser.SysDepartmentId = req.DepartmentId
+	sysUser.SysRoleId = req.RoleId
+	sysUser.Province = req.Province
+	sysUser.City = req.City
+	sysUser.IsEnabled = req.IsEnabled
+	sysUser.CreateTime = time.Now()
+	sysUser.ModifyTime = time.Now()
+	err = sysUser.Save()
+	if err != nil {
+		br.Msg = "用户添加失败"
+		br.ErrMsg = "用户添加失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.IsAddLog = true
+	br.Msg = "添加成功"
+}
+
+// Detail
+// @Title 系统用户详情信息
+// @Description 用户详情信息
+// @Param	request	body request.SysUserInfoReq true "type json string"
+// @Success 200 {object} models.LoginResp
+// @router /detail [get]
+func (this *SysUserController) Detail() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUserId, err := this.GetInt("SysUserId")
+	if err != nil {
+		br.Msg = "参数解析错误"
+		return
+	}
+	if sysUserId <= 0 {
+		br.Msg = "用户参数错误"
+		br.ErrMsg = fmt.Sprintf("用户参数错误 <%d>", sysUserId)
+		return
+	}
+	sysUser, err := models.GetSysUserById(sysUserId)
+	if err != nil {
+		br.Msg = "获取用户失败,用户已删除"
+		br.ErrMsg = "获取用户失败,用户已删除,Err" + err.Error()
+		return
+	}
+	sysUser.Password = ""
+	sysUser.SysDepartmentId = 0
+	br.Data = sysUser
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// Edit
+// @Title 系统用户编辑
+// @Description 系统用户编辑
+// @Param	request	body UserLoginReq true "type json string"
+// @Success 200 {object} models.LoginResp
+// @router /edit [post]
+func (this *SysUserController) Edit() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req request.SysUserInfoReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.SysUserName == "" {
+		br.Msg = "请输入用户名"
+		return
+	}
+	if req.SysUserId <= 0 {
+		br.Msg = "参数错误"
+		br.ErrMsg = fmt.Sprintf("参数错误,sysUserId<%d>", req.SysUserId)
+		return
+	}
+	if req.RoleId <= 0 {
+		br.Msg = "请选择角色"
+		br.ErrMsg = "角色ID小于等于0"
+		return
+	}
+
+	sysUser, err := models.GetSysUserById(req.SysUserId)
+	if err != nil {
+		if err == orm.ErrNoRows {
+			br.Msg = "用户不存在,请刷新页面"
+			return
+		}
+		br.Msg = "获取数据失败"
+		br.ErrMsg = "获取用户数据失败,Err:" + err.Error() + ";sysUserId:" + fmt.Sprint(req.SysUserId)
+		return
+	}
+	item, err := models.GetSysUserBySysUserName(req.SysUserName)
+	if err != nil && err != orm.ErrNoRows {
+		br.Msg = "获取数据失败"
+		br.ErrMsg = "获取系统用户数据失败,Err:" + err.Error() + ";sysUserName:" + req.SysUserName
+		return
+	}
+	if item != nil && item.SysUserId != req.SysUserId {
+		br.Msg = "账号名称已存在,请重新输入"
+		return
+	}
+	req.Phone = strings.TrimSpace(req.Phone)
+	req.Email = strings.TrimSpace(req.Email)
+	if req.Phone == "" && req.Email == "" {
+		br.Msg = "至少输入一个手机号或邮箱"
+		return
+	}
+	if req.Phone != "" {
+		if req.AreaCode == "86" {
+			if !utils.ValidateMobileFormatat(req.Phone) {
+				br.Msg = "手机号格式有误, 请检查"
+				return
+			}
+		}
+	}
+	if req.Email != "" {
+		if !utils.ValidateEmailFormatat(req.Email) {
+			br.Msg = "邮箱格式有误, 请检查"
+			return
+		}
+	}
+
+	var roleName string
+	roleItem, err := models.GetSysRoleById(req.RoleId)
+	if err != nil {
+		if err == orm.ErrNoRows {
+			br.Msg = "角色不存在,请重新选择"
+			br.ErrMsg = "角色不存在"
+			return
+		}
+		br.Msg = "获取数据失败"
+		br.ErrMsg = "获取角色数据失败,Err:" + err.Error()
+		return
+	}
+	if roleItem != nil {
+		roleName = roleItem.SysRoleName
+	}
+
+	sysUser.SysUserName = req.SysUserName
+	sysUser.SysRealName = req.RealName
+	sysUser.AreaCode = req.AreaCode
+	sysUser.Phone = req.Phone
+	sysUser.Email = req.Email
+	sysUser.SysRoleId = req.RoleId
+	sysUser.SysRoleName = roleName
+	sysUser.Province = req.Province
+	sysUser.City = req.City
+	sysUser.IsEnabled = req.IsEnabled
+	sysUser.ModifyTime = time.Now()
+	err = sysUser.Save()
+	if err != nil {
+		br.Msg = "编辑角色失败"
+		br.ErrMsg = "编辑角色失败,Err:" + err.Error()
+		return
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "编辑成功"
+}
+
+// List
+// @Title 系统用户列表
+// @Description 系统用户列表
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Param   DepartmentId   query   int  true       "部门ID"
+// @Success 200 {object} models.LoginResp
+// @router /list [get]
+func (this *SysUserController) List() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+
+	var startSize int
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	startSize = utils.StartIndex(currentIndex, pageSize)
+
+	total, err := models.GetSysUserCount()
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		return
+	}
+	list, err := models.GetSysUserList(startSize, pageSize)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		return
+	}
+	page := paging.GetPaging(currentIndex, pageSize, total)
+	resp := new(response.SysUserListResp)
+	resp.List = list
+	resp.Paging = page
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// ResetPass
+// @Title 重置密码
+// @Description 重置密码
+// @Param	request	body system.SysUserResetPassReq true "type json string"
+// @Success 200 编辑成功
+// @router /reset_pass [post]
+func (this *SysUserController) ResetPass() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req request.ResetPasswordReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.SysUserId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数有误,SysUserNameId"
+		return
+	}
+	req.Password = strings.TrimSpace(req.Password)
+	req.RePassword = strings.TrimSpace(req.RePassword)
+	if req.Password == "" {
+		br.Msg = "密码不能为空"
+		return
+	}
+	if req.Password != req.RePassword {
+		br.Msg = "两次密码输入不一致"
+		return
+	}
+	sysUser, err := models.GetSysUserById(req.SysUserId)
+	if err != nil {
+		if err == orm.ErrNoRows {
+			br.Msg = "用户已被删除, 请刷新页面"
+			return
+		}
+		br.Msg = "获取数据失败"
+		br.ErrMsg = "获取系统用户数据失败,Err:" + err.Error() + ";SysUserId:" + fmt.Sprint(req.SysUserId)
+		return
+	}
+	b, err := base64.StdEncoding.DecodeString(req.Password)
+	if err != nil {
+		br.Msg = "解析数据失败"
+		br.ErrMsg = "解析数据失败,Err:" + err.Error()
+		return
+	}
+	pwd := string(b)
+	if !utils.CheckPwd(pwd) {
+		br.Msg = "密码格式不对,必须包含8位及以上,包含数字、大写字母、小写字母、特殊字符中的三个类型"
+		return
+	}
+	pwd = utils.MD5(pwd)
+	sysUser.Password = pwd
+	sysUser.IsEnabled = true
+	sysUser.ModifyTime = time.Now()
+	err = sysUser.Save()
+	if err != nil {
+		br.Msg = "密码修改失败"
+		br.ErrMsg = "密码修改失败,系统错误,Err:" + err.Error()
+		return
+	}
+	br.Ret = 200
+	br.Msg = "重置密码成功"
+	br.Success = true
+
+}
+
+// @Title 开启/禁用系统用户
+// @Description 开启/禁用系统用户接口
+// @Param	request	body system.SysuserEditReq true "type json string"
+// @Success 200 操作成功
+// @router /editEnabled [post]
+func (this *SysUserController) EditEnabled() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req request.SysUserEditEnabledReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	sysUser, err := models.GetSysUserById(req.SysUserId)
+	if err != nil {
+		br.Msg = "获取数据失败"
+		br.ErrMsg = "获取系统用户数据失败,Err:" + err.Error()
+		return
+	}
+	if sysUser.SysRoleName == "admin" && sysUser.SysUserName == "admin" {
+		br.Msg = "禁止对admin使用<禁用>功能"
+		return
+	}
+	// 修改系统用户禁用状态
+	sysUser.IsEnabled = req.IsEnabled
+	err = sysUser.Update([]string{"is_enabled"})
+	if err != nil {
+		br.Msg = "修改失败"
+		br.ErrMsg = "修改系统用户数据失败,Err:" + err.Error()
+		return
+	}
+
+	//用户被禁用的情况下,需要将他对应的token给过期
+	if sysUser.IsEnabled && !req.IsEnabled {
+		services.LogoutSysUser(req.SysUserId)
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.IsAddLog = true
+	br.Msg = "操作成功"
+}

+ 111 - 0
controllers/user_login.go

@@ -0,0 +1,111 @@
+package controllers
+
+import (
+	"encoding/json"
+	"eta/eta_mini_crm/models"
+	"eta/eta_mini_crm/utils"
+	"fmt"
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type UserLoginController struct {
+	BaseCommonController
+}
+
+// Login
+// @Title 用户登录
+// @Description 用户登录
+// @Param	request	body UserLoginReq true "type json string"
+// @Success 200 {object} models.LoginResp
+// @router /login [post]
+func (this *UserLoginController) Login() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	type UserLoginReq struct {
+		UserName string `description:"账号"`
+		Password string `description:"密码"`
+		ReqTime  string `description:"登录时间戳"`
+	}
+
+	var req UserLoginReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.UserName == "" {
+		br.Msg = "请输入账号"
+		return
+	}
+	if req.Password == "" {
+		br.Msg = "请输入密码"
+		return
+	}
+	sysUser, err := models.GetSysUserBySysUserName(req.UserName)
+	if err != nil {
+		if err == orm.ErrNoRows {
+			br.Msg = "登录失败, 账号或密码错误"
+			return
+		} else {
+			br.Msg = "系统错误"
+			br.ErrMsg = "系统错误" + err.Error()
+			return
+		}
+	}
+	dbPass := utils.MD5(fmt.Sprintf("%s%s%s", sysUser.Password, utils.UserLoginSalt, req.ReqTime))
+	if req.Password != dbPass {
+		br.Msg = "登录失败, 账号或密码错误"
+		return
+	}
+	account := utils.MD5(sysUser.SysUserName)
+	token := utils.GenToken(account)
+	sysSession := new(models.SysSession)
+	sysSession.UserName = sysUser.SysUserName
+	sysSession.SysUserId = sysUser.SysUserId
+	sysSession.ExpiredTime = time.Now().AddDate(0, 0, 60)
+	sysSession.CreatedTime = time.Now()
+	sysSession.LastUpdatedTime = time.Now()
+	sysSession.AccessToken = token
+	err = sysSession.AddSysSession()
+	if err != nil {
+		br.Msg = "登录失败"
+		br.ErrMsg = "新增session信息失败, Err:" + err.Error()
+		return
+	}
+	sysRole, err := models.GetSysRoleById(sysUser.SysRoleId)
+	if err != nil {
+		br.Msg = "登录失败"
+		br.ErrMsg = "查询角色失败, Err:" + err.Error()
+		return
+	}
+	type LoginResp struct {
+		Authorization string
+		SysUserName   string `description:"系统用户名"`
+		SysRealName   string `description:"系统用户姓名"`
+		SysUserId     int    `description:"系统用户id"`
+		RoleName      string `description:"所属角色名称"`
+		RoleId        int    `description:"所属角色id"`
+	}
+	resp := new(LoginResp)
+	resp.Authorization = "authorization=" + token
+	resp.SysUserName = sysUser.SysUserName
+	resp.SysRealName = sysUser.SysRealName
+	resp.SysUserId = sysUser.SysUserId
+	resp.RoleName = sysRole.SysRoleName
+	resp.RoleId = sysUser.SysRoleId
+
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "登录成功"
+}

+ 228 - 0
go.sum

@@ -0,0 +1,228 @@
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
+github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
+github.com/astaxie/beego v1.12.3/go.mod h1:p3qIm0Ryx7zeBHLljmd7omloyca1s4yu1a8kM1FkpIA=
+github.com/beego/bee/v2 v2.1.0 h1:4WngbAnkvVOyKy74WXcRH3clon76wkjhuzrV2mx2fQU=
+github.com/beego/bee/v2 v2.1.0/go.mod h1:wDhKy5TNxv46LHKsK2gyxo38ObCOm9PbCN89lWHK3EU=
+github.com/beego/beego/v2 v2.1.0 h1:Lk0FtQGvDQCx5V5yEu4XwDsIgt+QOlNjt5emUa3/ZmA=
+github.com/beego/beego/v2 v2.1.0/go.mod h1:6h36ISpaxNrrpJ27siTpXBG8d/Icjzsc7pU1bWpp0EE=
+github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
+github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
+github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
+github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
+github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
+github.com/couchbase/go-couchbase v0.0.0-20200519150804-63f3cdb75e0d/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U=
+github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
+github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
+github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI=
+github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
+github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw=
+github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/garyburd/redigo v1.6.3/go.mod h1:rTb6epsqigu3kYKBnaF028A7Tf/Aw5s0cqA47doKKqw=
+github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
+github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
+github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
+github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
+github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ=
+github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/lib/pq v1.10.5 h1:J+gdV2cUmX7ZqL2B0lFcW0m+egaHC2V3lpO8nWxyYiQ=
+github.com/lib/pq v1.10.5/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/mattn/go-sqlite3 v1.14.7 h1:fxWBnXkxfM6sRiuH3bqJ4CfzZojMOLVc0UTsTglEghA=
+github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
+github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
+github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
+github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
+github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
+github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI=
+github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
+github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
+github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
+github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
+github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
+github.com/rdlucklib/rdluck_tools v1.0.3 h1:iOtK2QPlPQ6CL6c1htCk5VnFCHzyG6DCfJtunrMswK0=
+github.com/rdlucklib/rdluck_tools v1.0.3/go.mod h1:9Onw9o4w19C8KE5lxb8GyxgRBbZweRVkQSc79v38EaA=
+github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
+github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
+github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
+github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 h1:DAYUYH5869yV94zvCES9F51oYtN5oGlwjxJJz7ZCnik=
+github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
+github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
+github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s=
+github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
+github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
+github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
+github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
+github.com/ylywyn/jpush-api-go-client v0.0.0-20190906031852-8c4466c6e369/go.mod h1:Nv7wKD2/bCdKUFNKcJRa99a+1+aSLlCRJFriFYdjz/I=
+github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
+golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
+golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
+google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
+gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

+ 16 - 0
models/base.go

@@ -0,0 +1,16 @@
+package models
+
+type BaseResponse struct {
+	Ret         int
+	Msg         string
+	ErrMsg      string
+	ErrCode     string
+	Data        interface{}
+	Success     bool `description:"true 执行成功,false 执行失败"`
+	IsSendEmail bool `json:"-" description:"true 发送邮件,false 不发送邮件"`
+	IsAddLog    bool `json:"-" description:"true 新增操作日志,false 不新增操作日志" `
+}
+
+func (r *BaseResponse) Init() *BaseResponse {
+	return &BaseResponse{Ret: 403, IsSendEmail: true}
+}

+ 37 - 0
models/db.go

@@ -0,0 +1,37 @@
+package models
+
+import (
+	"eta/eta_mini_crm/utils"
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+)
+
+func init() {
+	_ = orm.RegisterDataBase("rddp", "mysql", utils.MYSQL_URL_RDDP)
+	orm.SetMaxIdleConns("rddp", 50)
+	orm.SetMaxOpenConns("rddp", 100)
+
+	report_db, _ := orm.GetDB("rddp")
+	report_db.SetConnMaxLifetime(10 * time.Minute)
+
+	_ = orm.RegisterDataBase("master", "mysql", utils.MYSQL_URL_MASTER)
+	orm.SetMaxIdleConns("master", 50)
+	orm.SetMaxOpenConns("master", 100)
+
+	master_db, _ := orm.GetDB("master")
+	master_db.SetConnMaxLifetime(10 * time.Minute)
+
+	orm.Debug = true
+	orm.DebugLog = orm.NewLog(utils.BinLog)
+
+	orm.RegisterModel(
+		new(SysSession),
+		new(SysRole),
+		new(SysUser),
+		new(SysDepartment),
+		new(SysMenu),
+		new(SysRoleMenuMapping),
+	)
+}

+ 27 - 0
models/request/sys_user.go

@@ -0,0 +1,27 @@
+package request
+
+type SysUserInfoReq struct {
+	SysUserId    int    `description:"id"`
+	SysUserName  string `description:"账号"`
+	Password     string `description:"密码"`
+	RealName     string `description:"姓名"`
+	Phone        string `description:"手机号"`
+	AreaCode     string `description:"区号"`
+	DepartmentId int    `description:"部门id"`
+	Email        string `description:"邮箱"`
+	RoleId       int    `description:"角色id"`
+	Province     string `description:"省"`
+	City         string `description:"市"`
+	IsEnabled    bool   `description:"是否启用"`
+}
+
+type ResetPasswordReq struct {
+	SysUserId  int    `description:"用户id"`
+	Password   string `description:"密码"`
+	RePassword string `description:"重复密码"`
+}
+
+type SysUserEditEnabledReq struct {
+	SysUserId int  `description:"用户id"`
+	IsEnabled bool `description:"是否启用"`
+}

+ 7 - 0
models/response/sys_department.go

@@ -0,0 +1,7 @@
+package response
+
+import "eta/eta_mini_crm/models"
+
+type SysDepartmentListResp struct {
+	List []*models.SysDepartmentList
+}

+ 12 - 0
models/response/sys_role.go

@@ -0,0 +1,12 @@
+package response
+
+import (
+	"eta/eta_mini_crm/models"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
+)
+
+type SysRoleListResp struct {
+	List   []*models.SysRole
+	Paging *paging.PagingItem `description:"分页数据"`
+}

+ 12 - 0
models/response/sys_user.go

@@ -0,0 +1,12 @@
+package response
+
+import (
+	"eta/eta_mini_crm/models"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
+)
+
+type SysUserListResp struct {
+	List   []*models.SysUser
+	Paging *paging.PagingItem `description:"分页数据"`
+}

+ 49 - 0
models/sys_department.go

@@ -0,0 +1,49 @@
+package models
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type SysDepartment struct {
+	SysDepartmentId   int    `description:"部门id"`
+	SysDepartmentName string `description:"部门名称"`
+	Sort              int    `description:"排序"`
+	Level             int    `description:"层级"`
+	ParentId          int    `description:"父目录id"`
+}
+
+type SysDepartmentList struct {
+	SysDepartmentId   int                  `description:"部门id"`
+	SysDepartmentName string               `description:"部门名称"`
+	Child             []*SysDepartmentList `description:"分组"`
+	Level             int                  `description:"1:部门, 2|3:分组"`
+	ParentId          int                  `description:"父目录id"`
+}
+
+func GetSysDepartmentById(sysDepartmentId int) (item *SysDepartment, err error) {
+	o := orm.NewOrmUsingDB("master")
+	sql := `SELECT * FROM sys_department WHERE sys_department_id=? `
+	err = o.Raw(sql, sysDepartmentId).QueryRow(&item)
+	return
+}
+
+func GetSysDepartmentListByLevel(level int) (items []*SysDepartmentList, err error) {
+	o := orm.NewOrmUsingDB("master")
+	sql := `SELECT * FROM sys_department WHERE level=? ORDER BY sort`
+	_, err = o.Raw(sql, level).QueryRows(&items)
+	return
+}
+
+func GetSysDepartmentListByParentId(parentId int) (item SysDepartmentList, err error) {
+	o := orm.NewOrmUsingDB("master")
+	sql := `SELECT * FROM sys_department WHERE sys_department_id=? `
+	err = o.Raw(sql, parentId).QueryRow(&item)
+	return
+}
+
+func GetChildSysDepartmentListById(sysDepartmentId int) (items []*SysDepartmentList, err error) {
+	o := orm.NewOrmUsingDB("master")
+	sql := `SELECT * FROM sys_department WHERE parent_id=? `
+	_, err = o.Raw(sql, sysDepartmentId).QueryRows(&items)
+	return
+}

+ 47 - 0
models/sys_role.go

@@ -0,0 +1,47 @@
+package models
+
+import (
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type SysRole struct {
+	SysRoleId   int       `description:"角色id"`
+	SysRoleName string    `description:"姓名"`
+	CreateTime  time.Time `description:"创建时间"`
+	ModifyTime  time.Time `description:"更新时间"`
+}
+
+func (s *SysRole) Save() (err error) {
+	o := orm.NewOrmUsingDB("master")
+	_, err = o.InsertOrUpdate(s)
+	return
+}
+
+func GetSysRoleById(id int) (item *SysRole, err error) {
+	o := orm.NewOrmUsingDB("master")
+	sql := `SELECT * FROM sys_role WHERE sys_role_id=?`
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+func GetSysRoleListCount() (count int, err error) {
+	o := orm.NewOrmUsingDB("master")
+	sql := `SELECT COUNT(1) AS count FROM sys_role `
+	err = o.Raw(sql).QueryRow(&count)
+	return
+}
+
+func GetSysRoleList(startSize, pageSize int) (items []*SysRole, err error) {
+	o := orm.NewOrmUsingDB("master")
+	sql := `SELECT * FROM sys_role ORDER BY modify_time DESC LIMIT ?,?`
+	_, err = o.Raw(sql, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+type SysMenu struct {
+}
+
+type SysRoleMenuMapping struct {
+}

+ 38 - 0
models/sys_session.go

@@ -0,0 +1,38 @@
+package models
+
+import (
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type SysSession struct {
+	SysSessionId    int `orm:"pk"`
+	SysUserId       int
+	UserName        string
+	AccessToken     string
+	ExpiredTime     time.Time
+	CreatedTime     time.Time
+	LastUpdatedTime time.Time
+}
+
+func (s *SysSession) AddSysSession() (err error) {
+	o := orm.NewOrmUsingDB("master")
+	_, err = o.Insert(s)
+	return
+}
+
+func GetSysSessionByToken(token string) (item *SysSession, err error) {
+	sql := `SELECT * FROM sys_session WHERE access_token=? AND expired_time> NOW() ORDER BY expired_time DESC LIMIT 1 `
+	o := orm.NewOrmUsingDB("master")
+	err = o.Raw(sql, token).QueryRow(&item)
+	return
+}
+
+// ExpiredSysSessionBySysUserId 过期掉用户token
+func ExpiredSysSessionBySysUserId(sysUserId int) (err error) {
+	sql := `UPDATE sys_session SET expired_time = NOW()  WHERE sys_user_id=? `
+	o := orm.NewOrmUsingDB("master")
+	_, err = o.Raw(sql, sysUserId).Exec()
+	return
+}

+ 73 - 0
models/sys_user.go

@@ -0,0 +1,73 @@
+package models
+
+import (
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type SysUser struct {
+	SysUserId         int       `orm:"pk" description:"系统用户id"`
+	SysUserName       string    `description:"账号"`
+	SysRealName       string    `description:"姓名"`
+	Password          string    `description:"密码"`
+	Email             string    `description:"邮箱"`
+	Phone             string    `description:"手机号"`
+	AreaCode          string    `description:"手机区号"`
+	SysRoleId         int       `description:"角色id"`
+	SysRoleName       string    `description:"角色名称"`
+	SysDepartmentId   int       `description:"所属部门id"`
+	SysDepartmentName string    `description:"所属部门全路径"`
+	Province          string    `description:"省"`
+	City              string    `description:"市"`
+	IsEnabled         bool      `description:"是否启用"`
+	CreateTime        time.Time `description:"创建时间"`
+	ModifyTime        time.Time `description:"更新时间"`
+}
+
+func (s *SysUser) Save() (err error) {
+	o := orm.NewOrmUsingDB("master")
+	_, err = o.InsertOrUpdate(s, "sys_user_id")
+	return
+}
+
+func (s *SysUser) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("master")
+	_, err = o.Update(s, cols...)
+	return
+}
+
+func GetSysUserBySysUserName(sysUserName string) (item *SysUser, err error) {
+	sql := `SELECT * FROM sys_user WHERE sys_user_name=?`
+	o := orm.NewOrmUsingDB("master")
+	err = o.Raw(sql, sysUserName).QueryRow(&item)
+	return
+}
+
+func GetSysUserById(sysUserId int) (item *SysUser, err error) {
+	sql := `SELECT * FROM sys_user WHERE sys_user_id=?`
+	o := orm.NewOrmUsingDB("master")
+	err = o.Raw(sql, sysUserId).QueryRow(&item)
+	return
+}
+
+func GetSysUserCountBySysUserName(sysUserName string) (count int, err error) {
+	sql := `SELECT COUNT(1) AS count FROM sys_user WHERE sys_user_name=?`
+	o := orm.NewOrmUsingDB("master")
+	err = o.Raw(sql, sysUserName).QueryRow(&count)
+	return
+}
+
+func GetSysUserCount() (count int, err error) {
+	sql := `SELECT COUNT(1) AS count FROM sys_user`
+	o := orm.NewOrmUsingDB("master")
+	err = o.Raw(sql).QueryRow(&count)
+	return
+}
+
+func GetSysUserList(startSize, pageSize int) (items []*SysUser, err error) {
+	sql := `SELECT * FROM sys_user ORDER BY modify_time DESC LIMIT ?,?`
+	o := orm.NewOrmUsingDB("master")
+	_, err = o.Raw(sql, startSize, pageSize).QueryRows(&items)
+	return
+}

+ 91 - 0
routers/commentsRouter.go

@@ -0,0 +1,91 @@
+package routers
+
+import (
+	beego "github.com/beego/beego/v2/server/web"
+	"github.com/beego/beego/v2/server/web/context/param"
+)
+
+func init() {
+
+    beego.GlobalControllerRouter["eta/eta_mini_crm/controllers:SysDepartmentController"] = append(beego.GlobalControllerRouter["eta/eta_mini_crm/controllers:SysDepartmentController"],
+        beego.ControllerComments{
+            Method: "List",
+            Router: `/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: "List",
+            Router: `/list`,
+            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",
+            Router: `/add`,
+            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: "Detail",
+            Router: `/detail`,
+            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: "Edit",
+            Router: `/edit`,
+            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: "EditEnabled",
+            Router: `/editEnabled`,
+            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: "List",
+            Router: `/list`,
+            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: "ResetPass",
+            Router: `/reset_pass`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mini_crm/controllers:UserLoginController"] = append(beego.GlobalControllerRouter["eta/eta_mini_crm/controllers:UserLoginController"],
+        beego.ControllerComments{
+            Method: "Login",
+            Router: `/login`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+}

+ 47 - 0
services/sys_department.go

@@ -0,0 +1,47 @@
+package services
+
+import (
+	"eta/eta_mini_crm/models"
+)
+
+func GetSysDepartmentPathById(sysDepartmentId int) (path string, err error) {
+	sysDepartment, err := models.GetSysDepartmentById(sysDepartmentId)
+	if err != nil {
+		return
+	}
+
+	path = sysDepartment.SysDepartmentName
+	curSysDepartmentId := sysDepartmentId
+	for curLevel := sysDepartment.Level; curLevel >= 1; curLevel-- {
+		nextSysDepartment, er := models.GetSysDepartmentListByParentId(curSysDepartmentId)
+		if er != nil {
+			return
+		}
+		curSysDepartmentId = nextSysDepartment.SysDepartmentId
+		path = nextSysDepartment.SysDepartmentName + "/" + path
+	}
+	return
+}
+
+func GetSysDepartmentList() ([]*models.SysDepartmentList, error) {
+	departmentList, err := models.GetSysDepartmentListByLevel(1)
+	if err != nil {
+		return nil, err
+	}
+	for _, dep := range departmentList {
+		childDepartmentList, err := models.GetChildSysDepartmentListById(dep.SysDepartmentId)
+		if err != nil {
+			return nil, err
+		}
+		dep.Child = childDepartmentList
+		for _, cdep := range childDepartmentList {
+			subDepartmentList, err := models.GetChildSysDepartmentListById(cdep.SysDepartmentId)
+			if err != nil {
+				return nil, err
+			}
+			cdep.Child = subDepartmentList
+		}
+	}
+	return departmentList, nil
+
+}

+ 8 - 0
services/sys_session.go

@@ -0,0 +1,8 @@
+package services
+
+import "eta/eta_mini_crm/models"
+
+func LogoutSysUser(sysUserId int) (err error) {
+	err = models.ExpiredSysSessionBySysUserId(sysUserId)
+	return
+}

+ 39 - 0
utils/common.go

@@ -0,0 +1,39 @@
+package utils
+
+import (
+	"crypto/md5"
+	"encoding/hex"
+	"regexp"
+)
+
+func MD5(data string) string {
+	m := md5.Sum([]byte(data))
+	return hex.EncodeToString(m[:])
+}
+
+func CheckPwd(pwd string) bool {
+	compile := `([0-9a-z]+){6,12}|(a-z0-9]+){6,12}`
+	reg := regexp.MustCompile(compile)
+	flag := reg.MatchString(pwd)
+	return flag
+}
+
+// 校验邮箱格式
+func ValidateEmailFormatat(email string) bool {
+	reg := regexp.MustCompile(RegularEmail)
+	return reg.MatchString(email)
+}
+
+// 验证是否是手机号
+func ValidateMobileFormatat(mobileNum string) bool {
+	reg := regexp.MustCompile(RegularMobile)
+	return reg.MatchString(mobileNum)
+}
+
+// 计算分页起始页
+func StartIndex(page, pagesize int) int {
+	if page > 1 {
+		return (page - 1) * pagesize
+	}
+	return 0
+}

+ 43 - 0
utils/config.go

@@ -0,0 +1,43 @@
+package utils
+
+import (
+	"fmt"
+
+	beeLogger "github.com/beego/bee/v2/logger"
+	"github.com/beego/beego/v2/server/web"
+)
+
+// 数据库配置
+var (
+	RunMode          string
+	MYSQL_URL_MASTER string
+	MYSQL_URL_RDDP   string
+)
+
+var (
+	ApiLogPath string // 接口请求地址和接口返回值日志存放地址
+	ApiLogFile string
+	BinLogPath string // 数据库相关的日志存放地址
+	BinLogFile string
+	LogMaxDays int // 日志最大保留天数
+)
+
+var DesKey string // 接口返回加密KEY
+
+func init() {
+	tmpRunMode, err := web.AppConfig.String("run_mode")
+	if err != nil {
+		panic(any("配置文件读取run_mode错误 " + err.Error()))
+	}
+	RunMode = tmpRunMode
+	fmt.Println("RunMode:", RunMode)
+
+	config, err := web.AppConfig.GetSection(RunMode)
+	if err != nil {
+		panic(any("配置文件读取错误 " + err.Error()))
+	}
+	beeLogger.Log.Info(RunMode + " 模式")
+	MYSQL_URL_RDDP = config["mysql_url_rddp"]
+	MYSQL_URL_MASTER = config["mysql_url_master"]
+
+}

+ 14 - 0
utils/constants.go

@@ -0,0 +1,14 @@
+package utils
+
+const (
+	UserLoginSalt = "MiQM9YUdf89T2uIH"         // 用户登录盐值
+	DesKeySalt    = "MxuqSoUrTAmyRd9fb0TtlrPk" // DesKey盐值
+)
+
+const PageSize20 = 20
+
+// 手机号,电子邮箱正则
+const (
+	RegularMobile = "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0-9])|(17[0-9])|(16[0-9])|(19[0-9]))\\d{8}$" //手机号码
+	RegularEmail  = `\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*`                                             //匹配电子邮箱
+)

+ 37 - 0
utils/des3.go

@@ -0,0 +1,37 @@
+package utils
+
+import (
+	"bytes"
+	"crypto/cipher"
+	"crypto/des"
+	"encoding/base64"
+)
+
+// des3 + base64 encrypt
+func DesBase64Encrypt(origData []byte, desKey string) []byte {
+	result, err := TripleDesEncrypt(origData, []byte(desKey))
+	if err != nil {
+		panic(any(err))
+	}
+	return []byte(base64.StdEncoding.EncodeToString(result))
+}
+
+// 3DES加密
+func TripleDesEncrypt(origData, key []byte) ([]byte, error) {
+	block, err := des.NewTripleDESCipher(key)
+	if err != nil {
+		return nil, err
+	}
+	origData = PKCS5Padding(origData, block.BlockSize())
+	// origData = ZeroPadding(origData, block.BlockSize())
+	blockMode := cipher.NewCBCEncrypter(block, key[:8])
+	crypted := make([]byte, len(origData))
+	blockMode.CryptBlocks(crypted, origData)
+	return crypted, nil
+}
+
+func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
+	padding := blockSize - len(ciphertext)%blockSize
+	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
+	return append(ciphertext, padtext...)
+}

+ 44 - 0
utils/jwt.go

@@ -0,0 +1,44 @@
+package utils
+
+import (
+	"fmt"
+	"time"
+
+	"github.com/beego/beego/v2/core/logs"
+	"github.com/dgrijalva/jwt-go"
+)
+
+var (
+	KEY = []byte("5McoGDMb5y")
+)
+
+func GenToken(account string) string {
+	token := jwt.New(jwt.SigningMethodHS256)
+	token.Claims = &jwt.StandardClaims{
+		NotBefore: int64(time.Now().Unix()) - int64(1*time.Second),
+		ExpiresAt: int64(time.Now().Unix() + 60*24*60*60),
+		Issuer:    "eta_mini_crm",
+		Subject:   account,
+	}
+	ss, err := token.SignedString(KEY)
+	if err != nil {
+		logs.Error(err)
+		return ""
+	}
+	return ss
+}
+
+// 校验token
+func CheckToken(account, token string) bool {
+	t, err := jwt.Parse(token, func(*jwt.Token) (interface{}, error) {
+		return KEY, nil
+	})
+	if err != nil {
+		fmt.Println(err.Error())
+		return false
+	}
+	if account != t.Claims.(jwt.MapClaims)["sub"] {
+		return false
+	}
+	return t.Valid
+}

+ 90 - 0
utils/logs.go

@@ -0,0 +1,90 @@
+package utils
+
+import (
+	"encoding/json"
+	"os"
+	"path"
+
+	"github.com/beego/beego/v2/core/logs"
+)
+
+const (
+	DefaultBinlogPath = "./etalogs/binlog"
+	DefaultApiLogPath = "./etalogs/apilog"
+)
+
+var (
+	BinLog *logs.BeeLogger
+	ApiLog *logs.BeeLogger
+)
+
+func init() {
+	initApiLog()
+	initBinLog()
+}
+
+// 初始化apilog日志
+func initApiLog() {
+	apilogPath := ApiLogPath
+	if apilogPath == "" {
+		apilogPath = DefaultApiLogPath
+	}
+	apilogFile := ApiLogFile
+	if apilogFile == "" {
+		apilogFile = "apilog.log"
+	}
+	os.MkdirAll(apilogPath, os.ModePerm)
+	logFileName := path.Join(apilogPath, apilogFile)
+	ApiLog = logs.NewLogger(1000000)
+	logConf := getDefaultLogConfig()
+	logConf.FileName = logFileName
+
+	b, _ := json.Marshal(logConf)
+	ApiLog.SetLogger(logs.AdapterFile, string(b))
+	ApiLog.EnableFuncCallDepth(true)
+}
+
+// 初始化binlog日志
+func initBinLog() {
+	binlogPath := BinLogPath
+	if binlogPath == "" {
+		binlogPath = DefaultBinlogPath
+	}
+	binlogFile := BinLogFile
+	if binlogFile == "" {
+		binlogFile = "binlog.log"
+	}
+	os.MkdirAll(binlogPath, os.ModePerm)
+	logFileName := path.Join(binlogPath, binlogFile)
+	BinLog = logs.NewLogger(1000000)
+	logConf := getDefaultLogConfig()
+	logConf.FileName = logFileName
+
+	b, _ := json.Marshal(logConf)
+	BinLog.SetLogger(logs.AdapterFile, string(b))
+	BinLog.EnableFuncCallDepth(true)
+}
+
+type logConfig struct {
+	FileName string `json:"filename" description:"保存的文件名"`
+	MaxLines int    `json:"maxlines"  description:"每个文件保存的最大行数,默认值 1000000"`
+	MaxSize  int    `json:"maxsize" description:"每个文件保存的最大尺寸,默认值是 1 << 28, //256 MB"`
+	Daily    bool   `json:"daily" description:"是否按照每天 logrotate,默认是 true"`
+	MaxDays  int    `json:"maxdays" description:"文件最多保存多少天,默认保存 7 天"`
+	Rotate   bool   `json:"rotate" description:"是否开启 logrotate,默认是 true"`
+	Level    int    `json:"level" description:"日志保存的时候的级别,默认是 Trace 级别"`
+	Color    bool   `json:"color" description:"日志是否输出颜色"`
+}
+
+func getDefaultLogConfig() logConfig {
+	return logConfig{
+		FileName: "",
+		MaxLines: 10000000,
+		MaxSize:  1 << 28,
+		Daily:    true,
+		MaxDays:  LogMaxDays,
+		Rotate:   true,
+		Level:    logs.LevelTrace,
+		//Perm:     "",
+	}
+}