mirror of
https://github.com/cfngc4594/monaco-editor-lsp-next.git
synced 2025-07-04 09:20:53 +00:00
feat(problem-editor): realize backend for save problem edit
- 在编辑面板组件中添加 onUpdate属性,用于处理数据更新 - 新增 updateProblem 函数,实现问题数据的更新逻辑 - 在问题编辑页面中集成更新功能,实现即时保存
This commit is contained in:
parent
05c6eec53a
commit
956a37d825
@ -1,27 +1,116 @@
|
||||
"use client";
|
||||
|
||||
import { ProblemFlexLayout } from "@/features/problems/components/problem-flexlayout";
|
||||
import { EditDescriptionPanel } from "@/components/creater/edit-description-panel";
|
||||
import { EditSolutionPanel } from "@/components/creater/edit-solution-panel";
|
||||
import { EditTestcasePanel } from "@/components/creater/edit-testcase-panel";
|
||||
import { EditDetailPanel } from "@/components/creater/edit-detail-panel";
|
||||
import { EditCodePanel } from "@/components/creater/edit-code-panel";
|
||||
import { ProblemFlexLayout } from '@/features/problems/components/problem-flexlayout';
|
||||
import { EditDescriptionPanel } from '@/components/creater/edit-description-panel';
|
||||
import { EditSolutionPanel } from '@/components/creater/edit-solution-panel';
|
||||
import { EditTestcasePanel } from '@/components/creater/edit-testcase-panel';
|
||||
import { EditDetailPanel } from '@/components/creater/edit-detail-panel';
|
||||
import { EditCodePanel } from '@/components/creater/edit-code-panel';
|
||||
import { updateProblem } from '@/app/actions/updateProblem';
|
||||
|
||||
interface ProblemEditorPageProps {
|
||||
params: Promise<{ problemId: string }>;
|
||||
}
|
||||
|
||||
interface UpdateData {
|
||||
content: string;
|
||||
language?: 'c' | 'cpp';
|
||||
inputs?: Array<{ index: number; name: string; value: string }>;
|
||||
}
|
||||
|
||||
const handleUpdate = async (
|
||||
updateFn: (data: UpdateData) => Promise<{ success: boolean }>,
|
||||
data: UpdateData
|
||||
) => {
|
||||
try {
|
||||
const result = await updateFn(data);
|
||||
if (!result.success) {
|
||||
// 这里可以添加更具体的错误处理
|
||||
}
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('更新失败:', error);
|
||||
return { success: false };
|
||||
}
|
||||
};
|
||||
|
||||
export default async function ProblemEditorPage({
|
||||
params,
|
||||
}: ProblemEditorPageProps) {
|
||||
const { problemId } = await params;
|
||||
|
||||
const components: Record<string, React.ReactNode> = {
|
||||
description: <EditDescriptionPanel problemId={problemId} />,
|
||||
solution: <EditSolutionPanel problemId={problemId} />,
|
||||
detail: <EditDetailPanel problemId={problemId} />,
|
||||
code: <EditCodePanel problemId={problemId} />,
|
||||
testcase: <EditTestcasePanel problemId={problemId} />,
|
||||
description: <EditDescriptionPanel
|
||||
problemId={problemId}
|
||||
onUpdate={async (data) => {
|
||||
await handleUpdate(
|
||||
(descriptionData) => updateProblem({
|
||||
problemId,
|
||||
displayId: 0,
|
||||
description: descriptionData.content
|
||||
}),
|
||||
data
|
||||
);
|
||||
}}
|
||||
/>,
|
||||
solution: <EditSolutionPanel
|
||||
problemId={problemId}
|
||||
onUpdate={async (data) => {
|
||||
await handleUpdate(
|
||||
(solutionData) => updateProblem({
|
||||
problemId,
|
||||
displayId: 0,
|
||||
solution: solutionData.content
|
||||
}),
|
||||
data
|
||||
);
|
||||
}}
|
||||
/>,
|
||||
detail: <EditDetailPanel
|
||||
problemId={problemId}
|
||||
onUpdate={async (data) => {
|
||||
await handleUpdate(
|
||||
(detailData) => updateProblem({
|
||||
problemId,
|
||||
displayId: 0,
|
||||
detail: detailData.content
|
||||
}),
|
||||
data
|
||||
);
|
||||
}}
|
||||
/>,
|
||||
code: <EditCodePanel
|
||||
problemId={problemId}
|
||||
onUpdate={async (data) => {
|
||||
await handleUpdate(
|
||||
(codeData) => updateProblem({
|
||||
problemId,
|
||||
displayId: 0,
|
||||
templates: [{
|
||||
language: codeData.language || 'c', // 添加默认值
|
||||
content: codeData.content
|
||||
}]
|
||||
}),
|
||||
data
|
||||
);
|
||||
}}
|
||||
/>,
|
||||
testcase: <EditTestcasePanel
|
||||
problemId={problemId}
|
||||
onUpdate={async (data) => {
|
||||
await handleUpdate(
|
||||
(testcaseData) => updateProblem({
|
||||
problemId,
|
||||
displayId: 0,
|
||||
testcases: [{
|
||||
expectedOutput: testcaseData.content,
|
||||
inputs: testcaseData.inputs || [] // 添加默认空数组
|
||||
}]
|
||||
}),
|
||||
data
|
||||
);
|
||||
}}
|
||||
/>
|
||||
};
|
||||
|
||||
return (
|
||||
|
127
src/app/actions/updateProblem.ts
Normal file
127
src/app/actions/updateProblem.ts
Normal file
@ -0,0 +1,127 @@
|
||||
'use server';
|
||||
|
||||
import prisma from '@/lib/prisma';
|
||||
import { revalidatePath } from 'next/cache';
|
||||
import { z } from 'zod';
|
||||
|
||||
const ProblemUpdateSchema = z.object({
|
||||
problemId: z.string(),
|
||||
displayId: z.number().optional(), // 改回可选字段
|
||||
difficulty: z.enum(['EASY', 'MEDIUM', 'HARD']).optional(),
|
||||
isPublished: z.boolean().optional(),
|
||||
timeLimit: z.number().optional(),
|
||||
memoryLimit: z.number().optional(),
|
||||
description: z.string().optional(),
|
||||
solution: z.string().optional(),
|
||||
detail: z.string().optional(),
|
||||
templates: z.array(z.object({
|
||||
language: z.enum(['c', 'cpp']),
|
||||
content: z.string()
|
||||
})).optional(),
|
||||
testcases: z.array(z.object({
|
||||
expectedOutput: z.string(),
|
||||
inputs: z.array(z.object({
|
||||
index: z.number(),
|
||||
name: z.string(),
|
||||
value: z.string()
|
||||
}))
|
||||
})).optional()
|
||||
});
|
||||
|
||||
export type UpdateProblemData = z.infer<typeof ProblemUpdateSchema>;
|
||||
|
||||
export async function updateProblem(data: z.infer<typeof ProblemUpdateSchema>) {
|
||||
try {
|
||||
const validatedData = ProblemUpdateSchema.parse(data);
|
||||
|
||||
// 使用upsert代替update实现存在时更新,不存在时创建
|
||||
const problem = await prisma.problem.upsert({
|
||||
where: { id: validatedData.problemId },
|
||||
create: {
|
||||
id: validatedData.problemId, // 需要显式指定ID
|
||||
displayId: validatedData.displayId || 0,
|
||||
difficulty: validatedData.difficulty || 'EASY',
|
||||
isPublished: validatedData.isPublished || false,
|
||||
timeLimit: validatedData.timeLimit || 1000,
|
||||
memoryLimit: validatedData.memoryLimit || 134217728,
|
||||
// 初始化关联数据
|
||||
localizations: validatedData.description ? {
|
||||
create: [{
|
||||
locale: 'en',
|
||||
type: 'DESCRIPTION',
|
||||
content: validatedData.description
|
||||
}]
|
||||
} : undefined,
|
||||
templates: validatedData.templates ? {
|
||||
create: validatedData.templates.map(t => ({
|
||||
language: t.language,
|
||||
content: t.content
|
||||
}))
|
||||
} : undefined,
|
||||
testcases: validatedData.testcases ? {
|
||||
create: validatedData.testcases.map(t => ({
|
||||
expectedOutput: t.expectedOutput,
|
||||
inputs: {
|
||||
create: t.inputs.map(i => ({
|
||||
index: i.index,
|
||||
name: i.name,
|
||||
value: i.value
|
||||
}))
|
||||
}
|
||||
}))
|
||||
} : undefined
|
||||
},
|
||||
update: {
|
||||
displayId: validatedData.displayId,
|
||||
difficulty: validatedData.difficulty,
|
||||
isPublished: validatedData.isPublished,
|
||||
timeLimit: validatedData.timeLimit,
|
||||
memoryLimit: validatedData.memoryLimit,
|
||||
// 更新关联数据
|
||||
localizations: validatedData.description ? {
|
||||
upsert: {
|
||||
where: { problemId_locale_type: {
|
||||
problemId: validatedData.problemId,
|
||||
locale: 'en',
|
||||
type: 'DESCRIPTION'
|
||||
}},
|
||||
create: {
|
||||
locale: 'en',
|
||||
type: 'DESCRIPTION',
|
||||
content: validatedData.description
|
||||
},
|
||||
update: {
|
||||
content: validatedData.description
|
||||
}
|
||||
}
|
||||
} : undefined,
|
||||
templates: validatedData.templates ? {
|
||||
deleteMany: {},
|
||||
create: validatedData.templates.map(t => ({
|
||||
language: t.language,
|
||||
content: t.content
|
||||
}))
|
||||
} : undefined,
|
||||
testcases: validatedData.testcases ? {
|
||||
deleteMany: {},
|
||||
create: validatedData.testcases.map(t => ({
|
||||
expectedOutput: t.expectedOutput,
|
||||
inputs: {
|
||||
create: t.inputs.map(i => ({
|
||||
index: i.index,
|
||||
name: i.name,
|
||||
value: i.value
|
||||
}))
|
||||
}
|
||||
}))
|
||||
} : undefined
|
||||
}
|
||||
});
|
||||
|
||||
revalidatePath(`/problem-editor/${validatedData.problemId}`);
|
||||
return { success: true, problem };
|
||||
} catch (error) {
|
||||
console.error('Failed to update problem:', error);
|
||||
return { success: false, error: 'Failed to update problem' };
|
||||
}
|
||||
}
|
@ -14,6 +14,10 @@ interface Template {
|
||||
|
||||
interface EditCodePanelProps {
|
||||
problemId: string;
|
||||
onUpdate?: (data: {
|
||||
content: string;
|
||||
language: 'c' | 'cpp'; // 移除可选标记
|
||||
}) => void;
|
||||
}
|
||||
|
||||
export const EditCodePanel = ({
|
||||
|
@ -10,6 +10,7 @@ import {CoreEditor} from "@/components/core-editor";
|
||||
|
||||
interface EditDescriptionPanelProps {
|
||||
problemId: string;
|
||||
onUpdate?: (data: { content: string }) => void;
|
||||
}
|
||||
|
||||
export const EditDescriptionPanel = ({
|
||||
@ -65,7 +66,7 @@ export const EditDescriptionPanel = ({
|
||||
<CoreEditor
|
||||
value={content}
|
||||
onChange={setContent}
|
||||
language="markdown"
|
||||
language="``"
|
||||
className="absolute inset-0 rounded-md border border-input"
|
||||
/>
|
||||
</div>
|
||||
|
@ -8,6 +8,7 @@ import { Button } from "@/components/ui/button";
|
||||
|
||||
interface EditDetailPanelProps {
|
||||
problemId: string;
|
||||
onUpdate?: (data: { content: string }) => void;
|
||||
}
|
||||
|
||||
export const EditDetailPanel = ({
|
||||
|
@ -10,6 +10,7 @@ import {CoreEditor} from "@/components/core-editor";
|
||||
|
||||
interface EditSolutionPanelProps {
|
||||
problemId: string;
|
||||
onUpdate?: (data: { content: string }) => void;
|
||||
}
|
||||
|
||||
export const EditSolutionPanel = ({
|
||||
@ -65,7 +66,7 @@ export const EditSolutionPanel = ({
|
||||
<CoreEditor
|
||||
value={content}
|
||||
onChange={setContent}
|
||||
language="markdown"
|
||||
language="``"
|
||||
className="absolute inset-0 rounded-md border border-input"
|
||||
/>
|
||||
</div>
|
||||
|
@ -21,6 +21,10 @@ interface TestCase {
|
||||
|
||||
interface EditTestcasePanelProps {
|
||||
problemId: string;
|
||||
onUpdate?: (data: {
|
||||
content: string;
|
||||
inputs: Array<{ index: number; name: string; value: string }>
|
||||
}) => void;
|
||||
}
|
||||
|
||||
export const EditTestcasePanel = ({
|
||||
|
Loading…
Reference in New Issue
Block a user