Files
zkxw/web-admin/src/utils/qc-work-order-inbound-sample-cards.ts
T
2026-08-18 14:40:15 +08:00

163 lines
5.7 KiB
TypeScript

import type { QcProtocolSiblingSample, QcWorkOrder } from '@/api/qc-work-order'
import {
compareLabStorageThenCreateTimeDesc,
resolveGroupLabStorageCode,
resolveGroupMaxCreateTime
} from '@/utils/qc-inbound-lab-storage-sort'
import {
groupInboundQcWorkOrders,
resolveInboundProtocolGroupKey,
resolveGateWorkOrderForSampleGroup,
type QcWorkOrderSampleGroupModel
} from '@/utils/qc-work-order-groups'
import { resolveInboundSampleGroupCardTitle } from '@/utils/qc-work-order-card-meta'
export type QcInboundProtocolSiblingLink = {
sampleCode: string
anchorId: string
labStorageCode: string
sampleTypeName: string
}
export type QcInboundSampleListItem = {
group: QcWorkOrderSampleGroupModel
cardAnchorId: string
protocolSiblingLinks: QcInboundProtocolSiblingLink[]
showProtocolPaymentAtGroup: boolean
}
export function buildInboundSampleCardAnchorId(groupKey: string) {
const safe = String(groupKey || 'sample')
.trim()
.replace(/[^a-zA-Z0-9_-]+/g, '_')
return `qc-inbound-sample-${safe}`
}
function sampleTypeNameForGroup(group: QcWorkOrderSampleGroupModel) {
const gate = resolveGateWorkOrderForSampleGroup(group.workOrders)
return (gate?.sampleTypeName || group.workOrders[0]?.sampleTypeName || '').trim()
}
function resolveProtocolSiblingSamplesForGroup(
group: QcWorkOrderSampleGroupModel
): QcProtocolSiblingSample[] {
for (const row of group.workOrders) {
const samples = row.protocolSiblingSamples
if (samples?.length) return samples
}
const gate = resolveGateWorkOrderForSampleGroup(group.workOrders)
return gate?.protocolSiblingSamples || []
}
export function buildProtocolSiblingLinksFromSamples(
group: QcWorkOrderSampleGroupModel,
samples: QcProtocolSiblingSample[]
): QcInboundProtocolSiblingLink[] {
const sorted = [...samples].sort((a, b) => (a.sampleCode || '').localeCompare(b.sampleCode || ''))
return sorted.map((sample) => {
const sampleCode = (sample.sampleCode || '').trim() || group.groupKey
const labStorageCode = (sample.labStorageCode || '').trim()
return {
sampleCode,
anchorId: buildInboundSampleCardAnchorId(sampleCode),
labStorageCode: labStorageCode || '—',
sampleTypeName: (sample.sampleTypeName || '').trim()
}
})
}
function buildLinksFromVisibleGroups(
protocolSampleGroups: QcWorkOrderSampleGroupModel[]
): QcInboundProtocolSiblingLink[] {
const sorted = [...protocolSampleGroups].sort((a, b) =>
(a.sampleCode || '').localeCompare(b.sampleCode || '')
)
return sorted.map((group) => ({
sampleCode: (group.sampleCode || group.groupKey || '').trim(),
anchorId: buildInboundSampleCardAnchorId(group.groupKey),
labStorageCode: resolveInboundSampleGroupCardTitle(group.workOrders),
sampleTypeName: sampleTypeNameForGroup(group)
}))
}
/** 样本组标题栏「同协议样本」胶囊(优先 API enrich,回退当前页多样本互链) */
export function resolveProtocolSiblingLinksForGroup(
group: QcWorkOrderSampleGroupModel
): QcInboundProtocolSiblingLink[] {
const apiSamples = resolveProtocolSiblingSamplesForGroup(group)
if (apiSamples.length > 1) {
return buildProtocolSiblingLinksFromSamples(group, apiSamples)
}
return []
}
/** 入库 Tab:按样本独立卡片,并生成同协议互链与协议费用展示位 */
export function buildInboundSampleListItems(rows: QcWorkOrder[]): QcInboundSampleListItem[] {
const groups = groupInboundQcWorkOrders(rows)
const protocolGroups = new Map<string, QcWorkOrderSampleGroupModel[]>()
for (const group of groups) {
const head = group.workOrders[0]
if (!head) continue
const protocolKey = resolveInboundProtocolGroupKey(head)
const list = protocolGroups.get(protocolKey)
if (list) list.push(group)
else protocolGroups.set(protocolKey, [group])
}
const siblingLinksByGroupKey = new Map<string, QcInboundProtocolSiblingLink[]>()
const protocolPaymentHostGroupKey = new Set<string>()
for (const [, protocolSampleGroups] of protocolGroups) {
const sorted = [...protocolSampleGroups].sort((a, b) =>
(a.sampleCode || '').localeCompare(b.sampleCode || '')
)
let links: QcInboundProtocolSiblingLink[] = []
for (const group of sorted) {
const apiSamples = resolveProtocolSiblingSamplesForGroup(group)
if (apiSamples.length > 1) {
links = buildProtocolSiblingLinksFromSamples(group, apiSamples)
break
}
}
if (links.length <= 1 && sorted.length > 1) {
links = buildLinksFromVisibleGroups(sorted)
}
if (links.length > 1) {
for (const group of sorted) {
siblingLinksByGroupKey.set(group.groupKey, links)
}
}
const paymentHost = sorted.find((group) =>
group.workOrders.some((wo) => wo.receptionSource === 'cell_storage' && !!wo.paymentSummary)
)
if (paymentHost) {
protocolPaymentHostGroupKey.add(paymentHost.groupKey)
}
}
const sortedGroups = [...groups].sort((a, b) =>
compareLabStorageThenCreateTimeDesc(
resolveGroupLabStorageCode(a.workOrders),
resolveGroupMaxCreateTime(a.workOrders),
resolveGroupLabStorageCode(b.workOrders),
resolveGroupMaxCreateTime(b.workOrders)
)
)
return sortedGroups.map((group) => ({
group,
cardAnchorId: buildInboundSampleCardAnchorId(group.groupKey),
protocolSiblingLinks: siblingLinksByGroupKey.get(group.groupKey) || [],
showProtocolPaymentAtGroup: protocolPaymentHostGroupKey.has(group.groupKey)
}))
}
export function scrollToInboundSampleCard(anchorId: string) {
const el = document.getElementById(anchorId)
if (!el) return
el.scrollIntoView({ behavior: 'smooth', block: 'start' })
el.classList.add('qc-sample-row--highlight')
window.setTimeout(() => el.classList.remove('qc-sample-row--highlight'), 1600)
}