CameraViewSetting.vue 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. <template>
  2. <div style="position: relative">
  3. <div class="toolbarWrapper">
  4. <!-- <ViewWindowSetting v-model="viewType" @update:model-value="handleUpdateViewType" /> -->
  5. <!-- <el-tooltip content="全屏">
  6. <el-icon class="el-input__icon" :size="18" style="margin-left: 10px; margin-right: 10px">
  7. <FullscreenExitOutlined role="full" @click="enterFullscreen" />
  8. </el-icon>
  9. </el-tooltip> -->
  10. <!-- <RenderSwitch />
  11. <FenceAppSetting /> -->
  12. </div>
  13. <div class="videoAlgoListWrapper">
  14. <div class="cameraViewSettingWrapper" :style="{ width: domWidth + 'px', height: domHeight + 'px' }">
  15. <div class="fenceEditorWrapper" v-if="showFenceTool" key="cameraDetailStore.cameraId">
  16. <FenceEditor
  17. ref="fenceEditorRef"
  18. :dom-width="domWidth"
  19. :canvas-size="{ width: canvasWidth, height: canvasHeight }"
  20. :line-points="fenceStore.allFences"
  21. :fence-id="fenceStore.currentFenceId"
  22. @save="handleSaveFenceToLocal"
  23. @select="handleSelectFencePolygon"
  24. />
  25. </div>
  26. <div class="cameraVideo">
  27. <CameraLiveVideo />
  28. </div>
  29. </div>
  30. <div> <AlgoCanSelect :selected-ids="cameraAlgoIds" @select="handleApplyAlgo" /></div>
  31. </div>
  32. <div
  33. class="presetAddWrapper"
  34. :class="{ hidePresetControlCls: showFenceTool }"
  35. v-if="!!cameraDetailStore.detail?.isPtz"
  36. >
  37. <CameraViewScale />
  38. <CameraDirectionControl />
  39. <ElButton type="primary" @click="handleAddPreset" size="small" style="margin-top: 20px; width: 100px"
  40. >添加预置位</ElButton
  41. >
  42. <AddPresetModal v-if="addPresetModalVisible" @close="handleClose" @ok="handleAddPresetOk" />
  43. </div>
  44. </div>
  45. <div class="presetWrapper" :style="{ display: showFenceTool ? 'block' : 'none' }">
  46. <FenceToolbar
  47. :is-edit="showFenceTool"
  48. @remove="handleRemove"
  49. @toggle-range="toggleRange"
  50. @select="handleSelectFenceList"
  51. @toggle-fence-status="paramsSettingFn.toggleFenceStatus"
  52. @save="handleSaveFenceToServer"
  53. @cancel="handleCancelFenceEdit"
  54. />
  55. </div>
  56. <div class="cameraParamsSettingWrapper">
  57. <div class="algorithmsSetting"> <AlgorithmsSetting /> </div>
  58. </div>
  59. </template>
  60. <script lang="ts" setup>
  61. import { computed, ref } from 'vue';
  62. import FenceToolbar from '../FenceToolbar/FenceToolbar.vue';
  63. import FenceEditor from '../FenceEditorV2/FenceEditor.vue';
  64. import CameraLiveVideo from '../CameraLiveVideo/CameraLiveVideo.vue';
  65. import useFenceStore from '../../store/useFenceStore';
  66. import AddPresetModal from '../AddPresetModal/AddPresetModal.vue';
  67. import usePresetListStore from '../../store/usePresetListStore';
  68. import useCameraDetailStore from '../../store/useCameraDetailStore';
  69. import useCameraAlgoStore from '../../store/useCameraAlgoStore';
  70. import AlgorithmsSetting from '../AlgorithmsSetting/AlgorithmsSetting.vue';
  71. import { ElMessage } from 'element-plus';
  72. import CameraDirectionControl from '../CameraDirectionControl/CameraDirectionControl.vue';
  73. import CameraViewScale from './CameraViewScale.vue';
  74. import { canvasHeight, canvasWidth, domHeight, domWidth } from './constants';
  75. import { createCameraAlgoApi, updateCameraAlgoApi } from '@/api/camera/camera-preview';
  76. import { RegionJudge } from '../FenceToolbar/constants';
  77. import AlgoCanSelect from '../AlgoCanSelect/AlgoCanSelect.vue';
  78. import { FencePolygonPoints } from '../FenceEditorV2/types';
  79. import useParamsSettingFn from '../../hooks/useParamsSettingFn';
  80. const emits = defineEmits<{
  81. (e: 'changeTreeRender', render: number | string): unknown;
  82. }>();
  83. const fenceEditorRef = ref<typeof FenceEditor | null>(null);
  84. const paramsSettingFn = useParamsSettingFn();
  85. const fenceStore = useFenceStore();
  86. const presetStore = usePresetListStore();
  87. const cameraDetailStore = useCameraDetailStore();
  88. const cameraAlgoStore = useCameraAlgoStore();
  89. const { getCameraAlgoList } = cameraAlgoStore;
  90. const addPresetModalVisible = ref(false);
  91. const cameraAlgoIds = computed(() => {
  92. return cameraAlgoStore.cameraAlgoList?.map((item) => item.algoId) || [];
  93. });
  94. const handleClose = () => {
  95. addPresetModalVisible.value = false;
  96. };
  97. const handleAddPresetOk = () => {
  98. presetStore.getPresetList(cameraDetailStore.cameraId);
  99. handleClose();
  100. };
  101. const handleRemove = () => {
  102. fenceEditorRef.value?.remove();
  103. };
  104. /** 从图中选中电子围栏多边形 */
  105. const handleSelectFencePolygon = (nextFenceId: number) => {
  106. fenceStore.currentFenceId = nextFenceId;
  107. };
  108. // 选中电子围栏列表时
  109. const handleSelectFenceList = (nextFenceId: number) => {
  110. fenceStore.currentFenceId = nextFenceId;
  111. };
  112. const handleSaveFenceToServer = () => {
  113. paramsSettingFn.saveFenceToServer();
  114. };
  115. const handleCancelFenceEdit = () => {
  116. fenceStore.confirmExitFence().then(() => {
  117. fenceStore.reset();
  118. fenceStore.showFenceTool = false;
  119. });
  120. };
  121. /** 将数据保存到前端本地 */
  122. const handleSaveFenceToLocal = (data: { fenceId?: number; polygon: FencePolygonPoints }) => {
  123. console.log('提交的fenceId', data);
  124. const { fenceId, polygon } = data;
  125. const cameraId = cameraDetailStore.cameraId;
  126. const algoId = cameraAlgoStore.selectedAlgoId;
  127. const presetToken = presetStore.currentPresetToken;
  128. if (!cameraId) {
  129. ElMessage.error('未选中相机');
  130. return;
  131. }
  132. if (!algoId) {
  133. ElMessage.error('未选中算法');
  134. return;
  135. }
  136. if (!presetToken) {
  137. ElMessage.error('未选中预置位');
  138. return;
  139. }
  140. if (!fenceId) {
  141. // 不存在的话,就新建电子围栏
  142. paramsSettingFn.createFence(polygon);
  143. } else {
  144. // 否则修改电子围栏
  145. paramsSettingFn.editFence({ polygon, id: fenceId });
  146. }
  147. };
  148. const toggleRange = () => {
  149. const selectedAlgoDetail = cameraAlgoStore.selectedAlgoDetail;
  150. const cameraId = cameraDetailStore.cameraId;
  151. const extraStr = selectedAlgoDetail.extra;
  152. const extraJSON = JSON.parse(extraStr);
  153. const nextRegionJudge =
  154. extraJSON.inferParams?.[0]?.regionJudge === RegionJudge.out ? RegionJudge.in : RegionJudge.out;
  155. extraJSON.inferParams[0].regionJudge = nextRegionJudge;
  156. const newParam = {
  157. cameraId: cameraId,
  158. algoId: selectedAlgoDetail.algoId,
  159. extra: JSON.stringify(extraJSON),
  160. id: selectedAlgoDetail.id!,
  161. };
  162. updateCameraAlgoApi(newParam).then(() => {
  163. ElMessage.success('修改成功');
  164. getCameraAlgoList(cameraId);
  165. });
  166. };
  167. const showFenceTool = computed(() => {
  168. return fenceStore.showFenceTool;
  169. });
  170. const handleAddPreset = () => {
  171. addPresetModalVisible.value = true;
  172. };
  173. const handleApplyAlgo = (id: number) => {
  174. createCameraAlgoApi({
  175. algoIds: [id],
  176. cameraId: cameraDetailStore.cameraId,
  177. }).then((res) => {
  178. getCameraAlgoList(cameraDetailStore.cameraId);
  179. ElMessage.success('添加成功,开启后算法生效');
  180. });
  181. };
  182. </script>
  183. <style scoped>
  184. .cameraViewSettingWrapper {
  185. position: relative;
  186. flex-shrink: 0;
  187. flex-grow: 0;
  188. /* border: 1px solid #ccc; */
  189. }
  190. .cameraViewOverflow {
  191. overflow: hidden;
  192. position: relative;
  193. }
  194. .cameraVideo {
  195. position: absolute;
  196. top: 0;
  197. left: 0;
  198. z-index: 8;
  199. background: #ccc;
  200. width: 100%;
  201. height: 100%;
  202. }
  203. .toolbarWrapper {
  204. display: flex;
  205. align-items: center;
  206. /* margin-left: 25px; */
  207. position: relative;
  208. }
  209. .presetAddWrapper {
  210. position: absolute;
  211. bottom: 50px;
  212. right: 280px;
  213. flex-direction: column;
  214. display: flex;
  215. align-items: center;
  216. z-index: 10;
  217. }
  218. .cameraParamsSettingWrapper {
  219. display: flex;
  220. margin-top: 10px;
  221. }
  222. .algorithmsSetting {
  223. flex: 1;
  224. min-height: 300px;
  225. /* margin-left: 15px; */
  226. /* border-left: 1px solid #ccc; */
  227. /* padding-left: 15px; */
  228. }
  229. .cameraParamsSetting {
  230. flex-basis: 330px;
  231. flex-shrink: 0;
  232. }
  233. .hidePresetControlCls {
  234. display: none;
  235. }
  236. .fenceEditorWrapper {
  237. position: relative;
  238. z-index: 9;
  239. }
  240. .presetWrapper {
  241. position: absolute;
  242. right: 0;
  243. top: 0;
  244. width: 260px;
  245. height: 540px;
  246. box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.1);
  247. background: #fff;
  248. /* width: 962px; */
  249. /* padding: 20px;
  250. padding-left: 15px;
  251. border-bottom: 1px solid #ccc;
  252. padding-bottom: 10px;
  253. margin-bottom: 15px;
  254. display: flex;
  255. justify-content: space-between; */
  256. transform: scale(1);
  257. }
  258. .videoAlgoListWrapper {
  259. display: flex;
  260. }
  261. </style>