feat: 完成前端业务闭环与后端联调
This commit is contained in:
@@ -64,6 +64,55 @@ const normalizeGenealogyCapabilities = (value, code) => {
|
||||
return capabilities
|
||||
}
|
||||
|
||||
export const normalizeGenealogyPermanentDeletionCapability = (value) => {
|
||||
if (!value || typeof value !== 'object' || Array.isArray(value) || typeof value.canDeletePermanently !== 'boolean') {
|
||||
throw createRequestError('家谱永久删除能力响应无效', 'GENEALOGY_DELETION_RESPONSE_INVALID')
|
||||
}
|
||||
if (!Array.isArray(value.disabledReasons) || value.disabledReasons.some((reason) => typeof reason !== 'string')) {
|
||||
throw createRequestError('家谱永久删除阻断原因无效', 'GENEALOGY_DELETION_RESPONSE_INVALID')
|
||||
}
|
||||
const phoneMasked = normalizeResponseText(value.verifiedMobileMasked, 'verifiedMobileMasked', {
|
||||
code: 'GENEALOGY_DELETION_RESPONSE_INVALID',
|
||||
subject: '家谱永久删除能力响应'
|
||||
})
|
||||
if (value.canDeletePermanently && !phoneMasked) {
|
||||
throw createRequestError('家谱永久删除能力缺少验证手机号', 'GENEALOGY_DELETION_RESPONSE_INVALID')
|
||||
}
|
||||
return {
|
||||
canDeletePermanently: value.canDeletePermanently,
|
||||
phoneMasked,
|
||||
disabledReasons: value.disabledReasons.map((reason) => reason.trim()).filter(Boolean)
|
||||
}
|
||||
}
|
||||
|
||||
export const normalizeGenealogyPermanentDeletionPayload = (payload) => {
|
||||
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
|
||||
throw new TypeError('家谱永久删除请求无效')
|
||||
}
|
||||
if (typeof payload.confirmationName !== 'string' || !payload.confirmationName.trim() || payload.confirmationName.trim().length > 24) {
|
||||
throw new TypeError('家谱永久删除确认名称无效')
|
||||
}
|
||||
if (typeof payload.smsCode !== 'string' || !/^\d{4}$/.test(payload.smsCode)) {
|
||||
throw new TypeError('家谱永久删除验证码必须是4位数字')
|
||||
}
|
||||
return { genealogyName: payload.confirmationName.trim(), smsCode: payload.smsCode }
|
||||
}
|
||||
|
||||
export const normalizeGenealogyDeletionTask = (value, expectedGenealogyId) => {
|
||||
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
||||
throw createRequestError('家谱删除任务响应无效', 'GENEALOGY_DELETION_RESPONSE_INVALID')
|
||||
}
|
||||
const taskId = normalizeResponseText(String(value.taskId ?? ''), 'taskId', {
|
||||
code: 'GENEALOGY_DELETION_RESPONSE_INVALID',
|
||||
subject: '家谱删除任务'
|
||||
})
|
||||
const genealogyId = String(value.genealogyId ?? '')
|
||||
if (!/^[1-9]\d*$/.test(taskId) || genealogyId !== expectedGenealogyId) {
|
||||
throw createRequestError('家谱删除任务缺少稳定归属字段', 'GENEALOGY_DELETION_RESPONSE_INVALID')
|
||||
}
|
||||
return { taskId, genealogyId, status: normalizeResponseText(value.status, 'status') }
|
||||
}
|
||||
|
||||
const normalizeMyGenealogyId = (value) => {
|
||||
if (typeof value === 'string' && /^[1-9]\d*$/.test(value)) return value
|
||||
if (typeof value === 'number' && Number.isSafeInteger(value) && value > 0) return String(value)
|
||||
@@ -179,6 +228,8 @@ export const normalizeAppGenealogy = (item) => {
|
||||
return {
|
||||
id: normalizeMyGenealogyId(item.genealogyId),
|
||||
name,
|
||||
firstAncestorName: normalizeGenealogyResponseText(item.firstAncestorName, 'firstAncestorName'),
|
||||
rootPersonId: normalizeOptionalNumericId(item.rootPersonId, '始迁祖人物标识', 'GENEALOGY_RESPONSE_INVALID'),
|
||||
surname: normalizeGenealogyResponseText(item.surname, 'surname'),
|
||||
hall: normalizeGenealogyResponseText(item.ancestralHall, 'ancestralHall'),
|
||||
location:
|
||||
@@ -239,6 +290,15 @@ export const normalizeGenealogyOrderIds = (value) => {
|
||||
return ids
|
||||
}
|
||||
|
||||
export const normalizePublicGenealogyQuery = (query = {}) => {
|
||||
assertPlainPayload(query, new Set(['keyword']), '公开家谱查询')
|
||||
if (query.keyword === undefined || query.keyword === null) return {}
|
||||
if (typeof query.keyword !== 'string') throw new TypeError('公开家谱关键词必须是字符串')
|
||||
const keyword = query.keyword.trim()
|
||||
if (keyword.length > 50) throw new TypeError('公开家谱关键词不能超过50个字符')
|
||||
return keyword ? { keyword } : {}
|
||||
}
|
||||
|
||||
export const normalizePublicGenealogies = (value) => {
|
||||
if (!Array.isArray(value)) {
|
||||
throw createRequestError('公开家谱响应不是列表', 'PUBLIC_GENEALOGY_RESPONSE_INVALID')
|
||||
@@ -257,10 +317,11 @@ export const normalizePublicGenealogies = (value) => {
|
||||
'公开家谱成员数量',
|
||||
'PUBLIC_GENEALOGY_RESPONSE_INVALID'
|
||||
)
|
||||
if (item.canManage !== undefined && typeof item.canManage !== 'boolean') {
|
||||
throw createRequestError('公开家谱管理权限无效', 'PUBLIC_GENEALOGY_RESPONSE_INVALID')
|
||||
}
|
||||
return {
|
||||
if (item.canManage !== undefined && typeof item.canManage !== 'boolean') {
|
||||
throw createRequestError('公开家谱管理权限无效', 'PUBLIC_GENEALOGY_RESPONSE_INVALID')
|
||||
}
|
||||
const memberStatus = normalizeGenealogyResponseText(item.memberStatus, 'memberStatus')
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
surname: normalizeGenealogyResponseText(item.surname, 'surname'),
|
||||
@@ -269,9 +330,11 @@ export const normalizePublicGenealogies = (value) => {
|
||||
normalizeGenealogyResponseText(item.regionName, 'regionName') ||
|
||||
normalizeGenealogyResponseText(item.originPlace, 'originPlace') ||
|
||||
normalizeGenealogyResponseText(item.addressDetail, 'addressDetail'),
|
||||
intro: normalizeGenealogyResponseText(item.intro, 'intro'),
|
||||
memberCount,
|
||||
canManage: item.canManage === true
|
||||
intro: normalizeGenealogyResponseText(item.intro, 'intro'),
|
||||
memberCount,
|
||||
canManage: item.canManage === true,
|
||||
memberStatus,
|
||||
hasMembership: item.canManage === true || Boolean(memberStatus)
|
||||
}
|
||||
})
|
||||
if (new Set(genealogies.map((genealogy) => genealogy.id)).size !== genealogies.length) {
|
||||
@@ -280,17 +343,6 @@ export const normalizePublicGenealogies = (value) => {
|
||||
return genealogies
|
||||
}
|
||||
|
||||
export const projectPreviewPublicGenealogies = (value) =>
|
||||
value.map((item) => ({
|
||||
id: String(item.id),
|
||||
name: String(item.name || '未命名家谱'),
|
||||
surname: String(item.surname || ''),
|
||||
location: String(item.location || ''),
|
||||
intro: String(item.publicDescription || ''),
|
||||
memberCount: Number.isSafeInteger(item.memberCount) ? item.memberCount : 0,
|
||||
canManage: false
|
||||
}))
|
||||
|
||||
const normalizeGenealogyWriteText = (value, field, { required = false } = {}) => {
|
||||
if (value === undefined || value === null) {
|
||||
if (required) throw new TypeError(`创建家谱缺少 ${field}`)
|
||||
@@ -315,16 +367,26 @@ const GENEALOGY_WRITE_FIELDS = new Set([
|
||||
'joinMode'
|
||||
])
|
||||
|
||||
const assertGenealogyWritePayload = (payload, operation) => {
|
||||
assertPlainPayload(payload, GENEALOGY_WRITE_FIELDS, `${operation}家谱请求`)
|
||||
}
|
||||
|
||||
export const normalizeGenealogyCreatePayload = (payload) => {
|
||||
assertGenealogyWritePayload(payload, '创建')
|
||||
assertPlainPayload(
|
||||
payload,
|
||||
new Set([...GENEALOGY_WRITE_FIELDS, 'firstAncestorName', 'requestId', 'ownerIsFirstAncestor']),
|
||||
'创建家谱请求'
|
||||
)
|
||||
const requestId = normalizeGenealogyWriteText(payload.requestId, 'requestId', { required: true })
|
||||
if (requestId.length > 64) throw new TypeError('创建家谱请求号不能超过64个字符')
|
||||
const firstAncestorName = normalizeGenealogyWriteText(payload.firstAncestorName, '始迁祖姓名', { required: true })
|
||||
if (firstAncestorName.length > 30) throw new TypeError('始迁祖姓名不能超过30个字符')
|
||||
if (payload.ownerIsFirstAncestor !== undefined && typeof payload.ownerIsFirstAncestor !== 'boolean') {
|
||||
throw new TypeError('谱主是否为始迁祖必须是布尔值')
|
||||
}
|
||||
const normalizedPayload = {
|
||||
genealogyName: normalizeGenealogyWriteText(payload.genealogyName, '谱名', { required: true }),
|
||||
surname: normalizeGenealogyWriteText(payload.surname, '姓氏', { required: true }),
|
||||
regionCode: normalizeGenealogyWriteText(payload.regionCode, '地区代码', { required: true })
|
||||
regionCode: normalizeGenealogyWriteText(payload.regionCode, '地区代码', { required: true }),
|
||||
firstAncestorName,
|
||||
requestId,
|
||||
ownerIsFirstAncestor: payload.ownerIsFirstAncestor === true
|
||||
}
|
||||
for (const field of ['ancestralHall', 'originPlace', 'addressDetail', 'intro']) {
|
||||
const normalizedText = normalizeGenealogyWriteText(payload[field], field)
|
||||
@@ -347,7 +409,7 @@ export const normalizeGenealogyCreatePayload = (payload) => {
|
||||
}
|
||||
|
||||
export const normalizeGenealogyUpdatePayload = (payload) => {
|
||||
assertGenealogyWritePayload(payload, '更新')
|
||||
assertPlainPayload(payload, GENEALOGY_WRITE_FIELDS, '更新家谱请求')
|
||||
const normalizedPayload = {}
|
||||
for (const field of [
|
||||
'genealogyName',
|
||||
@@ -372,8 +434,11 @@ export const normalizeGenealogyUpdatePayload = (payload) => {
|
||||
if (!isGenealogyJoinMode(joinMode)) throw new TypeError('更新家谱字段 joinMode 无效')
|
||||
normalizedPayload.joinMode = joinMode
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(payload, 'coverOssId') && payload.coverOssId !== null && payload.coverOssId !== '') {
|
||||
normalizedPayload.coverOssId = normalizeOssIdString(payload.coverOssId, '更新家谱字段 coverOssId')
|
||||
if (Object.prototype.hasOwnProperty.call(payload, 'coverOssId')) {
|
||||
if (payload.coverOssId === null) normalizedPayload.coverOssId = null
|
||||
else if (payload.coverOssId !== '') {
|
||||
normalizedPayload.coverOssId = normalizeOssIdString(payload.coverOssId, '更新家谱字段 coverOssId')
|
||||
}
|
||||
}
|
||||
if (!Object.keys(normalizedPayload).length) throw new TypeError('请至少填写一项需要更新的家谱信息')
|
||||
return normalizedPayload
|
||||
|
||||
Reference in New Issue
Block a user