refactor: component dialog, select input, select zone, tree view
This commit is contained in:
parent
5d292c5a5c
commit
51f41abc4b
4 changed files with 109 additions and 23 deletions
|
|
@ -45,7 +45,7 @@ const currentTab = defineModel<string>('currentTab');
|
|||
:model-value="modal"
|
||||
@update:model-value="(v) => (modal = beforeClose ? beforeClose() : v)"
|
||||
@before-show="show"
|
||||
@hide="hideCloseEvent !== undefined && hideCloseEvent ? '' : close"
|
||||
@hide="hideCloseEvent !== undefined && hideCloseEvent ? '' : close?.()"
|
||||
>
|
||||
<div
|
||||
class="surface-1"
|
||||
|
|
|
|||
|
|
@ -18,14 +18,23 @@ const props = withDefaults(
|
|||
option: Record<string, unknown>[];
|
||||
optionLabel?: string;
|
||||
optionValue?: string;
|
||||
placeholder?: string;
|
||||
|
||||
hideSelected?: boolean;
|
||||
readonly?: boolean;
|
||||
clearable?: boolean;
|
||||
incremental?: boolean;
|
||||
fillInput?: boolean;
|
||||
|
||||
rules?: ((value: string) => string | true)[];
|
||||
}>(),
|
||||
{ option: () => [], optionLabel: 'label', optionValue: 'value' },
|
||||
{
|
||||
option: () => [],
|
||||
optionLabel: 'label',
|
||||
optionValue: 'value',
|
||||
hideSelected: true,
|
||||
fillInput: true,
|
||||
},
|
||||
);
|
||||
|
||||
defineEmits<{
|
||||
|
|
@ -53,14 +62,15 @@ watch(
|
|||
</script>
|
||||
<template>
|
||||
<q-select
|
||||
:placeholder="placeholder"
|
||||
outlined
|
||||
:clearable
|
||||
use-input
|
||||
emit-value
|
||||
map-options
|
||||
hide-selected
|
||||
:hideSelected
|
||||
hide-bottom-space
|
||||
:fill-input="!!model"
|
||||
:fill-input="fillInput && !!model"
|
||||
:hide-dropdown-icon="readonly"
|
||||
input-debounce="0"
|
||||
:option-value="optionValue"
|
||||
|
|
@ -70,7 +80,7 @@ watch(
|
|||
:readonly
|
||||
:label="label"
|
||||
:options="incremental ? option : options"
|
||||
:for="`select-${id}`"
|
||||
:for="`${id}`"
|
||||
@filter="
|
||||
(val, update) => {
|
||||
incremental ? $emit('filter', val, update) : defaultFilter(val, update);
|
||||
|
|
@ -88,8 +98,8 @@ watch(
|
|||
</q-item>
|
||||
</template>
|
||||
|
||||
<template v-if="$slots.name" v-slot:selected-item="scope">
|
||||
<slot name="selected-item" :scope="scope"></slot>
|
||||
<template v-if="$slots.selectedItem" v-slot:selected-item="scope">
|
||||
<slot name="selectedItem" :scope="scope"></slot>
|
||||
</template>
|
||||
|
||||
<template v-if="$slots.option" v-slot:option="scope">
|
||||
|
|
|
|||
|
|
@ -7,23 +7,50 @@ const props = withDefaults(
|
|||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
items: any;
|
||||
color?: string;
|
||||
borderSearchSection?: boolean;
|
||||
itemClass?: string;
|
||||
noPadding?: boolean;
|
||||
noItemsIcon?: string;
|
||||
noItemsLabel?: string;
|
||||
}>(),
|
||||
{
|
||||
items: () => [],
|
||||
color: 'var(--brand-1)',
|
||||
noItemsIcon: 'mdi-close',
|
||||
itemClass: 'col-md-2 col-sm-6 col-12',
|
||||
},
|
||||
);
|
||||
|
||||
function select(item: unknown) {
|
||||
if (selectedItem.value.includes(item)) {
|
||||
let index = selectedItem.value.indexOf(item);
|
||||
selectedItem.value.splice(index, 1);
|
||||
} else selectedItem.value.push(item);
|
||||
defineExpose({ select });
|
||||
|
||||
function select(item?: unknown, all?: boolean) {
|
||||
if (all) {
|
||||
if (props.items.every((item) => selectedItem.value.includes(item))) {
|
||||
selectedItem.value = selectedItem.value.filter(
|
||||
(item) => !props.items.includes(item),
|
||||
);
|
||||
} else {
|
||||
props.items.forEach((i) => {
|
||||
const productExists = selectedItem.value.some((item) => item === i);
|
||||
if (!productExists) {
|
||||
selectedItem.value.push(i);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (selectedItem.value.includes(item)) {
|
||||
const index = selectedItem.value.indexOf(item);
|
||||
selectedItem.value.splice(index, 1);
|
||||
} else selectedItem.value.push(item);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<section class="full-width column q-pa-md">
|
||||
<header class="row items-center no-wrap q-mb-md">
|
||||
<section class="full-width column">
|
||||
<header
|
||||
class="row items-center no-wrap q-px-md q-py-sm"
|
||||
:class="{ 'bordered surface-3 ': borderSearchSection }"
|
||||
>
|
||||
<div class="col"><slot name="top"></slot></div>
|
||||
<q-input
|
||||
for="input-search"
|
||||
|
|
@ -40,14 +67,11 @@ function select(item: unknown) {
|
|||
</template>
|
||||
</q-input>
|
||||
</header>
|
||||
<slot name="tab"></slot>
|
||||
|
||||
<section class="col">
|
||||
<div class="row q-col-gutter-md">
|
||||
<div
|
||||
v-for="(item, i) in items"
|
||||
:key="i"
|
||||
class="col-md-2 col-sm-6 col-12"
|
||||
>
|
||||
<section class="col q-ma-md">
|
||||
<div v-if="items.length > 0" class="row q-col-gutter-md">
|
||||
<div v-for="(item, i) in items" :key="i" :class="`${itemClass}`">
|
||||
<div
|
||||
class="rounded cursor-pointer relative-position"
|
||||
:style="`border: 1px solid ${selectedItem.includes(item) ? color : 'transparent'}`"
|
||||
|
|
@ -64,6 +88,14 @@ function select(item: unknown) {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="flex justify-center full-height">
|
||||
<span class="col column items-center justify-center app-text-muted">
|
||||
<q-avatar style="background: var(--surface-0)" class="q-mb-md">
|
||||
<q-icon :name="noItemsIcon" />
|
||||
</q-avatar>
|
||||
{{ noItemsLabel || $t('general.noData') }}
|
||||
</span>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import { Icon } from '@iconify/vue';
|
||||
import { computed } from 'vue';
|
||||
import DeleteButton from '../button/DeleteButton.vue';
|
||||
|
||||
type Node = {
|
||||
[key: string]: any;
|
||||
|
|
@ -17,10 +18,14 @@ type Props = {
|
|||
level?: number;
|
||||
keyTitle?: string;
|
||||
keySubtitle?: string;
|
||||
expandable?: boolean;
|
||||
hideCheckBox?: boolean;
|
||||
iconSize?: string;
|
||||
|
||||
hideCheckBox?: boolean;
|
||||
expandable?: boolean;
|
||||
selectable?: boolean;
|
||||
deleteable?: boolean;
|
||||
movable?: boolean;
|
||||
|
||||
selectedNode?: Node[];
|
||||
ancestorNode?: Node[];
|
||||
decoration?: {
|
||||
|
|
@ -38,6 +43,9 @@ const emits = defineEmits<{
|
|||
(e: 'checked'): void;
|
||||
(e: 'select', node: Node, ancestor?: Node[]): void;
|
||||
(e: 'open', node: Node, ancestor?: Node[]): void;
|
||||
(e: 'delete', node: Node): void;
|
||||
(e: 'moveUp', node: Node): void;
|
||||
(e: 'moveDown', node: Node): void;
|
||||
}>();
|
||||
|
||||
const dec = props.decoration?.find((v) => v.level === (props.level || 0));
|
||||
|
|
@ -90,6 +98,34 @@ function toggleExpand(node: Node, ancestor?: []) {
|
|||
() => (selectable ? $emit('select', node) : toggleExpand(node))
|
||||
"
|
||||
>
|
||||
<div v-if="!level" style="margin-right: var(--size-1)">
|
||||
<q-btn
|
||||
id="btn-up"
|
||||
for="btn-up"
|
||||
icon="mdi-arrow-up"
|
||||
size="sm"
|
||||
dense
|
||||
flat
|
||||
round
|
||||
:disable="i === 0"
|
||||
style="color: hsl(var(--text-mute-2))"
|
||||
@click.stop="$emit('moveUp', node)"
|
||||
/>
|
||||
<q-btn
|
||||
id="btn-down"
|
||||
for="btn-down"
|
||||
icon="mdi-arrow-down"
|
||||
size="sm"
|
||||
dense
|
||||
flat
|
||||
round
|
||||
class="q-mx-sm"
|
||||
:disable="i === nodes.length - 1"
|
||||
style="color: hsl(var(--text-mute-2))"
|
||||
@click.stop="$emit('moveDown', node)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style="width: var(--size-6); margin-right: var(--size-1)">
|
||||
<div
|
||||
v-if="level !== maxLevel"
|
||||
|
|
@ -154,6 +190,13 @@ function toggleExpand(node: Node, ancestor?: []) {
|
|||
{{ node[keySubtitle || 'subtitle'] || 'No Subtitle' }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<DeleteButton
|
||||
v-if="!level"
|
||||
class="q-ml-auto"
|
||||
icon-only
|
||||
@click.stop="$emit('delete', node)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -208,6 +251,7 @@ function toggleExpand(node: Node, ancestor?: []) {
|
|||
/>
|
||||
</div>
|
||||
</transition>
|
||||
<q-separator v-if="!level && i !== nodes.length - 1" class="q-mt-sm" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue