Files
momentry_studio/docs/Quick_Implementation_Checklist.md
Momentry Studio 896b12be9a docs: 添加 Vue 3 分页实施指南
内容:
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
2026-10-11 21:37:50 +08:00

332 lines
7.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Studio 分页功能快速实施清单
**日期**: 2026-10-11
**目标**: 在 SearchView 中添加 More 按钮和分页加载
**预计时间**: 1-2 小时
---
## 📝 需要修改的文件
**只需修改 1 个文件**: `src/views/SearchView.vue`
---
## 🚀 5 步快速实施
### 步骤 1: 添加状态(1 分钟)
在 `<script setup>` 中添加:
```typescript
// === 在现有状态后添加 ===
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` 函数后添加:
```typescript
/**
* 加载更多结果
*/
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` 函数末尾添加:
```typescript
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>` 结果列表后添加:
```vue
<!-- 在结果列表后添加 -->
<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>` 中添加:
```css
/* 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;
}
```
---
## ✅ 验证步骤
1. **打开 Studio**
2. **搜索查询**: "sunset"
3. **验证**:
- ✅ 显示 Top 5 结果
- ✅ More 按钮显示 "X remaining"
- ✅ 点击 More 追加 10 个结果
- ✅ 无更多结果时显示 "All X results loaded"
---
## 📊 效果对比
### 之前
```
搜索 → 显示 20 个结果(一次性加载)
```
### 之后
```
搜索 → 快速显示 5 个
↓
More → 追加 10 个
↓
More → 再追加 10 个
↓
完成 → "All X results loaded"
```
---
## 🎯 完整代码片段
### 复制即用的完整修改
```typescript
// === 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
}
```
```vue
<!-- === 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>
```
```css
/* === 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;
}
```
---
## ⚠️ 注意事项
1. **API 兼容性**: 当前使用 offset 参数,如果后端支持 session_id,可以切换到 session 模式
2. **错误处理**: 已添加基本错误处理,如需更详细提示可扩展
3. **性能**: 初始加载 5 个结果,More 操作加载 10 个,避免一次性加载过多
---
## 🎉 完成标志
- [ ] 初始搜索显示 Top 5
- [ ] More 按钮显示正确
- [ ] 点击 More 追加结果
- [ ] 无更多结果时提示
- [ ] 样式正常显示
---
**快速实施完成!只需修改 SearchView.vue 一个文件。**