feat: подсправочник показывается целиком при выборе привязанной строки

This commit is contained in:
2026-07-21 12:01:07 +03:00
parent b086ff4513
commit 2e1652e7ee
3 changed files with 8 additions and 84 deletions

View File

@@ -200,7 +200,7 @@ export default function SubdirectoryFieldConfig({
</Select>
{selectedSubdirectory && (
<p className="text-xs text-muted-foreground mt-1">
Фильтр: «{selectedTable?.columns?.[selectedSubdirectory.parentColumnIndex ?? 0]?.name || '?'}» = «{selectedSubdirectory.childTable?.columns?.[selectedSubdirectory.childColumnIndex ?? 0]?.name || '?'}»
Подсправочник показывается при выборе привязанных строк родителя.
</p>
)}
</div>

View File

@@ -3,7 +3,7 @@ import { useQuery } from '@tanstack/react-query';
import { apiRequest } from '@/lib/queryClient';
import TableFieldSelect from '@/components/TableFieldSelect';
import TableFieldMultiSelect from '@/components/TableFieldMultiSelect';
import type { DataTableRow, DataTableSubdirectory } from '@shared/schema';
import type { DataTableSubdirectory } from '@shared/schema';
interface TableFieldValue {
parentId?: string | null;
@@ -67,23 +67,6 @@ export default function TableFieldWithSubdirectory({
const showSubdirectory = !!opts.showSubdirectory;
const subdirectoryId = opts.subdirectoryId as number | undefined;
const { data: tableData } = useQuery<{
table: {
rows: DataTableRow[];
columns: Array<{ name: string }>;
treeColumnIndex: number | null;
treeDisplayColumnIndex: number | null;
treeColumns: number[] | null;
treeDisplayColumns: number[] | null;
};
}>({
queryKey: ['/api/directories', tableId],
enabled: !!tableId,
staleTime: 5 * 60 * 1000,
gcTime: 10 * 60 * 1000,
retry: false,
});
const { data: subdirectoriesData } = useQuery<{ subdirectories: DataTableSubdirectory[] }>({
queryKey: ['/api/directories', tableId, 'subdirectories'],
queryFn: async () => {
@@ -100,24 +83,11 @@ export default function TableFieldWithSubdirectory({
const { parentId, childId } = parseTableValue(value);
const parentRow = useMemo(() => {
if (!parentId || !tableData?.table?.rows) return null;
return tableData.table.rows.find((r) => r.id.toString() === parentId) || null;
}, [parentId, tableData]);
const isParentLinked = useMemo(() => {
if (!subdirectory || !parentId) return false;
return subdirectory.parentRowIds?.includes(Number(parentId)) ?? false;
}, [subdirectory, parentId]);
const childFilter = useMemo(() => {
if (!subdirectory || !parentRow) return undefined;
const col = String(subdirectory.childColumnIndex ?? 0);
const parentValue = parentRow.values?.[subdirectory.parentColumnIndex ?? 0] ?? '';
if (!parentValue) return undefined;
return { [col]: parentValue };
}, [subdirectory, parentRow]);
const handleParentChange = (newParentId: string) => {
onChange(serializeTableValue(newParentId || null, null));
};
@@ -144,8 +114,6 @@ export default function TableFieldWithSubdirectory({
const childOptions = {
...opts,
tableId: subdirectory.childTableId,
displayColumn: subdirectory.childTable?.columns?.[subdirectory.childColumnIndex ?? 0]?.name || undefined,
filters: childFilter,
};
return (
@@ -158,7 +126,7 @@ export default function TableFieldWithSubdirectory({
value={parentId || ''}
onChange={handleParentChange}
/>
{isParentLinked && childFilter && (
{isParentLinked && (
<TableFieldSelect
fieldId={fieldId}
fieldCode={`${fieldCode}_sub`}

View File

@@ -116,8 +116,6 @@ export default function TableEditor() {
const [subdirectoriesOpen, setSubdirectoriesOpen] = useState(false);
const [editingSubdirectory, setEditingSubdirectory] = useState<DataTableSubdirectory | null>(null);
const [subdirectoryChildTableId, setSubdirectoryChildTableId] = useState<string>('none');
const [subdirectoryParentColumnIndex, setSubdirectoryParentColumnIndex] = useState<number>(0);
const [subdirectoryChildColumnIndex, setSubdirectoryChildColumnIndex] = useState<number>(0);
const [subdirectoryParentRowIds, setSubdirectoryParentRowIds] = useState<Set<number>>(new Set());
const { filters, sort, setFilter, clearFilter, clearAll, setSort, clearSort, hasActiveFilters } = useColumnFilters();
@@ -213,7 +211,7 @@ export default function TableEditor() {
}, [rowEditorOpen, rowEditorInitialValues]);
const createSubdirectoryMutation = useMutation({
mutationFn: async (payload: { childTableId: number; parentColumnIndex: number; childColumnIndex: number; parentRowIds: number[] }) => {
mutationFn: async (payload: { childTableId: number; parentRowIds: number[] }) => {
return apiRequest('POST', `/api/directories/${tableId}/subdirectories`, payload);
},
onSuccess: () => {
@@ -230,7 +228,7 @@ export default function TableEditor() {
});
const updateSubdirectoryMutation = useMutation({
mutationFn: async ({ linkId, payload }: { linkId: number; payload: { childTableId?: number; parentColumnIndex?: number; childColumnIndex?: number; parentRowIds?: number[] } }) => {
mutationFn: async ({ linkId, payload }: { linkId: number; payload: { childTableId?: number; parentRowIds?: number[] } }) => {
return apiRequest('PATCH', `/api/directories/${tableId}/subdirectories/${linkId}`, payload);
},
onSuccess: () => {
@@ -263,8 +261,6 @@ export default function TableEditor() {
const resetSubdirectoryForm = () => {
setSubdirectoryChildTableId('none');
setSubdirectoryParentColumnIndex(0);
setSubdirectoryChildColumnIndex(0);
setSubdirectoryParentRowIds(new Set());
setEditingSubdirectory(null);
};
@@ -273,8 +269,6 @@ export default function TableEditor() {
if (link) {
setEditingSubdirectory(link);
setSubdirectoryChildTableId(link.childTableId?.toString() || 'none');
setSubdirectoryParentColumnIndex(link.parentColumnIndex ?? 0);
setSubdirectoryChildColumnIndex(link.childColumnIndex ?? 0);
setSubdirectoryParentRowIds(new Set(link.parentRowIds || []));
} else {
resetSubdirectoryForm();
@@ -298,8 +292,6 @@ export default function TableEditor() {
}
const payload = {
childTableId: childId,
parentColumnIndex: subdirectoryParentColumnIndex,
childColumnIndex: subdirectoryChildColumnIndex,
parentRowIds: Array.from(subdirectoryParentRowIds),
};
if (editingSubdirectory?.id) {
@@ -1793,10 +1785,9 @@ export default function TableEditor() {
<div className="flex-1 min-w-0">
<div className="font-medium text-sm truncate">{link.childTable?.name || `ID ${link.childTableId}`}</div>
<div className="text-xs text-muted-foreground">
по столбцу «{columns[link.parentColumnIndex ?? 0]?.name || '?'}» =&gt; «{link.childTable?.columns?.[link.childColumnIndex ?? 0]?.name || '?'}»
{link.parentRowIds && link.parentRowIds.length > 0 && (
<span className="ml-1">({link.parentRowIds.length} строк)</span>
)}
{link.parentRowIds && link.parentRowIds.length > 0
? `Привязан к ${link.parentRowIds.length} строкам`
: 'Не привязан к строкам'}
</div>
</div>
<div className="flex items-center gap-1">
@@ -1833,41 +1824,6 @@ export default function TableEditor() {
</Select>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<Label>Столбец родителя</Label>
<Select value={String(subdirectoryParentColumnIndex)} onValueChange={(v) => setSubdirectoryParentColumnIndex(parseInt(v))}>
<SelectTrigger>
<SelectValue placeholder="Столбец" />
</SelectTrigger>
<SelectContent>
{columns.map((col, idx) => (
<SelectItem key={idx} value={String(idx)}>{col.name}</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div>
<Label>Столбец подсправочника</Label>
<Select
value={String(subdirectoryChildColumnIndex)}
onValueChange={(v) => setSubdirectoryChildColumnIndex(parseInt(v))}
disabled={subdirectoryChildTableId === 'none'}
>
<SelectTrigger>
<SelectValue placeholder="Столбец" />
</SelectTrigger>
<SelectContent>
{allTables
.find((t) => t.id.toString() === subdirectoryChildTableId)
?.columns?.map((col: any, idx: number) => (
<SelectItem key={idx} value={String(idx)}>{col.name}</SelectItem>
))}
</SelectContent>
</Select>
</div>
</div>
<div>
<Label className="mb-2 block">Строки родительского справочника</Label>
<div className="border rounded p-2 max-h-48 overflow-y-auto space-y-1">