style(frontend): 全项目表格统一百分比布局并居中
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
import type { TableColumnsType } from 'antd'
|
||||
|
||||
type Column<RecordType extends object> = TableColumnsType<RecordType>[number]
|
||||
|
||||
type WidthContext<RecordType extends object> = {
|
||||
leafPercent: WeakMap<Column<RecordType>, number>
|
||||
}
|
||||
|
||||
/**
|
||||
* 把业务列宽(px 数值)按相对权重归一化为百分比。
|
||||
* rowSelection / expandable 等内置列由调用方传入需要预留的百分比。
|
||||
*/
|
||||
export function normalizePercentColumns<RecordType extends object>(
|
||||
columns: TableColumnsType<RecordType>,
|
||||
options: { reservedPercent?: number } = {},
|
||||
): TableColumnsType<RecordType> {
|
||||
const leaves: Column<RecordType>[] = []
|
||||
collectLeaves(columns, leaves)
|
||||
|
||||
const explicitWeights = leaves
|
||||
.map((column) => numericWidth(column.width))
|
||||
.filter((width): width is number => width !== null)
|
||||
const fallbackWeight =
|
||||
explicitWeights.length > 0
|
||||
? explicitWeights.reduce((sum, width) => sum + width, 0) / explicitWeights.length
|
||||
: 100
|
||||
const totalWeight = leaves.reduce(
|
||||
(sum, column) => sum + (numericWidth(column.width) ?? fallbackWeight),
|
||||
0,
|
||||
)
|
||||
const budgetPercent = Math.max(60, 100 - Math.max(0, options.reservedPercent ?? 0))
|
||||
|
||||
const leafPercent = new WeakMap<Column<RecordType>, number>()
|
||||
for (const column of leaves) {
|
||||
const weight = numericWidth(column.width) ?? fallbackWeight
|
||||
leafPercent.set(column, (weight / totalWeight) * budgetPercent)
|
||||
}
|
||||
|
||||
return applyPercentWidths(columns, { leafPercent })
|
||||
}
|
||||
|
||||
function applyPercentWidths<RecordType extends object>(
|
||||
columns: TableColumnsType<RecordType>,
|
||||
context: WidthContext<RecordType>,
|
||||
): TableColumnsType<RecordType> {
|
||||
return columns.map((column) => {
|
||||
const children = 'children' in column ? column.children : undefined
|
||||
if (Array.isArray(children) && children.length > 0) {
|
||||
const normalizedChildren = applyPercentWidths(children, context)
|
||||
const width = normalizedChildren.reduce((sum, child) => sum + percentOf(child.width), 0)
|
||||
return {
|
||||
...column,
|
||||
width: `${width.toFixed(4)}%`,
|
||||
align: 'center',
|
||||
children: normalizedChildren,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...column,
|
||||
width: `${(context.leafPercent.get(column) ?? 0).toFixed(4)}%`,
|
||||
align: 'center',
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function collectLeaves<RecordType extends object>(
|
||||
columns: TableColumnsType<RecordType>,
|
||||
leaves: Column<RecordType>[],
|
||||
) {
|
||||
for (const column of columns) {
|
||||
const children = 'children' in column ? column.children : undefined
|
||||
if (Array.isArray(children) && children.length > 0) {
|
||||
collectLeaves(children, leaves)
|
||||
} else {
|
||||
leaves.push(column)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function numericWidth(width: Column<object>['width']) {
|
||||
if (typeof width === 'number' && Number.isFinite(width) && width > 0) return width
|
||||
if (typeof width === 'string') {
|
||||
const parsed = Number.parseFloat(width)
|
||||
if (Number.isFinite(parsed) && parsed > 0) return parsed
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function percentOf(width: Column<object>['width']) {
|
||||
if (typeof width !== 'string' || !width.endsWith('%')) return 0
|
||||
const parsed = Number.parseFloat(width)
|
||||
return Number.isFinite(parsed) ? parsed : 0
|
||||
}
|
||||
Reference in New Issue
Block a user