1.src文件夹下的components-》table -》index.js
import MTable from './table.vue';
import MyTable from './table1.vue';
export default (Vue)=>{
Vue.component("MTable", MTable);
Vue.component("myTable", MyTable)
}
2.src文件夹下的components-》table -》table1.vue (组件)
/**
* 自定义table组件
********** columns:表头信息 **********
* @type: index -- 序号
* checkbox -- 多选框
* date -- 日期组件
* imgUpdata -- 图片上传
* select -- 下拉框
* button -- 按钮
* @width: 宽
* @title: 表头
* @thClass: 表头class
* @tdClass: 表列class
* @key: 字段名
* @onBlur: 失焦事件
* @onChange: change事件
* @onClick: click事件
* @tdClass: 表列class
* @option:{
optionList:下拉框的列表
optionValueKey: 绑定的value值得字段名,
optionLabelKey: [],数组最多2个label字段名
* }
* @filterable: 下拉框可搜索
* @disabled: 下拉框禁用
* @clearable: 可清空下拉框内容
* @butTitle: button名
*CheckboxGroup 是一个多选框组件
* 注:optionList必须获取到list再赋值
***************** tableData:列表数据 **********
******* tableCheck:多选框绑定行的index ********
***********************************************
* 具体参考addAdvanceOrde.vue文件 *
***********************************************
*/
<template>
<div class="me-table">
<CheckboxGroup v-model="selections" @on-change="selectionsChange">
<div class="ivu-table-wrapper" :style="height ? {height: height + 'px'} : ''">
<div class="ivu-table ivu-table-small ivu-table-border ivu-table-with-fixed-top" style="overflow:auto;min-height:80px">
<table cellspacing="0" cellpadding="0" border="0" style=" 100%;">
<thead class="ivu-table-header">
<tr>
<th style="white-space: normal" class="ivu-table-column-center" v-for="(item, index) in columns" :width="item.width" :class="item.thClass">
<span v-if="item.type === 'index'">#</span>
<span v-else-if="item.type === 'checkbox'">选择</span>
<span v-else>{{item.title}}</span>
<span v-if="item.copyIcon">
<Icon type="ios-copy-outline" size="17" class="copyIcon" @click="copyFun(item.key)"></Icon>
</span>
</th>
</tr>
</thead>
<tbody class="ivu-table-tbody">
//tableData获取的后台列表数据 trItem数据用于v-model绑定数据 trIndex下标哪一行
<tr class="ivu-table-row" v-for="(trItem, trIndex) in tableData">
//tdItem 遍历的是 使用组件页面的columnsEdit的数据
<td class="ivu-table-column-center" v-for="(tdItem, tdIndex) in columns" :class="tdItem.tdClass">
<span v-if="tdItem.type === 'index'">{{trIndex + 1}}</span>
<span v-else-if="tdItem.type === 'checkbox'">
<Checkbox :label="trIndex"><span> </span></Checkbox>
</span>
<!--
-----
------
组件页面中的<span tdItem.type === 'input' && tdItem.onChange && tdItem.onKeyUp >
<Input v-model="trItem[tdItem.key]" :placeholder="tdItem.placeholder" :class="tdItem.inputClass" @on-blur="tdItem.onBlur(trItem, trIndex)" @keyup.native="tdItem.onKeyUp($event, trItem, trIndex)" />
</span>
是判断使用组件页面的:columns="columnsEdit"中对象中的type:是否为input 并且有onChange onKeyUp 属性 如果有就调用span这个组件元素
调用组件的页面
<my-table v-if="btnType[0]" :columns="columnsEdit" :tableData="tableData" :tableCheck="selects" height="650"></my-table>
this.columnsEdit = [
{
title: '工厂报价',
type: 'input',
'130',
key: 'factoryQuote',//和后端的key对应也就是 tableData遍历过后的 trItem[tdItem.key]
thClass: 'headerColor',
inputClass: this.message === 1 ? 'table_input normal_1 input_color1' : this.message === 2 ? 'table_input normal_1 input_color2' : 'table_input normal_1',
placeholder: this.message === 2 ? '未查询到核价单' : this.message === 1 ? '查询到多条结果请确认' : '',
onBlur: this.factoryQuoteChange,
onKeyUp: this.show,
copyIcon: true
}
]
下面这么多的span v-if v-else-if ....是为了判断调用组件的页面用哪一个span
------
------
-->
<span v-else-if="tdItem.type === 'input' && tdItem.onChange">
<Input v-model="trItem[tdItem.key]" :placeholder="tdItem.placeholder" @on-change="tdItem.onChange(trItem, trIndex)" />
</span>
<span v-else-if="tdItem.type === 'input' && tdItem.onKeyUp">
<Input v-model="trItem[tdItem.key]" :placeholder="tdItem.placeholder" :class="tdItem.inputClass" @keyup.native="tdItem.onKeyUp($event, trItem, trIndex)" />
</span>
<span v-else-if="tdItem.type === 'input' && tdItem.onKeyUp && tdItem.onBlur"> //键盘事件
<Input v-model="trItem[tdItem.key]" :placeholder="tdItem.placeholder" :class="tdItem.inputClass" @on-blur="tdItem.onBlur(trItem, trIndex)" @keyup.native="tdItem.onKeyUp($event, trItem, trIndex)" />
</span>
<span v-else-if="tdItem.type === 'input' && tdItem.onBlur">
<Input v-model="trItem[tdItem.key]" :placeholder="tdItem.placeholder" @on-blur="tdItem.onBlur(trItem, trIndex)" />
</span>
<!--日期-->
<span v-else-if="tdItem.type === 'date'">
<DatePicker type="date" :value="trItem[tdItem.key]" @on-change="trItem[tdItem.key]=$event" :editable="false" clearable></DatePicker>
</span>
<span v-else-if="tdItem.type === 'input' && !tdItem.onChange && !tdItem.onBlur && !tdItem.onKeyUp">
<Input v-model="trItem[tdItem.key]" :placeholder="tdItem.placeholder" :maxlength="tdItem.maxlength" />
</span>
<span v-else-if="tdItem.type === 'select' && tdItem.onChange">
<Select ref="select" v-model="trItem[tdItem.key]" @on-change="tdItem.onChange(trItem, trIndex)" :filterable="tdItem.filterable" :disabled="tdItem.disabled"
:clearable="tdItem.clearable">
<Option v-for="item in tdItem.option.optionList" :value="item[tdItem.option.optionValueKey]" :key="item[tdItem.option.optionKey]?item[tdItem.option.optionKey]:item[tdItem.option.optionValueKey]"
:label="tdItem.option.optionLabelKey.length === 1 ? item[tdItem.option.optionLabelKey[0]] : tdItem.option.optionLabelKey.length === 2 ?item[tdItem.option.optionLabelKey[0]] + '-' + item[tdItem.option.optionLabelKey[1]]:item[tdItem.option.optionLabelKey[0]] + '-' + item[tdItem.option.optionLabelKey[1]]+'-'+item[tdItem.option.optionLabelKey[2]]"></Option>
</Select>
</span>
<span v-else-if="tdItem.type === 'select' && !tdItem.onChange">
<Select ref="select1" v-model="trItem[tdItem.key]" :filterable="tdItem.filterable" :disabled="tdItem.disabled" :clearable="tdItem.clearable">
<Option v-for="item in tdItem.option.optionList" :value="item[tdItem.option.optionValueKey]" :key="item[tdItem.option.optionKey]?item[tdItem.option.optionKey]:item[tdItem.option.optionValueKey]"
:label="tdItem.option.optionLabelKey.length === 1 ? item[tdItem.option.optionLabelKey[0]] : tdItem.option.optionLabelKey.length === 2 ?item[tdItem.option.optionLabelKey[0]] + '-' + item[tdItem.option.optionLabelKey[1]]:item[tdItem.option.optionLabelKey[0]] + '-' + item[tdItem.option.optionLabelKey[1]]+'-'+item[tdItem.option.optionLabelKey[2]]"></Option>
</Select>
</span>
<span v-else-if="tdItem.type === 'button'">
<Button type="info" @click="tdItem.onClick(trItem, trIndex)" size="small">{{tdItem.butTitle}}</Button>
</span>
<span v-else v-html="trItem[tdItem.key]"></span>
</td>
</tr>
</tbody>
</table>
<div v-if="!tableData.length" class="no-data">暂无数据</div>
</div>
</div>
</CheckboxGroup>
</div>
</template>
<script>
import {
getImgBlobSrc
} from '@/libs/util'
export default {
//导出的tableData columns tableCheck....都是需要父页面传的数据,(:绑定的数据)
name: 'myTable',
props: {
// 选择供应商之后增加明细的数据(更改供应商时可以获取到该数据)
tableData: {
type: Array,
default () {
return []
}
},
height: {
type: String
},
// 点击增加明细之后 弹框确定之后需要添加的table数据
columns: {
type: Array,
default () {
return []
}
},
tableCheck: {
type: Array,
default () {
return []
}
}
},
data() {
return {
modelData: [],
selections: this.tableCheck,
imgIndex: '',
imgKey: ''
}
},
mounted() {
let self = this
this.$(".ivu-table-row").hover(function () {
self.$(this).addClass('ivu-table-row-hover')
}, function () {
self.$(this).removeClass('ivu-table-row-hover')
})
},
methods: {
selectionsChange() {
this.tableCheck.splice(0, this.tableCheck.length)
this.selections.forEach(ele => {
this.tableCheck.push(ele)
})
},
copyFun(key) {
if(key === 'qualifiedQuantity'){
this.tableData.forEach(ele => {
this.$set(ele, key, ele.quantity)
ele.unqualifiedQuantity = ele.qualifiedQuantity && ele.quantity ? Number(ele.quantity) - Number(ele.qualifiedQuantity) : ''
})
return
}
if (!this.tableData[0][key] && this.tableData[0][key] != 0) {
this.$Message.warning('第一行值为空,不能复制!')
return
}
this.tableData.forEach(ele => {
this.$set(ele, key, this.tableData[0][key])
})
if (key === 'taxUnitPrice' || key === 'taxRate') {
this.tableData.forEach(ele => {
if ((ele.taxUnitPrice || ele.taxUnitPrice == 0) && (ele.taxRate || ele.taxRate == 0)) {
let unitPrice = ele.taxUnitPrice / (1 + ele.taxRate / 100)
this.$set(ele, 'unitPrice', unitPrice.toFixed(4))
}
})
}
},
uploadImg(file) {
let formData = new FormData()
formData.append('file', file)
this.$axios({
url: '/chenfan_api/file/upload',
method: 'post',
data: formData
}).then((data) => {
if (data.code === 200) {
this.$set(this.tableData[this.imgIndex], [this.imgKey], data.obj[0].id)
}
})
return false
},
getImgIndex(index, key) {
this.imgIndex = index
this.imgKey = key
},
removeImg(key, index) {
this.tableData[index][key] = ''
}
},
watch: {
tableCheck(newVal, oldVal) {
this.selections = newVal
}
}
}
</script>
<style lang="less">
.me-table {
.ivu-table-wrapper {
min-height: 80px;
}
.ivu-table-row {
td {
padding: 0 5px;
}
}
.no-data {
position: absolute;
top: 50%;
left: 50%;
font-size: 14px;
}
.demo-upload-list {
display: inline-block;
70px;
height: 70px;
text-align: center;
line-height: 70px;
border: 1px solid transparent;
border-radius: 4px;
overflow: hidden;
background: #fff;
position: relative;
box-shadow: 0 1px 1px rgba(0, 0, 0, .2);
margin-right: 4px;
}
.demo-upload-list img {
100%;
height: 100%;
}
.demo-upload-list-cover {
display: none;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, .6);
}
.demo-upload-list:hover .demo-upload-list-cover {
display: block;
}
.demo-upload-list-cover i {
color: #fff;
font-size: 20px;
cursor: pointer;
margin: 0 2px;
}
.span-img {
display: inline-block;
padding: 5px 0;
}
.ivu-checkbox-group-item {
20px;
height: 20px;
overflow: hidden;
}
}
</style>
3.使用组件的页面
<Card style="margin-top: 20px;">
<!-- table1组件 -->
<my-table v-if="btnType[0]" :columns="columnsEdit" :tableData="tableData" :tableCheck="selects" height="650"></my-table>
</Card>
//tableData获取的后台列表数据
tableData:[ ],
//编辑
this.columnsEdit = [
{
type: 'index',
'40'
}, {
type: 'checkbox',
'40'
}, {
title: '品牌',
'100',
key: 'brandName'
},
{
title: '货号',
'110',
key: 'productCode'
}, {
title: '存货编码',
'120',
key: 'inventoryCode',
thClass: 'headerColor'
}, {
title: '存货名称',
'160',
key: 'inventoryName'
}, {
title: '颜色',
'100',
key: 'color'
}, {
title: '尺码',
'100',
key: 'size'
}, {
title: '季节',
'100',
key: 'season'
}, {
title: '工厂报价',
type: 'input',
'130',
key: 'factoryQuote',
thClass: 'headerColor',
inputClass: this.message === 1 ? 'table_input normal_1 input_color1' : this.message === 2 ? 'table_input normal_1 input_color2' : 'table_input normal_1',
placeholder: this.message === 2 ? '未查询到核价单' : this.message === 1 ? '查询到多条结果请确认' : '',
onBlur: this.factoryQuoteChange,
onKeyUp: this.show,//this.show是一个方法
copyIcon: true
}, {
title: '含税单价',
type: 'input',
'130',
key: 'taxUnitPrice',
thClass: 'headerColor',
onBlur: this.taxUnitPriceChange,
onKeyUp: this.show,
placeholder: this.message === 2 ? '未查询到核价单' : this.message === 1 ? '查询到多条结果请确认' : '',
inputClass: this.message === 1 ? 'table_input normal_2 input_color1' : this.message === 2 ? 'table_input normal_2 input_color2' : 'table_input normal_2',
copyIcon: true
}, {
title: '不含税单价',
'100',
key: 'unitPrice'
}, {
title: '税率',
type: 'select',
'110',
key: 'taxRate',
option: {optionList: taxRateList, optionValueKey: 'key', optionLabelKey: ['key']},
thClass: 'headerColor',
onChange: this.taxRateChange,
copyIcon: true
}, {
title: '调价原因',
type: 'input',
'160',
key: 'remark',
thClass: 'headerColor',
onKeyUp: this.show,
inputClass: 'table_input normal_3',
copyIcon: true
},{
title: '合同初始交期',
type: 'date',
'150',
key: 'conStartDate',
copyIcon: true,
thClass: 'headerColor'
}
]
// 删除行
deleteTrFun () {
let _arr = []
if (!this.selects.length) this.$Message.warning('请先选择行!')
this.tableData.forEach((ele, index) => {
console.log(this.selects, 22)
if (this.selects.indexOf(index) < 0) _arr.push(ele)
})
this.productList.splice(this.selects, 1)
console.log(this.productList, 333)
this.selects = []
this.tableData = _arr
if(!this.tableData.length){
this.btnType[1] = true
}
},
// 键盘触发事件 item==组件里的$event 也就是当前元素this trItem== row 这一条数据 trIndex===index第几行
show (item, row, index) {
let newIndex;
// 通过ev获取当前input的class名称,用于后期判断属于哪列
let className = item.target.offsetParent.className;
console.log(item, index);
// 每一列 inputClass中的normal_1 normal_2 normal_3 是用来判断当前焦点在哪个input的上 用于后期上下左右键盘可以控制移动到某个input
if (className.indexOf('normal_1') !== -1) {
this.data = index;
this.didata = index*3;
newIndex = index*3;
} else if (className.indexOf('normal_2') !== -1) {
this.data = index;
this.didata = index*3 + 1;
newIndex = index*3 + 1;
} else if (className.indexOf('normal_3') !== -1) {
this.data = index;
this.didata = index*3 + 2;
newIndex = index*3 + 2;
}
// 获取所有input
let inputAll = document.querySelectorAll('.table_input input');
this.iddata = inputAll;
// 向上 =38
if (item.keyCode === 38) {
newIndex -= 3;
if (inputAll[newIndex]) {
inputAll[newIndex].focus();
}
}
// 向下 =40
if (item.keyCode === 40) {
newIndex += 3;
if (inputAll[newIndex]) {
inputAll[newIndex].focus();
}
}
// 向左
if (item.keyCode === 37) {
newIndex -= 1;
if (inputAll[newIndex]) {
inputAll[newIndex].focus();
}
}
// 向右
if (item.keyCode === 39) {
newIndex += 1;
if (inputAll[newIndex]) {
inputAll[newIndex].focus();
}
}
}