123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580 |
- import {
- forwardRef,
- Key,
- useEffect,
- useImperativeHandle,
- useMemo,
- useState,
- } from "react";
- 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, 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 },
- ref
- ) {
- 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[]>([]);
- const [selectedRows, setSelectedRows] = useState<any[]>([]);
- const [okLoading, setOkLoading] = useState(false);
- const [resultStatus, setResultStatus] = useState<"success" | "error">(
- "success"
- );
- const [importTables, setImportTables] = useState<Key[]>([]);
- useEffect(() => {
- if (step === 0 && tableList.length) {
- setSelectedRowKeys(tableList.map((item) => item.table.id));
- setSelectedRows(tableList);
- }
- }, [tableList, step]);
- useImperativeHandle(ref, () => ({
- open: () => {
- setTabActiveKey("1");
- setColor(undefined);
- setStep(0);
- setOpen(true);
- run();
- run1({ type: project.type });
- },
- close: () => setOpen(false),
- }));
- useEffect(() => {
- 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.id],
- ...option,
- };
- } else {
- tableMap[item.id] = {
- ...option,
- children: [],
- };
- }
- }
- return;
- });
- return Object.keys(tableMap).map((key) => tableMap[key]);
- }, [data1]);
- // 已存在的数据表
- const existTableList = useMemo(() => {
- const list: {
- modelTable: TableItemType;
- dataTable: any;
- }[] = [];
- const tables = data?.result?.appBusinessTables || [];
- selectedRows.forEach((tableItem) => {
- const dataTable = tables.find(
- (item: any) => item.id === tableItem.table?.businessTableId
- // item.schemaName === tableItem.table.schemaName ||
- // item.aliasName === tableItem.table.aliasName
- );
- if (dataTable) {
- list.push({
- modelTable: tableItem,
- dataTable,
- });
- }
- });
- return list;
- }, [selectedRows, data]);
- // 差异对比更新当前模型数据
- const handleUpdateTable = (tableItem: TableItemType) => {
- setSelectedRows(
- selectedRows.map((item) =>
- item.table.id === tableItem.table.id ? tableItem : item
- )
- );
- };
- const Step1Comp = () => {
- return (
- <>
- <ProTable
- title={() => "请选择模型表"}
- dataSource={tableList.map((item) => item.table)}
- rowKey="id"
- search={false}
- pagination={false}
- options={false}
- size="small"
- rowSelection={{
- selectedRowKeys,
- onChange(selectedRowKeys) {
- setSelectedRowKeys(selectedRowKeys);
- setSelectedRows(
- tableList.filter((item) =>
- selectedRowKeys.includes(item.table.id)
- )
- );
- },
- }}
- columns={[
- {
- title: "类型",
- dataIndex: "type",
- valueType: "select",
- valueEnum: {
- 3: "业务表",
- 2: "流程表",
- },
- },
- {
- title: "编码",
- dataIndex: "schemaName",
- valueType: "text",
- },
- {
- title: "别名",
- dataIndex: "aliasName",
- valueType: "text",
- },
- {
- title: "名称",
- dataIndex: "langNameList",
- render: (_, record) => {
- return (
- record.langNameList?.find(
- (item: any) => item.name === "zh-CN"
- )?.value || "-"
- );
- },
- },
- {
- title: "描述",
- dataIndex: "langDescriptionList",
- render: (_, record) => {
- return (
- record?.langDescriptionList?.find(
- (item: any) => item.name === "zh-CN"
- )?.value || "-"
- );
- },
- },
- ]}
- />
- </>
- );
- };
- const Step2Comp = () => {
- const list = selectedRows.filter(({ table }) =>
- existTableList.find((item) => item.modelTable.table.id === table.id)
- );
- return (
- <>
- <div className="text-14px font-bold m-y-12px">
- 提示:共选择了
- <span className="color-green">{selectedRows.length}</span>
- 张表格数据。
- {existTableList.length ? (
- <>
- 其中有
- <span className="color-#faad14">{existTableList.length}</span>
- 张表已存在,可对比调整差异后开始操作。
- </>
- ) : null}
- </div>
- <Collapse
- items={list.map((item) => {
- const { table } = item;
- const name = table.langNameList?.find(
- (item: any) => item.name === "zh-CN"
- )?.value;
- const existTable = existTableList.find(
- (item) => item.modelTable.table.id === table.id
- );
- return {
- key: table.id,
- label: (
- <span
- style={{
- color: existTable ? "#faad14" : "",
- }}
- >{`${table.schemaName}${name ? `(${name})` : ""}`}</span>
- ),
- children: (
- <DiffTable
- sourceTable={item}
- targetTableId={existTable?.dataTable?.id}
- onChange={handleUpdateTable}
- />
- ),
- };
- })}
- />
- </>
- );
- };
- const Step3Comp = () => {
- return (
- <div className="flex justify-center items-center h-full">
- {okLoading ? (
- <Spin spinning={okLoading} tip="正在同步数据...">
- <div className="w-500px h-full"></div>
- </Spin>
- ) : (
- <>
- {resultStatus === "success" ? (
- <Result
- status="success"
- title={`数据${tabActiveKey === '1' ? '拉取' : '推送'}完成!`}
- subTitle="请查看数据表的数据信息"
- />
- ) : (
- <Result
- status="error"
- title={`数据${tabActiveKey === '1' ? '拉取' : '推送'}失败!`}
- subTitle="请检查数据表的数据信息"
- />
- )}
- </>
- )}
- </div>
- );
- };
- const handlePush = async () => {
- setStep(2);
- try {
- setOkLoading(true);
- await PushDataModelTable(selectedRows);
- // message.success("同步推送完成");
- setResultStatus("success");
- } catch (err) {
- setResultStatus("error");
- } finally {
- setOkLoading(false);
- }
- };
- 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((t) => t.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="数据同步"
- width={"100%"}
- open={open}
- loading={loading}
- style={{
- top: 10,
- padding: 0,
- }}
- bodyProps={{
- style: {
- height: "80vh",
- overflowY: "auto",
- },
- }}
- okButtonProps={{
- loading: okLoading,
- disabled: !selectedRows.length,
- }}
- onCancel={() => setOpen(false)}
- footer={(_, { CancelBtn }) => {
- return (
- <>
- <CancelBtn />
- {step === 0 && (
- <Button
- type="primary"
- disabled={!selectedRows.length}
- onClick={() => setStep(step + 1)}
- >
- 下一步
- </Button>
- )}
- {step > 0 && (
- <Button onClick={() => setStep(step - 1)}>上一步</Button>
- )}
- {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>
- )}
- </>
- );
- }}
- >
- <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}
- description="当前模型表为空,请添加后再进行同步!"
- />
- )}
- </Modal>
- );
- });
|