dtl.vue 18 KB

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