Merge branch 'dev/phat-2' into develop

This commit is contained in:
puriphatt 2024-04-22 14:06:15 +07:00
commit f2168a9e59
8 changed files with 178 additions and 83 deletions

View file

@ -212,6 +212,12 @@ watch(districtId, fetchSubDistrict);
:label="$t('province')" :label="$t('province')"
class="col-3" class="col-3"
:options="addrOptions.provinceOps" :options="addrOptions.provinceOps"
lazy-rules
:rules="[
(val) =>
(val && val.length > 0) || $t('formDialogInputProvinceValidate'),
]"
@update:model-value="districtId = subDistrictId = zipCode = null"
/> />
<q-select <q-select
id="select-district-en" id="select-district-en"
@ -228,6 +234,12 @@ watch(districtId, fetchSubDistrict);
:label="$t('district')" :label="$t('district')"
class="col-3" class="col-3"
:options="addrOptions.districtOps" :options="addrOptions.districtOps"
lazy-rules
:rules="[
(val) =>
(val && val.length > 0) || $t('formDialogInputDistrictValidate'),
]"
@update:model-value="subDistrictId = zipCode = null"
/> />
<q-select <q-select
id="select-sub-district-en" id="select-sub-district-en"
@ -244,6 +256,11 @@ watch(districtId, fetchSubDistrict);
:label="$t('subDistrict')" :label="$t('subDistrict')"
class="col-3" class="col-3"
:options="addrOptions.subDistrictOps" :options="addrOptions.subDistrictOps"
lazy-rules
:rules="[
(val) =>
(val && val.length > 0) || $t('formDialogInputSubDistrictValidate'),
]"
@update:model-value="(v: string) => selectSubDistrict(v)" @update:model-value="(v: string) => selectSubDistrict(v)"
/> />
<q-input <q-input

View file

@ -24,8 +24,8 @@ const importNationality = defineModel<string | null | undefined>(
'importNationality', 'importNationality',
); );
const trainingPlace = defineModel<string | null | undefined>('trainingPlace'); const trainingPlace = defineModel<string | null | undefined>('trainingPlace');
const checkpoint = defineModel<string>('checkPoint'); const checkpoint = defineModel<string | null | undefined>('checkPoint');
const checkpointEN = defineModel<string>('checkPointEN'); const checkpointEN = defineModel<string | null | undefined>('checkPointEN');
const agencyFile = defineModel<File[]>('agencyFile'); const agencyFile = defineModel<File[]>('agencyFile');
const agencyFileList = const agencyFileList =
defineModel<{ name: string; url: string }[]>('agencyFileList'); defineModel<{ name: string; url: string }[]>('agencyFileList');

View file

@ -44,7 +44,7 @@ async function selectHq(id: string) {
map-options map-options
options-dense options-dense
hide-bottom-space hide-bottom-space
class="col-6" class="col-4"
v-model="hqId" v-model="hqId"
option-label="label" option-label="label"
option-value="value" option-value="value"
@ -65,13 +65,31 @@ async function selectHq(id: string) {
options-dense options-dense
clearable clearable
hide-bottom-space hide-bottom-space
class="col-6" class="col-4"
v-model="brId" v-model="brId"
:label="$t('formDialogInputBrId')" :label="$t('formDialogInputBrId')"
option-label="label" option-label="label"
option-value="value" option-value="value"
:options="userStore.userOption.brOpts" :options="userStore.userOption.brOpts"
/> />
<q-input
id="input-username"
:dense="dense"
:outlined="readonly ? false : outlined"
:borderless="readonly"
:readonly="usernameReadonly"
emit-value
map-options
options-dense
hide-bottom-space
class="col-4"
:label="$t('formDialogInputUsername')"
v-model="username"
:rules="[
(val: string) =>
val.length > 2 || $t('formDialogInputUsernameValidate'),
]"
/>
<q-select <q-select
id="select-user-type" id="select-user-type"
:dense="dense" :dense="dense"
@ -83,7 +101,7 @@ async function selectHq(id: string) {
map-options map-options
options-dense options-dense
hide-bottom-space hide-bottom-space
class="col-3" class="col-6"
option-value="value" option-value="value"
option-label="label" option-label="label"
:label="$t('formDialogInputUserType')" :label="$t('formDialogInputUserType')"
@ -102,7 +120,7 @@ async function selectHq(id: string) {
map-options map-options
options-dense options-dense
hide-bottom-space hide-bottom-space
class="col-3" class="col-6"
:label="$t('formDialogInputUserRole')" :label="$t('formDialogInputUserRole')"
option-label="label" option-label="label"
option-value="value" option-value="value"
@ -110,25 +128,7 @@ async function selectHq(id: string) {
:options="userStore.userOption.roleOpts" :options="userStore.userOption.roleOpts"
:rules="[(val: string) => !!val || $t('formDialogInputUserRoleValidate')]" :rules="[(val: string) => !!val || $t('formDialogInputUserRoleValidate')]"
/> />
<q-input <!-- <q-input
id="input-username"
:dense="dense"
:outlined="readonly ? false : outlined"
:borderless="readonly"
:readonly="usernameReadonly"
emit-value
map-options
options-dense
hide-bottom-space
class="col-3"
:label="$t('formDialogInputUsername')"
v-model="username"
:rules="[
(val: string) =>
val.length > 2 || $t('formDialogInputUsernameValidate'),
]"
/>
<q-input
id="input-user-code" id="input-user-code"
:dense="dense" :dense="dense"
:outlined="readonly ? false : outlined" :outlined="readonly ? false : outlined"
@ -138,7 +138,7 @@ async function selectHq(id: string) {
class="col-3" class="col-3"
:label="$t('formDialogInputUserCode')" :label="$t('formDialogInputUserCode')"
v-model="userCode" v-model="userCode"
/> /> -->
</div> </div>
<q-separator <q-separator
v-if="separator" v-if="separator"

View file

@ -1,11 +1,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { ref } from 'vue';
import AppBox from './app/AppBox.vue';
defineProps<{ defineProps<{
title: string; title: string;
isEdit?: boolean; isEdit?: boolean;
bgOn?: boolean; bgOn?: boolean;
statusBranch?: string; statusBranch?: string;
badgeLabel?: string;
badgeClass?: string;
editData?: (...args: unknown[]) => void; editData?: (...args: unknown[]) => void;
deleteData?: (...args: unknown[]) => void; deleteData?: (...args: unknown[]) => void;
submit?: (...args: unknown[]) => void; submit?: (...args: unknown[]) => void;
@ -103,6 +106,13 @@ function reset() {
: $t('statusACTIVE') : $t('statusACTIVE')
}} }}
</text> </text>
<text
v-if="badgeLabel"
class="badge-label q-px-sm text-caption"
:class="badgeClass"
>
{{ badgeLabel }}
</text>
</div> </div>
<div style="width: 31.98px"></div> <div style="width: 31.98px"></div>
@ -214,4 +224,11 @@ function reset() {
background-color: hsla(var(--_branch-badge-bg) / 0.1); background-color: hsla(var(--_branch-badge-bg) / 0.1);
} }
} }
.badge-label {
display: inline-block;
border-radius: var(--radius-6);
background-color: var(--surface-2);
text-wrap: nowrap;
}
</style> </style>

View file

@ -9,6 +9,8 @@ defineProps<{
addressTitleEN?: string; addressTitleEN?: string;
addressSeparator?: boolean; addressSeparator?: boolean;
branchStatus?: string; branchStatus?: string;
badgeLabel?: string;
badgeClass?: string;
submit?: (...args: unknown[]) => void; submit?: (...args: unknown[]) => void;
close?: (...args: unknown[]) => void; close?: (...args: unknown[]) => void;
}>(); }>();
@ -27,7 +29,7 @@ const zipCode = defineModel<string>('zipCode', { default: '' });
style=" style="
padding: 0; padding: 0;
border-radius: var(--radius-2); border-radius: var(--radius-2);
max-width: 80%; max-width: 85%;
max-height: 100%; max-height: 100%;
" "
> >
@ -39,7 +41,14 @@ const zipCode = defineModel<string>('zipCode', { default: '' });
<div class="col text-subtitle1 text-weight-bold text-center"> <div class="col text-subtitle1 text-weight-bold text-center">
{{ title }} {{ title }}
<div>{{ branchStatus ? `(${branchStatus})` : '' }}</div> <text>{{ branchStatus ? `(${branchStatus})` : '' }}</text>
<text
v-if="badgeLabel"
class="badge-label q-px-sm text-caption"
:class="badgeClass"
>
{{ badgeLabel }}
</text>
</div> </div>
<q-btn <q-btn
round round
@ -169,4 +178,11 @@ const zipCode = defineModel<string>('zipCode', { default: '' });
.form-footer { .form-footer {
border-top: 1px solid var(--border-color); border-top: 1px solid var(--border-color);
} }
.badge-label {
display: inline-block;
border-radius: var(--radius-6);
background-color: var(--surface-2);
text-wrap: nowrap;
}
</style> </style>

View file

@ -147,3 +147,21 @@ html {
color: hsl(var(--positive-fg)); color: hsl(var(--positive-fg));
background-color: hsl(var(--positive-bg)); background-color: hsl(var(--positive-bg));
} }
.app-text-male {
color: hsl(var(--gender-male));
}
.app-bg-male {
color: hsl(var(--positive-fg));
background-color: hsl(var(--gender-male)) !important;
}
.app-text-female {
color: hsl(var(--gender-female));
}
.app-bg-female {
color: hsl(var(--positive-fg));
background-color: hsl(var(--gender-female)) !important;
}

View file

@ -13,8 +13,9 @@ import { useI18n } from 'vue-i18n';
import useLoader from 'stores/loader'; import useLoader from 'stores/loader';
import DrawerComponent from 'components/DrawerComponent.vue'; import DrawerComponent from 'components/DrawerComponent.vue';
import GlobalDialog from 'components/GlobalDialog.vue';
import useUserStore from 'src/stores/user'; import useUserStore from 'src/stores/user';
import { Option } from 'src/stores/user/types';
import { dialog } from 'src/stores/utils';
interface NotificationButton { interface NotificationButton {
item: string; item: string;
@ -34,11 +35,12 @@ const loaderStore = useLoader();
const { visible } = storeToRefs(loaderStore); const { visible } = storeToRefs(loaderStore);
const { locale } = useI18n({ useScope: 'global' }); const { locale } = useI18n({ useScope: 'global' });
const userStore = useUserStore();
const logoutModal = ref(false);
const leftDrawerOpen = ref(false); const leftDrawerOpen = ref(false);
const filterUnread = ref(false); const filterUnread = ref(false);
const unread = ref<number>(1); const unread = ref<number>(1);
const filterRole = ref<string[]>();
const currentLanguage = ref<string>('ไทย'); const currentLanguage = ref<string>('ไทย');
const language: { const language: {
@ -100,21 +102,46 @@ function setActive(button: NotificationButton) {
} }
} }
function doLogout(confirm: boolean = false) { function doLogout() {
logoutModal.value = true; dialog({
if (confirm) { icon: 'mdi-logout-variant',
logoutModal.value = false; title: 'ยืนยันการออกจากระบบ',
logout(); persistent: true,
} message: 'คุณต้องการออกจากระบบ ใช่หรือไม่',
action: async () => {
logout();
},
});
}
function getRoleName(userRoleValue?: string[], roleOptions: Option[]) {
if (!userRoleValue || !roleOptions) return;
const matchingRole: string | undefined = roleOptions.find(
(role) => role.value === userRoleValue[0],
)?.label;
return matchingRole ? matchingRole : '';
} }
onMounted(async () => { onMounted(async () => {
const user = getUsername(); const user = getUsername();
const uid = getUserId(); const uid = getUserId();
const userRoles = getRole();
if (userRoles) {
console.log(userRoles);
filterRole.value = userRoles.filter(
(role) =>
role !== 'default-roles-dev' &&
role !== 'offline_access' &&
role !== 'uma_authorization',
);
}
if (user === 'admin') return; if (user === 'admin') return;
if (uid) { if (uid) {
const res = await useUserStore().fetchById(uid); const res = await userStore.fetchById(uid);
if (res && res.profileImageUrl) userImage.value = res.profileImageUrl; if (res && res.profileImageUrl) userImage.value = res.profileImageUrl;
} }
@ -260,7 +287,9 @@ onMounted(async () => {
{{ getName() }} {{ getName() }}
</span> </span>
<div style="font-size: 11px; color: var(--surface)"> <div style="font-size: 11px; color: var(--surface)">
{{ getRole()?.includes('admin') ? 'Admin' : 'User' }} {{
getRoleName(filterRole, userStore.userOption.roleOpts)
}}
</div> </div>
</q-item-label> </q-item-label>
</q-item-section> </q-item-section>
@ -347,14 +376,6 @@ onMounted(async () => {
<drawer-component v-model:leftDrawerOpen="leftDrawerOpen" /> <drawer-component v-model:leftDrawerOpen="leftDrawerOpen" />
<GlobalDialog
v-model="logoutModal"
title="ยืนยันการออกจากระบบ"
message="คุณต้องการออกจากระบบ ใช่หรือไม่"
icon="mdi-logout-variant"
:persistent="true"
:action="() => doLogout(true)"
/>
<global-loading :visibility="visible" /> <global-loading :visibility="visible" />
</q-layout> </q-layout>
</template> </template>

View file

@ -70,6 +70,7 @@ const defaultFormData = {
checkpointEN: null, checkpointEN: null,
}; };
const userCode = ref<string>();
const currentUser = ref<User>(); const currentUser = ref<User>();
const infoPersonCardEdit = ref(false); const infoPersonCardEdit = ref(false);
const infoPersonId = ref<string>(''); const infoPersonId = ref<string>('');
@ -86,7 +87,6 @@ const userId = ref<string>();
const selectorLabel = ref<string>(''); const selectorLabel = ref<string>('');
const hqId = ref<string>(); const hqId = ref<string>();
const brId = ref<string>(); const brId = ref<string>();
const code = ref<string>();
const formDialogRef = ref(); const formDialogRef = ref();
const userStats = ref<BranchUserStats[]>(); const userStats = ref<BranchUserStats[]>();
const typeStats = ref<UserTypeStats>(); const typeStats = ref<UserTypeStats>();
@ -156,12 +156,33 @@ const selectorList = computed(() => [
]); ]);
async function openDialog(action?: 'FORM' | 'INFO', idEdit?: string) { async function openDialog(action?: 'FORM' | 'INFO', idEdit?: string) {
if (userStore.userOption.hqOpts.length === 0) {
await userStore.fetchHqOption();
}
if (userStore.userOption.roleOpts.length === 0) {
await userStore.fetchRoleOption();
}
if (idEdit && userData.value) {
assignFormData(idEdit);
isEdit.value = true;
if (formData.value.userType === 'AGENCY') {
const result = await userStore.fetchAttachment(idEdit);
if (result) {
agencyFileList.value = result;
}
}
}
if (action === 'FORM') { if (action === 'FORM') {
modal.value = true; modal.value = true;
} else if (action === 'INFO') { } else if (action === 'INFO') {
if (!userData.value) return;
infoDrawer.value = true; infoDrawer.value = true;
infoPersonCardEdit.value = false; infoPersonCardEdit.value = false;
if (!userData.value) return;
const user = userData.value.result.find((x) => x.id === idEdit); const user = userData.value.result.find((x) => x.id === idEdit);
infoPersonCard.value = user infoPersonCard.value = user
? [ ? [
@ -182,33 +203,8 @@ async function openDialog(action?: 'FORM' | 'INFO', idEdit?: string) {
} }
statusToggle.value = true; statusToggle.value = true;
profileSubmit.value = false;
userStore.userOption.brOpts = []; userStore.userOption.brOpts = [];
hqId.value = userStore.userOption.hqOpts[0].value;
if (userStore.userOption.hqOpts.length === 0) {
await userStore.fetchHqOption();
}
if (userStore.userOption.hqOpts.length === 1) {
hqId.value = userStore.userOption.hqOpts[0].value;
}
if (userStore.userOption.roleOpts.length === 0) {
await userStore.fetchRoleOption();
}
if (idEdit && userData.value) {
isEdit.value = true;
assignFormData(idEdit);
if (formData.value.userType === 'AGENCY') {
const result = await userStore.fetchAttachment(idEdit);
if (result) {
agencyFileList.value = result;
}
}
}
} }
function undo() { function undo() {
@ -218,16 +214,16 @@ function undo() {
} }
function onClose() { function onClose() {
code.value = '';
hqId.value = ''; hqId.value = '';
brId.value = ''; brId.value = '';
userId.value = ''; userId.value = '';
userCode.value = '';
urlProfile.value = ''; urlProfile.value = '';
agencyFile.value = []; agencyFile.value = [];
profileSubmit.value = false;
modal.value = false; modal.value = false;
infoDrawer.value = false;
isEdit.value = false; isEdit.value = false;
infoDrawer.value = false;
profileSubmit.value = false;
statusToggle.value = true; statusToggle.value = true;
Object.assign(formData.value, defaultFormData); Object.assign(formData.value, defaultFormData);
mapUserType(selectorLabel.value); mapUserType(selectorLabel.value);
@ -300,7 +296,10 @@ async function onSubmit() {
userType: selectorLabel.value ?? undefined, userType: selectorLabel.value ?? undefined,
}); });
typeStats.value = await userStore.typeStats(); typeStats.value = await userStore.typeStats();
const res = await branchStore.userStats(formData.value.userType);
if (res) {
userStats.value = res;
}
onClose(); onClose();
}, },
}); });
@ -346,7 +345,10 @@ async function onSubmit() {
userType: selectorLabel.value ?? undefined, userType: selectorLabel.value ?? undefined,
}); });
typeStats.value = await userStore.typeStats(); typeStats.value = await userStore.typeStats();
const res = await branchStore.userStats(formData.value.userType);
if (res) {
userStats.value = res;
}
onClose(); onClose();
}, },
}); });
@ -380,7 +382,6 @@ function mapUserType(label: string) {
DELEGATE: 'DELEGATE', DELEGATE: 'DELEGATE',
AGENCY: 'AGENCY', AGENCY: 'AGENCY',
}; };
formData.value.userType = userTypeMap[label]; formData.value.userType = userTypeMap[label];
} }
@ -398,6 +399,7 @@ async function toggleStatus(id: string) {
async function assignFormData(idEdit: string) { async function assignFormData(idEdit: string) {
if (!userData.value) return; if (!userData.value) return;
const foundUser = userData.value.result.find((user) => user.id === idEdit); const foundUser = userData.value.result.find((user) => user.id === idEdit);
if (foundUser) { if (foundUser) {
currentUser.value = foundUser; currentUser.value = foundUser;
infoPersonId.value = currentUser.value.id; infoPersonId.value = currentUser.value.id;
@ -456,7 +458,7 @@ async function assignFormData(idEdit: string) {
} }
} }
code.value = foundUser.code; userCode.value = foundUser.code;
urlProfile.value = foundUser.profileImageUrl; urlProfile.value = foundUser.profileImageUrl;
isEdit.value = true; isEdit.value = true;
profileSubmit.value = true; profileSubmit.value = true;
@ -701,6 +703,8 @@ watch(
<DrawerInfo <DrawerInfo
v-if="currentUser" v-if="currentUser"
bg-on bg-on
:badgeClass="formData.gender === 'male' ? 'app-bg-male' : 'app-bg-female'"
:badgeLabel="userCode"
:isEdit="infoPersonCardEdit" :isEdit="infoPersonCardEdit"
:title=" :title="
$i18n.locale === 'en-US' $i18n.locale === 'en-US'
@ -752,7 +756,7 @@ watch(
v-model:userType="formData.userType" v-model:userType="formData.userType"
v-model:userRole="formData.userRole" v-model:userRole="formData.userRole"
v-model:username="formData.username" v-model:username="formData.username"
v-model:userCode="code" v-model:userCode="userCode"
/> />
</template> </template>
<template #person> <template #person>
@ -801,6 +805,8 @@ watch(
<FormDialog <FormDialog
removeDialog removeDialog
ref="formDialogRef" ref="formDialogRef"
:badgeClass="formData.gender === 'male' ? 'app-bg-male' : 'app-bg-female'"
:badgeLabel="userCode"
:title="$t('personnelAdd')" :title="$t('personnelAdd')"
:addressTitle="$t('formDialogTitleAddressPure')" :addressTitle="$t('formDialogTitleAddressPure')"
:addressTitleEN="$t('formDialogTitleAddressPure') + ' ENG'" :addressTitleEN="$t('formDialogTitleAddressPure') + ' ENG'"
@ -909,7 +915,7 @@ watch(
v-model:userType="formData.userType" v-model:userType="formData.userType"
v-model:userRole="formData.userRole" v-model:userRole="formData.userRole"
v-model:username="formData.username" v-model:username="formData.username"
v-model:userCode="code" v-model:userCode="userCode"
/> />
</template> </template>
<template #person> <template #person>