feat: handle loading states

This commit is contained in:
AnotiaWang
2025-02-11 21:37:11 +08:00
parent 8c81b9a425
commit 501e25d835
5 changed files with 87 additions and 41 deletions

View File

@ -13,6 +13,7 @@
})
const selectedNode = ref<TreeNode>()
const searchResults = ref<Record<string, PartialSearchResult>>({})
const isLoading = ref(false)
function handleResearchProgress(step: ResearchStep) {
let node: TreeNode | null = null
@ -94,6 +95,7 @@
case 'complete':
emit('complete', step)
isLoading.value = false
break
}
}
@ -132,6 +134,7 @@
tree.value.children = []
selectedNode.value = undefined
searchResults.value = {}
isLoading.value = true
try {
await deepResearch({
query,
@ -141,11 +144,14 @@
})
} catch (error) {
console.error('Research failed:', error)
} finally {
isLoading.value = false
}
}
defineExpose({
startResearch,
isLoading,
})
</script>

View File

@ -8,6 +8,10 @@
userAnswer: string
}
const props = defineProps<{
isLoadingSearch?: boolean
}>()
defineEmits<{
(e: 'submit', feedback: ResearchFeedbackResult[]): void
}>()
@ -24,7 +28,8 @@
// All questions should be answered
feedback.value.some((v) => !v.assistantQuestion || !v.userAnswer) ||
// Should not be loading
isLoading.value,
isLoading.value ||
props.isLoadingSearch,
)
async function getFeedback(query: string, numQuestions = 3) {
@ -94,6 +99,7 @@
defineExpose({
getFeedback,
clear,
isLoading,
})
</script>
@ -113,7 +119,13 @@
<UInput v-model="feedback.userAnswer" />
</div>
</template>
<UButton color="primary" :loading="isLoading" :disabled="isSubmitButtonDisabled" block @click="$emit('submit', feedback)">
<UButton
color="primary"
:loading="isLoadingSearch || isLoading"
:disabled="isSubmitButtonDisabled"
block
@click="$emit('submit', feedback)"
>
Submit Answer
</UButton>
</div>

View File

@ -6,27 +6,31 @@
numQuestions: number
}
defineProps<{
isLoadingFeedback: boolean
}>()
const emit = defineEmits<{
(e: 'submit', value: ResearchInputData): void
}>()
const input = ref('天空为什么是蓝的?')
const breadth = ref(2)
const depth = ref(2)
const numQuestions = ref(3)
const isLoading = ref(false)
const form = reactive({
query: '',
breadth: 2,
depth: 2,
numQuestions: 3,
})
const isSubmitButtonDisabled = computed(() => !form.query || !form.breadth || !form.depth || !form.numQuestions)
function handleSubmit() {
emit('submit', {
query: input.value,
breadth: breadth.value,
depth: depth.value,
numQuestions: numQuestions.value,
...form,
})
}
onMounted(() => {
input.value = '天空为什么是蓝的?' // default
defineExpose({
form,
})
</script>
@ -37,30 +41,30 @@
</template>
<div class="flex flex-col gap-2">
<UFormField label="Research Topic" required>
<UTextarea class="w-full" v-model="input" :rows="3" placeholder="Enter whatever you want to research..." required />
<UTextarea class="w-full" v-model="form.query" :rows="3" placeholder="Enter whatever you want to research..." required />
</UFormField>
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4">
<UFormField label="Number of Questions">
<UFormField label="Number of Questions" required>
<template #help> Number of questions for you to clarify. </template>
<UInput v-model="numQuestions" class="w-full" type="number" :min="1" :max="5" :step="1" />
<UInput v-model="form.numQuestions" class="w-full" type="number" :min="1" :max="5" :step="1" />
</UFormField>
<UFormField label="Depth">
<UFormField label="Depth" required>
<template #help> How deep you want to dig. </template>
<UInput v-model="depth" class="w-full" type="number" :min="1" :max="5" :step="1" />
<UInput v-model="form.depth" class="w-full" type="number" :min="1" :max="5" :step="1" />
</UFormField>
<UFormField label="Breadth">
<UFormField label="Breadth" required>
<template #help> Number of searches in each depth. </template>
<UInput v-model="breadth" class="w-full" type="number" :min="1" :max="5" :step="1" />
<UInput v-model="form.breadth" class="w-full" type="number" :min="1" :max="5" :step="1" />
</UFormField>
</div>
</div>
<template #footer>
<UButton type="submit" color="primary" :loading="isLoading" block @click="handleSubmit">
{{ isLoading ? 'Researching...' : 'Start Research' }}
<UButton type="submit" color="primary" :loading="isLoadingFeedback" :disabled="isSubmitButtonDisabled" block @click="handleSubmit">
{{ isLoadingFeedback ? 'Researching...' : 'Start Research' }}
</UButton>
</template>
</UCard>

View File

@ -10,7 +10,7 @@
const loading = ref(false)
const loadingExportPdf = ref(false)
const reportContent = ref('')
const reportHtml = computed(() => marked(reportContent.value))
const reportHtml = computed(() => marked(reportContent.value, { gfm: true, silent: true }))
const isExportButtonDisabled = computed(() => !reportContent.value || loading.value || loadingExportPdf.value)
async function generateReport(params: CustomReportParams) {
@ -31,28 +31,52 @@
}
async function exportToPdf() {
const element = document.getElementById('report-content')
if (!element) return
// Create a temp container
const tempContainer = document.createElement('div')
loadingExportPdf.value = true
try {
// 动态导入 html2pdf确保只在客户端执行
// Dinamically import html2pdf
// @ts-ignore
const html2pdf = (await import('html2pdf.js')).default
const element = document.getElementById('report-content')
tempContainer.innerHTML = element.innerHTML
tempContainer.className = element.className
if (element) {
const opt = {
margin: [10, 10],
filename: 'research-report.pdf',
image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 2 },
jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' },
}
// Use print-friendly styles
tempContainer.style.cssText = `
font-family: Arial, sans-serif;
color: black;
background-color: white;
padding: 20px;
`
await html2pdf().set(opt).from(element).save()
document.body.appendChild(tempContainer)
const opt = {
margin: [10, 10],
filename: 'research-report.pdf',
image: { type: 'jpeg', quality: 0.98 },
html2canvas: {
scale: 2,
useCORS: true,
backgroundColor: '#ffffff',
},
jsPDF: {
unit: 'mm',
format: 'a4',
orientation: 'portrait',
},
}
await html2pdf().set(opt).from(tempContainer).save()
} catch (error) {
console.error('Export to PDF failed:', error)
} finally {
document.body.removeChild(tempContainer)
loadingExportPdf.value = false
}
}