el-table 统一封装下拉筛选功能

发布时间 2023-11-24 11:06:05作者: 崔国亮

先上效果图

 

 

目前支持:多选,文本模糊搜索,日期,时间,筛选列,筛选项展示 

 

三个文件

1.popover.vue //所有列公用一个弹窗

2.index.vue //table 代码主文件

3.filterContent.vue //处理不同类型代码逻辑

 

代码部分:

1.index.vue 

  1 <template>
  2   <div>
  3     <!-- 列筛选 -->
  4     <div v-if="showColumnFilter" class="column-filter">
  5       <el-popover placement="bottom" trigger="click">
  6         <div>
  7           <el-checkbox
  8             label="全选"
  9             v-model="checkAll"
 10             @change="onColumnCheckAll"
 11           >
 12             全选</el-checkbox
 13           >
 14           <el-checkbox-group v-model="checkedColumns">
 15             <el-checkbox
 16               v-for="(item, index) in allColumnFilter"
 17               :key="'column-filter-' + index + '-' + item"
 18               :disabled="requiredColumns.includes(item)"
 19               :label="item"
 20               >{{ item }}
 21             </el-checkbox>
 22           </el-checkbox-group>
 23         </div>
 24         <el-link slot="reference" :underline="false"
 25           >筛选项<i class="el-icon-arrow-down el-icon--right"></i
 26         ></el-link>
 27       </el-popover>
 28       <div class="option-con">
 29         <slot name="options"></slot>
 30       </div>
 31     </div>
 32 
 33     <!-- 条件筛选 -->
 34     <div v-if="showFilterInfo && filterInfo.length > 0" class="filter-info">
 35       <div class="title">筛选条件:</div>
 36       <div class="filters">
 37         <span class="item" v-for="item in filterInfo" :key="item.prop"
 38           >{{ `${item.label}:${item.value}` }}
 39           <i @click="onFilterDelete(item)" class="el-icon-circle-close"></i>
 40         </span>
 41       </div>
 42       <div class="options">展开</div>
 43     </div>
 44 
 45     <!-- Table列表 -->
 46     <div class="table-con">
 47       <el-table
 48         ref="listTable"
 49         v-loading="loading"
 50         :data="data"
 51         tooltip-effect="dark"
 52         :header-cell-style="{
 53           textAlign: 'left',
 54           background: '#f2f7ff',
 55           color: '#32425e',
 56           height: '40px',
 57           padding: '0',
 58         }"
 59         :cell-style="{ 'text-align': 'left', width: '100%', padding: '0' }"
 60         :row-style="{ height: '30px' }"
 61         @sort-change="$emit('sort-change', $event)"
 62         @selection-change="$emit('selection-change', $event)"
 63         lazy
 64         :load="load"
 65         :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
 66         row-key="id"
 67       >
 68         <el-table-column
 69           v-if="selectable"
 70           type="selection"
 71           width="55"
 72         ></el-table-column>
 73         <template v-for="(column, index) in columns">
 74           <el-table-column
 75             v-if="checkedColumns.includes(column.label)"
 76             show-overflow-tooltip
 77             :prop="column.prop"
 78             :label="column.label"
 79             :key="index + '-' + column.name"
 80             :width="column.width || 0"
 81             :sortable="column.sortable ? 'custom' : false"
 82           >
 83             <!-- Header -->
 84             <template slot="header">
 85               <span>{{ column.label }}</span>
 86               <span
 87                 class="img-filter"
 88                 v-if="column.filterable"
 89                 @click.stop="(e) => onFilterClick(e, column)"
 90               ></span>
 91             </template>
 92             <template slot-scope="scope">
 93               <template v-if="column.link">
 94                 <template v-if="scope.row[column.prop]=='-'">
 95                   {{ scope.row[column.prop] }}
 96                 </template>
 97                 <el-link
 98                   v-else
 99                   :underline="false"
100                   @click="column.click(scope.row)"
101                   type="primary"
102                   >{{ scope.row[column.prop] | formatData(column) }}</el-link
103                 >
104               </template>
105               <template v-else>
106                 {{ scope.row[column.prop] | formatData(column) }}
107               </template>
108             </template>
109           </el-table-column>
110         </template>
111         <slot></slot>
112       </el-table>
113     </div>
114 
115     <!-- 分页信息 -->
116     <div class="page-con" v-if="paging">
117       <el-pagination
118         background
119         @size-change="$emit('size-change', $event)"
120         @current-change="$emit('current-change', $event)"
121         :current-page="page"
122         :page-sizes="pageSizeArr"
123         :page-size="pageSize"
124         layout="total, sizes, prev, pager, next, jumper"
125         :total="total"
126       >
127       </el-pagination>
128     </div>
129 
130     <!-- 筛选弹出框 -->
131     <filter-popover ref="popoverDom">
132       <div class="table-pop-filter-con">
133         <div class="body">
134           <!-- 筛选项 -->
135           <filter-content
136             v-if="currentColumn"
137             :data="initFilterValue"
138             :type="currentColumn.type"
139             :options="options"
140             :defaultOptions="defaultOptions"
141             @valueChange="onValueChange"
142           ></filter-content>
143         </div>
144         <div class="footer">
145           <el-button size="mini" @click="resetFilter">重置</el-button>
146           <el-button type="primary" size="mini" @click="confirmFilter"
147             >筛选</el-button
148           >
149         </div>
150       </div>
151     </filter-popover>
152   </div>
153 </template>
154 
155 <script>
156 import FilterPopover from "./popover.vue";
157 import FilterContent from "./filterContent.vue";
158 
159 const userTypes = ["current-project-user", "project-user", "user"];
160 export default {
161   name: "FilterTable",
162   components: {
163     FilterContent,
164     FilterPopover,
165   },
166   filters: {
167     formatData(val, column) {
168       if (["select"].includes(column.type)) {
169         //val 可能是数组
170         let tmpVal = Array.isArray(val) ? val : [val];
171         // console.log(tmpVal,'tmpVal');
172         let arrayLabel =
173           column.options
174             ?.filter((item) => tmpVal.includes(item.value))
175             .map((item) => item.label) || [];
176 
177         if (arrayLabel.length > 0) {
178           return arrayLabel.join(",");
179         } else {
180           return "-";
181         }
182       } else {
183         return val;
184       }
185     },
186   },
187   props: {
188     /**显示所有过滤条件 */
189     showFilterInfo: {
190       type: Boolean,
191       default: false,
192     },
193     /**显示筛选列 */
194     showColumnFilter: {
195       type: Boolean,
196       default: true,
197     },
198     /**是否可以复选 */
199     selectable: {
200       type: Boolean,
201       default: false,
202     },
203     /**加载数据状态 */
204     loading: {
205       type: Boolean,
206       default: false,
207     },
208     /**table 数据 */
209     data: {
210       type: Array,
211       required: true,
212       default: [],
213     },
214     /**table 列 */
215     columns: {
216       type: Array,
217       required: true,
218       default: [],
219     },
220     /**分页信息 */
221     paging: {
222       type: Boolean,
223       default: true,
224     },
225     total: {
226       type: Number,
227       default: undefined,
228     },
229     page: {
230       type: Number,
231       default: 1,
232     },
233     pageSize: {
234       type: Number,
235       default: 10,
236     },
237     pageSizeArr: {
238       type: Array,
239       default: () => {
240         return [10, 20, 30, 40];
241       },
242     },
243     load: {
244       type: Function,
245       default: () => {},
246     },
247   },
248   watch: {
249     checkedColumns() {
250       if (this.columns.length == this.checkedColumns.length) {
251         this.checkAll = true;
252       } else {
253         this.checkAll = false;
254       }
255     },
256   },
257   data() {
258     return {
259       columnsList: this.columns,
260       currentColumn: null,
261       changeValue: null,
262       initFilterValue: null,
263       filterData: {},
264       defaultOptions: null,
265       checkedColumns: [],
266       checkAll: false,
267     };
268   },
269 
270   mounted() {
271     this.checkedColumns = this.columns
272       .filter((item) => item.required || !item.hide)
273       .map((item) => item.label);
274   },
275   computed: {
276     allColumnFilter() {
277       let result = [];
278       result = this.columns.map((item) => item.label);
279       return result;
280     },
281 
282     requiredColumns() {
283       let result = [];
284       result = this.columns
285         .filter((item) => item.required)
286         .map((item) => item.label);
287       return result;
288     },
289 
290     options() {
291       if (this.currentColumn) {
292         return this.currentColumn.options?.map((item) => item.label);
293       } else {
294         return [];
295       }
296     },
297     isSelect() {
298       return ["select"].includes(this.currentColumn.type);
299     },
300     isUserType() {
301       //current-project-user:当前项目下用户,project-user:所有项目用户,user:所有用户
302       return userTypes.includes(this.currentColumn.type);
303     },
304     isDateOrTime() {
305       return ["date", "datetime"].includes(this.currentColumn.type);
306     },
307     filterInfo() {
308       if (!this.showFilterInfo) {
309         return;
310       }
311       let result = []; //{name:'',value:'',prop:''}
312       for (const key in this.filterData) {
313         if (Object.hasOwnProperty.call(this.filterData, key)) {
314           const value = this.filterData[key];
315           const column = this.columns.find((item) => item.prop == key);
316           if (value && column) {
317             let showValue = value;
318 
319             if (Array.isArray(value)) {
320               //去options 内匹配
321 
322               if (userTypes.includes(column.type)) {
323                 const valueMap = value.map((item) => item.label);
324                 showValue = valueMap.join("/");
325               } else {
326                 const valueMap = column.options
327                   .filter((item) => value.includes(item.value))
328                   .map((item) => item.label);
329                 showValue = valueMap.join("/");
330               }
331             }
332             result.push({
333               label: column.label,
334               prop: column.prop,
335               queryprop: column.queryprop ? column.queryprop : undefined,
336               value: showValue,
337             });
338           }
339         }
340       }
341       return result;
342     },
343   },
344   methods: {
345     onColumnCheckAll(val) {
346       if (val) {
347         this.checkedColumns = this.allColumnFilter.map((item) => item);
348       } else {
349         //去掉必填都显示
350         let defaultCheckedColumns = this.columns
351           .filter((item) => item.required)
352           .map((item) => item.label);
353         this.checkedColumns = defaultCheckedColumns;
354       }
355     },
356     onLinkClick(row) {
357       console.log(row, "click");
358     },
359     onFilterDelete(item) {
360       let filterData = { ...this.filterData };
361       filterData[item.prop] = undefined;
362       if (item.queryprop) {
363         filterData[item.queryprop] = undefined;
364       }
365       this.filterData = filterData;
366       this.$emit("confirmFilter", filterData);
367     },
368     onFilterClick(e, column) {
369       this.currentColumn = column;
370       this.initFilterValue = this.getInitFilterValue();
371       this.$refs.popoverDom.popBy(e.target);
372     },
373     resetFilter() {
374       let filterData = { ...this.filterData };
375       filterData[this.currentColumn.prop] = undefined;
376       if (this.currentColumn.queryprop) {
377         filterData[this.currentColumn.queryprop] = undefined;
378       }
379       this.filterData = filterData;
380       this.defaultOptions = [];
381       this.initFilterValue = undefined;
382       console.log(filterData, "reset filterData");
383       this.$emit("confirmFilter", filterData);
384       this.$refs.popoverDom.close();
385     },
386     onPopoverHide() {},
387     onValueChange(data) {
388       //临时数据
389       this.changeValue = data;
390     },
391     //获取弹出框显示默认值
392     getInitFilterValue() {
393       const value = this.filterData[this.currentColumn.prop];
394       if (this.isUserType) {
395         if (value?.length > 0) {
396           this.defaultOptions = value;
397           return this.defaultOptions.map((item) => item.label);
398         }
399       } else if (this.isSelect) {
400         return this.currentColumn.options
401           ?.filter((option) => value?.includes(option.value))
402           .map((item) => item.label);
403       } else {
404         return value;
405       }
406     },
407     //获取emit 真实值
408     getEmitValue() {
409       if (this.isSelect) {
410         return this.currentColumn.options
411           ?.filter((option) => this.changeValue.includes(option.label))
412           .map((item) => item.value);
413       } else {
414         return this.changeValue;
415       }
416     },
417     //筛选确定
418     confirmFilter() {
419       let emitValue = this.getEmitValue();
420       let filterData = { ...this.filterData };
421       filterData[this.currentColumn.prop] = emitValue; // 如果是数组实际对应的是[value,value]
422       this.filterData = filterData;
423       this.initFilterValue = emitValue;
424       this.$emit("confirmFilter", filterData);
425       this.$refs.popoverDom.close();
426     },
427   },
428 };
429 </script>
430 
431 <style scoped lang="scss">
432 .column-filter {
433   padding-bottom: 10px;
434   display: flex;
435   align-items: center;
436   & > .option-con {
437     flex: 1;
438     text-align: right;
439   }
440 }
441 .filter-info {
442   background-color: #dbe1f6;
443   padding: 10px;
444   color: #435ebe;
445   font-size: 14px;
446   display: flex;
447   margin-bottom: 10px;
448   border-radius: 8px;
449   & > .title {
450     flex: 0 0 auto;
451     font-weight: bold;
452     padding-top: 5px;
453   }
454   & > .filters {
455     flex: 1;
456     padding: 0 10px;
457     & > .item {
458       font-weight: normal;
459       margin: 5px;
460       display: inline-block;
461       line-height: 20px;
462 
463       & > i {
464         display: inline-block;
465         cursor: pointer;
466       }
467     }
468   }
469   & > .options {
470     flex: 0 0 auto;
471     padding-top: 5px;
472   }
473 }
474 .table-con {
475   & .img-filter {
476     display: inline-block;
477     width: 24px;
478     height: 24px;
479     background: url("~@/assets/img/search.png") no-repeat center center / 15px
480       auto;
481     vertical-align: middle;
482     box-sizing: border-box;
483     cursor: pointer;
484     position: absolute;
485     margin-left: 13px;
486   }
487   & ::v-deep .sort-caret {
488     left: 4px;
489   }
490   & ::v-deep .is-sortable {
491     & .img-filter {
492       height: 34px;
493     }
494   }
495 }
496 .page-con {
497   text-align: right;
498   margin-top: 10px;
499 }
500 .el-checkbox-group {
501   max-height: 600px;
502   overflow: auto;
503 }
504 </style>
View Code

 

2.filterContent.vue

  1 <template>
  2   <div>
  3     <div v-if="type == 'text'">
  4       <el-input
  5         v-model="keyword"
  6         size="small"
  7         prefix-icon="el-input__icon el-icon-search"
  8         placeholder="搜索关键词"
  9         @change="onValueChange"
 10       ></el-input>
 11     </div>
 12     <div v-if="type == 'select'">
 13       <el-input
 14         v-model="keyword"
 15         size="small"
 16         prefix-icon="el-input__icon el-icon-search"
 17         type="text"
 18         placeholder="搜索关键词"
 19       />
 20       <div class="select-box">
 21         <el-checkbox-group v-model="arrayValue" @change="onValueChange">
 22           <el-checkbox
 23             v-for="(item, index) in optionList"
 24             :key="index"
 25             :label="item"
 26             >{{ item }}
 27           </el-checkbox>
 28         </el-checkbox-group>
 29         <div class="no-data" v-if="optionList.length == 0">暂无数据</div>
 30       </div>
 31     </div>
 32     <div v-if="['date', 'datetime'].includes(type)">
 33       <el-date-picker
 34         v-model="arrayValue"
 35         @change="onValueChange"
 36         :type="type == 'date' ? 'daterange' : 'datetimerange'"
 37         :value-format="type == 'date' ? 'yyyy-MM-dd' : 'yyyy-MM-dd HH:mm:ss'"
 38         range-separator="至"
 39         :start-placeholder="type == 'date' ? '开始日期' : '开始时间'"
 40         :end-placeholder="type == 'date' ? '结束日期' : '结束时间'"
 41       >
 42       </el-date-picker>
 43     </div>
 44     <div v-if="isUserType">
 45       <el-input
 46         v-model="keyword"
 47         size="small"
 48         prefix-icon="el-input__icon el-icon-search"
 49         type="text"
 50         placeholder="搜索关键词"
 51         @input="onUserKeywordChange"
 52         oninput="if(value.length>11)value=value.slice(0,100)"
 53       />
 54       <div v-loading="optionsLoading" class="select-box">
 55         <el-checkbox-group v-model="arrayValue" @change="onValueChange">
 56           <el-checkbox
 57             v-for="(item, index) in optionList"
 58             :key="index"
 59             :label="item"
 60             >{{ item }}
 61           </el-checkbox>
 62         </el-checkbox-group>
 63         <div class="no-data" v-if="optionList.length == 0">暂无数据</div>
 64       </div>
 65     </div>
 66     <div v-if="type == 'progress'">
 67       <el-progress
 68         :text-inside="true"
 69         :stroke-width="15"
 70         :percentage="50"
 71         status="exception"
 72       ></el-progress>
 73     </div>
 74   </div>
 75 </template>
 76 
 77 <script>
 78 import { memberApi } from "@/api/projectMember";
 79 import { mapGetters } from "vuex";
 80 
 81 export default {
 82   name: "filterContent",
 83   props: {
 84     type: {
 85       type: String,
 86       default: undefined,
 87       require: true,
 88     },
 89     options: {
 90       type: Array,
 91       default: () => [],
 92     },
 93     defaultOptions: {
 94       type: Array,
 95       default: () => [],
 96     },
 97     data: {
 98       type: String | Array,
 99       default: null,
100     },
101   },
102   data() {
103     return {
104       keyword: "",
105       arrayValue: [],
106       cacheUsers: [],
107       userList: [],
108       allUsers: [],
109       loading: false,
110       optionsLoading: false,
111     };
112   },
113   mounted() {},
114   watch: {
115     data: {
116       immediate: true,
117       handler() {
118         if (this.isArrayValue) {
119           this.keyword = "";
120           this.arrayValue = this.data || [];
121         } else {
122           this.keyword = this.data;
123         }
124       },
125     },
126     type: {
127       immediate: true,
128       handler() {
129         if (this.isUserType) {
130           this.getUser("GW");
131         }
132       },
133     },
134     defaultOptions: {
135       immediate: true,
136       deep: true,
137       handler(val) {
138         if (this.isUserType) {
139           this.cacheUsers = val || [];
140         }
141       },
142     },
143   },
144   computed: {
145     ...mapGetters(["currentProject"]),
146     isArrayValue() {
147       return (
148         ["select", "date", "datetime"].includes(this.type) || this.isUserType
149       );
150     },
151     isUserType() {
152       //current-project-user:当前项目下用户,project-user:所有项目用户,user:所有用户
153       return ["current-project-user", "project-user", "user"].includes(
154         this.type
155       );
156     },
157     optionList() {
158       let result = [];
159       if (this.isUserType) {
160         let userList = [];
161         this.cacheUsers.forEach((user) => {
162           if (!userList.some((obj) => obj.value == user.value)) {
163             userList.push(user);
164           }
165         });
166         this.userList.forEach((user) => {
167           if (!userList.some((obj) => obj.value == user.value)) {
168             userList.push({ label: user.label, value: user.value });
169           }
170         });
171         this.allUsers = userList;
172         result = userList.map((item) => item.label);
173       } else {
174         result = this.options.filter(
175           (item) => item.toLowerCase().indexOf(this.keyword.toLowerCase()) > -1
176         );
177       }
178       return result;
179     },
180   },
181   methods: {
182     onUserKeywordChange() {
183       this.getUser(this.keyword);
184     },
185     getUser(val) {
186       let keyword =
187         val !== null && val !== "" && val !== undefined ? val : "GW";
188 
189       this.optionsLoading = true;
190       let queryMethod = memberApi.findUser;
191       let queryData = keyword;
192       if (this.type == "current-project-user") {
193         //判断是否当前项目有值
194         if (this.currentProject) {
195           queryData = {
196             keyword: keyword,
197             pageNo: 1,
198             pageSize: 9999,
199             projectIds: ["43400"],
200           };
201           queryMethod = memberApi.getMemberList;
202         } else {
203           queryMethod = memberApi.findUser;
204         }
205       }
206       if (this.type == "project-user") {
207         queryMethod = memberApi.findUser;
208       }
209       if (this.type == "user") {
210         queryMethod = memberApi.searchEmployee;
211       }
212 
213       queryMethod(queryData)
214         .then((res) => {
215           let list = res.data.list || res.data;
216           this.userList = list?.map((item) => {
217             return {
218               label: `${item.nickName}(${item.userName})`,
219               value: item.userName,
220             };
221           });
222         })
223         .finally(() => {
224           this.optionsLoading = false;
225         });
226     },
227     onValueChange() {
228       let result = this.keyword;
229       if (this.isArrayValue) {
230         //加入缓存用户
231         //如果选择框内有去掉的,则从缓存列表里去掉
232         if (this.isUserType) {
233           let cacheUsers = [];
234           this.cacheUsers.forEach((item) => {
235             if (this.arrayValue.some((obj) => obj == item.label)) {
236               cacheUsers.push({ ...item });
237             }
238           });
239 
240           let selectCacheUsers = this.userList.filter((item) =>
241             this.arrayValue.includes(item.label)
242           );
243           selectCacheUsers.forEach((item) => {
244             if (!cacheUsers.some((user) => user.label == item.label)) {
245               cacheUsers.push({ ...item });
246             }
247           });
248           this.cacheUsers = cacheUsers;
249           //最终值
250           result = cacheUsers.map((item) => item);
251         } else {
252           result = this.arrayValue;
253         }
254       }
255       this.$emit("valueChange", result);
256     },
257   },
258 };
259 </script>
260 
261 <style lang="scss" scoped>
262 .select-box {
263   border: 1px solid #dcdfe6;
264   border-radius: 4px;
265   padding: 10px;
266   margin-top: 10px;
267   max-height: 280px;
268   overflow: auto;
269   max-width: 400px;
270   & .el-checkbox {
271     display: block;
272     margin-top: 5px;
273   }
274 }
275 .no-data {
276   text-align: "center";
277   color: "#909399";
278 }
279 </style>>
View Code

3.popover.vue

 1 <script>
 2 /**
 3  * 重写Popover 解决循环导致生成多个popover实例
 4  */
 5 import { Popover } from "element-ui";
 6 export default {
 7   name: "filterPopover",
 8   extends: Popover,
 9   methods: {
10     popBy(el) {
11       this.close();
12       this.doDestroy(true);
13       this.$nextTick(() => {
14         this.referenceElm = this.$refs.reference = el;
15         this.showPopper = true;
16         this.$emit("input", true);
17       });
18     },
19     close() {
20       this.showPopper = false;
21       this.$emit("input", false);
22     },
23   },
24 };
25 </script>
View Code

 

页面调用代码

  1 <template>
  2   <div class="body-con">
  3     <filter-table
  4       :show-filter-info="true"
  5       :loading="loading"
  6       :data="dataList"
  7       :columns="columnList"
  8       :paging="true"
  9       :total="total"
 10       :page="filterModel.pageNo"
 11       :page-size="filterModel.size"
 12       @confirmFilter="onConfirmFilter"
 13       @sort-change="onSortChange"
 14       @current-change="onCurrentChange"
 15       @size-change="onSizeChange"
 16       @load-tree = "load"
 17     >
 18       <el-table-column label="操作" width="160px">
 19         <template slot-scope="scope">
 20           <el-link class="option-link" :underline="false" size="mini"
 21             >完成{{ scope.row.No }}
 22           </el-link>
 23           <el-link class="option-link" :underline="false" size="mini"
 24             >编辑{{ scope.row.No }}
 25           </el-link>
 26           <el-link class="option-link" :underline="false" size="mini"
 27             >分解{{ scope.row.No }}
 28           </el-link>
 29           <el-link class="option-link" :underline="false" size="mini"
 30             >删除{{ scope.row.No }}
 31           </el-link>
 32         </template>
 33       </el-table-column>
 34     </filter-table>
 35   </div>
 36 </template>
 37 
 38 <script>
 39 import FilterTable from "@/components/FilterTable/index copy.vue";
 40 import { taskApi } from "@/api/pmTask";
 41 import { mapGetters } from "vuex";
 42 import { load } from "jszip/lib/object";
 43 const columnList = [
 44   // { label: "序号", prop: "sortNo", type: "text" },
 45   {
 46     label: "编号",
 47     prop: "missionNo",
 48     type: "text",
 49     sortable: true,
 50     filterable: true,
 51   },
 52   {
 53     label: "标题",
 54     prop: "missionTitle",
 55     type: "text",
 56     sortable: true,
 57     filterable: true,
 58   },
 59   {
 60     label: "类型", 
 61     prop: "type",
 62     type: "select",
 63     sortable: true,
 64     filterable: true,
 65     options: [
 66       { label: "A", value: 1 },
 67       { label: "B", value: 2 },
 68     ],
 69   },
 70   {
 71     label: "状态", 
 72     prop: "status",
 73     type: "select",
 74     sortable: true,
 75     filterable: true,
 76     options: [
 77       { label: "已完成", value: "1" },
 78       { label: "未完成", value: "2" }
 79     ],
 80   },
 81   {
 82     label: "负责人",
 83     prop: "dutyPeopleInfo",
 84     queryprop: "dutyPeopleNos",
 85     type: "current-project-user",
 86     width: "140px",
 87     sortable: true,
 88     filterable: true,
 89     options: [],
 90   },
 91   {
 92     label: "发布人",
 93     prop: "publisherInfo",
 94     queryprop: "publisherNos",
 95     type: "project-user",
 96     width: "140px",
 97     sortable: true,
 98     filterable: true,
 99     options: [],
100   },
101   {
102     label: "计划完成时间",
103     prop: "planEndDate",
104     type: "date",
105     width: "150px",
106     sortable: true,
107     filterable: true,
108   },
109 
110   {
111     label: "实际完成时间",
112     prop: "dateEnd",
113     type: "date",
114     width: "150px",
115     sortable: true,
116     filterable: true,
117   },
118 
119   {
120     label: "进度",
121     prop: "process",
122     type: "text",
123   },
124 
125   {
126     label: "负责人",
127     prop: "publisherNo",
128     type: "user",
129     sortable: true,
130     filterable: true,
131   },
132 ];
133 
134 export default {
135   name: "pmTask",
136   components: {
137     FilterTable,
138   },
139   data() {
140     return {
141       loading: false,
142       dataList: [],
143       total: undefined,
144       columnList: columnList,
145       searchData: {
146         publisherNos: undefined,
147         dutyPeopleNos: undefined,
148       },
149       filterModel: {
150         missionNo: undefined,
151         missionTitle: undefined,
152         types: undefined,
153         queryType: 1,
154         // types:[],
155         pageNo: 1,
156         pageSize: 10,
157         sort: undefined,
158       },
159     };
160   },
161   computed: {
162     ...mapGetters(["currentProject"]),
163   },
164   mounted() {
165     //模拟异步数据
166 
167     //  this.getProjectList();
168     // this.getTypeList();
169     // this.getStateList();
170 
171     this.getList();
172   },
173   methods: {
174     projectClick(row) {
175       console.log(row, "可以点击列");
176     },
177     getProjectList() {
178       getAlmProjectList().then((res) => {
179         const projectArray = res.data.map((item) => {
180           return {
181             value: item.Project,
182             label: item.Project,
183           };
184         });
185         const projectColumn = this.columnList.find(
186           (item) => item.prop == "Project"
187         );
188         projectColumn.options = projectArray;
189         projectColumn.click = this.projectClick;
190       });
191     },
192 
193     getList() {
194       this.loading = true;
195       const searchData = this.searchData;
196       this.filterModel.missionNo = searchData.missionNo || undefined;
197       this.filterModel.missionTitle = searchData.missionTitle || undefined;
198       this.filterModel.types = searchData.type || undefined;
199       this.filterModel.status = searchData.state || undefined;
200       this.filterModel.dutyPeopleNos = searchData.dutyPeopleNos || undefined;
201       this.filterModel.publisherNos = searchData.publisherNos || undefined;
202 
203       this.filterModel.planEndDate = searchData.planEndDate || undefined;
204       this.filterModel.dateEnd = searchData.dateEnd || undefined;
205       
206       // this.filterModel.projectIds = ['14707'].join(',') || undefined;
207 
208       taskApi
209         .getTaskList(this.filterModel)
210         .then((res) => {
211           console.log(res, "code");
212           if (res.code == 200) {
213             let list = res.data.list;
214             list?.forEach((item) => {
215               if(item.hasChildren){
216                 item.children = []
217               }
218               item.dutyPeopleInfo = item.liables
219                 .map((item) => `${item.name}(${item.jobNo})`)
220                 .join(",");
221               item.publisherInfo = `${item.publisher}(${item.publisherNo})`;
222             });
223             console.log(list);
224             this.dataList = list;
225             this.total = res.data.total;
226             // this.filterModel.pageNo = res.data.page;
227           }
228         })
229         .finally((_) => {
230           this.loading = false;
231         });
232     },
233 
234     onCurrentChange(val) {
235       this.filterModel.pageNo = val;
236       this.getList();
237     },
238     onSizeChange(val) {
239       this.filterModel.size = val;
240       this.getList();
241     },
242     onSortChange(column) {
243       console.log(column, "排序变化");
244       if (column.order == null) {
245         this.filterModel.sort = null;
246       } else {
247         this.filterModel.sort = {};
248         this.filterModel.sort.prop = column.prop;
249         this.filterModel.sort.order =
250           column.order === "ascending" ? true : false;
251       }
252 
253       this.getList();
254     },
255     onConfirmFilter(data) {
256       console.log(data, "回调筛选条件");
257       //处理各种人的数据
258 
259       //处理需要转义的人员属性名
260       this.columnList.filter((column) => {
261         if (
262           ["user", "project-user", "current-project-user"].includes(
263             column.type
264           ) &&
265           column.queryprop
266         ) {
267           if (data[column.prop]) {
268             data[column.queryprop] = data[column.prop].map(
269               (item) => item.value
270             );
271           }
272         }
273       });
274 
275       this.searchData = data;
276       console.log({...data}, "回调处理后条件");
277       this.filterModel.pageNo = 1;
278       this.getList();
279     },
280     load(tree,treeNode,resolve){
281       console.log(tree);
282       taskApi.getTaskChildrenById(tree.id).then((result) => {
283         console.log(result);
284         resolve(result.data);
285       }).catch((err) => {
286         
287       });
288     }
289   },
290 };
291 </script>
View Code