ziwen 1 year ago
parent
commit
2f6e22bdef

+ 571 - 0
controllers/sandbox/sandbox.go

@@ -4,14 +4,17 @@ import (
 	"encoding/json"
 	"eta/eta_api/controllers"
 	"eta/eta_api/models"
+	"eta/eta_api/models/data_manage"
 	"eta/eta_api/models/sandbox"
 	"eta/eta_api/models/sandbox/request"
 	"eta/eta_api/models/sandbox/response"
 	"eta/eta_api/models/system"
+	"eta/eta_api/services/data"
 	sandboxService "eta/eta_api/services/sandbox"
 	"eta/eta_api/utils"
 	"fmt"
 	"github.com/rdlucklib/rdluck_tools/paging"
+	"time"
 )
 
 // versionSize 版本列表第一页数据约定是:3条
@@ -812,3 +815,571 @@ func (this *SandboxController) ListByQuote() {
 	br.Msg = "获取成功"
 	br.Data = resp
 }
+
+//// ChartClassifyListV2
+//// @Title 沙盘分类列表
+//// @Description 沙盘分类列表接口
+//// @Param   IsShowMe   query   bool  true       "是否只看我的,true、false"
+//// @Success 200 {object} data_manage.ChartClassifyListResp
+//// @router /classify/list [get]
+//func (this *SandboxController) ClassifyList() {
+//	br := new(models.BaseResponse).Init()
+//	defer func() {
+//		this.Data["json"] = br
+//		this.ServeJSON()
+//	}()
+//	resp := new(sandbox.SandboxClassifyListResp)
+//
+//	rootList, err := sandbox.GetSandboxClassifyByParentId(0)
+//	if err != nil && err.Error() != utils.ErrNoRow() {
+//		br.Msg = "获取失败"
+//		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+//		return
+//	}
+//
+//	classifyAll, err := sandbox.GetSandboxClassifyAll()
+//	if err != nil && err.Error() != utils.ErrNoRow() {
+//		br.Msg = "获取失败"
+//		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+//		return
+//	}
+//
+//	sandboxClassifyId, _ := this.GetInt("SandboxClassifyId")
+//	if sandboxClassifyId <= 0 {
+//		br.Msg = "参数错误"
+//		return
+//	}
+//
+//	allSandboxInfo, err := sandbox.GetSandboxAll(sandboxClassifyId)
+//	if err != nil && err.Error() != utils.ErrNoRow() {
+//		br.Msg = "获取失败"
+//		br.ErrMsg = "获取沙盘信息失败,Err:" + err.Error()
+//		return
+//	}
+//
+//
+//	sandboxInfoMap := make(map[int][]*sandbox.SandboxClassifyItems)
+//	for _, v := range allSandboxInfo {
+//		sandboxInfoMap[v.SandboxClassifyId] = append(sandboxInfoMap[v.SandboxClassifyId], v)
+//	}
+//	rootChildMap := make(map[int][]*sandbox.SandboxClassifyItems)
+//	for _, v := range classifyAll {
+//		rootChildMap[v.ParentId] = append(rootChildMap[v.ParentId], v)
+//		if existItems, ok := sandboxInfoMap[v.SandboxClassifyId]; ok {
+//			v.Children = existItems
+//		} else {
+//			items := make([]*sandbox.SandboxClassifyItems, 0)
+//			v.Children = items
+//		}
+//	}
+//	nodeAll := make([]*sandbox.SandboxClassifyItems, 0)
+//	for _, v := range rootList {
+//		if existItems, ok := rootChildMap[v.SandboxClassifyId]; ok {
+//			v.Children = existItems
+//		} else {
+//			items := make([]*sandbox.SandboxClassifyItems, 0)
+//			v.Children = items
+//		}
+//		nodeAll = append(nodeAll, v)
+//	}
+//	//
+//	//
+//	//nodeAll := make([]*data_manage.ChartClassifyItems, 0)
+//	//for k := range rootList {
+//	//	rootNode := rootList[k]
+//	//	data.ChartClassifyListMakeTree(classifyAll, rootNode)
+//	//	nodeAll = append(nodeAll, rootNode)
+//	//}
+//	resp.AllNodes = nodeAll
+//
+//
+//	br.Ret = 200
+//	br.Success = true
+//	br.Msg = "获取成功"
+//	br.Data = resp
+//}
+
+// SandboxClassifyItems
+// @Title 获取所有沙盘分类接口-不包含沙盘
+// @Description 获取所有沙盘分类接口-不包含沙盘
+// @Success 200 {object} data_manage.ChartClassifyListResp
+// @router /classify/list [get]
+func (this *SandboxController) SandboxClassifyItems() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	rootList, err := sandbox.GetSandboxClassifyByParentId(0)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		return
+	}
+
+	classifyAll, err := sandbox.GetSandboxClassifyAll()
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		return
+	}
+
+	nodeAll := make([]*sandbox.SandboxClassifyItems, 0)
+	for k := range rootList {
+		rootNode := rootList[k]
+		sandboxService.ChartClassifyItemsMakeTree(this.SysUser, classifyAll, rootNode)
+		nodeAll = append(nodeAll, rootNode)
+	}
+
+	resp := sandbox.SandboxClassifyListResp{
+		AllNodes: nodeAll,
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// @Title 新增沙盘分类
+// @Description 新增沙盘分类接口
+// @Param	request	body data_manage.AddChartClassifyReq true "type json string"
+// @Success 200 Ret=200 保存成功
+// @router /classify/add [post]
+func (this *SandboxController) AddSandboxClassify() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req sandbox.AddSandboxClassifyReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.SandboxClassifyName == "" {
+		br.Msg = "请输入分类名称"
+		br.IsSendEmail = false
+		return
+	}
+	if req.ParentId < 0 {
+		br.Msg = "参数错误"
+		br.IsSendEmail = false
+		return
+	}
+
+	count, err := sandbox.GetSandboxClassifyCount(req.SandboxClassifyName, req.ParentId)
+	if err != nil {
+		br.Msg = "判断名称是否已存在失败"
+		br.ErrMsg = "判断名称是否已存在失败,Err:" + err.Error()
+		return
+	}
+	if count > 0 {
+		br.Msg = "分类名称已存在,请重新输入"
+		br.IsSendEmail = false
+		return
+	}
+	//获取该层级下最大的排序数
+	maxSort, err := sandbox.GetSandboxClassifyMaxSort(req.ParentId)
+
+	classify := new(sandbox.SandboxClassify)
+	classify.ParentId = req.ParentId
+	classify.SandboxClassifyName = req.SandboxClassifyName
+	classify.HasData = 0
+	classify.CreateTime = time.Now()
+	classify.ModifyTime = time.Now()
+	classify.SysUserId = this.SysUser.AdminId
+	classify.SysUserRealName = this.SysUser.RealName
+	classify.Level = req.Level + 1
+	classify.Sort = maxSort + 1
+
+	_, err = sandbox.AddSandboxClassify(classify)
+	if err != nil {
+		br.Msg = "保存分类失败"
+		br.ErrMsg = "保存分类失败,Err:" + err.Error()
+		return
+	}
+	br.Ret = 200
+	br.Msg = "保存成功"
+	br.Success = true
+}
+
+// @Title 修改沙盘分类
+// @Description 修改沙盘分类接口
+// @Param	request	body data_manage.EditChartClassifyReq true "type json string"
+// @Success 200 Ret=200 修改成功
+// @router /classify/edit [post]
+func (this *SandboxController) EditSandboxClassify() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req sandbox.EditSandboxClassifyReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.SandboxClassifyName == "" {
+		br.Msg = "请输入分类名称"
+		br.IsSendEmail = false
+		return
+	}
+
+	if req.SandboxClassifyId <= 0 {
+		br.Msg = "参数错误"
+		br.IsSendEmail = false
+		return
+	}
+
+	item, err := sandbox.GetSandboxClassifyById(req.SandboxClassifyId)
+	if err != nil {
+		br.Msg = "保存失败"
+		br.Msg = "获取分类信息失败,Err:" + err.Error()
+		return
+	}
+
+	if item.SandboxClassifyName != req.SandboxClassifyName {
+		count, err := sandbox.GetSandboxClassifyCount(req.SandboxClassifyName, item.ParentId)
+		if err != nil {
+			br.Msg = "判断名称是否已存在失败"
+			br.ErrMsg = "判断名称是否已存在失败,Err:" + err.Error()
+			return
+		}
+		if count > 0 {
+			br.Msg = "分类名称已存在,请重新输入"
+			br.IsSendEmail = false
+			return
+		}
+
+		err = sandbox.EditSandboxClassify(req.SandboxClassifyId, req.SandboxClassifyName)
+		if err != nil {
+			br.Msg = "保存失败"
+			br.ErrMsg = "保存失败,Err:" + err.Error()
+			return
+		}
+	}
+	br.Ret = 200
+	br.Msg = "保存成功"
+	br.Success = true
+	br.IsAddLog = true
+}
+
+// @Title 删除沙盘检测接口
+// @Description 删除沙盘检测接口
+// @Param	request	body data_manage.ChartClassifyDeleteCheckResp true "type json string"
+// @Success 200 Ret=200 检测成功
+// @router /classify/delete/check [post]
+func (this *SandboxController) DeleteSandboxClassifyCheck() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req sandbox.SandboxClassifyDeleteCheckReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.SandboxClassifyId < 0 && req.SandboxInfoId <= 0 {
+		br.Msg = "参数错误"
+		br.IsSendEmail = false
+		return
+	}
+	var deleteStatus int
+	var tipsMsg string
+	//删除分类
+	if req.SandboxClassifyId > 0 && req.SandboxInfoId == 0 {
+		//判断沙盘分类下,是否含有沙盘
+		count, err := sandbox.GetSandboxInfoCountByClassifyId(req.SandboxClassifyId)
+		if err != nil {
+			br.Msg = "删除失败"
+			br.ErrMsg = "分类下是否含有指标失败,Err:" + err.Error()
+			return
+		}
+
+		if count > 0 {
+			deleteStatus = 1
+			tipsMsg = "该分类下关联沙盘不可删除"
+		}
+	}
+
+	if deleteStatus != 1 && req.SandboxInfoId == 0 {
+		classifyCount, err := sandbox.GetSandboxInfoCountByClassifyId(req.SandboxClassifyId)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "删除失败"
+			br.ErrMsg = "分类下是否含有沙盘失败,Err:" + err.Error()
+			return
+		}
+		if classifyCount > 0 {
+			deleteStatus = 2
+			tipsMsg = "确认删除当前目录及包含的子目录吗"
+		}
+	}
+	if deleteStatus == 0 {
+		tipsMsg = "可删除,进行删除操作"
+	}
+
+	resp := new(sandbox.SandboxClassifyDeleteCheckResp)
+	resp.DeleteStatus = deleteStatus
+	resp.TipsMsg = tipsMsg
+	br.Ret = 200
+	br.Msg = "检测成功"
+	br.Success = true
+	br.Data = resp
+}
+
+// @Title 删除沙盘分类/沙盘
+// @Description 删除沙盘分类/沙盘接口
+// @Param	request	body data_manage.DeleteChartClassifyReq true "type json string"
+// @Success 200 Ret=200 删除成功
+// @router /classify/delete [post]
+func (this *SandboxController) DeleteSandboxClassify() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	var req sandbox.DeleteSandboxClassifyReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.SandboxClassifyId < 0 && req.SandboxId <= 0 {
+		br.Msg = "参数错误"
+		br.IsSendEmail = false
+		return
+	}
+
+	//删除分类
+	if req.SandboxClassifyId > 0 && req.SandboxId == 0 {
+		//判断是否含有指标
+		count, err := sandbox.GetSandboxInfoCountByClassifyId(req.SandboxId)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "删除失败"
+			br.ErrMsg = "判断名称是否已存在失败,Err:" + err.Error()
+			return
+		}
+
+		if count > 0 {
+			br.Msg = "该目录下存在关联指标,不可删除"
+			br.IsSendEmail = false
+			return
+		}
+
+		err = sandbox.DeleteSandboxClassify(req.SandboxClassifyId)
+		if err != nil {
+			br.Msg = "删除失败"
+			br.ErrMsg = "删除失败,Err:" + err.Error()
+			return
+		}
+	}
+
+	//删除沙盘
+	if req.SandboxId > 0 {
+		sandboxInfo, err := sandbox.GetSandboxById(req.SandboxId)
+		if err != nil {
+			if err.Error() == utils.ErrNoRow() {
+				br.Msg = "沙盘已删除,请刷新页面"
+				br.ErrMsg = "指标不存在,Err:" + err.Error()
+				return
+			} else {
+				br.Msg = "删除失败"
+				br.ErrMsg = "删除失败,获取指标信息失败,Err:" + err.Error()
+				return
+			}
+		}
+		if sandboxInfo == nil {
+			br.Msg = "沙盘已删除,请刷新页面"
+			return
+		}
+		////沙盘操作权限
+		//ok := sandbox.CheckOpSandboxPermission(sysUser, sandboxInfo.OpUserId)
+		//if !ok {
+		//	br.Msg = "没有该沙盘的操作权限"
+		//	br.ErrMsg = "没有该沙盘的操作权限"
+		//	return
+		//}
+
+		////新增操作日志
+		//{
+		//	chartLog := new(data_manage.ChartInfoLog)
+		//	chartLog.ChartName = chartInfo.ChartName
+		//	chartLog.ChartInfoId = req.ChartInfoId
+		//	chartLog.ChartClassifyId = chartInfo.ChartClassifyId
+		//	chartLog.SysUserId = sysUser.AdminId
+		//	chartLog.SysUserRealName = sysUser.RealName
+		//	chartLog.UniqueCode = chartInfo.UniqueCode
+		//	chartLog.CreateTime = time.Now()
+		//	chartLog.Content = string(this.Ctx.Input.RequestBody)
+		//	chartLog.Status = "删除沙盘"
+		//	chartLog.Method = this.Ctx.Input.URI()
+		//	go data_manage.AddChartInfoLog(chartLog)
+		//}
+	}
+	br.Ret = 200
+	br.Msg = "删除成功"
+	br.Success = true
+	br.IsAddLog = true
+}
+
+// ChartClassifyMove
+// @Title 沙盘分类移动接口
+// @Description 沙盘分类移动接口
+// @Success 200 {object} data_manage.MoveChartClassifyReq
+// @router /classify/move [post]
+func (this *SandboxController) ChartClassifyMove() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	var req data_manage.MoveChartClassifyReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.ClassifyId <= 0 {
+		br.Msg = "参数错误"
+		br.ErrMsg = "分类id小于等于0"
+		return
+	}
+	//判断分类是否存在
+	chartClassifyInfo, err := data_manage.GetChartClassifyById(req.ClassifyId)
+	if err != nil {
+		br.Msg = "移动失败"
+		br.ErrMsg = "获取分类信息失败,Err:" + err.Error()
+		return
+	}
+	// 权限校验
+	{
+		button := data.GetChartClassifyOpButton(this.SysUser, chartClassifyInfo.SysUserId)
+		if !button.OpButton {
+			br.Msg = "无操作权限"
+			br.IsSendEmail = false
+			return
+		}
+	}
+
+	if chartClassifyInfo.Source != utils.CHART_SOURCE_DEFAULT {
+		br.Msg = "分类异常"
+		br.ErrMsg = "分类异常,不是ETA图库的分类"
+		return
+	}
+	updateCol := make([]string, 0)
+
+	//判断上级id是否一致,如果不一致的话,那么需要移动该分类层级
+	if chartClassifyInfo.ParentId != req.ParentClassifyId && req.ParentClassifyId != 0 {
+		parentChartClassifyInfo, err := data_manage.GetChartClassifyById(req.ParentClassifyId)
+		if err != nil {
+			br.Msg = "移动失败"
+			br.ErrMsg = "获取上级分类信息失败,Err:" + err.Error()
+			return
+		}
+		chartClassifyInfo.ParentId = parentChartClassifyInfo.ChartClassifyId
+		chartClassifyInfo.Level = parentChartClassifyInfo.Level + 1
+		chartClassifyInfo.ModifyTime = time.Now()
+		updateCol = append(updateCol, "ParentId", "Level", "ModifyTime")
+	}
+
+	//如果有传入 上一个兄弟节点分类id
+	if req.PrevClassifyId > 0 {
+		//上一个兄弟节点
+		prevClassify, err := data_manage.GetChartClassifyById(req.PrevClassifyId)
+		if err != nil {
+			br.Msg = "移动失败"
+			br.ErrMsg = "获取上一个兄弟节点分类信息失败,Err:" + err.Error()
+			return
+		}
+
+		//如果是移动在两个兄弟节点之间
+		if req.NextClassifyId > 0 {
+			//下一个兄弟节点
+			nextClassify, err := data_manage.GetChartClassifyById(req.NextClassifyId)
+			if err != nil {
+				br.Msg = "移动失败"
+				br.ErrMsg = "获取下一个兄弟节点分类信息失败,Err:" + err.Error()
+				return
+			}
+			//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
+			if prevClassify.Sort == nextClassify.Sort || prevClassify.Sort == chartClassifyInfo.Sort {
+				//变更兄弟节点的排序
+				updateSortStr := `sort + 2`
+				_ = data_manage.UpdateChartClassifySortByParentId(prevClassify.ParentId, prevClassify.ChartClassifyId, prevClassify.Sort, updateSortStr)
+			} else {
+				//如果下一个兄弟的排序权重正好是上个兄弟节点的下一层,那么需要再加一层了
+				if nextClassify.Sort-prevClassify.Sort == 1 {
+					//变更兄弟节点的排序
+					updateSortStr := `sort + 1`
+					_ = data_manage.UpdateChartClassifySortByParentId(prevClassify.ParentId, 0, prevClassify.Sort, updateSortStr)
+				}
+			}
+		}
+
+		chartClassifyInfo.Sort = prevClassify.Sort + 1
+		chartClassifyInfo.ModifyTime = time.Now()
+		updateCol = append(updateCol, "Sort", "ModifyTime")
+
+	} else {
+		firstClassify, err := data_manage.GetFirstChartClassifyByParentId(chartClassifyInfo.ParentId)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "移动失败"
+			br.ErrMsg = "获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + err.Error()
+			return
+		}
+
+		//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
+		if firstClassify != nil && firstClassify.Sort == 0 {
+			updateSortStr := ` sort + 1 `
+			_ = data_manage.UpdateChartClassifySortByParentId(firstClassify.ParentId, firstClassify.ChartClassifyId-1, 0, updateSortStr)
+		}
+
+		chartClassifyInfo.Sort = 0 //那就是排在第一位
+		chartClassifyInfo.ModifyTime = time.Now()
+		updateCol = append(updateCol, "Sort", "ModifyTime")
+	}
+
+	//更新
+	if len(updateCol) > 0 {
+		err = chartClassifyInfo.Update(updateCol)
+		if err != nil {
+			br.Msg = "移动失败"
+			br.ErrMsg = "修改失败,Err:" + err.Error()
+			return
+		}
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "移动成功"
+}

+ 4 - 3
models/db.go

@@ -212,9 +212,10 @@ func initYb() {
 func initSandbox() {
 	//注册对象
 	orm.RegisterModel(
-		new(sandbox.Sandbox),        //沙盘主表
-		new(sandbox.SandboxVersion), //沙盘版本表
-		new(sandbox.SandboxDraft),   //沙盘草稿表
+		new(sandbox.Sandbox),         //沙盘主表
+		new(sandbox.SandboxVersion),  //沙盘版本表
+		new(sandbox.SandboxDraft),    //沙盘草稿表
+		new(sandbox.SandboxClassify), //沙盘分类表
 	)
 }
 

+ 154 - 0
models/sandbox/sand_box_classify.go

@@ -0,0 +1,154 @@
+package sandbox
+
+import (
+"github.com/beego/beego/v2/client/orm"
+"time"
+)
+
+type SandboxClassify struct {
+	SandboxClassifyId   int       `orm:"column(sandbox_classify_id);pk"`
+	SandboxClassifyName string    `description:"分类名称"`
+	ParentId          int       `description:"父级id"`
+	HasData           int       `description:"是否含有指标数据"`
+	CreateTime        time.Time `description:"创建时间"`
+	ModifyTime        time.Time `description:"修改时间"`
+	SysUserId         int       `description:"创建人id"`
+	SysUserRealName   string    `description:"创建人姓名"`
+	Level             int       `description:"层级"`
+	Sort              int       `description:"排序字段,越小越靠前,默认值:10"`
+}
+
+func AddSandboxClassify(item *SandboxClassify) (lastId int64, err error) {
+	o := orm.NewOrmUsingDB("data")
+	lastId, err = o.Insert(item)
+	return
+}
+
+// GetSandboxClassifyByParentId
+func GetSandboxClassifyByParentId(parentId int) (items []*SandboxClassifyItems, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM sandbox_classify WHERE parent_id=? order by sort asc,sandbox_classify_id asc`
+	_, err = o.Raw(sql, parentId).QueryRows(&items)
+	return
+}
+
+// GetSandboxClassifyAll
+func GetSandboxClassifyAll() (items []*SandboxClassifyItems, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM sandbox_classify WHERE parent_id<>0 order by sort asc,sandbox_classify_id asc`
+	_, err = o.Raw(sql).QueryRows(&items)
+	return
+}
+
+type SandboxClassifyItems struct {
+	SandboxClassifyId   int       `orm:"column(sandbox_classify_id);pk"`
+	SandboxClassifyName string    `description:"分类名称"`
+	ParentId            int       `description:"父级id"`
+	HasData             int       `description:"是否含有指标数据"`
+	CreateTime          time.Time `description:"创建时间"`
+	ModifyTime          time.Time `description:"修改时间"`
+	SysUserId           int       `description:"创建人id"`
+	SysUserRealName     string    `description:"创建人姓名"`
+	Level               int       `description:"层级"`
+	Sort                int       `description:"排序字段,越小越靠前,默认值:10"`
+	SandboxId           int       `description:"沙盘id"`
+	Children            []*SandboxClassifyItems
+}
+
+type SandboxClassifyListResp struct {
+	AllNodes []*SandboxClassifyItems
+}
+
+type AddSandboxClassifyReq struct {
+	SandboxClassifyName string `description:"分类名称"`
+	ParentId            int    `description:"父级id,第一级传0"`
+	Level               int    `description:"层级,第一级传0,其余传上一级的层级"`
+}
+
+func GetSandboxClassifyCount(sandboxClassifyName string, parentId int) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT COUNT(1) AS count FROM sandbox_classify WHERE parent_id=? AND sandbox_classify_name=? `
+	err = o.Raw(sql, parentId, sandboxClassifyName).QueryRow(&count)
+	return
+}
+
+// GetSandboxClassifyMaxSort 获取沙盘分类下最大的排序数
+func GetSandboxClassifyMaxSort(parentId int) (sort int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT Max(sort) AS sort FROM sandbox_classify WHERE parent_id=? `
+	err = o.Raw(sql, parentId).QueryRow(&sort)
+	return
+}
+
+type EditSandboxClassifyReq struct {
+	SandboxClassifyName string `description:"分类名称"`
+	SandboxClassifyId   int    `description:"分类id"`
+}
+
+func GetSandboxClassifyById(classifyId int) (item *SandboxClassify, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM sandbox_classify WHERE sandbox_classify_id=? `
+	err = o.Raw(sql, classifyId).QueryRow(&item)
+	return
+}
+
+func EditSandboxClassify(classifyId int, sandboxClassifyName string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `UPDATE sandbox_classify SET sandbox_classify_name=?,modify_time=NOW() WHERE sandbox_classify_id=? `
+	_, err = o.Raw(sql, sandboxClassifyName, classifyId).Exec()
+	return
+}
+
+type SandboxClassifyDeleteCheckReq struct {
+	SandboxClassifyId int `description:"分类id"`
+	SandboxInfoId     int `description:"指标id"`
+}
+
+func GetSandboxInfoCountByClassifyId(classifyId int) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT COUNT(1) AS count FROM sandbox AS a
+				WHERE a.sandbox_classify_id IN(
+				SELECT t.sandbox_classify_id FROM 
+				(
+				SELECT rd.*
+				FROM (SELECT * FROM sandbox_classify WHERE parent_id IS NOT NULL) rd,
+					 (SELECT @pid := ?) pd 
+				WHERE FIND_IN_SET(parent_id, @pid) > 0 
+				  AND @pid := CONCAT(@pid, ',', sandbox_classify_id) 
+				UNION SELECT * FROM sandbox_classify WHERE sandbox_classify_id = @pid
+				)AS t
+				) `
+	err = o.Raw(sql, classifyId).QueryRow(&count)
+	return
+}
+
+type SandboxClassifyDeleteCheckResp struct {
+	DeleteStatus int    `description:"检测状态:0:默认值,如果为0,继续走其他校验,1:该分类下关联图表不可删除,2:确认删除当前目录及包含的子目录吗"`
+	TipsMsg      string `description:"提示信息"`
+}
+
+
+type DeleteSandboxClassifyReq struct {
+	SandboxClassifyId int `description:"分类id"`
+	SandboxId     int `description:"指标id"`
+}
+
+
+func DeleteSandboxClassify(classifyId int) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` DELETE FROM sandbox_classify
+				WHERE sandbox_classify_id IN(
+				SELECT t.sandbox_classify_id FROM
+				(
+				SELECT rd.*
+				FROM (SELECT * FROM sandbox_classify WHERE parent_id IS NOT NULL) rd,
+				(SELECT @pid := ?) pd
+				WHERE FIND_IN_SET(parent_id, @pid) > 0
+				AND @pid := CONCAT(@pid, ',', sandbox_classify_id)
+				UNION SELECT * FROM sandbox_classify WHERE sandbox_classify_id = @pid
+				)AS t
+				) `
+	_, err = o.Raw(sql, classifyId).Exec()
+	return
+}
+

+ 28 - 0
models/sandbox/sandbox.go

@@ -1,6 +1,8 @@
 package sandbox
 
 import (
+	"eta/eta_api/models/system"
+	"eta/eta_api/utils"
 	"github.com/beego/beego/v2/client/orm"
 	"time"
 )
@@ -20,6 +22,8 @@ type Sandbox struct {
 	IsDelete            int8      `description:"是否删除,0:未删除,1:已删除"`
 	ModifyTime          time.Time `description:"修改时间"`
 	CreateTime          time.Time `description:"创建时间"`
+	SandboxClassifyId   int       `description:"分类id"`
+	Sort                int       `description:"排序"`
 }
 
 // Update 沙盘字段变更
@@ -193,3 +197,27 @@ type SandboxSaveResp struct {
 	*Sandbox
 	VersionCode string `description:"版本号"`
 }
+
+func GetSandboxAll(sandboxClassifyId int) (list []*SandboxClassifyItems, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT sandbox_id,sandbox_classify_id,name AS sandbox_classify_name, sort
+		FROM sandbox WHERE chart_classify_id = ? `
+	_, err = o.Raw(sql, sandboxClassifyId).QueryRows(&list)
+	return
+}
+
+// CheckOpSandboxPermission 判断沙盘操作权限
+func CheckOpSandboxPermission(sysUser *system.Admin, createUserId int) (ok bool) {
+	if sysUser.RoleTypeCode == utils.ROLE_TYPE_CODE_ADMIN || sysUser.RoleTypeCode == utils.ROLE_TYPE_CODE_FICC_ADMIN {
+		ok = true
+	}
+	// 如果图表创建人与当前操作人相同的话,那么就是允许操作
+	if ok == false && createUserId == sysUser.AdminId {
+		ok = true
+	}
+	// 如果图表权限id 是 1 ,那么允许编辑
+	if ok == false && sysUser.ChartPermission == 1 {
+		ok = true
+	}
+	return
+}

+ 54 - 0
routers/commentsRouter.go

@@ -4075,6 +4075,60 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/sandbox:SandboxController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/sandbox:SandboxController"],
+        beego.ControllerComments{
+            Method: "AddSandboxClassify",
+            Router: `/classify/add`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/sandbox:SandboxController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/sandbox:SandboxController"],
+        beego.ControllerComments{
+            Method: "DeleteSandboxClassify",
+            Router: `/classify/delete`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/sandbox:SandboxController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/sandbox:SandboxController"],
+        beego.ControllerComments{
+            Method: "DeleteSandboxClassifyCheck",
+            Router: `/classify/delete/check`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/sandbox:SandboxController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/sandbox:SandboxController"],
+        beego.ControllerComments{
+            Method: "EditSandboxClassify",
+            Router: `/classify/edit`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/sandbox:SandboxController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/sandbox:SandboxController"],
+        beego.ControllerComments{
+            Method: "SandboxClassifyItems",
+            Router: `/classify/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/sandbox:SandboxController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/sandbox:SandboxController"],
+        beego.ControllerComments{
+            Method: "ChartClassifyMove",
+            Router: `/classify/move`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/sandbox:SandboxController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/sandbox:SandboxController"],
         beego.ControllerComments{
             Method: "Delete",

+ 34 - 0
services/sandbox/sandbox.go

@@ -635,3 +635,37 @@ func checkoutContent(oldContent, reqContent string) (isUpdate bool) {
 
 	return
 }
+
+
+func sandboxClassifyHaveChild(allNode []*sandbox.SandboxClassifyItems, node *sandbox.SandboxClassifyItems) (childs []*sandbox.SandboxClassifyItems, yes bool) {
+	for _, v := range allNode {
+		if v.ParentId == node.SandboxClassifyId {
+			childs = append(childs, v)
+		}
+	}
+	if len(childs) > 0 {
+		yes = true
+	}
+	return
+}
+
+func ChartClassifyItemsMakeTree(sysUser *system.Admin, allNode []*sandbox.SandboxClassifyItems, node *sandbox.SandboxClassifyItems) {
+
+	childs, _ := sandboxClassifyHaveChild(allNode, node) //判断节点是否有子节点并返回
+	if len(childs) > 0 {
+
+		node.Children = append(node.Children, childs[0:]...) //添加子节点
+		for _, v := range childs {                           //查询子节点的子节点,并添加到子节点
+			_, has := sandboxClassifyHaveChild(allNode, v)
+			if has {
+				ChartClassifyItemsMakeTree(sysUser, allNode, v) //递归添加节点
+			} else {
+				childrenArr := make([]*sandbox.SandboxClassifyItems, 0)
+				v.Children = childrenArr
+			}
+		}
+	} else {
+		childrenArr := make([]*sandbox.SandboxClassifyItems, 0)
+		node.Children = childrenArr
+	}
+}