Files
CRM_Montzar/apps/web/src/components/UserMultiSelect.vue
T

109 lines
2.8 KiB
Vue

<script setup lang="ts">
import { computed } from 'vue';
import { Button as AButton, Select as ASelect } from 'ant-design-vue';
import { toFaDigits } from '@/lib/jalali';
type PickUser = { id: string; fullName: string };
const props = withDefaults(
defineProps<{
modelValue: string[];
users: PickUser[];
disabled?: boolean;
/** حداقل تعداد انتخاب (حذف آخرین نفر غیرفعال می‌شود) */
min?: number;
addLabel?: string;
emptyLabel?: string;
/** دکمهٔ انتخاب یکجای همهٔ اعضا و جمع‌کردن برچسب‌ها وقتی تعداد زیاد است */
selectAll?: boolean;
}>(),
{ disabled: false, min: 0, addLabel: 'افزودن', emptyLabel: 'کسی انتخاب نشده', selectAll: false },
);
const emit = defineEmits<{
'update:modelValue': [ids: string[]];
change: [ids: string[]];
}>();
const options = computed(() =>
props.users.map((u) => ({ value: u.id, label: u.fullName })),
);
const allPicked = computed(
() =>
props.users.length > 0 &&
props.users.every((user) => props.modelValue.includes(user.id)),
);
const tagLimit = computed(() => {
if (!props.selectAll) return undefined;
if (allPicked.value && props.users.length > 2) return 0;
return 'responsive' as const;
});
function tagPlaceholder(omitted: unknown[]) {
if (allPicked.value) return `همهٔ اعضا (${toFaDigits(props.users.length)})`;
const extra = Array.isArray(omitted) ? omitted.length : 0;
return extra ? `${toFaDigits(extra)} نفر دیگر` : '';
}
function commit(ids: string[]) {
if (ids.length < props.min && props.modelValue.length >= props.min) {
emit('update:modelValue', [...props.modelValue]);
return;
}
emit('update:modelValue', ids);
emit('change', ids);
}
function onUpdate(value: unknown) {
const ids = Array.isArray(value) ? value.map(String) : [];
commit(ids);
}
function pickAll() {
if (props.disabled || allPicked.value) return;
commit(props.users.map((user) => user.id));
}
</script>
<template>
<div class="user-multi" :class="{ 'with-all': selectAll }">
<a-select
mode="multiple"
allow-clear
show-search
option-filter-prop="label"
:value="modelValue"
:options="options"
:disabled="disabled"
:placeholder="emptyLabel"
:max-tag-count="tagLimit"
:max-tag-placeholder="selectAll ? tagPlaceholder : undefined"
style="width: 100%"
@update:value="onUpdate"
/>
<a-button v-if="selectAll" :disabled="disabled || allPicked || !users.length" @click="pickAll">
همه
</a-button>
</div>
</template>
<style scoped>
.user-multi.with-all {
display: flex;
align-items: flex-start;
gap: 8px;
width: 100%;
}
.user-multi.with-all :deep(.ant-select) {
flex: 1 1 auto;
min-width: 0;
}
.user-multi.with-all :deep(.ant-btn) {
flex: 0 0 auto;
}
</style>