package create import ( "context" "encoding/json" "fmt" "math/rand" "time" "github.com/gogf/gf/v2/util/gconv" "github.com/sony/sonyflake" "github.com/tiger1103/gfast/v3/api/v1/system" "github.com/tiger1103/gfast/v3/internal/app/system/dao" "github.com/tiger1103/gfast/v3/internal/app/system/model" "github.com/tiger1103/gfast/v3/internal/app/system/model/do" "github.com/tiger1103/gfast/v3/internal/app/system/model/entity" "github.com/tiger1103/gfast/v3/internal/consts" ) // 创建 gantt json 数据 func CreateGanttJson(ctx context.Context, fangzhenName string, parentName string, data []entity.ProjectSchedule) (string, error) { // 层级: 方阵名 --> 施工项目名 --> 子施工项目名 ganttData := make([]system.Gantt, 0, len(data)) // 添加项目名 ganttData = append(ganttData, system.Gantt{Id: 1, StartDate: "2024-01-01 00:00:00", Duration: 15, Text: "方阵1", Parent: 0, Progress: 0, Open: true}) ganttData = append(ganttData, system.Gantt{Id: 2, StartDate: "2024-01-01 00:00:00", EndDate: "2024-01-15 00:00:00", Duration: 15, Text: "防雷接地网", Parent: 1, Progress: 0, Open: true}) i := 3 for _, project := range data { ganttData = append(ganttData, system.Gantt{ Id: int64(i), StartDate: project.StartDate + " 00:00:00", EndDate: project.EndDate + " 00:00:00", Duration: rand.Intn(10) + 1, Text: project.Name, // Progress: float64(project.CurrentProgress), Parent: 2, Open: true, }) aa := entity.ProjectSchedule{} if err := dao.ProjectSchedule.Ctx(ctx).Where(dao.ProjectSchedule.Columns().ParentId, project.ParentId). WhereNotNull(dao.ProjectSchedule.Columns().Types).Scan(&aa); err != nil { return "", err } ganttData = append(ganttData, system.Gantt{ Id: int64(i + 1), StartDate: aa.StartDate + " 00:00:00", EndDate: aa.EndDate + " 00:00:00", Duration: 1, Text: "计划中", Parent: int64(i), }) i += 2 } // 打印 gantt json 数据 dd, _ := json.Marshal(ganttData) println(string(dd)) return string(dd), nil } func CreateGanttJson2(ctx context.Context, fangzhenName string, parentName string, data []entity.ProjectSchedule) ([]system.Gantt, error) { // 层级: 方阵名 --> 施工项目名 --> 子施工项目名 ganttData := make([]system.Gantt, 0, len(data)) // 添加项目名 ganttData = append(ganttData, system.Gantt{Id: 1, StartDate: "2024-01-01 00:00:00", Duration: 15, Text: fangzhenName, Parent: 0, Progress: 0, Open: true}) ganttData = append(ganttData, system.Gantt{Id: 2, StartDate: "2024-01-01 00:00:00", EndDate: "2024-01-15 00:00:00", Duration: 15, Text: parentName, Parent: 1, Progress: 0, Open: true}) i := 3 index := 0 for i < len(data) { ganttData = append(ganttData, system.Gantt{ Id: int64(i), StartDate: data[index].StartDate + " 00:00:00", EndDate: data[index].EndDate + " 00:00:00", Duration: rand.Intn(10) + 1, Text: data[index].Name, Parent: 2, Open: true, }) ganttData = append(ganttData, system.Gantt{ Id: int64(i + 1), StartDate: data[index+1].StartDate + " 00:00:00", EndDate: data[index+1].EndDate + " 00:00:00", Duration: 1, Text: "计划中", Parent: int64(i), }) index += 2 i += 2 if index >= len(data) { break } } return ganttData, nil } type projects struct { Name string StartTime string EndTime string Sub []subJ } type subJ struct { Name string ID int ParentID int StartTime string EndTime string } func FetchGanttData(ctx context.Context, matrixID int) ([]system.Gantt, error) { projectData := []entity.ConstructionProject{} // 获取指定方阵下的所有父项目 if err := dao.ConstructionProject.Ctx(ctx). Where(dao.ConstructionProject.Columns().FangzhenId, matrixID).Scan(&projectData); err != nil { return nil, err } // 父子项目列表 projectList := []projects{} // 构造所有的父项目及子项目 for _, project := range projectData { detailData := []entity.ConstructionDetails{} if err := dao.ConstructionDetails.Ctx(ctx). Where(dao.ConstructionDetails.Columns().ConstructionId, project.ConstructionId).Scan(&detailData); err != nil { return nil, err } // 如果 start_time 和 end_time 为空则使用当前时间 var startTime string var endTime string if project.StartTime == nil { startTime = time.Now().Format("2006-01-02 15:04:05") } else { startTime = project.StartTime.Format("2006-01-02 15:04:05") } if project.EndTime == nil { endTime = time.Now().Format("2006-01-02 15:04:05") } else { endTime = project.EndTime.Format("2006-01-02 15:04:05") } // 父 projectItem := projects{ Name: project.ConstructionName, StartTime: startTime, EndTime: endTime, Sub: make([]subJ, 0, len(detailData)), } // 子 for _, detail := range detailData { // 如果 start_time 和 end_time 为空则使用当前时间 var startTime string var endTime string if detail.StartTime == nil { startTime = time.Now().Format("2006-01-02 15:04:05") } else { startTime = detail.StartTime.Format("2006-01-02 15:04:05") } if detail.EndTime == nil { endTime = time.Now().Format("2006-01-02 15:04:05") } else { endTime = detail.EndTime.Format("2006-01-02 15:04:05") } projectItem.Sub = append(projectItem.Sub, subJ{ Name: detail.Name, ID: int(detail.Id), ParentID: int(detail.Id), StartTime: startTime, EndTime: endTime, }) } projectList = append(projectList, projectItem) } // 1 获取所有的排期数据 schedulerList := []entity.ProjectSchedule{} if err := dao.ProjectSchedule.Ctx(ctx).WhereNot(dao.ProjectSchedule.Columns().Types, 0). Scan(&schedulerList); err != nil { } // 子项目存在多个排期的情况下,需要将排期数据进行分组 scheduleMap := make(map[int][]entity.ProjectSchedule, 0) for _, schedule := range schedulerList { if _, ok := scheduleMap[schedule.ParentId]; !ok { scheduleMap[schedule.ParentId] = make([]entity.ProjectSchedule, 0, 1) } scheduleMap[schedule.ParentId] = append(scheduleMap[schedule.ParentId], schedule) } // 1.1 传入 parentid 返回一个子项目的排期数据 findSub := func(parentID int) ([]entity.ProjectSchedule, bool) { if schedule, ok := scheduleMap[parentID]; ok { return schedule, true } return nil, false } // 主任务 ganttList := make([]system.Gantt, 0, len(projectList)) taskIndex := 1 // 查询任务是否存在排期如果存在则不添加 for _, project := range projectList { // 父级数据 ganttList = append(ganttList, system.Gantt{ Id: int64(taskIndex), StartDate: project.StartTime, Duration: 15, Text: project.Name, Parent: 0, Open: true, }) taskIndex++ // 记录当前主项目的下标 parentIndex := taskIndex for _, sub := range project.Sub { scheduleData, ok := findSub(sub.ParentID) // 如果有排期的情况下,填充真实数据 if ok { // 添加子任务 ganttList = append(ganttList, system.Gantt{ Id: int64(taskIndex), StartDate: sub.StartTime, EndDate: sub.EndTime, Duration: rand.Intn(10) + 1, Text: sub.Name, Parent: int64(parentIndex) - 1, ConstructionId: sub.ID, }) // 记录当前子项目的下标 subIndex := taskIndex taskIndex++ for _, schedule := range scheduleData { // 添加子任务排期计划 ganttList = append(ganttList, system.Gantt{ Id: int64(taskIndex), StartDate: schedule.StartDate + " 00:00:00", EndDate: schedule.EndDate + " 00:00:00", Duration: gconv.Int(schedule.PlaneNum), Text: "计划中", Parent: int64(subIndex), ConstructionId: sub.ID, Open: true, }) taskIndex++ } continue } // 添加子任务,如果没有排期的情况下,填充假数据,维护队列 ganttList = append(ganttList, system.Gantt{ Id: int64(taskIndex), StartDate: "2029-01-01 00:00:00", Duration: 15, Text: sub.Name, Parent: int64(parentIndex) - 1, ConstructionId: sub.ID, Open: true, }) taskIndex++ } } return ganttList, nil } func FetchElementData(ctx context.Context, fangzhenId int) ([]*model.WorkStatusProgressRes, error) { // 获取所有的父项目 projectData := []entity.WorkStatus{} if err := dao.WorkStatus.Ctx(ctx).Where(dao.WorkStatus.Columns().FangzhenId, fangzhenId).WhereNull(dao.WorkStatus.Columns().Parent). Scan(&projectData); err != nil { return nil, err } // 获取所有的子项目 detailData := []entity.WorkStatus{} if err := dao.WorkStatus.Ctx(ctx).Where(dao.WorkStatus.Columns().FangzhenId, fangzhenId).WhereNotNull(dao.WorkStatus.Columns().Parent).Scan(&detailData); err != nil { return nil, err } // 根据关联关系进行数据拼接 index := 1 projectList := []*model.WorkStatusProgressRes{} for _, project := range projectData { // 父级数据 projectItem := model.WorkStatusProgressRes{ ID: index, Startat: project.StartAt.String(), Endat: project.EndAt.String(), Name: project.WorkName, Total: project.Total, Finished: project.Finished, Children: make([]model.WorkStatusProgressRes, 0, len(detailData)), } index++ // 子 for _, detail := range detailData { if detail.Parent == int(project.Id) { projectItem.Children = append(projectItem.Children, model.WorkStatusProgressRes{ ID: index, Startat: detail.StartAt.String(), Endat: detail.EndAt.String(), Name: detail.WorkName, Total: detail.Total, Finished: detail.Finished, }) index++ } } projectList = append(projectList, &projectItem) } return projectList, nil } func randomDate(dateStr string) string { t, _ := time.Parse("2006-01-02", dateStr) randDays := time.Duration(rand.Intn(2)+1) * 24 * time.Hour newDate := t.Add(-randDays) return newDate.Format("2006-01-02") } // 获取雪花算法生成的 ID func GetSonyFlakeID() (uint64, error) { // 初始化 sonyFlake 配置 st := sonyflake.Settings{} sonyFlake := sonyflake.NewSonyflake(st) if sonyFlake == nil { return 0, fmt.Errorf("需要先初始化以后再执行 GetID 函数") } // 获取全局 ID id, err := sonyFlake.NextID() if err != nil { return 0, err } return id, nil } func GetSonyFlakeIDs(mID uint16, count int) (ids []uint64, err error) { // 初始化 sonyFlake 配置 st := sonyflake.Settings{} sonyFlake := sonyflake.NewSonyflake(st) if sonyFlake == nil { err = fmt.Errorf("需要先初始化以后再执行 GetID 函数 err: %#v \n", err) return } // 获取全局 ID ids = make([]uint64, count) for i := 0; i < count; i++ { id, err := sonyFlake.NextID() if err != nil { return nil, err } ids[i] = id } return ids, nil } // FetchTemplateData 为方阵绑定父子项目 func FetchTemplateData(ctx context.Context, protectionNetID int64) ([]do.WorkStatus, error) { facilityGroups := createFacilities() // 雪花算法生成 ID ids, err := GetSonyFlakeIDs(1, 38) if err != nil { return nil, err } details := make([]do.WorkStatus, 0, len(facilityGroups)) index := 0 for _, group := range facilityGroups { projectID, err := dao.WorkStatus.Ctx(ctx).Data(do.WorkStatus{ FangzhenId: protectionNetID, WorkId: ids[index], WorkName: group.Name, Total: group.FacilityCount, Type: group.TypeNumber, IsPercent: group.IsPercentage, Status: 0, }).InsertAndGetId() if err != nil { return nil, err } index++ for _, component := range group.Components { details = append(details, do.WorkStatus{ FangzhenId: protectionNetID, Parent: projectID, WorkId: ids[index], WorkName: component.Name, Total: component.Quantity, IsPercent: component.IsPercentage, Type: component.TypeNumber, Status: 0, }) index++ } } return details, nil } // 为方阵绑定施工项目 func CreateConstructionProject(ctx context.Context, protectionNetID int64) error { facilityGroups := createFacilities() details := make([]do.ConstructionDetails, len(facilityGroups)) for _, group := range facilityGroups { projectID, err := dao.ConstructionProject.Ctx(ctx).Data(do.ConstructionProject{ FangzhenId: protectionNetID, ConstructionName: group.Name, Total: group.FacilityCount, IsPercentage: group.IsPercentage, }).InsertAndGetId() if err != nil { return err } for _, component := range group.Components { details = append(details, do.ConstructionDetails{ Name: component.Name, ConstructionId: projectID, Total: component.Quantity, IsPercentage: component.IsPercentage, }) } } _, err := dao.ConstructionDetails.Ctx(ctx).Batch(50).Insert(details) if err != nil { return err } return nil } func createFacilities() []system.FacilityGroup { return []system.FacilityGroup{{ Name: "防雷接地网", FacilityCount: nil, IsPercentage: &[]int{0}[0], TypeNumber: consts.LightningProtectionNet, Components: []system.Component{ { Name: "接地沟", IsPercentage: &[]int{1}[0], Quantity: 0, TypeNumber: consts.GroundingDitch, }, { Name: "接地敷设", IsPercentage: &[]int{1}[0], Quantity: 0, TypeNumber: consts.GroundingLaying, }, { Name: "检测", IsPercentage: &[]int{1}[0], Quantity: 0, TypeNumber: consts.GroundingTesting, }, }, }, { Name: "围栏", FacilityCount: nil, IsPercentage: &[]int{0}[0], TypeNumber: consts.Fence, Components: []system.Component{ { Name: "基础", IsPercentage: &[]int{0}[0], Quantity: 100, TypeNumber: consts.FenceFoundation, }, { Name: "安装", IsPercentage: &[]int{0}[0], Quantity: 100, TypeNumber: consts.FenceInstallation, }, }, }, { Name: "道路", IsPercentage: &[]int{0}[0], TypeNumber: consts.Road, Components: []system.Component{ { Name: "路基", IsPercentage: &[]int{0}[0], Quantity: 100, TypeNumber: consts.RoadBase, }, { Name: "排水沟", IsPercentage: &[]int{0}[0], Quantity: 100, TypeNumber: consts.RoadDrainageDitch, }, }, }, { Name: "低压部分", IsPercentage: &[]int{0}[0], FacilityCount: &[]int{0}[0], TypeNumber: consts.LowVoltage, Components: []system.Component{ { Name: "钻孔", IsPercentage: &[]int{1}[0], Quantity: 0, TypeNumber: consts.LowVoltageDrilling, }, { Name: "桩基", IsPercentage: &[]int{1}[0], Quantity: 0, TypeNumber: consts.LowVoltagePileFoundation, }, { Name: "支架", IsPercentage: &[]int{1}[0], Quantity: 0, TypeNumber: consts.LowVoltageBracket, }, { Name: "光伏板", IsPercentage: &[]int{1}[0], Quantity: 0, TypeNumber: consts.LowVoltagePhotovoltaicPanel, }, { Name: "直流电缆", IsPercentage: &[]int{1}[0], Quantity: 0, TypeNumber: consts.LowVoltageDC, }, { Name: "接地线", IsPercentage: &[]int{1}[0], Quantity: 0, TypeNumber: consts.LowVoltageGroundWire, }, { Name: "逆变器安装", IsPercentage: &[]int{1}[0], TypeNumber: consts.LowVoltageInverterInstallation, }, { Name: "电缆沟开挖", IsPercentage: &[]int{1}[0], Quantity: 0, TypeNumber: consts.LowVoltageCableTrenchExcavation, }, { Name: "低压电缆敷设", IsPercentage: &[]int{1}[0], Quantity: 0, TypeNumber: consts.LowVoltageLaying, }, { Name: "调试", IsPercentage: &[]int{1}[0], Quantity: 0, TypeNumber: consts.LowVoltageDebugging, }, }, }, { Name: "高压部分", IsPercentage: &[]int{1}[0], TypeNumber: consts.HighVoltage, Components: []system.Component{ { Name: "箱变基础", IsPercentage: &[]int{1}[0], TypeNumber: consts.HighVoltageBoxChangeFoundation, }, { Name: "箱变安装", IsPercentage: &[]int{1}[0], TypeNumber: consts.HighVoltageBoxChangeInstallation, }, { Name: "电缆沟开挖", IsPercentage: &[]int{1}[0], TypeNumber: consts.HighVoltageCableLineExcavation, }, { Name: "高压电缆敷设", IsPercentage: &[]int{1}[0], TypeNumber: consts.HighVoltageCableLaying, }, { Name: "高压电缆试验", IsPercentage: &[]int{1}[0], TypeNumber: consts.HighVoltageCableTest, }, { Name: "高压电缆调试试验", IsPercentage: &[]int{1}[0], TypeNumber: consts.HighVoltageCableDebuggingTest, }, }, }, { Name: "环网柜", IsPercentage: &[]int{1}[0], TypeNumber: consts.RingMainCabinet, Components: []system.Component{ { Name: "基础", IsPercentage: &[]int{1}[0], TypeNumber: consts.RingMainCabinetFoundation, }, { Name: "安装", IsPercentage: &[]int{1}[0], TypeNumber: consts.RingMainCabinetInstallation, }, { Name: "敷设", IsPercentage: &[]int{1}[0], TypeNumber: consts.RingMainCabinetLaying, }, { Name: "试验", IsPercentage: &[]int{1}[0], TypeNumber: consts.RingMainCabinetTest, }, { Name: "调试试验", IsPercentage: &[]int{1}[0], TypeNumber: consts.RingMainCabinetDebuggingTest, }, }, }} }