feat(操作统计): 抽屉内增加独立时间筛选

- 抽屉内提供 今天/近7天/近30天/自定义 时间选择,默认同步顶部当前值
- 切换时间自动刷新统计与明细,无需关闭看板调整顶部时间
This commit is contained in:
2026-08-28 14:40:58 +08:00
parent 788d7a7f78
commit 1a5716a1ab

View File

@ -277,6 +277,9 @@ export default function AdminDashboard() {
const [opFilterUsers, setOpFilterUsers] = useState<Set<string>>(new Set()); // 多选人员
const [opFilterTouched, setOpFilterTouched] = useState(false); // 用户是否主动操作过筛选
const [opSort, setOpSort] = useState<{ key: string; order: "asc" | "desc" } | null>(null);
// 抽屉内独立时间筛选(不依赖顶部)
const [opDateKey, setOpDateKey] = useState<DateRangeKey>("today");
const [opCustomRange, setOpCustomRange] = useState<[Dayjs, Dayjs] | null>(null);
// 操作明细下钻
const [opDetailOpen, setOpDetailOpen] = useState(false);
const [opDetailList, setOpDetailList] = useState<OperationDetail[]>([]);
@ -337,22 +340,28 @@ export default function AdminDashboard() {
.finally(() => setRejectedLoading(false));
};
// 人员操作统计 — 跟随顶部时间筛选(打开抽屉时加载)
// 人员操作统计 — 用抽屉内独立时间筛选
const loadUserOperations = useCallback(() => {
setOpLoading(true);
const { since, until } = rangeToParams(dateKey, customRange);
const { since, until } = rangeToParams(opDateKey, opCustomRange);
fetchUserOperations(since, until)
.then(setOpStats)
.catch(() => setOpStats([]))
.finally(() => setOpLoading(false));
}, [dateKey, customRange]);
}, [opDateKey, opCustomRange]);
// 抽屉打开或内部时间变化时加载
useEffect(() => {
if (opsDrawerOpen) loadUserOperations();
}, [opsDrawerOpen, loadUserOperations]);
const openOpsDrawer = () => {
setOpsDrawerOpen(true);
setOpDateKey(dateKey); // 默认同步顶部当前时间
setOpCustomRange(customRange);
setOpFilterUsers(new Set());
setOpFilterTouched(false);
setOpSort(null);
loadUserOperations();
};
// 首次加载完成后默认全选(显示全部);用户操作过筛选后不再自动覆盖
@ -390,12 +399,12 @@ export default function AdminDashboard() {
});
};
// 点击数字下钻查看明细
// 点击数字下钻查看明细(跟随抽屉内时间)
const openOpDetail = (user: UserOperation, actionType: string, label: string) => {
setOpDetailOpen(true);
setOpDetailTitle(`${user.user_name} · ${label}`);
setOpDetailLoading(true);
const { since, until } = rangeToParams(dateKey, customRange);
const { since, until } = rangeToParams(opDateKey, opCustomRange);
fetchOperationDetail(user.user_id, actionType, since, until)
.then(setOpDetailList)
.catch(() => setOpDetailList([]))
@ -740,6 +749,31 @@ export default function AdminDashboard() {
size="large"
styles={{ body: { padding: 16, background: "#f8fafc" } }}
>
{/* 抽屉内时间筛选 */}
<div className="mb-4 flex flex-wrap items-center gap-2">
<Radio.Group
value={opDateKey}
onChange={e => { setOpDateKey(e.target.value); setOpCustomRange(null); }}
size="small"
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>
{opDateKey === "custom" && (
<RangePicker
size="small"
value={opCustomRange as any}
onChange={dates => setOpCustomRange(dates as [Dayjs, Dayjs] | null)}
style={{ width: 240 }}
placeholder={["开始", "结束"]}
/>
)}
</div>
{/* 人员选择 — 人名宫格多选 */}
<div className="mb-4">
<div className="mb-2 flex items-center justify-between">