index.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  1. <template>
  2. <div>
  3. <div @click="show">
  4. <slot>
  5. <div v-if="value.heatMapData.length" class="cursor-pointer">
  6. 已选<span class="text-primary p-[4px]">{{ value.heatMapData.length }}</span
  7. >个热区
  8. </div>
  9. <div v-else class="cursor-pointer">添加热区</div>
  10. </slot>
  11. </div>
  12. <el-dialog v-model="showDialog" title="热区设置" width="810px" :destroy-on-close="true" :close-on-click-modal="false">
  13. <div class="flex">
  14. <div
  15. class="hot-area-img-wrap content-box relative bg-gray-100 border border-dashed border-gray-500 bg-no-repeat"
  16. :style="{ backgroundImage: 'url(' + img(value.imageUrl) + ')', width: contentBoxWidth + 'px', height: contentBoxHeight + 'px' }"
  17. >
  18. <div
  19. v-for="(item, index) in dragBoxArr"
  20. :id="'box_' + index"
  21. :key="index"
  22. class="area-box border border-solid border-[#ccc] w-[100px] h-[100px] absolute top-0 left-0 select-none p-[5px]"
  23. :style="{ left: item.left + item.unit, top: item.top + item.unit, width: item.width + item.unit, height: item.height + item.unit }"
  24. @mousedown="mouseDown($event, index)"
  25. >
  26. <span>{{ Number(index) + 1 }}</span>
  27. <!-- <template v-if="item.link">
  28. <span class="p-[4px]">|</span>
  29. <span>{{ item.link }}</span>
  30. </template> -->
  31. <span class="box1" @mousedown.stop="resizeMouseDown($event, index)"></span>
  32. <span class="box2" @mousedown.stop="resizeMouseDown($event, index)"></span>
  33. <span class="box3" @mousedown.stop="resizeMouseDown($event, index)"></span>
  34. <span class="box4" @mousedown.stop="resizeMouseDown($event, index)"></span>
  35. </div>
  36. </div>
  37. <el-form label-width="80px" class="pl-[20px]">
  38. <h3 class="mb-[10px] text-lg text-black">热区管理</h3>
  39. <el-button type="primary" plain size="small" class="mb-[10px]" @click="addArea">添加热区</el-button>
  40. <div class="overflow-y-auto h-[300px]">
  41. <template v-for="(item, index) in dragBoxArr" :key="index">
  42. <div class="mb-[16px]" v-if="item">
  43. <el-form-item :label="'热区' + (Number(index) + 1)">
  44. <div class="flex items-center">
  45. <div style="width: 230px">
  46. <WebLinkInput v-model="item.link" placeholder="请输入或选择链接" />
  47. </div>
  48. <icon
  49. class="del cursor-pointer mx-[10px]"
  50. name="element CircleCloseFilled"
  51. color="#bbb"
  52. size="20px"
  53. @click="dragBoxArr.splice(index, 1)"
  54. />
  55. </div>
  56. </el-form-item>
  57. </div>
  58. </template>
  59. </div>
  60. </el-form>
  61. </div>
  62. <template #footer>
  63. <span class="dialog-footer">
  64. <el-button @click="showDialog = false">返回</el-button>
  65. <el-button type="primary" @click="save">确定</el-button>
  66. </span>
  67. </template>
  68. </el-dialog>
  69. </div>
  70. </template>
  71. <script lang="ts" setup>
  72. import { ref, reactive, computed } from 'vue';
  73. import { ElMessage } from 'element-plus';
  74. import { img, deepClone } from '@/utils/common';
  75. const prop = defineProps({
  76. modelValue: {
  77. type: Object as () => Record<string, any>,
  78. default: () => {}
  79. }
  80. });
  81. const emit = defineEmits(['update:modelValue']);
  82. const value: any = computed({
  83. get() {
  84. return prop.modelValue;
  85. },
  86. set(value) {
  87. emit('update:modelValue', value);
  88. }
  89. });
  90. /**
  91. * 公式:
  92. * 宽度:400
  93. * 比例:原图高/原图宽,示例:466/698=0.66
  94. * 高度:宽度*比例,示例:400*0.66=264
  95. */
  96. const showDialog = ref(false);
  97. const contentBoxWidth = ref(400);
  98. const contentBoxHeight = ref(400);
  99. const dragBoxArr: any = reactive([]);
  100. const imgRatio = ref(1); // 图片比例
  101. // 热区尺寸
  102. const areaRadio = ref(0.25); // 占位图比例
  103. const areaWidth = ref(100);
  104. const areaHeight = ref(100);
  105. const areaNum = ref(4); // 每行显示的数量
  106. // 添加热区
  107. const addArea = () => {
  108. let left = (dragBoxArr.length % areaNum.value) * areaWidth.value;
  109. let top = Math.floor(dragBoxArr.length / areaNum.value) * areaHeight.value;
  110. const edgeHeight = top + areaHeight.value / 2;
  111. if (top >= contentBoxHeight.value || edgeHeight >= contentBoxHeight.value) {
  112. top = 0;
  113. left = 0;
  114. }
  115. dragBoxArr.push({
  116. left,
  117. top,
  118. width: areaWidth.value,
  119. height: areaHeight.value,
  120. unit: 'px',
  121. link: ''
  122. });
  123. };
  124. // 移动事件
  125. const mouseDown = (e: any, index: any) => {
  126. const box: any = document.getElementById('box_' + index);
  127. const disX = e.clientX - box.offsetLeft;
  128. const disY = e.clientY - box.offsetTop;
  129. // 鼠标移动时
  130. document.onmousemove = function (e) {
  131. box.style.left = e.clientX - disX + 'px';
  132. box.style.top = e.clientY - disY + 'px';
  133. // 边界判断
  134. if (e.clientX - disX < 0) {
  135. box.style.left = 0;
  136. }
  137. if (e.clientX - disX > contentBoxWidth.value - box.offsetWidth) {
  138. box.style.left = contentBoxWidth.value - box.offsetWidth + 'px';
  139. }
  140. if (e.clientY - disY < 0) {
  141. box.style.top = 0;
  142. }
  143. if (e.clientY - disY > contentBoxHeight.value - box.offsetHeight) {
  144. box.style.top = contentBoxHeight.value - box.offsetHeight + 'px';
  145. }
  146. dragBoxArr[index].left = box.offsetLeft;
  147. dragBoxArr[index].top = box.offsetTop;
  148. dragBoxArr[index].width = box.offsetWidth;
  149. dragBoxArr[index].height = box.offsetHeight;
  150. dragBoxArr[index].unit = 'px';
  151. };
  152. // 鼠标抬起时
  153. document.onmouseup = function (e) {
  154. document.onmousemove = null;
  155. };
  156. };
  157. // 拖拽大小事件
  158. const resizeMouseDown = (e: any, index: any) => {
  159. const oEv = e;
  160. oEv.stopPropagation();
  161. const box: any = document.getElementById('box_' + index);
  162. const className = e.target.className;
  163. // 获取移动前盒子的宽高,
  164. const oldWidth = box.offsetWidth;
  165. const oldHeight = box.offsetHeight;
  166. // 获取鼠标距离屏幕的left和top值
  167. const oldX = oEv.clientX;
  168. const oldY = oEv.clientY;
  169. // 元素相对于最近的父级定位
  170. const oldLeft = box.offsetLeft;
  171. const oldTop = box.offsetTop;
  172. // 设置最小的宽度
  173. const minWidth = 50;
  174. const minHeight = 50;
  175. document.onmousemove = function (e) {
  176. const oEv = e;
  177. // console.log('move', "width:" + oldWidth,
  178. // ',oldLeft: ' + oldLeft, ',oldTop: ' + oldTop,
  179. // ',oldX:clientX-- ' + oldX + ':' + oEv.clientX,
  180. // ',oldY:clientY-- ' + oldY + ':' + oEv.clientY,
  181. // )
  182. // 左上角
  183. if (className == 'box1') {
  184. let width = oldWidth - (oEv.clientX - oldX);
  185. const maxWidth = contentBoxWidth.value;
  186. let height = oldHeight - (oEv.clientY - oldY);
  187. const maxHeight = contentBoxHeight.value - oldTop;
  188. let left = oldLeft + (oEv.clientX - oldX);
  189. let top = oldTop + (oEv.clientY - oldY);
  190. if (width < minWidth) {
  191. width = minWidth;
  192. }
  193. if (width > maxWidth) {
  194. width = maxWidth;
  195. }
  196. if (height < minHeight) {
  197. height = minHeight;
  198. }
  199. if (height > maxHeight) {
  200. height = maxHeight;
  201. }
  202. if (oldLeft == 0 && oldTop == 0) {
  203. // 坐标:left = 0,top = 0
  204. if (width == minWidth && height == minHeight) {
  205. // 宽高 = 最小值,left = 最小宽度,top = 最小高度
  206. left = minWidth;
  207. top = minHeight;
  208. } else if (width == minWidth && height > minHeight) {
  209. // 宽 = 最小值,高 > 最小值,left = 最小宽度,top = 不予处理
  210. left = minWidth;
  211. } else if (width > minWidth && height == minHeight) {
  212. // 宽 > 最小值,高 = 最小值,left = 不予处理,top = 最小高度
  213. top = minHeight;
  214. } else if (width > minWidth && height > minHeight) {
  215. // 宽 > 最小值,高 > 最小值,left = 不予处理,top = 不予处理
  216. }
  217. } else if (oldLeft == 0 && oldTop > 0) {
  218. // 坐标:left = 0,top > 0
  219. if (width == minWidth && height == minHeight) {
  220. // 宽高 = 最小值,left = 最小宽度,top = 元素上偏移位置
  221. left = minWidth;
  222. top = box.offsetTop;
  223. } else if (width == minWidth && height > minHeight) {
  224. // 宽 = 最小值,高 > 最小值,left = 最小宽度,top = 元素上偏移位置
  225. left = minWidth;
  226. top = box.offsetTop;
  227. } else if (width > minWidth && height == minHeight) {
  228. // 宽 > 最小值,高 = 最小值,left = 不予处理,top = 元素上偏移位置
  229. top = box.offsetTop;
  230. } else if (width > minWidth && height > minHeight) {
  231. // 宽 > 最小值,高 > 最小值,left = 不予处理,top = 不予处理
  232. }
  233. } else if (oldLeft > 0 && oldTop == 0) {
  234. // 坐标:left > 0,top = 0
  235. if (width == minWidth && height == minHeight) {
  236. // 宽高 = 最小值,left = 元素左偏移位置,top = 元素上偏移位置
  237. left = box.offsetLeft;
  238. top = box.offsetTop;
  239. } else if (width == minWidth && height > minHeight) {
  240. // 宽 = 最小值,高 > 最小值,left = 元素左偏移位置,top = 0
  241. left = box.offsetLeft;
  242. top = 0;
  243. } else if (width > minWidth && height == minHeight) {
  244. // 宽 > 最小值,高 = 最小值,left = 不予处理,top = 元素上偏移位置
  245. top = box.offsetTop;
  246. } else if (width > minWidth && height > minHeight) {
  247. // 宽 > 最小值,高 > 最小值,left = 不予处理,top = 不予处理
  248. }
  249. } else if (oldLeft > 0 && oldTop > 0) {
  250. // 坐标:left > 0,top > 0
  251. if (width == minWidth && height == minHeight) {
  252. // 宽高 = 最小值,left = 元素左偏移位置,top = 元素上偏移位置
  253. left = box.offsetLeft;
  254. top = box.offsetTop;
  255. } else if (width == minWidth && height > minHeight) {
  256. // 宽 = 最小值,高 > 最小值,left = 元素左偏移位置,top = 元素上偏移位置
  257. left = box.offsetLeft;
  258. top = box.offsetTop;
  259. } else if (width > minWidth && height == minHeight) {
  260. // 宽 > 最小值,高 = 最小值,left = 不予处理,top = 元素上偏移位置
  261. top = box.offsetTop;
  262. } else if (width > minWidth && height > minHeight) {
  263. // 宽 > 最小值,高 > 最小值,left = 不予处理,top = 不予处理
  264. }
  265. }
  266. // 左上宽
  267. if (left < 0) {
  268. left = 0;
  269. width = oldWidth - (oEv.clientX - oldX) + (oldLeft + (oEv.clientX - oldX));
  270. }
  271. // 左上 高
  272. if (top < 0) {
  273. top = 0;
  274. height = oldTop + (oEv.clientY - oldY) + (oldHeight - (oEv.clientY - oldY));
  275. }
  276. box.style.width = width + 'px';
  277. box.style.height = height + 'px';
  278. box.style.left = left + 'px';
  279. box.style.top = top + 'px';
  280. } else if (className == 'box2') {
  281. // 右上角
  282. let width = oldWidth + (oEv.clientX - oldX);
  283. const maxWidth = contentBoxWidth.value - oldLeft;
  284. let height = oldHeight - (oEv.clientY - oldY);
  285. const maxHeight = contentBoxHeight.value - oldTop;
  286. let top = oldTop + (oEv.clientY - oldY);
  287. if (width < minWidth) {
  288. width = minWidth;
  289. }
  290. if (width > maxWidth) {
  291. width = maxWidth;
  292. }
  293. if (height < minHeight) {
  294. height = minHeight;
  295. }
  296. if (height > maxHeight) {
  297. height = maxHeight;
  298. }
  299. if (oldLeft == 0 && oldTop == 0) {
  300. // 坐标:left = 0,top = 0
  301. if (width == minWidth && height == minHeight) {
  302. // 宽高 = 最小值,top = 最小高度
  303. top = minHeight;
  304. } else if (width == minWidth && height > minHeight) {
  305. // 宽 = 最小值,高 > 最小值,不予处理
  306. } else if (width > minWidth && height == minHeight) {
  307. // 宽 > 最小值,高 = 最小值,top = 最小高度
  308. top = minHeight;
  309. } else if (width > minWidth && height > minHeight) {
  310. // 宽 > 最小值,高 > 最小值,不予处理
  311. }
  312. } else if (oldLeft == 0 && oldTop > 0) {
  313. // 坐标:left = 0,top > 0
  314. if (width == minWidth && height == minHeight) {
  315. // 宽高 = 最小值,top = 元素上偏移位置
  316. top = box.offsetTop;
  317. } else if (width == minWidth && height > minHeight) {
  318. // 宽 = 最小值,高 > 最小值,top = 元素上偏移位置
  319. top = box.offsetTop;
  320. } else if (width > minWidth && height == minHeight) {
  321. // 宽 > 最小值,高 = 最小值,top = 元素上偏移位置
  322. top = box.offsetTop;
  323. } else if (width > minWidth && height > minHeight) {
  324. // 宽 > 最小值,高 > 最小值,不予处理
  325. }
  326. } else if (oldLeft > 0 && oldTop == 0) {
  327. // 坐标:left = 0,top = 0
  328. if (width == minWidth && height == minHeight) {
  329. // 宽高 = 最小值,top = 元素上偏移位置
  330. top = box.offsetTop;
  331. } else if (width == minWidth && height > minHeight) {
  332. // 宽 = 最小值,高 > 最小值,top = 0
  333. top = 0;
  334. } else if (width > minWidth && height == minHeight) {
  335. // 宽 > 最小值,高 = 最小值,top = 元素上偏移位置
  336. top = box.offsetTop;
  337. } else if (width > minWidth && height > minHeight) {
  338. // 宽 > 最小值,高 > 最小值,不予处理
  339. }
  340. } else if (oldLeft > 0 && oldTop > 0) {
  341. // 坐标:left > 0,top > 0
  342. if (width == minWidth && height == minHeight) {
  343. // 宽高 = 最小值,top = 元素上偏移位置
  344. top = box.offsetTop;
  345. } else if (width == minWidth && height > minHeight) {
  346. // 宽 = 最小值,高 > 最小值,top = 元素上偏移位置
  347. top = box.offsetTop;
  348. } else if (width > minWidth && height == minHeight) {
  349. // 宽 > 最小值,高 = 最小值,top = 元素上偏移位置
  350. top = box.offsetTop;
  351. } else if (width > minWidth && height > minHeight) {
  352. // 宽 > 最小值,高 > 最小值,不予处理
  353. }
  354. }
  355. // 右上高
  356. if (top < 0) {
  357. top = 0;
  358. height = oldTop + (oEv.clientY - oldY) + (oldHeight - (oEv.clientY - oldY));
  359. }
  360. box.style.width = width + 'px';
  361. box.style.height = height + 'px';
  362. box.style.top = top + 'px';
  363. } else if (className == 'box3') {
  364. // 左下角
  365. let width = oldWidth - (oEv.clientX - oldX);
  366. const maxWidth = contentBoxWidth.value;
  367. let height = oldHeight + (oEv.clientY - oldY);
  368. const maxHeight = contentBoxHeight.value - oldTop;
  369. let left = oldLeft + (oEv.clientX - oldX);
  370. if (width < minWidth) {
  371. width = minWidth;
  372. }
  373. if (width > maxWidth) {
  374. width = maxWidth;
  375. }
  376. if (height < minHeight) {
  377. height = minHeight;
  378. }
  379. if (height > maxHeight) {
  380. height = maxHeight;
  381. }
  382. if (oldLeft == 0 && oldTop == 0) {
  383. // 坐标:left = 0,top = 0
  384. if (width == minWidth && height == minHeight) {
  385. // 宽高 = 最小值,left = 最小宽度
  386. left = minWidth;
  387. } else if (width == minWidth && height > minHeight) {
  388. // 宽 = 最小值,高 > 最小值,left = 最小宽度
  389. left = minWidth;
  390. } else if (width > minWidth && height == minHeight) {
  391. // 宽 > 最小值,高 = 最小值,不予处理
  392. } else if (width > minWidth && height > minHeight) {
  393. // 宽 > 最小值,高 > 最小值,不予处理
  394. }
  395. } else if (oldLeft == 0 && oldTop > 0) {
  396. // 坐标:left = 0,top > 0
  397. if (width == minWidth && height == minHeight) {
  398. // 宽高 = 最小值,left = 最小宽度
  399. left = minWidth;
  400. } else if (width == minWidth && height > minHeight) {
  401. // 宽 = 最小值,高 > 最小值,left = 最小宽度
  402. left = minWidth;
  403. } else if (width > minWidth && height == minHeight) {
  404. // 宽 > 最小值,高 = 最小值,不予处理
  405. } else if (width > minWidth && height > minHeight) {
  406. // 宽 > 最小值,高 > 最小值,不予处理
  407. }
  408. } else if (oldLeft > 0 && oldTop == 0) {
  409. // 坐标:left > 0,top = 0
  410. if (width == minWidth && height == minHeight) {
  411. // 宽高 = 最小值,left = 元素左偏移位置
  412. left = box.offsetLeft;
  413. } else if (width == minWidth && height > minHeight) {
  414. // 宽 = 最小值,高 > 最小值,left = 元素左偏移位置
  415. left = box.offsetLeft;
  416. } else if (width > minWidth && height == minHeight) {
  417. // 宽 > 最小值,高 = 最小值,不予处理
  418. } else if (width > minWidth && height > minHeight) {
  419. // 宽 > 最小值,高 > 最小值,不予处理
  420. }
  421. } else if (oldLeft > 0 && oldTop > 0) {
  422. // 坐标:left > 0,top > 0
  423. if (width == minWidth && height == minHeight) {
  424. // 宽高 = 最小值,left = 元素左偏移位置
  425. left = box.offsetLeft;
  426. } else if (width == minWidth && height > minHeight) {
  427. // 宽 = 最小值,高 > 最小值,left = 元素左偏移位置
  428. left = box.offsetLeft;
  429. } else if (width > minWidth && height == minHeight) {
  430. // 宽 > 最小值,高 = 最小值,不予处理
  431. } else if (width > minWidth && height > minHeight) {
  432. // 宽 > 最小值,高 > 最小值,不予处理
  433. }
  434. }
  435. if (left < 0) {
  436. left = 0;
  437. width = oldWidth - (oEv.clientX - oldX) + (oldLeft + (oEv.clientX - oldX));
  438. }
  439. box.style.width = width + 'px';
  440. box.style.height = height + 'px';
  441. box.style.left = left + 'px';
  442. } else if (className == 'box4') {
  443. // 右下角
  444. let width = oldWidth + (oEv.clientX - oldX);
  445. const maxWidth = contentBoxWidth.value - oldLeft;
  446. let height = oldHeight + (oEv.clientY - oldY);
  447. const maxHeight = contentBoxHeight.value - oldTop;
  448. if (width < minWidth) {
  449. width = minWidth;
  450. }
  451. if (width > maxWidth) {
  452. width = maxWidth;
  453. }
  454. if (height < minHeight) {
  455. height = minHeight;
  456. }
  457. if (height > maxHeight) {
  458. height = maxHeight;
  459. }
  460. box.style.width = width + 'px';
  461. box.style.height = height + 'px';
  462. }
  463. dragBoxArr[index].left = box.offsetLeft;
  464. dragBoxArr[index].top = box.offsetTop;
  465. dragBoxArr[index].width = box.offsetWidth;
  466. dragBoxArr[index].height = box.offsetHeight;
  467. dragBoxArr[index].unit = 'px';
  468. };
  469. // 鼠标抬起时
  470. document.onmouseup = function () {
  471. document.onmousemove = null;
  472. document.onmouseup = null;
  473. };
  474. };
  475. const show = () => {
  476. // 每次打开时赋值
  477. if (!value.value.imageUrl) {
  478. ElMessage({
  479. type: 'warning',
  480. message: '请上传图片'
  481. });
  482. return;
  483. }
  484. // 计算图片比例
  485. imgRatio.value = value.value.imgHeight / value.value.imgWidth;
  486. // 根据图片比例,调整图片高度
  487. contentBoxHeight.value = Math.floor(contentBoxWidth.value * imgRatio.value);
  488. areaWidth.value = Math.floor(areaRadio.value * contentBoxHeight.value);
  489. areaHeight.value = areaWidth.value;
  490. areaNum.value = Math.floor(contentBoxWidth.value / areaWidth.value);
  491. if (Object.keys(value.value.heatMapData).length) {
  492. dragBoxArr.splice(0, dragBoxArr.length, ...value.value.heatMapData);
  493. } else {
  494. dragBoxArr.splice(0, dragBoxArr.length);
  495. addArea();
  496. }
  497. showDialog.value = true;
  498. };
  499. const save = () => {
  500. let isOk = true;
  501. for (let i = 0; i < dragBoxArr.length; i++) {
  502. if (!dragBoxArr[i].link) {
  503. ElMessage({
  504. type: 'warning',
  505. message: '请选择热区' + (i + 1) + '的链接地址'
  506. });
  507. isOk = false;
  508. break;
  509. }
  510. }
  511. if (!isOk) return;
  512. dragBoxArr.forEach((item: any, index: number) => {
  513. const box: any = document.getElementById('box_' + index);
  514. item.width = Number(((box.offsetWidth / contentBoxWidth.value) * 100).toFixed(2));
  515. item.height = Number(((box.offsetHeight / contentBoxHeight.value) * 100).toFixed(2));
  516. item.left = Number(((box.offsetLeft / contentBoxWidth.value) * 100).toFixed(2));
  517. item.top = Number(((box.offsetTop / contentBoxHeight.value) * 100).toFixed(2));
  518. item.unit = '%';
  519. });
  520. value.value.heatMapData = deepClone(dragBoxArr);
  521. showDialog.value = false;
  522. };
  523. defineExpose({
  524. showDialog
  525. });
  526. </script>
  527. <style lang="scss" scoped>
  528. .area-box {
  529. background-color: rgba(255, 255, 255, 0.7);
  530. }
  531. .hot-area-img-wrap {
  532. // width: 1200px;
  533. background-size: 100%;
  534. }
  535. .box1,
  536. .box2,
  537. .box3,
  538. .box4 {
  539. width: 10px;
  540. height: 10px;
  541. background-color: #fff;
  542. position: absolute;
  543. border-radius: 50%;
  544. border: 1px solid #333;
  545. }
  546. .box1 {
  547. top: -5px;
  548. left: -5px;
  549. cursor: nw-resize;
  550. }
  551. .box2 {
  552. top: -5px;
  553. right: -5px;
  554. cursor: ne-resize;
  555. }
  556. .box3 {
  557. left: -5px;
  558. bottom: -5px;
  559. cursor: sw-resize;
  560. }
  561. .box4 {
  562. bottom: -5px;
  563. right: -5px;
  564. cursor: se-resize;
  565. }
  566. </style>