211 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <template>
 | |
|   <section class="AiTreePicker">
 | |
|     <AiSearchPopup mode="bottom" ref="areaSelector">
 | |
|       <div slot="btn" @tap="handleInit">
 | |
|         <slot v-if="$slots.default" />
 | |
|         <div v-else class="areaSelector">
 | |
|           <u-input v-model="currentSelected.girdName" disabled class="noEvents" />
 | |
|         </div>
 | |
|       </div>
 | |
|       <div class="areaSelector">
 | |
|         <div class="fixedTop">
 | |
|           <span v-text="'全部'" :class="{ current: !index }" @click="selectNode({}, -1)" />
 | |
|           <span v-for="(area, i) in fullSelected" :key="area.id" v-text="area.girdName" :class="{ current: area.id == index }" @click="selectNode(area, i)" />
 | |
|         </div>
 | |
|         <span class="placeholder" v-text="currentSelected.girdName" />
 | |
|       </div>
 | |
|       <div class="pendingItem flexRow" flex v-for="op in list" :key="op.id">
 | |
|         <div class="fill" :class="{ self: index == op.id }" v-html="op.girdName" @tap="handleSelect(op)" />
 | |
|         <u-icon v-if="showArrow(op)" name="arrow-right" color="#ddd" @click="getChild(op)" />
 | |
|       </div>
 | |
|     </AiSearchPopup>
 | |
|   </section>
 | |
| </template>
 | |
| 
 | |
| <script>
 | |
| // import AiCell from './AiCell'
 | |
| import { mapState } from 'vuex'
 | |
| 
 | |
| export default {
 | |
|   name: 'AiTreePicker',
 | |
|   components: {
 | |
|     // AiCell
 | |
|   },
 | |
|   model: {
 | |
|     prop: 'value',
 | |
|     event: 'change',
 | |
|   },
 | |
|   props: {
 | |
|     value: { default: '' },
 | |
|     name: { default: '' },
 | |
|     ops: { default: () => [] },
 | |
|   },
 | |
|   computed: {
 | |
|     ...mapState(['user']),
 | |
|     currentSelected() {
 | |
|       return this.fullSelected?.slice(-1)?.[0] || {}
 | |
|     },
 | |
|     origin() {
 | |
|       let meta = JSON.parse(JSON.stringify(this.ops)),
 | |
|         origin = []
 | |
|       while (meta.length > 0) {
 | |
|         let p = meta.shift()
 | |
|         origin.push(p)
 | |
|         if (p.girdList?.length > 0) {
 | |
|           meta.push(p.girdList.map((c) => ({ ...c, parent: p.id })))
 | |
|         }
 | |
|       }
 | |
|       return origin.flat()
 | |
|     },
 | |
|   },
 | |
|   data() {
 | |
|     return {
 | |
|       fullSelected: [],
 | |
|       index: '',
 | |
|       list: [],
 | |
|     }
 | |
|   },
 | |
|   watch: {
 | |
|     value(v) {
 | |
|       v && this.getFull()
 | |
|     },
 | |
|   },
 | |
|   methods: {
 | |
|     getFull() {
 | |
|       if (this.value) {
 | |
|         let current = this.origin.find((e) => e.id == this.value),
 | |
|           pend = [current]
 | |
|         while (!!current.parent) {
 | |
|           current = this.origin.find((e) => e.id == current.parent)
 | |
|           pend.push(current)
 | |
|         }
 | |
|         this.fullSelected = pend.reverse()
 | |
|       }
 | |
|     },
 | |
|     getgirdList(id) {
 | |
|       if (id) this.list = this.origin?.find((e) => e.id == id)?.girdList || []
 | |
|       else this.list = this.ops
 | |
|     },
 | |
|     handleSelect(op) {
 | |
|       if (op.girdList?.length > 0) {
 | |
|         this.getChild(op)
 | |
|       } else {
 | |
|         if (op.id != this.index) {
 | |
|           this.fullSelected.push(op)
 | |
|           this.index = op.id
 | |
|         }
 | |
|         this.$emit('select', op)
 | |
|         this.$emit('update:name', this.currentSelected.name)
 | |
|         this.$refs.areaSelector?.handleSelect()
 | |
|       }
 | |
|     },
 | |
|     getChild(op) {
 | |
|       this.fullSelected.push(op)
 | |
|       this.index = op.id
 | |
|       this.getgirdList(op.id)
 | |
|     },
 | |
|     selectNode(item, i) {
 | |
|       this.fullSelected.splice(i + 1, this.fullSelected.length - i)
 | |
|       if (item.girdList?.length <= 0) {
 | |
|         this.index = item.id
 | |
|       }
 | |
|       this.getgirdList(item.id)
 | |
|     },
 | |
|     handleInit() {
 | |
|       this.index = this.currentSelected.id
 | |
|       this.getgirdList(this.currentSelected.id)
 | |
|     },
 | |
|     showArrow(op) {
 | |
|       return this.index != op.id && op.girdList?.length > 0
 | |
|     },
 | |
|   },
 | |
|   created() {
 | |
|     this.index = this.value
 | |
|     this.getFull()
 | |
|   },
 | |
| }
 | |
| </script>
 | |
| 
 | |
| <style lang="scss" scoped>
 | |
| .AiTreePicker {
 | |
|   ::v-deep .areaSelector {
 | |
|     display: flex;
 | |
|     align-items: center;
 | |
| 
 | |
|     span {
 | |
|       cursor: pointer;
 | |
|       color: #333;
 | |
|       height: 120px;
 | |
|       display: flex;
 | |
|       align-items: center;
 | |
| 
 | |
|       &:first-of-type:before {
 | |
|         content: '';
 | |
|         padding: 0;
 | |
|       }
 | |
| 
 | |
|       &:before {
 | |
|         color: #333;
 | |
|         content: '/';
 | |
|         padding: 0 16px;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     .placeholder {
 | |
|       height: 120px;
 | |
|       width: 100%;
 | |
|     }
 | |
| 
 | |
|     .current {
 | |
|       color: #3f8df5;
 | |
|     }
 | |
| 
 | |
|     .fixedTop {
 | |
|       position: fixed;
 | |
|       top: 0;
 | |
|       width: 100%;
 | |
|       left: 0;
 | |
|       background: #fff;
 | |
|       border-bottom: 4px solid #f5f5f5;
 | |
|       z-index: 1;
 | |
|       text-align: start;
 | |
|       padding: 0 32px;
 | |
|       display: flex;
 | |
|       flex-wrap: wrap;
 | |
|       align-items: center;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   ::v-deep.u-drawer-content {
 | |
|     position: fixed;
 | |
| 
 | |
|     .areaSelector {
 | |
|       padding: 0 16px;
 | |
|       box-sizing: border-box;
 | |
|       border-bottom: 16px solid #f5f5f5;
 | |
| 
 | |
|       span {
 | |
|         line-height: 100px;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   ::v-deep.pendingItem {
 | |
|     color: #333;
 | |
|     margin-left: 32px;
 | |
|     padding-right: 32px;
 | |
|     height: 104px;
 | |
|     border-bottom: 1px solid #ddd;
 | |
|     text-align: start;
 | |
| 
 | |
|     .self {
 | |
|       font-weight: bold;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   ::v-deep.noEvents {
 | |
|     pointer-events: none;
 | |
|   }
 | |
| }
 | |
| </style>
 |