up
This commit is contained in:
@@ -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"`
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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'); }
|
||||
},
|
||||
|
||||
|
||||
@@ -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()})
|
||||
|
||||
Reference in New Issue
Block a user