Jelajahi Sumber

feat: 添加编辑跳转

liaojiaxing 4 bulan lalu
induk
melakukan
21d9c3e874

+ 33 - 4
apps/er-designer/src/components/NoticeNode.tsx

@@ -2,17 +2,31 @@ import React, { useEffect, useState, useRef } from "react";
 import { register } from "@antv/x6-react-shape";
 import { Graph, Node } from "@antv/x6";
 import { Input } from "antd";
-import { useSize } from 'ahooks';
+import { useSize, useSessionStorageState } from "ahooks";
 
 const NoticeNode = ({ node, graph }: { node: Node; graph: Graph }) => {
   const { style, name, text, id } = node.getData();
   const boxRef = useRef<HTMLDivElement>(null);
   const { width: w, height: h } = useSize(boxRef) || node.getSize();
+  const [showEdit, setShowEdit] = useState(false);
+
+  const [_tabActiveKey, setTabActiveKey] =
+    useSessionStorageState("tabs-active-key");
+  const [_, setRemarkActive] = useSessionStorageState("remark-active");
+  const handleEdit = () => {
+    setTabActiveKey("4");
+    setRemarkActive(id);
+  };
 
   const strokeWidth = 1;
   return (
     <>
-      <div className="relative w-full h-full" ref={boxRef}>
+      <div
+        className="relative w-full h-full"
+        ref={boxRef}
+        onMouseEnter={() => setShowEdit(true)}
+        onMouseLeave={() => setShowEdit(false)}
+      >
         <svg
           className="absolute top-0 left-0"
           viewBox={`0 0 ${w} ${h}`}
@@ -45,13 +59,28 @@ const NoticeNode = ({ node, graph }: { node: Node; graph: Graph }) => {
           />
         </svg>
         <div className="absolute w-full h-full flex flex-col">
-          <div className="color-#333 px-20px py-4px">{name}</div>
+          <div className="color-#333 px-20px py-4px flex items-center justify-between">
+            <span className="truncate leading-22px">{name}</span>
+            {showEdit && (
+              <div
+                className="edit-btn w-22px h-22px rounded-md flex items-center justify-center bg-#658dbe cursor-pointer"
+                onClick={handleEdit}
+              >
+                <i className="iconfont icon-bianji color-#fff text-12px" />
+              </div>
+            )}
+          </div>
           <Input.TextArea
             variant="borderless"
             className="w-full resize-none! flex-1 color-#666"
             value={text}
             key={id}
-            onChange={(e) => node.prop('update:remark', { ...node.getData(), text: e.target.value })}
+            onChange={(e) =>
+              node.prop("update:remark", {
+                ...node.getData(),
+                text: e.target.value,
+              })
+            }
           />
         </div>
       </div>

+ 27 - 2
apps/er-designer/src/components/TableNode.tsx

@@ -3,10 +3,16 @@ import { register } from "@antv/x6-react-shape";
 import { Graph, Node } from "@antv/x6";
 import type { ColumnItem, TableItemType } from "@/type";
 import { DATA_TYPE_OPTIONS } from "@/constants";
+import { MinusOutlined } from "@ant-design/icons";
+import { useSessionStorageState } from "ahooks";
 
 function TableNode({ node, graph }: { node: Node; graph: Graph }) {
   const { table, tableColumnList } = node.getData<TableItemType>();
   const containerRef = useRef<HTMLDivElement>(null);
+  const [showEdit, setShowEdit] = React.useState(false);
+  const [_tabActiveKey, setTabActiveKey] =
+    useSessionStorageState("tabs-active-key");
+  const [_active, setTableActive] = useSessionStorageState('table-active');
 
   useEffect(() => {
     const container = containerRef.current;
@@ -130,6 +136,11 @@ function TableNode({ node, graph }: { node: Node; graph: Graph }) {
     }
   };
 
+  const handleEdit = () => {
+    setTabActiveKey("1");
+    setTableActive(node.id);
+  };
+
   const ColumnItem = ({ record }: { record: ColumnItem }) => {
     const type = DATA_TYPE_OPTIONS.find((item) => item.value === record.type);
     return (
@@ -166,6 +177,8 @@ function TableNode({ node, graph }: { node: Node; graph: Graph }) {
     <div
       ref={containerRef}
       className="w-full border border-1px border-solid border-#333 flex flex-col overflow-hidden rounded-8px"
+      onMouseEnter={() => setShowEdit(true)}
+      onMouseLeave={() => setShowEdit(false)}
     >
       <div
         className="w-full h-10px bg-#eee"
@@ -177,16 +190,28 @@ function TableNode({ node, graph }: { node: Node; graph: Graph }) {
           border-b-solid 
           border-b-1px 
           border-b-#333 
-          truncate 
           bg-#e4e4e7 
           py-4px 
           font-bold 
           text-14px 
           min-h-32px 
           px-8px
+          flex 
+          justify-between 
+          items-center
         "
       >
-        {table.schemaName}({table.cn_name})
+        <div className="truncate flex-1">
+          {table.schemaName}({table.cn_name})
+        </div>
+        {showEdit && (
+          <div
+            className="edit-btn w-22px h-22px rounded-md flex items-center justify-center bg-#658dbe cursor-pointer"
+            onClick={handleEdit}
+          >
+            <i className="iconfont icon-bianji color-#fff text-12px" />
+          </div>
+        )}
       </div>
       <div className="bg-#fafafa flex-1">
         <div className="field-info">

+ 34 - 9
apps/er-designer/src/components/TopicNode.tsx

@@ -1,19 +1,44 @@
-
 import React, { useEffect, useMemo, useRef } from "react";
 import { register } from "@antv/x6-react-shape";
 import { Graph, Node } from "@antv/x6";
 import type { TopicAreaInfo } from "@/type";
+import { useSessionStorageState } from "ahooks";
 
 const TopicAreaNode = ({ node, graph }: { node: Node; graph: Graph }) => {
   const { style, name } = node.getData<TopicAreaInfo>();
-  return <div className="w-full h-full" style={{
-    border: "1px solid #666",
-    borderRadius: "4px",
-    background: style.background?.includes('#') ? `${style.background}88` : style.background,
-    padding: "10px",
-  }}>
-    <div className="color-#fff">{name}</div>
-  </div>
+  const [showEdit, setShowEdit] = React.useState(false);
+  const [_tabActiveKey, setTabActiveKey] =
+    useSessionStorageState("tabs-active-key");
+  const handleEdit = () => {
+    setTabActiveKey("3");
+  };
+  return (
+    <div
+      className="w-full h-full"
+      style={{
+        border: "1px solid #666",
+        borderRadius: "4px",
+        background: style.background?.includes("#")
+          ? `${style.background}88`
+          : style.background,
+        padding: "10px",
+      }}
+      onMouseEnter={() => setShowEdit(true)}
+      onMouseLeave={() => setShowEdit(false)}
+    >
+      <div className="color-#fff flex items-center justify-between leading-22px">
+        {name}{" "}
+        {showEdit && (
+          <div
+            className="edit-btn w-22px h-22px rounded-md flex items-center justify-center bg-#658dbe cursor-pointer"
+            onClick={handleEdit}
+          >
+            <i className="iconfont icon-bianji color-#fff text-12px" />
+          </div>
+        )}
+      </div>
+    </div>
+  );
 };
 
 register({

+ 9 - 0
apps/er-designer/src/layouts/index.less

@@ -16,4 +16,13 @@ body {
 
 .x6-widget-selection-box {
   border: 2px dashed #239edd;
+  border-radius: 8px;
+}
+
+.x6-graph-svg {
+  z-index: 1;
+}
+
+.x6-widget-selection-selected {
+  z-index: 0;
 }

+ 5 - 1
apps/er-designer/src/pages/er/components/RemarkPanel.tsx

@@ -5,12 +5,16 @@ import CustomColorPicker from "@/components/CustomColorPicker";
 import { useModel } from "umi";
 import noData from "@/assets/no-data.png";
 import { RemarkInfo } from "@/type";
+import { useSessionStorageState } from "ahooks";
 export default function RemarkPanel() {
   const { project, addRemark, deleteRemark, updateRemark } =
     useModel("erModel");
   const { remarks = [] } = project;
   const [search, setSearch] = React.useState("");
-  const [activeKey, setActiveKey] = React.useState("");
+  const [activeKey, setActiveKey] = useSessionStorageState("remark-active", {
+    defaultValue: "",
+    listenStorageChange: true
+  });
   const [remarkList, setRemarkList] = useState(remarks);
 
   useEffect(() => {

+ 1 - 1
apps/er-designer/src/pages/er/components/TableItem.tsx

@@ -32,7 +32,7 @@ export default function TableItem({
 }: {
   data: TableItemType;
   onChange: (data: TableItemType) => void;
-  active: string;
+  active?: string;
   setActive: (active: string) => void;
 }) {
   const { tableColumnList = [] } = data;

+ 42 - 26
apps/er-designer/src/pages/er/components/TablePanel.tsx

@@ -1,15 +1,21 @@
-import React, { useEffect } from 'react'
-import { Button, Collapse, Input } from 'antd'
-import { SearchOutlined, SettingOutlined } from '@ant-design/icons'
-import TableItem from './TableItem'
-import { useModel } from 'umi'
-import type { TableItemType } from '@/type'
-import noData from '@/assets/no-data.png'
+import React, { useEffect } from "react";
+import { Button, Collapse, Input } from "antd";
+import { SearchOutlined, SettingOutlined } from "@ant-design/icons";
+import TableItem from "./TableItem";
+import { useModel } from "umi";
+import type { TableItemType } from "@/type";
+import noData from "@/assets/no-data.png";
+import { useSessionStorageState } from "ahooks";
 export default function TablePanel() {
-  const { project, updateTable, addTable } = useModel('erModel');
+  const { project, updateTable, addTable } = useModel("erModel");
   const contentRef = React.useRef<HTMLDivElement>(null);
-  const [contentStyle, setContentStyle] = React.useState<React.CSSProperties>({});
-  const [active, setActive] = React.useState<string>('');
+  const [contentStyle, setContentStyle] = React.useState<React.CSSProperties>(
+    {}
+  );
+  const [active, setActive] = useSessionStorageState<string>('table-active', {
+    defaultValue: "",
+    listenStorageChange: true
+  });
 
   useEffect(() => {
     // 计算高度
@@ -19,25 +25,35 @@ export default function TablePanel() {
   }, []);
 
   return (
-    <div className='px-12px overflow-y-auto' ref={contentRef} style={contentStyle}>
+    <div
+      className="px-12px overflow-y-auto"
+      ref={contentRef}
+      style={contentStyle}
+    >
       <div className="search-box flex gap-4px mb-12px">
         <Input placeholder="输入关键字搜索" suffix={<SearchOutlined />} />
-        <Button type="primary" onClick={() => addTable()}>添加表</Button>
+        <Button type="primary" onClick={() => addTable()}>
+          添加表
+        </Button>
         <Button type="primary">导入表</Button>
       </div>
-      {
-        project.tables.map((item) => {
-          return <TableItem data={item} onChange={updateTable} key={item.table.id} active={active} setActive={setActive} />
-        })
-      }
-      {
-        project.tables.length === 0 && (
-          <div className="flex flex-col items-center justify-center h-[300px]">
-            <img src={noData} alt="暂无数据" className="w-[200px] h-[200px]" />
-            <div className="text-gray-400">暂无数据表,快来创建!</div>
-          </div>
-        )
-      }
+      {project.tables.map((item) => {
+        return (
+          <TableItem
+            data={item}
+            onChange={updateTable}
+            key={item.table.id}
+            active={active}
+            setActive={setActive}
+          />
+        );
+      })}
+      {project.tables.length === 0 && (
+        <div className="flex flex-col items-center justify-center h-[300px]">
+          <img src={noData} alt="暂无数据" className="w-[200px] h-[200px]" />
+          <div className="text-gray-400">暂无数据表,快来创建!</div>
+        </div>
+      )}
     </div>
-  )
+  );
 }

+ 6 - 1
apps/er-designer/src/pages/er/index.tsx

@@ -10,12 +10,17 @@ import Navigator from "./components/Navigator";
 import Menu from "./components/Menu";
 import { useModel } from "umi";
 import "./index.less";
+import { useSessionStorageState } from "ahooks";
 
 const { Header, Content, Sider } = Layout;
 
 const App: React.FC = () => {
   const containerRef = React.useRef(null);
   const { initGraph, project } = useModel("erModel");
+  const [tabActiveKey, setTabActiveKey] = useSessionStorageState('tabs-active-key', {
+    defaultValue: "1",
+    listenStorageChange: true
+  });
 
   useEffect(() => {
     if (containerRef.current) {
@@ -82,7 +87,7 @@ const App: React.FC = () => {
               },
             }}
           >
-            <Tabs animated items={tabItems} centered />
+            <Tabs animated activeKey={tabActiveKey} onChange={setTabActiveKey} items={tabItems} centered />
           </ConfigProvider>
         </Sider>
         <Layout>