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

查看前几篇内容:

第一篇:【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相关的文章的,所以可以关注我,不迷路~

参考阅读

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: