CameraConfigGroup.vue 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. <template>
  2. <div class="cameraConfigGroup">
  3. <el-button
  4. type="primary"
  5. @click="createGroupDialog = true"
  6. style="margin: 10px 0;"
  7. v-permission="{ action: [PERM_ALGO.CONFIG_ADD_GROUP] }"
  8. >
  9. <img src="@/assets/images/create.png" style="margin-top: -1px; margin-right: 5px" />新建相机分组
  10. </el-button>
  11. <el-table
  12. :data="cameraGroupList"
  13. :span-method="objectSpanMethod"
  14. height="calc(100vh - 300px)"
  15. style="width: 100%; margin-top: 16px; --el-table-border-color: none"
  16. v-loading="loading"
  17. :row-class-name="tableRowClassName"
  18. >
  19. <el-table-column prop="id" label="组序号" width="70"/>
  20. <el-table-column prop="cameraName" label="相机名称" align="center">
  21. <template #default="scope">
  22. <div class="cameraName-text" v-if="scope.row.isMainCamera === IsMainCamera.YES">
  23. <el-icon><Star color="Gold" /></el-icon>
  24. {{ scope.row.cameraName }}
  25. </div>
  26. </template>
  27. </el-table-column>
  28. <el-table-column prop="cameraCode" label="设备ID"/>
  29. <el-table-column prop="location" label="地点"/>
  30. <el-table-column prop="algoName" label="算法">
  31. <template #default="scope">
  32. <div class="algoId-text" @click="handleView(scope.row)">
  33. {{ scope.row.algoName }}
  34. </div>
  35. </template>
  36. </el-table-column>
  37. <el-table-column label="操作" fixed="right" width="120px">
  38. <template #default="scope">
  39. <div class="operation">
  40. <el-tooltip effect="light" content="关闭/开启" placement="bottom">
  41. <el-switch
  42. :model-value="scope.row.status"
  43. :inactive-value="CameraGroupStatus.CLOSE"
  44. :active-value="CameraGroupStatus.OPEN"
  45. @update:model-value="(val) => handleSwitch(val, scope.row)"/>
  46. </el-tooltip>
  47. <el-tooltip effect="light" content="删除" placement="bottom">
  48. <img src="@/views/message/alarmMessages/img/delete.png"
  49. @click="handleDelete(scope.row)"
  50. v-permission="{ action: [PERM_ALGO.CONFIG_DELETE_GROUP] }"
  51. />
  52. </el-tooltip>
  53. </div>
  54. </template>
  55. </el-table-column>
  56. <template #empty>
  57. <div class="emptyDiv">
  58. <img src="@/assets/images/empty.png" class="emptyImg" />
  59. <span class="emptySpan">暂无数据</span>
  60. </div>
  61. </template>
  62. </el-table>
  63. <section class="mt-4 flex justify-end">
  64. <el-pagination
  65. background
  66. layout="total, sizes, prev, pager, next"
  67. :page-sizes="[10, 30, 50]"
  68. :total="total"
  69. v-model:page-size="requestParams.pageSize"
  70. v-model:current-page="requestParams.pageNumber"
  71. @change="queryCameraGroupPage"
  72. />
  73. </section>
  74. <!-- </el-card> -->
  75. <!--删除弹窗 -->
  76. <el-dialog v-model="deleteDialog" width="424px" top="20%" class="deleteDialog">
  77. <template #header="">
  78. <div class="deleteDialogHeader">
  79. <img src="@/assets/images/deleteTip.png" class="deleteTip" />
  80. <span class="titleSpan">请确认删除该相机分组吗?</span>
  81. </div>
  82. </template>
  83. <span style="margin-left: 37px">删除之后,该组多相机检测将失效!</span>
  84. <div class="dialogBottom">
  85. <el-button class="dialogBtn" @click="deleteDialog = false">取消</el-button>
  86. <el-button class="dialogBtn" type="primary" @click="confirmDelete">确定</el-button>
  87. </div>
  88. </el-dialog>
  89. <!-- 新增相机分组弹窗 -->
  90. <el-dialog v-model="createGroupDialog" width="70%" top="15%" left="25%" class="deleteDialog" title="设置相机组" @close="handleCancle">
  91. <SettingCamera ref="settingCameraRef"/>
  92. <div class="dialogBottom">
  93. <el-button class="dialogBtn" @click="handleCancle">取消</el-button>
  94. <el-button class="dialogBtn" type="primary" @click="handleCreateGroup">确定</el-button>
  95. </div>
  96. </el-dialog>
  97. </div>
  98. </template>
  99. <script lang="ts" setup>
  100. import { onMounted, ref } from 'vue';
  101. import { useRouter } from 'vue-router';
  102. import { ElMessage } from 'element-plus';
  103. import { Star } from '@element-plus/icons-vue';
  104. import useCameraGroupQuery from './hooks/useCameraGroupQuery';
  105. import { CameraGroupTableItem, CameraGroupStatus, IsMainCamera } from '@/types/camera/camera-preview';
  106. import { deleteDetectionGroup, updateGroupStatus, saveDetectionGroup } from '@/api/camera/camera-preview-group';
  107. import SettingCamera from './components/SettingCamera.vue'
  108. import { PERM_ALGO } from '@/types/permission/constants';
  109. const router = useRouter();
  110. const { requestParams, total, queryCameraGroupPage, cameraGroupList, loading } = useCameraGroupQuery();
  111. const createGroupDialog = ref(false);
  112. const deleteDialog = ref(false);
  113. const cameraDetectionGroupId = ref();
  114. const tableRowClassName = ({
  115. row,
  116. }: {
  117. row: CameraGroupTableItem
  118. }) => {
  119. // 根据分组ID计算颜色索引(使用模运算实现颜色循环)
  120. const groupColors = ['normal', 'active'];
  121. const groupId = row.cameraDetectionGroupId;
  122. return groupColors[groupId % 3];
  123. }
  124. const objectSpanMethod = ({
  125. row,
  126. rowIndex,
  127. columnIndex,
  128. }) => {
  129. // 合并组序列和操作列
  130. if (columnIndex === 0 || columnIndex === 5) {
  131. const list = cameraGroupList.value;
  132. const groupId = row.cameraDetectionGroupId;
  133. const firstIndex = list.findIndex(item => item.cameraDetectionGroupId === groupId);
  134. if (rowIndex !== firstIndex) {
  135. return { rowspan: 0, colspan: 0 };
  136. }
  137. let rowCount = 0;
  138. for (let i = firstIndex; i < list.length; i++) {
  139. if (list[i].cameraDetectionGroupId === groupId) rowCount++;
  140. else break;
  141. }
  142. return {
  143. rowspan: rowCount,
  144. colspan: 1
  145. };
  146. }
  147. };
  148. const handleDelete = (row: CameraGroupTableItem) => {
  149. if (row.status === CameraGroupStatus.OPEN) {
  150. ElMessage({
  151. message: '开启状态的分组不可删除',
  152. type: 'warning',
  153. plain: true,
  154. });
  155. } else {
  156. deleteDialog.value = true;
  157. cameraDetectionGroupId.value = row.cameraDetectionGroupId;
  158. }
  159. }
  160. const handleSwitch = (newStatus: number, row: CameraGroupTableItem) => {
  161. const data = {
  162. cameraDetectionGroupId: row.cameraDetectionGroupId,
  163. status: newStatus,
  164. }
  165. updateGroupStatus(data).then(res => {
  166. ElMessage.success('操作成功')
  167. queryCameraGroupPage();
  168. })
  169. }
  170. const confirmDelete = () => {
  171. deleteDetectionGroup([Number(cameraDetectionGroupId.value)]).then(() => {
  172. ElMessage({
  173. message: '删除成功',
  174. type: 'success',
  175. plain: true,
  176. });
  177. deleteDialog.value = false;
  178. queryCameraGroupPage();
  179. })
  180. }
  181. const settingCameraRef = ref<InstanceType<typeof SettingCamera>>();
  182. const handleCreateGroup = () => {
  183. const { valid, data } = settingCameraRef.value?.isValidate();
  184. if(valid) {
  185. // 执行提交逻辑
  186. const saveData = data.map(item => {
  187. return {
  188. cameraId: Number(item.code),
  189. algoId: Number(item.algoCode),
  190. isMainCamera: item.isMainCamera,
  191. }
  192. })
  193. saveDetectionGroup(saveData).then(() => {
  194. ElMessage({
  195. message: '相机组添加成功',
  196. type:'success',
  197. plain: true,
  198. });
  199. createGroupDialog.value = false;
  200. settingCameraRef.value?.clearForm();
  201. queryCameraGroupPage();
  202. })
  203. }
  204. }
  205. const handleCancle = () => {
  206. createGroupDialog.value = false
  207. settingCameraRef.value?.clearForm();
  208. }
  209. const handleView = (row: CameraGroupTableItem) => {
  210. router.push({
  211. path: '/algorithm/camera-group',
  212. query: {
  213. groupId: row.cameraDetectionGroupId,
  214. cameraId: row.cameraId
  215. }
  216. })
  217. }
  218. onMounted(() => {
  219. queryCameraGroupPage();
  220. })
  221. </script>
  222. <style lang="scss" scoped>
  223. .emptyDiv {
  224. margin-top: 78px;
  225. margin: auto;
  226. width: 396px;
  227. .emptyImg {
  228. height: 257px;
  229. }
  230. .emptySpan {
  231. font-family: PingFangSC, PingFang SC;
  232. font-weight: 400;
  233. font-size: 18px;
  234. color: rgba(0, 0, 0, 0.45);
  235. text-align: left;
  236. font-style: normal;
  237. }
  238. }
  239. .algoId-text {
  240. cursor: pointer;
  241. color: #409eff;
  242. }
  243. .deleteDialog {
  244. .deleteDialogHeader {
  245. display: flex;
  246. .deleteTip {
  247. height: 24px;
  248. width: 24px;
  249. }
  250. .titleSpan {
  251. height: 24px;
  252. font-size: 16px;
  253. color: rgba(0, 0, 0, 0.88);
  254. line-height: 24px;
  255. text-align: center;
  256. margin-left: 12px;
  257. }
  258. }
  259. .dialogBottom {
  260. display: flex;
  261. justify-content: flex-end;
  262. margin-top: 12px;
  263. }
  264. }
  265. .operation {
  266. display: flex;
  267. align-items: center;
  268. img {
  269. margin-left: 20px;
  270. }
  271. }
  272. .el-table {
  273. :deep(.normal) {
  274. --el-table-tr-bg-color: #fff;
  275. &:hover {
  276. --el-table-tr-bg-color: #fff;
  277. }
  278. }
  279. :deep(.active) {
  280. --el-table-tr-bg-color: #fafafa;
  281. &:hover {
  282. --el-table-tr-bg-color: #fafafa;
  283. }
  284. }
  285. }
  286. </style>