fix(04): service tree view
This commit is contained in:
parent
55a6e03bcf
commit
76a08ac368
3 changed files with 159 additions and 14 deletions
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue