网格
This commit is contained in:
		
							
								
								
									
										267
									
								
								src/apps/AppGridManagement/Map.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										267
									
								
								src/apps/AppGridManagement/Map.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,267 @@ | ||||
| <template> | ||||
|   <div class="detail"> | ||||
|     <div class="grid-select"> | ||||
|       <span class="label">网格选择</span> | ||||
|       <div class="value"> | ||||
|         <AiTreePicker :ops="treeList" v-model="form.id" @select="handleSelect"> | ||||
|           <div class="grid-name" :style="{ color: form.girdName ? '' : '#c0c4cc' }">{{ form.girdName || '请选择网格' }} | ||||
|             <u-icon name="arrow-right" color="#cccccc" size="14"></u-icon> | ||||
|           </div> | ||||
|         </AiTreePicker> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="map-content"> | ||||
|       <AiTMap ref="AiTMap" :map.sync="map" :lib.sync="lib" :libraries="['service', 'tools']"/> | ||||
|     </div> | ||||
|     <u-popup v-model="show" mode="bottom" border-radius="14"> | ||||
|       <div class="popup"> | ||||
|         <div class="bg"></div> | ||||
|         <div class="title">{{ form.girdName }}</div> | ||||
|         <div class="info-flex"> | ||||
|           <span class="label">网格类型</span> | ||||
|           <span class="value">{{ $dict.getLabel('girdType', form.girdType) }}</span> | ||||
|         </div> | ||||
|         <div class="info-flex"> | ||||
|           <span class="label">网格层级</span> | ||||
|           <span class="value">{{ $dict.getLabel('girdLevel', form.girdLevel) }}</span> | ||||
|         </div> | ||||
|         <div v-if="form.girdMemberList && form.girdMemberList.length"> | ||||
|           <div class="info-flex" v-for="(item, index) in  form.girdMemberList" :key="index"> | ||||
|             <span class="label">网格管理员</span> | ||||
|             <span class="value">{{ item.name }}  {{ item.phone }} | ||||
|               <img :src="$cdn + 'common/phone.png'" alt="" @click="callPhone(item.phone)" class="phone-icon" | ||||
|                    v-if="item.phone"> | ||||
|             </span> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </u-popup> | ||||
|  | ||||
|     <div class="footer" @click="show=true" v-if="form.id && !show"> | ||||
|       <div class="btn">查看网格信息</div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from 'vuex' | ||||
|  | ||||
| export default { | ||||
|  | ||||
|   data() { | ||||
|     return { | ||||
|       areaId: '', | ||||
|       lib: null, | ||||
|       map: null, | ||||
|       show: false, | ||||
|       form: {girdName: '', id: ''}, | ||||
|       treeList: [], | ||||
|       showSelect: false, | ||||
|       editor: null, | ||||
|       polygons: [] | ||||
|     } | ||||
|   }, | ||||
|   computed: {...mapState(['user', 'config'])}, | ||||
|   created() { | ||||
|     this.$dict.load('girdType', 'girdLevel') | ||||
|     this.areaId = this.user.areaId | ||||
|     this.getLeafNodes() | ||||
|   }, | ||||
|   onShow() { | ||||
|     document.title = "网格管理" | ||||
|   }, | ||||
|   methods: { | ||||
|     getLeafNodes() { | ||||
|       this.$http.post(`/app/appgirdinfo/queryGirdMemberGirdsById`).then((res) => { | ||||
|         if (res?.data) { | ||||
|           let arr = [] | ||||
|           this.treeList = res.data | ||||
|           res.data.forEach(e => { | ||||
|             if (e.points?.length > 0) { | ||||
|               arr.push(e.points.map(p => [p.lng, p.lat])) | ||||
|             } | ||||
|           }) | ||||
|           arr.length > 0 && this.renderGridMap(arr) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     renderGridMap(paths, count = 0) { | ||||
|       let {map, lib: TMap, $refs: {AiTMap: {fitBounds}}} = this | ||||
|       if (TMap) { | ||||
|         const colors = ["#A194F4", "#7CBDF3", "#F3A57D", "#62D063", "#58DBDA", "#F7D151"] | ||||
|         if (this.polygons.length > 0) { | ||||
|           this.polygons.forEach(e => e.destroy()) | ||||
|           this.polygons = [] | ||||
|         } | ||||
|         if (paths?.length > 0) { | ||||
|           let bounds = [] | ||||
|           paths.forEach((path, i) => { | ||||
|             let color = colors[i % colors.length] | ||||
|             let polygon = new TMap.MultiPolygon({ | ||||
|               map, styles: { | ||||
|                 default: new TMap.PolygonStyle({ | ||||
|                   showBorder: true, | ||||
|                   borderColor: color, | ||||
|                   borderWidth: 2, | ||||
|                   color: this.$colorUtils.Hex2RGBA(color, 0.1), | ||||
|                   borderDashArray: [10, 10] | ||||
|                 }) | ||||
|               }, | ||||
|               geometries: [{paths: path.map(e => new TMap.LatLng(e[1], e[0]))}] | ||||
|             }) | ||||
|             this.polygons.push(polygon) | ||||
|             bounds.push(fitBounds(path.map(e => new TMap.LatLng(e[1], e[0])))) | ||||
|           }) | ||||
|           bounds = bounds.reduce((a, b) => { | ||||
|             return fitBounds([ | ||||
|               a.getNorthEast(), | ||||
|               a.getSouthWest(), | ||||
|               b.getNorthEast(), | ||||
|               b.getSouthWest(), | ||||
|             ]); | ||||
|           }); | ||||
|           map.fitBounds(bounds, {padding: 100}) | ||||
|         } else { | ||||
|           map.setCenter(this.config.latlng) | ||||
|         } | ||||
|  | ||||
|       } else { | ||||
|         if (count < 5) { | ||||
|           setTimeout(() => { | ||||
|             this.renderGridMap(paths, ++count) | ||||
|           }, 1000) | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     callPhone(phone) { | ||||
|       uni.makePhoneCall({phoneNumber: phone}) | ||||
|     }, | ||||
|     handleSelect(e) { | ||||
|       if (e?.points?.length > 0) { | ||||
|         this.form = e | ||||
|         let path = e.points?.map(p => [p.lng, p.lat]) || [] | ||||
|         this.renderGridMap([path]) | ||||
|       } else { | ||||
|         this.$u.toast("所选网格没有标绘!") | ||||
|       } | ||||
|     }, | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| ::v-deep uni-page-body { | ||||
|   height: 100%; | ||||
| } | ||||
|  | ||||
| ai-tree-picker { | ||||
|   display: inline-block; | ||||
| } | ||||
|  | ||||
| .detail { | ||||
|   height: 100%; | ||||
|  | ||||
|   .grid-select { | ||||
|     width: 100%; | ||||
|     padding: 34px 32px; | ||||
|     box-sizing: border-box; | ||||
|     background: #FFF; | ||||
|     display: flex; | ||||
|     justify-content: space-between; | ||||
|     line-height: 44px; | ||||
|     color: #333; | ||||
|  | ||||
|     .label { | ||||
|       display: inline-block; | ||||
|       width: 140px; | ||||
|       font-size: 32px; | ||||
|     } | ||||
|  | ||||
|     .value { | ||||
|       font-size: 28px; | ||||
|  | ||||
|       .u-icon { | ||||
|         margin-left: 8px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .map-content { | ||||
|     width: 100%; | ||||
|     height: calc(100% - 210px); | ||||
|   } | ||||
|  | ||||
|   .popup { | ||||
|     padding: 0 32px 16px; | ||||
|  | ||||
|     .bg { | ||||
|       width: 64px; | ||||
|       height: 10px; | ||||
|       background: #CCC; | ||||
|       border-radius: 6px; | ||||
|       margin: 32px 0 32px 344px; | ||||
|     } | ||||
|  | ||||
|     .title { | ||||
|       font-size: 36px; | ||||
|       font-family: PingFang-SC-Heavy, PingFang-SC; | ||||
|       font-weight: 800; | ||||
|       color: #333; | ||||
|       line-height: 50px; | ||||
|       margin-bottom: 24px; | ||||
|     } | ||||
|  | ||||
|     .info-flex { | ||||
|       padding: 26px 0 30px 0; | ||||
|       width: 100%; | ||||
|       border-bottom: 1px solid #D8DDE6; | ||||
|       line-height: 40px; | ||||
|       font-size: 28px; | ||||
|  | ||||
|       .label { | ||||
|         display: inline-block; | ||||
|         width: 160px; | ||||
|         font-weight: 800; | ||||
|         color: #333; | ||||
|       } | ||||
|  | ||||
|       .value { | ||||
|         color: #666; | ||||
|         font-size: 26px; | ||||
|  | ||||
|         .phone-icon { | ||||
|           width: 40px; | ||||
|           height: 40px; | ||||
|           vertical-align: sub; | ||||
|           margin-left: 16px; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| .grid-name { | ||||
|   display: inline-block; | ||||
| } | ||||
|  | ||||
| .footer { | ||||
|   width: 100%; | ||||
|   position: fixed; | ||||
|   bottom: 0; | ||||
|   left: 0; | ||||
|   z-index: 99999; | ||||
|   display: flex; | ||||
|   font-size: 32px; | ||||
|   font-family: PingFangSC-Medium, PingFang SC; | ||||
|   font-weight: 500; | ||||
|   height: 112px; | ||||
|   line-height: 112px; | ||||
|   text-align: center; | ||||
|  | ||||
|   .btn { | ||||
|     flex: 2; | ||||
|     background: #1365DD; | ||||
|     color: #FFF; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
		Reference in New Issue
	
	Block a user