refactor(透视表): 取消按人员分布,时间筛选对齐全局概览

- 移除按人员/按工序切换,固定按工序分布
- 时间筛选改为与全局概览一致: 今天/近7天/近30天/自定义(Radio+RangePicker)
This commit is contained in:
2026-08-28 16:36:45 +08:00
parent 9d08c50ef6
commit 8c3c0c4d90

View File

@ -3,33 +3,46 @@
* Y 轴 = 规格型号X 轴 = 人员 或 工序,单元格 = 该交叉点的在制品设备数
*/
import { useEffect, useMemo, useState } from "react";
import { Radio, Table, DatePicker, Button } from "antd";
import { Radio, Table, DatePicker } from "antd";
import { Loader2 } from "lucide-react";
import type { Dayjs } from "dayjs";
import dayjs, { type Dayjs } from "dayjs";
import { fetchWipMatrix, type WipMatrixRow } from "../services/dashboardApi";
const { RangePicker } = DatePicker;
// 每块最多显示的人员/工序列数,超过则分块垂直排列,避免横向超长
// 每块最多显示的工序列数,超过则分块垂直排列,避免横向超长
const CHUNK_MATRIX = 6;
// ⏰ 时间筛选(与全局概览一致)
type DateRangeKey = "today" | "7d" | "30d" | "custom";
function rangeToParams(key: DateRangeKey, customRange: [Dayjs, Dayjs] | null) {
if (key === "custom" && customRange) {
return {
since: customRange[0].startOf("day").toISOString(),
until: customRange[1].endOf("day").toISOString(),
};
}
const since = dayjs().startOf("day");
if (key === "7d") return { since: since.subtract(7, "day").toISOString() };
if (key === "30d") return { since: since.subtract(30, "day").toISOString() };
return { since: since.toISOString() };
}
export default function MatrixBoard() {
const [dimension, setDimension] = useState<"assignee" | "task_name">("assignee");
const [range, setRange] = useState<[Dayjs, Dayjs] | null>(null);
// 固定按工序分布(已取消按人员分布)
const [dateKey, setDateKey] = useState<DateRangeKey>("today");
const [customRange, setCustomRange] = useState<[Dayjs, Dayjs] | null>(null);
const [data, setData] = useState<WipMatrixRow[]>([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
setLoading(true);
fetchWipMatrix(
dimension,
range ? range[0].startOf("day").toISOString() : undefined,
range ? range[1].endOf("day").toISOString() : undefined,
)
const { since, until } = rangeToParams(dateKey, customRange);
fetchWipMatrix("task_name", since, until)
.then(setData)
.catch(() => setData([]))
.finally(() => setLoading(false));
}, [dimension, range]);
}, [dateKey, customRange]);
// 🔧 核心:扁平数组 → 动态交叉表规格型号为行、dimension_key 为列)
// 列数超过 CHUNK_MATRIX 时分块垂直排列,避免一行十几个人员横向超长
@ -96,21 +109,31 @@ export default function MatrixBoard() {
<div className="mb-4 flex flex-wrap items-center justify-between gap-3">
<div>
<h2 className="text-xl font-bold text-gray-800">📊 WIP </h2>
<p className="mt-1 text-sm text-gray-500"> × {dimension === "assignee" ? "人员" : "工序"} · /</p>
<p className="mt-1 text-sm text-gray-500"> × · /</p>
</div>
<div className="flex items-center gap-2">
<RangePicker
{/* ⏰ 时间筛选(与全局概览一致) */}
<div className="flex flex-wrap items-center gap-2">
<Radio.Group
value={dateKey}
onChange={e => { setDateKey(e.target.value); setCustomRange(null); }}
size="small"
value={range as any}
onChange={(dates) => setRange(dates as [Dayjs, Dayjs] | null)}
style={{ width: 240 }}
placeholder={["开始日期", "结束日期"]}
/>
{range && <Button size="small" onClick={() => setRange(null)}></Button>}
<Radio.Group value={dimension} onChange={(e) => setDimension(e.target.value)} optionType="button" buttonStyle="solid">
<Radio.Button value="assignee"></Radio.Button>
<Radio.Button value="task_name"></Radio.Button>
optionType="button"
buttonStyle="solid"
>
<Radio.Button value="today"></Radio.Button>
<Radio.Button value="7d">7</Radio.Button>
<Radio.Button value="30d">30</Radio.Button>
<Radio.Button value="custom"></Radio.Button>
</Radio.Group>
{dateKey === "custom" && (
<RangePicker
size="small"
value={customRange as any}
onChange={dates => setCustomRange(dates as [Dayjs, Dayjs] | null)}
style={{ width: 240 }}
placeholder={["开始", "结束"]}
/>
)}
</div>
</div>