| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- /** 分期缴费:期数对齐、应缴日/金额计算(与 ProtocolFormDialog 逻辑一致) */
- export function addMonthsYmd(dateStr: string, months: number): string {
- const compact = String(dateStr || '').replace(/-/g, '')
- if (compact.length !== 8) return ''
- const y = parseInt(compact.slice(0, 4), 10)
- const m = parseInt(compact.slice(4, 6), 10) - 1
- const d = parseInt(compact.slice(6, 8), 10)
- const date = new Date(y, m + months, d)
- const yy = date.getFullYear()
- const mm = String(date.getMonth() + 1).padStart(2, '0')
- const dd = String(date.getDate()).padStart(2, '0')
- return `${yy}${mm}${dd}`
- }
- export function calcInstallmentDueAmounts(
- contractAmount: number | null | undefined,
- count: number
- ): number[] {
- if (contractAmount == null || !count || count < 1) return []
- const totalCents = Math.round(Number(contractAmount) * 100)
- const baseCents = Math.floor(totalCents / count)
- const amounts: number[] = []
- let sumCents = 0
- for (let i = 0; i < count; i++) {
- if (i === count - 1) {
- amounts.push((totalCents - sumCents) / 100)
- } else {
- amounts.push(baseCents / 100)
- sumCents += baseCents
- }
- }
- return amounts
- }
- type PaymentLike = Record<string, unknown> | null | undefined
- type DetailLike = Record<string, any>
- /**
- * 分期模式下按 installmentCount 补齐缺失期次(保留已有明细数据),仅用于编辑表单。
- */
- export function alignFqPaymentDetailsForDisplay(
- payment: PaymentLike,
- details: DetailLike[]
- ): DetailLike[] {
- if (!payment || payment.payMode !== 'fq') return details
- const count = Number(payment.installmentCount)
- if (!count || count < 1) return details
- const rows = [...details]
- const byNo = new Map<number, DetailLike>()
- const unnumbered: DetailLike[] = []
- for (const row of rows) {
- const no = row.installmentNo
- if (no != null && no !== '') {
- byNo.set(Number(no), row)
- } else {
- unnumbered.push(row)
- }
- }
- const needed = new Set(Array.from({ length: count }, (_, i) => i + 1))
- const have = new Set(byNo.keys())
- let missing = false
- for (const n of needed) {
- if (!have.has(n)) {
- missing = true
- break
- }
- }
- if (!missing && rows.length >= count) {
- return sortFqPaymentDetails(rows).slice(0, count)
- }
- const contract = payment.contractAmount != null ? Number(payment.contractAmount) : null
- const amounts = calcInstallmentDueAmounts(contract, count)
- const startDate = String(payment.installmentStartDate || '')
- const interval = Number(payment.installmentIntervalMonths || 0)
- const result: DetailLike[] = []
- for (let i = 0; i < count; i++) {
- const no = i + 1
- if (byNo.has(no)) {
- result.push(byNo.get(no)!)
- continue
- }
- if (i < unnumbered.length) {
- const raw = { ...unnumbered[i], installmentNo: no }
- if (!raw.installmentDueDate && startDate && interval) {
- raw.installmentDueDate = addMonthsYmd(startDate, i * interval)
- }
- result.push(raw)
- continue
- }
- result.push({
- installmentNo: no,
- installmentDueDate: startDate && interval ? addMonthsYmd(startDate, i * interval) : '',
- dueAmount: amounts[i] ?? null,
- payStatus: 'dfj',
- transferType: '',
- transferAmount: null,
- attachments: []
- })
- }
- return result
- }
- export function sortFqPaymentDetails(details: DetailLike[]): DetailLike[] {
- return [...details].sort((a, b) => {
- const na = a.installmentNo != null && a.installmentNo !== '' ? Number(a.installmentNo) : 9999
- const nb = b.installmentNo != null && b.installmentNo !== '' ? Number(b.installmentNo) : 9999
- if (na !== nb) return na - nb
- return Number(a.orderNum || 0) - Number(b.orderNum || 0)
- })
- }
- /** 编辑表单:将缴费明细行数与分期期数对齐(不覆盖已有行) */
- export function syncFqPaymentDetailRowCount(
- payment: {
- payMode: string
- installmentCount: number | null
- contractAmount: number | null
- installmentStartDate: string
- installmentIntervalMonths: number | null
- },
- paymentDetails: DetailLike[]
- ): void {
- if (payment.payMode !== 'fq') return
- const count = Number(payment.installmentCount)
- if (!count || count < 1) return
- const aligned = alignFqPaymentDetailsForDisplay(payment, paymentDetails)
- paymentDetails.splice(0, paymentDetails.length, ...aligned)
- }
|