新增告警日誌API整合,調整告警查詢邏輯與顯示,優化儀表板告警顯示
This commit is contained in:
parent
30b3cb586b
commit
a4e56a7e2d
24
src/App.vue
24
src/App.vue
@ -3,9 +3,12 @@ import { RouterView } from "vue-router";
|
||||
import Navbar from "./components/navbar/Navbar.vue";
|
||||
import useUserInfoStore from "@/stores/useUserInfoStore";
|
||||
import { ref, provide, onUnmounted, onMounted } from "vue";
|
||||
import { getAlertLog } from "@/apis/alert";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
const store = useUserInfoStore();
|
||||
|
||||
const alerts = ref([]);
|
||||
let isToastOpen = ref({
|
||||
open: false,
|
||||
content: "",
|
||||
@ -24,6 +27,16 @@ const cancelToastOpen = () => {
|
||||
};
|
||||
};
|
||||
|
||||
let alertInterval = null;
|
||||
const getAlert = async () => {
|
||||
const res = await getAlertLog({
|
||||
isRecovery: 1,
|
||||
Start_date: dayjs().subtract(30, "day").format("YYYY-MM-DD"),
|
||||
End_date: dayjs().format("YYYY-MM-DD"),
|
||||
});
|
||||
alerts.value = (res.data || []).map((d) => ({ ...d, key: d.id }));
|
||||
};
|
||||
|
||||
const openToast = (status, content, to = "body", confirm = null) => {
|
||||
isToastOpen.value = {
|
||||
open: true,
|
||||
@ -33,8 +46,19 @@ const openToast = (status, content, to = "body", confirm = null) => {
|
||||
confirm,
|
||||
};
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getAlert();
|
||||
alertInterval = setInterval(getAlert, 30 * 1000);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (alertInterval) clearInterval(alertInterval);
|
||||
});
|
||||
|
||||
provide("app_toast", { openToast, cancelToastOpen });
|
||||
provide("app_toggle", { forgeLock, toggleForgeLock });
|
||||
provide("app_alerts", alerts);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -1,5 +1,6 @@
|
||||
export const POST_ACK_API = `/obix/alarm`;
|
||||
export const GET_ALERT_FORMID_API = `/Alert/AlertList`;
|
||||
export const GET_ALERT_LOG_API = `api/Alarm/GetAlarmLog`;
|
||||
export const POST_OPERATION_RECORD_API = `/operation/SavOpeRecord`;
|
||||
|
||||
export const GET_ALERT_SUB_LIST_API = `api/Device/GetMainSub`;
|
||||
|
@ -1,6 +1,7 @@
|
||||
import {
|
||||
POST_ACK_API,
|
||||
GET_ALERT_FORMID_API,
|
||||
GET_ALERT_LOG_API,
|
||||
POST_OPERATION_RECORD_API,
|
||||
GET_ALERT_SUB_LIST_API,
|
||||
GET_OUTLIERS_LIST_API,
|
||||
@ -58,6 +59,24 @@ export const getAlertFormId = async (uuid) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const getAlertLog = async ({
|
||||
Start_date,
|
||||
End_date,
|
||||
isRecovery,
|
||||
device_name_tag,
|
||||
}) => {
|
||||
const res = await instance.post(GET_ALERT_LOG_API, {
|
||||
Start_date,
|
||||
End_date,
|
||||
isRecovery,
|
||||
device_name_tag,
|
||||
});
|
||||
return apihandler(res.code, res.data, {
|
||||
msg: res.msg,
|
||||
code: res.code,
|
||||
});
|
||||
};
|
||||
|
||||
export const postOperationRecord = async (formData) => {
|
||||
const res = await instance.post(POST_OPERATION_RECORD_API, formData);
|
||||
|
||||
|
@ -37,7 +37,6 @@ onMounted(() => {
|
||||
<div class="drawer drawer-end">
|
||||
<input id="alarm" type="checkbox" class="drawer-toggle" />
|
||||
<div class="drawer-content">
|
||||
<!-- Page content here -->
|
||||
<label
|
||||
for="alarm"
|
||||
class="drawer-button flex flex-col justify-center items-center btn-group"
|
||||
|
@ -85,15 +85,6 @@ const updateMeterPositionsLocal = () => {
|
||||
meterPositions.value = newPositions;
|
||||
};
|
||||
|
||||
// 監聽 meterList 變化
|
||||
watch(
|
||||
() => props.meterList,
|
||||
() => {
|
||||
updateMeterPositionsLocal();
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
const forgeDom = ref(null);
|
||||
|
||||
const initViewer = (container) => {
|
||||
@ -135,8 +126,6 @@ const initForge = () => {
|
||||
viewer.isLoadDone()
|
||||
);
|
||||
updateForgeViewer(viewer);
|
||||
// 初始化 meter 位置
|
||||
updateMeterPositionsLocal();
|
||||
}
|
||||
);
|
||||
|
||||
@ -199,7 +188,6 @@ onUnmounted(() => {
|
||||
>
|
||||
<p class="absolute z-10 top-14 left-[27%]">
|
||||
更新時間 : {{ props.realTime }}
|
||||
{{ searchParams?.option == 4 ? " (溫度)" : "" }}
|
||||
</p>
|
||||
<div v-show="searchParams?.option == 4" class="absolute z-10 heatbar">
|
||||
<div class="w-40 flex justify-between text-[10px] mb-1">
|
||||
|
@ -76,9 +76,9 @@ onMounted(() => {
|
||||
>
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<!-- <li>
|
||||
<AlarmDrawer />
|
||||
</li>
|
||||
</li> -->
|
||||
<li>
|
||||
<div class="dropdown dropdown-bottom dropdown-end">
|
||||
<button
|
||||
@ -149,7 +149,6 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.menu-box .btn-group span {
|
||||
color: #fff;
|
||||
display: block;
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
@ -1,14 +1,17 @@
|
||||
<script setup>
|
||||
import { onMounted, ref, watch, computed } from "vue";
|
||||
import { onMounted, ref, watch, computed, inject } from "vue";
|
||||
import { AUTHPAGES } from "@/constant";
|
||||
import { getAuth, getAllSysSidebar } from "@/apis/building";
|
||||
import useBuildingStore from "@/stores/useBuildingStore";
|
||||
import useUserInfoStore from "@/stores/useUserInfoStore";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
const store = useUserInfoStore();
|
||||
|
||||
const buildingStore = useBuildingStore();
|
||||
|
||||
const alerts = inject("app_alerts");
|
||||
const alarmslength = computed(() => (alerts?.value || []).length);
|
||||
const iniFroList = async () => {
|
||||
const res = await getAuth();
|
||||
|
||||
@ -57,25 +60,58 @@ onMounted(() => {
|
||||
v-if="$route.path !== page.navigate"
|
||||
:to="page.navigate"
|
||||
type="link"
|
||||
class="flex flex-col justify-center items-center btn-group text-white"
|
||||
class="flex flex-col justify-center items-center btn-group"
|
||||
>
|
||||
<font-awesome-icon
|
||||
:icon="['fas', page.icon]"
|
||||
size="2x"
|
||||
class="menu-icon"
|
||||
:class="
|
||||
twMerge(
|
||||
'menu-icon',
|
||||
page.showView === 'alert' && alarmslength > 0
|
||||
? 'text-red-500 animate-pulse'
|
||||
: 'text-white'
|
||||
)
|
||||
"
|
||||
/>
|
||||
<span
|
||||
:class="
|
||||
twMerge(
|
||||
page.showView === 'alert' && alarmslength > 0
|
||||
? 'text-red-200'
|
||||
: 'text-white'
|
||||
)
|
||||
"
|
||||
>
|
||||
{{ page.subName }}
|
||||
</span>
|
||||
</router-link>
|
||||
<div
|
||||
v-else
|
||||
class="flex flex-col justify-center items-center btn-group text-white router-link-active cursor-pointer"
|
||||
class="flex flex-col justify-center items-center btn-group router-link-active cursor-pointer"
|
||||
>
|
||||
<font-awesome-icon
|
||||
:icon="['fas', page.icon]"
|
||||
size="2x"
|
||||
class="menu-icon"
|
||||
/>
|
||||
:class="
|
||||
twMerge(
|
||||
'menu-icon',
|
||||
page.showView === 'alert' && alarmslength > 0
|
||||
? 'text-red-500 animate-pulse'
|
||||
: ''
|
||||
)
|
||||
"
|
||||
/><span
|
||||
:class="
|
||||
twMerge(
|
||||
page.showView === 'alert' && alarmslength > 0
|
||||
? 'text-red-200'
|
||||
: ''
|
||||
)
|
||||
"
|
||||
>
|
||||
{{ page.subName }}
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -4,12 +4,8 @@ import AlertTable from "./AlertTable.vue";
|
||||
import AlertTableModal from "./AlertTableModal.vue";
|
||||
import { ref, provide, onMounted, watch } from "vue";
|
||||
import useSearchParam from "@/hooks/useSearchParam";
|
||||
import useAlarmData from "@/hooks/baja/useAlarmData";
|
||||
import { getAlertLog } from "@/apis/alert";
|
||||
import {
|
||||
getAlertFormId,
|
||||
} from "@/apis/alert";
|
||||
import {
|
||||
getOperationDeviceList,
|
||||
getOperationCompanyList,
|
||||
getOperationEditRecord,
|
||||
} from "@/apis/operation";
|
||||
@ -17,14 +13,12 @@ import { getAccountUserList } from "@/apis/account";
|
||||
import useBuildingStore from "@/stores/useBuildingStore";
|
||||
|
||||
const { searchParams } = useSearchParam();
|
||||
const { getAlarmByBaja, alarmData } = useAlarmData();
|
||||
const store = useBuildingStore();
|
||||
|
||||
const tableLoading = ref(false);
|
||||
const dataSource = ref([]);
|
||||
const model_data = ref({
|
||||
model_userList: [],
|
||||
model_devList: [],
|
||||
model_companyList: [],
|
||||
});
|
||||
|
||||
@ -49,30 +43,6 @@ const updateEditRecord = (data) => {
|
||||
}
|
||||
};
|
||||
|
||||
const getFormId = async (uuid) => {
|
||||
const res = await getAlertFormId(uuid);
|
||||
return res.data;
|
||||
};
|
||||
|
||||
const getModalDevList = async () => {
|
||||
const sub_system_tags = searchParams.value.system_tag.map(tag => tag.split('_')[1]);
|
||||
const res = await getOperationDeviceList({
|
||||
list_sub_system_tag: sub_system_tags,
|
||||
device_building_tag: store.buildings[0].building_tag,
|
||||
device_area_tag: "NTPC",
|
||||
});
|
||||
|
||||
return res.data.map((d) => {
|
||||
const formattedKey = d.device_number
|
||||
.replace(/-/g, '_')
|
||||
.split('_')
|
||||
.slice(0, 8)
|
||||
.join('_');
|
||||
|
||||
return { ...d, key: formattedKey };
|
||||
});
|
||||
};
|
||||
|
||||
const getModalUserList = async () => {
|
||||
const res = await getAccountUserList({});
|
||||
return res.data.map((d) => ({ ...d, key: d.userinfo_guid }));
|
||||
@ -84,15 +54,12 @@ const getModalCompanyList = async () => {
|
||||
};
|
||||
|
||||
const getAllOptions = async () => {
|
||||
Promise.all([
|
||||
getModalDevList(),
|
||||
getModalUserList(),
|
||||
getModalCompanyList(),
|
||||
]).then(([devices, users, companies]) => {
|
||||
Promise.all([getModalUserList(), getModalCompanyList()]).then(
|
||||
([devices, users, companies]) => {
|
||||
model_data.value.model_userList = users;
|
||||
model_data.value.model_devList = devices;
|
||||
model_data.value.model_companyList = companies;
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const updateDataSource = (data) => {
|
||||
@ -100,38 +67,13 @@ const updateDataSource = (data) => {
|
||||
};
|
||||
|
||||
const search = async () => {
|
||||
if (Object.keys(searchParams.value).length !== 0) {
|
||||
tableLoading.value = true;
|
||||
await getAlarmByBaja(
|
||||
searchParams.value.start_created_at,
|
||||
searchParams.value.end_created_at,
|
||||
searchParams.value.isRecover,
|
||||
searchParams.value.isAck,
|
||||
searchParams.value.system_tag,
|
||||
async (result) => {
|
||||
alarmData.value = result.data;
|
||||
// 確保所有 alarm 都包含 formId
|
||||
alarmData.value = alarmData.value.map(alarm => ({
|
||||
...alarm,
|
||||
formId: null // 初始設置 formId 為 null
|
||||
}));
|
||||
|
||||
const uuids = alarmData.value.map(alarm => ({ uuid: alarm.uuid }));
|
||||
const formIds = await getFormId(uuids);
|
||||
|
||||
if (Array.isArray(formIds)) {
|
||||
formIds.forEach((form) => {
|
||||
if (form && form.uuid) {
|
||||
const index = alarmData.value.findIndex(alarm => alarm.uuid === form.uuid);
|
||||
if (index !== -1) {
|
||||
alarmData.value[index].formId = form.formId || null;
|
||||
}
|
||||
}
|
||||
if (Object.keys(searchParams.value).length !== 0) {
|
||||
const res = await getAlertLog({
|
||||
...searchParams.value,
|
||||
isRecovery: Number(searchParams.value.isRecovery),
|
||||
});
|
||||
};
|
||||
updateDataSource(alarmData.value);
|
||||
}
|
||||
);
|
||||
dataSource.value = (res.data || []).map((d) => ({ ...d, key: d.id }));
|
||||
tableLoading.value = false;
|
||||
}
|
||||
};
|
||||
@ -140,11 +82,17 @@ const openModal = async (record) => {
|
||||
try {
|
||||
if (record.formId) {
|
||||
const res = await getOperationEditRecord(record.formId);
|
||||
updateEditRecord({ ...res.data, uuid: record.uuid });
|
||||
updateEditRecord({
|
||||
...res.data,
|
||||
uuid: res.data.error_code,
|
||||
device_number: record.device_number,
|
||||
});
|
||||
} else {
|
||||
updateEditRecord(record);
|
||||
updateEditRecord({
|
||||
...record,
|
||||
uuid: record.id,
|
||||
});
|
||||
}
|
||||
await getAllOptions();
|
||||
alert_action_item.showModal();
|
||||
} catch (error) {
|
||||
console.error("Error opening modal:", error);
|
||||
@ -153,20 +101,18 @@ const openModal = async (record) => {
|
||||
|
||||
watch(
|
||||
() => ({
|
||||
isAck: searchParams.value.isAck,
|
||||
isRecover: searchParams.value.isRecover,
|
||||
Start_date: searchParams.value.start_created_at,
|
||||
End_date: searchParams.value.end_created_at,
|
||||
system_tag: searchParams.value.system_tag,
|
||||
isRecovery: searchParams.value.isRecovery,
|
||||
Start_date: searchParams.value.Start_date,
|
||||
End_date: searchParams.value.End_date,
|
||||
device_name_tag: searchParams.value.device_name_tag,
|
||||
}),
|
||||
(val) => {
|
||||
// 判斷所有必要欄位都已經有值
|
||||
if (
|
||||
val.isAck !== undefined &&
|
||||
val.isRecover !== undefined &&
|
||||
val.isRecovery !== undefined &&
|
||||
val.Start_date &&
|
||||
val.End_date &&
|
||||
val.system_tag
|
||||
val.device_name_tag
|
||||
) {
|
||||
search();
|
||||
}
|
||||
@ -175,7 +121,13 @@ watch(
|
||||
);
|
||||
|
||||
provide("alert_modal", { model_data, search, updateEditRecord });
|
||||
provide("alert_table", { openModal, updateEditRecord, dataSource, search, tableLoading });
|
||||
provide("alert_table", {
|
||||
openModal,
|
||||
updateEditRecord,
|
||||
dataSource,
|
||||
search,
|
||||
tableLoading,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -1,7 +1,6 @@
|
||||
<script setup>
|
||||
import { inject } from "vue";
|
||||
import AlertSearchNormalBtns from "./AlertSearchNormalBtns.vue";
|
||||
import AlertSearchAckBtns from "./AlertSearchAckBtns.vue";
|
||||
import AlertSearchTimeRange from "./AlertSearchTimeRange.vue";
|
||||
import AlertSearchTypesButton from "./AlertSearchTypesButton.vue";
|
||||
|
||||
@ -13,7 +12,6 @@ const { search } = inject("alert_table");
|
||||
<div class="w-full flex flex-wrap flex-col custom-border px-4 pt-0 pb-4 mb-4">
|
||||
<div class="w-full flex flex-wrap items-center justify-start">
|
||||
<AlertSearchNormalBtns />
|
||||
<AlertSearchAckBtns />
|
||||
<AlertSearchTimeRange />
|
||||
<button class="btn btn-success ml-8" @click.stop.prevent="search">查詢</button>
|
||||
</div>
|
||||
|
@ -29,7 +29,7 @@ onMounted(() => {
|
||||
watch(
|
||||
selectedBtn,
|
||||
(newValue) => {
|
||||
changeParams({ ...searchParams.value, isAck: newValue.key });
|
||||
changeParams({ ...searchParams.value });
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -11,12 +11,12 @@ onMounted(() => {
|
||||
setItems([
|
||||
{
|
||||
title: "未復歸",
|
||||
key: "offnormal",
|
||||
key: 1,
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
title: "已賦歸",
|
||||
key: "normal",
|
||||
key: 2,
|
||||
active: false,
|
||||
},
|
||||
]);
|
||||
@ -27,7 +27,7 @@ onMounted(() => {
|
||||
watch(
|
||||
selectedBtn,
|
||||
(newValue) => {
|
||||
changeParams({ ...searchParams.value, isRecover: newValue.key });
|
||||
changeParams({ ...searchParams.value, isRecovery: newValue.key });
|
||||
}
|
||||
);
|
||||
|
||||
@ -35,8 +35,8 @@ watch(
|
||||
watch(
|
||||
searchParams,
|
||||
(newSearchParams) => {
|
||||
if (!newSearchParams.isRecover) {
|
||||
changeParams({ ...newSearchParams, isRecover: "offnormal" });
|
||||
if (!newSearchParams.isRecovery) {
|
||||
changeParams({ ...newSearchParams, isRecovery: 1 });
|
||||
}
|
||||
},
|
||||
{ immediate: true } // 確保在初始化立即觸發
|
||||
|
@ -8,13 +8,17 @@ const { searchParams, changeParams } = useSearchParam();
|
||||
const dateRange = ref([
|
||||
{
|
||||
key: "start_at",
|
||||
value: searchParams.value.start_created_at ? dayjs(searchParams.value.start_created_at).valueOf() : dayjs().subtract(30, 'day').valueOf(),
|
||||
value: searchParams.value.Start_date
|
||||
? dayjs(searchParams.value.Start_date)
|
||||
: dayjs().subtract(30, "day"),
|
||||
dateFormat: "yyyy-MM-dd",
|
||||
placeholder: "起始日期",
|
||||
},
|
||||
{
|
||||
key: "end_at",
|
||||
value: searchParams.value.end_created_at ? dayjs(searchParams.value.end_created_at).valueOf() : dayjs().valueOf(),
|
||||
value: searchParams.value.End_date
|
||||
? dayjs(searchParams.value.End_date)
|
||||
: dayjs(),
|
||||
dateFormat: "yyyy-MM-dd",
|
||||
placeholder: "結束日期",
|
||||
},
|
||||
@ -24,13 +28,13 @@ const changeTimeRange = () => {
|
||||
const newRange = [
|
||||
{
|
||||
key: "start_at",
|
||||
value: dayjs().subtract(30, 'day').startOf('day').valueOf(), // 向前推30天並設置為當天的00:00:00.000
|
||||
value: dayjs().subtract(30, "day"),
|
||||
dateFormat: "yyyy-MM-dd",
|
||||
placeholder: "起始日期",
|
||||
},
|
||||
{
|
||||
key: "end_at",
|
||||
value: dayjs().endOf('day').valueOf(), // 設置為今日的23:59:59.999
|
||||
value: dayjs().endOf("day"),
|
||||
dateFormat: "yyyy-MM-dd",
|
||||
placeholder: "結束日期",
|
||||
},
|
||||
@ -40,14 +44,17 @@ const changeTimeRange = () => {
|
||||
|
||||
changeParams({
|
||||
...searchParams.value,
|
||||
start_created_at: newRange[0].value,
|
||||
end_created_at: newRange[1].value,
|
||||
Start_date: newRange[0].value,
|
||||
End_date: newRange[1].value,
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
// 初始化日期範圍
|
||||
if (!searchParams.value.start_created_at || !searchParams.value.end_created_at) {
|
||||
if (
|
||||
!searchParams.value.Start_date ||
|
||||
!searchParams.value.End_date
|
||||
) {
|
||||
changeTimeRange();
|
||||
}
|
||||
});
|
||||
@ -58,8 +65,8 @@ watch(
|
||||
() => {
|
||||
changeParams({
|
||||
...searchParams.value,
|
||||
start_created_at: dayjs(dateRange.value[0].value).startOf('day').valueOf(),
|
||||
end_created_at: dayjs(dateRange.value[1].value).endOf('day').valueOf(),
|
||||
Start_date: dayjs(dateRange.value[0].value).format("YYYY-MM-DD"),
|
||||
End_date: dayjs(dateRange.value[1].value).format("YYYY-MM-DD"),
|
||||
});
|
||||
},
|
||||
{ deep: true } // 確保在初始化立即觸發
|
||||
|
@ -11,12 +11,12 @@ const changeCheckedItem = () => {
|
||||
if (checkedItem.value.length === store.subSys.length) {
|
||||
changeParams({
|
||||
...searchParams.value,
|
||||
system_tag: [store.subSys[0]?.main_system_tag+`_`+store.subSys[0]?.sub_system_tag],
|
||||
device_name_tag: [store.subSys[0]?.sub_system_tag],
|
||||
});
|
||||
} else {
|
||||
changeParams({
|
||||
...searchParams.value,
|
||||
system_tag: store.subSys.map(({ main_system_tag, sub_system_tag }) => main_system_tag+`_`+sub_system_tag),
|
||||
device_name_tag: store.subSys.map(({ sub_system_tag }) => sub_system_tag),
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -25,16 +25,16 @@ const onChange = (value, checked) => {
|
||||
if (checked) {
|
||||
changeParams({
|
||||
...searchParams.value,
|
||||
system_tag: searchParams.value.system_tag
|
||||
? typeof searchParams.value.system_tag === "string"
|
||||
? [searchParams.value.system_tag, value]
|
||||
: [...searchParams.value.system_tag, value]
|
||||
device_name_tag: searchParams.value.device_name_tag
|
||||
? typeof searchParams.value.device_name_tag === "string"
|
||||
? [searchParams.value.device_name_tag, value]
|
||||
: [...searchParams.value.device_name_tag, value]
|
||||
: [value],
|
||||
});
|
||||
} else {
|
||||
changeParams({
|
||||
...searchParams.value,
|
||||
sub_system_tag: searchParams.value.system_tag.filter(
|
||||
device_name_tag: searchParams.value.device_name_tag.filter(
|
||||
(sub) => sub !== value
|
||||
),
|
||||
});
|
||||
@ -42,18 +42,18 @@ const onChange = (value, checked) => {
|
||||
};
|
||||
|
||||
const checkedItem = computed(() =>
|
||||
searchParams.value.system_tag
|
||||
? typeof searchParams.value.system_tag === "string"
|
||||
? [searchParams.value.system_tag]
|
||||
: searchParams.value.system_tag
|
||||
searchParams.value.device_name_tag
|
||||
? typeof searchParams.value.device_name_tag === "string"
|
||||
? [searchParams.value.device_name_tag]
|
||||
: searchParams.value.device_name_tag
|
||||
: []
|
||||
);
|
||||
|
||||
watch(searchParams, (newValue) => {
|
||||
if (!newValue.system_tag) {
|
||||
if (!newValue.device_name_tag) {
|
||||
changeParams({
|
||||
...newValue,
|
||||
system_tag: store.subSys.map(({ main_system_tag, sub_system_tag }) => main_system_tag+`_`+sub_system_tag),
|
||||
device_name_tag: store.subSys.map(({ sub_system_tag }) => sub_system_tag),
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -71,8 +71,8 @@ watch(searchParams, (newValue) => {
|
||||
v-for="sub in store.subSys"
|
||||
:key="sub.key"
|
||||
:title="sub.full_name"
|
||||
:value="sub.main_system_tag+`_`+sub.sub_system_tag"
|
||||
:checked="checkedItem.includes(sub.main_system_tag+`_`+sub.sub_system_tag)"
|
||||
:value="sub.sub_system_tag"
|
||||
:checked="checkedItem.includes(sub.sub_system_tag)"
|
||||
class="mx-3 my-3 xl:my-0 text-lg"
|
||||
:onChange="onChange"
|
||||
/>
|
||||
|
@ -1,48 +1,34 @@
|
||||
<script setup>
|
||||
import { inject } from "vue";
|
||||
import {
|
||||
postChgAck,
|
||||
} from "@/apis/alert";
|
||||
import { postChgAck } from "@/apis/alert";
|
||||
import { Button } from "ant-design-vue";
|
||||
const { dataSource, openModal, search, tableLoading } = inject("alert_table");
|
||||
|
||||
const columns = [
|
||||
{
|
||||
key: "building_tag",
|
||||
title: "棟別-樓層",
|
||||
},
|
||||
{
|
||||
key: "uuid",
|
||||
key: "alarm_guid",
|
||||
title: "異常ID",
|
||||
},
|
||||
{
|
||||
key: "alarmClass",
|
||||
title: "異常類別",
|
||||
},
|
||||
{
|
||||
key: "full_name",
|
||||
title: "維修項目",
|
||||
key: "factor",
|
||||
title: "告警條件",
|
||||
},
|
||||
{
|
||||
key: "device_number",
|
||||
title: "設備編號",
|
||||
title: "設備名稱",
|
||||
},
|
||||
{
|
||||
key: "timestamp_date",
|
||||
title: "發生日期",
|
||||
key: "points",
|
||||
title: "點位名稱",
|
||||
},
|
||||
{
|
||||
key: "timestamp_time",
|
||||
key: "created_at",
|
||||
title: "發生時間",
|
||||
},
|
||||
{
|
||||
key: "msg",
|
||||
key: "reason",
|
||||
title: "異常原因",
|
||||
},
|
||||
{
|
||||
key: "ackState",
|
||||
title: "Ack 確認",
|
||||
},
|
||||
{
|
||||
key: "repairOrder",
|
||||
title: "派工 / 維運單號",
|
||||
@ -55,25 +41,16 @@ const chgAck = async (devUuid) => {
|
||||
search?.();
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Table :loading="tableLoading" :columns="columns" :dataSource="dataSource">
|
||||
<template #bodyCell="{ record, column, index }">
|
||||
<template v-if="column.key === 'ackState'">
|
||||
<template v-if="record.ackState === 'Unacked'">
|
||||
<button class="btn btn-sm btn-success text-white whitespace-nowrap mr-2" @click.stop.prevent="() => chgAck(record.uuid)">
|
||||
未確認
|
||||
</button>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ record.ackedTime }}
|
||||
</template>
|
||||
</template>
|
||||
<template v-if="column.key === 'repairOrder'">
|
||||
<button class="btn btn-sm btn-success text-white whitespace-nowrap mr-2"
|
||||
@click.stop.prevent="() => openModal(record)">
|
||||
<button
|
||||
class="btn btn-sm btn-success text-white whitespace-nowrap mr-2"
|
||||
@click.stop.prevent="() => openModal(record)"
|
||||
>
|
||||
<span v-if="record.formId">{{ record.formId }}</span>
|
||||
<span v-else>
|
||||
<font-awesome-icon :icon="['fas', 'plus']" />維修單
|
||||
|
@ -29,12 +29,13 @@ const dateItem = ref([
|
||||
const formState = ref(
|
||||
{
|
||||
formId: null,
|
||||
uuid: "",
|
||||
alarm_guid: "",
|
||||
work_type: 2,
|
||||
fix_do: "",
|
||||
fix_do_code: "",
|
||||
fix_firm: "",
|
||||
status: 0,
|
||||
device_number: "",
|
||||
work_person_id: "",
|
||||
start_time: dayjs().format("YYYY-MM-DD"),
|
||||
notice: "",
|
||||
@ -87,7 +88,7 @@ const onOk = async () => {
|
||||
|
||||
props.editRecord.id && formData.append("id", props.editRecord.id);
|
||||
|
||||
props.editRecord.uuid && formData.append("error_code", props.editRecord.uuid);
|
||||
props.editRecord.alarm_guid && formData.append("error_code", props.editRecord.alarm_guid);
|
||||
|
||||
formData.append("work_type", 2);
|
||||
|
||||
@ -112,12 +113,13 @@ const onOk = async () => {
|
||||
const onCancel = () => {
|
||||
formState.value = {
|
||||
formId: null,
|
||||
uuid: "",
|
||||
alarm_guid: "",
|
||||
work_type: 2,
|
||||
fix_do: "",
|
||||
fix_do_code: "",
|
||||
fix_firm: "",
|
||||
status: 0,
|
||||
device_number: "",
|
||||
work_person_id: "",
|
||||
start_time: dayjs().format("YYYY-MM-DD"),
|
||||
notice: "",
|
||||
@ -143,10 +145,6 @@ watch(
|
||||
formState.value.start_time = value ? dayjs(value).format("YYYY-MM-DD") : dayjs().format("YYYY-MM-DD");
|
||||
dateItem.value[0].value = value;
|
||||
}
|
||||
// 維修項目
|
||||
if (key === "full_name") {
|
||||
formState.value.fix_do = value;
|
||||
}
|
||||
// 維修項目代碼
|
||||
if (key === "device_number" || key === "fix_do_code") {
|
||||
formState.value.fix_do_code = value;
|
||||
@ -165,8 +163,8 @@ watch(
|
||||
<Input v-if="formState.value && formState.value.formId" class="my-2" :value="formState" name="formId" readonly>
|
||||
<template #topLeft>表單編號</template>
|
||||
</Input>
|
||||
<Input :value="formState" class="my-2" name="uuid" readonly>
|
||||
<template #topLeft>異常編號</template>
|
||||
<Input :value="formState" class="my-2" name="alarm_guid" readonly>
|
||||
<template #topLeft>異常ID</template>
|
||||
</Input>
|
||||
<DateGroup class="my-2" :items="dateItem" inputClass="w-full shadow-none" :required="true">
|
||||
<template #topLeft>預計開始時間</template>
|
||||
@ -191,20 +189,25 @@ watch(
|
||||
]" :required="true" :disabled="true">
|
||||
<template #topLeft>項目</template>
|
||||
</Select>
|
||||
<Input class="my-2" :value="formState" name="fix_do" :required="true" readonly>
|
||||
<Input class="my-2" :value="formState" name="fix_do" :required="true">
|
||||
<template #topLeft>維修項目</template>
|
||||
<template #bottomLeft><span class="text-error text-base">
|
||||
{{ formErrorMsg.fix_do }}
|
||||
</span>
|
||||
</template>
|
||||
</Input>
|
||||
<Select :value="formState" class="my-2" selectClass="border-info focus-within:border-info" name="fix_do_code"
|
||||
Attribute="full_name" :options="model_data.model_devList" :required="true" :disabled="true">
|
||||
<template #topLeft>維修項目代碼(設備編號)</template>
|
||||
<Input
|
||||
class="my-2"
|
||||
:value="formState"
|
||||
name="device_number"
|
||||
:required="true"
|
||||
:disabled="true"
|
||||
>
|
||||
<template #topLeft>設備名稱</template>
|
||||
<template #bottomLeft><span class="text-error text-base">
|
||||
{{ formErrorMsg.fix_do_code }}
|
||||
</span></template>
|
||||
</Select>
|
||||
</Input>
|
||||
<Select :value="formState" class="my-2" selectClass="border-info focus-within:border-info" name="fix_firm"
|
||||
Attribute="name" :options="model_data.model_companyList" :required="true">
|
||||
<template #topLeft>負責廠商</template>
|
||||
|
@ -1,47 +1,14 @@
|
||||
<script setup>
|
||||
import useAlarmStore from "@/stores/useAlarmStore";
|
||||
import dayjs from "dayjs";
|
||||
import { ref,computed } from "vue";
|
||||
|
||||
const store = useAlarmStore();
|
||||
// const alarms = computed(() =>
|
||||
// store.alarmData.slice(0, 5).map((d) => ({
|
||||
// ...d,
|
||||
// timestamp_date: dayjs(d.timestamp_date).format("YYYY.MM.DD"),
|
||||
// timestamp_time: d.timestamp_time.split(":").slice(0, 2).join(":"),
|
||||
// }))
|
||||
// );
|
||||
|
||||
const alarms = ref([
|
||||
{
|
||||
uuid: 1,
|
||||
timestamp_date: "2020-01-02",
|
||||
timestamp_time: "11:02",
|
||||
msg: "xx異常",
|
||||
status: "處理中",
|
||||
},
|
||||
{
|
||||
uuid: 2,
|
||||
timestamp_date: "2020-01-03",
|
||||
timestamp_time: "12:02",
|
||||
msg: "xx異常",
|
||||
status: "已處理",
|
||||
},
|
||||
{
|
||||
uuid: 3,
|
||||
timestamp_date: "2020-01-04",
|
||||
timestamp_time: "13:02",
|
||||
msg: "xx異常",
|
||||
status: "已處理",
|
||||
},
|
||||
{
|
||||
uuid: 4,
|
||||
timestamp_date: "2020-01-05",
|
||||
timestamp_time: "14:02",
|
||||
msg: "xx異常",
|
||||
status: "處理中",
|
||||
},
|
||||
]);
|
||||
import { ref, computed, inject } from "vue";
|
||||
const alerts = inject("app_alerts");
|
||||
const alarms = computed(() =>
|
||||
(alerts.value || []).slice(0, 5).map((d) => ({
|
||||
...d,
|
||||
timestamp_date: dayjs(d.created_at).format("YYYY.MM.DD"),
|
||||
timestamp_time: dayjs(d.created_at).format("HH:mm:ss"),
|
||||
})).sort((a, b) => (dayjs(a.created_at).isBefore(dayjs(b.created_at)) ? 1 : -1))
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -54,17 +21,22 @@ const alarms = ref([
|
||||
<tr class="">
|
||||
<th>日期</th>
|
||||
<th>時間</th>
|
||||
<th>備註</th>
|
||||
<th>狀態</th>
|
||||
<th>設備名稱</th>
|
||||
<th>異常原因</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-base">
|
||||
<tr>
|
||||
<tr v-if="alarms.length === 0">
|
||||
<td colspan="4" class="text-center h-40">
|
||||
<!-- <span>無資料</span> -->
|
||||
<div class="text-gray-400">目前無告警訊息</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr v-else v-for="alarm in alarms" :key="alarm.alarm_guid">
|
||||
<td>{{ alarm.timestamp_date }}</td>
|
||||
<td>{{ alarm.timestamp_time }}</td>
|
||||
<td>{{ alarm.device_number }}</td>
|
||||
<td>{{ alarm.reason }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user