refactor: workflow dialog & mock data
This commit is contained in:
parent
9e1881cba0
commit
3ddca35589
2 changed files with 322 additions and 16 deletions
250
src/components/04_flow-management/FormFlow.vue
Normal file
250
src/components/04_flow-management/FormFlow.vue
Normal file
|
|
@ -0,0 +1,250 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { QTableProps } from 'quasar';
|
||||||
|
import { moveItemUp, moveItemDown, deleteItem } from 'src/stores/utils';
|
||||||
|
|
||||||
|
import ToggleButton from 'src/components/button/ToggleButton.vue';
|
||||||
|
import { DeleteButton } from '../button';
|
||||||
|
|
||||||
|
type WorkFlow = {
|
||||||
|
name: string;
|
||||||
|
step: FlowStep[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type FlowStep = {
|
||||||
|
responsiblePersonId: string[];
|
||||||
|
value: string[];
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const flowData = defineModel<WorkFlow>('flowData', {
|
||||||
|
required: true,
|
||||||
|
default: {
|
||||||
|
name: '',
|
||||||
|
step: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const responsiblePersonSearch = ref('');
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
name: 'detail',
|
||||||
|
align: 'center',
|
||||||
|
label: 'general.detail',
|
||||||
|
field: 'detail',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'responsiblePerson',
|
||||||
|
align: 'center',
|
||||||
|
label: 'flow.responsiblePerson',
|
||||||
|
field: 'responsiblePerson',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'action',
|
||||||
|
align: 'right',
|
||||||
|
label: '',
|
||||||
|
field: 'action',
|
||||||
|
},
|
||||||
|
] satisfies QTableProps['columns'];
|
||||||
|
|
||||||
|
defineEmits<{
|
||||||
|
(e: 'moveUp'): void;
|
||||||
|
(e: 'moveDown'): void;
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="row col-12">
|
||||||
|
<section
|
||||||
|
class="col-12 q-pb-sm text-weight-bold text-body1 row items-center"
|
||||||
|
>
|
||||||
|
<q-icon
|
||||||
|
flat
|
||||||
|
size="xs"
|
||||||
|
class="q-pa-sm rounded q-mr-xs"
|
||||||
|
color="info"
|
||||||
|
name="mdi-office-building-outline"
|
||||||
|
style="background-color: var(--surface-3)"
|
||||||
|
/>
|
||||||
|
{{ $t(`general.name`, { msg: $t('flow.title') }) }}
|
||||||
|
<span class="row items-center q-ml-auto text-weight-regular">
|
||||||
|
{{ $t('status.title') }}
|
||||||
|
<ToggleButton class="q-ml-md" />
|
||||||
|
</span>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="form-flow-template" class="col-12 row">
|
||||||
|
<q-input
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
class="col"
|
||||||
|
v-model="flowData.name"
|
||||||
|
:label="$t(`general.name`, { msg: $t('flow.step') })"
|
||||||
|
></q-input>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section
|
||||||
|
id="form-flow-step"
|
||||||
|
class="col-12 q-pb-sm q-pt-lg text-weight-bold text-body1 row items-center"
|
||||||
|
>
|
||||||
|
<q-icon
|
||||||
|
flat
|
||||||
|
size="xs"
|
||||||
|
class="q-pa-sm rounded q-mr-xs"
|
||||||
|
color="info"
|
||||||
|
name="mdi-office-building-outline"
|
||||||
|
style="background-color: var(--surface-3)"
|
||||||
|
/>
|
||||||
|
{{ $t(`flow.processStep`) }}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="col-12">
|
||||||
|
<q-table
|
||||||
|
flat
|
||||||
|
bordered
|
||||||
|
hide-pagination
|
||||||
|
class="full-width"
|
||||||
|
:columns
|
||||||
|
:rows="flowData.step"
|
||||||
|
:no-data-label="$t('general.noDataTable')"
|
||||||
|
:pagination="{
|
||||||
|
rowsPerPage: 0,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template #header="{ cols }">
|
||||||
|
<q-tr style="background-color: hsla(var(--info-bg) / 0.07)">
|
||||||
|
<q-th v-for="v in cols" :key="v">
|
||||||
|
{{ v.label && $t(v.label, { msg: $t('flow.step') }) }}
|
||||||
|
</q-th>
|
||||||
|
</q-tr>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #body="props">
|
||||||
|
<q-tr>
|
||||||
|
<q-td style="width: 60%">
|
||||||
|
<section class="row items-center">
|
||||||
|
<q-btn
|
||||||
|
id="btn-up"
|
||||||
|
for="btn-up"
|
||||||
|
icon="mdi-arrow-up"
|
||||||
|
size="sm"
|
||||||
|
dense
|
||||||
|
flat
|
||||||
|
round
|
||||||
|
:disable="props.rowIndex === 0"
|
||||||
|
style="color: hsl(var(--text-mute-2))"
|
||||||
|
@click.stop="moveItemUp(flowData.step, props.rowIndex)"
|
||||||
|
/>
|
||||||
|
<q-btn
|
||||||
|
id="btn-down"
|
||||||
|
for="btn-down"
|
||||||
|
icon="mdi-arrow-down"
|
||||||
|
size="sm"
|
||||||
|
dense
|
||||||
|
flat
|
||||||
|
round
|
||||||
|
class="q-mx-sm"
|
||||||
|
:disable="props.rowIndex === flowData.step.length - 1"
|
||||||
|
style="color: hsl(var(--text-mute-2))"
|
||||||
|
@click.stop="moveItemDown(flowData.step, props.rowIndex)"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<q-avatar
|
||||||
|
size="md"
|
||||||
|
class="q-mx-lg"
|
||||||
|
style="background-color: var(--surface-tab)"
|
||||||
|
>
|
||||||
|
{{ props.rowIndex + 1 }}
|
||||||
|
</q-avatar>
|
||||||
|
|
||||||
|
<q-input
|
||||||
|
dense
|
||||||
|
outlined
|
||||||
|
:id="`input-flow-step-name-${props.rowIndex}`"
|
||||||
|
:for="`input-flow-step-name-${props.rowIndex}`"
|
||||||
|
class="col"
|
||||||
|
:placeholder="$t('general.no', { msg: $t('flow.step') })"
|
||||||
|
v-model="props.row.name"
|
||||||
|
></q-input>
|
||||||
|
</section>
|
||||||
|
</q-td>
|
||||||
|
|
||||||
|
<q-td>
|
||||||
|
<q-field @click.stop dense outlined>
|
||||||
|
<span class="app-text-muted">
|
||||||
|
{{ $t('general.no', { msg: $t('flow.responsiblePerson') }) }}
|
||||||
|
</span>
|
||||||
|
<q-menu style="width: 18rem" :offset="[0, 4]">
|
||||||
|
<q-list>
|
||||||
|
<q-item>
|
||||||
|
<q-input
|
||||||
|
for="input-search"
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
:label="$t('general.search')"
|
||||||
|
class="col responsible-search"
|
||||||
|
:bg-color="$q.dark.isActive ? 'dark' : 'white'"
|
||||||
|
v-model="responsiblePersonSearch"
|
||||||
|
debounce="200"
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<q-icon name="mdi-magnify" />
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
</q-item>
|
||||||
|
<span class="text-caption app-text-muted-2 q-px-md">
|
||||||
|
ผู้คน
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<q-item clickable class="column">
|
||||||
|
<div class="row items-center">
|
||||||
|
<q-checkbox :model-value="false" size="xs"></q-checkbox>
|
||||||
|
<q-avatar class="q-ml-sm" size="md">
|
||||||
|
<q-img :src="`/images/employee-avatar.png`" />
|
||||||
|
</q-avatar>
|
||||||
|
<div class="column q-pl-md">
|
||||||
|
<span>นาย กอไก่ ขอไข่</span>
|
||||||
|
<span class="text-caption app-text-muted">10002</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</q-item>
|
||||||
|
|
||||||
|
<span class="text-caption app-text-muted-2 q-px-md">
|
||||||
|
กลุ่ม
|
||||||
|
</span>
|
||||||
|
<q-item clickable class="column">
|
||||||
|
<div class="row items-center">
|
||||||
|
<q-checkbox :model-value="false" size="xs"></q-checkbox>
|
||||||
|
<q-avatar class="q-ml-sm" size="md">
|
||||||
|
<q-img :src="`/images/employee-avatar.png`" />
|
||||||
|
</q-avatar>
|
||||||
|
<div class="column q-pl-md">
|
||||||
|
<span>กลุ่มคาโมมายด์</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-menu>
|
||||||
|
</q-field>
|
||||||
|
</q-td>
|
||||||
|
|
||||||
|
<q-td style="width: 10%">
|
||||||
|
<DeleteButton
|
||||||
|
icon-only
|
||||||
|
class="q-ml-auto"
|
||||||
|
@click="deleteItem(flowData.step, props.rowIndex)"
|
||||||
|
/>
|
||||||
|
</q-td>
|
||||||
|
</q-tr>
|
||||||
|
</template>
|
||||||
|
</q-table>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
:deep(.responsible-search .q-field__control) {
|
||||||
|
height: 36px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,8 +1,56 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import DialogForm from 'src/components/DialogForm.vue';
|
import DialogForm from 'src/components/DialogForm.vue';
|
||||||
import SideMenu from 'src/components/SideMenu.vue';
|
import SideMenu from 'src/components/SideMenu.vue';
|
||||||
|
import FormFlow from 'src/components/04_flow-management/FormFlow.vue';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
type WorkFlow = {
|
||||||
|
name: string;
|
||||||
|
step: FlowStep[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type FlowStep = {
|
||||||
|
responsiblePersonId: string[];
|
||||||
|
value: string[];
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
|
||||||
const model = defineModel<boolean>({ required: true, default: false });
|
const model = defineModel<boolean>({ required: true, default: false });
|
||||||
|
const flowData = defineModel<WorkFlow>('flowStep', {
|
||||||
|
required: true,
|
||||||
|
default: {
|
||||||
|
name: '',
|
||||||
|
step: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const mockFlowData = ref<WorkFlow>({
|
||||||
|
name: '',
|
||||||
|
step: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
readonly?: boolean;
|
||||||
|
}>(),
|
||||||
|
{ readonly: false },
|
||||||
|
);
|
||||||
|
|
||||||
|
function addStep() {
|
||||||
|
mockFlowData.value.step.push({
|
||||||
|
responsiblePersonId: [''],
|
||||||
|
value: [''],
|
||||||
|
name: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
const scrollTarget = document.getElementById(
|
||||||
|
`input-flow-step-name-${mockFlowData.value.step.length - 1}`,
|
||||||
|
);
|
||||||
|
console.log(`input-flow-step-name-${mockFlowData.value.step.length - 1}`);
|
||||||
|
console.log(scrollTarget);
|
||||||
|
if (scrollTarget)
|
||||||
|
scrollTarget.scrollIntoView({ behavior: 'instant', inline: 'center' });
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<DialogForm :title="$t('flow.title')" v-model:modal="model">
|
<DialogForm :title="$t('flow.title')" v-model:modal="model">
|
||||||
|
|
@ -23,7 +71,12 @@ const model = defineModel<boolean>({ required: true, default: false });
|
||||||
:menu="[
|
:menu="[
|
||||||
{
|
{
|
||||||
name: $t('general.name', { msg: $t('flow.template') }),
|
name: $t('general.name', { msg: $t('flow.template') }),
|
||||||
anchor: 'form-group',
|
anchor: 'form-flow-template',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: $t('flow.processStep'),
|
||||||
|
anchor: 'form-flow-step',
|
||||||
|
useBtn: true,
|
||||||
},
|
},
|
||||||
]"
|
]"
|
||||||
background="transparent"
|
background="transparent"
|
||||||
|
|
@ -31,8 +84,23 @@ const model = defineModel<boolean>({ required: true, default: false });
|
||||||
background: 'hsla(var(--blue-6-hsl) / .2)',
|
background: 'hsla(var(--blue-6-hsl) / .2)',
|
||||||
foreground: 'var(--blue-6)',
|
foreground: 'var(--blue-6)',
|
||||||
}"
|
}"
|
||||||
scroll-element="#group-form"
|
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>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
@ -45,19 +113,7 @@ const model = defineModel<boolean>({ required: true, default: false });
|
||||||
}"
|
}"
|
||||||
style="height: 100%; max-height: 100%; overflow-y: auto"
|
style="height: 100%; max-height: 100%; overflow-y: auto"
|
||||||
>
|
>
|
||||||
<div class="row col-12">
|
<FormFlow id="#flow-form" v-model:flow-data="mockFlowData" />
|
||||||
<div class="col-12 q-pb-sm text-weight-bold text-body1">
|
|
||||||
<q-icon
|
|
||||||
flat
|
|
||||||
size="xs"
|
|
||||||
class="q-pa-sm rounded q-mr-xs"
|
|
||||||
color="info"
|
|
||||||
name="mdi-office-building-outline"
|
|
||||||
style="background-color: var(--surface-3)"
|
|
||||||
/>
|
|
||||||
{{ $t(`general.name`, { msg: $t('') }) }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</DialogForm>
|
</DialogForm>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue