Files
ndm-web-platform/src/components/station/device-param-config-modal/device-param-config.modal.vue
T
2026-05-19 16:40:18 +08:00

264 lines
7.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script lang="ts">
// 设备参数配置在系统中的key前缀
const DEVICE_PARAM_PREFIXES = {
Camera: 'CAMERA_',
Switch: 'SWITCH_',
Server: 'SERVER_',
Decoder: 'DECODER_',
Nvr: 'NVR_',
Box: 'BOX_',
Monitor: 'MONITOR_',
} as const;
type DeviceParamPrefix = (typeof DEVICE_PARAM_PREFIXES)[keyof typeof DEVICE_PARAM_PREFIXES];
// 渲染时的数据结构
interface DeviceParamItem {
id: string;
key: string;
name: string;
numValue?: number;
timeValue?: string;
suffix?: string;
step?: number;
min?: number;
max?: number;
}
// 一些参数值是零点几,一些参数值是好几十,需要根据参数名称中的关键词来做预处理
const parseNumericValue = (name: string, value: string) => {
let val = parseFloat(value);
const needMultiply = name.includes('流量') || name.includes('占用率');
if (needMultiply) val *= 100;
return val;
};
// 在保存参数时需要反向处理
const deparseNumericValue = (name: string, value: number) => {
let val = value;
const needMultiply = name.includes('流量') || name.includes('占用率');
if (needMultiply) val /= 100;
return val;
};
const getItemStep = (name: string) => {
if (name.includes('转速')) return 100;
return 1;
};
const getItemMax = (name: string) => {
if (name.includes('转速')) return 50000;
return 100;
};
const getItemSuffix = (name: string) => {
const percentLike = name.includes('流量') || name.includes('占用率') || name.includes('湿度');
const secondLike = name.includes('忽略丢失');
const currentLike = name.includes('电流');
const voltageLike = name.includes('电压');
const temperatureLike = name.includes('温');
const rpmLike = name.includes('转速');
if (percentLike) return '%';
if (secondLike) return '秒';
if (currentLike) return 'A';
if (voltageLike) return 'V';
if (temperatureLike) return '℃';
if (rpmLike) return '转/分';
return '';
};
const tabPanes = [
{
tab: '摄像机阈值',
name: DEVICE_PARAM_PREFIXES.Camera,
},
{
tab: '交换机阈值',
name: DEVICE_PARAM_PREFIXES.Switch,
},
{
tab: '服务器阈值',
name: DEVICE_PARAM_PREFIXES.Server,
},
{
tab: '解码器阈值',
name: DEVICE_PARAM_PREFIXES.Decoder,
},
{
tab: '录像机阈值',
name: DEVICE_PARAM_PREFIXES.Nvr,
},
{
tab: '安防箱阈值',
name: DEVICE_PARAM_PREFIXES.Box,
},
{
tab: '显示器计划',
name: DEVICE_PARAM_PREFIXES.Monitor,
},
];
</script>
<script setup lang="ts">
import { pageDefParameterApi, resetMonitorScheduleApi, updateDefParameterApi, type Station } from '@/apis';
import { parseErrorFeedback } from '@/utils';
import { useMutation } from '@tanstack/vue-query';
import { NFlex, NForm, NFormItemGi, NGrid, NInputNumber, NModal, NSpin, NTabPane, NTabs, NTimePicker } from 'naive-ui';
import { ref, toRefs } from 'vue';
const props = defineProps<{
station?: Station;
}>();
const show = defineModel<boolean>('show', { required: true });
const { station } = toRefs(props);
const activeTabName = ref<DeviceParamPrefix>(DEVICE_PARAM_PREFIXES.Camera);
const deviceParams = ref<DeviceParamItem[]>([]);
const { mutate: getDeviceParams, isPending: paramsLoading } = useMutation({
mutationFn: async (params: { deviceKeyPrefix: string }) => {
const { deviceKeyPrefix } = params;
const { records } = await pageDefParameterApi(
{
model: {},
extra: { key_likeRight: deviceKeyPrefix },
current: 1,
size: 1000,
sort: 'id',
order: 'descending',
},
{
stationCode: station.value?.code,
},
);
return records;
},
onSuccess: (records) => {
deviceParams.value = records.map<DeviceParamItem>((record) => {
if (record.key?.includes(DEVICE_PARAM_PREFIXES.Monitor)) {
return {
id: record.id ?? '',
key: record.key ?? '',
name: record.name ?? '',
timeValue: record.value ?? '',
};
}
return {
id: record.id ?? '',
key: record.key ?? '',
name: record.name ?? '',
numValue: parseNumericValue(record.name ?? '', record.value ?? '0'),
suffix: getItemSuffix(record.name ?? ''),
step: getItemStep(record.name ?? ''),
min: 0,
max: getItemMax(record.name ?? ''),
};
});
},
onError: (error) => {
console.error(error);
const errorFeedback = parseErrorFeedback(error);
window.$message.error(errorFeedback);
},
});
const { mutate: saveDeviceParams } = useMutation({
mutationFn: async (params: { tabName: string; items: DeviceParamItem[] }) => {
const { tabName, items } = params;
for (const item of items) {
if (tabName.includes(DEVICE_PARAM_PREFIXES.Monitor)) {
await updateDefParameterApi(
{
id: item.id,
key: item.key,
name: item.name,
value: item.timeValue,
},
{
stationCode: station.value?.code,
},
);
} else {
await updateDefParameterApi(
{
id: item.id,
key: item.key,
name: item.name,
value: `${deparseNumericValue(item.name, item.numValue ?? 0)}`,
},
{
stationCode: station.value?.code,
},
);
}
}
await resetMonitorScheduleApi({ stationCode: station.value?.code });
},
onError: (error) => {
console.error(error);
const errorFeedback = parseErrorFeedback(error);
window.$message.error(errorFeedback);
},
});
const onBeforeTabLeave = (name: string, oldName: string): boolean | Promise<boolean> => {
saveDeviceParams({ tabName: oldName, items: deviceParams.value });
getDeviceParams({ deviceKeyPrefix: name });
return true;
};
const onAfterModalEnter = () => {
getDeviceParams({ deviceKeyPrefix: activeTabName.value });
};
const onBeforeModalLeave = () => {
saveDeviceParams({ tabName: activeTabName.value, items: deviceParams.value });
activeTabName.value = DEVICE_PARAM_PREFIXES.Camera;
deviceParams.value = [];
};
</script>
<template>
<NModal
v-model:show="show"
preset="card"
style="width: 800px; height: 600px"
:title="`${station?.name} - 设备参数配置`"
:auto-focus="false"
:close-on-esc="false"
:mask-closable="false"
@after-enter="onAfterModalEnter"
@before-leave="onBeforeModalLeave"
>
<NTabs v-model:value="activeTabName" type="card" @before-leave="onBeforeTabLeave">
<NTabPane v-for="pane in tabPanes" :key="pane.name" :tab="pane.tab" :name="pane.name">
<NFlex v-if="paramsLoading" :justify="'center'" :align="'center'">
<NSpin :show="paramsLoading" description="加载设备参数中..." />
</NFlex>
<NForm v-else>
<NGrid cols="1">
<NFormItemGi v-for="item in deviceParams" :key="item.key" span="1" label-placement="left" :label="item.name">
<!-- 监视器计划配置渲染时间选择器其他配置项渲染数字输入框 -->
<template v-if="activeTabName === DEVICE_PARAM_PREFIXES.Monitor">
<NTimePicker v-model:formatted-value="item.timeValue" />
</template>
<template v-else>
<NInputNumber v-model:value="item.numValue" :step="item.step" :min="item.min" :max="item.max" style="width: 100%">
<template #suffix>
<span>{{ item.suffix }}</span>
</template>
</NInputNumber>
</template>
</NFormItemGi>
</NGrid>
</NForm>
</NTabPane>
</NTabs>
</NModal>
</template>
<style scoped lang="scss"></style>