Commit ba8d2186 authored by Andy-bubu's avatar Andy-bubu

feat: sync data grid headers with view config

parent 426a2639
......@@ -21,7 +21,7 @@ import {
} from '@/components/AppIcons';
import FilterSelect from '@/components/FilterSelect';
import FormDatePicker from '@/components/FormDatePicker';
import { formatFieldValue, getFieldValue } from '@/utils/subjectView';
import { formatFieldValue, getFieldValue, normalizeText } from '@/utils/subjectView';
import {
Alert,
Button,
......@@ -155,8 +155,16 @@ function buildColumnGroupMeta(columnGroups = [], columns = []) {
return {
...group,
id,
name: group?.name || id,
name:
normalizeText(group?.label) ||
normalizeText(group?.title) ||
normalizeText(group?.name) ||
id,
children,
columnLabels: children.map((field) => {
const column = columns.find((item) => item.field === field);
return String(column?.label || field).trim();
}),
};
})
.filter((group) => group.children.length > 0);
......@@ -331,28 +339,65 @@ function getWorkbenchColumnWidth(column, stickyMeta) {
return Math.min(readableWidth, 280);
}
function ColumnGroupControl({ group, collapsed, index, onToggle }) {
function ColumnGroupControl({
group,
collapsed,
index,
onPreviewChange,
onToggle,
}) {
const Icon = index % 2 === 0 ? Group : ChartBarSquareIcon;
const actionLabel = `${collapsed ? '显示' : '隐藏'}${group.name}列`;
const columnSummary = group.columnLabels.join('、');
return (
<Tooltip delay={300}>
<Tooltip closeDelay={80} delay={150}>
<ToggleButton
size="sm"
isSelected={collapsed}
onChange={onToggle}
onBlur={() => onPreviewChange(null)}
onFocus={() => onPreviewChange(group.id)}
onHoverEnd={() => onPreviewChange(null)}
onHoverStart={() => onPreviewChange(group.id)}
aria-label={actionLabel}
>
<Icon size={16} />
<span>{group.name}</span>
<span aria-hidden="true" className="text-xs opacity-70">
{group.children.length} 列
</span>
</ToggleButton>
<Tooltip.Content>
{actionLabel}(共 {group.children.length} 个字段)
<Tooltip.Content className="max-w-80" placement="bottom">
<div className="space-y-1">
<div className="font-medium">{actionLabel}</div>
<div className="text-xs opacity-80">包含:{columnSummary}</div>
</div>
</Tooltip.Content>
</Tooltip>
);
}
function ColumnHeaderLabel({ label, groupName }) {
if (!groupName) {
return label;
}
return (
<span className="flex min-w-0 flex-col items-start gap-0.5 py-0.5">
<span
aria-hidden="true"
className="text-[11px] font-normal leading-4 text-muted"
>
{groupName}
</span>
<span className="text-xs font-medium leading-4 text-foreground">
{label}
</span>
</span>
);
}
function renderRowActionButton({ action, isDisabled, onPress }) {
const Icon = action.icon || DEFAULT_ROW_ACTION_ICONS[action.key];
......@@ -442,6 +487,7 @@ export default function RecordWorkbench({
const [drawerDirty, setDrawerDirty] = useState(false);
const [filtersExpanded, setFiltersExpanded] = useState(false);
const [collapsedColumnGroups, setCollapsedColumnGroups] = useState({});
const [previewColumnGroupId, setPreviewColumnGroupId] = useState(null);
const [columnGroupAnnouncement, setColumnGroupAnnouncement] = useState('');
const [expandedRowIds, setExpandedRowIds] = useState({});
const filterFieldVariant = 'secondary';
......@@ -736,9 +782,24 @@ export default function RecordWorkbench({
: []),
...stickyColumns.orderedColumns.map((column, columnIndex) => {
const stickyMeta = stickyColumns.stickyMeta[column.field];
const columnGroupId = columnGroupMeta.fieldToGroup[column.field];
const columnGroup = columnGroupId
? columnGroupMeta.groupById[columnGroupId]
: null;
const isPreviewedGroupColumn =
columnGroupId === previewColumnGroupId;
return {
key: column.field,
title: column.label,
title: (
<ColumnHeaderLabel
groupName={columnGroup?.name}
label={column.label}
/>
),
headerClassName: clsx(
column.headerClassName,
isPreviewedGroupColumn && 'bg-accent-soft text-accent-soft-foreground',
),
width: getWorkbenchColumnWidth(column, stickyMeta),
minWidth: getWorkbenchColumnWidth(column, stickyMeta),
pin:
......@@ -1056,6 +1117,7 @@ export default function RecordWorkbench({
group={group}
collapsed={Boolean(collapsedColumnGroups[group.id])}
index={index}
onPreviewChange={setPreviewColumnGroupId}
onToggle={() => toggleColumnGroup(group.id)}
/>
))}
......
......@@ -2,6 +2,7 @@ import dayjs from 'dayjs';
import {
countRecords,
getSubjectView,
getSubjectViewDetail,
loadSubject,
queryRecords,
} from '@/services/DataService';
......@@ -1095,14 +1096,35 @@ export async function loadProblemRectificationListData({
}
export async function loadProblemRectificationListResources() {
const [subject, views] = await Promise.all([
const [subject, viewSummaries] = await Promise.all([
loadSubject(PROBLEM_RECTIFICATION_SUBJECT),
getSubjectView(PROBLEM_RECTIFICATION_SUBJECT),
]);
const views = await Promise.all(
toArray(viewSummaries).map(async (view) => {
if (!view?.name) {
return view;
}
try {
const detail = await getSubjectViewDetail(
PROBLEM_RECTIFICATION_SUBJECT,
view.name,
);
return {
...view,
...detail,
settings: detail?.settings || view?.settings || {},
};
} catch (error) {
return view;
}
}),
);
return {
subject,
views: views || [],
views,
};
}
......
......@@ -139,6 +139,20 @@ export function getFieldPath(fieldDef) {
return fieldDef.name === 'title' ? 'title' : `metadata.${fieldDef.name}`;
}
function getConfiguredColumnLabel(column, fieldDef) {
const configuredLabel = [
column?.label,
column?.title,
column?.header,
column?.displayName,
column?.display_name,
]
.map(normalizeText)
.find(Boolean);
return configuredLabel || fieldDef?.label || (column?.field === 'title' ? '标题' : column?.field);
}
export function getFieldNameFromPath(fieldPath) {
if (!fieldPath) {
return '';
......@@ -234,7 +248,7 @@ export function buildViewColumns(view, subject, { includeHidden = false } = {})
return {
...column,
width: column.width || 180,
label: fieldDef?.label || (column.field === 'title' ? '标题' : column.field),
label: getConfiguredColumnLabel(column, fieldDef),
fieldDef: fieldDef || { name: column.field, label: column.field, type: 'text' },
};
});
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment