292 lines
9.4 KiB
TypeScript
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
|
|
)
|
|
}
|