Browse Source

feat: 新增客户自助扫码开票

zhangyuhan 3 months ago
parent
commit
2f0219d160

+ 624 - 0
src/views/create-order/components/newSetOrderInfo.vue

@@ -0,0 +1,624 @@
+<template>
+  <div class="set-order-info">
+    <!-- 客户扫码自助开票 -->
+    <common-dialog
+      class="com-dialog-box"
+      :visible="showDialog"
+      :show-footer="false"
+      :show-close="true"
+      @close="$emit('close')">
+      <div class="com-dialog-main">
+        <div class="com-dialog-title">
+          <h2>{{ title }}</h2>
+          <p v-if="showCon !== 3 && showCon !== 4">将二维码发送给客户,引导客户微信扫码开票</p>
+          <p v-if="showCon === 4">注:将二维码发送给客户,可查看发票信息、换开发票,注:1个发票只能线上换开申请1次,如超过1次请联系财务线下开票;</p>
+        </div>
+        <div class="com-dialog-content" v-if="showCon === 1">
+          <el-form :rules="rulesOrder" :model="dynamicValidateForm" ref="dynamicValidateForm" label-width="100px" class="order-dynamic">
+            <div v-for="(domain, index) in dynamicValidateForm.domains" :key="domain.key">
+              <el-form-item
+                :prop="'domains.' + index + '.code'"
+                :label="'订单编号' + (index + 1)"
+              >
+                <el-input placeholder="请输入订单编号" v-model="domain.code"></el-input>
+                <el-button class="delete-btn" v-if="index!== 0" @click.prevent="removeDomain(domain)">删除</el-button>
+              </el-form-item>
+              <el-form-item
+                :label="'开票金额' + (index + 1)"
+                :prop="'domains.' + index + '.price'"
+              >
+                <el-input @input="orderHandleInput($event, domain)" type="number" placeholder="请输入开票金额" v-model="domain.price"></el-input>
+              </el-form-item>
+            </div>
+            <el-form-item>
+              <el-button @click="addDomain">+添加订单</el-button>
+            </el-form-item>
+            <div class="price-total">开票金额合计:{{ totalPrice }}元</div>
+            <el-form-item>
+              <el-button type="primary" @click="submitForm('dynamicValidateForm')">下一步</el-button>
+            </el-form-item>
+          </el-form>
+        </div>
+        <div class="com-dialog-content" v-if="showCon === 2">
+          <div class="com-dialog-content-item">
+            <div class="com-dialog-price">
+              <label>开票金额(元):</label>
+              <el-input
+                type="number"
+                :disabled="showEditPrice"
+                @input="handleInput"
+                v-model="comDialogParams.price"
+                placeholder="请输入金额"
+                style="width: 200px;margin-right: 10px"
+              ></el-input>
+            </div>
+            <div class="qr-code-item">
+              <img ref="qrCodeImage" :src="QrCodeImage" alt="">
+            </div>
+            <div class="com-dialog-btn">
+              <el-button v-if="showEditPrice" @click="editPrice">修改开票金额</el-button>
+              <el-button @click="copyQrCode">复制二维码</el-button>
+            </div>
+          </div>
+        </div>
+        <div class="com-dialog-content" v-if="showCon === 3">
+          <el-form :model="rulesLogisticsForm" :rules="rulesLogistics" ref="ruleForm" label-width="100px" class="demo-ruleForm">
+            <el-form-item label="订单编号:" prop="codes">
+              <el-input v-model="rulesLogisticsForm.codes"></el-input>
+            </el-form-item>
+            <div class="more-order-tip">如为多个订单合并开票,多个订单编号逗号隔开</div>
+            <el-form-item label="发票链接:" prop="invoice" v-if="showItem === 1">
+              <el-input placeholder="电子发票,请输入发票链接" v-model="rulesLogisticsForm.invoice"></el-input>
+            </el-form-item>
+            <el-form-item label="快递单号:" prop="track" v-if="showItem === 2">
+              <el-input placeholder="纸质发票,请输入快递单号" v-model="rulesLogisticsForm.track"></el-input>
+            </el-form-item>
+            <el-form-item class="form-group">
+              <el-button @click="resetForm('ruleForm')">取消</el-button>
+              <el-button type="primary" @click="submitForm('ruleForm')">确定</el-button>
+            </el-form-item>
+          </el-form>
+        </div>
+        <div class="com-dialog-content" v-if="showCon === 4">
+          <div class="com-dialog-content-item">
+            <div class="com-dialog-price">
+              <slot name="content"></slot>
+            </div>
+            <div class="qr-code-item">
+              <img ref="qrCodeImage" :src="QrCodeImage" alt="">
+            </div>
+            <div class="com-dialog-btn">
+              <el-button @click="copyQrCode">复制二维码</el-button>
+            </div>
+          </div>
+        </div>
+      </div>
+    </common-dialog>
+  </div>
+</template>
+
+<script>
+import commonDialog from '@/components/Dialog.vue';
+import { Form } from 'element-ui';
+import 'clipboard-polyfill';
+export default {
+  name: 'new-set-order-info',
+  components: {
+    commonDialog,
+    [Form.name]: Form
+  },
+  props: {
+    showDialog: {
+      type: Boolean,
+      default: false
+    },
+    title: {
+      type: String,
+      default: '客户自助扫码开票'
+    },
+    showContent: {
+      type: Number,
+      default: 1
+    },
+    orderInfo: {
+      type: Object,
+      default () {
+        return {
+          order_code: '', // 订单编号
+          pay_money: 0 // 实付金额
+        }
+      }
+    }
+  },
+  data () {
+    return {
+      dynamicValidateForm: {
+        domains: [{
+          code: '',
+          price: '',
+          amount: ''
+        }]
+      },
+      rulesOrder: {
+        domains: [{
+          code: [
+            { required: true, validator: this.validCode, trigger: 'blur' }
+          ],
+          price: [
+            { required: true, validator: this.validPrice, trigger: 'blur' }
+          ]
+        }]
+      },
+      comDialogParams: {
+        show: false,
+        showFooter: false,
+        showClose: true,
+        price: ''
+      },
+      showEditPrice: false,
+      rulesLogisticsForm: {
+        codes: '',
+        invoice: '',
+        track: ''
+      },
+      rulesLogistics: {
+        codes: [
+          { required: true, validator: this.validLogistics, trigger: ['blur', 'change'] },
+        ],
+        invoice: [
+          { required: true, message: '发票链接必填', trigger: 'blur' },
+        ],
+        track: [
+          { required: true, message: '快递单号必填', trigger: 'blur' },
+        ],
+      },
+      QrCodeImage: '',
+      showItem: 0,
+      detailMoney: 0,
+      showCon: 1,
+      priceTotal: 0
+    }
+  },
+  created () {
+    this.showCon = this.showContent
+  },
+  watch: {
+    showDialog: {
+      handler (val) {
+        if (val) {
+          if (this.showCon === 2) {
+            // 如果详情页打开客户自助开票弹窗,则不展示修改开票金额按钮,调用查看剩余开票金额接口
+            // 否则是订单页进行客户自助开票,展示修改开票金额按钮,可开票金额为输入多个订单金额总价
+            if (!this.showEditPrice) {
+              this.checkOrderCode(this.orderInfo.order_code).then(res => {
+                if(res.status === 'success') {
+                  this.detailMoney = res.data.money / 100
+                  this.comDialogParams.price = res.data.money / 100
+                }
+              })
+            } else {
+              this.comDialogParams.price = this.totalPrice
+            }
+            this.getQRCode()
+          }
+          this.showCon = this.showContent
+        }
+      }
+      // else {
+      //   if(this.showContent === 2) {
+      //     //手动输入多个订单编号时,生成二维码,当弹窗关闭时清除输入框信息
+      //     this.$refs['dynamicValidateForm'].resetFields();
+      //   }
+      // }
+    },
+    'comDialogParams.price': {
+      handler (val) {
+        let pay = this.detailMoney
+        if (!this.showEditPrice) {
+          val = parseFloat(val)
+          if (val < 0) {
+            this.comDialogParams.price = 0
+          } else if (val > pay) {
+            this.comDialogParams.price = pay
+            this.$message({
+              message: `0<开票金额≤${pay}`,
+              type: 'error',
+              duration: 1500
+            })
+          } else {
+            this.getQRCode()
+          }
+        }
+      },
+      deep: true
+    }
+  },
+  computed: {
+    // 计算开票总价
+    totalPrice () {
+      let total = 0
+      this.dynamicValidateForm.domains.forEach(item => {
+        if (item.price) {
+          total += parseFloat(item.price * 100000)
+        }
+      })
+      return total / 100000
+    }
+  },
+  methods: {
+    // 订单页输入金额控制
+    orderHandleInput (value, item) {
+      const decimalPart = value.split('.')[1];
+
+      if (decimalPart && decimalPart.length > 2) {
+        value = parseFloat(value).toFixed(2);
+      }
+
+      item.price = value;
+    },
+    // 详情页输入金额控制
+    handleInput(value) {
+      const decimalPart = value.split('.')[1];
+
+      if (decimalPart && decimalPart.length > 2) {
+        value = parseFloat(value).toFixed(2);
+      }
+
+      this.comDialogParams.price = value;
+    },
+    fixedNum(val) {
+      return val ? Number(parseFloat(val).toFixed(0)) : 0
+    },
+    // content === 3
+    // 校验订单编号
+    validLogistics (rule, value, callback) {
+      if (value === '') {
+        callback(new Error('请输入订单编号'))
+      } else {
+        this.checkInvoiceQuery(value).then((res) => {
+          if (res.status === 'success') {
+            if(res.data.invoice_variety.indexOf('电子') > -1) {
+              this.showItem = 1
+            } else if(res.data.invoice_variety.indexOf('纸质') > -1) {
+              this.showItem = 2
+            } else {
+              this.showItem = 0
+            }
+            callback()
+          } else {
+            callback(new Error(res.info))
+          }
+        })
+      }
+    },
+    checkInvoiceQuery (codes) {
+      return new Promise((resolve) => {
+        this.$jyRequest('/jyOrderManager/order/invoiceQuery').data({ orderCodes: codes }).success((res) => {
+          resolve(res)
+        }).error((err) => {
+          resolve(err)
+        }).post()
+      })
+    },
+    // 录入物流信息
+    submitFormExpress(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          alert('submit!');
+        } else {
+          console.log('error submit!!');
+          return false;
+        }
+      });
+    },
+    resetFormExpress(formName) {
+      this.$refs[formName].resetFields();
+    },
+    // content === 2
+    // 修改开票金额
+    editPrice () {
+      this.showCon = 1
+    },
+    getQRCode (data) {
+      let params = { ['invoiceMoney' + '[' + this.orderInfo.order_code + ']']: this.fixedNum(this.comDialogParams.price * 100) }
+      if(data) {
+        params = {}
+        // 多个订单开票
+        data.forEach(item => {
+          const key = ['invoiceMoney' + '['+ item.code +']']
+          const value = this.fixedNum(item.price * 100)
+          params[key] = value
+        })
+      }
+      this.$jyRequest('/jyOrderManager/order/createQRCode').data(params).success((res) => {
+          if (res.status === 'success') {
+            this.QrCodeImage = res.data.url
+          }
+      }).post()
+    },
+    // 复制二维码
+    copyQrCode () {
+      const navigatorInfo = window.navigator.userAgent.toLowerCase()
+      if (navigatorInfo.indexOf('chrome') > -1) {
+        const imageElement = this.$refs.qrCodeImage;
+        const canvas = document.createElement('canvas');
+        const context = canvas.getContext('2d');
+        const image = new Image();
+
+        image.crossOrigin = 'Anonymous';
+        image.src = imageElement.src;
+
+        image.onload = () => {
+          canvas.width = image.width;
+          canvas.height = image.height;
+          context.drawImage(image, 0, 0);
+          canvas.toBlob((blob) => {
+            navigator.clipboard.write([
+              new ClipboardItem({ 'image/png': blob })
+            ])
+            .then(() => {
+              this.$message({
+                message: '二维码复制成功',
+                type:'success',
+                duration: 1500
+              })
+              this.$emit('close')
+            })
+            .catch((error) => {
+              console.error('二维码复制失败', error);
+              this.$message({
+                message: '二维码复制失败',
+                type: 'error',
+                duration: 1500
+              })
+            });
+          }, 'image/png');
+        }
+      } else {
+        this.$message({
+          message: '请右键点击二维码进行复制',
+          type: 'error',
+          duration: 1500
+        })
+      }
+    },
+    // 保存发票信息
+    saveInvoiceInfo () {
+      const params = {
+        orderCodes: this.rulesLogisticsForm.codes
+      }
+      if (this.showItem === 1) {
+        params.url = this.rulesLogisticsForm.invoice
+      } else if (this.showItem === 2) {
+        params.logisticsCode = this.rulesLogisticsForm.track
+      }
+      this.$jyRequest('/jyOrderManager/order/savaInvoice').data(params).success(() => {
+        this.resetForm('ruleForm')
+      }).post()
+    },
+    // content === 1
+    submitForm(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          if (formName === 'ruleForm') {
+            this.saveInvoiceInfo()
+          } else if (formName === 'dynamicValidateForm') {
+            this.showEditPrice = true
+            this.showCon = 2
+            this.comDialogParams.price = this.totalPrice
+            // 多个订单开票生成二维码
+            this.getQRCode(this.dynamicValidateForm.domains)
+          }
+        } else {
+          console.log('error submit!!');
+          return false;
+        }
+      });
+    },
+    resetForm(formName) {
+      this.$refs[formName].resetFields();
+      this.showItem = 0
+      this.$emit('close')
+    },
+    removeDomain(item) {
+      var index = this.dynamicValidateForm.domains.indexOf(item)
+      if (index !== -1) {
+        this.dynamicValidateForm.domains.splice(index, 1)
+      }
+    },
+    validCode (rule, value, callback) {
+      const ruleArr = rule.field.split('.')
+      if (value === '') {
+        return callback(new Error('请输入订单编号'))
+      } else {
+        this.dynamicValidateForm.domains.forEach((item, index) => {
+          if (item.code === value && index != ruleArr[1]) {
+            return callback(new Error('订单编号重复'))
+          }
+        })
+        const hasCodeKey = this.dynamicValidateForm.domains.filter((item, index) => {
+          return item.code === value && index != ruleArr[1]
+        })
+        if(hasCodeKey && hasCodeKey.length > 0) {
+          return callback(new Error('订单编号重复'))
+        } else {
+          this.checkOrderCode(value).then(res => {
+            console.log(res)
+            if(res.status === 'success') {
+              if (!this.dynamicValidateForm.domains[ruleArr[1]].price) {
+                this.dynamicValidateForm.domains[ruleArr[1]].price = parseFloat(res.data.money) / 100
+              }
+              this.dynamicValidateForm.domains[ruleArr[1]].amount = parseFloat(res.data.money) / 100
+              callback()
+            } else {
+              callback(new Error(res.info))
+            }
+          })
+        }
+      }
+    },
+    validPrice (rule, value, callback) {
+      const ruleArr = rule.field.split('.')
+      const code = this.dynamicValidateForm.domains[ruleArr[1]].code
+      const amount = this.dynamicValidateForm.domains[ruleArr[1]].amount
+      if (value) {
+        value = parseFloat(value)
+      }
+      if (!code) {
+        return callback(new Error('请先输入订单编号'))
+      } else if (value === '') {
+        return callback(new Error('请输入开票金额'))
+      } else if (value <= 0 || value > amount) {
+        this.dynamicValidateForm.domains[ruleArr[1]].price = amount
+        return callback(new Error('0<开票金额≤' + amount))
+      } else {
+        this.dynamicValidateForm.domains[ruleArr[1]].price = value
+        // this.totalPrice()
+        callback()
+      }
+    },
+    checkOrderCode (code) {
+      return new Promise((resolve) => {
+        this.$jyRequest('/jyOrderManager/order/orderInfo').data({ orderCode: code }).success((res) => {
+          resolve(res)
+        }).error((err) => {
+          resolve(err)
+        }).post()
+      })
+    },
+    addDomain() {
+      this.dynamicValidateForm.domains.push({
+        code: '',
+        price: '',
+        amount: ''
+      });
+      this.rulesOrder.domains.push({
+        code: [
+          { required: true, validator: this.validCode, trigger: 'blur' }
+        ],
+        price: [
+          { required: true, validator: this.validPrice, trigger: ['blur', 'change'] }
+        ]
+      })
+    },
+  }
+}
+</script>
+<style>
+/* 隐藏Element UI的el-input中数字输入框的上下按钮 */
+input::-webkit-outer-spin-button,
+input::-webkit-inner-spin-button {
+  -webkit-appearance: none;
+}
+input[type="number"] {
+  -moz-appearance: textfield;
+}
+</style>
+<style lang="scss" scoped>
+::v-deep {
+  .el-dialog{
+    width: 600px!important;
+  }
+}
+
+.com-dialog-box{
+  .com-dialog-main{
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    margin-top: -20px;
+  }
+  .com-dialog-content{
+    width: 100%;
+    margin-top: 20px;
+    max-height: 500px;
+    overflow-y: scroll;
+    scrollbar-width: none;
+    .order-dynamic{
+      margin-left: 68px;
+      width: 350px;
+    }
+    /* WebKit浏览器 */
+    &::-webkit-scrollbar {
+        width: 0;
+        height: 0;
+    }
+    .com-dialog-content-item{
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      ::v-deep{
+        .el-input__inner{
+          height: 32px;
+        }
+      }
+    }
+    .more-order-tip{
+      padding-left: 100px;
+      margin: -5px 0 10px;
+    }
+    .form-group{
+      margin-top: 20px;
+      ::v-deep{
+        .el-form-item__content{
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          margin-left: 0!important;
+        }
+      }
+      .el-button{
+        width: 120px;
+        height: 40px;
+      }
+      .el-button+.el-button{
+        margin-left: 20px;
+      }
+    }
+  }
+  .com-dialog-title{
+    text-align: center;
+    h2 {
+      font-size: 22px;
+      color: #1D1D1D;
+      text-align: center;
+    }
+    p{
+      margin-top: 10px;
+      font-size: 14px;
+      color: #333;
+    }
+  }
+
+  .qr-code-item{
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    margin-top: 20px;
+    width: 100%;
+    height: 120px;
+    img{
+      width: 120px;
+      height: 100%;
+    }
+  }
+  .com-dialog-btn{
+    display: flex;
+    justify-content: center;
+    margin-top: 20px;
+    width: 100%;
+    button {
+      width: 120px;
+      height: 40px;
+    }
+  }
+  .delete-btn{
+    position: absolute;
+    right: -84px;
+  }
+  .price-total{
+    margin-bottom: 22px;
+    padding-left: 25px;
+  }
+}
+</style>

+ 6 - 1
src/views/create-order/order-list.vue

@@ -156,6 +156,9 @@
     </div>
     </div>
 
 
     <div>
     <div>
+      <new-set-order-info :title="setDialogStatus.setTitle" :show-content="setDialogStatus.showContent"
+                      @close="closeComDialog" :show-dialog="setDialogStatus.showDialog"></new-set-order-info>
+
       <el-dialog
       <el-dialog
           title="创建订单"
           title="创建订单"
           width="90%"
           width="90%"
@@ -177,10 +180,12 @@ import ProductTypeSelector from "@/views/create-order/components/product-info-su
 import { debounce } from "lodash";
 import { debounce } from "lodash";
 import {productTypeMap} from "@/views/create-order/data";
 import {productTypeMap} from "@/views/create-order/data";
 import CreateOrder from './components/create.vue'
 import CreateOrder from './components/create.vue'
+import NewSetOrderInfo from "@/views/create-order/components/newSetOrderInfo.vue";
 
 
 export default {
 export default {
   name: 'OrderList',
   name: 'OrderList',
   components: {
   components: {
+    NewSetOrderInfo,
     CreateOrder,
     CreateOrder,
     ProductTypeSelector
     ProductTypeSelector
   },
   },
@@ -833,7 +838,7 @@ export default {
   },
   },
   methods: {
   methods: {
     doCreateQrcode () {
     doCreateQrcode () {
-      this.$notify.warning('接口暂不支持')
+      this.scanCodeVote(1)
     },
     },
     doCreateOrder () {
     doCreateOrder () {
       this.dialogVisible = true
       this.dialogVisible = true