This commit is contained in:
zlwu committed 2026-05-24 10:42:11 +08:00
1 parent 2eb1807fe6
commit 93f5801aa9
18 files changed
+3045 -2319

No files matched your search

+149
View File
@@ -0,0 +1,149 @@
/**
* 储物格下拉选项:设施树 DFS(order_num)+ 盒内格位按行/列升序
*/
import { buildTreePathLabelFromFlat } from '@/utils/tree-path'
export type StorageSlotSelectOption = { id: string; name: string }
export function getStorageFacilityOrderNum(item: Record<string, unknown>): number {
const raw =
item?.orderNum ?? item?.order_num ?? item?.sortOrder ?? item?.sort_order ?? 0
const parsed = Number(raw)
return Number.isFinite(parsed) ? parsed : 0
}
export function getStorageSlotOrderNum(slot: Record<string, unknown>): number {
const raw = slot?.orderNum ?? slot?.order_num ?? 0
const parsed = Number(raw)
return Number.isFinite(parsed) ? parsed : 0
}
/** 解析 slotCode「{prefix}{row}-{col}」 */
export function parseStorageSlotCode(
code: string
): { row: number; col: number } | null {
const match = (code || '').trim().match(/^(.*?)(\d+)-(\d+)$/)
if (!match) return null
return { row: parseInt(match[2], 10), col: parseInt(match[3], 10) }
}
/** 盒内格位:order_num → 行 → 列 → 编码 */
export function compareStorageFacilitySlots(
a: Record<string, unknown>,
b: Record<string, unknown>
): number {
const orderDiff = getStorageSlotOrderNum(a) - getStorageSlotOrderNum(b)
if (orderDiff !== 0) return orderDiff
const codeA = String(a.slotCode ?? a.slot_code ?? '')
const codeB = String(b.slotCode ?? b.slot_code ?? '')
const pa = parseStorageSlotCode(codeA)
const pb = parseStorageSlotCode(codeB)
if (pa && pb) {
if (pa.row !== pb.row) return pa.row - pb.row
if (pa.col !== pb.col) return pa.col - pb.col
} else if (pa && !pb) return -1
else if (!pa && pb) return 1
const codeCmp = codeA.localeCompare(codeB, 'zh-Hans-CN', { numeric: true })
if (codeCmp !== 0) return codeCmp
return String(a.id ?? '').localeCompare(String(b.id ?? ''))
}
export function sortStorageFacilitySlots<T extends Record<string, unknown>>(
slots: T[]
): T[] {
return [...slots].sort(compareStorageFacilitySlots)
}
/**
* 按设施树顺序收集叶子节点(罐 → 层 → 盒…),同级按 order_num、名称排序。
*/
export function collectLeafFacilityNodesInTreeOrder(
flatList: Record<string, unknown>[]
): Record<string, unknown>[] {
const map = new Map<string, Record<string, unknown> & { children: unknown[] }>()
const roots: (Record<string, unknown> & { children: unknown[] })[] = []
for (const item of flatList || []) {
const id = String(item?.id ?? '').trim()
if (!id) continue
map.set(id, { ...item, children: [] })
}
for (const item of flatList || []) {
const id = String(item?.id ?? '').trim()
const node = map.get(id)
if (!node) continue
const parentId = String(item?.parentId ?? item?.parent_id ?? '').trim()
if (parentId && parentId !== '0' && map.has(parentId)) {
;(map.get(parentId)!.children as typeof roots).push(node)
} else {
roots.push(node)
}
}
const sortNodes = (nodes: (typeof roots)[number][]) => {
nodes.sort((a, b) => {
const orderDiff = getStorageFacilityOrderNum(a) - getStorageFacilityOrderNum(b)
if (orderDiff !== 0) return orderDiff
return String(a.nodeName ?? '').localeCompare(String(b.nodeName ?? ''), 'zh-Hans-CN')
})
nodes.forEach((node) => {
const ch = node.children
if (Array.isArray(ch) && ch.length) sortNodes(ch as typeof roots)
})
}
sortNodes(roots)
const leaves: Record<string, unknown>[] = []
const walk = (nodes: typeof roots) => {
for (const n of nodes) {
const isLeaf = n.isLeaf === 1 || n.is_leaf === 1
const ch = n.children
if (isLeaf) {
leaves.push(n)
} else if (Array.isArray(ch) && ch.length) {
walk(ch as typeof roots)
}
}
}
walk(roots)
return leaves
}
export function mapSlotsToSelectOptions(
facilityNodeId: string,
facilities: Record<string, unknown>[],
slots: Record<string, unknown>[]
): StorageSlotSelectOption[] {
const nodePath = buildTreePathLabelFromFlat(facilityNodeId, facilities, {
nameKey: 'nodeName',
})
return sortStorageFacilitySlots(slots).map((slot) => {
const id = String(slot.id ?? '').trim()
const code = String(slot.slotCode ?? slot.slot_code ?? '')
const name = nodePath && code ? `${nodePath} / ${code}` : code || nodePath
return { id, name }
})
}
export async function loadStorageSlotSelectOptions(
facilities: Record<string, unknown>[],
fetchStorageSlotList: (params: { facilityNodeId: string }) => Promise<unknown>
): Promise<StorageSlotSelectOption[]> {
const leafNodes = collectLeafFacilityNodesInTreeOrder(facilities)
if (!leafNodes.length) return []
const results = await Promise.allSettled(
leafNodes.map(async (node) => {
const nodeId = String(node.id ?? '').trim()
const res: any = await fetchStorageSlotList({ facilityNodeId: nodeId })
const slots = (res?.list || res || []) as Record<string, unknown>[]
return mapSlotsToSelectOptions(nodeId, facilities, slots)
})
)
const options: StorageSlotSelectOption[] = []
results.forEach((r) => {
if (r.status === 'fulfilled') options.push(...r.value)
})
return options
}