refactor: workflow dialog & mock data

This commit is contained in:
puriphatt 2024-10-24 17:33:33 +07:00
parent 9e1881cba0
commit 3ddca35589
2 changed files with 322 additions and 16 deletions

View 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>

View file

@ -1,8 +1,56 @@
<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 { 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 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>
<template>
<DialogForm :title="$t('flow.title')" v-model:modal="model">
@ -23,7 +71,12 @@ const model = defineModel<boolean>({ required: true, default: false });
:menu="[
{
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"
@ -31,8 +84,23 @@ const model = defineModel<boolean>({ required: true, default: false });
background: 'hsla(var(--blue-6-hsl) / .2)',
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>
</section>
@ -45,19 +113,7 @@ const model = defineModel<boolean>({ required: true, default: false });
}"
style="height: 100%; max-height: 100%; overflow-y: auto"
>
<div class="row col-12">
<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>
<FormFlow id="#flow-form" v-model:flow-data="mockFlowData" />
</section>
</div>
</DialogForm>