jws-frontend/src/pages/01_branch-management/MainPage.vue

1932 lines
68 KiB
Vue
Raw Normal View History

2024-04-02 17:47:32 +07:00
<script setup lang="ts">
2024-04-09 16:47:52 +07:00
import { storeToRefs } from 'pinia';
2024-07-18 09:10:51 +00:00
import { ref, onMounted, computed, watch } from 'vue';
2024-04-17 15:15:44 +07:00
import { Icon } from '@iconify/vue';
import { BranchContact } from 'src/stores/branch-contact/types';
2024-07-18 09:10:51 +00:00
import { useQuasar } from 'quasar';
import { useI18n } from 'vue-i18n';
import type { QTableProps } from 'quasar';
2024-04-05 18:14:53 +07:00
import useBranchStore from 'stores/branch';
2024-07-18 09:10:51 +00:00
import useFlowStore from 'src/stores/flow';
import { BranchWithChildren, BranchCreate } from 'stores/branch/types';
import { Status } from 'src/stores/types';
2024-04-16 18:33:41 +07:00
2024-07-02 09:22:06 +00:00
import useUtilsStore, { dialog } from 'src/stores/utils';
import AddButton from 'components/AddButton.vue';
2024-04-05 18:14:53 +07:00
import TooltipComponent from 'components/TooltipComponent.vue';
2024-04-16 18:33:41 +07:00
import StatCard from 'components/StatCardComponent.vue';
2024-06-28 14:14:23 +07:00
import BranchCard from 'components/01_branch-management/BranchCard.vue';
import FormDialog from 'components/FormDialog.vue';
import FormBranchInformation from 'components/01_branch-management/FormBranchInformation.vue';
import FormLocation from 'components/01_branch-management/FormLocation.vue';
import FormQr from 'components/01_branch-management/FormQr.vue';
import FormBranchContact from 'components/01_branch-management/FormBranchContact.vue';
import FormImage from 'components/01_branch-management/FormImage.vue';
import DrawerInfo from 'components/DrawerInfo.vue';
import InfoForm from 'components/02_personnel-management/InfoForm.vue';
2024-07-18 09:10:51 +00:00
const $q = useQuasar();
2024-04-17 15:15:44 +07:00
const { t } = useI18n();
2024-07-02 09:22:06 +00:00
const utilsStore = useUtilsStore();
2024-04-09 15:54:47 +07:00
const holdDialog = ref(false);
const columns = [
{
name: 'branchLabelName',
align: 'left',
label: 'office',
field: 'name',
sortable: true,
},
{
name: 'branchLabelAddress',
align: 'left',
label: 'address',
field: 'address',
sortable: true,
},
{
name: 'branchLabelTel',
align: 'left',
2024-07-05 11:43:07 +07:00
label: 'formDialogInputTelephone',
field: 'telephoneNo',
},
{
name: 'branchLabelType',
align: 'left',
label: 'type',
field: 'isHeadOffice',
},
] satisfies QTableProps['columns'];
const modal = ref<boolean>(false);
2024-07-05 03:39:41 +00:00
const hideStat = ref(false);
2024-07-16 02:52:38 +00:00
const currentStatus = ref<Status | 'All'>('All');
2024-07-18 14:18:16 +07:00
const expandedTree = ref<string[]>([]);
const profileFileImg = ref<File | undefined>(undefined);
const imageUrl = ref<string | null>('');
2024-07-19 04:56:08 +00:00
const currentNode = ref<BranchWithChildren>();
const inputFileImg = (() => {
const element = document.createElement('input');
element.type = 'file';
element.accept = 'image/*';
const reader = new FileReader();
reader.addEventListener('load', () => {
if (typeof reader.result === 'string') imageUrl.value = reader.result;
});
element.addEventListener('change', () => {
profileFileImg.value = element.files?.[0];
if (profileFileImg.value) {
reader.readAsDataURL(profileFileImg.value);
}
});
return element;
})();
const profileFile = ref<File | undefined>(undefined);
2024-04-18 15:10:54 +07:00
const qrCodeimageUrl = ref<string | null>('');
const inputFile = (() => {
const element = document.createElement('input');
element.type = 'file';
element.accept = 'image/*';
const reader = new FileReader();
reader.addEventListener('load', () => {
2024-04-18 15:10:54 +07:00
if (typeof reader.result === 'string') qrCodeimageUrl.value = reader.result;
});
element.addEventListener('change', () => {
profileFile.value = element.files?.[0];
if (profileFile.value) {
reader.readAsDataURL(profileFile.value);
}
});
return element;
})();
2024-04-09 15:54:47 +07:00
const branchStore = useBranchStore();
2024-06-25 16:05:51 +07:00
const flowStore = useFlowStore();
2024-04-16 18:33:41 +07:00
const { locale } = useI18n();
2024-04-09 16:47:52 +07:00
const { data: branchData } = storeToRefs(branchStore);
2024-04-16 18:33:41 +07:00
const treeData = computed(() => {
const arr: BranchWithChildren[] = [];
2024-04-09 15:54:47 +07:00
2024-04-16 18:33:41 +07:00
branchData.value?.result.forEach((a) => {
if (a.isHeadOffice) arr.push(Object.assign(a, { branch: [] }));
else arr.find((b) => b.id === a.headOfficeId)?.branch.push(a);
});
2024-04-09 15:54:47 +07:00
2024-04-16 18:33:41 +07:00
return arr;
});
async function calculateStats() {
2024-04-16 18:33:41 +07:00
const _stats = await branchStore.stats();
if (_stats) {
stats.value = [
2024-07-03 14:13:22 +07:00
{
2024-07-04 14:44:56 +07:00
icon: 'mdi-office-building-outline',
2024-07-03 14:13:22 +07:00
count: _stats.hq,
label: 'branchHQLabel',
color: 'pink',
},
{
2024-07-04 14:44:56 +07:00
icon: 'mdi-home-group',
2024-07-03 14:13:22 +07:00
count: _stats.br,
label: 'branchLabel',
color: 'purple',
},
];
2024-04-16 18:33:41 +07:00
}
}
onMounted(async () => {
2024-07-02 09:22:06 +00:00
utilsStore.currentTitle.title = 'branchManagement';
utilsStore.currentTitle.path = [
{
text: 'branchManagementCaption',
handler: () => {
fieldSelectedBranch.value.value = 'branchHQLabel';
currentHq.value = {
id: '',
code: '',
};
},
},
];
2024-07-02 09:22:06 +00:00
await branchStore.fetchList({ pageSize: 99999 });
await calculateStats();
2024-06-25 16:08:46 +07:00
2024-07-18 09:10:51 +00:00
modeView.value = $q.screen.lt.md ? true : false;
2024-06-25 16:08:46 +07:00
flowStore.rotate();
2024-04-16 18:33:41 +07:00
});
2024-04-18 16:13:16 +07:00
const statusFilter = ref<'all' | 'statusACTIVE' | 'statusINACTIVE'>('all');
const beforeBranch = ref<{ id: string; code: string }>({
id: '',
2024-04-17 15:15:44 +07:00
code: '',
});
const inputSearch = ref<string>('');
const fieldBranch = ref(['all', 'branchHQLabel', 'branchLabel']);
2024-07-04 15:04:52 +07:00
const fieldDisplay = ref<
(
| 'branchLabelName'
| 'branchLabelAddress'
| 'branchLabelTel'
| 'branchLabelType'
)[]
>([
'branchLabelName',
'branchLabelTel',
'branchLabelAddress',
'branchLabelType',
]);
2024-07-04 15:04:52 +07:00
const fieldSelected = ref<
(
| 'branchLabelName'
| 'branchLabelAddress'
| 'branchLabelTel'
| 'branchLabelType'
)[]
2024-07-04 15:04:52 +07:00
>(fieldDisplay.value);
const fieldSelectedBranch = ref<{
label: string;
value: string;
}>({
2024-04-17 15:15:44 +07:00
label: t('branchHQLabel'),
value: 'branchHQLabel',
});
2024-07-03 14:13:22 +07:00
const stats = ref<
{ icon: string; count: number; label: string; color: 'pink' | 'purple' }[]
>([]);
2024-04-16 18:33:41 +07:00
const modeView = ref<boolean>(false);
const splitterModel = ref(25);
const defaultFormData = {
headOfficeId: null,
taxNo: '',
nameEN: '',
name: '',
addressEN: '',
address: '',
zipCode: '',
email: '',
contactName: '',
contact: '',
telephoneNo: '',
longitude: '',
latitude: '',
subDistrictId: '',
districtId: '',
provinceId: '',
lineId: '',
};
const formDialogRef = ref();
2024-04-18 18:07:38 +07:00
2024-04-18 15:47:53 +07:00
const formType = ref<'create' | 'edit' | 'delete' | 'view'>('create');
const formTypeBranch = ref<'headOffice' | 'subBranch'>('headOffice');
const currentHq = ref<{ id: string; code: string }>({ id: '', code: '' });
const currentEdit = ref<{ id: string; code: string }>({ id: '', code: '' });
2024-06-28 11:14:58 +07:00
const formData = ref<
Omit<BranchCreate & { codeHeadOffice?: string }, 'qrCodeImage' | 'imageUrl'>
>(structuredClone(defaultFormData));
2024-06-28 11:14:58 +07:00
const prevFormData = ref<
Omit<BranchCreate & { codeHeadOffice?: string }, 'qrCodeImage' | 'imageUrl'>
>(structuredClone(defaultFormData));
const modalDrawer = ref<boolean>(false);
function openDrawer() {
modalDrawer.value = true;
}
function openDialog() {
modal.value = true;
}
2024-04-18 15:10:54 +07:00
async function fetchBranchById(id: string) {
const res = await branchStore.fetchById(id, { includeContact: true });
2024-04-18 15:10:54 +07:00
if (res) {
qrCodeimageUrl.value = res.qrCodeImageUrl;
imageUrl.value = res.imageUrl;
2024-04-18 15:10:54 +07:00
formData.value = {
headOfficeId: res.headOfficeId,
taxNo: res.taxNo,
nameEN: res.nameEN,
name: res.name,
addressEN: res.addressEN,
address: res.address,
zipCode: res.zipCode,
email: res.email,
contactName: res.contactName,
contact: res.contact.length > 0 ? res.contact[0].telephoneNo : ' ',
2024-04-18 15:10:54 +07:00
telephoneNo: res.telephoneNo,
longitude: res.longitude,
latitude: res.latitude,
subDistrictId: res.subDistrictId,
districtId: res.districtId,
provinceId: res.provinceId,
lineId: res.lineId,
2024-04-18 18:07:38 +07:00
status: res.status,
2024-04-18 15:10:54 +07:00
};
}
}
function clearData() {
formData.value = structuredClone(defaultFormData);
imageUrl.value = null;
qrCodeimageUrl.value = null;
currentEdit.value = {
id: '',
code: '',
};
2024-04-18 15:10:54 +07:00
profileFile.value = undefined;
}
async function undo() {
formType.value = 'view';
formData.value = prevFormData.value;
2024-04-18 15:47:53 +07:00
}
function triggerCreate(
type: 'headOffice' | 'subBranch',
id?: string,
code?: string,
) {
clearData();
formTypeBranch.value = type;
if (type === 'headOffice') {
currentHq.value = {
id: id ?? '',
code: code ?? '',
};
}
2024-06-28 11:14:58 +07:00
if (type === 'subBranch' && id && code) {
formData.value.headOfficeId = id;
formData.value.codeHeadOffice = code;
}
formType.value = 'create';
openDialog();
}
function drawerEdit() {
formType.value = 'edit';
prevFormData.value = {
...formData.value,
};
}
async function triggerEdit(
openFormType: string,
id: string,
typeBranch: 'headOffice' | 'subBranch',
code?: string,
) {
await fetchBranchById(id);
if (openFormType === 'form') {
formType.value = 'edit';
openDialog();
2024-04-18 15:10:54 +07:00
}
if (openFormType === 'drawer') {
formType.value = 'view';
openDrawer();
}
if (typeBranch === 'headOffice') {
formData.value.codeHeadOffice = code;
}
const currentRecord = branchData.value.result.find((x) => x.id === id);
if (!currentRecord) return;
currentEdit.value = {
id: currentRecord.id,
code: currentRecord.code,
};
if (typeBranch === 'subBranch') {
const currentRecordHead = branchData.value.result.find(
(x) => x.id === currentRecord.headOfficeId,
);
formData.value.codeHeadOffice = currentRecordHead?.code;
if (currentRecordHead) {
currentHq.value.id = currentRecordHead.id;
currentHq.value.code = currentRecordHead.code;
} else {
currentHq.value = currentEdit.value;
}
}
formTypeBranch.value = typeBranch;
2024-04-18 15:10:54 +07:00
}
function triggerDelete(id: string) {
if (id) {
dialog({
color: 'negative',
icon: 'mdi-alert',
title: t('deleteConfirmTitle'),
actionText: t('agree'),
2024-04-18 15:10:54 +07:00
persistent: true,
message: t('deleteConfirmMessage'),
2024-04-18 15:10:54 +07:00
action: async () => {
await branchStore.deleteById(id);
await branchStore.fetchList({ pageSize: 99999 });
modalDrawer.value = false;
await calculateStats();
2024-06-26 17:03:49 +07:00
flowStore.rotate();
2024-04-18 15:10:54 +07:00
},
cancel: () => {},
});
}
}
async function onSubmit() {
2024-04-18 15:10:54 +07:00
if (formType.value === 'edit') {
delete formData.value['codeHeadOffice'];
await branchStore.editById(
currentEdit.value.id,
{
...formData.value,
status: undefined,
},
profileFile.value,
profileFileImg.value,
);
await branchStore.fetchList({ pageSize: 99999 });
modal.value = false;
modalDrawer.value = false;
2024-04-18 15:10:54 +07:00
}
if (formType.value === 'create') {
if (formTypeBranch.value === 'subBranch') {
const currentRecord = branchData.value.result.find(
(x) => x.id === formData.value.headOfficeId,
);
formData.value.headOfficeId = currentRecord?.id;
2024-06-28 11:14:58 +07:00
delete formData.value['codeHeadOffice'];
}
2024-04-18 15:10:54 +07:00
await branchStore.create({
...formData.value,
qrCodeImage: profileFile.value,
imageUrl: profileFileImg.value,
});
await branchStore.fetchList({ pageSize: 99999 });
modal.value = false;
}
const _stats = await branchStore.stats();
if (_stats) {
2024-04-23 14:43:00 +07:00
stats.value = [
{
2024-07-03 14:13:22 +07:00
icon: 'mdi-home',
2024-04-23 14:43:00 +07:00
count: _stats.hq,
label: 'branchHQLabel',
color: 'pink',
},
{
2024-07-03 14:13:22 +07:00
icon: 'mdi-domain',
2024-04-23 14:43:00 +07:00
count: _stats.br,
label: 'branchLabel',
color: 'purple',
},
];
}
2024-06-25 16:05:51 +07:00
flowStore.rotate();
}
function changeTitle(
2024-04-18 15:47:53 +07:00
formType: 'edit' | 'create' | 'delete' | 'view',
typeBranch: 'headOffice' | 'subBranch',
) {
if (typeBranch === 'headOffice') {
2024-04-18 15:47:53 +07:00
return formType === 'create'
? t('formDialogTitleCreateHeadOffice')
: formType === 'view'
? t('formDialogTitleViewHeadOffice')
: t('formDialogTitleEditHeadOffice');
}
if (typeBranch === 'subBranch') {
2024-04-18 15:47:53 +07:00
return formType === 'create'
? t('formDialogTitleCreateSubBranch')
: formType === 'view'
? t('formDialogTitleViewSubBranch')
: t('formDialogTitleEditSubBranch');
}
return '';
}
2024-07-19 04:56:08 +00:00
function handleHold(node: BranchWithChildren) {
if ($q.screen.gt.xs) return;
2024-07-19 04:56:08 +00:00
return function (props: unknown) {
holdDialog.value = true;
currentNode.value = node;
};
}
watch(locale, () => {
fieldSelectedBranch.value = {
label: t(`${fieldSelectedBranch.value.label}`),
value: fieldSelectedBranch.value.value,
};
});
2024-07-18 09:10:51 +00:00
watch(
() => $q.screen.lt.md,
(v) => {
if (v) modeView.value = true;
},
);
2024-04-02 17:47:32 +07:00
</script>
2024-04-16 18:33:41 +07:00
2024-04-02 17:47:32 +07:00
<template>
2024-07-02 09:22:06 +00:00
<div class="column full-height no-wrap">
2024-07-05 03:39:41 +00:00
<div class="text-body-2 q-mb-xs flex items-center">
{{ $t('branchStatTitle') }}
<q-btn
class="q-ml-xs"
icon="mdi-pin"
color="primary"
size="sm"
flat
dense
rounded
@click="hideStat = !hideStat"
:style="hideStat ? 'rotate: 90deg' : ''"
style="transition: 0.1s ease-in-out"
/>
</div>
<transition name="slide">
<StatCard
v-if="!hideStat"
class="q-pb-md"
label-i18n
:branch="
expandedTree[0]
? [
{
...stats[1],
count: (() => {
const foundItem = treeData.find(
(i) => i.id === expandedTree[0],
);
return foundItem ? foundItem._count.branch : 0;
})(),
},
]
: stats
"
2024-07-05 03:39:41 +00:00
:dark="$q.dark.isActive"
/>
</transition>
2024-07-16 02:52:38 +00:00
<div class="col surface-2 rounded" :no-padding="!!branchData.total">
2024-04-16 18:33:41 +07:00
<template v-if="!branchData.total">
2024-07-17 02:17:10 +00:00
<div class="full-width full-height column">
<div class="self-end q-ma-md">
<TooltipComponent
class="self-end"
title="branchNoMainOfficeYet"
caption="branchClickToCreateMainOffice"
imgSrc="personnel-table-"
/>
</div>
<div class="col flex items-center justify-center">
<AddButton
label="branchAdd"
@trigger="() => triggerCreate('headOffice')"
/>
</div>
2024-04-16 18:33:41 +07:00
</div>
</template>
2024-07-16 02:52:38 +00:00
2024-04-16 18:33:41 +07:00
<template v-else>
2024-07-16 02:52:38 +00:00
<div class="full-height column" style="flex-grow: 1; flex-wrap: nowrap">
<q-splitter
v-model="splitterModel"
2024-07-08 14:26:30 +07:00
:limits="[0, 100]"
2024-07-16 02:52:38 +00:00
class="col"
2024-07-18 04:51:09 +00:00
before-class="overflow-hidden"
2024-07-16 10:29:47 +00:00
after-class="overflow-hidden"
>
<template v-slot:before>
2024-07-16 02:52:38 +00:00
<div class="surface-1 column full-height">
<div
class="row no-wrap full-width bordered-b text-weight-bold surface-3 items-center q-px-md q-py-sm"
2024-07-16 02:52:38 +00:00
:style="`min-height: ${$q.screen.gt.sm ? '57px' : '100.8px'}`"
>
<div class="col ellipsis-2-lines">ดการสาขาทงหมด</div>
2024-07-05 09:23:45 +07:00
<q-btn
round
flat
size="md"
dense
id="hq-add-btn"
class="q-mr-sm"
@click="
() => {
if (!currentHq.id) {
triggerCreate('headOffice');
} else {
triggerCreate(
'subBranch',
currentHq.id,
currentHq.code,
);
}
}
"
2024-07-05 09:23:45 +07:00
>
<Icon
icon="pixelarticons:plus"
class="cursor-pointer"
style="color: var(--foreground); scale: 1.5"
/>
</q-btn>
</div>
<div class="col full-width">
<div class="q-pa-md">
2024-07-05 13:10:37 +07:00
<q-tree
:nodes="treeData"
node-key="id"
label-key="name"
children-key="branch"
2024-07-18 11:01:19 +00:00
color="transparent"
v-model:expanded="expandedTree"
2024-07-05 13:10:37 +07:00
style="color: var(--foreground)"
>
2024-07-05 13:10:37 +07:00
<template #default-header="{ node }">
2024-07-18 15:04:58 +07:00
<div
2024-07-23 02:48:17 +00:00
class="full-width q-py-xs"
:class="{ 'clickable-node': node.isHeadOffice }"
2024-07-19 04:56:08 +00:00
v-touch-hold.mouse="handleHold(node)"
2024-07-18 15:04:58 +07:00
@click.stop="
() => {
if (
node.isHeadOffice &&
node._count.branch !== 0 &&
currentHq.id === node.id
) {
expandedTree = expandedTree.filter(
(i) => node.id !== i,
);
fieldSelectedBranch.value = 'branchHQLabel';
currentHq = {
id: '',
code: '',
};
return;
}
if (
node.isHeadOffice &&
node._count.branch !== 0 &&
currentHq.id !== node.id
) {
expandedTree = [];
expandedTree.push(node.id);
fieldSelectedBranch.value = '';
inputSearch = '';
currentHq = {
id: node.id,
code: node.code,
};
beforeBranch = {
id: '',
code: '',
};
}
}
"
>
2024-07-05 13:10:37 +07:00
<div
2024-07-18 14:18:16 +07:00
class="row col items-center justify-between full-width no-wrap"
2024-07-05 13:10:37 +07:00
>
2024-07-23 02:26:15 +00:00
<q-icon
2024-07-23 04:08:55 +00:00
v-if="
node.isHeadOffice && node._count.branch !== 0
"
2024-07-23 02:26:15 +00:00
name="mdi-triangle-down"
size="12px"
class="app-text-muted q-mr-md"
:style="`rotate: ${expandedTree[0] === node.id ? '0deg' : '30deg'}`"
/>
<div class="col row">
<span
class="ellipsis col-12"
style="white-space: nowrap"
:class="{
'text-weight-bold':
expandedTree[0] === node.id,
'app-text-info': expandedTree[0] === node.id,
}"
>
{{ node.name }}
</span>
<span
class="app-text-muted text-caption ellipsis"
>
2024-07-18 11:01:19 +00:00
{{ node.code }}
</span>
</div>
2024-07-18 11:01:19 +00:00
2024-07-18 14:18:16 +07:00
<div
class="row q-gutter-xs items-center no-wrap"
@click.stop
v-if="$q.screen.gt.xs"
2024-07-05 13:10:37 +07:00
>
2024-07-18 14:18:16 +07:00
<q-btn
v-if="node.isHeadOffice"
:id="`create-sub-branch-btn-${node.name}`"
@click.stop="
triggerCreate('subBranch', node.id, node.code)
"
2024-07-18 11:01:19 +00:00
icon="mdi-file-plus"
class="app-text-muted-2"
2024-07-18 14:18:16 +07:00
size="sm"
dense
round
flat
/>
<q-btn
:id="`view-detail-btn-${node.name}`"
icon="mdi-dots-vertical"
2024-07-18 11:01:19 +00:00
class="app-text-muted-2"
2024-07-18 14:18:16 +07:00
size="sm"
dense
round
flat
>
<q-menu class="bordered">
<q-list v-close-popup>
<q-item
:id="`view-detail-btn-${node.name}-view`"
@click.stop="
2024-07-05 13:10:37 +07:00
if (node.isHeadOffice) {
triggerEdit(
2024-07-18 14:18:16 +07:00
'drawer',
2024-07-05 13:10:37 +07:00
node.id,
'headOffice',
node.code,
);
} else {
triggerEdit(
2024-07-18 14:18:16 +07:00
'drawer',
2024-07-05 13:10:37 +07:00
node.id,
'subBranch',
);
}
2024-07-18 14:18:16 +07:00
"
clickable
dense
class="row q-py-sm"
style="white-space: nowrap"
2024-07-05 13:10:37 +07:00
>
2024-07-18 14:18:16 +07:00
<q-icon
name="mdi-eye-outline"
class="col-3"
size="xs"
style="color: hsl(var(--green-6-hsl))"
/>
<span
class="col-9 q-px-md flex items-center"
>
{{ $t('viewDetail') }}
</span>
</q-item>
<q-item
:id="`view-detail-btn-${node.name}-edit`"
clickable
dense
class="row q-py-sm"
style="white-space: nowrap"
@click="
() => {
if (node.isHeadOffice) {
triggerEdit(
'form',
node.id,
'headOffice',
node.code,
);
} else {
triggerEdit(
'form',
node.id,
'subBranch',
);
}
}
"
>
<q-icon
name="mdi-pencil-outline"
class="col-3"
size="xs"
style="color: hsl(var(--cyan-6-hsl))"
/>
<span
class="col-9 q-px-md flex items-center"
>
{{ $t('edit') }}
</span>
</q-item>
<q-item
:id="`view-detail-btn-${node.name}-delete`"
dense
:clickable="node.status === 'CREATED'"
class="row"
2024-07-05 13:10:37 +07:00
:class="{
2024-07-18 14:18:16 +07:00
'surface-3': node.status !== 'CREATED',
'app-text-muted':
node.status !== 'CREATED',
2024-07-05 13:10:37 +07:00
}"
2024-07-18 14:18:16 +07:00
style="white-space: nowrap"
@click="triggerDelete(node.id)"
2024-07-05 13:10:37 +07:00
>
2024-07-18 14:18:16 +07:00
<q-icon
name="mdi-trash-can-outline"
size="xs"
class="col-3"
:class="{
'app-text-negative':
node.status === 'CREATED',
}"
/>
<span
class="col-9 q-px-md flex items-center"
>
{{ $t('delete') }}
</span>
</q-item>
<q-item dense>
<q-item-section class="q-py-sm">
<div class="q-pa-sm surface-2 rounded">
<q-toggle
:id="`view-detail-btn-${node.name}-status`"
dense
size="sm"
:label="
node.status !== 'INACTIVE'
? $t('switchOnLabel')
: $t('switchOffLabel')
"
@click="
async () => {
const res =
await branchStore.editById(
node.id,
{
status:
node.status !==
'INACTIVE'
? 'INACTIVE'
: 'ACTIVE',
},
);
if (res)
node.status = res.status;
}
"
:model-value="
node.status === 'CREATED' ||
node.status === 'ACTIVE'
"
/>
</div>
</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
</div>
</div>
2024-07-05 13:10:37 +07:00
</div>
</template>
</q-tree>
</div>
</div>
</div>
</template>
<template v-slot:after>
2024-07-16 10:29:47 +00:00
<div class="column full-height no-wrap">
<div
2024-07-16 02:52:38 +00:00
class="row q-py-sm q-px-md justify-between full-width surface-3 bordered-b"
>
2024-07-16 02:52:38 +00:00
<q-input
for="input-search"
outlined
dense
:label="$t('search')"
class="q-mr-md col-12 col-md-4"
:bg-color="$q.dark.isActive ? 'dark' : 'white'"
v-model="inputSearch"
debounce="200"
>
<template v-slot:prepend>
<q-icon name="mdi-magnify" />
</template>
</q-input>
2024-07-16 02:52:38 +00:00
<div
class="row col-12 col-md-6"
:class="{ 'q-pt-xs': $q.screen.lt.md }"
>
<q-select
v-model="statusFilter"
outlined
dense
2024-07-16 02:52:38 +00:00
option-value="value"
2024-07-18 04:51:09 +00:00
:hide-dropdown-icon="$q.screen.lt.sm"
2024-07-16 02:52:38 +00:00
option-label="label"
class="col"
map-options
emit-value
:options="[
{ label: $t('all'), value: 'all' },
{ label: $t('statusACTIVE'), value: 'statusACTIVE' },
{
label: $t('statusINACTIVE'),
value: 'statusINACTIVE',
},
]"
></q-select>
<q-select
id="select-field"
for="select-field"
:options="
fieldDisplay.map((v) => ({ label: $t(v), value: v }))
"
:display-value="$t('displayField')"
2024-07-18 04:51:09 +00:00
:hide-dropdown-icon="$q.screen.lt.sm"
2024-07-16 02:52:38 +00:00
class="col q-mx-sm"
v-model="fieldSelected"
option-label="label"
option-value="value"
map-options
emit-value
outlined
multiple
dense
/>
<q-btn-toggle
id="btn-mode"
2024-07-16 02:52:38 +00:00
v-model="modeView"
dense
2024-07-05 11:43:07 +07:00
class="no-shadow bordered rounded surface-1"
:toggle-color="$q.dark.isActive ? 'grey-9' : 'grey-2'"
size="xs"
:options="[
{ value: true, slot: 'folder' },
{ value: false, slot: 'list' },
]"
>
<template v-slot:folder>
<q-icon
name="mdi-view-grid-outline"
size="16px"
class="q-px-sm q-py-xs rounded"
:style="{
color: $q.dark.isActive
? modeView
? '#C9D3DB '
: '#787B7C'
: modeView
? '#787B7C'
: '#C9D3DB',
}"
/>
</template>
<template v-slot:list>
<q-icon
name="mdi-format-list-bulleted"
class="q-px-sm q-py-xs rounded"
size="16px"
:style="{
color: $q.dark.isActive
? modeView === false
? '#C9D3DB'
: '#787B7C'
: modeView === false
? '#787B7C'
: '#C9D3DB',
}"
/>
</template>
</q-btn-toggle>
</div>
</div>
2024-07-05 12:09:45 +07:00
2024-07-16 10:29:47 +00:00
<div class="surface-2 q-pa-md scroll full-width">
2024-07-16 02:52:38 +00:00
<q-table
flat
bordered
2024-07-16 10:29:47 +00:00
class="full-width"
2024-07-16 02:52:38 +00:00
:rows-per-page-options="[0]"
:rows="
treeData
.flatMap((v) => [v, ...v.branch])
.filter((v) => {
if (
statusFilter === 'statusACTIVE' &&
v.status === 'INACTIVE'
) {
return false;
}
if (
statusFilter === 'statusINACTIVE' &&
v.status !== 'INACTIVE'
) {
return false;
}
2024-07-05 12:09:45 +07:00
2024-07-16 02:52:38 +00:00
const terms = `${v.code} ${$i18n.locale === 'en-US' ? v.nameEN : v.name} ${v.telephoneNo}`;
if (inputSearch && !terms.includes(inputSearch)) {
return false;
}
if (
!!currentHq.id &&
currentHq.id === v.headOfficeId
) {
return true;
}
if (fieldSelectedBranch.value === 'all') return true;
if (fieldSelectedBranch.value === 'branchHQLabel')
return v.isHeadOffice;
if (fieldSelectedBranch.value === 'branchLabel')
return !v.isHeadOffice;
return false;
})
"
:columns="columns"
:grid="modeView"
card-container-class="row q-col-gutter-md"
row-key="name"
hide-pagination
:visible-columns="fieldSelected"
>
<template v-slot:header="props">
<q-tr class="surface-3" :props="props">
<q-th
v-for="col in props.cols"
:key="col.name"
:props="props"
>
{{ $t(col.label) }}
</q-th>
<q-th auto-width />
</q-tr>
</template>
<template v-slot:body="props">
<q-tr
:class="{
'app-text-muted': props.row.status === 'INACTIVE',
'cursor-pointer': props.row._count.branch !== 0,
}"
:props="props"
@click="
() => {
2024-07-05 12:09:45 +07:00
if (
2024-07-16 02:52:38 +00:00
props.row.isHeadOffice &&
props.row._count.branch !== 0
2024-07-05 12:09:45 +07:00
) {
2024-07-16 02:52:38 +00:00
fieldSelectedBranch.value = '';
inputSearch = '';
currentHq = {
id: props.row.id,
code: props.row.code,
};
beforeBranch = {
id: '',
code: '',
};
expandedTree = [];
expandedTree.push(props.row.id);
2024-07-05 12:09:45 +07:00
}
2024-07-16 02:52:38 +00:00
}
"
>
<q-td v-if="fieldSelected.includes('branchLabelName')">
<div class="row items-center">
<div
:class="{
'status-active':
props.row.status !== 'INACTIVE',
'status-inactive':
props.row.status === 'INACTIVE',
'branch-card__hq': props.row.isHeadOffice,
'branch-card__br': !props.row.isHeadOffice,
}"
style="
width: 50px;
display: flex;
margin-bottom: var(--size-2);
"
>
<div class="branch-card__icon">
<q-icon
size="md"
style="scale: 0.8"
name="mdi-office-building-outline"
/>
</div>
</div>
<div class="col">
<div class="col">{{ props.row.name }}</div>
<div class="col app-text-muted">
{{ props.row.code }}
</div>
</div>
</div>
</q-td>
<q-td
v-if="fieldSelected.includes('branchLabelAddress')"
>
{{ props.row.address }}
</q-td>
<q-td v-if="fieldSelected.includes('branchLabelTel')">
{{ props.row.contact[0]?.telephoneNo || '-' }}
</q-td>
<q-td v-if="fieldSelected.includes('branchLabelType')">
{{
props.row.isHeadOffice
? $t('branchHQLabel')
: $t('branchLabel')
}}
</q-td>
<q-td>
<q-btn
icon="mdi-dots-vertical"
size="sm"
dense
round
flat
@click.stop
2024-07-05 12:09:45 +07:00
>
2024-07-16 02:52:38 +00:00
<q-menu class="bordered">
<q-list v-close-popup>
<q-item
:id="`view-detail-btn-${props.row.name}-view`"
@click.stop="
if (props.row.isHeadOffice) {
triggerEdit(
'drawer',
props.row.id,
'headOffice',
props.row.code,
);
} else {
triggerEdit(
'drawer',
props.row.id,
'subBranch',
);
}
"
clickable
dense
class="row q-py-sm"
style="white-space: nowrap"
>
<q-icon
name="mdi-eye-outline"
class="col-3"
size="xs"
style="color: hsl(var(--green-6-hsl))"
/>
<span class="col-9 q-px-md flex items-center">
{{ $t('viewDetail') }}
</span>
</q-item>
<q-item
:id="`view-detail-btn-${props.row.name}-edit`"
clickable
dense
class="row q-py-sm"
style="white-space: nowrap"
@click="
() => {
if (props.row.isHeadOffice) {
triggerEdit(
'form',
props.row.id,
'headOffice',
props.row.code,
);
} else {
triggerEdit(
'form',
props.row.id,
'subBranch',
);
}
}
"
>
<q-icon
name="mdi-pencil-outline"
class="col-3"
size="xs"
style="color: hsl(var(--cyan-6-hsl))"
/>
<span class="col-9 q-px-md flex items-center">
{{ $t('edit') }}
</span>
</q-item>
<q-item
:id="`view-detail-btn-${props.row.name}-delete`"
dense
:clickable="props.row.status === 'CREATED'"
class="row"
:class="{
'surface-3': props.row.status !== 'CREATED',
'app-text-muted':
props.row.status !== 'CREATED',
}"
style="white-space: nowrap"
@click="triggerDelete(props.row.id)"
>
<q-icon
name="mdi-trash-can-outline"
size="xs"
class="col-3"
:class="{
'app-text-negative':
props.row.status === 'CREATED',
}"
/>
<span class="col-9 q-px-md flex items-center">
{{ $t('delete') }}
</span>
</q-item>
<q-item dense>
<q-item-section class="q-py-sm">
<div class="q-pa-sm surface-2 rounded">
<q-toggle
:id="`view-detail-btn-${props.row.name}-status`"
dense
size="sm"
:label="
props.row.status !== 'INACTIVE'
? $t('switchOnLabel')
: $t('switchOffLabel')
"
@click="
async () => {
const res =
await branchStore.editById(
props.row.id,
{
status:
props.row.status !==
'INACTIVE'
? 'INACTIVE'
: 'ACTIVE',
},
);
if (res)
props.row.status = res.status;
}
"
:model-value="
props.row.status === 'CREATED' ||
props.row.status === 'ACTIVE'
"
/>
</div>
</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
</q-td>
</q-tr>
</template>
<template v-slot:item="props">
<div class="col-12 col-md-6">
<BranchCard
2024-07-16 10:29:47 +00:00
class="surface-1"
2024-07-16 02:52:38 +00:00
:id="`branch-card-${props.row.name}`"
2024-07-05 12:09:45 +07:00
:class="{
2024-07-16 02:52:38 +00:00
'cursor-pointer': props.row._count.branch !== 0,
2024-07-05 12:09:45 +07:00
}"
@click="
() => {
2024-07-16 02:52:38 +00:00
if (
props.row.isHeadOffice &&
props.row._count.branch !== 0
) {
fieldSelectedBranch.value = '';
inputSearch = '';
currentHq = {
id: props.row.id,
code: props.row.code,
};
beforeBranch = {
id: '',
code: '',
};
expandedTree = [];
expandedTree.push(props.row.id);
}
}
"
2024-07-16 02:52:38 +00:00
:metadata="props.row"
:color="props.row.isHeadOffice ? 'hq' : 'br'"
:key="props.row.id"
:data="{
branchLabelCode: props.row.code,
branchLabelName:
$i18n.locale === 'en-US'
? props.row.nameEN
: props.row.name,
branchLabelTel: props.row.contact
.map((c: BranchContact) => c.telephoneNo)
.join(','),
branchLabelAddress:
$i18n.locale === 'en-US'
? `${props.row.addressEN || ''} ${props.row.subDistrict?.nameEN || ''} ${props.row.district?.nameEN || ''} ${props.row.province?.nameEN || ''}`
: `${props.row.address || ''} ${props.row.subDistrict?.name || ''} ${props.row.district?.name || ''} ${props.row.province?.name || ''}`,
branchLabelType: $t(
props.row.isHeadOffice
? 'branchHQLabel'
: 'branchLabel',
),
}"
:field-selected="fieldSelected"
:badge-field="['branchLabelStatus']"
:inactive="props.row.status === 'INACTIVE'"
@view-detail="
(v) => {
triggerEdit(
'drawer',
v.id,
v.isHeadOffice ? 'headOffice' : 'subBranch',
v.code,
);
}
"
2024-07-05 12:09:45 +07:00
>
2024-07-16 02:52:38 +00:00
<template v-slot:action>
<q-menu class="bordered">
<q-list>
<q-item
:id="`view-detail-btn-${props.row.name}-view`"
@click.stop="
if (props.row.isHeadOffice) {
triggerEdit(
'drawer',
props.row.id,
'headOffice',
props.row.code,
);
} else {
triggerEdit(
'drawer',
props.row.id,
'subBranch',
);
}
"
v-close-popup
clickable
dense
class="row q-py-sm"
style="white-space: nowrap"
>
2024-07-05 12:09:45 +07:00
<q-icon
2024-07-16 02:52:38 +00:00
name="mdi-eye-outline"
class="col-3"
size="xs"
style="color: hsl(var(--green-6-hsl))"
2024-07-05 12:09:45 +07:00
/>
2024-07-16 02:52:38 +00:00
<span class="col-9 q-px-md flex items-center">
{{ $t('viewDetail') }}
</span>
</q-item>
<q-item
:id="`view-detail-btn-${props.row.name}-edit`"
v-close-popup
clickable
dense
class="row q-py-sm"
style="white-space: nowrap"
@click="
() => {
2024-07-05 15:46:47 +07:00
if (props.row.isHeadOffice) {
triggerEdit(
2024-07-16 02:52:38 +00:00
'form',
2024-07-05 15:46:47 +07:00
props.row.id,
'headOffice',
props.row.code,
);
} else {
triggerEdit(
2024-07-16 02:52:38 +00:00
'form',
2024-07-05 15:46:47 +07:00
props.row.id,
'subBranch',
);
}
2024-07-16 02:52:38 +00:00
}
"
>
<q-icon
name="mdi-pencil-outline"
class="col-3"
size="xs"
style="color: hsl(var(--cyan-6-hsl))"
/>
<span class="col-9 q-px-md flex items-center">
{{ $t('edit') }}
</span>
</q-item>
<q-item
:id="`view-detail-btn-${props.row.name}-delete`"
dense
v-close-popup
:clickable="props.row.status === 'CREATED'"
class="row"
:class="{
'surface-3': props.row.status !== 'CREATED',
'app-text-muted':
props.row.status !== 'CREATED',
}"
style="white-space: nowrap"
@click="triggerDelete(props.row.id)"
>
<q-icon
name="mdi-trash-can-outline"
size="xs"
class="col-3"
2024-07-05 15:46:47 +07:00
:class="{
2024-07-16 02:52:38 +00:00
'app-text-negative':
props.row.status === 'CREATED',
2024-07-05 15:46:47 +07:00
}"
2024-07-16 02:52:38 +00:00
/>
<span class="col-9 q-px-md flex items-center">
{{ $t('delete') }}
</span>
</q-item>
<q-item dense>
<q-item-section class="q-py-sm">
<div class="q-pa-sm surface-2 rounded">
<q-toggle
:id="`view-detail-btn-${props.row.name}-status`"
dense
size="sm"
:label="
props.row.status !== 'INACTIVE'
? $t('switchOnLabel')
: $t('switchOffLabel')
"
@click="
async () => {
const res =
await branchStore.editById(
props.row.id,
{
status:
props.row.status !==
'INACTIVE'
? 'INACTIVE'
: 'ACTIVE',
},
);
if (res)
props.row.status = res.status;
}
"
:model-value="
props.row.status === 'CREATED' ||
props.row.status === 'ACTIVE'
"
/>
</div>
</q-item-section>
</q-item>
</q-list>
</q-menu>
</template>
</BranchCard>
</div>
</template>
</q-table>
</div>
</div>
</template>
</q-splitter>
</div>
2024-04-16 18:33:41 +07:00
</template>
2024-07-02 09:22:06 +00:00
</div>
2024-04-02 17:47:32 +07:00
</div>
<FormDialog
ref="formDialogRef"
v-model:modal="modal"
v-model:address="formData.address"
v-model:addressEN="formData.addressEN"
v-model:province-id="formData.provinceId"
v-model:district-id="formData.districtId"
v-model:sub-district-id="formData.subDistrictId"
v-model:zip-code="formData.zipCode"
:title="changeTitle(formType, formTypeBranch) + ' ' + currentEdit.code"
2024-04-18 15:47:53 +07:00
:titleFormAddress="$t('formDialogTitleAddress')"
:address-title="$t('formDialogAddress')"
:address-title-EN="$t('formDialogAddressEN')"
:addressSeparator="true"
:submit="
() => {
onSubmit();
}
"
2024-06-27 04:55:39 +00:00
:close="() => (modal = false)"
>
<template #information>
<FormBranchInformation
2024-06-28 11:14:58 +07:00
v-model:code="formData.codeHeadOffice"
v-model:code-sub-branch="currentEdit.code"
v-model:taxNo="formData.taxNo"
v-model:name="formData.name"
v-model:nameEN="formData.nameEN"
2024-04-18 18:07:38 +07:00
v-model:type-branch="formTypeBranch"
:separator="true"
:dense="true"
:outlined="true"
:readonly="formType === 'view'"
:view="formType === 'view'"
title="formDialogTitleInformation"
/>
</template>
<template #person>
<FormBranchContact
2024-06-28 10:49:23 +07:00
v-model:type-branch="formTypeBranch"
v-model:telephone-no="formData.telephoneNo"
v-model:contact="formData.contact"
v-model:email="formData.email"
v-model:contact-name="formData.contactName"
v-model:line-id="formData.lineId"
:separator="true"
title="formDialogTitleContact"
:dense="true"
:outlined="true"
/>
</template>
<template #qr-code>
<FormQr
2024-04-18 15:47:53 +07:00
title="QR Code"
:separator="true"
2024-04-18 15:10:54 +07:00
:qr="qrCodeimageUrl"
:readonly="formType === 'view'"
@upload="
() => {
inputFile.click();
}
"
/>
</template>
<template #location>
<FormLocation
:readonly="formType === 'view'"
:separator="true"
v-model:latitude="formData.latitude"
v-model:longitude="formData.longitude"
title="formDialogTitleLocation"
/>
</template>
<template #by-type>
<FormImage
:readonly="formType === 'view'"
v-model:image="imageUrl"
@upload="
() => {
inputFileImg.click();
}
"
:title="$t('formDialogTitleImg')"
/>
</template>
</FormDialog>
<DrawerInfo
ref="formDialogRef"
v-model:drawerOpen="modalDrawer"
:title="changeTitle(formType, formTypeBranch) + ' ' + currentEdit.code"
:titleFormAddress="$t('formDialogTitleAddress')"
:addressSeparator="true"
:undo="() => undo()"
:isEdit="formType === 'edit'"
:editData="() => drawerEdit()"
:submit="() => onSubmit()"
:delete-data="() => triggerDelete(currentEdit.id)"
2024-06-26 17:03:49 +07:00
:close="() => ((modalDrawer = false), flowStore.rotate())"
:statusBranch="formData.status"
>
<template #info>
2024-04-19 13:25:48 +07:00
<InfoForm
v-model:address="formData.address"
v-model:addressEN="formData.addressEN"
v-model:province-id="formData.provinceId"
v-model:district-id="formData.districtId"
v-model:sub-district-id="formData.subDistrictId"
v-model:zip-code="formData.zipCode"
:title-form-address="$t('formDialogTitleAddress')"
:address-title="$t('formDialogAddress')"
:address-title-e-n="$t('formDialogAddressEN')"
:readonly="formType === 'view'"
>
<template #information>
<FormBranchInformation
v-model:code="formData.codeHeadOffice"
v-model:code-sub-branch="currentEdit.code"
v-model:taxNo="formData.taxNo"
v-model:name="formData.name"
v-model:nameEN="formData.nameEN"
v-model:type-branch="formTypeBranch"
:separator="true"
:dense="true"
:outlined="true"
:readonly="formType === 'view'"
:view="formType === 'view'"
title="formDialogTitleInformation"
/>
</template>
<template #person>
<FormBranchContact
title="formDialogTitleContact"
v-model:telephone-no="formData.telephoneNo"
v-model:contact="formData.contact"
v-model:email="formData.email"
v-model:contact-name="formData.contactName"
v-model:line-id="formData.lineId"
:readonly="formType === 'view'"
:view="formType === 'view'"
:separator="true"
:dense="true"
:outlined="true"
/>
</template>
<template #qr-code>
<FormQr
:readonly="formType === 'view'"
title="QR Code"
:separator="true"
:qr="qrCodeimageUrl"
@upload="
() => {
inputFile.click();
}
"
/>
</template>
<template #location>
<FormLocation
title="formDialogTitleLocation"
v-model:latitude="formData.latitude"
v-model:longitude="formData.longitude"
:readonly="formType === 'view'"
:separator="true"
/>
</template>
<template #by-type>
<FormImage
@upload="
() => {
inputFileImg.click();
}
"
v-model:image="imageUrl"
:title="$t('formDialogTitleImg')"
:readonly="formType === 'view'"
/>
</template>
2024-04-19 13:25:48 +07:00
</InfoForm>
</template>
</DrawerInfo>
<q-dialog v-model="holdDialog" position="bottom">
<div class="surface-1 full-width rounded column q-pb-md">
<div class="flex q-py-sm justify-center full-width">
<div
class="rounded"
style="
width: 8%;
height: 4px;
background-color: hsla(0, 0%, 50%, 0.75);
"
></div>
</div>
2024-07-19 04:56:08 +00:00
<q-list v-if="currentNode">
<q-item
clickable
v-ripple
v-close-popup
@click.stop="
triggerCreate('subBranch', currentNode.id, currentNode.code)
"
>
<q-item-section avatar>
<q-icon name="mdi-file-plus" class="app-text-muted-2" />
</q-item-section>
<q-item-section>
{{ $t('formDialogTitleCreateSubBranch') }}
</q-item-section>
</q-item>
2024-07-19 04:56:08 +00:00
<q-item
clickable
v-ripple
v-close-popup
@click.stop="
if (currentNode.isHeadOffice) {
triggerEdit(
'drawer',
currentNode.id,
'headOffice',
currentNode.code,
);
} else {
triggerEdit('drawer', currentNode.id, 'subBranch');
}
"
>
<q-item-section avatar>
<q-icon
name="mdi-eye-outline"
style="color: hsl(var(--green-6-hsl))"
/>
</q-item-section>
<q-item-section>{{ $t('viewDetail') }}</q-item-section>
</q-item>
2024-07-19 04:56:08 +00:00
<q-item
clickable
v-ripple
v-close-popup
@click="
() => {
if (currentNode && currentNode.isHeadOffice) {
triggerEdit(
'form',
currentNode.id,
'headOffice',
currentNode.code,
);
} else {
currentNode && triggerEdit('form', currentNode.id, 'subBranch');
}
}
"
>
<q-item-section avatar>
<q-icon
name="mdi-pencil-outline"
style="color: hsl(var(--cyan-6-hsl))"
/>
</q-item-section>
<q-item-section>{{ $t('edit') }}</q-item-section>
</q-item>
2024-07-19 04:56:08 +00:00
<q-item
clickable
v-ripple
v-close-popup
@click="triggerDelete(currentNode.id)"
>
<q-item-section avatar>
<q-icon name="mdi-trash-can-outline" class="app-text-negative" />
</q-item-section>
<q-item-section>{{ $t('delete') }}</q-item-section>
</q-item>
<q-item clickable v-ripple>
<q-item-section avatar>
2024-07-19 04:56:08 +00:00
<q-toggle
dense
:id="`view-detail-btn-${currentNode.name}-status`"
size="sm"
@click="
async () => {
if (!currentNode) return;
const res = await branchStore.editById(currentNode.id, {
status:
currentNode.status !== 'INACTIVE' ? 'INACTIVE' : 'ACTIVE',
});
if (res) currentNode.status = res.status;
}
"
:model-value="
currentNode.status === 'CREATED' ||
currentNode.status === 'ACTIVE'
"
/>
</q-item-section>
<q-item-section>
{{
currentNode.status !== 'INACTIVE'
? $t('switchOnLabel')
: $t('switchOffLabel')
}}
</q-item-section>
</q-item>
</q-list>
</div>
</q-dialog>
2024-04-02 17:47:32 +07:00
</template>
<style scoped>
2024-04-17 15:15:44 +07:00
.color-icon-arrow {
color: var(--gray-3);
}
.color-icon-plus {
color: var(--cyan-6);
}
2024-04-16 18:33:41 +07:00
.tree-container {
width: 100%;
min-width: 300px;
max-width: 25%;
max-height: 100%;
}
2024-04-16 18:33:41 +07:00
.branch-wrapper {
flex-grow: 1;
2024-04-16 18:33:41 +07:00
& > .branch-container {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-template-rows: unset;
gap: var(--size-4);
}
}
.branch-card__hq {
--_branch-card-bg: var(--pink-6-hsl);
}
.branch-card__br {
--_branch-card-bg: var(--violet-11-hsl);
&.branch-card__dark {
--_branch-card-bg: var(--violet-10-hsl);
}
}
.status-active {
--_branch-status-color: var(--green-6-hsl);
}
.status-inactive {
--_branch-status-color: var(--red-4-hsl);
--_branch-badge-bg: var(--red-4-hsl);
filter: grayscale(1);
opacity: 0.5;
}
.branch-card__icon {
background-color: hsla(var(--_branch-card-bg) / 0.15);
border-radius: 50%;
padding: var(--size-1);
position: relative;
transform: rotate(45deg);
&::after {
content: ' ';
display: block;
block-size: 0.5rem;
aspect-ratio: 1;
position: absolute;
border-radius: 50%;
right: -0.25rem;
top: calc(50% - 0.25rem);
bottom: calc(50% - 0.25rem);
background-color: hsla(var(--_branch-status-color) / 1);
}
& :deep(.q-icon) {
transform: rotate(-45deg);
color: hsla(var(--_branch-card-bg) / 1);
}
}
2024-07-05 03:39:41 +00:00
.slide-enter-active {
transition: all 0.1s ease-out;
}
.slide-leave-active {
transition: all 0.1s cubic-bezier(1, 0.5, 0.8, 1);
}
.slide-enter-from,
.slide-leave-to {
transform: translateY(-20px);
opacity: 0;
}
2024-07-23 02:26:15 +00:00
* :deep(.q-icon.mdi-play) {
display: none;
}
</style>