dtl.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. <template>
  2. <div class="app-container">
  3. <div :class="isDbShow ? 'scoped-deal-box' : 'scoped-deal-box t2'">
  4. <div class="sdb-info">
  5. <div class="p1">当前缩放级别:{{mapDiyObj.zoom}}<span class="more" @click="setShowChange">{{isMapSetShow ? '收起设置' : '展开设置'}}></span></div>
  6. <div class="p2" v-show="isMapSetShow">
  7. <base-form ref="ruleForm" :data="formData" :is-inline="false" label-width="80px">
  8. <div slot="footer">
  9. <el-button class="xl-form-btn bgc2" @click="setHandle">设置</el-button>
  10. <div class="scoped-select-center" @click="setCenterHandle">中心坐标<div class="s">{{centerStr}}</div></div>
  11. </div>
  12. </base-form>
  13. </div>
  14. </div>
  15. <div class="sdb-add">
  16. <div class="b t2" @click="openMte('polygonAdd')">添加多边形</div>
  17. <div class="b t2" @click="openMte('textAdd')">添加文字</div>
  18. </div>
  19. <div class="sdb-add">
  20. <div class="b t3" @click="saveHandle()">保 存</div>
  21. </div>
  22. <div class="sdb-list" v-if="polygons.length > 0">
  23. <div class="label t2">多边形列表</div>
  24. <div class="ul">
  25. <div class="op" v-for="(polygon, index) in polygons" :key="index">
  26. <p class="p1" @click="openMte('polygonAdd', {obj: polygon, index})">{{polygon.text}}</p>
  27. <p class="more">
  28. <span v-if="polygon.editable" class="d d2" @click="textAdd(polygon)">标点</span>
  29. <span v-if="polygon.editable" class="d d1" @click="mapIsEdit(index, 'polygons')">编辑</span>
  30. <span v-else class="d d3" @click="mapIsEdit(index, 'polygons')">只读</span>
  31. <span class="d d4" @click="mapDel(index, 'polygons')">删除</span>
  32. </p>
  33. </div>
  34. </div>
  35. </div>
  36. <div class="sdb-list" v-if="markerData.length > 0">
  37. <div class="label t2">文字列表(选中:{{curMarkersIndex + 1}})</div>
  38. <div class="ul">
  39. <div class="op" v-for="(t, index) in markerData" :key="index">
  40. <p class="p1" @click="openMte('textAdd', {obj: t, index})">({{curMarkersIndex + 1}}){{t.content}}</p>
  41. <p class="more">
  42. <span v-if="t.draggable" class="d d1" @click="mapIsEdit(index, 'markerData')">编辑</span>
  43. <span v-else class="d d3" @click="mapIsEdit(index, 'markerData')">只读</span>
  44. <span class="d d4" @click="mapDel(index, 'markerData')">删除</span>
  45. </p>
  46. </div>
  47. </div>
  48. </div>
  49. </div>
  50. <el-amap
  51. class="amap-box"
  52. :vid="'amap-vue'"
  53. :amap-manager="amapManager"
  54. :zoom="mapDiyObj.zoom"
  55. :zooms="mapDiyObj.zooms"
  56. :mapStyle="mapDiyObj.mapStyle"
  57. :center="mapDiyObj.center"
  58. :events="events"
  59. :plugin="plugin"
  60. >
  61. <template v-if="mapDiyObj.zoom > 3">
  62. <el-amap-marker v-for="(marker, index) in markerData" :key="1000 + index"
  63. :position="marker.position"
  64. :draggable="marker.draggable"
  65. :animation="marker.animation"
  66. :offset="marker.offset"
  67. :events="markersEvents">
  68. <div class="scoped-marker-text" :style="`color: ${marker.color}`">{{marker.content}}</div>
  69. </el-amap-marker>
  70. </template>
  71. <el-amap-polygon
  72. v-for="(polygon, index) in polygons"
  73. :key="index"
  74. :path="polygon.path"
  75. :editable="polygon.editable"
  76. :fillColor="polygon.fillColor"
  77. :fillOpacity="polygon.fillOpacity"
  78. :strokeColor="polygon.strokeColor"
  79. :strokeWeight="polygon.strokeWeight"
  80. :strokeOpacity="polygon.strokeOpacity"
  81. :extData="{index}"
  82. :events="polygonEvents">
  83. </el-amap-polygon>
  84. </el-amap>
  85. <MapTextEdit
  86. :isShow="isMteShow"
  87. :mteStr="mteStr"
  88. :curObj="mteObj"
  89. @close="closeMte"/>
  90. </div>
  91. </template>
  92. <script>
  93. import { AMapManager, lazyAMapApiLoaderInstance } from 'vue-amap'
  94. const amapManager = new AMapManager()
  95. import MapTextEdit from './components/popup/MapTextEdit'
  96. import { arrToObj } from '@/utils'
  97. export default {
  98. name: 'map',
  99. components: {
  100. MapTextEdit
  101. },
  102. mixins,
  103. data() {
  104. const that = this
  105. return {
  106. isDbShow: true,
  107. isMapSetShow: false,
  108. formData: [],
  109. isMteShow: false,
  110. mapDiyObj: {
  111. center: [115.852386, 28.684076],
  112. zoom: 17,
  113. zooms: [15, 19],
  114. },
  115. amapManager,
  116. polygons: [
  117. // {
  118. // path: [[115.823481,28.702359],[115.861933,28.672241],[115.812838,28.629609],[115.793784,28.657179]],
  119. // strokeWeight: 2,
  120. // fillColor: '#f00',
  121. // strokeStyle: 'solid',
  122. // },
  123. // {
  124. // path: [[115.859015,28.654919],[115.93386,28.630212],[115.841849,28.606101]],
  125. // editable: true,
  126. // strokeWeight: 1,
  127. // fillColor: '#ffffff',
  128. // strokeStyle: 'dashed',
  129. // },
  130. ],
  131. markerData: [],
  132. events: {
  133. init(map) {
  134. // map.setFeatures(['road', 'point', 'bg', 'building']); // 多个种类要素显示
  135. // map.setFeatures(['road']); // 多个种类要素显示
  136. // map.setMapStyle('amap://styles/647a4a7f773b3c7143b46e7c3e499f1f');
  137. AMapUI.loadUI(['control/BasicControl'], function(BasicControl) {
  138. //图层切换控件
  139. var layerControl = new BasicControl.LayerSwitcher({
  140. baseLayers: [
  141. {
  142. id: 'basic',//图层id,需唯一
  143. enable: true, //是否启用
  144. name: '基础地图',//显示名称,html
  145. layer: new AMap.TileLayer()
  146. },
  147. {
  148. id: 'Satellite',//图层id,需唯一
  149. enable: false, //是否启用
  150. name: '卫星图',//显示名称,html
  151. layer: new AMap.TileLayer.Satellite()
  152. },
  153. ],
  154. overlayLayers:[
  155. ],
  156. position: {
  157. bottom:'50px',
  158. right:'30px',
  159. },
  160. });
  161. map.addControl(layerControl);
  162. })
  163. },
  164. zoomchange (e) {
  165. const curMap = amapManager.getMap()
  166. that.mapDiyObj.zoom = curMap.getZoom() || 17
  167. },
  168. // click(e) {
  169. // const { lng, lat } = e.lnglat
  170. // console.log(lng, lat)
  171. // },
  172. },
  173. markersEvents: {
  174. dragend(e) {
  175. const { lng, lat } = e.lnglat
  176. let markerData = JSON.parse(JSON.stringify(that.markerData))
  177. markerData[that.curMarkersIndex].position = [lng, lat]
  178. that.markerData = [...markerData]
  179. },
  180. },
  181. polygonEvents: {
  182. click(e) {
  183. // console.log(e.target.getExtData())
  184. console.log(wx)
  185. console.log('abc')
  186. wx.miniProgram.navigateTo({url: '/pagesSchool/class'})
  187. },
  188. },
  189. curMarkersIndex: 0,
  190. plugin: [{
  191. pName: 'MouseTool',
  192. }],
  193. mteStr: 'polygonAdd',
  194. mteObj: {},
  195. }
  196. },
  197. computed: {
  198. centerStr () {
  199. const center = this.mapDiyObj.center
  200. if (center && center.length > 0) {
  201. return `${center[0]}, ${center[1]}`
  202. } else {
  203. return '待选取'
  204. }
  205. }
  206. },
  207. created() {
  208. this.getData()
  209. },
  210. mounted() {},
  211. methods: {
  212. setShowChange () {
  213. this.isMapSetShow = !this.isMapSetShow
  214. },
  215. getDef () {
  216. let params = {}
  217. params = { ...this.mapDiyObj }
  218. params.zoom1 = params.zooms[0]
  219. params.zoom2 = params.zooms[1]
  220. this.formData = [
  221. { label: '地图标题', key: 'title', rules: 1},
  222. { label: '主题样式', key: 'mapStyle', type: 'select', rules: 1,
  223. options: [
  224. {key: '默认样式', val: 'normal'},
  225. {key: '深色样式', val: 'dark'},
  226. {key: '浅色样式', val: 'light'},
  227. {key: '清新风格osm', val: 'fresh'},
  228. ]
  229. },
  230. { label: '显示内容', key: 'features', type: 'select', multiple: true, rules: 1,
  231. options: [
  232. {key: '区域面', val: 'bg'},
  233. {key: '兴趣点', val: 'point'},
  234. {key: '道路和标注', val: 'road'},
  235. {key: '建筑物', val: 'building'},
  236. ]
  237. },
  238. { label: '默认级别', key: 'zoom', rules: 1},
  239. { label: '最小3+', key: 'zoom1', rules: 1},
  240. { label: '最大19-', key: 'zoom2', rules: 1},
  241. ]
  242. this.setDefaultValue(params)
  243. this.setCurFeatures(params.features)
  244. },
  245. setCurFeatures (data) {
  246. window.setTimeout(() => {
  247. const curMap = this.amapManager.getMap()
  248. curMap.setFeatures(data)
  249. }, 500)
  250. },
  251. getData () {
  252. const query = this.$route.query
  253. this.$api.other.admmapcoordindetail({
  254. uuid: query.id
  255. }).then(res => {
  256. if (res.data) {
  257. const data = JSON.parse(res.data)
  258. this.polygons = [...data.polygons]
  259. this.markerData = [...data.markerData]
  260. this.mapDiyObj = {
  261. ...data.mapDiyObj,
  262. title: res.title,
  263. }
  264. } else {
  265. this.mapDiyObj = {
  266. mapStyle: 'light',
  267. zoom: 17,
  268. zooms: [15, 19],
  269. center: [115.852386, 28.684076],
  270. title: res.title,
  271. features: ['road', 'bg', 'building']
  272. }
  273. }
  274. this.getDef()
  275. })
  276. },
  277. setHandle () {
  278. this.$refs['ruleForm'].$refs['baseForm'].validate((valid) => {
  279. if (valid) {
  280. const oldform = this.$refs.ruleForm.baseForm
  281. let newForm = { ...oldform }
  282. let mapDiyObj = { ...this.mapDiyObj }
  283. mapDiyObj.zoom = Number(newForm.zoom)
  284. mapDiyObj.zooms = [Number(newForm.zoom1), Number(newForm.zoom2)]
  285. mapDiyObj.title = newForm.title
  286. mapDiyObj.mapStyle = newForm.mapStyle
  287. mapDiyObj.features = newForm.features
  288. this.mapDiyObj = {...mapDiyObj}
  289. this.setCurFeatures(newForm.features)
  290. this.isMapSetShow = false
  291. }
  292. })
  293. },
  294. setCenterHandle () {
  295. const that = this
  296. const curMap = this.amapManager.getMap()
  297. let mouseTool = new AMap.MouseTool(curMap)
  298. mouseTool.marker({
  299. content: ' ',
  300. })
  301. that.isDbShow = false
  302. that.$msgs('请在地图上选择中心点')
  303. AMap.event.addListener(mouseTool,'draw',function(e){
  304. let cPath = e.obj.getPosition()
  305. let mapDiyObj = {...that.mapDiyObj}
  306. mapDiyObj.center = [cPath.lng, cPath.lat]
  307. that.mapDiyObj = {...mapDiyObj}
  308. that.$msg('中心坐标选取成功~如需重新选中心点,请再次点击中心坐标位置')
  309. that.isDbShow = true
  310. window.setTimeout(() => {
  311. mouseTool.close(true)
  312. }, 100)
  313. })
  314. },
  315. saveHandle () {
  316. this.$msg(`您确定要保存该数据(覆盖原来数据)吗?`, 'confirm', () => {
  317. let polygons = JSON.parse(JSON.stringify(this.polygons))
  318. polygons.map(one=> {
  319. let tPath = []
  320. one.editable = false
  321. one.path.forEach(sub => {
  322. tPath.push([sub.lng, sub.lat])
  323. })
  324. one.path = tPath
  325. })
  326. let markerData = JSON.parse(JSON.stringify(this.markerData))
  327. markerData.map(one => {
  328. one.draggable = false
  329. })
  330. const data = {
  331. polygons,
  332. markerData,
  333. mapDiyObj: this.mapDiyObj,
  334. }
  335. const query = this.$route.query
  336. this.$api.other.admmapcoordinedit({
  337. uuid: query.id,
  338. title: this.mapDiyObj.title,
  339. data: JSON.stringify(data)
  340. }).then(res => {
  341. this.getData()
  342. })
  343. })
  344. },
  345. polygonAdd (obj) {
  346. const that = this
  347. const curMap = this.amapManager.getMap()
  348. let mouseTool = new AMap.MouseTool(curMap)
  349. mouseTool.polygon({
  350. fillColor:'#00b0ff',
  351. strokeColor:'#80d8ff',
  352. editable: true,
  353. strokeStyle: 'dashed',
  354. })
  355. AMap.event.addListener(mouseTool,'draw',function(e) {
  356. let cPath = [...e.obj.getPath()]
  357. let tempPath = []
  358. cPath.forEach(item => {
  359. tempPath.push([item.lng, item.lat])
  360. })
  361. let polygons = [...that.polygons]
  362. polygons.push({
  363. path: tempPath,
  364. editable: true,
  365. fillColor: obj.fillColor || '#DC3021', // 填充色
  366. fillOpacity: obj.fillOpacity || 0.3, // 填充透明度
  367. strokeColor: obj.strokeColor || '#DC3021', // 轮廓颜色
  368. strokeWeight: 2, // 轮廓宽度
  369. strokeOpacity: 0.9, // 轮廓透明度
  370. text: obj.text,
  371. })
  372. that.polygons = [...polygons]
  373. mouseTool.close(true)
  374. that.isDbShow = true
  375. console.log(that.isDbShow)
  376. })
  377. },
  378. mapIsEdit (index, str) {
  379. this.curMarkersIndex = index
  380. let tempData = [...this[str]]
  381. if (str === 'polygons') {
  382. if (tempData[index].editable) {
  383. tempData[index].editable = false
  384. tempData[index].strokeStyle = 'solid'
  385. } else {
  386. tempData[index].editable = true
  387. tempData[index].strokeStyle = 'dashed'
  388. }
  389. } else {
  390. tempData[index].draggable = !tempData[index].draggable
  391. // tempData[index].animation = tempData[index].draggable ? 'AMAP_ANIMATION_BOUNCE' : 'AMAP_ANIMATION_DROP'
  392. }
  393. this[str] = [...tempData]
  394. this.$storage(`map_${str}`, JSON.stringify(tempData))
  395. },
  396. mapDel (index, str) {
  397. this.$msg(`您确定要删除该数据吗?`, 'confirm', () => {
  398. let tempData = [...this[str]]
  399. tempData.splice(index, 1)
  400. this[str] = [...tempData]
  401. this.$storage(`map_${str}`, JSON.stringify(tempData))
  402. })
  403. },
  404. openMte (str, obj) {
  405. this.mteStr = str
  406. this.isMteShow = true
  407. if (obj) {
  408. this.mteObj = {...obj}
  409. }
  410. },
  411. closeMte (obj, bcStr) {
  412. this.isMteShow = false
  413. if (obj) {
  414. if (bcStr && bcStr === 'edit') {
  415. const index = this.mteObj.index || 0
  416. console.log(this.mteObj)
  417. const str = this.mteStr === 'textAdd' ? 'markerData' : 'polygons'
  418. let tempData = [...this[str]]
  419. if (this.mteStr === 'textAdd') {
  420. tempData[index].content = obj.text
  421. tempData[index].text = obj.text
  422. tempData[index].color = obj.color
  423. } else {
  424. tempData[index].text = obj.text
  425. tempData[index].fillColor = obj.fillColor
  426. tempData[index].fillOpacity = obj.fillOpacity
  427. tempData[index].strokeColor = obj.strokeColor
  428. }
  429. this[str] = [...tempData]
  430. this.$storage(`map_${str}`, JSON.stringify(tempData))
  431. } else {
  432. this[this.mteStr](obj)
  433. this.isDbShow = false
  434. this.$msgs('请在地图上操作')
  435. }
  436. }
  437. this.mteObj = {}
  438. },
  439. textAdd (obj) {
  440. const that = this
  441. const curMap = this.amapManager.getMap()
  442. let mouseTool = new AMap.MouseTool(curMap)
  443. mouseTool.marker({
  444. content: ' ',
  445. })
  446. AMap.event.addListener(mouseTool,'draw',function(e){
  447. let cPath = e.obj.getPosition()
  448. let markerData = [...that.markerData]
  449. markerData.push({
  450. position: [cPath.lng, cPath.lat],
  451. draggable: true,
  452. animation: 'AMAP_ANIMATION_DROP',
  453. content: obj.text,
  454. offset: [0, -10],
  455. text: obj.text,
  456. color: obj.color,
  457. })
  458. that.markerData = [...markerData]
  459. window.setTimeout(() => {
  460. mouseTool.close(true)
  461. that.isDbShow = true
  462. }, 100)
  463. })
  464. },
  465. }
  466. }
  467. </script>
  468. <style lang="scss" scoped>
  469. .app-container {
  470. height: 100%;
  471. padding: 0;
  472. margin: 0;
  473. position: relative;
  474. .amap-box {
  475. height: 100%;
  476. }
  477. }
  478. .scoped-deal-box {
  479. background: #f2f2f2;
  480. box-shadow: 0 0 5px #666;
  481. position: absolute;
  482. z-index: 999;
  483. left: 0;
  484. top: 0;
  485. height: 100%;
  486. width: 220px;
  487. overflow-y: auto;
  488. overflow-x: hidden;
  489. &.t2 {
  490. opacity: 0.5;
  491. }
  492. .sdb-info {
  493. background: #fff;
  494. margin-bottom: 10px;
  495. padding: 10px 10px 0;
  496. .p1 {
  497. font-size: 14px;
  498. user-select: none;
  499. padding-bottom: 10px;
  500. .more {
  501. color: #409eff;
  502. text-decoration: underline;
  503. padding-left: 2px;
  504. cursor: pointer;
  505. }
  506. }
  507. .p2 {
  508. padding-bottom: 6px;
  509. }
  510. }
  511. .sdb-add {
  512. padding: 0 10px 10px;
  513. .b {
  514. display: inline-block;
  515. vertical-align: middle;
  516. border-radius: 0;
  517. background: #0c78b1;
  518. color: #fff;
  519. min-width: 60px;
  520. height: 36px;
  521. line-height: 36px;
  522. cursor: pointer;
  523. outline: none;
  524. padding: 0 10px;
  525. margin-right: 10px;
  526. font-size: 14px;
  527. text-align: center;
  528. &:last-child {
  529. margin-right: 0;
  530. }
  531. &.t2 {
  532. background: #409eff;
  533. }
  534. &.t3 {
  535. width: 177px;
  536. }
  537. }
  538. }
  539. .sdb-list {
  540. background: #fff;
  541. margin-bottom: 10px;
  542. padding-top: 10px;
  543. .label {
  544. margin-left: 10px;
  545. border-left: 4px solid #409eff;
  546. padding-left: 6px;
  547. &.t2 {
  548. border-left-color: #0c78b1;
  549. }
  550. }
  551. .ul {
  552. height: 300px;
  553. overflow-y: auto;
  554. }
  555. .op {
  556. border-bottom: 1px solid #dcdcdc;
  557. padding: 10px;
  558. .p1 {
  559. color: #313131;
  560. font-weight: bold;
  561. padding-bottom: 6px;
  562. }
  563. .more {
  564. .d {
  565. display: inline-block;
  566. vertical-align: middle;
  567. margin-right: 10px;
  568. padding: 0 6px;
  569. line-height: 20px;
  570. height: 20px;
  571. border: 1px solid #0c78b1;
  572. color: #0c78b1;
  573. border-radius: 6px;
  574. font-size: 12px;
  575. font-weight: bold;
  576. cursor: pointer;
  577. &.d2 {
  578. color: #409eff;
  579. border-color: #409eff;
  580. }
  581. &.d3 {
  582. color: #313131;
  583. border-color: #313131;
  584. }
  585. &.d4 {
  586. color: #f00;
  587. border-color: #f00;
  588. }
  589. }
  590. }
  591. }
  592. }
  593. }
  594. .scoped-marker-text {
  595. color: #fff;
  596. min-width: 100px;
  597. font-weight: bold;
  598. }
  599. .scoped-select-center {
  600. position: absolute;
  601. left: -75px;
  602. top: 0px;
  603. cursor: pointer;
  604. width: 60px;
  605. line-height: 14px;
  606. color: #313131;
  607. .s {
  608. color: #f00;
  609. font-size: 12px;
  610. }
  611. }
  612. </style>