张延森 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 파일 보기

@@ -0,0 +1,9 @@
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 파일 보기

@@ -0,0 +1,24 @@
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,25 +1,44 @@
1
-import React, { useRef, useCallback, useState } from 'react';
1
+import React, { useRef, useCallback, useState, useMemo } from 'react';
2 2
 import { connect, history } from 'umi';
3 3
 import { PageContainer } from '@ant-design/pro-layout';
4 4
 import ProTable from '@ant-design/pro-table';
5 5
 import { PlusOutlined, MenuOutlined } from '@ant-design/icons';
6 6
 import { Button, Popconfirm, Image, Space, notification } from 'antd';
7
-import { sortableContainer, sortableElement, sortableHandle } from 'react-sortable-hoc';
8 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 11
 const typeList = { post: '科普' };
17
-// const stateList = { post: '科普' };
18 12
 
19 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 42
   const handleHotClick = useCallback((id) => {
24 43
     history.push(id ? `/cms/hot/edit?id=${id}` : '/cms/hot/edit');
25 44
   }, []);
@@ -36,7 +55,7 @@ const HotList = () => {
36 55
     request(`/topic/${id}`, { method: 'delete' })
37 56
       .then(() => {
38 57
         notification.success({ message: '删除成功' });
39
-        ref.current.submit();
58
+        // ref.current.submit();
40 59
       })
41 60
       .catch((e) => {
42 61
         setLoading(false);
@@ -54,7 +73,7 @@ const HotList = () => {
54 73
       .then(() => {
55 74
         notification.info({ message: '修改成功' });
56 75
         setLoading(false);
57
-        ref.current.submit();
76
+        // ref.current.submit();
58 77
       })
59 78
       .catch((e) => {
60 79
         notification.error({ message: e.message });
@@ -68,10 +87,9 @@ const HotList = () => {
68 87
       title: '排序',
69 88
       dataIndex: 'sort',
70 89
       width: 60,
71
-      className: 'drag-visible',
72 90
       hideInSearch: true,
73 91
       align: 'center',
74
-      render: () => <DragHandle />,
92
+      render: () => (<MenuOutlined style={{ cursor: 'grab', color: '#999' }} />),
75 93
     },
76 94
     {
77 95
       title: '主图',
@@ -112,8 +130,8 @@ const HotList = () => {
112 130
       hideInSearch: true,
113 131
       render: (text, record) => (
114 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 135
           </a>
118 136
           <a onClick={() => handleHotClick(record.serialNo)}>编辑</a>
119 137
           <Popconfirm
@@ -130,61 +148,26 @@ const HotList = () => {
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 159
   return (
170 160
     <PageContainer>
171 161
       <ProTable
162
+        pagination={false}
172 163
         columns={columns}
173
-        dataSource={dataSource}
174
-        request={getData}
175
-        postData={(data) => data}
176
-        formRef={ref}
164
+        actionRef={actRef}
165
+        request={queryTable('/topic')}
177 166
         rowKey="serialNo"
178 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 171
         toolBarRender={() => actions}
189 172
       />
190 173
     </PageContainer>

+ 38
- 0
src/utils/hooks/useDnD.js 파일 보기

@@ -0,0 +1,38 @@
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
+}