Древовидные справочники: parent_id, drag&drop, древовидный выбор в полях table

This commit is contained in:
2026-07-12 20:55:30 +03:00
parent 833fa97f56
commit ec08f3222d
10 changed files with 1284 additions and 68 deletions

View File

@@ -3,6 +3,8 @@ import { useQuery } from '@tanstack/react-query';
import { Input } from '@/components/ui/input';
import { Popover, PopoverAnchor, PopoverContent } from '@/components/ui/popover';
import { Table } from 'lucide-react';
import { DirectoryTreeSelect } from '@/components/directories/DirectoryTreeSelect';
import type { DataTableRow } from '@shared/schema';
interface TableFieldSelectProps {
fieldId: number;
@@ -27,7 +29,7 @@ export default function TableFieldSelect({
const { data: tableData, isLoading, error } = useQuery<{
table: {
rows: Array<{ id: number; values: string[] }>;
rows: DataTableRow[];
columns: Array<{ name: string }>;
};
}>({
@@ -94,6 +96,8 @@ export default function TableFieldSelect({
setIsOpen(false);
};
const hasHierarchy = rows.some((r) => r.parentId !== null && r.parentId !== undefined);
return (
<Popover open={isOpen} onOpenChange={setIsOpen}>
<PopoverAnchor asChild>
@@ -125,29 +129,41 @@ export default function TableFieldSelect({
}
}}
>
<ul className="max-h-60 overflow-auto py-1">
<li
className="cursor-pointer px-3 py-2 hover:bg-accent text-sm text-muted-foreground"
onMouseDown={(e) => { e.preventDefault(); handleSelect(''); }}
>
—
</li>
{filtered.map((row) => (
<li
key={row.id}
className="cursor-pointer px-3 py-2 hover:bg-accent"
onMouseDown={(e) => { e.preventDefault(); handleSelect(row.id.toString()); }}
>
<div className="flex items-center gap-2 text-sm">
<Table className="w-3 h-3 text-muted-foreground" />
{row.values[displayColumnIndex!] || row.values[0]}
</div>
</li>
))}
{filtered.length === 0 && (
<li className="px-3 py-2 text-sm text-muted-foreground">Нет совпадений</li>
<div className="max-h-60 overflow-auto">
{hasHierarchy ? (
<DirectoryTreeSelect
rows={rows}
displayColumnIndex={displayColumnIndex!}
value={value}
onChange={handleSelect}
searchTerm={searchTerm}
/>
) : (
<ul className="py-1">
<li
className="cursor-pointer px-3 py-2 hover:bg-accent text-sm text-muted-foreground"
onMouseDown={(e) => { e.preventDefault(); handleSelect(''); }}
>
—
</li>
{filtered.map((row) => (
<li
key={row.id}
className="cursor-pointer px-3 py-2 hover:bg-accent"
onMouseDown={(e) => { e.preventDefault(); handleSelect(row.id.toString()); }}
>
<div className="flex items-center gap-2 text-sm">
<Table className="w-3 h-3 text-muted-foreground" />
{row.values[displayColumnIndex!] || row.values[0]}
</div>
</li>
))}
{filtered.length === 0 && (
<li className="px-3 py-2 text-sm text-muted-foreground">Нет совпадений</li>
)}
</ul>
)}
</ul>
</div>
</PopoverContent>
</Popover>
);