All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m5s
- Agregar endpoint oldest.get.ts para obtener mensaje mas antiguo de un chat - Agregar boton 'Cargar historial de WhatsApp' en vista de mensajes - Mejorar HistorySection.vue con selector de chats y auto-deteccion
231 lines
6.7 KiB
Vue
231 lines
6.7 KiB
Vue
<template>
|
|
<div class="space-y-6 p-4">
|
|
<!-- Fetch Message History -->
|
|
<div class="space-y-4">
|
|
<h3 class="text-lg font-medium text-[var(--wa-text)]">Solicitar Historial de Mensajes</h3>
|
|
<p class="text-sm text-[var(--wa-text-muted)]">
|
|
Solicita mensajes adicionales del historial de WhatsApp. Los mensajes se guardaran en la base de datos.
|
|
</p>
|
|
|
|
<!-- Chat Selector -->
|
|
<div class="space-y-2">
|
|
<label class="text-sm text-[var(--wa-text-muted)]">Seleccionar Chat</label>
|
|
<USelectMenu
|
|
v-model="selectedChat"
|
|
:items="chatOptions"
|
|
placeholder="Seleccionar chat..."
|
|
searchable
|
|
:loading="loadingChats"
|
|
class="w-full"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Selected Chat Info -->
|
|
<div v-if="selectedChat && oldestMessage" class="p-3 rounded bg-[var(--wa-bg-hover)] space-y-1">
|
|
<p class="text-sm text-[var(--wa-text)]">
|
|
<span class="text-[var(--wa-text-muted)]">Chat:</span> {{ selectedChat.label }}
|
|
</p>
|
|
<p class="text-sm text-[var(--wa-text)]">
|
|
<span class="text-[var(--wa-text-muted)]">Mensaje mas antiguo:</span>
|
|
{{ formatDate(oldestMessage.timestamp) }}
|
|
</p>
|
|
</div>
|
|
|
|
<div v-else-if="selectedChat && !loadingOldest" class="p-3 rounded bg-yellow-900/20 text-yellow-400 text-sm">
|
|
Este chat no tiene mensajes guardados en la base de datos.
|
|
</div>
|
|
|
|
<!-- Count Input -->
|
|
<div class="space-y-2">
|
|
<label class="text-sm text-[var(--wa-text-muted)]">Cantidad de mensajes a solicitar</label>
|
|
<UInput
|
|
v-model.number="count"
|
|
type="number"
|
|
placeholder="Cantidad de mensajes"
|
|
:min="1"
|
|
:max="1000"
|
|
class="w-48"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Action Button -->
|
|
<UButton
|
|
:loading="loading"
|
|
:disabled="!instanceId || !count"
|
|
@click="fetchHistory"
|
|
color="primary"
|
|
>
|
|
Solicitar {{ count }} mensajes del historial
|
|
</UButton>
|
|
|
|
<!-- Advanced Mode Toggle -->
|
|
<div class="pt-4 border-t border-[var(--wa-border)]">
|
|
<UCheckbox v-model="showAdvanced" label="Modo avanzado (JSON manual)" />
|
|
</div>
|
|
|
|
<!-- Advanced Mode Fields -->
|
|
<div v-if="showAdvanced" class="space-y-4 p-4 rounded bg-[var(--wa-bg-hover)]">
|
|
<p class="text-xs text-[var(--wa-text-muted)]">
|
|
Estos campos permiten especificar manualmente el mensaje de referencia para la sincronizacion.
|
|
</p>
|
|
<div class="grid grid-cols-2 gap-4">
|
|
<UInput
|
|
v-model.number="manualTimestamp"
|
|
type="number"
|
|
placeholder="Timestamp (segundos)"
|
|
/>
|
|
</div>
|
|
<div class="space-y-2">
|
|
<label class="text-sm text-[var(--wa-text-muted)]">Message Key (JSON):</label>
|
|
<UTextarea
|
|
v-model="oldestMsgKeyJson"
|
|
placeholder='{"remoteJid": "...", "id": "...", "fromMe": false}'
|
|
:rows="3"
|
|
class="font-mono text-sm"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
interface Chat {
|
|
id: string
|
|
jid: string
|
|
name: string
|
|
isGroup: boolean
|
|
}
|
|
|
|
interface OldestMessage {
|
|
hasMessages: boolean
|
|
messageKey: { remoteJid: string; id: string; fromMe: boolean } | null
|
|
timestamp: number | null
|
|
}
|
|
|
|
const props = defineProps<{
|
|
instanceId: string | null
|
|
}>()
|
|
|
|
const emit = defineEmits<{
|
|
(e: 'response', data: any): void
|
|
}>()
|
|
|
|
const count = ref<number>(100)
|
|
const loading = ref(false)
|
|
const showAdvanced = ref(false)
|
|
const oldestMsgKeyJson = ref('')
|
|
const manualTimestamp = ref<number | null>(null)
|
|
|
|
// Chat selection
|
|
const chats = ref<Chat[]>([])
|
|
const selectedChat = ref<{ label: string; value: string; jid: string } | null>(null)
|
|
const loadingChats = ref(false)
|
|
const oldestMessage = ref<OldestMessage | null>(null)
|
|
const loadingOldest = ref(false)
|
|
|
|
// Computed chat options for select menu
|
|
const chatOptions = computed(() =>
|
|
chats.value.map(chat => ({
|
|
label: chat.name || chat.jid.split('@')[0],
|
|
value: chat.id,
|
|
jid: chat.jid
|
|
}))
|
|
)
|
|
|
|
// Load chats when instanceId changes
|
|
watch(() => props.instanceId, async (instanceId) => {
|
|
if (!instanceId) {
|
|
chats.value = []
|
|
selectedChat.value = null
|
|
return
|
|
}
|
|
|
|
loadingChats.value = true
|
|
try {
|
|
chats.value = await $fetch<Chat[]>(`/api/messages/${instanceId}/chats`)
|
|
} catch (e) {
|
|
console.error('Error loading chats:', e)
|
|
chats.value = []
|
|
} finally {
|
|
loadingChats.value = false
|
|
}
|
|
}, { immediate: true })
|
|
|
|
// Load oldest message when chat is selected
|
|
watch(selectedChat, async (chat) => {
|
|
if (!chat || !props.instanceId) {
|
|
oldestMessage.value = null
|
|
return
|
|
}
|
|
|
|
loadingOldest.value = true
|
|
try {
|
|
oldestMessage.value = await $fetch<OldestMessage>(
|
|
`/api/messages/${props.instanceId}/${chat.value}/oldest`
|
|
)
|
|
|
|
// Auto-populate JSON field if not in advanced mode
|
|
if (oldestMessage.value?.hasMessages && oldestMessage.value.messageKey) {
|
|
oldestMsgKeyJson.value = JSON.stringify(oldestMessage.value.messageKey, null, 2)
|
|
manualTimestamp.value = oldestMessage.value.timestamp
|
|
} else {
|
|
oldestMsgKeyJson.value = ''
|
|
manualTimestamp.value = null
|
|
}
|
|
} catch (e) {
|
|
console.error('Error loading oldest message:', e)
|
|
oldestMessage.value = null
|
|
} finally {
|
|
loadingOldest.value = false
|
|
}
|
|
})
|
|
|
|
// Format timestamp to readable date
|
|
const formatDate = (timestamp: number | null) => {
|
|
if (!timestamp) return 'N/A'
|
|
return new Date(timestamp * 1000).toLocaleString()
|
|
}
|
|
|
|
const fetchHistory = async () => {
|
|
loading.value = true
|
|
try {
|
|
let oldestMsgKey = undefined
|
|
let oldestMsgTimestamp = undefined
|
|
|
|
if (showAdvanced.value) {
|
|
// Use manual JSON input
|
|
if (oldestMsgKeyJson.value.trim()) {
|
|
try {
|
|
oldestMsgKey = JSON.parse(oldestMsgKeyJson.value)
|
|
} catch {
|
|
emit('response', { success: false, error: 'Invalid JSON for oldestMsgKey' })
|
|
loading.value = false
|
|
return
|
|
}
|
|
}
|
|
oldestMsgTimestamp = manualTimestamp.value || undefined
|
|
} else if (oldestMessage.value?.hasMessages) {
|
|
// Use auto-detected oldest message
|
|
oldestMsgKey = oldestMessage.value.messageKey
|
|
oldestMsgTimestamp = oldestMessage.value.timestamp
|
|
}
|
|
|
|
const result = await $fetch('/api/debug/history/fetch', {
|
|
method: 'POST',
|
|
body: {
|
|
instanceId: props.instanceId,
|
|
count: count.value,
|
|
oldestMsgKey,
|
|
oldestMsgTimestamp
|
|
}
|
|
})
|
|
emit('response', result)
|
|
} catch (error: any) {
|
|
emit('response', { success: false, error: error.data?.message || error.message })
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
</script>
|