index.tsx 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. import React, { useEffect, useMemo, useState } from "react";
  2. import { Button, Input, Dropdown, Tooltip, MenuProps, Divider } from "antd";
  3. import { LeftOutlined, MenuOutlined } from "@ant-design/icons";
  4. import logo from "@/assets/logo.png";
  5. import { useModel, Icon } from "umi";
  6. import { addTopic } from "../../mindMap";
  7. import { TopicType } from "@/enum";
  8. import { selectTopic, addBorder, addSummary } from "@/utils/mindmapHander";
  9. import { createNew } from "@/utils";
  10. export default function index() {
  11. const {
  12. mindProjectInfo,
  13. setMindProjectInfo,
  14. canRedo,
  15. canUndo,
  16. onRedo,
  17. onUndo,
  18. enableFormatBrush,
  19. toggleFormatBrush,
  20. graph,
  21. selectedCell,
  22. setCorrelationEdgeInfo,
  23. } = useModel("mindMapModel");
  24. const currentNode = useMemo(() => {
  25. return selectedCell.filter(cell => cell.isNode());
  26. }, [selectedCell]);
  27. const [title, setTitle] = useState<string>(mindProjectInfo?.name || "");
  28. useEffect(() => {
  29. setTitle(mindProjectInfo?.name || "");
  30. }, [mindProjectInfo?.name])
  31. const handleChangeTitle = () => {
  32. mindProjectInfo && setMindProjectInfo({
  33. ...mindProjectInfo,
  34. name: title,
  35. })
  36. }
  37. // 预览 todo
  38. const handlePreview = () => {};
  39. // 保存 todo
  40. const handleSave = () => {};
  41. // 克隆 todo
  42. const handleClone = () => {};
  43. // 历史记录 todo
  44. const handleHistory = () => {};
  45. // 查找替换
  46. const handleReplace = () => {};
  47. // 增加子主题
  48. const handleAddSubTopic = () => {
  49. if(!currentNode.length) return;
  50. const topic = addTopic(
  51. currentNode[0].data.type === TopicType.main ? TopicType.branch : TopicType.sub,
  52. setMindProjectInfo,
  53. currentNode[0]
  54. );
  55. graph && selectTopic(graph, topic);
  56. };
  57. // 添加边框
  58. const handleAddBorder = () => {
  59. addBorder(currentNode.filter(item => item.data.parentId));
  60. }
  61. // 添加概要
  62. const handleAddSummary = () => {
  63. addSummary(currentNode.filter(item => item.data.parentId))
  64. }
  65. // 添加关联线
  66. const handleAddCorrelation = () => {
  67. if(!currentNode.length) return;
  68. setCorrelationEdgeInfo(currentNode[0]);
  69. };
  70. const menuData: MenuProps["items"] = [
  71. {
  72. key: "1",
  73. label: "新建",
  74. icon: <i className="w-20px iconfont icon-zengjiahuamian-1" />,
  75. children: [
  76. {
  77. key: "1-1-1",
  78. label: "流程图",
  79. icon: <Icon width="20" className="mt-5px" icon="local:flow" />,
  80. onClick: () => {
  81. createNew("flow");
  82. },
  83. },
  84. {
  85. key: "1-1-2",
  86. label: "思维导图",
  87. icon: <Icon width="20" className="mt-5px" icon="local:mind" />,
  88. onClick: () => {
  89. createNew("mindmap");
  90. },
  91. },
  92. {
  93. key: "1-1-3",
  94. label: "UML",
  95. icon: <Icon width="20" className="mt-5px" icon="local:uml" />,
  96. onClick: () => {
  97. createNew("uml");
  98. },
  99. },
  100. {
  101. key: "1-1-4",
  102. label: "网络拓扑图",
  103. icon: <Icon width="20" className="mt-5px" icon="local:net" />,
  104. onClick: () => {
  105. createNew("net");
  106. },
  107. },
  108. {
  109. key: "1-1-5",
  110. label: "组织结构图",
  111. icon: <Icon width="20" className="mt-5px" icon="local:flow" />,
  112. onClick: () => {
  113. createNew("org");
  114. },
  115. },
  116. {
  117. key: "1-1-6",
  118. label: "BPMN",
  119. icon: <Icon width="20" className="mt-5px" icon="local:bpmn" />,
  120. onClick: () => {
  121. createNew("bpmn");
  122. },
  123. },
  124. ],
  125. },
  126. // {
  127. // key: "2",
  128. // label: "预览",
  129. // icon: <i className="w-20px iconfont icon-yulan" />,
  130. // onClick: handlePreview,
  131. // },
  132. {
  133. key: "3",
  134. label: (
  135. <div className="flex justify-between">
  136. <span>保存</span>
  137. <span>Ctrl+S</span>
  138. </div>
  139. ),
  140. icon: <i className="w-20px iconfont icon-shangchuan" />,
  141. onClick: handleSave,
  142. },
  143. {
  144. key: "4",
  145. label: "克隆",
  146. icon: <i className="w-20px iconfont icon-niantie-1" />,
  147. onClick: handleClone,
  148. },
  149. {
  150. key: "5",
  151. label: "查找替换",
  152. icon: <i className="w-20px iconfont icon-lishijilu" />,
  153. onClick: handleReplace,
  154. },
  155. {
  156. key: "6",
  157. label: "历史记录",
  158. icon: <i className="w-20px iconfont icon-lishijilu" />,
  159. onClick: handleHistory,
  160. },
  161. // {
  162. // key: "1-8",
  163. // type: "divider",
  164. // },
  165. ];
  166. const noParent = useMemo(() => {
  167. const nodes = selectedCell?.filter(cell => cell.isNode());
  168. return !!(nodes.length && !nodes.find(node => !node.data?.parentId));
  169. }, [selectedCell]);
  170. return (
  171. <div className="absolute absolute top-8px left-8px bg-white shadow-md flex items-center gap-4px rounded-4px px-8px">
  172. <Button type="text" icon={<LeftOutlined />}></Button>
  173. <Dropdown
  174. trigger={["hover"]}
  175. menu={{ items: menuData, style: { width: 200 } }}
  176. >
  177. <div className="flex items-center gap-4px">
  178. <img className="w-22px" src={logo} />
  179. <MenuOutlined />
  180. </div>
  181. </Dropdown>
  182. <div className="flex flex-col leading-32px">
  183. {mindProjectInfo && (
  184. <Input
  185. className="text-16px max-w-100px"
  186. variant="borderless"
  187. value={title}
  188. onChange={(e) =>
  189. setTitle(e.target.value)
  190. }
  191. onBlur={handleChangeTitle}
  192. onPressEnter={handleChangeTitle}
  193. />
  194. )}
  195. </div>
  196. <Tooltip placement="bottom" title="撤销">
  197. <Button
  198. type="text"
  199. icon={<i className="iconfont icon-undo"></i>}
  200. disabled={!canUndo}
  201. onClick={onUndo}
  202. />
  203. </Tooltip>
  204. <Tooltip placement="bottom" title="恢复">
  205. <Button
  206. type="text"
  207. icon={<i className="iconfont icon-redo"></i>}
  208. disabled={!canRedo}
  209. onClick={onRedo}
  210. />
  211. </Tooltip>
  212. <Tooltip
  213. placement="bottom"
  214. title={`格式刷${enableFormatBrush ? "生效中按ESC取消" : "(Ctrl+Shift+C)"}`}
  215. >
  216. <Button
  217. type="text"
  218. icon={<i className="iconfont icon-geshishua"></i>}
  219. disabled={!currentNode?.length}
  220. className={
  221. enableFormatBrush && currentNode?.length ? "active" : ""
  222. }
  223. onClick={() => graph && toggleFormatBrush(graph)}
  224. />
  225. </Tooltip>
  226. <Divider type="vertical" />
  227. <Tooltip placement="bottom" title="子主题">
  228. <Button
  229. type="text"
  230. icon={<i className="iconfont icon-zizhuti"></i>}
  231. disabled={!currentNode.length}
  232. onClick={handleAddSubTopic}
  233. />
  234. </Tooltip>
  235. <Tooltip placement="bottom" title="关联线">
  236. <Button
  237. type="text"
  238. icon={<i className="iconfont icon-guanlianxian"></i>}
  239. disabled={!currentNode.length}
  240. onClick={handleAddCorrelation}
  241. />
  242. </Tooltip>
  243. <Tooltip placement="bottom" title="概要">
  244. <Button
  245. type="text"
  246. icon={<i className="iconfont icon-summary-outline"></i>}
  247. disabled={!noParent}
  248. onClick={handleAddSummary}
  249. />
  250. </Tooltip>
  251. <Tooltip placement="bottom" title="外框">
  252. <Button
  253. type="text"
  254. icon={<i className="iconfont icon-waikuang"></i>}
  255. disabled={!noParent}
  256. onClick={handleAddBorder}
  257. />
  258. </Tooltip>
  259. </div>
  260. );
  261. }