micro-bundle/internal/dao/taskDao.go

965 lines
38 KiB
Go
Raw Normal View History

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 ?",
"%"+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
}