diff --git a/src/stores/useBuildingStore.js b/src/stores/useBuildingStore.js
index 63692d6..40307a0 100644
--- a/src/stores/useBuildingStore.js
+++ b/src/stores/useBuildingStore.js
@@ -123,6 +123,7 @@ const useBuildingStore = defineStore("buildingInfo", () => {
fetchDepartmentList,
getSubMonitorPage,
initialize,
+ getSysConfig,
};
});
export default useBuildingStore;
diff --git a/src/views/dashboard/Dashboard.vue b/src/views/dashboard/Dashboard.vue
index f7c633a..45978fb 100644
--- a/src/views/dashboard/Dashboard.vue
+++ b/src/views/dashboard/Dashboard.vue
@@ -4,16 +4,16 @@ import DashboardEffectScatter from "./components/DashboardEffectScatter.vue";
import DashboardSysCard from "./components/DashboardSysCard.vue";
import DashboardProduct from "./components/DashboardProduct.vue";
import DashboardProductComplete from "./components/DashboardProductComplete.vue";
-import DashboardTemp from "./components/DashboardTemp.vue";
-import DashboardHumidity from "./components/DashboardHumidity.vue";
-import DashboardRefrigTemp from "./components/DashboardRefrigTemp.vue";
-import DashboardIndoorTemp from "./components/DashboardIndoorTemp.vue";
+import DashboardIndoor from "./components/DashboardIndoor.vue";
+// import DashboardRefrigTemp from "./components/DashboardRefrigTemp.vue";
+// import DashboardIndoorTemp from "./components/DashboardIndoorTemp.vue";
import DashboardElectricity from "./components/DashboardElectricity.vue";
import DashboardEmission from "./components/DashboardEmission.vue";
import DashboardAlert from "./components/DashboardAlert.vue";
import { computed, inject, ref, watch, onMounted, onUnmounted } from "vue";
import useBuildingStore from "@/stores/useBuildingStore";
import { getSystemDevices, getSystemRealTime } from "@/apis/system";
+import DashboardRefrig from "./components/DashboardRefrig.vue";
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
const buildingStore = useBuildingStore()
@@ -135,10 +135,10 @@ onUnmounted(() => {
+import LineChart from "@/components/chart/LineChart.vue";
+import { SECOND_CHART_COLOR } from "@/constant";
+import dayjs from "dayjs";
+import { ref, watch, onUnmounted, computed } from "vue";
+import useActiveBtn from "@/hooks/useActiveBtn";
+import { getDashboardTemp } from "@/apis/dashboard";
+import useSearchParams from "@/hooks/useSearchParam";
+import useBuildingStore from "@/stores/useBuildingStore";
+import { useI18n } from "vue-i18n";
+
+const { t, locale } = useI18n();
+const { searchParams } = useSearchParams();
+const buildingStore = useBuildingStore();
+const timeoutTimer = ref(null); // 定時器參考
+
+const { items, changeActiveBtn, setItems, selectedBtn } = useActiveBtn();
+
+const allTempData = ref([]);
+const currentOptionType = ref(1); // 當前顯示類型:1 = 溫度,2 = 濕度
+const noData = ref(false); // 無資料顯示控制
+const indoorChartRef = ref(null);
+
+// 確認是否有資料,無則不呼叫 getDashboardTemp 也不顯示 chart
+watch(
+ () => buildingStore.selectedBuilding?.building_guid,
+ async (guid) => {
+ if (!guid) return;
+
+ await buildingStore.getSysConfig(guid);
+ const showRoom = buildingStore.sysConfig?.value?.show_room;
+
+ if (timeoutTimer.value) clearInterval(timeoutTimer.value);
+
+ if (showRoom === false) {
+ noData.value = true;
+ return; // 不呼叫 getData
+ }
+
+ // 允許顯示圖表+呼叫資料
+ noData.value = false;
+ getData();
+ timeoutTimer.value = setInterval(getData, 60000); // 每分鐘自動更新
+ },
+ { immediate: true }
+);
+
+// 預設圖表設定
+const defaultChartOption = ref({
+ tooltip: { trigger: "axis" },
+ legend: {
+ data: [],
+ textStyle: { color: "#ffffff", fontSize: 16 },
+ },
+ grid: {
+ top: "10%",
+ left: "0%",
+ right: "0%",
+ bottom: "0%",
+ containLabel: true,
+ },
+ xAxis: {
+ type: "category",
+ splitLine: { show: false },
+ axisLabel: { color: "#ffffff" },
+ data: [],
+ },
+ yAxis: {
+ type: "value",
+ splitLine: { show: false },
+ axisLabel: { color: "#ffffff" },
+ },
+ series: [],
+});
+
+const getData = async () => {
+ const buildingGuid = buildingStore.selectedBuilding?.building_guid;
+ if (!buildingGuid) return;
+
+ try {
+ const res = await getDashboardTemp({
+ building_guid: buildingGuid,
+ tempOption: 1, // 室溫區域
+ timeInterval: 1,
+ option: currentOptionType.value,
+ });
+
+ const key = "室溫";
+ allTempData.value = res.isSuccess ? res.data?.[key] ?? [] : [];
+ noData.value = allTempData.value.length === 0;
+ } catch (e) {
+ console.error("getDashboardTemp error", e);
+ allTempData.value = [];
+ noData.value = true;
+ }
+};
+
+// 溫度與濕度切換按鈕
+const buttonItems = computed(() => [
+ { key: 1, title: t("dashboard.temperature"), active: true },
+ { key: 2, title: t("dashboard.humidity"), active: false },
+]);
+
+// 多語系切換時更新按鈕文字
+watch(
+ () => locale.value,
+ () => setItems(buttonItems.value),
+ { immediate: true }
+);
+
+// 切換溫度/濕度按鈕後更新資料與啟動定時器
+// 切換溫度/濕度按鈕
+watch(
+ selectedBtn,
+ (newVal) => {
+ if ([1, 2].includes(newVal?.key)) {
+ currentOptionType.value = newVal.key;
+
+ // 再次確認 show_room 為 true 才重新取資料
+ if (buildingStore.sysConfig?.value?.show_room) {
+ getData();
+ if (timeoutTimer.value) clearInterval(timeoutTimer.value);
+ timeoutTimer.value = setInterval(getData, 60000);
+ }
+ }
+ },
+ { immediate: true, deep: true }
+);
+
+// 設定資料點顯示數量
+function sampleData(data = [], maxCount = 30) {
+ const len = data.length;
+ if (len <= maxCount) return data;
+
+ const sampled = [];
+ const step = (len - 1) / (maxCount - 1);
+
+ for (let i = 0; i < maxCount; i++) {
+ const index = Math.round(i * step);
+ sampled.push(data[index]);
+ }
+
+ return sampled;
+}
+
+// 更新圖表資料
+watch(
+ allTempData,
+ (newVal) => {
+ if (!newVal?.length || !indoorChartRef.value?.chart) return;
+
+ const firstValid = newVal.find((d) => d.data?.length);
+ if (!firstValid) return;
+
+ const sampledXAxis = sampleData(firstValid.data).map(({ time }) =>
+ dayjs(time).format("HH:mm:ss")
+ );
+
+ const allValues = newVal
+ .flatMap((d) => sampleData(d.data))
+ .map((d) => d.value)
+ .filter((v) => v != null);
+
+ if (!allValues.length) return;
+
+ const minVal = Math.min(...allValues);
+ const maxVal = Math.max(...allValues);
+
+ const yMin = Math.floor(minVal) - 1;
+ const yMax = Math.ceil(maxVal) + 1;
+
+ indoorChartRef.value.chart.setOption({
+ legend: {
+ data: newVal.map((d) => d.full_name),
+ },
+ xAxis: {
+ data: sampledXAxis,
+ },
+ yAxis: {
+ min: yMin,
+ max: yMax,
+ },
+ series: newVal.map((d, i) => ({
+ name: d.full_name,
+ type: "line",
+ data: sampleData(d.data).map(({ value }) => value),
+ showSymbol: false,
+ itemStyle: {
+ color: SECOND_CHART_COLOR[i % SECOND_CHART_COLOR.length],
+ },
+ })),
+ });
+ },
+ { deep: true }
+);
+// 離開元件時清除定時器
+onUnmounted(() => {
+ if (timeoutTimer.value) clearInterval(timeoutTimer.value);
+});
+
+
+
+
+ {{ $t("dashboard.indoor_chart") }}
+
+
+
+
+
+ {{ $t("dashboard.no_data") }}
+
+
+
+
+
diff --git a/src/views/dashboard/components/DashboardRefrig.vue b/src/views/dashboard/components/DashboardRefrig.vue
new file mode 100644
index 0000000..8e8538e
--- /dev/null
+++ b/src/views/dashboard/components/DashboardRefrig.vue
@@ -0,0 +1,228 @@
+
+
+
+
+ {{ $t("dashboard.refrig_chart") }}
+
+
+
+
+
+ {{ $t("dashboard.no_data") }}
+
+
+
+
+