Compare commits

...

2 Commits

Author SHA1 Message Date
15683799673
69f0d4adb4 Merge branch 'master' of http://47.109.37.87:3000/by2025/admin-vben5
Some checks failed
/ Explore-Gitea-Actions (push) Failing after 3m58s
2025-08-17 07:03:59 +08:00
15683799673
4bc18e0e4c 视频告警页面 2025-08-17 07:03:48 +08:00
6 changed files with 132 additions and 103 deletions

View File

@ -1,18 +1,30 @@
import type { AlarmEventAttachmentsVO, AlarmEventAttachmentsForm, AlarmEventAttachmentsQuery } from './model'; import type {
AlarmEventAttachmentsForm,
AlarmEventAttachmentsQuery,
AlarmEventAttachmentsVO,
} from './model';
import type { ID, IDS } from '#/api/common'; import type { ID, IDS, PageResult } from '#/api/common';
import type { PageResult } from '#/api/common';
import { commonExport } from '#/api/helper'; import { commonExport } from '#/api/helper';
import { requestClient } from '#/api/request'; import { requestClient } from '#/api/request';
/** /**
* *
* @param params * @param params
* @returns * @returns
*/ */
export function alarmEventAttachmentsList(params?: AlarmEventAttachmentsQuery) { export function alarmEventAttachmentsList(params?: AlarmEventAttachmentsQuery) {
return requestClient.get<PageResult<AlarmEventAttachmentsVO>>('/sis/alarmEventAttachments/list', { params }); return requestClient.get<PageResult<AlarmEventAttachmentsVO>>(
'/sis/alarmEventAttachments/list',
{ params },
);
}
export function queryAlarmEventAttachmentsList(id: ID) {
return requestClient.get<AlarmEventAttachmentsVO[]>(
'/sis/alarmEventAttachments/query/' + id,
);
} }
/** /**
@ -20,7 +32,9 @@ export function alarmEventAttachmentsList(params?: AlarmEventAttachmentsQuery) {
* @param params * @param params
* @returns * @returns
*/ */
export function alarmEventAttachmentsExport(params?: AlarmEventAttachmentsQuery) { export function alarmEventAttachmentsExport(
params?: AlarmEventAttachmentsQuery,
) {
return commonExport('/sis/alarmEventAttachments/export', params ?? {}); return commonExport('/sis/alarmEventAttachments/export', params ?? {});
} }
@ -30,7 +44,9 @@ export function alarmEventAttachmentsExport(params?: AlarmEventAttachmentsQuery)
* @returns * @returns
*/ */
export function alarmEventAttachmentsInfo(id: ID) { export function alarmEventAttachmentsInfo(id: ID) {
return requestClient.get<AlarmEventAttachmentsVO>(`/sis/alarmEventAttachments/${id}`); return requestClient.get<AlarmEventAttachmentsVO>(
`/sis/alarmEventAttachments/${id}`,
);
} }
/** /**

View File

@ -16,6 +16,8 @@ export interface AlarmEventAttachmentsVO {
*/ */
ossId: string | number; ossId: string | number;
imagePath: string;
/** /**
* 123 * 123
*/ */

View File

@ -5,6 +5,9 @@ import { getPopupContainer } from '@vben/utils';
import { getDictOptions } from '#/utils/dict'; import { getDictOptions } from '#/utils/dict';
import { DictEnum } from '@vben/constants'; import { DictEnum } from '@vben/constants';
export const fallImg =
'data:image/png;base64,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';
export const querySchema: FormSchemaGetter = () => [ export const querySchema: FormSchemaGetter = () => [
{ {
component: 'Input', component: 'Input',
@ -15,7 +18,7 @@ export const querySchema: FormSchemaGetter = () => [
component: 'Select', component: 'Select',
componentProps: { componentProps: {
getPopupContainer, getPopupContainer,
options: getDictOptions(DictEnum.alarm_level), options: getDictOptions(DictEnum.alarm_level, true),
}, },
fieldName: 'level', fieldName: 'level',
label: '级别', label: '级别',
@ -24,7 +27,7 @@ export const querySchema: FormSchemaGetter = () => [
component: 'Select', component: 'Select',
componentProps: { componentProps: {
getPopupContainer, getPopupContainer,
options: getDictOptions(DictEnum.alarm_state), options: getDictOptions(DictEnum.alarm_state, true),
}, },
fieldName: 'state', fieldName: 'state',
label: '处理状态', label: '处理状态',
@ -83,11 +86,11 @@ export const columns: VxeGridProps['columns'] = [
}, },
{ {
title: '预期处理时间', title: '预期处理时间',
field: 'processSt', field: 'servBeginTime',
}, },
{ {
title: '处理时间', title: '处理时间',
field: 'processEt', field: 'servEndTime',
}, },
{ {
field: 'action', field: 'action',
@ -110,14 +113,14 @@ export const modalSchema: FormSchemaGetter = () => [
}, },
{ {
label: '预警编号', label: '预警编号',
fieldName: 'alarmId', fieldName: 'id',
component: 'Input', component: 'Input',
rules: 'required', rules: 'required',
disabled: true, disabled: true,
}, },
{ {
label: '预警时间', label: '预警时间',
fieldName: 'alarmTime', fieldName: 'reportTime',
component: 'DatePicker', component: 'DatePicker',
componentProps: { componentProps: {
format: 'YYYY.MM.DD HH:mm', format: 'YYYY.MM.DD HH:mm',
@ -129,7 +132,7 @@ export const modalSchema: FormSchemaGetter = () => [
}, },
{ {
label: '预警类型', label: '预警类型',
fieldName: 'alarmType', fieldName: 'bigTypeName',
component: 'Input', component: 'Input',
rules: 'required', rules: 'required',
disabled: true, disabled: true,
@ -141,13 +144,13 @@ export const modalSchema: FormSchemaGetter = () => [
formItemClass: 'col-span-2', formItemClass: 'col-span-2',
disabled: true, disabled: true,
}, },
{ /* {
label: '所在位置', label: '所在位置',
fieldName: 'location', fieldName: 'location',
component: 'Input', component: 'Input',
rules: 'required', rules: 'required',
disabled: true, disabled: true,
}, },*/
{ {
label: '设备名称', label: '设备名称',
fieldName: 'deviceName', fieldName: 'deviceName',
@ -188,27 +191,22 @@ export const modalSchema: FormSchemaGetter = () => [
fieldName: 'level', fieldName: 'level',
component: 'Select', component: 'Select',
componentProps: { componentProps: {
options: [ getPopupContainer,
{ label: '特大', value: '特大' }, options: getDictOptions(DictEnum.alarm_level, true),
{ label: '重要', value: '重要' },
{ label: '一般', value: '一般' },
],
}, },
rules: 'selectRequired', rules: 'selectRequired',
}, },
{ {
label: '处理状态', label: '处理状态',
fieldName: 'processingStatus',
component: 'Select', component: 'Select',
componentProps: { componentProps: {
options: [ getPopupContainer,
{ label: '待分配', value: '待分配' }, options: getDictOptions(DictEnum.alarm_state, true),
{ label: '处理中', value: '处理中' },
{ label: '已完成', value: '已完成' },
],
}, },
fieldName: 'state',
rules: 'selectRequired', rules: 'selectRequired',
}, },
{ {
label: '预期处理时间', label: '预期处理时间',
fieldName: 'expectedProcessingTime', fieldName: 'expectedProcessingTime',

View File

@ -103,14 +103,7 @@ function handleAssign(row: any) {
title: '分配处理', title: '分配处理',
content: `确定要分配预警 ${row.alarmId} 给处理人员吗?`, content: `确定要分配预警 ${row.alarmId} 给处理人员吗?`,
onOk() { onOk() {
// //
const index = row.id;
if (index !== -1) {
// mockData.value[index].processingStatus = '';
// mockData.value[index].processingDetails = '';
// mockData.value[index].processingTime = new Date().toLocaleString();
tableApi.query();
}
}, },
}); });
} }

View File

@ -1,19 +1,23 @@
<script setup lang="ts"> <script setup lang="ts">
import { shallowRef } from 'vue'; import { ref, shallowRef } from 'vue';
import { useVbenModal } from '@vben/common-ui'; import { useVbenModal } from '@vben/common-ui';
import { import {
Descriptions, Descriptions,
DescriptionsItem, DescriptionsItem,
Image,
Tag, Tag,
Timeline, Timeline,
TimelineItem, TimelineItem,
} from 'ant-design-vue'; } from 'ant-design-vue';
import { queryAlarmEventAttachmentsList } from '#/api/sis/alarmEventAttachments';
import type { AlarmEventAttachmentsVO } from '#/api/sis/alarmEventAttachments/model';
import { fallImg } from './data';
const [BasicModal, modalApi] = useVbenModal({ const [BasicModal, modalApi] = useVbenModal({
onOpenChange: handleOpenChange, onOpenChange: handleOpenChange,
onClosed() { onClosed() {
// warningDetail.value = null; // warningDetail.value = null;
modalApi.close(); modalApi.close();
}, },
}); });
@ -21,16 +25,22 @@ const warningDetail = shallowRef<any>(null);
// 线 // 线
const timelineConfig = { const timelineConfig = {
'已完成': ['已完成'], 已完成: ['已完成'],
'处理异常': ['已完成', '处理异常'], 处理异常: ['已完成', '处理异常'],
'处理中': ['已完成', '处理中', '处理异常'] 处理中: ['已完成', '处理中', '处理异常'],
}; };
function showTimelineItem(type: string): boolean { function showTimelineItem(type: string): boolean {
const currentStatus = warningDetail.value?.processingStatus; const currentStatus = warningDetail.value?.processingStatus;
return timelineConfig[type as keyof typeof timelineConfig]?.includes(currentStatus) || false; return (
timelineConfig[type as keyof typeof timelineConfig]?.includes(
currentStatus,
) || false
);
} }
const currFiles = ref<AlarmEventAttachmentsVO[]>([]);
async function handleOpenChange(open: boolean) { async function handleOpenChange(open: boolean) {
if (!open) { if (!open) {
return null; return null;
@ -42,11 +52,11 @@ async function handleOpenChange(open: boolean) {
}; };
// //
const record = data.find((item: any) => item.id === id); if (data) {
if (record) { warningDetail.value = data;
warningDetail.value = record;
} }
//
currFiles.value = await queryAlarmEventAttachmentsList(id);
modalApi.modalLoading(false); modalApi.modalLoading(false);
} }
</script> </script>
@ -56,7 +66,7 @@ async function handleOpenChange(open: boolean) {
:footer="false" :footer="false"
:fullscreen-button="false" :fullscreen-button="false"
title="预警详情" title="预警详情"
class="w-[70%]" class="w-[60%]"
> >
<Descriptions <Descriptions
v-if="warningDetail" v-if="warningDetail"
@ -67,11 +77,13 @@ async function handleOpenChange(open: boolean) {
style="margin-bottom: 30px" style="margin-bottom: 30px"
> >
<DescriptionsItem label="预警编号"> <DescriptionsItem label="预警编号">
{{ warningDetail.alarmId }} {{ warningDetail.id }}
</DescriptionsItem> </DescriptionsItem>
<DescriptionsItem label="预警时间"> <DescriptionsItem label="预警时间">
{{ warningDetail.alarmTime }} {{ warningDetail.reportTime }}
</DescriptionsItem> </DescriptionsItem>
<DescriptionsItem label="级别"> <DescriptionsItem label="级别">
<Tag <Tag
:color=" :color="
@ -82,83 +94,83 @@ async function handleOpenChange(open: boolean) {
: 'blue' : 'blue'
" "
> >
{{ warningDetail.level }} {{ warningDetail.levelName }}
</Tag> </Tag>
</DescriptionsItem> </DescriptionsItem>
<DescriptionsItem label="预警类型"> <DescriptionsItem label="预警类型">
{{ warningDetail.alarmType }} {{ warningDetail.bigTypeName + ' - ' + warningDetail.smallTypeName }}
</DescriptionsItem> </DescriptionsItem>
<DescriptionsItem label="设备ip"
>{{ warningDetail.deviceIp }}
</DescriptionsItem>
<DescriptionsItem label="设备ip"
>{{ warningDetail.deviceName }}
</DescriptionsItem>
<DescriptionsItem label="描述" :span="2"> <DescriptionsItem label="描述" :span="2">
{{ warningDetail.description }} {{ warningDetail.description }}
</DescriptionsItem> </DescriptionsItem>
<DescriptionsItem label="所在位置"> <DescriptionsItem label="所在位置">
{{ warningDetail.location }} {{ warningDetail.deviceName }}
</DescriptionsItem> </DescriptionsItem>
<DescriptionsItem label="处理状态"> <DescriptionsItem label="处理状态">
<Tag <Tag>
:color=" {{ warningDetail.stateName }}
warningDetail.processingStatus === '待分配'
? 'red'
: warningDetail.processingStatus === '处理中'
? 'orange'
: 'green'
"
>
{{ warningDetail.processingStatus }}
</Tag> </Tag>
</DescriptionsItem> </DescriptionsItem>
<DescriptionsItem label="处理情况" :span="2"> <DescriptionsItem label="处理情况" :span="2">
{{ warningDetail.processingDetails || '-' }} {{ warningDetail.processingDetails || '-' }}
</DescriptionsItem> </DescriptionsItem>
<DescriptionsItem label="处理时间">
<DescriptionsItem label="处理时间" :span="2">
{{ warningDetail.processingTime || '-' }} {{ warningDetail.processingTime || '-' }}
</DescriptionsItem> </DescriptionsItem>
<DescriptionsItem label="设备名称">
{{ warningDetail.deviceName || '-' }} <DescriptionsItem :span="1" label="附件信息">
</DescriptionsItem> <div class="file-box">
<DescriptionsItem label="预处理时间" v-if="warningDetail.processingStatus === '处理中'"> <div class="img-box" v-for="item in currFiles">
{{ warningDetail.expectedProcessingTime || '-' }} <Image
</DescriptionsItem> style="width: 120px; height: 120px"
<DescriptionsItem label="处理图片" v-if="warningDetail.processingStatus === '已完成'"> :src="item.imagePath"
<img :src="warningDetail.imgUrl" alt="处理图片" style="max-width: 200px; max-height: 150px;"> :fallback="fallImg"
/>
</div>
</div>
</DescriptionsItem> </DescriptionsItem>
<DescriptionsItem :span="1" label="报警视频"></DescriptionsItem>
</Descriptions> </Descriptions>
<!-- <Timeline>
<TimelineItem v-if="showTimelineItem('已完成')"> <Timeline>
<p style="display: flex">类型已完成</p>
<p>时间2025-06-01 11:07:59</p>
<p>处理人张三</p>
</TimelineItem>
<TimelineItem v-if="showTimelineItem('处理异常')">
<p style="display: flex">类型处理异常</p>
<p>时间2025-06-01 11:07:59</p>
<p>处理人张三</p>
<p>异常原因时长不够</p>
</TimelineItem>
<TimelineItem v-if="showTimelineItem('处理中')">
<p style="display: flex">类型处理中</p>
<p>时间2025-06-01 11:07:59</p>
<p>处理人张三</p>
</TimelineItem>
<TimelineItem>
<p style="display: flex">类型创建预警</p>
<p>时间2025-06-01 11:07:59</p>
<p>处理人张三</p>
</TimelineItem>
</Timeline> -->
<Timeline>
<TimelineItem v-if="warningDetail.processingStatus === '已完成'"> <TimelineItem v-if="warningDetail.processingStatus === '已完成'">
<p style="display: flex">类型已完成</p> <p style="display: flex">类型已完成</p>
<p>时间2025-06-01 11:07:59</p> <p>时间2025-06-01 11:07:59</p>
<p>处理人张三</p> <p>处理人张三</p>
</TimelineItem> </TimelineItem>
<TimelineItem v-if="warningDetail.processingStatus === '已完成' || warningDetail.processingStatus === '处理异常'"> <TimelineItem
v-if="
warningDetail.processingStatus === '已完成' ||
warningDetail.processingStatus === '处理异常'
"
>
<p style="display: flex">类型处理异常</p> <p style="display: flex">类型处理异常</p>
<p>时间2025-06-01 11:07:59</p> <p>时间2025-06-01 11:07:59</p>
<p>处理人张三</p> <p>处理人张三</p>
<p>异常原因时长不够</p> <p>异常原因时长不够</p>
</TimelineItem> </TimelineItem>
<TimelineItem v-if="warningDetail.processingStatus === '已完成'|| warningDetail.processingStatus === '处理中' || warningDetail.processingStatus === '处理异常'"> <TimelineItem
v-if="
warningDetail.processingStatus === '已完成' ||
warningDetail.processingStatus === '处理中' ||
warningDetail.processingStatus === '处理异常'
"
>
<p style="display: flex">类型处理中</p> <p style="display: flex">类型处理中</p>
<p>时间2025-06-01 11:07:59</p> <p>时间2025-06-01 11:07:59</p>
<p>处理人张三</p> <p>处理人张三</p>
@ -171,3 +183,12 @@ async function handleOpenChange(open: boolean) {
</Timeline> </Timeline>
</BasicModal> </BasicModal>
</template> </template>
<style scoped lang="scss">
.file-box {
.img-box {
float: left;
margin-left: 5px;
}
}
</style>

View File

@ -57,13 +57,12 @@ const [BasicModal, modalApi] = useVbenModal({
id: number | string; id: number | string;
data: any[]; data: any[];
}; };
const record = data.find((item: any) => item.id === id); if (data) {
if (record) { console.log(data)
await formApi.setValues(record); await formApi.setValues(data);
} }
} }
await markInitialized(); await markInitialized();
modalApi.modalLoading(false); modalApi.modalLoading(false);
}, },
}); });