内容: 1. Vue3_Pagination_Implementation_Guide.md (718 行) - Vue 3 + TypeScript + Tauri 2 完整实施指南 - 完整的代码示例 - 分页和 Session 管理 - 临时方案(兼容现有 API) 2. Quick_Implementation_Checklist.md (331 行) - 5 步快速实施(1-2 小时) - 只需修改 1 个文件(SearchView.vue) - 复制即用的代码片段 - 验证步骤 实施方案: - 添加状态(sessionId, hasMore, nextOffset 等) - 实现 loadMore() 函数 - 修改 executeSearch() 支持分页 - 添加 More 按钮 UI - 添加样式 预期效果: - 初始加载:~2s → ~0.5s(4x 更快) - 内存占用:渐进式加载 - 用户体验:立即反馈 技术栈适配: - useState → ref / reactive - useEffect → onMounted / watch - lucide-react → 内联 SVG
7.3 KiB
7.3 KiB
Studio 分页功能快速实施清单
日期: 2026-10-11
目标: 在 SearchView 中添加 More 按钮和分页加载
预计时间: 1-2 小时
📝 需要修改的文件
只需修改 1 个文件: src/views/SearchView.vue
🚀 5 步快速实施
步骤 1: 添加状态(1 分钟)
在 <script setup> 中添加:
// === 在现有状态后添加 ===
const sessionId = ref('')
const nextOffset = ref(0)
const hasMore = ref(false)
const totalResults = ref(0)
const isLoadingMore = ref(false)
// 修改 pageSize
const pageSize = 5 // 从 20 改为 5
步骤 2: 添加 loadMore 函数(5 分钟)
在 executeSearch 函数后添加:
/**
* 加载更多结果
*/
async function loadMore() {
if (isLoadingMore.value || !hasMore.value) return
isLoadingMore.value = true
try {
const query = searchQuery.value.trim()
const mode = searchMode.value
// 使用 offset 参数(当前 API 支持)
let res: any
switch (mode) {
case 'keyword':
res = await apiCall('search_keyword', { query, offset: results.value.length, limit: 10 })
break
case 'semantic':
res = await apiCall('search_semantic', { query, offset: results.value.length, limit: 10 })
break
case 'visual':
res = await apiCall('search_vlm_scenes', { query, offset: results.value.length, limit: 10 })
break
case 'agent':
res = await apiCall('agents_search', { query, offset: results.value.length, limit: 10 })
break
case 'people':
res = await apiCall('search_people', { query, offset: results.value.length, limit: 10 })
break
}
if (res && res.length > 0) {
results.value.push(...res)
hasMore.value = res.length >= 10
totalResults.value = results.value.length
} else {
hasMore.value = false
}
} catch (err) {
console.error('Load more failed:', err)
} finally {
isLoadingMore.value = false
}
}
步骤 3: 修改 executeSearch(3 分钟)
在 executeSearch 函数末尾添加:
async function executeSearch() {
// ... 现有代码 ...
results.value = res.results || res
// === 添加以下代码 ===
totalResults.value = results.value.length
hasMore.value = results.value.length >= pageSize
nextOffset.value = pageSize
sessionId.value = '' // 重置
}
步骤 4: 添加 UI(2 分钟)
在 <template> 结果列表后添加:
<!-- 在结果列表后添加 -->
<div v-if="hasMore && results.length > 0" class="load-more-container">
<button
class="load-more-btn"
@click="loadMore"
:disabled="isLoadingMore"
>
{{ isLoadingMore ? 'Loading...' : `More Results (${totalResults - results.length} remaining)` }}
</button>
</div>
<div v-if="!hasMore && results.length > 0" class="no-more-results">
<p>All {{ results.length }} results loaded</p>
</div>
步骤 5: 添加样式(1 分钟)
在 <style scoped> 中添加:
/* More 按钮 */
.load-more-container {
margin-top: 24px;
display: flex;
justify-content: center;
}
.load-more-btn {
padding: 12px 24px;
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 8px;
color: rgba(255, 255, 255, 0.7);
font-size: 14px;
cursor: pointer;
transition: all 0.2s;
}
.load-more-btn:hover:not(:disabled) {
background: rgba(255, 255, 255, 0.08);
}
.load-more-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.no-more-results {
margin-top: 24px;
text-align: center;
color: rgba(255, 255, 255, 0.5);
font-size: 13px;
}
✅ 验证步骤
- 打开 Studio
- 搜索查询: "sunset"
- 验证:
- ✅ 显示 Top 5 结果
- ✅ More 按钮显示 "X remaining"
- ✅ 点击 More 追加 10 个结果
- ✅ 无更多结果时显示 "All X results loaded"
📊 效果对比
之前
搜索 → 显示 20 个结果(一次性加载)
之后
搜索 → 快速显示 5 个
↓
More → 追加 10 个
↓
More → 再追加 10 个
↓
完成 → "All X results loaded"
🎯 完整代码片段
复制即用的完整修改
// === 1. 状态定义(script setup 开头) ===
const sessionId = ref('')
const nextOffset = ref(0)
const hasMore = ref(false)
const totalResults = ref(0)
const isLoadingMore = ref(false)
const pageSize = 5
// === 2. loadMore 函数 ===
async function loadMore() {
if (isLoadingMore.value || !hasMore.value) return
isLoadingMore.value = true
try {
const query = searchQuery.value.trim()
const mode = searchMode.value
const offset = results.value.length
let res: any
if (mode === 'keyword') {
res = await apiCall('search_keyword', { query, offset, limit: 10 })
} else if (mode === 'semantic') {
res = await apiCall('search_semantic', { query, offset, limit: 10 })
} else if (mode === 'visual') {
res = await apiCall('search_vlm_scenes', { query, offset, limit: 10 })
} else if (mode === 'agent') {
res = await apiCall('agents_search', { query, offset, limit: 10 })
} else if (mode === 'people') {
res = await apiCall('search_people', { query, offset, limit: 10 })
}
if (res?.length > 0) {
results.value.push(...res)
hasMore.value = res.length >= 10
} else {
hasMore.value = false
}
} catch (err) {
console.error('Load more failed:', err)
} finally {
isLoadingMore.value = false
}
}
// === 3. executeSearch 修改 ===
async function executeSearch() {
// ... 现有代码 ...
// 在 results.value = res 后添加
totalResults.value = results.value.length
hasMore.value = results.value.length >= pageSize
nextOffset.value = pageSize
}
<!-- === 4. Template 添加 === -->
<!-- 在结果列表后 -->
<div v-if="hasMore && results.length > 0" class="load-more-container">
<button class="load-more-btn" @click="loadMore" :disabled="isLoadingMore">
{{ isLoadingMore ? 'Loading...' : `More Results (${totalResults - results.length} remaining)` }}
</button>
</div>
<div v-if="!hasMore && results.length > 0" class="no-more-results">
<p>All {{ results.length }} results loaded</p>
</div>
/* === 5. 样式添加 === */
.load-more-container {
margin-top: 24px;
display: flex;
justify-content: center;
}
.load-more-btn {
padding: 12px 24px;
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 8px;
color: rgba(255, 255, 255, 0.7);
font-size: 14px;
cursor: pointer;
}
.load-more-btn:hover:not(:disabled) {
background: rgba(255, 255, 255, 0.08);
}
.no-more-results {
margin-top: 24px;
text-align: center;
color: rgba(255, 255, 255, 0.5);
font-size: 13px;
}
⚠️ 注意事项
- API 兼容性: 当前使用 offset 参数,如果后端支持 session_id,可以切换到 session 模式
- 错误处理: 已添加基本错误处理,如需更详细提示可扩展
- 性能: 初始加载 5 个结果,More 操作加载 10 个,避免一次性加载过多
🎉 完成标志
- 初始搜索显示 Top 5
- More 按钮显示正确
- 点击 More 追加结果
- 无更多结果时提示
- 样式正常显示
快速实施完成!只需修改 SearchView.vue 一个文件。