Your Name 4 years ago
parent
commit
9e79691bf1

+ 1
- 0
package.json View File

66
     "react-dom": "^17.0.0",
66
     "react-dom": "^17.0.0",
67
     "react-helmet-async": "^1.0.4",
67
     "react-helmet-async": "^1.0.4",
68
     "react-player": "^2.9.0",
68
     "react-player": "^2.9.0",
69
+    "react-sortable-hoc": "^2.0.0",
69
     "umi": "^3.4.1",
70
     "umi": "^3.4.1",
70
     "umi-request": "^1.0.8",
71
     "umi-request": "^1.0.8",
71
     "wangeditor": "^4.6.15"
72
     "wangeditor": "^4.6.15"

src/components/DndTr/Provider.jsx → src/components/DndRow/Provider.jsx View File


src/components/DndTr/index.jsx → src/components/DndRow/index.jsx View File

3
 
3
 
4
 export default (props) => {
4
 export default (props) => {
5
   const ref = useRef();
5
   const ref = useRef();
6
-  const { index, bizId, moveRow, ...restProps } = props;
6
+  const { id, moveRow, ...restProps } = props;
7
   const { dragPreview, dragSource, dropTarget, onDrop } = useDnd({
7
   const { dragPreview, dragSource, dropTarget, onDrop } = useDnd({
8
-    item: { index, id: bizId },
8
+    item: { id },
9
   });
9
   });
10
 
10
 
11
   onDrop((item) => {
11
   onDrop((item) => {
12
     moveRow({
12
     moveRow({
13
-      source: item,
14
-      target: { index, id: bizId }
13
+      from: item.id,
14
+      to: id,
15
     });
15
     });
16
   });
16
   });
17
 
17
 

+ 5
- 0
src/components/DragTable/DragHandle.jsx View File

1
+import React from 'react';
2
+import { sortableHandle } from 'react-sortable-hoc';
3
+import { MenuOutlined } from '@ant-design/icons';
4
+
5
+export default sortableHandle(() => <MenuOutlined style={{ cursor: 'grab', color: '#999' }} />);

+ 15
- 0
src/components/DragTable/DraggableContainer.jsx View File

1
+import React from 'react';
2
+import { sortableContainer } from 'react-sortable-hoc';
3
+import Styles from './style.less'
4
+
5
+export const SortableContainer = sortableContainer(props => <tbody {...props} />);
6
+
7
+export default (props) => (
8
+  <SortableContainer
9
+    useDragHandle
10
+    disableAutoscroll
11
+    helperClass={Styles['row-dragging']}
12
+    onSortEnd={props.onSortEnd}
13
+    {...props}
14
+  />
15
+);

+ 11
- 0
src/components/DragTable/DraggableRow.jsx View File

1
+import React from 'react';
2
+import { sortableElement } from 'react-sortable-hoc';
3
+
4
+export const SortableItem = sortableElement(props => <tr {...props} />);
5
+
6
+export default function withDraggableRow(dataSource) {
7
+  return (props) => {
8
+    const index = dataSource.current.findIndex(x => x.serialNo === props['data-row-key']);
9
+    return  <SortableItem index={index} {...props} />
10
+  }
11
+}

+ 11
- 0
src/components/DragTable/index.jsx View File

1
+import DraggableContainer, { SortableContainer } from './DraggableContainer';
2
+import withDraggableRow, { SortableItem } from './DraggableRow';
3
+import DragHandle from './DragHandle'
4
+
5
+export {
6
+  DraggableContainer,
7
+  withDraggableRow,
8
+  SortableContainer,
9
+  SortableItem,
10
+  DragHandle,
11
+}

+ 13
- 0
src/components/DragTable/style.less View File

1
+
2
+.row-dragging {
3
+  background: #fafafa;
4
+  border: 1px solid rgba(0, 0, 0, .02);
5
+
6
+  td {
7
+    // padding: 1em;
8
+  }
9
+
10
+  .drag-visible {
11
+    visibility: visible;
12
+  }
13
+}

+ 5
- 5
src/pages/Cms/Banner/List/index.jsx View File

6
 import { Button, Popconfirm, Image, Space, notification } from 'antd';
6
 import { Button, Popconfirm, Image, Space, notification } from 'antd';
7
 import { sortableContainer, sortableElement, sortableHandle } from 'react-sortable-hoc';
7
 import { sortableContainer, sortableElement, sortableHandle } from 'react-sortable-hoc';
8
 import request, { queryTable } from '@/utils/request';
8
 import request, { queryTable } from '@/utils/request';
9
-import arrayMove from 'array-move';
9
+// import arrayMove from 'array-move';
10
 
10
 
11
 const DragHandle = sortableHandle(() => <MenuOutlined style={{ cursor: 'grab', color: '#999' }} />);
11
 const DragHandle = sortableHandle(() => <MenuOutlined style={{ cursor: 'grab', color: '#999' }} />);
12
 
12
 
135
     // const { dataSource } = this.state;
135
     // const { dataSource } = this.state;
136
     console.log('Sorted items: ', dataSource, oldIndex, newIndex);
136
     console.log('Sorted items: ', dataSource, oldIndex, newIndex);
137
     if (oldIndex !== newIndex) {
137
     if (oldIndex !== newIndex) {
138
-      const newData = arrayMove([].concat(dataSource), oldIndex, newIndex).filter((el) => !!el);
139
-      console.log('Sorted items: ', newData);
140
-      //   this.setState({ dataSource: newData });
141
-      setDataSource(newData);
138
+      // const newData = arrayMove([].concat(dataSource), oldIndex, newIndex).filter((el) => !!el);
139
+      // console.log('Sorted items: ', newData);
140
+      // //   this.setState({ dataSource: newData });
141
+      // setDataSource(newData);
142
     }
142
     }
143
   };
143
   };
144
 
144
 

+ 36
- 42
src/pages/Cms/Hot/List/index.jsx View File

1
-import React, { useRef, useCallback, useState, useMemo } from 'react';
1
+import React, { useRef, useCallback, useMemo, useState } from 'react';
2
 import { connect, history } from 'umi';
2
 import { connect, history } from 'umi';
3
 import { PageContainer } from '@ant-design/pro-layout';
3
 import { PageContainer } from '@ant-design/pro-layout';
4
 import ProTable from '@ant-design/pro-table';
4
 import ProTable from '@ant-design/pro-table';
5
 import { PlusOutlined, MenuOutlined } from '@ant-design/icons';
5
 import { PlusOutlined, MenuOutlined } from '@ant-design/icons';
6
 import { Button, Popconfirm, Image, Space, notification } from 'antd';
6
 import { Button, Popconfirm, Image, Space, notification } from 'antd';
7
 import request, { queryTable } from '@/utils/request';
7
 import request, { queryTable } from '@/utils/request';
8
-import DnDProvider from '@/components/DndTr/Provider';
9
-import DndTr from '@/components/DndTr';
8
+import { DraggableContainer, withDraggableRow, DragHandle } from '@/components/DragTable'
10
 
9
 
11
 const typeList = { post: '科普' };
10
 const typeList = { post: '科普' };
12
 
11
 
13
 const HotList = () => {
12
 const HotList = () => {
14
-  const [forceUpdate, setForceUpdate] = useState(1)
13
+  const list = useRef([])
15
   const actRef = useRef()
14
   const actRef = useRef()
16
 
15
 
17
-  // eslint-disable-next-line react-hooks/exhaustive-deps
18
-  const RowWrapper = useMemo(() => DndTr, [forceUpdate])
16
+  const handleDragEnd = useCallback(
17
+    ({oldIndex, newIndex}) => {
18
+      if (oldIndex === newIndex) {
19
+        return
20
+      }
21
+
22
+      const from = list.current[oldIndex]?.serialNo
23
+      const to = list.current[newIndex]?.serialNo
24
+
25
+      console.log('----------->', from, to)
26
+  
27
+      request('/sort/topic', { method: 'PUT', data: { from, to } }).then(() => {
28
+        actRef.current.reload()
29
+      }).catch((e) => {
30
+        notification.error({ message: e.message })
31
+      })
32
+    },
33
+    [],
34
+  )
19
 
35
 
20
   const tableWrapper = useMemo(() => ({
36
   const tableWrapper = useMemo(() => ({
21
     body: {
37
     body: {
22
-      wrapper: DnDProvider,
23
-      row: RowWrapper,
38
+      wrapper: (props) => <DraggableContainer {...props} onSortEnd={handleDragEnd} />,
39
+      row: withDraggableRow(list),
24
     },
40
     },
25
-  // eslint-disable-next-line react-hooks/exhaustive-deps
26
-  }), [forceUpdate])
27
-
28
-  const moveRow = ({ source, target }) => {
29
-    console.log('--------->', source.index, target.index)
30
-    if (source.index === target.index) {
31
-      return
32
-    }
33
-
34
-    request('/sort/topic', { method: 'PUT', data: { from: source.index, to: target.index, id: source.id } }).then(() => {
35
-      actRef.current.reload()
36
-      setForceUpdate(forceUpdate + 1)
37
-    }).catch((e) => {
38
-      notification.error({ message: e.message })
39
-    })
40
-  }
41
+  }), [handleDragEnd])
41
 
42
 
42
   const handleHotClick = useCallback((id) => {
43
   const handleHotClick = useCallback((id) => {
43
     history.push(id ? `/cms/hot/edit?id=${id}` : '/cms/hot/edit');
44
     history.push(id ? `/cms/hot/edit?id=${id}` : '/cms/hot/edit');
50
   ];
51
   ];
51
 
52
 
52
   const deleteHotClick = (id) => {
53
   const deleteHotClick = (id) => {
53
-    setLoading(true);
54
-
55
     request(`/topic/${id}`, { method: 'delete' })
54
     request(`/topic/${id}`, { method: 'delete' })
56
       .then(() => {
55
       .then(() => {
57
         notification.success({ message: '删除成功' });
56
         notification.success({ message: '删除成功' });
58
         // ref.current.submit();
57
         // ref.current.submit();
59
       })
58
       })
60
       .catch((e) => {
59
       .catch((e) => {
61
-        setLoading(false);
62
         notification.error({ message: e.message });
60
         notification.error({ message: e.message });
63
       });
61
       });
64
   };
62
   };
65
 
63
 
66
   const changeStatus = (row) => {
64
   const changeStatus = (row) => {
67
-    setLoading(true);
68
-
69
     request(`/topic/${row.serialNo}`, {
65
     request(`/topic/${row.serialNo}`, {
70
       method: 'put',
66
       method: 'put',
71
       data: { ...row, status: row.status === 1 ? 0 : 1 },
67
       data: { ...row, status: row.status === 1 ? 0 : 1 },
72
     })
68
     })
73
       .then(() => {
69
       .then(() => {
74
         notification.info({ message: '修改成功' });
70
         notification.info({ message: '修改成功' });
75
-        setLoading(false);
76
         // ref.current.submit();
71
         // ref.current.submit();
77
       })
72
       })
78
       .catch((e) => {
73
       .catch((e) => {
79
         notification.error({ message: e.message });
74
         notification.error({ message: e.message });
80
-        setLoading(false);
81
         return Promise.reject(e.message);
75
         return Promise.reject(e.message);
82
       });
76
       });
83
   };
77
   };
89
       width: 60,
83
       width: 60,
90
       hideInSearch: true,
84
       hideInSearch: true,
91
       align: 'center',
85
       align: 'center',
92
-      render: () => (<MenuOutlined style={{ cursor: 'grab', color: '#999' }} />),
86
+      className: 'drag-visible',
87
+      render: () => <DragHandle />,
93
     },
88
     },
94
     {
89
     {
95
       title: '主图',
90
       title: '主图',
96
       dataIndex: 'poster',
91
       dataIndex: 'poster',
97
       hideInSearch: true,
92
       hideInSearch: true,
98
-
99
       align: 'center',
93
       align: 'center',
100
       render: (text) => <Image width={64} height={64} src={text} />,
94
       render: (text) => <Image width={64} height={64} src={text} />,
101
     },
95
     },
148
     },
142
     },
149
   ];
143
   ];
150
 
144
 
151
-  const handleRow = useCallback((record) => ({
152
-    index: record.sortNo,
153
-    bizId: record.serialNo,
154
-    moveRow,
155
-
156
-  // eslint-disable-next-line react-hooks/exhaustive-deps
157
-  }), [forceUpdate])
145
+  const requestWrapper = (...args) => {
146
+    return new Promise((resolve, reject) => {
147
+      queryTable('/topic')(...args).then((res) => {
148
+        resolve(res)
149
+        list.current = res.data
150
+      }).catch(reject)
151
+    })
152
+  }
158
 
153
 
159
   return (
154
   return (
160
     <PageContainer>
155
     <PageContainer>
162
         pagination={false}
157
         pagination={false}
163
         columns={columns}
158
         columns={columns}
164
         actionRef={actRef}
159
         actionRef={actRef}
165
-        request={queryTable('/topic')}
160
+        request={requestWrapper}
166
         rowKey="serialNo"
161
         rowKey="serialNo"
167
         headerTitle="科普列表"
162
         headerTitle="科普列表"
168
         search={{ labelWidth: '4em' }}
163
         search={{ labelWidth: '4em' }}
169
         components={tableWrapper}
164
         components={tableWrapper}
170
-        onRow={handleRow}
171
         toolBarRender={() => actions}
165
         toolBarRender={() => actions}
172
       />
166
       />
173
     </PageContainer>
167
     </PageContainer>