345 lines
9.1 KiB
Vue
345 lines
9.1 KiB
Vue
<template style="max-width: 100vw">
|
|
<div>
|
|
<a-card class="panel-content">
|
|
<a-form
|
|
:class="page.status.Active ? 'disabled-div' : ''"
|
|
:label-col="labelCol"
|
|
:wrapper-col="wrapperCol"
|
|
>
|
|
<a-form-item
|
|
:label="t(`components.admin.domains.mails_perm_deletion.filter`)"
|
|
>
|
|
<div style="text-align: center">
|
|
<a-flex gap="middle" vertical>
|
|
<a-row>
|
|
<a-col flex="auto">
|
|
<a-radio-group v-model:value="page.status.Condition.Op">
|
|
<a-radio-button value="and">{{
|
|
t("components.common.rules.edit_conditions_all")
|
|
}}</a-radio-button>
|
|
<a-radio-button value="or">{{
|
|
t("components.common.rules.edit_conditions_any")
|
|
}}</a-radio-button>
|
|
</a-radio-group>
|
|
</a-col>
|
|
<a-col flex="100px"> </a-col>
|
|
</a-row>
|
|
<template v-if="page.renderConditions">
|
|
<div v-for="(condition, i) in page.status.Condition.Conditions">
|
|
<a-row>
|
|
<a-col flex="auto">
|
|
<Conditions
|
|
:value="condition"
|
|
:update="(newVal: string[]) => updateCondition(i, newVal)"
|
|
:conditions="conditionsListForMailDeletion"
|
|
>
|
|
<template #condition-value="valueProps">
|
|
<ConditionValue
|
|
:change="valueProps.change"
|
|
:value="valueProps.value"
|
|
:type="valueProps.type"
|
|
>
|
|
</ConditionValue>
|
|
</template>
|
|
</Conditions>
|
|
</a-col>
|
|
<a-col flex="100px">
|
|
<a-button
|
|
:disabled="i === 0"
|
|
danger
|
|
@click="deleteCondition(i)"
|
|
>
|
|
{{ t("components.common.rules.delete") }}
|
|
</a-button>
|
|
</a-col>
|
|
</a-row>
|
|
</div>
|
|
</template>
|
|
<a-row>
|
|
<a-col flex="auto">
|
|
<a-button
|
|
style="width: fit-content; margin: auto"
|
|
@click="addCondition"
|
|
>
|
|
<PlusOutlined> </PlusOutlined>
|
|
{{ t("components.common.rules.add_condition") }}
|
|
</a-button>
|
|
</a-col>
|
|
<a-col flex="100px"> </a-col>
|
|
</a-row>
|
|
</a-flex>
|
|
</div>
|
|
</a-form-item>
|
|
</a-form>
|
|
<a-divider></a-divider>
|
|
<div>
|
|
<a-space style="width: 100%" direction="vertical">
|
|
<a-alert
|
|
v-if="page.status.Error"
|
|
type="error"
|
|
showIcon
|
|
:message="page.status.Error"
|
|
/>
|
|
<a-alert
|
|
v-if="page.status.Percent === 100 && !page.status.OnlyFind"
|
|
type="success"
|
|
showIcon
|
|
:message="t(`components.admin.domains.mails_perm_deletion.success`)"
|
|
/>
|
|
<a-progress
|
|
v-if="
|
|
(page.status.Count || page.status.Percent) &&
|
|
!page.status.OnlyFind
|
|
"
|
|
:percent="page.status.Percent"
|
|
/>
|
|
|
|
<a-row>
|
|
<a-col flex="2"> </a-col>
|
|
<a-col>
|
|
<a-space>
|
|
<a-button
|
|
:type="page.status.Count === 0 ? `primary` : undefined"
|
|
:loading="page.status.OnlyFind && page.status.Active"
|
|
:disabled="page.status.Active"
|
|
@click="start(true)"
|
|
>
|
|
{{ t("components.admin.domains.mails_perm_deletion.find") }}
|
|
</a-button>
|
|
<a-button
|
|
danger
|
|
:type="`primary`"
|
|
:disabled="page.status.Active || !page.status.Count"
|
|
:loading="!page.status.OnlyFind && page.status.Active"
|
|
@click="confirmDelete"
|
|
>
|
|
{{ t("components.admin.domains.mails_perm_deletion.delete") }}
|
|
{{ page.status.Count }}
|
|
</a-button>
|
|
</a-space>
|
|
</a-col>
|
|
</a-row>
|
|
</a-space>
|
|
</div>
|
|
</a-card>
|
|
</div>
|
|
</template>
|
|
<script setup lang="ts">
|
|
import { notifyError, notifySuccess } from "@/composables/alert";
|
|
import { apiFetch } from "@/composables/apiFetch";
|
|
|
|
import { Modal } from "ant-design-vue";
|
|
import { createVNode, onMounted, onUnmounted, reactive } from "vue";
|
|
import { saveAndRestart } from "@/composables/restart";
|
|
import { message } from "ant-design-vue";
|
|
import Conditions from "@/components/common/rules/Conditions.vue";
|
|
import ConditionValue from "@/components/common/rules/incoming/Conditions.vue";
|
|
import { conditionsListForMailDeletion } from "@/components/common/rules/incoming/Conditions.vue";
|
|
|
|
import { useI18n } from "vue-i18n";
|
|
import router from "@/router";
|
|
import {
|
|
DomainPlaceholder,
|
|
RouteAdminDomainsDomainMailStorageSettings,
|
|
} from "@/router/consts";
|
|
import {
|
|
ArrowLeftOutlined,
|
|
DeleteOutlined,
|
|
DownOutlined,
|
|
ExclamationCircleOutlined,
|
|
HomeOutlined,
|
|
PlusOutlined,
|
|
UpOutlined,
|
|
} from "@ant-design/icons-vue";
|
|
import { useRoute } from "vue-router";
|
|
import type { Condition } from "@/components/common/rules/Conditions.vue";
|
|
import { nextTick } from "vue";
|
|
import { getStatusClassNames } from "ant-design-vue/es/_util/statusUtils";
|
|
|
|
const route = useRoute();
|
|
|
|
const { t } = useI18n();
|
|
|
|
const labelCol = { span: 3, style: { "text-align": "left" } };
|
|
const wrapperCol = { span: 21, style: { "text-align": "center" } };
|
|
|
|
interface ConditionStruct {
|
|
Op: string;
|
|
Conditions: string[][];
|
|
}
|
|
|
|
interface DeleteStatus {
|
|
Condition: ConditionStruct;
|
|
OnlyFind: boolean;
|
|
Active: boolean;
|
|
Count: number;
|
|
Percent: number;
|
|
Error: string;
|
|
}
|
|
|
|
const page = reactive<{
|
|
// @ts-ignore
|
|
timeout: NodeJS.Timeout | undefined;
|
|
interval: number | undefined;
|
|
domain: string;
|
|
loading: boolean;
|
|
valid: boolean;
|
|
renderConditions: boolean;
|
|
|
|
status: DeleteStatus;
|
|
}>({
|
|
interval: 1000,
|
|
timeout: undefined,
|
|
domain: "",
|
|
loading: false,
|
|
|
|
renderConditions: true,
|
|
valid: true,
|
|
|
|
status: {
|
|
Condition: {
|
|
Op: "and",
|
|
Conditions: [[...conditionsListForMailDeletion[0].Args]],
|
|
},
|
|
OnlyFind: true,
|
|
Active: false,
|
|
Count: 0,
|
|
Percent: 0,
|
|
Error: "",
|
|
},
|
|
});
|
|
|
|
onMounted(() => {
|
|
page.domain = route.params.domain as string;
|
|
get();
|
|
});
|
|
|
|
onUnmounted(() => {
|
|
page.interval = undefined;
|
|
clearTimeout(page.timeout);
|
|
});
|
|
|
|
async function get() {
|
|
clearTimeout(page.timeout);
|
|
|
|
page.loading = true;
|
|
|
|
const res = await apiFetch(
|
|
`/admin/domains/${page.domain}/mails_perm_deletion`
|
|
);
|
|
|
|
if (res.error) {
|
|
notifyError(res.error);
|
|
return;
|
|
}
|
|
page.loading = false;
|
|
|
|
page.status = res.data as DeleteStatus;
|
|
page.renderConditions = false;
|
|
validate();
|
|
nextTick(() => {
|
|
page.renderConditions = true;
|
|
});
|
|
|
|
if (page.status.Active && page.interval) {
|
|
page.timeout = setTimeout(get, page.interval);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
async function start(onlyFind: boolean) {
|
|
page.loading = true;
|
|
|
|
page.status.OnlyFind = onlyFind;
|
|
if (page.status.OnlyFind) {
|
|
page.status.Count = 0;
|
|
}
|
|
page.status.Active = true;
|
|
page.status.Error = "";
|
|
page.status.Percent = 0;
|
|
|
|
const res = await apiFetch(
|
|
`/admin/domains/${page.domain}/mails_perm_deletion`,
|
|
{
|
|
method: "POST",
|
|
body: page.status,
|
|
}
|
|
);
|
|
|
|
page.loading = false;
|
|
|
|
if (res.error) {
|
|
notifyError(res.error);
|
|
return;
|
|
}
|
|
|
|
return get();
|
|
}
|
|
|
|
function updateCondition(i: number, newVal: string[]) {
|
|
page.status.Condition.Conditions[i] = newVal;
|
|
validate();
|
|
}
|
|
|
|
function deleteCondition(i: number) {
|
|
page.status.Condition.Conditions.splice(i, 1);
|
|
page.renderConditions = false;
|
|
validate();
|
|
nextTick(() => {
|
|
page.renderConditions = true;
|
|
});
|
|
}
|
|
|
|
function validate() {
|
|
let ok = true;
|
|
|
|
page.status.Condition.Conditions.forEach((args) => {
|
|
let cond = conditionsListForMailDeletion.find(
|
|
(a: Condition) => a.Value === args[0]
|
|
) as Condition;
|
|
if (cond.ValIdx != -1 && args[cond.ValIdx] === "") {
|
|
ok = false;
|
|
}
|
|
});
|
|
|
|
page.valid = ok;
|
|
}
|
|
|
|
function addCondition() {
|
|
page.status.Condition.Conditions.push(conditionsListForMailDeletion[0].Args);
|
|
validate();
|
|
}
|
|
|
|
function confirmDelete() {
|
|
Modal.confirm({
|
|
title:
|
|
t("components.admin.domains.mails_perm_deletion.delete") +
|
|
page.status.Count,
|
|
icon: createVNode(ExclamationCircleOutlined),
|
|
content: t("components.admin.domains.mails_perm_deletion.delete_text"),
|
|
okText: t("components.admin.domains.mails_perm_deletion.ok"),
|
|
okType: "danger",
|
|
cancelText: t("components.admin.domains.mails_perm_deletion.cancel"),
|
|
async onOk() {
|
|
start(false);
|
|
},
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.panel-content {
|
|
min-width: 800px;
|
|
max-width: 60%;
|
|
margin: auto;
|
|
}
|
|
|
|
.save-button {
|
|
width: 30%;
|
|
min-width: 150px;
|
|
display: block;
|
|
margin: auto;
|
|
}
|
|
</style>
|