190 lines
8.8 KiB
HTML
190 lines
8.8 KiB
HTML
<div x-data="websmsApp()" x-init="init()" class="p-6">
|
|
|
|
<div class="flex items-center justify-between mb-6">
|
|
<div>
|
|
<h1 class="text-2xl font-bold text-slate-800">WebSMS (LabsMobile)</h1>
|
|
<p class="text-sm text-slate-500 mt-1">Integración de SMS para notificaciones</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Configuración -->
|
|
<div class="bg-white rounded-xl shadow-sm border border-slate-200 p-6 mb-6">
|
|
<h2 class="text-lg font-bold text-slate-800 mb-4">Configuración API</h2>
|
|
<form @submit.prevent="save()">
|
|
<div class="grid grid-cols-2 gap-4">
|
|
<div class="col-span-2">
|
|
<label class="label">Usuario (email)</label>
|
|
<input x-model="form.username" class="input-field w-full" required placeholder="lizandro.guarnizo@u-site.app">
|
|
</div>
|
|
<div class="col-span-2">
|
|
<label class="label">API Token</label>
|
|
<div class="relative">
|
|
<input x-model="form.api_token" type="password" class="input-field w-full pr-10" required>
|
|
<button type="button" @click="showToken=!showToken; $el.previousElementSibling.type=showToken?'text':'password'" class="absolute right-2 top-1/2 -translate-y-1/2 text-slate-400 hover:text-slate-600">
|
|
<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="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/><path stroke-linecap="round" stroke-linejoin="round" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/></svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label class="label">Remitente (TPOA)</label>
|
|
<input x-model="form.sender" class="input-field w-full" placeholder="U-SITE">
|
|
</div>
|
|
<div>
|
|
<label class="label">Notas</label>
|
|
<input x-model="form.notas" class="input-field w-full" placeholder="Opcional">
|
|
</div>
|
|
</div>
|
|
<p x-show="error" x-text="error" class="text-red-500 text-sm mt-3"></p>
|
|
<div class="flex justify-end mt-5">
|
|
<button type="submit" :disabled="saving" class="btn-primary" x-text="saving?'Guardando...':'Guardar configuración'"></button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Probar envío -->
|
|
<div class="bg-white rounded-xl shadow-sm border border-slate-200 p-6 mb-6">
|
|
<h2 class="text-lg font-bold text-slate-800 mb-4">Probar envío</h2>
|
|
<form @submit.prevent="test()">
|
|
<div class="grid grid-cols-2 gap-4">
|
|
<div>
|
|
<label class="label">Número destino</label>
|
|
<input x-model="testPara" class="input-field w-full" placeholder="57300xxxxxx" required>
|
|
</div>
|
|
<div>
|
|
<label class="label">Mensaje (opcional)</label>
|
|
<input x-model="testMsg" class="input-field w-full" placeholder="Texto de prueba">
|
|
</div>
|
|
</div>
|
|
<p x-show="testResult" x-text="testResult" class="text-sm mt-3" :class="testOk?'text-green-600':'text-red-500'"></p>
|
|
<div class="flex justify-end mt-4">
|
|
<button type="submit" :disabled="saving" class="btn-primary" x-text="saving?'Enviando...':'Enviar SMS de prueba'"></button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Webhooks URLs -->
|
|
<div class="bg-white rounded-xl shadow-sm border border-slate-200 p-6 mb-6">
|
|
<h2 class="text-lg font-bold text-slate-800 mb-4">Webhooks</h2>
|
|
<p class="text-sm text-slate-500 mb-4">Configura estas URLs en el panel de WebSMS para recibir notificaciones:</p>
|
|
<div class="space-y-3">
|
|
<div>
|
|
<label class="label">Confirmaciones de entrega (ACK)</label>
|
|
<code class="block text-xs bg-slate-50 p-2 rounded border border-slate-200 text-slate-700 break-all">https://admin.u-site.app/webhooks/websms/delivery</code>
|
|
</div>
|
|
<div>
|
|
<label class="label">Clics en shortlinks</label>
|
|
<code class="block text-xs bg-slate-50 p-2 rounded border border-slate-200 text-slate-700 break-all">https://admin.u-site.app/webhooks/websms/click</code>
|
|
</div>
|
|
<div>
|
|
<label class="label">Mensajes entrantes</label>
|
|
<code class="block text-xs bg-slate-50 p-2 rounded border border-slate-200 text-slate-700 break-all">https://admin.u-site.app/webhooks/websms/incoming</code>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Logs -->
|
|
<div class="bg-white rounded-xl shadow-sm border border-slate-200 p-6">
|
|
<h2 class="text-lg font-bold text-slate-800 mb-4">Últimos envíos</h2>
|
|
<div class="overflow-x-auto">
|
|
<table class="w-full text-sm">
|
|
<thead class="bg-slate-50 text-slate-500 text-xs uppercase tracking-wide">
|
|
<tr>
|
|
<th class="px-3 py-2 text-left">Fecha</th>
|
|
<th class="px-3 py-2 text-left">Para</th>
|
|
<th class="px-3 py-2 text-left">Mensaje</th>
|
|
<th class="px-3 py-2 text-left">Estado</th>
|
|
<th class="px-3 py-2 text-left">ID</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-slate-100">
|
|
<template x-for="l in logs" :key="l.ID">
|
|
<tr class="hover:bg-slate-50">
|
|
<td class="px-3 py-2 text-xs text-slate-500" x-text="formatDate(l.CreatedAt)"></td>
|
|
<td class="px-3 py-2 text-slate-700" x-text="l.para"></td>
|
|
<td class="px-3 py-2 text-slate-600 max-w-xs truncate" x-text="l.mensaje"></td>
|
|
<td class="px-3 py-2">
|
|
<span class="badge" :class="l.status==='0'?'badge-green':'badge-red'" x-text="l.status"></span>
|
|
</td>
|
|
<td class="px-3 py-2 text-xs font-mono text-slate-500" x-text="l.msg_id||'-'"></td>
|
|
</tr>
|
|
</template>
|
|
<template x-if="!logs.length">
|
|
<tr><td colspan="5" class="text-center py-6 text-slate-400">Sin envíos aún</td></tr>
|
|
</template>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<script>
|
|
function websmsApp() {
|
|
return {
|
|
form:{ username:'', api_token:'', sender:'', notas:'' },
|
|
showToken:false,
|
|
logs:[],
|
|
testPara:'', testMsg:'', testResult:'', testOk:false,
|
|
saving:false, error:'',
|
|
|
|
async init(){
|
|
await this.loadConfig();
|
|
await this.loadLogs();
|
|
},
|
|
|
|
async loadConfig(){
|
|
try {
|
|
const r=await axios.get('/app/websms/config');
|
|
if(r.data.data){
|
|
this.form={id:r.data.data.ID, username:r.data.data.username, api_token:r.data.data.api_token, sender:r.data.data.sender||'', notas:r.data.data.notas||''};
|
|
}
|
|
} catch(e){}
|
|
},
|
|
|
|
async loadLogs(){
|
|
try { const r=await axios.get('/app/websms/logs'); this.logs=r.data; } catch(e){}
|
|
},
|
|
|
|
async save(){
|
|
this.saving=true; this.error='';
|
|
try {
|
|
await axios.post('/app/websms/save', this.form);
|
|
await this.loadConfig();
|
|
} catch(e){ this.error=e.response?.data?.error||'Error al guardar'; }
|
|
finally{ this.saving=false; }
|
|
},
|
|
|
|
async test(){
|
|
this.saving=true; this.testResult=''; this.testOk=false;
|
|
try {
|
|
const r=await axios.post('/app/websms/test', {para:this.testPara, mensaje:this.testMsg});
|
|
this.testResult='SMS enviado correctamente. Código: '+r.data.response.code;
|
|
this.testOk=true;
|
|
await this.loadLogs();
|
|
} catch(e){ this.testResult=e.response?.data?.error||'Error al enviar'; this.testOk=false; }
|
|
finally{ this.saving=false; }
|
|
},
|
|
|
|
formatDate(d){ if(!d) return ''; return new Date(d).toLocaleDateString('es-CO',{day:'2-digit',month:'short',year:'numeric',hour:'2-digit',minute:'2-digit'}); },
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.btn-primary { background:#8eb02f; color:#fff; padding:0.5rem 1rem; border-radius:0.5rem; font-weight:600; font-size:.875rem; transition:background .15s; }
|
|
.btn-primary:hover { background:#6d8c24; }
|
|
.btn-secondary { background:#f1f5f9; color:#475569; padding:0.5rem 1rem; border-radius:0.5rem; font-weight:500; font-size:.875rem; border:1px solid #e2e8f0; }
|
|
.btn-danger { background:#ef4444; color:#fff; padding:0.5rem 1rem; border-radius:0.5rem; font-weight:600; font-size:.875rem; }
|
|
.btn-icon { display:inline-flex; align-items:center; padding:0.25rem; border-radius:0.375rem; }
|
|
.btn-icon:hover { background:#f1f5f9; }
|
|
.input-field { border:1px solid #e2e8f0; border-radius:0.5rem; padding:0.5rem 0.75rem; font-size:.875rem; outline:none; transition:border-color .15s; }
|
|
.input-field:focus { border-color:#8eb02f; }
|
|
.label { display:block; font-size:.75rem; font-weight:600; color:#475569; margin-bottom:.25rem; text-transform:uppercase; letter-spacing:.05em; }
|
|
.badge { display:inline-block; padding:.15rem .6rem; border-radius:9999px; font-size:.7rem; font-weight:600; text-transform:capitalize; }
|
|
.badge-green { background:#dcfce7; color:#15803d; }
|
|
.badge-yellow { background:#fef9c3; color:#854d0e; }
|
|
.badge-slate { background:#f1f5f9; color:#475569; }
|
|
.badge-red { background:#fee2e2; color:#991b1b; }
|
|
.badge-blue { background:#dbeafe; color:#1d4ed8; }
|
|
</style>
|