fix(04): service tree view

This commit is contained in:
puriphatt 2024-09-25 17:47:01 +07:00
parent 55a6e03bcf
commit 76a08ac368
3 changed files with 159 additions and 14 deletions

View file

@ -5,17 +5,21 @@ import { moveItemUp, moveItemDown, deleteItem, dialog } from 'stores/utils';
import NoData from 'components/NoData.vue';
import WorkManagementComponent from './WorkManagementComponent.vue';
import AddButton from '../button/AddButton.vue';
import { WorkItems } from 'stores/product-service/types';
import { ServiceCreate, WorkItems } from 'stores/product-service/types';
import TreeView from '../shared/TreeView.vue';
import { ref } from 'vue';
const { t } = useI18n();
const workItems = defineModel<WorkItems[]>('workItems', { default: [] });
defineProps<{
const props = defineProps<{
service?: ServiceCreate;
dense?: boolean;
outlined?: boolean;
readonly?: boolean;
separator?: boolean;
treeView?: boolean;
priceDisplay?: {
price: boolean;
@ -30,6 +34,22 @@ defineEmits<{
(e: 'workProperties', index: number): void;
}>();
const nodes = ref([
{
title: props.service?.name,
subtitle: props.service?.code,
selected: false,
children: workItems.value.map((v) => ({
title: v.name,
subtitle: ' ',
children: v.product.map((x) => ({
title: x.name,
subtitle: x.code,
})),
})),
},
]);
function addWork() {
workItems.value.push({
id: '',
@ -75,7 +95,7 @@ function confirmDelete(items: unknown[], index: number) {
/>
</div>
<div v-if="workItems.length > 0" class="q-gutter-y-md row">
<div v-if="workItems.length > 0 && !treeView" class="q-gutter-y-md row">
<WorkManagementComponent
class="col-12"
v-for="(work, index) in workItems"
@ -101,6 +121,39 @@ function confirmDelete(items: unknown[], index: number) {
<div class="col-12" style="height: 12px"></div>
</div>
<div
v-else-if="workItems.length > 0 && treeView"
class="row rounded bordered surface-2 col q-pa-md"
>
<TreeView
expandable
hideCheckBox
icon-size="2.5rem"
class="full-width"
v-model:nodes="nodes"
:decoration="[
{
level: 0,
icon: 'mdi-server-outline',
bg: 'hsla(var(--orange-5-hsl)/0.1)',
fg: 'var(--orange-5)',
},
{
level: 1,
icon: 'mdi-briefcase-outline',
bg: 'hsla(var(--violet-11-hsl)/0.1)',
fg: 'var(--violet-11)',
},
{
level: 2,
icon: 'mdi-shopping-outline',
bg: 'hsla(var(--teal-10-hsl)/0.1)',
fg: 'var(--teal-10)',
},
]"
/>
</div>
<div
v-else
class="col row rounded bordered surface-2 justify-center items-center"

View file

@ -1,5 +1,6 @@
<script setup lang="ts">
import { Icon } from '@iconify/vue';
import { computed } from 'vue';
type Node = {
[key: string]: any;
@ -13,6 +14,8 @@ type Props = {
keyTitle?: string;
keySubtitle?: string;
expandable?: boolean;
hideCheckBox?: boolean;
iconSize?: string;
decoration?: {
level?: number;
bg?: string;
@ -27,6 +30,11 @@ const nodes = defineModel<Node[]>('nodes', { required: true });
const emits = defineEmits<{ (e: 'checked'): void }>();
const dec = props.decoration?.find((v) => v.level === (props.level || 0));
const maxLevel = computed(() =>
props.decoration?.reduce((max, v) => {
return v.level && v.level > max ? v.level : max;
}, 0),
);
function recursiveDeselect(node: Node) {
if (node.children) {
@ -48,8 +56,22 @@ function toggleExpand(node: Node) {
</script>
<template>
<div class="tree-container">
<div v-for="(node, i) in nodes" class="tree-item" :key="i">
<div
class="tree-container"
:class="{
'q-pl-lg': level && level > 0,
'last-children': level && level === maxLevel,
}"
>
<div
v-for="(node, i) in nodes"
class="tree-item"
:class="{
'q-pt-sm': level !== 0 && level !== maxLevel && i !== 0,
'q-pt-xs': level === maxLevel && i === 0,
}"
:key="i"
>
<slot
v-if="$slots['item']"
name="item"
@ -61,7 +83,23 @@ function toggleExpand(node: Node) {
class="item__content row items-center no-wrap"
@click="toggleExpand(node)"
>
<label class="flex items-center item__checkbox" @click.stop>
<div
v-if="level !== maxLevel"
class="q-mr-md"
style="color: var(--stone-4)"
>
<q-icon
name="mdi-chevron-down-circle"
size="sm"
:style="`transform: rotate(${node.opened ? '180deg' : '0'})`"
/>
</div>
<label
v-if="!hideCheckBox"
class="flex items-center item__checkbox"
@click.stop
>
<input
type="checkbox"
v-model="node.selected"
@ -71,9 +109,17 @@ function toggleExpand(node: Node) {
<div
class="item__icon flex items-center justify-center"
:style="`background: ${dec?.bg}; color: ${dec?.fg}`"
:style="`background: ${dec?.bg}; color: ${dec?.fg}; height: ${iconSize}; width: ${iconSize}`"
>
<Icon v-if="dec && dec.icon" :icon="dec.icon" />
<div
:style="`height: calc(${iconSize} - 40%); width: calc(${iconSize} - 40%)`"
>
<Icon
v-if="dec && dec.icon"
:icon="dec.icon"
class="full-width full-height"
/>
</div>
</div>
<div class="column">
@ -86,14 +132,13 @@ function toggleExpand(node: Node) {
</div>
</div>
</template>
<q-separator v-if="!level"></q-separator>
<q-separator v-if="!level" spaced="md"></q-separator>
<transition name="slide">
<div
class="q-pl-lg q-pt-sm"
v-if="node.opened && node.children && node.children.length > 0"
>
<div v-if="node.opened && node.children && node.children.length > 0">
<TreeView
:iconSize
:hideCheckBox
class="item__children"
v-if="node.children"
v-model:nodes="node.children"
@ -153,6 +198,10 @@ function toggleExpand(node: Node) {
}
}
.last-children {
margin-left: 50px;
}
.slide-enter-active {
transition: all 0.1s ease-out;
}

View file

@ -209,6 +209,8 @@ const dialogService = ref(false);
const dialogProductEdit = ref(false);
const dialogServiceEdit = ref(false);
const serviceTreeView = ref(false);
const statusToggle = ref(false);
const profileSubmit = ref(false);
const infoProductEdit = ref(false);
@ -4019,10 +4021,49 @@ watch(
id="group-form"
>
<div
class="surface-1 rounded q-my-md q-mx-lg row"
class="surface-1 rounded q-my-md q-mx-lg row items-center"
style="position: absolute; z-index: 999; top: 0; right: 0"
v-if="actionDisplay && !currentNoAction"
>
<div class="bordered rounded q-mr-md" v-if="serviceTab === 2">
<q-btn
icon="mdi-file-tree-outline"
flat
square
:class="{
' surface-3': serviceTreeView,
'app-text-muted-2': serviceTreeView,
'app-text-muted': !serviceTreeView,
}"
size="sm"
padding="6px 10px"
title="Tree"
style="
border-top-left-radius: var(--radius-2);
border-bottom-left-radius: var(--radius-2);
"
@click="serviceTreeView = true"
/>
<q-btn
icon="mdi-view-list-outline"
flat
square
:class="{
' surface-3': !serviceTreeView,
'app-text-muted-2': !serviceTreeView,
'app-text-muted': serviceTreeView,
}"
size="sm"
padding="6px 10px"
title="List"
style="
border-top-right-radius: var(--radius-2);
border-bottom-right-radius: var(--radius-2);
"
@click="serviceTreeView = false"
/>
</div>
<UndoButton
v-if="infoServiceEdit"
id="btn-info-basic-undo"
@ -4104,6 +4145,8 @@ watch(
<FormServiceWork
v-if="serviceTab === 2"
:service="formDataProductService"
:tree-view="serviceTreeView"
:readonly="!infoServiceEdit"
v-model:work-items="workItems"
dense