2
0

EditableTocTree.tsx 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. import { Button, message } from "antd";
  2. import { useEffect, useState } from "react";
  3. import { FolderOpenOutlined } from "@ant-design/icons";
  4. import { get as getUiLang } from "../../locales";
  5. import { get, post, put } from "../../request";
  6. import {
  7. IArticleCreateRequest,
  8. IArticleDataResponse,
  9. IArticleMapAddResponse,
  10. IArticleMapListResponse,
  11. IArticleMapRequest,
  12. IArticleMapUpdateRequest,
  13. IArticleResponse,
  14. } from "../api/Article";
  15. import ArticleListModal from "../article/ArticleListModal";
  16. import EditableTree, {
  17. ListNodeData,
  18. TreeNodeData,
  19. } from "../article/EditableTree";
  20. import ArticleEditDrawer from "../article/ArticleEditDrawer";
  21. import ArticleDrawer from "../article/ArticleDrawer";
  22. import { fullUrl, randomString } from "../../utils";
  23. interface IWidget {
  24. anthologyId?: string;
  25. studioName?: string;
  26. onSelect?: Function;
  27. }
  28. const EditableTocTreeWidget = ({
  29. anthologyId,
  30. studioName,
  31. onSelect,
  32. }: IWidget) => {
  33. const [tocData, setTocData] = useState<ListNodeData[]>([]);
  34. const [addArticle, setAddArticle] = useState<TreeNodeData>();
  35. const [articleId, setArticleId] = useState<string>();
  36. const [openEditor, setOpenEditor] = useState(false);
  37. const [updatedArticle, setUpdatedArticle] = useState<TreeNodeData>();
  38. const [openViewer, setOpenViewer] = useState(false);
  39. const [viewArticleId, setViewArticleId] = useState<string>();
  40. const save = (data?: ListNodeData[]) => {
  41. console.log("onSave", data);
  42. if (typeof data === "undefined") {
  43. return;
  44. }
  45. const url = `/v2/article-map/${anthologyId}`;
  46. const newData: IArticleMapRequest[] = data.map((item) => {
  47. let title = "";
  48. if (typeof item.title === "string") {
  49. title = item.title;
  50. }
  51. //TODO 整一个string title
  52. return {
  53. article_id: item.key,
  54. level: item.level,
  55. title: title,
  56. children: item.children,
  57. deleted_at: item.deletedAt,
  58. };
  59. });
  60. put<IArticleMapUpdateRequest, IArticleMapAddResponse>(url, {
  61. data: newData,
  62. operation: "anthology",
  63. })
  64. .finally(() => {})
  65. .then((json) => {
  66. if (json.ok) {
  67. message.success(json.data);
  68. } else {
  69. message.error(json.message);
  70. }
  71. })
  72. .catch((e) => console.error(e));
  73. };
  74. useEffect(() => {
  75. get<IArticleMapListResponse>(
  76. `/v2/article-map?view=anthology&id=${anthologyId}`
  77. ).then((json) => {
  78. if (json.ok) {
  79. const toc: ListNodeData[] = json.data.rows.map((item) => {
  80. return {
  81. key: item.article_id ? item.article_id : item.title,
  82. title: item.title,
  83. level: item.level,
  84. deletedAt: item.deleted_at,
  85. };
  86. });
  87. setTocData(toc);
  88. }
  89. });
  90. }, [anthologyId]);
  91. return (
  92. <div>
  93. <EditableTree
  94. treeData={tocData}
  95. addOnArticle={addArticle}
  96. addFileButton={
  97. <ArticleListModal
  98. studioName={studioName}
  99. trigger={<Button icon={<FolderOpenOutlined />}>添加</Button>}
  100. multiple={false}
  101. onSelect={(id: string, title: string) => {
  102. console.log("add article", id);
  103. const newNode: TreeNodeData = {
  104. key: randomString(),
  105. id: id,
  106. title: title,
  107. children: [],
  108. level: 1,
  109. };
  110. setAddArticle(newNode);
  111. }}
  112. />
  113. }
  114. updatedNode={updatedArticle}
  115. onChange={(data: ListNodeData[]) => {
  116. save(data);
  117. }}
  118. onSave={(data: ListNodeData[]) => {
  119. save(data);
  120. }}
  121. onAppend={async (
  122. node: TreeNodeData
  123. ): Promise<TreeNodeData | undefined> => {
  124. if (typeof studioName === "undefined") {
  125. console.log("studio", studioName);
  126. return;
  127. }
  128. const res = await post<IArticleCreateRequest, IArticleResponse>(
  129. `/v2/article`,
  130. {
  131. title: "new article",
  132. lang: getUiLang(),
  133. studio: studioName,
  134. anthologyId: anthologyId,
  135. }
  136. );
  137. console.log(res);
  138. if (res.ok) {
  139. return {
  140. key: randomString(),
  141. id: res.data.uid,
  142. title: res.data.title,
  143. children: [],
  144. level: node.level + 1,
  145. };
  146. } else {
  147. return;
  148. }
  149. }}
  150. onNodeEdit={(key: string) => {
  151. setArticleId(key);
  152. setOpenEditor(true);
  153. }}
  154. onTitleClick={(
  155. e: React.MouseEvent<HTMLElement, MouseEvent>,
  156. node: TreeNodeData
  157. ) => {
  158. if (e.ctrlKey || e.metaKey) {
  159. window.open(fullUrl(`/article/article/${node.id}`), "_blank");
  160. } else {
  161. setViewArticleId(node.id);
  162. setOpenViewer(true);
  163. }
  164. }}
  165. />
  166. <ArticleEditDrawer
  167. articleId={articleId}
  168. open={openEditor}
  169. onClose={() => setOpenEditor(false)}
  170. onChange={(data: IArticleDataResponse) => {
  171. console.log("new title", data.title);
  172. setUpdatedArticle({
  173. key: randomString(),
  174. id: data.uid,
  175. title: data.title,
  176. level: 0,
  177. children: [],
  178. });
  179. }}
  180. />
  181. <ArticleDrawer
  182. articleId={viewArticleId}
  183. type="article"
  184. open={openViewer}
  185. onClose={() => setOpenViewer(false)}
  186. />
  187. </div>
  188. );
  189. };
  190. export default EditableTocTreeWidget;