feat: 实现 API 接口对接功能 (删除作品、作品搜索、修改密码)

按照 TDD 规范完成三个核心功能的接口对接:

## 新增功能

### 1. 删除作品功能 (app/generationRecord.tsx)
- 新增 use-template-generation-actions.ts hook
- 支持单个删除和批量删除作品
- 删除确认对话框
- 删除成功后自动刷新列表
- 完整的错误处理和加载状态

### 2. 作品搜索功能 (app/searchWorksResults.tsx)
- 新增 use-works-search.ts hook
- 替换模拟数据为真实 SDK 接口
- 支持关键词搜索和分类筛选
- 支持分页加载
- 完整的加载、错误、空结果状态处理

### 3. 修改密码功能 (app/changePassword.tsx)
- 新增 use-change-password.ts hook
- 使用 Better Auth 的 changePassword API
- 客户端表单验证(密码长度、确认密码匹配等)
- 成功后自动返回并提示

## 技术实现
- 严格遵循 TDD 规范(先写测试,后写实现)
- 新增 3 个 hooks 和对应的单元测试
- 更新中英文翻译文件
- 更新 jest.setup.js 添加必要的 mock

## 文档
- 新增 api_integration_report.md - API 对接分析报告
- 新增 api_integration_development_plan.md - 开发计划和完成汇总

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
imeepos
2026-01-23 19:15:24 +08:00
parent 4c01d8e9e7
commit e1340fa101
19 changed files with 2273 additions and 299 deletions

View File

@@ -6,6 +6,7 @@ import {
Dimensions,
Pressable,
StatusBar as RNStatusBar,
Alert,
} from 'react-native'
import { StatusBar } from 'expo-status-bar'
import { SafeAreaView } from 'react-native-safe-area-context'
@@ -19,7 +20,11 @@ import { DeleteConfirmDialog } from '@/components/ui/delete-confirm-dialog'
import LoadingState from '@/components/LoadingState'
import ErrorState from '@/components/ErrorState'
import PaginationLoader from '@/components/PaginationLoader'
import { useTemplateGenerations, type TemplateGeneration } from '@/hooks'
import {
useTemplateGenerations,
useDeleteGeneration,
type TemplateGeneration,
} from '@/hooks'
const { width: screenWidth } = Dimensions.get('window')
@@ -30,14 +35,27 @@ export default function GenerationRecordScreen() {
const [selectedId, setSelectedId] = useState<string | null>(null)
const { generations, loading, loadingMore, error, execute, refetch, loadMore, hasMore } = useTemplateGenerations()
const { deleteGeneration, loading: deleting } = useDeleteGeneration()
useEffect(() => {
execute({ page: 1, limit: 20 })
}, [execute])
const handleDelete = () => {
console.log('删除记录:', selectedId)
const handleDelete = async () => {
if (!selectedId) return
const { data, error } = await deleteGeneration(selectedId)
if (error) {
Alert.alert(t('common.error'), error.message || t('generationRecord.deleteError'))
} else {
Alert.alert(t('common.success'), data?.message || t('generationRecord.deleteSuccess'))
// 刷新列表
refetch({ page: 1, limit: 20 })
}
setDeleteDialogOpen(false)
setSelectedId(null)
}
const handleRefresh = () => {
@@ -122,11 +140,14 @@ export default function GenerationRecordScreen() {
<Text style={styles.actionButtonText}>{t('generationRecord.regenerate')}</Text>
</Pressable>
<Pressable
style={styles.deleteButton}
style={[styles.deleteButton, deleting && selectedId === item.id && styles.deleteButtonDisabled]}
onPress={() => {
setSelectedId(item.id)
setDeleteDialogOpen(true)
if (!deleting) {
setSelectedId(item.id)
setDeleteDialogOpen(true)
}
}}
disabled={deleting && selectedId === item.id}
>
<DeleteIcon />
</Pressable>
@@ -285,5 +306,8 @@ const styles = StyleSheet.create({
justifyContent: 'center',
marginLeft: 'auto',
},
deleteButtonDisabled: {
opacity: 0.5,
},
})