37 lines
3.6 KiB
Vue
37 lines
3.6 KiB
Vue
<script setup lang="ts">
|
||
import { computed, onMounted, ref } from 'vue'
|
||
import { getRetrievalRuns, type RetrievalRunResult } from '../api'
|
||
import { exportRetrievalHistory } from '../services/exports'
|
||
|
||
const runs=ref<RetrievalRunResult[]>([]), selected=ref<string[]>([]), page=ref(1), total=ref(0), loading=ref(true), exporting=ref(false), error=ref(''), notice=ref(''), includeContexts=ref(false)
|
||
const pageSize=20
|
||
const selectedSet=computed(()=>new Set(selected.value))
|
||
function runLabel(run:RetrievalRunResult){return `${new Date(run.created_at).toLocaleString()} · ${run.mode} · ${run.query}`}
|
||
function toggle(runId:string){if(selectedSet.value.has(runId)){selected.value=selected.value.filter(id=>id!==runId);return}if(selected.value.length>=100){error.value='一次最多选择 100 条检索历史。';return}selected.value=[...selected.value,runId]}
|
||
async function refresh(next=page.value){loading.value=true;error.value='';try{const result=await getRetrievalRuns(next,pageSize);runs.value=result.items;total.value=result.total;page.value=result.page}catch(cause){error.value=cause instanceof Error?cause.message:'无法读取检索历史'}finally{loading.value=false}}
|
||
async function download(){error.value='';notice.value='';if(!selected.value.length){error.value='请先选择至少一条检索历史。';return}exporting.value=true;try{const file=await exportRetrievalHistory({run_ids:selected.value,include_contexts:includeContexts.value});const url=URL.createObjectURL(file.blob);const link=document.createElement('a');link.href=url;link.download=file.filename;link.style.display='none';document.body.append(link);link.click();link.remove();window.setTimeout(()=>URL.revokeObjectURL(url),0);notice.value=`已开始下载 ${file.filename}${file.recordsSha256?`(记录摘要 ${file.recordsSha256})`:''}。`}catch(cause){error.value=cause instanceof Error?cause.message:'导出失败'}finally{exporting.value=false}}
|
||
onMounted(()=>refresh(1))
|
||
</script>
|
||
|
||
<template>
|
||
<main>
|
||
<RouterLink to="/admin">返回管理员工作台</RouterLink>
|
||
<h1>导出检索历史</h1>
|
||
<p>从已保存的历史快照选择记录,导出 JSONL;不会重新检索、调用模型或导出认证信息。</p>
|
||
<p v-if="error" role="alert">{{error}}</p><p v-if="notice" role="status">{{notice}}</p>
|
||
<form @submit.prevent="download">
|
||
<label><input v-model="includeContexts" type="checkbox"/> 同时包含关联的 RAG 准备上下文</label>
|
||
<button :disabled="exporting||!selected.length">{{exporting?'正在准备…':`导出已选 ${selected.length} 条`}}</button>
|
||
<p>最多选择 100 条记录;导出上限为 8 MiB。文件仅表示当时历史快照,并不代表当前知识仍有效。</p>
|
||
</form>
|
||
<p v-if="loading">正在读取检索历史…</p>
|
||
<template v-else>
|
||
<table>
|
||
<thead><tr><th>选择</th><th>时间</th><th>模式</th><th>查询</th><th>状态</th><th>命中数</th></tr></thead>
|
||
<tbody><tr v-for="run in runs" :key="run.run_id"><td><input :checked="selectedSet.has(run.run_id)" type="checkbox" :aria-label="runLabel(run)" @change="toggle(run.run_id)"/></td><td>{{new Date(run.created_at).toLocaleString()}}</td><td>{{run.mode}}</td><td>{{run.query}}</td><td>{{run.status}}</td><td>{{run.total_hits}}</td></tr><tr v-if="!runs.length"><td colspan="6">暂无可导出的检索历史。</td></tr></tbody>
|
||
</table>
|
||
<div><button :disabled="page===1" @click="refresh(page-1)">上一页</button><span>第 {{page}} 页,共 {{total}} 条</span><button :disabled="page*pageSize>=total" @click="refresh(page+1)">下一页</button></div>
|
||
</template>
|
||
</main>
|
||
</template>
|