188 lines
5.4 KiB
TypeScript
188 lines
5.4 KiB
TypeScript
/**
|
|
* 按业务域分组的 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;
|