/* * @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/utils" "go.mod/web/viewmodels" ) // 定义项目Service接口 type TreeService interface { //ValidManager(code string, account string, password string) error ValidRule(ctx iris.Context) (viewmodels.Tree, error) ValidRuleBidsectionType(ctx iris.Context) (viewmodels.Permission, error) Create(data viewmodels.Tree) error GetAllProject(projectId int) *viewmodels.Tree GetAllContract(projectId int, account *models.CmProjectAccount, bidsectionType int) *viewmodels.FolderContract GetAllContractByJL(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 permissionAccountDao *dao.PermissionAccountDao } // 创建项目service func NewTreeService() TreeService { return &treeService{ dao: dao.NewTreeDao(datasource.InstanceDbMaster()), permissionAccountDao: dao.NewPermissionAccountDao(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) ValidRuleBidsectionType(ctx iris.Context) (viewmodels.Permission, error) { folderVaild := viewmodels.Permission{} err := ctx.ReadForm(&folderVaild) if err != nil { log.Println("folder-ValidRule-ReadForm转换异常, error=", err) return folderVaild, err } err = folderVaild.ValidateType() 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 = "根目录" folder.Isfolder = 1 folder.ParentId = parentId folder.Children = make([]*viewmodels.Tree, 0) 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.Accounts = data.Accounts 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, account *models.CmProjectAccount, bidsectionType int) *viewmodels.FolderContract { datalist := s.dao.GetAllTree(projectId) folderlist := make([]viewmodels.FolderContract, 0) // 2.获得该账号的权限 permissionData := s.permissionAccountDao.GetProjectIdAccountId(projectId, account.Id) // 生成根 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 // folder.Children = make([]*viewmodels.FolderContract, 0) folderlist = append(folderlist, folder) // 加入数据 for _, data := range datalist { flag := true // 标段过滤开始 if data.BidsectionId != 0 && account.IsAdmin != 1 { flag = false } // 过滤没有权限访问的标段-管理员不需要过滤 if data.BidsectionId != 0 && account.IsAdmin != 1 { permission := map[string]int{} for _, item := range permissionData { if data.BidsectionId == item.BidsectionId { // 区别合同,安全,质量 if bidsectionType == 1 { json.Unmarshal([]byte(item.SafePermission), &permission) } else if bidsectionType == 2 { json.Unmarshal([]byte(item.QualityPermission), &permission) } else if bidsectionType == 0 { json.Unmarshal([]byte(item.ContractPermission), &permission) // fmt.Println(permission) // if permission["access"] == 1 { // flag = true // break // } } else { return nil } if permission["access"] == 1 { flag = true break } } } } // 标段过滤结束 if flag { 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 contractsIncome, _ := strconv.ParseFloat(data.ContractsIncome, 64) contractsReturned, _ := strconv.ParseFloat(data.ContractsReturned, 64) folder.ContractsIncome = utils.PriceToStringFormat(contractsIncome) folder.ContractsReturned = utils.PriceToStringFormat(contractsReturned) contractDeductionTotal, _ := strconv.ParseFloat(data.ContractDeductionTotal, 64) folder.ContractDeductionTotal = utils.PriceToStringFormat(contractDeductionTotal) // 汇款进度 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("%.2f", (ContractsReturned/ContractsIncome)*100) } contractsPay, _ := strconv.ParseFloat(data.ContractsPay, 64) contractsPaid, _ := strconv.ParseFloat(data.ContractsPaid, 64) folder.ContractsPay = utils.PriceToStringFormat(contractsPay) folder.ContractsPaid = utils.PriceToStringFormat(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("%.2f", (ContractsPaid/ContractsPay)*100) } // 安全 folder.SafeTotal = data.SafeTotal folder.SafeRectification = data.SafeRectification folder.SafeRectificationFinish = data.SafeRectificationFinish folder.SafeRectificationIn = data.SafeRectificationIn folder.SafeApproval = data.SafeApproval folder.SafeClose = data.SafeClose // 质量 folder.QualityTotal = data.QualityTotal folder.QualityApproval = data.QualityApproval folder.QualityRectification = data.QualityRectification folder.QualityRectificationFinish = data.QualityRectificationFinish folder.QualityRectificationIn = data.QualityRectificationIn folder.QualityClose = data.QualityClose folder.Isfolder = data.Isfolder folder.IsEnd = false folder.HasFolder = false folder.IsBid = false folderlist = append(folderlist, folder) } } 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 s.filterFolder(node) // 删除空目录 ChildrenShow := make([]*viewmodels.FolderContract, 0) for _, item := range node.Children { if item.IsHidden == 0 { ChildrenShow = append(ChildrenShow, item) } } node.Children = ChildrenShow // node.Children = s.copyShowFolder(node.Children) // fmt.Println(node) return node } // 复制出需要展示的目录 // func (s *treeService) copyShowFolder(children []*viewmodels.FolderContract) []*viewmodels.FolderContract { // ChildrenShow := make([]*viewmodels.FolderContract, 0) // for _, item := range children { // if item.IsHidden == 0 { // ChildrenShow = append(ChildrenShow, item) // } // } // return ChildrenShow // } func (s *treeService) filterFolder(node *viewmodels.FolderContract) { if node == nil { return } // 目录下是否为空目录 1空目录 isEmptyFolder := 1 length := len(node.Children) // 如果length为0叶子节点---为目录才需要遍历 if length == 0 { // 1.如果是目录-已经为叶子目录不需要遍历 // 2.是标段 目录不为空 if node.Isfolder == 0 { isEmptyFolder = 0 } } else { // 1.遍历目录下 for i := 0; i < length; i++ { // 2.该节点下子对象 从0-length 依次进入 s.filterFolder(node.Children[i]) // 后序-父节点逻辑 处理完0 ... -length // 2-1 是标段 设置目录不为空 if node.Children[i].Isfolder == 0 { // 有标段 isEmptyFolder = 0 } else { // 2-2 是目录 ----后序遍历,最后一层下的孩子们是否能删除 走完三个点后返回到父亲 // 2-2-1 可展示目录 集合 ChildrenShow := make([]*viewmodels.FolderContract, 0) // 2-2-2 目录下内容 if len(node.Children[i].Children) != 0 { // 2-2-3 内容中是否有需要显示的目录 for _, item := range node.Children[i].Children { // 2-2-4 有 设置为需要显示并拷贝显示内容 if item.IsHidden == 0 { ChildrenShow = append(ChildrenShow, item) node.Children[i].IsHidden = 0 } } } // 2-2-5 覆盖父亲节点的显示内容 node.Children[i].Children = ChildrenShow // s.copyShowFolder(node.Children[i].Children) // fmt.Println("==========filterFolder执行完成") // fmt.Println(node.Children[i].Name) // fmt.Println(fmt.Sprintf("删除:%d", node.Children[i].IsHidden)) // fmt.Println(node.Children[i].Children) } } } // fmt.Println("=========================进入") // fmt.Println(node.Name) // fmt.Println(fmt.Sprintf("空目录:%d", isEmptyFolder)) // 后序的第一位叶子节点 如果目录为空,设置不显示 if isEmptyFolder == 1 { node.IsHidden = 1 } } // 新增一个文件夹 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 } // 获得合同管理的目录 func (s *treeService) GetAllContractByJL(projectId int) *viewmodels.FolderContract { datalist := s.dao.GetAllTree(projectId) folderlist := make([]viewmodels.FolderContract, 0) // 生成根 folder := viewmodels.FolderContract{} id := strconv.Itoa(0) parentId := strconv.Itoa(-1) folder.Id = id folder.Name = "root" folder.ParentId = parentId folder.Isfolder = 1 // folder.Children = make([]*viewmodels.FolderContract, 0) folderlist = append(folderlist, folder) // 加入数据 for _, data := range datalist { folder := viewmodels.FolderContract{} id := strconv.Itoa(data.Id) parentId := strconv.Itoa(data.ParentId) projectId := strconv.Itoa(data.ProjectId) bidsectionId := strconv.Itoa(data.BidsectionId) folder.Id = id folder.Name = data.Name folder.ParentId = parentId folder.ProjectId = projectId folder.BidsectionId = bidsectionId // 合同数据 folder.Contracts = data.Contracts contractsIncome, _ := strconv.ParseFloat(data.ContractsIncome, 64) contractsReturned, _ := strconv.ParseFloat(data.ContractsReturned, 64) folder.ContractsIncome = utils.PriceToStringFormat(contractsIncome) folder.ContractsReturned = utils.PriceToStringFormat(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("%.2f", (ContractsReturned/ContractsIncome)*100) } contractsPay, _ := strconv.ParseFloat(data.ContractsPay, 64) contractsPaid, _ := strconv.ParseFloat(data.ContractsPaid, 64) folder.ContractsPay = utils.PriceToStringFormat(contractsPay) folder.ContractsPaid = utils.PriceToStringFormat(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("%.2f", (ContractsPaid/ContractsPay)*100) } // 安全 folder.SafeTotal = data.SafeTotal folder.SafeRectification = data.SafeRectification folder.SafeRectificationFinish = data.SafeRectificationFinish folder.SafeRectificationIn = data.SafeRectificationIn folder.SafeApproval = data.SafeApproval folder.SafeClose = data.SafeClose // 质量 folder.QualityTotal = data.QualityTotal folder.QualityApproval = data.QualityApproval folder.QualityRectification = data.QualityRectification folder.QualityRectificationFinish = data.QualityRectificationFinish folder.QualityRectificationIn = data.QualityRectificationIn folder.QualityClose = data.QualityClose folder.Isfolder = data.Isfolder folder.IsEnd = false folder.HasFolder = false folder.IsBid = false folderlist = append(folderlist, folder) } 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 s.filterFolder(node) // 删除空目录 ChildrenShow := make([]*viewmodels.FolderContract, 0) for _, item := range node.Children { if item.IsHidden == 0 { ChildrenShow = append(ChildrenShow, item) } } node.Children = ChildrenShow // node.Children = s.copyShowFolder(node.Children) // fmt.Println(node) return node } // 创建一颗树...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 // } // }