changes
This commit is contained in:
@@ -121,12 +121,12 @@
|
|||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import Avatarbox from "~/components/common/Avatarbox.vue";
|
import Avatarbox from "~/components/common/Avatarbox.vue";
|
||||||
import { watch } from "vue";
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const emit = defineEmits(["changeTab"]);
|
const emit = defineEmits(["changeTab"]);
|
||||||
const { $find, $filter, $store, $snackbar } = useNuxtApp();
|
const { $find, $filter, $store, $snackbar } = useNuxtApp();
|
||||||
const lang = ref($store.lang);
|
const lang = computed(() => $store.lang);
|
||||||
const menu = $filter($store.common, { category: "topmenu" });
|
const menu = $filter($store.common, { category: "topmenu" });
|
||||||
// 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)
|
||||||
@@ -148,7 +148,7 @@ const currentTab = ref(leftmenu[0]);
|
|||||||
const subTab = ref();
|
const subTab = ref();
|
||||||
const tabConfig = $find(menu, { code: "configuration" });
|
const tabConfig = $find(menu, { code: "configuration" });
|
||||||
const avatar = ref();
|
const avatar = ref();
|
||||||
const isAdmin = ref();
|
const isAdmin = computed(() => $store.login.type__code === "admin");
|
||||||
|
|
||||||
function toggleBurger() {
|
function toggleBurger() {
|
||||||
const target = document.getElementById("burger");
|
const target = document.getElementById("burger");
|
||||||
@@ -174,8 +174,8 @@ function changeTab(tab, subtab) {
|
|||||||
subTab.value = subtab;
|
subTab.value = subtab;
|
||||||
emit("changeTab", tab, subtab);
|
emit("changeTab", tab, subtab);
|
||||||
closeMenu();
|
closeMenu();
|
||||||
let query = subtab ? { tab: tab.code, subtab: subtab.code } : { tab: tab.code };
|
const query = subtab ? { tab: tab.code, subtab: subtab.code } : { tab: tab.code };
|
||||||
router.push({ query: query });
|
router.push({ query });
|
||||||
}
|
}
|
||||||
function openProfile() {
|
function openProfile() {
|
||||||
$store.commit("showmodal", {
|
$store.commit("showmodal", {
|
||||||
@@ -187,6 +187,7 @@ function openProfile() {
|
|||||||
}
|
}
|
||||||
const found = route.query.tab && $find(menu, { code: route.query.tab });
|
const found = route.query.tab && $find(menu, { code: route.query.tab });
|
||||||
if (found || currentTab.value) changeTab(found || currentTab.value);
|
if (found || currentTab.value) changeTab(found || currentTab.value);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (!$store.login) return;
|
if (!$store.login) return;
|
||||||
avatar.value = {
|
avatar.value = {
|
||||||
@@ -195,7 +196,6 @@ onMounted(() => {
|
|||||||
size: "two",
|
size: "two",
|
||||||
type: "findata",
|
type: "findata",
|
||||||
};
|
};
|
||||||
isAdmin.value = $store.login.type__code === "admin";
|
|
||||||
});
|
});
|
||||||
watch(
|
watch(
|
||||||
() => $store.login,
|
() => $store.login,
|
||||||
@@ -207,8 +207,6 @@ watch(
|
|||||||
size: "two",
|
size: "two",
|
||||||
type: "findata",
|
type: "findata",
|
||||||
};
|
};
|
||||||
isAdmin.value = $store.login.type__code === "admin";
|
|
||||||
lang.value = $store.lang;
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,26 +1,4 @@
|
|||||||
<!-- CountdownTimer.vue -->
|
|
||||||
<template>
|
|
||||||
<div class="countdown-wrapper">
|
|
||||||
<span
|
|
||||||
v-if="isExpired"
|
|
||||||
class="tag is-danger"
|
|
||||||
>
|
|
||||||
{{ isVietnamese ? "Hết giờ" : "Expired" }}
|
|
||||||
</span>
|
|
||||||
<span
|
|
||||||
v-else
|
|
||||||
class="tag"
|
|
||||||
:class="tagClass"
|
|
||||||
>
|
|
||||||
<span class="countdown-text">{{ formattedTime }}</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, watch, onMounted, onBeforeUnmount } from "vue";
|
|
||||||
import { useStore } from "~/stores/index";
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
dateValue: {
|
dateValue: {
|
||||||
type: [String, Date],
|
type: [String, Date],
|
||||||
@@ -48,6 +26,8 @@ let intervalId = null;
|
|||||||
const isVietnamese = computed(() => store.lang === "vi");
|
const isVietnamese = computed(() => store.lang === "vi");
|
||||||
|
|
||||||
const tagClass = computed(() => {
|
const tagClass = computed(() => {
|
||||||
|
if (isExpired) return "is-danger";
|
||||||
|
|
||||||
const totalSeconds =
|
const totalSeconds =
|
||||||
timeRemaining.value.days * 86400 +
|
timeRemaining.value.days * 86400 +
|
||||||
timeRemaining.value.hours * 3600 +
|
timeRemaining.value.hours * 3600 +
|
||||||
@@ -123,19 +103,15 @@ watch(
|
|||||||
{ deep: true },
|
{ deep: true },
|
||||||
);
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(startCountdown);
|
||||||
startCountdown();
|
|
||||||
});
|
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
if (intervalId) {
|
|
||||||
clearInterval(intervalId);
|
clearInterval(intervalId);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<template>
|
||||||
.countdown-wrapper {
|
<span :class="['tag', tagClass]">
|
||||||
display: inline-block;
|
{{ isExpired ? (isVietnamese ? "Hết giờ" : "Expired") : formattedTime }}
|
||||||
}
|
</span>
|
||||||
</style>
|
</template>
|
||||||
|
|||||||
@@ -1,82 +1,85 @@
|
|||||||
|
<script setup>
|
||||||
|
const props = defineProps(["row", "pagename"]);
|
||||||
|
const { $copyToClipboard } = useNuxtApp();
|
||||||
|
|
||||||
|
const phone = props.row.customer__phone || props.row.party__phone || props.row.phone;
|
||||||
|
const format = (s) => `${s.slice(0, 3)} ${s.slice(3, 6)} ${s.slice(6, 20)}`;
|
||||||
|
const text = format(phone);
|
||||||
|
const showmodal = ref();
|
||||||
|
|
||||||
|
function call() {
|
||||||
|
window.open(`tel:${phone}`);
|
||||||
|
}
|
||||||
|
function sms() {
|
||||||
|
window.open(`sms:${phone}`);
|
||||||
|
}
|
||||||
|
function openZalo() {
|
||||||
|
window.open(`https://zalo.me/${phone}`, "_blank");
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendSms() {
|
||||||
|
showmodal.value = {
|
||||||
|
component: "user/Sms",
|
||||||
|
title: "Nhắn tin SMS",
|
||||||
|
width: "50%",
|
||||||
|
height: "400px",
|
||||||
|
vbind: {
|
||||||
|
row: props.row,
|
||||||
|
pagename: props.pagename,
|
||||||
|
api: "customersms",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<p class="fsb-30">
|
<p class="is-flex is-gap-1 is-align-items-center">
|
||||||
|
<span class="is-size-4 font-bold">
|
||||||
{{ text }}
|
{{ text }}
|
||||||
<a
|
</span>
|
||||||
class="ml-3"
|
<button
|
||||||
@click="copy()"
|
class="button is-small is-light is-primary rounded-full"
|
||||||
|
@click="$copyToClipboard(phone)"
|
||||||
>
|
>
|
||||||
<SvgIcon v-bind="{ name: 'copy.svg', type: 'primary', size: 24 }"></SvgIcon>
|
<span class="icon">
|
||||||
</a>
|
<Icon
|
||||||
|
name="material-symbols:content-copy-outline-rounded"
|
||||||
|
:size="17"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
</p>
|
</p>
|
||||||
<p class="buttons mt-4">
|
<p class="buttons are-small mt-2">
|
||||||
<button
|
<button
|
||||||
class="button is-primary"
|
class="button is-primary"
|
||||||
@click="call()"
|
@click="call"
|
||||||
>
|
>
|
||||||
Call
|
<span class="icon">
|
||||||
|
<Icon
|
||||||
|
name="material-symbols:call-outline-rounded"
|
||||||
|
:size="18"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span>Call</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="button is-primary"
|
class="button"
|
||||||
@click="sms()"
|
@click="sms"
|
||||||
>
|
>
|
||||||
SMS
|
SMS
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="button is-primary"
|
class="button"
|
||||||
@click="openZalo()"
|
@click="openZalo"
|
||||||
>
|
>
|
||||||
Zalo
|
Zalo
|
||||||
</button>
|
</button>
|
||||||
</p>
|
</p>
|
||||||
<Modal
|
<Modal
|
||||||
@close="showmodal = undefined"
|
|
||||||
v-bind="showmodal"
|
|
||||||
v-if="showmodal"
|
v-if="showmodal"
|
||||||
></Modal>
|
v-bind="showmodal"
|
||||||
|
@close="showmodal = undefined"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
props: ["row", "pagename"],
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
text: undefined,
|
|
||||||
phone: this.row.customer__phone || this.row.party__phone || this.row.phone,
|
|
||||||
showmodal: undefined,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
var format = function (s) {
|
|
||||||
return `${s.slice(0, 3)} ${s.slice(3, 6)} ${s.slice(6, 20)}`;
|
|
||||||
};
|
|
||||||
this.text = format(this.phone);
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
call() {
|
|
||||||
window.open(`tel:${this.phone}`);
|
|
||||||
},
|
|
||||||
sms() {
|
|
||||||
window.open(`sms:${this.phone}`);
|
|
||||||
},
|
|
||||||
sendSms() {
|
|
||||||
let api = this.row.code.indexOf("CN") >= 0 ? "customersms" : undefined;
|
|
||||||
if (this.row.code.indexOf("LN") >= 0) api = "loansms";
|
|
||||||
else if (this.row.code.indexOf("TS") >= 0) api = "collateralsms";
|
|
||||||
this.showmodal = {
|
|
||||||
component: "user/Sms",
|
|
||||||
title: "Nhắn tin SMS",
|
|
||||||
width: "50%",
|
|
||||||
height: "400px",
|
|
||||||
vbind: { row: this.row, pagename: this.pagename, api: api },
|
|
||||||
};
|
|
||||||
},
|
|
||||||
copy() {
|
|
||||||
this.$copyToClipboard(this.phone);
|
|
||||||
},
|
|
||||||
openZalo() {
|
|
||||||
window.open(`https://zalo.me/${this.phone}`, "_blank");
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|||||||
@@ -1,51 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div v-if="isLoaded && record">
|
||||||
v-if="!selectedCustomerType && isNewCustomer && !props.customerType"
|
|
||||||
class="p-5"
|
|
||||||
>
|
|
||||||
<h3 class="title is-4 mb-5 has-text-centered">
|
|
||||||
{{ isVietnamese ? "Chọn loại khách hàng" : "Select Customer Type" }}
|
|
||||||
</h3>
|
|
||||||
<div class="columns is-multiline">
|
|
||||||
<div class="column is-6">
|
|
||||||
<button
|
|
||||||
:disabled="!$getEditRights('edit', { code: 'individual', category: 'submenu' })"
|
|
||||||
class="button is-large is-fullwidth"
|
|
||||||
style="height: 120px"
|
|
||||||
@click="selectCustomerType(1)"
|
|
||||||
>
|
|
||||||
<div class="has-text-centered">
|
|
||||||
<div>
|
|
||||||
<SvgIcon v-bind="{ name: 'user.svg', type: 'black', size: 40 }"></SvgIcon>
|
|
||||||
</div>
|
|
||||||
<div class="title is-5 mb-0">
|
|
||||||
{{ isVietnamese ? "Cá nhân" : "Individual" }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="column is-6">
|
|
||||||
<button
|
|
||||||
:disabled="!$getEditRights('edit', { code: 'org', category: 'submenu' })"
|
|
||||||
class="button is-large is-fullwidth"
|
|
||||||
style="height: 120px"
|
|
||||||
@click="selectCustomerType(2)"
|
|
||||||
>
|
|
||||||
<div class="has-text-centered">
|
|
||||||
<div>
|
|
||||||
<SvgIcon v-bind="{ name: 'building.svg', type: 'black', size: 40 }"></SvgIcon>
|
|
||||||
</div>
|
|
||||||
<div class="title is-5 mb-0">
|
|
||||||
{{ isVietnamese ? "Tổ chức" : "Organization" }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<template v-else-if="isLoaded">
|
|
||||||
<div v-if="record && isLoaded">
|
|
||||||
<div class="columns is-multiline">
|
<div class="columns is-multiline">
|
||||||
<div class="column is-4">
|
<div class="column is-4">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
@@ -73,9 +27,10 @@
|
|||||||
>{{ dataLang && findFieldName("phone_number")[lang] }}<b class="ml-1 has-text-danger">*</b></label
|
>{{ dataLang && findFieldName("phone_number")[lang] }}<b class="ml-1 has-text-danger">*</b></label
|
||||||
>
|
>
|
||||||
<InputPhone
|
<InputPhone
|
||||||
v-bind="{ record: record, attr: 'phone' }"
|
:record="record"
|
||||||
|
attr="phone"
|
||||||
@phone="selected('phone', $event)"
|
@phone="selected('phone', $event)"
|
||||||
></InputPhone>
|
/>
|
||||||
<p
|
<p
|
||||||
class="help is-danger"
|
class="help is-danger"
|
||||||
v-if="errors.phone"
|
v-if="errors.phone"
|
||||||
@@ -94,9 +49,10 @@
|
|||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">Email</label>
|
<label class="label">Email</label>
|
||||||
<InputEmail
|
<InputEmail
|
||||||
v-bind="{ record: record, attr: 'email' }"
|
:record="record"
|
||||||
|
attr="email"
|
||||||
@email="selected('email', $event)"
|
@email="selected('email', $event)"
|
||||||
></InputEmail>
|
/>
|
||||||
<p
|
<p
|
||||||
class="help is-danger"
|
class="help is-danger"
|
||||||
v-if="errors.email"
|
v-if="errors.email"
|
||||||
@@ -129,32 +85,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
|
||||||
v-if="isOrganization"
|
|
||||||
class="columns is-multiline"
|
|
||||||
>
|
|
||||||
<div class="column is-6">
|
|
||||||
<div class="field">
|
|
||||||
<label class="label">Tài khoản ngân hàng</label>
|
|
||||||
<input
|
|
||||||
class="input"
|
|
||||||
type="text"
|
|
||||||
v-model="organizationData.bank_account"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="column is-6">
|
|
||||||
<div class="field">
|
|
||||||
<label class="label">Tên ngân hàng</label>
|
|
||||||
<input
|
|
||||||
class="input"
|
|
||||||
type="text"
|
|
||||||
v-model="organizationData.bank_name"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="columns is-multiline">
|
<div class="columns is-multiline">
|
||||||
<div class="column is-3">
|
<div class="column is-3">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
@@ -286,87 +216,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-5 mb-4">
|
|
||||||
<h4 class="title is-6 has-text-warning">
|
|
||||||
{{ isIndividual ? "Người liên quan" : "Người đại diện pháp luật" }}
|
|
||||||
</h4>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="columns is-multiline mb-0 is-2"
|
|
||||||
v-for="(v, i) in localPeople"
|
|
||||||
:key="i"
|
|
||||||
>
|
|
||||||
<div class="column">
|
|
||||||
<label
|
|
||||||
class="label"
|
|
||||||
v-if="i === 0"
|
|
||||||
>{{ findFieldName("select")[lang] }}</label
|
|
||||||
>
|
|
||||||
<SearchBox
|
|
||||||
v-bind="{
|
|
||||||
api: 'people',
|
|
||||||
field: 'label',
|
|
||||||
column: ['code', 'fullname', 'phone'],
|
|
||||||
first: true,
|
|
||||||
optionid: v.people,
|
|
||||||
position: 'is-top-left',
|
|
||||||
addon: peopleAddon,
|
|
||||||
viewaddon: peopleviewAddon,
|
|
||||||
}"
|
|
||||||
@option="selectPeople($event, v, i)"
|
|
||||||
></SearchBox>
|
|
||||||
</div>
|
|
||||||
<div class="column is-4">
|
|
||||||
<label
|
|
||||||
class="label"
|
|
||||||
v-if="i === 0"
|
|
||||||
>{{ isIndividual ? "Quan hệ" : "Chức vụ" }}</label
|
|
||||||
>
|
|
||||||
<SearchBox
|
|
||||||
v-bind="{
|
|
||||||
api: 'relation',
|
|
||||||
field: store.lang === 'en' ? 'en' : 'name',
|
|
||||||
column: ['code', 'name', 'en'],
|
|
||||||
first: true,
|
|
||||||
optionid: v.relation,
|
|
||||||
position: 'is-top-left',
|
|
||||||
filter: {
|
|
||||||
id__in: isIndividual ? [1, 2, 3, 4, 5, 6, 7, 8] : [9, 10, 11, 12],
|
|
||||||
},
|
|
||||||
}"
|
|
||||||
@option="selectRelation($event, v, i)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="column is-narrow">
|
|
||||||
<label
|
|
||||||
class="label"
|
|
||||||
v-if="i === 0"
|
|
||||||
> </label
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="buttons is-gap-0.5 is-flex-wrap-nowrap are-small"
|
|
||||||
style="height: 40px"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="button is-dark"
|
|
||||||
@click="add()"
|
|
||||||
>
|
|
||||||
<span class="icon">
|
|
||||||
<SvgIcon v-bind="{ name: 'add4.svg', type: 'white', size: 20 }"></SvgIcon>
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="button is-dark"
|
|
||||||
@click="remove(v, i)"
|
|
||||||
>
|
|
||||||
<span class="icon">
|
|
||||||
<SvgIcon v-bind="{ name: 'bin1.svg', type: 'white', size: 20 }"></SvgIcon>
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-5 buttons is-right">
|
<div class="mt-5 buttons is-right">
|
||||||
<button
|
<button
|
||||||
class="button"
|
class="button"
|
||||||
@@ -383,23 +232,20 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
@close="showmodal = undefined"
|
|
||||||
v-bind="showmodal"
|
|
||||||
v-if="showmodal"
|
v-if="showmodal"
|
||||||
></Modal>
|
v-bind="showmodal"
|
||||||
|
@close="showmodal = undefined"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted, watch } from "vue";
|
import { isEqual, pick } from "es-toolkit";
|
||||||
import { useNuxtApp } from "#app";
|
import { useStore } from "~/stores/index";
|
||||||
import InputPhone from "~/components/common/InputPhone";
|
import InputPhone from "~/components/common/InputPhone";
|
||||||
import InputEmail from "~/components/common/InputEmail";
|
import InputEmail from "~/components/common/InputEmail";
|
||||||
import SearchBox from "~/components/SearchBox";
|
import SearchBox from "~/components/SearchBox";
|
||||||
import Datepicker from "~/components/datepicker/Datepicker";
|
import Datepicker from "~/components/datepicker/Datepicker";
|
||||||
import { useStore } from "~/stores/index";
|
|
||||||
import { isEqual, pick } from "es-toolkit";
|
|
||||||
|
|
||||||
const emit = defineEmits(["close", "update", "modalevent"]);
|
const emit = defineEmits(["close", "update", "modalevent"]);
|
||||||
const { $getdata, $patchapi, $insertapi, $deleteapi, $empty, $errPhone, $resetNull, $snackbar, $copy } = useNuxtApp();
|
const { $getdata, $patchapi, $insertapi, $deleteapi, $empty, $errPhone, $resetNull, $snackbar, $copy } = useNuxtApp();
|
||||||
|
|||||||
@@ -1,314 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="columns mx-0">
|
|
||||||
<div class="column is-2">
|
|
||||||
<Caption
|
|
||||||
class="mb-2"
|
|
||||||
v-bind="{ title: 'Tên model (bảng)', type: 'has-text-warning' }"
|
|
||||||
></Caption>
|
|
||||||
<div class="mb-2">
|
|
||||||
<input
|
|
||||||
class="input"
|
|
||||||
v-model="text"
|
|
||||||
placeholder="Tìm model"
|
|
||||||
@change="findModel()"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div style="max-height: 80vh; overflow: auto">
|
|
||||||
<div
|
|
||||||
:class="`py-1 border-bottom is-clickable ${current.model === v.model ? 'has-background-primary has-text-white' : ''}`"
|
|
||||||
v-for="v in displayData"
|
|
||||||
@click="changeMenu(v)"
|
|
||||||
>
|
|
||||||
{{ v.model }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="column is-10 py-0 px-0">
|
|
||||||
<div class="tabs mb-3">
|
|
||||||
<ul>
|
|
||||||
<li
|
|
||||||
:class="`${v.code === tab ? 'is-active has-text-weight-bold fs-18' : 'fs-18'}`"
|
|
||||||
v-for="v in tabs"
|
|
||||||
>
|
|
||||||
<a @click="changeTab(v)">{{ v.name }}</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div v-if="tab === 'datatype'">
|
|
||||||
<Caption
|
|
||||||
class="mb-2"
|
|
||||||
v-bind="{ title: 'Kiểu dữ liệu (type)', type: 'has-text-warning' }"
|
|
||||||
></Caption>
|
|
||||||
<div style="max-height: 75vh; overflow-y: auto">
|
|
||||||
<div
|
|
||||||
class="py-1 border-bottom is-clickable"
|
|
||||||
v-for="x in current.fields"
|
|
||||||
>
|
|
||||||
{{ x.name }}
|
|
||||||
<span class="ml-6 has-text-grey">{{ x.type }}</span>
|
|
||||||
<a
|
|
||||||
class="ml-6 has-text-primary"
|
|
||||||
v-if="x.model"
|
|
||||||
@click="openModel(x)"
|
|
||||||
>{{ x.model }}</a
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<template v-else-if="tab === 'table'">
|
|
||||||
<div class="columns mx-0 mb-0 pb-0">
|
|
||||||
<div class="column is-5">
|
|
||||||
<Caption
|
|
||||||
class="mb-1"
|
|
||||||
v-bind="{ title: 'Values', type: 'has-text-warning' }"
|
|
||||||
></Caption>
|
|
||||||
<input
|
|
||||||
class="input"
|
|
||||||
rows="1"
|
|
||||||
v-model="values"
|
|
||||||
placeholder="Tên trường không chứa dấu cách, vd: code,name"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="column is-4">
|
|
||||||
<Caption
|
|
||||||
class="mb-1"
|
|
||||||
v-bind="{ title: 'Filter', type: 'has-text-warning' }"
|
|
||||||
></Caption>
|
|
||||||
<input
|
|
||||||
class="input"
|
|
||||||
rows="1"
|
|
||||||
v-model="filter"
|
|
||||||
placeholder="{'code': 'xyz'}"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="column is-2">
|
|
||||||
<Caption
|
|
||||||
class="mb-1"
|
|
||||||
v-bind="{ title: 'Sort', type: 'has-text-warning' }"
|
|
||||||
></Caption>
|
|
||||||
<input
|
|
||||||
class="input"
|
|
||||||
rows="1"
|
|
||||||
v-model="sort"
|
|
||||||
placeholder="vd: -code,name"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="column is-1">
|
|
||||||
<Caption
|
|
||||||
class="mb-1"
|
|
||||||
v-bind="{ title: 'Load', type: 'has-text-warning' }"
|
|
||||||
></Caption>
|
|
||||||
<div>
|
|
||||||
<button
|
|
||||||
class="button is-primary has-text-white"
|
|
||||||
@click="loadData()"
|
|
||||||
>
|
|
||||||
Load
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Caption
|
|
||||||
class="mb-1"
|
|
||||||
v-bind="{ title: 'Query', type: 'has-text-warning' }"
|
|
||||||
></Caption>
|
|
||||||
<div class="mb-2">
|
|
||||||
{{ query }}
|
|
||||||
<a
|
|
||||||
class="has-text-primary ml-5"
|
|
||||||
@click="copy()"
|
|
||||||
>copy</a
|
|
||||||
>
|
|
||||||
<p>
|
|
||||||
{{ apiUrl }}
|
|
||||||
<a
|
|
||||||
class="has-text-primary ml-5"
|
|
||||||
@click="$copyToClipboard(apiUrl)"
|
|
||||||
>copy</a
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
class="has-text-primary ml-5"
|
|
||||||
target="_blank"
|
|
||||||
:href="apiUrl"
|
|
||||||
>open</a
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<DataTable
|
|
||||||
v-bind="{ pagename: pagename }"
|
|
||||||
v-if="pagedata"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<div v-else>
|
|
||||||
<img
|
|
||||||
id="image"
|
|
||||||
:src="filePath"
|
|
||||||
alt=""
|
|
||||||
/>
|
|
||||||
<p class="pl-5">
|
|
||||||
<a
|
|
||||||
class="mr-5"
|
|
||||||
@click="downloadFile()"
|
|
||||||
>
|
|
||||||
<SvgIcon v-bind="{ name: 'download.svg', type: 'black', size: 24 }"></SvgIcon>
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
target="_blank"
|
|
||||||
:href="filePath"
|
|
||||||
>
|
|
||||||
<SvgIcon v-bind="{ name: 'open.svg', type: 'black', size: 24 }"></SvgIcon>
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Modal
|
|
||||||
@close="showmodal = undefined"
|
|
||||||
v-bind="showmodal"
|
|
||||||
v-if="showmodal"
|
|
||||||
></Modal>
|
|
||||||
</template>
|
|
||||||
<script setup>
|
|
||||||
import { useStore } from "~/stores/index";
|
|
||||||
const {
|
|
||||||
$getdata,
|
|
||||||
$getapi,
|
|
||||||
$createField,
|
|
||||||
$clone,
|
|
||||||
$getpage,
|
|
||||||
$empty,
|
|
||||||
$copyToClipboard,
|
|
||||||
$find,
|
|
||||||
$multiSort,
|
|
||||||
$download,
|
|
||||||
$getpath,
|
|
||||||
} = useNuxtApp();
|
|
||||||
const store = useStore();
|
|
||||||
var pagename = "pagedata3";
|
|
||||||
var pagedata = ref();
|
|
||||||
pagedata.value = $getpage();
|
|
||||||
pagedata.value.perPage = 10;
|
|
||||||
store.commit(pagename, pagedata);
|
|
||||||
let list = ["LogEntry", "Permission", "ContentType", "Session", "Group"];
|
|
||||||
var data = (await $getdata("getmodel")).filter((v) => list.findIndex((x) => x === v.model) < 0);
|
|
||||||
data = $multiSort(data, { model: "asc" });
|
|
||||||
var current = ref({ fields: [] });
|
|
||||||
var tabs = [
|
|
||||||
{ code: "datatype", name: "Kiểu dữ liệu" },
|
|
||||||
{ code: "table", name: "Dữ liệu" },
|
|
||||||
{ code: "datamodel", name: "Data model" },
|
|
||||||
];
|
|
||||||
var tab = ref("datatype");
|
|
||||||
var datatable = ref();
|
|
||||||
var query = ref();
|
|
||||||
var values, filter;
|
|
||||||
var apiUrl = ref();
|
|
||||||
var showmodal = ref();
|
|
||||||
var text = null;
|
|
||||||
var displayData = ref(data);
|
|
||||||
var filePath = `${$getpath()}static/files/datamodel.png`;
|
|
||||||
var sort = "-id";
|
|
||||||
current.value = data[0];
|
|
||||||
function changeMenu(v) {
|
|
||||||
values = undefined;
|
|
||||||
filter = undefined;
|
|
||||||
sort = undefined;
|
|
||||||
current.value = v;
|
|
||||||
if (tab.value === "table") loadData();
|
|
||||||
}
|
|
||||||
async function changeTab(v) {
|
|
||||||
tab.value = v.code;
|
|
||||||
if (v.code === "table") loadData();
|
|
||||||
}
|
|
||||||
async function loadData() {
|
|
||||||
let vfilter = filter ? filter.trim() : undefined;
|
|
||||||
if (vfilter) {
|
|
||||||
try {
|
|
||||||
vfilter = JSON.parse(vfilter);
|
|
||||||
} catch (error) {
|
|
||||||
alert("Cấu trúc filter có lỗi");
|
|
||||||
vfilter = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let params = {
|
|
||||||
values: $empty(values) ? undefined : values.trim(),
|
|
||||||
filter: filter,
|
|
||||||
sort: $empty(sort) ? undefined : sort.trim(),
|
|
||||||
};
|
|
||||||
let modelName = current.value.model;
|
|
||||||
let found = {
|
|
||||||
name: modelName.toLowerCase().replace("_", ""),
|
|
||||||
url: `data/${modelName}/`,
|
|
||||||
url_detail: `data-detail/${modelName}/`,
|
|
||||||
params: params,
|
|
||||||
};
|
|
||||||
query.value = $clone(found);
|
|
||||||
let rs = await $getapi([found]);
|
|
||||||
if (rs === "error") return alert("Đã xảy ra lỗi, hãy xem lại câu lệnh.");
|
|
||||||
datatable.value = rs[0].data.rows;
|
|
||||||
showData();
|
|
||||||
|
|
||||||
// api query
|
|
||||||
const baseUrl = $getpath() + `${query.value.url}`;
|
|
||||||
apiUrl.value = baseUrl;
|
|
||||||
let vparams = !$empty(values) ? { values: values } : null;
|
|
||||||
if (!$empty(filter)) {
|
|
||||||
vparams = vparams ? { values: values, filter: filter } : { filter: filter };
|
|
||||||
}
|
|
||||||
if (!$empty(sort)) {
|
|
||||||
if (vparams) {
|
|
||||||
vparams.sort = sort.trim();
|
|
||||||
} else {
|
|
||||||
vparams = { sort: sort.trim() };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (vparams) {
|
|
||||||
let url = new URL(baseUrl);
|
|
||||||
let searchParams = new URLSearchParams(vparams);
|
|
||||||
url.search = searchParams.toString();
|
|
||||||
apiUrl.value = baseUrl + url.search;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function showData() {
|
|
||||||
let arr = [];
|
|
||||||
if (!$empty(values)) {
|
|
||||||
let arr1 = values.trim().split(",");
|
|
||||||
arr1.map((v) => {
|
|
||||||
let val = v.trim();
|
|
||||||
let field = $createField(val, val, "string", true);
|
|
||||||
arr.push(field);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
current.value.fields.map((v) => {
|
|
||||||
let field = $createField(v.name, v.name, "string", true);
|
|
||||||
arr.push(field);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let clone = $clone(pagedata.value);
|
|
||||||
clone.fields = arr;
|
|
||||||
clone.data = datatable.value;
|
|
||||||
pagedata.value = undefined;
|
|
||||||
setTimeout(() => (pagedata.value = clone));
|
|
||||||
}
|
|
||||||
function copy() {
|
|
||||||
$copyToClipboard(JSON.stringify(query.value));
|
|
||||||
}
|
|
||||||
function openModel(x) {
|
|
||||||
showmodal.value = {
|
|
||||||
component: "datatable/ModelInfo",
|
|
||||||
title: x.model,
|
|
||||||
width: "70%",
|
|
||||||
height: "600px",
|
|
||||||
vbind: { data: data, info: $find(data, { model: x.model }) },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
function downloadFile() {
|
|
||||||
$download(`${$getpath()}download/?name=datamodel.png&type=file`, "datamodel.png");
|
|
||||||
}
|
|
||||||
function findModel() {
|
|
||||||
if ($empty(text)) return (displayData.value = data);
|
|
||||||
displayData.value = data.filter((v) => v.model.toLowerCase().indexOf(text.toLowerCase()) >= 0);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -87,6 +87,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr
|
<tr
|
||||||
|
v-if="displayData.length"
|
||||||
v-for="(v, i) in displayData"
|
v-for="(v, i) in displayData"
|
||||||
:key="i"
|
:key="i"
|
||||||
>
|
>
|
||||||
@@ -107,6 +108,14 @@
|
|||||||
<span v-else>{{ v[field.name] }}</span>
|
<span v-else>{{ v[field.name] }}</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr v-else>
|
||||||
|
<td
|
||||||
|
:colspan="displayFields.length"
|
||||||
|
class="fs-14 has-text-centered has-text-grey py-4"
|
||||||
|
>
|
||||||
|
Không tìm thấy kết quả
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<DatatablePagination
|
<DatatablePagination
|
||||||
|
|||||||
@@ -248,9 +248,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from "vue";
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { useNuxtApp } from "nuxt/app";
|
|
||||||
import { apiUrl } from "~/components/marketing/email/Email.utils";
|
import { apiUrl } from "~/components/marketing/email/Email.utils";
|
||||||
import type dayjs from "dayjs";
|
import type dayjs from "dayjs";
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,10 @@
|
|||||||
class="p-2 is-flex is-justify-content-center is-align-items-center"
|
class="p-2 is-flex is-justify-content-center is-align-items-center"
|
||||||
style="min-height: 120px"
|
style="min-height: 120px"
|
||||||
>
|
>
|
||||||
<SvgIcon v-bind="{ name: 'pdf.svg', type: 'primary', size: 32 }" />
|
<Icon
|
||||||
|
name="mdi:file-pdf-box"
|
||||||
|
:size="32"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-else
|
v-else
|
||||||
@@ -45,7 +48,10 @@
|
|||||||
@click="this.$copyToClipboard(`${$getpath()}static/files/${file.file__file}`)"
|
@click="this.$copyToClipboard(`${$getpath()}static/files/${file.file__file}`)"
|
||||||
>
|
>
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<SvgIcon v-bind="{ name: 'copy.svg', type: 'primary', size: 18 }" />
|
<Icon
|
||||||
|
name="material-symbols:content-copy-outline-rounded"
|
||||||
|
:size="18"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@@ -53,7 +59,10 @@
|
|||||||
@click="download()"
|
@click="download()"
|
||||||
>
|
>
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<SvgIcon v-bind="{ name: 'download.svg', type: 'primary', size: 18 }" />
|
<Icon
|
||||||
|
name="material-symbols:download-rounded"
|
||||||
|
:size="18"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@@ -62,7 +71,10 @@
|
|||||||
@click="askConfirm()"
|
@click="askConfirm()"
|
||||||
>
|
>
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<SvgIcon v-bind="{ name: 'bin1.svg', type: 'primary', size: 18 }" />
|
<Icon
|
||||||
|
name="material-symbols:delete-outline-rounded"
|
||||||
|
:size="18"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
const { $buildFileUrl, $copyToClipboard, $getEditRights } = useNuxtApp();
|
const { $buildFileUrl, $copyToClipboard } = useNuxtApp();
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
className: String,
|
className: String,
|
||||||
@@ -12,24 +12,29 @@ const props = defineProps({
|
|||||||
const url = $buildFileUrl(props.image.file__file);
|
const url = $buildFileUrl(props.image.file__file);
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div :class="['buttons is-gap-1', className]">
|
<div :class="['buttons has-addons', className]">
|
||||||
<button
|
<button
|
||||||
class="button is-small is-white"
|
class="button is-small is-white"
|
||||||
@click="$copyToClipboard(url)"
|
@click="$copyToClipboard(url)"
|
||||||
title="Sao chép link"
|
title="Sao chép link"
|
||||||
>
|
>
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<SvgIcon v-bind="{ name: 'copy.svg', type: 'primary', size: 18 }" />
|
<Icon
|
||||||
|
name="material-symbols:content-copy-outline-rounded"
|
||||||
|
:size="18"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="$getEditRights()"
|
|
||||||
class="button is-small is-white"
|
class="button is-small is-white"
|
||||||
@click="editImage(image)"
|
@click="editImage(image)"
|
||||||
title="Sửa"
|
title="Sửa"
|
||||||
>
|
>
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<SvgIcon v-bind="{ name: 'edit.svg', type: 'primary', size: 18 }" />
|
<Icon
|
||||||
|
name="material-symbols:edit-outline-rounded"
|
||||||
|
:size="18"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@@ -38,17 +43,23 @@ const url = $buildFileUrl(props.image.file__file);
|
|||||||
title="Tải xuống"
|
title="Tải xuống"
|
||||||
>
|
>
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<SvgIcon v-bind="{ name: 'download.svg', type: 'success', size: 18 }" />
|
<Icon
|
||||||
|
name="material-symbols:download-rounded"
|
||||||
|
:size="18"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="$getEditRights()"
|
|
||||||
class="button is-small is-white"
|
class="button is-small is-white"
|
||||||
@click="openDeleteImageConfirm(image)"
|
@click="openDeleteImageConfirm(image)"
|
||||||
title="Xóa"
|
title="Xóa"
|
||||||
>
|
>
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<SvgIcon v-bind="{ name: 'bin1.svg', type: 'primary', size: 18 }" />
|
<Icon
|
||||||
|
name="material-symbols:delete-outline-rounded"
|
||||||
|
:size="18"
|
||||||
|
class="has-text-danger"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<p
|
<p
|
||||||
class="py-1 border-bottom"
|
|
||||||
v-for="(v, i) in vfiles"
|
v-for="(v, i) in vfiles"
|
||||||
|
class="py-1"
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
class="mr-4"
|
class="mr-4"
|
||||||
@@ -12,34 +12,44 @@
|
|||||||
class="mr-4"
|
class="mr-4"
|
||||||
@click="download(v, i)"
|
@click="download(v, i)"
|
||||||
>
|
>
|
||||||
<SvgIcon v-bind="{ name: 'download1.svg', type: 'dark', size: 16 }"></SvgIcon>
|
<span class="icon">
|
||||||
|
<Icon
|
||||||
|
name="material-symbols:download-rounded"
|
||||||
|
:size="18"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
|
v-if="show?.delete"
|
||||||
@click="remove(v, i)"
|
@click="remove(v, i)"
|
||||||
v-if="show ? show.delete : false"
|
|
||||||
>
|
>
|
||||||
<SvgIcon v-bind="{ name: 'bin1.svg', type: 'dark', size: 16 }"></SvgIcon>
|
<span class="icon">
|
||||||
|
<Icon
|
||||||
|
name="material-symbols:delete-outline-rounded"
|
||||||
|
:size="18"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
<Modal
|
<Modal
|
||||||
@close="showmodal = undefined"
|
|
||||||
v-bind="showmodal"
|
|
||||||
v-if="showmodal"
|
v-if="showmodal"
|
||||||
></Modal>
|
v-bind="showmodal"
|
||||||
|
@close="showmodal = undefined"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
const { $copy, $getpath, $download } = useNuxtApp();
|
const { $copy, $getpath, $download } = useNuxtApp();
|
||||||
const emit = defineEmits(["remove", "close"]);
|
const emit = defineEmits(["remove", "close"]);
|
||||||
var props = defineProps({
|
const props = defineProps({
|
||||||
files: Object,
|
files: Object,
|
||||||
show: Object,
|
show: Object,
|
||||||
});
|
});
|
||||||
var showmodal = ref();
|
const showmodal = ref();
|
||||||
var vfiles = ref($copy(props.files));
|
const vfiles = ref($copy(props.files));
|
||||||
function remove(v, i) {
|
function remove(v, i) {
|
||||||
vfiles.value.splice(i, 1);
|
vfiles.value.splice(i, 1);
|
||||||
emit("remove", { v: v, i: i });
|
emit("remove", { v, i });
|
||||||
emit("modalevent", { name: "removefile", data: { v: v, i: i } });
|
emit("modalevent", { name: "removefile", data: { v, i } });
|
||||||
if (vfiles.value.length === 0) emit("close");
|
if (vfiles.value.length === 0) emit("close");
|
||||||
}
|
}
|
||||||
function open(v) {
|
function open(v) {
|
||||||
@@ -62,7 +72,7 @@ function download(v) {
|
|||||||
}
|
}
|
||||||
watch(
|
watch(
|
||||||
() => props.files,
|
() => props.files,
|
||||||
(newVal, oldVal) => {
|
() => {
|
||||||
vfiles.value = props.files;
|
vfiles.value = props.files;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<b-tooltip
|
|
||||||
label="Bút toán hạch toán"
|
|
||||||
position="is-left"
|
|
||||||
type="is-primary"
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
class="mr-2"
|
|
||||||
@click="list()"
|
|
||||||
>
|
|
||||||
<SvgIcon v-bind="{ name: 'menu.png', type: 'gray', size: 16 }"></SvgIcon>
|
|
||||||
</a>
|
|
||||||
</b-tooltip>
|
|
||||||
<b-tooltip
|
|
||||||
v-if="$getEditRights()"
|
|
||||||
label="Hạch toán"
|
|
||||||
position="is-left"
|
|
||||||
type="is-primary"
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
class="mr-2"
|
|
||||||
@click="entry()"
|
|
||||||
>
|
|
||||||
<SvgIcon v-bind="{ name: 'usd.png', type: 'gray', size: 16 }"></SvgIcon>
|
|
||||||
</a>
|
|
||||||
</b-tooltip>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
props: ["row", "api", "pagename"],
|
|
||||||
methods: {
|
|
||||||
list() {
|
|
||||||
let obj = {
|
|
||||||
component: "common/ViewList",
|
|
||||||
title: this.$lang("entry"),
|
|
||||||
width: "80%",
|
|
||||||
height: "400px",
|
|
||||||
vbind: {
|
|
||||||
vbind: {
|
|
||||||
api: "internalentry",
|
|
||||||
setting: "internal-entry-fields",
|
|
||||||
filter: { account__code: this.row.code },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
this.$emit("open", { name: "dataevent", data: { modal: obj } });
|
|
||||||
},
|
|
||||||
entry() {
|
|
||||||
let obj = {
|
|
||||||
component: "accounting/InternalDeposit",
|
|
||||||
title: this.$lang("accounting-entry"),
|
|
||||||
width: "1000px",
|
|
||||||
height: "450px",
|
|
||||||
vbind: { row: this.row, api: this.api, pagename: this.pagename },
|
|
||||||
};
|
|
||||||
this.$emit("open", { name: "dataevent", data: { modal: obj } });
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a
|
|
||||||
class="has-text-link"
|
|
||||||
@click="open"
|
|
||||||
>{{ row["collaborator__code"] }}</a
|
|
||||||
>
|
|
||||||
</template>
|
|
||||||
<script setup>
|
|
||||||
import { useStore } from "~/stores/index";
|
|
||||||
const store = useStore();
|
|
||||||
const { $getdata } = useNuxtApp();
|
|
||||||
|
|
||||||
const emit = defineEmits(["clickevent"]);
|
|
||||||
const props = defineProps({
|
|
||||||
row: Object,
|
|
||||||
});
|
|
||||||
async function open() {
|
|
||||||
const record = await $getdata("collaborator", {
|
|
||||||
first: true,
|
|
||||||
filter: { code: props.row.collaborator__code },
|
|
||||||
});
|
|
||||||
emit("clickevent", {
|
|
||||||
name: "dataevent",
|
|
||||||
data: {
|
|
||||||
modal: {
|
|
||||||
title: store.lang === "en" ? "Collaborator" : "Cộng tác viên",
|
|
||||||
height: "400px",
|
|
||||||
width: "60%",
|
|
||||||
component: "collaborator/CollaboratorView",
|
|
||||||
vbind: { row: record },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a
|
|
||||||
class="has-text-link"
|
|
||||||
@click="open"
|
|
||||||
>{{ row["payment_status__code"] }}</a
|
|
||||||
>
|
|
||||||
</template>
|
|
||||||
<script setup>
|
|
||||||
const { $store } = useNuxtApp();
|
|
||||||
const emit = defineEmits(["clickevent"]);
|
|
||||||
const props = defineProps({
|
|
||||||
row: Object,
|
|
||||||
api: String,
|
|
||||||
pagename: String,
|
|
||||||
});
|
|
||||||
function open() {
|
|
||||||
emit("clickevent", {
|
|
||||||
name: "dataevent",
|
|
||||||
data: {
|
|
||||||
modal: {
|
|
||||||
title: $store.lang === "en" ? "Payment status" : "Trạng thái thanh toán",
|
|
||||||
height: "300px",
|
|
||||||
width: "600px",
|
|
||||||
component: "application/CommPayment",
|
|
||||||
vbind: { row: props.row, api: props.api, pagename: "pagedata5" },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -54,7 +54,7 @@ onMounted(fetchImeis);
|
|||||||
<Icon
|
<Icon
|
||||||
name="svg-spinners:180-ring-with-bg"
|
name="svg-spinners:180-ring-with-bg"
|
||||||
:size="26"
|
:size="26"
|
||||||
class="has-text-grey-light"
|
class="has-text-primary"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="imeis.length === 0">
|
<div v-else-if="imeis.length === 0">
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export default defineNuxtPlugin(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const keys = Object.keys(obj);
|
const keys = Object.keys(obj);
|
||||||
let found = arr.find((v) => {
|
const found = arr.find((v) => {
|
||||||
let valid = true;
|
let valid = true;
|
||||||
keys.map((key) => {
|
keys.map((key) => {
|
||||||
let val = obj[key];
|
let val = obj[key];
|
||||||
@@ -49,7 +49,7 @@ export default defineNuxtPlugin(() => {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
let rows = arr.filter((v) => {
|
const rows = arr.filter((v) => {
|
||||||
let valid = true;
|
let valid = true;
|
||||||
keys.map((key) => {
|
keys.map((key) => {
|
||||||
let val = obj[key];
|
let val = obj[key];
|
||||||
|
|||||||
@@ -1,3 +1,39 @@
|
|||||||
|
import SvgIcon from "~/components/SvgIcon.vue";
|
||||||
|
import Datepicker from "~/components/datepicker/Datepicker.vue";
|
||||||
|
|
||||||
|
import DataTable from "~/components/datatable/DataTable.vue";
|
||||||
|
import DataView from "~/components/datatable/DataView.vue";
|
||||||
|
import ViewList from "~/components/datatable/ViewList.vue";
|
||||||
|
import PivotDataView from "~/components/datatable/PivotDataView.vue";
|
||||||
|
|
||||||
|
import ImageGallery from "~/components/media/ImageGallery.vue";
|
||||||
|
import FileGallery from "~/components/media/FileGallery.vue";
|
||||||
|
import FileUpload from "~/components/media/FileUpload.vue";
|
||||||
|
import FileShow from "~/components/media/FileShow.vue";
|
||||||
|
import ChipImage from "~/components/media/ChipImage.vue";
|
||||||
|
import ImageLayout from "~/components/media/ImageLayout.vue";
|
||||||
|
import Email from "~/components/marketing/email/Email.vue";
|
||||||
|
|
||||||
|
import Avatarbox from "~/components/common/Avatarbox.vue";
|
||||||
|
import CountdownTimer from "~/components/common/CountdownTimer.vue";
|
||||||
|
import FormatNumber from "~/components/common/FormatNumber.vue";
|
||||||
|
import FormatDate from "~/components/common/FormatDate.vue";
|
||||||
|
import InputNumber from "~/components/common/InputNumber.vue";
|
||||||
|
import CountWithAdd from "~/components/common/CountWithAdd.vue";
|
||||||
|
|
||||||
|
// menu
|
||||||
|
import MenuAction from "~/components/menu/MenuAction.vue";
|
||||||
|
import MenuApp from "~/components/menu/MenuApp.vue";
|
||||||
|
import MenuCust from "~/components/menu/MenuCust.vue";
|
||||||
|
import MenuPhone from "~/components/menu/MenuPhone.vue";
|
||||||
|
import MenuParam from "~/components/menu/MenuParam.vue";
|
||||||
|
import MenuAdd from "~/components/menu/MenuAdd.vue";
|
||||||
|
import MenuNote from "~/components/menu/MenuNote.vue";
|
||||||
|
import MenuFile from "~/components/menu/MenuFile.vue";
|
||||||
|
|
||||||
|
import CustomerForm from "~/components/customer/CustomerForm.vue";
|
||||||
|
import CustomerQuickAdd from "~/components/customer/CustomerQuickAdd.vue";
|
||||||
|
|
||||||
import Dashboard from "~/components/dashboard/Dashboard.vue";
|
import Dashboard from "~/components/dashboard/Dashboard.vue";
|
||||||
import Orders from "~/components/orders/Orders.vue";
|
import Orders from "~/components/orders/Orders.vue";
|
||||||
import Inventory from "~/components/inventory/Inventory.vue";
|
import Inventory from "~/components/inventory/Inventory.vue";
|
||||||
@@ -46,47 +82,6 @@ import Customers from "~/components/report/Customers.vue";
|
|||||||
import Goods from "~/components/report/Goods.vue";
|
import Goods from "~/components/report/Goods.vue";
|
||||||
import ReportCashBook from "~/components/report/CashBook.vue";
|
import ReportCashBook from "~/components/report/CashBook.vue";
|
||||||
import Finance from "~/components/report/Finance.vue";
|
import Finance from "~/components/report/Finance.vue";
|
||||||
import SvgIcon from "~/components/SvgIcon.vue";
|
|
||||||
import DataView from "~/components/datatable/DataView.vue";
|
|
||||||
import PivotDataView from "~/components/datatable/PivotDataView.vue";
|
|
||||||
import PickDay from "~/components/datepicker/PickDay.vue";
|
|
||||||
import Datepicker from "~/components/datepicker/Datepicker.vue";
|
|
||||||
import ImageGallery from "~/components/media/ImageGallery.vue";
|
|
||||||
import FileGallery from "~/components/media/FileGallery.vue";
|
|
||||||
import FileUpload from "~/components/media/FileUpload.vue";
|
|
||||||
import FileShow from "~/components/media/FileShow.vue";
|
|
||||||
import ChipImage from "~/components/media/ChipImage.vue";
|
|
||||||
import Avatarbox from "~/components/common/Avatarbox.vue";
|
|
||||||
import Email from "~/components/marketing/email/Email.vue";
|
|
||||||
import ViewList from "~/components/common/ViewList.vue";
|
|
||||||
import Configuration from "~/components/maintab/Configuration.vue";
|
|
||||||
|
|
||||||
// format
|
|
||||||
import FormatNumber from "~/components/datatable/format/FormatNumber.vue";
|
|
||||||
import FormatDate from "~/components/datatable/format/FormatDate.vue";
|
|
||||||
import DataTable from "~/components/datatable/DataTable.vue";
|
|
||||||
import DataModel from "~/components/datatable/DataModel.vue";
|
|
||||||
import InputNumber from "~/components/common/InputNumber.vue";
|
|
||||||
|
|
||||||
// menu
|
|
||||||
import MenuAction from "~/components/menu/MenuAction.vue";
|
|
||||||
import MenuApp from "~/components/menu/MenuApp.vue";
|
|
||||||
import MenuCust from "~/components/menu/MenuCust.vue";
|
|
||||||
import MenuPhone from "~/components/menu/MenuPhone.vue";
|
|
||||||
import MenuParam from "~/components/menu/MenuParam.vue";
|
|
||||||
import MenuAdd from "~/components/menu/MenuAdd.vue";
|
|
||||||
import MenuCollab from "~/components/menu/MenuCollab.vue";
|
|
||||||
import MenuNote from "~/components/menu/MenuNote.vue";
|
|
||||||
import MenuFile from "~/components/menu/MenuFile.vue";
|
|
||||||
import MenuPayment from "~/components/menu/MenuPayment.vue";
|
|
||||||
import ScrollBox from "~/components/datatable/ScrollBox.vue";
|
|
||||||
import CountWithAdd from "~/components/common/CountWithAdd.vue";
|
|
||||||
import MenuAccount from "~/components/menu/MenuAccount.vue";
|
|
||||||
import ImageLayout from "~/components/media/ImageLayout.vue";
|
|
||||||
|
|
||||||
import CountdownTimer from "~/components/common/CountdownTimer.vue";
|
|
||||||
import CustomerForm from "~/components/customer/CustomerForm.vue";
|
|
||||||
import CustomerQuickAdd from "~/components/customer/CustomerQuickAdd.vue";
|
|
||||||
|
|
||||||
const components = {
|
const components = {
|
||||||
PivotDataView,
|
PivotDataView,
|
||||||
@@ -99,7 +94,6 @@ const components = {
|
|||||||
Email,
|
Email,
|
||||||
SvgIcon,
|
SvgIcon,
|
||||||
Datepicker,
|
Datepicker,
|
||||||
PickDay,
|
|
||||||
ImageGallery,
|
ImageGallery,
|
||||||
FileGallery,
|
FileGallery,
|
||||||
FileUpload,
|
FileUpload,
|
||||||
@@ -108,21 +102,15 @@ const components = {
|
|||||||
ChipImage,
|
ChipImage,
|
||||||
Avatarbox,
|
Avatarbox,
|
||||||
DataTable,
|
DataTable,
|
||||||
Configuration,
|
|
||||||
InputNumber,
|
InputNumber,
|
||||||
MenuPhone,
|
MenuPhone,
|
||||||
MenuParam,
|
MenuParam,
|
||||||
ScrollBox,
|
|
||||||
MenuPayment,
|
|
||||||
DataModel,
|
|
||||||
FormatNumber,
|
FormatNumber,
|
||||||
FormatDate,
|
FormatDate,
|
||||||
MenuApp,
|
MenuApp,
|
||||||
MenuCust,
|
MenuCust,
|
||||||
MenuAdd,
|
MenuAdd,
|
||||||
MenuCollab,
|
|
||||||
MenuNote,
|
MenuNote,
|
||||||
MenuAccount,
|
|
||||||
ImageLayout,
|
ImageLayout,
|
||||||
MenuFile,
|
MenuFile,
|
||||||
Dashboard,
|
Dashboard,
|
||||||
|
|||||||
Reference in New Issue
Block a user