323 lines
8.5 KiB
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>
|