This commit is contained in:
Viet An
2026-07-09 16:45:48 +07:00
parent 42124d4071
commit df4ed4bd4d
20 changed files with 726 additions and 964 deletions

View File

@@ -1,102 +1,91 @@
<template>
<div class="box">
<div class="level">
<div class="level-left">
<h5 class="title is-5">Automation Jobs</h5>
</div>
<div class="level-right">
<button
class="button is-primary"
@click="openNewJobForm"
>
<span class="icon">
<Icon
name="material-symbols:add-rounded"
:size="18"
/>
</span>
<span>Add New Job</span>
</button>
</div>
<div>
<div class="block is-flex is-gap-1 is-align-items-center is-justify-content-space-between">
<p class="fs-17 font-semibold">Automation Jobs</p>
<button
class="button is-primary"
@click="openNewJobForm"
>
<span class="icon">
<Icon
name="material-symbols:add-rounded"
:size="18"
/>
</span>
<span>Add New Job</span>
</button>
</div>
<div
<p
v-if="isLoading"
class="has-text-centered"
class="has-text-centered has-text-grey py-4"
>
<p>Loading jobs...</p>
</div>
<div
Loading jobs...
</p>
<p
v-else-if="jobs.length === 0"
class="has-text-centered"
class="has-text-centered has-text-grey py-4"
>
<p>No automation jobs found for this template.</p>
</div>
No automation jobs found for this template.
</p>
<div v-else>
<div
v-for="job in jobs"
:key="job.id"
class="mb-4 p-3 border"
class="mb-4 p-3 rounded"
style="border: 1px solid var(--bulma-grey-90)"
>
<div class="level">
<div class="level-left">
<div>
<p class="has-text-weight-bold">{{ job.name }}</p>
<p class="is-size-7">Model: {{ job.model_name }}</p>
<p class="is-size-7">
Triggers:
<span
v-if="job.trigger_on_create"
class="tag is-info is-light mr-1"
>On Create</span
>
<span
v-if="job.trigger_on_update"
class="tag is-warning is-light"
>On Update</span
>
</p>
</div>
<div class="is-flex is-gap-1 is-justify-content-space-between is-align-items-center">
<div class="is-flex-shrink-1">
<p class="font-semibold mb-1">{{ job.name }}</p>
<p class="is-size-7">Model: {{ job.model_name }}</p>
<p class="is-size-7">
Triggers:
<span
v-if="job.trigger_on_create"
class="tag is-info is-light mr-1"
>On Create</span
>
<span
v-if="job.trigger_on_update"
class="tag is-warning is-light"
>On Update</span
>
</p>
</div>
<div class="level-right">
<div class="field has-addons">
<div class="control">
<button
class="button is-small"
:class="{ 'is-success': job.active, 'is-light': !job.active }"
@click="toggleJobStatus(job)"
>
{{ job.active ? "Active" : "Inactive" }}
</button>
</div>
<div class="control">
<button
class="button is-small"
@click="openEditJobForm(job)"
>
<span class="icon">
<Icon
name="material-symbols:edit-outline-rounded"
:size="18"
/>
</span>
</button>
</div>
<div class="control">
<button
class="button is-danger is-small"
@click="confirmDelete(job)"
>
<span class="icon">
<Icon
name="material-symbols:delete-outline-rounded"
:size="18"
/>
</span>
</button>
</div>
<div class="field has-addons">
<div class="control">
<button
:class="['button is-small', job.active && 'is-primary']"
@click="toggleJobStatus(job)"
>
{{ job.active ? "Active" : "Inactive" }}
</button>
</div>
<div class="control">
<button
class="button is-small"
@click="openEditJobForm(job)"
>
<span class="icon">
<Icon
name="material-symbols:edit-outline-rounded"
:size="18"
/>
</span>
</button>
</div>
<div class="control">
<button
class="button is-danger is-small"
@click="confirmDelete(job)"
>
<span class="icon">
<Icon
name="material-symbols:delete-outline-rounded"
:size="18"
/>
</span>
</button>
</div>
</div>
</div>
@@ -197,7 +186,7 @@
</div>
</template>
<script setup lang="ts">
<script setup>
import { apiUrl, putApiUrl } from "~/components/marketing/email/Email.utils";
const props = defineProps({
@@ -207,10 +196,9 @@ const props = defineProps({
},
});
const nuxtApp = useNuxtApp();
const $snackbar = nuxtApp.$snackbar as (message: string) => void;
const { $getdata, $snackbar } = useNuxtApp();
const jobs = ref<any[]>([]);
const jobs = ref([]);
const isLoading = ref(false);
const isSaving = ref(false);
const showForm = ref(false);
@@ -238,7 +226,11 @@ const fetchJobs = async () => {
const response = await $fetch(`${apiUrl}/Email_Job/`, {
params: { template_id: props.templateId },
});
jobs.value = response.rows || [];
jobs.value = await $getdata("Email_Job", {
filter: {
template_id: props.templateId,
},
});
} catch (error) {
console.error("Error fetching email jobs:", error);
$snackbar(`Error fetching jobs`);
@@ -259,7 +251,7 @@ const openNewJobForm = () => {
showForm.value = true;
};
const openEditJobForm = (job: any) => {
const openEditJobForm = (job) => {
isEditing.value = true;
jobForm.value = { ...job };
showForm.value = true;
@@ -283,19 +275,19 @@ const saveJob = async () => {
body: data,
});
if (response) {
$snackbar(`Job saved successfully`);
$snackbar("Job saved successfully", "Success");
await fetchJobs();
closeForm();
}
} catch (error) {
console.error("Error saving job:", error);
$snackbar(`Error saving job`);
$snackbar("Error saving job", "Error");
} finally {
isSaving.value = false;
}
};
const toggleJobStatus = async (job: any) => {
const toggleJobStatus = async (job) => {
const updatedJob = { ...job, active: !job.active };
try {
await $fetch(`${putApiUrl}/Email_Job/${job.id}`, {
@@ -310,13 +302,13 @@ const toggleJobStatus = async (job: any) => {
}
};
const confirmDelete = (job: any) => {
const confirmDelete = (job) => {
if (confirm(`Are you sure you want to delete the job "${job.name}"?`)) {
deleteJob(job.id);
}
};
const deleteJob = async (jobId: number) => {
const deleteJob = async (jobId) => {
try {
await $fetch(`${putApiUrl}/Email_Job/${jobId}`, {
method: "DELETE",
@@ -333,13 +325,6 @@ onMounted(fetchJobs);
</script>
<style scoped>
.box {
padding: 1.5rem;
}
.border {
border: 1px solid #dbdbdb;
border-radius: 4px;
}
.modal-card-foot {
justify-content: flex-end;
}