weiximei před 5 roky
rodič
revize
9cf98fe42b

+ 6
- 0
config/routes.js Zobrazit soubor

@@ -357,6 +357,12 @@ export default [
357 357
                 hideInMenu: true,
358 358
                 component: './staff/list/addRole',
359 359
               },
360
+              {
361
+                path: '/staff/list/distribution',
362
+                name: '分配归属',
363
+                hideInMenu: true,
364
+                component: './staff/list/distribution',
365
+              },
360 366
             ],
361 367
           },
362 368
           {

+ 0
- 1
src/components/XForm/ImageUpload.jsx Zobrazit soubor

@@ -53,7 +53,6 @@ class ImageUpload extends React.Component {
53 53
     );
54 54
 
55 55
     const value = this.props.value;
56
-
57 56
     return (
58 57
       <Upload
59 58
         listType="picture-card"

+ 1
- 1
src/components/XForm/WrapperForm.jsx Zobrazit soubor

@@ -61,7 +61,7 @@ class WrapperForm extends React.Component {
61 61
 
62 62
   render () {
63 63
     const {fields, form, children, submitBtn, cancelBtn, ...formProps} = this.props;
64
-
64
+    console.log('fields:', fields)
65 65
     const FeildItems = (fields || []).filter(x => x).map((props, inx) => (<WrapperItem key={inx} {...props} form={form} />))
66 66
     
67 67
     return (

+ 2
- 1
src/components/XForm/WrapperItem.jsx Zobrazit soubor

@@ -122,7 +122,8 @@ const WrapperItem = props => {
122 122
         Field = <Select placeholder={placeholder} style={{ width: '100%' }} {...fieldProps}>{SelectOpts}</Select>
123 123
         break;
124 124
       case FieldTypes.ImageUploader:
125
-        Field = <ImageUploader {...fieldProps}/>
125
+        const beforeUpload = { beforeUpload: props.beforeUpload }
126
+        Field = <ImageUploader {...fieldProps} { ...beforeUpload}/>
126 127
         break;
127 128
       default:
128 129
         throw new Error(`暂时不支持的组件类型: ${type}`)

+ 60
- 0
src/pages/news/list/style.less Zobrazit soubor

@@ -55,5 +55,65 @@
55 55
     white-space: nowrap;
56 56
     overflow: hidden;
57 57
   }
58
+
59
+  .SubmitButton {
60
+    background: rgba(239,39,58,1);
61
+    border-radius: 7px;
62
+    border: 0px;
63
+  }
64
+  .SelectFrom {
65
+    width: 180px;
66
+    background: #ffffff;
67
+    border-radius: 7px;
68
+    border: 1px solid #dbdbdb;
69
+  }
70
+  .addButton {
71
+    background: #50be00;
72
+    border-radius: 4px;
73
+    border: 0px;
74
+    margin: 10px 0px;
75
+  }
76
+  .cardText {
77
+    color: #333;
78
+    display: flex;
79
+    align-items: center;
80
+    position: relative;
81
+    line-height: 1.5;
82
+    font-size: 0.106rem;
83
+    margin-bottom: 0.08rem;
84
+  
85
+  }
86
+  .cardItem{
87
+    font-size: 0.106rem;
88
+    font-weight: 400;
89
+    color: #666;
90
+    line-height: 24px;
91
+    display: flex;
92
+    align-items: center;  
93
+  }
94
+  .ediText {
95
+    font-size:  0.106rem;
96
+    color: #ff925c;
97
+    line-height: 24px;
98
+    position: absolute;
99
+    right: 0;
100
+  }
101
+  .title{
102
+    display: inline-block;
103
+    width:  0.54rem;
104
+    justify-content: space-between;
105
+    text-align: justify;
106
+    text-align-last:justify
107
+  }
108
+  
109
+  .address { 
110
+    width: 400px;
111
+    height: 24px; 
112
+    text-overflow: ellipsis; 
113
+    white-space: nowrap;
114
+    overflow: hidden;
115
+  }
116
+  
117
+  
58 118
   
59 119
   

+ 140
- 0
src/pages/staff/components/attribution.jsx Zobrazit soubor

@@ -0,0 +1,140 @@
1
+import React, { useState, useEffect } from 'react';
2
+import { Form, Icon, Input, Button, DatePicker, Select, Card, Row, Col, Pagination, Alert, Table, Avatar, Radio, Modal, Descriptions, notification } from 'antd';
3
+import moment from 'moment';
4
+import request from '../../../utils/request';
5
+import apis from '../../../services/apis';
6
+
7
+
8
+const { Option } = Select;
9
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
10
+const { Meta } = Card;
11
+
12
+/**
13
+ * 调整归属
14
+ *
15
+ * @param {*} props
16
+ * @returns
17
+ */
18
+class ModalAttribution extends React.Component {
19
+  constructor(props) {
20
+    super(props);
21
+    this.state = {
22
+       dataSource: { records: [] },
23
+       visibleData: { visible: false, realtyConsultant: '', buildingId: '', userId: '' },
24
+    }
25
+  }
26
+
27
+  // 挂载之后
28
+  componentDidMount() {
29
+    // this.getList({ pageNumber: 1, pageSize: 5 })
30
+  }
31
+
32
+  componentDidUpdate(preProps, preState) {
33
+    if (this.props.visibleData.visible !== preState.visibleData.visible) {
34
+      this.getList({ pageNumber: 1, pageSize: 5, buildingId: this.props.visibleData.buildingId })
35
+      // eslint-disable-next-line react/no-did-update-set-state
36
+      this.setState({ visibleData: this.props.visibleData });
37
+    }
38
+  }
39
+
40
+  // 弹框确定按钮
41
+  // eslint-disable-next-line react/sort-comp
42
+  handleOk() {
43
+    this.props.onCancel()
44
+  }
45
+
46
+  // 弹框取消按钮
47
+  handleCancel() {
48
+    this.props.onCancel()
49
+  }
50
+
51
+  getList(params) {
52
+    if (params.buildingId === '' || params.buildingId === null || params.buildingId === undefined) {
53
+      return
54
+    }
55
+
56
+    // 网路请求
57
+    request({ ...apis.customer.buildingConsultant, params: { ...params } }).then(res => {
58
+      const records = res.records.filter(f => f.userId !== this.state.visibleData.userId)
59
+      this.setState({ dataSource: { ...res, records, total: res.total - 1 } })
60
+    }).catch(() => {
61
+      // eslint-disable-next-line no-unused-expressions
62
+
63
+    })
64
+  }
65
+
66
+  openNotificationWithIcon = (type, message) => {
67
+    notification[type]({
68
+      message,
69
+      description:
70
+        '',
71
+    });
72
+  };
73
+
74
+   // 分页
75
+  onChange(pageNum) {
76
+    this.getList({ pageNumber: pageNum, pageSize: 5, buildingId: this.props.visibleData.buildingId })
77
+  }
78
+
79
+  // 提交
80
+  submitGm(record) {
81
+
82
+    console.log('传递之前:', record)
83
+    this.handleCancel()
84
+    this.props.onSuccess({ realtyConsultant: record.userId, name: record.userName })
85
+  }
86
+
87
+  render() {
88
+    const columns = [
89
+      // {
90
+      //   title: '编号',
91
+      //   dataIndex: 'personId',
92
+      //   key: 'personId',
93
+      // },
94
+      {
95
+        title: '姓名',
96
+        dataIndex: 'userName',
97
+        key: 'userName',
98
+      },
99
+      {
100
+        title: '电话',
101
+        dataIndex: 'phone',
102
+        key: 'phone',
103
+      },
104
+      {
105
+        title: '部门',
106
+        dataIndex: 'department',
107
+        key: 'department',
108
+      },
109
+      {
110
+        title: '岗位',
111
+        dataIndex: 'position',
112
+        key: 'position',
113
+      },
114
+      {
115
+        title: '操作',
116
+        dataIndex: 'personId',
117
+        key: 'personId',
118
+        // eslint-disable-next-line no-nested-ternary
119
+        render: (_, record) => <>{ this.props.visibleData.realtyConsultant !== record.userId && <Button type="danger" onClick={() => this.submitGm(record)}>确定</Button>}</>,
120
+      },
121
+    ]
122
+    return (
123
+      <>
124
+        <Modal
125
+            title="选择置业顾问"
126
+            width={800}
127
+            destroyOnClose="true"
128
+            footer={null}
129
+            visible={this.state.visibleData.visible}
130
+            // onOk={() => this.handleOk()}
131
+            onCancel={(e) => this.handleCancel(e)}
132
+          >
133
+            <Table rowKey="attribution" dataSource={this.state.dataSource.records} columns={columns} pagination={{ total: this.state.dataSource.total, onChange: e => this.onChange(e) }} />
134
+          </Modal>
135
+      </>
136
+    );
137
+  }
138
+}
139
+
140
+export default ModalAttribution

+ 34
- 32
src/pages/staff/list/StaffList.jsx Zobrazit soubor

@@ -1,10 +1,10 @@
1 1
 
2 2
 import React, { useState, useEffect } from 'react';
3
-import { Form, Input, Button, Icon, Select, message, Table, Divider, Row, Col, Tag, Pagination, Modal, DatePicker } from 'antd';
3
+import { Form, Input, Button, Icon, Select, message, Table, Divider, Row, Col, Tag, Pagination, Modal, DatePicker , Card, Avatar } from 'antd';
4 4
 import { FormattedMessage } from 'umi-plugin-react/locale';
5 5
 import styles from '../../style/GoodsList.less';
6 6
 import router from 'umi/router';
7
-import { Card, Avatar } from 'antd';
7
+
8 8
 import apis from '../../../services/apis';
9 9
 import request from '../../../utils/request'
10 10
 import Styles from './style.less';
@@ -14,11 +14,11 @@ const { Option } = Select;
14 14
 const { MonthPicker, RangePicker, WeekPicker } = DatePicker;
15 15
 
16 16
 // 跳转到编辑商品
17
-const toEditStaff = (userId) => () => {
17
+const toEditStaff = userId => () => {
18 18
   router.push({
19 19
     pathname: '/staff/editStaff',
20 20
     query: {
21
-      userId
21
+      userId,
22 22
     },
23 23
   });
24 24
 }
@@ -29,11 +29,11 @@ const toEditStaff = (userId) => () => {
29 29
  *
30 30
  * @returns
31 31
  */
32
-const CartBody = (props) => {
32
+const CartBody = props => {
33 33
   const { data } = props
34 34
   // console.log("data11:", data)
35 35
 
36
-  const confirm = (data) => () => {
36
+  const confirm = data => () => {
37 37
     // console.log(data, "11111")
38 38
     if (data.status === 1) {
39 39
       Modal.confirm({
@@ -41,11 +41,11 @@ const CartBody = (props) => {
41 41
         okText: '确认',
42 42
         cancelText: '取消',
43 43
         onOk () {
44
-          request({ ...apis.staff.change, urlData: { id: data.userId, type: 'off' } }).then((data) => {
45
-            message.info("操作成功")
44
+          request({ ...apis.staff.change, urlData: { id: data.userId, type: 'off' } }).then(data => {
45
+            message.info('操作成功')
46 46
             props.onFresh()
47 47
           })
48
-        }
48
+        },
49 49
       });
50 50
     } else {
51 51
       Modal.confirm({
@@ -53,23 +53,26 @@ const CartBody = (props) => {
53 53
         okText: '确认',
54 54
         cancelText: '取消',
55 55
         onOk () {
56
-          request({ ...apis.staff.change, urlData: { id: data.userId, type: 'on' } }).then((data) => {
57
-            message.info("操作成功")
56
+          request({ ...apis.staff.change, urlData: { id: data.userId, type: 'on' } }).then(data => {
57
+            message.info('操作成功')
58 58
             props.onFresh()
59 59
           })
60
-        }
60
+        },
61 61
       });
62 62
     }
63
-
64 63
   }
65 64
 
66 65
   // 员工离职
67 66
   const departure = row => {
68
-    console.log('row:', row)
69
-
70 67
     // 是置业顾问
71 68
     if (row.isConsultant === true) {
72
-
69
+      // 跳转路由
70
+      router.push({
71
+        pathname: '/staff/list/distribution',
72
+        query: {
73
+          id: row.userId,
74
+        },
75
+      })
73 76
       return
74 77
     }
75 78
 
@@ -80,13 +83,14 @@ const CartBody = (props) => {
80 83
       okText: '确认',
81 84
       cancelText: '取消',
82 85
       onOk () {
83
-        // request({ ...apis.staff.change, urlData: { id: data.userId, type: 'off' } }).then((data) => {
84
-        //   message.info("操作成功")
85
-        //   props.onFresh()
86
-        // })
87
-      }
88
-    });
86
+        request({ ...apis.staff.departure, urlData: { id: row.userId } }).then(() => {
87
+          message.info('操作成功')
88
+          props.onFresh()
89
+        }).catch(() => {
89 90
 
91
+        })
92
+      },
93
+    });
90 94
   }
91 95
 
92 96
   return (
@@ -112,9 +116,7 @@ const CartBody = (props) => {
112 116
 
113 117
         <span>
114 118
           {
115
-            data.taTagsList.map((item, index) => {
116
-              return <Tag className={Styles.cardTag} color={item.tagColor}>{item.tagName}</Tag>
117
-            })
119
+            data.taTagsList.map((item, index) => <Tag className={Styles.cardTag} color={item.tagColor}>{item.tagName}</Tag>)
118 120
           }
119 121
         </span>
120 122
 
@@ -131,21 +133,21 @@ const CartBody = (props) => {
131 133
   )
132 134
 }
133 135
 
134
-const header = (props) => {
136
+const header = props => {
135 137
   const [tempData, setTempData] = useState({ records: [] })
136 138
   useEffect(() => {
137 139
     getList({ pageNum: 1, pageSize: 8 });
138 140
   }, [])
139 141
 
140
-  const getList = (params) => {
141
-    request({ ...apis.staff.taUser, params: { ...params } }).then((data) => {
142
-      console.log(data, "listData")
142
+  const getList = params => {
143
+    request({ ...apis.staff.taUser, params: { ...params } }).then(data => {
144
+      console.log(data, 'listData')
143 145
       setTempData(data)
144 146
     })
145 147
   }
146 148
 
147 149
   // 分页
148
-  const onChange = (pageNumber) => {
150
+  const onChange = pageNumber => {
149 151
     getList({ pageNum: pageNumber, pageSize: 8, ...props.form.getFieldsValue() });
150 152
   }
151 153
 
@@ -160,7 +162,7 @@ const header = (props) => {
160 162
     });
161 163
   }
162 164
 
163
-  //重置搜索
165
+  // 重置搜索
164 166
   function handleReset () {
165 167
     props.form.resetFields();
166 168
     getList({ pageNum: 1, pageSize: 8 });
@@ -230,7 +232,7 @@ const header = (props) => {
230 232
       </Row>
231 233
 
232 234
       {/* 分页  */}
233
-      <div style={{ display: 'flex', justifyContent: 'flex-end' }}>     
235
+      <div style={{ display: 'flex', justifyContent: 'flex-end' }}>
234 236
         <Pagination showQuickJumper defaultCurrent={1} pageSize={8} total={tempData.total} onChange={onChange} current={tempData.current}/>
235 237
       </div>
236 238
     </>

+ 159
- 0
src/pages/staff/list/distribution.jsx Zobrazit soubor

@@ -0,0 +1,159 @@
1
+import React, { useState, useEffect } from 'react';
2
+import { Button, Table, message, Modal } from 'antd';
3
+
4
+import apis from '../../../services/apis';
5
+import request from '../../../utils/request';
6
+import ModalAttribution from '../components/attribution';
7
+import { router } from 'umi';
8
+
9
+function body(props) {
10
+    console.log('props.localtion.query: ', props.location.query)
11
+
12
+    const { id } = props.location.query
13
+    
14
+
15
+    // eslint-disable-next-line react-hooks/rules-of-hooks
16
+    const [dataSource, setDataSource] = useState({ records: [], current: 1, size: 10, total: 0 })
17
+    // eslint-disable-next-line react-hooks/rules-of-hooks
18
+    const [consultant, setConsultant] = useState({ consultantUserId: '', consultantName: '' })
19
+
20
+    // eslint-disable-next-line react-hooks/rules-of-hooks
21
+    const [selectedRowIndex, setSelectedRowIndex] = useState([])
22
+
23
+    // eslint-disable-next-line react-hooks/rules-of-hooks
24
+    const [customerIdList, setCustomerIdList] = useState([])
25
+
26
+    // eslint-disable-next-line react-hooks/rules-of-hooks
27
+    const [visibleData, setVisibleData] = useState({ visible: false, realtyConsultant: '', buildingId: '', userId: '' })
28
+
29
+    // eslint-disable-next-line react-hooks/rules-of-hooks
30
+    const [userData, setUserData] = useState({})
31
+
32
+    // eslint-disable-next-line react-hooks/rules-of-hooks
33
+    useEffect(() => {
34
+        if (id) {
35
+            getList({ pageNumber: 1, pageSize: 99999, userId: id })
36
+            getUserData(id)
37
+        }
38
+    }, [])
39
+
40
+    function getList(params) {
41
+        // 网路请求
42
+        request({ ...apis.customer.byUserIdSelectCustomer, urlData: { id: params.userId }, params: { ...params } }).then(res => {
43
+          setDataSource(res)
44
+        }).catch(() => {
45
+
46
+        })
47
+    }
48
+
49
+     // 查询列表
50
+    function getUserData(userId) {
51
+        request({ ...apis.staff.getTaUser, urlData: { id: userId } }).then((data) => {
52
+            setUserData(data)
53
+        })
54
+    }
55
+
56
+    function onShow() {
57
+        setVisibleData({ visible: true, realtyConsultant: '', buildingId: userData.buildingId, userId: userData.userId })
58
+    }
59
+
60
+    function onCancel() {
61
+        setVisibleData({ visible: false, realtyConsultant: '', buildingId: '', userId: '' })
62
+    }
63
+
64
+    function onSuccess({ realtyConsultant, name }) {
65
+        setConsultant({ consultantUserId: realtyConsultant, consultantName: name })
66
+    }
67
+
68
+    function onSubmit() {
69
+        if (customerIdList.length !== dataSource.total) {
70
+            message.error('存在未分配归属客户')
71
+            return
72
+        }
73
+
74
+        if (consultant.consultantId === '') {
75
+            message.error('请选择分配归属的置业顾问')
76
+            return
77
+        }
78
+
79
+        Modal.confirm({
80
+            title: '确认保存后,当前员工下的客户数据将转移',
81
+            content: '同时删除此员工所有数据,确认进行保存操作?',
82
+            okText: '确认',
83
+            cancelText: '取消',
84
+            onOk () {
85
+                request({ ...apis.staff.departure, urlData: { id: userData.userId }, params: { customerIdList, consultantUserId: consultant.consultantUserId } }).then(() => {
86
+                    message.info('操作成功')
87
+                    props.onFresh()
88
+                    router.go(-1)
89
+                }).catch(() => {
90
+          
91
+                })
92
+            },
93
+          });
94
+    }
95
+
96
+    const rowSelection = {
97
+        selectedRowKeys: selectedRowIndex,
98
+        hideDefaultSelections: true,
99
+        onChange: (selectedRowKeys, selectedRows) => {
100
+          console.log('selectedRowKeys: ', selectedRowKeys, 'selectedRows: ', selectedRows, selectedRowKeys);
101
+          setSelectedRowIndex(selectedRowKeys)
102
+          setCustomerIdList(selectedRows.map(p => p.customerId))
103
+        },
104
+    };
105
+
106
+    const columns = [
107
+        {
108
+          title: '用户名',
109
+          dataIndex: 'name',
110
+          key: 'name',
111
+          align: 'center',
112
+        },
113
+        {
114
+          title: '手机号',
115
+          dataIndex: 'phone',
116
+          align: 'center',
117
+          key: 'phone',
118
+        },
119
+        {
120
+            title: '状态',
121
+            dataIndex: 'reportRecommendStatus',
122
+            key: 'reportRecommendStatus',
123
+            align: 'center',
124
+            // eslint-disable-next-line no-nested-ternary
125
+            render: (text, records) => {
126
+              if (records.status === 1) { return '报备' }
127
+              if (records.status === 2) { return '到访' }
128
+              if (records.status === 3) { return '认筹' }
129
+              if (records.status === 4) { return '签约' }
130
+            },
131
+          },
132
+        {
133
+            title: '调整后归属',
134
+            dataIndex: 'consultantName',
135
+            key: 'consultantName',
136
+            align: 'center',
137
+            render: (text, records, index) => {
138
+                return selectedRowIndex.includes(index) ? consultant.consultantName : ''
139
+            },
140
+        },
141
+      ];
142
+
143
+    return (
144
+        <>
145
+            <Button type="primary" onClick={() => onShow()}>分配归属</Button>
146
+            <Table rowSelection={rowSelection} dataSource={dataSource.records} columns={columns} pagination={{ pageSize: dataSource.size, current: dataSource.current, total: dataSource.total }} />
147
+            <div style={{ display: 'flex', justifyContent: 'center', marginTop: '20px' }}>
148
+                <Button type="primary" onClick={() => onSubmit()}>保存</Button>
149
+                &nbsp;&nbsp;&nbsp;&nbsp;
150
+                <Button onClick={() => router.go(-1)}>取消</Button>
151
+            </div>
152
+
153
+            {/* 选择只顾问弹框 */}
154
+            <ModalAttribution visibleData={visibleData} onCancel={() => onCancel()} onSuccess={e => onSuccess(e)}/>
155
+        </>
156
+    )
157
+}
158
+
159
+export default body

+ 15
- 1
src/pages/staff/list/editStaff.jsx Zobrazit soubor

@@ -81,6 +81,19 @@ const Edit = (props) => {
81 81
     }
82 82
   }
83 83
 
84
+  const photoBeforeUpload = (file) => {
85
+    // const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
86
+    // if (!isJpgOrPng) {
87
+    //   message.error('请上传 JPG/PNG 格式的图片!');
88
+    // }
89
+    console.log(file.size, file.size / 1024)
90
+    const isLt100k = (file.size / 1024) < 100;
91
+    if (!isLt100k) {
92
+      message.error('请上传小于100k的图片!');
93
+    }
94
+    return isLt100k;
95
+  }
96
+
84 97
   const fields = [
85 98
     {
86 99
       label: '姓名',
@@ -194,8 +207,9 @@ const Edit = (props) => {
194 207
       label: '置业顾问头像',
195 208
       name: 'photo',
196 209
       type: FieldTypes.ImageUploader,
197
-      extra: '建议图片尺寸:320*320px,比例1:1,格式:jpg,用于置业顾问头像',
210
+      extra: '建议图片尺寸:320*320px,比例1:1,格式:jpg,用于置业顾问头像,限制大小:100k',
198 211
       value: userData.photo,
212
+      beforeUpload: (e) => photoBeforeUpload(e),
199 213
       rules: [
200 214
         { required: true, message: '请选择头像' },
201 215
       ]

+ 10
- 0
src/services/apis.js Zobrazit soubor

@@ -303,6 +303,11 @@ export default {
303 303
       url: `${prefix}/customer/recommend/:id`,
304 304
       action: 'admin.customer.recommend.get',
305 305
     },
306
+    byUserIdSelectCustomer: { // 根据置业顾问查询客户
307
+      method: 'GET',
308
+      url: `${prefix}/customer/list/:id`,
309
+      action: 'admin.customer.list.get',
310
+    },
306 311
   },
307 312
   indexEcharts: {
308 313
     list:{
@@ -686,6 +691,11 @@ export default {
686 691
       method: 'PUT',
687 692
       action: 'admin.turn.taUser.put',  
688 693
     },
694
+    departure: {
695
+      url: `${prefix}/user/departure/:id`,
696
+      method: 'PUT',
697
+      action: 'admin.user.departure.put',
698
+    },
689 699
   },
690 700
   channelList: {
691 701
     getList: {