feat(任务全景): 新增列显隐控制,可勾选去掉不想要的列
- 工具栏新增「列设置」按钮,弹出 checkbox 列表控制列显示/隐藏 - 勾选=显示,取消=去掉该列(如不需要宏观状态可直接取消勾选) - 操作列(流转树)固定显示不可隐藏,提供「全部显示」重置 - 表格列数与网格跨度按实际显示列动态计算,原有排序/筛选/拖拽保留
This commit is contained in:
@ -3,7 +3,7 @@ import { useState, useEffect, useMemo, useCallback } from "react";
|
|||||||
import { useSearchParams } from "react-router-dom";
|
import { useSearchParams } from "react-router-dom";
|
||||||
import {
|
import {
|
||||||
Search, Loader2, Package, ChevronDown, ChevronRight,
|
Search, Loader2, Package, ChevronDown, ChevronRight,
|
||||||
Warehouse, GitBranch, X, ArrowUp, ArrowDown, ArrowUpDown, Filter,
|
Warehouse, GitBranch, X, ArrowUp, ArrowDown, ArrowUpDown, Filter, Columns,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { Tooltip, Popover, Checkbox, Input } from "antd";
|
import { Tooltip, Popover, Checkbox, Input } from "antd";
|
||||||
import api from "../../services/api";
|
import api from "../../services/api";
|
||||||
@ -185,8 +185,6 @@ export default function AdminTasksPage() {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const TOTAL_SPAN = columns.reduce((s, c) => s + c.colSpan, 0);
|
|
||||||
|
|
||||||
// ---- 列顺序 / 行排序 / 列筛选状态 ----
|
// ---- 列顺序 / 行排序 / 列筛选状态 ----
|
||||||
const [columnOrder, setColumnOrder] = useState<string[]>(() => columns.map((c) => c.key));
|
const [columnOrder, setColumnOrder] = useState<string[]>(() => columns.map((c) => c.key));
|
||||||
const [sort, setSort] = useState<{ key: string; order: SortOrder } | null>(null);
|
const [sort, setSort] = useState<{ key: string; order: SortOrder } | null>(null);
|
||||||
@ -194,6 +192,8 @@ export default function AdminTasksPage() {
|
|||||||
const [enumFilters, setEnumFilters] = useState<Record<string, Set<string>>>({});
|
const [enumFilters, setEnumFilters] = useState<Record<string, Set<string>>>({});
|
||||||
const [dragCol, setDragCol] = useState<string | null>(null);
|
const [dragCol, setDragCol] = useState<string | null>(null);
|
||||||
const [dragOverCol, setDragOverCol] = useState<string | null>(null);
|
const [dragOverCol, setDragOverCol] = useState<string | null>(null);
|
||||||
|
// 🔧 列显隐:默认全部显示,勾选取消的列从表格中去掉(操作列始终显示)
|
||||||
|
const [hiddenColumns, setHiddenColumns] = useState<Set<string>>(new Set());
|
||||||
|
|
||||||
// 从看板跳转: ?sn=xxx → 自动搜索 + 自动展开流转树
|
// 从看板跳转: ?sn=xxx → 自动搜索 + 自动展开流转树
|
||||||
const autoSn = searchParams.get("sn") || "";
|
const autoSn = searchParams.get("sn") || "";
|
||||||
@ -308,6 +308,15 @@ export default function AdminTasksPage() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---- 列显隐:勾选=显示,取消=隐藏(操作列始终显示) ----
|
||||||
|
function toggleColumnVisible(key: string) {
|
||||||
|
setHiddenColumns((prev) => {
|
||||||
|
const next = new Set(prev);
|
||||||
|
if (next.has(key)) next.delete(key); else next.add(key);
|
||||||
|
return next;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// ---- 枚举列多选筛选 ----
|
// ---- 枚举列多选筛选 ----
|
||||||
function toggleEnumFilter(key: string, value: string) {
|
function toggleEnumFilter(key: string, value: string) {
|
||||||
setEnumFilters((prev) => {
|
setEnumFilters((prev) => {
|
||||||
@ -450,6 +459,29 @@ export default function AdminTasksPage() {
|
|||||||
.map((key) => columns.find((c) => c.key === key))
|
.map((key) => columns.find((c) => c.key === key))
|
||||||
.filter((c): c is ColumnDef => !!c);
|
.filter((c): c is ColumnDef => !!c);
|
||||||
|
|
||||||
|
// 🔧 实际显示的列(排除被隐藏的)+ 动态总跨度
|
||||||
|
const visibleColumns = orderedColumns.filter((c) => !hiddenColumns.has(c.key));
|
||||||
|
const visibleSpan = visibleColumns.reduce((s, c) => s + c.colSpan, 0);
|
||||||
|
|
||||||
|
// 列设置面板内容(列显隐)
|
||||||
|
function renderColumnPanel() {
|
||||||
|
const toggleable = columns.filter((c) => c.key !== "actions");
|
||||||
|
return (
|
||||||
|
<div className="max-h-80 w-48 overflow-auto p-2">
|
||||||
|
{toggleable.map((col) => (
|
||||||
|
<label key={col.key} className="flex cursor-pointer items-center gap-2 rounded px-1 py-1 text-xs text-gray-700 hover:bg-gray-50">
|
||||||
|
<Checkbox checked={!hiddenColumns.has(col.key)} onChange={() => toggleColumnVisible(col.key)} />
|
||||||
|
<span className="truncate">{col.label}</span>
|
||||||
|
</label>
|
||||||
|
))}
|
||||||
|
<div className="mt-1 flex items-center justify-between border-t border-gray-100 pt-1.5">
|
||||||
|
<button onClick={() => setHiddenColumns(new Set())} className="text-xs text-blue-600 hover:underline">全部显示</button>
|
||||||
|
<span className="text-[10px] text-gray-300">操作列固定</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// 列筛选面板内容
|
// 列筛选面板内容
|
||||||
function renderFilterPanel(col: ColumnDef) {
|
function renderFilterPanel(col: ColumnDef) {
|
||||||
if (col.filterType === "text") {
|
if (col.filterType === "text") {
|
||||||
@ -505,7 +537,12 @@ export default function AdminTasksPage() {
|
|||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-1">
|
<div className="flex items-center gap-1">
|
||||||
|
<Popover trigger="click" placement="bottomRight" content={renderColumnPanel()}>
|
||||||
|
<button className="flex items-center gap-1 rounded px-2 py-1 text-[11px] text-gray-500 hover:bg-gray-100 hover:text-blue-600">
|
||||||
|
<Columns className="h-3 w-3" />列设置
|
||||||
|
</button>
|
||||||
|
</Popover>
|
||||||
<button onClick={() => setExpandedOrders(new Set(orderGroups.map(g => g.orderNo)))}
|
<button onClick={() => setExpandedOrders(new Set(orderGroups.map(g => g.orderNo)))}
|
||||||
className="rounded px-2 py-1 text-[11px] text-blue-600 hover:bg-blue-50">全部展开</button>
|
className="rounded px-2 py-1 text-[11px] text-blue-600 hover:bg-blue-50">全部展开</button>
|
||||||
<button onClick={() => setExpandedOrders(new Set())}
|
<button onClick={() => setExpandedOrders(new Set())}
|
||||||
@ -646,9 +683,9 @@ export default function AdminTasksPage() {
|
|||||||
{/* 订单展开内容 */}
|
{/* 订单展开内容 */}
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
<div className="border-t border-gray-100">
|
<div className="border-t border-gray-100">
|
||||||
{/* 表头(可排序 / 可筛选 / 可拖拽换列) */}
|
{/* 表头(可排序 / 可筛选 / 可拖拽换列 / 可显隐) */}
|
||||||
<div className="grid gap-2 bg-gray-50 px-5 py-2 text-xs font-medium text-gray-500" style={{ gridTemplateColumns: `repeat(${TOTAL_SPAN}, minmax(0, 1fr))` }}>
|
<div className="grid gap-2 bg-gray-50 px-5 py-2 text-xs font-medium text-gray-500" style={{ gridTemplateColumns: `repeat(${visibleSpan}, minmax(0, 1fr))` }}>
|
||||||
{orderedColumns.map((col) => {
|
{visibleColumns.map((col) => {
|
||||||
const sorted = sort?.key === col.key;
|
const sorted = sort?.key === col.key;
|
||||||
const hasFilter = col.filterType === "text"
|
const hasFilter = col.filterType === "text"
|
||||||
? !!(textFilters[col.key] || "").trim()
|
? !!(textFilters[col.key] || "").trim()
|
||||||
@ -694,8 +731,8 @@ export default function AdminTasksPage() {
|
|||||||
{group.products.map((p) => {
|
{group.products.map((p) => {
|
||||||
return (
|
return (
|
||||||
<div key={p.id}>
|
<div key={p.id}>
|
||||||
<div className="grid gap-2 border-t border-gray-50 px-5 py-3 items-center text-sm hover:bg-gray-50/50" style={{ gridTemplateColumns: `repeat(${TOTAL_SPAN}, minmax(0, 1fr))` }}>
|
<div className="grid gap-2 border-t border-gray-50 px-5 py-3 items-center text-sm hover:bg-gray-50/50" style={{ gridTemplateColumns: `repeat(${visibleSpan}, minmax(0, 1fr))` }}>
|
||||||
{orderedColumns.map((col) => (
|
{visibleColumns.map((col) => (
|
||||||
<div key={col.key} style={{ gridColumn: `span ${col.colSpan} / span ${col.colSpan}` }}>
|
<div key={col.key} style={{ gridColumn: `span ${col.colSpan} / span ${col.colSpan}` }}>
|
||||||
{col.render(p)}
|
{col.render(p)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user