package logic import ( "encoding/json" "micro-bundle/internal/dao" "micro-bundle/pb/bundle" commonErr "micro-bundle/pkg/err" "strings" ) // GetValidArtistList 查询套餐状态为有效中的艺人列表 func GetValidArtistList() ([]dao.ValidArtistInfo, error) { return dao.GetValidArtistList() } // GetValidArtistIDs 查询套餐没有过期的艺人ID列表(保持向后兼容) 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 } // GetArtistUploadStatsList 查询艺人上传与额度统计列表 func GetArtistUploadStatsList(req *dao.TaskQueryRequest) ([]*dao.ArtistUploadStatsItem, int64, error) { return dao.GetArtistUploadStatsList(req) } // GetPendingAssignBySubNums 查询指定艺人的可指派数量 func GetPendingAssignBySubNums(subNums []string, page int, pageSize int) ([]*dao.ArtistPendingAssignItem, int64, error) { return dao.GetPendingAssignBySubNums(subNums, page, pageSize) } // AssignTask 指派某位员工完成某个艺人的任务 func AssignTask(req *dao.TaskAssignRequest) error { // 1. 验证员工是否可以被指派任务 isValid, err := ValidateEmployee(req.TaskAssigneeNum) if err != nil { return err } if !isValid { return commonErr.ReturnError(nil, "员工不能被指派任务", "该员工不在可指派任务的员工列表中") } if req.AssignVideoCount < 0 || req.AssignPostCount < 0 || req.AssignDataCount < 0 || req.AssignVideoScriptCount < 0 { return commonErr.ReturnError(nil, "指派数量不能小于0", "任一指派数量不得小于0") } if req.AssignVideoCount == 0 && req.AssignPostCount == 0 && req.AssignDataCount == 0 && req.AssignVideoScriptCount == 0 { return commonErr.ReturnError(nil, "指派数量不能全部为0", "至少有一个指派数量需大于0") } progressTaskCount, completeTaskCount, err := dao.GetArtistTaskStatsBySubNum(req.SubNum) if err != nil { // 查询不到的话,给一个默认值 progressTaskCount, completeTaskCount = 0, 0 } // 2. 调用DAO层执行指派任务 // 待完成任务数量需要+1,因为这个任务暂时还没有指派,所以+1 return dao.AssignTask(req, progressTaskCount+1, completeTaskCount) } // BatchAssignTask 批量指派 func BatchAssignTask(items []*dao.BatchAssignItem) error { if len(items) == 0 { return commonErr.ReturnError(nil, "参数错误", "批量指派项不能为空") } // 逐项校验员工是否可被指派(当前实现默认全部有效) hasPositive := false for _, it := range items { if it == nil { return commonErr.ReturnError(nil, "参数错误", "存在空的指派项") } isValid, err := ValidateEmployee(it.TaskAssigneeNum) if err != nil { return err } if !isValid { return commonErr.ReturnError(nil, "员工不能被指派任务", "该员工不在可指派任务的员工列表中") } if it.AssignVideoCount < 0 || it.AssignPostCount < 0 || it.AssignDataCount < 0 || it.AssignVideoScriptCount < 0 { return commonErr.ReturnError(nil, "指派数量不能小于0", "任一指派数量不得小于0") } if it.AssignVideoCount == 0 && it.AssignPostCount == 0 && it.AssignDataCount == 0 && it.AssignVideoScriptCount == 0 { return commonErr.ReturnError(nil, "指派数量不能全部为0", "至少有一个指派数量需大于0") } if it.AssignVideoCount > 0 || it.AssignPostCount > 0 || it.AssignDataCount > 0 || it.AssignVideoScriptCount > 0 { hasPositive = true } } if !hasPositive { return commonErr.ReturnError(nil, "所有指派项数量都为0", "至少有一个指派项的数量需大于0") } // 调用DAO层批量写入指派记录 return dao.BatchAssignTasks(items) } // GetRecentAssignRecords 查询最近被指派记录 func GetRecentAssignRecords(limit int) ([]*bundle.RecentAssigneeItem, error) { records, err := dao.GetRecentAssignRecords(limit) if err != nil { return nil, err } var operatorList []*bundle.RecentAssigneeItem for _, record := range records { operatorList = append(operatorList, &bundle.RecentAssigneeItem{ TaskAssignee: record.TaskAssignee, TaskAssigneeNum: record.TaskAssigneeNum, }) } return operatorList, 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 } // 如果查询的 status = 2 的话,待发数量就为指派时,指派的数量 if req.Status == 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.AssignVideoCount, PendingPostCount: record.AssignPostCount, PendingDataCount: record.AssignDataCount, PendingVideoScriptCount: record.AssignVideoScriptCount, TaskBatch: record.TaskBatch, UpdatedAt: record.UpdatedAt, }) } return recordResponse, total, nil } // 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, PendingVideoScriptCount: record.PendingVideoScriptCount, TaskBatch: record.TaskBatch, UpdatedAt: record.UpdatedAt, }) } return recordResponse, total, nil } // TerminateTaskByUUID 根据指派记录UUID更新实际完成状态(1:未完成 2:完成 3:已中止) func TerminateTaskByUUID(assignRecordsUUID string) error { if assignRecordsUUID == "" { return commonErr.ReturnError(nil, "参数错误", "AssignRecordsUUID 不能为空") } return dao.UpdateTaskActualStatusByUUID(assignRecordsUUID, 3) } // BatchTerminateTaskByUUIDs 批量根据指派记录UUID终止任务(实际状态置为已中止) func BatchTerminateTaskByUUIDs(assignRecordsUUIDs []string) (int, int, []string, error) { if len(assignRecordsUUIDs) == 0 { return 0, 0, nil, commonErr.ReturnError(nil, "参数错误", "AssignRecordsUUIDs 不能为空") } success := 0 failed := 0 failedUUIDs := make([]string, 0) for _, uuid := range assignRecordsUUIDs { if strings.TrimSpace(uuid) == "" { failed++ failedUUIDs = append(failedUUIDs, uuid) continue } if err := dao.UpdateTaskActualStatusByUUID(uuid, 3); err != nil { failed++ failedUUIDs = append(failedUUIDs, uuid) continue } success++ } return success, failed, failedUUIDs, nil } func RevertTaskCompletionByUUIDItem(uuid string) error { if strings.TrimSpace(uuid) == "" { return commonErr.ReturnError(nil, "参数错误", "UUID不能为空") } return dao.RevertTaskCompletionByUUIDItem(uuid) } // CompleteTaskManually 员工手动点击完成任务 func CompleteTaskManually(assignRecordsUUID string, taskAssigneeNum string) error { // 第一步,查询指派记录,获取艺人编号 record, err := dao.GetAssignRecordByUUID(assignRecordsUUID) if err != nil { return err } if record == nil { return commonErr.ReturnError(nil, "未找到任务记录", "未找到指派记录: ") } // 第二步,校验该艺人是否为有效艺人(套餐未过期且已激活) validArtistList, err := GetValidArtistList() if err != nil { return err } isValid := false for _, a := range validArtistList { if a.CustomerNum == record.SubNum { isValid = true break } } if !isValid { return commonErr.ReturnError(nil, "该艺人套餐已过期,暂不能完成任务", "艺人套餐已过期,暂不能完成任务: ") } // 第三步,执行任务完成更新 return dao.CompleteTaskManually(assignRecordsUUID) } // UpdateTaskProgress 员工实际完成任务状态更新 func UpdateTaskProgress(req *dao.CompleteTaskRequest) error { if req.UUID == "" { return commonErr.ReturnError(nil, "作品UUID不能为空", "UUID不能为空") } return dao.UpdateTaskProgress(req) } // GetTaskAssignRecordsList 多条件查询操作记录表 func GetTaskAssignRecordsList(req *dao.TaskAssignRecordsQueryRequest) ([]*dao.TaskAssignRecordsResponse, int64, *dao.TaskAssignRecordsSummary, error) { record, total, summary, err := dao.GetTaskAssignRecordsList(req) if err != nil { return nil, 0, nil, 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, TaskBatch: record.TaskBatch, 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.AssignVideoCount, PendingPostCount: record.AssignPostCount, PendingDataCount: record.AssignDataCount, PendingVideoScriptCount: record.AssignVideoScriptCount, CompleteVideoScriptCount: record.CompleteVideoScriptCount, CompleteVideoCount: record.CompleteVideoCount, CompletePostCount: record.CompletePostCount, CompleteDataCount: record.CompleteDataCount, UpdatedAt: record.UpdatedAt, }) } return recordResponse, total, summary, nil } // GetTaskActualStatusByUUID 根据指派记录UUID查询实际完成状态 func GetTaskActualStatusByUUID(assignRecordsUUID string) (int, error) { if strings.TrimSpace(assignRecordsUUID) == "" { return 0, commonErr.ReturnError(nil, "查询参数错误", "AssignRecordsUUID 不能为空") } record, err := dao.GetAssignRecordByUUID(assignRecordsUUID) if err != nil { return 0, err } if record == nil { return 0, commonErr.ReturnError(nil, "未找到任务记录", "未找到指派记录: ") } return record.ActualStatus, nil } func GetPendingTaskLayout() (string, error) { data, err := dao.GetPendingTaskLayout() if err != nil { return buildDefaultPendingLayout(), nil } return data, nil } func SetPendingTaskLayout(data string) error { return dao.SetPendingTaskLayout(data) } func buildDefaultPendingLayout() string { var data = []struct { Title string Column string Status int }{ {"用户编号", "subNum", 1}, {"艺人", "artistName", 1}, {"手机号", "telNum", 1}, {"最近一次指派人", "lastTaskAssignee", 1}, {"可指派视频脚本数", "allowVideoScriptCount", 1}, {"可上传视频脚本数", "pendingVideoScriptCount", 1}, {"已上传视频脚本数", "uploadedVideoScriptCount", 1}, {"可指派视频数", "allowVideoCount", 1}, {"可上传视频数", "pendingVideoCount", 1}, {"已经上传视频数", "uploadedVideoCount", 1}, {"已释放视频额度", "releasedVideoTotal", 1}, {"套餐视频总数", "bundleVideoTotal", 1}, {"增值视频总数", "increaseVideoTotal", 1}, {"可指派图文数", "allowPostCount", 1}, {"可上传图文数", "pendingPostCount", 1}, {"已上传图文数", "uploadedPostCount", 1}, {"已释放图文额度", "releasedPostTotal", 1}, {"套餐图文总数", "bundlePostTotal", 1}, {"增值图文总数", "increasePostTotal", 1}, {"可指派数据数", "allowDataCount", 1}, {"可上传数据数", "pendingDataAnalysisCount", 1}, {"已上传数据数", "uploadedDataAnalysisCount", 1}, {"已释放数据额度", "releasedDataAnalysisTotal", 1}, {"套餐数据总数", "bundleDataAnalysisTotal", 1}, {"增值数据总数", "increaseDataAnalysisTotal", 1}, {"进行中任务数", "progressTaskCount", 1}, {"已完成任务数", "completeTaskCount", 1}, } jsonMap := []map[string]any{} for _, v := range data { jsonMap = append(jsonMap, map[string]any{ "sort": 1, "fieldKey": v.Column, "fieldValue": v.Title, "sortOrNot": true, "status": v.Status, "width": 160, }) } b, _ := json.Marshal(jsonMap) return string(b) } func AddHiddenTaskAssignee(taskAssignee string, taskAssigneeNum string) error { if strings.TrimSpace(taskAssignee) == "" || strings.TrimSpace(taskAssigneeNum) == "" { return commonErr.ReturnError(nil, "参数错误", "任务指派人或账号不能为空") } return dao.AddHiddenTaskAssignee(taskAssignee, taskAssigneeNum) } // CreateTaskWorkLog 创建任务日志记录 func CreateTaskWorkLog(req *dao.CreateTaskWorkLogRequest) error { if req.OperationType < 1 || req.OperationType > 4 { return commonErr.ReturnError(nil, "参数错误", "操作类型必须在1-4之间") } if req.TaskType < 1 || req.TaskType > 3 { return commonErr.ReturnError(nil, "参数错误", "任务类型必须在1-3之间") } if req.TaskCount < 0 { return commonErr.ReturnError(nil, "参数错误", "任务数量不能为负数") } // 调用 DAO 层创建日志 return dao.CreateTaskWorkLog(req) }