import { addMonthsYmd } from '@/utils/oa-confirmation-date' import { CONFIRMATION_KIT_FIELD_DEFS, type ConfirmationKitFieldKey } from '@/utils/oa-confirmation-kit-rule' import { resolveCurrentOwnerDept } from '@/utils/oa-owner-field-defaults' export const CONFIRMATION_MANUAL_PREFIX = '__manual_' export type ConfirmationKitBinding = { fields: Partial> visible: Record confirmationDateField?: string hireDateField?: string probationMonthsField?: string } function asRules(schema: unknown): Record[] { 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[], out: Record[]) { 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[], out ) } const props = r.props as Record | undefined if (props && Array.isArray(props.rule)) { walk( props.rule.filter((c) => c && typeof c === 'object') as Record[], out ) } } } function kitChildren(kit: Record): Record[] { const props = (kit.props && typeof kit.props === 'object' ? kit.props : {}) as Record< string, any > if (Array.isArray(kit.children)) return kit.children as any if (Array.isArray(props.rule)) return props.rule as any return [] } function resolveBinding(kit: Record): ConfirmationKitBinding { const props = (kit.props && typeof kit.props === 'object' ? kit.props : {}) as Record< string, any > const fields: Partial> = {} const propFieldMap: Record = { hireDateField: 'hireDate', probationMonthsField: 'probationMonths', confirmationDateField: 'confirmationDate', postField: 'post', jobLevelField: 'jobLevel', nameField: 'name', emailField: 'email', deptField: 'dept', phoneField: 'phone' } for (const [propKey, sem] of Object.entries(propFieldMap)) { const f = props[propKey] if (f) fields[sem] = String(f) } for (const c of kitChildren(kit)) { if (!c?.field) continue const sem = String(c.props?._fc_kit_field || '') as ConfirmationKitFieldKey if (CONFIRMATION_KIT_FIELD_DEFS.some((d) => d.key === sem) && !fields[sem]) { fields[sem] = String(c.field) } } const visible = {} as Record for (const d of CONFIRMATION_KIT_FIELD_DEFS) { const v = props[d.showProp] visible[d.key] = v === undefined || v === null ? true : !!v } return { fields, visible, confirmationDateField: fields.confirmationDate, hireDateField: fields.hireDate, probationMonthsField: fields.probationMonths } } export function listConfirmationKitBindings(schema: unknown): ConfirmationKitBinding[] { const flat: Record[] = [] walk(asRules(schema), flat) const out: ConfirmationKitBinding[] = [] for (const r of flat) { if (String(r.type || '') !== 'confirmationKit') continue out.push(resolveBinding(r)) } return out } function isEmptyValue(raw: unknown): boolean { if (raw == null || raw === '') return true if (Array.isArray(raw)) return raw.length === 0 if (typeof raw === 'object') { const o = raw as Record return !String(o.id || '').trim() } return false } /** 按 show* props 同步子字段 hidden,并去掉隐藏字段的前端必填 */ export function ensureConfirmationKitVisibility(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 || '') === 'confirmationKit') { const binding = resolveBinding(rule) const patchChildren = (list: any[]): any[] => list.map((c) => { if (!c || typeof c !== 'object') return c const child: any = { ...c } const sem = String(child.props?._fc_kit_field || '') as ConfirmationKitFieldKey const show = sem && CONFIRMATION_KIT_FIELD_DEFS.some((d) => d.key === sem) ? binding.visible[sem] !== false : true child.hidden = !show if (!show) { child.$required = false if (child.validate) child.validate = [] } 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 = ensureConfirmationKitVisibility(rule.children) } if (Array.isArray(rule.props?.rule)) { rule.props = { ...rule.props, rule: ensureConfirmationKitVisibility(rule.props.rule) } } return rule }) } export async function applyConfirmationKitDefaults( schema: unknown, formData: Record, user: Record | null | undefined ): Promise> { const data = { ...formData } const kits = listConfirmationKitBindings(schema) if (!kits.length || !user) return data const name = String(user.realName || user.nickName || user.userName || '').trim() const email = String(user.email || '').trim() const phone = String(user.phone || user.phoneNo || '').trim() const hireDate = String(user.hireDate || '').trim() const probationRaw = user.probationMonths const probationMonths = probationRaw === null || probationRaw === undefined || probationRaw === '' ? null : Number(probationRaw) const dept = await resolveCurrentOwnerDept(user as any) for (const kit of kits) { const setIfEmpty = (sem: ConfirmationKitFieldKey, value: unknown) => { const field = kit.fields[sem] if (!field) return if (!isEmptyValue(data[field])) return if (value === null || value === undefined || value === '') return data[field] = value } setIfEmpty('hireDate', hireDate || null) if (probationMonths !== null && Number.isFinite(probationMonths) && probationMonths >= 0) { setIfEmpty('probationMonths', Math.trunc(probationMonths)) } setIfEmpty('name', name || null) setIfEmpty('email', email || null) setIfEmpty('phone', phone || null) if (dept) setIfEmpty('dept', dept) const confField = kit.confirmationDateField const hireField = kit.hireDateField const probField = kit.probationMonthsField if (confField && isEmptyValue(data[confField]) && hireField && probField) { const suggested = addMonthsYmd( String(data[hireField] || ''), Number(data[probField]) ) if (suggested) data[confField] = suggested } } return data } export function applyConfirmationKitDateLinkage( schema: unknown, formData: Record ): { data: Record; changed: boolean } { const data = { ...formData } let changed = false for (const kit of listConfirmationKitBindings(schema)) { const confField = kit.confirmationDateField const hireField = kit.hireDateField const probField = kit.probationMonthsField if (!confField || !hireField || !probField) continue if (data[CONFIRMATION_MANUAL_PREFIX + confField]) continue const suggested = addMonthsYmd(String(data[hireField] || ''), Number(data[probField])) if (suggested == null) continue if (data[confField] !== suggested) { data[confField] = suggested changed = true } } return { data, changed } } export function markConfirmationDateManual( formData: Record, confirmationDateField: string, manual = true ) { const data = { ...formData } const key = CONFIRMATION_MANUAL_PREFIX + confirmationDateField if (manual) data[key] = true else delete data[key] return data } export function clearConfirmationDateManualAndRelink( schema: unknown, formData: Record, confirmationDateField: string ) { let data = markConfirmationDateManual(formData, confirmationDateField, false) const linked = applyConfirmationKitDateLinkage(schema, data) return linked.data } export function listManualConfirmationDateFields(schema: unknown, formData: Record) { return listConfirmationKitBindings(schema) .map((k) => k.confirmationDateField) .filter((f): f is string => !!f && !!formData[CONFIRMATION_MANUAL_PREFIX + f]) } export function isConfirmationDateField(schema: unknown, field: string): boolean { return listConfirmationKitBindings(schema).some((k) => k.confirmationDateField === field) } export function findConfirmationKitByHireOrProbation( schema: unknown, field: string ): ConfirmationKitBinding | null { return ( listConfirmationKitBindings(schema).find( (k) => k.hireDateField === field || k.probationMonthsField === field ) || null ) }