在准备环境前提交次全部更改。
This commit is contained in:
187
apps/admin-web/src/components/DwdTableSelector.tsx
Normal file
187
apps/admin-web/src/components/DwdTableSelector.tsx
Normal file
@@ -0,0 +1,187 @@
|
||||
/**
|
||||
* 按业务域分组的 DWD 表选择器。
|
||||
*
|
||||
* 从 /api/tasks/dwd-tables 获取 DWD 表定义,按业务域折叠展示,
|
||||
* 支持全选/反选。仅在 Flow 包含 DWD 层时由父组件渲染。
|
||||
*/
|
||||
|
||||
import React, { useEffect, useState, useMemo, useCallback } from "react";
|
||||
import {
|
||||
Collapse,
|
||||
Checkbox,
|
||||
Spin,
|
||||
Alert,
|
||||
Button,
|
||||
Space,
|
||||
Typography,
|
||||
} from "antd";
|
||||
import type { CheckboxChangeEvent } from "antd/es/checkbox";
|
||||
import { fetchDwdTables } from "../api/tasks";
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Props */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
export interface DwdTableSelectorProps {
|
||||
/** 已选中的 DWD 表名列表 */
|
||||
selectedTables: string[];
|
||||
/** 选中表变化回调 */
|
||||
onTablesChange: (tables: string[]) => void;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* 组件 */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
const DwdTableSelector: React.FC<DwdTableSelectorProps> = ({
|
||||
selectedTables,
|
||||
onTablesChange,
|
||||
}) => {
|
||||
/** 按业务域分组的 DWD 表 */
|
||||
const [tableGroups, setTableGroups] = useState<Record<string, string[]>>({});
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
/* ---------- 加载 DWD 表定义 ---------- */
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
fetchDwdTables()
|
||||
.then((data) => {
|
||||
if (!cancelled) setTableGroups(data);
|
||||
})
|
||||
.catch((err) => {
|
||||
if (!cancelled) setError(err?.message ?? "获取 DWD 表列表失败");
|
||||
})
|
||||
.finally(() => {
|
||||
if (!cancelled) setLoading(false);
|
||||
});
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, []);
|
||||
|
||||
/** 所有表名的扁平列表 */
|
||||
const allTableNames = useMemo(
|
||||
() => Object.values(tableGroups).flat(),
|
||||
[tableGroups],
|
||||
);
|
||||
|
||||
/* ---------- 事件处理 ---------- */
|
||||
|
||||
/** 单个业务域的勾选变化 */
|
||||
const handleDomainChange = useCallback(
|
||||
(domain: string, checkedTables: string[]) => {
|
||||
const domainTables = new Set(tableGroups[domain] ?? []);
|
||||
const otherSelected = selectedTables.filter((t) => !domainTables.has(t));
|
||||
onTablesChange([...otherSelected, ...checkedTables]);
|
||||
},
|
||||
[selectedTables, tableGroups, onTablesChange],
|
||||
);
|
||||
|
||||
/** 全选 */
|
||||
const handleSelectAll = useCallback(() => {
|
||||
onTablesChange(allTableNames);
|
||||
}, [allTableNames, onTablesChange]);
|
||||
|
||||
/** 反选 */
|
||||
const handleInvertSelection = useCallback(() => {
|
||||
const currentSet = new Set(selectedTables);
|
||||
const inverted = allTableNames.filter((t) => !currentSet.has(t));
|
||||
onTablesChange(inverted);
|
||||
}, [allTableNames, selectedTables, onTablesChange]);
|
||||
|
||||
/* ---------- 渲染 ---------- */
|
||||
|
||||
if (loading) {
|
||||
return <Spin tip="加载 DWD 表列表…" />;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <Alert type="error" message="加载失败" description={error} />;
|
||||
}
|
||||
|
||||
const domainEntries = Object.entries(tableGroups);
|
||||
|
||||
if (domainEntries.length === 0) {
|
||||
return <Text type="secondary">无可选 DWD 表</Text>;
|
||||
}
|
||||
|
||||
const selectedCount = selectedTables.filter((t) =>
|
||||
allTableNames.includes(t),
|
||||
).length;
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* 全选 / 反选 */}
|
||||
<Space style={{ marginBottom: 8 }}>
|
||||
<Button size="small" onClick={handleSelectAll}>
|
||||
全选
|
||||
</Button>
|
||||
<Button size="small" onClick={handleInvertSelection}>
|
||||
反选
|
||||
</Button>
|
||||
<Text type="secondary">
|
||||
已选 {selectedCount} / {allTableNames.length}
|
||||
</Text>
|
||||
</Space>
|
||||
|
||||
<Collapse
|
||||
defaultActiveKey={domainEntries.map(([d]) => d)}
|
||||
items={domainEntries.map(([domain, tables]) => {
|
||||
const domainSelected = selectedTables.filter((t) =>
|
||||
tables.includes(t),
|
||||
);
|
||||
|
||||
const allChecked = domainSelected.length === tables.length;
|
||||
const indeterminate = domainSelected.length > 0 && !allChecked;
|
||||
|
||||
const handleDomainCheckAll = (e: CheckboxChangeEvent) => {
|
||||
handleDomainChange(domain, e.target.checked ? tables : []);
|
||||
};
|
||||
|
||||
return {
|
||||
key: domain,
|
||||
label: (
|
||||
<span onClick={(e) => e.stopPropagation()}>
|
||||
<Checkbox
|
||||
indeterminate={indeterminate}
|
||||
checked={allChecked}
|
||||
onChange={handleDomainCheckAll}
|
||||
style={{ marginRight: 8 }}
|
||||
/>
|
||||
{domain}
|
||||
<Text type="secondary" style={{ marginLeft: 4 }}>
|
||||
({domainSelected.length}/{tables.length})
|
||||
</Text>
|
||||
</span>
|
||||
),
|
||||
children: (
|
||||
<Checkbox.Group
|
||||
value={domainSelected}
|
||||
onChange={(checked) =>
|
||||
handleDomainChange(domain, checked as string[])
|
||||
}
|
||||
>
|
||||
<Space direction="vertical">
|
||||
{tables.map((table) => (
|
||||
<Checkbox key={table} value={table}>
|
||||
{table}
|
||||
</Checkbox>
|
||||
))}
|
||||
</Space>
|
||||
</Checkbox.Group>
|
||||
),
|
||||
};
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DwdTableSelector;
|
||||
Reference in New Issue
Block a user