Encapsulation and use of vue clipboard function

Article directory


Project renderings

1. What is the use of the clipboard?

In order to meet the needs of fast and convenient business operations, often the business only knows the code of the product and the required corresponding quantity. At this time, just copy the simple content and throw it to the clipboard to fill in the desired corresponding data.

2. Packaging shear board

1. Encapsulate button

<template>

          <span>  
 
             <template v-else-if="type === 'copyPaste'">
    
                  <el-button

                    size="small"

                    type="primary"

                    :disabled="disabled"

                    @click="handleCopyPaste"

                      >

                        剪切板

                  </el-button>

                </template>

         </span>
        <CopyPaste
              ref="copyPasteDialog"
              :paste="paste"
              :copy-paste-function="copyPasteFunction"
              @close-callback="$emit('getProductData')"
        />

</template>
<script>
props: {
    copyPasteFunction: {
        //copyPaste 剪贴板判断使用方式 byTransfer:调拨单剪切板
        type: String,
        default: '',
      }, 
 paste: {
        type: Function,
        default: () => {
          return Function
        },
      },
 beforePasteOpen: {
        type: Function,
        default: () => Function,
      },
}
//点击事件
handleCopyPaste() {
     if (!this.beforePasteOpen()) return
     this.$refs.copyPasteDialog.open()
},

handleCopyPaste() {
        if (!this.beforePasteOpen()) return
        this.$refs.copyPasteDialog.open()
      },
</script>

2. Encapsulate the clipboard component (the pop-up window can be directly used natively)

<template>
  <DragDialog
    :is-need-footer="true"
    :dialog-visible.sync="visible"
    :title="$t('common.copyPaste')"
    :append-to-body="true"
    @submit="handleOk"
  >
    <template slot="dialog-main">
      <div class="tiplabel">
        请粘贴产品编码/数量到此处
        <span class="download" @click="handleExport()">模版下载</span>
      </div>
      <el-input
        v-model="textarea"
        type="textarea"
        :autosize="{ minRows: 6, maxRows: 10 }"
        placeholder="请粘贴内容"
        @change="change"
      >
        >
      </el-input>
      <div v-if="err.length">
        产品编号:
        <span
          v-for="(item, index) in err"
          :key="index"
          style="color: red; padding: 0 5px"
        >
          {
   
   { item }}
        </span>
        不存在,请修改Excel再进行尝试!
      </div>
    </template>
  </DragDialog>
</template>

<script>
  import DragDialog from '@/components/DragDialog'
  import { baseURL } from '@/config' //项目的基础地址
  import axios from 'axios'
  import store from '@/store' //仓库 获取token
  import { details } from '@/api/commodity/product' //获取商品的详情接口 后续看你们自己什么业务
  import { tenantId } from '@/utils/token'
  export default {
    name: 'CopyPaste',
    components: { DragDialog },
    props: {
      paste: {
        type: Function,
        default: () => {
          return Function
        },
      },
      copyPasteFunction: {
        //copyPaste 剪贴板判断使用方式 byTransfer:调拨单剪切板
        type: String,
        default: '',
      },
    },
    data() {
      return {
        err: [],
        textarea: '',
        visible: false,
      }
    },
    computed: {
      uploadHeaders() {
        return {
          Authorization: `bearer ${store.getters['user/token']}`, //获取token
        }
      },
      templateUrl() { //模板下载地址
        let fileName = '剪贴板模板.xls'
        this.copyPasteFunction === 'byTransfer' &&
          (fileName = `调拨单剪贴板模板.xls`)
        return `${baseURL}/tfle/v1/files/download-by-key?fileKey=inventory/template/product/${tenantId()}/${fileName}`
      },
    },
    methods: {
      change() {
        //处理你需要的数据结构
        let str = this.textarea
        let target = str.split('\n') //切割拿到input框的值进行下面操作
        let list = []
        target.map((item) => {
          let itemArr = item.split('\t')
          if (itemArr[0]) {
            let obj =
              this.copyPasteFunction === 'byTransfer'
                ? {
                    outLogicWarehouseName: itemArr[0],
                    inLogicWarehouseName: itemArr[1],
                    productCode: itemArr[2],
                    applyQuantity: itemArr[3] || 0,
                  }
                : {
                    productCode: itemArr[0],
                    applyQuantity: itemArr[1] || 0,
                  }
            list.push(obj)
          }
        })
        //判断你传进来的是什么类型,这里可以根据你传进来的剪贴板判断使用方式 进行不同的操作
        if (this.copyPasteFunction === 'byTransfer') {
          this.data = list
        } else {
            //不是调拨单剪切板进行接口请求操作
          this.verify(list)
        }
      },
      verify(list) {
        let data = [],
          err = []
        list.map((item) => {
          details({ productCode: item.productCode }).then((res) => {
            if (res.success == false) {
              err.push(item.productCode)
            } else {
              res.applyQuantity = item.applyQuantity
              data.push(res)
            }
          })
        })
        this.err = err
        if (err.length) {
          return false
        }
        this.data = data
      },
      open() {
        // if (!this.checkUrl()) {
        this.visible = true
        // }
      },
      close() {
        this.visible = false
      },
      handleOk() {
        if (this.data.length) {
          console.log('这里的', this.data)
          this.visible = false
          this.paste(this.data) //传进来的函数接收处理完的数据进行操作
        }
      },
        //模板下载操作
      handleExport() {
        axios
          .get(this.templateUrl, {
            responseType: 'blob',
            headers: { ...this.uploadHeaders },
          })
          .then((res) => {
            if (res.status === 200) {
              var dom = document.createElement('a')
              dom.download = '剪贴板模板.xls'
              dom.style.display = 'none'
              dom.href = window.URL.createObjectURL(res.data)
              dom.click()
              this.$message({
                type: 'success',
                message: '下载成功',
              })
            }
          })
          .catch((err) => {
            this.$message.error(`下载失败,${err.message}`)
          })
      },
    },
  }
</script>

<style scoped lang="scss">
  .export-line {
    background: #e8e8e8;
    height: 1px;
    width: 100%;
    margin-bottom: 24px;
    clear: both;
  }
  .export-title {
    margin: 12px auto;
    line-height: 24px;
    font-size: 16px;
    color: #333;
  }
  .el-tree {
    color: #333;
  }
  .download {
    color: red;
    cursor: pointer;
  }
  .tiplabel {
    margin-bottom: 7px;
  }
</style>

3. Pop-up window packaging (included, if there are international operations, you need to remove or reference the internationalization for your own use)

<template>
  <el-dialog
    v-if="destroyOnClose"
    v-el-drag-dialog
    :title="title"
    :visible.sync="visible"
    :close-on-click-modal="false"
    :width="width"
    :append-to-body="appendToBody"
    :show-close="!isLoading"
    :fullscreen="dialogFull"
    @dragDialog="handleDrag"
    @close="close"
  >
    <template slot="title">
      <div class="avue-crud__dialog__header">
        <span class="el-dialog__title">
          <span
            style="
              display: inline-block;
              background-color: #3478f5;
              width: 3px;
              height: 20px;
              margin-right: 5px;
              float: left;
              margin-top: 2px;
            "
          ></span>
          {
   
   { title }}
        </span>
        <div
          v-if="isShowFullScreen"
          class="avue-crud__dialog__menu"
          @click="dialogFull ? (dialogFull = false) : (dialogFull = true)"
        >
          <i class="el-icon-full-screen"></i>
        </div>
      </div>
    </template>
    <div class="drag-dialog-container">
      <div
        ref="dragDialogContainerBody"
        class="main-bar"
        :style="{ maxHeight: maxHeight, minHeight: minHeight }"
      >
        <slot name="dialog-main" />
      </div>
      <div v-if="isNeedFooter" class="dialog-footer">
        <slot name="dialog-footer">
          <!-- 有默认的button,如果需要自定义,在外面通过slot传入也可以,如果使用默认按钮,记得传入相应按钮事件 -->
          <el-button
            v-show="isMore"
            type="primary"
            size="small"
            :loading="isLoading"
            @click="moreButton"
          >
            {
   
   { moreButtonText || $t('common.ok') }}
          </el-button>
          <el-button
            v-show="isHidden"
            type="primary"
            size="small"
            :loading="isLoading"
            @click="submit"
          >
            {
   
   { submitText || $t('common.ok') }}
          </el-button>
          <!-- 审批流 提交时禁止取消-->
          <el-button plain size="small" :disabled="isLoading" @click="cancel">
            {
   
   { cancelText || $t('buttonTxt.cancel') }}
          </el-button>
        </slot>
      </div>
    </div>
  </el-dialog>
</template>

<script>
  import elDragDialog from '@/directive/el-drag-dialog'
  import { Debounce } from '../../utils/public.js'

  export default {
    name: 'DragDialog',
    directives: { elDragDialog },
    props: {
      title: {
        type: String,
        default: '',
      },
      dialogVisible: {
        type: Boolean,
        default: false,
      },
      isNeedFooter: {
        // 是否需要footer, 默认需要
        type: Boolean,
        default: true,
      },
      maxHeight: {
        type: String,
        default: '70vh',
      },
      minHeight: {
        type: String,
        default: '350px',
      },
      width: {
        type: String,
        default: '50%',
      },
      cancelText: {
        type: String,
        default: '',
      },
      submitText: {
        type: String,
        default: '',
      },
      appendToBody: {
        // 是否是嵌套
        type: Boolean,
        default: false,
      },
      destroyOnClose: {
        // 是否关闭时销毁 Dialog 中的元素
        type: Boolean,
        default: true,
      },
      isLoading: {
        type: Boolean,
        default: false,
      },
      moreButtonText: {
        type: String,
        default: '',
      },
      isMore: {
        type: Boolean,
        default: false,
      },
      isHidden: {
        type: Boolean,
        default: true,
      },
      isShowFullScreen: {
        type: Boolean,
        default: false,
      },
    },
    data() {
      return {
        dialogFull: false,
      }
    },
    computed: {
      visible: {
        get() {
          return this.dialogVisible
        },
        set(val) {
          this.$emit('update:dialogVisible', val)
          this.$emit('resetThContent') // 关闭弹窗的时候进行重置
        },
      },
    },
    methods: {
      // v-el-drag-dialog onDrag callback function
      handleDrag() {
        console.log('you had handle drag')
      },
      close() {
        this.$emit('close')
      },
      submit: Debounce(function () {
        this.$emit('submit')
      }, 500),
      cancel() {
        this.visible = false
        this.$emit('cancel')
      },
      getBodyRefs() {
        return this.$refs.dragDialogContainerBody
      },
      moreButton() {
        this.$emit('moreButton')
      },
    },
  }
</script>
<style lang="scss" scoped>
  .drag-dialog-container {
    position: relative;
    padding-bottom: 52px;
    // overflow: auto;
    .main-bar {
      overflow-y: auto;
      overflow-x: hidden;
      padding: 24px 24px 0;
      min-height: 200px !important;
    }
    .dialog-footer {
      width: 100%;
      height: 52px;
      position: absolute;
      bottom: 0;
      left: 0;
      text-align: right;
      padding: 0 20px 0;
      border-top: 1px solid $dashed-01;
      line-height: 52px;
      .el-button--default {
        border: 1px solid #d9d9d9;
      }
      button {
        margin-left: 24px;
        margin-right: 0 !important;
      }
    }
  }
  .el-dialog__header {
    padding: 15px 20px 15px;
  }
  .el-dialog__headerbtn {
    top: 15px;
  }

  /*dialog header*/
  .el-dialog__header {
    background: #e3eaed;
  }
  .avue-crud__dialog__header {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    -webkit-box-pack: justify;
    -ms-flex-pack: justify;
    justify-content: space-between;
  }
  .el-dialog__title {
    color: rgba(0, 0, 0, 0.85);
    font-weight: 500;
    word-wrap: break-word;
  }
  .avue-crud__dialog__menu {
    padding-right: 20px;
    float: left;
  }
  .avue-crud__dialog__menu i {
    color: #909399;
    font-size: 15px;
  }
  .el-icon-full-screen {
    cursor: pointer;
  }
  .el-icon-full-screen:before {
    content: '\e719';
    color: #fff;
    font-size: 22px;
    margin-right: 6px;
  }
</style>

 3. Use the clipboard

<OperateButton
            type="copyPaste"
            copy-paste-function="byTransfer" //传入的使用方式
            :before-paste-open="beforePasteOpen" //传入前的函数判断
            :paste="addDetail"
/>


addDetail(data) {
    //data就是封装那边返回来的数据填写的 需要统一格式可以封装好数据
    //这里若是还需要调接口进行其它操作

    //若是不进行其它操作 只需要商品数据,下面即可
    let list = data.map((item) => {
          return {
            productName: item.productName,
            productCode: item.productCode,
            applyQuantity: item.applyQuantity,
            isSet: true,
          }
        })
    this.$refs.Detailed.list = this.$refs.Detailed.list.concat(list)
}


beforePasteOpen() {
        if (!this.schema_model.businessType) {
          this.$message.error('请先选择业务类型')
          return false
        }
        return true
},

 


Summarize

剪切板有需要的可以自取,有问题可以咨询

Guess you like

Origin blog.csdn.net/weixin_42125732/article/details/130358076