You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
autoflow-web-console/src/views/Select.vue

269 lines
7.4 KiB

<script setup lang="ts">
import { ApiProject, UiProject } from "@/components/models/project/Project";
import { UserManagerService } from "@/components/service/management/userManagerService";
import { ProjectService } from "@/components/service/project/projectService";
import { useAutoflowStore } from "@/stores/autoflowStore";
import { storeToRefs } from "pinia";
import { onMounted, ref } from "vue";
import { useRouter } from "vue-router";
const dialog = ref(false);
const contextMenu = ref(false);
const menuX = ref(0);
const menuY = ref(0);
const selectedIndex = ref<number | null>(null);
const projects = ref<UiProject[]>([]);
const userOptions = ref<string[]>([]);
const modalMode = ref<"create" | "edit">("create");
const editingProjectId = ref<number | null>(null);
const autoflowStore = useAutoflowStore();
const router = useRouter();
const form = ref({
prjCd: "",
prjNm: "",
prjDesc: "",
selectedUsers: [] as string[],
});
const loadProjects = async (): Promise<void> => {
try {
const res = await ProjectService.search();
projects.value = res.data.map((p) => ({
id: p.id!,
title: p.prjNm,
creator: p.regUserId,
date: p.prjStartDt,
description: p.prjDesc,
}));
} catch (error) {
console.error("프로젝트 조회 실패:", error);
}
};
const loadUsers = async () => {
try {
const res = await UserManagerService.getAll();
userOptions.value = res.data.map((u: any) => u.username);
} catch (err) {
console.error("사용자 조회 실패:", err);
}
};
const selectProject = (idx: number): void => {
const p = projects.value[idx];
autoflowStore.setProjectName(p.title);
router.push("/home");
};
const openContextMenu = (e: MouseEvent, idx: number): void => {
e.preventDefault();
selectedIndex.value = idx;
menuX.value = e.pageX;
menuY.value = e.pageY;
contextMenu.value = true;
};
const saveProject = async () => {
const payload: ApiProject = {
id: modalMode.value === "edit" ? editingProjectId.value! : null,
prjCd: form.value.prjCd,
prjNm: form.value.prjNm,
prjDesc: form.value.prjDesc,
prjStartDt: new Date().toISOString().slice(0, 10),
prjEndDt: new Date().toISOString().slice(0, 10),
delYn: "N",
regDate: new Date().toISOString(),
regUserId: form.value.selectedUsers.join(","),
regUserNm: form.value.selectedUsers.join(","),
modDate: new Date().toISOString(),
modUserId: form.value.selectedUsers.join(","),
modUserNm: form.value.selectedUsers.join(","),
};
try {
if (modalMode.value === "create") {
await ProjectService.add(payload);
} else {
await ProjectService.update(editingProjectId.value!, payload);
}
await loadProjects();
closeDialog();
} catch (err) {
console.error(`${modalMode.value} 실패:`, err);
}
};
const deleteProject = async (): Promise<void> => {
contextMenu.value = false;
const idx = selectedIndex.value;
if (idx === null) return;
const p = projects.value[idx];
try {
await ProjectService.delete(p.id);
await loadProjects();
} catch (error) {
console.error("삭제 실패:", error);
}
};
const onAddProject = () => {
modalMode.value = "create";
editingProjectId.value = null;
form.value.prjCd = `PRJ${Date.now()}`;
form.value.prjNm = "";
form.value.prjDesc = "";
form.value.selectedUsers = [];
dialog.value = true;
};
const modifyProject = () => {
contextMenu.value = false;
const idx = selectedIndex.value;
if (idx === null) return;
const p = projects.value[idx];
modalMode.value = "edit";
editingProjectId.value = p.id;
form.value.prjCd = p.title;
form.value.prjNm = p.title;
form.value.prjDesc = p.description;
form.value.selectedUsers = p.creator.split(",");
dialog.value = true;
};
const cancel = () => {
dialog.value = false;
};
const closeDialog = () => {
dialog.value = false;
contextMenu.value = false;
selectedIndex.value = null;
};
onMounted(() => {
loadProjects();
loadUsers();
});
</script>
<template>
<v-container class="mt-12" style="max-width: 1600px">
<v-row class="mb-6" align="center" justify="space-between">
<v-col cols="auto">
<h2 class="font-weight-bold text-h5">Project Selection</h2>
</v-col>
<v-col cols="auto">
<v-btn
color="secondary"
variant="flat"
class="text-white font-weight-bold"
@click="onAddProject"
>
<v-icon left icon="mdi-plus" size="20" />
Create Project
</v-btn>
</v-col>
</v-row>
<v-row dense>
<v-col
v-for="(project, index) in projects"
:key="index"
cols="12"
sm="6"
md="6"
lg="6"
class="d-flex"
>
<v-card
class="pa-4 flex-grow-1 d-flex flex-column"
color="primary"
variant="elevated"
elevation="6"
rounded="lg"
@click="selectProject(index)"
@contextmenu.prevent="(e) => openContextMenu(e, index)"
>
<v-card-title class="d-flex align-center">
<v-icon color="#6EC1E4" icon="mdi-file" start size="18" />
<h4>{{ project.title }}</h4>
</v-card-title>
<v-card-subtitle
class="text-white text-caption d-flex justify-space-between"
>
<span>생성자: {{ project.creator }}</span>
<span>등록일: {{ project.date }}</span>
</v-card-subtitle>
<v-card-text
class="text-white mt-3 text-body-2 flex-grow-1"
style="white-space: normal"
>
{{ project.description }}
</v-card-text>
</v-card>
</v-col>
</v-row>
<v-menu
v-model="contextMenu"
absolute
:style="{ top: menuY + 'px', left: menuX + 'px' }"
max-width="180"
width="130"
>
<v-list>
<v-list-item @click="modifyProject">
<v-list-item-icon
><v-icon>mdi-square-edit-outline</v-icon></v-list-item-icon
>
<v-list-item-title>Modify</v-list-item-title>
</v-list-item>
<v-list-item @click="deleteProject">
<v-list-item-icon><v-icon>mdi-delete</v-icon></v-list-item-icon>
<v-list-item-title>Delete</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
<v-dialog v-model="dialog" max-width="500">
<v-card>
<!-- 모드에 따라 타이틀 변경 -->
<v-card-title class="headline">
{{ modalMode === "create" ? "Create Project" : "Modify Project" }}
</v-card-title>
<v-card-text>
<v-form>
<v-text-field label="Project Name" v-model="form.prjNm" required />
<v-textarea
label="Description"
v-model="form.prjDesc"
rows="3"
required
/>
<v-select
label="Select Users"
v-model="form.selectedUsers"
:items="userOptions"
multiple
chips
closable-chips
/>
</v-form>
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn text @click="closeDialog">Cancel</v-btn>
<!-- 클릭 핸들러도 공용 saveProject -->
<v-btn color="primary" @click="saveProject">
{{ modalMode === "create" ? "Create" : "Save" }}
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-container>
</template>
<style scoped></style>