Explorar o código

feat: 详情编辑器添加导入字段excel表格

liaojiaxing hai 3 meses
pai
achega
96664b550d

+ 61 - 7
apps/er-designer/src/components/ImportResultModal.tsx

@@ -3,8 +3,12 @@ import { message, Modal, Table, Tooltip } from "antd";
 import { ColumnItem } from "@/type";
 import { TableProps } from "antd/lib";
 import { createColumn } from "@/utils";
+import { DataType } from "@/enum";
 
-export default forwardRef(function ImportResultModal(props: { tableId?: string}, ref) {
+export default forwardRef(function ImportResultModal(
+  props: { tableId?: string; onChange: (list: ColumnItem[]) => void },
+  ref
+) {
   const [open, setOpen] = useState(false);
   const [dataSource, setDataSource] = useState<any[]>([]);
   const originData = useRef<ColumnItem[]>([]);
@@ -33,6 +37,10 @@ export default forwardRef(function ImportResultModal(props: { tableId?: string},
       msg += "!编码长度不能超过50";
     }
 
+    if (["id", ""].includes(val)) {
+      msg += "编码不能是预定义字段!";
+    }
+
     return msg;
   };
 
@@ -58,6 +66,12 @@ export default forwardRef(function ImportResultModal(props: { tableId?: string},
         msg = "长度不能超过4000!";
       }
     }
+    if (type !== "Decimal" && val.toString().includes(",")) {
+      msg = "非Decimal类型不能包含逗号!";
+    }
+    if (!/^\d+(,\d+)?$/.test(val.toString())) {
+      msg = "长度必须是数字逗号组成!";
+    }
     return msg;
   };
 
@@ -72,7 +86,7 @@ export default forwardRef(function ImportResultModal(props: { tableId?: string},
         valid = false;
       }
     });
-    if(!valid) {
+    if (!valid) {
       message.error("数据校验失败,请检查数据修改后重新导入!");
       return;
     }
@@ -83,11 +97,51 @@ export default forwardRef(function ImportResultModal(props: { tableId?: string},
       okText: "确认",
       cancelText: "取消",
       onOk: () => {
-        const addList = dataSource.map((item, i) => {
-          const old = originData.current.find((obj) => obj.schemaName === item?.['字段名']);
-          const newColumn = createColumn(props?.tableId, old?.displayOrder || originData.current.length + i + 1);
-          return newColumn;
+        const list = [...originData.current];
+        dataSource.forEach((item, i) => {
+          const data = {
+            schemaName: item["字段名"],
+            type: DataType[item["类型"]] as unknown as DataType,
+            langNameList: [
+              { name: "en", value: item["英文名"] },
+              { name: "zh-CN", value: item["中文名"] },
+            ],
+            isRequired: item["是否必填"] === "是",
+            defaultValue: item["默认值"],
+            memo: item["描述"],
+            maxLength: 0,
+            precision: 0,
+            scale: 0,
+          };
+          if (item["类型"] === "Nvarchar") {
+            data.maxLength = item["长度"];
+          }
+          if (item["类型"] === "Decimal") {
+            const arr = item["长度"].toString().split(",");
+            data.precision = arr?.[0];
+            data.scale = item.arr?.[1];
+          }
+          const index = list.findIndex(
+            (obj) => obj.schemaName === item?.["字段名"]
+          );
+          if (index >= 0) {
+            list[index] = {
+              ...list[index],
+              ...data,
+            };
+          } else {
+            const newColumn = createColumn(
+              props?.tableId,
+              list.length + i + 1
+            );
+            list.push({
+              ...newColumn,
+              ...data,
+            });
+          }
         });
+
+        props.onChange(list);
         setOpen(false);
       },
       onCancel: () => {
@@ -153,7 +207,7 @@ export default forwardRef(function ImportResultModal(props: { tableId?: string},
     >
       {contextHolder}
       <Table
-        key={"字段名"}
+        rowKey={"字段名"}
         scroll={{ y: 400 }}
         columns={columns}
         dataSource={dataSource}

+ 6 - 3
apps/er-designer/src/components/TableEdit.tsx

@@ -318,6 +318,7 @@ export default function TableEdit(props: {
       .then((res) => {
         console.log("加载数据:", res);
         const list = res?.["表单字段"];
+        message.destroy();
         if (!list || !list.length) {
           message.warning("当前文件无字段数据,请检查");
         } else {
@@ -327,15 +328,17 @@ export default function TableEdit(props: {
       .catch((err) => {
         console.error("加载数据失败:", err);
         message.error("文件解析失败");
-      })
-      .finally(() => {
         message.destroy();
       });
   };
 
+  const handleChangeColumn = (list: ColumnItem[]) => {
+    setDataSource(list);
+  }
+
   return (
     <div className="w-full h-full overflow-auto" ref={boxRef}>
-      <ImportResultModal ref={importResultRef} tableId={props?.tableId} />
+      <ImportResultModal ref={importResultRef} tableId={props?.tableId} onChange={handleChangeColumn} />
       <EditableProTable
         columns={columns}
         rowKey="id"

+ 7 - 13
apps/er-designer/src/models/erModel.tsx

@@ -76,19 +76,13 @@ export default function erModel() {
   const timer = useRef<any>();
   const saveData = (info: ProjectInfo) => {
     // 提交服务器
-    setPlayModeEnable(state => {
-      if(!state) {
-        // 清除定时器
-        clearTimeout(timer.current);
-        timer.current = setTimeout(() => {
-          SaveDataModel(info);
-          // 格式化当前时间
-          setSaveTime(dayjs().format("YYYY-MM-DD HH:mm:ss"));
-        }, 500);
-      }
-
-      return !!state;
-    });
+    // 清除定时器
+    clearTimeout(timer.current);
+    timer.current = setTimeout(() => {
+      SaveDataModel(info);
+      // 格式化当前时间
+      setSaveTime(dayjs().format("YYYY-MM-DD HH:mm:ss"));
+    }, 500);
   };
 
   /**

+ 1 - 1
apps/er-designer/src/models/initInfo.ts

@@ -33,7 +33,7 @@ export const initInfo = (info: ProjectInfo) => {
       tableItem.table.style as unknown as string
     );
     tableItem.tableColumnList = tableItem.tableColumnList.sort(
-      (a, b) => (a.displayOrder || 0) - (b.displayOrder || 0)
+      (a, b) => a.isPreDefined ? -1 : (a.displayOrder || 0) - (b.displayOrder || 0)
     );
   });
 

+ 1 - 0
apps/er-designer/src/models/renderer.ts

@@ -78,6 +78,7 @@ export const render = (graph: Graph, project: ProjectInfo) => {
     // 添加关系连线
     const relationEdge = graph?.addEdge({
       id: relation.id,
+      zIndex: 0,
       router: {
         name: "er",
         args: {

+ 20 - 5
apps/er-designer/src/pages/detail/index.tsx

@@ -50,6 +50,7 @@ export default function index() {
   const [isFullscreen, { enterFullscreen, exitFullscreen }] =
     useFullscreen(erRef);
   const [collapsed, setCollapsed] = useState(false);
+  const [seachColumn, setSearchColumn] = useState("");
 
   useEffect(() => {
     insertCss(`
@@ -104,7 +105,7 @@ export default function index() {
       {
         key: "4-1",
         label: "更新用户",
-        children: project?.updatedBy || "-",
+        children: project?.updateByName || "-",
       },
       {
         key: "4",
@@ -178,6 +179,15 @@ export default function index() {
     return project.tables.find((item) => item.table.id === selectKey);
   }, [project, selectKey]);
 
+  const currentColumns = useMemo(() => {
+    return (currentTable?.tableColumnList || []).filter((item) => {
+      if (seachColumn) {
+        return item.langName?.includes(seachColumn);
+      }
+      return true;
+    });
+  }, [currentTable, seachColumn]);
+
   const handleAddTable = (tableItem: TableItemType) => {
     setProject({
       ...project,
@@ -284,7 +294,7 @@ export default function index() {
         </Header>
 
         <Content className="flex-1 overflow-auto flex gap-12px">
-          <div className="left w-300px shrink-0 h-full shadow-sm bg-#fff rounded-8px">
+          <div className="left w-300px shrink-0 h-full shadow-sm bg-#fff rounded-8px overflow-y-auto">
             <div
               className="
               flex 
@@ -351,7 +361,7 @@ export default function index() {
               <div className="right flex gap-8px m-b-12px">
                 {active === 0 ? (
                   <>
-                    <Input placeholder="搜索" suffix={<SearchOutlined />} />
+                    {/* <Input placeholder="搜索" suffix={<SearchOutlined />} /> */}
                     <Button
                       type={showNavigator ? "primary" : "default"}
                       onClick={() => setShowNavigator(!showNavigator)}
@@ -371,7 +381,12 @@ export default function index() {
                   </>
                 ) : (
                   <>
-                    <Input placeholder="搜索" suffix={<SearchOutlined />} />
+                    <Input
+                      placeholder="搜索"
+                      suffix={<SearchOutlined />}
+                      value={seachColumn}
+                      onChange={(e) => setSearchColumn(e.target.value)}
+                    />
                   </>
                 )}
               </div>
@@ -497,7 +512,7 @@ export default function index() {
                   </div>
                   <TableEdit
                     key={selectKey}
-                    data={currentTable?.tableColumnList || []}
+                    data={currentColumns}
                     tableId={currentTable?.table?.id}
                     onChange={handleChangeColumn}
                   />

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

@@ -100,7 +100,7 @@ export default function Menu() {
         },
         { key: "1-4", label: "保存为模版" },
         { key: "1-5", label: "发布模版" },
-        { key: "1-6", label: "同步数据表" },
+        { key: "1-6", label: "同步数据表" },
         {
           key: "1-7",
           label: "导出为图片",
@@ -339,6 +339,14 @@ export default function Menu() {
     }
   };
 
+  const handleAddAfter = (id: any) => {
+    const { origin, pathname } = window.location;
+    const enterpriseCode = sessionStorage.getItem("enterpriseCode");
+    window.open(
+      `${origin}${pathname}#/detail/${id}?enterpriseCode=${enterpriseCode}`
+    );
+  };
+
   return (
     <>
       <div className="flex-1 flex items-center">
@@ -405,7 +413,7 @@ export default function Menu() {
           onChange={(value) => handleChangeSetting("tableWidth", value)}
         />
       </Modal>
-      <AddModel ref={addModelRef}/>
+      <AddModel ref={addModelRef} onChange={handleAddAfter}/>
     </>
   );
 }

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

@@ -1,4 +1,7 @@
-import { DeleteOutlined, HolderOutlined } from "@ant-design/icons";
+import {
+  DeleteOutlined,
+  PlusOutlined,
+} from "@ant-design/icons";
 import {
   Col,
   Row,
@@ -81,7 +84,10 @@ export default function TableItem({
 
   // 添加字段
   const handleAddColumn = () => {
-    const newColumn: ColumnItemType = createColumn(table.id, tableColumnList.length + 1);
+    const newColumn: ColumnItemType = createColumn(
+      table.id,
+      tableColumnList.length + 1
+    );
     onChange({
       table,
       tableColumnList: [...tableColumnList, newColumn],
@@ -276,12 +282,22 @@ export default function TableItem({
             </CustomColorPicker>
             <div className="flex gap-4px">
               {!table.parentBusinessTableId && (
-                <Button type="primary" onClick={handleAddChildTable}>
-                  添加子表
+                <Button
+                  type="text"
+                  className="w-50px"
+                  onClick={handleAddChildTable}
+                  icon={<PlusOutlined />}
+                >
+                  子表
                 </Button>
               )}
-              <Button type="primary" onClick={handleAddColumn}>
-                添加字段
+              <Button
+                type="text"
+                 className="w-50px"
+                onClick={handleAddColumn}
+                icon={<PlusOutlined />}
+              >
+                字段
               </Button>
               <Popconfirm
                 okType="primary"

+ 44 - 4
apps/er-designer/src/pages/er/components/TablePanel.tsx

@@ -1,15 +1,30 @@
-import React, { useEffect } from "react";
-import { Button, Collapse, Input } from "antd";
-import { SearchOutlined, SettingOutlined } from "@ant-design/icons";
+import React, { useEffect, useState } from "react";
+import { Button, Modal, Input } from "antd";
+import { SearchOutlined } from "@ant-design/icons";
 import TableItem from "./TableItem";
 import { useModel } from "umi";
 import noData from "@/assets/no-data.png";
+import TableEdit from "@/components/TableEdit";
+import { ColumnItem, TableItemType } from "@/type";
 export default function TablePanel() {
-  const { project, updateTable, addTable, tableActive, setTableActive } = useModel("erModel");
+  const { project, updateTable, addTable, tableActive, setTableActive, graph } =
+    useModel("erModel");
   const contentRef = React.useRef<HTMLDivElement>(null);
   const [contentStyle, setContentStyle] = React.useState<React.CSSProperties>(
     {}
   );
+  const [tableData, setTableData] = React.useState<TableItemType>();
+  const [open, setOpen] = useState(false);
+
+  useEffect(() => {
+    graph?.on("node:dblclick", (args) => {
+      const data = args.node.getData();
+      if (data?.isTable) {
+        setOpen(true);
+        setTableData(data);
+      }
+    });
+  }, [graph]);
 
   useEffect(() => {
     // 计算高度
@@ -18,6 +33,15 @@ export default function TablePanel() {
     });
   }, []);
 
+  const handleChangeTableColumns = (columnList: readonly ColumnItem[]) => {
+    if (tableData) {
+      updateTable({
+        ...tableData,
+        tableColumnList: columnList as ColumnItem[],
+      });
+    }
+  };
+
   return (
     <div
       className="px-12px overflow-y-auto"
@@ -48,6 +72,22 @@ export default function TablePanel() {
           <div className="text-gray-400">暂无数据表,快来创建!</div>
         </div>
       )}
+      <Modal
+        title="字段详情"
+        width={"80%"}
+        open={open}
+        onCancel={() => {
+          setOpen(false);
+          setTableData(undefined);
+        }}
+      >
+        <TableEdit
+          tableId={tableData?.table?.id}
+          data={tableData?.tableColumnList || []}
+          modelId={project.id}
+          onChange={handleChangeTableColumns}
+        />
+      </Modal>
     </div>
   );
 }

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

@@ -1,5 +1,5 @@
 import React, { useEffect, useState } from "react";
-import { Card, Dropdown, Modal, Input, message } from "antd";
+import { Card, Dropdown, Modal, Input, message, Tooltip } from "antd";
 import defaultImg from "@/assets/image/default.png"
 import { GetFile, DeleteDataModel, SaveDataModel } from "@/api";
 
@@ -136,11 +136,11 @@ export default function ProjectCard({
       <Card.Meta
         title={
           <span className="flex items-center justify-between">
-            <span className="flex-1 tru ">{record.name}</span>
-            <span className="text-12px font-normal color-#999">更新:{record.updateTime}</span>
+            <Tooltip title={record.name}><span className="flex-1 truncate ">{record.name}</span></Tooltip>
+            <span className="text-12px font-normal color-#999">更新:{record.updateTime}</span>
           </span>
         }
-        description={<span className="block truncate">{record.description || '暂无描述'}</span>}
+        description={<span className="block truncate"><Tooltip title={record.description}>{record.description || '暂无描述'}</Tooltip></span>}
       />
     </Card>
   );

+ 2 - 2
apps/er-designer/src/type.d.ts

@@ -165,8 +165,8 @@ export interface ProjectInfo {
   createdBy?: string;
   createdByName?: string;
   // 更新者
-  updatedBy?: string;
-  updatedByName?: string;
+  updateBy?: string;
+  updateByName?: string;
   // 更新时间
   updateTime?: string;
   // 模型说明