|
@@ -1,7 +1,53 @@
|
|
|
-import React from "react";
|
|
|
-import { Button, Dropdown, Input } from "antd";
|
|
|
-import type { MenuProps } from "antd";
|
|
|
+import React, { useState } from "react";
|
|
|
+import { Button, Dropdown, Input, Modal, Switch } from "antd";
|
|
|
+import type { DropDownProps, MenuProps } from "antd";
|
|
|
+import { useModel } from "umi";
|
|
|
+import { useFullscreen } from "ahooks";
|
|
|
export default function Menu() {
|
|
|
+ const {
|
|
|
+ project,
|
|
|
+ canRedo,
|
|
|
+ canUndo,
|
|
|
+ onRedo,
|
|
|
+ onUndo,
|
|
|
+ graph,
|
|
|
+ setProject,
|
|
|
+ onClean,
|
|
|
+ onCut,
|
|
|
+ onCopy,
|
|
|
+ onPaste,
|
|
|
+ onDelete,
|
|
|
+ } = useModel("erModel");
|
|
|
+ const [modal, contextHolder] = Modal.useModal();
|
|
|
+ const [isFullscreen, { toggleFullscreen }] = useFullscreen(document.body);
|
|
|
+ const [openKey, setOpenKey] = useState("");
|
|
|
+ const handleClean = () => {
|
|
|
+ modal.confirm({
|
|
|
+ title: "确认清除画布全部内容?",
|
|
|
+ content: "清空后将无法恢复",
|
|
|
+ cancelText: "取消",
|
|
|
+ okText: "确定",
|
|
|
+ onOk() {
|
|
|
+ onClean();
|
|
|
+ },
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleChangeSetting = (key: string, value: boolean) => {
|
|
|
+ setProject({ ...project, setting: { ...project.setting, [key]: value } });
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleZoom = (value: number) => {
|
|
|
+ if (value < 0.2) {
|
|
|
+ graph?.zoomTo(0.2);
|
|
|
+ return;
|
|
|
+ } else if (value > 2) {
|
|
|
+ graph?.zoomTo(2);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ graph?.zoomTo(value);
|
|
|
+ };
|
|
|
+
|
|
|
const menuData: {
|
|
|
key: string;
|
|
|
label: string;
|
|
@@ -14,12 +60,16 @@ export default function Menu() {
|
|
|
type: "group",
|
|
|
children: [
|
|
|
{ key: "1-1", label: "新建" },
|
|
|
- { key: "1-2", label: "在新标签页打开" },
|
|
|
+ { key: "1-2", label: "新标签页打开" },
|
|
|
{ key: "1-3", label: "保存" },
|
|
|
{ key: "1-4", label: "保存为模版" },
|
|
|
{ key: "1-5", label: "发布模版" },
|
|
|
{ key: "1-6", label: "同步到数据表" },
|
|
|
- { key: "1-7", label: "导出为图片" },
|
|
|
+ {
|
|
|
+ key: "1-7",
|
|
|
+ label: "导出为图片",
|
|
|
+ onClick: () => graph && graph?.exportPNG(),
|
|
|
+ },
|
|
|
],
|
|
|
},
|
|
|
{
|
|
@@ -27,13 +77,13 @@ export default function Menu() {
|
|
|
label: "编辑",
|
|
|
type: "group",
|
|
|
children: [
|
|
|
- { key: "1-1", label: "撤销" },
|
|
|
- { key: "1-2", label: "恢复" },
|
|
|
- { key: "1-3", label: "清楚" },
|
|
|
- { key: "1-4", label: "剪切" },
|
|
|
- { key: "1-5", label: "复制" },
|
|
|
- { key: "1-6", label: "粘贴" },
|
|
|
- { key: "1-7", label: "删除" },
|
|
|
+ { key: "1-1", label: "撤销", onClick: () => canUndo && onUndo() },
|
|
|
+ { key: "1-2", label: "恢复", onClick: () => canRedo && onRedo() },
|
|
|
+ { key: "1-3", label: "清除", onClick: handleClean },
|
|
|
+ { key: "1-4", label: "剪切", onClick: onCut },
|
|
|
+ { key: "1-5", label: "复制", onClick: onCopy },
|
|
|
+ { key: "1-6", label: "粘贴", onClick: onPaste },
|
|
|
+ { key: "1-7", label: "删除", onClick: onDelete },
|
|
|
],
|
|
|
},
|
|
|
{
|
|
@@ -41,16 +91,94 @@ export default function Menu() {
|
|
|
label: "视图",
|
|
|
type: "group",
|
|
|
children: [
|
|
|
- { key: "1-1", label: "菜单栏隐藏" },
|
|
|
- { key: "1-2", label: "侧边栏隐藏" },
|
|
|
+ {
|
|
|
+ key: "1-1",
|
|
|
+ label: (
|
|
|
+ <span className="flex items-center justify-between">
|
|
|
+ <span>菜单栏隐藏</span>
|
|
|
+ <Switch
|
|
|
+ size="small"
|
|
|
+ checked={project.setting.showMenu}
|
|
|
+ onChange={(checked) => handleChangeSetting("showMenu", checked)}
|
|
|
+ />
|
|
|
+ </span>
|
|
|
+ ),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: "1-2",
|
|
|
+ label: (
|
|
|
+ <span className="flex items-center justify-between">
|
|
|
+ <span>侧边栏隐藏</span>
|
|
|
+ <Switch
|
|
|
+ size="small"
|
|
|
+ checked={project.setting.showSidebar}
|
|
|
+ onChange={(checked) =>
|
|
|
+ handleChangeSetting("showSidebar", checked)
|
|
|
+ }
|
|
|
+ />
|
|
|
+ </span>
|
|
|
+ ),
|
|
|
+ },
|
|
|
{ key: "1-3", label: "演示模式" },
|
|
|
- { key: "1-4", label: "字段详情" },
|
|
|
- { key: "1-5", label: "重置视图" },
|
|
|
- { key: "1-6", label: "显示网格" },
|
|
|
- { key: "1-7", label: "显示关系" },
|
|
|
- { key: "1-8", label: "放大" },
|
|
|
- { key: "1-9", label: "缩小" },
|
|
|
- { key: "1-10", label: "全屏" },
|
|
|
+ {
|
|
|
+ key: "1-4",
|
|
|
+ label: (
|
|
|
+ <span className="flex items-center justify-between">
|
|
|
+ <span>字段详情</span>
|
|
|
+ <Switch
|
|
|
+ size="small"
|
|
|
+ checked={project.setting.showColumnDetail}
|
|
|
+ onChange={(checked) =>
|
|
|
+ handleChangeSetting("showColumnDetail", checked)
|
|
|
+ }
|
|
|
+ />
|
|
|
+ </span>
|
|
|
+ ),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: "1-5",
|
|
|
+ label: (
|
|
|
+ <span className="flex items-center justify-between">
|
|
|
+ <span>显示网格</span>
|
|
|
+ <Switch
|
|
|
+ size="small"
|
|
|
+ checked={project.setting.showGrid}
|
|
|
+ onChange={(checked) => handleChangeSetting("showGrid", checked)}
|
|
|
+ />
|
|
|
+ </span>
|
|
|
+ ),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: "1-6",
|
|
|
+ label: (
|
|
|
+ <span className="flex items-center justify-between">
|
|
|
+ <span>显示关系</span>
|
|
|
+ <Switch
|
|
|
+ size="small"
|
|
|
+ checked={project.setting.showRelation}
|
|
|
+ onChange={(checked) =>
|
|
|
+ handleChangeSetting("showRelation", checked)
|
|
|
+ }
|
|
|
+ />
|
|
|
+ </span>
|
|
|
+ ),
|
|
|
+ },
|
|
|
+ { key: "1-7", label: "重置视图", onClick: () => graph?.zoomTo(1) },
|
|
|
+ {
|
|
|
+ key: "1-8",
|
|
|
+ label: "放大",
|
|
|
+ onClick: () => handleZoom((graph?.zoom() || 1) + 0.2),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: "1-9",
|
|
|
+ label: "缩小",
|
|
|
+ onClick: () => handleZoom((graph?.zoom() || 1) - 0.2),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: "1-10",
|
|
|
+ label: isFullscreen ? "退出全屏" : "全屏",
|
|
|
+ onClick: () => toggleFullscreen(),
|
|
|
+ },
|
|
|
],
|
|
|
},
|
|
|
{
|
|
@@ -59,8 +187,34 @@ export default function Menu() {
|
|
|
type: "group",
|
|
|
children: [
|
|
|
{ key: "1-1", label: "修改记录" },
|
|
|
- { key: "1-2", label: "自动保存" },
|
|
|
- { key: "1-3", label: "自动同步" },
|
|
|
+ {
|
|
|
+ key: "1-2",
|
|
|
+ label: (
|
|
|
+ <span className="flex items-center justify-between">
|
|
|
+ <span>自动保存</span>
|
|
|
+ <Switch
|
|
|
+ size="small"
|
|
|
+ checked={project.setting.autoUpdate}
|
|
|
+ onChange={(checked) =>
|
|
|
+ handleChangeSetting("autoUpdate", checked)
|
|
|
+ }
|
|
|
+ />
|
|
|
+ </span>
|
|
|
+ ),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: "1-3",
|
|
|
+ label: (
|
|
|
+ <span className="flex items-center justify-between">
|
|
|
+ <span>自动同步</span>
|
|
|
+ <Switch size="small" />
|
|
|
+ </span>
|
|
|
+ ),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: "1-4",
|
|
|
+ label: "表格宽度",
|
|
|
+ },
|
|
|
],
|
|
|
},
|
|
|
{
|
|
@@ -74,8 +228,19 @@ export default function Menu() {
|
|
|
},
|
|
|
];
|
|
|
|
|
|
+ const handleOpenChange = (
|
|
|
+ nextOpen: boolean,
|
|
|
+ info: { source: "trigger" | "menu" },
|
|
|
+ key: string
|
|
|
+ ) => {
|
|
|
+ if (info.source === "trigger" || nextOpen) {
|
|
|
+ setOpenKey(nextOpen ? key : "");
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
return (
|
|
|
<div className="flex-1 flex items-center">
|
|
|
+ {contextHolder}
|
|
|
<div className="logo h-48px m-l-12px">
|
|
|
<svg className="icon h-48px w-48px" aria-hidden="true">
|
|
|
<use xlinkHref="#icon-shujujianmo"></use>
|
|
@@ -88,7 +253,9 @@ export default function Menu() {
|
|
|
variant="borderless"
|
|
|
value={"模型名称"}
|
|
|
/>
|
|
|
- <div className="bg-#eee text-12px leading-20px color-#666 rounded-4px p-x-4px p-y-2px">上次保存时间:2024-12-13 13:21:23</div>
|
|
|
+ <div className="bg-#eee text-12px leading-20px color-#666 rounded-4px p-x-4px p-y-2px">
|
|
|
+ 上次保存时间:2024-12-13 13:21:23
|
|
|
+ </div>
|
|
|
</div>
|
|
|
<div className="flex">
|
|
|
{menuData.map((item) => {
|
|
@@ -97,6 +264,10 @@ export default function Menu() {
|
|
|
key={item.key}
|
|
|
menu={{ items: item.children, style: { width: 200 } }}
|
|
|
placement="bottomLeft"
|
|
|
+ open={openKey === item.key}
|
|
|
+ onOpenChange={(nextOpen, info) =>
|
|
|
+ handleOpenChange(nextOpen, info, item.key)
|
|
|
+ }
|
|
|
>
|
|
|
<Button type="text" size="small">
|
|
|
{item.label}
|