From d2ecbec16ab9d7768b8d07a93d22816507d81833 Mon Sep 17 00:00:00 2001
From: hongjli <3117313295@qq.com>
Date: 星期日, 27 四月 2025 20:52:14 +0800
Subject: [PATCH] 渲染echarts图优化
---
src/app/chat/page.tsx | 95 ++++++++++++++++++++++++++++-------------------
1 files changed, 57 insertions(+), 38 deletions(-)
diff --git a/src/app/chat/page.tsx b/src/app/chat/page.tsx
index e4d65cd..5530946 100644
--- a/src/app/chat/page.tsx
+++ b/src/app/chat/page.tsx
@@ -1,6 +1,6 @@
'use client';
-import { useState, useEffect, useRef, useCallback } from 'react';
+import { useState, useEffect, useRef, useCallback, useContext, createContext } from 'react';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import Image from 'next/image';
@@ -10,6 +10,9 @@
import rehypeSanitize from 'rehype-sanitize';
import dynamic from 'next/dynamic';
import { ReactNode } from 'react';
+
+// 鍒涘缓涓�涓秷鎭畬鎴愮姸鎬佺殑Context
+const MessageCompletionContext = createContext<boolean>(true);
// 鍔ㄦ�佸鍏� ECharts锛岀‘淇濆畠鍙湪瀹㈡埛绔覆鏌�
const ReactECharts = dynamic(() => import('echarts-for-react'), { ssr: false });
@@ -272,27 +275,41 @@
// 淇敼浠g爜鍧楁覆鏌撶粍浠讹紝娣诲姞鏇村ソ鐨勭被鍨嬫娴�
function CodeBlockRenderer({ language, value }: { language: string; value: string }) {
- // 鏇寸簿纭湴妫�娴婨Charts浠g爜
- const isEchartsCode = () => {
+ // 鍒ゆ柇鏄惁鏄疛avaScript浠g爜锛屾娴嬫槸鍚﹀寘鍚浘琛ㄧ浉鍏崇壒寰�
+ const isEchartsCode = useCallback(() => {
if (language !== 'javascript') return false;
// 妫�鏌ユ槸鍚﹀寘鍚獷Charts鐗规湁鐨勯厤缃」
- const hasEchartsConfig =
- value.includes('option =') ||
- value.includes('const option') ||
- value.includes('let option') ||
- value.includes('series') &&
- (value.includes('type:') || value.includes('tooltip:') || value.includes('xAxis:'));
-
- return hasEchartsConfig;
- };
+ return value.includes('option') &&
+ (value.includes('series') ||
+ value.includes('chart') ||
+ value.includes('echarts') ||
+ value.includes('xAxis') ||
+ value.includes('yAxis'));
+ }, [language, value]);
- // 濡傛灉鏄� ECharts 浠g爜鍒欐覆鏌撳浘琛�
- if (isEchartsCode()) {
+ // 妫�鏌ユ秷鎭槸鍚﹀畬鏁� - 閫氳繃鐖剁粍浠朵紶閫掔殑isMessageComplete鐘舵��
+ const isComplete = useContext(MessageCompletionContext);
+
+ // 鍦ㄦ秷鎭湭瀹屾垚鏃舵樉绀哄姞杞藉姩鐢�
+ if (language === 'javascript' && !isComplete) {
+ return (
+ <div className="w-full bg-gray-50 rounded-md my-4 p-6 text-center">
+ <div className="flex flex-col items-center justify-center">
+ <div className="animate-spin rounded-full h-8 w-8 border-t-2 border-b-2 border-gray-400 mb-4"></div>
+ <p className="text-gray-500">浠g爜鍔犺浇涓�...</p>
+ <p className="text-xs text-gray-400 mt-2">绛夊緟娑堟伅瀹屾垚鍚庡皢娓叉煋鍥捐〃</p>
+ </div>
+ </div>
+ );
+ }
+
+ // 娑堟伅瀹屾垚鍚庯紝濡傛灉鏄浘琛ㄤ唬鐮佸垯娓叉煋涓哄浘琛�
+ if (isEchartsCode() && isComplete) {
return <EchartsRenderer code={value} />;
}
- // 鍚﹀垯鎸夋櫘閫氫唬鐮佸潡娓叉煋
+ // 鏅�欽avaScript浠g爜鎴栧叾浠栬瑷�鐨勪唬鐮佸潡锛岀洿鎺ユ樉绀轰唬鐮�
return (
<div className="bg-gray-800 rounded-md my-2 overflow-hidden">
<div className="flex items-center justify-between px-4 py-2 border-b border-gray-700">
@@ -1004,30 +1021,32 @@
<div className="p-3">
<div className="text-gray-800 leading-relaxed">
{mainContent ? (
- <ReactMarkdown
- remarkPlugins={[remarkGfm]}
- rehypePlugins={[rehypeRaw, rehypeSanitize]}
- components={{
- // @ts-ignore - ReactMarkdown 缁勪欢绫诲瀷瀹氫箟鐨勫吋瀹规�ч棶棰�
- code: ({ node, inline, className, children, ...props }) => {
- const match = /language-(\w+)/.exec(className || '');
- const language = match ? match[1] : '';
- const value = String(children).replace(/\n$/, '');
-
- if (!inline && match) {
- return <CodeBlockRenderer language={language} value={value} />;
+ <MessageCompletionContext.Provider value={isMessageComplete && msg.id === currentMessageId}>
+ <ReactMarkdown
+ remarkPlugins={[remarkGfm]}
+ rehypePlugins={[rehypeRaw, rehypeSanitize]}
+ components={{
+ // @ts-ignore - ReactMarkdown 缁勪欢绫诲瀷瀹氫箟鐨勫吋瀹规�ч棶棰�
+ code: ({ node, inline, className, children, ...props }) => {
+ const match = /language-(\w+)/.exec(className || '');
+ const language = match ? match[1] : '';
+ const value = String(children).replace(/\n$/, '');
+
+ if (!inline && match) {
+ return <CodeBlockRenderer language={language} value={value} />;
+ }
+
+ return (
+ <code className={className} {...props}>
+ {children}
+ </code>
+ );
}
-
- return (
- <code className={className} {...props}>
- {children}
- </code>
- );
- }
- }}
- >
- {mainContent}
- </ReactMarkdown>
+ }}
+ >
+ {mainContent}
+ </ReactMarkdown>
+ </MessageCompletionContext.Provider>
) : (
msg.role === 'assistant' && !isMessageComplete ? '澶勭悊鍥炲涓�...' : ''
)}
--
Gitblit v1.9.3