欸嘿,窝又来辣😁昨天没时间更新,今天补上😊
查看前几篇内容:
第一篇:【Go】基于GoFiber从零开始搭建一个GoWeb后台管理系统(一)搭建项目
第二篇:【Go】基于GoFiber从零开始搭建一个GoWeb后台管理系统(二)日志输出中间件、校验token中间件、配置路由、基础工具函数。
第三篇:【Go】基于GoFiber从零开始搭建一个GoWeb后台管理系统(三)日志管理(登录日志、操作日志)、用户登录模块
第四篇:【Go】基于GoFiber从零开始搭建一个GoWeb后台管理系统(四)用户管理、部门管理模块
第五篇:【Go】基于GoFiber从零开始搭建一个GoWeb后台管理系统(五)角色管理、菜单管理模块
这篇是这个后台管理系统的最后一篇了(也有可能不是,可能后续还会有补充)
这个模块有两个接口:hasDictByName、hasDictByCode
不是必须的,大家可以根据自己喜欢或需求决定用不用。
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()))
}
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
配置也可以,看哪一种更方便吧。
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))
}
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相关的文章的,所以可以关注我,不迷路~