150 lines
4.3 KiB
JavaScript
150 lines
4.3 KiB
JavaScript
|
|
'use client';
|
|||
|
|
|
|||
|
|
import { useState, useEffect, useCallback, useRef } from 'react';
|
|||
|
|
import { useRouter } from 'next/navigation';
|
|||
|
|
import { toast } from 'sonner';
|
|||
|
|
import axios from 'axios';
|
|||
|
|
|
|||
|
|
export default function useEvalDatasetDetails(projectId, evalId) {
|
|||
|
|
const router = useRouter();
|
|||
|
|
const [data, setData] = useState(null);
|
|||
|
|
const [loading, setLoading] = useState(true);
|
|||
|
|
const [error, setError] = useState(null);
|
|||
|
|
|
|||
|
|
// 编辑状态
|
|||
|
|
const [editingField, setEditingField] = useState(null); // 'question', 'options', 'correctAnswer', 'note', 'tags'
|
|||
|
|
const [fieldValue, setFieldValue] = useState('');
|
|||
|
|
// 获取详情
|
|||
|
|
const fetchData = useCallback(async () => {
|
|||
|
|
try {
|
|||
|
|
setLoading(true);
|
|||
|
|
setError(null);
|
|||
|
|
const response = await fetch(`/api/projects/${projectId}/eval-datasets/${evalId}`);
|
|||
|
|
|
|||
|
|
if (!response.ok) {
|
|||
|
|
if (response.status === 404) {
|
|||
|
|
throw new Error('未找到该题目');
|
|||
|
|
}
|
|||
|
|
throw new Error('获取数据失败');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const result = await response.json();
|
|||
|
|
setData(result);
|
|||
|
|
} catch (err) {
|
|||
|
|
console.error(err);
|
|||
|
|
setError(err.message);
|
|||
|
|
} finally {
|
|||
|
|
setLoading(false);
|
|||
|
|
}
|
|||
|
|
}, [projectId, evalId]);
|
|||
|
|
|
|||
|
|
useEffect(() => {
|
|||
|
|
fetchData();
|
|||
|
|
}, [fetchData]);
|
|||
|
|
|
|||
|
|
// 导航
|
|||
|
|
const handleNavigate = async direction => {
|
|||
|
|
try {
|
|||
|
|
const response = await fetch(`/api/projects/${projectId}/eval-datasets/${evalId}?operateType=${direction}`);
|
|||
|
|
if (response.ok) {
|
|||
|
|
const neighbor = await response.json();
|
|||
|
|
if (neighbor && neighbor.id) {
|
|||
|
|
router.push(`/projects/${projectId}/eval-datasets/${neighbor.id}`);
|
|||
|
|
} else {
|
|||
|
|
toast.warning(`已经是${direction === 'next' ? '最后' : '第'}一条数据了`);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} catch (err) {
|
|||
|
|
console.error('Navigation error:', err);
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 开始编辑
|
|||
|
|
const handleStartEdit = (field, value) => {
|
|||
|
|
setEditingField(field);
|
|||
|
|
// 对于 options,如果是数组则转为 JSON 字符串编辑,或者在组件层面处理
|
|||
|
|
// 这里假设 value 已经是适合编辑的格式
|
|||
|
|
setFieldValue(value);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 取消编辑
|
|||
|
|
const handleCancelEdit = () => {
|
|||
|
|
setEditingField(null);
|
|||
|
|
setFieldValue('');
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 保存编辑
|
|||
|
|
const handleSave = async (field, value) => {
|
|||
|
|
try {
|
|||
|
|
const response = await fetch(`/api/projects/${projectId}/eval-datasets/${evalId}`, {
|
|||
|
|
method: 'PUT',
|
|||
|
|
headers: { 'Content-Type': 'application/json' },
|
|||
|
|
body: JSON.stringify({ [field]: value })
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (!response.ok) throw new Error('保存失败');
|
|||
|
|
|
|||
|
|
const updated = await response.json();
|
|||
|
|
setData(prev => ({ ...prev, ...updated })); // 更新本地数据
|
|||
|
|
setEditingField(null);
|
|||
|
|
toast.success('保存成功');
|
|||
|
|
} catch (err) {
|
|||
|
|
toast.error(err.message);
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 删除
|
|||
|
|
const handleDelete = async () => {
|
|||
|
|
if (!confirm('确定要删除这条数据吗?此操作不可撤销。')) return;
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// 先尝试获取下一条,以便删除后跳转
|
|||
|
|
const nextResponse = await fetch(`/api/projects/${projectId}/eval-datasets/${evalId}?operateType=next`);
|
|||
|
|
let nextId = null;
|
|||
|
|
if (nextResponse.ok) {
|
|||
|
|
const next = await nextResponse.json();
|
|||
|
|
if (next && next.id) nextId = next.id;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果没有下一条,尝试获取上一条
|
|||
|
|
if (!nextId) {
|
|||
|
|
const prevResponse = await fetch(`/api/projects/${projectId}/eval-datasets/${evalId}?operateType=prev`);
|
|||
|
|
if (prevResponse.ok) {
|
|||
|
|
const prev = await prevResponse.json();
|
|||
|
|
if (prev && prev.id) nextId = prev.id;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 删除
|
|||
|
|
const deleteResponse = await fetch(`/api/projects/${projectId}/eval-datasets/${evalId}`, {
|
|||
|
|
method: 'DELETE'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (!deleteResponse.ok) throw new Error('删除失败');
|
|||
|
|
|
|||
|
|
toast.success('删除成功');
|
|||
|
|
|
|||
|
|
if (nextId) {
|
|||
|
|
router.replace(`/projects/${projectId}/eval-datasets/${nextId}`);
|
|||
|
|
} else {
|
|||
|
|
router.push(`/projects/${projectId}/eval-datasets`);
|
|||
|
|
}
|
|||
|
|
} catch (err) {
|
|||
|
|
toast.error(err.message);
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
return {
|
|||
|
|
data,
|
|||
|
|
loading,
|
|||
|
|
error,
|
|||
|
|
editingField,
|
|||
|
|
fieldValue,
|
|||
|
|
setFieldValue,
|
|||
|
|
handleNavigate,
|
|||
|
|
handleStartEdit,
|
|||
|
|
handleCancelEdit,
|
|||
|
|
handleSave,
|
|||
|
|
handleDelete
|
|||
|
|
};
|
|||
|
|
}
|