This commit is contained in:
Lizandro Guarnizo
2026-05-16 20:54:11 -05:00
parent f08416f11f
commit 562ffa4184
5 changed files with 44 additions and 6 deletions
+1
View File
@@ -15,6 +15,7 @@ type PartnerRecurso struct {
Categoria string `json:"categoria" gorm:"column:categoria;default:'general'"` // general|tecnico|comercial|marketing
Archivo string `json:"archivo" gorm:"column:archivo"`
NombreOrig string `json:"nombre_orig" gorm:"column:nombre_orig"`
Enlace string `json:"enlace" gorm:"column:enlace"` // URL externa opcional
Activo bool `json:"activo" gorm:"column:activo;default:true"`
}
+12 -2
View File
@@ -213,9 +213,19 @@ func sendTelegramAdmin(mensaje string) {
continue
}
ts := &TelegramService{BotToken: cfg.BotToken}
if err := ts.SendMessage(cfg.ChatID, mensaje); err != nil {
log.Printf("[Notif] Error enviando telegram admin (cfg %d): %v", cfg.ID, err)
sendErr := ts.SendMessage(cfg.ChatID, mensaje)
logEntry := &models.TelegramLog{
TelegramConfigID: cfg.ID,
Titulo: "Notificación del sistema",
Mensaje: mensaje,
Estado: "ok",
}
if sendErr != nil {
log.Printf("[Notif] Error enviando telegram admin (cfg %d): %v", cfg.ID, sendErr)
logEntry.Estado = "failed"
logEntry.ErrorMsg = sendErr.Error()
}
_ = models.CreateTelegramLog(logEntry)
}
}
+19 -3
View File
@@ -37,6 +37,7 @@
<option value="marketing">Marketing</option>
</select>
<textarea x-model="newR.descripcion" placeholder="Descripción breve..." rows="2" class="input-f sm:col-span-2"></textarea>
<input x-model="newR.enlace" type="url" placeholder="Enlace externo (opcional, ej: https://...)" class="input-f sm:col-span-2">
<label class="flex items-center gap-2 text-sm text-slate-600 cursor-pointer">
<input type="checkbox" x-model="newR.activo" class="rounded accent-[#8eb02f]">
Visible para partners
@@ -85,7 +86,22 @@
</template>
</td>
<!-- Descripción -->
<td class="px-4 py-3 hidden md:table-cell text-slate-500 text-xs max-w-xs truncate" x-text="r.descripcion"></td>
<td class="px-4 py-3 hidden md:table-cell text-slate-500 text-xs max-w-xs truncate">
<template x-if="editR?.ID === r.ID">
<div class="space-y-1">
<div x-text="r.descripcion" class="truncate"></div>
<input x-model="editR.enlace" type="url" placeholder="Enlace externo..." class="input-f text-xs w-full">
</div>
</template>
<template x-if="editR?.ID !== r.ID">
<div class="space-y-0.5">
<span x-text="r.descripcion"></span>
<template x-if="r.enlace">
<a :href="r.enlace" target="_blank" class="block text-[#8eb02f] hover:underline text-xs truncate" x-text="r.enlace"></a>
</template>
</div>
</template>
</td>
<!-- Archivo -->
<td class="px-4 py-3 text-center">
<template x-if="r.archivo">
@@ -243,7 +259,7 @@ function partnerRecursos() {
tab: 'recursos',
recursos: [],
comunicados: [],
newR: { nombre:'', descripcion:'', categoria:'general', activo:true },
newR: { nombre:'', descripcion:'', categoria:'general', enlace:'', activo:true },
newC: { titulo:'', contenido:'', activo:true },
editR: null,
editC: null,
@@ -267,7 +283,7 @@ function partnerRecursos() {
try {
const r = await axios.post('/app/partner-recursos', this.newR);
this.recursos.unshift(r.data);
this.newR = { nombre:'', descripcion:'', categoria:'general', activo:true };
this.newR = { nombre:'', descripcion:'', categoria:'general', enlace:'', activo:true };
} catch(e) { alert(e.response?.data?.error || 'Error al crear'); }
},
+8 -1
View File
@@ -162,7 +162,14 @@
Descargar
</a>
</template>
<template x-if="!r.archivo">
<template x-if="r.enlace">
<a :href="r.enlace" target="_blank" rel="noopener noreferrer"
class="inline-flex items-center gap-2 text-xs font-medium text-[#8eb02f] border border-[#8eb02f] hover:bg-[#f0f6e4] px-3 py-1.5 rounded-lg transition-colors">
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"/></svg>
Ver enlace
</a>
</template>
<template x-if="!r.archivo && !r.enlace">
<span class="text-xs text-slate-400 italic">Sin archivo adjunto</span>
</template>
</div>
@@ -35,6 +35,7 @@ func CreatePartnerRecurso(c *fiber.Ctx) error {
Nombre string `json:"nombre"`
Descripcion string `json:"descripcion"`
Categoria string `json:"categoria"`
Enlace string `json:"enlace"`
Activo bool `json:"activo"`
}
var req Req
@@ -45,6 +46,7 @@ func CreatePartnerRecurso(c *fiber.Ctx) error {
Nombre: req.Nombre,
Descripcion: req.Descripcion,
Categoria: req.Categoria,
Enlace: req.Enlace,
Activo: req.Activo,
}
if err := models.CreatePartnerRecurso(r); err != nil {
@@ -59,6 +61,7 @@ func UpdatePartnerRecurso(c *fiber.Ctx) error {
Nombre string `json:"nombre"`
Descripcion string `json:"descripcion"`
Categoria string `json:"categoria"`
Enlace string `json:"enlace"`
Activo bool `json:"activo"`
}
var req Req
@@ -72,6 +75,7 @@ func UpdatePartnerRecurso(c *fiber.Ctx) error {
r.Nombre = req.Nombre
r.Descripcion = req.Descripcion
r.Categoria = req.Categoria
r.Enlace = req.Enlace
r.Activo = req.Activo
if err := models.UpdatePartnerRecurso(r); err != nil {
return c.Status(500).JSON(fiber.Map{"error": err.Error()})