VisualEditor.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715
  1. <template>
  2. <div class="map-container">
  3. <nav>
  4. <map-selector :default-val="formData.mapId" @setMapInfo="handleSelectMap" />
  5. <!-- <div class="page-title">
  6. 现场分布图
  7. </div> -->
  8. <el-button size="mini" type="primary" style="margin-left:15px;" @click="submit">保存</el-button>
  9. </nav>
  10. <div class="layout-map">
  11. <div class="left-side">
  12. <div class="title">作业项目</div>
  13. <div v-for="(item,index) in markerItems" :key="index" :class="checkItemIndex===index?'item active':'item'" @click="checkItem(item,index)">
  14. <img :src="item.icon" alt="" class="icon">
  15. <div class="name">{{ item.name }}</div>
  16. </div>
  17. </div>
  18. <div id="vmap" />
  19. <div class="rightSide">
  20. <div v-if="type==1" class="remark">
  21. <div class="title">使用说明</div>
  22. <ul>
  23. <li>1.点击作业项目下面的图标</li>
  24. <li>2.点击地图绘制点</li>
  25. <li>3.编辑信息保存点位</li>
  26. </ul>
  27. </div>
  28. <div v-if="type==2||type=='drage'" class="saveForm">
  29. <div class="title">新增标记点</div>
  30. <div class="item">
  31. <div class="lable">矿带:</div>
  32. <div class="content">
  33. <el-select v-model="saveForm.goafOrebelt" class="safe-area-item" filterable clearable placeholder="矿带">
  34. <el-option :value="0" label="请选择矿带" disabled />
  35. <el-option v-for="(item,index) in goaf" :key="index" :value="item.goafOrebelt" :label="item.goafOrebelt" />
  36. </el-select>
  37. </div>
  38. </div>
  39. <div class="item">
  40. <div class="lable">矿体:</div>
  41. <div class="content">
  42. <el-select v-model="saveForm.goafOrebody" class="safe-area-item" filterable clearable placeholder="矿体">
  43. <el-option :value="0" label="请选择矿体" disabled />
  44. <el-option v-for="(item,index) in goaf" :key="index" :value="item.goafOrebody" :label="item.goafOrebody" />
  45. </el-select>
  46. </div>
  47. </div>
  48. <div class="item">
  49. <div class="lable">中段:</div>
  50. <div class="content">
  51. <el-select v-model="saveForm.goafOreheight" class="safe-area-item" filterable clearable placeholder="中段">
  52. <el-option :value="0" label="请选择中段" disabled />
  53. <el-option v-for="(item,index) in goaf" :key="index" :value="item.goafOreheight" :label="item.goafOreheight" />
  54. </el-select>
  55. </div>
  56. </div>
  57. <div class="item">
  58. <div class="lable">采空区:</div>
  59. <div class="content">
  60. <el-select v-model="saveForm.goafName" class="safe-area-item" filterable clearable placeholder="采空区名称">
  61. <el-option :value="0" label="请选择采空区" disabled />
  62. <el-option v-for="(item,index) in goaf" :key="index" :value="item.goafName" :label="item.goafName" />
  63. </el-select>
  64. </div>
  65. </div>
  66. <div class="bt-wrap">
  67. <div class="bt save" @click="save">保存</div>
  68. <div class="bt margin" @click="cancel">撤销</div>
  69. </div>
  70. </div>
  71. <div v-if="type==3" class="deleteForm">
  72. <div class="title">删除标记点</div>
  73. <div class="item">
  74. <div class="lable">矿带:</div>
  75. <div class="content"> {{ deleteForm.goafOrebelt }}</div>
  76. </div>
  77. <div class="item">
  78. <div class="lable">矿体:</div>
  79. <div class="content"> {{ deleteForm.goafOrebody }}</div>
  80. </div>
  81. <div class="item">
  82. <div class="lable">中段:</div>
  83. <div class="content"> {{ deleteForm.goafOreheight }}</div>
  84. </div>
  85. <div class="item">
  86. <div class="lable">采空区:</div>
  87. <div class="content"> {{ deleteForm.goafName }}</div>
  88. </div>
  89. <div class="bt-wrap">
  90. <div class="bt" @click="save">保存</div>
  91. <div class="bt delete margin" @click="delMarker">删除</div>
  92. </div>
  93. </div>
  94. </div>
  95. </div>
  96. </div>
  97. </template>
  98. <script>
  99. import * as L from 'leaflet'
  100. import '@geoman-io/leaflet-geoman-free'
  101. import { mapGetters } from 'vuex'
  102. import MapSelector from '@/components/MapSelector'
  103. import { getMapLayerByList } from '@/api/system/mapLayerApi'
  104. import { getGoafBaseInfo } from '@/api/goaf/info'
  105. import { getMapLayerById, createMapLayer, delMapLayer, updateMapLayer } from '@/api/goaf/layer'
  106. const markerIcon = L.icon({
  107. iconUrl: require('@/assets/images/icon/4.png'),
  108. shadowUrl: require('@/assets/images/icon/4hover.png'),
  109. iconSize: [60, 70],
  110. shadowSize: [60, 70],
  111. iconAnchor: [16, 52],
  112. popupAnchor: [1, -38]
  113. })
  114. L.Marker.prototype.options.icon = markerIcon
  115. export default {
  116. name: 'GoafVisualEditor',
  117. components: {
  118. MapSelector
  119. },
  120. data() {
  121. return {
  122. viewData: {},
  123. formData: {
  124. mapId: undefined,
  125. layerId: undefined,
  126. layerVector: ''
  127. },
  128. type: 1,
  129. checkItemIndex: -1,
  130. state: 0,
  131. markerId: undefined,
  132. veditId: undefined,
  133. dragstartMarker: undefined,
  134. markerItems: [
  135. { icon: require('@/assets/images/icon/4.png'), name: '' }
  136. ],
  137. map: undefined,
  138. geoLayer: undefined,
  139. conditions: {
  140. layerId: undefined
  141. },
  142. saveForm: {
  143. 'goaflayerId': '',
  144. 'ocId': '',
  145. 'goafId': '',
  146. 'goafOrebelt': 0,
  147. 'goafOrebody': 0,
  148. 'goafOreheight': 0,
  149. 'goafName': '',
  150. 'mapId': '',
  151. 'layerId': '',
  152. 'layerCatId': '',
  153. 'layerTitle': '',
  154. 'layerMarker': '',
  155. 'layerVector': '',
  156. 'layerVectorType': ''
  157. },
  158. deleteForm: {
  159. 'icon': '',
  160. 'name': '',
  161. 'goaflayerId': '',
  162. 'ocId': '',
  163. 'goafId': '',
  164. 'goafOrebelt': 0,
  165. 'goafOrebody': 0,
  166. 'goafOreheight': 0,
  167. 'goafName': '',
  168. 'mapId': '',
  169. 'layerId': '',
  170. 'layerCatId': '1',
  171. 'layerTitle': '',
  172. 'layerMarker': '',
  173. 'layerVector': '',
  174. 'layerVectorType': ''
  175. },
  176. layer: null,
  177. layers: [],
  178. layerGroup: [],
  179. imageOverlay: undefined,
  180. goaf: []
  181. }
  182. },
  183. computed: {
  184. ...mapGetters([
  185. 'userData'
  186. ])
  187. },
  188. mounted() {
  189. this.init()
  190. },
  191. methods: {
  192. init() {
  193. this.initMap()
  194. getGoafBaseInfo().then((res) => {
  195. this.goaf = res.data
  196. })
  197. },
  198. // 加载数据
  199. load(layerId) {
  200. this.conditions.layerId = layerId
  201. this.getData()
  202. },
  203. // 初始化
  204. getData() {
  205. getMapLayerById(this.conditions.layerId).then((resp) => {
  206. const { code, data, msg } = resp
  207. if (code === 0) {
  208. this.viewData = data
  209. this.setRasterLayer()
  210. } else {
  211. this.$message.error(msg)
  212. }
  213. })
  214. },
  215. // 初始化地图
  216. initMap() {
  217. var yx = L.latLng
  218. var xy = function xy(x, y) {
  219. if (L.Util.isArray(x)) {
  220. return yx(x[1], x[0])
  221. }
  222. return yx(y, x)
  223. }
  224. var bounds = [xy(-600, -600), xy(300, 300)]
  225. this.map = L.map('vmap', {
  226. crs: L.CRS.Simple, // 一个简单的CRS,可将经度和纬度直接映射到x其中y。可用于平面地图(例如游戏地图)
  227. minZoom: 0,
  228. maxZoom: 1,
  229. zoom: 1,
  230. maxBounds: bounds, // 地图拖动到边界后自动弹回
  231. maxBoundsViscosity: 0.2,
  232. attributionControl: false,
  233. zoomControl: true // zoomControl(缩放控制):确定缩放控制是否默认加载在地图上。
  234. })
  235. this.geoLayer = L.geoJson(null, { pmIgnore: false })
  236. this.geoLayer.addTo(this.map)
  237. this.mapListener()
  238. if (!this.viewData.layerVector) return
  239. this.geoLayer.addData(this.viewData.layerVector)
  240. },
  241. // 设置地图背景图
  242. setRasterLayer() {
  243. var yx = L.latLng
  244. var xy = function xy(x, y) {
  245. if (L.Util.isArray(x)) {
  246. return yx(x[1], x[0])
  247. }
  248. return yx(y, x)
  249. }
  250. var bounds = [xy(-600, -600), xy(300, 300)]
  251. if (this.imageOverlay) {
  252. this.imageOverlay.setUrl(this.viewData.mapRasterLayer)
  253. } else {
  254. this.imageOverlay = L.imageOverlay(this.viewData.mapRasterLayer, bounds).addTo(this.map)
  255. }
  256. this.map.fitBounds(bounds)
  257. this.map.scrollWheelZoom.disable()
  258. this.getMapLayers()
  259. },
  260. // 选择地图
  261. handleSelectMap(obj) {
  262. this.viewData.mapRasterLayer = obj.mapRasterLayer
  263. this.viewData.mapId = obj.mapId
  264. this.formData.mapId = obj.mapId
  265. this.setRasterLayer()
  266. },
  267. createMapLayer() {
  268. createMapLayer().then(() => {
  269. })
  270. },
  271. formSuccess() {
  272. this.$emit('formSuccess')
  273. },
  274. mapListener() {
  275. this.map.on('pm:drawstart', (e) => { // 绘制开始时事件
  276. if (e.shape === 'Marker') {
  277. const iconUrl = this.saveForm.icon
  278. const layer = e.workingLayer
  279. var icon = L.icon({
  280. iconUrl,
  281. shadowUrl: iconUrl,
  282. shadowSize: [60, 70],
  283. iconSize: [60, 70]
  284. })
  285. layer.setIcon(icon)
  286. }
  287. })
  288. this.map.on('pm:create', (e) => {
  289. const self = this
  290. if (e.shape === 'Marker') {
  291. const iconUrl = this.saveForm.icon
  292. const name = this.saveForm.name
  293. const typeId = this.checkItemIndex + 1
  294. const layer = e.layer
  295. var icon = L.icon({
  296. iconUrl,
  297. shadowUrl: iconUrl,
  298. name,
  299. typeId,
  300. shadowSize: [60, 70],
  301. iconSize: [60, 70]
  302. })
  303. layer.setIcon(icon)
  304. self.layer = layer
  305. layer.addTo(this.layerGroup)
  306. layer.on('click', (ev) => {
  307. if (self.type === 2) {
  308. layer.dragging.enable()
  309. }
  310. })
  311. layer.on('dragend', function(ev) {
  312. self.layer = ev.target
  313. })
  314. }
  315. this.map.pm.disableDraw(e.shape)
  316. })
  317. },
  318. // 获取地图图层数据
  319. getMapLayers() {
  320. const obj = {}
  321. obj.mapId = this.mapId
  322. getMapLayerByList(obj).then((resp) => {
  323. const { code, data, msg } = resp
  324. if (code === 0) {
  325. this.mapLayerList = data
  326. this.initMapLayers()
  327. } else {
  328. this.$message.error(msg)
  329. }
  330. })
  331. },
  332. // 初始化地图图层
  333. initMapLayers() {
  334. const self = this
  335. const layerList = this.mapLayerList
  336. const feature = []
  337. this.layerGroup = L.layerGroup().addTo(this.map)
  338. if (layerList != null && layerList.length > 0) {
  339. layerList.forEach((item) => {
  340. item.layerMarker && feature.push(JSON.parse(item.layerMarker))
  341. item.layerVector && feature.push(JSON.parse(item.layerVector))
  342. })
  343. L.geoJSON(feature, {
  344. // pointToLayer: function(_feature, latlng) {
  345. // // var smallIcon = L.Icon({
  346. // // options: {
  347. // // iconSize: [27, 27],
  348. // // iconAnchor: [13, 27],
  349. // // popupAnchor: [1, -24],
  350. // // iconUrl: 'icone/chapel-2.png'
  351. // // }
  352. // // })
  353. // // return L.marker(latlng, { icon: smallIcon })
  354. // },
  355. onEachFeature: (_feature, layer) => {
  356. this.layerGroup.addLayer(layer)
  357. layer.on('click', (ev) => {
  358. if (self.type === 2 || self.type === 'drage') {
  359. self.$message.success('请先确认当前标记点操作!')
  360. return
  361. }
  362. self.type = 3
  363. self.layer = ev.target
  364. layer.dragging.enable()
  365. })
  366. layer.on('dragstart', function(ev) {
  367. if (self.dragstartMarker === undefined) {
  368. self.dragstartMarker = { layer, latlng: ev.target._latlng }
  369. }
  370. })
  371. layer.on('dragend', function(ev) {
  372. self.type = 'drage'
  373. self.layer = ev.target
  374. })
  375. }
  376. }).addTo(this.layerGroup)
  377. }
  378. },
  379. clearLayers() {
  380. this.layerGroup.clearLayers()
  381. },
  382. submit() {
  383. // 图层操作完,一次导出geoJSON
  384. const layers = this.map._layers
  385. console.log({
  386. layers,
  387. geoLayer: this.geoLayer,
  388. geoJson: this.createGeoJson()
  389. })
  390. },
  391. checkItem(item, index) {
  392. if (this.state === 1) {
  393. this.$message('请保存后再操作!')
  394. return
  395. }
  396. this.checkItemIndex = index
  397. this.type = 2
  398. this.state = 1
  399. this.saveForm.icon = item.icon
  400. this.saveForm.name = item.name
  401. this.map.pm.enableDraw('Marker', { snappable: false, tooltips: false })// tooltips: { 'placeMarker': '点击放置标记' },
  402. },
  403. save() {
  404. if (this.type === 3) {
  405. // 删除表单里面的保存
  406. this.type = 1
  407. } else if (this.type === 'drage') {
  408. updateMapLayer({
  409. // 'goaflayerId': '',
  410. 'ocId': this.userData.ocId,
  411. // 'goafId': '',
  412. 'goafOrebelt': this.saveForm.goafOrebelt,
  413. 'goafOrebody': this.saveForm.goafOrebody,
  414. 'goafOreheight': this.saveForm.goafOreheight,
  415. 'goafName': this.saveForm.goafName,
  416. 'mapId': this.formData.mapId,
  417. 'layerId': '',
  418. 'layerCatId': '',
  419. 'layerTitle': '',
  420. 'layerMarker': this.layer?.toGeoJSON(),
  421. 'layerVector': '',
  422. 'layerVectorType': ''
  423. }).then(() => {
  424. this.type = 1
  425. this.checkItemIndex = -1
  426. this.state = 2
  427. this.resetForm()
  428. this.$message.success('修改成功!')
  429. this.dragstartMarker = undefined
  430. // this.getLayers()
  431. })
  432. } else {
  433. // 新增
  434. createMapLayer({
  435. // 'goaflayerId': '',
  436. 'ocId': this.userData.ocId,
  437. // 'goafId': '',
  438. 'goafOrebelt': this.saveForm.goafOrebelt,
  439. 'goafOrebody': this.saveForm.goafOrebody,
  440. 'goafOreheight': this.saveForm.goafOreheight,
  441. 'goafName': this.saveForm.goafName,
  442. 'mapId': this.formData.mapId,
  443. 'layerId': '',
  444. 'layerCatId': '',
  445. 'layerTitle': '',
  446. 'layerMarker': this.layer?.toGeoJSON(),
  447. 'layerVector': '',
  448. 'layerVectorType': ''
  449. }).then(() => {
  450. this.type = 1
  451. this.checkItemIndex = -1
  452. this.state = 2
  453. this.resetForm()
  454. this.$message.success('新增成功!')
  455. // this.getLayers()
  456. })
  457. }
  458. },
  459. cancel() {
  460. this.state = 2
  461. this.checkItemIndex = -1
  462. this.resetForm()
  463. if (this.type === 'drage') {
  464. this.type = 1
  465. this.dragstartMarker.layer.setLatLng(this.dragstartMarker.latlng)
  466. this.dragstartMarker.layer.dragging.disable()
  467. this.dragstartMarker = undefined
  468. return
  469. }
  470. if (this.layer && this.layer._leaflet_id && this.map._layers[this.layer._leaflet_id]) {
  471. this.map.removeLayer(this.map._layers[this.layer._leaflet_id])
  472. this.layer = undefined
  473. this.type = 1
  474. }
  475. },
  476. delMarker() {
  477. delMapLayer(this.veditId).then(() => {
  478. this.type = 1
  479. this.state = 2
  480. this.checkItemIndex = -1
  481. this.resetForm()
  482. this.$message.success('删除成功!')
  483. // this.getLayers()
  484. })
  485. },
  486. resetForm() {
  487. const data = {
  488. 'icon': '',
  489. 'name': '',
  490. 'goaflayerId': '',
  491. 'ocId': '',
  492. 'goafId': '',
  493. 'goafName': '',
  494. 'mapId': '',
  495. 'layerId': '',
  496. 'layerCatId': '',
  497. 'layerTitle': '',
  498. 'layerMarker': '',
  499. 'layerVector': '',
  500. 'layerVectorType': ''
  501. }
  502. this.saveForm = JSON.parse(JSON.stringify(data))
  503. this.deleteForm = JSON.parse(JSON.stringify(data))
  504. },
  505. drawLayer(params, map = this.map) {
  506. var layer = null
  507. const _latlng = params.geometry.coordinates.latlng
  508. const latlng = Array.isArray(_latlng) ? _latlng(item => [item.lat, item.lng]) : [_latlng.lat, _latlng.lng]
  509. switch (params.type) {
  510. case 'Marker' :
  511. layer = L.marker([latlng]).addTo(map)
  512. break
  513. case 'Line' :
  514. layer = L.polyline([latlng]).addTo(map)
  515. break
  516. case 'Circle' :
  517. layer = L.circle([latlng], {
  518. color: 'red',
  519. fillColor: '#f03',
  520. fillOpacity: 0.5,
  521. radius: params.properties.radius
  522. }).addTo(map)
  523. break
  524. case 'Rectangle' :
  525. layer = L.rectangle(latlng).addTo(map)
  526. break
  527. case 'Polygon' :
  528. layer = L.polygon(latlng).addTo(map)
  529. break
  530. }
  531. return layer
  532. },
  533. createGeoJson() {
  534. var layerArray = []
  535. this.map.eachLayer(function(layer) {
  536. if (layer.pm !== 'undefined' && layer.pm != null && layer.pm !== '') {
  537. if (layer.pm._enabled === false && layer.pm.options.draggable === true) {
  538. layerArray.push(layer)
  539. }
  540. }
  541. })
  542. var geojson = L.layerGroup(layerArray).toGeoJSON()
  543. for (var n = 0; n < geojson.features.length; n++) {
  544. var nowJson = JSON.stringify(geojson.features[n])
  545. for (var m = n + 1; m < geojson.features.length; m++) {
  546. var nextJson = JSON.stringify(geojson.features[m])
  547. if (nowJson === nextJson) {
  548. geojson.features.splice(n, 1)
  549. }
  550. }
  551. }
  552. return geojson
  553. }
  554. }
  555. }
  556. </script>
  557. <style lang="scss" scoped>
  558. .map-container{
  559. padding: 15px;
  560. nav{
  561. height: 60px;
  562. display: flex;
  563. justify-content: space-between;
  564. align-items: center;
  565. padding: 10px 16px;
  566. box-sizing: border-box;
  567. background-color: #193142;
  568. .page-title {
  569. font-size: 18px;
  570. font-weight: bold;
  571. color: #FFFFFF;
  572. font-weight: bold;
  573. }
  574. }
  575. .layout-map{
  576. display: flex;
  577. justify-content: space-between;
  578. height: calc(100vh - 160px);
  579. margin-top: 10px;
  580. .left-side{
  581. min-width: 266px;
  582. height: 100%;
  583. overflow-y: auto;
  584. background-color: #193142;
  585. box-sizing: border-box;
  586. .title{
  587. height: 42px;
  588. line-height: 42px;
  589. background-color: #36556b;
  590. font-size: 16px;
  591. color: #666;
  592. text-indent: 10px;
  593. color: #fff;
  594. }
  595. .item{
  596. display: flex;
  597. align-items: center;
  598. height: 48px;
  599. padding-left: 10px;
  600. cursor: default;
  601. &.active{
  602. background-color: rgba(45, 140, 240, 0.16);
  603. }
  604. .icon{
  605. width: 30px;
  606. display: block;
  607. }
  608. .name{
  609. font-size: 14px;
  610. padding-left: 12px;
  611. color: #fff;
  612. }
  613. }
  614. }
  615. #vmap {
  616. height: 100%;
  617. flex: 1;
  618. background: #8c939d;
  619. box-sizing: border-box;
  620. }
  621. .rightSide{
  622. width: 269px;
  623. height: 100%;
  624. overflow-y: auto;
  625. background-color: #193142;
  626. box-sizing: border-box;
  627. padding: 17px 16px;
  628. color: #fff;
  629. .title{
  630. color: #fff;
  631. font-size: 16px;
  632. margin-bottom: 16px;
  633. }
  634. .remark{
  635. ul,li{
  636. list-style: none;
  637. margin: 0;
  638. padding: 0;
  639. }
  640. li{
  641. color: rgba(255, 255, 255, 0.7);
  642. line-height: 28px;
  643. font-size: 14px;
  644. margin-bottom: 8px;
  645. }
  646. }
  647. .saveForm,.deleteForm{
  648. .item{
  649. height: 48px;
  650. display: flex;
  651. justify-content: flex-start;
  652. align-items: center;
  653. font-size: 14px;
  654. border-bottom:2px solid rgba(45, 140, 240, 0.16);
  655. .lable{
  656. width: 80px;
  657. font-size: 14px;
  658. }
  659. .content{
  660. display: flex;
  661. justify-content: flex-start;
  662. align-items: center;
  663. overflow: hidden;
  664. text-overflow: ellipsis;
  665. .icon{
  666. width: 17.5px;
  667. display: block;
  668. margin-right:8px;
  669. }
  670. }
  671. }
  672. }
  673. .bt-wrap{
  674. margin-top: 65px;
  675. .bt{
  676. width: 100px;
  677. height: 36px;
  678. color: #fff;
  679. font-size: 14px;
  680. line-height: 36px;
  681. text-align: center;
  682. background-color: rgba(24, 144, 255, 0.3);
  683. display: inline-block;
  684. cursor: pointer;
  685. user-select: none;
  686. -moz-user-select: none;
  687. -webkit-user-select: none;
  688. -ms-user-select: none;
  689. &.save{
  690. background-color: #1890ff;
  691. }
  692. &.delete{
  693. background-color: #f97647;
  694. }
  695. &.margin{
  696. margin-left: 12px;
  697. }
  698. }
  699. }
  700. }
  701. }
  702. }
  703. </style>