index.tsx 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. import React, { useEffect, useMemo, useRef, useState } from "react";
  2. import {
  3. Layout,
  4. Menu,
  5. Button,
  6. Descriptions,
  7. Input,
  8. Tooltip,
  9. Empty,
  10. } from "antd";
  11. import type { DescriptionsProps, MenuProps } from "antd";
  12. import { PlusOutlined, SearchOutlined } from "@ant-design/icons";
  13. import TableEdit from "@/components/TableEdit";
  14. import ER from "./components/ER";
  15. import AddTable from "./components/AddTable";
  16. import { useModel, history } from "umi";
  17. import NoData from "@/assets/no-data.png";
  18. import { TableItemType } from "@/type";
  19. const { Content, Header } = Layout;
  20. export default function index() {
  21. const [active, setActive] = useState(0);
  22. const [showNavigator, setShowNavigator] = useState(true);
  23. const addTableRef = useRef<{ open: () => void }>();
  24. const { project, setProject, setPlayModeEnable } = useModel("erModel");
  25. const [searchKeyword, setSearchKeyword] = useState("");
  26. const [selectKey, setSelectKey] = useState<string>("");
  27. useEffect(() => {
  28. setPlayModeEnable(true);
  29. }, [project]);
  30. const descItems: DescriptionsProps["items"] = [
  31. {
  32. key: "1",
  33. label: "模型名称",
  34. children: "用户模型名称",
  35. },
  36. {
  37. key: "2",
  38. label: "创建用户",
  39. children: "张XX",
  40. },
  41. {
  42. key: "3",
  43. label: "创建时间",
  44. children: "2024-12-12 13:45",
  45. },
  46. {
  47. key: "4",
  48. label: "更新时间",
  49. children: "2024-12-12 13:45",
  50. },
  51. {
  52. key: "5",
  53. label: "发布状态",
  54. children: "未发布",
  55. },
  56. {
  57. key: "6",
  58. label: "数据库同步",
  59. children: "5/6",
  60. },
  61. {
  62. key: "7",
  63. label: "描述",
  64. children: "模型说明啊多发点是否,的发射点发射点,打发打发",
  65. },
  66. ];
  67. const tableData: MenuProps["items"] = useMemo(() => {
  68. const { tables } = project;
  69. const treeList: {
  70. key: string;
  71. label: string | React.ReactNode;
  72. icon: React.ReactNode;
  73. children?: MenuProps["items"];
  74. }[] = [];
  75. tables.forEach((item) => {
  76. const name = item.table.langNameList?.find(
  77. (item) => item.name === "zh-CN"
  78. )?.value;
  79. const newItem = {
  80. key: item.table.id,
  81. label: item.table.schemaName + `${name ? `(${name})}` : ""}`,
  82. icon: <i className="iconfont icon-biaogebeifen" />,
  83. // children: [],
  84. };
  85. if (!item.table.parentBusinessTableId) {
  86. treeList.push(newItem);
  87. } else {
  88. const parent = treeList.find(
  89. (tableItem) => tableItem?.key === item.table.parentBusinessTableId
  90. );
  91. if (parent) {
  92. if(!parent?.children) {
  93. parent.children = [];
  94. }
  95. parent.children?.push(newItem);
  96. }
  97. }
  98. });
  99. return treeList;
  100. }, [project]);
  101. const currentTable = useMemo(() => {
  102. return project.tables.find((item) => item.table.id === selectKey);
  103. }, [project, selectKey]);
  104. const handleAddTable = (tableItem: TableItemType) => {
  105. setProject({
  106. ...project,
  107. tables: [...project.tables, tableItem],
  108. });
  109. };
  110. const extra = (
  111. <div className="flex gap-12px">
  112. <a>
  113. <i className="iconfont icon-tongbu text-12px" />
  114. 一键同步
  115. </a>
  116. <a>
  117. <i className="iconfont icon-bianji text-12px" />
  118. 修改
  119. </a>
  120. <a onClick={() => history.push(`/er/${project.id}`)}>
  121. <i className="iconfont icon-bianji text-12px" />
  122. 进入编辑
  123. </a>
  124. <a>
  125. <i className="iconfont icon-moban text-14px" />
  126. 保存为模板
  127. </a>
  128. </div>
  129. );
  130. return (
  131. <Layout className="h-100vh flex flex-col bg-#fafafa p-12px">
  132. <Header
  133. className="shadow-sm"
  134. style={{
  135. backgroundColor: "#fff",
  136. padding: 16,
  137. height: "auto",
  138. borderRadius: 8,
  139. // boxShadow: "0 2px 4px rgba(0, 0, 0, 0.15)",
  140. marginBottom: 12,
  141. }}
  142. >
  143. <Descriptions
  144. title={
  145. <span>
  146. <svg className="iconfont w-14px h-14px m-r-4px">
  147. <use xlinkHref="#icon-shujumoxing" />
  148. </svg>
  149. 模型详情
  150. </span>
  151. }
  152. items={descItems}
  153. extra={extra}
  154. ></Descriptions>
  155. </Header>
  156. <Content className="flex-1 flex gap-12px">
  157. <div className="left w-300px shrink-0 h-full shadow-sm bg-#fff rounded-8px">
  158. <div
  159. className="
  160. flex
  161. justify-between
  162. header-tit
  163. p-x-16px
  164. p-y-12px
  165. text-16px
  166. font-bold
  167. text-rgba(0, 0, 0, 0.88)
  168. border-b-1px
  169. border-b-#eee
  170. border-b-solid"
  171. >
  172. <div>
  173. <svg className="iconfont w-14px h-14px m-r-4px">
  174. <use xlinkHref="#icon-biaoge" />
  175. </svg>
  176. <span>数据表</span>
  177. </div>
  178. <div>
  179. <Input
  180. placeholder="搜索"
  181. className="w-100px m-r-4px"
  182. suffix={<SearchOutlined />}
  183. value={searchKeyword}
  184. onChange={(e) => setSearchKeyword(e.target.value)}
  185. />
  186. <Tooltip title="添加数据表">
  187. <Button
  188. type="primary"
  189. icon={<PlusOutlined />}
  190. onClick={() => addTableRef.current?.open()}
  191. ></Button>
  192. </Tooltip>
  193. </div>
  194. </div>
  195. <Menu
  196. mode="inline"
  197. items={tableData}
  198. selectedKeys={[selectKey]}
  199. onSelect={({ key }) => setSelectKey(key)}
  200. />
  201. {!tableData.length && (
  202. <Empty image={NoData} description="点击+添加数据表!" />
  203. )}
  204. </div>
  205. <div className="right flex-1 h-full shadow-sm bg-#fff rounded-8px p-12px flex flex-col">
  206. <div className="head flex justify-between">
  207. <div className="left flex gap-8px">
  208. <Button
  209. type={active === 0 ? "primary" : "default"}
  210. onClick={() => setActive(0)}
  211. >
  212. ER图
  213. </Button>
  214. <Button
  215. type={active === 1 ? "primary" : "default"}
  216. onClick={() => setActive(1)}
  217. >
  218. 实体
  219. </Button>
  220. </div>
  221. <div className="right flex gap-8px m-b-12px">
  222. {active === 0 ? (
  223. <>
  224. <Input placeholder="搜索" suffix={<SearchOutlined />} />
  225. <Button
  226. type={showNavigator ? "primary" : "default"}
  227. onClick={() => setShowNavigator(!showNavigator)}
  228. icon={<i className="iconfont icon-xiaoditu text-14px" />}
  229. >
  230. 导航
  231. </Button>
  232. <Button
  233. type="primary"
  234. icon={<i className="iconfont icon-quanping_o text-14px" />}
  235. >
  236. 全屏
  237. </Button>
  238. </>
  239. ) : (
  240. <>
  241. <Input placeholder="搜索" suffix={<SearchOutlined />} />
  242. </>
  243. )}
  244. </div>
  245. </div>
  246. <div className="content w-full flex-1">
  247. {active === 0 ? (
  248. <div className="er w-full h-full bg-#ccc">
  249. <ER showNavigator={showNavigator} />
  250. </div>
  251. ) : (
  252. <TableEdit data={currentTable?.tableColumnList || []} />
  253. )}
  254. </div>
  255. </div>
  256. </Content>
  257. <AddTable ref={addTableRef} onChange={handleAddTable} />
  258. </Layout>
  259. );
  260. }