refactor: workflow
This commit is contained in:
parent
249f7d59f5
commit
3395995f68
4 changed files with 562 additions and 165 deletions
|
|
@ -7,20 +7,32 @@ import useUserStore from 'src/stores/user';
|
||||||
import useOptionStore from 'src/stores/options';
|
import useOptionStore from 'src/stores/options';
|
||||||
import { baseUrl } from 'stores/utils';
|
import { baseUrl } from 'stores/utils';
|
||||||
import { getRole } from 'src/services/keycloak';
|
import { getRole } from 'src/services/keycloak';
|
||||||
import { WorkflowTemplatePayload } from 'src/stores/workflow-template/types';
|
import {
|
||||||
|
WorkflowUserInTable,
|
||||||
|
WorkflowTemplatePayload,
|
||||||
|
} from 'src/stores/workflow-template/types';
|
||||||
import { User } from 'src/stores/user/types';
|
import { User } from 'src/stores/user/types';
|
||||||
|
|
||||||
import SelectInput from '../shared/SelectInput.vue';
|
import SelectInput from '../shared/SelectInput.vue';
|
||||||
import ToggleButton from 'src/components/button/ToggleButton.vue';
|
import ToggleButton from 'src/components/button/ToggleButton.vue';
|
||||||
import { DeleteButton } from '../button';
|
import { DeleteButton } from '../button';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
readonly?: boolean;
|
||||||
|
onDrawer?: boolean;
|
||||||
|
}>();
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const optionStore = useOptionStore();
|
const optionStore = useOptionStore();
|
||||||
|
|
||||||
|
const userInTable = defineModel<WorkflowUserInTable[]>('userInTable', {
|
||||||
|
default: [],
|
||||||
|
});
|
||||||
const registerBranchId = defineModel('registerBranchId', { default: '' });
|
const registerBranchId = defineModel('registerBranchId', { default: '' });
|
||||||
const flowData = defineModel<WorkflowTemplatePayload>('flowData', {
|
const flowData = defineModel<WorkflowTemplatePayload>('flowData', {
|
||||||
required: true,
|
required: true,
|
||||||
default: {
|
default: {
|
||||||
|
status: 'CREATED',
|
||||||
name: '',
|
name: '',
|
||||||
step: [],
|
step: [],
|
||||||
},
|
},
|
||||||
|
|
@ -28,7 +40,6 @@ const flowData = defineModel<WorkflowTemplatePayload>('flowData', {
|
||||||
|
|
||||||
const role = ref<string[]>([]);
|
const role = ref<string[]>([]);
|
||||||
const userList = ref<User[]>([]);
|
const userList = ref<User[]>([]);
|
||||||
const userInTable = ref<User[]>([]);
|
|
||||||
const responsiblePersonSearch = ref('');
|
const responsiblePersonSearch = ref('');
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
|
|
@ -58,10 +69,10 @@ async function getUserList(opts?: { query: string }) {
|
||||||
if (resUser) userList.value = resUser.result;
|
if (resUser) userList.value = resUser.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getUserById(responsiblePersonId: string) {
|
// async function getUserById(responsiblePersonId: string) {
|
||||||
const resUser = await userStore.fetchById(responsiblePersonId);
|
// const resUser = await userStore.fetchById(responsiblePersonId);
|
||||||
if (resUser) userInTable.value.push(resUser);
|
// if (resUser) userInTable.value.push(resUser);
|
||||||
}
|
// }
|
||||||
|
|
||||||
function selectResponiblePerson(stepIndex: number, responsiblePerson: User) {
|
function selectResponiblePerson(stepIndex: number, responsiblePerson: User) {
|
||||||
const currStep = flowData.value.step[stepIndex];
|
const currStep = flowData.value.step[stepIndex];
|
||||||
|
|
@ -71,16 +82,38 @@ function selectResponiblePerson(stepIndex: number, responsiblePerson: User) {
|
||||||
|
|
||||||
if (existPersonIndex === -1) {
|
if (existPersonIndex === -1) {
|
||||||
currStep.responsiblePersonId?.push(responsiblePerson.id);
|
currStep.responsiblePersonId?.push(responsiblePerson.id);
|
||||||
userInTable.value.push(responsiblePerson);
|
|
||||||
|
if (!userInTable.value[stepIndex]) {
|
||||||
|
userInTable.value[stepIndex] = {
|
||||||
|
name: flowData.value.step[stepIndex].name,
|
||||||
|
resposiblePerson: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
userInTable.value[stepIndex]?.resposiblePerson.push({
|
||||||
|
id: responsiblePerson.id,
|
||||||
|
selectedImage: responsiblePerson.selectedImage,
|
||||||
|
gender: responsiblePerson.gender,
|
||||||
|
namePrefix: responsiblePerson.namePrefix,
|
||||||
|
firstName: responsiblePerson.firstName,
|
||||||
|
lastName: responsiblePerson.lastName,
|
||||||
|
firstNameEN: responsiblePerson.firstNameEN,
|
||||||
|
lastNameEN: responsiblePerson.lastNameEN,
|
||||||
|
code: responsiblePerson.code,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
currStep.responsiblePersonId?.splice(Number(existPersonIndex), 1);
|
currStep.responsiblePersonId?.splice(Number(existPersonIndex), 1);
|
||||||
userInTable.value.splice(Number(existPersonIndex), 1);
|
userInTable.value[stepIndex]?.resposiblePerson.splice(
|
||||||
|
Number(existPersonIndex),
|
||||||
|
1,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
defineEmits<{
|
defineEmits<{
|
||||||
(e: 'moveUp'): void;
|
(e: 'moveUp'): void;
|
||||||
(e: 'moveDown'): void;
|
(e: 'moveDown'): void;
|
||||||
|
(e: 'changeStatus'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
|
@ -90,8 +123,8 @@ watch(
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
role.value = getRole() || [];
|
role.value = getRole() || [];
|
||||||
|
await getUserList();
|
||||||
await userStore.fetchHqOption();
|
await userStore.fetchHqOption();
|
||||||
getUserList();
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -109,14 +142,28 @@ onMounted(async () => {
|
||||||
style="background-color: var(--surface-3)"
|
style="background-color: var(--surface-3)"
|
||||||
/>
|
/>
|
||||||
{{ $t(`general.name`, { msg: $t('flow.title') }) }}
|
{{ $t(`general.name`, { msg: $t('flow.title') }) }}
|
||||||
<span class="row items-center q-ml-auto text-weight-regular text-body2">
|
<span class="row q-ml-lg items-center text-weight-regular text-body2">
|
||||||
|
<ToggleButton
|
||||||
|
class="q-mr-sm"
|
||||||
|
two-way
|
||||||
|
:model-value="flowData.status !== 'INACTIVE'"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
onDrawer
|
||||||
|
? $emit('changeStatus')
|
||||||
|
: flowData.status !== 'INACTIVE'
|
||||||
|
? (flowData.status = 'INACTIVE')
|
||||||
|
: (flowData.status = 'CREATED');
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
{{ $t('status.title') }}
|
{{ $t('status.title') }}
|
||||||
<ToggleButton class="q-ml-md" />
|
|
||||||
</span>
|
</span>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section id="form-flow-template" class="col-12 row">
|
<section id="form-flow-template" class="col-12 row">
|
||||||
<SelectInput
|
<SelectInput
|
||||||
|
:readonly
|
||||||
v-model="registerBranchId"
|
v-model="registerBranchId"
|
||||||
v-if="role.includes('system')"
|
v-if="role.includes('system')"
|
||||||
class="col-12 q-pb-sm"
|
class="col-12 q-pb-sm"
|
||||||
|
|
@ -124,6 +171,8 @@ onMounted(async () => {
|
||||||
:label="$t('branch.form.code')"
|
:label="$t('branch.form.code')"
|
||||||
/>
|
/>
|
||||||
<q-input
|
<q-input
|
||||||
|
:readonly
|
||||||
|
bg-color="transparent"
|
||||||
outlined
|
outlined
|
||||||
dense
|
dense
|
||||||
class="col-12"
|
class="col-12"
|
||||||
|
|
@ -212,6 +261,7 @@ onMounted(async () => {
|
||||||
<q-input
|
<q-input
|
||||||
dense
|
dense
|
||||||
outlined
|
outlined
|
||||||
|
:readonly
|
||||||
:id="`input-flow-step-name-${props.rowIndex}`"
|
:id="`input-flow-step-name-${props.rowIndex}`"
|
||||||
:for="`input-flow-step-name-${props.rowIndex}`"
|
:for="`input-flow-step-name-${props.rowIndex}`"
|
||||||
class="col"
|
class="col"
|
||||||
|
|
@ -224,7 +274,7 @@ onMounted(async () => {
|
||||||
</q-td>
|
</q-td>
|
||||||
|
|
||||||
<q-td>
|
<q-td>
|
||||||
<q-field @click.stop dense outlined>
|
<q-field @click.stop dense outlined :readonly>
|
||||||
<span
|
<span
|
||||||
v-if="props.row.responsiblePersonId.length === 0"
|
v-if="props.row.responsiblePersonId.length === 0"
|
||||||
class="app-text-muted row items-center col"
|
class="app-text-muted row items-center col"
|
||||||
|
|
@ -238,17 +288,21 @@ onMounted(async () => {
|
||||||
<q-img
|
<q-img
|
||||||
class="text-center"
|
class="text-center"
|
||||||
:ratio="1"
|
:ratio="1"
|
||||||
:src="`${baseUrl}/user/${userInTable[props.rowIndex].id}/profile-image/${userInTable[props.rowIndex].selectedImage}`"
|
:src="`${baseUrl}/user/${userInTable[props.rowIndex]?.resposiblePerson[0]?.id}/profile-image/${userInTable[props.rowIndex]?.resposiblePerson[0]?.selectedImage}`"
|
||||||
>
|
>
|
||||||
<template #error>
|
<template #error>
|
||||||
<div
|
<div
|
||||||
class="no-padding full-width full-height flex items-center justify-center"
|
class="no-padding full-width full-height flex items-center justify-center"
|
||||||
:style="`${userInTable[props.rowIndex].gender ? 'background: white' : 'background: linear-gradient(135deg,rgba(43, 137, 223, 1) 0%, rgba(230, 51, 81, 1) 100%);'}`"
|
:style="`${userInTable[props.rowIndex]?.resposiblePerson[0].gender ? 'background: white' : 'background: linear-gradient(135deg,rgba(43, 137, 223, 1) 0%, rgba(230, 51, 81, 1) 100%);'}`"
|
||||||
>
|
>
|
||||||
<q-img
|
<q-img
|
||||||
v-if="userInTable[props.rowIndex].gender"
|
v-if="
|
||||||
|
userInTable[props.rowIndex]?.resposiblePerson[0]
|
||||||
|
?.gender
|
||||||
|
"
|
||||||
:src="
|
:src="
|
||||||
userInTable[props.rowIndex].gender === 'male'
|
userInTable[props.rowIndex]?.resposiblePerson[0]
|
||||||
|
?.gender === 'male'
|
||||||
? '/no-img-man.png'
|
? '/no-img-man.png'
|
||||||
: '/no-img-female.png'
|
: '/no-img-female.png'
|
||||||
"
|
"
|
||||||
|
|
@ -269,19 +323,25 @@ onMounted(async () => {
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
{{
|
{{
|
||||||
`${optionStore.mapOption(userInTable[props.rowIndex].namePrefix || '')} ${
|
`${optionStore.mapOption(userInTable[props.rowIndex]?.resposiblePerson[0]?.namePrefix || '')} ${
|
||||||
$i18n.locale === 'eng'
|
$i18n.locale === 'eng'
|
||||||
? userInTable[props.rowIndex].firstNameEN
|
? userInTable[props.rowIndex]?.resposiblePerson[0]
|
||||||
: userInTable[props.rowIndex].firstName
|
?.firstNameEN
|
||||||
|
: userInTable[props.rowIndex]?.resposiblePerson[0]
|
||||||
|
?.firstName
|
||||||
} ${
|
} ${
|
||||||
$i18n.locale === 'eng'
|
$i18n.locale === 'eng'
|
||||||
? userInTable[props.rowIndex].lastNameEN
|
? userInTable[props.rowIndex]?.resposiblePerson[0]
|
||||||
: userInTable[props.rowIndex].lastName
|
?.lastNameEN
|
||||||
|
: userInTable[props.rowIndex]?.resposiblePerson[0]
|
||||||
|
?.lastName
|
||||||
}`
|
}`
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
<span class="text-caption app-text-muted">
|
<span class="text-caption app-text-muted">
|
||||||
{{ userInTable[props.rowIndex].code }}
|
{{
|
||||||
|
userInTable[props.rowIndex]?.resposiblePerson[0]?.code
|
||||||
|
}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
|
|
@ -292,7 +352,7 @@ onMounted(async () => {
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<q-menu :offset="[0, 4]">
|
<q-menu v-if="!readonly" :offset="[0, 4]">
|
||||||
<q-list>
|
<q-list>
|
||||||
<q-item>
|
<q-item>
|
||||||
<q-input
|
<q-input
|
||||||
|
|
@ -404,6 +464,7 @@ onMounted(async () => {
|
||||||
|
|
||||||
<q-td style="width: 10%">
|
<q-td style="width: 10%">
|
||||||
<DeleteButton
|
<DeleteButton
|
||||||
|
v-if="!readonly"
|
||||||
icon-only
|
icon-only
|
||||||
class="q-ml-auto"
|
class="q-ml-auto"
|
||||||
@click="deleteItem(flowData.step, props.rowIndex)"
|
@click="deleteItem(flowData.step, props.rowIndex)"
|
||||||
|
|
|
||||||
285
src/pages/04_flow-managment/FlowDialog.vue
Normal file
285
src/pages/04_flow-managment/FlowDialog.vue
Normal file
|
|
@ -0,0 +1,285 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { nextTick } from 'vue';
|
||||||
|
import {
|
||||||
|
WorkflowUserInTable,
|
||||||
|
WorkflowTemplatePayload,
|
||||||
|
} from 'src/stores/workflow-template/types';
|
||||||
|
|
||||||
|
import FormFlow from 'src/components/04_flow-management/FormFlow.vue';
|
||||||
|
import DialogForm from 'src/components/DialogForm.vue';
|
||||||
|
import SideMenu from 'src/components/SideMenu.vue';
|
||||||
|
import DrawerInfo from 'src/components/DrawerInfo.vue';
|
||||||
|
import {
|
||||||
|
UndoButton,
|
||||||
|
SaveButton,
|
||||||
|
EditButton,
|
||||||
|
DeleteButton,
|
||||||
|
} from 'src/components/button';
|
||||||
|
|
||||||
|
const model = defineModel<boolean>({ required: true, default: false });
|
||||||
|
const drawerModel = defineModel<boolean>('drawerModel', {
|
||||||
|
required: true,
|
||||||
|
default: false,
|
||||||
|
});
|
||||||
|
const registerBranchId = defineModel('registerBranchId', { default: '' });
|
||||||
|
const flowData = defineModel<WorkflowTemplatePayload>('flowData', {
|
||||||
|
required: true,
|
||||||
|
default: {
|
||||||
|
name: '',
|
||||||
|
step: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const userInTable = defineModel<WorkflowUserInTable[]>('userInTable', {
|
||||||
|
default: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
readonly?: boolean;
|
||||||
|
isEdit?: boolean;
|
||||||
|
}>(),
|
||||||
|
{ readonly: false, isEdit: false },
|
||||||
|
);
|
||||||
|
|
||||||
|
defineEmits<{
|
||||||
|
(e: 'submit'): void;
|
||||||
|
(e: 'close'): void;
|
||||||
|
(e: 'changeStatus'): void;
|
||||||
|
(e: 'drawerUndo'): void;
|
||||||
|
(e: 'drawerEdit'): void;
|
||||||
|
(e: 'drawerDelete'): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
async function addStep() {
|
||||||
|
flowData.value.step.push({
|
||||||
|
responsiblePersonId: [],
|
||||||
|
value: [],
|
||||||
|
name: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
await nextTick();
|
||||||
|
const scrollTarget = document.getElementById(
|
||||||
|
`input-flow-step-name-${flowData.value.step.length - 1}`,
|
||||||
|
);
|
||||||
|
if (scrollTarget)
|
||||||
|
scrollTarget.scrollIntoView({ behavior: 'instant', inline: 'center' });
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<DialogForm
|
||||||
|
:title="$t('flow.title')"
|
||||||
|
v-model:modal="model"
|
||||||
|
:submit="() => $emit('submit')"
|
||||||
|
:close="() => $emit('close')"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="col surface-1 rounded bordered scroll row relative-position"
|
||||||
|
:class="{
|
||||||
|
'q-mx-lg q-my-md': $q.screen.gt.sm,
|
||||||
|
'q-mx-md q-my-sm': !$q.screen.gt.sm,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<section
|
||||||
|
class="col"
|
||||||
|
style="height: 100%; max-height: 100; overflow-y: auto"
|
||||||
|
v-if="$q.screen.gt.sm"
|
||||||
|
>
|
||||||
|
<div class="q-py-md q-pl-md q-pr-sm">
|
||||||
|
<SideMenu
|
||||||
|
:menu="[
|
||||||
|
{
|
||||||
|
name: $t('general.name', { msg: $t('flow.template') }),
|
||||||
|
anchor: 'form-flow-template',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: $t('flow.processStep'),
|
||||||
|
anchor: 'form-flow-step',
|
||||||
|
useBtn: true,
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
background="transparent"
|
||||||
|
:active="{
|
||||||
|
background: 'hsla(var(--blue-6-hsl) / .2)',
|
||||||
|
foreground: 'var(--blue-6)',
|
||||||
|
}"
|
||||||
|
scroll-element="#flow-form"
|
||||||
|
>
|
||||||
|
<template v-slot:btn-form-flow-step>
|
||||||
|
<q-btn
|
||||||
|
dense
|
||||||
|
flat
|
||||||
|
icon="mdi-plus"
|
||||||
|
size="sm"
|
||||||
|
rounded
|
||||||
|
id="btn-add-step"
|
||||||
|
padding="0px 0px"
|
||||||
|
style="color: var(--stone-9)"
|
||||||
|
@click.stop="addStep"
|
||||||
|
:disabled="readonly"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</SideMenu>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section
|
||||||
|
class="col-12 col-md-10"
|
||||||
|
:class="{
|
||||||
|
'q-py-md q-pr-md ': $q.screen.gt.sm,
|
||||||
|
'q-py-md q-px-lg': !$q.screen.gt.sm,
|
||||||
|
}"
|
||||||
|
style="height: 100%; max-height: 100%; overflow-y: auto"
|
||||||
|
id="flow-form"
|
||||||
|
>
|
||||||
|
<FormFlow
|
||||||
|
v-model:flow-data="flowData"
|
||||||
|
v-model:register-branch-id="registerBranchId"
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</DialogForm>
|
||||||
|
|
||||||
|
<DrawerInfo
|
||||||
|
bg-on
|
||||||
|
hide-action
|
||||||
|
:is-edit="isEdit"
|
||||||
|
:title="flowData.name"
|
||||||
|
v-model:drawerOpen="drawerModel"
|
||||||
|
:submit="() => $emit('submit')"
|
||||||
|
:close="() => $emit('close')"
|
||||||
|
>
|
||||||
|
<div class="col column full-height">
|
||||||
|
<div
|
||||||
|
style="flex: 1; width: 100%; overflow-y: auto"
|
||||||
|
id="drawer-user-form"
|
||||||
|
:class="{
|
||||||
|
'q-px-lg q-py-md': $q.screen.gt.sm,
|
||||||
|
'q-px-md q-py-sm': !$q.screen.gt.sm,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="col surface-1 full-height rounded bordered scroll row relative-position"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="rounded row"
|
||||||
|
:class="{
|
||||||
|
'q-py-md q-px-lg': $q.screen.gt.sm,
|
||||||
|
'q-py-sm q-px-lg': !$q.screen.gt.sm,
|
||||||
|
}"
|
||||||
|
style="position: absolute; z-index: 999; top: 0; right: 0"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="flowData.status !== 'INACTIVE'"
|
||||||
|
class="surface-1 row rounded"
|
||||||
|
>
|
||||||
|
<UndoButton
|
||||||
|
v-if="isEdit"
|
||||||
|
id="btn-info-basic-undo"
|
||||||
|
icon-only
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
$emit('drawerUndo');
|
||||||
|
}
|
||||||
|
"
|
||||||
|
type="button"
|
||||||
|
/>
|
||||||
|
<SaveButton
|
||||||
|
v-if="isEdit"
|
||||||
|
id="btn-info-basic-save"
|
||||||
|
icon-only
|
||||||
|
type="submit"
|
||||||
|
/>
|
||||||
|
<EditButton
|
||||||
|
v-if="!isEdit"
|
||||||
|
id="btn-info-basic-edit"
|
||||||
|
icon-only
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
$emit('drawerEdit');
|
||||||
|
// infoDrawerEdit = true;
|
||||||
|
// isImageEdit = true;
|
||||||
|
}
|
||||||
|
"
|
||||||
|
type="button"
|
||||||
|
/>
|
||||||
|
<DeleteButton
|
||||||
|
v-if="!isEdit"
|
||||||
|
id="btn-info-basic-delete"
|
||||||
|
icon-only
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
$emit('drawerDelete');
|
||||||
|
// onDelete(currentUser.id);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
type="button"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<section
|
||||||
|
class="col"
|
||||||
|
style="height: 100%; max-height: 100; overflow-y: auto"
|
||||||
|
v-if="$q.screen.gt.sm"
|
||||||
|
>
|
||||||
|
<div class="q-py-md q-pl-md q-pr-sm">
|
||||||
|
<SideMenu
|
||||||
|
:menu="[
|
||||||
|
{
|
||||||
|
name: $t('general.name', { msg: $t('flow.template') }),
|
||||||
|
anchor: 'form-flow-template',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: $t('flow.processStep'),
|
||||||
|
anchor: 'form-flow-step',
|
||||||
|
useBtn: true,
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
background="transparent"
|
||||||
|
:active="{
|
||||||
|
background: 'hsla(var(--blue-6-hsl) / .2)',
|
||||||
|
foreground: 'var(--blue-6)',
|
||||||
|
}"
|
||||||
|
scroll-element="#flow-form"
|
||||||
|
>
|
||||||
|
<template v-slot:btn-form-flow-step>
|
||||||
|
<q-btn
|
||||||
|
dense
|
||||||
|
flat
|
||||||
|
icon="mdi-plus"
|
||||||
|
size="sm"
|
||||||
|
rounded
|
||||||
|
id="btn-add-step"
|
||||||
|
padding="0px 0px"
|
||||||
|
style="color: var(--stone-9)"
|
||||||
|
@click.stop="addStep"
|
||||||
|
:disabled="readonly"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</SideMenu>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section
|
||||||
|
class="col-12 col-md-10"
|
||||||
|
:class="{
|
||||||
|
'q-py-md q-pr-md ': $q.screen.gt.sm,
|
||||||
|
'q-py-md q-px-lg': !$q.screen.gt.sm,
|
||||||
|
}"
|
||||||
|
style="height: 100%; max-height: 100%; overflow-y: auto"
|
||||||
|
id="flow-form"
|
||||||
|
>
|
||||||
|
<FormFlow
|
||||||
|
:readonly
|
||||||
|
@change-status="$emit('changeStatus')"
|
||||||
|
onDrawer
|
||||||
|
v-model:user-in-table="userInTable"
|
||||||
|
v-model:flow-data="flowData"
|
||||||
|
v-model:register-branch-id="registerBranchId"
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DrawerInfo>
|
||||||
|
</template>
|
||||||
|
<style scoped></style>
|
||||||
|
|
@ -1,22 +1,26 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, reactive, ref } from 'vue';
|
import { onMounted, reactive, ref, watch } from 'vue';
|
||||||
|
import { QTableProps } from 'quasar';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
WorkflowUserInTable,
|
||||||
WorkflowTemplate,
|
WorkflowTemplate,
|
||||||
WorkflowTemplatePayload,
|
WorkflowTemplatePayload,
|
||||||
} from 'src/stores/workflow-template/types';
|
} from 'src/stores/workflow-template/types';
|
||||||
import { useWorkflowTemplate } from 'src/stores/workflow-template';
|
import { useWorkflowTemplate } from 'src/stores/workflow-template';
|
||||||
|
import { dialog } from 'src/stores/utils';
|
||||||
|
|
||||||
import ButtonAddComponent from 'components/ButtonAddCompoent.vue';
|
import ButtonAddComponent from 'components/ButtonAddCompoent.vue';
|
||||||
import StatCardComponent from 'src/components/StatCardComponent.vue';
|
import StatCardComponent from 'src/components/StatCardComponent.vue';
|
||||||
import CreateButton from 'src/components/AddButton.vue';
|
import CreateButton from 'src/components/AddButton.vue';
|
||||||
import PaginationComponent from 'src/components/PaginationComponent.vue';
|
import PaginationComponent from 'src/components/PaginationComponent.vue';
|
||||||
import FlowDialog from '../04_product-service/FlowDialog.vue';
|
import FlowDialog from './FlowDialog.vue';
|
||||||
import NoData from 'src/components/NoData.vue';
|
import NoData from 'src/components/NoData.vue';
|
||||||
import { QTableProps } from 'quasar';
|
import KebabAction from 'src/components/shared/KebabAction.vue';
|
||||||
import { storeToRefs } from 'pinia';
|
|
||||||
import { watch } from 'vue';
|
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
const workflowStore = useWorkflowTemplate();
|
const workflowStore = useWorkflowTemplate();
|
||||||
const {
|
const {
|
||||||
data: workflowData,
|
data: workflowData,
|
||||||
|
|
@ -33,12 +37,17 @@ const pageState = reactive({
|
||||||
total: 0,
|
total: 0,
|
||||||
|
|
||||||
addModal: false,
|
addModal: false,
|
||||||
|
viewDrawer: false,
|
||||||
|
isDrawerEdit: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const currWorkflowData = ref<WorkflowTemplate>();
|
||||||
const formDataWorkflow = ref<WorkflowTemplatePayload>({
|
const formDataWorkflow = ref<WorkflowTemplatePayload>({
|
||||||
|
status: 'CREATED',
|
||||||
name: '',
|
name: '',
|
||||||
step: [],
|
step: [],
|
||||||
});
|
});
|
||||||
|
const userInTable = ref<WorkflowUserInTable[]>([]);
|
||||||
const registeredBranchId = ref('');
|
const registeredBranchId = ref('');
|
||||||
const statusFilter = ref<'all' | 'statusACTIVE' | 'statusINACTIVE'>('all');
|
const statusFilter = ref<'all' | 'statusACTIVE' | 'statusINACTIVE'>('all');
|
||||||
const columns = [
|
const columns = [
|
||||||
|
|
@ -68,23 +77,149 @@ const columns = [
|
||||||
},
|
},
|
||||||
] satisfies QTableProps['columns'];
|
] satisfies QTableProps['columns'];
|
||||||
|
|
||||||
function triggerAddDialog() {
|
function triggerDialog(type: 'add' | 'edit' | 'view') {
|
||||||
|
if (type === 'add') {
|
||||||
pageState.addModal = true;
|
pageState.addModal = true;
|
||||||
|
pageState.isDrawerEdit = true;
|
||||||
|
}
|
||||||
|
if (type === 'view') {
|
||||||
|
pageState.viewDrawer = true;
|
||||||
|
pageState.isDrawerEdit = false;
|
||||||
|
}
|
||||||
|
if (type === 'edit') {
|
||||||
|
pageState.viewDrawer = true;
|
||||||
|
pageState.isDrawerEdit = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function submitAdd() {
|
async function deleteWorkflow(id?: string) {
|
||||||
const res = await workflowStore.creatWorkflowTemplate({
|
const targetId = id || currWorkflowData.value?.id;
|
||||||
|
if (targetId === undefined) return;
|
||||||
|
|
||||||
|
dialog({
|
||||||
|
color: 'negative',
|
||||||
|
icon: 'mdi-trash-can-outline',
|
||||||
|
title: t('dialog.title.confirmDelete'),
|
||||||
|
actionText: t('general.delete'),
|
||||||
|
persistent: true,
|
||||||
|
message: t('dialog.message.confirmDelete'),
|
||||||
|
action: async () => {
|
||||||
|
await workflowStore.deleteWorkflowTemplate(targetId);
|
||||||
|
await fetchWorkflowList();
|
||||||
|
|
||||||
|
resetForm();
|
||||||
|
},
|
||||||
|
cancel: () => {},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function changeStatus(id?: string) {
|
||||||
|
const targetId = id || currWorkflowData.value?.id;
|
||||||
|
if (targetId === undefined) return;
|
||||||
|
|
||||||
|
formDataWorkflow.value.status !== 'INACTIVE' ? 'INACTIVE' : 'ACTIVE';
|
||||||
|
|
||||||
|
const res = await workflowStore.editWorkflowTemplate({
|
||||||
|
id: targetId,
|
||||||
registeredBranchId: registeredBranchId.value,
|
registeredBranchId: registeredBranchId.value,
|
||||||
...formDataWorkflow.value,
|
...formDataWorkflow.value,
|
||||||
});
|
});
|
||||||
if (res) {
|
if (res) {
|
||||||
pageState.addModal = false;
|
console.log(res);
|
||||||
await fetchWorkflowList();
|
// if(currWorkflowData.value) currWorkflowData.value.status
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetForm() {
|
async function triggerChangeStatus(id?: string, status?: string) {
|
||||||
|
const targetId = id || currWorkflowData.value?.id;
|
||||||
|
const targetStatus = status || currWorkflowData.value?.status;
|
||||||
|
if (targetId === undefined || targetStatus === undefined) return;
|
||||||
|
|
||||||
|
return await new Promise((resolve, reject) => {
|
||||||
|
dialog({
|
||||||
|
color: targetStatus !== 'INACTIVE' ? 'warning' : 'info',
|
||||||
|
icon:
|
||||||
|
targetStatus !== 'INACTIVE'
|
||||||
|
? 'mdi-alert'
|
||||||
|
: 'mdi-message-processing-outline',
|
||||||
|
title: t('dialog.title.confirmChangeStatus'),
|
||||||
|
actionText:
|
||||||
|
targetStatus !== 'INACTIVE' ? t('general.close') : t('general.open'),
|
||||||
|
message:
|
||||||
|
targetStatus !== 'INACTIVE'
|
||||||
|
? t('dialog.message.confirmChangeStatusOff')
|
||||||
|
: t('dialog.message.confirmChangeStatusOn'),
|
||||||
|
action: async () => {
|
||||||
|
await changeStatus(targetId).then(resolve).catch(reject);
|
||||||
|
},
|
||||||
|
cancel: () => {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function undo() {
|
||||||
|
if (!currWorkflowData.value) return;
|
||||||
|
assignFormData(currWorkflowData.value);
|
||||||
|
pageState.isDrawerEdit = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function submit() {
|
||||||
|
if (currWorkflowData.value?.id !== undefined) {
|
||||||
|
await workflowStore.editWorkflowTemplate({
|
||||||
|
id: currWorkflowData.value.id,
|
||||||
|
registeredBranchId: registeredBranchId.value,
|
||||||
|
...formDataWorkflow.value,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await workflowStore.creatWorkflowTemplate({
|
||||||
|
registeredBranchId: registeredBranchId.value,
|
||||||
|
...formDataWorkflow.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await fetchWorkflowList();
|
||||||
|
resetForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
function assignFormData(workflowData: WorkflowTemplate) {
|
||||||
|
currWorkflowData.value = workflowData;
|
||||||
formDataWorkflow.value = {
|
formDataWorkflow.value = {
|
||||||
|
status: workflowData.status,
|
||||||
|
name: workflowData.name,
|
||||||
|
step: workflowData.step.map((s, i) => {
|
||||||
|
userInTable.value[i] = { name: s.name, resposiblePerson: [] };
|
||||||
|
s.responsiblePerson.forEach((p) => {
|
||||||
|
userInTable.value[i].resposiblePerson.push({
|
||||||
|
id: p.user.id,
|
||||||
|
selectedImage: p.user.selectedImage,
|
||||||
|
gender: p.user.gender,
|
||||||
|
namePrefix: p.user.namePrefix,
|
||||||
|
firstName: p.user.firstName,
|
||||||
|
lastName: p.user.lastName,
|
||||||
|
firstNameEN: p.user.firstNameEN,
|
||||||
|
lastNameEN: p.user.lastNameEN,
|
||||||
|
code: p.user.code,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
name: s.name,
|
||||||
|
// type: s.type,
|
||||||
|
value: s.value || [],
|
||||||
|
responsiblePersonId: s.responsiblePerson.map((p) => p.userId),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
registeredBranchId.value = workflowData.registeredBranchId;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetForm() {
|
||||||
|
currWorkflowData.value = undefined;
|
||||||
|
pageState.isDrawerEdit = true;
|
||||||
|
pageState.addModal = false;
|
||||||
|
pageState.viewDrawer = false;
|
||||||
|
registeredBranchId.value = '';
|
||||||
|
userInTable.value = [];
|
||||||
|
formDataWorkflow.value = {
|
||||||
|
status: 'CREATED',
|
||||||
name: '',
|
name: '',
|
||||||
step: [],
|
step: [],
|
||||||
};
|
};
|
||||||
|
|
@ -122,7 +257,7 @@ watch(() => pageState.inputSearch, fetchWorkflowList);
|
||||||
<ButtonAddComponent
|
<ButtonAddComponent
|
||||||
style="z-index: 999"
|
style="z-index: 999"
|
||||||
hide-icon
|
hide-icon
|
||||||
@click="triggerAddDialog"
|
@click="triggerDialog('add')"
|
||||||
></ButtonAddComponent>
|
></ButtonAddComponent>
|
||||||
|
|
||||||
<div class="column full-height no-wrap">
|
<div class="column full-height no-wrap">
|
||||||
|
|
@ -234,7 +369,7 @@ watch(() => pageState.inputSearch, fetchWorkflowList);
|
||||||
|
|
||||||
<CreateButton
|
<CreateButton
|
||||||
v-if="!pageState.inputSearch"
|
v-if="!pageState.inputSearch"
|
||||||
@click="triggerAddDialog"
|
@click="triggerDialog('add')"
|
||||||
label="general.add"
|
label="general.add"
|
||||||
:i18n-args="{ text: $t('flow.title') }"
|
:i18n-args="{ text: $t('flow.title') }"
|
||||||
/>
|
/>
|
||||||
|
|
@ -277,14 +412,41 @@ watch(() => pageState.inputSearch, fetchWorkflowList);
|
||||||
<q-td class="text-center">{{ props.rowIndex + 1 }}</q-td>
|
<q-td class="text-center">{{ props.rowIndex + 1 }}</q-td>
|
||||||
<q-td>{{ props.row.name }}</q-td>
|
<q-td>{{ props.row.name }}</q-td>
|
||||||
<q-td class="text-right">{{ props.row.step.length }}</q-td>
|
<q-td class="text-right">{{ props.row.step.length }}</q-td>
|
||||||
<q-td class="text-right">
|
<q-td class="row items-center justify-end">
|
||||||
|
<div class="row">
|
||||||
<q-btn
|
<q-btn
|
||||||
icon="mdi-eye-outline"
|
icon="mdi-eye-outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
dense
|
dense
|
||||||
round
|
round
|
||||||
flat
|
flat
|
||||||
@click.stop="$emit('view', props.rowIndex)"
|
@click.stop="
|
||||||
|
() => {
|
||||||
|
assignFormData(props.row);
|
||||||
|
triggerDialog('view');
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<KebabAction
|
||||||
|
:id-name="props.row.id"
|
||||||
|
:status="props.row.status"
|
||||||
|
@view="
|
||||||
|
() => {
|
||||||
|
assignFormData(props.row);
|
||||||
|
triggerDialog('view');
|
||||||
|
}
|
||||||
|
"
|
||||||
|
@edit="
|
||||||
|
() => {
|
||||||
|
assignFormData(props.row);
|
||||||
|
triggerDialog('edit');
|
||||||
|
}
|
||||||
|
"
|
||||||
|
@delete="() => deleteWorkflow(props.row.id)"
|
||||||
|
@change-status="
|
||||||
|
() => triggerChangeStatus(props.row.id, props.row.status)
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
</q-td>
|
</q-td>
|
||||||
</q-tr>
|
</q-tr>
|
||||||
|
|
@ -349,10 +511,18 @@ watch(() => pageState.inputSearch, fetchWorkflowList);
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<FlowDialog
|
<FlowDialog
|
||||||
|
@change-status="triggerChangeStatus"
|
||||||
|
@drawer-delete="deleteWorkflow"
|
||||||
|
@drawer-edit="pageState.isDrawerEdit = true"
|
||||||
|
@drawer-undo="undo"
|
||||||
@close="resetForm"
|
@close="resetForm"
|
||||||
@submit="submitAdd"
|
@submit="submit"
|
||||||
|
:readonly="!pageState.isDrawerEdit"
|
||||||
|
:isEdit="pageState.isDrawerEdit"
|
||||||
v-model="pageState.addModal"
|
v-model="pageState.addModal"
|
||||||
|
v-model:user-in-table="userInTable"
|
||||||
v-model:flow-data="formDataWorkflow"
|
v-model:flow-data="formDataWorkflow"
|
||||||
|
v-model:drawer-model="pageState.viewDrawer"
|
||||||
v-model:register-branch-id="registeredBranchId"
|
v-model:register-branch-id="registeredBranchId"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,119 +0,0 @@
|
||||||
<script lang="ts" setup>
|
|
||||||
import DialogForm from 'src/components/DialogForm.vue';
|
|
||||||
import SideMenu from 'src/components/SideMenu.vue';
|
|
||||||
import FormFlow from 'src/components/04_flow-management/FormFlow.vue';
|
|
||||||
import { WorkflowTemplatePayload } from 'src/stores/workflow-template/types';
|
|
||||||
import { nextTick } from 'vue';
|
|
||||||
|
|
||||||
const registerBranchId = defineModel('registerBranchId', { default: '' });
|
|
||||||
const model = defineModel<boolean>({ required: true, default: false });
|
|
||||||
const flowData = defineModel<WorkflowTemplatePayload>('flowData', {
|
|
||||||
required: true,
|
|
||||||
default: {
|
|
||||||
name: '',
|
|
||||||
step: [],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
withDefaults(
|
|
||||||
defineProps<{
|
|
||||||
readonly?: boolean;
|
|
||||||
}>(),
|
|
||||||
{ readonly: false },
|
|
||||||
);
|
|
||||||
|
|
||||||
defineEmits<{
|
|
||||||
(e: 'submit'): void;
|
|
||||||
(e: 'close'): void;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
async function addStep() {
|
|
||||||
flowData.value.step.push({
|
|
||||||
responsiblePersonId: [],
|
|
||||||
value: [],
|
|
||||||
name: '',
|
|
||||||
});
|
|
||||||
|
|
||||||
await nextTick();
|
|
||||||
const scrollTarget = document.getElementById(
|
|
||||||
`input-flow-step-name-${flowData.value.step.length - 1}`,
|
|
||||||
);
|
|
||||||
if (scrollTarget)
|
|
||||||
scrollTarget.scrollIntoView({ behavior: 'instant', inline: 'center' });
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<template>
|
|
||||||
<DialogForm
|
|
||||||
:title="$t('flow.title')"
|
|
||||||
v-model:modal="model"
|
|
||||||
:submit="() => $emit('submit')"
|
|
||||||
:close="() => $emit('close')"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="col surface-1 rounded bordered scroll row relative-position"
|
|
||||||
:class="{
|
|
||||||
'q-mx-lg q-my-md': $q.screen.gt.sm,
|
|
||||||
'q-mx-md q-my-sm': !$q.screen.gt.sm,
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<section
|
|
||||||
class="col"
|
|
||||||
style="height: 100%; max-height: 100; overflow-y: auto"
|
|
||||||
v-if="$q.screen.gt.sm"
|
|
||||||
>
|
|
||||||
<div class="q-py-md q-pl-md q-pr-sm">
|
|
||||||
<SideMenu
|
|
||||||
:menu="[
|
|
||||||
{
|
|
||||||
name: $t('general.name', { msg: $t('flow.template') }),
|
|
||||||
anchor: 'form-flow-template',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: $t('flow.processStep'),
|
|
||||||
anchor: 'form-flow-step',
|
|
||||||
useBtn: true,
|
|
||||||
},
|
|
||||||
]"
|
|
||||||
background="transparent"
|
|
||||||
:active="{
|
|
||||||
background: 'hsla(var(--blue-6-hsl) / .2)',
|
|
||||||
foreground: 'var(--blue-6)',
|
|
||||||
}"
|
|
||||||
scroll-element="#flow-form"
|
|
||||||
>
|
|
||||||
<template v-slot:btn-form-flow-step>
|
|
||||||
<q-btn
|
|
||||||
dense
|
|
||||||
flat
|
|
||||||
icon="mdi-plus"
|
|
||||||
size="sm"
|
|
||||||
rounded
|
|
||||||
id="btn-add-step"
|
|
||||||
padding="0px 0px"
|
|
||||||
style="color: var(--stone-9)"
|
|
||||||
@click.stop="addStep"
|
|
||||||
:disabled="readonly"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</SideMenu>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section
|
|
||||||
class="col-12 col-md-10"
|
|
||||||
:class="{
|
|
||||||
'q-py-md q-pr-md ': $q.screen.gt.sm,
|
|
||||||
'q-py-md q-px-lg': !$q.screen.gt.sm,
|
|
||||||
}"
|
|
||||||
style="height: 100%; max-height: 100%; overflow-y: auto"
|
|
||||||
id="flow-form"
|
|
||||||
>
|
|
||||||
<FormFlow
|
|
||||||
v-model:flow-data="flowData"
|
|
||||||
v-model:register-branch-id="registerBranchId"
|
|
||||||
/>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
</DialogForm>
|
|
||||||
</template>
|
|
||||||
<style scoped></style>
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue