Files
web/app/components/accounting/ConfirmDeleteEntry.vue
2026-05-05 11:06:49 +07:00

149 lines
4.1 KiB
Vue

<template>
<div class="has-text-centered">
<div class="mb-3 p-3">
<p class="is-size-5 has-text-weight-semibold mb-4">Bạn chắc chắn muốn xóa bút toán này?</p>
<p class="mt-3 has-text-danger has-text-weight-semibold">
Hành động này <strong>không thể hoàn tác</strong>.<br />
Dữ liệu liên quan (nếu ) sẽ bị xóa vĩnh viễn.
</p>
</div>
<div class="field is-grouped is-justify-content-center">
<!-- Captcha addon group - shown only when captcha is not confirmed -->
<div
class="control"
v-if="!isConfirmed"
>
<div class="field has-addons">
<p class="control">
<input
class="input"
type="text"
placeholder="Nhập mã xác nhận"
v-model="userInputCaptcha"
@keyup.enter="isConfirmed && confirmDelete()"
/>
</p>
<p class="control">
<a
class="button is-static has-text-weight-bold has-background-grey-lighter"
style="font-family: &quot;Courier New&quot;, monospace; letter-spacing: 2px"
>
{{ captchaCode }}
</a>
</p>
<p class="control">
<button
class="button"
@click="generateCaptcha"
title="Tạo mã mới"
>
<span class="icon">
<SvgIcon
name="refresh.svg"
type="primary"
:size="23"
></SvgIcon>
</span>
</button>
</p>
</div>
</div>
<!-- Action buttons -->
<!-- Confirm button - shown only when captcha IS confirmed -->
<p
class="control"
v-if="isConfirmed"
>
<button
class="button is-danger"
:class="{ 'is-loading': isDeleting }"
:disabled="isDeleting"
@click="confirmDelete"
>
Xác nhận xóa
</button>
</p>
<!-- Cancel button - always shown -->
<p class="control">
<button
class="button"
:disabled="isDeleting"
@click="cancel"
>
Hủy
</button>
</p>
</div>
</div>
</template>
<script setup>
import { ref, computed } from "vue";
import { useNuxtApp } from "#app";
const props = defineProps({
entryId: {
type: [String, Number],
required: true,
},
});
const emit = defineEmits(["close", "deleted"]);
const { $snackbar, $insertapi } = useNuxtApp();
const isDeleting = ref(false);
const captchaCode = ref("");
const userInputCaptcha = ref("");
const isConfirmed = computed(() => {
return userInputCaptcha.value.toLowerCase() === captchaCode.value.toLowerCase() && userInputCaptcha.value !== "";
});
const generateCaptcha = () => {
captchaCode.value = Math.random().toString(36).substring(2, 7).toUpperCase();
userInputCaptcha.value = "";
};
// Initial generation
generateCaptcha();
const confirmDelete = async () => {
if (isDeleting.value || !isConfirmed.value) return;
isDeleting.value = true;
try {
// Gọi API xóa theo đúng endpoint delete-entry/{id}
const result = await $insertapi("deleteentry", { id: props.entryId });
if (result === "error" || !result) {
throw new Error("API xóa trả về lỗi");
}
$snackbar(`Đã xóa bút toán ID ${props.entryId} thành công`, "Thành công", "Success");
emit("deleted", props.entryId);
emit("close");
} catch (err) {
console.error("Xóa bút toán thất bại:", err);
let errorMsg = "Không thể xóa bút toán. Vui lòng thử lại.";
// Nếu backend trả về thông báo cụ thể
if (err?.response?.data?.detail) {
errorMsg = err.response.data.detail;
} else if (err?.response?.data?.non_field_errors) {
errorMsg = err.response.data.non_field_errors.join(" ");
}
$snackbar(errorMsg, "Lỗi", "Danger");
} finally {
isDeleting.value = false;
}
};
const cancel = () => {
emit("close");
};
</script>