【Go】基于GoFiber从零开始搭建一个GoWeb后台管理系统(六)字典管理、安全设置模块

7 篇文章 0 订阅

欸嘿,窝又来辣😁昨天没时间更新,今天补上😊


查看前几篇内容:

第一篇:【Go】基于GoFiber从零开始搭建一个GoWeb后台管理系统(一)搭建项目

第二篇:【Go】基于GoFiber从零开始搭建一个GoWeb后台管理系统(二)日志输出中间件、校验token中间件、配置路由、基础工具函数。

第三篇:【Go】基于GoFiber从零开始搭建一个GoWeb后台管理系统(三)日志管理(登录日志、操作日志)、用户登录模块

第四篇:【Go】基于GoFiber从零开始搭建一个GoWeb后台管理系统(四)用户管理、部门管理模块

第五篇:【Go】基于GoFiber从零开始搭建一个GoWeb后台管理系统(五)角色管理、菜单管理模块


这篇是这个后台管理系统的最后一篇了(也有可能不是,可能后续还会有补充)

字典管理

在这里插入图片描述

这个模块有两个接口:hasDictByName、hasDictByCode 不是必须的,大家可以根据自己喜欢或需求决定用不用。

controller层:sys_dict.go

package sys

import (
	"github.com/gofiber/fiber/v2"
	"github.com/mozillazg/go-pinyin"
	"go-web2/app/common/config"
	"go-web2/app/common/util"
	"go-web2/app/model/sys"
	"strings"
)

type DictController struct{}

// 字典类型列表
func (DictController) GetTypeList(c *fiber.Ctx) error {
	dict := sys.SysDict{}
	dict.DictName = c.Query("name")
	return c.Status(200).JSON(config.Success(dict.GetTypeList()))
}

// 字段项列表分页
func (DictController) GetPage(c *fiber.Ctx) error {
	dict := sys.SysDict{}
	dict.DictCode = c.Query("code")
	dict.DictName = c.Query("name")
	dict.ParentId = c.Query("parentId")
	pageSize := c.QueryInt("pageSize", 10)
	pageNum := c.QueryInt("pageNum", 1)
	return c.Status(200).JSON(config.Success(dict.GetPage(pageSize, pageNum)))
}

// 根据id获取字典
func (DictController) GetById(c *fiber.Ctx) error {
	dict := sys.SysDict{}
	dict.Id = c.Params("id")
	dict.GetById()
	return c.Status(200).JSON(config.Success(dict))
}

// 生成字典代码
func (DictController) CreateCode(c *fiber.Ctx) error {
	dictName := c.Query("dictName")
	p := pinyin.NewArgs()
	p.Style = pinyin.FirstLetter
	dictCode := util.ConvertToPinyin(dictName, p)
	return c.Status(200).JSON(config.Success(dictCode))
}

// 字典名称是否存在
func (DictController) HasByName(c *fiber.Ctx) error {
	dict := sys.SysDict{}
	dict.Id = c.Query("id")
	dict.DictName = c.Query("dictName")
	flag := dict.HasDictByNameAndCode()
	result := map[string]any{}
	result["isRepeat"] = flag
	if flag {
		dictName := dict.CreateNameOrCode()
		p := pinyin.NewArgs()
		p.Style = pinyin.FirstLetter
		dictCode := util.ConvertToPinyin(dictName, p)
		result["dictName"] = dictName
		result["dictCode"] = dictCode
	}
	return c.Status(200).JSON(config.Success(result))
}

// 字典代码是否存在
func (DictController) HasByCode(c *fiber.Ctx) error {
	dict := sys.SysDict{}
	dict.Id = c.Query("id")
	dict.DictCode = c.Query("dictCode")
	flag := dict.HasDictByNameAndCode()
	result := map[string]any{}
	result["isRepeat"] = flag
	if flag {
		dictCode := dict.CreateNameOrCode()
		result["dictCode"] = dictCode
	}
	return c.Status(200).JSON(config.Success(result))
}

// 新增字典
func (DictController) Insert(c *fiber.Ctx) error {
	dict := sys.SysDict{}
	if err := c.BodyParser(&dict); err != nil {
		return c.Status(200).JSON(config.Error(err.Error()))
	}
	err := dict.Insert()
	if err != nil {
		return c.Status(200).JSON(config.Error(err.Error()))
	}
	return c.Status(200).JSON(config.Success(nil))
}

// 修改字典
func (DictController) Update(c *fiber.Ctx) error {
	dict := sys.SysDict{}
	if err := c.BodyParser(&dict); err != nil {
		return c.Status(200).JSON(config.Error(err.Error()))
	}
	err := dict.Update()
	if err != nil {
		return c.Status(200).JSON(config.Error(err.Error()))
	}
	return c.Status(200).JSON(config.Success(nil))
}

// 删除字典类型
func (DictController) DeleteType(c *fiber.Ctx) error {
	dict := sys.SysDict{}
	dict.Id = c.Params("id")
	if err := dict.DeleteType(); err != nil {
		return c.Status(200).JSON(config.Error(err.Error()))
	}
	return c.Status(200).JSON(config.Success(nil))
}

// 删除字典
func (DictController) Delete(c *fiber.Ctx) error {
	dict := sys.SysDict{}
	if err := c.BodyParser(&dict); err != nil {
		return c.Status(200).JSON(config.Error(err.Error()))
	}
	ids := strings.Split(dict.Id, ",")
	if err := dict.Delete(ids); err != nil {
		return c.Status(200).JSON(config.Error(err.Error()))
	}
	return c.Status(200).JSON(config.Success(nil))
}

// 根据字典类型代码获取字典项列表
func (DictController) GetByTypeCode(c *fiber.Ctx) error {
	dict := sys.SysDict{}
	dict.DictCode = c.Query("dictCode")
	return c.Status(200).JSON(config.Success(dict.GetSelectList()))
}

model层:sys_dict.go

package sys

import (
	"fmt"
	"github.com/google/uuid"
	"github.com/pkg/errors"
	"go-web2/app/common/config"
	"strconv"
	"strings"
	"time"
)

// 字典管理
type SysDict struct {
	config.BaseModel
	ParentId  string    `json:"parentId" form:"parentId"`   // 上级id
	DictName  string    `json:"dictName" form:"dictName"`   // 字典名称
	DictCode  string    `json:"dictCode" form:"dictCode"`   // 字典代码
	DictValue string    `json:"dictValue" form:"dictValue"` // 字典值
	Sort      int       `json:"sort" form:"sort"`           // 排序
	IsType    int       `json:"isType" form:"isType"`       // 是否是字典类型(1 字典类型 2 字典项)
	Remark    string    `json:"remark" form:"remark"`       // 备注
	Children  []SysDict `gorm:"-" json:"children"`          // 子级数据
}

// 获取表名
func (SysDict) TableName() string {
	return "sys_dict"
}

// 字典类型列表
func (e *SysDict) GetTypeList() []SysDict {
	var list []SysDict
	query := config.DB.Table(e.TableName())
	query.Where("is_type = 1")
	if e.DictName != "" {
		query.Where("dict_name like ?", fmt.Sprintf("%%%s%%", e.DictName))
	}
	query.Debug().Order("parent_id,sort asc").Find(&list)
	return buildDictTree(list, "ROOT")
}

// 列表
func (e *SysDict) GetPage(pageSize int, pageNum int) config.PageInfo {
	var list []SysDict // 查询结果
	var total int64    // 总数
	query := config.DB.Table(e.TableName())
	query.Where("is_type = 2")
	if e.DictName != "" {
		query.Where("dict_name like ?", fmt.Sprintf("%%%s%%", e.DictName))
	}
	if e.DictCode != "" {
		query.Where("dict_code like ?", fmt.Sprintf("%%%s%%", e.DictCode))
	}
	if e.ParentId != "" {
		query.Where("parent_id = ?", e.ParentId)
	}
	offset := (pageNum - 1) * pageSize                                                   // 计算跳过的记录数
	query.Debug().Order("parent_id,sort asc").Offset(offset).Limit(pageSize).Find(&list) // 分页查询,根据offset和limit来查询
	query.Count(&total)
	return config.PageInfo{list, total}
}

// 获取详情
func (e *SysDict) GetById() {
	config.DB.Table(e.TableName()).Where("id = ?", e.Id).Find(e)
}

// 详情
func (e *SysDict) HasDictByNameAndCode() bool {
	var count int64
	query := config.DB.Table(e.TableName())
	if e.Id != "" {
		query.Where("id <> ?", e.Id)
	}
	if e.DictName != "" {
		query.Where("dict_name = ?", e.DictName)
	}
	if e.DictCode != "" {
		query.Where("dict_code = ?", e.DictCode)
	}
	query.Count(&count)
	return count > 0
}

// 生成字典名称或字典代码
func (e *SysDict) CreateNameOrCode() string {
	index := -1
	str := ""
	if e.DictName != "" {
		str = e.DictName
	}
	if e.DictCode != "" {
		str = e.DictCode
	}
	index = strings.LastIndex(str, "_")
	if index != -1 {
		str = str[:index] // 截取从索引0到索引index的子串(包括索引0,不包括索引index)
	}
	return e.rightLikeNameOrCode(str)
}

// 字典名称或代码右模糊匹配
func (e *SysDict) rightLikeNameOrCode(str string) string {
	var list []SysDict
	query := config.DB.Table(SysDict{}.TableName())
	if e.DictName != "" {
		query.Where("dict_name LIKE ?", fmt.Sprintf("%s%%", str)) // 右模糊查询
	}
	if e.DictCode != "" {
		query.Where("dict_code LIKE ?", fmt.Sprintf("%s%%", str)) // 右模糊查询
	}
	query.Debug().Order("create_time desc").Find(&list) // 根据创建时间倒序,查询最新的那一个
	if len(list) > 0 {
		dict := ""
		if e.DictName != "" {
			dict = list[0].DictName
		}
		if e.DictCode != "" {
			dict = list[0].DictCode
		}
		strIndex := strings.LastIndex(dict, "_")
		if strIndex != -1 {
			dict = dict[strIndex+1:] // 截取从索引strIndex+1到字符串末尾的子串(包括索引strIndex+1)
			i, err := strconv.ParseInt(dict, 10, 64)
			if err == nil {
				str = str + "_" + fmt.Sprintf("%d", (i+1))
			} else {
				str = str + "_1"
			}
		} else {
			str = str + "_1"
		}
	}
	return str
}

// 新增
func (e *SysDict) Insert() (err error) {
	query := config.DB.Table(e.TableName())
	// 如果字典名称已存在,不提示重复,直接生成新的字典名称
	if checkDictNameAndCode(e.DictName, "", "") {
		dict := SysDict{}
		dict.DictName = e.DictName
		name := dict.CreateNameOrCode()
		e.DictName = name
	}
	// 如果字典代码已存在,不提示重复,直接生成新的字典代码
	if checkDictNameAndCode("", e.DictCode, "") {
		dict := SysDict{}
		dict.DictCode = e.DictCode
		code := dict.CreateNameOrCode()
		e.DictCode = code
	}
	if e.ParentId == "0" {
		e.ParentId = "ROOT"
	}
	e.Id = strings.ReplaceAll(uuid.NewString(), "-", "")
	e.CreateTime = time.Now()
	query.Create(e)
	return
}

// 修改
func (e *SysDict) Update() (err error) {
	// 如果字典名称已存在,不提示重复,直接生成新的字典名称
	if checkDictNameAndCode(e.DictName, "", e.Id) {
		dict := SysDict{}
		dict.DictName = e.DictName
		name := dict.CreateNameOrCode()
		e.DictName = name
	}
	// 如果字典代码已存在,不提示重复,直接生成新的字典代码
	if checkDictNameAndCode("", e.DictCode, e.Id) {
		dict := SysDict{}
		dict.DictCode = e.DictCode
		code := dict.CreateNameOrCode()
		e.DictCode = code
	}
	config.DB.Model(&SysDict{}).Omit("id", "create_time").Where("id = ?", e.Id).Save(e)
	return
}

// 删除字典类型
func (e *SysDict) DeleteType() (err error) {
	var count int64
	query := config.DB.Table(e.TableName())
	query.Where("parent_id = ?", e.Id).Count(&count)
	if count > 0 {
		err = errors.New("存在子级,不允许删除")
		return
	}
	config.DB.Table(e.TableName()).Where("id = ?", e.Id).Delete(SysDict{})
	return
}

// 删除字典项
func (e *SysDict) Delete(ids []string) (err error) {
	config.DB.Table(e.TableName()).Delete(&SysRole{}, ids)
	return
}

// 角色下拉列表
func (e *SysDict) GetSelectList() []SysDict {
	var dict SysDict
	var list []SysDict // 查询结果
	// 先根据字典代码查询字典类型
	config.DB.Table(e.TableName()).Where("dict_code = ?", e.DictCode).Find(&dict)
	// 再根据字典类型的id查询它下面的字典项列表
	//config.DB.Table(e.TableName()).Where("parent_id = ? and is_type = 2", dict.Id).Debug().Order("sort asc").Find(&list)
	config.DB.Table(e.TableName()).Where("parent_id = ?", dict.Id).Debug().Order("sort asc").Find(&list)
	return list
}

// 构建树结构
func buildDictTree(list []SysDict, parentId string) []SysDict {
	var tree []SysDict
	for _, item := range list {
		if item.ParentId == parentId {
			children := buildDictTree(list, item.Id)
			if len(children) > 0 {
				item.Children = children
			}
			tree = append(tree, item)
		}
	}
	return tree
}

// 校验字典名称和代码是否存在
func checkDictNameAndCode(roleName, roleKey, id string) bool {
	var count int64
	query := config.DB.Table(SysDict{}.TableName())
	if roleName != "" {
		query.Where("dict_name = ?", roleName)
	}
	if roleKey != "" {
		query.Where("dict_code = ?", roleKey)
	}
	if id != "" {
		query.Where("id <> ?", id)
	}
	query.Count(&count)
	return count > 0
}

安全设置

安全设置这个模块也不是必须的,看自己喜欢或需求,不要这个模块的话,登录的时候,错误次数限定、锁定时间、token有效期这些可以自己固定值,或者是在 application.yml 配置也可以,看哪一种更方便吧。

controller层:sys_safe.go

package sys

import (
	"github.com/gofiber/fiber/v2"
	"go-web2/app/common/config"
	"go-web2/app/model/sys"
)

type SafeController struct{}

// 获取安全设置
func (SafeController) GetSafeSet(c *fiber.Ctx) error {
	safe := sys.SysSafe{}
	safe.GetById()
	return c.Status(200).JSON(config.Success(safe))
}

// 修改安全设置
func (SafeController) Update(c *fiber.Ctx) error {
	var safe sys.SysSafe
	if err := c.BodyParser(&safe); err != nil {
		return c.Status(200).JSON(config.Error(err.Error()))
	}
	safe.Token = c.Get(config.TokenHeader)
	err := safe.Update()
	if err != nil {
		return c.Status(200).JSON(config.Error(err.Error()))
	}
	return c.Status(200).JSON(config.Success(nil))
}

model层:sys_safe.go

package sys

import (
	"github.com/google/uuid"
	"go-web2/app/common/config"
	"strings"
)

// 安全中心
type SysSafe struct {
	config.BaseModel
	PwdCycle        int `json:"pwdCycle" form:"pwdCycle"`               // 密码更改周期(90天,60天,30天,0无)
	PwdLoginLimit   int `json:"pwdLoginLimit" form:"pwdLoginLimit"`     // 密码登录限制(0:连续错3次,锁定账号15分钟。1:连续错5次,锁定账号30分钟)
	IdleTimeSetting int `json:"idleTimeSetting" form:"idleTimeSetting"` // 闲置时间设置(0:无。1:空闲30分钟,系统默认用户退出)
}

// 获取表名
func (SysSafe) TableName() string {
	return "sys_safe"
}

// 详情
func (e *SysSafe) GetById() (err error) {
	query := config.DB.Table(e.TableName())
	if err = query.First(e).Error; err != nil {
		return
	}
	return
}

// 修改
func (e *SysSafe) Update() (err error) {
	if e.Id == "" {
		e.Id = strings.ReplaceAll(uuid.NewString(), "-", "")
		e.CreatorId = GetLoginId(e.Token)
		config.DB.Create(e)
	} else {
		// 使用Save方法进行更新,标识零值也需要进行更新。Select是指定需要更新哪些字段
		config.DB.Model(&SysSafe{}).Select("pwd_cycle", "pwd_login_limit", "idle_time_setting").Where("id = ?", e.Id).Save(e)
		expire := GetTimeOut(e.Token)
		i := e.IdleTimeSetting
		//修改token的过期时间
		if expire > 0 && i == 0 {
			UpdateTimeOut(e.Token, -1)
		} else if expire < 0 && i != 0 {
			UpdateTimeOut(e.Token, config.TokenExpire)
		}
	}
	return
}

最后

到这里,我们这个后台管理系统算是搭建起来了,后续可以自行添加模块。然后因为个人不会vue,这个demo是只有后端代码的,木有前端哦。不过大家也别急,我自己写这些代码的时候,都是用 apipost 把接口都测试了的,所以每个接口都有接口文档,我一起放到源码里面了,大家可以下载后自行导入 apipost 或 postman 中进行测试。然后用到的数据库也在里面,还有一些基本的测试数据都有,大家直接用就行辣~

在这里插入图片描述

源码

Gitee:点我查看,记得给俺点个星星~


好啦,以上就是本篇文章和本后台管理系统的全部内容辣,欢迎大家多多点赞、Star 支持下哦,后续我还会更新go相关的文章的,所以可以关注我,不迷路~

  • 16
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

符华-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值