Files
zkxw/web-admin/src/utils/oa-leave-kit-runtime.ts
T
2026-07-30 17:54:48 +08:00

213 lines
6.5 KiB
TypeScript

import {
calcLeaveHours,
DEFAULT_LEAVE_WORK_HOURS,
type LeaveWorkHours
} from '@/utils/oa-leave-hours'
export const LEAVE_MANUAL_PREFIX = '__manual_'
export type LeaveKitBinding = {
startField: string
endField: string
durationField: string
workHours: LeaveWorkHours
}
function asRules(schema: unknown): Record<string, unknown>[] {
if (Array.isArray(schema)) return schema.filter((r) => r && typeof r === 'object') as any
if (schema && typeof schema === 'object') {
const s = schema as any
const rules = s.rule || s.rules || s.fields
if (Array.isArray(rules)) return rules.filter((r: any) => r && typeof r === 'object')
if (s.type || s.field) return [s]
}
return []
}
function walk(rules: Record<string, unknown>[], out: Record<string, unknown>[]) {
for (const r of rules) {
out.push(r)
const children = r.children
if (Array.isArray(children)) {
walk(
children.filter((c) => c && typeof c === 'object') as Record<string, unknown>[],
out
)
}
const props = r.props as Record<string, unknown> | undefined
if (props && Array.isArray(props.rule)) {
walk(
props.rule.filter((c) => c && typeof c === 'object') as Record<string, unknown>[],
out
)
}
}
}
function resolveFields(kit: Record<string, unknown>): LeaveKitBinding | null {
const props = (kit.props && typeof kit.props === 'object' ? kit.props : {}) as Record<
string,
any
>
let startField = props.startField as string | undefined
let endField = props.endField as string | undefined
let durationField = props.durationField as string | undefined
const children = (
Array.isArray(kit.children)
? kit.children
: Array.isArray(props.rule)
? props.rule
: []
) as Record<string, any>[]
if (!startField || !endField || !durationField) {
const dateFields: string[] = []
let dur: string | undefined
for (const c of children) {
if (!c?.field) continue
const t = String(c.type || '')
if (t === 'datePicker' || t === 'date' || t === 'timePicker' || t === 'time') {
dateFields.push(String(c.field))
} else if ((t === 'inputNumber' || t === 'number') && !dur) {
dur = String(c.field)
}
}
startField = startField || dateFields[0]
endField = endField || dateFields[1]
durationField = durationField || dur
}
if (!startField || !endField || !durationField) return null
return {
startField,
endField,
durationField,
workHours: {
morningStart: String(props.morningStart || DEFAULT_LEAVE_WORK_HOURS.morningStart),
morningEnd: String(props.morningEnd || DEFAULT_LEAVE_WORK_HOURS.morningEnd),
afternoonStart: String(props.afternoonStart || DEFAULT_LEAVE_WORK_HOURS.afternoonStart),
afternoonEnd: String(props.afternoonEnd || DEFAULT_LEAVE_WORK_HOURS.afternoonEnd)
}
}
}
export function listLeaveKitBindings(schema: unknown): LeaveKitBinding[] {
const flat: Record<string, unknown>[] = []
walk(asRules(schema), flat)
const out: LeaveKitBinding[] = []
for (const r of flat) {
if (String(r.type || '') !== 'leaveKit') continue
const b = resolveFields(r)
if (b) out.push(b)
}
return out
}
/** 未手改时写回时长;返回是否有变更 */
export function applyLeaveKitDurationsToFormData(
schema: unknown,
formData: Record<string, unknown>
): { data: Record<string, unknown>; changed: boolean } {
const data = { ...formData }
let changed = false
for (const kit of listLeaveKitBindings(schema)) {
const manualKey = LEAVE_MANUAL_PREFIX + kit.durationField
if (data[manualKey]) continue
const hours = calcLeaveHours(
String(data[kit.startField] || ''),
String(data[kit.endField] || ''),
kit.workHours
)
if (hours == null) continue
if (data[kit.durationField] !== hours) {
data[kit.durationField] = hours
changed = true
}
}
return { data, changed }
}
export function markLeaveDurationManual(
formData: Record<string, unknown>,
durationField: string,
manual = true
) {
const data = { ...formData }
const key = LEAVE_MANUAL_PREFIX + durationField
if (manual) data[key] = true
else delete data[key]
return data
}
export function isLeaveDurationField(schema: unknown, field: string): boolean {
return listLeaveKitBindings(schema).some((k) => k.durationField === field)
}
export function findLeaveKitByStartOrEnd(
schema: unknown,
field: string
): LeaveKitBinding | null {
return (
listLeaveKitBindings(schema).find(
(k) => k.startField === field || k.endField === field
) || null
)
}
/**
* 运行时补齐请假套件子规则:时长数字框默认左对齐(覆盖 Element Plus 默认居中)。
* 对已发布且未带 align 的旧 schema 同样生效。
*/
export function ensureLeaveKitRuleProps(rules: unknown): any[] {
if (!Array.isArray(rules)) return []
return rules.map((raw) => {
if (!raw || typeof raw !== 'object') return raw
const rule: any = { ...(raw as object) }
if (String(rule.type || '') === 'leaveKit') {
const binding = resolveFields(rule)
const patchChildren = (list: any[]): any[] =>
list.map((c) => {
if (!c || typeof c !== 'object') return c
const child: any = { ...c }
const t = String(child.type || '')
const isDuration =
(binding && child.field === binding.durationField) ||
((t === 'inputNumber' || t === 'number') &&
String(child.title || '').includes('时长'))
if (isDuration) {
child.props = { ...(child.props || {}), align: 'left' }
const cls = String(child.class || child.className || '')
if (!cls.includes('oa-leave-duration')) {
child.class = (cls ? cls + ' ' : '') + 'oa-leave-duration'
}
}
if (Array.isArray(child.children)) {
child.children = patchChildren(child.children)
}
return child
})
if (Array.isArray(rule.children)) {
rule.children = patchChildren(rule.children)
}
if (Array.isArray(rule.props?.rule)) {
rule.props = {
...rule.props,
rule: patchChildren(rule.props.rule)
}
}
}
if (Array.isArray(rule.children)) {
rule.children = ensureLeaveKitRuleProps(rule.children)
}
if (Array.isArray(rule.props?.rule)) {
rule.props = {
...rule.props,
rule: ensureLeaveKitRuleProps(rule.props.rule)
}
}
return rule
})
}