refactor: implement request list action dialog and enhance messenger functionality
Some checks failed
Spell Check / Spell Check with Typos (push) Failing after 7s
Some checks failed
Spell Check / Spell Check with Typos (push) Failing after 7s
This commit is contained in:
parent
a40f9f9775
commit
ed5a05709a
5 changed files with 300 additions and 1 deletions
|
|
@ -24,6 +24,8 @@ import { RequestData, RequestDataStatus } from 'src/stores/request-list/types';
|
||||||
import { dialogWarningClose } from 'src/stores/utils';
|
import { dialogWarningClose } from 'src/stores/utils';
|
||||||
import { CancelButton, SaveButton } from 'src/components/button';
|
import { CancelButton, SaveButton } from 'src/components/button';
|
||||||
import { getRole } from 'src/services/keycloak';
|
import { getRole } from 'src/services/keycloak';
|
||||||
|
import FloatingActionButton from 'src/components/FloatingActionButton.vue';
|
||||||
|
import RequestListAction from './RequestListAction .vue';
|
||||||
|
|
||||||
const $q = useQuasar();
|
const $q = useQuasar();
|
||||||
const navigatorStore = useNavigator();
|
const navigatorStore = useNavigator();
|
||||||
|
|
@ -32,6 +34,7 @@ const requestListStore = useRequestList();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { data, stats, page, pageMax, pageSize } = storeToRefs(requestListStore);
|
const { data, stats, page, pageMax, pageSize } = storeToRefs(requestListStore);
|
||||||
|
|
||||||
|
const requestListActionData = ref<RequestData[]>();
|
||||||
const refFilter = ref<InstanceType<typeof QSelect>>();
|
const refFilter = ref<InstanceType<typeof QSelect>>();
|
||||||
|
|
||||||
// NOTE: Variable
|
// NOTE: Variable
|
||||||
|
|
@ -45,6 +48,7 @@ const pageState = reactive({
|
||||||
rejectCancelDialog: false,
|
rejectCancelDialog: false,
|
||||||
rejectCancelReason: '',
|
rejectCancelReason: '',
|
||||||
requestId: '',
|
requestId: '',
|
||||||
|
requestListActionDialog: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const fieldSelectedOption = computed(() => {
|
const fieldSelectedOption = computed(() => {
|
||||||
|
|
@ -131,6 +135,33 @@ async function submitRejectCancel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function openRequestListDialog() {
|
||||||
|
const ret = await requestListStore.getRequestDataList({
|
||||||
|
page: 1,
|
||||||
|
pageSize: 999,
|
||||||
|
incomplete: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(ret);
|
||||||
|
if (ret) {
|
||||||
|
requestListActionData.value = ret.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
pageState.requestListActionDialog = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function submitRequestListAction(data: {
|
||||||
|
form: { responsibleUserLocal: boolean; responsibleUserId: string };
|
||||||
|
selected: RequestData[];
|
||||||
|
}) {
|
||||||
|
const res = await requestListStore.updateMessenger(
|
||||||
|
data.selected.map((v) => v.id),
|
||||||
|
data.form.responsibleUserId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res) pageState.requestListActionDialog = false;
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
pageState.gridView = $q.screen.lt.md ? true : false;
|
pageState.gridView = $q.screen.lt.md ? true : false;
|
||||||
navigatorStore.current.title = 'requestList.title';
|
navigatorStore.current.title = 'requestList.title';
|
||||||
|
|
@ -147,6 +178,13 @@ watch([() => pageState.inputSearch, () => pageState.statusFilter], () => {
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
<FloatingActionButton
|
||||||
|
hide-icon
|
||||||
|
style="z-index: 999"
|
||||||
|
icon="mdi-account-outline"
|
||||||
|
@click.stop="openRequestListDialog"
|
||||||
|
></FloatingActionButton>
|
||||||
|
|
||||||
<div class="column full-height no-wrap">
|
<div class="column full-height no-wrap">
|
||||||
<!-- SEC: stat -->
|
<!-- SEC: stat -->
|
||||||
<section class="text-body-2 q-mb-xs flex items-center">
|
<section class="text-body-2 q-mb-xs flex items-center">
|
||||||
|
|
@ -485,6 +523,13 @@ watch([() => pageState.inputSearch, () => pageState.statusFilter], () => {
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</DialogFormContainer>
|
</DialogFormContainer>
|
||||||
|
|
||||||
|
<RequestListAction
|
||||||
|
v-if="requestListActionData"
|
||||||
|
v-model="pageState.requestListActionDialog"
|
||||||
|
:request-list="requestListActionData"
|
||||||
|
@submit="submitRequestListAction"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<style></style>
|
<style></style>
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ const props = defineProps<{
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
step: Step;
|
step: Step;
|
||||||
responsibleAreaDistrictId?: string;
|
responsibleAreaDistrictId?: string;
|
||||||
|
defaultMessenger?: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
|
@ -85,7 +86,8 @@ function assignToForm() {
|
||||||
companyDuty: attributesForm.value.companyDuty ?? false,
|
companyDuty: attributesForm.value.companyDuty ?? false,
|
||||||
companyDutyCost: attributesForm.value.companyDutyCost ?? 30,
|
companyDutyCost: attributesForm.value.companyDutyCost ?? 30,
|
||||||
responsibleUserLocal: attributesForm.value.responsibleUserLocal ?? true,
|
responsibleUserLocal: attributesForm.value.responsibleUserLocal ?? true,
|
||||||
responsibleUserId: attributesForm.value.responsibleUserId ?? '',
|
responsibleUserId:
|
||||||
|
attributesForm.value.responsibleUserId || props.defaultMessenger,
|
||||||
individualDuty: attributesForm.value.individualDuty ?? false,
|
individualDuty: attributesForm.value.individualDuty ?? false,
|
||||||
individualDutyCost: attributesForm.value.individualDutyCost ?? 10,
|
individualDutyCost: attributesForm.value.individualDutyCost ?? 10,
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
226
src/pages/08_request-list/RequestListAction .vue
Normal file
226
src/pages/08_request-list/RequestListAction .vue
Normal file
|
|
@ -0,0 +1,226 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, ref } from 'vue';
|
||||||
|
import { RequestData } from 'src/stores/request-list';
|
||||||
|
import { DialogContainer, DialogHeader } from 'src/components/dialog';
|
||||||
|
import {
|
||||||
|
BackButton,
|
||||||
|
CancelButton,
|
||||||
|
MainButton,
|
||||||
|
SaveButton,
|
||||||
|
} from 'src/components/button';
|
||||||
|
import TableProductAndService from 'src/components/shared/table/TableProductAndService.vue';
|
||||||
|
import { Product } from 'src/stores/product-service/types';
|
||||||
|
import FormResponsibleUser from './FormResponsibleUser.vue';
|
||||||
|
import FormGroupHead from './FormGroupHead.vue';
|
||||||
|
import TableRequestList from './TableRequestList.vue';
|
||||||
|
import { column } from './constants';
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
requestList: RequestData[];
|
||||||
|
}>();
|
||||||
|
|
||||||
|
defineEmits<{
|
||||||
|
(
|
||||||
|
e: 'submit',
|
||||||
|
data: {
|
||||||
|
form: { responsibleUserLocal: boolean; responsibleUserId: string };
|
||||||
|
selected: RequestData[];
|
||||||
|
},
|
||||||
|
): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
enum Step {
|
||||||
|
RequestList = 1,
|
||||||
|
Configure = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
const open = defineModel<boolean>({ default: false });
|
||||||
|
const step = ref<Step>(Step.RequestList);
|
||||||
|
const selected = ref<RequestData[]>([]);
|
||||||
|
const form = reactive({
|
||||||
|
responsibleUserLocal: false,
|
||||||
|
responsibleUserId: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
step.value = Step.RequestList;
|
||||||
|
selected.value = [];
|
||||||
|
form.responsibleUserLocal = false;
|
||||||
|
form.responsibleUserId = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function prev() {
|
||||||
|
step.value = Step.RequestList;
|
||||||
|
console.log(selected.value[0]);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<DialogContainer v-model="open" :onOpen="reset">
|
||||||
|
<template #header>
|
||||||
|
<DialogHeader :title="$t('requestList.action.title')" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div class="surface-0 q-pa-md">
|
||||||
|
<div class="stepper-wrapper">
|
||||||
|
<div class="stepper">
|
||||||
|
<template
|
||||||
|
v-for="(label, i) in [
|
||||||
|
$t('menu.product'),
|
||||||
|
$t('requestList.action.configure'),
|
||||||
|
]"
|
||||||
|
:key="i"
|
||||||
|
>
|
||||||
|
<span class="step" :class="{ ['step__active']: step > i }">
|
||||||
|
<span class="step-outer"><span class="step-inner" /></span>
|
||||||
|
<span class="step-label">{{ label }}</span>
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="step-connector"
|
||||||
|
:class="{ ['step-connector__active']: step > i + 1 }"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="surface-1 q-pa-md col full-width scroll">
|
||||||
|
<TableRequestList
|
||||||
|
v-if="step === Step.RequestList"
|
||||||
|
v-model:selected="selected"
|
||||||
|
hide-action
|
||||||
|
hide-view
|
||||||
|
checkable
|
||||||
|
:columns="column"
|
||||||
|
:rows="requestList"
|
||||||
|
:visible-columns="[...column.map((col) => col.name)]"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<template v-if="step === Step.Configure">
|
||||||
|
<q-expansion-item
|
||||||
|
dense
|
||||||
|
class="overflow-hidden bordered full-width"
|
||||||
|
switch-toggle-side
|
||||||
|
style="border-radius: var(--radius-2)"
|
||||||
|
expand-icon="mdi-chevron-down-circle"
|
||||||
|
header-class="surface-1 q-py-sm text-medium text-body1"
|
||||||
|
default-opened
|
||||||
|
>
|
||||||
|
<template #header>
|
||||||
|
<span>
|
||||||
|
{{ $t('requestList.employeeMessenger') }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<FormGroupHead>
|
||||||
|
{{
|
||||||
|
$t('general.select', { msg: $t('requestList.employeeMessenger') })
|
||||||
|
}}
|
||||||
|
</FormGroupHead>
|
||||||
|
|
||||||
|
<FormResponsibleUser
|
||||||
|
v-model:responsible-user-id="form.responsibleUserId"
|
||||||
|
v-model:responsible-user-local="form.responsibleUserLocal"
|
||||||
|
/>
|
||||||
|
</q-expansion-item>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<div class="q-gutter-x-xs q-ml-auto">
|
||||||
|
<CancelButton
|
||||||
|
v-if="step === Step.RequestList"
|
||||||
|
id="btn-cancel"
|
||||||
|
outlined
|
||||||
|
@click="
|
||||||
|
reset();
|
||||||
|
open = false;
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<BackButton
|
||||||
|
v-if="step === Step.Configure"
|
||||||
|
id="btn-back"
|
||||||
|
outlined
|
||||||
|
@click="prev"
|
||||||
|
/>
|
||||||
|
<MainButton
|
||||||
|
icon="mdi-check"
|
||||||
|
color="207 96% 32%"
|
||||||
|
solid
|
||||||
|
id="btn-next"
|
||||||
|
v-if="step === Step.RequestList"
|
||||||
|
@click="step = Step.Configure"
|
||||||
|
>
|
||||||
|
{{ $t('general.next') }}
|
||||||
|
</MainButton>
|
||||||
|
<SaveButton
|
||||||
|
v-if="step === Step.Configure"
|
||||||
|
id="btn-save"
|
||||||
|
solid
|
||||||
|
@click="$emit('submit', { form, selected })"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</DialogContainer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.stepper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
margin-inline: 25%;
|
||||||
|
|
||||||
|
& > .step {
|
||||||
|
--__color: var(--gray-5);
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
gap: 0.25rem;
|
||||||
|
|
||||||
|
&.step__active {
|
||||||
|
--__color: var(--brand-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .step-label {
|
||||||
|
position: absolute;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--__color);
|
||||||
|
white-space: nowrap;
|
||||||
|
top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .step-outer {
|
||||||
|
display: inline-flex;
|
||||||
|
border: 2px solid var(--__color);
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 1.5rem;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
& > .step-inner {
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: var(--__color);
|
||||||
|
width: 0.7rem;
|
||||||
|
height: 0.7rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .step-connector {
|
||||||
|
display: block;
|
||||||
|
border-bottom: 2px solid var(--gray-5);
|
||||||
|
flex-grow: 1;
|
||||||
|
|
||||||
|
&.step-connector__active {
|
||||||
|
border-color: var(--brand-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -873,6 +873,11 @@ async function submitRejectCancel() {
|
||||||
:readonly="
|
:readonly="
|
||||||
data.requestDataStatus === RequestDataStatus.Canceled
|
data.requestDataStatus === RequestDataStatus.Canceled
|
||||||
"
|
"
|
||||||
|
:default-messenger="
|
||||||
|
value.stepStatus[pageState.currentStep - 1]
|
||||||
|
? undefined
|
||||||
|
: data.defaultMessengerId
|
||||||
|
"
|
||||||
:step="{
|
:step="{
|
||||||
step: pageState.currentStep,
|
step: pageState.currentStep,
|
||||||
requestWorkId: value.id || '',
|
requestWorkId: value.id || '',
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ const props = withDefaults(
|
||||||
grid?: boolean;
|
grid?: boolean;
|
||||||
visibleColumns?: string[];
|
visibleColumns?: string[];
|
||||||
hideAction?: boolean;
|
hideAction?: boolean;
|
||||||
|
hideView?: boolean;
|
||||||
|
checkable?: boolean;
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
row: () => [],
|
row: () => [],
|
||||||
|
|
@ -36,6 +38,8 @@ defineEmits<{
|
||||||
(e: 'rejectCancel', data: RequestData): void;
|
(e: 'rejectCancel', data: RequestData): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const selected = defineModel<unknown[]>('selected');
|
||||||
|
|
||||||
function responsiblePerson(quotation: QuotationFull): CreatedBy[] | undefined {
|
function responsiblePerson(quotation: QuotationFull): CreatedBy[] | undefined {
|
||||||
const productServiceList = quotation.productServiceList;
|
const productServiceList = quotation.productServiceList;
|
||||||
const tempPerson: CreatedBy[] = [];
|
const tempPerson: CreatedBy[] = [];
|
||||||
|
|
@ -106,12 +110,25 @@ function getEmployeeName(
|
||||||
card-container-class="q-col-gutter-sm"
|
card-container-class="q-col-gutter-sm"
|
||||||
:rows-per-page-options="[0]"
|
:rows-per-page-options="[0]"
|
||||||
class="full-width"
|
class="full-width"
|
||||||
|
selection="multiple"
|
||||||
|
v-model:selected="selected"
|
||||||
|
:selected-rows-label="
|
||||||
|
(n) =>
|
||||||
|
$t('general.selected', {
|
||||||
|
number: n,
|
||||||
|
msg: $t('general.list'),
|
||||||
|
})
|
||||||
|
"
|
||||||
|
:no-data-label="$t('general.noDataTable')"
|
||||||
>
|
>
|
||||||
<template v-slot:header="props">
|
<template v-slot:header="props">
|
||||||
<q-tr
|
<q-tr
|
||||||
style="background-color: hsla(var(--info-bg) / 0.07)"
|
style="background-color: hsla(var(--info-bg) / 0.07)"
|
||||||
:props="props"
|
:props="props"
|
||||||
>
|
>
|
||||||
|
<q-th v-if="checkable">
|
||||||
|
<q-checkbox v-model="props.selected" size="sm" />
|
||||||
|
</q-th>
|
||||||
<q-th v-for="col in props.cols" :key="col.name" :props="props">
|
<q-th v-for="col in props.cols" :key="col.name" :props="props">
|
||||||
{{ col.label && $t(col.label) }}
|
{{ col.label && $t(col.label) }}
|
||||||
</q-th>
|
</q-th>
|
||||||
|
|
@ -128,6 +145,9 @@ function getEmployeeName(
|
||||||
:class="{ urgent: props.row.quotation.urgent, dark: $q.dark.isActive }"
|
:class="{ urgent: props.row.quotation.urgent, dark: $q.dark.isActive }"
|
||||||
class="text-center"
|
class="text-center"
|
||||||
>
|
>
|
||||||
|
<q-td v-if="checkable">
|
||||||
|
<q-checkbox v-model="props.selected" size="sm" />
|
||||||
|
</q-td>
|
||||||
<q-td v-if="visibleColumns.includes('order')">
|
<q-td v-if="visibleColumns.includes('order')">
|
||||||
{{ props.rowIndex + 1 }}
|
{{ props.rowIndex + 1 }}
|
||||||
</q-td>
|
</q-td>
|
||||||
|
|
@ -215,6 +235,7 @@ function getEmployeeName(
|
||||||
</q-td>
|
</q-td>
|
||||||
<q-td class="text-right">
|
<q-td class="text-right">
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="!hideView"
|
||||||
:id="`btn-eye-${props.row.code}`"
|
:id="`btn-eye-${props.row.code}`"
|
||||||
icon="mdi-eye-outline"
|
icon="mdi-eye-outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue