FenceToolbar.vue 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. <template>
  2. <div class="fenceWrapper">
  3. <div>
  4. <TitleWithLine>电子围栏</TitleWithLine>
  5. <ElSwitch
  6. size="small"
  7. class="fenceSwitchBtn"
  8. v-model="selectedAlgoDetail.electronicFenceBool"
  9. @update:modelValue="handleUpdateFenceStatus"
  10. v-if="fenceStore.allFences.length > 0"
  11. />
  12. </div>
  13. <div class="algoName">
  14. {{ selectedAlgoDetail?.algoInfo?.name }}
  15. </div>
  16. <PresetSelect />
  17. <Description :is-simple="Boolean(!cameraDetailStore.detail?.isPtz)" v-if="fenceStore.allFences.length === 0" />
  18. <div v-if="fenceStore.allFences.length > 0">
  19. <div style="display: flex">
  20. <ElCheckbox label="检测围栏外部" v-model="isFenceRegionOut" @update:modelValue="handleUpdateRegion" />
  21. <ElCheckbox
  22. label="前台画面显示"
  23. v-model="isDisplayFenceInVideo"
  24. @update:modelValue="handleUpdateDisplay"
  25. v-if="!baseProps.isCameraGroup"
  26. />
  27. </div>
  28. <div class="fenceListWrapper">
  29. <FenceNameItem
  30. :active="item.id === fenceStore.currentFenceId"
  31. v-for="item in fenceStore.allFences"
  32. :detail="item"
  33. :key="item.id"
  34. @click="handleSelectFence(item.id)"
  35. @delete="handleDeleteFence"
  36. @edit="handleEditFenceInfo(item)"
  37. />
  38. </div>
  39. <div style="text-align: right">
  40. <ElButton size="small" @click="handleCancelFence">取消</ElButton>
  41. <ElButton type="primary" size="small" @click="handleSaveFence">保存</ElButton>
  42. </div>
  43. </div>
  44. <div>
  45. <EditFenceDialog
  46. v-if="showEditFenceDialog"
  47. @cancel="handleEditCancel"
  48. @submit="handleEditSubmit"
  49. :detail="selectedDetail"
  50. />
  51. </div>
  52. </div>
  53. </template>
  54. <script setup lang="ts">
  55. import { defineEmits, inject, ref, watch } from 'vue';
  56. import { ElMessage, ElSwitch } from 'element-plus';
  57. import useCameraAlgoStore from '../../store/useCameraAlgoStore';
  58. import PresetSelect from '../PresetSelect/PresetSelect.vue';
  59. import FenceNameItem from './FenceNameItem.vue';
  60. import useFenceStore from '../../store/useFenceStore';
  61. import useCameraDetailStore from '../../store/useCameraDetailStore';
  62. import usePresetListStore from '../../store/usePresetListStore';
  63. import EditFenceDialog from './EditFenceDialog.vue';
  64. import { ServerLineInfo } from '../FenceEditor/constants';
  65. import { storeToRefs } from 'pinia';
  66. import { RegionJudge } from './constants';
  67. import { choosePreset, updateFenceDisplayStatus } from '@/api/camera/camera-preview';
  68. import { FenceDisplayStatus } from '@/types/camera/constant';
  69. import useParamsSettingFn from '../../hooks/useParamsSettingFn';
  70. import Description from './Description.vue';
  71. import TitleWithLine from '@/components/TitleWithLine/TitleWithLine.vue';
  72. import { BaseProps } from '../../types';
  73. import { PROVIDE_CONSTANTS } from '../../constants';
  74. const cameraAlgoStore = useCameraAlgoStore();
  75. const fenceStore = useFenceStore();
  76. const cameraDetailStore = useCameraDetailStore();
  77. const presetStore = usePresetListStore();
  78. const baseProps = inject<BaseProps>(PROVIDE_CONSTANTS.baseProps);
  79. const showEditFenceDialog = ref(false);
  80. const selectedDetail = ref<ServerLineInfo | null>(null);
  81. const paramsSettingFn = useParamsSettingFn();
  82. const { selectedAlgoDetail } = storeToRefs(cameraAlgoStore);
  83. const emits = defineEmits<{
  84. (e: 'toggleRange', nextStatus: RegionJudge): unknown;
  85. (e: 'remove'): unknown;
  86. (e: 'cancel'): unknown;
  87. (e: 'save'): unknown;
  88. (e: 'select', fenceId: number): unknown;
  89. /** 切换电子围栏打开关闭状态 */
  90. (e: 'toggleFenceStatus', nextStatus: boolean): unknown;
  91. }>();
  92. const isFenceRegionOut = ref(false);
  93. const isDisplayFenceInVideo = ref(false);
  94. watch(
  95. () => selectedAlgoDetail.value?.regionJudge,
  96. (newVal) => {
  97. isFenceRegionOut.value = newVal === RegionJudge.out;
  98. },
  99. {
  100. immediate: true,
  101. },
  102. );
  103. watch(
  104. () => cameraDetailStore.isDisplayFence,
  105. (isDisplayFence) => {
  106. isDisplayFenceInVideo.value = isDisplayFence;
  107. },
  108. {
  109. immediate: true,
  110. },
  111. );
  112. const handleSaveFence = () => {
  113. emits('save');
  114. };
  115. const handleCancelFence = () => {
  116. emits('cancel');
  117. };
  118. const handleSelectFence = (nextFenceId: number) => {
  119. emits('select', nextFenceId);
  120. };
  121. const handleUpdateRegion = (nextStatus: boolean) => {
  122. emits('toggleRange', nextStatus ? RegionJudge.out : RegionJudge.in);
  123. };
  124. const handleEditFenceInfo = (detail) => {
  125. showEditFenceDialog.value = true;
  126. selectedDetail.value = detail;
  127. };
  128. const handleEditCancel = () => {
  129. showEditFenceDialog.value = false;
  130. selectedDetail.value = null;
  131. };
  132. const handleDeleteFence = (fenceId: number) => {
  133. paramsSettingFn.deleteFence(fenceId);
  134. };
  135. const handleEditSubmit = (data: { label: string; name: string }) => {
  136. const fenceId = selectedDetail.value?.id;
  137. if (!fenceId) return;
  138. paramsSettingFn.editFence({
  139. id: fenceId,
  140. label: data.label,
  141. name: data.name,
  142. });
  143. handleEditCancel();
  144. };
  145. const handleUpdateDisplay = (nextStatus: boolean) => {
  146. const params = {
  147. cameraCode: cameraDetailStore.detail?.code!,
  148. isDisplayFence: nextStatus ? FenceDisplayStatus.enabled : FenceDisplayStatus.disabled,
  149. };
  150. updateFenceDisplayStatus(params);
  151. if (nextStatus) {
  152. // 由于历史原因,需要调用两次接口
  153. const cameraId = cameraDetailStore.cameraId;
  154. const algoId = cameraAlgoStore.selectedAlgoId!;
  155. const presetToken = presetStore.currentPresetToken;
  156. const params = {
  157. algoId,
  158. cameraId,
  159. presetToken,
  160. };
  161. choosePreset(params).then((res) => {
  162. ElMessage.success('修改成功');
  163. });
  164. }
  165. };
  166. const handleUpdateFenceStatus = (nextStatus: boolean) => {
  167. console.log('nextFenceStatus', nextStatus);
  168. emits('toggleFenceStatus', nextStatus);
  169. };
  170. </script>
  171. <style scoped>
  172. .toolbar {
  173. display: flex;
  174. align-items: center;
  175. z-index: 10;
  176. padding: 5px;
  177. border-radius: 50px;
  178. }
  179. .fenceDrawingTip {
  180. background: #e8f5ff;
  181. border-radius: 6px;
  182. border: 1px solid #bae0ff;
  183. text-align: center;
  184. font-size: 12px;
  185. padding: 2px 20px;
  186. margin-right: 30px;
  187. color: #1890ff;
  188. }
  189. .fenceSwitchBtn {
  190. position: absolute;
  191. right: 10px;
  192. top: 10px;
  193. }
  194. .algoName {
  195. color: #ccc;
  196. margin-top: 10px;
  197. font-size: 12px;
  198. }
  199. .fenceWrapper {
  200. padding: 10px;
  201. }
  202. .fenceListWrapper {
  203. height: 365px;
  204. overflow-y: auto;
  205. margin-bottom: 10px;
  206. }
  207. .fenceTitle {
  208. font-weight: bold;
  209. font-size: 16px;
  210. position: relative;
  211. margin-left: 10px;
  212. &::before {
  213. content: '';
  214. width: 4px;
  215. position: absolute;
  216. left: -8px;
  217. height: 20px;
  218. top: 2px;
  219. background-color: #1890ff;
  220. }
  221. }
  222. </style>