promptmanager / src /pages /PromptGroupDetailPage.tsx
samlax12's picture
Upload 55 files
e85fa50 verified
import React, { useState } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import Layout from '../components/Layout/Layout';
import Card, { CardHeader, CardContent } from '../components/common/Card';
import Button from '../components/common/Button';
import PromptList from '../components/Prompt/PromptList';
import DslFileList from '../components/DslFile/DslFileList';
import DslFileUploader from '../components/DslFile/DslFileUploader';
import CategoryBadge from '../components/Category/CategoryBadge';
import { useApp } from '../contexts/AppContext';
import { exportPromptGroupToZip } from '../utils/exportUtils';
const PromptGroupDetailPage: React.FC = () => {
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
const {
promptGroups,
categories,
updatePromptGroup,
deletePromptGroup,
addPrompt,
updatePrompt,
deletePrompt
} = useApp();
const [activeTab, setActiveTab] = useState<'prompts' | 'dslFiles'>('prompts');
if (!id) {
return <div>提示词组ID无效</div>;
}
const promptGroup = promptGroups.find(group => group._id === id);
if (!promptGroup) {
return (
<Layout title="未找到" showBackButton>
<div className="ios-empty-state">
<div className="ios-empty-state-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<circle cx="12" cy="12" r="10"></circle>
<line x1="12" y1="8" x2="12" y2="12"></line>
<line x1="12" y1="16" x2="12.01" y2="16"></line>
</svg>
</div>
<h3 className="ios-empty-state-title">未找到提示词组</h3>
<p className="ios-empty-state-text">该提示词组可能已被删除</p>
<Button
variant="primary"
className="mt-4"
onClick={() => navigate('/')}
>
返回首页
</Button>
</div>
</Layout>
);
}
const category = categories.find(c => c._id === promptGroup.category);
const handleDeletePromptGroup = () => {
if (window.confirm('确定要删除此提示词组吗?此操作不可撤销,所有相关提示词和文件都将被删除。')) {
deletePromptGroup(promptGroup._id);
navigate('/');
}
};
const handleExportPromptGroup = () => {
exportPromptGroupToZip(promptGroup);
};
const formatDate = (date: string | Date) => {
const dateObj = typeof date === 'string' ? new Date(date) : date;
return dateObj.toLocaleDateString('zh-CN', {
year: 'numeric',
month: 'long',
day: 'numeric'
});
};
return (
<Layout
title={promptGroup.name}
showBackButton
rightAction={
<Button
variant="primary"
size="small"
onClick={handleExportPromptGroup}
>
导出
</Button>
}
>
<Card className="mb-4">
<CardContent>
<div className="flex justify-between items-start">
<div>
<h1 className="text-2xl font-bold mb-2">{promptGroup.name}</h1>
{category && <CategoryBadge category={category} className="mb-2" />}
<p className="text-gray-600 mb-2">{promptGroup.description || '无描述'}</p>
<div className="text-sm text-gray-500">
创建于 {formatDate(promptGroup.createdAt)}
<span className="mx-2"></span>
更新于 {formatDate(promptGroup.updatedAt)}
</div>
</div>
<div className="flex space-x-2">
<Button
variant="secondary"
size="small"
onClick={() => navigate(`/edit-prompt-group/${promptGroup._id}`)}
>
编辑
</Button>
<Button
variant="danger"
size="small"
onClick={handleDeletePromptGroup}
>
删除
</Button>
</div>
</div>
</CardContent>
</Card>
<div className="flex border-b border-gray-200 mb-4">
<button
className={`py-2 px-4 font-medium text-sm ${activeTab === 'prompts' ? 'text-blue-600 border-b-2 border-blue-600' : 'text-gray-500'}`}
onClick={() => setActiveTab('prompts')}
>
提示词 ({promptGroup.prompts.length})
</button>
<button
className={`py-2 px-4 font-medium text-sm ${activeTab === 'dslFiles' ? 'text-blue-600 border-b-2 border-blue-600' : 'text-gray-500'}`}
onClick={() => setActiveTab('dslFiles')}
>
DSL文件 ({promptGroup.dslFiles.length})
</button>
</div>
<div className="space-y-4 max-h-screen overflow-y-auto">
{activeTab === 'prompts' && (
<PromptList
groupId={promptGroup._id}
prompts={promptGroup.prompts}
onAddPrompt={(promptData) => addPrompt(promptGroup._id, promptData)}
onUpdatePrompt={(promptId, promptData) => updatePrompt(promptGroup._id, promptId, promptData)}
onDeletePrompt={(promptId) => deletePrompt(promptGroup._id, promptId)}
/>
)}
</div>
{activeTab === 'dslFiles' && (
<div>
<div className="flex justify-between items-center mb-4">
<h3 className="text-lg font-medium">DSL文件列表</h3>
<DslFileUploader groupId={promptGroup._id} />
</div>
<DslFileList
groupId={promptGroup._id}
files={promptGroup.dslFiles}
/>
</div>
)}
</Layout>
);
};
export default PromptGroupDetailPage;