Browse Source

add:调拨时钢瓶验证

zoie 6 months ago
parent
commit
856498c372
56 changed files with 2683 additions and 503 deletions
  1. 0 1
      .gitignore
  2. 180 3
      app/admin/controller/gas_cylinder.go
  3. 4 4
      app/admin/controller/gas_cylinder_allot.go
  4. 41 1
      app/admin/controller/gas_cylinder_status.go
  5. 208 0
      app/admin/controller/inspect_expand.go
  6. 14 0
      app/admin/controller/store.go
  7. 36 0
      app/admin/controller/sys_user.go
  8. 7 0
      app/admin/controller/truck_enterprise.go
  9. 2 1
      app/admin/model/gas_cylinder.go
  10. 13 11
      app/admin/model/gas_cylinder_allot.go
  11. 20 5
      app/admin/model/gas_cylinder_status.go
  12. 16 0
      app/admin/model/inspect_expand.go
  13. 2 1
      app/admin/model/operation_log.go
  14. 29 0
      app/admin/model/sys_dept.go
  15. 1 1
      app/admin/model/sys_opera_log.go
  16. 3 0
      app/admin/router/gas_cylinder.go
  17. 1 0
      app/admin/router/gas_cylinder_status.go
  18. 25 0
      app/admin/router/inspect_expand.go
  19. 1 0
      app/admin/router/sys_user.go
  20. 3 3
      app/admin/service/dto/car_info.go
  21. 3 7
      app/admin/service/dto/gas_cylinder.go
  22. 6 1
      app/admin/service/dto/gas_cylinder_allot.go
  23. 26 3
      app/admin/service/dto/gas_cylinder_status.go
  24. 74 0
      app/admin/service/dto/inspect_expand.go
  25. 5 2
      app/admin/service/dto/operation_log.go
  26. 22 11
      app/admin/service/dto/sys_user.go
  27. 35 94
      app/admin/service/gas_cylinder.go
  28. 384 249
      app/admin/service/gas_cylinder_allot.go
  29. 111 22
      app/admin/service/gas_cylinder_status.go
  30. 291 0
      app/admin/service/inspect_expand.go
  31. 1 1
      app/admin/service/inspect_record.go
  32. 35 7
      app/admin/service/operation_log.go
  33. 10 2
      app/admin/service/order.go
  34. 34 19
      app/admin/service/store.go
  35. 60 0
      app/admin/service/sys_user.go
  36. 14 17
      app/admin/service/truck_enterprise.go
  37. 13 13
      app/admin/service/warehouse.go
  38. 72 0
      app/jobs/controller/sys_job.go
  39. 205 0
      app/jobs/jobbase.go
  40. 140 0
      app/jobs/jobs.go
  41. 62 0
      app/jobs/model/sys_job.go
  42. 35 0
      app/jobs/router/int_router.go
  43. 42 0
      app/jobs/router/router.go
  44. 39 0
      app/jobs/router/sys_job.go
  45. 108 0
      app/jobs/service/dto/sys_job.go
  46. 92 0
      app/jobs/service/sys_job.go
  47. 16 0
      app/jobs/type.go
  48. 15 0
      common/global/lib.go
  49. 28 0
      common/global/lib_test.go
  50. 53 0
      common/global/string.go
  51. 4 0
      common/model/byat.go
  52. 2 2
      conf/city_data_array.go
  53. 0 1
      conf/data-array.json
  54. 1 0
      db/migration.go
  55. 13 8
      go.mod
  56. 26 13
      go.sum

+ 0 - 1
.gitignore

@@ -38,7 +38,6 @@ Makefile
 /ofile
 setting.yml
 /temp
-/app/jobs
 /docs
 uploads
 .DS_Store

+ 180 - 3
app/admin/controller/gas_cylinder.go

@@ -1,15 +1,22 @@
 package controller
 
 import (
+	"errors"
 	"gas-cylinder-api/app/admin/model"
 	"gas-cylinder-api/app/admin/service"
 	"gas-cylinder-api/app/admin/service/dto"
 	"gas-cylinder-api/common/actions"
+	"gas-cylinder-api/common/global"
 	"github.com/gin-gonic/gin"
 	"github.com/gin-gonic/gin/binding"
+	"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"
+	"net/url"
+	"os"
+	"path"
+	"strings"
 )
 
 type GasCylinderController struct {
@@ -81,6 +88,10 @@ func (e GasCylinderController) Get(c *gin.Context) {
 	//数据权限检查
 	err = s.Get(&req, &object, p)
 	if err != nil {
+		if errors.Is(err, global.GetNotFoundOrNoPermissionErr) {
+			e.Error(400, err, "钢瓶不存在,请在钢瓶档案添加钢瓶信息!")
+			return
+		}
 		e.Error(500, err, err.Error())
 		return
 	}
@@ -112,15 +123,14 @@ func (e GasCylinderController) GetByUid(c *gin.Context) {
 		return
 	}
 	var gasCylinder model.GasCylinder
-	p := actions.GetPermissionFromContext(c)
 	//数据权限检查
-	err = s.GetByUid(&req, &gasCylinder, p)
+	err = s.GetByUid(&req, &gasCylinder, nil)
 	if err != nil {
 		e.Error(500, err, err.Error())
 		return
 	}
 	operationLogList := make([]model.OperationLog, 0)
-	err = operationLogSvc.ListByUid(gasCylinder.InnerCode, &operationLogList)
+	err = operationLogSvc.ListByInnerCode(gasCylinder.InnerCode, &operationLogList)
 	if err != nil {
 		e.Error(500, err, err.Error())
 		return
@@ -273,3 +283,170 @@ func (e GasCylinderController) Delete(c *gin.Context) {
 	e.OK(req.GetId(), "删除成功")
 }
 
+// Import 添加钢瓶
+// @Summary 添加钢瓶
+// @Description 添加钢瓶
+// @Tags 钢瓶
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.GasCylinderInsertReq true "data"
+// @Param pageSize query int false "页条数"
+// @Param page query int false "页码"
+// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
+// @Router /api/gas-cylinder [post]
+// @Security Bearer
+func (e GasCylinderController) Import(c *gin.Context) {
+	s := service.GasCylinder{}
+	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)
+	// 获取上传的文件
+	file, err := c.FormFile("file")
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	// 打开上传的文件
+	f, err := file.Open()
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	defer f.Close()
+
+	// 解析Excel文件
+	excelFile, err := excelize.OpenReader(f)
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	// 读取第一个Sheet
+	rows, err := excelFile.GetRows(excelFile.GetSheetName(0))
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	// 遍历行数据并插入数据库
+	for i, row := range rows {
+		if i == 0 {
+			continue
+		}
+		if len(row) < 13 {
+			continue // 跳过不完整的行
+		}
+
+		r := dto.GasCylinderInsertReq{
+			InnerCode:     strings.TrimSpace(row[0]),  // 单位内编码
+			Uid:           strings.TrimSpace(row[1]),  // 高频编码
+			Status:        strings.TrimSpace(row[2]),  // 高频编码
+			ProVariety:    strings.TrimSpace(row[3]),  // 设备品种
+			ProName:       strings.TrimSpace(row[4]),  // 产品名称
+			ProNo:         strings.TrimSpace(row[5]),  // 气瓶生产编号
+			FillMedia:     strings.TrimSpace(row[6]),  // 充装介质
+			MakeUnit:      strings.TrimSpace(row[7]),  // 制造单位
+			MakeTime:      strings.TrimSpace(row[8]),  // 生产日期
+			WorkPressure:  strings.TrimSpace(row[9]),  // 公称工作压口(MPa)
+			Volume:        strings.TrimSpace(row[10]), // 容积(L)
+			CheckTime:     strings.TrimSpace(row[11]), // 最近一次检验日期
+			NextCheckTime: strings.TrimSpace(row[12]), // 下次检验日期
+			ProUuid:       strings.TrimSpace(row[13]), // 产品唯一性编码
+		}
+
+		// 设置创建人
+		r.SetCreateBy(user.GetUserId(c))
+		r.SetDeptId(p.DeptId)
+		err = s.Insert(&r)
+		if err != nil {
+			e.Error(500, err, err.Error())
+			return
+		}
+	}
+
+	e.OK(nil, "导入成功")
+}
+
+// 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 GasCylinderController) ExportTemplate(c *gin.Context) {
+	s := service.GasCylinder{}
+	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)
+
+}
+
+func (e GasCylinderController) Status(c *gin.Context) {
+	s := service.GasCylinder{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	var object []string
+	p := actions.GetPermissionFromContext(c)
+
+	//数据权限检查
+	err = s.GetStatus(&object, p)
+	if err != nil {
+		if errors.Is(err, global.GetNotFoundOrNoPermissionErr) {
+			e.Error(400, err, "钢瓶不存在,请在钢瓶档案添加钢瓶信息!")
+			return
+		}
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	e.OK(object, "查询成功")
+}

+ 4 - 4
app/admin/controller/gas_cylinder_allot.go

@@ -159,7 +159,7 @@ func (e GasCylinderAllotController) Insert(c *gin.Context) {
 
 	// 送气员
 	if userObj.ProvUser.UserType == 3 && userObj.ProvUser.Isorders == 0 {
-		if !global.CheckElementExists(req.OptType, []string{"21", "35", "Unqualified"}) {
+		if !global.CheckElementExists(req.OptType, []string{"21", "35", "md" + model.GasCylinderStatusScrap, "md" + model.GasCylinderStatusExtended}) {
 			err = errors.New("该调拨码不支持操作!")
 			e.Error(500, err, err.Error())
 			return
@@ -168,7 +168,7 @@ func (e GasCylinderAllotController) Insert(c *gin.Context) {
 
 	// 门店
 	if userObj.ProvUser.UserType == 3 && userObj.ProvUser.Isorders == 1 {
-		if !global.CheckElementExists(req.OptType, []string{"11", "25", "033", "Unqualified"}) {
+		if !global.CheckElementExists(req.OptType, []string{"11", "25", "033", "sj" + model.GasCylinderStatusScrap, "sj" + model.GasCylinderStatusExtended}) {
 			err = errors.New("该调拨码不支持操作!")
 			e.Error(500, err, err.Error())
 			return
@@ -177,7 +177,7 @@ func (e GasCylinderAllotController) Insert(c *gin.Context) {
 
 	// 司机
 	if userObj.ProvUser.UserType == 4 {
-		if !global.CheckElementExists(req.OptType, []string{"31", "13", "016", "Unqualified"}) {
+		if !global.CheckElementExists(req.OptType, []string{"31", "13", "016", "md" + model.GasCylinderStatusScrap, "md" + model.GasCylinderStatusExtended, "qz" + model.GasCylinderStatusScrap, "qz" + model.GasCylinderStatusExtended}) {
 			err = errors.New("该调拨码不支持操作!")
 			e.Error(500, err, err.Error())
 			return
@@ -186,7 +186,7 @@ func (e GasCylinderAllotController) Insert(c *gin.Context) {
 
 	// 气站
 	if userObj.ProvUser.UserType == 5 {
-		if !global.CheckElementExists(req.OptType, []string{"17"}) {
+		if !global.CheckElementExists(req.OptType, []string{"17", "sj" + model.GasCylinderStatusScrap, "sj" + model.GasCylinderStatusExtended}) {
 			err = errors.New("该调拨码不支持操作!")
 			e.Error(500, err, err.Error())
 			return

+ 41 - 1
app/admin/controller/gas_cylinder_status.go

@@ -99,7 +99,7 @@ func (e GasCylinderStatusController) Get(c *gin.Context) {
 	e.OK(object, "查询成功")
 }
 
-// Update 修改钢瓶状态
+// Insert 添加钢瓶状态
 // @Summary 修改钢瓶状态
 // @Description 修改钢瓶状态
 // @Tags 钢瓶状态
@@ -153,6 +153,46 @@ func (e GasCylinderStatusController) Insert(c *gin.Context) {
 	e.OK(req.GetId(), "添加成功")
 }
 
+// Update 修改钢瓶状态
+// @Summary 修改钢瓶状态
+// @Description 修改钢瓶状态
+// @Tags 钢瓶状态
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.GasCylinderStatusUpdateReq true "body"
+// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
+// @Router /api/dispatch-cost [put]
+// @Security Bearer
+func (e GasCylinderStatusController) Update(c *gin.Context) {
+	s := service.GasCylinderStatus{}
+	userSvc := service.SysUser{}
+	req := dto.GasCylinderStatusUpdateReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req).
+		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)
+
+	// 设置创建人
+	req.SetUpdateBy(user.GetUserId(c))
+
+	err = s.Update(&req, p)
+
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.OK(req.InnerCodeList, "修改成功")
+}
+
 // Delete 删除钢瓶状态
 // @Summary 删除钢瓶状态
 // @Description 删除钢瓶状态

+ 208 - 0
app/admin/controller/inspect_expand.go

@@ -0,0 +1,208 @@
+package controller
+
+import (
+	"gas-cylinder-api/app/admin/model"
+	"gas-cylinder-api/app/admin/service"
+	"gas-cylinder-api/app/admin/service/dto"
+	"gas-cylinder-api/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"
+)
+
+type InspectExpandController struct {
+	api.Api
+}
+
+// GetPage 获取入户安全检查项项列表
+// @Summary 获取入户安全检查项项列表
+// @Description 获取入户安全检查项项列表
+// @Tags 入户安全检查项项
+// @Param state            query int false "订单状态 状态 0-待整改 1-整改中 2-已整改 -1 合格"
+// @Param inspectStartTime query string false "检查开始时间"
+// @Param inspectEndTime   query string false "检查结束时间"
+// @Param customerName     query string false "客户名称"
+// @Param inspectorName    query string false "检查人"
+// @Param pageSize query int false "页条数"
+// @Param page query int false "页码"
+// @Success 200 {object} response.Response{data=response.Page{list=[]model.InspectExpand}} "{"code": 200, "data": [...]}"
+// @Router /api/inspect_record [get]
+// @Security Bearer
+func (e InspectExpandController) GetPage(c *gin.Context) {
+	s := service.InspectExpand{}
+	req := dto.InspectExpandGetPageReq{}
+	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.InspectExpand, 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(), "查询成功")
+}
+
+// Insert 添加入户安全检查项项
+// @Summary 添加入户安全检查项项
+// @Description 添加入户安全检查项项
+// @Tags 入户安全检查项项
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.InspectExpandInsertReq true "data"
+// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
+// @Router /api/inspect_record [post]
+// @Security Bearer
+func (e InspectExpandController) Insert(c *gin.Context) {
+	s := service.InspectExpand{}
+	req := dto.InspectExpandInsertReq{}
+	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(user.GetDeptId(c))
+
+	err = s.Insert(&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.InspectExpandInsertReq true "data"
+// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
+// @Router /api/inspect_record [post]
+// @Security Bearer
+func (e InspectExpandController) Update(c *gin.Context) {
+	s := service.InspectExpand{}
+	userSvc := service.SysUser{}
+	req := dto.InspectExpandInsertReq{}
+	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
+	}
+
+	// 设置创建人
+	req.SetCreateBy(user.GetUserId(c))
+	req.SetDeptId(user.GetDeptId(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.GasCylinderStatusDeleteReq true "body"
+// @Success 200 {string} string	"{"code": 200, "message": "删除成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "删除失败"}"
+// @Router /api/dispatch-cost [delete]
+// @Security Bearer
+func (e InspectExpandController) Delete(c *gin.Context) {
+	s := service.InspectExpand{}
+	req := dto.InspectExpandDeleteReq{}
+	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(), "删除成功")
+}
+
+// SyncStore 删除钢瓶状态
+// @Summary 删除钢瓶状态
+// @Description 删除钢瓶状态
+// @Tags 钢瓶状态
+// @Accept  application/json
+// @Product application/json
+// @Param data body dto.InspectExpandSyncStoreReq true "body"
+// @Success 200 {string} string	"{"code": 200, "message": "删除成功"}"
+// @Success 200 {string} string	"{"code": -1, "message": "删除失败"}"
+// @Router /api/dispatch-cost [delete]
+// @Security Bearer
+func (e InspectExpandController) SyncStore(c *gin.Context) {
+	s := service.InspectExpand{}
+	req := dto.InspectExpandSyncStoreReq{}
+	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.SyncStore(&req, p)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.OK(req.StoreIds, "同步成功")
+}

+ 14 - 0
app/admin/controller/store.go

@@ -235,11 +235,13 @@ func (e StoreController) Get(c *gin.Context) {
 // @Security Bearer
 func (e StoreController) Insert(c *gin.Context) {
 	s := service.Store{}
+	inspectExpandSvc := service.InspectExpand{}
 	req := dto.StoreInsertReq{}
 	err := e.MakeContext(c).
 		MakeOrm().
 		Bind(&req, binding.JSON).
 		MakeService(&s.Service).
+		MakeService(&inspectExpandSvc.Service).
 		Errors
 	if err != nil {
 		e.Logger.Error(err)
@@ -255,6 +257,11 @@ func (e StoreController) Insert(c *gin.Context) {
 		e.Error(500, err, err.Error())
 		return
 	}
+	err = inspectExpandSvc.Init(user.GetUserId(c), (req.GetId()).(int))
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
 	e.OK(req.GetId(), "创建成功")
 }
 
@@ -305,6 +312,7 @@ func (e StoreController) Update(c *gin.Context) {
 // @Security Bearer
 func (e StoreController) Delete(c *gin.Context) {
 	s := service.Store{}
+	inspectExpandSvc := service.InspectExpand{}
 	req := dto.StoreDeleteReq{}
 	userSvc := service.SysUser{}
 	err := e.MakeContext(c).
@@ -312,6 +320,7 @@ func (e StoreController) Delete(c *gin.Context) {
 		Bind(&req, binding.JSON, nil).
 		MakeService(&s.Service).
 		MakeService(&userSvc.Service).
+		MakeService(&inspectExpandSvc.Service).
 		Errors
 	if err != nil {
 		e.Logger.Error(err)
@@ -337,6 +346,11 @@ func (e StoreController) Delete(c *gin.Context) {
 		e.Error(500, err, err.Error())
 		return
 	}
+	err = inspectExpandSvc.DeleteByDeptId((req.GetId()).(int))
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
 	e.OK(req.GetId(), "删除成功")
 }
 

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

@@ -616,3 +616,39 @@ func (e SysUser) Home(c *gin.Context) {
 		"customerCount":        customerCount,
 	}, "查询")
 }
+
+// GetPageByOptType 根据OptType获取用户列表
+// @Summary 根据OptType获取用户列表
+// @Description 根据OptType获取用户列表
+// @Tags 用户
+// @Param pageSize query int false "页条数"
+// @Param pageIndex query int false "页码"
+// @Success 200 {object} response.Response{data=response.Page{list=[]model.SysUser}}  "{"code": 200, "data": [...]}"
+// @Router /api/sys-user/delivery [get]
+// @Security Bearer
+func (e SysUser) GetPageByOptType(c *gin.Context) {
+	s := service.SysUser{}
+	req := dto.SysUserGetPageByOptTypeReq{}
+	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.SysUser, 0)
+	var count int64
+
+	err = s.GetPageByOptType(&req, &list, &count)
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
+}

+ 7 - 0
app/admin/controller/truck_enterprise.go

@@ -170,11 +170,13 @@ func (e TruckEnterpriseController) Delete(c *gin.Context) {
 	s := service.TruckEnterprise{}
 	req := dto.TruckEnterpriseDeleteReq{}
 	userSvc := service.SysUser{}
+	inspectExpandSvc := service.InspectExpand{}
 	err := e.MakeContext(c).
 		MakeOrm().
 		Bind(&req, binding.JSON, nil).
 		MakeService(&s.Service).
 		MakeService(&userSvc.Service).
+		MakeService(&inspectExpandSvc.Service).
 		Errors
 	if err != nil {
 		e.Logger.Error(err)
@@ -200,6 +202,11 @@ func (e TruckEnterpriseController) Delete(c *gin.Context) {
 		e.Error(500, err, err.Error())
 		return
 	}
+	err = inspectExpandSvc.DeleteByDeptId((req.GetId()).(int))
+	if err != nil {
+		e.Error(500, err, err.Error())
+		return
+	}
 	e.OK(req.GetId(), "删除成功")
 }
 

+ 2 - 1
app/admin/model/gas_cylinder.go

@@ -54,7 +54,7 @@ type GasCylinder struct {
 	ProVariety            string `json:"pro_variety"`             // 1设备品种
 	EnterpriseName        string `json:"enterprise_name"`         // 产权单位
 	ProName               string `json:"pro_name"`                // 1产品名称
-	ProNo                 string `json:"pro_no"`                  // 气瓶生产编号 (出厂)编号
+	ProNo                 string `json:"pro_no"`                  // 1气瓶生产编号 (出厂)编号
 	FillMedia             string `json:"fill_media"`              // 1充装介质:0液化石油气,1二甲醚,2氧气,3二氧化碳,4溶解乙炔
 	MakeUnit              string `json:"make_unit"`               // 1制造单位
 	MakeTime              string `json:"make_time"`               // 1生产日期
@@ -70,6 +70,7 @@ type GasCylinder struct {
 	AliasName             string `json:"alias_name"`
 	Status                string `json:"status"`
 
+	LastOperationTime model2.Time `json:"last_operation_time"` // 最新操作时间
 	model2.ControlBy
 	model2.ModelTime
 	model2.DeptBy

+ 13 - 11
app/admin/model/gas_cylinder_allot.go

@@ -19,17 +19,19 @@ var (
 // 气瓶调拨
 type GasCylinderAllot struct {
 	model2.Model
-	OptType         string            `json:"optType" gorm:"size:48"`          // 气瓶流转步骤
-	AllotUserId     int               `json:"allotUserId" gorm:"size:48;"`     // 调拨者用户id
-	AcceptUserId    int               `json:"acceptUserId" gorm:"size:48;"`    // 接收者用户id
-	AllotCompanyId  int               `json:"allotCompanyId" gorm:"size:48;"`  // 调拨者所属公司id
-	AcceptCompanyId int               `json:"acceptCompanyId" gorm:"size:48;"` // 接收者所属公司id
-	InnerCodeList   model2.StringList `json:"innerCodeList" gorm:"type:json"`  // 单位内编码列表
-	Status          int               `json:"status" gorm:"size:4"`            // 1-调拨中 2-调拨完成 3-取消调拨 4-超时取消
-	AllotUser       SysUserOmit       `json:"allotUser"  gorm:"foreignkey:AllotUserId;references:Id"`
-	AcceptUser      SysUserOmit       `json:"acceptUser"  gorm:"foreignkey:AcceptUserId;references:Id"`
-	AllotCompany    SysDeptOmit       `json:"allotCompany"  gorm:"foreignkey:AllotCompanyId;references:Id"`
-	AcceptCompany   SysDeptOmit       `json:"acceptCompany" gorm:"->;foreignkey:AcceptCompanyId;references:Id"`
+	OptType             string            `json:"optType" gorm:"size:48"`               // 气瓶流转步骤
+	AllotUserId         int               `json:"allotUserId" gorm:"size:48;"`          // 调拨者用户id
+	AcceptUserId        int               `json:"acceptUserId" gorm:"size:48;"`         // 接收者用户id
+	AllotCompanyId      int               `json:"allotCompanyId" gorm:"size:48;"`       // 调拨者所属公司id
+	AcceptCompanyId     int               `json:"acceptCompanyId" gorm:"size:48;"`      // 接收者所属公司id
+	InnerCodeList       model2.StringList `json:"innerCodeList" gorm:"type:json"`       // 单位内编码列表 调拨人发的气瓶列表
+	AcceptInnerCodeList model2.StringList `json:"acceptInnerCodeList" gorm:"type:json"` // 单位内编码列表 接收人接收的气瓶列表
+	Status              int               `json:"status" gorm:"size:4"`                 // 1-调拨中 2-调拨完成 3-取消调拨 4-超时取消
+	AllotType           int               `json:"allotType" gorm:"size:4"`              // 调拨类型 1-扫码调拨 2-一键调拨
+	AllotUser           SysUserOmit       `json:"allotUser"  gorm:"foreignkey:AllotUserId;references:Id"`
+	AcceptUser          SysUserOmit       `json:"acceptUser"  gorm:"foreignkey:AcceptUserId;references:Id"`
+	AllotCompany        SysDeptOmit       `json:"allotCompany"  gorm:"foreignkey:AllotCompanyId;references:Id"`
+	AcceptCompany       SysDeptOmit       `json:"acceptCompany" gorm:"->;foreignkey:AcceptCompanyId;references:Id"`
 
 	model2.ControlBy
 	model2.ModelTime

+ 20 - 5
app/admin/model/gas_cylinder_status.go

@@ -3,14 +3,28 @@ package model
 import model2 "gas-cylinder-api/common/model"
 
 var (
-	GasCylinderStatusWeighty     = 1 // 重瓶区
-	GasCylinderStatusEmpty       = 2 // 空瓶区
-	GasCylinderStatusUnqualified = 3 // 不合格瓶区
+	GasCylinderStatusWeighty     = "1" // 重瓶区
+	GasCylinderStatusEmpty       = "2" // 空瓶区
+	GasCylinderStatusUnqualified = "3" // 不合格瓶区
+	//报废(scrap)超期(extended)
+	GasCylinderStatusScrap = "scrap" // 报废瓶区
 
-	GasCylinderStatusStateMap = map[int]string{
+	GasCylinderStatusExtended = "extended" // 超期瓶区
+
+	GasCylinderStatusStateMap = map[string]string{
 		GasCylinderStatusWeighty:     "重瓶区",
 		GasCylinderStatusEmpty:       "空瓶区",
 		GasCylinderStatusUnqualified: "不合格瓶区",
+		GasCylinderStatusScrap:       "报废瓶区",
+		GasCylinderStatusExtended:    "超期瓶区",
+	}
+
+	GasCylinderStatusState2Map = map[string]string{
+		GasCylinderStatusWeighty:     "重瓶",
+		GasCylinderStatusEmpty:       "空瓶",
+		GasCylinderStatusUnqualified: "不合格瓶",
+		GasCylinderStatusScrap:       "报废瓶",
+		GasCylinderStatusExtended:    "超期瓶",
 	}
 )
 
@@ -18,9 +32,10 @@ var (
 type GasCylinderStatus struct {
 	model2.Model
 	InnerCode string      `json:"inner_code"`                // 1单位内编号
-	Status    int         `json:"status" gorm:"size:1;"`     // 1-重瓶区 2-空瓶区 3-不合格瓶区
+	Status    string      `json:"status" gorm:"size:48;"`    // 1-重瓶区 2-空瓶区 3-不合格瓶区
 	UserId    int         `json:"userId" gorm:"size:48;"`    // 省平台用户id 司机 送气员
 	CompanyId int         `json:"companyId" gorm:"size:48;"` // 所属公司id
+	IsAllot   bool        `json:"isAllot" gorm:"size:48;"`   // true 调拨中
 	User      SysUserOmit `json:"user"  gorm:"foreignkey:UserId;references:Id"`
 	Company   SysDeptOmit `json:"company" gorm:"->;foreignkey:CompanyId;references:Id"`
 	model2.ControlBy

+ 16 - 0
app/admin/model/inspect_expand.go

@@ -0,0 +1,16 @@
+package model
+
+import model2 "gas-cylinder-api/common/model"
+
+type InspectExpand struct {
+	model2.Model
+	InspectItem    string `json:"inspectItem" gorm:"size:48"`     // 安全检查项
+	InspectExplain string `json:"inspectExplain" gorm:"size:256"` // 安全检查想说明
+	model2.ControlBy
+	model2.ModelTime
+	model2.DeptBy
+}
+
+func (InspectExpand) TableName() string {
+	return "inspect_expand"
+}

+ 2 - 1
app/admin/model/operation_log.go

@@ -4,7 +4,7 @@ import model2 "gas-cylinder-api/common/model"
 
 type ProvOperationLog struct {
 	InnerCode          string `json:"innerCode" gorm:"size:36" vd:"len($)>0"` //气瓶唯一性编码,单位内编号
-	OptType            string `json:"optType" gorm:"size:4"`                  //气瓶流转步骤
+	OptType            string `json:"optType" gorm:"size:48"`                 //气瓶流转步骤
 	OptTime            string `json:"optTime" gorm:"size:"`                   //操作时间
 	OptUser            string `json:"optUser" gorm:"size:36"`                 //操作人
 	Lng                string `json:"lng" gorm:"size:9"`                      //经度
@@ -26,6 +26,7 @@ type OperationLog struct {
 	model2.Model
 	ProvOperationLog
 	State                int          `json:"state" gorm:"size:36;default:1"` // 1 - 新循环 2-已完成
+	BatchNumber          string       `json:"batchNumber" gorm:"size:36"`     // 批号
 	OptUserObj           SysUserOmit  `json:"optUserObj" gorm:"->;foreignkey:OptUser;references:ProvUserId"`
 	ObjectUserObj        SysUserOmit  `json:"objectUserObj" gorm:"->;foreignkey:ObjectUser;references:ProvUserId"`
 	ObjectCustomerObj    CustomerOmit `json:"objectCustomerObj" gorm:"->;foreignkey:ObjectCustomer;references:Id"`

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

@@ -220,3 +220,32 @@ func GetParentIds(id int) (arr []int, err error) {
 	}
 	return arr, nil
 }
+
+func GetRootCompanyIds(id int) (arr []int, 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 arr, err
+	}
+	err = db.First(&deptModel, id).Error
+	if err != nil {
+		log.Errorf("db error: %s", err)
+		err = errors.New("获取企业信息失败")
+		return arr, err
+	}
+	// 获取跟公司id
+	rootId := strings.Split(strings.Trim(deptModel.Path, "/0/"), "/")[0]
+
+	// 获取所有子id
+
+	err = db.Model(&SysDept{}).Select("id").Where("path like ?", "%/"+rootId+"/%").Find(&arr).Error
+	if err != nil {
+		log.Errorf("db error: %s", err)
+		err = errors.New("获取企业信息失败")
+		return arr, err
+	}
+	return arr, nil
+}

+ 1 - 1
app/admin/model/sys_opera_log.go

@@ -74,7 +74,7 @@ func SaveOperaLog(message storage.Messager) (err error) {
 		return nil
 	}
 	// 外部调用获取身份信息,操作频繁,不做日志记录
-	if l.OperaUrl == "/api/service/userinfo" || l.OperaUrl == "/api/upload" {
+	if l.OperaUrl == "/api/service/userinfo" || l.OperaUrl == "/api/upload" || l.OperaUrl == "/api/gas-cylinder/import" {
 		return nil
 	}
 	// 超出100个字符返回值截断

+ 3 - 0
app/admin/router/gas_cylinder.go

@@ -24,6 +24,9 @@ func registerGasCylinderRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMi
 		r.POST("", cont.Insert)
 		r.PUT("", cont.Update)
 		r.DELETE("", cont.Delete)
+		r.POST("/import", cont.Import)
+		r.POST("/export-template", cont.ExportTemplate)
+		r.GET("/status", cont.Status)
 	}
 }
 

+ 1 - 0
app/admin/router/gas_cylinder_status.go

@@ -20,6 +20,7 @@ func registerGasCylinderStatusRouter(v1 *gin.RouterGroup, authMiddleware *jwt.Gi
 		r.GET("", cont.GetPage)
 		r.GET("/:id", cont.Get)
 		r.POST("", cont.Insert)
+		r.PUT("", cont.Update)
 		r.DELETE("", cont.Delete)
 	}
 }

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

@@ -0,0 +1,25 @@
+package router
+
+import (
+	"gas-cylinder-api/app/admin/controller"
+	"gas-cylinder-api/common/actions"
+	"github.com/gin-gonic/gin"
+	jwt "gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth"
+)
+
+func init() {
+	routerCheckRole = append(routerCheckRole, registerInspectExpandRouter)
+}
+
+// 需认证的路由代码
+func registerInspectExpandRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
+	cont := controller.InspectExpandController{}
+	r := v1.Group("/inspect-expand").Use(authMiddleware.MiddlewareFunc()).Use(actions.PermissionAction())
+	{
+		r.GET("", cont.GetPage)
+		r.POST("", cont.Insert)
+		r.PUT("", cont.Update)
+		r.DELETE("", cont.Delete)
+		r.POST("/sync-store", cont.SyncStore)
+	}
+}

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

@@ -22,6 +22,7 @@ func registerSysUserRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddle
 	{
 		r.GET("", cont.GetPage)
 		r.GET("/delivery", cont.GetDeliveryPage)
+		r.GET("/opt-type", cont.GetPageByOptType)
 		r.GET("/:id", cont.Get)
 		r.POST("", cont.Insert)
 		r.PUT("", cont.Update)

+ 3 - 3
app/admin/service/dto/car_info.go

@@ -8,9 +8,9 @@ import (
 
 type CarInfoGetPageReq struct {
 	dto.Pagination     `search:"-"`
-	CarNo              string `form:"carNo" search:"type:contains;column:car_no;table:car_info"` // 角色名称
-	StartTransportTime string `form:"startTransportTime" search:"-"`                             // 角色名称
-	EndTransportTime   string `form:"endTransportTime" search:"-"`                               // 角色名称
+	CarNo              string `form:"carNo" search:"type:contains;column:car_no;table:car_info"` // 车牌号
+	StartTransportTime string `form:"startTransportTime" search:"-"`                             // 道路运输证有效期
+	EndTransportTime   string `form:"endTransportTime" search:"-"`                               // 道路运输证有效期
 	CarInfoOrder
 }
 

+ 3 - 7
app/admin/service/dto/gas_cylinder.go

@@ -23,10 +23,6 @@ type GasCylinderGetReq struct {
 	InnerCode string `uri:"inner_code"`
 }
 
-func (s *GasCylinderGetReq) GetInnerCode() interface{} {
-	return s.InnerCode
-}
-
 type GasCylinderGetByUidReq struct {
 	ChipUid string `uri:"chipUid"`
 }
@@ -74,7 +70,7 @@ func (s *GasCylinderInsertReq) Generate(m *model.GasCylinder) {
 		m.Id = s.Id
 	}
 	m.InnerCode = s.InnerCode
-	m.Uid = s.InnerCode
+	m.Uid = s.Uid
 	m.StationName = s.StationName
 	m.FillTime = s.FillTime
 	m.RegisterSuperviseName = s.RegisterSuperviseName
@@ -104,7 +100,7 @@ func (s *GasCylinderInsertReq) Generate(m *model.GasCylinder) {
 	if s.ControlBy.CreateBy != 0 {
 		m.CreateBy = s.CreateBy
 	}
-	if s.DeptBy.DeptId != 0 {
+	if s.DeptBy.DeptId != 0 && m.DeptId == 0 {
 		m.DeptId = s.DeptId
 	}
 }
@@ -147,7 +143,7 @@ func (s *GasCylinderUpdateReq) Generate(m *model.GasCylinder) {
 		m.Id = s.Id
 	}
 	m.InnerCode = s.InnerCode
-	m.Uid = s.InnerCode
+	m.Uid = s.Uid
 	m.StationName = s.StationName
 	m.FillTime = s.FillTime
 	m.RegisterSuperviseName = s.RegisterSuperviseName

+ 6 - 1
app/admin/service/dto/gas_cylinder_allot.go

@@ -8,6 +8,9 @@ import (
 
 type GasCylinderAllotGetPageReq struct {
 	dto.Pagination `search:"-"`
+	My             string `form:"my" search:"-"`                                                     // 我的 allot-我调拨的 accept-我签收的
+	Status         int    `form:"status" search:"type:exact;column:status;table:gas_cylinder_allot"` // 1-调拨中 2-已完成 3-已取消 4-超时取消
+
 	GasCylinderAllotOrder
 }
 type GasCylinderAllotOrder struct {
@@ -26,8 +29,9 @@ type GasCylinderAllotInsertReq struct {
 	AllotCompanyId    int               `json:"allotCompanyId" swaggerignore:"true"`         // 调拨者所属公司id
 	AcceptCompanyId   int               `json:"acceptCompanyId" vd:"$>0;msg:'接收者公司id不能为空'"`  // 接收者所属公司id
 	InnerCodeList     common.StringList `json:"innerCodeList" vd:"len($)>0;msg:'单位内编码不能为空'"` // 单位内编码列表
-	GasCylinderStatus int               `json:"gasCylinderStatus"`                           // 气瓶状态
+	GasCylinderStatus string            `json:"gasCylinderStatus"`                           // 气瓶状态
 	Status            int               `json:"status" swaggerignore:"true"`                 // 调拨状态
+	AllotType         int               `json:"allotType" `                                  // 调拨类型 1-扫码调拨 2-一键调拨
 	common.ControlBy  `swaggerignore:"true"`
 	common.DeptBy     `swaggerignore:"true"`
 }
@@ -43,6 +47,7 @@ func (s *GasCylinderAllotInsertReq) Generate(m *model.GasCylinderAllot) {
 	m.AcceptCompanyId = s.AcceptCompanyId
 	m.InnerCodeList = s.InnerCodeList
 	m.Status = model.GasCylinderAllotStateAllot
+	m.AllotType = s.AllotType
 	if s.ControlBy.UpdateBy != 0 {
 		m.UpdateBy = s.UpdateBy
 	}

+ 26 - 3
app/admin/service/dto/gas_cylinder_status.go

@@ -11,7 +11,7 @@ type GasCylinderStatusGetPageReq struct {
 	UserId         int    `form:"userId" search:"-"`
 	CompanyId      string `form:"companyId" search:"-"`
 	InnerCode      string `form:"inner_code" search:"type:contains;column:inner_code;table:gas_cylinder_status"` // 1单位内编号
-	Status         int    `form:"status" search:"type:exact;column:status;table:gas_cylinder_status"`            // 1-重瓶区 2-空瓶区 3-不合格瓶区
+	Status         string    `form:"status" search:"-"`            // 1-重瓶区 2-空瓶区 3-不合格瓶区
 	GasCylinderStatusOrder
 }
 type GasCylinderStatusOrder struct {
@@ -25,8 +25,8 @@ func (m *GasCylinderStatusGetPageReq) GetNeedSearch() interface{} {
 type GasCylinderStatusInsertReq struct {
 	Id               int      `json:"id" comment:"编码"` // 编码
 	InnerCodeList    []string `json:"innerCodeList" vd:"len($)>0;msg:'单位内编码不能为空'"`
-	Status           int      `json:"status" vd:"$>0;msg:'钢瓶状态不能为空'"` // 钢瓶状态
-	Remark           string   `json:"remark"`                         // 备注
+	Status           string   `json:"status" vd:"len($)>0;msg:'钢瓶状态不能为空'"` // 钢瓶状态
+	Remark           string   `json:"remark"`                              // 备注
 	common.ControlBy `swaggerignore:"true"`
 	common.DeptBy    `swaggerignore:"true"`
 }
@@ -69,3 +69,26 @@ type GasCylinderStatusDeleteReq struct {
 func (s *GasCylinderStatusDeleteReq) GetId() interface{} {
 	return s.Id
 }
+
+
+type GasCylinderStatusUpdateReq struct {
+	InnerCodeList    []string `json:"innerCodeList" vd:"len($)>0;msg:'单位内编码不能为空'"`
+	Status           string   `json:"status" vd:"len($)>0;msg:'钢瓶状态不能为空'"` // 钢瓶状态
+	Remark           string   `json:"remark"`                              // 备注
+	common.ControlBy `swaggerignore:"true"`
+	common.DeptBy    `swaggerignore:"true"`
+}
+
+func (s *GasCylinderStatusUpdateReq) Generate(innerCode string, model *model.GasCylinderStatus) {
+	model.InnerCode = innerCode
+	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
+	}
+}

+ 74 - 0
app/admin/service/dto/inspect_expand.go

@@ -0,0 +1,74 @@
+package dto
+
+import (
+	"gas-cylinder-api/app/admin/model"
+	"gas-cylinder-api/common/dto"
+	common "gas-cylinder-api/common/model"
+)
+
+// 入库安全检查
+type InspectExpandGetPageReq struct {
+	dto.Pagination `search:"-"`
+	InspectExpandOrder
+}
+type InspectExpandOrder struct {
+	CreatedAtOrder string `search:"type:order;column:created_at;table:inspect_expand" form:"createdAtOrder" default:"asc"`
+}
+
+func (m *InspectExpandGetPageReq) GetNeedSearch() interface{} {
+	return *m
+}
+
+type InspectExpandInsertReq struct {
+	Id               int    `json:"id" comment:"编码" swaggerignore:"true"` // 编码
+	InspectExplain   string `json:"inspectExplain"`
+	common.ControlBy `swaggerignore:"true"`
+	common.DeptBy    `swaggerignore:"true"`
+}
+
+func (s *InspectExpandInsertReq) Generate(model *model.InspectExpand) {
+	if s.Id != 0 {
+		model.Id = s.Id
+	}
+	model.InspectExplain = s.InspectExplain
+	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 *InspectExpandInsertReq) GetId() interface{} {
+	return s.Id
+}
+
+func (s *InspectExpandInsertReq) UpdateGenerate(model *model.InspectExpand) {
+	if s.Id != 0 {
+		model.Id = s.Id
+	}
+	model.InspectExplain = s.InspectExplain
+	if s.ControlBy.UpdateBy != 0 {
+		model.UpdateBy = s.UpdateBy
+	}
+	if s.ControlBy.CreateBy != 0 {
+		model.CreateBy = s.CreateBy
+	}
+}
+
+type InspectExpandDeleteReq struct {
+	Id               int `json:"id" vd:"$>0;msg:'id不能为空'"`
+	common.ControlBy `swaggerignore:"true"`
+}
+
+func (s *InspectExpandDeleteReq) GetId() interface{} {
+	return s.Id
+}
+
+type InspectExpandSyncStoreReq struct {
+	StoreIds         []int `json:"storeIds" vd:"len($)>0;msg:'门店id不能为空'"`
+	common.ControlBy `swaggerignore:"true"`
+}

+ 5 - 2
app/admin/service/dto/operation_log.go

@@ -6,8 +6,11 @@ import (
 
 type OperationLogGetPageReq struct {
 	dto.Pagination `search:"-"`
-	OptType        int    `form:"optType" search:"type:exact;column:opt_type;table:operation_log"`        // 气瓶流转步骤
-	InnerCode      string `form:"innerCode" search:"type:contains;column:inner_code;table:operation_log"` //
+	OptType        int    `form:"optType" search:"type:exact;column:opt_type;table:operation_log"`            // 气瓶流转步骤
+	InnerCode      string `form:"innerCode" search:"type:contains;column:inner_code;table:operation_log"`     //
+	OptStartTime   string `form:"optStartTime" search:"type:gte;column:opt_time;table:operation_log"`         // 操作开始时间
+	OptEndTime     string `form:"optEndTime" search:"type:lte;column:opt_time;table:operation_log"`           // 操作结束时间
+	BatchNumber    string `form:"batchNumber" search:"type:contains;column:batch_number;table:operation_log"` // 操作结束时间
 	OperationLogOrder
 }
 type OperationLogOrder struct {

+ 22 - 11
app/admin/service/dto/sys_user.go

@@ -95,18 +95,18 @@ func (s *UpdateSysUserStatusReq) Generate(userModel *model.SysUser) {
 }
 
 type SysUserInsertReq struct {
-	Id                           int                                `json:"id" swaggerignore:"true" comment:"用户ID"`                         // 用户ID
+	Id                           int                                `json:"id" swaggerignore:"true" comment:"用户ID"`                    // 用户ID
 	Username                     string                             `json:"username" example:"username" vd:"@:len($)>0;msg:'用户名不能为空'"` // 用户名
 	Password                     string                             `json:"password" example:"123456" vd:"@:len($)>5;msg:'密码格式不正确'"`   // 密码
-	Name                         string                             `json:"name" swaggerignore:"true"`                                        // 姓名
-	Phone                        string                             `json:"phone" swaggerignore:"true"`                                       // 手机号
-	RoleId                       int                                `json:"roleId" example:"1"`                                               // 角色id
-	DeptId                       int                                `json:"deptId" example:"1"  swaggerignore:"true"`                         // 机构id
-	Status                       string                             `json:"status" example:"2" swaggerignore:"true"`                          // 状态
-	ProvUser                     model.ProvUser                     `json:"provUser"`                                                         // 省平台用户信息
-	ProvStoreUserBindCertificate model.ProvStoreUserBindCertificate `json:"provStoreUserBindCertificate"`                                     // 送气人员绑定资质信息《燃气从业资格证》
-	ProvTruckUserBindCertificate model.ProvTruckUserBindCertificate `json:"provTruckUserBindCertificate"`                                     // 货车司机绑定《道路运输从业人员从业资格证》信息
-	ProvUserId                   string                             `json:"provUserId"  swaggerignore:"true"`                                 // 省平台用户id
+	Name                         string                             `json:"name" swaggerignore:"true"`                                 // 姓名
+	Phone                        string                             `json:"phone" swaggerignore:"true"`                                // 手机号
+	RoleId                       int                                `json:"roleId" example:"1"`                                        // 角色id
+	DeptId                       int                                `json:"deptId" example:"1"  swaggerignore:"true"`                  // 机构id
+	Status                       string                             `json:"status" example:"2" swaggerignore:"true"`                   // 状态
+	ProvUser                     model.ProvUser                     `json:"provUser"`                                                  // 省平台用户信息
+	ProvStoreUserBindCertificate model.ProvStoreUserBindCertificate `json:"provStoreUserBindCertificate"`                              // 送气人员绑定资质信息《燃气从业资格证》
+	ProvTruckUserBindCertificate model.ProvTruckUserBindCertificate `json:"provTruckUserBindCertificate"`                              // 货车司机绑定《道路运输从业人员从业资格证》信息
+	ProvUserId                   string                             `json:"provUserId"  swaggerignore:"true"`                          // 省平台用户id
 	model2.ControlBy             `swaggerignore:"true"`
 }
 
@@ -146,7 +146,7 @@ func (s *SysUserInsertReq) GetId() interface{} {
 }
 
 type SysUserUpdateReq struct {
-	Id                           int                                `json:"id" swaggerignore:"true" comment:"用户ID"` // 用户ID
+	Id                           int                                `json:"id" swaggerignore:"true" comment:"用户ID"`   // 用户ID
 	Name                         string                             `json:"name" swaggerignore:"true"`                // 姓名
 	Phone                        string                             `json:"phone" swaggerignore:"true"`               // 手机号
 	RoleId                       int                                `json:"roleId" example:"1"`                       // 角色id
@@ -322,3 +322,14 @@ type SysUserGetSMSVerifyCodeReq struct {
 type GetNewestTokenReq struct {
 	UserId int64 `uri:"userId" example:"1"` //手机号
 }
+
+type SysUserGetPageByOptTypeReq struct {
+	dto2.Pagination `search:"-"`
+	OptType         string `form:"optType" search:"-"` // 气瓶流转步骤
+	Name    string `form:"name" search:"type:contains;column:nick_name;table:sys_user" comment:"昵称"`
+	StoreId string `form:"storeId" search:"type:exact;column:dept_id;table:sys_user" comment:"门店id"`
+}
+
+func (m *SysUserGetPageByOptTypeReq) GetNeedSearch() interface{} {
+	return *m
+}

+ 35 - 94
app/admin/service/gas_cylinder.go

@@ -45,113 +45,26 @@ func (e *GasCylinder) GetPage(c *dto.GasCylinderGetPageReq, list *[]model.GasCyl
 func (e *GasCylinder) Get(d *dto.GasCylinderGetReq, data *model.GasCylinder, p *actions.DataPermission) error {
 	// TODO 通过省平台获取气瓶详情
 
-	//client := resty.New()
-	//
-	//resp, err := client.R().Get("https://mock.apifox.com/m2/4037076-0-default/151344663")
-	//if err != nil {
-	//	e.Log.Errorf("db error: %s", err)
-	//	return global.GetFailedErr
-	//}
-	//err = json.Unmarshal(resp.Body(), data)
-	//if err != nil {
-	//	e.Log.Errorf("json Unmarshal err: %s", err)
-	//	return global.GetFailedErr
-	//}
-	//obj := model.GasCylinder{
-	//	ProVariety:   data.ProVariety,
-	//	ProName:      data.ProName,
-	//	ProNo:        data.ProNo,
-	//	FillMedia:    data.FillMedia,
-	//	MakeUnit:     data.MakeUnit,
-	//	MakeTime:     data.MakeTime,
-	//	WorkPressure: data.WorkPressure,
-	//	//InnerCode:     data.InnerCode,
-	//	Volume:        data.Volume,
-	//	CheckTime:     data.CheckTime,
-	//	NextCheckTime: data.NextCheckTime,
-	//	ProUuid:       data.ProUuid,
-	//	//Uid:           data.Uid,
-	//	ProductId:    data.ProductId,
-	//	DeadlineTime: data.DeadlineTime,
-	//	CheckInTime:  data.CheckInTime,
-	//	DeptBy: model2.DeptBy{
-	//		DeptId: p.DeptId,
-	//	},
-	//}
-	////e.Orm.Create(&obj)
-	//
-	//err = e.Orm.Where("inner_code = ?", d.GetInnerCode()).Updates(&obj).Error
-	//if err != nil {
-	//	e.Log.Errorf("db error: %s", err)
-	//	if errors.Is(err, gorm.ErrRecordNotFound) {
-	//		return global.GetNotFoundOrNoPermissionErr
-	//	}
-	//	return global.GetFailedErr
-	//}
-	//
-	//data.InnerCode = d.InnerCode
-
-	err := e.Orm.Where("inner_code = ?", d.GetInnerCode()).First(&data).Error
+	err := e.Orm.Where("inner_code = ? or uid = ?", d.InnerCode, d.InnerCode).First(&data).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 *GasCylinder) GetByUid(d *dto.GasCylinderGetByUidReq, data *model.GasCylinder, p *actions.DataPermission) error {
 
 	// 1、通过高频ID查询气瓶内编码
-	err := e.Orm.Where("uid = ?", d.ChipUid).First(&data).Error
+	err := e.Orm.Where("inner_code = ?", d.ChipUid).First(&data).Error
 	if err != nil {
 		e.Log.Errorf("db error: %s", err)
 		return global.GetFailedErr
 	}
-	//client := resty.New()
-	//resp, err := client.R().Get("https://mock.apifox.com/m2/4037076-0-default/151344663")
-	//if err != nil {
-	//	e.Log.Errorf("db error: %s", err)
-	//	return global.GetFailedErr
-	//}
-	//err = json.Unmarshal(resp.Body(), data)
-	//if err != nil {
-	//	e.Log.Errorf("json Unmarshal err: %s", err)
-	//	return global.GetFailedErr
-	//}
-	//obj := model.GasCylinder{
-	//	ProVariety:   data.ProVariety,
-	//	ProName:      data.ProName,
-	//	ProNo:        data.ProNo,
-	//	FillMedia:    data.FillMedia,
-	//	MakeUnit:     data.MakeUnit,
-	//	MakeTime:     data.MakeTime,
-	//	WorkPressure: data.WorkPressure,
-	//	//InnerCode:     data.InnerCode,
-	//	Volume:        data.Volume,
-	//	CheckTime:     data.CheckTime,
-	//	NextCheckTime: data.NextCheckTime,
-	//	ProUuid:       data.ProUuid,
-	//	//Uid:           data.Uid,
-	//	ProductId:    data.ProductId,
-	//	DeadlineTime: data.DeadlineTime,
-	//	CheckInTime:  data.CheckInTime,
-	//	DeptBy: model2.DeptBy{
-	//		DeptId: p.DeptId,
-	//	},
-	//}
-	////e.Orm.Create(&obj)
-	//
-	//err = e.Orm.Where("inner_code = ?", gasCylinder.InnerCode).Updates(&obj).Error
-	//if err != nil {
-	//	e.Log.Errorf("db error: %s", err)
-	//	if errors.Is(err, gorm.ErrRecordNotFound) {
-	//		return global.GetNotFoundOrNoPermissionErr
-	//	}
-	//	return global.GetFailedErr
-	//}
-	//
-	//data.InnerCode = gasCylinder.InnerCode
-	//data.Uid = gasCylinder.Uid
 
 	return nil
 }
@@ -223,7 +136,7 @@ func (e *GasCylinder) Insert(c *dto.GasCylinderInsertReq) error {
 			tx.Commit()
 		}
 	}()
-	err = e.Orm.Where("inner_code = ? AND dept_id = ?", c.InnerCode, c.DeptId).First(&data).Error
+	err = e.Orm.Scopes(InRootCompanyIdsScopes(c.DeptId)).Where("inner_code = ?", c.InnerCode).First(&data).Error
 	if err != nil {
 		if errors.Is(err, gorm.ErrRecordNotFound) {
 			// 添加气瓶
@@ -315,6 +228,19 @@ func (e *GasCylinder) Remove(c *dto.GasCylinderDeleteReq, p *actions.DataPermiss
 		return global.DeleteFailedErr
 	}
 
+	// 判断是否有人关联重瓶/空瓶/不合格瓶
+
+	var gasCylinderStatusModel model.GasCylinderStatus
+
+	// 查询钢瓶是否存在
+	err = e.Orm.Scopes(InRootCompanyIdsScopes(p.DeptId)).
+		Where("inner_code = ?", gasCylinderModel.InnerCode).
+		First(&gasCylinderStatusModel, c.GetId()).Error
+	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
+		e.Log.Errorf("db error: %s", err)
+		return errors.New("查询钢瓶状态失败")
+	}
+
 	db := tx.Delete(&gasCylinderModel)
 
 	if err = db.Error; err != nil {
@@ -328,4 +254,19 @@ func (e *GasCylinder) Remove(c *dto.GasCylinderDeleteReq, p *actions.DataPermiss
 	return nil
 }
 
+func (e *GasCylinder) GetStatus(list *[]string, p *actions.DataPermission) error {
+	var err error
+	var data model.GasCylinder
 
+	err = e.Orm.Model(&data).
+		Distinct("status").
+		Scopes(
+			actions.Permission(data.TableName(), p),
+		).
+		Find(list).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+	return nil
+}

File diff suppressed because it is too large
+ 384 - 249
app/admin/service/gas_cylinder_allot.go


+ 111 - 22
app/admin/service/gas_cylinder_status.go

@@ -12,6 +12,7 @@ import (
 	"gogs.baozhida.cn/zoie/OAuth-core/service"
 	"gorm.io/gorm"
 	"gorm.io/gorm/utils"
+	"strings"
 	"time"
 )
 
@@ -19,6 +20,25 @@ type GasCylinderStatus struct {
 	service.Service
 }
 
+func GasCylinderStatusScopes(status string) func(db *gorm.DB) *gorm.DB {
+
+	return func(db *gorm.DB) *gorm.DB {
+		if len(status) == 0 {
+			return db
+		}
+		if status == model.GasCylinderStatusUnqualified {
+			return db.Where("status = ? or status = ?", model.GasCylinderStatusScrap, model.GasCylinderStatusExtended)
+		}
+		if strings.Contains(status, model.GasCylinderStatusScrap) {
+			return db.Where("status = ?", model.GasCylinderStatusScrap)
+		}
+		if strings.Contains(status, model.GasCylinderStatusExtended) {
+			return db.Where("status = ?", model.GasCylinderStatusExtended)
+		}
+		return db.Where("status = ? ", status)
+	}
+}
+
 // GetPage 获取GasCylinderStatus列表
 func (e *GasCylinderStatus) GetPage(c *dto.GasCylinderStatusGetPageReq, list *[]model.GasCylinderStatus, count *int64, p *actions.DataPermission) error {
 	var err error
@@ -29,6 +49,7 @@ func (e *GasCylinderStatus) GetPage(c *dto.GasCylinderStatusGetPageReq, list *[]
 			cDto.MakeCondition(c.GetNeedSearch()),
 			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
 			//actions.Permission(data.TableName(), p),
+			GasCylinderStatusScopes(c.Status),
 		).
 		Where("company_id = ? AND user_id = 0", p.DeptId).
 		Find(list).Limit(-1).Offset(-1).
@@ -50,6 +71,7 @@ func (e *GasCylinderStatus) GetUserPage(c *dto.GasCylinderStatusGetPageReq, list
 			cDto.MakeCondition(c.GetNeedSearch()),
 			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
 			//actions.Permission(data.TableName(), p),
+			GasCylinderStatusScopes(c.Status),
 		).
 		Where("user_id = ?", p.UserId).
 		Find(list).Limit(-1).Offset(-1).
@@ -62,10 +84,10 @@ func (e *GasCylinderStatus) GetUserPage(c *dto.GasCylinderStatusGetPageReq, list
 }
 
 // Get 获取GasCylinderStatus对象
-func (e *GasCylinderStatus) Get(d *dto.GasCylinderStatusGetReq, carInfoModel *model.GasCylinderStatus, p *actions.DataPermission) error {
+func (e *GasCylinderStatus) Get(d *dto.GasCylinderStatusGetReq, gasCylinderStatusModel *model.GasCylinderStatus, p *actions.DataPermission) error {
 	err := e.Orm.
-		Scopes(actions.Permission(carInfoModel.TableName(), p)).
-		First(carInfoModel, d.GetId()).Error
+		Scopes(actions.Permission(gasCylinderStatusModel.TableName(), p)).
+		First(gasCylinderStatusModel, d.GetId()).Error
 
 	if err != nil {
 		e.Log.Errorf("db error: %s", err)
@@ -91,12 +113,29 @@ func (e *GasCylinderStatus) Insert(c *dto.GasCylinderStatusInsertReq, p *actions
 		}
 	}()
 
+	inDeptIdScopes := InRootCompanyIdsScopes(p.DeptId)
 	for _, innerCode := range c.InnerCodeList {
+		// 查询钢瓶档案
+		var gasCylinder = model.GasCylinder{}
+		// 查询订单是否存在
+		err = e.Orm.
+			Scopes(inDeptIdScopes).
+			Where("inner_code = ?", innerCode).
+			First(&gasCylinder).Error
+		if err != nil {
+			e.Log.Errorf("db error: %s", err)
+			if errors.Is(err, gorm.ErrRecordNotFound) {
+				return errors.New(fmt.Sprintf("钢瓶%s不存在,请先在钢瓶档案添加!", innerCode))
+			}
+			return errors.New(fmt.Sprintf("查询钢瓶%s失败,请检查!", innerCode))
+		}
+
 		var data model.GasCylinderStatus
 
 		err = e.Orm.
 			Where("inner_code = ? ", innerCode).
 			Preload("Company").
+			Preload("User").
 			First(&data).Error
 
 		if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
@@ -104,16 +143,17 @@ func (e *GasCylinderStatus) Insert(c *dto.GasCylinderStatusInsertReq, p *actions
 			return global.GetFailedErr
 		}
 		if data.Id > 0 {
+			if data.UserId > 0 && data.UserId != p.UserId {
+				err = errors.New(fmt.Sprintf("钢瓶%s被【%s】关联,请检查!", innerCode, data.User.NickName))
+				return err
+			}
 			if data.CompanyId == p.DeptId {
 				if data.Status != c.Status {
-					data.Status = c.Status
-					err = tx.Save(&data).Error
-					if err != nil {
-						e.Log.Errorf("db error: %s", err)
-						return global.CreateFailedErr
+					if data.Status != c.Status {
+						err = errors.New(fmt.Sprintf("钢瓶%s状态为【%s】,请检查!", innerCode, model.GasCylinderStatusState2Map[data.Status]))
+						return err
 					}
 				}
-				continue
 			} else {
 				err = errors.New(fmt.Sprintf("钢瓶%s被【%s】关联,请检查!", innerCode, data.Company.Name))
 				return err
@@ -146,7 +186,23 @@ func (e *GasCylinderStatus) UserInsert(c *dto.GasCylinderStatusInsertReq, p *act
 		}
 	}()
 
+	inDeptIdScopes := InRootCompanyIdsScopes(p.DeptId)
 	for _, innerCode := range c.InnerCodeList {
+		// 查询钢瓶档案
+		var gasCylinder = model.GasCylinder{}
+		// 查询订单是否存在
+		err = e.Orm.
+			Scopes(inDeptIdScopes).
+			Where("inner_code = ?", innerCode).
+			First(&gasCylinder).Error
+		if err != nil {
+			e.Log.Errorf("db error: %s", err)
+			if errors.Is(err, gorm.ErrRecordNotFound) {
+				return errors.New(fmt.Sprintf("钢瓶%s不存在,请先在钢瓶档案添加!", innerCode))
+			}
+			return errors.New(fmt.Sprintf("查询钢瓶%s失败,请检查!", innerCode))
+		}
+
 		var data model.GasCylinderStatus
 
 		err = e.Orm.
@@ -162,16 +218,11 @@ func (e *GasCylinderStatus) UserInsert(c *dto.GasCylinderStatusInsertReq, p *act
 		if data.Id > 0 {
 			if data.UserId == p.UserId {
 				if data.Status != c.Status {
-					data.Status = c.Status
-					err = tx.Save(&data).Error
-					if err != nil {
-						e.Log.Errorf("db error: %s", err)
-						return global.CreateFailedErr
-					}
+					err = errors.New(fmt.Sprintf("钢瓶%s状态为【%s】,请检查!", innerCode, model.GasCylinderStatusState2Map[data.Status]))
+					return err
 				}
-				continue
 			} else {
-				err = errors.New(fmt.Sprintf("钢瓶被【%s】%s关联,请检查!", data.Company.Name, data.User.NickName))
+				err = errors.New(fmt.Sprintf("钢瓶%s被【%s】%s关联,请检查!", innerCode, data.Company.Name, data.User.NickName))
 				return err
 			}
 
@@ -187,7 +238,7 @@ func (e *GasCylinderStatus) UserInsert(c *dto.GasCylinderStatusInsertReq, p *act
 			return global.CreateFailedErr
 		}
 
-		if isorders && c.Status == 2 {
+		if isorders && c.Status == model.GasCylinderStatusWeighty {
 			// 27 送气员回收空瓶
 			log := make([]model.OperationLog, 0)
 			var user model.SysUser
@@ -265,11 +316,11 @@ func (e *GasCylinderStatus) Remove(c *dto.GasCylinderStatusDeleteReq, p *actions
 		}
 	}()
 
-	var carInfoModel model.GasCylinderStatus
+	var gasCylinderStatusModel model.GasCylinderStatus
 
 	// 查询钢瓶是否存在
-	err = e.Orm.Scopes(actions.Permission(carInfoModel.TableName(), p)).
-		First(&carInfoModel, c.GetId()).Error
+	err = e.Orm.Scopes(actions.Permission(gasCylinderStatusModel.TableName(), p)).
+		First(&gasCylinderStatusModel, c.GetId()).Error
 	if err != nil {
 		e.Log.Errorf("db error: %s", err)
 		if errors.Is(err, gorm.ErrRecordNotFound) {
@@ -278,7 +329,7 @@ func (e *GasCylinderStatus) Remove(c *dto.GasCylinderStatusDeleteReq, p *actions
 		return global.DeleteFailedErr
 	}
 
-	db := tx.Delete(&carInfoModel)
+	db := tx.Delete(&gasCylinderStatusModel)
 
 	if err = db.Error; err != nil {
 		e.Log.Errorf("db error: %s", err)
@@ -290,3 +341,41 @@ func (e *GasCylinderStatus) Remove(c *dto.GasCylinderStatusDeleteReq, p *actions
 
 	return nil
 }
+
+// Update 创建GasCylinderStatus对象
+func (e *GasCylinderStatus) Update(c *dto.GasCylinderStatusUpdateReq, p *actions.DataPermission) error {
+	var err error
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	for _, innerCode := range c.InnerCodeList {
+		var data model.GasCylinderStatus
+
+		err = e.Orm.
+			Where("inner_code = ? ", innerCode).
+			First(&data).Error
+
+		if err != nil {
+			e.Log.Errorf("db error: %s", err)
+			return global.GetFailedErr
+		}
+
+		if data.Status != c.Status {
+			data.Status = c.Status
+			data.UpdateBy = c.UpdateBy
+			err = tx.Save(&data).Error
+			if err != nil {
+				e.Log.Errorf("db error: %s", err)
+				return global.CreateFailedErr
+			}
+		}
+	}
+	return nil
+}

+ 291 - 0
app/admin/service/inspect_expand.go

@@ -0,0 +1,291 @@
+package service
+
+import (
+	"errors"
+	"fmt"
+	"gas-cylinder-api/app/admin/model"
+	"gas-cylinder-api/app/admin/service/dto"
+	"gas-cylinder-api/common/actions"
+	cDto "gas-cylinder-api/common/dto"
+	"gas-cylinder-api/common/global"
+	"gogs.baozhida.cn/zoie/OAuth-core/service"
+	"gorm.io/gorm"
+	"strconv"
+	"strings"
+)
+
+type InspectExpand struct {
+	service.Service
+}
+
+// GetPage 获取InspectExpand列表
+func (e *InspectExpand) GetPage(c *dto.InspectExpandGetPageReq, list *[]model.InspectExpand, count *int64, p *actions.DataPermission) error {
+	var err error
+	var data model.InspectExpand
+
+	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
+}
+
+// Insert 创建InspectExpand对象
+func (e *InspectExpand) Insert(c *dto.InspectExpandInsertReq, p *actions.DataPermission) error {
+	var err error
+	var data model.InspectExpand
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+	err = tx.Where("dept_id = ? and inspect_explain = ?", p.DeptId).First(&data).Error
+	if err == nil {
+		c.Id = data.Id
+		return nil
+	}
+
+	var inspectItem string
+	err = tx.Where("dept_id = ?", p.DeptId).Last(&data).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			inspectItem = "ITEM_1"
+		} else {
+			return global.CreateFailedErr
+		}
+	} else {
+		item, _ := strconv.Atoi(strings.Split(data.InspectItem, "_")[1])
+		inspectItem = fmt.Sprintf("ITEM_%d", item+1)
+	}
+	data.Id = 0
+	data.InspectItem = inspectItem
+	c.Generate(&data)
+	err = tx.Create(&data).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.CreateFailedErr
+	}
+
+	c.Id = data.Id
+
+	return nil
+
+}
+
+// Update 修改InspectExpand对象
+func (e *InspectExpand) Update(c *dto.InspectExpandInsertReq) error {
+	var err error
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	var InspectExpandModel = model.InspectExpand{}
+	// 查询入户安全检查项是否存在
+	err = e.Orm.First(&InspectExpandModel, 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.UpdateGenerate(&InspectExpandModel)
+	err = tx.Save(&InspectExpandModel).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.UpdateFailedErr
+	}
+
+	c.Id = InspectExpandModel.Id
+
+	return nil
+}
+
+// Init 初始化
+func (e *InspectExpand) Init(userId, deptId int) error {
+	var err error
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	inspectionItems := []model.InspectExpand{
+		{InspectItem: "ITEM_1", InspectExplain: "检查是否违规在地下室、卫生间或密闭的房间内存放使用瓶装液化气。"},
+		{InspectItem: "ITEM_2", InspectExplain: "检查液化气瓶、炉具使用或气瓶存放的房间内是否违反规定安床住人。"},
+		{InspectItem: "ITEM_3", InspectExplain: "检查液化气瓶、炉具使用或存放的房间上方是否搭建阁楼。"},
+		{InspectItem: "ITEM_4", InspectExplain: "检查液化气瓶、炉具使用或存放的房间内通风是否良好及加装换气装置。"},
+		{InspectItem: "ITEM_5", InspectExplain: "检查液化气瓶、炉具使用或存放的场所是否配备灭火器。"},
+		{InspectItem: "ITEM_6", InspectExplain: "检查液化气瓶存放间内是否按照国家规范安装燃气浓度报警仪装置。"},
+		{InspectItem: "ITEM_7", InspectExplain: "检查液化气瓶、炉具使用或存放处是否堆放易燃物及其它杂物。"},
+		{InspectItem: "ITEM_8", InspectExplain: "检查液化气瓶、炉具、软管是否放在不易碰撞且易操作检查的地方。"},
+		{InspectItem: "ITEM_9", InspectExplain: "检查液化气瓶是否摆放在密闭狭小的橱柜内使用。"},
+		{InspectItem: "ITEM_10", InspectExplain: "检查液化气炉具下方是否密闭及不具备通风条件。"},
+		{InspectItem: "ITEM_11", InspectExplain: "检查液化气瓶是否完好有效、开关是否正常无泄漏。"},
+		{InspectItem: "ITEM_12", InspectExplain: "检查燃气炉具工作性能正常,无破损、无泄漏,且开关完好正常。"},
+		{InspectItem: "ITEM_13", InspectExplain: "检查减压阀是否功能完好无破损,且安装到位无松动、无异常、无泄漏。"},
+		{InspectItem: "ITEM_14", InspectExplain: "检查连接软管是否完好无老化、龟裂、鼓包、破损、泄漏等现象。"},
+		{InspectItem: "ITEM_15", InspectExplain: "检查软管与炉具、减压阀连接处是否安装到位且卡子紧固无松动、无泄漏。"},
+		{InspectItem: "ITEM_16", InspectExplain: "检查连接软管有无加装三通、套管、穿墙或铺设顶棚、埋地等不易检查处。"},
+		{InspectItem: "ITEM_17", InspectExplain: "检查连接软管是否放置炉具底部靠近明火、高温或电源线路及电器处。"},
+		{InspectItem: "ITEM_18", InspectExplain: "检查气瓶护罩及气瓶周围是否堆放或悬挂杂物。"},
+		{InspectItem: "ITEM_19", InspectExplain: "检查气瓶是否与炉具、高温物体保持一定的安全间距。"},
+		{InspectItem: "ITEM_20", InspectExplain: "检查燃气热水器是否放置在卫生间或其它密闭不通风的房间内使用。"},
+		{InspectItem: "ITEM_21", InspectExplain: "检查燃气热水器或汤锅桶是否安装排烟管将废气引出室外。"},
+		{InspectItem: "ITEM_22", InspectExplain: "检查是否明确专人负责具体操作及日常安全巡查管理。"},
+	}
+
+	for i := 0; i < len(inspectionItems); i++ {
+		inspectionItems[i].CreateBy = userId
+		inspectionItems[i].DeptId = deptId
+	}
+
+	err = tx.Create(&inspectionItems).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return errors.New("初始化安全检查项失败")
+	}
+
+	return nil
+
+}
+
+// Init 初始化
+func (e *InspectExpand) DeleteByDeptId(deptId int) error {
+	var err error
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	inspectExpand := model.InspectExpand{}
+	err = tx.Where("dept_id = ?", deptId).Delete(&inspectExpand).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return errors.New("删除安全检查项失败")
+	}
+
+	return nil
+
+}
+
+// Remove 删除GasCylinderStatus
+func (e *InspectExpand) Remove(c *dto.InspectExpandDeleteReq, p *actions.DataPermission) error {
+	var err error
+
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	var inspectExpandModel model.InspectExpand
+
+	// 查询钢瓶是否存在
+	err = e.Orm.Scopes(actions.Permission(inspectExpandModel.TableName(), p)).
+		First(&inspectExpandModel, 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(&inspectExpandModel)
+
+	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 *InspectExpand) SyncStore(c *dto.InspectExpandSyncStoreReq, p *actions.DataPermission) error {
+	var err error
+	var data model.InspectExpand
+	var list []model.InspectExpand
+	tx := e.Orm.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	err = e.Orm.Model(&data).
+		Scopes(
+			actions.Permission(data.TableName(), p),
+		).
+		Find(&list).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return errors.New("获取安全检查项失败")
+	}
+	if len(list) == 0 {
+		return errors.New("暂无安全检查项可同步")
+	}
+	for _, storeId := range c.StoreIds {
+		if storeId == p.DeptId {
+			continue
+		}
+		inspectExpand := model.InspectExpand{}
+		err = tx.Where("dept_id = ?", storeId).Delete(&inspectExpand).Error
+		if err != nil {
+			e.Log.Errorf("db error: %s", err)
+			return errors.New("删除安全检查项失败")
+		}
+		inspectExpandList := []model.InspectExpand{}
+
+		for _, v := range list {
+			v.Id = 0
+			v.DeptId = storeId
+			v.CreateBy = p.UserId
+			inspectExpandList = append(inspectExpandList, v)
+		}
+
+		err = tx.Create(&inspectExpandList).Error
+		if err != nil {
+			e.Log.Errorf("db error: %s", err)
+			return errors.New("同步安全检查项失败")
+		}
+	}
+
+	return nil
+}

+ 1 - 1
app/admin/service/inspect_record.go

@@ -173,7 +173,7 @@ func (e *InspectRecord) Update(c *dto.InspectRecordInsertReq) error {
 	}()
 
 	var inspectRecordModel = model.InspectRecord{}
-	// 查询角色是否存在
+	// 查询入户安全检查是否存在
 	err = e.Orm.First(&inspectRecordModel, c.GetId()).Error
 	if err != nil {
 		e.Log.Errorf("db error: %s", err)

+ 35 - 7
app/admin/service/operation_log.go

@@ -90,6 +90,10 @@ func (e *OperationLog) Insert(c *dto.OperationLogInsertReq, p *actions.DataPermi
 			tx.Commit()
 		}
 	}()
+
+	batchNumber := fmt.Sprintf("%03d%s", p.DeptId, time.Now().Format("20060102150405"))
+	optTime := time.Now().Format("2006-01-02 15:04:05")
+
 	switch c.OptType {
 	case "25", "27":
 		// 送气员领重瓶
@@ -103,6 +107,7 @@ func (e *OperationLog) Insert(c *dto.OperationLogInsertReq, p *actions.DataPermi
 			//	return global.CreateFailedErr
 			//}
 			operationLog := model.OperationLog{
+				BatchNumber: batchNumber,
 				ProvOperationLog: model.ProvOperationLog{
 					InnerCode:         chipUid,
 					OptType:           c.OptType,
@@ -113,7 +118,7 @@ func (e *OperationLog) Insert(c *dto.OperationLogInsertReq, p *actions.DataPermi
 					CurrentStore:      user.Dept.CmpCode,
 					Lng:               utils.ToString(user.Dept.ProvStore.Lng),
 					Lat:               utils.ToString(user.Dept.ProvStore.Lat),
-					OptTime:           time.Now().Format("2006-01-02 15:04:05"),
+					OptTime:           optTime,
 				},
 				ControlBy: cModel.ControlBy{
 					CreateBy: p.UserId,
@@ -165,6 +170,7 @@ func (e *OperationLog) Insert(c *dto.OperationLogInsertReq, p *actions.DataPermi
 			}
 
 			operationLog := model.OperationLog{
+				BatchNumber: batchNumber,
 				ProvOperationLog: model.ProvOperationLog{
 					InnerCode:         chipUid,
 					OptType:           c.OptType,
@@ -175,7 +181,7 @@ func (e *OperationLog) Insert(c *dto.OperationLogInsertReq, p *actions.DataPermi
 					CurrentStore:      user.ProvUser.CmpCode,
 					Lng:               utils.ToString(user.Dept.ProvStore.Lng),
 					Lat:               utils.ToString(user.Dept.ProvStore.Lat),
-					OptTime:           time.Now().Format("2006-01-02 15:04:05"),
+					OptTime:           optTime,
 				},
 				ControlBy: cModel.ControlBy{
 					CreateBy: p.UserId,
@@ -206,6 +212,7 @@ func (e *OperationLog) Insert(c *dto.OperationLogInsertReq, p *actions.DataPermi
 				return errors.New("获取车辆信息失败")
 			}
 			operationLog := model.OperationLog{
+				BatchNumber: batchNumber,
 				ProvOperationLog: model.ProvOperationLog{
 					InnerCode:  chipUid,
 					OptType:    c.OptType,
@@ -216,7 +223,7 @@ func (e *OperationLog) Insert(c *dto.OperationLogInsertReq, p *actions.DataPermi
 					//CurrentStore:      user.ProvUser.CmpCode,
 					CurrentTruck: user.ProvUserId,
 					CurrentMotor: truckUserCarInfo.CarNo,
-					OptTime:      time.Now().Format("2006-01-02 15:04:05"),
+					OptTime:      optTime,
 				},
 				ControlBy: cModel.ControlBy{
 					CreateBy: p.UserId,
@@ -253,6 +260,7 @@ func (e *OperationLog) Insert(c *dto.OperationLogInsertReq, p *actions.DataPermi
 			//}
 
 			operationLog := model.OperationLog{
+				BatchNumber: batchNumber,
 				ProvOperationLog: model.ProvOperationLog{
 					InnerCode:         chipUid,
 					OptType:           c.OptType,
@@ -264,7 +272,7 @@ func (e *OperationLog) Insert(c *dto.OperationLogInsertReq, p *actions.DataPermi
 					CurrentStation: user.ProvUser.CmpCode,
 					Lng:            utils.ToString(user.Dept.ProvStore.Lng),
 					Lat:            utils.ToString(user.Dept.ProvStore.Lat),
-					OptTime:        time.Now().Format("2006-01-02 15:04:05"),
+					OptTime:        optTime,
 				},
 				ControlBy: cModel.ControlBy{
 					CreateBy: p.UserId,
@@ -285,7 +293,17 @@ func (e *OperationLog) Insert(c *dto.OperationLogInsertReq, p *actions.DataPermi
 	err = e.UpdateGasCylinderStatus(tx, c, user, p)
 	if err != nil {
 		e.Log.Errorf("更新钢瓶状态失败: %s", err)
-		return global.CreateFailedErr
+		return errors.New("更新气瓶状态失败")
+	}
+
+	// 更新钢瓶最新流转步骤时间
+	err = tx.Model(&model.GasCylinder{}).Where("inner_code in (?) ", c.ChipUidList).
+		Updates(map[string]interface{}{
+			"last_operation_time": time.Now(),
+		}).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return errors.New("更新钢瓶最新流转步骤时间失败")
 	}
 
 	// TODO 同步省平台 1.1.1.22  批量新增操作记录
@@ -547,6 +565,16 @@ func (e *OperationLog) UpdateGasCylinderStatus(tx *gorm.DB, c *dto.OperationLogI
 			e.Log.Errorf("db error: %s", err)
 			return global.CreateFailedErr
 		}
+		// 更新钢瓶充装记录
+		err = tx.Model(&model.GasCylinder{}).Where("inner_code in (?) ", c.ChipUidList).
+			Updates(map[string]interface{}{
+				"station_name": user.Dept.Name,
+				"fill_time":    time.Now().Format("2006-01-02 15:04:05"),
+			}).Error
+		if err != nil {
+			e.Log.Errorf("db error: %s", err)
+			return global.CreateFailedErr
+		}
 
 	case "16":
 		// 司机讲订单(重瓶)退回气站 删除司机重瓶
@@ -821,8 +849,8 @@ func InsertOperationLogByOptType26Or36(tx *gorm.DB, OptType string, chipUids []s
 
 }
 
-// ListByUid 通过uid获取OperationLog列表
-func (e *OperationLog) ListByUid(InnerCode string, list *[]model.OperationLog) error {
+// ListByInnerCode 通过uid获取OperationLog列表
+func (e *OperationLog) ListByInnerCode(InnerCode string, list *[]model.OperationLog) error {
 	var err error
 	var data model.OperationLog
 

+ 10 - 2
app/admin/service/order.go

@@ -27,7 +27,7 @@ func (e *Order) GetPage(c *dto.OrderGetPageReq, list *[]model.Order, count *int6
 		Scopes(
 			cDto.MakeCondition(c.GetNeedSearch()),
 			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
-			actions.Permission(data.TableName(), p),
+			OrderDeptIdScopes(p.DeptId),
 			OrderStateScopes(c.State),
 		).
 		Preload("Customer").Preload("Store").Preload("User").Preload("Goods").Preload("Spec").
@@ -40,6 +40,14 @@ func (e *Order) GetPage(c *dto.OrderGetPageReq, list *[]model.Order, count *int6
 	return nil
 }
 
+// 创建订单门店和配送门店都可以查看订单
+func OrderDeptIdScopes(deptId int) func(db *gorm.DB) *gorm.DB {
+
+	return func(db *gorm.DB) *gorm.DB {
+		return db.Where("dept_id = ? or store_id = ?", deptId, deptId)
+	}
+}
+
 func OrderStateScopes(state int) func(db *gorm.DB) *gorm.DB {
 
 	return func(db *gorm.DB) *gorm.DB {
@@ -411,7 +419,7 @@ func (e *Order) Delivery(c *dto.OrderDeliveryReq, p *actions.DataPermission) err
 
 	var orderModel = model.Order{}
 	// 查询订单是否存在
-	err = e.Orm.Scopes(actions.Permission(orderModel.TableName(), p)).
+	err = e.Orm.Scopes(OrderDeptIdScopes(p.DeptId)).
 		First(&orderModel, c.GetId()).Error
 	if err != nil {
 		e.Log.Errorf("db error: %s", err)

+ 34 - 19
app/admin/service/store.go

@@ -12,20 +12,18 @@ import (
 	"math/rand"
 	"time"
 
-	"gorm.io/gorm"
-	"gorm.io/gorm/clause"
-
 	"gas-cylinder-api/app/admin/model"
 	"gas-cylinder-api/app/admin/service/dto"
 	"gogs.baozhida.cn/zoie/OAuth-core/pkg"
+	"gorm.io/gorm"
 )
 
 type Store struct {
 	service.Service
 }
 
+// 获取所有上级目录
 func InDeptIdScopes(deptId int) func(db *gorm.DB) *gorm.DB {
-
 	return func(db *gorm.DB) *gorm.DB {
 		if deptId == 0 {
 			return db
@@ -38,6 +36,20 @@ func InDeptIdScopes(deptId int) func(db *gorm.DB) *gorm.DB {
 	}
 }
 
+// 获取顶级公司下所有子公司
+func InRootCompanyIdsScopes(deptId int) func(db *gorm.DB) *gorm.DB {
+	return func(db *gorm.DB) *gorm.DB {
+		if deptId == 0 {
+			return db
+		}
+		ids, err := model.GetRootCompanyIds(deptId)
+		if err != nil {
+			return db
+		}
+		return db.Where("dept_id in (?)", ids)
+	}
+}
+
 // Get 获取SysDept对象
 func (e *Store) Get(d *dto.StoreGetReq, deptModel *model.SysDept) error {
 	err := e.Orm.
@@ -89,7 +101,11 @@ func (e *Store) Insert(c *dto.StoreInsertReq, deptId int) error {
 	deptPath := pkg.IntToString(data.Id) + "/"
 	if data.ParentId != 0 {
 		var deptP model.SysDept
-		tx.First(&deptP, data.ParentId)
+		err = tx.First(&deptP, data.ParentId).Error
+		if err != nil {
+			e.Log.Errorf("db error: %s", err)
+			return errors.New("获取父级信息失败")
+		}
 		deptPath = deptP.Path + deptPath
 	} else {
 		deptPath = "/0/" + deptPath
@@ -171,30 +187,29 @@ func (e *Store) Remove(d *dto.StoreDeleteReq, p *actions.DataPermission) error {
 	}
 
 	var deptList = make([]model.SysDept, 0)
-	var deptIds = make([]int, 0)
-	tx.Where("path like ?", dept.Path+"%").Find(&deptList)
+	var subDeptIds = make([]int, 0)
+	err = tx.Where("path like ?", dept.Path+"%").Find(&deptList).Error
+	if err != nil {
+		e.Log.Errorf("Delete User error: %s", err)
+		return errors.New("查询子门店失败!")
+	}
 
 	// 获取部门及其子部门下ID
 	for _, v := range deptList {
-		deptIds = append(deptIds, v.Id)
+		if v.Id != dept.Id {
+			subDeptIds = append(subDeptIds, v.Id)
+		}
 	}
 
-	db := tx.Select(clause.Associations).Delete(&deptList)
+	if len(subDeptIds) > 0 {
+		return errors.New("请先删除子门店!")
+	}
+	db := tx.Delete(&dept)
 	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
 }
 

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

@@ -387,3 +387,63 @@ func (e *SysUser) GetProfile(c *dto.SysUserById, user *model.SysUser) error {
 
 	return nil
 }
+
+func SysUserOptTypeScopes(optType string) func(db *gorm.DB) *gorm.DB {
+
+	return func(db *gorm.DB) *gorm.DB {
+		switch optType {
+		// 查询司机
+		case "17", "033", "11":
+			//司机确认重瓶从气站出库17
+			//司机确认重瓶从门店出库033
+			//司机确认空瓶装车11
+			db.Where("JSON_EXTRACT(prov_user, '$.userType') = 4 and JSON_EXTRACT(prov_user, '$.isorders') = 0")
+		// 查询库管
+		case "31", "35", "21":
+			//门店确认重瓶卸货入库31
+			//门店确认未配送重瓶返库35
+			//门店回收空瓶21
+			db.Where("JSON_EXTRACT(prov_user, '$.userType') = 3 and JSON_EXTRACT(prov_user, '$.isorders') = 1")
+		// 查询气站
+		case "016", "13":
+			//气站确认重瓶到达气站016
+			//气站确认空瓶到达气站13
+			db.Where("JSON_EXTRACT(prov_user, '$.userType') = 5 and JSON_EXTRACT(prov_user, '$.isorders') = 0")
+		// 查询送气员 送气员领重瓶出库25
+		case "25":
+			db.Where("JSON_EXTRACT(prov_user, '$.userType') = 3 and JSON_EXTRACT(prov_user, '$.isorders') = 0")
+		// 查询门店
+		case "mdscrap", "mdextended":
+			db.Where("JSON_EXTRACT(prov_user, '$.userType') = 3 and JSON_EXTRACT(prov_user, '$.isorders') = 1")
+		// 查询气站
+		case "qzscrap", "qzextended":
+			db.Where("JSON_EXTRACT(prov_user, '$.userType') = 5 and JSON_EXTRACT(prov_user, '$.isorders') = 0")
+		// 查询司机
+		case "sjscrap", "sjextended":
+			db.Where("JSON_EXTRACT(prov_user, '$.userType') = 4 and JSON_EXTRACT(prov_user, '$.isorders') = 0")
+		}
+		return db
+	}
+}
+
+// GetPageByOptType 通过OptType获取用户信息
+func (e *SysUser) GetPageByOptType(c *dto.SysUserGetPageByOptTypeReq, list *[]model.SysUser, count *int64) error {
+	var err error
+	//var data model.SysUser
+
+	err = e.Orm.
+		Scopes(
+			cDto.MakeCondition(c.GetNeedSearch()),
+			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
+			SysUserOptTypeScopes(c.OptType),
+		).
+		Preload("Dept").
+		Find(&list).Limit(-1).Offset(-1).
+		Count(count).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+
+	return nil
+}

+ 14 - 17
app/admin/service/truck_enterprise.go

@@ -11,12 +11,10 @@ import (
 	"gogs.baozhida.cn/zoie/OAuth-core/service"
 	"time"
 
-	"gorm.io/gorm"
-	"gorm.io/gorm/clause"
-
 	"gas-cylinder-api/app/admin/model"
 	"gas-cylinder-api/app/admin/service/dto"
 	"gogs.baozhida.cn/zoie/OAuth-core/pkg"
+	"gorm.io/gorm"
 )
 
 type TruckEnterprise struct {
@@ -160,30 +158,29 @@ func (e TruckEnterprise) Remove(d *dto.TruckEnterpriseDeleteReq, p *actions.Data
 	}
 
 	var deptList = make([]model.SysDept, 0)
-	var deptIds = make([]int, 0)
-	tx.Where("path like ?", dept.Path+"%").Find(&deptList)
+	var subDeptIds = make([]int, 0)
+	err = tx.Where("path like ?", dept.Path+"%").Find(&deptList).Error
+	if err != nil {
+		e.Log.Errorf("Delete User error: %s", err)
+		return errors.New("查询子门店失败!")
+	}
 
 	// 获取部门及其子部门下ID
 	for _, v := range deptList {
-		deptIds = append(deptIds, v.Id)
+		if v.Id != dept.Id {
+			subDeptIds = append(subDeptIds, v.Id)
+		}
 	}
 
-	db := tx.Select(clause.Associations).Delete(&deptList)
+	if len(subDeptIds) > 0 {
+		return errors.New("请先删除子门店!")
+	}
+	db := tx.Delete(&dept)
 	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
 }
 

+ 13 - 13
app/admin/service/warehouse.go

@@ -36,10 +36,10 @@ func (e *Warehouse) GetPage(c *dto.WarehouseGetPageReq, list *[]model.Warehouse,
 }
 
 // Get 获取Warehouse对象
-func (e *Warehouse) Get(d *dto.WarehouseGetReq, carInfoModel *model.Warehouse, p *actions.DataPermission) error {
+func (e *Warehouse) Get(d *dto.WarehouseGetReq, warehouseModel *model.Warehouse, p *actions.DataPermission) error {
 	err := e.Orm.
-		Scopes(actions.Permission(carInfoModel.TableName(), p)).
-		First(carInfoModel, d.GetId()).Error
+		Scopes(actions.Permission(warehouseModel.TableName(), p)).
+		First(warehouseModel, d.GetId()).Error
 
 	if err != nil {
 		e.Log.Errorf("db error: %s", err)
@@ -91,10 +91,10 @@ func (e *Warehouse) Update(c *dto.WarehouseUpdateReq, p *actions.DataPermission)
 		}
 	}()
 
-	var carInfoModel = model.Warehouse{}
+	var warehouseModel = model.Warehouse{}
 	// 查询角色是否存在
-	err = e.Orm.Scopes(actions.Permission(carInfoModel.TableName(), p)).
-		First(&carInfoModel, c.GetId()).Error
+	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) {
@@ -103,14 +103,14 @@ func (e *Warehouse) Update(c *dto.WarehouseUpdateReq, p *actions.DataPermission)
 		return global.UpdateFailedErr
 	}
 
-	c.Generate(&carInfoModel)
-	err = tx.Save(&carInfoModel).Error
+	c.Generate(&warehouseModel)
+	err = tx.Save(&warehouseModel).Error
 	if err != nil {
 		e.Log.Errorf("db error: %s", err)
 		return global.UpdateFailedErr
 	}
 
-	c.Id = carInfoModel.Id
+	c.Id = warehouseModel.Id
 
 	return nil
 }
@@ -128,11 +128,11 @@ func (e *Warehouse) Remove(c *dto.WarehouseDeleteReq, p *actions.DataPermission)
 		}
 	}()
 
-	var carInfoModel model.Warehouse
+	var warehouseModel model.Warehouse
 
 	// 查询角色是否存在
-	err = e.Orm.Scopes(actions.Permission(carInfoModel.TableName(), p)).
-		First(&carInfoModel, c.GetId()).Error
+	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) {
@@ -141,7 +141,7 @@ func (e *Warehouse) Remove(c *dto.WarehouseDeleteReq, p *actions.DataPermission)
 		return global.DeleteFailedErr
 	}
 
-	db := tx.Delete(&carInfoModel)
+	db := tx.Delete(&warehouseModel)
 
 	if err = db.Error; err != nil {
 		e.Log.Errorf("db error: %s", err)

+ 72 - 0
app/jobs/controller/sys_job.go

@@ -0,0 +1,72 @@
+package controller
+
+import (
+	"gas-cylinder-api/common/dto"
+	"gogs.baozhida.cn/zoie/OAuth-core/api"
+	toolsConfig "gogs.baozhida.cn/zoie/OAuth-core/sdk/config"
+	"net/http"
+
+	"github.com/gin-gonic/gin"
+
+	"gas-cylinder-api/app/jobs/service"
+	_ "gogs.baozhida.cn/zoie/OAuth-core/pkg/response"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk"
+)
+
+type SysJob struct {
+	api.Api
+}
+
+// RemoveJobForService 调用service实现
+func (e SysJob) RemoveJobForService(c *gin.Context) {
+	v := dto.GeneralDelDto{}
+	s := service.SysJob{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&v, nil).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, "")
+		return
+	}
+
+	s.Cron = sdk.Runtime.GetCrontabKey(toolsConfig.ApplicationConfig.Host)
+	err = s.RemoveJob(&v)
+	if err != nil {
+		e.Logger.Errorf("RemoveJob error, %s", err.Error())
+		e.Error(500, err, "")
+		return
+	}
+	e.OK(nil, s.Msg)
+}
+
+// StartJobForService 启动job service实现
+func (e SysJob) StartJobForService(c *gin.Context) {
+	e.MakeContext(c)
+	log := e.GetLogger()
+	db, err := e.GetOrm()
+	if err != nil {
+		log.Error(err)
+		return
+	}
+	var v dto.GeneralGetDto
+	err = c.BindUri(&v)
+	if err != nil {
+		log.Warnf("参数验证错误, error: %s", err)
+		e.Error(http.StatusUnprocessableEntity, err, "参数验证失败")
+		return
+	}
+	s := service.SysJob{}
+	s.Orm = db
+	s.Log = log
+	s.Cron = sdk.Runtime.GetCrontabKey(toolsConfig.ApplicationConfig.Host)
+	err = s.StartJob(&v)
+	if err != nil {
+		log.Errorf("GetCrontabKey error, %s", err.Error())
+		e.Error(500, err, err.Error())
+		return
+	}
+	e.OK(nil, s.Msg)
+}

+ 205 - 0
app/jobs/jobbase.go

@@ -0,0 +1,205 @@
+package jobs
+
+import (
+	"fmt"
+	"github.com/robfig/cron/v3"
+	"gorm.io/gorm"
+	"sync"
+	"time"
+
+	models2 "gas-cylinder-api/app/jobs/model"
+	log "gogs.baozhida.cn/zoie/OAuth-core/logger"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg"
+	"gogs.baozhida.cn/zoie/OAuth-core/pkg/cronjob"
+	"gogs.baozhida.cn/zoie/OAuth-core/sdk"
+)
+
+var timeFormat = "2006-01-02 15:04:05"
+var retryCount = 3
+
+var jobList map[string]JobsExec
+var lock sync.Mutex
+
+type JobCore struct {
+	InvokeTarget   string
+	Name           string
+	JobId          int
+	EntryId        int
+	CronExpression string
+	Args           string
+}
+
+// 任务类型 http
+type HttpJob struct {
+	JobCore
+}
+
+type ExecJob struct {
+	JobCore
+}
+
+func (e *ExecJob) Run() {
+	startTime := time.Now()
+	var obj = jobList[e.InvokeTarget]
+	if obj == nil {
+		log.Warn("[Job] ExecJob Run job nil")
+		return
+	}
+	err := CallExec(obj.(JobsExec), e.Args)
+	if err != nil {
+		// 如果失败暂停一段时间重试
+		fmt.Println(time.Now().Format(timeFormat), " [ERROR] mission failed! ", err)
+	}
+	// 结束时间
+	endTime := time.Now()
+
+	// 执行时间
+	latencyTime := endTime.Sub(startTime)
+	//TODO: 待完善部分
+	//str := time.Now().Format(timeFormat) + " [INFO] JobCore " + string(e.EntryId) + "exec success , spend :" + latencyTime.String()
+	//ws.SendAll(str)
+	log.Infof("[Job] JobCore %s exec success , spend :%v", e.Name, latencyTime)
+	return
+}
+
+// http 任务接口
+func (h *HttpJob) Run() {
+
+	startTime := time.Now()
+	var count = 0
+	var err error
+	var str string
+	/* 循环 */
+LOOP:
+	if count < retryCount {
+		/* 跳过迭代 */
+		str, err = pkg.Get(h.InvokeTarget)
+		if err != nil {
+			// 如果失败暂停一段时间重试
+			fmt.Println(time.Now().Format(timeFormat), " [ERROR] mission failed! ", err)
+			fmt.Printf(time.Now().Format(timeFormat)+" [INFO] Retry after the task fails %d seconds! %s \n", (count+1)*5, str)
+			time.Sleep(time.Duration(count+1) * 5 * time.Second)
+			count = count + 1
+			goto LOOP
+		}
+	}
+	// 结束时间
+	endTime := time.Now()
+
+	// 执行时间
+	latencyTime := endTime.Sub(startTime)
+	//TODO: 待完善部分
+
+	log.Infof("[Job] JobCore %s exec success , spend :%v", h.Name, latencyTime)
+	return
+}
+
+// 初始化
+func Setup(dbs map[string]*gorm.DB) {
+
+	fmt.Println(time.Now().Format(timeFormat), " [INFO] JobCore Starting...")
+
+	for k, db := range dbs {
+		sdk.Runtime.SetCrontab(k, cronjob.NewWithSeconds())
+		setup(k, db)
+	}
+}
+
+func setup(key string, db *gorm.DB) {
+	crontab := sdk.Runtime.GetCrontabKey(key)
+	sysJob := models2.SysJob{}
+	jobs := make([]models2.SysJob, 0)
+	err := sysJob.GetList(db, &jobs)
+	if err != nil {
+		fmt.Println(time.Now().Format(timeFormat), " [ERROR] JobCore init error", err)
+	}
+	if len(jobs) == 0 {
+		fmt.Println(time.Now().Format(timeFormat), " [INFO] JobCore total:0")
+	}
+
+	_, err = sysJob.RemoveAllEntryID(db)
+	if err != nil {
+		fmt.Println(time.Now().Format(timeFormat), " [ERROR] JobCore remove entry_id error", err)
+	}
+
+	for i := 0; i < len(jobs); i++ {
+		if !jobs[i].Auto {
+			continue
+		}
+		if jobs[i].JobType == 1 {
+			j := &HttpJob{}
+			j.InvokeTarget = jobs[i].InvokeTarget
+			j.CronExpression = jobs[i].CronExpression
+			j.JobId = jobs[i].JobId
+			j.Name = jobs[i].JobName
+
+			sysJob.EntryId, err = AddJob(crontab, j)
+		} else if jobs[i].JobType == 2 {
+			j := &ExecJob{}
+			j.InvokeTarget = jobs[i].InvokeTarget
+			j.CronExpression = jobs[i].CronExpression
+			j.JobId = jobs[i].JobId
+			j.Name = jobs[i].JobName
+			j.Args = jobs[i].Args
+			sysJob.EntryId, err = AddJob(crontab, j)
+		}
+		err = sysJob.Update(db, jobs[i].JobId)
+	}
+
+	// 启动任务
+	crontab.Start()
+	fmt.Println(time.Now().Format(timeFormat), " [INFO] JobCore start success.")
+	// 关闭任务
+	defer crontab.Stop()
+	select {}
+}
+
+// 添加任务 AddJob(invokeTarget string, jobId int, jobName string, cronExpression string)
+func AddJob(c *cron.Cron, job Job) (int, error) {
+	if job == nil {
+		fmt.Println("unknown")
+		return 0, nil
+	}
+	return job.addJob(c)
+}
+
+func (h *HttpJob) addJob(c *cron.Cron) (int, error) {
+	id, err := c.AddJob(h.CronExpression, h)
+	if err != nil {
+		fmt.Println(time.Now().Format(timeFormat), " [ERROR] JobCore AddJob error", err)
+		return 0, err
+	}
+	EntryId := int(id)
+	return EntryId, nil
+}
+
+func (h *ExecJob) addJob(c *cron.Cron) (int, error) {
+	id, err := c.AddJob(h.CronExpression, h)
+	if err != nil {
+		fmt.Println(time.Now().Format(timeFormat), " [ERROR] JobCore AddJob error", err)
+		return 0, err
+	}
+	EntryId := int(id)
+	return EntryId, nil
+}
+
+// 移除任务
+func Remove(c *cron.Cron, entryID int) chan bool {
+	ch := make(chan bool)
+	go func() {
+		c.Remove(cron.EntryID(entryID))
+		fmt.Println(time.Now().Format(timeFormat), " [INFO] JobCore Remove success ,info entryID :", entryID)
+		ch <- true
+	}()
+	return ch
+}
+
+// 任务停止
+//func Stop() chan bool {
+//	ch := make(chan bool)
+//	go func() {
+//		global.GADMCron.Stop()
+//		ch <- true
+//	}()
+//	return ch
+//}

+ 140 - 0
app/jobs/jobs.go

@@ -0,0 +1,140 @@
+package jobs
+
+import (
+	"fmt"
+	sysModel "gas-cylinder-api/app/admin/model"
+	"gas-cylinder-api/common/global"
+	"gas-cylinder-api/db"
+	"github.com/gin-gonic/gin"
+	log "gogs.baozhida.cn/zoie/OAuth-core/logger"
+	"time"
+)
+
+// 需要将定义的struct 添加到字典中;
+// 字典 key 可以配置到 自动任务 调用目标 中;
+func InitJob() {
+	jobList = map[string]JobsExec{
+		//"ExamplesOne": ExamplesOne{},
+		//"CheckDeptSigned": CheckDeptSigned{},
+		"UpdateGasCylinderAllotStatus": UpdateGasCylinderAllotStatus{},
+		"UpdateGasCylinderStatus":      UpdateGasCylinderStatus{},
+	}
+}
+
+// 新添加的job 必须按照以下格式定义,并实现Exec函数
+type ExamplesOne struct {
+}
+
+func (t ExamplesOne) Exec(arg interface{}) error {
+	str := time.Now().Format(timeFormat) + " [INFO] JobCore ExamplesOne exec success"
+	// TODO: 这里需要注意 Examples 传入参数是 string 所以 arg.(string);请根据对应的类型进行转化;
+	switch arg.(type) {
+
+	case string:
+		if arg.(string) != "" {
+			fmt.Println("string", arg.(string))
+			fmt.Println(str, arg.(string))
+		} else {
+			fmt.Println("arg is nil")
+			fmt.Println(str, "arg is nil")
+		}
+		break
+	}
+
+	return nil
+}
+
+type CheckDeptSigned struct {
+}
+
+//// 检查机构签约是否过期
+//func (t CheckDeptSigned) Exec(arg interface{}) error {
+//
+//	organList := make([]sysModel.SysDept, 0)
+//	// GetOrm 获取orm连接
+//	orm, _ := db.GetOrm(&gin.Context{})
+//
+//	err := orm.Find(&organList).Error
+//	if err != nil {
+//		log.Errorf("db error: %s", err)
+//		return global.GetFailedErr
+//	}
+//
+//	for _, organ := range organList {
+//		// 未签约或已过期不处理
+//		if organ.IsSigned == cmodel.DeptNotSigned || organ.IsSigned == cmodel.DeptExpired {
+//			continue
+//		}
+//		expiredDate, _ := time.Parse("2006-01-02 15:04:05", organ.ExpiredDate+" 23:59:59")
+//		// 已过期
+//		if time.Now().After(expiredDate) {
+//			organ.IsSigned = cmodel.DeptExpired
+//			if err := orm.Save(&organ).Error; err != nil {
+//				log.Errorf("db error: %s", err)
+//				return global.UpdateFailedErr
+//			}
+//		}
+//	}
+//
+//	return nil
+//
+//}
+
+// 修改扫码调拨状态
+type UpdateGasCylinderAllotStatus struct {
+}
+
+// 统计冰排冷冻时长
+func (t UpdateGasCylinderAllotStatus) Exec(arg interface{}) error {
+
+	gasCylinderAllotList := make([]sysModel.GasCylinderAllot, 0)
+	// GetOrm 获取orm连接
+	orm, _ := db.GetOrm(&gin.Context{})
+
+	err := orm.Where("status = ? and allot_type = 1", sysModel.GasCylinderAllotStateAllot).
+		Find(&gasCylinderAllotList).Error
+	if err != nil {
+		log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+
+	for _, allot := range gasCylinderAllotList {
+
+		createdAt := allot.CreatedAt.Local()
+		if createdAt.Add(time.Minute * 10).Before(time.Now()) {
+			// 扫码调拨超过10分钟 自动取消
+			allot.Status = sysModel.GasCylinderAllotStateTimeoutCancel
+		}
+
+		if err = orm.Save(&allot).Error; err != nil {
+			log.Errorf("db error: %s", err)
+			return global.UpdateFailedErr
+		}
+
+	}
+
+	return nil
+
+}
+
+type UpdateGasCylinderStatus struct {
+}
+
+// 修改钢瓶状态
+func (t UpdateGasCylinderStatus) Exec(arg interface{}) error {
+
+	// GetOrm 获取orm连接
+	orm, _ := db.GetOrm(&gin.Context{})
+	sixMonthsAgo := time.Now().AddDate(0, -6, 0)
+	err := orm.Model(&sysModel.GasCylinder{}).Where("last_operation_time < ?", sixMonthsAgo).
+		Updates(map[string]interface{}{
+			"status": "半年未流转",
+		}).Error
+	if err != nil {
+		log.Errorf("db error: %s", err)
+		return global.GetFailedErr
+	}
+
+	return nil
+
+}

+ 62 - 0
app/jobs/model/sys_job.go

@@ -0,0 +1,62 @@
+package model
+
+import (
+	model2 "gas-cylinder-api/common/model"
+	"gorm.io/gorm"
+)
+
+type SysJob struct {
+	JobId          int    `json:"jobId" gorm:"primaryKey;autoIncrement"` // 编码
+	JobName        string `json:"jobName" gorm:"size:255;"`              // 名称
+	JobGroup       string `json:"jobGroup" gorm:"size:255;"`             // 任务分组
+	JobType        int    `json:"jobType" gorm:"size:1;"`                // 任务类型
+	CronExpression string `json:"cronExpression" gorm:"size:255;"`       // cron表达式
+	InvokeTarget   string `json:"invokeTarget" gorm:"size:255;"`         // 调用目标
+	Args           string `json:"args" gorm:"size:255;"`                 // 目标参数
+	MisfirePolicy  int    `json:"misfirePolicy" gorm:"size:255;"`        // 执行策略
+	Concurrent     int    `json:"concurrent" gorm:"size:1;"`             // 是否并发
+	Status         int    `json:"status" gorm:"size:1;"`                 // 状态
+	EntryId        int    `json:"entry_id" gorm:"size:11;"`              // job启动时返回的id
+	Auto           bool   `json:"auto" gorm:"size:4;"`                   // 是否开机自启动
+	model2.ControlBy
+	model2.ModelTime
+
+	DataScope string `json:"dataScope" gorm:"-"`
+}
+
+func (SysJob) TableName() string {
+	return "sys_job"
+}
+
+func (e *SysJob) Generate() model2.ActiveRecord {
+	o := *e
+	return &o
+}
+
+func (e *SysJob) GetId() interface{} {
+	return e.JobId
+}
+
+func (e *SysJob) SetCreateBy(createBy int) {
+	e.CreateBy = createBy
+}
+
+func (e *SysJob) SetUpdateBy(updateBy int) {
+	e.UpdateBy = updateBy
+}
+
+func (e *SysJob) GetList(tx *gorm.DB, list interface{}) (err error) {
+	return tx.Table(e.TableName()).Where("status = ?", 2).Find(list).Error
+}
+
+// 更新SysJob
+func (e *SysJob) Update(tx *gorm.DB, id interface{}) (err error) {
+	return tx.Table(e.TableName()).Where(id).Updates(&e).Error
+}
+
+func (e *SysJob) RemoveAllEntryID(tx *gorm.DB) (update SysJob, err error) {
+	if err = tx.Table(e.TableName()).Where("entry_id > ?", 0).Update("entry_id", 0).Error; err != nil {
+		return
+	}
+	return
+}

+ 35 - 0
app/jobs/router/int_router.go

@@ -0,0 +1,35 @@
+package router
+
+import (
+	common "gas-cylinder-api/common/middleware"
+	"os"
+
+	"github.com/gin-gonic/gin"
+	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)
+	}
+
+	authMiddleware, err := common.AuthInit()
+	if err != nil {
+		log.Fatalf("JWT Init Error, %s", err.Error())
+	}
+
+	// 注册业务路由
+	initRouter(r, authMiddleware)
+}

+ 42 - 0
app/jobs/router/router.go

@@ -0,0 +1,42 @@
+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)
+)
+
+// initRouter 路由示例
+func initRouter(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware) *gin.Engine {
+
+	// 无需认证的路由
+	noCheckRoleRouter(r)
+	// 需要认证的路由
+	checkRoleRouter(r, authMiddleware)
+
+	return r
+}
+
+// noCheckRoleRouter 无需认证的路由示例
+func noCheckRoleRouter(r *gin.Engine) {
+	// 可根据业务需求来设置接口版本
+	v1 := r.Group("/api")
+
+	for _, f := range routerNoCheckRole {
+		f(v1)
+	}
+}
+
+// checkRoleRouter 需要认证的路由示例
+func checkRoleRouter(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware) {
+	// 可根据业务需求来设置接口版本
+	v1 := r.Group("/api")
+
+	for _, f := range routerCheckRole {
+		f(v1, authMiddleware)
+	}
+}

+ 39 - 0
app/jobs/router/sys_job.go

@@ -0,0 +1,39 @@
+package router
+
+import (
+	actions2 "gas-cylinder-api/common/actions"
+	"gas-cylinder-api/common/middleware"
+	"github.com/gin-gonic/gin"
+
+	"gas-cylinder-api/app/jobs/controller"
+	"gas-cylinder-api/app/jobs/model"
+	"gas-cylinder-api/app/jobs/service/dto"
+	jwt "gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth"
+)
+
+func init() {
+	routerCheckRole = append(routerCheckRole, registerSysJobRouter)
+}
+
+// 需认证的路由代码
+func registerSysJobRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
+
+	r := v1.Group("/sys-job").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
+	{
+		sysJob := &model.SysJob{}
+		r.GET("", actions2.PermissionAction(), actions2.IndexAction(sysJob, new(dto.SysJobSearch), func() interface{} {
+			list := make([]model.SysJob, 0)
+			return &list
+		}))
+		r.GET("/:id", actions2.PermissionAction(), actions2.ViewAction(new(dto.SysJobById), func() interface{} {
+			return &dto.SysJobItem{}
+		}))
+		r.POST("", actions2.CreateAction(new(dto.SysJobControl)))
+		r.PUT("", actions2.PermissionAction(), actions2.UpdateAction(new(dto.SysJobControl)))
+		r.DELETE("", actions2.PermissionAction(), actions2.DeleteAction(new(dto.SysJobById)))
+	}
+	sysJob := controller.SysJob{}
+
+	v1.GET("/job/remove/:id", sysJob.RemoveJobForService)
+	v1.GET("/job/start/:id", sysJob.StartJobForService)
+}

+ 108 - 0
app/jobs/service/dto/sys_job.go

@@ -0,0 +1,108 @@
+package dto
+
+import (
+	dto2 "gas-cylinder-api/common/dto"
+	common "gas-cylinder-api/common/model"
+	"github.com/gin-gonic/gin"
+
+	"gas-cylinder-api/app/jobs/model"
+	"gogs.baozhida.cn/zoie/OAuth-core/api"
+)
+
+type SysJobSearch struct {
+	dto2.Pagination `search:"-"`
+	JobId           int    `form:"jobId" search:"type:exact;column:job_id;table:sys_job"`
+	JobName         string `form:"jobName" search:"type:icontains;column:job_name;table:sys_job"`
+	JobGroup        string `form:"jobGroup" search:"type:exact;column:job_group;table:sys_job"`
+	CronExpression  string `form:"cronExpression" search:"type:exact;column:cron_expression;table:sys_job"`
+	InvokeTarget    string `form:"invokeTarget" search:"type:exact;column:invoke_target;table:sys_job"`
+	Status          int    `form:"status" search:"type:exact;column:status;table:sys_job"`
+}
+
+func (m *SysJobSearch) GetNeedSearch() interface{} {
+	return *m
+}
+
+func (m *SysJobSearch) Bind(ctx *gin.Context) error {
+	log := api.GetRequestLogger(ctx)
+	err := ctx.ShouldBind(m)
+	if err != nil {
+		log.Errorf("Bind error: %s", err)
+	}
+	return err
+}
+
+func (m *SysJobSearch) Generate() dto2.Index {
+	o := *m
+	return &o
+}
+
+type SysJobControl struct {
+	JobId          int    `json:"jobId"`
+	JobName        string `json:"jobName" validate:"required"` // 名称
+	JobGroup       string `json:"jobGroup"`                    // 任务分组
+	JobType        int    `json:"jobType"`                     // 任务类型
+	CronExpression string `json:"cronExpression"`              // cron表达式
+	InvokeTarget   string `json:"invokeTarget"`                // 调用目标
+	Args           string `json:"args"`                        // 目标参数
+	MisfirePolicy  int    `json:"misfirePolicy"`               // 执行策略
+	Concurrent     int    `json:"concurrent"`                  // 是否并发
+	Status         int    `json:"status"`                      // 状态
+	EntryId        int    `json:"entryId"`                     // job启动时返回的id
+}
+
+func (s *SysJobControl) Bind(ctx *gin.Context) error {
+	return ctx.ShouldBind(s)
+}
+
+func (s *SysJobControl) Generate() dto2.Control {
+	cp := *s
+	return &cp
+}
+
+func (s *SysJobControl) GenerateM() (common.ActiveRecord, error) {
+	return &model.SysJob{
+		JobId:          s.JobId,
+		JobName:        s.JobName,
+		JobGroup:       s.JobGroup,
+		JobType:        s.JobType,
+		CronExpression: s.CronExpression,
+		InvokeTarget:   s.InvokeTarget,
+		Args:           s.Args,
+		MisfirePolicy:  s.MisfirePolicy,
+		Concurrent:     s.Concurrent,
+		Status:         s.Status,
+		EntryId:        s.EntryId,
+	}, nil
+}
+
+func (s *SysJobControl) GetId() interface{} {
+	return s.JobId
+}
+
+type SysJobById struct {
+	dto2.ObjectById
+}
+
+func (s *SysJobById) Generate() dto2.Control {
+	cp := *s
+	return &cp
+}
+
+func (s *SysJobById) GenerateM() (common.ActiveRecord, error) {
+	return &model.SysJob{}, nil
+}
+
+type SysJobItem struct {
+	JobId          int    `json:"jobId"`
+	JobName        string `json:"jobName" validate:"required"` // 名称
+	JobGroup       string `json:"jobGroup"`                    // 任务分组
+	JobType        int    `json:"jobType"`                     // 任务类型
+	CronExpression string `json:"cronExpression"`              // cron表达式
+	InvokeTarget   string `json:"invokeTarget"`                // 调用目标
+	Args           string `json:"args"`                        // 目标参数
+	MisfirePolicy  int    `json:"misfirePolicy"`               // 执行策略
+	Concurrent     int    `json:"concurrent"`                  // 是否并发
+	Status         int    `json:"status"`                      // 状态
+	EntryId        int    `json:"entryId"`                     // job启动时返回的id
+}

+ 92 - 0
app/jobs/service/sys_job.go

@@ -0,0 +1,92 @@
+package service
+
+import (
+	"gas-cylinder-api/common/dto"
+	"errors"
+	"github.com/robfig/cron/v3"
+	"gogs.baozhida.cn/zoie/OAuth-core/service"
+	"time"
+
+	"gas-cylinder-api/app/jobs"
+	"gas-cylinder-api/app/jobs/model"
+)
+
+type SysJob struct {
+	service.Service
+	Cron *cron.Cron
+}
+
+// RemoveJob 删除job
+func (e *SysJob) RemoveJob(c *dto.GeneralDelDto) error {
+	var err error
+	var data model.SysJob
+	err = e.Orm.Table(data.TableName()).First(&data, c.Id).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return err
+	}
+	cn := jobs.Remove(e.Cron, data.EntryId)
+
+	select {
+	case res := <-cn:
+		if res {
+			err = e.Orm.Table(data.TableName()).Where("entry_id = ?", data.EntryId).Update("entry_id", 0).Error
+			if err != nil {
+				e.Log.Errorf("db error: %s", err)
+			}
+			return err
+		}
+	case <-time.After(time.Second * 1):
+		e.Msg = "操作超时!"
+		return nil
+	}
+	return nil
+}
+
+// StartJob 启动任务
+func (e *SysJob) StartJob(c *dto.GeneralGetDto) error {
+	var data model.SysJob
+	var err error
+	err = e.Orm.Table(data.TableName()).First(&data, c.Id).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+		return err
+	}
+
+	if data.Status == 1 {
+		err = errors.New("当前Job是关闭状态不能被启动,请先启用。")
+		return err
+	}
+
+	if data.JobType == 1 {
+		var j = &jobs.HttpJob{}
+		j.InvokeTarget = data.InvokeTarget
+		j.CronExpression = data.CronExpression
+		j.JobId = data.JobId
+		j.Name = data.JobName
+		data.EntryId, err = jobs.AddJob(e.Cron, j)
+		if err != nil {
+			e.Log.Errorf("jobs AddJob[HttpJob] error: %s", err)
+		}
+	} else {
+		var j = &jobs.ExecJob{}
+		j.InvokeTarget = data.InvokeTarget
+		j.CronExpression = data.CronExpression
+		j.JobId = data.JobId
+		j.Name = data.JobName
+		j.Args = data.Args
+		data.EntryId, err = jobs.AddJob(e.Cron, j)
+		if err != nil {
+			e.Log.Errorf("jobs AddJob[ExecJob] error: %s", err)
+		}
+	}
+	if err != nil {
+		return err
+	}
+
+	err = e.Orm.Table(data.TableName()).Where(c.Id).Updates(&data).Error
+	if err != nil {
+		e.Log.Errorf("db error: %s", err)
+	}
+	return err
+}

+ 16 - 0
app/jobs/type.go

@@ -0,0 +1,16 @@
+package jobs
+
+import "github.com/robfig/cron/v3"
+
+type Job interface {
+	Run()
+	addJob(*cron.Cron) (int, error)
+}
+
+type JobsExec interface {
+	Exec(arg interface{}) error
+}
+
+func CallExec(e JobsExec, arg interface{}) error {
+	return e.Exec(arg)
+}

+ 15 - 0
common/global/lib.go

@@ -0,0 +1,15 @@
+package global
+
+// 判断a列表是否包含b列表
+func ContainsAllOptimized[T comparable](a, b []T) bool {
+	m := make(map[T]bool)
+	for _, valA := range a {
+		m[valA] = true
+	}
+	for _, valB := range b {
+		if !m[valB] {
+			return false
+		}
+	}
+	return true
+}

+ 28 - 0
common/global/lib_test.go

@@ -0,0 +1,28 @@
+package global
+
+import "testing"
+
+// 测试用例
+func TestContainsAllOptimized(t *testing.T) {
+	// 定义测试数据
+	tests := []struct {
+		a      []int
+		b      []int
+		result bool
+	}{
+		{[]int{1, 2, 3, 4, 5}, []int{1, 2, 3, 4, 5}, true},
+		{[]int{1, 2, 3, 4, 5}, []int{2, 3, 5}, true},
+		{[]int{1, 2, 3, 4, 5}, []int{6}, false},
+		{[]int{1, 2, 3, 4, 5}, []int{1, 5}, true},
+		{[]int{1, 2, 3, 4, 5}, []int{1, 2, 6}, false},
+		{[]int{}, []int{1}, false},      // 边界条件,a为空
+		{[]int{1, 2, 3}, []int{}, true}, // 边界条件,b为空
+	}
+
+	// 运行测试
+	for _, test := range tests {
+		if result := ContainsAllOptimized(test.a, test.b); result != test.result {
+			t.Errorf("containsAllOptimized(%v, %v) = %v; want %v", test.a, test.b, result, test.result)
+		}
+	}
+}

+ 53 - 0
common/global/string.go

@@ -8,3 +8,56 @@ func CheckElementExists(a string, list []string) bool {
 	}
 	return false
 }
+
+func StringListCompare(list1, list2 []string) (isEqual bool, common, onlyList1, onlyList2 []string) {
+	if len(list1) != len(list2) {
+		isEqual = false
+	}
+
+	// 创建map来存储list1列表中的元素
+	AMap := make(map[string]int)
+	for _, item := range list1 {
+		AMap[item]++
+	}
+
+	// 检查B列表中的元素是否在AMap中
+	for _, item := range list2 {
+		if count, exists := AMap[item]; !exists || count == 0 {
+			isEqual = false
+		}
+		AMap[item]--
+	}
+	if !isEqual {
+		// 创建一个map来存储A列表中的元素
+		list1Map := make(map[string]struct{})
+		for _, a := range list1 {
+			list1Map[a] = struct{}{}
+		}
+
+		// 查找list2列表中存在但list1列表中不存在的元素
+		for _, v := range list2 {
+			if _, exists := list1Map[v]; !exists {
+				onlyList2 = append(onlyList2, v)
+			} else {
+				common = append(common, v)
+			}
+		}
+
+		// 创建一个map来存储B列表中的元素
+		list2Map := make(map[string]struct{})
+		for _, b := range list2 {
+			list2Map[b] = struct{}{}
+		}
+
+		// 查找list1列表中存在但list2列表中不存在的元素
+		for _, a := range list1 {
+			if _, exists := list2Map[a]; !exists {
+				onlyList1 = append(onlyList1, a)
+			}
+		}
+		return
+	}
+
+	isEqual = true
+	return
+}

+ 4 - 0
common/model/byat.go

@@ -108,3 +108,7 @@ func (e StringList) Value() (driver.Value, error) {
 func (e *StringList) Scan(src interface{}) error {
 	return json.Unmarshal(src.([]byte), e)
 }
+
+func (e *StringList) Self() []string {
+	return *e
+}

+ 2 - 2
conf/city_data_array.go

@@ -10,7 +10,7 @@ import (
 
 // 定义结构体用于存储 JSON 内容
 type CityDataArray struct {
-	Name string `json:"name"`
+	Name  string `json:"name"`
 	Value string `json:"value"`
 }
 
@@ -36,4 +36,4 @@ func InitCityData() {
 		CityDataMap[city.Value] = city.Name
 	}
 
-}
+}

+ 0 - 1
conf/data-array.json

@@ -51,7 +51,6 @@
     "value": "520181",
     "name": "清镇市"
   },
-  ,
   {
     "value": "520200",
     "name": "六盘水市"

+ 1 - 0
db/migration.go

@@ -40,6 +40,7 @@ func AutoMigrateDB() {
 			&model.CustomerGasCylinder{},
 			&model.GasCylinderAllot{},
 			&model.GasCylinderStatus{},
+			&model.InspectExpand{},
 		)
 	if err != nil {
 		zap.L().Panic("migrate db fail", zap.Error(err))

+ 13 - 8
go.mod

@@ -21,14 +21,16 @@ require (
 	github.com/swaggo/swag v1.8.12
 	github.com/unrolled/secure v1.12.0
 	go.uber.org/zap v1.19.1
-	golang.org/x/crypto v0.5.0
+	golang.org/x/crypto v0.19.0
 	gorm.io/driver/mysql v1.3.5
 	gorm.io/gorm v1.23.8
 )
 
 require (
+	github.com/dgrijalva/jwt-go v3.2.0+incompatible
+	github.com/go-redis/redis/v7 v7.4.0
 	github.com/go-resty/resty/v2 v2.7.0
-	github.com/tealeg/xlsx v1.0.5
+	github.com/xuri/excelize/v2 v2.8.1
 	gogs.baozhida.cn/zoie/OAuth-core v0.0.0-00010101000000-000000000000
 )
 
@@ -44,7 +46,6 @@ require (
 	github.com/chanxuehong/wechat v0.0.0-20201110083048-0180211b69fd // indirect
 	github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
 	github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
-	github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
 	github.com/fatih/color v1.9.0 // indirect
 	github.com/fsnotify/fsnotify v1.4.9 // indirect
 	github.com/ghodss/yaml v1.0.0 // indirect
@@ -58,7 +59,6 @@ require (
 	github.com/go-playground/locales v0.14.1 // indirect
 	github.com/go-playground/universal-translator v0.18.1 // indirect
 	github.com/go-playground/validator/v10 v10.11.2 // indirect
-	github.com/go-redis/redis/v7 v7.4.0 // indirect
 	github.com/goccy/go-json v0.10.0 // indirect
 	github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
 	github.com/golang/protobuf v1.5.3 // indirect
@@ -83,10 +83,13 @@ require (
 	github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
+	github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
 	github.com/mojocn/base64Captcha v1.3.1 // indirect
 	github.com/nsqio/go-nsq v1.0.8 // indirect
 	github.com/nyaruka/phonenumbers v1.0.55 // indirect
 	github.com/pelletier/go-toml/v2 v2.0.6 // indirect
+	github.com/richardlehane/mscfb v1.0.4 // indirect
+	github.com/richardlehane/msoleps v1.0.3 // indirect
 	github.com/robinjoseph08/redisqueue/v2 v2.1.0 // indirect
 	github.com/russross/blackfriday/v2 v2.1.0 // indirect
 	github.com/shamsher31/goimgext v1.0.0 // indirect
@@ -97,14 +100,16 @@ require (
 	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
 	github.com/ugorji/go/codec v1.2.9 // indirect
 	github.com/urfave/cli v1.22.1 // indirect
+	github.com/xuri/efp v0.0.0-20231025114914-d1ff6096ae53 // indirect
+	github.com/xuri/nfp v0.0.0-20230919160717-d98342af3f05 // indirect
 	go.uber.org/atomic v1.9.0 // indirect
 	go.uber.org/multierr v1.7.0 // indirect
 	golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
-	golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 // indirect
-	golang.org/x/net v0.8.0 // indirect
+	golang.org/x/image v0.14.0 // indirect
+	golang.org/x/net v0.21.0 // indirect
 	golang.org/x/sync v0.1.0 // indirect
-	golang.org/x/sys v0.6.0 // indirect
-	golang.org/x/text v0.8.0 // indirect
+	golang.org/x/sys v0.17.0 // indirect
+	golang.org/x/text v0.14.0 // indirect
 	golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
 	golang.org/x/tools v0.7.0 // indirect
 	google.golang.org/protobuf v1.30.0 // indirect

+ 26 - 13
go.sum

@@ -340,6 +340,7 @@ github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/
 github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
 github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
 github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
 github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
 github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
 github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
@@ -383,6 +384,7 @@ github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL
 github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
 github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
 github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
+github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8=
 github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is=
 github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4=
 github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA=
@@ -446,6 +448,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
 github.com/mojocn/base64Captcha v1.3.1 h1:2Wbkt8Oc8qjmNJ5GyOfSo4tgVQPsbKMftqASnq8GlT0=
 github.com/mojocn/base64Captcha v1.3.1/go.mod h1:wAQCKEc5bDujxKRmbT6/vTnTt5CjStQ8bRfPWUuz/iY=
 github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
@@ -528,6 +532,11 @@ github.com/qiniu/go-sdk/v7 v7.13.0/go.mod h1:btsaOc8CA3hdVloULfFdDgDc+g4f3TDZEFs
 github.com/qiniu/x v1.10.5/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs=
 github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKcyumwBO6qip7RNQ5r77yrssm9bfCowcLEBcU5IA=
 github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM=
+github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
+github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
+github.com/richardlehane/msoleps v1.0.3 h1:aznSZzrwYRl3rLKRT3gUk9am7T/mLNSnJINvN0AQoVM=
+github.com/richardlehane/msoleps v1.0.3/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
 github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
 github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
 github.com/robinjoseph08/redisqueue/v2 v2.1.0 h1:GactHlrxS8YSCJc4CbP1KbTObo14pieNmNWSUlquTGI=
@@ -580,8 +589,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
 github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
 github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
 github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
 github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M=
@@ -589,8 +598,6 @@ github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRd
 github.com/swaggo/swag v1.8.12 h1:pctzkNPu0AlQP2royqX3apjKCQonAnf7KGoxeO4y64w=
 github.com/swaggo/swag v1.8.12/go.mod h1:lNfm6Gg+oAq3zRJQNEMBE66LIJKM44mxFqhEEgy2its=
 github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
-github.com/tealeg/xlsx v1.0.5 h1:+f8oFmvY8Gw1iUXzPk+kz+4GpbDZPK1FhPiQRd+ypgE=
-github.com/tealeg/xlsx v1.0.5/go.mod h1:btRS8dz54TDnvKNosuAqxrM1QgN1udgk9O34bDCnORM=
 github.com/tebeka/strftime v0.1.3/go.mod h1:7wJm3dZlpr4l/oVK0t1HYIc4rMzQ2XJlOMIUJUJH6XQ=
 github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
 github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls=
@@ -625,6 +632,12 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:
 github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
 github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/xuri/efp v0.0.0-20231025114914-d1ff6096ae53 h1:Chd9DkqERQQuHpXjR/HSV1jLZA6uaoiwwH3vSuF3IW0=
+github.com/xuri/efp v0.0.0-20231025114914-d1ff6096ae53/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
+github.com/xuri/excelize/v2 v2.8.1 h1:pZLMEwK8ep+CLIUWpWmvW8IWE/yxqG0I1xcN6cVMGuQ=
+github.com/xuri/excelize/v2 v2.8.1/go.mod h1:oli1E4C3Pa5RXg1TBXn4ENCXDV5JUMlBluUhG7c+CEE=
+github.com/xuri/nfp v0.0.0-20230919160717-d98342af3f05 h1:qhbILQo1K3mphbwKh1vNm4oGezE1eF9fQWmNiIpSfI4=
+github.com/xuri/nfp v0.0.0-20230919160717-d98342af3f05/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
@@ -678,8 +691,8 @@ golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPh
 golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
-golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
+golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
+golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -688,8 +701,8 @@ golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u0
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190501045829-6d32002ffd75/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 h1:/eM0PCrQI2xd471rI+snWuu251/+/jpBpZqir2mPdnU=
-golang.org/x/image v0.0.0-20220722155232-062f8c9fd539/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
+golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4=
+golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
 golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
@@ -736,8 +749,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
 golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
-golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
-golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
+golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
+golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -802,8 +815,8 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
-golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
+golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@@ -814,8 +827,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
-golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

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