Parcourir la source

ADD:初始化项目

zoie il y a 1 an
commit
ef9860bd50
100 fichiers modifiés avec 8634 ajouts et 0 suppressions
  1. 44 0
      .gitignore
  2. 26 0
      Dockerfile
  3. 112 0
      README.md
  4. 190 0
      app/admin/controller/address.go
  5. 39 0
      app/admin/controller/captcha.go
  6. 202 0
      app/admin/controller/company.go
  7. 123 0
      app/admin/controller/sys_login_log_controller.go
  8. 239 0
      app/admin/controller/sys_menu.go
  9. 128 0
      app/admin/controller/sys_opera_log.go
  10. 535 0
      app/admin/controller/sys_user.go
  11. 68 0
      app/admin/controller/upload.go
  12. 197 0
      app/admin/controller/warehouse.go
  13. 32 0
      app/admin/model/address.go
  14. 48 0
      app/admin/model/sys_dept.go
  15. 72 0
      app/admin/model/sys_login_log.go
  16. 45 0
      app/admin/model/sys_menu.go
  17. 92 0
      app/admin/model/sys_opera_log.go
  18. 50 0
      app/admin/model/sys_role.go
  19. 74 0
      app/admin/model/sys_role_menu.go
  20. 110 0
      app/admin/model/sys_user.go
  21. 17 0
      app/admin/model/warehouse.go
  22. 24 0
      app/admin/router/address.go
  23. 19 0
      app/admin/router/captcha.go
  24. 90 0
      app/admin/router/init_router.go
  25. 11 0
      app/admin/router/router.go
  26. 28 0
      app/admin/router/sys_dept.go
  27. 25 0
      app/admin/router/sys_login_log.go
  28. 33 0
      app/admin/router/sys_menu.go
  29. 24 0
      app/admin/router/sys_opera_log.go
  30. 55 0
      app/admin/router/sys_user.go
  31. 19 0
      app/admin/router/upload.go
  32. 26 0
      app/admin/router/warehouse.go
  33. 184 0
      app/admin/service/address.go
  34. 184 0
      app/admin/service/company.go
  35. 111 0
      app/admin/service/dto/address.go
  36. 98 0
      app/admin/service/dto/company.go
  37. 58 0
      app/admin/service/dto/sys_login_log_dto.go
  38. 134 0
      app/admin/service/dto/sys_menu.go
  39. 103 0
      app/admin/service/dto/sys_opera_log_dto.go
  40. 158 0
      app/admin/service/dto/sys_role.go
  41. 215 0
      app/admin/service/dto/sys_user.go
  42. 92 0
      app/admin/service/dto/warehouse.go
  43. 72 0
      app/admin/service/sys_login_log_service.go
  44. 669 0
      app/admin/service/sys_menu.go
  45. 84 0
      app/admin/service/sys_opera_log_service.go
  46. 404 0
      app/admin/service/sys_role.go
  47. 414 0
      app/admin/service/sys_user.go
  48. 155 0
      app/admin/service/warehouse.go
  49. 8 0
      cmd/api/jobs.go
  50. 180 0
      cmd/api/server.go
  51. 51 0
      cmd/cobra.go
  52. 62 0
      cmd/config/server.go
  53. 63 0
      cmd/migrate/initdb.go
  54. 41 0
      cmd/migrate/server.go
  55. 49 0
      common/actions/create.go
  56. 61 0
      common/actions/delete.go
  57. 58 0
      common/actions/index.go
  58. 121 0
      common/actions/permission.go
  59. 5 0
      common/actions/type.go
  60. 59 0
      common/actions/update.go
  61. 67 0
      common/actions/view.go
  62. 106 0
      common/dto/generate.go
  63. 12 0
      common/dto/order.go
  64. 20 0
      common/dto/pagination.go
  65. 94 0
      common/dto/search.go
  66. 21 0
      common/dto/type.go
  67. 69 0
      common/file_store/initialize.go
  68. 27 0
      common/file_store/interface.go
  69. 111 0
      common/file_store/kodo.go
  70. 23 0
      common/file_store/kodo_test.go
  71. 53 0
      common/file_store/obs.go
  72. 15 0
      common/file_store/obs_test.go
  73. 49 0
      common/file_store/oss.go
  74. 16 0
      common/file_store/oss_test.go
  75. 11 0
      common/global/adm.go
  76. 27 0
      common/global/casbin.go
  77. 25 0
      common/global/error.go
  78. 7 0
      common/global/topic.go
  79. 27 0
      common/ip.go
  80. 39 0
      common/middleware/auth.go
  81. 60 0
      common/middleware/customerror.go
  82. 12 0
      common/middleware/db.go
  83. 289 0
      common/middleware/handler/auth.go
  84. 13 0
      common/middleware/handler/dept.go
  85. 22 0
      common/middleware/handler/httpshandler.go
  86. 100 0
      common/middleware/handler/login.go
  87. 17 0
      common/middleware/handler/role.go
  88. 21 0
      common/middleware/handler/service.go
  89. 22 0
      common/middleware/handler/user.go
  90. 48 0
      common/middleware/header.go
  91. 36 0
      common/middleware/init.go
  92. 147 0
      common/middleware/logger.go
  93. 66 0
      common/middleware/permission.go
  94. 37 0
      common/middleware/request_id.go
  95. 23 0
      common/middleware/sentinel.go
  96. 43 0
      common/middleware/service_auth.go
  97. 45 0
      common/middleware/settings.go
  98. 98 0
      common/model/byat.go
  99. 13 0
      common/model/menu.go
  100. 13 0
      common/model/pay.go

+ 44 - 0
.gitignore

@@ -0,0 +1,44 @@
+# ---> Go
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
+
+# local
+.idea
+/_
+/.cache
+.vscode/
+/logs/logx
+lastupdate.tmp
+main
+nohup.out
+/bin
+Makefile
+/ofile
+setting.yml
+/temp
+/app/jobs
+/docs
+uploads
+

+ 26 - 0
Dockerfile

@@ -0,0 +1,26 @@
+# FROM ... AS builder : 表示依赖的镜像只是使用在编译阶段
+#FROM golang:1.19 AS builder
+
+#ARG VERSION=""
+#ARG VCS_BRANCH=""
+#ARG PROJECT_NAME=OAuth
+#ARG DOCKER_PROJECT_DIR=/build
+#ARG EXTRA_BUILD_ARGS=""
+
+# 编译阶段的工作目录,也可以作为全局工作目录
+#WORKDIR $DOCKER_PROJECT_DIR
+#COPY . $DOCKER_PROJECT_DIR
+
+#ENV GOPROXY="https://goproxy.cn,direct"
+
+#RUN git config --global url."gogs.baozhida.cn/zoie/OAuth-core".insteadOf "https://gogs.baozhida.cn/zoie/OAuth-core" && \
+#    mkdir -p /output && \
+#    make build-linux -e OUTPUT_FILE_LINUX=/output/OAuth \
+#    -e VERSION=$VERSION -e VCS_BRANCH=$VCS_BRANCH -e EXTRA_BUILD_ARGS=$EXTRA_BUILD_ARGS
+
+FROM alpine
+COPY ./bin/linux/GasCylinderApi /usr/local/bin
+COPY ./conf/ /etc/conf/
+#COPY /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
+EXPOSE 8000
+CMD ["cold-logistics","server","-c", "/etc/conf/settings.yml"]

+ 112 - 0
README.md

@@ -0,0 +1,112 @@
+# 冷链运输平台
+
+### 环境要求
+
+- go 1.19
+- mysql 8.0+
+- redis 4.0+
+
+### 关联工具库
+
+#### 导入线上库
+
+[//]: # (git config --global url."git@gogs.baozhida.cn/zoie/OAuth-core".insteadOf"https://gogs.baozhida.cn/zoie/OAuth-core")
+git config --global url."admin@gogs.baozhida.cn:zoie/OAuth-core".insteadOf "https://gogs.baozhida.cn/zoie/OAuth-core"
+
+9d18bb783ab3c0ecfa550e241a2de79fe1383278
+
+
+#### 导入本地库
+
+go mod edit -replace gogs.baozhida.cn/zoie/OAuth-core=${Yours_Path}/OAuth-core
+
+##### 示列:
+
+```bash
+go mod edit -replace gogs.baozhida.cn/zoie/OAuth-core=/Users/work/bzd_project/OAuth-core
+```
+
+### 软件架构
+
+go gorm
+
+### 开发工具
+
+开发前需要安装以下工具
+
+- [cobra](https://github.com/spf13/cobra) (optional): CLI tool, 可以生成 cmd.go 文件
+- [gin-swagger](https://github.com/swaggo/gin-swagger) (required): 生成swagger文档
+
+### 配置
+
+参考 `conf/setting.yml`
+
+### 编译
+
+```bash
+# windows
+go build main.go
+
+# macOS or linux 
+make build
+```
+
+#### 交叉编译
+
+```bash
+# windows
+env GOOS=windows GOARCH=amd64 go build main.go
+
+# macOS or linux 
+env GOOS=linux GOARCH=amd64 go build main.go
+```
+
+### 初始化数据库,以及服务启动
+
+``` bash
+# 首次配置需要初始化数据库资源信息
+# macOS or linux 下使用
+$ ./OAuth migrate -c conf/settings.yml
+
+# ️注意:windows 下使用
+$ OAuth.exe migrate -c conf/settings.yml
+```
+
+### 启动服务,也可以用IDE进行调试
+
+```shell
+# macOS or linux 下使用
+$ ./OAuth server -c conf/settings.yml
+
+
+# 注意:windows 下使用
+$ OAuth.exe server -c conf/settings.yml
+```
+
+### 接口文档
+
+#### 生成swag接口文档
+
+./ssh/swag.sh
+
+```bash
+swag init --parseDependency --parseInternal
+swag init --parseDependency --parseDepth=6
+```
+
+#### 访问
+
+```bash
+http://localhost:port/swagger/index.html
+```
+
+### 角色数据权限
+
+```bash
+1 - 全部数据权限
+3 - 本机构数据权限
+4 - 本机构及以下数据权限
+5 - 仅本人数据权限
+```
+### 开发库
+- [validator](https://github.com/bytedance/go-tagexpr) 参数校验

+ 190 - 0
app/admin/controller/address.go

@@ -0,0 +1,190 @@
+package controller
+
+import (
+	"cold-logistics/app/admin/model"
+	"cold-logistics/app/admin/service"
+	"cold-logistics/app/admin/service/dto"
+	"cold-logistics/common/actions"
+	"github.com/gin-gonic/gin"
+	"github.com/gin-gonic/gin/binding"
+	"gogs.baozhida.cn/zoie/OAuth-core/api"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth/user"
+	_ "gogs.baozhida.cn/zoie/OAuth-core/pkg/response"
+)
+
+type AddressController struct {
+	api.Api
+}
+
+// GetPage 获取收货地址列表
+// @Summary 获取收货地址列表
+// @Description 获取收货地址列表
+// @Tags 收货地址
+// @Param pageSize query int false "页条数"
+// @Param page query int false "页码"
+// @Success 200 {object} response.Response{data=response.Page{list=[]model.Address}} "{"code": 200, "data": [...]}"
+// @Router /api/address [get]
+// @Security Bearer
+func (e AddressController) GetPage(c *gin.Context) {
+	s := service.Address{}
+	req := dto.AddressGetPageReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.Query).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	//数据权限检查
+	list := make([]model.Address, 0)
+	var count int64
+
+	err = s.GetPage(&req, &list, &count)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
+}
+
+// Get 通过id获取收货地址
+// @Summary 通过id获取收货地址
+// @Description 通过id获取收货地址
+// @Tags 收货地址
+// @Param id path string true "收货地址id"
+// @Success 200 {object} response.Response{data=model.Address} "{"code": 200, "data": [...]}"
+// @Router /api/address/{id} [get]
+// @Security Bearer
+func (e AddressController) Get(c *gin.Context) {
+	s := service.Address{}
+	req := dto.AddressGetReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, nil).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	var object model.Address
+	p := actions.GetPermissionFromContext(c)
+
+	//数据权限检查
+	err = s.Get(&req, &object, p)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	e.OK(object, "查询成功")
+}
+
+// Insert 添加收货地址
+// @Summary 添加收货地址
+// @Description 添加收货地址
+// @Tags 收货地址
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.AddressInsertReq true "data"
+// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
+// @Router /api/address [post]
+// @Security Bearer
+func (e AddressController) Insert(c *gin.Context) {
+	s := service.Address{}
+	req := dto.AddressInsertReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.JSON).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	err = s.Insert(&req)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.OK(req.GetId(), "创建成功")
+}
+
+// Update 修改收货地址
+// @Summary 修改收货地址
+// @Description 修改收货地址
+// @Tags 收货地址
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.AddressUpdateReq true "body"
+// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
+// @Router /api/address [put]
+// @Security Bearer
+func (e AddressController) Update(c *gin.Context) {
+	s := service.Address{}
+	req := dto.AddressUpdateReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	p := actions.GetPermissionFromContext(c)
+
+	req.SetUpdateBy(user.GetUserId(c))
+	err = s.Update(&req, p)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.OK(req.GetId(), "更新成功")
+}
+
+// Delete 删除收货地址
+// @Summary 删除收货地址
+// @Description 删除收货地址
+// @Tags 收货地址
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.AddressDeleteReq true "body"
+// @Success 200 {string} string	"{"code": 200, "message": "删除成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "删除失败"}"
+// @Router /api/address [delete]
+// @Security Bearer
+func (e AddressController) Delete(c *gin.Context) {
+	s := service.Address{}
+	req := dto.AddressDeleteReq{}
+	userSvc := service.SysUser{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.JSON, nil).
+		MakeService(&s.Service).
+		MakeService(&userSvc.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	//数据权限检查
+	p := actions.GetPermissionFromContext(c)
+	err = s.Remove(&req, p)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.OK(req.GetId(), "删除成功")
+}

+ 39 - 0
app/admin/controller/captcha.go

@@ -0,0 +1,39 @@
+package controller
+
+import (
+	"github.com/gin-gonic/gin"
+	"gogs.baozhida.cn/zoie/OAuth-core/api"
+
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/captcha"
+	_ "gogs.baozhida.cn/zoie/OAuth-core/pkg/response"
+)
+
+type SystemController struct {
+	api.Api
+}
+
+// GenerateCaptchaHandler 获取验证码
+// @Summary 获取验证码
+// @Description 获取验证码
+// @Tags 登录
+// @Success 200 {object} response.Response{data=string,id=string,msg=string} "{"code": 200, "data": [...]}"
+// @Router /api/captcha [get]
+func (e SystemController) GenerateCaptchaHandler(c *gin.Context) {
+	err := e.MakeContext(c).Errors
+	if err != nil {
+		e.Error(500, err, "服务初始化失败!")
+		return
+	}
+	id, b64s, err := captcha.DriverDigitFunc()
+	if err != nil {
+		e.Logger.Errorf("DriverDigitFunc error, %s", err.Error())
+		e.Error(500, err, "验证码获取失败")
+		return
+	}
+	e.Custom(gin.H{
+		"code": 200,
+		"data": b64s,
+		"id":   id,
+		"msg":  "success",
+	})
+}

+ 202 - 0
app/admin/controller/company.go

@@ -0,0 +1,202 @@
+package controller
+
+import (
+	"cold-logistics/app/admin/model"
+	"cold-logistics/app/admin/service"
+	"cold-logistics/app/admin/service/dto"
+	"cold-logistics/common/actions"
+	"github.com/gin-gonic/gin"
+	"github.com/gin-gonic/gin/binding"
+	"gogs.baozhida.cn/zoie/OAuth-core/api"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth/user"
+	_ "gogs.baozhida.cn/zoie/OAuth-core/pkg/response"
+)
+
+type CompanyController struct {
+	api.Api
+}
+
+// GetPage 获取销售门店列表
+// @Summary 获取销售门店列表
+// @Description 获取销售门店列表(用户公司及子公司)
+// @Tags 销售门店
+// @Param name query string false "销售门店名称"
+// @Success 200 {object} response.Response{data=response.Page{list=[]model.SysDept}} "{"code": 200, "data": [...]}"
+// @Router /api/store [get]
+// @Security Bearer
+func (e CompanyController) GetPage(c *gin.Context) {
+	s := service.Company{}
+	req := dto.CompanyGetPageReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.Query).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	//数据权限检查
+	p := actions.GetPermissionFromContext(c)
+	p.DeptId = user.GetDeptId(c)
+	list := make([]model.SysDept, 0)
+	var count int64
+	err = s.GetPage(&req, &list, &count)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
+}
+
+// Get 通过id获取销售门店
+// @Summary 通过id获取销售门店
+// @Description 通过id获取销售门店
+// @Tags 销售门店
+// @Param id path string true "销售门店id"
+// @Success 200 {object} response.Response{data=model.SysDept} "{"code": 200, "data": [...]}"
+// @Router /api/store/{id} [get]
+// @Security Bearer
+func (e CompanyController) Get(c *gin.Context) {
+	s := service.Company{}
+	req := dto.CompanyGetReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, nil).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	var object model.SysDept
+	//数据权限检查
+	err = s.Get(&req, &object)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	e.OK(object, "查询成功")
+}
+
+// Insert 添加销售门店
+// @Summary 添加销售门店
+// @Description 添加销售门店
+// @Tags 销售门店
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.CompanyInsertReq true "data"
+// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
+// @Router /api/store [post]
+// @Security Bearer
+func (e CompanyController) Insert(c *gin.Context) {
+	s := service.Company{}
+	req := dto.CompanyInsertReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.JSON).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	// 设置创建人
+	req.SetCreateBy(user.GetUserId(c))
+	deptId := user.GetDeptId(c)
+	err = s.Insert(&req, deptId)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.OK(req.GetId(), "创建成功")
+}
+
+// Update 修改销售门店
+// @Summary 修改销售门店
+// @Description 修改销售门店
+// @Tags 销售门店
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.CompanyUpdateReq true "body"
+// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
+// @Router /api/store [put]
+// @Security Bearer
+func (e CompanyController) Update(c *gin.Context) {
+	s := service.Company{}
+	req := dto.CompanyUpdateReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	req.SetUpdateBy(user.GetUserId(c))
+	err = s.Update(&req)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.OK(req.GetId(), "更新成功")
+}
+
+// Delete 删除销售门店
+// @Summary 删除销售门店
+// @Description 删除销售门店
+// @Tags 销售门店
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.CompanyDeleteReq true "body"
+// @Success 200 {string} string	"{"code": 200, "message": "删除成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "删除失败"}"
+// @Router /api/store [delete]
+// @Security Bearer
+func (e CompanyController) Delete(c *gin.Context) {
+	s := service.Company{}
+	req := dto.CompanyDeleteReq{}
+	userSvc := service.SysUser{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.JSON, nil).
+		MakeService(&s.Service).
+		MakeService(&userSvc.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	var count int64
+	err = userSvc.GetCount(&dto.SysUserGetCountReq{DeptIds: []int{req.Id}}, &count)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	if count > 0 {
+		e.Error(500, err, "有用户关联,禁止删除!")
+		return
+	}
+
+	//数据权限检查
+	//p := actions.GetPermissionFromContext(c)
+	err = s.Remove(&req, nil)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.OK(req.GetId(), "删除成功")
+}

+ 123 - 0
app/admin/controller/sys_login_log_controller.go

@@ -0,0 +1,123 @@
+package controller
+
+import (
+	"cold-logistics/common/actions"
+	"github.com/gin-gonic/gin"
+	"github.com/gin-gonic/gin/binding"
+	"gogs.baozhida.cn/zoie/OAuth-core/api"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth/user"
+	_ "gogs.baozhida.cn/zoie/OAuth-core/pkg/response"
+
+	"cold-logistics/app/admin/model"
+	"cold-logistics/app/admin/service"
+	"cold-logistics/app/admin/service/dto"
+)
+
+type SysLoginLogController struct {
+	api.Api
+}
+
+// GetPage 登录日志列表
+// @Summary 登录日志列表
+// @Description 登录日志列表
+// @Tags 登录日志
+// @Param username query string false "用户名"
+// @Param ipaddr query string false "ip地址"
+// @Param loginLocation  query string false "归属地"
+// @Param status query string false "状态"
+// @Param beginTime query string false "开始时间"
+// @Param endTime query string false "结束时间"
+// @Param pageSize query int false "页条数"
+// @Param pageIndex query int false "页码"
+// @Success 200 {object} response.Response{data=response.Page{list=[]model.SysLoginLog}} "{"code": 200, "data": [...]}"
+// @Router /api/sys-login-log [get]
+// @Security Bearer
+func (e SysLoginLogController) GetPage(c *gin.Context) {
+	s := service.SysLoginLogService{}
+	req := dto.SysLoginLogGetPageReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.Form).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	//数据权限检查
+	p := actions.GetPermissionFromContext(c)
+
+	list := make([]model.SysLoginLog, 0)
+	var count int64
+	err = s.GetPage(&req, &list, &count, p)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
+}
+
+// Get 通过id获取登录日志
+// @Summary 通过id获取登录日志
+// @Description 通过id获取登录日志
+// @Tags 登录日志
+// @Param id path string true "登录日志id"
+// @Success 200 {object} response.Response{data=model.SysLoginLog} "{"code": 200, "data": [...]}"
+// @Router /api/sys-login-log/{id} [get]
+// @Security Bearer
+func (e SysLoginLogController) Get(c *gin.Context) {
+	s := service.SysLoginLogService{}
+	req := dto.SysLoginLogGetReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	//数据权限检查
+	p := actions.GetPermissionFromContext(c)
+	var object model.SysLoginLog
+	err = s.Get(&req, &object, p)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.OK(object, "查询成功")
+}
+
+// Delete 删除登录日志
+// @Summary 删除登录日志
+// @Description 删除登录日志
+// @Tags 登录日志
+// @Param data body dto.SysLoginLogDeleteReq true "body"
+// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
+// @Router /api/sys-login-log [delete]
+// @Security Bearer
+func (e SysLoginLogController) Delete(c *gin.Context) {
+	s := service.SysLoginLogService{}
+	req := dto.SysLoginLogDeleteReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.JSON, nil).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	//数据权限检查
+	p := actions.GetPermissionFromContext(c)
+	req.SetUpdateBy(user.GetUserId(c))
+	err = s.Remove(&req, p)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.OK(req.GetId(), "删除成功")
+}

+ 239 - 0
app/admin/controller/sys_menu.go

@@ -0,0 +1,239 @@
+package controller
+
+import (
+	"cold-logistics/app/admin/model"
+	"cold-logistics/app/admin/service"
+	"cold-logistics/app/admin/service/dto"
+	"cold-logistics/common/actions"
+	"github.com/gin-gonic/gin"
+	"github.com/gin-gonic/gin/binding"
+	"gogs.baozhida.cn/zoie/OAuth-core/api"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth/user"
+	_ "gogs.baozhida.cn/zoie/OAuth-core/pkg/response"
+)
+
+type SysMenuController struct {
+	api.Api
+}
+
+// GetPage 获取菜单列表
+// @Summary 获取菜单列表
+// @Description 获取菜单列表
+// @Tags 菜单
+// @Param menuName query string false "菜单名称"
+// @Param title query string false "显示名称"
+// @Param visible query string false "显示状态"
+// @Param pageSize query int false "页条数"
+// @Param pageIndex query int false "页码"
+// @Success 200 {object} response.Response{data=response.Page{list=[]model.SysMenu}} "{"code": 200, "data": [...]}"
+// @Router /api/menu [get]
+// @Security Bearer
+func (e SysMenuController) GetPage(c *gin.Context) {
+	s := service.SysMenu{}
+	req := dto.SysMenuGetPageReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.Form).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	var list = make([]model.SysMenu, 0)
+	if err = s.GetPage(&req, &list).Error; err != nil {
+		e.Error(500, err, "查询失败")
+		return
+	}
+	e.OK(list, "查询成功")
+}
+
+// Get 通过id获取菜单
+// @Summary 通过id获取菜单
+// @Description 通过id获取菜单
+// @Tags 菜单
+// @Param id path string true "菜单id"
+// @Success 200 {object} response.Response{data=model.SysMenu} "{"code": 200, "data": [...]}"
+// @Router /api/menu/{id} [get]
+// @Security Bearer
+func (e SysMenuController) Get(c *gin.Context) {
+	req := dto.SysMenuGetReq{}
+	s := service.SysMenu{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, nil).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	var object = model.SysMenu{}
+	err = s.Get(&req, &object).Error
+	if err != nil {
+		e.Error(500, err, "查询失败")
+		return
+	}
+	e.OK(object, "查询成功")
+}
+
+// Insert 创建菜单
+// @Summary 创建菜单
+// @Description 创建菜单
+// @Tags 菜单
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.SysMenuInsertReq true "data"
+// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
+// @Router /api/menu [post]
+// @Security Bearer
+func (e SysMenuController) Insert(c *gin.Context) {
+	req := dto.SysMenuInsertReq{}
+	s := service.SysMenu{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.JSON).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	// 设置创建人
+	req.SetCreateBy(user.GetUserId(c))
+	err = s.Insert(&req).Error
+	if err != nil {
+		e.Error(500, err, "创建失败")
+		return
+	}
+	e.OK(req.GetId(), "创建成功")
+}
+
+// Update 修改菜单
+// @Summary 修改菜单
+// @Description 修改菜单
+// @Tags 菜单
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.SysMenuUpdateReq true "body"
+// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
+// @Router /api/menu/{id} [put]
+// @Security Bearer
+func (e SysMenuController) Update(c *gin.Context) {
+	s := service.SysMenu{}
+	req := dto.SysMenuUpdateReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.JSON, nil).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	req.SetUpdateBy(user.GetUserId(c))
+	err = s.Update(&req).Error
+	if err != nil {
+		e.Error(500, err, "更新失败")
+		return
+	}
+	e.OK(req.GetId(), "更新成功")
+}
+
+// Delete 删除菜单
+// @Summary 删除菜单
+// @Description 删除菜单
+// @Tags 菜单
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.SysMenuDeleteReq true "body"
+// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
+// @Router /api/menu [delete]
+// @Security Bearer
+func (e SysMenuController) Delete(c *gin.Context) {
+	s := service.SysMenu{}
+	req := dto.SysMenuDeleteReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.JSON).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	req.SetUpdateBy(user.GetUserId(c))
+	err = s.Remove(&req).Error
+	if err != nil {
+		e.Logger.Errorf("RemoveSysMenu error, %s", err)
+		e.Error(500, err, "删除失败")
+		return
+	}
+	e.OK(req.GetId(), "删除成功")
+}
+
+// GetMenuRole 根据登录角色名称获取菜单列表数据【左菜单使用】
+// @Summary 根据登录角色名称获取菜单列表数据【左菜单使用】
+// @Description 根据登录角色名称获取菜单列表数据【左菜单使用】
+// @Tags 菜单
+// @Success 200 {object} response.Response{data=[]model.SysMenu} "{"code": 200, "data": [...]}"
+// @Router /api/menu-role [get]
+// @Security Bearer
+func (e SysMenuController) GetMenuRole(c *gin.Context) {
+	s := new(service.SysMenu)
+	err := e.MakeContext(c).
+		MakeOrm().
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	p := actions.GetPermissionFromContext(c)
+	result, err := s.SetMenuRole(user.GetRoleKey(c), user.GetUserId(c), p)
+
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	e.OK(result, "")
+}
+
+// GetMenuRole 根据登录角色名称获取菜单列表数据【左菜单使用】
+// @Summary 根据登录角色名称获取菜单列表数据【左菜单使用】
+// @Description 根据登录角色名称获取菜单列表数据【左菜单使用】
+// @Tags 菜单
+// @Success 200 {object} response.Response{data=[]model.SysMenu} "{"code": 200, "data": [...]}"
+// @Router /api/select-menu [get]
+// @Security Bearer
+func (e SysMenuController) MenuSelect(c *gin.Context) {
+	s := new(service.SysMenu)
+	err := e.MakeContext(c).
+		MakeOrm().
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	p := actions.GetPermissionFromContext(c)
+	result, err := s.MenuSelect(user.GetRoleKey(c), user.GetUserId(c), p)
+
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	e.OK(result, "")
+}

+ 128 - 0
app/admin/controller/sys_opera_log.go

@@ -0,0 +1,128 @@
+package controller
+
+import (
+	"cold-logistics/common/actions"
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"github.com/gin-gonic/gin/binding"
+	"gogs.baozhida.cn/zoie/OAuth-core/api"
+	_ "gogs.baozhida.cn/zoie/OAuth-core/pkg/response"
+
+	"cold-logistics/app/admin/model"
+	"cold-logistics/app/admin/service"
+	"cold-logistics/app/admin/service/dto"
+)
+
+type SysOperaLogController struct {
+	api.Api
+}
+
+// GetPage 操作日志列表
+// @Summary 操作日志列表
+// @Description 操作日志列表
+// @Tags 操作日志
+// @Param title query string false "title"
+// @Param method query string false "method"
+// @Param requestMethod  query string false "requestMethod"
+// @Param operaUrl query string false "operaUrl"
+// @Param operaIp query string false "operaIp"
+// @Param status query string false "status"
+// @Param beginTime query string false "beginTime"
+// @Param endTime query string false "endTime"
+// @Param pageSize query int false "页条数"
+// @Param pageIndex query int false "页码"
+// @Success 200 {object} response.Response{data=response.Page{list=[]model.SysOperaLog}} "{"code": 200, "data": [...]}"
+// @Router /api/sys-opera-log [get]
+// @Security Bearer
+func (e SysOperaLogController) GetPage(c *gin.Context) {
+	s := service.SysOperaLog{}
+	req := new(dto.SysOperaLogGetPageReq)
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(req, binding.Form).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	list := make([]model.SysOperaLog, 0)
+	var count int64
+	//数据权限检查
+	p := actions.GetPermissionFromContext(c)
+	err = s.GetPage(req, &list, &count, p)
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, "查询失败")
+		return
+	}
+
+	e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
+}
+
+// Get 通过id获取操作日志
+// @Summary 通过id获取操作日志
+// @Description 通过id获取操作日志
+// @Tags 操作日志
+// @Param id path string true "操作日志id"
+// @Success 200 {object} response.Response{data=model.SysOperaLog} "{"code": 200, "data": [...]}"
+// @Router /api/sys-opera-log/{id} [get]
+// @Security Bearer
+func (e SysOperaLogController) Get(c *gin.Context) {
+	s := new(service.SysOperaLog)
+	req := dto.SysOperaLogGetReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, nil).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	//数据权限检查
+	p := actions.GetPermissionFromContext(c)
+	var object model.SysOperaLog
+	err = s.Get(&req, &object, p)
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, "查询失败")
+		return
+	}
+	e.OK(object, "查询成功")
+}
+
+// Delete 删除操作日志
+// @Summary 删除操作日志
+// @Description 删除操作日志
+// @Tags 操作日志
+// @Param data body dto.SysOperaLogDeleteReq true "body"
+// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
+// @Router /api/sys-opera-log [delete]
+// @Security Bearer
+func (e SysOperaLogController) Delete(c *gin.Context) {
+	s := new(service.SysOperaLog)
+	req := dto.SysOperaLogDeleteReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.JSON).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	//数据权限检查
+	p := actions.GetPermissionFromContext(c)
+	err = s.Remove(&req, p)
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, fmt.Sprintf("删除失败!错误详情:%s", err.Error()))
+		return
+	}
+	e.OK(req.GetId(), "删除成功")
+}

+ 535 - 0
app/admin/controller/sys_user.go

@@ -0,0 +1,535 @@
+package controller
+
+import (
+	"cold-logistics/app/admin/model"
+	"cold-logistics/app/admin/service"
+	"cold-logistics/app/admin/service/dto"
+	"cold-logistics/common/actions"
+	"cold-logistics/common/middleware/handler"
+	"cold-logistics/conf"
+	"errors"
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"github.com/gin-gonic/gin/binding"
+	"go.uber.org/zap"
+	"gogs.baozhida.cn/zoie/OAuth-core/api"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth/user"
+	_ "gogs.baozhida.cn/zoie/OAuth-core/pkg/response"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/sms"
+	"golang.org/x/crypto/bcrypt"
+	"net/http"
+)
+
+// SysUser 定义用户控制器
+type SysUser struct {
+	api.Api
+}
+
+// GetPage 获取系统用户列表
+// @Summary 获取系统用户列表
+// @Description 获取系统用户列表
+// @Tags 用户
+// @Param username query string false "用户名"
+// @Param deptId query int false "部门id"
+// @Param roleId query string false "角色id"
+// @Param postId query string false "岗位id"
+// @Param status query string false "状态 1-停用 2-正常"
+// @Param pageSize query int false "页条数"
+// @Param page query int false "页码"
+// @Success 200 {object} response.Response{data=response.Page{list=[]model.SysUser}}  "{"code": 200, "data": [...]}"
+// @Router /api/sys-user [get]
+// @Security Bearer
+func (e SysUser) GetPage(c *gin.Context) {
+	s := service.SysUser{}
+	req := dto.SysUserGetPageReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.Query).
+		MakeService(&s.Service).
+		Errors
+
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	//数据权限检查
+	p := actions.GetPermissionFromContext(c)
+
+	list := make([]model.SysUser, 0)
+	var count int64
+
+	err = s.GetPage(&req, p, &list, &count)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
+}
+
+// GetDeliveryPage 获取送气员列表
+// @Summary 获取送气员列表
+// @Description 获取送气员列表
+// @Tags 用户
+// @Param pageSize query int false "页条数"
+// @Param pageIndex query int false "页码"
+// @Success 200 {object} response.Response{data=response.Page{list=[]model.SysUser}}  "{"code": 200, "data": [...]}"
+// @Router /api/sys-user/delivery [get]
+// @Security Bearer
+func (e SysUser) GetDeliveryPage(c *gin.Context) {
+	s := service.SysUser{}
+	req := dto.SysUserGetDeliveryPageReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.Query).
+		MakeService(&s.Service).
+		Errors
+
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	//数据权限检查
+	//p := actions.GetPermissionFromContext(c)
+
+	list := make([]model.SysUser, 0)
+	var count int64
+
+	err = s.GetDeliveryPage(&req, nil, &list, &count)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
+}
+
+// Get 通过id获取用户
+// @Summary 通过id获取用户
+// @Description 通过id获取用户
+// @Tags 用户
+// @Param id path int true "用户id"
+// @Success 200 {object} response.Response{data=model.SysUser}  "{"code": 200, "data": [...]}"
+// @Router /api/sys-user/{id} [get]
+// @Security Bearer
+func (e SysUser) Get(c *gin.Context) {
+	s := service.SysUser{}
+	req := dto.SysUserGetReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, nil).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	//数据权限检查
+	p := actions.GetPermissionFromContext(c)
+
+	var object model.SysUser
+	err = s.Get(&req, p, &object)
+	if err != nil {
+		e.Error(http.StatusUnprocessableEntity, err, err.Error())
+		return
+	}
+	e.OK(object, "查询成功")
+}
+
+// Insert 创建用户
+// @Summary 创建用户
+// @Description 创建用户
+// @Tags 用户
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.SysUserInsertReq true "用户数据"
+// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
+// @Router /api/sys-user [post]
+// @Security Bearer
+func (e SysUser) Insert(c *gin.Context) {
+	s := service.SysUser{}
+	roleSvc := service.SysRole{}
+	req := dto.SysUserInsertReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.JSON).
+		MakeService(&s.Service).
+		MakeService(&roleSvc.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	p := actions.GetPermissionFromContext(c)
+	req.DeptId = p.DeptId
+	// 设置创建人
+	req.SetCreateBy(user.GetUserId(c))
+	err = s.Insert(&req)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	e.OK(req.GetId(), "创建成功")
+}
+
+// Update 修改用户数据
+// @Summary 修改用户数据
+// @Description 修改用户数据
+// @Tags 用户
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.SysUserUpdateReq true "body"
+// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
+// @Router /api/sys-user [put]
+// @Security Bearer
+func (e SysUser) Update(c *gin.Context) {
+	s := service.SysUser{}
+	req := dto.SysUserUpdateReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	req.SetUpdateBy(user.GetUserId(c))
+
+	//数据权限检查
+	p := actions.GetPermissionFromContext(c)
+
+	err = s.Update(&req, p)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.OK(req.GetId(), "更新成功")
+}
+
+// Delete 通过id删除用户数据
+// @Summary 通过id删除用户数据
+// @Description 通过id删除用户数据
+// @Tags 用户
+// @Param data body dto.SysUserDeleteReq true "body"
+// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
+// @Router /api/sys-user [delete]
+// @Security Bearer
+func (e SysUser) Delete(c *gin.Context) {
+	s := service.SysUser{}
+	req := dto.SysUserDeleteReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.JSON).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	userId := user.GetUserId(c)
+	if userId == req.Id {
+		err := errors.New("禁止删除自己")
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	// 设置编辑人
+	req.SetUpdateBy(userId)
+	//数据权限检查
+	p := actions.GetPermissionFromContext(c)
+
+	err = s.Remove(&req, p)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.OK(req.GetId(), "删除成功")
+}
+
+// UpdateStatus 修改用户状态
+// @Summary 修改用户状态
+// @Description 修改用户状态
+// @Tags 用户
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.UpdateSysUserStatusReq true "body"
+// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
+// @Router /api/user/status [put]
+// @Security Bearer
+func (e SysUser) UpdateStatus(c *gin.Context) {
+	s := service.SysUser{}
+	req := dto.UpdateSysUserStatusReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.JSON, nil).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	req.SetUpdateBy(user.GetUserId(c))
+
+	//数据权限检查
+	p := actions.GetPermissionFromContext(c)
+
+	err = s.UpdateStatus(&req, p)
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.OK(req.GetId(), "更新成功")
+}
+
+// ResetPwd 重置用户密码
+// @Summary 重置用户密码
+// @Description 重置用户密码
+// @Tags 用户
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.ResetSysUserPwdReq true "body"
+// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
+// @Router /api/user/pwd/reset [put]
+// @Security Bearer
+func (e SysUser) ResetPwd(c *gin.Context) {
+	s := service.SysUser{}
+	req := dto.ResetSysUserPwdReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.JSON).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	req.SetUpdateBy(user.GetUserId(c))
+
+	//数据权限检查
+	p := actions.GetPermissionFromContext(c)
+
+	err = s.ResetPwd(&req, p)
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	e.OK(req.GetId(), "更新成功")
+
+}
+
+// UpdatePwd 修改密码
+// @Summary 修改密码
+// @Description 修改密码
+// @Tags 个人中心
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.PassWord true "body"
+// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
+// @Router /api/user/pwd/set [put]
+// @Security Bearer
+func (e SysUser) UpdatePwd(c *gin.Context) {
+	s := service.SysUser{}
+	req := dto.PassWord{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	var hash []byte
+	if hash, err = bcrypt.GenerateFromPassword([]byte(req.NewPassword), bcrypt.DefaultCost); err != nil {
+		req.NewPassword = string(hash)
+	}
+
+	err = s.UpdatePwd(user.GetUserId(c), req.OldPassword, req.NewPassword)
+	if err != nil {
+		e.Error(http.StatusForbidden, err, err.Error())
+		return
+	}
+
+	e.OK(nil, "密码修改成功")
+
+}
+
+// GetProfile 获取个人中心用户
+// @Summary 获取个人中心用户
+// @Description 获取个人中心用户
+// @Tags 个人中心
+// @Success 200 {object} response.Response{user=model.SysUser,role=model.SysRole}  "{"code": 200, "data": {"user":[...],"role":[...]}}"
+// @Router /api/user/profile [get]
+// @Security Bearer
+func (e SysUser) GetProfile(c *gin.Context) {
+	s := service.SysUser{}
+	req := dto.SysUserById{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	req.Id = user.GetUserId(c)
+
+	sysUser := model.SysUser{}
+	err = s.GetProfile(&req, &sysUser)
+	if err != nil {
+		e.Logger.Errorf("get user profile error, %s", err.Error())
+		e.Error(500, err, "获取用户信息失败")
+		return
+	}
+	e.OK(gin.H{
+		"user": sysUser,
+	}, "查询成功")
+}
+
+// GetInfo 获取个人信息
+// @Summary 获取个人信息
+// @Description 获取个人信息
+// @Tags 个人中心
+// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
+// @Router /api/user/info [get]
+// @Security Bearer
+func (e SysUser) GetInfo(c *gin.Context) {
+	req := dto.SysUserGetReq{}
+	s := service.SysUser{}
+	r := service.SysRole{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		MakeService(&r.Service).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	var roles = make([]string, 1)
+	roles[0] = user.GetRoleName(c)
+	var permissions = make([]string, 1)
+	permissions[0] = "*:*:*"
+	var buttons = make([]string, 1)
+	buttons[0] = "*:*:*"
+
+	var mp = make(map[string]interface{})
+	mp["roles"] = roles
+	list, _ := r.GetById(user.GetRoleId(c))
+	mp["permissions"] = list
+	mp["buttons"] = list
+
+	sysUser := model.SysUser{}
+	req.Id = user.GetUserId(c)
+
+	err = s.Get(&req, nil, &sysUser)
+	if err != nil {
+		e.Logger.Errorf("get user info error, %s", err.Error())
+		e.Error(http.StatusUnauthorized, err, err.Error())
+		return
+	}
+
+	mp["userName"] = sysUser.Username
+	mp["userId"] = sysUser.Id
+	mp["deptId"] = sysUser.DeptId
+	mp["name"] = sysUser.NickName
+	mp["code"] = 200
+	e.OK(mp, "查询成功")
+}
+
+// VerifyCode 获取短信验证码
+// @Summary 获取短信验证码
+// @Description 获取短信验证码
+// @Tags 登录
+// @Accept  application/json
+// @Product application/json
+// @Success 200 {string} string "{"code": 200, "data": "18888888888"}"
+// @Router /verify-code [get]
+// @Security Bearer
+func (e SysUser) VerifyCode(c *gin.Context) {
+	s := service.SysUser{}
+	req := dto.SysUserGetSMSVerifyCodeReq{}
+	err := e.MakeContext(c).
+		MakeService(&s.Service).
+		Bind(&req, binding.Query).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	key := handler.GetVerifyCodeCacheKey(req.Phone)
+	_, err = e.Cache.Get(key)
+	// 验证吗缓存已存在
+	if err == nil {
+		e.Error(500, err, "验证吗已发送,请注意查收")
+		return
+	}
+
+	code := pkg.GenerateRandomFigureKey6()
+
+	ss := sms.NewSMS(conf.ExtConfig.SubMail.Appid, conf.ExtConfig.SubMail.Signature)
+	content := fmt.Sprintf("【气瓶追溯管理系统】您的短信验证码:%s,请在10分钟内输入", code)
+	res, err := ss.Send(req.Phone, content)
+	if err != nil || res.Status != sms.SUCCESS {
+		e.Logger.Error("发送短信验证码出现异常", zap.Any("res", res), zap.Error(err))
+		e.Error(500, err, "验证吗发送失败,请重试")
+		return
+	}
+	_ = e.Cache.Set(key, code, 600)
+	e.OK(req.Phone, "发送成功")
+
+}
+
+// GetNewestToken 获取最新token
+// @Summary 获取最新token
+// @Description 获取最新token,提供给接入服务访问,用于单一认证检查
+// @Tags 用户
+// @Param serviceId header int true "服务id"
+// @Param userId path int true "用户id"
+// @Success 200 {string} string "{"code": 200, "data": "...token..."}"
+// @Router /newest-token [get]
+func (e SysUser) GetNewestToken(c *gin.Context) {
+	s := service.SysUser{}
+	req := dto.GetNewestTokenReq{}
+	err := e.MakeContext(c).
+		MakeService(&s.Service).
+		Bind(&req, nil).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	key, err := handler.GetNewestToken(c, req.UserId)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.OK(key, "查询成功")
+}

+ 68 - 0
app/admin/controller/upload.go

@@ -0,0 +1,68 @@
+package controller
+
+import (
+	"cold-logistics/common/file_store"
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"github.com/google/uuid"
+	"gogs.baozhida.cn/zoie/OAuth-core/api"
+	"os"
+	"path/filepath"
+	"strings"
+	"time"
+)
+
+type UploadController struct {
+	api.Api
+}
+
+// FilesUpload 文件上传
+// @Summary 文件上传
+// @Description 文件上传
+// @Tags 工具
+// @Success 200 {object} response.Response{data=string,id=string,msg=string} "{"code": 200, "data": [...]}"
+// @Router /api/captcha [get]
+func (e UploadController) FilesUpload(c *gin.Context) {
+	err := e.MakeContext(c).Errors
+	if err != nil {
+		e.Error(500, err, "服务初始化失败!")
+		return
+	}
+
+	// 处理文件上传逻辑
+	file, err := c.FormFile("file")
+	//bizType := c.PostForm("bizType")
+	//correlationCode := c.PostForm("correlationCode")
+	uploadFileName := file.Filename          // 获取文件名
+	fileType := filepath.Ext(uploadFileName) // 获取文件类型(扩展名)
+	if err != nil {
+		c.JSON(400, gin.H{"error": err.Error()})
+		return
+	}
+	filePath := file_store.GetCurrentDirectory() + "/uploads/" + uploadFileName
+	err = c.SaveUploadedFile(file, filePath)
+	if err != nil {
+		c.JSON(400, gin.H{"error": err.Error()})
+		return
+	}
+
+	defer func() {
+		os.Remove(filePath)
+	}()
+
+	// TODO: 文件上传到省平台
+
+	filename := fmt.Sprintf("%s/%s%s", time.Now().Format("2006-01-02"), strings.Replace(uuid.New().String(), "-", "", -1), fileType)
+
+	err = file_store.QiniuFileStore.UpLoad(filename, filePath)
+	if err != nil {
+		c.JSON(400, gin.H{"error": "文件上传失败"})
+		return
+	}
+
+	e.Custom(gin.H{
+		"code": 200,
+		"data": filename,
+		"msg":  "success",
+	})
+}

+ 197 - 0
app/admin/controller/warehouse.go

@@ -0,0 +1,197 @@
+package controller
+
+import (
+	"cold-logistics/app/admin/model"
+	"cold-logistics/app/admin/service"
+	"cold-logistics/app/admin/service/dto"
+	"cold-logistics/common/actions"
+	"github.com/gin-gonic/gin"
+	"github.com/gin-gonic/gin/binding"
+	"gogs.baozhida.cn/zoie/OAuth-core/api"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth/user"
+	_ "gogs.baozhida.cn/zoie/OAuth-core/pkg/response"
+)
+
+type WarehouseController struct {
+	api.Api
+}
+
+// GetPage 获取仓库列表
+// @Summary 获取仓库列表
+// @Description 获取仓库列表
+// @Tags 仓库
+// @Param name query string false "仓库名称"
+// @Param pageSize query int false "页条数"
+// @Param page query int false "页码"
+// @Success 200 {object} response.Response{data=response.Page{list=[]model.Warehouse}} "{"code": 200, "data": [...]}"
+// @Router /api/warehouse [get]
+// @Security Bearer
+func (e WarehouseController) GetPage(c *gin.Context) {
+	s := service.Warehouse{}
+	req := dto.WarehouseGetPageReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.Query).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	//数据权限检查
+	p := actions.GetPermissionFromContext(c)
+
+	list := make([]model.Warehouse, 0)
+	var count int64
+
+	err = s.GetPage(&req, &list, &count, p)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
+}
+
+// Get 通过id获取仓库
+// @Summary 通过id获取仓库
+// @Description 通过id获取仓库
+// @Tags 仓库
+// @Param id path string true "仓库id"
+// @Success 200 {object} response.Response{data=model.Warehouse} "{"code": 200, "data": [...]}"
+// @Router /api/warehouse/{id} [get]
+// @Security Bearer
+func (e WarehouseController) Get(c *gin.Context) {
+	s := service.Warehouse{}
+	req := dto.WarehouseGetReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, nil).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	var object model.Warehouse
+	p := actions.GetPermissionFromContext(c)
+
+	//数据权限检查
+	err = s.Get(&req, &object, p)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	e.OK(object, "查询成功")
+}
+
+// Insert 添加仓库
+// @Summary 添加仓库
+// @Description 添加仓库
+// @Tags 仓库
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.WarehouseInsertReq true "data"
+// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
+// @Router /api/warehouse [post]
+// @Security Bearer
+func (e WarehouseController) Insert(c *gin.Context) {
+	s := service.Warehouse{}
+	req := dto.WarehouseInsertReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.JSON).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	p := actions.GetPermissionFromContext(c)
+	// 设置创建人
+	req.SetCreateBy(user.GetUserId(c))
+	req.SetDeptId(p.DeptId)
+	err = s.Insert(&req)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.OK(req.GetId(), "创建成功")
+}
+
+// Update 修改仓库
+// @Summary 修改仓库
+// @Description 修改仓库
+// @Tags 仓库
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.WarehouseUpdateReq true "body"
+// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
+// @Router /api/warehouse [put]
+// @Security Bearer
+func (e WarehouseController) Update(c *gin.Context) {
+	s := service.Warehouse{}
+	req := dto.WarehouseUpdateReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	p := actions.GetPermissionFromContext(c)
+
+	req.SetUpdateBy(user.GetUserId(c))
+	err = s.Update(&req, p)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.OK(req.GetId(), "更新成功")
+}
+
+// Delete 删除仓库
+// @Summary 删除仓库
+// @Description 删除仓库
+// @Tags 仓库
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.WarehouseDeleteReq true "body"
+// @Success 200 {string} string	"{"code": 200, "message": "删除成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "删除失败"}"
+// @Router /api/warehouse [delete]
+// @Security Bearer
+func (e WarehouseController) Delete(c *gin.Context) {
+	s := service.Warehouse{}
+	req := dto.WarehouseDeleteReq{}
+	userSvc := service.SysUser{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.JSON, nil).
+		MakeService(&s.Service).
+		MakeService(&userSvc.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	//数据权限检查
+	p := actions.GetPermissionFromContext(c)
+	err = s.Remove(&req, p)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.OK(req.GetId(), "删除成功")
+}

+ 32 - 0
app/admin/model/address.go

@@ -0,0 +1,32 @@
+package model
+
+import model2 "cold-logistics/common/model"
+
+type Address struct {
+	model2.Model
+	Name       string  `json:"name" gorm:"size:32;"`        // 收货人名称
+	Phone      string  `json:"phone" gorm:"size:32;"`       // 联系电话
+	City       string  `json:"city" gorm:"size:6;"`         // 所在地市
+	Area       string  `json:"area" gorm:"size:6;"`         // 所属区/县
+	Address    string  `json:"address" gorm:"size:128"`     // 详细地址
+	Lng        float64 `json:"lng" gorm:"size:9;"`          // 经度
+	Lat        float64 `json:"lat" gorm:"size:9;"`          // 纬度
+	IsDefault  bool    `json:"isDefault" gorm:"size:128"`   // 默认
+	AddressImg string  `json:"addressImg" gorm:"size:255;"` // 现场图片
+	model2.ControlBy
+	model2.ModelTime
+	model2.DeptBy
+}
+
+func (Address) TableName() string {
+	return "address"
+}
+
+func (e *Address) Generate() model2.ActiveRecord {
+	o := *e
+	return &o
+}
+
+func (e *Address) GetId() interface{} {
+	return e.Id
+}

+ 48 - 0
app/admin/model/sys_dept.go

@@ -0,0 +1,48 @@
+package model
+
+import (
+	model2 "cold-logistics/common/model"
+	"errors"
+	"gorm.io/gorm"
+)
+
+type SysDept struct {
+	model2.Model
+	ParentId int    `json:"parentId" gorm:""`                                     // 上级部门
+	Path     string `json:"path,omitempty" gorm:"size:255;" swaggerignore:"true"` // 路径
+	Name     string `json:"name"  gorm:"size:128;"`                               // 部门名称
+	Sort     int    `json:"sort,omitempty" gorm:"size:4;"`                        // 排序
+	Status   int    `json:"status,omitempty" gorm:"size:4;"`                      // 状态 1-停用 2-正常
+	model2.ControlBy
+	model2.ModelTime
+}
+
+func (SysDept) TableName() string {
+	return "sys_dept"
+}
+
+type SysDeptOmit struct {
+	Id   int    `json:"id,omitempty"`
+	Path string `json:"path,omitempty"` // 路径
+	Name string `json:"name,omitempty"` // 部门名称
+}
+
+func (SysDeptOmit) TableName() string {
+	return "sys_dept"
+}
+
+func (e *SysDept) Generate() model2.ActiveRecord {
+	o := *e
+	return &o
+}
+
+func (e *SysDept) GetId() interface{} {
+	return e.Id
+}
+
+func (e *SysDept) BeforeDelete(_ *gorm.DB) (err error) {
+	if e.Id == 1 {
+		return errors.New("禁止删除系统部门")
+	}
+	return
+}

+ 72 - 0
app/admin/model/sys_login_log.go

@@ -0,0 +1,72 @@
+package model
+
+import (
+	model2 "cold-logistics/common/model"
+	"encoding/json"
+	"errors"
+	"time"
+
+	log "gogs.baozhida.cn/zoie/OAuth-core/logger"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk/config"
+	"gogs.baozhida.cn/zoie/OAuth-core/storage"
+)
+
+type SysLoginLog struct {
+	model2.Model
+	Username      string    `json:"username" gorm:"size:128;comment:用户名"`
+	Status        string    `json:"status" gorm:"size:4;comment:状态"`
+	Ipaddr        string    `json:"ipaddr" gorm:"size:255;comment:ip地址"`
+	LoginLocation string    `json:"loginLocation" gorm:"size:255;comment:归属地"`
+	Browser       string    `json:"browser" gorm:"size:255;comment:浏览器"`
+	Os            string    `json:"os" gorm:"size:255;comment:系统"`
+	Platform      string    `json:"platform" gorm:"size:255;comment:固件"`
+	LoginTime     time.Time `json:"loginTime" gorm:"comment:登录时间"`
+	Remark        string    `json:"remark" gorm:"size:255;comment:备注"`
+	Msg           string    `json:"msg" gorm:"size:255;comment:信息"`
+	CreatedAt     time.Time `json:"createdAt" gorm:"comment:创建时间"`
+	UpdatedAt     time.Time `json:"updatedAt" gorm:"comment:最后更新时间"`
+	model2.ControlBy
+}
+
+func (SysLoginLog) TableName() string {
+	return "sys_login_log"
+}
+
+func (e *SysLoginLog) Generate() model2.ActiveRecord {
+	o := *e
+	return &o
+}
+
+func (e *SysLoginLog) GetId() interface{} {
+	return e.Id
+}
+
+// SaveLoginLog 从队列中获取登录日志
+func SaveLoginLog(message storage.Messager) (err error) {
+	//准备db
+	db := sdk.Runtime.GetDbByKey(config.ApplicationConfig.Host)
+	if db == nil {
+		err = errors.New("db not exist")
+		log.Errorf("host[%s]'s %s", message.GetPrefix(), err.Error())
+		return err
+	}
+	var rb []byte
+	rb, err = json.Marshal(message.GetValues())
+	if err != nil {
+		log.Errorf("json Marshal error, %s", err.Error())
+		return err
+	}
+	var l SysLoginLog
+	err = json.Unmarshal(rb, &l)
+	if err != nil {
+		log.Errorf("json Unmarshal error, %s", err.Error())
+		return err
+	}
+	err = db.Create(&l).Error
+	if err != nil {
+		log.Errorf("db create error, %s", err.Error())
+		return err
+	}
+	return nil
+}

+ 45 - 0
app/admin/model/sys_menu.go

@@ -0,0 +1,45 @@
+package model
+
+import (
+	model2 "cold-logistics/common/model"
+)
+
+type SysMenu struct {
+	model2.Model
+	ParentId   int    `json:"parentId" gorm:"size:11;"`                // 父id
+	Sort       int    `json:"sort" gorm:"size:4;"`                     // 排序
+	Visible    string `json:"visible" gorm:"size:1;default:1"`         // 1-显示 0-隐藏
+	MenuPath   string `json:"-" gorm:"size:128;" swaggerignore:"true"` // 菜单id路径 /0/1
+	Redirect   string `json:"redirect" gorm:"size:128;"`               // 重定向
+	Title      string `json:"title" gorm:"size:128;"`                  // 菜单名称
+	MenuType   string `json:"menuType" gorm:"size:1;"`                 // 菜单类型 M-目录 C-菜单 F-按钮
+	Icon       string `json:"icon" gorm:"size:128;"`                   // 图标
+	Component  string `json:"component" gorm:"size:255;"`              // 组件路径
+	IsFrame    string `json:"-" gorm:"size:128;default:0"`             // 是否外链 1-是 0-否
+	Path       string `json:"-" gorm:"size:128;"`                      // 后端路由地址
+	Name       string `json:"name" gorm:"size:255;"`                   // 路由名称
+	Permission string `json:"-" gorm:"size:255;"`                      // 权限标识
+	IsDept     int    `json:"-" gorm:"size:255;default:1"`             // 是否为企业菜单
+
+	Children []SysMenu `json:"children,omitempty" gorm:"-"`
+	model2.ControlBy
+	model2.ModelTime
+}
+
+type SysMenuSlice []SysMenu
+
+func (x SysMenuSlice) Len() int           { return len(x) }
+func (x SysMenuSlice) Less(i, j int) bool { return x[i].Sort < x[j].Sort }
+func (x SysMenuSlice) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
+func (SysMenu) TableName() string {
+	return "sys_menu"
+}
+
+func (e *SysMenu) Generate() model2.ActiveRecord {
+	o := *e
+	return &o
+}
+
+func (e *SysMenu) GetId() interface{} {
+	return e.Id
+}

+ 92 - 0
app/admin/model/sys_opera_log.go

@@ -0,0 +1,92 @@
+package model
+
+import (
+	model2 "cold-logistics/common/model"
+	"encoding/json"
+	"errors"
+	log "gogs.baozhida.cn/zoie/OAuth-core/logger"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk/config"
+	"gogs.baozhida.cn/zoie/OAuth-core/storage"
+	"time"
+)
+
+type SysOperaLog struct {
+	model2.Model
+	Title         string    `json:"title" gorm:"size:255;comment:操作模块"`
+	BusinessType  string    `json:"businessType" gorm:"size:128;comment:操作类型"`
+	BusinessTypes string    `json:"businessTypes" gorm:"size:128;comment:BusinessTypes"`
+	Method        string    `json:"method" gorm:"size:128;comment:函数"`
+	RequestMethod string    `json:"requestMethod" gorm:"size:128;comment:请求方式 GET POST PUT DELETE"`
+	OperatorType  string    `json:"operatorType" gorm:"size:128;comment:操作类型"`
+	OperaName     string    `json:"operaName" gorm:"size:128;comment:操作者"`
+	DeptName      string    `json:"deptName" gorm:"size:128;comment:机构名称"`
+	OperaUrl      string    `json:"operaUrl" gorm:"size:255;comment:访问地址"`
+	OperaIp       string    `json:"operaIp" gorm:"size:128;comment:客户端ip"`
+	OperaLocation string    `json:"operaLocation" gorm:"size:128;comment:访问位置"`
+	OperaParam    string    `json:"operaParam" gorm:"text;comment:请求参数"`
+	Status        string    `json:"status" gorm:"size:4;comment:操作状态 1:正常 2:关闭"`
+	OperaTime     time.Time `json:"operaTime" gorm:"comment:操作时间"`
+	JsonResult    string    `json:"jsonResult" gorm:"text;comment:返回数据"`
+	Remark        string    `json:"remark" gorm:"size:255;comment:备注"`
+	LatencyTime   string    `json:"latencyTime" gorm:"size:128;comment:耗时"`
+	UserAgent     string    `json:"userAgent" gorm:"size:255;comment:ua"`
+	CreatedAt     time.Time `json:"createdAt" gorm:"comment:创建时间"`
+	UpdatedAt     time.Time `json:"updatedAt" gorm:"comment:最后更新时间"`
+	model2.ControlBy
+}
+
+func (SysOperaLog) TableName() string {
+	return "sys_opera_log"
+}
+
+func (e *SysOperaLog) Generate() model2.ActiveRecord {
+	o := *e
+	return &o
+}
+
+func (e *SysOperaLog) GetId() interface{} {
+	return e.Id
+}
+
+// SaveOperaLog 从队列中获取操作日志
+func SaveOperaLog(message storage.Messager) (err error) {
+	//准备db
+	db := sdk.Runtime.GetDbByKey(config.ApplicationConfig.Host)
+	if db == nil {
+		err = errors.New("db not exist")
+		log.Errorf("host[%s]'s %s", config.ApplicationConfig.Host, err.Error())
+		// Log writing to the database ignores error
+		return nil
+	}
+	var rb []byte
+	rb, err = json.Marshal(message.GetValues())
+	if err != nil {
+		log.Errorf("json Marshal error, %s", err.Error())
+		// Log writing to the database ignores error
+		return nil
+	}
+	var l SysOperaLog
+	err = json.Unmarshal(rb, &l)
+	if err != nil {
+		log.Errorf("json Unmarshal error, %s", err.Error())
+		// Log writing to the database ignores error
+		return nil
+	}
+	// 外部调用获取身份信息,操作频繁,不做日志记录
+	if l.OperaUrl == "/api/service/userinfo" || l.OperaUrl == "/api/upload" {
+		return nil
+	}
+	// 超出100个字符返回值截断
+	if len(l.JsonResult) > 500 {
+		l.JsonResult = l.JsonResult[:500]
+	}
+	l.OperaTime = time.Now()
+	err = db.Create(&l).Error
+	if err != nil {
+		log.Errorf("db create error, %s", err.Error())
+		// Log writing to the database ignores error
+		return nil
+	}
+	return nil
+}

+ 50 - 0
app/admin/model/sys_role.go

@@ -0,0 +1,50 @@
+package model
+
+import (
+	model2 "cold-logistics/common/model"
+	coreModel "gogs.baozhida.cn/zoie/OAuth-core/model"
+
+	"errors"
+	"gorm.io/gorm"
+)
+
+type SysRole struct {
+	model2.Model
+	coreModel.Role
+	MenuIds []int `json:"menuIds" gorm:"-"`
+	model2.ControlBy
+	model2.ModelTime
+	model2.DeptBy
+}
+
+func (SysRole) TableName() string {
+	return "sys_role"
+}
+
+func (e *SysRole) Generate() model2.ActiveRecord {
+	o := *e
+	return &o
+}
+
+func (e *SysRole) GetId() interface{} {
+	return e.Id
+}
+
+var (
+	ErrForbidUpdateSysRole = errors.New("禁止修改系统角色")
+	ErrForbidDeleteSysRole = errors.New("禁止删除系统角色")
+)
+
+func (e *SysRole) BeforeDelete(_ *gorm.DB) (err error) {
+	if e.RoleKey == "admin" {
+		return ErrForbidDeleteSysRole
+	}
+	return
+}
+
+func (e *SysRole) BeforeUpdate(_ *gorm.DB) (err error) {
+	if e.RoleKey == "admin" {
+		return ErrForbidUpdateSysRole
+	}
+	return
+}

+ 74 - 0
app/admin/model/sys_role_menu.go

@@ -0,0 +1,74 @@
+package model
+
+import (
+	model2 "cold-logistics/common/model"
+	"encoding/json"
+	"errors"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk/config"
+)
+
+type SysRoleMenu struct {
+	model2.Model
+	RoleKey string `json:"roleKey" gorm:"size:128;comment:角色编码"` // 角色编码
+	MenuId  int    `json:"menuId" gorm:"size:128;comment:菜单id"`  // 菜单id
+	model2.ControlBy
+	model2.ModelTime
+}
+
+func (SysRoleMenu) TableName() string {
+	return "sys_role_menu"
+}
+
+func (e *SysRoleMenu) Generate() model2.ActiveRecord {
+	o := *e
+	return &o
+}
+
+func (e *SysRoleMenu) GetId() interface{} {
+	return e.Id
+}
+
+func GetRoleMenuCacheKey(roleKey string) string {
+	return "role_menu-" + roleKey
+}
+
+// 添加、修改、删除菜单时删除角色菜单缓存
+func DeleteAllRoleMenuCache() error {
+	//准备db
+	db := sdk.Runtime.GetDbByKey(config.ApplicationConfig.Host)
+	if db == nil {
+		return errors.New("db not exist")
+	}
+	var list []SysRole
+	err := db.Model(SysRole{}).Find(&list).Error
+	if err != nil {
+		return err
+	}
+	for _, role := range list {
+		_ = sdk.Runtime.GetCacheAdapter().Del(GetRoleMenuCacheKey(role.RoleKey) + "-0")
+		_ = sdk.Runtime.GetCacheAdapter().Del(GetRoleMenuCacheKey(role.RoleKey) + "-1")
+	}
+	return nil
+}
+
+func DeleteRoleMenuCache(roleKey string) error {
+	err := sdk.Runtime.GetCacheAdapter().Del(GetRoleMenuCacheKey(roleKey) + "-0")
+	err = sdk.Runtime.GetCacheAdapter().Del(GetRoleMenuCacheKey(roleKey) + "-1")
+	return err
+}
+
+func SetRoleMenuCache(roleKey string, menuList []SysMenu) error {
+	s, err := json.Marshal(menuList)
+	err = sdk.Runtime.GetCacheAdapter().Set(GetRoleMenuCacheKey(roleKey), s, 24*60*60)
+	return err
+}
+
+func GetRoleMenuCache(roleKey string, menuList *[]SysMenu) error {
+	s, err := sdk.Runtime.GetCacheAdapter().Get(GetRoleMenuCacheKey(roleKey))
+	if err != nil {
+		return err
+	}
+	err = json.Unmarshal([]byte(s), &menuList)
+	return err
+}

+ 110 - 0
app/admin/model/sys_user.go

@@ -0,0 +1,110 @@
+package model
+
+import (
+	model2 "cold-logistics/common/model"
+	"errors"
+	"fmt"
+	log "gogs.baozhida.cn/zoie/OAuth-core/logger"
+	coreModel "gogs.baozhida.cn/zoie/OAuth-core/model"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk/config"
+	"golang.org/x/crypto/bcrypt"
+	"gorm.io/gorm"
+)
+
+type SysUser struct {
+	model2.Model
+	coreModel.User
+	Dept SysDept `json:"dept" gorm:"->"` // 部门
+	Role SysRole `json:"role" gorm:"->"` // 角色
+	model2.ControlBy
+	model2.ModelTime
+}
+
+func (SysUser) TableName() string {
+	return "sys_user"
+}
+func (e *SysUser) Generate() model2.ActiveRecord {
+	o := *e
+	return &o
+}
+
+func (e *SysUser) GetId() interface{} {
+	return e.Id
+}
+
+// 加密
+func (e *SysUser) Encrypt() (err error) {
+	if e.Password == "" {
+		return
+	}
+
+	var hash []byte
+	if hash, err = bcrypt.GenerateFromPassword([]byte(e.Password), bcrypt.DefaultCost); err != nil {
+		return
+	} else {
+		e.Password = string(hash)
+		return
+	}
+}
+
+var (
+	ErrForbidUpdateSysUser = errors.New("禁止修改系统用户")
+	ErrForbidDeleteSysUser = errors.New("禁止删除系统用户")
+)
+
+func (e *SysUser) BeforeCreate(_ *gorm.DB) error {
+	return e.Encrypt()
+}
+
+func (e *SysUser) BeforeUpdate(_ *gorm.DB) error {
+	if e.Username == "admin" {
+		return ErrForbidUpdateSysUser
+	}
+	var err error
+	if e.Password != "" {
+		err = e.Encrypt()
+	}
+	return err
+}
+
+func (e *SysUser) BeforeDelete(_ *gorm.DB) error {
+	if e.Username == "admin" {
+		return ErrForbidDeleteSysUser
+	}
+	return nil
+}
+
+func GetUserCacheKey(id int) string {
+	return fmt.Sprintf("oauth:user:%d", id)
+}
+
+func GetUserCode(id int) (SysUser, error) {
+	var err error
+	var userModel SysUser
+	//准备db
+	db := sdk.Runtime.GetDbByKey(config.ApplicationConfig.Host)
+	if db == nil {
+		err = errors.New("db not exist")
+		log.Errorf("host[%s]'s %s", err.Error())
+		return userModel, err
+	}
+	err = db.First(&userModel, id).Error
+	if err != nil {
+		log.Errorf("db error: %s", err)
+		err = errors.New("获取用户信息失败")
+		return userModel, err
+	}
+
+	return userModel, nil
+}
+
+type SysUserOmit struct {
+	Id       int    `json:"id,omitempty"`       // 主键编码
+	NickName string `json:"nickName,omitempty"` // 昵称
+	Phone    string `json:"phone"`              // 手机号
+}
+
+func (SysUserOmit) TableName() string {
+	return "sys_user"
+}

+ 17 - 0
app/admin/model/warehouse.go

@@ -0,0 +1,17 @@
+package model
+
+import model2 "cold-logistics/common/model"
+
+// 仓库
+type Warehouse struct {
+	model2.Model
+	Name    string `json:"name" gorm:"size:128"`     // 商品名称
+	Address string `json:"address" gorm:"size:255;"` // 地址
+	model2.ControlBy
+	model2.ModelTime
+	model2.DeptBy
+}
+
+func (Warehouse) TableName() string {
+	return "warehouse"
+}

+ 24 - 0
app/admin/router/address.go

@@ -0,0 +1,24 @@
+package router
+
+import (
+	"cold-logistics/app/admin/controller"
+	"github.com/gin-gonic/gin"
+	jwt "gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth"
+)
+
+func init() {
+	routerCheckRole = append(routerCheckRole, registerAddressRouter)
+}
+
+// 需认证的路由代码
+func registerAddressRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
+	cont := controller.AddressController{}
+	r := v1.Group("/address").Use(authMiddleware.MiddlewareFunc())
+	{
+		r.GET("", cont.GetPage)
+		r.GET("/:id", cont.Get)
+		r.POST("", cont.Insert)
+		r.PUT("", cont.Update)
+		r.DELETE("", cont.Delete)
+	}
+}

+ 19 - 0
app/admin/router/captcha.go

@@ -0,0 +1,19 @@
+package router
+
+import (
+	"cold-logistics/app/admin/controller"
+	"github.com/gin-gonic/gin"
+	jwt "gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth"
+)
+
+func init() {
+	routerCheckRole = append(routerCheckRole, registerCaptchaRouter)
+}
+
+func registerCaptchaRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
+	r1 := v1.Group("")
+	{
+		cont := controller.SystemController{}
+		r1.GET("/captcha", cont.GenerateCaptchaHandler)
+	}
+}

+ 90 - 0
app/admin/router/init_router.go

@@ -0,0 +1,90 @@
+package router
+
+import (
+	"cold-logistics/common/middleware"
+	handler2 "cold-logistics/common/middleware/handler"
+	"github.com/gin-gonic/gin"
+	swaggerfiles "github.com/swaggo/files"
+	ginSwagger "github.com/swaggo/gin-swagger"
+	jwt "gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk/config"
+	"os"
+
+	log "gogs.baozhida.cn/zoie/OAuth-core/logger"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk"
+)
+
+// InitRouter 路由初始化,不要怀疑,这里用到了
+func InitRouter() {
+	var r *gin.Engine
+	h := sdk.Runtime.GetEngine()
+	if h == nil {
+		log.Fatal("not found engine...")
+		os.Exit(-1)
+	}
+	switch h.(type) {
+	case *gin.Engine:
+		r = h.(*gin.Engine)
+	default:
+		log.Fatal("not support other engine")
+		os.Exit(-1)
+	}
+
+	// the jwt middleware
+	authMiddleware, err := middleware.AuthInit()
+	if err != nil {
+		log.Fatalf("JWT Init Error, %s", err.Error())
+	}
+
+	// 注册系统路由
+	InitSysRouter(r, authMiddleware)
+
+}
+
+func InitSysRouter(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware) *gin.RouterGroup {
+	g := r.Group("")
+	// 静态文件
+	// sysStaticFileRouter(g)
+	// swagger;注意:生产环境可以注释掉
+	if config.ApplicationConfig.Mode != "prod" {
+		sysSwaggerRouter(g)
+	}
+	// 需要认证
+	sysCheckRoleRouterInit(g, authMiddleware)
+
+	return g
+}
+
+func sysSwaggerRouter(r *gin.RouterGroup) {
+	//r.GET("/swagger/admin/*any", ginSwagger.WrapHandler(swaggerfiles.NewHandler(), ginSwagger.InstanceName("admin")))
+	//r.GET("/swagger/*any", func(c *gin.Context) {
+	//	ginSwagger.DisablingWrapHandler(swaggerfiles.Handler, "SWAGGER")(c)
+	//})
+	r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler))
+}
+
+func sysCheckRoleRouterInit(r *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
+
+	v1 := r.Group("/api/")
+	{
+		v1.POST("/login", authMiddleware.LoginHandler)
+		// Refresh time can be longer than token timeout
+		v1.GET("/refresh_token", authMiddleware.RefreshHandler)
+	}
+
+	for _, f := range routerCheckRole {
+		f(v1, authMiddleware)
+	}
+	for _, f := range routerNoCheckRole {
+		f(v1)
+	}
+
+	registerBaseRouter(v1, authMiddleware)
+}
+
+func registerBaseRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
+	v1auth := v1.Group("").Use(authMiddleware.MiddlewareFunc())
+	{
+		v1auth.POST("/logout", handler2.LogOut)
+	}
+}

+ 11 - 0
app/admin/router/router.go

@@ -0,0 +1,11 @@
+package router
+
+import (
+	"github.com/gin-gonic/gin"
+	jwt "gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth"
+)
+
+var (
+	routerNoCheckRole = make([]func(*gin.RouterGroup), 0)
+	routerCheckRole   = make([]func(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware), 0)
+)

+ 28 - 0
app/admin/router/sys_dept.go

@@ -0,0 +1,28 @@
+package router
+
+import (
+	"cold-logistics/app/admin/controller"
+	"cold-logistics/common/actions"
+	"github.com/gin-gonic/gin"
+	jwt "gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth"
+)
+
+func init() {
+	routerCheckRole = append(routerCheckRole, registerCompanyRouter)
+}
+
+// 需认证的路由代码
+func registerCompanyRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
+	cont := controller.CompanyController{}
+
+	r := v1.Group("/company").Use(authMiddleware.MiddlewareFunc()).Use(actions.PermissionAction())
+	{
+		r.GET("", cont.GetPage)
+		r.GET("/:id", cont.Get)
+		r.POST("", cont.Insert)
+		r.PUT("", cont.Update)
+		r.DELETE("", cont.Delete)
+
+	}
+
+}

+ 25 - 0
app/admin/router/sys_login_log.go

@@ -0,0 +1,25 @@
+package router
+
+import (
+	"cold-logistics/common/middleware"
+	"github.com/gin-gonic/gin"
+
+	"cold-logistics/app/admin/controller"
+	jwt "gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth"
+)
+
+func init() {
+	routerCheckRole = append(routerCheckRole, registerSysLoginLogRouter)
+}
+
+// 需认证的路由代码
+func registerSysLoginLogRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
+	cont := controller.SysLoginLogController{}
+
+	r := v1.Group("/sys-login-log").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
+	{
+		r.GET("", cont.GetPage)
+		r.GET("/:id", cont.Get)
+		r.DELETE("", cont.Delete)
+	}
+}

+ 33 - 0
app/admin/router/sys_menu.go

@@ -0,0 +1,33 @@
+package router
+
+import (
+	"cold-logistics/app/admin/controller"
+	"cold-logistics/common/actions"
+	"github.com/gin-gonic/gin"
+	jwt "gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth"
+)
+
+func init() {
+	routerCheckRole = append(routerCheckRole, registerSysMenuRouter)
+}
+
+// 需认证的路由代码
+func registerSysMenuRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
+	cont := controller.SysMenuController{}
+
+	r := v1.Group("/menu").Use(authMiddleware.MiddlewareFunc())
+	{
+		r.GET("", cont.GetPage)
+		r.GET("/:id", cont.Get)
+		r.POST("", cont.Insert)
+		r.PUT("", cont.Update)
+		r.DELETE("", cont.Delete)
+	}
+
+	r1 := v1.Group("").Use(authMiddleware.MiddlewareFunc()).Use(actions.PermissionAction())
+	{
+		r1.GET("/menu-role", cont.GetMenuRole)
+		r1.GET("/menu-select", cont.MenuSelect)
+	}
+
+}

+ 24 - 0
app/admin/router/sys_opera_log.go

@@ -0,0 +1,24 @@
+package router
+
+import (
+	"cold-logistics/common/middleware"
+	"github.com/gin-gonic/gin"
+
+	"cold-logistics/app/admin/controller"
+	jwt "gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth"
+)
+
+func init() {
+	routerCheckRole = append(routerCheckRole, registerSysOperaLogRouter)
+}
+
+// 需认证的路由代码
+func registerSysOperaLogRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
+	cont := controller.SysOperaLogController{}
+	r := v1.Group("/sys-opera-log").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
+	{
+		r.GET("", cont.GetPage)
+		r.GET("/:id", cont.Get)
+		r.DELETE("", cont.Delete)
+	}
+}

+ 55 - 0
app/admin/router/sys_user.go

@@ -0,0 +1,55 @@
+package router
+
+import (
+	"cold-logistics/common/actions"
+	"cold-logistics/common/middleware"
+	"github.com/gin-gonic/gin"
+
+	"cold-logistics/app/admin/controller"
+	jwt "gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth"
+)
+
+func init() {
+	routerCheckRole = append(routerCheckRole, registerSysUserRouter)
+	routerNoCheckRole = append(routerNoCheckRole, registerSysUserRouter2)
+
+}
+
+// 需认证的路由代码
+func registerSysUserRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
+	cont := controller.SysUser{}
+	r := v1.Group("/sys-user").Use(authMiddleware.MiddlewareFunc()).Use(actions.PermissionAction())
+	{
+		r.GET("", cont.GetPage)
+		r.GET("/delivery", cont.GetDeliveryPage)
+		r.GET("/:id", cont.Get)
+		r.POST("", cont.Insert)
+		r.PUT("", cont.Update)
+		r.DELETE("", cont.Delete)
+	}
+
+	user := v1.Group("/user").Use(authMiddleware.MiddlewareFunc()).Use(actions.PermissionAction())
+	{
+		user.GET("/profile", cont.GetProfile)
+		user.GET("/info", cont.GetInfo)
+		user.PUT("/status", cont.UpdateStatus)
+		user.PUT("/pwd/set", cont.UpdatePwd)
+		user.PUT("/pwd/reset", cont.ResetPwd)
+
+	}
+
+	r3 := v1.Group("/newest-token").Use(middleware.AuthCheckService())
+	{
+		r3.GET("/:userId", cont.GetNewestToken)
+	}
+
+}
+func registerSysUserRouter2(v1 *gin.RouterGroup) {
+	cont := controller.SysUser{}
+
+	r2 := v1.Group("")
+	{
+		r2.GET("/verify-code", cont.VerifyCode)
+	}
+
+}

+ 19 - 0
app/admin/router/upload.go

@@ -0,0 +1,19 @@
+package router
+
+import (
+	"cold-logistics/app/admin/controller"
+	"github.com/gin-gonic/gin"
+	jwt "gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth"
+)
+
+func init() {
+	routerCheckRole = append(routerCheckRole, registerUploadRouter)
+}
+
+func registerUploadRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
+	r1 := v1.Group("").Use(authMiddleware.MiddlewareFunc())
+	{
+		cont := controller.UploadController{}
+		r1.POST("/upload", cont.FilesUpload)
+	}
+}

+ 26 - 0
app/admin/router/warehouse.go

@@ -0,0 +1,26 @@
+package router
+
+import (
+	"cold-logistics/app/admin/controller"
+	"cold-logistics/common/actions"
+	"github.com/gin-gonic/gin"
+	jwt "gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth"
+)
+
+func init() {
+	routerCheckRole = append(routerCheckRole, registerWarehouseRouter)
+}
+
+// 派费管理
+// 需认证的路由代码
+func registerWarehouseRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
+	cont := controller.WarehouseController{}
+	r := v1.Group("/warehouse").Use(authMiddleware.MiddlewareFunc()).Use(actions.PermissionAction())
+	{
+		r.GET("", cont.GetPage)
+		r.GET("/:id", cont.Get)
+		r.POST("", cont.Insert)
+		r.PUT("", cont.Update)
+		r.DELETE("", cont.Delete)
+	}
+}

+ 184 - 0
app/admin/service/address.go

@@ -0,0 +1,184 @@
+package service
+
+import (
+	"cold-logistics/app/admin/model"
+	"cold-logistics/app/admin/service/dto"
+	"cold-logistics/common/actions"
+	cDto "cold-logistics/common/dto"
+	"cold-logistics/common/global"
+	"errors"
+	"gogs.baozhida.cn/zoie/OAuth-core/service"
+	"gorm.io/gorm"
+)
+
+type Address struct {
+	service.Service
+}
+
+// GetPage 获取Address列表
+func (e *Address) GetPage(c *dto.AddressGetPageReq, list *[]model.Address, count *int64) error {
+	var err error
+	var data model.Address
+
+	err = e.Orm.Model(&data).
+		Scopes(
+			cDto.MakeCondition(c.GetNeedSearch()),
+			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
+		).
+		Find(list).Limit(-1).Offset(-1).
+		Count(count).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+	return nil
+}
+
+// Get 获取Address对象
+func (e *Address) Get(d *dto.AddressGetReq, carInfoModel *model.Address, p *actions.DataPermission) error {
+	err := e.Orm.
+		Scopes(actions.Permission(carInfoModel.TableName(), p)).
+		First(carInfoModel, d.GetId()).Error
+
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return global.GetNotFoundOrNoPermissionErr
+		}
+		return global.GetFailedErr
+	}
+
+	return nil
+}
+
+// Insert 创建Address对象
+func (e *Address) Insert(c *dto.AddressInsertReq) error {
+	var err error
+	var data model.Address
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	// 查询是否有其他默认地址
+	var count int64
+	err = tx.Model(&model.Address{}).Where("is_default = ? and customer_id = ?", 1, c.CustomerId).Count(&count).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.CreateFailedErr
+	}
+
+	if count > 0 && c.IsDefault == true {
+		err = tx.Model(&model.Address{}).Where("customer_id = ?", c.CustomerId).
+			Updates(map[string]interface{}{
+				"is_default": 0,
+			}).Error
+		if err != nil {
+			e.Log.Errorf("db error: %s", err)
+			return global.CreateFailedErr
+		}
+	}
+
+	// 添加角色
+	c.Generate(&data)
+	err = tx.Create(&data).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.CreateFailedErr
+	}
+	c.Id = data.Id
+	return nil
+
+}
+
+// Update 修改Address对象
+func (e *Address) Update(c *dto.AddressUpdateReq, p *actions.DataPermission) error {
+	var err error
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	var carInfoModel = model.Address{}
+	// 查询角色是否存在
+	err = e.Orm.Scopes(actions.Permission(carInfoModel.TableName(), p)).
+		First(&carInfoModel, c.GetId()).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return global.UpdateNotFoundOrNoPermissionErr
+		}
+		return global.UpdateFailedErr
+	}
+
+	if c.IsDefault == true && c.IsDefault != carInfoModel.IsDefault {
+		err = tx.Model(&model.Address{}).Where("create_by = ?", carInfoModel.UpdateBy).
+			Updates(map[string]interface{}{
+				"is_default": 0,
+			}).Error
+		if err != nil {
+			e.Log.Errorf("db error: %s", err)
+			return global.CreateFailedErr
+		}
+	}
+
+	c.Generate(&carInfoModel)
+	err = tx.Save(&carInfoModel).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.UpdateFailedErr
+	}
+
+	c.Id = carInfoModel.Id
+
+	return nil
+}
+
+// Remove 删除Address
+func (e *Address) Remove(c *dto.AddressDeleteReq, p *actions.DataPermission) error {
+	var err error
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	var carInfoModel model.Address
+
+	// 查询角色是否存在
+	err = e.Orm.Scopes(actions.Permission(carInfoModel.TableName(), p)).
+		First(&carInfoModel, c.GetId()).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return global.DeleteNotFoundOrNoPermissionErr
+		}
+		return global.DeleteFailedErr
+	}
+
+	db := tx.Delete(&carInfoModel)
+
+	if err = db.Error; err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.DeleteFailedErr
+	}
+	if db.RowsAffected == 0 {
+		return global.DeleteNotFoundOrNoPermissionErr
+	}
+
+	return nil
+}

+ 184 - 0
app/admin/service/company.go

@@ -0,0 +1,184 @@
+package service
+
+import (
+	"cold-logistics/common/actions"
+	cDto "cold-logistics/common/dto"
+	"cold-logistics/common/global"
+	"errors"
+	"gogs.baozhida.cn/zoie/OAuth-core/service"
+	"gorm.io/gorm"
+	"gorm.io/gorm/clause"
+
+	"cold-logistics/app/admin/model"
+	"cold-logistics/app/admin/service/dto"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg"
+)
+
+type Company struct {
+	service.Service
+}
+
+// GetPage 获取Address列表
+func (e *Company) GetPage(c *dto.CompanyGetPageReq, list *[]model.SysDept, count *int64) error {
+	var err error
+	var data model.Address
+
+	err = e.Orm.Model(&data).
+		Scopes(
+			cDto.MakeCondition(c.GetNeedSearch()),
+			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
+		).
+		Find(list).Limit(-1).Offset(-1).
+		Count(count).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+	return nil
+}
+
+// Get 获取SysDept对象
+func (e *Company) Get(d *dto.CompanyGetReq, deptModel *model.SysDept) error {
+	err := e.Orm.
+		First(deptModel, d.GetId()).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return global.GetNotFoundOrNoPermissionErr
+		}
+		return global.GetFailedErr
+	}
+	return nil
+}
+
+// Insert 创建SysDept对象
+func (e *Company) Insert(c *dto.CompanyInsertReq, deptId int) error {
+	var err error
+	var data model.SysDept
+	tx := e.Orm.Debug().Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	err = tx.Create(&data).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.CreateFailedErr
+	}
+
+	c.Id = data.Id
+	deptPath := pkg.IntToString(data.Id) + "/"
+	if data.ParentId != 0 {
+		var deptP model.SysDept
+		tx.First(&deptP, data.ParentId)
+		deptPath = deptP.Path + deptPath
+	} else {
+		deptPath = "/0/" + deptPath
+	}
+	var mp = map[string]string{}
+	mp["path"] = deptPath
+
+	err = tx.Model(&data).Update("path", deptPath).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.CreateFailedErr
+	}
+	return nil
+}
+
+// Update 修改SysDept对象
+func (e *Company) Update(c *dto.CompanyUpdateReq) error {
+	var err error
+	var deptModel = model.SysDept{}
+	tx := e.Orm.Debug().Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	err = tx.First(&deptModel, c.GetId()).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return global.UpdateNotFoundOrNoPermissionErr
+		}
+		return global.UpdateFailedErr
+	}
+
+	c.Generate(&deptModel)
+
+	DeptPath := pkg.IntToString(deptModel.Id) + "/"
+	if deptModel.ParentId != 0 {
+		var DeptP model.SysDept
+		tx.First(&DeptP, deptModel.ParentId)
+		DeptPath = DeptP.Path + DeptPath
+	} else {
+		DeptPath = "/0/" + DeptPath
+	}
+	deptModel.Path = DeptPath
+	db := tx.Save(&deptModel)
+	if err = db.Error; err != nil {
+		e.Log.Errorf("UpdateSysDept error: %s", err)
+		return err
+	}
+	return nil
+}
+
+// Remove 删除SysDept
+// 删除部门 同时删除其子部门、部门下的用户
+func (e *Company) Remove(d *dto.CompanyDeleteReq, p *actions.DataPermission) error {
+	var err error
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+	var dept model.SysDept
+	err = e.Orm.
+		First(&dept, d.GetId()).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return global.GetNotFoundOrNoPermissionErr
+		}
+		return global.DeleteFailedErr
+	}
+
+	var deptList = make([]model.SysDept, 0)
+	var deptIds = make([]int, 0)
+	tx.Where("path like ?", dept.Path+"%").Find(&deptList)
+
+	// 获取部门及其子部门下ID
+	for _, v := range deptList {
+		deptIds = append(deptIds, v.Id)
+	}
+
+	db := tx.Select(clause.Associations).Delete(&deptList)
+	if err = db.Error; err != nil {
+		e.Log.Errorf("Delete error: %s", err)
+		return global.DeleteFailedErr
+	}
+
+	if db.RowsAffected == 0 {
+		return global.DeleteNotFoundOrNoPermissionErr
+	}
+	// 删除部门下的用户
+	dbUser := tx.Where("dept_id in (?)", deptIds).Delete(&model.SysUser{})
+	if err = dbUser.Error; err != nil {
+		e.Log.Errorf("Delete User error: %s", err)
+		return global.DeleteFailedErr
+	}
+
+	return nil
+}

+ 111 - 0
app/admin/service/dto/address.go

@@ -0,0 +1,111 @@
+package dto
+
+import (
+	"cold-logistics/app/admin/model"
+	"cold-logistics/common/dto"
+	common "cold-logistics/common/model"
+)
+
+type AddressGetPageReq struct {
+	dto.Pagination `search:"-"`
+	Name           string `form:"name" search:"-"` // 角色名称
+	AddressOrder
+}
+
+type AddressOrder struct {
+	CreatedAtOrder string `search:"type:order;column:created_at;table:address" form:"createdAtOrder" default:"desc"`
+}
+
+func (m *AddressGetPageReq) GetNeedSearch() interface{} {
+	return *m
+}
+
+type AddressInsertReq struct {
+	Id         int     `json:"id" comment:"编码" swaggerignore:"true"` // 编码
+	CustomerId string  `json:"customerId"  swaggerignore:"true"`     // 客户id
+	Name       string  `json:"name"`                                 // 收货人名称
+	Phone      string  `json:"phone" vd:"len($)>0;msg:'手机号不能为空'"`    // 联系电话
+	City       string  `json:"city" vd:"len($)>0;msg:'所在地市不能为空'"`    // 所在地市
+	Area       string  `json:"area" vd:"len($)>0;msg:'所属区/县不能为空'"`   // 所属区/县
+	Address    string  `json:"address"`                              // 详细地址
+	IsDefault  bool    `json:"isDefault"`                            // 默认地址
+	Lng        float64 `json:"lng"`                                  // 经度
+	Lat        float64 `json:"lat"`                                  // 纬度
+}
+
+func (s *AddressInsertReq) Generate(m *model.Address) {
+	if s.Id != 0 {
+		m.Id = s.Id
+	}
+	m.Name = s.Name
+	m.Phone = s.Phone
+	m.City = s.City
+	m.Area = s.Area
+	m.Address = s.Address
+	m.IsDefault = s.IsDefault
+	m.Lng = s.Lng
+	m.Lat = s.Lat
+}
+
+func (e *AddressInsertReq) SetCustomerId(CustomerId string) {
+	e.CustomerId = CustomerId
+}
+
+func (s *AddressInsertReq) GetId() interface{} {
+	return s.Id
+}
+
+type AddressUpdateReq struct {
+	Id        int     `json:"id" comment:"编码"` // 编码
+	Name      string  `json:"name"`            // 收货人名称
+	Phone     string  `json:"phone"`           // 联系电话
+	City      string  `json:"city"`            // 所在地市
+	Area      string  `json:"area"`            // 所属区/县
+	Address   string  `json:"address"`         // 详细地址
+	IsDefault bool    `json:"isDefault"`       // 默认地址
+	Lng       float64 `json:"lng"`             // 经度
+	Lat       float64 `json:"lat"`             // 纬度
+
+	common.ControlBy `swaggerignore:"true"`
+}
+
+func (s *AddressUpdateReq) Generate(m *model.Address) {
+	if s.Id != 0 {
+		m.Id = s.Id
+	}
+	m.Name = s.Name
+	m.Phone = s.Phone
+	m.City = s.City
+	m.Area = s.Area
+	m.Address = s.Address
+	m.IsDefault = s.IsDefault
+	m.Lng = s.Lng
+	m.Lat = s.Lat
+	if s.ControlBy.UpdateBy != 0 {
+		m.UpdateBy = s.UpdateBy
+	}
+	if s.ControlBy.CreateBy != 0 {
+		m.CreateBy = s.CreateBy
+	}
+}
+
+func (s *AddressUpdateReq) GetId() interface{} {
+	return s.Id
+}
+
+type AddressGetReq struct {
+	Id int `uri:"id"`
+}
+
+func (s *AddressGetReq) GetId() interface{} {
+	return s.Id
+}
+
+type AddressDeleteReq struct {
+	Id               int `json:"id"`
+	common.ControlBy `swaggerignore:"true"`
+}
+
+func (s *AddressDeleteReq) GetId() interface{} {
+	return s.Id
+}

+ 98 - 0
app/admin/service/dto/company.go

@@ -0,0 +1,98 @@
+package dto
+
+import (
+	"cold-logistics/app/admin/model"
+	"cold-logistics/common/dto"
+	common "cold-logistics/common/model"
+)
+
+// SysDeptGetPageReq 列表或者搜索使用结构体
+type CompanyGetPageReq struct {
+	dto.Pagination `search:"-"`
+	Name           string `form:"name" search:"type:contains;column:name;table:sys_dept" example:"公司名称"` //公司名称
+	CompanyOrder
+}
+
+type CompanyOrder struct {
+	SortOrder string `search:"type:order;column:sort;table:sys_dept" form:"sort" default:"asc"` //排序 ASC 升序 DESC 降序
+}
+
+func (m *CompanyGetPageReq) GetNeedSearch() interface{} {
+	return *m
+}
+
+type CompanyInsertReq struct {
+	Id               int    `json:"id" swaggerignore:"true"`
+	ParentId         int    `json:"parentId" example:"0" vd:"?"` //上级
+	Name             string `json:"name" example:"名称" `          //名称
+	common.ControlBy `swaggerignore:"true"`
+}
+
+func (s *CompanyInsertReq) Generate(model *model.SysDept) {
+	if s.Id != 0 {
+		model.Id = s.Id
+	}
+	model.Name = s.Name
+	model.ParentId = 0
+}
+
+// GetId 获取数据对应的ID
+func (s *CompanyInsertReq) GetId() interface{} {
+	return s.Id
+}
+
+type CompanyUpdateReq struct {
+	Id               int    `json:"id" comment:"编码"`   // 编码
+	Name             string `json:"name" example:"名称"` //名称
+	common.ControlBy `swaggerignore:"true"`
+}
+
+// Generate 结构体数据转化 从 SysDeptControl 至 SysDept 对应的模型
+func (s *CompanyUpdateReq) Generate(model *model.SysDept) {
+	if s.Id != 0 {
+		model.Id = s.Id
+	}
+	model.Name = s.Name
+}
+
+// GetId 获取数据对应的ID
+func (s *CompanyUpdateReq) GetId() interface{} {
+	return s.Id
+}
+
+type CompanyGetReq struct {
+	Id int `uri:"id"`
+}
+
+func (s *CompanyGetReq) GetId() interface{} {
+	return s.Id
+}
+
+type CompanyDeleteReq struct {
+	Id int `json:"id"`
+}
+
+func (s *CompanyDeleteReq) GetId() interface{} {
+	return s.Id
+}
+
+type CompanyEnterReq struct {
+	Id int `json:"id"`
+}
+
+func (s *CompanyEnterReq) GetId() interface{} {
+	return s.Id
+}
+
+// SysDeptGetPageReq 列表或者搜索使用结构体
+type AppletCompanyGetPageReq struct {
+	Name     string `form:"name" search:"type:contains;column:name;table:sys_dept" example:"部门名称"`    //公司名称
+	District string `form:"district" search:"-" example:"520100"`                                     //所在地市
+	City     string `form:"city" search:"-" example:"520115"`                                         //所在区县
+	Type     int    `form:"type" search:"type:exact;column:type;table:sys_dept" swaggerignore:"true"` //公司类型
+	CompanyOrder
+}
+
+func (m *AppletCompanyGetPageReq) GetNeedSearch() interface{} {
+	return *m
+}

+ 58 - 0
app/admin/service/dto/sys_login_log_dto.go

@@ -0,0 +1,58 @@
+package dto
+
+import (
+	"cold-logistics/common/dto"
+	common "cold-logistics/common/model"
+	"time"
+)
+
+type SysLoginLogGetPageReq struct {
+	dto.Pagination `search:"-"`
+	Username       string `form:"username" search:"type:exact;column:username;table:sys_error: %s_log" comment:"用户名"`
+	Status         string `form:"status" search:"type:exact;column:status;table:sys_error: %s_log" comment:"状态"`
+	Ipaddr         string `form:"ipaddr" search:"type:exact;column:ipaddr;table:sys_login_log" comment:"ip地址"`
+	LoginLocation  string `form:"loginLocation" search:"type:exact;column:login_location;table:sys_login_log" comment:"归属地"`
+	BeginTime      string `form:"beginTime" search:"type:gte;column:ctime;table:sys_login_log" comment:"创建时间"`
+	EndTime        string `form:"endTime" search:"type:lte;column:ctime;table:sys_login_log" comment:"结束时间"`
+	SysLoginLogOrder
+}
+
+type SysLoginLogOrder struct {
+	CreatedAtOrder string `search:"type:order;column:created_at;table:sys_login_log" form:"createdAtOrder"`
+}
+
+func (m *SysLoginLogGetPageReq) GetNeedSearch() interface{} {
+	return *m
+}
+
+type SysLoginLogControl struct {
+	ID            int       `uri:"Id" comment:"主键"` // 主键
+	Username      string    `json:"username" comment:"用户名"`
+	Status        string    `json:"status" comment:"状态"`
+	Ipaddr        string    `json:"ipaddr" comment:"ip地址"`
+	LoginLocation string    `json:"loginLocation" comment:"归属地"`
+	Browser       string    `json:"browser" comment:"浏览器"`
+	Os            string    `json:"os" comment:"系统"`
+	Platform      string    `json:"platform" comment:"固件"`
+	LoginTime     time.Time `json:"loginTime" comment:"登录时间"`
+	Remark        string    `json:"remark" comment:"备注"`
+	Msg           string    `json:"msg" comment:"信息"`
+}
+
+type SysLoginLogGetReq struct {
+	Id int `uri:"id"`
+}
+
+func (s *SysLoginLogGetReq) GetId() interface{} {
+	return s.Id
+}
+
+// SysLoginLogDeleteReq 功能删除请求参数
+type SysLoginLogDeleteReq struct {
+	Ids              []int `json:"ids"`
+	common.ControlBy `swaggerignore:"true"`
+}
+
+func (s *SysLoginLogDeleteReq) GetId() interface{} {
+	return s.Ids
+}

+ 134 - 0
app/admin/service/dto/sys_menu.go

@@ -0,0 +1,134 @@
+package dto
+
+import (
+	"cold-logistics/app/admin/model"
+	"cold-logistics/common/dto"
+	common "cold-logistics/common/model"
+)
+
+// SysMenuGetPageReq 列表或者搜索使用结构体
+type SysMenuGetPageReq struct {
+	dto.Pagination `search:"-"`
+	Name           string `form:"name" search:"type:contains;column:name;table:sys_menu"`    // 菜单名称
+	Visible        int    `form:"visible" search:"type:exact;column:visible;table:sys_menu"` // 显示状态
+	SysMenuOrder
+}
+
+type SysMenuOrder struct {
+	SortOrder string `search:"type:order;column:sort;table:sys_menu" form:"sort" default:"ASC"` //排序 ASC 升序 DESC 降序
+}
+
+func (m *SysMenuGetPageReq) GetNeedSearch() interface{} {
+	return *m
+}
+
+type SysMenuInsertReq struct {
+	Id               int    `json:"id" swaggerignore:"true"`                                      //编码
+	Title            string `json:"title" example:"菜单名称"`                                         //菜单名称
+	Name             string `json:"name" example:"admin"`                                         //路由名称
+	Icon             string `json:"icon" example:"app-group-fill"`                                //图标
+	Path             string `json:"path" example:"/admin" swaggerignore:"true"`                   //后端路由地址
+	MenuPath         string `json:"paths" swaggerignore:"true"`                                   //id路径
+	MenuType         string `json:"menuType" example:"C"`                                         //菜单类型 M-目录 C-菜单 F-按钮
+	Permission       string `json:"permission" example:"admin:sysUser:list" swaggerignore:"true"` //权限编码
+	ParentId         int    `json:"parentId" example:"0"`                                         //上级菜单
+	Component        string `json:"component" example:"/admin/sys-user/index"`                    //组件名称
+	Sort             int    `json:"sort" example:"0"`                                             //排序
+	Visible          string `json:"visible" example:"1"`                                          //是否显示 1-显示 2-隐藏
+	IsFrame          string `json:"isFrame" example:"0" swaggerignore:"true"`                     //是否frame 1-是 2-否
+	common.ControlBy `swaggerignore:"true"`
+}
+
+func (s *SysMenuInsertReq) Generate(model *model.SysMenu) {
+	if s.Id != 0 {
+		model.Id = s.Id
+	}
+	model.Title = s.Title
+	model.Icon = s.Icon
+	model.Path = s.Path
+	model.MenuPath = s.MenuPath
+	model.MenuType = s.MenuType
+	model.Name = s.Name
+	model.ParentId = s.ParentId
+	model.Component = s.Component
+	model.Sort = s.Sort
+	model.Visible = s.Visible
+	model.IsFrame = s.IsFrame
+	if s.CreateBy != 0 {
+		model.CreateBy = s.CreateBy
+	}
+	if s.UpdateBy != 0 {
+		model.UpdateBy = s.UpdateBy
+	}
+}
+
+func (s *SysMenuInsertReq) GetId() interface{} {
+	return s.Id
+}
+
+type SysMenuUpdateReq struct {
+	Id               int    `json:"id" comment:"编码"`                            // 编码
+	Title            string `json:"title" example:"菜单名称"`                       //菜单名称
+	Name             string `json:"name" example:"admin"`                       // 路由名称
+	Icon             string `json:"icon" example:"app-group-fill"`              //图标
+	Path             string `json:"path" example:"/admin" swaggerignore:"true"` //后端路由地址
+	MenuPath         string `json:"paths" swaggerignore:"true"`                 //id路径
+	MenuType         string `json:"menuType" example:"C"`                       //菜单类型 M-目录 C-菜单 F-按钮
+	Permission       string `json:"permission" example:"admin:sysUser:list"`    //权限编码
+	ParentId         int    `json:"parentId" example:"0"`                       //上级菜单
+	Component        string `json:"component" example:"admin"`                  //组件名称
+	Sort             int    `json:"sort" example:"0"`                           //排序
+	Visible          string `json:"visible" example:"1"`                        //是否显示 1-显示 2-隐藏
+	IsFrame          string `json:"isFrame" example:"0" swaggerignore:"true"`   //是否frame 1-是 2-否
+	common.ControlBy `swaggerignore:"true"`
+}
+
+func (s *SysMenuUpdateReq) Generate(model *model.SysMenu) {
+	if s.Id != 0 {
+		model.Id = s.Id
+	}
+	model.Title = s.Title
+	model.Icon = s.Icon
+	model.Path = s.Path
+	model.MenuPath = s.MenuPath
+	model.MenuType = s.MenuType
+	model.Name = s.Name
+	model.ParentId = s.ParentId
+	model.Component = s.Component
+	model.Sort = s.Sort
+	model.Visible = s.Visible
+	model.IsFrame = s.IsFrame
+	if s.CreateBy != 0 {
+		model.CreateBy = s.CreateBy
+	}
+	if s.UpdateBy != 0 {
+		model.UpdateBy = s.UpdateBy
+	}
+}
+
+func (s *SysMenuUpdateReq) GetId() interface{} {
+	return s.Id
+}
+
+type SysMenuGetReq struct {
+	Id int `uri:"id"`
+}
+
+func (s *SysMenuGetReq) GetId() interface{} {
+	return s.Id
+}
+
+type SysMenuDeleteReq struct {
+	Id               int `json:"id"`
+	common.ControlBy `swaggerignore:"true"`
+}
+
+func (s *SysMenuDeleteReq) GetId() interface{} {
+	return s.Id
+}
+
+type MenuLabel struct {
+	Id       int         `json:"id,omitempty" gorm:"-"`
+	Label    string      `json:"label,omitempty" gorm:"-"`
+	Children []MenuLabel `json:"children,omitempty" gorm:"-"`
+}

+ 103 - 0
app/admin/service/dto/sys_opera_log_dto.go

@@ -0,0 +1,103 @@
+package dto
+
+import (
+	"cold-logistics/common/dto"
+	common "cold-logistics/common/model"
+	"time"
+
+	"cold-logistics/app/admin/model"
+)
+
+const (
+	OperaStatusEnabel  = "1" // 状态-正常
+	OperaStatusDisable = "2" // 状态-关闭
+)
+
+type SysOperaLogGetPageReq struct {
+	dto.Pagination `search:"-"`
+	Title          string `form:"title" search:"type:contains;column:title;table:sys_opera_log" comment:"操作模块"`
+	Method         string `form:"method" search:"type:contains;column:method;table:sys_opera_log" comment:"函数"`
+	RequestMethod  string `form:"requestMethod" search:"type:contains;column:request_method;table:sys_opera_log" comment:"请求方式: GET POST PUT DELETE"`
+	OperaUrl       string `form:"operaUrl" search:"type:contains;column:opera_url;table:sys_opera_log" comment:"访问地址"`
+	OperaIp        string `form:"operaIp" search:"type:exact;column:opera_ip;table:sys_opera_log" comment:"客户端ip"`
+	Status         int    `form:"status" search:"type:exact;column:status;table:sys_opera_log" comment:"状态 1:正常 2:关闭"`
+	BeginTime      string `form:"beginTime" search:"type:gte;column:created_at;table:sys_opera_log" comment:"创建时间"`
+	EndTime        string `form:"endTime" search:"type:lte;column:created_at;table:sys_opera_log" comment:"更新时间"`
+	SysOperaLogOrder
+}
+
+type SysOperaLogOrder struct {
+	CreatedAtOrder string `search:"type:order;column:created_at;table:sys_opera_log" form:"createdAtOrder"`
+}
+
+func (m *SysOperaLogGetPageReq) GetNeedSearch() interface{} {
+	return *m
+}
+
+type SysOperaLogControl struct {
+	ID            int       `uri:"Id" comment:"编码"` // 编码
+	Title         string    `json:"title" comment:"操作模块"`
+	BusinessType  string    `json:"businessType" comment:"操作类型"`
+	BusinessTypes string    `json:"businessTypes" comment:""`
+	Method        string    `json:"method" comment:"函数"`
+	RequestMethod string    `json:"requestMethod" comment:"请求方式"`
+	OperatorType  string    `json:"operatorType" comment:"操作类型"`
+	OperaName     string    `json:"operaName" comment:"操作者"`
+	DeptName      string    `json:"organName" comment:"机构名称"`
+	OperaUrl      string    `json:"operaUrl" comment:"访问地址"`
+	OperaIp       string    `json:"operaIp" comment:"客户端ip"`
+	OperaLocation string    `json:"operaLocation" comment:"访问位置"`
+	OperaParam    string    `json:"operaParam" comment:"请求参数"`
+	Status        string    `json:"status" comment:"操作状态"`
+	OperaTime     time.Time `json:"operaTime" comment:"操作时间"`
+	JsonResult    string    `json:"jsonResult" comment:"返回数据"`
+	Remark        string    `json:"remark" comment:"备注"`
+	LatencyTime   string    `json:"latencyTime" comment:"耗时"`
+	UserAgent     string    `json:"userAgent" comment:"ua"`
+}
+
+func (s *SysOperaLogControl) Generate() (*model.SysOperaLog, error) {
+	return &model.SysOperaLog{
+		Model:         common.Model{Id: s.ID},
+		Title:         s.Title,
+		BusinessType:  s.BusinessType,
+		BusinessTypes: s.BusinessTypes,
+		Method:        s.Method,
+		RequestMethod: s.RequestMethod,
+		OperatorType:  s.OperatorType,
+		OperaName:     s.OperaName,
+		DeptName:      s.DeptName,
+		OperaUrl:      s.OperaUrl,
+		OperaIp:       s.OperaIp,
+		OperaLocation: s.OperaLocation,
+		OperaParam:    s.OperaParam,
+		Status:        s.Status,
+		OperaTime:     s.OperaTime,
+		JsonResult:    s.JsonResult,
+		Remark:        s.Remark,
+		LatencyTime:   s.LatencyTime,
+		UserAgent:     s.UserAgent,
+	}, nil
+}
+
+func (s *SysOperaLogControl) GetId() interface{} {
+	return s.ID
+}
+
+type SysOperaLogGetReq struct {
+	Id int `uri:"id"`
+}
+
+func (s *SysOperaLogGetReq) GetId() interface{} {
+	return s.Id
+}
+
+// SysOperaLogDeleteReq 功能删除请求参数
+type SysOperaLogDeleteReq struct {
+	Ids              []int `json:"ids"`
+	common.ControlBy `swaggerignore:"true"`
+}
+
+func (s *SysOperaLogDeleteReq) GetId() interface{} {
+	return s.Ids
+}

+ 158 - 0
app/admin/service/dto/sys_role.go

@@ -0,0 +1,158 @@
+package dto
+
+import (
+	"cold-logistics/app/admin/model"
+	"cold-logistics/common/dto"
+	common "cold-logistics/common/model"
+)
+
+type SysRoleGetPageReq struct {
+	dto.Pagination `search:"-"`
+	Name           string `form:"name" search:"type:contains;column:name;table:sys_role"` // 角色名称
+	SysRoleOrder
+}
+
+type SysRoleOrder struct {
+	SortOrder string `form:"sort" search:"type:order;column:sort;table:sys_role" default:"asc"`
+}
+
+func (m *SysRoleGetPageReq) GetNeedSearch() interface{} {
+	return *m
+}
+
+type SysRoleInsertReq struct {
+	Id        int    `json:"id" comment:"编码" swaggerignore:"true"`       // 编码
+	Name      string `json:"name" example:"管理员"`                         // 角色名称
+	Status    string `json:"status" swaggerignore:"true"`                // 状态 1-停用 2-正常
+	RoleKey   string `json:"roleKey" swaggerignore:"true"`               // 角色代码
+	Sort      int    `json:"roleSort" example:"0" swaggerignore:"true"`  // 角色排序
+	DataScope int    `json:"dataScope" example:"1" swaggerignore:"true"` // 数据权限 1-全部数据权限 3-本机构数据权限 4-本机构及以下数据权限 5-仅本人数据权限
+	Remark    string `json:"remark" example:"备注"`                        // 备注
+	MenuIds   []int  `json:"menuIds"`
+	common.DeptBy
+	common.ControlBy `swaggerignore:"true"`
+}
+
+func (s *SysRoleInsertReq) Generate(model *model.SysRole) {
+	if s.Id != 0 {
+		model.Id = s.Id
+	}
+	model.Name = s.Name
+	model.Status = "2"
+	model.RoleKey = s.RoleKey
+	model.Sort = 0
+	model.DataScope = 3
+	model.Remark = s.Remark
+	if s.ControlBy.UpdateBy != 0 {
+		model.UpdateBy = s.UpdateBy
+	}
+	if s.ControlBy.CreateBy != 0 {
+		model.CreateBy = s.CreateBy
+	}
+	if s.DeptBy.DeptId != 0 {
+		model.DeptId = s.DeptId
+	}
+}
+
+func (s *SysRoleInsertReq) GetId() interface{} {
+	return s.Id
+}
+
+type SysRoleUpdateReq struct {
+	Id               int    `json:"id" comment:"编码"`                            // 编码
+	Name             string `form:"roleName" example:"管理员"`                     // 角色名称
+	Status           string `form:"status" example:"2" swaggerignore:"true"`    // 状态 1-停用 2-正常
+	Sort             int    `form:"roleSort" example:"0" swaggerignore:"true"`  // 角色排序
+	DataScope        int    `form:"dataScope" example:"1" swaggerignore:"true"` // 数据权限 1-全部数据权限 3-本机构数据权限 4-本机构及以下数据权限 5-仅本人数据权限
+	Remark           string `form:"remark" example:"备注"`                        // 备注
+	MenuIds          []int  `form:"menuIds"`
+	common.ControlBy `swaggerignore:"true"`
+}
+
+func (s *SysRoleUpdateReq) Generate(model *model.SysRole) {
+	if s.Id != 0 {
+		model.Id = s.Id
+	}
+	model.Name = s.Name
+	model.Status = "2"
+	model.Sort = 0
+	model.DataScope = 3
+	model.Remark = s.Remark
+	if s.ControlBy.UpdateBy != 0 {
+		model.UpdateBy = s.UpdateBy
+	}
+	if s.ControlBy.CreateBy != 0 {
+		model.CreateBy = s.CreateBy
+	}
+}
+
+func (s *SysRoleUpdateReq) GetId() interface{} {
+	return s.Id
+}
+
+type SysRoleByName struct {
+	RoleName string `form:"role"` // 角色编码
+}
+
+type SysRoleGetReq struct {
+	Id int `uri:"id"`
+}
+
+func (s *SysRoleGetReq) GetId() interface{} {
+	return s.Id
+}
+
+type SysRoleDeleteReq struct {
+	Id               int `json:"id"`
+	common.ControlBy `swaggerignore:"true"`
+}
+
+func (s *SysRoleDeleteReq) GetId() interface{} {
+	return s.Id
+}
+
+type DeptIdList struct {
+	DeptId int `json:"Id"`
+}
+
+type SysRoleUpdateRoleApiReq struct {
+	Id               int   `uri:"id" comment:"角色编码" swaggerignore:"true"` // 角色编码
+	ServiceId        int   `json:"serviceId" example:"1"`                 // 服务id
+	ApiIds           []int `json:"apiIds" example:"1,2,3"`                // api路由 id
+	common.ControlBy `swaggerignore:"true"`
+}
+
+func (s *SysRoleUpdateRoleApiReq) GetId() interface{} {
+	return s.Id
+}
+
+type SysRoleGetRoleApiListReq struct {
+	Id        int `uri:"id" comment:"角色编码" swaggerignore:"true"` // 角色编码
+	ServiceId int `form:"serviceId" example:"1"`                 // 服务id
+}
+
+func (s *SysRoleGetRoleApiListReq) GetId() interface{} {
+	return s.Id
+}
+
+type SysRoleUpdateRoleMenuReq struct {
+	Id               int   `uri:"id" comment:"角色编码" swaggerignore:"true"` // 角色编码
+	MenuIds          []int `json:"menuIds" example:"1,2,3"`               // 系统菜单id
+	common.ControlBy `swaggerignore:"true"`
+}
+
+func (s *SysRoleUpdateRoleMenuReq) GetId() interface{} {
+	return s.Id
+}
+
+type SysRoleGetRoleMenuListReq struct {
+	Id int `uri:"id" comment:"角色编码" swaggerignore:"true"` // 角色编码
+}
+
+func (s *SysRoleGetRoleMenuListReq) GetId() interface{} {
+	return s.Id
+}
+
+type SysRoleGetRoleMenuListResp struct {
+	MenuIds []int `json:"menuIds"`
+}

+ 215 - 0
app/admin/service/dto/sys_user.go

@@ -0,0 +1,215 @@
+package dto
+
+import (
+	"cold-logistics/app/admin/model"
+	dto2 "cold-logistics/common/dto"
+	model2 "cold-logistics/common/model"
+)
+
+type SysUserGetPageReq struct {
+	dto2.Pagination `search:"-"`
+	Username        string `form:"username" search:"type:contains;column:username;table:sys_user" comment:"用户名"`
+	Name            string `form:"name" search:"type:contains;column:nick_name;table:sys_user" comment:"昵称"`
+	Uuid            string `form:"uuid" search:"type:contains;column:uuid;table:sys_user" comment:"昵称"`
+	RoleId          int    `form:"roleId" search:"type:exact;column:role_id;table:sys_user" comment:"角色ID"`
+	DeptId          int    `form:"deptId" search:"type:exact;column:dept_id;table:sys_user" comment:"部门ID"`
+	Status          string `form:"status" search:"type:exact;column:status;table:sys_user" comment:"状态"`
+	UserType        int    `form:"userType" search:"-"`
+	SysUserOrder
+}
+type SysUserOrder struct {
+	//UserIdOrder    string `search:"type:order;column:id;table:sys_user" form:"userIdOrder"`
+	//UsernameOrder  string `search:"type:order;column:username;table:sys_user" form:"usernameOrder"`
+	//StatusOrder    string `search:"type:order;column:status;table:sys_user" form:"statusOrder"`
+	CreatedAtOrder string `search:"type:order;column:created_at;table:sys_user" form:"createdAtOrder" default:"desc"`
+}
+
+func (m *SysUserGetPageReq) GetNeedSearch() interface{} {
+	return *m
+}
+
+type SysUserGetDeliveryPageReq struct {
+	dto2.Pagination `search:"-"`
+	Name            string `form:"name" search:"type:contains;column:nick_name;table:sys_user" comment:"昵称"`
+	StoreId         string `form:"storeId" search:"type:exact;column:dept_id;table:sys_user" comment:"门店id"`
+}
+
+func (m *SysUserGetDeliveryPageReq) GetNeedSearch() interface{} {
+	return *m
+}
+
+type SysUserGetCountReq struct {
+	RoleIds []int `form:"roleId" search:"type:in;column:role_id;table:sys_user" comment:"角色ID"`
+	DeptIds []int `form:"deptId" search:"type:in;column:dept_id;table:sys_user" comment:"部门ID"`
+	PostIds []int `form:"postId" search:"type:in;column:post_id;table:sys_user" comment:"岗位ID"`
+}
+
+func (m *SysUserGetCountReq) GetNeedSearch() interface{} {
+	return *m
+}
+
+type ResetSysUserPwdReq struct {
+	Id               int    `json:"id" example:"1" vd:"$>0"`                 // 用户ID
+	Password         string `json:"password" example:"123456" vd:"len($)>0"` // 密码
+	model2.ControlBy `swaggerignore:"true"`
+}
+
+func (s *ResetSysUserPwdReq) GetId() interface{} {
+	return s.Id
+}
+
+func (s *ResetSysUserPwdReq) Generate(userModel *model.SysUser) {
+	if s.Id != 0 {
+		userModel.Id = s.Id
+	}
+	userModel.Password = s.Password
+	if s.ControlBy.UpdateBy != 0 {
+		userModel.UpdateBy = s.UpdateBy
+	}
+	if s.ControlBy.CreateBy != 0 {
+		userModel.CreateBy = s.CreateBy
+	}
+}
+
+type UpdateSysUserStatusReq struct {
+	Id               int    `json:"id" example:"1" vd:"$>0"`          // 用户ID
+	Status           string `json:"status" example:"2" vd:"len($)>0"` // 状态 1-停用 2-正常
+	model2.ControlBy `swaggerignore:"true"`
+}
+
+func (s *UpdateSysUserStatusReq) GetId() interface{} {
+	return s.Id
+}
+
+func (s *UpdateSysUserStatusReq) Generate(userModel *model.SysUser) {
+	if s.Id != 0 {
+		userModel.Id = s.Id
+	}
+	userModel.Status = s.Status
+	if s.ControlBy.UpdateBy != 0 {
+		userModel.UpdateBy = s.UpdateBy
+	}
+	if s.ControlBy.CreateBy != 0 {
+		userModel.CreateBy = s.CreateBy
+	}
+}
+
+type SysUserInsertReq struct {
+	Id               int    `json:"id" swaggerignore:"true" comment:"用户ID"`                    // 用户ID
+	Username         string `json:"username" example:"username" vd:"@:len($)>0;msg:'用户名不能为空'"` // 用户名
+	Password         string `json:"password" example:"123456" vd:"@:len($)>5;msg:'密码格式不正确'"`   // 密码
+	Name             string `json:"name" swaggerignore:"true"`                                 // 姓名
+	Phone            string `json:"phone" swaggerignore:"true"`                                // 手机号
+	RoleId           int    `json:"roleId" example:"1"`                                        // 角色id
+	DeptId           int    `json:"deptId" example:"1"  swaggerignore:"true"`                  // 机构id
+	Status           string `json:"status" example:"2" swaggerignore:"true"`                   // 状态 	// 货车司机绑定《道路运输从业人员从业资格证》信息
+	ProvUserId       string `json:"provUserId"  swaggerignore:"true"`                          // 省平台用户id
+	model2.ControlBy `swaggerignore:"true"`
+}
+
+func (s *SysUserInsertReq) Generate(userModel *model.SysUser) {
+	if s.Id != 0 {
+		userModel.Id = s.Id
+	}
+	userModel.Username = s.Username
+	userModel.Password = s.Password
+	userModel.NickName = s.Name
+	userModel.Phone = s.Phone
+	userModel.DeptId = s.DeptId
+	userModel.RoleId = s.RoleId
+	userModel.Status = "2"
+
+	if s.ControlBy.UpdateBy != 0 {
+		userModel.UpdateBy = s.UpdateBy
+	}
+	if s.ControlBy.CreateBy != 0 {
+		userModel.CreateBy = s.CreateBy
+	}
+}
+
+func (s *SysUserInsertReq) GetId() interface{} {
+	return s.Id
+}
+
+type SysUserUpdateReq struct {
+	Id               int    `json:"id" swaggerignore:"true" comment:"用户ID"`   // 用户ID
+	Name             string `json:"name" swaggerignore:"true"`                // 姓名
+	Phone            string `json:"phone" swaggerignore:"true"`               // 手机号
+	RoleId           int    `json:"roleId" example:"1"`                       // 角色id
+	DeptId           int    `json:"deptId" example:"1"  swaggerignore:"true"` // 机构id
+	Status           string `json:"status" example:"2" swaggerignore:"true"`  // 状态
+	ProvUserId       string `json:"provUserId"  swaggerignore:"true"`         // 省平台用户id
+	model2.ControlBy `swaggerignore:"true"`
+}
+
+func (s *SysUserUpdateReq) Generate(userModel *model.SysUser) {
+	if s.Id != 0 {
+		userModel.Id = s.Id
+	}
+	userModel.NickName = s.Name
+	userModel.Phone = s.Phone
+	userModel.DeptId = s.DeptId
+	userModel.RoleId = s.RoleId
+	userModel.Status = "2"
+	if s.ControlBy.UpdateBy != 0 {
+		userModel.UpdateBy = s.UpdateBy
+	}
+	if s.ControlBy.CreateBy != 0 {
+		userModel.CreateBy = s.CreateBy
+	}
+}
+
+func (s *SysUserUpdateReq) GetId() interface{} {
+	return s.Id
+}
+
+type SysUserGetReq struct {
+	Id int `uri:"id"`
+}
+
+func (s *SysUserGetReq) GetId() interface{} {
+	return s.Id
+}
+
+type SysUserDeleteReq struct {
+	Id               int `json:"id"`
+	model2.ControlBy `swaggerignore:"true"`
+}
+
+func (s *SysUserDeleteReq) GetId() interface{} {
+	return s.Id
+}
+
+type SysUserById struct {
+	dto2.ObjectById
+	model2.ControlBy `swaggerignore:"true"`
+}
+
+func (s *SysUserById) GetIds() interface{} {
+	return s.Ids
+}
+
+func (s *SysUserById) GetId() interface{} {
+	if len(s.Ids) > 0 {
+		s.Ids = append(s.Ids, s.Id)
+		return s.Ids
+	}
+	return s.Id
+}
+
+func (s *SysUserById) GenerateM() (model2.ActiveRecord, error) {
+	return &model.SysUser{}, nil
+}
+
+// PassWord 密码
+type PassWord struct {
+	NewPassword string `json:"newPassword" example:"123456" vd:"len($)>0"`   // 新密码
+	OldPassword string `json:"oldPassword" example:"12345678" vd:"len($)>0"` // 旧密码
+}
+
+type SysUserGetSMSVerifyCodeReq struct {
+	Phone string `form:"phone" example:"13912345678"` //手机号
+}
+type GetNewestTokenReq struct {
+	UserId int64 `uri:"userId" example:"1"` //手机号
+}

+ 92 - 0
app/admin/service/dto/warehouse.go

@@ -0,0 +1,92 @@
+package dto
+
+import (
+	"cold-logistics/app/admin/model"
+	"cold-logistics/common/dto"
+	common "cold-logistics/common/model"
+)
+
+type WarehouseGetPageReq struct {
+	dto.Pagination `search:"-"`
+	Name           string `form:"name" search:"type:contains;column:name;table:warehouse"` // 商品名称
+	WarehouseOrder
+}
+
+type WarehouseOrder struct {
+	CreatedAtOrder string `search:"type:order;column:created_at;table:warehouse" form:"createdAtOrder" default:"desc"`
+}
+
+func (m *WarehouseGetPageReq) GetNeedSearch() interface{} {
+	return *m
+}
+
+type WarehouseInsertReq struct {
+	Id               int    `json:"id" comment:"编码" swaggerignore:"true"` // 编码
+	Name             string `json:"name"`                                 // 名称
+	Address          string `json:"address"`                              // 地址
+	common.ControlBy `swaggerignore:"true"`
+	common.DeptBy    `swaggerignore:"true"`
+}
+
+func (s *WarehouseInsertReq) Generate(model *model.Warehouse) {
+	if s.Id != 0 {
+		model.Id = s.Id
+	}
+	model.Name = s.Name
+	model.Address = s.Address
+	if s.ControlBy.UpdateBy != 0 {
+		model.UpdateBy = s.UpdateBy
+	}
+	if s.ControlBy.CreateBy != 0 {
+		model.CreateBy = s.CreateBy
+	}
+	if s.DeptBy.DeptId != 0 {
+		model.DeptId = s.DeptId
+	}
+}
+
+func (s *WarehouseInsertReq) GetId() interface{} {
+	return s.Id
+}
+
+type WarehouseUpdateReq struct {
+	Id               int    `json:"id" comment:"编码"` // 编码
+	Name             string `json:"name"`            // 商品名称
+	Address          string `json:"address"`         // 备注
+	common.ControlBy `swaggerignore:"true"`
+}
+
+func (s *WarehouseUpdateReq) Generate(model *model.Warehouse) {
+	if s.Id != 0 {
+		model.Id = s.Id
+	}
+	model.Name = s.Name
+	model.Address = s.Address
+	if s.ControlBy.UpdateBy != 0 {
+		model.UpdateBy = s.UpdateBy
+	}
+	if s.ControlBy.CreateBy != 0 {
+		model.CreateBy = s.CreateBy
+	}
+}
+
+func (s *WarehouseUpdateReq) GetId() interface{} {
+	return s.Id
+}
+
+type WarehouseGetReq struct {
+	Id int `uri:"id"`
+}
+
+func (s *WarehouseGetReq) GetId() interface{} {
+	return s.Id
+}
+
+type WarehouseDeleteReq struct {
+	Id               int `json:"id"`
+	common.ControlBy `swaggerignore:"true"`
+}
+
+func (s *WarehouseDeleteReq) GetId() interface{} {
+	return s.Id
+}

+ 72 - 0
app/admin/service/sys_login_log_service.go

@@ -0,0 +1,72 @@
+package service
+
+import (
+	"cold-logistics/common/actions"
+	cDto "cold-logistics/common/dto"
+	"cold-logistics/common/global"
+	"errors"
+	"gogs.baozhida.cn/zoie/OAuth-core/service"
+
+	"gorm.io/gorm"
+
+	"cold-logistics/app/admin/model"
+	"cold-logistics/app/admin/service/dto"
+)
+
+type SysLoginLogService struct {
+	service.Service
+}
+
+// GetPage 获取SysLoginLog列表
+func (e *SysLoginLogService) GetPage(c *dto.SysLoginLogGetPageReq, list *[]model.SysLoginLog, count *int64, p *actions.DataPermission) error {
+	var err error
+	var data model.SysLoginLog
+
+	err = e.Orm.Model(&data).
+		Scopes(
+			cDto.MakeCondition(c.GetNeedSearch()),
+			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
+			actions.Permission(data.TableName(), p),
+		).
+		Find(list).Limit(-1).Offset(-1).
+		Count(count).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+	return nil
+}
+
+// Get 获取SysLoginLog对象
+func (e *SysLoginLogService) Get(d *dto.SysLoginLogGetReq, loginLogModel *model.SysLoginLog, p *actions.DataPermission) error {
+	err := e.Orm.
+		Scopes(actions.Permission(loginLogModel.TableName(), p)).
+		First(loginLogModel, d.GetId()).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return global.GetNotFoundOrNoPermissionErr
+		}
+		return global.GetFailedErr
+	}
+	return nil
+}
+
+// Remove 删除SysLoginLog
+func (e *SysLoginLogService) Remove(c *dto.SysLoginLogDeleteReq, p *actions.DataPermission) error {
+	var err error
+	var data model.SysLoginLog
+
+	db := e.Orm.
+		Scopes(actions.Permission(data.TableName(), p)).
+		Delete(&data, c.GetId())
+	if db.Error != nil {
+		err = db.Error
+		e.Log.Errorf("Delete error: %s", err)
+		return err
+	}
+	if db.RowsAffected == 0 {
+		return global.DeleteNotFoundOrNoPermissionErr
+	}
+	return nil
+}

+ 669 - 0
app/admin/service/sys_menu.go

@@ -0,0 +1,669 @@
+package service
+
+import (
+	"cold-logistics/common/actions"
+	dto2 "cold-logistics/common/dto"
+	"cold-logistics/common/global"
+	cModel "cold-logistics/common/model"
+	"encoding/json"
+	"fmt"
+	"gogs.baozhida.cn/zoie/OAuth-core/service"
+	"strings"
+
+	"github.com/pkg/errors"
+	"gorm.io/gorm"
+
+	"cold-logistics/app/admin/model"
+	"cold-logistics/app/admin/service/dto"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg"
+)
+
+type SysMenu struct {
+	service.Service
+}
+
+// GetPage 获取SysMenu列表
+func (e *SysMenu) GetPage(c *dto.SysMenuGetPageReq, menus *[]model.SysMenu) *SysMenu {
+	var menu = make([]model.SysMenu, 0)
+	err := e.getPage(c, &menu).Error
+	if err != nil {
+		_ = e.AddError(global.GetFailedErr)
+		return e
+	}
+	for i := 0; i < len(menu); i++ {
+		if menu[i].ParentId != 0 {
+			continue
+		}
+		menusInfo := SysMenuCall(&menu, menu[i])
+		*menus = append(*menus, menusInfo)
+	}
+
+	if len(*menus) == 0 {
+		parentMap, flag := getSysMenuParent(&menu)
+		if flag {
+			for i := 0; i < len(menu); i++ {
+				if parentMap[menu[i].ParentId] {
+					continue
+				}
+				menusInfo := SysMenuCall(&menu, menu[i])
+				*menus = append(*menus, menusInfo)
+			}
+		} else {
+			for i := 0; i < len(menu); i++ {
+				menusInfo := SysMenuCall(&menu, menu[i])
+				*menus = append(*menus, menusInfo)
+			}
+		}
+	}
+
+	return e
+}
+
+// 获取搜索出来的菜单的父菜单
+func getSysMenuParent(menuList *[]model.SysMenu) (map[int]bool, bool) {
+	list := *menuList
+	var flag = false
+	var parentMap = map[int]bool{}
+	for j := 0; j < len(list); j++ {
+		parentMap[list[j].ParentId] = false
+	}
+
+	for j := 0; j < len(list); j++ {
+		if _, ok := parentMap[list[j].Id]; !ok {
+			continue
+		}
+		parentMap[list[j].Id] = true
+		flag = true
+	}
+	return parentMap, flag
+}
+
+// getPage 菜单分页列表
+func (e *SysMenu) getPage(c *dto.SysMenuGetPageReq, list *[]model.SysMenu) *SysMenu {
+	var err error
+	var data model.SysMenu
+	var tempList []model.SysMenu
+	err = e.Orm.Model(&data).
+		Scopes(dto2.MakeCondition(c.GetNeedSearch())).
+		Order("id").
+		Find(&tempList).Error
+	if err != nil {
+		e.Log.Errorf("getSysMenuPage error: %s", err)
+		_ = e.AddError(err)
+		return e
+	}
+
+	// 获取菜单及其子菜单下ID
+	for _, menu := range tempList {
+		var menuList = make([]model.SysMenu, 0)
+		err = e.Orm.Where("menu_path like ?", menu.MenuPath+"%").Order(fmt.Sprintf("sort %s", c.SortOrder)).Order("id").Find(&menuList).Error
+		*list = append(*list, menuList...)
+	}
+
+	*list = DeduplicateSysMenu(*list)
+
+	return e
+}
+
+// Get 获取SysMenu对象
+func (e *SysMenu) Get(d *dto.SysMenuGetReq, menuModel *model.SysMenu) *SysMenu {
+	err := e.Orm.First(menuModel, d.GetId()).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			err = global.GetNotFoundOrNoPermissionErr
+		} else {
+			err = global.GetFailedErr
+		}
+		_ = e.AddError(err)
+		return e
+	}
+	return e
+}
+
+// Insert 创建SysMenu对象
+func (e *SysMenu) Insert(c *dto.SysMenuInsertReq) *SysMenu {
+	var err error
+	var data model.SysMenu
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	c.Generate(&data)
+	err = tx.Create(&data).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		_ = e.AddError(global.CreateFailedErr)
+		return e
+	}
+	c.Id = data.Id
+
+	menuPath, err := e.initPaths(&data)
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		_ = e.AddError(err)
+		return e
+	}
+	err = tx.Model(&data).Where("id = ?", data.Id).Update("menu_path", menuPath).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		_ = e.AddError(global.CreateFailedErr)
+		return e
+	}
+
+	// 添加菜单后删除角色菜单缓存,防止系统菜单与服务菜单不同步
+	err = model.DeleteAllRoleMenuCache()
+	if err != nil {
+		e.Log.Errorf("删除角色菜单缓存失败 %s", err)
+		_ = e.AddError(err)
+		return e
+	}
+
+	return e
+}
+
+func (e *SysMenu) initPaths(menu *model.SysMenu) (menuPath string, err error) {
+	var data model.SysMenu
+	parentMenu := new(model.SysMenu)
+	if menu.ParentId != 0 {
+		e.Orm.Model(&data).First(parentMenu, menu.ParentId)
+		if parentMenu.MenuPath == "" {
+			err = errors.New("父级menu_path异常,请尝试对当前节点父级菜单进行更新操作!")
+			return menuPath, err
+		}
+		menuPath = parentMenu.MenuPath + "/" + pkg.IntToString(menu.Id)
+	} else {
+		menuPath = "/0/" + pkg.IntToString(menu.Id)
+	}
+	return menuPath, nil
+}
+
+// Update 修改SysMenu对象
+func (e *SysMenu) Update(c *dto.SysMenuUpdateReq) *SysMenu {
+	var err error
+	tx := e.Orm.Debug().Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+	var menuModel = model.SysMenu{}
+	err = tx.First(&menuModel, c.GetId()).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			err = global.UpdateNotFoundOrNoPermissionErr
+		} else {
+			err = global.UpdateFailedErr
+		}
+		_ = e.AddError(err)
+		return e
+	}
+	oldPath := menuModel.MenuPath
+	oldParentId := menuModel.ParentId
+	c.Generate(&menuModel)
+
+	// 替换旧的path
+	if c.ParentId != oldParentId {
+		menuPath, err := e.initPaths(&menuModel)
+		if err != nil {
+			e.Log.Errorf("db error: %s", err)
+			_ = e.AddError(err)
+			return e
+		}
+		menuModel.MenuPath = menuPath
+	}
+	// 更新菜单信息
+	err = tx.Model(&menuModel).Save(&menuModel).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		_ = e.AddError(global.UpdateFailedErr)
+		return e
+	}
+	// 替换旧的path
+	if oldPath != menuModel.MenuPath {
+		var menuList []model.SysMenu
+		tx.Where("menu_path like ?", oldPath+"%").Find(&menuList)
+		for _, v := range menuList {
+			v.MenuPath = strings.Replace(v.MenuPath, oldPath, menuModel.MenuPath, 1)
+			err := tx.Model(&v).Update("menu_path", v.MenuPath).Error
+			if err != nil {
+				e.Log.Errorf("db error: %s", err)
+				_ = e.AddError(global.CreateFailedErr)
+				return e
+			}
+		}
+	}
+
+	// 修改服务菜单后删除角色菜单缓存,防止系统菜单与服务菜单不同步
+	err = model.DeleteAllRoleMenuCache()
+	if err != nil {
+		_ = e.AddError(err)
+		return e
+	}
+
+	return e
+}
+
+// Remove 删除SysMenu
+func (e *SysMenu) Remove(d *dto.SysMenuDeleteReq) *SysMenu {
+	var err error
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	var menuModel model.SysMenu
+	err = tx.First(&menuModel, d.GetId()).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			err = global.DeleteNotFoundOrNoPermissionErr
+		} else {
+			err = global.DeleteFailedErr
+		}
+		_ = e.AddError(err)
+		return e
+	}
+
+	err = e.Orm.Where("menu_path like ?", menuModel.MenuPath+"%").Delete(&model.SysMenu{}).Error
+	if err != nil {
+		e.Log.Errorf("Delete error: %s", err)
+		_ = e.AddError(global.DeleteFailedErr)
+		return e
+	}
+
+	// 删除服务菜单后删除角色菜单缓存,防止系统菜单与服务菜单不同步
+	err = model.DeleteAllRoleMenuCache()
+	if err != nil {
+		e.Log.Errorf("删除角色菜单缓存失败 %s", err)
+		_ = e.AddError(err)
+		return e
+	}
+	return e
+}
+
+// GetList 获取菜单数据
+func (e *SysMenu) GetList(c *dto.SysMenuGetPageReq, list *[]model.SysMenu) error {
+	var err error
+	var data model.SysMenu
+
+	err = e.Orm.Model(&data).
+		Scopes(
+			dto2.MakeCondition(c.GetNeedSearch()),
+		).
+		Find(list).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+	return nil
+}
+
+// SysMenuCall 构建菜单树
+func SysMenuCall(menuList *[]model.SysMenu, menu model.SysMenu) model.SysMenu {
+	list := *menuList
+
+	min := make([]model.SysMenu, 0)
+	for j := 0; j < len(list); j++ {
+
+		if menu.Id != list[j].ParentId {
+			continue
+		}
+		mi := model.SysMenu{}
+		mi.Id = list[j].Id
+		mi.Title = list[j].Title
+		mi.Icon = list[j].Icon
+		mi.Path = list[j].Path
+		mi.MenuType = list[j].MenuType
+		mi.Name = list[j].Name
+		mi.ParentId = list[j].ParentId
+		mi.Component = list[j].Component
+		mi.Sort = list[j].Sort
+		mi.Visible = list[j].Visible
+		mi.Redirect = list[j].Redirect
+		mi.CreatedAt = list[j].CreatedAt
+		mi.Children = []model.SysMenu{}
+
+		if mi.MenuType != cModel.Button {
+			ms := SysMenuCall(menuList, mi)
+			min = append(min, ms)
+		} else {
+			min = append(min, mi)
+		}
+	}
+	menu.Children = min
+	return menu
+}
+
+// DeduplicateSysMenu 菜单列表去重
+func DeduplicateSysMenu(list []model.SysMenu) []model.SysMenu {
+	seen := make(map[string]bool)
+	deduplicated := []model.SysMenu{}
+
+	for _, v := range list {
+		// 将结构体编码为 JSON 字符串
+		key, err := json.Marshal(v)
+		if err != nil {
+			// 处理错误
+			continue
+		}
+		// 将 JSON 字符串作为键插入到 map 中
+		if _, ok := seen[string(key)]; !ok {
+			seen[string(key)] = true
+			deduplicated = append(deduplicated, v)
+		}
+	}
+
+	return deduplicated
+}
+
+// menuLabelCall 递归构造组织数据
+func menuLabelCall(eList *[]model.SysMenu, organ dto.MenuLabel) dto.MenuLabel {
+	list := *eList
+
+	min := make([]dto.MenuLabel, 0)
+	for j := 0; j < len(list); j++ {
+
+		if organ.Id != list[j].ParentId {
+			continue
+		}
+		mi := dto.MenuLabel{}
+		mi.Id = list[j].Id
+		mi.Label = list[j].Title
+		mi.Children = []dto.MenuLabel{}
+		if list[j].MenuType != "F" {
+			ms := menuLabelCall(eList, mi)
+			min = append(min, ms)
+		} else {
+			min = append(min, mi)
+		}
+	}
+	if len(min) > 0 {
+		organ.Children = min
+	} else {
+		organ.Children = nil
+	}
+	return organ
+}
+
+// SetLabel 修改角色中 设置菜单基础数据
+func (e *SysMenu) SetLabel() (m []dto.MenuLabel, err error) {
+	var list []model.SysMenu
+	err = e.GetList(&dto.SysMenuGetPageReq{}, &list)
+	if err != nil {
+		return
+	}
+
+	m = make([]dto.MenuLabel, 0)
+	for i := 0; i < len(list); i++ {
+		if list[i].ParentId != 0 {
+			continue
+		}
+		e := dto.MenuLabel{}
+		e.Id = list[i].Id
+		e.Label = list[i].Title
+		menuInfo := menuLabelCall(&list, e)
+
+		m = append(m, menuInfo)
+	}
+	return
+}
+
+// menuCall 构建菜单树
+func menuCall(menuList *[]model.SysMenu, menu model.SysMenu) model.SysMenu {
+	list := *menuList
+
+	min := make([]model.SysMenu, 0)
+	for j := 0; j < len(list); j++ {
+
+		if menu.Id != list[j].ParentId {
+			continue
+		}
+		mi := model.SysMenu{}
+		mi.Id = list[j].Id
+		mi.Title = list[j].Title
+		mi.Icon = list[j].Icon
+		mi.Path = list[j].Path
+		mi.MenuType = list[j].MenuType
+		mi.Name = list[j].Name
+		mi.ParentId = list[j].ParentId
+		mi.Component = list[j].Component
+		mi.Sort = list[j].Sort
+		mi.Visible = list[j].Visible
+		mi.CreatedAt = list[j].CreatedAt
+		mi.Children = []model.SysMenu{}
+		ms := menuCall(menuList, mi)
+		min = append(min, ms)
+	}
+	menu.Children = min
+	return menu
+}
+
+// 通过roleName获取菜单列表
+func (e *SysMenu) getByRoleName(roleName string) ([]model.SysMenu, error) {
+	var err error
+
+	data := make([]model.SysMenu, 0)
+
+	if roleName == "admin" {
+		err = e.Orm.Find(&data).Error
+	} else {
+		roleMenuIds := make([]int, 0)
+		err = e.Orm.Model(&model.SysRoleMenu{}).Select("menu_id").Where("role_key = ? ", roleName).Scan(&roleMenuIds).Error
+
+		if len(roleMenuIds) > 0 {
+			if err = recursiveSetMenu(e.Orm, roleMenuIds, &data); err != nil {
+				return nil, err
+			}
+			// 菜单id及父id 去重
+			data = menuDistinct(data)
+		}
+	}
+
+	return data, err
+}
+func recursiveSetMenu(orm *gorm.DB, mIds []int, menus *[]model.SysMenu) error {
+	if len(mIds) == 0 || menus == nil {
+		return nil
+	}
+	var subMenus []model.SysMenu
+	err := orm.Where("id in ?", mIds).Find(&subMenus).Error
+	if err != nil {
+		return err
+	}
+
+	subIds := make([]int, 0)
+	for _, menu := range subMenus {
+		if menu.ParentId != 0 {
+			subIds = append(subIds, menu.ParentId)
+		}
+		//if menu.MenuType != cModel.Button {
+		//	*menus = append(*menus, menu)
+		//}
+		*menus = append(*menus, menu)
+	}
+	return recursiveSetMenu(orm, subIds, menus)
+}
+
+// 去掉重复菜单
+func menuDistinct(menuList []model.SysMenu) (result []model.SysMenu) {
+	distinctMap := make(map[int]struct{}, len(menuList))
+	for _, menu := range menuList {
+		if _, ok := distinctMap[menu.Id]; !ok {
+			distinctMap[menu.Id] = struct{}{}
+			result = append(result, menu)
+		}
+	}
+	return result
+}
+
+// SetMenuRole 获取左侧菜单树使用
+func (e *SysMenu) SetMenuRole(roleKey string, userId int, p *actions.DataPermission) (m []model.SysMenu, err error) {
+	// 从缓存获取角色关联的菜单
+	var cacheKey string
+	if p.DeptId > 0 {
+		//cacheKey = fmt.Sprintf("%s-1-%d", roleKey, userId)
+		cacheKey = fmt.Sprintf("%s-1", roleKey)
+	} else {
+		//cacheKey = fmt.Sprintf("%s-0-%d", roleKey, userId)
+		cacheKey = fmt.Sprintf("%s-0", roleKey)
+	}
+	if err := model.GetRoleMenuCache(cacheKey, &m); err == nil {
+		return m, nil
+	}
+	menus, err := e.getByRoleName(roleKey)
+	if err != nil {
+		return m, global.GetFailedErr
+	}
+	m = make([]model.SysMenu, 0)
+
+	var menuList []model.SysMenu
+
+	if p.DeptId == 0 {
+		if roleKey == "admin" {
+			err = e.Orm.Table("sys_menu").
+				Where("sys_menu.visible = 1 and sys_menu.deleted_at is null and is_dept = 0").
+				Order("sys_menu.sort").
+				Order("id").
+				Scan(&menuList).Error
+			if err != nil {
+				return m, global.GetFailedErr
+			}
+		} else {
+			menuIds := make([]int, 0)
+			for _, menu := range menus {
+				menuIds = append(menuIds, menu.Id)
+			}
+			err = e.Orm.Table("sys_menu").
+				Where("sys_menu.id in (?) and sys_menu.visible = 1 and sys_menu.deleted_at is null and is_dept = 0", menuIds).
+				Order("sys_menu.sort").
+				Order("id").
+				Scan(&menuList).Error
+			if err != nil {
+				return m, global.GetFailedErr
+			}
+		}
+	} else {
+
+		if roleKey == "admin" {
+			err = e.Orm.Table("sys_menu").
+				Where("sys_menu.visible = 1 and sys_menu.deleted_at is null").
+				Order("sys_menu.sort").
+				Order("id").
+				Scan(&menuList).Error
+			if err != nil {
+				return m, global.GetFailedErr
+			}
+		} else {
+			menuIds := make([]int, 0)
+			for _, menu := range menus {
+				menuIds = append(menuIds, menu.Id)
+			}
+			err = e.Orm.Table("sys_menu").
+				Where("sys_menu.id in (?) and sys_menu.visible = 1 and sys_menu.deleted_at is null", menuIds).
+				Order("sys_menu.sort").
+				Order("id").
+				Scan(&menuList).Error
+			if err != nil {
+				return m, global.GetFailedErr
+			}
+		}
+	}
+
+	//sort.Sort(model.SysMenuSlice(menuList))
+	for i := 0; i < len(menuList); i++ {
+		if menuList[i].ParentId != 0 {
+			continue
+		}
+		menusInfo := menuCall(&menuList, menuList[i])
+		m = append(m, menusInfo)
+	}
+	// 保存角色菜单到缓存
+	_ = model.SetRoleMenuCache(cacheKey, m)
+	return
+}
+func (e *SysMenu) MenuSelect(roleKey string, userId int, p *actions.DataPermission) (m []model.SysMenu, err error) {
+
+	menus, err := e.getByRoleName(roleKey)
+	if err != nil {
+		return m, global.GetFailedErr
+	}
+	m = make([]model.SysMenu, 0)
+
+	var menuList []model.SysMenu
+
+	if p.DeptId == 0 {
+		if roleKey == "admin" {
+			err = e.Orm.Table("sys_menu").
+				Where("sys_menu.visible = 1 and sys_menu.deleted_at is null").
+				Order("sys_menu.sort").
+				Order("id").
+				Scan(&menuList).Error
+			if err != nil {
+				return m, global.GetFailedErr
+			}
+		} else {
+			menuIds := make([]int, 0)
+			for _, menu := range menus {
+				menuIds = append(menuIds, menu.Id)
+			}
+			err = e.Orm.Table("sys_menu").
+				Where("sys_menu.id in (?) and sys_menu.visible = 1 and sys_menu.deleted_at is null", menuIds).
+				Order("sys_menu.sort").
+				Order("id").
+				Scan(&menuList).Error
+			if err != nil {
+				return m, global.GetFailedErr
+			}
+		}
+	} else {
+
+		if roleKey == "admin" {
+			err = e.Orm.Table("sys_menu").
+				Where("sys_menu.visible = 1 and sys_menu.deleted_at is null").
+				Order("sys_menu.sort").
+				Order("id").
+				Scan(&menuList).Error
+			if err != nil {
+				return m, global.GetFailedErr
+			}
+		} else {
+			menuIds := make([]int, 0)
+			for _, menu := range menus {
+				menuIds = append(menuIds, menu.Id)
+			}
+			err = e.Orm.Table("sys_menu").
+				Where("sys_menu.id in (?) and sys_menu.visible = 1 and sys_menu.deleted_at is null", menuIds).
+				Order("sys_menu.sort").
+				Order("id").
+				Scan(&menuList).Error
+			if err != nil {
+				return m, global.GetFailedErr
+			}
+		}
+	}
+
+	//sort.Sort(model.SysMenuSlice(menuList))
+	for i := 0; i < len(menuList); i++ {
+		if menuList[i].ParentId != 0 {
+			continue
+		}
+		menusInfo := menuCall(&menuList, menuList[i])
+		m = append(m, menusInfo)
+	}
+	return
+}

+ 84 - 0
app/admin/service/sys_opera_log_service.go

@@ -0,0 +1,84 @@
+package service
+
+import (
+	"cold-logistics/common/actions"
+	cDto "cold-logistics/common/dto"
+	"cold-logistics/common/global"
+	"errors"
+	"gogs.baozhida.cn/zoie/OAuth-core/service"
+	"gorm.io/gorm"
+
+	"cold-logistics/app/admin/model"
+	"cold-logistics/app/admin/service/dto"
+)
+
+type SysOperaLog struct {
+	service.Service
+}
+
+// GetPage 获取SysOperaLog列表
+func (e *SysOperaLog) GetPage(c *dto.SysOperaLogGetPageReq, list *[]model.SysOperaLog, count *int64, p *actions.DataPermission) error {
+	var err error
+	var data model.SysOperaLog
+
+	err = e.Orm.Model(&data).
+		Scopes(
+			cDto.MakeCondition(c.GetNeedSearch()),
+			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
+			actions.Permission(data.TableName(), p),
+		).
+		Find(list).Limit(-1).Offset(-1).
+		Count(count).Error
+	if err != nil {
+		e.Log.Errorf("Service GetSysOperaLogPage error: %s", err.Error())
+		return global.GetFailedErr
+	}
+	return nil
+}
+
+// Get 获取SysOperaLog对象
+func (e *SysOperaLog) Get(d *dto.SysOperaLogGetReq, operaLogModel *model.SysOperaLog, p *actions.DataPermission) error {
+	err := e.Orm.
+		Scopes(actions.Permission(operaLogModel.TableName(), p)).
+		First(operaLogModel, d.GetId()).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return global.GetNotFoundOrNoPermissionErr
+		}
+		return global.GetFailedErr
+	}
+	return nil
+}
+
+// Insert 创建SysOperaLog对象
+func (e *SysOperaLog) Insert(operaLogModel *model.SysOperaLog) error {
+	var err error
+	var data model.SysOperaLog
+
+	err = e.Orm.Model(&data).
+		Create(operaLogModel).Error
+	if err != nil {
+		e.Log.Errorf("Service InsertSysOperaLog error: %s", err.Error())
+		return global.CreateFailedErr
+	}
+	return nil
+}
+
+// Remove 删除SysOperaLog
+func (e *SysOperaLog) Remove(d *dto.SysOperaLogDeleteReq, p *actions.DataPermission) error {
+	var err error
+	var data model.SysOperaLog
+
+	db := e.Orm.
+		Scopes(actions.Permission(data.TableName(), p)).
+		Delete(&data, d.GetId())
+	if err = db.Error; err != nil {
+		e.Log.Errorf("Service RemoveSysOperaLog error: %s", err.Error())
+		return global.DeleteFailedErr
+	}
+	if db.RowsAffected == 0 {
+		return global.DeleteNotFoundOrNoPermissionErr
+	}
+	return nil
+}

+ 404 - 0
app/admin/service/sys_role.go

@@ -0,0 +1,404 @@
+package service
+
+import (
+	"cold-logistics/common/actions"
+	cDto "cold-logistics/common/dto"
+	"cold-logistics/common/global"
+	"errors"
+	"fmt"
+	"github.com/casbin/casbin/v2"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/utils"
+	"gogs.baozhida.cn/zoie/OAuth-core/service"
+	"strings"
+
+	"cold-logistics/app/admin/model"
+	"cold-logistics/app/admin/service/dto"
+	"gorm.io/gorm"
+)
+
+type SysRole struct {
+	service.Service
+}
+
+// GetPage 获取SysRole列表
+func (e *SysRole) GetPage(c *dto.SysRoleGetPageReq, list *[]model.SysRole, count *int64, p *actions.DataPermission) error {
+	var err error
+	var data model.SysRole
+
+	err = e.Orm.Model(&data).
+		Scopes(
+			cDto.MakeCondition(c.GetNeedSearch()),
+			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
+			actions.Permission(data.TableName(), p),
+		).
+		Find(list).Limit(-1).Offset(-1).
+		Count(count).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+	return nil
+}
+
+// Get 获取SysRole对象
+func (e *SysRole) Get(d *dto.SysRoleGetReq, roleModel *model.SysRole, p *actions.DataPermission) error {
+	err := e.Orm.
+		Scopes(actions.Permission(roleModel.TableName(), p)).
+		First(roleModel, d.GetId()).Error
+
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return global.GetNotFoundOrNoPermissionErr
+		}
+		return global.GetFailedErr
+	}
+	roleModel.MenuIds, err = e.GetRoleMenuId(roleModel.Id)
+	if err != nil {
+		e.Log.Errorf("get menuIds error, %s", err)
+		return global.GetFailedErr
+	}
+
+	return nil
+}
+
+// Insert 创建SysRole对象
+func (e *SysRole) Insert(c *dto.SysRoleInsertReq) error {
+	var err error
+	var data model.SysRole
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	var roleKey string
+	for {
+		var count int64
+		roleKey = utils.GetRandString(8, "", 0)
+		var i int64
+		err = tx.Model(&data).Where("role_key = ?", roleKey).Count(&count).Error
+		if err != nil {
+			continue
+		}
+		if i == 0 {
+			break
+		}
+	}
+	// 添加角色
+	c.Generate(&data)
+	data.RoleKey = roleKey
+	err = tx.Create(&data).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.CreateFailedErr
+	}
+	c.Id = data.Id
+
+	// 添加角色菜单关联
+	var menuList []model.SysMenu
+	err = e.Orm.Where("id in (?)", c.MenuIds).Find(&menuList).Error
+	if err != nil {
+		return global.GetFailedErr
+	}
+	if len(menuList) == 0 {
+		return errors.New("菜单不存在!")
+	}
+
+	var roleMenuList []model.SysRoleMenu
+	// 添加角色关联的菜单
+	for _, v := range menuList {
+		roleMenuObj := model.SysRoleMenu{
+			RoleKey: data.RoleKey,
+			MenuId:  v.Id,
+		}
+		roleMenuObj.SetCreateBy(c.CreateBy)
+		roleMenuList = append(roleMenuList, roleMenuObj)
+
+	}
+	err = tx.Save(&roleMenuList).Error
+	if err != nil {
+		e.Log.Errorf("save menuIds error, %s", err)
+		return global.UpdateFailedErr
+	}
+	return nil
+
+}
+
+// Update 修改SysRole对象
+func (e *SysRole) Update(c *dto.SysRoleUpdateReq, p *actions.DataPermission) error {
+	var err error
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	var roleModel = model.SysRole{}
+	// 查询角色是否存在
+	err = e.Orm.Scopes(actions.Permission(roleModel.TableName(), p)).
+		First(&roleModel, c.GetId()).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return global.UpdateNotFoundOrNoPermissionErr
+		}
+		return global.UpdateFailedErr
+	}
+
+	c.Generate(&roleModel)
+	err = tx.Save(&roleModel).Error
+	if err != nil {
+		if errors.Is(err, model.ErrForbidUpdateSysRole) {
+			return err
+		}
+		e.Log.Errorf("db error: %s", err)
+		return global.UpdateFailedErr
+	}
+
+	// 删除角色关联的菜单
+	err = tx.Where("role_key = ?", roleModel.RoleKey).Delete(&model.SysRoleMenu{}).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.UpdateFailedErr
+	}
+	var menuList []model.SysMenu
+	err = e.Orm.Where("id in (?)", c.MenuIds).Find(&menuList).Error
+	if err != nil {
+		return global.GetFailedErr
+	}
+	if len(menuList) == 0 {
+		return errors.New("菜单不存在!")
+	}
+
+	var roleMenuList []model.SysRoleMenu
+	// 添加角色关联的菜单
+	for _, v := range menuList {
+		roleMenuObj := model.SysRoleMenu{
+			RoleKey: roleModel.RoleKey,
+			MenuId:  v.Id,
+		}
+		roleMenuObj.SetCreateBy(c.UpdateBy)
+		roleMenuList = append(roleMenuList, roleMenuObj)
+
+	}
+	err = tx.Save(&roleMenuList).Error
+	if err != nil {
+		e.Log.Errorf("save menuIds error, %s", err)
+		return global.UpdateFailedErr
+	}
+	if err := model.DeleteRoleMenuCache(roleModel.RoleKey); err != nil {
+		e.Log.Errorf("delete role menu cache error, %s", err)
+		return global.UpdateFailedErr
+	}
+	model.DeleteRoleMenuCache(model.GetRoleMenuCacheKey(roleModel.RoleKey) + "-0")
+	model.DeleteRoleMenuCache(model.GetRoleMenuCacheKey(roleModel.RoleKey) + "-1")
+	//redisClient := storage.GetRedisClient()
+	////获取相似的 Key
+	//keys, err := redisClient.Keys("/" + model.GetRoleMenuCacheKey(roleModel.RoleKey) + "*").Result()
+	//if err != nil {
+	//	return global.UpdateFailedErr
+	//}
+	////删除相似的 Key
+	//if len(keys) > 0 {
+	//	_, err = redisClient.Del(keys...).Result()
+	//	if err != nil {
+	//		return global.UpdateFailedErr
+	//	}
+	//}
+
+	c.Id = roleModel.Id
+
+	return nil
+}
+
+// Remove 删除SysRole
+func (e *SysRole) Remove(c *dto.SysRoleDeleteReq, p *actions.DataPermission, cb *casbin.SyncedEnforcer) error {
+	var err error
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	var userList = make([]model.SysUser, 0)
+	var roleModel model.SysRole
+	err = e.Orm.Where("role_id = ?", c.Id).Find(&userList).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.DeleteFailedErr
+	}
+
+	// 统计与用户关联的角色名
+	if len(userList) > 0 {
+		var roleNameStr string
+		for i := 0; i < len(userList); i++ {
+			roleNameStr += fmt.Sprintf(" %s,", userList[i].Username)
+		}
+		if !pkg.IsEmptyStr(roleNameStr) {
+			// eg: role1,role2有用户关联,禁止删除!
+			return errors.New(strings.TrimRight(roleNameStr, ",") + "有用户关联,禁止删除!")
+		}
+	}
+
+	// 查询角色是否存在
+	err = e.Orm.Scopes(actions.Permission(roleModel.TableName(), p)).
+		First(&roleModel, c.GetId()).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return global.DeleteNotFoundOrNoPermissionErr
+		}
+		return global.DeleteFailedErr
+	}
+	db := tx.Delete(&roleModel)
+
+	if err = db.Error; err != nil {
+		if errors.Is(err, model.ErrForbidDeleteSysRole) {
+			return err
+		}
+		e.Log.Errorf("db error: %s", err)
+		return global.DeleteFailedErr
+	}
+	if db.RowsAffected == 0 {
+		return global.DeleteNotFoundOrNoPermissionErr
+	}
+
+	// 删除之前的角色关联的菜单
+	var roleMenu model.SysRoleMenu
+	err = tx.Where("role_key = ?", roleModel.RoleKey).Delete(&roleMenu).Error
+	if err != nil {
+		return global.UpdateFailedErr
+	}
+
+	// 清除 sys_casbin_rule 权限表里 当前角色的所有记录
+	_, _ = cb.RemoveFilteredPolicy(0, roleModel.RoleKey)
+
+	return nil
+}
+
+// GetRoleMenuId 获取角色对应的菜单ids
+func (e *SysRole) GetRoleMenuId(roleId int) ([]int, error) {
+	var err error
+	var roleModel model.SysRole
+	var menuIds []int
+	err = e.Orm.Where("id = ?", roleId).First(&roleModel).Error
+	if err != nil {
+		return []int{}, global.GetFailedErr
+	}
+
+	err = e.Orm.Model(&model.SysRoleMenu{}).Select("menu_id").Where("role_key = ? ", roleModel.RoleKey).Scan(&menuIds).Error
+	if err != nil {
+		return []int{}, global.GetFailedErr
+	}
+	return menuIds, nil
+}
+
+// GetWithName 获取SysRole对象
+func (e *SysRole) GetWithName(d *dto.SysRoleByName, roleModel *model.SysRole) *SysRole {
+	err := e.Orm.Where("name = ?", d.RoleName).First(roleModel).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			err = global.GetNotFoundOrNoPermissionErr
+		} else {
+			err = global.GetFailedErr
+		}
+		_ = e.AddError(err)
+		return e
+	}
+
+	//roleModel.MenuIds, err = e.GetRoleMenuId(roleModel.Id)
+	if err != nil {
+		e.Log.Errorf("get menuIds error, %s", err.Error())
+		_ = e.AddError(global.GetFailedErr)
+		return e
+	}
+	return e
+}
+
+// GetById 获取SysRole对象
+func (e *SysRole) GetById(roleId int) ([]string, error) {
+	permissions := make([]string, 0)
+	roleModel := model.SysRole{}
+	roleModel.Id = roleId
+	err := e.Orm.Model(&roleModel).First(&roleModel).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			err = global.GetNotFoundOrNoPermissionErr
+		} else {
+			err = global.GetFailedErr
+		}
+		return nil, err
+	}
+	//l := *roleModel.SysMenu
+	//for i := 0; i < len(l); i++ {
+	//	permissions = append(permissions, l[i].Title)
+	//}
+	return permissions, nil
+}
+
+// UpdateRoleMenu 修改角色绑定的菜单
+func (e *SysRole) UpdateRoleMenu(d *dto.SysRoleUpdateRoleMenuReq) error {
+	var err error
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+	var roleModel model.SysRole
+	err = e.Orm.Where("id = ?", d.GetId()).First(&roleModel).Error
+	if err != nil {
+		return global.GetFailedErr
+	}
+
+	var menuList []model.SysMenu
+	err = e.Orm.Where("id in (?)", d.MenuIds).Find(&menuList).Error
+	if err != nil {
+		return global.GetFailedErr
+	}
+	if len(menuList) == 0 {
+		return errors.New("菜单不存在!")
+	}
+
+	// 删除之前的角色关联的菜单
+	var roleMenu model.SysRoleMenu
+	err = tx.Where("role_key = ?", roleModel.RoleKey).Delete(&roleMenu).Error
+	if err != nil {
+		return global.UpdateFailedErr
+	}
+	var roleMenuList []model.SysRoleMenu
+	// 添加角色关联的菜单
+	for _, v := range menuList {
+		roleMenuObj := model.SysRoleMenu{
+			RoleKey: roleModel.RoleKey,
+			MenuId:  v.Id,
+		}
+		roleMenuObj.SetCreateBy(d.CreateBy)
+		roleMenuList = append(roleMenuList, roleMenuObj)
+
+	}
+	err = tx.Save(&roleMenuList).Error
+	if err != nil {
+		e.Log.Errorf("save menuIds error, %s", err)
+		return global.UpdateFailedErr
+	}
+	return nil
+}

+ 414 - 0
app/admin/service/sys_user.go

@@ -0,0 +1,414 @@
+package service
+
+import (
+	"cold-logistics/app/admin/model"
+	"cold-logistics/app/admin/service/dto"
+	"cold-logistics/common/actions"
+	cDto "cold-logistics/common/dto"
+	"cold-logistics/common/global"
+	"errors"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/utils"
+	"gogs.baozhida.cn/zoie/OAuth-core/service"
+	"gorm.io/gorm"
+)
+
+type SysUser struct {
+	service.Service
+}
+
+// GetPage 获取SysUser列表
+func (e *SysUser) GetPage(c *dto.SysUserGetPageReq, p *actions.DataPermission, list *[]model.SysUser, count *int64) error {
+	var err error
+	var data model.SysUser
+	var userList []model.SysUser
+	if c.UserType > 0 {
+		err = e.Orm.
+			Scopes(
+				cDto.MakeCondition(c.GetNeedSearch()),
+				cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
+				actions.UserPermission(data.TableName(), p),
+			).
+			Where("JSON_EXTRACT(prov_user, '$.userType') = ?", c.UserType).
+			Find(&userList).Limit(-1).Offset(-1).
+			Count(count).Error
+	} else {
+		err = e.Orm.
+			Scopes(
+				cDto.MakeCondition(c.GetNeedSearch()),
+				cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
+				actions.UserPermission(data.TableName(), p),
+			).
+			Find(&userList).Limit(-1).Offset(-1).
+			Count(count).Error
+	}
+
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+
+	for i := 0; i < len(userList); i++ {
+		var dept model.SysDept
+		var role model.SysRole
+		//var post model.SysPost
+		err = e.Orm.First(&dept, userList[i].DeptId).Error
+		userList[i].Dept = dept
+
+		err = e.Orm.First(&role, userList[i].RoleId).Error
+		userList[i].Role = role
+
+		//err = e.Orm.First(&post, userList[i].PostId).Error
+		//userList[i].Post = post
+	}
+	*list = userList
+	return nil
+}
+
+// GetPage 获取送气员列表
+func (e *SysUser) GetDeliveryPage(c *dto.SysUserGetDeliveryPageReq, p *actions.DataPermission, list *[]model.SysUser, count *int64) error {
+	var err error
+	var data model.SysUser
+	var userList []model.SysUser
+
+	err = e.Orm.
+		Scopes(
+			cDto.MakeCondition(c.GetNeedSearch()),
+			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
+			actions.UserPermission(data.TableName(), p),
+		).Where("JSON_EXTRACT(prov_user, '$.userType') = 3 and JSON_EXTRACT(prov_user, '$.isorders') = 0").
+		Find(&userList).Limit(-1).Offset(-1).
+		Count(count).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+
+	for i := 0; i < len(userList); i++ {
+		var dept model.SysDept
+		var role model.SysRole
+		//var post model.SysPost
+		err = e.Orm.First(&dept, userList[i].DeptId).Error
+		userList[i].Dept = dept
+
+		err = e.Orm.First(&role, userList[i].RoleId).Error
+		userList[i].Role = role
+
+		//err = e.Orm.First(&post, userList[i].PostId).Error
+		//userList[i].Post = post
+	}
+	*list = userList
+	return nil
+}
+
+func (e *SysUser) GetCount(c *dto.SysUserGetCountReq, count *int64) error {
+	var err error
+	var data model.SysUser
+	err = e.Orm.Model(&data).
+		Scopes(
+			cDto.MakeCondition(c.GetNeedSearch()),
+		).Count(count).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+
+	return nil
+}
+
+// Get 获取SysUser对象
+func (e *SysUser) Get(d *dto.SysUserGetReq, p *actions.DataPermission, userModel *model.SysUser) error {
+	var data model.SysUser
+	var dept model.SysDept
+	var role model.SysRole
+	//var post model.SysPost
+	err := e.Orm.Model(&data).
+		Scopes(actions.UserPermission(data.TableName(), p)).
+		First(userModel, d.GetId()).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return global.GetNotFoundOrNoPermissionErr
+		}
+		return global.GetFailedErr
+	}
+	err = e.Orm.First(&dept, userModel.DeptId).Error
+	userModel.Dept = dept
+
+	err = e.Orm.First(&role, userModel.RoleId).Error
+	userModel.Role = role
+
+	//err = e.Orm.First(&post, userModel.PostId).Error
+	//userModel.Post = post
+
+	return nil
+}
+func (e *SysUser) GetByProvUserId(provUserId string, userModel *model.SysUser) error {
+	var data model.SysUser
+	var dept model.SysDept
+	//var role model.SysRole
+	//var post model.SysPost
+	err := e.Orm.Model(&data).Where("prov_user_id = ?", provUserId).Preload("Dept").First(userModel).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return global.GetNotFoundOrNoPermissionErr
+		}
+		return global.GetFailedErr
+	}
+	err = e.Orm.First(&dept, userModel.DeptId).Error
+	userModel.Dept = dept
+	//
+	//err = e.Orm.First(&role, userModel.RoleId).Error
+	//userModel.Role = role
+
+	//err = e.Orm.First(&post, userModel.PostId).Error
+	//userModel.Post = post
+
+	return nil
+}
+
+// Insert 创建SysUser对象
+func (e *SysUser) Insert(c *dto.SysUserInsertReq) error {
+	var err error
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+	var data model.SysUser
+	var i int64
+	err = e.Orm.Model(&data).Where("username = ?", c.Username).Count(&i).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.CreateFailedErr
+	}
+	if i > 0 {
+		err = errors.New("用户名已存在!")
+		e.Log.Errorf("db error: %s", err)
+		return err
+	}
+
+	// TODO 1.1.1.7新增用户信息
+	// TODO 1.1.1.10送气人员绑定资质信息
+	// TODO 1.1.1.11货车司机绑定资质信息
+
+	var uuid string
+	for {
+		uuid = utils.GetUUID()
+		var j int64
+		err = e.Orm.Model(&data).Where("uuid = ?", uuid).Count(&j).Error
+		if err != nil {
+			continue
+		}
+		if j == 0 {
+			break
+		}
+	}
+	c.Generate(&data)
+	data.Uuid = uuid
+	err = tx.Create(&data).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.CreateFailedErr
+	}
+	c.Id = data.Id
+
+	return nil
+}
+
+// Update 修改SysUser对象
+func (e *SysUser) Update(c *dto.SysUserUpdateReq, p *actions.DataPermission) error {
+	var err error
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+	var userModel model.SysUser
+	err = e.Orm.
+		Scopes(actions.UserPermission(userModel.TableName(), p)).
+		First(&userModel, c.GetId()).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return global.UpdateNotFoundOrNoPermissionErr
+		}
+		return global.UpdateFailedErr
+	}
+
+	// TODO 1.1.1.8更新用户信息
+	// TODO 1.1.1.10送气人员绑定资质信息
+	// TODO 1.1.1.11货车司机绑定资质信息
+
+	c.Generate(&userModel)
+	err = tx.Model(&userModel).Where("id = ?", &userModel.Id).
+		Omit("password", "salt").Updates(&userModel).Error
+	if err != nil {
+		if errors.Is(err, model.ErrForbidUpdateSysRole) {
+			return model.ErrForbidUpdateSysRole
+		}
+		e.Log.Errorf("db error: %s", err)
+		return global.UpdateFailedErr
+	}
+	return nil
+}
+
+// UpdateStatus 更新用户状态
+func (e *SysUser) UpdateStatus(c *dto.UpdateSysUserStatusReq, p *actions.DataPermission) error {
+	var userModel model.SysUser
+	err := e.Orm.
+		Scopes(actions.UserPermission(userModel.TableName(), p)).
+		First(&userModel, c.GetId()).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return global.UpdateNotFoundOrNoPermissionErr
+		}
+		return global.UpdateFailedErr
+	}
+	err = e.Orm.Table(userModel.TableName()).Where("id = ? ", c.Id).Updates(c).Error
+	if err != nil {
+		if errors.Is(err, model.ErrForbidUpdateSysRole) {
+			return model.ErrForbidUpdateSysRole
+		}
+		e.Log.Errorf("db error: %s", err)
+		return global.UpdateFailedErr
+	}
+	return nil
+}
+
+// ResetPwd 重置用户密码
+func (e *SysUser) ResetPwd(c *dto.ResetSysUserPwdReq, p *actions.DataPermission) error {
+	var userModel model.SysUser
+	err := e.Orm.
+		Scopes(actions.UserPermission(userModel.TableName(), p)).
+		First(&userModel, c.GetId()).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return global.UpdateNotFoundOrNoPermissionErr
+		}
+		return global.UpdateFailedErr
+	}
+	c.Generate(&userModel)
+	err = e.Orm.Omit("username", "nick_name", "phone", "role_id", "avatar", "sex").Save(&userModel).Error
+	if err != nil {
+		if errors.Is(err, model.ErrForbidUpdateSysRole) {
+			return model.ErrForbidUpdateSysRole
+		}
+		e.Log.Errorf("db error: %s", err)
+		return global.UpdateFailedErr
+	}
+	return nil
+}
+
+// Remove 删除SysUser
+func (e *SysUser) Remove(c *dto.SysUserDeleteReq, p *actions.DataPermission) error {
+	var err error
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+	var data model.SysUser
+	db := e.Orm.Model(&data).
+		Scopes(actions.UserPermission(data.TableName(), p)).
+		Find(&data, c.GetId())
+
+	if err := db.Error; err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return err
+	}
+	if db.RowsAffected == 0 {
+		return global.DeleteNotFoundOrNoPermissionErr
+	}
+
+	// TODO 1.1.1.9注销用户信息
+
+	if err := tx.Delete(&data, c.GetId()).Error; err != nil {
+		if errors.Is(err, model.ErrForbidDeleteSysRole) {
+			return model.ErrForbidDeleteSysRole
+		}
+		e.Log.Errorf("db error: %s", err)
+		return err
+	}
+	return nil
+}
+
+// UpdatePwd 修改SysUser对象密码
+func (e *SysUser) UpdatePwd(id int, oldPassword, newPassword string) error {
+	var err error
+
+	if newPassword == "" {
+		return nil
+	}
+	c := &model.SysUser{}
+
+	err = e.Orm.Model(c).
+		Select("id", "password", "salt").
+		First(c, id).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return global.UpdateNotFoundOrNoPermissionErr
+		}
+		return errors.New("密码修改失败")
+	}
+	var ok bool
+	ok, err = pkg.CompareHashAndPassword(c.Password, oldPassword)
+	if err != nil {
+		e.Log.Errorf("CompareHashAndPassword error, %s", err.Error())
+		return errors.New("密码修改失败")
+	}
+	if !ok {
+		err = errors.New("incorrect Password")
+		e.Log.Warnf("user[%d] %s", id, err.Error())
+		return err
+	}
+	c.Password = newPassword
+	db := e.Orm.Model(c).Where("id = ?", id).
+		Select("Password", "Salt").
+		Updates(c)
+	if err = db.Error; err != nil {
+		if errors.Is(err, model.ErrForbidUpdateSysRole) {
+			return model.ErrForbidUpdateSysRole
+		}
+		e.Log.Errorf("db error: %s", err)
+		return errors.New("密码修改失败")
+	}
+	return nil
+}
+
+func (e *SysUser) GetProfile(c *dto.SysUserById, user *model.SysUser) error {
+	err := e.Orm.First(user, c.GetId()).Error
+	if err != nil {
+		return err
+	}
+	var dept model.SysDept
+	var role model.SysRole
+	//var post model.SysPost
+
+	err = e.Orm.First(&dept, user.DeptId).Error
+	if err != nil {
+		return err
+	}
+	user.Dept = dept
+
+	err = e.Orm.First(&role, user.RoleId).Error
+	if err != nil {
+		return err
+	}
+	user.Role = role
+
+	return nil
+}

+ 155 - 0
app/admin/service/warehouse.go

@@ -0,0 +1,155 @@
+package service
+
+import (
+	"cold-logistics/app/admin/model"
+	"cold-logistics/app/admin/service/dto"
+	"cold-logistics/common/actions"
+	cDto "cold-logistics/common/dto"
+	"cold-logistics/common/global"
+	"errors"
+	"gogs.baozhida.cn/zoie/OAuth-core/service"
+	"gorm.io/gorm"
+)
+
+type Warehouse struct {
+	service.Service
+}
+
+// GetPage 获取Warehouse列表
+func (e *Warehouse) GetPage(c *dto.WarehouseGetPageReq, list *[]model.Warehouse, count *int64, p *actions.DataPermission) error {
+	var err error
+	var data model.Warehouse
+
+	err = e.Orm.Model(&data).
+		Scopes(
+			cDto.MakeCondition(c.GetNeedSearch()),
+			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
+			actions.Permission(data.TableName(), p),
+		).
+		Find(list).Limit(-1).Offset(-1).
+		Count(count).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+	return nil
+}
+
+// Get 获取Warehouse对象
+func (e *Warehouse) Get(d *dto.WarehouseGetReq, carInfoModel *model.Warehouse, p *actions.DataPermission) error {
+	err := e.Orm.
+		Scopes(actions.Permission(carInfoModel.TableName(), p)).
+		First(carInfoModel, d.GetId()).Error
+
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return global.GetNotFoundOrNoPermissionErr
+		}
+		return global.GetFailedErr
+	}
+
+	return nil
+}
+
+// Insert 创建Warehouse对象
+func (e *Warehouse) Insert(c *dto.WarehouseInsertReq) error {
+	var err error
+	var data model.Warehouse
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	// 添加角色
+	c.Generate(&data)
+	err = tx.Create(&data).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.CreateFailedErr
+	}
+	c.Id = data.Id
+	return nil
+
+}
+
+// Update 修改Warehouse对象
+func (e *Warehouse) Update(c *dto.WarehouseUpdateReq, p *actions.DataPermission) error {
+	var err error
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	var carInfoModel = model.Warehouse{}
+	// 查询角色是否存在
+	err = e.Orm.Scopes(actions.Permission(carInfoModel.TableName(), p)).
+		First(&carInfoModel, c.GetId()).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return global.UpdateNotFoundOrNoPermissionErr
+		}
+		return global.UpdateFailedErr
+	}
+
+	c.Generate(&carInfoModel)
+	err = tx.Save(&carInfoModel).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.UpdateFailedErr
+	}
+
+	c.Id = carInfoModel.Id
+
+	return nil
+}
+
+// Remove 删除Warehouse
+func (e *Warehouse) Remove(c *dto.WarehouseDeleteReq, p *actions.DataPermission) error {
+	var err error
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	var carInfoModel model.Warehouse
+
+	// 查询角色是否存在
+	err = e.Orm.Scopes(actions.Permission(carInfoModel.TableName(), p)).
+		First(&carInfoModel, c.GetId()).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return global.DeleteNotFoundOrNoPermissionErr
+		}
+		return global.DeleteFailedErr
+	}
+
+	db := tx.Delete(&carInfoModel)
+
+	if err = db.Error; err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.DeleteFailedErr
+	}
+	if db.RowsAffected == 0 {
+		return global.DeleteNotFoundOrNoPermissionErr
+	}
+
+	return nil
+}

+ 8 - 0
cmd/api/jobs.go

@@ -0,0 +1,8 @@
+package api
+
+import "cold-logistics/app/jobs/router"
+
+func init() {
+	//注册路由 fixme 其他应用的路由,在本目录新建文件放在init方法
+	AppRouters = append(AppRouters, router.InitRouter)
+}

+ 180 - 0
cmd/api/server.go

@@ -0,0 +1,180 @@
+package api
+
+import (
+	"cold-logistics/app/admin/model"
+	"cold-logistics/common/file_store"
+	global2 "cold-logistics/common/global"
+	"cold-logistics/common/middleware"
+	"cold-logistics/common/middleware/handler"
+	"cold-logistics/common/storage"
+	"context"
+	"fmt"
+	"log"
+	"net/http"
+	"os"
+	"os/signal"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/spf13/cobra"
+	"gogs.baozhida.cn/zoie/OAuth-core/api"
+	"gogs.baozhida.cn/zoie/OAuth-core/config/source/file"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg"
+	"gogs.baozhida.cn/zoie/OAuth-core/runtime"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk/config"
+
+	"cold-logistics/app/admin/router"
+	ext "cold-logistics/conf"
+	database "cold-logistics/db"
+)
+
+var (
+	configYml string
+	StartCmd  = &cobra.Command{
+		Use:          "server",
+		Short:        "Start API server",
+		Example:      "cold-logistics server -c conf/settings.yml",
+		SilenceUsage: true,
+		PreRun: func(cmd *cobra.Command, args []string) {
+			setup()
+		},
+		RunE: func(cmd *cobra.Command, args []string) error {
+			return run()
+		},
+	}
+)
+
+var AppRouters = make([]func(), 0)
+
+func init() {
+	StartCmd.PersistentFlags().StringVarP(&configYml, "config", "c", "config/settings.yml", "Start server with provided configuration file")
+
+	//注册路由
+	AppRouters = append(AppRouters, router.InitRouter)
+}
+
+func setup() {
+	// 注入配置扩展项
+	config.ExtendConfig = &ext.ExtConfig
+	//1. 读取配置
+	config.Setup(
+		file.NewSource(file.WithPath(configYml)),
+		database.Setup,
+		storage.Setup,
+		file_store.QiniuSetup,
+	)
+	database.AutoMigrateDB()
+	//注册监听函数
+	queue := sdk.Runtime.GetMemoryQueue("")
+	queue.Register(global2.LoginLog, model.SaveLoginLog)
+	queue.Register(global2.OperateLog, model.SaveOperaLog)
+	//queue.Register(global2.ApiCheck, model.SaveSysApi)
+	go queue.Run()
+
+	usageStr := `starting api server...`
+	log.Println(usageStr)
+}
+
+func run() error {
+	if config.ApplicationConfig.Mode == pkg.ModeProd.String() {
+		gin.SetMode(gin.ReleaseMode)
+	}
+	initRouter()
+
+	for _, f := range AppRouters {
+		f()
+	}
+
+	srv := &http.Server{
+		Addr:    fmt.Sprintf("%s:%d", config.ApplicationConfig.Host, config.ApplicationConfig.Port),
+		Handler: sdk.Runtime.GetEngine(),
+	}
+
+	// fixme 新加的服务在这里配置
+	//go func() {
+	//	otherSvc.InitJob()
+	//	otherSvc.Setup(sdk.Runtime.GetDb())
+	//
+	//}()
+
+	// fixme 定时任务,需要时再配置
+	//go func() {
+	//	jobs.InitJob()
+	//	jobs.Setup(sdk.Runtime.GetDb())
+	//}()
+
+	go func() {
+		// 服务连接
+		if config.SslConfig.Enable {
+			if err := srv.ListenAndServeTLS(config.SslConfig.Pem, config.SslConfig.KeyStr); err != nil && err != http.ErrServerClosed {
+				log.Fatal("listen: ", err)
+			}
+		} else {
+			if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
+				log.Fatal("listen: ", err)
+			}
+		}
+	}()
+
+	//go func() {
+	//	InitService()
+	//}()
+
+	tip()
+	fmt.Println(pkg.Green("Server run at:"))
+	fmt.Printf("-  Local:   http://localhost:%d/ \r\n", config.ApplicationConfig.Port)
+	fmt.Printf("-  Network: http://%s:%d/ \r\n", pkg.GetLocalHost(), config.ApplicationConfig.Port)
+	fmt.Println(pkg.Green("Swagger run at:"))
+	fmt.Printf("-  Local:   http://localhost:%d/swagger/index.html \r\n", config.ApplicationConfig.Port)
+	fmt.Printf("-  Network: http://%s:%d/swagger/index.html \r\n", pkg.GetLocalHost(), config.ApplicationConfig.Port)
+	fmt.Printf("%s Enter Control + C Shutdown Server \r\n", pkg.GetCurrentTimeStr())
+	// 等待中断信号以优雅地关闭服务器(设置 5 秒的超时时间)
+	quit := make(chan os.Signal)
+	signal.Notify(quit, os.Interrupt)
+	<-quit
+
+	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+	defer cancel()
+
+	fmt.Printf("%s Shutdown Server ... \r\n", pkg.GetCurrentTimeStr())
+
+	if err := srv.Shutdown(ctx); err != nil {
+		log.Fatal("Server Shutdown:", err)
+	}
+	log.Println("Server exiting")
+
+	return nil
+}
+
+var Router runtime.Router
+
+func tip() {
+	usageStr := `欢迎使用 ` + pkg.Green(`OAuth `+global2.Version) + ` 可以使用 ` + pkg.Red(`-h`) + ` 查看命令`
+	fmt.Printf("%s \n\n", usageStr)
+}
+
+func initRouter() {
+	var r *gin.Engine
+	h := sdk.Runtime.GetEngine()
+	if h == nil {
+		h = gin.New()
+		sdk.Runtime.SetEngine(h)
+	}
+	switch h.(type) {
+	case *gin.Engine:
+		r = h.(*gin.Engine)
+	default:
+		log.Fatal("not support other engine")
+		os.Exit(-1)
+	}
+	if config.SslConfig.Enable {
+		r.Use(handler.TlsHandler())
+	}
+	r.Use(middleware.Sentinel()).
+		Use(middleware.RequestId(pkg.TrafficKey)).
+		Use(api.SetRequestLogger)
+
+	middleware.InitMiddleware(r)
+
+}

+ 51 - 0
cmd/cobra.go

@@ -0,0 +1,51 @@
+package cmd
+
+import (
+	"cold-logistics/common/global"
+	"errors"
+	"fmt"
+	"os"
+
+	"github.com/spf13/cobra"
+
+	"cold-logistics/cmd/api"
+	"cold-logistics/cmd/config"
+	"cold-logistics/cmd/migrate"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg"
+)
+
+var rootCmd = &cobra.Command{
+	Use:          "cold-logistics",
+	Short:        "cold-logistics",
+	SilenceUsage: true,
+	Long:         `OAuth`,
+	Args: func(cmd *cobra.Command, args []string) error {
+		if len(args) < 1 {
+			tip()
+			return errors.New(pkg.Red("requires at least one arg"))
+		}
+		return nil
+	},
+	PersistentPreRunE: func(*cobra.Command, []string) error { return nil },
+	Run: func(cmd *cobra.Command, args []string) {
+		tip()
+	},
+}
+
+func tip() {
+	usageStr := `欢迎使用 ` + pkg.Green(`OAuth `+global.Version) + ` 可以使用 ` + pkg.Red(`-h`) + ` 查看命令`
+	fmt.Printf("%s\n", usageStr)
+}
+
+func init() {
+	rootCmd.AddCommand(api.StartCmd)
+	rootCmd.AddCommand(config.StartCmd)
+	rootCmd.AddCommand(migrate.StartCmd)
+}
+
+// Execute : apply commands
+func Execute() {
+	if err := rootCmd.Execute(); err != nil {
+		os.Exit(-1)
+	}
+}

+ 62 - 0
cmd/config/server.go

@@ -0,0 +1,62 @@
+package config
+
+import (
+	"encoding/json"
+	"fmt"
+
+	"github.com/spf13/cobra"
+
+	"gogs.baozhida.cn/zoie/OAuth-core/config/source/file"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk/config"
+)
+
+var (
+	configYml string
+	StartCmd  = &cobra.Command{
+		Use:     "config",
+		Short:   "Get Application config info",
+		Example: "cold-logistics config -c conf/settings.yml",
+		Run: func(cmd *cobra.Command, args []string) {
+			run()
+		},
+	}
+)
+
+func init() {
+	StartCmd.PersistentFlags().StringVarP(&configYml, "config", "c", "config/settings.yml", "Start server with provided configuration file")
+}
+
+func run() {
+	config.Setup(file.NewSource(file.WithPath(configYml)))
+
+	application, errs := json.MarshalIndent(config.ApplicationConfig, "", "   ") //转换成JSON返回的是byte[]
+	if errs != nil {
+		fmt.Println(errs.Error())
+	}
+	fmt.Println("application:", string(application))
+
+	jwt, errs := json.MarshalIndent(config.JwtConfig, "", "   ") //转换成JSON返回的是byte[]
+	if errs != nil {
+		fmt.Println(errs.Error())
+	}
+	fmt.Println("jwt:", string(jwt))
+
+	database, errs := json.MarshalIndent(config.DatabasesConfig, "", "   ") //转换成JSON返回的是byte[]
+	if errs != nil {
+		fmt.Println(errs.Error())
+	}
+	fmt.Println("database:", string(database))
+
+	gen, errs := json.MarshalIndent(config.GenConfig, "", "   ") //转换成JSON返回的是byte[]
+	if errs != nil {
+		fmt.Println(errs.Error())
+	}
+	fmt.Println("gen:", string(gen))
+
+	loggerConfig, errs := json.MarshalIndent(config.LoggerConfig, "", "   ") //转换成JSON返回的是byte[]
+	if errs != nil {
+		fmt.Println(errs.Error())
+	}
+	fmt.Println("logger:", string(loggerConfig))
+
+}

+ 63 - 0
cmd/migrate/initdb.go

@@ -0,0 +1,63 @@
+package migrate
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"strings"
+
+	"gorm.io/gorm"
+)
+
+func InitDb(db *gorm.DB) (err error) {
+	filePath := "conf/db.sql"
+	if err = ExecSql(db, filePath); err != nil {
+		return err
+	}
+	return err
+}
+
+func ExecSql(db *gorm.DB, filePath string) error {
+	sql, err := IoUtil(filePath)
+	if err != nil {
+		fmt.Println("数据库基础数据初始化脚本读取失败!原因:", err.Error())
+		return err
+	}
+
+	tx := db.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	sqlList := strings.Split(sql, ";")
+	for i := 0; i < len(sqlList)-1; i++ {
+		if strings.Contains(sqlList[i], "--") {
+			fmt.Println(sqlList[i])
+			continue
+		}
+		sql := strings.Replace(sqlList[i]+";", "\n", "", -1)
+		sql = strings.TrimSpace(sql)
+		if err = tx.Exec(sql).Error; err != nil {
+			log.Printf("error sql: %s", sql)
+			if !strings.Contains(err.Error(), "Query was empty") {
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+func IoUtil(filePath string) (string, error) {
+	if contents, err := os.ReadFile(filePath); err == nil {
+		//因为contents是[]byte类型,直接转换成string类型后会多一行空格,需要使用strings.Replace替换换行符
+		result := strings.Replace(string(contents), "\n", "", 1)
+		fmt.Println("Use ioUtil.ReadFile to read a file:", result)
+		return result, nil
+	} else {
+		return "", err
+	}
+}

+ 41 - 0
cmd/migrate/server.go

@@ -0,0 +1,41 @@
+package migrate
+
+import (
+	"github.com/spf13/cobra"
+
+	"cold-logistics/db"
+	"gogs.baozhida.cn/zoie/OAuth-core/config/source/file"
+	log "gogs.baozhida.cn/zoie/OAuth-core/logger"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk/config"
+)
+
+var (
+	configYml string
+	StartCmd  = &cobra.Command{
+		Use:     "migrate",
+		Short:   "初始化数据库基础数据",
+		Example: "cold-logistics migrate -c conf/settings.yml",
+		PreRunE: func(cmd *cobra.Command, args []string) error {
+			//1. 读取配置
+			config.Setup(
+				file.NewSource(file.WithPath(configYml)),
+				db.Setup,
+			)
+			db.AutoMigrateDB()
+
+			return nil
+		},
+		RunE: func(cmd *cobra.Command, args []string) error {
+			if err := InitDb(db.DB); err != nil {
+				log.Error("数据库基础数据初始化失败", err.Error())
+			} else {
+				log.Info("数据库基础数据初始化成功")
+			}
+			return nil
+		},
+	}
+)
+
+func init() {
+	StartCmd.PersistentFlags().StringVarP(&configYml, "config", "c", "config/settings.yml", "Start server with provided configuration file")
+}

+ 49 - 0
common/actions/create.go

@@ -0,0 +1,49 @@
+package actions
+
+import (
+	"cold-logistics/common/dto"
+	"cold-logistics/common/model"
+	"net/http"
+
+	"github.com/gin-gonic/gin"
+
+	"gogs.baozhida.cn/zoie/OAuth-core/api"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth/user"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/response"
+)
+
+// CreateAction 通用新增动作
+func CreateAction(control dto.Control) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		log := api.GetRequestLogger(c)
+		db, err := pkg.GetOrm(c)
+		if err != nil {
+			log.Error(err)
+			return
+		}
+
+		//新增操作
+		req := control.Generate()
+		err = req.Bind(c)
+		if err != nil {
+			response.Error(c, http.StatusUnprocessableEntity, err, err.Error())
+			return
+		}
+		var object model.ActiveRecord
+		object, err = req.GenerateM()
+		if err != nil {
+			response.Error(c, 500, err, "模型生成失败")
+			return
+		}
+		object.SetCreateBy(user.GetUserId(c))
+		err = db.WithContext(c).Create(object).Error
+		if err != nil {
+			log.Errorf("Create error: %s", err)
+			response.Error(c, 500, err, "创建失败")
+			return
+		}
+		response.OK(c, object.GetId(), "创建成功")
+		c.Next()
+	}
+}

+ 61 - 0
common/actions/delete.go

@@ -0,0 +1,61 @@
+package actions
+
+import (
+	"cold-logistics/common/dto"
+	"cold-logistics/common/model"
+	"net/http"
+
+	"github.com/gin-gonic/gin"
+
+	log "gogs.baozhida.cn/zoie/OAuth-core/logger"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth/user"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/response"
+)
+
+// DeleteAction 通用删除动作
+func DeleteAction(control dto.Control) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		db, err := pkg.GetOrm(c)
+		if err != nil {
+			log.Error(err)
+			return
+		}
+
+		msgID := pkg.GenerateMsgIDFromContext(c)
+		//删除操作
+		req := control.Generate()
+		err = req.Bind(c)
+		if err != nil {
+			log.Errorf("MsgID[%s] Bind error: %s", msgID, err)
+			response.Error(c, http.StatusUnprocessableEntity, err, "参数验证失败")
+			return
+		}
+		var object model.ActiveRecord
+		object, err = req.GenerateM()
+		if err != nil {
+			response.Error(c, 500, err, "模型生成失败")
+			return
+		}
+
+		object.SetUpdateBy(user.GetUserId(c))
+
+		//数据权限检查
+		p := GetPermissionFromContext(c)
+
+		db = db.WithContext(c).Scopes(
+			Permission(object.TableName(), p),
+		).Where(req.GetId()).Delete(object)
+		if db.Error != nil {
+			log.Errorf("MsgID[%s] Delete error: %s", msgID, err)
+			response.Error(c, 500, err, "删除失败")
+			return
+		}
+		if db.RowsAffected == 0 {
+			response.Error(c, http.StatusForbidden, nil, "无权删除该数据")
+			return
+		}
+		response.OK(c, object.GetId(), "删除成功")
+		c.Next()
+	}
+}

+ 58 - 0
common/actions/index.go

@@ -0,0 +1,58 @@
+package actions
+
+import (
+	dto2 "cold-logistics/common/dto"
+	"cold-logistics/common/model"
+	"errors"
+	"gorm.io/gorm"
+	"net/http"
+
+	"github.com/gin-gonic/gin"
+
+	log "gogs.baozhida.cn/zoie/OAuth-core/logger"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/response"
+)
+
+// IndexAction 通用查询动作
+func IndexAction(m model.ActiveRecord, d dto2.Index, f func() interface{}) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		db, err := pkg.GetOrm(c)
+		if err != nil {
+			log.Error(err)
+			return
+		}
+
+		msgID := pkg.GenerateMsgIDFromContext(c)
+		list := f()
+		object := m.Generate()
+		req := d.Generate()
+		var count int64
+
+		//查询列表
+		err = req.Bind(c)
+		if err != nil {
+			response.Error(c, http.StatusUnprocessableEntity, err, "参数验证失败")
+			return
+		}
+
+		//数据权限检查
+		p := GetPermissionFromContext(c)
+
+		err = db.WithContext(c).Model(object).
+			Scopes(
+				dto2.MakeCondition(req.GetNeedSearch()),
+				dto2.Paginate(req.GetPageSize(), req.GetPageIndex()),
+				Permission(object.TableName(), p),
+			).
+			Find(list).Limit(-1).Offset(-1).
+			Count(&count).Error
+		if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
+			log.Errorf("MsgID[%s] Index error: %s", msgID, err)
+			response.Error(c, 500, err, "查询失败")
+			return
+		}
+		response.PageOK(c, list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
+		c.Next()
+	}
+}

+ 121 - 0
common/actions/permission.go

@@ -0,0 +1,121 @@
+package actions
+
+import (
+	"errors"
+	"github.com/gin-gonic/gin"
+	log "gogs.baozhida.cn/zoie/OAuth-core/logger"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth/user"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/response"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk/config"
+	"gorm.io/gorm"
+)
+
+type DataPermission struct {
+	DataScope string
+	UserId    int
+	DeptId    int
+	RoleId    int
+}
+
+func PermissionAction() gin.HandlerFunc {
+	return func(c *gin.Context) {
+		ormDB, err := pkg.GetOrm(c)
+		if err != nil {
+			log.Error(err)
+			return
+		}
+
+		msgID := pkg.GenerateMsgIDFromContext(c)
+		var p = new(DataPermission)
+		if userId := user.GetUserIdStr(c); userId != "" {
+			p, err = newDataPermission(ormDB, userId)
+			if err != nil {
+				log.Errorf("MsgID[%s] PermissionAction error: %s", msgID, err)
+				response.Error(c, 500, err, "权限范围鉴定错误")
+				c.Abort()
+				return
+			}
+		}
+		c.Set(PermissionKey, p)
+		c.Next()
+	}
+}
+
+func newDataPermission(tx *gorm.DB, userId interface{}) (*DataPermission, error) {
+	var err error
+	p := &DataPermission{}
+
+	err = tx.Table("sys_user").
+		Select("sys_user.id as user_id", "sys_role.id as role_id", "sys_user.dept_id", "sys_role.data_scope").
+		Joins("left join sys_role on sys_role.id = sys_user.role_id").
+		Where("sys_user.id = ?", userId).
+		Scan(p).Error
+	if err != nil {
+		err = errors.New("获取用户数据出错 msg:" + err.Error())
+		return nil, err
+	}
+	return p, nil
+}
+
+func UserPermission(tableName string, p *DataPermission) func(db *gorm.DB) *gorm.DB {
+	return func(db *gorm.DB) *gorm.DB {
+		if !config.ApplicationConfig.EnableDP {
+			return db
+		}
+		if p == nil {
+			return db
+		}
+		switch p.DataScope {
+		//case "2":
+		//	return db.Where(tableName+".create_by in (select sys_user.id from sys_role_dept left join sys_user on sys_user.dept_id=sys_role_dept.dept_id where sys_role_dept.role_id = ?) id = ?", p.RoleId, p.UserId)
+		case "3":
+			return db.Where(tableName+".dept_id = ? ", p.DeptId)
+		case "4":
+			return db.Where(tableName+".create_by in (SELECT id from sys_user where sys_user.dept_id in(select id from sys_dept where dept_path like ? )) or id = ?", "%/"+pkg.IntToString(p.DeptId)+"/%", p.UserId)
+		case "5":
+			return db.Where(tableName+".id = ?", p.UserId)
+		default:
+			return db
+		}
+	}
+}
+
+func Permission(tableName string, p *DataPermission) func(db *gorm.DB) *gorm.DB {
+	return func(db *gorm.DB) *gorm.DB {
+		if !config.ApplicationConfig.EnableDP {
+			return db
+		}
+		if p == nil {
+			return db
+		}
+		switch p.DataScope {
+		//case "2":
+		//	return db.Where(tableName+".create_by in (select sys_user.id from sys_role_dept left join sys_user on sys_user.dept_id=sys_role_dept.dept_id where sys_role_dept.role_id = ?)", p.RoleId)
+		case "3":
+			return db.Where(tableName+".dept_id = ?", p.DeptId)
+		case "4":
+			return db.Where(tableName+".create_by in (SELECT id from sys_user where sys_user.dept_id in (select id from sys_dept where dept_path like ? ))", "%/"+pkg.IntToString(p.DeptId)+"/%")
+		case "5":
+			return db.Where(tableName+".create_by = ?", p.UserId)
+		default:
+			return db
+		}
+	}
+}
+
+func getPermissionFromContext(c *gin.Context) *DataPermission {
+	p := new(DataPermission)
+	if pm, ok := c.Get(PermissionKey); ok {
+		switch pm.(type) {
+		case *DataPermission:
+			p = pm.(*DataPermission)
+		}
+	}
+	return p
+}
+
+// GetPermissionFromContext 提供非action写法数据范围约束
+func GetPermissionFromContext(c *gin.Context) *DataPermission {
+	return getPermissionFromContext(c)
+}

+ 5 - 0
common/actions/type.go

@@ -0,0 +1,5 @@
+package actions
+
+const (
+	PermissionKey = "dataPermission"
+)

+ 59 - 0
common/actions/update.go

@@ -0,0 +1,59 @@
+package actions
+
+import (
+	"cold-logistics/common/dto"
+	"cold-logistics/common/model"
+	"net/http"
+
+	"github.com/gin-gonic/gin"
+
+	log "gogs.baozhida.cn/zoie/OAuth-core/logger"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth/user"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/response"
+)
+
+// UpdateAction 通用更新动作
+func UpdateAction(control dto.Control) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		db, err := pkg.GetOrm(c)
+		if err != nil {
+			log.Error(err)
+			return
+		}
+
+		msgID := pkg.GenerateMsgIDFromContext(c)
+		req := control.Generate()
+		//更新操作
+		err = req.Bind(c)
+		if err != nil {
+			response.Error(c, http.StatusUnprocessableEntity, err, "参数验证失败")
+			return
+		}
+		var object model.ActiveRecord
+		object, err = req.GenerateM()
+		if err != nil {
+			response.Error(c, 500, err, "模型生成失败")
+			return
+		}
+		object.SetUpdateBy(user.GetUserId(c))
+
+		//数据权限检查
+		p := GetPermissionFromContext(c)
+
+		db = db.WithContext(c).Scopes(
+			Permission(object.TableName(), p),
+		).Where(req.GetId()).Updates(object)
+		if db.Error != nil {
+			log.Errorf("MsgID[%s] Update error: %s", msgID, err)
+			response.Error(c, 500, err, "更新失败")
+			return
+		}
+		if db.RowsAffected == 0 {
+			response.Error(c, http.StatusForbidden, nil, "无权更新该数据")
+			return
+		}
+		response.OK(c, object.GetId(), "更新成功")
+		c.Next()
+	}
+}

+ 67 - 0
common/actions/view.go

@@ -0,0 +1,67 @@
+package actions
+
+import (
+	"cold-logistics/common/dto"
+	"cold-logistics/common/model"
+	"errors"
+	"gorm.io/gorm"
+	"net/http"
+
+	"github.com/gin-gonic/gin"
+
+	log "gogs.baozhida.cn/zoie/OAuth-core/logger"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/response"
+)
+
+// ViewAction 通用详情动作
+func ViewAction(control dto.Control, f func() interface{}) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		db, err := pkg.GetOrm(c)
+		if err != nil {
+			log.Error(err)
+			return
+		}
+
+		msgID := pkg.GenerateMsgIDFromContext(c)
+		//查看详情
+		req := control.Generate()
+		err = req.Bind(c)
+		if err != nil {
+			response.Error(c, http.StatusUnprocessableEntity, err, "参数验证失败")
+			return
+		}
+		var object model.ActiveRecord
+		object, err = req.GenerateM()
+		if err != nil {
+			response.Error(c, 500, err, "模型生成失败")
+			return
+		}
+
+		var rsp interface{}
+		if f != nil {
+			rsp = f()
+		} else {
+			rsp, _ = req.GenerateM()
+		}
+
+		//数据权限检查
+		p := GetPermissionFromContext(c)
+
+		err = db.Model(object).WithContext(c).Scopes(
+			Permission(object.TableName(), p),
+		).Where(req.GetId()).First(rsp).Error
+
+		if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
+			response.Error(c, http.StatusNotFound, nil, "查看对象不存在或无权查看")
+			return
+		}
+		if err != nil {
+			log.Errorf("MsgID[%s] View error: %s", msgID, err)
+			response.Error(c, 500, err, "查看失败")
+			return
+		}
+		response.OK(c, rsp, "查询成功")
+		c.Next()
+	}
+}

+ 106 - 0
common/dto/generate.go

@@ -0,0 +1,106 @@
+package dto
+
+import (
+	vd "github.com/bytedance/go-tagexpr/v2/validator"
+	"net/http"
+
+	"github.com/gin-gonic/gin"
+	"gogs.baozhida.cn/zoie/OAuth-core/api"
+)
+
+type ObjectById struct {
+	Id  int   `uri:"id"`
+	Ids []int `json:"ids"`
+}
+
+func (s *ObjectById) Bind(ctx *gin.Context) error {
+	var err error
+	log := api.GetRequestLogger(ctx)
+	err = ctx.ShouldBindUri(s)
+	if err != nil {
+		log.Warnf("ShouldBindUri error: %s", err.Error())
+		return err
+	}
+	if ctx.Request.Method == http.MethodDelete {
+		err = ctx.ShouldBind(&s)
+		if err != nil {
+			log.Warnf("ShouldBind error: %s", err.Error())
+			return err
+		}
+		if len(s.Ids) > 0 {
+			return nil
+		}
+		if s.Ids == nil {
+			s.Ids = make([]int, 0)
+		}
+		if s.Id != 0 {
+			s.Ids = append(s.Ids, s.Id)
+		}
+	}
+	if err = vd.Validate(s); err != nil {
+		log.Errorf("Validate error: %s", err.Error())
+		return err
+	}
+	return err
+}
+
+func (s *ObjectById) GetId() interface{} {
+	if len(s.Ids) > 0 {
+		s.Ids = append(s.Ids, s.Id)
+		return s.Ids
+	}
+	return s.Id
+}
+
+type ObjectGetReq struct {
+	Id int `uri:"id"`
+}
+
+func (s *ObjectGetReq) Bind(ctx *gin.Context) error {
+	var err error
+	log := api.GetRequestLogger(ctx)
+	err = ctx.ShouldBindUri(s)
+	if err != nil {
+		log.Warnf("ShouldBindUri error: %s", err.Error())
+		return err
+	}
+	if err = vd.Validate(s); err != nil {
+		log.Errorf("Validate error: %s", err.Error())
+		return err
+	}
+	return err
+}
+
+func (s *ObjectGetReq) GetId() interface{} {
+	return s.Id
+}
+
+type ObjectDeleteReq struct {
+	Ids []int `json:"ids"`
+}
+
+func (s *ObjectDeleteReq) Bind(ctx *gin.Context) error {
+	var err error
+	log := api.GetRequestLogger(ctx)
+	err = ctx.ShouldBind(&s)
+	if err != nil {
+		log.Warnf("ShouldBind error: %s", err.Error())
+		return err
+	}
+	if len(s.Ids) > 0 {
+		return nil
+	}
+	if s.Ids == nil {
+		s.Ids = make([]int, 0)
+	}
+
+	if err = vd.Validate(s); err != nil {
+		log.Errorf("Validate error: %s", err.Error())
+		return err
+	}
+	return err
+}
+
+func (s *ObjectDeleteReq) GetId() interface{} {
+	return s.Ids
+}

+ 12 - 0
common/dto/order.go

@@ -0,0 +1,12 @@
+package dto
+
+import (
+	"gorm.io/gorm"
+	"gorm.io/gorm/clause"
+)
+
+func OrderDest(sort string, bl bool) func(db *gorm.DB) *gorm.DB {
+	return func(db *gorm.DB) *gorm.DB {
+		return db.Order(clause.OrderByColumn{Column: clause.Column{Name: sort}, Desc: bl})
+	}
+}

+ 20 - 0
common/dto/pagination.go

@@ -0,0 +1,20 @@
+package dto
+
+type Pagination struct {
+	Page     int `form:"page" example:"1"`
+	PageSize int `form:"pageSize" example:"10"`
+}
+
+func (m *Pagination) GetPageIndex() int {
+	if m.Page <= 0 {
+		m.Page = 1
+	}
+	return m.Page
+}
+
+func (m *Pagination) GetPageSize() int {
+	if m.PageSize <= 0 {
+		m.PageSize = 10
+	}
+	return m.PageSize
+}

+ 94 - 0
common/dto/search.go

@@ -0,0 +1,94 @@
+package dto
+
+import (
+	"cold-logistics/common/global"
+	"fmt"
+	"gogs.baozhida.cn/zoie/OAuth-core/tools/search"
+	"gorm.io/gorm"
+	"strings"
+)
+
+type GeneralDelDto struct {
+	Id  int   `uri:"id" json:"id" validate:"required"`
+	Ids []int `json:"ids"`
+}
+
+func (g GeneralDelDto) GetIds() []int {
+	ids := make([]int, 0)
+	if g.Id != 0 {
+		ids = append(ids, g.Id)
+	}
+	if len(g.Ids) > 0 {
+		for _, id := range g.Ids {
+			if id > 0 {
+				ids = append(ids, id)
+			}
+		}
+	} else {
+		if g.Id > 0 {
+			ids = append(ids, g.Id)
+		}
+	}
+	if len(ids) <= 0 {
+		//方式全部删除
+		ids = append(ids, 0)
+	}
+	return ids
+}
+
+type GeneralGetDto struct {
+	Id int `uri:"id" json:"id" validate:"required"`
+}
+
+func MakeCondition(q interface{}) func(db *gorm.DB) *gorm.DB {
+	return func(db *gorm.DB) *gorm.DB {
+		condition := &search.GormCondition{
+			GormPublic: search.GormPublic{},
+			Join:       make([]*search.GormJoin, 0),
+		}
+		search.ResolveSearchQuery(global.Driver, q, condition)
+		for _, join := range condition.Join {
+			if join == nil {
+				continue
+			}
+			db = db.Joins(join.JoinOn)
+			for k, v := range join.Where {
+				db = db.Where(k, v...)
+			}
+			for k, v := range join.Or {
+				db = db.Or(k, v...)
+			}
+			for _, o := range join.Order {
+				db = db.Order(o)
+			}
+		}
+		for k, v := range condition.Where {
+			db = db.Where(k, v...)
+		}
+
+		for k, v := range condition.Or {
+			db = db.Or(k, v...)
+		}
+		var orContains string
+		for k, v := range condition.OrContains {
+			orContains += fmt.Sprintf(" OR %v '%v'", k, v[0])
+		}
+		if len(orContains) > 0 {
+			db = db.Where(strings.TrimLeft(orContains, " OR"))
+		}
+		for _, o := range condition.Order {
+			db = db.Order(o)
+		}
+		return db
+	}
+}
+
+func Paginate(pageSize, pageIndex int) func(db *gorm.DB) *gorm.DB {
+	return func(db *gorm.DB) *gorm.DB {
+		offset := (pageIndex - 1) * pageSize
+		if offset < 0 {
+			offset = 0
+		}
+		return db.Offset(offset).Limit(pageSize)
+	}
+}

+ 21 - 0
common/dto/type.go

@@ -0,0 +1,21 @@
+package dto
+
+import (
+	"cold-logistics/common/model"
+	"github.com/gin-gonic/gin"
+)
+
+type Index interface {
+	Generate() Index
+	Bind(ctx *gin.Context) error
+	GetPageIndex() int
+	GetPageSize() int
+	GetNeedSearch() interface{}
+}
+
+type Control interface {
+	Generate() Control
+	Bind(ctx *gin.Context) error
+	GenerateM() (model.ActiveRecord, error)
+	GetId() interface{}
+}

+ 69 - 0
common/file_store/initialize.go

@@ -0,0 +1,69 @@
+package file_store
+
+import (
+	"cold-logistics/conf"
+	"fmt"
+	"os"
+	"path/filepath"
+	"strings"
+)
+
+type OXS struct {
+	// Endpoint 访问域名
+	Endpoint string
+	// AccessKeyID AK
+	AccessKeyID string
+	// AccessKeySecret AKS
+	AccessKeySecret string
+	// BucketName 桶名称
+	BucketName string
+}
+
+// Setup 配置文件存储driver
+func (e *OXS) Setup(driver DriverType, options ...ClientOption) FileStoreType {
+	fileStoreType := driver
+	var fileStore FileStoreType
+	switch fileStoreType {
+	case AliYunOSS:
+		fileStore = new(ALiYunOSS)
+		err := fileStore.Setup(e.Endpoint, e.AccessKeyID, e.AccessKeySecret, e.BucketName)
+		if err != nil {
+			fmt.Println(err)
+		}
+		return fileStore
+	case HuaweiOBS:
+		fileStore = new(HuaWeiOBS)
+		err := fileStore.Setup(e.Endpoint, e.AccessKeyID, e.AccessKeySecret, e.BucketName)
+		if err != nil {
+			fmt.Println(err)
+		}
+		return fileStore
+	case QiNiuKodo:
+		fileStore = new(QiNiuKODO)
+		err := fileStore.Setup(e.Endpoint, e.AccessKeyID, e.AccessKeySecret, e.BucketName)
+		if err != nil {
+			fmt.Println(err)
+		}
+		return fileStore
+	}
+
+	return nil
+}
+
+var QiniuFileStore FileStoreType
+
+func QiniuSetup() {
+	e := OXS{
+		conf.ExtConfig.Qiniu.Endpoint,
+		conf.ExtConfig.Qiniu.AccessKeyID,
+		conf.ExtConfig.Qiniu.AccessKeySecret,
+		conf.ExtConfig.Qiniu.BucketName}
+	QiniuFileStore = e.Setup(QiNiuKodo, map[string]interface{}{"Zone": "华东"})
+}
+
+// golang获取程序运行路径
+func GetCurrentDirectory() string {
+	dir, _ := filepath.Abs(filepath.Dir(os.Args[0]))
+
+	return strings.Replace(dir, "\\", "/", -1)
+}

+ 27 - 0
common/file_store/interface.go

@@ -0,0 +1,27 @@
+package file_store
+
+// DriverType 驱动类型
+type DriverType string
+
+const (
+	// HuaweiOBS 华为云OBS
+	HuaweiOBS DriverType = "HuaweiOBS"
+	// AliYunOSS 阿里云OSS
+	AliYunOSS DriverType = "AliYunOSS"
+	// QiNiuKodo 七牛云kodo
+	QiNiuKodo DriverType = "QiNiuKodo"
+)
+
+type ClientOption map[string]interface{}
+
+// TODO: FileStoreType名称待定
+
+// FileStoreType OXS
+type FileStoreType interface {
+	// Setup 装载 endpoint sss
+	Setup(endpoint, accessKeyID, accessKeySecret, BucketName string, options ...ClientOption) error
+	// UpLoad 上传
+	UpLoad(yourObjectName string, localFile interface{}) error
+	// GetTempToken 获取临时Token
+	GetTempToken() (string, error)
+}

+ 111 - 0
common/file_store/kodo.go

@@ -0,0 +1,111 @@
+package file_store
+
+import (
+	"context"
+	"fmt"
+	"github.com/qiniu/go-sdk/v7/auth/qbox"
+	"github.com/qiniu/go-sdk/v7/storage"
+)
+
+type Zone string
+
+const (
+	// HuaDong 华东
+	HuaDong Zone = "HuaDong"
+	// HuaBei 华北
+	HuaBei Zone = "HuaBei"
+	// HuaNan 华南
+	HuaNan Zone = "HuaNan"
+	// BeiMei 北美
+	BeiMei Zone = "BeiMei"
+	// XinJiaPo 新加坡
+	XinJiaPo Zone = "XinJiaPo"
+)
+
+type QiNiuKODO struct {
+	Client     interface{}
+	BucketName string
+	cfg        storage.Config
+	options    []ClientOption
+}
+
+func (e *QiNiuKODO) getToken() string {
+	putPolicy := storage.PutPolicy{
+		Scope: e.BucketName,
+	}
+	if len(e.options) > 0 && e.options[0]["Expires"] != nil {
+		putPolicy.Expires = e.options[0]["Expires"].(uint64)
+	}
+	upToken := putPolicy.UploadToken(e.Client.(*qbox.Mac))
+	return upToken
+}
+
+//Setup 装载
+//endpoint sss
+func (e *QiNiuKODO) Setup(endpoint, accessKeyID, accessKeySecret, BucketName string, options ...ClientOption) error {
+
+	mac := qbox.NewMac(accessKeyID, accessKeySecret)
+	// 获取存储空间。
+	cfg := storage.Config{}
+	// 空间对应的机房
+	e.setZoneORDefault(cfg, options...)
+	// 是否使用https域名
+	cfg.UseHTTPS = true
+	// 上传是否使用CDN上传加速
+	cfg.UseCdnDomains = false
+
+	e.Client = mac
+	e.BucketName = BucketName
+	e.cfg = cfg
+	e.options = options
+	return nil
+}
+
+// setZoneORDefault 设置Zone或者默认华东
+func (e *QiNiuKODO) setZoneORDefault(cfg storage.Config, options ...ClientOption) {
+	if len(options) > 0 && options[0]["Zone"] != nil {
+		if _, ok := options[0]["Zone"].(Zone); !ok {
+			cfg.Zone = &storage.ZoneHuadong
+		}
+		switch options[0]["Zone"].(Zone) {
+		case HuaDong:
+			cfg.Zone = &storage.ZoneHuadong
+		case HuaBei:
+			cfg.Zone = &storage.ZoneHuabei
+		case HuaNan:
+			cfg.Zone = &storage.ZoneHuanan
+		case BeiMei:
+			cfg.Zone = &storage.ZoneBeimei
+		case XinJiaPo:
+			cfg.Zone = &storage.ZoneXinjiapo
+		default:
+			cfg.Zone = &storage.ZoneHuadong
+		}
+	}
+}
+
+// UpLoad 文件上传
+func (e *QiNiuKODO) UpLoad(yourObjectName string, localFile interface{}) error {
+
+	// 构建表单上传的对象
+	formUploader := storage.NewFormUploader(&e.cfg)
+	ret := storage.PutRet{}
+	// 可选配置
+	putExtra := storage.PutExtra{
+		Params: map[string]string{
+			"x:name": "github logo",
+		},
+	}
+	err := formUploader.PutFile(context.Background(), &ret, e.getToken(), yourObjectName, localFile.(string), &putExtra)
+	if err != nil {
+		fmt.Println(err)
+		return err
+	}
+	fmt.Println(ret.Key, ret.Hash)
+	return nil
+}
+
+func (e *QiNiuKODO) GetTempToken() (string, error) {
+	token := e.getToken()
+	return token, nil
+}

+ 23 - 0
common/file_store/kodo_test.go

@@ -0,0 +1,23 @@
+package file_store
+
+import (
+	"testing"
+)
+
+func TestKODOUpload(t *testing.T) {
+	e := OXS{"", "", "", ""}
+	var oxs = e.Setup(QiNiuKodo, map[string]interface{}{"Zone": "华东"})
+	err := oxs.UpLoad("test.png", "./test.png")
+	if err != nil {
+		t.Error(err)
+	}
+	t.Log("ok")
+}
+
+func TestKODOGetTempToken(t *testing.T) {
+	e := OXS{"", "", "", ""}
+	var oxs = e.Setup(QiNiuKodo, map[string]interface{}{"Zone": "华东"})
+	token, _ := oxs.GetTempToken()
+	t.Log(token)
+	t.Log("ok")
+}

+ 53 - 0
common/file_store/obs.go

@@ -0,0 +1,53 @@
+package file_store
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/huaweicloud/huaweicloud-sdk-go-obs/obs"
+)
+
+type HuaWeiOBS struct {
+	Client     interface{}
+	BucketName string
+}
+
+func (e *HuaWeiOBS) Setup(endpoint, accessKeyID, accessKeySecret, BucketName string, options ...ClientOption) error {
+	// 创建ObsClient结构体
+	client, err := obs.New(accessKeyID, accessKeySecret, endpoint)
+	if err != nil {
+		log.Println("Error:", err)
+		return err
+	}
+	e.Client = client
+	e.BucketName = BucketName
+	return nil
+}
+
+// UpLoad 文件上传
+// yourObjectName 文件路径名称,与objectKey是同一概念,表示断点续传上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg
+func (e *HuaWeiOBS) UpLoad(yourObjectName string, localFile interface{}) error {
+	// 获取存储空间。
+	input := &obs.PutFileInput{}
+	input.Bucket = e.BucketName
+	input.Key = yourObjectName
+	input.SourceFile = localFile.(string)
+	output, err := e.Client.(*obs.ObsClient).PutFile(input)
+
+	if err == nil {
+		fmt.Printf("RequestId:%s\n", output.RequestId)
+		fmt.Printf("ETag:%s, StorageClass:%s\n", output.ETag, output.StorageClass)
+	} else {
+		if obsError, ok := err.(obs.ObsError); ok {
+			fmt.Println(obsError.Code)
+			fmt.Println(obsError.Message)
+		} else {
+			fmt.Println(err)
+		}
+	}
+	return nil
+}
+
+func (e *HuaWeiOBS) GetTempToken() (string, error) {
+	return "", nil
+}

+ 15 - 0
common/file_store/obs_test.go

@@ -0,0 +1,15 @@
+package file_store
+
+import (
+	"testing"
+)
+
+func TestOBSUpload(t *testing.T) {
+	e := OXS{"", "", "", ""}
+	var oxs = e.Setup(HuaweiOBS)
+	err := oxs.UpLoad("test.png", "./test.png")
+	if err != nil {
+		t.Error(err)
+	}
+	t.Log("ok")
+}

+ 49 - 0
common/file_store/oss.go

@@ -0,0 +1,49 @@
+package file_store
+
+import (
+	"log"
+
+	"github.com/aliyun/aliyun-oss-go-sdk/oss"
+)
+
+type ALiYunOSS struct {
+	Client     interface{}
+	BucketName string
+}
+
+//Setup 装载
+//endpoint sss
+func (e *ALiYunOSS) Setup(endpoint, accessKeyID, accessKeySecret, BucketName string, options ...ClientOption) error {
+	client, err := oss.New(endpoint, accessKeyID, accessKeySecret)
+	if err != nil {
+		log.Println("Error:", err)
+		return err
+	}
+	e.Client = client
+	e.BucketName = BucketName
+
+	return nil
+}
+
+// UpLoad 文件上传
+func (e *ALiYunOSS) UpLoad(yourObjectName string, localFile interface{}) error {
+	// 获取存储空间。
+	bucket, err := e.Client.(*oss.Client).Bucket(e.BucketName)
+	if err != nil {
+		log.Println("Error:", err)
+		return err
+	}
+	// 设置分片大小为100 KB,指定分片上传并发数为3,并开启断点续传上传。
+	// 其中<yourObjectName>与objectKey是同一概念,表示断点续传上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
+	// "LocalFile"为filePath,100*1024为partSize。
+	err = bucket.UploadFile(yourObjectName, localFile.(string), 100*1024, oss.Routines(3), oss.Checkpoint(true, ""))
+	if err != nil {
+		log.Println("Error:", err)
+		return err
+	}
+	return nil
+}
+
+func (e *ALiYunOSS) GetTempToken() (string, error) {
+	return "", nil
+}

+ 16 - 0
common/file_store/oss_test.go

@@ -0,0 +1,16 @@
+package file_store
+
+import (
+	"testing"
+)
+
+func TestOSSUpload(t *testing.T) {
+	// 打括号内填写自己的测试信息即可
+	e := OXS{}
+	var oxs = e.Setup(AliYunOSS)
+	err := oxs.UpLoad("test.png", "./test.png")
+	if err != nil {
+		t.Error(err)
+	}
+	t.Log("ok")
+}

+ 11 - 0
common/global/adm.go

@@ -0,0 +1,11 @@
+package global
+
+const (
+	Version = "0.0.1"
+)
+
+var (
+	Source string
+	Driver string
+	DBName string
+)

+ 27 - 0
common/global/casbin.go

@@ -0,0 +1,27 @@
+package global
+
+import (
+	"github.com/casbin/casbin/v2"
+	"github.com/gin-gonic/gin"
+
+	"gogs.baozhida.cn/zoie/OAuth-core/api"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk/config"
+)
+
+func LoadPolicy(c *gin.Context) (*casbin.SyncedEnforcer, error) {
+	log := api.GetRequestLogger(c)
+	//if err := sdk.Runtime.GetCasbinKey(c.Request.Host).LoadPolicy(); err == nil {
+	//	return sdk.Runtime.GetCasbinKey(c.Request.Host), nil
+	//} else {
+	//	log.Errorf("casbin rbac_model or policy init error, %s ", err.Error())
+	//	return nil, err
+	//}
+
+	if err := sdk.Runtime.GetCasbinKey(config.ApplicationConfig.Host).LoadPolicy(); err == nil {
+		return sdk.Runtime.GetCasbinKey(config.ApplicationConfig.Host), nil
+	} else {
+		log.Errorf("casbin rbac_model or policy init error, %s ", err.Error())
+		return nil, err
+	}
+}

+ 25 - 0
common/global/error.go

@@ -0,0 +1,25 @@
+package global
+
+import (
+	"errors"
+	"github.com/go-sql-driver/mysql"
+)
+
+var (
+	GetFailedErr                    = errors.New("查询失败")
+	CreateFailedErr                 = errors.New("添加失败")
+	UpdateFailedErr                 = errors.New("更新失败")
+	DeleteFailedErr                 = errors.New("删除失败")
+	GetNotFoundErr                  = errors.New("数据不存在")
+	GetNotFoundOrNoPermissionErr    = errors.New("数据不存在或无权查看该数据")
+	UpdateNotFoundOrNoPermissionErr = errors.New("数据不存在或无权修改该数据")
+	DeleteNotFoundOrNoPermissionErr = errors.New("数据不存在或无权删除该数据")
+)
+
+func IsUniqueIndexErr(err error) bool {
+	uniqueErr := &mysql.MySQLError{}
+	if ok := errors.As(err, &uniqueErr); ok {
+		return uniqueErr.Number == 1062
+	}
+	return false
+}

+ 7 - 0
common/global/topic.go

@@ -0,0 +1,7 @@
+package global
+
+const (
+	LoginLog   = "login_log_queue"
+	OperateLog = "operate_log_queue"
+	ApiCheck   = "api_check_queue"
+)

+ 27 - 0
common/ip.go

@@ -0,0 +1,27 @@
+package common
+
+import (
+	"github.com/gin-gonic/gin"
+	"strings"
+)
+
+func GetClientIP(c *gin.Context) string {
+	ClientIP := c.ClientIP()
+	//fmt.Println("ClientIP:", ClientIP)
+	RemoteIP := c.RemoteIP()
+	//fmt.Println("RemoteIP:", RemoteIP)
+	ip := c.Request.Header.Get("X-Forwarded-For")
+	if strings.Contains(ip, "127.0.0.1") || ip == "" {
+		ip = c.Request.Header.Get("X-real-ip")
+	}
+	if ip == "" {
+		ip = "127.0.0.1"
+	}
+	if RemoteIP != "127.0.0.1" {
+		ip = RemoteIP
+	}
+	if ClientIP != "127.0.0.1" {
+		ip = ClientIP
+	}
+	return ip
+}

+ 39 - 0
common/middleware/auth.go

@@ -0,0 +1,39 @@
+package middleware
+
+import (
+	"cold-logistics/common/middleware/handler"
+	jwt "gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk/config"
+	"time"
+)
+
+// AuthInit jwt验证new
+func AuthInit() (*jwt.GinJWTMiddleware, error) {
+	timeout := time.Hour
+	if config.ApplicationConfig.Mode == "dev" {
+		timeout = time.Duration(876000) * time.Hour
+	} else {
+		if config.JwtConfig.Timeout != 0 {
+			timeout = time.Duration(config.JwtConfig.Timeout) * time.Second
+		}
+	}
+	return jwt.New(&jwt.GinJWTMiddleware{
+		Realm:      "bzd oauth",
+		Key:        []byte(config.JwtConfig.Secret),
+		Timeout:    timeout,
+		SendCookie: true,
+		// token 最大刷新时间
+		MaxRefresh:      2 * time.Hour,
+		PayloadFunc:     handler.PayloadFunc,
+		IdentityHandler: handler.IdentityHandler,
+		Authenticator:   handler.Authenticator,
+		Authorizator:    handler.Authorizator,
+		Unauthorized:    handler.Unauthorized,
+		TokenLookup:     "header: Authorization, query: token, cookie: jwt",
+		TokenHeadName:   "Bearer",
+		TimeFunc:        time.Now,
+		SaveNewestToken: handler.SaveNewestToken,
+		GetNewestToken:  handler.GetNewestToken,
+	})
+
+}

+ 60 - 0
common/middleware/customerror.go

@@ -0,0 +1,60 @@
+package middleware
+
+import (
+	"fmt"
+	"net/http"
+	"runtime"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/gin-gonic/gin"
+)
+
+func CustomError(c *gin.Context) {
+	defer func() {
+		if err := recover(); err != nil {
+			if c.IsAborted() {
+				c.Status(200)
+			}
+			switch errStr := err.(type) {
+			case string:
+				p := strings.Split(errStr, "#")
+				if len(p) == 3 && p[0] == "CustomError" {
+					statusCode, e := strconv.Atoi(p[1])
+					if e != nil {
+						break
+					}
+					c.Status(statusCode)
+					fmt.Println(
+						time.Now().Format("2006-01-02 15:04:05"),
+						"[ERROR]",
+						c.Request.Method,
+						c.Request.URL,
+						statusCode,
+						c.Request.RequestURI,
+						c.ClientIP(),
+						p[2],
+					)
+					c.JSON(http.StatusOK, gin.H{
+						"code": statusCode,
+						"msg":  p[2],
+					})
+				} else {
+					c.JSON(http.StatusOK, gin.H{
+						"code": 500,
+						"msg":  errStr,
+					})
+				}
+			case runtime.Error:
+				c.JSON(http.StatusOK, gin.H{
+					"code": 500,
+					"msg":  errStr.Error(),
+				})
+			default:
+				panic(err)
+			}
+		}
+	}()
+	c.Next()
+}

+ 12 - 0
common/middleware/db.go

@@ -0,0 +1,12 @@
+package middleware
+
+import (
+	"github.com/gin-gonic/gin"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk/config"
+)
+
+func WithContextDb(c *gin.Context) {
+	c.Set("db", sdk.Runtime.GetDbByKey(config.ApplicationConfig.Host).WithContext(c))
+	c.Next()
+}

+ 289 - 0
common/middleware/handler/auth.go

@@ -0,0 +1,289 @@
+package handler
+
+import (
+	"cold-logistics/app/admin/model"
+	"cold-logistics/common"
+	"cold-logistics/common/global"
+	"errors"
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"github.com/go-redis/redis/v7"
+	"github.com/mssola/user_agent"
+	"gogs.baozhida.cn/zoie/OAuth-core/api"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg"
+	jwt "gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth/user"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/response"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk/config"
+	"gorm.io/gorm"
+	"net/http"
+	"strings"
+)
+
+func PayloadFunc(data interface{}) jwt.MapClaims {
+	if v, ok := data.(map[string]interface{}); ok {
+		u, _ := v["user"].(SysUser)
+		r, _ := v["role"].(SysRole)
+		d, _ := v["dept"].(SysDept)
+		single, _ := v["single"].(bool)
+		return jwt.MapClaims{
+			jwt.UUIDKey:      u.Uuid,
+			jwt.IdentityKey:  u.Id,
+			jwt.RoleIdKey:    r.Id,
+			jwt.RoleKey:      r.RoleKey,
+			jwt.UserNameKey:  u.Username,
+			jwt.DataScopeKey: r.DataScope,
+			jwt.RoleNameKey:  r.Name,
+			jwt.SingleKey:    single,
+			jwt.DeptIdKey:    u.DeptId,
+			jwt.DeptNameKey:  d.DeptName,
+		}
+	}
+	return jwt.MapClaims{}
+}
+
+func IdentityHandler(c *gin.Context) interface{} {
+	claims := jwt.ExtractClaims(c)
+	return map[string]interface{}{
+		"UUIDKey":     claims["uuid"],
+		"IdentityKey": claims["identity"],
+		"UserName":    claims["username"],
+		"RoleName":    claims["roleName"],
+		"RoleKey":     claims["roleKey"],
+		"Id":          claims["identity"],
+		"RoleId":      claims["roleId"],
+		"DataScope":   claims["dataScope"],
+		"single":      claims["single"],
+		"DeptId":      claims["deptId"],
+		"DeptName":    claims["deptName"],
+	}
+}
+
+// Authenticator 登录认证
+// Update 登录认证
+// @Summary 登录认证
+// @Description 登录认证
+// @Tags 登录
+// @Accept  application/json
+// @Product application/json
+// @Param data body Login true "body"
+// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
+// @Router /api/login [post]
+func Authenticator(c *gin.Context) (interface{}, error) {
+	log := api.GetRequestLogger(c)
+	ormDB, err := pkg.GetOrm(c)
+	if err != nil {
+		log.Errorf("get db error, %s", err.Error())
+		response.Error(c, 500, err, "数据库连接获取失败")
+		return nil, jwt.ErrFailedAuthentication
+	}
+
+	var loginVals Login
+	var status = "2"
+	var msg = "登录成功"
+	var username = ""
+	defer func() {
+		LoginLogToDB(c, status, msg, username)
+	}()
+
+	if err = c.ShouldBind(&loginVals); err != nil {
+		username = loginVals.Username
+		msg = "数据解析失败"
+		status = "1"
+
+		return nil, jwt.ErrFailedAuthentication
+	}
+	//if config.ApplicationConfig.Mode != "dev" {
+	//	if !captcha.Verify(loginVals.UUID, loginVals.Code, true) {
+	//		username = loginVals.Username
+	//		msg = "验证码错误"
+	//		status = "1"
+	//
+	//		return nil, jwt.ErrInvalidVerificationCode
+	//	}
+	//}
+	var u SysUser
+	var role SysRole
+	var dept SysDept
+	var e error
+	if loginVals.Type == 1 {
+		u, role, dept, e = loginVals.GetUser(ormDB)
+		if e != nil {
+			msg = e.Error()
+			status = "1"
+			log.Warnf("%s login failed!", username)
+			return nil, jwt.ErrFailedAuthentication
+		}
+	}
+	if loginVals.Type == 2 {
+		u, role, dept, e = loginVals.GetUserByCode(ormDB)
+		if e != nil {
+			msg = e.Error()
+			status = "1"
+			log.Warnf("%s login failed!", username)
+			return nil, jwt.ErrFailedSmsVerifyCode
+		}
+	}
+	if loginVals.Type == 0 {
+		return nil, jwt.ErrFailedAuthentication
+	}
+
+	username = loginVals.Username
+
+	single, err := GetSingleLogin(c)
+	if err != nil {
+		return nil, err
+	}
+
+	return map[string]interface{}{"user": u, "role": role, "dept": dept, "single": single, "mobile": loginVals.Mobile}, nil
+}
+
+// LoginLogToDB Write log to database
+func LoginLogToDB(c *gin.Context, status string, msg string, username string) {
+	if !config.LoggerConfig.EnabledDB {
+		return
+	}
+	log := api.GetRequestLogger(c)
+	l := make(map[string]interface{})
+
+	ua := user_agent.New(c.Request.UserAgent())
+	l["ipaddr"] = common.GetClientIP(c)
+	l["loginTime"] = pkg.GetCurrentTime()
+	l["status"] = status
+	l["remark"] = c.Request.UserAgent()
+	browserName, browserVersion := ua.Browser()
+	l["browser"] = browserName + " " + browserVersion
+	l["os"] = ua.OS()
+	l["platform"] = ua.Platform()
+	l["username"] = username
+	l["msg"] = msg
+
+	q := sdk.Runtime.GetMemoryQueue(c.Request.Host)
+	message, err := sdk.Runtime.GetStreamMessage("", global.LoginLog, l)
+	if err != nil {
+		log.Errorf("GetStreamMessage error, %s", err.Error())
+		//日志报错错误,不中断请求
+	} else {
+		err = q.Append(message)
+		if err != nil {
+			log.Errorf("Append message error, %s", err.Error())
+		}
+	}
+}
+
+// LogOut 退出登录
+// @Summary 退出登录
+// @Description 退出登录
+// @Description LoginHandler can be used by clients to get a jwt token.
+// @Description Reply will be of the form {"token": "TOKEN"}.
+// @Tags 登录
+// @Accept  application/json
+// @Product application/json
+// @Success 200 {string} string "{"code": 200, "msg": "成功退出系统"}"
+// @Router /logout [post]
+// @Security Bearer
+func LogOut(c *gin.Context) {
+	LoginLogToDB(c, "2", "退出成功", user.GetUserName(c))
+
+	c.JSON(http.StatusOK, gin.H{
+		"code": 200,
+		"msg":  "退出成功",
+	})
+
+}
+
+func Authorizator(data interface{}, c *gin.Context) bool {
+
+	if v, ok := data.(map[string]interface{}); ok {
+		u, _ := v["user"].(model.SysUser)
+		r, _ := v["role"].(model.SysRole)
+		d, _ := v["dept"].(model.SysDept)
+		single, _ := v["single"].(bool)
+		c.Set("uuid", u.Uuid)
+		c.Set("identity", u.Id)
+		c.Set("userName", u.Username)
+		c.Set("roleName", r.Name)
+		c.Set("roleKey", r.RoleKey)
+		c.Set("userId", u.Id)
+		c.Set("roleId", r.Id)
+		c.Set("single", single)
+		c.Set("dataScope", r.DataScope)
+		c.Set("deptId", u.DeptId)
+		c.Set("deptName", d.Name)
+		return true
+	}
+	return false
+}
+
+func Unauthorized(c *gin.Context, code int, message string) {
+	c.JSON(http.StatusOK, gin.H{
+		"code": code,
+		"msg":  message,
+	})
+}
+
+// 保存token到redis
+func SaveNewestToken(c *gin.Context, userId int64, token string, expire int64) error {
+	key := fmt.Sprintf("%s:%d", "bzd.oauth.token", userId)
+	return sdk.Runtime.GetCacheAdapter().Set(key, token, int(expire))
+}
+
+// redis从redis获取token
+func GetNewestToken(c *gin.Context, userId int64) (string, error) {
+	key := fmt.Sprintf("%s:%d", "bzd.oauth.token", userId)
+	return sdk.Runtime.GetCacheAdapter().Get(key)
+}
+
+func GetSingleLogin(c *gin.Context) (bool, error) {
+	log := api.GetRequestLogger(c)
+	ormDB, err := pkg.GetOrm(c)
+	if err != nil {
+		log.Errorf("get db error, %s", err.Error())
+		response.Error(c, 500, err, "数据库连接获取失败")
+		return false, err
+	}
+	//result := map[string]interface{}{}
+	var result string
+	err = ormDB.Table("sys_config").Select("config_value").Where("config_key = ? ", "sys_single_login").Scan(&result).Error
+	if err != nil {
+		log.Errorf("get sys_config error, %s", err.Error())
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			// 默认为非单一登录
+			return false, nil
+		}
+		return false, err
+	}
+
+	if result == "是" {
+		return true, nil
+	}
+	return false, nil
+
+}
+
+func SetEnterDeptId(c *gin.Context, newToken string, userId int64) error {
+	oldToken := ""
+	list := strings.Split(c.Request.Header.Get("Authorization"), ".")
+	if len(list) > 0 {
+		oldToken = list[len(list)-1]
+	} else {
+		return errors.New("token is null")
+	}
+	list2 := strings.Split(newToken, ".")
+	newToken2 := list2[len(list2)-1]
+	deptIdStr, err := sdk.Runtime.GetCacheAdapter().Get(fmt.Sprintf("enter-dept-%s-%d", oldToken, userId))
+	if err == nil {
+		sdk.Runtime.GetCacheAdapter().Set(fmt.Sprintf("enter-dept-%s-%d", newToken2, userId), deptIdStr, int(config.JwtConfig.Timeout)+7200)
+		sdk.Runtime.GetCacheAdapter().Del(fmt.Sprintf("enter-dept-%s-%d", oldToken, userId))
+	}
+	deptName, err := sdk.Runtime.GetCacheAdapter().Get(fmt.Sprintf("enter-dept-name-%s-%d", oldToken, userId))
+	if err == nil {
+		sdk.Runtime.GetCacheAdapter().Set(fmt.Sprintf("enter-dept-name-%s-%d", newToken2, userId), deptName, int(config.JwtConfig.Timeout)+7200)
+		sdk.Runtime.GetCacheAdapter().Del(fmt.Sprintf("enter-dept-name-%s-%d", oldToken, userId))
+	}
+	if err == redis.Nil {
+		return nil
+	}
+	return err
+}

+ 13 - 0
common/middleware/handler/dept.go

@@ -0,0 +1,13 @@
+package handler
+
+import (
+	model2 "cold-logistics/common/model"
+	coreModel "gogs.baozhida.cn/zoie/OAuth-core/model"
+)
+
+type SysDept struct {
+	model2.Model
+	coreModel.Dept
+	model2.ControlBy
+	model2.ModelTime
+}

+ 22 - 0
common/middleware/handler/httpshandler.go

@@ -0,0 +1,22 @@
+package handler
+
+import (
+	"github.com/gin-gonic/gin"
+	"github.com/unrolled/secure"
+
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk/config"
+)
+
+func TlsHandler() gin.HandlerFunc {
+	return func(c *gin.Context) {
+		secureMiddleware := secure.New(secure.Options{
+			SSLRedirect: true,
+			SSLHost:     config.SslConfig.Domain,
+		})
+		err := secureMiddleware.Process(c.Writer, c.Request)
+		if err != nil {
+			return
+		}
+		c.Next()
+	}
+}

+ 100 - 0
common/middleware/handler/login.go

@@ -0,0 +1,100 @@
+package handler
+
+import (
+	"errors"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk"
+	"gorm.io/gorm"
+
+	log "gogs.baozhida.cn/zoie/OAuth-core/logger"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg"
+)
+
+type Login struct {
+	Username   string `form:"UserName" json:"username"`     // 用户名
+	Password   string `form:"Password" json:"password"`     // 密码
+	Phone      string `form:"Phone" json:"phone"`           // 手机号
+	VerifyCode string `form:"VerifyCode" json:"verifyCode"` // 验证码
+	Type       int    `form:"Type" json:"type"`             // 1-密码  2-短信验证码
+	Mobile     bool   `form:"Mobile" json:"mobile"`         // 是否手机登录
+}
+
+//Code     string `form:"Code" json:"code" binding:"required"`
+//UUID     string `form:"UUID" json:"uuid" binding:"required"`
+
+type SmsLogin struct {
+}
+
+func (u *Login) GetUser(tx *gorm.DB) (user SysUser, role SysRole, dept SysDept, err error) {
+	err = tx.Table("sys_user").Where("username = ? and status = 2", u.Username).First(&user).Error
+	if err != nil {
+		log.Errorf("get user error, %s", err.Error())
+		return
+	}
+	_, err = pkg.CompareHashAndPassword(user.Password, u.Password)
+	if err != nil {
+		log.Errorf("user login error, %s", err.Error())
+		return
+	}
+	err = tx.Table("sys_role").Where("id = ? ", user.RoleId).First(&role).Error
+	if err != nil {
+		log.Errorf("get role error, %s", err.Error())
+		return
+	}
+	if user.DeptId > 0 {
+		err = tx.Table("sys_dept").Where("id = ? ", user.DeptId).First(&dept).Error
+		if err != nil {
+			log.Errorf("get dept error, %s", err.Error())
+			return
+		}
+	}
+
+	return
+}
+
+func (u *Login) GetUserByCode(tx *gorm.DB) (user SysUser, role SysRole, dept SysDept, err error) {
+	err = tx.Table("sys_user").Where("phone = ? and status = 2", u.Phone).First(&user).Error
+	if err != nil {
+		log.Errorf("get user error, %s", err.Error())
+		return
+	}
+	code, err := sdk.Runtime.GetCacheAdapter().Get(GetVerifyCodeCacheKey(u.Phone))
+	if err != nil {
+		log.Errorf("user login error, %s", err.Error())
+		err = errors.New("验证码已过期")
+		return
+	}
+	if code != u.VerifyCode {
+		log.Errorf("user login error, %s", "验证码错误")
+		err = errors.New("验证码错误")
+		return
+	}
+
+	err = tx.Table("sys_role").Where("id = ? ", user.RoleId).First(&role).Error
+	if err != nil {
+		log.Errorf("get role error, %s", err.Error())
+		return
+	}
+	if user.DeptId > 0 {
+		err = tx.Table("sys_dept").Where("id = ? ", user.DeptId).First(&dept).Error
+		if err != nil {
+			log.Errorf("get dept error, %s", err.Error())
+			return
+		}
+	}
+
+	return
+}
+
+func GetUserByID(tx *gorm.DB, id int64) (user SysUser, role SysRole, err error) {
+	err = tx.Table("sys_user").Where("id = ? ", id).First(&user).Error
+	if err != nil {
+		log.Errorf("get user error, %s", err.Error())
+		return
+	}
+	err = tx.Table("sys_role").Where("id = ? ", user.RoleId).First(&role).Error
+	if err != nil {
+		log.Errorf("get role error, %s", err.Error())
+		return
+	}
+	return
+}

+ 17 - 0
common/middleware/handler/role.go

@@ -0,0 +1,17 @@
+package handler
+
+import (
+	"cold-logistics/common/model"
+	coreModel "gogs.baozhida.cn/zoie/OAuth-core/model"
+)
+
+type SysRole struct {
+	model.Model
+	coreModel.Role
+	model.ControlBy
+	model.ModelTime
+}
+
+func (SysRole) TableName() string {
+	return "sys_role"
+}

+ 21 - 0
common/middleware/handler/service.go

@@ -0,0 +1,21 @@
+package handler
+
+import (
+	model2 "cold-logistics/common/model"
+)
+
+type SysService struct {
+	model2.Model
+	No         string `gorm:"size:8;not null;" json:"no"`                         // 服务编号
+	Name       string `gorm:"size:128;" json:"name"`                              // 服务名称
+	Host       string `gorm:"size:512;not null;comment:服务地址" json:"host"`         // 服务地址
+	AuthCode   string `gorm:"size:32;not null;comment:授权码" json:"authCode"`       // 授权码
+	Status     int    `gorm:"size:4;not null;default:2;comment:状态" json:"status"` // 状态 1-停用 2-正常
+	RoleApiUrl string `gorm:"size:128;" json:"roleApiUrl"`                        // 角色权限回调地址
+	model2.ControlBy
+	model2.ModelTime
+}
+
+func (SysService) TableName() string {
+	return "sys_service"
+}

+ 22 - 0
common/middleware/handler/user.go

@@ -0,0 +1,22 @@
+package handler
+
+import (
+	"cold-logistics/common/model"
+	"fmt"
+	coreModel "gogs.baozhida.cn/zoie/OAuth-core/model"
+)
+
+type SysUser struct {
+	model.Model
+	coreModel.User
+	model.ControlBy
+	model.ModelTime
+}
+
+func (SysUser) TableName() string {
+	return "sys_user"
+}
+
+func GetVerifyCodeCacheKey(phone string) string {
+	return fmt.Sprintf("verify-code-%s", phone)
+}

+ 48 - 0
common/middleware/header.go

@@ -0,0 +1,48 @@
+package middleware
+
+import (
+	"net/http"
+	"time"
+
+	"github.com/gin-gonic/gin"
+)
+
+// NoCache is a middleware function that appends headers
+// to prevent the client from caching the HTTP response.
+func NoCache(c *gin.Context) {
+	c.Header("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate, value")
+	c.Header("Expires", "Thu, 01 Jan 1970 00:00:00 GMT")
+	c.Header("Last-Modified", time.Now().UTC().Format(http.TimeFormat))
+	c.Next()
+}
+
+// Options is a middleware function that appends headers
+// for options requests and aborts then exits the middleware
+// chain and ends the request.
+func Options(c *gin.Context) {
+	if c.Request.Method != "OPTIONS" {
+		c.Next()
+	} else {
+		c.Header("Access-Control-Allow-Origin", "*")
+		c.Header("Access-Control-Allow-Methods", "GET,POST,PUT,PATCH,DELETE,OPTIONS")
+		c.Header("Access-Control-Allow-Headers", "authorization, origin, content-type, accept, X-Token, serviceId")
+		c.Header("Allow", "HEAD,GET,POST,PUT,PATCH,DELETE,OPTIONS")
+		c.Header("Content-Type", "application/json")
+		c.AbortWithStatus(200)
+	}
+}
+
+// Secure is a middleware function that appends security
+// and resource access headers.
+func Secure(c *gin.Context) {
+	c.Header("Access-Control-Allow-Origin", "*")
+	//c.Header("X-Frame-Options", "DENY")
+	c.Header("X-Content-Type-Options", "nosniff")
+	c.Header("X-XSS-Protection", "1; mode=block")
+	if c.Request.TLS != nil {
+		c.Header("Strict-Transport-Security", "max-age=31536000")
+	}
+
+	// Also consider adding Content-Security-Policy headers
+	// c.Header("Content-Security-Policy", "script-src 'self' https://cdnjs.cloudflare.com")
+}

+ 36 - 0
common/middleware/init.go

@@ -0,0 +1,36 @@
+package middleware
+
+import (
+	"cold-logistics/common/actions"
+	"github.com/gin-gonic/gin"
+
+	jwt "gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk"
+)
+
+const (
+	JwtTokenCheck   string = "JwtToken"
+	RoleCheck       string = "AuthCheckRole"
+	PermissionCheck string = "PermissionAction"
+)
+
+func InitMiddleware(r *gin.Engine) {
+	// 数据库链接
+	r.Use(WithContextDb)
+	// 日志处理
+	r.Use(LoggerToFile())
+	// 自定义错误处理
+	r.Use(CustomError)
+	// NoCache is a middleware function that appends headers
+	r.Use(NoCache)
+	// 跨域处理
+	r.Use(Options)
+	// Secure is a middleware function that appends security
+	r.Use(Secure)
+	//r.Use(DemoEvn())
+	// 链路追踪
+	//r.Use(middleware.Trace())
+	sdk.Runtime.SetMiddleware(JwtTokenCheck, (*jwt.GinJWTMiddleware).MiddlewareFunc)
+	//sdk.Runtime.SetMiddleware(RoleCheck, AuthCheckRole())
+	sdk.Runtime.SetMiddleware(PermissionCheck, actions.PermissionAction())
+}

+ 147 - 0
common/middleware/logger.go

@@ -0,0 +1,147 @@
+package middleware
+
+import (
+	"bufio"
+	"bytes"
+	"cold-logistics/common"
+	"cold-logistics/common/global"
+	"encoding/json"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"strings"
+	"time"
+
+	"github.com/casbin/casbin/v2/util"
+	"github.com/gin-gonic/gin"
+
+	"cold-logistics/app/admin/service/dto"
+	"gogs.baozhida.cn/zoie/OAuth-core/api"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth/user"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk/config"
+)
+
+// LoggerToFile 日志记录到文件
+func LoggerToFile() gin.HandlerFunc {
+	return func(c *gin.Context) {
+
+		for _, i := range LogExclude {
+			if util.KeyMatch2(c.Request.URL.Path, i.Url) && c.Request.Method == i.Method {
+				return
+			}
+		}
+
+		log := api.GetRequestLogger(c)
+		// 开始时间
+		startTime := time.Now()
+		// 处理请求
+		var body string
+		switch c.Request.Method {
+		case http.MethodPost, http.MethodPut, http.MethodDelete:
+			bf := bytes.NewBuffer(nil)
+			wt := bufio.NewWriter(bf)
+			_, err := io.Copy(wt, c.Request.Body)
+			if err != nil {
+				log.Warnf("copy body error, %s", err.Error())
+				err = nil
+			}
+			rb, _ := ioutil.ReadAll(bf)
+			c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(rb))
+			body = string(rb)
+		case http.MethodGet:
+			body = c.Request.URL.RawQuery
+		}
+
+		c.Next()
+		url := c.Request.RequestURI
+		if strings.Index(url, "logout") > -1 ||
+			strings.Index(url, "login") > -1 {
+			return
+		}
+		// 结束时间
+		endTime := time.Now()
+		if c.Request.Method == http.MethodOptions {
+			return
+		}
+
+		rt, bl := c.Get("result")
+		var result = ""
+		if bl {
+			rb, err := json.Marshal(rt)
+			if err != nil {
+				log.Warnf("json Marshal result error, %s", err.Error())
+			} else {
+				result = string(rb)
+			}
+		}
+
+		st, bl := c.Get("status")
+		var statusBus = 0
+		if bl {
+			statusBus = st.(int)
+		}
+
+		// 请求方式
+		reqMethod := c.Request.Method
+		// 请求路由
+		reqUri := c.Request.RequestURI
+		// 状态码
+		statusCode := c.Writer.Status()
+		// 请求IP
+		clientIP := common.GetClientIP(c)
+		// 执行时间
+		latencyTime := endTime.Sub(startTime)
+		// 日志格式
+		logData := map[string]interface{}{
+			"statusCode":  statusCode,
+			"latencyTime": latencyTime,
+			"clientIP":    clientIP,
+			"method":      reqMethod,
+			"uri":         reqUri,
+		}
+		log.WithFields(logData).Info()
+
+		if c.Request.Method != "OPTIONS" && config.LoggerConfig.EnabledDB && statusCode != 404 {
+			SetDBOperaLog(c, clientIP, statusCode, reqUri, reqMethod, latencyTime, body, result, statusBus)
+		}
+	}
+}
+
+// SetDBOperaLog 写入操作日志表 fixme 该方法后续即将弃用
+func SetDBOperaLog(c *gin.Context, clientIP string, statusCode int, reqUri string, reqMethod string, latencyTime time.Duration, body string, result string, status int) {
+
+	log := api.GetRequestLogger(c)
+
+	l := make(map[string]interface{})
+	l["_fullPath"] = c.FullPath()
+	l["operaUrl"] = reqUri
+	l["operaIp"] = clientIP
+	l["operaName"] = user.GetUserName(c)
+	l["requestMethod"] = reqMethod
+	l["operaParam"] = body
+	l["operaTime"] = time.Now()
+	l["jsonResult"] = result
+	l["latencyTime"] = latencyTime.String()
+	l["statusCode"] = statusCode
+	l["userAgent"] = c.Request.UserAgent()
+	l["createBy"] = user.GetUserId(c)
+	l["updateBy"] = user.GetUserId(c)
+	if status == http.StatusOK {
+		l["status"] = dto.OperaStatusEnabel
+	} else {
+		l["status"] = dto.OperaStatusDisable
+	}
+
+	q := sdk.Runtime.GetMemoryQueue(c.Request.Host)
+	message, err := sdk.Runtime.GetStreamMessage("", global.OperateLog, l)
+	if err != nil {
+		log.Errorf("GetStreamMessage error, %s", err.Error())
+		//日志报错错误,不中断请求
+	} else {
+		err = q.Append(message)
+		if err != nil {
+			log.Errorf("Append message error, %s", err.Error())
+		}
+	}
+}

+ 66 - 0
common/middleware/permission.go

@@ -0,0 +1,66 @@
+package middleware
+
+import (
+	"github.com/casbin/casbin/v2/util"
+	"github.com/gin-gonic/gin"
+	"gogs.baozhida.cn/zoie/OAuth-core/api"
+	mycasbin "gogs.baozhida.cn/zoie/OAuth-core/pkg/casbin"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/response"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk/config"
+	"net/http"
+)
+
+// AuthCheckRole 权限检查中间件
+func AuthCheckRole() gin.HandlerFunc {
+	return func(c *gin.Context) {
+		log := api.GetRequestLogger(c)
+		data, _ := c.Get(jwtauth.JwtPayloadKey)
+		v := data.(jwtauth.MapClaims)
+		e := sdk.Runtime.GetCasbinKey(config.ApplicationConfig.Host)
+		var res, casbinExclude bool
+		var err error
+		// 检查权限
+		rolekey := v["roleKey"].(string)
+		if rolekey == "admin" {
+			res = true
+			c.Next()
+			return
+		}
+
+		for _, i := range CasbinExclude {
+			if util.KeyMatch2(c.Request.URL.Path, i.Url) && c.Request.Method == i.Method {
+				casbinExclude = true
+				break
+			}
+
+		}
+		if casbinExclude {
+			log.Infof("Casbin exclusion, no validation method:%s path:%s", c.Request.Method, c.Request.URL.Path)
+			c.Next()
+			return
+		}
+		res, err = mycasbin.EnforceRoute(rolekey, "", c.Request, e)
+		if err != nil {
+			log.Errorf("AuthCheckRole error: %s method:%s path:%s", err, c.Request.Method, c.Request.URL.Path)
+			response.Error(c, 500, err, err.Error())
+			return
+		}
+
+		if res {
+			log.Infof("isTrue: %v role: %s method: %s path: %s", res, v["roleKey"], c.Request.Method, c.Request.URL.Path)
+			c.Next()
+			return
+		} else {
+			log.Warnf("isFalse: %v role: %s method: %s path: %s message: %s", res, v["roleKey"], c.Request.Method, c.Request.URL.Path, "当前request无权限,请管理员确认!")
+			c.JSON(http.StatusOK, gin.H{
+				"code": 403,
+				"msg":  "对不起,您没有该接口访问权限,请联系管理员",
+			})
+			c.Abort()
+			return
+		}
+
+	}
+}

+ 37 - 0
common/middleware/request_id.go

@@ -0,0 +1,37 @@
+package middleware
+
+import (
+	"net/http"
+	"strings"
+
+	"github.com/gin-gonic/gin"
+	"github.com/google/uuid"
+
+	log "gogs.baozhida.cn/zoie/OAuth-core/logger"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg"
+)
+
+// RequestId 自动增加requestId
+func RequestId(trafficKey string) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		if c.Request.Method == http.MethodOptions {
+			c.Next()
+			return
+		}
+		requestId := c.GetHeader(trafficKey)
+		if requestId == "" {
+			requestId = c.GetHeader(strings.ToLower(trafficKey))
+		}
+		if requestId == "" {
+			requestId = uuid.New().String()
+		}
+		c.Request.Header.Set(trafficKey, requestId)
+		c.Set(trafficKey, requestId)
+		c.Set(pkg.LoggerKey,
+			log.NewHelper(log.DefaultLogger).
+				WithFields(map[string]interface{}{
+					trafficKey: requestId,
+				}))
+		c.Next()
+	}
+}

+ 23 - 0
common/middleware/sentinel.go

@@ -0,0 +1,23 @@
+package middleware
+
+import (
+	sentinelPlugin "github.com/alibaba/sentinel-golang/adapter/gin"
+	"github.com/alibaba/sentinel-golang/core/system"
+	"github.com/gin-gonic/gin"
+
+	log "gogs.baozhida.cn/zoie/OAuth-core/logger"
+)
+
+// Sentinel 限流
+func Sentinel() gin.HandlerFunc {
+	if _, err := system.LoadRules([]*system.Rule{
+		{
+			MetricType:   system.InboundQPS,
+			TriggerCount: 200,
+			Strategy:     system.BBR,
+		},
+	}); err != nil {
+		log.Fatalf("Unexpected error: %+v", err)
+	}
+	return sentinelPlugin.SentinelMiddleware()
+}

+ 43 - 0
common/middleware/service_auth.go

@@ -0,0 +1,43 @@
+package middleware
+
+import (
+	"cold-logistics/common/middleware/handler"
+	"errors"
+	"github.com/gin-gonic/gin"
+	"gogs.baozhida.cn/zoie/OAuth-core/api"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/response"
+	"gorm.io/gorm"
+)
+
+// AuthCheckService 服务检查中间件
+func AuthCheckService() gin.HandlerFunc {
+	return func(c *gin.Context) {
+		serviceId := c.Request.Header.Get("serviceId")
+		log := api.GetRequestLogger(c)
+		ormDB, err := pkg.GetOrm(c)
+		if err != nil {
+			log.Errorf("get db error, %s", err.Error())
+			response.Error(c, 500, err, "数据库连接获取失败")
+			return
+		}
+		service := handler.SysService{}
+
+		err = ormDB.Table("sys_service").Where("id = ? ", serviceId).First(&service).Error
+		if err != nil {
+			log.Errorf("get service error, %s", err.Error())
+			if errors.Is(err, gorm.ErrRecordNotFound) {
+				response.Error(c, 400, err, "未认证")
+				return
+			}
+			response.Error(c, 500, err, "数据库连接获取失败")
+			return
+		}
+		if service.Status == 1 {
+			response.Error(c, 400, err, "服务已停用")
+			return
+		}
+		c.Next()
+
+	}
+}

+ 45 - 0
common/middleware/settings.go

@@ -0,0 +1,45 @@
+package middleware
+
+type UrlInfo struct {
+	Url    string
+	Method string
+}
+
+// CasbinExclude casbin 排除的路由列表
+var CasbinExclude = []UrlInfo{
+	{Url: "/api/dict/type-option-select", Method: "GET"},
+	{Url: "/api/dict-data/option-select", Method: "GET"},
+	{Url: "/api/organTree", Method: "GET"},
+	{Url: "/api/db/tables/page", Method: "GET"},
+	{Url: "/api/db/columns/page", Method: "GET"},
+	{Url: "/api/gen/toproject/:tableId", Method: "GET"},
+	{Url: "/api/gen/todb/:tableId", Method: "GET"},
+	{Url: "/api/gen/tabletree", Method: "GET"},
+	{Url: "/api/gen/preview/:tableId", Method: "GET"},
+	{Url: "/api/gen/apitofile/:tableId", Method: "GET"},
+	{Url: "/api/getCaptcha", Method: "GET"},
+	{Url: "/api/getinfo", Method: "GET"},
+	{Url: "/api/menurole", Method: "GET"},
+	{Url: "/api/roleMenuTreeselect/:roleId", Method: "GET"},
+	{Url: "/api/roleDeptTreeselect/:roleId", Method: "GET"},
+	{Url: "/api/refresh_token", Method: "GET"},
+	{Url: "/api/configKey/:configKey", Method: "GET"},
+	{Url: "/api/app-config", Method: "GET"},
+	{Url: "/api/user/profile", Method: "GET"},
+	{Url: "/info", Method: "GET"},
+	{Url: "/api/login", Method: "POST"},
+	{Url: "/api/logout", Method: "POST"},
+	{Url: "/api/user/pwd/set", Method: "PUT"},
+	{Url: "/api/metrics", Method: "GET"},
+	{Url: "/api/health", Method: "GET"},
+	{Url: "/", Method: "GET"},
+	{Url: "/api/server-monitor", Method: "GET"},
+	{Url: "/api/public/uploadFile", Method: "POST"},
+	{Url: "/api/public/download", Method: "GET"},
+}
+
+// LogExclude log 排除的路由列表
+var LogExclude = []UrlInfo{
+	{Url: "/api/public/uploadFile", Method: "POST"},
+	{Url: "/api/public/download", Method: "GET"},
+}

+ 98 - 0
common/model/byat.go

@@ -0,0 +1,98 @@
+package model
+
+import (
+	"database/sql/driver"
+	"fmt"
+	"gorm.io/gorm"
+	"time"
+)
+
+type ControlBy struct {
+	CreateBy int `json:"createBy" gorm:"index;comment:创建者"` // 创建者
+	UpdateBy int `json:"updateBy" gorm:"index;comment:更新者"` // 更新者
+}
+
+// SetCreateBy 设置创建人id
+func (e *ControlBy) SetCreateBy(createBy int) {
+	e.CreateBy = createBy
+}
+
+// SetUpdateBy 设置修改人id
+func (e *ControlBy) SetUpdateBy(updateBy int) {
+	e.UpdateBy = updateBy
+}
+
+type DeptBy struct {
+	DeptId int `json:"deptId" gorm:"index;comment:部门id"` // 部门id
+}
+
+// SetCreateBy 设置创建人id
+func (e *DeptBy) SetDeptId(deptId int) {
+	e.DeptId = deptId
+}
+
+type Model struct {
+	Id int `json:"id" gorm:"primaryKey;autoIncrement;comment:主键编码"` // 主键编码
+}
+
+type ModelTime struct {
+	CreatedAt Time           `json:"createdAt" gorm:"type:timestamp;comment:创建时间"`                  // 创建时间
+	UpdatedAt Time           `json:"updatedAt" gorm:"type:timestamp;comment:最后更新时间;autoUpdateTime"` // 最后更新时间
+	DeletedAt gorm.DeletedAt `json:"-" gorm:"index;comment:删除时间"`
+}
+
+const timeFormat = "2006-01-02 15:04:05"
+const timezone = "Asia/Shanghai"
+
+// 全局定义
+type Time time.Time
+
+func (t Time) MarshalJSON() ([]byte, error) {
+	b := make([]byte, 0, len(timeFormat)+2)
+	if time.Time(t).IsZero() {
+		b = append(b, '"')
+		b = append(b, '"')
+		return b, nil
+	}
+
+	b = append(b, '"')
+	b = time.Time(t).AppendFormat(b, timeFormat)
+	b = append(b, '"')
+	return b, nil
+}
+
+func (t *Time) UnmarshalJSON(data []byte) (err error) {
+	now, err := time.ParseInLocation(`"`+timeFormat+`"`, string(data), time.Local)
+	*t = Time(now)
+	return
+}
+
+func (t Time) String() string {
+	if time.Time(t).IsZero() {
+		return ""
+	}
+	return time.Time(t).Format(timeFormat)
+}
+
+func (t Time) local() time.Time {
+	loc, _ := time.LoadLocation(timezone)
+	return time.Time(t).In(loc)
+}
+
+func (t Time) Value() (driver.Value, error) {
+	var zeroTime time.Time
+	var ti = time.Time(t)
+	if ti.UnixNano() == zeroTime.UnixNano() {
+		return nil, nil
+	}
+	return ti, nil
+}
+
+func (t *Time) Scan(v interface{}) error {
+	value, ok := v.(time.Time)
+	if ok {
+		*t = Time(value)
+		return nil
+	}
+	return fmt.Errorf("can not convert %v to timestamp", v)
+}

+ 13 - 0
common/model/menu.go

@@ -0,0 +1,13 @@
+package model
+
+// Menu 菜单中的类型枚举值
+const (
+	// Directory 目录
+	Directory string = "M"
+
+	// Menu 菜单
+	Menu string = "C"
+
+	// Button 按钮
+	Button string = "F"
+)

+ 13 - 0
common/model/pay.go

@@ -0,0 +1,13 @@
+package model
+
+// PayAudit 缴费审核状态枚举值
+const (
+	// 未提交审核
+	PayAuditNotSubmit int = 1
+	// 待审核
+	PayAuditWait int = 2
+	// 审核通过
+	PayAuditPass int = 3
+	// 审核不通过
+	PayAuditNotPass int = 4
+)

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff