引入表单组件的封装 searchForm.vue
<template>
<div class="search_bar">
<el-form ref="searchForm" class="search-form FormTheHeadIpt" :inline='true' :model="searchForm">
<template v-for="(col,col_i) in conf">
<el-form-item :key="'form_'+col_i">
<!-- input -->
<el-input v-model="searchForm[col.prop]" :placeholder="col.placeholder" clearable @keyup.enter.native='search' v-if="col.type==='input'" :disabled="col.disabled" @change="change('input',col.prop,searchForm[col.prop])"></el-input>
<!-- 下拉选项 -->
<el-select v-model="searchForm[col.prop]" v-else-if="col.type === 'select'" :placeholder="col.placeholder" @change="change('select',col.prop,searchForm[col.prop])"
:disabled="col.disabled" :filterable="col.filterable" clearable :multiple="col.multiple" :value-key="col.selectValueKey || 'id'">
<el-option v-for="(colItem,i) in (selectOptions[col.prop] || col.selectOptions || [])" :key="'op_'+ col_i+'_'+i"
:label="colItem.label" :value="col.selectValueKey ? colItem : colItem.value" :disabled="colItem.disabled">
</el-option>
</el-select>
<!-- 时间 -->
<el-date-picker v-else-if="col.type === 'date'" v-model="searchForm[col.prop]" type="date" :placeholder="col.placeholder" :value-format="col.valueFormat || 'yyyy-MM-dd'" :picker-options="col.pickerOptions" @change="change('date',col.prop,searchForm[col.prop])"></el-date-picker>
<el-date-picker v-else-if="col.type === 'date-2'" v-model="searchForm[col.prop]" type="daterange" :value-format="col.valueFormat || 'yyyy-MM-dd'" :picker-options="col.pickerOptions" @change="change('date-2',col.prop,searchForm[col.prop])"
:range-separator="col.range || '-'" :start-placeholder="col.placeholder[0] || '请选择'" :end-placeholder="col.placeholder[1] || '请选择'"></el-date-picker>
<!-- 其他 -->
<slot v-else-if="col.slotName" :name="col.slotName"/>
</el-form-item>
</template>
<el-form-item>
<el-tooltip class="item" effect="dark" content="查询" placement="top">
<el-button @click="search" class="search-button"></el-button>
</el-tooltip>
<el-tooltip class="item" effect="dark" content="重置" placement="top">
<el-button @click="reset" class="reset-button"></el-button>
</el-tooltip>
<template v-for="(item,i) in btnMore || []">
<el-tooltip class="item" :effect="item.effect || 'dark'" :content="item.content" placement="top" :key="i" v-if="item.content">
<el-button @click="btnMoreAction(item)" :class="item.icon" :disabled="disabledOptions[item.btnKey] !== 'undefined' ? item.disabled :disabledOptions[item.btnKey]">{{item.text}}</el-button>
</el-tooltip>
<el-button v-else @click="btnMoreAction(item)" :class="item.icon" :disabled="disabledOptions[item.btnKey] !== 'undefined' ? item.disabled :disabledOptions[item.btnKey]" :key="i">{{item.text}}</el-button>
</template>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name:'searchForm',
props:{
/*
*prop:表单字段名,value:默认值,lable:表单名称,placeHolder:提示,disabled:禁用 selectValueKey:作为下拉选项的输出为对象时刻的关键KEY,此时输出为对象
*range:分隔符
*/
formConf:{
type:Array,
default:()=>([])
},
// 全局下拉选项
selectOptions:{
type:Object,
default:()=>({})
},
// 更多按钮 【{btnKey:icon:类名,text:按钮文字,disabled:时候禁用,content:提示内容,effect样式}】
btnMore:Array,
//btnMore中的按钮独立控制,此时btnMore 中必须要有btnKey:name
disabledOptions:{
type:Object,
default:()=>({})
}
},
data(){
return {
conf:[{}],
searchForm:this.formConf.reduce((p,c) =>{p[c['prop']] = c['value'];return p},{})
}
},
mounted(){
this.$nextTick( _ => {
this.$emit('initSearch',this.search)
})
},
watch:{
formConf:{
handler(cval){
this.conf = cval
},
deep:true,
immediate:true
}
},
methods:{
search(){
this.$emit('searchQuery',this.searchForm)
},
change(type,prop,value){
const params = {
type,prop,value,data:this.searchForm
}
this.$emit('change',params)
},
reset(){
this.searchForm = Object.keys(this.searchForm).reduce( (p,c)=>{
const att = this.formConf.find( v => v.prop === c)
if( (att.type === 'select' && !!att.multiple ) || att.type === 'date-2') {
p[c] = []
}else {
p[c] = ''
}
return p
},{})
this.$emit('resetAll',this.searchForm)
},
// 按钮事件抛出
btnMoreAction(item){
this.$emit('btnMoreAction',item)
}
}
}
</script>
<style lang="scss" scoped>
.search_bar{
.el-range-editor--small.el-input__inner{
height: 36px;
}
}
</style>
引入表格组件中使用 pushTable.vue中使用 这里使用到JS 变量控制SCSS样式
<template>
<div class="search-card">
<searchForm @searchQuery="search" :formConf="formConf" v-if="formConf.length" @resetAll="resetAll" :selectOptions="selectOptions" @initSearch="initSearch"
@btnMoreAction="btnMoreAction" :btnMore="btnMore" @change="change"/>
<div class="table-list" name="列表">
<div class="table-padding_both">
<el-table
class="c-table kyol-table_empty kyol-table_fixed"
:max-height="tableMaxHeight"
:data="tableData"
:style="{width: '100%','--expand':expandPadding}"
@filter-change="filterChange"
@select="select"
@select-all="select"
v-loading="loading"
v-if="showTbale"
ref="pushTable"
:height="tableHeight"
>
<template v-if="showTitle">
<el-table-column :label="showTitle" header-align="center">
<el-table-column v-if="showSelection" type="selection" fixed="left" :selectable="selectable"> </el-table-column>
<!-- 索引列 -->
<el-table-column v-if="showIndex" type="index" :label="showIndex.label || '序号'" :header-align="showIndex.headerAlign || 'left'" :align="showIndex.align || 'left'" :fixed="showIndex.fixed" :width="showIndex.width || '60px'"/>
<template v-for="(item,i) in tableConf">
<!-- 正常列 -->
<template v-if="!item.insertHeader">
<el-table-column :key="'tab'+i" :prop="item.prop" :label="item.label" :width="item.width" :filters="item.filters" :min-width="item.minWidth"
:header-align="item.headerAlign||'left'" :align="item.align || 'left'" :column-key="item.columnKey" show-overflow-tooltip>
<template slot-scope="{row}">
<div class="eslpse">
<!-- 正常的 如果带入函数 返回值 则使用函数带入 -->
<span v-if="!item.money" :style="{color:item.colors ? item.colors.get(row[item.prop]) : ''}">{{item.func ? item.func(row[item.prop]) : row[item.prop]}}</span>
<!-- 列配置 money为真 则 金钱格式化 -->
<span v-else>{{row[item.prop] | toMoney | addMoneyPre}}</span>
</div>
</template>
</el-table-column>
</template>
<!-- 过滤器列 -->
<el-table-column :key="'tab'+i" v-else width="160px">
<template slot="header" slot-scope="{column,$index}">
<div class="kyol-column_header" v-if="!item.slotHeadName">
<selectDataRange @search="dateQuery" :columnKey="item.columnKey" :columnName="item.label" ></selectDataRange>
</div>
<slot :name="item.slotHeadName" :column="column" :index="$index" v-else/>
</template>
<template slot-scope="{row}">
<div>
{{row[item.prop]}}
</div>
</template>
</el-table-column>
</template>
<slot name="lastColumn" v-if="lastColumn">
<el-table-column
header-align="center"
align="center"
label="操作"
fixed="right"
>
<template slot-scope="{row,$index}">
<div v-if="!btnSlot">
<template v-for="(btn,btn_i) in (btns || row.btns || [])">
<el-button :key="btn_i" type="text" @click="handlerClick(row,$index)" :style="{color:btn.color}" v-if="!btn.hide || !row.hideBtns.includes(btn.label)">{{btn.label}}</el-button>
</template>
</div>
<div v-else>
<slot name="btnSlot" :row="row" :index="$index"></slot>
</div>
</template>
</el-table-column>
</slot>
</el-table-column>
</template>
<!-- 下面是没有带有表头标题的表格 -->
<template v-else>
<el-table-column v-if="showSelection" type="selection" fixed="left" :selectable="selectable"> </el-table-column>
<!-- 索引列 -->
<el-table-column v-if="showIndex" type="index" :label="showIndex.label || '序号'" :header-align="showIndex.headerAlign || 'left'" :align="showIndex.align || 'left'" :fixed="showIndex.fixed" :width="showIndex.width || '60px'"/>
<!-- 扩展内部展示块 -->
<el-table-column type="expand" v-if="showExpand">
<template slot-scope="{row,$index}">
<slot :name="showExpand" :row="row" :index="$index"/>
</template>
</el-table-column>
<template v-for="(item,i) in tableConf">
<!-- 正常列 -->
<template v-if="!item.insertHeader">
<el-table-column :key="'tab'+i" :prop="item.prop" :label="item.label" :width="item.width" :filters="item.filters" :min-width="item.minWidth"
:header-align="item.headerAlign||'left'" :align="item.align || 'left'" :column-key="item.columnKey" show-overflow-tooltip>
<template slot-scope="{row}">
<div class="eslpse">
<!-- 正常的 如果带入函数 返回值 则使用函数带入 -->
<span v-if="!item.money" :style="{color:item.colors ? item.colors.get(row[item.prop]) : ''}">{{item.func ? item.func(row[item.prop]) : row[item.prop]}}</span>
<!-- 列配置 money为真 则 金钱格式化 -->
<span v-else>{{row[item.prop] | toMoney | addMoneyPre}}</span>
</div>
</template>
</el-table-column>
</template>
<!-- 过滤器列 -->
<el-table-column :key="'tab'+i" v-else :width="item.width || '160px'">
<template slot="header" slot-scope="{column,$index}">
<div class="kyol-column_header" v-if="!item.slotHeadName">
<selectDataRange @search="dateQuery" :columnKey="item.columnKey" :columnName="item.label" ></selectDataRange>
</div>
<slot :name="item.slotHeadName" :column="column" :index="$index" v-else/>
</template>
<template slot-scope="{row}">
<div>
{{row[item.prop]}}
</div>
</template>
</el-table-column>
</template>
<slot name="lastColumn" v-if="lastColumn">
<el-table-column
header-align="center"
align="center"
label="操作"
fixed="right"
>
<template slot-scope="{row,$index}">
<div v-if="!btnSlot">
<template v-for="(btn,btn_i) in (btns || row.btns || [])">
<el-button :key="btn_i" type="text" @click="handlerClick(row,$index)" :style="{color:btn.color}" v-if="!btn.hide || !row.hideBtns.includes(btn.label)">{{btn.label}}</el-button>
</template>
</div>
<div v-else>
<slot name="btnSlot" :row="row" :index="$index"></slot>
</div>
</template>
</el-table-column>
</slot>
</template>
</el-table>
</div>
<page
style="margin-top:10px;"
v-if="showPaginaition"
:size-change="handleSizeChange"
:current-change="handleCurrentChange"
:page-config="pageConfig" ></page>
</div>
</div>
</template>
<script>
import searchForm from '../components/searchForm'
import selectDataRange from "@/components/resourceManagement1/components/selectDataRange"
const creater = () => {
const createdField = (fieldL = 'label',fieldV = 'prop',surplus) => (label,prop,options ) => ({[fieldL]:label,[fieldV]:prop,...surplus,...options})
const setField = (label,list,compareValue = 'label') => func => {
const field = list.find(v => v[compareValue] === label) || {}
if(!Object.keys(field)){
list.push(field)
}
func(field)
return list
}
return {createdField,setField}
}
const createdDefault = creater()
export default {
name:'searchList',
components:{searchForm,selectDataRange},
props:{
// 表单配置对象 {prop:表单字段名,}
formConf:{
type:Array,
default:()=>([])
},
// 表格配置
/*
column=>
insertHeader 时候需要表头单独设置;label:表头文字,prop:对应数据row字段名,width:宽度,fixed:固定列
filters:过滤配置
align:对其
headerAlign:表头对其
money: Boolean 是否显示金钱 格式带¥
color:文字颜色 类型为 new Map()的对象格式返回值
func:列显示回调函数,用来处理列中的回显的 数据处理,必须有返回值
slotHeadName : insertHeader为真时,给与slotHeadName,来外部设定格式配置的插槽
*/
tableConf:{
type:Array,
default:()=>([])
},
// 内部控制按钮,自定义按钮数组
btns:Array,
// 是否需要按钮插槽,外部控制显示按钮
btnSlot:Boolean,
// 表格加载效果
loading:Boolean,
showSelection:Boolean,
showPaginaition:{
type:Boolean,default:true
},
tableMaxHeight:String,// 表格的高度
tableHeight:String,// 表格高度
showIndex:Object, // {label:显示文字,headerAlign,align 对齐方式}
pageConf:Object,// 分页设置配置
lastColumn:{
type:Boolean,
default:true
}, // 使用最后一列插槽
data:Array,//传入的数据对象优先显示,
rowCheckable:Function,
showTitle:String,// 显示表头单列,
selectOptions:{type:Object,default:()=>({})},// 异步下拉数据表
btnMore:{
type:Array,default:()=>([])
},
resetQuery:{type:Boolean,default:true}, // 重置之后是否查询,默认查询,
showExpand:String,// 是否有扩展的内部块
expandPadding:{
type:String,
default:'8px 10px'
},//扩展内部块的Padding
},
data(){
return {
dataList:[], //{ ...prop,btns:[要显示的所有按钮],hideBtns:[需要隐藏的按钮],slot}
pageConfig: {
pageSize: 10,
total: 0,
pageNumber: 1,
pageSizes: this.pageSizes || [10, 20, 50],
layout: 'slot,sizes, prev, pager, next, jumper',
...this.pageConf
},
curParams:{},// 当前查询变量
showTbale:true
}
},
computed:{
tableData(){
return this.data || this.dataList
}
},
methods:{
// 搜索关键字
search(formData){
this.curParams = {
...this.curParams,
...formData,
}
this.query()
},
// 开始查询
query(){
if(this.showPaginaition){
this.curParams.pageSize = this.pageConfig.pageSize
this.curParams.pageNo = this.pageConfig.pageNumber
}
this.throwEmit()
},
// 分页大小
handleSizeChange(val){
this.pageConfig.pageSize = val
this.query(this.curParams)
},
// 当前页
handleCurrentChange(val){
this.pageConfig.pageNumber = val
this.query(this.curParams)
},
// 接受表格头部过滤的函数
dateQuery(params,columnKey){
const list = Object.keys(params).reduce( (p,c) =>{
p[c+'Time'] = params[c]
return p
},{})
this.curParams = {...this.curParams,...list}
this.query()
},
// 过滤器筛选结构
filterChange(filters){
const {0:key} = Object.keys(filters)
this.curParams[key] = filters[key].join()
this.query()
},
select(selection,row){
this.$emit('select',selection,row)
console.log(selection,row)
},
// 清楚所有选中
clearSelectedAll(){
this.$refs['pushTable'].clearSelection()
},
//设置某一行被选中
setCurrentRow(rows,selected){
rows.forEach( row => this.$refs['pushTable'].toggleRowSelection(row,selected) )
},
// 抛出数据 和最新的查询条件
throwEmit(){
this.$emit('querySearch',this.curParams)
},
//当前行时候可勾选
selectable(row,index){
return this.rowCheckable ? this.rowCheckable(row,index) : true
},
// 重置查询条件
resetAll(searchParams){
this.curParams = {...searchParams}
this.pageConfig.pageSize = 10
this.pageConfig.pageNumber = 1
this.showTbale = false
this.$nextTick(_ =>{this.showTbale = true})
if(this.resetQuery) this.query()
this.$emit('resetAll',this.curParams)
},
// 创建函数
createdDefault,
//更多按钮事件
btnMoreAction(item){
this.$emit('btnMoreAction',item)
},
initSearch(clickFunc){
this.$emit('initSearch',clickFunc)
},
change(params){
this.$emit('change',params)
}
}
}
</script>
<style lang="scss" scoped>
@import "@/projects/proGdton/pages/EAS/common.scss";
.search-card{
.table-list{
.table-padding_both{
margin:10px 20px;
/deep/ .el-table th > .cell.highlight {
color: #1ab394;
}
.kyol-column_header{
display: flex;
justify-content: flex-start;
align-items:center;
}
}
/*JS控制SCSS变量*/
/deep/ .el-table{
.el-table__body-wrapper{
.el-table__body{
tbody tr .el-table__expanded-cell{
padding:var(--expand)//5px 10px;
}
}
}
}
.c-table{
.eslpse{
width:100%;
white-space:nowrap;
overflow: hidden;
text-overflow:ellipsis;
}
}
}
}
</style>
<reportFrame :title="title">
<pushTable :tableConf="tableConf" :formConf="formConf" :lastColumn="false" :showTitle="subTitle" :ref="title" :showIndex="showIndex" tableMaxHeight="440px"
@querySearch="search" v-loading="loading" :data="data" :selectOptions="selectOptions" :btnMore="btns" @btnMoreAction="btnMoreAction" @initSearch="initSearch" :resetQuery="false" @resetAll="formatParams">
</pushTable>
</reportFrame>
/*配置 =》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》*/
const task = {
0: _ =>{
const list = [
defaultCreated('关联单据编号','formCode'),
defaultCreated('账期开始日期','periodStartDate'),
defaultCreated('账期结束日期','periodEndDate'),
defaultCreated('客户名称','customerName'),
defaultCreated('合同名称','businessName'),
defaultCreated('账单ID','code'),
defaultCreated('期数','period'),
defaultCreated('G+费项','businessType'),
defaultCreated('操作类型','operateType'),
defaultCreated('金额','amount',{money:true}),
]
const form = [
createdForm('projectId','选择选项项目',{type:'select',value:14}),
createdForm('periodTime',['账期开始日期','账期开始结束日期'],{type:'date-2',value:[] ,range:'至'}),
createdForm('customerName','请输入客户/合同名称',{value:'',}),
createdForm('operateType','请选择操作类型',{value:[],type:'select',multiple:true,selectOptions:actionsType}),
]
return {list,form}
},
1:_ => {
const list = [
defaultCreated('关联单据编号','formCode'),
defaultCreated('客户名称','customerName'),
defaultCreated('意向单/合同名称','formName '),
defaultCreated('G+费项','businessType'),
defaultCreated('来源','sourceCondition'),
defaultCreated('类型','flowType'),
defaultCreated('业务','flowActType'),
defaultCreated('结转费项','settleCostObj'),
defaultCreated('是否跨主体','isAcrossMain'),
defaultCreated('操作日期','operateTime'),
defaultCreated('业务发生日期','businessTime'),
defaultCreated('金额','amount',{money:true})
]
const form = [
createdForm('projectId','选择选项项目',{type:'select',value:14}),
createdForm('businessTime',['业务日期开始时间','请选择业务日期结束时间'],{type:'date-2',value:[]}),
createdForm('customerName','请输入订单/合同/客户名称',{value:'',}),
createdForm('formCode','请输入单据编号',{value:''}),
createdForm('businessTypes','G+费项',{type:'select',multiple:true,value:[],selectOptions:feeTypeList.map(({label,prop})=>({label,value:prop}))}),
createdForm('sourceConditions','来源',{type:'select',multiple:true,value:[],selectOptions:sourceCondition }),
createdForm('flowTypes','请选择类型',{value:[],type:'select',multiple:false,selectOptions:flowTypes}),
createdForm('flowActTypes','请选择业务',{value:[],type:'select',multiple:false,selectOptions:flowActTypes}),
createdForm('isAcrossMain','是否跨主体',{type:'select',value:[],selectOptions:isAcrossMain }),
createdForm('settleCostObjs','请选择结转目标',{type:'select',multiple:true,value:[],selectOptions: settleCostObjs}),
]
return {list,form}
}
}
const {list:tableConf,form:formConf} = task[formType]()
@复杂嵌套表格,可以实现无限嵌套
<KyModel v-if="showLoglistDialog" title="变更日志" :close-on-click-modal="false" :before-close="closeLoglist" className="changeLoglist" maxHeight="60px;"
@close="closeLoglist" width="1200px">
<div slot="body" class="changeLoglist-body" v-infinite-scroll="loadingMore" infinite-scroll-disabled="changeLogDisabled" infinite-scroll-distance="50px">
<pushTable :tableConf="tableConf" :showPaginaition="false" :data="changeLoglist" :lastColumn="false" :showExpand="showExpand">
<template :slot="showExpand" slot-scope="{row}">
<pushTable :tableConf="childTableConf" :showPaginaition="false" :data="row.logs" :lastColumn="false" />
</template>
</pushTable>
<div v-if="!changeLoglist.length" class="changeLoglist_empty">暂无变更日志信息</div>
</div>
</KyModel>