Bei Profil die Dienststelle spackt nicht mehr
Dieser Commit ist enthalten in:
@ -74,6 +74,103 @@ router.get('/hierarchy', authenticate, async (req: AuthRequest, res, next) => {
|
||||
}
|
||||
})
|
||||
|
||||
// Sorting helpers to ensure intuitive order at the top level
|
||||
const isLeitungsstab = (u: any) =>
|
||||
(String(u.code || '').toLowerCase() === 'lstab') || /leitungsstab/i.test(String(u.name || ''))
|
||||
const isZA = (u: any) => {
|
||||
const code = String(u.code || '').toLowerCase()
|
||||
const name = String(u.name || '').toLowerCase()
|
||||
return code === 'za' || code === 'abt za' || /zentralabteilung/i.test(name)
|
||||
}
|
||||
const abteilungNumber = (u: any): number | null => {
|
||||
// Match "Abt 1", "Abt 2", etc.
|
||||
const m = String(u.code || '').match(/^\s*Abt\s+(\d+)\s*$/i)
|
||||
if (m) return parseInt(m[1], 10)
|
||||
// Also try name like "Abteilung 4 - ..."
|
||||
const n = String(u.name || '').match(/^\s*Abteilung\s+(\d+)/i)
|
||||
if (n) return parseInt(n[1], 10)
|
||||
return null
|
||||
}
|
||||
|
||||
const sortRootChildren = (children: any[]) => {
|
||||
children.sort((a, b) => {
|
||||
// 1) Leitungsstab first
|
||||
const aL = isLeitungsstab(a) ? 0 : 1
|
||||
const bL = isLeitungsstab(b) ? 0 : 1
|
||||
if (aL !== bL) return aL - bL
|
||||
|
||||
// 2) Zentralabteilung second
|
||||
const aZA = isZA(a) ? 0 : 1
|
||||
const bZA = isZA(b) ? 0 : 1
|
||||
if (aZA !== bZA) return aZA - bZA
|
||||
|
||||
// 3) Abteilungen numerisch
|
||||
const aNum = abteilungNumber(a)
|
||||
const bNum = abteilungNumber(b)
|
||||
const aIsAbt = aNum !== null
|
||||
const bIsAbt = bNum !== null
|
||||
if (aIsAbt && bIsAbt) return (aNum as number) - (bNum as number)
|
||||
if (aIsAbt) return -1
|
||||
if (bIsAbt) return 1
|
||||
|
||||
// 4) Fallback: orderIndex, then name
|
||||
const oi = (Number(a.orderIndex) || 0) - (Number(b.orderIndex) || 0)
|
||||
if (oi !== 0) return oi
|
||||
return String(a.name || '').localeCompare(String(b.name || ''))
|
||||
})
|
||||
}
|
||||
|
||||
const sortChildrenGeneric = (children: any[]) => {
|
||||
children.sort((a, b) => {
|
||||
// Prefer numeric sort by common prefixes (Dez, SG, TD)
|
||||
const parseKey = (u: any): [number, number, string] => {
|
||||
const code = String(u.code || '')
|
||||
// e.g. "Dez 41" / "Dezernat 41" / "Dez ZA 3"
|
||||
let primary = Number(u.orderIndex) || 0
|
||||
let secondary = 0
|
||||
const dez = code.match(/^\s*(Dez|Dezernat)\s*(?:ZA\s*)?(\d+)/i)
|
||||
if (dez) {
|
||||
primary = 10
|
||||
secondary = parseInt(dez[2], 10)
|
||||
} else {
|
||||
const sg = code.match(/^\s*(SG|TD)\s*(?:ZA\s*)?(\d+)(?:\.(\d+))?/i)
|
||||
if (sg) {
|
||||
primary = 20 + (sg[1].toUpperCase() === 'TD' ? 1 : 0)
|
||||
secondary = parseInt(sg[2], 10) * 100 + (sg[3] ? parseInt(sg[3], 10) : 0)
|
||||
}
|
||||
}
|
||||
return [primary, secondary, String(u.name || '')]
|
||||
}
|
||||
const [ap, as, an] = parseKey(a)
|
||||
const [bp, bs, bn] = parseKey(b)
|
||||
if (ap !== bp) return ap - bp
|
||||
if (as !== bs) return as - bs
|
||||
return an.localeCompare(bn)
|
||||
})
|
||||
}
|
||||
|
||||
// Recursively sort tree
|
||||
const sortTree = (node: any) => {
|
||||
if (!node || !Array.isArray(node.children)) return
|
||||
if (node.type === 'direktion') {
|
||||
sortRootChildren(node.children)
|
||||
} else {
|
||||
sortChildrenGeneric(node.children)
|
||||
}
|
||||
node.children.forEach(sortTree)
|
||||
}
|
||||
|
||||
// Ensure root order as well (Direktion first)
|
||||
rootUnits.sort((a, b) => {
|
||||
const aw = a.type === 'direktion' ? 0 : 1
|
||||
const bw = b.type === 'direktion' ? 0 : 1
|
||||
if (aw !== bw) return aw - bw
|
||||
return String(a.name || '').localeCompare(String(b.name || ''))
|
||||
})
|
||||
|
||||
// Apply sorting from the top
|
||||
rootUnits.forEach(sortTree)
|
||||
|
||||
res.json({ success: true, data: rootUnits })
|
||||
} catch (error) {
|
||||
logger.error('Error building organizational hierarchy:', error)
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren