864 lines
21 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

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

import request from '@/utils/request'
export interface Task {
id?: number
taskNo?: string
title: string
taskTypeId: number
taskSubType?: string
quantity?: number
score?: number
estimatedHours?: number
brandId?: number
categoryId?: number
spuInfo?: string
platformId?: number
attachmentUrl?: string
deliveryPath?: string
publisherId?: number
publisherDeptId?: number
receiverId?: number
receiverDeptId?: number
receiverName?: string
receiverDeptName?: string
releaseType: string
status?: string
auditStatus?: string
auditorId?: number
auditorName?: string
auditTime?: string
auditComment?: string
progress?: number
startTime?: string
deadline?: string
completeTime?: string
rating?: number
reviewComment?: string
rejectReason?: string
isUrgent?: number
isDelayed?: number
createTime?: string
updateTime?: string
remark?: string
// 流水线任务字段
isPipeline?: number
pipelineMode?: 'sequential' | 'parallel'
// 两级审核字段
approvalStatus?: string // pending_demand_approval/pending_receiving_approval/approved/rejected_by_demand/rejected_by_receiving
currentApproverId?: number
currentApproverRole?: string // demand_leader/receiving_leader
currentApproverName?: string // 当前审核人姓名
demandApprovalTime?: string
receivingApprovalTime?: string
// 关联字段(从后端查询返回)
brandName?: string
categoryName?: string
platformName?: string
publisherName?: string
publisherDeptName?: string
// 子任务统计(流水线任务)
subTaskTotal?: number
subTaskCompleted?: number
subTaskInProgress?: number
subTaskPending?: number
subTasks?: TaskItem[]
// 标记字段(前端使用)
isSubTask?: boolean
// 商品ID填写状态
productIdFilled?: number // 0-未填写 1-已填写
// 所有子任务交付路径汇总
allDeliveryPaths?: string[]
// 预览图
previewImage?: string
// 素材下载链接
downloadUrl?: string
// 一级需求部门相关字段
primaryPublisherId?: number // 一级部门发起人ID
primaryPublisherDeptId?: number // 一级部门ID
primaryPublisherName?: string // 一级部门发起人姓名
primaryPublisherDeptName?: string // 一级部门名称
detailCompleterId?: number // 明细完善人ID
detailCompleterName?: string // 明细完善人姓名
isPrimaryTask?: number // 是否一级部门任务:0-否,1-是
detailCompleted?: number // 明细是否已完善:0-否,1-是
}
// 任务子项(流水线任务)
export interface TaskItem {
id?: number
taskId: number
itemNo?: string
taskTypeId: number
taskTypeName?: string
quantity: number
unitScore: number
totalScore: number
estimatedHours?: number
deadline?: string // 截止时间(接单时计算)
receiverId?: number
receiverName?: string
status: string // locked/pending/in_progress/completed/rejected
progress?: number
isLocked?: number
prevItemId?: number
deliveryPath?: string
submitTime?: string
completeTime?: string
sortOrder: number
createTime?: string
updateTime?: string
// 主任务信息
mainTaskTitle?: string
pipelineMode?: 'sequential' | 'parallel'
totalItems?: number
// 其他关联字段
brandName?: string
categoryName?: string
platformName?: string
publisherName?: string
spuInfo?: string
taskSubType?: string
attachmentUrl?: string
previewImage?: string
downloadUrl?: string
prevDownloadUrl?: string // 前置子任务的素材下载链接
}
// 创建流水线任务请求
export interface PipelineTaskRequest {
title: string
isPipeline: boolean
pipelineMode: 'sequential' | 'parallel'
publisherDeptId?: number
items: Array<{
taskTypeId: number
quantity: number
sortOrder: number
receiverId?: number // 指定接收人
selectedDeptId?: number
}>
brandId?: number
categoryId?: number
platformId?: number
spuInfo?: string
taskSubType?: string
attachmentUrl?: string
remark?: string
priority?: string
}
export interface TaskAuditRequest {
taskId: number
result: 'pass' | 'reject'
comment?: string
}
export interface TaskListParams {
status?: string
taskTypeId?: number
page?: number
pageSize?: number
}
export interface TaskHallParams {
taskTypeId?: number
demandTypeId?: number
brandId?: number
categoryId?: number
platformId?: number
taskSubType?: string
minScore?: number
maxScore?: number
keyword?: string
publisherName?: string
timeRange?: 'today' | 'week' | 'month'
sortBy?: 'oldest' | 'latest' | 'score' | 'deadline' | 'hot' // 🔥 新增 oldest 选项
page?: number
pageSize?: number
}
export interface MyTasksParams {
role?: 'publisher' | 'receiver' | 'detail_completer'
status?: string
page?: number
pageSize?: number
keyword?: string
taskTypeId?: number
brandId?: number
categoryId?: number
platformId?: number
taskSubType?: string
minScore?: number
maxScore?: number
timeRange?: string
sortBy?: string
}
/**
* 创建任务
*/
export const createTask = (data: Task) => {
return request.post<any>('/tasks', data)
}
/**
* 获取任务列表
*/
export const getTaskList = (params: TaskListParams) => {
return request.get<any>('/tasks', { params })
}
/**
* 获取任务详情
*/
export const getTaskById = (id: number) => {
return request.get<any>(`/tasks/${id}`)
}
/**
* 更新任务
*/
export const updateTask = (id: number, data: Partial<Task>) => {
return request.put<any>(`/tasks/${id}`, data)
}
/**
* 抢单
*/
export const grabTask = (id: number) => {
return request.post<any>(`/tasks/${id}/grab`)
}
/**
* 提交任务
*/
export const submitTask = (id: number, deliveryPath: string) => {
return request.post<any>(`/tasks/${id}/submit`, null, {
params: { deliveryPath }
})
}
/**
* 审核任务
*/
export const reviewTask = (
id: number,
approved: boolean,
comment?: string,
rating?: number
) => {
return request.post<any>(`/tasks/${id}/review`, null, {
params: { approved, comment, rating }
})
}
/**
* 取消任务
*/
export const cancelTask = (id: number, reason: string) => {
return request.post<any>(`/tasks/${id}/cancel`, null, {
params: { reason }
})
}
/**
* 评分任务(需求方对已完成任务进行评分)
*/
export const rateTask = (id: number, rating: number, comment?: string) => {
return request.post<any>(`/tasks/${id}/rate`, null, {
params: { rating, comment }
})
}
/**
* 获取任务大厅
*/
export const getTaskHall = (params: TaskHallParams) => {
return request.get<any>('/tasks/hall', { params })
}
/**
* 获取已完成任务列表(根据角色权限)
*/
export const getCompletedTasks = (params: any) => {
return request.get<any>('/tasks/completed', { params })
}
/**
* 获取我的进行中任务列表
*/
export const getMyInProgressTasks = () => {
return request.get<any>('/tasks/my-in-progress')
}
/**
* 批量更新任务进度
*/
export const batchUpdateProgress = (updates: Array<{taskId: number, progress: number, remark?: string}>) => {
return request.post<any>('/tasks/batch-update-progress', { updates })
}
/**
* 获取我的任务
*/
export const getMyTasks = (params: MyTasksParams) => {
return request.get<any>('/tasks/my', { params })
}
/**
* 提交任务审核
*/
export const submitTaskAudit = (id: number) => {
return request.post<any>(`/tasks/${id}/submit-audit`)
}
/**
* 审核任务(部门负责人)
*/
export const auditTask = (data: TaskAuditRequest) => {
return request.post<any>('/tasks/audit', data)
}
/**
* 强制指派任务
*/
export const assignTask = (taskId: number, assigneeId: number, comment?: string) => {
return request.post<any>('/tasks/assign', {
taskId,
assigneeId,
assignType: 'force',
comment
})
}
/**
* 获取负责人任务列表(需求部门负责人)
*/
export const getLeaderTaskList = (params: { auditStatus?: string; page?: number; pageSize?: number }) => {
return request.get<any>('/tasks/leader/demand', { params })
}
/**
* 获取接单部门负责人视图
*/
export const getLeaderReceivingTaskList = (params: { status?: string; page?: number; pageSize?: number }) => {
return request.get<any>('/tasks/leader/receiving', { params })
}
/**
* 工作台统计数据接口
*/
export interface DashboardStats {
availableCount?: number
publishedCount?: number // 发布的任务数(当前用户当月发布的任务总数)
inProgressCount: number
completedCount: number
reviewCount: number
totalScore: number
todayStartedCount: number
todayCompletedCount: number
weekCompletedCount: number
lastWeekCompletedCount: number
}
/**
* 获取工作台统计数据
*/
export const getDashboardStats = (params?: { month?: string; deptId?: number }) => {
return request.get<DashboardStats>('/tasks/dashboard/stats', { params })
}
/**
* 通用获取任务列表(支持状态筛选)
*/
export const getTasks = (params: any) => {
return request.get<any>('/tasks', { params })
}
/**
* 更新任务进度
*/
export const updateTaskProgress = (taskId: number, progress: number) => {
return request.post<any>(`/tasks/${taskId}/progress`, { progress })
}
/**
* 完结任务(提交审核)
*/
export const completeTask = (taskId: number, data: { deliveryPath: string }) => {
return request.post<any>(`/tasks/${taskId}/complete`, data)
}
/**
* 审核通过任务
*/
export const approveTask = (taskId: number) => {
return request.post<any>(`/tasks/${taskId}/approve`)
}
/**
* 驳回任务
*/
export const rejectTask = (taskId: number, data: { reason: string }) => {
return request.post<any>(`/tasks/${taskId}/reject`, data)
}
// ==================== 流水线任务相关 API ====================
/**
* 创建流水线任务
*/
export const createPipelineTask = (data: PipelineTaskRequest) => {
return request.post<any>('/tasks/pipeline', data)
}
/**
* 获取可接单的子任务列表
*/
export const getAvailableTaskItems = (params: {
page?: number
pageSize?: number
taskTypeId?: number
keyword?: string
brandId?: number
categoryId?: number
platformId?: number
taskSubType?: string
filterDeptId?: number
sortBy?: string
}) => {
return request.get<any>('/tasks/items/available', { params })
}
/**
* 获取进行中的子任务列表
*/
export const getInProgressTaskItems = (params: {
page?: number
pageSize?: number
keyword?: string
deptId?: number // 部门负责人切换视角时使用
}) => {
return request.get<any>('/tasks/items/in-progress', { params })
}
/**
* 获取已完成的子任务列表
*/
export const getCompletedTaskItems = (params: {
page?: number
pageSize?: number
keyword?: string
deptId?: number // 部门负责人切换视角时使用
}) => {
return request.get<any>('/tasks/items/completed', { params })
}
/**
* 根据主任务ID获取所有子任务
*/
export const getTaskItemsByTaskId = (taskId: number) => {
return request.get<any>(`/tasks/items/task/${taskId}`)
}
/**
* 获取子任务详情
*/
export const getTaskItemById = (itemId: number) => {
return request.get<any>(`/tasks/items/${itemId}`)
}
/**
* 抢单子任务
*/
export const grabTaskItem = (itemId: number) => {
return request.post<any>(`/tasks/items/${itemId}/grab`)
}
/**
* 更新子任务进度
*/
export const updateTaskItemProgress = (itemId: number, progress: number) => {
return request.post<any>(`/tasks/items/${itemId}/progress`, null, {
params: { progress }
})
}
/**
* 完结子任务
*/
export const completeTaskItem = (itemId: number, data: { deliveryPath: string }) => {
return request.post<any>(`/tasks/items/${itemId}/complete`, data)
}
/**
* 驳回子任务
*/
export const rejectTaskItem = (itemId: number, data: { reason: string }) => {
return request.post<any>(`/tasks/items/${itemId}/reject`, data)
}
/**
* 获取主任务进度统计
*/
export const getTaskItemsProgress = (taskId: number) => {
return request.get<any>(`/tasks/items/task/${taskId}/progress`)
}
/**
* 审核子任务组
*/
export const approveTaskItemGroup = (data: {
taskId: number
groupNo: number
assignedReceiverId?: number
}) => {
return request.post<any>('/tasks/items/groups/approve', data)
}
/**
* 获取待审核的子任务组列表
*/
export const getPendingApprovalGroups = (deptId?: number) => {
return request.get<any>('/tasks/items/groups/pending-approval', {
params: deptId ? { deptId } : {}
})
}
// ==================== 两级审核API ====================
/**
* 任务审核DTO
*/
export interface TaskApprovalDTO {
comment?: string // 审核意见
taskUpdates?: TaskUpdateDTO // 任务修改(可选)
assignedReceiverId?: number // 指定的接收人ID(用于接单部门审核时指定设计师)
}
/**
* 任务更新DTO
*/
export interface TaskUpdateDTO {
title?: string
taskSubType?: string
brandId?: number
platformId?: number
categoryId?: number
spuInfo?: string
remark?: string
attachmentUrl?: string
taskTypes?: Array<{
taskTypeId: number
quantity: number
}>
}
/**
* 获取待审核任务列表
*/
export const getPendingApprovalTasks = () => {
return request.get<Task[]>('/tasks/pending-approval')
}
/**
* 获取所有待审核任务(处于审批流程中的任务)
*/
export const getAllPendingApprovalTasks = (params?: { taskTypeId?: number; page?: number; pageSize?: number }) => {
return request.get<any>('/tasks/pending-approval-all', { params })
}
/**
* 需求部门负责人审核通过
*/
export const approveDemandLevel = (taskId: number, data: TaskApprovalDTO) => {
return request.post<any>(`/tasks/${taskId}/approve-demand`, data)
}
/**
* 需求部门负责人驳回
*/
export const rejectByDemandLeader = (taskId: number, reason: string) => {
return request.post<any>(`/tasks/${taskId}/reject-demand`, { reason })
}
/**
* 接单部门负责人审核通过
*/
export const approveReceivingLevel = (taskId: number, data: TaskApprovalDTO) => {
return request.post<any>(`/tasks/${taskId}/approve-receiving`, data)
}
/**
* 接单部门负责人驳回
*/
export const rejectByReceivingLeader = (taskId: number, reason: string) => {
return request.post<any>(`/tasks/${taskId}/reject-receiving`, { reason })
}
// ==================== 子任务组审核相关 ====================
/**
* 子任务组信息
*/
export interface TaskGroup {
groupId: number
mainTaskId: number
mainTaskTitle: string
mainTaskNo: string
items: TaskItem[]
totalScore: number
}
/**
* 获取待审核的子任务组列表
*/
export const getPendingApprovalTaskGroups = (deptId?: number) => {
return request.get<TaskGroup[]>('/tasks/items/groups/pending-approval', {
params: deptId ? { deptId } : {}
})
}
/**
* 审核通过子任务组
*/
export const approveTaskGroup = (taskId: number, data: { groupNo: number; assignedReceiverId?: number; comment?: string }) => {
return request.post<any>('/tasks/items/groups/approve', { taskId, ...data })
}
/**
* 驳回子任务组
*/
export const rejectTaskGroup = (taskId: number, groupNo: number, reason: string) => {
return request.post<any>('/tasks/items/groups/reject', { taskId, groupNo, reason })
}
// ==================== 任务商品ID管理 ====================
/**
* 商品ID记录
*/
export interface TaskProduct {
id: number
taskId: number
productId: string
productName?: string
remark?: string
creatorId: number
creatorName?: string
createTime: string
}
/**
* 获取任务的商品ID列表
*/
export const getTaskProducts = (taskId: number) => {
return request.get<TaskProduct[]>(`/tasks/${taskId}/products`)
}
/**
* 添加商品ID
*/
export const addTaskProduct = (taskId: number, data: { productId: string; productName?: string; remark?: string }) => {
return request.post<TaskProduct>(`/tasks/${taskId}/products`, data)
}
/**
* 批量添加商品ID
*/
export const addTaskProductsBatch = (taskId: number, productIds: string[]) => {
return request.post<number>(`/tasks/${taskId}/products/batch`, { productIds })
}
/**
* 更新商品ID
*/
export const updateTaskProduct = (taskId: number, id: number, data: { productId?: string; productName?: string; remark?: string }) => {
return request.put<TaskProduct>(`/tasks/${taskId}/products/${id}`, data)
}
/**
* 删除商品ID
*/
export const deleteTaskProduct = (taskId: number, id: number) => {
return request.delete<void>(`/tasks/${taskId}/products/${id}`)
}
/**
* 获取商品ID数量
*/
export const getTaskProductCount = (taskId: number) => {
return request.get<number>(`/tasks/${taskId}/products/count`)
}
/**
* 确认商品ID填写完成
*/
export const confirmTaskProductFilled = (taskId: number) => {
return request.post<void>(`/tasks/${taskId}/products/confirm`)
}
// ==================== 任务撤回 ====================
/**
* 撤回任务(用于编辑后重新发布)
* 只有任务发起人可以撤回,且任务必须未被抢单
*/
export const withdrawTask = (taskId: number) => {
return request.post<any>(`/tasks/${taskId}/withdraw`)
}
// ==================== 管理员任务管理 ====================
/**
* 根据任务编号删除任务(仅管理员)
*/
export const deleteTaskByTaskNo = (taskNo: string) => {
return request.delete<any>(`/tasks/by-task-no/${taskNo}`)
}
// ==================== 导出功能 ====================
/**
* 导出任务大厅数据(仅部门负责人和管理员)
*/
export interface ExportTaskHallParams {
status?: string
month?: string
publisherDeptId?: number
receiverDeptId?: number
brandId?: number
categoryId?: number
platformId?: number
}
export const exportTaskHall = async (params: ExportTaskHallParams = {}) => {
const queryParams = new URLSearchParams()
if (params.status) queryParams.append('status', params.status)
if (params.month) queryParams.append('month', params.month)
if (params.publisherDeptId) queryParams.append('publisherDeptId', params.publisherDeptId.toString())
if (params.receiverDeptId) queryParams.append('receiverDeptId', params.receiverDeptId.toString())
if (params.brandId) queryParams.append('brandId', params.brandId.toString())
if (params.categoryId) queryParams.append('categoryId', params.categoryId.toString())
if (params.platformId) queryParams.append('platformId', params.platformId.toString())
const url = `/export/task-hall${queryParams.toString() ? '?' + queryParams.toString() : ''}`
// 使用 fetch 直接下载文件
const token = localStorage.getItem('token')
const response = await fetch(`/api${url}`, {
method: 'GET',
headers: {
'Authorization': token ? `Bearer ${token}` : ''
}
})
if (!response.ok) {
const errorText = await response.text()
try {
const errorJson = JSON.parse(errorText)
throw new Error(errorJson.message || '导出失败')
} catch {
throw new Error('导出失败')
}
}
// 获取文件名
const contentDisposition = response.headers.get('Content-Disposition')
let fileName = '任务大厅数据.xlsx'
if (contentDisposition) {
const fileNameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/)
if (fileNameMatch && fileNameMatch[1]) {
fileName = decodeURIComponent(fileNameMatch[1].replace(/['"]/g, ''))
}
}
// 下载文件
const blob = await response.blob()
const downloadUrl = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = downloadUrl
link.download = fileName
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
window.URL.revokeObjectURL(downloadUrl)
}
// ==================== 一级需求部门任务接口 ====================
// 审核一级需求部门任务
export const approvePrimaryTask = (taskId: number, completerId: number, comment?: string) => {
return request.post(`/tasks/${taskId}/approve-primary`, null, {
params: { completerId, comment }
})
}
// 驳回一级需求部门任务
export const rejectPrimaryTask = (taskId: number, reason: string) => {
return request.post(`/tasks/${taskId}/reject-primary`, null, {
params: { reason }
})
}
// 完善任务明细
export interface TaskItemDTO {
taskTypeId: number
quantity: number
receiverId?: number
selectedDeptId?: number
}
export const completeTaskDetail = (taskId: number, taskItems: TaskItemDTO[]) => {
return request.post(`/tasks/${taskId}/complete-detail`, taskItems)
}
// ==================== 任务流程查询接口 ====================
// 任务流程状态响应类型
export interface TaskFlowStatusVO {
task: {
id: number
taskNo: string
title: string
score: number
isPrimaryTask: boolean
isPipeline: boolean
status: string
statusName: string
createTime: string
}
currentNode: {
status: string
statusName: string
description: string
waitingFor?: {
userId: number
userName: string
deptName: string
role: string
roleName: string
}
}
flowTimeline: Array<{
nodeName: string
status: 'completed' | 'pending' | 'waiting'
operatorName?: string
operatorDept?: string
time?: string
comment?: string
}>
relatedUsers: {
publisher?: { userId: number; name: string; dept: string }
detailCompleter?: { userId: number; name: string; dept: string }
receiver?: { userId: number; name: string; dept: string }
currentApprover?: { userId: number; name: string; dept: string }
}
}
// 查询任务流程状态
export const getTaskFlowStatus = (params: { taskNo?: string; keyword?: string }) => {
return request.get<TaskFlowStatusVO>('/tasks/flow-status', { params })
}