249 lines
7.5 KiB
Vue
249 lines
7.5 KiB
Vue
<script lang="ts">
|
||
// 设备参数配置在系统中的key前缀
|
||
const DeviceConfigParamPrefix = {
|
||
Switch: 'SWITCH_',
|
||
Server: 'SERVER_',
|
||
Decoder: 'DECODER_',
|
||
Nvr: 'NVR_',
|
||
Box: 'BOX_',
|
||
Monitor: 'MONITOR_',
|
||
} as const;
|
||
|
||
type DeviceConfigParamPrefixType = (typeof DeviceConfigParamPrefix)[keyof typeof DeviceConfigParamPrefix];
|
||
|
||
// 渲染时的数据结构
|
||
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 '';
|
||
};
|
||
</script>
|
||
|
||
<script setup lang="ts">
|
||
import { postDefParameterPage, putDefParameter, type Station } from '@/apis';
|
||
import { useQueryControlStore } from '@/stores';
|
||
import { useMutation } from '@tanstack/vue-query';
|
||
import { NForm, NFormItemGi, NGrid, NInputNumber, NModal, NTabPane, NTabs, NTimePicker, NSpin, NFlex } from 'naive-ui';
|
||
import { ref, toRefs, watch } from 'vue';
|
||
|
||
const props = defineProps<{
|
||
station?: Station;
|
||
}>();
|
||
const { station } = toRefs(props);
|
||
const show = defineModel<boolean>('show', { required: true });
|
||
|
||
const queryControlStore = useQueryControlStore();
|
||
|
||
watch(show, (newValue) => {
|
||
if (newValue) {
|
||
console.log('对话框打开,停止轮询');
|
||
queryControlStore.disablePolling();
|
||
} else {
|
||
console.log('对话框关闭,开启轮询');
|
||
queryControlStore.enablePolling();
|
||
}
|
||
});
|
||
|
||
const tabPanes = [
|
||
{
|
||
tab: '交换机阈值',
|
||
name: DeviceConfigParamPrefix.Switch,
|
||
},
|
||
{
|
||
tab: '服务器阈值',
|
||
name: DeviceConfigParamPrefix.Server,
|
||
},
|
||
{
|
||
tab: '解码器阈值',
|
||
name: DeviceConfigParamPrefix.Decoder,
|
||
},
|
||
{
|
||
tab: '录像机阈值',
|
||
name: DeviceConfigParamPrefix.Nvr,
|
||
},
|
||
{
|
||
tab: '安防箱阈值',
|
||
name: DeviceConfigParamPrefix.Box,
|
||
},
|
||
{
|
||
tab: '显示器计划',
|
||
name: DeviceConfigParamPrefix.Monitor,
|
||
},
|
||
];
|
||
const activeTabName = ref<DeviceConfigParamPrefixType>(DeviceConfigParamPrefix.Switch);
|
||
|
||
const onBeforeTabLeave = (name: string, oldName: string): boolean | Promise<boolean> => {
|
||
saveDeviceParams({ tabName: oldName, params: deviceConfigParams.value });
|
||
getDeviceParams({ deviceKeyPrefix: name });
|
||
return true;
|
||
};
|
||
|
||
const onAfterModalEnter = () => {
|
||
getDeviceParams({ deviceKeyPrefix: activeTabName.value });
|
||
};
|
||
|
||
const onBeforeModalLeave = () => {
|
||
saveDeviceParams({ tabName: activeTabName.value, params: deviceConfigParams.value });
|
||
activeTabName.value = DeviceConfigParamPrefix.Switch;
|
||
deviceConfigParams.value = [];
|
||
};
|
||
|
||
const deviceConfigParams = ref<DeviceParamItem[]>([]);
|
||
|
||
const { mutate: getDeviceParams, isPending: paramsLoading } = useMutation({
|
||
mutationFn: async ({ deviceKeyPrefix }: { deviceKeyPrefix: string }) => {
|
||
if (!station.value) throw new Error('请先选择车站');
|
||
const { records } = await postDefParameterPage(station.value.code, {
|
||
model: {},
|
||
extra: { key_likeRight: deviceKeyPrefix },
|
||
current: 1,
|
||
size: 1000,
|
||
sort: 'id',
|
||
order: 'descending',
|
||
});
|
||
return records;
|
||
},
|
||
onSuccess: (records) => {
|
||
deviceConfigParams.value = records.map<DeviceParamItem>((record) => {
|
||
if (record.key?.includes(DeviceConfigParamPrefix.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);
|
||
window.$message.error(error.message);
|
||
},
|
||
});
|
||
|
||
const { mutate: saveDeviceParams } = useMutation({
|
||
mutationFn: async ({ tabName, params }: { tabName: string; params: DeviceParamItem[] }) => {
|
||
if (!station.value) throw new Error('请先选择车站');
|
||
for (const item of params) {
|
||
if (tabName.includes(DeviceConfigParamPrefix.Monitor)) {
|
||
await putDefParameter(station.value.code, {
|
||
id: item.id,
|
||
key: item.key,
|
||
name: item.name,
|
||
value: item.timeValue,
|
||
});
|
||
} else {
|
||
await putDefParameter(station.value.code, {
|
||
id: item.id,
|
||
key: item.key,
|
||
name: item.name,
|
||
value: `${deparseNumericValue(item.name, item.numValue ?? 0)}`,
|
||
});
|
||
}
|
||
}
|
||
},
|
||
onError: (error) => {
|
||
console.error(error);
|
||
window.$message.error(error.message);
|
||
},
|
||
});
|
||
</script>
|
||
|
||
<template>
|
||
<NModal
|
||
v-model:show="show"
|
||
preset="card"
|
||
style="width: 800px; height: 600px"
|
||
:title="`${station?.name} - 设备参数配置`"
|
||
: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 deviceConfigParams" :key="item.key" label-placement="left" :span="1" :label="item.name">
|
||
<!-- 监视器计划配置渲染时间选择器,其他配置项渲染数字输入框 -->
|
||
<template v-if="activeTabName === DeviceConfigParamPrefix.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></style>
|