fix: 設定 - 維運廠商 - modal 無法關閉問題
This commit is contained in:
parent
4db268d86b
commit
36e390d300
@ -1,38 +1,22 @@
|
||||
<script setup>
|
||||
import Table from "@/components/customUI/Table.vue";
|
||||
import VendorModal from "./VendorModal.vue";
|
||||
import { getOperationCompanyList,deleteOperationCompany } from "@/apis/operation";
|
||||
import {
|
||||
getOperationCompanyList,
|
||||
deleteOperationCompany,
|
||||
} from "@/apis/operation";
|
||||
import { onMounted, ref, inject, computed } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
const { t } = useI18n();
|
||||
const { openToast, cancelToastOpen } = inject("app_toast");
|
||||
|
||||
const columns = computed(() => [
|
||||
{
|
||||
title: t("operation.vendor"),
|
||||
key: "name",
|
||||
},
|
||||
{
|
||||
title: t("operation.contact_person"),
|
||||
key: "contact_person",
|
||||
},
|
||||
{
|
||||
title: t("operation.phone"),
|
||||
key: "phone",
|
||||
},
|
||||
{
|
||||
title: t("operation.email"),
|
||||
key: "email",
|
||||
},
|
||||
{
|
||||
title: t("operation.created_at"),
|
||||
key: "created_at",
|
||||
},
|
||||
{
|
||||
title: t("operation.operation"),
|
||||
key: "operation",
|
||||
width: 200,
|
||||
},
|
||||
{ title: t("operation.vendor"), key: "name" },
|
||||
{ title: t("operation.contact_person"), key: "contact_person" },
|
||||
{ title: t("operation.phone"), key: "phone" },
|
||||
{ title: t("operation.email"), key: "email" },
|
||||
{ title: t("operation.created_at"), key: "created_at" },
|
||||
{ title: t("operation.operation"), key: "operation", width: 200 },
|
||||
]);
|
||||
|
||||
const dataSource = ref([]);
|
||||
@ -49,7 +33,9 @@ onMounted(() => {
|
||||
getDataSource();
|
||||
});
|
||||
|
||||
const formState = ref({
|
||||
// ====== Modal 狀態與開關 ======
|
||||
const MODAL_ID = "company_modal";
|
||||
const emptyForm = () => ({
|
||||
contact_person: "",
|
||||
email: "",
|
||||
name: "",
|
||||
@ -60,22 +46,36 @@ const formState = ref({
|
||||
address: "",
|
||||
});
|
||||
|
||||
const openModal = (record) => {
|
||||
if (record.id) {
|
||||
formState.value = { ...record };
|
||||
} else {
|
||||
formState.value = {
|
||||
contact_person: "",
|
||||
email: "",
|
||||
name: "",
|
||||
phone: "",
|
||||
remark: "",
|
||||
tax_id_number: "",
|
||||
city: "",
|
||||
address: "",
|
||||
};
|
||||
const formState = ref(emptyForm());
|
||||
|
||||
// 同一函式同時處理:開啟(新增/編輯) 與 關閉
|
||||
const openModal = (payload) => {
|
||||
const el = document.getElementById(MODAL_ID);
|
||||
|
||||
// 關閉
|
||||
if (payload === false) {
|
||||
try {
|
||||
el?.close?.();
|
||||
} catch {}
|
||||
return;
|
||||
}
|
||||
|
||||
// 開啟(無參數或 true → 新增)
|
||||
if (payload === true || payload == null) {
|
||||
formState.value = emptyForm();
|
||||
try {
|
||||
el?.showModal?.();
|
||||
} catch {}
|
||||
return;
|
||||
}
|
||||
|
||||
// 開啟(有帶 record → 編輯)
|
||||
if (payload && typeof payload === "object") {
|
||||
formState.value = { ...emptyForm(), ...payload }; // 合併保險
|
||||
try {
|
||||
el?.showModal?.();
|
||||
} catch {}
|
||||
}
|
||||
company_modal.showModal();
|
||||
};
|
||||
|
||||
const remove = async (id) => {
|
||||
@ -95,15 +95,19 @@ const remove = async (id) => {
|
||||
<template>
|
||||
<div class="flex justify-start items-center mt-10 mb-5">
|
||||
<h3 class="text-xl mr-5">{{ $t("assetManagement.company") }}</h3>
|
||||
|
||||
<!-- 子層會渲染「新增」按鈕,照你的原樣 -->
|
||||
<VendorModal
|
||||
:formState="formState"
|
||||
:getData="getDataSource"
|
||||
:openModal="openModal"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Table :columns="columns" :dataSource="dataSource" :loading="loading">
|
||||
<template #bodyCell="{ record, column, index }">
|
||||
<template v-if="column.key === 'index'">{{ index + 1 }}</template>
|
||||
|
||||
<template v-else-if="column.key === 'operation'">
|
||||
<button
|
||||
class="btn btn-sm btn-success text-white mr-2"
|
||||
@ -118,6 +122,7 @@ const remove = async (id) => {
|
||||
{{ $t("button.delete") }}
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
{{ record[column.key] }}
|
||||
</template>
|
||||
|
@ -1,23 +1,21 @@
|
||||
<script setup>
|
||||
import { ref, onMounted, defineProps, inject, watch } from "vue";
|
||||
import { ref, inject } from "vue";
|
||||
import * as yup from "yup";
|
||||
import "yup-phone-lite";
|
||||
import useFormErrorMessage from "@/hooks/useFormErrorMessage";
|
||||
import {
|
||||
postOperationCompany,
|
||||
updateOperationCompany,
|
||||
} from "@/apis/operation";
|
||||
import { postOperationCompany, updateOperationCompany } from "@/apis/operation";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
const { openToast } = inject("app_toast");
|
||||
|
||||
const props = defineProps({
|
||||
formState: Object,
|
||||
getData: Function,
|
||||
openModal: Function
|
||||
openModal: Function, // 父層傳入:開/關 modal
|
||||
});
|
||||
|
||||
const deptScheme = yup.object({
|
||||
const schema = yup.object({
|
||||
name: yup.string().required(t("button.required")),
|
||||
contact_person: yup.string().nullable(true),
|
||||
email: yup.string().email().nullable(true),
|
||||
@ -28,34 +26,104 @@ const deptScheme = yup.object({
|
||||
remark: yup.string().nullable(true),
|
||||
});
|
||||
|
||||
const { formErrorMsg, handleSubmit, handleErrorReset, updateScheme } =
|
||||
useFormErrorMessage(deptScheme);
|
||||
const { formErrorMsg, handleSubmit, handleErrorReset } =
|
||||
useFormErrorMessage(schema);
|
||||
|
||||
const loading = ref(false);
|
||||
const MODAL_ID = "company_modal";
|
||||
|
||||
/** ====== 關閉 Modal:多重保險 ====== */
|
||||
const closeModal = () => {
|
||||
// 1) 父層 boolean 控制
|
||||
if (typeof props.openModal === "function") {
|
||||
try {
|
||||
if (props.openModal.length >= 1) {
|
||||
// 偏好:openModal(false)
|
||||
props.openModal(false);
|
||||
} else {
|
||||
// 兼容:無參數 toggler → 先嘗試傳 false,不行再當作切換
|
||||
try {
|
||||
props.openModal(false);
|
||||
} catch {
|
||||
props.openModal();
|
||||
}
|
||||
}
|
||||
return;
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
// 2) 原生 <dialog> 或可 close() 的自製 Modal
|
||||
const el = document.getElementById(MODAL_ID);
|
||||
if (el?.close) {
|
||||
try {
|
||||
el.close();
|
||||
return;
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
// 3) 發送一個常見的關閉事件給自製 Modal(若有監聽)
|
||||
try {
|
||||
el?.dispatchEvent?.(new CustomEvent("close", { bubbles: true }));
|
||||
} catch (_) {}
|
||||
};
|
||||
|
||||
/** ====== 開啟 Modal:呼叫父層 ====== */
|
||||
const openModal = () => {
|
||||
if (typeof props.openModal === "function") {
|
||||
try {
|
||||
if (props.openModal.length >= 1) props.openModal(true);
|
||||
else props.openModal();
|
||||
} catch {
|
||||
// 忽略
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onCancel = () => {
|
||||
handleErrorReset();
|
||||
company_modal.close();
|
||||
// 只做「關閉」;不要清空內容,避免你說的「取消→內容被清空但沒關」情況
|
||||
// 若要清錯誤訊息,可在下次打開前再清
|
||||
closeModal();
|
||||
};
|
||||
|
||||
const onOk = async () => {
|
||||
const value = await handleSubmit(deptScheme, props.formState);
|
||||
if (props.formState?.id) {
|
||||
res = await updateOperationCompany(value);
|
||||
} else {
|
||||
res = await postOperationCompany(value);
|
||||
}
|
||||
if (res.isSuccess) {
|
||||
props.getData();
|
||||
onCancel();
|
||||
} else {
|
||||
openToast("error", res.msg, "#company_modal");
|
||||
try {
|
||||
loading.value = true;
|
||||
|
||||
const value = await handleSubmit(schema, props.formState);
|
||||
|
||||
let res;
|
||||
if (props.formState?.id) {
|
||||
// 若你的 API 需要 id 參數,改成:updateOperationCompany(props.formState.id, value)
|
||||
res = await updateOperationCompany(value);
|
||||
} else {
|
||||
res = await postOperationCompany(value);
|
||||
}
|
||||
|
||||
if (res?.isSuccess) {
|
||||
await props.getData?.();
|
||||
props.openModal(false);
|
||||
// 成功後關閉
|
||||
closeModal();
|
||||
// 下次打開前再清錯誤
|
||||
handleErrorReset();
|
||||
props.openModal(false);
|
||||
openToast?.("success", t("common.success"), `#${MODAL_ID}`);
|
||||
} else {
|
||||
openToast?.("error", res?.msg ?? t("common.failed"), `#${MODAL_ID}`);
|
||||
}
|
||||
} catch (err) {
|
||||
openToast?.("error", err?.message ?? t("common.failed"), `#${MODAL_ID}`);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button class="btn btn-sm btn-add " @click.stop.prevent="props.openModal">
|
||||
<button class="btn btn-sm btn-add" @click.stop.prevent="openModal">
|
||||
<font-awesome-icon :icon="['fas', 'plus']" />{{ $t("button.add") }}
|
||||
</button>
|
||||
|
||||
<Modal
|
||||
id="company_modal"
|
||||
:title="props.formState?.id ? t('button.edit') : t('button.add')"
|
||||
@ -63,87 +131,79 @@ const onOk = async () => {
|
||||
width="710"
|
||||
>
|
||||
<template #modalContent>
|
||||
<form ref="form" class="mt-5 w-full flex flex-wrap justify-between">
|
||||
<Input :value="formState" class="my-2" name="name">
|
||||
<form class="mt-5 w-full flex flex-wrap justify-between">
|
||||
<Input :value="props.formState" class="my-2" name="name">
|
||||
<template #topLeft>{{ $t("operation.name") }}</template>
|
||||
<template #bottomLeft
|
||||
><span class="text-error text-base">
|
||||
{{ formErrorMsg.name }}
|
||||
</span></template
|
||||
></Input
|
||||
>
|
||||
<Input :value="formState" class="my-2" name="contact_person">
|
||||
<template #bottomLeft>
|
||||
<span class="text-error text-base">{{ formErrorMsg.name }}</span>
|
||||
</template>
|
||||
</Input>
|
||||
<Input :value="props.formState" class="my-2" name="contact_person">
|
||||
<template #topLeft>{{ $t("operation.contact_person") }}</template>
|
||||
<template #bottomLeft
|
||||
><span class="text-error text-base">
|
||||
{{ formErrorMsg.contact_person }}
|
||||
</span></template
|
||||
></Input
|
||||
>
|
||||
<Input :value="formState" class="my-2" name="phone">
|
||||
<template #bottomLeft>
|
||||
<span class="text-error text-base">{{
|
||||
formErrorMsg.contact_person
|
||||
}}</span>
|
||||
</template>
|
||||
</Input>
|
||||
<Input :value="props.formState" class="my-2" name="phone">
|
||||
<template #topLeft>{{ $t("operation.phone") }}</template>
|
||||
<template #bottomLeft
|
||||
><span class="text-error text-base">
|
||||
{{ formErrorMsg.phone }}
|
||||
</span></template
|
||||
></Input
|
||||
>
|
||||
<Input :value="formState" class="my-2" name="email">
|
||||
<template #bottomLeft>
|
||||
<span class="text-error text-base">{{ formErrorMsg.phone }}</span>
|
||||
</template>
|
||||
</Input>
|
||||
<Input :value="props.formState" class="my-2" name="email">
|
||||
<template #topLeft>{{ $t("operation.email") }}</template>
|
||||
<template #bottomLeft
|
||||
><span class="text-error text-base">
|
||||
{{ formErrorMsg.email }}
|
||||
</span></template
|
||||
></Input
|
||||
>
|
||||
<Input :value="formState" class="my-2" name="city">
|
||||
<template #bottomLeft>
|
||||
<span class="text-error text-base">{{ formErrorMsg.email }}</span>
|
||||
</template>
|
||||
</Input>
|
||||
<Input :value="props.formState" class="my-2" name="city">
|
||||
<template #topLeft>{{ $t("operation.city") }}</template>
|
||||
<template #bottomLeft
|
||||
><span class="text-error text-base">
|
||||
{{ formErrorMsg.city }}
|
||||
</span></template
|
||||
></Input
|
||||
>
|
||||
<Input :value="formState" class="my-2" name="address">
|
||||
<template #bottomLeft>
|
||||
<span class="text-error text-base">{{ formErrorMsg.city }}</span>
|
||||
</template>
|
||||
</Input>
|
||||
<Input :value="props.formState" class="my-2" name="address">
|
||||
<template #topLeft>{{ $t("operation.address") }}</template>
|
||||
<template #bottomLeft
|
||||
><span class="text-error text-base">
|
||||
{{ formErrorMsg.address }}
|
||||
</span></template
|
||||
></Input
|
||||
>
|
||||
<Input :value="formState" class="my-2" name="tax_id_number">
|
||||
<template #bottomLeft>
|
||||
<span class="text-error text-base">{{ formErrorMsg.address }}</span>
|
||||
</template>
|
||||
</Input>
|
||||
<Input :value="props.formState" class="my-2" name="tax_id_number">
|
||||
<template #topLeft>{{ $t("operation.tax_id_number") }}</template>
|
||||
<template #bottomLeft
|
||||
><span class="text-error text-base">
|
||||
{{ formErrorMsg.tax_id_number }}
|
||||
</span></template
|
||||
></Input
|
||||
>
|
||||
<Input :value="formState" class="my-2" name="remark">
|
||||
<template #bottomLeft>
|
||||
<span class="text-error text-base">{{
|
||||
formErrorMsg.tax_id_number
|
||||
}}</span>
|
||||
</template>
|
||||
</Input>
|
||||
<Input :value="props.formState" class="my-2" name="remark">
|
||||
<template #topLeft>{{ $t("operation.remark") }}</template>
|
||||
<template #bottomLeft
|
||||
><span class="text-error text-base">
|
||||
{{ formErrorMsg.remark }}
|
||||
</span></template
|
||||
></Input
|
||||
>
|
||||
|
||||
<template #bottomLeft>
|
||||
<span class="text-error text-base">{{ formErrorMsg.remark }}</span>
|
||||
</template>
|
||||
</Input>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<template #modalAction>
|
||||
<button
|
||||
type="reset"
|
||||
type="button"
|
||||
class="btn btn-outline-success mr-2"
|
||||
@click.prevent="onCancel"
|
||||
:disabled="loading"
|
||||
>
|
||||
{{ $t("button.cancel") }}
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
type="button"
|
||||
class="btn btn-outline-success"
|
||||
@click.stop.prevent="onOk"
|
||||
:disabled="loading"
|
||||
>
|
||||
<span v-if="loading" class="loading loading-spinner loading-xs mr-2" />
|
||||
{{ $t("button.submit") }}
|
||||
</button>
|
||||
</template>
|
||||
|
Loading…
Reference in New Issue
Block a user