up
This commit is contained in:
@@ -95,6 +95,14 @@ func JoinModulos(modules []string) string {
|
||||
return strings.Join(clean, ",")
|
||||
}
|
||||
|
||||
func GetAiConfigSelect() ([]AiConfig, error) {
|
||||
var items []AiConfig
|
||||
if err := app.Http.Database.DB.Model(&AiConfig{}).Select("id, nombre, provider").Order("nombre ASC").Find(&items).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
// GetAiConfigForService retorna la config activa asignada al módulo indicado.
|
||||
// Lógica de prioridad:
|
||||
// 1. Config activa con modulo conteniendo service (puede ser comma-separated)
|
||||
|
||||
+28
-4
@@ -20,6 +20,13 @@ type Contrato struct {
|
||||
Estado string `json:"estado" gorm:"column:estado;default:'activo'"` // activo | vencido | cancelado | renovado
|
||||
AutoRenovar bool `json:"auto_renovar" gorm:"column:auto_renovar;default:false"`
|
||||
Notas string `json:"notas" gorm:"column:notas"`
|
||||
// Infraestructura asociada (opcional)
|
||||
ServidorID *uint `json:"servidor_id" gorm:"column:servidor_id"`
|
||||
Servidor Servidor `json:"servidor" gorm:"foreignKey:ServidorID"`
|
||||
ConxDbID *uint `json:"conx_db_id" gorm:"column:conx_db_id"`
|
||||
ConxDb ConxDb `json:"conx_db" gorm:"foreignKey:ConxDbID"`
|
||||
AiConfigID *uint `json:"ai_config_id" gorm:"column:ai_config_id"`
|
||||
AiConfig AiConfig `json:"ai_config" gorm:"foreignKey:AiConfigID"`
|
||||
// Enlace de pago Bold: único por ciclo de pago.
|
||||
// Se reutiliza en múltiples notificaciones del mismo ciclo.
|
||||
// Se anula (vacía) cuando SALE_APPROVED llega y se registra el pago.
|
||||
@@ -36,7 +43,8 @@ func GetAllContratos(limit, offset int, search, estado string) ([]Contrato, int6
|
||||
var items []Contrato
|
||||
var total int64
|
||||
db := app.Http.Database.DB.Model(&Contrato{}).
|
||||
Preload("Cliente").Preload("Servicios")
|
||||
Preload("Cliente").Preload("Servicios").
|
||||
Preload("Servidor").Preload("ConxDb").Preload("AiConfig")
|
||||
if search != "" {
|
||||
db = db.Joins("JOIN clientes ON clientes.id = contratos.cliente_id").
|
||||
Where("clientes.nombre ILIKE ? OR clientes.empresa ILIKE ?",
|
||||
@@ -56,7 +64,7 @@ func GetAllContratos(limit, offset int, search, estado string) ([]Contrato, int6
|
||||
|
||||
func GetContratoByID(id uint) (*Contrato, error) {
|
||||
var item Contrato
|
||||
if err := app.Http.Database.DB.Preload("Cliente").Preload("Servicios").First(&item, id).Error; err != nil {
|
||||
if err := app.Http.Database.DB.Preload("Cliente").Preload("Servicios").Preload("Servidor").Preload("ConxDb").Preload("AiConfig").First(&item, id).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &item, nil
|
||||
@@ -156,7 +164,7 @@ func CreateContrato(c Contrato, servicioIDs []uint) error {
|
||||
|
||||
func UpdateContrato(c Contrato, servicioIDs []uint) error {
|
||||
db := app.Http.Database.DB
|
||||
if err := db.Model(&Contrato{}).Where("id = ?", c.ID).Updates(map[string]interface{}{
|
||||
updates := map[string]interface{}{
|
||||
"cliente_id": c.ClienteID,
|
||||
"fecha_inicio": c.FechaInicio,
|
||||
"fecha_vencimiento": c.FechaVencimiento,
|
||||
@@ -165,7 +173,23 @@ func UpdateContrato(c Contrato, servicioIDs []uint) error {
|
||||
"estado": c.Estado,
|
||||
"auto_renovar": c.AutoRenovar,
|
||||
"notas": c.Notas,
|
||||
}).Error; err != nil {
|
||||
}
|
||||
if c.ServidorID != nil {
|
||||
updates["servidor_id"] = *c.ServidorID
|
||||
} else {
|
||||
updates["servidor_id"] = nil
|
||||
}
|
||||
if c.ConxDbID != nil {
|
||||
updates["conx_db_id"] = *c.ConxDbID
|
||||
} else {
|
||||
updates["conx_db_id"] = nil
|
||||
}
|
||||
if c.AiConfigID != nil {
|
||||
updates["ai_config_id"] = *c.AiConfigID
|
||||
} else {
|
||||
updates["ai_config_id"] = nil
|
||||
}
|
||||
if err := db.Model(&Contrato{}).Where("id = ?", c.ID).Updates(updates).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if servicioIDs != nil {
|
||||
|
||||
@@ -88,3 +88,15 @@ func DeleteConxDb(conxDb ConxDb) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetConxDbSelect(servidorID string) ([]ConxDb, error) {
|
||||
var items []ConxDb
|
||||
db := app.Http.Database.DB.Model(&ConxDb{}).Select("id, nombre, servidor_id").Order("nombre ASC")
|
||||
if servidorID != "" {
|
||||
db = db.Where("servidor_id = ?", servidorID)
|
||||
}
|
||||
if err := db.Find(&items).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
<tr>
|
||||
<th class="py-2 px-3">Cliente</th>
|
||||
<th class="py-2 px-3">Servicios</th>
|
||||
<th class="py-2 px-3">Infra</th>
|
||||
<th class="py-2 px-3">Vencimiento</th>
|
||||
<th class="py-2 px-3">Días</th>
|
||||
<th class="py-2 px-3">Precio</th>
|
||||
@@ -49,6 +50,29 @@
|
||||
</template>
|
||||
<span x-show="!d.servicios||d.servicios.length===0" class="text-gray-400">—</span>
|
||||
</td>
|
||||
<td class="py-2 px-3">
|
||||
<div class="flex gap-1 flex-wrap">
|
||||
<template x-if="d.servidor">
|
||||
<span class="inline-flex items-center gap-0.5 text-xs bg-blue-50 text-blue-700 rounded px-1.5 py-0.5" title="Servidor: " + d.servidor.nombre>
|
||||
<svg class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M5.25 14.25h13.5m-13.5 0a3 3 0 0 1-3-3m3 3a3 3 0 1 0 0 6h13.5a3 3 0 1 0 0-6m-16.5-3a3 3 0 0 1 3-3h13.5a3 3 0 0 1 3 3m-19.5 0a4.5 4.5 0 0 1 .9-2.75L4.5 7.5l.75-1.5m-2.25 6.75h16.5"/></svg>
|
||||
<span x-text="d.servidor.nombre"></span>
|
||||
</span>
|
||||
</template>
|
||||
<template x-if="d.conx_db">
|
||||
<span class="inline-flex items-center gap-0.5 text-xs bg-green-50 text-green-700 rounded px-1.5 py-0.5" title="BD: " + d.conx_db.nombre>
|
||||
<svg class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M20.25 6.375c0 2.278-3.694 4.125-8.25 4.125S3.75 8.653 3.75 6.375m16.5 0c0-2.278-3.694-4.125-8.25-4.125S3.75 4.097 3.75 6.375m16.5 0v11.25c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125V6.375m16.5 0v3.75m-16.5-3.75v3.75m16.5 0v3.75C20.25 16.153 16.556 18 12 18s-8.25-1.847-8.25-4.125v-3.75m16.5 0c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125"/></svg>
|
||||
<span x-text="d.conx_db.nombre"></span>
|
||||
</span>
|
||||
</template>
|
||||
<template x-if="d.ai_config">
|
||||
<span class="inline-flex items-center gap-0.5 text-xs bg-purple-50 text-purple-700 rounded px-1.5 py-0.5" title="IA: " + d.ai_config.nombre>
|
||||
<svg class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M9.813 15.904 9 18.75l-.813-2.846a4.5 4.5 0 0 0-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 0 0 3.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 0 0 3.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 0 0-3.09 3.09ZM18.259 8.715 18 9.75l-.259-1.035a3.375 3.375 0 0 0-2.455-2.456L14.25 6l1.036-.259a3.375 3.375 0 0 0 2.455-2.456L18 2.25l.259 1.035a3.375 3.375 0 0 0 2.455 2.456L21.75 6l-1.036.259a3.375 3.375 0 0 0-2.455 2.456ZM16.894 20.567 16.5 21.75l-.394-1.183a2.25 2.25 0 0 0-1.423-1.423L13.5 18.75l1.183-.394a2.25 2.25 0 0 0 1.423-1.423l.394-1.183.394 1.183a2.25 2.25 0 0 0 1.423 1.423l1.183.394-1.183.394a2.25 2.25 0 0 0-1.423 1.423Z"/></svg>
|
||||
<span x-text="d.ai_config.nombre"></span>
|
||||
</span>
|
||||
</template>
|
||||
<span x-show="!d.servidor && !d.conx_db && !d.ai_config" class="text-gray-300">—</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-2 px-3" x-text="fmtDate(d.fecha_vencimiento)"></td>
|
||||
<td class="py-2 px-3">
|
||||
<span class="px-2 py-0.5 rounded text-xs font-semibold"
|
||||
@@ -103,7 +127,7 @@
|
||||
</tr>
|
||||
</template>
|
||||
<tr x-show="!loading && datos.length===0">
|
||||
<td colspan="7" class="text-center text-gray-400 py-8">Sin registros</td>
|
||||
<td colspan="8" class="text-center text-gray-400 py-8">Sin registros</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -186,6 +210,37 @@
|
||||
<label class="text-xs font-medium text-gray-600">Notas</label>
|
||||
<textarea x-model="form.notas" rows="2" class="mt-1 w-full border rounded px-3 py-2 text-sm"></textarea>
|
||||
</div>
|
||||
<div class="col-span-2 border-t border-gray-100 pt-3 mt-1">
|
||||
<p class="text-xs font-semibold text-gray-500 mb-2 uppercase tracking-wider">Infraestructura <span class="font-normal normal-case text-gray-400">(opcional)</span></p>
|
||||
</div>
|
||||
<div class="col-span-2 sm:col-span-1">
|
||||
<label class="text-xs font-medium text-gray-600">Servidor</label>
|
||||
<select x-model="form.servidor_id" @change="onServidorChange()" class="mt-1 w-full border rounded px-3 py-2 text-sm">
|
||||
<option value="">— Sin servidor —</option>
|
||||
<template x-for="s in servidoresList" :key="s.ID">
|
||||
<option :value="s.ID" x-text="s.nombre + ' — ' + (s.ip_servidor||'')"></option>
|
||||
</template>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-span-2 sm:col-span-1">
|
||||
<label class="text-xs font-medium text-gray-600">Base de datos</label>
|
||||
<select x-model="form.conx_db_id" class="mt-1 w-full border rounded px-3 py-2 text-sm">
|
||||
<option value="">— Sin BD —</option>
|
||||
<template x-for="db in conxDbList" :key="db.ID">
|
||||
<option :value="db.ID" x-text="db.nombre"></option>
|
||||
</template>
|
||||
</select>
|
||||
<p x-show="form.servidor_id && conxDbList.length===0" class="text-xs text-gray-400 mt-0.5">Sin BD para este servidor</p>
|
||||
</div>
|
||||
<div class="col-span-2">
|
||||
<label class="text-xs font-medium text-gray-600">IA / AI Config</label>
|
||||
<select x-model="form.ai_config_id" class="mt-1 w-full border rounded px-3 py-2 text-sm">
|
||||
<option value="">— Sin IA —</option>
|
||||
<template x-for="ai in aiConfigList" :key="ai.ID">
|
||||
<option :value="ai.ID" x-text="ai.nombre + ' (' + ai.provider + ')'"></option>
|
||||
</template>
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<input type="checkbox" x-model="form.auto_renovar" id="auto_ren" />
|
||||
<label for="auto_ren" class="text-sm">Auto-renovar</label>
|
||||
@@ -349,9 +404,10 @@ document.addEventListener('alpine:init', () => {
|
||||
bienvenidaModal: false, bienvenidaReglaId: '', bienvenidaContratoId: null,
|
||||
historialModal: false, historialTitulo: '', historialTimeline: [], historialLoading: false,
|
||||
clientes: [], servicios: [], reglas: [], reglasBienvenida: [],
|
||||
servidoresList: [], conxDbList: [], aiConfigList: [],
|
||||
selectedId: null,
|
||||
verificandoID: null,
|
||||
form: { cliente_id:'', servicio_ids:[], fecha_inicio:'', fecha_vencimiento:'', precio_acordado:0, moneda:'COP', estado:'activo', auto_renovar:false, notas:'' },
|
||||
form: { cliente_id:'', servicio_ids:[], fecha_inicio:'', fecha_vencimiento:'', precio_acordado:0, moneda:'COP', estado:'activo', auto_renovar:false, notas:'', servidor_id:'', conx_db_id:'', ai_config_id:'' },
|
||||
toast: { show: false, msg: '', type: 'ok' },
|
||||
|
||||
async init() {
|
||||
@@ -369,10 +425,12 @@ document.addEventListener('alpine:init', () => {
|
||||
|
||||
async loadSelects() {
|
||||
try {
|
||||
const [c, s, r] = await Promise.all([
|
||||
const [c, s, r, sv, ai] = await Promise.all([
|
||||
axios.get('/app/api/clientes/select'),
|
||||
axios.get('/app/api/servicios/select'),
|
||||
axios.get('/app/api/reglas-notificacion'),
|
||||
axios.get('/app/loadservidorselect'),
|
||||
axios.get('/app/api/ai-config/select'),
|
||||
]);
|
||||
this.clientes = Array.isArray(c.data) ? c.data : (c.data.registros || []);
|
||||
this.servicios = Array.isArray(s.data) ? s.data : (s.data.registros || []);
|
||||
@@ -380,11 +438,24 @@ document.addEventListener('alpine:init', () => {
|
||||
this.reglas = todasReglas.filter(x => x.activo);
|
||||
this.reglasBienvenida = todasReglas.filter(x => x.activo && x.tipo_evento === 'bienvenida');
|
||||
if (this.reglasBienvenida.length > 0) this.bienvenidaReglaId = this.reglasBienvenida[0].ID;
|
||||
this.servidoresList = sv.data.registros || [];
|
||||
this.aiConfigList = ai.data.registros || [];
|
||||
} catch(e) {
|
||||
this.showToast('Error cargando listas: ' + (e.response?.data?.error || e.message), 'error');
|
||||
}
|
||||
},
|
||||
|
||||
async onServidorChange() {
|
||||
this.form.conx_db_id = '';
|
||||
if (!this.form.servidor_id) { this.conxDbList = []; return; }
|
||||
try {
|
||||
const res = await axios.get('/app/api/conxdb/select', { params: { servidor_id: this.form.servidor_id } });
|
||||
this.conxDbList = res.data.registros || [];
|
||||
} catch(e) {
|
||||
this.conxDbList = [];
|
||||
}
|
||||
},
|
||||
|
||||
get precioSugerido() {
|
||||
return this.servicios
|
||||
.filter(s => (this.form.servicio_ids || []).includes(s.ID))
|
||||
@@ -400,7 +471,7 @@ document.addEventListener('alpine:init', () => {
|
||||
this.form.precio_acordado = this.precioSugerido;
|
||||
},
|
||||
|
||||
openEdit(d) {
|
||||
async openEdit(d) {
|
||||
this.form = {
|
||||
cliente_id: d.cliente_id,
|
||||
servicio_ids: (d.servicios || []).map(s => s.ID),
|
||||
@@ -410,16 +481,24 @@ document.addEventListener('alpine:init', () => {
|
||||
moneda: d.moneda || 'COP',
|
||||
estado: d.estado,
|
||||
auto_renovar: d.auto_renovar,
|
||||
notas: d.notas
|
||||
notas: d.notas,
|
||||
servidor_id: d.servidor_id || '',
|
||||
conx_db_id: d.conx_db_id || '',
|
||||
ai_config_id: d.ai_config_id || ''
|
||||
};
|
||||
this.selectedId = d.ID;
|
||||
this.editModal = true;
|
||||
// Cargar BD del servidor seleccionado
|
||||
if (d.servidor_id) {
|
||||
await this.onServidorChange();
|
||||
}
|
||||
},
|
||||
openDelete(d) { this.selectedId = d.ID; this.deleteModal = true; },
|
||||
closeModals() {
|
||||
this.addModal = this.editModal = this.deleteModal = false;
|
||||
this.selectedId = null;
|
||||
this.form = { cliente_id:'', servicio_ids:[], fecha_inicio:'', fecha_vencimiento:'', precio_acordado:0, moneda:'COP', estado:'activo', auto_renovar:false, notas:'' };
|
||||
this.conxDbList = [];
|
||||
this.form = { cliente_id:'', servicio_ids:[], fecha_inicio:'', fecha_vencimiento:'', precio_acordado:0, moneda:'COP', estado:'activo', auto_renovar:false, notas:'', servidor_id:'', conx_db_id:'', ai_config_id:'' };
|
||||
},
|
||||
|
||||
async save() {
|
||||
@@ -430,6 +509,9 @@ document.addEventListener('alpine:init', () => {
|
||||
cliente_id: parseInt(this.form.cliente_id) || 0,
|
||||
servicio_id: parseInt(this.form.servicio_id) || 0,
|
||||
precio_acordado: parseFloat(this.form.precio_acordado) || 0,
|
||||
servidor_id: this.form.servidor_id ? parseInt(this.form.servidor_id) : null,
|
||||
conx_db_id: this.form.conx_db_id ? parseInt(this.form.conx_db_id) : null,
|
||||
ai_config_id: this.form.ai_config_id ? parseInt(this.form.ai_config_id) : null,
|
||||
};
|
||||
if (this.editModal) {
|
||||
await axios.put(`/app/api/contratos/${this.selectedId}`, payload);
|
||||
|
||||
@@ -155,6 +155,15 @@ func UpdateAiConfigHandler(c *fiber.Ctx) error {
|
||||
return c.JSON(fiber.Map{"ok": true})
|
||||
}
|
||||
|
||||
// GetAiConfigSelect devuelve lista simple para selects
|
||||
func GetAiConfigSelect(c *fiber.Ctx) error {
|
||||
items, err := models.GetAiConfigSelect()
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
return c.JSON(fiber.Map{"registros": items})
|
||||
}
|
||||
|
||||
// DeleteAiConfigHandler elimina una configuración de IA.
|
||||
func DeleteAiConfigHandler(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 64)
|
||||
|
||||
@@ -62,13 +62,16 @@ func GetContratos(c *fiber.Ctx) error {
|
||||
|
||||
func CreateContrato(c *fiber.Ctx) error {
|
||||
type Input struct {
|
||||
ClienteID uint `json:"cliente_id"`
|
||||
ServicioIDs []uint `json:"servicio_ids"`
|
||||
FechaInicio string `json:"fecha_inicio"`
|
||||
FechaVencimiento string `json:"fecha_vencimiento"`
|
||||
ClienteID uint `json:"cliente_id"`
|
||||
ServicioIDs []uint `json:"servicio_ids"`
|
||||
FechaInicio string `json:"fecha_inicio"`
|
||||
FechaVencimiento string `json:"fecha_vencimiento"`
|
||||
PrecioAcordado float64 `json:"precio_acordado"`
|
||||
AutoRenovar bool `json:"auto_renovar"`
|
||||
Notas string `json:"notas"`
|
||||
AutoRenovar bool `json:"auto_renovar"`
|
||||
Notas string `json:"notas"`
|
||||
ServidorID *uint `json:"servidor_id"`
|
||||
ConxDbID *uint `json:"conx_db_id"`
|
||||
AiConfigID *uint `json:"ai_config_id"`
|
||||
}
|
||||
var inp Input
|
||||
if err := c.BodyParser(&inp); err != nil {
|
||||
@@ -86,10 +89,13 @@ func CreateContrato(c *fiber.Ctx) error {
|
||||
ClienteID: inp.ClienteID,
|
||||
FechaInicio: fi,
|
||||
FechaVencimiento: fv,
|
||||
PrecioAcordado: inp.PrecioAcordado,
|
||||
PrecioAcordado: float64(inp.PrecioAcordado),
|
||||
AutoRenovar: inp.AutoRenovar,
|
||||
Notas: inp.Notas,
|
||||
Estado: "activo",
|
||||
ServidorID: inp.ServidorID,
|
||||
ConxDbID: inp.ConxDbID,
|
||||
AiConfigID: inp.AiConfigID,
|
||||
}
|
||||
if err := models.CreateContrato(m, inp.ServicioIDs); err != nil {
|
||||
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
|
||||
@@ -115,10 +121,13 @@ func UpdateContrato(c *fiber.Ctx) error {
|
||||
PrecioAcordado float64 `json:"precio_acordado"`
|
||||
AutoRenovar bool `json:"auto_renovar"`
|
||||
Notas string `json:"notas"`
|
||||
ServidorID *uint `json:"servidor_id"`
|
||||
ConxDbID *uint `json:"conx_db_id"`
|
||||
AiConfigID *uint `json:"ai_config_id"`
|
||||
}
|
||||
var inp Input
|
||||
if err := c.BodyParser(&inp); err != nil {
|
||||
return c.Status(400).JSON(fiber.Map{"error": err.Error()})
|
||||
return c.Status(400).JSON(fiber.Map{"error": "ID inválido"})
|
||||
}
|
||||
existing, err := models.GetContratoByID(uint(id))
|
||||
if err != nil {
|
||||
@@ -136,6 +145,9 @@ func UpdateContrato(c *fiber.Ctx) error {
|
||||
existing.PrecioAcordado = inp.PrecioAcordado
|
||||
existing.AutoRenovar = inp.AutoRenovar
|
||||
existing.Notas = inp.Notas
|
||||
existing.ServidorID = inp.ServidorID
|
||||
existing.ConxDbID = inp.ConxDbID
|
||||
existing.AiConfigID = inp.AiConfigID
|
||||
if err := models.UpdateContrato(*existing, inp.ServicioIDs); err != nil {
|
||||
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
|
||||
@@ -125,3 +125,12 @@ func DeleteConxDb(c *fiber.Ctx) error {
|
||||
"message": "conx ssh eliminado exitosamente",
|
||||
})
|
||||
}
|
||||
|
||||
func GetConxDbSelect(c *fiber.Ctx) error {
|
||||
servidorID := c.Query("servidor_id")
|
||||
items, err := models.GetConxDbSelect(servidorID)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
return c.JSON(fiber.Map{"registros": items})
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ func UserRoutes(app fiber.Router) {
|
||||
// Rutas de conexiones db
|
||||
protected.Get("/conexion_db", middlewares.MenuMiddleware, controllers.ConxDb) // Renderizar la vista
|
||||
protected.Get("/loadconexiondb", controllers.GetConxDb) // Obtener
|
||||
protected.Get("/api/conxdb/select", controllers.GetConxDbSelect) // Select (filtrado por ?servidor_id=)
|
||||
protected.Post("/conexiondb", controllers.CreateConxDb) // Crear
|
||||
protected.Put("/conexiondb/:id", controllers.UpdateConxDb) // Actualizar
|
||||
protected.Delete("/conexiondb/:id", controllers.DeleteConxDb) // Eliminar
|
||||
@@ -284,6 +285,7 @@ func UserRoutes(app fiber.Router) {
|
||||
// ─── Configuraciones de IA (Qwen, OpenAI, etc.) ─────────────────────────
|
||||
protected.Get("/ai-config", middlewares.MenuMiddleware, controllers.AiConfigIndex)
|
||||
protected.Get("/ai-config/list", controllers.GetAiConfigs)
|
||||
protected.Get("/api/ai-config/select", controllers.GetAiConfigSelect)
|
||||
protected.Post("/ai-config", controllers.CreateAiConfigHandler)
|
||||
protected.Put("/ai-config/:id", controllers.UpdateAiConfigHandler)
|
||||
protected.Delete("/ai-config/:id", controllers.DeleteAiConfigHandler)
|
||||
|
||||
Reference in New Issue
Block a user