Article directory
Table of contents
1. What is the use of the clipboard?
2. Encapsulate the clipboard component (the pop-up window can be directly used natively)
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
剪切板有需要的可以自取,有问题可以咨询