448 lines
12 KiB
TypeScript
448 lines
12 KiB
TypeScript
/**
|
||
* 审批流服务 - 与后端审批API交互
|
||
*/
|
||
|
||
import { authFetch, baseUrl } from './authHelper'
|
||
import type { AdminRole } from '../auth/roles'
|
||
|
||
export interface ApprovalFlow {
|
||
id: number
|
||
flowCode: string
|
||
flowName: string
|
||
moduleCode: string
|
||
description?: string
|
||
status: number
|
||
createdAt: string
|
||
updatedAt?: string
|
||
}
|
||
|
||
export interface ApprovalRecord {
|
||
id: number
|
||
flowId: number
|
||
bizType: string
|
||
bizId: string
|
||
title: string
|
||
applicantId: number
|
||
applicantName: string
|
||
currentStatus: string
|
||
currentNodeId: number
|
||
currentNodeName: string
|
||
applyReason?: string
|
||
applyAttachments?: string
|
||
createdAt: string
|
||
updatedAt?: string
|
||
}
|
||
|
||
export interface ApprovalNode {
|
||
id: number
|
||
flowId: number
|
||
nodeName: string
|
||
nodeType: 'start' | 'approver' | 'condition' | 'cc' | 'end'
|
||
approverType: 'user' | 'role' | 'department_leader'
|
||
approverIds?: string
|
||
approverRoles?: string
|
||
condition?: string
|
||
timeout: number
|
||
action: string
|
||
sortOrder: number
|
||
}
|
||
|
||
export interface ApprovalHistory {
|
||
id: number
|
||
recordId: number
|
||
nodeId: number
|
||
nodeName: string
|
||
action: 'submit' | 'approve' | 'reject' | 'transfer' | 'callback'
|
||
operatorId: number
|
||
operatorName: string
|
||
comment?: string
|
||
attachments?: string
|
||
createdAt: string
|
||
}
|
||
|
||
export interface CreateFlowRequest {
|
||
flowCode: string
|
||
flowName: string
|
||
moduleCode: string
|
||
description?: string
|
||
}
|
||
|
||
export interface UpdateFlowRequest extends Partial<CreateFlowRequest> {
|
||
id: number
|
||
status?: number
|
||
}
|
||
|
||
export interface ApiResponse<T> {
|
||
code: number
|
||
data: T
|
||
message?: string
|
||
}
|
||
|
||
/**
|
||
* 审批流服务类
|
||
*/
|
||
class ApprovalService {
|
||
private baseUrl = baseUrl || '/api/v1'
|
||
|
||
/**
|
||
* 获取所有审批流
|
||
*/
|
||
async getFlows(): Promise<ApprovalFlow[]> {
|
||
const response = await authFetch(`${this.baseUrl}/approval/flows`, {
|
||
credentials: undefined
|
||
})
|
||
const result = await response.json() as ApiResponse<ApprovalFlow[]>
|
||
if (result.code !== 200) {
|
||
throw new Error(result.message || '获取审批流失败')
|
||
}
|
||
return result.data
|
||
}
|
||
|
||
/**
|
||
* 获取审批流详情
|
||
*/
|
||
async getFlowById(id: number): Promise<ApprovalFlow | null> {
|
||
const response = await authFetch(`${this.baseUrl}/approval/flows/${id}`, {
|
||
credentials: undefined
|
||
})
|
||
const result = await response.json() as ApiResponse<ApprovalFlow>
|
||
if (result.code !== 200) {
|
||
return null
|
||
}
|
||
return result.data
|
||
}
|
||
|
||
/**
|
||
* 创建审批流
|
||
*/
|
||
async createFlow(data: CreateFlowRequest): Promise<number> {
|
||
const response = await authFetch(`${this.baseUrl}/approval/flows`, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
credentials: undefined,
|
||
body: JSON.stringify(data)
|
||
})
|
||
const result = await response.json() as ApiResponse<number>
|
||
if (result.code !== 200) {
|
||
throw new Error(result.message || '创建审批流失败')
|
||
}
|
||
return result.data
|
||
}
|
||
|
||
/**
|
||
* 更新审批流
|
||
*/
|
||
async updateFlow(data: UpdateFlowRequest): Promise<void> {
|
||
const response = await authFetch(`${this.baseUrl}/approval/flows/${data.id}`, {
|
||
method: 'PUT',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
credentials: undefined,
|
||
body: JSON.stringify(data)
|
||
})
|
||
const result = await response.json() as ApiResponse<void>
|
||
if (result.code !== 200) {
|
||
throw new Error(result.message || '更新审批流失败')
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 删除审批流
|
||
*/
|
||
async deleteFlow(id: number): Promise<void> {
|
||
const response = await authFetch(`${this.baseUrl}/approval/flows/${id}`, {
|
||
method: 'DELETE',
|
||
credentials: undefined
|
||
})
|
||
const result = await response.json() as ApiResponse<void>
|
||
if (result.code !== 200) {
|
||
throw new Error(result.message || '删除审批流失败')
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取待审批列表
|
||
*/
|
||
async getPendingApprovals(): Promise<ApprovalRecord[]> {
|
||
const response = await authFetch(`${this.baseUrl}/approval/pending`, {
|
||
credentials: undefined
|
||
})
|
||
const result = await response.json() as ApiResponse<ApprovalRecord[]>
|
||
if (result.code !== 200) {
|
||
throw new Error(result.message || '获取待审批列表失败')
|
||
}
|
||
return result.data
|
||
}
|
||
|
||
/**
|
||
* 获取已审批列表
|
||
*/
|
||
async getApprovedList(): Promise<ApprovalRecord[]> {
|
||
const response = await authFetch(`${this.baseUrl}/approval/processed`, {
|
||
credentials: undefined
|
||
})
|
||
const result = await response.json() as ApiResponse<ApprovalRecord[]>
|
||
if (result.code !== 200) {
|
||
throw new Error(result.message || '获取已审批列表失败')
|
||
}
|
||
return result.data
|
||
}
|
||
|
||
/**
|
||
* 获取我发起的审批
|
||
*/
|
||
async getMyApplications(): Promise<ApprovalRecord[]> {
|
||
const response = await authFetch(`${this.baseUrl}/approval/my`, {
|
||
credentials: undefined
|
||
})
|
||
const result = await response.json() as ApiResponse<ApprovalRecord[]>
|
||
if (result.code !== 200) {
|
||
throw new Error(result.message || '获取我发起的审批失败')
|
||
}
|
||
return result.data
|
||
}
|
||
|
||
/**
|
||
* 审批操作(统一入口)
|
||
* @deprecated 请使用 approveRecord, rejectRecord, transferRecord 三个独立方法
|
||
*/
|
||
async approve(data: {
|
||
recordId: number
|
||
action: 'APPROVE' | 'REJECT' | 'TRANSFER'
|
||
operatorId: number
|
||
comment?: string
|
||
transferTo?: number // TRANSFER时必填
|
||
}): Promise<void> {
|
||
// 根据action调用对应的独立接口
|
||
switch (data.action) {
|
||
case 'APPROVE':
|
||
return this.approveRecord({ recordId: data.recordId, comment: data.comment })
|
||
case 'REJECT':
|
||
return this.rejectRecord({ recordId: data.recordId, comment: data.comment })
|
||
case 'TRANSFER':
|
||
if (data.transferTo == null) {
|
||
throw new Error('TRANSFER操作需要提供transferTo参数')
|
||
}
|
||
return this.transferRecord({ recordId: data.recordId, transferTo: data.transferTo, comment: data.comment })
|
||
default:
|
||
throw new Error(`Unknown action: ${data.action}`)
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 审批通过
|
||
*/
|
||
async approveRecord(data: {
|
||
recordId: number
|
||
comment?: string
|
||
}): Promise<void> {
|
||
const response = await authFetch(`${this.baseUrl}/approval/approve`, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
credentials: undefined,
|
||
body: JSON.stringify({
|
||
recordId: data.recordId,
|
||
comment: data.comment || ''
|
||
})
|
||
})
|
||
const result = await response.json() as ApiResponse<void>
|
||
if (result.code !== 200) {
|
||
throw new Error(result.message || '审批通过失败')
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 审批拒绝
|
||
*/
|
||
async rejectRecord(data: {
|
||
recordId: number
|
||
comment?: string
|
||
}): Promise<void> {
|
||
const response = await authFetch(`${this.baseUrl}/approval/reject`, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
credentials: undefined,
|
||
body: JSON.stringify({
|
||
recordId: data.recordId,
|
||
comment: data.comment || ''
|
||
})
|
||
})
|
||
const result = await response.json() as ApiResponse<void>
|
||
if (result.code !== 200) {
|
||
throw new Error(result.message || '审批拒绝失败')
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 审批转交
|
||
*/
|
||
async transferRecord(data: {
|
||
recordId: number
|
||
transferTo: number
|
||
comment?: string
|
||
}): Promise<void> {
|
||
const response = await authFetch(`${this.baseUrl}/approval/transfer`, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
credentials: undefined,
|
||
body: JSON.stringify({
|
||
recordId: data.recordId,
|
||
transferTo: data.transferTo,
|
||
comment: data.comment || ''
|
||
})
|
||
})
|
||
const result = await response.json() as ApiResponse<void>
|
||
if (result.code !== 200) {
|
||
throw new Error(result.message || '审批转交失败')
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 审批委托
|
||
*/
|
||
async delegateRecord(data: {
|
||
recordId: number
|
||
delegateTo: number
|
||
reason?: string
|
||
}): Promise<void> {
|
||
const response = await authFetch(`${this.baseUrl}/approval/delegate`, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
credentials: undefined,
|
||
body: JSON.stringify({
|
||
recordId: data.recordId,
|
||
delegateTo: data.delegateTo,
|
||
reason: data.reason || ''
|
||
})
|
||
})
|
||
const result = await response.json() as ApiResponse<void>
|
||
if (result.code !== 200) {
|
||
throw new Error(result.message || '审批委托失败')
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 批量审批操作
|
||
* 使用新批量接口 POST /api/v1/approval/batch (approval.index.batch.ALL)
|
||
* 注意:批量转交使用 POST /api/v1/approval/batch-transfer (approval.index.batch.transfer.ALL)
|
||
*/
|
||
async batchApprove(data: {
|
||
recordIds: number[]
|
||
action: 'APPROVE' | 'REJECT' | 'TRANSFER'
|
||
comment?: string
|
||
}): Promise<{
|
||
total: number
|
||
successCount: number
|
||
failCount: number
|
||
results: Array<{ recordId: number; success: boolean; status: string; message: string }>
|
||
}> {
|
||
// 根据操作类型选择接口:TRANSFER使用批量转交接口,其他使用批量审批接口
|
||
const endpoint = data.action === 'TRANSFER'
|
||
? `${this.baseUrl}/api/v1/approval/batch-transfer`
|
||
: `${this.baseUrl}/api/v1/approval/batch`;
|
||
|
||
const response = await authFetch(endpoint, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
credentials: undefined,
|
||
body: JSON.stringify(data)
|
||
})
|
||
const result = await response.json() as ApiResponse<{
|
||
total: number
|
||
successCount: number
|
||
failCount: number
|
||
results: Array<{ recordId: number; success: boolean; status: string; message: string }>
|
||
}>
|
||
if (result.code !== 200) {
|
||
throw new Error(result.message || '批量审批操作失败')
|
||
}
|
||
return result.data
|
||
}
|
||
|
||
/**
|
||
* 提交审批申请
|
||
*/
|
||
async submitApproval(data: {
|
||
flowId: number
|
||
bizType: string
|
||
bizId: number
|
||
title: string
|
||
applicantId: number
|
||
applyReason: string
|
||
}): Promise<number> {
|
||
const response = await authFetch(`${this.baseUrl}/approval/submit`, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
credentials: undefined,
|
||
body: JSON.stringify(data)
|
||
})
|
||
const result = await response.json() as ApiResponse<{ recordId: number }>
|
||
if (result.code !== 200) {
|
||
throw new Error(result.message || '提交审批失败')
|
||
}
|
||
return result.data.recordId
|
||
}
|
||
|
||
/**
|
||
* 取消审批
|
||
*/
|
||
async cancelApproval(recordId: number, operatorId: number): Promise<void> {
|
||
const response = await authFetch(`${this.baseUrl}/approval/cancel`, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
credentials: undefined,
|
||
body: JSON.stringify({ recordId, operatorId })
|
||
})
|
||
const result = await response.json() as ApiResponse<void>
|
||
if (result.code !== 200) {
|
||
throw new Error(result.message || '取消审批失败')
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取审批记录详情
|
||
*/
|
||
async getRecordById(id: number): Promise<ApprovalRecord | null> {
|
||
const response = await authFetch(`${this.baseUrl}/approval/records/${id}`, {
|
||
credentials: undefined
|
||
})
|
||
const result = await response.json() as ApiResponse<ApprovalRecord>
|
||
if (result.code !== 200) {
|
||
return null
|
||
}
|
||
return result.data
|
||
}
|
||
|
||
/**
|
||
* 获取审批历史
|
||
*/
|
||
async getApprovalHistory(recordId: number): Promise<ApprovalHistory[]> {
|
||
const response = await authFetch(`${this.baseUrl}/approval/records/${recordId}/history`, {
|
||
credentials: undefined
|
||
})
|
||
const result = await response.json() as ApiResponse<ApprovalHistory[]>
|
||
if (result.code !== 200) {
|
||
throw new Error(result.message || '获取审批历史失败')
|
||
}
|
||
return result.data
|
||
}
|
||
|
||
/**
|
||
* 添加审批意见(不改变审批状态)
|
||
*/
|
||
async addComment(recordId: number, comment: string): Promise<void> {
|
||
const response = await authFetch(`${this.baseUrl}/approval/records/${recordId}/comment`, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
credentials: undefined,
|
||
body: JSON.stringify({ comment })
|
||
})
|
||
const result = await response.json() as ApiResponse<void>
|
||
if (result.code !== 200) {
|
||
throw new Error(result.message || '添加审批意见失败')
|
||
}
|
||
}
|
||
}
|
||
|
||
export const approvalService = new ApprovalService()
|
||
export default approvalService
|