el-table 统一封装下拉筛选功能
先上效果图
目前支持:多选,文本模糊搜索,日期,时间,筛选列,筛选项展示
三个文件
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>
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>>
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>
页面调用代码
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>