封装 AInputTable 组件
<!--下拉Table-->
<template><div class="input-select-table" ref="inputTableRef" v-clickoutside="handleHide"><div class="input-select-table-input" @click="disabled?this:handleShow()"><a-inputv-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-tableref="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的stylestyle: {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 = 0this.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-tablekeep-sourceref="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-tablev-elsev-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 = truegetAction(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.partCodethis.currentRow.row.productName = record.partNamethis.currentRow.row.productId = record.idthis.currentRow.row.spec = record.partSpecthis.currentRow.row.uom = record.partUnitthis.currentRow.row.proDesc = record.partDescthis.currentRow.target.setValues([this.currentRow.row])}},//子表单提交验证submitValidate() {let _this = thisreturn 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 = thisdeleteAction(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