feat/fix: new component(select input/zone, quoCard)

This commit is contained in:
puriphatt 2024-09-23 15:03:54 +07:00
parent 08068137af
commit c04039d8a7
7 changed files with 332 additions and 37 deletions

View file

@ -49,7 +49,7 @@ defineEmits<{
}"
@click="$emit('enterCard', 'INFO')"
>
<div class="column items-center">
<div class="column items-center" :class="{ 'q-pt-sm': noAction }">
<!-- kebab menu -->
<div class="full-width flex no-wrap" v-if="!noAction">
<div style="margin-right: auto">

View file

@ -1,45 +1,82 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { onMounted, ref, watch } from 'vue';
import { selectFilterOptionRefMod } from 'src/stores/utils';
import { QSelect } from 'quasar';
const model = defineModel<string | Date | null>();
const option = defineModel<[]>('option', { default: [] });
const props = defineProps<{
id?: string;
readonly?: boolean;
clearable?: boolean;
label?: string;
rules?: ((value: string) => string | true)[];
disabledDates?: string[] | Date[] | ((date: Date) => boolean);
}>();
const options = ref<Record<string, unknown>[]>([]);
let typeBusinessFilter = selectFilterOptionRefMod(option, options, 'label');
let defaultFilter: (
value: string,
update: (callbackFn: () => void, afterFn?: (ref: QSelect) => void) => void,
) => void;
const props = withDefaults(
defineProps<{
id?: string;
label?: string;
option: Record<string, unknown>[];
optionLabel?: string;
optionValue?: string;
readonly?: boolean;
clearable?: boolean;
incremental?: boolean;
rules?: ((value: string) => string | true)[];
}>(),
{ option: () => [], optionLabel: 'label', optionValue: 'value' },
);
defineEmits<{
(e: 'filter', val: string, update: void): void;
}>();
onMounted(() => {
defaultFilter = selectFilterOptionRefMod(
ref(props.option),
options,
props.optionLabel,
);
});
watch(
() => props.option,
() => {
defaultFilter = selectFilterOptionRefMod(
ref(props.option),
options,
props.optionLabel,
);
},
);
</script>
<template>
<q-select
outlined
clearable
:clearable
use-input
fill-input
emit-value
map-options
hide-selected
hide-bottom-space
:fill-input="!!model"
:hide-dropdown-icon="readonly"
input-debounce="0"
option-value="value"
option-label="label"
:option-value="optionValue"
:option-label="optionLabel"
v-model="model"
class="col-md-6 col-12"
dense
:readonly="readonly"
:readonly
:label="label"
:options="options"
:for="`${prefixId}-select-business-type`"
@filter="typeBusinessFilter"
:rules="[(val: string) => !!val || $t('form.error.required')]"
:options="incremental ? option : options"
:for="`select-${id}`"
@filter="
(val, update) => {
incremental ? $emit('filter', val, update) : defaultFilter(val, update);
}
"
:rules
>
<template v-slot:no-option>
<q-item>
@ -48,5 +85,13 @@ let typeBusinessFilter = selectFilterOptionRefMod(option, options, 'label');
</q-item-section>
</q-item>
</template>
<template v-if="$slots.name" v-slot:selected-item="scope">
<slot name="selected-item" :scope="scope"></slot>
</template>
<template v-if="$slots.option" v-slot:option="scope">
<slot name="option" :scope="scope"></slot>
</template>
</q-select>
</template>

View file

@ -0,0 +1,76 @@
<script setup lang="ts">
const search = defineModel<string>('search');
const selectedItem = defineModel<unknown[]>('selectedItem', { default: [] });
const props = withDefaults(
defineProps<{
items: unknown[];
color?: string;
}>(),
{
items: () => [],
color: 'var(--brand-1)',
},
);
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);
}
</script>
<template>
<section class="full-width column q-pa-md">
<header class="row items-center no-wrap q-mb-md">
<div class="col"><slot name="top"></slot></div>
<q-input
for="input-search"
outlined
dense
:label="$t('general.search')"
class="q-ml-auto"
:bg-color="$q.dark.isActive ? 'dark' : 'white'"
v-model="search"
debounce="200"
>
<template #prepend>
<q-icon name="mdi-magnify" />
</template>
</q-input>
</header>
<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"
>
<div
class="rounded cursor-pointer relative-position"
:style="`border: 1px solid ${selectedItem.includes(item) ? color : 'transparent'}`"
@click="() => select(item)"
>
<div
v-if="selectedItem.includes(item)"
class="badge absolute-top-right flex justify-center q-ma-sm"
:style="`background-color: ${color}`"
>
{{ selectedItem.indexOf(item) + 1 }}
</div>
<slot name="data" :item="item"></slot>
</div>
</div>
</div>
</section>
</section>
</template>
<style lang="scss" scoped>
.badge {
border-radius: 50%;
width: 20px;
height: 20px;
color: var(--surface-1);
}
</style>