封装 AInputTable 组件
<!--下拉Table-->
<template>
<div class="input-select-table" ref="inputTableRef" v-clickoutside="handleHide">
<div class="input-select-table-input" @click="disabled?this:handleShow()">
<a-input
v-model="showValue"
:disabled="disabled"
class="select-table-input"
:placeholder="placeholder"
@change="inputValueChange"
>
<a-icon type="bars" style="color: rgba(0,0,0,.45)" slot="suffix" />
</a-input>
</div>
<div v-bind:class="getTableVisible" :style="tableDivStyle()" ref="tDivTableList">
<t-table
ref="tTableList"
:columns="tableColumn"
:dataSource="dataSource"
:tableConfig="tableConfig"
:tableMethods="tableMethods"
>
</t-table>
</div>
</div>
</template>
<script>
import { getAction } from "@/api/manage";
import { deepClone, filterObj } from '@/utils/util';
import debounce from 'lodash/debounce'
import tTable from '@/components/content/defaultTable'
const clickoutside = {
// 初始化指令
bind(el, binding, vnode) {
function documentHandler(e) {
// 这里判断点击的元素是否是本身,是本身,则返回
if (el.contains(e.target)) {
return false
}
// 判断指令中是否绑定了函数
if (binding.expression) {
// 如果绑定了函数 则调用那个函数,此处binding.value就是handleHide方法
binding.value(e)
}
}
// 给当前元素绑定个私有变量,方便在unbind中可以解除事件监听
el.__vueClickOutside__ = documentHandler;
document.addEventListener('click', documentHandler)
},
update() {
},
unbind(el, binding) {
// 解除事件监听
document.removeEventListener('click', el.__vueClickOutside__);
delete el.__vueClickOutside__
}
};
export default {
name: 'AInputTable',
props: {
placeholder: {
type: String,
required: false,
default: ''
},
disabled: {
type: Boolean,
required: false,
default: false,
},
url: {
type: String,
required: false,
default: ''
},
columns: {
type: Array,
required: false,
default: () => [],
},
value: {
type: String,
required: false,
default: '',
},
saveLabel: {
type: String,
required: false,
default: 'id',
},
showLabel: {
type: String,
required: false,
default: 'name',
},
sorter: {
type: Object,
required: false,
default: ()=>{},
},
queryParams: {
type: Object,
required: false,
default: ()=>{},
},
superQueryParams: {
type: String,
required: false,
default: '',
},
pageSize: {
type: Number,
required: false,
default: 10,
},
rowKey: {
type: String,
required: false,
default: "id",
},
scroll: {
type: Object,
required: false,
default: function () {
return { x:true, y: 300 }
},
},
},
directives: {clickoutside},
components: {
tTable
},
data() {
return {
tableVisible: false,
//----- new -----
dataSource: [],
/* 分页参数 */
ipagination: {
current: 1,
pageSize: this.pageSize,
pageSizeOptions: ['5','10','15','20','30'],
showTotal: (total, range) => {
return range[0] + "-" + range[1] + " 共" + total + "条"
},
showSizeChanger: true,
total: 0
},
isorter: this.sorter,/* 排序参数 */
showValue:'',//展示值
saveValue:'',//保存值
record:{},
/* table加载状态 */
loading: false,
// 存储各个div的style
style: {
tableDiv:{
position: "fixed",
// position: "absolute",
zIndex: "999",
backgroundColor: "#ffffff",
border:"#dedede 1px solid",
padding: "5"
},
},
tableMethods: {
change: this.handleTableChange,
},
}
},
created() {
},
computed: {
tableColumn() {
let jsonColumns = deepClone(this.columns);
return jsonColumns.filter(item => item.dataIndex != 'action')
},
tableConfig() {
return {
pagination: this.ipagination,
loading: this.loading,
rowKey: "id",
size:"small",
scroll: this.scroll,
bordered: true,
customRow: this.onCustomRow
}
},
getTableVisible() {
if (this.tableVisible) {
return 'showTable';
} else {
return 'hideTable';
}
},
},
watch: {
value: {
immediate: true,
handler(val) {
if (val) {
this.saveValue = val;
this.queryShowValueBySaveValue();
} else {
this.saveValue = '';
this.showValue = '';
this.record = {};
this.$emit('getRecord',{});
this.loadData(1);
}
}
},
},
methods: {
loadData(arg) {
if(!this.url){
this.$message.error("AInputTable组件未指定请求url,请设置url属性!")
return
}
//加载数据 若传入参数1则加载第一页的内容
if (arg === 1) {
this.ipagination.current = 1;
}
let params = this.getQueryParams();//查询条件
getAction(this.url, params).then((res) => {
if (res.success) {
this.dataSource = res.result.records;
this.ipagination.total = res.result.total;
}
if(res.code===510){
this.$message.warning(res.message)
}
})
},
getQueryParams() {
let superQueryParamsArr = []
if(this.superQueryParams) {
superQueryParamsArr = JSON.parse(this.superQueryParams)
}
if(this.showValue) {
//对输入文字进行模糊查询
let queryParamsModel = {type: 'string', rule: 'like', field: this.showLabel, val: this.showValue}
superQueryParamsArr.push(queryParamsModel)
}
let sqp = {}
if(superQueryParamsArr) {
sqp['superQueryParams'] = encodeURI(JSON.stringify(superQueryParamsArr))
}
let param = Object.assign(sqp, this.queryParam, this.isorter ,this.filters);
param.field = this.getQueryField();
param.pageNo = this.ipagination.current;
param.pageSize = this.ipagination.pageSize;
return filterObj(param);
},
getQueryField() {
//TODO 字段权限控制
let str = "id,";
this.tableColumn.forEach(function (value) {
str += "," + value.dataIndex;
});
return str;
},
handleHide() { // 点击除了页面其他地方关闭车型选择
this.tableVisible = false;
},
handleShow() {
this.$emit('click', this.saveValue);
this.loadData(1);
this.tableVisible = true;
},
onCustomRow(record) {
return {
props: {},
on: {
click: () => {
this.record = record;
this.saveValue = this.record[this.saveLabel];
this.showValue = this.record[this.showLabel];
this.$emit('select', this.saveValue);
this.$emit('input', this.saveValue);
this.$emit('change', this.saveValue);
this.$emit('getRecord',this.record);
this.handleHide();
},
},
};
},
inputValueChange(e) {
this.showValue = e.target.value;
this.$emit('inputChange',e.target.value);
if(this.showValue === null || this.showValue === undefined || this.showValue === ''){
this.clear();
}
debounce(()=>{this.loadData(1)}, 1000);
},
getShowValue(){
return this.showValue;
},
getSaveValue(){
return this.saveValue;
},
clear() {
this.saveValue = '';
this.showValue = '';
this.record = {};
this.$emit('select', '');
this.$emit('input', '');
this.$emit('change', '');
this.$emit('getRecord',{});
this.handleHide();
},
handleTableChange(pagination, filters, sorter) {
//分页、排序、筛选变化时触发
//TODO 筛选
if (Object.keys(sorter).length > 0) {
this.isorter.column = sorter.field;
this.isorter.order = "ascend" == sorter.order ? "asc" : "desc"
}
this.ipagination = pagination;
this.loadData();
},
queryShowValueBySaveValue(page = 1) {
let params = this.getQueryParams(); // 查询条件
params.pageNo = page; // 设置当前页码
params.pageSize = this.ipagination.pageSize; // 设置每页记录数
getAction(this.url, params).then((res) => {
if (res.success) {
this.dataSource = res.result.records;
this.ipagination.total = res.result.total;
// 在当前页查找目标值
let found = false;
for (let i = 0; i < this.dataSource.length; i++) {
const item = this.dataSource[i];
if (item && item[this.saveLabel] == this.saveValue) {
this.showValue = item[this.showLabel];
this.record = item;
this.ipagination.current = page; // 更新当前页码
found = true;
break;
}
}
if (!found && page * params.pageSize < res.result.total) {
// 如果当前页未找到目标值且还有下一页,继续查找下一页
this.queryShowValueBySaveValue(page + 1);
}
} else {
this.$message.warning(res.message);
}
});
},
//表格div样式
tableDivStyle() {
let style = Object.assign({}, this.style.tableDiv)
let width1 = this.getDivTopLength();
let width2 = this.realTrWidth();
if(width1>width2){
style['width'] = width2+"px";
}else {
style['width'] = width1+"px";
}
this.scroll.x = style.width
//设置表格div的位置样式
this.setTableDivPosition()
return style
},
//设置表格div的位置样式
setTableDivPosition() {
this.$nextTick(() => {
if (this.$refs.inputTableRef && this.$refs.tDivTableList) {
let tDivTableList = this.$refs.tDivTableList
// 输入框在页面上的位置
const inputBox = this.$refs.inputTableRef.getBoundingClientRect();
// 视口高度
const viewportHeight =
window.innerHeight || document.documentElement.clientHeight;
// 视口高度 - 输入框元素底距离视顶的高度 = 输入框距离视口下方的高度
let inputBoxBottomDistance = viewportHeight - inputBox.bottom;
// 表格的高度
let selectTableHeight = tDivTableList.offsetHeight + 8;
// 如果下方的距离不够表格展示
if (inputBoxBottomDistance < selectTableHeight) {
tDivTableList.style.top = inputBox.top - selectTableHeight + "px";
} else {
tDivTableList.style.top = inputBox.top + inputBox.height + "px";
}
}
})
},
//table 列总宽度
realTrWidth() {
let calcWidth = 0
this.tableColumn.forEach((column, i) => {
let { type, width } = column
// 隐藏字段不参与计算
if (typeof width === 'number') {
calcWidth += width
} else if (typeof width === 'string') {
width = width.replace("px","");
calcWidth += Number(width)
} else {
calcWidth += Number('120')
}
})
return calcWidth
},
//获取指定第v据屏幕右侧宽度
getDivTopLength() {
return 600;
},
},
//2.2新增 在组件内定义 指定父组件调用时候的传值属性和事件类型
model: {
prop: 'value',
event: 'input'
}
}
</script>
<style scoped lang="less">
.input-select-table {
width: 91%;
.showTable {
display: block;
}
.hideTable {
display: none;
}
.select-table-input {
margin-right: 20px;
}
/deep/ .ant-spin-container > .ant-table > .ant-table-content > .ant-table-scroll > .ant-table-header {
overflow: hidden !important;
overflow-y: scroll !important;
margin-bottom: 0 !important;
}
}
</style>
参数配置
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
placeholder | String | 输入框未填值展示提示信息 | |
disabled | Boolean | true/false 默认false | |
value | String | 绑定v-model或是v-decorator后不需要设置 | |
columns | Array | 表格列的配置描述 | |
url | String | table 数据源请求地址 查询需返回带分页的数据 | |
sorter | Object | 排序字段及排序方式 { column: this.sorter, order: ‘desc’ } | |
saveLabel | String | 选中实际保存字段 | |
showLabel | String | 选中输入框展示字段 | |
queryParams | String | 查询条件 | |
pageSize | String | 指定每页显示条数 | |
rowKey | String | 指定rowKey 默认id 没有id时指定 | |
scroll | String | 设置显示Table高度限制,超出指定高度 滚动展示 | |
superQueryParams | String | 高级查询条件 |
使用示例
<template>
<div style="padding: 0 15px">
<j-vxe-table
keep-source
ref="vTable"
:loading="loading"
:columns="columns"
:dataSource="dataSource"
:maxHeight="400"
:disabled="formDisabled"
:toolbar="true"
:bordered="true"
class="model_table"
:alwaysEdit="true"
@valueChange="handleValueChange"
>
<template v-slot:action="props">
<a-popconfirm :title="$t('system.confirmDelete') + '?'" @confirm="handleDelete(props)">
<a>{{$t('system.delete')}}</a>
</a-popconfirm>
</template>
<template v-slot:productCode="props">
<span v-if="formDisabled" >{{props.value}}</span>
<a-input-table
v-else
v-model="props.value"
:columns="partColumns"
:url="partUrl.list"
:show-label="'partCode'"
:save-label="'partCode'"
:super-query-params="superQueryParams"
@getRecord="getProductCodeRecord($event, props)"
>
</a-input-table>
</template>
</j-vxe-table>
</div>
</template>
<script>
import '@/assets/less/TableExpand.less'
import {deleteAction, getAction, httpAction} from '@/api/manage'
import { columns, url, storageQuantityCol } from './config'
import { deepClone } from '@/utils/util'
import AInputTable from '@/components/common/AInputTable'
import { selectPartColumns as partColumns, url as partUrl } from '@/views/psi/psiBasics/psiPart/config/index'
import {ajaxGetDictItems, getDictItemsFromCache} from "@/api/api";
export default {
name: 'PsiPurchaseDetailList',
props: {
//表单禁用
disabled: {
type: Boolean,
default: false,
required: false
},
parentModel: {
type: Object,
default: () => {},
required: false
}
},
components: {
AInputTable
},
data() {
return {
description: '表体页面',
dictOptions: {},
superFieldList: [],
disableMixinCreated: true,
dataSource: [],
loading: false,
// 表头
columns,
url,
storageQuantityCol,
partColumns,
partUrl,
currentRow: {},
superQueryParams: JSON.stringify([{field: 'partStatus', rule: 'in', type: 'string', val: '1'}]),
}
},
watch: {
},
computed: {
formDisabled() {
return this.disabled
},
},
methods: {
//获取列表
getDataList(purchaseId) {
if(!purchaseId) {
return
}
this.loading = true
getAction(this.url.list, {purchaseId: purchaseId, pageSize: 50}).then(res => {
if (res.success) {
this.dataSource = res.result.records || res.result
}
}).finally(() => {
this.loading = false
})
},
//产品编号选择
getProductCodeRecord(record, props) {
this.currentRow = props;
//物料确认选择
this.selectConfirmOk(record)
},
//物料确认选择
selectConfirmOk(record) {
if(this.currentRow.row) {
this.currentRow.row.productCode = record.partCode
this.currentRow.row.productName = record.partName
this.currentRow.row.productId = record.id
this.currentRow.row.spec = record.partSpec
this.currentRow.row.uom = record.partUnit
this.currentRow.row.proDesc = record.partDesc
this.currentRow.target.setValues([this.currentRow.row])
}
},
//子表单提交验证
submitValidate() {
let _this = this
return new Promise(function(resolve, reject){
_this.$refs.vTable.validateTable().then(errMap => {
if (errMap) {
resolve(false)
} else {
const values = _this.$refs.vTable.getTableData()
if(!(values && values.length > 0)) {
_this.$message.warning("至少有一条明细!")
resolve(false)
} else {
resolve(true)
}
}
})
});
},
getSubData() {
return this.$refs.vTable.getTableData()
},
//删除方法
handleDelete(props) {
if (!this.url.delete) {
this.$message.error('请设置url.delete属性!')
return
}
props.target.removeRows(props.row)
let that = this
deleteAction(that.url.delete, { id: props.rowId }).then(res => {
if (res.success) {
//重新计算分页问题
that.$message.success(res.message)
} else {
that.$message.warning(res.message)
}
})
},
//监听输入值改变
handleValueChange(e) {
},
}
}
</script>
参考博客链接:https://blog.csdn.net/weixin_44912745/article/details/125407433