|
@@ -1,6 +1,6 @@
|
|
|
import { DownloadOutlined, LeftOutlined } from "@ant-design/icons";
|
|
|
import { Button, Input, Dropdown, MenuProps, Tooltip, InputRef } from "antd";
|
|
|
-import React, { useRef, useState } from "react";
|
|
|
+import React, { useEffect, useRef, useState } from "react";
|
|
|
import logo from "@/assets/logo.png";
|
|
|
import { Icon, useModel } from "umi";
|
|
|
import { exportImage } from "@/components/ExportImage";
|
|
@@ -23,14 +23,16 @@ import {
|
|
|
handleLock,
|
|
|
handleUnLock,
|
|
|
handleDelete,
|
|
|
- createNew
|
|
|
+ createNew,
|
|
|
} from "@/utils";
|
|
|
+import FindReplaceModal from "@/components/FindReplaceModal";
|
|
|
+import { useFindReplace } from "@/hooks/useFindReplace";
|
|
|
|
|
|
InsertCss(`
|
|
|
.custom-color-picker-popover {
|
|
|
z-index: 9999;
|
|
|
}
|
|
|
- `)
|
|
|
+ `);
|
|
|
export default function MenuBar() {
|
|
|
const {
|
|
|
projectInfo,
|
|
@@ -41,6 +43,7 @@ export default function MenuBar() {
|
|
|
pageState,
|
|
|
onChangePageSettings,
|
|
|
setLeftPanelActiveKey,
|
|
|
+ setShowHistory,
|
|
|
} = useModel("appModel");
|
|
|
const { graph, canRedo, canUndo, selectedCell } = useModel("graphModel");
|
|
|
const inputRef = useRef<InputRef>(null);
|
|
@@ -48,9 +51,56 @@ export default function MenuBar() {
|
|
|
// 重命名
|
|
|
const handleRename = () => {
|
|
|
inputRef.current?.select();
|
|
|
- inputRef.current?.setSelectionRange(0, projectInfo.name.length);
|
|
|
+ projectInfo &&
|
|
|
+ inputRef.current?.setSelectionRange(0, projectInfo.name.length);
|
|
|
};
|
|
|
|
|
|
+ useEffect(() => {
|
|
|
+ if (projectInfo?.name !== name) {
|
|
|
+ setName(projectInfo?.name);
|
|
|
+ }
|
|
|
+ }, [projectInfo]);
|
|
|
+
|
|
|
+ // 修改项目名称
|
|
|
+ const handleChangeName = () => {
|
|
|
+ if (!name?.trim()) {
|
|
|
+ setName(projectInfo?.name);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ projectInfo &&
|
|
|
+ setProjectInfo({
|
|
|
+ ...projectInfo,
|
|
|
+ name: name,
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ const [name, setName] = useState(projectInfo?.name);
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ setName(projectInfo?.name);
|
|
|
+ }, [projectInfo?.name]);
|
|
|
+
|
|
|
+ const {
|
|
|
+ handleFind,
|
|
|
+ handleReplace,
|
|
|
+ handleReplaceAll,
|
|
|
+ handleClose,
|
|
|
+ handleFindNext,
|
|
|
+ handleFindPrev,
|
|
|
+ findCount,
|
|
|
+ currentIndex,
|
|
|
+ setInstance,
|
|
|
+ } = useFindReplace(graph);
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ graph && setInstance(graph);
|
|
|
+ setSelectionStrict(!!graph?.isStrictRubberband())
|
|
|
+ }, [graph]);
|
|
|
+
|
|
|
+ const findModalRef = useRef<any>();
|
|
|
+
|
|
|
+ const [selectionStrict, setSelectionStrict] = useState(true);
|
|
|
+
|
|
|
// 预览 todo
|
|
|
const handlePreview = () => {};
|
|
|
|
|
@@ -61,17 +111,13 @@ export default function MenuBar() {
|
|
|
const handleClone = () => {};
|
|
|
|
|
|
// 历史记录 todo
|
|
|
- const handleHistory = () => {};
|
|
|
+ const handleHistory = () => {
|
|
|
+ setShowHistory(true);
|
|
|
+ };
|
|
|
|
|
|
// 默认样式 todo
|
|
|
const handleDefaultStyle = () => {};
|
|
|
|
|
|
- // 查找 todo
|
|
|
- const handleFind = () => {};
|
|
|
-
|
|
|
- // 替换 todo
|
|
|
- const handleReplace = () => {};
|
|
|
-
|
|
|
// 数据属性 todo
|
|
|
const handleShowDataAttr = () => {};
|
|
|
|
|
@@ -340,7 +386,9 @@ export default function MenuBar() {
|
|
|
</div>
|
|
|
),
|
|
|
icon: <i className="w-20px iconfont " />,
|
|
|
- onClick: handleFind,
|
|
|
+ onClick: () => {
|
|
|
+ findModalRef.current?.open();
|
|
|
+ },
|
|
|
},
|
|
|
{
|
|
|
key: "2-10",
|
|
@@ -351,7 +399,9 @@ export default function MenuBar() {
|
|
|
</div>
|
|
|
),
|
|
|
icon: <i className="w-20px iconfont " />,
|
|
|
- onClick: handleReplace,
|
|
|
+ onClick: () => {
|
|
|
+ findModalRef.current?.open(2);
|
|
|
+ },
|
|
|
},
|
|
|
{
|
|
|
key: "2-11",
|
|
@@ -385,7 +435,7 @@ export default function MenuBar() {
|
|
|
</div>
|
|
|
),
|
|
|
icon: <i className="w-20px iconfont " />,
|
|
|
- onClick: () => selectAll,
|
|
|
+ onClick: () => graph && selectAll(graph),
|
|
|
},
|
|
|
{
|
|
|
key: "3-2",
|
|
@@ -394,12 +444,20 @@ export default function MenuBar() {
|
|
|
{
|
|
|
key: "3-3",
|
|
|
label: "框选部分选中数据",
|
|
|
- icon: <i className="w-20px iconfont " />,
|
|
|
+ icon: <i className={`w-20px iconfont ${!selectionStrict ? "icon-cheked_16x16" : ''}`} />,
|
|
|
+ onClick: () => {
|
|
|
+ graph?.disableStrictRubberband();
|
|
|
+ setSelectionStrict(false);
|
|
|
+ }
|
|
|
},
|
|
|
{
|
|
|
key: "3-4",
|
|
|
label: "框选全部选中图形",
|
|
|
- icon: <i className="w-20px iconfont " />,
|
|
|
+ icon: <i className={`w-20px iconfont ${selectionStrict ? "icon-cheked_16x16" : ''}`} />,
|
|
|
+ onClick: () => {
|
|
|
+ graph?.enableStrictRubberband();
|
|
|
+ setSelectionStrict(true);
|
|
|
+ }
|
|
|
},
|
|
|
],
|
|
|
},
|
|
@@ -527,16 +585,16 @@ export default function MenuBar() {
|
|
|
),
|
|
|
onClick: () => graph && handleCreateEdge(graph),
|
|
|
},
|
|
|
- {
|
|
|
- key: "5-5",
|
|
|
- type: "divider",
|
|
|
- },
|
|
|
- {
|
|
|
- key: "5-6",
|
|
|
- label: "数据属性",
|
|
|
- icon: <i className="w-20px iconfont icon-tubiao" />,
|
|
|
- onClick: handleShowDataAttr,
|
|
|
- },
|
|
|
+ // {
|
|
|
+ // key: "5-5",
|
|
|
+ // type: "divider",
|
|
|
+ // },
|
|
|
+ // {
|
|
|
+ // key: "5-6",
|
|
|
+ // label: "数据属性",
|
|
|
+ // icon: <i className="w-20px iconfont icon-tubiao" />,
|
|
|
+ // onClick: handleShowDataAttr,
|
|
|
+ // },
|
|
|
// {
|
|
|
// key: "5-7",
|
|
|
// label: (
|
|
@@ -567,7 +625,7 @@ export default function MenuBar() {
|
|
|
<CustomColorPicker
|
|
|
otherPopoverAttr={{
|
|
|
placement: "left",
|
|
|
- overlayClassName: "custom-color-picker-popover"
|
|
|
+ overlayClassName: "custom-color-picker-popover",
|
|
|
}}
|
|
|
color={pageState.backgroundColor}
|
|
|
onChange={(color) =>
|
|
@@ -894,84 +952,99 @@ export default function MenuBar() {
|
|
|
];
|
|
|
|
|
|
return (
|
|
|
- <div className="w-full px-8px flex justify-between items-center">
|
|
|
- <div className="menu-left flex items-center">
|
|
|
- <Button type="text" icon={<LeftOutlined />}></Button>
|
|
|
- <div className="w-40px h-40px mx-8px">
|
|
|
- <img className="w-40px" src={logo} />
|
|
|
- </div>
|
|
|
- <div className="flex flex-col leading-32px">
|
|
|
- <div>
|
|
|
- <Input
|
|
|
- ref={inputRef}
|
|
|
- className="text-16px max-w-200px"
|
|
|
- variant="borderless"
|
|
|
- value={projectInfo.name}
|
|
|
- onChange={(e) =>
|
|
|
- setProjectInfo((state) => ({ ...state, name: e.target.value }))
|
|
|
- }
|
|
|
- />
|
|
|
+ <>
|
|
|
+ <div className="w-full px-8px flex justify-between items-center">
|
|
|
+ <div className="menu-left flex items-center">
|
|
|
+ <Button type="text" icon={<LeftOutlined />}></Button>
|
|
|
+ <div className="w-40px h-40px mx-8px">
|
|
|
+ <img className="w-40px" src={logo} />
|
|
|
</div>
|
|
|
- <div>
|
|
|
- {menuData.map((item) => {
|
|
|
- return (
|
|
|
- <Dropdown
|
|
|
- key={item.key}
|
|
|
- menu={{ items: item.children, style: { width: 200 } }}
|
|
|
- placement="bottomLeft"
|
|
|
- >
|
|
|
- <Button type="text" size="small">
|
|
|
- {item.label}
|
|
|
- </Button>
|
|
|
- </Dropdown>
|
|
|
- );
|
|
|
- })}
|
|
|
+ <div className="flex flex-col leading-32px">
|
|
|
+ <div>
|
|
|
+ <Input
|
|
|
+ ref={inputRef}
|
|
|
+ className="text-16px max-w-200px"
|
|
|
+ variant="borderless"
|
|
|
+ value={name}
|
|
|
+ onChange={(e) => setName(e.target.value)}
|
|
|
+ onBlur={handleChangeName}
|
|
|
+ onPressEnter={handleChangeName}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ {menuData.map((item) => {
|
|
|
+ return (
|
|
|
+ <Dropdown
|
|
|
+ key={item.key}
|
|
|
+ menu={{ items: item.children, style: { width: 200 } }}
|
|
|
+ placement="bottomLeft"
|
|
|
+ >
|
|
|
+ <Button type="text" size="small">
|
|
|
+ {item.label}
|
|
|
+ </Button>
|
|
|
+ </Dropdown>
|
|
|
+ );
|
|
|
+ })}
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
+ <div>
|
|
|
+ <Dropdown
|
|
|
+ trigger={["click"]}
|
|
|
+ menu={{
|
|
|
+ items: [
|
|
|
+ {
|
|
|
+ key: 1,
|
|
|
+ label: (
|
|
|
+ <span>
|
|
|
+ <i className="w-20px iconfont icon-file-image" />
|
|
|
+ PNG
|
|
|
+ </span>
|
|
|
+ ),
|
|
|
+ onClick: () => graph && exportImage(graph, "png"),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 2,
|
|
|
+ label: (
|
|
|
+ <span>
|
|
|
+ <i className="w-20px iconfont icon-file-image" />
|
|
|
+ JPG
|
|
|
+ </span>
|
|
|
+ ),
|
|
|
+ onClick: () => graph && exportImage(graph, "jpg"),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 3,
|
|
|
+ label: (
|
|
|
+ <span>
|
|
|
+ <i className="w-20px iconfont icon-file-image" />
|
|
|
+ SVG
|
|
|
+ </span>
|
|
|
+ ),
|
|
|
+ onClick: () => graph && exportImage(graph, "svg"),
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <Tooltip title="导出为">
|
|
|
+ <Button type="text" icon={<DownloadOutlined />}></Button>
|
|
|
+ </Tooltip>
|
|
|
+ </Dropdown>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <div>
|
|
|
- <Dropdown
|
|
|
- trigger={["click"]}
|
|
|
- menu={{
|
|
|
- items: [
|
|
|
- {
|
|
|
- key: 1,
|
|
|
- label: (
|
|
|
- <span>
|
|
|
- <i className="w-20px iconfont icon-file-image" />
|
|
|
- PNG
|
|
|
- </span>
|
|
|
- ),
|
|
|
- onClick: () => graph && exportImage(graph, "png"),
|
|
|
- },
|
|
|
- {
|
|
|
- key: 2,
|
|
|
- label: (
|
|
|
- <span>
|
|
|
- <i className="w-20px iconfont icon-file-image" />
|
|
|
- JPG
|
|
|
- </span>
|
|
|
- ),
|
|
|
- onClick: () => graph && exportImage(graph, "jpg"),
|
|
|
- },
|
|
|
- {
|
|
|
- key: 3,
|
|
|
- label: (
|
|
|
- <span>
|
|
|
- <i className="w-20px iconfont icon-file-image" />
|
|
|
- SVG
|
|
|
- </span>
|
|
|
- ),
|
|
|
- onClick: () => graph && exportImage(graph, "svg"),
|
|
|
- },
|
|
|
- ],
|
|
|
- }}
|
|
|
- >
|
|
|
- <Tooltip title="导出为">
|
|
|
- <Button type="text" icon={<DownloadOutlined />}></Button>
|
|
|
- </Tooltip>
|
|
|
- </Dropdown>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ <FindReplaceModal
|
|
|
+ ref={findModalRef}
|
|
|
+ current={currentIndex}
|
|
|
+ count={findCount}
|
|
|
+ onClose={handleClose}
|
|
|
+ onFind={handleFind}
|
|
|
+ onFindNext={handleFindNext}
|
|
|
+ onFindPrev={handleFindPrev}
|
|
|
+ onReplace={handleReplace}
|
|
|
+ onReplaceAll={handleReplaceAll}
|
|
|
+ right={30}
|
|
|
+ top={110}
|
|
|
+ />
|
|
|
+ </>
|
|
|
);
|
|
|
}
|