GuDingZiChan/backend/src/services/hrSyncHelpers.ts

117 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

export type OpenBorrowAssetPreview = {
equipmentId?: number | null
borrowRecordId?: number | null
personId?: number | null
equipmentCode: string
equipmentName: string
}
type HrSyncPersonDisplayNameSource = {
nickname?: string | null
realName?: string | null
}
const safeTrim = (value: unknown) => {
if (value === null || value === undefined) {
return null
}
const text = String(value).trim()
return text ? text : null
}
const getConfiguredSet = (value: string, defaultValue: string) =>
new Set(
((value && value.trim() ? value : defaultValue) || '')
.split(',')
.map((item) => item.trim())
.filter(Boolean)
)
const getInactiveStatusValues = () =>
getConfiguredSet(process.env.HR_SYNC_INACTIVE_STATUS_VALUES || '', '5')
const getInactiveStatusKeywords = () =>
Array.from(
getConfiguredSet(
process.env.HR_SYNC_INACTIVE_STATUS_KEYWORDS || '',
'离职,停用,停职,离岗,辞职,注销,禁用,失效,inactive,disabled,left'
)
).map((keyword) => keyword.toLowerCase())
export const resolveSourcePersonStatus = (employeeStatus: unknown): 'active' | 'inactive' => {
const inactiveStatusValues = getInactiveStatusValues()
const sourceStatus =
employeeStatus === null || employeeStatus === undefined ? null : String(employeeStatus).trim()
if (sourceStatus && inactiveStatusValues.has(sourceStatus)) {
return 'inactive'
}
if (sourceStatus) {
const normalizedStatus = sourceStatus.toLowerCase()
const inactiveStatusKeywords = getInactiveStatusKeywords()
if (inactiveStatusKeywords.some((keyword) => normalizedStatus.includes(keyword))) {
return 'inactive'
}
}
return 'active'
}
export const shouldUseSourceDepartmentBinding = (employeeStatus: unknown) =>
resolveSourcePersonStatus(employeeStatus) === 'active'
export const formatBorrowedAssetSummary = (assets: OpenBorrowAssetPreview[], limit = 3) => {
if (assets.length === 0) {
return '暂无待处理资产'
}
const summary = assets
.slice(0, limit)
.map((asset) => `${asset.equipmentCode} / ${asset.equipmentName}`)
.join('、')
return assets.length > limit ? `${summary} 等 ${assets.length} 项` : summary
}
export const resolveHrSyncPersonDisplayName = (person: HrSyncPersonDisplayNameSource) =>
safeTrim(person.nickname) || safeTrim(person.realName) || '未命名'
const extractBorrowedAssetSummary = (detail: string) => {
const matched = detail.match(/名下(?:待处理)?资产:([^。]+)/)
return matched?.[1]?.trim() || null
}
const extractStructuredBorrowedAssets = (afterSnapshot?: Record<string, any> | null) => {
if (!afterSnapshot || !Array.isArray(afterSnapshot.assets)) {
return []
}
return afterSnapshot.assets
.map((asset: Record<string, any>) => ({
equipmentCode: safeTrim(asset?.equipmentCode) || '',
equipmentName: safeTrim(asset?.equipmentName) || ''
}))
.filter((asset) => asset.equipmentCode && asset.equipmentName)
}
export const buildHrSyncPreviewLine = (change: {
changeType: string
title: string
detail: string
afterSnapshot?: Record<string, any> | null
}) => {
if (change.changeType !== 'person_deactivated' && change.changeType !== 'person_position_changed') {
return change.title
}
const structuredAssets = extractStructuredBorrowedAssets(change.afterSnapshot)
const assetSummary =
structuredAssets.length > 0
? formatBorrowedAssetSummary(structuredAssets)
: extractBorrowedAssetSummary(change.detail)
return assetSummary ? `${change.title}(名下资产:${assetSummary})` : change.title
}