Files
zkxw/web-admin/src/utils/oa-confirmation-kit-runtime.ts
T

292 lines
9.4 KiB
TypeScript

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<Record<ConfirmationKitFieldKey, string>>
visible: Record<ConfirmationKitFieldKey, boolean>
confirmationDateField?: string
hireDateField?: string
probationMonthsField?: string
}
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 kitChildren(kit: Record<string, unknown>): Record<string, any>[] {
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<string, unknown>): ConfirmationKitBinding {
const props = (kit.props && typeof kit.props === 'object' ? kit.props : {}) as Record<
string,
any
>
const fields: Partial<Record<ConfirmationKitFieldKey, string>> = {}
const propFieldMap: Record<string, ConfirmationKitFieldKey> = {
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<ConfirmationKitFieldKey, boolean>
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<string, unknown>[] = []
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<string, unknown>
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<string, unknown>,
user: Record<string, unknown> | null | undefined
): Promise<Record<string, unknown>> {
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<string, unknown>
): { data: Record<string, unknown>; 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<string, unknown>,
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<string, unknown>,
confirmationDateField: string
) {
let data = markConfirmationDateManual(formData, confirmationDateField, false)
const linked = applyConfirmationKitDateLinkage(schema, data)
return linked.data
}
export function listManualConfirmationDateFields(schema: unknown, formData: Record<string, unknown>) {
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
)
}