This commit is contained in:
Viet An
2026-05-07 15:01:09 +07:00
parent 56cfcd09bf
commit ad2d1fbfb6
31 changed files with 356 additions and 367 deletions

View File

@@ -129,12 +129,14 @@ const doClick = function (e) {
}; };
onMounted(() => { onMounted(() => {
document.documentElement.classList.add("is-clipped"); if (Object.values(props).some((x) => isNotNil(x))) {
window.addEventListener("keydown", (e) => { document.documentElement.classList.add("is-clipped");
if (e.key === "Escape") closeModal(); window.addEventListener("keydown", (e) => {
}); if (e.key === "Escape") closeModal();
const collection = document.getElementsByClassName("modal-background"); });
count = collection.length; const collection = document.getElementsByClassName("modal-background");
count = collection.length;
}
}); });
onUnmounted(() => { onUnmounted(() => {

View File

@@ -41,7 +41,7 @@
<div class="field"> <div class="field">
<label class="label">{{ $lang("open-date") }}:</label> <label class="label">{{ $lang("open-date") }}:</label>
<div class="control"> <div class="control">
{{ `${$dayjs(record.create_time).format("DD/MM/YYYY")}` }} {{ `${$dayjs(record.create_time).format("L")}` }}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -407,7 +407,7 @@ async function loadData() {
remainingTTTHNV = Math.max(0, remainingTTTHNV); remainingTTTHNV = Math.max(0, remainingTTTHNV);
return { return {
to_date: sch.to_date ? $dayjs(sch.to_date).format("DD/MM/YYYY") : "—", to_date: sch.to_date ? $dayjs(sch.to_date).format("L") : "—",
amount: scheduleAmount, amount: scheduleAmount,
luy_ke_sang_dot: luyKeSangDot, luy_ke_sang_dot: luyKeSangDot,
thuc_thanh_toan: thucThanhToan, thuc_thanh_toan: thucThanhToan,
@@ -433,7 +433,7 @@ async function loadData() {
customer_code: txn.customer__code || "", customer_code: txn.customer__code || "",
customer_name: txn.customer__fullname || "", customer_name: txn.customer__fullname || "",
trade_code: txn.product__trade_code || txn.code || "", trade_code: txn.product__trade_code || txn.code || "",
contract_date: txn.date ? $dayjs(txn.date).format("DD/MM/YYYY") : "—", contract_date: txn.date ? $dayjs(txn.date).format("L") : "—",
contract_date_raw: txn.date, contract_date_raw: txn.date,
sale_price: salePriceNum, sale_price: salePriceNum,
ttthnv_paid: ttthnvPaid, ttthnv_paid: ttthnvPaid,

View File

@@ -37,7 +37,7 @@
<div class="field"> <div class="field">
<label class="label">Ngày hạch toán:</label> <label class="label">Ngày hạch toán:</label>
<div class="control"> <div class="control">
{{ $dayjs(record.date).format("DD/MM/YYYY") }} {{ $dayjs(record.date).format("L") }}
</div> </div>
</div> </div>
</div> </div>
@@ -102,7 +102,7 @@
<div class="field"> <div class="field">
<label class="label">{{ $lang("time") }}:</label> <label class="label">{{ $lang("time") }}:</label>
<div class="control"> <div class="control">
{{ `${$dayjs(record.create_time).format("DD/MM/YYYY")}` }} {{ `${$dayjs(record.create_time).format("L")}` }}
</div> </div>
</div> </div>
</div> </div>
@@ -209,7 +209,7 @@
> >
</td> </td>
<td class="has-text-centered"> <td class="has-text-centered">
{{ $dayjs(item.date).format("DD/MM/YYYY HH:mm:ss") }} {{ $dayjs(item.date).format("L HH:mm:ss") }}
</td> </td>
</tr> </tr>
</tbody> </tbody>

View File

@@ -77,7 +77,7 @@
</p> </p>
<p class="is-size-7 has-text-white-bis"> <p class="is-size-7 has-text-white-bis">
{{ $formatFileSize(file.file__size) }} {{ $formatFileSize(file.file__size) }}
{{ $dayjs(file.create_time).format("DD/MM/YYYY HH:mm") }} {{ $dayjs(file.create_time).format("L HH:mm") }}
</p> </p>
</div> </div>

View File

@@ -853,8 +853,8 @@ export default {
originalCalculatedAmount: originalAmount, originalCalculatedAmount: originalAmount,
discountAmount: earlyDetail.discountAmount, discountAmount: earlyDetail.discountAmount,
netAmount: earlyDetail.netAmount, netAmount: earlyDetail.netAmount,
actualDueDate: this.calculationStartDate.format("DD/MM/YYYY"), actualDueDate: this.calculationStartDate.format("L"),
dueDate: plan.days > 0 ? this.calculationStartDate.add(plan.days, "day").format("DD/MM/YYYY") : null, dueDate: plan.days > 0 ? this.calculationStartDate.add(plan.days, "day").format("L") : null,
displayValue: plan.type === 1 ? `${plan.value}%` : this.$numtoString(plan.value), displayValue: plan.type === 1 ? `${plan.value}%` : this.$numtoString(plan.value),
}; };
} else { } else {
@@ -865,7 +865,7 @@ export default {
discountAmount: 0, discountAmount: 0,
netAmount: originalAmount, netAmount: originalAmount,
actualDueDate: null, actualDueDate: null,
dueDate: plan.days > 0 ? this.calculationStartDate.add(plan.days, "day").format("DD/MM/YYYY") : null, dueDate: plan.days > 0 ? this.calculationStartDate.add(plan.days, "day").format("L") : null,
displayValue: plan.type === 1 ? `${plan.value}%` : this.$numtoString(plan.value), displayValue: plan.type === 1 ? `${plan.value}%` : this.$numtoString(plan.value),
}; };
} }
@@ -891,7 +891,7 @@ export default {
const daysDiff = plan.days || 0; const daysDiff = plan.days || 0;
if (daysDiff > 0) { if (daysDiff > 0) {
const dueDateObj = this.calculationStartDate.add(daysDiff, "day"); const dueDateObj = this.calculationStartDate.add(daysDiff, "day");
dueDate = dueDateObj.format("DD/MM/YYYY"); dueDate = dueDateObj.format("L");
} }
return { return {
@@ -927,7 +927,7 @@ export default {
isEarlyPaymentMerged: true, isEarlyPaymentMerged: true,
calculatedAmount: this.totalEarlyPayment - (this.selectedPolicy.deposit || 0), calculatedAmount: this.totalEarlyPayment - (this.selectedPolicy.deposit || 0),
days: 0, days: 0,
dueDate: this.calculationStartDate.format("DD/MM/YYYY"), dueDate: this.calculationStartDate.format("L"),
payment_note: "Thanh toán sớm gộp", payment_note: "Thanh toán sớm gộp",
displayValue: "-", displayValue: "-",
isFirstPlan: true, isFirstPlan: true,
@@ -942,7 +942,7 @@ export default {
const daysDiff = plan.days || 0; const daysDiff = plan.days || 0;
if (daysDiff > 0) { if (daysDiff > 0) {
const dueDateObj = this.calculationStartDate.add(daysDiff, "day"); const dueDateObj = this.calculationStartDate.add(daysDiff, "day");
dueDate = dueDateObj.format("DD/MM/YYYY"); dueDate = dueDateObj.format("L");
} }
displayPlans.push({ displayPlans.push({
@@ -963,9 +963,7 @@ export default {
calculatedPlans() { calculatedPlans() {
if (this.isPrecalculated && this.paymentPlans && this.paymentPlans.length > 0) { if (this.isPrecalculated && this.paymentPlans && this.paymentPlans.length > 0) {
return this.paymentPlans.map((plan, index) => { return this.paymentPlans.map((plan, index) => {
const dueDate = plan.due_days const dueDate = plan.due_days ? this.calculationStartDate.add(plan.due_days, "day").format("L") : null;
? this.calculationStartDate.add(plan.due_days, "day").format("DD/MM/YYYY")
: null;
return { return {
...plan, ...plan,
displayCycle: plan.cycle || index + 1, displayCycle: plan.cycle || index + 1,
@@ -1039,7 +1037,7 @@ export default {
return this.enableEarlyPayment; return this.enableEarlyPayment;
}, },
formatDate(date) { formatDate(date) {
return dayjs(date).format("DD/MM/YYYY"); return dayjs(date).format("L");
}, },
handleEarlyPaymentToggle() { handleEarlyPaymentToggle() {

View File

@@ -721,7 +721,7 @@ const totalPaid = computed(() => {
const formatDate = (date) => { const formatDate = (date) => {
if (!date) return "-"; if (!date) return "-";
return dayjs(date).format("DD/MM/YYYY"); return dayjs(date).format("L");
}; };
</script> </script>

View File

@@ -1195,7 +1195,7 @@ function handleContractUpdated(eventData) {
function formatDate(dateString) { function formatDate(dateString) {
if (!dateString) return "-"; if (!dateString) return "-";
return dayjs(dateString).format("DD/MM/YYYY"); return dayjs(dateString).format("L");
} }
function showCustomerDetails() { function showCustomerDetails() {

View File

@@ -69,7 +69,7 @@
<div class="field"> <div class="field">
<label class="label">Ngày cấp</label> <label class="label">Ngày cấp</label>
<div class="control"> <div class="control">
{{ record.issued_date ? $dayjs(record.issued_date).format("DD/MM/YYYY") : "/" }} {{ record.issued_date ? $dayjs(record.issued_date).format("L") : "/" }}
</div> </div>
</div> </div>
</div> </div>
@@ -129,10 +129,7 @@
<div class="field"> <div class="field">
<label class="label">Thời gian tạo</label> <label class="label">Thời gian tạo</label>
<div class="control"> <div class="control">
<span <span>{{ $dayjs(record.create_time).format("L") }} {{ $dayjs(record.create_time).format("HH:mm") }}</span>
>{{ $dayjs(record.create_time).format("DD/MM/YYYY") }}
{{ $dayjs(record.create_time).format("HH:mm") }}</span
>
</div> </div>
</div> </div>
</div> </div>
@@ -153,7 +150,7 @@
<label class="label">Thời gian cập nhật</label> <label class="label">Thời gian cập nhật</label>
<div class="control"> <div class="control">
<span> <span>
{{ record.update_time ? $dayjs(record.update_time).format("DD/MM/YYYY HH:mm") : "/" }} {{ record.update_time ? $dayjs(record.update_time).format("L HH:mm") : "/" }}
</span> </span>
</div> </div>
</div> </div>

View File

@@ -529,7 +529,7 @@ const formatCellValue = (value, field) => {
} }
if (field.format === "date") { if (field.format === "date") {
return $dayjs(value).format("DD/MM/YYYY"); return $dayjs(value).format("L");
} }
return value; return value;

View File

@@ -1,5 +1,5 @@
<template> <template>
<span :style="color ? `color:${color}` : ''">{{ $dayjs(date).format("DD/MM/YYYY") }}</span> <span :style="color ? `color:${color}` : ''">{{ $dayjs(date).format("L") }}</span>
</template> </template>
<script setup> <script setup>
const { $dayjs } = useNuxtApp(); const { $dayjs } = useNuxtApp();

View File

@@ -1,19 +1,13 @@
<template> <template>
<div <div
class="control has-icons-left" class="control has-icons-left"
:id="docid" ref="datepickerRoot"
> >
<div <div :class="['dropdown w-full', pos, focused && 'is-active']">
:class="`dropdown ${pos || ''} ${focused ? 'is-active' : ''}`" <div class="dropdown-trigger w-full">
style="width: 100%"
>
<div
class="dropdown-trigger"
style="width: 100%"
>
<input <input
:disabled="disabled" :disabled="disabled"
:class="`input ${error ? 'is-danger' : ''} ${disabled ? 'has-text-dark' : ''}`" :class="['input', error && 'is-danger', disabled && 'has-text-dark']"
type="text" type="text"
placeholder="DD/MM/YYYY" placeholder="DD/MM/YYYY"
maxlength="10" maxlength="10"
@@ -33,7 +27,7 @@
<PickDay <PickDay
v-bind="{ date, maxdate }" v-bind="{ date, maxdate }"
@date="selectDate" @date="selectDate"
></PickDay> />
</div> </div>
</div> </div>
</div> </div>
@@ -41,119 +35,131 @@
<Icon <Icon
name="material-symbols:calendar-today-outline-rounded" name="material-symbols:calendar-today-outline-rounded"
:size="21" :size="21"
class="has-text-grey" :class="focused ? 'has-text-primary' : 'has-text-grey'"
/> />
</span> </span>
</div> </div>
</template> </template>
<script> <script setup>
export default { const props = defineProps({
props: ["record", "attr", "position", "mindate", "maxdate", "disabled"], record: Object,
data() { attr: String,
return { position: String,
date: undefined, mindate: String,
show: undefined, maxdate: String,
error: false, disabled: Boolean,
focused: false, });
docid: this.$id(),
count1: 0, const emit = defineEmits(["date"]);
count2: 0, const { $id, $copy, $dayjs, $empty } = useNuxtApp();
pos: undefined,
}; const date = ref();
}, const show = ref();
created() { const error = ref(false);
this.getPos(); const focused = ref(false);
if (this.record) { const count1 = ref(0);
this.date = this.record[this.attr] ? this.$copy(this.record[this.attr]) : undefined; const count2 = ref(0);
if (this.date) this.show = this.$dayjs(this.date).format("DD/MM/YYYY"); const pos = ref();
const datepickerRoot = useTemplateRef("datepickerRoot");
function getPos() {
switch (props.position) {
case "is-top-left":
pos.value = "is-up is-left";
break;
case "is-top-right":
pos.value = "is-up is-right";
break;
case "is-bottom-left":
pos.value = "is-left";
break;
case "is-bottom-right":
pos.value = "is-right";
break;
}
}
function initializeDate() {
if (props.record) {
date.value = props.record[props.attr] ? $copy(props.record[props.attr]) : undefined;
if (date.value) show.value = $dayjs(date.value).format("L");
}
}
function pressEnter() {
checkDate();
if (!error.value) focused.value = false;
}
function setFocus() {
focused.value = true;
count1.value = 0;
count2.value = 0;
}
function lostFocus() {
setTimeout(() => {
if (focused.value && count1.value === 0) focused.value = false;
}, 200);
}
function processEvent(event) {
count2.value += 1;
const isClickInside = datepickerRoot.value.contains(event.target);
if (!isClickInside && focused.value) {
if (count2.value - 1 !== count1.value) {
focused.value = false;
count1.value = 0;
count2.value = 0;
} }
}
}
function doClick() {
count1.value += 1;
}
function selectDate(v) {
date.value = v;
show.value = $dayjs(v).format("L");
emit("date", date.value);
if (focused.value) focused.value = false;
count1.value = 0;
count2.value = 0;
}
function getDate(value) {
let v = value.replace(/\D/g, "").slice(0, 10);
if (v.length >= 5) {
return `${v.slice(0, 2)}/${v.slice(2, 4)}/${v.slice(4)}`;
} else if (v.length >= 3) {
return `${v.slice(0, 2)}/${v.slice(2)}`;
}
return v;
}
function checkDate() {
if (!focused.value) setFocus();
error.value = false;
date.value = undefined;
if ($empty(show.value)) return emit("date", null);
show.value = getDate(show.value);
let val = `${show.value.substring(6, 10)}-${show.value.substring(3, 5)}-${show.value.substring(0, 2)}`;
if ($dayjs(val, "YYYY-MM-DD", true).isValid()) {
date.value = val;
emit("date", date.value);
} else error.value = true;
}
onMounted(() => {
getPos();
initializeDate();
});
watch(
() => props.record,
() => {
initializeDate();
}, },
watch: { );
record: function (newVal) {
if (this.record) {
this.date = this.record[this.attr] ? this.$copy(this.record[this.attr]) : undefined;
if (this.date) this.show = this.$dayjs(this.date).format("DD/MM/YYYY");
}
},
},
methods: {
pressEnter() {
this.checkDate();
if (!this.error) this.focused = false;
},
setFocus() {
this.focused = true;
this.count1 = 0;
this.count2 = 0;
},
lostFocus() {
let self = this;
setTimeout(() => {
if (self.focused && self.count1 === 0) self.focused = false;
}, 200);
},
processEvent(event) {
var doc = document.getElementById(this.docid);
if (!doc) return;
this.count2 += 1;
var isClickInside = false;
isClickInside = doc.contains(event.target);
if (!isClickInside && this.focused) {
if (this.count2 - 1 !== this.count1) {
this.focused = false;
this.count1 = 0;
this.count2 = 0;
}
}
},
doClick() {
this.count1 += 1;
},
selectDate(v) {
this.date = v;
this.show = this.$dayjs(v).format("DD/MM/YYYY");
this.$emit("date", this.date);
if (this.focused) this.focused = false;
this.count1 = 0;
this.count2 = 0;
},
getDate(value) {
let v = value.replace(/\D/g, "").slice(0, 10);
if (v.length >= 5) {
return `${v.slice(0, 2)}/${v.slice(2, 4)}/${v.slice(4)}`;
} else if (v.length >= 3) {
return `${v.slice(0, 2)}/${v.slice(2)}`;
}
return v;
},
checkDate() {
if (!this.focused) this.setFocus();
this.error = false;
this.date = undefined;
if (this.$empty(this.show)) return this.$emit("date", null);
this.show = this.getDate(this.show);
let val = `${this.show.substring(6, 10)}-${this.show.substring(3, 5)}-${this.show.substring(0, 2)}`;
if (this.$dayjs(val, "YYYY-MM-DD", true).isValid()) {
this.date = val;
this.$emit("date", this.date);
} else this.error = true;
},
getPos() {
switch (this.position) {
case "is-top-left":
this.pos = "is-up is-left";
break;
case "is-top-right":
this.pos = "is-up is-right";
break;
case "is-bottom-left":
this.pos = "is-left";
break;
case "is-bottom-right":
this.pos = "is-right";
break;
}
},
},
};
</script> </script>

View File

@@ -86,7 +86,7 @@
<span <span
class="has-text-primary hyperlink" class="has-text-primary hyperlink"
@click="chooseToday()" @click="chooseToday()"
>{{ $dayjs(today).format("DD/MM/YYYY") }}</span >{{ $dayjs(today).format("L") }}</span
> >
</div> </div>
</template> </template>

View File

@@ -56,26 +56,26 @@
</div> </div>
</div> </div>
<div <div
:class="`columns is-mobile mx-0 mb-1 ${i === weeks.length - 1 ? 'mb-1' : ''}`"
v-for="(v, i) in weeks" v-for="(v, i) in weeks"
:key="i" :key="i"
:class="`columns is-mobile mx-0 mb-1 ${i === weeks.length - 1 ? 'mb-1' : ''}`"
> >
<div <div
class="column p-0 is-flex is-justify-content-center is-align-items-center"
style="width: 40px; height: 32px"
v-for="(m, h) in v.dates" v-for="(m, h) in v.dates"
:key="h" :key="h"
class="column p-0 is-flex is-justify-content-center is-align-items-center"
style="width: 40px; height: 32px"
> >
<span <span
class="fs-13 has-text-grey-80"
v-if="m.disable" v-if="m.disable"
class="fs-13 has-text-grey-80"
> >
{{ m.dayPrint }} {{ m.dayPrint }}
</span> </span>
<span <span
v-else
class="fs-13 is-clickable" class="fs-13 is-clickable"
@click="choose(m)" @click="choose(m)"
v-else
> >
<span <span
style="width: 25px; height: 25px" style="width: 25px; height: 25px"
@@ -96,36 +96,33 @@
<hr class="my-1" /> <hr class="my-1" />
<div class="mt-2 fs-14"> <div class="mt-2 fs-14">
<span class="ml-2">Hôm nay: </span> <span class="ml-2">Hôm nay: </span>
<a <a @click="chooseToday()">{{ $dayjs(today).format("L") }}</a>
class="has-text-primary"
@click="chooseToday()"
>{{ $dayjs(today).format("DD/MM/YYYY") }}</a
>
</div> </div>
</div> </div>
<PickMonth <PickMonth
v-else-if="type === 'months'" v-else-if="type === 'months'"
@month="selectMonth" @month="selectMonth"
></PickMonth> />
<PickYear <PickYear
v-else-if="type === 'years'" v-else-if="type === 'years'"
v-bind="{ year, month, action }" v-bind="{ year, month, action }"
@year="selectYear" @year="selectYear"
@caption="changeCaption" @caption="changeCaption"
></PickYear> />
</div> </div>
</template> </template>
<script setup> <script setup>
import PickMonth from "@/components/datepicker/PickMonth"; import PickMonth from "@/components/datepicker/PickMonth";
import PickYear from "@/components/datepicker/PickYear"; import PickYear from "@/components/datepicker/PickYear";
const { $id, $dayjs, $unique } = useNuxtApp(); const { $id, $dayjs, $unique } = useNuxtApp();
const emit = defineEmits(["date"]); const emit = defineEmits(["date"]);
var props = defineProps({ const props = defineProps({
date: String, date: String,
maxdate: String, maxdate: String,
}); });
var dates = []; const dates = ref([]);
var dateOfWeek = [ const dateOfWeek = [
{ id: 0, text: "CN" }, { id: 0, text: "CN" },
{ id: 1, text: "T2" }, { id: 1, text: "T2" },
{ id: 2, text: "T3" }, { id: 2, text: "T3" },
@@ -134,18 +131,19 @@ var dateOfWeek = [
{ id: 5, text: "T6" }, { id: 5, text: "T6" },
{ id: 6, text: "T7" }, { id: 6, text: "T7" },
]; ];
var weeks = ref([]); const weeks = ref([]);
var year = ref(undefined); const year = ref();
var month = undefined; let month;
var type = ref("days"); const type = ref("days");
var caption = ref(undefined); const caption = ref();
var action = ref(undefined); const action = ref();
var curdate = undefined; const curdate = ref();
var today = new Date(); const today = new Date();
function showDate() { function showDate() {
curdate = props.date ? props.date.replaceAll("-", "/") : undefined; curdate.value = props.date ? props.date.replaceAll("-", "/") : undefined;
year.value = $dayjs(curdate || today).year(); year.value = $dayjs(curdate.value || today).year();
month = $dayjs(curdate || today).month() + 1; month = $dayjs(curdate.value || today).month() + 1;
getDates(); getDates();
} }
function chooseToday() { function chooseToday() {
@@ -169,12 +167,12 @@ function selectYear(v) {
} }
function getDates() { function getDates() {
caption.value = undefined; caption.value = undefined;
dates = allDaysInMonth(year.value, month); dates.value = allDaysInMonth(year.value, month);
weeks.value = $unique(dates, ["week"]).map((v) => { weeks.value = $unique(dates.value, ["week"]).map((v) => {
return { week: v.week }; return { week: v.week };
}); });
weeks.value.map((v) => { weeks.value.map((v) => {
v.dates = dates.filter((x) => x.week === v.week); v.dates = dates.value.filter((x) => x.week === v.week);
}); });
} }
function nextMonth() { function nextMonth() {
@@ -248,7 +246,7 @@ showDate();
// change date // change date
watch( watch(
() => props.date, () => props.date,
(newVal, oldVal) => { () => {
showDate(); showDate();
}, },
); );

View File

@@ -1,19 +1,11 @@
<template> <template>
<div class="columns is-mobile is-multiline mx-0"> <div class="columns is-mobile is-multiline mx-0">
<span <span
v-for="month in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]"
:id="String(month)"
class="column has-text-centered is-4 is-clickable fs-14" class="column has-text-centered is-4 is-clickable fs-14"
v-for="v in months" @click="$emit('month', month)"
@click="$emit('month', v)" >Tháng {{ month }}
>Tháng {{ v }}</span </span>
>
</div> </div>
</template> </template>
<script>
export default {
data() {
return {
months: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
};
},
};
</script>

View File

@@ -1,65 +1,53 @@
<template> <template>
<div class="columns is-mobile is-multiline mx-0"> <div class="columns is-mobile is-multiline mx-0">
<span <span
v-for="(v, i) in years" v-for="(year, i) in years"
class="column is-4 has-text-centered is-clickable fs-14" :key="year"
:class="i === 0 || i === 11 ? 'has-text-grey-light' : ''" :class="['column is-4 has-text-centered is-clickable fs-14', (i === 0 || i === 11) && 'has-text-grey-light']"
@click="$emit('year', v)" @click="$emit('year', year)"
>{{ v }}</span
> >
{{ year }}
</span>
</div> </div>
</template> </template>
<script> <script setup>
export default { const props = defineProps({
props: ["year", "month", "action"], year: Number,
data() { month: Number,
return { action: Object,
years: [], });
};
const emit = defineEmits(["caption"]);
const years = ref(
Array.from({ length: 12 })
.fill(props.year)
.map((y, i) => y + i - 6),
);
emit("caption", `${years.value[1]} ${years.value[10]}`);
watch(
() => props.action,
(newVal) => {
if (newVal.name === "next") next();
if (newVal.name === "previous") previous();
}, },
created() { );
this.years = [this.year];
for (let i = 1; i < 7; i++) { watch(years, () => {
this.years.push(this.year + i); emit("caption", `${years.value[1]} ${years.value[10]}`);
this.years.push(this.year - i); });
}
this.years.sort(function (a, b) { function next() {
return a - b; const baseYear = years.value[11];
}); years.value = Array.from({ length: 12 })
this.years = this.years.slice(0, 12); .fill(baseYear)
this.$emit("caption", `${this.years[1]}-${this.years[10]}`); .map((y, i) => y + i - 6);
}, }
watch: {
action: function (newVal) { function previous() {
if (newVal.name === "next") this.next(); const baseYear = years.value[0];
if (newVal.name === "previous") this.previous(); years.value = Array.from({ length: 12 })
}, .fill(baseYear)
}, .map((y, i) => y + i - 6);
methods: { }
next() {
let year = this.years[this.years.length - 1];
this.years = [];
for (let i = 0; i < 12; i++) {
this.years.push(year + i);
}
this.years.sort(function (a, b) {
return a - b;
});
this.years = this.years.slice(0, 12);
this.$emit("caption", `${this.years[1]}-${this.years[10]}`);
},
previous() {
let year = this.years[0];
this.years = [];
for (let i = 0; i < 12; i++) {
this.years.push(year - i);
}
this.years.sort(function (a, b) {
return a - b;
});
this.years = this.years.slice(0, 12);
this.$emit("caption", `${this.years[1]}-${this.years[10]}`);
},
},
};
</script> </script>

View File

@@ -279,7 +279,7 @@ async function sendEmails() {
{ {
ref: paymentScheduleData[i].txn_detail__transaction__product, ref: paymentScheduleData[i].txn_detail__transaction__product,
user: $store.login.id, user: $store.login.id,
detail: `Đã gửi email thông báo nhắc nợ cho sản phẩm ${paymentScheduleData[i].txn_detail__transaction__product__trade_code} vào lúc ${$dayjs().format("HH:mm ngày DD/MM/YYYY")}.`, detail: `Đã gửi email thông báo nhắc nợ cho sản phẩm ${paymentScheduleData[i].txn_detail__transaction__product__trade_code} vào lúc ${$dayjs().format("HH:mm ngày L")}.`,
}, },
undefined, undefined,
false, false,

View File

@@ -278,7 +278,7 @@ async function sendEmails() {
{ {
ref: paymentScheduleData[i].txn_detail__transaction__product, ref: paymentScheduleData[i].txn_detail__transaction__product,
user: $store.login.id, user: $store.login.id,
detail: `Đã gửi email thông báo quá hạn cho sản phẩm ${paymentScheduleData[i].txn_detail__transaction__product__trade_code} vào lúc ${$dayjs().format("HH:mm ngày DD/MM/YYYY")}.`, detail: `Đã gửi email thông báo quá hạn cho sản phẩm ${paymentScheduleData[i].txn_detail__transaction__product__trade_code} vào lúc ${$dayjs().format("HH:mm ngày L")}.`,
}, },
undefined, undefined,
false, false,

View File

@@ -2,43 +2,48 @@
<div> <div>
<div class="field is-grouped"> <div class="field is-grouped">
<div <div
class="control is-expanded pr-3" class="control is-expanded"
v-html="content" v-html="content"
></div> ></div>
<div class="control"> <div class="control">
<SvgIcon v-bind="{ name: 'error.svg', type: 'danger', size: 24 }"></SvgIcon> <Icon
name="material-symbols:cancel-rounded"
:size="24"
class="has-text-danger"
/>
</div> </div>
</div> </div>
<p class="border-bottom mt-3 mb-5"></p> <div class="mt-3 mb-5"></div>
<div class="field is-grouped"> <div class="field is-grouped">
<div class="control is-expanded"> <div class="control is-expanded">
<button <button
class="button is-danger has-text-white" class="button is-danger"
@click="cancel()" @click="cancel()"
> >
Đóng Đóng
</button> </button>
</div> </div>
<div <div
class="control"
v-if="duration" v-if="duration"
class="control"
> >
<CountDown <CountDown
v-bind="{ duration: duration }" :duration="duration"
@close="cancel()" @close="cancel()"
></CountDown> />
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { useStore } from "@/stores/index"; const props = defineProps({
const store = useStore();
var props = defineProps({
content: String, content: String,
duration: Number, duration: Number,
}); });
const emit = defineEmits(["close"]);
function cancel() { function cancel() {
this.$emit("close"); emit("close");
} }
</script> </script>

View File

@@ -1,35 +1,37 @@
<template> <template>
<div> <div>
<p v-html="content"></p> <p v-html="content"></p>
<p class="border-bottom mt-3 mb-5"></p> <div class="mt-3 mb-5"></div>
<div class="field is-grouped"> <div class="field is-grouped">
<div class="control is-expanded"> <div class="control is-expanded">
<button <button
class="button is-dark" class="button is-light"
@click="cancel()" @click="cancel()"
> >
Đóng Đóng
</button> </button>
</div> </div>
<div <div
class="control"
v-if="duration" v-if="duration"
class="control"
> >
<CountDown <CountDown
v-bind="{ duration: duration }" :duration="duration"
@close="cancel()" @close="cancel()"
></CountDown> />
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script> <script setup>
export default { const props = defineProps({
props: ["content", "duration"], content: String,
methods: { duration: Number,
cancel() { });
this.$emit("close");
}, const emit = defineEmits(["close"]);
},
}; function cancel() {
emit("close");
}
</script> </script>

View File

@@ -2,14 +2,18 @@
<div> <div>
<div class="field is-grouped"> <div class="field is-grouped">
<div <div
class="control is-expanded pr-3" class="control is-expanded"
v-html="content" v-html="content"
></div> ></div>
<div class="control"> <div class="control">
<SvgIcon v-bind="{ name: 'check2.svg', type: 'primary', size: 24 }"></SvgIcon> <Icon
name="material-symbols:check-circle-rounded"
:size="24"
class="has-text-success"
/>
</div> </div>
</div> </div>
<p class="border-bottom mt-3 mb-5"></p> <div class="mt-3 mb-5"></div>
<div class="field is-grouped"> <div class="field is-grouped">
<div class="control is-expanded"> <div class="control is-expanded">
<button <button
@@ -20,24 +24,26 @@
</button> </button>
</div> </div>
<div <div
class="control"
v-if="duration" v-if="duration"
class="control"
> >
<CountDown <CountDown
v-bind="{ duration: duration }" :duration="duration"
@close="cancel()" @close="cancel()"
></CountDown> />
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script> <script setup>
export default { const props = defineProps({
props: ["content", "duration"], content: String,
methods: { duration: Number,
cancel() { });
this.$emit("close");
}, const emit = defineEmits(["close"]);
},
}; function cancel() {
emit("close");
}
</script> </script>

View File

@@ -1,3 +1,4 @@
<!-- extract logic to a composable -->
<template> <template>
<div> <div>
<div <div
@@ -10,6 +11,7 @@
> >
<input <input
class="file-input" class="file-input"
ref="file-input"
type="file" type="file"
:id="docid" :id="docid"
multiple multiple
@@ -50,9 +52,10 @@ const props = defineProps({
const emit = defineEmits(["files"]); const emit = defineEmits(["files"]);
const { $id, $snackbar, $upload } = useNuxtApp(); const { $id, $snackbar, $upload } = useNuxtApp();
const fileInput = useTemplateRef("file-input");
const vtype = props.type || ["image"]; const vtype = props.type || ["image"];
const files = ref(); const files = ref(); // files selected in <input>
const dataFiles = ref(); const dataFiles = ref(); // files returned by $upload
const showmodal = ref(); const showmodal = ref();
const docid = $id(); const docid = $id();
@@ -74,10 +77,9 @@ function getType(ext) {
} }
function doChange() { function doChange() {
if (fileInput.value.files.length === 0) return;
dataFiles.value = []; dataFiles.value = [];
const fileList = document.getElementById(docid).files; files.value = Array.from(fileInput.value.files);
files.value = Array.from(fileList);
if (files.value.length === 0) return;
// Xác định giá trị convert: "1" nếu convert được bật, "0" nếu không // Xác định giá trị convert: "1" nếu convert được bật, "0" nếu không
const convertValue = props.convert ? "1" : "0"; const convertValue = props.convert ? "1" : "0";
@@ -96,6 +98,7 @@ function doChange() {
dataFiles.value.push(file); dataFiles.value.push(file);
}); });
console.log("dataFiles.value", dataFiles.value);
showmodal.value = { showmodal.value = {
component: "media/UploadProgress", component: "media/UploadProgress",
title: "Upload files", title: "Upload files",
@@ -103,19 +106,14 @@ function doChange() {
height: "200px", height: "200px",
vbind: { files: dataFiles.value }, vbind: { files: dataFiles.value },
}; };
clearFileList();
}
function clearFileList() { fileInput.value.value = ""; // clear input
const fileInput = document.getElementById(docid);
const dt = new DataTransfer();
fileInput.files = dt.files;
} }
function getFiles(files) { function getFiles(files) {
emit("files", files); emit("files", files);
setTimeout(() => { // setTimeout(() => {
showmodal.value = undefined; // showmodal.value = undefined;
}, 3000); // }, 3000);
} }
</script> </script>

View File

@@ -41,44 +41,43 @@
</p> </p>
</div> </div>
</template> </template>
<script> <script setup>
export default { const props = defineProps({
props: ["files"], files: Array,
data() { });
return {
vfiles: this.$copy(this.files), const emit = defineEmits(["files", "modalevent"]);
data: [], const { $copy, $find, $insertapi } = useNuxtApp();
}; const vfiles = ref($copy(props.files));
}, const data = ref([]);
created() {
let found = this.$find(this.vfiles, { error: true }); const found = $find(vfiles.value, { error: true });
if (!found) this.upload(); if (!found) upload();
},
methods: { async function doUpload(v, i) {
async doUpload(v, i) { const file = props.files[i];
let file = this.files[i]; const rs = await $insertapi("upload", file.form, undefined, false);
let rs = await this.$insertapi("upload", file.form, undefined, false); v.status = rs === "error" ? "error" : "success";
v.status = rs === "error" ? "error" : "success"; vfiles.value[i] = v;
this.vfiles[i] = v; const obj = rs.rows[0];
let obj = rs.rows[0]; obj.source = file;
obj.source = file; data.value.push(obj);
this.data.push(obj); checkDone();
this.checkDone(); }
},
async upload() { async function upload() {
for (let i = 0; i < this.vfiles.length; i++) { for (let i = 0; i < vfiles.value.length; i++) {
let v = this.vfiles[i]; let v = vfiles.value[i];
v.status = "uploading"; v.status = "uploading";
await this.doUpload(v, i); await doUpload(v, i);
} }
}, }
checkDone() {
let found = this.vfiles.find((v) => !v.status || v.status === "uploading"); function checkDone() {
if (!found) { let found = vfiles.value.find((v) => !v.status || v.status === "uploading");
this.$emit("files", this.data); if (!found) {
this.$emit("modalevent", { name: "files", data: this.data }); emit("files", data.value);
} emit("modalevent", { name: "files", data: data.value });
}, }
}, }
};
</script> </script>

View File

@@ -269,7 +269,7 @@ const isUpdateValid = computed(() => {
const formatDate = (dateString) => { const formatDate = (dateString) => {
if (!dateString) return "-"; if (!dateString) return "-";
return dayjs(dateString).format("DD/MM/YYYY"); return dayjs(dateString).format("L");
}; };
const fetchPaymentScheduleData = async () => { const fetchPaymentScheduleData = async () => {

View File

@@ -42,7 +42,7 @@
<div class="field"> <div class="field">
<label class="label">{{ isVietnamese ? "Ngày bút toán" : "Date" }}</label> <label class="label">{{ isVietnamese ? "Ngày bút toán" : "Date" }}</label>
<div class="control"> <div class="control">
<span>{{ entry.date ? $dayjs(entry.date).format("DD/MM/YYYY") : "/" }}</span> <span>{{ entry.date ? $dayjs(entry.date).format("L") : "/" }}</span>
</div> </div>
</div> </div>
</div> </div>
@@ -207,7 +207,7 @@
<div class="field"> <div class="field">
<label class="label">{{ isVietnamese ? "Thời gian" : "Create Time" }}</label> <label class="label">{{ isVietnamese ? "Thời gian" : "Create Time" }}</label>
<div class="control"> <div class="control">
<span>{{ entry.create_time ? $dayjs(entry.create_time).format("DD/MM/YYYY HH:mm") : "/" }}</span> <span>{{ entry.create_time ? $dayjs(entry.create_time).format("L HH:mm") : "/" }}</span>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -367,7 +367,7 @@ 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("L");
}; };
const getEntryTypeLabel = (type) => { const getEntryTypeLabel = (type) => {
@@ -430,8 +430,8 @@ const processedEntries = computed(() => {
rate: Number(entry.DAILY_PENALTY_RATE || 0) * 100, rate: Number(entry.DAILY_PENALTY_RATE || 0) * 100,
totalDebt: Number(entry.amount_remain_after_allocation || 0) + penaltyThisPeriod, totalDebt: Number(entry.amount_remain_after_allocation || 0) + penaltyThisPeriod,
penaltyDetail: { penaltyDetail: {
from: lastEventDate.format("DD/MM/YYYY"), from: lastEventDate.format("L"),
to: entryDate.format("DD/MM/YYYY"), to: entryDate.format("L"),
days, days,
}, },
}); });

View File

@@ -80,7 +80,7 @@
<div class="field"> <div class="field">
<label class="label">{{ findLang("dob") }}</label> <label class="label">{{ findLang("dob") }}</label>
<div class="control"> <div class="control">
{{ record.dob ? $dayjs(record.dob).format("DD/MM/YYYY") : "/" }} {{ record.dob ? $dayjs(record.dob).format("L") : "/" }}
</div> </div>
</div> </div>
</div> </div>
@@ -112,7 +112,7 @@
<div class="field"> <div class="field">
<label class="label">{{ findLang("issued_date") }}</label> <label class="label">{{ findLang("issued_date") }}</label>
<div class="control"> <div class="control">
{{ record.issued_date ? $dayjs(record.issued_date).format("DD/MM/YYYY") : "/" }} {{ record.issued_date ? $dayjs(record.issued_date).format("L") : "/" }}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -412,7 +412,7 @@ export default {
this.coOwner = selectedPerson || null; this.coOwner = selectedPerson || null;
}, },
formatDate(date) { formatDate(date) {
return date ? dayjs(date).format("DD/MM/YYYY") : "-"; return date ? dayjs(date).format("L") : "-";
}, },
updateDueDate(newDate) { updateDueDate(newDate) {
this.editableDueDate = newDate; this.editableDueDate = newDate;

View File

@@ -212,15 +212,13 @@ async function handleFileUpload(uploadedFiles) {
> >
<p class="column is-3"> <p class="column is-3">
<span>Từ ngày: </span> <span>Từ ngày: </span>
<span class="has-text-weight-semibold">{{ <span class="has-text-weight-semibold">{{ txndetail.date ? $dayjs(txndetail.date).format("L") : "" }}</span>
txndetail.date ? $dayjs(txndetail.date).format("DD/MM/YYYY") : ""
}}</span>
</p> </p>
<p class="column is-3"> <p class="column is-3">
<span>Đến ngày: </span> <span>Đến ngày: </span>
<span class="has-text-weight-semibold">{{ <span class="has-text-weight-semibold">{{
txndetail.due_date ? $dayjs(txndetail.due_date).format("DD/MM/YYYY") : "" txndetail.due_date ? $dayjs(txndetail.due_date).format("L") : ""
}}</span> }}</span>
</p> </p>
<p class="column is-3"> <p class="column is-3">

View File

@@ -315,7 +315,7 @@
<div class="field"> <div class="field">
<label class="label">{{ data && findFieldName("issued_date")[lang] }}</label> <label class="label">{{ data && findFieldName("issued_date")[lang] }}</label>
<div class="control"> <div class="control">
{{ record.issued_date ? $dayjs(record.issued_date).format("DD/MM/YYYY") : "/" }} {{ record.issued_date ? $dayjs(record.issued_date).format("L") : "/" }}
</div> </div>
</div> </div>
</div> </div>
@@ -395,7 +395,7 @@
<div class="field"> <div class="field">
<label class="label">{{ data && findFieldName("create-time")[lang] }}</label> <label class="label">{{ data && findFieldName("create-time")[lang] }}</label>
<div class="control"> <div class="control">
<span>{{ $dayjs(transaction.create_time).format("DD/MM/YYYY HH:mm") }}</span> <span>{{ $dayjs(transaction.create_time).format("L HH:mm") }}</span>
</div> </div>
</div> </div>
</div> </div>
@@ -1201,7 +1201,7 @@ export default {
const postProductNotePayload = { const postProductNotePayload = {
ref: this.product.id, ref: this.product.id,
user: id, user: id,
detail: `${username} ${this.isVietnamese ? "khóa sản phẩm trong" : "locked product for"} ${this.lockDurationMinutes} ${this.isVietnamese ? "phút đến lúc" : "minutes until"} ${this.$dayjs(lockedUntilValue).format("HH:mm:ss - DD/MM/YYYY")}`, detail: `${username} ${this.isVietnamese ? "khóa sản phẩm trong" : "locked product for"} ${this.lockDurationMinutes} ${this.isVietnamese ? "phút đến lúc" : "minutes until"} ${this.$dayjs(lockedUntilValue).format("HH:mm:ss - L")}`,
}; };
try { try {

View File

@@ -40,7 +40,7 @@
>{{ isVietnamese ? "Thời gian tạo" : "Create time" }}<b class="ml-1 has-text-danger">*</b></label >{{ isVietnamese ? "Thời gian tạo" : "Create time" }}<b class="ml-1 has-text-danger">*</b></label
> >
<div class="control"> <div class="control">
{{ $dayjs(record.create_time).format("DD/MM/YYYY") }} {{ $dayjs(record.create_time).format("L") }}
</div> </div>
</div> </div>
</div> </div>