257 lines
6.7 KiB
Vue
257 lines
6.7 KiB
Vue
<script setup>
|
|
import Collapse from "@/components/customUI/FileSystemCollapse.vue";
|
|
import GraphSidebarDropdown from "./GraphSidebarDropdown.vue";
|
|
import {
|
|
getSideBar,
|
|
updateSideBarTreeName,
|
|
removeSideBarTreeName,
|
|
addSideBarTreeName,
|
|
} from "@/apis/graph";
|
|
import { ref, onMounted, onUnmounted, provide, computed, inject } from "vue";
|
|
import useSearchParams from "@/hooks/useSearchParam";
|
|
import { useI18n } from "vue-i18n";
|
|
const { t, locale } = useI18n();
|
|
const { openToast, cancelToastOpen } = inject("app_toast");
|
|
const { changeParams, searchParams } = useSearchParams();
|
|
|
|
let raw_data = ref([]);
|
|
|
|
const { updateCurrentDir, sidebar_data } = inject("current_dir");
|
|
|
|
// 處理data資料
|
|
const graphData = computed(() => {
|
|
let data = raw_data.value.map((d) => ({ ...d, children: [] }));
|
|
let formatD = [];
|
|
data
|
|
.sort((a, b) => b.parent_id - a.parent_id)
|
|
.forEach((d) => {
|
|
if (d.parent_id === 0) {
|
|
formatD.push({ ...d, key: d.id, title: d.name });
|
|
} else {
|
|
let parent = data.find(({ id }) => id === d.parent_id);
|
|
if (parent) {
|
|
parent.children = [
|
|
...(parent?.children || []),
|
|
{ ...d, key: d.id, title: d.name },
|
|
];
|
|
}
|
|
}
|
|
});
|
|
changeParams({ id: searchParams.value.id || formatD[0]?.id });
|
|
updateCurrentDir(
|
|
data.find((d) => d.id === parseInt(searchParams.value.id)) || formatD[0]
|
|
);
|
|
sidebar_data.value = formatD;
|
|
return formatD;
|
|
});
|
|
|
|
const getData = async (id = "") => {
|
|
const res = await getSideBar();
|
|
raw_data.value = res.data;
|
|
if (id) {
|
|
const currentDir = raw_data.value.find((d) => parseInt(id) === d.id);
|
|
updateCurrentDir(currentDir);
|
|
}
|
|
cancelDropdownAndInput();
|
|
};
|
|
|
|
const dropdownOpen = ref(false);
|
|
const selectedItem = ref(null);
|
|
|
|
const cancelOpen = () => {
|
|
dropdownOpen.value = false;
|
|
};
|
|
|
|
const cancelDropdownAndInput = () => {
|
|
dropdownOpen.value = false;
|
|
filenameInputIsOpen.value = false;
|
|
};
|
|
|
|
const dropdownPosition = ref({
|
|
x: 0,
|
|
y: 0,
|
|
});
|
|
|
|
const sidebar = ref(null);
|
|
const onAddRightClick = (e) => {
|
|
console.log(e);
|
|
if (e.target.nodeName === "LI") {
|
|
const targetPos = e.target.getBoundingClientRect();
|
|
const sidebarPos = e.target.closest(".sidebar").getBoundingClientRect();
|
|
|
|
dropdownPosition.value = {
|
|
left: e.offsetX + 30,
|
|
top: e.clientY - sidebarPos.y + targetPos.height,
|
|
};
|
|
} else {
|
|
dropdownPosition.value = {
|
|
left: e.offsetX + 30,
|
|
top: e.offsetY + 30,
|
|
};
|
|
}
|
|
|
|
selectedItem.value = null;
|
|
dropdownOpen.value = true;
|
|
};
|
|
|
|
const onRightClick = (e, d) => {
|
|
cancelDropdownAndInput();
|
|
const targetPos = e.target.closest("li").getBoundingClientRect();
|
|
const sidebarPos = e.target.closest(".sidebar").getBoundingClientRect();
|
|
console.log("onRightClick", sidebarPos, targetPos);
|
|
dropdownPosition.value = {
|
|
left: targetPos.x - sidebarPos.x + targetPos.width / 2 - 50,
|
|
top: targetPos.y - sidebarPos.y + 2 * targetPos.height + 5,
|
|
};
|
|
selectedItem.value = d;
|
|
dropdownOpen.value = true;
|
|
};
|
|
|
|
const onLeftClick = (id, data) => {
|
|
// if (data.children.length === 0) {
|
|
updateCurrentDir(data);
|
|
changeParams({ id });
|
|
// } else {
|
|
// changeParams({});
|
|
// }
|
|
};
|
|
|
|
const filenameInputIsOpen = ref(false);
|
|
const getNewFilename = async (e) => {
|
|
// if (!e) {
|
|
// // console.log("無資料");
|
|
// // raw_data.value = raw_data.value.filter(
|
|
// // (d) => d.id !== selectedItem.value?.id
|
|
// // );
|
|
|
|
// // selectedItem.value = null;
|
|
// return;
|
|
// }
|
|
if (selectedItem.value?.isNewDir) {
|
|
// 新增
|
|
const res = await addSideBarTreeName({
|
|
parent_id: selectedItem.value?.parent_id,
|
|
name: e?.target?.value || selectedItem.value?.title,
|
|
});
|
|
getData(res);
|
|
} else if (
|
|
e &&
|
|
e?.target.value !== "" &&
|
|
e?.target.value !== selectedItem.value?.title
|
|
) {
|
|
// 編輯
|
|
const res = await updateSideBarTreeName({
|
|
id: selectedItem.value?.id,
|
|
name: e.target.value,
|
|
});
|
|
getData();
|
|
} else if (selectedItem.value) {
|
|
// 以防資料被刪掉
|
|
selectedItem.value.title = selectedItem.value?.name;
|
|
}
|
|
};
|
|
// 編輯filename
|
|
const editFilename = () => {
|
|
filenameInputIsOpen.value = true;
|
|
cancelOpen();
|
|
};
|
|
// 新增filename
|
|
const openItem = ref([]);
|
|
const addFilename = (root = false) => {
|
|
const newItem = {
|
|
id: raw_data.value?.[raw_data.value.length - 1].id + 1,
|
|
key: raw_data.value?.[raw_data.value.length - 1].id + 1,
|
|
title: t("graphManagement.new_category"),
|
|
name: t("graphManagement.new_category"),
|
|
parent_id: selectedItem.value?.id || 0,
|
|
isNewDir: true,
|
|
};
|
|
raw_data.value = [...raw_data.value, newItem];
|
|
|
|
// 第二層之後
|
|
if (!root) {
|
|
let parent = raw_data.value.find(
|
|
({ id }) => id === selectedItem.value.parent_id
|
|
);
|
|
let ids = [selectedItem.value.id];
|
|
while (Boolean(parent?.id)) {
|
|
ids = [...ids, parent.id];
|
|
parent = raw_data.value.find(({ id }) => id === parent.parent_id);
|
|
}
|
|
openItem.value = ids;
|
|
}
|
|
|
|
selectedItem.value = newItem;
|
|
// editFilename();
|
|
};
|
|
|
|
// 刪除filename
|
|
const deleteFilename = async () => {
|
|
openToast("warning", t("msg.sure_to_delete"), "body", async () => {
|
|
await cancelToastOpen();
|
|
const filterData = raw_data.value.filter(({ id }) => id !== selectedItem.value.id)
|
|
const res = await removeSideBarTreeName(selectedItem.value.id);
|
|
if (res.isSuccess) {
|
|
raw_data.value = filterData;
|
|
cancelOpen();
|
|
openToast("success", t("msg.delete_success"));
|
|
} else {
|
|
openToast("error", res.msg);
|
|
}
|
|
});
|
|
};
|
|
|
|
const onClickout = (e) => {
|
|
e.stopPropagation();
|
|
cancelOpen();
|
|
getNewFilename();
|
|
selectedItem.value = null;
|
|
filenameInputIsOpen.value = false;
|
|
};
|
|
|
|
onMounted(() => {
|
|
getData();
|
|
document.querySelector("body").addEventListener("click", onClickout);
|
|
});
|
|
|
|
onUnmounted(() => {
|
|
document.querySelector("body").removeEventListener("click", onClickout);
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div
|
|
ref="sidebar"
|
|
class="custom-border py-2 px-4 sidebar"
|
|
@contextmenu.prevent.stop="onAddRightClick"
|
|
>
|
|
<Collapse
|
|
:open="true"
|
|
:data="graphData"
|
|
:onRightClick="onRightClick"
|
|
:onClick="onLeftClick"
|
|
:filenameInputIsOpen="filenameInputIsOpen"
|
|
:selected="selectedItem"
|
|
:edit="getNewFilename"
|
|
:openItem="openItem"
|
|
>
|
|
</Collapse>
|
|
<GraphSidebarDropdown
|
|
:position="dropdownPosition"
|
|
:open="dropdownOpen"
|
|
:selectedItem="selectedItem"
|
|
:edit="editFilename"
|
|
:add="addFilename"
|
|
:remove="deleteFilename"
|
|
/>
|
|
<p class="text-xl py-1 ml-7 cursor-pointer" @click.stop.prevent="onLeftClick(-1,null)">
|
|
<font-awesome-icon
|
|
:icon="['fas', 'trash-alt']"
|
|
class="text-rose-500 text-2xl me-3 "
|
|
/>{{$t("graphManagement.staging_area")}}
|
|
</p>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss" scoped></style>
|