mirror of
https://origin.cursor.com/mrdevmx/panels.git
synced 2026-10-09 18:43:18 +00:00
Implementa el módulo completo de programa de obra vinculado al presupuesto: - Schema PostgreSQL: work_programs, periods, concept_slots, partida_amounts, progress - RPC: CRUD, import replace, generate wizard, recalculate partidas, vs-cost - API: parser Excel Neodata (concepto Barra= + partida erogaciones), endpoints REST - UI: página /programa-obra con cuadrículas, Gantt, comparativo programado/ejecutado - Integración: menú, ficha proyecto, banner en presupuesto, permiso manage_budget Co-authored-by: alberto.martinez <alberto.martinez@mrdev.mx>
59 lines
1.9 KiB
Vue
59 lines
1.9 KiB
Vue
<template>
|
|
<Dialog v-model:visible="visibleModel" header="Generar programa automático" modal :style="{ width: '28rem' }">
|
|
<Message severity="info" :closable="false">
|
|
Crea un borrador distribuyendo los conceptos del presupuesto según la estrategia elegida.
|
|
</Message>
|
|
<FormField label="Estrategia" class="mt-3">
|
|
<Select v-model="strategy" :options="options" option-label="label" option-value="value" class="w-full" />
|
|
</FormField>
|
|
<Message v-if="error" severity="error" class="mt-3" :closable="false">{{ error }}</Message>
|
|
<template #footer>
|
|
<Button label="Cancelar" text @click="visibleModel = false" />
|
|
<Button label="Generar" icon="pi pi-bolt" :loading="busy" @click="run" />
|
|
</template>
|
|
</Dialog>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import FormField from "~/components/padron/FormField.vue";
|
|
|
|
const props = defineProps<{ visible: boolean; projectId: number }>();
|
|
const emit = defineEmits<{ "update:visible": [boolean]; generated: [] }>();
|
|
|
|
const { api } = useApi();
|
|
const toast = useToast();
|
|
|
|
const visibleModel = computed({
|
|
get: () => props.visible,
|
|
set: (v) => emit("update:visible", v),
|
|
});
|
|
|
|
const strategy = ref("keyword");
|
|
const busy = ref(false);
|
|
const error = ref("");
|
|
|
|
const options = [
|
|
{ value: "keyword", label: "Por tipo de partida (preliminares → acabados)" },
|
|
{ value: "wbs", label: "Por orden WBS del presupuesto" },
|
|
{ value: "amount", label: "Por peso económico" },
|
|
];
|
|
|
|
async function run() {
|
|
if (!props.projectId) return;
|
|
busy.value = true;
|
|
error.value = "";
|
|
try {
|
|
await api(`/v1/projects/${props.projectId}/work-program/generate`, {
|
|
method: "POST",
|
|
json: { strategy: strategy.value },
|
|
});
|
|
toast.add({ severity: "success", summary: "Programa generado", life: 2500 });
|
|
emit("generated");
|
|
visibleModel.value = false;
|
|
} catch (err) {
|
|
error.value = err instanceof Error ? err.message : "No se pudo generar";
|
|
} finally {
|
|
busy.value = false;
|
|
}
|
|
}
|
|
</script>
|