250 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			250 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <template>
 | |
|   <section class="AiTableSelect">
 | |
|     <el-row type="flex">
 | |
|       <ai-table v-if="isShowPagination" ref="PendingTable" :tableData="tableData" :total="page.total" :current.sync="page.current"
 | |
|                 :size.sync="page.size" class="fill" border height="330px" @getList="getTableData" tableSize="mini"
 | |
|                 :col-configs="[{slot: 'resident'}]" layout="slot,->, prev, pager, next, jumper" :pagerCount="5">
 | |
|         <el-table-column slot="resident" class="ai-table__header">
 | |
|           <template #header>
 | |
|             <b v-text="tableTitle"/>
 | |
|             <el-input class="fill searchbar" v-model="search[searchKey]" size="small" placeholder="搜索" clearable
 | |
|                       @change="page.current=1,getTableData()"/>
 | |
|           </template>
 | |
|           <template slot-scope="{row}">
 | |
|             <slot name="pending" v-if="$scopedSlots.pending" :row="row"/>
 | |
|             <el-row v-else type="flex" justify="space-between" @click.native="handleSelect(row)" class="toggle"
 | |
|                     :class="{selected:findSelected(row)>-1}">
 | |
|               <span v-text="row[nodeName]"/>
 | |
|               <slot name="extra" v-if="$scopedSlots.extra" :row="row"/>
 | |
|               <span v-else v-text="getExtra(row)"/>
 | |
|             </el-row>
 | |
|           </template>
 | |
|         </el-table-column>
 | |
|       </ai-table>
 | |
|       <ai-table v-else ref="PendingTable" :tableData="tableData" class="fill" border height="330px" @getList="getTableData" tableSize="mini"
 | |
|                 :col-configs="[{slot: 'resident'}]" :isShowPagination="false">
 | |
|         <el-table-column slot="resident">
 | |
|           <template #header>
 | |
|             <b v-text="tableTitle"/>
 | |
|             <el-input class="fill searchbar" v-model="search[searchKey]" size="small" placeholder="搜索" clearable
 | |
|                       @change="page.current=1,getTableData()"/>
 | |
|           </template>
 | |
|           <template slot-scope="{row}">
 | |
|             <slot name="pending" v-if="$scopedSlots.pending" :row="row"/>
 | |
|             <el-row v-else type="flex" justify="space-between" @click.native="handleSelect(row)" class="toggle"
 | |
|                     :class="{selected:findSelected(row)>-1}">
 | |
|               <span v-text="row[nodeName]"/>
 | |
|               <slot name="extra" v-if="$scopedSlots.extra" :row="row"/>
 | |
|               <span v-else v-text="getExtra(row)"/>
 | |
|             </el-row>
 | |
|           </template>
 | |
|         </el-table-column>
 | |
|       </ai-table>
 | |
|       <ai-table :tableData="selected" :col-configs="[{slot:'resident'}]" :isShowPagination="false" border
 | |
|                 height="330px" tableSize="mini" class="el-table--scrollable-y fill">
 | |
|         <el-table-column slot="resident">
 | |
|           <template #header>
 | |
|             <b v-text="`已选择`"/>
 | |
|             <el-button type="text" @click="selected=[]">清空</el-button>
 | |
|           </template>
 | |
|           <template slot-scope="{row,$index}">
 | |
|             <slot name="selected" v-if="$scopedSlots.selected" :row="row" :index="$index"/>
 | |
|             <el-row v-else type="flex" align="middle" justify="space-between">
 | |
|               <div v-text="[row[nodeName], getExtra(row)].join(' ')"/>
 | |
|               <el-button type="text" @click="selected.splice($index,1)">删除</el-button>
 | |
|             </el-row>
 | |
|           </template>
 | |
|         </el-table-column>
 | |
|       </ai-table>
 | |
|     </el-row>
 | |
|   </section>
 | |
| </template>
 | |
| 
 | |
| <script>
 | |
| /**
 | |
|  * 智能列表选择器
 | |
|  * @displayName AiTableSelect
 | |
|  */
 | |
| export default {
 | |
|   name: "AiTableSelect",
 | |
|   model: {
 | |
|     event: "change",
 | |
|     prop: "value"
 | |
|   },
 | |
|   props: {
 | |
|     /**
 | |
|      * 接口方法类:必填
 | |
|      */
 | |
|     instance: {type: Function, required: true},
 | |
|     /**
 | |
|      * 接口方法地址:必填
 | |
|      */
 | |
|     action: {default: "", required: true},
 | |
|     /**
 | |
|      * 选择表格标题
 | |
|      */
 | |
|     tableTitle: {default: "选择列表"},
 | |
|     /**
 | |
|      * 选择项
 | |
|      * @model
 | |
|      */
 | |
|     value: {default: ""},
 | |
|     /**
 | |
|      * 选择项绑定key
 | |
|      */
 | |
|     nodeKey: {default: "id"},
 | |
|     /**
 | |
|      * 选择项绑定展示值:必填
 | |
|      */
 | |
|     nodeName: {default: "name"},
 | |
|     /**
 | |
|      * 是否多选
 | |
|      */
 | |
|     multiple: Boolean,
 | |
|     /**
 | |
|      * 返回值为选择的对象而不是id
 | |
|      */
 | |
|     valueObj: Boolean,
 | |
|     /**
 | |
|      * 扩展字段,用于右侧展示
 | |
|      */
 | |
|     extra: {default: ""},
 | |
|     /**
 | |
|      * 搜索字段,用于搜索框
 | |
|      */
 | |
|     searchKey: {default: "con"},
 | |
|     /**
 | |
|      * 是否分页
 | |
|      */
 | |
|     isShowPagination: {default: true}
 | |
|   },
 | |
|   data() {
 | |
|     return {
 | |
|       page: {total: 0, current: 1, size: 10},
 | |
|       search: {},
 | |
|       tableData: [],
 | |
|       selected: [],
 | |
|     }
 | |
|   },
 | |
|   watch: {
 | |
|     action(v) {
 | |
|       v && (this.page.current = 1, this.getTableData())
 | |
|     },
 | |
|     selected: {
 | |
|       deep: true, handler(v) {
 | |
|         let ids = v.map(e => e[this.nodeKey] || e).filter(e => !!e)
 | |
|         this.$emit("change", this.valueObj ? v : this.multiple ? ids : ids?.toString())
 | |
|         this.$emit("select", v)
 | |
|       }
 | |
|     }
 | |
|   },
 | |
|   methods: {
 | |
|     getExtra(row) {
 | |
|       let {extra} = this
 | |
|       return extra ? row[extra] : this.idCardNoUtil.hideId(row.idNumber)
 | |
|     },
 | |
|     initValue() {
 | |
|       let unwatch = this.$watch('value', (v) => {
 | |
|         if (this.selected.length > 0) unwatch && unwatch()
 | |
|         else if (!!v) {
 | |
|           this.selected = this.multiple ? [v].flat().filter(e => !!e) || [] : (v?.split(",") || [])
 | |
|           unwatch && unwatch()
 | |
|         }
 | |
|       }, {immediate: true})
 | |
|     },
 | |
|     getTableData() {
 | |
|       let {page, search, action} = this
 | |
|       this.instance?.post(action, null, {
 | |
|         params: {...page, ...search}
 | |
|       }).then(res => {
 | |
|         if (res?.data) {
 | |
|           this.tableData = res.data.records || res.data || []
 | |
|           this.isShowPagination && (this.page.total = res.data.total)
 | |
|         }
 | |
|       })
 | |
|     },
 | |
|     handleSelect(row) {
 | |
|       let index = this.findSelected(row)
 | |
|       if (index > -1) {
 | |
|         this.selected.splice(index, 1)
 | |
|       } else {
 | |
|         if (this.multiple) {
 | |
|           this.selected.push(row)
 | |
|         } else {
 | |
|           this.selected = [row]
 | |
|         }
 | |
|       }
 | |
|       this.$forceUpdate()
 | |
|     },
 | |
|     findSelected(item) {
 | |
|       let {nodeKey} = this
 | |
|       return this.selected?.findIndex(e => e[nodeKey] == item[nodeKey])
 | |
|     },
 | |
|   },
 | |
|   created() {
 | |
|     this.$set(this.search, this.searchKey, "")
 | |
|     this.initValue()
 | |
|     this.getTableData()
 | |
|   }
 | |
| }
 | |
| </script>
 | |
| 
 | |
| <style lang="scss" scoped>
 | |
| 
 | |
| :deep(.AiTableSelect){
 | |
|   .el-row {
 | |
|     width: 100%;
 | |
| 
 | |
|     .ai-table + .ai-table {
 | |
|       margin-left: 16px;
 | |
|       width: 400px;
 | |
| 
 | |
|       .ai-table__header > .cell {
 | |
|         line-height: 40px;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   .toggle {
 | |
|     cursor: pointer;
 | |
| 
 | |
|     &.selected {
 | |
|       color: $primaryColor;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   .searchbar {
 | |
|     padding-right: 0;
 | |
|   }
 | |
| 
 | |
|   .newPagination {
 | |
|     height: 32px;
 | |
|     padding: 0 !important;
 | |
|     margin-top: 8px;
 | |
|   }
 | |
| 
 | |
|   .ai-table__cell {
 | |
|     .el-button--text {
 | |
|       padding: 0 8px;
 | |
|       height: 24px;
 | |
|     }
 | |
|   }
 | |
| 
 | |
| }
 | |
| :deep(.ai-table__header) {
 | |
|   & > .cell {
 | |
|     display: flex !important;
 | |
|     align-items: center !important;
 | |
|     justify-content: space-between !important;
 | |
|   }
 | |
| }
 | |
| :deep(.ai-table .el-table__header tr th:first-child .cell) {
 | |
|   padding-left: 20px !important;
 | |
| }
 | |
| 
 | |
| :deep(.ai-table .el-table__body tr td:first-child .cell ) {
 | |
|   padding-left: 20px !important;
 | |
| }
 | |
| 
 | |
| </style>
 |