index.vue 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268
  1. <template>
  2. <div class="gis-layout">
  3. <EasyMapComponent
  4. class="map"
  5. @easyMapLoad="mapLoad"
  6. />
  7. <div class="gis-menu">
  8. <img class="gis-menu-bottom" src="@/assets/images/gis-layout/gis-layout-menu_bottom.png" alt=""/>
  9. <template v-for="item in menuCpt">
  10. <div class="gis-menu-item __hover" :class="{active: $route.name === item.name, max: String(item.meta.title).length >5}" @click="$router.push({name: item.name})">
  11. {{item.meta.title}}
  12. </div>
  13. </template>
  14. </div>
  15. <div class="gis-tools">
  16. <div class="gt-search __box-shadow">
  17. <el-autocomplete
  18. ref="ref_search"
  19. v-model="searchInput"
  20. :fetch-suggestions="searchHandleMapSearch"
  21. :popper-append-to-body="false"
  22. clearable
  23. :disabled="true"
  24. :debounce="800"
  25. placeholder="请输入关键字进行搜索"
  26. @select="searchToMapLocation"
  27. >
  28. <template #default="{ item }">
  29. <div class="search-item __hover">
  30. <img :src="item.icon"/>
  31. <div class="name">{{item.name}}</div>
  32. </div>
  33. </template>
  34. </el-autocomplete>
  35. <div class="search-icon __hover" @click="ref_search.focus()">
  36. <SvgIcon name="search" color="#ffffff"/>
  37. </div>
  38. </div>
  39. <div class="gt-tools __box-shadow">
  40. <template v-for="(item, index) in ToolsMapper">
  41. <div class="tools-line" v-if="index > 0"/>
  42. <div class="tools-item __hover" :class="{active: toolsType === item.value, disabled: item.disabled}" @click="item.disabled ? undefined : toolsHandleClick(item)">
  43. {{item.label}}
  44. </div>
  45. </template>
  46. </div>
  47. <div class="gt-tools-component" v-if="toolsType && toolsType !== 'clear' && toolsCom">
  48. <Component :is="toolsCom" :map="map" :mapFunc="mapFunc" v-model:transfer="toolsParams[toolsType]" @cancel="toolsType = ''"/>
  49. </div>
  50. </div>
  51. <div class="gis-content">
  52. <RouterViewCom/>
  53. </div>
  54. <VideoPlayKedaCom v-if="$store.state.gis.videoParams.show" v-model:layout="videoLayout" :form="$store.state.gis.videoParams" @close="$store.commit('gis/SET_VIDEO_PARAMS', {show: false})"/>
  55. <div class="mockButtons">
  56. <el-button @click="mockSB1">模拟设备1</el-button>
  57. <el-button @click="mockSB2">模拟设备2</el-button><br/>
  58. <el-button @click="mockJQ1">模拟景区1</el-button><br/>
  59. <el-button @click="mockLG1">模拟旅馆1</el-button><br/>
  60. <el-button @click="mockCZW1">模拟出租屋1</el-button><br/>
  61. <el-button @click="mockHCZ1">模拟火车站1</el-button>
  62. </div>
  63. </div>
  64. <div ref="ref_qyDom" class="qy-info" :class="`qy--info-${qyParams.qyInfo.tab}`">
  65. <div class="qy-bg-icon qy-bg-icon-1"/>
  66. <div class="qy-bg-icon qy-bg-icon-2"/>
  67. <div class="qy-bg-icon qy-bg-icon-3"/>
  68. <div class="qy-bg-icon qy-bg-icon-4"/>
  69. <div class="qy-main">
  70. <div class="qy-main-head">
  71. <div class="qy-main-head-tips">【企业】</div>
  72. <div class="qy-main-head-name">{{ qyParams.qyInfo.name }}</div>
  73. <SvgIcon class="__hover" name="close_4" size="14" color="#8FFFFF" @click="onCloseQy"/>
  74. </div>
  75. <div class="qy-main-tab">
  76. <template v-for="item in [
  77. {label: '基本信息', value: '1', disabled: false},
  78. {label: '税收信息', value: '2', disabled: true},
  79. {label: '运输车辆', value: '3', disabled: true},
  80. {label: '能耗消息', value: '4', disabled: true},
  81. {label: '周边设备', value: '5', disabled: false},
  82. ]">
  83. <div class="qy-main-tab-item __hover" :class="{active: item.value === qyParams.qyInfo.tab, disabled: item.disabled}" @click="item.disabled ? undefined : qyParams.qyInfo.tab = item.value">{{item.label}}</div>
  84. </template>
  85. </div>
  86. <div v-if="qyParams.qyInfo.tab === '1'" class="qy-main-content-1">
  87. <div>企业名称:{{qyParams.qyInfo[qyParams.qyInfo.tab].name}}</div>
  88. <div>企业法人:{{qyParams.qyInfo[qyParams.qyInfo.tab].people}}</div>
  89. <div>统一社会信用代码:{{qyParams.qyInfo[qyParams.qyInfo.tab].number}}</div>
  90. <div>经营地址:{{qyParams.qyInfo[qyParams.qyInfo.tab].address}}</div>
  91. </div>
  92. <div v-else-if="qyParams.qyInfo.tab === '5'" class="qy-main-content-5">
  93. <div class="qy-main-content-5-radius">
  94. 周边范围:
  95. <div class="radius-min __hover" @click="qyParams.qyInfo[qyParams.qyInfo.tab].radius > 1 ? (qyParams.qyInfo[qyParams.qyInfo.tab].radius--) : undefined">-</div>
  96. <CusFormColumn
  97. link="number"
  98. label=""
  99. :min="1"
  100. :max="60"
  101. :clearable="false"
  102. v-model:param="qyParams.qyInfo[qyParams.qyInfo.tab].radius"
  103. @blur="handleRangeBlur"/>
  104. <div class="radius-max __hover" @click="qyParams.qyInfo[qyParams.qyInfo.tab].radius < 60 ? (qyParams.qyInfo[qyParams.qyInfo.tab].radius++) : undefined">+</div>
  105. km
  106. <div class="submit __hover" @click="onRadiusSubmit">确定</div>
  107. <div class="reset __hover" @click="onRadiusReset">重置</div>
  108. </div>
  109. <div class="qy-main-content-5-table" :style="`height: ${25 + (qyParams.qyInfo[qyParams.qyInfo.tab].tableData.length > 5 ? 5 * 25 : qyParams.qyInfo[qyParams.qyInfo.tab].tableData.length * 25)}px;`" v-loading="qyParams.qyInfo[qyParams.qyInfo.tab].loading" element-loading-background="rgba(0, 0, 0, 0.3)">
  110. <el-auto-resizer>
  111. <template #default="{ height, width }">
  112. <V2Table
  113. :width="width"
  114. :height="height"
  115. :data="qyParams.qyInfo[qyParams.qyInfo.tab].tableData"
  116. :center="qyParams.qyInfo['5'].center"
  117. />
  118. <!-- <el-table-v2-->
  119. <!-- class="__gis-overlay_table-v2"-->
  120. <!-- :columns="qyParams.qyInfo[qyParams.qyInfo.tab].tableHead"-->
  121. <!-- :data="qyParams.qyInfo[qyParams.qyInfo.tab].tableData"-->
  122. <!-- :width="width"-->
  123. <!-- :height="height"-->
  124. <!-- fixed-->
  125. <!-- :row-height="25"-->
  126. <!-- :header-height="25"-->
  127. <!-- >-->
  128. <!-- <template #empty></template>-->
  129. <!-- </el-table-v2>-->
  130. </template>
  131. </el-auto-resizer>
  132. </div>
  133. </div>
  134. </div>
  135. </div>
  136. <div ref="ref_sbDom" class="sb-info">
  137. <div class="sb-info-head">
  138. <SvgIcon class="__hover" name="tips" size="14" color="#8FFFFF"/>设备
  139. </div>
  140. <div class="sb-info-close __hover" @click="onCloseSb">
  141. <img src="@/components/easyMap/images/close.png" alt=""/>
  142. </div>
  143. <div class="sb-main">
  144. <div class="sb-item">
  145. <div class="sb-item-label">名称:</div>
  146. <div class="sb-item-value">{{qyParams.sbInfo?.name}}</div>
  147. </div>
  148. <div class="sb-item">
  149. <div class="sb-item-label">状态:</div>
  150. <div class="sb-item-value">{{qyParams.sbInfo?.online === '0' ? '在线' : '离线'}}</div>
  151. </div>
  152. <div class="play-button __hover" @click="showVideo = true">视频调阅</div>
  153. </div>
  154. </div>
  155. <GisDefaultDom ref="ref_gisDefault"/>
  156. </template>
  157. <script lang="ts">
  158. import {
  159. defineComponent,
  160. computed,
  161. onMounted,
  162. ref,
  163. reactive,
  164. watch,
  165. getCurrentInstance,
  166. ComponentInternalInstance,
  167. toRefs,
  168. nextTick,
  169. markRaw
  170. } from 'vue'
  171. import {useStore} from 'vuex'
  172. import {useRouter, useRoute} from 'vue-router'
  173. import {ElMessage, ElMessageBox} from "element-plus";
  174. import RouterViewCom from '@/layout/router-view.vue'
  175. import ElementCom from './tools/element.vue'
  176. import SelectCom from './tools/select.vue'
  177. import AnalysisCom from './tools/analysis.vue'
  178. import ToolCom from './tools/tool.vue'
  179. import PositionCom from './tools/position.vue'
  180. import BaseCom from './tools/base.vue'
  181. import ExampleCom from './tools/example.vue'
  182. import * as source from "ol/source";
  183. import * as layer from "ol/layer";
  184. import * as style from "ol/style";
  185. import * as format from "ol/format";
  186. import QyStyle from '../map-info/style/qy'
  187. import SbStyle from '../map-info/style/sb'
  188. import CommonStyle from '../map-info/style/common'
  189. import * as ol from "ol";
  190. import { v4 } from "uuid";
  191. import * as proj from "ol/proj";
  192. import * as turf from '@turf/turf'
  193. import * as geom from 'ol/geom';
  194. import VideoPlayKedaCom from "@/views/gis/business/common/VideoPlayKeda.vue";
  195. import V2Table from "./v2-table.vue";
  196. import {deviceQuery, enterpriseQuery} from "@/api/modules/enterprise";
  197. import {clearLocationDom} from '@/components/easyMap/func/location'
  198. import {clearMeasureDom} from '@/components/easyMap/func/measure'
  199. import GisDefaultDom from '../map-info/overlay/default/index.vue'
  200. export default defineComponent({
  201. name: '',
  202. components: {
  203. RouterViewCom,
  204. ElementCom,
  205. SelectCom,
  206. AnalysisCom,
  207. ToolCom,
  208. PositionCom,
  209. BaseCom,
  210. ExampleCom,
  211. VideoPlayKedaCom,
  212. V2Table,
  213. GisDefaultDom
  214. },
  215. props: {},
  216. setup(props, {emit}) {
  217. const store = useStore();
  218. const router = useRouter();
  219. const route = useRoute();
  220. const that = (getCurrentInstance() as ComponentInternalInstance).appContext.config.globalProperties
  221. const state = reactive({
  222. map: <any>null,
  223. mapFunc: <any>null,
  224. searchInput: '',
  225. toolsType: '',
  226. toolsCom: null,
  227. toolsParams: {
  228. element: null,
  229. position: null
  230. },
  231. qyParams: {
  232. layer: <any>null,
  233. source: <any>null,
  234. tempFeature: <any>null,
  235. overlay: <any>null,
  236. qyInfo: <any>{},
  237. analysisLayer: <any>null,
  238. analysisSource: <any>null,
  239. analysisCircle: <any>null,
  240. tempSbFeature: <any>null,
  241. sbOverlay: <any>null,
  242. sbInfo: <any>{
  243. name: '505县道新安村路口1-枪机-0110580',
  244. code: '46044123124125125',
  245. },
  246. },
  247. videoLayout: {
  248. width: 640,
  249. height: 366,
  250. left: 1200,
  251. top: 460
  252. },
  253. showVideo: false
  254. })
  255. const ToolsMapper = [
  256. {label: '图层', value: 'element', com: ElementCom, disabled: true},
  257. {label: '框选', value: 'select', com: SelectCom, disabled: true},
  258. {label: '周边分析', value: 'analysis', com: AnalysisCom, disabled: true},
  259. {label: '清空图层', value: 'clear', com: undefined},
  260. {label: '工具', value: 'tool', com: ToolCom},
  261. {label: '定位', value: 'position', com: PositionCom},
  262. {label: '底图', value: 'base', com: BaseCom},
  263. {label: '图例', value: 'example', com: ExampleCom},
  264. ]
  265. const ref_search = ref()
  266. const ref_gisDefault = ref()
  267. const mapLoad = (map, func) => {
  268. state.map = map
  269. store.dispatch('gis/LOAD_GIS_MAP', {
  270. map: state.map,
  271. defaultDom: ref_gisDefault.value
  272. })
  273. state.mapFunc = func
  274. state.map.on('singleclick', e => {
  275. let flag = false
  276. map.forEachFeatureAtPixel(e.pixel, (f) => {
  277. if (!flag && f.get('featureType')) {
  278. flag = true
  279. if (f.get('featureType') === 'qy') { // 企业
  280. // 恢复上一个要素的样式
  281. if (f.getId() !== state.qyParams.tempFeature?.getId()) {
  282. state.qyParams.tempFeature?.get('resetStyle')?.()
  283. state.qyParams.analysisSource?.clear()
  284. // 新的要素
  285. if (f.get('isAnalysis')) {
  286. f.setStyle(f.get('analysisActiveStyle'))
  287. } else {
  288. f.setStyle(f.get('activeStyle'))
  289. }
  290. state.qyParams.qyInfo = JSON.parse(JSON.stringify(f.get('info')))
  291. store.dispatch('gis/LOAD_ACTIVE_QY_ID', f.getId())
  292. // 备份新的要素
  293. state.qyParams.tempFeature = f
  294. }
  295. state.qyParams.overlay.setPosition(f.getGeometry().getCoordinates())
  296. } else if (f.get('featureType') === 'sb') { // 设备
  297. // 恢复上一个要素的样式
  298. if (f.getId() !== state.qyParams.tempSbFeature?.getId()) {
  299. state.qyParams.tempSbFeature?.get('resetStyle')?.()
  300. // 新的要素
  301. if (f.get('isAnalysis')) {
  302. f.setStyle(f.get('analysisActiveStyle'))
  303. } else {
  304. f.setStyle(f.get('activeStyle'))
  305. }
  306. state.qyParams.sbInfo = JSON.parse(JSON.stringify(f.get('info')))
  307. state.qyParams.sbOverlay.setPosition(f.getGeometry().getCoordinates())
  308. // 备份新的要素
  309. state.qyParams.tempSbFeature = f
  310. }
  311. state.qyParams.overlay.setPosition(undefined)
  312. }
  313. }
  314. }, {
  315. hitTolerance: 0,
  316. });
  317. })
  318. initQYLayer()
  319. }
  320. const menuCpt = computed(() => {
  321. return router.options.routes.filter(v => v.name === store.state.gis.menuRootName)[0].children?.filter(v => !v.meta.noMenu)
  322. })
  323. const searchHandleMapSearch = (queryString: string, cb: (arg: any) => void) => {
  324. if (queryString.trim()) {
  325. const arr = [
  326. {name: 123},
  327. {name: 123},
  328. {name: 123},
  329. {name: 123},
  330. {name: 123},
  331. {name: 123},
  332. ]
  333. cb(arr)
  334. } else {
  335. cb([])
  336. }
  337. }
  338. const searchToMapLocation = (val) => {
  339. state.searchInput = val.name
  340. // if (val.source === 'element') {
  341. // state.elementFilter.forEach(l => {
  342. // l.list.forEach(v => {
  343. // if (v.value === val.elementType) {
  344. // v.active = true
  345. // }
  346. // })
  347. // })
  348. // }
  349. // positionSwitchGeom(val.geomType, val.coordinates, true, val.source)
  350. }
  351. const toolsHandleClick = (item) => {
  352. if (item.value === 'clear') {
  353. // 工具-标绘'layerName', 'toolDrawViewsLayer'
  354. state.map.getLayers().getArray().filter(v => v.get('layerName') === 'toolDrawViewsLayer')?.[0]?.getSource()?.clear()
  355. state.map.getOverlayById('toolOverlay')?.setPosition(undefined)
  356. // 工具-测量'layerName', 'measureLayer'
  357. state.map.getLayers().getArray().filter(v => v.get('layerName') === 'measureLayer')?.[0]?.getSource()?.clear()
  358. clearMeasureDom(state.map)
  359. // 定位'layerName', 'positionLayer'
  360. state.map.getLayers().getArray().filter(v => v.get('layerName') === 'positionLayer')?.[0]?.getSource()?.clear()
  361. clearLocationDom()
  362. } else {
  363. state.toolsCom = markRaw(item.com)
  364. state.toolsType = (state.toolsType === item.value ? '' : item.value)
  365. }
  366. }
  367. const ref_qyDom = ref()
  368. const ref_sbDom = ref()
  369. const initQYLayer = () => {
  370. enterpriseQuery({
  371. "pageNumber":1,
  372. "pageSize":200,
  373. // "entName":null,
  374. // "entType":"加工增值"
  375. }).then((res: any) => {
  376. if (res.resp_code === 0 && res.datas?.length > 0) {
  377. const features: any = []
  378. res.datas.forEach(v => {
  379. try {
  380. const feat: any = new format.WKT().readFeature(`POINT(${v.longitude} ${v.latitude})`)
  381. let type = ''
  382. if (v.qykx === '零关税自用进口生产设备') {
  383. type = 'lgszyjkscsb'
  384. } else if (v.qykx === '加工增值免关税') {
  385. type = 'jgzzmgs'
  386. } else if (v.qykx === '零关税进口原辅料') {
  387. type = 'lgsjkyfl'
  388. }
  389. feat.set('defaultStyle', QyStyle.qyStyle(type))
  390. feat.set('activeStyle', [...CommonStyle.activeStyle(), ...QyStyle.qyStyle(type)])
  391. feat.set('analysisStyle', [...CommonStyle.analysisStyle(), ...QyStyle.qyStyle(type)])
  392. feat.set('analysisActiveStyle', [...CommonStyle.activeStyle(), ...CommonStyle.analysisStyle(), ...QyStyle.qyStyle(type)])
  393. feat.set('isAnalysis', false)
  394. feat.set('resetStyle', () => {
  395. if (feat.get('isAnalysis')) {
  396. feat.setStyle(feat.get('analysisStyle'))
  397. } else {
  398. feat.setStyle(feat.get('defaultStyle'))
  399. }
  400. })
  401. const obj = {
  402. coordinates: feat.getGeometry().getCoordinates(),
  403. tab: '1',
  404. name: v.qymc,
  405. 1: {
  406. name: v.qymc,
  407. people: v.lerep,
  408. number: v.uniscid,
  409. address: v.dom
  410. },
  411. 2: {},
  412. 3: {},
  413. 4: {},
  414. 5: {
  415. radius: 10,
  416. center: feat.getGeometry().getCoordinates(),
  417. tableData: [],
  418. loading: false
  419. },
  420. }
  421. feat.set('info', obj)
  422. feat.set('featureType', 'qy')
  423. feat.setStyle(feat.get('defaultStyle'))
  424. feat.setId(v.id)
  425. feat.set('mockClick', () => {
  426. state.qyParams.tempFeature?.get('resetStyle')?.()
  427. state.qyParams.analysisSource?.clear()
  428. // 新的要素
  429. if (feat.get('isAnalysis')) {
  430. feat.setStyle(feat.get('analysisActiveStyle'))
  431. } else {
  432. feat.setStyle(feat.get('activeStyle'))
  433. }
  434. state.qyParams.qyInfo = JSON.parse(JSON.stringify(feat.get('info')))
  435. // 备份新的要素
  436. state.qyParams.tempFeature = feat
  437. state.qyParams.overlay.setPosition(feat.getGeometry().getCoordinates())
  438. store.dispatch('gis/LOAD_ACTIVE_QY_ID', v.id)
  439. })
  440. feat.set('reset', () => {
  441. onCloseQy()
  442. onCloseSb()
  443. })
  444. features.push(feat)
  445. } catch (e) {
  446. console.error('异常企业:', v)
  447. }
  448. })
  449. state.qyParams.source = new source.Vector({
  450. features: features,
  451. wrapX: false
  452. })
  453. state.qyParams.layer = new layer.VectorImage({
  454. source: state.qyParams.source,
  455. zIndex: 10,
  456. layerName: 'qy'
  457. })
  458. state.map.addLayer(state.qyParams.layer)
  459. // 详情
  460. state.qyParams.overlay = new ol.Overlay({
  461. id: v4(),
  462. element: ref_qyDom.value,
  463. autoPan: false,
  464. offset: [0, -60],
  465. positioning: 'bottom-center',
  466. stopEvent: true,
  467. autoPanAnimation: {
  468. duration: 250
  469. }
  470. })
  471. state.map.addOverlay(state.qyParams.overlay)
  472. // 详情
  473. state.qyParams.sbOverlay = new ol.Overlay({
  474. id: v4(),
  475. element: ref_sbDom.value,
  476. autoPan: false,
  477. offset: [0, -60],
  478. positioning: 'bottom-center',
  479. stopEvent: true,
  480. autoPanAnimation: {
  481. duration: 250
  482. }
  483. })
  484. state.map.addOverlay(state.qyParams.sbOverlay)
  485. }
  486. })
  487. }
  488. const onCloseQy = () => {
  489. state.qyParams.overlay?.setPosition(undefined)
  490. state.qyParams.tempFeature?.get('resetStyle')()
  491. state.qyParams.tempFeature = null
  492. state.qyParams.qyInfo = {}
  493. state.qyParams.analysisSource?.clear()
  494. store.dispatch('gis/LOAD_ACTIVE_QY_ID', null)
  495. }
  496. const onCloseSb = () => {
  497. state.qyParams.sbOverlay?.setPosition(undefined)
  498. state.qyParams.tempSbFeature?.get('resetStyle')()
  499. state.qyParams.tempSbFeature = null
  500. }
  501. const handleRangeBlur = () => {
  502. if (!state.qyParams.qyInfo['5'].radius) {
  503. state.qyParams.qyInfo['5'].radius = 10
  504. }
  505. // setCircle()
  506. }
  507. const setCircle = () => {
  508. const transformProjection = (arr, EPSG, EPSG2) => {
  509. try {
  510. if (EPSG2 && EPSG) {
  511. if (arr && arr.length === 4) {
  512. return proj.transformExtent(arr, EPSG, EPSG2);
  513. } else {
  514. return proj.transform(arr, EPSG, EPSG2);
  515. }
  516. }
  517. return undefined;
  518. } catch (e) {
  519. console.error(e);
  520. }
  521. }
  522. // @ts-ignore
  523. state.qyParams.analysisCircle.getGeometry().setRadius(transformProjection([state.qyParams.qyInfo['5'].radius * 1000, 0], 'EPSG:3857', 'EPSG:4326')[0] - transformProjection([0, 0], 'EPSG:3857', 'EPSG:4326')[0],'XY')
  524. state.qyParams.analysisCircle.getGeometry().setCenter(state.qyParams.qyInfo.coordinates)
  525. }
  526. const onRadiusSubmit = () => {
  527. if (!state.qyParams.analysisLayer) {
  528. state.qyParams.analysisSource = new source.Vector()
  529. state.qyParams.analysisLayer = new layer.Vector({
  530. zIndex: 9,
  531. source: state.qyParams.analysisSource,
  532. style: [
  533. new style.Style({
  534. stroke: new style.Stroke({
  535. color: '#2860F1',
  536. width: 2,
  537. lineDash: [10, 10]
  538. }),
  539. fill: new style.Fill({
  540. color: 'rgba(20, 129, 241, 0.1)',
  541. }),
  542. })
  543. ]
  544. });
  545. state.qyParams.analysisCircle = new ol.Feature({
  546. geometry: new geom.Circle(state.qyParams.qyInfo.coordinates, 0),
  547. })
  548. state.qyParams.analysisSource.addFeature(state.qyParams.analysisCircle)
  549. setCircle()
  550. state.map.addLayer(state.qyParams.analysisLayer)
  551. }
  552. state.qyParams.analysisSource.clear()
  553. state.qyParams.analysisSource.addFeature(state.qyParams.analysisCircle)
  554. setCircle()
  555. state.qyParams.qyInfo['5'].tableData = []
  556. state.qyParams.qyInfo['5'].loading = true
  557. that.$api.deviceQuery({
  558. lon: state.qyParams.qyInfo.coordinates[0],
  559. lat: state.qyParams.qyInfo.coordinates[1],
  560. radius: state.qyParams.qyInfo['5'].radius
  561. }).then((res: any) => {
  562. // console.log(res)
  563. // for (let i = 0; i < 500; i++) {
  564. // state.qyParams.qyInfo['5'].tableData.push({
  565. // name: '505县道新安村路口1-枪机-0110580_' + i,
  566. // code: '46044123124125125',
  567. // status: i % 3 === 0 ? '1' : '0',
  568. // typeName: '公安类',
  569. // type: i % 3 === 0 ? 'galsb' : (i % 3 === 1 ? 'shlsb' : 'mylsb'),
  570. // wkt: `POINT(${that.$util.randomNum(108.738329, 110.912130, 6)} ${that.$util.randomNum(18.154784, 20, 6)})`
  571. // })
  572. // }
  573. if (res.resp_code === 0 && res.datas?.length > 0) {
  574. console.log(res.datas?.length)
  575. const features: any = []
  576. res.datas?.forEach(v => {
  577. try {
  578. const feat: any = new format.WKT().readFeature(`POINT(${v.longitude} ${v.latitude})`)
  579. let type = ''
  580. if (v.type === '公安类') {
  581. type = 'galsb'
  582. } else if (v.type === '社会类') {
  583. type = 'shlsb'
  584. } else if (v.type === '民用类') {
  585. type = 'mylsb'
  586. }
  587. feat.set('defaultStyle', SbStyle.sbStyle(type))
  588. feat.set('activeStyle', [...CommonStyle.activeStyle(), ...SbStyle.sbStyle(type)])
  589. feat.set('analysisStyle', [...CommonStyle.analysisStyle(), ...SbStyle.sbStyle(type)])
  590. feat.set('analysisActiveStyle', [...CommonStyle.activeStyle(), ...CommonStyle.analysisStyle(), ...SbStyle.sbStyle(type)])
  591. feat.set('isAnalysis', true)
  592. feat.set('resetStyle', () => {
  593. if (feat.get('isAnalysis')) {
  594. feat.setStyle(feat.get('analysisStyle'))
  595. } else {
  596. feat.setStyle(feat.get('defaultStyle'))
  597. }
  598. })
  599. feat.setStyle(feat.get('analysisStyle'))
  600. feat.set('featureType', 'sb')
  601. feat.set('info', v)
  602. feat.setId(v.deviceid)
  603. features.push(feat)
  604. state.qyParams.qyInfo['5'].tableData.push(v)
  605. } catch (e) {
  606. console.error('异常设备', v)
  607. }
  608. })
  609. state.qyParams.analysisSource.addFeatures(features)
  610. }
  611. state.qyParams.qyInfo['5'].loading = false
  612. }).catch(() => {
  613. state.qyParams.qyInfo['5'].loading = true
  614. })
  615. }
  616. const onRadiusReset = () => {
  617. state.qyParams.qyInfo['5'].radius = 10
  618. onRadiusSubmit()
  619. }
  620. const mockSB1 = () => {
  621. store.dispatch('gis/LOAD_GIS_PARAMS_DEFAULT', {
  622. type: 'sb',
  623. wkt: 'POINT(110.73667031084902 19.011386491828695)',
  624. id: 1,
  625. info: {
  626. "pn": "2526",
  627. "groupid": "89800003866",
  628. "monitorid": "18678",
  629. "name": "测试通道2526",
  630. "online": "0",
  631. "savestatus": "1",
  632. "ptztype": "3",
  633. "deviceid": "46012003001310000011 aaa",
  634. "areacode": "4.60E+19",
  635. "longitude": "110.455893",
  636. "latitude": "19.89477",
  637. "faultedflag": "0",
  638. "status": "OFF",
  639. "isfront": "363658824",
  640. "type": "公安类",
  641. "civilcode": "46012003"
  642. }
  643. })
  644. }
  645. const mockSB2 = () => {
  646. store.dispatch('gis/LOAD_GIS_PARAMS_DEFAULT', {
  647. type: 'sb',
  648. wkt: 'POINT(110.95227700030215 19.027865984016195)',
  649. id: 1,
  650. info: {
  651. "pn": "2526",
  652. "groupid": "89800003866",
  653. "monitorid": "18678",
  654. "name": "2526测试通道2526测试通道2526测试通道2526测试通道2526测试通道",
  655. "online": "0",
  656. "savestatus": "1",
  657. "ptztype": "3",
  658. "deviceid": "46012003001310000011",
  659. "areacode": "4.60E+19",
  660. "longitude": "110.455893",
  661. "latitude": "19.89477",
  662. "faultedflag": "0",
  663. "status": "OFF",
  664. "isfront": "363658824",
  665. "type": "公安类",
  666. "civilcode": "46012003"
  667. }
  668. })
  669. }
  670. const mockJQ1 = () => {
  671. store.dispatch('gis/LOAD_GIS_PARAMS_DEFAULT', {
  672. type: 'jq',
  673. wkt: 'POINT(110.74277601017481 18.85289817214939)',
  674. id: 1,
  675. info: {
  676. "name": "海南省博物馆",
  677. "address": "在海南省海口市琼山区国兴大道68号线",
  678. "level": "4A",
  679. }
  680. })
  681. }
  682. const mockLG1 = () => {
  683. store.dispatch('gis/LOAD_GIS_PARAMS_DEFAULT', {
  684. type: 'lg',
  685. wkt: 'POINT(110.74277601017481 18.85289817214939)',
  686. id: 1,
  687. info: {
  688. "name": "佳捷连锁酒店(解放西路)",
  689. "address": "海口市龙华区解放西路9号金棕榈商业广场F3",
  690. }
  691. })
  692. }
  693. const mockCZW1 = () => {
  694. store.dispatch('gis/LOAD_GIS_PARAMS_DEFAULT', {
  695. type: 'czw',
  696. wkt: 'POINT(110.74277601017481 18.85289817214939)',
  697. id: 1,
  698. info: {
  699. "name": "大英出租屋",
  700. "address": "海口市龙华区解放西路9号金棕榈商业广场F3",
  701. }
  702. })
  703. }
  704. const mockHCZ1 = () => {
  705. store.dispatch('gis/LOAD_GIS_PARAMS_DEFAULT', {
  706. type: 'hcz',
  707. wkt: 'POINT(110.74277601017481 18.85289817214939)',
  708. id: 1,
  709. info: {
  710. "name": "海口东站",
  711. "address": "海口市龙华区解放西路9号金棕榈商业广场F3",
  712. }
  713. })
  714. }
  715. onMounted(() => {
  716. if (window.cusConfig?.internetAuth) {
  717. if (!sessionStorage.getItem('auth')) {
  718. if(navigator.userAgent.indexOf("Firefox") != -1 || navigator.userAgent.indexOf("Chrome") != -1){
  719. window.location.href = "about:blank";
  720. window.close();
  721. }else{
  722. window.opener = null;
  723. window.open("", "_self");
  724. window.close();
  725. }
  726. }
  727. }
  728. })
  729. return {
  730. ...toRefs(state),
  731. mapLoad,
  732. ToolsMapper,
  733. ref_search,
  734. menuCpt,
  735. searchHandleMapSearch,
  736. searchToMapLocation,
  737. toolsHandleClick,
  738. ref_qyDom,
  739. onCloseQy,
  740. onCloseSb,
  741. handleRangeBlur,
  742. setCircle,
  743. onRadiusSubmit,
  744. onRadiusReset,
  745. ref_sbDom,
  746. ref_gisDefault,
  747. mockSB1,
  748. mockSB2,
  749. mockJQ1,
  750. mockLG1,
  751. mockCZW1,
  752. mockHCZ1,
  753. }
  754. },
  755. })
  756. </script>
  757. <style scoped lang="scss">
  758. .gis-layout {
  759. width: 100%;
  760. height: 100vh;
  761. position: absolute;
  762. top: 0;
  763. left: 0;
  764. z-index: 2;
  765. display: flex;
  766. align-items: center;
  767. justify-content: center;
  768. .map {
  769. z-index: 1;
  770. }
  771. .gis-menu {
  772. $diff: 14px;
  773. $menuBottom: 16px;
  774. position: absolute;
  775. z-index: 2;
  776. bottom: $menuBottom;
  777. display: flex;
  778. justify-content: center;
  779. align-items: center;
  780. &:before, &:after {
  781. content: '';
  782. background-image: url("@/assets/images/gis-layout/gis-layout-menu_side.png");
  783. width: 246px;
  784. height: 39px;
  785. position: absolute;
  786. bottom: -$menuBottom;
  787. }
  788. &:before {
  789. left: calc((#{$diff} + 246px) * -1);
  790. }
  791. &:after {
  792. right: calc((#{$diff} + 246px) * -1);
  793. transform: rotateY(180deg);
  794. }
  795. .gis-menu-bottom {
  796. position: absolute;
  797. height: 9px;
  798. width: calc(100% + 10px + #{$diff} * 2);
  799. bottom: -$menuBottom;
  800. }
  801. .gis-menu-item {
  802. width: 95px;
  803. height: 36px;
  804. background-image: url("@/assets/images/gis-layout/gis-layout-menu_item-min.png");
  805. background-size: 100% 100%;
  806. background-repeat: no-repeat;
  807. display: flex;
  808. align-items: center;
  809. justify-content: center;
  810. font-size: 18px;
  811. font-family: YouSheBiaoTiHei;
  812. font-weight: 400;
  813. color: #60AEFF;
  814. &:not(&:last-child) {
  815. margin-right: 4px;
  816. }
  817. &.active {
  818. color: #FFFFFF;
  819. background-image: url("@/assets/images/gis-layout/gis-layout-menu_item-min_active.png");
  820. }
  821. &.max {
  822. width: 125px;
  823. background-image: url("@/assets/images/gis-layout/gis-layout-menu_item-max.png");
  824. &.active {
  825. background-image: url("@/assets/images/gis-layout/gis-layout-menu_item-max_active.png");
  826. }
  827. }
  828. }
  829. }
  830. .gis-tools {
  831. position: absolute;
  832. z-index: 3;
  833. top: 10px;
  834. right: 10px;
  835. width: 404px;
  836. >div {
  837. box-sizing: border-box;
  838. }
  839. .gt-search {
  840. height: 38px;
  841. width: 100%;
  842. display: flex;
  843. align-items: center;
  844. .search-icon {
  845. width: 54px;
  846. height: 100%;
  847. background-color: #3e8ef7;
  848. display: flex;
  849. align-items: center;
  850. justify-content: center;
  851. }
  852. :deep(.el-autocomplete) {
  853. flex: 1;
  854. height: 100%;
  855. .el-input {
  856. width: 100%;
  857. height: 100%;
  858. .el-input__wrapper {
  859. border-radius: 0;
  860. }
  861. }
  862. }
  863. :deep(.el-autocomplete__popper) {
  864. opacity: 0.9;
  865. background-image: linear-gradient(45deg,transparent 10px,#101D69 10px), linear-gradient(-135deg,transparent 10px,#101D69 10px);
  866. border: none;
  867. .el-popper__arrow::before {
  868. background: #101D69;
  869. border-color: #101D69;
  870. }
  871. .el-autocomplete-suggestion {
  872. .el-scrollbar {
  873. .el-autocomplete-suggestion__wrap {
  874. .el-scrollbar__view {
  875. >li {
  876. &:hover {
  877. background-color: rgba(59,84,172,0.5);
  878. }
  879. .search-item {
  880. display: flex;
  881. align-items: center;
  882. justify-content: flex-start;
  883. >img {
  884. margin-right: 6px;
  885. width: 16px;
  886. height: 16px;
  887. }
  888. .name {
  889. color: #ffffff;
  890. }
  891. }
  892. }
  893. }
  894. }
  895. }
  896. }
  897. }
  898. }
  899. .gt-tools {
  900. width: 100%;
  901. height: 38px;
  902. margin-top: 2px;
  903. background-color: #FFFFFF;
  904. border: 1px solid #C7CFDE;
  905. display: flex;
  906. align-items: center;
  907. justify-content: space-around;
  908. padding: 0 8px;
  909. .tools-item {
  910. font-size: 14px;
  911. font-family: Microsoft YaHei;
  912. font-weight: 400;
  913. color: #AEAEAE;
  914. &.active {
  915. color: #1174DB;
  916. font-weight: bold;
  917. }
  918. &.disabled {
  919. opacity: 0.5;
  920. cursor: not-allowed;
  921. }
  922. }
  923. .tools-line {
  924. width: 1px;
  925. height: 16px;
  926. background: linear-gradient(0deg, rgba(174,174,174,0) 0%, rgba(213,213,213,0.99) 50%, rgba(174,174,174,0) 100%);
  927. }
  928. }
  929. .gt-tools-component {
  930. width: 100%;
  931. margin-top: 2px;
  932. }
  933. }
  934. .gis-content {
  935. z-index: 4;
  936. }
  937. .qy-info {
  938. $bgColor: #2860CE;
  939. $footH: 10px;
  940. min-width: 315px;
  941. min-height: 168px - $footH;
  942. background-color: $bgColor;
  943. position: relative;
  944. display: flex;
  945. justify-content: center;
  946. &:after {
  947. content: '';
  948. position: absolute;
  949. bottom: -$footH;
  950. border-top: $footH solid $bgColor;
  951. border-left: $footH solid transparent;
  952. border-right: $footH solid transparent;
  953. }
  954. .qy-bg-icon {
  955. width: 16px;
  956. height: 16px;
  957. background-image: url("@/views/gis/map-info/qy-dom-icon1.png");
  958. background-repeat: no-repeat;
  959. background-size: 100% 100%;
  960. position: absolute;
  961. z-index: 1;
  962. &.qy-bg-icon-1 {
  963. left: 0;
  964. top: 0;
  965. }
  966. &.qy-bg-icon-2 {
  967. right: 0;
  968. top: 0;
  969. transform: rotate(90deg);
  970. }
  971. &.qy-bg-icon-3 {
  972. right: 0;
  973. bottom: 0;
  974. transform: rotate(180deg);
  975. }
  976. &.qy-bg-icon-4 {
  977. left: 0;
  978. bottom: 0;
  979. transform: rotate(270deg);
  980. }
  981. }
  982. .qy-main {
  983. width: 100%;
  984. height: auto;
  985. z-index: 2;
  986. padding: 12px;
  987. .qy-main-head {
  988. display: flex;
  989. align-items: center;
  990. position: relative;
  991. &:after {
  992. content: '';
  993. position: absolute;
  994. width: 100%;
  995. height: 4px;
  996. bottom: -9px;
  997. background-image: url("@/views/gis/map-info/qy-info-icon2.png");
  998. background-repeat: no-repeat;
  999. }
  1000. .qy-main-head-tips {
  1001. font-size: 10px;
  1002. font-family: Microsoft YaHei;
  1003. font-weight: bold;
  1004. color: #8FFFFF;
  1005. }
  1006. .qy-main-head-name {
  1007. font-size: 14px;
  1008. font-family: Microsoft YaHei;
  1009. font-weight: bold;
  1010. color: #FFFFFF;
  1011. }
  1012. .svg-icon {
  1013. margin-left: auto;
  1014. }
  1015. }
  1016. .qy-main-tab {
  1017. margin: 20px 0 10px 0;
  1018. display: flex;
  1019. align-items: center;
  1020. .qy-main-tab-item {
  1021. font-size: 12px;
  1022. font-family: Microsoft YaHei;
  1023. font-weight: 400;
  1024. color: #CEE6FF;
  1025. height: 16px;
  1026. display: flex;
  1027. align-items: center;
  1028. justify-content: center;
  1029. padding: 0 4px;
  1030. border-radius: 2px;
  1031. background-color: rgba(255, 255, 255, 0.2);
  1032. &.active {
  1033. background-color: #1280F1;
  1034. color: #61FFFF;
  1035. }
  1036. &.disabled {
  1037. cursor: not-allowed;
  1038. opacity: 0.7;
  1039. }
  1040. &:not(:last-child) {
  1041. margin-right: 2px;
  1042. }
  1043. }
  1044. }
  1045. .qy-main-content-1 {
  1046. font-size: 12px;
  1047. font-family: Microsoft YaHei;
  1048. font-weight: 400;
  1049. color: #FFFFFF;
  1050. >div {
  1051. line-height: 18px;
  1052. }
  1053. }
  1054. .qy-main-content-5 {
  1055. .qy-main-content-5-radius {
  1056. display: flex;
  1057. align-items: center;
  1058. font-size: 12px;
  1059. font-family: Microsoft YaHei;
  1060. font-weight: 400;
  1061. color: #FFFFFF;
  1062. .radius-min, .radius-max {
  1063. margin: 0 3px;
  1064. &:hover {
  1065. color: #409EFF;
  1066. }
  1067. }
  1068. :deep(.cus-form-column) {
  1069. max-width: unset;
  1070. width: 44px;
  1071. flex: unset;
  1072. .el-form-item {
  1073. margin: 0;
  1074. .el-form-item__content {
  1075. height: 18px;
  1076. .el-input {
  1077. .el-input__wrapper {
  1078. padding: 0;
  1079. border-radius: 5px;
  1080. background-color: transparent;
  1081. .el-input__inner {
  1082. color: #FFFFFF;
  1083. background-color: transparent;
  1084. height: 100%;
  1085. text-align: center;
  1086. border: 1px solid #ffffff;
  1087. border-radius: 5px;
  1088. &::placeholder {
  1089. font-size: 12px;
  1090. font-family: Microsoft YaHei;
  1091. }
  1092. }
  1093. }
  1094. }
  1095. }
  1096. }
  1097. }
  1098. .submit {
  1099. display: flex;
  1100. align-items: center;
  1101. justify-content: center;
  1102. width: 36px;
  1103. height: 18px;
  1104. background: #8FFFFF;
  1105. border-radius: 4px;
  1106. font-size: 12px;
  1107. font-family: Microsoft YaHei;
  1108. font-weight: 400;
  1109. color: #1174DB;
  1110. margin-left: 10px;
  1111. }
  1112. .reset {
  1113. display: flex;
  1114. align-items: center;
  1115. justify-content: center;
  1116. width: 36px;
  1117. height: 18px;
  1118. border: 1px solid #8FFFFF;
  1119. border-radius: 4px;
  1120. font-size: 12px;
  1121. font-family: Microsoft YaHei;
  1122. font-weight: 400;
  1123. color: #8FFFFF;
  1124. margin-left: 8px;
  1125. }
  1126. }
  1127. .qy-main-content-5-table {
  1128. margin-top: 10px;
  1129. width: 440px;
  1130. :deep(.__gis-overlay_table-v2) {
  1131. .el-table-v2__header-cell{
  1132. justify-content: center;
  1133. &:nth-child(2) {
  1134. color: #00C6FC;
  1135. }
  1136. }
  1137. .el-table-v2__header-cell, .el-table-v2__row-cell {
  1138. width: 60px !important;
  1139. $w1: 60px;
  1140. $w3: 60px;
  1141. $w4: 60px;
  1142. $w5: 60px;
  1143. &:nth-child(1) {
  1144. width: $w1 !important;
  1145. }
  1146. &:nth-child(2) {
  1147. width: calc(100% - #{$w1} - #{$w3} - #{$w4} - #{$w5} - 6px) !important;
  1148. }
  1149. &:nth-child(3) {
  1150. width: $w3 !important;
  1151. }
  1152. &:nth-child(4) {
  1153. width: $w4 !important;
  1154. }
  1155. &:nth-child(5) {
  1156. width: $w5 !important;
  1157. }
  1158. }
  1159. }
  1160. }
  1161. }
  1162. }
  1163. }
  1164. .sb-info {
  1165. $footH: 10px;
  1166. width: 220px;
  1167. background: linear-gradient(180deg, #3874C9 0%, #0043C4 100%);
  1168. border-radius: 0px 4px 4px 4px;
  1169. position: relative;
  1170. display: flex;
  1171. justify-content: center;
  1172. &:after {
  1173. content: '';
  1174. position: absolute;
  1175. bottom: -$footH;
  1176. border-top: $footH solid #0043C4;
  1177. border-left: $footH solid transparent;
  1178. border-right: $footH solid transparent;
  1179. }
  1180. .sb-info-head {
  1181. min-width: 68px;
  1182. height: 18px;
  1183. position: absolute;
  1184. top: -18px;
  1185. left: 0;
  1186. font-size: 12px;
  1187. font-family: PingFang SC;
  1188. font-weight: 500;
  1189. color: #FFFFFF;
  1190. display: flex;
  1191. align-items: center;
  1192. line-height: 8px;
  1193. &:before {
  1194. z-index: -1;
  1195. content: '';
  1196. position: absolute;
  1197. width: 100%;
  1198. height: 100%;
  1199. background: linear-gradient(180deg, #3874C9 0%, #0043C4 100%);
  1200. border-radius: 2px 2px 0 0;/* 设置圆角 */
  1201. transform: perspective(20px)rotateX(4deg);
  1202. /* 镜头距离元素表面的位置为8px,x轴为1.1倍y轴为1.3倍,绕x轴旋转5度 */
  1203. transform-origin: bottom left;
  1204. /* bottom left = left bottom = 0 100% 中心点偏移量*/
  1205. }
  1206. .svg-icon {
  1207. margin: 0 4px 0 6px;
  1208. }
  1209. }
  1210. .sb-info-close {
  1211. position: absolute;
  1212. right: 0;
  1213. top: -16px;
  1214. }
  1215. .sb-main {
  1216. width: 100%;
  1217. height: auto;
  1218. padding: 10px;
  1219. .sb-item {
  1220. display: flex;
  1221. .sb-item-label {
  1222. width: 42px;
  1223. font-size: 14px;
  1224. font-family: PingFang SC;
  1225. font-weight: 600;
  1226. color: #08FFFF;
  1227. line-height: 20px;
  1228. }
  1229. .sb-item-value {
  1230. flex: 1;
  1231. font-size: 14px;
  1232. font-family: PingFang SC;
  1233. font-weight: 400;
  1234. color: #FFFFFF;
  1235. line-height: 20px;
  1236. }
  1237. }
  1238. .play-button {
  1239. width: 76px;
  1240. height: 24px;
  1241. background: #1280F1;
  1242. border-radius: 2px;
  1243. border: 1px solid #4BA0FF;
  1244. display: flex;
  1245. align-items: center;
  1246. justify-content: center;
  1247. font-size: 14px;
  1248. font-family: PingFang SC;
  1249. font-weight: 400;
  1250. color: #FFFFFF;
  1251. margin-left: calc((100% - 76px) / 2);
  1252. margin-top: 10px;
  1253. }
  1254. }
  1255. }
  1256. }
  1257. .mockButtons {
  1258. position: absolute;
  1259. top: 0;
  1260. left: 500px;
  1261. }
  1262. </style>