index.tsx 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. import React, { useEffect } from "react";
  2. import { Input, Layout, Tabs, ConfigProvider, Spin } from "antd";
  3. import type { TabsProps } from "antd/lib";
  4. import Toolbar from "./components/Toolbar";
  5. import TablePanel from "./components/TablePanel";
  6. import RelationPanel from "./components/RelationPanel";
  7. import ThemePanel from "./components/ThemePanel";
  8. import RemarkPanel from "./components/RemarkPanel";
  9. import Navigator from "./components/Navigator";
  10. import Menu from "./components/Menu";
  11. import { useModel, useRequest, useParams } from "umi";
  12. import "./index.less";
  13. import { useSessionStorageState } from "ahooks";
  14. import {
  15. EnvironmentOutlined,
  16. FullscreenExitOutlined,
  17. UnorderedListOutlined,
  18. } from "@ant-design/icons";
  19. import { GetDataModelDetail } from "@/api";
  20. const { Header, Content, Sider } = Layout;
  21. const App: React.FC = () => {
  22. const containerRef = React.useRef(null);
  23. const { initGraph, project, playModeEnable, exitPlayMode, setProject } =
  24. useModel("erModel");
  25. const [tabActiveKey, setTabActiveKey] = useSessionStorageState(
  26. "tabs-active-key",
  27. {
  28. defaultValue: "1",
  29. listenStorageChange: true,
  30. }
  31. );
  32. // 更新画布key 用于刷新画布
  33. const [updateKey, setUpdateKey] = useSessionStorageState("update-key", {
  34. listenStorageChange: true,
  35. defaultValue: 0,
  36. });
  37. const [show, setShow] = useSessionStorageState("show-navigator");
  38. const params = useParams();
  39. const { run, loading, refresh } = useRequest(GetDataModelDetail, {
  40. manual: true,
  41. onSuccess: (res) => {
  42. console.log("模型详情:", res);
  43. const result = res?.result;
  44. if (result) {
  45. setProject(result, false, true);
  46. }
  47. },
  48. });
  49. useEffect(() => {
  50. exitPlayMode();
  51. if (containerRef.current) {
  52. initGraph(containerRef.current);
  53. }
  54. if (!project.id && params?.id) {
  55. run({
  56. id: params.id,
  57. });
  58. }
  59. }, []);
  60. useEffect(() => {
  61. if (params?.id && updateKey) {
  62. run({
  63. id: params.id,
  64. });
  65. }
  66. }, [updateKey]);
  67. useEffect(() => {
  68. // 监听浏览器tab切换 刷新数据
  69. const handleVisibilityChange = () => {
  70. if (document.visibilityState === "visible") {
  71. refresh();
  72. }
  73. };
  74. document.addEventListener("visibilitychange", handleVisibilityChange);
  75. return () => {
  76. document.removeEventListener("visibilitychange", handleVisibilityChange);
  77. };
  78. });
  79. const tabItems: TabsProps["items"] = [
  80. {
  81. key: "1",
  82. label: "表",
  83. children: <TablePanel />,
  84. },
  85. {
  86. key: "2",
  87. label: "关系",
  88. children: <RelationPanel />,
  89. },
  90. {
  91. key: "3",
  92. label: "主题区域",
  93. children: <ThemePanel />,
  94. },
  95. {
  96. key: "4",
  97. label: "注释",
  98. children: <RemarkPanel />,
  99. },
  100. ];
  101. useEffect(() => {
  102. document.addEventListener(
  103. "mousewheel",
  104. function (e: any) {
  105. // 判断是否按下ctrl
  106. if (e.ctrlKey) {
  107. // 阻止默认事件
  108. e.preventDefault();
  109. }
  110. },
  111. { capture: false, passive: false }
  112. );
  113. document.addEventListener(
  114. "keydown",
  115. function (event) {
  116. if (
  117. (event.ctrlKey === true || event.metaKey === true) &&
  118. event.key.toLowerCase() === "s"
  119. ) {
  120. event.preventDefault();
  121. }
  122. },
  123. false
  124. );
  125. }, []);
  126. return (
  127. <Spin spinning={loading}>
  128. <Layout className="h-100vh">
  129. {!playModeEnable && (
  130. <Header
  131. className="bg-white h-100px border-b-1px border-b-solid border-b-gray-200 p-x-0 flex flex-col"
  132. style={{
  133. height: project.setting.showMenu ? "100px" : "32px",
  134. transition: "all 0.3s ease-in-out",
  135. }}
  136. >
  137. <div
  138. className="grid"
  139. style={{
  140. gridTemplateRows: project.setting.showMenu ? "1fr" : "0fr",
  141. transition: "all 0.3s",
  142. }}
  143. >
  144. <div className="overflow-hidden">
  145. <Menu />
  146. </div>
  147. </div>
  148. <Toolbar />
  149. </Header>
  150. )}
  151. <Layout>
  152. {!playModeEnable && (
  153. <Sider
  154. width={project.setting.showSidebar ? 360 : 0}
  155. style={{ background: "#fff", borderRight: "1px solid #eee" }}
  156. >
  157. <ConfigProvider
  158. theme={{
  159. components: {
  160. Tabs: {
  161. colorPrimary: "#000",
  162. },
  163. },
  164. }}
  165. >
  166. <Tabs
  167. animated
  168. activeKey={tabActiveKey}
  169. onChange={setTabActiveKey}
  170. items={tabItems}
  171. centered
  172. />
  173. </ConfigProvider>
  174. </Sider>
  175. )}
  176. <Layout>
  177. <Content className="overflow-hidden">
  178. <div id="graph-container" ref={containerRef}></div>
  179. <Navigator key="editor" />
  180. {playModeEnable && (
  181. <div className="absolute top-32px right-32px z-2">
  182. <div className="left bg-#fff shadow-md p-x-4px p-y-4px flex items-center gap-8px">
  183. <div
  184. className="
  185. rounded-4px
  186. cus-btn
  187. w-32px
  188. h-32px
  189. bg-#eee
  190. flex-none
  191. text-center
  192. leading-32px
  193. cursor-pointer
  194. hover:bg-#ddd"
  195. >
  196. <UnorderedListOutlined />
  197. </div>
  198. <div
  199. className="
  200. rounded-4px
  201. cus-btn
  202. w-32px
  203. h-32px
  204. bg-#eee
  205. flex-none
  206. text-center
  207. leading-32px
  208. cursor-pointer
  209. hover:bg-#ddd"
  210. >
  211. <EnvironmentOutlined onClick={() => setShow(!show)} />
  212. </div>
  213. <div
  214. className="
  215. rounded-4px
  216. cus-btn
  217. w-32px
  218. h-32px
  219. bg-#eee
  220. flex-none
  221. text-center
  222. leading-32px
  223. cursor-pointer
  224. hover:bg-#ddd"
  225. onClick={() => exitPlayMode()}
  226. >
  227. <FullscreenExitOutlined />
  228. </div>
  229. </div>
  230. </div>
  231. )}
  232. </Content>
  233. </Layout>
  234. </Layout>
  235. </Layout>
  236. </Spin>
  237. );
  238. };
  239. export default App;