package logic import ( "micro-bundle/internal/dao" commonErr "micro-bundle/pkg/err" "sort" "strings" ) // GetValidArtistList 查询套餐状态为有效中的艺人列表 // 调用dao层获取艺人详细信息 func GetValidArtistList() ([]dao.ValidArtistInfo, error) { return dao.GetValidArtistList() } // GetValidArtistIDs 查询套餐没有过期的艺人ID列表(保持向后兼容) // 根据BundleOrderRecords表查询过期时间大于当前时间且状态为已支付的艺人 func GetValidArtistIDs() ([]string, error) { artistList, err := GetValidArtistList() if err != nil { return nil, err } var artistIDs []string for _, artist := range artistList { if artist.CustomerNum != "" { artistIDs = append(artistIDs, artist.CustomerNum) } } return artistIDs, nil } // todo 目前暂时不做检验,后续需要做判断 // GetValidEmployeeIDs 查询可以被指派任务的员工ID列表 // 这里可以根据实际业务需求实现,比如查询员工表、权限表等 // 目前先返回一个示例实现,实际项目中需要根据具体的员工管理逻辑来实现 func GetValidEmployeeIDs() ([]string, error) { var employeeIDs []string return employeeIDs, nil } // ValidateEmployee 验证员工是否可以被指派任务 func ValidateEmployee(employeeNum string) (bool, error) { validEmployees, err := GetValidEmployeeIDs() if err != nil { return false, err } // 如果没有限制(返回空列表),则认为所有员工都可以被指派 if len(validEmployees) == 0 { return true, nil } for _, validEmp := range validEmployees { if validEmp == employeeNum { return true, nil } } return false, nil } // GetPendingTaskList 查询待指派任务记录 func GetPendingTaskList(req *dao.TaskQueryRequest) ([]*dao.TaskQueryResponse, int64, error) { // 1. 先查询套餐没有过期的艺人 validArtist, err := GetValidArtistList() if err != nil { return nil, 0, err } // 2. 调用DAO层查询待指派任务记录 record, total, err := dao.GetPendingTaskList(req, validArtist) if err != nil { return nil, 0, err } // 3. 转换为响应结构体 var recordResponse []*dao.TaskQueryResponse for _, record := range record { // 从TaskBalance表计算待发任务数量:任务余额 - 消耗数量 videoTotal, imageTotal, dataTotal := calculatePendingFromTaskBalance(record.SubNum) // 根据 SubNum 和 TelNum 查询对应的员工正在进行中的任务和已完成任务数量 progressTaskCount, completeTaskCount, err := dao.GetTaskAssigneeInfo(record.TaskAssigneeNum) if err != nil { recordResponse = append(recordResponse, &dao.TaskQueryResponse{ SubNum: record.SubNum, TelNum: record.TelNum, ArtistName: record.ArtistName, TaskAssigneeNum: record.TaskAssigneeNum, PendingPostCount: imageTotal, PendingVideoCount: videoTotal, PendingDataCount: dataTotal, ProgressTaskCount: 0, CompleteTaskCount: 0, LastTaskAssignee: record.LastTaskAssignee, }) } else { recordResponse = append(recordResponse, &dao.TaskQueryResponse{ SubNum: record.SubNum, TelNum: record.TelNum, ArtistName: record.ArtistName, TaskAssigneeNum: record.TaskAssigneeNum, PendingPostCount: imageTotal, PendingVideoCount: videoTotal, PendingDataCount: dataTotal, ProgressTaskCount: progressTaskCount, CompleteTaskCount: completeTaskCount, LastTaskAssignee: record.LastTaskAssignee, }) } } // 4. 处理待发数量相关的排序(在Logic层处理,因为这些数据从TaskBalance表计算) if req.SortBy != "" && req.SortType != "" { sortType := req.SortType if sortType != "asc" && sortType != "desc" && sortType != "ASC" && sortType != "DESC" { sortType = "DESC" } switch req.SortBy { case "pending_video_count", "pendingVideoCount": sort.Slice(recordResponse, func(i, j int) bool { if strings.ToUpper(sortType) == "ASC" { return recordResponse[i].PendingVideoCount < recordResponse[j].PendingVideoCount } return recordResponse[i].PendingVideoCount > recordResponse[j].PendingVideoCount }) case "pending_post_count", "pendingPostCount": sort.Slice(recordResponse, func(i, j int) bool { if strings.ToUpper(sortType) == "ASC" { return recordResponse[i].PendingPostCount < recordResponse[j].PendingPostCount } return recordResponse[i].PendingPostCount > recordResponse[j].PendingPostCount }) case "pending_data_count", "pendingDataCount": sort.Slice(recordResponse, func(i, j int) bool { if strings.ToUpper(sortType) == "ASC" { return recordResponse[i].PendingDataCount < recordResponse[j].PendingDataCount } return recordResponse[i].PendingDataCount > recordResponse[j].PendingDataCount }) case "progress_task_count", "progressTaskCount": sort.Slice(recordResponse, func(i, j int) bool { if strings.ToUpper(sortType) == "ASC" { return recordResponse[i].ProgressTaskCount < recordResponse[j].ProgressTaskCount } return recordResponse[i].ProgressTaskCount > recordResponse[j].ProgressTaskCount }) case "complete_task_count", "completeTaskCount": sort.Slice(recordResponse, func(i, j int) bool { if strings.ToUpper(sortType) == "ASC" { return recordResponse[i].CompleteTaskCount < recordResponse[j].CompleteTaskCount } return recordResponse[i].CompleteTaskCount > recordResponse[j].CompleteTaskCount }) } } // 5. 分页(在排序后进行) total = int64(len(recordResponse)) if req.PageSize > 0 && req.Page > 0 { offset := (req.Page - 1) * req.PageSize if offset < len(recordResponse) { end := offset + req.PageSize if end > len(recordResponse) { end = len(recordResponse) } recordResponse = recordResponse[offset:end] } else { recordResponse = []*dao.TaskQueryResponse{} } } return recordResponse, total, nil } // AssignTask 指派某位员工完成某个艺人的任务 func AssignTask(req *dao.TaskAssignRequest) error { // 1. 验证员工是否可以被指派任务 isValid, err := ValidateEmployee(req.TaskAssigneeNum) if err != nil { return err } if !isValid { return commonErr.ReturnError(nil, "员工不能被指派任务", "该员工不在可指派任务的员工列表中") } progressTaskCount, completeTaskCount, err := dao.GetTaskAssigneeInfo(req.TaskAssigneeNum) if err != nil { // 查询不到的话,给一个默认值 progressTaskCount, completeTaskCount = 1, 0 } // 2. 调用DAO层执行指派任务 // 待完成任务数量需要+1,因为这个任务暂时还没有指派,所以+1 return dao.AssignTask(req, progressTaskCount+1, completeTaskCount) } // UpdatePendingCount 修改待发数量 func UpdatePendingCount(req *dao.UpdatePendingCountRequest) error { // 1. 验证艺人是否有有效套餐 validArtistIDs, err := GetValidArtistIDs() if err != nil { return err } // 检查艺人是否在有效列表中 isValidArtist := false for _, artistID := range validArtistIDs { if artistID == req.SubNum { isValidArtist = true break } } if !isValidArtist { return commonErr.ReturnError(nil, "艺人套餐已过期", "该艺人没有有效的套餐,无法修改待发数量") } // 查询艺人当前任务余额,校验是否存在记录(不做数量比较,避免排除手动余额) _, err = dao.GetRemainingPendingBySubNum(req.SubNum) if err != nil { return commonErr.ReturnError(err, "查询艺人任务余额失败", "查询艺人任务余额失败: ") } // 2. 调用DAO层更新待发数量(DAO 内部已做充足的额度与当月限额校验) return dao.UpdatePendingCount(req) } // GetRecentAssignRecords 查询最近被指派记录 func GetRecentAssignRecords(limit int) ([]string, error) { records, err := dao.GetRecentAssignRecords(limit) if err != nil { return nil, err } var recordOperator []string for _, record := range records { recordOperator = append(recordOperator, record.TaskAssignee) } return recordOperator, nil } // GetEmployeeAssignedTasks 根据登录人信息查询被指派给该员工的艺人任务 func GetEmployeeAssignedTasks(req *dao.EmployeeTaskQueryRequest) ([]*dao.TaskAssignRecordsResponse, int64, error) { // 1. 调用DAO层查询被指派给该员工的艺人任务 record, total, err := dao.GetEmployeeAssignedTasks(req) if err != nil { return nil, 0, err } // 2. 转换为响应结构体 var recordResponse []*dao.TaskAssignRecordsResponse for _, record := range record { recordResponse = append(recordResponse, &dao.TaskAssignRecordsResponse{ AssignRecordsUUID: record.AssignRecordsUUID, SubNum: record.SubNum, TelNum: record.TelNum, ArtistName: record.ArtistName, Status: record.Status, ActualStatus: record.ActualStatus, CompleteTime: record.CompleteTime, OperatorType: record.OperatorType, Operator: record.Operator, OperatorNum: record.OperatorNum, OperatorTime: record.OperatorTime, TaskAssignee: record.TaskAssignee, TaskAssigneeNum: record.TaskAssigneeNum, PendingVideoCount: record.PendingVideoCount, PendingPostCount: record.PendingPostCount, PendingDataCount: record.PendingDataCount, // todo: 将更新时间转换成人类可读的格式 UpdatedAt: record.UpdatedAt, }) } return recordResponse, total, nil } // CompleteTaskManually 员工手动点击完成任务 func CompleteTaskManually(assignRecordsUUID string, taskAssigneeNum string) error { // // 第一步,批量更新记录被指派的员工为taskAssigneeNum的待完成任务数量和已经完成任务的数量 // err := dao.UpdateTaskRecordsByAssigneeNum(taskAssigneeNum) // if err != nil { // return err // } return dao.CompleteTaskManually(assignRecordsUUID) } // UpdateTaskProgress 员工实际完成任务状态更新 func UpdateTaskProgress(req *dao.CompleteTaskRequest) error { return dao.UpdateTaskProgress(req) } // GetTaskAssignRecordsList 多条件查询操作记录表 func GetTaskAssignRecordsList(req *dao.TaskAssignRecordsQueryRequest) ([]*dao.TaskAssignRecordsResponse, int64, error) { record, total, err := dao.GetTaskAssignRecordsList(req) if err != nil { return nil, 0, err } // 2. 转换为响应结构体 var recordResponse []*dao.TaskAssignRecordsResponse for _, record := range record { recordResponse = append(recordResponse, &dao.TaskAssignRecordsResponse{ AssignRecordsUUID: record.AssignRecordsUUID, SubNum: record.SubNum, TelNum: record.TelNum, ArtistName: record.ArtistName, Status: record.Status, ActualStatus: record.ActualStatus, CompleteTime: record.CompleteTime, OperatorType: record.OperatorType, Operator: record.Operator, OperatorNum: record.OperatorNum, OperatorTime: record.OperatorTime, TaskAssignee: record.TaskAssignee, TaskAssigneeNum: record.TaskAssigneeNum, PendingVideoCount: record.PendingVideoCount, PendingPostCount: record.PendingPostCount, PendingDataCount: record.PendingDataCount, UpdatedAt: record.UpdatedAt, }) } return recordResponse, total, nil } // 新增:查询艺人剩余待发数量(区分套餐/增值,共6个字段) func GetArtistRemainingPending(subNum string) (*dao.ArtistRemainingPendingResponse, error) { if strings.TrimSpace(subNum) == "" { return nil, commonErr.ReturnError(nil, "查询参数错误", "艺人编号不能为空") } return dao.GetRemainingPendingBySubNum(subNum) } // calculatePendingFromTaskBalance 从TaskBalance表计算待发任务数量 func calculatePendingFromTaskBalance(subNum string) (videoTotal, imageTotal, dataTotal int) { // 查询用户的任务余额 taskBalance, err := dao.GetTaskBalanceBySubNum(subNum) if err != nil || taskBalance == nil { return 0, 0, 0 } // 计算视频类待发数量:总余额 - 消耗数量 videoTotal = (taskBalance.TaskBundleVideoNumber - taskBalance.TaskBundleVideoConsumptionNumber) + (taskBalance.TaskIncreaseVideoNumber - taskBalance.TaskIncreaseVideoConsumptionNumber) + (taskBalance.TaskBundleLimitVideoNumber - taskBalance.TaskBundleLimitVideoConsumptionNumber) + (taskBalance.TaskIncreaseLimitVideoNumber - taskBalance.TaskIncreaseLimitVideoConsumptionNumber) + (taskBalance.TaskBundleLimitVideoExpiredNumber - taskBalance.TaskBundleLimitVideoExpiredConsumptionNumber) + (taskBalance.TaskIncreaseLimitVideoExpiredNumber - taskBalance.TaskIncreaseLimitVideoExpiredConsumptionNumber) if videoTotal < 0 { videoTotal = 0 } // 计算图片类待发数量:总余额 - 消耗数量 imageTotal = (taskBalance.TaskBundleImageNumber - taskBalance.TaskBundleImageConsumptionNumber) + (taskBalance.TaskIncreaseImageNumber - taskBalance.TaskIncreaseImageConsumptionNumber) + (taskBalance.TaskBundleLimitImageNumber - taskBalance.TaskBundleLimitImageConsumptionNumber) + (taskBalance.TaskIncreaseLimitImageNumber - taskBalance.TaskIncreaseLimitImageConsumptionNumber) + (taskBalance.TaskBundleLimitImageExpiredNumber - taskBalance.TaskBundleLimitImageExpiredConsumptionNumber) + (taskBalance.TaskIncreaseLimitImageExpiredNumber - taskBalance.TaskIncreaseLimitImageExpiredConsumptionNumber) if imageTotal < 0 { imageTotal = 0 } // 计算数据分析类待发数量:总余额 - 消耗数量 dataTotal = (taskBalance.TaskBundleDataAnalysisNumber - taskBalance.TaskBundleDataAnalysisConsumptionNumber) + (taskBalance.TaskIncreaseDataAnalysisNumber - taskBalance.TaskIncreaseDataAnalysisConsumptionNumber) + (taskBalance.TaskBundleLimitDataAnalysisNumber - taskBalance.TaskBundleLimitDataAnalysisConsumptionNumber) + (taskBalance.TaskIncreaseLimitDataAnalysisNumber - taskBalance.TaskIncreaseLimitDataAnalysisConsumptionNumber) + (taskBalance.TaskBundleLimitDataAnalysisExpiredNumber - taskBalance.TaskBundleLimitDataAnalysisExpiredConsumptionNumber) + (taskBalance.TaskIncreaseLimitDataAnalysisExpiredNumber - taskBalance.TaskIncreaseLimitDataAnalysisExpiredConsumptionNumber) if dataTotal < 0 { dataTotal = 0 } return videoTotal, imageTotal, dataTotal } func UpdateTaskBalanceEveryMonLogic() { dao.UpdateTaskBalanceEveryMon() }