feat: migrate app routes and business modules
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
import { createRequestError } from './request-client.js'
|
||||
import { normalizeOptionalResponseText } from './response-normalizers.js'
|
||||
import {
|
||||
assertPlainPayload,
|
||||
normalizeOssIdString,
|
||||
normalizeOptionalText,
|
||||
normalizeResourcePathId
|
||||
} from './request-normalizers.js'
|
||||
|
||||
export const EARNING_WITHDRAWAL_STATUS_LABELS = Object.freeze({
|
||||
PENDING: '等待审核',
|
||||
APPROVED: '审核通过',
|
||||
PAYING: '正在转账',
|
||||
PAID: '已到账',
|
||||
REJECTED: '未通过',
|
||||
FAILED: '转账失败',
|
||||
CANCELLED: '已取消'
|
||||
})
|
||||
|
||||
const earningWithdrawalStatuses = new Set(
|
||||
Object.keys(EARNING_WITHDRAWAL_STATUS_LABELS)
|
||||
)
|
||||
|
||||
const normalizeEarningText = (value, field) =>
|
||||
normalizeOptionalResponseText(value, field, '收益响应', 'EARNING_RESPONSE_INVALID')
|
||||
|
||||
const normalizeMoneyText = (value, label, { nullable = false, allowNegative = false } = {}) => {
|
||||
if (nullable && (value === undefined || value === null || value === '')) return null
|
||||
if (typeof value !== 'string') throw createRequestError(`${label}必须是金额字符串`, 'EARNING_RESPONSE_INVALID')
|
||||
const text = value.trim()
|
||||
const pattern = allowNegative ? /^-?(?:0|[1-9]\d{0,16})(?:\.\d{1,2})?$/ : /^(?:0|[1-9]\d{0,16})(?:\.\d{1,2})?$/
|
||||
if (!pattern.test(text)) throw createRequestError(`${label}格式无效`, 'EARNING_RESPONSE_INVALID')
|
||||
return Number(text).toFixed(2)
|
||||
}
|
||||
|
||||
export const normalizeEarningSummary = (value) => {
|
||||
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
||||
throw createRequestError('收益汇总响应无效', 'EARNING_RESPONSE_INVALID')
|
||||
}
|
||||
if (value.currency !== 'CNY' || typeof value.withdrawalEnabled !== 'boolean') {
|
||||
throw createRequestError('收益汇总缺少稳定字段', 'EARNING_RESPONSE_INVALID')
|
||||
}
|
||||
const rewardRateBps = value.rewardRateBps === undefined || value.rewardRateBps === null
|
||||
? null
|
||||
: value.rewardRateBps
|
||||
if (rewardRateBps !== null && (!Number.isSafeInteger(rewardRateBps) || rewardRateBps < 0 || rewardRateBps > 10000)) {
|
||||
throw createRequestError('收益比例无效', 'EARNING_RESPONSE_INVALID')
|
||||
}
|
||||
return {
|
||||
availableAmount: normalizeMoneyText(value.availableAmount, '可用收益'),
|
||||
frozenAmount: normalizeMoneyText(value.frozenAmount, '冻结收益'),
|
||||
minimumWithdrawal: normalizeMoneyText(value.minimumWithdrawal, '最低提现金额', { nullable: true }),
|
||||
rewardRateBps,
|
||||
currency: value.currency,
|
||||
withdrawalEnabled: value.withdrawalEnabled
|
||||
}
|
||||
}
|
||||
|
||||
export const normalizeEarningLedger = (value) => {
|
||||
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
||||
throw createRequestError('收益明细响应无效', 'EARNING_RESPONSE_INVALID')
|
||||
}
|
||||
if (value.currency !== 'CNY') throw createRequestError('收益币种无效', 'EARNING_RESPONSE_INVALID')
|
||||
return {
|
||||
ledgerId: normalizeResourcePathId(value.ledgerId, '收益明细标识'),
|
||||
entryType: normalizeEarningText(value.entryType, 'entryType'),
|
||||
availableDelta: normalizeMoneyText(value.availableDelta, '可用收益变动', { allowNegative: true }),
|
||||
frozenDelta: normalizeMoneyText(value.frozenDelta, '冻结收益变动', { allowNegative: true }),
|
||||
availableAfter: normalizeMoneyText(value.availableAfter, '变动后可用收益'),
|
||||
frozenAfter: normalizeMoneyText(value.frozenAfter, '变动后冻结收益'),
|
||||
currency: value.currency,
|
||||
remark: normalizeEarningText(value.remark, 'remark'),
|
||||
createTime: normalizeEarningText(value.createTime, 'createTime')
|
||||
}
|
||||
}
|
||||
|
||||
export const normalizeEarningWithdrawal = (value) => {
|
||||
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
||||
throw createRequestError('提现记录响应无效', 'EARNING_RESPONSE_INVALID')
|
||||
}
|
||||
const withdrawalStatus = normalizeEarningText(value.withdrawalStatus, 'withdrawalStatus')
|
||||
if (!earningWithdrawalStatuses.has(withdrawalStatus) || value.currency !== 'CNY') {
|
||||
throw createRequestError('提现记录状态或币种无效', 'EARNING_RESPONSE_INVALID')
|
||||
}
|
||||
return {
|
||||
withdrawalId: normalizeResourcePathId(value.withdrawalId, '提现记录标识'),
|
||||
withdrawalNo: normalizeEarningText(value.withdrawalNo, 'withdrawalNo'),
|
||||
amount: normalizeMoneyText(value.amount, '提现金额'),
|
||||
currency: value.currency,
|
||||
payoutAccountName: normalizeEarningText(value.payoutAccountName, 'payoutAccountName'),
|
||||
withdrawalStatus,
|
||||
auditRemark: normalizeEarningText(value.auditRemark, 'auditRemark'),
|
||||
payoutReference: normalizeEarningText(value.payoutReference, 'payoutReference'),
|
||||
paidAt: normalizeEarningText(value.paidAt, 'paidAt'),
|
||||
failureReason: normalizeEarningText(value.failureReason, 'failureReason'),
|
||||
createTime: normalizeEarningText(value.createTime, 'createTime')
|
||||
}
|
||||
}
|
||||
|
||||
export const normalizeEarningPage = (value, rowNormalizer, label) => {
|
||||
if (!value || typeof value !== 'object' || Array.isArray(value) || !Array.isArray(value.rows) || !Number.isSafeInteger(value.total) || value.total < 0) {
|
||||
throw createRequestError(`${label}分页响应无效`, 'EARNING_RESPONSE_INVALID')
|
||||
}
|
||||
return { rows: value.rows.map(rowNormalizer), total: value.total }
|
||||
}
|
||||
|
||||
export const normalizeEarningPageQuery = ({ pageNum = 1, pageSize = 20 } = {}) => {
|
||||
if (!Number.isSafeInteger(pageNum) || pageNum < 1 || !Number.isSafeInteger(pageSize) || pageSize < 1 || pageSize > 100) {
|
||||
throw new TypeError('收益分页参数无效')
|
||||
}
|
||||
return { pageNum, pageSize }
|
||||
}
|
||||
|
||||
export const normalizeEarningWithdrawalPayload = (payload) => {
|
||||
assertPlainPayload(payload, new Set(['requestId', 'amount', 'payoutQrOssId', 'payoutAccountName']), '提现申请')
|
||||
const requestId = normalizeOptionalText(payload.requestId, 'requestId')
|
||||
const payoutAccountName = normalizeOptionalText(payload.payoutAccountName, 'payoutAccountName')
|
||||
if (!requestId || requestId.length > 64) throw new TypeError('提现请求号无效')
|
||||
if (!payoutAccountName || payoutAccountName.length > 64) throw new TypeError('请填写不超过64个字符的收款人姓名')
|
||||
const amount = normalizeMoneyText(payload.amount, '提现金额')
|
||||
if (Number(amount) <= 0) throw new TypeError('提现金额必须大于0元')
|
||||
const payoutQrOssId = normalizeOssIdString(payload.payoutQrOssId, 'payoutQrOssId')
|
||||
return {
|
||||
requestId,
|
||||
amount: Number(amount),
|
||||
payoutQrOssId,
|
||||
payoutAccountName
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user