Selaa lähdekoodia

feat: 模型详情创建表格弹窗

liaojiaxing 4 kuukautta sitten
vanhempi
commit
80b604dc43

+ 1 - 1
apps/er-designer/.umirc.ts

@@ -24,7 +24,7 @@ export default defineConfig({
   scripts: [
     // 字体加载
     // '//ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js'
-    '//at.alicdn.com/t/c/font_4767192_fqfnpnz3yj.js'
+    '//at.alicdn.com/t/c/font_4767192_wzcidzyqjen.js'
   ],
   plugins: [
     require.resolve('@umijs/plugins/dist/unocss'),

+ 3 - 3
apps/er-designer/src/components/LangInput.tsx

@@ -13,8 +13,8 @@ export default function LangInput({
   onChange,
   disabled
 }: {
-  value: Record<string, string>[];
-  onChange: (value: Record<string, string>[], key?: string) => void;
+  value?: Record<string, string>[];
+  onChange?: (value: Record<string, string>[], key?: string) => void;
   disabled?: boolean;
 }) {
   const [lanOptions, setLanOptions] = React.useState<any[]>([]);
@@ -66,7 +66,7 @@ export default function LangInput({
   };
 
   useEffect(() => {
-    onChange([
+    onChange?.([
       { name: 'en', value: formModel.en},
       { name: 'zh-CN', value: formModel["zh-CN"]},
     ], formModel.langText);

+ 3 - 3
apps/er-designer/src/components/LangInputTextarea.tsx

@@ -12,8 +12,8 @@ export default function LangInputTextarea({
   value,
   onChange,
 }: {
-  value: Record<string, string>[];
-  onChange: (value: Record<string, string>[], key?: string) => void;
+  value?: Record<string, string>[];
+  onChange?: (value: Record<string, string>[], key?: string) => void;
 }) {
   const [lanOptions, setLanOptions] = React.useState<any[]>([]);
   const [formModel, setFormModel] = React.useState({
@@ -64,7 +64,7 @@ export default function LangInputTextarea({
   };
 
   useEffect(() => {
-    onChange([
+    onChange?.([
       { name: 'en', value: formModel.en},
       { name: 'zh-CN', value: formModel["zh-CN"]},
     ], formModel.langText);

+ 5 - 3
apps/er-designer/src/models/erModel.tsx

@@ -21,9 +21,10 @@ import type {
   TopicAreaInfo,
 } from "@/type";
 import { createColumn, uuid } from "@/utils";
-import { DataType, RelationLineType, RelationType } from "@/enum";
+import { DataType, RelationLineType, RelationType, TableType } from "@/enum";
 import { render } from "./renderer";
 import { useSessionStorageState } from "ahooks";
+import { useSearchParams } from "umi";
 
 import "@/components/TableNode";
 import "@/components/TopicNode";
@@ -337,8 +338,9 @@ export default function erModel() {
     const area = graphRef.current?.getGraphArea();
     const x = area?.center.x || 300;
     const y = area?.center.y || 300;
-    // todo 获取表类型
-    const newTable = createTable(3, parentId);
+    // 数据表类型动态路由传参
+    const [searchParams] = useSearchParams();
+    const newTable = createTable(searchParams.get('type') as unknown as TableType || 3, parentId);
     newTable.table.style.x = x;
     newTable.table.style.y = y;
 

+ 144 - 7
apps/er-designer/src/pages/detail/components/AddTable.tsx

@@ -1,9 +1,146 @@
-import React from 'react'
+import { forwardRef, useImperativeHandle, useRef, useState } from "react";
+import { Col, Form, Input, Modal, Row, Select, Tabs, TabsProps } from "antd";
+import LangInput from "@/components/LangInput";
+import LangInputTextarea from "@/components/LangInputTextarea";
+import { TableType } from "@/enum";
+import { createTable } from "@/utils";
+import { TableItemType, ViewTable } from "@/type";
+import { useSearchParams } from "umi";
+
+export default forwardRef(function AddTable(
+  props: {
+    onChange: (value: TableItemType) => void;
+  },
+  ref
+) {
+  const [open, setOpen] = useState(false);
+  const tableItemRef = useRef<TableItemType>();
+  const [searchParams] = useSearchParams();
+  const [tabActiveKey, setTabActiveKey] = useState("1");
+  useImperativeHandle(ref, () => ({
+    open: () => {
+      // 获取当前模型类型
+      tableItemRef.current = createTable(
+        searchParams.get("type") as unknown as TableType
+      );
+      setFormModel(tableItemRef.current.table);
+      setOpen(true);
+    },
+    close: () => {
+      setOpen(false);
+    },
+  }));
+
+  const [form] = Form.useForm();
+  const [formModel, setFormModel] = useState<TableItemType['table']>();
+
+  const items: TabsProps["items"] = [
+    {
+      key: "1",
+      label: `新建`,
+      children: (
+        <div>
+          <Form labelCol={{ span: 8 }} form={form}>
+            <Row gutter={16}>
+              <Col span={12}>
+                <Form.Item label="表类型">
+                  <Input
+                    placeholder="请输入"
+                    value={
+                      formModel?.type == TableType.BusinessTable
+                        ? "业务表"
+                        : "视图表"
+                    }
+                    disabled
+                  />
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item label="编码">
+                  <Input
+                    placeholder="请输入"
+                    value={formModel?.schemaName}
+                    onChange={(e) => handleChange("schemaName", e.target.value)}
+                  />
+                </Form.Item>
+              </Col>
+            </Row>
+            <Row gutter={16}>
+              <Col span={12}>
+                <Form.Item label="表名">
+                  <LangInput
+                    value={formModel?.langNameList}
+                    onChange={(lang) => handleChange("langNameList", lang)}
+                  />
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item label="别名">
+                  <Input
+                    placeholder="请输入"
+                    value={formModel?.aliasName}
+                    onChange={(e) => handleChange("aliasName", e.target.value)}
+                  />
+                </Form.Item>
+              </Col>
+            </Row>
+            <Row gutter={16}>
+              <Col span={24}>
+                <Form.Item label="描述" labelCol={{ span: 4 }}>
+                  <LangInputTextarea
+                    value={formModel?.langDescriptionList}
+                    onChange={(lang) =>
+                      handleChange("langDescriptionList", lang)
+                    }
+                  />
+                </Form.Item>
+              </Col>
+            </Row>
+          </Form>
+        </div>
+      ),
+    },
+    {
+      key: "2",
+      label: `引入`,
+      children: (
+        <div>
+          <Form.Item label="选择主表">
+            <Select placeholder="请选择" />
+          </Form.Item>
+        </div>
+      ),
+    },
+  ];
+
+  const handleChange = (key: string, value: any) => {
+    formModel && setFormModel({
+      ...formModel,
+      [key]: value
+    });
+  };
+  const handleOk = () => {
+    form.validateFields().then((values) => {
+      if(tableItemRef.current && formModel) {
+        props.onChange({
+          ...tableItemRef.current,
+          table: formModel
+        })
+      }
+      setOpen(false);
+    });
+  };
 
-export default function AddTable() {
   return (
-    <div>
-      
-    </div>
-  )
-}
+    <Modal
+      open={open}
+      title="添加表"
+      okText="确定"
+      cancelText="取消"
+      onCancel={() => setOpen(false)}
+      onOk={handleOk}
+    >
+      <Tabs items={items} activeKey={tabActiveKey} onChange={setTabActiveKey} />
+    </Modal>
+  );
+});

+ 50 - 34
apps/er-designer/src/pages/detail/index.tsx

@@ -1,14 +1,22 @@
-import React, { useState } from "react";
-import { Layout, Menu, Button, Descriptions, Input, Tooltip } from "antd";
+import React, { useMemo, useRef, useState } from "react";
+import { Layout, Menu, Button, Descriptions, Input, Tooltip, Empty } from "antd";
 import type { DescriptionsProps, MenuProps } from "antd";
 import { PlusOutlined, SearchOutlined } from "@ant-design/icons";
 import TableEdit from "@/components/TableEdit";
 import ER from "./components/ER";
+import AddTable from "./components/AddTable";
+import { useModel } from "umi";
+import NoData from "@/assets/no-data.png";
+import { TableItemType } from "@/type";
 
 const { Content, Header } = Layout;
 export default function index() {
   const [active, setActive] = useState(0);
   const [showNavigator, setShowNavigator] = useState(false);
+  const addTableRef = useRef<{open: () => void}>();
+  const { project } = useModel("erModel");
+  const [searchKeyword, setSearchKeyword] = useState("");
+
   const descItems: DescriptionsProps["items"] = [
     {
       key: "1",
@@ -47,35 +55,37 @@ export default function index() {
     },
   ];
 
-  const tableData: MenuProps["items"] = [
-    {
-      key: "1",
-      label: "user_info(用户信息表)",
-      icon: <i className="iconfont icon-biaogebeifen" />,
-      children: [
-        {
-          key: "1-1",
-          label: "user_xxx(xxx子表)",
-          icon: <i className="iconfont icon-biaogebeifen" />,
-        },
-        {
-          key: "1-2",
-          label: "user_xxx(xxx子表)",
-          icon: <i className="iconfont icon-biaogebeifen" />,
-        },
-      ],
-    },
-    {
-      key: "2",
-      label: "xxxx主表2",
-      icon: <i className="iconfont icon-biaogebeifen" />,
-    },
-    {
-      key: "3",
-      label: "xxxx主表2",
-      icon: <i className="iconfont icon-biaogebeifen" />,
-    },
-  ];
+  const tableData: MenuProps["items"] = useMemo(() => {
+    const { tables } = project;
+    const treeList: {
+      key: string;
+      label: string | React.ReactNode;
+      icon: React.ReactNode;
+      children: MenuProps["items"];
+    }[] = [];
+
+    tables.forEach((item) => {
+      const newItem = {
+        key: item.table.id,
+        label: item.table.langNameList?.find((item) => item.label === "zh-CN")?.value,
+        icon: <i className="iconfont icon-biaogebeifen" />,
+        children: []
+      };
+      if(!item.table.parentBusinessTableId) {
+        treeList.push(newItem);
+      } else {
+        const parent = treeList.find(tableItem => tableItem?.key === item.table.parentBusinessTableId);
+        if(parent) {
+          parent.children?.push(newItem);
+        }
+      }
+    });
+    return treeList;
+  }, [project]);
+
+  const handleAddTable = (tableItem: TableItemType) => {
+    
+  }
 
   const extra = (
     <div className="flex gap-12px">
@@ -97,6 +107,7 @@ export default function index() {
       </a>
     </div>
   );
+
   return (
     <Layout className="h-100vh flex flex-col bg-#fafafa p-12px">
       <Header
@@ -114,7 +125,7 @@ export default function index() {
           title={
             <span>
               <svg className="iconfont w-14px h-14px m-r-4px">
-                <use xlinkHref="#icon-model" />
+                <use xlinkHref="#icon-shujumoxing" />
               </svg>
               模型详情
             </span>
@@ -148,21 +159,25 @@ export default function index() {
             </div>
             <div>
               <Input
-                size="small"
                 placeholder="搜索"
                 className="w-100px m-r-4px"
                 suffix={<SearchOutlined />}
+                value={searchKeyword}
+                onChange={(e) => setSearchKeyword(e.target.value)}
               />
               <Tooltip title="添加数据表">
                 <Button
-                  size="small"
                   type="primary"
                   icon={<PlusOutlined />}
+                  onClick={() => addTableRef.current?.open()}
                 ></Button>
               </Tooltip>
             </div>
           </div>
           <Menu mode="inline" items={tableData} />
+          {
+            !tableData.length && <Empty image={NoData} description="点击+添加数据表!" />
+          }
         </div>
         <div className="right flex-1 h-full shadow-sm bg-#fff rounded-8px p-12px flex flex-col">
           <div className="head flex justify-between">
@@ -216,6 +231,7 @@ export default function index() {
           </div>
         </div>
       </Content>
+      <AddTable ref={addTableRef} onChange={handleAddTable}/>
     </Layout>
   );
 }

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

@@ -1,4 +1,4 @@
-import React, { useState } from "react";
+import React, { useEffect, useState } from "react";
 import { Button, Dropdown, Input, Modal, Switch, InputNumber } from "antd";
 import type { DropDownProps, MenuProps } from "antd";
 import { useModel } from "umi";
@@ -23,6 +23,11 @@ export default function Menu() {
   const [isFullscreen, { toggleFullscreen }] = useFullscreen(document.body);
   const [openKey, setOpenKey] = useState("");
   const [open, setOpen] = useState(false);
+  const [name, setName] = useState(project?.name);
+
+  useEffect(() => {
+    setName(project.name);
+  }, [project.name]);
   const handleClean = () => {
     modal.confirm({
       title: "确认清除画布全部内容?",
@@ -39,6 +44,10 @@ export default function Menu() {
     setProject({ ...project, setting: { ...project.setting, [key]: value } });
   };
 
+  const handleChangeName = () => {
+    name.trim() && setProject({ ...project, name });
+  }
+
   const handleZoom = (value: number) => {
     if (value < 0.2) {
       graph?.zoomTo(0.2);
@@ -335,7 +344,10 @@ export default function Menu() {
             <Input
               className="text-24px max-w-200px"
               variant="borderless"
-              value={"模型名称"}
+              value={name}
+              onChange={(e) => setName(e.target.value)}
+              onBlur={handleChangeName}
+              onPressEnter={handleChangeName}
             />
             <div className="bg-#eee text-12px leading-20px color-#666 rounded-4px p-x-4px p-y-2px">
               上次保存时间:2024-12-13 13:21:23

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

@@ -47,10 +47,10 @@ export interface ViewTable {
   aliasName: string;
   creationTime: string;
   creatorUserId: string;
-  displayOrder: boolean;
+  displayOrder: number;
   id: string;
   isDeleted: boolean;
-  langDescription: string;
+  langDescription?: string;
   langName?: string;
   parentBusinessTableId: string;
   schemaName: string;

+ 5 - 2
apps/er-designer/src/utils/index.ts

@@ -29,16 +29,19 @@ export const createTable = (tableType: TableType, parentId?: string): TableItemT
       aliasName: "newtable",
       creationTime: "",
       creatorUserId: "",
-      displayOrder: true,
+      displayOrder: 0,
       id: tableId,
       isDeleted: false,
-      langDescription: "",
       langName: "",
       parentBusinessTableId: parentId || "",
       schemaName: "new_table",
       type: 1,
       updateTime: "",
       openSync: false,
+      langNameList: [
+        { name: "zh-CN", value: "" },
+        { name: "en", value: "" },
+      ],
       style: {
         // 随机颜色
         color: "#" + Math.floor(Math.random() * 0x666666).toString(16),