# Conflicts: # pb/bundle.proto # pb/bundle/bundle.pb.go # pb/bundle/bundle_triple.pb.go
1708 lines
76 KiB
Go
1708 lines
76 KiB
Go
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"
|
||
)
|
||
|
||
// ===== 聚合和扣减的辅助函数 =====
|
||
|
||
// aggregatePendingVideo 汇总所有视频分类的待发数量
|
||
func aggregatePendingVideo(t *model.TaskManagement) int {
|
||
return t.PendingBundleLimitVideoExpiredCount + t.PendingBundleLimitVideoCount +
|
||
t.PendingIncreaseLimitVideoExpiredCount + t.PendingIncreaseLimitVideoCount +
|
||
t.PendingBundleVideoCount + t.PendingIncreaseVideoCount
|
||
}
|
||
|
||
// aggregatePendingImage 汇总所有图文分类的待发数量
|
||
func aggregatePendingImage(t *model.TaskManagement) int {
|
||
return t.PendingBundleLimitImageExpiredCount + t.PendingBundleLimitImageCount +
|
||
t.PendingIncreaseLimitImageExpiredCount + t.PendingIncreaseLimitImageCount +
|
||
t.PendingBundleImageCount + t.PendingIncreaseImageCount
|
||
}
|
||
|
||
// aggregatePendingData 汇总所有数据分析分类的待发数量
|
||
func aggregatePendingData(t *model.TaskManagement) int {
|
||
return t.PendingBundleLimitDataAnalysisExpiredCount + t.PendingBundleLimitDataAnalysisCount +
|
||
t.PendingIncreaseLimitDataAnalysisExpiredCount + t.PendingIncreaseLimitDataAnalysisCount +
|
||
t.PendingBundleDataAnalysisCount + t.PendingIncreaseDataAnalysisCount
|
||
}
|
||
|
||
// deductCount 按顺序从各个桶中扣减数量,剩余未扣减数量应为0(正常情况)
|
||
func deductCount(count *int, buckets ...*int) {
|
||
if count == nil {
|
||
return
|
||
}
|
||
for _, b := range buckets {
|
||
if *count <= 0 {
|
||
break
|
||
}
|
||
if b == nil || *b <= 0 {
|
||
continue
|
||
}
|
||
if *b >= *count {
|
||
*b = *b - *count
|
||
*count = 0
|
||
} else {
|
||
*count = *count - *b
|
||
*b = 0
|
||
}
|
||
}
|
||
}
|
||
|
||
// deductVideo 视频扣减优先级:受限 > 非受限;同类型中:打包 > 增量;受限类型中:过期优先
|
||
func deductVideo(t *model.TaskManagement, n int) {
|
||
c := n
|
||
deductCount(&c,
|
||
&t.PendingBundleLimitVideoExpiredCount,
|
||
&t.PendingBundleLimitVideoCount,
|
||
&t.PendingIncreaseLimitVideoExpiredCount,
|
||
&t.PendingIncreaseLimitVideoCount,
|
||
&t.PendingBundleVideoCount,
|
||
&t.PendingIncreaseVideoCount,
|
||
)
|
||
}
|
||
|
||
// deductImage 图文扣减优先级:受限 > 非受限;同类型中:打包 > 增量;受限类型中:过期优先
|
||
func deductImage(t *model.TaskManagement, n int) {
|
||
c := n
|
||
deductCount(&c,
|
||
&t.PendingBundleLimitImageExpiredCount,
|
||
&t.PendingBundleLimitImageCount,
|
||
&t.PendingIncreaseLimitImageExpiredCount,
|
||
&t.PendingIncreaseLimitImageCount,
|
||
&t.PendingBundleImageCount,
|
||
&t.PendingIncreaseImageCount,
|
||
)
|
||
}
|
||
|
||
// deductData 数据分析扣减优先级:受限 > 非受限;同类型中:打包 > 增量;受限类型中:过期优先
|
||
func deductData(t *model.TaskManagement, n int) {
|
||
c := n
|
||
deductCount(&c,
|
||
&t.PendingBundleLimitDataAnalysisExpiredCount,
|
||
&t.PendingBundleLimitDataAnalysisCount,
|
||
&t.PendingIncreaseLimitDataAnalysisExpiredCount,
|
||
&t.PendingIncreaseLimitDataAnalysisCount,
|
||
&t.PendingBundleDataAnalysisCount,
|
||
&t.PendingIncreaseDataAnalysisCount,
|
||
)
|
||
}
|
||
|
||
// 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)
|
||
}
|
||
|
||
// PendingAndBalanceRequest 查询待发与任务余额请求参数
|
||
// 优先使用艺人编号查询,如果为空则使用手机号查询
|
||
type PendingAndBalanceRequest struct {
|
||
SubNum string `json:"subNum"` // 艺人编号(推荐使用)
|
||
TelNum string `json:"telNum"` // 艺人手机号(备选)
|
||
}
|
||
|
||
// PendingAndBalanceResponse 查询待发与任务余额响应结构
|
||
// 待发数量为细分待发字段求和;余额为对应总数减已使用数后再按类别(套餐/增值)聚合
|
||
type PendingAndBalanceResponse struct {
|
||
// 待发(按类别聚合)
|
||
PendingBundleVideoCount int `json:"pendingBundleVideoCount"` // 待发套餐视频数量(非限制+限制非过期+限制会过期)
|
||
PendingBundleImageCount int `json:"pendingBundleImageCount"` // 待发套餐图文数量(非限制+限制非过期+限制会过期)
|
||
PendingBundleDataAnalysisCount int `json:"pendingBundleDataAnalysisCount"` // 待发套餐数据分析数量(非限制+限制非过期+限制会过期)
|
||
|
||
PendingIncreaseVideoCount int `json:"pendingIncreaseVideoCount"` // 待发增值视频数量(非限制+限制非过期+限制会过期)
|
||
PendingIncreaseImageCount int `json:"pendingIncreaseImageCount"` // 待发增值图文数量(非限制+限制非过期+限制会过期)
|
||
PendingIncreaseDataAnalysisCount int `json:"pendingIncreaseDataAnalysisCount"` // 待发增值数据分析数量(非限制+限制非过期+限制会过期)
|
||
|
||
// 任务余额(套餐/增值按类别聚合)
|
||
BundleVideoBalance int `json:"bundleVideoBalance"` // 套餐视频余额
|
||
BundleImageBalance int `json:"bundleImageBalance"` // 套餐图文余额
|
||
BundleDataAnalysisBalance int `json:"bundleDataAnalysisBalance"` // 套餐数据分析余额
|
||
|
||
IncreaseVideoBalance int `json:"increaseVideoBalance"` // 增值视频余额
|
||
IncreaseImageBalance int `json:"increaseImageBalance"` // 增值图文余额
|
||
IncreaseDataAnalysisBalance int `json:"increaseDataAnalysisBalance"` // 增值数据分析余额
|
||
}
|
||
|
||
// calculateBundleBalances 计算套餐类别下的三类余额(视频/图文/数据分析)
|
||
// 余额=对应类别总数-对应类别已使用数;再将非限制、限制非过期、限制会过期三类相加
|
||
func calculateBundleBalances(tb *model.TaskBalance) (video int, image int, data int) {
|
||
// 视频套餐余额
|
||
video = (tb.TaskBundleVideoNumber - tb.TaskBundleVideoConsumptionNumber) +
|
||
(tb.TaskBundleLimitVideoNumber - tb.TaskBundleLimitVideoConsumptionNumber) +
|
||
(tb.TaskBundleLimitVideoExpiredNumber - tb.TaskBundleLimitVideoExpiredConsumptionNumber)
|
||
|
||
// 图文套餐余额
|
||
image = (tb.TaskBundleImageNumber - tb.TaskBundleImageConsumptionNumber) +
|
||
(tb.TaskBundleLimitImageNumber - tb.TaskBundleLimitImageConsumptionNumber) +
|
||
(tb.TaskBundleLimitImageExpiredNumber - tb.TaskBundleLimitImageExpiredConsumptionNumber)
|
||
|
||
// 数据分析套餐余额
|
||
data = (tb.TaskBundleDataAnalysisNumber - tb.TaskBundleDataAnalysisConsumptionNumber) +
|
||
(tb.TaskBundleLimitDataAnalysisNumber - tb.TaskBundleLimitDataAnalysisConsumptionNumber) +
|
||
(tb.TaskBundleLimitDataAnalysisExpiredNumber - tb.TaskBundleLimitDataAnalysisExpiredConsumptionNumber)
|
||
|
||
return
|
||
}
|
||
|
||
// calculateIncreaseBalances 计算增值类别下的三类余额(视频/图文/数据分析)
|
||
// 余额=对应类别总数-对应类别已使用数;再将非限制、限制非过期、限制会过期三类相加
|
||
func calculateIncreaseBalances(tb *model.TaskBalance) (video int, image int, data int) {
|
||
// 视频增值余额
|
||
video = (tb.TaskIncreaseVideoNumber - tb.TaskIncreaseVideoConsumptionNumber) +
|
||
(tb.TaskIncreaseLimitVideoNumber - tb.TaskIncreaseLimitVideoConsumptionNumber) +
|
||
(tb.TaskIncreaseLimitVideoExpiredNumber - tb.TaskIncreaseLimitVideoExpiredConsumptionNumber)
|
||
|
||
// 图文增值余额
|
||
image = (tb.TaskIncreaseImageNumber - tb.TaskIncreaseImageConsumptionNumber) +
|
||
(tb.TaskIncreaseLimitImageNumber - tb.TaskIncreaseLimitImageConsumptionNumber) +
|
||
(tb.TaskIncreaseLimitImageExpiredNumber - tb.TaskIncreaseLimitImageExpiredConsumptionNumber)
|
||
|
||
// 数据分析增值余额
|
||
data = (tb.TaskIncreaseDataAnalysisNumber - tb.TaskIncreaseDataAnalysisConsumptionNumber) +
|
||
(tb.TaskIncreaseLimitDataAnalysisNumber - tb.TaskIncreaseLimitDataAnalysisConsumptionNumber) +
|
||
(tb.TaskIncreaseLimitDataAnalysisExpiredNumber - tb.TaskIncreaseLimitDataAnalysisExpiredConsumptionNumber)
|
||
|
||
return
|
||
}
|
||
|
||
// GetUserPendingAndTaskBalances 查询用户待发套餐/增值数量与任务余额(套餐/增值)
|
||
// 待发数量来自 task_management,余额来自 task_balance;均按视频/图文/数据分析三类返回
|
||
// 待发聚合口径:将该类别下(套餐或增值)的非限制、限制非过期、限制会过期三类相加
|
||
// 余额聚合口径:对应类别总数减已使用数后,再将三类相加
|
||
func GetUserPendingAndTaskBalances(req *PendingAndBalanceRequest) (*PendingAndBalanceResponse, error) {
|
||
// 校验查询条件
|
||
if req.SubNum == "" && req.TelNum == "" {
|
||
return nil, commonErr.ReturnError(nil, "查询参数错误", "艺人编号和手机号不能同时为空")
|
||
}
|
||
|
||
// 查询任务管理表(待发)
|
||
var tm model.TaskManagement
|
||
tmQuery := app.ModuleClients.TaskBenchDB.Model(&model.TaskManagement{})
|
||
if req.SubNum != "" {
|
||
tmQuery = tmQuery.Where("sub_num = ?", req.SubNum)
|
||
} else {
|
||
tmQuery = tmQuery.Where("tel_num = ?", req.TelNum)
|
||
}
|
||
// 若不存在,待发视为 0
|
||
_ = tmQuery.Take(&tm).Error
|
||
|
||
// 聚合待发(套餐与增值分开统计)
|
||
pendingBundleVideo := tm.PendingBundleVideoCount + tm.PendingBundleLimitVideoCount + tm.PendingBundleLimitVideoExpiredCount
|
||
pendingBundleImage := tm.PendingBundleImageCount + tm.PendingBundleLimitImageCount + tm.PendingBundleLimitImageExpiredCount
|
||
pendingBundleData := tm.PendingBundleDataAnalysisCount + tm.PendingBundleLimitDataAnalysisCount + tm.PendingBundleLimitDataAnalysisExpiredCount
|
||
|
||
pendingIncreaseVideo := tm.PendingIncreaseVideoCount + tm.PendingIncreaseLimitVideoCount + tm.PendingIncreaseLimitVideoExpiredCount
|
||
pendingIncreaseImage := tm.PendingIncreaseImageCount + tm.PendingIncreaseLimitImageCount + tm.PendingIncreaseLimitImageExpiredCount
|
||
pendingIncreaseData := tm.PendingIncreaseDataAnalysisCount + tm.PendingIncreaseLimitDataAnalysisCount + tm.PendingIncreaseLimitDataAnalysisExpiredCount
|
||
|
||
// 查询任务余额表(当前有效月份优先)
|
||
var tb model.TaskBalance
|
||
now := time.Now()
|
||
tbQuery := app.ModuleClients.TaskBenchDB.Model(&model.TaskBalance{})
|
||
if req.SubNum != "" {
|
||
tbQuery = tbQuery.Where("sub_num = ?", req.SubNum)
|
||
} else {
|
||
tbQuery = tbQuery.Where("tel_num = ?", req.TelNum)
|
||
}
|
||
// 选择当前有效区间的记录,若无则回退到最近一条
|
||
err := tbQuery.Where("start_at <= ? AND expired_at >= ?", now, now).Order("start_at DESC").Take(&tb).Error
|
||
if err != nil {
|
||
// 回退:取最近一条记录(可能没有有效期覆盖 now)
|
||
_ = tbQuery.Order("start_at DESC").Take(&tb).Error
|
||
}
|
||
|
||
// 计算套餐与增值余额
|
||
bundleVideo, bundleImage, bundleData := calculateBundleBalances(&tb)
|
||
increaseVideo, increaseImage, increaseData := calculateIncreaseBalances(&tb)
|
||
|
||
resp := &PendingAndBalanceResponse{
|
||
PendingBundleVideoCount: pendingBundleVideo,
|
||
PendingBundleImageCount: pendingBundleImage,
|
||
PendingBundleDataAnalysisCount: pendingBundleData,
|
||
|
||
PendingIncreaseVideoCount: pendingIncreaseVideo,
|
||
PendingIncreaseImageCount: pendingIncreaseImage,
|
||
PendingIncreaseDataAnalysisCount: pendingIncreaseData,
|
||
|
||
BundleVideoBalance: bundleVideo,
|
||
BundleImageBalance: bundleImage,
|
||
BundleDataAnalysisBalance: bundleData,
|
||
IncreaseVideoBalance: increaseVideo,
|
||
IncreaseImageBalance: increaseImage,
|
||
IncreaseDataAnalysisBalance: increaseData,
|
||
}
|
||
|
||
return resp, nil
|
||
}
|
||
|
||
// 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]
|
||
// 构建默认任务记录
|
||
// 默认将剩余数量分配到“非限制-套餐权益”类别,其它类别置零
|
||
remainingVideo := artist.VideoNumber - artist.VideoConsumptionNumber
|
||
remainingImage := artist.ImageNumber - artist.ImageConsumptionNumber
|
||
remainingData := artist.DataAnalysisNumber - artist.DataAnalysisConsumptionNumber
|
||
if remainingVideo < 0 {
|
||
remainingVideo = 0
|
||
}
|
||
if remainingImage < 0 {
|
||
remainingImage = 0
|
||
}
|
||
if remainingData < 0 {
|
||
remainingData = 0
|
||
}
|
||
|
||
defaultTask := &model.TaskManagement{
|
||
SubNum: subNum,
|
||
TelNum: artist.UserPhoneNumber,
|
||
ArtistName: artist.UserName,
|
||
|
||
// 视频
|
||
PendingBundleVideoCount: remainingVideo,
|
||
PendingIncreaseVideoCount: 0,
|
||
PendingBundleLimitVideoCount: 0,
|
||
PendingIncreaseLimitVideoCount: 0,
|
||
PendingBundleLimitVideoExpiredCount: 0,
|
||
PendingIncreaseLimitVideoExpiredCount: 0,
|
||
|
||
// 图片
|
||
PendingBundleImageCount: remainingImage,
|
||
PendingIncreaseImageCount: 0,
|
||
PendingBundleLimitImageCount: 0,
|
||
PendingIncreaseLimitImageCount: 0,
|
||
PendingBundleLimitImageExpiredCount: 0,
|
||
PendingIncreaseLimitImageExpiredCount: 0,
|
||
|
||
// 数据分析
|
||
PendingBundleDataAnalysisCount: remainingData,
|
||
PendingIncreaseDataAnalysisCount: 0,
|
||
PendingBundleLimitDataAnalysisCount: 0,
|
||
PendingIncreaseLimitDataAnalysisCount: 0,
|
||
PendingBundleLimitDataAnalysisExpiredCount: 0,
|
||
PendingIncreaseLimitDataAnalysisExpiredCount: 0,
|
||
|
||
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 != "" {
|
||
sortBy := req.SortBy
|
||
sortType := req.SortType
|
||
if sortType != "asc" && sortType != "desc" && sortType != "ASC" && sortType != "DESC" {
|
||
sortType = "DESC"
|
||
}
|
||
// 将常用聚合字段映射为详细字段总和表达式
|
||
switch sortBy {
|
||
case "pending_video_count", "pendingVideoCount":
|
||
sortBy = "(pending_bundle_limit_video_expired_count + pending_bundle_limit_video_count + pending_increase_limit_video_expired_count + pending_increase_limit_video_count + pending_bundle_video_count + pending_increase_video_count)"
|
||
case "pending_post_count", "pendingPostCount":
|
||
sortBy = "(pending_bundle_limit_image_expired_count + pending_bundle_limit_image_count + pending_increase_limit_image_expired_count + pending_increase_limit_image_count + pending_bundle_image_count + pending_increase_image_count)"
|
||
case "pending_data_count", "pendingDataCount":
|
||
sortBy = "(pending_bundle_limit_data_analysis_expired_count + pending_bundle_limit_data_analysis_count + pending_increase_limit_data_analysis_expired_count + pending_increase_limit_data_analysis_count + pending_bundle_data_analysis_count + pending_increase_data_analysis_count)"
|
||
}
|
||
orderClause := fmt.Sprintf("%s %s", sortBy, sortType)
|
||
query = query.Order(orderClause)
|
||
} else {
|
||
// 默认按待发视频总和降序
|
||
query = query.Order("(pending_bundle_limit_video_expired_count + pending_bundle_limit_video_count + pending_increase_limit_video_expired_count + pending_increase_limit_video_count + pending_bundle_video_count + pending_increase_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,
|
||
// 待发视频
|
||
PendingBundleVideoCount: 0,
|
||
PendingIncreaseVideoCount: 0,
|
||
PendingBundleLimitVideoCount: 0,
|
||
PendingIncreaseLimitVideoCount: 0,
|
||
PendingBundleLimitVideoExpiredCount: 0,
|
||
PendingIncreaseLimitVideoExpiredCount: 0,
|
||
// 待发图片
|
||
PendingBundleImageCount: 0,
|
||
PendingIncreaseImageCount: 0,
|
||
PendingBundleLimitImageCount: 0,
|
||
PendingIncreaseLimitImageCount: 0,
|
||
PendingBundleLimitImageExpiredCount: 0,
|
||
PendingIncreaseLimitImageExpiredCount: 0,
|
||
// 待发数据分析
|
||
PendingBundleDataAnalysisCount: 0,
|
||
PendingIncreaseDataAnalysisCount: 0,
|
||
PendingBundleLimitDataAnalysisCount: 0,
|
||
PendingIncreaseLimitDataAnalysisCount: 0,
|
||
PendingBundleLimitDataAnalysisExpiredCount: 0,
|
||
PendingIncreaseLimitDataAnalysisExpiredCount: 0,
|
||
// 其他字段
|
||
ProgressCount: 0,
|
||
CompleteCount: 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 aggregatePendingVideo(&taskManagement) <= 0 && aggregatePendingImage(&taskManagement) <= 0 && aggregatePendingData(&taskManagement) <= 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 > aggregatePendingVideo(&taskManagement) ||
|
||
req.AssignPostCount > aggregatePendingImage(&taskManagement) ||
|
||
req.AssignDataCount > aggregatePendingData(&taskManagement) {
|
||
tx.Rollback()
|
||
return commonErr.ReturnError(nil, "指派数量超出限制",
|
||
fmt.Sprintf("指派数量不能超过待发数量。当前待发:视频%d,图文%d,数据%d",
|
||
aggregatePendingVideo(&taskManagement), aggregatePendingImage(&taskManagement), aggregatePendingData(&taskManagement)))
|
||
}
|
||
|
||
if req.AssignVideoCount == 0 && req.AssignPostCount == 0 && req.AssignDataCount == 0 {
|
||
tx.Rollback()
|
||
return commonErr.ReturnError(nil, "指派数量不能全为0", "至少需要指派一种类型的任务")
|
||
}
|
||
|
||
// 4. 按优先级扣减详细待发数量
|
||
if req.AssignVideoCount > 0 {
|
||
deductVideo(&taskManagement, req.AssignVideoCount)
|
||
}
|
||
if req.AssignPostCount > 0 {
|
||
deductImage(&taskManagement, req.AssignPostCount)
|
||
}
|
||
if req.AssignDataCount > 0 {
|
||
deductData(&taskManagement, req.AssignDataCount)
|
||
}
|
||
|
||
// 汇总更新字段
|
||
updateData := map[string]interface{}{
|
||
// 视频
|
||
"pending_bundle_limit_video_expired_count": taskManagement.PendingBundleLimitVideoExpiredCount,
|
||
"pending_bundle_limit_video_count": taskManagement.PendingBundleLimitVideoCount,
|
||
"pending_increase_limit_video_expired_count": taskManagement.PendingIncreaseLimitVideoExpiredCount,
|
||
"pending_increase_limit_video_count": taskManagement.PendingIncreaseLimitVideoCount,
|
||
"pending_bundle_video_count": taskManagement.PendingBundleVideoCount,
|
||
"pending_increase_video_count": taskManagement.PendingIncreaseVideoCount,
|
||
// 图片
|
||
"pending_bundle_limit_image_expired_count": taskManagement.PendingBundleLimitImageExpiredCount,
|
||
"pending_bundle_limit_image_count": taskManagement.PendingBundleLimitImageCount,
|
||
"pending_increase_limit_image_expired_count": taskManagement.PendingIncreaseLimitImageExpiredCount,
|
||
"pending_increase_limit_image_count": taskManagement.PendingIncreaseLimitImageCount,
|
||
"pending_bundle_image_count": taskManagement.PendingBundleImageCount,
|
||
"pending_increase_image_count": taskManagement.PendingIncreaseImageCount,
|
||
// 数据分析
|
||
"pending_bundle_limit_data_analysis_expired_count": taskManagement.PendingBundleLimitDataAnalysisExpiredCount,
|
||
"pending_bundle_limit_data_analysis_count": taskManagement.PendingBundleLimitDataAnalysisCount,
|
||
"pending_increase_limit_data_analysis_expired_count": taskManagement.PendingIncreaseLimitDataAnalysisExpiredCount,
|
||
"pending_increase_limit_data_analysis_count": taskManagement.PendingIncreaseLimitDataAnalysisCount,
|
||
"pending_bundle_data_analysis_count": taskManagement.PendingBundleDataAnalysisCount,
|
||
"pending_increase_data_analysis_count": taskManagement.PendingIncreaseDataAnalysisCount,
|
||
// 其他字段
|
||
"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: aggregatePendingVideo(&taskManagement),
|
||
PendingPostCount: aggregatePendingImage(&taskManagement),
|
||
PendingDataCount: aggregatePendingData(&taskManagement),
|
||
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
|
||
// 与查询余额保持一致:优先使用 sub_num,否则使用 tel_num
|
||
tmQuery := tx.Model(&model.TaskManagement{})
|
||
if req.SubNum != "" {
|
||
tmQuery = tmQuery.Where("sub_num = ?", req.SubNum)
|
||
} else {
|
||
tmQuery = tmQuery.Where("tel_num = ?", req.TelNum)
|
||
}
|
||
err := tmQuery.First(&taskManagement).Error
|
||
if err != nil {
|
||
if err == gorm.ErrRecordNotFound {
|
||
return commonErr.ReturnError(err, "无该艺人任务记录", "无该艺人任务记录")
|
||
} else {
|
||
tx.Rollback()
|
||
return commonErr.ReturnError(err, "查询任务记录失败", "查询任务记录失败: ")
|
||
}
|
||
}
|
||
|
||
// 2. 查询任务余额记录(当前有效月份优先,若无则回退到最近一条)
|
||
var taskBalance model.TaskBalance
|
||
now := time.Now()
|
||
tbQuery := tx.Model(&model.TaskBalance{})
|
||
if req.SubNum != "" {
|
||
tbQuery = tbQuery.Where("sub_num = ?", req.SubNum)
|
||
} else {
|
||
tbQuery = tbQuery.Where("tel_num = ?", req.TelNum)
|
||
}
|
||
tbErr := tbQuery.Where("start_at <= ? AND expired_at >= ?", now, now).Order("start_at DESC").Take(&taskBalance).Error
|
||
if tbErr != nil {
|
||
// 回退:取最近一条记录
|
||
_ = tbQuery.Order("start_at DESC").Take(&taskBalance).Error
|
||
}
|
||
|
||
// 若余额记录不存在,且本次需要“扣返余额”(目标小于当前)或“占用余额”(目标大于当前),直接报错
|
||
// 说明:此处不创建余额记录,避免无源数据导致余额错账
|
||
hasBalanceRecord := taskBalance.ID != 0
|
||
|
||
// 3. 计算当前聚合待发与目标值的差异(目标为绝对值,不是增减)
|
||
curVideo := aggregatePendingVideo(&taskManagement)
|
||
curImage := aggregatePendingImage(&taskManagement)
|
||
curData := aggregatePendingData(&taskManagement)
|
||
|
||
diffVideo := req.PendingVideoCount - curVideo
|
||
diffImage := req.PendingPostCount - curImage
|
||
diffData := req.PendingDataCount - curData
|
||
|
||
// 4. 若需要增加目标(diff>0),从艺人余额中按优先级占用并分配到待发分类
|
||
// 优先级:受限>非受限;同类型:打包>增量;受限内:过期优先
|
||
if diffVideo > 0 || diffImage > 0 || diffData > 0 {
|
||
if !hasBalanceRecord {
|
||
tx.Rollback()
|
||
return commonErr.ReturnError(nil, "无可用任务余额记录", "该艺人没有任务余额记录,无法占用余额用于增加待发")
|
||
}
|
||
|
||
// 视频占用
|
||
if diffVideo > 0 {
|
||
need := diffVideo
|
||
// 可用余额按分类拆分
|
||
availBLE := taskBalance.TaskBundleLimitVideoExpiredNumber - taskBalance.TaskBundleLimitVideoExpiredConsumptionNumber
|
||
availILE := taskBalance.TaskIncreaseLimitVideoExpiredNumber - taskBalance.TaskIncreaseLimitVideoExpiredConsumptionNumber
|
||
availBL := taskBalance.TaskBundleLimitVideoNumber - taskBalance.TaskBundleLimitVideoConsumptionNumber
|
||
availIL := taskBalance.TaskIncreaseLimitVideoNumber - taskBalance.TaskIncreaseLimitVideoConsumptionNumber
|
||
availB := taskBalance.TaskBundleVideoNumber - taskBalance.TaskBundleVideoConsumptionNumber
|
||
availI := taskBalance.TaskIncreaseVideoNumber - taskBalance.TaskIncreaseVideoConsumptionNumber
|
||
|
||
// 逐类占用并写入待发分类与消费数
|
||
if need > 0 && availBLE > 0 {
|
||
take := minInt(need, availBLE)
|
||
taskManagement.PendingBundleLimitVideoExpiredCount += take
|
||
taskBalance.TaskBundleLimitVideoExpiredConsumptionNumber += take
|
||
need -= take
|
||
}
|
||
if need > 0 && availILE > 0 {
|
||
take := minInt(need, availILE)
|
||
taskManagement.PendingIncreaseLimitVideoExpiredCount += take
|
||
taskBalance.TaskIncreaseLimitVideoExpiredConsumptionNumber += take
|
||
need -= take
|
||
}
|
||
if need > 0 && availBL > 0 {
|
||
take := minInt(need, availBL)
|
||
taskManagement.PendingBundleLimitVideoCount += take
|
||
taskBalance.TaskBundleLimitVideoConsumptionNumber += take
|
||
need -= take
|
||
}
|
||
if need > 0 && availIL > 0 {
|
||
take := minInt(need, availIL)
|
||
taskManagement.PendingIncreaseLimitVideoCount += take
|
||
taskBalance.TaskIncreaseLimitVideoConsumptionNumber += take
|
||
need -= take
|
||
}
|
||
if need > 0 && availB > 0 {
|
||
take := minInt(need, availB)
|
||
taskManagement.PendingBundleVideoCount += take
|
||
taskBalance.TaskBundleVideoConsumptionNumber += take
|
||
need -= take
|
||
}
|
||
if need > 0 && availI > 0 {
|
||
take := minInt(need, availI)
|
||
taskManagement.PendingIncreaseVideoCount += take
|
||
taskBalance.TaskIncreaseVideoConsumptionNumber += take
|
||
need -= take
|
||
}
|
||
if need > 0 {
|
||
tx.Rollback()
|
||
return commonErr.ReturnError(nil, "视频任务余额不足", "可用余额不足以达到目标待发视频数量")
|
||
}
|
||
}
|
||
|
||
// 图片占用
|
||
if diffImage > 0 {
|
||
need := diffImage
|
||
availBLE := taskBalance.TaskBundleLimitImageExpiredNumber - taskBalance.TaskBundleLimitImageExpiredConsumptionNumber
|
||
availILE := taskBalance.TaskIncreaseLimitImageExpiredNumber - taskBalance.TaskIncreaseLimitImageExpiredConsumptionNumber
|
||
availBL := taskBalance.TaskBundleLimitImageNumber - taskBalance.TaskBundleLimitImageConsumptionNumber
|
||
availIL := taskBalance.TaskIncreaseLimitImageNumber - taskBalance.TaskIncreaseLimitImageConsumptionNumber
|
||
availB := taskBalance.TaskBundleImageNumber - taskBalance.TaskBundleImageConsumptionNumber
|
||
availI := taskBalance.TaskIncreaseImageNumber - taskBalance.TaskIncreaseImageConsumptionNumber
|
||
|
||
if need > 0 && availBLE > 0 {
|
||
take := minInt(need, availBLE)
|
||
taskManagement.PendingBundleLimitImageExpiredCount += take
|
||
taskBalance.TaskBundleLimitImageExpiredConsumptionNumber += take
|
||
need -= take
|
||
}
|
||
if need > 0 && availILE > 0 {
|
||
take := minInt(need, availILE)
|
||
taskManagement.PendingIncreaseLimitImageExpiredCount += take
|
||
taskBalance.TaskIncreaseLimitImageExpiredConsumptionNumber += take
|
||
need -= take
|
||
}
|
||
if need > 0 && availBL > 0 {
|
||
take := minInt(need, availBL)
|
||
taskManagement.PendingBundleLimitImageCount += take
|
||
taskBalance.TaskBundleLimitImageConsumptionNumber += take
|
||
need -= take
|
||
}
|
||
if need > 0 && availIL > 0 {
|
||
take := minInt(need, availIL)
|
||
taskManagement.PendingIncreaseLimitImageCount += take
|
||
taskBalance.TaskIncreaseLimitImageConsumptionNumber += take
|
||
need -= take
|
||
}
|
||
if need > 0 && availB > 0 {
|
||
take := minInt(need, availB)
|
||
taskManagement.PendingBundleImageCount += take
|
||
taskBalance.TaskBundleImageConsumptionNumber += take
|
||
need -= take
|
||
}
|
||
if need > 0 && availI > 0 {
|
||
take := minInt(need, availI)
|
||
taskManagement.PendingIncreaseImageCount += take
|
||
taskBalance.TaskIncreaseImageConsumptionNumber += take
|
||
need -= take
|
||
}
|
||
if need > 0 {
|
||
tx.Rollback()
|
||
return commonErr.ReturnError(nil, "图文任务余额不足", "可用余额不足以达到目标待发图文数量")
|
||
}
|
||
}
|
||
|
||
// 数据分析占用
|
||
if diffData > 0 {
|
||
need := diffData
|
||
availBLE := taskBalance.TaskBundleLimitDataAnalysisExpiredNumber - taskBalance.TaskBundleLimitDataAnalysisExpiredConsumptionNumber
|
||
availILE := taskBalance.TaskIncreaseLimitDataAnalysisExpiredNumber - taskBalance.TaskIncreaseLimitDataAnalysisExpiredConsumptionNumber
|
||
availBL := taskBalance.TaskBundleLimitDataAnalysisNumber - taskBalance.TaskBundleLimitDataAnalysisConsumptionNumber
|
||
availIL := taskBalance.TaskIncreaseLimitDataAnalysisNumber - taskBalance.TaskIncreaseLimitDataAnalysisConsumptionNumber
|
||
availB := taskBalance.TaskBundleDataAnalysisNumber - taskBalance.TaskBundleDataAnalysisConsumptionNumber
|
||
availI := taskBalance.TaskIncreaseDataAnalysisNumber - taskBalance.TaskIncreaseDataAnalysisConsumptionNumber
|
||
|
||
if need > 0 && availBLE > 0 {
|
||
take := minInt(need, availBLE)
|
||
taskManagement.PendingBundleLimitDataAnalysisExpiredCount += take
|
||
taskBalance.TaskBundleLimitDataAnalysisExpiredConsumptionNumber += take
|
||
need -= take
|
||
}
|
||
if need > 0 && availILE > 0 {
|
||
take := minInt(need, availILE)
|
||
taskManagement.PendingIncreaseLimitDataAnalysisExpiredCount += take
|
||
taskBalance.TaskIncreaseLimitDataAnalysisExpiredConsumptionNumber += take
|
||
need -= take
|
||
}
|
||
if need > 0 && availBL > 0 {
|
||
take := minInt(need, availBL)
|
||
taskManagement.PendingBundleLimitDataAnalysisCount += take
|
||
taskBalance.TaskBundleLimitDataAnalysisConsumptionNumber += take
|
||
need -= take
|
||
}
|
||
if need > 0 && availIL > 0 {
|
||
take := minInt(need, availIL)
|
||
taskManagement.PendingIncreaseLimitDataAnalysisCount += take
|
||
taskBalance.TaskIncreaseLimitDataAnalysisConsumptionNumber += take
|
||
need -= take
|
||
}
|
||
if need > 0 && availB > 0 {
|
||
take := minInt(need, availB)
|
||
taskManagement.PendingBundleDataAnalysisCount += take
|
||
taskBalance.TaskBundleDataAnalysisConsumptionNumber += take
|
||
need -= take
|
||
}
|
||
if need > 0 && availI > 0 {
|
||
take := minInt(need, availI)
|
||
taskManagement.PendingIncreaseDataAnalysisCount += take
|
||
taskBalance.TaskIncreaseDataAnalysisConsumptionNumber += take
|
||
need -= take
|
||
}
|
||
if need > 0 {
|
||
tx.Rollback()
|
||
return commonErr.ReturnError(nil, "数据分析任务余额不足", "可用余额不足以达到目标待发数据分析数量")
|
||
}
|
||
}
|
||
}
|
||
|
||
// 5. 若需要减少目标(diff<0),先按优先级从待发分类扣减,并将扣减的数量按对应分类冲回余额(减少消费数)
|
||
if diffVideo < 0 || diffImage < 0 || diffData < 0 {
|
||
if !hasBalanceRecord {
|
||
tx.Rollback()
|
||
return commonErr.ReturnError(nil, "无可用任务余额记录", "该艺人没有任务余额记录,无法将多余待发冲回余额")
|
||
}
|
||
|
||
// 视频冲回
|
||
if diffVideo < 0 {
|
||
refund := -diffVideo
|
||
// 记录扣减前的各分类待发值
|
||
prevBLE := taskManagement.PendingBundleLimitVideoExpiredCount
|
||
prevILE := taskManagement.PendingIncreaseLimitVideoExpiredCount
|
||
prevBL := taskManagement.PendingBundleLimitVideoCount
|
||
prevIL := taskManagement.PendingIncreaseLimitVideoCount
|
||
prevB := taskManagement.PendingBundleVideoCount
|
||
prevI := taskManagement.PendingIncreaseVideoCount
|
||
|
||
deductVideo(&taskManagement, refund)
|
||
|
||
// 计算各分类被扣减的数量,并减少对应消费数(不可小于0)
|
||
removedBLE := prevBLE - taskManagement.PendingBundleLimitVideoExpiredCount
|
||
removedILE := prevILE - taskManagement.PendingIncreaseLimitVideoExpiredCount
|
||
removedBL := prevBL - taskManagement.PendingBundleLimitVideoCount
|
||
removedIL := prevIL - taskManagement.PendingIncreaseLimitVideoCount
|
||
removedB := prevB - taskManagement.PendingBundleVideoCount
|
||
removedI := prevI - taskManagement.PendingIncreaseVideoCount
|
||
|
||
taskBalance.TaskBundleLimitVideoExpiredConsumptionNumber = maxInt(0, taskBalance.TaskBundleLimitVideoExpiredConsumptionNumber-removedBLE)
|
||
taskBalance.TaskIncreaseLimitVideoExpiredConsumptionNumber = maxInt(0, taskBalance.TaskIncreaseLimitVideoExpiredConsumptionNumber-removedILE)
|
||
taskBalance.TaskBundleLimitVideoConsumptionNumber = maxInt(0, taskBalance.TaskBundleLimitVideoConsumptionNumber-removedBL)
|
||
taskBalance.TaskIncreaseLimitVideoConsumptionNumber = maxInt(0, taskBalance.TaskIncreaseLimitVideoConsumptionNumber-removedIL)
|
||
taskBalance.TaskBundleVideoConsumptionNumber = maxInt(0, taskBalance.TaskBundleVideoConsumptionNumber-removedB)
|
||
taskBalance.TaskIncreaseVideoConsumptionNumber = maxInt(0, taskBalance.TaskIncreaseVideoConsumptionNumber-removedI)
|
||
}
|
||
|
||
// 图片冲回
|
||
if diffImage < 0 {
|
||
refund := -diffImage
|
||
prevBLE := taskManagement.PendingBundleLimitImageExpiredCount
|
||
prevILE := taskManagement.PendingIncreaseLimitImageExpiredCount
|
||
prevBL := taskManagement.PendingBundleLimitImageCount
|
||
prevIL := taskManagement.PendingIncreaseLimitImageCount
|
||
prevB := taskManagement.PendingBundleImageCount
|
||
prevI := taskManagement.PendingIncreaseImageCount
|
||
|
||
deductImage(&taskManagement, refund)
|
||
|
||
removedBLE := prevBLE - taskManagement.PendingBundleLimitImageExpiredCount
|
||
removedILE := prevILE - taskManagement.PendingIncreaseLimitImageExpiredCount
|
||
removedBL := prevBL - taskManagement.PendingBundleLimitImageCount
|
||
removedIL := prevIL - taskManagement.PendingIncreaseLimitImageCount
|
||
removedB := prevB - taskManagement.PendingBundleImageCount
|
||
removedI := prevI - taskManagement.PendingIncreaseImageCount
|
||
|
||
taskBalance.TaskBundleLimitImageExpiredConsumptionNumber = maxInt(0, taskBalance.TaskBundleLimitImageExpiredConsumptionNumber-removedBLE)
|
||
taskBalance.TaskIncreaseLimitImageExpiredConsumptionNumber = maxInt(0, taskBalance.TaskIncreaseLimitImageExpiredConsumptionNumber-removedILE)
|
||
taskBalance.TaskBundleLimitImageConsumptionNumber = maxInt(0, taskBalance.TaskBundleLimitImageConsumptionNumber-removedBL)
|
||
taskBalance.TaskIncreaseLimitImageConsumptionNumber = maxInt(0, taskBalance.TaskIncreaseLimitImageConsumptionNumber-removedIL)
|
||
taskBalance.TaskBundleImageConsumptionNumber = maxInt(0, taskBalance.TaskBundleImageConsumptionNumber-removedB)
|
||
taskBalance.TaskIncreaseImageConsumptionNumber = maxInt(0, taskBalance.TaskIncreaseImageConsumptionNumber-removedI)
|
||
}
|
||
|
||
// 数据分析冲回
|
||
if diffData < 0 {
|
||
refund := -diffData
|
||
prevBLE := taskManagement.PendingBundleLimitDataAnalysisExpiredCount
|
||
prevILE := taskManagement.PendingIncreaseLimitDataAnalysisExpiredCount
|
||
prevBL := taskManagement.PendingBundleLimitDataAnalysisCount
|
||
prevIL := taskManagement.PendingIncreaseLimitDataAnalysisCount
|
||
prevB := taskManagement.PendingBundleDataAnalysisCount
|
||
prevI := taskManagement.PendingIncreaseDataAnalysisCount
|
||
|
||
deductData(&taskManagement, refund)
|
||
|
||
removedBLE := prevBLE - taskManagement.PendingBundleLimitDataAnalysisExpiredCount
|
||
removedILE := prevILE - taskManagement.PendingIncreaseLimitDataAnalysisExpiredCount
|
||
removedBL := prevBL - taskManagement.PendingBundleLimitDataAnalysisCount
|
||
removedIL := prevIL - taskManagement.PendingIncreaseLimitDataAnalysisCount
|
||
removedB := prevB - taskManagement.PendingBundleDataAnalysisCount
|
||
removedI := prevI - taskManagement.PendingIncreaseDataAnalysisCount
|
||
|
||
taskBalance.TaskBundleLimitDataAnalysisExpiredConsumptionNumber = maxInt(0, taskBalance.TaskBundleLimitDataAnalysisExpiredConsumptionNumber-removedBLE)
|
||
taskBalance.TaskIncreaseLimitDataAnalysisExpiredConsumptionNumber = maxInt(0, taskBalance.TaskIncreaseLimitDataAnalysisExpiredConsumptionNumber-removedILE)
|
||
taskBalance.TaskBundleLimitDataAnalysisConsumptionNumber = maxInt(0, taskBalance.TaskBundleLimitDataAnalysisConsumptionNumber-removedBL)
|
||
taskBalance.TaskIncreaseLimitDataAnalysisConsumptionNumber = maxInt(0, taskBalance.TaskIncreaseLimitDataAnalysisConsumptionNumber-removedIL)
|
||
taskBalance.TaskBundleDataAnalysisConsumptionNumber = maxInt(0, taskBalance.TaskBundleDataAnalysisConsumptionNumber-removedB)
|
||
taskBalance.TaskIncreaseDataAnalysisConsumptionNumber = maxInt(0, taskBalance.TaskIncreaseDataAnalysisConsumptionNumber-removedI)
|
||
}
|
||
}
|
||
|
||
// 6. 更新TaskManagement表
|
||
updateData := map[string]interface{}{
|
||
// 视频
|
||
"pending_bundle_limit_video_expired_count": taskManagement.PendingBundleLimitVideoExpiredCount,
|
||
"pending_bundle_limit_video_count": taskManagement.PendingBundleLimitVideoCount,
|
||
"pending_increase_limit_video_expired_count": taskManagement.PendingIncreaseLimitVideoExpiredCount,
|
||
"pending_increase_limit_video_count": taskManagement.PendingIncreaseLimitVideoCount,
|
||
"pending_bundle_video_count": taskManagement.PendingBundleVideoCount,
|
||
"pending_increase_video_count": taskManagement.PendingIncreaseVideoCount,
|
||
// 图片
|
||
"pending_bundle_limit_image_expired_count": taskManagement.PendingBundleLimitImageExpiredCount,
|
||
"pending_bundle_limit_image_count": taskManagement.PendingBundleLimitImageCount,
|
||
"pending_increase_limit_image_expired_count": taskManagement.PendingIncreaseLimitImageExpiredCount,
|
||
"pending_increase_limit_image_count": taskManagement.PendingIncreaseLimitImageCount,
|
||
"pending_bundle_image_count": taskManagement.PendingBundleImageCount,
|
||
"pending_increase_image_count": taskManagement.PendingIncreaseImageCount,
|
||
// 数据分析
|
||
"pending_bundle_limit_data_analysis_expired_count": taskManagement.PendingBundleLimitDataAnalysisExpiredCount,
|
||
"pending_bundle_limit_data_analysis_count": taskManagement.PendingBundleLimitDataAnalysisCount,
|
||
"pending_increase_limit_data_analysis_expired_count": taskManagement.PendingIncreaseLimitDataAnalysisExpiredCount,
|
||
"pending_increase_limit_data_analysis_count": taskManagement.PendingIncreaseLimitDataAnalysisCount,
|
||
"pending_bundle_data_analysis_count": taskManagement.PendingBundleDataAnalysisCount,
|
||
"pending_increase_data_analysis_count": taskManagement.PendingIncreaseDataAnalysisCount,
|
||
// 通用
|
||
"updated_at": time.Now(),
|
||
}
|
||
if err = tx.Model(&taskManagement).Updates(updateData).Error; err != nil {
|
||
tx.Rollback()
|
||
return commonErr.ReturnError(err, "更新任务记录失败", "更新任务记录失败: ")
|
||
}
|
||
|
||
// 7. 更新TaskBalance(消费数发生变化时)
|
||
if hasBalanceRecord {
|
||
updateBal := map[string]interface{}{
|
||
// 视频消费数
|
||
"task_bundle_limit_video_expired_consumption_number": taskBalance.TaskBundleLimitVideoExpiredConsumptionNumber,
|
||
"task_increase_limit_video_expired_consumption_number": taskBalance.TaskIncreaseLimitVideoExpiredConsumptionNumber,
|
||
"task_bundle_limit_video_consumption_number": taskBalance.TaskBundleLimitVideoConsumptionNumber,
|
||
"task_increase_limit_video_consumption_number": taskBalance.TaskIncreaseLimitVideoConsumptionNumber,
|
||
"task_bundle_video_consumption_number": taskBalance.TaskBundleVideoConsumptionNumber,
|
||
"task_increase_video_consumption_number": taskBalance.TaskIncreaseVideoConsumptionNumber,
|
||
// 图片消费数
|
||
"task_bundle_limit_image_expired_consumption_number": taskBalance.TaskBundleLimitImageExpiredConsumptionNumber,
|
||
"task_increase_limit_image_expired_consumption_number": taskBalance.TaskIncreaseLimitImageExpiredConsumptionNumber,
|
||
"task_bundle_limit_image_consumption_number": taskBalance.TaskBundleLimitImageConsumptionNumber,
|
||
"task_increase_limit_image_consumption_number": taskBalance.TaskIncreaseLimitImageConsumptionNumber,
|
||
"task_bundle_image_consumption_number": taskBalance.TaskBundleImageConsumptionNumber,
|
||
"task_increase_image_consumption_number": taskBalance.TaskIncreaseImageConsumptionNumber,
|
||
// 数据分析消费数
|
||
"task_bundle_limit_data_analysis_expired_consumption_number": taskBalance.TaskBundleLimitDataAnalysisExpiredConsumptionNumber,
|
||
"task_increase_limit_data_analysis_expired_consumption_number": taskBalance.TaskIncreaseLimitDataAnalysisExpiredConsumptionNumber,
|
||
"task_bundle_limit_data_analysis_consumption_number": taskBalance.TaskBundleLimitDataAnalysisConsumptionNumber,
|
||
"task_increase_limit_data_analysis_consumption_number": taskBalance.TaskIncreaseLimitDataAnalysisConsumptionNumber,
|
||
"task_bundle_data_analysis_consumption_number": taskBalance.TaskBundleDataAnalysisConsumptionNumber,
|
||
"task_increase_data_analysis_consumption_number": taskBalance.TaskIncreaseDataAnalysisConsumptionNumber,
|
||
// 通用
|
||
"updated_at": time.Now(),
|
||
}
|
||
if err = tx.Model(&taskBalance).Updates(updateBal).Error; err != nil {
|
||
tx.Rollback()
|
||
return commonErr.ReturnError(err, "更新任务余额失败", "更新任务余额失败: ")
|
||
}
|
||
}
|
||
|
||
// 提交事务
|
||
if err = tx.Commit().Error; err != nil {
|
||
return commonErr.ReturnError(err, "提交事务失败", "提交事务失败: ")
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// minInt 返回两个整数的较小值
|
||
func minInt(a, b int) int {
|
||
if a < b {
|
||
return a
|
||
}
|
||
return b
|
||
}
|
||
|
||
// maxInt 返回两个整数的较大值
|
||
func maxInt(a, b int) int {
|
||
if a > b {
|
||
return a
|
||
}
|
||
return b
|
||
}
|
||
|
||
// 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 != "" && req.EndTime != "" {
|
||
query = query.Where("operator_time BETWEEN ? AND ?", req.StartTime, req.EndTime)
|
||
} else if req.StartTime != "" {
|
||
query = query.Where("operator_time >= ?", req.StartTime)
|
||
} else if req.EndTime != "" {
|
||
query = query.Where("operator_time <= ?", req.EndTime)
|
||
}
|
||
|
||
// 完成时间区间
|
||
if req.StartCompleteTime != "" && req.EndCompleteTime != "" {
|
||
query = query.Where("complete_time BETWEEN ? AND ?", req.StartCompleteTime, req.EndCompleteTime)
|
||
} else if req.StartCompleteTime != "" {
|
||
query = query.Where("complete_time >= ?", req.StartCompleteTime)
|
||
} else 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 != "" && req.EndTime != "" {
|
||
query = query.Where("operator_time BETWEEN ? AND ?", req.StartTime, req.EndTime)
|
||
} else if req.StartTime != "" {
|
||
query = query.Where("operator_time >= ?", req.StartTime)
|
||
} else 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.bundle_account_number + bb.increase_account_number + bb.manual_account_number) as account_number,
|
||
(bb.bundle_account_consumption_number + bb.increase_account_consumption_number + bb.manual_account_consumption_number) as account_consumption_number,
|
||
(bb.bundle_video_number + bb.increase_video_number) as video_number,
|
||
(bb.bundle_video_consumption_number + bb.increase_video_consumption_number) as video_consumption_number,
|
||
(bb.bundle_image_number + bb.increase_image_number + bb.manual_image_number) as image_number,
|
||
(bb.bundle_image_consumption_number + bb.increase_image_consumption_number + bb.manual_image_consumption_number) as image_consumption_number,
|
||
(bb.bundle_data_analysis_number + bb.increase_data_analysis_number + bb.manual_data_analysis_number) as data_analysis_number,
|
||
(bb.bundle_data_analysis_consumption_number + bb.increase_data_analysis_consumption_number + bb.manual_data_analysis_consumption_number) as 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 {
|
||
// 创建新记录,正数增加分配到“非限制-套餐权益”,负数忽略(置0)
|
||
video := req.AdjustVideoCount
|
||
post := req.AdjustPostCount
|
||
data := req.AdjustDataCount
|
||
if video < 0 {
|
||
video = 0
|
||
}
|
||
if post < 0 {
|
||
post = 0
|
||
}
|
||
if data < 0 {
|
||
data = 0
|
||
}
|
||
|
||
taskManagement = model.TaskManagement{
|
||
SubNum: req.SubNum,
|
||
TelNum: req.TelNum,
|
||
ArtistName: req.ArtistName,
|
||
|
||
// 视频
|
||
PendingBundleVideoCount: video,
|
||
PendingIncreaseVideoCount: 0,
|
||
PendingBundleLimitVideoCount: 0,
|
||
PendingIncreaseLimitVideoCount: 0,
|
||
PendingBundleLimitVideoExpiredCount: 0,
|
||
PendingIncreaseLimitVideoExpiredCount: 0,
|
||
// 图片
|
||
PendingBundleImageCount: post,
|
||
PendingIncreaseImageCount: 0,
|
||
PendingBundleLimitImageCount: 0,
|
||
PendingIncreaseLimitImageCount: 0,
|
||
PendingBundleLimitImageExpiredCount: 0,
|
||
PendingIncreaseLimitImageExpiredCount: 0,
|
||
// 数据分析
|
||
PendingBundleDataAnalysisCount: data,
|
||
PendingIncreaseDataAnalysisCount: 0,
|
||
PendingBundleLimitDataAnalysisCount: 0,
|
||
PendingIncreaseLimitDataAnalysisCount: 0,
|
||
PendingBundleLimitDataAnalysisExpiredCount: 0,
|
||
PendingIncreaseLimitDataAnalysisExpiredCount: 0,
|
||
|
||
ProgressCount: 0,
|
||
CompleteCount: 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, "任务记录不存在", "找不到对应的任务记录")
|
||
}
|
||
} else {
|
||
tx.Rollback()
|
||
return commonErr.ReturnError(err, "查询任务记录失败", "查询任务记录失败: ")
|
||
}
|
||
} else {
|
||
// 2. 计算调整:正数增加分配到“非限制-套餐权益”;负数按优先级扣减
|
||
if req.AdjustVideoCount > 0 {
|
||
taskManagement.PendingBundleVideoCount += req.AdjustVideoCount
|
||
} else if req.AdjustVideoCount < 0 {
|
||
deductVideo(&taskManagement, -req.AdjustVideoCount)
|
||
}
|
||
|
||
if req.AdjustPostCount > 0 {
|
||
taskManagement.PendingBundleImageCount += req.AdjustPostCount
|
||
} else if req.AdjustPostCount < 0 {
|
||
deductImage(&taskManagement, -req.AdjustPostCount)
|
||
}
|
||
|
||
if req.AdjustDataCount > 0 {
|
||
taskManagement.PendingBundleDataAnalysisCount += req.AdjustDataCount
|
||
} else if req.AdjustDataCount < 0 {
|
||
deductData(&taskManagement, -req.AdjustDataCount)
|
||
}
|
||
|
||
// 4. 更新TaskManagement表
|
||
updateData := map[string]interface{}{
|
||
// 视频
|
||
"pending_bundle_limit_video_expired_count": taskManagement.PendingBundleLimitVideoExpiredCount,
|
||
"pending_bundle_limit_video_count": taskManagement.PendingBundleLimitVideoCount,
|
||
"pending_increase_limit_video_expired_count": taskManagement.PendingIncreaseLimitVideoExpiredCount,
|
||
"pending_increase_limit_video_count": taskManagement.PendingIncreaseLimitVideoCount,
|
||
"pending_bundle_video_count": taskManagement.PendingBundleVideoCount,
|
||
"pending_increase_video_count": taskManagement.PendingIncreaseVideoCount,
|
||
// 图片
|
||
"pending_bundle_limit_image_expired_count": taskManagement.PendingBundleLimitImageExpiredCount,
|
||
"pending_bundle_limit_image_count": taskManagement.PendingBundleLimitImageCount,
|
||
"pending_increase_limit_image_expired_count": taskManagement.PendingIncreaseLimitImageExpiredCount,
|
||
"pending_increase_limit_image_count": taskManagement.PendingIncreaseLimitImageCount,
|
||
"pending_bundle_image_count": taskManagement.PendingBundleImageCount,
|
||
"pending_increase_image_count": taskManagement.PendingIncreaseImageCount,
|
||
// 数据分析
|
||
"pending_bundle_limit_data_analysis_expired_count": taskManagement.PendingBundleLimitDataAnalysisExpiredCount,
|
||
"pending_bundle_limit_data_analysis_count": taskManagement.PendingBundleLimitDataAnalysisCount,
|
||
"pending_increase_limit_data_analysis_expired_count": taskManagement.PendingIncreaseLimitDataAnalysisExpiredCount,
|
||
"pending_increase_limit_data_analysis_count": taskManagement.PendingIncreaseLimitDataAnalysisCount,
|
||
"pending_bundle_data_analysis_count": taskManagement.PendingBundleDataAnalysisCount,
|
||
"pending_increase_data_analysis_count": taskManagement.PendingIncreaseDataAnalysisCount,
|
||
// 通用
|
||
"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
|
||
}
|