EditableTocTree.tsx 6.0 KB

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