张延森 4 年之前
父節點
當前提交
4fd333961b
共有 4 個檔案被更改,包括 119 行新增65 行删除
  1. 9
    0
      src/components/DndTr/Provider.jsx
  2. 24
    0
      src/components/DndTr/index.jsx
  3. 48
    65
      src/pages/Cms/Hot/List/index.jsx
  4. 38
    0
      src/utils/hooks/useDnD.js

+ 9
- 0
src/components/DndTr/Provider.jsx 查看文件

1
+import React from 'react'
2
+import { DndProvider } from 'react-dnd'
3
+import { HTML5Backend } from 'react-dnd-html5-backend'
4
+
5
+export default (props) => {
6
+  return (
7
+    <DndProvider backend={HTML5Backend}><tbody>{props.children}</tbody></DndProvider>
8
+  )
9
+}

+ 24
- 0
src/components/DndTr/index.jsx 查看文件

1
+import React, { useRef } from 'react'
2
+import useDnd from '@/utils/hooks/useDnd'
3
+
4
+export default (props) => {
5
+  const ref = useRef();
6
+  const { index, bizId, moveRow, ...restProps } = props;
7
+  const { dragPreview, dragSource, dropTarget, onDrop } = useDnd({
8
+    item: { index, id: bizId },
9
+  });
10
+
11
+  onDrop((item) => {
12
+    moveRow({
13
+      source: item,
14
+      target: { index, id: bizId }
15
+    });
16
+  });
17
+
18
+  dragPreview(ref)
19
+  dragSource(dropTarget(ref))
20
+
21
+  return (
22
+    <tr ref={ref} {...restProps} />
23
+  )
24
+}

+ 48
- 65
src/pages/Cms/Hot/List/index.jsx 查看文件

1
-import React, { useRef, useCallback, useState } from 'react';
1
+import React, { useRef, useCallback, useState, useMemo } 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 { sortableContainer, sortableElement, sortableHandle } from 'react-sortable-hoc';
8
 import request, { queryTable } from '@/utils/request';
7
 import request, { queryTable } from '@/utils/request';
9
-import arrayMove from 'array-move';
10
-
11
-const DragHandle = sortableHandle(() => <MenuOutlined style={{ cursor: 'grab', color: '#999' }} />);
12
-
13
-const SortableItem = sortableElement((props) => <tr {...props} />);
14
-const SortableContainer = sortableContainer((props) => <tbody {...props} />);
8
+import DnDProvider from '@/components/DndTr/Provider';
9
+import DndTr from '@/components/DndTr';
15
 
10
 
16
 const typeList = { post: '科普' };
11
 const typeList = { post: '科普' };
17
-// const stateList = { post: '科普' };
18
 
12
 
19
 const HotList = () => {
13
 const HotList = () => {
20
-  const [, setLoading] = useState(false);
21
-  const [dataSource, setDataSource] = useState([]);
22
-  const ref = useRef();
14
+  const [forceUpdate, setForceUpdate] = useState(1)
15
+  const actRef = useRef()
16
+
17
+  // eslint-disable-next-line react-hooks/exhaustive-deps
18
+  const RowWrapper = useMemo(() => DndTr, [forceUpdate])
19
+
20
+  const tableWrapper = useMemo(() => ({
21
+    body: {
22
+      wrapper: DnDProvider,
23
+      row: RowWrapper,
24
+    },
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
+
23
   const handleHotClick = useCallback((id) => {
42
   const handleHotClick = useCallback((id) => {
24
     history.push(id ? `/cms/hot/edit?id=${id}` : '/cms/hot/edit');
43
     history.push(id ? `/cms/hot/edit?id=${id}` : '/cms/hot/edit');
25
   }, []);
44
   }, []);
36
     request(`/topic/${id}`, { method: 'delete' })
55
     request(`/topic/${id}`, { method: 'delete' })
37
       .then(() => {
56
       .then(() => {
38
         notification.success({ message: '删除成功' });
57
         notification.success({ message: '删除成功' });
39
-        ref.current.submit();
58
+        // ref.current.submit();
40
       })
59
       })
41
       .catch((e) => {
60
       .catch((e) => {
42
         setLoading(false);
61
         setLoading(false);
54
       .then(() => {
73
       .then(() => {
55
         notification.info({ message: '修改成功' });
74
         notification.info({ message: '修改成功' });
56
         setLoading(false);
75
         setLoading(false);
57
-        ref.current.submit();
76
+        // ref.current.submit();
58
       })
77
       })
59
       .catch((e) => {
78
       .catch((e) => {
60
         notification.error({ message: e.message });
79
         notification.error({ message: e.message });
68
       title: '排序',
87
       title: '排序',
69
       dataIndex: 'sort',
88
       dataIndex: 'sort',
70
       width: 60,
89
       width: 60,
71
-      className: 'drag-visible',
72
       hideInSearch: true,
90
       hideInSearch: true,
73
       align: 'center',
91
       align: 'center',
74
-      render: () => <DragHandle />,
92
+      render: () => (<MenuOutlined style={{ cursor: 'grab', color: '#999' }} />),
75
     },
93
     },
76
     {
94
     {
77
       title: '主图',
95
       title: '主图',
112
       hideInSearch: true,
130
       hideInSearch: true,
113
       render: (text, record) => (
131
       render: (text, record) => (
114
         <Space size="middle">
132
         <Space size="middle">
115
-           <a key="status" onClick={() => changeStatus(record)}>
116
-            {record.status === 1 ? '用' : '启用'}
133
+          <a key="status" onClick={() => changeStatus(record)}>
134
+            {record.status === 1 ? '用' : '启用'}
117
           </a>
135
           </a>
118
           <a onClick={() => handleHotClick(record.serialNo)}>编辑</a>
136
           <a onClick={() => handleHotClick(record.serialNo)}>编辑</a>
119
           <Popconfirm
137
           <Popconfirm
130
     },
148
     },
131
   ];
149
   ];
132
 
150
 
133
-  const onSortEnd = ({ oldIndex, newIndex }) => {
134
-    // const { dataSource } = this.state;
135
-    console.log('Sorted items: ', dataSource, oldIndex, newIndex);
136
-    if (oldIndex !== newIndex) {
137
-      const newData = arrayMove([].concat(dataSource), oldIndex, newIndex).filter((el) => !!el);
138
-      console.log('Sorted items: ', newData);
139
-      //   this.setState({ dataSource: newData });
140
-      setDataSource(newData);
141
-    }
142
-  };
151
+  const handleRow = useCallback((record) => ({
152
+    index: record.sortNo,
153
+    bizId: record.serialNo,
154
+    moveRow,
143
 
155
 
144
-  const DraggableContainer = (props) => (
145
-    <SortableContainer
146
-      useDragHandle
147
-      disableAutoscroll
148
-      helperClass="row-dragging"
149
-      onSortEnd={onSortEnd}
150
-      {...props}
151
-    />
152
-  );
153
-
154
-  const DraggableBodyRow = ({ className, style, ...restProps }) => {
155
-    // const { dataSource } = this.state;
156
-    // function findIndex base on Table rowKey props and should always be a right array index
157
-    console.log(restProps, dataSource, 'restProps');
158
-    const index = dataSource?.findIndex((x) => x.serialNo === restProps['data-row-key']);
159
-    return <SortableItem index={index} {...restProps} />;
160
-  };
161
-
162
-  const getData = (params, sort, filter) => {
163
-    return queryTable('/topic')(params, sort, filter).then((res) => {
164
-      setDataSource(res.data);
165
-      return res;
166
-    });
167
-  };
156
+  // eslint-disable-next-line react-hooks/exhaustive-deps
157
+  }), [forceUpdate])
168
 
158
 
169
   return (
159
   return (
170
     <PageContainer>
160
     <PageContainer>
171
       <ProTable
161
       <ProTable
162
+        pagination={false}
172
         columns={columns}
163
         columns={columns}
173
-        dataSource={dataSource}
174
-        request={getData}
175
-        postData={(data) => data}
176
-        formRef={ref}
164
+        actionRef={actRef}
165
+        request={queryTable('/topic')}
177
         rowKey="serialNo"
166
         rowKey="serialNo"
178
         headerTitle="科普列表"
167
         headerTitle="科普列表"
179
-        search={{
180
-          labelWidth: '4em',
181
-        }}
182
-        components={{
183
-          body: {
184
-            wrapper: DraggableContainer,
185
-            row: DraggableBodyRow,
186
-          },
187
-        }}
168
+        search={{ labelWidth: '4em' }}
169
+        components={tableWrapper}
170
+        onRow={handleRow}
188
         toolBarRender={() => actions}
171
         toolBarRender={() => actions}
189
       />
172
       />
190
     </PageContainer>
173
     </PageContainer>

+ 38
- 0
src/utils/hooks/useDnD.js 查看文件

1
+import { useRef } from "react";
2
+import { useDrag, useDrop } from "react-dnd";
3
+
4
+export default function useDnD(options, deps) {
5
+  const dndType = 'dnd_item';
6
+  const handleDrop = useRef(x => x);
7
+
8
+  const [{ isDragging }, dragSource, dragPreview ] = useDrag(() => ({
9
+    type: options.type || dndType,
10
+    item: options.item,
11
+    collect: (monitor) => ({
12
+      isDragging: monitor.isDragging(),
13
+    }),
14
+  }), deps)
15
+
16
+  const [{ isOver }, dropTarget ]  = useDrop(() => ({
17
+    accept: options.type || dndType,
18
+    collect: (monitor) => ({
19
+      isOver: monitor.isOver(),
20
+    }),
21
+    drop: (item) => {
22
+      handleDrop.current(item)
23
+    }
24
+  }), deps)
25
+
26
+  const onDrop = (cb) => {
27
+    handleDrop.current = cb
28
+  }
29
+
30
+  return {
31
+    dragSource,
32
+    dragPreview,
33
+    dropTarget,
34
+    isDragging,
35
+    isOver,
36
+    onDrop,
37
+  }
38
+}