增加修改和删除功能
This commit is contained in:
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user