当前位置: 首页 > article >正文

拖拽盖章处理

进行元素拖拽:同类章替换、删除已盖章
1.复制对应元素,在onmousemove中left和top一直在变化
2.onmouseup时,计算出在pdf显示区域内的left,top,removeChild删除原先复制的元素,再appendChild到pdf显示区域的父元素中。再次移动onmousedown绑定对应事件

效果图
在这里插入图片描述
主要代码文件如下,重点在于_signPic内的坐标获取处理

<template>
  <div
    class="app-container"
    v-loading.fullscreen="listLoading"
    element-loading-text="加载中"
  >
    <el-header class="headerBox flex">
      <div class="doc-title-list">
        <div class="active-doc">{{ activeDoc.signDocumentTitle }}</div>
      </div>
      <!-- 发起签署 -->
      <div class="sign-btn">
        <el-button size="small" type="primary" @click="submitSign"
          >确认签署</el-button
        >
      </div>
    </el-header>
    <!-- 主题内容 -->
    <div class="cont">
      <!-- 中间区域 -->
      <div id="pageContent" class="viewerContainer">
        <!-- 左边区域  -->
        <div class="left-area-container">
          <!-- 坐标签未预设位置,需要拖拽盖章 -->
          <DragSeal
            v-if="signType == 1"
            :sealList="sealList"
            @drag="_signPic"
          />
          <!-- 关键字签0&&坐标签已预设位置2,无需拖拽盖章,只需选择印章 -->
          <KeySeal v-else :sealList="sealList" @select="_select" />
        </div>
        <div class="pdfContent_1PW2f">
          <div class="pdf-header">
            <div class="block">
              <span class="demonstration">{{ scale * 100 }}%</span>
              <div class="slider">
                <!-- @change="handleChange" -->
                <el-slider
                  v-model="scale"
                  :min="0.5"
                  :max="2"
                  :step="0.25"
                  disabled
                ></el-slider>
              </div>
            </div>
            <div class="input">
              <span
                >Page:
                <input
                  type="text"
                  class="input-text"
                  v-model="page_num"
                  placeholder="1"
                />
                / {{ page_count }}</span
              >
              <el-button @click="jump" type="text">跳转</el-button>
            </div>
          </div>
          <div
            class="pdf-container"
            ref="pdfBox"
            v-loading="!isShow"
            element-loading-text="拼命加载中"
            element-loading-spinner="el-icon-loading"
            element-loading-background="rgba(0, 0, 0, 0.1)"
          >
            <div
              class="pdf-box"
              :style="{
                width: maxPdfWidth + 'px',
                left: '',
              }"
            >
              <div
                v-for="page in page_count"
                :key="page"
                class="pdfPage_1yRne"
                :style="{
                  width: pdfInfo[page].pdfWidth + 'px',
                  height: pdfInfo[page].pdfHeight + 'px',
                }"
              >
                <canvas class="pdf-item" :id="'the-canvas' + page"></canvas>
                <div class="dragLayer_3ccsq" :id="'can' + page"></div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <!-- 右边区域 -->
      <div class="right-area-container">
        <ShowSeal
          :sealList="sealList"
          @delete="deleteSign"
          :selPosList="currentDocPosList"
          :signType="signType"
        />
      </div>
    </div>
    <!-- 替换印章 -->
    <ReplaceSeal
      v-if="replaceVisible"
      :dialogVisible="replaceVisible"
      :sealList="sealList"
      :sealId="selectSeal.sealId"
      @confirm="_confirmReplace"
    />
  </div>
</template>

<script>
import { selectSignInfoH5Sign, sign } from "@/api/sign";
const ReplaceSeal = () => import("./components/ReplaceSeal.vue");
import common from "./model/common";
import DragSeal from "./components/DragSeal.vue";
import KeySeal from "./components/KeySeal.vue";
import ShowSeal from "./components/ShowSeal.vue";
export default {
  name: "companySign",
  components: {  DragSeal, KeySeal, ShowSeal, ReplaceSeal },
  data() {
    return {
      isShow: false,
      listLoading: false,
      currentDocPosList: [],
      docPosList: {}, //每个文档的印章坐标
      userData: {},
      activeDoc: {},
      AuthDialogVisible: false, // 认证弹窗控制器
      certInfo: {},
      verifyInfoList: [], //认证列表
      signType: 0, //1坐标签未预设位置,0关键字签,2坐标签已预设位置
      signPosJson: [], //印章回显坐标信息
      replaceVisible: false,
      selectSeal: {
        sealType: "",
        domId: "",
        sealId: "",
      },
      signerInfo: {}, //签署人信息
      pdfInfo: {
        0: {
          pdfHeight: 0,
          pdfWidth: 0,
        },
      },
    };
  },
  mixins: [common],
  methods: {
    // 计算已添加印章项
    handlePos() {
      this.sealList = this.sealList.map((item) => {
        return { ...item, num: 0 };
      });
      this.currentDocPosList.map((item) => {
        for (let i = 0; i < this.sealList.length; i++) {
          const element = this.sealList[i];
          if (element.code == item.code) {
            this.sealList[i].num += 1;
          }
        }
      });
    },
    // 检查是否加盖可用印章(除时间章)
    checkSealDate() {
      let checkRes = true;
      // 查找是否有加盖印章(只存在时间章的不可以)
      const hasSeal = this.currentDocPosList.find((item) => {
        return item.isSealDate == 0;
      });
      checkRes = hasSeal ? true : false;
      if (!checkRes) {
        this.$message.error("未加盖印章,请先拖拽盖章!");
      }
      return checkRes;
    },
    // 删除全部印章
    delAllSeal() {
      const sealPosList = [...this.currentDocPosList];
      for (let i = 0; i < sealPosList.length; i++) {
        const element = sealPosList[i];
        this.deleteSign(element);
      }
    },
    // 认证成功并提交
    async _submitSign() {
      this._cancelAuth();
      this.listLoading = true;
      let sealPosList = [];
      if (this.signType == 0) {
        // 关键字签无需传坐标
        sealPosList = this.currentDocPosList.map((item) => {
          return {
            sealId: item.code,
          };
        });
      } else {
        //坐标签需传坐标
        const docSeal = this.currentDocPosList.find((item) => {
          return item.isSealDate == 0;
        });
        sealPosList = this.currentDocPosList.map((item) => {
          const sealId = item.isSealDate == 1 ? docSeal.sealId : item.sealId;
          return {
            sealId,
            x: item.posX,
            y: item.posY,
            pageNo: item.posPage,
            isSealDate: item.isSealDate,
          };
        });
      }
      const formData = {
        signBatchId: this.userData.signBatchId,
        userType: 1,
        userId: this.userData.userId,
        companyId: this.userData.companyId,
        signDocumentId: this.userData.signDocumentId,
        sealPosList,
        verifyType: "",
        signPdfUrl: this.activeDoc.signCurrentUrl,
      };
      console.log(formData, 789789);
      if (this.handleCurrentSigner()) {
        const { data: res } = await sign(formData);
        console.log(res, 2525);
        if (res.code == 0) {
          this.listLoading = false;
          this.$message.success(res.msg);
          this.$router.push({
            path: "/Previewpdf",
            query: {
              signBatchId: this.userData.signBatchId,
              signDocumentId: this.userData.signDocumentId,
            },
          });
        } else {
          this.listLoading = false;
          this.$message.warning(res.msg);
          if (res.msg == "该文档已被另一方签署,请刷新页面后重试") {
            // 重新获取文档信息
            this.selectSignInfo("reload");
          }
        }
      } else {
        this.listLoading = false;
      }
    },
    // 删除印章
    deleteSign(seal) {
      let pic = document.querySelector("#" + seal.domId);
      pic.parentNode.removeChild(pic);
      let index = this.currentDocPosList.findIndex((i) => {
        return i.domId == seal.domId;
      });
      if (index > -1) {
        //大于0 代表存在,
        this.currentDocPosList.splice(index, 1); //存在就删除
        this.handlePos();
      }
    },
    // 印象回显处理
    _select(value) {
      console.log(value, 3636);
      if (this.currentDocPosList.length > 0) {
        this.delAllSeal();
      }
      this.handlePos();
      const sealList = this.signPosJson.map((item, index) => {
        return {
          ...value[0],
          domId: "dom-" + value[0].code + index,
          posPage: item.pageNo || item.posPage,
          posX: item.centerX || item.posX,
          posY: item.centerY || item.posY,
        };
      });
      let _sealList = [];
      if (this.signType == 0) {
        // 关键字签署类型
        switch (this.signerInfo.keywordSignType) {
          case 0: //首个
            _sealList = [sealList[0]];
            break;
          case 1: //倒数第一个
            _sealList = [sealList[sealList.length - 1]];
            break;
          case 2: //全部
            _sealList = sealList;
            break;
        }
      } else {
        _sealList = sealList;
      }
      this.currentDocPosList = [..._sealList];
      this.showBackSeal();
      this.handlePos();
    },
    //印章回显
    showBackSeal() {
      for (let i = 0; i < this.currentDocPosList.length; i++) {
        const element = this.currentDocPosList[i];
        console.log(element, 45454);
        const _box = document.getElementById(element.domId);
        // 如果已存在就不用添加了
        if (_box) break;
        const dom = document.createElement("div");
        dom.className = `sign-img back-seal drag-img`;
        dom.id = element.domId;
        dom.style.width = this.scale * element.seal_W + "px";
        dom.style.height = this.scale * element.seal_H + "px";
        dom.style["line-height"] = this.scale * 50 + "px";
        const wh = (this.scale * element.seal_W) / 2;
        dom.style.left = Number(element.posX) * this.scale - wh + "px";
        dom.style.bottom = Number(element.posY) * this.scale - wh + "px";
        dom.style["background-image"] = `url(${element.sealImg})`;
        dom.title = element.sealTypeName;
        dom.style["background-repeat"] = `no-repeat`;
        dom.style["background-size"] = `contain`;
        // 坐标签已预设位置的,印章回显后可进行印章替换操作
        if (this.signType == 2) {
          dom.onclick = this.changeBg;
        }
        dom.style.cursor = "pointer";
        document.querySelector("#can" + element.posPage).appendChild(dom);
      }
    },
    // 打开替换弹窗
    changeBg(e) {
      const _id = e.currentTarget.id;
      const isDom = this.currentDocPosList.find((item) => {
        return item.domId == _id;
      });
      this.selectSeal = {
        sealType: isDom.sealType,
        domId: isDom.domId,
        sealId: isDom.sealId,
      };
      this.replaceVisible = true;
    },
    // 印章替换处理
    _confirmReplace(visible, value) {
      this.replaceVisible = false;
      // 替换印章
      if (visible) {
        const dom = document.getElementById(this.selectSeal.domId);
        dom.style.backgroundImage = "url(" + value.sealImg + ")";
        const signedPicList = this.currentDocPosList.map((item) => {
          const isDom = item.domId == this.selectSeal.domId;
          let query = {
            ...item,
          };
          if (isDom) {
            query = { ...item, ...value, domId: this.selectSeal.domId };
          }
          return query;
        });
        this.currentDocPosList = [...signedPicList];
      }
    },
    _getPageIndex(y, dom) {
      let maxH = 0;
      let index = 1;
      let pdfHeight = 0;
      let _y = y || 0;
      let pdfWidth = 0;
      let margin = 0;
      let _space = 0;
      let pdfH = [];
      for (const key in this.pdfInfo) {
        if (_y < 0) {
          break;
        }
        const element = this.pdfInfo[key];
        pdfH.push(element.pdfHeight);
        if (element.index > 1) {
          // 外边距为10
          margin = (element.index - 1) * 10;
        }
        // 高度累计
        const _maxH = pdfH.reduce((last, i) => {
          return last + i;
        }, 0);
        maxH = _maxH + margin;
        // 当前页
        pdfWidth = element.pdfWidth;
        index = element.index;
        // 判断是处于空白区域(外边距)top为负数
        if (y > maxH && y < _space && element.index > 1) {
          _y = maxH - y + margin;
          break;
        }
        if (y < maxH) {
          if (element.index > 1) {
            _y = maxH - y - element.pdfHeight;
          }
          pdfHeight = element.pdfHeight - Math.abs(_y);
          break;
        }
        _space = maxH + margin;
      }
      return {
        index,
        top: Math.abs(_y),
        bottom: pdfHeight - dom.clientHeight,
        pdfWidth,
      };
    },
    // ed.clientX:鼠标焦点距离浏览器右侧的距离
    // dom.clientWidth / 2:印章图片宽度的一半
    // isMove:是否是再次移动的
    _getPageNum(ed, dom, isMove) {
      let isOver = true;
      const _clientWidth = parseInt(dom.clientWidth / 2);
      const _clientHeight = parseInt(dom.clientHeight / 2);
      const _left = ed.clientX - _clientWidth;
      const _top = ed.clientY - _clientHeight;
      // pdf展示区域距离左侧的距离+横向滚动条
      const _pdfBox = document.querySelector(".pdf-box");
      // 拿到左边坐标
      const _xLeft = _left + this.$refs.pdfBox.scrollLeft - _pdfBox.offsetLeft;
      const _yTop = _top + this.$refs.pdfBox.scrollTop - _pdfBox.offsetTop;
      const _index = this._getPageIndex(_yTop, dom);
      const _xRight = _index.pdfWidth - _xLeft - parseInt(dom.clientWidth);
      if (
        _xLeft >= 0 &&
        _index.bottom >= 0 &&
        _index.top >= 0 &&
        _xRight >= 0
      ) {
        isOver = true;
      } else {
        isOver = false;
      }
      // 判断再次移动的时候是否出界
      if (isMove) {
        const _clientHeight = document.querySelector(
          "#can" + _index.index
        ).clientHeight;
        const _distance = _clientHeight - dom.clientHeight - _index.bottom;
        isOver = _distance > 0 ? isOver && true : false;
      }
      return {
        isOver,
        top: _index.top,
        left: _xLeft,
        index: _index.index,
        bottom: _index.bottom,
        posX: (_xLeft + _clientWidth) / this.scale,
        posY: (_index.bottom + _clientHeight) / this.scale,
      };
    },
    // 坐标签拖拽处理
    _signPic(e, seal) {
      let checkRes = true;
      // 判断是否已加盖印章
      if (seal.sealType == "DATE_SEAL") {
        checkRes = this.checkSealDate();
      }
      if (!checkRes) return;
      // 印章的唯一标识
      const timerCount = new Date().getTime() + "";
      this.count++;
      let dom = document.createElement("div");
      dom.style.left = 0 + "px";
      dom.style.top = e.clientY + 1.5 * dom.clientHeight + "px";
      if (seal.sealType == "DATE_SEAL") {
        dom.style.height = this.scale * 16 + "px";
        dom.style.width = this.scale * 105 + "px";
        const getNowFormatDate = this.getNowFormatDate();
        dom.innerHTML = `<div class="delete" @click.stop="deleteIt">删除</div><span style="font-weight:bolder">${getNowFormatDate}</span>`;
      } else {
        dom.style.width = this.scale * seal.seal_W + "px";
        dom.style.height = this.scale * seal.seal_H + "px";
        dom.style["background-image"] = `url(${seal.sealImg})`;
        dom.innerHTML = `<div class="delete" @click.stop="deleteIt">删除</div>`;
      }
      dom.className = `sign-img drag-img`;
      const signDocumentId = this.activeDoc.signDocumentId.slice(
        this.activeDoc.signDocumentId.length - 6,
        this.activeDoc.signDocumentId.length
      );
      const domId = seal.sealType + signDocumentId + timerCount;
      dom.id = domId;
      document.querySelector("#pageContent").appendChild(dom);
      document.onmousemove = (e) => {
        dom.style.left = e.clientX - parseInt(dom.clientWidth / 2) + "px";
        dom.style.top = e.clientY - parseInt(dom.clientHeight / 2) + "px";
      };
      // 鼠标抬开
      document.onmouseup = (e) => {
        // 判断是否越界,未越界测返回坐标
        const _dom = this._getPageNum(e, dom);
        document.querySelector("#pageContent").removeChild(dom);
        if (!_dom.isOver) {
          document.onmousemove = null;
          document.onmouseup = null;
          this.$message.error("请将印章拖拽到合同区域");
          return;
        } else {
          dom.style.left = _dom.left + "px";
          dom.style.top = _dom.top + "px";
          document.querySelector("#can" + _dom.index).appendChild(dom);
          let docId = this.activeDoc.signDocumentId;
          // 若为加盖时间印章,则该时间印章的sealId、sealType拿可用印章第一个印章
          let selectSeal = this.sealList[0];
          let sealId =
            seal.sealType == "DATE_SEAL" ? selectSeal.sealId : seal.sealId;
          let sealType =
            seal.sealType == "DATE_SEAL" ? selectSeal.sealType : seal.sealType;
          let pos = {
            domId: domId,
            left: _dom.left * this.scale,
            top: _dom.top * this.scale,
            posX: _dom.posX,
            posY: _dom.posY,
            posPage: _dom.index,
            signDocumentId: docId,
            ...seal,
            sealId,
            sealType,
          };
          this.currentDocPosList.push(pos);
          this.handlePos();
        }
        document.onmousemove = null;
        document.onmouseup = null;
        dom.onmouseenter = this.mouseenter;
        dom.onmouseleave = this.mouseleave;
        dom.onmousedown = this.moveTo;
        dom.childNodes[0].onclick = this.deleteIt;
      };
    },
    moveTo(e) {
      let odiv = e.currentTarget; //获取目标元素
      const _domId = this.currentDocPosList.find((item) => {
        return item.domId == odiv.id;
      });
      let dragDom = "";
      document.onmousemove = (e) => {
        dragDom = this._getPageNum(e, odiv, true);
        odiv.style.left = dragDom.left + "px";
        odiv.style.top = dragDom.top + "px";
      };
      document.onmouseup = (e) => {
        document.onmousemove = null;
        document.onmouseup = null;
        if (dragDom && !dragDom.isOver) {
          odiv.style.left = _domId.left / this.scale + "px";
          odiv.style.top = _domId.top / this.scale + "px";
          this.$message.error("请将印章拖拽到合同区域");
          return;
        } else {
          const _index = this.currentDocPosList.findIndex((item) => {
            return item.domId == odiv.id;
          });
          this.currentDocPosList[_index].left = dragDom.left * this.scale;
          this.currentDocPosList[_index].top = dragDom.top * this.scale;
          this.currentDocPosList[_index].posX = dragDom.posX;
          this.currentDocPosList[_index].posY = dragDom.posY;
        }
      };
    },
    // 查询详情
    async selectSignInfo(code) {
      this.listLoading = true;
      const query = {
        signBatchId: this.userData.signBatchId,
      };
      const { data: res } = await selectSignInfoH5Sign(query);
      if (res.code == 0) {
        const document = res.data.documentList.filter((item) => {
          return item.signDocumentId == this.userData.signDocumentId;
        })[0];
        this._getFileSteam(document.signCurrentUrl);
      }
      this.listLoading = false;
    },
  },
  computed: {
    currentCompanyId() {
      return this.$store.state.currentCompanyId;
    },
  },
  created() {
    const query = this.$route.query;
    this._getAnalysisCode(query.code);
  },
  mounted() {
    this.$nextTick(function () {
      this.$refs.pdfBox.addEventListener("scroll", this.handleScroll, false);
    });
  },
};
</script>
<style lang="scss">
.back-seal {
  position: absolute;
  cursor: move;
  z-index: 7;
  // overflow: hidden;
}
.delete {
  width: 100%;
  position: absolute;
  bottom: -20px;
  text-align: center;
  color: #fff;
  font-size: 16px;
  background-color: rgba(236, 49, 49, 0.7);
  cursor: pointer;
  display: none;
}
.nameBox {
  margin-top: 10px;
  width: 100%;
  font-size: 14px;
  text-align: center;
  color: #333;
}
.sign-img {
  position: absolute;
  cursor: move;
  z-index: 7;
  // overflow: hidden;
  background-repeat: no-repeat;
  background-size: contain;
  background-position: 100%;
}
</style>

<style lang="scss">
.headerBox {
  // position: fixed;
  // top: 0;
  width: 100%;
  background: #fff;
  z-index: 999;
  .doc-title-list {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 100%;
    height: 60px;
    .active-doc {
      border: none;
      color: #444;
      font-size: 22px;
    }
  }
  .page-title {
    margin-left: 15px;
  }
  .sign-btn {
    position: absolute;
    top: 12px;
    right: 20px;
  }
}
.cont {
  margin-top: 20px;
  display: flex;
  .item {
    margin: 0 0 25px 0;
  }
}
.left-area-container,
.right-area-container {
  // width: 340px;
  width: 20%;
  overflow: auto;
  font-size: 14px;
  background: #fff;
}
.sign-title {
  height: 55px;
  line-height: 55px;
  background: #0091ff;
  border-radius: 5px;
  color: #fff;
  margin-bottom: 5px;
  font-size: 16px;
}
.sign-parties {
  padding: 0 5px;
}

.instructBox {
  text-align: left;
  color: #999;
  line-height: 22px;
  p {
    margin-top: 5px;
  }
}
.signed-sum li {
  text-align: left;
  cursor: auto;
}
.signed-sum-number {
  font-size: 16px;
  color: #0096ff;
}
.right-area-container .sign-title {
  li {
    width: 33.33%;
  }
}
.right-area-container .pages {
  ul {
    background: #fff;
    border-radius: 5px;
    margin-bottom: 5px;
    li {
      width: 33.33%;
      margin: 0;
    }
  }
}

.delete {
  width: 100%;
  position: absolute;
  bottom: -20px;
  text-align: center;
  color: #fff;
  font-size: 16px;
  background-color: rgba(236, 49, 49, 0.7);
  cursor: pointer;
  display: none;
}
.nameBox {
  margin-top: 10px;
  width: 100%;
  font-size: 14px;
  text-align: center;
  color: #333;
}

.viewerContainer {
  display: flex;
  height: 91vh;
  width: 80%;
  overflow: auto;
  user-select: none;
  /*firefox浏览器*/
  -moz-user-select: none;
  /*safari、chrome浏览器*/
  -webkit-user-select: none; /*Safari中不支持该属性值,只能使用none或者text,或者是在html的标签属性中使用*/
  .input {
    border: none;
    outline: none;
    width: 100%;
  }
}

.pdfContent_1PW2f {
  width: 700px;
  flex: 1;
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: auto;
  // background: #f5f5f5;
  .pdf-header {
    /*position: fixed;*/
    top: 55px;
    left: 240px;
    right: 240px;
    height: 40px;
    border-bottom: 1px solid #eee;
    background-color: #fff;
    z-index: 100;
    text-align: center;
    display: flex;
    .block {
      flex: 1;
      display: flex;
      .demonstration,
      .slider {
        flex: 0 0 150px;
        line-height: 40px;
        width: 150px;
        text-align: right;
      }
      .demonstration {
        flex: 1;
        margin-right: 20px;
      }
    }
    .input {
      flex: 1;
      text-align: left;
      line-height: 40px;
      margin-left: 20px;
      .input-text {
        border: none;
        outline: none;
        border-bottom: 1px solid #e4e7ed;
        margin-left: 10px;
        width: 25px;
        text-align: center;
      }
    }
  }
  .pdf-container {
    display: inline-block;
    overflow: auto;
    height: 100%;
    width: 100%;
    .pdf-box {
      position: relative;
      margin: 0 auto;
      .sign-img {
        z-index: 4;
      }
    }
  }
  .pdfPage_1yRne {
    /*transition: left .3s;*/
    position: relative;
    margin: 10px 0;
  }
  .dragLayer_3ccsq {
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
  }
}
.signed-list {
  padding: 0 15px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  span {
    flex: 1;
  }
}
.signed-item {
  margin: 10px 0;
  border: 1px dashed rgba(0, 0, 0, 0.3);
}
</style>

组件代码DragSeal:

<template>
  <div>
    <div class="sign-fields item">
      <div class="sign-title">请选择印章类型</div>
      <div class="sign-list">
        <div class="seal-box-wrap">
          <div
            v-for="seal in sealList"
            :key="seal.code"
            v-bind:id="seal.code"
            @mousedown="_dragSeal($event, seal)"
          >
            <template v-if="seal.isSealDate == 0">
              <div
                class="seal-img"
                :style="{
                  height: 130 + 'px',
                  width: 130 + 'px',
                  backgroundImage: 'url(' + seal.sealImg + ')',
                }"
              ></div>
            </template>
            <div
              v-else
              class="seal-date"
              :style="{
                height: 130 + 'px',
                width: 130 + 'px',
                lineHeight: 130 + 'px',
              }"
            >
              {{ getNowFormatDate() }}
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="sign-fields item instructBox">
      <div>
        <div>设置签章位置说明</div>
        <p>1、告知签署方需要在文件具体哪一处进行加盖电子印章</p>
      </div>
      <div>
        操作指示:鼠标选中上方签约方信息,鼠标左键单击选择印章/时间戳,查找正文内容盖章位置单击左键
      </div>
    </div>
  </div>
</template>
<script>
export default {
  props: {
    sealList: {
      type: Array,
      default: () => {
        return [];
      },
    },
  },
  components: {},
  data() {
    return {};
  },
  methods: {
    _dragSeal(e, seal) {
      this.$emit("drag", e, seal);
    },
    getNowFormatDate() {
      let date = new Date(),
        year = date.getFullYear(), //获取完整的年份(4位)
        month = date.getMonth() + 1, //获取当前月份(0-11,0代表1月)
        strDate = date.getDate(); // 获取当前日(1-31)
      if (month < 10) month = `0${month}`; // 如果月份是个位数,在前面补0
      if (strDate < 10) strDate = `0${strDate}`; // 如果日是个位数,在前面补0
      return `${year}${month}${strDate}`;
    },
  },
  mounted() {},
};
</script>
<style lang='scss'>
.sign-fields .sign-list {
  padding: 0 20px;
}
.seal-box-wrap {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  .seal-box {
    width: 100%;
    border-radius: 5px;
    padding: 10px;
    margin-top: 15px;
    background-color: #fff;
  }
  .seal-img {
    background-size: contain;
    background-repeat: no-repeat;
    background-position: 100%;
    border: 1px solid rgb(225, 225, 226);
    margin: 8px 0;
  }
  .seal-date {
    text-align: center;
    font-weight: bolder;
    border: 1px solid rgb(225, 225, 226);
  }
}
</style>

组件代码KeySeal:

<template>
  <div class="sign-fields item">
    <div class="sign-title">请选择印章类型</div>
    <div class="sign-list-vertical">
      <el-radio-group v-model="selectSeal" @input="_selectSeal">
        <el-radio
          v-for="seal in showList"
          :key="seal.code"
          v-bind:id="seal.code"
          v-model="seal.code"
          :label="seal.code"
          border
        >
          <template v-if="seal.sealType != 'DATE_SEAL'">
            <span class="seal-name">{{ seal.sealTypeName }}</span>
            <div
              class="seal-img"
              :style="{
                height: 100 + 'px',
                width: 100 + 'px',
                backgroundImage: 'url(' + seal.sealImg + ')',
              }"
            ></div>
          </template>
        </el-radio>
      </el-radio-group>
    </div>
  </div>
</template>
<script>
export default {
  props: {
    sealList: {
      type: Array,
      default: () => {
        return [];
      },
    },
  },
  components: {},
  data() {
    return {
      selectSeal: "",
      showList: [],
    };
  },
  watch: {
    sealList: {
      handler(newVal, oldVal) {
        this.showList = newVal.filter((item) => {
          return item.isSealDate == 0;
        });
      },
      immediate: true,
      deep: true,
    },
  },
  methods: {
    _selectSeal(value) {
      const _seal = this.sealList
        .filter((item) => {
          return item.code == value;
        })
        .map((item) => {
          return {
            ...item,
            posX: 0,
            posY: 0,
            posPage: 0,
          };
        });
      this.$emit("select", _seal);
    },
    getNowFormatDate() {
      let date = new Date(),
        year = date.getFullYear(), //获取完整的年份(4位)
        month = date.getMonth() + 1, //获取当前月份(0-11,0代表1月)
        strDate = date.getDate(); // 获取当前日(1-31)
      if (month < 10) month = `0${month}`; // 如果月份是个位数,在前面补0
      if (strDate < 10) strDate = `0${strDate}`; // 如果日是个位数,在前面补0
      return `${year}${month}${strDate}`;
    },
  },
  mounted() {},
};
</script>
<style lang='scss'>
.sign-list-vertical {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  margin-top: 10px;
  .seal-item {
    margin-bottom: 15px;
  }
  .el-radio.is-bordered {
    width: 100%;
    height: auto;
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 15px;
    padding: 10px;
  }
  .el-radio__label {
    display: flex;
    justify-content: space-around;
    align-items: center;
  }
}
.seal-name {
  margin-right: 15px;
}
.seal-img {
  background-size: contain;
  background-repeat: no-repeat;
  background-position: 100%;
}
.el-radio.is-bordered + .el-radio.is-bordered {
  margin-left: 0;
}
</style>

组件代码ReplaceSeal:

<template>
  <BaseDialog
    v-if="dialogVisible"
    :dialogVisible="dialogVisible"
    title="替换印章"
    @closeDialog="_closeDialog"
    @confirmDialog="_confirmSeal"
  >
    <span>选择印章:</span>
    <el-select
      v-model="changeSeal"
      placeholder="请选择"
      style="width: 80%"
      value-key="sealId"
    >
      <el-option
        v-for="item in showList"
        :key="item.sealId"
        :label="item.sealTypeName"
        :value="item"
        :disabled="item.sealId == sealId"
      >
        <span style="float: left">{{ item.sealTypeName }}</span>
        <span style="float: right; color: #8492a6; font-size: 13px">{{
          item.sealId == sealId ? "当前印章" : ""
        }}</span>
      </el-option>
    </el-select></BaseDialog
  >
</template>
<script>
const BaseDialog = () => import("@/components/BaseDialog.vue");
export default {
  props: {
    dialogVisible: {
      type: Boolean,
      default: false,
    },
    sealList: {
      type: Array,
      default: () => {
        return [];
      },
    },
    sealId: {
      type: String,
      default: "",
    },
  },
  components: { BaseDialog },
  data() {
    return {
      changeSeal: "",
      showList: [],
    };
  },
  watch: {
    sealList: {
      handler(newVal, oldVal) {
        this.showList = newVal.filter((item) => {
          return item.isSealDate == 0;
        });
      },
      immediate: true,
      deep: true,
    },
  },
  methods: {
    _closeDialog() {
      this.$emit("confirm", false);
    },
    _confirmSeal() {
      if (!this.changeSeal) {
        this.$message.warning("请先选择印章!");
        return;
      }
      this.$emit("confirm", true, this.changeSeal);
    },
  },
  mounted() {},
};
</script>
<style lang='scss' scoped></style>

组件代码ShowSeal:

<template>
  <div>
    <div class="sign-parties item">
      <div class="sign-title">{{ signType == 1 ? "添加" : "选" }}印章项</div>
      <div class="sign-list">
        <div v-for="seal in sealList" :key="seal.code" class="show-seal">
          <template v-if="seal.num > 0">
            <span> {{ seal.sealTypeName }} </span>
            <span class="primaryText"> {{ seal.num }} </span></template>
        </div>
      </div>
    </div>
    <div class="sign-fields item">
      <div class="sign-title signed-list">
        <span>签章类型</span>
        <span>页码</span>
        <span>操作</span>
      </div>
      <div class="sign-list pages">
        <div
          class="signed-list signed-item"
          v-for="a in selPosList"
          :key="a.domId"
          :title="a.sealTypeName"
        >
          <span
            ><span> {{ a.sealTypeName }}</span>
            <span v-if="a.code == 'date'">-盖章时间</span></span
          >
          <span>{{ a.posPage }}</span>
          <span
            v-if="signType == 1"
            class="el-icon-delete"
            @click="deleteSign(a)"
          ></span>
          <span v-else></span>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  props: {
    sealList: {
      type: Array,
      default: () => {
        return [];
      },
    },
    selPosList: {
      type: Array,
      default: () => {
        return [];
      },
    },
    signType: {
      type: Number,
      default: 1,
    },
  },
  components: {},
  data() {
    return {};
  },
  methods: {
    deleteSign(a) {
      this.$emit("delete", a);
    },
  },
  mounted() {},
};
</script>
<style lang='scss' scoped>
.sign-list {
  max-height: 580px;
  overflow-y: auto;
  .show-seal {
    padding-left: 10px;
    text-align: left;
    margin-bottom: 5px;
    font-size: 16px;
  }
}
</style>

http://www.kler.cn/a/369460.html

相关文章:

  • HarmonyOS ArkTS与C++数据类型转换
  • 大厂面试真题-为什么Innodb要用B+树
  • 中间件安全(三)
  • 【福建医科大学附属第一医院-注册安全分析报告】
  • Supabase:当开源遇上实时数据库服务
  • java :String 类
  • Virtuoso使用layout绘制版图、使用Calibre验证DRC和LVS
  • 丝氨酸/苏氨酸激酶(STKs):前列腺癌治疗的新兴靶点
  • 探索 JavaScript 事件机制(四):React 合成事件系统
  • Java虚拟机的历程(jvm01)
  • Unity编辑器界面及其基础功能介绍
  • 005:航空力学基础、无人机操纵、飞机性能
  • 谷粒商城の秒杀服务
  • 深度学习超参数调优指南
  • Typst 平替Latex的新一代工具
  • vue3+ts实时播放视频,视频分屏
  • 【学术会议论文投稿】JavaScript在数据可视化领域的探索与实践
  • 若依框架前后端结构
  • 前端构建工具vite的优势
  • Java虚拟机JVM的简要工作原理
  • 从零学习大模型(三)-----GPT3(下)
  • 轻松拿捏!windows系统上安装Mamba
  • HarmonyOS 模块化设计
  • 机器人学习仿真框架
  • linux下xdg-open打开文件
  • 大厂面试真题-说说DDD中的领域驱动事件