实现多个合同和签署方 - 添加多个印章

487 阅读1分钟

前言

公司在做合同签章业务,需要合同和签署人签署多个印章的问题,需要对印章进行拖拽,

实现

效果图如下

文件列表和签约方可以选择切换,通过拖动标签的印章类型来实现印章的位置预览

image.png

预先定义印章类型和一些基础数据

vue3中通过import将印章的背景图片引入

image.png image.png

拖动标签位置的vue代码

image.png

拖动标签位置的js代码和处理逻辑

image.png

 drop(e, index, iten) {
      // 获取拖拽对象的参数
      let data = e.dataTransfer.getData("item");

      data = JSON.parse(data);
      // 鼠标落点位置相对于当前拖拽存放地的 x y
      if (data.type === "crossSign") {
        data.left = 840 - data.widthX;
      } else {
        data.left = e.layerX;
      }

      if (data.type === "text") {
        // 设置文本空间宽高
        data.width = 2;
        data.height = 1;
      }
      data.top = e.layerY;
      data.fileIndex = index;
      data.pageNum = index + 1;
      data.id = Math.round(Math.random() * 1000000000);

      // 转为后端需要的cm格式
      data.x = +((Math.abs(data.left) + data.widthX / 2) / 1188).toFixed(2);
      data.y = +(1 - +Math.abs(1188 - data.top - data.heightH / 2) / 1188).toFixed(2);
      console.log("data", data);
      // 存放到当前拖拽对象生成的列表中

      // 显示拖拽印章的 - 操作
      this.signTypeFun(data.type);

      this.dropData.push(data);
      if (!this.fileCheckList[this.fileListIndex]) {
        // 当整个数据结构都为空时
        this.fileCheckList.push({
          signFiles: [],
          ...this.signerList[this.signIndex]
        });
        this.fileCheckList[this.fileListIndex].signFiles[this.signIndex] = {
          docId: `${this.fileList[this.fileListIndex].id}`,
          xySignControls: [
            {
              ...data,
              signName: `${this.signerList[this.signIndex].name} - ${this.signerList[this.signIndex].enterpriseName}`
            }
          ]
        };
        if (data.type === "crossSign") {
          this.fileCheckList[this.fileListIndex].signFiles[this.signIndex] = {
            docId: `${this.fileList[this.fileListIndex].id}`,
            crossSignControls: [
              {
                ...data,
                signName: `${this.signerList[this.signIndex].name} - ${this.signerList[this.signIndex].enterpriseName}`
              }
            ],
            xySignControls: [
              {
                ...data,
                signName: `${this.signerList[this.signIndex].name} - ${this.signerList[this.signIndex].enterpriseName}`
              }
            ]
          };
        }
      } else {
        // 切换签约方
        if (!this.fileCheckList[this.fileListIndex].signFiles[this.signIndex]) {
          this.fileCheckList[this.fileListIndex].signFiles[this.signIndex] = {
            docId: `${this.fileList[this.fileListIndex].id}`,
            xySignControls: [
              {
                ...data,
                signName: `${this.signerList[this.signIndex].name} - ${this.signerList[this.signIndex].enterpriseName}`
              }
            ]
          };
          if (data.type === "crossSign") {
            this.fileCheckList[this.fileListIndex].signFiles[this.signIndex] = {
              docId: `${this.fileList[this.fileListIndex].id}`,
              crossSignControls: [
                {
                  ...data,
                  docId: `${this.fileList[this.fileListIndex].id}`,
                  signName: `${this.signerList[this.signIndex].name} - ${this.signerList[this.signIndex].enterpriseName}`
                }
              ],
              xySignControls: [
                {
                  ...data,
                  docId: `${this.fileList[this.fileListIndex].id}`,
                  signName: `${this.signerList[this.signIndex].name} - ${this.signerList[this.signIndex].enterpriseName}`
                }
              ]
            };
          }
        } else {
          this.fileCheckList[this.fileListIndex].signFiles[this.signIndex].xySignControls.push({
            ...data,
            signName: `${this.signerList[this.signIndex].name} - ${this.signerList[this.signIndex].enterpriseName}`
          });
          if (data.type === "crossSign") {
            if (!this.fileCheckList[this.fileListIndex].signFiles[this.signIndex].crossSignControls) {
              this.fileCheckList[this.fileListIndex].signFiles[this.signIndex].crossSignControls = [];
            }
            this.fileCheckList[this.fileListIndex].signFiles[this.signIndex].crossSignControls.push({
              ...data,
              signName: `${this.signerList[this.signIndex].name} - ${this.signerList[this.signIndex].enterpriseName}`
            });
          }
        }
      }
      console.log("draoData", this.fileCheckList);
    },

点击获取到印章组件的信息,方便印章的删除操作

image.png

 getModel(e, item, index) {
      this.dropSelectIndex = index;
      this.fileCheckList[this.fileListIndex].signFiles[this.signIndex].xySignControls = this.fileCheckList[this.fileListIndex].signFiles[this.signIndex].xySignControls.map((item) => {
        item.selectName = "";
        return item;
      });
      item.selectName = "select";
      this.signTypeFun(item.type);
      e.stopPropagation();
    },

拖动的印章可支持删除

image.png

 // 删除印章
    handleDeleteSeal(type) {
      if (type === 0) {
        this.isSealDrap = false;
        this.fileCheckList[this.fileListIndex].signFiles[this.signIndex].xySignControls.splice(this.dropSelectIndex, 1);
      } else if (type === 1) {
        this.isSeaming = false;
        this.fileCheckList[this.fileListIndex].signFiles[this.signIndex].xySignControls.splice(this.dropSelectIndex, 1);
      } else if (type === 2) {
        this.isSignature = false;
        this.fileCheckList[this.fileListIndex].signFiles[this.signIndex].xySignControls.splice(this.dropSelectIndex, 1);
      } else if (type === 3) {
        this.isDate = false;
        this.fileCheckList[this.fileListIndex].signFiles[this.signIndex].xySignControls.splice(this.dropSelectIndex, 1);
      } else if (type === 4) {
        this.isText = false;
        this.fileCheckList[this.fileListIndex].signFiles[this.signIndex].xySignControls.splice(this.dropSelectIndex, 1);
      }
    },

整个组件基本代码如下:

<template>
  <div
    class="card"
    ref="inCcard"
    v-loading='loading'
    element-loading-text="准备表单中..">
    <el-row>
      <el-col :span="10">
      </el-col>
      <el-col :span="24">
        <el-card class="box-card box" shadow='never'>
          <el-card class="box-card" style="margin-bottom:5px;">
            <Steps :active='active'></Steps>
          </el-card>
          <el-scrollbar class="height nav" v-show="active === 1">
            <BussineInfo
              ref="bussineInfo"
              :detailsInfo="projectDetailsInfo"
              :bankList="bankList"
              :companyList="companyList"
              @refersh="getDetails"
              @addForm="handleGetBussineeInfo" />
            <BindProject
              v-if="('fdbOrderProjectDTOList' in bussineInfoData ||  'fdbOrderProjectDTOList' in  projectDetailsInfo) && (bussineInfoData.id !== null || projectDetailsInfo.id !== null) "
              ref="bindProject"
              :detailsInfo="projectDetailsInfo"
              :guaranteeTypeList="guaranteeTypeList"
              @refersh="getDetails" />
            <div
            v-if="('fdbGroupDTOList' in bussineInfoData ||  'fdbGroupDTOList' in  projectDetailsInfo) && (bussineInfoData.id !== null || projectDetailsInfo.id !== null) ">
              <FdbConfig
                ref="fdbConfig"
                v-if="$route.params.type === 'add'"
                :groupMaxCount='bussineInfoData.groupMaxCount'
                :detailsInfo="projectDetailsInfo"
                @refersh="getDetails"/>
              <FdbConfig
                ref="fdbConfig"
                v-if="$route.params.type === 'update'"
                :groupMaxCount='bussineInfoData.groupMaxCount'
                :detailsInfo="projectDetailsInfo"
                @refersh="getDetails"/>
                <FdbConfig
                ref="fdbConfig"
                v-if="$route.params.type === 'confirmUpdate'"
                :groupMaxCount='bussineInfoData.groupMaxCount'
                :detailsInfo="projectDetailsInfo"
                @refersh="getDetails"/>
            </div>
            <div
            class="step-btn"
            v-if="('in' in bussineInfoData ||  'fdbOrderProjectDTOList' in  projectDetailsInfo) && (bussineInfoData.id !== null || projectDetailsInfo.id !== null) ">
              <el-button @click="handlePreStep">取  消</el-button>
              <el-button type="primary" class="step-next" :loading="btnLoading"  @click="handleNextStep" >保存</el-button>
              <el-button type="primary" class="step-next" v-if="this.$route.params.type !=='confirmUpdate' && Number(projectDetailsInfo.businessStatus) !== 7" :loading="btnLoading" @click="handleGoAudit" >去审核</el-button>
            </div>
          </el-scrollbar>
          <el-card class="box-card box" shadow='never' v-if="active === 2">
            <AwaitingAudit/>
         </el-card>
        </el-card>
      </el-col>
    </el-row>
  </div>
</template>
<script>
import {
  getConfigTypeList
} from '@/api/fdb/configManagement'
import {
  saveAndUpdateOrderToReceiver, // 接单员 - 创建订单
  updateStatus // 接单员 - 去审核
} from '@/api/fdb/fdbgroup'
import {
  sendSms,
  createOrderContractPDF
} from '@/api/fdb/orderVerification'
import Steps from './components/steps.vue' // 步进器
import BussineInfo from './components/bussinessInfo.vue' // 业务信息
import BindProject from './components/bindProject.vue' // 绑定项目
import FdbConfig from './components/fdbConfig.vue' // 反担保配置
import AwaitingAudit from './components/awaitingAudit.vue' // 待审核

export default {
  components: {
    Steps,
    BussineInfo,
    BindProject,
    FdbConfig,
    AwaitingAudit
  },
  data () {
    return {
      loading: false,
      active: 1,
      companyList: [],
      bankList: [],
      guaranteeTypeList: [],
      projectDetailsInfo: {}, // 订单详情
      bussineInfoData: {}, // 订单信息
      btnLoading: false
    }
  },
  created () {
    this.handleSelectChange()
    if (this.$route.params.type !== 'add') {
      this.init()
    }
  },
  methods: {
    // 修改-查询详情
    init () {
      this.loading = true
      // 获取当前管理员信息
      return this.$http.get(`/fdb/fdborder/${this.$route.params.projectId}`).then(({ data: res }) => {
        this.loading = false
        this.projectDetailsInfo = res && res.data
      }).catch(() => {})
    },

    getDetails (id) {
      this.$http.get(`/fdb/fdborder/${id}`).then(({ data: res }) => {
        this.projectDetailsInfo = res && res.data
      }).catch(() => {})
    },

    // 获取通用类型 - 配置项
    async handleSelectChange () {
      this.guaranteeTypeList = []
      this.companyList = []
      this.bankList = []
      const { data: res } = await getConfigTypeList({
        deptId: this.$store.state.user.deptId,
        sceneType: this.$route.params.insuranceCode
      })

      if (!Number(res.code) === 0) return false

      // data 返回值  1:保函类型 2:银行  3:担保公司

      // 保函类型
      res.data[1].map(item => {
        if (Number(item.isTick) === 1) {
          return this.guaranteeTypeList.push(item)
        }
      })

      // 担保公司
      res.data[2].map(item => {
        if (Number(item.isTick) === 1) {
          return this.companyList.push(item)
        }
      })

      // 银行
      res.data[3].map(item => {
        if (Number(item.isTick) === 1) {
          return this.bankList.push(item)
        }
      })
    },
    // 关闭
    handlePreStep () {
      this.$router.back(-1)
    },

    // 去审核
    handleGoAudit () {
      this.$refs.bussineInfo.$refs.addForm.validate(async (valid) => {
        if (valid) {
          this.btnLoading = true
          const { id } = this.bussineInfoData
          const data = {
            id,
            businessStatus: 2
          }
          const { data: res } = await updateStatus(data)
          this.btnLoading = false
          if (res.code !== 0) return false
          this.$message.success(`${res.msg}`)

          this.$router.back(-1)
        } else {
          this.$message.error('表单信息请填写完整!')
          return false
        }
      })
    },

    // 保存
    handleNextStep () {
      this.$refs.bussineInfo.$refs.addForm.validate(async (valid) => {
        if (valid) {
          this.btnLoading = true
          if (this.$route.params.type === 'confirmUpdate') { // 批改后 直接发起签章
            // 先生成pdf
            createOrderContractPDF({ id: this.$route.params.projectId }).then(res => {
              if (res.data.code === 0) {
                sendSms({ id: this.$route.params.projectId }).then((res) => { // 发送短信
                  if (res.data.code === 0) {
                    this.btnLoading = false
                    this.$message.success('审核完成,已发起签章!')
                    this.$router.back(-1)
                  } else {
                    this.btnLoading = false
                  }
                }).catch(() => {
                  this.btnLoading = false
                })
              }
            }).catch(() => {
              this.loading = false
            })
          } else {
            const data = {
              ...this.bussineInfoData
            // sceneName: this.$route.params.insuranceName
            }
            const { data: res } = await saveAndUpdateOrderToReceiver(data)
            if (this.$route.params.type === 'confirmUpdate') { // 批改更改状态
              const { id } = this.bussineInfoData
              const data = {
                id,
                businessStatus: 3
              }
              const { data: res } = await updateStatus(data)
              if (res.code !== 0) return false

              this.$router.back(-1)
            }
            if (res.code !== 0) return false
            let msg = this.$route.params.type === 'add' ? '保存' : '修改'
            this.$message.success(`${msg}成功!`)
            if (this.$route.params.type !== 'confirmUpdate') {
              this.$router.back(-1)
            }
          }
        } else {
          this.$message.error('表单信息请填写完整!')
          return false
        }
      })
    },

    // 暂存
    handleTemporaryStorage () {

    },

    // 获取添加的订单信息
    handleGetBussineeInfo (data) {
      this.bussineInfoData = data
    }
  }
}
</script>
<style lang="scss" scoped>
.box {
  height: calc(100vh - 100px);
}
.height {
  height: 100%;
}
.nav{
  height: calc(100% - 100px);
}
.step-btn {
  margin-top: 40px;
  text-align: center;
}
.step-next {
  margin-left:  20px;
}
</style>