Files
CRM_Montzar/apps/web/src/components/pipeline/PipelineToolbar.vue
T

199 lines
4.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import UiFilterBar from '@/components/ui/UiFilterBar.vue';
import UiIcon from '@/components/UiIcon.vue';
import UiSegmented from '@/components/ui/UiSegmented.vue';
import UiSelect from '@/components/ui/UiSelect.vue';
export type PipelineViewMode = 'kanban' | 'list';
withDefaults(
defineProps<{
pipelineName: string;
pipelineOptions: Array<{ id: string; name: string }>;
canCreate?: boolean;
icon?: 'briefcase' | 'grid';
createOptionLabel?: string;
showAmountFilters?: boolean;
}>(),
{
canCreate: false,
icon: 'briefcase',
createOptionLabel: 'مسیر فروش جدید…',
showAmountFilters: true,
},
);
const emit = defineEmits<{
create: [];
}>();
const viewMode = defineModel<PipelineViewMode>('viewMode', { required: true });
const search = defineModel<string>('search', { default: '' });
const selectedPipelineId = defineModel<string>('selectedPipelineId', { required: true });
const amountMin = defineModel<string>('amountMin', { default: '' });
const amountMax = defineModel<string>('amountMax', { default: '' });
const viewOptions = [
{ value: 'kanban' as const, label: 'نمای ستونی', icon: 'grid' as const },
{ value: 'list' as const, label: 'نمای لیست', icon: 'list' as const },
];
function onPick(value: string) {
if (value === '__create__') {
emit('create');
return;
}
selectedPipelineId.value = value;
}
</script>
<template>
<header class="toolbar" dir="rtl">
<div class="title-block">
<span class="brand-ico" aria-hidden="true">
<UiIcon :name="icon" :size="18" />
</span>
<h1>{{ pipelineName }}</h1>
</div>
<UiSegmented v-model="viewMode" :options="viewOptions">
<template #icon="{ option }">
<UiIcon :name="option.icon ?? 'grid'" :size="16" />
</template>
</UiSegmented>
<UiSelect
class="pipeline-pick"
:model-value="selectedPipelineId"
@update:model-value="onPick"
>
<option
v-for="opt in pipelineOptions"
:key="opt.id"
:value="opt.id"
>
{{ opt.name }}
</option>
<option v-if="canCreate" value="__create__">{{ createOptionLabel }}</option>
</UiSelect>
<div class="excel-actions">
<slot name="excel" />
</div>
<UiFilterBar
v-model:search="search"
class="filters"
:show-filters="showAmountFilters"
>
<template v-if="showAmountFilters">
<label class="field">
<span>حداقل مبلغ</span>
<input v-model="amountMin" type="number" min="0" placeholder="۰" />
</label>
<label class="field">
<span>حداکثر مبلغ</span>
<input v-model="amountMax" type="number" min="0" placeholder="—" />
</label>
</template>
</UiFilterBar>
</header>
</template>
<style scoped>
.toolbar {
display: flex;
flex-wrap: nowrap;
align-items: center;
gap: 0.55rem;
margin-bottom: 0.85rem;
min-width: 0;
width: 100%;
}
.title-block {
display: flex;
align-items: center;
gap: 0.55rem;
flex: 0 0 auto;
min-width: 0;
}
.brand-ico {
width: var(--control-h);
height: var(--control-h);
border-radius: var(--radius);
display: grid;
place-items: center;
background: var(--accent-deep);
color: #fff;
flex: 0 0 auto;
}
h1 {
margin: 0;
font-size: 1.15rem;
font-weight: 600;
color: var(--ink);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.pipeline-pick {
flex: 0 1 13rem;
min-width: 8.5rem;
}
.excel-actions {
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
flex: 0 0 auto;
}
.excel-actions :deep(.btn-ghost-sm) {
border: 1px solid #e2e8f0;
background: #fff;
color: #0f766e;
border-radius: 10px;
padding: 0.45rem 0.75rem;
font-weight: 700;
font-size: 0.85rem;
cursor: pointer;
font: inherit;
}
.filters {
flex: 1 1 12rem;
min-width: 0;
}
.field {
display: grid;
gap: 0.3rem;
}
.field span {
font-size: 0.8rem;
color: var(--muted);
font-weight: 700;
}
@container pipeline (max-width: 720px) {
.toolbar {
flex-wrap: wrap;
}
.title-block {
width: 100%;
}
.pipeline-pick,
.excel-actions,
.filters {
flex: 1 1 100%;
}
}
</style>