Merge branch 'feat/handle-role' into develop
Some checks failed
Spell Check / Spell Check with Typos (push) Failing after 6s
Some checks failed
Spell Check / Spell Check with Typos (push) Failing after 6s
This commit is contained in:
commit
f08c83c98b
44 changed files with 430 additions and 237 deletions
|
|
@ -89,15 +89,7 @@ defineProps<{
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style="
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background: hsla(0 0% 0% / 0.1);
|
||||
margin-bottom: var(--size-2);
|
||||
"
|
||||
/>
|
||||
<q-separator />
|
||||
<slot name="data"></slot>
|
||||
<template v-if="!$slots.data">
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ const prop = withDefaults(
|
|||
inTable?: boolean;
|
||||
addButton?: boolean;
|
||||
prefixId?: string;
|
||||
hideAction?: boolean;
|
||||
hideDelete?: boolean;
|
||||
}>(),
|
||||
{
|
||||
gridView: false,
|
||||
|
|
@ -265,9 +267,10 @@ defineEmits<{
|
|||
@click.stop="$emit('view', props.row)"
|
||||
/>
|
||||
<KebabAction
|
||||
v-if="!inTable"
|
||||
v-if="!inTable && !hideAction"
|
||||
:id-name="props.row.firstName"
|
||||
:status="props.row.status"
|
||||
:hide-delete="hideDelete"
|
||||
@view="$emit('view', props.row)"
|
||||
@edit="$emit('edit', props.row)"
|
||||
@delete="$emit('delete', props.row)"
|
||||
|
|
@ -280,9 +283,11 @@ defineEmits<{
|
|||
<template v-slot:item="props">
|
||||
<div class="col-12 col-md-3 col-sm-6">
|
||||
<PersonCard
|
||||
history
|
||||
:hide-delete="hideDelete"
|
||||
:hide-action="hideAction"
|
||||
:id="`card-${props.row.firstNameEN}`"
|
||||
:field-selected="fieldSelected"
|
||||
history
|
||||
:prefix-id="props.row.firstNameEN ?? props.rowIndex"
|
||||
:data="{
|
||||
code: props.row.code,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import { QField } from 'quasar';
|
|||
defineProps<{
|
||||
readonly?: boolean;
|
||||
onDrawer?: boolean;
|
||||
hideAction?: boolean;
|
||||
}>();
|
||||
|
||||
const { t } = useI18n();
|
||||
|
|
@ -201,6 +202,7 @@ onMounted(async () => {
|
|||
:class="{ 'q-ml-lg': $q.screen.gt.xs, 'q-mt-sm': $q.screen.lt.sm }"
|
||||
>
|
||||
<ToggleButton
|
||||
:disable="hideAction"
|
||||
class="q-mr-sm"
|
||||
two-way
|
||||
:model-value="flowData.status !== 'INACTIVE'"
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ defineProps<{
|
|||
readonly?: boolean;
|
||||
onDrawer?: boolean;
|
||||
inputOnly?: boolean;
|
||||
disableToggle?: boolean;
|
||||
}>();
|
||||
|
||||
defineEmits<{
|
||||
|
|
@ -76,6 +77,7 @@ defineEmits<{
|
|||
<ToggleButton
|
||||
class="q-mr-sm"
|
||||
two-way
|
||||
:disable="disableToggle"
|
||||
:model-value="status !== 'INACTIVE'"
|
||||
@click="
|
||||
() => {
|
||||
|
|
@ -195,8 +197,8 @@ defineEmits<{
|
|||
}
|
||||
|
||||
:deep(
|
||||
.q-item__section.column.q-item__section--side.justify-center.q-item__section--avatar.q-focusable.relative-position.cursor-pointer
|
||||
) {
|
||||
.q-item__section.column.q-item__section--side.justify-center.q-item__section--avatar.q-focusable.relative-position.cursor-pointer
|
||||
) {
|
||||
justify-content: start !important;
|
||||
padding-right: 8px !important;
|
||||
padding-top: 16px;
|
||||
|
|
@ -208,15 +210,15 @@ defineEmits<{
|
|||
}
|
||||
|
||||
:deep(
|
||||
i.q-icon.mdi.mdi-chevron-down-circle.q-expansion-item__toggle-icon.q-expansion-item__toggle-icon--rotated
|
||||
) {
|
||||
i.q-icon.mdi.mdi-chevron-down-circle.q-expansion-item__toggle-icon.q-expansion-item__toggle-icon--rotated
|
||||
) {
|
||||
color: var(--brand-1);
|
||||
}
|
||||
|
||||
:deep(
|
||||
.q-item.q-item-type.row.no-wrap.q-item--dense.q-item--clickable.q-link.cursor-pointer.q-focusable.q-hoverable.expansion-rounded.surface-2
|
||||
.q-focus-helper
|
||||
) {
|
||||
.q-item.q-item-type.row.no-wrap.q-item--dense.q-item--clickable.q-link.cursor-pointer.q-focusable.q-hoverable.expansion-rounded.surface-2
|
||||
.q-focus-helper
|
||||
) {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ const props = withDefaults(
|
|||
page?: number;
|
||||
pageSize?: number;
|
||||
hideBtnPreview?: boolean;
|
||||
hideAction?: boolean;
|
||||
}>(),
|
||||
{
|
||||
row: () => [],
|
||||
|
|
@ -149,6 +150,7 @@ defineEmits<{
|
|||
/>
|
||||
|
||||
<KebabAction
|
||||
v-if="!hideAction"
|
||||
:idName="`btn-kebab-${props.row.workName}`"
|
||||
status="'ACTIVE'"
|
||||
hide-toggle
|
||||
|
|
|
|||
|
|
@ -229,6 +229,7 @@ const smallBanner = ref(false);
|
|||
|
||||
<ToggleButton
|
||||
v-if="useToggle"
|
||||
:disable="readonly"
|
||||
two-way
|
||||
:model-value="toggleStatus !== 'INACTIVE'"
|
||||
@click="$emit('update:toggleStatus', toggleStatus)"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import { BranchWithChildren } from 'stores/branch/types';
|
||||
import KebabAction from './shared/KebabAction.vue';
|
||||
import { isRoleInclude } from 'stores/utils';
|
||||
|
||||
const nodes = defineModel<(any | BranchWithChildren)[]>('nodes', {
|
||||
default: [],
|
||||
|
|
@ -120,11 +119,7 @@ defineEmits<{
|
|||
/>
|
||||
|
||||
<q-btn
|
||||
v-if="
|
||||
node.isHeadOffice &&
|
||||
typeTree === 'branch' &&
|
||||
isRoleInclude(['head_of_admin', 'admin', 'system'])
|
||||
"
|
||||
v-if="node.isHeadOffice && typeTree === 'branch'"
|
||||
:id="`create-sub-branch-btn-${node.name}`"
|
||||
@click.stop="$emit('create', node)"
|
||||
icon="mdi-file-plus-outline"
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ defineProps<{
|
|||
history?: boolean;
|
||||
prefixId?: string;
|
||||
separateEnter?: boolean;
|
||||
hideAction?: boolean;
|
||||
hideDelete?: boolean;
|
||||
}>();
|
||||
|
||||
defineEmits<{
|
||||
|
|
@ -76,8 +78,10 @@ defineEmits<{
|
|||
/>
|
||||
|
||||
<KebabAction
|
||||
v-if="!hideAction"
|
||||
:id-name="prefixId"
|
||||
:status="disabled ? 'INACTIVE' : 'ACTIVE'"
|
||||
:hide-delete="hideDelete"
|
||||
@view="
|
||||
separateEnter
|
||||
? $emit('viewCard', 'INFO')
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import useMyBranch from 'stores/my-branch';
|
|||
import { getUserId, getRole } from 'src/services/keycloak';
|
||||
import { useQuasar } from 'quasar';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { isRoleInclude } from 'src/stores/utils';
|
||||
import { canAccess } from 'src/stores/utils';
|
||||
|
||||
type Menu = {
|
||||
label: string;
|
||||
|
|
@ -71,82 +71,41 @@ function initMenu() {
|
|||
{
|
||||
label: 'branch',
|
||||
route: '/branch-management',
|
||||
hidden: !isRoleInclude([
|
||||
'system',
|
||||
'head_of_admin',
|
||||
'admin',
|
||||
'branch_manager',
|
||||
'head_of_accountant',
|
||||
]),
|
||||
hidden: !canAccess('branch'),
|
||||
},
|
||||
{
|
||||
label: 'personnel',
|
||||
route: '/personnel-management',
|
||||
hidden: !isRoleInclude([
|
||||
'owner',
|
||||
'system',
|
||||
'head_of_admin',
|
||||
'admin',
|
||||
'branch_manager',
|
||||
]),
|
||||
hidden: !canAccess('personnel'),
|
||||
},
|
||||
{
|
||||
label: 'workflow',
|
||||
route: '/workflow',
|
||||
hidden: !isRoleInclude(['system', 'head_of_admin', 'admin']),
|
||||
hidden: !canAccess('workflow'),
|
||||
},
|
||||
{
|
||||
label: 'property',
|
||||
route: '/property',
|
||||
hidden: !isRoleInclude(['system', 'head_of_admin', 'admin']),
|
||||
hidden: !canAccess('workflow'),
|
||||
},
|
||||
{
|
||||
label: 'productService',
|
||||
route: '/product-service',
|
||||
hidden: !isRoleInclude([
|
||||
'system',
|
||||
'head_of_admin',
|
||||
'admin',
|
||||
'branch_manager',
|
||||
'head_of_accountant',
|
||||
'head_of_sale',
|
||||
'sale',
|
||||
]),
|
||||
},
|
||||
{
|
||||
label: 'customer',
|
||||
route: '/customer-management',
|
||||
hidden: !isRoleInclude([
|
||||
'system',
|
||||
'head_of_admin',
|
||||
'admin',
|
||||
'branch_manager',
|
||||
'head_of_accountant',
|
||||
'accountant',
|
||||
'head_of_sale',
|
||||
'sale',
|
||||
]),
|
||||
hidden: !canAccess('customer'),
|
||||
},
|
||||
{
|
||||
label: 'agencies',
|
||||
route: '/agencies-management',
|
||||
hidden: !isRoleInclude(['system', 'head_of_admin', 'admin']),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'menu.sales',
|
||||
icon: 'mdi-store-settings-outline',
|
||||
hidden: !isRoleInclude([
|
||||
'system',
|
||||
'head_of_admin',
|
||||
'admin',
|
||||
'branch_manager',
|
||||
'head_of_accountant',
|
||||
'accountant',
|
||||
'head_of_sale',
|
||||
'sale',
|
||||
]),
|
||||
children: [
|
||||
{ label: 'quotation', route: '/quotation' },
|
||||
{ label: 'invoice', route: '/invoice' },
|
||||
|
|
@ -169,16 +128,6 @@ function initMenu() {
|
|||
label: 'menu.account',
|
||||
icon: 'mdi-bank-outline',
|
||||
disabled: false,
|
||||
hidden: !isRoleInclude([
|
||||
'system',
|
||||
'head_of_admin',
|
||||
'admin',
|
||||
'branch_manager',
|
||||
'head_of_accountant',
|
||||
'accountant',
|
||||
'head_of_sale',
|
||||
'sale',
|
||||
]),
|
||||
children: [
|
||||
{ label: 'receipt', route: '/receipt' },
|
||||
{ label: 'creditNote', route: '/credit-note' },
|
||||
|
|
@ -200,10 +149,13 @@ function initMenu() {
|
|||
{
|
||||
label: 'menu.overall',
|
||||
icon: 'mdi-monitor-dashboard',
|
||||
hidden: !isRoleInclude(['system', 'head_of_admin', 'admin', 'executive']),
|
||||
children: [
|
||||
{ label: 'report', route: '/report' },
|
||||
{ label: 'dashboard', route: '/dash-board' },
|
||||
{
|
||||
label: 'dashboard',
|
||||
route: '/dash-board',
|
||||
hidden: !canAccess('dashBoard'),
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import type { QTableProps, QTableSlots } from 'quasar';
|
|||
import { resetScrollBar } from 'src/stores/utils';
|
||||
import useBranchStore from 'stores/branch';
|
||||
import useFlowStore from 'stores/flow';
|
||||
import { isRoleInclude } from 'stores/utils';
|
||||
import { isRoleInclude, canAccess } from 'stores/utils';
|
||||
import {
|
||||
BranchWithChildren,
|
||||
BranchCreate,
|
||||
|
|
@ -1050,7 +1050,7 @@ watch(currentHq, () => {
|
|||
{{ $t('branch.allBranch') }}
|
||||
</div>
|
||||
<q-btn
|
||||
v-if="isRoleInclude(['head_of_admin', 'admin', 'system'])"
|
||||
v-if="isRoleInclude(['system'])"
|
||||
round
|
||||
flat
|
||||
size="md"
|
||||
|
|
@ -1561,6 +1561,16 @@ watch(currentHq, () => {
|
|||
</q-td>
|
||||
<q-td>
|
||||
<KebabAction
|
||||
v-if="
|
||||
isRoleInclude([
|
||||
'system',
|
||||
'head_of_admin',
|
||||
'admin',
|
||||
'executive',
|
||||
'accountant',
|
||||
]) ||
|
||||
(canAccess('branch') && currentHq.id)
|
||||
"
|
||||
:status="props.row.status"
|
||||
:idName="props.row.name"
|
||||
@view="
|
||||
|
|
@ -1702,6 +1712,16 @@ watch(currentHq, () => {
|
|||
>
|
||||
<template v-slot:action>
|
||||
<KebabAction
|
||||
v-if="
|
||||
isRoleInclude([
|
||||
'system',
|
||||
'head_of_admin',
|
||||
'admin',
|
||||
'executive',
|
||||
'accountant',
|
||||
]) ||
|
||||
(canAccess('branch') && currentHq.id)
|
||||
"
|
||||
:status="props.row.status"
|
||||
:idName="props.row.name"
|
||||
@view="
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { baseUrl } from 'src/stores/utils';
|
|||
import useCustomerStore from 'stores/customer';
|
||||
import useFlowStore from 'stores/flow';
|
||||
import useOptionStore from 'stores/options';
|
||||
import { dialog } from 'stores/utils';
|
||||
import { dialog, canAccess } from 'stores/utils';
|
||||
|
||||
import { Status } from 'stores/types';
|
||||
import { Employee } from 'stores/employee/types';
|
||||
|
|
@ -285,7 +285,7 @@ watch(
|
|||
<template>
|
||||
<FloatingActionButton
|
||||
style="z-index: 999"
|
||||
v-if="$route.name !== 'CustomerManagement'"
|
||||
v-if="$route.name !== 'CustomerManagement' && canAccess('customer', 'edit')"
|
||||
@click="openEmployerBranchForm('create')"
|
||||
hide-icon
|
||||
></FloatingActionButton>
|
||||
|
|
@ -615,7 +615,7 @@ watch(
|
|||
<div class="text-center">
|
||||
<TableEmpoloyee
|
||||
:prefix-id="props.row.registerName || props.row.firstName"
|
||||
add-button
|
||||
:add-button="canAccess('customer', 'edit')"
|
||||
in-table
|
||||
:list-employee="listEmployee"
|
||||
:columns-employee="columnsEmployee"
|
||||
|
|
@ -759,7 +759,10 @@ watch(
|
|||
/>
|
||||
<DeleteButton
|
||||
icon-only
|
||||
v-if="customerBranchFormState.dialogType === 'info'"
|
||||
v-if="
|
||||
customerBranchFormState.dialogType === 'info' &&
|
||||
canAccess('customer', 'edit')
|
||||
"
|
||||
@click="
|
||||
() => {
|
||||
deleteBranchById(customerBranchFormData.id || '');
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { useRoute, useRouter } from 'vue-router';
|
|||
import { getUserId, getRole } from 'src/services/keycloak';
|
||||
import { baseUrl, setPrefixName, waitAll } from 'src/stores/utils';
|
||||
import { dateFormat } from 'src/utils/datetime';
|
||||
import { dialogCheckData } from 'stores/utils';
|
||||
import { dialogCheckData, canAccess } from 'stores/utils';
|
||||
|
||||
import useOcrStore from 'stores/ocr';
|
||||
import useCustomerStore from 'stores/customer';
|
||||
|
|
@ -397,7 +397,11 @@ async function fetchListEmployee(opt?: {
|
|||
employeeStats.value = await employeeStore.getStatsEmployee();
|
||||
}
|
||||
|
||||
async function triggerChangeStatus(id: string, status: string) {
|
||||
async function triggerChangeStatus(
|
||||
id: string,
|
||||
status: string,
|
||||
employeeName?: string,
|
||||
) {
|
||||
return await new Promise((resolve, reject) => {
|
||||
dialog({
|
||||
color: status !== 'INACTIVE' ? 'warning' : 'info',
|
||||
|
|
@ -412,7 +416,11 @@ async function triggerChangeStatus(id: string, status: string) {
|
|||
: t('dialog.message.confirmChangeStatusOn'),
|
||||
action: async () => {
|
||||
if (currentTab.value === 'employee') {
|
||||
await toggleStatusEmployee(id, status === 'INACTIVE' ? false : true)
|
||||
await toggleStatusEmployee(
|
||||
id,
|
||||
status === 'INACTIVE' ? false : true,
|
||||
employeeName,
|
||||
)
|
||||
.then(resolve)
|
||||
.catch(reject);
|
||||
} else {
|
||||
|
|
@ -426,9 +434,14 @@ async function triggerChangeStatus(id: string, status: string) {
|
|||
});
|
||||
}
|
||||
|
||||
async function toggleStatusEmployee(id: string, status: boolean) {
|
||||
async function toggleStatusEmployee(
|
||||
id: string,
|
||||
status: boolean,
|
||||
employeeName: string,
|
||||
) {
|
||||
const res = await employeeStore.editById(id, {
|
||||
status: !status ? 'ACTIVE' : 'INACTIVE',
|
||||
firstNameEN: employeeName,
|
||||
});
|
||||
if (res && employeeFormState.value.drawerModal)
|
||||
currentFromDataEmployee.value.status = res.status;
|
||||
|
|
@ -658,7 +671,7 @@ const emptyCreateDialog = ref(false);
|
|||
<FloatingActionButton
|
||||
style="z-index: 999"
|
||||
:hide-icon="currentTab === 'employee'"
|
||||
v-if="$route.name === 'CustomerManagement'"
|
||||
v-if="$route.name === 'CustomerManagement' && canAccess('customer', 'edit')"
|
||||
@click="
|
||||
() => {
|
||||
if (currentTab === 'employee') {
|
||||
|
|
@ -1391,6 +1404,7 @@ const emptyCreateDialog = ref(false);
|
|||
/>
|
||||
|
||||
<KebabAction
|
||||
:hide-delete="!canAccess('customer', 'edit')"
|
||||
:id-name="
|
||||
props.row.branch[0].customerName ||
|
||||
props.row.branch[0].firstName
|
||||
|
|
@ -1638,7 +1652,17 @@ const emptyCreateDialog = ref(false);
|
|||
</div>
|
||||
</template>
|
||||
<template v-slot:action>
|
||||
<q-btn
|
||||
icon="mdi-eye-outline"
|
||||
:id="`btn-eye-${props.row.branch[0].customerName || props.row.branch[0].firstName}`"
|
||||
size="sm"
|
||||
dense
|
||||
round
|
||||
flat
|
||||
@click.stop="editCustomerForm(props.row.id)"
|
||||
/>
|
||||
<KebabAction
|
||||
:hide-delete="!canAccess('customer', 'edit')"
|
||||
:status="props.row.status"
|
||||
:id-name="props.row.name"
|
||||
@view="
|
||||
|
|
@ -1772,6 +1796,7 @@ const emptyCreateDialog = ref(false);
|
|||
"
|
||||
>
|
||||
<TableEmpoloyee
|
||||
:hide-delete="!canAccess('customer', 'edit')"
|
||||
v-model:page-size="pageSize"
|
||||
v-model:current-page="currentPageEmployee"
|
||||
:grid-view="gridView"
|
||||
|
|
@ -1819,7 +1844,11 @@ const emptyCreateDialog = ref(false);
|
|||
"
|
||||
@toggle-status="
|
||||
async (item: any) => {
|
||||
triggerChangeStatus(item.id, item.status);
|
||||
triggerChangeStatus(
|
||||
item.id,
|
||||
item.status,
|
||||
item.firstNameEN,
|
||||
);
|
||||
}
|
||||
"
|
||||
/>
|
||||
|
|
@ -1889,6 +1918,7 @@ const emptyCreateDialog = ref(false);
|
|||
"
|
||||
>
|
||||
<TooltipComponent
|
||||
v-if="canAccess('customer', 'edit')"
|
||||
class="self-end q-ma-md"
|
||||
:title="'general.noData'"
|
||||
:caption="'general.clickToCreate'"
|
||||
|
|
@ -1900,6 +1930,7 @@ const emptyCreateDialog = ref(false);
|
|||
style="flex-grow: 1"
|
||||
>
|
||||
<EmptyAddButton
|
||||
v-if="canAccess('customer', 'edit')"
|
||||
:label="'general.add'"
|
||||
:i18n-args="{
|
||||
text: $t(`customer.${currentTab}`),
|
||||
|
|
@ -1914,6 +1945,7 @@ const emptyCreateDialog = ref(false);
|
|||
}
|
||||
"
|
||||
/>
|
||||
<NoData v-else />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
|
@ -4423,6 +4455,7 @@ const emptyCreateDialog = ref(false);
|
|||
(customerFormState.branchIndex !== -1 &&
|
||||
customerFormState.branchIndex !== idx)
|
||||
"
|
||||
:hide-delete="!canAccess('customer', 'edit')"
|
||||
:readonly="customerFormState.branchIndex !== idx"
|
||||
@edit="() => (customerFormState.branchIndex = idx)"
|
||||
@cancel="() => customerFormUndo(false)"
|
||||
|
|
@ -4463,11 +4496,18 @@ const emptyCreateDialog = ref(false);
|
|||
}
|
||||
"
|
||||
:title="
|
||||
employeeFormState.currentEmployee
|
||||
? $i18n.locale === 'eng'
|
||||
? `${employeeFormState.currentEmployee.firstNameEN} ${employeeFormState.currentEmployee.lastNameEN}`
|
||||
: `${employeeFormState.currentEmployee.firstName} ${employeeFormState.currentEmployee.lastName}`
|
||||
: '-'
|
||||
setPrefixName(
|
||||
{
|
||||
namePrefix: employeeFormState.currentEmployee.namePrefix,
|
||||
firstName:
|
||||
employeeFormState.currentEmployee.firstName ||
|
||||
employeeFormState.currentEmployee.firstNameEN,
|
||||
lastName: employeeFormState.currentEmployee.lastName,
|
||||
firstNameEN: employeeFormState.currentEmployee.firstNameEN,
|
||||
lastNameEN: employeeFormState.currentEmployee.lastNameEN,
|
||||
},
|
||||
{ locale },
|
||||
)
|
||||
"
|
||||
:badge-class="
|
||||
currentFromDataEmployee.gender === 'male'
|
||||
|
|
@ -4562,7 +4602,11 @@ const emptyCreateDialog = ref(false);
|
|||
@update:toggle-status="
|
||||
(v) => {
|
||||
if (currentFromDataEmployee.id !== undefined)
|
||||
triggerChangeStatus(currentFromDataEmployee.id, v);
|
||||
triggerChangeStatus(
|
||||
currentFromDataEmployee.id,
|
||||
v,
|
||||
currentFromDataEmployee.firstNameEN,
|
||||
);
|
||||
}
|
||||
"
|
||||
:active="currentFromDataEmployee.status !== 'INACTIVE'"
|
||||
|
|
@ -4582,7 +4626,9 @@ const emptyCreateDialog = ref(false);
|
|||
? setPrefixName(
|
||||
{
|
||||
namePrefix: employeeFormState.currentEmployee.namePrefix,
|
||||
firstName: employeeFormState.currentEmployee.firstName,
|
||||
firstName:
|
||||
employeeFormState.currentEmployee.firstName ||
|
||||
employeeFormState.currentEmployee.firstNameEN,
|
||||
lastName: employeeFormState.currentEmployee.lastName,
|
||||
firstNameEN: employeeFormState.currentEmployee.firstNameEN,
|
||||
lastNameEN: employeeFormState.currentEmployee.lastNameEN,
|
||||
|
|
@ -4878,7 +4924,10 @@ const emptyCreateDialog = ref(false);
|
|||
type="button"
|
||||
/>
|
||||
<DeleteButton
|
||||
v-if="!employeeFormState.isEmployeeEdit"
|
||||
v-if="
|
||||
!employeeFormState.isEmployeeEdit &&
|
||||
canAccess('customer', 'edit')
|
||||
"
|
||||
id="btn-info-basic-delete"
|
||||
icon-only
|
||||
@click="
|
||||
|
|
|
|||
|
|
@ -102,7 +102,13 @@ const telephoneNo = defineModel<string>('telephoneNo', { default: '' });
|
|||
class="col-md-6"
|
||||
:readonly
|
||||
:disabled="
|
||||
!isRoleInclude(['admin', 'system', 'head_of_admin']) && !readonly
|
||||
!isRoleInclude([
|
||||
'admin',
|
||||
'system',
|
||||
'head_of_admin',
|
||||
'executive',
|
||||
'accountant',
|
||||
]) && !readonly
|
||||
"
|
||||
:label="$t('customer.form.registeredBranch')"
|
||||
select-first-value
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ withDefaults(
|
|||
actionDisabled?: boolean;
|
||||
customerType?: 'CORP' | 'PERS';
|
||||
hideAction?: boolean;
|
||||
hideDelete?: boolean;
|
||||
}>(),
|
||||
{
|
||||
hideAction: false,
|
||||
|
|
@ -81,7 +82,7 @@ withDefaults(
|
|||
/>
|
||||
<DeleteButton
|
||||
icon-only
|
||||
v-if="readonly"
|
||||
v-if="readonly && !hideDelete"
|
||||
@click="$emit('delete')"
|
||||
type="button"
|
||||
:disabled="actionDisabled"
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ withDefaults(
|
|||
defineProps<{
|
||||
readonly?: boolean;
|
||||
isEdit?: boolean;
|
||||
hideAction?: boolean;
|
||||
}>(),
|
||||
{ readonly: false, isEdit: false },
|
||||
);
|
||||
|
|
@ -207,7 +208,7 @@ function triggerPropertiesDialog(step: WorkFlowPayloadStep) {
|
|||
style="position: absolute; z-index: 999; top: 0; right: 0"
|
||||
>
|
||||
<div
|
||||
v-if="flowData.status !== 'INACTIVE'"
|
||||
v-if="flowData.status !== 'INACTIVE' && !hideAction"
|
||||
class="surface-1 row rounded"
|
||||
>
|
||||
<UndoButton
|
||||
|
|
@ -287,6 +288,7 @@ function triggerPropertiesDialog(step: WorkFlowPayloadStep) {
|
|||
>
|
||||
<template v-slot:btn-form-flow-step-drawer>
|
||||
<q-btn
|
||||
v-if="!hideAction"
|
||||
dense
|
||||
flat
|
||||
icon="mdi-plus"
|
||||
|
|
@ -315,6 +317,7 @@ function triggerPropertiesDialog(step: WorkFlowPayloadStep) {
|
|||
<FormFlow
|
||||
:readonly
|
||||
onDrawer
|
||||
:hide-action="hideAction"
|
||||
v-model:user-in-table="userInTable"
|
||||
v-model:flow-data="flowData"
|
||||
v-model:register-branch-id="registerBranchId"
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import {
|
|||
} from 'src/stores/workflow-template/types';
|
||||
import { useWorkflowTemplate } from 'src/stores/workflow-template';
|
||||
import { useNavigator } from 'src/stores/navigator';
|
||||
import { dialog } from 'src/stores/utils';
|
||||
import { dialog, canAccess } from 'src/stores/utils';
|
||||
|
||||
import FloatingActionButton from 'components/FloatingActionButton.vue';
|
||||
import StatCardComponent from 'src/components/StatCardComponent.vue';
|
||||
|
|
@ -334,6 +334,7 @@ watch(
|
|||
</script>
|
||||
<template>
|
||||
<FloatingActionButton
|
||||
v-if="canAccess('workflow', 'edit')"
|
||||
style="z-index: 999"
|
||||
hide-icon
|
||||
@click="triggerDialog('add')"
|
||||
|
|
@ -682,6 +683,7 @@ watch(
|
|||
"
|
||||
/>
|
||||
<KebabAction
|
||||
v-if="canAccess('workflow', 'edit')"
|
||||
:id-name="props.row.name"
|
||||
:status="props.row.status"
|
||||
@view="
|
||||
|
|
@ -763,6 +765,7 @@ watch(
|
|||
"
|
||||
/>
|
||||
<KebabAction
|
||||
v-if="canAccess('workflow', 'edit')"
|
||||
:id-name="props.row.name"
|
||||
:status="props.row.status"
|
||||
@view="
|
||||
|
|
@ -846,6 +849,7 @@ watch(
|
|||
@drawer-undo="undo"
|
||||
@close="resetForm"
|
||||
@submit="submit"
|
||||
:hide-action="!canAccess('workflow', 'edit')"
|
||||
:readonly="!pageState.isDrawerEdit"
|
||||
:isEdit="pageState.isDrawerEdit"
|
||||
v-model="pageState.addModal"
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ import PaginationPageSize from 'src/components/PaginationPageSize.vue';
|
|||
import useFlowStore from 'stores/flow';
|
||||
|
||||
import { dateFormat } from 'src/utils/datetime';
|
||||
import { formatNumberDecimal, isRoleInclude, notify } from 'stores/utils';
|
||||
import { formatNumberDecimal, isRoleInclude, canAccess } from 'stores/utils';
|
||||
const { getWorkflowTemplate } = useWorkflowTemplate();
|
||||
|
||||
import { Status } from 'stores/types';
|
||||
|
|
@ -143,27 +143,25 @@ const { t } = useI18n();
|
|||
const baseUrl = ref<string>(import.meta.env.VITE_API_BASE_URL);
|
||||
|
||||
const priceDisplay = computed(() => ({
|
||||
price: !isRoleInclude(['sale_agent']),
|
||||
// price: !isRoleInclude(['sale_agent']),
|
||||
price: true,
|
||||
agentPrice: isRoleInclude([
|
||||
'admin',
|
||||
'head_of_admin',
|
||||
'head_of_sale',
|
||||
'system',
|
||||
'owner',
|
||||
'head_of_admin',
|
||||
'admin',
|
||||
'executive',
|
||||
'accountant',
|
||||
'sale_agent',
|
||||
'head_of_sale',
|
||||
]),
|
||||
serviceCharge: isRoleInclude([
|
||||
'admin',
|
||||
'head_of_admin',
|
||||
'system',
|
||||
'owner',
|
||||
'head_of_admin',
|
||||
'admin',
|
||||
'executive',
|
||||
'accountant',
|
||||
]),
|
||||
}));
|
||||
const actionDisplay = computed(() =>
|
||||
isRoleInclude(['admin', 'head_of_admin', 'system', 'owner', 'accountant']),
|
||||
);
|
||||
const actionDisplay = computed(() => canAccess('product', 'edit'));
|
||||
const splitterModel = computed(() =>
|
||||
$q.screen.lt.md ? (productMode.value !== 'group' ? 0 : 100) : 25,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import { FloatingActionButton, PaginationComponent } from 'src/components';
|
|||
import PaginationPageSize from 'src/components/PaginationPageSize.vue';
|
||||
import PropertyDialog from './PropertyDialog.vue';
|
||||
import { Property } from 'src/stores/property/types';
|
||||
import { dialog, toCamelCase } from 'src/stores/utils';
|
||||
import { dialog, toCamelCase, canAccess } from 'src/stores/utils';
|
||||
import CreateButton from 'src/components/AddButton.vue';
|
||||
import useOptionStore from 'stores/options';
|
||||
import AdvanceSearch from 'src/components/shared/AdvanceSearch.vue';
|
||||
|
|
@ -331,6 +331,7 @@ watch(
|
|||
</script>
|
||||
<template>
|
||||
<FloatingActionButton
|
||||
v-if="canAccess('workflow', 'edit')"
|
||||
style="z-index: 999"
|
||||
hide-icon
|
||||
@click="triggerDialog('add')"
|
||||
|
|
@ -536,11 +537,19 @@ watch(
|
|||
class="col surface-2 flex items-center justify-center"
|
||||
>
|
||||
<NoData
|
||||
v-if="pageState.total !== 0 || pageState.searchDate.length > 0"
|
||||
v-if="
|
||||
pageState.total !== 0 ||
|
||||
pageState.searchDate.length > 0 ||
|
||||
!canAccess('workflow', 'edit')
|
||||
"
|
||||
:not-found="!!pageState.inputSearch"
|
||||
/>
|
||||
<CreateButton
|
||||
v-if="pageState.total === 0 && pageState.searchDate.length === 0"
|
||||
v-if="
|
||||
pageState.total === 0 &&
|
||||
pageState.searchDate.length === 0 &&
|
||||
canAccess('workflow', 'edit')
|
||||
"
|
||||
@click="triggerDialog('add')"
|
||||
label="general.add"
|
||||
:i18n-args="{ text: $t('flow.title') }"
|
||||
|
|
@ -698,6 +707,7 @@ watch(
|
|||
"
|
||||
/>
|
||||
<KebabAction
|
||||
v-if="canAccess('workflow', 'edit')"
|
||||
:id-name="props.row.name"
|
||||
:status="props.row.status"
|
||||
@view="
|
||||
|
|
@ -815,6 +825,7 @@ watch(
|
|||
"
|
||||
/>
|
||||
<KebabAction
|
||||
v-if="canAccess('workflow', 'edit')"
|
||||
:id-name="props.row.id"
|
||||
:status="props.row.status"
|
||||
@view="
|
||||
|
|
@ -906,6 +917,7 @@ watch(
|
|||
@drawer-undo="() => undo()"
|
||||
@close="() => resetForm()"
|
||||
@submit="() => submit()"
|
||||
:hide-action="!canAccess('workflow', 'edit')"
|
||||
:readonly="!pageState.isDrawerEdit"
|
||||
:isEdit="pageState.isDrawerEdit"
|
||||
v-model="pageState.addModal"
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ withDefaults(
|
|||
defineProps<{
|
||||
readonly?: boolean;
|
||||
isEdit?: boolean;
|
||||
hideAction?: boolean;
|
||||
}>(),
|
||||
{ readonly: false, isEdit: false },
|
||||
);
|
||||
|
|
@ -151,7 +152,7 @@ defineEmits<{
|
|||
style="position: absolute; z-index: 999; top: 0; right: 0"
|
||||
>
|
||||
<div
|
||||
v-if="propertyData.status !== 'INACTIVE'"
|
||||
v-if="propertyData.status !== 'INACTIVE' && !hideAction"
|
||||
class="surface-1 row rounded"
|
||||
>
|
||||
<UndoButton
|
||||
|
|
@ -236,6 +237,7 @@ defineEmits<{
|
|||
<FormProperty
|
||||
onDrawer
|
||||
:readonly="!isEdit"
|
||||
:disable-toggle="hideAction"
|
||||
v-model:name="formProperty.name"
|
||||
v-model:name-en="formProperty.nameEN"
|
||||
v-model:type="formProperty.type"
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import useMyBranch from 'stores/my-branch';
|
|||
import { useQuotationForm } from './form';
|
||||
import { hslaColors } from './constants';
|
||||
import { pageTabs, columnQuotation } from './constants';
|
||||
import { toCamelCase } from 'stores/utils';
|
||||
import { toCamelCase, canAccess } from 'stores/utils';
|
||||
|
||||
// NOTE Import Types
|
||||
import { CustomerBranchCreate, CustomerType } from 'stores/customer/types';
|
||||
|
|
@ -413,6 +413,7 @@ async function storeDataLocal(id: string) {
|
|||
hide-icon
|
||||
style="z-index: 999"
|
||||
@click.stop="triggerAddQuotationDialog"
|
||||
v-if="canAccess('quotation', 'edit')"
|
||||
/>
|
||||
|
||||
<div class="column full-height no-wrap">
|
||||
|
|
@ -647,12 +648,20 @@ async function storeDataLocal(id: string) {
|
|||
class="col surface-2 flex items-center justify-center"
|
||||
>
|
||||
<NoData
|
||||
v-if="pageState.inputSearch || pageState.currentTab !== 'Issued'"
|
||||
v-if="
|
||||
pageState.inputSearch ||
|
||||
!canAccess('quotation', 'edit') ||
|
||||
pageState.currentTab !== 'Issued'
|
||||
"
|
||||
:not-found="!!pageState.inputSearch"
|
||||
/>
|
||||
|
||||
<CreateButton
|
||||
v-if="!pageState.inputSearch && pageState.currentTab === 'Issued'"
|
||||
v-if="
|
||||
!pageState.inputSearch &&
|
||||
pageState.currentTab === 'Issued' &&
|
||||
canAccess('quotation', 'edit')
|
||||
"
|
||||
@click="triggerAddQuotationDialog"
|
||||
label="general.add"
|
||||
:i18n-args="{ text: $t('quotation.title') }"
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ const { data: config } = storeToRefs(configStore);
|
|||
|
||||
const prop = defineProps<{
|
||||
data?: Quotation | QuotationFull | DebitNote;
|
||||
readonly?: boolean;
|
||||
isDebitNote?: boolean;
|
||||
}>();
|
||||
|
||||
|
|
@ -479,7 +480,7 @@ onMounted(async () => {
|
|||
</div>
|
||||
|
||||
<!-- bill -->
|
||||
<span class="app-text-muted-2 q-pt-md">
|
||||
<span class="app-text-muted-2 q-pt-md" v-if="paymentData.length > 0">
|
||||
{{ $t('quotation.receiptDialog.billOfPayment') }}
|
||||
</span>
|
||||
|
||||
|
|
@ -521,6 +522,7 @@ onMounted(async () => {
|
|||
|
||||
<div class="q-ml-auto row" style="gap: 10px">
|
||||
<q-btn
|
||||
:disable="readonly"
|
||||
id="btn-payment"
|
||||
@click.stop
|
||||
unelevated
|
||||
|
|
@ -547,7 +549,11 @@ onMounted(async () => {
|
|||
<span>
|
||||
{{ $t(`quotation.receiptDialog.${p.paymentStatus}`) }}
|
||||
</span>
|
||||
<q-icon name="mdi-chevron-down" class="q-pl-xs" />
|
||||
<q-icon
|
||||
v-if="!readonly"
|
||||
name="mdi-chevron-down"
|
||||
class="q-pl-xs"
|
||||
/>
|
||||
<q-menu
|
||||
ref="refQMenu"
|
||||
fit
|
||||
|
|
@ -634,6 +640,7 @@ onMounted(async () => {
|
|||
})
|
||||
}}
|
||||
<q-btn
|
||||
v-if="!readonly"
|
||||
unelevated
|
||||
id="btn-upload-file"
|
||||
:label="$t('general.upload')"
|
||||
|
|
@ -762,10 +769,10 @@ onMounted(async () => {
|
|||
}
|
||||
|
||||
:deep(
|
||||
.q-expansion-item
|
||||
.q-item.q-item-type.row.no-wrap.q-item--clickable.q-link.cursor-pointer.q-focusable.q-hoverable
|
||||
.q-focus-helper
|
||||
) {
|
||||
.q-expansion-item
|
||||
.q-item.q-item-type.row.no-wrap.q-item--clickable.q-link.cursor-pointer.q-focusable.q-hoverable
|
||||
.q-focus-helper
|
||||
) {
|
||||
visibility: hidden;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import {
|
|||
dialogCheckData,
|
||||
dialogWarningClose,
|
||||
formatNumberDecimal,
|
||||
canAccess,
|
||||
isRoleInclude,
|
||||
} from 'stores/utils';
|
||||
import { ProductTree, quotationProductTree } from './utils';
|
||||
|
||||
|
|
@ -213,17 +215,6 @@ const attachmentData = ref<
|
|||
url?: string;
|
||||
}[]
|
||||
>([]);
|
||||
const hideBtnApproveInvoice = computed(() => {
|
||||
const role = getRole();
|
||||
const allowedRoles = [
|
||||
'system',
|
||||
'head_of_admin',
|
||||
'admin',
|
||||
'head_of_accountant',
|
||||
'accountant',
|
||||
];
|
||||
return !role || !role.some((r) => allowedRoles.includes(r));
|
||||
});
|
||||
|
||||
const getToolbarConfig = computed(() => {
|
||||
const toolbar = [['left', 'center', 'justify'], ['toggle'], ['clip']];
|
||||
|
|
@ -1746,7 +1737,7 @@ function covertToNode() {
|
|||
:readonly="
|
||||
{
|
||||
quotation: quotationFormState.mode !== 'edit',
|
||||
invoice: false,
|
||||
invoice: isRoleInclude(['sale', 'head_of_sale']),
|
||||
accepted: true,
|
||||
}[view]
|
||||
"
|
||||
|
|
@ -1950,6 +1941,7 @@ function covertToNode() {
|
|||
view !== View.Receipt &&
|
||||
view !== View.Complete
|
||||
"
|
||||
:readonly="isRoleInclude(['sale', 'head_of_sale'])"
|
||||
:data="quotationFormState.source"
|
||||
v-model:first-code-payment="firstCodePayment"
|
||||
@fetch-status="
|
||||
|
|
@ -2327,7 +2319,6 @@ function covertToNode() {
|
|||
"
|
||||
>
|
||||
<MainButton
|
||||
v-if="!hideBtnApproveInvoice"
|
||||
solid
|
||||
icon="mdi-account-multiple-check-outline"
|
||||
color="207 96% 32%"
|
||||
|
|
|
|||
|
|
@ -66,21 +66,21 @@ const serviceList = defineModel<Partial<Record<ProductGroupId, Service[]>>>(
|
|||
);
|
||||
|
||||
const priceDisplay = computed(() => ({
|
||||
price: !isRoleInclude(['sale_agent']),
|
||||
// price: !isRoleInclude(['sale_agent']),
|
||||
price: true,
|
||||
agentPrice: isRoleInclude([
|
||||
'admin',
|
||||
'head_of_admin',
|
||||
'head_of_sale',
|
||||
'system',
|
||||
'owner',
|
||||
'head_of_admin',
|
||||
'admin',
|
||||
'executive',
|
||||
'accountant',
|
||||
'sale_agent',
|
||||
'head_of_sale',
|
||||
]),
|
||||
serviceCharge: isRoleInclude([
|
||||
'admin',
|
||||
'head_of_admin',
|
||||
'system',
|
||||
'owner',
|
||||
'head_of_admin',
|
||||
'admin',
|
||||
'executive',
|
||||
'accountant',
|
||||
]),
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -62,6 +62,8 @@ const props = withDefaults(
|
|||
defineProps<{
|
||||
readonly?: boolean;
|
||||
isEdit?: boolean;
|
||||
hideAction?: boolean;
|
||||
hideDelete?: boolean;
|
||||
|
||||
dataId?: string;
|
||||
}>(),
|
||||
|
|
@ -411,6 +413,7 @@ watch(
|
|||
:prefix="data.name"
|
||||
hide-fade
|
||||
use-toggle
|
||||
:readonly="hideAction"
|
||||
:active="data.status !== 'INACTIVE'"
|
||||
:toggle-title="$t('status.title')"
|
||||
:icon="'ph-building-office'"
|
||||
|
|
@ -450,7 +453,7 @@ watch(
|
|||
style="position: absolute; z-index: 999; top: 0; right: 0"
|
||||
>
|
||||
<div
|
||||
v-if="data.status !== 'INACTIVE'"
|
||||
v-if="data.status !== 'INACTIVE' && !hideAction"
|
||||
class="surface-1 row rounded"
|
||||
>
|
||||
<UndoButton
|
||||
|
|
@ -484,7 +487,7 @@ watch(
|
|||
type="button"
|
||||
/>
|
||||
<DeleteButton
|
||||
v-if="!isEdit"
|
||||
v-if="!isEdit && !hideDelete"
|
||||
id="btn-info-basic-delete"
|
||||
icon-only
|
||||
@click="
|
||||
|
|
@ -597,6 +600,7 @@ watch(
|
|||
v-model:on-create-data-list="imageListOnCreate"
|
||||
v-model:image-url="imageState.imageUrl"
|
||||
v-model:data-list="imageList"
|
||||
:changeDisabled="hideAction"
|
||||
:on-create="model"
|
||||
:hiddenFooter="!imageState.isImageEdit"
|
||||
@add-image="addImage"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { Icon } from '@iconify/vue/dist/iconify.js';
|
|||
import { useI18n } from 'vue-i18n';
|
||||
import { useQuasar } from 'quasar';
|
||||
|
||||
import { baseUrl } from 'src/stores/utils';
|
||||
import { baseUrl, canAccess } from 'src/stores/utils';
|
||||
import { useNavigator } from 'src/stores/navigator';
|
||||
import { useInstitution } from 'src/stores/institution';
|
||||
import { Institution, InstitutionPayload } from 'src/stores/institution/types';
|
||||
|
|
@ -366,6 +366,7 @@ watch(
|
|||
</script>
|
||||
<template>
|
||||
<FloatingActionButton
|
||||
v-if="canAccess('agencies', 'edit')"
|
||||
style="z-index: 999"
|
||||
hide-icon
|
||||
@click="triggerDialog('add')"
|
||||
|
|
@ -750,6 +751,7 @@ watch(
|
|||
"
|
||||
/>
|
||||
<KebabAction
|
||||
:hide-delete="!canAccess('agencies', 'edit')"
|
||||
:id-name="props.row.name"
|
||||
:status="props.row.status"
|
||||
@view="
|
||||
|
|
@ -833,6 +835,7 @@ watch(
|
|||
"
|
||||
/>
|
||||
<KebabAction
|
||||
:hide-delete="!canAccess('agencies', 'edit')"
|
||||
:id-name="props.row.id"
|
||||
:status="props.row.status"
|
||||
@view="
|
||||
|
|
@ -973,6 +976,7 @@ watch(
|
|||
@change-status="triggerChangeStatus"
|
||||
:readonly="!pageState.isDrawerEdit"
|
||||
:isEdit="pageState.isDrawerEdit"
|
||||
:hide-delete="!canAccess('agencies', 'edit')"
|
||||
v-model="pageState.addModal"
|
||||
v-model:drawer-model="pageState.viewDrawer"
|
||||
v-model:data="formData"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import { column } from './constants';
|
|||
import useFlowStore from 'src/stores/flow';
|
||||
import { useRequestList } from 'src/stores/request-list';
|
||||
import { RequestData, RequestDataStatus } from 'src/stores/request-list/types';
|
||||
import { dialogWarningClose } from 'src/stores/utils';
|
||||
import { dialogWarningClose, canAccess } from 'src/stores/utils';
|
||||
import { CancelButton, SaveButton } from 'src/components/button';
|
||||
import { getRole } from 'src/services/keycloak';
|
||||
import FloatingActionButton from 'src/components/FloatingActionButton.vue';
|
||||
|
|
@ -473,6 +473,7 @@ watch(
|
|||
"
|
||||
>
|
||||
<TableRequestList
|
||||
:no-link="!canAccess('customer', 'view')"
|
||||
:columns="column"
|
||||
:rows="data"
|
||||
:grid="pageState.gridView"
|
||||
|
|
@ -574,6 +575,7 @@ watch(
|
|||
v-if="requestListActionData"
|
||||
v-model="pageState.requestListActionDialog"
|
||||
:request-list="requestListActionData"
|
||||
:no-link="!canAccess('customer', 'view')"
|
||||
@submit="submitRequestListAction"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -86,7 +86,11 @@ function assignToForm() {
|
|||
customerDutyCost: attributesForm.value.customerDutyCost ?? 30,
|
||||
companyDuty: attributesForm.value.companyDuty ?? false,
|
||||
companyDutyCost: attributesForm.value.companyDutyCost ?? 30,
|
||||
responsibleUserLocal: attributesForm.value.responsibleUserLocal ?? true,
|
||||
responsibleUserLocal: attributesForm.value.responsibleUserLocal
|
||||
? attributesForm.value.responsibleUserLocal
|
||||
: props.responsibleAreaDistrictId
|
||||
? false
|
||||
: true,
|
||||
responsibleUserId:
|
||||
attributesForm.value.responsibleUserId || props.defaultMessenger,
|
||||
individualDuty: attributesForm.value.individualDuty ?? false,
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import useAddressStore from 'src/stores/address';
|
|||
|
||||
defineProps<{
|
||||
requestList: RequestData[];
|
||||
noLink?: boolean;
|
||||
}>();
|
||||
|
||||
defineEmits<{
|
||||
|
|
@ -99,6 +100,7 @@ watch(
|
|||
hide-action
|
||||
hide-view
|
||||
checkable
|
||||
:no-link="noLink"
|
||||
:list-same-area="listSameArea"
|
||||
:columns="column"
|
||||
:rows="requestList"
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import {
|
|||
getEmployeeName,
|
||||
getCustomerName,
|
||||
dialogWarningClose,
|
||||
canAccess,
|
||||
} from 'src/stores/utils';
|
||||
import { dateFormatJS } from 'src/utils/datetime';
|
||||
import { useRequestList } from 'src/stores/request-list';
|
||||
|
|
@ -459,6 +460,7 @@ async function submitRejectCancel() {
|
|||
}
|
||||
|
||||
function toCustomer(customer: RequestData['quotation']['customerBranch']) {
|
||||
if (!canAccess('customer', 'view')) return;
|
||||
const url = new URL(
|
||||
`/customer-management?tab=customer&id=${customer.customerId}`,
|
||||
window.location.origin,
|
||||
|
|
@ -468,6 +470,7 @@ function toCustomer(customer: RequestData['quotation']['customerBranch']) {
|
|||
}
|
||||
|
||||
function toEmployee(employee: RequestData['employee']) {
|
||||
if (!canAccess('customer', 'view')) return;
|
||||
const url = new URL(
|
||||
`/customer-management?tab=employee&id=${employee.id}`,
|
||||
window.location.origin,
|
||||
|
|
@ -742,7 +745,7 @@ function toEmployee(employee: RequestData['employee']) {
|
|||
}"
|
||||
>
|
||||
<DataDisplay
|
||||
clickable
|
||||
:clickable="canAccess('customer', 'view')"
|
||||
class="col"
|
||||
icon="mdi-account-settings-outline"
|
||||
:label="$t('customer.employer')"
|
||||
|
|
@ -755,7 +758,7 @@ function toEmployee(employee: RequestData['employee']) {
|
|||
@label-click="toCustomer(data.quotation.customerBranch)"
|
||||
/>
|
||||
<DataDisplay
|
||||
clickable
|
||||
:clickable="canAccess('customer', 'view')"
|
||||
class="col"
|
||||
icon="mdi-account-settings-outline"
|
||||
:label="$t('customer.employee')"
|
||||
|
|
@ -864,7 +867,7 @@ function toEmployee(employee: RequestData['employee']) {
|
|||
requestWorkId: value.id || '',
|
||||
},
|
||||
value.stepStatus?.[pageState.currentStep - 1]
|
||||
?.responsibleUserId,
|
||||
?.responsibleUserId ?? data.defaultMessengerId,
|
||||
);
|
||||
}
|
||||
"
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ const props = withDefaults(
|
|||
hideView?: boolean;
|
||||
checkable?: boolean;
|
||||
listSameArea?: string[];
|
||||
noLink?: boolean;
|
||||
}>(),
|
||||
{
|
||||
row: () => [],
|
||||
|
|
@ -119,6 +120,7 @@ function getEmployeeName(
|
|||
}
|
||||
|
||||
function toCustomer(customer: RequestData['quotation']['customerBranch']) {
|
||||
if (props.noLink) return;
|
||||
const url = new URL(
|
||||
`/customer-management?tab=customer&id=${customer.customerId}`,
|
||||
window.location.origin,
|
||||
|
|
@ -128,6 +130,7 @@ function toCustomer(customer: RequestData['quotation']['customerBranch']) {
|
|||
}
|
||||
|
||||
function toEmployee(employee: RequestData['employee']) {
|
||||
if (props.noLink) return;
|
||||
const url = new URL(
|
||||
`/customer-management?tab=employee&id=${employee.id}`,
|
||||
window.location.origin,
|
||||
|
|
@ -234,7 +237,7 @@ function handleCheckAll() {
|
|||
</q-td>
|
||||
<q-td v-if="visibleColumns.includes('employer')" class="text-left">
|
||||
<span
|
||||
class="link"
|
||||
:class="{ link: !noLink }"
|
||||
@click="toCustomer(props.row.quotation.customerBranch)"
|
||||
>
|
||||
{{
|
||||
|
|
@ -246,7 +249,10 @@ function handleCheckAll() {
|
|||
</span>
|
||||
</q-td>
|
||||
<q-td v-if="visibleColumns.includes('employee')" class="text-left">
|
||||
<span class="link" @click="toEmployee(props.row.employee)">
|
||||
<span
|
||||
:class="{ link: !noLink }"
|
||||
@click="toEmployee(props.row.employee)"
|
||||
>
|
||||
{{ getEmployeeName(props.row, { locale: $i18n.locale }) || '-' }}
|
||||
</span>
|
||||
</q-td>
|
||||
|
|
@ -403,6 +409,7 @@ function handleCheckAll() {
|
|||
hide-kebab-delete
|
||||
:use-cancel="!hideAction"
|
||||
class="full-height"
|
||||
:hide-action="hideAction"
|
||||
:use-reject-cancel="
|
||||
props.row.customerRequestCancel && !props.row.rejectRequestCancel
|
||||
"
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { storeToRefs } from 'pinia';
|
|||
import { useQuasar } from 'quasar';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { canAccess } from 'src/stores/utils';
|
||||
|
||||
// NOTE: Components
|
||||
import StatCardComponent from 'src/components/StatCardComponent.vue';
|
||||
|
|
@ -172,6 +173,7 @@ watch(
|
|||
</script>
|
||||
<template>
|
||||
<FloatingActionButton
|
||||
v-if="canAccess('taskOrder', 'edit') || pageState.isMessenger"
|
||||
style="z-index: 999"
|
||||
:hide-icon="!pageState.isMessenger"
|
||||
@click.stop="
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import {
|
|||
useRequestList,
|
||||
RequestWork,
|
||||
RequestWorkStatus,
|
||||
RequestDataStatus,
|
||||
} from 'src/stores/request-list';
|
||||
import DialogHeader from 'src/components/dialog/DialogHeader.vue';
|
||||
import CancelButton from 'src/components/button/CancelButton.vue';
|
||||
|
|
@ -192,7 +193,8 @@ function submit() {
|
|||
s.workStatus ===
|
||||
(props.creditNote
|
||||
? RequestWorkStatus.Canceled
|
||||
: RequestWorkStatus.InProgress),
|
||||
: RequestWorkStatus.InProgress) ||
|
||||
v.request.requestDataStatus === RequestDataStatus.Canceled,
|
||||
);
|
||||
if (curr) {
|
||||
const task: Task = {
|
||||
|
|
@ -387,8 +389,8 @@ function assignTempGroup() {
|
|||
}
|
||||
|
||||
:deep(
|
||||
i.q-icon.mdi.mdi-chevron-down-circle.q-expansion-item__toggle-icon.q-expansion-item__toggle-icon--rotated
|
||||
) {
|
||||
i.q-icon.mdi.mdi-chevron-down-circle.q-expansion-item__toggle-icon.q-expansion-item__toggle-icon--rotated
|
||||
) {
|
||||
color: var(--brand-1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ function getEmployeeName(
|
|||
return (
|
||||
{
|
||||
['eng']: `${useOptionStore().mapOption(employee?.namePrefix || '')} ${employee?.firstNameEN} ${employee?.lastNameEN}`,
|
||||
['tha']: `${useOptionStore().mapOption(employee?.namePrefix || '')} ${employee?.firstName} ${employee?.lastName}`,
|
||||
['tha']: `${useOptionStore().mapOption(employee?.namePrefix || '')} ${employee?.firstName || employee?.firstNameEN} ${employee?.lastName}`,
|
||||
}[opts?.locale || 'eng'] || '-'
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
import { ref } from 'vue';
|
||||
import { QTableProps, QTableSlots } from 'quasar';
|
||||
|
||||
import { canAccess } from 'src/stores/utils';
|
||||
|
||||
import QuotationCard from 'src/components/05_quotation/QuotationCard.vue';
|
||||
import BadgeComponent from 'src/components/BadgeComponent.vue';
|
||||
import KebabAction from 'src/components/shared/KebabAction.vue';
|
||||
|
|
@ -216,6 +218,7 @@ const emit = defineEmits<{
|
|||
v-if="
|
||||
!receive && props.row.taskOrderStatus === TaskOrderStatus.Pending
|
||||
"
|
||||
:hide-delete="!canAccess('related', 'edit')"
|
||||
:idName="`btn-kebab-${props.row.taskName}`"
|
||||
status="'ACTIVE'"
|
||||
hide-toggle
|
||||
|
|
@ -264,6 +267,7 @@ const emit = defineEmits<{
|
|||
:status="$t(taskOrderStatus(props.row.taskOrderStatus, 'status'))"
|
||||
:badge-color="taskOrderStatus(props.row.taskOrderStatus, 'color')"
|
||||
hide-preview
|
||||
:hideKebabDelete="!canAccess('related', 'edit')"
|
||||
:hide-action="
|
||||
receive || props.row.taskOrderStatus !== TaskOrderStatus.Pending
|
||||
"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { useRoute, useRouter } from 'vue-router';
|
|||
import { useI18n } from 'vue-i18n';
|
||||
import { api } from 'src/boot/axios';
|
||||
import { Lang } from 'src/utils/ui';
|
||||
import { baseUrl } from 'stores/utils';
|
||||
import { baseUrl, canAccess } from 'stores/utils';
|
||||
|
||||
import TaskStatusComponent from '../TaskStatusComponent.vue';
|
||||
import StateButton from 'src/components/button/StateButton.vue';
|
||||
|
|
@ -1175,7 +1175,10 @@ watch(
|
|||
<template #append="{ props: subProps }">
|
||||
<TaskStatusComponent
|
||||
:key="subProps.row.id"
|
||||
:no-action="view !== TaskOrderStatus.Validate"
|
||||
:no-action="
|
||||
view !== TaskOrderStatus.Validate &&
|
||||
!canAccess('taskOrder', 'edit')
|
||||
"
|
||||
type="order"
|
||||
:readonly="
|
||||
(() => {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ import {
|
|||
import { RequestWork } from 'src/stores/request-list/types';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import useOptionStore from 'src/stores/options';
|
||||
import { dialogWarningClose } from 'src/stores/utils';
|
||||
import { dialogWarningClose, canAccess, isRoleInclude } from 'src/stores/utils';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { QForm } from 'quasar';
|
||||
import { getName } from 'src/services/keycloak';
|
||||
|
|
@ -684,6 +684,7 @@ onMounted(async () => {
|
|||
|
||||
<RefundInformation
|
||||
v-if="view === CreditNoteStatus.Pending"
|
||||
:readonly="!canAccess('related', 'edit')"
|
||||
:total="creditNoteData?.value"
|
||||
:paid="
|
||||
creditNoteData?.paybackStatus === CreditNotePaybackStatus.Done
|
||||
|
|
@ -727,7 +728,7 @@ onMounted(async () => {
|
|||
|
||||
<AdditionalFileExpansion
|
||||
v-if="view !== CreditNoteStatus.Success"
|
||||
:readonly="false"
|
||||
:readonly="isRoleInclude(['sale', 'head_of_sale'])"
|
||||
v-model:file-data="attachmentData"
|
||||
:transform-url="
|
||||
async (url: string) => {
|
||||
|
|
@ -871,7 +872,8 @@ onMounted(async () => {
|
|||
<SaveButton
|
||||
v-if="
|
||||
!creditNoteData ||
|
||||
creditNoteData?.creditNoteStatus === CreditNoteStatus.Waiting
|
||||
(creditNoteData?.creditNoteStatus === CreditNoteStatus.Waiting &&
|
||||
canAccess('related', 'edit'))
|
||||
"
|
||||
:disabled="taskListGroup.length === 0 || pageState.mode === 'edit'"
|
||||
type="submit"
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import useFlowStore from 'src/stores/flow';
|
|||
import { pageTabs, columns, hslaColors } from './constants';
|
||||
import { CreditNoteStatus, useCreditNote } from 'src/stores/credit-note';
|
||||
import TableCreditNote from './TableCreditNote.vue';
|
||||
import { dialogWarningClose } from 'src/stores/utils';
|
||||
import { dialogWarningClose, canAccess } from 'src/stores/utils';
|
||||
import AdvanceSearch from 'src/components/shared/AdvanceSearch.vue';
|
||||
|
||||
const $q = useQuasar();
|
||||
|
|
@ -146,6 +146,7 @@ watch(
|
|||
</script>
|
||||
<template>
|
||||
<FloatingActionButton
|
||||
v-if="canAccess('related', 'edit')"
|
||||
style="z-index: 999"
|
||||
hide-icon
|
||||
@click.stop="triggerCreateCreditNote()"
|
||||
|
|
@ -360,7 +361,10 @@ watch(
|
|||
<TableCreditNote
|
||||
:grid="pageState.gridView"
|
||||
:visible-columns="pageState.fieldSelected"
|
||||
:hide-delete="pageState.currentTab !== CreditNoteStatus.Waiting"
|
||||
:hide-delete="
|
||||
pageState.currentTab !== CreditNoteStatus.Waiting ||
|
||||
!canAccess('related', 'edit')
|
||||
"
|
||||
@view="(v) => navigateTo({ statusDialog: 'info', creditId: v.id })"
|
||||
@delete="(v) => triggerDelete(v.id)"
|
||||
>
|
||||
|
|
@ -376,6 +380,10 @@ watch(
|
|||
})
|
||||
"
|
||||
@delete="() => triggerDelete(item.row.id)"
|
||||
:hide-kebab-delete="
|
||||
pageState.currentTab !== CreditNoteStatus.Waiting ||
|
||||
!canAccess('related', 'edit')
|
||||
"
|
||||
:title="item.row.quotation.workName"
|
||||
:code="item.row.code"
|
||||
:status="$t(`creditNote.status.${item.row.creditNoteStatus}`)"
|
||||
|
|
|
|||
|
|
@ -172,11 +172,13 @@ const refundOpts = ref<
|
|||
>
|
||||
{{ $t('creditNote.label.refund') }}
|
||||
<q-btn-dropdown
|
||||
:disable="readonly"
|
||||
dense
|
||||
unelevated
|
||||
:label="$t(`creditNote.status.payback.${paybackStatus}`)"
|
||||
class="text-capitalize text-weight-regular product-status rounded"
|
||||
:class="{
|
||||
'hide-dropdown q-pr-md': readonly,
|
||||
warning: paybackStatus === CreditNotePaybackStatus.Pending,
|
||||
danger: paybackStatus === CreditNotePaybackStatus.Verify,
|
||||
'positive hide-dropdown q-pr-md':
|
||||
|
|
@ -219,7 +221,6 @@ const refundOpts = ref<
|
|||
<UploadFileSection
|
||||
multiple
|
||||
:layout="$q.screen.gt.sm ? 'column' : 'row'"
|
||||
:readonly
|
||||
:label="`${$t('general.upload', { msg: ' E-slip' })} ${$t(
|
||||
'general.or',
|
||||
{
|
||||
|
|
@ -281,9 +282,9 @@ const refundOpts = ref<
|
|||
}
|
||||
|
||||
:deep(
|
||||
.hide-dropdown
|
||||
i.q-icon.mdi.mdi-chevron-down.q-btn-dropdown__arrow.q-btn-dropdown__arrow-container
|
||||
) {
|
||||
.hide-dropdown
|
||||
i.q-icon.mdi.mdi-chevron-down.q-btn-dropdown__arrow.q-btn-dropdown__arrow-container
|
||||
) {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -46,7 +46,13 @@ import {
|
|||
import { RequestWork } from 'src/stores/request-list/types';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import useOptionStore from 'src/stores/options';
|
||||
import { deleteItem, dialog, dialogWarningClose } from 'src/stores/utils';
|
||||
import {
|
||||
canAccess,
|
||||
deleteItem,
|
||||
dialog,
|
||||
dialogWarningClose,
|
||||
isRoleInclude,
|
||||
} from 'src/stores/utils';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { Employee } from 'src/stores/employee/types';
|
||||
import QuotationFormWorkerSelect from '../05_quotation/QuotationFormWorkerSelect.vue';
|
||||
|
|
@ -1071,6 +1077,7 @@ async function submitAccepted() {
|
|||
<PaymentForm
|
||||
v-if="view === QuotationStatus.PaymentPending"
|
||||
is-debit-note
|
||||
:readonly="isRoleInclude(['sale', 'head_of_sale'])"
|
||||
:data="debitNoteData"
|
||||
@fetch-status="
|
||||
() => {
|
||||
|
|
@ -1126,7 +1133,6 @@ async function submitAccepted() {
|
|||
view === QuotationStatus.Issued ||
|
||||
view === QuotationStatus.Accepted
|
||||
"
|
||||
readonly
|
||||
:total-price="summaryPrice.finalPrice"
|
||||
class="q-mb-md"
|
||||
v-model:pay-type="currentFormData.payCondition"
|
||||
|
|
@ -1144,7 +1150,7 @@ async function submitAccepted() {
|
|||
view === QuotationStatus.Accepted ||
|
||||
view === QuotationStatus.PaymentPending
|
||||
"
|
||||
:readonly
|
||||
:readonly="isRoleInclude(['sale', 'head_of_sale'])"
|
||||
v-model:file-data="attachmentData"
|
||||
:transform-url="
|
||||
async (url: string) => {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import { useNavigator } from 'src/stores/navigator';
|
|||
import useFlowStore from 'src/stores/flow';
|
||||
import { pageTabs, columns, hslaColors } from './constants';
|
||||
import { DebitNoteStatus, useDebitNote } from 'src/stores/debit-note';
|
||||
import { dialogWarningClose } from 'src/stores/utils';
|
||||
import { canAccess, dialogWarningClose } from 'src/stores/utils';
|
||||
import { useQuasar } from 'quasar';
|
||||
import AdvanceSearch from 'src/components/shared/AdvanceSearch.vue';
|
||||
|
||||
|
|
@ -163,6 +163,7 @@ watch(
|
|||
<FloatingActionButton
|
||||
style="z-index: 999"
|
||||
hide-icon
|
||||
v-if="canAccess('related', 'edit')"
|
||||
@click.stop="() => triggerCreateDebitNote()"
|
||||
></FloatingActionButton>
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { DebitNote, useDebitNote } from 'src/stores/debit-note';
|
|||
|
||||
import { columns } from './constants';
|
||||
import KebabAction from 'src/components/shared/KebabAction.vue';
|
||||
import { canAccess } from 'src/stores/utils';
|
||||
|
||||
const debitNote = useDebitNote();
|
||||
const { data, page, pageSize } = storeToRefs(debitNote);
|
||||
|
|
@ -80,6 +81,7 @@ const visible = computed(() =>
|
|||
:id-name="`btn-kebab-${props.row.workName}`"
|
||||
hide-toggle
|
||||
hide-edit
|
||||
:hide-delete="!canAccess('related', 'edit')"
|
||||
@edit="$emit('edit', props.row)"
|
||||
@delete="$emit('delete', props.row)"
|
||||
@view="$emit('view', props.row)"
|
||||
|
|
|
|||
|
|
@ -2,17 +2,15 @@
|
|||
import MenuItem from 'components/00_home/MenuItem.vue';
|
||||
import { useNavigator } from 'src/stores/navigator';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { getRole } from 'src/services/keycloak';
|
||||
import { canAccess } from 'src/stores/utils';
|
||||
|
||||
const navigatorStore = useNavigator();
|
||||
const menu = ref<InstanceType<typeof MenuItem>['$props']['list']>([]);
|
||||
const role = ref();
|
||||
|
||||
onMounted(() => {
|
||||
navigatorStore.current.title = '';
|
||||
navigatorStore.current.path = [{ text: '' }];
|
||||
|
||||
role.value = getRole();
|
||||
menu.value = [
|
||||
{
|
||||
value: 'branch-management',
|
||||
|
|
@ -20,14 +18,7 @@ onMounted(() => {
|
|||
color: 'green',
|
||||
title: 'menu.branch',
|
||||
caption: 'menu.branchCaption',
|
||||
hidden:
|
||||
role.value.includes('admin') ||
|
||||
role.value.includes('branch_admin') ||
|
||||
role.value.includes('head_of_admin') ||
|
||||
role.value.includes('system') ||
|
||||
role.value.includes('owner')
|
||||
? false
|
||||
: true,
|
||||
hidden: !canAccess('branch'),
|
||||
},
|
||||
{
|
||||
value: 'personnel-management',
|
||||
|
|
@ -35,15 +26,7 @@ onMounted(() => {
|
|||
color: 'cyan',
|
||||
title: 'menu.user',
|
||||
caption: 'menu.userCaption',
|
||||
hidden:
|
||||
role.value.includes('admin') ||
|
||||
role.value.includes('branch_admin') ||
|
||||
role.value.includes('head_of_admin') ||
|
||||
role.value.includes('system') ||
|
||||
role.value.includes('owner') ||
|
||||
role.value.includes('branch_manager')
|
||||
? false
|
||||
: true,
|
||||
hidden: !canAccess('personnel'),
|
||||
},
|
||||
{
|
||||
value: 'customer-management',
|
||||
|
|
@ -52,6 +35,7 @@ onMounted(() => {
|
|||
title: 'menu.customer',
|
||||
caption: 'menu.customerCaption',
|
||||
isax: true,
|
||||
hidden: !canAccess('customer'),
|
||||
},
|
||||
{
|
||||
value: 'product-service',
|
||||
|
|
@ -115,6 +99,7 @@ onMounted(() => {
|
|||
title: 'menu.dashboard',
|
||||
caption: 'menu.dashboardCaption',
|
||||
isax: true,
|
||||
hidden: !canAccess('dashBoard'),
|
||||
},
|
||||
];
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { RouteRecordRaw } from 'vue-router';
|
||||
import { isRoleInclude } from 'stores/utils';
|
||||
import { isRoleInclude, canAccess } from 'stores/utils';
|
||||
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
|
|
@ -16,21 +16,8 @@ const routes: RouteRecordRaw[] = [
|
|||
path: '/branch-management',
|
||||
name: 'BranchManagement',
|
||||
beforeEnter: (to, from, next) => {
|
||||
if (
|
||||
isRoleInclude([
|
||||
'admin',
|
||||
'branch_admin',
|
||||
'head_of_admin',
|
||||
'head_of_account',
|
||||
'system',
|
||||
'owner',
|
||||
'branch_manager',
|
||||
])
|
||||
) {
|
||||
next();
|
||||
} else {
|
||||
next('/');
|
||||
}
|
||||
if (canAccess('branch')) next();
|
||||
else next('/');
|
||||
},
|
||||
component: () => import('pages/01_branch-management/MainPage.vue'),
|
||||
},
|
||||
|
|
@ -38,36 +25,36 @@ const routes: RouteRecordRaw[] = [
|
|||
path: '/personnel-management',
|
||||
name: 'PersonnelManagement',
|
||||
beforeEnter: (to, from, next) => {
|
||||
if (
|
||||
isRoleInclude([
|
||||
'admin',
|
||||
'branch_admin',
|
||||
'head_of_admin',
|
||||
'system',
|
||||
'owner',
|
||||
'branch_manager',
|
||||
])
|
||||
) {
|
||||
next();
|
||||
} else {
|
||||
next('/');
|
||||
}
|
||||
if (canAccess('personnel')) next();
|
||||
else next('/');
|
||||
},
|
||||
component: () => import('pages/02_personnel-management/MainPage.vue'),
|
||||
},
|
||||
{
|
||||
path: '/customer-management',
|
||||
name: 'CustomerManagement',
|
||||
beforeEnter: (to, from, next) => {
|
||||
if (canAccess('customer')) next();
|
||||
else next('/');
|
||||
},
|
||||
component: () => import('pages/03_customer-management/MainPage.vue'),
|
||||
},
|
||||
{
|
||||
path: '/customer-management/:customerId',
|
||||
name: 'CustomerSpecificManagement',
|
||||
beforeEnter: (to, from, next) => {
|
||||
if (canAccess('customer')) next();
|
||||
else next('/');
|
||||
},
|
||||
component: () => import('pages/03_customer-management/MainPage.vue'),
|
||||
},
|
||||
{
|
||||
path: '/customer-management/:customerId/branch',
|
||||
name: 'CustomerBranchManagement',
|
||||
beforeEnter: (to, from, next) => {
|
||||
if (canAccess('customer')) next();
|
||||
else next('/');
|
||||
},
|
||||
component: () => import('pages/03_customer-management/MainPage.vue'),
|
||||
},
|
||||
{
|
||||
|
|
@ -78,11 +65,19 @@ const routes: RouteRecordRaw[] = [
|
|||
{
|
||||
path: '/workflow',
|
||||
name: 'Workflow',
|
||||
beforeEnter: (to, from, next) => {
|
||||
if (canAccess('workflow')) next();
|
||||
else next('/');
|
||||
},
|
||||
component: () => import('pages/04_flow-managment/MainPage.vue'),
|
||||
},
|
||||
{
|
||||
path: '/property',
|
||||
name: 'Property',
|
||||
beforeEnter: (to, from, next) => {
|
||||
if (canAccess('workflow')) next();
|
||||
else next('/');
|
||||
},
|
||||
component: () => import('pages/04_property-managment/MainPage.vue'),
|
||||
},
|
||||
{
|
||||
|
|
@ -98,6 +93,10 @@ const routes: RouteRecordRaw[] = [
|
|||
{
|
||||
path: '/agencies-management',
|
||||
name: 'agencies-management',
|
||||
beforeEnter: (to, from, next) => {
|
||||
if (canAccess('agencies')) next();
|
||||
else next('/');
|
||||
},
|
||||
component: () => import('pages/07_agencies-management/MainPage.vue'),
|
||||
},
|
||||
{
|
||||
|
|
@ -138,6 +137,10 @@ const routes: RouteRecordRaw[] = [
|
|||
{
|
||||
path: '/dash-board',
|
||||
name: 'dashBoard',
|
||||
beforeEnter: (to, from, next) => {
|
||||
if (canAccess('dashBoard')) next();
|
||||
else next('/');
|
||||
},
|
||||
component: () => import('pages/15_dash-board/MainPage.vue'),
|
||||
},
|
||||
{
|
||||
|
|
@ -225,7 +228,7 @@ const routes: RouteRecordRaw[] = [
|
|||
},
|
||||
{
|
||||
path: '/receipt/:id',
|
||||
name: 'receiptform',
|
||||
name: 'receiptForm',
|
||||
component: () => import('pages/13_receipt/MainPage.vue'),
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -221,11 +221,99 @@ export function checkTabBeforeAdd(data: unknown[], except?: string[]) {
|
|||
|
||||
export function isRoleInclude(role2check: string[]): boolean {
|
||||
const roles = getRole() ?? [];
|
||||
const isIncluded = role2check.some((r) => roles.includes(r));
|
||||
const filterRole = roles.filter(
|
||||
(role: string) =>
|
||||
role !== 'offline_access' &&
|
||||
role !== 'uma_authorization' &&
|
||||
!role.startsWith('default-roles'),
|
||||
);
|
||||
const isIncluded = role2check.some((r) => filterRole.includes(r));
|
||||
|
||||
return isIncluded;
|
||||
}
|
||||
|
||||
const allRoles = [
|
||||
'head_of_admin',
|
||||
'admin',
|
||||
'executive',
|
||||
'accountant',
|
||||
'branch_admin',
|
||||
'branch_manager',
|
||||
'branch_accountant',
|
||||
'head_of_sale',
|
||||
'sale',
|
||||
'data_entry',
|
||||
'document_checker',
|
||||
'messenger',
|
||||
'corporate_customer',
|
||||
'agency',
|
||||
];
|
||||
|
||||
const permissions = {
|
||||
branch: {
|
||||
edit: allRoles.slice(0, 7),
|
||||
view: allRoles.slice(0, 7),
|
||||
},
|
||||
personnel: {
|
||||
edit: allRoles.slice(0, 6).filter((r) => r !== 'accountant'),
|
||||
view: allRoles.slice(0, 6).filter((r) => r !== 'accountant'),
|
||||
},
|
||||
product: {
|
||||
edit: allRoles.slice(0, 7),
|
||||
view: allRoles,
|
||||
},
|
||||
workflow: {
|
||||
edit: allRoles.slice(0, 6),
|
||||
view: allRoles.filter((r) => r !== 'branch_accountant'),
|
||||
},
|
||||
customer: {
|
||||
edit: allRoles.slice(0, 9).filter((r) => r !== 'branch_accountant'),
|
||||
view: allRoles.slice(0, 9),
|
||||
},
|
||||
agencies: {
|
||||
edit: allRoles.slice(0, 7),
|
||||
view: allRoles,
|
||||
},
|
||||
quotation: {
|
||||
edit: allRoles.slice(0, 9).filter((r) => r !== 'branch_accountant'),
|
||||
view: allRoles.slice(0, 9),
|
||||
},
|
||||
taskOrder: {
|
||||
edit: [...allRoles.slice(0, 6), 'data_entry'],
|
||||
view: allRoles,
|
||||
},
|
||||
related: {
|
||||
// ใช้กับหลายเมนู
|
||||
edit: allRoles.slice(0, 6),
|
||||
view: allRoles,
|
||||
},
|
||||
// account: {
|
||||
// edit: allRoles.slice(0, 6),
|
||||
// view: allRoles.slice(0, 7),
|
||||
// },
|
||||
uploadSlip: {
|
||||
edit: allRoles.slice(0, 6),
|
||||
view: allRoles.filter((r) => r !== 'head_of_sale' && r !== 'sale'),
|
||||
},
|
||||
dashBoard: {
|
||||
edit: allRoles.slice(0, 6).filter((r) => r !== 'admin'),
|
||||
view: allRoles.filter((r) => r !== 'admin'),
|
||||
},
|
||||
};
|
||||
|
||||
export function canAccess(
|
||||
menu: keyof typeof permissions,
|
||||
action: 'edit' | 'view' = 'view',
|
||||
): boolean {
|
||||
// uma_authorization = all roles
|
||||
const roles = getRole() ?? [];
|
||||
if (roles.includes('system')) return true;
|
||||
|
||||
const allowedRoles = permissions[menu]?.[action] || [];
|
||||
|
||||
return allowedRoles.some((role: string) => roles.includes(role));
|
||||
}
|
||||
|
||||
export function resetScrollBar(elementId: string) {
|
||||
const element = document.getElementById(elementId);
|
||||
|
||||
|
|
@ -606,7 +694,7 @@ export function getEmployeeName(
|
|||
|
||||
return {
|
||||
['eng']: `${typeof employee.namePrefix === 'string' ? useOptionStore().mapOption(employee.namePrefix) : ''} ${employee.firstNameEN} ${employee.lastNameEN}`,
|
||||
['tha']: `${typeof employee.namePrefix === 'string' ? useOptionStore().mapOption(employee.namePrefix) : ''} ${employee.firstName} ${employee.lastName}`,
|
||||
['tha']: `${typeof employee.namePrefix === 'string' ? useOptionStore().mapOption(employee.namePrefix) : ''} ${employee.firstName || employee.firstNameEN} ${employee.lastName}`,
|
||||
}[opts?.locale || 'eng'];
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue