調整異常設定表單,新增限定條件欄位

This commit is contained in:
koko 2025-09-05 16:50:49 +08:00
parent be4ff70043
commit 30b3cb586b
5 changed files with 216 additions and 150 deletions

View File

@ -16,6 +16,7 @@ export const GET_OUTLIERS_DEVLIST_API = `api/Alarm/GetDevList`; // 取得設備
export const GET_OUTLIERS_POINTS_API = `api/Alarm/GetAlarmPoints`; // 取得點位 export const GET_OUTLIERS_POINTS_API = `api/Alarm/GetAlarmPoints`; // 取得點位
export const POST_OUTLIERS_SETTING_API = `api/Alarm/SaveAlarmSetting`; // 新增與修改 export const POST_OUTLIERS_SETTING_API = `api/Alarm/SaveAlarmSetting`; // 新增與修改
export const DELETE_OUTLIERS_SETTING_API = `api/Alarm/DeleteAlarmSetting`; // 刪除 export const DELETE_OUTLIERS_SETTING_API = `api/Alarm/DeleteAlarmSetting`; // 刪除
export const GET_FACTOR_API = `api/Alarm/GetFactor`
export const GET_ALERT_SCHEDULE_LIST_API = `api/Alarm/GetAlarmSchedule`; export const GET_ALERT_SCHEDULE_LIST_API = `api/Alarm/GetAlarmSchedule`;
export const POST_ALERT_SCHEDULE = `api/Alarm/SaveAlarmSchedule`; export const POST_ALERT_SCHEDULE = `api/Alarm/SaveAlarmSchedule`;

View File

@ -16,7 +16,8 @@ import {
GET_SHOW_ALERT_API, GET_SHOW_ALERT_API,
GET_ALERT_SCHEDULE_LIST_API, GET_ALERT_SCHEDULE_LIST_API,
POST_ALERT_SCHEDULE, POST_ALERT_SCHEDULE,
DELETE_ALERT_SCHEDULE DELETE_ALERT_SCHEDULE,
GET_FACTOR_API
} from "./api"; } from "./api";
import instance from "@/util/request"; import instance from "@/util/request";
import apihandler from "@/util/apihandler"; import apihandler from "@/util/apihandler";
@ -153,6 +154,15 @@ export const getOutliersPoints = async (id) => {
}); });
}; };
export const getFactors = async () => {
const res = await instance.post(GET_FACTOR_API);
return apihandler(res.code, res.data, {
msg: res.msg,
code: res.code,
});
};
export const postOutliersSetting = async (data) => { export const postOutliersSetting = async (data) => {
const res = await instance.post(POST_OUTLIERS_SETTING_API, data); const res = await instance.post(POST_OUTLIERS_SETTING_API, data);

View File

@ -1,6 +1,12 @@
<script setup> <script setup>
import { onMounted, ref, watch, inject } from "vue"; import { onMounted, ref, watch, inject } from "vue";
import { getOutliersList, getOutliersDevList, getOutliersPoints, delOutliersSetting } from "@/apis/alert"; import {
getOutliersList,
getOutliersDevList,
getOutliersPoints,
getFactors,
delOutliersSetting,
} from "@/apis/alert";
import useSearchParam from "@/hooks/useSearchParam"; import useSearchParam from "@/hooks/useSearchParam";
import AlertOutliersTableAddModal from "./AlertOutliersTableAddModal.vue"; import AlertOutliersTableAddModal from "./AlertOutliersTableAddModal.vue";
@ -13,6 +19,7 @@ const tableData = ref([]);
const dev_data = ref({ const dev_data = ref({
devList: [], devList: [],
alarmPoints: [], alarmPoints: [],
alarmFactors: [],
}); });
const editRecord = ref(null); const editRecord = ref(null);
@ -39,31 +46,10 @@ const columns = [
title: "限定條件", title: "限定條件",
key: "factor_name", key: "factor_name",
}, },
{
title: "上限(>=)",
key: "highLimit",
},
{
title: "下限(<=)",
key: "lowLimit",
},
{
title: "上限持續秒數",
key: "highDelay",
},
{
title: "下限持續秒數",
key: "lowDelay",
},
{ {
title: "警示方式", title: "警示方式",
key: "warning_method", key: "warning_method",
}, },
{
title: "警示時間",
key: "warning_time",
width: 150,
},
{ {
title: "功能", title: "功能",
key: "operation", key: "operation",
@ -73,48 +59,64 @@ const columns = [
const getDevList = async () => { const getDevList = async () => {
const res = await getOutliersDevList({ const res = await getOutliersDevList({
device_name_tag: searchParams.value?.subSys_id device_name_tag: searchParams.value?.subSys_id,
}); });
return res.data.map((d) => ({ return res.data.map((d) => ({
...d, ...d,
key: d.device_number key: d.device_number,
})); }));
}; };
const getAlarmPoints = async () => { const getAlarmPoints = async () => {
const res = await getOutliersPoints({ const res = await getOutliersPoints({
device_name_tag: searchParams.value?.subSys_id device_name_tag: searchParams.value?.subSys_id,
}); });
return res.data.map((d) => ({ return res.data.map((d) => ({
...d, ...d,
key: d.points key: d.points,
}));
};
const getFactor = async () => {
const res = await getFactors();
return res.data.map((d) => ({
...d,
key: d.id,
})); }));
}; };
const getOutliersData = async () => { const getOutliersData = async () => {
const res = await getOutliersList({ const res = await getOutliersList({
device_name_tag: searchParams.value?.subSys_id device_name_tag: searchParams.value?.subSys_id,
}); });
loading.value = true; loading.value = true;
if (res.isSuccess) { if (res.isSuccess) {
tableData.value = res.data.map(item => { tableData.value = res.data.map((item) => {
const matchedDevice = dev_data.value.devList.find(dev => dev.device_number === item.device_number); const matchedDevice = dev_data.value.devList.find(
const matchedPoints = dev_data.value.alarmPoints.find(p => p.points === item.points); (dev) => dev.device_number === item.device_number
const matchedFactor = matchedPoints?.factor && item.factor ? matchedPoints?.factor?.find(f => f.id === item.factor) : null; );
const matchedTime = timesList.value.find(t => t.id === item.schedule_id); const matchedPoints = dev_data.value.alarmPoints.find(
const warningMethodKeys = item.notices?.map(noticeValue => { (p) => p.points === item.points
const matchedNotice = noticeList.value.find(n => n.system_value === noticeValue); );
return matchedNotice ? matchedNotice.system_key : ''; const matchedFactor = dev_data.value.alarmFactors.find(
}).filter(key => key !== '').join('\n'); (p) => p.id === item.factor
);
const warningMethodKeys = item.notices
?.map((noticeValue) => {
const matchedNotice = noticeList.value.find(
(n) => n.system_value === noticeValue
);
return matchedNotice ? matchedNotice.system_key : "";
})
.filter((key) => key !== "")
.join("\n");
return { return {
...item, ...item,
device_name: matchedDevice ? matchedDevice.device_name : '', device_name: matchedDevice ? matchedDevice.device_name : "",
points: matchedPoints ? matchedPoints.full_name : '', points_name: matchedPoints ? matchedPoints.full_name : "",
is_bool: matchedPoints ? matchedPoints.is_bool : 1, factor_name: matchedFactor ? matchedFactor.full_name : "",
factor_name: matchedFactor ? matchedFactor.full_name : '',
warning_method: warningMethodKeys, warning_method: warningMethodKeys,
warning_time: matchedTime ? matchedTime.schedule_name : '',
}; };
}); });
loading.value = false; loading.value = false;
@ -122,12 +124,14 @@ const getOutliersData = async () => {
}; };
const getAllOptions = async () => { const getAllOptions = async () => {
const [devices, points] = await Promise.all([ const [devices, points, factors] = await Promise.all([
getDevList(), getDevList(),
getAlarmPoints(), getAlarmPoints(),
getFactor(),
]); ]);
dev_data.value.devList = devices; dev_data.value.devList = devices;
dev_data.value.alarmPoints = points; dev_data.value.alarmPoints = points;
dev_data.value.alarmFactors = factors;
}; };
watch( watch(
@ -167,7 +171,6 @@ const onCancel = () => {
editRecord.value = null; editRecord.value = null;
outliers_add_table_item.close(); outliers_add_table_item.close();
}; };
</script> </script>
<template> <template>
@ -181,7 +184,12 @@ const onCancel = () => {
:OptionsData="dev_data" :OptionsData="dev_data"
/> />
</div> </div>
<Table :loading="loading" :columns="columns" :dataSource="tableData" class="mt-3"> <Table
:loading="loading"
:columns="columns"
:dataSource="tableData"
class="mt-3"
>
<template #bodyCell="{ record, column, index }"> <template #bodyCell="{ record, column, index }">
<template v-if="column.key === 'operation'"> <template v-if="column.key === 'operation'">
<button <button
@ -198,14 +206,11 @@ const onCancel = () => {
</button> </button>
</template> </template>
<template v-else-if="column.key === 'enable'"> <template v-else-if="column.key === 'enable'">
{{ record.enable === 1 ? '是' : '否' }} {{ record.enable === 1 ? "是" : "否" }}
</template> </template>
<template v-else-if="column.key === 'warning_method'"> <template v-else-if="column.key === 'warning_method'">
<span class="whitespace-pre">{{ record.warning_method }}</span> <span class="whitespace-pre">{{ record.warning_method }}</span>
</template> </template>
<template v-else-if="column.key === 'warning_time'">
<span class="whitespace-pre">{{ record.warning_time }}</span>
</template>
<template v-else> <template v-else>
{{ record[column.key] }} {{ record[column.key] }}
</template> </template>

View File

@ -20,18 +20,19 @@ const props = defineProps({
const form = ref(null); const form = ref(null);
const formState = ref({ const formState = ref({
"id": 0, id: 0,
"device_number": "", device_number: "",
"device_name_tag": searchParams.value?.subSys_id, device_name_tag: searchParams.value?.subSys_id,
"points": "", points: "",
"enable": 0, enable: 0,
"is_bool": 1, factor: 1,
"factor": null, alarm_value: "",
"highLimit": null, delay: 0,
"lowLimit": null, highLimit: null,
"highDelay": null, lowLimit: null,
"lowDelay": null, highDelay: null,
"notices": [] lowDelay: null,
notices: [],
}); });
let scheme = yup.object({ let scheme = yup.object({
@ -45,12 +46,12 @@ let scheme = yup.object({
lowDelay: yup.number().nullable(), lowDelay: yup.number().nullable(),
}); });
const { formErrorMsg, handleSubmit, handleErrorReset } = const { formErrorMsg, handleSubmit, handleErrorReset } = useFormErrorMessage(
useFormErrorMessage(scheme.value); scheme.value
);
const SaveCheckAuth = ref([]); const SaveCheckAuth = ref([]);
const isBool = ref(1); const factorNum = ref(1);
const factorData = ref([]);
watch( watch(
() => props.editRecord, () => props.editRecord,
@ -61,28 +62,15 @@ watch(
}; };
SaveCheckAuth.value = newValue.notices ? [...newValue.notices] : []; SaveCheckAuth.value = newValue.notices ? [...newValue.notices] : [];
if (newValue.points) { if (newValue.factor) {
onPointsChange(newValue.points); onFactorsChange(newValue.factor);
} }
} }
} }
); );
const onPointsChange = (selectedPoint) => { const onFactorsChange = (selectedFactor) => {
const pointData = props.OptionsData.alarmPoints.find(p => p.points === selectedPoint); factorNum.value = selectedFactor;
if (pointData) {
isBool.value = pointData.is_bool;
formState.value.is_bool = pointData.is_bool;
if (pointData.factor && Array.isArray(pointData.factor)) {
factorData.value = pointData.factor.map((d) => ({
...d,
key: d.id
}));;
} else {
factorData.value = [];
formState.value.factor = 0;
}
}
}; };
const onNoticesChange = (value, checked) => { const onNoticesChange = (value, checked) => {
@ -117,34 +105,69 @@ const closeModal = () => {
formState.value = {}; formState.value = {};
handleErrorReset(); handleErrorReset();
props.onCancel(); props.onCancel();
factorData.value = []; factorNum.value = 1;
isBool.value = 1;
}; };
</script> </script>
<template> <template>
<button class="btn btn-sm btn-success mr-3" @click.stop.prevent="openModal"> <button class="btn btn-sm btn-success mr-3" @click.stop.prevent="openModal">
<font-awesome-icon :icon="['fas', 'plus']" />新增 <font-awesome-icon :icon="['fas', 'plus']" />新增
</button> </button>
<Modal id="outliers_add_table_item" title="異常設定" :open="open" :onCancel="closeModal" width="710"> <Modal
id="outliers_add_table_item"
title="異常設定"
:open="open"
:onCancel="closeModal"
:width="710"
>
<template #modalContent> <template #modalContent>
<form ref="form" class="mt-5 w-full flex flex-wrap justify-between"> <form ref="form" class="mt-5 w-full flex flex-wrap justify-between">
<Select :value="formState" class="my-2" selectClass="border-info focus-within:border-info" name="device_number" <Select
Attribute="device_name" :options="OptionsData.devList"> :value="formState"
class="my-2"
selectClass="border-info focus-within:border-info"
name="device_number"
Attribute="device_name"
:options="OptionsData.devList"
>
<template #topLeft>設備名稱</template> <template #topLeft>設備名稱</template>
<template #bottomLeft><span class="text-error text-base"> <template #bottomLeft
><span class="text-error text-base">
{{ formErrorMsg.device_number }} {{ formErrorMsg.device_number }}
</span></template> </span></template
>
</Select> </Select>
<Select :value="formState" class="my-2" selectClass="border-info focus-within:border-info" name="points" <Select
Attribute="full_name" :options="OptionsData.alarmPoints" :onChange="onPointsChange"> :value="formState"
class="my-2"
selectClass="border-info focus-within:border-info"
name="points"
Attribute="full_name"
:options="OptionsData.alarmPoints"
>
<template #topLeft>項目</template> <template #topLeft>項目</template>
<template #bottomLeft><span class="text-error text-base"> <template #bottomLeft
><span class="text-error text-base">
{{ formErrorMsg.points }} {{ formErrorMsg.points }}
</span></template> </span></template
>
</Select> </Select>
<RadioGroup class="my-2" name="enable" :value="formState" :items="[ <Select
:value="formState"
class="my-2"
selectClass="border-info focus-within:border-info"
name="factor"
Attribute="full_name"
:options="OptionsData.alarmFactors"
:onChange="onFactorsChange"
>
<template #topLeft>限定條件</template>
</Select>
<RadioGroup
class="my-2"
name="enable"
:value="formState"
:items="[
{ {
key: 1, key: 1,
value: 1, value: 1,
@ -155,51 +178,78 @@ const closeModal = () => {
value: 0, value: 0,
title: '不啟用', title: '不啟用',
}, },
]" :required="true"> ]"
:required="true"
>
<template #topLeft>狀態</template> <template #topLeft>狀態</template>
</RadioGroup> </RadioGroup>
<Select :value="formState" class="my-2" selectClass="border-info focus-within:border-info" name="schedule_id" <template v-if="factorNum == 2">
Attribute="schedule_name" :options="timesList">
<template #topLeft>警示時間</template>
<template #topRight><button v-if="formState.schedule_id" class="text-base btn-text-without-border"
@click="() => {formState.schedule_id = null}"><font-awesome-icon
:icon="['fas', 'times']"
class="text-[#a5abb1] me-1"
/></button></template>
</Select>
<Select :value="formState" class="my-2" selectClass="border-info focus-within:border-info" name="factor"
Attribute="full_name" :options="factorData" v-if="factorData.length !== 0">
<template #topLeft>限定條件</template>
</Select>
<div class="flex gap-4 w-full"> <div class="flex gap-4 w-full">
<InputNumber :value="formState" class="" name="highLimit" v-if="!isBool"> <InputNumber
:value="formState"
class=""
name="highLimit"
v-if="!isBool"
>
<template #topLeft>上限(>=)</template> <template #topLeft>上限(>=)</template>
</InputNumber> </InputNumber>
<InputNumber :value="formState" class="" name="lowLimit" v-if="!isBool"> <InputNumber
:value="formState"
class=""
name="lowLimit"
v-if="!isBool"
>
<template #topLeft>下限(&lt;=)</template> <template #topLeft>下限(&lt;=)</template>
</InputNumber> </InputNumber>
</div> </div>
<div class="flex gap-4 w-full"> <div class="flex gap-4 w-full">
<InputNumber :value="formState" class="my-2" name="highDelay" v-if="!isBool"> <InputNumber
:value="formState"
class="my-2"
name="highDelay"
v-if="!isBool"
>
<template #topLeft>上限持續秒數</template> <template #topLeft>上限持續秒數</template>
</InputNumber> </InputNumber>
<InputNumber :value="formState" class="my-2" name="lowDelay" v-if="!isBool"> <InputNumber
:value="formState"
class="my-2"
name="lowDelay"
v-if="!isBool"
>
<template #topLeft>下限持續秒數</template> <template #topLeft>下限持續秒數</template>
</InputNumber> </InputNumber>
</div> </div>
</template>
<template v-if="factorNum == 1">
<Input :value="formState" class="my-2" name="alarm_value">
<template #topLeft>警示值</template>
</Input>
</template>
<div class="w-full mt-5"> <div class="w-full mt-5">
<p class="text-light text-lg ml-1"> <p class="text-light text-lg ml-1">警示方式</p>
警示方式 <AlertNoticesTable
</p> :SaveCheckAuth="SaveCheckAuth"
<AlertNoticesTable :SaveCheckAuth="SaveCheckAuth" :NoticeData="noticeList" :onChange="onNoticesChange" /> :NoticeData="noticeList"
:onChange="onNoticesChange"
/>
</div> </div>
</form> </form>
</template> </template>
<template #modalAction> <template #modalAction>
<button type="reset" class="btn btn-outline-success mr-2" @click.prevent="closeModal"> <button
type="reset"
class="btn btn-outline-success mr-2"
@click.prevent="closeModal"
>
取消 取消
</button> </button>
<button type="submit" class="btn btn-outline-success" @click.prevent="onOk"> <button
type="submit"
class="btn btn-outline-success"
@click.prevent="onOk"
>
確定 確定
</button> </button>
</template> </template>

View File

@ -36,7 +36,7 @@ provide("notify_table", { timesList, noticeList, timesListData });
<template> <template>
<AlertSubList /> <AlertSubList />
<AlertOutliersTable /> <AlertOutliersTable />
<AlertTimeTable /> <!-- <AlertTimeTable /> -->
<AlertNotifyTable /> <AlertNotifyTable />
</template> </template>