Toolbar.tsx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. import React, { useEffect, useState } from "react";
  2. import { Tooltip, Dropdown, DropDownProps } from "antd";
  3. import { CheckOutlined, DownOutlined } from "@ant-design/icons";
  4. import { useModel } from "umi";
  5. import TodoDrawer from "./TodoDrawer";
  6. import AICreator from "./AICreator";
  7. import { useFullscreen, useLocalStorageState } from "ahooks";
  8. export default function Toolbar() {
  9. const {
  10. addTable,
  11. addTopicArea,
  12. addRemark,
  13. graph,
  14. canRedo,
  15. canUndo,
  16. onRedo,
  17. onUndo,
  18. project,
  19. setProject,
  20. onSave,
  21. } = useModel("erModel");
  22. const todoRef = React.useRef<{ open: () => void }>();
  23. const [isFullscreen, { toggleFullscreen }] = useFullscreen(document.body);
  24. const scaleMenu = {
  25. style: {
  26. width: 200,
  27. },
  28. items: [
  29. {
  30. key: "1",
  31. label: "25%",
  32. onClick: () => {
  33. handleZoom(25);
  34. },
  35. },
  36. {
  37. key: "2",
  38. label: "50%",
  39. onClick: () => {
  40. handleZoom(50);
  41. },
  42. },
  43. {
  44. key: "3",
  45. label: "75%",
  46. onClick: () => {
  47. handleZoom(75);
  48. },
  49. },
  50. {
  51. key: "4",
  52. label: "100%",
  53. onClick: () => {
  54. handleZoom(100);
  55. },
  56. },
  57. {
  58. key: "5",
  59. label: "150%",
  60. onClick: () => {
  61. handleZoom(150);
  62. },
  63. },
  64. {
  65. key: "6",
  66. label: "200%",
  67. onClick: () => {
  68. handleZoom(200);
  69. },
  70. },
  71. ],
  72. };
  73. // 隐藏默认字段
  74. const [hideDefaultColumn, setHideDefaultColumn] = useLocalStorageState(
  75. "er-hideDefaultColumn",
  76. {
  77. defaultValue: false,
  78. listenStorageChange: true
  79. }
  80. );
  81. const layoutMenu: DropDownProps["menu"] = {
  82. style: {
  83. width: 120,
  84. },
  85. items: [
  86. {
  87. key: "1",
  88. label: (
  89. <span className="flex items-center">
  90. <span className="inlineblock w-25px">
  91. {project.setting.showMenu ? (
  92. <CheckOutlined className="text-12px" />
  93. ) : (
  94. ""
  95. )}
  96. </span>
  97. <span>菜单栏</span>
  98. </span>
  99. ),
  100. onClick: () => {
  101. setProject({
  102. ...project,
  103. setting: {
  104. ...project.setting,
  105. showMenu: !project.setting.showMenu,
  106. },
  107. });
  108. },
  109. },
  110. {
  111. key: "2",
  112. label: (
  113. <span className="flex items-center">
  114. <span className="inlineblock w-25px">
  115. {project.setting.showSidebar ? (
  116. <CheckOutlined className="text-12px" />
  117. ) : (
  118. ""
  119. )}
  120. </span>
  121. <span>侧边栏</span>
  122. </span>
  123. ),
  124. onClick: () => {
  125. setProject({
  126. ...project,
  127. setting: {
  128. ...project.setting,
  129. showSidebar: !project.setting.showSidebar,
  130. },
  131. });
  132. },
  133. },
  134. {
  135. key: "3",
  136. type: "divider",
  137. },
  138. {
  139. key: "4",
  140. label: (
  141. <span className="flex items-center">
  142. <span className="inlineblock w-25px">
  143. {isFullscreen && <CheckOutlined className="text-12px" />}
  144. </span>
  145. <span>全屏</span>
  146. </span>
  147. ),
  148. onClick: () => {
  149. toggleFullscreen();
  150. },
  151. },
  152. ],
  153. };
  154. const [scale, setScale] = useState(100);
  155. useEffect(() => {
  156. graph?.on("scale", (scaleInfo) => {
  157. setScale(parseInt(scaleInfo.sx * 100 + ""));
  158. });
  159. }, [graph]);
  160. const handleZoom = (value: number) => {
  161. if (value > 200) {
  162. graph?.zoomTo(2);
  163. return;
  164. }
  165. if (value < 20) {
  166. graph?.zoomTo(0.2);
  167. return;
  168. }
  169. graph?.zoomTo(value / 100);
  170. };
  171. const handleChangeShowMenu = () => {
  172. setProject({
  173. ...project,
  174. setting: { ...project.setting, showMenu: !project.setting.showMenu },
  175. });
  176. };
  177. return (
  178. <div className="flex justify-between bg-#fafafa">
  179. <div>
  180. <TodoDrawer ref={todoRef} />
  181. </div>
  182. <div className="flex items-center py-0px justify-center h-32px">
  183. <div className="group">
  184. <div className="btn flex flex-col items-center cursor-pointer py-4px px-10px hover:bg-gray-200">
  185. <Dropdown menu={layoutMenu} placement="bottomLeft">
  186. <span className="text-14px leading-18px">
  187. <i className="iconfont icon-layout-5-line text-20px text-#666" />
  188. <DownOutlined className="text-10px ml-4px" />
  189. </span>
  190. </Dropdown>
  191. </div>
  192. </div>
  193. <div className="group">
  194. <div className="btn flex flex-col items-center cursor-pointer py-4px px-10px hover:bg-gray-200">
  195. <Tooltip
  196. title={`${hideDefaultColumn ? "隐藏" : "显示"}默认字段`}
  197. >
  198. <i
  199. className={`iconfont text-20px leading-24px ${!hideDefaultColumn ? "icon-view" : "icon-hide"}`}
  200. onClick={() => {
  201. setHideDefaultColumn(!hideDefaultColumn);
  202. }}
  203. />
  204. </Tooltip>
  205. </div>
  206. </div>
  207. <div className="group">
  208. <div className="flex items-center">
  209. <Tooltip title="撤销上一步操作">
  210. <div
  211. className="btn flex flex-col items-center cursor-pointer py-4px px-10px hover:bg-gray-200"
  212. style={{
  213. opacity: canUndo ? 1 : 0.5,
  214. }}
  215. onClick={() => canUndo && onUndo()}
  216. >
  217. <svg className="icon h-24px w-24px" aria-hidden="true">
  218. <use xlinkHref="#icon-undo"></use>
  219. </svg>
  220. </div>
  221. </Tooltip>
  222. <Tooltip title="恢复上一步操作">
  223. <div
  224. className="btn flex flex-col items-center cursor-pointer py-4px px-10px hover:bg-gray-200"
  225. style={{
  226. opacity: canRedo ? 1 : 0.5,
  227. }}
  228. onClick={() => canRedo && onRedo()}
  229. >
  230. <svg className="icon h-24px w-24px" aria-hidden="true">
  231. <use xlinkHref="#icon-redo"></use>
  232. </svg>
  233. </div>
  234. </Tooltip>
  235. </div>
  236. </div>
  237. <div className="h-30px border-transparent border-r-1px border-solid border-r-#eee m-x-8px"></div>
  238. <div className="group">
  239. <div className="flex items-center">
  240. <Tooltip title="创建表">
  241. <div
  242. className="btn flex flex-col items-center cursor-pointer py-4px px-10px hover:bg-gray-200"
  243. onClick={() => addTable()}
  244. >
  245. <svg className="icon h-24px w-24px" aria-hidden="true">
  246. <use xlinkHref="#icon-biaoge"></use>
  247. </svg>
  248. </div>
  249. </Tooltip>
  250. <Tooltip title="创建主题域">
  251. <div
  252. className="btn flex flex-col items-center cursor-pointer py-4px px-10px hover:bg-gray-200"
  253. onClick={addTopicArea}
  254. >
  255. <svg className="icon h-24px w-24px" aria-hidden="true">
  256. <use xlinkHref="#icon-ditukuangxuan"></use>
  257. </svg>
  258. </div>
  259. </Tooltip>
  260. <Tooltip title="创建备注">
  261. <div
  262. className="btn flex flex-col items-center cursor-pointer py-4px px-10px hover:bg-gray-200"
  263. onClick={addRemark}
  264. >
  265. <svg className="icon h-24px w-24px" aria-hidden="true">
  266. <use xlinkHref="#icon-beizhu"></use>
  267. </svg>
  268. </div>
  269. </Tooltip>
  270. </div>
  271. </div>
  272. <div className="h-30px border-transparent border-r-1px border-solid border-r-#eee m-x-8px"></div>
  273. <div className="group">
  274. <div className="flex items-center">
  275. <Tooltip title="保存模型">
  276. <div
  277. className="btn flex flex-col items-center cursor-pointer py-4px px-10px hover:bg-gray-200"
  278. onClick={onSave}
  279. >
  280. <svg
  281. className="icon h-24px w-24px color-#666"
  282. aria-hidden="true"
  283. >
  284. <use xlinkHref="#icon-baocun"></use>
  285. </svg>
  286. </div>
  287. </Tooltip>
  288. <Tooltip title="待办项">
  289. <div
  290. className="btn flex flex-col items-center cursor-pointer py-4px px-10px hover:bg-gray-200"
  291. onClick={() => todoRef.current?.open()}
  292. >
  293. <svg
  294. className="icon h-24px w-24px color-#666"
  295. aria-hidden="true"
  296. >
  297. <use xlinkHref="#icon-daiban"></use>
  298. </svg>
  299. </div>
  300. </Tooltip>
  301. </div>
  302. </div>
  303. <div className="h-30px border-transparent border-r-1px border-solid border-r-#eee m-x-8px"></div>
  304. <div className="group">
  305. <div className="flex items-center">
  306. <Tooltip title="AI助手">
  307. <AICreator
  308. trigger={
  309. <div className="btn flex flex-col items-center cursor-pointer py-4px px-10px hover:bg-gray-200">
  310. <svg
  311. className="icon h-24px w-24px color-#666"
  312. aria-hidden="true"
  313. >
  314. <use xlinkHref="#icon-AI1"></use>
  315. </svg>
  316. </div>
  317. }
  318. />
  319. </Tooltip>
  320. </div>
  321. </div>
  322. <div className="h-30px border-transparent border-r-1px border-solid border-r-#eee m-x-8px"></div>
  323. <div className="group">
  324. <div className="flex items-center">
  325. <Tooltip title="放大">
  326. <div
  327. className="btn flex flex-col items-center cursor-pointer py-4px px-10px hover:bg-gray-200"
  328. style={{ opacity: scale >= 200 ? 0.5 : 1 }}
  329. onClick={() => handleZoom(scale + 25)}
  330. >
  331. <svg className="icon h-24px w-24px" aria-hidden="true">
  332. <use xlinkHref="#icon-suofangda"></use>
  333. </svg>
  334. </div>
  335. </Tooltip>
  336. <Tooltip title="缩小">
  337. <div
  338. className="btn flex flex-col items-center cursor-pointer py-4px px-10px hover:bg-gray-200"
  339. style={{ opacity: scale <= 20 ? 0.5 : 1 }}
  340. onClick={() => handleZoom(scale - 25)}
  341. >
  342. <svg className="icon h-24px w-24px" aria-hidden="true">
  343. <use xlinkHref="#icon-suofangxiao"></use>
  344. </svg>
  345. </div>
  346. </Tooltip>
  347. <Dropdown menu={scaleMenu}>
  348. <span className="text-14px leading-18px w-120px">
  349. <span>{scale}%</span>
  350. <DownOutlined className="text-10px ml-4px" />
  351. </span>
  352. </Dropdown>
  353. </div>
  354. </div>
  355. </div>
  356. <div>
  357. <div
  358. className="btn py-4px px-10px hover:bg-gray-200 opacity-50 flex items-center justify-center cursor-pointer"
  359. onClick={handleChangeShowMenu}
  360. >
  361. <i
  362. className="iconfont icon-open leading-24px inline-block"
  363. style={{
  364. transition: "all 0.3s",
  365. transform: project.setting.showMenu
  366. ? "rotate(180deg)"
  367. : "rotate(0deg)",
  368. }}
  369. ></i>
  370. </div>
  371. </div>
  372. </div>
  373. );
  374. }