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/components/atoms/organisms/WorkflowsBaseDialog.vue

277 lines
7.4 KiB

11 months ago
<script setup lang="ts">
import IconArrowDown from "@/components/atoms/button/IconArrowDown.vue";
import IconArrowUp from "@/components/atoms/button/IconArrowUp.vue";
import IconDeleteBtn from "@/components/atoms/button/IconDeleteBtn.vue";
import IconModifyBtn from "@/components/atoms/button/IconModifyBtn.vue";
import { computed, onBeforeUnmount, onMounted, watch, ref } from "vue";
import { WorkflowService } from "@/components/service/management/workflowService";
import { storage } from "@/utils/storage";
import type { Workflow } from "@/components/models/management/Workflow";
import { storeToRefs } from "pinia";
import { useAutoflowStore } from "@/stores/autoflowStore";
const { projectId } = storeToRefs(useAutoflowStore());
const props = defineProps<{
editData: any;
mode: "create" | "edit";
}>();
const emit = defineEmits<{
(e: "close-modal"): void;
(e: "saved", value: any): void;
}>();
const isEdit = computed(() => props.mode === "edit");
const saving = ref(false);
const errorMsg = ref("");
11 months ago
const steps = ref([
{ order: 1, stepName: "Data Load", type: "DataPrep", status: "Configured" },
{
order: 2,
stepName: "Preprocessing",
type: "Preprocess",
status: "Not Configured",
},
{
order: 3,
stepName: "Train Model",
type: "Train",
status: "Not Configured",
},
]);
/** form state */
11 months ago
const form = ref({
name: "",
description: "",
});
/** props.editData -> form 바인딩 */
function hydrateFormFromEdit(data: any) {
if (!data) return;
form.value.name = data.workflowName ?? data.name ?? "";
form.value.description = data.workflowDescription ?? data.description ?? "";
}
onMounted(() => {
if (isEdit.value) hydrateFormFromEdit(props.editData);
});
watch(
() => props.editData,
(v) => {
if (isEdit.value) hydrateFormFromEdit(v);
},
);
/** 시간 포맷 */
const nowLocalIso = (): string => {
const t = new Date(Date.now() - new Date().getTimezoneOffset() * 60000);
return t.toISOString().slice(0, 23);
};
async function submit() {
errorMsg.value = "";
const name = form.value.name.trim();
if (!name) {
errorMsg.value = "Workflow Name은 필수입니다.";
return;
}
// 로그인 사용자
const authObj =
(typeof storage?.getAuth === "function" ? storage.getAuth() : null) ??
JSON.parse(localStorage.getItem("autoflow-auth") || "{}");
const regUserId =
authObj?.userInfo?.username ??
authObj?.userinfo?.username ??
authObj?.username ??
authObj?.userId ??
"";
if (!regUserId) {
errorMsg.value = "로그인 사용자 정보를 찾을 수 없습니다.";
return;
}
const now = nowLocalIso();
const payload: Workflow = {
workflowName: name,
workflowDescription: form.value.description?.trim() || "",
uploadYn: "Y",
regUserId,
regDt: now,
modDt: now,
projectId: projectId.value,
};
try {
saving.value = true;
if (isEdit.value) {
// 수정: id 추출(행에서 넘겨준 deviceKey 또는 id 지원)
const rawId = props.editData?.id ?? props.editData?.deviceKey;
const id = Number(rawId);
if (!id) {
errorMsg.value = "수정할 ID가 없습니다.";
return;
}
const { data } = await WorkflowService.update(id, payload);
emit("saved", data);
emit("close-modal");
} else {
// 생성
const { data } = await WorkflowService.add(payload);
emit("saved", data);
emit("close-modal");
}
} catch (e) {
console.error("워크플로우 저장 실패:", e);
errorMsg.value = "저장에 실패했습니다. 잠시 후 다시 시도하세요.";
} finally {
saving.value = false;
}
}
/** ESC로 닫기 */
function onEsc(e: KeyboardEvent) {
if (e.key === "Escape") emit("close-modal");
}
onMounted(() => window.addEventListener("keydown", onEsc));
onBeforeUnmount(() => window.removeEventListener("keydown", onEsc));
11 months ago
</script>
<template>
<v-card>
<!-- 타이틀 -->
11 months ago
<v-card-title
class="text-white font-weight-bold text-h6"
style="background-color: #1976d2"
>
{{ isEdit ? "Edit Workflow" : "Create Workflow" }}
11 months ago
</v-card-title>
<v-card-text class="pa-6">
<div class="text-subtitle-1 font-weight-medium mb-4">
Workflow Information
</div>
11 months ago
<v-form @submit.prevent="submit">
<div class="mb-5">
<label class="text-subtitle-2 font-weight-medium mb-1 d-block"
>Workflow Name</label
>
<v-text-field
v-model="form.name"
variant="outlined"
:disabled="saving"
11 months ago
dense
hide-details
required
/>
</div>
<div>
<label class="text-subtitle-2 font-weight-medium mb-1 d-block"
>Workflow Description</label
>
<v-textarea
v-model="form.description"
variant="outlined"
:disabled="saving"
11 months ago
rows="3"
dense
hide-details
/>
</div>
<div v-if="errorMsg" class="mt-3 text-error">{{ errorMsg }}</div>
11 months ago
</v-form>
</v-card-text>
<v-card-text class="pt-6 pb-4 px-6">
<div class="text-subtitle-1 font-weight-medium mb-4">Workflow Steps</div>
11 months ago
<v-row class="align-center mb-4">
<v-col cols="auto"
><v-btn color="primary" small :disabled="saving"
><v-icon left>mdi-plus</v-icon> Add Step</v-btn
></v-col
>
<v-col cols="auto"
><v-btn color="success" small :loading="saving" @click="submit">{{
isEdit ? "Update" : "Save"
}}</v-btn></v-col
>
<v-col cols="auto"
><v-btn
color="grey"
small
:disabled="saving"
@click="$emit('close-modal')"
>Cancel</v-btn
></v-col
>
11 months ago
<v-spacer />
</v-row>
<v-simple-table dense>
<thead>
<tr class="grey lighten-2">
<th class="text-center" style="width: 5%">Order</th>
<th class="text-center">Step Name</th>
<th class="text-center">Component Type</th>
<th class="text-center">Status</th>
<th class="text-center" style="width: 20%">Action</th>
</tr>
</thead>
<tbody>
<tr
v-for="step in steps"
11 months ago
:key="step.order"
style="border: 1px solid #ccc"
>
<td class="text-center">{{ step.order }}</td>
<td class="text-center">{{ step.stepName }}</td>
<td class="d-flex justify-center align-center">
<v-select
v-model="step.type"
:items="['DataPrep', 'Preprocess', 'Train']"
dense
hide-details
style="max-width: 180px"
/>
</td>
<td class="text-center">{{ step.status }}</td>
<td class="text-center">
<IconArrowUp />
<IconArrowDown />
<IconModifyBtn />
<IconDeleteBtn />
</td>
</tr>
</tbody>
</v-simple-table>
</v-card-text>
<v-card-actions class="justify-end" style="padding: 16px 24px">
<v-btn color="success" :loading="saving" @click="submit">{{
isEdit ? "Update" : "Save"
}}</v-btn>
<v-btn
text
class="white--text"
:disabled="saving"
@click="$emit('close-modal')"
11 months ago
>Close</v-btn
>
</v-card-actions>
</v-card>
</template>