Ver código fonte

feat: 整理详情内容

liaojiaxing 3 meses atrás
pai
commit
ce555b5539

+ 14 - 0
apps/er-designer/src/api/index.ts

@@ -28,6 +28,20 @@ export const ListLangBySearchKey = (data: {
   });
 };
 
+/**
+ * 根据key查询多语言
+ * @param data {key: string}
+ * @returns
+ */
+export const ListLangByKey = (data: {
+  key: string;
+}) => {
+  return request("/api/system/ListLangByKey", {
+    method: "POST",
+    data,
+  });
+};
+
 /**
  * 获取表格字段列表
  * @param data 

+ 20 - 6
apps/er-designer/src/components/NoticeNode.tsx

@@ -13,11 +13,23 @@ const NoticeNode = ({ node, graph }: { node: Node; graph: Graph }) => {
   const [_tabActiveKey, setTabActiveKey] =
     useSessionStorageState("tabs-active-key");
   const [_, setRemarkActive] = useSessionStorageState("remark-active");
+  const [playModeEnable] = useSessionStorageState(
+    "playModeEnable",
+    {
+      listenStorageChange: true,
+    }
+  );
   const handleEdit = () => {
     setTabActiveKey("4");
     setRemarkActive(id);
   };
 
+  const [content, setContent] = useState(text);
+
+  useEffect(() => {
+    setContent(text);
+  }, [text]);
+
   const strokeWidth = 1;
   return (
     <>
@@ -61,7 +73,7 @@ const NoticeNode = ({ node, graph }: { node: Node; graph: Graph }) => {
         <div className="absolute w-full h-full flex flex-col">
           <div className="color-#333 px-20px py-4px flex items-center justify-between">
             <span className="truncate leading-22px">{name}</span>
-            {showEdit && (
+            {showEdit && !playModeEnable && (
               <div
                 className="edit-btn w-22px h-22px rounded-md flex items-center justify-center bg-#658dbe cursor-pointer"
                 onClick={handleEdit}
@@ -73,14 +85,16 @@ const NoticeNode = ({ node, graph }: { node: Node; graph: Graph }) => {
           <Input.TextArea
             variant="borderless"
             className="w-full resize-none! flex-1 color-#666"
-            value={text}
+            value={content}
             key={id}
-            onChange={(e) =>
+            readOnly={!!playModeEnable}
+            onChange={(e) => setContent(e.target.value)}
+            onBlur={() => {
               node.prop("update:remark", {
                 ...node.getData(),
-                text: e.target.value,
-              })
-            }
+                text: content,
+              });
+            }}
           />
         </div>
       </div>

+ 92 - 56
apps/er-designer/src/components/TableEdit.tsx

@@ -1,4 +1,4 @@
-import React from "react";
+import React, { useEffect } from "react";
 import { EditableProTable, ProColumns } from "@ant-design/pro-components";
 import type { ColumnItem } from "@/type";
 import { createColumn } from "@/utils";
@@ -8,13 +8,22 @@ import { Button, Input, InputNumber } from "antd";
 import LangInput from "./LangInput";
 import { validateColumnCode } from "@/utils/validator";
 import VariableModal from "./VariableModal";
-export default function TableEdit(props: { tableId?: string; data: any[] }) {
+import { FormInstance } from "antd/lib";
+export default function TableEdit(props: {
+  tableId?: string;
+  data: any[];
+  modelId?: string;
+  onChange?: (data: readonly ColumnItem[]) => void;
+}) {
   const [editableKeys, setEditableRowKeys] = React.useState<React.Key[]>([]);
   const [dataSource, setDataSource] = React.useState<readonly ColumnItem[]>(
     props.data
   );
   const boxRef = React.useRef<HTMLDivElement>(null);
 
+  useEffect(() => {
+    props.onChange?.(dataSource);
+  }, [dataSource]);
   const DefaultValueComp = ({
     value,
     onChange,
@@ -32,23 +41,61 @@ export default function TableEdit(props: { tableId?: string; data: any[] }) {
           }}
         />
         <div>
-        <VariableModal
-          trigger={
-            <Button size="small" style={{ width: 40, fontSize: 12 }} type="text">
-              +变量
-            </Button>
-          }
-          onOk={(val) => onChange?.(val)}
-        />
-        <Button size="small" style={{ width: 40, fontSize: 12 }} type="text">
-          +字段
-        </Button>
+          <VariableModal
+            trigger={
+              <Button
+                size="small"
+                style={{ width: 40, fontSize: 12 }}
+                type="text"
+              >
+                +变量
+              </Button>
+            }
+            onOk={(val) => onChange?.(val)}
+          />
+          <Button size="small" style={{ width: 40, fontSize: 12 }} type="text">
+            +字段
+          </Button>
         </div>
-        
       </div>
     );
   };
 
+  const LengthComp = ({
+    value,
+    onChange,
+    model,
+    form,
+    rowKey,
+  }: {
+    value?: string;
+    onChange?: (value: string) => void;
+    model: ColumnItem;
+    form: FormInstance;
+    rowKey?: React.Key | React.Key[];
+  }) => {
+    return (
+      <span className="flex gap-2px">
+        <InputNumber
+          min={0}
+          placeholder="总长度"
+          defaultValue={model.precision}
+          onChange={(value) =>
+            form.setFieldValue([rowKey || "", "precision"], value)
+          }
+        />
+        <InputNumber
+          min={0}
+          placeholder="小数位数"
+          defaultValue={model.scale}
+          onChange={(value) =>
+            form.setFieldValue([rowKey || "", "scale"], value)
+          }
+        />
+      </span>
+    );
+  };
+
   const columns: ProColumns[] = [
     {
       title: "字段代码",
@@ -71,16 +118,24 @@ export default function TableEdit(props: { tableId?: string; data: any[] }) {
     },
     {
       title: "字段名称",
-      dataIndex: "alignment",
+      dataIndex: "langNameList",
       valueType: "text",
       width: 80,
+      render: (_dom, entity) => {
+        return (
+          entity.langNameList?.find(
+            (item: Record<string, string>) => item.name === "zh-CN"
+          )?.value || "-"
+        );
+      },
       renderFormItem: (_schema, config, form) => {
         const model = config.record;
+        const rowKey = config.recordKey;
         return (
           <LangInput
             value={model.langNameList}
             onChange={(langValue) =>
-              form.setFieldValue("langNameList", langValue)
+              form.setFieldValue([rowKey || "", "langNameList"], langValue)
             }
           />
         );
@@ -91,8 +146,15 @@ export default function TableEdit(props: { tableId?: string; data: any[] }) {
       dataIndex: "type",
       valueType: "select",
       width: 120,
-      fieldProps: {
-        options: DATA_TYPE_OPTIONS,
+      fieldProps: (form, { rowKey }) => {
+        return {
+          options: DATA_TYPE_OPTIONS,
+          onChange: () => {
+            form.setFieldValue([rowKey || "", "maxLength"], undefined);
+            form.setFieldValue([rowKey || "", "scale"], undefined);
+            form.setFieldValue([rowKey || "", "precision"], undefined);
+          },
+        };
       },
       formItemProps: {
         rules: [
@@ -101,7 +163,7 @@ export default function TableEdit(props: { tableId?: string; data: any[] }) {
             message: "请选择类型",
           },
         ],
-      }
+      },
     },
     {
       title: "长度",
@@ -111,39 +173,20 @@ export default function TableEdit(props: { tableId?: string; data: any[] }) {
       fieldProps: {
         precision: 0,
       },
-      render: (text, record, index) => {
+      render: (text, record) => {
         return record.type === DataType.Decimal
           ? `${record.precision},${record.scale}`
           : text;
       },
-      renderFormItem: (schema, config, form) => {
+      renderFormItem: (_schema, config, form) => {
         const model = config.record;
+        const rowKey = config.recordKey;
         return model.type === DataType.Nvarchar ? (
-          <InputNumber
-            min={0}
-            max={255}
-            value={model.maxLength}
-            onChange={(value) => form.setFieldValue("maxLength", value)}
-          />
+          <InputNumber min={0} placeholder="字符长度" />
         ) : model.type === DataType.Decimal ? (
-          <span className="flex gap-2px">
-            <InputNumber
-              min={0}
-              max={20}
-              placeholder="总长度"
-              value={model.precision}
-              onChange={(value) => form.setFieldValue("precision", value)}
-            />
-            <InputNumber
-              min={0}
-              max={19}
-              placeholder="小数位数"
-              value={model.scale}
-              onChange={(value) => form.setFieldValue("scale", value)}
-            />
-          </span>
+          <LengthComp model={model} form={form} rowKey={rowKey} />
         ) : (
-          <>-</>
+          "-"
         );
       },
     },
@@ -203,7 +246,7 @@ export default function TableEdit(props: { tableId?: string; data: any[] }) {
       title: "操作",
       valueType: "option",
       width: 120,
-      render: (text, record, _, action) =>
+      render: (_text, record, _, action) =>
         record.isPreDefined
           ? []
           : [
@@ -234,7 +277,7 @@ export default function TableEdit(props: { tableId?: string; data: any[] }) {
   };
 
   return (
-    <div className="w-full h-full overflow-hidden" ref={boxRef}>
+    <div className="w-full h-full overflow-auto" ref={boxRef}>
       <EditableProTable
         columns={columns}
         rowKey="id"
@@ -243,19 +286,12 @@ export default function TableEdit(props: { tableId?: string; data: any[] }) {
         recordCreatorProps={{
           record: handleAdd,
         }}
-        pagination={{
-          total: 10,
-          pageSize: 10,
-          onChange: (page, pageSize) => {
-            console.log(page, pageSize);
-          },
-        }}
         editable={{
           type: "multiple",
           editableKeys,
-          onSave: async (rowKey, data, row) => {
-            console.log(rowKey, data, row);
-          },
+          // onSave: async (rowKey, data, row) => {
+          //   console.log(rowKey, data, row, dataSource);
+          // },
           onChange: setEditableRowKeys,
         }}
       />

+ 12 - 4
apps/er-designer/src/components/TableNode.tsx

@@ -12,6 +12,12 @@ function TableNode({ node, graph }: { node: Node; graph: Graph }) {
   const [_tabActiveKey, setTabActiveKey] =
     useSessionStorageState("tabs-active-key");
   const [_active, setTableActive] = useSessionStorageState('table-active');
+  const [playModeEnable] = useSessionStorageState(
+      "playModeEnable",
+      {
+        listenStorageChange: true,
+      }
+    );
 
   useEffect(() => {
     const container = containerRef.current;
@@ -75,7 +81,6 @@ function TableNode({ node, graph }: { node: Node; graph: Graph }) {
 
     tableColumnList.forEach((item, index) => {
       if (!ports.find((port) => port.id?.includes(item.id))) {
-        console.log("addPort", item);
         node.addPort({
           id: item.id + "_port1",
           group: "columnPort",
@@ -140,8 +145,11 @@ function TableNode({ node, graph }: { node: Node; graph: Graph }) {
     setTableActive(node.id);
   };
 
+  const tableName = table.langNameList?.find((item) => item.lang === "zh-CN")?.value;
+
   const ColumnItem = ({ record }: { record: ColumnItem }) => {
     const type = DATA_TYPE_OPTIONS.find((item) => item.value === record.type);
+    const columnName = record.langNameList?.find((item) => item.lang === "zh-CN")?.value;
     return (
       <div
         className="w-full flex py-4px px-8px"
@@ -151,7 +159,7 @@ function TableNode({ node, graph }: { node: Node; graph: Graph }) {
           <span className="flex items-center">
             <span className=" w-6px h-6px rounded-full mr-4px  inline-block cursor-pointer" />
             {record.schemaName}
-            {record.cn_name ? `(${record.cn_name})` : ""}
+            {columnName ? `(${columnName})` : ""}
           </span>
           <span>
             {record.isUnique ? (
@@ -202,9 +210,9 @@ function TableNode({ node, graph }: { node: Node; graph: Graph }) {
       >
         <div className="truncate flex-1">
           <span className="text-12px font-normal">{table.parentBusinessTableId && '[子]'}</span>
-          {table.schemaName}({table.cn_name})
+          {table.schemaName}({tableName})
         </div>
-        {showEdit && (
+        {showEdit && !playModeEnable && (
           <div
             className="edit-btn w-22px h-22px rounded-md flex items-center justify-center bg-#658dbe cursor-pointer"
             onClick={handleEdit}

+ 7 - 1
apps/er-designer/src/components/TopicNode.tsx

@@ -9,6 +9,12 @@ const TopicAreaNode = ({ node, graph }: { node: Node; graph: Graph }) => {
   const [showEdit, setShowEdit] = React.useState(false);
   const [_tabActiveKey, setTabActiveKey] =
     useSessionStorageState("tabs-active-key");
+  const [playModeEnable] = useSessionStorageState(
+      "playModeEnable",
+      {
+        listenStorageChange: true,
+      }
+    );
   const handleEdit = () => {
     setTabActiveKey("3");
   };
@@ -28,7 +34,7 @@ const TopicAreaNode = ({ node, graph }: { node: Node; graph: Graph }) => {
     >
       <div className="color-#fff flex items-center justify-between leading-22px">
         {name}{" "}
-        {showEdit && (
+        {showEdit && !playModeEnable && (
           <div
             className="edit-btn w-22px h-22px rounded-md flex items-center justify-center bg-#658dbe cursor-pointer"
             onClick={handleEdit}

+ 15 - 34
apps/er-designer/src/models/erModel.tsx

@@ -8,7 +8,6 @@ import { Export } from "@antv/x6-plugin-export";
 import { Selection } from "@antv/x6-plugin-selection";
 import { SaveDataModel } from "@/api";
 import { useFullscreen, useSessionStorageState } from "ahooks";
-import { throttle } from "lodash-es";
 import { createTable, uuid } from "@/utils";
 import dayjs from "dayjs";
 
@@ -23,6 +22,7 @@ import type {
 import { RelationLineType } from "@/enum";
 import { render } from "./renderer";
 import { DEFAULT_SETTING } from "@/constants";
+import { initInfo } from "./initInfo";
 
 import "@/components/TableNode";
 import "@/components/TopicNode";
@@ -96,29 +96,7 @@ export default function erModel() {
     if (isInit && typeof info === "object" && typeof info !== null) {
       historyRef.current = [];
       activeIndex.current = 0;
-      // 配置
-      info.setting = info?.setting
-        ? JSON.parse(info.setting as unknown as string)
-        : { ...DEFAULT_SETTING };
-      // json字符串转换
-      info.tables.forEach(tableItem => {
-        tableItem.table.style = JSON.parse(tableItem.table.style as unknown as string);
-      });
-      info.relations.forEach(relationItem => {
-        relationItem.style = JSON.parse(
-          relationItem.style as unknown as string
-        );
-      });
-      info.topicAreas.forEach(topicAreaItem => {
-        topicAreaItem.style = JSON.parse(
-          topicAreaItem.style as unknown as string
-        );
-      });
-      info.remarkInfos.forEach(remarkItem => {
-        remarkItem.style = JSON.parse(
-          remarkItem.style as unknown as string
-        );
-      });
+      initInfo(info);
     }
 
     if (info && typeof info === "function") {
@@ -174,6 +152,7 @@ export default function erModel() {
     width?: number,
     height?: number
   ) => {
+    graphRef.current?.dispose?.();
     const instance = new Graph({
       container,
       width: width || document.documentElement.clientWidth,
@@ -296,8 +275,8 @@ export default function erModel() {
 
     instance.on(
       "node:moved",
-      throttle((args) => {
-        console.log("moved", args);
+      (args) => {
+        const position = args.node.position();
         const data = args.node.data;
         if (data.isTable) {
           updateTable({
@@ -306,8 +285,8 @@ export default function erModel() {
               ...data.table,
               style: {
                 ...data.table.style,
-                x: args.x,
-                y: args.y,
+                x: position.x,
+                y: position.y,
               },
             },
           });
@@ -317,8 +296,8 @@ export default function erModel() {
             ...data,
             style: {
               ...data.style,
-              x: args.x,
-              y: args.y,
+              x: position.x,
+              y: position.y,
             },
           });
         }
@@ -327,12 +306,12 @@ export default function erModel() {
             ...data,
             style: {
               ...data.style,
-              x: args.x,
-              y: args.y,
+              x: position.x,
+              y: position.y,
             },
           });
         }
-      }, 500)
+      }
     );
 
     instance.bindKey("ctrl+z", onUndo);
@@ -463,6 +442,7 @@ export default function erModel() {
     const newTopicArea = {
       isTopicArea: true,
       id: topicAreaId,
+      dataModelId: project.id,
       name: "主题域_" + (project.topicAreas.length + 1),
       style: {
         background: "#175e7a",
@@ -515,6 +495,7 @@ export default function erModel() {
       id: remarkId,
       name: "备注_" + (project.remarkInfos.length + 1),
       text: "",
+      dataModelId: project.id,
       style: {
         x: 300,
         y: 300,
@@ -629,7 +610,7 @@ export default function erModel() {
       },
     };
     setProject((state) => {
-      const obj = getRelations(state, newRelation);
+      const obj = getRelations(state, {...newRelation, dataModelId: state.id});
       if (obj.canAdd) {
         return {
           ...state,

+ 43 - 0
apps/er-designer/src/models/initInfo.ts

@@ -0,0 +1,43 @@
+import { ProjectInfo } from "@/type";
+import { DEFAULT_SETTING } from "@/constants";
+
+export const initInfo = (info: ProjectInfo) => {
+  // 配置
+  info.setting = info?.setting
+    ? JSON.parse(info.setting as unknown as string)
+    : { ...DEFAULT_SETTING };
+  
+  info.tables.forEach((tableItem) => {
+    // 名称多语言
+    tableItem.table.langNameList = [
+      { name: 'en', value: tableItem.table?.enName || ''},
+      { name: 'zh-CN', value: tableItem.table?.cnName || ''},
+    ];
+    // 描述多语言
+    tableItem.table.langDescriptionList = [
+      { name: 'en', value: tableItem.table?.enDescription || ''},
+      { name: 'zh-CN', value: tableItem.table?.cnDescription || ''},
+    ];
+    // 字段处理
+    tableItem.tableColumnList.forEach((columnItem) => {
+      // 名称多语言
+      columnItem.langNameList = [
+        { name: 'en', value: columnItem?.enName || ''},
+        { name: 'zh-CN', value: columnItem?.cnName || ''},
+      ];
+    });
+    tableItem.table.style = JSON.parse(
+      tableItem.table.style as unknown as string
+    );
+  });
+  // json字符串转换
+  info.relations.forEach((relationItem) => {
+    relationItem.style = JSON.parse(relationItem.style as unknown as string);
+  });
+  info.topicAreas.forEach((topicAreaItem) => {
+    topicAreaItem.style = JSON.parse(topicAreaItem.style as unknown as string);
+  });
+  info.remarkInfos.forEach((remarkItem) => {
+    remarkItem.style = JSON.parse(remarkItem.style as unknown as string);
+  });
+};

+ 5 - 2
apps/er-designer/src/models/renderer.ts

@@ -190,6 +190,7 @@ export const render = (graph: Graph, project: ProjectInfo) => {
       const cell = graph.getCellById(tableItem.table.id);
       if (cell?.isNode()) {
         cell.setSize(project.setting.tableWidth, cell.size().height);
+        cell.setPosition(tableItem.table.style?.x, tableItem.table.style?.y);
         cell.setData(tableItem);
       }
     }
@@ -199,8 +200,9 @@ export const render = (graph: Graph, project: ProjectInfo) => {
       renderTopicArea(topicArea);
     } else {
       const cell = graph.getCellById(topicArea.id);
-      if (cell) {
+      if (cell?.isNode()) {
         cell.setData(topicArea);
+        cell.setPosition(topicArea.style?.x, topicArea.style?.y);
       }
     }
   });
@@ -209,8 +211,9 @@ export const render = (graph: Graph, project: ProjectInfo) => {
       renderRemark(remark);
     } else {
       const cell = graph.getCellById(remark.id);
-      if (cell) {
+      if (cell?.isNode()) {
         cell.setData(remark);
+        cell.setPosition(remark.style?.x, remark.style?.y);
       }
     }
   });

+ 44 - 12
apps/er-designer/src/pages/detail/index.tsx

@@ -10,23 +10,24 @@ import {
   Spin,
 } from "antd";
 import type { DescriptionsProps, MenuProps } from "antd";
-import { PlusOutlined, SearchOutlined } from "@ant-design/icons";
+import { DownOutlined, PlusOutlined, SearchOutlined } from "@ant-design/icons";
 import TableEdit from "@/components/TableEdit";
 import ER from "./components/ER";
 import AddTable from "./components/AddTable";
 import { useModel, history, useRequest, useParams } from "umi";
 import { GetDataModelDetail } from "@/api";
 import NoData from "@/assets/no-data.png";
-import { ProjectInfo, TableItemType } from "@/type";
+import { ColumnItem, ProjectInfo, TableItemType } from "@/type";
 import { useFullscreen } from "ahooks";
 import AddModel from "@/components/AddModel";
+import insertCss from "insert-css";
 
 const { Content, Header } = Layout;
 export default function index() {
   const [active, setActive] = useState(0);
   const [showNavigator, setShowNavigator] = useState(true);
   const addTableRef = useRef<{ open: () => void }>();
-  const { project, setProject, setPlayModeEnable, exitPlayMode, graph } =
+  const { project, setProject, setPlayModeEnable, exitPlayMode, updateTable } =
     useModel("erModel");
   const [searchKeyword, setSearchKeyword] = useState("");
   const [selectKey, setSelectKey] = useState<string>(
@@ -36,6 +37,15 @@ export default function index() {
   const addModelRef = useRef<{ edit: (info: ProjectInfo) => void }>();
   const [isFullscreen, { enterFullscreen, exitFullscreen }] =
     useFullscreen(erRef);
+  const [collapsed, setCollapsed] = useState(false);
+
+  useEffect(() => {
+    insertCss(`
+      .ant-descriptions-header {
+        margin-bottom: ${collapsed ? "0 !important" : "20px !important"};
+      }
+    `);
+  }, [collapsed]);
 
   useEffect(() => {
     setPlayModeEnable(true);
@@ -48,12 +58,9 @@ export default function index() {
     onSuccess: (res) => {
       console.log("模型详情:", res);
       const result = res?.result;
+      setSelectKey(result?.tables?.[0]?.table?.id || "");
       if (result) {
-        setProject(
-          result,
-          false,
-          true
-        );
+        setProject(result, false, true);
       }
     },
   });
@@ -169,6 +176,14 @@ export default function index() {
     history.push(`/er/${project.id}?enterpriseCode=${enterpriseCode}`);
   };
 
+  // 修改表格字段
+  const handleChangeColumn = (columns: readonly ColumnItem[]) => {
+    currentTable && updateTable({
+      ...currentTable,
+      tableColumnList: [...columns]
+    })
+  }
+
   const extra = (
     <div className="flex gap-12px">
       <a>
@@ -211,10 +226,16 @@ export default function index() {
                 <svg className="iconfont w-14px h-14px m-r-4px">
                   <use xlinkHref="#icon-shujumoxing" />
                 </svg>
-                模型详情
+                {project?.name || "-"}
+                <Button
+                  type="text"
+                  className={collapsed ? "rotate-180" : ""}
+                  icon={<DownOutlined />}
+                  onClick={() => setCollapsed(!collapsed)}
+                />
               </span>
             }
-            items={descItems}
+            items={collapsed ? [] : descItems}
             extra={extra}
           ></Descriptions>
         </Header>
@@ -315,7 +336,7 @@ export default function index() {
             <div className="content w-full flex-1 overflow-auto">
               {active === 0 ? (
                 <div
-                  className="er w-full h-full bg-#ccc overflow-hidden"
+                  className="er w-full h-full bg-#ccc overflow-auto"
                   ref={erRef}
                 >
                   <ER
@@ -326,7 +347,18 @@ export default function index() {
                   />
                 </div>
               ) : (
-                <TableEdit data={currentTable?.tableColumnList || []} />
+                <div>
+                  <div className="p-y-10px p-l-20px">
+                    <span className="font-bold">当前表格:</span>
+                    {currentTable?.table.schemaName}
+                  </div>
+                  <TableEdit
+                    key={selectKey}
+                    data={currentTable?.tableColumnList || []}
+                    tableId={currentTable?.table?.id}
+                    onChange={handleChangeColumn}
+                  />
+                </div>
               )}
             </div>
           </div>

+ 7 - 2
apps/er-designer/src/pages/er/components/ColumnItem.tsx

@@ -16,7 +16,6 @@ import { DATA_TYPE_OPTIONS } from "@/constants";
 import { useSortable } from "@dnd-kit/sortable";
 import { CSS } from "@dnd-kit/utilities";
 import LangInput from "@/components/LangInput";
-import { validateColumnCode } from "@/utils/validator";
 
 export default function ColumnItem({
   column,
@@ -36,6 +35,8 @@ export default function ColumnItem({
       },
     });
 
+  const [open, setOpen] = React.useState(false);
+
   const styles = {
     transform: CSS.Transform.toString(transform),
     transition,
@@ -48,6 +49,8 @@ export default function ColumnItem({
     }
     const regex = /^[a-z][a-z0-9_]*$/;
     if (!regex.test(val)) return "编码只能包含字母和数字, 必须小写字母开头!";
+    setOpen(false);
+    return false;
   };
 
   return (
@@ -69,7 +72,9 @@ export default function ColumnItem({
           title={
             <span className="text-red">{validMsg(column.schemaName)}</span>
           }
-          trigger={["focus"]}
+          open={open}
+          onOpenChange={(o) => setOpen(o && !!validMsg(column.schemaName))}
+          trigger={['focus']}
         >
           <Input
             placeholder="编码"

+ 2 - 3
apps/er-designer/src/pages/er/components/Navigator.tsx

@@ -9,12 +9,11 @@ export default function Navigator() {
     defaultValue: true,
     listenStorageChange: true,
   });
-  const miniMap = React.useRef<any>();
 
   useEffect(() => {
     if (graph && mapRef.current) {
-      if(miniMap.current) return;
-      miniMap.current = graph.use(
+      console.log('mini map');
+      graph.use(
         new MiniMap({
           container: mapRef.current,
           width: mapRef.current.offsetWidth || 300,

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

@@ -145,8 +145,8 @@ export default function TableItem({
         m-b-[10px]"
         onClick={() => setActive(active === table.id ? "" : table.id)}
       >
-        <div className="font-bold truncate">
-          {table.schemaName}({table.langName})
+        <div className="font-bold truncate flex-1">
+          {table.schemaName}({table?.langNameList?.find(item => item.name === 'zh-CN')?.value})
         </div>
         <div>
           <Popover

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

@@ -46,6 +46,7 @@ const App: React.FC = () => {
   });
 
   useEffect(() => {
+    exitPlayMode();
     if (containerRef.current) {
       initGraph(containerRef.current);
     }

+ 4 - 4
apps/er-designer/src/pages/home/All.tsx

@@ -211,7 +211,6 @@ export default function All({
     {
       key: "2",
       label: <span className="ml-4px">添加模型</span>,
-      // icon: <Icon icon="local:flow" width="22px" />,
       onClick: async () => {
         addModelRef.current?.open(type);
       },
@@ -321,6 +320,7 @@ export default function All({
         pageHeaderRender={() => <div className="m-t-12px"></div>}
         title={false}
         footer={[]}
+        loading={loading}
       >
         <div className="flex justify-between items-center m-b-12px">
           <Breadcrumb items={breadcrumbData} />
@@ -555,12 +555,12 @@ export default function All({
                     dataIndex: "name",
                   },
                   {
-                    title: "类型",
-                    dataIndex: "type",
+                    title: "描述",
+                    dataIndex: "description",
                   },
                   {
                     title: "修改时间",
-                    dataIndex: "updatedTime",
+                    dataIndex: "updateTime",
                     sorter: (a, b) => a.updateTime - b.updateTime,
                   },
                 ]}

+ 10 - 0
apps/er-designer/src/type.d.ts

@@ -38,6 +38,8 @@ export interface ColumnItem {
   langNameList: Record<string, string>[];
   // 字符集
   chartset?: string;
+  cnName?: string;
+  enName?: string;
 }
 
 /**
@@ -59,6 +61,10 @@ export interface ViewTable {
   langName: string;
   langNameList?: Record<string, string>[];
   langDescriptionList?: Record<string, string>[];
+  cnName?: string;
+  enName?: string;
+  enDescription?: string;
+  cnDescription?: string;
 }
 
 /**
@@ -80,6 +86,7 @@ export interface ColumnRelation {
   relationType: 1 | 2 | 3;
   // 连线样式
   style: Record<string, any>;
+  dataModelId?: string;
 }
 
 /**
@@ -91,6 +98,7 @@ export interface TodoItem {
   text: string;
   isDone: boolean;
   level: 0 | 1 | 2 | 3; // 0 默认 1 一般 2 紧急 3 最高
+  dataModelId?: string;
 }
 
 /**
@@ -105,6 +113,7 @@ export interface TopicAreaInfo {
   style: Record<string, any>;
   // 主题区域
   isTopicArea: boolean;
+  dataModelId?: string;
 }
 
 /**
@@ -125,6 +134,7 @@ export interface RemarkInfo {
     background: string;
   };
   isRemark: boolean;
+  dataModelId?: string;
 }
 
 /**

+ 3 - 3
apps/er-designer/src/utils/index.ts

@@ -62,9 +62,9 @@ export const createColumn = (tableId?: string): ColumnItem => {
     id: uuid(),
     schemaName: "",
     type: DataType.Nvarchar,
-    maxLength: 100,
-    precision: 0,
-    scale: 0,
+    maxLength: undefined,
+    precision: undefined,
+    scale: undefined,
     isRequired: false,
     isUnique: false,
     isPreDefined: false,