jws-frontend/src/pages/09_task-order/SelectReadyRequestWork.vue
Methapon Metanipat 9eff614dbd
feat: task order (#141)
* feat: task order => routes

* feat: Page

* refactor: pagination

* refactor: taskOrder => table, card and constants

* feat: add structure select request list comp

* fix: re-export type

* refactor: edit path route of task order

* feat: trigger task order

* refactor: edit type task statss

* feat: table select request list

* feat: i18n

* refactor: quasar expansion chevron color

* refactor: type

* refactor: state btn status done

* feat: task order => order view layout

* feat: task order => remark expansion

* fix: task order => rename attachment to additional file

* feat: upload file section optional layout

* feat: task order => additional file expansion

* feat: task order => payment expansion

* feat: conditionally add urgent

* feat: send id together with link

* refactor: edit type

* feat: new form.ts

* refactor: edit url

* refactor: edit id trigger

* feat: select institution component

* feat: task order code i18n

* feat: task order => document expansion form

* feat: fallback address on null

* refactor: add type for table

* feat: add filter parameter

* refactor: edit name routes

* refactor: add type of task order payload

* refactor: by value form

* refactor: responsive quotation form info

* refactor: submit form

* refactor: add i18n

* refactor: status canceled

* refactor: handle task status

* refactor: handle mode view

* refactor: addtaskstatus

* refactor: i18n & constants

* refactor: table employee

* refactor: select ready request work

* refactor: handle save form

* refactor: edit layout btn

* feat: undo()

* cleanup delete import

* feat: closetab

* refactor: handle readonly

* fix: body edit

* refactor: handle readonly uploadfile

* feat: import manage attachment

* refactor: quotation/task-order => type

* refactor: select ready request work

* refactor: i18n & constants

* chore: clean duplicate i18n

* refactor: type according to backend relation

* refactor: edit base url

* feat: upload file

* feat: fetch file list

* feat: get url file

* refactor: set default opened

* refactor: type

* feat: removefile

* feat: task order => select product

* feat: add parameter only active branch is selectable

* refactor: add i18n

* feat: set layout

* feat: add info product expansion

* refactor: new info messenger

* refactor: add slot name value

* refactor: add i18n

* refactor: edit type task status

* refactor: use date format

* refactor: value can null

* refactor: add i18n

* cleanup

* feat: productlistinput

* refactor: edit i18n

* refactor: edit redo

* refactor: add slot

* feat: task order => i18n

* refactor: task order => constant

* refactor: taskOrder => status type and index

* feat: taskOrder => ReceiveDialog

* refactor: wording

* refactor: table employee due date

* refactor: receive task i18n

* feat: trigger receive & task stat in receive page

* refactor: receive dialog task in cart  i18n

* fix: remove task-order/receive/add

* feat: receivetabletaskorder

* refactor: fetch task on receive dialog

* feat: add separate api get user task

* refactor: receive fetch (messenger)

* refactor: edit layout table

* refactor: task order i18n & constant

* refactor: task order change tab and stat (messenger and !messenger)

* fix: task order status display & receive badge color (card)

* refactor: trigger receive view

* fix: add receive task condition

* feat: total count

* feat: prepare information

* fix: i18n error task order not found

* refacor: value

* feat: select worker

* refactor: status i18n & constant

* refactor: table employee props (check box, step)

* fix: order => select ready task

* refactor: order => toggle status

* refactor: receive => receive dialog

* feat: featch value

* refactor: task status display components

* refactor: status active can is null

* feat: update status tab

* refactor: data display

* refactor: i18n & fullTaskOrder variable

* refactor: task receive view

* refactor: add type responsible user

* refactor: set group messenger

* cleanup:

* refactor: i18n / clone full task order / service => workflow type

* refactor: receive view

* refactor: show info messenger

* refactor: handle flow step

* refactor: receive view => opacity when pending

* feat: add workflow template name and step name

* feat: display workflow data on table

* feat: add template step identifier

* fix: edit does not change workflow id if changed

* feat: detect if same template and step

* refactor: handle template

* refactor: add slot name product

* refactor: map step in list product

* refactor: bind data messenger list group

* refactor: change endpoint name

* chore: add helper package

* feat: changetaskstatus

* refactor: update type

* refactor: set color btn

* refactor: add step

* refactor: add resposible institution

* feat: disabled

* refactor: map responsible institution

* fix: order view => readonly

* chore: clean

* refactor: edit url api

* refactor: edit name type

* refactor: add slots action

* refactor: add type row

* refactor: add opts of task status

* refactor: add select status

* refactor: handle btn

* refactor: add btn change task status

* refactor: edit i18n redo th

* refactor: sort status opts

* feat: receive & order banner img

* refactor: fetch status after submit

* refactor: handle create only

* refactor: task order status type Accept (messenger only)

* feat: receive messenger profile

* refactor: receive toggle status (display only)

* fix: document expansion readonly

* feat: confirmsendingbtn

* refactor: constant and task order status

* feat: receive task list count

* refactor: post or get

* refactor: define props institution group

* refactor: fetch status after submit

* refactor: handle create

* refactor: handle query

* refactor: update endpoint to support accept multiple order

* refactor: change function name

* feat: receive => functional accept task order

* feat: task status count

* feat: receive stat card count

* refactor: order messenger profile

* refactor: edit value to be task status

* refactor: handle status of type order

* refactor: use componet task status

* refactor: handle show btn saving status

* refactor: order => task status

* refactor: edit selectStatus => changeStatus

* refactor: edit @click btn confirmssending

* refactor: add i18n

* refactor: add function get template data

* refactor: add change status

* refactor: handle type receive

* feat: order => auto change tab by status

* refactor: fetch task after change status

* feat: fail remark dialog

* refactor: display step order (table employee)

* refactor: fail remark dialog

* refactor: order => open ready request dialog map selected

* refactor: task list type & change status param

* refactor: table task order, td background when selected

* refactor: order => change status param

* refactor: order => selectedEmployee variable type

* refactor: task status component => shield btn

* refactor: receive => change status

* refactor: order => step btn waiting

* fix: step btn waiting condition

* refactor: filter selectable task (Failed)

* refactor: find index condition on check

* refactor: no request list available

* refactor: fail btn no-wrap

* refactor: fail dialog readonly

* fix: reset state on open dialog

* fix: wrong title position

* refactor: hide task status drop down icon

* fix: handle check condition

* refactor: add userTask type and status

* feat: submit task order function

* refactor: table employee checkbox display condition

* refactor: main layout

* fix: task order validate i18n

* refactor: table task order add submit status

* refactor: status list

* refactor: info product => user task status

* feat: receive => submit task & step

* refactor: i18n

* feat: complete task oder function

* refactor: task status component no action props

* refactor: info messenger status

* refactor: receive and order view

* refactor: order complete view

* refactor: order => complete color and title

* refactor: calc price on table

* refactor: quotation table i18n + product image

* refactor: remove urgent checkbox

* refactor: task status color

* feat: calc summary price

* fix: data is not available

* feat: add doc view structure

* refactor: format address text

* feat: fetch document data from api

* fix: value is null

* fix: regression cannot edit package

* feat: add document view for task order

* feat: add view document button

* feat: update type add discount

* feat: readonly on cancel

* feat: add discount from relation

* refactor: add taskProduct on submit order

* refactor: order => task product discount

* refactor: order => date, task status count, view example

* refactor: receive date

* refactor: receive task status count

---------

Co-authored-by: puriphatt <puriphat@frappet.com>
Co-authored-by: nwpptrs <jay02499@gmail.com>
Co-authored-by: Thanaphon Frappet <thanaphon@frappet.com>
Co-authored-by: Methapon2001 <61303214+Methapon2001@users.noreply.github.com>
Co-authored-by: oat_dev <nattapon@frappet.com>
2024-12-25 11:59:49 +07:00

302 lines
8 KiB
Vue

<script setup lang="ts">
import { computed, ref, reactive, watch, onMounted } from 'vue';
import {
useRequestList,
RequestWork,
RequestWorkStatus,
} from 'src/stores/request-list';
import DialogHeader from 'src/components/dialog/DialogHeader.vue';
import CancelButton from 'src/components/button/CancelButton.vue';
import SaveButton from 'src/components/button/SaveButton.vue';
import DialogFormContainer from 'src/components/dialog/DialogFormContainer.vue';
import TableEmployee from './TableEmployee.vue';
import FormGroupHead from '../08_request-list/FormGroupHead.vue';
import NoData from 'src/components/NoData.vue';
import { baseUrl } from 'src/stores/utils';
import { Task } from 'src/stores/task-order/types';
const emit = defineEmits<{
(e: 'select', value: RequestWork[]): void;
(e: 'afterSubmit'): void;
}>();
const requestListStore = useRequestList();
const taskList = defineModel<
{
step: number;
requestWorkId: string;
requestWorkStep?: Task;
}[]
>('taskList', {
default: [],
});
const open = defineModel<boolean>('open', { default: false });
const selectedEmployee = ref<
(RequestWork & {
_template?: {
id: string;
templateName: string;
templateStepName: string;
step: number;
} | null;
})[]
>([]);
let data = ref<RequestWork[]>([]);
let group = computed(() =>
data.value.reduce<
{
product: RequestWork['productService']['product'];
list: RequestWork[];
}[]
>((acc, curr) => {
let exist = acc.find(
(item) => curr.productService.productId == item.product.id,
);
if (exist) exist.list.push(curr);
else acc.push({ product: curr.productService.product, list: [curr] });
return acc;
}, []),
);
let state = reactive({
search: '',
});
onMounted(getList);
watch(() => state.search, getList);
async function getList() {
let res = await requestListStore.getRequestWorkList({
page: 1,
pageSize: 99999,
query: state.search,
readyToTask: true,
});
if (!res) return;
data.value = res.result;
}
// function toggle(item: RequestWork) {
// switch (selected(item)) {
// case true:
// return deselect(item);
// case false:
// return select(item);
// }
// }
// function select(item: RequestWork) {
// if (selected(item)) return;
// selectedEmployee.value = selectedEmployee.value
// ? selectedEmployee.value.concat(item)
// : [item];
// }
// function deselect(item: RequestWork) {
// const idx = selectedEmployee.value?.findIndex((v) => v.id === item.id);
// if (idx !== -1) selectedEmployee.value?.splice(idx, 1);
// }
// function selected(item: RequestWork): boolean {
// return !!selectedEmployee.value?.some((v) => v.id === item.id);
// }
//
function getStep(requestWork: RequestWork) {
const target = requestWork.stepStatus.find(
(v) => v.workStatus === RequestWorkStatus.Ready,
);
return target?.step || 0;
}
function getTemplateData(requestWork: RequestWork) {
const target = getStep(requestWork);
if (!target) return null;
const flow = requestWork.productService.service?.workflow;
if (!flow) return null;
const step = flow.step.find((v) => v.order === target);
if (!step) return null;
return {
id: step.id,
step: step.order,
templateName: flow.name,
templateStepName: step.name || '-',
};
}
function submit() {
let selected: {
step: number;
requestWorkId: string;
requestWorkStep?: Task;
}[] = [];
selectedEmployee.value.forEach((v, i) => {
const curr = v.stepStatus.find(
(s) => s.workStatus === RequestWorkStatus.Ready,
);
if (curr) {
const task: Task = {
...curr,
attributes: curr.attributes,
workStatus: RequestWorkStatus.Ready,
taskOrderId: '',
requestWork: selectedEmployee.value[i],
};
selected.push({
step: task.step,
requestWorkId: task.requestWorkId,
requestWorkStep: task,
});
}
});
if (selected) {
taskList.value = selected;
emit('afterSubmit');
}
open.value = false;
}
function close() {
open.value = false;
}
function onDialogOpen() {
selectedEmployee.value = [];
if (taskList.value.length === 0) return;
const matchingItems = group.value
.flatMap((g) => g.list)
.filter((l) =>
l.stepStatus.some((s) =>
taskList.value.some((t) => s.requestWorkId === t.requestWorkId),
),
);
selectedEmployee.value = JSON.parse(JSON.stringify(matchingItems));
}
</script>
<template>
<DialogFormContainer v-model="open" v-on:open="onDialogOpen">
<template #header>
<DialogHeader
:title="$t('general.list', { msg: $t('productService.title') })"
/>
</template>
<section class="col column full-width no-wrap surface-2 scroll">
<template v-if="group.length > 0">
<div
v-for="{ product, list } in group"
:key="product.id"
class="bordered-b"
>
<q-expansion-item
dense
class="overflow-hidden"
switch-toggle-side
style="border-radius: var(--radius-2)"
:default-opened="
list.some((v) => selectedEmployee.some((s) => s.id === v.id))
"
expand-icon="mdi-chevron-down-circle"
header-class="q-py-sm text-medium text-body items-center rounded q-mx-md q-my-sm"
>
<template #header>
<q-avatar class="q-mr-md" size="md">
<q-img
class="text-center"
:ratio="1"
:src="`${baseUrl}/product/${product.id}/image/${product.selectedImage}`"
>
<template #error>
<q-icon
class="full-width full-height"
name="mdi-shopping-outline"
:style="`color: var(--teal-10); background: hsla(var(--teal-${$q.dark.isActive ? '8' : '10'}-hsl)/0.15)`"
/>
</template>
</q-img>
</q-avatar>
<span>
{{ product.name }}
<div class="app-text-muted text-caption">
{{ product.code }}
</div>
</span>
<span class="q-ml-auto">
<div
class="rounded q-px-sm row items-center"
style="background: hsl(var(--text-mute) / 0.15)"
>
<q-icon
name="mdi-account-group-outline"
size="xs"
class="q-pr-sm"
/>
{{ list.length }}
</div>
</span>
</template>
<div>
<FormGroupHead>
{{ $t('quotation.employeeList') }}
</FormGroupHead>
<div class="q-pa-md full-width">
<TableEmployee
checkbox-on
step-on
:rows="
list.map((v) =>
Object.assign(v, { _template: getTemplateData(v) }),
)
"
v-model:selected-employee="selectedEmployee"
/>
</div>
</div>
</q-expansion-item>
</div>
</template>
<div v-else class="row items-center justify-center full-height">
<NoData :text="$t('taskOrder.noRequestAvailable')" />
</div>
</section>
<template #footer>
<CancelButton class="q-ml-auto" outlined @click="close" />
<SaveButton
:label="$t('general.select')"
class="q-ml-sm"
icon="mdi-check"
solid
@click="submit"
/>
</template>
</DialogFormContainer>
</template>
<style scoped>
:deep(i.q-icon.mdi.mdi-chevron-down-circle.q-expansion-item__toggle-icon) {
color: hsl(var(--text-mute));
}
:deep(
i.q-icon.mdi.mdi-chevron-down-circle.q-expansion-item__toggle-icon.q-expansion-item__toggle-icon--rotated
) {
color: var(--brand-1);
}
.active {
background: red;
}
</style>