|
@@ -6,14 +6,32 @@ import {
|
|
|
useMemo,
|
|
|
useState,
|
|
|
} from "react";
|
|
|
-import { Modal, Collapse, Empty, Steps, Result, Button, Spin } from "antd";
|
|
|
+import {
|
|
|
+ Modal,
|
|
|
+ Collapse,
|
|
|
+ Empty,
|
|
|
+ Steps,
|
|
|
+ Result,
|
|
|
+ Button,
|
|
|
+ Spin,
|
|
|
+ Form,
|
|
|
+ TreeSelect,
|
|
|
+ Tabs,
|
|
|
+ message,
|
|
|
+} from "antd";
|
|
|
import { ProTable } from "@ant-design/pro-components";
|
|
|
import DiffTable from "./DiffTable";
|
|
|
import { useModel, useRequest } from "umi";
|
|
|
-import { PushDataModelTable } from "@/api/dataModel";
|
|
|
-import { GetAllDesignTables } from "@/api";
|
|
|
+import { PushDataModelTable, GetCanUseTableList } from "@/api/dataModel";
|
|
|
+import {
|
|
|
+ GetAllDesignTables,
|
|
|
+ SaveDataModel,
|
|
|
+ ImportFromBusinessTables,
|
|
|
+} from "@/api";
|
|
|
import { TableItemType } from "@/type";
|
|
|
import NoData from "@/assets/no-data.png";
|
|
|
+import CustomColorPicker from "./CustomColorPicker";
|
|
|
+import { pick, set } from "lodash-es";
|
|
|
|
|
|
export default forwardRef(function SyncModal(
|
|
|
props: { onPush: () => void },
|
|
@@ -21,11 +39,13 @@ export default forwardRef(function SyncModal(
|
|
|
) {
|
|
|
const [open, setOpen] = useState(false);
|
|
|
const { project } = useModel("erModel");
|
|
|
+ const [color, setColor] = useState<string>();
|
|
|
const { data, loading, run } = useRequest(GetAllDesignTables, {
|
|
|
manual: true,
|
|
|
});
|
|
|
const [tableList, setTableList] = useState<TableItemType[]>(project?.tables);
|
|
|
const [step, setStep] = useState(0);
|
|
|
+ const [tabActiveKey, setTabActiveKey] = useState<string>("1");
|
|
|
|
|
|
// 选中需要同步的表
|
|
|
const [selectedRowKeys, setSelectedRowKeys] = useState<Key[]>([]);
|
|
@@ -34,6 +54,7 @@ export default forwardRef(function SyncModal(
|
|
|
const [resultStatus, setResultStatus] = useState<"success" | "error">(
|
|
|
"success"
|
|
|
);
|
|
|
+ const [importTables, setImportTables] = useState<Key[]>([]);
|
|
|
|
|
|
useEffect(() => {
|
|
|
if (step === 0 && tableList.length) {
|
|
@@ -44,9 +65,12 @@ export default forwardRef(function SyncModal(
|
|
|
|
|
|
useImperativeHandle(ref, () => ({
|
|
|
open: () => {
|
|
|
+ setTabActiveKey("1");
|
|
|
+ setColor(undefined);
|
|
|
setStep(0);
|
|
|
setOpen(true);
|
|
|
run();
|
|
|
+ run1({ type: project.type });
|
|
|
},
|
|
|
close: () => setOpen(false),
|
|
|
}));
|
|
@@ -55,6 +79,75 @@ export default forwardRef(function SyncModal(
|
|
|
setTableList(project.tables);
|
|
|
}, [project.tables]);
|
|
|
|
|
|
+ useEffect(() => {
|
|
|
+ setStep(0);
|
|
|
+ }, [tabActiveKey]);
|
|
|
+
|
|
|
+ const {
|
|
|
+ data: data1,
|
|
|
+ loading: loading1,
|
|
|
+ run: run1,
|
|
|
+ } = useRequest(GetCanUseTableList, {
|
|
|
+ manual: true,
|
|
|
+ });
|
|
|
+
|
|
|
+ // 可引入表列表
|
|
|
+ const treeData = useMemo(() => {
|
|
|
+ const tableMap: Record<string, any> = {};
|
|
|
+ data1?.result
|
|
|
+ ?.filter(
|
|
|
+ (item: any) =>
|
|
|
+ // 过滤当前数据表类型及存在相同schemaName、aliasName的表
|
|
|
+ item?.type == project?.type
|
|
|
+ // && !project.tables.find(
|
|
|
+ // (tableItem) =>
|
|
|
+ // tableItem.table.schemaName === item.schemaName ||
|
|
|
+ // tableItem.table.aliasName === item.aliasName
|
|
|
+ // )
|
|
|
+ )
|
|
|
+ ?.forEach((item: any) => {
|
|
|
+ // 判断是否存在已引入的表
|
|
|
+ const hasTable = project.tables.find(
|
|
|
+ (tableItem: TableItemType) =>
|
|
|
+ tableItem.table.schemaName === item.schemaName ||
|
|
|
+ tableItem.table.aliasName === item.aliasName
|
|
|
+ );
|
|
|
+
|
|
|
+ const option = {
|
|
|
+ key: item.id,
|
|
|
+ title: `${item?.schemaName}(${item.name})`,
|
|
|
+ value: item?.id,
|
|
|
+ disabled: hasTable,
|
|
|
+ selectable: !item.parentBusinessTableId,
|
|
|
+ };
|
|
|
+ // 子表
|
|
|
+ if (item.parentBusinessTableId) {
|
|
|
+ if (tableMap[item.parentBusinessTableId]) {
|
|
|
+ tableMap[item.parentBusinessTableId].children.push(option);
|
|
|
+ } else {
|
|
|
+ tableMap[item.parentBusinessTableId] = {
|
|
|
+ children: [option],
|
|
|
+ };
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 主表
|
|
|
+ if (tableMap[item.id]) {
|
|
|
+ tableMap[item.id] = {
|
|
|
+ ...tableMap[item.parentBusinessTableId],
|
|
|
+ ...option,
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ tableMap[item.id] = {
|
|
|
+ ...option,
|
|
|
+ children: [],
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ });
|
|
|
+ return Object.keys(tableMap).map((key) => tableMap[key]);
|
|
|
+ }, [data1]);
|
|
|
+
|
|
|
// 已存在的数据表
|
|
|
const existTableList = useMemo(() => {
|
|
|
const list: {
|
|
@@ -64,9 +157,9 @@ export default forwardRef(function SyncModal(
|
|
|
const tables = data?.result?.appBusinessTables || [];
|
|
|
selectedRows.forEach((tableItem) => {
|
|
|
const dataTable = tables.find(
|
|
|
- (item: any) =>
|
|
|
- item.schemaName === tableItem.table.schemaName ||
|
|
|
- item.aliasName === tableItem.table.aliasName
|
|
|
+ (item: any) => item.id === tableItem.table?.businessTableId
|
|
|
+ // item.schemaName === tableItem.table.schemaName ||
|
|
|
+ // item.aliasName === tableItem.table.aliasName
|
|
|
);
|
|
|
if (dataTable) {
|
|
|
list.push({
|
|
@@ -92,7 +185,7 @@ export default forwardRef(function SyncModal(
|
|
|
return (
|
|
|
<>
|
|
|
<ProTable
|
|
|
- title={() => "请选择需要推送的表"}
|
|
|
+ title={() => "请选择模型表"}
|
|
|
dataSource={tableList.map((item) => item.table)}
|
|
|
rowKey="id"
|
|
|
search={false}
|
|
@@ -172,7 +265,7 @@ export default forwardRef(function SyncModal(
|
|
|
<>
|
|
|
其中有
|
|
|
<span className="color-#faad14">{existTableList.length}</span>
|
|
|
- 张表存在相同的编码或别名,可对比确认后提交。
|
|
|
+ 张表已存在,可对比调整差异后开始操作。
|
|
|
</>
|
|
|
) : null}
|
|
|
</div>
|
|
@@ -237,15 +330,14 @@ export default forwardRef(function SyncModal(
|
|
|
);
|
|
|
};
|
|
|
|
|
|
- const handleSubmit = async () => {
|
|
|
+ const handlePush = async () => {
|
|
|
setStep(2);
|
|
|
try {
|
|
|
setOkLoading(true);
|
|
|
await PushDataModelTable(selectedRows);
|
|
|
// message.success("同步推送完成");
|
|
|
+
|
|
|
setResultStatus("success");
|
|
|
- setOpen(false);
|
|
|
- props.onPush?.();
|
|
|
} catch (err) {
|
|
|
setResultStatus("error");
|
|
|
} finally {
|
|
@@ -253,9 +345,72 @@ export default forwardRef(function SyncModal(
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+ const handlePull = async () => {
|
|
|
+ setOkLoading(true);
|
|
|
+ try {
|
|
|
+ // 1、更新原有表的数据
|
|
|
+ const tableIds = selectedRows.map(({ table }) => table.id);
|
|
|
+ await SaveDataModel({
|
|
|
+ erDataModel: {
|
|
|
+ ...project,
|
|
|
+ tables: project.tables.map((item) => {
|
|
|
+ if (tableIds.includes(item.table.id)) {
|
|
|
+ return (
|
|
|
+ selectedRows.find((item) => item.table.id === item.table.id) ||
|
|
|
+ item
|
|
|
+ );
|
|
|
+ }
|
|
|
+ return item;
|
|
|
+ }),
|
|
|
+ },
|
|
|
+ });
|
|
|
+ } catch (err) {
|
|
|
+ console.log(err);
|
|
|
+ message.error("拉取失败");
|
|
|
+ setResultStatus("error");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2、添加引入数据
|
|
|
+ try {
|
|
|
+ const businessTables =
|
|
|
+ data1?.result
|
|
|
+ ?.filter((item: any) => importTables?.includes(item.id))
|
|
|
+ ?.map((item: any) => {
|
|
|
+ return pick(item, [
|
|
|
+ "aliasName",
|
|
|
+ "schemaName",
|
|
|
+ "id",
|
|
|
+ "parentBusinessTableId",
|
|
|
+ ]);
|
|
|
+ }) || [];
|
|
|
+ if (!businessTables.length) {
|
|
|
+ setResultStatus("success");
|
|
|
+ setStep(2);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ await ImportFromBusinessTables({
|
|
|
+ dataModelId: project.id,
|
|
|
+ color,
|
|
|
+ businessTables,
|
|
|
+ });
|
|
|
+ } catch (err) {
|
|
|
+ console.log(err);
|
|
|
+ message.error("引入失败");
|
|
|
+ setResultStatus("error");
|
|
|
+ } finally {
|
|
|
+ setOkLoading(false);
|
|
|
+ setStep(2);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleDone = () => {
|
|
|
+ setOpen(false);
|
|
|
+ props.onPush?.();
|
|
|
+ };
|
|
|
+
|
|
|
return (
|
|
|
<Modal
|
|
|
- title="数据同步推送"
|
|
|
+ title="数据同步"
|
|
|
width={"100%"}
|
|
|
open={open}
|
|
|
loading={loading}
|
|
@@ -290,42 +445,129 @@ export default forwardRef(function SyncModal(
|
|
|
{step > 0 && (
|
|
|
<Button onClick={() => setStep(step - 1)}>上一步</Button>
|
|
|
)}
|
|
|
- {step === 1 && (
|
|
|
- <Button type="primary" onClick={handleSubmit}>
|
|
|
- 开始同步
|
|
|
+ {step === 2 && resultStatus === "success" && (
|
|
|
+ <Button type="primary" onClick={handleDone}>
|
|
|
+ 完成
|
|
|
+ </Button>
|
|
|
+ )}
|
|
|
+ {step === 1 && tabActiveKey === "1" && (
|
|
|
+ <Button type="primary" onClick={handlePull}>
|
|
|
+ 开始
|
|
|
+ </Button>
|
|
|
+ )}
|
|
|
+ {step === 1 && tabActiveKey === "2" && (
|
|
|
+ <Button type="primary" onClick={handlePush}>
|
|
|
+ 开始
|
|
|
</Button>
|
|
|
)}
|
|
|
</>
|
|
|
);
|
|
|
}}
|
|
|
>
|
|
|
- <div className="h-full flex flex-col overflow-hidden">
|
|
|
- <div className="py-12px px-30px">
|
|
|
- <Steps
|
|
|
- current={step}
|
|
|
- progressDot
|
|
|
- items={[
|
|
|
- {
|
|
|
- title: "选择数据表",
|
|
|
- description: "选择需要同步的表",
|
|
|
- },
|
|
|
- {
|
|
|
- title: "差异对比",
|
|
|
- description: "数据模型与数据表进行对比",
|
|
|
- },
|
|
|
- {
|
|
|
- title: "推送",
|
|
|
- description: "推送到数据表",
|
|
|
- },
|
|
|
- ]}
|
|
|
- />
|
|
|
- </div>
|
|
|
- <div className="flex-1 overflow-auto">
|
|
|
- {step === 0 && <Step1Comp />}
|
|
|
- {step === 1 && <Step2Comp />}
|
|
|
- {step === 2 && <Step3Comp />}
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ <Tabs
|
|
|
+ activeKey={tabActiveKey}
|
|
|
+ onChange={setTabActiveKey}
|
|
|
+ items={[
|
|
|
+ {
|
|
|
+ key: "1",
|
|
|
+ label: "拉取",
|
|
|
+ children: (
|
|
|
+ <div className="h-full flex flex-col overflow-hidden">
|
|
|
+ <div className="py-12px px-30px">
|
|
|
+ <Steps
|
|
|
+ current={step}
|
|
|
+ // progressDot
|
|
|
+ items={[
|
|
|
+ {
|
|
|
+ title: "选择数据表",
|
|
|
+ description: "选择需要拉取的表",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: "差异对比",
|
|
|
+ description: "数据模型与数据表进行对比",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: "结果",
|
|
|
+ description: "拉取到模型",
|
|
|
+ },
|
|
|
+ ]}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ {step === 0 && (
|
|
|
+ <>
|
|
|
+ <Form>
|
|
|
+ <Form.Item label="引入表" name="table">
|
|
|
+ <TreeSelect
|
|
|
+ multiple
|
|
|
+ treeCheckable
|
|
|
+ allowClear
|
|
|
+ placeholder="请选择"
|
|
|
+ loading={loading1}
|
|
|
+ treeData={treeData}
|
|
|
+ value={importTables}
|
|
|
+ onChange={(value) => {
|
|
|
+ setImportTables(value);
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </Form.Item>
|
|
|
+ <Form.Item label="颜色" name="color">
|
|
|
+ <CustomColorPicker onChange={setColor}>
|
|
|
+ {color ? (
|
|
|
+ <div
|
|
|
+ className="rounded-4px cus-btn w-32px h-32px bg-#eee flex-none cursor-pointer shadow-inner"
|
|
|
+ style={{ background: color || "#eee" }}
|
|
|
+ ></div>
|
|
|
+ ) : (
|
|
|
+ <span className="bg-#eee px-5px py-3px rounded-4px cursor-pointer text-12px text-#666">
|
|
|
+ 随机生成,点击可选择颜色
|
|
|
+ </span>
|
|
|
+ )}
|
|
|
+ </CustomColorPicker>
|
|
|
+ </Form.Item>
|
|
|
+ </Form>
|
|
|
+ <Step1Comp />
|
|
|
+ </>
|
|
|
+ )}
|
|
|
+ {step === 1 && <Step2Comp />}
|
|
|
+ {step === 2 && <Step3Comp />}
|
|
|
+ </div>
|
|
|
+ ),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: "2",
|
|
|
+ label: "推送",
|
|
|
+ children: (
|
|
|
+ <div className="h-full flex flex-col overflow-hidden">
|
|
|
+ <div className="py-12px px-30px">
|
|
|
+ <Steps
|
|
|
+ current={step}
|
|
|
+ // progressDot
|
|
|
+ items={[
|
|
|
+ {
|
|
|
+ title: "选择数据表",
|
|
|
+ description: "选择需要同步的表",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: "差异对比",
|
|
|
+ description: "数据模型与数据表进行对比",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: "结果",
|
|
|
+ description: "推送到数据表",
|
|
|
+ },
|
|
|
+ ]}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div className="flex-1 overflow-auto">
|
|
|
+ {step === 0 && <Step1Comp />}
|
|
|
+ {step === 1 && <Step2Comp />}
|
|
|
+ {step === 2 && <Step3Comp />}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ ),
|
|
|
+ },
|
|
|
+ ]}
|
|
|
+ />
|
|
|
{!tableList.length && (
|
|
|
<Empty
|
|
|
image={NoData}
|