dishui 0.0.64 → 0.0.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Badge/index.js +12 -9
- package/dist/components/Badge/index.js.map +1 -1
- package/dist/components/Button/index.js +43 -40
- package/dist/components/Button/index.js.map +1 -1
- package/dist/components/Card/index.d.ts +11 -0
- package/dist/components/Card/index.js +62 -37
- package/dist/components/Card/index.js.map +1 -1
- package/dist/components/Chart/Chart.js.map +1 -1
- package/dist/components/Checkbox/index.js +32 -30
- package/dist/components/Checkbox/index.js.map +1 -1
- package/dist/components/Demo/index.js.map +1 -1
- package/dist/components/EmptyState/index.d.ts +4 -1
- package/dist/components/EmptyState/index.js +3 -3
- package/dist/components/EmptyState/index.js.map +1 -1
- package/dist/components/FileUploader/DropZone.js.map +1 -1
- package/dist/components/FileUploader/FileItem.js.map +1 -1
- package/dist/components/FileUploader/FileUploader.js.map +1 -1
- package/dist/components/FileUploader/UploadQueue.js.map +1 -1
- package/dist/components/Input/index.js +30 -30
- package/dist/components/Input/index.js.map +1 -1
- package/dist/components/Label/index.js +41 -40
- package/dist/components/Label/index.js.map +1 -1
- package/dist/components/List/index.js +47 -32
- package/dist/components/List/index.js.map +1 -1
- package/dist/components/Markdown/Markdown.js +61 -57
- package/dist/components/Markdown/Markdown.js.map +1 -1
- package/dist/components/Markdown/markdownComponents.js +49 -49
- package/dist/components/Markdown/markdownComponents.js.map +1 -1
- package/dist/components/Modal/index.d.ts +7 -3
- package/dist/components/Modal/index.js +77 -65
- package/dist/components/Modal/index.js.map +1 -1
- package/dist/components/Page/index.d.ts +58 -0
- package/dist/components/Page/index.js +74 -0
- package/dist/components/Page/index.js.map +1 -0
- package/dist/components/PageHeader/index.js.map +1 -1
- package/dist/components/Select/index.js +0 -3
- package/dist/components/Select/index.js.map +1 -1
- package/dist/components/SidebarToggleButton/index.js.map +1 -1
- package/dist/components/StatCard/index.d.ts +3 -1
- package/dist/components/StatCard/index.js +39 -11
- package/dist/components/StatCard/index.js.map +1 -1
- package/dist/components/Table/index.js +103 -85
- package/dist/components/Table/index.js.map +1 -1
- package/dist/components/Tabs/index.d.ts +19 -5
- package/dist/components/Tabs/index.js +32 -13
- package/dist/components/Tabs/index.js.map +1 -1
- package/dist/components/Tree/Tree.js.map +1 -1
- package/dist/components/pro/ArticleContextMenu/index.js.map +1 -1
- package/dist/components/pro/ArticleControl/ArticleControl2.js.map +1 -1
- package/dist/components/pro/CodeEditor/editors/CodeEditor.js +141 -134
- package/dist/components/pro/CodeEditor/editors/CodeEditor.js.map +1 -1
- package/dist/components/pro/CodeEditor/editors/MarkdownEditor.js +81 -78
- package/dist/components/pro/CodeEditor/editors/MarkdownEditor.js.map +1 -1
- package/dist/components/pro/CodeEditor/panels/FootnotePanel.js.map +1 -1
- package/dist/components/pro/CodeEditor/panels/HistoryPanel.js.map +1 -1
- package/dist/components/pro/CodeEditor/panels/OutlinePanel.js.map +1 -1
- package/dist/components/pro/CodeEditor/panels/TableOfContentsPanel.js.map +1 -1
- package/dist/components/pro/CodeEditor/panels/VariablePanel.js.map +1 -1
- package/dist/components/pro/CodeEditor/themes.js +59 -59
- package/dist/components/pro/CodeEditor/themes.js.map +1 -1
- package/dist/components/pro/DataTable/DataTable.js +49 -48
- package/dist/components/pro/DataTable/DataTable.js.map +1 -1
- package/dist/components/pro/DataTable/Filters.js +42 -42
- package/dist/components/pro/DataTable/Filters.js.map +1 -1
- package/dist/components/pro/DataTable/PivotPanel.js.map +1 -1
- package/dist/components/pro/DataTable/PivotView.js +35 -32
- package/dist/components/pro/DataTable/PivotView.js.map +1 -1
- package/dist/components/pro/DataTable/components/BulkActions.js.map +1 -1
- package/dist/components/pro/DataTable/components/ColumnSelector.js.map +1 -1
- package/dist/components/pro/DataTable/components/FilterBar.js.map +1 -1
- package/dist/components/pro/DataTable/components/TableBody.js.map +1 -1
- package/dist/components/pro/DataTable/components/TableHeader.js.map +1 -1
- package/dist/components/pro/DataTable/components/TablePagination.js.map +1 -1
- package/dist/components/pro/DataTable/components/TableToolbar.js.map +1 -1
- package/dist/components/pro/DataTable/pivotExtension.js.map +1 -1
- package/dist/components/pro/DataTable/rowDetailExtension.js.map +1 -1
- package/dist/components/pro/DataTable/tanstack-table.js +37 -37
- package/dist/components/pro/DataTable/tanstack-table.js.map +1 -1
- package/dist/components/pro/FileExplorer/Breadcrumb.js +53 -53
- package/dist/components/pro/FileExplorer/Breadcrumb.js.map +1 -1
- package/dist/components/pro/FileExplorer/CreateDialog.js.map +1 -1
- package/dist/components/pro/FileExplorer/FileExplorer.js.map +1 -1
- package/dist/components/pro/FileExplorer/FileIcon.js +22 -22
- package/dist/components/pro/FileExplorer/FileIcon.js.map +1 -1
- package/dist/components/pro/FileExplorer/GridView.js.map +1 -1
- package/dist/components/pro/FileExplorer/ListView.js.map +1 -1
- package/dist/components/pro/FileExplorer/Toolbar.js.map +1 -1
- package/dist/components/pro/Flow/Flow.js +496 -494
- package/dist/components/pro/Flow/Flow.js.map +1 -1
- package/dist/components/pro/Flow/FlowCanvas.js +916 -917
- package/dist/components/pro/Flow/FlowCanvas.js.map +1 -1
- package/dist/components/pro/Flow/context/FlowUIContext.js.map +1 -1
- package/dist/components/pro/Flow/edges/EdgeRenderer.js +59 -59
- package/dist/components/pro/Flow/edges/EdgeRenderer.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useClipboard.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useDeleteSelection.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useEdgeMutations.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useLayoutActions.js +9 -11
- package/dist/components/pro/Flow/hooks/useLayoutActions.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useLineMutations.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useMindMap.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useNodeMutations.js.map +1 -1
- package/dist/components/pro/Flow/lines/FreehandTool.js +9 -9
- package/dist/components/pro/Flow/lines/FreehandTool.js.map +1 -1
- package/dist/components/pro/Flow/lines/LineRenderer.js +5 -5
- package/dist/components/pro/Flow/lines/LineRenderer.js.map +1 -1
- package/dist/components/pro/Flow/nodes/DataNodeView.js +113 -93
- package/dist/components/pro/Flow/nodes/DataNodeView.js.map +1 -1
- package/dist/components/pro/Flow/nodes/MediaContent.js.map +1 -1
- package/dist/components/pro/Flow/nodes/MediaOverlay.js.map +1 -1
- package/dist/components/pro/Flow/nodes/Model3DView.js +1 -1
- package/dist/components/pro/Flow/nodes/Model3DView.js.map +1 -1
- package/dist/components/pro/Flow/nodes/NodeRenderer.js +118 -118
- package/dist/components/pro/Flow/nodes/NodeRenderer.js.map +1 -1
- package/dist/components/pro/Flow/nodes/dataUtils.js.map +1 -1
- package/dist/components/pro/Flow/nodes/shapes.js +1 -3
- package/dist/components/pro/Flow/nodes/shapes.js.map +1 -1
- package/dist/components/pro/Flow/panels/AIPanel.js.map +1 -1
- package/dist/components/pro/Flow/panels/Breadcrumb.js.map +1 -1
- package/dist/components/pro/Flow/panels/ContextMenu.js.map +1 -1
- package/dist/components/pro/Flow/panels/DataInspectorSection.js.map +1 -1
- package/dist/components/pro/Flow/panels/ExpandableTextarea.js.map +1 -1
- package/dist/components/pro/Flow/panels/FlowPanelGroup.js.map +1 -1
- package/dist/components/pro/Flow/panels/FlowToolbar.js +97 -97
- package/dist/components/pro/Flow/panels/FlowToolbar.js.map +1 -1
- package/dist/components/pro/Flow/panels/InspectorPanel.js +57 -57
- package/dist/components/pro/Flow/panels/InspectorPanel.js.map +1 -1
- package/dist/components/pro/Flow/panels/OutlinePanel.js +26 -22
- package/dist/components/pro/Flow/panels/OutlinePanel.js.map +1 -1
- package/dist/components/pro/Flow/panels/PresentationMode.js +18 -16
- package/dist/components/pro/Flow/panels/PresentationMode.js.map +1 -1
- package/dist/components/pro/Flow/panels/ProjectTitle.js.map +1 -1
- package/dist/components/pro/Flow/panels/ShapePalette.js +109 -104
- package/dist/components/pro/Flow/panels/ShapePalette.js.map +1 -1
- package/dist/components/pro/Flow/panels/toolbarIcons.js.map +1 -1
- package/dist/components/pro/RichTextEditor/AIRewrite.js.map +1 -1
- package/dist/components/pro/RichTextEditor/BlockHandle.js.map +1 -1
- package/dist/components/pro/RichTextEditor/BubbleToolbar.js.map +1 -1
- package/dist/components/pro/RichTextEditor/CommentDialog.js.map +1 -1
- package/dist/components/pro/RichTextEditor/CommentPanel.js.map +1 -1
- package/dist/components/pro/RichTextEditor/CommentPopover.js.map +1 -1
- package/dist/components/pro/RichTextEditor/ContextMenu.js.map +1 -1
- package/dist/components/pro/RichTextEditor/RichTextEditor.js.map +1 -1
- package/dist/components/pro/RichTextEditor/SlashMenu.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/ColorPicker.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/FloatingDialogMenu.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/MarkdownTemplates.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/SelectDropdown.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/TableOpsMenu.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/Toolbar.js.map +1 -1
- package/dist/components/pro/RichTextEditor/extensions/CodeBlockView.js.map +1 -1
- package/dist/components/pro/RichTextEditor/extensions/FloatingDialog.js.map +1 -1
- package/dist/components/pro/RichTextEditor/extensions/MarkdownBlock.js.map +1 -1
- package/dist/contexts/AppContext.js.map +1 -1
- package/dist/dishui.css +1 -1
- package/dist/hooks/useTableColumns.js +7 -8
- package/dist/hooks/useTableColumns.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +227 -221
- package/dist/layouts/MainLayout.js +22 -22
- package/dist/layouts/MainLayout.js.map +1 -1
- package/dist/layouts/Navbar.js.map +1 -1
- package/dist/layouts/Sidebar.js +94 -73
- package/dist/layouts/Sidebar.js.map +1 -1
- package/dist/layouts/headbar/Headbar.js.map +1 -1
- package/dist/layouts/headbar/HeadbarLangSwitcher.js.map +1 -1
- package/dist/layouts/headbar/HeadbarSearch.js.map +1 -1
- package/dist/layouts/headbar/HeadbarThemeSwitcher.js +11 -11
- package/dist/layouts/headbar/HeadbarThemeSwitcher.js.map +1 -1
- package/dist/layouts/headbar/HeadbarTitle.js.map +1 -1
- package/dist/utils/i18n.js +10 -10
- package/dist/utils/i18n.js.map +1 -1
- package/dist/utils/menu.js.map +1 -1
- package/dist/utils/routerBuilder.js +17 -15
- package/dist/utils/routerBuilder.js.map +1 -1
- package/dist/utils/themes.js.map +1 -1
- package/package.json +7 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Filters.js","names":[],"sources":["../../../../src/components/pro/DataTable/Filters.tsx"],"sourcesContent":["import React, { useState, useEffect } from 'react';\nimport { Column } from './tanstack-table';\nimport { useDebounce } from '../../../hooks/useDebounce';\n\n// 扩展列元数据接口(v9 的 ColumnMeta 位于 @tanstack/table-core,签名必须与原声明完全一致)\ndeclare module '@tanstack/table-core' {\n interface ColumnMeta<\n in out TFeatures extends import('@tanstack/table-core').TableFeatures,\n in out TData extends import('@tanstack/table-core').RowData,\n TValue extends import('@tanstack/table-core').CellData = import('@tanstack/table-core').CellData,\n > {\n filterType?: 'text' | 'number' | 'select' | 'boolean' | 'date' | 'multiSelect';\n filterOptions?: { value: any; label: string }[];\n }\n}\n\nexport interface TextFilterProps {\n column: Column<any, unknown>;\n placeholder?: string;\n}\n\n// 文本过滤器组件\nexport const TextFilter: React.FC<TextFilterProps> = ({\n column,\n placeholder = '搜索...'\n}) => {\n const [value, setValue] = useState('');\n const debouncedValue = useDebounce(value, 300);\n\n // 将组件状态与列过滤状态同步\n useEffect(() => {\n const currentFilterValue = column.getFilterValue() as string || '';\n if (currentFilterValue !== value) {\n setValue(currentFilterValue);\n }\n }, [column.getFilterValue()]);\n\n // 当 debouncedValue 变化时更新列过滤状态\n useEffect(() => {\n column.setFilterValue(debouncedValue || undefined);\n }, [debouncedValue]);\n\n // 处理输入变更\n const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n setValue(e.target.value);\n };\n\n return (\n <div className=\"flex items-center mt-2\">\n <input\n type=\"text\"\n value={value}\n onChange={onChange}\n placeholder={placeholder}\n className=\"input input-bordered input-sm w-full\"\n />\n {value && (\n <button\n className=\"btn btn-ghost btn-xs ml-1\"\n onClick={() => {\n setValue('');\n column.setFilterValue(undefined);\n }}\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n )}\n </div>\n );\n};\n\nexport interface NumberFilterProps {\n column: Column<any, unknown>;\n min?: number;\n max?: number;\n step?: number;\n}\n\n// 数字范围过滤器组件\nexport const NumberRangeFilter: React.FC<NumberFilterProps> = ({\n column,\n min,\n max,\n step = 1\n}) => {\n const [minValue, setMinValue] = useState<string>('');\n const [maxValue, setMaxValue] = useState<string>('');\n\n const debouncedMin = useDebounce(minValue, 300);\n const debouncedMax = useDebounce(maxValue, 300);\n\n // 将组件状态与列过滤状态同步\n useEffect(() => {\n const filterValue = column.getFilterValue() as [number, number] | undefined;\n const newMin = filterValue && filterValue[0] !== undefined ? String(filterValue[0]) : '';\n const newMax = filterValue && filterValue[1] !== undefined ? String(filterValue[1]) : '';\n\n if (newMin !== minValue) setMinValue(newMin);\n if (newMax !== maxValue) setMaxValue(newMax);\n }, [column.getFilterValue()]);\n\n // 当 debounced 值变化时更新列过滤状态\n useEffect(() => {\n const filterValue: [number | undefined, number | undefined] = [\n debouncedMin === '' ? undefined : Number(debouncedMin),\n debouncedMax === '' ? undefined : Number(debouncedMax)\n ];\n\n // 如果两者都是undefined,则清除过滤器\n if (filterValue[0] === undefined && filterValue[1] === undefined) {\n column.setFilterValue(undefined);\n } else {\n column.setFilterValue(filterValue);\n }\n }, [debouncedMin, debouncedMax]);\n\n\n\n return (\n <div className=\"flex flex-col gap-1 mt-2\">\n <div className=\"flex items-center gap-2\">\n <input\n type=\"number\"\n value={minValue}\n onChange={(e) => {\n setMinValue(e.target.value);\n }}\n placeholder=\"最小值\"\n min={min}\n max={max}\n step={step}\n className=\"input input-bordered input-sm w-full\"\n />\n <span>至</span>\n <input\n type=\"number\"\n value={maxValue}\n onChange={(e) => {\n setMaxValue(e.target.value);\n }}\n placeholder=\"最大值\"\n min={min}\n max={max}\n step={step}\n className=\"input input-bordered input-sm w-full\"\n />\n </div>\n {(minValue || maxValue) && (\n <button\n className=\"btn btn-ghost btn-xs self-end\"\n onClick={() => {\n setMinValue('');\n setMaxValue('');\n column.setFilterValue(undefined);\n }}\n >\n 清除\n </button>\n )}\n </div>\n );\n};\n\nexport interface SelectFilterProps {\n column: Column<any, unknown>;\n options: { value: any; label: string }[];\n placeholder?: string;\n}\n\n// 选择过滤器组件\nexport const SelectFilter: React.FC<SelectFilterProps> = ({\n column,\n options,\n placeholder = '全部'\n}) => {\n const [value, setValue] = useState<string>('');\n\n // 将组件状态与列过滤状态同步\n useEffect(() => {\n const filterValue = column.getFilterValue();\n setValue(filterValue !== undefined ? String(filterValue) : '');\n }, [column.getFilterValue()]);\n\n // 处理选择变更\n const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {\n const selectedValue = e.target.value;\n setValue(selectedValue);\n\n if (selectedValue === '') {\n column.setFilterValue(undefined);\n } else {\n column.setFilterValue(selectedValue);\n }\n };\n\n return (\n <div className=\"mt-2\">\n <select\n value={value}\n onChange={handleChange}\n className=\"select select-bordered select-sm w-full\"\n >\n <option value=\"\">{placeholder}</option>\n {options.map((option, index) => (\n <option key={index} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n </div>\n );\n};\n\nexport interface BooleanFilterProps {\n column: Column<any, unknown>;\n trueLabel?: string;\n falseLabel?: string;\n allLabel?: string;\n}\n\n// 布尔值过滤器组件\nexport const BooleanFilter: React.FC<BooleanFilterProps> = ({\n column,\n trueLabel = '是',\n falseLabel = '否',\n allLabel = '全部'\n}) => {\n const options = [\n { value: '', label: allLabel },\n { value: 'true', label: trueLabel },\n { value: 'false', label: falseLabel }\n ];\n\n const [value, setValue] = useState<string>('');\n\n // 将组件状态与列过滤状态同步\n useEffect(() => {\n const filterValue = column.getFilterValue();\n setValue(filterValue !== undefined ? String(filterValue) : '');\n }, [column.getFilterValue()]);\n\n // 处理选择变更\n const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {\n const selectedValue = e.target.value;\n setValue(selectedValue);\n\n if (selectedValue === '') {\n column.setFilterValue(undefined);\n } else {\n column.setFilterValue(selectedValue === 'true');\n }\n };\n\n return (\n <div className=\"mt-2\">\n <select\n value={value}\n onChange={handleChange}\n className=\"select select-bordered select-sm w-full\"\n >\n {options.map((option, index) => (\n <option key={index} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n </div>\n );\n};\n\nexport interface DateRangeFilterProps {\n column: Column<any, unknown>;\n}\n\n// 日期范围过滤器组件\nexport const DateRangeFilter: React.FC<DateRangeFilterProps> = ({\n column\n}) => {\n const [startDate, setStartDate] = useState<string>('');\n const [endDate, setEndDate] = useState<string>('');\n\n const debouncedStart = useDebounce(startDate, 300);\n const debouncedEnd = useDebounce(endDate, 300);\n\n // 将组件状态与列过滤状态同步\n useEffect(() => {\n const filterValue = column.getFilterValue() as [string, string] | undefined;\n const newStart = filterValue && filterValue[0] ? filterValue[0] : '';\n const newEnd = filterValue && filterValue[1] ? filterValue[1] : '';\n\n if (newStart !== startDate) setStartDate(newStart);\n if (newEnd !== endDate) setEndDate(newEnd);\n }, [column.getFilterValue()]);\n\n // 当 debounced 值变化时更新列过滤状态\n useEffect(() => {\n const filterValue: [string | undefined, string | undefined] = [\n debouncedStart || undefined,\n debouncedEnd || undefined\n ];\n\n // 如果两者都是undefined,则清除过滤器\n if (!filterValue[0] && !filterValue[1]) {\n column.setFilterValue(undefined);\n } else {\n column.setFilterValue(filterValue);\n }\n }, [debouncedStart, debouncedEnd]);\n\n\n\n return (\n <div className=\"flex flex-col gap-1 mt-2\">\n <div className=\"flex items-center gap-2\">\n <input\n type=\"date\"\n value={startDate}\n onChange={(e) => {\n setStartDate(e.target.value);\n }}\n className=\"input input-bordered input-sm w-full\"\n />\n <span>至</span>\n <input\n type=\"date\"\n value={endDate}\n onChange={(e) => {\n setEndDate(e.target.value);\n }}\n className=\"input input-bordered input-sm w-full\"\n />\n </div>\n {(startDate || endDate) && (\n <button\n className=\"btn btn-ghost btn-xs self-end\"\n onClick={() => {\n setStartDate('');\n setEndDate('');\n column.setFilterValue(undefined);\n }}\n >\n 清除\n </button>\n )}\n </div>\n );\n};\n\n// 多选过滤器组件\nexport const MultiSelectFilter: React.FC<SelectFilterProps> = ({\n column,\n options,\n placeholder = '选择选项'\n}) => {\n const [selectedValues, setSelectedValues] = useState<string[]>([]);\n\n // 将组件状态与列过滤状态同步\n useEffect(() => {\n const filterValue = column.getFilterValue() as string[] | undefined;\n setSelectedValues(filterValue || []);\n }, [column.getFilterValue()]);\n\n // 处理选择变更\n const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {\n const values = Array.from(e.target.selectedOptions, option => option.value);\n setSelectedValues(values);\n\n if (values.length === 0) {\n column.setFilterValue(undefined);\n } else {\n column.setFilterValue(values);\n }\n };\n\n return (\n <div className=\"mt-2\">\n <select\n multiple\n value={selectedValues}\n onChange={handleChange}\n className=\"select select-bordered select-sm w-full max-h-32\"\n >\n {options.map((option, index) => (\n <option key={index} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n {selectedValues.length > 0 && (\n <div className=\"flex justify-between mt-1\">\n <span className=\"text-xs text-base-content/70\">已选择 {selectedValues.length} 项</span>\n <button\n className=\"btn btn-ghost btn-xs\"\n onClick={() => {\n setSelectedValues([]);\n column.setFilterValue(undefined);\n }}\n >\n 清除\n </button>\n </div>\n )}\n </div>\n );\n};\n\n// 过滤器面板组件\nexport interface FilterPanelProps {\n column: Column<any, unknown>;\n onClose: () => void;\n}\n\nexport const FilterPanel: React.FC<FilterPanelProps> = ({\n column,\n onClose\n}) => {\n // 确保column和column.columnDef存在\n if (!column || !column.columnDef) {\n return null;\n }\n\n // 获取过滤器类型,确保meta存在\n const meta = column.columnDef.meta || {};\n const filterType = meta.filterType;\n const filterOptions = meta.filterOptions || [];\n\n // 根据过滤器类型渲染相应的组件\n const renderFilter = () => {\n if (!filterType) return null;\n\n switch (filterType) {\n case 'text':\n return <TextFilter column={column} />;\n case 'number':\n return <NumberRangeFilter column={column} />;\n case 'select':\n return <SelectFilter column={column} options={filterOptions} />;\n case 'boolean':\n return <BooleanFilter column={column} />;\n case 'date':\n return <DateRangeFilter column={column} />;\n case 'multiSelect':\n return <MultiSelectFilter column={column} options={filterOptions} />;\n default:\n return <TextFilter column={column} />;\n }\n };\n\n // 列标题\n const columnHeader = column.columnDef.header ?\n (typeof column.columnDef.header === 'string' ?\n column.columnDef.header :\n column.id\n ) : column.id;\n\n return (\n <div className=\"card bg-base-100 shadow-lg p-4 w-64 z-50\">\n <div className=\"flex justify-between items-center mb-2\">\n <h3 className=\"font-medium\">{columnHeader}</h3>\n <button\n className=\"btn btn-ghost btn-xs\"\n onClick={onClose}\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n {renderFilter()}\n\n <div className=\"flex justify-end mt-2\">\n <button\n className=\"btn btn-ghost btn-xs\"\n onClick={() => {\n column.setFilterValue(undefined);\n onClose();\n }}\n >\n 清除过滤\n </button>\n </div>\n </div>\n );\n};\n\nexport default {\n TextFilter,\n NumberRangeFilter,\n SelectFilter,\n BooleanFilter,\n DateRangeFilter,\n MultiSelectFilter,\n FilterPanel\n}; "],"mappings":";;;;;;;;;;;;;IAsBa,IAAA,CAAyC,EACpD,QAAA,GACA,aAAA,IAAc,QAAA,MACV;AACJ,QAAM,CAAC,GAAO,CAAA,IAAY,EAAS,EAAE,GAC/B,IAAiB,EAAY,GAAO,GAAG;AAG7C,SAAA,EAAA,MAAgB;AACd,UAAM,IAAqB,EAAO,eAAe,KAAe;AAChE,IAAI,MAAuB,KACzB,EAAS,CAAkB;AAAA,EAE/B,GAAG,CAAC,EAAO,eAAe,CAAC,CAAC,GAG5B,EAAA,MAAgB;AACd,IAAA,EAAO,eAAe,KAAkB,MAAS;AAAA,EACnD,GAAG,CAAC,CAAc,CAAC,GAQjB,gBAAA,EAAC,OAAD;AAAA,IAAK,WAAU;AAAA,cAAf,CACE,gBAAA,EAAC,SAAD;AAAA,MACE,MAAK;AAAA,MACE,OAAA;AAAA,MACG,UATV,CAAY,MAA2C;AAC3D,QAAA,EAAS,EAAE,OAAO,KAAK;AAAA,MACzB;AAAA,MAQmB,aAAA;AAAA,MACb,WAAU;AAAA,IACX,CAAA,GACA,KACC,gBAAA,EAAC,UAAD;AAAA,MACE,WAAU;AAAA,MACV,SAAA,MAAe;AACb,QAAA,EAAS,EAAE,GACX,EAAO,eAAe,MAAS;AAAA,MACjC;AAAA,gBAEA,gBAAA,EAAC,OAAD;AAAA,QAAK,OAAM;AAAA,QAA6B,WAAU;AAAA,QAAU,MAAK;AAAA,QAAO,SAAQ;AAAA,QAAY,QAAO;AAAA,kBACjG,gBAAA,EAAC,QAAD;AAAA,UAAM,eAAc;AAAA,UAAQ,gBAAe;AAAA,UAAQ,aAAY;AAAA,UAAI,GAAE;AAAA,QAAwB,CAAA;AAAA,MAC1F,CAAA;AAAA,IACC,CAAA,CAEP;AAAA;AAET,GAUa,IAAA,CAAkD,EAC7D,QAAA,GACA,KAAA,GACA,KAAA,GACA,MAAA,IAAO,EAAA,MACH;AACJ,QAAM,CAAC,GAAU,CAAA,IAAe,EAAiB,EAAE,GAC7C,CAAC,GAAU,CAAA,IAAe,EAAiB,EAAE,GAE7C,IAAe,EAAY,GAAU,GAAG,GACxC,IAAe,EAAY,GAAU,GAAG;AAG9C,SAAA,EAAA,MAAgB;AACd,UAAM,IAAc,EAAO,eAAe,GACpC,IAAS,KAAe,EAAY,CAAA,MAAO,SAAY,OAAO,EAAY,CAAA,CAAE,IAAI,IAChF,IAAS,KAAe,EAAY,CAAA,MAAO,SAAY,OAAO,EAAY,CAAA,CAAE,IAAI;AAEtF,IAAI,MAAW,KAAU,EAAY,CAAM,GACvC,MAAW,KAAU,EAAY,CAAM;AAAA,EAC7C,GAAG,CAAC,EAAO,eAAe,CAAC,CAAC,GAG5B,EAAA,MAAgB;AACd,UAAM,IAAwD,CAC5D,MAAiB,KAAK,SAAY,OAAO,CAAY,GACrD,MAAiB,KAAK,SAAY,OAAO,CAAY,CACvD;AAGA,IAAI,EAAY,CAAA,MAAO,UAAa,EAAY,CAAA,MAAO,SACrD,EAAO,eAAe,MAAS,IAE/B,EAAO,eAAe,CAAW;AAAA,EAErC,GAAG,CAAC,GAAc,CAAY,CAAC,GAK7B,gBAAA,EAAC,OAAD;AAAA,IAAK,WAAU;AAAA,cAAf,CACE,gBAAA,EAAC,OAAD;AAAA,MAAK,WAAU;AAAA,gBAAf;AAAA,QACE,gBAAA,EAAC,SAAD;AAAA,UACE,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAA,CAAW,MAAM;AACf,YAAA,EAAY,EAAE,OAAO,KAAK;AAAA,UAC5B;AAAA,UACA,aAAY;AAAA,UACP,KAAA;AAAA,UACA,KAAA;AAAA,UACC,MAAA;AAAA,UACN,WAAU;AAAA,QACX,CAAA;AAAA,QACD,gBAAA,EAAC,QAAD,EAAA,UAAM,IAAO,CAAA;AAAA,QACb,gBAAA,EAAC,SAAD;AAAA,UACE,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAA,CAAW,MAAM;AACf,YAAA,EAAY,EAAE,OAAO,KAAK;AAAA,UAC5B;AAAA,UACA,aAAY;AAAA,UACP,KAAA;AAAA,UACA,KAAA;AAAA,UACC,MAAA;AAAA,UACN,WAAU;AAAA,QACX,CAAA;AAAA,MACE;AAAA,SACH,KAAY,MACZ,gBAAA,EAAC,UAAD;AAAA,MACE,WAAU;AAAA,MACV,SAAA,MAAe;AACb,QAAA,EAAY,EAAE,GACd,EAAY,EAAE,GACd,EAAO,eAAe,MAAS;AAAA,MACjC;AAAA,gBACD;AAAA,IAEO,CAAA,CAEP;AAAA;AAET,GASa,IAAA,CAA6C,EACxD,QAAA,GACA,SAAA,GACA,aAAA,IAAc,KAAA,MACV;AACJ,QAAM,CAAC,GAAO,CAAA,IAAY,EAAiB,EAAE;AAG7C,SAAA,EAAA,MAAgB;AACd,UAAM,IAAc,EAAO,eAAe;AAC1C,IAAA,EAAS,MAAgB,SAAY,OAAO,CAAW,IAAI,EAAE;AAAA,EAC/D,GAAG,CAAC,EAAO,eAAe,CAAC,CAAC,GAe1B,gBAAA,EAAC,OAAD;AAAA,IAAK,WAAU;AAAA,cACb,gBAAA,EAAC,UAAD;AAAA,MACS,OAAA;AAAA,MACP,UAfA,CAAgB,MAA4C;AAChE,cAAM,IAAgB,EAAE,OAAO;AAC/B,QAAA,EAAS,CAAa,GAElB,MAAkB,KACpB,EAAO,eAAe,MAAS,IAE/B,EAAO,eAAe,CAAa;AAAA,MAEvC;AAAA,MAOM,WAAU;AAAA,gBAHZ,CAKE,gBAAA,EAAC,UAAD;AAAA,QAAQ,OAAM;AAAA,kBAAI;AAAA,MAAoB,CAAA,GACrC,EAAQ,IAAA,CAAK,GAAQ,MACpB,gBAAA,EAAC,UAAD;AAAA,QAAoB,OAAO,EAAO;AAAA,kBAC/B,EAAO;AAAA,MACF,GAFK,CAEL,CACT,CACK;AAAA;EACL,CAAA;AAET,GAUa,IAAA,CAA+C,EAC1D,QAAA,GACA,WAAA,IAAY,KACZ,YAAA,IAAa,KACb,UAAA,IAAW,KAAA,MACP;AACJ,QAAM,IAAU;AAAA,IACd;AAAA,MAAE,OAAO;AAAA,MAAI,OAAO;AAAA,IAAS;AAAA,IAC7B;AAAA,MAAE,OAAO;AAAA,MAAQ,OAAO;AAAA,IAAU;AAAA,IAClC;AAAA,MAAE,OAAO;AAAA,MAAS,OAAO;AAAA,IAAW;AAAA,EACtC,GAEM,CAAC,GAAO,CAAA,IAAY,EAAiB,EAAE;AAG7C,SAAA,EAAA,MAAgB;AACd,UAAM,IAAc,EAAO,eAAe;AAC1C,IAAA,EAAS,MAAgB,SAAY,OAAO,CAAW,IAAI,EAAE;AAAA,EAC/D,GAAG,CAAC,EAAO,eAAe,CAAC,CAAC,GAe1B,gBAAA,EAAC,OAAD;AAAA,IAAK,WAAU;AAAA,cACb,gBAAA,EAAC,UAAD;AAAA,MACS,OAAA;AAAA,MACP,UAfA,CAAgB,MAA4C;AAChE,cAAM,IAAgB,EAAE,OAAO;AAC/B,QAAA,EAAS,CAAa,GAElB,MAAkB,KACpB,EAAO,eAAe,MAAS,IAE/B,EAAO,eAAe,MAAkB,MAAM;AAAA,MAElD;AAAA,MAOM,WAAU;AAAA,gBAET,EAAQ,IAAA,CAAK,GAAQ,MACpB,gBAAA,EAAC,UAAD;AAAA,QAAoB,OAAO,EAAO;AAAA,kBAC/B,EAAO;AAAA,MACF,GAFK,CAEL,CACT;AAAA,IACK,CAAA;AAAA,EACL,CAAA;AAET,GAOa,IAAA,CAAmD,EAC9D,QAAA,EAAA,MACI;AACJ,QAAM,CAAC,GAAW,CAAA,IAAgB,EAAiB,EAAE,GAC/C,CAAC,GAAS,CAAA,IAAc,EAAiB,EAAE,GAE3C,IAAiB,EAAY,GAAW,GAAG,GAC3C,IAAe,EAAY,GAAS,GAAG;AAG7C,SAAA,EAAA,MAAgB;AACd,UAAM,IAAc,EAAO,eAAe,GACpC,IAAW,KAAe,EAAY,CAAA,IAAK,EAAY,CAAA,IAAK,IAC5D,IAAS,KAAe,EAAY,CAAA,IAAK,EAAY,CAAA,IAAK;AAEhE,IAAI,MAAa,KAAW,EAAa,CAAQ,GAC7C,MAAW,KAAS,EAAW,CAAM;AAAA,EAC3C,GAAG,CAAC,EAAO,eAAe,CAAC,CAAC,GAG5B,EAAA,MAAgB;AACd,UAAM,IAAwD,CAC5D,KAAkB,QAClB,KAAgB,MAClB;AAGA,IAAI,CAAC,EAAY,CAAA,KAAM,CAAC,EAAY,CAAA,IAClC,EAAO,eAAe,MAAS,IAE/B,EAAO,eAAe,CAAW;AAAA,EAErC,GAAG,CAAC,GAAgB,CAAY,CAAC,GAK/B,gBAAA,EAAC,OAAD;AAAA,IAAK,WAAU;AAAA,cAAf,CACE,gBAAA,EAAC,OAAD;AAAA,MAAK,WAAU;AAAA,gBAAf;AAAA,QACE,gBAAA,EAAC,SAAD;AAAA,UACE,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAA,CAAW,MAAM;AACf,YAAA,EAAa,EAAE,OAAO,KAAK;AAAA,UAC7B;AAAA,UACA,WAAU;AAAA,QACX,CAAA;AAAA,QACD,gBAAA,EAAC,QAAD,EAAA,UAAM,IAAO,CAAA;AAAA,QACb,gBAAA,EAAC,SAAD;AAAA,UACE,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAA,CAAW,MAAM;AACf,YAAA,EAAW,EAAE,OAAO,KAAK;AAAA,UAC3B;AAAA,UACA,WAAU;AAAA,QACX,CAAA;AAAA,MACE;AAAA,SACH,KAAa,MACb,gBAAA,EAAC,UAAD;AAAA,MACE,WAAU;AAAA,MACV,SAAA,MAAe;AACb,QAAA,EAAa,EAAE,GACf,EAAW,EAAE,GACb,EAAO,eAAe,MAAS;AAAA,MACjC;AAAA,gBACD;AAAA,IAEO,CAAA,CAEP;AAAA;AAET,GAGa,IAAA,CAAkD,EAC7D,QAAA,GACA,SAAA,GACA,aAAA,IAAc,OAAA,MACV;AACJ,QAAM,CAAC,GAAgB,CAAA,IAAqB,EAAmB,CAAC,CAAC;AAGjE,SAAA,EAAA,MAAgB;AACd,UAAM,IAAc,EAAO,eAAe;AAC1C,IAAA,EAAkB,KAAe,CAAC,CAAC;AAAA,EACrC,GAAG,CAAC,EAAO,eAAe,CAAC,CAAC,GAe1B,gBAAA,EAAC,OAAD;AAAA,IAAK,WAAU;AAAA,cAAf,CACE,gBAAA,EAAC,UAAD;AAAA,MACE,UAAA;AAAA,MACA,OAAO;AAAA,MACP,UAhBA,CAAgB,MAA4C;AAChE,cAAM,IAAS,MAAM,KAAK,EAAE,OAAO,iBAAA,CAAiB,MAAU,EAAO,KAAK;AAC1E,QAAA,EAAkB,CAAM,GAEpB,EAAO,WAAW,IACpB,EAAO,eAAe,MAAS,IAE/B,EAAO,eAAe,CAAM;AAAA,MAEhC;AAAA,MAQM,WAAU;AAAA,gBAET,EAAQ,IAAA,CAAK,GAAQ,MACpB,gBAAA,EAAC,UAAD;AAAA,QAAoB,OAAO,EAAO;AAAA,kBAC/B,EAAO;AAAA,MACF,GAFK,CAEL,CACT;AAAA,IACK,CAAA,GACP,EAAe,SAAS,KACvB,gBAAA,EAAC,OAAD;AAAA,MAAK,WAAU;AAAA,gBAAf,CACE,gBAAA,EAAC,QAAD;AAAA,QAAM,WAAU;AAAA,kBAAhB;AAAA,UAA+C;AAAA,UAAK,EAAe;AAAA,UAAO;AAAA,QAAQ;AAAA,UAClF,gBAAA,EAAC,UAAD;AAAA,QACE,WAAU;AAAA,QACV,SAAA,MAAe;AACb,UAAA,EAAkB,CAAC,CAAC,GACpB,EAAO,eAAe,MAAS;AAAA,QACjC;AAAA,kBACD;AAAA,MAEO,CAAA,CACL;AAAA,MAEJ;AAAA;AAET,GAQa,IAAA,CAA2C,EACtD,QAAA,GACA,SAAA,EAAA,MACI;AAEJ,MAAI,CAAC,KAAU,CAAC,EAAO,UACrB,QAAO;AAIT,QAAM,IAAO,EAAO,UAAU,QAAQ,CAAC,GACjC,IAAa,EAAK,YAClB,IAAgB,EAAK,iBAAiB,CAAC,GAGvC,IAAA,MAAqB;AACzB,QAAI,CAAC,EAAY,QAAO;AAExB,YAAQ,GAAR;AAAA,MACE,KAAK;AACH,eAAO,gBAAA,EAAC,GAAD,EAAoB,QAAA,EAAS,CAAA;AAAA,MACtC,KAAK;AACH,eAAO,gBAAA,EAAC,GAAD,EAA2B,QAAA,EAAS,CAAA;AAAA,MAC7C,KAAK;AACH,eAAO,gBAAA,EAAC,GAAD;AAAA,UAAsB,QAAA;AAAA,UAAQ,SAAS;AAAA,QAAgB,CAAA;AAAA,MAChE,KAAK;AACH,eAAO,gBAAA,EAAC,GAAD,EAAuB,QAAA,EAAS,CAAA;AAAA,MACzC,KAAK;AACH,eAAO,gBAAA,EAAC,GAAD,EAAyB,QAAA,EAAS,CAAA;AAAA,MAC3C,KAAK;AACH,eAAO,gBAAA,EAAC,GAAD;AAAA,UAA2B,QAAA;AAAA,UAAQ,SAAS;AAAA,QAAgB,CAAA;AAAA,MACrE;AACE,eAAO,gBAAA,EAAC,GAAD,EAAoB,QAAA,EAAS,CAAA;AAAA,IACxC;AAAA,EACF;AASA,SACE,gBAAA,EAAC,OAAD;AAAA,IAAK,WAAU;AAAA,cAAf;AAAA,MACE,gBAAA,EAAC,OAAD;AAAA,QAAK,WAAU;AAAA,kBAAf,CACE,gBAAA,EAAC,MAAD;AAAA,UAAI,WAAU;AAAA,oBATC,EAAO,UAAU,UACnC,OAAO,EAAO,UAAU,UAAW,WAClC,EAAO,UAAU,SAEf,EAAO;AAAA,QAKuC,CAAA,GAC9C,gBAAA,EAAC,UAAD;AAAA,UACE,WAAU;AAAA,UACV,SAAS;AAAA,oBAET,gBAAA,EAAC,OAAD;AAAA,YAAK,OAAM;AAAA,YAA6B,WAAU;AAAA,YAAU,MAAK;AAAA,YAAO,SAAQ;AAAA,YAAY,QAAO;AAAA,sBACjG,gBAAA,EAAC,QAAD;AAAA,cAAM,eAAc;AAAA,cAAQ,gBAAe;AAAA,cAAQ,aAAY;AAAA,cAAI,GAAE;AAAA,YAAwB,CAAA;AAAA,UAC1F,CAAA;AAAA,QACC,CAAA,CACL;AAAA;MAEJ,EAAa;AAAA,MAEd,gBAAA,EAAC,OAAD;AAAA,QAAK,WAAU;AAAA,kBACb,gBAAA,EAAC,UAAD;AAAA,UACE,WAAU;AAAA,UACV,SAAA,MAAe;AACb,YAAA,EAAO,eAAe,MAAS,GAC/B,EAAQ;AAAA,UACV;AAAA,oBACD;AAAA,QAEO,CAAA;AAAA,MACL,CAAA;AAAA,IACF;AAAA;AAET,GAEA,IAAe;AAAA,EACb,YAAA;AAAA,EACA,mBAAA;AAAA,EACA,cAAA;AAAA,EACA,eAAA;AAAA,EACA,iBAAA;AAAA,EACA,mBAAA;AAAA,EACA,aAAA;AACF"}
|
|
1
|
+
{"version":3,"file":"Filters.js","names":[],"sources":["../../../../src/components/pro/DataTable/Filters.tsx"],"sourcesContent":["import React, { useState, useEffect } from 'react';\nimport { Column } from './tanstack-table';\nimport { useDebounce } from '../../../hooks/useDebounce';\n\n// 扩展列元数据接口(v9 的 ColumnMeta 位于 @tanstack/table-core,签名必须与原声明完全一致)\ndeclare module '@tanstack/table-core' {\n interface ColumnMeta<\n in out TFeatures extends import('@tanstack/table-core').TableFeatures,\n in out TData extends import('@tanstack/table-core').RowData,\n TValue extends import('@tanstack/table-core').CellData = import('@tanstack/table-core').CellData,\n > {\n filterType?: 'text' | 'number' | 'select' | 'boolean' | 'date' | 'multiSelect';\n filterOptions?: { value: any; label: string }[];\n }\n}\n\nexport interface TextFilterProps {\n column: Column<any, unknown>;\n placeholder?: string;\n}\n\n// 文本过滤器组件\nexport const TextFilter: React.FC<TextFilterProps> = ({\n column,\n placeholder = '搜索...'\n}) => {\n const [value, setValue] = useState('');\n const debouncedValue = useDebounce(value, 300);\n\n // 将组件状态与列过滤状态同步\n useEffect(() => {\n const currentFilterValue = column.getFilterValue() as string || '';\n if (currentFilterValue !== value) {\n setValue(currentFilterValue);\n }\n }, [column.getFilterValue()]);\n\n // 当 debouncedValue 变化时更新列过滤状态\n useEffect(() => {\n column.setFilterValue(debouncedValue || undefined);\n }, [debouncedValue]);\n\n // 处理输入变更\n const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n setValue(e.target.value);\n };\n\n return (\n <div className=\"flex items-center mt-2\">\n <input\n type=\"text\"\n value={value}\n onChange={onChange}\n placeholder={placeholder}\n className=\"input input-bordered input-sm w-full\"\n />\n {value && (\n <button\n className=\"btn btn-ghost btn-xs ml-1\"\n onClick={() => {\n setValue('');\n column.setFilterValue(undefined);\n }}\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n )}\n </div>\n );\n};\n\nexport interface NumberFilterProps {\n column: Column<any, unknown>;\n min?: number;\n max?: number;\n step?: number;\n}\n\n// 数字范围过滤器组件\nexport const NumberRangeFilter: React.FC<NumberFilterProps> = ({\n column,\n min,\n max,\n step = 1\n}) => {\n const [minValue, setMinValue] = useState<string>('');\n const [maxValue, setMaxValue] = useState<string>('');\n\n const debouncedMin = useDebounce(minValue, 300);\n const debouncedMax = useDebounce(maxValue, 300);\n\n // 将组件状态与列过滤状态同步\n useEffect(() => {\n const filterValue = column.getFilterValue() as [number, number] | undefined;\n const newMin = filterValue && filterValue[0] !== undefined ? String(filterValue[0]) : '';\n const newMax = filterValue && filterValue[1] !== undefined ? String(filterValue[1]) : '';\n\n if (newMin !== minValue) setMinValue(newMin);\n if (newMax !== maxValue) setMaxValue(newMax);\n }, [column.getFilterValue()]);\n\n // 当 debounced 值变化时更新列过滤状态\n useEffect(() => {\n const filterValue: [number | undefined, number | undefined] = [\n debouncedMin === '' ? undefined : Number(debouncedMin),\n debouncedMax === '' ? undefined : Number(debouncedMax)\n ];\n\n // 如果两者都是undefined,则清除过滤器\n if (filterValue[0] === undefined && filterValue[1] === undefined) {\n column.setFilterValue(undefined);\n } else {\n column.setFilterValue(filterValue);\n }\n }, [debouncedMin, debouncedMax]);\n\n\n\n return (\n <div className=\"flex flex-col gap-1 mt-2\">\n <div className=\"flex items-center gap-2\">\n <input\n type=\"number\"\n value={minValue}\n onChange={(e) => {\n setMinValue(e.target.value);\n }}\n placeholder=\"最小值\"\n min={min}\n max={max}\n step={step}\n className=\"input input-bordered input-sm w-full\"\n />\n <span>至</span>\n <input\n type=\"number\"\n value={maxValue}\n onChange={(e) => {\n setMaxValue(e.target.value);\n }}\n placeholder=\"最大值\"\n min={min}\n max={max}\n step={step}\n className=\"input input-bordered input-sm w-full\"\n />\n </div>\n {(minValue || maxValue) && (\n <button\n className=\"btn btn-ghost btn-xs self-end\"\n onClick={() => {\n setMinValue('');\n setMaxValue('');\n column.setFilterValue(undefined);\n }}\n >\n 清除\n </button>\n )}\n </div>\n );\n};\n\nexport interface SelectFilterProps {\n column: Column<any, unknown>;\n options: { value: any; label: string }[];\n placeholder?: string;\n}\n\n// 选择过滤器组件\nexport const SelectFilter: React.FC<SelectFilterProps> = ({\n column,\n options,\n placeholder = '全部'\n}) => {\n const [value, setValue] = useState<string>('');\n\n // 将组件状态与列过滤状态同步\n useEffect(() => {\n const filterValue = column.getFilterValue();\n setValue(filterValue !== undefined ? String(filterValue) : '');\n }, [column.getFilterValue()]);\n\n // 处理选择变更\n const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {\n const selectedValue = e.target.value;\n setValue(selectedValue);\n\n if (selectedValue === '') {\n column.setFilterValue(undefined);\n } else {\n column.setFilterValue(selectedValue);\n }\n };\n\n return (\n <div className=\"mt-2\">\n <select\n value={value}\n onChange={handleChange}\n className=\"select select-bordered select-sm w-full\"\n >\n <option value=\"\">{placeholder}</option>\n {options.map((option, index) => (\n <option key={index} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n </div>\n );\n};\n\nexport interface BooleanFilterProps {\n column: Column<any, unknown>;\n trueLabel?: string;\n falseLabel?: string;\n allLabel?: string;\n}\n\n// 布尔值过滤器组件\nexport const BooleanFilter: React.FC<BooleanFilterProps> = ({\n column,\n trueLabel = '是',\n falseLabel = '否',\n allLabel = '全部'\n}) => {\n const options = [\n { value: '', label: allLabel },\n { value: 'true', label: trueLabel },\n { value: 'false', label: falseLabel }\n ];\n\n const [value, setValue] = useState<string>('');\n\n // 将组件状态与列过滤状态同步\n useEffect(() => {\n const filterValue = column.getFilterValue();\n setValue(filterValue !== undefined ? String(filterValue) : '');\n }, [column.getFilterValue()]);\n\n // 处理选择变更\n const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {\n const selectedValue = e.target.value;\n setValue(selectedValue);\n\n if (selectedValue === '') {\n column.setFilterValue(undefined);\n } else {\n column.setFilterValue(selectedValue === 'true');\n }\n };\n\n return (\n <div className=\"mt-2\">\n <select\n value={value}\n onChange={handleChange}\n className=\"select select-bordered select-sm w-full\"\n >\n {options.map((option, index) => (\n <option key={index} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n </div>\n );\n};\n\nexport interface DateRangeFilterProps {\n column: Column<any, unknown>;\n}\n\n// 日期范围过滤器组件\nexport const DateRangeFilter: React.FC<DateRangeFilterProps> = ({\n column\n}) => {\n const [startDate, setStartDate] = useState<string>('');\n const [endDate, setEndDate] = useState<string>('');\n\n const debouncedStart = useDebounce(startDate, 300);\n const debouncedEnd = useDebounce(endDate, 300);\n\n // 将组件状态与列过滤状态同步\n useEffect(() => {\n const filterValue = column.getFilterValue() as [string, string] | undefined;\n const newStart = filterValue && filterValue[0] ? filterValue[0] : '';\n const newEnd = filterValue && filterValue[1] ? filterValue[1] : '';\n\n if (newStart !== startDate) setStartDate(newStart);\n if (newEnd !== endDate) setEndDate(newEnd);\n }, [column.getFilterValue()]);\n\n // 当 debounced 值变化时更新列过滤状态\n useEffect(() => {\n const filterValue: [string | undefined, string | undefined] = [\n debouncedStart || undefined,\n debouncedEnd || undefined\n ];\n\n // 如果两者都是undefined,则清除过滤器\n if (!filterValue[0] && !filterValue[1]) {\n column.setFilterValue(undefined);\n } else {\n column.setFilterValue(filterValue);\n }\n }, [debouncedStart, debouncedEnd]);\n\n\n\n return (\n <div className=\"flex flex-col gap-1 mt-2\">\n <div className=\"flex items-center gap-2\">\n <input\n type=\"date\"\n value={startDate}\n onChange={(e) => {\n setStartDate(e.target.value);\n }}\n className=\"input input-bordered input-sm w-full\"\n />\n <span>至</span>\n <input\n type=\"date\"\n value={endDate}\n onChange={(e) => {\n setEndDate(e.target.value);\n }}\n className=\"input input-bordered input-sm w-full\"\n />\n </div>\n {(startDate || endDate) && (\n <button\n className=\"btn btn-ghost btn-xs self-end\"\n onClick={() => {\n setStartDate('');\n setEndDate('');\n column.setFilterValue(undefined);\n }}\n >\n 清除\n </button>\n )}\n </div>\n );\n};\n\n// 多选过滤器组件\nexport const MultiSelectFilter: React.FC<SelectFilterProps> = ({\n column,\n options,\n placeholder = '选择选项'\n}) => {\n const [selectedValues, setSelectedValues] = useState<string[]>([]);\n\n // 将组件状态与列过滤状态同步\n useEffect(() => {\n const filterValue = column.getFilterValue() as string[] | undefined;\n setSelectedValues(filterValue || []);\n }, [column.getFilterValue()]);\n\n // 处理选择变更\n const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {\n const values = Array.from(e.target.selectedOptions, option => option.value);\n setSelectedValues(values);\n\n if (values.length === 0) {\n column.setFilterValue(undefined);\n } else {\n column.setFilterValue(values);\n }\n };\n\n return (\n <div className=\"mt-2\">\n <select\n multiple\n value={selectedValues}\n onChange={handleChange}\n className=\"select select-bordered select-sm w-full max-h-32\"\n >\n {options.map((option, index) => (\n <option key={index} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n {selectedValues.length > 0 && (\n <div className=\"flex justify-between mt-1\">\n <span className=\"text-xs text-base-content/70\">已选择 {selectedValues.length} 项</span>\n <button\n className=\"btn btn-ghost btn-xs\"\n onClick={() => {\n setSelectedValues([]);\n column.setFilterValue(undefined);\n }}\n >\n 清除\n </button>\n </div>\n )}\n </div>\n );\n};\n\n// 过滤器面板组件\nexport interface FilterPanelProps {\n column: Column<any, unknown>;\n onClose: () => void;\n}\n\nexport const FilterPanel: React.FC<FilterPanelProps> = ({\n column,\n onClose\n}) => {\n // 确保column和column.columnDef存在\n if (!column || !column.columnDef) {\n return null;\n }\n\n // 获取过滤器类型,确保meta存在\n const meta = column.columnDef.meta || {};\n const filterType = meta.filterType;\n const filterOptions = meta.filterOptions || [];\n\n // 根据过滤器类型渲染相应的组件\n const renderFilter = () => {\n if (!filterType) return null;\n\n switch (filterType) {\n case 'text':\n return <TextFilter column={column} />;\n case 'number':\n return <NumberRangeFilter column={column} />;\n case 'select':\n return <SelectFilter column={column} options={filterOptions} />;\n case 'boolean':\n return <BooleanFilter column={column} />;\n case 'date':\n return <DateRangeFilter column={column} />;\n case 'multiSelect':\n return <MultiSelectFilter column={column} options={filterOptions} />;\n default:\n return <TextFilter column={column} />;\n }\n };\n\n // 列标题\n const columnHeader = column.columnDef.header ?\n (typeof column.columnDef.header === 'string' ?\n column.columnDef.header :\n column.id\n ) : column.id;\n\n return (\n <div className=\"card bg-base-100 shadow-lg p-4 w-64 z-50\">\n <div className=\"flex justify-between items-center mb-2\">\n <h3 className=\"font-medium\">{columnHeader}</h3>\n <button\n className=\"btn btn-ghost btn-xs\"\n onClick={onClose}\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n {renderFilter()}\n\n <div className=\"flex justify-end mt-2\">\n <button\n className=\"btn btn-ghost btn-xs\"\n onClick={() => {\n column.setFilterValue(undefined);\n onClose();\n }}\n >\n 清除过滤\n </button>\n </div>\n </div>\n );\n};\n\nexport default {\n TextFilter,\n NumberRangeFilter,\n SelectFilter,\n BooleanFilter,\n DateRangeFilter,\n MultiSelectFilter,\n FilterPanel\n}; "],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PivotPanel.js","names":[],"sources":["../../../../src/components/pro/DataTable/PivotPanel.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\nimport type { PivotValue, PivotFieldLabels } from './PivotView';\nimport type { PivotAggFn } from './pivotEngine';\nimport type { PivotField } from './pivotExtension';\n\nconst AGG_FNS: PivotAggFn[] = ['sum', 'avg', 'count', 'min', 'max'];\n\n/** 面板内的区域标识。 */\ntype ZoneId = 'available' | 'rows' | 'cols' | 'values';\n\nconst TEXT = {\n zh: {\n available: '可用字段',\n rowGroups: '行分组',\n colGroups: '列分组',\n values: '数值',\n empty: '(无字段)',\n dropHint: '拖拽字段到此',\n remove: '移除',\n },\n en: {\n available: 'Available',\n rowGroups: 'Row Groups',\n colGroups: 'Column Labels',\n values: 'Values',\n empty: '(no fields)',\n dropHint: 'Drag fields here',\n remove: 'Remove',\n },\n} as const;\n\n/** 透明的 1x1 拖拽图,用于隐藏浏览器默认的拖拽影像(改用自定义 ghost)。 */\nconst EMPTY_DRAG_IMAGE =\n typeof Image !== 'undefined'\n ? (() => {\n const img = new Image();\n img.src =\n 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';\n return img;\n })()\n : null;\n\nexport interface PivotPanelProps {\n /** 面板排布方向:水平(工具栏下方)或垂直(表格左/右侧)。 */\n orientation: 'horizontal' | 'vertical';\n lang: 'zh' | 'en';\n fieldLabels: PivotFieldLabels;\n dimensionFields: PivotField[];\n numericFields: PivotField[];\n rowFields: string[];\n colFields: string[];\n values: PivotValue[];\n setRowFields: React.Dispatch<React.SetStateAction<string[]>>;\n setColFields: React.Dispatch<React.SetStateAction<string[]>>;\n setValues: React.Dispatch<React.SetStateAction<PivotValue[]>>;\n /**\n * 垂直(左/右)面板的宽度。数字视为 px,字符串直接作为 CSS 宽度\n * (如 `'20%'` / `'16rem'`)。仅在 `orientation='vertical'` 时生效,默认 224px。\n */\n panelWidth?: number | string;\n}\n\n/**\n * 当前拖拽的字段信息(低频变化:仅在拖拽开始 / 结束时更新,\n * 不含坐标,避免拖拽过程中高频 setState 导致 chip 重挂载而使拖拽卡死)。\n */\ninterface DragInfo {\n field: string;\n label: string;\n numeric: boolean;\n}\n\n/**\n * ag-grid 风格的透视配置面板。\n *\n * 特性:\n * - 支持水平(`horizontal`)与垂直(`vertical`)两种排布,后者用于表格左/右侧。\n * - 拖拽字段时显示跟随光标的「拖拽引用」(ghost 预览),并高亮可放置的目标区域。\n *\n * 关键实现:拖拽期间**不** setState 更新坐标,而是用 ref 直接改写 ghost 的\n * transform;`Chip`/`Zone` 用渲染函数而非内联组件,避免每次渲染都被 React\n * 当作新组件类型而卸载重挂载(那会中断浏览器原生拖拽,导致卡死)。\n */\nexport function PivotPanel({\n orientation,\n lang,\n fieldLabels,\n dimensionFields,\n numericFields,\n rowFields,\n colFields,\n values,\n setRowFields,\n setColFields,\n setValues,\n panelWidth = 224,\n}: PivotPanelProps) {\n const t = TEXT[lang];\n const labelOf = (field: string) => fieldLabels[field] ?? field;\n const isNumericField = (field: string) =>\n numericFields.some((f) => f.field === field);\n\n const [drag, setDrag] = useState<DragInfo | null>(null);\n const [overZone, setOverZone] = useState<ZoneId | null>(null);\n const ghostRef = useRef<HTMLDivElement | null>(null);\n const pointerRef = useRef<{ x: number; y: number }>({ x: 0, y: 0 });\n const dragging = drag != null;\n\n // 拖拽期间用 window 级 `dragover` 直接更新 ghost 位置(ref 操作 DOM,不触发\n // React 重渲染),坐标不进入 state,从根本上避免 chip 子树重挂载而卡死。\n // 同时用 window 级 `dragend`/`drop` 兜底清除拖拽状态:放置后源 chip 常因状态\n // 更新被移动/重建,其自身的 `onDragEnd` 可能不再触发,导致 ghost 残留。\n useEffect(() => {\n if (!dragging) return;\n const positionGhost = () => {\n const el = ghostRef.current;\n if (!el) return;\n el.style.transform = `translate(${pointerRef.current.x + 12}px, ${\n pointerRef.current.y + 12\n }px)`;\n };\n positionGhost();\n const onWindowDragOver = (e: DragEvent) => {\n if (e.clientX === 0 && e.clientY === 0) return;\n pointerRef.current = { x: e.clientX, y: e.clientY };\n positionGhost();\n };\n const clear = () => {\n setDrag(null);\n setOverZone(null);\n };\n window.addEventListener('dragover', onWindowDragOver);\n window.addEventListener('dragend', clear);\n window.addEventListener('drop', clear);\n return () => {\n window.removeEventListener('dragover', onWindowDragOver);\n window.removeEventListener('dragend', clear);\n window.removeEventListener('drop', clear);\n };\n }, [dragging]);\n\n const usedDims = new Set<string>([...rowFields, ...colFields]);\n const availableDims = dimensionFields.filter((f) => !usedDims.has(f.field));\n const usedValues = new Set(values.map((v) => v.field));\n const availableValues = numericFields.filter((f) => !usedValues.has(f.field));\n\n const removeFromAll = (field: string) => {\n setRowFields((prev) => prev.filter((x) => x !== field));\n setColFields((prev) => prev.filter((x) => x !== field));\n setValues((prev) => prev.filter((x) => x.field !== field));\n };\n\n /** 某个区域是否能接收当前正在拖拽的字段。 */\n const zoneAccepts = (zone: ZoneId): boolean => {\n if (!drag) return false;\n if (zone === 'available') return true;\n if (zone === 'values') return drag.numeric;\n return !drag.numeric; // rows / cols 只接受维度字段\n };\n\n const dropTo = (zone: ZoneId, field: string) => {\n const numeric = isNumericField(field);\n if (zone === 'values') {\n if (!numeric) return;\n setRowFields((prev) => prev.filter((x) => x !== field));\n setColFields((prev) => prev.filter((x) => x !== field));\n setValues((prev) =>\n prev.some((v) => v.field === field)\n ? prev\n : [...prev, { field, aggFn: 'sum' }],\n );\n return;\n }\n if (zone === 'rows' || zone === 'cols') {\n if (numeric) return;\n setValues((prev) => prev.filter((x) => x.field !== field));\n if (zone === 'rows') {\n setColFields((prev) => prev.filter((x) => x !== field));\n setRowFields((prev) =>\n prev.includes(field) ? prev : [...prev, field],\n );\n } else {\n setRowFields((prev) => prev.filter((x) => x !== field));\n setColFields((prev) =>\n prev.includes(field) ? prev : [...prev, field],\n );\n }\n return;\n }\n removeFromAll(field);\n };\n\n const onChipDragStart = (e: React.DragEvent, field: string) => {\n e.dataTransfer.setData('text/plain', field);\n e.dataTransfer.effectAllowed = 'move';\n if (EMPTY_DRAG_IMAGE) {\n e.dataTransfer.setDragImage(EMPTY_DRAG_IMAGE, 0, 0);\n }\n pointerRef.current = { x: e.clientX, y: e.clientY };\n setDrag({\n field,\n label: labelOf(field),\n numeric: isNumericField(field),\n });\n };\n\n const onChipDragEnd = () => {\n setDrag(null);\n setOverZone(null);\n };\n\n const vertical = orientation === 'vertical';\n\n // 渲染一个可拖拽的字段 chip(用渲染函数而非组件,避免重挂载)。\n const renderChip = (\n field: string,\n opts?: { onRemove?: () => void; prefix?: React.ReactNode },\n ) => (\n <span\n key={field}\n draggable\n onDragStart={(e) => onChipDragStart(e, field)}\n onDragEnd={onChipDragEnd}\n className={`badge badge-outline gap-1 items-center cursor-grab active:cursor-grabbing select-none ${\n drag?.field === field ? 'opacity-40' : ''\n }`}\n >\n {opts?.prefix}\n {labelOf(field)}\n {opts?.onRemove && (\n <button\n type=\"button\"\n className=\"text-xs opacity-60 hover:opacity-100\"\n onClick={opts.onRemove}\n aria-label={t.remove}\n >\n ✕\n </button>\n )}\n </span>\n );\n\n // 渲染一个拖放区段(渲染函数,非组件)。\n const renderZone = (\n zone: ZoneId,\n icon: string,\n title: string,\n children: React.ReactNode,\n ) => {\n const accepts = zoneAccepts(zone);\n const isOver = overZone === zone;\n const boxTone = drag\n ? accepts\n ? isOver\n ? 'border-primary border-solid bg-primary/10'\n : 'border-primary/60 border-dashed bg-primary/5'\n : 'border-base-300 border-dashed opacity-40'\n : 'border-base-300 border-dashed bg-base-100/50';\n return (\n <div\n className={`flex flex-col gap-1 ${vertical ? 'w-full' : 'flex-1 min-w-40'}`}\n onDragOver={(e) => {\n if (!accepts) return;\n e.preventDefault();\n e.dataTransfer.dropEffect = 'move';\n if (overZone !== zone) setOverZone(zone);\n }}\n onDragLeave={(e) => {\n // 仅当真正离开该区域(而非进入其子元素)时才清除高亮。\n if (e.currentTarget.contains(e.relatedTarget as Node)) return;\n if (overZone === zone) setOverZone(null);\n }}\n onDrop={(e) => {\n e.preventDefault();\n const field = e.dataTransfer.getData('text/plain');\n setOverZone(null);\n if (field) dropTo(zone, field);\n }}\n >\n <span className=\"text-xs font-semibold opacity-60 flex items-center gap-1\">\n <span aria-hidden>{icon}</span>\n {title}\n </span>\n <div\n className={`flex flex-wrap gap-1 items-center content-start p-1.5 border rounded transition-colors ${\n vertical ? 'min-h-16' : 'min-h-9'\n } ${boxTone}`}\n >\n {children}\n </div>\n </div>\n );\n };\n\n const divider = vertical ? null : (\n <div className=\"w-px bg-base-300 self-stretch\" />\n );\n\n return (\n <>\n <div\n className={`gap-2 p-2 border border-base-300 rounded-box bg-base-200/40 ${\n vertical\n ? 'flex flex-col shrink-0 self-stretch overflow-auto'\n : 'w-full flex flex-wrap items-stretch'\n }`}\n style={\n vertical\n ? {\n width:\n typeof panelWidth === 'number'\n ? `${panelWidth}px`\n : panelWidth,\n }\n : undefined\n }\n >\n {renderZone(\n 'available',\n '☷',\n t.available,\n <>\n {availableDims.length === 0 &&\n availableValues.length === 0 && (\n <span className=\"text-xs opacity-40\">\n {t.empty}\n </span>\n )}\n {availableDims.map((f) => renderChip(f.field))}\n {availableValues.map((f) =>\n renderChip(f.field, {\n prefix: <span className=\"opacity-70\">#</span>,\n }),\n )}\n </>,\n )}\n\n {divider}\n\n {renderZone(\n 'rows',\n '≣',\n t.rowGroups,\n <>\n {rowFields.length === 0 && (\n <span className=\"text-xs opacity-40\">\n {t.dropHint}\n </span>\n )}\n {rowFields.map((field) =>\n renderChip(field, {\n onRemove: () => removeFromAll(field),\n }),\n )}\n </>,\n )}\n\n {divider}\n\n {renderZone(\n 'cols',\n '║',\n t.colGroups,\n <>\n {colFields.length === 0 && (\n <span className=\"text-xs opacity-40\">\n {t.dropHint}\n </span>\n )}\n {colFields.map((field) =>\n renderChip(field, {\n onRemove: () => removeFromAll(field),\n }),\n )}\n </>,\n )}\n\n {divider}\n\n {renderZone(\n 'values',\n 'Σ',\n t.values,\n <>\n {values.length === 0 && (\n <span className=\"text-xs opacity-40\">\n {t.dropHint}\n </span>\n )}\n {values.map((v, i) => (\n <span\n key={`${v.field}:${i}`}\n draggable\n onDragStart={(e) => onChipDragStart(e, v.field)}\n onDragEnd={onChipDragEnd}\n className={`badge badge-outline gap-1 items-center cursor-grab active:cursor-grabbing select-none ${\n drag?.field === v.field ? 'opacity-40' : ''\n }`}\n >\n <select\n className=\"bg-transparent text-xs outline-none\"\n value={v.aggFn}\n // 防止在 select 上开始拖拽。\n draggable={false}\n onChange={(e) =>\n setValues(\n values.map((x, xi) =>\n xi === i\n ? {\n ...x,\n aggFn: e.target\n .value as PivotAggFn,\n }\n : x,\n ),\n )\n }\n >\n {AGG_FNS.map((fn) => (\n <option key={fn} value={fn}>\n {fn}\n </option>\n ))}\n </select>\n <span>{labelOf(v.field)}</span>\n <button\n type=\"button\"\n className=\"text-xs opacity-60 hover:opacity-100\"\n onClick={() =>\n setValues(\n values.filter((_, xi) => xi !== i),\n )\n }\n aria-label={t.remove}\n >\n ✕\n </button>\n </span>\n ))}\n </>,\n )}\n </div>\n\n {/* 拖拽引用(ghost 预览):跟随光标显示当前拖拽的字段。\n 位置由 window `dragover` 通过 ref 直接更新,不触发重渲染。 */}\n {drag && (\n <div\n ref={ghostRef}\n className=\"badge badge-primary gap-1 items-center shadow-lg pointer-events-none\"\n style={{\n position: 'fixed',\n left: 0,\n top: 0,\n zIndex: 2000,\n willChange: 'transform',\n }}\n >\n {drag.numeric && <span className=\"opacity-80\">#</span>}\n {drag.label}\n </div>\n )}\n </>\n );\n}\n\nexport default PivotPanel;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PivotPanel.js","names":[],"sources":["../../../../src/components/pro/DataTable/PivotPanel.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\nimport type { PivotValue, PivotFieldLabels } from './PivotView';\nimport type { PivotAggFn } from './pivotEngine';\nimport type { PivotField } from './pivotExtension';\n\nconst AGG_FNS: PivotAggFn[] = ['sum', 'avg', 'count', 'min', 'max'];\n\n/** 面板内的区域标识。 */\ntype ZoneId = 'available' | 'rows' | 'cols' | 'values';\n\nconst TEXT = {\n zh: {\n available: '可用字段',\n rowGroups: '行分组',\n colGroups: '列分组',\n values: '数值',\n empty: '(无字段)',\n dropHint: '拖拽字段到此',\n remove: '移除',\n },\n en: {\n available: 'Available',\n rowGroups: 'Row Groups',\n colGroups: 'Column Labels',\n values: 'Values',\n empty: '(no fields)',\n dropHint: 'Drag fields here',\n remove: 'Remove',\n },\n} as const;\n\n/** 透明的 1x1 拖拽图,用于隐藏浏览器默认的拖拽影像(改用自定义 ghost)。 */\nconst EMPTY_DRAG_IMAGE =\n typeof Image !== 'undefined'\n ? (() => {\n const img = new Image();\n img.src =\n 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';\n return img;\n })()\n : null;\n\nexport interface PivotPanelProps {\n /** 面板排布方向:水平(工具栏下方)或垂直(表格左/右侧)。 */\n orientation: 'horizontal' | 'vertical';\n lang: 'zh' | 'en';\n fieldLabels: PivotFieldLabels;\n dimensionFields: PivotField[];\n numericFields: PivotField[];\n rowFields: string[];\n colFields: string[];\n values: PivotValue[];\n setRowFields: React.Dispatch<React.SetStateAction<string[]>>;\n setColFields: React.Dispatch<React.SetStateAction<string[]>>;\n setValues: React.Dispatch<React.SetStateAction<PivotValue[]>>;\n /**\n * 垂直(左/右)面板的宽度。数字视为 px,字符串直接作为 CSS 宽度\n * (如 `'20%'` / `'16rem'`)。仅在 `orientation='vertical'` 时生效,默认 224px。\n */\n panelWidth?: number | string;\n}\n\n/**\n * 当前拖拽的字段信息(低频变化:仅在拖拽开始 / 结束时更新,\n * 不含坐标,避免拖拽过程中高频 setState 导致 chip 重挂载而使拖拽卡死)。\n */\ninterface DragInfo {\n field: string;\n label: string;\n numeric: boolean;\n}\n\n/**\n * ag-grid 风格的透视配置面板。\n *\n * 特性:\n * - 支持水平(`horizontal`)与垂直(`vertical`)两种排布,后者用于表格左/右侧。\n * - 拖拽字段时显示跟随光标的「拖拽引用」(ghost 预览),并高亮可放置的目标区域。\n *\n * 关键实现:拖拽期间**不** setState 更新坐标,而是用 ref 直接改写 ghost 的\n * transform;`Chip`/`Zone` 用渲染函数而非内联组件,避免每次渲染都被 React\n * 当作新组件类型而卸载重挂载(那会中断浏览器原生拖拽,导致卡死)。\n */\nexport function PivotPanel({\n orientation,\n lang,\n fieldLabels,\n dimensionFields,\n numericFields,\n rowFields,\n colFields,\n values,\n setRowFields,\n setColFields,\n setValues,\n panelWidth = 224,\n}: PivotPanelProps) {\n const t = TEXT[lang];\n const labelOf = (field: string) => fieldLabels[field] ?? field;\n const isNumericField = (field: string) =>\n numericFields.some((f) => f.field === field);\n\n const [drag, setDrag] = useState<DragInfo | null>(null);\n const [overZone, setOverZone] = useState<ZoneId | null>(null);\n const ghostRef = useRef<HTMLDivElement | null>(null);\n const pointerRef = useRef<{ x: number; y: number }>({ x: 0, y: 0 });\n const dragging = drag != null;\n\n // 拖拽期间用 window 级 `dragover` 直接更新 ghost 位置(ref 操作 DOM,不触发\n // React 重渲染),坐标不进入 state,从根本上避免 chip 子树重挂载而卡死。\n // 同时用 window 级 `dragend`/`drop` 兜底清除拖拽状态:放置后源 chip 常因状态\n // 更新被移动/重建,其自身的 `onDragEnd` 可能不再触发,导致 ghost 残留。\n useEffect(() => {\n if (!dragging) return;\n const positionGhost = () => {\n const el = ghostRef.current;\n if (!el) return;\n el.style.transform = `translate(${pointerRef.current.x + 12}px, ${\n pointerRef.current.y + 12\n }px)`;\n };\n positionGhost();\n const onWindowDragOver = (e: DragEvent) => {\n if (e.clientX === 0 && e.clientY === 0) return;\n pointerRef.current = { x: e.clientX, y: e.clientY };\n positionGhost();\n };\n const clear = () => {\n setDrag(null);\n setOverZone(null);\n };\n window.addEventListener('dragover', onWindowDragOver);\n window.addEventListener('dragend', clear);\n window.addEventListener('drop', clear);\n return () => {\n window.removeEventListener('dragover', onWindowDragOver);\n window.removeEventListener('dragend', clear);\n window.removeEventListener('drop', clear);\n };\n }, [dragging]);\n\n const usedDims = new Set<string>([...rowFields, ...colFields]);\n const availableDims = dimensionFields.filter((f) => !usedDims.has(f.field));\n const usedValues = new Set(values.map((v) => v.field));\n const availableValues = numericFields.filter((f) => !usedValues.has(f.field));\n\n const removeFromAll = (field: string) => {\n setRowFields((prev) => prev.filter((x) => x !== field));\n setColFields((prev) => prev.filter((x) => x !== field));\n setValues((prev) => prev.filter((x) => x.field !== field));\n };\n\n /** 某个区域是否能接收当前正在拖拽的字段。 */\n const zoneAccepts = (zone: ZoneId): boolean => {\n if (!drag) return false;\n if (zone === 'available') return true;\n if (zone === 'values') return drag.numeric;\n return !drag.numeric; // rows / cols 只接受维度字段\n };\n\n const dropTo = (zone: ZoneId, field: string) => {\n const numeric = isNumericField(field);\n if (zone === 'values') {\n if (!numeric) return;\n setRowFields((prev) => prev.filter((x) => x !== field));\n setColFields((prev) => prev.filter((x) => x !== field));\n setValues((prev) =>\n prev.some((v) => v.field === field)\n ? prev\n : [...prev, { field, aggFn: 'sum' }],\n );\n return;\n }\n if (zone === 'rows' || zone === 'cols') {\n if (numeric) return;\n setValues((prev) => prev.filter((x) => x.field !== field));\n if (zone === 'rows') {\n setColFields((prev) => prev.filter((x) => x !== field));\n setRowFields((prev) =>\n prev.includes(field) ? prev : [...prev, field],\n );\n } else {\n setRowFields((prev) => prev.filter((x) => x !== field));\n setColFields((prev) =>\n prev.includes(field) ? prev : [...prev, field],\n );\n }\n return;\n }\n removeFromAll(field);\n };\n\n const onChipDragStart = (e: React.DragEvent, field: string) => {\n e.dataTransfer.setData('text/plain', field);\n e.dataTransfer.effectAllowed = 'move';\n if (EMPTY_DRAG_IMAGE) {\n e.dataTransfer.setDragImage(EMPTY_DRAG_IMAGE, 0, 0);\n }\n pointerRef.current = { x: e.clientX, y: e.clientY };\n setDrag({\n field,\n label: labelOf(field),\n numeric: isNumericField(field),\n });\n };\n\n const onChipDragEnd = () => {\n setDrag(null);\n setOverZone(null);\n };\n\n const vertical = orientation === 'vertical';\n\n // 渲染一个可拖拽的字段 chip(用渲染函数而非组件,避免重挂载)。\n const renderChip = (\n field: string,\n opts?: { onRemove?: () => void; prefix?: React.ReactNode },\n ) => (\n <span\n key={field}\n draggable\n onDragStart={(e) => onChipDragStart(e, field)}\n onDragEnd={onChipDragEnd}\n className={`badge badge-outline gap-1 items-center cursor-grab active:cursor-grabbing select-none ${\n drag?.field === field ? 'opacity-40' : ''\n }`}\n >\n {opts?.prefix}\n {labelOf(field)}\n {opts?.onRemove && (\n <button\n type=\"button\"\n className=\"text-xs opacity-60 hover:opacity-100\"\n onClick={opts.onRemove}\n aria-label={t.remove}\n >\n ✕\n </button>\n )}\n </span>\n );\n\n // 渲染一个拖放区段(渲染函数,非组件)。\n const renderZone = (\n zone: ZoneId,\n icon: string,\n title: string,\n children: React.ReactNode,\n ) => {\n const accepts = zoneAccepts(zone);\n const isOver = overZone === zone;\n const boxTone = drag\n ? accepts\n ? isOver\n ? 'border-primary border-solid bg-primary/10'\n : 'border-primary/60 border-dashed bg-primary/5'\n : 'border-base-300 border-dashed opacity-40'\n : 'border-base-300 border-dashed bg-base-100/50';\n return (\n <div\n className={`flex flex-col gap-1 ${vertical ? 'w-full' : 'flex-1 min-w-40'}`}\n onDragOver={(e) => {\n if (!accepts) return;\n e.preventDefault();\n e.dataTransfer.dropEffect = 'move';\n if (overZone !== zone) setOverZone(zone);\n }}\n onDragLeave={(e) => {\n // 仅当真正离开该区域(而非进入其子元素)时才清除高亮。\n if (e.currentTarget.contains(e.relatedTarget as Node)) return;\n if (overZone === zone) setOverZone(null);\n }}\n onDrop={(e) => {\n e.preventDefault();\n const field = e.dataTransfer.getData('text/plain');\n setOverZone(null);\n if (field) dropTo(zone, field);\n }}\n >\n <span className=\"text-xs font-semibold opacity-60 flex items-center gap-1\">\n <span aria-hidden>{icon}</span>\n {title}\n </span>\n <div\n className={`flex flex-wrap gap-1 items-center content-start p-1.5 border rounded transition-colors ${\n vertical ? 'min-h-16' : 'min-h-9'\n } ${boxTone}`}\n >\n {children}\n </div>\n </div>\n );\n };\n\n const divider = vertical ? null : (\n <div className=\"w-px bg-base-300 self-stretch\" />\n );\n\n return (\n <>\n <div\n className={`gap-2 p-2 border border-base-300 rounded-box bg-base-200/40 ${\n vertical\n ? 'flex flex-col shrink-0 self-stretch overflow-auto'\n : 'w-full flex flex-wrap items-stretch'\n }`}\n style={\n vertical\n ? {\n width:\n typeof panelWidth === 'number'\n ? `${panelWidth}px`\n : panelWidth,\n }\n : undefined\n }\n >\n {renderZone(\n 'available',\n '☷',\n t.available,\n <>\n {availableDims.length === 0 &&\n availableValues.length === 0 && (\n <span className=\"text-xs opacity-40\">\n {t.empty}\n </span>\n )}\n {availableDims.map((f) => renderChip(f.field))}\n {availableValues.map((f) =>\n renderChip(f.field, {\n prefix: <span className=\"opacity-70\">#</span>,\n }),\n )}\n </>,\n )}\n\n {divider}\n\n {renderZone(\n 'rows',\n '≣',\n t.rowGroups,\n <>\n {rowFields.length === 0 && (\n <span className=\"text-xs opacity-40\">\n {t.dropHint}\n </span>\n )}\n {rowFields.map((field) =>\n renderChip(field, {\n onRemove: () => removeFromAll(field),\n }),\n )}\n </>,\n )}\n\n {divider}\n\n {renderZone(\n 'cols',\n '║',\n t.colGroups,\n <>\n {colFields.length === 0 && (\n <span className=\"text-xs opacity-40\">\n {t.dropHint}\n </span>\n )}\n {colFields.map((field) =>\n renderChip(field, {\n onRemove: () => removeFromAll(field),\n }),\n )}\n </>,\n )}\n\n {divider}\n\n {renderZone(\n 'values',\n 'Σ',\n t.values,\n <>\n {values.length === 0 && (\n <span className=\"text-xs opacity-40\">\n {t.dropHint}\n </span>\n )}\n {values.map((v, i) => (\n <span\n key={`${v.field}:${i}`}\n draggable\n onDragStart={(e) => onChipDragStart(e, v.field)}\n onDragEnd={onChipDragEnd}\n className={`badge badge-outline gap-1 items-center cursor-grab active:cursor-grabbing select-none ${\n drag?.field === v.field ? 'opacity-40' : ''\n }`}\n >\n <select\n className=\"bg-transparent text-xs outline-none\"\n value={v.aggFn}\n // 防止在 select 上开始拖拽。\n draggable={false}\n onChange={(e) =>\n setValues(\n values.map((x, xi) =>\n xi === i\n ? {\n ...x,\n aggFn: e.target\n .value as PivotAggFn,\n }\n : x,\n ),\n )\n }\n >\n {AGG_FNS.map((fn) => (\n <option key={fn} value={fn}>\n {fn}\n </option>\n ))}\n </select>\n <span>{labelOf(v.field)}</span>\n <button\n type=\"button\"\n className=\"text-xs opacity-60 hover:opacity-100\"\n onClick={() =>\n setValues(\n values.filter((_, xi) => xi !== i),\n )\n }\n aria-label={t.remove}\n >\n ✕\n </button>\n </span>\n ))}\n </>,\n )}\n </div>\n\n {/* 拖拽引用(ghost 预览):跟随光标显示当前拖拽的字段。\n 位置由 window `dragover` 通过 ref 直接更新,不触发重渲染。 */}\n {drag && (\n <div\n ref={ghostRef}\n className=\"badge badge-primary gap-1 items-center shadow-lg pointer-events-none\"\n style={{\n position: 'fixed',\n left: 0,\n top: 0,\n zIndex: 2000,\n willChange: 'transform',\n }}\n >\n {drag.numeric && <span className=\"opacity-80\">#</span>}\n {drag.label}\n </div>\n )}\n </>\n );\n}\n\nexport default PivotPanel;\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import t from "../../Table/index.js";
|
|
2
2
|
import { computePivot as P } from "./pivotEngine.js";
|
|
3
3
|
import { useMemo as W, useState as D } from "react";
|
|
4
4
|
import { jsx as a, jsxs as s } from "react/jsx-runtime";
|
|
@@ -31,12 +31,15 @@ function Q({ data: m, rowFields: g, colFields: b, values: p, fieldLabels: R = {}
|
|
|
31
31
|
const [M, T] = D({}), y = (e) => R[e] ?? e, B = (e) => H[e][x], f = W(() => (p.length ? p : [{
|
|
32
32
|
field: "",
|
|
33
33
|
aggFn: "count"
|
|
34
|
-
}]).map((e) =>
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
}]).map((e) => {
|
|
35
|
+
const n = {
|
|
36
|
+
rowFields: g,
|
|
37
|
+
colFields: b,
|
|
38
|
+
valueField: e.field,
|
|
39
|
+
aggFn: e.aggFn
|
|
40
|
+
};
|
|
41
|
+
return P(m, n);
|
|
42
|
+
}), [
|
|
40
43
|
m,
|
|
41
44
|
g,
|
|
42
45
|
b,
|
|
@@ -49,22 +52,22 @@ function Q({ data: m, rowFields: g, colFields: b, values: p, fieldLabels: R = {}
|
|
|
49
52
|
const C = p.length ? p : [{
|
|
50
53
|
field: "",
|
|
51
54
|
aggFn: "count"
|
|
52
|
-
}], { rowKeys: V, colKeys: N, rowFields: S } = h, k = N.length, w = h.rowCounts,
|
|
53
|
-
...
|
|
54
|
-
[e]: !
|
|
55
|
+
}], { rowKeys: V, colKeys: N, rowFields: S } = h, k = N.length, w = h.rowCounts, r = h.colFields.length > 0, L = v && S.length > 1 && h.rowTree.length > 0, $ = S.map(y).join(" / ") || "Group", j = r ? N : [[]], _ = (e) => T((n) => ({
|
|
56
|
+
...n,
|
|
57
|
+
[e]: !n[e]
|
|
55
58
|
})), z = [];
|
|
56
59
|
if (L) {
|
|
57
|
-
const e = (
|
|
58
|
-
const l = /* @__PURE__ */ new Map(),
|
|
60
|
+
const e = (c) => {
|
|
61
|
+
const l = /* @__PURE__ */ new Map(), i = (u) => {
|
|
59
62
|
for (const d of u)
|
|
60
|
-
l.set(d.key.join(F), d), d.children.length &&
|
|
63
|
+
l.set(d.key.join(F), d), d.children.length && i(d.children);
|
|
61
64
|
};
|
|
62
|
-
return c
|
|
63
|
-
},
|
|
64
|
-
for (const l of
|
|
65
|
-
const
|
|
65
|
+
return i(c), l;
|
|
66
|
+
}, n = f.map((c) => e(c.rowTree)), o = (c) => {
|
|
67
|
+
for (const l of c) {
|
|
68
|
+
const i = l.key.join(F), u = l.children.length > 0, d = M[i] ?? l.depth === 0, E = n.map((G) => G.get(i)?.cells ?? []);
|
|
66
69
|
z.push({
|
|
67
|
-
keyStr:
|
|
70
|
+
keyStr: i,
|
|
68
71
|
label: l.label,
|
|
69
72
|
depth: l.depth,
|
|
70
73
|
count: l.count,
|
|
@@ -78,22 +81,22 @@ function Q({ data: m, rowFields: g, colFields: b, values: p, fieldLabels: R = {}
|
|
|
78
81
|
}
|
|
79
82
|
return /* @__PURE__ */ a("div", {
|
|
80
83
|
className: "overflow-auto border border-base-300 rounded-box",
|
|
81
|
-
children: /* @__PURE__ */ s(
|
|
84
|
+
children: /* @__PURE__ */ s(t, {
|
|
82
85
|
className: "table-sm w-full border-collapse",
|
|
83
|
-
children: [/* @__PURE__ */ s(
|
|
86
|
+
children: [/* @__PURE__ */ s(t.Head, { children: [r && /* @__PURE__ */ s(t.Row, { children: [/* @__PURE__ */ a(t.Cell, {
|
|
84
87
|
className: "bg-base-200 font-semibold text-left align-bottom",
|
|
85
88
|
children: $
|
|
86
|
-
}), j.map((e,
|
|
89
|
+
}), j.map((e, n) => /* @__PURE__ */ a(t.Cell, {
|
|
87
90
|
colSpan: C.length,
|
|
88
91
|
className: "bg-base-200 font-semibold text-center",
|
|
89
92
|
children: e.join(" / ")
|
|
90
|
-
},
|
|
93
|
+
}, n))] }), /* @__PURE__ */ s(t.Row, { children: [/* @__PURE__ */ a(t.Cell, {
|
|
91
94
|
className: "bg-base-200 font-semibold text-left",
|
|
92
|
-
children:
|
|
93
|
-
}), j.map((e,
|
|
95
|
+
children: r ? "" : $
|
|
96
|
+
}), j.map((e, n) => C.map((o) => /* @__PURE__ */ s(t.Cell, {
|
|
94
97
|
className: "bg-base-200 font-semibold text-right",
|
|
95
98
|
children: [B(o.aggFn), o.field ? `(${y(o.field)})` : ""]
|
|
96
|
-
}, `${
|
|
99
|
+
}, `${n}:${o.field}:${o.aggFn}`)))] })] }), /* @__PURE__ */ a(t.Body, { children: L ? z.map((e) => /* @__PURE__ */ s(t.Row, { children: [/* @__PURE__ */ a(t.Cell, {
|
|
97
100
|
style: { paddingLeft: e.depth * 16 + 8 },
|
|
98
101
|
children: /* @__PURE__ */ s("span", {
|
|
99
102
|
className: "inline-flex items-center gap-1",
|
|
@@ -120,21 +123,21 @@ function Q({ data: m, rowFields: g, colFields: b, values: p, fieldLabels: R = {}
|
|
|
120
123
|
})
|
|
121
124
|
]
|
|
122
125
|
})
|
|
123
|
-
}), Array.from({ length:
|
|
126
|
+
}), Array.from({ length: r ? k : 1 }).map((n, o) => e.cellsByValue.map((c, l) => /* @__PURE__ */ a(t.Cell, {
|
|
124
127
|
className: "text-right tabular-nums",
|
|
125
|
-
children: A(r
|
|
126
|
-
}, `${o}:${l}`)))] }, e.keyStr)) : V.map((e,
|
|
128
|
+
children: A(c[r ? o : 0] ?? null)
|
|
129
|
+
}, `${o}:${l}`)))] }, e.keyStr)) : V.map((e, n) => /* @__PURE__ */ s(t.Row, { children: [/* @__PURE__ */ s(t.Cell, { children: [e.join(" / "), w[n] != null && /* @__PURE__ */ s("span", {
|
|
127
130
|
className: "opacity-50",
|
|
128
131
|
children: [
|
|
129
132
|
" ",
|
|
130
133
|
"(",
|
|
131
|
-
w[
|
|
134
|
+
w[n].toLocaleString(),
|
|
132
135
|
")"
|
|
133
136
|
]
|
|
134
|
-
})] }), Array.from({ length:
|
|
137
|
+
})] }), Array.from({ length: r ? k : 1 }).map((o, c) => f.map((l, i) => /* @__PURE__ */ a(t.Cell, {
|
|
135
138
|
className: "text-right tabular-nums",
|
|
136
|
-
children: A(l.matrix[
|
|
137
|
-
}, `${
|
|
139
|
+
children: A(l.matrix[n]?.[r ? c : 0] ?? null)
|
|
140
|
+
}, `${c}:${i}`)))] }, n)) })]
|
|
138
141
|
})
|
|
139
142
|
});
|
|
140
143
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PivotView.js","names":[],"sources":["../../../../src/components/pro/DataTable/PivotView.tsx"],"sourcesContent":["import React, { useMemo, useState } from 'react';\nimport Table from '../../Table';\nimport {\n computePivot,\n type PivotAggFn,\n type PivotConfig,\n type PivotResult,\n type PivotRowNode,\n} from './pivotEngine';\n\nconst SEP = '\\u0001';\n\n/** 一个数值度量:字段 + 聚合函数。 */\nexport interface PivotValue {\n field: string;\n aggFn: PivotAggFn;\n}\n\n/** 字段的展示标签映射。 */\nexport type PivotFieldLabels = Record<string, string>;\n\nconst AGG_LABELS: Record<PivotAggFn, { zh: string; en: string }> = {\n sum: { zh: '求和', en: 'Sum' },\n avg: { zh: '平均', en: 'Avg' },\n count: { zh: '计数', en: 'Count' },\n min: { zh: '最小', en: 'Min' },\n max: { zh: '最大', en: 'Max' },\n};\n\nfunction fmt(v: number | null): string {\n if (v == null) return '';\n return v.toLocaleString(undefined, { maximumFractionDigits: 2 });\n}\n\nexport interface PivotViewProps<T extends object> {\n /** 全量数据(会在其之上进行客户端聚合)。 */\n data: T[];\n /** 行分组字段。 */\n rowFields: string[];\n /** 列分组字段。 */\n colFields: string[];\n /** 数值度量列表。 */\n values: PivotValue[];\n /** 字段展示标签。 */\n fieldLabels?: PivotFieldLabels;\n /** 语言(影响聚合函数文案)。默认 'zh'。 */\n lang?: 'zh' | 'en';\n /** 是否以树形(可展开分组)方式展示多级行分组。默认 true。 */\n treeView?: boolean;\n}\n\n/**\n * ag-grid 风格的透视(Pivot)交叉表视图。支持多级行分组、列分组交叉表、\n * 多个数值度量,以及树形分组的展开/折叠。\n */\nexport function PivotView<T extends object>({\n data,\n rowFields,\n colFields,\n values,\n fieldLabels = {},\n lang = 'zh',\n treeView = true,\n}: PivotViewProps<T>) {\n const [expanded, setExpanded] = useState<Record<string, boolean>>({});\n\n const fieldLabel = (f: string) => fieldLabels[f] ?? f;\n const aggLabel = (fn: PivotAggFn) => AGG_LABELS[fn][lang];\n\n // 为每个数值度量分别计算一份透视结果。\n const results: PivotResult[] = useMemo(() => {\n const activeValues = values.length\n ? values\n : [{ field: '', aggFn: 'count' as PivotAggFn }];\n return activeValues.map((v) => {\n const config: PivotConfig = {\n rowFields,\n colFields,\n valueField: v.field,\n aggFn: v.aggFn,\n };\n return computePivot(data, config);\n });\n }, [data, rowFields, colFields, values]);\n\n const primary = results[0];\n if (!primary || rowFields.length === 0) {\n return (\n <div className=\"p-8 text-center opacity-60\">\n {lang === 'zh'\n ? '请至少配置一个行分组字段以启用透视视图。'\n : 'Add at least one row group field to enable the pivot view.'}\n </div>\n );\n }\n\n const activeValues = values.length ? values : [{ field: '', aggFn: 'count' as PivotAggFn }];\n const { rowKeys, colKeys, rowFields: rf } = primary;\n const colCount = colKeys.length;\n const rowCounts = primary.rowCounts;\n const hasCols = primary.colFields.length > 0;\n const treeMode = treeView && rf.length > 1 && primary.rowTree.length > 0;\n\n const groupLabel = rf.map(fieldLabel).join(' / ') || 'Group';\n const columns = hasCols ? colKeys : [[]];\n\n const toggle = (nodeKey: string) =>\n setExpanded((prev) => ({ ...prev, [nodeKey]: !prev[nodeKey] }));\n\n // 树形模式:将树扁平化为可见行(尊重展开状态)。\n interface VisibleRow {\n keyStr: string;\n label: string;\n depth: number;\n count: number;\n hasChildren: boolean;\n open: boolean;\n cellsByValue: (number | null)[][];\n }\n\n const visibleRows: VisibleRow[] = [];\n if (treeMode) {\n const indexTree = (nodes: PivotRowNode[]): Map<string, PivotRowNode> => {\n const map = new Map<string, PivotRowNode>();\n const walk = (ns: PivotRowNode[]) => {\n for (const n of ns) {\n map.set(n.key.join(SEP), n);\n if (n.children.length) walk(n.children);\n }\n };\n walk(nodes);\n return map;\n };\n const valueIndexes = results.map((r) => indexTree(r.rowTree));\n\n const walk = (nodes: PivotRowNode[]) => {\n for (const node of nodes) {\n const keyStr = node.key.join(SEP);\n const hasChildren = node.children.length > 0;\n const open = expanded[keyStr] ?? node.depth === 0;\n const cellsByValue = valueIndexes.map(\n (idx) => idx.get(keyStr)?.cells ?? [],\n );\n visibleRows.push({\n keyStr,\n label: node.label,\n depth: node.depth,\n count: node.count,\n hasChildren,\n open,\n cellsByValue,\n });\n if (hasChildren && open) walk(node.children);\n }\n };\n walk(primary.rowTree);\n }\n\n return (\n <div className=\"overflow-auto border border-base-300 rounded-box\">\n <Table className=\"table-sm w-full border-collapse\">\n <Table.Head>\n {/* 列分组标签行(交叉表) */}\n {hasCols && (\n <Table.Row>\n <Table.Cell className=\"bg-base-200 font-semibold text-left align-bottom\">\n {groupLabel}\n </Table.Cell>\n {columns.map((ck, ci) => (\n <Table.Cell\n key={ci}\n colSpan={activeValues.length}\n className=\"bg-base-200 font-semibold text-center\"\n >\n {ck.join(' / ')}\n </Table.Cell>\n ))}\n </Table.Row>\n )}\n {/* 度量表头行 */}\n <Table.Row>\n <Table.Cell className=\"bg-base-200 font-semibold text-left\">\n {hasCols ? '' : groupLabel}\n </Table.Cell>\n {columns.map((_, ci) =>\n activeValues.map((v) => (\n <Table.Cell\n key={`${ci}:${v.field}:${v.aggFn}`}\n className=\"bg-base-200 font-semibold text-right\"\n >\n {aggLabel(v.aggFn)}\n {v.field ? `(${fieldLabel(v.field)})` : ''}\n </Table.Cell>\n )),\n )}\n </Table.Row>\n </Table.Head>\n <Table.Body>\n {treeMode\n ? visibleRows.map((row) => (\n <Table.Row key={row.keyStr}>\n <Table.Cell\n style={{ paddingLeft: row.depth * 16 + 8 }}\n >\n <span\n className=\"inline-flex items-center gap-1\"\n style={{\n cursor: row.hasChildren\n ? 'pointer'\n : 'default',\n }}\n onClick={() =>\n row.hasChildren && toggle(row.keyStr)\n }\n >\n <span\n aria-hidden\n className=\"inline-block w-3 text-xs opacity-60\"\n >\n {row.hasChildren\n ? row.open\n ? '▾'\n : '▸'\n : ''}\n </span>\n <span\n style={{\n fontWeight:\n row.depth === 0 ? 600 : 400,\n }}\n >\n {row.label}\n </span>\n <span className=\"opacity-50\">\n {' '}\n ({row.count.toLocaleString()})\n </span>\n </span>\n </Table.Cell>\n {Array.from({\n length: hasCols ? colCount : 1,\n }).map((_, ci) =>\n row.cellsByValue.map((cells, vi) => (\n <Table.Cell\n key={`${ci}:${vi}`}\n className=\"text-right tabular-nums\"\n >\n {fmt(cells[hasCols ? ci : 0] ?? null)}\n </Table.Cell>\n )),\n )}\n </Table.Row>\n ))\n : rowKeys.map((rk, ri) => (\n <Table.Row key={ri}>\n <Table.Cell>\n {rk.join(' / ')}\n {rowCounts[ri] != null && (\n <span className=\"opacity-50\">\n {' '}\n ({rowCounts[ri].toLocaleString()})\n </span>\n )}\n </Table.Cell>\n {Array.from({\n length: hasCols ? colCount : 1,\n }).map((_, ci) =>\n results.map((res, vi) => (\n <Table.Cell\n key={`${ci}:${vi}`}\n className=\"text-right tabular-nums\"\n >\n {fmt(\n res.matrix[ri]?.[\n hasCols ? ci : 0\n ] ?? null,\n )}\n </Table.Cell>\n )),\n )}\n </Table.Row>\n ))}\n </Table.Body>\n </Table>\n </div>\n );\n}\n\nexport default PivotView;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PivotView.js","names":[],"sources":["../../../../src/components/pro/DataTable/PivotView.tsx"],"sourcesContent":["import React, { useMemo, useState } from 'react';\nimport Table from '../../Table';\nimport {\n computePivot,\n type PivotAggFn,\n type PivotConfig,\n type PivotResult,\n type PivotRowNode,\n} from './pivotEngine';\n\nconst SEP = '\\u0001';\n\n/** 一个数值度量:字段 + 聚合函数。 */\nexport interface PivotValue {\n field: string;\n aggFn: PivotAggFn;\n}\n\n/** 字段的展示标签映射。 */\nexport type PivotFieldLabels = Record<string, string>;\n\nconst AGG_LABELS: Record<PivotAggFn, { zh: string; en: string }> = {\n sum: { zh: '求和', en: 'Sum' },\n avg: { zh: '平均', en: 'Avg' },\n count: { zh: '计数', en: 'Count' },\n min: { zh: '最小', en: 'Min' },\n max: { zh: '最大', en: 'Max' },\n};\n\nfunction fmt(v: number | null): string {\n if (v == null) return '';\n return v.toLocaleString(undefined, { maximumFractionDigits: 2 });\n}\n\nexport interface PivotViewProps<T extends object> {\n /** 全量数据(会在其之上进行客户端聚合)。 */\n data: T[];\n /** 行分组字段。 */\n rowFields: string[];\n /** 列分组字段。 */\n colFields: string[];\n /** 数值度量列表。 */\n values: PivotValue[];\n /** 字段展示标签。 */\n fieldLabels?: PivotFieldLabels;\n /** 语言(影响聚合函数文案)。默认 'zh'。 */\n lang?: 'zh' | 'en';\n /** 是否以树形(可展开分组)方式展示多级行分组。默认 true。 */\n treeView?: boolean;\n}\n\n/**\n * ag-grid 风格的透视(Pivot)交叉表视图。支持多级行分组、列分组交叉表、\n * 多个数值度量,以及树形分组的展开/折叠。\n */\nexport function PivotView<T extends object>({\n data,\n rowFields,\n colFields,\n values,\n fieldLabels = {},\n lang = 'zh',\n treeView = true,\n}: PivotViewProps<T>) {\n const [expanded, setExpanded] = useState<Record<string, boolean>>({});\n\n const fieldLabel = (f: string) => fieldLabels[f] ?? f;\n const aggLabel = (fn: PivotAggFn) => AGG_LABELS[fn][lang];\n\n // 为每个数值度量分别计算一份透视结果。\n const results: PivotResult[] = useMemo(() => {\n const activeValues = values.length\n ? values\n : [{ field: '', aggFn: 'count' as PivotAggFn }];\n return activeValues.map((v) => {\n const config: PivotConfig = {\n rowFields,\n colFields,\n valueField: v.field,\n aggFn: v.aggFn,\n };\n return computePivot(data, config);\n });\n }, [data, rowFields, colFields, values]);\n\n const primary = results[0];\n if (!primary || rowFields.length === 0) {\n return (\n <div className=\"p-8 text-center opacity-60\">\n {lang === 'zh'\n ? '请至少配置一个行分组字段以启用透视视图。'\n : 'Add at least one row group field to enable the pivot view.'}\n </div>\n );\n }\n\n const activeValues = values.length ? values : [{ field: '', aggFn: 'count' as PivotAggFn }];\n const { rowKeys, colKeys, rowFields: rf } = primary;\n const colCount = colKeys.length;\n const rowCounts = primary.rowCounts;\n const hasCols = primary.colFields.length > 0;\n const treeMode = treeView && rf.length > 1 && primary.rowTree.length > 0;\n\n const groupLabel = rf.map(fieldLabel).join(' / ') || 'Group';\n const columns = hasCols ? colKeys : [[]];\n\n const toggle = (nodeKey: string) =>\n setExpanded((prev) => ({ ...prev, [nodeKey]: !prev[nodeKey] }));\n\n // 树形模式:将树扁平化为可见行(尊重展开状态)。\n interface VisibleRow {\n keyStr: string;\n label: string;\n depth: number;\n count: number;\n hasChildren: boolean;\n open: boolean;\n cellsByValue: (number | null)[][];\n }\n\n const visibleRows: VisibleRow[] = [];\n if (treeMode) {\n const indexTree = (nodes: PivotRowNode[]): Map<string, PivotRowNode> => {\n const map = new Map<string, PivotRowNode>();\n const walk = (ns: PivotRowNode[]) => {\n for (const n of ns) {\n map.set(n.key.join(SEP), n);\n if (n.children.length) walk(n.children);\n }\n };\n walk(nodes);\n return map;\n };\n const valueIndexes = results.map((r) => indexTree(r.rowTree));\n\n const walk = (nodes: PivotRowNode[]) => {\n for (const node of nodes) {\n const keyStr = node.key.join(SEP);\n const hasChildren = node.children.length > 0;\n const open = expanded[keyStr] ?? node.depth === 0;\n const cellsByValue = valueIndexes.map(\n (idx) => idx.get(keyStr)?.cells ?? [],\n );\n visibleRows.push({\n keyStr,\n label: node.label,\n depth: node.depth,\n count: node.count,\n hasChildren,\n open,\n cellsByValue,\n });\n if (hasChildren && open) walk(node.children);\n }\n };\n walk(primary.rowTree);\n }\n\n return (\n <div className=\"overflow-auto border border-base-300 rounded-box\">\n <Table className=\"table-sm w-full border-collapse\">\n <Table.Head>\n {/* 列分组标签行(交叉表) */}\n {hasCols && (\n <Table.Row>\n <Table.Cell className=\"bg-base-200 font-semibold text-left align-bottom\">\n {groupLabel}\n </Table.Cell>\n {columns.map((ck, ci) => (\n <Table.Cell\n key={ci}\n colSpan={activeValues.length}\n className=\"bg-base-200 font-semibold text-center\"\n >\n {ck.join(' / ')}\n </Table.Cell>\n ))}\n </Table.Row>\n )}\n {/* 度量表头行 */}\n <Table.Row>\n <Table.Cell className=\"bg-base-200 font-semibold text-left\">\n {hasCols ? '' : groupLabel}\n </Table.Cell>\n {columns.map((_, ci) =>\n activeValues.map((v) => (\n <Table.Cell\n key={`${ci}:${v.field}:${v.aggFn}`}\n className=\"bg-base-200 font-semibold text-right\"\n >\n {aggLabel(v.aggFn)}\n {v.field ? `(${fieldLabel(v.field)})` : ''}\n </Table.Cell>\n )),\n )}\n </Table.Row>\n </Table.Head>\n <Table.Body>\n {treeMode\n ? visibleRows.map((row) => (\n <Table.Row key={row.keyStr}>\n <Table.Cell\n style={{ paddingLeft: row.depth * 16 + 8 }}\n >\n <span\n className=\"inline-flex items-center gap-1\"\n style={{\n cursor: row.hasChildren\n ? 'pointer'\n : 'default',\n }}\n onClick={() =>\n row.hasChildren && toggle(row.keyStr)\n }\n >\n <span\n aria-hidden\n className=\"inline-block w-3 text-xs opacity-60\"\n >\n {row.hasChildren\n ? row.open\n ? '▾'\n : '▸'\n : ''}\n </span>\n <span\n style={{\n fontWeight:\n row.depth === 0 ? 600 : 400,\n }}\n >\n {row.label}\n </span>\n <span className=\"opacity-50\">\n {' '}\n ({row.count.toLocaleString()})\n </span>\n </span>\n </Table.Cell>\n {Array.from({\n length: hasCols ? colCount : 1,\n }).map((_, ci) =>\n row.cellsByValue.map((cells, vi) => (\n <Table.Cell\n key={`${ci}:${vi}`}\n className=\"text-right tabular-nums\"\n >\n {fmt(cells[hasCols ? ci : 0] ?? null)}\n </Table.Cell>\n )),\n )}\n </Table.Row>\n ))\n : rowKeys.map((rk, ri) => (\n <Table.Row key={ri}>\n <Table.Cell>\n {rk.join(' / ')}\n {rowCounts[ri] != null && (\n <span className=\"opacity-50\">\n {' '}\n ({rowCounts[ri].toLocaleString()})\n </span>\n )}\n </Table.Cell>\n {Array.from({\n length: hasCols ? colCount : 1,\n }).map((_, ci) =>\n results.map((res, vi) => (\n <Table.Cell\n key={`${ci}:${vi}`}\n className=\"text-right tabular-nums\"\n >\n {fmt(\n res.matrix[ri]?.[\n hasCols ? ci : 0\n ] ?? null,\n )}\n </Table.Cell>\n )),\n )}\n </Table.Row>\n ))}\n </Table.Body>\n </Table>\n </div>\n );\n}\n\nexport default PivotView;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BulkActions.js","names":[],"sources":["../../../../../src/components/pro/DataTable/components/BulkActions.tsx"],"sourcesContent":["import React from 'react';\nimport { RowSelectionState } from '../tanstack-table';\nimport { BulkAction } from '../types';\nimport { useAppContext } from '../../../../contexts/AppContext';\n\ninterface BulkActionsProps<T extends object> {\n bulkActions: BulkAction[];\n rowSelection: RowSelectionState;\n data: T[];\n}\n\nexport function BulkActions<T extends object>({\n bulkActions,\n rowSelection,\n data,\n}: BulkActionsProps<T>) {\n const { language } = useAppContext();\n\n const getLocalizedText = (zhText: string, enText: string) => {\n return language === 'zh' ? zhText : enText;\n };\n\n if (!bulkActions || bulkActions.length === 0) return null;\n\n return (\n <div className=\"flex gap-2\">\n <div className=\"dropdown dropdown-end\">\n <div tabIndex={0} role=\"button\" className=\"btn btn-sm btn-primary\">\n {getLocalizedText('批量操作', 'Bulk Actions')}\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n className=\"h-4 w-4 ml-1\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </div>\n <ul tabIndex={0} className=\"dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-52\">\n {bulkActions.map((action, index) => (\n <li key={index}>\n <a\n onClick={() => {\n const selectedRowIds = Object.keys(rowSelection);\n const selectedRowData = selectedRowIds.map(id => {\n const rowData = data.find((row, idx) => {\n const rowId = (row as any).id !== undefined ? (row as any).id.toString() : idx.toString();\n return rowId === id;\n });\n return rowData;\n }).filter(Boolean);\n\n action.onClick(rowSelection, selectedRowData);\n }}\n className={action.className}\n >\n {action.label}\n </a>\n </li>\n ))}\n </ul>\n </div>\n </div>\n );\n}\n"],"mappings":";;;AAWA,SAAgB,EAA8B,EAC1C,aAAA,GACA,cAAA,GACA,MAAA,EAAA,GACoB;AACpB,QAAM,EAAE,UAAA,EAAA,IAAa,EAAc,GAE7B,IAAA,CAAoB,GAAgB,MAC/B,MAAa,OAAO,IAAS;AAGxC,SAAI,CAAC,KAAe,EAAY,WAAW,IAAU,OAGjD,gBAAA,EAAC,OAAD;AAAA,IAAK,WAAU;AAAA,
|
|
1
|
+
{"version":3,"file":"BulkActions.js","names":[],"sources":["../../../../../src/components/pro/DataTable/components/BulkActions.tsx"],"sourcesContent":["import React from 'react';\nimport { RowSelectionState } from '../tanstack-table';\nimport { BulkAction } from '../types';\nimport { useAppContext } from '../../../../contexts/AppContext';\n\ninterface BulkActionsProps<T extends object> {\n bulkActions: BulkAction[];\n rowSelection: RowSelectionState;\n data: T[];\n}\n\nexport function BulkActions<T extends object>({\n bulkActions,\n rowSelection,\n data,\n}: BulkActionsProps<T>) {\n const { language } = useAppContext();\n\n const getLocalizedText = (zhText: string, enText: string) => {\n return language === 'zh' ? zhText : enText;\n };\n\n if (!bulkActions || bulkActions.length === 0) return null;\n\n return (\n <div className=\"flex gap-2\">\n <div className=\"dropdown dropdown-end\">\n <div tabIndex={0} role=\"button\" className=\"btn btn-sm btn-primary\">\n {getLocalizedText('批量操作', 'Bulk Actions')}\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n className=\"h-4 w-4 ml-1\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </div>\n <ul tabIndex={0} className=\"dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-52\">\n {bulkActions.map((action, index) => (\n <li key={index}>\n <a\n onClick={() => {\n const selectedRowIds = Object.keys(rowSelection);\n const selectedRowData = selectedRowIds.map(id => {\n const rowData = data.find((row, idx) => {\n const rowId = (row as any).id !== undefined ? (row as any).id.toString() : idx.toString();\n return rowId === id;\n });\n return rowData;\n }).filter(Boolean);\n\n action.onClick(rowSelection, selectedRowData);\n }}\n className={action.className}\n >\n {action.label}\n </a>\n </li>\n ))}\n </ul>\n </div>\n </div>\n );\n}\n"],"mappings":";;;AAWA,SAAgB,EAA8B,EAC1C,aAAA,GACA,cAAA,GACA,MAAA,EAAA,GACoB;AACpB,QAAM,EAAE,UAAA,EAAA,IAAa,EAAc,GAE7B,IAAA,CAAoB,GAAgB,MAC/B,MAAa,OAAO,IAAS;AAGxC,SAAI,CAAC,KAAe,EAAY,WAAW,IAAU,OAGjD,gBAAA,EAAC,OAAD;AAAA,IAAK,WAAU;AAAA,IACX,UAAA,gBAAA,EAAC,OAAD;AAAA,MAAK,WAAU;AAAA,MAAf,UAAA,CACI,gBAAA,EAAC,OAAD;AAAA,QAAK,UAAU;AAAA,QAAG,MAAK;AAAA,QAAS,WAAU;AAAA,QAA1C,UAAA,CACK,EAAiB,QAAQ,cAAc,GACxC,gBAAA,EAAC,OAAD;AAAA,UACI,OAAM;AAAA,UACN,WAAU;AAAA,UACV,MAAK;AAAA,UACL,SAAQ;AAAA,UACR,QAAO;AAAA,UAEP,UAAA,gBAAA,EAAC,QAAD;AAAA,YAAM,eAAc;AAAA,YAAQ,gBAAe;AAAA,YAAQ,aAAY;AAAA,YAAI,GAAE;AAAA,UAAkB,CAAA;AAAA,QACtF,CAAA,CACJ;AAAA,MACL,CAAA,GAAA,gBAAA,EAAC,MAAD;AAAA,QAAI,UAAU;AAAA,QAAG,WAAU;AAAA,QACtB,UAAA,EAAY,IAAA,CAAK,GAAQ,MACtB,gBAAA,EAAC,MAAD,EAAA,UACI,gBAAA,EAAC,KAAD;AAAA,UACI,SAAA,MAAe;AAEX,kBAAM,IADiB,OAAO,KAAK,CACX,EAAe,IAAA,CAAI,MACvB,EAAK,KAAA,CAAM,GAAK,OACb,EAAY,OAAO,SAAa,EAAY,GAAG,SAAS,IAAI,EAAI,SAAS,OACvE,CAEd,CACV,EAAE,OAAO,OAAO;AAEjB,YAAA,EAAO,QAAQ,GAAc,CAAe;AAAA,UAChD;AAAA,UACA,WAAW,EAAO;AAAA,UAEjB,UAAA,EAAO;AAAA,QACT,CAAA,EACH,GAlBK,CAkBL,CACP;AAAA,MACD,CAAA,CACH;AAAA;EACJ,CAAA;AAEb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ColumnSelector.js","names":[],"sources":["../../../../../src/components/pro/DataTable/components/ColumnSelector.tsx"],"sourcesContent":["import React from 'react';\nimport { Table, VisibilityState } from '../tanstack-table';\nimport { useAppContext } from '../../../../contexts/AppContext';\n\ninterface ColumnSelectorProps<T extends object> {\n table: Table<T>;\n columns: any[];\n columnOrderState: string[];\n visibilityState: VisibilityState;\n toggleColumnVisibility: (columnId: string) => void;\n enableColumnReordering: boolean;\n handleDragStart: (e: React.DragEvent, columnId: string) => void;\n handleDrop: (e: React.DragEvent, targetColumnId: string) => void;\n draggedColumnId: string | null;\n}\n\nexport function ColumnSelector<T extends object>({\n columns,\n columnOrderState,\n visibilityState,\n toggleColumnVisibility,\n enableColumnReordering,\n handleDragStart,\n handleDrop,\n draggedColumnId,\n}: ColumnSelectorProps<T>) {\n const { language } = useAppContext();\n\n const getLocalizedText = (zhText: string, enText: string) => {\n return language === 'zh' ? zhText : enText;\n };\n\n return (\n <div className=\"dropdown\">\n <div tabIndex={0} role=\"button\" className=\"btn btn-sm\">\n {getLocalizedText('列控制', 'Column Control')}\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n className=\"h-4 w-4 ml-1\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </div>\n <ul tabIndex={0} className=\"dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-52\">\n {(() => {\n const validColumnIds = columns\n .map(col => 'accessorKey' in col ? col.accessorKey as string : col.id as string)\n .filter(id => id !== 'selection');\n\n const fullOrderedColumnIds = [\n ...columnOrderState.filter(id => validColumnIds.includes(id)),\n ...validColumnIds.filter(id => !columnOrderState.includes(id))\n ];\n\n return fullOrderedColumnIds.map(columnId => {\n const column = columns.find(col =>\n ('accessorKey' in col && col.accessorKey === columnId) ||\n ('id' in col && col.id === columnId)\n );\n\n if (!column) return null;\n\n const headerText = typeof column.header === 'string'\n ? column.header\n : columnId;\n\n const isDragging = draggedColumnId === columnId;\n\n return (\n <li key={columnId}>\n <a\n className={`flex items-center justify-between py-2 px-2 ${isDragging ? 'bg-primary/30 shadow-md border-l-4 border-primary' : ''\n }`}\n onClick={() => toggleColumnVisibility(columnId)}\n draggable={enableColumnReordering}\n onDragStart={(e) => {\n handleDragStart(e, columnId);\n }}\n onDragOver={(e) => {\n e.preventDefault();\n document.querySelectorAll('.menu-item-highlight').forEach(el => {\n if (el !== e.currentTarget) {\n el.classList.remove('menu-item-highlight');\n el.classList.remove('bg-primary/10');\n el.classList.remove('border-l-4');\n el.classList.remove('border-primary');\n }\n });\n\n e.currentTarget.classList.add('menu-item-highlight');\n e.currentTarget.classList.add('bg-primary/10');\n e.currentTarget.classList.add('border-l-4');\n e.currentTarget.classList.add('border-primary');\n }}\n onDragLeave={(e) => {\n e.currentTarget.classList.remove('menu-item-highlight');\n e.currentTarget.classList.remove('bg-primary/10');\n e.currentTarget.classList.remove('border-l-4');\n e.currentTarget.classList.remove('border-primary');\n }}\n onDrop={(e) => {\n e.currentTarget.classList.remove('menu-item-highlight');\n e.currentTarget.classList.remove('bg-primary/10');\n e.currentTarget.classList.remove('border-l-4');\n e.currentTarget.classList.remove('border-primary');\n\n handleDrop(e, columnId);\n\n document.querySelectorAll('.dragging-source, .menu-item-highlight').forEach(el => {\n el.classList.remove('dragging-source');\n el.classList.remove('menu-item-highlight');\n });\n }}\n >\n <div className=\"flex items-center gap-2\">\n <input\n type=\"checkbox\"\n className=\"checkbox checkbox-sm\"\n checked={visibilityState[columnId] !== false}\n onChange={(e) => {\n e.stopPropagation();\n toggleColumnVisibility(columnId);\n }}\n onClick={(e) => e.stopPropagation()}\n />\n <span>{headerText}</span>\n </div>\n\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n className={`h-4 w-4 cursor-grab active:cursor-grabbing`}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4\" />\n </svg>\n </a>\n </li>\n );\n });\n })()}\n </ul>\n </div>\n );\n}\n"],"mappings":";;;AAgBA,SAAgB,EAAiC,EAC7C,SAAA,GACA,kBAAA,GACA,iBAAA,GACA,wBAAA,GACA,wBAAA,GACA,iBAAA,GACA,YAAA,GACA,iBAAA,EAAA,GACuB;AACvB,QAAM,EAAE,UAAA,EAAA,IAAa,EAAc;AAMnC,SACI,gBAAA,EAAC,OAAD;AAAA,IAAK,WAAU;AAAA,cAAf,CACI,gBAAA,EAAC,OAAD;AAAA,MAAK,UAAU;AAAA,MAAG,MAAK;AAAA,MAAS,WAAU;AAAA,gBAA1C,EANF,CAAoB,GAAgB,MAC/B,MAAa,OAAO,IAAS,GAMV,OAAO,gBAAgB,GACzC,gBAAA,EAAC,OAAD;AAAA,QACI,OAAM;AAAA,QACN,WAAU;AAAA,QACV,MAAK;AAAA,QACL,SAAQ;AAAA,QACR,QAAO;AAAA,kBAEP,gBAAA,EAAC,QAAD;AAAA,UAAM,eAAc;AAAA,UAAQ,gBAAe;AAAA,UAAQ,aAAY;AAAA,UAAI,GAAE;AAAA,QAAkB,CAAA;AAAA,MACtF,CAAA,CACJ;AAAA,QACL,gBAAA,EAAC,MAAD;AAAA,MAAI,UAAU;AAAA,MAAG,WAAU;AAAA,uBACf;AACJ,cAAM,IAAiB,EAClB,IAAA,CAAI,MAAO,iBAAiB,IAAM,EAAI,cAAwB,EAAI,EAAY,EAC9E,OAAA,CAAO,MAAM,MAAO,WAAW;AAOpC,eAAO,CAJH,GAAG,EAAiB,OAAA,CAAO,MAAM,EAAe,SAAS,CAAE,CAAC,GAC5D,GAAG,EAAe,OAAA,CAAO,MAAM,CAAC,EAAiB,SAAS,CAAE,CAAC,CAG1D,EAAqB,IAAA,CAAI,MAAY;AACxC,gBAAM,IAAS,EAAQ,KAAA,CAAK,MACvB,iBAAiB,KAAO,EAAI,gBAAgB,KAC5C,QAAQ,KAAO,EAAI,OAAO,CAC/B;AAEA,cAAI,CAAC,EAAQ,QAAO;AAEpB,gBAAM,IAAa,OAAO,EAAO,UAAW,WACtC,EAAO,SACP;AAIN,iBACI,gBAAA,EAAC,MAAD,EAAA,UACI,gBAAA,EAAC,KAAD;AAAA,YACI,WAAW,+CALJ,MAAoB,IAK4C,sDAAsD,EAAA;AAAA,YAE7H,SAAA,MAAe,EAAuB,CAAQ;AAAA,YAC9C,WAAW;AAAA,YACX,aAAA,CAAc,MAAM;AAChB,cAAA,EAAgB,GAAG,CAAQ;AAAA,YAC/B;AAAA,YACA,YAAA,CAAa,MAAM;AACf,cAAA,EAAE,eAAe,GACjB,SAAS,iBAAiB,sBAAsB,EAAE,QAAA,CAAQ,MAAM;AAC5D,gBAAI,MAAO,EAAE,kBACT,EAAG,UAAU,OAAO,qBAAqB,GACzC,EAAG,UAAU,OAAO,eAAe,GACnC,EAAG,UAAU,OAAO,YAAY,GAChC,EAAG,UAAU,OAAO,gBAAgB;AAAA,cAE5C,CAAC,GAED,EAAE,cAAc,UAAU,IAAI,qBAAqB,GACnD,EAAE,cAAc,UAAU,IAAI,eAAe,GAC7C,EAAE,cAAc,UAAU,IAAI,YAAY,GAC1C,EAAE,cAAc,UAAU,IAAI,gBAAgB;AAAA,YAClD;AAAA,YACA,aAAA,CAAc,MAAM;AAChB,cAAA,EAAE,cAAc,UAAU,OAAO,qBAAqB,GACtD,EAAE,cAAc,UAAU,OAAO,eAAe,GAChD,EAAE,cAAc,UAAU,OAAO,YAAY,GAC7C,EAAE,cAAc,UAAU,OAAO,gBAAgB;AAAA,YACrD;AAAA,YACA,QAAA,CAAS,MAAM;AACX,cAAA,EAAE,cAAc,UAAU,OAAO,qBAAqB,GACtD,EAAE,cAAc,UAAU,OAAO,eAAe,GAChD,EAAE,cAAc,UAAU,OAAO,YAAY,GAC7C,EAAE,cAAc,UAAU,OAAO,gBAAgB,GAEjD,EAAW,GAAG,CAAQ,GAEtB,SAAS,iBAAiB,wCAAwC,EAAE,QAAA,CAAQ,MAAM;AAC9E,gBAAA,EAAG,UAAU,OAAO,iBAAiB,GACrC,EAAG,UAAU,OAAO,qBAAqB;AAAA,cAC7C,CAAC;AAAA,YACL;AAAA,sBA1CJ,CA4CI,gBAAA,EAAC,OAAD;AAAA,cAAK,WAAU;AAAA,wBAAf,CACI,gBAAA,EAAC,SAAD;AAAA,gBACI,MAAK;AAAA,gBACL,WAAU;AAAA,gBACV,SAAS,EAAgB,CAAA,MAAc;AAAA,gBACvC,UAAA,CAAW,MAAM;AACb,kBAAA,EAAE,gBAAgB,GAClB,EAAuB,CAAQ;AAAA,gBACnC;AAAA,gBACA,SAAA,CAAU,MAAM,EAAE,gBAAgB;AAAA,cACrC,CAAA,GACD,gBAAA,EAAC,QAAD,EAAA,UAAO,EAAiB,CAAA,CACvB;AAAA,gBAEL,gBAAA,EAAC,OAAD;AAAA,cACI,OAAM;AAAA,cACN,WAAW;AAAA,cACX,MAAK;AAAA,cACL,SAAQ;AAAA,cACR,QAAO;AAAA,wBAEP,gBAAA,EAAC,QAAD;AAAA,gBAAM,eAAc;AAAA,gBAAQ,gBAAe;AAAA,gBAAQ,aAAY;AAAA,gBAAI,GAAE;AAAA,cAAoD,CAAA;AAAA,YACxH,CAAA,CACN;AAAA,aACH,GArEK,CAqEL;AAAA,QAEZ,CAAC;AAAA,MACL,GAAG;AAAA,IACH,CAAA,CACH;AAAA;AAEb"}
|
|
1
|
+
{"version":3,"file":"ColumnSelector.js","names":[],"sources":["../../../../../src/components/pro/DataTable/components/ColumnSelector.tsx"],"sourcesContent":["import React from 'react';\nimport { Table, VisibilityState } from '../tanstack-table';\nimport { useAppContext } from '../../../../contexts/AppContext';\n\ninterface ColumnSelectorProps<T extends object> {\n table: Table<T>;\n columns: any[];\n columnOrderState: string[];\n visibilityState: VisibilityState;\n toggleColumnVisibility: (columnId: string) => void;\n enableColumnReordering: boolean;\n handleDragStart: (e: React.DragEvent, columnId: string) => void;\n handleDrop: (e: React.DragEvent, targetColumnId: string) => void;\n draggedColumnId: string | null;\n}\n\nexport function ColumnSelector<T extends object>({\n columns,\n columnOrderState,\n visibilityState,\n toggleColumnVisibility,\n enableColumnReordering,\n handleDragStart,\n handleDrop,\n draggedColumnId,\n}: ColumnSelectorProps<T>) {\n const { language } = useAppContext();\n\n const getLocalizedText = (zhText: string, enText: string) => {\n return language === 'zh' ? zhText : enText;\n };\n\n return (\n <div className=\"dropdown\">\n <div tabIndex={0} role=\"button\" className=\"btn btn-sm\">\n {getLocalizedText('列控制', 'Column Control')}\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n className=\"h-4 w-4 ml-1\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </div>\n <ul tabIndex={0} className=\"dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-52\">\n {(() => {\n const validColumnIds = columns\n .map(col => 'accessorKey' in col ? col.accessorKey as string : col.id as string)\n .filter(id => id !== 'selection');\n\n const fullOrderedColumnIds = [\n ...columnOrderState.filter(id => validColumnIds.includes(id)),\n ...validColumnIds.filter(id => !columnOrderState.includes(id))\n ];\n\n return fullOrderedColumnIds.map(columnId => {\n const column = columns.find(col =>\n ('accessorKey' in col && col.accessorKey === columnId) ||\n ('id' in col && col.id === columnId)\n );\n\n if (!column) return null;\n\n const headerText = typeof column.header === 'string'\n ? column.header\n : columnId;\n\n const isDragging = draggedColumnId === columnId;\n\n return (\n <li key={columnId}>\n <a\n className={`flex items-center justify-between py-2 px-2 ${isDragging ? 'bg-primary/30 shadow-md border-l-4 border-primary' : ''\n }`}\n onClick={() => toggleColumnVisibility(columnId)}\n draggable={enableColumnReordering}\n onDragStart={(e) => {\n handleDragStart(e, columnId);\n }}\n onDragOver={(e) => {\n e.preventDefault();\n document.querySelectorAll('.menu-item-highlight').forEach(el => {\n if (el !== e.currentTarget) {\n el.classList.remove('menu-item-highlight');\n el.classList.remove('bg-primary/10');\n el.classList.remove('border-l-4');\n el.classList.remove('border-primary');\n }\n });\n\n e.currentTarget.classList.add('menu-item-highlight');\n e.currentTarget.classList.add('bg-primary/10');\n e.currentTarget.classList.add('border-l-4');\n e.currentTarget.classList.add('border-primary');\n }}\n onDragLeave={(e) => {\n e.currentTarget.classList.remove('menu-item-highlight');\n e.currentTarget.classList.remove('bg-primary/10');\n e.currentTarget.classList.remove('border-l-4');\n e.currentTarget.classList.remove('border-primary');\n }}\n onDrop={(e) => {\n e.currentTarget.classList.remove('menu-item-highlight');\n e.currentTarget.classList.remove('bg-primary/10');\n e.currentTarget.classList.remove('border-l-4');\n e.currentTarget.classList.remove('border-primary');\n\n handleDrop(e, columnId);\n\n document.querySelectorAll('.dragging-source, .menu-item-highlight').forEach(el => {\n el.classList.remove('dragging-source');\n el.classList.remove('menu-item-highlight');\n });\n }}\n >\n <div className=\"flex items-center gap-2\">\n <input\n type=\"checkbox\"\n className=\"checkbox checkbox-sm\"\n checked={visibilityState[columnId] !== false}\n onChange={(e) => {\n e.stopPropagation();\n toggleColumnVisibility(columnId);\n }}\n onClick={(e) => e.stopPropagation()}\n />\n <span>{headerText}</span>\n </div>\n\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n className={`h-4 w-4 cursor-grab active:cursor-grabbing`}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4\" />\n </svg>\n </a>\n </li>\n );\n });\n })()}\n </ul>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FilterBar.js","names":[],"sources":["../../../../../src/components/pro/DataTable/components/FilterBar.tsx"],"sourcesContent":["import React from 'react';\nimport { Table } from '../tanstack-table';\nimport { FilterConfig, CustomFilterPanelProps } from '../types';\nimport { useAppContext } from '../../../../contexts/AppContext';\nimport { FilterPanel } from '../Filters';\n\ninterface FilterBarProps<T extends object> {\n table: Table<T>;\n columns: any[];\n activeFilter: string | null;\n setActiveFilter: (filter: string | null) => void;\n customFilterPanel?: React.ComponentType<CustomFilterPanelProps>;\n filterConfig?: FilterConfig;\n}\n\nexport function FilterBar<T extends object>({\n table,\n columns,\n activeFilter,\n setActiveFilter,\n customFilterPanel,\n filterConfig,\n}: FilterBarProps<T>) {\n const { language } = useAppContext();\n\n const getLocalizedText = (zhText: string, enText: string) => {\n return language === 'zh' ? zhText : enText;\n };\n\n const renderColumnFilter = (columnId: string) => {\n const column = columns.find(col =>\n ('accessorKey' in col && col.accessorKey === columnId) ||\n ('id' in col && col.id === columnId)\n );\n\n if (!column) return null;\n\n const isActive = activeFilter === columnId;\n const filterType = column.meta?.filterType;\n\n if (!filterType) return null;\n\n const tableColumn = table.getColumn(columnId);\n if (!tableColumn) return null;\n\n const columnHeader = typeof column.header === 'string' ? column.header : columnId;\n\n return (\n <div className=\"relative\">\n <button\n className={`btn btn-sm ${isActive ? 'btn-primary' : 'btn-ghost'}`}\n onClick={() => setActiveFilter(isActive ? null : columnId)}\n >\n {columnHeader}\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n className=\"h-4 w-4 ml-1\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z\" />\n </svg>\n </button>\n\n {isActive && (\n <div className=\"absolute mt-2 z-[100]\">\n {React.createElement(customFilterPanel || FilterPanel, {\n column: tableColumn as any,\n onClose: () => setActiveFilter(null)\n })}\n </div>\n )}\n </div>\n );\n };\n\n return (\n <div className=\"flex gap-2 flex-wrap items-center\">\n {columns.map(column => {\n const columnId = 'accessorKey' in column ? column.accessorKey as string : column.id as string;\n if (column.meta?.filterType) {\n return <React.Fragment key={columnId}>{renderColumnFilter(columnId)}</React.Fragment>;\n }\n return null;\n })}\n\n {filterConfig?.showClearAll && (\n <button\n className=\"btn btn-sm btn-ghost text-error\"\n onClick={() => table.resetColumnFilters()}\n >\n {getLocalizedText('清除所有', 'Clear All')}\n </button>\n )}\n\n {filterConfig?.customFilters}\n </div>\n );\n}\n"],"mappings":";;;;AAeA,SAAgB,EAA4B,EACxC,OAAA,GACA,SAAA,GACA,cAAA,GACA,iBAAA,GACA,mBAAA,GACA,cAAA,EAAA,GACkB;AAClB,QAAM,EAAE,UAAA,EAAA,IAAa,EAAc,GAE7B,IAAA,CAAoB,GAAgB,MAC/B,MAAa,OAAO,IAAS,GAGlC,IAAA,CAAsB,MAAqB;AAC7C,UAAM,IAAS,EAAQ,KAAA,CAAK,MACvB,iBAAiB,KAAO,EAAI,gBAAgB,KAC5C,QAAQ,KAAO,EAAI,OAAO,CAC/B;AAEA,QAAI,CAAC,EAAQ,QAAO;AAEpB,UAAM,IAAW,MAAiB;AAGlC,QAAI,CAFe,EAAO,MAAM,WAEf,QAAO;AAExB,UAAM,IAAc,EAAM,UAAU,CAAQ;AAC5C,QAAI,CAAC,EAAa,QAAO;AAEzB,UAAM,IAAe,OAAO,EAAO,UAAW,WAAW,EAAO,SAAS;AAEzE,WACI,gBAAA,EAAC,OAAD;AAAA,MAAK,WAAU;AAAA,
|
|
1
|
+
{"version":3,"file":"FilterBar.js","names":[],"sources":["../../../../../src/components/pro/DataTable/components/FilterBar.tsx"],"sourcesContent":["import React from 'react';\nimport { Table } from '../tanstack-table';\nimport { FilterConfig, CustomFilterPanelProps } from '../types';\nimport { useAppContext } from '../../../../contexts/AppContext';\nimport { FilterPanel } from '../Filters';\n\ninterface FilterBarProps<T extends object> {\n table: Table<T>;\n columns: any[];\n activeFilter: string | null;\n setActiveFilter: (filter: string | null) => void;\n customFilterPanel?: React.ComponentType<CustomFilterPanelProps>;\n filterConfig?: FilterConfig;\n}\n\nexport function FilterBar<T extends object>({\n table,\n columns,\n activeFilter,\n setActiveFilter,\n customFilterPanel,\n filterConfig,\n}: FilterBarProps<T>) {\n const { language } = useAppContext();\n\n const getLocalizedText = (zhText: string, enText: string) => {\n return language === 'zh' ? zhText : enText;\n };\n\n const renderColumnFilter = (columnId: string) => {\n const column = columns.find(col =>\n ('accessorKey' in col && col.accessorKey === columnId) ||\n ('id' in col && col.id === columnId)\n );\n\n if (!column) return null;\n\n const isActive = activeFilter === columnId;\n const filterType = column.meta?.filterType;\n\n if (!filterType) return null;\n\n const tableColumn = table.getColumn(columnId);\n if (!tableColumn) return null;\n\n const columnHeader = typeof column.header === 'string' ? column.header : columnId;\n\n return (\n <div className=\"relative\">\n <button\n className={`btn btn-sm ${isActive ? 'btn-primary' : 'btn-ghost'}`}\n onClick={() => setActiveFilter(isActive ? null : columnId)}\n >\n {columnHeader}\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n className=\"h-4 w-4 ml-1\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z\" />\n </svg>\n </button>\n\n {isActive && (\n <div className=\"absolute mt-2 z-[100]\">\n {React.createElement(customFilterPanel || FilterPanel, {\n column: tableColumn as any,\n onClose: () => setActiveFilter(null)\n })}\n </div>\n )}\n </div>\n );\n };\n\n return (\n <div className=\"flex gap-2 flex-wrap items-center\">\n {columns.map(column => {\n const columnId = 'accessorKey' in column ? column.accessorKey as string : column.id as string;\n if (column.meta?.filterType) {\n return <React.Fragment key={columnId}>{renderColumnFilter(columnId)}</React.Fragment>;\n }\n return null;\n })}\n\n {filterConfig?.showClearAll && (\n <button\n className=\"btn btn-sm btn-ghost text-error\"\n onClick={() => table.resetColumnFilters()}\n >\n {getLocalizedText('清除所有', 'Clear All')}\n </button>\n )}\n\n {filterConfig?.customFilters}\n </div>\n );\n}\n"],"mappings":";;;;AAeA,SAAgB,EAA4B,EACxC,OAAA,GACA,SAAA,GACA,cAAA,GACA,iBAAA,GACA,mBAAA,GACA,cAAA,EAAA,GACkB;AAClB,QAAM,EAAE,UAAA,EAAA,IAAa,EAAc,GAE7B,IAAA,CAAoB,GAAgB,MAC/B,MAAa,OAAO,IAAS,GAGlC,IAAA,CAAsB,MAAqB;AAC7C,UAAM,IAAS,EAAQ,KAAA,CAAK,MACvB,iBAAiB,KAAO,EAAI,gBAAgB,KAC5C,QAAQ,KAAO,EAAI,OAAO,CAC/B;AAEA,QAAI,CAAC,EAAQ,QAAO;AAEpB,UAAM,IAAW,MAAiB;AAGlC,QAAI,CAFe,EAAO,MAAM,WAEf,QAAO;AAExB,UAAM,IAAc,EAAM,UAAU,CAAQ;AAC5C,QAAI,CAAC,EAAa,QAAO;AAEzB,UAAM,IAAe,OAAO,EAAO,UAAW,WAAW,EAAO,SAAS;AAEzE,WACI,gBAAA,EAAC,OAAD;AAAA,MAAK,WAAU;AAAA,MAAf,UAAA,CACI,gBAAA,EAAC,UAAD;AAAA,QACI,WAAW,cAAc,IAAW,gBAAgB,WAAA;AAAA,QACpD,SAAA,MAAe,EAAgB,IAAW,OAAO,CAAQ;AAAA,QAF7D,UAAA,CAIK,GACD,gBAAA,EAAC,OAAD;AAAA,UACI,OAAM;AAAA,UACN,WAAU;AAAA,UACV,MAAK;AAAA,UACL,SAAQ;AAAA,UACR,QAAO;AAAA,UAEP,UAAA,gBAAA,EAAC,QAAD;AAAA,YAAM,eAAc;AAAA,YAAQ,gBAAe;AAAA,YAAQ,aAAY;AAAA,YAAI,GAAE;AAAA,UAA2J,CAAA;AAAA,QAC/N,CAAA,CACD;AAAA,MAEP,CAAA,GAAA,KACG,gBAAA,EAAC,OAAD;AAAA,QAAK,WAAU;AAAA,QACV,UAAA,EAAM,cAAc,KAAqB,GAAa;AAAA,UACnD,QAAQ;AAAA,UACR,SAAA,MAAe,EAAgB,IAAI;AAAA,QACvC,CAAC;AAAA,MACA,CAAA,CAER;AAAA;EAEb;AAEA,SACI,gBAAA,EAAC,OAAD;AAAA,IAAK,WAAU;AAAA,IAAf,UAAA;AAAA,MACK,EAAQ,IAAA,CAAI,MAAU;AACnB,cAAM,IAAW,iBAAiB,IAAS,EAAO,cAAwB,EAAO;AACjF,eAAI,EAAO,MAAM,aACN,gBAAA,EAAC,EAAM,UAAP,EAAA,UAAgC,EAAmB,CAAQ,EAAkB,GAAxD,CAAwD,IAEjF;AAAA,MACX,CAAC;AAAA,MAEA,GAAc,gBACX,gBAAA,EAAC,UAAD;AAAA,QACI,WAAU;AAAA,QACV,SAAA,MAAe,EAAM,mBAAmB;AAAA,QAEvC,UAAA,EAAiB,QAAQ,WAAW;AAAA,MACjC,CAAA;AAAA,MAGX,GAAc;AAAA,IACd;AAAA;AAEb"}
|