import { useCallback, useMemo, useState } from 'react' import Taro, { useDidShow, useRouter } from '@tarojs/taro' import { Text, View } from '@tarojs/components' import { Button, ConfigProvider, Empty, Loading } from '@nutui/nutui-react-taro' import dayjs from 'dayjs' import { getCreditMpCustomer, updateCreditMpCustomer } from '@/api/credit/creditMpCustomer' import type { CreditMpCustomer } from '@/api/credit/creditMpCustomer/model' const safeParseJSON = (v: any): T | null => { try { if (!v) return null if (typeof v === 'object') return v as T if (typeof v === 'string') return JSON.parse(v) as T return null } catch (_e) { return null } } type PaymentRecord = { id: string amount: number principal: number interest: number paymentTime: string status: 'pending' | 'completed' } type ExpectedPayment = { id: string amount: number expectedDate: string createdAt: string } type PaymentStats = { totalAmount: number totalPrincipal: number totalInterest: number paidPrincipal: number paidInterest: number unpaidPrincipal: number unpaidInterest: number } const makeId = () => `${Date.now()}-${Math.random().toString(16).slice(2)}` const parsePaymentRecords = (raw?: string): PaymentRecord[] => { const parsed = safeParseJSON(raw) if (!Array.isArray(parsed)) return [] return parsed.map(item => ({ id: makeId(), amount: Number(item?.amount || 0), principal: Number(item?.principal || 0), interest: Number(item?.interest || 0), paymentTime: String(item?.paymentTime || '').trim(), status: item?.status || 'completed' })) } const parseExpectedPayments = (raw?: string): ExpectedPayment[] => { const parsed = safeParseJSON(raw) if (!Array.isArray(parsed)) return [] return parsed.map(item => ({ id: makeId(), amount: Number(item?.amount || 0), expectedDate: String(item?.expectedDate || '').trim(), createdAt: String(item?.createdAt || dayjs().format('YYYY-MM-DD HH:mm:ss')) })) } export default function CreditMpCustomerFollowStep6Page() { const router = useRouter() const customerId = useMemo(() => { const id = Number((router?.params as any)?.id) return Number.isFinite(id) && id > 0 ? id : undefined }, [router?.params]) const [loading, setLoading] = useState(false) const [error, setError] = useState(null) const [row, setRow] = useState(null) const [paymentRecords, setPaymentRecords] = useState([]) const [expectedPayments, setExpectedPayments] = useState([]) const [paymentStats, setPaymentStats] = useState({ totalAmount: 0, totalPrincipal: 0, totalInterest: 0, paidPrincipal: 0, paidInterest: 0, unpaidPrincipal: 0, unpaidInterest: 0 }) const reload = useCallback(async () => { setError(null) setLoading(true) try { if (!customerId) throw new Error('缺少客户ID') const res = await getCreditMpCustomer(customerId) const next = (res || null) as CreditMpCustomer | null setRow(next) const anyRow = next as any const submitted = Boolean(anyRow?.followStep5Submitted) || Boolean(anyRow?.followStep5SubmittedAt) // 解析财务录入的回款记录 const records = parsePaymentRecords(anyRow?.followStep6PaymentRecords) setPaymentRecords(records) // 解析预计回款 const expected = parseExpectedPayments(anyRow?.followStep6ExpectedPayments) setExpectedPayments(expected) // 计算统计信息 const stats = calculatePaymentStats(records, anyRow) setPaymentStats(stats) // 如果第五步未完成,显示提示 if (!submitted) { setError('请先完成第五步合同签订') } } catch (e) { console.error('加载失败:', e) setRow(null) setError(String((e as any)?.message || '加载失败')) } finally { setLoading(false) } }, [customerId]) const calculatePaymentStats = useCallback((records: PaymentRecord[], rowData: any): PaymentStats => { const contracts = safeParseJSON(rowData?.followStep5Contracts) || [] // 计算应回款总额(从合同中获取) let totalPrincipal = 0 let totalInterest = 0 contracts.forEach((contract: any) => { totalPrincipal += Number(contract?.principal || 0) totalInterest += Number(contract?.interest || 0) }) const totalAmount = totalPrincipal + totalInterest // 计算已回款金额 let paidPrincipal = 0 let paidInterest = 0 records.forEach(record => { if (record.status === 'completed') { paidPrincipal += record.principal paidInterest += record.interest } }) const unpaidPrincipal = totalPrincipal - paidPrincipal const unpaidInterest = totalInterest - paidInterest return { totalAmount, totalPrincipal, totalInterest, paidPrincipal, paidInterest, unpaidPrincipal, unpaidInterest } }, []) useDidShow(() => { reload().then() }) const step5Done = useMemo(() => { const anyRow = row as any return Boolean(anyRow?.followStep5Submitted) || Boolean(anyRow?.followStep5SubmittedAt) }, [row]) const addExpectedPayment = useCallback(async () => { if (!step5Done) { Taro.showToast({ title: '请先完成第五步合同签订', icon: 'none' }) return } try { // 简化实现,直接使用当前日期和固定金额作为示例 // 在实际项目中,您可能需要使用自定义输入组件 const amount = 1000 // 默认金额 const date = dayjs().add(7, 'day').format('YYYY-MM-DD') // 默认7天后 const newExpected: ExpectedPayment = { id: makeId(), amount, expectedDate: date, createdAt: dayjs().format('YYYY-MM-DD HH:mm:ss') } setExpectedPayments(prev => [...prev, newExpected]) // 保存到后端 if (row && customerId) { const payload = [...expectedPayments, newExpected].map(item => ({ amount: item.amount, expectedDate: item.expectedDate, createdAt: item.createdAt })) await updateCreditMpCustomer({ ...(row as any), id: customerId, followStep6ExpectedPayments: JSON.stringify(payload) } as any) } Taro.showToast({ title: '添加成功', icon: 'success' }) } catch (e) { Taro.showToast({ title: (e as any)?.message || '添加失败', icon: 'none' }) } }, [step5Done, expectedPayments, row, customerId]) const deleteExpectedPayment = useCallback(async (expectedId: string) => { try { const res = await Taro.showModal({ title: '确认删除', content: '确定要删除这条预计回款记录吗?' }) if (!res.confirm) return const updated = expectedPayments.filter(item => item.id !== expectedId) setExpectedPayments(updated) // 保存到后端 if (row && customerId) { const payload = updated.map(item => ({ amount: item.amount, expectedDate: item.expectedDate, createdAt: item.createdAt })) await updateCreditMpCustomer({ ...(row as any), id: customerId, followStep6ExpectedPayments: JSON.stringify(payload) } as any) } Taro.showToast({ title: '删除成功', icon: 'success' }) } catch (e) { Taro.showToast({ title: (e as any)?.message || '删除失败', icon: 'none' }) } }, [expectedPayments, row, customerId]) const goStep5 = () => { if (!customerId) return Taro.navigateTo({ url: `/credit/mp-customer/follow-step5?id=${customerId}` }).catch(() => {}) } const goStep7 = () => { if (!customerId) return Taro.navigateTo({ url: `/credit/mp-customer/follow-step7?id=${customerId}` }).catch(() => {}) } const formatCurrency = (amount: number) => { return `¥${amount.toFixed(2)}` } const headerOffset = 12 return ( {loading ? ( 加载中... ) : error ? ( {error} {!step5Done && ( )} ) : !row ? ( ) : ( {/* 回款统计 */} 回款统计 回款总金额 {formatCurrency(paymentStats.totalAmount)} 应回款本金 {formatCurrency(paymentStats.totalPrincipal)} 应回款利息 {formatCurrency(paymentStats.totalInterest)} 已回款本金 {formatCurrency(paymentStats.paidPrincipal)} 已回款利息 {formatCurrency(paymentStats.paidInterest)} 未回款本金 {formatCurrency(paymentStats.unpaidPrincipal)} 未回款利息 {formatCurrency(paymentStats.unpaidInterest)} {/* 回款记录 */} 回款记录 {paymentRecords.length === 0 ? ( 暂无回款记录 回款信息由财务人员录入 ) : ( {paymentRecords.map((record) => ( {formatCurrency(record.amount)} 本金: {formatCurrency(record.principal)} | 利息: {formatCurrency(record.interest)} {record.paymentTime} {record.status === 'completed' ? '已完成' : '待确认'} ))} )} {/* 预计回款 */} 预计回款 {expectedPayments.length === 0 ? ( 暂无预计回款 ) : ( {expectedPayments.map((expected) => ( {formatCurrency(expected.amount)} 预计日期: {expected.expectedDate} 添加时间: {expected.createdAt} ))} )} )} {step5Done && ( )} ) }