fix: 以 systemConfig 判斷 Dashboard 左上生產指標顯示

This commit is contained in:
MJM_2025_05\polly 2025-08-11 11:22:25 +08:00
parent 94568c3f86
commit d88dfe3c85
5 changed files with 191 additions and 79 deletions

View File

@ -15,12 +15,15 @@ import useBuildingStore from "@/stores/useBuildingStore";
import { getSystemDevices, getSystemRealTime } from "@/apis/system"; import { getSystemDevices, getSystemRealTime } from "@/apis/system";
import DashboardRefrig from "./components/DashboardRefrig.vue"; import DashboardRefrig from "./components/DashboardRefrig.vue";
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL; const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
const buildingStore = useBuildingStore() const buildingStore = useBuildingStore();
const subscribeData = ref([]); const subscribeData = ref([]);
const systemData = ref({}); const systemData = ref({});
let intervalId = null; let intervalId = null;
const productVisible = ref(false); //
const productCompleteVisible = ref(false); //
// //
const startInterval = () => { const startInterval = () => {
// //
@ -37,21 +40,21 @@ const startInterval = () => {
const getData = async () => { const getData = async () => {
const res = await getSystemDevices({ const res = await getSystemDevices({
building_guid: buildingStore.selectedBuilding?.building_guid, building_guid: buildingStore.selectedBuilding?.building_guid,
}) });
subscribeData.value = res.data subscribeData.value = res.data;
console.log("devices", subscribeData.value) console.log("devices", subscribeData.value);
// //
const transformedData = {}; const transformedData = {};
subscribeData.value.forEach(floor => { subscribeData.value.forEach((floor) => {
if (floor.device_list && floor.device_list.length > 0) { if (floor.device_list && floor.device_list.length > 0) {
const fullUrl = floor.floor_map_name; const fullUrl = floor.floor_map_name;
const uuid = fullUrl ? fullUrl.replace(/\.svg$/, "") : ""; const uuid = fullUrl ? fullUrl.replace(/\.svg$/, "") : "";
transformedData[uuid] = floor.device_list.map(device => { transformedData[uuid] = floor.device_list.map((device) => {
// //
const coordinates = JSON.parse(device.device_coordinate || '[0,0]'); const coordinates = JSON.parse(device.device_coordinate || "[0,0]");
const x = coordinates[0]; const x = coordinates[0];
const y = coordinates[1]; const y = coordinates[1];
@ -59,7 +62,10 @@ const getData = async () => {
let state = "Online"; let state = "Online";
let bgColor = device.device_normal_color; let bgColor = device.device_normal_color;
if (device.device_status === "Offline" || device.device_status === null) { if (
device.device_status === "Offline" ||
device.device_status === null
) {
state = "Offline"; state = "Offline";
bgColor = device.device_close_color; bgColor = device.device_close_color;
} }
@ -80,7 +86,9 @@ const getData = async () => {
points: device.points || [], points: device.points || [],
floor: floor.full_name, floor: floor.full_name,
state: state, state: state,
icon: device.device_image ? `${FILE_BASEURL}/upload/device_icon/${device.device_image}` : '', icon: device.device_image
? `${FILE_BASEURL}/upload/device_icon/${device.device_image}`
: "",
bgColor: bgColor, bgColor: bgColor,
Online_color: device.device_normal_color, Online_color: device.device_normal_color,
Offline_color: device.device_close_color, Offline_color: device.device_close_color,
@ -92,7 +100,7 @@ const getData = async () => {
buying_date: device.buying_date, buying_date: device.buying_date,
created_at: device.created_at, created_at: device.created_at,
bgSize: 50, bgSize: 50,
} },
]; ];
}); });
} }
@ -100,7 +108,7 @@ const getData = async () => {
console.log("transformedData", transformedData); console.log("transformedData", transformedData);
systemData.value = transformedData; systemData.value = transformedData;
} };
watch( watch(
() => buildingStore.selectedBuilding, () => buildingStore.selectedBuilding,
@ -111,7 +119,7 @@ watch(
} }
}, },
{ {
immediate: true immediate: true,
} }
); );
@ -126,21 +134,30 @@ onUnmounted(() => {
<template> <template>
<div class="flex flex-wrap justify-between"> <div class="flex flex-wrap justify-between">
<div <div
class="order-3 lg:order-1 w-full lg:w-1/4 h-full flex flex-col justify-start z-10 border-dashboard gap-5" class="order-3 lg:order-1 w-full lg:w-1/4 min-h-screen flex flex-col justify-start z-10 border-dashboard gap-5"
> >
<div> <!-- 無資料時完整隱藏區塊不留空白 -->
<DashboardProduct /> <div class="mb-6">
<DashboardProduct
@visible-change="(v) => (productVisible = v)"
v-show="productVisible"
/>
</div> </div>
<div class="mt-6"> <div class="mb-6">
<DashboardProductComplete /> <DashboardProductComplete
@visible-change="(v) => (productCompleteVisible = v)"
v-show="productVisible"
/>
</div> </div>
<div class="mt-6"> <div class="mb-6">
<DashboardIndoor /> <DashboardIndoor />
</div> </div>
<div class="mt-10">
<div class="mb-10">
<DashboardRefrig /> <DashboardRefrig />
</div> </div>
</div> </div>
<div <div
class="order-1 lg:order-2 w-full lg:w-2/4 relative lg:static min-h-[300px] lg:h-full" class="order-1 lg:order-2 w-full lg:w-2/4 relative lg:static min-h-[300px] lg:h-full"
> >

View File

@ -216,6 +216,7 @@ onUnmounted(() => {
{{ $t("dashboard.no_data") }} {{ $t("dashboard.no_data") }}
</div> </div>
<LineChart <LineChart
v-if="!noData"
id="dashboard_other_real_temp" id="dashboard_other_real_temp"
class="min-h-[260px] max-h-fit" class="min-h-[260px] max-h-fit"
:option="defaultChartOption" :option="defaultChartOption"

View File

@ -1,8 +1,54 @@
<script setup> <script setup>
import { ref, onMounted } from "vue"; import { ref, onMounted, watch } from "vue";
import GaugeChart from "@/components/chart/GaugeChart.vue"; import GaugeChart from "@/components/chart/GaugeChart.vue";
import { CHART_COLOR, SECOND_CHART_COLOR } from "@/constant"; import { CHART_COLOR, SECOND_CHART_COLOR } from "@/constant";
import useBuildingStore from "@/stores/useBuildingStore";
const buildingStore = useBuildingStore();
const visible = ref(false); // /
const emit = defineEmits(["visible-change"]);
// guid sysConfig
watch(
() => buildingStore.selectedBuilding?.building_guid,
async (guid) => {
if (!guid) {
visible.value = false;
return;
}
await buildingStore.getSysConfig(guid);
// .value .value ref/reactive
const cfg = buildingStore.sysConfig?.value ?? buildingStore.sysConfig;
const showIndicator = !!cfg?.show_production_indicator;
console.log("[DashboardProduct] guid:", guid);
console.log("[DashboardProduct] sysConfig:", cfg);
console.log("[DashboardProduct] show_production_indicator:", showIndicator);
if (showIndicator === false) {
visible.value = false; //
return;
}
//
visible.value = true;
},
{ immediate: true }
);
// visible
watch(
visible,
(v) => {
emit("visible-change", v);
},
{ immediate: true }
);
//
const sameOptionAttr = { const sameOptionAttr = {
type: "gauge", type: "gauge",
center: ["50%", "60%"], center: ["50%", "60%"],
@ -119,10 +165,12 @@ onMounted(() => {
}); });
</script> </script>
<template> <template>
<div> <!-- 僅在 show_production_indicator === true 時渲染整個元件 -->
<div v-if="visible">
<h3 class="text-info text-xl text-center mb-3"> <h3 class="text-info text-xl text-center mb-3">
{{ $t("dashboard.production_quantity") }} {{ $t("dashboard.production_quantity") }}
</h3> </h3>
<div class="w-full grid grid-cols-3"> <div class="w-full grid grid-cols-3">
<div> <div>
<GaugeChart <GaugeChart
@ -150,6 +198,7 @@ onMounted(() => {
</div> </div>
</div> </div>
</div> </div>
<!-- shouldShow null false 時都不顯示任何東西避免閃動與空白框 -->
</template> </template>
<style lang="scss" scoped></style> <style lang="scss" scoped></style>

View File

@ -1,7 +1,48 @@
<script setup> <script setup>
import useActiveBtn from "@/hooks/useActiveBtn"; import useActiveBtn from "@/hooks/useActiveBtn";
import { ref, onMounted } from "vue"; import { ref, onMounted, watch } from "vue";
import DashboardProductCompleteModal from "./DashboardProductCompleteModal.vue"; import DashboardProductCompleteModal from "./DashboardProductCompleteModal.vue";
import useBuildingStore from "@/stores/useBuildingStore";
const buildingStore = useBuildingStore();
const visible = ref(false); // /
const emit = defineEmits(["visible-change"]);
// guid sysConfig show_production_indicator
watch(
() => buildingStore.selectedBuilding?.building_guid,
async (guid) => {
if (!guid) {
visible.value = false;
return;
}
await buildingStore.getSysConfig(guid);
// ref/reactive .value
const cfg = buildingStore.sysConfig?.value ?? buildingStore.sysConfig;
const flag = !!cfg?.show_production_indicator;
//
// console.log("[DashboardProductRate] guid:", guid);
// console.log("[DashboardProductRate] sysConfig:", cfg);
// console.log("[DashboardProductRate] show_production_indicator:", flag);
visible.value = flag;
},
{ immediate: true }
);
// visible
watch(
visible,
(v) => {
emit("visible-change", v);
},
{ immediate: true }
);
const { items, changeActiveBtn, setItems, selectedBtn } = useActiveBtn(); const { items, changeActiveBtn, setItems, selectedBtn } = useActiveBtn();
@ -44,6 +85,8 @@ onMounted(() => {
</script> </script>
<template> <template>
<!-- show_production_indicator 控制整個元件顯示 -->
<div v-if="visible">
<DashboardProductCompleteModal /> <DashboardProductCompleteModal />
<div class="mb-3 relative"> <div class="mb-3 relative">
<h3 class="text-info text-xl text-center"> <h3 class="text-info text-xl text-center">
@ -92,6 +135,7 @@ onMounted(() => {
<template v-else> <template v-else>
<p class="text-center mt-8 text-lg">尚未設定目標值</p> <p class="text-center mt-8 text-lg">尚未設定目標值</p>
</template> </template>
</div>
</template> </template>
<style lang="css" scoped></style> <style lang="css" scoped></style>

View File

@ -218,10 +218,11 @@ onUnmounted(() => {
{{ $t("dashboard.no_data") }} {{ $t("dashboard.no_data") }}
</div> </div>
<LineChart <LineChart
id="dashboard_refrigeration" v-if="!noData"
id="dashboard_other_real_temp"
class="min-h-[260px] max-h-fit" class="min-h-[260px] max-h-fit"
:option="defaultChartOption" :option="defaultChartOption"
ref="other_real_temp_chart" ref="indoorChartRef"
/> />
</template> </template>