|
<template>
|
<el-form class="search-region" @submit.native.prevent>
|
<el-form-item class="margin-bottom-10">
|
<div class="tool-left">
|
<slot name="button-tool-slot">
|
<template v-for="(button, index) in buttons">
|
<!--分组按钮-->
|
<el-button-group v-if="button.type=='button-group' && hasValidButton(button.buttons)" :key="index" class="tool-group">
|
<template v-for="(btn, btnIndex) in button.buttons">
|
<template v-if="btn.type==='button'">
|
<el-tooltip v-if="['refresh','helper'].indexOf(btn.options.authNode)>=0 || authNodes[btn.options.authNode]" :key="btnIndex" :content="btn.label" :open-delay="1000" placement="top">
|
<el-button v-if="btn.options.authNode=='refresh'" :loading="refreshLoading" v-bind="btn.options" @click="()=>onButtonAction(btn.options.authNode, btn)">{{ btn.label }}</el-button>
|
<el-button v-else v-bind="btn.options" :disabled="btnReadOnly[btn.options.authNode]" @click="()=>onButtonAction(btn.options.authNode, btn)">{{ btn.label }}</el-button>
|
</el-tooltip>
|
</template>
|
<el-dropdown v-else-if="btn.type==='button-dropdown' && authNodes[btn.options.authNode]" :key="btnIndex">
|
<el-button v-bind="btn.options">
|
{{ btn.label }}
|
<i class="el-icon-arrow-down el-icon--right"></i>
|
</el-button>
|
<el-dropdown-menu slot="dropdown">
|
<el-dropdown-item v-for="(item, itemIndex) in btn.options.options" :key="itemIndex" @click.native="()=>onButtonAction(item.authNode, btn)">{{ item.label }}</el-dropdown-item>
|
</el-dropdown-menu>
|
</el-dropdown>
|
</template>
|
</el-button-group>
|
<!--下拉框按钮-->
|
<el-dropdown v-else-if="button.type==='button-dropdown' && authNodes[button.options.authNode]" :key="index">
|
<el-button v-bind="button.options">
|
{{ button.label }}
|
<i class="el-icon-arrow-down el-icon--right"></i>
|
</el-button>
|
<el-dropdown-menu slot="dropdown">
|
<el-dropdown-item v-for="(item, itemIndex) in button.options.options" :key="itemIndex" @click.native="onButtonAction(item.authNode, button)">{{ item.label }}</el-dropdown-item>
|
</el-dropdown-menu>
|
</el-dropdown>
|
<!--不分组按钮-->
|
<el-tooltip v-else-if="['refresh','helper'].indexOf(button.options.authNode)>=0 || authNodes[button.options.authNode]" :key="index" :content="button.label" :open-delay="1000" placement="top">
|
<el-button :disabled="btnReadOnly[button.options.authNode]" v-bind="button.options" @click="()=>onButtonAction(button.options.authNode, button)">{{ button.label }}</el-button>
|
</el-tooltip>
|
</template>
|
</slot>
|
|
<slot name="button-tool2-slot">
|
</slot>
|
</div>
|
<div :class="['tool-right', {'search-only-line':dataOptions.searchOnlyLine}]">
|
<!-- 快速查询字段 - 自定义 -->
|
<template v-for="(col, index) in quickSearchFields">
|
<div v-if="['date', 'datetime'].indexOf(col.dataType)>=0" :key="index" class="inline-block">
|
<el-date-picker v-model="col.value" :picker-options="datePickOptions" :start-placeholder="col.label+'开始日期'" type="daterange" align="right" unlink-panels range-separator="至" end-placeholder="结束日期" value-format="yyyy-MM-dd HH:mm:ss" class="w-230">
|
</el-date-picker>
|
</div>
|
<div v-else-if="col.type==='select'" :key="index" class="inline-block">
|
<el-select v-model="col.value" :placeholder="col.label" :multiple="col.multiple" clearable class="w-120 inline-block">
|
<el-option v-for="(item, optionIndex) in col.dropdownData" :key="'ops'+optionIndex" :label="item.label" :value="item.value"></el-option>
|
</el-select>
|
</div>
|
<div v-else-if="col.type==='textarea'" :key="index" class="inline-block">
|
<el-input v-model="col.value" :placeholder="col.label" :rows="1" type="textarea" class="search-texarea"></el-input>
|
</div>
|
<div v-else :key="index" class="inline-block">
|
<el-input v-model="col.value" :placeholder="col.label" @keydown.native.stop.enter="()=>{loadData('quick');}"></el-input>
|
</div>
|
</template>
|
<!-- 快速查询字段 - 常用查询字段 -->
|
<template v-for="(col, index) in searchFields_quick">
|
<div v-if="['date', 'datetime'].indexOf(col.dataType)>=0" :key="index" class="inline-block">
|
<el-date-picker v-model="col.value" :picker-options="datePickOptions" :start-placeholder="col.label+'开始日期'" type="daterange" align="right" unlink-panels range-separator="至" end-placeholder="结束日期" value-format="yyyy-MM-dd HH:mm:ss" class="w-230">
|
</el-date-picker>
|
</div>
|
<template v-else-if="col.type=='select'">
|
<el-select v-model="col.value" :key="'col_'+index" :placeholder="col.label" :multiple="col.multiple" clearable class="w-120 inline-block">
|
<el-option v-for="(item, optionIndex) in getOptions(col)" :key="'ops'+optionIndex" :label="item.label" :value="item.value"></el-option>
|
</el-select>
|
</template>
|
<div v-else :key="'input_'+index" class="w-120 inline-block">
|
<el-input v-model="col.value" :placeholder="col.label" @keydown.native.stop.enter="()=>{loadData('quick');}"></el-input>
|
</div>
|
</template>
|
|
<!-- 快速查询字段 - 关键词 -->
|
<el-input ref="quickSearchInput" v-model="currentQuickSearchValue" :type="searchInpuType" :rows="1" :placeholder="quickSearch.placeholder" class="search-input" @keydown.native.stop.enter="()=>{loadData('quick');}">
|
<el-select slot="prepend" v-model="currentQuickSearchType" placeholder="请选择" class="w-60" @change="changeQuickSearchType">
|
<el-option label="精确" value="精确"></el-option>
|
<el-option label="模糊" value="模糊"></el-option>
|
<el-option label="多行" value="多行"></el-option>
|
</el-select>
|
</el-input>
|
<el-button type="primary" class="search-btn" @click="quickSearchData">查询</el-button>
|
<el-button class="search-btn super-reset" type="text" @click="superReset">重置</el-button>
|
<el-button class="show-supper-searcher" type="text" @click.stop="showPopupRight">高级</el-button>
|
<!--高级查询侧滑-->
|
<popup-right :top="'48px'" :width="'810px'" :height="'auto'" :is-active="popupRightActive" class="popup-right">
|
<div slot="header" class="header">高级查询</div>
|
<div class="main">
|
<el-scrollbar :noresize="false" :native="false" wrap-class="scrollbar-wrap">
|
<el-form :inline="true" label-width="110px">
|
<el-form-item v-for="(col, index) in searchFields" v-if="col.prop!='_action'" :key="index" :label="col.label">
|
<template v-if="col.type=='select'">
|
<el-select v-model="col.operator" :default-first-option="true" placeholder="请选择" class="operator" style="width:70px;">
|
<el-option v-for="item in operators" :key="item.value" :label="item.label" :value="item.value">
|
</el-option>
|
</el-select>
|
<el-select v-model="col.value" :multiple="col.multiple" clearable class="w-200">
|
<el-option v-for="(item, optionIndex) in getOptions(col)" :key="'ops'+optionIndex" :label="item.label" :value="item.value"></el-option>
|
</el-select>
|
</template>
|
<template v-else-if="col.type=='radio'">
|
<el-select v-model="col.operator" :default-first-option="true" placeholder="请选择" class="operator" style="width:70px;">
|
<el-option v-for="item in operators" :key="item.value" :label="item.label" :value="item.value">
|
</el-option>
|
</el-select>
|
<el-radio-group v-model="col.value">
|
<el-radio v-for="(item, optionIndex) in dropdownData['dropdown'+col.dropdown_Id]" :label="item.value" :key="'ops'+optionIndex">{{ item.label }}</el-radio>
|
</el-radio-group>
|
</template>
|
<template v-else-if="col.type=='tree'">
|
<el-select v-model="col.operator" :default-first-option="true" placeholder="请选择" class="operator" style="width:70px;">
|
<el-option v-for="item in operators" :key="item.value" :label="item.label" :value="item.value">
|
</el-option>
|
</el-select>
|
<tree-select v-model="col.value" :options="{prop: col.prop, width: '200px'}" :label="col.label" :tree-load="(node, resolve)=>{treeLoad(node, resolve, col)}" @on-tree-node-click="(data, node, el)=>{onTreeNodeClick(data, node, el, col)}">
|
</tree-select>
|
</template>
|
<template v-else>
|
<template v-if="['byte', 'int32', 'int64', 'decimal', 'double'].indexOf(col.dataType)>=0">
|
从:
|
<el-input v-model.number="col.fromValue" placeholder="开始值" style="width:90px;" @keydown.native.stop.enter="loadData"></el-input>
|
<span class="margin-left-10">到:</span>
|
<el-input v-model.number="col.toValue" placeholder="结束值" style="width:90px;" @keydown.native.stop.enter="loadData"></el-input>
|
</template>
|
<template v-else-if="['date', 'datetime'].indexOf(col.dataType)>=0">
|
<el-date-picker v-model="col.value" :picker-options="datePickOptions" type="daterange" align="right" unlink-panels range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" value-format="yyyy-MM-dd HH:mm:ss" style="width:275px">
|
</el-date-picker>
|
</template>
|
<template v-else>
|
<el-select v-model="col.operator" :default-first-option="true" placeholder="请选择" class="operator" style="width:70px;" @change="if(col.operator==='null'){col.value=null;}">
|
<el-option v-for="item in operators" :key="item.value" :label="item.label" :value="item.value">
|
</el-option>
|
</el-select>
|
<el-input v-model="col.value" :disabled="col.operator=='null'" :type="col.operator==='in'?'textarea':'text'" :rows="1" class="w-200" @keydown.native.stop.enter="loadData"></el-input>
|
</template>
|
</template>
|
</el-form-item>
|
</el-form>
|
</el-scrollbar>
|
</div>
|
<div slot="footer" class="footer">
|
<el-button class="left" type="text" @click="hidePopupRight">关闭</el-button>
|
<el-button class="right" @click="superReset">重置</el-button>
|
<el-button class="right" type="primary" @click="superSearcher">查询</el-button>
|
</div>
|
</popup-right>
|
</div>
|
</el-form-item>
|
</el-form>
|
</template>
|
|
<script>
|
import PopupRight from "@/components/base/PopupRight";
|
var moment = require("moment");
|
import TreeSelect from "@/components/base/TreeSelect";
|
|
export default {
|
name: "data-list-toolbar",
|
components: {
|
PopupRight,
|
TreeSelect
|
},
|
props: {
|
// 字段定义
|
fields: {
|
type: Array,
|
required: true,
|
default: () => []
|
},
|
// 按钮定义
|
buttons: {
|
type: Array,
|
required: false,
|
default: () => []
|
},
|
// 按钮点击事件
|
buttonClick: {
|
type: Function,
|
required: false,
|
default: null
|
},
|
// 数据参数
|
dataOptions: {
|
type: Object,
|
default: () => {}
|
},
|
// 权限集合
|
authNodes: {
|
type: Object,
|
required: true,
|
default: () => {}
|
},
|
// 刷新按钮loading
|
refreshLoading: {
|
type: Boolean,
|
required: true,
|
default: false
|
},
|
// 按钮是否可用
|
btnReadOnly: {
|
type: Object,
|
required: false,
|
default: () => {
|
return {
|
save: false,
|
auditing: false,
|
add: false,
|
delete: false,
|
stop: false,
|
open: false
|
};
|
}
|
},
|
// 加载数据
|
loadData: {
|
type: Function,
|
required: true,
|
default: () => {}
|
},
|
// 编辑器ref
|
editorRef: {
|
type: String,
|
required: true
|
},
|
// 选中项
|
dataListSelections: {
|
type: Array,
|
required: true
|
},
|
// 高级查询字段
|
searchFields: {
|
type: Array,
|
required: true
|
},
|
// 下拉框数据
|
dropdownData: {
|
type: Object,
|
required: true
|
},
|
// 快速查询参数设置
|
quickSearch: {
|
type: Object,
|
required: true
|
},
|
// 关键词查询值
|
quickSearchValue: {
|
type: String,
|
required: true
|
},
|
// 查询类别
|
quickSearchType: {
|
type: String,
|
required: true
|
},
|
// 快捷查询扩展条件集合
|
quickSearchFields: {
|
type: Array,
|
required: true
|
},
|
// 右侧搜索宽度
|
rightWidth: {
|
type: Number,
|
required: true
|
}
|
},
|
data() {
|
return {
|
// 是否显示右侧弹出窗
|
popupRightActive: false,
|
// 查询运算符
|
operators: [
|
{ value: "like", label: "模糊" },
|
{ value: "null", label: "空值" },
|
{ value: ">=", label: ">=" },
|
{ value: "<=", label: "<=" },
|
{ value: "=", label: "=" },
|
{ value: "<>", label: "<>" },
|
{ value: "in", label: "多行" }
|
],
|
datePickOptions: {
|
shortcuts: [
|
{
|
text: "最近一周",
|
onClick(picker) {
|
const end = new Date();
|
const start = new Date();
|
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
|
picker.$emit("pick", [start, end]);
|
}
|
},
|
{
|
text: "最近一个月",
|
onClick(picker) {
|
const end = new Date();
|
const start = moment()
|
.subtract(1, "months")
|
.toDate();
|
picker.$emit("pick", [start, end]);
|
}
|
},
|
{
|
text: "最近三个月",
|
onClick(picker) {
|
const end = new Date();
|
const start = moment()
|
.subtract(3, "months")
|
.toDate();
|
picker.$emit("pick", [start, end]);
|
}
|
},
|
{
|
text: "最近半年",
|
onClick(picker) {
|
const end = new Date();
|
const start = moment()
|
.subtract(6, "months")
|
.toDate();
|
picker.$emit("pick", [start, end]);
|
}
|
},
|
{
|
text: "最近一年",
|
onClick(picker) {
|
const end = new Date();
|
const start = moment()
|
.subtract(12, "months")
|
.toDate();
|
picker.$emit("pick", [start, end]);
|
}
|
}
|
]
|
},
|
// 快速查询框类别
|
searchInpuType: "text"
|
};
|
},
|
computed: {
|
// 判断按钮组是否存在可用按钮
|
hasValidButton: {
|
get: function() {
|
return buttons => {
|
const authNodes = Object.assign({}, this.authNodes, {
|
refresh: true,
|
helper: true
|
});
|
return (
|
buttons.filter(btn => {
|
return authNodes[btn.options.authNode];
|
}).length > 0
|
);
|
};
|
}
|
},
|
// 高级查询筛出序号>=200的字段作为快速查询
|
searchFields_quick: {
|
get: function() {
|
return this.searchFields
|
.filter(item => {
|
return item.searchRowNo >= 200;
|
})
|
.sort(function(a, b) {
|
if (a.searchRowNo > b.searchRowNo) {
|
return -1;
|
}
|
if (a.searchRowNo < b.searchRowNo) {
|
return 1;
|
}
|
return 0;
|
});
|
}
|
},
|
// 快捷查询值
|
currentQuickSearchValue: {
|
get: function() {
|
return this.quickSearchValue;
|
},
|
set: function(newValue) {
|
this.$emit("update:quickSearchValue", newValue); // 双向绑定prop.action,通知父级组件变量值同步更新
|
}
|
},
|
// 快捷查询值
|
currentQuickSearchType: {
|
get: function() {
|
return this.quickSearchType;
|
},
|
set: function(newValue) {
|
this.$emit("update:quickSearchType", newValue); // 双向绑定prop.action,通知父级组件变量值同步更新
|
if (newValue === "多行") {
|
this.currentQuickSearchType = "精确";
|
this.searchInpuType = "textarea";
|
}
|
}
|
},
|
// 获得下拉框options
|
getOptions: {
|
get: function() {
|
var the = this;
|
return function(col) {
|
let options = [];
|
if (col.dropdown_Id > 0) {
|
options = the.dropdownData["dropdown" + col.dropdown_Id];
|
} else if (col.options && col.options.remote === "bindDropdown") {
|
options = the.dropdownData["dropdown" + col.options.dropdown_Id];
|
} else if (col.options && col.options.remote === false) {
|
options = col.options.options;
|
}
|
return options;
|
};
|
}
|
}
|
},
|
watch: {},
|
methods: {
|
// 工具栏按钮事件
|
onButtonAction(authNode, btnOpts) {
|
let result;
|
if (this.buttonClick) {
|
result = this.buttonClick(authNode, btnOpts);
|
}
|
if (result !== undefined) {
|
return;
|
}
|
this.$nextTick(() => {
|
switch (authNode) {
|
case "add":
|
// 新建
|
this.findRef(this.editorRef).addData();
|
break;
|
case "refresh":
|
// 刷新
|
this.loadData();
|
break;
|
case "delete":
|
// 批量删除
|
this.$parent.delete(this.dataListSelections);
|
break;
|
case "import":
|
// 批量导入
|
this.$parent.importDialog(btnOpts);
|
break;
|
case "export":
|
// 批量导出
|
this.$parent.exportDialog(btnOpts);
|
break;
|
case "print":
|
// 默认打印
|
this.$parent.print();
|
break;
|
case "batchOpen":
|
// 批量开启
|
this.$parent.batchOpen(this.dataListSelections);
|
break;
|
case "batchStop":
|
// 批量终止
|
this.$parent.batchStop(this.dataListSelections);
|
break;
|
case "auditing":
|
case "batchAuditing":
|
// 批量审核
|
this.$parent.batchAuditing(this.dataListSelections);
|
break;
|
}
|
});
|
},
|
// 显示搜索侧滑栏
|
showPopupRight() {
|
this.$parent.loadDropDown(); // 加载下拉框值
|
this.popupRightActive = !this.popupRightActive;
|
document.addEventListener("click", this.hidePopupRight, false);
|
},
|
// 隐藏搜索侧滑栏
|
hidePopupRight() {
|
this.popupRightActive = false;
|
document.removeEventListener("click", this.hidePopupRight, false);
|
},
|
// 重置高级查询
|
superReset() {
|
this.searchInpuType = "text";
|
this.currentQuickSearchType = "精确";
|
this.currentQuickSearchValue = "";
|
this.searchFields.concat(this.quickSearchFields).forEach((item, index, arr) => {
|
item.operator = "=";
|
if (item.type === "select") {
|
item.value = item.multiple ? [] : null;
|
} else {
|
item.value = null;
|
if (typeof item.fromValue !== undefined) {
|
item.fromValue = null;
|
item.toValue = null;
|
}
|
}
|
});
|
// 重置事件
|
this.$emit("on-super-reset");
|
},
|
// 快速查询
|
quickSearchData() {
|
// 重置分页索引
|
this.$set(this.dataOptions, "pageIndex", 1);
|
this.loadData("quick");
|
},
|
// 高级查询
|
superSearcher() {
|
// 重置分页索引
|
this.$set(this.dataOptions, "pageIndex", 1);
|
this.loadData();
|
// this.hidePopupRight();
|
},
|
// 树形输入框load
|
treeLoad(node, resolve, subField) {
|
var the = this;
|
this.$emit("tree-load", node, resolve, subField);
|
// 默认加载数据
|
if (!subField.isLoaded) {
|
var keyName = subField.ajaxParams.keyName;
|
if (!keyName) {
|
the.$message.error("未设置tree下拉框ajax加载参数!");
|
return;
|
}
|
the.$nextTick(() => {
|
var where = "";
|
var userInfo = this.common.getUserInfo();
|
if (node.level === 0) {
|
where = {
|
userProduct_Id: userInfo.userProduct_Id,
|
parentId: 0
|
};
|
} else {
|
where = {
|
userProduct_Id: userInfo.userProduct_Id,
|
parentId: node.data[subField.ajaxParams.keyName]
|
};
|
}
|
|
var url = "/api/common/loadTreeNode";
|
var params = subField.ajaxParams;
|
params.where = where;
|
params.openNodeApi = true;
|
the.common.ajax(
|
url,
|
params,
|
res => {
|
if (res.result) {
|
resolve(res.data);
|
} else {
|
the.$message.error(res.msg);
|
}
|
},
|
true
|
);
|
});
|
}
|
},
|
// 树形下拉框获得点击项
|
onTreeNodeClick(data, node, el, field) {
|
// 仅选择叶节点
|
if (!node.isLeaf && field.onlySelectLeaf) return;
|
|
var keyProp = field.keyProp;
|
if (keyProp) {
|
this.$set(field, "keyValue", data[keyProp]);
|
}
|
var prop = field.prop;
|
field.value = data[prop];
|
},
|
// 获取数据
|
changeQuickSearchType(val) {
|
this.searchFields.forEach(item => {
|
if (val === "模糊") {
|
item.operator = "like";
|
} else {
|
item.operator = "=";
|
}
|
});
|
}
|
}
|
};
|
</script>
|
|
<style lang="scss" scoped>
|
.search-region {
|
.tool-left {
|
float: left;
|
.tool-group + .tool-group {
|
margin-left: 10px;
|
}
|
.el-button--medium {
|
padding: 10px 10px;
|
}
|
}
|
.tool-right {
|
text-align: right;
|
min-width: 380px;
|
&.search-only-line {
|
text-align: left;
|
clear: both;
|
margin-top: 50px;
|
}
|
.inline-block {
|
margin-bottom: 3px;
|
margin-right: 5px;
|
}
|
.search-texarea {
|
/deep/ textarea {
|
min-height: 36px !important;
|
line-height: 24px !important;
|
max-width: 150px;
|
}
|
}
|
.search-input {
|
width: calc(100% - 110px);
|
max-width: 250px;
|
/deep/ .el-input__inner {
|
padding-left: 5px;
|
padding-right: 5px;
|
}
|
/deep/ .el-input__suffix {
|
right: 0;
|
}
|
/deep/ .el-input__prefix {
|
left: 2px;
|
}
|
/deep/ textarea {
|
min-height: 36px !important;
|
line-height: 24px !important;
|
}
|
}
|
.search-btn {
|
padding: 10px;
|
&.el-button--text {
|
padding: 10px 0;
|
}
|
}
|
/deep/ .el-date-editor {
|
.el-range-separator {
|
width: 25px;
|
}
|
.el-range__close-icon {
|
width: 10px;
|
}
|
}
|
> .el-select + .el-select {
|
margin-left: 5px;
|
}
|
.super-reset,
|
.show-supper-searcher {
|
margin-left: 3px;
|
}
|
.popup-right {
|
text-align: left;
|
line-height: 1.2;
|
z-index: 1000;
|
.header {
|
background-color: #f6f6f6;
|
padding: 10px;
|
}
|
.main {
|
background-color: #fff;
|
padding: 0;
|
min-height: 400px;
|
/deep/ .el-scrollbar {
|
height: 395px;
|
}
|
/deep/ .scrollbar-wrap {
|
max-height: 410px;
|
overflow-x: hidden;
|
.el-form {
|
padding: 10px;
|
.el-form-item {
|
margin-bottom: 10px;
|
.el-date-editor .el-range-separator {
|
width: 25px;
|
}
|
/deep/ .operator .el-input__inner {
|
padding-left: 5px;
|
padding-right: 20px;
|
text-align: center;
|
}
|
}
|
}
|
}
|
}
|
.footer {
|
background-color: #f6f6f6;
|
padding: 10px;
|
overflow: hidden;
|
}
|
}
|
}
|
/deep/ .el-form-item__content {
|
position: static;
|
}
|
}
|
</style>
|