import { assertPlainPayload, normalizeOssIdString } from './request-normalizers.js' import { LINEAGE_PERSON_OPTIONS, LINEAGE_RELATION_TYPE } from './lineage-person-options.js' import { normalizeLineagePersonDate, normalizeLineagePersonIdentity, normalizeLineagePersonText } from './lineage-person-contract.js' const lineageWriteOptionValues = Object.freeze({ bindingMode: new Set(LINEAGE_PERSON_OPTIONS.bindingMode.map(({ value }) => value)), sex: new Set(LINEAGE_PERSON_OPTIONS.sex.map(({ value }) => value)), birthLunar: new Set(LINEAGE_PERSON_OPTIONS.lunar.map(({ value }) => value)), deathLunar: new Set(LINEAGE_PERSON_OPTIONS.lunar.map(({ value }) => value)), personStatus: new Set(LINEAGE_PERSON_OPTIONS.personStatus.map(({ value }) => value)) }) export const normalizeLineageWritePayload = (payload) => { const allowedFields = new Set([ 'bindingMode', 'appUserId', 'personNo', 'name', 'courtesyName', 'aliasName', 'sex', 'generationName', 'fatherId', 'motherId', 'avatarOssId', 'birthDate', 'birthLunar', 'birthPlace', 'zodiacCode', 'currentAddress', 'mobile', 'email', 'educationCode', 'occupation', 'deathDate', 'deathLunar', 'deathAge', 'deathPlace', 'deathExpressionCode', 'burialDate', 'burialPlace', 'biography', 'remark', 'relationName', 'relationVariantCode', 'generation', 'personStatus', 'sortOrder' ]) assertPlainPayload(payload, allowedFields, '人物写入请求') const name = normalizeLineagePersonText(payload.name, '姓名', { required: true }) if (name.length > 20) throw new TypeError('人物姓名长度超出当前页面合同') const bindingMode = normalizeLineagePersonText(payload.bindingMode, '身份认领方式') if (!lineageWriteOptionValues.bindingMode.has(bindingMode)) { throw new TypeError('人物身份认领方式必须是 NONE、SELF 或 SPECIFIED') } const normalizedPayload = { bindingMode, name } if (bindingMode === 'SPECIFIED') { if (payload.appUserId === undefined || payload.appUserId === null || payload.appUserId === '') { throw new TypeError('指定业务用户绑定必须提供业务用户标识') } normalizedPayload.appUserId = normalizeLineagePersonIdentity(payload.appUserId, '绑定用户标识') } else if (payload.appUserId !== undefined && payload.appUserId !== null && payload.appUserId !== '') { throw new TypeError(`${bindingMode} 身份认领不能提供业务用户标识`) } for (const [field, label] of [ ['fatherId', '父亲标识'], ['motherId', '母亲标识'] ]) { if (payload[field] === undefined || payload[field] === null || payload[field] === '') continue normalizedPayload[field] = normalizeLineagePersonIdentity(payload[field], label) } if (payload.avatarOssId !== undefined && payload.avatarOssId !== null && payload.avatarOssId !== '') { normalizedPayload.avatarOssId = normalizeOssIdString(payload.avatarOssId, '头像文件标识') } if (payload.generation !== undefined) { if (!Number.isSafeInteger(payload.generation) || payload.generation < 1) { throw new TypeError('人物世代必须是正安全整数') } normalizedPayload.generation = payload.generation } for (const [field, label, maxLength] of [ ['personNo', '人物编号', null], ['sex', '性别', null], ['generationName', '字辈', 12], ['courtesyName', '表字', 40], ['aliasName', '别号或曾用名', 40], ['birthLunar', '出生农历', null], ['birthPlace', '出生地', 120], ['zodiacCode', '生肖编码', 60], ['currentAddress', '现居地', 120], ['mobile', '联系电话', 30], ['email', '电子邮箱', 254], ['educationCode', '学历分类编码', 60], ['occupation', '职业', 80], ['deathLunar', '逝世农历', null], ['deathPlace', '逝世地', 120], ['deathExpressionCode', '逝世表述编码', 60], ['burialPlace', '安葬地', 120], ['biography', '人物简介', 500], ['remark', '备注', null], ['relationName', '关系显示名称', null], ['relationVariantCode', '关系显示修饰编码', 60], ['personStatus', '人物状态', null] ]) { if (payload[field] === undefined) continue const normalizedText = normalizeLineagePersonText(payload[field], label) if (maxLength && normalizedText.length > maxLength) throw new TypeError(`人物${label}长度超出当前页面合同`) if (normalizedText && lineageWriteOptionValues[field] && !lineageWriteOptionValues[field].has(normalizedText)) { throw new TypeError(`人物${label}字典值无效`) } if (normalizedText) normalizedPayload[field] = normalizedText } if (normalizedPayload.email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(normalizedPayload.email)) { throw new TypeError('人物电子邮箱格式无效') } for (const [field, label] of [ ['birthDate', '出生日期'], ['deathDate', '离世日期'], ['burialDate', '安葬日期'] ]) { if (payload[field] === undefined) continue const normalizedDate = normalizeLineagePersonDate(payload[field], label) if (normalizedDate) normalizedPayload[field] = normalizedDate } if (normalizedPayload.birthDate && normalizedPayload.deathDate && normalizedPayload.deathDate < normalizedPayload.birthDate) { throw new TypeError('人物离世日期不能早于出生日期') } if (normalizedPayload.deathDate && normalizedPayload.burialDate && normalizedPayload.burialDate < normalizedPayload.deathDate) { throw new TypeError('人物安葬日期不能早于离世日期') } if (payload.deathAge !== undefined && payload.deathAge !== null && payload.deathAge !== '') { const deathAge = typeof payload.deathAge === 'number' ? payload.deathAge : Number(payload.deathAge) if (!Number.isSafeInteger(deathAge) || deathAge < 0 || deathAge > 200) { throw new TypeError('人物享年必须是 0 至 200 的整数') } normalizedPayload.deathAge = deathAge } if (payload.sortOrder !== undefined && payload.sortOrder !== null && payload.sortOrder !== '') { const sortOrder = typeof payload.sortOrder === 'number' ? payload.sortOrder : Number(payload.sortOrder) if (!Number.isSafeInteger(sortOrder)) throw new TypeError('人物排序值必须是安全整数') normalizedPayload.sortOrder = sortOrder } return normalizedPayload } export const lineageRelationPath = Object.freeze({ [LINEAGE_RELATION_TYPE.FATHER]: 'parents', [LINEAGE_RELATION_TYPE.MOTHER]: 'parents', [LINEAGE_RELATION_TYPE.SPOUSE]: 'spouses', [LINEAGE_RELATION_TYPE.SIBLING]: 'siblings', [LINEAGE_RELATION_TYPE.SON]: 'children', [LINEAGE_RELATION_TYPE.DAUGHTER]: 'children' })