index.vue 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522
  1. <template>
  2. <div class="menu-content">
  3. <div class="gradient-text common-dialog-title2">实时标绘</div>
  4. <div v-show="collaboration" style="display: flex; align-items: center; justify-content: flex-end">
  5. <div class="btn2" style="margin-left: 10px" @click="handleCloseCollaboration">关闭协同</div>
  6. <div class="btn2" style="margin-left: 10px">保存</div>
  7. </div>
  8. <div class="line">
  9. <div class="tabs1">
  10. <div v-for="(item, index) in menu" :key="index" :class="menuActive1 === index ? 'tab tab_active' : 'tab'" @click="clickTab(index)">
  11. {{ item.name }}
  12. </div>
  13. </div>
  14. <div class="btn-box">
  15. <div class="btn1" @click="handleScreenshot">
  16. <div class="icon1" />
  17. 当前地图截图导出
  18. </div>
  19. <div v-show="!collaboration" class="btn2" @click="handleShare('1')">协同标绘</div>
  20. <div v-show="collaboration" class="btn2" @click="handleShowLayer">查看图层</div>
  21. </div>
  22. </div>
  23. <div v-if="menuActive1 === 0" class="content">
  24. <div class="box1">
  25. <div v-show="!showSetting" class="box-item">
  26. <div class="btn" @click="handleUndo">
  27. <div class="revoke-icon"></div>
  28. 撤回
  29. </div>
  30. <div class="line2"></div>
  31. <div class="btn">
  32. <div class="delete-icon"></div>
  33. 删除
  34. </div>
  35. <div class="line2"></div>
  36. <div class="btn" @click="handleShowDialog">
  37. <div class="save-icon"></div>
  38. 保存
  39. </div>
  40. </div>
  41. <div v-show="showSetting" class="box-item">
  42. <div class="btn" @click="handleQuitSetting">
  43. <div class="revoke-icon"></div>
  44. 退出设置
  45. </div>
  46. </div>
  47. <div class="box-item">
  48. <div class="btn">
  49. <i class="template-icon" />
  50. 模板导入
  51. </div>
  52. <div class="line2"></div>
  53. <div class="btn">
  54. <i class="categoryImport-icon" />
  55. 分类导入
  56. </div>
  57. <div class="line2"></div>
  58. <div class="btn" @click="handleOpenSetting">
  59. <i class="setting-icon" />
  60. 设置
  61. </div>
  62. </div>
  63. </div>
  64. <div class="tab-content">
  65. <div class="tabs2">
  66. <div
  67. v-for="(item, index) in menu[menuActive1].children"
  68. :key="index"
  69. :class="menuActive2 === index ? 'tab tab_active' : 'tab'"
  70. @click="clickTab2(index)"
  71. >
  72. {{ item.name }}
  73. </div>
  74. </div>
  75. <div class="tab-content2">
  76. <div v-show="menuActive2 === 0" class="line3">
  77. <LineWidthSelect v-model="mouseToolState.lineWidth" :options="lineWidthOptions" />
  78. <div class="color-container">
  79. <el-color-picker v-model="mouseToolState.color" size="small" popper-class="custom-color-picker" show-alpha />
  80. </div>
  81. </div>
  82. <div v-if="menu[menuActive1] && menu[menuActive1].children && menu[menuActive1].children[menuActive2]" class="tab-list">
  83. <div
  84. v-for="(item, index) in menu[menuActive1].children[menuActive2].children"
  85. :key="index"
  86. :class="menuActive3 === index ? 'tab tab_active' : 'tab'"
  87. @click="clickTab3(item, index)"
  88. >
  89. <div v-show="!showSetting" :class="menuActive3 === index ? 'checked2' : 'checked1'"></div>
  90. <img :src="getImageUrl(item.image)" class="icon" />
  91. {{ item.name }}
  92. <div v-if="!!showSetting" class="setting-btn" @click="handleShowSetting(item)" />
  93. <div v-if="item.showSetting" class="setting-menu">
  94. <div class="menu-item" @click="handleShowSwitch(item)">
  95. <i class="icon-switch" />
  96. <span>更换</span>
  97. </div>
  98. <div class="menu-item" @click="handleMenuItemHide(item)">
  99. <i class="icon-eye" />
  100. <span>{{ item.visible === '0' ? '隐藏' : '显示' }}</span>
  101. </div>
  102. <div class="menu-item" @click="handleMenuItemDelete(item)">
  103. <i class="icon-delete" />
  104. <span>删除</span>
  105. </div>
  106. </div>
  107. </div>
  108. <div v-if="showSetting" class="tab" @click="handleShowAddClass">
  109. <el-icon color="#7495b4" :size="35"><Plus /></el-icon>
  110. </div>
  111. </div>
  112. </div>
  113. </div>
  114. </div>
  115. <div v-else-if="menuActive1 === 1" class="tab-content3">
  116. <!-- <div class="box1">-->
  117. <!-- <div class="box-item">-->
  118. <!-- <div class="btn">-->
  119. <!-- <div class="merge-icon"></div>-->
  120. <!-- 合并-->
  121. <!-- </div>-->
  122. <!-- </div>-->
  123. <!-- </div>-->
  124. <div class="params-box">
  125. <el-input v-model="queryParams.pattern_name" class="custom-input" placeholder="请输入" @input="handleQuery">
  126. <template #prefix>
  127. <el-icon class="el-input__icon"><search /></el-icon>
  128. </template>
  129. </el-input>
  130. </div>
  131. <div class="custom-table">
  132. <div class="table-header">
  133. <div class="th">预案名称</div>
  134. <div class="th">操作</div>
  135. </div>
  136. <div v-for="(item, index) in patternList" :key="index" class="tr">
  137. <div class="td">
  138. <div>{{ item.pattern_name }}</div>
  139. </div>
  140. <div class="td td2">
  141. <div class="btn" @click="handleDelete(item.id)">
  142. <div class="delete-icon"></div>
  143. 删除
  144. </div>
  145. <div class="line2"></div>
  146. <div class="btn" @click="handleEdit(item.id)">
  147. <div class="edit-icon"></div>
  148. 编辑
  149. </div>
  150. <div class="line2"></div>
  151. <div class="btn" @click="handleShare('2', item.id)">
  152. <div class="share-icon"></div>
  153. 分享
  154. </div>
  155. </div>
  156. </div>
  157. <div class="footer">
  158. <el-pagination
  159. v-model:current-page="queryParams.page"
  160. v-model:page-size="queryParams.pageSize"
  161. background
  162. :hide-on-single-page="true"
  163. layout="total, prev, pager, next"
  164. :total="total"
  165. @current-change="getList"
  166. />
  167. </div>
  168. </div>
  169. </div>
  170. </div>
  171. <!--添加修改分类弹窗-->
  172. <EditClassDialog v-if="showAddDialog" v-model="showAddDialog" :id="selectEditId" :templateId="selectTemplateId" @updateData="getTemplateTreeData" />
  173. <!--添加文字-->
  174. <TextEdit v-if="showTextEdit" v-model="showTextEdit" @add-text="addText" />
  175. <!--绘制提示信息-->
  176. <div v-show="tipTitle !== ''" class="tipTitle">{{ tipTitle }}</div>
  177. <!--保存修改弹窗-->
  178. <EditDialog v-if="showEdit" v-model="showEdit" :edit-data="editData" @submit="handleSubmit" />
  179. <Contact v-if="shareState.showShare" v-model="shareState.showShare" @close="handleCloseShare" @confirm="handleShareConfirm" />
  180. <Dialog v-if="showForm" v-model="showForm" customShow title="协同标绘" type="xs" @close="showForm = false" @confirm="handleSendForm">
  181. <div style="display: flex; align-items: center">
  182. <div style="font-size: 16px">预案名称:</div>
  183. <el-input v-model="form.pattern_name" class="custom-input" placeholder="请输入" style="flex: 1" />
  184. </div>
  185. </Dialog>
  186. <LayerDetail v-if="showLayer" v-model="showLayer" :patternId="patternId" />
  187. </template>
  188. <script lang="ts" setup name="OnlinePlotting">
  189. import { nanoid } from 'nanoid';
  190. import { deepClone } from '@/utils';
  191. import { useHistory } from '@/hooks/useHistory';
  192. import {
  193. changeVisibleClassification,
  194. closeCollaboration,
  195. createCollaboration,
  196. deleteClassificationCreate,
  197. deletePatternById,
  198. getPatternInfo,
  199. getPatternList,
  200. getTemplateTree
  201. } from '@/api/globalMap/onlinePlotting';
  202. import EditClassDialog from './EditClassDialog.vue';
  203. import TextEdit from './TextEdit.vue';
  204. import EditDialog from './EditDialog.vue';
  205. import { Search } from '@element-plus/icons-vue';
  206. import html2canvas from 'html2canvas';
  207. import LayerDetail from './LayerDetail.vue';
  208. import { createWebSocket } from '@/utils/websocket';
  209. import * as turf from '@turf/turf';
  210. import Style from 'ol/style/Style';
  211. import Icon from 'ol/style/Icon';
  212. import { Fill, Stroke } from 'ol/style';
  213. import Text from 'ol/style/Text';
  214. const props = defineProps({
  215. activeMap: String
  216. });
  217. const AMapType = ['vectorgraph', 'satellite'];
  218. const { proxy } = getCurrentInstance() as ComponentInternalInstance;
  219. const getDrawTool = inject('getDrawTool');
  220. const getMap = inject('getMap');
  221. const getMapUtils = inject('getMapUtils');
  222. const containerScale = inject('containerScale');
  223. const { currentState, commit, undo, history, future } = useHistory();
  224. const emits = defineEmits(['getCollaborationData']);
  225. const getImageUrl = (name: string) => {
  226. return import.meta.env.VITE_APP_BASE_API + import.meta.env.VITE_APP_BASE_DOWNLOAD_API + name;
  227. };
  228. let drawing = ref(false);
  229. const mouseToolState = ref({
  230. color: 'rgba(248, 1, 2, 1)',
  231. lineWidth: '1',
  232. graphicsType: ''
  233. });
  234. const menuActive1 = ref<string | number>(0);
  235. const menuActive2 = ref<string | number>(0);
  236. const menuActive3 = ref<string | number>('');
  237. const menu = ref([
  238. {
  239. name: '标绘工具',
  240. children: []
  241. },
  242. {
  243. name: '历史预案',
  244. children: []
  245. }
  246. ]);
  247. const lineWidthOptions = reactive([
  248. { name: '1像素', value: '1' },
  249. { name: '2像素', value: '2' },
  250. { name: '3像素', value: '3' }
  251. ]);
  252. let showTextEdit = ref(false);
  253. let lnglat = ref([]);
  254. // 协同
  255. let collaboration = ref(false);
  256. let webSock;
  257. // 分享
  258. let shareState = reactive({
  259. type: '',
  260. showShare: false,
  261. id: ''
  262. });
  263. let patternId = ref('');
  264. let shareId = ref('');
  265. let overlays = [];
  266. let overlaysData = [];
  267. watch(
  268. () => drawing,
  269. () => {
  270. if (!drawing.value) {
  271. menuActive3.value = '';
  272. }
  273. }
  274. );
  275. const tipTitle = computed(() => {
  276. let res = '';
  277. if (
  278. menu.value[menuActive1.value] &&
  279. menu.value[menuActive1.value].children &&
  280. menu.value[menuActive1.value].children[menuActive2.value] &&
  281. menu.value[menuActive1.value].children[menuActive2.value].children &&
  282. menu.value[menuActive1.value].children[menuActive2.value].children[menuActive3.value]
  283. ) {
  284. const data = menu.value[menuActive1.value].children[menuActive2.value].children[menuActive3.value];
  285. if (data.value === 'straightArrow') {
  286. res = '单击开始、单击结束';
  287. } else if (['rectangle', 'polygon', 'anyLine', 'circle'].includes(data.value)) {
  288. res = '鼠标按住拖曳,松开鼠标结束标绘';
  289. } else if (['straightLine', 'measureArea'].includes(data.value)) {
  290. res = '单击开始,移动,单击改变方向,双击结束';
  291. }
  292. }
  293. return res;
  294. });
  295. // 获取模板分类树
  296. const getTemplateTreeData = () => {
  297. getTemplateTree({ visible: showSetting.value ? '' : '1'}).then((res) => {
  298. menu.value[0].children = res.data;
  299. });
  300. };
  301. let showAddDialog = ref(false);
  302. let selectTemplateId = ref('');
  303. let selectEditId = ref('');
  304. // 显示现在分类弹窗
  305. const handleShowAddClass = () => {
  306. selectTemplateId.value = menu.value[menuActive1.value].children[menuActive2.value].template_id;
  307. selectEditId.value = '';
  308. showAddDialog.value = true;
  309. };
  310. const handleShowSwitch = (item) => {
  311. selectTemplateId.value = menu.value[menuActive1.value].children[menuActive2.value].template_id;
  312. item.showSetting = false;
  313. selectEditId.value = item.classification_id;
  314. showAddDialog.value = true;
  315. };
  316. const handleMenuItemHide = (item) => {
  317. item.showSetting = false;
  318. const newVisible = item.visible === '0' ? '1' : '0';
  319. changeVisibleClassification({ classification_id: item.classification_id, visible: newVisible }).then(() => {
  320. proxy.$modal.msgSuccess(newVisible === '0' ? '隐藏成功' : '显示成功');
  321. getTemplateTreeData();
  322. });
  323. };
  324. const handleMenuItemDelete = (item) => {
  325. item.showSetting = false;
  326. deleteClassificationCreate(item.classification_id).then(() => {
  327. proxy.$modal.msgSuccess('删除成功');
  328. getTemplateTreeData();
  329. });
  330. };
  331. // 点击一级菜单
  332. const clickTab = (value: number) => {
  333. menuActive1.value = value;
  334. };
  335. // 点击二级菜单
  336. const clickTab2 = (value: number) => {
  337. handleExitMenuActive();
  338. menuActive2.value = value;
  339. };
  340. // 点击三级菜单
  341. const clickTab3 = (item, index) => {
  342. if (showSetting.value) return;
  343. handleExitMenuActive(true);
  344. const type = item.value;
  345. if (mouseToolState.value.graphicsType !== type || (mouseToolState.value.graphicsType === 'marker' && mouseToolState.value.title !== item.name)) {
  346. if (type === 'text') {
  347. mouseToolState.value.graphicsType = type;
  348. mouseToolState.value.title = item.name;
  349. handleTextEdit();
  350. } else if (type === 'marker') {
  351. const data = {
  352. graphicsType: type,
  353. lineWidth: mouseToolState.value.lineWidth,
  354. color: mouseToolState.value.color,
  355. icon: getImageUrl(item.image),
  356. iconName: item.image,
  357. size: item.size,
  358. title: item.name
  359. };
  360. drawing.value = true;
  361. mouseToolState.value = data;
  362. } else {
  363. showTextEdit.value = false;
  364. drawing.value = true;
  365. mouseToolState.value.graphicsType = type;
  366. mouseToolState.value.title = item.name;
  367. }
  368. const drawTool = getDrawTool();
  369. if (mouseToolState.value.graphicsType === 'anyLine') {
  370. drawTool.setDrawEndMethod(handleEndDraw);
  371. } else if (mouseToolState.value.graphicsType !== 'text') {
  372. const newOptions = drawTool.drawGraphics(mouseToolState.value);
  373. // 绘制完成事件
  374. initDrawMethod(newOptions);
  375. }
  376. menuActive3.value = index;
  377. } else {
  378. handleExitMenuActive();
  379. }
  380. };
  381. // 切换菜单、设置后退出菜单选中
  382. const handleExitMenuActive = (noClearActive?: boolean) => {
  383. if (!noClearActive) {
  384. menuActive3.value = '';
  385. }
  386. showTextEdit.value = false;
  387. drawing.value = false;
  388. mouseToolState.value.graphicsType = '';
  389. const drawTool = getDrawTool();
  390. drawTool.closeDraw();
  391. };
  392. const handleTextEdit = () => {
  393. const drawTool = getDrawTool();
  394. const map = drawTool.getMap();
  395. drawTool.closeDraw();
  396. // 监听地图点击事件
  397. map.on('click', handleClickMap);
  398. };
  399. const handleClickMap = (e) => {
  400. // 获取点击位置的经纬度
  401. if (AMapType.includes(props.activeMap)) {
  402. lnglat.value = [e.lnglat.lng, e.lnglat.lat];
  403. } else {
  404. lnglat.value = e.coordinate;
  405. }
  406. showTextEdit.value = true;
  407. };
  408. const addText = (textEditState) => {
  409. const data = {
  410. graphicsType: 'text',
  411. type: 'text',
  412. lineWidth: mouseToolState.value.lineWidth,
  413. color: mouseToolState.value.color,
  414. title: '文本',
  415. text: textEditState.text,
  416. fontColor: textEditState.fontColor,
  417. fontSize: textEditState.fontSize,
  418. lnglat: lnglat.value
  419. };
  420. showTextEdit.value = false;
  421. drawing.value = true;
  422. mouseToolState.value = data;
  423. // 绘制完成事件
  424. const drawTool = getDrawTool();
  425. const res = drawTool.drawGraphics(mouseToolState.value);
  426. overlays.push(res.text);
  427. overlaysData.push(res.data);
  428. commit(deepClone(overlaysData));
  429. res.text.on('rightclick', handleRightClick);
  430. const map = drawTool.getMap();
  431. // 监听地图点击事件
  432. if (AMapType.includes(props.activeMap)) {
  433. map.off('click', handleClickMap);
  434. } else {
  435. map.un('click', handleClickMap);
  436. }
  437. sendWebSocket(data);
  438. close();
  439. };
  440. const close = () => {
  441. const drawTool = getDrawTool();
  442. drawTool.closeDraw();
  443. drawing.value = false;
  444. menuActive3.value = '';
  445. mouseToolState.value.graphicsType = '';
  446. };
  447. watch(
  448. mouseToolState,
  449. () => {
  450. if (mouseToolState.value.graphicsType !== 'text') {
  451. const map = getMap();
  452. if (AMapType.includes(props.activeMap)) {
  453. map.off('click', handleClickMap);
  454. } else {
  455. map.un('click', handleClickMap);
  456. }
  457. }
  458. },
  459. {
  460. deep: true
  461. }
  462. );
  463. // 初始化绘制完成回调
  464. const initDrawMethod = (options) => {
  465. const drawTool = getDrawTool();
  466. const mouseTool = drawTool.getMouseTool();
  467. let onDraw;
  468. if (AMapType.includes(props.activeMap)) {
  469. onDraw = (event) => {
  470. mouseTool.off('draw', onDraw);
  471. close();
  472. const obj = event.obj;
  473. const id = nanoid();
  474. obj._opts.extData = {
  475. id: id
  476. };
  477. const data: any = deepClone(options);
  478. data.id = id;
  479. if (options.type == 'marker') {
  480. const position = obj.getPosition();
  481. data.lnglat = [position.lng, position.lat];
  482. data.latitude = position.lat;
  483. data.longitude = position.lng;
  484. data.icon = data.iconName;
  485. data.image = data.iconName;
  486. data.imageHover = data.iconName;
  487. data.visible = true;
  488. obj.setLabel({
  489. content: '<div>' + data.title + '</div>',
  490. direction: 'top'
  491. });
  492. } else {
  493. if (options.type == 'circle') {
  494. data.center = [obj.getCenter().lng, obj.getCenter().lat];
  495. data.radius = obj.getRadius();
  496. } else {
  497. const path = obj.getPath();
  498. // 将AMap.LngLat对象数组转换为经纬度数组
  499. const pathArr = path.map((lngLat) => {
  500. // 返回经度和纬度的数组
  501. return [lngLat.lng, lngLat.lat];
  502. });
  503. if (options.type !== 'straightLine') {
  504. pathArr.push(pathArr[0]);
  505. }
  506. data.path = pathArr;
  507. }
  508. }
  509. if (options.type == 'measureArea') {
  510. const AMap = getDrawTool().getAMap();
  511. const map = getMap();
  512. // 计算区域面积
  513. const area = Math.round(AMap.GeometryUtil.ringArea(data.path));
  514. const text = new AMap.Text({
  515. position: data.path[data.path.length - 1],
  516. text: '区域面积' + area + '平方米',
  517. offset: new AMap.Pixel(-20, -20)
  518. });
  519. data.area = area;
  520. map.add(text);
  521. overlays.push([obj, text]);
  522. overlaysData.push(data);
  523. commit(deepClone(overlaysData));
  524. } else {
  525. overlays.push(obj);
  526. overlaysData.push(data);
  527. commit(deepClone(overlaysData));
  528. console.log(overlaysData);
  529. }
  530. // 右击进入编辑
  531. obj.on('rightclick', handleRightClick);
  532. // 发送
  533. sendWebSocket(data);
  534. };
  535. mouseTool.on('draw', onDraw);
  536. } else {
  537. onDraw = (event) => {
  538. mouseTool.un('draw', onDraw);
  539. close();
  540. const feature = event.feature;
  541. const geometry = feature.getGeometry();
  542. const id = nanoid();
  543. feature.set('id', id);
  544. const data: any = deepClone(options);
  545. data.id = id;
  546. if (options.type == 'marker') {
  547. const img = new Image();
  548. img.onload = () => {
  549. // 图片加载完成后,可以访问其 width 和 height 属性
  550. const width = img.width;
  551. const height = img.height;
  552. const style = new Style({
  553. image: new Icon({
  554. src: options.icon,
  555. anchor: [0.5, 0.5], // 图标锚点,通常是图标的中心点
  556. anchorXUnits: 'fraction',
  557. anchorYUnits: 'fraction',
  558. size: [width, height],
  559. scale: !!options.size[0] ? options.size[0] / width : 1
  560. }),
  561. // text: new Text({
  562. // text: data.title, // 使用属性中的值作为文本
  563. // font: '14px sans-serif',
  564. // fill: new Fill({
  565. // color: '#ffff'
  566. // })
  567. // })
  568. });
  569. feature.setStyle(style);
  570. const position = geometry.getCoordinates();
  571. data.lnglat = position;
  572. data.latitude = position[0];
  573. data.longitude = position[1];
  574. data.icon = data.iconName;
  575. data.image = data.iconName;
  576. data.imageHover = data.iconName;
  577. data.visible = true;
  578. };
  579. img.src = options.icon; // 设置图片的 URL,触发加载
  580. } else {
  581. if (options.type == 'circle') {
  582. data.center = [geometry.getCenter().lng, geometry.getCenter().lat];
  583. data.radius = geometry.getRadius();
  584. } else {
  585. const coordinates = geometry.getCoordinates();
  586. const pathArr = coordinates[0];
  587. data.path = pathArr;
  588. }
  589. }
  590. if (options.type == 'measureArea') {
  591. // 计算区域面积
  592. const area = turf.area(turf.polygon([data.path]));
  593. // const text = new AMap.Text({
  594. // position: data.path[data.path.length - 1],
  595. // text: '区域面积' + area + '平方米',
  596. // offset: new AMap.Pixel(-20, -20)
  597. // });
  598. data.area = area;
  599. // map.add(text);
  600. // overlays.push([feature, text]);
  601. overlays.push(feature);
  602. overlaysData.push(data);
  603. commit(deepClone(overlaysData));
  604. } else {
  605. overlays.push(feature);
  606. overlaysData.push(data);
  607. commit(deepClone(overlaysData));
  608. console.log(overlaysData);
  609. }
  610. // 右击进入编辑
  611. feature.on('rightclick', handleRightClick);
  612. // 发送
  613. sendWebSocket(data);
  614. };
  615. mouseTool.on('drawend', onDraw);
  616. }
  617. };
  618. const handleEndDraw = (options, obj) => {
  619. const drawTool = getDrawTool();
  620. drawing.value = false;
  621. menuActive3.value = '';
  622. mouseToolState.value.graphicsType = '';
  623. drawTool.setDrawEndMethod();
  624. const id = nanoid();
  625. obj._opts.extData = {
  626. id: id
  627. };
  628. const data: any = deepClone(options);
  629. data.id = id;
  630. if (data.type === 'anyLine') {
  631. const path = obj.getPath();
  632. // 将AMap.LngLat对象数组转换为经纬度数组
  633. const pathArr = path.map((lngLat) => {
  634. // 返回经度和纬度的数组
  635. return [lngLat.lng, lngLat.lat];
  636. });
  637. pathArr.push(pathArr[0]);
  638. data.path = pathArr;
  639. }
  640. overlays.push(obj);
  641. overlaysData.push(data);
  642. commit(deepClone(overlaysData));
  643. sendWebSocket(data);
  644. };
  645. // 协同标绘发送新增
  646. const sendWebSocket = (data) => {
  647. if (!collaboration.value || !webSock) return;
  648. webSock.send(
  649. JSON.stringify({
  650. operation: 'add', // 必填
  651. id: data.id,
  652. name: data.title, // 必填
  653. content: JSON.stringify(data), // 必填
  654. visible: '1'
  655. })
  656. );
  657. };
  658. // 图形右击事件
  659. let rightClickObj;
  660. let initContextMenu = false;
  661. const handleRightClick = (event) => {
  662. rightClickObj = event.target;
  663. const contextMenu = getDrawTool().getContextMenu();
  664. if (!initContextMenu) {
  665. // 右键删除按钮
  666. contextMenu.addItem(
  667. '删除',
  668. function () {
  669. contextMenu.close();
  670. deleteGraphics();
  671. },
  672. 0
  673. );
  674. initContextMenu = true;
  675. }
  676. contextMenu.open(getMap(), event.lnglat);
  677. };
  678. // 删除图形
  679. const deleteGraphics = () => {
  680. const id = rightClickObj.getExtData()?.id;
  681. if (id) {
  682. for (let i = 0; i < overlays.length; i++) {
  683. const overlay = Array.isArray(overlays[i]) ? overlays[i][0] : overlays[i];
  684. if (overlay?.getExtData().id === id) {
  685. removeOverlayByIndex(i);
  686. commit(deepClone(overlaysData));
  687. rightClickObj = null;
  688. }
  689. }
  690. }
  691. };
  692. // 撤销绘制
  693. const handleUndo = () => {
  694. // drawing.value = false;
  695. const previous = history.value[history.value.length - 2];
  696. if (history.value.length > 1) {
  697. if (currentState.value.length > previous.length) {
  698. // 撤销新增
  699. removeOverlayByIndex(currentState.value.length - 1);
  700. } else {
  701. let restoreData;
  702. for (let i = 0; i < previous.length; i++) {
  703. let index = 0;
  704. for (let k = 0; k < currentState.value.length; k++) {
  705. if (previous[i].id !== currentState.value[k].id) {
  706. index++;
  707. } else {
  708. break;
  709. }
  710. }
  711. if (index === previous.length - 1) {
  712. restoreData = previous[i];
  713. break;
  714. }
  715. }
  716. if (restoreData) {
  717. const obj = getDrawTool().createGraphics(restoreData);
  718. overlays.push(obj);
  719. }
  720. }
  721. undo();
  722. console.log(history.value, future.value, currentState.value);
  723. }
  724. };
  725. // 移除所有覆盖物
  726. const removeAllOverlay = () => {
  727. const map = getMap();
  728. overlays.forEach((item, index) => {
  729. if (Array.isArray(item)) {
  730. item.forEach((overlay) => {
  731. // 移除地图上覆盖物
  732. map.remove(overlay);
  733. });
  734. } else {
  735. // 移除地图上覆盖物
  736. map.remove(item);
  737. }
  738. });
  739. overlays = [];
  740. overlaysData = [];
  741. };
  742. // 根据索引移除覆盖物
  743. const removeOverlayByIndex = (index: number) => {
  744. const map = getMap();
  745. if (Array.isArray(overlays[index])) {
  746. overlays[index].forEach((overlay) => {
  747. // 移除地图上覆盖物
  748. map.remove(overlay);
  749. });
  750. } else {
  751. // 移除地图上覆盖物
  752. map.remove(overlays[index]);
  753. if (collaboration.value) {
  754. webSock.send(
  755. JSON.stringify({
  756. operation: 'delete',
  757. id: overlays[index].getExtData()?.id
  758. })
  759. );
  760. }
  761. }
  762. overlays.splice(index, 1);
  763. overlaysData.splice(index, 1);
  764. };
  765. // 历史预案
  766. const queryParams = reactive({
  767. page: 1,
  768. pageSize: 9,
  769. pattern_name: ''
  770. });
  771. const patternList = ref([]);
  772. let total = ref(0);
  773. let editData = ref({
  774. id: '',
  775. pattern_name: '',
  776. content: {}
  777. });
  778. let showEdit = ref(false);
  779. const handleSubmit = () => {
  780. showEdit.value = false;
  781. editData.value = {
  782. id: '',
  783. pattern_name: '',
  784. content: {}
  785. };
  786. getList();
  787. };
  788. const handleQuery = () => {
  789. queryParams.page = 1;
  790. getList();
  791. };
  792. const getList = () => {
  793. // if (menuActive1.value === 1 && menu.value[menuActive1.value].name == '历史预案') {
  794. getPatternList(queryParams).then((res) => {
  795. patternList.value = res.data;
  796. total.value = res.total;
  797. });
  798. // }
  799. };
  800. const handleDelete = (id: number) => {
  801. proxy?.$modal.confirm('是否确认删除选择的数据项?').then(() => {
  802. deletePatternById(id).then(() => {
  803. getList();
  804. });
  805. });
  806. };
  807. const handleEdit = (id) => {
  808. getPatternInfo(id).then((res) => {
  809. editData.value = res.data;
  810. editData.value.id = id;
  811. });
  812. showEdit.value = true;
  813. };
  814. const handleShare = (type, id?: string) => {
  815. shareState.type = type;
  816. shareState.id = id;
  817. shareState.showShare = true;
  818. };
  819. const handleCloseShare = () => {
  820. shareState.type = '';
  821. shareState.id = '';
  822. };
  823. const handleCloseCollaboration = () => {
  824. closeCollaboration({ pattern_id: patternId.value }).then(() => {
  825. collaboration.value = false;
  826. });
  827. };
  828. let showForm = ref(false);
  829. let form = ref({
  830. pattern_id: '',
  831. user_id_list: [],
  832. name: '',
  833. pattern_name: '',
  834. visible: 'false',
  835. content: ''
  836. });
  837. const handleShareConfirm = (data) => {
  838. if (shareState.type === '1') {
  839. // 协同标绘
  840. const userIdList = [];
  841. data.forEach((item) => {
  842. userIdList.push(item.userId);
  843. });
  844. let list = [];
  845. currentState.value.forEach((item) => {
  846. list.push({
  847. name: item.title,
  848. visible: 'true',
  849. content: JSON.stringify(item)
  850. });
  851. });
  852. form.value = {
  853. pattern_id: nanoid(),
  854. user_id_list: userIdList,
  855. pattern_name: '',
  856. bz_list: list
  857. };
  858. showForm.value = true;
  859. } else {
  860. // 分享
  861. }
  862. shareState.type = '';
  863. shareState.id = '';
  864. };
  865. const getWebSocketData = (data) => {
  866. if (data && data.length > 0) {
  867. const data2 = [];
  868. const data3 = deepClone(data);
  869. data.forEach((item) => {
  870. if (!!item.content) {
  871. const parseContent = JSON.parse(item.content);
  872. if (parseContent.type === 'marker' && !!parseContent.icon) {
  873. parseContent.icon = getImageUrl(parseContent.icon);
  874. }
  875. data2.push(parseContent);
  876. }
  877. });
  878. const res = getMapUtils().drawData(data2);
  879. removeAllOverlay();
  880. res.forEach((item, index) => {
  881. overlays.push(item);
  882. overlaysData.push(data3[index]);
  883. });
  884. commit(deepClone(overlaysData));
  885. currentState.value = data;
  886. }
  887. console.log('接收数据', data);
  888. };
  889. const handleSendForm = () => {
  890. if (!form.value.pattern_name) {
  891. return proxy?.$modal.msgWarning('请填写预案名称');
  892. }
  893. // webSock = createWebSocket('X_cBqh0q1GUVhTOmS5c8w', getWebSocketData);
  894. // patternId.value = 'X_cBqh0q1GUVhTOmS5c8w';
  895. createCollaboration(form.value).then(() => {
  896. patternId.value = form.value.pattern_id;
  897. webSock = createWebSocket(form.value.pattern_id, getWebSocketData);
  898. showForm.value = false;
  899. collaboration.value = true;
  900. proxy?.$modal.msgSuccess('开启协同标绘成功');
  901. });
  902. };
  903. const handleShowDialog = () => {
  904. editData.value = {
  905. id: '',
  906. pattern_name: '',
  907. content: currentState.value
  908. };
  909. showEdit.value = true;
  910. };
  911. let showSetting = ref(false);
  912. const handleOpenSetting = () => {
  913. showSetting.value = true;
  914. handleExitMenuActive();
  915. getTemplateTreeData();
  916. };
  917. const handleQuitSetting = () => {
  918. showSetting.value = false;
  919. getTemplateTreeData();
  920. };
  921. const handleShowSetting = (item, index) => {
  922. menu.value[0].children.forEach((menu2) => {
  923. menu2.children.forEach((item2) => {
  924. item2.showSetting = item.name === item2.name;
  925. });
  926. });
  927. };
  928. let dataURL = ref('');
  929. // 页面元素转图片
  930. const handleScreenshot = () => {
  931. const canvasBox = getMap().Iv;
  932. // 手动创建一个 canvas 标签
  933. const canvas = document.createElement('canvas');
  934. if (canvasBox) {
  935. // 获取父级的宽高
  936. const width = parseInt(window.getComputedStyle(canvasBox).width) / containerScale().scaleX;
  937. const height = parseInt(window.getComputedStyle(canvasBox).height) / containerScale().scaleX;
  938. canvas.style.width = width + 'px';
  939. canvas.style.height = height + 'px';
  940. const options = {
  941. backgroundColor: null, // 设置背景色为透明
  942. useCORS: true, //是否尝试使用CORS从服务器加载图像,解决跨域问题
  943. tainttest: true, // 是否在渲染前测试图片
  944. logging: false // 不启动日志调试
  945. };
  946. // canvasBox是要截图的元素,options是一些相关配置
  947. html2canvas(canvasBox, options).then((canvas) => {
  948. // toDataURL 图片格式转成 base64
  949. dataURL.value = canvas.toDataURL('image/png');
  950. // 新建一个a标签
  951. var oA = document.createElement('a');
  952. oA.download = '截图'; // 设置下载的文件名
  953. oA.href = dataURL.value;
  954. document.body.appendChild(oA);
  955. oA.click(); // 模拟点击a标签
  956. oA.remove(); // 下载之后把创建的元素删除
  957. });
  958. }
  959. };
  960. let showLayer = ref(false);
  961. let handleShowLayer = () => {
  962. showLayer.value = true;
  963. };
  964. const handleSendData = (data) => {
  965. const { type, content } = data;
  966. if (type === 'update') {
  967. webSock.send(
  968. JSON.stringify({
  969. operation: 'update',
  970. id: content.id,
  971. name: content.name,
  972. content: content.content,
  973. visible: content.visible
  974. })
  975. );
  976. }
  977. };
  978. onMounted(() => {
  979. getTemplateTreeData();
  980. getList();
  981. });
  982. </script>
  983. <style lang="scss" scoped>
  984. .menu-content {
  985. width: 612px;
  986. height: 685px;
  987. background: url('@/assets/images/map/rightMenu/onlinePlotting/dialog.png') no-repeat;
  988. padding: 60px 10px 10px 15px;
  989. font-size: 14px;
  990. position: relative;
  991. color: #ffffff;
  992. }
  993. :deep(.el-color-dropdown__link-btn) {
  994. display: none;
  995. }
  996. .line {
  997. display: flex;
  998. justify-content: space-between;
  999. align-items: center;
  1000. }
  1001. .tabs1 {
  1002. display: flex;
  1003. .tab {
  1004. width: 123px;
  1005. height: 30px;
  1006. line-height: 30px;
  1007. background: url('@/assets/images/map/rightMenu/onlinePlotting/tab.png') no-repeat;
  1008. background-size: 100% 100%;
  1009. cursor: pointer;
  1010. font-size: 16px;
  1011. color: #b7c1d5;
  1012. font-family: YouSheBiaoTiHei;
  1013. padding-left: 28px;
  1014. &:hover {
  1015. width: 123px;
  1016. height: 30px;
  1017. color: #ffffff;
  1018. background: url('@/assets/images/map/rightMenu/onlinePlotting/tabActive.png') no-repeat;
  1019. background-size: 100% 100%;
  1020. }
  1021. }
  1022. .tab_active {
  1023. width: 123px;
  1024. height: 30px;
  1025. color: #ffffff;
  1026. background: url('@/assets/images/map/rightMenu/onlinePlotting/tabActive.png') no-repeat;
  1027. background-size: 100% 100%;
  1028. }
  1029. }
  1030. .btn1 {
  1031. width: 200px;
  1032. height: 60px;
  1033. background: url('@/assets/images/map/rightMenu/onlinePlotting/btn1.png') no-repeat;
  1034. background-size: 100% 100%;
  1035. display: flex;
  1036. justify-content: center;
  1037. align-items: center;
  1038. cursor: pointer;
  1039. font-size: 14px;
  1040. color: #edfaff;
  1041. .icon1 {
  1042. width: 22px;
  1043. height: 22px;
  1044. background: url('@/assets/images/map/rightMenu/onlinePlotting/screenshot.png') no-repeat;
  1045. background-size: 100% 100%;
  1046. margin-right: 6px;
  1047. }
  1048. }
  1049. .btn2 {
  1050. width: 104px;
  1051. height: 29px;
  1052. background: url('@/assets/images/map/rightMenu/btn.png') no-repeat;
  1053. display: flex;
  1054. justify-content: center;
  1055. align-items: center;
  1056. cursor: pointer;
  1057. font-size: 16px;
  1058. color: #edfaff;
  1059. .icon1 {
  1060. width: 42px;
  1061. height: 42px;
  1062. background: url('@/assets/images/map/rightMenu/onlinePlotting/screenshot.png') no-repeat;
  1063. margin-right: 12px;
  1064. }
  1065. }
  1066. .box1 {
  1067. display: flex;
  1068. justify-content: space-between;
  1069. align-items: center;
  1070. width: 100%;
  1071. height: 36px;
  1072. background: url('@/assets/images/map/rightMenu/onlinePlotting/box1.png') no-repeat;
  1073. background-size: 100% 100%;
  1074. padding: 10px 12px;
  1075. .box-item {
  1076. display: flex;
  1077. align-items: center;
  1078. }
  1079. }
  1080. .btn {
  1081. display: flex;
  1082. align-items: center;
  1083. cursor: pointer;
  1084. .revoke-icon {
  1085. width: 24px;
  1086. height: 25px;
  1087. margin-right: 3px;
  1088. background: url('@/assets/images/map/rightMenu/onlinePlotting/revoke.png') no-repeat;
  1089. background-size: 100% 100%;
  1090. }
  1091. .delete-icon {
  1092. width: 25px;
  1093. height: 25px;
  1094. margin-right: 3px;
  1095. background: url('@/assets/images/map/rightMenu/onlinePlotting/delete.png') no-repeat;
  1096. background-size: 100% 100%;
  1097. }
  1098. .edit-icon {
  1099. width: 23px;
  1100. height: 23px;
  1101. margin-right: 3px;
  1102. background: url('@/assets/images/map/rightMenu/onlinePlotting/edit.png') no-repeat;
  1103. background-size: 100% 100%;
  1104. }
  1105. .cancel-icon {
  1106. width: 25px;
  1107. height: 25px;
  1108. margin-right: 3px;
  1109. background: url('@/assets/images/map/rightMenu/onlinePlotting/cancel.png') no-repeat;
  1110. background-size: 100% 100%;
  1111. }
  1112. .save-icon {
  1113. width: 23px;
  1114. height: 23px;
  1115. margin-right: 3px;
  1116. background: url('@/assets/images/map/rightMenu/onlinePlotting/save.png') no-repeat;
  1117. background-size: 100% 100%;
  1118. }
  1119. .share-icon {
  1120. width: 23px;
  1121. height: 24px;
  1122. margin-right: 3px;
  1123. background: url('@/assets/images/map/rightMenu/onlinePlotting/share.png') no-repeat;
  1124. background-size: 100% 100%;
  1125. }
  1126. .setting-icon {
  1127. width: 24px;
  1128. height: 25px;
  1129. margin-right: 3px;
  1130. background: url('@/assets/images/map/rightMenu/onlinePlotting/setting.png') no-repeat;
  1131. background-size: 100% 100%;
  1132. }
  1133. .template-icon {
  1134. width: 24px;
  1135. height: 26px;
  1136. margin-right: 3px;
  1137. background: url('@/assets/images/map/rightMenu/onlinePlotting/template.png') no-repeat;
  1138. background-size: 100% 100%;
  1139. }
  1140. .categoryImport-icon {
  1141. width: 24px;
  1142. height: 26px;
  1143. margin-right: 3px;
  1144. background: url('@/assets/images/map/rightMenu/onlinePlotting/categoryImport.png') no-repeat;
  1145. background-size: 100% 100%;
  1146. }
  1147. .merge-icon {
  1148. width: 26px;
  1149. height: 26px;
  1150. margin-right: 3px;
  1151. background: url('@/assets/images/map/rightMenu/onlinePlotting/merge.png') no-repeat;
  1152. background-size: 100% 100%;
  1153. }
  1154. }
  1155. .line2 {
  1156. width: 1px;
  1157. height: 10px;
  1158. background-color: #a7ccdf;
  1159. margin: 0 10px;
  1160. }
  1161. .tabs2 {
  1162. width: 115px;
  1163. min-width: 115px;
  1164. height: 460px;
  1165. background: url('@/assets/images/map/rightMenu/onlinePlotting/tabBg.png') no-repeat;
  1166. background-size: 100% 100%;
  1167. overflow-y: auto;
  1168. padding: 10px 0;
  1169. .tab {
  1170. width: 100%;
  1171. height: 35px;
  1172. cursor: pointer;
  1173. color: #eaf3fc;
  1174. font-size: 14px;
  1175. padding: 0 25px;
  1176. display: flex;
  1177. align-items: center;
  1178. &:hover {
  1179. background: url('@/assets/images/map/rightMenu/onlinePlotting/tabActive2.png') no-repeat;
  1180. background-size: 100% 100%;
  1181. }
  1182. }
  1183. .tab_active {
  1184. background: url('@/assets/images/map/rightMenu/onlinePlotting/tabActive2.png') no-repeat;
  1185. background-size: 100% 100%;
  1186. }
  1187. }
  1188. .tab-content {
  1189. display: flex;
  1190. margin-top: 6px;
  1191. .tab-content2 {
  1192. padding: 18px 15px;
  1193. display: flex;
  1194. flex-direction: column;
  1195. .line {
  1196. height: 100px;
  1197. }
  1198. .line3 {
  1199. display: flex;
  1200. }
  1201. .tab-list {
  1202. width: 100%;
  1203. flex: 1;
  1204. overflow-x: hidden;
  1205. overflow-y: auto;
  1206. display: flex;
  1207. flex-wrap: wrap;
  1208. align-content: baseline;
  1209. .icon {
  1210. width: 45px;
  1211. height: 25px;
  1212. margin-bottom: 8px;
  1213. }
  1214. .tab {
  1215. &:nth-child(3n-1) {
  1216. margin: 18px 23px 0;
  1217. }
  1218. }
  1219. .setting-btn {
  1220. position: absolute;
  1221. bottom: 7px;
  1222. right: 5px;
  1223. width: 25px;
  1224. height: 24px;
  1225. background: url('@/assets/images/map/rightMenu/onlinePlotting/setting2.png') no-repeat;
  1226. background-size: 100% 100%;
  1227. cursor: pointer;
  1228. }
  1229. .setting-menu {
  1230. position: absolute;
  1231. bottom: -103px;
  1232. right: 0;
  1233. z-index: 99;
  1234. width: 66px;
  1235. height: 94px;
  1236. border: 1px solid #2c81ff;
  1237. background-color: #091432;
  1238. //box-shadow: inset 0 0 60px #596891;
  1239. padding: 6px 0;
  1240. &::after {
  1241. content: '';
  1242. width: 14px;
  1243. height: 14px;
  1244. border-top: 1px solid #2c81ff;
  1245. border-left: 1px solid #2c81ff;
  1246. border-bottom: 1px solid transparent;
  1247. border-right: 1px solid transparent;
  1248. position: absolute;
  1249. top: -7px;
  1250. right: 10px;
  1251. transform: rotate(45deg);
  1252. background-color: #091432;
  1253. }
  1254. .menu-item {
  1255. width: 100%;
  1256. display: flex;
  1257. align-items: center;
  1258. justify-content: center;
  1259. color: #a7b3c5;
  1260. font-size: 14px;
  1261. height: 26px;
  1262. cursor: pointer;
  1263. .icon-switch {
  1264. display: inline-block;
  1265. width: 12px;
  1266. height: 12px;
  1267. background: url('@/assets/images/map/rightMenu/onlinePlotting/switch1.png') no-repeat;
  1268. background-size: 100% 100%;
  1269. margin-right: 6px;
  1270. }
  1271. .icon-eye {
  1272. display: inline-block;
  1273. width: 12px;
  1274. height: 10px;
  1275. background: url('@/assets/images/map/rightMenu/onlinePlotting/show1.png') no-repeat;
  1276. background-size: 100% 100%;
  1277. margin-right: 6px;
  1278. }
  1279. .icon-eye2 {
  1280. display: inline-block;
  1281. width: 12px;
  1282. height: 11px;
  1283. background: url('@/assets/images/map/rightMenu/onlinePlotting/hide1.png') no-repeat;
  1284. background-size: 100% 100%;
  1285. margin-right: 6px;
  1286. }
  1287. .icon-delete {
  1288. display: inline-block;
  1289. width: 11px;
  1290. height: 12px;
  1291. background: url('@/assets/images/map/rightMenu/onlinePlotting/delete1.png') no-repeat;
  1292. background-size: 100% 100%;
  1293. margin-right: 6px;
  1294. }
  1295. &:hover {
  1296. color: #00fde7;
  1297. background: #1e3b77;
  1298. .icon-switch {
  1299. background: url('@/assets/images/map/rightMenu/onlinePlotting/switch2.png') no-repeat;
  1300. background-size: 100% 100%;
  1301. }
  1302. .icon-eye {
  1303. background: url('@/assets/images/map/rightMenu/onlinePlotting/show2.png') no-repeat;
  1304. background-size: 100% 100%;
  1305. }
  1306. .icon-eye2 {
  1307. background: url('@/assets/images/map/rightMenu/onlinePlotting/hide2.png') no-repeat;
  1308. background-size: 100% 100%;
  1309. }
  1310. .icon-delete {
  1311. background: url('@/assets/images/map/rightMenu/onlinePlotting/delete2.png') no-repeat;
  1312. background-size: 100% 100%;
  1313. }
  1314. }
  1315. }
  1316. }
  1317. }
  1318. .tab {
  1319. width: 129px;
  1320. height: 91px;
  1321. background: url('@/assets/images/map/rightMenu/onlinePlotting/box2.png') no-repeat;
  1322. background-size: 100% 100%;
  1323. padding: 7px;
  1324. cursor: pointer;
  1325. position: relative;
  1326. font-size: 14px;
  1327. color: #eaf3fc;
  1328. display: flex;
  1329. flex-direction: column;
  1330. justify-content: center;
  1331. align-items: center;
  1332. margin-top: 18px;
  1333. &:hover {
  1334. background: url('@/assets/images/map/rightMenu/onlinePlotting/boxHover2.png') no-repeat;
  1335. background-size: 100% 100%;
  1336. }
  1337. .checked1 {
  1338. position: absolute;
  1339. top: 8px;
  1340. right: 8px;
  1341. width: 13px;
  1342. height: 13px;
  1343. background: url('@/assets/images/map/rightMenu/onlinePlotting/checked1.png') no-repeat;
  1344. background-size: 100% 100%;
  1345. }
  1346. .checked2 {
  1347. position: absolute;
  1348. top: 8px;
  1349. right: 8px;
  1350. width: 13px;
  1351. height: 13px;
  1352. background: url('@/assets/images/map/rightMenu/onlinePlotting/checked2.png') no-repeat;
  1353. background-size: 100% 100%;
  1354. }
  1355. }
  1356. .tab_active {
  1357. background: url('@/assets/images/map/rightMenu/onlinePlotting/boxActive2.png') no-repeat;
  1358. background-size: 100% 100%;
  1359. }
  1360. }
  1361. }
  1362. .tipTitle {
  1363. position: fixed;
  1364. top: 123px;
  1365. left: 50%;
  1366. transform: translateX(-50%);
  1367. z-index: 2;
  1368. padding: 10px 30px;
  1369. font-size: 18px;
  1370. color: #fff;
  1371. background-color: rgba(0, 0, 0, 0.4);
  1372. border-radius: 10px;
  1373. }
  1374. .tab-content3 {
  1375. .custom-table {
  1376. width: 100%;
  1377. color: #000;
  1378. .table-header {
  1379. display: flex;
  1380. font-size: 14px;
  1381. width: 100%;
  1382. background-color: #194ba0;
  1383. .th {
  1384. padding: 11px;
  1385. flex: 1;
  1386. color: #edfaff;
  1387. &:last-child {
  1388. flex: unset;
  1389. width: 180px;
  1390. }
  1391. }
  1392. }
  1393. .tr {
  1394. display: flex;
  1395. font-size: 14px;
  1396. height: 32px;
  1397. background: url('@/assets/images/map/rightMenu/onlinePlotting/tr.png') no-repeat;
  1398. background-size: 100% 100%;
  1399. margin-top: 10px;
  1400. &:hover {
  1401. background: url('@/assets/images/map/rightMenu/onlinePlotting/trActive.png') no-repeat;
  1402. }
  1403. .td {
  1404. padding: 11px;
  1405. color: #edfaff;
  1406. flex: 1;
  1407. .icon {
  1408. margin: 0 10px;
  1409. cursor: pointer;
  1410. }
  1411. }
  1412. .td2 {
  1413. flex: unset;
  1414. display: flex;
  1415. justify-content: center;
  1416. align-items: center;
  1417. }
  1418. }
  1419. }
  1420. }
  1421. .color-container {
  1422. width: 31px;
  1423. height: 22px;
  1424. display: flex;
  1425. justify-content: center;
  1426. align-items: center;
  1427. position: relative;
  1428. background-color: #0d3980;
  1429. border: 1px solid #0b5fbb;
  1430. margin-left: 8px;
  1431. :deep(.el-color-picker) {
  1432. height: 14px !important;
  1433. .el-color-picker__trigger {
  1434. width: 14px;
  1435. height: 14px;
  1436. padding: 0;
  1437. border: none;
  1438. }
  1439. }
  1440. &::before {
  1441. content: '';
  1442. position: absolute;
  1443. top: 0;
  1444. left: 0;
  1445. width: 6px;
  1446. height: 6px;
  1447. background: url('@/assets/images/inputIcon1.png') no-repeat;
  1448. }
  1449. &::after {
  1450. content: '';
  1451. position: absolute;
  1452. right: 0;
  1453. bottom: 0;
  1454. width: 6px;
  1455. height: 6px;
  1456. background: url('@/assets/images/inputIcon2.png') no-repeat;
  1457. }
  1458. }
  1459. .params-box {
  1460. margin: 10px 0;
  1461. }
  1462. .footer {
  1463. display: flex;
  1464. justify-content: flex-end;
  1465. margin-top: 30px;
  1466. padding-right: 40px;
  1467. :deep(.el-pagination__total) {
  1468. color: #a7ccdf !important;
  1469. }
  1470. :deep(.el-pagination) {
  1471. .btn-next,
  1472. .btn-prev {
  1473. background-color: transparent !important;
  1474. border: none !important;
  1475. .el-icon {
  1476. color: #a7ccdf !important;
  1477. }
  1478. }
  1479. .btn-prev:disabled,
  1480. .btn-next:disabled {
  1481. background-color: transparent !important;
  1482. border: none !important;
  1483. }
  1484. .el-pager li {
  1485. text-align: center;
  1486. color: #a7ccdf !important;
  1487. background-color: #0e3064 !important;
  1488. border: 1px solid #0c57a7 !important;
  1489. &:hover {
  1490. background-color: #038dff !important;
  1491. border: 1px solid #038dff !important;
  1492. }
  1493. }
  1494. .el-pager li.is-active {
  1495. background-color: #038dff !important;
  1496. border: 1px solid #038dff !important;
  1497. }
  1498. }
  1499. }
  1500. .btn-box {
  1501. display: flex;
  1502. align-items: center;
  1503. }
  1504. .btn-text {
  1505. color: #5983df;
  1506. cursor: pointer;
  1507. }
  1508. </style>