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' items: Array<{ taskTypeId: number quantity: number sortOrder: number receiverId?: 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?: 'latest' | 'score' | 'deadline' | 'hot' page?: number pageSize?: number } export interface MyTasksParams { role?: 'publisher' | 'receiver' | 'detail_completer' status?: string page?: number pageSize?: number keyword?: string } /** * 创建任务 */ export const createTask = (data: Task) => { return request.post('/tasks', data) } /** * 获取任务列表 */ export const getTaskList = (params: TaskListParams) => { return request.get('/tasks', { params }) } /** * 获取任务详情 */ export const getTaskById = (id: number) => { return request.get(`/tasks/${id}`) } /** * 更新任务 */ export const updateTask = (id: number, data: Partial) => { return request.put(`/tasks/${id}`, data) } /** * 抢单 */ export const grabTask = (id: number) => { return request.post(`/tasks/${id}/grab`) } /** * 提交任务 */ export const submitTask = (id: number, deliveryPath: string) => { return request.post(`/tasks/${id}/submit`, null, { params: { deliveryPath } }) } /** * 审核任务 */ export const reviewTask = ( id: number, approved: boolean, comment?: string, rating?: number ) => { return request.post(`/tasks/${id}/review`, null, { params: { approved, comment, rating } }) } /** * 取消任务 */ export const cancelTask = (id: number, reason: string) => { return request.post(`/tasks/${id}/cancel`, null, { params: { reason } }) } /** * 评分任务(需求方对已完成任务进行评分) */ export const rateTask = (id: number, rating: number, comment?: string) => { return request.post(`/tasks/${id}/rate`, null, { params: { rating, comment } }) } /** * 获取任务大厅 */ export const getTaskHall = (params: TaskHallParams) => { return request.get('/tasks/hall', { params }) } /** * 获取已完成任务列表(根据角色权限) */ export const getCompletedTasks = (params: any) => { return request.get('/tasks/completed', { params }) } /** * 获取我的进行中任务列表 */ export const getMyInProgressTasks = () => { return request.get('/tasks/my-in-progress') } /** * 批量更新任务进度 */ export const batchUpdateProgress = (updates: Array<{taskId: number, progress: number, remark?: string}>) => { return request.post('/tasks/batch-update-progress', { updates }) } /** * 获取我的任务 */ export const getMyTasks = (params: MyTasksParams) => { return request.get('/tasks/my', { params }) } /** * 提交任务审核 */ export const submitTaskAudit = (id: number) => { return request.post(`/tasks/${id}/submit-audit`) } /** * 审核任务(部门负责人) */ export const auditTask = (data: TaskAuditRequest) => { return request.post('/tasks/audit', data) } /** * 强制指派任务 */ export const assignTask = (taskId: number, assigneeId: number, comment?: string) => { return request.post('/tasks/assign', { taskId, assigneeId, assignType: 'force', comment }) } /** * 获取负责人任务列表(需求部门负责人) */ export const getLeaderTaskList = (params: { auditStatus?: string; page?: number; pageSize?: number }) => { return request.get('/tasks/leader/demand', { params }) } /** * 获取接单部门负责人视图 */ export const getLeaderReceivingTaskList = (params: { status?: string; page?: number; pageSize?: number }) => { return request.get('/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('/tasks/dashboard/stats', { params }) } /** * 通用获取任务列表(支持状态筛选) */ export const getTasks = (params: any) => { return request.get('/tasks', { params }) } /** * 更新任务进度 */ export const updateTaskProgress = (taskId: number, progress: number) => { return request.post(`/tasks/${taskId}/progress`, { progress }) } /** * 完结任务(提交审核) */ export const completeTask = (taskId: number, data: { deliveryPath: string }) => { return request.post(`/tasks/${taskId}/complete`, data) } /** * 审核通过任务 */ export const approveTask = (taskId: number) => { return request.post(`/tasks/${taskId}/approve`) } /** * 驳回任务 */ export const rejectTask = (taskId: number, data: { reason: string }) => { return request.post(`/tasks/${taskId}/reject`, data) } // ==================== 流水线任务相关 API ==================== /** * 创建流水线任务 */ export const createPipelineTask = (data: PipelineTaskRequest) => { return request.post('/tasks/pipeline', data) } /** * 获取可接单的子任务列表 */ export const getAvailableTaskItems = (params: { page?: number pageSize?: number taskTypeId?: number keyword?: string }) => { return request.get('/tasks/items/available', { params }) } /** * 获取进行中的子任务列表 */ export const getInProgressTaskItems = (params: { page?: number pageSize?: number keyword?: string deptId?: number // 部门负责人切换视角时使用 }) => { return request.get('/tasks/items/in-progress', { params }) } /** * 获取已完成的子任务列表 */ export const getCompletedTaskItems = (params: { page?: number pageSize?: number keyword?: string deptId?: number // 部门负责人切换视角时使用 }) => { return request.get('/tasks/items/completed', { params }) } /** * 根据主任务ID获取所有子任务 */ export const getTaskItemsByTaskId = (taskId: number) => { return request.get(`/tasks/items/task/${taskId}`) } /** * 获取子任务详情 */ export const getTaskItemById = (itemId: number) => { return request.get(`/tasks/items/${itemId}`) } /** * 抢单子任务 */ export const grabTaskItem = (itemId: number) => { return request.post(`/tasks/items/${itemId}/grab`) } /** * 更新子任务进度 */ export const updateTaskItemProgress = (itemId: number, progress: number) => { return request.post(`/tasks/items/${itemId}/progress`, null, { params: { progress } }) } /** * 完结子任务 */ export const completeTaskItem = (itemId: number, data: { deliveryPath: string }) => { return request.post(`/tasks/items/${itemId}/complete`, data) } /** * 驳回子任务 */ export const rejectTaskItem = (itemId: number, data: { reason: string }) => { return request.post(`/tasks/items/${itemId}/reject`, data) } /** * 获取主任务进度统计 */ export const getTaskItemsProgress = (taskId: number) => { return request.get(`/tasks/items/task/${taskId}/progress`) } /** * 审核子任务组 */ export const approveTaskItemGroup = (data: { taskId: number groupNo: number assignedReceiverId?: number }) => { return request.post('/tasks/items/groups/approve', data) } /** * 获取待审核的子任务组列表 */ export const getPendingApprovalGroups = (deptId?: number) => { return request.get('/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('/tasks/pending-approval') } /** * 获取所有待审核任务(处于审批流程中的任务) */ export const getAllPendingApprovalTasks = (params?: { taskTypeId?: number; page?: number; pageSize?: number }) => { return request.get('/tasks/pending-approval-all', { params }) } /** * 需求部门负责人审核通过 */ export const approveDemandLevel = (taskId: number, data: TaskApprovalDTO) => { return request.post(`/tasks/${taskId}/approve-demand`, data) } /** * 需求部门负责人驳回 */ export const rejectByDemandLeader = (taskId: number, reason: string) => { return request.post(`/tasks/${taskId}/reject-demand`, { reason }) } /** * 接单部门负责人审核通过 */ export const approveReceivingLevel = (taskId: number, data: TaskApprovalDTO) => { return request.post(`/tasks/${taskId}/approve-receiving`, data) } /** * 接单部门负责人驳回 */ export const rejectByReceivingLeader = (taskId: number, reason: string) => { return request.post(`/tasks/${taskId}/reject-receiving`, { reason }) } // ==================== 子任务组审核相关 ==================== /** * 子任务组信息 */ export interface TaskGroup { groupId: number mainTaskId: number mainTaskTitle: string mainTaskNo: string items: TaskItem[] totalScore: number } /** * 获取待审核的子任务组列表 */ export const getPendingApprovalTaskGroups = () => { return request.get('/tasks/items/groups/pending-approval') } /** * 审核通过子任务组 */ export const approveTaskGroup = (taskId: number, data: { groupNo: number; assignedReceiverId?: number; comment?: string }) => { return request.post('/tasks/items/groups/approve', { taskId, ...data }) } /** * 驳回子任务组 */ export const rejectTaskGroup = (taskId: number, groupNo: number, reason: string) => { return request.post('/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(`/tasks/${taskId}/products`) } /** * 添加商品ID */ export const addTaskProduct = (taskId: number, data: { productId: string; productName?: string; remark?: string }) => { return request.post(`/tasks/${taskId}/products`, data) } /** * 批量添加商品ID */ export const addTaskProductsBatch = (taskId: number, productIds: string[]) => { return request.post(`/tasks/${taskId}/products/batch`, { productIds }) } /** * 更新商品ID */ export const updateTaskProduct = (taskId: number, id: number, data: { productId?: string; productName?: string; remark?: string }) => { return request.put(`/tasks/${taskId}/products/${id}`, data) } /** * 删除商品ID */ export const deleteTaskProduct = (taskId: number, id: number) => { return request.delete(`/tasks/${taskId}/products/${id}`) } /** * 获取商品ID数量 */ export const getTaskProductCount = (taskId: number) => { return request.get(`/tasks/${taskId}/products/count`) } /** * 确认商品ID填写完成 */ export const confirmTaskProductFilled = (taskId: number) => { return request.post(`/tasks/${taskId}/products/confirm`) } // ==================== 任务撤回 ==================== /** * 撤回任务(用于编辑后重新发布) * 只有任务发起人可以撤回,且任务必须未被抢单 */ export const withdrawTask = (taskId: number) => { return request.post(`/tasks/${taskId}/withdraw`) } // ==================== 管理员任务管理 ==================== /** * 根据任务编号删除任务(仅管理员) */ export const deleteTaskByTaskNo = (taskNo: string) => { return request.delete(`/tasks/by-task-no/${taskNo}`) } // ==================== 导出功能 ==================== /** * 导出任务大厅数据(仅部门负责人和管理员) */ export interface ExportTaskHallParams { status?: 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.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) }