|
@@ -1,226 +1,247 @@
|
|
|
-import React, { useEffect, useState, useReducer } from 'react'
|
|
|
-import { PageContainer } from '@ant-design/pro-layout'
|
|
|
-import { Row, Col, Space, Button, Input, Table, Card, Select, message, Tooltip } from 'antd'
|
|
|
-
|
|
|
-import { getPlate, getPosts, enablePosts } from '@/services/tieba'
|
|
|
-
|
|
|
-import { useClassify } from '@/hooks/tieba/index'
|
|
|
-
|
|
|
-import type { initstateType, actionType } from './data'
|
|
|
-
|
|
|
-import DetailModal from './modal'
|
|
|
-
|
|
|
-const request = (url: string): Promise<any> => {
|
|
|
- return new Promise( (resolve, reject) => {
|
|
|
- const xhr = new XMLHttpRequest()
|
|
|
- xhr.open('GET', url, false)
|
|
|
- xhr.onreadystatechange = function () {
|
|
|
- if (xhr.readyState === 4 && xhr.status === 200) {
|
|
|
- resolve(xhr.response)
|
|
|
- } else {
|
|
|
- reject(new Error('置换contenturl出错'))
|
|
|
- }
|
|
|
- }
|
|
|
- xhr.send()
|
|
|
- }).catch(e => e)
|
|
|
-}
|
|
|
-
|
|
|
-const sendRequest = async (url: string ) => await request(url)
|
|
|
-
|
|
|
-const initstate: initstateType = {
|
|
|
- curPage: 1,
|
|
|
- barId: '',
|
|
|
- categoryId: '',
|
|
|
- label: '',
|
|
|
- type: 0
|
|
|
-}
|
|
|
-
|
|
|
-const reduce: React.Reducer<initstateType, actionType> = (state, action): initstateType => {
|
|
|
- const { type, value} = action
|
|
|
-
|
|
|
- switch (type) {
|
|
|
- case 'reload':
|
|
|
- return {...state, barId: '', categoryId: '', label: ''}
|
|
|
- case 'barId':
|
|
|
- return {...state, barId: value}
|
|
|
- case 'curPage':
|
|
|
- return {...state, curPage: value}
|
|
|
- case 'categoryId':
|
|
|
- return {...state, categoryId: value}
|
|
|
- case 'label':
|
|
|
- return {...state, label: value}
|
|
|
- case 'type':
|
|
|
- return {...state, type: value}
|
|
|
- default:
|
|
|
- throw new Error('posts/index.tsx => reduce 参数 action 下, type类型不存在')
|
|
|
- }
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-const Posts: React.FC = () => {
|
|
|
-
|
|
|
- const [plateList, setPlateList] = useState([])
|
|
|
-
|
|
|
- const [postsList, setPostsList] = useState([])
|
|
|
-
|
|
|
- const classIfy = useClassify()
|
|
|
-
|
|
|
- const [total, setTotal] = useState(0)
|
|
|
-
|
|
|
- const [queryParams, dispatch] = useReducer(reduce, initstate)
|
|
|
-
|
|
|
- const [visible, setVissible] = useState(false)
|
|
|
-
|
|
|
- const [detailData, setDetailData] = useState({})
|
|
|
-
|
|
|
- const [loading, setLoading] = useState(false)
|
|
|
- // 当前点击的id
|
|
|
- // const [id, setId] = useState('')
|
|
|
- // 获取贴吧板块
|
|
|
- const GetPlate = async (): Promise<void> => {
|
|
|
- const { code, data } = await getPlate({curPage: 1, pageSize: 10000})
|
|
|
-
|
|
|
- if (code === 0) {
|
|
|
- const { records } = data
|
|
|
- setPlateList(records)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 获取帖子
|
|
|
- const GetPosts = async (): Promise<void> => {
|
|
|
- setLoading(true)
|
|
|
- const { code, data} = await getPosts(queryParams)
|
|
|
- setLoading(false)
|
|
|
- if (code === 0) {
|
|
|
- const { records, total: Total } = data
|
|
|
-
|
|
|
- // eslint-disable-next-line no-plusplus
|
|
|
- for(let i = 0 ; i < records.length; i++) {
|
|
|
- // eslint-disable-next-line no-await-in-loop
|
|
|
- records[i].content = records[i].contentUrl && await sendRequest(records[i]?.contentUrl)
|
|
|
- }
|
|
|
- setPostsList(records)
|
|
|
- setTotal(Total)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 封禁帖子
|
|
|
- const EnablePosts = async (record: Record<string, any>): Promise<void> => {
|
|
|
- const $par = {
|
|
|
- id: record.id,
|
|
|
- enable: record.enable ? 0 : 1,
|
|
|
- type: queryParams.type
|
|
|
- }
|
|
|
- const { code } = await enablePosts($par)
|
|
|
- if (code === 0) {
|
|
|
- message.success('操作成功')
|
|
|
- }
|
|
|
- GetPosts()
|
|
|
- }
|
|
|
-
|
|
|
- useEffect (() =>{
|
|
|
- GetPlate()
|
|
|
- GetPosts()
|
|
|
- }, [])
|
|
|
- // 打开弹窗
|
|
|
- const openModal = (record: Record<string, any>): void => {
|
|
|
- setVissible(true)
|
|
|
- setDetailData(record)
|
|
|
- }
|
|
|
- // 关闭弹窗
|
|
|
- const closeModal = (): void => setVissible(false)
|
|
|
-
|
|
|
- // 选择barId
|
|
|
- const changeBarId = (value: string): void => dispatch({type: 'barId', value})
|
|
|
- // 填写标题
|
|
|
- const changeLabel = (e: React.ChangeEvent<HTMLInputElement>): void => dispatch({type: 'label', value: e.target.value})
|
|
|
-
|
|
|
- return (
|
|
|
- <PageContainer title="帖子管理">
|
|
|
- <Card>
|
|
|
- <Row gutter={[16, 16]} justify="space-between">
|
|
|
- <Col>
|
|
|
- <Space>
|
|
|
- <Select
|
|
|
- style={{width: 200}}
|
|
|
- placeholder="请选择贴吧板块"
|
|
|
- value={queryParams.barId || undefined}
|
|
|
- onChange={changeBarId}
|
|
|
- >
|
|
|
- {
|
|
|
- plateList.length && plateList.map( (item: Record<string, any> ) => (
|
|
|
- <Select.Option key={item.id} value={item.id}>
|
|
|
- {item.label}
|
|
|
- </Select.Option>
|
|
|
- ))
|
|
|
- }
|
|
|
- </Select>
|
|
|
- <Select
|
|
|
- style={{width: 200}}
|
|
|
- placeholder="请选择分类"
|
|
|
- value={queryParams.categoryId || undefined}
|
|
|
- onChange={(value: string) => dispatch({type: 'categoryId', value})}
|
|
|
- >
|
|
|
- {
|
|
|
- classIfy.length && classIfy.map( (item: Record<string, any> ) => (
|
|
|
- <Select.Option key={item.id} value={item.id}>
|
|
|
- {item.label}
|
|
|
- </Select.Option>
|
|
|
- ))
|
|
|
- }
|
|
|
- </Select>
|
|
|
- <Input onChange={changeLabel} placeholder="请输入帖子标题"></Input>
|
|
|
- <Select
|
|
|
- style={{width: 200}}
|
|
|
- placeholder="请选择类型"
|
|
|
- value={queryParams.type}
|
|
|
- onChange={(value: number) => dispatch({type: 'type', value})}
|
|
|
- >
|
|
|
- <Select.Option value={0}>帖子</Select.Option>
|
|
|
- <Select.Option value={1}>问答</Select.Option>
|
|
|
- </Select>
|
|
|
- </Space>
|
|
|
- </Col>
|
|
|
- <Col>
|
|
|
- <Space>
|
|
|
- <Button onClick={() => dispatch({type: 'reload'})}>重置</Button>
|
|
|
- <Button type="primary" onClick={GetPosts}>搜索</Button>
|
|
|
- </Space>
|
|
|
- </Col>
|
|
|
- </Row>
|
|
|
- <Table rowKey={ record => record.id } loading={loading} style={{marginTop: 20}} dataSource={postsList} pagination={{total, onChange: (page) => dispatch({type: 'curPage', value: page})}}>
|
|
|
- <Table.Column key="label" dataIndex="label" title="帖子标题" ></Table.Column>
|
|
|
- <Table.Column key="content" width={320} ellipsis dataIndex="content" title="内容"
|
|
|
- render={(text, record: Record<string, any>) => (
|
|
|
- <Tooltip placement="topLeft" title={record.content}>
|
|
|
- <span>{record.content}</span>
|
|
|
- </Tooltip>
|
|
|
- )}
|
|
|
- ></Table.Column>
|
|
|
- <Table.Column key="authorName" dataIndex="authorName" title="发布人"
|
|
|
- render={(text, record: Record<string, any>) => (
|
|
|
- <Row >
|
|
|
- <Col>{record.authorName}</Col>
|
|
|
- <Col>{record.createTime}</Col>
|
|
|
- </Row>
|
|
|
- )} />
|
|
|
- <Table.Column key="answerNum" dataIndex="answerNum" title="回帖数" ></Table.Column>
|
|
|
- <Table.Column key="praiseNum" dataIndex="praiseNum" title="点赞数" ></Table.Column>
|
|
|
- <Table.Column key="action" dataIndex="action" title="操作"
|
|
|
- render={(text, record: Record<string, any>) => (
|
|
|
- <Space>
|
|
|
- <a onClick={() => openModal(record)}>查看</a>
|
|
|
- <a onClick={() => EnablePosts(record)}>{record.enable? '封禁' : '解封'}</a>
|
|
|
- </Space>
|
|
|
- )}
|
|
|
- />
|
|
|
- </Table>
|
|
|
- </Card>
|
|
|
- {/* 详情弹窗 */}
|
|
|
- <DetailModal detailData={detailData} visible={visible} closeModal={closeModal} />
|
|
|
- </PageContainer>
|
|
|
- )
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-export default Posts
|
|
|
+import React, { useEffect, useState, useReducer } from 'react';
|
|
|
+import { PageContainer } from '@ant-design/pro-layout';
|
|
|
+import { Row, Col, Space, Button, Input, Table, Card, Select, message, Tooltip, Image } from 'antd';
|
|
|
+
|
|
|
+import { getPlate, getPosts, enablePosts } from '@/services/tieba';
|
|
|
+
|
|
|
+import { useClassify } from '@/hooks/tieba/index';
|
|
|
+
|
|
|
+import type { initstateType, actionType } from './data';
|
|
|
+
|
|
|
+import DetailModal from './modal';
|
|
|
+
|
|
|
+const request = (url: string): Promise<any> => {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ const xhr = new XMLHttpRequest();
|
|
|
+ xhr.open('GET', url, false);
|
|
|
+ xhr.onreadystatechange = function () {
|
|
|
+ if (xhr.readyState === 4 && xhr.status === 200) {
|
|
|
+ resolve(xhr.response);
|
|
|
+ } else {
|
|
|
+ reject(new Error('置换contenturl出错'));
|
|
|
+ }
|
|
|
+ };
|
|
|
+ xhr.send();
|
|
|
+ }).catch((e) => e);
|
|
|
+};
|
|
|
+
|
|
|
+const sendRequest = async (url: string) => await request(url);
|
|
|
+
|
|
|
+const initstate: initstateType = {
|
|
|
+ curPage: 1,
|
|
|
+ barId: '',
|
|
|
+ categoryId: '',
|
|
|
+ label: '',
|
|
|
+ type: 0,
|
|
|
+};
|
|
|
+
|
|
|
+const reduce: React.Reducer<initstateType, actionType> = (state, action): initstateType => {
|
|
|
+ const { type, value } = action;
|
|
|
+
|
|
|
+ switch (type) {
|
|
|
+ case 'reload':
|
|
|
+ return { ...state, barId: '', categoryId: '', label: '' };
|
|
|
+ case 'barId':
|
|
|
+ return { ...state, barId: value };
|
|
|
+ case 'curPage':
|
|
|
+ return { ...state, curPage: value };
|
|
|
+ case 'categoryId':
|
|
|
+ return { ...state, categoryId: value };
|
|
|
+ case 'label':
|
|
|
+ return { ...state, label: value };
|
|
|
+ case 'type':
|
|
|
+ return { ...state, type: value };
|
|
|
+ default:
|
|
|
+ throw new Error('posts/index.tsx => reduce 参数 action 下, type类型不存在');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const Posts: React.FC = () => {
|
|
|
+ const [plateList, setPlateList] = useState([]);
|
|
|
+
|
|
|
+ const [postsList, setPostsList] = useState([]);
|
|
|
+
|
|
|
+ const classIfy = useClassify();
|
|
|
+
|
|
|
+ const [total, setTotal] = useState(0);
|
|
|
+
|
|
|
+ const [queryParams, dispatch] = useReducer(reduce, initstate);
|
|
|
+
|
|
|
+ const [visible, setVissible] = useState(false);
|
|
|
+
|
|
|
+ const [detailData, setDetailData] = useState({});
|
|
|
+
|
|
|
+ const [loading, setLoading] = useState(false);
|
|
|
+ // 当前点击的id
|
|
|
+ // const [id, setId] = useState('')
|
|
|
+ // 获取贴吧板块
|
|
|
+ const GetPlate = async (): Promise<void> => {
|
|
|
+ const { code, data } = await getPlate({ curPage: 1, pageSize: 10000 });
|
|
|
+
|
|
|
+ if (code === 0) {
|
|
|
+ const { records } = data;
|
|
|
+ setPlateList(records);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 获取帖子
|
|
|
+ const GetPosts = async (): Promise<void> => {
|
|
|
+ setLoading(true);
|
|
|
+ const { code, data } = await getPosts(queryParams);
|
|
|
+ setLoading(false);
|
|
|
+ if (code === 0) {
|
|
|
+ const { records, total: Total } = data;
|
|
|
+
|
|
|
+ // eslint-disable-next-line no-plusplus
|
|
|
+ for (let i = 0; i < records.length; i++) {
|
|
|
+ // eslint-disable-next-line no-await-in-loop
|
|
|
+ // records[i].content = records[i].contentUrl && await sendRequest(records[i]?.contentUrl)
|
|
|
+ }
|
|
|
+ console.log(records, 'recordsrecordsrecords');
|
|
|
+
|
|
|
+ setPostsList(records);
|
|
|
+ setTotal(Total);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 封禁帖子
|
|
|
+ const EnablePosts = async (record: Record<string, any>): Promise<void> => {
|
|
|
+ const $par = {
|
|
|
+ id: record.id,
|
|
|
+ enable: record.enable ? 0 : 1,
|
|
|
+ type: queryParams.type,
|
|
|
+ };
|
|
|
+ const { code } = await enablePosts($par);
|
|
|
+ if (code === 0) {
|
|
|
+ message.success('操作成功');
|
|
|
+ }
|
|
|
+ GetPosts();
|
|
|
+ };
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ GetPlate();
|
|
|
+ GetPosts();
|
|
|
+ }, []);
|
|
|
+ // 打开弹窗
|
|
|
+ const openModal = (record: Record<string, any>): void => {
|
|
|
+ setVissible(true);
|
|
|
+ setDetailData(record);
|
|
|
+ };
|
|
|
+ // 关闭弹窗
|
|
|
+ const closeModal = (): void => setVissible(false);
|
|
|
+
|
|
|
+ // 选择barId
|
|
|
+ const changeBarId = (value: string): void => dispatch({ type: 'barId', value });
|
|
|
+ // 填写标题
|
|
|
+ const changeLabel = (e: React.ChangeEvent<HTMLInputElement>): void =>
|
|
|
+ dispatch({ type: 'label', value: e.target.value });
|
|
|
+
|
|
|
+ return (
|
|
|
+ <PageContainer title="帖子管理">
|
|
|
+ <Card>
|
|
|
+ <Row gutter={[16, 16]} justify="space-between">
|
|
|
+ <Col>
|
|
|
+ <Space>
|
|
|
+ <Select
|
|
|
+ style={{ width: 200 }}
|
|
|
+ placeholder="请选择贴吧板块"
|
|
|
+ value={queryParams.barId || undefined}
|
|
|
+ onChange={changeBarId}
|
|
|
+ allowClear
|
|
|
+ >
|
|
|
+ {plateList.length &&
|
|
|
+ plateList.map((item: Record<string, any>) => (
|
|
|
+ <Select.Option key={item.id} value={item.id}>
|
|
|
+ {item.label}
|
|
|
+ </Select.Option>
|
|
|
+ ))}
|
|
|
+ </Select>
|
|
|
+ <Select
|
|
|
+ style={{ width: 200 }}
|
|
|
+ placeholder="请选择分类"
|
|
|
+ value={queryParams.categoryId || undefined}
|
|
|
+ onChange={(value: string) => dispatch({ type: 'categoryId', value })}
|
|
|
+ allowClear
|
|
|
+ >
|
|
|
+ {classIfy.length &&
|
|
|
+ classIfy.map((item: Record<string, any>) => (
|
|
|
+ <Select.Option key={item.id} value={item.id}>
|
|
|
+ {item.label}
|
|
|
+ </Select.Option>
|
|
|
+ ))}
|
|
|
+ </Select>
|
|
|
+ <Input onChange={changeLabel} placeholder="请输入帖子标题"></Input>
|
|
|
+ <Select
|
|
|
+ style={{ width: 200 }}
|
|
|
+ placeholder="请选择类型"
|
|
|
+ value={queryParams.type}
|
|
|
+ onChange={(value: number) => dispatch({ type: 'type', value })}
|
|
|
+ allowClear
|
|
|
+ >
|
|
|
+ <Select.Option value={0}>帖子</Select.Option>
|
|
|
+ <Select.Option value={1}>问答</Select.Option>
|
|
|
+ </Select>
|
|
|
+ </Space>
|
|
|
+ </Col>
|
|
|
+ <Col>
|
|
|
+ <Space>
|
|
|
+ <Button onClick={() => dispatch({ type: 'reload' })}>重置</Button>
|
|
|
+ <Button type="primary" onClick={GetPosts}>
|
|
|
+ 搜索
|
|
|
+ </Button>
|
|
|
+ </Space>
|
|
|
+ </Col>
|
|
|
+ </Row>
|
|
|
+ <Table
|
|
|
+ rowKey={(record) => record.id}
|
|
|
+ loading={loading}
|
|
|
+ style={{ marginTop: 20 }}
|
|
|
+ dataSource={postsList}
|
|
|
+ pagination={{ total, onChange: (page) => dispatch({ type: 'curPage', value: page }) }}
|
|
|
+ >
|
|
|
+ <Table.Column key="label" dataIndex="label" title="帖子标题"></Table.Column>
|
|
|
+ <Table.Column
|
|
|
+ key="content"
|
|
|
+ width={320}
|
|
|
+ ellipsis
|
|
|
+ dataIndex="content"
|
|
|
+ title="内容"
|
|
|
+ render={(text, record: Record<string, any>) => (
|
|
|
+ <Tooltip placement="topLeft" title={record.content}>
|
|
|
+ <span>{record.content}</span>
|
|
|
+ </Tooltip>
|
|
|
+ )}
|
|
|
+ ></Table.Column>
|
|
|
+ <Table.Column
|
|
|
+ key="authorName"
|
|
|
+ dataIndex="authorName"
|
|
|
+ title="发布人"
|
|
|
+ render={(text, record: Record<string, any>) => (
|
|
|
+ <Space>
|
|
|
+ <Col>{record.authorName}</Col>
|
|
|
+ <Col>{record.createTime}</Col>
|
|
|
+ </Space>
|
|
|
+ )}
|
|
|
+ />
|
|
|
+ <Table.Column key="answerNum" dataIndex="answerNum" title="回帖数"></Table.Column>
|
|
|
+ <Table.Column key="praiseNum" dataIndex="praiseNum" title="点赞数"></Table.Column>
|
|
|
+ <Table.Column
|
|
|
+ key="action"
|
|
|
+ dataIndex="action"
|
|
|
+ title="操作"
|
|
|
+ render={(text, record: Record<string, any>) => (
|
|
|
+ <Space>
|
|
|
+ <a onClick={() => openModal(record)}>查看</a>
|
|
|
+ <a onClick={() => EnablePosts(record)}>{record.enable ? '封禁' : '解封'}</a>
|
|
|
+ </Space>
|
|
|
+ )}
|
|
|
+ />
|
|
|
+ </Table>
|
|
|
+ </Card>
|
|
|
+ {/* 详情弹窗 */}
|
|
|
+ <DetailModal detailData={detailData} visible={visible} closeModal={closeModal} />
|
|
|
+ </PageContainer>
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+export default Posts;
|