mirror of
https://github.com/cfngc4594/monaco-editor-lsp-next.git
synced 2025-07-04 01:10:53 +00:00
feat(problem-editor): optimize ai-optimized-editor button and store
-将 AIEditorWrapper 组件集成到 ProblemEditor 中 - 添加 AIOptimizeButton 组件到代码工具栏 - 更新 problem-editor store,增加 useAIEditor 和 loading 状态 - 调整 ProblemEditor 组件,根据 useAIEditor状态切换编辑器
This commit is contained in:
parent
fdbc1f06b2
commit
ac67ad26a1
@ -4,25 +4,24 @@ import React, { useState, useEffect } from "react";
|
|||||||
import { DiffEditor } from "@monaco-editor/react";
|
import { DiffEditor } from "@monaco-editor/react";
|
||||||
import { useMonacoTheme } from "@/hooks/use-monaco-theme";
|
import { useMonacoTheme } from "@/hooks/use-monaco-theme";
|
||||||
import { optimizeCode } from "@/app/actions/ai-improve";
|
import { optimizeCode } from "@/app/actions/ai-improve";
|
||||||
import { AIOptimizeButton } from "@/features/problems/code/components/toolbar/actions/AIOptimizeButton";
|
import { useProblemEditorStore } from "@/stores/problem-editor";
|
||||||
|
// import {LanguageServerConfig} from "@/generated/client";
|
||||||
|
// import type {editor} from "monaco-editor";
|
||||||
|
|
||||||
interface AIEditorWrapperProps {
|
export const AIEditorWrapper = (
|
||||||
language: string;
|
) => {
|
||||||
originalCode: string;
|
const {
|
||||||
onReset: () => void;
|
language,
|
||||||
}
|
value: originalCode,
|
||||||
|
// setUseAIEditor,
|
||||||
|
setLoading,
|
||||||
|
} = useProblemEditorStore();
|
||||||
|
|
||||||
export const AIEditorWrapper = ({ language, originalCode, onReset }: AIEditorWrapperProps) => {
|
|
||||||
const [optimizedCode, setOptimizedCode] = useState<string>("");
|
const [optimizedCode, setOptimizedCode] = useState<string>("");
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
const { theme } = useMonacoTheme();
|
const { theme } = useMonacoTheme();
|
||||||
|
|
||||||
// 自动在组件首次挂载后执行 AI 优化
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!optimizedCode) {
|
handleOptimize();
|
||||||
handleOptimize();
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleOptimize = async () => {
|
const handleOptimize = async () => {
|
||||||
@ -42,27 +41,8 @@ export const AIEditorWrapper = ({ language, originalCode, onReset }: AIEditorWra
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClick = () => {
|
|
||||||
if (optimizedCode) {
|
|
||||||
// 已有优化,点击返回
|
|
||||||
setOptimizedCode("");
|
|
||||||
onReset();
|
|
||||||
} else {
|
|
||||||
// 手动触发优化(如果需要)
|
|
||||||
handleOptimize();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-[80vh] flex flex-col gap-4">
|
<div className="w-full h-[80vh] flex flex-col gap-4">
|
||||||
<div>
|
|
||||||
<AIOptimizeButton
|
|
||||||
loading={loading}
|
|
||||||
hasOptimized={!!optimizedCode}
|
|
||||||
onClick={handleClick}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{optimizedCode && (
|
{optimizedCode && (
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<DiffEditor
|
<DiffEditor
|
||||||
@ -71,7 +51,11 @@ export const AIEditorWrapper = ({ language, originalCode, onReset }: AIEditorWra
|
|||||||
modified={optimizedCode}
|
modified={optimizedCode}
|
||||||
height="100%"
|
height="100%"
|
||||||
theme={theme}
|
theme={theme}
|
||||||
options={{ readOnly: true, renderSideBySide: true, automaticLayout: true }}
|
options={{
|
||||||
|
readOnly: true,
|
||||||
|
renderSideBySide: true,
|
||||||
|
automaticLayout: true,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { CoreEditor } from "@/components/core-editor";
|
import { CoreEditor } from "@/components/core-editor";
|
||||||
import { useProblemEditorStore } from "@/stores/problem-editor";
|
import { useProblemEditorStore } from "@/stores/problem-editor";
|
||||||
import type { LanguageServerConfig, Template } from "@/generated/client";
|
import type { LanguageServerConfig, Template } from "@/generated/client";
|
||||||
@ -26,9 +26,10 @@ export const ProblemEditor = ({
|
|||||||
setEditor,
|
setEditor,
|
||||||
setLspWebSocket,
|
setLspWebSocket,
|
||||||
setMarkers,
|
setMarkers,
|
||||||
|
useAIEditor,
|
||||||
|
// setUseAIEditor
|
||||||
} = useProblemEditorStore();
|
} = useProblemEditorStore();
|
||||||
|
|
||||||
const [useAIEditor, setUseAIEditor] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setProblem(problemId, templates);
|
setProblem(problemId, templates);
|
||||||
@ -38,12 +39,12 @@ export const ProblemEditor = ({
|
|||||||
<div className="w-full h-[85vh] relative">
|
<div className="w-full h-[85vh] relative">
|
||||||
{!useAIEditor ? (
|
{!useAIEditor ? (
|
||||||
<>
|
<>
|
||||||
<button
|
{/*<button*/}
|
||||||
className="absolute right-4 top-4 bg-blue-600 text-white px-3 py-1 rounded z-10"
|
{/* className="absolute right-4 top-4 bg-blue-600 text-white px-3 py-1 rounded z-10"*/}
|
||||||
onClick={() => setUseAIEditor(true)}
|
{/* onClick={() => setUseAIEditor(true)}*/}
|
||||||
>
|
{/*>*/}
|
||||||
AI 优化代码
|
{/* AI 优化代码*/}
|
||||||
</button>
|
{/*</button>*/}
|
||||||
<CoreEditor
|
<CoreEditor
|
||||||
language={language}
|
language={language}
|
||||||
value={value}
|
value={value}
|
||||||
@ -57,11 +58,7 @@ export const ProblemEditor = ({
|
|||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<AIEditorWrapper
|
<AIEditorWrapper/>
|
||||||
language={language}
|
|
||||||
originalCode={value}
|
|
||||||
onReset={() => setUseAIEditor(false)}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { TooltipButton } from "@/components/tooltip-button";
|
||||||
|
import { Wand2Icon, LoaderCircleIcon, Undo2Icon } from "lucide-react";
|
||||||
|
import { useProblemEditorStore } from "@/stores/problem-editor";
|
||||||
|
|
||||||
|
export const AIOptimizeButton = () => {
|
||||||
|
const { useAIEditor, setUseAIEditor, loading } = useProblemEditorStore();
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
if (!loading) {
|
||||||
|
setUseAIEditor(!useAIEditor);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const tooltipContent = loading
|
||||||
|
? "AI 正在优化中…"
|
||||||
|
: useAIEditor
|
||||||
|
? "返回原始编辑器"
|
||||||
|
: "使用 AI 优化代码";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TooltipButton
|
||||||
|
tooltipContent={tooltipContent}
|
||||||
|
onClick={handleClick}
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
{loading ? (
|
||||||
|
<LoaderCircleIcon
|
||||||
|
className="opacity-60 animate-spin"
|
||||||
|
size={16}
|
||||||
|
strokeWidth={2}
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
) : useAIEditor ? (
|
||||||
|
<Undo2Icon size={16} strokeWidth={2} aria-hidden="true" />
|
||||||
|
) : (
|
||||||
|
<Wand2Icon size={16} strokeWidth={2} aria-hidden="true" />
|
||||||
|
)}
|
||||||
|
</TooltipButton>
|
||||||
|
);
|
||||||
|
};
|
@ -9,6 +9,7 @@ import {
|
|||||||
} from "@/features/problems/code/components/toolbar";
|
} from "@/features/problems/code/components/toolbar";
|
||||||
import { AnalyzeButton } from "./actions/analyze-button";
|
import { AnalyzeButton } from "./actions/analyze-button";
|
||||||
import { LspConnectionIndicator } from "./controls/lsp-connection-indicator";
|
import { LspConnectionIndicator } from "./controls/lsp-connection-indicator";
|
||||||
|
import {AIOptimizeButton} from "@/features/problems/code/components/toolbar/actions/AIOptimizeButton";
|
||||||
|
|
||||||
interface CodeToolbarProps {
|
interface CodeToolbarProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
@ -25,6 +26,7 @@ export const CodeToolbar = async ({ className }: CodeToolbarProps) => {
|
|||||||
<LspConnectionIndicator />
|
<LspConnectionIndicator />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
|
<AIOptimizeButton />
|
||||||
<AnalyzeButton />
|
<AnalyzeButton />
|
||||||
<ResetButton />
|
<ResetButton />
|
||||||
<UndoButton />
|
<UndoButton />
|
||||||
|
@ -16,6 +16,8 @@ type ProblemEditorState = {
|
|||||||
editor: editor.IStandaloneCodeEditor | null;
|
editor: editor.IStandaloneCodeEditor | null;
|
||||||
lspWebSocket: WebSocket | null;
|
lspWebSocket: WebSocket | null;
|
||||||
markers: editor.IMarker[];
|
markers: editor.IMarker[];
|
||||||
|
useAIEditor: boolean;
|
||||||
|
loading: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ProblemEditorAction = {
|
type ProblemEditorAction = {
|
||||||
@ -26,6 +28,8 @@ type ProblemEditorAction = {
|
|||||||
setEditor: (editor: editor.IStandaloneCodeEditor) => void;
|
setEditor: (editor: editor.IStandaloneCodeEditor) => void;
|
||||||
setLspWebSocket: (lspWebSocket: WebSocket) => void;
|
setLspWebSocket: (lspWebSocket: WebSocket) => void;
|
||||||
setMarkers: (markers: editor.IMarker[]) => void;
|
setMarkers: (markers: editor.IMarker[]) => void;
|
||||||
|
setUseAIEditor: (flag: boolean) => void;
|
||||||
|
setLoading: (flag: boolean) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ProblemEditorStore = ProblemEditorState & ProblemEditorAction;
|
type ProblemEditorStore = ProblemEditorState & ProblemEditorAction;
|
||||||
@ -38,6 +42,10 @@ export const useProblemEditorStore = create<ProblemEditorStore>((set, get) => ({
|
|||||||
editor: null,
|
editor: null,
|
||||||
lspWebSocket: null,
|
lspWebSocket: null,
|
||||||
markers: [],
|
markers: [],
|
||||||
|
useAIEditor: false,
|
||||||
|
loading: false,
|
||||||
|
setLoading: (loading) => set({loading}),
|
||||||
|
setUseAIEditor: (loading) => set({ useAIEditor: loading }),
|
||||||
setProblem: (problemId, templates) => {
|
setProblem: (problemId, templates) => {
|
||||||
const language = getLanguage(problemId);
|
const language = getLanguage(problemId);
|
||||||
const value = getValue(problemId, language, templates);
|
const value = getValue(problemId, language, templates);
|
||||||
|
Loading…
Reference in New Issue
Block a user