changes
This commit is contained in:
@@ -166,20 +166,20 @@ const menu = [
|
|||||||
if ($store.rights.length > 0) {
|
if ($store.rights.length > 0) {
|
||||||
menu = menu.filter((v) => $findIndex($store.rights, { setting: v.id }) >= 0);
|
menu = menu.filter((v) => $findIndex($store.rights, { setting: v.id }) >= 0);
|
||||||
}
|
}
|
||||||
if (menu.length === 0) {
|
// if (menu.length === 0) {
|
||||||
$snackbar(
|
// $snackbar(
|
||||||
$store.lang === 'vi'
|
// $store.lang === 'vi'
|
||||||
? 'Bạn không có quyền truy cập'
|
// ? 'Bạn không có quyền truy cập'
|
||||||
: 'You do not have permission to access.',
|
// : 'You do not have permission to access.',
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
menu.map((v) => {
|
// menu.map((v) => {
|
||||||
let arr = $filter($store.common, { category: 'submenu', classify: v.code });
|
// let arr = $filter($store.common, { category: 'submenu', classify: v.code });
|
||||||
if ($store.rights.length > 0) {
|
// if ($store.rights.length > 0) {
|
||||||
arr = arr.filter((x) => $findIndex($store.rights, { setting: x.id }) >= 0);
|
// arr = arr.filter((x) => $findIndex($store.rights, { setting: x.id }) >= 0);
|
||||||
}
|
// }
|
||||||
v.submenu = arr.length > 0 ? arr : null;
|
// v.submenu = arr.length > 0 ? arr : null;
|
||||||
});
|
// });
|
||||||
const leftmenu = $filter(menu, { category: 'topmenu', classify: 'left' });
|
const leftmenu = $filter(menu, { category: 'topmenu', classify: 'left' });
|
||||||
let currentTab = ref(leftmenu.length > 0 ? leftmenu[0] : undefined);
|
let currentTab = ref(leftmenu.length > 0 ? leftmenu[0] : undefined);
|
||||||
const subTab = ref();
|
const subTab = ref();
|
||||||
|
|||||||
@@ -2,24 +2,22 @@
|
|||||||
import useSendEmail from '@/components/debt/useSendEmail';
|
import useSendEmail from '@/components/debt/useSendEmail';
|
||||||
import { isEqual } from 'es-toolkit';
|
import { isEqual } from 'es-toolkit';
|
||||||
|
|
||||||
const {
|
const { $dayjs, $getdata, $store } = useNuxtApp();
|
||||||
$dayjs,
|
|
||||||
$getdata,
|
|
||||||
$store,
|
|
||||||
} = useNuxtApp();
|
|
||||||
|
|
||||||
const payables = ref(null);
|
const payables = ref(null);
|
||||||
const defaultFilter = {
|
const defaultFilter = {
|
||||||
status: 1,
|
status: 1,
|
||||||
to_date__gte: $dayjs().format('YYYY-MM-DD'),
|
to_date__gte: $dayjs().format('YYYY-MM-DD'),
|
||||||
to_date__lte: undefined,
|
to_date__lte: undefined,
|
||||||
}
|
};
|
||||||
const filter = ref(defaultFilter);
|
const filter = ref(defaultFilter);
|
||||||
const activeDateFilter = ref(null);
|
const activeDateFilter = ref(null);
|
||||||
const key = ref(0);
|
const key = ref(0);
|
||||||
|
|
||||||
function setDateFilter(detail) {
|
function setDateFilter(detail) {
|
||||||
activeDateFilter.value = isEqual(activeDateFilter.value, detail) ? null : detail;
|
activeDateFilter.value = isEqual(activeDateFilter.value, detail)
|
||||||
|
? null
|
||||||
|
: detail;
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetDateFilter() {
|
function resetDateFilter() {
|
||||||
@@ -28,23 +26,27 @@ function resetDateFilter() {
|
|||||||
|
|
||||||
const paymentSchedules = ref([]);
|
const paymentSchedules = ref([]);
|
||||||
|
|
||||||
onMounted(async () => {
|
// onMounted(async () => {
|
||||||
const payablesData = await $getdata('bizsetting', undefined, { filter: { classify: 'duepayables' }, sort: 'index' });
|
// const payablesData = await $getdata('bizsetting', undefined, { filter: { classify: 'duepayables' }, sort: 'index' });
|
||||||
payables.value = payablesData;
|
// payables.value = payablesData;
|
||||||
});
|
// });
|
||||||
|
|
||||||
watch(activeDateFilter, (val) => {
|
watch(
|
||||||
if (!val) {
|
activeDateFilter,
|
||||||
filter.value = defaultFilter;
|
(val) => {
|
||||||
} else {
|
if (!val) {
|
||||||
const cutoffDate = $dayjs().add(val.time, 'day').format('YYYY-MM-DD');
|
filter.value = defaultFilter;
|
||||||
const filterField = `to_date__${val.lookup}`;
|
} else {
|
||||||
filter.value = {
|
const cutoffDate = $dayjs().add(val.time, 'day').format('YYYY-MM-DD');
|
||||||
...defaultFilter,
|
const filterField = `to_date__${val.lookup}`;
|
||||||
[filterField]: cutoffDate,
|
filter.value = {
|
||||||
|
...defaultFilter,
|
||||||
|
[filterField]: cutoffDate,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}, { deep: true })
|
{ deep: true },
|
||||||
|
);
|
||||||
|
|
||||||
const showmodal = ref(null);
|
const showmodal = ref(null);
|
||||||
|
|
||||||
@@ -56,40 +58,53 @@ function openConfirmModal() {
|
|||||||
height: '100px',
|
height: '100px',
|
||||||
vbind: {
|
vbind: {
|
||||||
content: `Bạn có đồng ý gửi ${$store.selectedPaymentSchedulesForEmailInDue.length} thông báo đến hạn không?`,
|
content: `Bạn có đồng ý gửi ${$store.selectedPaymentSchedulesForEmailInDue.length} thông báo đến hạn không?`,
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
watch(filter, () => {
|
watch(
|
||||||
key.value += 1;
|
filter,
|
||||||
}, { deep: true })
|
() => {
|
||||||
|
key.value += 1;
|
||||||
|
},
|
||||||
|
{ deep: true },
|
||||||
|
);
|
||||||
|
|
||||||
watch(key, () => {
|
watch(key, () => {
|
||||||
// reset when DataView re-renders because of filter
|
// reset when DataView re-renders because of filter
|
||||||
$store.commit('selectedPaymentSchedulesForEmailInDue', [])
|
$store.commit('selectedPaymentSchedulesForEmailInDue', []);
|
||||||
})
|
});
|
||||||
|
|
||||||
function toggleAll() {
|
function toggleAll() {
|
||||||
if ($store.selectedPaymentSchedulesForEmailInDue.length === 0) {
|
if ($store.selectedPaymentSchedulesForEmailInDue.length === 0) {
|
||||||
$store.commit('selectedPaymentSchedulesForEmailInDue', paymentSchedules.value.map(p => p.id))
|
$store.commit(
|
||||||
|
'selectedPaymentSchedulesForEmailInDue',
|
||||||
|
paymentSchedules.value.map((p) => p.id),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
$store.commit('selectedPaymentSchedulesForEmailInDue', [])
|
$store.commit('selectedPaymentSchedulesForEmailInDue', []);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const { contents, send, isSending } = useSendEmail(filter, 13);
|
const { contents, send, isSending } = useSendEmail(filter, 13);
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="is-flex is-justify-content-space-between is-align-content-center mb-4">
|
<div
|
||||||
|
class="is-flex is-justify-content-space-between is-align-content-center mb-4"
|
||||||
|
>
|
||||||
<div class="buttons m-0">
|
<div class="buttons m-0">
|
||||||
<p>Đến hạn:</p>
|
<p>Đến hạn:</p>
|
||||||
<button
|
<button
|
||||||
v-for="payable in payables"
|
v-for="payable in payables"
|
||||||
:key="payable.id"
|
:key="payable.id"
|
||||||
@click="setDateFilter(payable.detail)"
|
@click="setDateFilter(payable.detail)"
|
||||||
:class="['button', { 'is-primary': isEqual(activeDateFilter, payable.detail) }]"
|
:class="[
|
||||||
|
'button',
|
||||||
|
{ 'is-primary': isEqual(activeDateFilter, payable.detail) },
|
||||||
|
]"
|
||||||
>
|
>
|
||||||
{{ payable.detail.lookup === 'lte' ? '≤' : '>' }} {{ payable.detail.time }} ngày
|
{{ payable.detail.lookup === 'lte' ? '≤' : '>' }}
|
||||||
|
{{ payable.detail.time }} ngày
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="activeDateFilter"
|
v-if="activeDateFilter"
|
||||||
@click="resetDateFilter()"
|
@click="resetDateFilter()"
|
||||||
class="button is-white"
|
class="button is-white"
|
||||||
@@ -97,7 +112,10 @@ const { contents, send, isSending } = useSendEmail(filter, 13);
|
|||||||
Xoá lọc
|
Xoá lọc
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons" v-if="$store.selectedPaymentSchedulesForEmailInDue !== undefined">
|
<div
|
||||||
|
class="buttons"
|
||||||
|
v-if="$store.selectedPaymentSchedulesForEmailInDue !== undefined"
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
v-if="$store.selectedPaymentSchedulesForEmailInDue.length > 0"
|
v-if="$store.selectedPaymentSchedulesForEmailInDue.length > 0"
|
||||||
@click="openConfirmModal()"
|
@click="openConfirmModal()"
|
||||||
@@ -105,12 +123,17 @@ const { contents, send, isSending } = useSendEmail(filter, 13);
|
|||||||
>
|
>
|
||||||
Gửi {{ $store.selectedPaymentSchedulesForEmailInDue.length }} thông báo
|
Gửi {{ $store.selectedPaymentSchedulesForEmailInDue.length }} thông báo
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@click="toggleAll"
|
@click="toggleAll"
|
||||||
class="button"
|
class="button"
|
||||||
:disabled="paymentSchedules.length === 0"
|
:disabled="paymentSchedules.length === 0"
|
||||||
>
|
>
|
||||||
{{ $store.selectedPaymentSchedulesForEmailInDue.length > 0 ? 'Bỏ chọn' : 'Chọn' }} tất cả
|
{{
|
||||||
|
$store.selectedPaymentSchedulesForEmailInDue.length > 0
|
||||||
|
? 'Bỏ chọn'
|
||||||
|
: 'Chọn'
|
||||||
|
}}
|
||||||
|
tất cả
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -124,18 +147,19 @@ const { contents, send, isSending } = useSendEmail(filter, 13);
|
|||||||
params: {
|
params: {
|
||||||
filter,
|
filter,
|
||||||
sort: 'to_date',
|
sort: 'to_date',
|
||||||
values: 'id,penalty_paid,penalty_remain,penalty_amount,penalty_reduce,batch_date,amount_remain,paid_amount,remain_amount,code,status,txn_detail,txn_detail__transaction__product,txn_detail__transaction__product__trade_code,txn_detail__transaction__code,txn_detail__code,txn_detail__transaction__customer__code,txn_detail__transaction__customer__fullname,txn_detail__transaction__customer__email,txn_detail__transaction__customer__type__code,txn_detail__transaction__customer__legal_code,txn_detail__transaction__customer__contact_address,txn_detail__transaction__customer__address,txn_detail__transaction__customer__phone,txn_detail__transaction__policy__code,txn_detail__phase__name,type__name,from_date,to_date,amount,cycle,cycle_days,status__name,detail,entry',
|
values:
|
||||||
|
'id,penalty_paid,penalty_remain,penalty_amount,penalty_reduce,batch_date,amount_remain,paid_amount,remain_amount,code,status,txn_detail,txn_detail__transaction__product,txn_detail__transaction__product__trade_code,txn_detail__transaction__code,txn_detail__code,txn_detail__transaction__customer__code,txn_detail__transaction__customer__fullname,txn_detail__transaction__customer__email,txn_detail__transaction__customer__type__code,txn_detail__transaction__customer__legal_code,txn_detail__transaction__customer__contact_address,txn_detail__transaction__customer__address,txn_detail__transaction__customer__phone,txn_detail__transaction__policy__code,txn_detail__phase__name,type__name,from_date,to_date,amount,cycle,cycle_days,status__name,detail,entry',
|
||||||
},
|
},
|
||||||
onDisplayDataChange: (values) => paymentSchedules = values
|
onDisplayDataChange: (values) => (paymentSchedules = values),
|
||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
<Modal
|
<Modal
|
||||||
v-if="showmodal"
|
v-if="showmodal"
|
||||||
v-bind="showmodal"
|
v-bind="showmodal"
|
||||||
@confirm="send"
|
@confirm="send"
|
||||||
@close="showmodal = undefined"
|
@close="showmodal = undefined"
|
||||||
/>
|
/>
|
||||||
<!-- <div class="is-flex is-gap-1">
|
<!-- <div class="is-flex is-gap-1">
|
||||||
// debug
|
// debug
|
||||||
<Template1
|
<Template1
|
||||||
v-if="contents"
|
v-if="contents"
|
||||||
@@ -144,4 +168,4 @@ const { contents, send, isSending } = useSendEmail(filter, 13);
|
|||||||
previewMode
|
previewMode
|
||||||
/>
|
/>
|
||||||
</div> -->
|
</div> -->
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -2,23 +2,21 @@
|
|||||||
import useSendEmail from '@/components/debt/useSendEmail';
|
import useSendEmail from '@/components/debt/useSendEmail';
|
||||||
import { isEqual } from 'es-toolkit';
|
import { isEqual } from 'es-toolkit';
|
||||||
|
|
||||||
const {
|
const { $dayjs, $getdata, $store } = useNuxtApp();
|
||||||
$dayjs,
|
|
||||||
$getdata,
|
|
||||||
$store,
|
|
||||||
} = useNuxtApp();
|
|
||||||
|
|
||||||
const payables = ref(null);
|
const payables = ref(null);
|
||||||
const defaultFilter = {
|
const defaultFilter = {
|
||||||
status: 1,
|
status: 1,
|
||||||
to_date__lt: $dayjs().format('YYYY-MM-DD'),
|
to_date__lt: $dayjs().format('YYYY-MM-DD'),
|
||||||
}
|
};
|
||||||
const filter = ref(defaultFilter);
|
const filter = ref(defaultFilter);
|
||||||
const activeDateFilter = ref(null);
|
const activeDateFilter = ref(null);
|
||||||
const key = ref(0);
|
const key = ref(0);
|
||||||
|
|
||||||
function setDateFilter(detail) {
|
function setDateFilter(detail) {
|
||||||
activeDateFilter.value = isEqual(activeDateFilter.value, detail) ? null : detail;
|
activeDateFilter.value = isEqual(activeDateFilter.value, detail)
|
||||||
|
? null
|
||||||
|
: detail;
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetDateFilter() {
|
function resetDateFilter() {
|
||||||
@@ -26,40 +24,42 @@ function resetDateFilter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const paymentSchedule = ref([]);
|
const paymentSchedule = ref([]);
|
||||||
const paymentScheduleValues = 'id,penalty_paid,penalty_remain,penalty_amount,penalty_reduce,batch_date,amount_remain,paid_amount,remain_amount,code,status,txn_detail,txn_detail__transaction__product,txn_detail__transaction__product__trade_code,txn_detail__transaction__code,txn_detail__code,txn_detail__transaction__customer__code,txn_detail__transaction__customer__fullname,txn_detail__transaction__customer__email,txn_detail__transaction__customer__type__code,txn_detail__transaction__customer__legal_code,txn_detail__transaction__customer__contact_address,txn_detail__transaction__customer__address,txn_detail__transaction__customer__phone,txn_detail__transaction__policy__code,txn_detail__phase__name,type__name,from_date,to_date,amount,cycle,cycle_days,status__name,detail,entry';
|
const paymentScheduleValues =
|
||||||
|
'id,penalty_paid,penalty_remain,penalty_amount,penalty_reduce,batch_date,amount_remain,paid_amount,remain_amount,code,status,txn_detail,txn_detail__transaction__product,txn_detail__transaction__product__trade_code,txn_detail__transaction__code,txn_detail__code,txn_detail__transaction__customer__code,txn_detail__transaction__customer__fullname,txn_detail__transaction__customer__email,txn_detail__transaction__customer__type__code,txn_detail__transaction__customer__legal_code,txn_detail__transaction__customer__contact_address,txn_detail__transaction__customer__address,txn_detail__transaction__customer__phone,txn_detail__transaction__policy__code,txn_detail__phase__name,type__name,from_date,to_date,amount,cycle,cycle_days,status__name,detail,entry';
|
||||||
|
|
||||||
async function setPaymentSheduleData() {
|
async function setPaymentSheduleData() {
|
||||||
const paymentScheduleData = await $getdata(
|
const paymentScheduleData = await $getdata('payment_schedule', undefined, {
|
||||||
'payment_schedule',
|
filter: filter.value,
|
||||||
undefined,
|
sort: 'to_date',
|
||||||
{
|
values: paymentScheduleValues,
|
||||||
filter: filter.value,
|
});
|
||||||
sort: 'to_date',
|
|
||||||
values: paymentScheduleValues,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
paymentSchedule.value = paymentScheduleData;
|
paymentSchedule.value = paymentScheduleData;
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
// onMounted(async () => {
|
||||||
setPaymentSheduleData();
|
// setPaymentSheduleData();
|
||||||
const payablesData = await $getdata('bizsetting', undefined, { filter: { classify: 'overduepayables' }, sort: 'index' });
|
// const payablesData = await $getdata('bizsetting', undefined, { filter: { classify: 'overduepayables' }, sort: 'index' });
|
||||||
payables.value = payablesData;
|
// payables.value = payablesData;
|
||||||
});
|
// });
|
||||||
|
|
||||||
watch(activeDateFilter, (val) => {
|
watch(
|
||||||
if (!val) {
|
activeDateFilter,
|
||||||
filter.value = defaultFilter;
|
(val) => {
|
||||||
} else {
|
if (!val) {
|
||||||
const cutoffDate = $dayjs().subtract(val.time, 'day').format('YYYY-MM-DD');
|
filter.value = defaultFilter;
|
||||||
const filterField = `to_date__${val.lookup === 'lte' ? 'gt' :
|
} else {
|
||||||
'lte'}`;
|
const cutoffDate = $dayjs()
|
||||||
filter.value = {
|
.subtract(val.time, 'day')
|
||||||
...defaultFilter,
|
.format('YYYY-MM-DD');
|
||||||
[filterField]: cutoffDate,
|
const filterField = `to_date__${val.lookup === 'lte' ? 'gt' : 'lte'}`;
|
||||||
|
filter.value = {
|
||||||
|
...defaultFilter,
|
||||||
|
[filterField]: cutoffDate,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}, { deep: true })
|
{ deep: true },
|
||||||
|
);
|
||||||
|
|
||||||
const showmodal = ref(null);
|
const showmodal = ref(null);
|
||||||
|
|
||||||
@@ -71,42 +71,55 @@ function openConfirmModal() {
|
|||||||
height: '100px',
|
height: '100px',
|
||||||
vbind: {
|
vbind: {
|
||||||
content: `Bạn có đồng ý gửi ${$store.selectedPaymentSchedulesForEmailInOverdue.length} thông báo quá hạn không?`,
|
content: `Bạn có đồng ý gửi ${$store.selectedPaymentSchedulesForEmailInOverdue.length} thông báo quá hạn không?`,
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(filter, () => {
|
watch(
|
||||||
key.value += 1;
|
filter,
|
||||||
setPaymentSheduleData();
|
() => {
|
||||||
}, { deep: true })
|
key.value += 1;
|
||||||
|
setPaymentSheduleData();
|
||||||
|
},
|
||||||
|
{ deep: true },
|
||||||
|
);
|
||||||
|
|
||||||
watch(key, () => {
|
watch(key, () => {
|
||||||
// reset when DataView re-renders because of filter
|
// reset when DataView re-renders because of filter
|
||||||
$store.commit('selectedPaymentSchedulesForEmailInOverdue', [])
|
$store.commit('selectedPaymentSchedulesForEmailInOverdue', []);
|
||||||
})
|
});
|
||||||
|
|
||||||
function toggleAll() {
|
function toggleAll() {
|
||||||
if ($store.selectedPaymentSchedulesForEmailInOverdue.length === 0) {
|
if ($store.selectedPaymentSchedulesForEmailInOverdue.length === 0) {
|
||||||
$store.commit('selectedPaymentSchedulesForEmailInOverdue', paymentSchedule.value.map(p => p.id))
|
$store.commit(
|
||||||
|
'selectedPaymentSchedulesForEmailInOverdue',
|
||||||
|
paymentSchedule.value.map((p) => p.id),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
$store.commit('selectedPaymentSchedulesForEmailInOverdue', [])
|
$store.commit('selectedPaymentSchedulesForEmailInOverdue', []);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const { contents, send, isSending } = useSendEmail(filter, 14);
|
const { contents, send, isSending } = useSendEmail(filter, 14);
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="is-flex is-justify-content-space-between is-align-content-center mb-4">
|
<div
|
||||||
|
class="is-flex is-justify-content-space-between is-align-content-center mb-4"
|
||||||
|
>
|
||||||
<div class="buttons m-0">
|
<div class="buttons m-0">
|
||||||
<p>Quá hạn:</p>
|
<p>Quá hạn:</p>
|
||||||
<button
|
<button
|
||||||
v-for="payable in payables"
|
v-for="payable in payables"
|
||||||
:key="payable.id"
|
:key="payable.id"
|
||||||
@click="setDateFilter(payable.detail)"
|
@click="setDateFilter(payable.detail)"
|
||||||
:class="['button', { 'is-primary': isEqual(activeDateFilter, payable.detail) }]"
|
:class="[
|
||||||
|
'button',
|
||||||
|
{ 'is-primary': isEqual(activeDateFilter, payable.detail) },
|
||||||
|
]"
|
||||||
>
|
>
|
||||||
{{ payable.detail.lookup === 'lte' ? '≤' : '>' }} {{ payable.detail.time }} ngày
|
{{ payable.detail.lookup === 'lte' ? '≤' : '>' }}
|
||||||
|
{{ payable.detail.time }} ngày
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="activeDateFilter"
|
v-if="activeDateFilter"
|
||||||
@click="resetDateFilter()"
|
@click="resetDateFilter()"
|
||||||
class="button is-white"
|
class="button is-white"
|
||||||
@@ -114,19 +127,25 @@ const { contents, send, isSending } = useSendEmail(filter, 14);
|
|||||||
Xoá lọc
|
Xoá lọc
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons" v-if="$store.selectedPaymentSchedulesForEmailInOverdue !== undefined">
|
<div
|
||||||
|
class="buttons"
|
||||||
|
v-if="$store.selectedPaymentSchedulesForEmailInOverdue !== undefined"
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
v-if="$store.selectedPaymentSchedulesForEmailInOverdue.length > 0"
|
v-if="$store.selectedPaymentSchedulesForEmailInOverdue.length > 0"
|
||||||
@click="openConfirmModal()"
|
@click="openConfirmModal()"
|
||||||
:class="['button', 'is-light', { 'is-loading': isSending }]"
|
:class="['button', 'is-light', { 'is-loading': isSending }]"
|
||||||
>
|
>
|
||||||
Gửi {{ $store.selectedPaymentSchedulesForEmailInOverdue.length }} thông báo
|
Gửi {{ $store.selectedPaymentSchedulesForEmailInOverdue.length }} thông
|
||||||
|
báo
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button @click="toggleAll" class="button">
|
||||||
@click="toggleAll"
|
{{
|
||||||
class="button"
|
$store.selectedPaymentSchedulesForEmailInOverdue.length > 0
|
||||||
>
|
? 'Bỏ chọn'
|
||||||
{{ $store.selectedPaymentSchedulesForEmailInOverdue.length > 0 ? 'Bỏ chọn' : 'Chọn' }} tất cả
|
: 'Chọn'
|
||||||
|
}}
|
||||||
|
tất cả
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -141,16 +160,16 @@ const { contents, send, isSending } = useSendEmail(filter, 14);
|
|||||||
filter,
|
filter,
|
||||||
sort: 'to_date',
|
sort: 'to_date',
|
||||||
values: paymentScheduleValues,
|
values: paymentScheduleValues,
|
||||||
}
|
},
|
||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
<Modal
|
<Modal
|
||||||
v-if="showmodal"
|
v-if="showmodal"
|
||||||
v-bind="showmodal"
|
v-bind="showmodal"
|
||||||
@confirm="send()"
|
@confirm="send()"
|
||||||
@close="showmodal = undefined"
|
@close="showmodal = undefined"
|
||||||
/>
|
/>
|
||||||
<!-- <div class="is-flex is-gap-1">
|
<!-- <div class="is-flex is-gap-1">
|
||||||
// debug
|
// debug
|
||||||
<Template1
|
<Template1
|
||||||
v-if="contents"
|
v-if="contents"
|
||||||
@@ -159,4 +178,4 @@ const { contents, send, isSending } = useSendEmail(filter, 14);
|
|||||||
previewMode
|
previewMode
|
||||||
/>
|
/>
|
||||||
</div> -->
|
</div> -->
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -4,7 +4,11 @@
|
|||||||
<div style="width: 200px">
|
<div style="width: 200px">
|
||||||
<div class="py-1" v-for="v in array">
|
<div class="py-1" v-for="v in array">
|
||||||
<a
|
<a
|
||||||
:class="(current ? current.code === v.code : false) ? 'has-text-primary has-text-weight-bold' : ''"
|
:class="
|
||||||
|
(current ? current.code === v.code : false)
|
||||||
|
? 'has-text-primary has-text-weight-bold'
|
||||||
|
: ''
|
||||||
|
"
|
||||||
@click="changeTab(v)"
|
@click="changeTab(v)"
|
||||||
>{{ v.name }}</a
|
>{{ v.name }}</a
|
||||||
>
|
>
|
||||||
@@ -13,162 +17,105 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<div class="fsb-20 mb-3" v-if="current">{{ current.name }}</div>
|
<div class="fsb-20 mb-3" v-if="current">{{ current.name }}</div>
|
||||||
<DataView v-bind="current.vbind" v-if="current && current.typeView === 'table'"></DataView>
|
<DataView
|
||||||
<component v-if="current && current.typeView === 'component'" :is="current.component" v-bind="current.vbind" />
|
v-bind="current.vbind"
|
||||||
|
v-if="current && current.typeView === 'table'"
|
||||||
|
></DataView>
|
||||||
|
<component
|
||||||
|
v-if="current && current.typeView === 'component'"
|
||||||
|
:is="current.component"
|
||||||
|
v-bind="current.vbind"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
var array = [
|
var array = [
|
||||||
{
|
{
|
||||||
code: "transactionphase",
|
code: 'transactionphase',
|
||||||
name: "Giai đoạn giao dịch",
|
name: 'Giai đoạn giao dịch',
|
||||||
typeView: "table",
|
typeView: 'table',
|
||||||
vbind: {
|
vbind: {
|
||||||
api: "transactionphase",
|
api: 'transactionphase',
|
||||||
setting: "transaction-phase",
|
setting: 'transaction-phase',
|
||||||
pagename: "pagedata99",
|
pagename: 'pagedata99',
|
||||||
timeopt: 36000,
|
timeopt: 36000,
|
||||||
modal: {
|
modal: {
|
||||||
component: "parameter/TransactionPhase",
|
component: 'parameter/TransactionPhase',
|
||||||
title: "Transaction phase",
|
title: 'Transaction phase',
|
||||||
height: "400px",
|
height: '400px',
|
||||||
vbind: { api: "transactionphase" },
|
vbind: { api: 'transactionphase' },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: "cart",
|
code: 'cart',
|
||||||
name: "Danh sách giỏ hàng",
|
name: 'Danh sách giỏ hàng',
|
||||||
typeView: "table",
|
typeView: 'table',
|
||||||
vbind: {
|
vbind: {
|
||||||
api: "cart",
|
api: 'cart',
|
||||||
setting: "parameter-fields-cart",
|
setting: 'parameter-fields-cart',
|
||||||
pagename: "parameter-fields-cart",
|
pagename: 'parameter-fields-cart',
|
||||||
timeopt: 36000,
|
timeopt: 36000,
|
||||||
modal: {
|
modal: {
|
||||||
component: "parameter/CodeName",
|
component: 'parameter/CodeName',
|
||||||
title: "Giỏ hàng",
|
title: 'Giỏ hàng',
|
||||||
height: "400px",
|
height: '400px',
|
||||||
vbind: { api: "cart" },
|
vbind: { api: 'cart' },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: "documenttype",
|
code: 'documenttype',
|
||||||
name: "Loại tài liệu",
|
name: 'Loại tài liệu',
|
||||||
typeView: "table",
|
typeView: 'table',
|
||||||
vbind: {
|
vbind: {
|
||||||
api: "documenttype",
|
api: 'documenttype',
|
||||||
setting: "parameter-fields",
|
setting: 'parameter-fields',
|
||||||
pagename: "pagedata99",
|
pagename: 'pagedata99',
|
||||||
timeopt: 36000,
|
timeopt: 36000,
|
||||||
modal: {
|
modal: {
|
||||||
component: "parameter/CodeName",
|
component: 'parameter/CodeName',
|
||||||
title: "Document type",
|
title: 'Document type',
|
||||||
height: "400px",
|
height: '400px',
|
||||||
vbind: { api: "documenttype" },
|
vbind: { api: 'documenttype' },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: "discounttype",
|
code: 'discounttype',
|
||||||
name: "Danh sách chiết khấu",
|
name: 'Danh sách chiết khấu',
|
||||||
typeView: "table",
|
typeView: 'table',
|
||||||
vbind: {
|
vbind: {
|
||||||
api: "discounttype",
|
api: 'discounttype',
|
||||||
setting: "parameter-discount",
|
setting: 'parameter-discount',
|
||||||
pagename: "tableDiscountType",
|
pagename: 'tableDiscountType',
|
||||||
timeopt: 36000,
|
timeopt: 36000,
|
||||||
modal: {
|
modal: {
|
||||||
component: "parameter/DiscountType",
|
component: 'parameter/DiscountType',
|
||||||
title: "Thông tin chiết khấu",
|
title: 'Thông tin chiết khấu',
|
||||||
height: "400px",
|
height: '400px',
|
||||||
vbind: { api: "discounttype" },
|
vbind: { api: 'discounttype' },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
code: "gifttype",
|
code: 'gifttype',
|
||||||
name: "Danh sách quà tặng",
|
name: 'Danh sách quà tặng',
|
||||||
typeView: "table",
|
typeView: 'table',
|
||||||
vbind: {
|
vbind: {
|
||||||
api: "gift",
|
api: 'gift',
|
||||||
setting: "parameter-gift",
|
setting: 'parameter-gift',
|
||||||
pagename: "tableDiscountType",
|
pagename: 'tableDiscountType',
|
||||||
timeopt: 36000,
|
timeopt: 36000,
|
||||||
modal: {
|
modal: {
|
||||||
component: "parameter/GiftType",
|
component: 'parameter/GiftType',
|
||||||
title: "Thông tin quà tặng",
|
title: 'Thông tin quà tặng',
|
||||||
height: "400px",
|
height: '400px',
|
||||||
vbind: { api: "gift" },
|
vbind: { api: 'gift' },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
code: "DuePayables",
|
|
||||||
name: "Lịch công nợ đến hạn",
|
|
||||||
typeView: "table",
|
|
||||||
vbind: {
|
|
||||||
api: "bizsetting",
|
|
||||||
params: {
|
|
||||||
filter: {
|
|
||||||
category: "system",
|
|
||||||
classify: "duepayables",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
setting: "parameter-payable-schedule",
|
|
||||||
pagename: "tablePayableSchedule",
|
|
||||||
timeopt: 36000,
|
|
||||||
modal: {
|
|
||||||
component: "parameter/DuePayables",
|
|
||||||
title: "Thông tin lịch công nợ đến hạn",
|
|
||||||
height: "400px",
|
|
||||||
vbind: { api: "bizsetting" },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: "OverduePayables",
|
|
||||||
name: "Lịch công nợ quá hạn",
|
|
||||||
typeView: "table",
|
|
||||||
vbind: {
|
|
||||||
api: "bizsetting",
|
|
||||||
params: {
|
|
||||||
filter: {
|
|
||||||
category: "system",
|
|
||||||
classify: "overduepayables",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
setting: "parameter-overdue-payables",
|
|
||||||
pagename: "tableOverduePayables",
|
|
||||||
timeopt: 36000,
|
|
||||||
modal: {
|
|
||||||
component: "parameter/OverduePayables",
|
|
||||||
title: "Thông tin lịch công nợ quá hạn",
|
|
||||||
height: "400px",
|
|
||||||
vbind: { api: "bizsetting" },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// {
|
|
||||||
// code: "allocationRules",
|
|
||||||
// name: "Quy tắc phân bổ",
|
|
||||||
// typeView: "component",
|
|
||||||
// component: defineAsyncComponent(() => import("@/components/parameter/AllocationRules.vue")),
|
|
||||||
// vbind: {
|
|
||||||
// api: "common",
|
|
||||||
// setting: "parameter-gift",
|
|
||||||
// pagename: "tableDiscountType",
|
|
||||||
// timeopt: 36000,
|
|
||||||
// modal: {
|
|
||||||
// component: "parameter/AllocationRules",
|
|
||||||
// title: "Thông tin quà tặng",
|
|
||||||
// height: "400px",
|
|
||||||
// vbind: { api: "gift" },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
];
|
];
|
||||||
var current = ref(array[0]);
|
var current = ref(array[0]);
|
||||||
function changeTab(v) {
|
function changeTab(v) {
|
||||||
|
|||||||
@@ -3,7 +3,11 @@
|
|||||||
<div v-if="loadingData" class="has-text-centered py-5">
|
<div v-if="loadingData" class="has-text-centered py-5">
|
||||||
<SvgIcon v-bind="{ name: 'loading.svg', type: 'primary', size: 18 }" />
|
<SvgIcon v-bind="{ name: 'loading.svg', type: 'primary', size: 18 }" />
|
||||||
<p class="mt-2">
|
<p class="mt-2">
|
||||||
{{ isVietnamese ? "Đang tải thông tin công nợ..." : "Loading payment schedule information..." }}
|
{{
|
||||||
|
isVietnamese
|
||||||
|
? 'Đang tải thông tin công nợ...'
|
||||||
|
: 'Loading payment schedule information...'
|
||||||
|
}}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -12,95 +16,171 @@
|
|||||||
<!-- Thông tin cơ bản -->
|
<!-- Thông tin cơ bản -->
|
||||||
<div class="columns is-multiline is-mobile">
|
<div class="columns is-multiline is-mobile">
|
||||||
<div class="column is-3">
|
<div class="column is-3">
|
||||||
<strong>{{ isVietnamese ? "Mã:" : "Schedule Code:" }}</strong>
|
<strong>{{ isVietnamese ? 'Mã:' : 'Schedule Code:' }}</strong>
|
||||||
<p>{{ paymentScheduleData.code || "-" }}</p>
|
<p>{{ paymentScheduleData.code || '-' }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-3">
|
<div class="column is-3">
|
||||||
<strong>{{ isVietnamese ? "Trạng thái:" : "Status:" }}</strong>
|
<strong>{{ isVietnamese ? 'Trạng thái:' : 'Status:' }}</strong>
|
||||||
<p :class="{
|
<p
|
||||||
'has-text-success': paymentScheduleData.status__name === 'Đã xác nhận' || paymentScheduleData.status__name === 'Paid',
|
:class="{
|
||||||
'has-text-warning': paymentScheduleData.status__name === 'Chưa xác nhận' || paymentScheduleData.status__name === 'Pending',
|
'has-text-success':
|
||||||
'has-text-danger': paymentScheduleData.status__name === 'Quá hạn' || paymentScheduleData.status__name === 'Overdue'
|
paymentScheduleData.status__name === 'Đã xác nhận' ||
|
||||||
}">
|
paymentScheduleData.status__name === 'Paid',
|
||||||
{{ paymentScheduleData.status__name || "-" }}
|
'has-text-warning':
|
||||||
|
paymentScheduleData.status__name === 'Chưa xác nhận' ||
|
||||||
|
paymentScheduleData.status__name === 'Pending',
|
||||||
|
'has-text-danger':
|
||||||
|
paymentScheduleData.status__name === 'Quá hạn' ||
|
||||||
|
paymentScheduleData.status__name === 'Overdue',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ paymentScheduleData.status__name || '-' }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-3">
|
<div class="column is-3">
|
||||||
<strong>{{ isVietnamese ? "Loại thanh toán:" : "Payment Type:" }}</strong>
|
<strong>{{
|
||||||
<p>{{ paymentScheduleData.type__name || "-" }}</p>
|
isVietnamese ? 'Loại thanh toán:' : 'Payment Type:'
|
||||||
|
}}</strong>
|
||||||
|
<p>{{ paymentScheduleData.type__name || '-' }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-3">
|
<div class="column is-3">
|
||||||
<strong>{{ isVietnamese ? "Đợt thanh toán:" : "Cycle:" }}</strong>
|
<strong>{{ isVietnamese ? 'Đợt thanh toán:' : 'Cycle:' }}</strong>
|
||||||
<p>{{ paymentScheduleData.cycle_days || 0 }} ngày</p>
|
<p>{{ paymentScheduleData.cycle_days || 0 }} ngày</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-3">
|
<div class="column is-3">
|
||||||
<strong>{{ isVietnamese ? "Tiền gốc theo kỳ thanh toán:" : "Amount:" }}</strong>
|
<strong>{{
|
||||||
<p class="has-text-weight-bold has-text-primary">{{ $numtoString(paymentScheduleData.amount) }}</p>
|
isVietnamese ? 'Tiền gốc theo kỳ thanh toán:' : 'Amount:'
|
||||||
|
}}</strong>
|
||||||
|
<p class="has-text-weight-bold has-text-primary">
|
||||||
|
{{ $numtoString(paymentScheduleData.amount) }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-3">
|
<div class="column is-3">
|
||||||
<strong>{{ isVietnamese ? "Số tiền gốc đã thanh toán:" : "Paid Amount:" }}</strong>
|
<strong>{{
|
||||||
<p class="has-text-weight-bold has-text-primary">{{ $numtoString(paymentScheduleData.paid_amount) }}</p>
|
isVietnamese ? 'Số tiền gốc đã thanh toán:' : 'Paid Amount:'
|
||||||
|
}}</strong>
|
||||||
|
<p class="has-text-weight-bold has-text-primary">
|
||||||
|
{{ $numtoString(paymentScheduleData.paid_amount) }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-3">
|
<div class="column is-3">
|
||||||
<strong>{{ isVietnamese ? "Số tiền gốc còn lại:" : "Remaining Principal:" }}</strong>
|
<strong>{{
|
||||||
<p class="has-text-weight-bold"
|
isVietnamese ? 'Số tiền gốc còn lại:' : 'Remaining Principal:'
|
||||||
:class="paymentScheduleData.amount_remain > 0 ? 'has-text-danger' : 'has-text-success'">
|
}}</strong>
|
||||||
|
<p
|
||||||
|
class="has-text-weight-bold"
|
||||||
|
:class="
|
||||||
|
paymentScheduleData.amount_remain > 0
|
||||||
|
? 'has-text-danger'
|
||||||
|
: 'has-text-success'
|
||||||
|
"
|
||||||
|
>
|
||||||
{{ $numtoString(paymentScheduleData.amount_remain) }}
|
{{ $numtoString(paymentScheduleData.amount_remain) }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-3">
|
<div class="column is-3">
|
||||||
<strong>{{ isVietnamese ? "Ngày đến hạn:" : "Due Date:" }}</strong>
|
<strong>{{ isVietnamese ? 'Ngày đến hạn:' : 'Due Date:' }}</strong>
|
||||||
<p :class="{ 'has-text-danger': isOverdue(paymentScheduleData.to_date && paymentScheduleData.ovd_days > 0) }">
|
<p
|
||||||
|
:class="{
|
||||||
|
'has-text-danger': isOverdue(
|
||||||
|
paymentScheduleData.to_date &&
|
||||||
|
paymentScheduleData.ovd_days > 0,
|
||||||
|
),
|
||||||
|
}"
|
||||||
|
>
|
||||||
{{ formatDate(paymentScheduleData.to_date) }}
|
{{ formatDate(paymentScheduleData.to_date) }}
|
||||||
<span v-if="isOverdue(paymentScheduleData.to_date && paymentScheduleData.ovd_days > 0)" class="has-text-weight-bold">
|
<span
|
||||||
|
v-if="
|
||||||
|
isOverdue(
|
||||||
|
paymentScheduleData.to_date &&
|
||||||
|
paymentScheduleData.ovd_days > 0,
|
||||||
|
)
|
||||||
|
"
|
||||||
|
class="has-text-weight-bold"
|
||||||
|
>
|
||||||
(Quá hạn {{ paymentScheduleData.ovd_days }} ngày)
|
(Quá hạn {{ paymentScheduleData.ovd_days }} ngày)
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-3">
|
<div class="column is-3">
|
||||||
<strong>{{ isVietnamese ? "Tổng lãi phải thu:" : "Total Penalty Amount:" }}</strong>
|
<strong>{{
|
||||||
|
isVietnamese ? 'Tổng lãi phải thu:' : 'Total Penalty Amount:'
|
||||||
|
}}</strong>
|
||||||
<p class="has-text-weight-bold has-text-danger">
|
<p class="has-text-weight-bold has-text-danger">
|
||||||
{{ paymentScheduleData.penalty_amount > 0 ? $numtoString(paymentScheduleData.penalty_amount) : "-" }}
|
{{
|
||||||
|
paymentScheduleData.penalty_amount > 0
|
||||||
|
? $numtoString(paymentScheduleData.penalty_amount)
|
||||||
|
: '-'
|
||||||
|
}}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-3">
|
<div class="column is-3">
|
||||||
<strong>{{ isVietnamese ? "Lãi phạt đã thanh toán:" : "Penalty Paid:" }}</strong>
|
<strong>{{
|
||||||
|
isVietnamese ? 'Lãi phạt đã thanh toán:' : 'Penalty Paid:'
|
||||||
|
}}</strong>
|
||||||
<p class="has-text-weight-bold has-text-success">
|
<p class="has-text-weight-bold has-text-success">
|
||||||
{{ paymentScheduleData.penalty_paid > 0 ? $numtoString(paymentScheduleData.penalty_paid) : "-" }}
|
{{
|
||||||
|
paymentScheduleData.penalty_paid > 0
|
||||||
|
? $numtoString(paymentScheduleData.penalty_paid)
|
||||||
|
: '-'
|
||||||
|
}}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-3">
|
<div class="column is-3">
|
||||||
<strong>{{ isVietnamese ? "Lãi phạt còn lại:" : "Penalty Remaining:" }}</strong>
|
<strong>{{
|
||||||
|
isVietnamese ? 'Lãi phạt còn lại:' : 'Penalty Remaining:'
|
||||||
|
}}</strong>
|
||||||
<p class="has-text-weight-bold has-text-danger">
|
<p class="has-text-weight-bold has-text-danger">
|
||||||
{{ paymentScheduleData.penalty_remain > 0 ? $numtoString(paymentScheduleData.penalty_remain) : "-" }}
|
{{
|
||||||
|
paymentScheduleData.penalty_remain > 0
|
||||||
|
? $numtoString(paymentScheduleData.penalty_remain)
|
||||||
|
: '-'
|
||||||
|
}}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-3">
|
<div class="column is-3">
|
||||||
<strong>{{ isVietnamese ? "Miễn giảm lãi phạt:" : "Penalty Reduced:" }}</strong>
|
<strong>{{
|
||||||
|
isVietnamese ? 'Miễn giảm lãi phạt:' : 'Penalty Reduced:'
|
||||||
|
}}</strong>
|
||||||
<p class="has-text-weight-bold has-text-primary">
|
<p class="has-text-weight-bold has-text-primary">
|
||||||
{{ paymentScheduleData.penalty_reduce > 0 ? $numtoString(paymentScheduleData.penalty_reduce) : "-" }}
|
{{
|
||||||
|
paymentScheduleData.penalty_reduce > 0
|
||||||
|
? $numtoString(paymentScheduleData.penalty_reduce)
|
||||||
|
: '-'
|
||||||
|
}}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-3">
|
<div class="column is-3">
|
||||||
<strong>{{ isVietnamese ? "Tổng tiền phải thanh toán:" : "Total Remaining:" }}</strong>
|
<strong>{{
|
||||||
<p class="has-text-weight-bold has-text-primary">{{ $numtoString(paymentScheduleData.remain_amount) }}</p>
|
isVietnamese ? 'Tổng tiền phải thanh toán:' : 'Total Remaining:'
|
||||||
|
}}</strong>
|
||||||
|
<p class="has-text-weight-bold has-text-primary">
|
||||||
|
{{ $numtoString(paymentScheduleData.remain_amount) }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-3">
|
<div class="column is-3">
|
||||||
<strong>{{ isVietnamese ? "Ghi chú:" : "Note:" }}</strong>
|
<strong>{{ isVietnamese ? 'Ghi chú:' : 'Note:' }}</strong>
|
||||||
<p class="is-size-6">{{ paymentScheduleData.detail?.note || "-" }}</p>
|
<p class="is-size-6">
|
||||||
|
{{ paymentScheduleData.detail?.note || '-' }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<!-- Timeline lịch sử -->
|
<!-- Timeline lịch sử -->
|
||||||
<div v-if="processedEntries.length > 0" class="is-flex is-flex-direction-column is-gap-5">
|
<div
|
||||||
|
v-if="processedEntries.length > 0"
|
||||||
<div v-for="(item, index) in processedEntries" :key="index" class="is-flex is-align-items-start is-gap-4">
|
class="is-flex is-flex-direction-column is-gap-5"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in processedEntries"
|
||||||
|
:key="index"
|
||||||
|
class="is-flex is-align-items-start is-gap-4"
|
||||||
|
>
|
||||||
<!-- ===================== REDUCTION ===================== -->
|
<!-- ===================== REDUCTION ===================== -->
|
||||||
<template v-if="item.isReduction">
|
<template v-if="item.isReduction">
|
||||||
<div style="min-width: 3rem;">
|
<div style="min-width: 3rem">
|
||||||
<p class="is-size-5 has-text-weight-bold has-text-info">
|
<p class="is-size-5 has-text-weight-bold has-text-info">
|
||||||
{{ formatDate(item.entry.date) }}
|
{{ formatDate(item.entry.date) }}
|
||||||
</p>
|
</p>
|
||||||
@@ -112,23 +192,40 @@
|
|||||||
<div class="is-flex-grow-1">
|
<div class="is-flex-grow-1">
|
||||||
<p class="is-size-5 has-text-weight-bold has-text-info mb-2">
|
<p class="is-size-5 has-text-weight-bold has-text-info mb-2">
|
||||||
Miễn giảm lãi phạt
|
Miễn giảm lãi phạt
|
||||||
<span v-if="item.entry.code" class="tag is-info is-light ml-2">
|
<span
|
||||||
|
v-if="item.entry.code"
|
||||||
|
class="tag is-info is-light ml-2"
|
||||||
|
>
|
||||||
{{ item.entry.code }}
|
{{ item.entry.code }}
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="box is-shadowless p-4" style="border-left: 5px solid #3273dc;">
|
<div
|
||||||
|
class="box is-shadowless p-4"
|
||||||
|
style="border-left: 5px solid #3273dc"
|
||||||
|
>
|
||||||
<div class="columns is-mobile is-multiline">
|
<div class="columns is-mobile is-multiline">
|
||||||
<div class="column is-6-mobile">
|
<div class="column is-6-mobile">
|
||||||
<span class="has-text-grey-light">Số tiền miễn giảm:</span><br />
|
<span class="has-text-grey-light">Số tiền miễn giảm:</span
|
||||||
<span class="has-text-info has-text-weight-semibold is-size-5">
|
><br />
|
||||||
|
<span
|
||||||
|
class="has-text-info has-text-weight-semibold is-size-5"
|
||||||
|
>
|
||||||
{{ $numtoString(item.reduceAmount) }}
|
{{ $numtoString(item.reduceAmount) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-6-mobile">
|
<div class="column is-6-mobile">
|
||||||
<span class="has-text-grey-light">Lãi còn lại sau miễn giảm:</span><br />
|
<span class="has-text-grey-light"
|
||||||
<span class="has-text-weight-semibold is-size-5"
|
>Lãi còn lại sau miễn giảm:</span
|
||||||
:class="item.penaltyRemain > 0 ? 'has-text-danger' : 'has-text-success'">
|
><br />
|
||||||
|
<span
|
||||||
|
class="has-text-weight-semibold is-size-5"
|
||||||
|
:class="
|
||||||
|
item.penaltyRemain > 0
|
||||||
|
? 'has-text-danger'
|
||||||
|
: 'has-text-success'
|
||||||
|
"
|
||||||
|
>
|
||||||
{{ $numtoString(item.penaltyRemain) }}
|
{{ $numtoString(item.penaltyRemain) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -139,7 +236,7 @@
|
|||||||
|
|
||||||
<!-- ===================== PAYMENT ===================== -->
|
<!-- ===================== PAYMENT ===================== -->
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div style="min-width: 3rem;">
|
<div style="min-width: 3rem">
|
||||||
<p class="is-size-5 has-text-weight-bold has-text-primary">
|
<p class="is-size-5 has-text-weight-bold has-text-primary">
|
||||||
{{ formatDate(item.entry.date) }}
|
{{ formatDate(item.entry.date) }}
|
||||||
</p>
|
</p>
|
||||||
@@ -151,16 +248,25 @@
|
|||||||
<div class="is-flex-grow-1">
|
<div class="is-flex-grow-1">
|
||||||
<p class="is-size-5 has-text-weight-bold has-text-dark mb-2">
|
<p class="is-size-5 has-text-weight-bold has-text-dark mb-2">
|
||||||
{{ getEntryTypeLabel(item.entry.type) }}
|
{{ getEntryTypeLabel(item.entry.type) }}
|
||||||
<span v-if="item.entry.code" class="tag is-link is-light ml-2">
|
<span
|
||||||
|
v-if="item.entry.code"
|
||||||
|
class="tag is-link is-light ml-2"
|
||||||
|
>
|
||||||
{{ item.entry.code }}
|
{{ item.entry.code }}
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="box is-shadowless p-4" style="border-left: 5px solid #204853;">
|
<div
|
||||||
|
class="box is-shadowless p-4"
|
||||||
|
style="border-left: 5px solid #204853"
|
||||||
|
>
|
||||||
<div class="columns is-mobile is-multiline is-gap-3">
|
<div class="columns is-mobile is-multiline is-gap-3">
|
||||||
<div class="column is-6-mobile">
|
<div class="column is-6-mobile">
|
||||||
<span class="has-text-grey-light">Gốc trả:</span><br />
|
<span class="has-text-grey-light">Gốc trả:</span><br />
|
||||||
<span v-if="item.entry.principal > 0" class="has-text-success has-text-weight-semibold is-size-5">
|
<span
|
||||||
|
v-if="item.entry.principal > 0"
|
||||||
|
class="has-text-success has-text-weight-semibold is-size-5"
|
||||||
|
>
|
||||||
{{ $numtoString(item.entry.principal) }}
|
{{ $numtoString(item.entry.principal) }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else class="has-text-grey-light">-</span>
|
<span v-else class="has-text-grey-light">-</span>
|
||||||
@@ -168,16 +274,26 @@
|
|||||||
|
|
||||||
<div class="column is-6-mobile">
|
<div class="column is-6-mobile">
|
||||||
<span class="has-text-grey-light">Lãi trả:</span><br />
|
<span class="has-text-grey-light">Lãi trả:</span><br />
|
||||||
<span v-if="item.entry.penalty > 0" class="has-text-danger has-text-weight-semibold is-size-5">
|
<span
|
||||||
|
v-if="item.entry.penalty > 0"
|
||||||
|
class="has-text-danger has-text-weight-semibold is-size-5"
|
||||||
|
>
|
||||||
{{ $numtoString(item.entry.penalty) }}
|
{{ $numtoString(item.entry.penalty) }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else class="has-text-grey-light">-</span>
|
<span v-else class="has-text-grey-light">-</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="column is-6-mobile">
|
<div class="column is-6-mobile">
|
||||||
<span class="has-text-grey-light">Gốc còn lại:</span><br />
|
<span class="has-text-grey-light">Gốc còn lại:</span
|
||||||
<strong :class="item.principalRemain > 0 ? 'has-text-danger' : 'has-text-success'"
|
><br />
|
||||||
class="is-size-5">
|
<strong
|
||||||
|
:class="
|
||||||
|
item.principalRemain > 0
|
||||||
|
? 'has-text-danger'
|
||||||
|
: 'has-text-success'
|
||||||
|
"
|
||||||
|
class="is-size-5"
|
||||||
|
>
|
||||||
{{ $numtoString(item.principalRemain) }}
|
{{ $numtoString(item.principalRemain) }}
|
||||||
</strong>
|
</strong>
|
||||||
</div>
|
</div>
|
||||||
@@ -185,15 +301,30 @@
|
|||||||
|
|
||||||
<!-- Chi tiết lãi phát sinh -->
|
<!-- Chi tiết lãi phát sinh -->
|
||||||
<div class="">
|
<div class="">
|
||||||
<p v-if="item.penaltyThisPeriod > 0" class="is-size-6 has-text-grey">
|
<p
|
||||||
Dư nợ gốc còn lại: {{ $numtoString(item.principalBefore) }} ×
|
v-if="item.penaltyThisPeriod > 0"
|
||||||
{{ item.penaltyDetail.days }} ngày (từ {{ item.penaltyDetail.from }} đến {{ item.penaltyDetail.to }})
|
class="is-size-6 has-text-grey"
|
||||||
× {{ item.rate }}%/ngày = {{ $numtoString(item.penaltyThisPeriod) }}
|
>
|
||||||
|
Dư nợ gốc còn lại:
|
||||||
|
{{ $numtoString(item.principalBefore) }} ×
|
||||||
|
{{ item.penaltyDetail.days }} ngày (từ
|
||||||
|
{{ item.penaltyDetail.from }} đến
|
||||||
|
{{ item.penaltyDetail.to }}) × {{ item.rate }}%/ngày =
|
||||||
|
{{ $numtoString(item.penaltyThisPeriod) }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="is-size-6 mt-3">
|
<p class="is-size-6 mt-3">
|
||||||
<strong>Tổng lãi tích lũy đến {{ formatDate(item.entry.date) }}: </strong>
|
<strong
|
||||||
<span :class="item.penaltyAccumulated > 0 ? 'has-text-danger' : 'has-text-grey'">
|
>Tổng lãi tích lũy đến
|
||||||
|
{{ formatDate(item.entry.date) }}:
|
||||||
|
</strong>
|
||||||
|
<span
|
||||||
|
:class="
|
||||||
|
item.penaltyAccumulated > 0
|
||||||
|
? 'has-text-danger'
|
||||||
|
: 'has-text-grey'
|
||||||
|
"
|
||||||
|
>
|
||||||
{{ $numtoString(item.penaltyAccumulated) }}
|
{{ $numtoString(item.penaltyAccumulated) }}
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
@@ -201,20 +332,36 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Tiền lãi hiện tại (nếu chưa hết nợ) -->
|
<!-- Tiền lãi hiện tại (nếu chưa hết nợ) -->
|
||||||
<div v-if="hasUnpaidDebt && latestPenaltyToThisEntry != paymentScheduleData.penalty_amount && processedEntries.length > 0 && latestPenaltyToThisEntry > 0" class="mt-5 box has-background-warning-light">
|
<div
|
||||||
|
v-if="
|
||||||
|
hasUnpaidDebt &&
|
||||||
|
latestPenaltyToThisEntry != paymentScheduleData.penalty_amount &&
|
||||||
|
processedEntries.length > 0 &&
|
||||||
|
latestPenaltyToThisEntry > 0
|
||||||
|
"
|
||||||
|
class="mt-5 box has-background-warning-light"
|
||||||
|
>
|
||||||
<p class="is-size-5">
|
<p class="is-size-5">
|
||||||
<strong>Lãi đến ngày thanh toán gần nhất ({{ latestEntryDate }}) :</strong> {{ $numtoString(latestPenaltyToThisEntry) }}
|
<strong
|
||||||
|
>Lãi đến ngày thanh toán gần nhất ({{ latestEntryDate }})
|
||||||
|
:</strong
|
||||||
|
>
|
||||||
|
{{ $numtoString(latestPenaltyToThisEntry) }}
|
||||||
</p>
|
</p>
|
||||||
<p v-if="latestAdditionalPenalty > 0" class="is-size-5 mt-2">
|
<p v-if="latestAdditionalPenalty > 0" class="is-size-5 mt-2">
|
||||||
<strong>Lãi phát sinh từ ngày {{ latestEntryDate }} đến nay:</strong> {{ $numtoString(latestAdditionalPenalty) }}
|
<strong
|
||||||
|
>Lãi phát sinh từ ngày {{ latestEntryDate }} đến nay:</strong
|
||||||
|
>
|
||||||
|
{{ $numtoString(latestAdditionalPenalty) }}
|
||||||
</p>
|
</p>
|
||||||
<p class="is-size-5 has-text-weight-bold mt-3">
|
<p class="is-size-5 has-text-weight-bold mt-3">
|
||||||
Tổng lãi hiện tại: {{ $numtoString(latestPenaltyToThisEntry) }} + {{ $numtoString(latestAdditionalPenalty) }} = {{ $numtoString(paymentScheduleData.penalty_amount) }}
|
Tổng lãi hiện tại: {{ $numtoString(latestPenaltyToThisEntry) }} +
|
||||||
|
{{ $numtoString(latestAdditionalPenalty) }} =
|
||||||
|
{{ $numtoString(paymentScheduleData.penalty_amount) }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -224,59 +371,96 @@
|
|||||||
<div class="columns is-mobile is-multiline">
|
<div class="columns is-mobile is-multiline">
|
||||||
<div class="column is-3-tablet is-6-mobile">
|
<div class="column is-3-tablet is-6-mobile">
|
||||||
<p class="heading">Gốc đã trả</p>
|
<p class="heading">Gốc đã trả</p>
|
||||||
<p class="title is-5 has-text-success">{{ $numtoString(paymentScheduleData.paid_amount) }}</p>
|
<p class="title is-5 has-text-success">
|
||||||
|
{{ $numtoString(paymentScheduleData.paid_amount) }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-3-tablet is-6-mobile">
|
<div class="column is-3-tablet is-6-mobile">
|
||||||
<p class="heading">Gốc còn lại</p>
|
<p class="heading">Gốc còn lại</p>
|
||||||
<p class="title is-5"
|
<p
|
||||||
:class="paymentScheduleData.amount_remain > 0 ? 'has-text-danger' : 'has-text-success'">
|
class="title is-5"
|
||||||
|
:class="
|
||||||
|
paymentScheduleData.amount_remain > 0
|
||||||
|
? 'has-text-danger'
|
||||||
|
: 'has-text-success'
|
||||||
|
"
|
||||||
|
>
|
||||||
{{ $numtoString(paymentScheduleData.amount_remain) }}
|
{{ $numtoString(paymentScheduleData.amount_remain) }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-3-tablet is-6-mobile">
|
<div class="column is-3-tablet is-6-mobile">
|
||||||
<p class="heading">Lãi đã trả</p>
|
<p class="heading">Lãi đã trả</p>
|
||||||
<p class="title is-5 has-text-success">{{ $numtoString(paymentScheduleData.penalty_paid) }}</p>
|
<p class="title is-5 has-text-success">
|
||||||
|
{{ $numtoString(paymentScheduleData.penalty_paid) }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-3-tablet is-6-mobile">
|
<div class="column is-3-tablet is-6-mobile">
|
||||||
<p class="heading">Lãi còn lại</p>
|
<p class="heading">Lãi còn lại</p>
|
||||||
<p class="title is-5"
|
<p
|
||||||
:class="paymentScheduleData.penalty_remain > 0 ? 'has-text-danger' : 'has-text-success'">
|
class="title is-5"
|
||||||
|
:class="
|
||||||
|
paymentScheduleData.penalty_remain > 0
|
||||||
|
? 'has-text-danger'
|
||||||
|
: 'has-text-success'
|
||||||
|
"
|
||||||
|
>
|
||||||
{{ $numtoString(paymentScheduleData.penalty_remain) }}
|
{{ $numtoString(paymentScheduleData.penalty_remain) }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="paymentScheduleData.penalty_reduce > 0" class="column is-3-tablet is-6-mobile">
|
<div
|
||||||
|
v-if="paymentScheduleData.penalty_reduce > 0"
|
||||||
|
class="column is-3-tablet is-6-mobile"
|
||||||
|
>
|
||||||
<p class="heading">Đã miễn giảm lãi</p>
|
<p class="heading">Đã miễn giảm lãi</p>
|
||||||
<p class="title is-5 has-text-info">{{ $numtoString(paymentScheduleData.penalty_reduce) }}</p>
|
<p class="title is-5 has-text-info">
|
||||||
|
{{ $numtoString(paymentScheduleData.penalty_reduce) }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-3-tablet is-6-mobile">
|
<div class="column is-3-tablet is-6-mobile">
|
||||||
<p class="heading">Tổng tiền phải thanh toán</p>
|
<p class="heading">Tổng tiền phải thanh toán</p>
|
||||||
<p class="title is-5 has-text-primary">{{ $numtoString(paymentScheduleData.remain_amount) }}</p>
|
<p class="title is-5 has-text-primary">
|
||||||
|
{{ $numtoString(paymentScheduleData.remain_amount) }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="isConfirmAllowed && $getEditRights()" class="field is-grouped is-grouped-left">
|
<div
|
||||||
|
v-if="isConfirmAllowed && $getEditRights()"
|
||||||
|
class="field is-grouped is-grouped-left"
|
||||||
|
>
|
||||||
<p class="control">
|
<p class="control">
|
||||||
<button class="button is-info mr-3 has-text-white" @click="handleViewEmail">
|
<button
|
||||||
|
class="button is-info mr-3 has-text-white"
|
||||||
|
@click="handleViewEmail"
|
||||||
|
>
|
||||||
<span>Gửi thông báo</span>
|
<span>Gửi thông báo</span>
|
||||||
</button>
|
</button>
|
||||||
<button v-if="paymentScheduleData.batch_date == null" class="button is-danger has-text-white"
|
<button
|
||||||
:class="{ 'is-loading': isLoading }" @click="getPenalty" :disabled="isLoading">
|
v-if="paymentScheduleData.batch_date == null"
|
||||||
|
class="button is-danger has-text-white"
|
||||||
|
:class="{ 'is-loading': isLoading }"
|
||||||
|
@click="getPenalty"
|
||||||
|
:disabled="isLoading"
|
||||||
|
>
|
||||||
<span>Tính lãi</span>
|
<span>Tính lãi</span>
|
||||||
</button>
|
</button>
|
||||||
</p>
|
</p>
|
||||||
<Modal @close="showModalViewEmail = undefined" v-bind="showModalViewEmail" v-if="showModalViewEmail"></Modal>
|
<Modal
|
||||||
|
@close="showModalViewEmail = undefined"
|
||||||
|
v-bind="showModalViewEmail"
|
||||||
|
v-if="showModalViewEmail"
|
||||||
|
></Modal>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted } from "vue";
|
import { ref, computed, onMounted } from 'vue';
|
||||||
import { useNuxtApp } from "#app";
|
import { useNuxtApp } from '#app';
|
||||||
import { useStore } from "@/stores/index";
|
import { useStore } from '@/stores/index';
|
||||||
import dayjs from "dayjs";
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
scheduleItemId: {
|
scheduleItemId: {
|
||||||
@@ -285,39 +469,50 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(["close", "confirmed"]);
|
const emit = defineEmits(['close', 'confirmed']);
|
||||||
|
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
const { $insertapi, $snackbar, $getEditRights, $getdata, $patchapi, $numtoString } = useNuxtApp();
|
const {
|
||||||
|
$insertapi,
|
||||||
|
$snackbar,
|
||||||
|
$getEditRights,
|
||||||
|
$getdata,
|
||||||
|
$patchapi,
|
||||||
|
$numtoString,
|
||||||
|
} = useNuxtApp();
|
||||||
|
|
||||||
const isLoading = ref(false);
|
const isLoading = ref(false);
|
||||||
const loadingData = ref(true);
|
const loadingData = ref(true);
|
||||||
const paymentScheduleData = ref(null);
|
const paymentScheduleData = ref(null);
|
||||||
const rule = ref(null);
|
const rule = ref(null);
|
||||||
const invoiceData = ref({ link: "", ref_code: "" });
|
const invoiceData = ref({ link: '', ref_code: '' });
|
||||||
const isUpdatingInvoice = ref(false);
|
const isUpdatingInvoice = ref(false);
|
||||||
const showModal = ref(null);
|
const showModal = ref(null);
|
||||||
const showModalViewEmail = ref(null);
|
const showModalViewEmail = ref(null);
|
||||||
|
|
||||||
const isVietnamese = computed(() => store.lang === "vi");
|
const isVietnamese = computed(() => store.lang === 'vi');
|
||||||
|
|
||||||
const isOverdue = (dueDate) => {
|
const isOverdue = (dueDate) => {
|
||||||
if (!dueDate) return false;
|
if (!dueDate) return false;
|
||||||
return dayjs(dueDate).isBefore(dayjs(), "day");
|
return dayjs(dueDate).isBefore(dayjs(), 'day');
|
||||||
};
|
};
|
||||||
|
|
||||||
const isConfirmAllowed = computed(() => paymentScheduleData.value?.status === 1);
|
const isConfirmAllowed = computed(
|
||||||
const isInvoiceAllowed = computed(() => paymentScheduleData.value?.status === 2);
|
() => paymentScheduleData.value?.status === 1,
|
||||||
|
);
|
||||||
|
const isInvoiceAllowed = computed(
|
||||||
|
() => paymentScheduleData.value?.status === 2,
|
||||||
|
);
|
||||||
|
|
||||||
const formatDate = (dateString) => {
|
const formatDate = (dateString) => {
|
||||||
if (!dateString) return "-";
|
if (!dateString) return '-';
|
||||||
return dayjs(dateString).format("DD/MM/YYYY");
|
return dayjs(dateString).format('DD/MM/YYYY');
|
||||||
};
|
};
|
||||||
|
|
||||||
const getEntryTypeLabel = (type) => {
|
const getEntryTypeLabel = (type) => {
|
||||||
const labels = {
|
const labels = {
|
||||||
PAYMENT: "Thanh toán",
|
PAYMENT: 'Thanh toán',
|
||||||
REDUCTION: "Miễn giảm",
|
REDUCTION: 'Miễn giảm',
|
||||||
};
|
};
|
||||||
return labels[type] || type;
|
return labels[type] || type;
|
||||||
};
|
};
|
||||||
@@ -330,33 +525,33 @@ const processedEntries = computed(() => {
|
|||||||
|
|
||||||
const relevantEntries = paymentScheduleData.value.entry.filter(
|
const relevantEntries = paymentScheduleData.value.entry.filter(
|
||||||
(e) =>
|
(e) =>
|
||||||
(e.type === "PAYMENT" && e.penalty_added_to_entry !== undefined) ||
|
(e.type === 'PAYMENT' && e.penalty_added_to_entry !== undefined) ||
|
||||||
e.type === "REDUCTION"
|
e.type === 'REDUCTION',
|
||||||
);
|
);
|
||||||
|
|
||||||
relevantEntries.sort((a, b) => new Date(a.date) - new Date(b.date));
|
relevantEntries.sort((a, b) => new Date(a.date) - new Date(b.date));
|
||||||
|
|
||||||
let currentPrincipal = Number(paymentScheduleData.value.amount || 0);
|
let currentPrincipal = Number(paymentScheduleData.value.amount || 0);
|
||||||
let totalPenaltyAccumulated = 0;
|
let totalPenaltyAccumulated = 0;
|
||||||
let totalPenaltyPaid = 0;
|
let totalPenaltyPaid = 0;
|
||||||
let totalPenaltyReduce = 0;
|
let totalPenaltyReduce = 0;
|
||||||
let lastDate = null; // null = chưa có lần trả nào
|
let lastDate = null; // null = chưa có lần trả nào
|
||||||
const toDate = paymentScheduleData.value.to_date;
|
const toDate = paymentScheduleData.value.to_date;
|
||||||
|
|
||||||
const result = [];
|
const result = [];
|
||||||
|
|
||||||
relevantEntries.forEach((entry) => {
|
relevantEntries.forEach((entry) => {
|
||||||
const entryDate = dayjs(entry.date);
|
const entryDate = dayjs(entry.date);
|
||||||
|
|
||||||
if (entry.type === "PAYMENT") {
|
if (entry.type === 'PAYMENT') {
|
||||||
const penaltyThisPeriod = Number(entry.penalty_added_to_entry || 0);
|
const penaltyThisPeriod = Number(entry.penalty_added_to_entry || 0);
|
||||||
totalPenaltyAccumulated += penaltyThisPeriod;
|
totalPenaltyAccumulated += penaltyThisPeriod;
|
||||||
|
|
||||||
const principalPaid = Number(entry.principal || 0);
|
const principalPaid = Number(entry.principal || 0);
|
||||||
const penaltyPaid = Number(entry.penalty || 0);
|
const penaltyPaid = Number(entry.penalty || 0);
|
||||||
currentPrincipal -= principalPaid;
|
currentPrincipal -= principalPaid;
|
||||||
if (currentPrincipal < 0) currentPrincipal = 0;
|
if (currentPrincipal < 0) currentPrincipal = 0;
|
||||||
totalPenaltyPaid += penaltyPaid;
|
totalPenaltyPaid += penaltyPaid;
|
||||||
|
|
||||||
// last_event = max(to_date, lastDate) — khớp với logic backend
|
// last_event = max(to_date, lastDate) — khớp với logic backend
|
||||||
// Nếu chưa có lần trả nào: dùng to_date
|
// Nếu chưa có lần trả nào: dùng to_date
|
||||||
@@ -365,36 +560,44 @@ const processedEntries = computed(() => {
|
|||||||
const lastEventDate = lastDate
|
const lastEventDate = lastDate
|
||||||
? dayjs(Math.max(dayjs(toDate).valueOf(), dayjs(lastDate).valueOf()))
|
? dayjs(Math.max(dayjs(toDate).valueOf(), dayjs(lastDate).valueOf()))
|
||||||
: dayjs(toDate);
|
: dayjs(toDate);
|
||||||
const days = Math.max(0, entryDate.diff(lastEventDate, "day"));
|
const days = Math.max(0, entryDate.diff(lastEventDate, 'day'));
|
||||||
|
|
||||||
lastDate = entry.date; // cập nhật sau khi đã tính
|
lastDate = entry.date; // cập nhật sau khi đã tính
|
||||||
|
|
||||||
result.push({
|
result.push({
|
||||||
entry,
|
entry,
|
||||||
isReduction: false,
|
isReduction: false,
|
||||||
principalRemain: Number(entry.amount_remain_after_allocation || 0),
|
principalRemain: Number(entry.amount_remain_after_allocation || 0),
|
||||||
principalBefore: Number(entry.amount_remain_after_allocation || 0) + principalPaid,
|
principalBefore:
|
||||||
|
Number(entry.amount_remain_after_allocation || 0) + principalPaid,
|
||||||
penaltyAccumulated: totalPenaltyAccumulated,
|
penaltyAccumulated: totalPenaltyAccumulated,
|
||||||
penaltyThisPeriod,
|
penaltyThisPeriod,
|
||||||
penaltyRemain: Math.max(0, totalPenaltyAccumulated - totalPenaltyPaid - totalPenaltyReduce),
|
penaltyRemain: Math.max(
|
||||||
rate: Number(entry.DAILY_PENALTY_RATE || 0) * 100,
|
0,
|
||||||
totalDebt: Number(entry.amount_remain_after_allocation || 0) + penaltyThisPeriod,
|
totalPenaltyAccumulated - totalPenaltyPaid - totalPenaltyReduce,
|
||||||
|
),
|
||||||
|
rate: Number(entry.DAILY_PENALTY_RATE || 0) * 100,
|
||||||
|
totalDebt:
|
||||||
|
Number(entry.amount_remain_after_allocation || 0) + penaltyThisPeriod,
|
||||||
penaltyDetail: {
|
penaltyDetail: {
|
||||||
from: lastEventDate.format("DD/MM/YYYY"),
|
from: lastEventDate.format('DD/MM/YYYY'),
|
||||||
to: entryDate.subtract(1, "day").format("DD/MM/YYYY"),
|
to: entryDate.subtract(1, 'day').format('DD/MM/YYYY'),
|
||||||
days,
|
days,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else if (entry.type === "REDUCTION") {
|
} else if (entry.type === 'REDUCTION') {
|
||||||
const reduceAmount = Number(entry.amount || 0);
|
const reduceAmount = Number(entry.amount || 0);
|
||||||
totalPenaltyReduce += reduceAmount;
|
totalPenaltyReduce += reduceAmount;
|
||||||
// REDUCTION không dịch chuyển lastDate
|
// REDUCTION không dịch chuyển lastDate
|
||||||
|
|
||||||
result.push({
|
result.push({
|
||||||
entry,
|
entry,
|
||||||
isReduction: true,
|
isReduction: true,
|
||||||
reduceAmount,
|
reduceAmount,
|
||||||
penaltyRemain: Math.max(0, totalPenaltyAccumulated - totalPenaltyPaid - totalPenaltyReduce),
|
penaltyRemain: Math.max(
|
||||||
|
0,
|
||||||
|
totalPenaltyAccumulated - totalPenaltyPaid - totalPenaltyReduce,
|
||||||
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -406,7 +609,7 @@ const processedEntries = computed(() => {
|
|||||||
const latestEntry = computed(() => {
|
const latestEntry = computed(() => {
|
||||||
if (!paymentScheduleData.value?.entry?.length) return null;
|
if (!paymentScheduleData.value?.entry?.length) return null;
|
||||||
const paymentEntries = paymentScheduleData.value.entry.filter(
|
const paymentEntries = paymentScheduleData.value.entry.filter(
|
||||||
(e) => e.type === "PAYMENT" && e.penalty_to_this_entry !== undefined
|
(e) => e.type === 'PAYMENT' && e.penalty_to_this_entry !== undefined,
|
||||||
);
|
);
|
||||||
if (paymentEntries.length === 0) return null;
|
if (paymentEntries.length === 0) return null;
|
||||||
return paymentEntries[paymentEntries.length - 1];
|
return paymentEntries[paymentEntries.length - 1];
|
||||||
@@ -419,39 +622,59 @@ const hasUnpaidDebt = computed(() => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const latestPenaltyToThisEntry = computed(() => latestEntry.value?.penalty_to_this_entry || 0);
|
const latestPenaltyToThisEntry = computed(
|
||||||
|
() => latestEntry.value?.penalty_to_this_entry || 0,
|
||||||
|
);
|
||||||
|
|
||||||
const latestAdditionalPenalty = computed(() => {
|
const latestAdditionalPenalty = computed(() => {
|
||||||
return paymentScheduleData.value?.penalty_amount - (latestEntry.value?.penalty_to_this_entry || 0) || 0;
|
return (
|
||||||
|
paymentScheduleData.value?.penalty_amount -
|
||||||
|
(latestEntry.value?.penalty_to_this_entry || 0) || 0
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const latestTotalPenalty = computed(() => latestPenaltyToThisEntry.value + latestAdditionalPenalty.value);
|
const latestTotalPenalty = computed(
|
||||||
|
() => latestPenaltyToThisEntry.value + latestAdditionalPenalty.value,
|
||||||
|
);
|
||||||
|
|
||||||
const latestEntryCode = computed(() => latestEntry.value?.code || "-");
|
const latestEntryCode = computed(() => latestEntry.value?.code || '-');
|
||||||
|
|
||||||
const latestEntryDate = computed(() => {
|
const latestEntryDate = computed(() => {
|
||||||
return latestEntry.value?.date ? formatDate(latestEntry.value.date) : "-";
|
return latestEntry.value?.date ? formatDate(latestEntry.value.date) : '-';
|
||||||
});
|
});
|
||||||
|
|
||||||
const fetchPaymentScheduleData = async () => {
|
const fetchPaymentScheduleData = async () => {
|
||||||
loadingData.value = true;
|
loadingData.value = true;
|
||||||
try {
|
try {
|
||||||
const data = await $getdata("payment_schedule", { id: props.scheduleItemId }, undefined, true);
|
const data = await $getdata(
|
||||||
const ruleData = await $getdata("bizsetting", { code: "rule" }, undefined, true);
|
'payment_schedule',
|
||||||
|
{ id: props.scheduleItemId },
|
||||||
|
undefined,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
const ruleData = await $getdata(
|
||||||
|
'payment_schedule',
|
||||||
|
{ code: 'rule' },
|
||||||
|
undefined,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
rule.value =
|
rule.value =
|
||||||
ruleData?.detail === "fee-principal"
|
ruleData?.detail === 'fee-principal'
|
||||||
? "Lãi phạt quá hạn trước - Gốc sau"
|
? 'Lãi phạt quá hạn trước - Gốc sau'
|
||||||
: "Tiền gốc trước - Lãi phạt quá hạn sau";
|
: 'Tiền gốc trước - Lãi phạt quá hạn sau';
|
||||||
|
|
||||||
paymentScheduleData.value = data;
|
paymentScheduleData.value = data;
|
||||||
if (data?.link) invoiceData.value.link = data.link;
|
if (data?.link) invoiceData.value.link = data.link;
|
||||||
if (data?.ref_code) invoiceData.value.ref_code = data.ref_code;
|
if (data?.ref_code) invoiceData.value.ref_code = data.ref_code;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Error fetching payment schedule data:", e);
|
console.error('Error fetching payment schedule data:', e);
|
||||||
$snackbar(
|
$snackbar(
|
||||||
isVietnamese.value ? "Không thể tải thông tin công nợ." : "Failed to load payment schedule information.",
|
isVietnamese.value
|
||||||
"Lỗi", "Error"
|
? 'Không thể tải thông tin công nợ.'
|
||||||
|
: 'Failed to load payment schedule information.',
|
||||||
|
'Lỗi',
|
||||||
|
'Error',
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
loadingData.value = false;
|
loadingData.value = false;
|
||||||
@@ -462,17 +685,23 @@ const getPenalty = async () => {
|
|||||||
isLoading.value = true;
|
isLoading.value = true;
|
||||||
const target_item = paymentScheduleData.value;
|
const target_item = paymentScheduleData.value;
|
||||||
const workflowPayload = {
|
const workflowPayload = {
|
||||||
workflow_code: "CALCULATE_LATE_PAYMENT_PENALTY",
|
workflow_code: 'CALCULATE_LATE_PAYMENT_PENALTY',
|
||||||
trigger: "create",
|
trigger: 'create',
|
||||||
target_item,
|
target_item,
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
const response = await $insertapi("workflow", workflowPayload, undefined, false);
|
const response = await $insertapi(
|
||||||
if (response === "error" || !response?.success) throw new Error("Calculate penalty failed");
|
'workflow',
|
||||||
$snackbar("Tính lãi thành công!", "Thành công", "Success");
|
workflowPayload,
|
||||||
|
undefined,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
if (response === 'error' || !response?.success)
|
||||||
|
throw new Error('Calculate penalty failed');
|
||||||
|
$snackbar('Tính lãi thành công!', 'Thành công', 'Success');
|
||||||
await fetchPaymentScheduleData();
|
await fetchPaymentScheduleData();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
$snackbar("Có lỗi xảy ra khi tính lãi.", "Lỗi", "Error");
|
$snackbar('Có lỗi xảy ra khi tính lãi.', 'Lỗi', 'Error');
|
||||||
} finally {
|
} finally {
|
||||||
isLoading.value = false;
|
isLoading.value = false;
|
||||||
}
|
}
|
||||||
@@ -481,29 +710,43 @@ const getPenalty = async () => {
|
|||||||
const handleUpdateInvoice = async () => {
|
const handleUpdateInvoice = async () => {
|
||||||
if (!invoiceData.value.link || !invoiceData.value.ref_code) {
|
if (!invoiceData.value.link || !invoiceData.value.ref_code) {
|
||||||
$snackbar(
|
$snackbar(
|
||||||
isVietnamese.value ? "Vui lòng nhập đầy đủ link và mã xác thực" : "Please enter both link and reference code",
|
isVietnamese.value
|
||||||
"Cảnh báo", "Warning"
|
? 'Vui lòng nhập đầy đủ link và mã xác thực'
|
||||||
|
: 'Please enter both link and reference code',
|
||||||
|
'Cảnh báo',
|
||||||
|
'Warning',
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
isUpdatingInvoice.value = true;
|
isUpdatingInvoice.value = true;
|
||||||
try {
|
try {
|
||||||
const response = await $patchapi(
|
const response = await $patchapi(
|
||||||
"payment_schedule",
|
'payment_schedule',
|
||||||
{ id: props.scheduleItemId, link: invoiceData.value.link, ref_code: invoiceData.value.ref_code },
|
{
|
||||||
undefined, false
|
id: props.scheduleItemId,
|
||||||
|
link: invoiceData.value.link,
|
||||||
|
ref_code: invoiceData.value.ref_code,
|
||||||
|
},
|
||||||
|
undefined,
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
if (response === "error" || !response) throw new Error("Update failed");
|
if (response === 'error' || !response) throw new Error('Update failed');
|
||||||
$snackbar(
|
$snackbar(
|
||||||
isVietnamese.value ? "Cập nhật hóa đơn thành công!" : "Invoice updated successfully!",
|
isVietnamese.value
|
||||||
"Thành công", "Success"
|
? 'Cập nhật hóa đơn thành công!'
|
||||||
|
: 'Invoice updated successfully!',
|
||||||
|
'Thành công',
|
||||||
|
'Success',
|
||||||
);
|
);
|
||||||
await fetchPaymentScheduleData();
|
await fetchPaymentScheduleData();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error updating invoice:", error);
|
console.error('Error updating invoice:', error);
|
||||||
$snackbar(
|
$snackbar(
|
||||||
isVietnamese.value ? "Có lỗi xảy ra khi cập nhật hóa đơn" : "Error updating invoice",
|
isVietnamese.value
|
||||||
"Lỗi", "Error"
|
? 'Có lỗi xảy ra khi cập nhật hóa đơn'
|
||||||
|
: 'Error updating invoice',
|
||||||
|
'Lỗi',
|
||||||
|
'Error',
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
isUpdatingInvoice.value = false;
|
isUpdatingInvoice.value = false;
|
||||||
@@ -511,30 +754,31 @@ const handleUpdateInvoice = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const resetInvoiceData = () => {
|
const resetInvoiceData = () => {
|
||||||
invoiceData.value = { link: "", ref_code: "" };
|
invoiceData.value = { link: '', ref_code: '' };
|
||||||
};
|
};
|
||||||
|
|
||||||
function openEntryDetailModal(entry) {
|
function openEntryDetailModal(entry) {
|
||||||
if (!entry.code) return;
|
if (!entry.code) return;
|
||||||
showModal.value = {
|
showModal.value = {
|
||||||
component: "accounting/InternalEntry",
|
component: 'accounting/InternalEntry',
|
||||||
title: `Chi tiết bút toán: ${entry.code}`,
|
title: `Chi tiết bút toán: ${entry.code}`,
|
||||||
height: "500px",
|
height: '500px',
|
||||||
width: "80%",
|
width: '80%',
|
||||||
vbind: { row: { code: entry.code } },
|
vbind: { row: { code: entry.code } },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleViewEmail() {
|
async function handleViewEmail() {
|
||||||
const emailTemplate = await $getdata(
|
const emailTemplate = await $getdata(
|
||||||
"emailtemplate",
|
'emailtemplate',
|
||||||
{ name: "Mail Thông báo đến hạn thanh toán" },
|
{ name: 'Mail Thông báo đến hạn thanh toán' },
|
||||||
undefined, false
|
undefined,
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
showModalViewEmail.value = {
|
showModalViewEmail.value = {
|
||||||
component: "marketing/email/viewEmail/ViewEmail",
|
component: 'marketing/email/viewEmail/ViewEmail',
|
||||||
title: "Xem trước nội dung nhắc thanh toán",
|
title: 'Xem trước nội dung nhắc thanh toán',
|
||||||
width: "60%",
|
width: '60%',
|
||||||
vbind: {
|
vbind: {
|
||||||
idEmailTemplate: emailTemplate[0]?.id || null,
|
idEmailTemplate: emailTemplate[0]?.id || null,
|
||||||
scheduleItemId: props.scheduleItemId,
|
scheduleItemId: props.scheduleItemId,
|
||||||
@@ -543,10 +787,14 @@ async function handleViewEmail() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleModalClose = () => { showModal.value = null; };
|
const handleModalClose = () => {
|
||||||
const handleConfirmDelete = () => { showModal.value = null; };
|
showModal.value = null;
|
||||||
|
};
|
||||||
|
const handleConfirmDelete = () => {
|
||||||
|
showModal.value = null;
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchPaymentScheduleData();
|
fetchPaymentScheduleData();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -3,13 +3,15 @@
|
|||||||
<div class="container is-fluid px-4">
|
<div class="container is-fluid px-4">
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
Bạn có chắc chắn muốn xóa lịch công nợ thời gian: {{ detail.time }} ngày - mẫu: [{{
|
Bạn có chắc chắn muốn xóa lịch công nợ thời gian:
|
||||||
detail.name?.toUpperCase()
|
{{ detail.time }} ngày - mẫu: [{{ detail.name?.toUpperCase() }}]
|
||||||
}}] không?
|
không?
|
||||||
</p>
|
</p>
|
||||||
<div class="action mt-3">
|
<div class="action mt-3">
|
||||||
<button class="button is-light" @click="handleCancel">Hủy</button>
|
<button class="button is-light" @click="handleCancel">Hủy</button>
|
||||||
<button class="button is-primary" @click="handleDeleteCart">Đồng ý</button>
|
<button class="button is-primary" @click="handleDeleteCart">
|
||||||
|
Đồng ý
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -19,7 +21,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
const { $snackbar, $deleteapi } = useNuxtApp();
|
const { $snackbar, $deleteapi } = useNuxtApp();
|
||||||
|
|
||||||
const emit = defineEmits(["close"]);
|
const emit = defineEmits(['close']);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
row: Object,
|
row: Object,
|
||||||
});
|
});
|
||||||
@@ -27,15 +29,15 @@ const props = defineProps({
|
|||||||
const detail = JSON.parse(props.row?.detail || null);
|
const detail = JSON.parse(props.row?.detail || null);
|
||||||
|
|
||||||
const handleDeleteCart = async () => {
|
const handleDeleteCart = async () => {
|
||||||
const res = await $deleteapi("bizsetting", props.row.id);
|
const res = await $deleteapi('user', props.row.id);
|
||||||
if (res) {
|
if (res) {
|
||||||
emit("close");
|
emit('close');
|
||||||
$snackbar("Xóa lịch công nợ thành công");
|
$snackbar('Xóa lịch công nợ thành công');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
emit("close");
|
emit('close');
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
class="has-background-white"
|
class="has-background-white"
|
||||||
data-theme="light"
|
data-theme="light"
|
||||||
lang="vi"
|
lang="vi"
|
||||||
v-if="authorized"
|
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
|
|
||||||
@@ -24,7 +23,7 @@ import { useRoute } from 'vue-router';
|
|||||||
import SnackBar from '@/components/snackbar/SnackBar.vue';
|
import SnackBar from '@/components/snackbar/SnackBar.vue';
|
||||||
import Modal from '@/components/Modal.vue';
|
import Modal from '@/components/Modal.vue';
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { $getdata, $requestLogin, $store } = useNuxtApp();
|
const { $getdata, $store } = useNuxtApp();
|
||||||
var authorized = ref(false);
|
var authorized = ref(false);
|
||||||
const snackbar = ref(undefined);
|
const snackbar = ref(undefined);
|
||||||
const showmodal = ref(undefined);
|
const showmodal = ref(undefined);
|
||||||
@@ -46,6 +45,7 @@ function getViewport() {
|
|||||||
$store.commit('viewport', viewport);
|
$store.commit('viewport', viewport);
|
||||||
}
|
}
|
||||||
async function checkRedirect() {
|
async function checkRedirect() {
|
||||||
|
console.log('checkRedirect');
|
||||||
if (route.query.username && route.query.token) {
|
if (route.query.username && route.query.token) {
|
||||||
let row = await $getdata(
|
let row = await $getdata(
|
||||||
'user',
|
'user',
|
||||||
@@ -57,12 +57,14 @@ async function checkRedirect() {
|
|||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
if (row === 'error' || row === undefined) $requestLogin();
|
if (row === 'error' || row === undefined) return;
|
||||||
else {
|
else {
|
||||||
row.token = route.query.token;
|
row.token = route.query.token;
|
||||||
$store.commit('login', row);
|
$store.commit('login', row);
|
||||||
}
|
}
|
||||||
} else if (!$store.login) return $requestLogin();
|
} else if (!$store.login) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
await checkLogin();
|
await checkLogin();
|
||||||
}
|
}
|
||||||
async function checkLogin() {
|
async function checkLogin() {
|
||||||
@@ -89,9 +91,9 @@ async function checkLogin() {
|
|||||||
undefined,
|
undefined,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
if (authtoken ? authtoken.expiry : true) return $requestLogin();
|
if (authtoken ? authtoken.expiry : true) return;
|
||||||
authorized.value = true;
|
authorized.value = true;
|
||||||
} else $requestLogin();
|
}
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
checkRedirect();
|
checkRedirect();
|
||||||
|
|||||||
@@ -603,13 +603,6 @@ export default defineNuxtPlugin(() => {
|
|||||||
url_detail: "data-detail/Menu_Choice/",
|
url_detail: "data-detail/Menu_Choice/",
|
||||||
params: {},
|
params: {},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "moneyunit",
|
|
||||||
commit: "moneyunit",
|
|
||||||
url: "data/Money_Unit/",
|
|
||||||
url_detail: "data-detail/Money_Unit/",
|
|
||||||
params: {},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "legaltype",
|
name: "legaltype",
|
||||||
commit: "legaltype",
|
commit: "legaltype",
|
||||||
@@ -847,6 +840,7 @@ export default defineNuxtPlugin(() => {
|
|||||||
store.commit("login", undefined);
|
store.commit("login", undefined);
|
||||||
store.commit("layersetting", undefined);
|
store.commit("layersetting", undefined);
|
||||||
store.commit("lastlegendfiltertab", "Giỏ hàng");
|
store.commit("lastlegendfiltertab", "Giỏ hàng");
|
||||||
|
console.log('requestLogin: redirect to login')
|
||||||
window.location.href = `https://${mode === "dev" ? "dev." : ""}login.utopia.com.vn/signin?module=${module}&link=${window.location.origin}`;
|
window.location.href = `https://${mode === "dev" ? "dev." : ""}login.utopia.com.vn/signin?module=${module}&link=${window.location.origin}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -876,6 +870,7 @@ export default defineNuxtPlugin(() => {
|
|||||||
|
|
||||||
// get data
|
// get data
|
||||||
const getapi = async function (list) {
|
const getapi = async function (list) {
|
||||||
|
console.trace('getapi')
|
||||||
try {
|
try {
|
||||||
let arr = list.map((v) => {
|
let arr = list.map((v) => {
|
||||||
let found = apis.find((api) => api.name === v.name);
|
let found = apis.find((api) => api.name === v.name);
|
||||||
@@ -898,7 +893,7 @@ export default defineNuxtPlugin(() => {
|
|||||||
});
|
});
|
||||||
return list;
|
return list;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return "error";
|
return "error";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ export default defineNuxtPlugin(async (nuxtApp) => {
|
|||||||
const { $getapi, $readyapi } = useNuxtApp()
|
const { $getapi, $readyapi } = useNuxtApp()
|
||||||
let connlist = $readyapi(['moneyunit', 'datatype', 'filterchoice', 'colorchoice', 'textalign', 'placement', 'colorscheme',
|
let connlist = $readyapi(['moneyunit', 'datatype', 'filterchoice', 'colorchoice', 'textalign', 'placement', 'colorscheme',
|
||||||
'filtertype', 'sorttype', 'tablesetting', 'settingchoice', 'sharechoice', 'menuchoice', 'settingtype', 'settingclass',
|
'filtertype', 'sorttype', 'tablesetting', 'settingchoice', 'sharechoice', 'menuchoice', 'settingtype', 'settingclass',
|
||||||
'common', 'sex', 'legaltype', 'cart'])
|
'sex', 'legaltype', 'cart'])
|
||||||
let filter = connlist.filter(v=>!v.ready)
|
let filter = connlist.filter(v=>!v.ready)
|
||||||
if(filter.length>0) await $getapi(filter)
|
if(filter.length>0) await $getapi(filter)
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user