@@ -8,7 +8,12 @@ import {
88 PieChart , Pie , Cell , Legend ,
99} from 'recharts'
1010import type { AiVisualizationSpec } from '@/types'
11- import { fieldToLabel , fmtNum , fmtQtyWithUnit , fmtFieldValue , fmtNumRaw , prepareVisualizationRows } from '@/lib/detectVisualization'
11+ import {
12+ fieldToLabel ,
13+ formatChartMetricValue ,
14+ fmtFieldValue ,
15+ prepareVisualizationRows ,
16+ } from '@/lib/detectVisualization'
1217import { getDisplayColumns , isSummarizableMetricField } from '@shared/constants/ai-field-label'
1318
1419const COLORS = [ '#D4A853' , '#52b788' , '#74c69d' , '#e76f51' , '#457b9d' , '#e9c46a' , '#a8dadc' , '#f4a261' ]
@@ -18,8 +23,14 @@ interface Props {
1823 spec : AiVisualizationSpec
1924}
2025
21- function tooltipFormatter ( value : number | string , name : string ) : [ number | string , string ] {
22- return [ typeof value === 'number' ? fmtNumRaw ( value ) : value , fieldToLabel ( name ) ]
26+ function createMetricTickFormatter ( fieldName : string , rows : Record < string , unknown > [ ] ) {
27+ return ( value : number | string ) => formatChartMetricValue ( value , fieldName , rows )
28+ }
29+
30+ function createTooltipFormatter ( fieldName : string , rows : Record < string , unknown > [ ] ) {
31+ return ( value : number | string , name : string ) : [ string , string ] => (
32+ [ formatChartMetricValue ( value , fieldName , rows ) , fieldToLabel ( name ) ]
33+ )
2334}
2435
2536function formatCellValue ( field : string , value : unknown ) : string {
@@ -43,7 +54,7 @@ function Summary({ type, rows, spec }: { type: string; rows: Record<string, unkn
4354 const minIdx = vals . indexOf ( minVal )
4455 const maxName = String ( chartRows [ maxIdx ] ?. [ spec . xField ] ?? '' )
4556 const minName = String ( chartRows [ minIdx ] ?. [ spec . xField ] ?? '' )
46- text = `共 ${ rows . length } 项,${ yLabel } 合计 ${ fmtQtyWithUnit ( total , spec . yField ! , rows [ 0 ] ?? { } , rows ) } 。最高「${ maxName } 」${ fmtQtyWithUnit ( maxVal , spec . yField ! , rows [ maxIdx ] ?? { } , rows ) } ,最低「${ minName } 」${ fmtQtyWithUnit ( minVal , spec . yField ! , rows [ minIdx ] ?? { } , rows ) } 。`
57+ text = `共 ${ rows . length } 项,${ yLabel } 合计 ${ formatChartMetricValue ( total , spec . yField ! , rows ) } 。最高「${ maxName } 」${ formatChartMetricValue ( maxVal , spec . yField ! , rows ) } ,最低「${ minName } 」${ formatChartMetricValue ( minVal , spec . yField ! , rows ) } 。`
4758 }
4859
4960 if ( type === 'line' && spec . xField && spec . yField ) {
@@ -53,7 +64,7 @@ function Summary({ type, rows, spec }: { type: string; rows: Record<string, unkn
5364 const avg = total / vals . length
5465 const firstX = String ( chartRows [ 0 ] ?. [ spec . xField ] ?? '' )
5566 const lastX = String ( chartRows [ chartRows . length - 1 ] ?. [ spec . xField ] ?? '' )
56- text = `${ firstX } →${ lastX } 共 ${ rows . length } 个周期,${ yLabel } 均值 ${ fmtQtyWithUnit ( avg , spec . yField ! , rows [ 0 ] ?? { } , rows ) } ,合计 ${ fmtQtyWithUnit ( total , spec . yField ! , rows [ 0 ] ?? { } , rows ) } 。`
67+ text = `${ firstX } →${ lastX } 共 ${ rows . length } 个周期,${ yLabel } 均值 ${ formatChartMetricValue ( avg , spec . yField ! , rows ) } ,合计 ${ formatChartMetricValue ( total , spec . yField ! , rows ) } 。`
5768 }
5869
5970 if ( type === 'pie' && spec . nameField && spec . valueField ) {
@@ -65,7 +76,7 @@ function Summary({ type, rows, spec }: { type: string; rows: Record<string, unkn
6576 const total = data . reduce ( ( s , d ) => s + d . value , 0 )
6677 const top = data [ 0 ]
6778 const topPct = total > 0 ? ( ( top . value / total ) * 100 ) . toFixed ( 1 ) : '0'
68- text = `共 ${ data . length } 类,${ yLabel } 合计 ${ fmtQtyWithUnit ( total , spec . valueField ! , rows [ 0 ] ?? { } , rows ) } 。占比最高「${ top . name } 」${ topPct } %。`
79+ text = `共 ${ data . length } 类,${ yLabel } 合计 ${ formatChartMetricValue ( total , spec . valueField ! , rows ) } 。占比最高「${ top . name } 」${ topPct } %。`
6980 }
7081
7182 if ( type === 'table' ) {
@@ -76,7 +87,7 @@ function Summary({ type, rows, spec }: { type: string; rows: Record<string, unkn
7687 if ( isSummarizableMetricField ( col , rawValues ) ) {
7788 const vals = rawValues . map ( ( value ) => Number ( value ) ) . filter ( ( v ) => ! isNaN ( v ) && v !== 0 )
7889 const colTotal = vals . reduce ( ( a , b ) => a + b , 0 )
79- numSummaries . push ( `${ fieldToLabel ( col ) } ${ fmtQtyWithUnit ( colTotal , col , rows [ 0 ] ?? { } , rows ) } ` )
90+ numSummaries . push ( `${ fieldToLabel ( col ) } ${ formatChartMetricValue ( colTotal , col , rows ) } ` )
8091 }
8192 }
8293 text = `共 ${ rows . length } 条记录。${ numSummaries . length > 0 ? '合计:' + numSummaries . join ( ',' ) + '。' : '' } `
@@ -130,8 +141,8 @@ function BarViz({ rows, xField, yField }: { rows: Record<string, unknown>[]; xFi
130141 < BarChart data = { data } margin = { { top : 6 , right : 8 , left : - 16 , bottom : 36 } } >
131142 < CartesianGrid strokeDasharray = "3 3" stroke = "hsl(var(--border))" />
132143 < XAxis dataKey = { xField } tick = { { fontSize : 10 } } angle = { - 30 } textAnchor = "end" interval = { 0 } />
133- < YAxis tick = { { fontSize : 10 } } />
134- < Tooltip formatter = { tooltipFormatter } contentStyle = { { fontSize : 12 } } />
144+ < YAxis tick = { { fontSize : 10 } } tickFormatter = { createMetricTickFormatter ( yField , rows ) } />
145+ < Tooltip formatter = { createTooltipFormatter ( yField , rows ) } contentStyle = { { fontSize : 12 } } />
135146 < Bar dataKey = { yField } name = { fieldToLabel ( yField ) } fill = "#D4A853" radius = { [ 3 , 3 , 0 , 0 ] } maxBarSize = { 40 } />
136147 </ BarChart >
137148 </ ResponsiveContainer >
@@ -146,8 +157,8 @@ function LineViz({ rows, xField, yField }: { rows: Record<string, unknown>[]; xF
146157 < LineChart data = { data } margin = { { top : 6 , right : 8 , left : - 16 , bottom : 36 } } >
147158 < CartesianGrid strokeDasharray = "3 3" stroke = "hsl(var(--border))" />
148159 < XAxis dataKey = { xField } tick = { { fontSize : 10 } } angle = { - 30 } textAnchor = "end" interval = { 0 } />
149- < YAxis tick = { { fontSize : 10 } } />
150- < Tooltip formatter = { tooltipFormatter } contentStyle = { { fontSize : 12 } } />
160+ < YAxis tick = { { fontSize : 10 } } tickFormatter = { createMetricTickFormatter ( yField , rows ) } />
161+ < Tooltip formatter = { createTooltipFormatter ( yField , rows ) } contentStyle = { { fontSize : 12 } } />
151162 < Line
152163 type = "monotone"
153164 dataKey = { yField }
@@ -164,8 +175,8 @@ function LineViz({ rows, xField, yField }: { rows: Record<string, unknown>[]; xF
164175
165176// ─── 饼图 ─────────────────────────────────────────────────────────────────────
166177function PieViz ( { rows, nameField, valueField } : { rows : Record < string , unknown > [ ] ; nameField : string ; valueField : string } ) {
167- const data = prepareVisualizationRows ( rows , nameField )
168- . map ( ( r ) => ( { name : String ( r [ nameField ] ?? '' ) , value : Number ( r [ valueField ] ) || 0 } ) )
178+ const data = prepareVisualizationRows ( rows , nameField , valueField )
179+ . map ( ( r ) => ( { ... r , name : String ( r [ nameField ] ?? '' ) , value : Number ( r [ valueField ] ) || 0 } ) )
169180 . filter ( ( d ) => d . value > 0 )
170181 const total = data . reduce ( ( s , d ) => s + d . value , 0 )
171182
@@ -187,7 +198,7 @@ function PieViz({ rows, nameField, valueField }: { rows: Record<string, unknown>
187198 < Cell key = { i } fill = { COLORS [ i % COLORS . length ] } />
188199 ) ) }
189200 </ Pie >
190- < Tooltip formatter = { ( v : number ) => [ fmtNum ( v ) ] } />
201+ < Tooltip formatter = { ( value : number | string ) => [ formatChartMetricValue ( value , valueField , rows ) , fieldToLabel ( valueField ) ] } />
191202 < Legend iconSize = { 10 } wrapperStyle = { { fontSize : 11 } } />
192203 </ PieChart >
193204 </ ResponsiveContainer >
0 commit comments