index.tsx 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. import React, { useEffect, useState, useMemo, useRef } from "react";
  2. import { useModel } from "umi";
  3. import { Tabs } from "antd";
  4. import InsertCss from "insert-css";
  5. import { useDragResize } from "@/hooks/useDragResize";
  6. import PageStyle from "./PageStyle";
  7. import NodeStyle from "./NodeStyle";
  8. import Structure from "./Structure";
  9. import Theme from "./Theme";
  10. import TagConfig from "./TagConfig";
  11. import IconConfig from "./IconConfig";
  12. import Remark from "./Remark";
  13. import NodeAttrs from "@/components/NodeAttrs";
  14. import AICreator from "./AiCreator";
  15. import AIChat from "@/components/ai/AIChat";
  16. import { buildTopic } from "../../mindMap";
  17. import { TopicType } from "@/enum";
  18. import { Node } from "@antv/x6";
  19. import { TopicItem } from "@/types";
  20. import { traverseNode } from "@/utils/mindmapHander";
  21. InsertCss(`
  22. .shalu-tabs-nav {
  23. padding: 0 16px
  24. }
  25. `);
  26. export default function index() {
  27. const {
  28. rightToobarActive,
  29. selectedCell,
  30. rightToolbarActive,
  31. graph,
  32. mindProjectInfo,
  33. setMindProjectInfo,
  34. } = useModel("mindMapModel");
  35. const { setMindMapRightPanelWidth } = useModel("appModel");
  36. const [activeKey, setActiveKey] = useState("1");
  37. const { dragging, handleMouseDown } = useDragResize(
  38. setMindMapRightPanelWidth
  39. );
  40. useEffect(() => {
  41. if (selectedCell.find((cell) => cell.isNode())) {
  42. setActiveKey("2");
  43. } else {
  44. setActiveKey("1");
  45. }
  46. }, [selectedCell]);
  47. const firstNode = useMemo(() => {
  48. return selectedCell.find((cell) => cell.isNode());
  49. }, [selectedCell]);
  50. // 设置节点属性
  51. const handleSetNodeAttr = (attrs: any) => {
  52. firstNode?.setData({
  53. attrs,
  54. });
  55. };
  56. const handleCloseAI = () => {
  57. rightToolbarActive("");
  58. };
  59. // 记录ai新增的节点id
  60. const aiAddNodeIds = useRef<string[]>([]);
  61. // 获取转换数据
  62. const getConvertData = (data: any[], parentId: string, type: TopicType, parentTopic: TopicItem) => {
  63. return data.map((item) => {
  64. const topic = buildTopic(
  65. type,
  66. { id: item.id, label: item.label },
  67. graph,
  68. { id: parentId, data: parentTopic } as Node
  69. );
  70. topic.parentId = parentId;
  71. aiAddNodeIds.current.push(topic.id);
  72. if (item.children) {
  73. topic.children = getConvertData(item.children, topic.id, TopicType.sub, topic);
  74. }
  75. return topic;
  76. });
  77. };
  78. // 渲染AI创作
  79. const handleAiCreated = (data: any) => {
  80. aiAddNodeIds.current = [];
  81. if (Array.isArray(data)) {
  82. let currentTopic = graph?.getSelectedCells()?.[0]?.data;
  83. if(!currentTopic){
  84. currentTopic = mindProjectInfo?.topics?.find(
  85. (topic) => topic.type === TopicType.main
  86. );
  87. }
  88. const type = currentTopic?.type === TopicType.main ? TopicType.branch : TopicType.sub;
  89. // 获取AI转换数据
  90. const result = getConvertData(data, currentTopic?.id, type, currentTopic);
  91. // 往节点下添加
  92. mindProjectInfo && setMindProjectInfo({
  93. ...mindProjectInfo,
  94. topics: traverseNode(mindProjectInfo.topics, (topic) => {
  95. if (topic.id === currentTopic?.id) {
  96. topic.children = [
  97. ...(topic.children || []),
  98. ...result
  99. ];
  100. }
  101. return topic
  102. })
  103. });
  104. setTimeout(() => {
  105. graph &&
  106. aiAddNodeIds.current.forEach((id) => {
  107. graph.select(graph.getCellById(id));
  108. });
  109. }, 200);
  110. }
  111. };
  112. return (
  113. <div className="w-full h-full flex">
  114. <div
  115. className="h-full w-4px cursor-e-resize hover:bg-blue flex-shrink-0"
  116. style={{ backgroundColor: dragging ? "#60a5fa" : "" }}
  117. onMouseDown={handleMouseDown}
  118. ></div>
  119. <div
  120. className="relative h-full w-full"
  121. style={{ display: rightToobarActive ? "block" : "none" }}
  122. >
  123. {rightToobarActive &&
  124. !["ai-chat", "ai-creator"].includes(rightToobarActive) && (
  125. <div
  126. className="absolute w-16px h-16px right-10px top-10px cursor-pointer z-99"
  127. onClick={() => rightToolbarActive("")}
  128. >
  129. <i className="iconfont icon-cuowu-1 color-#666 hover:color-#333" />
  130. </div>
  131. )}
  132. {/* 样式 */}
  133. {rightToobarActive === "style" && (
  134. <>
  135. <Tabs
  136. activeKey={activeKey}
  137. onChange={(key) => setActiveKey(key)}
  138. items={[
  139. {
  140. key: "1",
  141. label: "页面样式",
  142. children: <PageStyle />,
  143. },
  144. {
  145. key: "2",
  146. label: "主题样式",
  147. children: <NodeStyle />,
  148. },
  149. ]}
  150. />
  151. </>
  152. )}
  153. {/* 节点属性 */}
  154. {rightToobarActive === "attrs" && (
  155. <>
  156. <Tabs
  157. items={[
  158. {
  159. key: "1",
  160. label: "节点属性",
  161. children: (
  162. <NodeAttrs cell={firstNode} onChange={handleSetNodeAttr} />
  163. ),
  164. },
  165. ]}
  166. />
  167. </>
  168. )}
  169. {/* 结构 */}
  170. {rightToobarActive === "structure" && <Structure />}
  171. {/* 风格 */}
  172. {rightToobarActive === "theme" && <Theme />}
  173. {/* 图标 */}
  174. {rightToobarActive === "icon" && <IconConfig />}
  175. {/* 标签 */}
  176. {rightToobarActive === "tag" && <TagConfig />}
  177. {/* 备注 */}
  178. {rightToobarActive === "remark" && <Remark />}
  179. {/* AI对话 */}
  180. {rightToobarActive === "ai-chat" && <AIChat onClose={handleCloseAI}/>}
  181. {/* AI创作 */}
  182. {rightToobarActive === "ai-creator" && (
  183. <AICreator
  184. type="mindmap"
  185. onClose={handleCloseAI}
  186. onChange={handleAiCreated}
  187. />
  188. )}
  189. </div>
  190. </div>
  191. );
  192. }