199 lines
4.2 KiB
Vue
199 lines
4.2 KiB
Vue
<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>
|