filter-box.vue 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. <template>
  2. <div class="filter-box" :class="{ multiple }">
  3. <el-input v-if="!multiple" placeholder="请输入内容" class="input-with-select" :clearable="true" size="mini" v-model="filterData.value">
  4. <el-select class="prepend" slot="prepend" placeholder="请选择" v-model="filterData.name" @clear="handleClear" clearable>
  5. <el-option v-for="(item, index) in fields" :label="item.field.label" :value="item.field.name" :key="'filter' + index"></el-option>
  6. </el-select>
  7. <el-button slot="append" icon="el-icon-search" @click="query"></el-button>
  8. </el-input>
  9. <el-form v-else ref="form" :model="form" :inline="true">
  10. <el-form-item v-for="(item, index) in simpleFields" :key="'form-field-' + index" :label="item.field.label">
  11. <naf-input v-model="form[item.field.name]" size="mini" :dict="item.dict" :clearable="true"></naf-input>
  12. </el-form-item>
  13. <el-form-item>
  14. <el-dropdown v-if="matcher == 'all'" size="mini" split-button type="primary" @click="query" @command="handleCommand">
  15. 查询
  16. <el-dropdown-menu slot="dropdown">
  17. <el-dropdown-item command="exact">精确查询<i v-if="matching == 'exact'" class="el-icon-check el-icon--right"></i></el-dropdown-item>
  18. <el-dropdown-item command="like">模糊查询<i v-if="matching == 'like'" class="el-icon-check el-icon--right"></i></el-dropdown-item>
  19. </el-dropdown-menu>
  20. </el-dropdown>
  21. <el-button v-else type="primary" size="mini" @click="query">查询</el-button>
  22. </el-form-item>
  23. <el-form-item>
  24. <el-button type="primary" size="mini" @click="reset">重置</el-button>
  25. </el-form-item>
  26. <el-form-item v-if="$scopedSlots.ext || moreFields.length > 0">
  27. <el-button type="primary" size="mini" @click="toggleMore" v-if="!showMore">更多</el-button>
  28. <el-button type="default" size="mini" @click="toggleMore" v-else>收起</el-button>
  29. </el-form-item>
  30. </el-form>
  31. <slot name="ext" v-bind="{ form, handleFieldChange }" v-if="showMore">
  32. <el-form ref="form-ext" :model="form" :inline="true">
  33. <el-form-item v-for="(item, index) in moreFields" :key="'form-ex-field-' + index" :label="item.field.label">
  34. <naf-input v-model="form[item.field.name]" size="mini" :dict="item.dict" :clearable="true"></naf-input>
  35. </el-form-item>
  36. </el-form>
  37. </slot>
  38. </div>
  39. </template>
  40. <script>
  41. import NafInput from './naf-input';
  42. import { Util } from 'naf-core';
  43. const defaultMatcher = process.env.VUE_APP_FILTER_MATCHER_DEFAULT || 'like';
  44. export default {
  45. components: {
  46. NafInput,
  47. },
  48. props: {
  49. fields: { type: Array, required: true },
  50. multiple: { type: Boolean, default: eval(process.env.VUE_APP_FILTER_MULTI || false) },
  51. matcher: { type: String, default: process.env.VUE_APP_FILTER_MATCHER || 'like' },
  52. maxFields: { type: Number, default: 4 },
  53. },
  54. data() {
  55. return {
  56. filterData: { name: '', value: '' },
  57. form: {},
  58. matching: (defaultMatcher == 'exact' && 'exact') || (defaultMatcher == 'like' && 'like') || 'like',
  59. showMore: false,
  60. };
  61. },
  62. methods: {
  63. async query() {
  64. const filter = { ...this.filter, exact: this.matching != 'like' };
  65. const paging = { page: this.page, size: this.size };
  66. Object.freeze(filter);
  67. Object.freeze(paging);
  68. this.$emit('query', {
  69. filter,
  70. paging,
  71. });
  72. },
  73. handleClear() {
  74. this.filterData = { name: '', value: '' };
  75. },
  76. reset() {
  77. this.form = {};
  78. this.query();
  79. },
  80. handleCommand(command) {
  81. this.matching = command;
  82. this.query();
  83. },
  84. toggleMore() {
  85. this.showMore = !this.showMore;
  86. },
  87. handleFieldChange(name, value) {
  88. console.debug(`filter field ${name} changed:`, value);
  89. this.$set(this.form, name, value);
  90. },
  91. },
  92. computed: {
  93. filterFields() {
  94. return this.fields.map(p => ({
  95. ...p,
  96. dict: p.dict || (this.$dict && p.formatter && p.formatter.name === 'dict' && this.$dict(p.formatter.param)),
  97. }));
  98. },
  99. filter() {
  100. if (this.multiple) {
  101. const entries = Object.entries(this.form).filter(p => p[1] != undefined && p[1] != null && p[1] != '');
  102. return Object.fromEntries(entries);
  103. }
  104. let filter = { [this.filterData.name]: this.filterData.value };
  105. if (this.filterData.name == undefined || this.filterData.value == undefined || this.filterData.value == '') {
  106. filter = undefined;
  107. }
  108. return filter;
  109. },
  110. simpleFields() {
  111. return this.filterFields.slice(0, this.maxFields);
  112. },
  113. moreFields() {
  114. return this.filterFields.slice(this.maxFields) || [];
  115. },
  116. },
  117. };
  118. </script>
  119. <style lang="less" scoped>
  120. .filter-box {
  121. width: 300px;
  122. display: inline-block;
  123. margin-right: 20px;
  124. .prepend.el-select {
  125. width: 100px;
  126. }
  127. }
  128. .filter-box.multiple {
  129. width: 100%;
  130. min-width: 920px;
  131. .naf-input {
  132. width: 100px;
  133. /deep/ .el-input__inner {
  134. padding: 0 5px;
  135. }
  136. }
  137. .el-form-item {
  138. margin-bottom: 0;
  139. }
  140. }
  141. </style>