增加修改和删除功能

This commit is contained in:
2025-12-24 15:20:58 +08:00
parent 1aa39e11b4
commit 31cc78038b
26 changed files with 707 additions and 492 deletions
+188 -22
View File
@@ -1,6 +1,7 @@
import { useState, useEffect } from 'react';
import { UserCog, PenTool, Sparkles, BookOpen, Loader2 } from 'lucide-react';
import { UserCog, PenTool, Sparkles, BookOpen, Loader2, Pencil, Trash2 } from 'lucide-react';
import { GlassCard, GlassButton, GlassInput, GlassSelect } from '../components/ui';
import Modal from '../components/Modal';
import useStore from '../store/useStore';
import { scriptStyles, scriptLengths } from '../utils/constants';
@@ -11,12 +12,14 @@ import { scriptStyles, scriptLengths } from '../utils/constants';
* @param {Function} props.onOpenProfile - 打开用户资料模态框回调
*/
const ScriptView = ({ onOpenProfile }) => {
const {
registrationData,
lifeEvents,
scripts,
selectedScriptId,
addScript,
const {
registrationData,
lifeEvents,
scripts,
selectedScriptId,
addScript,
updateScript,
deleteScript,
setSelectedScriptId,
getSelectedScript,
loadScripts
@@ -35,6 +38,18 @@ const ScriptView = ({ onOpenProfile }) => {
const [length, setLength] = useState(scriptLengths[0].value);
const [isLoading, setIsLoading] = useState(false);
// 编辑模态框状态
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
const [editingScript, setEditingScript] = useState(null);
const [editForm, setEditForm] = useState({
theme: '',
style: '',
length: ''
});
// 删除确认状态
const [deleteConfirmId, setDeleteConfirmId] = useState(null);
/**
* 处理剧本生成
*/
@@ -45,17 +60,17 @@ const ScriptView = ({ onOpenProfile }) => {
}
setIsLoading(true);
try {
// 直接调用后端创建接口,由后端调用AI生成
await addScript({
theme,
style,
length,
await addScript({
theme,
style,
length,
character: registrationData,
events: lifeEvents
});
setTheme('');
} catch (error) {
console.error('Failed to generate script:', error);
@@ -64,6 +79,73 @@ const ScriptView = ({ onOpenProfile }) => {
}
};
/**
* 打开编辑模态框
* @param {Object} script - 要编辑的剧本
*/
const openEditModal = (script) => {
setEditingScript(script);
setEditForm({
theme: script.theme || '',
style: script.style || scriptStyles[0].value,
length: script.length || scriptLengths[0].value
});
setIsEditModalOpen(true);
};
/**
* 关闭编辑模态框
*/
const closeEditModal = () => {
setIsEditModalOpen(false);
setEditingScript(null);
setEditForm({ theme: '', style: '', length: '' });
};
/**
* 处理编辑提交
*/
const handleEditSubmit = async () => {
if (!editForm.theme) {
alert('请输入主题');
return;
}
setIsLoading(true);
try {
await updateScript({
id: editingScript.id,
theme: editForm.theme,
style: editForm.style,
length: editForm.length,
character: registrationData,
events: lifeEvents,
regenerateContent: true // 标记需要重新生成AI内容
});
closeEditModal();
} catch (error) {
console.error('Failed to update script:', error);
} finally {
setIsLoading(false);
}
};
/**
* 处理删除确认
* @param {string} id - 剧本ID
*/
const handleDeleteConfirm = async (id) => {
try {
await deleteScript(id);
setDeleteConfirmId(null);
} catch (error) {
console.error('Failed to delete script:', error);
alert('删除失败,请稍后重试');
setDeleteConfirmId(null);
}
};
/**
* 格式化剧本内容,高亮【标题】
*/
@@ -165,16 +247,35 @@ const ScriptView = ({ onOpenProfile }) => {
scripts.map((script) => (
<div
key={script.id}
onClick={() => setSelectedScriptId(script.id)}
className={`
p-3 glass-card text-left cursor-pointer hover:bg-white/5 border-white/5 transition-all
p-3 glass-card text-left cursor-pointer hover:bg-white/5 border-white/5 transition-all relative group
${script.id === selectedScriptId ? 'border-orange-200/30 bg-orange-200/5' : ''}
`}
>
<div className="text-[11px] text-white/80 truncate">{script.theme}</div>
<div className="text-[9px] text-white/30 flex justify-between mt-1">
<span>{script.style} | {script.length}</span>
<span>{script.date}</span>
{/* 操作按钮 */}
<div className="absolute top-2 right-2 flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
<button
onClick={(e) => { e.stopPropagation(); openEditModal(script); }}
className="p-1.5 rounded-full bg-white/5 hover:bg-orange-200/10 text-white/30 hover:text-orange-200 transition-all"
title="编辑"
>
<Pencil className="w-3 h-3" />
</button>
<button
onClick={(e) => { e.stopPropagation(); setDeleteConfirmId(script.id); }}
className="p-1.5 rounded-full bg-white/5 hover:bg-red-400/10 text-white/30 hover:text-red-400 transition-all"
title="删除"
>
<Trash2 className="w-3 h-3" />
</button>
</div>
<div onClick={() => setSelectedScriptId(script.id)}>
<div className="text-[11px] text-white/80 truncate pr-12">{script.theme}</div>
<div className="text-[9px] text-white/30 flex justify-between mt-1">
<span>{script.style} | {script.length}</span>
<span>{script.date}</span>
</div>
</div>
</div>
))
@@ -189,9 +290,18 @@ const ScriptView = ({ onOpenProfile }) => {
<div className="lg:col-span-8">
<div className="h-full">
{selectedScript ? (
<GlassCard className="h-full overflow-y-auto custom-scrollbar border-orange-200/20 shadow-2xl animate-fade-in" padding="lg">
<GlassCard className="h-full overflow-y-auto custom-scrollbar border-orange-200/20 shadow-2xl animate-fade-in relative group" padding="lg">
{/* 编辑按钮 */}
<button
onClick={() => openEditModal(selectedScript)}
className="absolute top-4 right-4 p-2 rounded-full bg-white/5 hover:bg-orange-200/10 text-white/30 hover:text-orange-200 transition-all opacity-0 group-hover:opacity-100"
title="修改剧本"
>
<Pencil className="w-4 h-4" />
</button>
<div className="prose prose-invert max-w-none">
<div className="flex justify-between items-center mb-8 pb-4 border-b border-white/5">
<div className="flex justify-between items-center mb-8 pb-4 border-b border-white/5 pr-10">
<div>
<h4 className="text-2xl font-serif text-orange-200">{selectedScript.theme}</h4>
<p className="text-[10px] text-white/30 mt-1 uppercase tracking-widest">
@@ -200,7 +310,7 @@ const ScriptView = ({ onOpenProfile }) => {
</div>
<BookOpen className="text-white/20" />
</div>
<div
<div
className="text-white/70 leading-loose whitespace-pre-wrap space-y-6 text-sm"
dangerouslySetInnerHTML={{ __html: formatScriptContent(selectedScript.content) }}
/>
@@ -214,6 +324,62 @@ const ScriptView = ({ onOpenProfile }) => {
)}
</div>
</div>
{/* 编辑剧本模态框 */}
<Modal isOpen={isEditModalOpen} onClose={closeEditModal} title="修改剧本">
<div className="space-y-6">
<GlassInput
label="剧本主题"
placeholder="例如:我在职场逆袭了"
value={editForm.theme}
onChange={(v) => setEditForm(prev => ({ ...prev, theme: v }))}
/>
<GlassSelect
label="叙事风格"
options={scriptStyles}
value={editForm.style}
onChange={(v) => setEditForm(prev => ({ ...prev, style: v }))}
/>
<GlassSelect
label="剧本篇幅"
options={scriptLengths}
value={editForm.length}
onChange={(v) => setEditForm(prev => ({ ...prev, length: v }))}
/>
<GlassButton
variant="primary"
onClick={handleEditSubmit}
loading={isLoading}
className="w-full"
>
{isLoading ? '正在重新编撰...' : '重新生成剧本'}
</GlassButton>
</div>
</Modal>
{/* 删除确认模态框 */}
<Modal isOpen={!!deleteConfirmId} onClose={() => setDeleteConfirmId(null)} title="确认删除" maxWidth="sm">
<div className="space-y-6">
<p className="text-white/70 text-sm">
确定要删除这个剧本吗此操作不可恢复关联的实现路径也将被删除
</p>
<div className="flex gap-4">
<GlassButton
onClick={() => setDeleteConfirmId(null)}
className="flex-1"
>
取消
</GlassButton>
<GlassButton
variant="primary"
onClick={() => handleDeleteConfirm(deleteConfirmId)}
className="flex-1 bg-red-500/10 text-red-400 border-red-400/20 hover:bg-red-500/20"
>
确认删除
</GlassButton>
</div>
</div>
</Modal>
</div>
);
};