index.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. import ReadText from '@/components/readText';
  2. import { useAjax } from '@/Hook/useAjax';
  3. import {
  4. apiBookContentShortBookInfoAdd,
  5. apiBookContentShortBookInfoBatch,
  6. apiBookContentShortBookInfoDel,
  7. apiBookContentShortBookInfoDels,
  8. apiBookContentShortBookInfoEdit,
  9. apiBookContentShortBookInfoList,
  10. apiShortBookGetInfo,
  11. } from '@/services/book/shortbookList';
  12. import { ColumnHeightOutlined, DeleteOutlined, PlusCircleOutlined } from '@ant-design/icons';
  13. import {
  14. ActionType,
  15. BetaSchemaForm,
  16. PageContainer,
  17. ProFormInstance,
  18. ProTable,
  19. } from '@ant-design/pro-components';
  20. import { useModel } from '@umijs/max';
  21. import { Button, Drawer, message, Popconfirm, Space } from 'antd';
  22. import { useEffect, useRef, useState } from 'react';
  23. import formConfig from './formConfig';
  24. import Item from './item';
  25. import { columns } from './tableConfig';
  26. const wordCountRanges: any = {
  27. '': { start: null, end: null }, // 全部
  28. '0-2': { start: 0, end: 2 * 10000 },
  29. '2-5': { start: 2 * 10000, end: 5 * 10000 },
  30. '5-10': { start: 5 * 10000, end: 10 * 10000 },
  31. '10-20': { start: 10 * 10000, end: 20 * 10000 },
  32. '20-40': { start: 20 * 10000, end: 40 * 10000 },
  33. '40-100': { start: 40 * 10000, end: 100 * 10000 },
  34. '100-150': { start: 100 * 10000, end: 150 * 10000 },
  35. '150-200': { start: 150 * 10000, end: 200 * 10000 },
  36. '200-300': { start: 200 * 10000, end: 300 * 10000 },
  37. '300-0': { start: 300 * 10000, end: null }, // 300万以上
  38. };
  39. type DataItem = {
  40. name: string;
  41. state: string;
  42. };
  43. const Page: React.FC = () => {
  44. let { state, getLabelAndClassList } = useModel('global');
  45. let [open, setOpen] = useState<any>(null); //付费配置
  46. let [editValues, setEditValues] = useState<any>({});
  47. let [workDirection, setWorkDirection] = useState<any>(null);
  48. const [openBook, setOpneBook] = useState<any>(null); //阅读小说
  49. const [editSelectedRow, setEditSelectedRow] = useState<any[]>([]); //小说列表选择
  50. // ======================API=======================
  51. let BookContentShortBookInfoList = useAjax((params) => apiBookContentShortBookInfoList(params), {
  52. type: 'table',
  53. }); //获取书籍列表
  54. let BookContentShortBookInfoAdd = useAjax((params) => apiBookContentShortBookInfoAdd(params)); //新增书籍
  55. let BookContentShortBookInfoEdit = useAjax((params) => apiBookContentShortBookInfoEdit(params)); //编辑书籍
  56. let BookContentShortBookInfoDel = useAjax((id) => apiBookContentShortBookInfoDel(id)); //单个删除书籍
  57. let BookContentShortBookInfoDels = useAjax((ids) => apiBookContentShortBookInfoDels(ids)); //批量删除书籍
  58. let BookContentShortBookInfoBatch = useAjax((params) => apiBookContentShortBookInfoBatch(params)); //批量上下架
  59. let ShortBookGetInfo = useAjax((params) => apiShortBookGetInfo(params)); //查询单个段落
  60. const formRef = useRef<ProFormInstance>();
  61. const actionRef = useRef<ActionType>();
  62. // 获取标签和分类
  63. useEffect(() => {
  64. getLabelAndClassList({ workDirection });
  65. }, [workDirection]);
  66. // 看小说
  67. const lookBook = (params: any) => {
  68. let { id, pageNum, pageSize } = params;
  69. return ShortBookGetInfo.run({ id, pageNum, pageSize }).then((res) => {
  70. setOpneBook({ ...res.data, ...params });
  71. return res.data;
  72. });
  73. };
  74. // 删除or批量删除
  75. const del = (ids: any) => {
  76. let api = Array.isArray(ids) ? BookContentShortBookInfoDels : BookContentShortBookInfoDel;
  77. api.run(ids).then((res) => {
  78. if (res.code === 200) {
  79. actionRef?.current?.reload();
  80. message.success('删除成功');
  81. setEditSelectedRow([]);
  82. }
  83. });
  84. };
  85. // 批量上下架
  86. const shelveAll = (ids: any[], shelve: 0 | 1) => {
  87. BookContentShortBookInfoBatch.run({ ids, shelve }).then((res) => {
  88. if (res.code === 200) {
  89. actionRef?.current?.reload();
  90. message.success('批量' + (shelve === 0 ? '上架成功' : '下架成功'));
  91. }
  92. });
  93. };
  94. // 提交表单
  95. const submit = async (values: any) => {
  96. let api = editValues?.id ? BookContentShortBookInfoEdit : BookContentShortBookInfoAdd;
  97. if (editValues?.id) {
  98. values.id = editValues?.id;
  99. }
  100. api.run(values).then((res) => {
  101. if (res.code === 200) {
  102. actionRef?.current?.reload();
  103. message.success('操作成功!');
  104. closeForm(false);
  105. }
  106. });
  107. };
  108. // 关闭表单弹窗和重置表单内容
  109. const closeForm = (b: boolean, values?: any) => {
  110. if (!b) {
  111. setEditValues({});
  112. formRef?.current?.resetFields?.();
  113. setOpen(b);
  114. } else {
  115. setEditValues(values);
  116. setWorkDirection(values.workDirection);
  117. setTimeout(() => {
  118. formRef?.current?.setFieldsValue(values);
  119. }, 100);
  120. setOpen(b);
  121. }
  122. };
  123. return (
  124. <PageContainer title={false} tabProps={{ type: 'card' }}>
  125. <ProTable<any, any>
  126. // 实例
  127. actionRef={actionRef}
  128. // 标题
  129. headerTitle={'短篇小说列表'}
  130. // 唯一key
  131. rowKey={(r) => r.id}
  132. // 按钮
  133. toolBarRender={() => {
  134. return [
  135. <Button
  136. type="primary"
  137. onClick={() => {
  138. setOpen(true);
  139. }}
  140. >
  141. <PlusCircleOutlined />
  142. 新增书籍
  143. </Button>,
  144. ];
  145. }}
  146. //多选
  147. rowSelection={{
  148. selectedRowKeys: editSelectedRow?.map((item: { id: any }) => item.id),
  149. onSelect: (record, selected) => {
  150. if (selected) {
  151. setEditSelectedRow([...editSelectedRow, record]);
  152. } else {
  153. setEditSelectedRow(
  154. editSelectedRow?.filter((item: { id: any }) => item.id !== record.id),
  155. );
  156. }
  157. },
  158. onSelectAll: (selected, rows, changeRows) => {
  159. if (selected) {
  160. setEditSelectedRow([...editSelectedRow, ...changeRows]);
  161. } else {
  162. let newArr = editSelectedRow?.filter((item: { id: any }) =>
  163. changeRows.every((i) => i?.id !== item?.id),
  164. );
  165. setEditSelectedRow(newArr);
  166. }
  167. },
  168. }}
  169. //多选展示栏
  170. tableAlertRender={({ selectedRowKeys, selectedRows }) => {
  171. return (
  172. <Space size={24}>
  173. <span style={{ width: 90, display: 'inline-block' }}>
  174. 已选 {selectedRowKeys.length} 项
  175. </span>
  176. <span style={{ color: 'red' }}>
  177. {selectedRows
  178. ?.map((item: { bookName: string }) => '《' + item.bookName + '》')
  179. .join()}
  180. </span>
  181. </Space>
  182. );
  183. }}
  184. // 多选后的按钮操作
  185. tableAlertOptionRender={({ selectedRowKeys }) => {
  186. return (
  187. <Space>
  188. <Popconfirm
  189. title={null}
  190. icon={null}
  191. onConfirm={() => {
  192. shelveAll(
  193. editSelectedRow?.map((item) => item.id),
  194. 0,
  195. );
  196. }}
  197. onCancel={() => {
  198. shelveAll(
  199. editSelectedRow?.map((item) => item.id),
  200. 1,
  201. );
  202. }}
  203. okText="全部上架"
  204. cancelText="全部下架"
  205. >
  206. <Button type="primary" disabled={selectedRowKeys.length === 0}>
  207. <ColumnHeightOutlined />
  208. 批量上下架
  209. </Button>
  210. </Popconfirm>
  211. <Popconfirm
  212. title={<div>确定要删除此批书籍?</div>}
  213. onConfirm={() => {
  214. del(editSelectedRow?.map((item) => item.id));
  215. }}
  216. >
  217. <Button type="primary" danger disabled={selectedRowKeys.length === 0}>
  218. <DeleteOutlined />
  219. 批量删除
  220. </Button>
  221. </Popconfirm>
  222. </Space>
  223. );
  224. }}
  225. //宽度自适应
  226. scroll={{ x: true }}
  227. // 加载
  228. loading={BookContentShortBookInfoList?.loading}
  229. // 搜索的配置
  230. search={{
  231. labelWidth: 90,
  232. searchGutter: [10, 15],
  233. }}
  234. //处理搜索数据
  235. beforeSearchSubmit={(params) => {
  236. let newParams = Object.entries(params).reduce((acc: any, [key, value]) => {
  237. // 过滤掉空值,包括空字符串和 null
  238. if (value !== '' && value != null) {
  239. acc[key] = value;
  240. }
  241. if (key === 'wordCount' && value) {
  242. let obj = wordCountRanges[value];
  243. acc['startWordCount'] = obj.start;
  244. acc['endWordCount'] = obj.end;
  245. delete acc[key];
  246. }
  247. return acc;
  248. }, {});
  249. return newParams;
  250. }}
  251. // 数据请求
  252. request={async (params) => {
  253. return await BookContentShortBookInfoList.run(params);
  254. }}
  255. // 表
  256. columns={columns({
  257. authList: state?.authList,
  258. labelList: state.labelList,
  259. categoryList: state.categoryList,
  260. enumList: state?.enumList,
  261. lookBook,
  262. closeForm,
  263. setWorkDirection,
  264. del,
  265. setEditValues,
  266. })}
  267. />
  268. {/* 新增编辑小说 */}
  269. <BetaSchemaForm<DataItem>
  270. layout="horizontal"
  271. title={!editValues?.id ? '新增书籍' : '编辑书籍'}
  272. formRef={formRef}
  273. open={open}
  274. onOpenChange={(b) => {
  275. !b && closeForm(b);
  276. }}
  277. layoutType={'ModalForm'}
  278. rowProps={{
  279. gutter: [16, 16],
  280. }}
  281. colProps={{
  282. span: 12,
  283. }}
  284. grid={true}
  285. onValuesChange={(changedValues, allValues) => {
  286. // 检查 workDirection 是否变化
  287. if ('workDirection' in changedValues) {
  288. setWorkDirection(changedValues['workDirection']);
  289. // 清空 categoryId 和 labelIds 的值
  290. formRef.current?.setFieldsValue({
  291. categoryId: undefined,
  292. labelIds: undefined,
  293. });
  294. }
  295. }}
  296. onFinish={submit}
  297. columns={formConfig({
  298. authList: state?.authList,
  299. enumList: state?.enumList,
  300. labelList: state.labelList,
  301. categoryList: state.categoryList,
  302. })}
  303. loading={BookContentShortBookInfoAdd?.loading || BookContentShortBookInfoEdit?.loading}
  304. />
  305. {/* 阅读小说 */}
  306. <Drawer
  307. open={!!openBook}
  308. placement="right"
  309. onClose={() => {
  310. setOpneBook(null);
  311. }}
  312. footer={null}
  313. width={'65%'}
  314. destroyOnClose={true}
  315. // getContainer={false}
  316. styles={{ body: { padding: 0 } }}
  317. closeIcon={false}
  318. title={<div style={{ fontSize: 20 }}>{openBook?.bookName ? openBook?.bookName : ''}</div>}
  319. >
  320. <ReadText data={openBook} next={lookBook} />
  321. </Drawer>
  322. {/* 段落管理 */}
  323. <Item data={editValues} onClose={setEditValues} />
  324. </PageContainer>
  325. );
  326. };
  327. export default Page;