提交 41a0d3f0 作者: 龚洪江

功能:话题列表

上级 e7d18ee9
...@@ -8,6 +8,7 @@ export type forumListType = InterListFunction< ...@@ -8,6 +8,7 @@ export type forumListType = InterListFunction<
description: string; description: string;
mediaVO: null; mediaVO: null;
show: number; show: number;
gambitName: string[];
userBaseInfo: { userBaseInfo: {
nickName: string; nickName: string;
userImg: string; userImg: string;
...@@ -55,4 +56,89 @@ export type checkDynamicType = InterFunction< ...@@ -55,4 +56,89 @@ export type checkDynamicType = InterFunction<
>; >;
// 话题-列表 // 话题-列表
export type listGambitType = InterFunction<any, any>; export type listGambitType = InterListFunction<
{
/**
* 话题名称
*/
gambitName?: string;
/**
* 话题属性 1普通 2热门 3推荐
*/
gambitProperty?: number;
},
{
/**
* 话题参与讨论数量
*/
discussionCount?: number;
/**
* 话题封面
*/
gambitCover?: string;
/**
* 话题图标
*/
gambitIcon?: string;
/**
* 话题名称
*/
gambitName?: string;
/**
* 话题属性
*/
gambitProperty?: number;
id: number;
/**
* 贴子数
*/
postCount?: number;
}
>;
// 话题-新增
export type addGambitType = InterFunction<
{
/**
* 话题封面
*/
gambitCover: string;
/**
* 话题图标
*/
gambitIcon: string;
/**
* 话题名称
*/
gambitName: string;
/**
* 话题属性 话题属性 1普通 2热门 3推荐
*/
gambitProperty: number;
},
any
>;
// 话题-删除
export type deleteGambitType = InterFunction<{ id: number }, any>;
// 话题-编辑
export type updateGambitType = InterFunction<
{
/**
* 话题封面
*/
gambitCover: string;
/**
* 话题图标
*/
gambitIcon: string;
/**
* 话题名称
*/
gambitName: string;
/**
* 话题属性 话题属性 1普通 2热门 3推荐
*/
gambitProperty: number;
id?: number;
},
any
>;
import { import {
addGambitType,
checkDynamicType, checkDynamicType,
deleteForumType, deleteForumType,
deleteGambitType,
forumDetailType, forumDetailType,
forumListType, forumListType,
hiddenForumType, hiddenForumType,
likeUserInfoType, likeUserInfoType,
listGambitType,
updateGambitType,
} from '~/api/interface/forumManageType'; } from '~/api/interface/forumManageType';
import axios from '~/api/request'; import axios from '~/api/request';
...@@ -27,4 +31,14 @@ export class ForumManageAPI { ...@@ -27,4 +31,14 @@ export class ForumManageAPI {
// 动态审核 // 动态审核
static checkDynamic: checkDynamicType = (params) => static checkDynamic: checkDynamicType = (params) =>
axios.get('/release/backstage/forum/checkDynamic', { params }); axios.get('/release/backstage/forum/checkDynamic', { params });
// 话题-列表
static getTopicList: listGambitType = (data) => axios.post('/release/gambit/listGambit', data);
// 话题-新增
static addGambit: addGambitType = (data) => axios.post('/release/gambit/insertGambit', data);
// 话题-删除
static deleteGambit: deleteGambitType = (params) =>
axios.get('/release/gambit/deleteGambit', { params });
// 话题-编辑
static updateGambit: updateGambitType = (data) =>
axios.post('/release/gambit/updateGambit', data);
} }
...@@ -7,6 +7,8 @@ import { InterDataType } from '~/api/interface'; ...@@ -7,6 +7,8 @@ import { InterDataType } from '~/api/interface';
import { userJoinReportDataType } from '~/api/interface/dataDashboardsType'; import { userJoinReportDataType } from '~/api/interface/dataDashboardsType';
// 数据看板-加盟返回类型 // 数据看板-加盟返回类型
type joinReportDataType = InterDataType<userJoinReportDataType>; type joinReportDataType = InterDataType<userJoinReportDataType>;
let timer: any;
const JoinInfo = () => { const JoinInfo = () => {
const [joinReportDataType, setJoinReportDataType] = useState<joinReportDataType>(); const [joinReportDataType, setJoinReportDataType] = useState<joinReportDataType>();
const [listingProducts, setListingProducts] = useState<{ label: string; value: number }[]>([]); const [listingProducts, setListingProducts] = useState<{ label: string; value: number }[]>([]);
...@@ -59,7 +61,7 @@ const JoinInfo = () => { ...@@ -59,7 +61,7 @@ const JoinInfo = () => {
series: [ series: [
{ {
type: 'pie', type: 'pie',
radius: ['40%', '70%'], radius: ['40%', '60%'],
avoidLabelOverlap: false, avoidLabelOverlap: false,
itemStyle: { itemStyle: {
normal: { normal: {
...@@ -93,8 +95,16 @@ const JoinInfo = () => { ...@@ -93,8 +95,16 @@ const JoinInfo = () => {
}); });
}; };
// 定时刷新数据
const refreshData = () => {
if (timer) clearInterval(timer);
timer = setInterval(() => {
getUserJoinReportData();
}, 600000);
};
useEffect(() => { useEffect(() => {
getUserJoinReportData(); getUserJoinReportData();
refreshData();
}, []); }, []);
return ( return (
<div className='join-info'> <div className='join-info'>
......
...@@ -8,6 +8,8 @@ import dayjs from 'dayjs'; ...@@ -8,6 +8,8 @@ import dayjs from 'dayjs';
// 数据看板-订单数据返回类型 // 数据看板-订单数据返回类型
type orderDataType = InterDataType<orderReportDataType>; type orderDataType = InterDataType<orderReportDataType>;
let timer: any;
const TradeInfo = () => { const TradeInfo = () => {
const [orderData, setOrderData] = useState<orderDataType>(); const [orderData, setOrderData] = useState<orderDataType>();
// 表格数据 // 表格数据
...@@ -82,9 +84,17 @@ const TradeInfo = () => { ...@@ -82,9 +84,17 @@ const TradeInfo = () => {
} }
}); });
}; };
// 定时刷新数据
const refreshData = () => {
if (timer) clearInterval(timer);
timer = setInterval(() => {
getOrderReportData();
}, 600000);
};
useEffect(() => { useEffect(() => {
getOrderReportData(); getOrderReportData();
refreshData();
}, []); }, []);
return ( return (
......
...@@ -9,6 +9,7 @@ type userInfoDataType = InterDataType<userReportDataType>; ...@@ -9,6 +9,7 @@ type userInfoDataType = InterDataType<userReportDataType>;
// 数据报表-信息发布返回类型 // 数据报表-信息发布返回类型
type releaseReportData = InterDataType<releaseReportDataType>; type releaseReportData = InterDataType<releaseReportDataType>;
let timer: any;
const UserInfo = () => { const UserInfo = () => {
const [userReportData, setUserReportData] = useState<userInfoDataType>(); const [userReportData, setUserReportData] = useState<userInfoDataType>();
const [releaseReportData, setReleaseReportData] = useState<releaseReportData>(); const [releaseReportData, setReleaseReportData] = useState<releaseReportData>();
...@@ -28,10 +29,19 @@ const UserInfo = () => { ...@@ -28,10 +29,19 @@ const UserInfo = () => {
} }
}); });
}; };
// 定时刷新数据
const refreshData = () => {
if (timer) clearInterval(timer);
timer = setInterval(() => {
getUserReportData();
getReleaseReportData();
}, 600000);
};
useEffect(() => { useEffect(() => {
getUserReportData(); getUserReportData();
getReleaseReportData(); getReleaseReportData();
refreshData();
}, []); }, []);
return ( return (
<div className='user-info'> <div className='user-info'>
......
import SearchBox, { searchColumns } from '~/components/search-box'; import SearchBox, { searchColumns } from '~/components/search-box';
import { Button, message, Modal, Table, Tooltip } from 'antd'; import { Button, message, Modal, Table, Tag, Tooltip } from 'antd';
import { ColumnsType } from 'antd/es/table'; import { ColumnsType } from 'antd/es/table';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import DynamicDetailModal from './components/dynamicDetailModal'; import DynamicDetailModal from './components/dynamicDetailModal';
...@@ -44,6 +44,12 @@ const DynamicList = () => { ...@@ -44,6 +44,12 @@ const DynamicList = () => {
), ),
}, },
{ {
title: '话题',
align: 'center',
dataIndex: 'gambitName',
render: (text: string[]) => text?.map((v, index) => <Tag key={index}>{v}</Tag>),
},
{
title: '作者(用户名称)', title: '作者(用户名称)',
align: 'center', align: 'center',
render: (_text: string, record) => ( render: (_text: string, record) => (
......
import { Form, Input, message, Modal, ModalProps, Select } from 'antd';
import { FC, useEffect, useState } from 'react';
import { Uploader } from '~/components/uploader';
import { UploadOutlined } from '@ant-design/icons';
import { InterListType, InterReqType } from '~/api/interface';
import { addGambitType, listGambitType } from '~/api/interface/forumManageType';
import { gambitPropertyList } from '~/utils/dictionary';
import { ForumManageAPI } from '~/api';
// 新增话题参数类型
type addTopicParams = Exclude<InterReqType<addGambitType>, undefined>;
// 话题列表返回类型
type topicListType = InterListType<listGambitType>;
interface selfProps {
onOk: () => void;
onCancel: () => void;
currentTopicItem: topicListType[0] | undefined;
}
const AddTopicModal: FC<ModalProps & selfProps> = ({ open, onCancel, onOk, currentTopicItem }) => {
const [form] = Form.useForm<addTopicParams>();
const [gambitIconFileList, setGambitIconFileList] = useState<any>([]);
const [gambitCoverFileList, setGambitCoverFileList] = useState<any>([]);
const handleOk = () => {
form.validateFields().then((values) => {
ForumManageAPI[currentTopicItem ? 'updateGambit' : 'addGambit']({
...values,
gambitName: '#' + values.gambitName + '#',
id: currentTopicItem ? currentTopicItem.id : undefined,
}).then(({ code }) => {
if (code === '200') {
message.success(currentTopicItem ? '编辑成功' : '新增成功');
form.resetFields();
setGambitIconFileList([]);
setGambitCoverFileList([]);
onOk();
}
});
});
};
const handleCancel = () => {
form.resetFields();
setGambitIconFileList([]);
setGambitCoverFileList([]);
onCancel();
};
// 图标上传成功
const gambitIconUploadSuccess = (value: any) => {
setGambitIconFileList(value);
form.setFieldValue('gambitIcon', value.length ? value[0].url : undefined);
};
// 封面上传成功
const gambitCoverUploadSuccess = (value: any) => {
setGambitCoverFileList(value);
form.setFieldValue('gambitCover', value.length ? value[0].url : undefined);
};
useEffect(() => {
if (currentTopicItem) {
form.setFieldsValue({
gambitCover: currentTopicItem.gambitCover || undefined,
gambitIcon: currentTopicItem.gambitIcon || undefined,
gambitName: currentTopicItem.gambitName,
gambitProperty: currentTopicItem.gambitProperty,
});
setGambitIconFileList(
currentTopicItem.gambitIcon
? [
{
id: Math.random(),
uid: Math.random(),
name: 'icon',
url: currentTopicItem.gambitIcon,
},
]
: [],
);
setGambitCoverFileList(
currentTopicItem.gambitCover
? [
{
id: Math.random(),
uid: Math.random(),
name: 'icon',
url: currentTopicItem.gambitCover,
},
]
: [],
);
}
}, [currentTopicItem]);
return (
<Modal title='新增话题' open={open} onOk={handleOk} onCancel={handleCancel}>
<Form labelCol={{ span: 4 }} wrapperCol={{ span: 15 }} form={form}>
<Form.Item
label='名称'
name='gambitName'
rules={[{ required: true, message: '请输入名称' }]}
>
<Input placeholder='请输入名称' maxLength={30} />
</Form.Item>
<Form.Item label='图标' name='gambitIcon'>
<Uploader
fileUpload
listType='picture-card'
fileLength={1}
onChange={gambitIconUploadSuccess}
defaultFileList={gambitIconFileList}
>
<UploadOutlined />
</Uploader>
</Form.Item>
<Form.Item label='封面' name='gambitCover'>
<Uploader
fileUpload
listType='picture-card'
fileLength={1}
onChange={gambitCoverUploadSuccess}
defaultFileList={gambitCoverFileList}
>
<UploadOutlined />
</Uploader>
</Form.Item>
<Form.Item
label='属性'
name='gambitProperty'
rules={[{ required: true, message: '请选择属性' }]}
>
<Select placeholder='请选择属性' options={gambitPropertyList}></Select>
</Form.Item>
</Form>
</Modal>
);
};
export default AddTopicModal;
import { Table } from 'antd'; import { Button, Table, Image, Tag, Modal, message } from 'antd';
import SearchBox from '~/components/search-box'; import SearchBox from '~/components/search-box';
import AddTopicModal from './components/addTopicModal';
import { useEffect, useState } from 'react';
import { ForumManageAPI } from '~/api';
import { InterListType, InterReqListType, PaginationProps } from '~/api/interface';
import { listGambitType } from '~/api/interface/forumManageType';
import { ColumnsType } from 'antd/es/table/InternalTable';
import { gambitPropertyList } from '~/utils/dictionary';
// 话题列表返回类型
type topicListType = InterListType<listGambitType>;
// 话题列表参数类型
type topicParameters = InterReqListType<listGambitType>;
const TopicList = () => { const TopicList = () => {
const tableColumns: ColumnsType<topicListType[0]> = [
{
title: '名称',
align: 'center',
dataIndex: 'gambitName',
},
{
title: '属性',
align: 'center',
dataIndex: 'gambitProperty',
render: (text: number) => (
<Tag>{gambitPropertyList.find((v) => v.value === text)?.label}</Tag>
),
},
{
title: '图标',
align: 'center',
dataIndex: 'gambitIcon',
render: (text: string) => <Image src={text} width={50} height={50} />,
},
{
title: '封面',
align: 'center',
dataIndex: 'gambitCover',
render: (text: string) => <Image src={text} width={50} height={50} />,
},
{
title: '操作',
align: 'center',
width: '20%',
render: (_text: any, record) => (
<>
<Button type='link' onClick={() => addTopicModalShowClick(record)}>
编辑
</Button>
<Button type='link' onClick={() => deleteTopic(record)}>
删除
</Button>
</>
),
},
];
const [addTopicModalShow, setAddTopicModalShow] = useState<boolean>(false);
const [pagination, setPagination] = useState<PaginationProps & { totalCount: number }>({
pageNo: 1,
pageSize: 10,
totalCount: 0,
});
const [query, setQuery] = useState<topicParameters>();
const [tableData, setTableData] = useState<topicListType>([]);
const [currentTopicItem, setCurrentTopicItem] = useState<topicListType[0]>();
// 筛选
const searchSuccess = (value: topicParameters) => {
pagination.pageSize = 10;
pagination.pageNo = 1;
setQuery(value);
getTopicList(value);
};
// 获取话题列表
const getTopicList = (query?: topicParameters) => {
ForumManageAPI.getTopicList({
pageNo: pagination.pageNo,
pageSize: pagination.pageSize,
...query,
}).then(({ result }) => {
setTableData(result.list || []);
pagination.totalCount = result.totalCount;
setPagination({ ...pagination });
});
};
// 分页
const paginationChange = (pageNo: number, pageSize: number) => {
pagination.pageNo = pageNo;
pagination.pageSize = pageSize;
getTopicList(query);
};
// 新建话题弹窗
const addTopicModalShowClick = (record?: topicListType[0]) => {
setCurrentTopicItem(record ? { ...record } : undefined);
setAddTopicModalShow(true);
};
const addTopicModalCancel = () => {
setAddTopicModalShow(false);
};
const addTopicModalShowOk = () => {
getTopicList();
setAddTopicModalShow(false);
};
// 删除话题
const deleteTopic = (record: topicListType[0]) => {
Modal.confirm({
title: '删除话题',
content: '确认删除该话题?',
onOk: () => {
ForumManageAPI.deleteGambit({ id: record.id }).then(({ code }) => {
if (code === '200') {
message.success('删除成功');
getTopicList();
}
});
},
});
};
useEffect(() => {
getTopicList();
}, []);
return ( return (
<div className='topic-list'> <div className='topic-list'>
<SearchBox /> <SearchBox
<Table bordered /> search={[
{
label: '名称',
type: 'input',
name: 'gambitName',
placeholder: '请输入名称',
},
{
label: '属性',
type: 'Select',
name: 'gambitProperty',
options: gambitPropertyList,
placeholder: '请选择属性',
},
]}
child={
<Button type='primary' onClick={() => addTopicModalShowClick()}>
新建
</Button>
}
searchData={searchSuccess}
/>
<Table
bordered
dataSource={tableData}
rowKey='id'
columns={tableColumns}
pagination={{
total: pagination.totalCount,
pageSize: pagination.pageSize,
current: pagination.pageNo,
showSizeChanger: true,
showQuickJumper: true,
onChange: (page: number, pageSize: number) => paginationChange(page, pageSize),
showTotal: (total, range) => `当前 ${range[0]}-${range[1]} 条记录 / 共 ${total} 条数据`,
}}
/>
<AddTopicModal
open={addTopicModalShow}
onCancel={addTopicModalCancel}
onOk={addTopicModalShowOk}
currentTopicItem={currentTopicItem}
/>
</div> </div>
); );
}; };
......
...@@ -47,11 +47,14 @@ const AddEditModal: React.FC<propType> = (props) => { ...@@ -47,11 +47,14 @@ const AddEditModal: React.FC<propType> = (props) => {
const [form] = Form.useForm<ReqType>(); const [form] = Form.useForm<ReqType>();
// 上传图片 // 上传图片
const [bannerTypeValue, setBannerTypeValue] = useState(0); const [bannerTypeValue, setBannerTypeValue] = useState(0);
// 封面图文件
const [bannerImgFileList, setBannerImgFileList] = useState<any>([]);
// 是否有效 // 是否有效
const [validTime, setValidTime] = useState<number>(0); const [validTime, setValidTime] = useState<number>(0);
// 关闭弹窗 // 关闭弹窗
const handleCancel = () => { const handleCancel = () => {
setBannerTypeValue(0); setBannerTypeValue(0);
setBannerImgFileList([]);
form.resetFields(); form.resetFields();
closed(); closed();
}; };
...@@ -93,6 +96,9 @@ const AddEditModal: React.FC<propType> = (props) => { ...@@ -93,6 +96,9 @@ const AddEditModal: React.FC<propType> = (props) => {
if (!open) return; if (!open) return;
if (!data) return; if (!data) return;
form.setFieldsValue(data); form.setFieldsValue(data);
setBannerImgFileList([
{ id: Math.random(), uid: Math.random(), name: 'bannerImg', url: data?.bannerImg },
]);
setBannerTypeValue(data?.bannerType); setBannerTypeValue(data?.bannerType);
if (data?.endTime && data?.startTime) { if (data?.endTime && data?.startTime) {
setValidTime(1); setValidTime(1);
...@@ -180,8 +186,11 @@ const AddEditModal: React.FC<propType> = (props) => { ...@@ -180,8 +186,11 @@ const AddEditModal: React.FC<propType> = (props) => {
fileLength={1} fileLength={1}
fileSize={10} fileSize={10}
fileType={['image/png', 'image/jpeg', 'image/jpg', 'image/gif', 'image/bmp']} fileType={['image/png', 'image/jpeg', 'image/jpg', 'image/gif', 'image/bmp']}
onChange={(e) => form.setFieldValue('bannerImg', e[0].url)} onChange={(e) => {
defaultFileList={data?.bannerImg ? [{ url: data?.bannerImg }] : []} setBannerImgFileList(e);
form.setFieldValue('bannerImg', e[0].url);
}}
defaultFileList={bannerImgFileList}
> >
<PlusOutlined /> <PlusOutlined />
</Uploader> </Uploader>
...@@ -235,9 +244,7 @@ const AddEditModal: React.FC<propType> = (props) => { ...@@ -235,9 +244,7 @@ const AddEditModal: React.FC<propType> = (props) => {
wrapperCol={{ span: 20 }} wrapperCol={{ span: 20 }}
> >
<RichText <RichText
// eslint-disable-next-line @typescript-eslint/ban-ts-comment richTextContent={form.getFieldValue('textContent')}
// @ts-ignore
value={form.getFieldValue('textContent')}
onChange={(e) => form.setFieldValue('textContent', e)} onChange={(e) => form.setFieldValue('textContent', e)}
height={250} height={250}
/> />
......
...@@ -187,3 +187,18 @@ export const fileTypeList = [ ...@@ -187,3 +187,18 @@ export const fileTypeList = [
value: 'application/vnd.openxmlformats-officedocument.presentationml.presentation', value: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
}, },
]; ];
// 话题-属性字典
export const gambitPropertyList = [
{
label: '普通',
value: 1,
},
{
label: '热门',
value: 2,
},
{
label: '推荐',
value: 3,
},
];
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论