fix(图表): 修复明细表基础样式勾选“自动换行”后,会出现表头部分部分信息不显示的问题 #16804

This commit is contained in:
jianneng-fit2cloud
2025-09-04 13:55:50 +08:00
committed by jianneng-fit2cloud
parent 4e482fc860
commit 84f4a7386f
2 changed files with 184 additions and 40 deletions

View File

@@ -16,21 +16,22 @@ import { TABLE_EDITOR_PROPERTY, TABLE_EDITOR_PROPERTY_INNER } from './common'
import { useI18n } from '@/hooks/web/useI18n'
import { filter, isEqual, isNumber, merge } from 'lodash-es'
import {
calcTreeWidth,
calculateGroupHeaderHeight,
calculateHeaderHeight,
configEmptyDataStyle,
copyContent,
CustomDataCell,
CustomTableColCell,
getRowIndex,
calculateHeaderHeight,
SortTooltip,
configEmptyDataStyle,
getLeafNodes,
getColumns,
drawImage,
getColumns,
getLeafNodes,
getRowIndex,
getStartPosition,
getSummaryRow,
SortTooltip,
SummaryCell,
summaryRowStyle,
calcTreeWidth,
getStartPosition
summaryRowStyle
} from '@/views/chart/components/js/panel/common/common_table'
const { t } = useI18n()
@@ -236,28 +237,48 @@ export class TableInfo extends S2ChartView<TableSheet> {
summaryRowStyle(newChart, newData, tableCell, tableHeader, basicStyle.showSummary)
// 开启自动换行
if (basicStyle.autoWrap && !tableCell.mergeCells) {
// 调整表头宽度时,计算表头高度
// 记录调整列宽的信息
const setResizeColWidthInfo = (info?) => {
newChart.store.set('resizeColWidthInfo', info ? info : undefined)
}
setResizeColWidthInfo()
// 计算分组表头的高度
newChart.on(S2Event.LAYOUT_BEFORE_RENDER, () => {
calculateGroupHeaderHeight(newChart, tableHeader, basicStyle)
setResizeColWidthInfo()
})
// 调整行高不能小于初始行高
newChart.on(S2Event.LAYOUT_RESIZE_COL_HEIGHT, info => {
if (info.info.resizedHeight < newChart.options.style.colCfg.height) {
info.style.colCfg.heightByField[info.info.id] = newChart.options.style.colCfg.height
}
})
// 调整表头单元格宽度时,计算表头高度
newChart.on(S2Event.LAYOUT_RESIZE_COL_WIDTH, info => {
setResizeColWidthInfo(info.info)
calculateHeaderHeight(info, newChart, tableHeader, basicStyle, null)
})
newChart.on(S2Event.LAYOUT_AFTER_HEADER_LAYOUT, (ev: LayoutResult) => {
const maxHeight = newChart.store.get('autoCalcHeight') as number
if (maxHeight) {
// 更新列的高度
ev.colLeafNodes.forEach(n => (n.height = maxHeight))
ev.colsHierarchy.height = maxHeight
newChart.store.set('autoCalcHeight', undefined)
} else {
if (ev.colLeafNodes?.length) {
const { value, width } = ev.colLeafNodes[0]
calculateHeaderHeight(
{ info: { meta: { value }, resizedWidth: width } },
newChart,
tableHeader,
basicStyle,
ev
)
}
if (ev.colLeafNodes?.length) {
const { value, width } = ev.colLeafNodes[0]
calculateHeaderHeight(
{ info: { meta: { value }, resizedWidth: width } },
newChart,
tableHeader,
basicStyle,
ev
)
}
if (tableHeader.headerGroup) {
const groupHeight = ev.colNodes.filter(node => node.colIndex === -1)?.[0]?.height || 0
ev.colsHierarchy.height =
ev.colsHierarchy.height + ev.colsHierarchy.maxLevel * groupHeight
ev.colLeafNodes.forEach(node => {
if (node.level < ev.colsHierarchy.maxLevel) {
const addHeight = ev.colsHierarchy.maxLevel - node.level
node.height = node.height + addHeight * groupHeight
}
})
}
})
}

View File

@@ -59,7 +59,8 @@ import {
repeat,
sumBy,
size,
sum
sum,
isNumber
} from 'lodash-es'
import { createVNode, render } from 'vue'
import TableTooltip from '@/views/chart/components/editor/common/TableTooltip.vue'
@@ -69,7 +70,6 @@ import { ElMessage } from 'element-plus-secondary'
import { useI18n } from '@/hooks/web/useI18n'
import Decimal from 'decimal.js'
const { t: i18nt } = useI18n()
export function getCustomTheme(chart: Chart): S2Theme {
@@ -1874,10 +1874,15 @@ export async function exportRowQuotaTreePivot(instance: PivotSheet, chart: Chart
saveAs(dataBlob, `${chart.title ?? '透视表'}.xlsx`)
}
function extractNumber(formattedValue: string, formatterCfg: BaseFormatter): {
value: number
numFmt: string
} | string {
function extractNumber(
formattedValue: string,
formatterCfg: BaseFormatter
):
| {
value: number
numFmt: string
}
| string {
if (!formatterCfg) {
return formattedValue
}
@@ -2255,9 +2260,9 @@ const drawTextShape = (cell, isHeader) => {
cell.actualTextWidth = cell.spreadsheet.measureTextWidth(wrapText, textStyle)
// 获取文本位置并渲染文本
const position = cell.getTextPosition()
const { x, y } = cell.getTextAndIconPosition()?.text || cell.getTextPosition()
// 绘制文本
cell.textShape = renderText(cell, [cell.textShape], position.x, position.y, wrapText, textStyle, {
cell.textShape = renderText(cell, [cell.textShape], x, y, wrapText, textStyle, {
fontSize: extraStyleFontSize
})
@@ -2312,8 +2317,6 @@ export const calculateHeaderHeight = (info, newChart, tableHeader, basicStyle, l
ev.colLeafNodes.forEach(n => (n.height = maxHeight))
ev.colsHierarchy.height = maxHeight
}
newChart.store.set('autoCalcHeight', maxHeight)
}
/**
@@ -2450,7 +2453,10 @@ export function getSummaryRow(data, axis, sumCon = []) {
})
// 计算方差(平方差的平均值)
const variance = squaredDeviations.reduce((acc, val) => acc.plus(val), new Decimal(0))
summaryObj[a] = variance.dividedBy(data.length - 1).sqrt().toNumber() // 计算总体标准差
summaryObj[a] = variance
.dividedBy(data.length - 1)
.sqrt()
.toNumber() // 计算总体标准差
}
break
}
@@ -2460,7 +2466,6 @@ export function getSummaryRow(data, axis, sumCon = []) {
return summaryObj
}
export class SummaryCell extends CustomDataCell {
getTextStyle() {
const textStyle = cloneDeep(this.theme.colCell.bolderText)
@@ -2568,7 +2573,6 @@ export function drawImage() {
}
}
export function calcTreeWidth(node) {
if (!node.children?.length) {
return node.width
@@ -2615,3 +2619,122 @@ export function summaryRowStyle(newChart, newData, tableCell, tableHeader, showS
}
})
}
/**
* 计算分组表头高度
* @param newChart
* @param tableHeader
* @param basicStyle
*/
export const calculateGroupHeaderHeight = (newChart, tableHeader, basicStyle) => {
let maxGroupHeight = 0
// 获取分组名字最长的列
const maxNameMeta = newChart.dataCfg?.meta
?.filter(item => !item.field.startsWith('f_'))
?.reduce((max, cur) => (cur.name.length > (max?.name.length ?? 0) ? cur : max), null)
if (maxNameMeta) {
let colWidth = basicStyle.tableColumnWidth
const maxNameColumn = findNodeByKey(newChart.dataCfg.fields.columns, maxNameMeta.field)
const maxNameColumns = []
if (maxNameColumn) {
maxNameColumns.push(maxNameColumn)
}
const { resizedWidth, meta } = newChart.store.get('resizeColWidthInfo') || {
resizedWidth: 0,
width: 0
}
const leafKeys = getLeafKeys(maxNameColumns)
if (basicStyle.tableFieldWidth.length > 0) {
colWidth = 0
const fieldWidth = basicStyle.tableFieldWidth
// fieldWidth中对象的key在leafKeys时对fieldWidth中对象的width求和
fieldWidth.forEach(fw => {
// 调整单元格宽度时,排除掉当前调整的列,使用调整后的宽度
if (
leafKeys.filter(key => meta?.key !== key).includes(fw.fieldId) &&
isNumber(fw.width) &&
fw.width > 0
) {
colWidth += fw.width
}
})
}
if (basicStyle.tableColumnMode === 'custom') {
colWidth = basicStyle.tableColumnWidth * (leafKeys.length === 0 ? 1 : leafKeys.length) || 100
} else {
colWidth =
(newChart.facet?.cfg?.width ? newChart.facet.cfg.width : newChart.options.width) *
(colWidth / 100)
}
// 计算分组表头的高度
if (colWidth > 0) {
colWidth = colWidth + resizedWidth
const nodeHeight = calculateGroupHeaderMaxTextHeight(
{ info: { name: maxNameMeta.name, resizedWidth: colWidth } },
newChart,
tableHeader,
basicStyle,
null
)
maxGroupHeight = Math.max(maxGroupHeight, nodeHeight)
}
if (maxGroupHeight > 0) {
newChart.options.style.colCfg.height = maxGroupHeight
}
}
}
// 获取最里层的叶子节点
const getLeafKeys = (columns: any[]): string[] => {
const keys: string[] = []
columns.forEach(col => {
if (col && typeof col === 'object' && Array.isArray(col.children) && col.children.length > 0) {
keys.push(...getLeafKeys(col.children))
} else if (col && typeof col === 'object' && col.key) {
keys.push(col.key)
}
})
return keys
}
// 根据 key 查找节点
const findNodeByKey = (columns: any[], key: string): any | null => {
for (const col of columns) {
if (col.key === key) return col
if (col.children) {
const found = findNodeByKey(col.children, key)
if (found) return found
}
}
return null
}
/**
* 计算分组表头最大文本高度
* @param info
* @param newChart
* @param tableHeader
* @param basicStyle
* @param _layoutResult
*/
const calculateGroupHeaderMaxTextHeight = (
info,
newChart,
tableHeader,
basicStyle,
_layoutResult
) => {
if (tableHeader.showTableHeader === false) return
const maxLines = basicStyle.maxLines ?? 1
const textStyle = { ...newChart.theme.cornerCell.text, fontSize: tableHeader.tableTitleFontSize }
const sourceText = info.info.name
return (
getWrapTextHeight(
getWrapText(sourceText, textStyle, info.info.resizedWidth, newChart),
textStyle,
newChart,
maxLines
) +
textStyle.fontSize +
10.5
)
}