生產設定: 匯出excel API串接

調整報表管理日期範圍
修改今日生產目標UI
溫度 - 糖度、冷藏溫度 新增 一小時、四小時、八小時 設定
告警小類篩選
This commit is contained in:
koko1108 2025-10-16 11:28:32 +08:00
parent 02d819437c
commit fe1570e63b
14 changed files with 340 additions and 93 deletions

View File

@ -5,3 +5,4 @@ export const POST_SETTING_TYPE_API = `/SituationRoom/SetProduct`;
export const GET_SETTING_INVENTORY_API = `/SituationRoom/GetInventory`; export const GET_SETTING_INVENTORY_API = `/SituationRoom/GetInventory`;
export const POST_SETTING_INVENTORY_API = `/SituationRoom/SaveInventory`; export const POST_SETTING_INVENTORY_API = `/SituationRoom/SaveInventory`;
export const GET_SETTING_INVENTORY_LOG_API = `/SituationRoom/GetInventoryLog`; export const GET_SETTING_INVENTORY_LOG_API = `/SituationRoom/GetInventoryLog`;
export const GET_SETTING_INVENTORY_EXPORT_API = `/api/report/Inventory`;

View File

@ -1,4 +1,4 @@
import instance from "@/util/request"; import instance, { fileInstance } from "@/util/request";
import apihandler from "@/util/apihandler"; import apihandler from "@/util/apihandler";
import { import {
POST_CHANGE_GROUP_VALUE_API, POST_CHANGE_GROUP_VALUE_API,
@ -7,7 +7,9 @@ import {
GET_SETTING_INVENTORY_API, GET_SETTING_INVENTORY_API,
POST_SETTING_INVENTORY_API, POST_SETTING_INVENTORY_API,
GET_SETTING_INVENTORY_LOG_API, GET_SETTING_INVENTORY_LOG_API,
GET_SETTING_INVENTORY_EXPORT_API,
} from "./api"; } from "./api";
import downloadExcel from "@/util/downloadExcel";
export const postChangeGroupValue = async (data) => { export const postChangeGroupValue = async (data) => {
const res = await instance.post(POST_CHANGE_GROUP_VALUE_API, data); const res = await instance.post(POST_CHANGE_GROUP_VALUE_API, data);
@ -72,3 +74,26 @@ export const getSettingInventoryLog = async ({ start_time, end_time }) => {
isSuccess: false, isSuccess: false,
}); });
}; };
export const getInventoryExportData = async ({ start_date, end_date }) => {
const res = await fileInstance.get(
GET_SETTING_INVENTORY_EXPORT_API,
{
params: {
start_date,
end_date,
},
responseType: "blob",
}
);
return apihandler(
res.code,
res,
{
msg: res.msg,
code: res.code,
},
downloadExcel
);
};

View File

@ -12,10 +12,11 @@ import instance, { fileInstance } from "@/util/request";
import apihandler from "@/util/apihandler"; import apihandler from "@/util/apihandler";
import downloadExcel from "@/util/downloadExcel"; import downloadExcel from "@/util/downloadExcel";
export const getElectricMeterLog = async ({ start_date }) => { export const getElectricMeterLog = async ({ start_date, end_date }) => {
const res = await instance.get(GET_ELECTRIC_METER_API, { const res = await instance.get(GET_ELECTRIC_METER_API, {
params: { params: {
start_date, start_date,
end_date,
}, },
}); });
@ -26,10 +27,14 @@ export const getElectricMeterLog = async ({ start_date }) => {
}); });
}; };
export const getRefrigerationRoomTemperatureLog = async ({ start_date }) => { export const getRefrigerationRoomTemperatureLog = async ({
start_date,
end_date,
}) => {
const res = await instance.get(GET_REFRIGERATION_ROOM_TEMPERATURE_API, { const res = await instance.get(GET_REFRIGERATION_ROOM_TEMPERATURE_API, {
params: { params: {
start_date, start_date,
end_date,
}, },
}); });
return apihandler(res.code, res.data, { return apihandler(res.code, res.data, {
@ -39,10 +44,11 @@ export const getRefrigerationRoomTemperatureLog = async ({ start_date }) => {
}); });
}; };
export const getSipLog = async ({ start_date }) => { export const getSipLog = async ({ start_date, end_date }) => {
const res = await instance.get(GET_SIP_API, { const res = await instance.get(GET_SIP_API, {
params: { params: {
start_date, start_date,
end_date,
}, },
}); });
return apihandler(res.code, res.data, { return apihandler(res.code, res.data, {
@ -52,10 +58,11 @@ export const getSipLog = async ({ start_date }) => {
}); });
}; };
export const getCipLog = async ({ start_date }) => { export const getCipLog = async ({ start_date, end_date }) => {
const res = await instance.get(GET_CIP_API, { const res = await instance.get(GET_CIP_API, {
params: { params: {
start_date, start_date,
end_date,
}, },
}); });
return apihandler(res.code, res.data, { return apihandler(res.code, res.data, {
@ -65,10 +72,11 @@ export const getCipLog = async ({ start_date }) => {
}); });
}; };
export const exportElectricMeterLog = async ({ start_date }) => { export const exportElectricMeterLog = async ({ start_date, end_date }) => {
const res = await fileInstance.get(EXPORT_ELECTRIC_METER_API, { const res = await fileInstance.get(EXPORT_ELECTRIC_METER_API, {
params: { params: {
start_date, start_date,
end_date,
}, },
responseType: "blob", responseType: "blob",
}); });
@ -84,12 +92,16 @@ export const exportElectricMeterLog = async ({ start_date }) => {
); );
}; };
export const exportRefrigerationRoomTemperatureLog = async ({ start_date }) => { export const exportRefrigerationRoomTemperatureLog = async ({
start_date,
end_date,
}) => {
const res = await fileInstance.get( const res = await fileInstance.get(
EXPORT_REFRIGERATION_ROOM_TEMPERATURE_API, EXPORT_REFRIGERATION_ROOM_TEMPERATURE_API,
{ {
params: { params: {
start_date, start_date,
end_date,
}, },
responseType: "blob", responseType: "blob",
} }
@ -106,10 +118,11 @@ export const exportRefrigerationRoomTemperatureLog = async ({ start_date }) => {
); );
}; };
export const exportSipLog = async ({ start_date }) => { export const exportSipLog = async ({ start_date, end_date }) => {
const res = await fileInstance.get(EXPORT_SIP_API, { const res = await fileInstance.get(EXPORT_SIP_API, {
params: { params: {
start_date, start_date,
end_date,
}, },
responseType: "blob", responseType: "blob",
}); });
@ -124,10 +137,11 @@ export const exportSipLog = async ({ start_date }) => {
); );
}; };
export const exportCipLog = async ({ start_date }) => { export const exportCipLog = async ({ start_date, end_date }) => {
const res = await fileInstance.get(EXPORT_CIP_API, { const res = await fileInstance.get(EXPORT_CIP_API, {
params: { params: {
start_date, start_date,
end_date,
}, },
responseType: "blob", responseType: "blob",
}); });

View File

@ -68,7 +68,7 @@ watch(searchParams, (newValue) => {
{{ checkedItem.length === store.subSys.length ? "取消全選" : "全選" }} {{ checkedItem.length === store.subSys.length ? "取消全選" : "全選" }}
</button> </button>
<Checkbox <Checkbox
v-for="sub in store.subSys" v-for="sub in store.subSys.filter(sub => sub.is_alarm === 1)"
:key="sub.key" :key="sub.key"
:title="sub.full_name" :title="sub.full_name"
:value="sub.sub_system_tag" :value="sub.sub_system_tag"

View File

@ -2,29 +2,33 @@
import { ref, onMounted, watch } from "vue"; import { ref, onMounted, watch } from "vue";
import useSearchParam from "@/hooks/useSearchParam"; import useSearchParam from "@/hooks/useSearchParam";
import useActiveBtn from "@/hooks/useActiveBtn"; import useActiveBtn from "@/hooks/useActiveBtn";
import { getAlertSubList } from "@/apis/alert"; import useBuildingStore from "@/stores/useBuildingStore";
const { searchParams, changeParams } = useSearchParam(); const { searchParams, changeParams } = useSearchParam();
const { items, changeActiveBtn, setItems, selectedBtn } = useActiveBtn(); const { items, changeActiveBtn, setItems, selectedBtn } = useActiveBtn();
const store = useBuildingStore();
const getSubSystems = async () => { const updateSubSystemsFromStore = () => {
const res = await getAlertSubList(); const subSystems = store.subSys
const subSystems = res.data.history_Main_Systems.flatMap((mainSystem) => { .filter(subSystem => subSystem.is_alarm === 1)
return mainSystem.history_Sub_systems.map((subSystem, index) => ({ .map(subSystem => ({
title: subSystem.full_name, title: subSystem.full_name,
key: subSystem.sub_system_tag, key: subSystem.sub_system_tag,
active: searchParams.value?.subSys_id active: searchParams.value?.subSys_id
? searchParams.value.subSys_id === subSystem.sub_system_tag ? searchParams.value.subSys_id === subSystem.sub_system_tag
: subSystem.sub_system_tag == "DP", : subSystem.sub_system_tag == "DP",
})); }));
});
setItems(subSystems); setItems(subSystems);
}; };
onMounted(() => { onMounted(() => {
getSubSystems(); updateSubSystemsFromStore();
}); });
watch(() => store.subSys, () => {
updateSubSystemsFromStore();
}, { deep: true });
watch(selectedBtn, watch(selectedBtn,
(newValue) => { (newValue) => {
if (newValue) { if (newValue) {

View File

@ -9,6 +9,7 @@ import DashboardElectricity from "./components/DashboardElectricity.vue";
import DashboardAlert from "./components/DashboardAlert.vue"; import DashboardAlert from "./components/DashboardAlert.vue";
import DashboardForgeOptionButton from "./components/DashboardForgeOptionButton.vue"; import DashboardForgeOptionButton from "./components/DashboardForgeOptionButton.vue";
import DashboardForgeOptionCard from "./components/DashboardForgeOptionCard.vue"; import DashboardForgeOptionCard from "./components/DashboardForgeOptionCard.vue";
import DashboardMoreModal from "./components/DashboardMoreModal.vue";
import { import {
getDashboardInit, getDashboardInit,
getDashboardOptionRealTimeData, getDashboardOptionRealTimeData,
@ -106,6 +107,13 @@ const getCompany = async () => {
companyOptions.value = res.data.map((d) => ({ ...d, key: d.id })); companyOptions.value = res.data.map((d) => ({ ...d, key: d.id }));
}; };
const currentIntervalType = ref("");
const openModal = (type) => {
currentIntervalType.value = type;
dashboard_more.showModal();
};
// //
const startInterval = (option) => { const startInterval = (option) => {
// //
@ -155,6 +163,7 @@ onUnmounted(() => {
</script> </script>
<template> <template>
<DashboardMoreModal :currentIntervalType="currentIntervalType" />
<div class="flex justify-between"> <div class="flex justify-between">
<div class="w-1/4 h-full flex flex-col justify-start border-dashboard z-20"> <div class="w-1/4 h-full flex flex-col justify-start border-dashboard z-20">
<div class=""><DashboardProduct /></div> <div class=""><DashboardProduct /></div>
@ -186,9 +195,11 @@ onUnmounted(() => {
:companyOptions="companyOptions" :companyOptions="companyOptions"
/> />
<div class="w-1/4 flex flex-col justify-start border-dashboard z-20"> <div class="w-1/4 flex flex-col justify-start border-dashboard z-20">
<div class=""><DashboardImmediateTemp /></div> <div class="">
<DashboardImmediateTemp @open-modal="openModal" />
</div>
<div class="mt-5"> <div class="mt-5">
<DashboardFrozenTemp /> <DashboardFrozenTemp @open-modal="openModal"/>
</div> </div>
<div class="mt-5"> <div class="mt-5">
<DashboardElectricity /> <DashboardElectricity />

View File

@ -55,12 +55,11 @@ const defaultChartOption = ref({
const frozen_temp_chart = ref(null); const frozen_temp_chart = ref(null);
const data = ref([]); const data = ref([]);
const getData = async () => { const getData = async (timeInterval) => {
const res = await getDashboardTemp({ const res = await getDashboardTemp({
timeInterval: 1, // =>1.4.8 timeInterval, // =>1.4.8
tempOption: 2, // 1:;2: tempOption: 2, // 1:;2:
}); });
if (res.isSuccess) { if (res.isSuccess) {
@ -68,6 +67,25 @@ const getData = async () => {
} }
}; };
watch(
searchParams,
(newValue, oldValue) => {
if (
newValue[intervalType] &&
newValue[intervalType] !== oldValue[intervalType]
) {
window.clearInterval(timeoutTimer.value);
getData(parseInt(newValue[intervalType]));
timeoutTimer.value = setInterval(() => {
getData(parseInt(newValue[intervalType]));
}, 60000);
}
},
{
deep: true,
}
);
watch(data, (newValue) => { watch(data, (newValue) => {
if (newValue?.length > 0) { if (newValue?.length > 0) {
frozen_temp_chart.value.chart.setOption({ frozen_temp_chart.value.chart.setOption({
@ -90,19 +108,19 @@ watch(data, (newValue) => {
} }
}); });
let timer = null; const timeoutTimer = ref("");
onMounted(() => { onMounted(() => {
getData(); getData();
timer = setInterval(() => { timeoutTimer.value = setInterval(() => {
getData(); getData();
}, 60 * 1000); }, 60 * 1000);
}); });
onUnmounted(() => { onUnmounted(() => {
if (timer) { if (timeoutTimer.value) {
clearInterval(timer); clearInterval(timeoutTimer.value);
timer = null; timeoutTimer.value = null;
} }
}); });
</script> </script>
@ -111,6 +129,12 @@ onUnmounted(() => {
<!-- 冷藏溫度 --> <!-- 冷藏溫度 -->
<div class="flex items-center justify-between mb-3"> <div class="flex items-center justify-between mb-3">
<h3 class="text-info font-bold text-xl text-center">冷藏溫度</h3> <h3 class="text-info font-bold text-xl text-center">冷藏溫度</h3>
<button
class="btn-xs btn btn-info"
@click="$emit('open-modal', intervalType)"
>
時間設定
</button>
</div> </div>
<LineChart <LineChart

View File

@ -80,9 +80,9 @@ onMounted(() => {
]); ]);
}); });
const getData = async (typeOption) => { const getData = async (timeInterval, typeOption) => {
const res = await getDashboardTemp({ const res = await getDashboardTemp({
timeInterval: 1, // =>1.4.8 timeInterval, // =>1.4.8
tempOption: 1, tempOption: 1,
typeOption, // 1:-;2:調-;3:- typeOption, // 1:-;2:調-;3:-
}); });
@ -91,16 +91,35 @@ const getData = async (typeOption) => {
} }
}; };
let timer = null; const timeoutTimer = ref("");
watch( watch(
selectedBtn, selectedBtn,
(newValue) => { (newValue) => {
window.clearInterval(timer); window.clearInterval(timeoutTimer.value);
getData(newValue.key); getData(parseInt(searchParams.value[intervalType] || 1), newValue.key);
timer = setInterval(() => { timeoutTimer.value = setInterval(() => {
getData(newValue.key); getData(parseInt(searchParams.value[intervalType] || 1), newValue.key);
}, 60 * 1000); }, 60000);
},
{
deep: true,
}
);
watch(
searchParams,
(newValue, oldValue) => {
if (
newValue[intervalType] &&
newValue[intervalType] !== oldValue[intervalType]
) {
window.clearInterval(timeoutTimer.value);
getData(parseInt(newValue[intervalType]), selectedBtn.value.key);
timeoutTimer.value = setInterval(() => {
getData(parseInt(newValue[intervalType]), selectedBtn.value.key);
}, 60000);
}
}, },
{ {
deep: true, deep: true,
@ -110,34 +129,39 @@ watch(
watch(data, (newValue) => { watch(data, (newValue) => {
// clearChart(other_real_temp_chart.value.chart); // clearChart(other_real_temp_chart.value.chart);
if (newValue?.length > 0) { if (newValue?.length > 0) {
other_real_temp_chart.value.chart.setOption({ other_real_temp_chart.value.chart.setOption(
...defaultChartOption.value, {
legend: { ...defaultChartOption.value,
data: newValue.map(({ full_name }) => full_name), legend: {
...defaultChartOption.value.legend, data: newValue.map(({ full_name }) => full_name),
}, ...defaultChartOption.value.legend,
xAxis: {
...defaultChartOption.value.xAxis,
data: newValue[0]?.data.map(({ time }) => dayjs(time).format("HH:mm")),
},
series: newValue.map(({ full_name, data: seriesData }, index) => ({
name: full_name,
type: "line",
data: seriesData.map(({ value }) => value),
showSymbol: false,
itemStyle: {
color: SECOND_CHART_COLOR[index],
}, },
})), xAxis: {
}, { notMerge: true }); ...defaultChartOption.value.xAxis,
data: newValue[0]?.data.map(({ time }) =>
dayjs(time).format("HH:mm")
),
},
series: newValue.map(({ full_name, data: seriesData }, index) => ({
name: full_name,
type: "line",
data: seriesData.map(({ value }) => value),
showSymbol: false,
itemStyle: {
color: SECOND_CHART_COLOR[index],
},
})),
},
{ notMerge: true }
);
} }
// other_real_temp_chart.value.chart.hideLoading(); // other_real_temp_chart.value.chart.hideLoading();
}); });
onUnmounted(() => { onUnmounted(() => {
if (timer) { if (timeoutTimer.value) {
clearInterval(timer); clearInterval(timeoutTimer.value);
timer = null; timeoutTimer.value = null;
} }
}); });
</script> </script>
@ -145,6 +169,12 @@ onUnmounted(() => {
<template> <template>
<div class="flex items-center justify-between mb-3"> <div class="flex items-center justify-between mb-3">
<h3 class="text-info font-bold text-xl text-center">溫度-糖度</h3> <h3 class="text-info font-bold text-xl text-center">溫度-糖度</h3>
<button
class="btn-xs btn btn-info"
@click="$emit('open-modal', intervalType)"
>
時間設定
</button>
</div> </div>
<div class="text-center"> <div class="text-center">
<ButtonConnectedGroup <ButtonConnectedGroup

View File

@ -0,0 +1,122 @@
<script setup>
import useActiveBtn from "@/hooks/useActiveBtn";
import { onMounted, watch } from "vue";
import useSearchParams from "@/hooks/useSearchParam";
const { changeParams, searchParams } = useSearchParams();
const { items, changeActiveBtn, setItems, selectedBtn } = useActiveBtn();
const props = defineProps({
currentIntervalType: {
type: String,
default: "interval_hour",
},
});
onMounted(() => {
setItems([
{
title: "1小時",
key: "1hour",
active:
!searchParams.value?.[props.currentIntervalType] ||
searchParams.value?.[props.currentIntervalType] === 1,
timeInterval: 1,
},
{
title: "4小時",
key: "4hour",
active: searchParams.value?.[props.currentIntervalType] === 4,
timeInterval: 4,
},
{
title: "8小時",
key: "8hour",
active: searchParams.value?.[props.currentIntervalType] === 8,
timeInterval: 8,
},
]);
});
watch(
() => props.currentIntervalType,
(newValue) => {
console.log(
"currentIntervalType",
newValue,
searchParams.value,
searchParams.value?.[newValue]
);
setItems([
{
title: "1小時",
key: "1hour",
active:
!searchParams.value?.[newValue] ||
parseInt(searchParams.value?.[newValue]) === 1,
timeInterval: 1,
},
{
title: "4小時",
key: "4hour",
active: parseInt(searchParams.value?.[newValue]) === 4,
timeInterval: 4,
},
{
title: "8小時",
key: "8hour",
active: parseInt(searchParams.value?.[newValue]) === 8,
timeInterval: 8,
},
]);
}
);
const onCancel = () => {
dashboard_more.close();
};
const onOk = async () => {
console.log(searchParams.value);
changeParams({
...searchParams.value,
[props.currentIntervalType]: selectedBtn.value.timeInterval,
});
onCancel();
};
</script>
<template>
<Modal id="dashboard_more" title="顯示設定" :onCancel="onCancel" width="500">
<template #modalContent>
<ButtonGroup
:items="items"
:withLine="true"
class="mt-8 mb-6"
:onclick="
(e, item) => {
changeActiveBtn(item);
}
"
/>
</template>
<template #modalAction>
<button
type="reset"
class="btn btn-outline-success mr-2"
@click.prevent="onCancel"
>
取消
</button>
<button
type="submit"
class="btn btn-outline-success"
@click.stop.prevent="onOk"
>
確定
</button>
</template>
</Modal>
</template>
<style lang="scss" scoped></style>

View File

@ -48,7 +48,7 @@ onMounted(() => {
setItems([ setItems([
{ {
id: 1, id: 1,
title: "配方", title: "調理",
key: 1, key: 1,
active: true, active: true,
}, },
@ -107,7 +107,7 @@ onUnmounted(() => {
<tr> <tr>
<th>品名</th> <th>品名</th>
<th>狀態</th> <th>狀態</th>
<th>生產進度</th> <!-- <th>生產進度</th> -->
<th v-if="selectedBtn?.key === 1">功能</th> <th v-if="selectedBtn?.key === 1">功能</th>
</tr> </tr>
</thead> </thead>
@ -131,7 +131,7 @@ onUnmounted(() => {
<tr v-for="item in production_data" :key="item.name"> <tr v-for="item in production_data" :key="item.name">
<td>{{ item.name }}</td> <td>{{ item.name }}</td>
<td>{{ item.status }}</td> <td>{{ item.status }}</td>
<td>{{ item.progress }}</td> <!-- <td>{{ item.progress }}</td> -->
<td v-if="item.details && item.details.length"> <td v-if="item.details && item.details.length">
<button <button
class="btn btn-xs btn-outline-info" class="btn btn-xs btn-outline-info"

View File

@ -9,6 +9,7 @@ const tabs = [
{ label: "品檢" }, { label: "品檢" },
{ label: "流量計" }, { label: "流量計" },
{ label: "SIP" }, { label: "SIP" },
{ label: "AI" },
]; ];
const activeTab = ref(tabs[0].label); const activeTab = ref(tabs[0].label);
</script> </script>
@ -86,9 +87,9 @@ const activeTab = ref(tabs[0].label);
<th>風味</th> <th>風味</th>
<th>色澤</th> <th>色澤</th>
<th>雜異物</th> <th>雜異物</th>
<th>鹽度</th>
<th>酸度</th> <th>酸度</th>
<th>糖度</th> <th>糖度</th>
<th>鹽度</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -102,9 +103,9 @@ const activeTab = ref(tabs[0].label);
<td>{{ flow.flavor }}</td> <td>{{ flow.flavor }}</td>
<td>{{ flow.color }}</td> <td>{{ flow.color }}</td>
<td>{{ flow.impurities }}</td> <td>{{ flow.impurities }}</td>
<td>{{ flow.actual_Salinity }}</td>
<td>{{ flow.actual_PH }}</td> <td>{{ flow.actual_PH }}</td>
<td>{{ flow.actual_Brix }}</td> <td>{{ flow.actual_Brix }}</td>
<td>{{ flow.actual_Salinity }}</td>
</tr> </tr>
<tr <tr
v-if="!pot.qcResult || !pot.qcResult.length" v-if="!pot.qcResult || !pot.qcResult.length"

View File

@ -62,6 +62,7 @@ const onOk = async () => {
class="my-2" class="my-2"
name="total_capacity" name="total_capacity"
v-if="formState?.type == 1" v-if="formState?.type == 1"
readonly
> >
<template #topLeft>總庫存量</template> <template #topLeft>總庫存量</template>
<template #bottomLeft> <template #bottomLeft>

View File

@ -5,8 +5,9 @@ import {
getSettingInventory, getSettingInventory,
postSettingInventory, postSettingInventory,
getSettingInventoryLog, getSettingInventoryLog,
getInventoryExportData,
} from "@/apis/productSetting"; } from "@/apis/productSetting";
import { ref, onMounted, inject, watch } from "vue"; import { ref, onMounted, inject, watch, computed } from "vue";
import useActiveBtn from "@/hooks/useActiveBtn"; import useActiveBtn from "@/hooks/useActiveBtn";
const { items, changeActiveBtn, setItems, selectedBtn } = useActiveBtn(); const { items, changeActiveBtn, setItems, selectedBtn } = useActiveBtn();
import dayjs from "dayjs"; import dayjs from "dayjs";
@ -106,6 +107,15 @@ const onSearch = async () => {
} }
}; };
const exportFile = async () => {
const res = await getInventoryExportData({
start_date: dayjs(dateRange.value[0].value).format("YYYY-MM-DD"),
end_date: dayjs(dateRange.value[1].value).format("YYYY-MM-DD"),
}).catch((err) => {
console.error(err);
});
};
const openModal = (type, item_id, record) => { const openModal = (type, item_id, record) => {
if (type === 1) { if (type === 1) {
formState.value = { formState.value = {
@ -146,6 +156,21 @@ onMounted(() => {
]); ]);
}); });
const submitBtns = computed(() => [
{
title: "搜尋",
key: "submit",
active: false,
onClick: onSearch,
},
{
title: "匯出",
key: "export",
active: false,
onClick: exportFile,
},
]);
watch( watch(
() => selectedBtn.value?.key, () => selectedBtn.value?.key,
(key) => { (key) => {
@ -185,9 +210,7 @@ watch(
:isBottomLabelExist="false" :isBottomLabelExist="false"
class="mr-5" class="mr-5"
/> />
<button class="btn btn-success" @click.stop.prevent="onSearch"> <ButtonGroup class="ml-5" :items="submitBtns" :withLine="false" />
搜尋
</button>
</template> </template>
</div> </div>
</div> </div>

View File

@ -20,15 +20,21 @@ const { items, changeActiveBtn, setItems, selectedBtn } = useActiveBtn();
const dateRange = ref([ const dateRange = ref([
{ {
key: "start_at", key: "start_at",
value: dayjs(), value: dayjs().subtract(30, "day").valueOf(),
dateFormat: "yyyy-MM", dateFormat: "yyyy-MM-dd",
placeholder: "起始日期", placeholder: "起始日期",
monthPicker: true, },
{
key: "end_at",
value: dayjs().valueOf(),
dateFormat: "yyyy-MM-dd",
placeholder: "結束日期",
}, },
]); ]);
const searchState = ref({ const searchState = ref({
start_date: dayjs().format("YYYY-MM"), start_date: dayjs().subtract(30, "day").format("YYYY-MM-DD"),
end_date: dayjs().format("YYYY-MM-DD"),
}); });
// Table // Table
@ -88,26 +94,6 @@ watch(
{ immediate: true } { immediate: true }
); );
watch(
dateRange,
(newRange) => {
let raw = newRange && newRange[0] && newRange[0].value;
let baseDayjs = null;
if (raw && typeof raw === "object" && "year" in raw && "month" in raw) {
baseDayjs = dayjs(new Date(raw.year, raw.month, 1));
} else {
baseDayjs = dayjs(raw);
}
if (!baseDayjs.isValid()) {
baseDayjs = dayjs();
}
searchState.value = {
start_date: baseDayjs.format("YYYY-MM"),
};
},
{ deep: true }
);
const submit = async (e, type = "") => { const submit = async (e, type = "") => {
e?.preventDefault?.(); e?.preventDefault?.();
e?.stopPropagation?.(); e?.stopPropagation?.();
@ -181,8 +167,13 @@ onBeforeMount(() => {
} }
" "
/> />
<div class="flex flex-wrap items-center"> <div class="flex flex-wrap items-center mt-2">
<DateGroup :items="dateRange" /> <DateGroup
:items="dateRange"
:withLine="true"
:isTopLabelExist="false"
:isBottomLabelExist="false"
/>
<ButtonGroup class="ml-5" :items="submitBtns" :withLine="false" /> <ButtonGroup class="ml-5" :items="submitBtns" :withLine="false" />
</div> </div>
</div> </div>