215 lines
6.2 KiB
TypeScript
215 lines
6.2 KiB
TypeScript
import request from '@/utils/http'
|
|
import type { QcTask } from '@/api/qc-task'
|
|
|
|
export type QcInspectionBatch = {
|
|
id: string
|
|
workOrderId?: string
|
|
batchNo: string
|
|
batchName: string
|
|
orderNum?: number
|
|
assigneeUserIds: string[]
|
|
assigneeUserNames?: string
|
|
hasLab?: boolean
|
|
hasThirdParty?: boolean
|
|
labItemIds?: string[]
|
|
thirdPartyItemIds?: string[]
|
|
taskCount?: number
|
|
completedTaskCount?: number
|
|
tasks?: QcTask[]
|
|
}
|
|
|
|
export type QcInspectionBatchConfigureItem = {
|
|
id?: string
|
|
batchName: string
|
|
assigneeUserIds: string[]
|
|
hasLab: boolean
|
|
hasThirdParty: boolean
|
|
labItemIds: string[]
|
|
thirdPartyItemIds: string[]
|
|
}
|
|
|
|
export function fetchQcInspectionBatches(workOrderId: string) {
|
|
return request.get<QcInspectionBatch[]>({
|
|
url: `/web/admin/qc-work-orders/${workOrderId}/inspection-batches`
|
|
})
|
|
}
|
|
|
|
export function fetchQcInspectionBatchesBatch(workOrderIds: string[]) {
|
|
return request.post<Record<string, QcInspectionBatch[]>>({
|
|
url: '/web/admin/qc-work-orders/inspection-batches/batch',
|
|
data: { workOrderIds: workOrderIds.filter(Boolean) }
|
|
})
|
|
}
|
|
|
|
/** 优先使用详情内嵌批次,否则独立 GET */
|
|
export async function loadQcInspectionBatches(
|
|
workOrderId: string,
|
|
embedded?: QcInspectionBatch[] | null
|
|
): Promise<QcInspectionBatch[]> {
|
|
if (embedded?.length) return embedded
|
|
if (!workOrderId) return []
|
|
try {
|
|
return (await fetchQcInspectionBatches(workOrderId)) || []
|
|
} catch {
|
|
return []
|
|
}
|
|
}
|
|
|
|
type QcBatchTaskLike = {
|
|
id?: string
|
|
batchId?: string
|
|
taskStatus?: string
|
|
assigneeUserNames?: string
|
|
}
|
|
|
|
export type QcBatchTaskSection<T extends QcBatchTaskLike = QcBatchTaskLike> = {
|
|
key: string
|
|
batchId: string
|
|
batchNo: string
|
|
batchName: string
|
|
assigneeUserNames: string
|
|
taskCount: number
|
|
completedTaskCount: number
|
|
tasks: T[]
|
|
}
|
|
|
|
export function batchTasksPanelSlot(batchKey: string) {
|
|
return `batch-tasks-${batchKey}`
|
|
}
|
|
|
|
function resolveBatchSectionTasks<T extends QcBatchTaskLike>(
|
|
batch: QcInspectionBatch,
|
|
fallbackTasks?: T[]
|
|
): T[] {
|
|
const enrichedById = new Map<string, T>()
|
|
if (fallbackTasks?.length) {
|
|
for (const t of fallbackTasks) {
|
|
if (t.id) enrichedById.set(t.id, t)
|
|
}
|
|
}
|
|
const rawFromBatch = (batch.tasks || []) as T[]
|
|
if (enrichedById.size && rawFromBatch.length) {
|
|
return rawFromBatch.map((t) => (t.id && enrichedById.get(t.id)) || t)
|
|
}
|
|
if (enrichedById.size && batch.id) {
|
|
return fallbackTasks!.filter((t) => (t.batchId || '').trim() === batch.id)
|
|
}
|
|
return rawFromBatch
|
|
}
|
|
|
|
export function buildBatchSectionsFromBatches<T extends QcBatchTaskLike>(
|
|
batches: QcInspectionBatch[],
|
|
fallbackTasks?: T[]
|
|
): QcBatchTaskSection<T>[] {
|
|
if (batches.length) {
|
|
return batches.map((b) => {
|
|
const tasks = resolveBatchSectionTasks(b, fallbackTasks)
|
|
const completed = tasks.filter((t) => t.taskStatus === 'ywc').length
|
|
return {
|
|
key: b.id || b.batchNo,
|
|
batchId: b.id,
|
|
batchNo: b.batchNo,
|
|
batchName: b.batchName || b.batchNo || '检测批次',
|
|
assigneeUserNames: b.assigneeUserNames || '',
|
|
taskCount: b.taskCount ?? tasks.length,
|
|
completedTaskCount: b.completedTaskCount ?? completed,
|
|
tasks
|
|
}
|
|
})
|
|
}
|
|
if (fallbackTasks?.length) {
|
|
return buildBatchSectionsFromTasks(fallbackTasks)
|
|
}
|
|
return []
|
|
}
|
|
|
|
export function buildBatchSectionsFromTasks<T extends QcBatchTaskLike>(
|
|
tasks: T[]
|
|
): QcBatchTaskSection<T>[] {
|
|
const map = new Map<string, T[]>()
|
|
const order: string[] = []
|
|
for (const t of tasks) {
|
|
const bid = (t.batchId || '').trim() || '__legacy__'
|
|
if (!map.has(bid)) {
|
|
map.set(bid, [])
|
|
order.push(bid)
|
|
}
|
|
map.get(bid)!.push(t)
|
|
}
|
|
return order.map((bid) => {
|
|
const group = map.get(bid)!
|
|
const completed = group.filter((t) => t.taskStatus === 'ywc').length
|
|
return {
|
|
key: bid,
|
|
batchId: bid === '__legacy__' ? '' : bid,
|
|
batchNo: '',
|
|
batchName: bid === '__legacy__' ? '历史任务' : '检测批次',
|
|
assigneeUserNames: group[0]?.assigneeUserNames || '',
|
|
taskCount: group.length,
|
|
completedTaskCount: completed,
|
|
tasks: group
|
|
}
|
|
})
|
|
}
|
|
|
|
export function resolveBatchSections<T extends QcBatchTaskLike>(
|
|
batches: QcInspectionBatch[] | undefined | null,
|
|
tasks: T[] | undefined | null
|
|
): QcBatchTaskSection<T>[] {
|
|
const fromBatches = buildBatchSectionsFromBatches(batches || [], tasks || undefined)
|
|
if (fromBatches.length) return fromBatches
|
|
if (tasks?.length) return buildBatchSectionsFromTasks(tasks)
|
|
return []
|
|
}
|
|
|
|
/** 细胞存储 / 科研捐赠:批次名默认用实验室入库编码 */
|
|
const INBOUND_LAB_CODE_BATCH_SOURCES = new Set(['cell_storage', 'research_donation'])
|
|
|
|
export type ResolveDefaultQcBatchNameOpts = {
|
|
receptionSource?: string | null
|
|
labStorageCode?: string | null
|
|
/** 已占用名称;仅非入库类型做 YYYYMMDD检测 去重时使用 */
|
|
usedNames?: Iterable<string>
|
|
}
|
|
|
|
/**
|
|
* 配置检测弹窗新增批次的默认名称。
|
|
* - 细胞存储 / 科研捐赠:有实验室入库编码则用该编码(多批次相同);无则空串
|
|
* - 其它类型:YYYYMMDD检测,冲突则 -2、-3…
|
|
*/
|
|
export function resolveDefaultQcBatchName(opts: ResolveDefaultQcBatchNameOpts = {}): string {
|
|
const source = String(opts.receptionSource || '').trim()
|
|
if (INBOUND_LAB_CODE_BATCH_SOURCES.has(source)) {
|
|
return String(opts.labStorageCode || '').trim()
|
|
}
|
|
const today = new Date()
|
|
const y = today.getFullYear()
|
|
const m = String(today.getMonth() + 1).padStart(2, '0')
|
|
const d = String(today.getDate()).padStart(2, '0')
|
|
const base = `${y}${m}${d}检测`
|
|
const used = new Set(
|
|
[...(opts.usedNames || [])].map((n) => String(n || '').trim()).filter(Boolean)
|
|
)
|
|
if (!used.has(base)) return base
|
|
let n = 2
|
|
while (used.has(`${base}-${n}`)) n += 1
|
|
return `${base}-${n}`
|
|
}
|
|
|
|
export function createEmptyInspectionBatch(
|
|
defaultAssigneeUserIds?: string[],
|
|
nameOpts?: ResolveDefaultQcBatchNameOpts
|
|
): QcInspectionBatchConfigureItem {
|
|
const assigneeUserIds = (defaultAssigneeUserIds || [])
|
|
.map((id) => String(id || '').trim())
|
|
.filter(Boolean)
|
|
return {
|
|
batchName: resolveDefaultQcBatchName(nameOpts),
|
|
assigneeUserIds,
|
|
hasLab: false,
|
|
hasThirdParty: false,
|
|
labItemIds: [],
|
|
thirdPartyItemIds: []
|
|
}
|
|
}
|