CviLux_fe/src/views/AssetManagement/components/AssetTableModalRightInfo.vue

323 lines
8.5 KiB
Vue

<script setup>
import { onMounted, ref, inject, onBeforeMount, watch, computed } from "vue";
import EffectScatter from "@/components/chart/EffectScatter.vue";
import {
getAssetFloorList,
postAssetFloor,
deleteAssetFloor,
} from "@/apis/asset";
import useFormErrorMessage from "@/hooks/useFormErrorMessage";
import useBuildingStore from "@/stores/useBuildingStore";
import * as yup from "yup";
import { twMerge } from "tailwind-merge";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const { openToast, cancelToastOpen } = inject("app_toast");
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
const { totalCoordinates } = inject("asset_table_data");
const { updateRightFields, formErrorMsg, formState } = inject(
"asset_table_modal_form"
);
const store = useBuildingStore();
let schema = {
floor_guid: yup.string().nullable(true),
device_coordinate: yup.string().nullable(true),
};
onBeforeMount(() => {
const data = {
floor_guid: "",
device_coordinate: "",
};
updateRightFields(schema, data);
});
const asset_floor_chart = ref(null);
const currentFloor = ref(null);
const selectedOption = ref("add");
const parsedCoordinates = ref(null);
const defaultOption = (map, data = []) => {
// 生成坐標數據,根據坐標值的不同設置不同顏色
const formattedData = data.map((coordinate) => {
const coordString = JSON.stringify(coordinate);
return {
name: coordString,
value: coordinate,
itemStyle: {
color: coordString === formState.value.device_coordinate ? "#0000FF" : "#b02a02",
},
};
});
return {
tooltip: {},
geo: {
tooltip: {
show: false,
},
map,
roam: true,
},
series: {
type: "effectScatter",
coordinateSystem: "geo",
geoIndex: 0,
symbolSize: 10,
encode: {
tooltip: 2,
},
data: formattedData, // 使用格式化的數據
},
};
};
watch(currentFloor, (newValue) => {
if (newValue?.floor_map_name) {
const coordinates =
(totalCoordinates.value?.[newValue.floor_guid]?.filter(
(coord) => coord !== ""
) || []);
parsedCoordinates.value = coordinates.length > 0
? coordinates.map((coord) => JSON.parse(coord))
: [];
asset_floor_chart.value.updateSvg(
{
full_name: newValue.floor_map_name,
path: `${FILE_BASEURL}/${newValue.floor_map_url}.svg`,
},
defaultOption(newValue.floor_map_name, parsedCoordinates.value)
);
}
});
const floors = ref([]);
const getFloors = async () => {
const res = await getAssetFloorList();
floors.value = res.data[0]?.floors.map((d) => ({ ...d, key: d.floor_guid }));
};
watch(
formState,
(newValue) => {
if (newValue.floor_guid) {
const floor = floors.value.find(
({ floor_guid }) => floor_guid === newValue.floor_guid
);
currentFloor.value = floor;
} else {
currentFloor.value = null;
}
},
{
deep: true,
}
);
const getCoordinate = (position) => {
formState.value.device_coordinate = JSON.stringify(position);
};
onMounted(() => {
getFloors();
});
// modal
const openModal = () => {
if (selectedOption.value === "add") {
FloorFormState.value = {
full_name: "",
floorFile: [],
};
} else if (selectedOption.value === "edit") {
const floor = floors.value.find(
(f) => f.floor_guid === formState.value.floor_guid
);
if (floor) {
console.log("floor", floor);
FloorFormState.value = {
full_name: floor.full_name,
floorFile: [],
};
}
}
asset_add_floor.showModal();
};
const form = ref(null);
const FloorFormState = ref({
full_name: "",
floorFile: [],
});
const floorScheme = yup.object({
full_name: yup.string().required(t("button.required")),
floorFile: yup.array(),
});
const updateFileList = (files) => {
console.log("file", files);
FloorFormState.value.floorFile = files;
};
const {
formErrorMsg: floorFormErrorMsg,
handleSubmit,
handleErrorReset,
updateScheme,
} = useFormErrorMessage(floorScheme);
const onOk = async () => {
const value = handleSubmit(floorScheme, FloorFormState.value);
const formData = new FormData(form.value);
formData.append("floor_guid", selectedOption.value === "add" ? null :currentFloor.value.floor_guid);
formData.append("building_tag", store.selectedBuilding.building_tag);
formData.append("initMapName", FloorFormState.value.floorFile[0]?.name);
formData.append("mapFile", FloorFormState.value.floorFile[0]);
formData.delete("floorFile");
for (let [key, value] of formData) {
console.log(key, value);
}
const res = await postAssetFloor(formData);
if (res.isSuccess) {
getFloors();
onCancel();
}
};
const onDelete = async () => {
openToast("warning", t("msg.sure_to_delete"), "#asset_add_table_item", async () => {
await cancelToastOpen();
const res = await deleteAssetFloor({
floor_guid: formState.value.floor_guid,
});
if (res.isSuccess) {
getFloors();
openToast("success", t("msg.delete_success"), "#asset_add_table_item");
} else {
openToast("error", res.msg, "#asset_add_table_item");
}
});
};
const onCancel = () => {
FloorFormState.value = {
full_name: "",
floorFile: [],
};
asset_add_floor.close();
};
</script>
<template>
<!-- 平面圖 -->
<div class="flex gap-4 mb-5">
<div className="join w-80 mb-4">
<Select
:value="formState"
selectClass="border-info focus-within:border-info rounded-r-none"
name="floor_guid"
Attribute="full_name"
:options="floors"
:isBottomLabelExist="false"
>
<template #topLeft>{{ $t("assetManagement.floor") }}</template>
</Select>
<select
v-model="selectedOption"
className="select border-info focus-within:border-info join-item mt-11"
>
<option value="add" selected>{{ $t("button.add") }}</option>
<option value="edit">{{ $t("button.edit") }}</option>
<option value="delete">{{ $t("button.delete") }}</option>
</select>
<button
type="button"
class="btn btn-success join-item mt-11"
@click="selectedOption === 'delete' ? onDelete() : openModal()"
:aria-label="$t('button.submit')"
>
{{ $t("button.submit") }}
</button>
</div>
<Input
:value="formState"
width="270"
name="device_coordinate"
:disabled="true"
>
<template #topLeft>{{ $t("assetManagement.device_coordinate") }}</template>
<template #bottomLeft
><span class="text-error text-base">
{{ formErrorMsg.device_coordinate }}
</span></template
></Input
>
</div>
<div class="relative">
<EffectScatter
id="asset_floor_chart"
ref="asset_floor_chart"
:getCoordinate="getCoordinate"
:class="
twMerge(
'absolute top-0 left-0 bg-white',
currentFloor?.floor_map_url ? 'opacity-1' : 'opacity-0'
)
"
/>
<div
v-if="!currentFloor?.floor_map_url"
class="absolute top-0 left-0 flex justify-center items-center min-h-[500px] w-full border border-stone-900 shadow-lg bg-sub-success bg-opacity-25 rounded-md"
>
<p class="text-2xl">{{ $t("assetManagement.add_floor_text") }}</p>
</div>
</div>
<Modal
id="asset_add_floor"
:title="t('assetManagement.floor_plan')"
:onCancel="onCancel"
width="400"
>
<template #modalContent>
<form ref="form">
<Input :value="FloorFormState" width="270" name="full_name">
<template #topLeft>{{ $t("assetManagement.system_name") }}</template>
<template #bottomLeft
><span class="text-error text-base">
{{ floorFormErrorMsg.full_name }}
</span></template
></Input
>
<Upload
name="floorFile"
:fileList="FloorFormState.floorFile"
:getFileList="updateFileList"
:multiple="false"
class="col-span-2"
formats="svg"
>
<template #topLeft>{{ $t("assetManagement.oriFile") }}</template>
</Upload>
</form>
</template>
<template #modalAction>
<button
type="reset"
class="btn btn-outline-success mr-2"
@click.prevent="onCancel"
>
{{ $t("button.cancel") }}
</button>
<button type="submit" class="btn btn-outline-success" @click="onOk">
{{ $t("button.submit") }}
</button>
</template></Modal
>
</template>
<style lang="scss" scoped></style>