<template>
  <div class="page">
    <div class="search-box">
      <el-button v-if="$route.query?.type=='init'" type="primary" style="margin-right:10px;" @click="toggleShowCard">地址取点</el-button>
      <input id="tipinput" v-model="searchValue" placeholder="请输入搜索地址" class="input-with-select" @keyup.enter="searchAddress">
      <el-card v-show="showAddrCard" class="addr-card">
        <el-button type="primary" size="small" @click="addressList.push({address:''})">增加范围</el-button>
        <p class="tips">地址的门牌号范围请用“~”号分隔</p>
        <ul>
          <li v-for="(each, index) in addressList" :key="'addressList'+index" class="addr">
            <el-input v-model="each.address" placeholder="请输入详细地址或地址范围" class="el-addr" @keyup.enter.native="getAddressCode(each)">
              <el-button slot="append" type="primary" icon="el-icon-map-location" @click="getAddressCode(each)" />
            </el-input>
            <el-button type="danger" size="mini" class="remove" @click="removeAddress(index)">-</el-button>
          </li>
        </ul>
        <div class="btn-box">
          <el-button v-loading="gettingAddr" type="primary" size="small" @click="createPolygonByAddress">创建地址围点</el-button>
        </div>
      </el-card>
    </div>
    <div id="container" />
    <div class="btn-con">
      <el-button v-if="$route.query.type === 'init' || $route.query.type === 'edit'" type="primary" @click="submitPoly">提交</el-button>
    </div>
  </div>
</template>

<script>
import AMapLoader from '@amap/amap-jsapi-loader'
import { saveSlicePolygon, getSlicePolygon } from '@/api/areaSlice'
export default {
  name: 'MarketMap',
  data() {
    return {
      searchValue: '',
      showAddrCard: false,
      gettingAddr: false,
      map: null,
      addressList: [{ address: '' }],
      AMap: null,
      polyEditor: null,
      basePolygon: {
        fillColor: '#00b0ff',
        fillOpacity: 0.3, // 边框线透明度
        strokeColor: '#3366FF', // 边框线颜色
        strokeOpacity: 0.3, // 边框线透明度
        strokeWeight: 3 // 边框线宽
      },
      mapList: [],
      currenLngLat: [],
      geocoder: null,
      curMarker: null,
      dMenu: null, // 清除片区的菜单
      pMenu: null // 路段锚点右键菜单
    }
  },
  mounted() {
    AMapLoader.load({
      'key': process.env.VUE_APP_AMAP_KEY, // 申请好的Web端开发者Key，首次调用 load 时必填
      'version': '2.0', // 指定要加载的 JSAPI 的版本，缺省时默认为 1.4.15
      'plugins': ['AMap.PolygonEditor', 'AMap.AutoComplete'], // 需要使用的的插件列表，如比例尺'AMap.Scale'等
      'AMapUI': { // 是否加载 AMapUI，缺省不加载
        'version': '1.1', // AMapUI 缺省 1.1
        'plugins': [] // 需要加载的 AMapUI ui插件
      },
      'Loca': { // 是否加载 Loca， 缺省不加载
        'version': '2.0' // Loca 版本，缺省 1.3.2
      }
    }).then((AMap) => {
      this.AMap = AMap
      this.map = new AMap.Map('container', {
        city: '广州市',
        zoom: 14, // 初始地图级别
        resizeEnable: true
      })
      const _this = this
      AMap.plugin(['AMap.PlaceSearch', 'AMap.AutoComplete'], function() {
        var autoOptions = {
          // city 限定城市，默认全国
          input: 'tipinput',
          city: '广州市'
        }
        // 实例化AutoComplete
        const autoComplete = new AMap.AutoComplete(autoOptions)
        var placeSearch = new AMap.PlaceSearch({
          map: _this.map
        })
        autoComplete.on('select', select)
        // 根据关键字进行搜索
        function select(e) {
          placeSearch.setCity(e.poi.adcode)
          placeSearch.search(e.poi.name) // 关键字查询查询
        }
      })
      // 初始化地址编码
      AMap.plugin('AMap.Geocoder', function() {
        _this.geocoder = new AMap.Geocoder({
          // city 指定进行编码查询的城市，支持传入城市名、adcode 和 citycode
          city: '广州'
        })
      })

      // 状态初始化
      const type = this.$route.type
      if (type === 'init') {
        this.$confirm('选取区域后点击右上角进行提交', '提示', {
          showCancelButton: false,
          showClose: false,
          closeOnClickModal: false
        })
      } else {
        let index = 0
        getSlicePolygon(this.$route.query.id).then(res => {
          if (res.data && res.data.length > 0) {
            res.data.forEach(each => {
              this.mapList.push({
                id: new Date().getTime() + index++ + '',
                lngLat: each,
                labelName: this.$route.query.name
              })
            })
            this.initZoning()
          }
        })
      }

      // 初始化范围列表的范围显示
      this.initZoning()
      // 监听绘画覆盖物围点
      this.createEditor()
      // 初始化右键菜单
      this.initRightClickMenu()

      if (this.$route.query.type === 'init') {
        this.polyEditor.setTarget()
        this.polyEditor.open()
      }
    }).catch(e => {
      console.log(e)
    })
  },
  methods: {
    initZoning() {
      // 遍历片区
      if (!this.mapList || this.mapList.length === 0) return
      for (const item of this.mapList) {
        // 初始化覆盖物
        const polygonPath = []
        for (const lngLat of item.lngLat) {
          if (!lngLat) continue
          polygonPath.push(
            new this.AMap.LngLat(lngLat.lng, lngLat.lat),
          )
        }
        // 创建面覆盖物
        const polygon = new this.AMap.Polygon({
          id: item.id,
          path: polygonPath,
          ...this.basePolygon
        })
        this.signMarkerLabel(polygon, item)
        // 绑定添加多个覆盖物事件
        this.map.add(polygon)
        polygon.on('rightclick', (e) => {
          this.dMenu.open(this.map, e.lnglat)
        })
        if (this.$route.query.type === 'edit') {
          this.polyEditor.setTarget(polygon)
          this.polyEditor.open()
        }
      }
      // 自动自适应所有覆盖物
      // this.map.setFitView()
    },
    signMarkerLabel(polygon, item) {
      // 中心点标记
      const centerPoint = this.getCenterPoint(item.lngLat)
      const marker = new this.AMap.Marker({
        icon: '无',
        position: [centerPoint.lng, centerPoint.lat]
      })
      // marker.setLabel({
      //   content: `${item.labelName}`, // 设置文本标注内容
      //   direction: 'center' // 设置文本标注方位
      // })
      marker.setMap(this.map)
      // 设置地图显示中点
      this.map.setCenter(new this.AMap.LngLat(centerPoint.lng, centerPoint.lat))
    },
    getCenterPoint(data) {
      // 获取多边形中点
      let lng = 0.0
      let lat = 0.0
      for (let i = 0; i < data.length; i++) {
        if (!data[i]) { continue }
        lng = lng + parseFloat(data[i].lng)
        lat = lat + parseFloat(data[i].lat)
      }
      lng = lng / data.length
      lat = lat / data.length
      return { lng: lng, lat: lat }
    },
    createEditor(setPolygon) {
      if (setPolygon) {
        if (this.polyEditor) {
          this.polyEditor.setTarget(setPolygon)
          this.polyEditor.open()
        } else {
          this.polyEditor = new this.AMap.PolygonEditor(this.map, setPolygon)
        }
      } else {
        this.polyEditor = new this.AMap.PolygonEditor(this.map)
      }
      const _this = this
      this.polyEditor.on('add', (data) => {
        const polygon = data.target
        // this.polyEditor.addAdsorbPolygons(polygon)
        // polygon.on('dblclick', () => {
        // this.polyEditor.setTarget(polygon)
        // this.polyEditor.open()
        // })
        // 绑定鼠标右击事件——弹出右键菜单
        polygon.on('rightclick', (e) => {
          _this.dMenu.open(_this.map, e.lnglat)
        })
      })
    },
    submitPoly() {
      const target = this.polyEditor.getTarget()
      if (!target) {
        this.$message.warning('请先选取区域')
        return
      }
      this.polyEditor.close()
      const paths = target.getPath()
      this.$confirm('是否确认提交该片区围点信息？', '确认提交', {
        beforeClose: (action, instance, done) => {
          if (action === 'confirm') {
            instance.confirmButtonLoading = true
            const pointList = []
            paths.map(each => pointList.push(each.lng + ',' + each.lat))
            const data = {
              sliceId: this.$route.query.id,
              pointList: pointList
            }
            saveSlicePolygon(data).then(res => {
              if (res.code === 0) {
                this.$message.success('保存成功')
                instance.confirmButtonLoading = false
                done()
                this.$router.replace({ path: '/system/slice/map', query: {
                  ...this.$route.query,
                  type: 'edit'
                }})
                if (window.opener && window.opener.loadPage) {
                  window.opener.loadPage()
                }
              } else {
                this.$message.error('保存失败，' + res.msg)
              }
            })
            setTimeout(() => {
              instance.confirmButtonLoading = false
              done()
            }, 3000)
          } else if (!instance.confirmButtonLoading) {
            this.polyEditor.open()
            done()
          }
        }
      })
    },
    // 右键菜单
    initRightClickMenu() {
      const _this = this
      this.dMenu = new this.AMap.ContextMenu()
      this.dMenu.addItem('清除重画', () => {
        this.$confirm('是否确定删除清除该围点信息？').then(_ => {
          _this.polyEditor.getTarget().destroy()
          _this.polyEditor.setTarget()
          _this.polyEditor.open()
        }).catch(_ => {})
        this.dMenu.close()
      }, 0)
      this.pMenu = new this.AMap.ContextMenu()
      this.pMenu.addItem('清除锚点', e => {
        this.$confirm('是否确定删除清除该锚点信息？').then(_ => {
          this._thisMarker.destroy()
          _this.map.remove(e.target)
        }).catch(_ => {})
        this.pMenu.close()
      }, 0)
    },
    // 显示地址选卡
    toggleShowCard() {
      this.showAddrCard = !this.showAddrCard
      if (this.showAddrCard) {
        this.polyEditor.close()
      } else {
        this.polyEditor.open()
      }
    },
    // 通过地址创建围点地图
    createPolygonByAddress() {
      if (this.gettingAddr) return
      let flag = false
      for (const i in this.addressList) {
        flag = this.$util.isNotEmpty(this.addressList[i].address) | flag
      }
      if (!flag) {
        return this.$message.info('请先输入地址范围')
      }
      let info = '是否确认进行地址围点的创建'
      const polygon = this.polyEditor.getTarget()
      if (polygon) {
        info = '是否确认清除已画围点，并进行地址围点的创建？'
      }
      this.$confirm(info).then(_ => {
        if (polygon) {
          polygon.destroy()
        }
        this.gettingAddr = true
        for (const i in this.addressList) {
          if (this.$util.isNotEmpty(this.addressList[i].address)) {
            this.getAddressCode(this.addressList[i])
          }
        }
        const _this = this
        setTimeout(() => {
          _this.gettingAddr = false
          const mapList = []
          const list = []
          let count = 0
          for (const i in _this.addressList) {
            if (_this.$util.isNotEmpty(_this.addressList[i].address)) {
              const resultList = _this.addressList[i].pointList
              for (const j in resultList) {
                const each = resultList[j]
                list.push(each.location)
                count++
              }
            }
          }
          if (count < 3) {
            return this.$message.error('无法找到3个或以上的地理坐标进行围点创建')
          }
          mapList.push({ lngLat: list })
          _this.mapList = mapList
          const pointList = []
          for (const item of _this.mapList) {
            // 整合点排列
            for (const lngLat of item.lngLat) {
              pointList.push(lngLat)
            }
          }
          // 经纬度点排序
          const lngList = this.pointSort(pointList, 'lng')
          // x轴最大点
          const lastPoint = lngList[lngList.length - 1]
          // 以x轴最小值的点为起点
          const startPoint = lngList[0]
          // 以起点为零点建立直角坐标系，求出x轴最大点与起点形成的直线的斜截式 y=ax+0
          // 求起点与x轴最大点的连线的斜率a
          const a = (lastPoint.lat - startPoint.lat) / (lastPoint.lng - startPoint.lng)
          // 连线
          const polygonPath = []
          for (let i = 0; i < lngList.length; i++) {
            const each = lngList[i]
            if (((each.lat - startPoint.lat) / (each.lng - startPoint.lng)) < a) {
              each.use = true
              polygonPath.push(
                new this.AMap.LngLat(each.lng, each.lat),
              )
            }
          }
          for (let i = lngList.length - 1; i > -1; i--) {
            const each = lngList[i]
            if (!each.use) {
              polygonPath.push(
                new this.AMap.LngLat(each.lng, each.lat),
              )
            } else {
              delete each.use
            }
          }
          // 创建面覆盖物
          const polygon = new _this.AMap.Polygon({
            id: 'AddressPolygon' + new Date().getTime(),
            path: polygonPath,
            ..._this.basePolygon
          })
          polygon.on('rightclick', e => {
            _this.dMenu.open(_this.map, e.lnglat)
          })
          for (const each of _this.addressList) {
            each.markerList.forEach(marker => {
              _this.map.remove(marker)
            })
          }
          _this.map.add(polygon)
          _this.polyEditor.setTarget(polygon)
          _this.polyEditor.open()
          _this.toggleShowCard()
        }, 1500)
      }).catch(_ => {})
    },
    // 点列表排序，key（排序字段，lng经度，lat纬度）
    pointSort(sortList, key) {
      let resultList = []
      sortList.forEach(point => {
        if (resultList.length === 0) {
          resultList.push(point)
        } else {
          for (let i = 0; i < resultList.length; i++) {
            const each = resultList[i]
            if (point[key] > each[key]) {
              if (i === resultList.length - 1) {
                resultList.push(point)
                break
              }
              if (point[key] > resultList[i + 1][key]) {
                continue
              }
              const list = []
              for (let j = 0; j < resultList.length; j++) {
                if (j === i + 1) {
                  list.push(point)
                }
                list.push(resultList[j])
              }
              resultList = list
              break
            } else {
              const list = []
              for (let j = 0; j < resultList.length; j++) {
                if (j === i) {
                  list.push(point)
                }
                list.push(resultList[j])
              }
              resultList = list
              break
            }
          }
        }
      })
      return resultList
    },
    // 搜索地址
    searchAddress() {
      if (this.$util.isEmpty(this.searchValue)) return
      const value = this.searchValue
      const cur = this
      this.geocoder.getLocation(value, (status, result) => {
        if (status === 'complete' && result.info === 'OK') {
          console.log(result)
          if (result && result.geocodes.length > 0) {
            const list = result.geocodes
            for (const i in list) {
              const each = list[i]
              const lnglat = new cur.AMap.LngLat(each.location.lng, each.location.lat)
              const marker = new cur.AMap.Marker({
                position: lnglat, // 经纬度对象，也可以是经纬度构成的一维数组[116.39, 39.9]
                title: each.formattedAddress
              })
              marker.on('rightclick', e => {
                cur._thisMarker = e.target
                cur.pMenu.open(cur.map, e.lnglat)
              })
              cur.map.add(marker)
              this.map.setCenter(lnglat)
            }
          } else {
            cur.$message.info('地址不存在')
          }
        }
      })
    },
    // 删除地址
    removeAddress(index) {
      const addressInfo = this.addressList.splice(index, 1)
      const markerList = addressInfo[0].markerList
      if (markerList) {
        markerList.forEach(each => {
          this.map.remove(each)
        })
      }
    },
    // 获取地址编码
    getAddressCode(addressInfo) {
      const addr = addressInfo.address
      if (this.$util.isEmpty(addr)) return this.$message.info('请输入地址路段')
      const list = this.getAddressRange(addr)
      let count = 0
      const resultList = []
      if (addressInfo.markerList) {
        addressInfo.markerList.forEach(each => {
          this.map.remove(each)
        })
      }
      for (const i in list) {
        this.geocoder.getLocation(list[i], (status, result) => {
          count += 1
          if (status === 'complete' && result.info === 'OK') {
            // result中对应详细地理坐标信息
            /**
             * {"info":"OK","resultNum":"1","geocodes":[{"location":[113.420469,23.039233],"formattedAddress":"广东省广州市番禺区秀发村",
             * "adcode":"440113","level":"村庄","addressComponent":{"neighborhood":"","neighborhoodType":"","building":"","buildingType":""
             * ,"province":"广东省","city":"广州市","district":"番禺区","township":"","citycode":"020","street":"","streetNumber":""}}]}
             */
            resultList[i] = { addr: list[i], location: { lng: result.geocodes[0].location.lng, lat: result.geocodes[0].location.lat }}
          } else {
            resultList[i] = { addr: list[i], location: null }
          }
          if (count === list.length) {
            addressInfo.pointList = resultList
            const markerList = []
            addressInfo.markerList = markerList
            let position = null
            for (let i = 0; i < resultList.length; i++) {
              const each = resultList[i]
              if (each.location) {
                const lnglat = new this.AMap.LngLat(each.location.lng, each.location.lat)
                if (!position) {
                  position = lnglat
                }
                const marker = new this.AMap.Marker({
                  position: lnglat, // 经纬度对象，也可以是经纬度构成的一维数组[116.39, 39.9]
                  title: each.addr
                })
                marker.on('rightclick', e => {
                  this._thisMarker = e.target
                  this.pMenu.open(this.map, e.lnglat)
                })
                markerList.push(marker)
                this.map.add(marker)
              }
            }
            if (position) {
              this.map.setCenter(position)
            }
          }
        })
      }
    },
    // 获取地址范围
    getAddressRange(addr) {
      const list = []
      let exec = /(\d)+\~(\d)+/.exec(addr)
      if (!exec) {
        exec = /(\d)+号\~(\d)+号/.exec(addr)
      }
      if (exec) {
        const match = exec[0]
        if (match.indexOf('号') > -1) {
          const numSplice = match.split('~')
          let num1 = parseInt(numSplice[0].replace('号', ''))
          let num2 = parseInt(numSplice[1].replace('号', ''))
          if (num1 > num2) {
            const temp = num2
            num2 = num1
            num1 = temp
          }
          for (let i = num1; i <= num2; i++) {
            list.push(addr.replace(match, i + '号'))
          }
        } else {
          const numSplice = match.split('~')
          let num1 = parseInt(numSplice[0])
          let num2 = parseInt(numSplice[1])
          if (num1 > num2) {
            const temp = num2
            num2 = num1
            num1 = temp
          }
          for (let i = num1; i <= num2; i++) {
            list.push(addr.replace(match, i + ''))
          }
        }
      } else {
        list.push(addr)
      }
      return list
    }
  }
}
</script>
<style lang="scss" scoped>
.page{
  position: relative;
  .btn-con{
    position: absolute;
    right: 50px;
    top: 50px;
  }
  .search-box{
    position:fixed;
    top:55px;
    right:160px;
    z-index:9999;
    input{
      height:35px;
      padding:7px;
    }
    .addr-card{
      min-width:355px;
      ul{
        list-style:none;
        padding-inline-start:0;
        li.addr{
          .el-addr{
            width:calc(100% - 45px)
          }
          .remove{
            margin-left:5px;
          }
        }
      }
      .tips{
        color:grey;
        font-size:12px;
      }
    }
  }
}
#container{
  height: 100vh;
  width: 100%;
}
</style>
