import React , { Component } from "react" ; import Taro , { getCurrentInstance } from "@tarojs/taro" ; import { View , Text , Input , Video } from "@tarojs/components" ; import "./index.scss" ; import { KeyboardAwareScrollView , SafeAreaView , BoxShadow , StatusBar } from "@components" ; import HouseLoanComputeHeader from "./compute-header" ; import { TitleTpl } from "./title-tpl" ; import { LineWrap } from "./line-wrap" ; import { getRenderList , COMPUTE_WAY_TITLE , LOAN_WAY_TITLE , LIST_TYPE , COMPUTE_WAY , OPTION , DEMO_VIDEO } from "./constans" ; import { equalInterestCalc } from "./helper" ; import { isAndriod , setGlobalData , getStorageData , fomatFloat } from "@utils" ; export default class HouseLoanCompute extends Component < any , any > { loading : any ; scroll : any ; computeResult : any ; isFirstChange : boolean = true ; constructor ( props ) { super ( props ) ; const { price = 0 } = getCurrentInstance ( ) . router ! . params ; this . state = { showResult : false , equalPrincipalPayMonth : 0 , equalInterestPayMonth : 0 , userLoanWay : "等额本息" , way : price ? 1 : 0 , loanType : 1 , renderList : [ ] , options : { } , params : { houseTotal : price || 0 , downPayRate : 30 , loanAmount : 0 , accumulatTotalPirce : 0 , accumulatLoanLimit : 0 , commercialLoanBasePoint : 0 , commerceLoanRate : 0 , publicReserveFundsRate : 0 , commercialLoanTerm : 0 , commercialLoanWay : 0 , commerceTotalPirce : 0 } , defaultValue : { } , keyboardHeight : - 1 , loanLrpType : 1 , downPayRateCustom : "" , btnOpacity : 1 , backgroundColor : "#fff" } ; } componentDidMount ( ) { this . getData ( ) ; } async componentDidShow ( ) { const { title = "等额本息" } = await getStorageData ( "USER_LOAN_WAY" ) || { } ; this . setState ( { userLoanWay : title } ) ; } /**
     * 获取渲染项，处理picker range以及默认值
     * 需要在每次表单值改变后重新调用
     */ getRenderList = ( ) => { const { params , options , loanLrpType , commerceLoanRateNew , way } = this . state ; const commerceLoanRateEqua = `${ params . loanLrp * 100 }% + ${ params . commercialLoanBasePoint }‱ = ` ; const commerceLoanRateNewUnit = `${ fomatFloat ( commerceLoanRateNew * 100 , 2 ) }%` ; this . setState ( { renderList : getRenderList ( { ... params , options , way , downPayRateCustom : params . downPayRate , loanLrpType , commerceLoanRateEqua , commerceLoanRateNewUnit } ) } ) ; } ; description getData = ( ) => { const { params } = this . state ; const { defult , options } = OPTION ; const { downPayRate = [ ] , commerceLoanRate = [ ] , commerceLoanInFiveYearRate = [ ] , commerceLoanInOneYearRate = [ ] , accumulatFundRate = [ ] , accumulatFundInFiveYearRate = [ ] } = options ; downPayRate . splice ( 0 , 0 , { value : - 1 , label : "手动输入" } ) ; this . handleDownPaySelectLabel ( params . houseTotal , downPayRate ) ; params . loanAmount = Math . ceil ( this . handleAmount ( params . houseTotal , defult . downPayRate ) as number ) ; commerceLoanRate . forEach ( ( rate ) => { rate . limit = "outFive" ; } ) ; params . commerceOutFiveLoanRate = defult . commerceLoanRate ; commerceLoanInFiveYearRate . forEach ( ( rate ) => { rate . limit = "inFive" ; } ) ; commerceLoanInOneYearRate . forEach ( ( rate ) => { rate . limit = "inOne" ; } ) ; options . commerceLoanRate = [ ... commerceLoanRate , ... commerceLoanInFiveYearRate , ... commerceLoanInOneYearRate ] ; accumulatFundRate . forEach ( ( rate ) => { rate . limit = "outFive" ; } ) ; params . accumulatOutFiveFundRate = defult . accumulatFundRate ; accumulatFundInFiveYearRate . forEach ( ( rate ) => { rate . limit = "inFive" ; } ) ; options . accumulatFundRate = [ ... accumulatFundRate , ... accumulatFundInFiveYearRate ] ; const commerceLoanRateNew = fomatFloat ( defult . loanLrp + params . commercialLoanBasePoint / 10000 , 4 ) ; this . setState ( { ... OPTION , commerceLoanRateNew , params : { ... params , ... defult } } , ( ) => { this . getRenderList ( ) ; params . houseTotal && this . submit ( ) ; } ) ; } ; param data param selectObj onChangePicker = ( data , selectObj ) => { const { key } = data ; const { params } = this . state ; if ( key === "downPayRate" ) { const isInput = selectObj . value === - 1 ; params [ key ] = isInput ? params [ key ] : selectObj . value ; if ( ! isInput ) { params . loanAmount = Math . ceil ( this . handleAmount ( params . houseTotal , selectObj . value as number ) as number ) ; params . commerceTotalPirce = Math . max ( parseInt ( params . loanAmount ) - params . accumulatTotalPirce , 0 ) ; params . accumulatTotalPirce = parseInt ( params . loanAmount ) - params . commerceTotalPirce ; } this . setState ( { params , btnOpacity : isInput ? 0 : 1 , keyboardHeight : isInput ? 0 : - 1 } , this . getRenderList ) ; return ; } if ( data . key === "accumulatFundYear" ) { params . accumulatFundRate = selectObj . value > 5 ? params . accumulatOutFiveFundRate : params . accumulatFundInFiveYearRate ; } if ( data . key === "commerceLoanYear" ) { params . commerceLoanRate = selectObj . value > 5 ? params . commerceOutFiveLoanRate : selectObj . value > 1 ? params . commerceLoanInFiveYearRate : params . commerceLoanInOneYearRate ; } params [ key ] = selectObj . value ; let loanLrpTypeObj = { } ; if ( data . key === "loanLrp" ) { loanLrpTypeObj = { loanLrpType : selectObj . label . indexOf ( "最新" ) > - 1 ? 1 : 0 } ; } this . setState ( { params , ... loanLrpTypeObj } , this . getRenderList ) ; } ; /**
     * 处理首付展示
     */ handleDownPaySelectLabel = ( data , range ? ) => { const { options } = this . state ; const list = range || options . downPayRate ; list . forEach ( ( pay ) => { pay . labelCopy = pay . labelCopy || pay . label ; const amount = Math . floor ( fomatFloat ( pay . value * parseInt ( data as string , 10 ) , 1 ) as number ) ; if ( pay . value !== - 1 && amount >= 0 ) { pay . label = `${ pay . labelCopy } (${ amount }万)` ; } else { pay . label = pay . labelCopy ; } } ) ; this . setState ( { options } ) ; } ; param data param value param _index onInputChange = ( data , _value , _index ) => { const { params } = this . state ; const value = _value > 0 ? _value : 0 ; if ( data . key === "houseTotal" ) { this . handleDownPaySelectLabel ( value ) ; const { downPayRate } = params ; params . loanAmount = Math . ceil ( this . handleAmount ( value , downPayRate ) as number ) ; } params [ data . key ] = value ; if ( data . key === "loanAmount" || data . key === "houseTotal" ) { params . commerceTotalPirce = parseInt ( params . loanAmount ) - params . accumulatTotalPirce ; params . commerceTotalPirce = params . commerceTotalPirce > 0 ? params . commerceTotalPirce : 0 ; } const baseParams = { } ; if ( data . key === "commercialLoanBasePoint" ) { baseParams . commerceLoanRateNew = fomatFloat ( params . loanLrp + params . commercialLoanBasePoint / 10000 , 4 ) ; } if ( data . key === "accumulatTotalPirce" ) { params . accumulatTotalPirceMaxValue = - 1 ; params . commerceTotalPirce = parseInt ( params . loanAmount ) - params . accumulatTotalPirce ; if ( params . commerceTotalPirce <= 0 ) { params . commerceTotalPirce = 0 ; params . accumulatTotalPirce = parseInt ( params . loanAmount ) - params . commerceTotalPirce ; params . accumulatTotalPirceMaxValue = params . accumulatTotalPirce ; } } const { accumulatLoanLimit } = params ; if ( data . key === "commerceTotalPirce" ) { params . commerceTotalPirce = params . commerceTotalPirce > params . loanAmount ? params . loanAmount : params . commerceTotalPirce ; params . accumulatTotalPirce = parseInt ( params . loanAmount ) - params . commerceTotalPirce ; } if ( params . accumulatTotalPirce > accumulatLoanLimit ) { if ( this . isFirstChange || data . key !== "commerceTotalPirce" ) { Taro . showToast ( { title : `当前城市公积金最高可贷${ accumulatLoanLimit }万` , icon : "none" } ) ; params . commerceTotalPirce = parseInt ( params . loanAmount ) - accumulatLoanLimit ; } this . isFirstChange = ! ( data . key === "commerceTotalPirce" ) ; params . accumulatTotalPirce = accumulatLoanLimit ; params . accumulatTotalPirceMaxValue = accumulatLoanLimit ; } this . setState ( { params , ... baseParams } , this . getRenderList ) ; } ; /**
     * 处理切换计算方式时，贷款总额或房屋总价
     */ handleAmount = ( value , ratio ) => { return fomatFloat ( parseInt ( value + "" , 10 ) * ( 1 - ratio ) , 1 ) ; } ; param data onWayClick = ( data ) => { const { key , index } = data ; let obj = { } ; if ( data . key === "way" && index === 1 ) { const { params } = this . state ; const { downPayRate , loanAmount } = params ; params . houseTotal = Math . floor ( fomatFloat ( loanAmount / ( 1 - downPayRate ) , 1 ) as number ) ; obj = { params } ; this . handleDownPaySelectLabel ( params . houseTotal ) ; } if ( data . key === "way" && index === 0 ) { const { params } = this . state ; const { loanAmount } = params ; params . loanAmount = Math . ceil ( fomatFloat ( loanAmount , 1 ) as number ) ; obj = { params } ; } this . setState ( { [ key ] : index , showResult : false , ... obj } , this . getRenderList ) ; } ; param path goPage = ( path , data = { } ) => ( ) => { setGlobalData ( "COMPUTE_RESULT" , data ) ; Taro . navigateTo ( { url : `/pages/calculator/${ path }/index` } ) ; } ; param frames onKeyboardDidShow = ( frames ) => { const { endCoordinates } = frames ; console . log ( endCoordinates ) ; this . setState ( { btnOpacity : 0 , keyboardHeight : endCoordinates . height } ) ; } ; param frames onKeyboardDidHide = ( _frames ) => { this . setState ( { keyboardHeight : - 1 , btnOpacity : 1 } ) ; } ; param e downPayRateHandle = ( e ) => { const { value } = e . detail ; const valueNumbe = parseInt ( value , 10 ) ; this . setState ( { downPayRateCustom : valueNumbe } ) ; } ; /**
     * 确定手动输入首付比例
     */ downPayRateConfirm = ( ) => { const { options , params , downPayRateCustom } = this . state ; const { downPayRate } = options ; const value = parseInt ( downPayRateCustom , 10 ) ; if ( ! ( value > 0 && value <= 99 ) ) { this . setState ( { btnOpacity : 1 , keyboardHeight : - 1 } ) ; return ; } const realValue = value / 100 ; const existIndex = downPayRate . findIndex ( ( item ) => item . value === realValue ) ; if ( realValue && existIndex < 0 ) { const maxIndex = downPayRate . length - 1 ; const insertIndex = downPayRate . findIndex ( ( item , index ) => realValue > item . value && realValue < ( index < maxIndex ? downPayRate [ index + 1 ] . value : Infinity ) ) ; downPayRate . splice ( insertIndex + 1 , 0 , { value : realValue , label : `${ downPayRateCustom }%` } ) ; } params . downPayRate = realValue ; params . loanAmount = Math . ceil ( this . handleAmount ( params . houseTotal , params . downPayRate ) as number ) ; params . commerceTotalPirce = parseInt ( params . loanAmount ) - params . accumulatTotalPirce ; this . setState ( { options , params , btnOpacity : 1 , keyboardHeight : - 1 } , ( ) => { this . handleDownPaySelectLabel ( params . houseTotal ) ; this . getRenderList ( ) ; } ) ; } ; /**
     * 检验公积金金额
     */ checkAccumulatLoanAmount = ( ) => { const { params } = this . state ; const { accumulatLoanLimit , accumulatTotalPirce } = params ; if ( accumulatTotalPirce > accumulatLoanLimit ) { Taro . showToast ( { title : `当前城市公积金最高可贷${ accumulatLoanLimit }万` , icon : "none" } ) ; params . accumulatTotalPirce = accumulatLoanLimit ; return ; } const amount = parseInt ( params . loanAmount ) - params . commerceTotalPirce ; params . accumulatTotalPirce = amount ; if ( amount > accumulatLoanLimit ) { Taro . showToast ( { title : `当前城市公积金最高可贷${ accumulatLoanLimit }万` , icon : "none" } ) ; params . accumulatTotalPirce = accumulatLoanLimit ; params . commerceTotalPirce = parseInt ( params . loanAmount ) - params . accumulatTotalPirce ; } } ; checkParams = ( ) => { const { params , loanType } = this . state ; const { loanAmount , accumulatTotalPirce , commerceTotalPirce , accumulatLoanLimit } = params ; if ( loanAmount === 0 ) { Taro . showToast ( { title : `贷款金额不能为0` , icon : "none" } ) ; return false ; } if ( loanType === 0 && loanAmount != commerceTotalPirce + accumulatTotalPirce ) { Taro . showToast ( { title : `商贷金额和公积金贷款金额之和必须等于贷款总额` , icon : "none" } ) ; return false ; } if ( loanType === 2 && loanAmount > accumulatLoanLimit ) { Taro . showToast ( { title : `当前城市公积金最高可贷${ accumulatLoanLimit }万` , icon : "none" } ) ; return false ; } return true ; } ; getTip = ( showMonthlyPay = true ) => { const { params , loanType , loanLrpType , commerceLoanRateNew , userLoanWay } = this . state ; const { commerceLoanYear , accumulatFundYear , accumulatFundRate , accumulatTotalPirce , commerceTotalPirce , commerceLoanRate , loanAmount , downPayRate } = params ; const downPayRateStr = `首付${ fomatFloat ( downPayRate * 100 , 2 ) }%` ; const accumulatStr = `公积金贷${ loanType === 2 ? loanAmount : accumulatTotalPirce }万·${ accumulatFundYear }年·利率${ fomatFloat ( accumulatFundRate * 100 , 2 ) }%` ; const commerceLoanRateStr = `${ fomatFloat ( ( loanLrpType === 1 ? commerceLoanRateNew : commerceLoanRate ) * 100 , 2 ) }` ; const commerceStr = `商业贷${ loanType === 1 ? loanAmount : commerceTotalPirce }万·${ commerceLoanYear || 0 }年·利率${ commerceLoanRateStr }%` ; const loanStr = loanType === 0 ? [ accumulatStr , commerceStr ] : loanType === 1 ? [ commerceStr ] : [ accumulatStr ] ; const loanWayStr = `${ userLoanWay || "等额本息" }` ; const tip = ( showMonthlyPay ? [ downPayRateStr , ... loanStr , loanWayStr ] : [ downPayRateStr , ... loanStr ] ) . join ( "、" ) ; return tip ; } ; submit = async ( ) => { if ( this . loading ) return ; if ( ! this . checkParams ( ) ) return ; Taro . showLoading ( { title : "计算中..." } ) ; const { params , loanType , loanLrpType , commerceLoanRateNew , userLoanWay } = this . state ; const { commerceLoanYear , accumulatFundYear , accumulatFundRate , accumulatTotalPirce , loanAmount , commerceTotalPirce , commerceLoanRate , houseTotal } = params ; const res = await equalInterestCalc ( { totalPrice : houseTotal , commerceLoanYear , commerceLoanRate : loanLrpType === 1 ? commerceLoanRateNew : commerceLoanRate , accumulatFundYear , accumulatFundRate , accumulatTotalPirce : loanType === 2 ? loanAmount : accumulatTotalPirce , commerceTotalPirce : loanType === 1 ? loanAmount : commerceTotalPirce } ) ; try { const tip = this . getTip ( false ) ; this . computeResult = { ... res , loanAmount , tip } ; const backgroundColor = "#12B983" ; this . setState ( { tip , showResult : true , equalInterestPayMonth : res . equalInterest . payMonth , equalPrincipalPayMonth : res . equalPrincipal . payMonth , backgroundColor } ) ; Taro . setNavigationBarColor ( { frontColor : "#ffffff" , backgroundColor } ) ; IS_RN ? this . scroll . scrollTo ( { x : 0 , animation : true } ) : Taro . pageScrollTo ( { scrollTop : 0 , duration : 300 } ) ; const list = ( await getStorageData ( "LOAN_HISTORY" ) ) || [ ] ; const historyList = [ { commerceLoanYear : commerceLoanYear , commerceTotalPirce : loanType === 1 ? loanAmount : loanType === 2 ? 0 : commerceTotalPirce , accumulatFundYear , accumulatTotalPirce : loanType === 1 ? 0 : loanType === 2 ? loanAmount : accumulatTotalPirce , payMonthStr : userLoanWay === "等额本息" ? "每月应还(等额本息)" : "首月应还(等额本金)" , firstPay : userLoanWay === "等额本息" ? res . equalInterest . payMonth : res . equalPrincipal . payMonth } , ... list ] ; await Taro . setStorage ( { key : "LOAN_HISTORY" , data : historyList . slice ( 0 , 10 ) } ) ; } catch ( e ) { console . log ( e ) ; } finally { setTimeout ( ( ) => { Taro . hideLoading ( ) ; } , 1000 ) ; this . loading = false ; } } ; render ( ) { const { way , loanType , renderList , params , keyboardHeight , btnOpacity , userLoanWay , equalInterestPayMonth , equalPrincipalPayMonth , showResult , backgroundColor } = this . state ; const { houseTotal , downPayRate } = params ; return ( < SafeAreaView className = "calculator" > < StatusBar backgroundColor = { backgroundColor } barStyle = "dark-content" / > { keyboardHeight >= 0 && ( < View className = "fixed" > < View className = "mask" / > < View className = "keyboard-box" style = { { bottom : isAndriod ( ) ? 0 : keyboardHeight } } > < Text className = "keyboard-box-text" > 请输入 < /Text> < KeyboardAwareScrollView keyboardShouldPersistTaps = "always" enableAutomaticScroll = { false } onKeyboardDidShow = { this . onKeyboardDidShow } className = "keyboard-box-view" onKeyboardDidHide = { this . onKeyboardDidHide } > < Input keyboardType = "number-pad" type = "number" cursorSpacing = { 10 } className = "keyboard-box-input" focus style = { { paddingVertical : 0 } } onInput = { this . downPayRateHandle } onBlur = { this . downPayRateConfirm } holdKeyboard / > < /KeyboardAwareScrollView> < Text className = "keyboard-box-confirm" onClick = { this . downPayRateConfirm } > 确定 < /Text> < /View> < /View>)} < KeyboardAwareScrollView innerRef = { ( ref ) => { this . scroll = ref ; } } style = { { flex : 1 } } > { showResult && ( < HouseLoanComputeHeader way = { way } tip = { this . getTip ( ) } downPayRate = { downPayRate } equalInterestPayMonth = { equalInterestPayMonth } equalPrincipalPayMonth = { equalPrincipalPayMonth } houseTotal = { houseTotal } userLoanWay = { userLoanWay } goHistory = { this . goPage ( "history" ) } goMonthlyPayments = { this . goPage ( "monthly-payments" , this . computeResult ) } / > ) } < View className = "content" > < TitleTpl title = "计算方式" data = { COMPUTE_WAY_TITLE } onWayClick = { this . onWayClick } activeIndex = { way } / > < LineWrap data = { renderList } type = { COMPUTE_WAY [ way ] } onChangePicker = { this . onChangePicker } onInputChange = { this . onInputChange } / > < TitleTpl title = "贷款方式" data = { LOAN_WAY_TITLE } onWayClick = { this . onWayClick } activeIndex = { loanType } / > < LineWrap data = { renderList } type = { LIST_TYPE [ loanType ] } onBlur = { this . checkAccumulatLoanAmount } onChangePicker = { this . onChangePicker } onInputChange = { this . onInputChange } / > < Video className = "video" src = { DEMO_VIDEO } controls = { false } showFullscreenBtn = { false } autoplay loop muted / > < /View> < /KeyboardAwareScrollView> < BoxShadow shadowColor = "#000" shadowOffset = { { width : 0 , height : - 1 } } shadowOpacity = { 0.1 } shadowRadius = { 1 } elevation = { 5 } className = "compute" style = { { opacity : btnOpacity , } } boxShadow = "0px 2px 8px 0px rgba(211,215,218,1)" > < SafeAreaView > < View className = "compute-btn" onClick = { this . submit } > < Text className = "compute-btn-text" > 开始计算 < /Text> < /View> < /SafeAreaView> < /BoxShadow> < /SafeAreaView>); } }