micro-bundle/internal/dao/taskDao.go

965 lines
38 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package dao
import (
"fmt"
"micro-bundle/internal/model"
"micro-bundle/pkg/app"
commonErr "micro-bundle/pkg/err"
"micro-bundle/pkg/msg"
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
// TaskQueryRequest 查询待指派任务记录请求参数
type TaskQueryRequest struct {
Keyword string `json:"keyword"` // 艺人姓名、编号、手机号搜索关键词
Page int `json:"page"` // 页码
PageSize int `json:"pageSize"` // 每页数量
SortBy string `json:"sortBy"` // 排序字段
SortType string `json:"sortType"` // 排序类型 asc/desc
}
// TaskAssignRequest 指派任务请求参数
type TaskAssignRequest struct {
SubNum string `json:"subNum"` // 艺人编号
TelNum string `json:"telNum"` // 艺人手机号
ArtistName string `json:"artistName"` // 艺人姓名
TaskAssignee string `json:"taskAssignee"` // 任务指派人
TaskAssigneeNum string `json:"taskAssigneeNum"` // 任务指派人账号
Operator string `json:"operator"` // 操作人
OperatorNum string `json:"operatorNum"` // 操作人账号
AssignVideoCount int `json:"assignVideoCount"` // 指派视频数
AssignPostCount int `json:"assignPostCount"` // 指派图文数
AssignDataCount int `json:"assignDataCount"` // 指派数据数
}
// UpdatePendingCountRequest 修改待发数量请求参数
type UpdatePendingCountRequest struct {
SubNum string `json:"subNum"` // 艺人编号
TelNum string `json:"telNum"` // 艺人手机号
ArtistName string `json:"artistName"` // 艺人姓名
PendingVideoCount int `json:"pendingVideoCount"` // 待发视频数量
PendingPostCount int `json:"pendingPostCount"` // 待发图文数量
PendingDataCount int `json:"pendingDataCount"` // 待发数据数量
Operator string `json:"operator"` // 操作人
OperatorNum string `json:"operatorNum"` // 操作人账号
}
// EmployeeTaskQueryRequest 员工任务查询请求参数
type EmployeeTaskQueryRequest struct {
TaskAssigneeNum string `json:"taskAssigneeNum"` // 被指派人账号
Keyword string `json:"keyword"` // 艺人姓名、编号、手机号搜索关键词
Operator string `json:"operator"` // 操作人
SortBy string `json:"sortBy"` // 排序字段
StartTime string `json:"startTime"` // 指派开始时间
EndTime string `json:"endTime"` // 指派结束时间
StartCompleteTime string `json:"startCompleteTime"` // 开始完成时间
EndCompleteTime string `json:"endCompleteTime"` // 结束完成时间
Status int `json:"status"` // 反馈完成状态
Page int `json:"page"` // 页码
PageSize int `json:"pageSize"` // 每页数量
}
// CompleteTaskRequest 完成任务请求参数
type CompleteTaskRequest struct {
AssignRecordsUUID string `json:"assignRecordsUUID,omitempty"` // 指派记录UUID可选
EmployeeName string `json:"employeeName"` // 员工姓名(必要)
EmployeeNum string `json:"employeeNum"` // 员工工号(必要)
TaskType string `json:"taskType"` // 任务类型: video/post/data
CompleteCount int `json:"completeCount"` // 完成数量
}
// TaskAssignRecordsQueryRequest 多条件查询操作记录表请求参数
type TaskAssignRecordsQueryRequest struct {
Keyword string `json:"keyword"` // 艺人姓名、编号、手机号搜索关键词
TaskAssignee string `json:"taskAssignee"` // 指派人姓名
Operator string `json:"operator"` // 操作人姓名
OperatorNum string `json:"operatorNum"` // 操作人手机号
StartTime string `json:"startTime"` // 操作开始时间
EndTime string `json:"endTime"` // 操作结束时间
Status int `json:"status"` // 反馈完成状态 0:全部 1:未完成 2:完成
ActualStatus int `json:"actualStatus"` // 实际完成状态 0:全部 1:未完成 2:完成
Page int `json:"page"` // 页码
PageSize int `json:"pageSize"` // 每页数量
}
// 待指派任务 response
type TaskQueryResponse struct {
SubNum string `json:"subNum"`
TelNum string `json:"telNum"`
ArtistName string `json:"artistName"`
PendingVideoCount int `gorm:"column:pending_video_count;comment:待发视频数量" json:"pendingVideoCount"`
PendingPostCount int `gorm:"column:pending_post_count;comment:待发图文数量" json:"pendingPostCount"`
PendingDataCount int `gorm:"column:pending_data_count;comment:待发数据数量" json:"pendingDataCount"`
ProgressTaskCount int `gorm:"column:progress_task_count;comment:进行中的任务数量" json:"progressTaskCount"`
CompleteTaskCount int `gorm:"column:complete_task_count;comment:已完成任务数量" json:"completeTaskCount"`
LastTaskAssignee string `gorm:"column:last_task_assignee;comment:最后一次的任务指派人" json:"lastTaskAssignee"`
TaskAssigneeNum string `gorm:"column:task_assignee_num;comment:最后一次指派人账号" json:"taskAssigneeNum"`
}
// 任务记录表返回结构体
type TaskAssignRecordsResponse struct {
AssignRecordsUUID string `gorm:"column:assign_records_uuid;comment:指派记录UUID" json:"assignRecordsUUID"`
SubNum string `gorm:"column:sub_num;comment:艺人编号" json:"subNum"`
TelNum string `gorm:"column:tel_num;comment:艺人手机号" json:"telNum"`
ArtistName string `gorm:"column:artist_name;comment:艺人名称" json:"artistName"`
Status int `gorm:"column:status;comment:反馈完成状态 1:未完成 2:完成" json:"status"`
ActualStatus int `gorm:"column:actual_status;comment:实际完成状态 1:未完成 2:完成" json:"actualStatus"`
CompleteTime *time.Time `gorm:"column:complete_time;comment:反馈完成时间" json:"completeTime"`
OperatorType int `gorm:"column:operator_type;comment:操作类型 1:修改待发数量 2:指派" json:"operatorType"`
Operator string `gorm:"column:operator;comment:操作人" json:"operator"`
OperatorNum string `gorm:"column:operator_num;comment:操作人账号" json:"operatorNum"`
OperatorTime time.Time `gorm:"column:operator_time;comment:操作时间" json:"operatorTime"`
TaskAssignee string `gorm:"column:task_assignee;comment:任务指派人" json:"taskAssignee"`
TaskAssigneeNum string `gorm:"column:task_assignee_num;comment:任务指派人账号" json:"taskAssigneeNum"`
PendingVideoCount int `gorm:"column:pending_video_count;comment:待发视频数量" json:"pendingVideoCount"`
PendingPostCount int `gorm:"column:pending_post_count;comment:待发图文数量" json:"pendingPostCount"`
PendingDataCount int `gorm:"column:pending_data_count;comment:待发数据数量" json:"pendingDataCount"`
UpdatedAt time.Time `gorm:"column:updated_at;comment:更新时间" json:"updatedAt"`
}
// 任务指派记录数量结构体
type TaskAssignRecords struct {
TaskAssigneeNum string `json:"taskAssigneeNum"` // 任务指派人工号
ProgressTaskCount int `json:"progressTaskCount"` // 进行中任务数量
CompleteTaskCount int `json:"completeTaskCount"` // 已完成任务数量
}
// ValidArtistInfo 有效艺人信息结构体
type ValidArtistInfo struct {
UserID int `json:"userId"` // 用户ID
CustomerNum string `json:"customerNum"` // 艺人编号
UserName string `json:"userName"` // 艺人姓名
UserPhoneNumber string `json:"userPhoneNumber"` // 艺人手机号
BundleName string `json:"bundleName"` // 套餐名称
ExpirationTime string `json:"expirationTime"` // 过期时间
Status int `json:"status"` // 套餐状态
OrderUUID string `json:"orderUUID"` // 订单UUID
AccountNumber int `json:"accountNumber"` // 账号数量
AccountConsumptionNumber int `json:"accountConsumptionNumber"` // 账号消耗数量
VideoNumber int `json:"videoNumber"` // 视频数量
VideoConsumptionNumber int `json:"videoConsumptionNumber"` // 视频消耗数量
ImageNumber int `json:"imageNumber"` // 图片数量
ImageConsumptionNumber int `json:"imageConsumptionNumber"` // 图片消耗数量
DataAnalysisNumber int `json:"dataAnalysisNumber"` // 数据分析数量
DataAnalysisConsumptionNumber int `json:"dataAnalysisConsumptionNumber"` // 数据分析消耗数量
ExpansionPacksNumber int `json:"expansionPacksNumber"` // 扩展套餐数量
}
// ArtistBundleBalanceRequest 查询艺人套餐剩余数量请求参数
type ArtistBundleBalanceRequest struct {
CustomerNum string `json:"customerNum"` // 艺人编号(推荐使用)
TelNum string `json:"telNum"` // 艺人手机号(备选)
}
// ArtistBundleBalanceResponse 艺人套餐剩余数量响应结构体
type ArtistBundleBalanceResponse struct {
RemainingVideoCount int `json:"remainingVideoCount"` // 剩余视频数量 (video_number - video_consumption_number)
RemainingImageCount int `json:"remainingImageCount"` // 剩余图片数量 (image_number - image_consumption_number)
RemainingDataAnalysisCount int `json:"remainingDataAnalysisCount"` // 剩余数据分析数量 (data_analysis_number - data_analysis_consumption_number)
}
// GetPendingTaskList 查询待指派任务记录
// 根据套餐没有过期的艺人查询TaskManagement表中的记录如果不存在则构建默认值
func GetPendingTaskList(req *TaskQueryRequest, validArtist []ValidArtistInfo) ([]*model.TaskManagement, int64, error) {
// 构建有效艺人ID列表
var validArtistIDs []string
for _, artist := range validArtist {
if artist.CustomerNum != "" {
validArtistIDs = append(validArtistIDs, artist.CustomerNum)
}
}
// 如果没有有效艺人,直接返回空结果
if len(validArtistIDs) == 0 {
return []*model.TaskManagement{}, 0, nil
}
// 第一步:查询所有有效艺人在数据库中的存在情况(不应用关键词过滤)
var existingTasks []*model.TaskManagement
existQuery := app.ModuleClients.TaskBenchDB.Model(&model.TaskManagement{}).Where("sub_num IN (?)", validArtistIDs)
err := existQuery.Find(&existingTasks).Error
if err != nil {
return nil, 0, commonErr.ReturnError(err, msg.ErrorGetBundleList, "查询现有任务记录失败: ")
}
// 创建已存在艺人编号的映射
existingSubNums := make(map[string]bool)
for _, task := range existingTasks {
existingSubNums[task.SubNum] = true
}
// 创建艺人编号到艺人信息的映射,便于快速查找
artistMap := make(map[string]ValidArtistInfo)
for _, artist := range validArtist {
artistMap[artist.CustomerNum] = artist
}
// 为不存在的艺人创建默认记录
var newTasksToCreate []*model.TaskManagement
for _, subNum := range validArtistIDs {
if !existingSubNums[subNum] {
artist := artistMap[subNum]
// 构建默认任务记录
defaultTask := &model.TaskManagement{
SubNum: subNum,
TelNum: artist.UserPhoneNumber,
ArtistName: artist.UserName,
PendingVideoCount: artist.VideoNumber - artist.VideoConsumptionNumber,
PendingPostCount: artist.ImageNumber - artist.ImageConsumptionNumber,
PendingDataCount: artist.DataAnalysisNumber - artist.DataAnalysisConsumptionNumber,
ProgressCount: 0,
CompleteCount: 0,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
newTasksToCreate = append(newTasksToCreate, defaultTask)
}
}
// 批量创建新的任务记录
if len(newTasksToCreate) > 0 {
if err := app.ModuleClients.TaskBenchDB.Create(&newTasksToCreate).Error; err != nil {
return nil, 0, commonErr.ReturnError(err, msg.ErrorGetBundleList, "创建默认任务记录失败: ")
}
}
// 第二步:应用完整的查询条件进行最终查询
var tasks []*model.TaskManagement
var total int64
// 构建最终查询条件
query := app.ModuleClients.TaskBenchDB.Model(&model.TaskManagement{})
// 限制在有效艺人范围内
query = query.Where("sub_num IN (?)", validArtistIDs)
// 关键词搜索(艺人姓名、编号、手机号)
if req.Keyword != "" {
query = query.Where("sub_num LIKE ? OR tel_num LIKE ? OR artist_name LIKE ?",
"%"+req.Keyword+"%", "%"+req.Keyword+"%", "%"+req.Keyword+"%")
}
// 计算总数
query.Count(&total)
// 排序
if req.SortBy != "" && req.SortType != "" {
orderClause := fmt.Sprintf("%s %s", req.SortBy, req.SortType)
query = query.Order(orderClause)
} else {
// 默认按待发视频降序
query = query.Order("pending_video_count DESC")
}
// 分页
if req.PageSize > 0 && req.Page > 0 {
offset := (req.Page - 1) * req.PageSize
query = query.Limit(req.PageSize).Offset(offset)
}
err = query.Find(&tasks).Error
if err != nil {
return nil, 0, commonErr.ReturnError(err, msg.ErrorGetBundleList, "查询待指派任务记录失败: ")
}
return tasks, total, nil
}
// AssignTask 指派某位员工完成某个艺人的任务
func AssignTask(req *TaskAssignRequest, progressTaskCount int, completeTaskCount int) error {
// 开启事务
tx := app.ModuleClients.TaskBenchDB.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
// 1. 查询当前艺人的任务记录
var taskManagement model.TaskManagement
err := tx.Where("sub_num = ? AND tel_num = ?", req.SubNum, req.TelNum).First(&taskManagement).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
// 如果不存在,创建新记录
taskManagement = model.TaskManagement{
SubNum: req.SubNum,
TelNum: req.TelNum,
ArtistName: req.ArtistName,
PendingVideoCount: 0,
PendingPostCount: 0,
PendingDataCount: 0,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
if err = tx.Create(&taskManagement).Error; err != nil {
tx.Rollback()
return commonErr.ReturnError(err, "创建任务记录失败", "创建任务记录失败: ")
}
} else {
tx.Rollback()
return commonErr.ReturnError(err, "查询任务记录失败", "查询任务记录失败: ")
}
}
// 2. 检查待发数量是否大于0
if taskManagement.PendingVideoCount <= 0 && taskManagement.PendingPostCount <= 0 && taskManagement.PendingDataCount <= 0 {
tx.Rollback()
return commonErr.ReturnError(nil, "无可指派任务", "当前艺人待发视频数、图文数、数据数均为0无法指派任务")
}
// 3. 检查指派数量是否合理(增强验证)
if req.AssignVideoCount < 0 || req.AssignPostCount < 0 || req.AssignDataCount < 0 {
tx.Rollback()
return commonErr.ReturnError(nil, "指派数量不能为负数", "指派数量必须大于等于0")
}
if req.AssignVideoCount > taskManagement.PendingVideoCount ||
req.AssignPostCount > taskManagement.PendingPostCount ||
req.AssignDataCount > taskManagement.PendingDataCount {
tx.Rollback()
return commonErr.ReturnError(nil, "指派数量超出限制",
fmt.Sprintf("指派数量不能超过待发数量。当前待发:视频%d图文%d数据%d",
taskManagement.PendingVideoCount, taskManagement.PendingPostCount, taskManagement.PendingDataCount))
}
if req.AssignVideoCount == 0 && req.AssignPostCount == 0 && req.AssignDataCount == 0 {
tx.Rollback()
return commonErr.ReturnError(nil, "指派数量不能全为0", "至少需要指派一种类型的任务")
}
// 4. 更新TaskManagement表
updateData := map[string]interface{}{
"pending_video_count": taskManagement.PendingVideoCount - req.AssignVideoCount,
"pending_post_count": taskManagement.PendingPostCount - req.AssignPostCount,
"pending_data_count": taskManagement.PendingDataCount - req.AssignDataCount,
"last_task_assignee": req.TaskAssignee,
"task_assignee_num": req.TaskAssigneeNum,
"progress_count": progressTaskCount,
"complete_count": completeTaskCount,
"updated_at": time.Now(),
}
if err = tx.Model(&taskManagement).Updates(updateData).Error; err != nil {
tx.Rollback()
return commonErr.ReturnError(err, "更新任务记录失败", "更新任务记录失败: ")
}
// 5. 创建指派记录
assignRecord := &model.TaskAssignRecords{
AssignRecordsUUID: uuid.New().String(), // 使用Google UUID
SubNum: req.SubNum,
TelNum: req.TelNum,
ArtistName: req.ArtistName,
Status: 1, // 1:未完成
ActualStatus: 1, // 1:未完成
OperatorType: 2, // 2:指派
Operator: req.Operator, // 当前操作人名字
OperatorNum: req.OperatorNum, // 当前操作人账号
OperatorTime: time.Now(),
TaskAssignee: req.TaskAssignee, // 指派员工姓名
TaskAssigneeNum: req.TaskAssigneeNum, // 指派员工账号
PendingVideoCount: taskManagement.PendingVideoCount,
PendingPostCount: taskManagement.PendingPostCount,
PendingDataCount: taskManagement.PendingDataCount,
AssignVideoCount: req.AssignVideoCount,
AssignPostCount: req.AssignPostCount,
AssignDataCount: req.AssignDataCount,
CompleteVideoCount: 0,
CompletePostCount: 0,
CompleteDataCount: 0,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
if err = tx.Create(assignRecord).Error; err != nil {
tx.Rollback()
return commonErr.ReturnError(err, "创建指派记录失败", "创建指派记录失败: ")
}
// 提交事务
if err = tx.Commit().Error; err != nil {
return commonErr.ReturnError(err, "提交事务失败", "提交事务失败: ")
}
return nil
}
// UpdatePendingCount 修改待发数量
func UpdatePendingCount(req *UpdatePendingCountRequest) error {
// 开启事务
tx := app.ModuleClients.TaskBenchDB.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
// 1. 查询或创建TaskManagement记录
var taskManagement model.TaskManagement
err := tx.Where("sub_num = ? AND tel_num = ?", req.SubNum, req.TelNum).First(&taskManagement).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return commonErr.ReturnError(err, "无该艺人任务记录", "无该艺人任务记录")
} else {
tx.Rollback()
return commonErr.ReturnError(err, "查询任务记录失败", "查询任务记录失败: ")
}
} else {
// 更新现有记录
updateData := map[string]interface{}{
"pending_video_count": req.PendingVideoCount,
"pending_post_count": req.PendingPostCount,
"pending_data_count": req.PendingDataCount,
"updated_at": time.Now(),
}
if err = tx.Model(&taskManagement).Updates(updateData).Error; err != nil {
tx.Rollback()
return commonErr.ReturnError(err, "更新任务记录失败", "更新任务记录失败: ")
}
}
// 提交事务
if err = tx.Commit().Error; err != nil {
return commonErr.ReturnError(err, "提交事务失败", "提交事务失败: ")
}
return nil
}
// GetRecentAssignRecords 查询最近被指派记录
// 查询操作类型为"指派"的最近n条不同员工的记录
func GetRecentAssignRecords(limit int) ([]*model.TaskAssignRecords, error) {
var records []*model.TaskAssignRecords
// 查询操作类型为指派(2)的记录,按操作时间倒序,去重员工
err := app.ModuleClients.TaskBenchDB.Model(&model.TaskAssignRecords{}).
Where("operator_type = ?", 2). // 2:指派
Group("task_assignee_num"). // 按指派人账号分组去重
Order("operator_time DESC"). // 按操作时间倒序
Limit(limit).
Find(&records).Error
if err != nil {
return nil, commonErr.ReturnError(err, "查询最近指派记录失败", "查询最近指派记录失败: ")
}
return records, nil
}
// GetEmployeeAssignedTasks 根据登录人信息查询被指派给该员工的艺人任务
func GetEmployeeAssignedTasks(req *EmployeeTaskQueryRequest) ([]*model.TaskAssignRecords, int64, error) {
var records []*model.TaskAssignRecords
var total int64
// 构建查询条件
query := app.ModuleClients.TaskBenchDB.Model(&model.TaskAssignRecords{}).
Where("task_assignee_num = ?", req.TaskAssigneeNum)
// 关键词搜索(艺人姓名、编号、手机号)
if req.Keyword != "" {
query = query.Where("sub_num LIKE ? OR tel_num LIKE ? OR artist_name LIKE ?",
"%"+req.Keyword+"%", "%"+req.Keyword+"%", "%"+req.Keyword+"%")
}
// 被指派人姓名
if req.Operator != "" {
query = query.Where("task_assignee LIKE ?", "%"+req.Operator+"%")
}
// 指派时间区间
if req.StartTime != "" {
query = query.Where("operator_time >= ?", req.StartTime)
}
if req.EndTime != "" {
query = query.Where("operator_time <= ?", req.EndTime)
}
// 完成时间区间
if req.StartCompleteTime != "" {
query = query.Where("complete_time >= ?", req.StartCompleteTime)
}
if req.EndCompleteTime != "" {
query = query.Where("complete_time <= ?", req.EndCompleteTime)
}
// 反馈完成状态
if req.Status != 0 {
query = query.Where("status = ?", req.Status)
}
// 根据排序字段倒序
if req.SortBy != "" {
query = query.Order(req.SortBy + " DESC")
}
// 计算总数
query.Count(&total)
// 分页
if req.PageSize > 0 && req.Page > 0 {
offset := (req.Page - 1) * req.PageSize
query = query.Limit(req.PageSize).Offset(offset)
}
// 按操作时间倒序
err := query.Order("operator_time DESC").Find(&records).Error
if err != nil {
return nil, 0, commonErr.ReturnError(err, "查询员工指派任务失败", "查询员工指派任务失败: ")
}
return records, total, nil
}
// CompleteTaskManually 员工手动点击完成任务
func CompleteTaskManually(assignRecordsUUID string) error {
now := time.Now()
updateData := map[string]interface{}{
"status": 2, // 2:完成
"complete_time": &now,
"updated_at": now,
}
err := app.ModuleClients.TaskBenchDB.Model(&model.TaskAssignRecords{}).
Where("assign_records_uuid = ?", assignRecordsUUID).
Updates(updateData).Error
if err != nil {
return commonErr.ReturnError(err, "更新任务完成状态失败", "更新任务完成状态失败: ")
}
return nil
}
// UpdateTaskProgress 员工实际完成任务状态更新
// 员工调用视频、图文、数据时,对应的待完成数据减一,已完成数据加一
func UpdateTaskProgress(req *CompleteTaskRequest) error {
// 开启事务
tx := app.ModuleClients.TaskBenchDB.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
// 1. 查询指派记录
var assignRecord model.TaskAssignRecords
var err error
if req.AssignRecordsUUID != "" {
// 如果提供了UUID直接根据UUID查询
err = tx.Where("assign_records_uuid = ?", req.AssignRecordsUUID).First(&assignRecord).Error
if err != nil {
tx.Rollback()
return commonErr.ReturnError(err, "查询指派记录失败", "查询指派记录失败: ")
}
} else {
// 如果没有提供UUID根据员工信息查询最早的未完成任务
if req.EmployeeName == "" || req.EmployeeNum == "" {
tx.Rollback()
return commonErr.ReturnError(nil, "参数错误", "员工姓名和手机号不能为空")
}
err = tx.Where("task_assignee = ? AND task_assignee_num = ? AND actual_status = 1",
req.EmployeeName, req.EmployeeNum).
Order("operator_time ASC").
First(&assignRecord).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
tx.Rollback()
return commonErr.ReturnError(nil, "未找到任务记录", "该员工没有未完成的任务记录")
}
tx.Rollback()
return commonErr.ReturnError(err, "查询指派记录失败", "查询指派记录失败: ")
}
}
// 2. 根据任务类型更新完成数量
updateData := map[string]interface{}{
"updated_at": time.Now(),
}
switch req.TaskType {
case "video":
newCompleteCount := assignRecord.CompleteVideoCount + req.CompleteCount
if newCompleteCount > assignRecord.AssignVideoCount {
tx.Rollback()
return commonErr.ReturnError(nil, "完成数量超出限制", "视频完成数量不能超过指派数量")
}
updateData["complete_video_count"] = newCompleteCount
case "post":
newCompleteCount := assignRecord.CompletePostCount + req.CompleteCount
if newCompleteCount > assignRecord.AssignPostCount {
tx.Rollback()
return commonErr.ReturnError(nil, "完成数量超出限制", "图文完成数量不能超过指派数量")
}
updateData["complete_post_count"] = newCompleteCount
case "data":
newCompleteCount := assignRecord.CompleteDataCount + req.CompleteCount
if newCompleteCount > assignRecord.AssignDataCount {
tx.Rollback()
return commonErr.ReturnError(nil, "完成数量超出限制", "数据完成数量不能超过指派数量")
}
updateData["complete_data_count"] = newCompleteCount
default:
tx.Rollback()
return commonErr.ReturnError(nil, "无效的任务类型", "任务类型必须是video、post或data")
}
// 3. 更新指派记录
if err = tx.Model(&assignRecord).Updates(updateData).Error; err != nil {
tx.Rollback()
return commonErr.ReturnError(err, "更新完成数量失败", "更新完成数量失败: ")
}
// 4. 重新查询更新后的记录,检查是否全部完成
if err = tx.Where("assign_records_uuid = ?", assignRecord.AssignRecordsUUID).First(&assignRecord).Error; err != nil {
tx.Rollback()
return commonErr.ReturnError(err, "查询更新后记录失败", "查询更新后记录失败: ")
}
// 5. 检查是否所有任务都已完成
if assignRecord.CompleteVideoCount == assignRecord.AssignVideoCount &&
assignRecord.CompletePostCount == assignRecord.AssignPostCount &&
assignRecord.CompleteDataCount == assignRecord.AssignDataCount {
// 更新实际完成状态
if err = tx.Model(&assignRecord).Update("actual_status", 2).Error; err != nil {
tx.Rollback()
return commonErr.ReturnError(err, "更新实际完成状态失败", "更新实际完成状态失败: ")
}
}
// 提交事务
if err = tx.Commit().Error; err != nil {
return commonErr.ReturnError(err, "提交事务失败", "提交事务失败: ")
}
return nil
}
// GetTaskManagementBySubNum 根据艺人编号查询任务管理记录
func GetTaskManagementBySubNum(subNum string) (*model.TaskManagement, error) {
var task model.TaskManagement
err := app.ModuleClients.TaskBenchDB.Where("sub_num = ?", subNum).First(&task).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil // 记录不存在
}
return nil, commonErr.ReturnError(err, "查询任务管理记录失败", "查询任务管理记录失败: ")
}
return &task, nil
}
// GetAssignRecordByUUID 根据UUID查询指派记录
func GetAssignRecordByUUID(uuid string) (*model.TaskAssignRecords, error) {
var record model.TaskAssignRecords
err := app.ModuleClients.TaskBenchDB.Where("assign_records_uuid = ?", uuid).First(&record).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil // 记录不存在
}
return nil, commonErr.ReturnError(err, "查询指派记录失败", "查询指派记录失败: ")
}
return &record, nil
}
// GetTaskAssignRecordsList 多条件查询操作记录表
// 支持通过艺人信息、指派人、操作人、操作时间、完成状态等多条件查询TaskAssignRecords表
func GetTaskAssignRecordsList(req *TaskAssignRecordsQueryRequest) ([]*model.TaskAssignRecords, int64, error) {
var records []*model.TaskAssignRecords
var total int64
// 构建查询条件
query := app.ModuleClients.TaskBenchDB.Model(&model.TaskAssignRecords{})
// 关键词搜索(艺人姓名、编号、手机号)
if req.Keyword != "" {
query = query.Where("sub_num LIKE ? OR tel_num LIKE ? OR artist_name LIKE ?",
"%"+req.Keyword+"%", "%"+req.Keyword+"%", "%"+req.Keyword+"%")
}
// 指派人姓名
if req.TaskAssignee != "" {
query = query.Where("task_assignee LIKE ?", "%"+req.TaskAssignee+"%")
}
// 操作人姓名
if req.Operator != "" {
query = query.Where("operator LIKE ?", "%"+req.Operator+"%")
}
// 操作人手机号
if req.OperatorNum != "" {
query = query.Where("operator_num LIKE ?", "%"+req.OperatorNum+"%")
}
// 操作时间区间
if req.StartTime != "" {
query = query.Where("operator_time >= ?", req.StartTime)
}
if req.EndTime != "" {
query = query.Where("operator_time <= ?", req.EndTime)
}
// 反馈完成状态
if req.Status != 0 {
query = query.Where("status = ?", req.Status)
}
// 实际完成状态
if req.ActualStatus != 0 {
query = query.Where("actual_status = ?", req.ActualStatus)
}
// 计算总数
query.Count(&total)
// 分页
if req.PageSize > 0 && req.Page > 0 {
offset := (req.Page - 1) * req.PageSize
query = query.Limit(req.PageSize).Offset(offset)
}
// 按更新时间倒序排序
err := query.Order("updated_at DESC").Find(&records).Error
if err != nil {
return nil, 0, commonErr.ReturnError(err, "查询操作记录失败", "查询操作记录失败: ")
}
return records, total, nil
}
// GetValidArtistList 查询套餐状态为有效中的艺人数据列表
// 根据BundleOrderRecords表查询过期时间大于当前时间且状态为已支付的艺人详细信息
func GetValidArtistList() ([]ValidArtistInfo, error) {
// 构建子查询,获取每个用户的最新订单记录
subQuery := app.ModuleClients.BundleDB.Table("bundle_order_records as bor1").
Select("bor1.*").
Joins(`INNER JOIN (
SELECT customer_id, MAX(created_at) AS max_created_time
FROM bundle_order_records
GROUP BY customer_id
) bor2 ON bor1.customer_id = bor2.customer_id AND bor1.created_at = bor2.max_created_time`)
// 主查询,关联用户表和实名信息表
session := app.ModuleClients.BundleDB.Table("`micro-account`.`user` AS u").
Select(`u.id as user_id, bor.customer_num, rn.name as user_name,
u.tel_num as user_phone_number, bor.bundle_name, bor.expiration_time,
bor.status, bor.uuid as order_uuid, bb.account_number, bb.account_consumption_number,
bb.video_number, bb.video_consumption_number, bb.image_number, bb.image_consumption_number,
bb.data_analysis_number, bb.data_analysis_consumption_number, bb.expansion_packs_number`).
Joins("LEFT JOIN `micro-account`.real_name rn ON u.real_name_id = rn.id").
Joins("LEFT JOIN (?) as bor ON bor.customer_id = u.id", subQuery).
Joins("LEFT JOIN bundle_balance bb ON u.id = bb.user_id AND bb.order_uuid = bor.uuid").
Where("rn.name IS NOT NULL").
Where("u.deleted_at = 0").
Where("bor.expiration_time > ?", time.Now().Format("2006-01-02 15:04:05")).
Where("bor.status = ?", 2). // 2:已签已支付
Order("bor.expiration_time desc")
var data []ValidArtistInfo
err := session.Find(&data).Error
if err != nil {
return nil, commonErr.ReturnError(err, "查询有效艺人失败", "查询有效艺人失败: ")
}
return data, nil
}
// 根据员工的工号从指派任务记录表中查询这名员工,进行中任务数量和已经完成的任务数量
func GetTaskAssigneeInfo(taskAssigneeNum string) (int, int, error) {
// 如果taskAssigneeNum为空直接返回默认值
if taskAssigneeNum == "" {
return 0, 0, nil
}
var taskAssignRecords TaskAssignRecords
err := app.ModuleClients.TaskBenchDB.Table("task_assign_records").
Select("task_assignee_num, count(*) as progress_task_count, sum(status = 2) as complete_task_count").
Where("task_assignee_num = ?", taskAssigneeNum).
Group("task_assignee_num").
First(&taskAssignRecords).Error
// 如果查询不到记录,返回默认值而不是错误
if err != nil {
if err == gorm.ErrRecordNotFound {
return 0, 0, nil
}
return 0, 0, commonErr.ReturnError(err, "查询任务指派记录失败", "查询任务指派记录失败: ")
}
return taskAssignRecords.ProgressTaskCount, taskAssignRecords.CompleteTaskCount, nil
}
// 更新被指派员工为 taskAssigneeNum 的记录中的ProgressCount + 1 和CompleteCount - 1
func UpdateTaskRecordsByAssigneeNum(taskAssigneeNum string) error {
err := app.ModuleClients.TaskBenchDB.Table("task_management").
Where("task_assignee_num = ?", taskAssigneeNum).
Update("progress_count", gorm.Expr("progress_count + ?", 1)).
Update("complete_count", gorm.Expr("complete_count - ?", 1)).Error
if err != nil {
return commonErr.ReturnError(err, "更新员工任务进度失败", "更新员工任务进度失败: ")
}
return nil
}
// GetArtistBundleBalance 根据艺人编号或手机号查询套餐剩余数量
// 优先使用艺人编号查询,如果为空则使用手机号查询
func GetArtistBundleBalance(req *ArtistBundleBalanceRequest) (*ArtistBundleBalanceResponse, error) {
// 构建子查询,获取用户的最新订单记录
subQuery := app.ModuleClients.BundleDB.Table("bundle_order_records as bor1").
Select("bor1.*").
Joins(`INNER JOIN (
SELECT customer_id, MAX(created_at) AS max_created_time
FROM bundle_order_records
GROUP BY customer_id
) bor2 ON bor1.customer_id = bor2.customer_id AND bor1.created_at = bor2.max_created_time`)
// 主查询,关联用户表和实名信息表
session := app.ModuleClients.BundleDB.Table("`micro-account`.`user` AS u").
Select(`u.id, bor.customer_num, rn.name as user_name,
u.tel_num as user_phone_number, bor.bundle_name, bor.expiration_time,
bor.status, bor.uuid as order_uuid, bb.account_number, bb.account_consumption_number,
bb.video_number, bb.video_consumption_number, bb.image_number, bb.image_consumption_number,
bb.data_analysis_number, bb.data_analysis_consumption_number, bb.expansion_packs_number`).
Joins("LEFT JOIN `micro-account`.real_name rn ON u.real_name_id = rn.id").
Joins("LEFT JOIN (?) as bor ON bor.customer_id = u.id", subQuery).
Joins("LEFT JOIN bundle_balance bb ON u.id = bb.user_id AND bb.order_uuid = bor.uuid").
Where("rn.name IS NOT NULL").
Where("u.deleted_at = 0").
Where("bor.expiration_time > ?", time.Now().Format("2006-01-02 15:04:05")).
Where("bor.status = ?", 2) // 2:已签已支付
// 根据查询条件添加WHERE子句
if req.CustomerNum != "" {
session = session.Where("bor.customer_num = ?", req.CustomerNum)
} else if req.TelNum != "" {
session = session.Where("u.tel_num = ?", req.TelNum)
} else {
return nil, commonErr.ReturnError(nil, "查询参数错误", "艺人编号和手机号不能同时为空")
}
var data ValidArtistInfo
err := session.Take(&data).Error // 使用Take()替代First(),避免自动排序
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, commonErr.ReturnError(err, "艺人不存在或套餐已过期", "未找到有效的艺人套餐信息")
}
return nil, commonErr.ReturnError(err, "查询艺人套餐信息失败", "查询艺人套餐信息失败: ")
}
// 计算剩余数量
response := &ArtistBundleBalanceResponse{
RemainingVideoCount: data.VideoNumber - data.VideoConsumptionNumber,
RemainingImageCount: data.ImageNumber - data.ImageConsumptionNumber,
RemainingDataAnalysisCount: data.DataAnalysisNumber - data.DataAnalysisConsumptionNumber,
}
return response, nil
}
// AdjustPendingCountRequest 调整待发数量请求参数
type AdjustPendingCountRequest struct {
SubNum string `json:"subNum"` // 艺人编号
TelNum string `json:"telNum"` // 艺人手机号
ArtistName string `json:"artistName"` // 艺人姓名
AdjustVideoCount int `json:"adjustVideoCount"` // 调整视频数量(正数为增加,负数为减少)
AdjustPostCount int `json:"adjustPostCount"` // 调整图文数量(正数为增加,负数为减少)
AdjustDataCount int `json:"adjustDataCount"` // 调整数据数量(正数为增加,负数为减少)
CreateIfNotExists bool `json:"createIfNotExists"` // 如果记录不存在是否创建
}
// AdjustPendingCount 调整待发数量(增加或减少)
// 支持正数增加和负数减少,可用于套餐扩展时同步增加待发任务数量
func AdjustPendingCount(req *AdjustPendingCountRequest) error {
// 开启事务
tx := app.ModuleClients.TaskBenchDB.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
// 1. 查询现有任务记录
var taskManagement model.TaskManagement
err := tx.Where("sub_num = ? AND tel_num = ?", req.SubNum, req.TelNum).First(&taskManagement).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
if req.CreateIfNotExists {
// 创建新记录
taskManagement = model.TaskManagement{
SubNum: req.SubNum,
TelNum: req.TelNum,
ArtistName: req.ArtistName,
PendingVideoCount: req.AdjustVideoCount,
PendingPostCount: req.AdjustPostCount,
PendingDataCount: req.AdjustDataCount,
ProgressCount: 0,
CompleteCount: 0,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
// 确保数量不为负数
if taskManagement.PendingVideoCount < 0 {
taskManagement.PendingVideoCount = 0
}
if taskManagement.PendingPostCount < 0 {
taskManagement.PendingPostCount = 0
}
if taskManagement.PendingDataCount < 0 {
taskManagement.PendingDataCount = 0
}
if err = tx.Create(&taskManagement).Error; err != nil {
tx.Rollback()
return commonErr.ReturnError(err, "创建任务记录失败", "创建任务记录失败: ")
}
} else {
tx.Rollback()
return commonErr.ReturnError(err, "任务记录不存在", "找不到对应的任务记录")
}
} else {
tx.Rollback()
return commonErr.ReturnError(err, "查询任务记录失败", "查询任务记录失败: ")
}
} else {
// 2. 计算调整后的数量
newVideoCount := taskManagement.PendingVideoCount + req.AdjustVideoCount
newPostCount := taskManagement.PendingPostCount + req.AdjustPostCount
newDataCount := taskManagement.PendingDataCount + req.AdjustDataCount
// 3. 确保调整后的数量不为负数
if newVideoCount < 0 {
newVideoCount = 0
}
if newPostCount < 0 {
newPostCount = 0
}
if newDataCount < 0 {
newDataCount = 0
}
// 4. 更新TaskManagement表
updateData := map[string]interface{}{
"pending_video_count": newVideoCount,
"pending_post_count": newPostCount,
"pending_data_count": newDataCount,
"updated_at": time.Now(),
}
if err = tx.Model(&taskManagement).Updates(updateData).Error; err != nil {
tx.Rollback()
return commonErr.ReturnError(err, "更新任务记录失败", "更新任务记录失败: ")
}
}
// 提交事务
if err = tx.Commit().Error; err != nil {
return commonErr.ReturnError(err, "提交事务失败", "提交事务失败: ")
}
return nil
}