feat(web): AI对话框增加图表显示
支持Mermaid、EChart、Chart.js
This commit is contained in:
@@ -14,15 +14,21 @@
|
||||
"@ant-design/x": "^1.4.0",
|
||||
"@echofly/fetch-event-source": "^3.0.2",
|
||||
"@fortawesome/fontawesome-free": "^6.7.2",
|
||||
"@lightenna/react-mermaid-diagram": "^1.0.20",
|
||||
"@tinyflow-ai/react": "^0.1.10",
|
||||
"ahooks": "^3.8.5",
|
||||
"amis": "^6.12.0",
|
||||
"antd": "^5.25.3",
|
||||
"axios": "^1.9.0",
|
||||
"chart.js": "^4.4.9",
|
||||
"echarts-for-react": "^3.0.2",
|
||||
"licia": "^1.48.0",
|
||||
"markdown-it": "^14.1.0",
|
||||
"mermaid": "^11.6.0",
|
||||
"react": "^18.3.1",
|
||||
"react-chartjs-2": "^5.3.0",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-markdown": "^10.1.0",
|
||||
"react-router": "^7.6.1",
|
||||
"styled-components": "^6.1.18"
|
||||
},
|
||||
|
||||
1585
service-web/client/pnpm-lock.yaml
generated
1585
service-web/client/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
129
service-web/client/src/pages/Test.tsx
Normal file
129
service-web/client/src/pages/Test.tsx
Normal file
@@ -0,0 +1,129 @@
|
||||
import MarkdownRender from '../util/Markdown.tsx'
|
||||
import {useState} from 'react'
|
||||
|
||||
// language=Markdown
|
||||
const markdownText = `### Hello
|
||||
|
||||
world
|
||||
tony
|
||||
jenny
|
||||
|
||||
\`\`\`javascript
|
||||
console.log('hello')
|
||||
\`\`\`
|
||||
|
||||
\`\`\`mermaid
|
||||
graph TD
|
||||
a-->b;
|
||||
\`\`\`
|
||||
|
||||
\`\`\`mermaid
|
||||
graph TD
|
||||
c-->d;
|
||||
\`\`\`
|
||||
|
||||
\`\`\`chartjs
|
||||
{
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: ['苹果', '香蕉', '橙子', '葡萄', '菠萝'],
|
||||
datasets: [{
|
||||
label: '水果销量',
|
||||
data: [43, 32, 56, 29, 38],
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
plugins: {
|
||||
legend: {
|
||||
position: 'top',
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: '水果店周销量数据'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
\`\`\`chartjs
|
||||
{
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: ['苹果', '香蕉', '橙子', '葡萄', '菠萝'],
|
||||
datasets: [{
|
||||
label: '水果销量',
|
||||
data: [43, 32, 56, 29, 38],
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
plugins: {
|
||||
legend: {
|
||||
position: 'top',
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: '水果店周销量数据'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
\`\`\`echart
|
||||
{
|
||||
grid: { top: 8, right: 8, bottom: 24, left: 36 },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: [820, 932, 901, 934, 1290, 1330, 1320],
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
},
|
||||
],
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
},
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
\`\`\`echart
|
||||
{
|
||||
grid: { top: 8, right: 8, bottom: 24, left: 36 },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: [820, 932, 901, 934, 1290, 1330, 1320],
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
},
|
||||
],
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
},
|
||||
}
|
||||
\`\`\``
|
||||
|
||||
function Test() {
|
||||
const [value, setValue] = useState<string>(markdownText)
|
||||
return (
|
||||
<>
|
||||
<button onClick={() => setValue('hahaha\n' + markdownText)}>Button</button>
|
||||
<MarkdownRender content={value}/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Test
|
||||
@@ -30,6 +30,7 @@ import Version from './pages/overview/Version.tsx'
|
||||
import Yarn from './pages/overview/Yarn.tsx'
|
||||
import YarnCluster from './pages/overview/YarnCluster.tsx'
|
||||
import {commonInfo} from './util/amis.tsx'
|
||||
import Test from './pages/Test.tsx'
|
||||
|
||||
export const routes: RouteObject[] = [
|
||||
{
|
||||
@@ -109,6 +110,10 @@ export const routes: RouteObject[] = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'test',
|
||||
Component: Test,
|
||||
}
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
50
service-web/client/src/util/Markdown.tsx
Normal file
50
service-web/client/src/util/Markdown.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
import 'chart.js/auto'
|
||||
import {trim} from 'licia'
|
||||
import {MermaidDiagram} from '@lightenna/react-mermaid-diagram'
|
||||
import {Chart} from 'react-chartjs-2'
|
||||
import EChartsReact from 'echarts-for-react'
|
||||
import Markdown from 'react-markdown'
|
||||
|
||||
type MarkdownOptions = {
|
||||
content: string
|
||||
}
|
||||
|
||||
function MarkdownRender(options: MarkdownOptions) {
|
||||
return (
|
||||
<Markdown
|
||||
children={options.content}
|
||||
components={{
|
||||
code: ({children, className, node, ...rest}) => {
|
||||
switch (trim(className || '')) {
|
||||
case 'language-mermaid':
|
||||
return (
|
||||
<MermaidDiagram
|
||||
children={children as string}
|
||||
/>
|
||||
)
|
||||
case 'language-chartjs':
|
||||
let chartjsData = eval(`(${children as string})`)
|
||||
return (
|
||||
<Chart
|
||||
{...chartjsData}
|
||||
/>
|
||||
)
|
||||
case 'language-echart':
|
||||
let echartData = eval(`(${children as string})`)
|
||||
return (
|
||||
<EChartsReact option={echartData}/>
|
||||
)
|
||||
default:
|
||||
return (
|
||||
<code {...rest} className={className}>
|
||||
{children}
|
||||
</code>
|
||||
)
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default MarkdownRender
|
||||
1
service-web/client/src/vite-env.d.ts
vendored
1
service-web/client/src/vite-env.d.ts
vendored
@@ -1 +0,0 @@
|
||||
/// <reference types="vite/client" />
|
||||
Reference in New Issue
Block a user