panels-origin/web-panel/components/BudgetItemPicker.vue
Cursor Agent 4b5d9572ee
fix: concepto de presupuesto con Select filtrable de PrimeVue
El buscador pasa a Select con filtro, el mismo patrón que proveedor y unidad, para que overlay y tema coincidan con el resto del formulario.

Co-authored-by: alberto.martinez <alberto.martinez@mrdev.mx>
2026-09-08 20:13:06 +00:00

82 lines
2.4 KiB
Vue

<template>
<Select
:model-value="modelValue ?? null"
:options="items"
option-label="label"
option-value="id"
placeholder="Buscar concepto del presupuesto..."
filter
filter-placeholder="Clave o descripción"
show-clear
fluid
class="w-full budget-item-picker"
overlay-class="budget-item-picker-overlay"
panel-class="budget-item-picker-overlay"
empty-filter-message="Sin conceptos que coincidan"
empty-message="Esta obra no tiene partidas cargadas"
@update:model-value="onUpdate"
>
<template #value="{ value, placeholder }">
<span v-if="selected" class="budget-item-value">
<span class="identifier">{{ selected.code || "—" }}</span>
<span class="budget-item-value-desc">{{ selected.description }}</span>
</span>
<span v-else class="p-select-placeholder">{{ placeholder }}</span>
</template>
<template #option="{ option }">
<div class="budget-item-option">
<span class="identifier">{{ option.code || "—" }}</span>
<span class="budget-item-option-desc">{{ option.description }}</span>
</div>
</template>
</Select>
</template>
<script setup lang="ts">
const props = defineProps<{
projectId: number;
modelValue?: number | null;
}>();
const emit = defineEmits<{ "update:modelValue": [number | null]; select: [BudgetOption | null] }>();
type BudgetOption = {
id: number;
code: string;
description: string;
unit: string;
amount: number;
label: string;
};
const { api } = useApi();
const items = ref<BudgetOption[]>([]);
const selected = computed(() => items.value.find((i) => i.id === props.modelValue) ?? null);
async function load() {
if (!props.projectId) {
items.value = [];
return;
}
const r = await api<{ items?: Array<Record<string, unknown>> }>(
`/v1/projects/${props.projectId}/budget`,
);
const raw = r.items ?? [];
items.value = raw.map((row) => ({
id: Number(row.id),
code: String(row.code ?? ""),
description: String(row.description ?? ""),
unit: String(row.unit ?? ""),
amount: Number(row.amount ?? 0),
label: [row.code, row.description].filter(Boolean).join(" — "),
}));
}
function onUpdate(id: number | null) {
const option = id == null ? null : items.value.find((i) => i.id === id) ?? null;
emit("update:modelValue", option?.id ?? null);
emit("select", option);
}
watch(() => props.projectId, load, { immediate: true });
</script>