Header.vue 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. <template>
  2. <header
  3. class="layout-header-box"
  4. mb-10px
  5. color-white
  6. font-bold
  7. flex
  8. flex-items-end
  9. flex-justify-between
  10. px-15px
  11. >
  12. <div class="layout-header-box-address" flex flex-items-center>
  13. <div :key="i" v-for="(btn, i) in btns">
  14. <dv-button :bg="false" @click="open(btn)"
  15. ><Icon :icon="btn.icon" width="2vw" height="2vw" mr-1 />{{ btn.name }}</dv-button
  16. >
  17. </div>
  18. <!-- <i-mdi:address-marker-outline color="#0080ff" width="40" height="40" />
  19. <span class="layout-header-box-address-text" text-25px color="#8ac5ff" v-if="city">
  20. {{ city }}
  21. </span>
  22. <div w-full h-full flex flex-justify-center flex-items-center v-else>
  23. <img src="@/assets/images/loading-icon.gif" alt="" width="40" />
  24. </div> -->
  25. </div>
  26. <span class="layout-header-box-title text-2vw">{{ title }}</span>
  27. <div
  28. class="layout-header-box-right"
  29. flex
  30. flex-justify-between
  31. flex-items-center
  32. color="#8ac5ff"
  33. >
  34. <div class="layout-header-box-right-btn" flex flex-items-center cursor-pointer gap-3>
  35. <div
  36. class="flex justify-center items-center"
  37. :style="{ width: item.w + 'px', height: item.h + 'px' }"
  38. v-for="(item, i) in listComputed"
  39. :key="i"
  40. v-on:[event]="toolsClick(item.type)"
  41. >
  42. <Icon
  43. :class="[item.class]"
  44. :icon="item.iCom"
  45. :width="item.w"
  46. :height="item.h"
  47. color="#8ac5ff"
  48. />
  49. </div>
  50. </div>
  51. <!-- <div
  52. class="layout-header-box-right-hat"
  53. flex
  54. flex-items-center
  55. cursor-pointer
  56. mr-2
  57. v-on:[event]="openModal('aqm')"
  58. >
  59. <Icon icon="lucide:hard-hat" width="2.5vw" height="2.5vw" style="color: #8ac5ff" />
  60. </div> -->
  61. <!-- <div class="layout-header-box-right-switch" flex flex-items-center cursor-pointer>
  62. <svg
  63. xmlns="http://www.w3.org/2000/svg"
  64. v-on:[event]="toAi"
  65. width="3vw"
  66. height="3vw"
  67. viewBox="0 0 24 24"
  68. >
  69. <path
  70. fill="none"
  71. :stroke="ai.color"
  72. stroke-linecap="round"
  73. stroke-linejoin="round"
  74. stroke-width="2"
  75. d="M20 11V9a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v5a2 2 0 0 0 2 2h4m4 5v-4a2 2 0 1 1 4 0v4m-4-2h4m3-4v6"
  76. />
  77. </svg>
  78. </div> -->
  79. <!-- <div
  80. class="layout-header-box-right-compass"
  81. flex
  82. flex-items-center
  83. cursor-pointer
  84. @click="openAlarm"
  85. >
  86. <n-popover trigger="hover" placement="bottom">
  87. <template #trigger>
  88. <Icon icon="line-md:compass-loop" width="20" height="20" style="color: #8ac5ff" />
  89. </template>
  90. <Compass />
  91. </n-popover>
  92. </div> -->
  93. <div class="layout-header-box-right-tq" mx-3>
  94. <Weather />
  95. </div>
  96. <div class="layout-header-box-right-icon screen-full-trigger" flex flex-items-center>
  97. <Icon
  98. icon="akar-icons:reduce"
  99. cursor-pointer
  100. v-if="isFullscreen"
  101. width="20"
  102. height="20"
  103. color="#8ac5ff"
  104. ></Icon>
  105. <Icon
  106. icon="akar-icons:full-screen"
  107. v-else
  108. cursor-pointer
  109. width="20"
  110. height="20"
  111. color="#8ac5ff"
  112. ></Icon>
  113. </div>
  114. </div>
  115. </header>
  116. <pub-modal v-model:showModal="showModal" width="60%" classN="video-show" :title="titleModal">
  117. <template #modal-slot>
  118. <component :is="comN"></component>
  119. </template>
  120. </pub-modal>
  121. </template>
  122. <script setup>
  123. import storage from '@/utils/storage'
  124. import useScreenfull from '@/hooks/useScreenfull'
  125. import SafetyHat from './SafetyHat.vue'
  126. import { Button as DvButton } from '@kjgl77/datav-vue3'
  127. import { useOutsideScreenOperation } from '@/stores/modules/screenOperation.js'
  128. import { useOutsideSystemStore } from '@/stores/modules/system.js'
  129. const useSystem = useOutsideSystemStore()
  130. const useScreenOperation = useOutsideScreenOperation()
  131. const { isFullscreen } = useScreenfull(`.screen-full-target`, `.screen-full-trigger`)
  132. const { API_LY_ADDRESS_GET } = useRequest()
  133. const event = computed(() => useSystem.event)
  134. const router = useRouter()
  135. const title = computed(() => {
  136. return useScreenOperation.title
  137. })
  138. // https://restapi.amap.com/v3/ip?ip=114.247.50.2&output=xml&key=<用户的key>
  139. const ai = reactive({
  140. name: 'AI',
  141. path: 'dropdown1',
  142. color: '#8ac5ff',
  143. iCom: 'uil:refresh',
  144. type: 'dropdown',
  145. options: [
  146. {
  147. label: '不检测',
  148. key: 1,
  149. disabled: useSystem.videoSwitch == 1
  150. },
  151. {
  152. label: 'AI检测',
  153. key: 2,
  154. disabled: useSystem.videoSwitch == 2
  155. }
  156. ],
  157. handleSelect(v, nav) {
  158. useSystem.videoSwitch = v
  159. storage.local.set('v_switch', v)
  160. nav.options = [
  161. {
  162. label: '不检测',
  163. key: 1,
  164. disabled: useSystem.videoSwitch == 1
  165. },
  166. {
  167. label: 'AI检测',
  168. key: 2,
  169. disabled: useSystem.videoSwitch == 2
  170. }
  171. ]
  172. }
  173. })
  174. const route = useRoute()
  175. const state = ref(false)
  176. const workerObj = inject('workerObj')
  177. const btns = [
  178. {
  179. name: '全景态势',
  180. type: 'path',
  181. path: '/video_monitoring/panoramic_situation',
  182. color: '#3299ff',
  183. icon: 'wpf:panorama',
  184. auth: []
  185. },
  186. {
  187. name: '远程回放',
  188. path: '/video_monitoring/remote_playback',
  189. type: 'path',
  190. color: '#3299ff',
  191. icon: 'solar:playback-speed-bold',
  192. auth: ['PlaybackView']
  193. }
  194. // {
  195. // name: '设备维护',
  196. // path: '/video_monitoring/device_management',
  197. // type: 'path',
  198. // color: '#3299ff',
  199. // icon: 'pepicons-pop:gear',
  200. // auth: ['PlaybackView']
  201. // }
  202. ]
  203. const list = shallowRef([
  204. // {
  205. // iCom: 'ant-design:tag-outlined',
  206. // label: '标签过滤',
  207. // color: 'white',
  208. // isPopover: true,
  209. // component: RightBqglBox
  210. // },
  211. {
  212. iCom: 'iconoir:screenshot',
  213. label: '截图',
  214. color: 'white',
  215. type: 'jt',
  216. w: 20,
  217. h: 20
  218. },
  219. {
  220. iCom: 'carbon:video',
  221. label: '录像',
  222. color: 'white',
  223. type: 'lx',
  224. class: '',
  225. w: 25,
  226. h: 25
  227. }
  228. // {
  229. // iCom: 'mdi:video-3d',
  230. // label: '3D缩放',
  231. // },
  232. // {
  233. // iCom: 'ep:set-up',
  234. // label: '码流切换',
  235. // color: 'white'
  236. // }
  237. ])
  238. const listComputed = computed(() => {
  239. return (
  240. route.name == 'RemotePlayback'
  241. ? list.value.filter((v) => !['gl', 'lx', 'jt', 'dropdown'].includes(v.type))
  242. : list.value
  243. ).map((item) => {
  244. if (item.type === 'lx') {
  245. if (state.value) {
  246. item.iCom = 'fad:armrecording'
  247. item.color = 'red'
  248. item.class = 'update-style'
  249. } else {
  250. item.iCom = 'carbon:video'
  251. item.color = 'white'
  252. item.class = ''
  253. }
  254. }
  255. return item
  256. })
  257. })
  258. const toolsClick = (type) => {
  259. switch (type) {
  260. case 'lx':
  261. state.value = !state.value
  262. workerObj.value.WebSocketWork.postMessage({ type: 'lx', lx: state.value })
  263. useSystem.recordingStatus = state.value
  264. break
  265. case 'jt':
  266. workerObj.value.worker.postMessage({ type: 'jt' })
  267. break
  268. }
  269. }
  270. const open = (nav) => {
  271. if (nav.type == 'link') {
  272. window.open(nav.path, '_blank')
  273. } else {
  274. router.push(nav.path)
  275. }
  276. }
  277. const toAi = async () => {
  278. const res = await API_LY_ADDRESS_GET({ name: '鲲鹏云' })
  279. window.open(res, '_blank')
  280. }
  281. const titleModal = ref('')
  282. const showModal = ref(false)
  283. const comN = shallowRef(null)
  284. const openModal = (type) => {
  285. switch (type) {
  286. case 'aqm':
  287. titleModal.value = ''
  288. comN.value = SafetyHat
  289. break
  290. }
  291. showModal.value = true
  292. }
  293. onMounted(() => {
  294. document.oncontextmenu = function (e) {
  295. e.preventDefault()
  296. }
  297. })
  298. </script>
  299. <style scoped lang="scss">
  300. @keyframes showHide {
  301. 0% {
  302. opacity: 0;
  303. }
  304. 100% {
  305. opacity: 1;
  306. }
  307. }
  308. .layout-header-box {
  309. width: 100%;
  310. position: relative;
  311. background: url('@/assets/images/h-bg.png') no-repeat center;
  312. background-size: 100% 100%;
  313. min-height: 5vw;
  314. .update-style {
  315. animation-name: showHide;
  316. animation-duration: 1s;
  317. animation-direction: alternate;
  318. animation-iteration-count: infinite;
  319. animation-timing-function: linear;
  320. }
  321. & > span {
  322. position: absolute;
  323. top: 50%;
  324. left: 50%;
  325. transform: translate(-50%, -50%);
  326. }
  327. :deep(.dv-button) {
  328. width: 12vw;
  329. .dv-button-text {
  330. font-size: 1.5vw;
  331. width: 10vw;
  332. margin-left: -2vw;
  333. margin-bottom: -1vw;
  334. }
  335. .dv-button-text svg {
  336. margin-bottom: -0.5vw;
  337. }
  338. }
  339. &-right-alarm.alarm-tip {
  340. animation: showHide 1s infinite alternate;
  341. }
  342. }
  343. </style>