查詢條件及列表都是動態配置
界面:
使用:
<el-input v-model="name" readonly class="input-with-select">
<el-button
slot="append"
icon="el-icon-document-checked"
@click="BtnClick()"
/>
</el-input>
<lzg-select
ref="selectLzg"
:title="config.title"
:visible.sync="config.visible"
:search-column="config.searchColumn"
:table-url="config.tableUrl"
:is-selection="config.isSelection"
:table-column="config.tableColumn"
@confirm="selectConfirm()"
/>
config: {
title: '選擇',
visible: false,
searchColumn: [
{ key: 'name', label: '名稱', type: 'string' },
{ key: 'type', label: '類型', type: 'radio', options: [{ Key: '0', Value: '類型1' }, { Key: '1', Value: '類型2' }] },
{ key: 'createTime', label: '時間', type: 'dateRange' }
],
tableUrl: 'url',
isSelection: true,
tableColumn: [
{ prop: 'id', label: '編碼' },
{ prop: 'name', label: '名稱' },
{ prop: 'createTime', label: '添加時間' }
]
},
事件
BtnClick() {
//設置選中唯一鍵
const rowKeys = [1,2,3]
this.$refs.selectLzg.setSelectDatas(rowKeys)
this.config.visible = true
}
selectConfirm(val) {
val.addData.forEach(t => {
//添加數據.具體實現業務
})
val.delData.forEach(t => {
//刪除數據.具體實現業務
})
}
控件代碼
// 通用組件HTML字符渲染
Vue.component('template-html', {
props: {
html: {
type: String,
default: ''
},
scope: {
type: Object,
default: () => {}
},
config: {
type: Object,
default: () => {}
},
disabled: {
default: false
}
},
created() {
this.$options.template = `<div>${this.html}</div>`
},
template: ''
})
<template>
<el-dialog
:title="title"
:visible.sync="visible"
:width="width+'px'"
:show-close="false"
:close-on-click-modal="false"
:close-on-press-escape="false"
@opened="selectInit"
>
<el-form :model="selectForm" label-width="80px" :style="'height:'+height+'px;'">
<el-row v-for="(row, rowIndex) of searchRows">
<el-col v-for="(col, colIndex) of row" :span="10" :offset="1">
<el-form-item :label="col.label">
<el-input
v-if="col.type==='string'"
v-model.trim="selectForm[col.key]"
clearable
/>
<el-input-number
v-if="col.type==='int'"
v-model.trim="selectForm[col.key]"
:precision="0"
/>
<el-input-number
v-if="col.type==='float'"
v-model.trim="selectForm[col.key]"
:precision="col.precision"
/>
<el-date-picker
v-if="col.type==='date'"
v-model.trim="selectForm[col.key]"
value-format="yyyy-MM-dd"
format="yyyy-MM-dd"
type="date"
style="width:100%"
/>
<el-date-picker
v-if="col.type==='dateRange'"
v-model.trim="selectForm[col.key]"
value-format="yyyy-MM-dd"
format="yyyy-MM-dd"
type="daterange"
style="width:100%"
range-separator="至"
start-placeholder="開始日期"
end-placeholder="結束日期"
/>
<el-select
v-if="col.type==='select'"
v-model.trim="selectForm[col.key]"
clearable
filterable
>
<el-option
v-for="opt in col.options"
:key="opt.Key"
:label="opt.Value"
:value="opt.Key"
/>
</el-select>
<el-cascader v-if="col.type==='cascader' " :options="col.options"
v-model.trim="selectForm[col.key]"
:props="{checkStrictly: true,multiple: (col.multiple===undefined?false:true),value:'Key',label:'Value'}" clearable>
</el-cascader>
<el-radio
v-for="opt in col.options"
v-if="col.type==='radio'"
v-model="selectForm[col.key]"
:label="opt.Key"
>{{ opt.Value }}
</el-radio>
</el-form-item>
</el-col>
<el-col v-if="rowIndex===searchRows.length-1" :span="2" :offset="row.length==2?0:11">
<el-button icon="el-icon-search" @click.native="selectBtnClick('selectSearch')">搜索</el-button>
</el-col>
</el-row>
<el-row>
<el-col :span="21" :offset="1">
<el-table
:ref="tableRef"
:height="tableHeight"
:fit="true"
:data="datas"
:border="true"
:row-key="rowKey"
:highlight-current-row="isHighlight"
@current-change="selectListComRowCurrentChange"
@selection-change="selectListComRowSelectionChange"
@select="selectListCheckSelect"
@select-all="selectListCheckAll"
>
<el-table-column type="index" width="50" fixed="left">
<template slot-scope="scope">
<span>{{ scope.$index+(tempPageIndex - 1) * tempPageSize + 1 }}</span>
</template>
</el-table-column>
<el-table-column
v-if="isSelection"
type="selection"
width="55"
fixed="left"
:reserve-selection="true"
:disabled="true"
/>
<transition v-for="column in tableColumn" :key="column.prop">
<template v-if="selectCheckColumnShow(column)==1">
<el-table-column
:prop="column.prop"
:label="column.label"
:width="column.width"
:fixed="column.fixed"
:sortable="column.sortable"
:align="column.align"
:header-align="column.headeralign"
:formatter="column.formatter"
show-overflow-tooltip
/>
</template>
<template v-else-if="selectCheckColumnShow(column)==2">
<el-table-column
:prop="column.prop"
:label="column.label"
:width="column.width"
:fixed="column.fixed"
:sortable="column.sortable"
:align="column.align"
:header-align="column.headeralign"
show-overflow-tooltip
>
<template slot-scope="scope">
<oppo-html
:html="column.templateHtml"
:scope="scope"
:config="this"
/>
</template>
</el-table-column>
</template>
<template v-else-if="selectCheckColumnShow(column)==3">
<el-table-column
:prop="column.prop"
:label="column.label"
:width="column.width"
:fixed="column.fixed"
:sortable="column.sortable"
:align="column.align"
:header-align="column.headeralign"
:formatter="selectFormatterCellData"
show-overflow-tooltip
/>
</template>
<template v-else-if="selectCheckColumnShow(column)==4">
<el-table-column
:prop="column.prop"
:label="column.label"
:width="column.width"
:fixed="column.fixed"
:sortable="column.sortable"
:align="column.align"
:header-align="column.headeralign"
show-overflow-tooltip
>
<template slot-scope="scope">
{{ selectMultiProp(column.prop,scope.row) }}
</template>
</el-table-column>
</template>
<template v-else>
<el-table-column
:prop="column.prop"
:label="column.label"
:width="column.width"
:fixed="column.fixed"
:sortable="column.sortable"
:align="column.align"
:header-align="column.headeralign"
show-overflow-tooltip
/>
</template>
</transition>
</el-table>
<el-pagination
v-if="isPage"
:current-page="tempPageIndex"
:page-sizes="pageList"
:page-size="tempPageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="pageTotal"
@size-change="selectListComPageSizeChange"
@current-change="selectListComPageCurrentChange"
/>
</el-col>
</el-row>
</el-form>
<span slot="footer">
<el-button icon="el-icon-check" @click.native="selectBtnClick('selectConfirm')">確定</el-button>
<el-button icon="el-icon-delete" @click.native="selectBtnClick('selectReset')">清除</el-button>
<el-button type="info" icon="el-icon-back" @click.native="selectBtnClick('selectCancel')">取消</el-button>
</span>
</el-dialog>
</template>
<script>
export default {
name: 'Select',
props: {
// 標題
title: {
type: String
},
// 是否顯示
visible: {
type: Boolean
},
// 寬度
width: {
type: Number,
default: 1100
},
// 高度
height: {
type: Number,
default: 600
},
// 查詢列集合
// {
// key:'', //字段名
// label:'', //顯示名稱
// type:'', //類型 string/int/float/date/dateRange/select/radio/cascader
// options:[ { Key: "", Value: "" }], //下拉數據集
// url:'', //下拉URL
// urlParmas:{} //下拉URL參數
// urlRequest:'' //URL請求類型
// precision:0 //小數位
// }
searchColumn: {
type: Array,
default: () => []
},
// 行數據的 Key
rowKey: {
type: String,
default: 'id'
},
// 表格Url
tableUrl: {
type: String,
default: ''
},
// 表格列集合
// element本身參數
// 擴展參數: templateHtml 模板,url 下拉Url, urlParmas Url參數,urlRequest 請求類型 get post ,options 下拉數據 { Key: "", Value: "" }
tableColumn: {
type: Array,
default: () => []
},
// 默認查詢條件
// {
// Value: '', //值
// Key: '', //字段
// Operator: '', //操作符 Equal,NoEqual,Like,In,NotIn,LikeLeft,LikeRight,GreaterThan,GreaterThanOrEqual,LessThan,LessThanOrEqual,DateRange
// }
defalutConditions: {
type: Array,
default: () => []
},
// 是否多選
isSelection: {
type: Boolean,
default: false
},
// 是否分頁
isPage: {
type: Boolean,
default: true
},
// 分頁集合
pageList: {
type: Array,
default: () => [5, 10, 20, 30, 50, 100]
},
// 頁碼
pageSize: {
type: Number,
default: 10
},
// 頁數
pageIndex: {
type: Number,
default: 1
},
// 擴展數據
extData: {
type: Object,
default: () => {
}
}
},
data() {
return {
// 表單綁定值
selectForm: {},
// 表格高度
tableHeight: 0,
// 未選頁ref
tableRef: 'tableSelect' + Math.random(),
// 總行數
pageTotal: 0,
// 數據集
datas: [],
// 新增數據集
addDatas: [],
// 刪除數據集
delDatas: [],
// 已選數據rowKey集
tempSelectRowKeyDatas: [],
// 頁碼
tempPageSize: 10,
// 寬度
tempPageIndex: 1,
// 查詢條件
// {
// Value: '', //值
// Key: '', //字段
// Operator: '', //操作符 Equal,NoEqual,Like,In,NotIn,LikeLeft,LikeRight,GreaterThan,GreaterThanOrEqual,LessThan,LessThanOrEqual,DateRange
// }
conditions: [],
// 是否高亮顯示行數據
isHighlight: false,
// url
tempUrl: '',
searchRows:[]
}
},
watch: {
pageSize(newValue, oldValue) {
this.tempPageSize = newValue
},
pageIndex(newValue, oldValue) {
this.tempPageIndex = newValue
}
},
created() {
},
methods: {
// 初始化界面
selectInit() {
this.$refs[this.tableRef].doLayout()
this.isHighlight = !this.isSelection
this.activeName = 'unSelect'
this.selectInitSearchUrl()
this.selectInitTableUrl()
this.$refs[this.tableRef].clearSelection()
this.$refs[this.tableRef].setCurrentRow()
this.addData = []
this.delData = []
this.tempPageIndex = this.pageIndex
this.tempPageSize = this.pageSize
this.tempUrl = this.tableUrl
this.setSearchRows()
this.selectLoadData(this.pageIndex, this.pageSize)
},
selectMultiProp(prop, row) {
const vals = prop.split(',')
let valueString = ''
vals.forEach(t => {
if (row[t])valueString += row[t]
})
return valueString
},
setSearchRows() {
this.searchRows=[]
this.searchColumn.forEach((item, index) => {
const row = Math.floor(index / 2)// 2代表2條爲一行,隨意更改
if (!this.searchRows[row]) {
this.searchRows[row] = []
}
this.searchRows[row].push(item)
})
this.tableHeight = this.height - this.searchRows.length * 52
if (this.isPage) {
this.tableHeight = this.tableHeight - 30
}
},
// 初始化查詢條件下拉url數據集
selectInitSearchUrl() {
const vue = this
vue.searchColumn.forEach(item => {
if (item.url) {
if (item.urlRequest === 'get') {
vue.$store.dispatch('table/tableColumnInitGet', { url: item.url, data: item.urlParmas }).then(res => {
const listDatas = []
if(item.type==='cascader')
{
let cols = item.key.split(',')
vue.getTreeData(listDatas,res.data.result,null,1,cols.length)
}
else {
res.data.result.forEach(t => {
listDatas.push({ Key: t.id, Value: t.name })
})
}
item.options = listDatas
})
} else {
vue.$store.dispatch('table/tableColumnInitPost', { url: item.url, data: item.urlParmas }).then(res => {
const listDatas = []
if(item.type==='cascader')
{
let cols = item.key.split(',')
vue.getTreeData(listDatas,res.data.result,null,1,cols.length)
}
else {
res.data.result.forEach(t => {
listDatas.push({ Key: t.id, Value: t.name })
})
}
item.options = listDatas
this.setSearchRows()
})
}
}
})
},
// 初始化列表條件下拉url數據集
selectInitTableUrl() {
const vue = this
vue.tableColumn.forEach(item => {
if (item.url) {
if (item.urlRequest === 'get') {
vue.$store.dispatch('table/tableColumnInitGet', {
url: item.url,
data: item.urlParmas
}).then(res => {
const listDatas = []
res.data.result.forEach(t => {
listDatas.push({ Key: t.id, Value: t.name })
})
item.options = listDatas
})
} else {
vue.$store.dispatch('table/tableColumnInitPost', { url: item.url, data: item.urlParmas }).then(res => {
const listDatas = []
res.data.result.forEach(t => {
listDatas.push({ Key: t.id, Value: t.name })
})
item.options = listDatas
})
}
}
})
},
//獲取樹形集合
getTreeData(listDatas,datas,parent,index,totalIndex){
let vue = this;
datas.forEach(t => {
let item={ Key: t.id, Value: t.name };
if(parent)
{
parent.children.push(item)
}
else{
listDatas.push(item)
}
if(t.children && index<totalIndex)
{
item.children=[]
vue.getTreeData(listDatas,t.children,item,index+1,totalIndex)
}
})
},
setConditions(conditions) {
this.conditions = conditions
},
// 查詢列表數據
selectLoadData(pageIndex, pageSize) {
const vue = this
if (vue.tempUrl) {
const requestData = {
pageNum: pageIndex,
pageSize: pageSize
}
vue.defalutConditions.forEach(item => {
vue.conditions.push(item)
})
vue.conditions.forEach(item => {
requestData[item.Key] = item.Value
})
const request = {
url: vue.tempUrl,
data: requestData
}
vue.$store.dispatch('table/getTableGet', request).then(res => {
const result = res.data.result
if (vue.isPage) {
vue.datas = result.list
vue.pageTotal = result.total
} else {
vue.datas = result.list
}
vue.selectRowSelection()
}).catch(res => {
})
}
},
// 按鈕點擊事件
selectBtnClick(type, row) {
switch (type) {
// 確定
case 'selectConfirm':
if (this.addData.length === 0 && this.tempSelectRowKeyDatas.length === 0) {
this.$message.info('親,是不是忘記' + this.title + '?')
} else {
this.$emit('update:visible', false)
this.$emit('confirm', this.extData)
this.conditions = []
for (const key in this.selectForm) {
this.selectForm[key] = ''
}
}
break
// 取消
case 'selectCancel':
this.$emit('update:visible', false)
this.$emit('cancel', this.extData)
this.conditions = []
for (const key in this.selectForm) {
this.selectForm[key] = ''
}
break
// 清除
case 'selectReset':
this.addData=[]
this.delData = []
this.tempSelectRowKeyDatas.forEach(t => {
this.delData.push({ id: t })
})
//this.$emit('update:visible', false)
this.$emit('confirm', this.extData)
this.conditions = []
for (const key in this.selectForm) {
this.selectForm[key] = ''
}
if (this.isSelection) {
this.$refs[this.tableRef].clearSelection()
} else {
this.$refs[this.tableRef].setCurrentRow()
}
break
// 搜索
case 'selectSearch':
this.conditions = []
for (const key in this.selectForm) {
if (this.selectForm[key]) {
const col = this.searchColumn.find(t => {
return t.key === key
})
if (col.type === 'dateRange') {
let times=this.selectForm[key];
if(times[0])this.conditions.push({ Value: times[0]+' 00:00:00', Key: 'startTime', Operator: '' })
if(times[1])this.conditions.push({ Value: times[1]+' 23:59:59', Key: 'endTime', Operator: '' })
}
else if(col.type === 'cascader'){
let cols = col.key.split(',')
let values=this.selectForm[key];
cols.forEach((t,index)=>{
if(values.length>index)
{
this.conditions.push({ Value: values[index], Key: t, Operator: '' })
}
})
}
else {
this.conditions.push({ Value: this.selectForm[key], Key: key, Operator: '' })
}
}
}
this.selectLoadData(this.pageIndex, this.pageSize)
break
}
},
// 檢測列顯示樣式
selectCheckColumnShow(column) {
// 自定義格式化
if (column.formatter) {
return 1
}
// 自定義模板
else if (column.templateHtml) {
return 2
}
// 數據動態格式化
else if (column.formatter == undefined && column.templateHtml == undefined && ((column.options && column.options.length > 0) || column.url)) {
return 3
} else if (column.prop.indexOf(',') > -1) {
return 4
}
// 默認
return 99
},
// 格式化列數據
selectFormatterCellData: function(row, column, cellValue) {
const col = this.tableColumn.find((item) => {
return item.prop === column.property
})
if (col && col.options) {
if (col.options.length > 0) {
if (cellValue === undefined || cellValue === null) {
return ''
}
const tempDatas = cellValue.toString().split(',')
let str = ''
tempDatas.forEach(d => {
const datas = col.options.filter(item => item.Key.toString() === d)
if (datas.length > 0) {
str += datas[0].Value + ','
}
})
if (str) {
return str.substr(0, str.length - 1)
} else {
return str
}
}
}
return ''
},
// 分頁數量改變
selectListComPageSizeChange(val) {
this.tempPageSize = val
this.selectLoadData(this.tempPageIndex, this.tempPageSize)
},
// 分頁頁面改變
selectListComPageCurrentChange(val) {
this.tempPageIndex = val
this.selectLoadData(this.tempPageIndex, this.tempPageSize)
},
// 當前行選中改變事件
selectListComRowCurrentChange(selection) {
// 單選數據
if (!this.isSelection) {
this.addData = []
this.addData.push(selection)
}
},
// 當前行選中改變事件
selectListComRowSelectionChange(selection) {
// 多選數據
if (this.isSelection) {
}
},
selectListCheckAll(selection) {
if (this.isSelection) {
this.datas.forEach(row => {
// 是否全選中
if (selection.length > 0) {
const rowKey = this.tempSelectRowKeyDatas.find(t => { return t === row[this.rowKey] })
const rowAdd = this.addData.find(t => { return t[this.rowKey] === row[this.rowKey] })
if (!rowKey && !rowAdd) {
this.addData.push(row)
}
const dd = this.delData.find(t => t[this.rowKey] === rowKey)
if (dd) {
this.removeObj(this.delData, dd)
}
} else {
const rowKey = this.tempSelectRowKeyDatas.find(t => { return t === row[this.rowKey] })
if (rowKey) {
this.delData.push(row)
}
const rowAdd = this.addData.find(t => { return t[this.rowKey] === row[this.rowKey] })
if (rowAdd) {
this.removeObj(this.addData, row)
}
}
})
}
},
// 當用戶手動勾選數據行的 Checkbox 時觸發的事件
selectListCheckSelect(selection, row) {
const selected = selection.indexOf(row) !== -1
const rowKey = this.tempSelectRowKeyDatas.find(t => t === row[this.rowKey])
const rowAdd = this.addData.find(t => { return t[this.rowKey] === row[this.rowKey] })
if (selected && !rowKey) {
this.addData.push(row)
}
if (!selected && rowAdd && !rowKey) {
this.removeObj(this.addData, row)
}
if (!selected && rowKey) {
this.delData.push(row)
}
if (selected && rowKey) {
const dd = this.delData.find(t => t[this.rowKey] === rowKey)
if (dd) {
this.removeObj(this.delData, dd)
}
}
},
// 設置選中行
selectRowSelection() {
this.tempSelectRowKeyDatas.forEach(t => {
const data = this.datas.find(m => {
return m[this.rowKey] === t
})
if (data) {
if (this.isSelection) {
this.$refs[this.tableRef].toggleRowSelection(data)
} else {
this.$refs[this.tableRef].setCurrentRow(data)
}
}
})
},
// 獲取數據集合
getSelectDatas() {
return { addData: this.addData, delData: this.delData }
},
// 設置已選集合
setSelectDatas(val) {
const r = val.filter(function(s) {
return s
})
this.tempSelectRowKeyDatas = r
}
}
}
</script>
<style scoped>
.el-date-editor >>> .el-range-separator {
padding: 5px;
width: 30px;
}
.el-tabs >>> .el-tabs__header {
margin: 0 0 0px;
}
.el-table {
width: 100%;
margin: 0px;
font-size: 12px;
color: #000;
border-top: none;
}
.el-cascader-panel .el-radio{
width: 100%;
height: 100%;
z-index: 10;
position: absolute;
top: 10px;
right: -10px;
}
.el-cascader-panel .el-radio__input{
visibility: hidden;
}
.el-cascader-panel .el-cascader-node__postfix{
top: 10px;
}
</style>