/* * @description:层级文件夹数据操作相关 * @Author: CP * @Date: 2020-09-11 14:43:58 * @FilePath: \construction_management\services\tree_service.go */ package services import ( "encoding/json" "errors" "fmt" "log" "strconv" "time" "github.com/kataras/iris/v12" "go.mod/comm" "go.mod/conf" "go.mod/dao" "go.mod/datasource" "go.mod/models" "go.mod/web/viewmodels" ) //定义项目Service接口 type TreeService interface { //ValidManager(code string, account string, password string) error ValidRule(ctx iris.Context) (viewmodels.Tree, error) Create(data viewmodels.Tree) error GetAllProject(projectId int) *viewmodels.Tree GetAllContract(projectId int) *viewmodels.FolderContract Rename(treevm viewmodels.Tree, projectId int) error GetFolderAndBid(id int, projectId int) ([]models.CmTree, error) DeleteFolderAndBid(id int, projectId int) error Move(id int, moveId int, projectId int) error } //返回service操作类 type treeService struct { dao *dao.TreeDao } //创建项目service func NewTreeService() TreeService { return &treeService{ dao: dao.NewTreeDao(datasource.InstanceDbMaster()), } } // 文件夹规则验证 func (s *treeService) ValidRule(ctx iris.Context) (viewmodels.Tree, error) { folderVaild := viewmodels.Tree{} err := ctx.ReadJSON(&folderVaild) if err != nil { log.Println("folder-ValidRule-ReadForm转换异常, error=", err) return folderVaild, err } err = folderVaild.Validate() if err != nil { log.Println("文件夹验证, error=", err) return folderVaild, err } return folderVaild, nil } // 获得项目下 相关文件夹-整个树结构 func (s *treeService) GetAllProject(projectId int) *viewmodels.Tree { datalist := s.dao.GetAllTree(projectId) folderlist := make([]*viewmodels.Tree, 0) // 生成根 folder := &viewmodels.Tree{} id, _ := comm.AesEncrypt(strconv.Itoa(0), conf.SignSecret) parentId, _ := comm.AesEncrypt(strconv.Itoa(-1), conf.SignSecret) folder.Id = id folder.Name = "root" folder.Isfolder = 1 folder.ParentId = parentId folderlist = append(folderlist, folder) // 加入数据 for _, data := range datalist { folder := &viewmodels.Tree{} //folder.Id = comm.Encrypt([]byte(conf.SignSecret), []byte(strconv.Itoa(data.Id))) id, _ := comm.AesEncrypt(strconv.Itoa(data.Id), conf.SignSecret) parentId, _ := comm.AesEncrypt(strconv.Itoa(data.ParentId), conf.SignSecret) projectId, _ := comm.AesEncrypt(strconv.Itoa(data.ProjectId), conf.SignSecret) serial, _ := comm.AesEncrypt(strconv.Itoa(data.Serial), conf.SignSecret) bidsectionId, _ := comm.AesEncrypt(strconv.Itoa(data.BidsectionId), conf.SignSecret) folder.Id = id folder.Name = data.Name folder.ParentId = parentId folder.ProjectId = projectId folder.BidsectionId = bidsectionId folder.Depth = data.Depth + 1 folder.Serial = serial folder.Ancounts = data.Ancounts folder.Isfolder = data.Isfolder folder.IsEnd = false //folder.Leaf = true folder.HasFolder = false folder.IsBid = false folder.CreateTime = data.CreateTime.Format(conf.SysTimeform) folderlist = append(folderlist, folder) } //fmt.Println(folderlist) //var data []*viewmodels.Tree // data := make([]*viewmodels.Tree, 0) // for i, _ := range folderlist { // var a *viewmodels.Tree // a = &folderlist[i] // data = append(data, a) // } node := folderlist[0] //父节点 maketree(folderlist, node) //调用生成tree //transformjson(node) //转化为json return node } // 获得合同管理的目录 func (s *treeService) GetAllContract(projectId int) *viewmodels.FolderContract { datalist := s.dao.GetAllTree(projectId) folderlist := make([]viewmodels.FolderContract, 0) // 生成根 folder := viewmodels.FolderContract{} id, _ := comm.AesEncrypt(strconv.Itoa(0), conf.SignSecret) parentId, _ := comm.AesEncrypt(strconv.Itoa(-1), conf.SignSecret) folder.Id = id folder.Name = "root" folder.ParentId = parentId folder.Isfolder = 1 folderlist = append(folderlist, folder) // 加入数据 for _, data := range datalist { folder := viewmodels.FolderContract{} id, _ := comm.AesEncrypt(strconv.Itoa(data.Id), conf.SignSecret) parentId, _ := comm.AesEncrypt(strconv.Itoa(data.ParentId), conf.SignSecret) projectId, _ := comm.AesEncrypt(strconv.Itoa(data.ProjectId), conf.SignSecret) bidsectionId, _ := comm.AesEncrypt(strconv.Itoa(data.BidsectionId), conf.SignSecret) folder.Id = id folder.Name = data.Name folder.ParentId = parentId folder.ProjectId = projectId folder.BidsectionId = bidsectionId // 合同数据 folder.Contracts = data.Contracts folder.ContractsIncome = data.ContractsIncome folder.ContractsReturned = data.ContractsReturned // 汇款进度 ContractsIncome, err := strconv.ParseFloat(data.ContractsIncome, 64) if err != nil { ContractsIncome = 0 } ContractsReturned, err := strconv.ParseFloat(data.ContractsReturned, 64) if err != nil || ContractsReturned == 0 { ContractsReturned = 0 folder.ContractsIncomeProgress = "0%" } else { folder.ContractsIncomeProgress = fmt.Sprintf("%.0f", (ContractsReturned/ContractsIncome)*100) + "%" } folder.ContractsPay = data.ContractsPay folder.ContractsPaid = data.ContractsPaid // 支付进度 ContractsPay, err := strconv.ParseFloat(data.ContractsPay, 64) if err != nil { ContractsPay = 0 } ContractsPaid, err := strconv.ParseFloat(data.ContractsPaid, 64) if err != nil || ContractsPaid == 0 { ContractsPaid = 0 folder.ContractsPayProgress = "0%" } else { folder.ContractsPayProgress = fmt.Sprintf("%.0f", (ContractsPaid/ContractsPay)*100) + "%" } folder.Isfolder = data.Isfolder folder.IsEnd = false folder.HasFolder = false folder.IsBid = false folderlist = append(folderlist, folder) } //fmt.Println(folderlist) var data []*viewmodels.FolderContract data = make([]*viewmodels.FolderContract, 0) for i, _ := range folderlist { var a *viewmodels.FolderContract a = &folderlist[i] data = append(data, a) } node := &folderlist[0] //父节点 comm.MakeFolderContract(data, node) // 求和 // dataLenght := len(data) + 4 return node } // 新增一个文件夹 func (s *treeService) Create(data viewmodels.Tree) error { // 类型校验 folder := models.CmTree{} folder.Name = data.Name // 项目ID ProjectId, err := strconv.Atoi(data.ProjectId) if err != nil { return err } // 获得该目录ID Id, err := comm.AesDecrypt(data.Id, conf.SignSecret) if err != nil { return err } IdInt, err1 := strconv.Atoi(Id) if err1 != nil { return err1 } // 该目录中是否有标段 bidlist := s.dao.GetBidsection(IdInt) if len(bidlist) > 0 { return errors.New("该文件夹已存在标段,不能在新增目录") } // 获得该深度的文件夹最大序号 serial := 0 depth := data.Depth + 1 if data.Depth == -1 { // 1-创建顶级目录--获得最大序号 datalist := s.dao.GetAllDepth(depth, ProjectId) maxIndex := len(datalist) if maxIndex != 0 { serial = datalist[maxIndex-1].Serial + 1 } } else { // 1-创建次目录-获得次级目录最大序号 treeNode := s.dao.Get(IdInt, ProjectId) // 去除前端depth作用-在这里获得下级目录的深度 depth = treeNode.Depth + 1 if treeNode.Id == 0 { return errors.New("上级目录不正确") } attribution := fmt.Sprintf("%s%d-", treeNode.Attribution, treeNode.Serial) datalist := s.dao.GetALLDepthByAttribution(depth, ProjectId, attribution) maxIndex := len(datalist) if maxIndex != 0 { serial = datalist[maxIndex-1].Serial + 1 } // 设置归属 folder.Attribution = attribution //treeNode.Attribution + strconv.Itoa(treeNode.Serial) + "-" folder.ParentId = IdInt } folder.ProjectId = ProjectId folder.Serial = serial folder.Depth = depth folder.Isfolder = 1 folder.CreateTime = time.Now() folder.UpdateTime = time.Now() folder.ContractsIncome = "0" folder.ContractsPaid = "0" folder.ContractsPay = "0" folder.ContractsReturned = "0" err = s.dao.Create(&folder) if err != nil { log.Println("添加目录出错, error=", err) return errors.New("添加目录出错") } return nil } // 重命名 func (s *treeService) Rename(data viewmodels.Tree, projectId int) error { // 获得该目录ID Id, err := comm.AesDecrypt(data.Id, conf.SignSecret) if err != nil { return err } IdInt, err1 := strconv.Atoi(Id) if err1 != nil { return err1 } // 获得树信息 treeData := s.dao.Get(IdInt, projectId) if treeData.Id == 0 { return errors.New("修改的目录不合法") } treeNode := models.CmTree{} treeNode.Id = IdInt treeNode.Name = data.Name if treeData.Isfolder == 1 { // 目录 err = s.dao.Update(&treeNode, []string{"Name"}) } else { // 标段 treeNode.BidsectionId = treeData.BidsectionId err = s.dao.Rename(&treeNode, []string{"Name"}) } if err != nil { return err } return nil } // 获得该目录下所有的目录和标段 func (s *treeService) GetFolderAndBid(id int, projectId int) ([]models.CmTree, error) { // 获得该目录ID // id, err := comm.AesDecrypt(id, conf.SignSecret) // if err != nil { // return nil, errors.New("目录解析错误") // } // IdInt, err := strconv.Atoi(id) // if err != nil { // return nil, errors.New("目录解析错误") // } // 获得该目录下所有数据 folder := s.dao.Get(id, projectId) if folder.Id == 0 { return nil, errors.New("目录不合法") } attribution := fmt.Sprintf("%s%d-", folder.Attribution, folder.Serial) // 获得目录归属 dataList := s.dao.GetFolderAndBid(folder.ProjectId, attribution) return dataList, nil } // 删除该目录和所属的目录和标段 func (s *treeService) DeleteFolderAndBid(id int, projectId int) error { // 获得该目录ID // id, err := comm.AesDecrypt(id, conf.SignSecret) // if err != nil { // return errors.New("目录解析错误") // } // IdInt, err := strconv.Atoi(id) // if err != nil { // return errors.New("目录解析错误") // } // 获得该目录下 归属关系 folder := s.dao.Get(id, projectId) if folder.Id == 0 { return errors.New("目录不合法") } attribution := fmt.Sprintf("%s%d-", folder.Attribution, folder.Serial) // --逻辑删除 目录和数据 err := s.dao.DeleteFolderAndBid(folder.Id, folder.ProjectId, attribution) if err != nil { return err } // TODO -加入堆栈 物理删除数据 return nil } // 移动目录 func (s *treeService) Move(id int, moveId int, projectId int) error { // 获得项目目录 treeNode := s.dao.Get(id, projectId) if treeNode.Id == 0 { return errors.New("目录或标段解析错误") } targetFolder := &models.CmTree{} // id为0是跟目录 if moveId == 0 { // id targetFolder.Id = 0 // 1.获得最大序号 // seriallist := s.dao.GetALLDepthByAttribution(0, projectId, "") // maxIndex := len(seriallist) // serial := 0 // if maxIndex != 0 { // serial = seriallist[maxIndex-1].Serial + 1 // } // targetFolder.Serial = serial targetFolder.Serial = 0 // 2.归属 targetFolder.Attribution = "" // 3.深度depth-根目录为-1 targetFolder.Depth = -1 // 4.为目录 targetFolder.Isfolder = 1 // 5.项目ID targetFolder.ProjectId = projectId // fmt.Println(targetFolder) // if targetFolder.Id == 0 { // return errors.New("目录解析错误-测试") // } } else { targetFolder = s.dao.Get(moveId, projectId) if targetFolder.Id == 0 { return errors.New("目录解析错误") } } // 目录必须是目录 if targetFolder.Isfolder == 0 { return errors.New("目标不是文件夹") } // 目录的目标不能是自己 if id == moveId { return errors.New("目标目录是原目录-不能移动") } // 移动的是目录 if treeNode.Isfolder == 1 { // 1.目录下不能有标段 // 被移动的目录存在标段 moveBidList := s.dao.GetBidsection(moveId) if len(moveBidList) > 0 { return errors.New("该目录中存在标段,不能移动") } } else { // 标段 // 1.移动的目录是否为叶子节点 moveBidList := s.dao.GetChildFolder(moveId) if len(moveBidList) > 0 { return errors.New("该目录中存在其他目录,不能移动") } } err := s.dao.Move(treeNode, targetFolder) if err != nil { return err } return nil } // 创建一颗树...interface{} func maketree(Data []*viewmodels.Tree, node *viewmodels.Tree) { //参数为父节点,添加父节点的子节点指针切片 childs, _ := havechild(Data, node) //判断节点是否有子节点并返回 if childs != nil { // fmt.Printf("\n") // fmt.Println(*node) // fmt.Println("子节点:") // for _, v := range childs { // fmt.Println(*v) // } //打印 // 子节点总数 Total := len(childs) node.ChildsTotal = Total // 标记最后一个元素 end := Total - 1 childs[end].IsEnd = true // 往父节点添加子节点 node.Children = append(node.Children, childs[0:]...) //添加子节点 for _, v := range childs { //查询子节点的子节点,并添加到子节点 _, has := havechild(Data, v) if has { // 递归添加节点 maketree(Data, v) } // else { // // 叶子节点 // node.Leaf = false // } // 目录下是否包含标段 if v.Isfolder == 0 { node.IsBid = true } else { node.HasFolder = true } } } } // 是否有子树 func havechild(Data []*viewmodels.Tree, node *viewmodels.Tree) (child []*viewmodels.Tree, yes bool) { for _, v := range Data { if v.ParentId == node.Id { child = append(child, v) } } if child != nil { yes = true } return } func transformjson(Data *viewmodels.Tree) { //转为json Jsondata, _ := json.Marshal(Data) fmt.Println(string(Jsondata)) } //now := comm.NowUnix() //comm.FormatFromUnixTime(now) // ParentIdInt := 0 // if data.ParentId != "" { // ParentId, err := comm.AesDecrypt(data.ParentId, conf.SignSecret) // if err != nil { // return err // } // ParentIdInt, err = strconv.Atoi(ParentId) // if err != nil { // ParentIdInt = 0 // } // }