up
This commit is contained in:
@@ -210,6 +210,12 @@
|
||||
class="w-full border border-slate-200 rounded-lg px-3 py-2 text-sm focus:outline-none focus:border-[#8eb02f] focus:ring-2 focus:ring-[#8eb02f]/20">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-slate-500 uppercase tracking-wide mb-1">Ciudad</label>
|
||||
<input x-model="perfil.ciudad" type="text" placeholder="Ej: Bogotá"
|
||||
class="w-full border border-slate-200 rounded-lg px-3 py-2 text-sm focus:outline-none focus:border-[#8eb02f] focus:ring-2 focus:ring-[#8eb02f]/20">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-slate-500 uppercase tracking-wide mb-1">RUT / Documento legal</label>
|
||||
<input x-model="perfil.documento" type="text" placeholder="Ej: NIT, RUT, CC, CUIT..."
|
||||
@@ -408,7 +414,7 @@ function miCuenta() {
|
||||
open: false,
|
||||
tab: 'perfil',
|
||||
saving: false,
|
||||
perfil: { nombre:'', email:'', telefono:'', indicativo:'', pais:'', documento:'', empresa:'', sitio_web:'', documento_rut_file:'', documento_rut_nombre:'' },
|
||||
perfil: { nombre:'', email:'', telefono:'', indicativo:'', pais:'', ciudad:'', documento:'', empresa:'', sitio_web:'', documento_rut_file:'', documento_rut_nombre:'' },
|
||||
perfilMsg: '', perfilOk: false,
|
||||
pass: { actual:'', nueva:'', confirma:'' },
|
||||
passMsg: '', passOk: false,
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
<!-- Tabs -->
|
||||
<div class="flex border-b border-slate-200 mb-6 gap-0 overflow-x-auto">
|
||||
<template x-for="tab in ['Roadmap','Avances','Entregables','Tickets','Facturas']" :key="tab">
|
||||
<template x-for="tab in ['Roadmap','Avances','Entregables','Documentos','Tickets','Facturas']" :key="tab">
|
||||
<button @click="activeTab=tab; if(tab==='Tickets') marcarTicketsPendientesLeidos(); if(tab==='Facturas') marcarFacturasLeidas()" class="relative px-4 py-2 text-sm whitespace-nowrap border-b-2 -mb-px transition-colors"
|
||||
:class="activeTab===tab ? 'font-semibold border-[#8eb02f] text-[#8eb02f]' : 'border-transparent text-slate-500 hover:text-slate-700'">
|
||||
<span x-text="tab"></span>
|
||||
@@ -142,6 +142,41 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ─── DOCUMENTOS ─────────────────────────────────────────────────────────── -->
|
||||
<div x-show="activeTab==='Documentos'" x-cloak>
|
||||
<div class="space-y-3">
|
||||
<template x-if="documentos.length === 0">
|
||||
<p class="text-slate-400 text-sm text-center py-10">Sin documentos disponibles.</p>
|
||||
</template>
|
||||
<template x-for="d in documentos" :key="d.ID">
|
||||
<div class="bg-white rounded-xl border border-slate-200 p-4 flex items-center gap-4">
|
||||
<!-- Icono por tipo -->
|
||||
<div class="w-10 h-10 rounded-xl flex items-center justify-center flex-shrink-0"
|
||||
:class="d.tipo==='contrato' ? 'bg-blue-50' : d.tipo==='orden_servicio' ? 'bg-amber-50' : 'bg-slate-100'">
|
||||
<svg x-show="d.tipo==='contrato'" class="w-5 h-5 text-blue-500" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/></svg>
|
||||
<svg x-show="d.tipo==='orden_servicio'" class="w-5 h-5 text-amber-500" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"/></svg>
|
||||
<svg x-show="d.tipo!=='contrato' && d.tipo!=='orden_servicio'" class="w-5 h-5 text-slate-400" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13"/></svg>
|
||||
</div>
|
||||
<!-- Info -->
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="font-semibold text-sm text-slate-800 truncate" x-text="d.nombre"></p>
|
||||
<div class="flex items-center gap-2 mt-0.5">
|
||||
<span class="text-xs px-2 py-0.5 rounded-full font-medium capitalize"
|
||||
:class="d.tipo==='contrato' ? 'bg-blue-100 text-blue-700' : d.tipo==='orden_servicio' ? 'bg-amber-100 text-amber-700' : 'bg-slate-100 text-slate-500'"
|
||||
x-text="d.tipo?.replace('_',' ')"></span>
|
||||
<span x-show="d.descripcion" class="text-xs text-slate-400 truncate" x-text="d.descripcion"></span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Descarga -->
|
||||
<a :href="`/portal/documentos/${d.ID}/download`"
|
||||
class="flex-shrink-0 text-[#8eb02f] hover:text-[#6d8c24]" title="Descargar">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/></svg>
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ─── TICKETS ───────────────────────────────────────────────────────────── -->
|
||||
<div x-show="activeTab==='Tickets'" x-cloak>
|
||||
<!-- Crear ticket -->
|
||||
@@ -259,6 +294,7 @@ function portalProyecto() {
|
||||
ticketForm: { titulo:'', descripcion:'', prioridad:'media' },
|
||||
facturas: [],
|
||||
facturasNoLeidas: 0,
|
||||
documentos: [],
|
||||
|
||||
async init() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
@@ -299,6 +335,7 @@ function portalProyecto() {
|
||||
...f,
|
||||
_nuevo: this.facturasNoLeidas > 0,
|
||||
}));
|
||||
this.documentos = r.data.documentos || [];
|
||||
} catch(e){} finally { this.loadingTickets=false; }
|
||||
},
|
||||
|
||||
|
||||
@@ -111,6 +111,32 @@
|
||||
<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><label class="label">Sitio Web</label><input x-model="form.sitio_web" class="input-field w-full" type="url" placeholder="https://ejemplo.com"><p class="text-xs text-slate-400 mt-1">Sitio web del partner o cliente.</p></div>
|
||||
<!-- Contacto -->
|
||||
<div>
|
||||
<label class="label">Teléfono</label>
|
||||
<div class="flex gap-2">
|
||||
<select x-model="form.indicativo" class="input-field w-28">
|
||||
<option value="">Indicativo</option>
|
||||
<option value="+57">🇨🇴 +57</option>
|
||||
<option value="+1">🇺🇸 +1</option>
|
||||
<option value="+52">🇲🇽 +52</option>
|
||||
<option value="+54">🇦🇷 +54</option>
|
||||
<option value="+56">🇨🇱 +56</option>
|
||||
<option value="+51">🇵🇪 +51</option>
|
||||
<option value="+58">🇻🇪 +58</option>
|
||||
<option value="+593">🇪🇨 +593</option>
|
||||
<option value="+34">🇪🇸 +34</option>
|
||||
<option value="+55">🇧🇷 +55</option>
|
||||
<option value="+44">🇬🇧 +44</option>
|
||||
<option value="+1-other">Otro +1</option>
|
||||
</select>
|
||||
<input x-model="form.telefono" type="tel" class="input-field flex-1" placeholder="Número de teléfono">
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<div><label class="label">País</label><input x-model="form.pais" class="input-field w-full" placeholder="Ej: Colombia"></div>
|
||||
<div><label class="label">Ciudad</label><input x-model="form.ciudad" class="input-field w-full" placeholder="Ej: Bogotá"></div>
|
||||
</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">
|
||||
@@ -241,6 +267,11 @@
|
||||
<p class="text-sm" :class="detailUser?.pais ? 'text-slate-700' : 'text-slate-300'"
|
||||
x-text="detailUser?.pais || '—'"></p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="label">Ciudad</p>
|
||||
<p class="text-sm" :class="detailUser?.ciudad ? 'text-slate-700' : 'text-slate-300'"
|
||||
x-text="detailUser?.ciudad || '—'"></p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="label">Sitio Web</p>
|
||||
<template x-if="detailUser?.sitio_web">
|
||||
@@ -353,7 +384,7 @@ function portalUsuariosApp() {
|
||||
editId: null, deleteId: null, error: '',
|
||||
accesoUserId: null, accesoClienteId: '',
|
||||
showCredModal: false, credUserId: null, credNombre: '', credEmail: '', credPassword: '', credSending: false, credMsg: '', credOk: false,
|
||||
form: { nombre:'', email:'', password:'', rol:'cliente', cliente_id:'', activo:true, notas:'', telegram_chat_id:'', sitio_web:'' },
|
||||
form: { nombre:'', email:'', password:'', rol:'cliente', cliente_id:'', activo:true, notas:'', telegram_chat_id:'', sitio_web:'', telefono:'', indicativo:'', pais:'', ciudad:'' },
|
||||
|
||||
async init() { await this.load(); },
|
||||
|
||||
@@ -382,12 +413,12 @@ function portalUsuariosApp() {
|
||||
|
||||
openCreate() {
|
||||
this.editId=null; this.error='';
|
||||
this.form={nombre:'',email:'',password:'',rol:'cliente',cliente_id:'',activo:true,notas:'',telegram_chat_id:'',sitio_web:''};
|
||||
this.form={nombre:'',email:'',password:'',rol:'cliente',cliente_id:'',activo:true,notas:'',telegram_chat_id:'',sitio_web:'',telefono:'',indicativo:'',pais:'',ciudad:''};
|
||||
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||'',telegram_chat_id:u.telegram_chat_id||'',sitio_web:u.sitio_web||''};
|
||||
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||'',sitio_web:u.sitio_web||'',telefono:u.telefono||'',indicativo:u.indicativo||'',pais:u.pais||'',ciudad:u.ciudad||''};
|
||||
this.showModal=true;
|
||||
},
|
||||
async save() {
|
||||
|
||||
Reference in New Issue
Block a user