cfe94d9178
Раньше чтобы убрать один регион из выбора, приходилось сбрасывать все и выбирать заново. Добавлен closable-chips на v-autocomplete регионов в трёх местах: карточка создания проекта (NewProjectDialog), панель редактирования (ProjectDetailsDrawer) и массовое изменение регионов (RegionsBulkDialog). Теперь у каждого чипа есть крестик. Покрыто Vitest: closableChips=true на каждом селекторе. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
117 lines
4.6 KiB
Vue
117 lines
4.6 KiB
Vue
<template>
|
||
<v-dialog v-model="open" max-width="560">
|
||
<v-card>
|
||
<v-card-title>Регионы — для {{ count }} проектов</v-card-title>
|
||
<v-card-text>
|
||
<p class="text-caption text-medium-emphasis mb-4">
|
||
Изменения применяются к каждому из {{ count }} выбранных проектов: выбранные субъекты
|
||
добавляются к их регионам или убираются из них.
|
||
</p>
|
||
|
||
<div class="mb-2">
|
||
<div class="text-caption text-success font-weight-medium mb-2">➕ Добавить регионы</div>
|
||
<v-autocomplete
|
||
v-model="addRegions"
|
||
:items="selectableRegions"
|
||
item-title="name"
|
||
item-value="code"
|
||
label="Субъекты РФ"
|
||
multiple
|
||
chips
|
||
closable-chips
|
||
clearable
|
||
density="comfortable"
|
||
data-testid="region-add-select"
|
||
@update:menu="repositionMenuAfterOpen"
|
||
>
|
||
<template #item="{ props: itemProps, item }">
|
||
<v-list-item v-bind="itemProps">
|
||
<template #subtitle>
|
||
{{ FEDERAL_DISTRICT_NAMES[item.raw.federalDistrict] || '' }}
|
||
</template>
|
||
</v-list-item>
|
||
</template>
|
||
</v-autocomplete>
|
||
</div>
|
||
|
||
<div>
|
||
<div class="text-caption text-error font-weight-medium mb-2">➖ Убрать регионы</div>
|
||
<v-autocomplete
|
||
v-model="removeRegions"
|
||
:items="selectableRegions"
|
||
item-title="name"
|
||
item-value="code"
|
||
label="Субъекты РФ"
|
||
multiple
|
||
chips
|
||
closable-chips
|
||
clearable
|
||
density="comfortable"
|
||
data-testid="region-remove-select"
|
||
@update:menu="repositionMenuAfterOpen"
|
||
>
|
||
<template #item="{ props: itemProps, item }">
|
||
<v-list-item v-bind="itemProps">
|
||
<template #subtitle>
|
||
{{ FEDERAL_DISTRICT_NAMES[item.raw.federalDistrict] || '' }}
|
||
</template>
|
||
</v-list-item>
|
||
</template>
|
||
</v-autocomplete>
|
||
</div>
|
||
</v-card-text>
|
||
<v-card-actions>
|
||
<v-spacer />
|
||
<v-btn data-testid="cancel" @click="open = false">Отмена</v-btn>
|
||
<v-btn
|
||
color="primary"
|
||
data-testid="apply"
|
||
:disabled="addRegions.length === 0 && removeRegions.length === 0"
|
||
@click="apply"
|
||
>Применить к {{ count }}</v-btn
|
||
>
|
||
</v-card-actions>
|
||
</v-card>
|
||
</v-dialog>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, watch } from 'vue';
|
||
import { REGIONS, FEDERAL_DISTRICT_NAMES } from '../../constants/regions';
|
||
import { repositionMenuAfterOpen } from '../../utils/menuRepositionFix';
|
||
|
||
const props = defineProps<{ modelValue: boolean; count: number }>();
|
||
const emit = defineEmits<{
|
||
'update:modelValue': [value: boolean];
|
||
apply: [payload: { add_regions: number[]; remove_regions: number[] }];
|
||
}>();
|
||
|
||
// code:0 — sentinel «Вся РФ»; в bulk add/remove субъектов не выбирается.
|
||
const selectableRegions = REGIONS.filter((r) => r.code !== 0);
|
||
|
||
const open = ref(props.modelValue);
|
||
const addRegions = ref<number[]>([]);
|
||
const removeRegions = ref<number[]>([]);
|
||
|
||
watch(
|
||
() => props.modelValue,
|
||
(val) => {
|
||
open.value = val;
|
||
if (val) {
|
||
addRegions.value = [];
|
||
removeRegions.value = [];
|
||
}
|
||
},
|
||
);
|
||
watch(open, (val) => emit('update:modelValue', val));
|
||
|
||
function apply() {
|
||
emit('apply', { add_regions: [...addRegions.value], remove_regions: [...removeRegions.value] });
|
||
addRegions.value = [];
|
||
removeRegions.value = [];
|
||
open.value = false;
|
||
}
|
||
|
||
defineExpose({ addRegions, removeRegions, apply });
|
||
</script>
|