index.tsx 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. import React, { useEffect, useState, useReducer } from 'react';
  2. import { PageContainer } from '@ant-design/pro-layout';
  3. import {
  4. Row,
  5. Col,
  6. Space,
  7. Button,
  8. Input,
  9. Table,
  10. Card,
  11. Select,
  12. message,
  13. Tooltip,
  14. Image,
  15. Tag,
  16. } from 'antd';
  17. import { getPlate, getPosts, enablePosts } from '@/services/tieba';
  18. import { useClassify } from '@/hooks/tieba/index';
  19. import type { initstateType, actionType } from './data';
  20. import DetailModal from './modal';
  21. import { Record } from 'immutable';
  22. const request = (url: string): Promise<any> => {
  23. return new Promise((resolve, reject) => {
  24. const xhr = new XMLHttpRequest();
  25. xhr.open('GET', url, false);
  26. xhr.onreadystatechange = function () {
  27. if (xhr.readyState === 4 && xhr.status === 200) {
  28. resolve(xhr.response);
  29. } else {
  30. reject(new Error('置换contenturl出错'));
  31. }
  32. };
  33. xhr.send();
  34. }).catch((e) => e);
  35. };
  36. const sendRequest = async (url: string) => await request(url);
  37. const initstate: initstateType = {
  38. curPage: 1,
  39. barId: '',
  40. categoryId: '',
  41. label: '',
  42. type: 0,
  43. };
  44. const reduce: React.Reducer<initstateType, actionType> = (state, action): initstateType => {
  45. const { type, value } = action;
  46. switch (type) {
  47. case 'reload':
  48. return { ...state, barId: '', categoryId: '', label: '' };
  49. case 'barId':
  50. return { ...state, barId: value };
  51. case 'curPage':
  52. return { ...state, curPage: value };
  53. case 'categoryId':
  54. return { ...state, categoryId: value };
  55. case 'label':
  56. return { ...state, label: value };
  57. case 'type':
  58. return { ...state, type: value };
  59. default:
  60. throw new Error('posts/index.tsx => reduce 参数 action 下, type类型不存在');
  61. }
  62. };
  63. const Posts: React.FC = () => {
  64. const [plateList, setPlateList] = useState([]);
  65. const [postsList, setPostsList] = useState([]);
  66. const classIfy = useClassify();
  67. const [total, setTotal] = useState(0);
  68. const [queryParams, dispatch] = useReducer(reduce, initstate);
  69. const [visible, setVissible] = useState(false);
  70. const [detailData, setDetailData] = useState({});
  71. const [loading, setLoading] = useState(false);
  72. useEffect(() => {
  73. GetPlate();
  74. GetPosts();
  75. }, []);
  76. useEffect(() => {
  77. GetPosts();
  78. }, [queryParams.curPage]);
  79. // 获取贴吧板块
  80. const GetPlate = async (): Promise<void> => {
  81. const { code, data } = await getPlate({ curPage: queryParams.curPage, pageSize: 10 });
  82. if (code === 0) {
  83. const { records } = data;
  84. setPlateList(records);
  85. }
  86. };
  87. // 获取帖子
  88. const GetPosts = async (): Promise<void> => {
  89. setLoading(true);
  90. const { code, data } = await getPosts(queryParams);
  91. setLoading(false);
  92. if (code === 0) {
  93. const { records, total: Total } = data;
  94. // eslint-disable-next-line no-plusplus
  95. for (let i = 0; i < records.length; i++) {
  96. // eslint-disable-next-line no-await-in-loop
  97. // records[i].content = records[i].contentUrl && await sendRequest(records[i]?.contentUrl)
  98. }
  99. console.log(records, 'recordsrecordsrecords');
  100. setPostsList(records);
  101. setTotal(Total);
  102. }
  103. };
  104. // 封禁帖子
  105. const EnablePosts = async (record: Record<string, any>): Promise<void> => {
  106. const $par = {
  107. id: record.id,
  108. enable: record.enable ? 0 : 1,
  109. type: queryParams.type,
  110. };
  111. const { code } = await enablePosts($par);
  112. if (code === 0) {
  113. message.success('操作成功');
  114. }
  115. GetPosts();
  116. };
  117. // 打开弹窗
  118. const openModal = (record: Record<string, any>): void => {
  119. setVissible(true);
  120. setDetailData(record);
  121. };
  122. // 关闭弹窗
  123. const closeModal = (): void => setVissible(false);
  124. // 选择barId
  125. const changeBarId = (value: string): void => dispatch({ type: 'barId', value });
  126. // 填写标题
  127. const changeLabel = (e: React.ChangeEvent<HTMLInputElement>) =>
  128. dispatch({ type: 'label', value: e.target.value });
  129. return (
  130. <PageContainer title="帖子管理">
  131. <Card>
  132. <Row gutter={[16, 16]} justify="space-between">
  133. <Col>
  134. <Space>
  135. <Select
  136. style={{ width: 200 }}
  137. placeholder="请选择贴吧板块"
  138. value={queryParams.barId || undefined}
  139. onChange={changeBarId}
  140. allowClear
  141. >
  142. {plateList.length &&
  143. plateList.map((item: Record<string, any>) => (
  144. <Select.Option key={item.id} value={item.id}>
  145. {item.label}
  146. </Select.Option>
  147. ))}
  148. </Select>
  149. <Select
  150. style={{ width: 200 }}
  151. placeholder="请选择分类"
  152. value={queryParams.categoryId || undefined}
  153. onChange={(value: string) => dispatch({ type: 'categoryId', value })}
  154. allowClear
  155. >
  156. {classIfy.length &&
  157. classIfy.map((item: Record<string, any>) => (
  158. <Select.Option key={item.id} value={item.id}>
  159. {item.label}
  160. </Select.Option>
  161. ))}
  162. </Select>
  163. <Input onChange={changeLabel} placeholder="请输入帖子标题"></Input>
  164. <Select
  165. style={{ width: 200 }}
  166. placeholder="请选择类型"
  167. value={queryParams.type}
  168. onChange={(value: number) => dispatch({ type: 'type', value })}
  169. allowClear
  170. >
  171. <Select.Option value={0}>帖子</Select.Option>
  172. <Select.Option value={1}>问答</Select.Option>
  173. </Select>
  174. </Space>
  175. </Col>
  176. <Col>
  177. <Space>
  178. <Button onClick={() => dispatch({ type: 'reload' })}>重置</Button>
  179. <Button type="primary" onClick={GetPosts}>
  180. 搜索
  181. </Button>
  182. </Space>
  183. </Col>
  184. </Row>
  185. <Table
  186. rowKey={(record) => record.id}
  187. loading={loading}
  188. style={{ marginTop: 20 }}
  189. dataSource={postsList}
  190. pagination={{ total, onChange: (page) => dispatch({ type: 'curPage', value: page }) }}
  191. >
  192. <Table.Column
  193. key="label"
  194. dataIndex="label"
  195. title="帖子标题"
  196. ellipsis
  197. width={200}
  198. render={(text, record) => (
  199. <Tooltip title={'pagesarticle'} placement="topLeft">
  200. <span>{text}</span>
  201. </Tooltip>
  202. )}
  203. />
  204. <Table.Column
  205. key="content"
  206. width={320}
  207. ellipsis
  208. dataIndex="content"
  209. title="内容"
  210. render={(text, record: Record<string, any>) => (
  211. <Tooltip placement="topLeft" title={record.content}>
  212. <span>{record.content}</span>
  213. </Tooltip>
  214. )}
  215. ></Table.Column>
  216. <Table.Column
  217. key="authorName"
  218. dataIndex="authorName"
  219. title="发布人"
  220. render={(text, record: Record<string, any>) => (
  221. <Space>
  222. <Col>
  223. <Tag color="blue"> {record.authorName} </Tag>
  224. </Col>
  225. {/* <Col>{record.createTime}</Col> */}
  226. </Space>
  227. )}
  228. />
  229. <Table.Column key="replyNum" dataIndex="replyNum" title="回帖数"></Table.Column>
  230. <Table.Column key="praiseNum" dataIndex="praiseNum" title="点赞数"></Table.Column>
  231. <Table.Column
  232. key="path"
  233. dataIndex="path"
  234. title="链接地址"
  235. render={(text, record: Record<string, any>) => (
  236. <Tooltip
  237. title={
  238. record.hasOwnProperty('coverImg')
  239. ? `/pages/article/index?id=${record.id}&type=POSTS`
  240. : `/pages/article/index?id=${record.id}&type=ISSUES`
  241. }
  242. placement="topLeft"
  243. >
  244. <span>/pages/article/index....</span>
  245. </Tooltip>
  246. )}
  247. />
  248. <Table.Column
  249. key="action"
  250. dataIndex="action"
  251. title="操作"
  252. render={(text, record: Record<string, any>) => (
  253. <Space>
  254. <a onClick={() => openModal(record)}>查看</a>
  255. <a onClick={() => EnablePosts(record)}>{record.enable ? '封禁' : '解封'}</a>
  256. </Space>
  257. )}
  258. />
  259. </Table>
  260. </Card>
  261. {/* 详情弹窗 */}
  262. <DetailModal detailData={detailData} visible={visible} closeModal={closeModal} />
  263. </PageContainer>
  264. );
  265. };
  266. export default Posts;