Browse Source

first commit

zoie 9 months ago
commit
e3366ae976
100 changed files with 13709 additions and 0 deletions
  1. 44 0
      .gitignore
  2. 26 0
      Dockerfile
  3. 36 0
      Makefile
  4. 112 0
      README.md
  5. 204 0
      app/admin/controller/address.go
  6. 39 0
      app/admin/controller/captcha.go
  7. 197 0
      app/admin/controller/car.go
  8. 225 0
      app/admin/controller/company.go
  9. 322 0
      app/admin/controller/cooler_box.go
  10. 431 0
      app/admin/controller/customer.go
  11. 74 0
      app/admin/controller/device.go
  12. 123 0
      app/admin/controller/sys_login_log_controller.go
  13. 128 0
      app/admin/controller/sys_opera_log.go
  14. 519 0
      app/admin/controller/sys_user.go
  15. 106 0
      app/admin/controller/upload.go
  16. 197 0
      app/admin/controller/warehouse.go
  17. 2057 0
      app/admin/controller/waybill.go
  18. 51 0
      app/admin/controller/waybill_logistics.go
  19. 142 0
      app/admin/controller/waybill_task.go
  20. 40 0
      app/admin/model/address.go
  21. 15 0
      app/admin/model/address_default.go
  22. 33 0
      app/admin/model/car.go
  23. 27 0
      app/admin/model/cooler_box.go
  24. 75 0
      app/admin/model/sys_dept.go
  25. 72 0
      app/admin/model/sys_login_log.go
  26. 45 0
      app/admin/model/sys_menu.go
  27. 92 0
      app/admin/model/sys_opera_log.go
  28. 50 0
      app/admin/model/sys_role.go
  29. 74 0
      app/admin/model/sys_role_menu.go
  30. 113 0
      app/admin/model/sys_user.go
  31. 32 0
      app/admin/model/warehouse.go
  32. 67 0
      app/admin/model/waybill.go
  33. 38 0
      app/admin/model/waybill_logistics.go
  34. 31 0
      app/admin/model/waybill_task.go
  35. 25 0
      app/admin/router/address.go
  36. 19 0
      app/admin/router/captcha.go
  37. 25 0
      app/admin/router/car.go
  38. 29 0
      app/admin/router/company.go
  39. 30 0
      app/admin/router/cooler_box.go
  40. 31 0
      app/admin/router/customer.go
  41. 23 0
      app/admin/router/device.go
  42. 90 0
      app/admin/router/init_router.go
  43. 11 0
      app/admin/router/router.go
  44. 25 0
      app/admin/router/sys_login_log.go
  45. 24 0
      app/admin/router/sys_opera_log.go
  46. 49 0
      app/admin/router/sys_user.go
  47. 20 0
      app/admin/router/upload.go
  48. 26 0
      app/admin/router/warehouse.go
  49. 56 0
      app/admin/router/waybill.go
  50. 20 0
      app/admin/router/waybill_logistics.go
  51. 23 0
      app/admin/router/waybill_task.go
  52. 259 0
      app/admin/service/address.go
  53. 281 0
      app/admin/service/car.go
  54. 224 0
      app/admin/service/company.go
  55. 235 0
      app/admin/service/cooler_box.go
  56. 306 0
      app/admin/service/customer.go
  57. 64 0
      app/admin/service/device.go
  58. 131 0
      app/admin/service/dto/address.go
  59. 102 0
      app/admin/service/dto/car.go
  60. 115 0
      app/admin/service/dto/company.go
  61. 109 0
      app/admin/service/dto/cooler_box.go
  62. 192 0
      app/admin/service/dto/customer.go
  63. 11 0
      app/admin/service/dto/device.go
  64. 58 0
      app/admin/service/dto/sys_login_log_dto.go
  65. 134 0
      app/admin/service/dto/sys_menu.go
  66. 103 0
      app/admin/service/dto/sys_opera_log_dto.go
  67. 158 0
      app/admin/service/dto/sys_role.go
  68. 185 0
      app/admin/service/dto/sys_user.go
  69. 107 0
      app/admin/service/dto/warehouse.go
  70. 256 0
      app/admin/service/dto/waybill.go
  71. 17 0
      app/admin/service/dto/waybill_logistics.go
  72. 46 0
      app/admin/service/dto/waybill_task.go
  73. 72 0
      app/admin/service/sys_login_log_service.go
  74. 669 0
      app/admin/service/sys_menu.go
  75. 84 0
      app/admin/service/sys_opera_log_service.go
  76. 404 0
      app/admin/service/sys_role.go
  77. 348 0
      app/admin/service/sys_user.go
  78. 278 0
      app/admin/service/warehouse.go
  79. 915 0
      app/admin/service/waybill.go
  80. 32 0
      app/admin/service/waybill_logistics.go
  81. 229 0
      app/admin/service/waybill_task.go
  82. 182 0
      cmd/api/server.go
  83. 51 0
      cmd/cobra.go
  84. 62 0
      cmd/config/server.go
  85. 63 0
      cmd/migrate/initdb.go
  86. 41 0
      cmd/migrate/server.go
  87. 49 0
      common/actions/create.go
  88. 61 0
      common/actions/delete.go
  89. 58 0
      common/actions/index.go
  90. 127 0
      common/actions/permission.go
  91. 5 0
      common/actions/type.go
  92. 59 0
      common/actions/update.go
  93. 67 0
      common/actions/view.go
  94. 75 0
      common/amap/amap.go
  95. 106 0
      common/dto/generate.go
  96. 12 0
      common/dto/order.go
  97. 20 0
      common/dto/pagination.go
  98. 94 0
      common/dto/search.go
  99. 21 0
      common/dto/type.go
  100. 69 0
      common/file_store/initialize.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-delivery","server","-c", "/etc/conf/settings.yml"]

+ 36 - 0
Makefile

@@ -0,0 +1,36 @@
+PACKAGE=cold-delivery
+PREFIX=$(shell pwd)
+CMD_PACKAGE=${PACKAGE}
+OUTPUT_DIR=${PREFIX}/bin
+OUTPUT_FILE=${OUTPUT_DIR}/cold-delivery
+OUTPUT_FILE_LINUX=${OUTPUT_DIR}/linux/cold-delivery6280
+COMMIT_ID=$(shell git rev-parse --short HEAD)
+VERSION=$(shell git describe --tags || echo "v0.0.1")
+VERSION_IMPORT_PATH=github.com/lneoe/go-help-libs/version
+BUILD_TIME=$(shell date '+%Y-%m-%dT%H:%M:%S%Z')
+VCS_BRANCH=$(shell git symbolic-ref --short -q HEAD)
+
+# build args
+BUILD_ARGS := \
+    -ldflags "-X $(VERSION_IMPORT_PATH).appName=$(PACKAGE) \
+    -X $(VERSION_IMPORT_PATH).version=$(VERSION) \
+    -X $(VERSION_IMPORT_PATH).revision=$(COMMIT_ID) \
+    -X $(VERSION_IMPORT_PATH).branch=$(VCS_BRANCH) \
+    -X $(VERSION_IMPORT_PATH).buildDate=$(BUILD_TIME)"
+EXTRA_BUILD_ARGS=
+build:
+	@echo "+ build"
+	go build $(BUILD_ARGS) $(EXTRA_BUILD_ARGS) -o ${OUTPUT_FILE} $(CMD_PACKAGE)
+
+build-linux:
+	@echo "+ build linux"
+	GOOS=linux GOARCH=amd64 go build $(BUILD_ARGS) $(EXTRA_BUILD_ARGS) -o ${OUTPUT_FILE_LINUX} $(CMD_PACKAGE)
+
+
+#.PHONY: test
+#test:
+#	go test -v ./... -cover
+
+#.PHONY: docker
+#docker:
+#	docker build . -t cold-delivery:latest

+ 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) 参数校验

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

@@ -0,0 +1,204 @@
+package controller
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/app/admin/service"
+	"cold-delivery/app/admin/service/dto"
+	"cold-delivery/common/actions"
+	"errors"
+	"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
+	}
+
+	if req.AddressType != model.AddressTypeConsignee && req.AddressType != model.AddressTypeSender {
+		err = errors.New("地址类型错误")
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	//数据权限检查
+	p := actions.GetPermissionFromContext(c)
+
+	//数据权限检查
+	list := make([]model.Address, 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.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
+	}
+	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.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",
+	})
+}

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

@@ -0,0 +1,197 @@
+package controller
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/app/admin/service"
+	"cold-delivery/app/admin/service/dto"
+	"cold-delivery/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 CarController 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.Car}} "{"code": 200, "data": [...]}"
+// @Router /api/car [get]
+// @Security Bearer
+func (e CarController) GetPage(c *gin.Context) {
+	s := service.Car{}
+	req := dto.CarGetPageReq{}
+	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.Car, 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.Car} "{"code": 200, "data": [...]}"
+// @Router /api/car/{id} [get]
+// @Security Bearer
+func (e CarController) Get(c *gin.Context) {
+	s := service.Car{}
+	req := dto.CarGetReq{}
+	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.Car
+	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.CarInsertReq true "data"
+// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
+// @Router /api/car [post]
+// @Security Bearer
+func (e CarController) Insert(c *gin.Context) {
+	s := service.Car{}
+	req := dto.CarInsertReq{}
+	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.CarUpdateReq true "body"
+// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
+// @Router /api/car [put]
+// @Security Bearer
+func (e CarController) Update(c *gin.Context) {
+	s := service.Car{}
+	req := dto.CarUpdateReq{}
+	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.CarDeleteReq true "body"
+// @Success 200 {string} string	"{"code": 200, "message": "删除成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "删除失败"}"
+// @Router /api/car [delete]
+// @Security Bearer
+func (e CarController) Delete(c *gin.Context) {
+	s := service.Car{}
+	req := dto.CarDeleteReq{}
+	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(), "删除成功")
+}

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

@@ -0,0 +1,225 @@
+package controller
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/app/admin/service"
+	"cold-delivery/app/admin/service/dto"
+	"cold-delivery/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/company [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(), "查询成功")
+}
+
+// GetAll 添加用户-获取公司列表
+// @Summary 添加用户-获取公司列表
+// @Description 添加用户-获取公司列表
+// @Tags 公司
+// @Param id path string true "公司id"
+// @Success 200 {object} response.Response{data=model.SysDept} "{"code": 200, "data": [...]}"
+// @Router /api/company/{id} [get]
+// @Security Bearer
+func (e CompanyController) GetAll(c *gin.Context) {
+	s := service.Company{}
+	req := dto.CompanyGetAllReq{}
+	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.GetAll(&req, &list, &count, p)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.PageOK(list, int(count), 0, 0, "查询成功")
+}
+
+// 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/company/{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/company [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))
+	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.CompanyUpdateReq true "body"
+// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
+// @Router /api/company [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/company [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
+	}
+
+	//数据权限检查
+	//p := actions.GetPermissionFromContext(c)
+	err = s.Remove(&req, nil)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.OK(req.GetId(), "删除成功")
+}

+ 322 - 0
app/admin/controller/cooler_box.go

@@ -0,0 +1,322 @@
+package controller
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/app/admin/service"
+	"cold-delivery/app/admin/service/dto"
+	"cold-delivery/common/actions"
+	"cold-delivery/common/nats/nats_server"
+	"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 CoolerBoxController 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.CoolerBox}} "{"code": 200, "data": [...]}"
+// @Router /api/CoolerBox [get]
+// @Security Bearer
+func (e CoolerBoxController) GetPage(c *gin.Context) {
+	s := service.CoolerBox{}
+	req := dto.CoolerBoxGetPageReq{}
+	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.CoolerBox, 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.CoolerBox} "{"code": 200, "data": [...]}"
+// @Router /api/CoolerBox/{id} [get]
+// @Security Bearer
+func (e CoolerBoxController) Get(c *gin.Context) {
+	s := service.CoolerBox{}
+	req := dto.CoolerBoxGetReq{}
+	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.CoolerBox
+	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.CoolerBoxInsertReq true "data"
+// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
+// @Router /api/CoolerBox [post]
+// @Security Bearer
+func (e CoolerBoxController) Insert(c *gin.Context) {
+	s := service.CoolerBox{}
+	req := dto.CoolerBoxInsertReq{}
+	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.CoolerBoxUpdateReq true "body"
+// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
+// @Router /api/CoolerBox [put]
+// @Security Bearer
+func (e CoolerBoxController) Update(c *gin.Context) {
+	s := service.CoolerBox{}
+	req := dto.CoolerBoxUpdateReq{}
+	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.CoolerBoxDeleteReq true "body"
+// @Success 200 {string} string	"{"code": 200, "message": "删除成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "删除失败"}"
+// @Router /api/CoolerBox [delete]
+// @Security Bearer
+func (e CoolerBoxController) Delete(c *gin.Context) {
+	s := service.CoolerBox{}
+	req := dto.CoolerBoxDeleteReq{}
+	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(), "删除成功")
+}
+
+// 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.CoolerBox}} "{"code": 200, "data": [...]}"
+// @Router /api/CoolerBox [get]
+// @Security Bearer
+func (e CoolerBoxController) GetDevicePage(c *gin.Context) {
+	s := service.CoolerBox{}
+	req := dto.DeviceGetPageReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		MakeService(&s.Service).
+		Bind(&req, binding.Query).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	list := make([]nats_server.Device_R, 0)
+	p := actions.GetPermissionFromContext(c)
+
+	var coolerBoxCount int64
+	coolerBoxList := make([]model.CoolerBox, 0)
+
+	coolerBoxReq := dto.CoolerBoxGetPageReq{}
+	coolerBoxReq.PageSize = 9999
+	err = s.GetPage(&coolerBoxReq, &coolerBoxList, &coolerBoxCount, p)
+
+	var count int64
+	company, err := model.GetCompanyById(p.DeptId)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	list, count, err = nats_server.Cold_ReadDevice_List(req.Name, company.ColdKey, req.GetPageIndex(), 9999)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	var coolerBoxMap = make(map[string]model.CoolerBox)
+	for _, box := range coolerBoxList {
+		coolerBoxMap[box.Sn] = box
+	}
+	// Fixme 测试完成之后删除
+	//for i := 0; i < 20; i++ {
+	//	list = append(list, nats_server.Device_R{
+	//		T_devName: fmt.Sprintf("保温箱%03d", i),
+	//		T_sn:      fmt.Sprintf("2024114956064%03d", i),
+	//	})
+	//}
+
+	list2 := make([]nats_server.Device_R, 0)
+	for i := 0; i < len(list); i++ {
+		if _, ok := coolerBoxMap[list[i].T_sn]; ok {
+			count--
+			continue
+		}
+		list2 = append(list2, list[i])
+	}
+
+	//if len(list2) == 0 {
+	//	e.PageOK(list2, len(list2), req.GetPageIndex(), req.GetPageSize(), "查询成功")
+	//}
+
+	// 计算总页数
+	totalPages := (len(list2) + req.GetPageSize() - 1) / req.GetPageSize()
+
+	// 如果n超出范围,返回错误
+	if req.GetPageIndex() > totalPages {
+		req.Page = totalPages
+	}
+	// 计算当前页的数据
+	start := (req.GetPageIndex() - 1) * req.GetPageSize()
+	end := start + req.GetPageSize()
+	if end > len(list2) {
+		end = len(list2)
+	}
+	currentPage := list2[start:end]
+
+	e.PageOK(currentPage, len(list2), req.GetPageIndex(), req.GetPageSize(), "查询成功")
+}
+
+// BatchInsert 批量添加保温箱
+// @Summary 批量添加保温箱
+// @Description 批量添加保温箱
+// @Tags 保温箱
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.CoolerBoxInsertReq true "data"
+// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
+// @Router /api/CoolerBox [post]
+// @Security Bearer
+func (e CoolerBoxController) BatchInsert(c *gin.Context) {
+	s := service.CoolerBox{}
+	req := dto.CoolerBoxBatchInsertReq{}
+	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.BatchInsert(&req)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.OK(nil, "创建成功")
+}

+ 431 - 0
app/admin/controller/customer.go

@@ -0,0 +1,431 @@
+package controller
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/app/admin/service"
+	"cold-delivery/app/admin/service/dto"
+	"cold-delivery/common/actions"
+	"cold-delivery/common/middleware/handler"
+	"cold-delivery/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"
+)
+
+// Customer 定义客户控制器
+type Customer struct {
+	api.Api
+}
+
+// GetPage 获取客户列表
+// @Summary 获取客户列表
+// @Description 获取客户列表
+// @Tags 客户
+// @Param username query string false "客户名"
+// @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/customer [get]
+// @Security Bearer
+func (e Customer) GetPage(c *gin.Context) {
+	s := service.Customer{}
+	req := dto.CustomerGetPageReq{}
+	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(), "查询成功")
+}
+
+// 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/customer/{id} [get]
+// @Security Bearer
+func (e Customer) Get(c *gin.Context) {
+	s := service.Customer{}
+	req := dto.CustomerGetReq{}
+	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, nil, &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.CustomerInsertReq true "客户数据"
+// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
+// @Router /api/customer [post]
+// @Security Bearer
+func (e Customer) Insert(c *gin.Context) {
+	s := service.Customer{}
+	req := dto.CustomerInsertReq{}
+	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)
+	if p.DeptId == 0 {
+		err = errors.New("无权添加,请联系管理员!")
+		e.Error(500, err, err.Error())
+		return
+	}
+	// 设置创建人
+	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.CustomerUpdateReq true "body"
+// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
+// @Router /api/customer [put]
+// @Security Bearer
+func (e Customer) Update(c *gin.Context) {
+	s := service.Customer{}
+	req := dto.CustomerUpdateReq{}
+	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, nil)
+	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.CustomerDeleteReq true "body"
+// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
+// @Router /api/customer [delete]
+// @Security Bearer
+func (e Customer) Delete(c *gin.Context) {
+	s := service.Customer{}
+	req := dto.CustomerDeleteReq{}
+	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, nil)
+	if err != nil {
+		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.ResetCustomerPwdReq true "body"
+// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
+// @Router /api/user/pwd/reset [put]
+// @Security Bearer
+func (e Customer) ResetPwd(c *gin.Context) {
+	s := service.Customer{}
+	req := dto.ResetCustomerPwdReq{}
+	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, nil)
+	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.CustomerPassWord true "body"
+// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
+// @Router /api/customer/pwd/set [put]
+// @Security Bearer
+func (e Customer) UpdatePwd(c *gin.Context) {
+	s := service.Customer{}
+	req := dto.CustomerPassWord{}
+	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 Customer) GetProfile(c *gin.Context) {
+	s := service.Customer{}
+	req := dto.CustomerById{}
+	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 Customer) GetInfo(c *gin.Context) {
+	req := dto.CustomerGetReq{}
+	s := service.Customer{}
+	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 Customer) VerifyCode(c *gin.Context) {
+	s := service.Customer{}
+	req := dto.CustomerGetSMSVerifyCodeReq{}
+	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, "发送成功")
+
+}

+ 74 - 0
app/admin/controller/device.go

@@ -0,0 +1,74 @@
+package controller
+
+import (
+	"cold-delivery/app/admin/service"
+	"cold-delivery/app/admin/service/dto"
+	"cold-delivery/common/actions"
+	"github.com/gin-gonic/gin"
+	"github.com/gin-gonic/gin/binding"
+	"gogs.baozhida.cn/zoie/OAuth-core/api"
+)
+
+type DeviceController struct {
+	api.Api
+}
+
+// GetSensorList 获取传感器列表
+// @Summary 获取传感器列表
+// @Description 获取传感器列表
+// @Tags 设备
+// @Success 200 {object} response.Response{data=response.Page{list=[]model.Device}} "{"code": 200, "data": [...]}"
+// @Router /api/device/sensor-list [get]
+// @Security Bearer
+func (e DeviceController) GetSensorList(c *gin.Context) {
+	s := service.Device{}
+	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)
+
+	// 获取传感器信息
+	deviceSensorList, count, _ := s.GetSensorList(p)
+	e.PageOK(deviceSensorList, int(count), 0, 0, "查询成功")
+}
+
+// GetData 获取车辆温湿度信息
+// @Summary 获取车辆温湿度信息
+// @Description 获取车辆温湿度信息
+// @Tags 设备
+// @Param t_sn query string false "sn"
+// @Param t_id query string false "传感器id"
+// @Param pageSize query int false "页条数"
+// @Param page query int false "页码"
+// @Success 200 {object} response.Response{data=response.Page{list=[]model.Device}} "{"code": 200, "data": [...]}"
+// @Router /api/device/sensor-list [get]
+// @Security Bearer
+func (e DeviceController) GetData(c *gin.Context) {
+	s := service.Device{}
+	req := dto.DeviceGetDataReq{}
+	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)
+
+	// 获取传感器信息
+	dataList, count, _ := s.GetData(req, p)
+	e.PageOK(dataList, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
+}

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

@@ -0,0 +1,123 @@
+package controller
+
+import (
+	"cold-delivery/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-delivery/app/admin/model"
+	"cold-delivery/app/admin/service"
+	"cold-delivery/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(), "删除成功")
+}

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

@@ -0,0 +1,128 @@
+package controller
+
+import (
+	"cold-delivery/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-delivery/app/admin/model"
+	"cold-delivery/app/admin/service"
+	"cold-delivery/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(), "删除成功")
+}

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

@@ -0,0 +1,519 @@
+package controller
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/app/admin/service"
+	"cold-delivery/app/admin/service/dto"
+	"cold-delivery/common/actions"
+	"cold-delivery/common/middleware/handler"
+	"cold-delivery/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(), "查询成功")
+}
+
+// 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, nil, &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{}
+	req := dto.SysUserInsertReq{}
+	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)
+	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, nil)
+	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, nil)
+	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.SysUserPassWord 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.SysUserPassWord{}
+	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, "发送成功")
+
+}
+
+// GetPageFoeBind 获取用户列表-仓库/车辆绑定
+// @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) GetPageFoeBind(c *gin.Context) {
+	warehouseSvc := service.Warehouse{}
+	carSvc := service.Car{}
+	req := dto.SysUserGetPageReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.Query).
+		MakeService(&warehouseSvc.Service).
+		MakeService(&carSvc.Service).
+		Errors
+
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	//数据权限检查
+	p := actions.GetPermissionFromContext(c)
+
+	list := make([]model.SysUserForBind, 0)
+	var count int64
+
+	if req.Type == 2 {
+		err = warehouseSvc.GetUserList(&req, p, &list, &count)
+		if err != nil {
+			e.Error(500, err, err.Error())
+			return
+		}
+	}
+	if req.Type == 3 {
+		err = carSvc.GetUserList(&req, p, &list, &count)
+		if err != nil {
+			e.Error(500, err, err.Error())
+			return
+		}
+	}
+
+	e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
+}

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

@@ -0,0 +1,106 @@
+package controller
+
+import (
+	"cold-delivery/common/file_store"
+	"cold-delivery/conf"
+	"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/upload [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")
+	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)
+	}()
+
+	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": conf.ExtConfig.Qiniu.Endpoint + filename,
+		"msg":  "success",
+	})
+}
+
+// ApkUpload 文件上传
+// @Summary 文件上传
+// @Description 文件上传
+// @Tags 工具
+// @Success 200 {object} response.Response{data=string,id=string,msg=string} "{"code": 200, "data": [...]}"
+// @Router /api/apk-upload [get]
+func (e UploadController) ApkUpload(c *gin.Context) {
+	err := e.MakeContext(c).Errors
+	if err != nil {
+		e.Error(500, err, "服务初始化失败!")
+		return
+	}
+
+	// 处理文件上传逻辑
+	file, err := c.FormFile("file")
+	uploadFileName := file.Filename          // 获取文件名
+	fileType := filepath.Ext(uploadFileName) // 获取文件类型(扩展名)
+	if err != nil {
+		c.JSON(500, gin.H{"error": err.Error()})
+		return
+	}
+	if fileType != ".apk" {
+		c.JSON(500, gin.H{"code": 200,
+			"data": conf.ExtConfig.Apk.Path + "/" + uploadFileName,
+			"msg":  "success"})
+		return
+	}
+	filePath := conf.ExtConfig.Apk.Path + "/" + uploadFileName
+	err = c.SaveUploadedFile(file, filePath)
+	if err != nil {
+		c.JSON(500, gin.H{"error": err.Error()})
+		return
+	}
+
+	e.Custom(gin.H{
+		"code": 200,
+		"data": conf.ExtConfig.Apk.Path + "/" + uploadFileName,
+		"msg":  "success",
+	})
+}

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

@@ -0,0 +1,197 @@
+package controller
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/app/admin/service"
+	"cold-delivery/app/admin/service/dto"
+	"cold-delivery/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(), "删除成功")
+}

+ 2057 - 0
app/admin/controller/waybill.go

@@ -0,0 +1,2057 @@
+package controller
+
+import (
+	"bufio"
+	"cold-delivery/app/admin/model"
+	"cold-delivery/app/admin/service"
+	"cold-delivery/app/admin/service/dto"
+	"cold-delivery/common/actions"
+	"cold-delivery/common/lib"
+	"cold-delivery/common/nats/nats_server"
+	"errors"
+	"fmt"
+	"github.com/beego/beego/v2/core/logs"
+	"github.com/gin-gonic/gin"
+	"github.com/gin-gonic/gin/binding"
+	"github.com/golang/freetype/truetype"
+	"github.com/signintech/gopdf"
+	"github.com/wcharczuk/go-chart/v2"
+	"github.com/wcharczuk/go-chart/v2/drawing"
+	"github.com/xuri/excelize/v2"
+	"gogs.baozhida.cn/zoie/OAuth-core/api"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth/user"
+	_ "gogs.baozhida.cn/zoie/OAuth-core/pkg/response"
+	"gonum.org/v1/plot"
+	"gonum.org/v1/plot/plotter"
+	"gonum.org/v1/plot/vg"
+	"gonum.org/v1/plot/vg/draw"
+	"image/color"
+	"log"
+	"math"
+	"net/url"
+	"os"
+	"path"
+	"sort"
+	"strconv"
+	"sync"
+	"time"
+)
+
+type WaybillController struct {
+	api.Api
+}
+
+// GetPage 获取运单列表
+// @Summary 获取运单列表
+// @Description 获取运单列表
+// @Tags 运单
+// @Param no query string false "运单号"
+// @Param pageSize query int false "页条数"
+// @Param page query int false "页码"
+// @Success 200 {object} response.Response{data=response.Page{list=[]model.Waybill}} "{"code": 200, "data": [...]}"
+// @Router /api/waybill [get]
+// @Security Bearer
+func (e WaybillController) GetPage(c *gin.Context) {
+	s := service.Waybill{}
+	req := dto.WaybillGetPageReq{}
+	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.Waybill, 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(), "查询成功")
+}
+
+// GetPage 获取运单列表
+// @Summary 获取运单列表
+// @Description 获取运单列表
+// @Tags 运单
+// @Param no query string false "运单号"
+// @Param pageSize query int false "页条数"
+// @Param page query int false "页码"
+// @Success 200 {object} response.Response{data=response.Page{list=[]model.Waybill}} "{"code": 200, "data": [...]}"
+// @Router /api/waybill [get]
+// @Security Bearer
+func (e WaybillController) Export(c *gin.Context) {
+	s := service.Waybill{}
+	req := dto.WaybillGetPageReq{}
+	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.Waybill, 0)
+	var count int64
+	req.PageSize = 9999
+	err = s.GetPage(&req, &list, &count, p)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	f := excelize.NewFile() // 设置单元格的值
+	// 这里设置表头ÒÒ
+	f.SetCellValue("Sheet1", "A1", "序号")
+	f.SetCellValue("Sheet1", "B1", "状态")
+	f.SetCellValue("Sheet1", "C1", "寄件人名称")
+	f.SetCellValue("Sheet1", "D1", "寄件人电话")
+	f.SetCellValue("Sheet1", "E1", "寄件人地址")
+	f.SetCellValue("Sheet1", "F1", "收件人名称")
+	f.SetCellValue("Sheet1", "G1", "收件人电话")
+	f.SetCellValue("Sheet1", "H1", "收件人地址")
+	f.SetCellValue("Sheet1", "I1", "防拆标签码")
+	f.SetCellValue("Sheet1", "J1", "运输备注")
+	//f.SetCellValue("Sheet1", "K1", "货物类型")
+	//f.SetCellValue("Sheet1", "L1", "运输备注")
+
+	// 设置列宽
+	f.SetColWidth("Sheet1", "A", "A", 6)
+	f.SetColWidth("Sheet1", "B", "B", 8)
+	f.SetColWidth("Sheet1", "C", "C", 14)
+	f.SetColWidth("Sheet1", "D", "D", 14)
+	f.SetColWidth("Sheet1", "E", "E", 30)
+	f.SetColWidth("Sheet1", "F", "F", 14)
+	f.SetColWidth("Sheet1", "G", "G", 14)
+	f.SetColWidth("Sheet1", "H", "H", 30)
+	f.SetColWidth("Sheet1", "I", "K", 15)
+	f.SetColWidth("Sheet1", "L", "L", 15)
+
+	line := 1
+
+	// 循环写入数据
+	for i, v := range list {
+		line++
+		f.SetCellValue("Sheet1", fmt.Sprintf("A%d", line), i+1)
+		f.SetCellValue("Sheet1", fmt.Sprintf("B%d", line), model.WaybillStatusMap[v.Status])
+		f.SetCellValue("Sheet1", fmt.Sprintf("C%d", line), v.SenderAddressName)
+		f.SetCellValue("Sheet1", fmt.Sprintf("D%d", line), v.SenderAddressPhone)
+		f.SetCellValue("Sheet1", fmt.Sprintf("E%d", line), v.SenderAddressDetails)
+		f.SetCellValue("Sheet1", fmt.Sprintf("F%d", line), v.ConsigneeAddressName)
+		f.SetCellValue("Sheet1", fmt.Sprintf("G%d", line), v.ConsigneeAddressPhone)
+		f.SetCellValue("Sheet1", fmt.Sprintf("H%d", line), v.ConsigneeAddressDetails)
+		//f.SetCellValue("Sheet1", fmt.Sprintf("I%d", line), v.TemperatureInterval)
+		//f.SetCellValue("Sheet1", fmt.Sprintf("J%d", line), v.DeliveryCondition)
+		//f.SetCellValue("Sheet1", fmt.Sprintf("K%d", line), v.CargoType)
+		f.SetCellValue("Sheet1", fmt.Sprintf("I%d", line), v.Remark)
+
+	}
+	timeStr := time.Now().Format("20060102150405")
+	filePath := "ofile/" + "运单" + timeStr + ".xlsx"
+	// 保存文件
+	if err = f.SaveAs(filePath); err != nil {
+		logs.Error("保存运单失败:", err)
+	}
+	defer func() {
+		os.Remove(filePath)
+	}()
+	c.Header("Content-Type", "application/vnd.ms-excel;charset=utf8")
+	// PathEscape 函数对中文做处理
+	c.Header("Content-Disposition", "attachment; filename="+url.PathEscape("运单"+timeStr+".xlsx"))
+	c.Header("Content-Transfer-Encoding", "binary")
+	c.File(filePath)
+}
+
+// Home 首页统计
+// @Summary 首页统计
+// @Description 首页统计
+// @Tags 运单
+// @Param no query string false "运单号"
+// @Param pageSize query int false "页条数"
+// @Param page query int false "页码"
+// @Success 200 {object} response.Response{data=response.Page{list=[]model.Waybill}} "{"code": 200, "data": [...]}"
+// @Router /api/waybill [get]
+// @Security Bearer
+func (e WaybillController) Home(c *gin.Context) {
+	s := service.Waybill{}
+	req := dto.WaybillStatsReq{}
+	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)
+
+	res := s.GetBasicsStats(&req, p)
+	e.OK(res, "查询成功")
+}
+
+// GetAppletPage 获取运单列表
+// @Summary 获取运单列表
+// @Description 获取运单列表
+// @Tags 运单
+// @Param no query string false "运单号"
+// @Param pageSize query int false "页条数"
+// @Param page query int false "页码"
+// @Success 200 {object} response.Response{data=response.Page{list=[]model.Waybill}} "{"code": 200, "data": [...]}"
+// @Router /api/waybill [get]
+// @Security Bearer
+func (e WaybillController) GetAppletPage(c *gin.Context) {
+	s := service.Waybill{}
+	req := dto.WaybillGetAppletPageReq{}
+	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.Waybill, 0)
+	var count int64
+	err = s.GetAppletPage(&req, &list, &count, p)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
+}
+
+// GetAppletCount 获取app运单统计数量
+// @Summary 获取app运单统计数量
+// @Description 获取app运单统计数量
+// @Tags 运单
+// @Param no query string false "运单号"
+// @Success 200 {object} response.Response{data=response.Page{list=[]model.Waybill}} "{"code": 200, "data": [...]}"
+// @Router /api/waybill/applet-count [get]
+// @Security Bearer
+func (e WaybillController) GetAppletCount(c *gin.Context) {
+	s := service.Waybill{}
+	userSvc := service.SysUser{}
+	req := dto.WaybillGetAppletPageReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.Query).
+		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)
+	var userObj model.SysUser
+	err = userSvc.Get(&dto.SysUserGetReq{Id: p.UserId}, nil, &userObj)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	list := make([]model.Waybill, 0)
+	var count int64
+
+	if userObj.UserType == "customer" {
+		r := dto.WaybillGetCustomerPageReq{}
+		r.PageSize = 9999
+		r.CustomerId = p.UserId
+		err = s.GetCustomerPage(&r, &list, &count, p)
+		var statusCount = make(map[int]int)
+		statusCount[0] = int(count)
+		for _, waybill := range list {
+			if _, ok := statusCount[waybill.Status]; ok {
+				statusCount[waybill.Status] += 1
+			} else {
+				statusCount[waybill.Status] = 1
+			}
+		}
+		e.OK(statusCount, "查询成功")
+		return
+	}
+
+	err = s.GetAppletCount(&list, &count, p)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	var statusCount = make(map[int]int)
+	statusCount[0] = int(count)
+	for _, waybill := range list {
+		if _, ok := statusCount[waybill.Status]; ok {
+			statusCount[waybill.Status] += 1
+		} else {
+			statusCount[waybill.Status] = 1
+		}
+	}
+
+	e.OK(statusCount, "查询成功")
+}
+
+// Get 通过id获取运单
+// @Summary 通过id获取运单
+// @Description 通过id获取运单
+// @Tags 运单
+// @Param id path string true "运单id"
+// @Success 200 {object} response.Response{data=model.Waybill} "{"code": 200, "data": [...]}"
+// @Router /api/waybill/{id} [get]
+// @Security Bearer
+func (e WaybillController) Get(c *gin.Context) {
+	s := service.Waybill{}
+	req := dto.WaybillGetReq{}
+	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.Waybill
+	p := actions.GetPermissionFromContext(c)
+
+	//数据权限检查
+	err = s.Get(&req, &object, p)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	e.OK(object, "查询成功")
+}
+
+// GetByWaybillNo 通过id获取运单
+// @Summary 通过id获取运单
+// @Description 通过id获取运单
+// @Tags 运单
+// @Param id path string true "运单id"
+// @Success 200 {object} response.Response{data=model.Waybill} "{"code": 200, "data": [...]}"
+// @Router /api/waybill/no [get]
+// @Security Bearer
+func (e WaybillController) GetByWaybillNo(c *gin.Context) {
+	s := service.Waybill{}
+	req := dto.WaybillGetByWaybillPdfReq{}
+	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
+	}
+	var object model.Waybill
+
+	//数据权限检查
+	err = s.GetByWaybillNo(&req, &object, nil)
+	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.WaybillInsertReq true "data"
+// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
+// @Router /api/waybill [post]
+// @Security Bearer
+func (e WaybillController) Insert(c *gin.Context) {
+	s := service.Waybill{}
+	req := dto.WaybillInsertReq{}
+	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(), "创建成功")
+}
+
+// AppletInsert 添加运单app
+// @Summary 添加运单app
+// @Description 添加运单app
+// @Tags 运单
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.WaybillInsertReq true "data"
+// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
+// @Router /api/waybill [post]
+// @Security Bearer
+func (e WaybillController) AppletInsert(c *gin.Context) {
+	s := service.Waybill{}
+	req := dto.WaybillInsertReq{}
+	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.AppletInsert(&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.WaybillUpdateStatusReq true "body"
+// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
+// @Router /api/waybill [put]
+// @Security Bearer
+func (e WaybillController) UpdateStatus(c *gin.Context) {
+	s := service.Waybill{}
+	req := dto.WaybillUpdateStatusReq{}
+	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.UpdateStatus(&req, p)
+	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.WaybillUpdateReq true "body"
+// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
+// @Router /api/waybill [put]
+// @Security Bearer
+func (e WaybillController) Update(c *gin.Context) {
+	s := service.Waybill{}
+	req := dto.WaybillUpdateReq{}
+	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(), "更新成功")
+}
+
+// Delivery 派单
+// @Summary 派单
+// @Description 派单
+// @Tags 运单
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.WaybillDeliveryReq true "body"
+// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
+// @Router /api/waybill [put]
+// @Security Bearer
+func (e WaybillController) Delivery(c *gin.Context) {
+	s := service.Waybill{}
+	req := dto.WaybillDeliveryReq{}
+	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.Delivery(&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.WaybillDeleteReq true "body"
+// @Success 200 {string} string	"{"code": 200, "message": "删除成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "删除失败"}"
+// @Router /api/waybill [delete]
+// @Security Bearer
+func (e WaybillController) Delete(c *gin.Context) {
+	s := service.Waybill{}
+	req := dto.WaybillDeleteReq{}
+	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(), "删除成功")
+}
+
+// Receipt 签收
+// @Summary 签收
+// @Description 签收
+// @Tags 运单
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.WaybillInOutReq true "body"
+// @Success 200 {string} string	"{"code": 200, "message": "删除成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "删除失败"}"
+// @Router /api/waybill/car-out [post]
+// @Security Bearer
+func (e WaybillController) Receipt(c *gin.Context) {
+	s := service.Waybill{}
+	req := dto.WaybillReceiptReq{}
+	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)
+	err = s.Receipt(&req, p)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.OK(req.WaybillNo, "签收成功")
+}
+
+// CustomerReceipt 客户签收
+// @Summary 客户签收
+// @Description 客户签收
+// @Tags 运单
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.WaybillReceiptReq true "body"
+// @Success 200 {string} string	"{"code": 200, "message": "删除成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "删除失败"}"
+// @Router /api/waybill/car-out [post]
+// @Security Bearer
+func (e WaybillController) CustomerReceipt(c *gin.Context) {
+	s := service.Waybill{}
+	req := dto.WaybillReceiptReq{}
+	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.WaybillNo = lib.AesDecryptCBC(req.WaybillNo, lib.AesKey)
+	//数据权限检查
+	err = s.Receipt(&req, nil)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.OK(req.WaybillNo, "签收成功")
+}
+
+// GetCustomerPage 获取客户运单列表
+// @Summary 获取客户运单列表
+// @Description 获取客户运单列表
+// @Tags 运单
+// @Param no query string false "运单号"
+// @Param pageSize query int false "页条数"
+// @Param page query int false "页码"
+// @Success 200 {object} response.Response{data=response.Page{list=[]model.Waybill}} "{"code": 200, "data": [...]}"
+// @Router /api/waybill/customer [get]
+// @Security Bearer
+func (e WaybillController) GetCustomerPage(c *gin.Context) {
+	s := service.Waybill{}
+	req := dto.WaybillGetCustomerPageReq{}
+	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.Waybill, 0)
+	var count int64
+	req.CustomerId = p.UserId
+	err = s.GetCustomerPage(&req, &list, &count, p)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
+}
+
+func (e WaybillController) CustomerExport(c *gin.Context) {
+	s := service.Waybill{}
+	req := dto.WaybillGetCustomerPageReq{}
+	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.Waybill, 0)
+	var count int64
+	req.CustomerId = p.UserId
+	req.PageSize = 9999
+	err = s.GetCustomerPage(&req, &list, &count, p)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	f := excelize.NewFile() // 设置单元格的值
+	// 这里设置表头ÒÒ
+	f.SetCellValue("Sheet1", "A1", "序号")
+	f.SetCellValue("Sheet1", "B1", "状态")
+	f.SetCellValue("Sheet1", "C1", "寄件人名称")
+	f.SetCellValue("Sheet1", "D1", "寄件人电话")
+	f.SetCellValue("Sheet1", "E1", "寄件人地址")
+	f.SetCellValue("Sheet1", "F1", "收件人名称")
+	f.SetCellValue("Sheet1", "G1", "收件人电话")
+	f.SetCellValue("Sheet1", "H1", "收件人地址")
+	f.SetCellValue("Sheet1", "I1", "温度要求")
+	f.SetCellValue("Sheet1", "J1", "配送要求")
+	f.SetCellValue("Sheet1", "K1", "货物类型")
+	f.SetCellValue("Sheet1", "L1", "运输备注")
+
+	// 设置列宽
+	f.SetColWidth("Sheet1", "A", "A", 6)
+	f.SetColWidth("Sheet1", "B", "B", 8)
+	f.SetColWidth("Sheet1", "C", "C", 14)
+	f.SetColWidth("Sheet1", "D", "D", 14)
+	f.SetColWidth("Sheet1", "E", "E", 30)
+	f.SetColWidth("Sheet1", "F", "F", 14)
+	f.SetColWidth("Sheet1", "G", "G", 14)
+	f.SetColWidth("Sheet1", "H", "H", 30)
+	f.SetColWidth("Sheet1", "I", "I", 15)
+
+	line := 1
+
+	// 循环写入数据
+	for i, v := range list {
+		line++
+		f.SetCellValue("Sheet1", fmt.Sprintf("A%d", line), i+1)
+		f.SetCellValue("Sheet1", fmt.Sprintf("B%d", line), model.WaybillStatusMap[v.Status])
+		f.SetCellValue("Sheet1", fmt.Sprintf("C%d", line), v.SenderAddressName)
+		f.SetCellValue("Sheet1", fmt.Sprintf("D%d", line), v.SenderAddressPhone)
+		f.SetCellValue("Sheet1", fmt.Sprintf("E%d", line), v.SenderAddressDetails)
+		f.SetCellValue("Sheet1", fmt.Sprintf("F%d", line), v.ConsigneeAddressName)
+		f.SetCellValue("Sheet1", fmt.Sprintf("G%d", line), v.ConsigneeAddressPhone)
+		f.SetCellValue("Sheet1", fmt.Sprintf("H%d", line), v.ConsigneeAddressDetails)
+		f.SetCellValue("Sheet1", fmt.Sprintf("I%d", line), v.Remark)
+
+	}
+	timeStr := time.Now().Format("20060102150405")
+	filePath := "ofile/" + "运单" + timeStr + ".xlsx"
+	defer func() {
+		os.Remove(filePath)
+	}()
+	// 保存文件
+	if err = f.SaveAs(filePath); err != nil {
+		logs.Error("保存运单失败:", err)
+	}
+	c.Header("Content-Type", "application/vnd.ms-excel;charset=utf8")
+	// PathEscape 函数对中文做处理
+	c.Header("Content-Disposition", "attachment; filename="+url.PathEscape("运单"+timeStr+".xlsx"))
+	c.Header("Content-Transfer-Encoding", "binary")
+	c.File(filePath)
+}
+
+// CustomerInsert 客户添加运单
+// @Summary 客户添加运单
+// @Description 客户添加运单
+// @Tags 运单
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.WaybillInsertReq true "data"
+// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
+// @Router /api/waybill/customer [post]
+// @Security Bearer
+func (e WaybillController) CustomerInsert(c *gin.Context) {
+	s := service.Waybill{}
+	userSvc := service.SysUser{}
+	req := dto.WaybillInsertReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.JSON).
+		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)
+	var userObj model.SysUser
+	err = userSvc.Get(&dto.SysUserGetReq{Id: p.UserId}, nil, &userObj)
+	if err != nil {
+		e.Error(500, err, "获取用户信息失败")
+		return
+	}
+	if p.DeptId == 0 && req.DeptId == 0 {
+		e.Error(500, err, "请先选择运输公司")
+		return
+	}
+	// 设置创建人
+	req.SetCreateBy(user.GetUserId(c))
+	if p.DeptId > 0 {
+		req.SetDeptId(p.DeptId)
+	}
+	err = s.Insert(&req)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.OK(req.GetId(), "创建成功")
+}
+
+// Import 导入运单
+// @Summary 导入运单
+// @Description 导入运单
+// @Tags 运单
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.WaybillInsertReq true "data"
+// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
+// @Router /api/waybill/import [post]
+// @Security Bearer
+func (e WaybillController) Import(c *gin.Context) {
+	s := service.Waybill{}
+	userSvc := service.SysUser{}
+	req := dto.WaybillImportReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req, binding.Form).
+		MakeService(&s.Service).
+		MakeService(&userSvc.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	//读取第一fileName的文件
+	fileHeader, err := c.FormFile("file")
+	if err != nil {
+		err = errors.New("文件格式错误" + err.Error())
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	if fileHeader.Size > 1024*1024*2 {
+		err = errors.New("文件大小超过2M")
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	file, err := fileHeader.Open()
+	if err != nil {
+		err = errors.New("文件格式错误" + err.Error())
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	defer file.Close()
+
+	xlsx, err := excelize.OpenReader(bufio.NewReader(file))
+	if err != nil {
+		err = errors.New("文件格式错误" + err.Error())
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	p := actions.GetPermissionFromContext(c)
+	if p.DeptId == 0 {
+		e.Error(500, err, "获取用户信息失败")
+		return
+	}
+
+	var userObj model.SysUser
+	err = userSvc.Get(&dto.SysUserGetReq{Id: p.UserId}, nil, &userObj)
+	if err != nil {
+		e.Error(500, err, "获取用户信息失败")
+		return
+	}
+
+	rows, _ := xlsx.GetRows("Sheet1")
+	for indexRow, row := range rows {
+		if indexRow == 0 {
+			continue
+		}
+		if len(row) < 10 {
+			for i := 0; i < 10-len(row); i++ {
+				row = append(row, "")
+			}
+		}
+		for i, colCell := range row {
+			fmt.Println(i, ":", colCell)
+		}
+		quantity, _ := strconv.Atoi(row[6])
+		obj := dto.WaybillInsertReq{
+			Status:               1,
+			SenderAddressName:    row[0],
+			SenderAddressPhone:   row[1],
+			SenderAddressDetails: row[2],
+			//CustomerName:            row[3],
+			ConsigneeAddressName:    row[3],
+			ConsigneeAddressPhone:   row[4],
+			ConsigneeAddressDetails: row[5],
+			//TemperatureInterval:     row[7],
+			//DeliveryCondition:       row[8],
+			//CargoType:               row[9],
+			Quantity:         quantity,
+			TamperProofLabel: row[7], // 防拆标签
+			Remark:           row[8],
+		}
+		obj.SetDeptId(p.DeptId)
+		obj.SetCreateBy(user.GetUserId(c))
+		err = s.Insert(&obj)
+		if err != nil {
+			e.Error(500, err, err.Error())
+			return
+		}
+	}
+
+	e.OK(len(rows)-1, "导入成功")
+}
+
+// ExportTemplate 导出运单模板
+// @Summary 导出运单模板
+// @Description 导出运单模板
+// @Tags 运单
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.WaybillInsertReq true "data"
+// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
+// @Router /api/waybill/export-template [post]
+// @Security Bearer
+func (e WaybillController) ExportTemplate(c *gin.Context) {
+	s := service.Waybill{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	filePath := "./ofile/运单导入模板.xlsx"
+	//打开文件
+	fileTmp, errByOpenFile := os.Open(filePath)
+	defer fileTmp.Close()
+
+	//获取文件的名称
+	fileName := path.Base(filePath)
+	if errByOpenFile != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	c.Header("Content-Type", "application/vnd.ms-excel;charset=utf8")
+	// PathEscape 函数对中文做处理
+	c.Header("Content-Disposition", "attachment; filename="+url.PathEscape(fileName))
+	c.Header("Content-Transfer-Encoding", "binary")
+	c.File(filePath)
+
+}
+
+// TemperaturePDF 导出温度记录
+// @Summary  导出温度记录
+// @Description  导出温度记录
+// @Tags 运单
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.WaybillInsertReq true "data"
+// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
+// @Router /api/waybill/temperature-pdf [post]
+// @Security Bearer
+func (e WaybillController) TemperaturePDF(c *gin.Context) {
+	s := service.Waybill{}
+	req := dto.WaybillGetByWaybillPdfReq{}
+	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
+	}
+	var waybill model.Waybill
+	//p := actions.GetPermissionFromContext(c)
+	//err = s.GetByWaybillNo(&req, &waybill, p)
+	err = s.GetByWaybillNo(&req, &waybill, nil)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	DeviceSensor_data, waybillPDF, err := s.GetAllData(&dto.WaybillGetByWaybillNoReq{WaybillNo: req.WaybillNo})
+	// 最高温度、最低温度、最高湿度、最低湿度
+	var maxTemp, minTemp, maxHumidity, minHumidity float32
+	// 最高温度时间、最低温度时间、最高湿度时间、最低湿度时间
+	var maxTempTime, minTempTime, maxHumidityTime, minHumidityTime string
+	// 总温度 总湿度
+	var totalTemp, totalHumidity float32
+	// 平均温度 平均湿度
+	var avgTemp, avgHumidity float32
+	// 温度阈值,湿度阈值
+	var tempThreshold, humidityThreshold string
+	// 记录开始时间,记录结束时间
+	var s_time, e_time string
+
+	var lastTime string
+	var isFirst, isSecond = true, false
+	var first_column, second_column []nats_server.DeviceData_R
+
+	if len(DeviceSensor_data) > 0 {
+		tempThreshold = fmt.Sprintf("%.1f-%.1f", DeviceSensor_data[0].T_tl, DeviceSensor_data[0].T_tu)
+		humidityThreshold = fmt.Sprintf("%.1f-%.1f", DeviceSensor_data[0].T_rhl, DeviceSensor_data[0].T_rhu)
+		s_time = DeviceSensor_data[0].T_time
+		e_time = DeviceSensor_data[len(DeviceSensor_data)-1].T_time
+		// 最高温度及时刻
+		maxTemp = DeviceSensor_data[0].T_t
+		maxTempTime = DeviceSensor_data[0].T_time
+		// 最低温度及时刻
+		minTemp = DeviceSensor_data[0].T_t
+		minTempTime = DeviceSensor_data[0].T_time
+
+		// 最高湿度及时刻
+		maxHumidity = DeviceSensor_data[0].T_rh
+		maxHumidityTime = DeviceSensor_data[0].T_time
+		// 获取最低湿度及时刻
+		minHumidity = DeviceSensor_data[0].T_rh
+		minHumidityTime = DeviceSensor_data[0].T_time
+		for i := 0; i < len(DeviceSensor_data); i++ {
+			data := DeviceSensor_data[i]
+			if data.T_t > maxTemp {
+				maxTemp = data.T_t
+				maxTempTime = data.T_time
+			}
+			if data.T_t < minTemp {
+				minTemp = data.T_t
+				minTempTime = data.T_time
+			}
+			totalTemp += data.T_t
+
+			if data.T_rh > maxHumidity {
+				maxHumidity = data.T_rh
+				maxHumidityTime = data.T_time
+			}
+			if data.T_rh < minHumidity {
+				minHumidity = data.T_rh
+				minHumidityTime = data.T_time
+			}
+			totalHumidity += data.T_rh
+
+		}
+		var sn string
+		for _, w := range waybillPDF {
+			for _, data := range w.Data {
+				if len(lastTime) > 0 {
+					if lastTime != data.T_time && isFirst == true {
+						isFirst = false
+						isSecond = true
+					} else if lastTime != data.T_time && isSecond == true {
+						isFirst = true
+						isSecond = false
+					}
+				}
+				if len(sn) > 0 && sn != data.T_sn && len(first_column)%2 == 1 {
+					isFirst, isSecond = isSecond, isFirst
+				}
+				if isFirst {
+					first_column = append(first_column, data)
+					lastTime = data.T_time
+					sn = data.T_sn
+				}
+				if isSecond {
+					second_column = append(second_column, data)
+					lastTime = data.T_time
+					sn = data.T_sn
+				}
+			}
+		}
+
+		// 平均温度
+		avgTemp = totalTemp / float32(len(DeviceSensor_data))
+		// 平均湿度
+		avgHumidity = totalHumidity / float32(len(DeviceSensor_data))
+	}
+
+	// -------------------获取最高温湿度、温蒂温湿度、平均温湿度结束
+
+	pdf := &gopdf.GoPdf{}
+	pdf.Start(gopdf.Config{PageSize: gopdf.Rect{W: 595.28, H: 841.89}}) //595.28, 841.89 = A4
+
+	err = pdf.AddTTFFont("wts", "static/fonts/MiSans-Medium.ttf")
+	if err != nil {
+		return
+	}
+	err = pdf.SetFont("wts", "", 20)
+	if err != nil {
+		return
+	}
+
+	pdf.SetGrayFill(0.5)
+
+	pdf.SetMargins(0, 20, 0, 20)
+	pdf.AddPage()
+	title := "运单" + req.WaybillNo + "温度记录"
+	if req.HumidityShow {
+		title = "运单" + req.WaybillNo + "温湿度记录"
+	}
+	var y float64 = 40
+	textw, _ := pdf.MeasureTextWidth(title)
+	pdf.SetX((595 / 2) - (textw / 2))
+	pdf.SetY(y)
+	pdf.Text(title)
+
+	//y += 30
+	//pdf.SetFont("wts", "", 16)
+	//pdf.SetXY(10, y)
+	//pdf.Text("实施设备信息")
+	//// 线
+	//y += 10
+	//pdf.SetLineWidth(0.5)
+	//pdf.SetStrokeColor(169, 169, 169)
+	//pdf.Line(10, y, 585, y)
+	//pdf.SetFont("wts", "", 10)
+	//y += 20
+	//pdf.SetXY(10, y)
+	//pdf.Text(fmt.Sprintf("主机名称:%s", device.T_devName))
+	//pdf.SetXY(300, y)
+	//pdf.Text(fmt.Sprintf("主机编号:%s", device.T_sn))
+
+	y += 25
+	pdf.SetFont("wts", "", 16)
+	pdf.SetXY(10, y)
+	pdf.Text("记录概要信息")
+	// 线
+	y += 10
+	pdf.SetLineWidth(0.5)
+	pdf.SetStrokeColor(169, 169, 169)
+	pdf.Line(10, y, 585, y)
+
+	y += 20
+	pdf.SetFont("wts", "", 10)
+	pdf.SetXY(10, y)
+	pdf.Text(fmt.Sprintf("记录开始时间:%s", s_time))
+
+	pdf.SetXY(240, y)
+	pdf.Text(fmt.Sprintf("记录结束时间:%s", e_time))
+
+	sTime, _ := lib.TimeStrToTime(s_time)
+	eTime, _ := lib.TimeStrToTime(e_time)
+	pdf.SetXY(470, y)
+	minutes := int(eTime.Sub(sTime).Minutes())
+	hours := minutes / 60
+	remainingMinutes := minutes % 60
+	pdf.Text(fmt.Sprintf("记录总时间:%dh%dmin", hours, remainingMinutes))
+
+	// -------------最高温/湿度 最低温/湿度 平均温/湿度
+	y += 15
+	pdf.SetXY(10, y)
+	pdf.Text(fmt.Sprintf("最高温度:%.1f℃,%s", lib.RoundToDecimal(float64(maxTemp), 1), maxTempTime))
+
+	pdf.SetXY(240, y)
+	pdf.Text(fmt.Sprintf("最低温度:%.1f℃,%s", lib.RoundToDecimal(float64(minTemp), 1), minTempTime))
+
+	pdf.SetXY(470, y)
+	pdf.Text(fmt.Sprintf("平均温度:%.1f℃", lib.RoundToDecimal(float64(avgTemp), 1)))
+
+	if req.HumidityShow {
+		y += 15
+		pdf.SetXY(10, y)
+		pdf.Text(fmt.Sprintf("最高湿度:%.1f%%RH,%s", lib.RoundToDecimal(float64(maxHumidity), 1), maxHumidityTime))
+
+		pdf.SetXY(240, y)
+		pdf.Text(fmt.Sprintf("最低湿度:%.1f%%RH,%s", lib.RoundToDecimal(float64(minHumidity), 1), minHumidityTime))
+
+		pdf.SetXY(470, y)
+		pdf.Text(fmt.Sprintf("平均湿度:%.1f%%RH", lib.RoundToDecimal(float64(avgHumidity), 1)))
+	}
+
+	// -------------温/湿度阈值
+
+	y += 15
+	pdf.SetXY(10, y)
+	pdf.Text(fmt.Sprintf("温度阈值:%s℃", tempThreshold))
+
+	if req.HumidityShow {
+		pdf.SetXY(240, y)
+		pdf.Text(fmt.Sprintf("温度阈值:%s%%", humidityThreshold))
+	}
+
+	//-------------发货单位,收货单位,备注
+	y += 15
+	pdf.SetXY(10, y)
+	T_forwarding_unit_temp := []rune(waybill.SenderAddressName)
+	if len(T_forwarding_unit_temp) > 17 {
+		pdf.Text(fmt.Sprintf("发货人:%s", string(T_forwarding_unit_temp[0:17])))
+		pdf.SetXY(60, y+15)
+		pdf.Text(fmt.Sprintf("%s", string(T_forwarding_unit_temp[17:])))
+	} else {
+		pdf.Text(fmt.Sprintf("发货人:%s", string(T_forwarding_unit_temp)))
+	}
+
+	pdf.SetXY(240, y)
+	T_consignee_unit_temp := []rune(waybill.ConsigneeAddressName)
+	if len(T_consignee_unit_temp) > 17 {
+		pdf.Text(fmt.Sprintf("收货人:%s", string(T_consignee_unit_temp[0:17])))
+		pdf.SetXY(290, y+15)
+		pdf.Text(fmt.Sprintf("%s", string(T_consignee_unit_temp[17:])))
+	} else {
+		pdf.Text(fmt.Sprintf("收货人:%s", string(T_consignee_unit_temp)))
+	}
+
+	// 承运方
+	y += 15
+	pdf.SetXY(10, y)
+	company_name := []rune(waybill.Dept.Name)
+	pdf.Text(fmt.Sprintf("承运方:%s", string(company_name)))
+
+	y += 15
+	pdf.SetXY(10, y)
+	T_remark_temp := []rune(waybill.Remark)
+	if len(waybill.Remark) > 35 {
+		pdf.Text(fmt.Sprintf("备注:%s", string(T_remark_temp[0:35])))
+		pdf.SetXY(10, y+15)
+		pdf.Text(fmt.Sprintf("%s", string(T_remark_temp[35:])))
+	} else {
+		pdf.Text(fmt.Sprintf("备注: %s", string(T_remark_temp)))
+	}
+
+	y += 15
+	//pdf.SetFont("wts", "", 16)
+	//pdf.SetXY(10, y)
+	//pdf.Text("记录曲线信息")
+	//// 线
+	//y += 10
+	//pdf.SetLineWidth(0.5)
+	//pdf.SetStrokeColor(169, 169, 169)
+	//pdf.Line(10, y, 585, y)
+	//y += 1
+	//
+	//var tempFilepath string
+	//tempFilepath, err = DeviceDataTemperatureJPG2(s_time, e_time, waybillPDF)
+	//if err == nil {
+	//	imgH, _ := gopdf.ImageHolderByPath(tempFilepath)
+	//	pdf.ImageByHolder(imgH, 10, y, &gopdf.Rect{W: 575, H: 315})
+	//	y += 315
+	//}
+	//
+	//var humidityFilepath string
+	//if req.HumidityShow {
+	//	humidityFilepath, err = DeviceDataHumidityJPG2(s_time, e_time, waybillPDF)
+	//	if err == nil {
+	//		imgH, _ := gopdf.ImageHolderByPath(humidityFilepath)
+	//		pdf.ImageByHolder(imgH, 10, y, &gopdf.Rect{W: 575, H: 315})
+	//		y += 315
+	//	}
+	//}
+
+	if y > 841.89 {
+		// 图片结束直接分页
+		pdf.AddPage()
+		y = 20
+	}
+	y += 20
+	pdf.SetFont("wts", "", 16)
+	pdf.SetXY(10, y)
+	pdf.Text("记录数据信息")
+	// 线
+	y += 10
+	pdf.SetLineWidth(0.5)
+	pdf.SetStrokeColor(169, 169, 169)
+	pdf.Line(10, y, 585, y)
+	y += 10
+	pdf.SetFont("wts", "", 10)
+	var x float64 = 10
+	var w float64 = 112
+	lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+	x = x + w
+	w = 101
+	lib.RectFillColor(pdf, "名称", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+
+	if req.HumidityShow {
+		x = x + w
+		w = 37
+		lib.RectFillColor(pdf, "温度℃", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+		x = x + w
+		w = 37
+		lib.RectFillColor(pdf, "湿度%", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+	} else {
+		x = x + w
+		w = 37 * 2
+		lib.RectFillColor(pdf, "温度℃", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+	}
+	x = x + w
+	w = 112
+	lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+	x = x + w
+	w = 101
+	lib.RectFillColor(pdf, "名称", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+
+	if req.HumidityShow {
+		x = x + w
+		w = 37
+		lib.RectFillColor(pdf, "温度℃", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+		x = x + w
+		w = 37
+		lib.RectFillColor(pdf, "湿度%", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+	} else {
+		x = x + w
+		w = 37 * 2
+		lib.RectFillColor(pdf, "温度℃", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+	}
+	y += 20
+	var textH float64 = 25 // if text height is 25px.
+	for i, v := range first_column {
+		pdf.SetNewY(y, textH)
+		y = pdf.GetY()
+		x, w = 10, 112
+
+		lib.RectFillColor(pdf, v.T_time, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+		x = x + w
+		w = 101
+		lib.RectFillColor(pdf, v.T_name, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+
+		// 显示温湿度
+		if req.HumidityShow {
+			x = x + w
+			w = 37
+			lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", v.T_t), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			x = x + w
+			w = 37
+			lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", v.T_rh), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+		} else {
+			x = x + w
+			w = 37 * 2
+			lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", v.T_t), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+		}
+		if i < len(second_column) {
+			x = x + w
+			w = 112
+			lib.RectFillColor(pdf, second_column[i].T_time, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			x = x + w
+			w = 101
+			lib.RectFillColor(pdf, second_column[i].T_name, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+
+			if req.HumidityShow {
+				x = x + w
+				w = 37
+				lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", second_column[i].T_t), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+				x = x + w
+				w = 37
+				lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", second_column[i].T_rh), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			} else {
+				x = x + w
+				w = 37 * 2
+				lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", second_column[i].T_t), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			}
+		}
+
+		y += 20
+	}
+	if len(second_column) > len(first_column) {
+		for i := len(first_column); i < len(second_column); i++ {
+			pdf.SetNewY(y, textH)
+			y = pdf.GetY()
+			x, w = 297, 112
+			lib.RectFillColor(pdf, second_column[i].T_time, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			x = x + w
+			w = 101
+			lib.RectFillColor(pdf, second_column[i].T_name, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+
+			if req.HumidityShow {
+				x = x + w
+				w = 37
+				lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", second_column[i].T_t), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+				x = x + w
+				w = 37
+				lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", second_column[i].T_rh), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			} else {
+				x = x + w
+				w = 37 * 2
+				lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", second_column[i].T_t), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+
+			}
+			y += 20
+		}
+	}
+	filename := "运单" + req.WaybillNo + "温湿度记录" + time.Now().Format("20060102150405") + ".pdf"
+	filePath := "ofile/" + filename
+
+	err = pdf.WritePdf(filePath)
+	if err != nil {
+		return
+	}
+	defer func() {
+		//os.Remove(tempFilepath)
+		//os.Remove(humidityFilepath)
+		os.Remove(filePath)
+	}()
+
+	c.Header("Content-Disposition", "attachment; filename="+url.PathEscape(filename))
+	c.Header("Content-Transfer-Encoding", "binary")
+	c.File(filePath)
+
+}
+
+// 获取温度图片
+func DeviceDataTemperatureJPG(startTime, endTime string, waybillPDF []service.WaybillPDF) (string, error) {
+
+	if len(waybillPDF) == 0 {
+		return "", errors.New("暂无数据可生成图片")
+	}
+
+	// 创建一个新的绘图
+	p := plot.New()
+
+	// 设置绘图标题和标签
+	p.Title.Text = "temperature"
+	//p.Legend.ThumbnailWidth = 20
+
+	deviceSensorList := []nats_server.DeviceSensor_R{}
+	dataList := []nats_server.DeviceData_R{}
+
+	for _, w := range waybillPDF {
+		deviceSensorList = append(deviceSensorList, w.DeviceSensorList...)
+		dataList = append(dataList, w.Data...)
+	}
+
+	TemperatureMin := deviceSensorList[0].T_DeviceSensorParameter.T_Tlower
+	TemperatureMax := deviceSensorList[0].T_DeviceSensorParameter.T_Tupper
+
+	var ymin, ymax float32
+	for i, r := range dataList {
+		if i == 0 {
+			ymin = r.T_t
+			ymax = r.T_t
+		}
+		if ymin > r.T_t {
+			ymin = r.T_t
+		}
+		if ymax < r.T_t {
+			ymax = r.T_t
+		}
+	}
+
+	var chData = make(chan int, 10)
+	var jobGroup sync.WaitGroup
+	// 创建温度线
+	for i := 0; i < len(deviceSensorList); i++ {
+		chData <- 1
+		jobGroup.Add(1)
+		go func(index int) {
+			defer func() {
+				<-chData        // 完成时chan取出1个
+				jobGroup.Done() // 完成时将等待组值减1
+			}()
+			sn, id := deviceSensorList[index].T_sn, deviceSensorList[index].T_id
+			r_maps := []nats_server.DeviceData_R{}
+			for _, data := range dataList {
+				if data.T_sn == sn && data.T_id == id {
+					r_maps = append(r_maps, data)
+				}
+			}
+
+			fmt.Println(r_maps)
+			if len(r_maps) == 0 {
+				return
+			}
+			sort.Slice(r_maps, func(i, j int) bool {
+				return r_maps[i].T_time < r_maps[j].T_time
+			})
+
+			pts := make(plotter.XYs, len(r_maps))
+			for j, d := range r_maps {
+				t, _ := lib.TimeStrToTime(d.T_time)
+				pts[j].X = float64(t.Unix())
+				pts[j].Y = float64(d.T_t)
+			}
+
+			line, err := plotter.NewLine(pts)
+			if err != nil {
+				return
+			}
+			line.Color = randomColor(index)
+			p.Add(line)
+		}(i)
+	}
+	jobGroup.Wait()
+
+	st, _ := lib.TimeStrToTime(startTime)
+	et, _ := lib.TimeStrToTime(endTime)
+	xmin, xmax := float64(st.Unix()), float64(et.Unix())
+	// 添加最高,最低标准线 用红色虚线标识
+	p.Add(horizontalLine(xmin, xmax, float64(TemperatureMin)))
+	p.Add(horizontalLine(xmin, xmax, float64(TemperatureMax)))
+
+	if ymax < TemperatureMax {
+		ymax = TemperatureMax
+	}
+	if ymin > 0 {
+		ymin = 0
+	}
+
+	p.Y.Min, p.Y.Max = float64(ymin), float64(ymax)
+
+	p.X.Min, p.X.Max = xmin, xmax
+	p.Y.Tick.Marker = commaTicks{}
+	p.X.Tick.Marker = timeTicks{}
+	p.X.Tick.Label.Rotation = math.Pi / 5
+	p.X.Tick.Label.YAlign = draw.YCenter
+	p.X.Tick.Label.XAlign = draw.XRight
+
+	filepath := "ofile/" + "temperature" + deviceSensorList[0].T_sn + ".jpg"
+	// 保存文件
+	if err := p.Save(10*vg.Inch, 4*vg.Inch, filepath); err != nil {
+
+		logs.Error(lib.FuncName(), "生成图片失败", err)
+		return "", err
+	}
+
+	return filepath, nil
+
+}
+func DeviceDataTemperatureJPG2(startTime, endTime string, waybillPDF []service.WaybillPDF) (string, error) {
+
+	if len(waybillPDF) == 0 {
+		return "", errors.New("暂无数据可生成图片")
+	}
+
+	deviceSensorList := []nats_server.DeviceSensor_R{}
+	dataList := []nats_server.DeviceData_R{}
+
+	for _, w := range waybillPDF {
+		deviceSensorList = append(deviceSensorList, w.DeviceSensorList...)
+		dataList = append(dataList, w.Data...)
+	}
+	TemperatureMin := deviceSensorList[0].T_DeviceSensorParameter.T_Tlower
+	TemperatureMax := deviceSensorList[0].T_DeviceSensorParameter.T_Tupper
+
+	var ymin, ymax float32
+	for i, r := range dataList {
+		if i == 0 {
+			ymin = r.T_t
+			ymax = r.T_t
+		}
+		if ymin > r.T_t {
+			ymin = r.T_t
+		}
+		if ymax < r.T_t {
+			ymax = r.T_t
+		}
+	}
+	series := make([]chart.Series, 0)
+	var chData = make(chan int, 10)
+	var jobGroup sync.WaitGroup
+	// 创建温度线
+	for i := 0; i < len(deviceSensorList); i++ {
+		chData <- 1
+		jobGroup.Add(1)
+		go func(index int) {
+			defer func() {
+				<-chData        // 完成时chan取出1个
+				jobGroup.Done() // 完成时将等待组值减1
+			}()
+			sn, id := deviceSensorList[index].T_sn, deviceSensorList[index].T_id
+			r_maps := []nats_server.DeviceData_R{}
+			for _, data := range dataList {
+				if data.T_sn == sn && data.T_id == id {
+					r_maps = append(r_maps, data)
+				}
+			}
+
+			fmt.Println(r_maps)
+			if len(r_maps) == 0 {
+				return
+			}
+			sort.Slice(r_maps, func(i, j int) bool {
+				return r_maps[i].T_time < r_maps[j].T_time
+			})
+
+			xValues := make([]time.Time, len(r_maps))
+			yValues := make([]float64, len(r_maps))
+
+			for j := 0; j < len(r_maps); j++ {
+				t, _ := lib.TimeStrToTime(r_maps[j].T_time)
+				xValues[j] = t
+				yValues[j] = float64(r_maps[j].T_t)
+			}
+			series = append(series, chart.TimeSeries{
+				Name:    fmt.Sprintf("%s-%d", sn, id),
+				XValues: xValues,
+				YValues: yValues,
+			})
+		}(i)
+	}
+	jobGroup.Wait()
+	if ymax < TemperatureMax {
+		ymax = TemperatureMax
+	}
+	if ymin > 0 {
+		ymin = 0
+	}
+
+	if ymin > TemperatureMin {
+		ymin = TemperatureMin
+	}
+
+	st, _ := lib.TimeStrToTime(startTime)
+	et, _ := lib.TimeStrToTime(endTime)
+	series = append(series, chart.TimeSeries{
+		Style: chart.Style{
+			StrokeColor:     drawing.ColorRed,
+			StrokeDashArray: []float64{5.0, 5.0},
+		},
+		XValues: []time.Time{st, et},
+		YValues: []float64{float64(TemperatureMin), float64(TemperatureMin)},
+	})
+	series = append(series, chart.TimeSeries{
+		Style: chart.Style{
+			StrokeColor:     drawing.ColorRed,
+			StrokeDashArray: []float64{5.0, 5.0},
+		},
+		XValues: []time.Time{st, et},
+		YValues: []float64{float64(TemperatureMax), float64(TemperatureMax)},
+	})
+	font := getZWFont()
+	graph := chart.Chart{
+		Title: "温度记录",
+		TitleStyle: chart.Style{
+			FontSize: 15,
+		},
+		Background: chart.Style{
+			Padding: chart.Box{
+				Top: 20,
+			},
+		},
+		Font: font,
+		XAxis: chart.XAxis{
+			Name:           "时间",
+			ValueFormatter: chart.TimeValueFormatterWithFormat("2006-01-02 15:04"),
+		},
+		YAxis: chart.YAxis{
+			Name: "温度",
+			Range: &chart.ContinuousRange{
+				Min: float64(ymin),
+				Max: float64(ymax + 2),
+			},
+		},
+		Series: series,
+	}
+	//graph.Elements = []chart.Renderable{
+	//	chart.Legend(&graph),
+	//}
+
+	filepath := "ofile/" + "temperature" + deviceSensorList[0].T_sn + ".jpg"
+	f, _ := os.Create(filepath)
+	defer f.Close()
+	graph.Render(chart.PNG, f)
+
+	return filepath, nil
+
+}
+
+// 获取湿度图片
+func DeviceDataHumidityJPG(startTime, endTime string, waybillPDF []service.WaybillPDF) (string, error) {
+
+	if len(waybillPDF) == 0 {
+		return "", errors.New("暂无数据可生成图片")
+	}
+
+	// 创建一个新的绘图
+	p := plot.New()
+
+	// 设置绘图标题和标签
+	p.Title.Text = "humidity"
+
+	deviceSensorList := []nats_server.DeviceSensor_R{}
+	dataList := []nats_server.DeviceData_R{}
+
+	for _, w := range waybillPDF {
+		deviceSensorList = append(deviceSensorList, w.DeviceSensorList...)
+		dataList = append(dataList, w.Data...)
+	}
+
+	humidityMin := deviceSensorList[0].T_DeviceSensorParameter.T_RHlower
+	humidityMax := deviceSensorList[0].T_DeviceSensorParameter.T_RHupper
+
+	var ymin, ymax float32
+	for i, r := range dataList {
+		if i == 0 {
+			ymin = r.T_rh
+			ymax = r.T_rh
+		}
+		if ymin > r.T_rh {
+			ymin = r.T_rh
+		}
+		if ymax < r.T_rh {
+			ymax = r.T_rh
+		}
+	}
+
+	var chData = make(chan int, 10)
+	var jobGroup sync.WaitGroup
+	// 创建温度线
+	for i := 0; i < len(deviceSensorList); i++ {
+		chData <- 1
+		jobGroup.Add(1)
+		go func(index int) {
+			defer func() {
+				<-chData        // 完成时chan取出1个
+				jobGroup.Done() // 完成时将等待组值减1
+			}()
+			sn, id := deviceSensorList[index].T_sn, deviceSensorList[index].T_id
+			r_maps := []nats_server.DeviceData_R{}
+			for _, data := range dataList {
+				if data.T_sn == sn && data.T_id == id {
+					r_maps = append(r_maps, data)
+				}
+			}
+			if len(r_maps) == 0 {
+				return
+			}
+			sort.Slice(r_maps, func(i, j int) bool {
+				return r_maps[i].T_time < r_maps[j].T_time
+			})
+
+			pts := make(plotter.XYs, len(r_maps))
+			for j, d := range r_maps {
+				t, _ := lib.TimeStrToTime(d.T_time)
+				pts[j].X = float64(t.Unix())
+				pts[j].Y = float64(d.T_rh)
+			}
+
+			line, err := plotter.NewLine(pts)
+			if err != nil {
+				return
+			}
+			line.Color = randomColor(index)
+			p.Add(line)
+		}(i)
+	}
+	jobGroup.Wait()
+
+	st, _ := lib.TimeStrToTime(startTime)
+	et, _ := lib.TimeStrToTime(endTime)
+	xmin, xmax := float64(st.Unix()), float64(et.Unix())
+	// 添加最高,最低标准线 用红色虚线标识
+	p.Add(horizontalLine(xmin, xmax, float64(humidityMin)))
+	p.Add(horizontalLine(xmin, xmax, float64(humidityMax)))
+
+	if ymax < humidityMax {
+		ymax = humidityMax
+	}
+	if ymin > 0 {
+		ymin = 0
+	}
+
+	p.Y.Min, p.Y.Max = float64(ymin), float64(ymax)
+
+	p.X.Min, p.X.Max = xmin, xmax
+	p.Y.Tick.Marker = commaTicks{}
+	//p.X.Tick.Marker = plot.TimeTicks{Format: "2006-01-02 15:04:05"}
+	p.X.Tick.Marker = timeTicks{}
+	p.X.Tick.Label.Rotation = math.Pi / 5
+	p.X.Tick.Label.YAlign = draw.YCenter
+	p.X.Tick.Label.XAlign = draw.XRight
+
+	filepath := "ofile/" + "humidity" + deviceSensorList[0].T_sn + ".jpg"
+	// 保存文件
+	if err := p.Save(10*vg.Inch, 4*vg.Inch, filepath); err != nil {
+
+		logs.Error(lib.FuncName(), "生成图片失败", err)
+		return "", err
+	}
+
+	return filepath, nil
+
+}
+func DeviceDataHumidityJPG2(startTime, endTime string, waybillPDF []service.WaybillPDF) (string, error) {
+
+	if len(waybillPDF) == 0 {
+		return "", errors.New("暂无数据可生成图片")
+	}
+
+	deviceSensorList := []nats_server.DeviceSensor_R{}
+	dataList := []nats_server.DeviceData_R{}
+
+	for _, w := range waybillPDF {
+		deviceSensorList = append(deviceSensorList, w.DeviceSensorList...)
+		dataList = append(dataList, w.Data...)
+	}
+	humidityMin := deviceSensorList[0].T_DeviceSensorParameter.T_RHlower
+	humidityMax := deviceSensorList[0].T_DeviceSensorParameter.T_RHupper
+
+	var ymin, ymax float32
+	for i, r := range dataList {
+		if i == 0 {
+			ymin = r.T_t
+			ymax = r.T_t
+		}
+		if ymin > r.T_t {
+			ymin = r.T_t
+		}
+		if ymax < r.T_t {
+			ymax = r.T_t
+		}
+	}
+	series := make([]chart.Series, 0)
+	var chData = make(chan int, 10)
+	var jobGroup sync.WaitGroup
+	// 创建温度线
+	for i := 0; i < len(deviceSensorList); i++ {
+		chData <- 1
+		jobGroup.Add(1)
+		go func(index int) {
+			defer func() {
+				<-chData        // 完成时chan取出1个
+				jobGroup.Done() // 完成时将等待组值减1
+			}()
+			sn, id := deviceSensorList[index].T_sn, deviceSensorList[index].T_id
+			r_maps := []nats_server.DeviceData_R{}
+			for _, data := range dataList {
+				if data.T_sn == sn && data.T_id == id {
+					r_maps = append(r_maps, data)
+				}
+			}
+
+			if len(r_maps) == 0 {
+				return
+			}
+			sort.Slice(r_maps, func(i, j int) bool {
+				return r_maps[i].T_time < r_maps[j].T_time
+			})
+
+			xValues := make([]time.Time, len(r_maps))
+			yValues := make([]float64, len(r_maps))
+
+			for j := 0; j < len(r_maps); j++ {
+				t, _ := lib.TimeStrToTime(r_maps[j].T_time)
+				xValues[j] = t
+				yValues[j] = float64(r_maps[j].T_rh)
+			}
+			series = append(series, chart.TimeSeries{
+				Name:    fmt.Sprintf("%s-%d", sn, id),
+				XValues: xValues,
+				YValues: yValues,
+			})
+		}(i)
+	}
+	jobGroup.Wait()
+	if ymax < humidityMax {
+		ymax = humidityMax
+	}
+	if ymin > 0 {
+		ymin = 0
+	}
+
+	if ymin > humidityMin {
+		ymin = humidityMin
+	}
+
+	st, _ := lib.TimeStrToTime(startTime)
+	et, _ := lib.TimeStrToTime(endTime)
+	series = append(series, chart.TimeSeries{
+		Style: chart.Style{
+			StrokeColor:     drawing.ColorRed,
+			StrokeDashArray: []float64{5.0, 5.0},
+		},
+		XValues: []time.Time{st, et},
+		YValues: []float64{float64(humidityMin), float64(humidityMin)},
+	})
+	series = append(series, chart.TimeSeries{
+		Style: chart.Style{
+			StrokeColor:     drawing.ColorRed,
+			StrokeDashArray: []float64{5.0, 5.0},
+		},
+		XValues: []time.Time{st, et},
+		YValues: []float64{float64(humidityMax), float64(humidityMax)},
+	})
+	font := getZWFont()
+	graph := chart.Chart{
+		Title: "湿度记录",
+		TitleStyle: chart.Style{
+			FontSize: 15,
+		},
+		Background: chart.Style{
+			Padding: chart.Box{
+				Top: 20,
+			},
+		},
+		Font: font,
+		XAxis: chart.XAxis{
+			Name:           "时间",
+			ValueFormatter: chart.TimeValueFormatterWithFormat("2006-01-02 15:04"),
+		},
+		YAxis: chart.YAxis{
+			Name: "湿度",
+			Range: &chart.ContinuousRange{
+				Min: float64(ymin),
+				Max: float64(ymax + 2),
+			},
+		},
+		Series: series,
+	}
+	//graph.Elements = []chart.Renderable{
+	//	chart.Legend(&graph),
+	//}
+
+	filepath := "ofile/" + "humidity" + deviceSensorList[0].T_sn + ".jpg"
+	f, _ := os.Create(filepath)
+	defer f.Close()
+	graph.Render(chart.PNG, f)
+
+	return filepath, nil
+
+}
+
+func horizontalLine(xmin, xmax, y float64) *plotter.Line {
+	pts := make(plotter.XYs, 2)
+	pts[0].X = xmin
+	pts[0].Y = y
+	pts[1].X = xmax
+	pts[1].Y = y
+	line, err := plotter.NewLine(pts)
+	if err != nil {
+		panic(err)
+	}
+	line.LineStyle.Dashes = []vg.Length{vg.Points(8), vg.Points(5), vg.Points(1), vg.Points(5)}
+	line.Color = color.RGBA{R: 255, A: 255}
+	return line
+}
+
+type timeTicks struct{}
+
+func (timeTicks) Ticks(min, max float64) []plot.Tick {
+	tks := plot.TimeTicks{}.Ticks(min, max)
+	for i, t := range tks {
+		//if t.Label == "" { // Skip minor ticks, they are fine.
+		//	continue
+		//}
+		tks[i].Label = time.Unix(int64(t.Value), 0).Format("2006-01-02 15:04:05")
+	}
+
+	return tks
+}
+
+type commaTicks struct{}
+
+// Ticks computes the default tick marks, but inserts commas
+// into the labels for the major tick marks.
+func (commaTicks) Ticks(min, max float64) []plot.Tick {
+	tks := plot.DefaultTicks{}.Ticks(min, max)
+	for i, t := range tks {
+		//if t.Label == "" { // Skip minor ticks, they are fine.
+		//	continue
+		//}
+		tks[i].Label = fmt.Sprintf("%.0f", t.Value)
+	}
+
+	return tks
+}
+
+// 生成随机颜色的辅助函数
+func randomColor(i int) color.RGBA {
+	var colors []color.RGBA
+	colors = append(colors,
+		color.RGBA{R: 52, G: 152, B: 219, A: 255},
+		color.RGBA{R: 230, G: 126, B: 34, A: 255},
+		color.RGBA{R: 142, G: 68, B: 173, A: 255},
+		color.RGBA{R: 211, G: 84, B: 0, A: 255},
+		color.RGBA{R: 231, G: 76, B: 60, A: 255},
+		color.RGBA{R: 26, G: 188, B: 156, A: 255},
+		color.RGBA{R: 243, G: 156, B: 18, A: 255},
+		color.RGBA{R: 22, G: 160, B: 133, A: 255},
+		color.RGBA{R: 46, G: 204, B: 113, A: 255},
+		color.RGBA{R: 39, G: 174, B: 96, A: 255},
+		color.RGBA{R: 41, G: 128, B: 185, A: 255},
+		color.RGBA{R: 155, G: 89, B: 182, A: 255},
+		color.RGBA{R: 192, G: 57, B: 43, A: 255},
+		color.RGBA{R: 241, G: 196, B: 15, A: 255},
+	)
+
+	return colors[i%len(colors)]
+}
+func randomColor2(i int) drawing.Color {
+	var colors []drawing.Color
+	colors = append(colors,
+		drawing.Color{R: 52, G: 152, B: 219, A: 255},
+		drawing.Color{R: 230, G: 126, B: 34, A: 255},
+		drawing.Color{R: 142, G: 68, B: 173, A: 255},
+		drawing.Color{R: 211, G: 84, B: 0, A: 255},
+		drawing.Color{R: 231, G: 76, B: 60, A: 255},
+		drawing.Color{R: 26, G: 188, B: 156, A: 255},
+		drawing.Color{R: 243, G: 156, B: 18, A: 255},
+		drawing.Color{R: 22, G: 160, B: 133, A: 255},
+		drawing.Color{R: 46, G: 204, B: 113, A: 255},
+		drawing.Color{R: 39, G: 174, B: 96, A: 255},
+		drawing.Color{R: 41, G: 128, B: 185, A: 255},
+		drawing.Color{R: 155, G: 89, B: 182, A: 255},
+		drawing.Color{R: 192, G: 57, B: 43, A: 255},
+		drawing.Color{R: 241, G: 196, B: 15, A: 255},
+	)
+	return colors[i%len(colors)]
+}
+
+// getZWFont 加载字体
+func getZWFont() *truetype.Font {
+	fontFile := "./static/fonts/MiSans-Medium.ttf"
+	fontBytes, err := os.ReadFile(fontFile)
+	if err != nil {
+		log.Println(err)
+		return nil
+	}
+	font, err := truetype.Parse(fontBytes)
+	if err != nil {
+		log.Println(err)
+		return nil
+	}
+	return font
+}

+ 51 - 0
app/admin/controller/waybill_logistics.go

@@ -0,0 +1,51 @@
+package controller
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/app/admin/service"
+	"cold-delivery/app/admin/service/dto"
+	"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"
+)
+
+type WaybillLogisticsController struct {
+	api.Api
+}
+
+// GetPage 获取运单列表
+// @Summary 获取运单列表
+// @Description 获取运单列表
+// @Tags 运单
+// @Param no query string false "运单号"
+// @Param pageSize query int false "页条数"
+// @Param page query int false "页码"
+// @Success 200 {object} response.Response{data=response.Page{list=[]model.WaybillLogistics}} "{"code": 200, "data": [...]}"
+// @Router /api/waybill [get]
+// @Security Bearer
+func (e WaybillLogisticsController) GetPage(c *gin.Context) {
+	s := service.WaybillLogistics{}
+	req := dto.WaybillLogisticsGetPageReq{}
+	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.WaybillLogistics, 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(), "查询成功")
+	e.PageOK(list, int(count), 0, 0, "查询成功")
+}

+ 142 - 0
app/admin/controller/waybill_task.go

@@ -0,0 +1,142 @@
+package controller
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/app/admin/service"
+	"cold-delivery/app/admin/service/dto"
+	"cold-delivery/common/nats/nats_server"
+	"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"
+)
+
+type WaybillTaskController struct {
+	api.Api
+}
+
+// GetPage 获取运单任务列表
+// @Summary 获取运单任务列表
+// @Description 获取运单任务列表
+// @Tags 运单任务
+// @Param no query string true "运单号"
+// @Success 200 {object} response.Response{data=response.Page{list=[]model.WaybillTask}} "{"code": 200, "data": [...]}"
+// @Router /api/waybill-task [get]
+// @Security Bearer
+func (e WaybillTaskController) GetPage(c *gin.Context) {
+	s := service.WaybillTask{}
+	req := dto.WaybillTaskGetPageReq{}
+	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.WaybillTask, 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(), "查询成功")
+	e.PageOK(list, int(count), 0, 0, "查询成功")
+}
+
+// GetData 获取温湿度记录
+// @Summary 获取传感器列表
+// @Description 获取传感器列表
+// @Tags 运单任务
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.WaybillTaskGetDataPageReq true "body"
+// @Success 200 {object} response.Response{data=response.Page{list=[]model.WaybillTask}} "{"code": 200, "data": [...]}"
+// @Router /api/waybill-task/data [post]
+// @Security Bearer
+func (e WaybillTaskController) GetData(c *gin.Context) {
+	s := service.WaybillTask{}
+	req := dto.WaybillTaskGetDataPageReq{}
+	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
+	}
+
+	list := make([]nats_server.DeviceData_R, 0)
+	var count int64
+
+	list, count, err = s.GetDataPage(&req)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
+}
+
+// GetNewestData 获取最新温湿度记录
+// @Summary 获取最新温湿度记录
+// @Description 获取最新温湿度记录
+// @Tags 运单任务
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.WaybillTaskGetDataPageReq true "body"
+// @Success 200 {object} response.Response{data=response.Page{list=[]model.WaybillTask}} "{"code": 200, "data": [...]}"
+// @Router /api/waybill-task/data [post]
+// @Security Bearer
+func (e WaybillTaskController) GetNewestData(c *gin.Context) {
+	s := service.WaybillTask{}
+	req := dto.WaybillTaskGetNewestDataPageReq{}
+	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
+	}
+
+	data := nats_server.DeviceData_R{}
+
+	data, err = s.GetNewestDataPage(&req)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.OK(data, "查询成功")
+}
+
+func (e WaybillTaskController) GetLocus(c *gin.Context) {
+	s := service.WaybillTask{}
+	req := dto.WaybillGetLocusReq{}
+	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([]nats_server.DeviceData_R2, 0)
+
+	list, err = s.GetLocus(&req)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.OK(list, "获取轨迹信息成功")
+}

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

@@ -0,0 +1,40 @@
+package model
+
+import model2 "cold-delivery/common/model"
+
+var (
+	AddressTypeSender    = "sender"
+	AddressTypeConsignee = "consignee"
+)
+
+type Address struct {
+	model2.Model
+	Name         string `json:"name" gorm:"size:32;"`           // 收货人名称
+	Phone        string `json:"phone" gorm:"size:32;"`          // 联系电话
+	Address      string `json:"address" gorm:"size:128"`        // 详细地址
+	IsDefault    bool   `json:"isDefault" gorm:"-"`             // 默认
+	ProvinceId   string `json:"provinceId"  gorm:"size:255;"`   // 省Id
+	ProvinceName string `json:"provinceName"  gorm:"size:255;"` // 省中文名
+	CityId       string `json:"cityId"  gorm:"size:255;"`       // 市Id
+	CityName     string `json:"cityName"  gorm:"size:255;"`     // 市中文名
+	RegionId     string `json:"regionId"  gorm:"size:255;"`     // 区Id
+	RegionName   string `json:"regionName"  gorm:"size:255;"`   // 区中文名
+	AddressType  string `json:"addressType" gorm:"size:255;" `  //地址类型:sender-发货人 consignee-收货人
+
+	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
+}

+ 15 - 0
app/admin/model/address_default.go

@@ -0,0 +1,15 @@
+package model
+
+import model2 "cold-delivery/common/model"
+
+type AddressDefault struct {
+	model2.Model
+	UserId           int `json:"userId" gorm:"size:128;comment:用户id;uniqueIndex"` // 用户id
+	AddressId        int `json:"addressId" gorm:"size:128;comment:地址id"`          // 仓库id
+	model2.ControlBy `json:"-"`
+	model2.ModelTime `json:"-"`
+}
+
+func (AddressDefault) TableName() string {
+	return "address_default"
+}

+ 33 - 0
app/admin/model/car.go

@@ -0,0 +1,33 @@
+package model
+
+import (
+	model2 "cold-delivery/common/model"
+)
+
+// 仓库
+type Car struct {
+	model2.Model
+	CarNo     string            `json:"carNo" gorm:"size:128"`                                // 商品名称
+	Sn        string            `json:"sn" gorm:"size:128"`                                   // sn
+	Status    string            `json:"status" gorm:"size:4;not null;default:'2';comment:状态"` // 1-停用 2-正启用
+	UserId    int               `json:"userId" gorm:"size:255;"`                              // 司机id
+	HistorySn model2.StringList `json:"historySn"`                                            // 历史绑定的sn
+	User      SysUserOmit       `json:"user"`
+	model2.ControlBy
+	model2.ModelTime
+	model2.DeptBy
+}
+
+type CarOmit struct {
+	Id     int         `json:"id,omitempty"`     // 主键编码
+	CarNo  string      `json:"carNo,omitempty"`  // 商品名称
+	UserId int         `json:"userId,omitempty"` // 仓管id
+	User   SysUserOmit `json:"user,omitempty"`
+}
+
+func (Car) TableName() string {
+	return "car"
+}
+func (CarOmit) TableName() string {
+	return "car"
+}

+ 27 - 0
app/admin/model/cooler_box.go

@@ -0,0 +1,27 @@
+package model
+
+import model2 "cold-delivery/common/model"
+
+// 仓库
+type CoolerBox struct {
+	model2.Model
+	Name      string            `json:"name" gorm:"size:128"`                                 // 商品名称
+	Sn        string            `json:"sn" gorm:"size:128"`                                   // sn
+	Status    string            `json:"status" gorm:"size:4;not null;default:'2';comment:状态"` // 1-停用 2-正启用
+	HistorySn model2.StringList `json:"historySn"`                                            // 历史绑定的sn
+
+	model2.ControlBy
+	model2.ModelTime
+	model2.DeptBy
+}
+type CoolerBoxOmit struct {
+	Id   int    `json:"id,omitempty"`   // 主键编码
+	Name string `json:"name,omitempty"` // 商品名称
+}
+
+func (CoolerBox) TableName() string {
+	return "cooler_box"
+}
+func (CoolerBoxOmit) TableName() string {
+	return "cooler_box"
+}

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

@@ -0,0 +1,75 @@
+package model
+
+import (
+	model2 "cold-delivery/common/model"
+	"errors"
+	log "gogs.baozhida.cn/zoie/OAuth-core/logger"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk/config"
+	"gorm.io/gorm"
+)
+
+var GetCompanyKeyErr = errors.New("获取公司秘钥失败")
+
+type SysDept struct {
+	model2.Model
+	ParentId int    `json:"parentId" gorm:""`                        // 上级部门
+	Path     string `json:"-" gorm:"size:255;" swaggerignore:"true"` // 路径
+	Name     string `json:"name"  gorm:"size:128;"`                  // 部门名称
+	Sort     int    `json:"-" gorm:"size:4;"`                        // 排序
+	Status   int    `json:"-" gorm:"size:4;"`                        // 状态 1-停用 2-正常
+	Remark   string `json:"remark"  gorm:"size:1024;"`               // 备注
+	ColdKey  string `json:"coldKey"  gorm:"size:128;"`               // 冷链3.0key
+	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
+}
+
+func GetCompanyById(id int) (SysDept, error) {
+	var err error
+	var deptModel SysDept
+	//准备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 deptModel, err
+	}
+	err = db.First(&deptModel, id).Error
+	if err != nil {
+		log.Errorf("db error: %s", err)
+		err = errors.New("获取企业信息失败")
+		return deptModel, err
+	}
+
+	return deptModel, nil
+}

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

@@ -0,0 +1,72 @@
+package model
+
+import (
+	model2 "cold-delivery/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-delivery/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-delivery/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" || l.OperaUrl == "/api/waybill/import" || l.OperaUrl == "/api/apk-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-delivery/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-delivery/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
+}

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

@@ -0,0 +1,113 @@
+package model
+
+import (
+	model2 "cold-delivery/common/model"
+	"errors"
+	"fmt"
+	coreModel "gogs.baozhida.cn/zoie/OAuth-core/model"
+	"golang.org/x/crypto/bcrypt"
+	"gorm.io/gorm"
+)
+
+var (
+	UserTypeSys          = "sys"
+	UserTypeCustomer     = "customer"
+	SysUserTypeSys       = 1
+	SysUserTypeWarehouse = 2
+	SysUserTypeDriver    = 3
+)
+
+type SysUser struct {
+	model2.Model
+	coreModel.User
+	Type     int     `json:"type" gorm:"size:128;comment:类型"`         // 管理员1 仓管2 司机3
+	UserType string  `json:"userType" gorm:"size:128;comment:用户类型"`   // 系统用户-sys 客户-customer
+	Openid   string  `json:"openid" gorm:"size:128;comment:微信openid"` // 微信openid
+	Dept     SysDept `json:"dept" gorm:"->"`                          // 部门
+	Role     SysRole `json:"-" 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)
+}
+
+type SysUserOmit struct {
+	Id       int    `json:"id,omitempty"`       // 主键编码
+	NickName string `json:"nickName,omitempty"` // 昵称
+	Phone    string `json:"phone,omitempty"`    // 昵称
+}
+
+func (SysUserOmit) TableName() string {
+	return "sys_user"
+}
+
+type SysUserForBind struct {
+	model2.Model
+	coreModel.User
+	Type     int    `json:"type" gorm:"size:128;comment:类型"`         // 管理员1 仓管2 司机3
+	UserType string `json:"userType" gorm:"size:128;comment:用户类型"`   // 系统用户-sys 客户-customer
+	Openid   string `json:"openid" gorm:"size:128;comment:微信openid"` // 微信openid
+	IsBind   bool
+	model2.ControlBy
+	model2.ModelTime
+}
+
+func (SysUserForBind) TableName() string {
+	return "sys_user"
+}

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

@@ -0,0 +1,32 @@
+package model
+
+import model2 "cold-delivery/common/model"
+
+// 仓库
+type Warehouse struct {
+	model2.Model
+	Name      string            `json:"name" gorm:"size:128"`                                 // 商品名称
+	Sn        string            `json:"sn" gorm:"size:128"`                                   // sn
+	Address   string            `json:"address" gorm:"size:255;"`                             // 地址
+	Status    string            `json:"status" gorm:"size:4;not null;default:'2';comment:状态"` // 1-停用 2-正启用
+	UserId    int               `json:"userId" gorm:"size:255;"`                              // 仓管id
+	HistorySn model2.StringList `json:"historySn"`                                            // 历史绑定的sn
+
+	User SysUserOmit `json:"user"`
+	model2.ControlBy
+	model2.ModelTime
+	model2.DeptBy
+}
+type WarehouseOmit struct {
+	Id     int         `json:"id,omitempty"`     // 主键编码
+	Name   string      `json:"name,omitempty"`   // 商品名称
+	UserId int         `json:"userId,omitempty"` // 仓管id
+	User   SysUserOmit `json:"user,omitempty"`
+}
+
+func (Warehouse) TableName() string {
+	return "warehouse"
+}
+func (WarehouseOmit) TableName() string {
+	return "warehouse"
+}

+ 67 - 0
app/admin/model/waybill.go

@@ -0,0 +1,67 @@
+package model
+
+import (
+	model2 "cold-delivery/common/model"
+	"database/sql/driver"
+	"encoding/json"
+)
+
+var (
+	WaybillStatusWaitDelivery = 1 // 已下单
+	WaybillStatusInDelivery   = 2 // 配送中
+
+	WaybillStatusReceipt   = 3 // 已签收
+	WaybillStatusRejection = 4 // 已拒收
+	WaybillStatusMap       = map[int]string{
+		WaybillStatusWaitDelivery: "已下单",
+		WaybillStatusInDelivery:   "配送中",
+		WaybillStatusReceipt:      "已签收",
+		WaybillStatusRejection:    "已拒收",
+	}
+)
+
+// 运单短信发送日志
+type WaybillSendLog struct {
+	Phone   string `json:"phone"`
+	Content string `json:"content"`
+}
+
+func (e WaybillSendLog) Value() (driver.Value, error) {
+	d, err := json.Marshal(e)
+	return string(d), err
+}
+func (e *WaybillSendLog) Scan(src interface{}) error {
+	return json.Unmarshal(src.([]byte), e)
+}
+
+// 运单
+type Waybill struct {
+	model2.Model
+	WaybillNo               string         `json:"waybillNo"  gorm:"size:128"`               // 单号
+	Status                  int            `json:"status"  gorm:"size:128"`                  // 订单状态:1已下单 2配送中 3已送达 4已拒收
+	SenderAddressDetails    string         `json:"senderAddressDetails"  gorm:"size:128"`    // 发货地址详情
+	SenderAddressName       string         `json:"senderAddressName"  gorm:"size:128"`       // 发货地址名称
+	SenderAddressPhone      string         `json:"senderAddressPhone"  gorm:"size:128"`      // 发货地址电话
+	ConsigneeAddressDetails string         `json:"consigneeAddressDetails"  gorm:"size:128"` // 收发货地址详情
+	ConsigneeAddressName    string         `json:"consigneeAddressName"  gorm:"size:128"`    // 收发货地址名称
+	ConsigneeAddressPhone   string         `json:"consigneeAddressPhone"  gorm:"size:128"`   // 收发货地址电话
+	Remark                  string         `json:"remark"  gorm:"size:4"`                    // 运输备注
+	OrderTime               model2.Time    `json:"orderTime"  gorm:"size:128"`               // 下单时间
+	DeliveryTime            model2.Time    `json:"deliveryTime"  gorm:"size:128"`            // 配送时间
+	ReceiptTime             model2.Time    `json:"receiptTime"  gorm:"size:128"`             // 签收时间
+	Quantity                int            `json:"quantity"  gorm:"size:128"`                // 药品数量
+	CoolerBoxId             int            `json:"coolerBoxId"  gorm:"size:128"`             // 保温箱id
+	ReceiptImg              string         `json:"receiptImg"  gorm:"size:text"`             // 签收图片
+	TamperProofLabel        string         `json:"tamperProofLabel"  gorm:"size:128"`        // 防拆标签
+	RejectionReason         string         `json:"rejectionReason"  gorm:"size:128"`         // 拒收原因
+	SendLog                 WaybillSendLog `json:"sendLog"`                                  // 运单短信发送日志
+	CoolerBox               CoolerBoxOmit  `json:"coolerBox" gorm:"->"`                      // 保温箱
+	Dept                    SysDeptOmit    `json:"dept" gorm:"->"`                           // 部门
+	model2.ControlBy
+	model2.ModelTime
+	model2.DeptBy
+}
+
+func (Waybill) TableName() string {
+	return "waybill"
+}

+ 38 - 0
app/admin/model/waybill_logistics.go

@@ -0,0 +1,38 @@
+package model
+
+import (
+	amap "cold-delivery/common/amap"
+	model2 "cold-delivery/common/model"
+	"gorm.io/gorm"
+)
+
+// 运单物流
+type WaybillLogistics struct {
+	model2.Model
+	WaybillNo string `json:"waybillNo"  gorm:"size:128"` // 单号
+	Status    int    `json:"status"  gorm:"size:128"`    //订单状态:1待派单 2待装车 3待入库 4已装车 5已入库 6已下车 7已出库 8已签收
+	//WarehouseId int           `json:"warehouseId"  gorm:"size:128"` // 仓库id
+	//CarId       int           `json:"carId"  gorm:"size:128"`       // 车辆id
+	CoolerBoxId int    `json:"coolerBoxId"  gorm:"size:128"` // 保温箱id
+	UserId      int    `json:"userId"  gorm:"size:128"`      // 司机/仓管id
+	Lng         string `json:"lng" gorm:"size:128;"`         // 经度
+	Lat         string `json:"lat" gorm:"size:128;"`         // 纬度
+	Address     string `json:"address" gorm:"size:128;"`     // 地址
+	//Warehouse   WarehouseOmit `json:"warehouse" gorm:"->;foreignkey:WarehouseId;references:Id"`
+	//Car         CarOmit       `json:"car" gorm:"->;foreignkey:CarId;references:Id"`
+	CoolerBox CoolerBoxOmit `json:"coolerBox" gorm:"->;foreignkey:CoolerBoxId;references:Id"`
+	model2.ControlBy
+	model2.ModelTime
+	model2.DeptBy
+}
+
+func (WaybillLogistics) TableName() string {
+	return "waybill_logistics"
+}
+
+func (u *WaybillLogistics) BeforeCreate(tx *gorm.DB) (err error) {
+	address := amap.GeocodeRegeo(u.Lng, u.Lat)
+	ac := address.Regeocode.AddressComponent
+	u.Address = ac.City + ac.District
+	return
+}

+ 31 - 0
app/admin/model/waybill_task.go

@@ -0,0 +1,31 @@
+package model
+
+import (
+	model2 "cold-delivery/common/model"
+	"cold-delivery/common/nats/nats_server"
+)
+
+// 运单任务
+type WaybillTask struct {
+	model2.Model
+	WaybillNo string `json:"waybillNo"  gorm:"size:128"` // 单号
+	//WarehouseId      int                          `json:"warehouseId"  gorm:"size:128"` // 仓库id
+	//CarId            int                          `json:"carId"  gorm:"size:128"`       // 车辆id
+	CoolerBoxId int         `json:"coolerBoxId"  gorm:"size:128"` // 保温箱id
+	UserId      int         `json:"userId"  gorm:"size:128"`      // 司机/仓管id
+	Sn          string      `json:"sn" gorm:"size:128"`           // sn
+	StartTime   model2.Time `json:"startTime"  gorm:"size:128"`   // 签收时间
+	EndTime     model2.Time `json:"endTime"  gorm:"size:128"`     // 签收时间
+	//Warehouse        WarehouseOmit                `json:"warehouse"`
+	//Car              CarOmit                      `json:"car"`
+	CoolerBox        CoolerBoxOmit                `json:"coolerBox"`
+	DeviceSensorList []nats_server.DeviceSensor_R `json:"deviceSensorList,omitempty"  gorm:"-"` // 传感器列表
+	DataList         []nats_server.DeviceData_R   `json:"dataList,omitempty"  gorm:"-"`         // 传感器列表
+	model2.ControlBy
+	model2.ModelTime
+	model2.DeptBy
+}
+
+func (WaybillTask) TableName() string {
+	return "waybill_task"
+}

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

@@ -0,0 +1,25 @@
+package router
+
+import (
+	"cold-delivery/app/admin/controller"
+	"cold-delivery/common/actions"
+	"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()).Use(actions.PermissionAction())
+	{
+		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-delivery/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)
+	}
+}

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

@@ -0,0 +1,25 @@
+package router
+
+import (
+	"cold-delivery/app/admin/controller"
+	"cold-delivery/common/actions"
+	"github.com/gin-gonic/gin"
+	jwt "gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth"
+)
+
+func init() {
+	routerCheckRole = append(routerCheckRole, registerCarRouter)
+}
+
+// 需认证的路由代码
+func registerCarRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
+	cont := controller.CarController{}
+	r := v1.Group("/car").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)
+	}
+}

+ 29 - 0
app/admin/router/company.go

@@ -0,0 +1,29 @@
+package router
+
+import (
+	"cold-delivery/app/admin/controller"
+	"cold-delivery/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("/all", cont.GetAll)
+		r.GET("/:id", cont.Get)
+		r.POST("", cont.Insert)
+		r.PUT("", cont.Update)
+		r.DELETE("", cont.Delete)
+
+	}
+
+}

+ 30 - 0
app/admin/router/cooler_box.go

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

+ 31 - 0
app/admin/router/customer.go

@@ -0,0 +1,31 @@
+package router
+
+import (
+	"cold-delivery/common/actions"
+	"github.com/gin-gonic/gin"
+
+	"cold-delivery/app/admin/controller"
+	jwt "gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth"
+)
+
+func init() {
+	routerCheckRole = append(routerCheckRole, registerCustomerRouter)
+
+}
+
+// 需认证的路由代码
+func registerCustomerRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
+	cont := controller.Customer{}
+	r := v1.Group("/customer").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)
+		r.PUT("/pwd/reset", cont.ResetPwd)
+		r.GET("/profile", cont.GetProfile)
+		r.PUT("/pwd/set", cont.UpdatePwd)
+
+	}
+}

+ 23 - 0
app/admin/router/device.go

@@ -0,0 +1,23 @@
+package router
+
+import (
+	"cold-delivery/app/admin/controller"
+	"cold-delivery/common/actions"
+	"github.com/gin-gonic/gin"
+	jwt "gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth"
+)
+
+func init() {
+	routerCheckRole = append(routerCheckRole, registerDeviceRouter)
+
+}
+
+// 需认证的路由代码
+func registerDeviceRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
+	cont := controller.DeviceController{}
+	r := v1.Group("/device").Use(authMiddleware.MiddlewareFunc()).Use(actions.PermissionAction())
+	{
+		r.GET("/sensor-list", cont.GetSensorList)
+		r.GET("/data", cont.GetData)
+	}
+}

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

@@ -0,0 +1,90 @@
+package router
+
+import (
+	"cold-delivery/common/middleware"
+	handler2 "cold-delivery/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)
+)

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

@@ -0,0 +1,25 @@
+package router
+
+import (
+	"cold-delivery/common/middleware"
+	"github.com/gin-gonic/gin"
+
+	"cold-delivery/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)
+	}
+}

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

@@ -0,0 +1,24 @@
+package router
+
+import (
+	"cold-delivery/common/middleware"
+	"github.com/gin-gonic/gin"
+
+	"cold-delivery/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)
+	}
+}

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

@@ -0,0 +1,49 @@
+package router
+
+import (
+	"cold-delivery/common/actions"
+	"github.com/gin-gonic/gin"
+
+	"cold-delivery/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("/bind", cont.GetPageFoeBind)
+		r.GET("/:id", cont.Get)
+		r.POST("", cont.Insert)
+		r.PUT("", cont.Update)
+		r.DELETE("", cont.Delete)
+		r.PUT("/pwd/reset", cont.ResetPwd)
+	}
+
+	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)
+
+	}
+
+}
+func registerSysUserRouter2(v1 *gin.RouterGroup) {
+	cont := controller.SysUser{}
+
+	r2 := v1.Group("")
+	{
+		r2.GET("/verify-code", cont.VerifyCode)
+	}
+
+}

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

@@ -0,0 +1,20 @@
+package router
+
+import (
+	"cold-delivery/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)
+		r1.POST("/apk-upload", cont.ApkUpload)
+	}
+}

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

@@ -0,0 +1,26 @@
+package router
+
+import (
+	"cold-delivery/app/admin/controller"
+	"cold-delivery/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)
+	}
+}

+ 56 - 0
app/admin/router/waybill.go

@@ -0,0 +1,56 @@
+package router
+
+import (
+	"cold-delivery/app/admin/controller"
+	"cold-delivery/common/actions"
+	"github.com/gin-gonic/gin"
+	jwt "gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth"
+)
+
+func init() {
+	routerCheckRole = append(routerCheckRole, registerWaybillRouter)
+	routerNoCheckRole = append(routerNoCheckRole, registerWaybillRouter2)
+
+}
+
+// 派费管理
+// 需认证的路由代码
+func registerWaybillRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
+	cont := controller.WaybillController{}
+	r := v1.Group("/waybill").Use(authMiddleware.MiddlewareFunc()).Use(actions.PermissionAction())
+	{
+		r.GET("", cont.GetPage)
+		r.GET("/:id", cont.Get)
+		r.POST("", cont.Insert)
+		r.POST("/applet", cont.AppletInsert)
+		r.POST("/delivery", cont.Delivery)
+		r.PUT("", cont.Update)
+		r.DELETE("", cont.Delete)
+		//r.POST("/warehouse-in", cont.WarehouseIn)   // 入库
+		//r.POST("/warehouse-out", cont.WarehouseOut) // 出库
+		//r.POST("/car-in", cont.CarIn)               // 装车
+		//r.POST("/car-out", cont.CarOut)             // 下车
+		r.POST("/receipt", cont.Receipt)         // 签收
+		r.GET("/customer", cont.GetCustomerPage) // 客户下单列表
+		r.POST("/customer", cont.CustomerInsert) // 客户下单
+
+		r.GET("/applet", cont.GetAppletPage)           // app 运单列表
+		r.GET("/applet-count", cont.GetAppletCount)    // app 运单-统计
+		r.POST("/import", cont.Import)                 // 导入运单
+		r.GET("/export-template", cont.ExportTemplate) // 导出运单模板
+		r.GET("/home", cont.Home)                      // 首页统计
+		r.GET("/export", cont.Export)                  // 运单管理-导出
+		r.GET("/customer/export", cont.CustomerExport) // 客户下单
+		r.GET("/temperature-pdf", cont.TemperaturePDF) // 导出温湿度pdf
+	}
+}
+
+func registerWaybillRouter2(v1 *gin.RouterGroup) {
+	cont := controller.WaybillController{}
+	r := v1.Group("/waybill")
+	{
+		r.POST("/customer/receipt", cont.CustomerReceipt) // 客户签收
+		r.GET("/no", cont.GetByWaybillNo)
+
+	}
+}

+ 20 - 0
app/admin/router/waybill_logistics.go

@@ -0,0 +1,20 @@
+package router
+
+import (
+	"cold-delivery/app/admin/controller"
+	"github.com/gin-gonic/gin"
+)
+
+func init() {
+	routerNoCheckRole = append(routerNoCheckRole, registerWaybillLogisticsRouter)
+}
+
+// 物流详情
+// 需认证的路由代码
+func registerWaybillLogisticsRouter(v1 *gin.RouterGroup) {
+	cont := controller.WaybillLogisticsController{}
+	r := v1.Group("/waybill-logistics")
+	{
+		r.GET("", cont.GetPage)
+	}
+}

+ 23 - 0
app/admin/router/waybill_task.go

@@ -0,0 +1,23 @@
+package router
+
+import (
+	"cold-delivery/app/admin/controller"
+	"github.com/gin-gonic/gin"
+)
+
+func init() {
+	routerNoCheckRole = append(routerNoCheckRole, registerWaybillTaskRouter)
+}
+
+// 物流详情
+// 需认证的路由代码
+func registerWaybillTaskRouter(v1 *gin.RouterGroup) {
+	cont := controller.WaybillTaskController{}
+	r := v1.Group("/waybill-task")
+	{
+		r.GET("", cont.GetPage)
+		r.POST("/data", cont.GetData)
+		r.GET("/locus", cont.GetLocus)
+		r.POST("/newest-locus", cont.GetNewestData)
+	}
+}

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

@@ -0,0 +1,259 @@
+package service
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/app/admin/service/dto"
+	"cold-delivery/common/actions"
+	cDto "cold-delivery/common/dto"
+	"cold-delivery/common/global"
+	"errors"
+	"fmt"
+	"gogs.baozhida.cn/zoie/OAuth-core/service"
+	"gorm.io/gorm"
+	"gorm.io/gorm/clause"
+)
+
+type Address struct {
+	service.Service
+}
+
+func AddressNameScopes(name string) func(db *gorm.DB) *gorm.DB {
+	return func(db *gorm.DB) *gorm.DB {
+		if len(name) == 0 {
+			return db
+		}
+		name = "%" + name + "%"
+		return db.Where("phone like ? or address like ? or province_name like ? or city_name like ? or region_name like ?",
+			name, name, name, name, name)
+	}
+}
+
+func AddressDataScopes(dataType string, userId int) func(db *gorm.DB) *gorm.DB {
+	return func(db *gorm.DB) *gorm.DB {
+
+		if dataType == "all" {
+			return db
+		}
+		return db.Where("create_by = ?", userId)
+	}
+}
+
+// GetPage 获取Address列表
+func (e *Address) GetPage(c *dto.AddressGetPageReq, list *[]model.Address, count *int64, p *actions.DataPermission) error {
+	var err error
+	var data model.Address
+
+	var ad model.AddressDefault
+	err = e.Orm.Model(&ad).Where("user_id = ?", p.UserId).First(&ad).Error
+	if err != nil && !errors.Is(gorm.ErrRecordNotFound, err) {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+
+	err = e.Orm.Model(&data).
+		Scopes(
+			AddressNameScopes(c.Name),
+			AddressDataScopes(c.DataType, p.UserId),
+			cDto.MakeCondition(c.GetNeedSearch()),
+			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
+		).
+		Order(fmt.Sprintf("id = %d desc", ad.AddressId)).
+		Find(list).Limit(-1).Offset(-1).
+		Count(count).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+
+	if *count > 0 {
+		if (*list)[0].Id == ad.AddressId {
+			(*list)[0].IsDefault = true
+		}
+	}
+	return nil
+}
+
+// Get 获取Address对象
+func (e *Address) Get(d *dto.AddressGetReq, carInfoModel *model.Address, p *actions.DataPermission) error {
+
+	var ad model.AddressDefault
+	err := e.Orm.Model(&ad).Where("user_id = ?", p.UserId).First(&ad).Error
+	if err != nil && !errors.Is(gorm.ErrRecordNotFound, err) {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+
+	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
+	}
+
+	if ad.AddressId == carInfoModel.Id {
+		carInfoModel.IsDefault = true
+	}
+
+	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()
+		}
+	}()
+
+	// 添加地址
+	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
+
+	if c.AddressType == model.AddressTypeSender && c.IsDefault == true {
+		ad := &model.AddressDefault{UserId: c.CreateBy, AddressId: c.Id}
+		//err = tx.Model(&ad).
+		//	Where("user_id = ?", c.CreateBy).Update("address_id", c.Id).Error
+		//if err != nil {
+		//	if errors.Is(gorm.ErrRecordNotFound, err) {
+		//		err = tx.Create(&ad).Error
+		//		if err != nil {
+		//			e.Log.Errorf("db error: %s", err)
+		//			return global.CreateFailedErr
+		//		}
+		//		return nil
+		//	}
+		//	e.Log.Errorf("db error: %s", err)
+		//	return global.CreateFailedErr
+		//}
+		err = tx.Debug().Clauses(clause.OnConflict{
+			Columns: []clause.Column{{Name: "user_id"}},
+			//DoUpdates: clause.AssignmentColumns([]string{"address_id"}),
+			UpdateAll: true,
+		}).Create(&ad).Error
+		if err != nil {
+			e.Log.Errorf("db error: %s", err)
+			return global.CreateFailedErr
+		}
+	}
+
+	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 ad model.AddressDefault
+	err = e.Orm.Model(&ad).Where("user_id = ?", p.UserId).First(&ad).Error
+	if err != nil && !errors.Is(gorm.ErrRecordNotFound, err) {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+
+	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 && carInfoModel.Id != ad.AddressId && ad.AddressId > 0 {
+		err = tx.Model(&model.AddressDefault{}).Where("id = ?", ad.Id).
+			Update("address_id", carInfoModel.Id).Error
+		if err != nil {
+			e.Log.Errorf("db error: %s", err)
+			return global.UpdateFailedErr
+		}
+	}
+
+	// 取消默认地址
+	if c.IsDefault == false && carInfoModel.Id == ad.AddressId {
+		err = tx.Unscoped().Where("id = ?", ad.Id).Delete(&model.AddressDefault{}).Error
+		if err != nil {
+			e.Log.Errorf("db error: %s", err)
+			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 删除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
+}

+ 281 - 0
app/admin/service/car.go

@@ -0,0 +1,281 @@
+package service
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/app/admin/service/dto"
+	"cold-delivery/common/actions"
+	cDto "cold-delivery/common/dto"
+	"cold-delivery/common/global"
+	"errors"
+	"gogs.baozhida.cn/zoie/OAuth-core/service"
+	"gorm.io/gorm"
+)
+
+type Car struct {
+	service.Service
+}
+
+func CarIsBindUserScopes(isBind bool) func(db *gorm.DB) *gorm.DB {
+	return func(db *gorm.DB) *gorm.DB {
+		// 未发货
+		if isBind {
+			return db.Where("user_id > 0")
+		}
+		return db
+	}
+}
+
+// GetPage 获取Car列表
+func (e *Car) GetPage(c *dto.CarGetPageReq, list *[]model.Car, count *int64, p *actions.DataPermission) error {
+	var err error
+	var data model.Car
+
+	err = e.Orm.Model(&data).
+		Scopes(
+			cDto.MakeCondition(c.GetNeedSearch()),
+			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
+			actions.Permission(data.TableName(), p),
+			CarIsBindUserScopes(c.IsBind),
+		).
+		Joins("User").
+		Where("car_no like ? or User.nick_name like ?", "%"+c.Name+"%", "%"+c.Name+"%").
+		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 获取Car对象
+func (e *Car) Get(d *dto.CarGetReq, carModel *model.Car, p *actions.DataPermission) error {
+	err := e.Orm.
+		Scopes(actions.Permission(carModel.TableName(), p)).
+		Preload("User").
+		First(carModel, 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 创建Car对象
+func (e *Car) Insert(c *dto.CarInsertReq) error {
+	var err error
+	var data model.Car
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	var i int64
+	err = tx.Model(&data).Where("car_no = ?", c.CarNo).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
+	}
+	var j int64
+	err = tx.Model(&data).Where("user_id = ?", c.UserId).Count(&j).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.CreateFailedErr
+	}
+	if j > 0 {
+		err = errors.New("该用户已绑定其他车辆!")
+		e.Log.Errorf("db error: %s", err)
+		return err
+	}
+
+	var k int64
+	err = tx.Model(&data).Where("sn = ?", c.Sn).Count(&k).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.CreateFailedErr
+	}
+	if k > 0 {
+		err = errors.New("该Sn已绑定其他车辆!")
+		e.Log.Errorf("db error: %s", err)
+		return err
+	}
+
+	// 添加仓库
+	c.Generate(&data)
+	data.HistorySn = []string{data.Sn}
+	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 修改Car对象
+func (e *Car) Update(c *dto.CarUpdateReq, p *actions.DataPermission) error {
+	var err error
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	var carModel = model.Car{}
+	// 查询仓库是否存在
+	err = e.Orm.Scopes(actions.Permission(carModel.TableName(), p)).
+		First(&carModel, 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 carModel.Sn != c.Sn {
+		var k int64
+		var data = model.Car{}
+		err = tx.Model(&data).Where("sn = ?", c.Sn).Count(&k).Error
+		if err != nil {
+			e.Log.Errorf("db error: %s", err)
+			return global.CreateFailedErr
+		}
+		if k > 0 {
+			err = errors.New("该Sn已绑定其他车辆!")
+			e.Log.Errorf("db error: %s", err)
+			return err
+		}
+
+		carModel.HistorySn = append(carModel.HistorySn, c.Sn)
+	}
+
+	if carModel.UserId != c.UserId {
+		var k int64
+		var data = model.Car{}
+		err = tx.Model(&data).Where("user_id = ?", c.UserId).Count(&k).Error
+		if err != nil {
+			e.Log.Errorf("db error: %s", err)
+			return global.CreateFailedErr
+		}
+		if k > 0 {
+			err = errors.New("该用户已绑定其他车辆!")
+			e.Log.Errorf("db error: %s", err)
+			return err
+		}
+	}
+
+	c.Generate(&carModel)
+	err = tx.Save(&carModel).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.UpdateFailedErr
+	}
+
+	c.Id = carModel.Id
+	return nil
+}
+
+// Remove 删除Car
+func (e *Car) Remove(c *dto.CarDeleteReq, p *actions.DataPermission) error {
+	var err error
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	var carModel model.Car
+
+	// 查询仓库是否存在
+	err = e.Orm.Scopes(actions.Permission(carModel.TableName(), p)).
+		First(&carModel, 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(&carModel)
+
+	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
+}
+
+// GetUserList 获取绑定车辆的用户
+func (e *Car) GetUserList(c *dto.SysUserGetPageReq, p *actions.DataPermission, list *[]model.SysUserForBind, count *int64) error {
+	var err error
+	var userList []model.SysUserForBind
+
+	var carModel model.Car
+	var userModel model.SysUserForBind
+	var userIds []int
+	// 查询仓库是否存在
+	err = e.Orm.Model(&carModel).Select("user_id").Scopes(actions.Permission(carModel.TableName(), p)).
+		Find(&userIds).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+
+	err = e.Orm.
+		Scopes(
+			cDto.MakeCondition(c.GetNeedSearch()),
+			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
+			actions.UserPermission(userModel.TableName(), p),
+		).
+		Where("user_type = ? ", model.UserTypeSys).
+		Find(&userList).Limit(-1).Offset(-1).
+		Count(count).Error
+
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+	userIdMap := make(map[int]bool)
+	for _, id := range userIds {
+		userIdMap[id] = true
+	}
+
+	for i := 0; i < len(userList); i++ {
+		if _, ok := userIdMap[userList[i].Id]; ok {
+			userList[i].IsBind = true
+		}
+	}
+
+	*list = userList
+	return nil
+}

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

@@ -0,0 +1,224 @@
+package service
+
+import (
+	"cold-delivery/common/actions"
+	cDto "cold-delivery/common/dto"
+	"cold-delivery/common/global"
+	"errors"
+	"gogs.baozhida.cn/zoie/OAuth-core/service"
+	"gorm.io/gorm"
+	"gorm.io/gorm/clause"
+
+	"cold-delivery/app/admin/model"
+	"cold-delivery/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.SysDept
+
+	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
+}
+
+func CompanyIdScopes(id int) func(db *gorm.DB) *gorm.DB {
+
+	return func(db *gorm.DB) *gorm.DB {
+		if id == 0 {
+			return db
+		}
+		return db.Where("id = ? ", id)
+	}
+}
+func (e *Company) GetAll(c *dto.CompanyGetAllReq, list *[]model.SysDept, count *int64, p *actions.DataPermission) error {
+	var err error
+	var data model.SysDept
+
+	err = e.Orm.Model(&data).
+		Scopes(
+			CompanyIdScopes(p.DeptId),
+			cDto.MakeCondition(c.GetNeedSearch()),
+		).
+		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) error {
+	var err error
+	var data model.SysDept
+	tx := e.Orm.Debug().Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	var i int64
+	err = e.Orm.Model(&data).Where("name = ?", c.Name).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
+	}
+
+	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
+	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
+}

+ 235 - 0
app/admin/service/cooler_box.go

@@ -0,0 +1,235 @@
+package service
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/app/admin/service/dto"
+	"cold-delivery/common/actions"
+	cDto "cold-delivery/common/dto"
+	"cold-delivery/common/global"
+	"errors"
+	"gogs.baozhida.cn/zoie/OAuth-core/service"
+	"gorm.io/gorm"
+)
+
+type CoolerBox struct {
+	service.Service
+}
+
+// GetPage 获取CoolerBox列表
+func (e *CoolerBox) GetPage(c *dto.CoolerBoxGetPageReq, list *[]model.CoolerBox, count *int64, p *actions.DataPermission) error {
+	var err error
+	var data model.CoolerBox
+
+	if c.PageSize == 9999 {
+		err = e.Orm.Model(&data).
+			Scopes(
+				actions.Permission(data.TableName(), p),
+			).
+			Find(list).Limit(-1).Offset(-1).
+			Count(count).Error
+	} else {
+		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 获取CoolerBox对象
+func (e *CoolerBox) Get(d *dto.CoolerBoxGetReq, CoolerBoxModel *model.CoolerBox, p *actions.DataPermission) error {
+	err := e.Orm.
+		Scopes(actions.Permission(CoolerBoxModel.TableName(), p)).
+		First(CoolerBoxModel, 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 创建CoolerBox对象
+func (e *CoolerBox) Insert(c *dto.CoolerBoxInsertReq) error {
+	var err error
+	var data model.CoolerBox
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	var k int64
+	err = tx.Model(&data).Where("sn = ?", c.Sn).Count(&k).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.CreateFailedErr
+	}
+	if k > 0 {
+		err = errors.New("该Sn已绑定!")
+		e.Log.Errorf("db error: %s", err)
+		return err
+	}
+
+	// 添加保温箱
+	c.Generate(&data)
+	data.HistorySn = []string{data.Sn}
+	err = tx.Create(&data).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.CreateFailedErr
+	}
+	c.Id = data.Id
+
+	return nil
+
+}
+func (e *CoolerBox) BatchInsert(c *dto.CoolerBoxBatchInsertReq) error {
+	var err error
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	for _, coolerBox := range c.List {
+		var data model.CoolerBox
+
+		var k int64
+		err = tx.Model(&data).Where("sn = ?", coolerBox.Sn).Count(&k).Error
+		if err != nil {
+			e.Log.Errorf("db error: %s", err)
+			return global.CreateFailedErr
+		}
+		if k > 0 {
+			err = errors.New("该Sn已绑定!")
+			continue
+		}
+
+		// 添加保温箱
+		coolerBox.CreateBy = c.CreateBy
+		coolerBox.DeptId = c.DeptId
+		coolerBox.Status = c.Status
+		coolerBox.Generate(&data)
+		data.HistorySn = []string{data.Sn}
+		err = tx.Create(&data).Error
+		if err != nil {
+			e.Log.Errorf("db error: %s", err)
+			return global.CreateFailedErr
+		}
+	}
+
+	return nil
+
+}
+
+// Update 修改CoolerBox对象
+func (e *CoolerBox) Update(c *dto.CoolerBoxUpdateReq, p *actions.DataPermission) error {
+	var err error
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	var CoolerBoxModel = model.CoolerBox{}
+	// 查询保温箱是否存在
+	err = e.Orm.Scopes(actions.Permission(CoolerBoxModel.TableName(), p)).
+		First(&CoolerBoxModel, 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 CoolerBoxModel.Sn != c.Sn {
+		var k int64
+		var data = model.CoolerBox{}
+		err = tx.Model(&data).Where("sn = ?", c.Sn).Count(&k).Error
+		if err != nil {
+			e.Log.Errorf("db error: %s", err)
+			return global.CreateFailedErr
+		}
+		if k > 0 {
+			err = errors.New("该Sn已绑定!")
+			e.Log.Errorf("db error: %s", err)
+			return err
+		}
+
+		CoolerBoxModel.HistorySn = append(CoolerBoxModel.HistorySn, c.Sn)
+	}
+
+	c.Generate(&CoolerBoxModel)
+	err = tx.Save(&CoolerBoxModel).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.UpdateFailedErr
+	}
+
+	c.Id = CoolerBoxModel.Id
+	return nil
+}
+
+// Remove 删除CoolerBox
+func (e *CoolerBox) Remove(c *dto.CoolerBoxDeleteReq, p *actions.DataPermission) error {
+	var err error
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	var CoolerBoxModel model.CoolerBox
+
+	// 查询保温箱是否存在
+	err = e.Orm.Scopes(actions.Permission(CoolerBoxModel.TableName(), p)).
+		First(&CoolerBoxModel, 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(&CoolerBoxModel)
+
+	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
+}

+ 306 - 0
app/admin/service/customer.go

@@ -0,0 +1,306 @@
+package service
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/app/admin/service/dto"
+	"cold-delivery/common/actions"
+	cDto "cold-delivery/common/dto"
+	"cold-delivery/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 Customer struct {
+	service.Service
+}
+
+// GetPage 获取Customer列表
+func (e *Customer) GetPage(c *dto.CustomerGetPageReq, 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("user_type = ?", model.UserTypeCustomer).
+		Find(&userList).Limit(-1).Offset(-1).
+		Count(count).Error
+
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+
+	*list = userList
+	return nil
+}
+
+// Get 获取Customer对象
+func (e *Customer) Get(d *dto.CustomerGetReq, p *actions.DataPermission, userModel *model.SysUser) error {
+	var data model.SysUser
+	//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
+	}
+	return nil
+}
+
+// Insert 创建Customer对象
+func (e *Customer) Insert(c *dto.CustomerInsertReq) error {
+	var err error
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	var dept model.SysDept
+	var deptCount int64
+	err = e.Orm.Model(&dept).Where("id = ?", c.DeptId).Count(&deptCount).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.CreateFailedErr
+	}
+	if deptCount == 0 {
+		err = errors.New("公司不存在!")
+		e.Log.Errorf("db error: %s", err)
+		return err
+	}
+
+	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
+	}
+
+	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 修改Customer对象
+func (e *Customer) Update(c *dto.CustomerUpdateReq, 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
+	}
+
+	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 *Customer) UpdateStatus(c *dto.UpdateCustomerStatusReq, 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 *Customer) ResetPwd(c *dto.ResetCustomerPwdReq, 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 删除Customer
+func (e *Customer) Remove(c *dto.CustomerDeleteReq, 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
+	}
+
+	var car model.Car
+	var j int64
+	err = e.Orm.Model(&car).Where("user_id = ?", c.GetId()).Count(&j).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.CreateFailedErr
+	}
+	if j > 0 {
+		err = errors.New("该用户已绑定车辆,禁止删除!")
+		e.Log.Errorf("db error: %s", err)
+		return err
+	}
+
+	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 修改Customer对象密码
+func (e *Customer) 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 *Customer) GetProfile(c *dto.CustomerById, user *model.SysUser) error {
+	err := e.Orm.Preload("Dept").First(user, c.GetId()).Error
+	if err != nil {
+		return err
+	}
+
+	return nil
+}

+ 64 - 0
app/admin/service/device.go

@@ -0,0 +1,64 @@
+package service
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/app/admin/service/dto"
+	"cold-delivery/common/actions"
+	"cold-delivery/common/global"
+	"cold-delivery/common/nats/nats_server"
+	"fmt"
+	"gogs.baozhida.cn/zoie/OAuth-core/service"
+)
+
+type Device struct {
+	service.Service
+}
+
+// GetPage 获取Device列表
+func (e *Device) GetSensorList(p *actions.DataPermission) (list []nats_server.DeviceSensor_R, count int64, err error) {
+	var userObj model.SysUser
+
+	err = e.Orm.Model(&userObj).First(&userObj, p.UserId).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return list, count, global.GetFailedErr
+	}
+	var sn string
+	// 仓管2 司机3
+	if userObj.Type == 2 {
+		err = e.Orm.Model(&model.Warehouse{}).Select("sn").Where("user_id = ?", userObj.Id).Scan(&sn).Error
+	}
+	if userObj.Type == 3 {
+		err = e.Orm.Model(&model.Car{}).Select("sn").Where("user_id = ?", userObj.Id).Scan(&sn).Error
+	}
+
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return list, count, global.GetFailedErr
+	}
+
+	if len(sn) == 0 {
+		return list, count, nil
+	}
+
+	company, err := model.GetCompanyById(p.DeptId)
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return list, count, model.GetCompanyKeyErr
+	}
+	list, count, err = nats_server.Cold_CompanyDeviceSensor_List_ByKey(sn, company.ColdKey)
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return list, count, err
+	}
+	return list, count, nil
+}
+func (e *Device) GetData(c dto.DeviceGetDataReq, p *actions.DataPermission) (list []nats_server.DeviceData_R, count int64, err error) {
+	T_snid := fmt.Sprintf("%s,%d|", c.T_sn, c.T_id)
+	list, count, err = nats_server.Cold_ReadDeviceDataListBy_T_snid(T_snid, c.StartTime, c.EndTime, c.Page, c.PageSize)
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return list, count, err
+	}
+	return list, count, nil
+}

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

@@ -0,0 +1,131 @@
+package dto
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/common/dto"
+	common "cold-delivery/common/model"
+)
+
+type AddressGetPageReq struct {
+	dto.Pagination `search:"-"`
+	Name           string `form:"name" search:"-"`                                                   // 地址名称
+	AddressType    string `form:"addressType" search:"type:exact;column:address_type;table:address"` //地址类型:sender-发货人 consignee-收货人
+	DataType       string `form:"dataType" search:"-"`                                               // 我的my 全部all
+	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"` // 编码
+	Name         string `json:"name" vd:"len($)>0;msg:'姓名不能为空'"`      // 收货人名称
+	Phone        string `json:"phone" vd:"len($)>0;msg:'手机号不能为空'"`    // 联系电话
+	Address      string `json:"address" vd:"len($)>0;msg:'详细地址不能为空'"` // 详细地址
+	IsDefault    bool   `json:"isDefault"`                            // 默认地址
+	ProvinceId   string `json:"provinceId"`                           // 省Id
+	ProvinceName string `json:"provinceName"`                         // 省中文名
+	CityId       string `json:"cityId"`                               // 市Id
+	CityName     string `json:"cityName"`                             // 市中文名
+	RegionId     string `json:"regionId"`                             // 区Id
+	RegionName   string `json:"regionName"`                           // 区中文名
+	AddressType  string `json:"addressType"`                          // 地址类型:sender-发货人 consignee-收货人
+
+	common.ControlBy `swaggerignore:"true"`
+	common.DeptBy    `swaggerignore:"true"`
+}
+
+func (s *AddressInsertReq) Generate(m *model.Address) {
+	if s.Id != 0 {
+		m.Id = s.Id
+	}
+	m.Name = s.Name
+	m.Phone = s.Phone
+	m.Address = s.Address
+	m.IsDefault = s.IsDefault
+	m.ProvinceId = s.ProvinceId
+	m.ProvinceName = s.ProvinceName
+	m.CityId = s.CityId
+	m.CityName = s.CityName
+	m.RegionId = s.RegionId
+	m.RegionName = s.RegionName
+	m.AddressType = s.AddressType
+	if s.ControlBy.UpdateBy != 0 {
+		m.UpdateBy = s.UpdateBy
+	}
+	if s.ControlBy.CreateBy != 0 {
+		m.CreateBy = s.CreateBy
+	}
+	if s.DeptBy.DeptId != 0 {
+		m.DeptId = s.DeptId
+	}
+}
+
+func (s *AddressInsertReq) GetId() interface{} {
+	return s.Id
+}
+
+type AddressUpdateReq struct {
+	Id           int    `json:"id" comment:"编码"`                      // 编码
+	Name         string `json:"name" vd:"len($)>0;msg:'姓名不能为空'"`      // 收货人名称
+	Phone        string `json:"phone" vd:"len($)>0;msg:'手机号不能为空'"`    // 联系电话
+	Address      string `json:"address" vd:"len($)>0;msg:'详细地址不能为空'"` // 详细地址
+	IsDefault    bool   `json:"isDefault"`                            // 默认地址
+	ProvinceId   string `json:"provinceId"`                           // 省Id
+	ProvinceName string `json:"provinceName"`                         // 省中文名
+	CityId       string `json:"cityId"`                               // 市Id
+	CityName     string `json:"cityName"`                             // 市中文名
+	RegionId     string `json:"regionId"`                             // 区Id
+	RegionName   string `json:"regionName"`                           // 区中文名
+	AddressType  string `json:"addressType"`                          // 地址类型:sender-发货人 consignee-收货人
+
+	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.Address = s.Address
+	m.IsDefault = s.IsDefault
+	m.ProvinceId = s.ProvinceId
+	m.ProvinceName = s.ProvinceName
+	m.CityId = s.CityId
+	m.CityName = s.CityName
+	m.RegionId = s.RegionId
+	m.RegionName = s.RegionName
+	m.AddressType = s.AddressType
+	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
+}

+ 102 - 0
app/admin/service/dto/car.go

@@ -0,0 +1,102 @@
+package dto
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/common/dto"
+	common "cold-delivery/common/model"
+)
+
+type CarGetPageReq struct {
+	dto.Pagination `search:"-"`
+	Name           string `form:"name" search:"-"`                               // 车牌号
+	Sn             string `form:"sn" search:"type:contains;column:sn;table:car"` // sn
+	IsBind         bool   `form:"isBind" search:"-"`                             // 是否绑定司机
+	CarOrder
+}
+
+type CarOrder struct {
+	CreatedAtOrder string `search:"type:order;column:created_at;table:car" form:"createdAtOrder" default:"desc"`
+}
+
+func (m *CarGetPageReq) GetNeedSearch() interface{} {
+	return *m
+}
+
+type CarInsertReq struct {
+	Id               int    `json:"id" comment:"编码" swaggerignore:"true"` // 编码
+	CarNo            string `json:"carNo"`                                // 商品名称
+	Sn               string `json:"sn"`                                   // sn
+	Status           string `json:"status"`                               // 1-停用 2-正启用
+	UserId           int    `json:"userId"`                               // 绑定的用户id
+	common.ControlBy `swaggerignore:"true"`
+	common.DeptBy    `swaggerignore:"true"`
+}
+
+func (s *CarInsertReq) Generate(model *model.Car) {
+	if s.Id != 0 {
+		model.Id = s.Id
+	}
+	model.CarNo = s.CarNo
+	model.Sn = s.Sn
+	model.Status = s.Status
+	model.UserId = s.UserId
+	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 *CarInsertReq) GetId() interface{} {
+	return s.Id
+}
+
+type CarUpdateReq struct {
+	Id               int    `json:"id" comment:"编码"` // 编码
+	CarNo            string `json:"carNo"`           // 商品名称
+	Sn               string `json:"sn"`              // sn
+	Status           string `json:"status"`          // 1-停用 2-正启用
+	UserId           int    `json:"userId"`          // 绑定的用户id
+	common.ControlBy `swaggerignore:"true"`
+}
+
+func (s *CarUpdateReq) Generate(model *model.Car) {
+	if s.Id != 0 {
+		model.Id = s.Id
+	}
+	model.CarNo = s.CarNo
+	model.Sn = s.Sn
+	model.Status = s.Status
+	model.UserId = s.UserId
+	if s.ControlBy.UpdateBy != 0 {
+		model.UpdateBy = s.UpdateBy
+	}
+	if s.ControlBy.CreateBy != 0 {
+		model.CreateBy = s.CreateBy
+	}
+}
+
+func (s *CarUpdateReq) GetId() interface{} {
+	return s.Id
+}
+
+type CarGetReq struct {
+	Id int `uri:"id"`
+}
+
+func (s *CarGetReq) GetId() interface{} {
+	return s.Id
+}
+
+type CarDeleteReq struct {
+	Id               int `json:"id"`
+	common.ControlBy `swaggerignore:"true"`
+}
+
+func (s *CarDeleteReq) GetId() interface{} {
+	return s.Id
+}

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

@@ -0,0 +1,115 @@
+package dto
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/common/dto"
+	common "cold-delivery/common/model"
+)
+
+// SysDeptGetPageReq 列表或者搜索使用结构体
+type CompanyGetPageReq struct {
+	dto.Pagination `search:"-"`
+	Name           string `form:"name" search:"type:contains;column:name;table:sys_dept" example:"公司名称"` //公司名称
+	CompanyOrder
+}
+
+type CompanyGetAllReq struct {
+	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
+}
+
+func (m *CompanyGetAllReq) GetNeedSearch() interface{} {
+	return *m
+}
+
+type CompanyInsertReq struct {
+	Id      int    `json:"id" swaggerignore:"true"`
+	Name    string `json:"name" example:"名称" vd:"len($)>0;msg:'公司名称不能为空'"` //名称
+	Remark  string `json:"remark"`                                         // 备注
+	ColdKey string `json:"coldKey"`                                        // 冷链3.0key
+
+	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
+	model.Remark = s.Remark
+	model.ColdKey = s.ColdKey
+}
+
+// GetId 获取数据对应的ID
+func (s *CompanyInsertReq) GetId() interface{} {
+	return s.Id
+}
+
+type CompanyUpdateReq struct {
+	Id               int    `json:"id" comment:"编码"`   // 编码
+	Name             string `json:"name" example:"名称"` //名称
+	Remark           string `json:"remark"`            // 备注
+	ColdKey          string `json:"coldKey"`           // 冷链3.0key
+	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
+	model.Remark = s.Remark
+	model.ColdKey = s.ColdKey
+}
+
+// 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
+}

+ 109 - 0
app/admin/service/dto/cooler_box.go

@@ -0,0 +1,109 @@
+package dto
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/common/dto"
+	common "cold-delivery/common/model"
+)
+
+type CoolerBoxGetPageReq struct {
+	dto.Pagination `search:"-"`
+	Name           string `form:"name" search:"type:contains;column:name;table:cooler_box"` // 保温箱
+	Sn             string `form:"sn" search:"type:contains;column:sn;table:cooler_box"`     // sn
+	CoolerBoxOrder
+}
+
+type CoolerBoxOrder struct {
+	CreatedAtOrder string `search:"type:order;column:created_at;table:cooler_box" form:"createdAtOrder" default:"desc"`
+}
+
+func (m *CoolerBoxGetPageReq) GetNeedSearch() interface{} {
+	return *m
+}
+
+type CoolerBoxInsertReq struct {
+	Id               int    `json:"id" comment:"编码" swaggerignore:"true"` // 编码
+	Name             string `json:"name"`                                 // 保温箱名称
+	Sn               string `json:"sn"`                                   // sn
+	Status           string `json:"status"`                               // 1-停用 2-正启用
+	common.ControlBy `swaggerignore:"true"`
+	common.DeptBy    `swaggerignore:"true"`
+}
+
+func (s *CoolerBoxInsertReq) Generate(model *model.CoolerBox) {
+	if s.Id != 0 {
+		model.Id = s.Id
+	}
+	model.Name = s.Name
+	model.Sn = s.Sn
+	model.Status = s.Status
+	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 *CoolerBoxInsertReq) GetId() interface{} {
+	return s.Id
+}
+
+type CoolerBoxUpdateReq struct {
+	Id               int    `json:"id" comment:"编码"` // 编码
+	Name             string `json:"Name"`            // 保温箱名称
+	Sn               string `json:"sn"`              // sn
+	Status           string `json:"status"`          // 1-停用 2-正启用
+	common.ControlBy `swaggerignore:"true"`
+}
+
+func (s *CoolerBoxUpdateReq) Generate(model *model.CoolerBox) {
+	if s.Id != 0 {
+		model.Id = s.Id
+	}
+	model.Name = s.Name
+	model.Sn = s.Sn
+	model.Status = s.Status
+	if s.ControlBy.UpdateBy != 0 {
+		model.UpdateBy = s.UpdateBy
+	}
+	if s.ControlBy.CreateBy != 0 {
+		model.CreateBy = s.CreateBy
+	}
+}
+
+func (s *CoolerBoxUpdateReq) GetId() interface{} {
+	return s.Id
+}
+
+type CoolerBoxGetReq struct {
+	Id int `uri:"id"`
+}
+
+func (s *CoolerBoxGetReq) GetId() interface{} {
+	return s.Id
+}
+
+type CoolerBoxDeleteReq struct {
+	Id               int `json:"id"`
+	common.ControlBy `swaggerignore:"true"`
+}
+
+func (s *CoolerBoxDeleteReq) GetId() interface{} {
+	return s.Id
+}
+
+type DeviceGetPageReq struct {
+	dto.Pagination `search:"-"`
+	Name           string `form:"name" search:"-"`
+}
+
+type CoolerBoxBatchInsertReq struct {
+	List             []CoolerBoxInsertReq
+	Status           string `json:"status"` // 1-停用 2-正启用
+	common.ControlBy `swaggerignore:"true"`
+	common.DeptBy    `swaggerignore:"true"`
+}

+ 192 - 0
app/admin/service/dto/customer.go

@@ -0,0 +1,192 @@
+package dto
+
+import (
+	"cold-delivery/app/admin/model"
+	dto2 "cold-delivery/common/dto"
+	model2 "cold-delivery/common/model"
+)
+
+type CustomerGetPageReq 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:"昵称"`
+	Type            int    `form:"type" search:"type:exact;column:type;table:sys_user" comment:"状态"`
+	CustomerOrder
+}
+type CustomerOrder 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 *CustomerGetPageReq) GetNeedSearch() interface{} {
+	return *m
+}
+
+type ResetCustomerPwdReq 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 *ResetCustomerPwdReq) GetId() interface{} {
+	return s.Id
+}
+
+func (s *ResetCustomerPwdReq) 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 UpdateCustomerStatusReq 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 *UpdateCustomerStatusReq) GetId() interface{} {
+	return s.Id
+}
+
+func (s *UpdateCustomerStatusReq) 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 CustomerInsertReq 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" vd:"@:len($)>0;msg:'姓名不能为空'"`                         // 姓名
+	Phone            string `json:"phone"`                                                     // 手机号
+	RoleId           int    `json:"roleId" example:"1" swaggerignore:"true"`                   // 角色id
+	DeptId           int    `json:"deptId" example:"1"`                                        // 机构id
+	Status           string `json:"status" example:"2" swaggerignore:"true"`                   // 状态 	// 货车司机绑定《道路运输从业人员从业资格证》信息
+	Type             int    `json:"type" example:"2"`                                          // 管理员1 仓管2 司机3
+	model2.ControlBy `swaggerignore:"true"`
+}
+
+// SetCreateBy 设置创建人id
+func (e *CustomerInsertReq) SetDeptId(deptId int) {
+	e.DeptId = deptId
+}
+
+func (s *CustomerInsertReq) 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.Status = "2"
+	userModel.Type = 0
+	userModel.UserType = model.UserTypeCustomer
+
+	if s.ControlBy.UpdateBy != 0 {
+		userModel.UpdateBy = s.UpdateBy
+	}
+	if s.ControlBy.CreateBy != 0 {
+		userModel.CreateBy = s.CreateBy
+	}
+}
+
+func (s *CustomerInsertReq) GetId() interface{} {
+	return s.Id
+}
+
+type CustomerUpdateReq struct {
+	Id               int    `json:"id"  comment:"用户ID"`                // 用户ID
+	Name             string `json:"name" vd:"@:len($)>0;msg:'姓名不能为空'"` // 姓名
+	Phone            string `json:"phone" swaggerignore:"true"`        // 手机号
+	model2.ControlBy `swaggerignore:"true"`
+}
+
+func (s *CustomerUpdateReq) Generate(userModel *model.SysUser) {
+	if s.Id != 0 {
+		userModel.Id = s.Id
+	}
+	userModel.NickName = s.Name
+	userModel.Phone = s.Phone
+	if s.ControlBy.UpdateBy != 0 {
+		userModel.UpdateBy = s.UpdateBy
+	}
+	if s.ControlBy.CreateBy != 0 {
+		userModel.CreateBy = s.CreateBy
+	}
+}
+
+func (s *CustomerUpdateReq) GetId() interface{} {
+	return s.Id
+}
+
+type CustomerGetReq struct {
+	Id int `uri:"id"`
+}
+
+func (s *CustomerGetReq) GetId() interface{} {
+	return s.Id
+}
+
+type CustomerDeleteReq struct {
+	Id               int `json:"id"`
+	model2.ControlBy `swaggerignore:"true"`
+}
+
+func (s *CustomerDeleteReq) GetId() interface{} {
+	return s.Id
+}
+
+type CustomerById struct {
+	dto2.ObjectById
+	model2.ControlBy `swaggerignore:"true"`
+}
+
+func (s *CustomerById) GetIds() interface{} {
+	return s.Ids
+}
+
+func (s *CustomerById) GetId() interface{} {
+	if len(s.Ids) > 0 {
+		s.Ids = append(s.Ids, s.Id)
+		return s.Ids
+	}
+	return s.Id
+}
+
+func (s *CustomerById) GenerateM() (model2.ActiveRecord, error) {
+	return &model.SysUser{}, nil
+}
+
+// PassWord 密码
+type CustomerPassWord struct {
+	NewPassword string `json:"newPassword" example:"123456" vd:"len($)>0"`   // 新密码
+	OldPassword string `json:"oldPassword" example:"12345678" vd:"len($)>0"` // 旧密码
+}
+
+type CustomerGetSMSVerifyCodeReq struct {
+	Phone string `form:"phone" example:"13912345678"` //手机号
+}
+
+type CustomerWxLoginReq struct {
+	Phone string `json:"phone"` // 手机号
+	Code  string `json:"code"`  // 密码
+}

+ 11 - 0
app/admin/service/dto/device.go

@@ -0,0 +1,11 @@
+package dto
+
+import "cold-delivery/common/dto"
+
+type DeviceGetDataReq struct {
+	dto.Pagination `search:"-"`
+	T_sn           string `form:"t_sn"`
+	T_id           int    `form:"t_id"`
+	StartTime      string `form:"startTime"`
+	EndTime        string `form:"endTime"`
+}

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

@@ -0,0 +1,58 @@
+package dto
+
+import (
+	"cold-delivery/common/dto"
+	common "cold-delivery/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-delivery/app/admin/model"
+	"cold-delivery/common/dto"
+	common "cold-delivery/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-delivery/common/dto"
+	common "cold-delivery/common/model"
+	"time"
+
+	"cold-delivery/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-delivery/app/admin/model"
+	"cold-delivery/common/dto"
+	common "cold-delivery/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"`
+}

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

@@ -0,0 +1,185 @@
+package dto
+
+import (
+	"cold-delivery/app/admin/model"
+	dto2 "cold-delivery/common/dto"
+	model2 "cold-delivery/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:"昵称"`
+	Type            int    `form:"type" search:"type:exact;column:type;table:sys_user" comment:"状态"`
+	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 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" vd:"@:len($)>0;msg:'姓名不能为空'"`                         // 姓名
+	Phone    string `json:"phone"`                                                     // 电话号码
+	RoleId   int    `json:"roleId" example:"1" swaggerignore:"true"`                   // 角色id
+	DeptId   int    `json:"deptId" example:"1"`                                        // 机构id
+	Status   string `json:"status" example:"2" swaggerignore:"true"`                   // 状态 	// 货车司机绑定《道路运输从业人员从业资格证》信息
+	//Type             int    `json:"type" example:"2"`                                          // 管理员1 仓管2 司机3
+	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"
+	userModel.Type = 1
+	userModel.UserType = model.UserTypeSys
+
+	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"  comment:"用户ID"`                // 用户ID
+	Name  string `json:"name" vd:"@:len($)>0;msg:'姓名不能为空'"` // 姓名
+	Phone string `json:"phone"`                             // 电话号码
+	//Type  int    `json:"type" example:"2"`                  // 管理员1 仓管2 司机3
+
+	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
+	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 SysUserPassWord 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"` //手机号
+}

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

@@ -0,0 +1,107 @@
+package dto
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/common/dto"
+	common "cold-delivery/common/model"
+)
+
+type WarehouseGetPageReq struct {
+	dto.Pagination `search:"-"`
+	//Name           string `form:"name" search:"type:contains;column:name;table:warehouse"` // 仓库名称
+	Name   string `form:"name" search:"-"`                                     // 仓库名称
+	Sn     string `form:"sn" search:"type:contains;column:sn;table:warehouse"` // sn
+	IsBind bool   `form:"isBind" search:"-"`                                   // 是否绑定司机
+	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"`                                 // 商品名称
+	Sn               string `json:"sn"`                                   // sn
+	Address          string `json:"address"`                              // 地址
+	Status           string `json:"status"`                               // 1-停用 2-正启用
+	UserId           int    `json:"userId"`                               // 绑定的用户id
+	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.Sn = s.Sn
+	model.Status = s.Status
+	model.Address = s.Address
+	model.UserId = s.UserId
+	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"`            // 商品名称
+	Sn               string `json:"sn"`              // sn
+	Address          string `json:"address"`         // 地址
+	Status           string `json:"status"`          // 1-停用 2-正启用
+	UserId           int    `json:"userId"`          // 绑定的用户id
+	common.ControlBy `swaggerignore:"true"`
+}
+
+func (s *WarehouseUpdateReq) Generate(model *model.Warehouse) {
+	if s.Id != 0 {
+		model.Id = s.Id
+	}
+	model.Name = s.Name
+	model.Sn = s.Sn
+	model.Address = s.Address
+	model.Status = s.Status
+	model.UserId = s.UserId
+	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
+}

+ 256 - 0
app/admin/service/dto/waybill.go

@@ -0,0 +1,256 @@
+package dto
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/common/dto"
+	common "cold-delivery/common/model"
+	model2 "cold-delivery/common/model"
+	"time"
+)
+
+// 运单
+
+type WaybillGetPageReq struct {
+	dto.Pagination `search:"-"`
+	WaybillNo      string `form:"waybillNo" search:"type:contains;column:waybill_no;table:waybill"` // 运单编号
+	Status         int    `form:"status" search:"type:exact;column:status;table:waybill"`           // 状态
+	OrderStartTime string `form:"orderStartTime" search:"type:gte;column:order_time;table:waybill"` // 下单开始时间
+	OrderEndTime   string `form:"orderEndTime" search:"type:lte;column:order_time;table:waybill"`   // 下单结束时间
+	WaybillOrder
+}
+
+type WaybillOrder struct {
+	CreatedAtOrder string `search:"type:order;column:created_at;table:waybill" form:"createdAtOrder" default:"desc"`
+}
+
+func (m *WaybillGetPageReq) GetNeedSearch() interface{} {
+	return *m
+}
+
+type WaybillGetCustomerPageReq struct {
+	dto.Pagination `search:"-"`
+	WaybillNo      string `form:"waybillNo" search:"type:contains;column:waybill_no;table:waybill"`                      // 运单编号
+	Status         int    `form:"status" search:"-"`                                                                     // 状态
+	OrderStartTime string `form:"orderStartTime" search:"type:gte;column:order_time;table:waybill"`                      // 下单开始时间
+	OrderEndTime   string `form:"orderEndTime" search:"type:lte;column:order_time;table:waybill"`                        // 下单结束时间
+	CustomerId     int    `form:"customerId" search:"type:exact;column:customer_id;table:waybill"  swaggerignore:"true"` // 客户id
+	WaybillOrder
+}
+
+func (m *WaybillGetCustomerPageReq) GetNeedSearch() interface{} {
+	return *m
+}
+
+type WaybillInsertReq struct {
+	Id                      int    `json:"id" comment:"编码" swaggerignore:"true"` // 编码
+	No                      string `json:"no" swaggerignore:"true"`              //单号
+	Status                  int    `json:"status" swaggerignore:"true"`          //订单状态:1-待处理;102-待装车 103-运输中 104-已签收
+	SenderAddressDetails    string `json:"senderAddressDetails"`                 //发货地址详情
+	SenderAddressName       string `json:"senderAddressName"`                    //发货地址名称
+	SenderAddressPhone      string `json:"senderAddressPhone"`                   //发货地址电话
+	ConsigneeAddressDetails string `json:"consigneeAddressDetails"`              //收发货地址详情
+	ConsigneeAddressName    string `json:"consigneeAddressName"`                 //收发货地址名称
+	ConsigneeAddressPhone   string `json:"consigneeAddressPhone"`                //收发货地址电话
+	Quantity                int    `json:"quantity"`                             //药品数量
+	Remark                  string `json:"remark"`                               //运输备注
+	TamperProofLabel        string `json:"tamperProofLabel"`                     //防拆码标签
+	CoolerBoxId             int    `json:"coolerBoxId"`                          //保温箱id
+	model2.ControlBy        `swaggerignore:"true"`
+	model2.DeptBy
+}
+
+func (s *WaybillInsertReq) Generate(m *model.Waybill) {
+	if s.Id != 0 {
+		m.Id = s.Id
+	}
+	m.Status = 1
+	m.SenderAddressDetails = s.SenderAddressDetails
+	m.SenderAddressName = s.SenderAddressName
+	m.SenderAddressPhone = s.SenderAddressPhone
+	m.ConsigneeAddressDetails = s.ConsigneeAddressDetails
+	m.ConsigneeAddressName = s.ConsigneeAddressName
+	m.ConsigneeAddressPhone = s.ConsigneeAddressPhone
+	m.Quantity = s.Quantity
+	m.Remark = s.Remark
+	m.TamperProofLabel = s.TamperProofLabel
+	m.CoolerBoxId = s.CoolerBoxId
+	m.OrderTime = model2.Time(time.Now())
+
+	if s.ControlBy.UpdateBy != 0 {
+		m.UpdateBy = s.UpdateBy
+	}
+	if s.ControlBy.CreateBy != 0 {
+		m.CreateBy = s.CreateBy
+	}
+	if s.DeptBy.DeptId != 0 {
+		m.DeptId = s.DeptId
+	}
+}
+
+func (s *WaybillInsertReq) GetId() interface{} {
+	return s.Id
+}
+
+type WaybillUpdateReq struct {
+	Id                      int    `json:"id" comment:"编码" swaggerignore:"true"` // 编码
+	SenderAddressDetails    string `json:"senderAddressDetails"`                 //发货地址详情
+	SenderAddressName       string `json:"senderAddressName"`                    //发货地址名称
+	SenderAddressPhone      string `json:"senderAddressPhone"`                   //发货地址电话
+	ConsigneeAddressDetails string `json:"consigneeAddressDetails"`              //收发货地址详情
+	ConsigneeAddressName    string `json:"consigneeAddressName"`                 //收发货地址名称
+	ConsigneeAddressPhone   string `json:"consigneeAddressPhone"`                //收发货地址电话
+	TamperProofLabel        string `json:"tamperProofLabel"`                     //防拆标签
+	DeliveryCondition       string `json:"deliveryCondition"`                    //配送要求
+	Quantity                int    `json:"quantity"`                             //药品数量
+	Remark                  string `json:"remark"`                               //运输备注
+	CoolerBoxId             int    `json:"coolerBoxId"`                          //保温箱id
+	model2.ControlBy        `swaggerignore:"true"`
+	model2.DeptBy           `swaggerignore:"true"`
+}
+
+func (s *WaybillUpdateReq) Generate(m *model.Waybill) {
+	if s.Id != 0 {
+		m.Id = s.Id
+	}
+	m.SenderAddressDetails = s.SenderAddressDetails
+	m.SenderAddressName = s.SenderAddressName
+	m.SenderAddressPhone = s.SenderAddressPhone
+	m.ConsigneeAddressDetails = s.ConsigneeAddressDetails
+	m.ConsigneeAddressName = s.ConsigneeAddressName
+	m.ConsigneeAddressPhone = s.ConsigneeAddressPhone
+	m.Quantity = s.Quantity
+	m.Remark = s.Remark
+	m.TamperProofLabel = s.TamperProofLabel
+	if s.CoolerBoxId > 0 {
+		m.CoolerBoxId = s.CoolerBoxId
+	}
+
+	if s.ControlBy.UpdateBy != 0 {
+		m.UpdateBy = s.UpdateBy
+	}
+	if s.ControlBy.CreateBy != 0 {
+		m.CreateBy = s.CreateBy
+	}
+}
+
+func (s *WaybillUpdateReq) GetId() interface{} {
+	return s.Id
+}
+
+type WaybillUpdateStatusReq struct {
+	Id               int `json:"id" comment:"编码" swaggerignore:"true"` // 编码
+	Status           int `json:"status"`                               //药品数量
+	model2.ControlBy `swaggerignore:"true"`
+	model2.DeptBy    `swaggerignore:"true"`
+}
+
+func (s *WaybillUpdateStatusReq) Generate(m *model.Waybill) {
+	if s.Id != 0 {
+		m.Id = s.Id
+	}
+	m.Status = s.Status
+
+	if s.ControlBy.UpdateBy != 0 {
+		m.UpdateBy = s.UpdateBy
+	}
+	if s.ControlBy.CreateBy != 0 {
+		m.CreateBy = s.CreateBy
+	}
+}
+
+func (s *WaybillUpdateStatusReq) GetId() interface{} {
+	return s.Id
+}
+
+type WaybillDeliveryReq struct {
+	WaybillIds       []int `json:"waybillIds"`  // 运单id
+	CoolerBoxId      int   `json:"coolerBoxId"` // 保温箱id
+	model2.ControlBy `swaggerignore:"true"`
+	model2.DeptBy    `swaggerignore:"true"`
+}
+
+func (s *WaybillDeliveryReq) GetId() interface{} {
+	return s.WaybillIds
+}
+
+type WaybillGetReq struct {
+	Id int `uri:"id"`
+}
+
+func (s *WaybillGetReq) GetId() interface{} {
+	return s.Id
+}
+
+type WaybillDeleteReq struct {
+	Id               int `json:"id"`
+	common.ControlBy `swaggerignore:"true"`
+}
+
+func (s *WaybillDeleteReq) GetId() interface{} {
+	return s.Id
+}
+
+// 运单出入库/上下车
+type WaybillInOutReq struct {
+	StartTime     model2.Time `json:"startTime"`
+	WaybillNoList []string    `json:"waybillNoList"  gorm:"size:128"` // 订单编号
+}
+
+// 运单签收
+type WaybillReceiptReq struct {
+	Status          int    `json:"status"`                      // 3 已签收 5 已拒收
+	RejectionReason string `json:"rejectionReason"`             // 拒收原因
+	WaybillNo       string `json:"waybillNo"  gorm:"size:128"`  // 订单编号
+	ReceiptImg      string `json:"receiptImg"  gorm:"size:128"` // 签收图片
+}
+
+type WaybillGetAppletPageReq struct {
+	dto.Pagination `search:"-"`
+	WaybillNo      string `form:"waybillNo" search:"type:contains;column:waybill_no;table:waybill_logistics"` // 运单编号
+	Status         int    `form:"status" search:"type:exact;column:status;table:waybill_logistics"`           // 状态
+	WaybillOrder
+}
+
+type WaybillGetAppletPageOrder struct {
+	CreatedAtOrder string `search:"type:order;column:created_at;table:waybill_logistics" form:"createdAtOrder" default:"desc"`
+}
+
+func (m *WaybillGetAppletPageReq) GetNeedSearch() interface{} {
+	return *m
+}
+
+type WaybillImportReq struct {
+	CustomerName string `form:"customerName"` //下单客户名称
+}
+
+type WaybillStatsReq struct {
+	Date string `form:"date"` // 日期
+	Type string `form:"type"` // 类型 month-月 year-年
+}
+
+type WaybillStatsRes struct {
+	TodayNum        int64 `json:"todayNum"`        // 今日总运单数
+	WaitDeliveryNum int64 `json:"waitDeliveryNum"` // 已下单
+	ReceiptNum      int64 `json:"receiptNum"`      // 已签收
+	RejectionNum    int64 `json:"rejectionNum"`    // 已拒收
+	InDeliveryNum   int64 `json:"inDeliveryNum"`   // 运送中
+	ThisMonthNum    int64 `json:"thisMonthNum"`    // 本月运单数
+	LastMonthNum    int64 `json:"lastMonthNum"`    // 上月运单数
+	ThisYearNum     int64 `json:"thisYearNum"`     // 本年运单数
+	LastYearNum     int64 `json:"lastYearNum"`     // 上年运单数
+
+	Stats []struct {
+		Date string `json:"date"` // 日期 2024-01-01
+		Num  int64  `json:"num"`  // 数量
+	} `json:"stats"`
+}
+
+type WaybillGetByWaybillNoReq struct {
+	WaybillNo string `form:"waybillNo" vd:"len($)>0;msg:'订单编号不能为空'"` // 运单编号-必填
+}
+
+type WaybillGetByWaybillPdfReq struct {
+	WaybillNo    string `form:"waybillNo" vd:"len($)>0;msg:'订单编号不能为空'"` // 运单编号-必填
+	HumidityShow bool   `form:"humidityShow" vd:""`                     // 湿度显示
+	//TemplateShow bool   `form:"templateShow" vd:""`                     // 湿度显示
+}

+ 17 - 0
app/admin/service/dto/waybill_logistics.go

@@ -0,0 +1,17 @@
+package dto
+
+// 运单
+
+type WaybillLogisticsGetPageReq struct {
+	WaybillNo string `form:"waybillNo" search:"type:contains;column:waybill_no;table:waybill_logistics" vd:"len($)>0;msg:'订单编号不能为空'"` // 运单编号-必填
+	Status    int    `form:"status" search:"type:exact;column:status;table:waybill_logistics"`                                        // 状态
+	WaybillLogisticsOrder
+}
+
+type WaybillLogisticsOrder struct {
+	IdOrder        string `search:"type:order;column:id;table:waybill_logistics" form:"idOrder" default:"desc"`
+}
+
+func (m *WaybillLogisticsGetPageReq) GetNeedSearch() interface{} {
+	return *m
+}

+ 46 - 0
app/admin/service/dto/waybill_task.go

@@ -0,0 +1,46 @@
+package dto
+
+import "cold-delivery/common/dto"
+
+// 运单
+
+type WaybillTaskGetPageReq struct {
+	//dto.Pagination `search:"-"`
+	WaybillNo string `form:"waybillNo" search:"type:contains;column:waybill_no;table:waybill_task" vd:"len($)>0;msg:'订单编号不能为空'"` // 运单编号-必填
+	WaybillTaskOrder
+}
+
+type WaybillTaskOrder struct {
+	CreatedAtOrder string `search:"type:order;column:created_at;table:waybill_task" form:"createdAtOrder" default:"asc"`
+}
+
+func (m *WaybillTaskGetPageReq) GetNeedSearch() interface{} {
+	return *m
+}
+
+type WaybillTaskGetDataPageReq struct {
+	dto.Pagination `search:"-"`
+	WaybillNo      string `form:"waybillNo" vd:"len($)>0;msg:'订单编号不能为空'"` // 运单编号-必填
+	TaskId         int    `form:"taskId"`
+	T_ids          []int  `form:"t_ids"`
+	StartTime      string `form:"startTime"`
+	EndTime        string `form:"endTime"`
+}
+
+func (m *WaybillTaskGetDataPageReq) GetNeedSearch() interface{} {
+	return *m
+}
+
+// 获取运单轨迹
+type WaybillGetLocusReq struct {
+	WaybillNo      string `form:"waybillNo" search:"type:contains;column:waybill_no;table:waybill_task" vd:"len($)>0;msg:'订单编号不能为空'"` // 运单编号-必填
+	CreatedAtOrder string `search:"type:order;column:created_at;table:waybill_task" form:"createdAtOrder" default:"asc"`
+}
+
+func (m *WaybillGetLocusReq) GetNeedSearch() interface{} {
+	return *m
+}
+
+type WaybillTaskGetNewestDataPageReq struct {
+	WaybillNo string `form:"waybillNo" vd:"len($)>0;msg:'订单编号不能为空'"` // 运单编号-必填
+}

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

@@ -0,0 +1,72 @@
+package service
+
+import (
+	"cold-delivery/common/actions"
+	cDto "cold-delivery/common/dto"
+	"cold-delivery/common/global"
+	"errors"
+	"gogs.baozhida.cn/zoie/OAuth-core/service"
+
+	"gorm.io/gorm"
+
+	"cold-delivery/app/admin/model"
+	"cold-delivery/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-delivery/common/actions"
+	dto2 "cold-delivery/common/dto"
+	"cold-delivery/common/global"
+	cModel "cold-delivery/common/model"
+	"encoding/json"
+	"fmt"
+	"gogs.baozhida.cn/zoie/OAuth-core/service"
+	"strings"
+
+	"github.com/pkg/errors"
+	"gorm.io/gorm"
+
+	"cold-delivery/app/admin/model"
+	"cold-delivery/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-delivery/common/actions"
+	cDto "cold-delivery/common/dto"
+	"cold-delivery/common/global"
+	"errors"
+	"gogs.baozhida.cn/zoie/OAuth-core/service"
+	"gorm.io/gorm"
+
+	"cold-delivery/app/admin/model"
+	"cold-delivery/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-delivery/common/actions"
+	cDto "cold-delivery/common/dto"
+	"cold-delivery/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-delivery/app/admin/model"
+	"cold-delivery/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
+}

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

@@ -0,0 +1,348 @@
+package service
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/app/admin/service/dto"
+	"cold-delivery/common/actions"
+	cDto "cold-delivery/common/dto"
+	"cold-delivery/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 p.DeptId == 0 {
+		err = e.Orm.
+			Scopes(
+				cDto.MakeCondition(c.GetNeedSearch()),
+				cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
+			).Where("create_by = ?", p.UserId).
+			Where("user_type = ?", model.UserTypeSys).
+			Preload("Dept").
+			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),
+			).
+			Where("user_type = ?", model.UserTypeSys).
+			Preload("Dept").
+			Find(&userList).Limit(-1).Offset(-1).
+			Count(count).Error
+	}
+
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+	*list = userList
+	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)).
+		Preload("Dept").
+		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
+}
+
+// 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 dept model.SysDept
+	var deptCount int64
+	err = e.Orm.Model(&dept).Where("id = ?", c.DeptId).Count(&deptCount).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.CreateFailedErr
+	}
+	if deptCount == 0 {
+		err = errors.New("公司不存在!")
+		e.Log.Errorf("db error: %s", err)
+		return err
+	}
+
+	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
+	}
+
+	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
+	}
+
+	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 p.UserId != 1 {
+		if data.CreateBy == 1 && data.Type == 1 {
+			return errors.New("禁止删除管理员")
+		}
+	}
+
+	if err = db.Error; err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return err
+	}
+	if db.RowsAffected == 0 {
+		return global.DeleteNotFoundOrNoPermissionErr
+	}
+
+	var car model.Car
+	var j int64
+	err = e.Orm.Model(&car).Where("user_id = ?", c.GetId()).Count(&j).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.CreateFailedErr
+	}
+	if j > 0 {
+		err = errors.New("该用户已绑定车辆,禁止删除!")
+		e.Log.Errorf("db error: %s", err)
+		return err
+	}
+
+	var warehouse model.Warehouse
+	var k int64
+	err = e.Orm.Model(&warehouse).Where("user_id = ?", c.GetId()).Count(&k).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.CreateFailedErr
+	}
+	if k > 0 {
+		err = errors.New("该用户已绑定仓库,禁止删除!")
+		e.Log.Errorf("db error: %s", err)
+		return err
+	}
+
+	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.Preload("Dept").First(user, c.GetId()).Error
+	if err != nil {
+		return err
+	}
+
+	return nil
+}

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

@@ -0,0 +1,278 @@
+package service
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/app/admin/service/dto"
+	"cold-delivery/common/actions"
+	cDto "cold-delivery/common/dto"
+	"cold-delivery/common/global"
+	"errors"
+	"gogs.baozhida.cn/zoie/OAuth-core/service"
+	"gorm.io/gorm"
+)
+
+type Warehouse struct {
+	service.Service
+}
+
+func WarehouseIsBindUserScopes(isBind bool) func(db *gorm.DB) *gorm.DB {
+	return func(db *gorm.DB) *gorm.DB {
+		// 未发货
+		if isBind {
+			return db.Where("user_id > 0")
+		}
+		return db
+	}
+}
+
+// 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),
+			WarehouseIsBindUserScopes(c.IsBind),
+		).
+		Joins("User").
+		Where("name like ? or User.nick_name like ?", "%"+c.Name+"%", "%"+c.Name+"%").
+		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, warehouseModel *model.Warehouse, p *actions.DataPermission) error {
+	err := e.Orm.
+		Scopes(actions.Permission(warehouseModel.TableName(), p)).
+		Preload("User").
+		First(warehouseModel, 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()
+		}
+	}()
+
+	var i int64
+	err = tx.Model(&data).Where("name = ? and dept_id = ?", c.Name, c.DeptId).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
+	}
+	var j int64
+	err = tx.Model(&data).Where("user_id = ?", c.UserId).Count(&j).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.CreateFailedErr
+	}
+	if j > 0 {
+		err = errors.New("该用户已绑定其他仓库!")
+		e.Log.Errorf("db error: %s", err)
+		return err
+	}
+
+	var k int64
+	err = tx.Model(&data).Where("sn = ?", c.Sn).Count(&k).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.CreateFailedErr
+	}
+	if k > 0 {
+		err = errors.New("该Sn已绑定其他仓库!")
+		e.Log.Errorf("db error: %s", err)
+		return err
+	}
+
+	// 添加仓库
+	c.Generate(&data)
+	data.HistorySn = []string{c.Sn}
+	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 warehouseModel = model.Warehouse{}
+	// 查询仓库是否存在
+	err = e.Orm.Scopes(actions.Permission(warehouseModel.TableName(), p)).
+		First(&warehouseModel, 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 warehouseModel.Sn != c.Sn {
+		var k int64
+		var data = model.Warehouse{}
+		err = tx.Model(&data).Where("sn = ?", c.Sn).Count(&k).Error
+		if err != nil {
+			e.Log.Errorf("db error: %s", err)
+			return global.CreateFailedErr
+		}
+		if k > 0 {
+			err = errors.New("该Sn已绑定其他仓库!")
+			e.Log.Errorf("db error: %s", err)
+			return err
+		}
+		warehouseModel.HistorySn = append(warehouseModel.HistorySn, c.Sn)
+	}
+
+	if warehouseModel.UserId != c.UserId {
+		var k int64
+		var data = model.Warehouse{}
+		err = tx.Model(&data).Where("user_id = ?", c.UserId).Count(&k).Error
+		if err != nil {
+			e.Log.Errorf("db error: %s", err)
+			return global.CreateFailedErr
+		}
+		if k > 0 {
+			err = errors.New("该用户绑定其他仓库!")
+			e.Log.Errorf("db error: %s", err)
+			return err
+		}
+	}
+
+	c.Generate(&warehouseModel)
+	err = tx.Save(&warehouseModel).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.UpdateFailedErr
+	}
+
+	c.Id = warehouseModel.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 warehouseModel model.Warehouse
+
+	// 查询仓库是否存在
+	err = e.Orm.Scopes(actions.Permission(warehouseModel.TableName(), p)).
+		First(&warehouseModel, 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(&warehouseModel)
+
+	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
+}
+
+// GetUserList 获取绑定车辆的用户
+func (e *Warehouse) GetUserList(c *dto.SysUserGetPageReq, p *actions.DataPermission, list *[]model.SysUserForBind, count *int64) error {
+	var err error
+	var userList []model.SysUserForBind
+
+	var warehouseModel model.Warehouse
+	var userModel model.SysUserForBind
+	var userIds []int
+	// 查询仓库是否存在
+	err = e.Orm.Model(&warehouseModel).Select("user_id").Scopes(actions.Permission(warehouseModel.TableName(), p)).
+		Find(&userIds).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+
+	err = e.Orm.
+		Scopes(
+			cDto.MakeCondition(c.GetNeedSearch()),
+			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
+			actions.UserPermission(userModel.TableName(), p),
+		).
+		Where("user_type = ? ", model.UserTypeSys).
+		Find(&userList).Limit(-1).Offset(-1).
+		Count(count).Error
+
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+	userIdMap := make(map[int]bool)
+	for _, id := range userIds {
+		userIdMap[id] = true
+	}
+
+	for i := 0; i < len(userList); i++ {
+		if _, ok := userIdMap[userList[i].Id]; ok {
+			userList[i].IsBind = true
+		}
+	}
+
+	*list = userList
+	return nil
+}

+ 915 - 0
app/admin/service/waybill.go

@@ -0,0 +1,915 @@
+package service
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/app/admin/service/dto"
+	"cold-delivery/common/actions"
+	cDto "cold-delivery/common/dto"
+	"cold-delivery/common/global"
+	"cold-delivery/common/lib"
+	model2 "cold-delivery/common/model"
+	"cold-delivery/common/nats/nats_server"
+	"cold-delivery/conf"
+	"errors"
+	"fmt"
+	"go.uber.org/zap"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/sms"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/utils"
+	"gogs.baozhida.cn/zoie/OAuth-core/service"
+	"gorm.io/gorm"
+	"sort"
+	"strconv"
+	"strings"
+	"time"
+)
+
+type Waybill struct {
+	service.Service
+}
+
+// GetPage 获取Waybill列表
+func (e *Waybill) GetPage(c *dto.WaybillGetPageReq, list *[]model.Waybill, count *int64, p *actions.DataPermission) error {
+	var err error
+	var data model.Waybill
+	if c.PageSize == 9999 {
+		err = e.Orm.Model(&data).
+			Scopes(
+				cDto.MakeCondition(c.GetNeedSearch()),
+				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
+	}
+
+	err = e.Orm.Model(&data).
+		Scopes(
+			cDto.MakeCondition(c.GetNeedSearch()),
+			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
+			actions.Permission(data.TableName(), p),
+		).
+		Preload("CoolerBox").
+		Find(list).Limit(-1).Offset(-1).
+		Count(count).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+	return nil
+}
+func (e *Waybill) GetAppletPage(c *dto.WaybillGetAppletPageReq, list *[]model.Waybill, count *int64, p *actions.DataPermission) error {
+	var err error
+	//var data model.Waybill
+	var logistics model.WaybillLogistics
+	err = e.Orm.Table("waybill").
+		Select("waybill.*,waybill_logistics.status as status").
+		Scopes(
+			cDto.MakeCondition(c.GetNeedSearch()),
+			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
+			actions.Permission(logistics.TableName(), p)).
+		Where("waybill_logistics.id in (SELECT MAX(id) FROM waybill_logistics where user_id = ? group by waybill_no )", p.UserId).
+		Joins("left join waybill_logistics on waybill.waybill_no = waybill_logistics.waybill_no").
+		Find(&list).Limit(-1).Offset(-1).Count(count).Error
+
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+	return nil
+}
+
+func (e *Waybill) GetAppletCount(list *[]model.Waybill, count *int64, p *actions.DataPermission) error {
+	var err error
+	//var data model.Waybill
+	var logistics model.WaybillLogistics
+	err = e.Orm.Table("waybill").
+		Select("waybill.*,waybill_logistics.status as status").
+		Scopes(
+			actions.Permission(logistics.TableName(), p)).
+		Where("waybill_logistics.id in (SELECT MAX(id) FROM waybill_logistics where user_id = ? group by waybill_no )", p.UserId).
+		Joins("left join waybill_logistics on waybill.waybill_no = waybill_logistics.waybill_no").
+		Find(list).Count(count).Error
+
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+	return nil
+}
+
+func (e *Waybill) GetCustomerPage(c *dto.WaybillGetCustomerPageReq, list *[]model.Waybill, count *int64, p *actions.DataPermission) error {
+	var err error
+	var data model.Waybill
+
+	if c.PageSize == 9999 {
+		err = e.Orm.Model(&data).
+			Scopes(
+				cDto.MakeCondition(c.GetNeedSearch()),
+				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
+	}
+
+	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 获取Waybill对象
+func (e *Waybill) Get(d *dto.WaybillGetReq, waybillModel *model.Waybill, p *actions.DataPermission) error {
+	err := e.Orm.
+		Scopes(actions.Permission(waybillModel.TableName(), p)).
+		Preload("User").
+		First(waybillModel, 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
+}
+func (e *Waybill) GetByWaybillNo(d *dto.WaybillGetByWaybillPdfReq, waybillModel *model.Waybill, p *actions.DataPermission) error {
+	err := e.Orm.
+		Scopes(actions.Permission(waybillModel.TableName(), p)).
+		Where("waybill_no = ?", d.WaybillNo).
+		Preload("Dept").
+		First(waybillModel).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 创建Waybill对象
+func (e *Waybill) Insert(c *dto.WaybillInsertReq) error {
+	var err error
+	var data model.Waybill
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	var no string
+	for {
+		no = time.Now().Format("200601021504") + utils.GetRandString(6, "0123456789", 0)
+		var j int64
+		err = e.Orm.Model(&data).Where("waybill_no = ?", no).Count(&j).Error
+		if err != nil {
+			continue
+		}
+		if j == 0 {
+			break
+		}
+	}
+
+	// 添加运单
+	data.WaybillNo = no
+	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
+
+}
+
+// AppletInsert 员工添加运单
+func (e *Waybill) AppletInsert(c *dto.WaybillInsertReq, p *actions.DataPermission) error {
+	var err error
+	var data model.Waybill
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	var userModel = model.SysUser{}
+	// 查询运单是否存在
+	err = tx.Scopes(actions.Permission(userModel.TableName(), p)).
+		First(&userModel, p.UserId).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return global.GetNotFoundErr
+		}
+		return global.CreateFailedErr
+	}
+	if (userModel.Type != model.SysUserTypeDriver && userModel.Type != model.SysUserTypeWarehouse) && userModel.UserType != "customer" {
+		err = errors.New("无权添加!")
+		return err
+	}
+	var status = model.WaybillStatusWaitDelivery
+	var coolerBox = model.CoolerBox{}
+	// 查询保温箱信息
+	err = tx.Scopes(actions.Permission(coolerBox.TableName(), p)).
+		First(&coolerBox, c.CoolerBoxId).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return errors.New("获取车辆信息失败")
+	}
+
+	var no string
+	for {
+		no = time.Now().Format("200601021504") + utils.GetRandString(6, "0123456789", 0)
+		var j int64
+		err = e.Orm.Model(&data).Where("waybill_no = ?", no).Count(&j).Error
+		if err != nil {
+			continue
+		}
+		if j == 0 {
+			break
+		}
+	}
+
+	// 添加运单
+	data.DeptId = p.DeptId
+	data.CreateBy = p.UserId
+	data.WaybillNo = no
+	c.Generate(&data)
+	data.Status = status
+	err = tx.Create(&data).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.CreateFailedErr
+	}
+	c.Id = data.Id
+
+	// 添加物流
+	Logistics := model.WaybillLogistics{
+		WaybillNo:   data.WaybillNo,
+		Status:      data.Status,
+		CoolerBoxId: coolerBox.Id,
+		UserId:      p.UserId,
+		ControlBy: model2.ControlBy{
+			CreateBy: p.UserId,
+		},
+		DeptBy: model2.DeptBy{
+			DeptId: p.DeptId,
+		},
+	}
+	err = tx.Create(&Logistics).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return errors.New(fmt.Sprintf("保存运单物流信息失败:%s", err))
+	}
+
+	return nil
+
+}
+
+// Update 修改Waybill对象
+func (e *Waybill) Update(c *dto.WaybillUpdateReq, p *actions.DataPermission) error {
+	var err error
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	var waybillModel = model.Waybill{}
+	// 查询运单是否存在
+	err = e.Orm.Scopes(actions.Permission(waybillModel.TableName(), p)).
+		First(&waybillModel, 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(&waybillModel)
+	err = tx.Save(&waybillModel).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.UpdateFailedErr
+	}
+
+	c.Id = waybillModel.Id
+	return nil
+}
+func (e *Waybill) UpdateStatus(c *dto.WaybillUpdateStatusReq, p *actions.DataPermission) error {
+	var err error
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	var waybillModel = model.Waybill{}
+	// 查询运单是否存在
+	err = e.Orm.Scopes(actions.Permission(waybillModel.TableName(), p)).
+		First(&waybillModel, 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(&waybillModel)
+	err = tx.Save(&waybillModel).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.UpdateFailedErr
+	}
+
+	c.Id = waybillModel.Id
+	return nil
+}
+func (e *Waybill) Delivery(c *dto.WaybillDeliveryReq, p *actions.DataPermission) error {
+	var err error
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	var coolerBox = model.CoolerBox{}
+	// 查询保温箱信息
+	err = tx.Scopes(actions.Permission(coolerBox.TableName(), p)).
+		First(&coolerBox, c.CoolerBoxId).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return errors.New("获取保温箱信息失败")
+	}
+
+	for _, id := range c.WaybillIds {
+
+		var waybillModel = model.Waybill{}
+		// 查询运单是否存在
+		err = tx.Scopes(actions.Permission(waybillModel.TableName(), p)).
+			First(&waybillModel, id).Error
+		if err != nil {
+			e.Log.Errorf("db error: %s", err)
+			if errors.Is(err, gorm.ErrRecordNotFound) {
+				return global.UpdateNotFoundOrNoPermissionErr
+			}
+			return global.UpdateFailedErr
+		}
+		if waybillModel.Status == model.WaybillStatusWaitDelivery || (waybillModel.Status == model.WaybillStatusInDelivery && waybillModel.CoolerBoxId != c.CoolerBoxId) {
+			waybillModel.Status = model.WaybillStatusInDelivery
+			waybillModel.CoolerBoxId = c.CoolerBoxId
+			waybillModel.DeliveryTime = model2.Time(time.Now())
+			err = tx.Save(&waybillModel).Error
+			if err != nil {
+				e.Log.Errorf("db error: %s", err)
+				return global.UpdateFailedErr
+			}
+
+			// 查询任务
+			var logistics model.WaybillLogistics
+			err = tx.Model(&logistics).Where("waybill_no = ? and status = ?", waybillModel.WaybillNo, model.WaybillStatusInDelivery).
+				Last(&logistics).Error
+			if err != nil {
+				if errors.Is(err, gorm.ErrRecordNotFound) {
+					// 添加物流
+					logisticsObj := model.WaybillLogistics{
+						WaybillNo:   waybillModel.WaybillNo,
+						Status:      waybillModel.Status,
+						CoolerBoxId: coolerBox.Id,
+						ControlBy: model2.ControlBy{
+							CreateBy: p.UserId,
+						},
+						DeptBy: model2.DeptBy{
+							DeptId: p.DeptId,
+						},
+					}
+					err = tx.Create(&logisticsObj).Error
+					if err != nil {
+						e.Log.Errorf("db error: %s", err)
+						return errors.New(fmt.Sprintf("保存运单物流信息失败:%s", err))
+					}
+				} else {
+					e.Log.Errorf("db error: %s", err)
+					return errors.New(fmt.Sprintf("保存运单物流信息失败:%s", err))
+				}
+			}
+			logistics.CoolerBoxId = coolerBox.Id
+			err = tx.Save(&logistics).Error
+			if err != nil {
+				e.Log.Errorf("db error: %s", err)
+				return errors.New(fmt.Sprintf("保存运单物流信息失败:%s", err))
+			}
+
+			// 查询任务
+			var task model.WaybillTask
+			err = tx.Model(&task).Where("waybill_no = ? ", waybillModel.WaybillNo).
+				Last(&task).Error
+			if err != nil {
+				if errors.Is(err, gorm.ErrRecordNotFound) {
+					// 添加任务
+					taskObj := model.WaybillTask{
+						WaybillNo:   waybillModel.WaybillNo,
+						CoolerBoxId: coolerBox.Id,
+						UserId:      p.UserId,
+						Sn:          coolerBox.Sn,
+						StartTime:   model2.Time(time.Now()),
+						ControlBy: model2.ControlBy{
+							CreateBy: p.UserId,
+						},
+						DeptBy: model2.DeptBy{
+							DeptId: p.DeptId,
+						},
+					}
+					err = tx.Create(&taskObj).Error
+					if err != nil {
+						e.Log.Errorf("db error: %s", err)
+						return errors.New(fmt.Sprintf("保存运单任务信息失败:%s", err))
+					}
+				} else {
+					e.Log.Errorf("db error: %s", err)
+					return errors.New(fmt.Sprintf("查询运单任务信息失败:%s", err))
+				}
+			}
+
+			task.StartTime = model2.Time(time.Now())
+			task.UpdateBy = p.UserId
+			task.CoolerBoxId = coolerBox.Id
+			task.Sn = coolerBox.Sn
+			err = tx.Save(&task).Error
+			if err != nil {
+				e.Log.Errorf("db error: %s", err)
+				return errors.New(fmt.Sprintf("保存运单任务信息失败:%s", err))
+			}
+
+			//if logistics.Id == 0 {
+			//	ss := sms.NewSMS(conf.ExtConfig.SubMail.Appid, conf.ExtConfig.SubMail.Signature)
+			//	res, err1 := ss.SmsXSend(waybillModel.ConsigneeAddressPhone, lib.AesEncryptCBC(waybillModel.WaybillNo, lib.AesKey))
+			//	if err1 != nil || res.Status != sms.SUCCESS {
+			//		e.Log.Errorf("发送短信验证码出现异常", zap.Any("res", res), zap.Error(err1))
+			//		err = errors.New("验证吗发送失败,请重试")
+			//		return err
+			//	}
+			//}
+			ss := sms.NewSMS(conf.ExtConfig.SubMail.Appid, conf.ExtConfig.SubMail.Signature)
+			addr := conf.ExtConfig.Applet.WaybillUrl + lib.AesEncryptCBC(waybillModel.WaybillNo, lib.AesKey)
+			res, err1 := ss.SmsXSend(waybillModel.ConsigneeAddressPhone, addr)
+			if err1 != nil || res.Status != sms.SUCCESS {
+				e.Log.Errorf("发送短信验证码出现异常", zap.Any("res", res), zap.Error(err1))
+				err = errors.New("验证吗发送失败,请重试")
+				return err
+			}
+			waybillModel.SendLog = model.WaybillSendLog{
+				Phone:   waybillModel.ConsigneeAddressPhone,
+				Content: "【冷链送药平台】您的订单正在派送中,点击查看详情:" + addr,
+			}
+		}
+
+	}
+
+	return nil
+}
+
+// Remove 删除Waybill
+func (e *Waybill) Remove(c *dto.WaybillDeleteReq, p *actions.DataPermission) error {
+	var err error
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	var waybillModel model.Waybill
+
+	// 查询运单是否存在
+	err = e.Orm.Scopes(actions.Permission(waybillModel.TableName(), p)).
+		First(&waybillModel, 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
+	}
+	if waybillModel.Status != model.WaybillStatusWaitDelivery {
+		return errors.New(fmt.Sprintf("运单状态为%s,禁止删除", model.WaybillStatusMap[waybillModel.Status]))
+	}
+
+	db := tx.Delete(&waybillModel)
+
+	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
+}
+
+func (e *Waybill) Receipt(c *dto.WaybillReceiptReq, p *actions.DataPermission) error {
+	var err error
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	var waybillModel = model.Waybill{}
+	// 查询运单是否存在
+	err = tx.Scopes(actions.Permission(waybillModel.TableName(), p)).
+		Where("waybill_no = ?", c.WaybillNo).
+		First(&waybillModel).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			return errors.New(fmt.Sprintf("运单号%s不存在", c.WaybillNo))
+		}
+		return errors.New(fmt.Sprintf("运单号%s查询失败", c.WaybillNo))
+	}
+
+	// 查询保温箱信息
+	var coolerBox = model.CoolerBox{}
+	err = tx.Scopes(actions.Permission(coolerBox.TableName(), p)).
+		First(&coolerBox, waybillModel.CoolerBoxId).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return errors.New("获取保温箱信息失败")
+	}
+	if waybillModel.Status == model.WaybillStatusWaitDelivery {
+		err = errors.New(fmt.Sprintf("运单状态为%s,禁止操作", model.WaybillStatusMap[waybillModel.Status]))
+		return err
+	}
+
+	if waybillModel.Status == model.WaybillStatusReceipt || waybillModel.Status == model.WaybillStatusRejection {
+		return nil
+	}
+	waybillModel.Status = c.Status
+	waybillModel.RejectionReason = c.RejectionReason
+	waybillModel.ReceiptTime = model2.Time(time.Now())
+	waybillModel.ReceiptImg = c.ReceiptImg
+	err = tx.Save(&waybillModel).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return errors.New(fmt.Sprintf("保存运单信息失败:%s", err))
+	}
+
+	var lng, lat string
+	lng, lat, err = e.GetSite(p.DeptId, coolerBox.Sn, waybillModel.ReceiptTime.String())
+	if err != nil {
+		e.Log.Errorf("获取定位信息失败: %s", err)
+		return err
+	}
+
+	// 查询任务
+	var task model.WaybillTask
+	err = tx.Model(&task).Where("waybill_no = ? and cooler_box_id = ?", c.WaybillNo, coolerBox.Id).
+		Last(&task).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return errors.New(fmt.Sprintf("查询运单任务信息失败:%s", err))
+	}
+	// 未下车 直接点签收
+	if time.Time(task.EndTime).IsZero() {
+		task.EndTime = model2.Time(time.Now())
+		task.UpdateBy = p.UserId
+		err = tx.Save(&task).Error
+		if err != nil {
+			e.Log.Errorf("db error: %s", err)
+			return errors.New(fmt.Sprintf("保存运单任务信息失败:%s", err))
+		}
+	}
+
+	// 添加签收记录
+	Logistics := model.WaybillLogistics{
+		WaybillNo:   c.WaybillNo,
+		Status:      c.Status,
+		CoolerBoxId: coolerBox.Id,
+		UserId:      p.UserId,
+		Lng:         lng,
+		Lat:         lat,
+		ControlBy: model2.ControlBy{
+			CreateBy: p.UserId,
+		},
+		DeptBy: model2.DeptBy{
+			DeptId: p.DeptId,
+		},
+		ModelTime: model2.ModelTime{
+			CreatedAt: waybillModel.ReceiptTime,
+		},
+	}
+	err = tx.Create(&Logistics).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return errors.New(fmt.Sprintf("保存运单物流信息失败:%s", err))
+	}
+
+	return nil
+}
+
+// 获取入库 出库 上车 下车 定位信息
+func (e *Waybill) GetSite(companyId int, sn string, time string) (lng, lat string, err error) {
+	// 获取公司秘钥
+	var company model.SysDept
+	company, err = model.GetCompanyById(companyId)
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return lng, lat, model.GetCompanyKeyErr
+	}
+	// 获取传感器信息
+	var deviceSensorList = []nats_server.DeviceSensor_R{}
+	var count int64
+	deviceSensorList, count, err = nats_server.Cold_CompanyDeviceSensor_List_ByKey(sn, company.ColdKey)
+	if err != nil || count == 0 {
+		err = errors.New("查询设备定位信息失败")
+		return lng, lat, err
+	}
+	var deviceData nats_server.DeviceData_
+	deviceData, err = nats_server.Cold_ReadDeviceDataBy_T_snid_T_time(deviceSensorList[0].T_sn, deviceSensorList[0].T_id, time)
+	if err != nil {
+		err = errors.New("查询设备定位信息失败")
+		return lng, lat, err
+	}
+	if len(deviceData.T_site) > 0 {
+		site := strings.Split(deviceSensorList[0].T_DeviceSensorData.T_site, ",")
+		if len(site) == 2 {
+			lng = site[0]
+			lat = site[1]
+		}
+	}
+	return lng, lat, nil
+}
+
+// 获取今日运单数 未派单 未装车 未入库 运送中
+// 本月运单总数 上月运单总数 本年运单总数 上年运单总数
+func (e *Waybill) GetBasicsStats(c *dto.WaybillStatsReq, p *actions.DataPermission) dto.WaybillStatsRes {
+	var res dto.WaybillStatsRes
+	var data model.Waybill
+	type DateCount struct {
+		Date  string
+		Count int64
+	}
+	yearCount := make([]DateCount, 0)
+	monthCount := make([]DateCount, 0)
+	now := time.Now()
+	todayStartTime := now.Format("2006-01-02") + " 00:00:00"
+	todayEndTime := now.Format("2006-01-02") + " 23:59:59"
+
+	// 获取上个月第一天
+	firstDayOfLastMonth := time.Date(now.Year(), now.Month()-1, 1, 0, 0, 0, 0, now.Location())
+
+	// 获取去年的第一天
+	firstDayOfLastYear := time.Date(now.Year()-1, time.January, 1, 0, 0, 0, 0, now.Location())
+	monthStartTime := firstDayOfLastMonth.Format("2006-01-02") + " 00:00:00"
+	yearStartTime := firstDayOfLastYear.Format("2006-01-02") + " 00:00:00"
+
+	// 今日总运单数
+	e.Orm.Model(&data).Scopes(actions.Permission(data.TableName(), p)).Where("order_time between ? and ?", todayStartTime, todayEndTime).Count(&res.TodayNum)
+	// 待派单
+	e.Orm.Model(&data).Scopes(actions.Permission(data.TableName(), p)).Where("status = ?", model.WaybillStatusWaitDelivery).Count(&res.WaitDeliveryNum)
+	// 配送中
+	e.Orm.Model(&data).Scopes(actions.Permission(data.TableName(), p)).Where("status = ?", model.WaybillStatusInDelivery).Count(&res.InDeliveryNum)
+	// 已送达
+	e.Orm.Model(&data).Scopes(actions.Permission(data.TableName(), p)).Where("status = ?", model.WaybillStatusReceipt).Count(&res.ReceiptNum)
+	// 已取消
+	e.Orm.Model(&data).Scopes(actions.Permission(data.TableName(), p)).Where("status = ?", model.WaybillStatusRejection).Count(&res.RejectionNum)
+	// 获取本月,上月数据
+	e.Orm.Model(&data).Select("date_format(order_time,'%Y%m') date,count(1) as count ").Scopes(actions.Permission(data.TableName(), p)).
+		Where("order_time between ? and ?", monthStartTime, now).Group("date").Find(&monthCount)
+
+	for _, month := range monthCount {
+		if month.Date == now.Format("200601") {
+			res.ThisMonthNum = month.Count
+		}
+		if month.Date == firstDayOfLastMonth.Format("200601") {
+			res.LastMonthNum = month.Count
+		}
+	}
+
+	// 获取本年,上年数据
+	e.Orm.Model(&data).Select("date_format(order_time,'%Y') date,count(1) as count ").Scopes(actions.Permission(data.TableName(), p)).
+		Where("order_time between ? and ?", yearStartTime, now).Group("date").Find(&yearCount)
+
+	for _, month := range yearCount {
+		if month.Date == now.Format("2006") {
+			res.ThisYearNum = month.Count
+		}
+		if month.Date == firstDayOfLastYear.Format("2006") {
+			res.LastYearNum = month.Count
+		}
+	}
+
+	if c.Type == "year" {
+		// 获取上个月第一天
+		year, _ := strconv.Atoi(c.Date)
+		firstDayOfyear := time.Date(year, 1, 1, 0, 0, 0, 0, now.Location())
+		lastDayOfyear := time.Date(year, 12, 31, 23, 59, 59, 0, now.Location())
+
+		// 年度数据统计
+		e.Orm.Model(&data).Select("date_format(order_time,'%Y-%m') date,count(1) as num ").Scopes(actions.Permission(data.TableName(), p)).
+			Where("order_time between ? and ?", firstDayOfyear, lastDayOfyear).Group("date").Find(&res.Stats)
+	}
+
+	if c.Type == "month" {
+		// 获取上个月第一天
+		month, _ := time.Parse("2006-01", c.Date)
+		firstDayOfMonth := time.Date(month.Year(), month.Month(), 1, 0, 0, 0, 0, now.Location())
+		lastDayOfMonth := time.Date(month.Year(), month.Month()+1, 1, 23, 59, 59, 0, now.Location()).Add(-time.Hour * 24)
+		e.Orm.Model(&data).Select("date_format(order_time,'%Y-%m-%d') date,count(1) as num ").Scopes(actions.Permission(data.TableName(), p)).
+			Where("order_time between ? and ?", firstDayOfMonth, lastDayOfMonth).Group("date").Find(&res.Stats)
+	}
+
+	return res
+}
+
+// 获取运单所有温湿度素具
+func (e *Waybill) GetAllData(c *dto.WaybillGetByWaybillNoReq) ([]nats_server.DeviceData_R, []WaybillPDF, error) {
+	var err error
+	var data model.WaybillTask
+	var waybill model.Waybill
+	var taskList []model.WaybillTask
+	var waybillPDF []WaybillPDF
+	dataList := make([]nats_server.DeviceData_R, 0)
+
+	err = e.Orm.Model(&waybill).Where("waybill_no = ?", c.WaybillNo).First(&waybill).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return dataList, waybillPDF, errors.New("获取运单信息失败")
+	}
+
+	// 未签收,不返回数据
+	if waybill.Status != model.WaybillStatusReceipt {
+		return dataList, waybillPDF, nil
+	}
+
+	// 获取公司秘钥
+	var company model.SysDept
+	company, err = model.GetCompanyById(waybill.DeptId)
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return dataList, waybillPDF, model.GetCompanyKeyErr
+	}
+
+	err = e.Orm.Model(&data).
+		Where("waybill_no = ?", c.WaybillNo).
+		Order("id desc").
+		Find(&taskList).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return dataList, waybillPDF, global.GetFailedErr
+	}
+
+	// 获取最后一个任务id
+	var lastWaybillTask model.WaybillTask
+	err = e.Orm.Model(&lastWaybillTask).Where("waybill_no = ?", c.WaybillNo).Last(&lastWaybillTask).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		err = errors.New("获取运单信息错误!")
+		return dataList, waybillPDF, err
+	}
+
+	// 创建名称到权重的映射
+	orderMap := make(map[string]int)
+	for i, v := range taskList {
+		orderMap[v.Sn] = i
+	}
+
+	for i := 0; i < len(taskList); i++ {
+		// 获取传感器信息
+		deviceSensorList, _, _ := nats_server.Cold_CompanyDeviceSensor_List_ByKey(taskList[i].Sn, company.ColdKey)
+		var T_snid string
+		var list []nats_server.DeviceData_R
+		for _, r := range deviceSensorList {
+			T_snid += fmt.Sprintf("%s,%d|", r.T_sn, r.T_id)
+		}
+		var count int64
+		list, count, err = nats_server.Cold_ReadDeviceDataListBy_T_snid(T_snid, taskList[i].StartTime.String(), taskList[i].EndTime.String(), 0, 9999)
+		if err != nil {
+			e.Log.Errorf("nats 获取温湿度信息失败: %s", err)
+			return dataList, waybillPDF, global.GetFailedErr
+		}
+
+		firstMap := map[int]nats_server.DeviceData_R{}
+		lastMap := map[int]nats_server.DeviceData_R{}
+		if count > 0 {
+			for _, v := range deviceSensorList {
+
+				for j := 0; j < len(list); j++ {
+					if v.T_id == list[j].T_id {
+						if list[j].T_time != taskList[i].StartTime.String() {
+							firstData := list[j]
+							firstData.T_time = taskList[i].StartTime.String()
+							firstMap[v.T_id] = firstData
+							count += 1
+						}
+						break
+					}
+				}
+				if waybill.Status == model.WaybillStatusReceipt {
+					for k := len(list) - 1; k >= 0; k-- {
+						if v.T_id == list[k].T_id {
+							if taskList[i].Id == lastWaybillTask.Id && list[k].T_time != taskList[i].EndTime.String() && !time.Time(taskList[i].EndTime).IsZero() {
+								lastData := list[k]
+								lastData.T_time = taskList[i].EndTime.String()
+								lastMap[v.T_id] = lastData
+								count += 1
+							}
+							break
+						}
+					}
+				}
+			}
+		}
+
+		for _, v := range firstMap {
+			list = append(list, v)
+		}
+
+		for _, v := range lastMap {
+			list = append(list, v)
+		}
+		sort.Slice(list, func(x, y int) bool {
+			if list[x].T_time == list[y].T_time {
+				// 如果时间相同,则按预设顺序排序
+				return orderMap[list[x].T_sn] < orderMap[list[y].T_sn]
+			}
+			return list[x].T_time > list[y].T_time
+		})
+
+		dataList = append(dataList, list...)
+		waybillPDF = append(waybillPDF, WaybillPDF{
+			Data:             list,
+			DeviceSensorList: deviceSensorList,
+			Task:             taskList[i],
+		})
+	}
+
+	sort.Slice(dataList, func(i, j int) bool {
+		if dataList[i].T_time == dataList[j].T_time {
+			// 如果时间相同,则按预设顺序排序
+			return orderMap[dataList[i].T_sn] < orderMap[dataList[j].T_sn]
+		}
+		return dataList[i].T_time < dataList[j].T_time
+	})
+
+	return dataList, waybillPDF, nil
+}
+
+type WaybillPDF struct {
+	Data             []nats_server.DeviceData_R   `json:"data"`
+	DeviceSensorList []nats_server.DeviceSensor_R `json:"deviceSensorList"`
+	Task             model.WaybillTask            `json:"task"`
+}

+ 32 - 0
app/admin/service/waybill_logistics.go

@@ -0,0 +1,32 @@
+package service
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/app/admin/service/dto"
+	cDto "cold-delivery/common/dto"
+	"cold-delivery/common/global"
+	"gogs.baozhida.cn/zoie/OAuth-core/service"
+)
+
+type WaybillLogistics struct {
+	service.Service
+}
+
+// GetPage 获取WaybillLogistics列表
+func (e *WaybillLogistics) GetPage(c *dto.WaybillLogisticsGetPageReq, list *[]model.WaybillLogistics, count *int64) error {
+	var err error
+	var data model.WaybillLogistics
+
+	err = e.Orm.Model(&data).
+		Scopes(
+			cDto.MakeCondition(c.GetNeedSearch()),
+		).
+		Preload("CoolerBox").
+		Find(list).
+		Count(count).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+	return nil
+}

+ 229 - 0
app/admin/service/waybill_task.go

@@ -0,0 +1,229 @@
+package service
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/app/admin/service/dto"
+	cDto "cold-delivery/common/dto"
+	"cold-delivery/common/global"
+	model2 "cold-delivery/common/model"
+	"cold-delivery/common/nats/nats_server"
+	"errors"
+	"fmt"
+	"gogs.baozhida.cn/zoie/OAuth-core/service"
+	"gorm.io/gorm"
+	"sort"
+	"time"
+)
+
+type WaybillTask struct {
+	service.Service
+}
+
+func WaybillTaskTimeScopes(startTime, endTime string) func(db *gorm.DB) *gorm.DB {
+	return func(db *gorm.DB) *gorm.DB {
+		if len(startTime) == 0 && len(endTime) == 0 {
+			return db
+		}
+		return db.Where("(start_time between ? and ?) or (end_time between ? and ?)",
+			startTime, endTime, startTime, endTime)
+	}
+}
+
+// GetPage 获取WaybillTask列表
+func (e *WaybillTask) GetPage(c *dto.WaybillTaskGetPageReq, list *[]model.WaybillTask, count *int64) error {
+	var err error
+	var data model.WaybillTask
+	var waybill model.Waybill
+	err = e.Orm.Model(&waybill).Where("waybill_no = ?", c.WaybillNo).First(&waybill).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return errors.New("获取运单信息失败")
+	}
+
+	err = e.Orm.Model(&data).
+		Scopes(
+			cDto.MakeCondition(c.GetNeedSearch()),
+		).
+		Preload("CoolerBox").
+		Find(list).Limit(-1).Offset(-1).
+		Count(count).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+	// 获取公司秘钥
+	var company model.SysDept
+	company, err = model.GetCompanyById(waybill.DeptId)
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return model.GetCompanyKeyErr
+	}
+	for i := 0; i < len(*list); i++ {
+		// 获取传感器信息
+		deviceSensorList, _, _ := nats_server.Cold_CompanyDeviceSensor_List_ByKey((*list)[i].Sn, company.ColdKey)
+		(*list)[i].DeviceSensorList = deviceSensorList
+	}
+	return nil
+}
+
+// GetPage 获取WaybillTask列表
+func (e *WaybillTask) GetDataPage(c *dto.WaybillTaskGetDataPageReq) (list []nats_server.DeviceData_R, count int64, err error) {
+
+	var waybill model.Waybill
+	err = e.Orm.Where("waybill_no = ?", c.WaybillNo).First(&waybill).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		err = errors.New("获取运单信息错误!")
+		return
+	}
+
+	var task model.WaybillTask
+	err = e.Orm.Where("id = ? and waybill_no = ?", c.TaskId, c.WaybillNo).First(&task).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		err = errors.New("获取运单信息错误!")
+		return
+	}
+
+	if len(c.StartTime) > 0 {
+		var st time.Time
+		st, err = time.Parse("2006-01-02 15:04:05", c.StartTime)
+		if err != nil {
+			err = errors.New("解析时间字符串出错!")
+			return
+		}
+		if st.Before(time.Time(task.StartTime)) {
+			c.StartTime = task.StartTime.String()
+		}
+	} else {
+		c.StartTime = task.StartTime.String()
+	}
+	if len(c.EndTime) > 0 {
+		var et time.Time
+		et, err = time.Parse("2006-01-02 15:04:05", c.EndTime)
+		if err != nil {
+			err = errors.New("解析时间字符串出错!")
+			return
+		}
+		if et.After(time.Time(task.EndTime)) {
+			c.EndTime = task.EndTime.String()
+		}
+	} else {
+		c.EndTime = task.EndTime.String()
+	}
+
+	T_snid := ""
+	for _, id := range c.T_ids {
+		T_snid += fmt.Sprintf("%s,%d|", task.Sn, id)
+	}
+	list, count, err = nats_server.Cold_ReadDeviceDataListBy_T_snid(T_snid, c.StartTime, c.EndTime, c.Page, c.PageSize)
+	return list, count, err
+}
+func (e *WaybillTask) GetNewestDataPage(c *dto.WaybillTaskGetNewestDataPageReq) (data nats_server.DeviceData_R, err error) {
+	var waybill model.Waybill
+	err = e.Orm.Model(&waybill).Where("waybill_no = ?", c.WaybillNo).First(&waybill).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		err = errors.New("获取运单信息错误!")
+		return
+	}
+	// 获取公司秘钥
+	var company model.SysDept
+	company, err = model.GetCompanyById(waybill.DeptId)
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		err = model.GetCompanyKeyErr
+		return
+	}
+
+	var taskList []model.WaybillTask
+	err = e.Orm.Where("waybill_no = ?", c.WaybillNo).Order("id desc").Find(&taskList).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		err = errors.New("获取运单信息任务失败!")
+		return
+	}
+	if len(taskList) == 0 {
+		err = errors.New("暂无温湿度记录信息!")
+		return
+	}
+	var listAll []nats_server.DeviceData_R
+	for _, task := range taskList {
+		deviceSensorList, _, _ := nats_server.Cold_CompanyDeviceSensor_List_ByKey(task.Sn, company.ColdKey)
+		if len(deviceSensorList) == 0 {
+			continue
+		}
+		T_snid := fmt.Sprintf("%s,%d|", deviceSensorList[0].T_sn, deviceSensorList[0].T_id)
+		if len(task.EndTime.String()) == 0 {
+			task.EndTime = model2.Time(time.Now())
+		}
+		// 获取传感器信息
+		list, _, _ := nats_server.Cold_ReadDeviceDataListBy_T_snid(T_snid, task.StartTime.String(), task.EndTime.String(), 0, 9999)
+		if len(list) > 0 {
+			listAll = append(listAll, list...)
+			break
+		}
+	}
+
+	if len(listAll) > 0 {
+		data = listAll[0]
+		return
+	}
+	err = errors.New("暂无温湿度记录信息!")
+	return
+}
+func (e *WaybillTask) GetLocus(c *dto.WaybillGetLocusReq) ([]nats_server.DeviceData_R2, error) {
+	var err error
+	var data model.WaybillTask
+	var waybill model.Waybill
+	var taskList []model.WaybillTask
+	locusList := make([]nats_server.DeviceData_R2, 0)
+
+	err = e.Orm.Model(&waybill).Where("waybill_no = ?", c.WaybillNo).First(&waybill).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return locusList, errors.New("获取运单信息失败")
+	}
+	// 获取公司秘钥
+	var company model.SysDept
+	company, err = model.GetCompanyById(waybill.DeptId)
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return locusList, model.GetCompanyKeyErr
+	}
+
+	err = e.Orm.Model(&data).
+		Scopes(
+			cDto.MakeCondition(c.GetNeedSearch()),
+		).Where("car_id > 0").
+		Find(&taskList).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return locusList, global.GetFailedErr
+	}
+
+	for i := 0; i < len(taskList); i++ {
+		// 获取传感器信息
+		deviceSensorList, _, _ := nats_server.Cold_CompanyDeviceSensor_List_ByKey(taskList[i].Sn, company.ColdKey)
+		if len(deviceSensorList) > 0 {
+			T_snid := fmt.Sprintf("%s,%d|", taskList[i].Sn, deviceSensorList[0].T_id)
+			dataList, _, err := nats_server.Cold_ReadDeviceDataListBy_T_snidForLocus(T_snid, taskList[i].StartTime.String(), taskList[i].EndTime.String(), 0, 9999)
+			if err != nil {
+				e.Log.Errorf("nats 获取轨迹信息失败: %s", err)
+				return locusList, global.GetFailedErr
+			}
+
+			// 倒序
+			sort.Slice(dataList, func(i, j int) bool {
+				if dataList[i].T_time < dataList[j].T_time {
+					return true
+				}
+				return false
+			})
+			locusList = append(locusList, dataList...)
+
+		}
+
+	}
+	return locusList, nil
+}

+ 182 - 0
cmd/api/server.go

@@ -0,0 +1,182 @@
+package api
+
+import (
+	"cold-delivery/app/admin/model"
+	"cold-delivery/common/file_store"
+	global2 "cold-delivery/common/global"
+	"cold-delivery/common/middleware"
+	"cold-delivery/common/middleware/handler"
+	"cold-delivery/common/nats"
+	"cold-delivery/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-delivery/app/admin/router"
+	ext "cold-delivery/conf"
+	database "cold-delivery/db"
+)
+
+var (
+	configYml string
+	StartCmd  = &cobra.Command{
+		Use:          "server",
+		Short:        "Start API server",
+		Example:      "cold-delivery 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,
+		nats.Setup,
+	)
+	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-delivery/common/global"
+	"errors"
+	"fmt"
+	"os"
+
+	"github.com/spf13/cobra"
+
+	"cold-delivery/cmd/api"
+	"cold-delivery/cmd/config"
+	"cold-delivery/cmd/migrate"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg"
+)
+
+var rootCmd = &cobra.Command{
+	Use:          "cold-delivery",
+	Short:        "cold-delivery",
+	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-delivery 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-delivery/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-delivery 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-delivery/common/dto"
+	"cold-delivery/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-delivery/common/dto"
+	"cold-delivery/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-delivery/common/dto"
+	"cold-delivery/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()
+	}
+}

+ 127 - 0
common/actions/permission.go

@@ -0,0 +1,127 @@
+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
+	UserType  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
+	err = tx.Table("sys_user").
+		Select("sys_user.id as user_id", "sys_user.dept_id", "sys_user.user_type").
+		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)
+		}
+	}
+	p.DataScope = "3"
+	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-delivery/common/dto"
+	"cold-delivery/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-delivery/common/dto"
+	"cold-delivery/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()
+	}
+}

+ 75 - 0
common/amap/amap.go

@@ -0,0 +1,75 @@
+package amap
+
+import (
+	"cold-delivery/conf"
+	"encoding/json"
+	"fmt"
+	"github.com/go-resty/resty/v2"
+	"strconv"
+)
+
+type Address struct {
+	Status    string    `json:"status"`
+	Regeocode Regeocode `json:"regeocode"`
+	Info      string    `json:"info"`
+	Infocode  string    `json:"infocode"`
+}
+
+type Regeocode struct {
+	AddressComponent AddressComponent `json:"addressComponent"`
+	FormattedAddress string           `json:"formatted_address"`
+}
+
+type AddressComponent struct {
+	City         string       `json:"city"`
+	Province     string       `json:"province"`
+	Adcode       string       `json:"adcode"`
+	District     string       `json:"district"`
+	Township     string       `json:"township"`
+	StreetNumber StreetNumber `json:"streetNumber"`
+	Country      string       `json:"country"`
+	Citycode     string       `json:"citycode"`
+}
+
+type StreetNumber struct {
+	Number    string `json:"number"`
+	Location  string `json:"location"`
+	Direction string `json:"direction"`
+	Distance  string `json:"distance"`
+	Street    string `json:"street"`
+}
+
+// 高德-逆地址解析
+func GeocodeRegeo(lng, lat string) (address Address) {
+	if len(lng) == 0 || len(lat) == 0 {
+		return
+	}
+
+	lngFloat64, err := strconv.ParseFloat(lng, 64)
+	if err != nil {
+		return
+	}
+	lngStr := fmt.Sprintf("%.6f", lngFloat64)
+
+	latFloat64, err := strconv.ParseFloat(lat, 64)
+	if err != nil {
+		return
+	}
+	latStr := fmt.Sprintf("%.6f", latFloat64)
+
+	client := resty.New()
+
+	resp, err := client.R().SetQueryParams(map[string]string{
+		"key":      conf.ExtConfig.Amap.Key,
+		"location": lngStr + "," + latStr,
+	}).Get("https://restapi.amap.com/v3/geocode/regeo")
+
+	if err != nil {
+		return
+	}
+	err = json.Unmarshal(resp.Body(), &address)
+	if err != nil {
+		return
+	}
+	return address
+}

+ 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-delivery/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-delivery/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-delivery/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)
+}

Some files were not shown because too many files changed in this diff