Merge branch 'dev' into develop

This commit is contained in:
Net 2024-07-19 16:11:44 +07:00
commit 084d400d30
10 changed files with 8399 additions and 20 deletions

7355
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,526 @@
<script setup lang="ts">
import { ref, onMounted, computed, watch } from "vue";
import { useQuasar } from "quasar";
/**
* importType
*/
import type { QTableProps } from "quasar";
import type { Schedule } from "@/modules/04_system/interface/response/Main";
import type { ScheduleCreate } from "@/modules/04_system/interface/request/Main";
import type { ItemsTeb } from "@/modules/04_system/interface/index/Main";
/**
* import components
*/
import FormDialog from "@/modules/04_system/components/formDialog.vue";
import formSchedule from "./formSchedule .vue";
/**
* importStore
*/
import { useCounterMixin } from "@/stores/mixin";
import { useDataStore } from "@/modules/04_system/stores/main";
import { storeToRefs } from "pinia";
/**
* use
*/
const $q = useQuasar();
const { showLoader, hideLoader, date2Thai, dialogRemove, dialogConfirm } =
useCounterMixin();
const {
fetchListBackup,
createBackUp,
restore,
deleteBackUp,
backupRunningList,
restoreRunningList,
getSize,
getSchedule,
createSchedule,
editSchedule,
deleteSchedule,
toggleSchedule,
} = useDataStore();
const storeData = useDataStore();
const { dataBackUp, restoreRunTotal, dataSchedule } = storeToRefs(storeData);
/**
* props
*/
/**
* ref
*/
const idEditSchedule = ref<string>("");
const openDialog = ref<boolean>(false);
const prevFormDataschedule = ref<ScheduleCreate>({
timeStartEvery: "",
type: "",
date: [],
name: "",
time: "",
schedule: "",
});
const formDataschedule = ref<ScheduleCreate>({
timeStartEvery: "",
type: "",
date: [],
name: "",
time: "",
schedule: "",
});
/**
* Table
*/
const filter = ref<string>("");
const visibleColumns = ref<string[]>([
"name",
"type",
"date",
"startAt",
"status",
]);
const baseColumns = ref<QTableProps["columns"]>([
{
name: "name",
align: "left",
label: "ชื่อของข้อมูลสำรองใหม่",
sortable: true,
field: "name",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "type",
align: "center",
label: "ตารางการข้อมูลสำรองใหม่",
sortable: true,
// field: (v) => date2Thai(v, false, true),
field: "type",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "date",
align: "left",
label: "เวลาการทำข้อมูลสำรองใหม่",
sortable: true,
// field: (v) => date2Thai(v, false, true),
field: "date",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "startAt",
align: "left",
label: "วันที่เริ่มการสำรองข้อมูล",
sortable: true,
field: (v) => date2Thai(v, false, true),
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "status",
align: "center",
label: "สถานะ",
sortable: true,
field: "status",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
]);
const columns = computed(() => {
return baseColumns.value;
});
/**
* function assignDataformDataschedule() iรบคาเข formDataschedule
*
*/
function assignDataformDataschedule(data: Schedule) {
typeTime.value = data.time !== "" ? "set" : "start";
idEditSchedule.value = data.id;
prevFormDataschedule.value = {
timeStartEvery: data.timeStartEvery,
type: data.type,
date: [],
name: data.name,
time: data.time,
schedule: data.schedule,
startAt: data.startAt,
};
const tempValue = data.date.split(" ");
tempValue.forEach((element) => {
prevFormDataschedule.value.date.push(element);
});
formDataschedule.value = { ...prevFormDataschedule.value };
tab.value = data.type;
}
/**
* function submit() เเปลงคาใหเป แบบ cron อนสงไปย backend
*
*/
function convertFormToCron() {
let allValues = formDataschedule.value.date.join(" ").split(" ");
let uniqueValues = [...new Set(allValues)];
let result = uniqueValues.join(",");
let [hour, minute] = formDataschedule.value.time.split(":");
let time = `${minute} ${hour}`;
if (formDataschedule.value.type === "daily") {
if (typeTime.value.includes("set")) {
formDataschedule.value.schedule = `0 ${time} * * *`;
} else {
formDataschedule.value.schedule = `0 0 */${formDataschedule.value.timeStartEvery} * * *`;
}
}
if (formDataschedule.value.type === "weekly") {
formDataschedule.value.schedule = `0 ${time} * * ${result}`;
}
if (formDataschedule.value.type === "monthly") {
formDataschedule.value.schedule = `0 ${time} ${result} * *`;
}
}
/**
* function submit() งเวลา backup
*
*/
async function onSubmit() {
showLoader();
if (typeOnSubmit.value === "create") {
await createSchedule(formDataschedule.value);
}
if (typeOnSubmit.value === "edit") {
await editSchedule(idEditSchedule.value, formDataschedule.value);
}
getSchedule();
hideLoader();
}
/**
* function ลบรายการขอมลสำรอง
* @param id รายการสำรอง
*/
function onDelete(id: string) {
dialogRemove($q, async () => {
showLoader();
await deleteSchedule(id);
await getSchedule();
});
}
/**
* function นคาขอมลสำรอง
* @param id อมลสำรอง
*/
function onRestore(id: string) {
dialogConfirm(
$q,
async () => {
await restore(id);
},
"ยืนยันการคืนค่าข้อมูลสำรอง",
"ต้องการยืนยันการคืนค่าข้อมูลสำรองนี้ใช่หรือไม่?"
);
}
const typeOnSubmit = ref<"edit" | "create">("create");
const dateStart = ref<string>("");
const typeTime = ref<string>("set");
const timeStartEvery = ref<number>();
const tab = ref<string>("daily");
const tabItems = ref<ItemsTeb[]>([
{ name: "daily", label: "ทุกวัน", icon: "" },
{ name: "weekly", label: "ทุกสัปดาห์", icon: "" },
{ name: "monthly", label: "ทุกเดือน", icon: "" },
]);
const dayColors: { [key: string]: string } = {
mon: "#FFC700", // Yellow
tue: "#FF69B4", // Pink
wed: "#008000", // Green
thu: "#FFA500", // Orange
fri: "#0000FF", // Blue
sat: "#800080", // Purple
sun: "#FF0000", // Red
};
const dayNames: { [key: string]: string } = {
mon: "จ", // Yellow
tue: "อ", // Pink
wed: "พ", // Green
thu: "พฤ", // Orange
fri: "ศ", // Blue
sat: "ส", // Purple
sun: "อา", // Red
};
const typeSchedule: { [key: string]: string } = {
daily: "รายวัน",
weekly: "รายสัปดาห์",
monthly: "รายเดือน",
};
onMounted(async () => {
getSchedule();
});
watch(tab, () => {
if (tab.value === formDataschedule.value.type) {
formDataschedule.value = { ...prevFormDataschedule.value };
}
if (tab.value !== formDataschedule.value.type) {
formDataschedule.value.date = [];
formDataschedule.value.time = "";
formDataschedule.value.timeStartEvery = "";
typeTime.value = "set";
}
});
</script>
<template>
<q-card-section>
<div class="items-center col-12 row q-gutter-x-sm q-mb-sm">
<q-btn
color="primary"
icon="add"
label="ตั้งเวลาสำรองข้อมูล"
@click="
() => {
typeOnSubmit = 'create';
openDialog = true;
}
"
>
<q-tooltip>งเวลาสำรองขอม </q-tooltip>
</q-btn>
<q-space />
<q-input
borderless
dense
debounce="300"
outlined
v-model="filter"
placeholder="ค้นหา"
>
<template v-slot:append>
<q-icon name="search" />
</template>
</q-input>
<q-select
v-model="visibleColumns"
multiple
outlined
dense
options-dense
:display-value="$q.lang.table.columns"
emit-value
map-options
:options="columns"
option-value="name"
options-cover
/>
</div>
<d-table
:rows="dataSchedule"
:columns="columns"
row-key="name"
:visible-columns="visibleColumns"
:filter="filter"
>
<template v-slot:header="props">
<q-tr :props="props">
<q-th v-for="(col, i) in props.cols" :key="col.name" :props="props">
{{ col.label }}
</q-th>
<q-th></q-th>
</q-tr>
</template>
<template v-slot:body="props">
<q-tr :props="props">
<q-td v-if="visibleColumns.includes('name')">
{{ props.row.name }}
</q-td>
<q-td class="text-center" v-if="visibleColumns.includes('type')">
<q-badge
rounded
style="color: #007aff; background: #ededed"
:label="typeSchedule[props.row.type]"
/>
</q-td>
<q-td v-if="visibleColumns.includes('date')">
<div class="column">
<div class="col-6">{{ props.row.time }}</div>
<div
class="col-6 q-gutter-x-sm"
v-if="props.row.type.includes('daily')"
>
<q-badge
rounded
style="color: #fefefe; background: #242121"
:label="
props.row.timeStartEvery !== ''
? `ทุก ${props.row.timeStartEvery} ชั่วโมง`
: 'ทุกวัน'
"
/>
</div>
<div
class="col-6 q-gutter-x-sm"
v-if="props.row.type.includes('weekly')"
>
<q-badge
v-for="(t, i) in props.row.date.split(' ')"
rounded
:style="`color: #fefefe; background: ${dayColors[t]}`"
:label="dayNames[t]"
/>
</div>
<div
class="col-6 q-gutter-x-sm"
v-if="props.row.type.includes('monthly')"
>
<q-badge
v-for="(t, i) in props.row.date.split(' ')"
rounded
style="color: #fefefe; background: #242121"
:label="`ทุกวันที่ ${t}`"
/>
</div>
</div>
</q-td>
<q-td v-if="visibleColumns.includes('startAt')">
{{ date2Thai(props.row.startAt, true, false) }}
</q-td>
<q-td v-if="visibleColumns.includes('status')">
<q-toggle
size="lg"
v-model="props.row.enabled"
@click.stop="
() => {
toggleSchedule(props.row.id);
}
"
/>
</q-td>
<q-td>
<q-btn
dense
flat
round
icon="edit"
color="primary"
size="12px"
@click.petvent="
() => {
typeOnSubmit = 'edit';
assignDataformDataschedule({ ...props.row });
openDialog = true;
}
"
>
<q-tooltip>ลบขอมลสำรอง </q-tooltip>
</q-btn>
<q-btn
dense
flat
round
:disable="restoreRunTotal !== 0"
icon="delete"
color="red"
size="12px"
@click.petvent="onDelete(props.row.id)"
>
<q-tooltip>นค </q-tooltip>
</q-btn>
</q-td>
</q-tr>
</template>
</d-table>
</q-card-section>
<FormDialog
v-model:openDialog="openDialog"
:title="`${
typeOnSubmit === 'create' ? 'สร้าง' : 'แก้ไข'
}อมลสำรองใหม งตารางเวลา`"
:close="() => (openDialog = false)"
:submit="
() => {
formDataschedule.type = tab;
if (formDataschedule.startAt !== undefined) {
formDataschedule.startAt = new Date(
formDataschedule.startAt
).toISOString();
}
convertFormToCron();
onSubmit();
openDialog = false;
}
"
>
<q-card flast bordered>
<q-tabs
v-model="tab"
dense
align="left"
inline-label
class="bg-white text-grey"
active-color="primary"
indicator-color="primary"
>
<div v-for="item in tabItems">
<q-tab :name="item.name" :label="item.label" />
</div>
</q-tabs>
<q-separator />
<div class="q-pa-sm">
<formSchedule
v-model:name="formDataschedule.name"
v-model:type-time="typeTime"
v-model:time="formDataschedule.time"
v-model:time-start-every="formDataschedule.timeStartEvery"
v-model:start-at="formDataschedule.startAt"
v-model:date="formDataschedule.date"
v-model:tab="tab"
/>
</div>
</q-card>
</FormDialog>
</template>
<style scoped></style>

View file

@ -146,9 +146,12 @@ function onRestore(name: string) {
}
onMounted(async () => {
fetchListBackup();
backupRunningList();
restoreRunningList();
const res = await fetchListBackup();
if (!!res) {
await backupRunningList();
await restoreRunningList();
}
});
</script>
@ -156,7 +159,6 @@ onMounted(async () => {
<q-card-section>
<div class="items-center col-12 row q-gutter-x-sm q-mb-sm">
<q-btn
v-if="tab === 'backup'"
color="primary"
icon="add"
label="สร้างข้อมูลสำรอง"

View file

@ -0,0 +1,46 @@
<script setup lang="ts">
import DialogHeader from "@/components/DialogHeader.vue";
const openDialog = defineModel<boolean>("openDialog", {
required: true,
default: false,
});
defineProps<{
title: string;
submit?: (...args: unknown[]) => void;
close?: (...args: unknown[]) => void;
}>();
</script>
<template>
<q-dialog v-model="openDialog" class="dialog-content-top">
<q-card style="width: 80%">
<q-form
greedy
@submit.prevent
@validation-success="submit"
class="full-height"
>
<!-- header -->
<DialogHeader :tittle="title" :close="close" />
<q-separator />
<q-card-section> <slot /> </q-card-section>
<q-separator />
<q-card-actions align="right">
<q-btn label="บันทึก" color="secondary" type="submit"
><q-tooltip>นทกขอม</q-tooltip></q-btn
>
</q-card-actions>
</q-form>
</q-card>
</q-dialog>
</template>
<style lang="scss">
.form-header {
border-bottom: 1px solid $grey-2;
}
</style>

View file

@ -0,0 +1,263 @@
<script setup lang="ts">
import { ref, watch } from "vue";
const name = defineModel<string>("name");
const typeTime = defineModel<string>("typeTime", { default: "set" });
const time = defineModel<string>("time");
const timeStartEvery = defineModel<string>("timeStartEvery");
const startAt = defineModel<string>("startAt");
const selectDate = defineModel<string[]>("date", { default: [] });
const tab = defineModel<string>("tab");
const timeStartEveryOptions: { value: string }[] = Array.from(
{ length: 24 },
(_, i) => ({ value: (i + 1).toString() })
);
watch(typeTime, () => {
time.value = "";
timeStartEvery.value = "";
});
</script>
<template>
<div class="row q-col-gutter-md items-center text-grey-8">
<div class="col-12">
อของขอมลสำรองใหม
<q-input
outlined
clearable
hide-bottom-space
dense
v-model="name"
label="ชื่อ Backup"
:rules="[(val:string) => val.length <= 30 || 'ชื่อต้องไม่เกิน 16 ตัวอักษร' , (val:string) => /^[A-Za-z0-9\-]+$/.test(val) || 'ชื่อต้องเป็นภาษาอังกฤษ พิมพ์ใหญ่หรือเล็ก และตัวเลขเท่านั้น']"
/>
</div>
<div class="col-12 column" v-if="tab === 'daily'">
ทำซ
<div class="col-6 row items-center">
<div class="col-3">
<q-radio v-model="typeTime" val="set" label="กำหนดเวลา" />
</div>
<div class="col-3">
<q-input
v-model="time"
outlined
clearable
hide-bottom-space
dense
type="time"
/>
</div>
</div>
<div class="col-6 row items-center q-pt-sm">
<div class="col-3">
<q-radio v-model="typeTime" val="start" label="เริ่มทุก" />
</div>
<div class="col-3">
<q-select
label="เลือก"
v-model="timeStartEvery"
:options="timeStartEveryOptions"
outlined
emit-value
dense
emit-option
option-label="value"
option-value="value"
map-options
suffix="ชั่วโมง"
/>
</div>
</div>
</div>
<div class="col-12 column" v-if="tab === 'weekly'">
<div class="col-12 row">
<div>
ทำซ
<q-input
v-model="time"
outlined
clearable
hide-bottom-space
dense
type="time"
/>
</div>
</div>
<div class="col-12 q-gutter-sm row q-pt-sm">
<q-card
:class="{
'bg-primary text-white': selectDate.includes(v.value),
}"
style="
user-select: none;
transition: 100ms background-color ease-in-out;
"
v-for="(v, i) in [
{
value: 'mon',
name: 'จันทร์',
},
{
value: 'tue',
name: 'อังคาร',
},
{
value: 'wed',
name: 'พุธ',
},
{
value: 'thu',
name: 'พฤหัสบดี',
},
{
value: 'fri',
name: 'ศุกร์',
},
{
value: 'sun',
name: 'อาทิตย์',
},
{
value: 'sat',
name: 'เสาร์',
},
]"
flast
bordered
class="q-pa-sm col text-center cursor-pointer"
@click="
() => {
if (!selectDate.includes(v.value)) selectDate.push(v.value);
else selectDate.splice(selectDate.indexOf(v.value), 1);
}
"
>{{ v.name }}</q-card
>
</div>
</div>
<div class="col-12 column" v-if="tab === 'monthly'">
<div class="col-12 row">
<div>
ทำซ
<q-input
v-model="time"
outlined
clearable
hide-bottom-space
dense
type="time"
/>
</div>
</div>
<div class="col-12 q-pt-sm">
<div class="row q-col-gutter-sm">
<div
class="col-2"
v-for="(v, i) in Array.from({ length: 31 }, (_, i) => ({
value: i + 1,
}))"
>
<q-card
:class="{
'bg-primary text-white': selectDate.includes(
v.value.toString()
),
}"
style="
user-select: none;
transition: 100ms background-color ease-in-out;
"
flat
bordered
class="text-center q-px-md q-py-sm cursor-pointer"
@click="
() => {
if (!selectDate.includes(v.value.toString()))
selectDate.push(v.value.toString());
else
selectDate.splice(
selectDate.indexOf(v.value.toString()),
1
);
}
"
>{{ v.value }}</q-card
>
</div>
</div>
</div>
</div>
<div class="col-6 column">
นท - เวลาเรมการสำรองขอม
<q-input outlined clearable hide-bottom-space dense v-model="startAt">
<template v-slot:prepend>
<q-icon name="event" class="cursor-pointer">
<q-popup-proxy
cover
transition-show="scale"
transition-hide="scale"
>
<q-date v-model="startAt" mask="YYYY-MM-DD HH:mm">
<div class="row items-center justify-end">
<q-btn v-close-popup label="Close" color="primary" flat />
</div>
</q-date>
</q-popup-proxy>
</q-icon>
</template>
<template v-slot:append>
<q-icon name="access_time" class="cursor-pointer">
<q-popup-proxy
cover
transition-show="scale"
transition-hide="scale"
>
<q-time v-model="startAt" mask="YYYY-MM-DD HH:mm" format24h>
<div class="row items-center justify-end">
<q-btn v-close-popup label="Close" color="primary" flat />
</div>
</q-time>
</q-popup-proxy>
</q-icon>
</template>
</q-input>
<!--
<q-input v-model="startAt" outlined clearable hide-bottom-space dense>
<template v-slot:prepend>
<q-btn size="8px" icon="event" round>
<q-popup-proxy
cover
transition-show="scale"
transition-hide="scale"
>
<q-date
v-model="startAt"
minimal
navigation-min-year-month="2024/09"
navigation-max-year-month="2024/09"
>
<div class="row items-center justify-end q-gutter-sm">
<q-btn label="Cancel" color="primary" flat v-close-popup />
<q-btn label="OK" color="primary" flat v-close-popup />
</div>
</q-date>
</q-popup-proxy>
</q-btn>
</template>
</q-input> -->
</div>
</div>
</template>
<style scoped lang="scss"></style>

View file

@ -0,0 +1,14 @@
interface ScheduleCreate {
name: string;
time: string;
timeStartEvery: string;
timezone?: string;
type: string;
date: string[];
schedule: string;
startAt?: string;
enabled?: boolean;
}
export type { ScheduleCreate };

View file

@ -32,4 +32,16 @@ interface BackUpRunning {
tag: string;
}
export type { DataBackup, BackUpRunning };
interface Schedule {
type: string;
date: string;
time: string;
schedule: string;
name: string;
id: string;
timeStartEvery: string;
startAt?: string;
enabled: boolean;
}
export type { DataBackup, BackUpRunning, Schedule };

View file

@ -1,14 +1,17 @@
import { defineStore } from "pinia";
import http from "@/plugins/http";
import config from "@/app.config";
import moment from "moment";
import { useCounterMixin } from "@/stores/mixin";
import type {
DataBackup,
BackUpRunning,
Schedule,
} from "@/modules/04_system/interface/response/Main";
import type { ScheduleCreate } from "@/modules/04_system/interface/request/Main";
import { ref } from "vue";
const mixin = useCounterMixin();
@ -23,6 +26,7 @@ const {
export const useDataStore = defineStore("systemStore", () => {
const dataBackUp = ref<DataBackup[]>([]);
const dataSchedule = ref<Schedule[]>([]);
const prevBackupRunTotal = ref<number>(-1);
const backupRunTotal = ref<number>(0);
@ -33,21 +37,24 @@ export const useDataStore = defineStore("systemStore", () => {
async function fetchListBackup() {
showLoader();
await http
.get(config.API.backup)
.then((res) => {
dataBackUp.value = res.data;
dataBackUp.value = dataBackUp.value.map((item) => {
return {
...item,
status: "สำเร็จ",
};
});
})
.finally(() => {
hideLoader();
const res = await http.get(config.API.backup);
hideLoader();
if (!res) return false;
if (res.status === 200) {
dataBackUp.value = await res.data;
dataBackUp.value = dataBackUp.value.map((item) => {
return {
...item,
status: "สำเร็จ",
};
});
return res.status;
}
}
async function createBackUp() {
@ -178,11 +185,153 @@ export const useDataStore = defineStore("systemStore", () => {
return sizeNumber.toFixed(2) + " " + units[i];
}
function convertCronToForm(schedule: string, typeReturn: string): string {
let allValues = schedule.split(" ");
if (typeReturn === "typeOfSchedule") {
if (
allValues[3].includes("*") &&
allValues[4].includes("*") &&
allValues[5].includes("*")
) {
return `daily`;
}
if (
allValues[3].includes("*") &&
allValues[4].includes("*") &&
!allValues[5].includes("*")
) {
return `weekly`;
}
if (
!allValues[3].includes("*") &&
allValues[4].includes("*") &&
allValues[5].includes("*")
) {
return `monthly`;
}
}
if (typeReturn === "time") {
if (allValues[2].includes("/")) {
console.log(allValues[2]);
return "";
} else {
return `${allValues[2]}:${allValues[1]}`;
}
}
if (typeReturn === "timeStartEvery") {
return allValues[2].split("/")[1];
}
if (typeReturn === "date") {
if (!allValues[3].includes("*")) {
const tempValue = allValues[3].split(",").join(" ");
return `${tempValue}`;
}
if (!allValues[5].includes("*")) {
const tempValue = allValues[5].split(",").join(" ");
return `${tempValue}`;
}
}
return "";
}
async function getSchedule() {
showLoader();
await http
.get<Schedule[]>(config.API.backup + "/schedule")
.then((res) => {
dataSchedule.value = res.data.map((item) => {
return {
id: item.id,
name: item.name,
schedule: item.schedule,
type: convertCronToForm(item.schedule, "typeOfSchedule") || "",
time: convertCronToForm(item.schedule, "time") || "",
date: convertCronToForm(item.schedule, "date") || "",
timeStartEvery:
convertCronToForm(item.schedule, "timeStartEvery") || "",
startAt: moment(item.startAt)
.utcOffset(7)
.format("YYYY-MM-DD HH:mm"),
enabled: item.enabled,
};
});
})
.finally(() => {
hideLoader();
});
}
async function createSchedule(data: ScheduleCreate) {
showLoader();
await http
.post(config.API.backup + "/schedule", {
name: data.name,
schedule: data.schedule,
startAt: data.startAt !== undefined ? data.startAt : undefined,
})
.then(async (res) => {
return res.data;
})
.finally(() => {
hideLoader();
});
}
async function editSchedule(id: string, data: ScheduleCreate) {
showLoader();
await http
.put(config.API.backup + "/schedule/" + id, {
startAt: data.startAt !== undefined ? data.startAt : undefined,
enabled: data.enabled,
schedule: data.schedule,
name: data.name,
})
.then(async (res) => {
return res.data;
})
.finally(() => {
hideLoader();
});
}
async function toggleSchedule(id: string) {
showLoader();
await http
.post(config.API.backup + "/schedule/" + id + "/toggle")
.then(async (res) => {
return res.data;
})
.finally(() => {
hideLoader();
});
}
async function deleteSchedule(id: string) {
showLoader();
await http
.delete(config.API.backup + "/schedule/" + id)
.then(async (res) => {
await fetchListBackup();
})
.finally(() => {
hideLoader();
});
}
return {
dataBackUp,
backupRunTotal,
restoreRunTotal,
dataSchedule,
fetchListBackup,
createBackUp,
restore,
@ -192,5 +341,12 @@ export const useDataStore = defineStore("systemStore", () => {
restoreRunningList,
getSize,
getSchedule,
createSchedule,
editSchedule,
deleteSchedule,
toggleSchedule,
};
});

View file

@ -10,6 +10,7 @@ import type { ItemsTeb } from "@/modules/04_system/interface/index/Main";
* import components
*/
import Card from "@/modules/04_system/components/cardBackupRestore.vue";
import CardAutoBackup from "@/modules/04_system/components/cardAutoBackup.vue";
/**
* วแปร
@ -17,6 +18,7 @@ import Card from "@/modules/04_system/components/cardBackupRestore.vue";
const tab = ref<string>("backup");
const tabItems = ref<ItemsTeb[]>([
{ name: "backup", label: "Backup & Restore", icon: "mdi-database" },
{ name: "autoBackUp", label: "Schedule ", icon: "mdi-clock-outline" },
]);
</script>
@ -48,11 +50,11 @@ const tabItems = ref<ItemsTeb[]>([
<Card :tab="tab" />
</q-tab-panel>
<q-tab-panel name="restore">
<q-tab-panel name="autoBackUp">
<q-card-section class="q-pa-none">
<div class="text-h6">นค</div>
</q-card-section>
<Card :tab="tab" />
<CardAutoBackup :tab="tab" />
</q-tab-panel>
</q-tab-panels>
</q-card>

View file

@ -174,3 +174,6 @@ h3.resigtry-tab-title
overflow: hidden
text-overflow: ellipsis
width: 200px
.dialog-content-top .q-dialog__inner
align-items: start