This commit is contained in:
Lizandro Guarnizo
2026-05-16 15:06:05 -05:00
parent fef471ff6c
commit 9820405475
3 changed files with 50 additions and 38 deletions
+11 -9
View File
@@ -20,9 +20,10 @@ type PortalUser struct {
ClienteID *uint `json:"cliente_id" gorm:"column:cliente_id;index"` // nil si es partner
Cliente *Cliente `json:"cliente" gorm:"foreignKey:ClienteID"`
Rol string `json:"rol" gorm:"column:rol;default:'cliente'"` // cliente|partner
Activo bool `json:"activo" gorm:"column:activo;default:true"`
Notas string `json:"notas" gorm:"column:notas;type:text"`
PortalAccesos []PortalAcceso `json:"portal_accesos" gorm:"foreignKey:PortalUserID"`
Activo bool `json:"activo" gorm:"column:activo;default:true"`
Notas string `json:"notas" gorm:"column:notas;type:text"`
TelegramChatID string `json:"telegram_chat_id" gorm:"column:telegram_chat_id"`
PortalAccesos []PortalAcceso `json:"portal_accesos" gorm:"foreignKey:PortalUserID"`
}
func (PortalUser) TableName() string { return "portal_users" }
@@ -71,12 +72,13 @@ func CreatePortalUser(u *PortalUser) error {
func UpdatePortalUser(u *PortalUser) error {
return app.Http.Database.DB.Model(&PortalUser{}).Where("id = ?", u.ID).Updates(map[string]interface{}{
"nombre": u.Nombre,
"email": u.Email,
"cliente_id": u.ClienteID,
"rol": u.Rol,
"activo": u.Activo,
"notas": u.Notas,
"nombre": u.Nombre,
"email": u.Email,
"cliente_id": u.ClienteID,
"rol": u.Rol,
"activo": u.Activo,
"notas": u.Notas,
"telegram_chat_id": u.TelegramChatID,
}).Error
}
+9 -3
View File
@@ -21,6 +21,7 @@
<th class="px-4 py-3 text-left">Rol</th>
<th class="px-4 py-3 text-left">Cliente / Accesos</th>
<th class="px-4 py-3 text-left">Estado</th>
<th class="px-4 py-3 text-left">Telegram</th>
<th class="px-4 py-3 text-left">Acciones</th>
</tr>
</thead>
@@ -54,6 +55,10 @@
<td class="px-4 py-3">
<span :class="u.activo ? 'badge-green' : 'badge-slate'" class="badge" x-text="u.activo ? 'Activo' : 'Inactivo'"></span>
</td>
<td class="px-4 py-3 text-slate-500 text-xs">
<span x-show="u.telegram_chat_id" x-text="u.telegram_chat_id" class="font-mono"></span>
<span x-show="!u.telegram_chat_id" class="text-slate-300"></span>
</td>
<td class="px-4 py-3 flex gap-2">
<button @click="openEdit(u)" class="btn-icon text-yellow-500" title="Editar">
<svg class="w-4 h-4" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/></svg>
@@ -101,6 +106,7 @@
<input type="checkbox" x-model="form.activo" class="w-4 h-4">
</div>
<div><label class="label">Notas</label><textarea x-model="form.notas" class="input-field w-full" rows="2"></textarea></div>
<div><label class="label">Chat ID de Telegram</label><input x-model="form.telegram_chat_id" class="input-field w-full font-mono" placeholder="Ej: 123456789"><p class="text-xs text-slate-400 mt-1">Se usa para enviar notificaciones al usuario vía Telegram.</p></div>
</div>
<p x-show="error" x-text="error" class="text-red-500 text-sm mt-3"></p>
<div class="flex justify-end gap-3 mt-5">
@@ -150,7 +156,7 @@ function portalUsuariosApp() {
showModal: false, showDelete: false, showAccesoModal: false,
editId: null, deleteId: null, error: '',
accesoUserId: null, accesoClienteId: '',
form: { nombre:'', email:'', password:'', rol:'cliente', cliente_id:'', activo:true, notas:'' },
form: { nombre:'', email:'', password:'', rol:'cliente', cliente_id:'', activo:true, notas:'', telegram_chat_id:'' },
async init() { await this.load(); },
@@ -165,12 +171,12 @@ function portalUsuariosApp() {
openCreate() {
this.editId=null; this.error='';
this.form={nombre:'',email:'',password:'',rol:'cliente',cliente_id:'',activo:true,notas:''};
this.form={nombre:'',email:'',password:'',rol:'cliente',cliente_id:'',activo:true,notas:'',telegram_chat_id:''};
this.showModal=true;
},
openEdit(u) {
this.editId=u.ID; this.error='';
this.form={nombre:u.nombre,email:u.email,password:'',rol:u.rol,cliente_id:u.cliente_id||'',activo:u.activo,notas:u.notas||''};
this.form={nombre:u.nombre,email:u.email,password:'',rol:u.rol,cliente_id:u.cliente_id||'',activo:u.activo,notas:u.notas||'',telegram_chat_id:u.telegram_chat_id||''};
this.showModal=true;
},
async save() {
+30 -26
View File
@@ -40,12 +40,13 @@ func LoadPortalUsuarios(c *fiber.Ctx) error {
func CreatePortalUsuario(c *fiber.Ctx) error {
type Req struct {
Nombre string `json:"nombre"`
Email string `json:"email"`
Password string `json:"password"`
ClienteID *uint `json:"cliente_id"`
Rol string `json:"rol"`
Notas string `json:"notas"`
Nombre string `json:"nombre"`
Email string `json:"email"`
Password string `json:"password"`
ClienteID *uint `json:"cliente_id"`
Rol string `json:"rol"`
Notas string `json:"notas"`
TelegramChatID string `json:"telegram_chat_id"`
}
var req Req
if err := c.BodyParser(&req); err != nil {
@@ -62,13 +63,14 @@ func CreatePortalUsuario(c *fiber.Ctx) error {
req.Rol = "cliente"
}
u := &models.PortalUser{
Nombre: req.Nombre,
Email: strings.ToLower(strings.TrimSpace(req.Email)),
Password: hashed,
ClienteID: req.ClienteID,
Rol: req.Rol,
Activo: true,
Notas: req.Notas,
Nombre: req.Nombre,
Email: strings.ToLower(strings.TrimSpace(req.Email)),
Password: hashed,
ClienteID: req.ClienteID,
Rol: req.Rol,
Activo: true,
Notas: req.Notas,
TelegramChatID: req.TelegramChatID,
}
if err := models.CreatePortalUser(u); err != nil {
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
@@ -83,25 +85,27 @@ func UpdatePortalUsuario(c *fiber.Ctx) error {
return c.Status(400).JSON(fiber.Map{"error": "ID inválido"})
}
type Req struct {
Nombre string `json:"nombre"`
Email string `json:"email"`
Password string `json:"password"`
ClienteID *uint `json:"cliente_id"`
Rol string `json:"rol"`
Activo bool `json:"activo"`
Notas string `json:"notas"`
Nombre string `json:"nombre"`
Email string `json:"email"`
Password string `json:"password"`
ClienteID *uint `json:"cliente_id"`
Rol string `json:"rol"`
Activo bool `json:"activo"`
Notas string `json:"notas"`
TelegramChatID string `json:"telegram_chat_id"`
}
var req Req
if err := c.BodyParser(&req); err != nil {
return c.Status(400).JSON(fiber.Map{"error": err.Error()})
}
u := &models.PortalUser{
Nombre: req.Nombre,
Email: strings.ToLower(strings.TrimSpace(req.Email)),
ClienteID: req.ClienteID,
Rol: req.Rol,
Activo: req.Activo,
Notas: req.Notas,
Nombre: req.Nombre,
Email: strings.ToLower(strings.TrimSpace(req.Email)),
ClienteID: req.ClienteID,
Rol: req.Rol,
Activo: req.Activo,
Notas: req.Notas,
TelegramChatID: req.TelegramChatID,
}
u.ID = uint(id)
if err := models.UpdatePortalUser(u); err != nil {