diff --git a/editor/components/AIPanel.vue b/editor/components/AIPanel.vue index 6344ef0..890c1bf 100644 --- a/editor/components/AIPanel.vue +++ b/editor/components/AIPanel.vue @@ -19,15 +19,9 @@ function toggleMode() { function buildMessage(userInput: string): string { if (mode.value !== 'json') return `需求: ${userInput}` - let ctx = `当前编辑文件: ${store.sourcePath}\n` - if (store.selectedScene) { - ctx += `选中场景: ${store.selectedScene.id}\n` - ctx += `当前场景 JSON:\n${JSON.stringify(store.selectedScene, null, 2)}\n\n` - } else if (Object.keys(store.gameData.scenes).length > 0) { - const { scenes, ...rest } = store.gameData - ctx += `全局配置:\n${JSON.stringify(rest, null, 2)}\n\n` - } - ctx += `需求: ${userInput}` + let ctx = `修改文件 ${store.sourcePath}` + if (store.selectedScene) ctx += `,针对场景节点 ${store.selectedScene.id}` + ctx += `。需求: ${userInput}` return ctx } @@ -51,14 +45,8 @@ async function send() { if (newSid) store.setAISessionId(newSid) if (mode.value === 'json') { - const clean = result.replace(/^```json\n?|\n?```$/g, '').trim() - try { - JSON.parse(clean) - store.setAIResult(clean) - messages.value.push({ role: 'assistant', content: '已生成 JSON,请查看编辑器面板' }) - } catch { - messages.value.push({ role: 'assistant', content: result }) - } + messages.value.push({ role: 'assistant', content: result || '已完成' }) + await store.reloadFromDisk() } else { messages.value.push({ role: 'assistant', content: result || '已完成' }) } diff --git a/editor/components/NodeEditor.vue b/editor/components/NodeEditor.vue index 92611ca..b3ef186 100644 --- a/editor/components/NodeEditor.vue +++ b/editor/components/NodeEditor.vue @@ -17,29 +17,6 @@ const store = useEditorStore() const jsonText = ref('') const errorMsg = ref('') const saved = ref(false) -const showAcceptReject = ref(false) -const preAIValue = ref('') - -watch(() => store.aiResult, (result) => { - if (!result) return - preAIValue.value = jsonText.value - jsonText.value = result - showAcceptReject.value = true - errorMsg.value = '' -}) - -function acceptAI() { - showAcceptReject.value = false - jsonText.value = jsonText.value - store.setAIResult('') - onBlur() -} - -function rejectAI() { - jsonText.value = preAIValue.value - showAcceptReject.value = false - store.setAIResult('') -} watch(() => [props.scene, store.gameData] as const, () => { errorMsg.value = '' @@ -79,11 +56,7 @@ function onBlur() {

{{ scene ? scene.id : '全局配置' }}

- - - - - 已保存 + 已保存 JSON 错误: {{ errorMsg }} @@ -175,33 +148,6 @@ function onBlur() { .icon-btn:hover { color: #ddd; border-color: rgba(255,255,255,0.25); } .icon-btn.danger:hover { color: #e74c3c; border-color: #e74c3c; } -.ai-actions { - display: flex; - gap: 4px; -} - -.ai-accept-btn { - padding: 3px 8px; - font-size: 11px; - color: #fff; - background: #4caf50; - border: none; - border-radius: 3px; - cursor: pointer; -} -.ai-accept-btn:hover { background: #388e3c; } - -.ai-reject-btn { - padding: 3px 8px; - font-size: 11px; - color: #fff; - background: #e74c3c; - border: none; - border-radius: 3px; - cursor: pointer; -} -.ai-reject-btn:hover { background: #c62828; } - .json-area { flex: 1; padding: 14px 16px; diff --git a/editor/stores/editorStore.ts b/editor/stores/editorStore.ts index f07b465..eb4792e 100644 --- a/editor/stores/editorStore.ts +++ b/editor/stores/editorStore.ts @@ -10,7 +10,6 @@ export const useEditorStore = defineStore('editor', () => { const sourcePath = ref('/scenes/demo.json') const deepseekKey = ref(localStorage.getItem('deepseek_key') || '') const showAIPanel = ref(false) - const aiResult = ref('') const aiSessionId = ref('') const selectedScene = computed(() => { @@ -142,8 +141,6 @@ export const useEditorStore = defineStore('editor', () => { function clearAISession() { aiSessionId.value = ''; localStorage.removeItem('editor_ai_session') } - function setAIResult(r: string) { aiResult.value = r } - async function autoSave() { try { await fetch('/api/save', { @@ -154,11 +151,21 @@ export const useEditorStore = defineStore('editor', () => { } catch { /* dev server not running */ } } + async function reloadFromDisk() { + try { + const resp = await fetch(sourcePath.value) + const data = await resp.json() + gameData.value = data + selectedNodeId.value = null + clearAISession() + } catch { /* failed to reload */ } + } + return { gameData, selectedNodeId, selectedScene, startSceneId, dirty, sourcePath, - deepseekKey, showAIPanel, aiResult, aiSessionId, + deepseekKey, showAIPanel, aiSessionId, markDirty, loadJSON, exportJSON, addScene, deleteScene, updateScene, addChoice, updateChoice, deleteChoice, generateId, - setSourcePath, setDeepseekKey, setAISessionId, clearAISession, setAIResult, autoSave, + setSourcePath, setDeepseekKey, setAISessionId, clearAISession, autoSave, reloadFromDisk, } }) diff --git a/vite.config.ts b/vite.config.ts index c0b0d11..2aa9044 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -80,7 +80,7 @@ function apiSavePlugin() { const modePrefix = mode === 'code' ? `当前项目根目录: ${__dirname}\n代码模式:直接修改 src/ 下的源码文件并保存。需求:` - : `当前项目根目录: ${__dirname}\nJSON模式:只返回修改后的 JSON 文本,不要写任何文件。需求:` + : `当前项目根目录: ${__dirname}\nJSON模式:直接修改 JSON 配置文件并保存,用自然语言回复修改了什么。需求:` const fullMessage = modePrefix + userMessage const args = ['run', '--model', 'deepseek/deepseek-v4-pro', '--format', 'json'] @@ -131,16 +131,8 @@ function apiSavePlugin() { } if (mode === 'json') { - const codeBlock = aiText.match(/```(?:json)?\s*\n?([\s\S]*?)\n?\s*```/) - let jsonStr = codeBlock ? codeBlock[1] : aiText - try { - JSON.parse(jsonStr) - } catch { - const bareMatch = aiText.match(/(\{[\s\S]*\}|\[[\s\S]*\])/) - jsonStr = bareMatch ? bareMatch[0] : aiText - } res.writeHead(200, { 'Content-Type': 'application/json' }) - res.end(JSON.stringify({ result: jsonStr, sessionId: resolvedSessionId || '' })) + res.end(JSON.stringify({ result: aiText || 'done', sessionId: resolvedSessionId || '' })) } else { res.writeHead(200, { 'Content-Type': 'application/json' }) res.end(JSON.stringify({ result: aiText || 'done', sessionId: resolvedSessionId || '' }))