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 { ...@@ -21,7 +21,7 @@ import {
} from '@/components/AppIcons'; } from '@/components/AppIcons';
import FilterSelect from '@/components/FilterSelect'; import FilterSelect from '@/components/FilterSelect';
import FormDatePicker from '@/components/FormDatePicker'; import FormDatePicker from '@/components/FormDatePicker';
import { formatFieldValue, getFieldValue } from '@/utils/subjectView'; import { formatFieldValue, getFieldValue, normalizeText } from '@/utils/subjectView';
import { import {
Alert, Alert,
Button, Button,
...@@ -155,8 +155,16 @@ function buildColumnGroupMeta(columnGroups = [], columns = []) { ...@@ -155,8 +155,16 @@ function buildColumnGroupMeta(columnGroups = [], columns = []) {
return { return {
...group, ...group,
id, id,
name: group?.name || id, name:
normalizeText(group?.label) ||
normalizeText(group?.title) ||
normalizeText(group?.name) ||
id,
children, 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); .filter((group) => group.children.length > 0);
...@@ -331,28 +339,65 @@ function getWorkbenchColumnWidth(column, stickyMeta) { ...@@ -331,28 +339,65 @@ function getWorkbenchColumnWidth(column, stickyMeta) {
return Math.min(readableWidth, 280); 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 Icon = index % 2 === 0 ? Group : ChartBarSquareIcon;
const actionLabel = `${collapsed ? '显示' : '隐藏'}${group.name}列`; const actionLabel = `${collapsed ? '显示' : '隐藏'}${group.name}列`;
const columnSummary = group.columnLabels.join('、');
return ( return (
<Tooltip delay={300}> <Tooltip closeDelay={80} delay={150}>
<ToggleButton <ToggleButton
size="sm" size="sm"
isSelected={collapsed} isSelected={collapsed}
onChange={onToggle} onChange={onToggle}
onBlur={() => onPreviewChange(null)}
onFocus={() => onPreviewChange(group.id)}
onHoverEnd={() => onPreviewChange(null)}
onHoverStart={() => onPreviewChange(group.id)}
aria-label={actionLabel} aria-label={actionLabel}
> >
<Icon size={16} /> <Icon size={16} />
<span>{group.name}</span> <span>{group.name}</span>
<span aria-hidden="true" className="text-xs opacity-70">
{group.children.length} 列
</span>
</ToggleButton> </ToggleButton>
<Tooltip.Content> <Tooltip.Content className="max-w-80" placement="bottom">
{actionLabel}(共 {group.children.length} 个字段) <div className="space-y-1">
<div className="font-medium">{actionLabel}</div>
<div className="text-xs opacity-80">包含:{columnSummary}</div>
</div>
</Tooltip.Content> </Tooltip.Content>
</Tooltip> </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 }) { function renderRowActionButton({ action, isDisabled, onPress }) {
const Icon = action.icon || DEFAULT_ROW_ACTION_ICONS[action.key]; const Icon = action.icon || DEFAULT_ROW_ACTION_ICONS[action.key];
...@@ -442,6 +487,7 @@ export default function RecordWorkbench({ ...@@ -442,6 +487,7 @@ export default function RecordWorkbench({
const [drawerDirty, setDrawerDirty] = useState(false); const [drawerDirty, setDrawerDirty] = useState(false);
const [filtersExpanded, setFiltersExpanded] = useState(false); const [filtersExpanded, setFiltersExpanded] = useState(false);
const [collapsedColumnGroups, setCollapsedColumnGroups] = useState({}); const [collapsedColumnGroups, setCollapsedColumnGroups] = useState({});
const [previewColumnGroupId, setPreviewColumnGroupId] = useState(null);
const [columnGroupAnnouncement, setColumnGroupAnnouncement] = useState(''); const [columnGroupAnnouncement, setColumnGroupAnnouncement] = useState('');
const [expandedRowIds, setExpandedRowIds] = useState({}); const [expandedRowIds, setExpandedRowIds] = useState({});
const filterFieldVariant = 'secondary'; const filterFieldVariant = 'secondary';
...@@ -736,9 +782,24 @@ export default function RecordWorkbench({ ...@@ -736,9 +782,24 @@ export default function RecordWorkbench({
: []), : []),
...stickyColumns.orderedColumns.map((column, columnIndex) => { ...stickyColumns.orderedColumns.map((column, columnIndex) => {
const stickyMeta = stickyColumns.stickyMeta[column.field]; const stickyMeta = stickyColumns.stickyMeta[column.field];
const columnGroupId = columnGroupMeta.fieldToGroup[column.field];
const columnGroup = columnGroupId
? columnGroupMeta.groupById[columnGroupId]
: null;
const isPreviewedGroupColumn =
columnGroupId === previewColumnGroupId;
return { return {
key: column.field, 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), width: getWorkbenchColumnWidth(column, stickyMeta),
minWidth: getWorkbenchColumnWidth(column, stickyMeta), minWidth: getWorkbenchColumnWidth(column, stickyMeta),
pin: pin:
...@@ -1056,6 +1117,7 @@ export default function RecordWorkbench({ ...@@ -1056,6 +1117,7 @@ export default function RecordWorkbench({
group={group} group={group}
collapsed={Boolean(collapsedColumnGroups[group.id])} collapsed={Boolean(collapsedColumnGroups[group.id])}
index={index} index={index}
onPreviewChange={setPreviewColumnGroupId}
onToggle={() => toggleColumnGroup(group.id)} onToggle={() => toggleColumnGroup(group.id)}
/> />
))} ))}
......
...@@ -2,6 +2,7 @@ import dayjs from 'dayjs'; ...@@ -2,6 +2,7 @@ import dayjs from 'dayjs';
import { import {
countRecords, countRecords,
getSubjectView, getSubjectView,
getSubjectViewDetail,
loadSubject, loadSubject,
queryRecords, queryRecords,
} from '@/services/DataService'; } from '@/services/DataService';
...@@ -1095,14 +1096,35 @@ export async function loadProblemRectificationListData({ ...@@ -1095,14 +1096,35 @@ export async function loadProblemRectificationListData({
} }
export async function loadProblemRectificationListResources() { export async function loadProblemRectificationListResources() {
const [subject, views] = await Promise.all([ const [subject, viewSummaries] = await Promise.all([
loadSubject(PROBLEM_RECTIFICATION_SUBJECT), loadSubject(PROBLEM_RECTIFICATION_SUBJECT),
getSubjectView(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 { return {
subject, subject,
views: views || [], views,
}; };
} }
......
...@@ -139,6 +139,20 @@ export function getFieldPath(fieldDef) { ...@@ -139,6 +139,20 @@ export function getFieldPath(fieldDef) {
return fieldDef.name === 'title' ? 'title' : `metadata.${fieldDef.name}`; 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) { export function getFieldNameFromPath(fieldPath) {
if (!fieldPath) { if (!fieldPath) {
return ''; return '';
...@@ -234,7 +248,7 @@ export function buildViewColumns(view, subject, { includeHidden = false } = {}) ...@@ -234,7 +248,7 @@ export function buildViewColumns(view, subject, { includeHidden = false } = {})
return { return {
...column, ...column,
width: column.width || 180, 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' }, 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