ArticleTpl.tsx 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. import { useEffect, useState } from "react";
  2. import {
  3. Button,
  4. Divider,
  5. Input,
  6. Modal,
  7. Select,
  8. Space,
  9. Tabs,
  10. Typography,
  11. } from "antd";
  12. import { FolderOpenOutlined } from "@ant-design/icons";
  13. import { ArticleCtl, type TDisplayStyle } from "../Article";
  14. import type { ArticleType } from "../../article/Article";
  15. import { useIntl } from "react-intl";
  16. import ArticleListModal from "../../article/ArticleListModal";
  17. import { useAppSelector } from "../../../hooks";
  18. import { currentUser } from "../../../reducers/current-user";
  19. import ChannelTableModal from "../../channel/ChannelTableModal";
  20. import type { IChannel } from "../../channel/Channel";
  21. const { TextArea } = Input;
  22. const { Paragraph } = Typography;
  23. interface IWidget {
  24. type?: ArticleType;
  25. articleId?: string;
  26. title?: string;
  27. style?: TDisplayStyle;
  28. channel?: string | null;
  29. onSelect?: Function;
  30. onCancel?: Function;
  31. }
  32. const ArticleTplWidget = ({
  33. type,
  34. articleId,
  35. channel,
  36. title,
  37. style = "modal",
  38. }: IWidget) => {
  39. const intl = useIntl(); //i18n
  40. const [currTitle, setCurrTitle] = useState(title);
  41. const [currChannel, setCurrChannel] = useState(channel);
  42. const [styleText, setStyleText] = useState(style);
  43. const [typeText, setTypeText] = useState(type);
  44. const [idText, setIdText] = useState(articleId);
  45. const [tplText, setTplText] = useState("");
  46. const user = useAppSelector(currentUser);
  47. const ids = articleId?.split("_");
  48. const id1 = ids ? ids[0] : undefined;
  49. const channels = ids
  50. ? ids.length > 1
  51. ? ids?.slice(1)
  52. : undefined
  53. : undefined;
  54. useEffect(() => {
  55. setCurrTitle(title);
  56. }, [title]);
  57. useEffect(() => {
  58. let tplText = `{{article|\n`;
  59. tplText += `type=${typeText}|\n`;
  60. tplText += `id=${idText}|\n`;
  61. tplText += `title=${currTitle}|\n`;
  62. tplText += currChannel ? `channel=${currChannel}|\n` : "";
  63. tplText += `style=${styleText}`;
  64. tplText += channels ? `channel=${channels}` : "";
  65. tplText += "}}";
  66. setTplText(tplText);
  67. }, [currTitle, styleText, type, id1, channels, typeText, idText]);
  68. return (
  69. <>
  70. <Space orientation="vertical" style={{ width: 500 }}>
  71. <Space style={{ width: 500 }}>
  72. {"标题:"}
  73. <Input
  74. width={400}
  75. value={currTitle}
  76. placeholder="Title"
  77. onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
  78. setCurrTitle(event.target.value);
  79. }}
  80. />
  81. </Space>
  82. <Space>
  83. {"类别:"}
  84. <Select
  85. disabled={type ? true : false}
  86. defaultValue={type}
  87. style={{ width: 120 }}
  88. onChange={(value: string) => {
  89. console.log(`selected ${value}`);
  90. setTypeText(value as ArticleType);
  91. }}
  92. options={["article", "chapter", "para"].map((item) => {
  93. return { value: item, label: item };
  94. })}
  95. />
  96. </Space>
  97. <Space style={{ width: 500 }}>
  98. {"id:"}
  99. <Space>
  100. <Input
  101. disabled={articleId ? true : false}
  102. defaultValue={articleId}
  103. width={400}
  104. value={idText}
  105. placeholder="Id"
  106. onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
  107. setIdText(event.target.value);
  108. }}
  109. />
  110. {typeText === "article" ? (
  111. <ArticleListModal
  112. studioName={user?.realName}
  113. trigger={<Button icon={<FolderOpenOutlined />} type="text" />}
  114. multiple={false}
  115. onSelect={(id: string, title: string) => {
  116. setIdText(id);
  117. setCurrTitle(title);
  118. }}
  119. />
  120. ) : undefined}
  121. </Space>
  122. </Space>
  123. <Space style={{ width: 500 }}>
  124. {"channel:"}
  125. <Space>
  126. <Input
  127. defaultValue={channel ?? ""}
  128. width={400}
  129. value={currChannel ?? ""}
  130. placeholder="channel"
  131. onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
  132. setCurrChannel(event.target.value);
  133. }}
  134. />
  135. <ChannelTableModal
  136. trigger={<Button icon={<FolderOpenOutlined />} type="text" />}
  137. onSelect={(channel: IChannel) => {
  138. setCurrChannel(channel.id);
  139. }}
  140. />
  141. </Space>
  142. </Space>
  143. <Space>
  144. {"显示为:"}
  145. <Select
  146. defaultValue={style}
  147. style={{ width: 120 }}
  148. onChange={(value: string) => {
  149. console.log(`selected ${value}`);
  150. setStyleText(value as TDisplayStyle);
  151. }}
  152. options={["modal", "card", "toggle", "link"].map((item) => {
  153. return { value: item, label: item };
  154. })}
  155. />
  156. </Space>
  157. <Tabs
  158. size="small"
  159. defaultActiveKey="preview"
  160. items={[
  161. {
  162. label: intl.formatMessage({
  163. id: "buttons.preview",
  164. }),
  165. key: "preview",
  166. children: (
  167. <ArticleCtl
  168. type={typeText}
  169. id={idText}
  170. title={currTitle}
  171. style={styleText}
  172. />
  173. ),
  174. },
  175. {
  176. label: `Code`,
  177. key: "code",
  178. children: (
  179. <TextArea
  180. value={tplText}
  181. rows={4}
  182. placeholder="maxLength is 6"
  183. maxLength={6}
  184. />
  185. ),
  186. },
  187. ]}
  188. />
  189. <Divider></Divider>
  190. <Paragraph copyable={{ text: tplText }}>复制到剪贴板</Paragraph>
  191. </Space>
  192. </>
  193. );
  194. };
  195. interface IModalWidget {
  196. open?: boolean;
  197. type?: ArticleType;
  198. articleId?: string;
  199. channelsId?: string | null;
  200. title?: string;
  201. style?: TDisplayStyle;
  202. trigger?: JSX.Element;
  203. onClose?: () => void;
  204. }
  205. export const ArticleTplModal = ({
  206. open = false,
  207. type,
  208. articleId,
  209. channelsId,
  210. title,
  211. style = "modal",
  212. trigger,
  213. onClose,
  214. }: IModalWidget) => {
  215. const [isModalOpen, setIsModalOpen] = useState(open);
  216. useEffect(() => setIsModalOpen(open), [open]);
  217. const showModal = () => {
  218. setIsModalOpen(true);
  219. };
  220. const handleOk = () => {
  221. setIsModalOpen(false);
  222. };
  223. const handleCancel = () => {
  224. if (onClose) {
  225. onClose();
  226. } else {
  227. setIsModalOpen(false);
  228. }
  229. };
  230. return (
  231. <>
  232. <span onClick={showModal}>{trigger}</span>
  233. <Modal
  234. width={"80%"}
  235. title="生成模版"
  236. open={isModalOpen}
  237. onOk={handleOk}
  238. onCancel={handleCancel}
  239. destroyOnClose
  240. >
  241. <ArticleTplWidget
  242. type={type}
  243. articleId={articleId}
  244. channel={channelsId}
  245. title={title}
  246. style={style}
  247. />
  248. </Modal>
  249. </>
  250. );
  251. };
  252. export default ArticleTplWidget;