vue2+ts el-dialog+el-table 实现价格 金额 小计 总价计算的需求

<template>
  <div class="organ-config-form">
    <el-form ref="form" :model="formData" :rules="formRules">
    <el-dialog :visible.sync="dialogVisible"
               :title="dialogTitle"
               :before-close="closeDialog"
               :close-on-click-modal="false"
              :close-on-press-escape="false"
               width="80%">
     
     <div class="contentBox">

        <div class="topBox">
            <div><span style="font-weight: bold;">合计金额:</span><span style="color:red;">{{totalPrice.toFixed(2)}}元</span></div>
            <div v-if="!isLook"><el-button type="primary" @click="addProject">添加项目</el-button></div>
        </div>
       
        <el-table :data="formData.gridData" class="middelTable" style="width:100%;">
            <el-table-column prop="xuhao" label="序号" width="50">
            <template slot-scope="scope">
                <div style="margin-bottom:20px"> {{ scope.$index + 1}}</div>
            </template>
        </el-table-column>
            <el-table-column prop="name" label="项目名称" width="200" >
            <template slot="header">
                <span><span style="color: red">*</span>项目名称</span>
            </template>
            <template slot-scope="scope">
                <template v-if="scope.row.editable">
                     <el-form-item :prop="'gridData.' +  scope.$index  + '.name'" :rules="formRules.name">
                         <el-tooltip class="tooltip-item" effect="dark" content="请输入30位以内字符" placement="top-start">
                        <el-input v-model="scope.row.name" placeholder="请输入"></el-input>
                         </el-tooltip>
                     </el-form-item>
                </template>
                <template v-else>
                     {{ scope.row.name }}     
                </template>
                
            </template>
            </el-table-column>

            <el-table-column prop="unit" label="计量单位" width="120">
            <template slot-scope="scope">
                <template v-if="scope.row.editable">
                    <el-tooltip class="tooltip-item" effect="dark" content="请输入10位以内字符" placement="top-start">
                        <el-input  v-model="scope.row.unit" placeholder="请输入" :maxlength="10" style="margin-bottom:20px"></el-input>
                    </el-tooltip>
                </template>
                <template v-else>
                {{ scope.row.unit }}
                </template>
            </template>
            </el-table-column>

            <el-table-column prop="number" label="数量" width="120">
            <template slot="header">
                <span><span style="color: red">*</span>数量</span>
            </template>
            <template slot-scope="scope">
                <template v-if="scope.row.editable">
                     <el-form-item :prop="'gridData.' +  scope.$index  + '.number'" :rules="formRules.number" >  
                         <el-tooltip class="tooltip-item" effect="dark" content="请输入4位以内正整数" placement="top-start">
                            <el-input v-model="scope.row.number" placeholder="请输入" :maxlength="4"></el-input>
                         </el-tooltip>
                     </el-form-item>
                </template>
                <template v-else>
                {{ scope.row.number }}
                </template>
            </template>
            </el-table-column>

            <el-table-column prop="unitPrice" label="单价" width="120">
            <template slot="header">
                <span><span style="color: red">*</span>单价</span>
            </template>    
            <template slot-scope="scope">
                <template v-if="scope.row.editable">
                     <el-form-item :prop="'gridData.' +  scope.$index  + '.unitPrice'" :rules="formRules.unitPrice" > 
                         <el-tooltip class="tooltip-item" effect="dark" content="请输入7位以内数字 小数点只支持2位" placement="top-start">
                            <el-input  v-model="scope.row.unitPrice" placeholder="请输入" :maxlength="10"></el-input>
                         </el-tooltip>
                     </el-form-item>
                </template>
                <template v-else>
                {{ scope.row.unitPrice }}
                </template>
            </template>
            </el-table-column>

            <el-table-column prop="remnant" label="残值" width="120">
            <template slot-scope="scope">
                <template v-if="scope.row.editable">
                    <el-form-item :prop="'gridData.' +  scope.$index  + '.remnant'" :rules="formRules.remnant" > 
                    <el-tooltip class="tooltip-item" effect="dark" content="请输入10位以内数字 小数点只支持2位" placement="top-start">
                        <el-input v-model="scope.row.remnant" placeholder="请输入" :maxlength="10" type="number"></el-input>
                    </el-tooltip>
                    </el-form-item>
                </template>
                <template v-else>
                {{ scope.row.remnant }}
                </template>
            </template>
            </el-table-column>

            <el-table-column prop="subTotal" label="金额小计" width="120">
            <template slot-scope="scope">
                <div style="margin-bottom:20px">  {{ (scope.row.unitPrice * scope.row.number).toFixed(2) }}</div>
            </template>
            </el-table-column>

            <el-table-column prop="remark" label="备注"  >
            <template slot-scope="scope">
                <template v-if="scope.row.editable">
                    <el-tooltip class="tooltip-item" effect="dark" content="请输入50位以内的字符" placement="top-start">
                        <el-input v-model="scope.row.remark" placeholder="请输入" :maxlength="50" style="margin-bottom:20px"></el-input>
                    </el-tooltip>
                </template>
                <template v-else>
                {{ scope.row.remark }}
                </template>
            </template>
            </el-table-column>

            <el-table-column  label="操作" width="80" v-if="!isLook"> 
            <template slot-scope="scope">
                <el-link
                v-if="isModifyPrice"
                    type="danger"
                    class="operation-delete"
                    :underline="false"
                    @click="deleteData(scope.row)"
                    style="margin-bottom:20px"
                >删除</el-link >
            </template>
            </el-table-column>
        </el-table>


     <div class="inputBox">
        <div class="txt-tip">报价说明(非必填)</div>
        <el-input
            type="textarea"
            maxlength="200"
            :disabled="isLook"
            placeholder="请输入"
            :autosize="{minRows: 5, maxRows: 10}"
            v-model="iptReason">
        </el-input> 
     </div>

   </div>
      <div 
            v-if="!isLook"
            slot="footer"
           class="dialog-footer"
           style="margin-top: 10px;">
    <!--  待派单/待报价审核  显示 取消和确认派单-->
        <div  class="dispatcc-check-btn-box" v-if="isDispatchCheck">    
            <el-button @click="dialogVisible=false"
                        size="medium">取消</el-button>
            <el-button type="primary"
                    @click="confirmDispatch"
                    size="medium"
                    style="margin-left:10px;"
                    :loading="loading"
                    >确认派单</el-button>
        </div>
        <!-- 维修中状态 取消 提交报价-->
        <div v-else-if="isDealing">
             <el-button 
                    @click="dialogVisible=false"
                    size="medium">取消</el-button>
              <el-button type="primary"
                        size="medium"
                        @click="rePrice"
                        >提交报价</el-button>           
        </div>

        <!-- 待验收状态 修改报价 确认通过 -->
        <div v-else-if="isAuditing">
                <el-button
                        @click="modifyPrice(true)"
                        size="medium" >修改报价</el-button>
                <el-button type="primary"
                        size="medium"
                        @click="confirmPass"
                        >确认通过</el-button>   
        </div>
        <!-- 维修中状态 、应答中  显示 取消 暂存 提交报价-->
        <div v-else-if="isYingDa">
                <el-button 
                        @click="dialogVisible=false"
                        size="medium">取消</el-button>
                <el-button
                @click="tempSave"
                        size="medium">暂存</el-button>
                <el-button type="primary"
                        size="medium"
                        @click="submitPrice"
                        :loading="loading"
                        >提交报价</el-button>   
        </div>
    </div>
    </el-dialog>
    </el-form>
  </div>
</template>

<style lang="scss" scoped>
/** @format */
</style>

<script lang="ts">
/** @format */

import { Component, Vue, Watch, Prop } from 'vue-property-decorator';
import { NUMBER_4,PRICE_7_with_2decimal } from '@/utils/Reg';
import { queryDamageQuote ,reQuote,takeOrder,dispatchOrder,temporarySave,checkApprove
    ,queryTaskQuote,checkDispatchOrder,queryQuote } from '@/api/easyrepaire2';

@Component({
    name: 'MaterialDamageDialog',
    components: {
    },
})
export default class extends Vue {
  private dialogVisible= false
  private dialogTitle:String='物损维修清单'
  private loading = false
  //总价
  private totalPrice=0
  //输入框
  private iptReason=''
  private orderDetail:any
  //根据状态显示不同ui
  private orderStatus=''
  private thirdUserId=''
  //是否点击了修改报价
  private isModifyPrice=false
  //报价方案只能查看
  private isLook:any=false;
  //
  private isLookPriceDetail=false;
  //原始表格数据
  private originalTableData=[]
  //表格数据在form数据对象中 才能让输入框失去焦点触发
  private formData:any = {
      unit: '',
      number: 0,
      gridData: [],
  };


 @Watch('formData.gridData', { deep: true })
  private onFormDataChange(newVal: any) {
      let total = 0;
      for (let item of newVal) {
          if (item.unitPrice && item.number) {
              total += item.unitPrice * item.number;
              //新增一个subTotal字段
              item.subTotal=item.unitPrice * item.number;
          }
      }
      this.totalPrice = total;
  }

  private formRules = {
      //项目名称,必填,任意字符,30字符以内,超出后自动换行
      name: [ { required: true, message: '请输入30字符以内',max: 30,trigger: 'blur' } ],
      //数量,必填,仅数字,10字符以内,超出后自动分行;
      number: [ { required: true, message: '请输入正确的值',pattern: NUMBER_4,trigger: 'blur'  } ],
      //单价,必填,仅数字和小数点,10字符以内,需满足小数校验逻辑,小数后仅支持2位数字;
      unitPrice: [ { required: true, message: '请输入正确的值',pattern: PRICE_7_with_2decimal,trigger: 'blur' } ],
      //残值,非必填,默认0,删除未填写时则默认0,仅数字和小数点,10字符以内,需满足小数校验逻辑,小数后仅支持2位数字;
  };


  private closeDialog(done:any) {
      done();
  }

  public init(data:any){
      this.dialogVisible= true;
      this.orderDetail=data;
      this.orderStatus=this.orderDetail.orderStatus;
      this.thirdUserId=this.orderDetail.thirdUserId;
      this.isLook=data.isLook;
      this.isLookPriceDetail=data.isLookPriceDetail;
      //如果是维修中 和应答中 进来就要默认为输入框可编辑
      //   if(this.isDealing||this.isYingDa){
      //       this.modifyPrice(true);
      //   }
      this.reqList();
     
  }
  //待派单/待报价审核状态
  private get isDispatchCheck(){
      if(this.orderStatus==='1'||this.orderStatus==='2'){
          return '应答成功'===this.orderDetail.replyStatus;
      }
      return false;
  }
  //待报价审核
  private get isOrderStatus2(){
      return  this.orderStatus==='2';
  }

  //维修中 
  private get isDealing(){
      return this.orderStatus==='4';
  }

  //待审核
  private get isAuditing(){
      return this.orderStatus==='5';
  }
  //待派单 应答中
  private get isYingDa(){
      if(this.orderStatus==='1'||this.orderStatus==='2'){
          return '应答中'===this.orderDetail.replyStatus;
      }
      return false;
  }
  
  private addProject(){
      const emptyItem={
          name: '',
          unit: '',
          number: '',
          unitPrice: '',
          remnant: '0',
          subTotal: '',
          editable: true,
          remark: '',
      };
      this.formData.gridData.push(emptyItem);
  }

  private modifyPrice(isEditable:boolean){
      this.isModifyPrice=isEditable;
      this.formData.gridData.forEach((item:any) => {
          item.editable = isEditable;
      });
  }

  private deleteData(row:any){
      // 在这里处理删除数据的逻辑
      const index = this.formData.gridData.indexOf(row);
      if (index !== -1) {
          this.formData.gridData.splice(index, 1);
      }
  }

  private checkInputValidate():boolean{
      //金额为0需要提示
      if(this.totalPrice<=0){
          this.$message.error('物损报价金额不可为0,请修改后重试');
          return false;
      }
      let isValidate=false;
      const form: any = this.$refs.form; // 添加类型声明
      form.validate((valid: boolean) => {
          console.log('form',form,valid);
          if (!valid) {
              return;
          }
          isValidate= this.validateNon();
      });
      return isValidate;
  }
  // 校验非必填的
  private validateNon():boolean {
      let isValidate=true;
      //残值非必填,默认0,删除未填写时则默认0,仅数字和小数点,10字符以内,需满足小数校验逻辑,小数后仅支持2位数字;
      const remnantReg=/^(?=.*[0-9])\d{1,10}(\.\d{1,2})?$/;
      this.formData.gridData.forEach((e:any) => {
          if(!e.remnant){
              e.remnant='0';
              return true;
          }
          if(e.remnant!==''){
              if (!remnantReg.test(e.remnant)) {
              // 单价格式不符合要求,进行相应的提示或处理
                  this.$message.error('残值输入不正确');
                  isValidate=false;
                  return;
              }
          }
      });
      return isValidate;
  }

  private cancelModify(){
      this.modifyPrice(false);
      this.formData.gridData = JSON.parse(JSON.stringify(this.originalTableData));
  }

  private confirmModify(){
      if(this.checkInputValidate()){
          //保存修改
          this.modifyPrice(false);
      }
  }

  private confirmDispatch(){
      if(!this.checkInputValidate()){
          return ;
      }
      this.$confirm(
          '请确定是否派单该物损机构作业?',
          '提示',
          {
              confirmButtonText: '确定',
              cancelButtonText: '取消',
              closeOnClickModal: false,
              closeOnPressEscape: false,
          },
      ).then(async() => {
          if('2'===this.orderStatus){
              this.confirmCheckDispatchReq();
          }else{
              this.confirmDispatchReq();
          }
      });
  }
  //派单
  private  async confirmDispatchReq(){
      this.loading=true;
      const res=await dispatchOrder(this.getReqDispatchOrderParaObj());
      this.loading=false;
      if(res.isSuccess()){
          this.dialogVisible=false;
          this.$emit('refresh');
      }
  }
  //审核派单
  private  async confirmCheckDispatchReq(){
      this.loading=true;
      const res = await  checkDispatchOrder(
          this.getReqCheckDispatchOrderParaObj(),
      );
      this.loading=false;
      if(res.isSuccess()){
          this.dialogVisible=false;
          this.$emit('refresh');
      }
  }
  //确认通过
  private confirmPass(){
      if(!this.checkInputValidate()){
          return ;
      }
      this.$confirm(
          '验收前请确认该物损项目是否已按要求完成,是否提交验收通过?',
          '提示',
          {
              confirmButtonText: '确定',
              cancelButtonText: '取消',
              closeOnClickModal: false,
              closeOnPressEscape: false,
          },
      ).then(async() => {
          this.confirmPassReq();
      });
  }
  private async confirmPassReq(){
      this.loading=true;
      const res=await checkApprove(this.getReqConfirmPassParaObj());
      console.log('checkApprove');
      this.loading=false;
      if(res.isSuccess()){
          this.dialogVisible=false;
          this.$emit('refresh');
      }
  }

  //提交报价 接单接口 需校验物损金额,若金额小于0则限制提交,页面toast提示“物损报价金额不可为0,请修改后重试”,应答成功。
  private  submitPrice(){
      if(!this.checkInputValidate()){
          return ;
      }
      this.$confirm(
          '请确定是否提交报价方案?',
          '提示',
          {
              confirmButtonText: '确定',
              cancelButtonText: '取消',
              closeOnClickModal: false,
              closeOnPressEscape: false,
          },
      ).then(async() => {
          this.submitPriceReq();
      });
     
  }
  private async submitPriceReq(){
      this.loading=true;
      const res=await takeOrder(this.getReqTakeOrderParaObj());
      this.loading=false;
      if(res.isSuccess()){
          this.dialogVisible=false;
          this.$emit('refresh');
      }
  }
  //维修中 重新报价
  private async rePrice(){
      if(!this.checkInputValidate()){
          return ;
      }
      const para=this.getReqReQuoteParaObj();
      this.loading=true;
      const res= await reQuote(para);
      this.loading=false;
      if(res.isSuccess()){
          this.dialogVisible=false;
          this.$emit('refresh');
      }
  }
  //暂存
  private async tempSave(){
      if(!this.checkInputValidate()){
          return ;
      }
      const para=this.getReqTempSaveParaObj();
      this.loading=true;
      const res= await temporarySave(para);
      this.loading=false;
      if(res.isSuccess()){
          this.$message.success('暂存成功');
      }
  }
  //查询列表数据 维修中查询
  private async reqList(){
      let res:any;
      //报价方案
      if(this.isLook){
          if(this.isLookPriceDetail){
              res=await queryTaskQuote({ taskId: this.orderDetail.id  });
          }else{
              res=await queryQuote({ taskId: this.orderDetail.id ,repairOrgId: this.orderDetail.repairOrgId 
                  ,replyId: this.orderDetail.replyId });
          }
      }else{
          if(this.isDealing||this.isOrderStatus2){
              res=await queryTaskQuote({ taskId: this.orderDetail.id ,repairOrgId: this.orderDetail.repairOrgId 
                  ,replyId: this.orderDetail.replyId });
          }else{
              res=await queryDamageQuote({ taskId: this.orderDetail.id ,repairOrgId: this.orderDetail.repairOrgId 
                  ,replyId: this.orderDetail.replyId });
          }
      }
      if(res.isSuccess()){
          let list=res.getData().damageSubPojectList;
          this.iptReason=res.getData().remark||'';
          if(list){
              this.formData.gridData=[];
              this.formData.gridData.push(...list);
              this.originalTableData= JSON.parse(JSON.stringify(this.formData.gridData));
          }
          if(this.isLook){
              this.modifyPrice(false);
          }else{
              this.modifyPrice(true);
          }
          
      }
  }

  //重新报价请求参数对象
  private getReqParaObj(){
      const para={
          changeReason: this.iptReason,
          id: this.orderDetail.id,
          damageSubPojectList: this.formData.gridData,
          replyPrice: this.totalPrice,
      };
      return para;
  }

  //接单请求参数对象
  private getReqTakeOrderParaObj(){
      const para={
          remark: this.iptReason,
          id: this.orderDetail.replyId,
          damageSubPojectList: this.formData.gridData,
          replyPrice: this.totalPrice,
      };
      return para;
  }

  //派单请求参数对象
  private getReqDispatchOrderParaObj(){
      const para={
          changeReason: this.iptReason,
          id: this.orderDetail.id,
          orderId: this.orderDetail.orderId,
          subPojectList: this.formData.gridData,
          repairPrice: this.totalPrice,
          repairOrgId: this.orderDetail.repairOrgId,
          repairOrgName: this.orderDetail.repairOrgName,
      };
      return para;
  }
  //审核派单请求参数对象
  private getReqCheckDispatchOrderParaObj(){
      const para={
          approveModifyReason: this.iptReason,
          id: this.orderDetail.id,
          orderId: this.orderDetail.orderId,
          subPojectList: this.formData.gridData,
          finalQuote: this.totalPrice,
          userId: Number(this.thirdUserId),
      };
      return para;
  }

  //重新报价请求参数对象
  private getReqReQuoteParaObj(){
      const para={
          changeReason: this.iptReason,
          id: this.orderDetail.id,
          reQuotePrice: this.totalPrice,
          damageSubPojectList: this.formData.gridData,
      };
      return para;
  }

  //暂存请求参数对象
  private getReqTempSaveParaObj(){
      const para={
          remark: this.iptReason,
          id: this.orderDetail.replyId,
          damageSubPojectList: this.formData.gridData,
          replyPrice: this.totalPrice,
      };
      return para;
  }
  //确认通过请求参数对象
  private getReqConfirmPassParaObj(){
      const para={
          approveAction: '2',
          changeReason: this.iptReason,
          id: this.orderDetail.id,
          orderId: this.orderDetail.orderId,
          subPojectList: this.formData.gridData,
          repairPrice: this.totalPrice,
      };
      return para;
  }
}

</script>


<style lang="scss" scoped>

.contentBox{
    margin-left: 20px;
    margin-right: 20px;
    .topBox{
        margin-bottom: 30px;
        display: flex;
        justify-content: space-between;
    }
    .inputBox{
        margin-top: 58px;
    }
    .txt-tip{
        margin-bottom: 10px;
    }
   
}
.dispatcc-check-btn-box{
    display: flex;
    justify-content: flex-end; // 将子元素靠右对齐
   }
</style>

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容