金额输入框-带格式:千分位分隔符,保留两位小数四舍五入,如果人没有小数位就写(.00)

475 阅读1分钟

vue3 + element-plus实现金额组件。

金额组件命名MoneyInput.vue,父组件引用MoneyInput.vue时依然可以在父组件进行表单校验并且不需要额外的处理。

参考文章:blog.csdn.net/qq_38571305…

MoneyInput.vue代码

<template>
  <el-input
    v-model="currentData"
    :placeholder="placeholder"
    maxlength="18"
    @blur="handlerIllegalStr"
    :formatter="moneyFormatter"
    :parser="moneyParser"
    :disabled="disabled"
  >
  </el-input>
</template>

<script setup lang="ts">
import { ref, watch} from 'vue' 

const props = defineProps({
  modelValue: {
    type: [String, Number],
    default: ''
  },
  disabled: {
    type: Boolean,
    default: false
  },
  placeholder: {
    type: String,
    default: '请输入'
  }
})
const emit = defineEmits(['update:modelValue'])




// 数字格式化
const toNumber = (val) => {
    val = val.toString().replace(/[^\d^\.^\-]+/g, "") // 第二步:把不是数字,不是小数点、-的过滤掉
        .replace(/^0+(\d)/, "$1") // 第三步:第一位0开头,0后面为数字,则过滤掉,取后面的数字
        .replace(/^\./, "0.") // 第四步:如果输入的第一位为小数点,则替换成 0. 实现自动补全
        .replace(".", "$#$").replace(/\./g, "").replace("$#$", ".") // 只保留第一个".", 清除多余的"."
    // .match(/^\d*(\.?\d{0,9})/g)[0] || ""; // 第五步:最终匹配得到结果 以数字开头,只有一个小数点,而且小数点后面只能有1到9位小数
    return val
}
// 处理最后一位非法字符
const handlerIllegalStr = () => {
  if(currentData.value===0){
    currentData.value = '0.00'
  }else if(currentData.value && currentData.value!==''){
    currentData.value = toNumber(currentData.value)
    currentData.value = Math.round(parseFloat(currentData.value) * 100) / 100
    currentData.value = currentData.value.toString() 
    // console.log(currentData.value.slice(currentData.value.length-2, currentData.value.length-1))
    if(currentData.value.indexOf(".") === -1){
      currentData.value = currentData.value + '.00' 
    }else if(currentData.value.slice(currentData.value.length-2, currentData.value.length-1)  === "."){
      currentData.value = currentData.value + '0' 
    }
  }else{
    currentData.value = ''
  }
  //console.log('ccc_cccccccc',currentData.value)
  emit('update:modelValue', currentData.value)
}
      
// 格式化函数
const moneyFormatter = (num)=>{
  num = toNumber(num)
  num = num.toString()
  let num1 = num.split(".")[0], num2 = num.split(".")[1]
  let c = num1.toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,') 
  // console.log('aaa_cccccccc',currentData.value)

  return num.toString().indexOf(".") !== -1 ? (c+"."+ num2) : c
}
// 解析函数    
const moneyParser = (num)=>{
  num = toNumber(num)
  num = num.toString().replace(/,/g, "")
  // console.log('bbb_ccccccccc',currentData.value)
  emit('update:modelValue', num)
  return num
}

const currentData = ref()
currentData.value = props.modelValue
handlerIllegalStr()

watch(
  () => props.modelValue,
  (newValue) => {
    //console.log('watch', props.modelValue)
    currentData.value = props.modelValue
  }
)
</script>
<style lang="scss" scoped>
 
</style>

父组件代码

<template>
<div class="wrapper">
    <div class="sign-container">
      <div class="seal-new-page" >
        <el-form
          ref="ruleForm"
          :model="formData"
          :rules="rules"
          label-width="160px"
        >
            <CardView title="合同信息确认" v-if="formData.contractSignWeSignedInfo.isSigned===1">
            <template v-for="(item, index) in formData.contractSignBaseInfoList" :key="item.contractSignContractBaseInfo.contractStartTime + index">
               
              
              <template v-if="item.contractSignContractBaseInfo.isConnectedTransaction==='是'&&item.contractSignContractBaseInfo.isRelated==='是'">
                <el-collapse v-model="activeCollapse">
                  <el-collapse-item :key="index" :name="index">
                    <template #title>
                      <div class="title">{{ item.contractSignOtherSignedInfo.counterpartName }}</div>
                    </template>
                    <el-row class="mt-20"> 
                        <el-col :span="8" :xs="24" :md="12" :lg="8">
                          <el-form-item label-width="210px" label="关联交易金额(元)" :prop="`contractSignBaseInfoList[${index}][contractSignContractBaseInfo][relatedPartyTransactionAmount]`" :rules="rules.relatedPartyTransactionAmount">
                            <MoneyInput 
                              v-model="item.contractSignContractBaseInfo.relatedPartyTransactionAmount"
                              placeholder="请输入"
                              :disabled="disabled1"
                            ></MoneyInput>
                          </el-form-item>
                        </el-col>
                        <el-col :span="8" :xs="24" :md="12" :lg="8">
                          <el-form-item label-width="210px" label="统一交易协议执行情况(元)" :prop="`contractSignBaseInfoList[${index}][contractSignContractBaseInfo][agreeTransactionAgreementSituation]`" :rules="rules.agreeTransactionAgreementSituation">
                            <MoneyInput 
                              v-model="item.contractSignContractBaseInfo.agreeTransactionAgreementSituation"
                              placeholder="请输入"
                              :disabled="disabled1"
                            ></MoneyInput>
                          </el-form-item>
                        </el-col>
                        <el-col :span="8" :xs="24" :md="12" :lg="8">
                          <el-form-item label-width="210px" label="关联交易价格(元)" :prop="`contractSignBaseInfoList[${index}][contractSignContractBaseInfo][relatedPartyTransactionPrice]`" :rules="rules.relatedPartyTransactionPrice">
                            <MoneyInput 
                              v-model="item.contractSignContractBaseInfo.relatedPartyTransactionPrice"
                              placeholder="请输入"
                              :disabled="disabled1"
                            ></MoneyInput>
                          </el-form-item>
                        </el-col>
                        <el-col :span="8" :xs="24" :md="12" :lg="8" v-if="item.contractSignContractBaseInfo.relatedPartyTransactionBusinessType.includes('投资金融产品')">
                          <el-form-item label-width="210px" label="投资金融产品份额占比(%)" :prop="`contractSignBaseInfoList[${index}][contractSignContractBaseInfo][investmentFinancialProductsProportion]`" :rules="rules.investmentFinancialProductsProportion">
                            <MoneyInput 
                              v-model="item.contractSignContractBaseInfo.investmentFinancialProductsProportion"
                              placeholder="请输入"
                              :disabled="disabled1"
                            ></MoneyInput>
                          </el-form-item>
                        </el-col>
                    </el-row>
                  </el-collapse-item>
                </el-collapse>
              </template>
            </template>
          </CardView>
        </el-form>
      </div>
    </div>  
</div>
</template>
<script setup lang="ts">
import { ref, reactive, computed, watch, onBeforeMount,inject } from 'vue'
import type { FormRules, UploadInstance } from 'element-plus'
import { QuestionFilled } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import CardView from '@/components/CardView.vue'
import MoneyInput from '@/components/MoneyInput.vue'

//校验表单
const ruleForm = ref()
const commitNoSign = async () => {
  const valid = await ruleForm.value.validate().catch(() => {
    ElMessage({
      showClose: true,
      message: '请确认输入信息是否完整',
      type: 'warning'
    })
    return false
  })
  if(valid){
      let currentData = JSON.parse(JSON.stringify(formData))
      formData.contractSignBaseInfoList.forEach((item, index) => {
        currentData.contractSignBaseInfoList[index].contractSignContractBaseInfo.contractTermType = ''
        currentData.contractSignBaseInfoList[index].contractSignContractBaseInfo.contractStartTime = ''
        currentData.contractSignBaseInfoList[index].contractSignContractBaseInfo.contractEndTime = ''
        currentData.contractSignBaseInfoList[index].contractSignContractBaseInfo.termDescription = ''
        currentData.contractSignBaseInfoList[index].contractSignOtherSignedInfo.legalPersonIdentificationFileName = ''
        currentData.contractSignBaseInfoList[index].contractSignOtherSignedInfo.powerOfAttorneyFileName = ''
      })
      currentData.contractSignWeSignedInfo.contractSignTextFileName = ''
      currentData.contractSignWeSignedInfo.powerOfAttorneyFileName = ''
       
      const res = await noSignRelease({
        examineGroupId: currentData.examineGroupId,
        examineId: currentData.examineId,
        id: currentData.id,
        version: currentData.version,
        remark: currentData.remark,
        contractSignBaseInfoList: currentData.contractSignBaseInfoList,
        contractSignWeSignedInfo: currentData.contractSignWeSignedInfo,
      })
      if (res.code == 200) {
        ElMessage({
          showClose: true,
          message: '发布成功',
          type: 'success'
        })
        setTimeout(() => {
          router.go(-1)
        })
      } else {
        ElMessage({
          showClose: true,
          message: res.message,
          type: 'warning'
        })
      }
  
  }
}
</script>