andrew 4 년 전
부모
커밋
5b3f94026a
59개의 변경된 파일7594개의 추가작업 그리고 0개의 파일을 삭제
  1. 56
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/BasicHeat/index.jsx
  2. 36
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/BasicHeat/style.less
  3. 55
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/BatchRaise/BatchDel.jsx
  4. 59
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/BatchRaise/BatchInvalid.jsx
  5. 76
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/BatchRaise/BatchPay.jsx
  6. 82
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/BatchRaise/BatchRefund.jsx
  7. 114
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/BatchRaise/Refund.jsx
  8. 240
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/BatchRaise/style.less
  9. 77
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/BuildSelect/BuildSelect.jsx
  10. 14
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/EnDash/index.jsx
  11. 109
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/HelpDoc/index.jsx
  12. 36
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/HelpDoc/style.less
  13. 40
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/HotBlock/index.jsx
  14. 46
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/HotBlock/style.less
  15. 21
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/HouseGrid/Floor.jsx
  16. 35
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/HouseGrid/Room.jsx
  17. 15
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/HouseGrid/Unit.jsx
  18. 37
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/HouseGrid/index.js
  19. 72
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/HouseGrid/style.less
  20. 141
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/HouseInfo/index.jsx
  21. 240
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/HouseInfo/style.less
  22. 164
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/HouseListInfo/index.jsx
  23. 36
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/HouseListInfo/style.less
  24. 26
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/RaiseHelpDoc/index.jsx
  25. 36
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/RaiseHelpDoc/style.less
  26. 230
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/RaiseHouse.jsx
  27. 239
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/Refund.jsx
  28. 29
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/SalesBatchHelpDoc/index.jsx
  29. 36
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/SalesBatchHelpDoc/style.less
  30. 58
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/UserInfo/index.jsx
  31. 240
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/UserInfo/style.less
  32. 97
    0
      estateagents-admin-manager/src/pages/house/raise/edit/components/style.less
  33. 332
    0
      estateagents-admin-manager/src/pages/house/raise/list/index.jsx
  34. 132
    0
      estateagents-admin-manager/src/pages/indexEcharts/components/IntentionalCustomers.jsx
  35. 103
    0
      estateagents-admin-manager/src/pages/indexEcharts/components/NewUsers.jsx
  36. 109
    0
      estateagents-admin-manager/src/pages/indexEcharts/components/UserActive.jsx
  37. 289
    0
      estateagents-admin-manager/src/pages/indexEcharts/components/UserBehavior.jsx
  38. 291
    0
      estateagents-admin-manager/src/pages/indexEcharts/components/UserBehaviorIndex.jsx
  39. 139
    0
      estateagents-admin-manager/src/pages/indexEcharts/components/UserConversion.jsx
  40. 92
    0
      estateagents-admin-manager/src/pages/indexEcharts/components/UserSex.jsx
  41. 125
    0
      estateagents-admin-manager/src/pages/indexEcharts/components/UserSource.jsx
  42. 139
    0
      estateagents-admin-manager/src/pages/indexEcharts/components/UserSourceDetail.jsx
  43. 104
    0
      estateagents-admin-manager/src/pages/indexEcharts/components/UserSourcepie.jsx
  44. 92
    0
      estateagents-admin-manager/src/pages/indexEcharts/index.jsx
  45. 191
    0
      estateagents-admin-manager/src/pages/indexEcharts/newUsers.jsx
  46. 37
    0
      estateagents-admin-manager/src/pages/indexEcharts/styles.less
  47. 237
    0
      estateagents-admin-manager/src/pages/indexEcharts/userBehavior.jsx
  48. 207
    0
      estateagents-admin-manager/src/pages/indexEcharts/userSource.jsx
  49. 219
    0
      estateagents-admin-manager/src/pages/integralMall/GoodsList.jsx
  50. 161
    0
      estateagents-admin-manager/src/pages/integralMall/achieve.jsx
  51. 73
    0
      estateagents-admin-manager/src/pages/integralMall/editAchieve.jsx
  52. 156
    0
      estateagents-admin-manager/src/pages/integralMall/editGoods.jsx
  53. 222
    0
      estateagents-admin-manager/src/pages/integralMall/exchangeRecords.jsx
  54. 123
    0
      estateagents-admin-manager/src/pages/integralMall/verifyList.jsx
  55. 161
    0
      estateagents-admin-manager/src/pages/integralMall/writeOff.jsx
  56. 96
    0
      estateagents-admin-manager/src/pages/miniapp/editIcons.jsx
  57. 220
    0
      estateagents-admin-manager/src/pages/miniapp/menuList.jsx
  58. 354
    0
      estateagents-admin-manager/src/pages/news/list/NewsList.jsx
  59. 398
    0
      estateagents-admin-manager/src/pages/news/list/editNewsList.jsx

+ 56
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/BasicHeat/index.jsx 파일 보기

@@ -0,0 +1,56 @@
1
+import React, { PureComponent, useState, useEffect } from 'react'
2
+import { Modal, Row, Col, Table, Pagination, Button, Form, Input, Select, message } from 'antd'
3
+import EnDash from '../EnDash'
4
+import AuthButton from '@/components/AuthButton';
5
+import request from '../../../../../../utils/request';
6
+import apis from '../../../../../../services/apis';
7
+import Style from './style.less'
8
+import { router } from 'umi';
9
+import HotBlock from '../HotBlock'
10
+
11
+const BasicHeat = props => {
12
+
13
+  const houseIdList = props.houseId;
14
+  const salesBatchId = props.salesBatchId;
15
+
16
+  function handleSubmit (e) {
17
+    console.log(houseIdList, salesBatchId)
18
+    e.preventDefault();
19
+    props.form.validateFields((err, values) => {
20
+      if (!err){
21
+        request({ ...apis.house.batchUpdateRaiseHeat, data: { raiseHeat: values.raiseHeat, houseIdList , salesBatchId: salesBatchId},}).then((data) => {
22
+          message.info("修改成功")
23
+          props.onCancel(false)
24
+          props.onSuccess();
25
+        }).catch((err) => {
26
+          message.info(err.msg || err.message)
27
+        })
28
+      }
29
+    });
30
+  }
31
+
32
+  const { getFieldDecorator } = props.form;
33
+
34
+  return (
35
+    <>
36
+      <Modal footer={null} title="批量修改基础热度" visible={props.visible} onCancel={props.onCancel} width={600}>
37
+        <span>将所选{houseIdList.length}条房源预选基础热度信息修改为</span>
38
+        <Form labelCol={{ span: 7 }} wrapperCol={{ span: 12 }} onSubmit={handleSubmit}>
39
+          <Form.Item label="基础热度值" labelAlign='left'>
40
+            {getFieldDecorator('raiseHeat')(<Input placeholder='填写预选基础热度,建议为0' label='left'/>)}
41
+          </Form.Item>
42
+          <Form.Item wrapperCol={{ span: 15, offset: 10 }}>
43
+            <Button type="primary" htmlType="submit" >
44
+              提交
45
+            </Button>
46
+          </Form.Item>
47
+        </Form>
48
+        
49
+      </Modal>
50
+    </>
51
+  );
52
+}
53
+
54
+const WrappedBase = Form.create({ name: 'BasicHeat' })(BasicHeat);
55
+
56
+export default WrappedBase

+ 36
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/BasicHeat/style.less 파일 보기

@@ -0,0 +1,36 @@
1
+.article {
2
+    .section {
3
+        font-size: 16px;
4
+        line-height: 1.8em;
5
+        color: #666;
6
+
7
+        & + .section {
8
+            margin-top: 24px;
9
+        }
10
+    }
11
+
12
+    .title {
13
+        font-size: 18px;
14
+        line-height: 2em;
15
+        color: #333;
16
+    }
17
+
18
+    .subtitle {
19
+        font-size: 14px;
20
+        line-height: 1.6em;
21
+        color: #999;
22
+    }
23
+
24
+    .flex {
25
+        display: flex;
26
+        flex-wrap: wrap;
27
+
28
+        .flex-item {
29
+            margin-top: 16px;
30
+            margin-right: 8px;
31
+            flex: none;
32
+            width: 100px;
33
+            text-align: center;
34
+        }
35
+    }
36
+}

+ 55
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/BatchRaise/BatchDel.jsx 파일 보기

@@ -0,0 +1,55 @@
1
+import React, { PureComponent, useState, useEffect } from 'react'
2
+import { Modal, Row, Col, Table, Pagination, Button, Form, Input,message } from 'antd'
3
+import EnDash from '../EnDash'
4
+import AuthButton from '@/components/AuthButton';
5
+
6
+import Style from './style.less'
7
+import HotBlock from '../HotBlock'
8
+import apis from '../../../../../../services/apis';
9
+import request from '../../../../../../utils/request';
10
+
11
+const BatchDel = props => {
12
+  const taRaiseRecords = props.houseIds;
13
+  function handleSubmit (e) {
14
+    e.preventDefault();
15
+    props.form.validateFields((err, values) => {
16
+      if (!err){
17
+        request({ ...apis.house.batchDeleteRaiseRecord, data: { ...values,taRaiseRecords }, }).then((data) => {
18
+          message.info("保存成功")
19
+          props.onSuccess(false);
20
+        }).catch((err) => {
21
+          message.info(err.msg || err.message)
22
+        })
23
+      }
24
+    });
25
+  }
26
+
27
+  const { getFieldDecorator } = props.form;
28
+
29
+  return (
30
+    <>
31
+      <Modal footer={null} title="批量删除" visible={props.visible} onCancel={props.onCancel} width={600}>
32
+        <span style={{textAlign:'center'}}>将所选{taRaiseRecords.length}条认筹记录批量删除?</span>
33
+        <Form labelCol={{ span: 7 }} wrapperCol={{ span: 12 }} onSubmit={handleSubmit}>
34
+          <Form.Item wrapperCol={{ span: 15, offset: 10 }}>
35
+            <Button type="primary" htmlType="submit" >
36
+              提交
37
+            </Button>
38
+          </Form.Item>
39
+        </Form>
40
+        <div>
41
+          <font>警告:</font><br/>
42
+          <font>1.删除功能建议仅用于删除测试数据,正常业务数据使用作废功能。</font><br/>
43
+          <font>2.删除前请确认缴退费业务是否全部处理完成。</font><br/>
44
+          <font>3.若认筹单中含认筹人锁定的房源,删除认筹单后会解锁此房源。</font><br/>
45
+          <font>4.请优先使用作废操作。删除数据可能会导致关联业务异常。</font>
46
+        </div>
47
+        
48
+      </Modal>
49
+    </>
50
+  );
51
+}
52
+
53
+const WrappedBase = Form.create({ name: 'BatchDel' })(BatchDel);
54
+
55
+export default WrappedBase

+ 59
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/BatchRaise/BatchInvalid.jsx 파일 보기

@@ -0,0 +1,59 @@
1
+import React, { PureComponent, useState, useEffect } from 'react'
2
+import { Modal, Row, Col, Table, Pagination, Button, Form, Input,message } from 'antd'
3
+import EnDash from '../EnDash'
4
+import AuthButton from '@/components/AuthButton';
5
+
6
+import Style from './style.less'
7
+import HotBlock from '../HotBlock'
8
+import apis from '../../../../../../services/apis';
9
+import request from '../../../../../../utils/request';
10
+
11
+const BatchInvalid = props => {
12
+  const taRaiseRecords = props.houseIds;
13
+  function handleSubmit (e) {
14
+    e.preventDefault();
15
+    props.form.validateFields((err, values) => {
16
+      if (!err){
17
+        request({ ...apis.house.batchInvalidRaiseRecord, data: { ...values,taRaiseRecords },}).then((data) => {
18
+          message.info("保存成功")
19
+          props.onSuccess(false);
20
+        }).catch((err) => {
21
+          message.info(err.msg || err.message)
22
+        })
23
+      }
24
+    });
25
+  }
26
+
27
+  const { getFieldDecorator } = props.form;
28
+
29
+  return (
30
+    <>
31
+      <Modal footer={null} title="批量作废" visible={props.visible} onCancel={props.onCancel} width={600}>
32
+        <span>所选XX条数据中,符合作废条件的有YY条,不符合作废条件的有ZZ条。确认将YY条数据作废?</span>
33
+        <Form labelCol={{ span: 7 }} wrapperCol={{ span: 12 }} onSubmit={handleSubmit}>
34
+          <Form.Item label="作废原因" labelAlign='left'>
35
+            {getFieldDecorator('invalidReason', {
36
+              rules: [{ required: true, message: ' 请输入作废原因' }],
37
+            })(<Input label='left'/>)}
38
+          </Form.Item>
39
+          <Form.Item wrapperCol={{ span: 15, offset: 10 }}>
40
+            <Button type="primary" htmlType="submit" >
41
+              提交
42
+            </Button>
43
+          </Form.Item>
44
+        </Form>
45
+        <div>
46
+          <font style={{color:'#999'}}>作废条件:未作废的认筹单。</font><br/>
47
+          <font style={{color:'#999'}}>注意:</font><br/>
48
+          <font style={{color:'#999'}}>作废的认筹单不可继续缴费,如果需要退费,仍然可以点击退费或批量线下退费。</font><br/>
49
+          <font style={{color:'#999'}}>认筹单作废后,会释放已锁定的房源。</font>
50
+        </div>
51
+        
52
+      </Modal>
53
+    </>
54
+  );
55
+}
56
+
57
+const WrappedBase = Form.create({ name: 'BatchInvalid' })(BatchInvalid);
58
+
59
+export default WrappedBase

+ 76
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/BatchRaise/BatchPay.jsx 파일 보기

@@ -0,0 +1,76 @@
1
+import React, { PureComponent, useState, useEffect } from 'react'
2
+import { Modal, Row, Col, Table, Pagination, Button, Form, Input, Select,message } from 'antd'
3
+import EnDash from '../EnDash'
4
+import AuthButton from '@/components/AuthButton';
5
+
6
+import Style from './style.less'
7
+import HotBlock from '../HotBlock'
8
+import apis from '../../../../../../services/apis';
9
+import request from '../../../../../../utils/request';
10
+
11
+const BatchPay = props => {
12
+  const taRaiseRecords = props.houseIds;
13
+
14
+  function handleSubmit (e) {
15
+    e.preventDefault();
16
+    props.form.validateFields((err, values) => {
17
+      if (!err){
18
+        request({ ...apis.house.batchPayOfflineRaiseRecord, data: { ...values, taRaiseRecords },}).then((data) => {
19
+          message.info("保存成功")
20
+          props.onSuccess(false)
21
+        }).catch((err) => {
22
+          message.info(err.msg || err.message)
23
+        })
24
+      }
25
+    });
26
+  }
27
+
28
+  const { getFieldDecorator } = props.form;
29
+
30
+  return (
31
+    <>
32
+      <Modal footer={null} title="批量线下缴费" visible={props.visible} onCancel={props.onCancel} width={600}>
33
+        <span>所选XX条数据中,符合批量设置线下缴费条件的有YY条,不符合条件的有ZZ条。确认将YY条数据设置为:</span>
34
+        <Form labelCol={{ span: 7 }} wrapperCol={{ span: 12 }} onSubmit={handleSubmit}>
35
+          <Form.Item label="缴费状态" labelAlign='left'>
36
+            {getFieldDecorator('payStatus', {initialValue:'paid'})(
37
+                <Select style={{width: '120px'}} disabled>
38
+                <Option value="paid">已缴费</Option>
39
+              </Select>,
40
+              )}
41
+          </Form.Item>
42
+          <Form.Item label="缴费方式" labelAlign='left'>
43
+            {getFieldDecorator('payType', {initialValue:'offLine'})(
44
+                <Select style={{width: '120px'}} disabled>
45
+                <Option value="offLine">线下缴费</Option>
46
+              </Select>,
47
+              )}
48
+          </Form.Item>
49
+          <Form.Item label="线下缴费结果" labelAlign='left'>
50
+            {getFieldDecorator('payStatus', {initialValue:'paid'})(
51
+                <Select style={{width: '120px'}} disabled>
52
+                <Option value="paid">成功</Option>
53
+              </Select>,
54
+              )}
55
+          </Form.Item>
56
+          <Form.Item wrapperCol={{ span: 15, offset: 9 }}>
57
+            <Button type="primary" htmlType="submit" >
58
+              确定
59
+            </Button>
60
+          </Form.Item>
61
+        </Form>
62
+        <div>
63
+          <font style={{color:'#999'}}>可批量设置线下缴费的认筹单条件必须满足以下全部:</font><br/>
64
+          <font style={{color:'#999'}}>0.认筹单未作废。</font><br/>
65
+          <font style={{color:'#999'}}>1.当前销售批次缴费方式包含但不限于线下缴费。</font><br/>
66
+          <font style={{color:'#999'}}>2.认筹单缴费状态为未缴费。</font>
67
+        </div>
68
+        
69
+      </Modal>
70
+    </>
71
+  );
72
+}
73
+
74
+const WrappedBase = Form.create({ name: 'BatchPay' })(BatchPay);
75
+
76
+export default WrappedBase

+ 82
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/BatchRaise/BatchRefund.jsx 파일 보기

@@ -0,0 +1,82 @@
1
+import React, { PureComponent, useState, useEffect } from 'react'
2
+import { Modal, Row, Col, Table, Pagination, Button, Form, Input, Select,message } from 'antd'
3
+import EnDash from '../EnDash'
4
+import AuthButton from '@/components/AuthButton';
5
+
6
+import Style from './style.less'
7
+import HotBlock from '../HotBlock'
8
+import apis from '../../../../../../services/apis';
9
+import request from '../../../../../../utils/request';
10
+
11
+const BatchRefund = props => {
12
+  const taRaiseRecords = props.houseIds;
13
+
14
+  function handleSubmit (e) {
15
+    e.preventDefault();
16
+    props.form.validateFields((err, values) => {
17
+      if (!err){
18
+        request({ ...apis.house.batchRefundOfflineRaiseRecord, data: { ...values,taRaiseRecords },}).then((data) => {
19
+          message.info("保存成功")
20
+          props.onSuccess(false);
21
+        }).catch((err) => {
22
+          message.info(err.msg || err.message)
23
+        })
24
+      }
25
+    });
26
+  }
27
+
28
+  const { getFieldDecorator } = props.form;
29
+
30
+  return (
31
+    <>
32
+      <Modal footer={null} title="批量线下退费" visible={props.visible} onCancel={props.onCancel} width={600}>
33
+        <span>所选XX条数据中,符合批量设置线下缴费条件的有YY条,不符合条件的有ZZ条。确认将YY条数据设置为:</span>
34
+        <Form labelCol={{ span: 7 }} wrapperCol={{ span: 12 }} onSubmit={handleSubmit}>
35
+          <Form.Item label="退费状态" labelAlign='left'>
36
+            {getFieldDecorator('payStatus', {initialValue:'refunded'})(
37
+                <Select style={{width: '120px'}} disabled>
38
+                <Option value="refunded">已退费</Option>
39
+              </Select>,
40
+              )}
41
+          </Form.Item>
42
+          <Form.Item label="退费方式" labelAlign='left'>
43
+            {getFieldDecorator('payType', {initialValue:'offLine'})(
44
+                <Select style={{width: '120px'}} disabled>
45
+                <Option value="offLine">线下退费</Option>
46
+              </Select>,
47
+              )}
48
+          </Form.Item>
49
+          <Form.Item label="退费结果" labelAlign='left'>
50
+            {getFieldDecorator('payStatus', {initialValue:'refunded'})(
51
+                <Select style={{width: '120px'}} disabled>
52
+                <Option value="refunded">成功</Option>
53
+              </Select>,
54
+              )}
55
+          </Form.Item>
56
+          <Form.Item label="退费原因" labelAlign='left'>
57
+            {getFieldDecorator('refundReason',{
58
+              rules: [{ required: true, message: ' 请输入作废原因' }],
59
+              })(
60
+                <Input ></Input>
61
+              )}
62
+          </Form.Item>
63
+          <Form.Item wrapperCol={{ span: 15, offset: 9 }}>
64
+            <Button type="primary" htmlType="submit" >
65
+              确定
66
+            </Button>
67
+          </Form.Item>
68
+        </Form>
69
+        <div>
70
+          <font style={{color:'#999'}}>可批量设置线下退费的认筹单条件必须满足以下全部:</font><br/>
71
+          <font style={{color:'#999'}}>1.认筹单缴费状态为已缴费。</font><br/>
72
+          <font style={{color:'#999'}}>2.退费状态为未退费。</font><br/>
73
+        </div>
74
+        
75
+      </Modal>
76
+    </>
77
+  );
78
+}
79
+
80
+const WrappedBase = Form.create({ name: 'BatchRefund' })(BatchRefund);
81
+
82
+export default WrappedBase

+ 114
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/BatchRaise/Refund.jsx 파일 보기

@@ -0,0 +1,114 @@
1
+import React, { PureComponent, useState, useEffect } from 'react'
2
+import { Modal, Row, Col, Table, Pagination, Button, Form, Input, message, Select } from 'antd'
3
+import EnDash from '../EnDash'
4
+import AuthButton from '@/components/AuthButton';
5
+
6
+import Style from './style.less'
7
+import HotBlock from '../HotBlock'
8
+import apis from '../../../../../../services/apis';
9
+import request from '../../../../../../utils/request';
10
+
11
+const Refund = props => {
12
+  const raiseRecordId = props.raiseRecordId;
13
+  const raiseId = props.raiseId;
14
+  const [data, setData] = useState([])
15
+
16
+  
17
+
18
+  useEffect(() => {
19
+    getList();
20
+  }, [props,raiseRecordId])
21
+
22
+  function getList(params) {
23
+    request({
24
+      ...apis.house.taRaiseById,
25
+      urlData: { id: raiseId }
26
+    }).then((data) => {
27
+      setData(data)
28
+    })
29
+  }
30
+
31
+  function toDecimal2 (x){
32
+    var f = parseFloat(x);
33
+    if (isNaN(f)) {
34
+      return false;
35
+    }
36
+    var f = Math.round(x * 100) / 100;
37
+    var s = f.toString();
38
+    var rs = s.indexOf('.');
39
+    if (rs < 0) {
40
+      rs = s.length;
41
+      s += '.';
42
+    }
43
+    while (s.length <= rs + 2) {
44
+      s += '0';
45
+    }
46
+    return s;
47
+  }
48
+  function regFenToYuan(fen){
49
+    var num = fen;
50
+    num = fen * 0.01;
51
+    num += '';
52
+    var reg = num.indexOf('.') > -1 ? /(\d{1,3})(?=(?:\d{3})+\.)/g : /(\d{1,3})(?=(?:\d{3})+$)/g;
53
+    num = num.replace(reg, '$1');
54
+    num = toDecimal2(num)
55
+    return num
56
+  }
57
+  
58
+  function handleSubmit (e) {
59
+    e.preventDefault();
60
+    props.form.validateFields((err, values) => {
61
+      if (!err){
62
+        request({ ...apis.house.refund, data: {targetId:raiseRecordId, targetType:"house", refundReason:values.refundReason}, }).then((data) => {
63
+          console.log('caozuochgegngong')
64
+            message.info("操作成功,微信退费会有延迟,请在稍后查询认筹单状态")
65
+            props.onSuccess(false);
66
+        }).catch((err) => {
67
+            // message.info(err.msg)
68
+        })        
69
+      }
70
+    });
71
+  }
72
+
73
+  const { getFieldDecorator } = props.form;
74
+
75
+  return (
76
+    <>
77
+      <Modal footer={null} title="退款" visible={props.visible} onCancel={props.onCancel} width={600}>
78
+        <Form labelCol={{ span: 7 }} wrapperCol={{ span: 12 }} onSubmit={handleSubmit}>
79
+          <div><span>当前系统设置认筹金额:{regFenToYuan(data.raisePrice)}元</span></div>
80
+          <div><span>用户实付金额:{regFenToYuan(data.raisePrice)}元</span></div>
81
+          <div><span>即将退费金额:{regFenToYuan(data.raisePrice)}元</span></div>
82
+          <Form.Item label="退费方式" labelAlign='left'>
83
+              {getFieldDecorator('refundType', {
84
+                  rules: [{ required: true, message: ' 退款原因' }],initialValue:'onLine'
85
+                })(
86
+                <Select style={{width: '120px'}} disabled>
87
+                  <Option value="onLine">线上退费</Option>
88
+                </Select>,
89
+              )}
90
+          </Form.Item>
91
+          <Form.Item label="退款原因" labelAlign='left'>
92
+            {getFieldDecorator('refundReason', {
93
+              rules: [{ required: true, message: ' 退款原因' }],
94
+            })(<Input label='left'/>)}
95
+          </Form.Item>
96
+          <Form.Item wrapperCol={{ span: 15, offset: 10 }}>
97
+            <Button type="primary" htmlType="submit" >
98
+              提交
99
+            </Button>
100
+          </Form.Item>
101
+        </Form>
102
+        <div>
103
+          <font style={{color:'#999'}}>支持退费的认筹单:</font><br/>
104
+          <font style={{color:'#999'}}>1.认筹单缴费状态为已缴费且缴费结果为成功且退费状态为未退费的。</font><br/><br/>
105
+          <font style={{color:'#999'}}>注意:发起线上退费后需要微信和银行处理,退费是否成功结果请到退费记录中查看</font><br/>
106
+        </div>
107
+      </Modal>
108
+    </>
109
+  );
110
+}
111
+
112
+const WrappedBase = Form.create({ name: 'Refund' })(Refund);
113
+
114
+export default WrappedBase

+ 240
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/BatchRaise/style.less 파일 보기

@@ -0,0 +1,240 @@
1
+.SubmitButton {
2
+    background: rgba(239,39,58,1);
3
+    border-radius: 7px;
4
+    border: 0px;
5
+  }
6
+  .text {
7
+    color: rgba(239,39,58,1);
8
+  }
9
+  .SelectFrom {
10
+    width: 180px;
11
+    background: #ffffff;
12
+    border-radius: 7px;
13
+    border: 1px solid #dbdbdb;
14
+  }
15
+  .addButton {
16
+    background: #50be00;
17
+    border-radius: 4px;
18
+    border: 0px;
19
+    margin: 10px 0px;
20
+  }
21
+  .cardText {
22
+    color: #333;
23
+    display: flex;
24
+    align-items: center;
25
+    position: relative;
26
+    line-height: 1.5;
27
+    font-size: 0.106rem;
28
+    margin-bottom: 0.08rem;
29
+  
30
+  }
31
+  .cardItem{
32
+    color: #666;
33
+    display: flex;
34
+    align-items: center; 
35
+    line-height: 1.5;
36
+    font-size: 0.106rem;
37
+    margin-bottom: 0.08rem; 
38
+  }
39
+  .ediText {
40
+    font-size: 0.106rem;
41
+    color: #ff925c;
42
+    line-height: 24px;
43
+    position: absolute;
44
+    right: 0;
45
+  }
46
+  .title{
47
+    display: inline-block;
48
+    width:  0.54rem;
49
+    justify-content: space-between;
50
+    text-align: justify;
51
+    text-align-last:justify
52
+  }
53
+  
54
+  .address { 
55
+    width: 400px;
56
+    height: 24px; 
57
+    text-overflow: ellipsis; 
58
+    white-space: nowrap;
59
+    overflow: hidden;
60
+  }
61
+  
62
+  .pitchButton { 
63
+    border-color: rgba(255,126,72,1);
64
+    background-color: rgba(255,126,72,1);
65
+    color: rgba(255,255,255,1); 
66
+  }
67
+  .noButton {
68
+    border-color: rgba(255,126,72,1);
69
+    color: rgba(255,126,72,1);
70
+  }
71
+  .displayS {
72
+    display: none;
73
+  }
74
+  
75
+  
76
+  // 客户详情样式
77
+  .cardBox{
78
+    display: flex;
79
+    .leftBox{
80
+      width:1000px;
81
+      min-width:350px;
82
+      height:1000px;
83
+      background:rgba(255,255,255,1);
84
+      box-shadow:0px 0px 16px 2px rgba(0,0,0,0.12);
85
+      border-radius:8px;
86
+      display: inline-block;
87
+      margin-right: 30px;
88
+      padding: 30px;
89
+      overflow: hidden;
90
+    }
91
+    .rightBox{
92
+      width:865px;
93
+      min-width:342px;
94
+      height:290px;
95
+      background:rgba(255,255,255,1);
96
+      // box-shadow:0px 0px 16px 2px rgba(0,0,0,0.12);
97
+      border-radius:8px;
98
+      display: inline-block;
99
+      margin-right: 30px;
100
+      padding: 30px;
101
+      overflow: hidden;
102
+    }
103
+    .rightBox{
104
+      width:-webkit-fill-available;
105
+      height:315px;
106
+      min-width: 100%;
107
+      background:rgba(255,255,255,1);
108
+      // box-shadow:0px 0px 16px 2px rgba(0,0,0,0.12);
109
+      border-radius:8px;
110
+      display: inline-block;
111
+      padding: 30px;
112
+      overflow: hidden;
113
+      // position: relative;
114
+    }
115
+    .rightBoxCentre{
116
+      width:865px;
117
+      height:345px;
118
+      min-width: 60%;
119
+      background:rgba(255,255,255,1);
120
+      box-shadow:0px 0px 16px 2px rgba(0,0,0,0.12);
121
+      border-radius:8px;
122
+      display: inline-block;
123
+      padding: 30px;
124
+      overflow: hidden;
125
+      position: relative;
126
+    }
127
+    .leftBoxCentre{
128
+      width:100%;
129
+      height:345px;
130
+      background:rgba(255,255,255,1);
131
+      box-shadow:0px 0px 16px 2px rgba(0,0,0,0.12);
132
+      border-radius:8px;
133
+      display: inline-block;
134
+      padding: 30px;
135
+      overflow: hidden;
136
+      position: relative;
137
+    }
138
+    .tit{
139
+      font-size:0.15rem;
140
+      font-weight:600;
141
+      color:#222;
142
+      margin: 10px 0 0 0;
143
+    }
144
+    .flexBox{
145
+      display: flex;
146
+      align-items: end;
147
+    }
148
+    .touxiang{
149
+      width: 120px;
150
+      width: 120px;
151
+      border-radius: 6px;
152
+      margin: 80px 0 20px 0;
153
+    }
154
+    .touxiangphoto{
155
+      width: 80px;
156
+      height: 80px;
157
+      margin: 38px 0 0px 0;
158
+    }
159
+    .infoItem{
160
+      color:#666;
161
+      font-size: 0.1rem;
162
+      margin: 0 0 30px 0;
163
+      
164
+    }
165
+    .rightItem{
166
+      color:#666;
167
+      font-size: 0.1rem;
168
+      margin: 0 0 15px 0;
169
+    }
170
+    .right{
171
+      width: 25%;
172
+      min-width: 1.3rem;
173
+      margin-left: 0.1rem;
174
+      padding-top: 0.3rem;
175
+      // position: absolute;
176
+      // top:108px;
177
+      // left:170px;
178
+    }
179
+    .rightphone{
180
+    
181
+      position: absolute;
182
+      top:108px;
183
+      left:170px;
184
+    }
185
+    .left{
186
+      position: absolute;
187
+      top:108px;
188
+      left:60%;
189
+    
190
+    }
191
+    .rightInfo{
192
+      width: 25%;
193
+      min-width: 1.3rem;
194
+      margin-right: 0.1rem;
195
+      padding-top: 0.3rem;
196
+      // position: absolute;
197
+      // top:108px;
198
+      // left:80%;
199
+    }
200
+  
201
+    .Centered{
202
+      width: 25%;
203
+      // position: absolute;
204
+      // top:108px;
205
+      // left:30%;
206
+      min-width: 1.3rem;
207
+      margin: 0 0 15px 0;
208
+      color:#666;
209
+      font-size: 0.1rem;
210
+      padding-top: 0.3rem;
211
+    }
212
+  
213
+    .rightCentered{
214
+      // position: absolute;
215
+      // top:108px;
216
+      // left:55%;
217
+      width: 25%;
218
+      min-width: 1.3rem;
219
+      margin: 0 0 15px 0;
220
+      padding-top: 0.3rem;
221
+      color:#666;
222
+      font-size: 0.1rem;
223
+    }
224
+    
225
+  }
226
+  .recordBox{
227
+    width:100%;
228
+    background:rgba(255,255,255,1);
229
+    box-shadow:0px 0px 16px 2px rgba(0,0,0,0.12);
230
+    border-radius:8px;
231
+    margin-top: 30px;
232
+    padding: 30px;
233
+    .tableName{
234
+      font-size:24px;
235
+      font-weight:600;
236
+      color:#222;
237
+    }
238
+  }
239
+  
240
+  

+ 77
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/BuildSelect/BuildSelect.jsx 파일 보기

@@ -0,0 +1,77 @@
1
+import React, { useState, useEffect, useRef } from 'react';
2
+import { Select } from 'antd';
3
+import apis from '../../../../../../services/apis';
4
+import request from '../../../../../../utils/request'
5
+
6
+const { Option } = Select;
7
+
8
+function usePrevious(props) {
9
+  const ref = useRef();
10
+  useEffect(() => {
11
+    ref.current = props;
12
+  });
13
+  return ref.current;
14
+}
15
+
16
+/**
17
+ *
18
+ *
19
+ * @param {*} props
20
+ * @returns
21
+ */
22
+const BuildingSelect = props => {
23
+  const [data, setData] = useState([])
24
+  const [value, setValue] = useState([])
25
+  const type = props.type
26
+  const salesBatchId = props.salesBatchId
27
+
28
+  useEffect(() => {
29
+    getBuildList();
30
+  }, [props.salesBatchId])
31
+
32
+
33
+  const getBuildList = e => {
34
+    if (salesBatchId && salesBatchId != 'undefine'){
35
+      request({ ...apis.house.buildingIdBySalesBatchId, urlData:{id: salesBatchId}, params: { pageNum: 1, pageSize: 999 } }).then(data => {
36
+        setData(data)
37
+        checkValue(data)
38
+        // 默认选中第一个
39
+      })
40
+    }
41
+    else{
42
+      request({ ...apis.building.buildingSelect, params: { pageNum: 1, pageSize: 999 } }).then(data => {
43
+        setData(data)
44
+        checkValue(data)
45
+        // 默认选中第一个
46
+      })
47
+    }
48
+  }
49
+
50
+
51
+  const checkValue = (data) => {
52
+    if (props.value) {
53
+      const tempData = data.filter(f => f.buildingId == props.value)
54
+      const va = (tempData.length > 0) ? props.value : '项目已下线,请重新选择项目'
55
+      props.onChange(va)
56
+
57
+    }
58
+  }
59
+
60
+  return (
61
+      <Select
62
+      disabled={type == 'false'?false:true}
63
+      showSearch
64
+      value={props.value}
65
+      style={{ width: '300px' }}
66
+      placeholder="请选择项目"
67
+      onChange={props.onChange}
68
+      filterOption={(input, option) =>
69
+        option.props.children && option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
70
+      }>
71
+          {data.map(building => (
72
+            <Option key={building.buildingId} value={building.buildingId}>{building.buildingName}</Option>
73
+          ))}
74
+      </Select>
75
+  )
76
+}
77
+export default BuildingSelect

+ 14
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/EnDash/index.jsx 파일 보기

@@ -0,0 +1,14 @@
1
+import React from 'react'
2
+
3
+export default function EnDash(props) {
4
+    const { size = 1, color = '#999', style = {}, ...left } = props
5
+
6
+    const newSt = { 
7
+        ...style,
8
+        display: 'flex',
9
+        alignItems: 'center',
10
+        justifyContent: 'center',
11
+    }
12
+
13
+    return <div style={newSt} { ...left }><hr style={{ border: 'none', borderBottom: `${size}px dashed ${color}`, width: '100%' }} /></div>
14
+}

+ 109
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/HelpDoc/index.jsx 파일 보기

@@ -0,0 +1,109 @@
1
+import React, { PureComponent } from 'react'
2
+import { Modal, Row, Col } from 'antd'
3
+import EnDash from '../EnDash'
4
+
5
+import Style from './style.less'
6
+import HotBlock from '../HotBlock'
7
+
8
+const dataset = [
9
+  {
10
+    label: '(0)',
11
+    value: 0,
12
+  },
13
+  {
14
+    label: '(1)',
15
+    value: 1,
16
+  },
17
+  {
18
+    label: '(2)',
19
+    value: 2,
20
+  },
21
+  {
22
+    label: '(3)',
23
+    value: 3,
24
+  },
25
+  {
26
+    label: '(4)',
27
+    value: 4,
28
+  },
29
+  {
30
+    label: '(5)',
31
+    value: 5,
32
+  },
33
+  {
34
+    label: '(6~10)',
35
+    value: 8,
36
+  },
37
+  {
38
+    label: '(11~20)',
39
+    value: 15,
40
+  },
41
+  {
42
+    label: '(21~30)',
43
+    value: 25,
44
+  },
45
+  {
46
+    label: '(31~40)',
47
+    value: 35,
48
+  },
49
+  {
50
+    label: '(41~50)',
51
+    value: 45,
52
+  },
53
+  {
54
+    label: '(51~100)',
55
+    value: 80,
56
+  },
57
+  {
58
+    label: '(101~200)',
59
+    value: 150,
60
+  },
61
+  {
62
+    label: '(200以上)',
63
+    value: 201,
64
+  },
65
+]
66
+
67
+function Cell(props) {
68
+  return (
69
+    <Row type="flex" align="middle" gutter={20}>
70
+      <Col span={2}>{props.left}</Col>
71
+      <Col span={12}><EnDash /></Col>
72
+      <Col span={6}>{props.right}</Col>
73
+    </Row>
74
+  )
75
+}
76
+
77
+export default function HelpDoc(props) {
78
+  return (
79
+    <Modal footer={null} title="相关说明" visible={props.visible} onCancel={props.onCancel} width={800}>
80
+      <div className={Style.article}>
81
+        <div className={Style.section}>
82
+          <div className={Style.title}>1.图例解释:</div>
83
+          <div>
84
+            <Cell left="1号楼" right="楼栋/幢" />
85
+            <Cell left="2单元" right="单元" />
86
+            <Cell left="3楼" right="楼层" />
87
+            <Cell left="301" right="房号" />
88
+            <Cell left="1人" right="预选人数" />
89
+            <Cell left="234万" right="价格" />
90
+            <Cell left="A户型" right="户型名" />
91
+          </div>
92
+        </div>
93
+        <div className={Style.section}>
94
+          <div className={Style.title}>2.预选人数(热度):</div>
95
+          <div>每有一位客户预选此房源,热度自动增加1,热度越大说明想购买此房源的用户越多,认筹摇号购买难度越大。</div>
96
+        </div>
97
+        <div className={Style.section}>
98
+          <div className={Style.title}>3.热度指标:</div>
99
+          <div className={Style.subtitle}>颜色越深代表热度越高。黑底白字代表房源未发布,未发布房源用户不会看到。</div>
100
+          <div className={Style.flex}>
101
+            {
102
+              dataset.map((block) => (<div className={Style['flex-item']} key={block.value}><HotBlock number={block.value}>{block.label}</HotBlock></div>))
103
+            }
104
+          </div>
105
+        </div>
106
+      </div>
107
+    </Modal>
108
+  );
109
+}

+ 36
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/HelpDoc/style.less 파일 보기

@@ -0,0 +1,36 @@
1
+.article {
2
+    .section {
3
+        font-size: 16px;
4
+        line-height: 1.8em;
5
+        color: #666;
6
+
7
+        & + .section {
8
+            margin-top: 24px;
9
+        }
10
+    }
11
+
12
+    .title {
13
+        font-size: 18px;
14
+        line-height: 2em;
15
+        color: #333;
16
+    }
17
+
18
+    .subtitle {
19
+        font-size: 14px;
20
+        line-height: 1.6em;
21
+        color: #999;
22
+    }
23
+
24
+    .flex {
25
+        display: flex;
26
+        flex-wrap: wrap;
27
+
28
+        .flex-item {
29
+            margin-top: 16px;
30
+            margin-right: 8px;
31
+            flex: none;
32
+            width: 100px;
33
+            text-align: center;
34
+        }
35
+    }
36
+}

+ 40
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/HotBlock/index.jsx 파일 보기

@@ -0,0 +1,40 @@
1
+import React from 'react'
2
+import classNames from 'classnames'
3
+
4
+import Style from './style.less'
5
+
6
+function computeLevel (num) {
7
+    switch (true) {
8
+      case num >= 200:
9
+        return 13;
10
+      case num > 100:
11
+        return 12;
12
+      case num > 50:
13
+        return 11;
14
+      case num > 40:
15
+        return 10;
16
+      case num > 30:
17
+        return 9;
18
+      case num > 20:
19
+        return 8;
20
+      case num > 20:
21
+        return 8;
22
+      case num > 10:
23
+        return 7;
24
+      case num >= 6:
25
+        return 6;
26
+      case num > 0:
27
+        return num;
28
+      default:
29
+        return 0;
30
+    }
31
+  }
32
+  
33
+  export default function HotBlock(props) {
34
+    const level = computeLevel(props.number)
35
+
36
+    const cls = classNames(Style.hotblock, Style[`bkg-${level}`])
37
+
38
+    return (<div className={cls}>{props.children}</div>)
39
+  }
40
+  

+ 46
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/HotBlock/style.less 파일 보기

@@ -0,0 +1,46 @@
1
+
2
+.hotblock {
3
+    &.bkg-0 {
4
+      background:#F8F8F8;
5
+    }
6
+    &.bkg-1 {
7
+      background:#F9DED1;
8
+    }
9
+    &.bkg-2 {
10
+      background:#F6D4C3;
11
+    }
12
+    &.bkg-3 {
13
+      background:#F8C6AD;
14
+    }
15
+    &.bkg-4 {
16
+      background:#FDDBDB;
17
+    }
18
+    &.bkg-5 {
19
+      background:#F9CCCC;
20
+    }
21
+    &.bkg-6 {
22
+      background:#F9B7B7;
23
+    }
24
+    &.bkg-7 {
25
+      background:#FFADAD;
26
+    }
27
+    &.bkg-8 {
28
+      background:#F59683;
29
+    }
30
+    &.bkg-9 {
31
+      background:#F7836C;
32
+    }
33
+    &.bkg-10 {
34
+      background:#F97459;
35
+    }
36
+    &.bkg-11 {
37
+      background:#FC6749;
38
+    }
39
+    &.bkg-12 {
40
+      background:#FD4E2B;
41
+    }
42
+    &.bkg-13 {
43
+      background:#FE2E2E;
44
+    }
45
+  }
46
+  

+ 21
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/HouseGrid/Floor.jsx 파일 보기

@@ -0,0 +1,21 @@
1
+import React from 'react'
2
+import Style from './style.less'
3
+
4
+export default function Floor(props) {
5
+  const { floorName, roomList = [] } = props.dataset || {}
6
+
7
+  return (
8
+    <div className={Style.floor}>
9
+      <div className={Style['floor-head']}>{floorName}</div>
10
+      <div className={Style['floor-body']}>
11
+        {roomList.map((room) => {
12
+          return (
13
+            <div className={Style.item} key={room.houseId} >
14
+              {props.render(room)}
15
+            </div>
16
+          )
17
+        })}
18
+      </div>
19
+    </div>
20
+  );
21
+}

+ 35
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/HouseGrid/Room.jsx 파일 보기

@@ -0,0 +1,35 @@
1
+import React from 'react'
2
+import classNames from 'classnames'
3
+import HotBlock from "../HotBlock"
4
+import Style from './style.less'
5
+
6
+export default function Room(props) {
7
+  console.log(props.dataset, 'propsDataSet')
8
+  const { roomName, price, apartmentName, status, raiseHeat, raiseRealHeat } = props.dataset || {}
9
+  let personNum = props.hotType === 1 ? (raiseHeat || 0) : (raiseRealHeat || 0)
10
+  if (props.hotType === 2){
11
+    personNum = isNaN(raiseRealHeat) ? 0 : raiseRealHeat
12
+  }  
13
+  if (props.hotType === 3) {
14
+    personNum = !isNaN(raiseHeat) && !isNaN(raiseRealHeat) ?  raiseHeat+raiseRealHeat : isNaN(raiseHeat) && !isNaN(raiseRealHeat) ? raiseRealHeat : !isNaN(raiseHeat) && isNaN(raiseRealHeat) ? raiseHeat : 0
15
+  }
16
+
17
+  const handleClick = () => {
18
+    if (props.onClick) {
19
+      props.onClick(props.dataset || {})
20
+    }
21
+  }
22
+
23
+  const wanY = Number(price - 0)
24
+
25
+  return (
26
+    <HotBlock number={personNum}>
27
+      <div className={classNames(Style.room, { [`${Style.offline}`]: status !== 1 })} onClick={handleClick}>
28
+        <div className={Style.warn}>{roomName}</div>
29
+        <div className={Style.warn}>{`(${personNum === null ? 0 : personNum}人)`}</div>
30
+        <div className={Style.info}>{`${wanY} 万`}</div>
31
+        <div className={Style.info}>{apartmentName}</div>
32
+      </div>
33
+    </HotBlock>
34
+  )
35
+}

+ 15
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/HouseGrid/Unit.jsx 파일 보기

@@ -0,0 +1,15 @@
1
+import React from 'react'
2
+import Style from './style.less'
3
+
4
+export default function Unit(props) {
5
+  const { unitName, floorList = [] } = props.dataset || {}
6
+
7
+  return (
8
+    <div className={Style.unit}>
9
+      <div className={Style['unit-head']}>{unitName}</div>
10
+      <div className={Style['unit-body']}>
11
+        {floorList.map(floor => props.render(floor))}
12
+      </div>
13
+    </div>
14
+  )
15
+}

+ 37
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/HouseGrid/index.js 파일 보기

@@ -0,0 +1,37 @@
1
+import React from 'react'
2
+import { PageHeader, Card } from 'antd';
3
+import Floor from "./Floor";
4
+import Room from "./Room";
5
+import Unit from './Unit';
6
+
7
+
8
+export default function(props) {
9
+  const blockList = props.dataset || []
10
+  
11
+  // 仅仅是一个函数, 不是函数式组件
12
+  function renderRoom(room) {
13
+    return (<Room dataset={room} hotType={props.hotType} />)
14
+  }
15
+
16
+  // 仅仅是一个函数, 不是函数式组件
17
+  function renderFloor(floor) {
18
+    return (<Floor key={floor.floorId} dataset={floor} render={renderRoom} />)
19
+  }
20
+
21
+  return (
22
+    <div>
23
+      {
24
+        blockList.map((block) => (
25
+          <div key={block.blockId} style={{marginTop: '20px', overflowX: 'auto'}}>
26
+            <PageHeader title={`${block.termName} ${block.blockName}`} backIcon={false} />
27
+            <div style={{ display: 'flex', padding: '10px' }}>
28
+            {
29
+              (block.unitList || []).map((unit) => (<div key={unit.unitId} style={{ flex: 'auto', marginRight: '30px' }} ><Unit dataset={unit} render={renderFloor} /></div>))
30
+            }
31
+            </div>
32
+          </div>
33
+        ))
34
+      }
35
+    </div>
36
+  )
37
+}

+ 72
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/HouseGrid/style.less 파일 보기

@@ -0,0 +1,72 @@
1
+.room {
2
+  text-align: center;
3
+  margin-bottom: 12px;
4
+  padding: 10px;
5
+  font-size: 16px;
6
+  line-height: 1.4em;
7
+
8
+  .info {
9
+    color: #333;
10
+  }
11
+
12
+  .warn {
13
+    color: #730000;
14
+  }
15
+
16
+  &.offline {
17
+    color: #fff;
18
+    background: #000;
19
+    
20
+    .info, .warn {
21
+      color: #fff;
22
+    }
23
+  }
24
+}
25
+
26
+.floor {
27
+  display: flex;
28
+
29
+  &-head {
30
+    font-size: 20px;
31
+    padding-top: 36px;
32
+    flex: none;
33
+    width: 14%;
34
+    min-width: 100px;
35
+    text-align: center;
36
+  }
37
+
38
+  &-body {
39
+    padding-top: 10px;
40
+    text-align: center;
41
+    flex: auto;
42
+    display: flex;
43
+    justify-content: flex-start;
44
+    overflow-x: auto;
45
+
46
+    .item {
47
+      flex: none;
48
+      width: 110px;
49
+
50
+      & + .item {
51
+          margin-left: 2%;
52
+      }
53
+    }
54
+  }
55
+}
56
+
57
+.unit {
58
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
59
+  // max-width: 600px;
60
+
61
+  &-head {
62
+    padding-left: 40px;
63
+    font-size: 22px;
64
+    line-height: 44px;
65
+    color: #000;
66
+    background: #f8f8f8;
67
+  }
68
+
69
+  &-body {
70
+    // padding: 0 20px;
71
+  }
72
+}

+ 141
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/HouseInfo/index.jsx 파일 보기

@@ -0,0 +1,141 @@
1
+import React, { PureComponent, useState, useEffect } from 'react'
2
+import { Modal, Row, Col, Table, Pagination, Button, Form, Input,message } from 'antd'
3
+import EnDash from '../EnDash'
4
+import moment from 'moment';
5
+import AuthButton from '@/components/AuthButton';
6
+
7
+import Style from './style.less'
8
+import HotBlock from '../HotBlock'
9
+import HouseListInfo from '../HouseListInfo'
10
+import request from '../../../../../../utils/request';
11
+import apis from '../../../../../../services/apis';
12
+
13
+const HouseInfo = props => {
14
+  const [data, setData] = useState({ list: [], total: 0 })
15
+  const [raiseData, setRaiseData ] = useState({})
16
+  const [house, setHouse] = useState({visable:false, salesBatchId:'',buildingId:'', raiseRecordId:''});
17
+  const raiseRecordId = props.raiseRecordId
18
+  const salesBatchId = props.salesBatchId
19
+  const buildingId = props.buildingId
20
+  const raiseId = props.raiseId
21
+
22
+  useEffect(() => {
23
+    getList({ pageNum: 1, pageSize: 10 });
24
+    getRaiseInfo();
25
+  }, [raiseRecordId])
26
+
27
+  function getList(params) {
28
+    // 网路请求
29
+    request({ ...apis.house.listHouseByRaiseRecordId, params: { ...params,raiseRecordId: raiseRecordId} }).then(res => {
30
+      setData(res)
31
+    }).catch(err => {
32
+      // openNotificationWithIcon('error', err.message)
33
+    })
34
+  }
35
+
36
+  function getRaiseInfo(){
37
+    request({ ...apis.house.taRaiseById, urlData: {id: raiseId} }).then((data) => {
38
+      setRaiseData(data)
39
+      console.log(raiseData, 'raiseDataraiseDataraiseData')
40
+    })
41
+  }
42
+
43
+  function refreshList(e){
44
+    setHouse(e)
45
+    getList()
46
+  }
47
+
48
+  function infoOnCancel(e){
49
+    console.log(12321344)
50
+    props.onCancel();
51
+  }
52
+
53
+  //锁定和解锁
54
+  const updateLockingStatus = rowData => () => {
55
+    console.log(rowData,'12321323')
56
+    const type = rowData.houseLockingStatus === 'locked' ? "unlocked":"locked"
57
+    request({ ...apis.house.updateLockingStatus, params: {houseId:rowData.houseId, raiseHouseId:rowData.raiseHouseId, personId:rowData.lockingPersonId, type:type, raiseRecordId:raiseRecordId} }).then(res => {
58
+      message.info("操作成功")
59
+      props.onCancel(false)
60
+      getList();
61
+    }).catch(err => {
62
+    })
63
+  }
64
+
65
+
66
+  const columns = [
67
+    {
68
+      title: '房源编号',
69
+      dataIndex: 'houseId',
70
+      key: 'houseId',
71
+      align: 'center',
72
+    },
73
+    {
74
+      title: '房源',
75
+      dataIndex: 'buildingName',
76
+      key: 'buildingName',
77
+      align: 'center',
78
+      render: (text, records) => <span>{records.termName}/{records.blockName}/{records.unitName}/{records.floorName}/{records.roomName}</span>,
79
+    },
80
+    {
81
+      title: '预选实际人数',
82
+      dataIndex: 'realHeat',
83
+      key: 'realHeat',
84
+      align: 'center',
85
+    },
86
+    {
87
+      title: '认筹实际人数',
88
+      dataIndex: 'raiseRealHeat',
89
+      key: 'raiseRealHeat',
90
+      align: 'center',
91
+    },
92
+    {
93
+      title: '锁定状态',
94
+      dataIndex: 'houseLockingStatus',
95
+      key: 'houseLockingStatus',
96
+      align: 'center',
97
+      render: (x, row) => <><span>{row.houseLockingStatus === 'locked'?'已锁定':'未锁定'}</span></>,
98
+    },
99
+    {
100
+      title: '锁定人',
101
+      dataIndex: 'lockingPersonName',
102
+      key: 'lockingPersonName',
103
+      align: 'center',
104
+      render: (x, row) => <><span>{row.houseLockingStatus === 'locked'? row.lockingPersonName :''}</span></>,
105
+    },
106
+    {
107
+      title: '操作',
108
+      dataIndex: '',
109
+      key: '',
110
+      align: 'center',
111
+      render: (text, record) => (
112
+        <AuthButton name="admin.salesBatch.detail.get" noRight={null}>
113
+          <a style={{ color: '#66B3FF' }} onClick={updateLockingStatus(record)} >{record.houseLockingStatus === 'locked' ? '解锁':'锁定'}</a>
114
+        </AuthButton>
115
+      ),
116
+    },
117
+  ];
118
+
119
+  return (
120
+    <>
121
+      <Modal footer={null} title="认筹单房源清单" visible={props.visible} onCancel={() => infoOnCancel()} width={800}>
122
+        <AuthButton noRight={null}>
123
+          {raiseData.houseLockingType === 'auto' ? null : <Button type="danger" style={{marginLeft:'663px'}} onClick={() => setHouse({visable:true, salesBatchId:salesBatchId, raiseRecordId:raiseRecordId, buildingId:buildingId})}>添加房源</Button>}
124
+        </AuthButton>
125
+        <Table dataSource={data.records} columns={columns} pagination={false} rowKey="activityList" />
126
+        <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '30px' }}>
127
+          <Pagination showQuickJumper defaultCurrent={1} total={data.total} onChange={e => changePageNum(e)} current={data.current}/>
128
+        </div>
129
+      </Modal>
130
+      <HouseListInfo visible={house.visable} salesBatchId={house.salesBatchId} buildingId={house.buildingId} raiseRecordId = {house.raiseRecordId} onCancel={() => refreshList({visable:false, salesBatchId:salesBatchId, buildingId:''})}/>
131
+    </>
132
+  );
133
+}
134
+
135
+
136
+const WrappedBase = Form.create({ name: 'HouseInfo' })(HouseInfo);
137
+
138
+export default WrappedBase
139
+
140
+// export default function UserInfo(props) {
141
+// }

+ 240
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/HouseInfo/style.less 파일 보기

@@ -0,0 +1,240 @@
1
+.SubmitButton {
2
+    background: rgba(239,39,58,1);
3
+    border-radius: 7px;
4
+    border: 0px;
5
+  }
6
+  .text {
7
+    color: rgba(239,39,58,1);
8
+  }
9
+  .SelectFrom {
10
+    width: 180px;
11
+    background: #ffffff;
12
+    border-radius: 7px;
13
+    border: 1px solid #dbdbdb;
14
+  }
15
+  .addButton {
16
+    background: #50be00;
17
+    border-radius: 4px;
18
+    border: 0px;
19
+    margin: 10px 0px;
20
+  }
21
+  .cardText {
22
+    color: #333;
23
+    display: flex;
24
+    align-items: center;
25
+    position: relative;
26
+    line-height: 1.5;
27
+    font-size: 0.106rem;
28
+    margin-bottom: 0.08rem;
29
+  
30
+  }
31
+  .cardItem{
32
+    color: #666;
33
+    display: flex;
34
+    align-items: center; 
35
+    line-height: 1.5;
36
+    font-size: 0.106rem;
37
+    margin-bottom: 0.08rem; 
38
+  }
39
+  .ediText {
40
+    font-size: 0.106rem;
41
+    color: #ff925c;
42
+    line-height: 24px;
43
+    position: absolute;
44
+    right: 0;
45
+  }
46
+  .title{
47
+    display: inline-block;
48
+    width:  0.54rem;
49
+    justify-content: space-between;
50
+    text-align: justify;
51
+    text-align-last:justify
52
+  }
53
+  
54
+  .address { 
55
+    width: 400px;
56
+    height: 24px; 
57
+    text-overflow: ellipsis; 
58
+    white-space: nowrap;
59
+    overflow: hidden;
60
+  }
61
+  
62
+  .pitchButton { 
63
+    border-color: rgba(255,126,72,1);
64
+    background-color: rgba(255,126,72,1);
65
+    color: rgba(255,255,255,1); 
66
+  }
67
+  .noButton {
68
+    border-color: rgba(255,126,72,1);
69
+    color: rgba(255,126,72,1);
70
+  }
71
+  .displayS {
72
+    display: none;
73
+  }
74
+  
75
+  
76
+  // 客户详情样式
77
+  .cardBox{
78
+    display: flex;
79
+    .leftBox{
80
+      width:1000px;
81
+      min-width:350px;
82
+      height:1000px;
83
+      background:rgba(255,255,255,1);
84
+      box-shadow:0px 0px 16px 2px rgba(0,0,0,0.12);
85
+      border-radius:8px;
86
+      display: inline-block;
87
+      margin-right: 30px;
88
+      padding: 30px;
89
+      overflow: hidden;
90
+    }
91
+    .rightBox{
92
+      width:865px;
93
+      min-width:342px;
94
+      height:290px;
95
+      background:rgba(255,255,255,1);
96
+      box-shadow:0px 0px 16px 2px rgba(0,0,0,0.12);
97
+      border-radius:8px;
98
+      display: inline-block;
99
+      margin-right: 30px;
100
+      padding: 30px;
101
+      overflow: hidden;
102
+    }
103
+    .rightBox{
104
+      width:-webkit-fill-available;
105
+      height:315px;
106
+      min-width: 100%;
107
+      background:rgba(255,255,255,1);
108
+      box-shadow:0px 0px 16px 2px rgba(0,0,0,0.12);
109
+      border-radius:8px;
110
+      display: inline-block;
111
+      padding: 30px;
112
+      overflow: hidden;
113
+      position: relative;
114
+    }
115
+    .rightBoxCentre{
116
+      width:865px;
117
+      height:345px;
118
+      min-width: 60%;
119
+      background:rgba(255,255,255,1);
120
+      box-shadow:0px 0px 16px 2px rgba(0,0,0,0.12);
121
+      border-radius:8px;
122
+      display: inline-block;
123
+      padding: 30px;
124
+      overflow: hidden;
125
+      position: relative;
126
+    }
127
+    .leftBoxCentre{
128
+      width:100%;
129
+      height:345px;
130
+      background:rgba(255,255,255,1);
131
+      box-shadow:0px 0px 16px 2px rgba(0,0,0,0.12);
132
+      border-radius:8px;
133
+      display: inline-block;
134
+      padding: 30px;
135
+      overflow: hidden;
136
+      position: relative;
137
+    }
138
+    .tit{
139
+      font-size:0.15rem;
140
+      font-weight:600;
141
+      color:#222;
142
+      margin: 10px 0 0 0;
143
+    }
144
+    .flexBox{
145
+      display: flex;
146
+      align-items: end;
147
+    }
148
+    .touxiang{
149
+      width: 120px;
150
+      width: 120px;
151
+      border-radius: 6px;
152
+      margin: 80px 0 20px 0;
153
+    }
154
+    .touxiangphoto{
155
+      width: 80px;
156
+      height: 80px;
157
+      margin: 38px 0 0px 0;
158
+    }
159
+    .infoItem{
160
+      color:#666;
161
+      font-size: 0.1rem;
162
+      margin: 0 0 30px 0;
163
+      
164
+    }
165
+    .rightItem{
166
+      color:#666;
167
+      font-size: 0.1rem;
168
+      margin: 0 0 15px 0;
169
+    }
170
+    .right{
171
+      width: 25%;
172
+      min-width: 1.3rem;
173
+      margin-left: 0.1rem;
174
+      padding-top: 0.3rem;
175
+      // position: absolute;
176
+      // top:108px;
177
+      // left:170px;
178
+    }
179
+    .rightphone{
180
+    
181
+      position: absolute;
182
+      top:108px;
183
+      left:170px;
184
+    }
185
+    .left{
186
+      position: absolute;
187
+      top:108px;
188
+      left:60%;
189
+    
190
+    }
191
+    .rightInfo{
192
+      width: 25%;
193
+      min-width: 1.3rem;
194
+      margin-right: 0.1rem;
195
+      padding-top: 0.3rem;
196
+      // position: absolute;
197
+      // top:108px;
198
+      // left:80%;
199
+    }
200
+  
201
+    .Centered{
202
+      width: 25%;
203
+      // position: absolute;
204
+      // top:108px;
205
+      // left:30%;
206
+      min-width: 1.3rem;
207
+      margin: 0 0 15px 0;
208
+      color:#666;
209
+      font-size: 0.1rem;
210
+      padding-top: 0.3rem;
211
+    }
212
+  
213
+    .rightCentered{
214
+      // position: absolute;
215
+      // top:108px;
216
+      // left:55%;
217
+      width: 25%;
218
+      min-width: 1.3rem;
219
+      margin: 0 0 15px 0;
220
+      padding-top: 0.3rem;
221
+      color:#666;
222
+      font-size: 0.1rem;
223
+    }
224
+    
225
+  }
226
+  .recordBox{
227
+    width:100%;
228
+    background:rgba(255,255,255,1);
229
+    box-shadow:0px 0px 16px 2px rgba(0,0,0,0.12);
230
+    border-radius:8px;
231
+    margin-top: 30px;
232
+    padding: 30px;
233
+    .tableName{
234
+      font-size:24px;
235
+      font-weight:600;
236
+      color:#222;
237
+    }
238
+  }
239
+  
240
+  

+ 164
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/HouseListInfo/index.jsx 파일 보기

@@ -0,0 +1,164 @@
1
+import React, { PureComponent, useState, useEffect } from 'react'
2
+import { Modal, Row, Col, Table, Pagination, Button, Form, Input,message } from 'antd'
3
+import EnDash from '../EnDash'
4
+
5
+import Style from './style.less'
6
+import HotBlock from '../HotBlock'
7
+import request from '../../../../../../utils/request';
8
+import apis from '../../../../../../services/apis';
9
+import AuthButton from '@/components/AuthButton';
10
+
11
+
12
+
13
+const HouseListInfo = props => {
14
+  const [data, setData] = useState([])
15
+  const raiseRecordId = props.raiseRecordId
16
+  useEffect(() => {
17
+    console.log('raiseRecordIdraiseRecordId',raiseRecordId)
18
+    getList({ pageNum: 1, pageSize: 10 });
19
+  }, [props.raiseRecordId])
20
+
21
+  function getList(params) {
22
+    // 网路请求
23
+    request({ ...apis.house.taHousingResources, params: { ...params, salesBatchId:props.salesBatchId, lockingStatus:'unlocked', buildingId:props.buildingId} }).then(res => {
24
+      setData(res)
25
+    }).catch(err => {
26
+      // openNotificationWithIcon('error', err.message)
27
+    })
28
+  }
29
+
30
+  const toAddHouse = rowData => () =>{
31
+    console.log(rowData,'record');
32
+    request({ ...apis.house.addUnlockRaiseHouse, params: {houseId: rowData.houseId, raiseRecordId: raiseRecordId, lockingStatus:'unlocked'} }).then(res => {
33
+      message.info("添加成功");
34
+      props.onCancel();
35
+    }).catch(err => {
36
+      // openNotificationWithIcon('error', err.message)
37
+    })
38
+  }
39
+
40
+  const changePageNum = (pageNumber) => {
41
+    getList({ pageNum: pageNumber, pageSize: 10, ...props.form.getFieldsValue() })
42
+  }
43
+
44
+
45
+  const columns = [
46
+    {
47
+      title: '房源编号',
48
+      dataIndex: 'houseId',
49
+      key: 'houseId',
50
+      align: 'center',
51
+    },
52
+    {
53
+      title: '房源',
54
+      dataIndex: 'room',
55
+      key: 'room',
56
+      align: 'center',
57
+      render: (text, records) => <span>{records.termname}/{records.blockName}/{records.unitName}/{records.floorName}/{records.roomName}</span>,
58
+    },
59
+    {
60
+      title: '价格(万元)',
61
+      dataIndex: 'price',
62
+      key: 'price',
63
+      align: 'center',
64
+    },
65
+    {
66
+      title: '对应户型',
67
+      dataIndex: 'apartmentName',
68
+      key: 'apartmentName',
69
+    },
70
+    {
71
+      title: '预选实际热度',
72
+      dataIndex: 'realHeat',
73
+      key: 'realHeat',
74
+    },
75
+    {
76
+      title: '认筹实际热度',
77
+      dataIndex: 'raiseRealHeat',
78
+      key: 'raiseRealHeat',
79
+    },
80
+    {
81
+      title: '操作',
82
+      dataIndex: '',
83
+      key: '',
84
+      align: 'center',
85
+      render: (text, record) => (
86
+        <AuthButton name="admin.salesBatch.detail.get" noRight={null}>
87
+          <a style={{ color: '#66B3FF' }} onClick={toAddHouse(record)} >添加</a>
88
+        </AuthButton>
89
+      ),
90
+    },
91
+  ];
92
+
93
+  function handleSubmit (e) {
94
+    e.preventDefault();
95
+    props.form.validateFields((err, values) => {
96
+      if (!err){
97
+        getList({ pageNum: 1, pageSize: 10, ...values })
98
+      }
99
+    });
100
+  }
101
+
102
+  // 重置搜索
103
+  function handleReset () {
104
+    props.form.resetFields();
105
+  }
106
+
107
+  const { getFieldDecorator } = props.form;
108
+
109
+  return (
110
+    <>
111
+      <Modal footer={null} title="添加房源" visible={props.visible} onCancel={props.onCancel} width={600}>
112
+        <span>可选房源仅包括当前销售批次中已发布且未被锁定的房源</span>
113
+        <Form layout="inline" onSubmit={handleSubmit}>
114
+            <Form.Item>
115
+              {getFieldDecorator('houseId')(
116
+                <Input placeholder="房源编号" style={{width:'150px'}} />,
117
+              )}
118
+            </Form.Item>
119
+            <Form.Item>
120
+              {getFieldDecorator('termName')(
121
+                <Input placeholder="期区" style={{width:'150px'}}/>,
122
+              )}
123
+            </Form.Item>
124
+            <Form.Item>
125
+              {getFieldDecorator('blockName')(
126
+                <Input placeholder="楼栋" style={{width:'150px'}}/>,
127
+              )}
128
+            </Form.Item>
129
+            <Form.Item>
130
+              {getFieldDecorator('unitName')(
131
+                <Input placeholder="单元" style={{width:'150px'}}/>,
132
+              )}
133
+            </Form.Item>
134
+            <Form.Item>
135
+              {getFieldDecorator('floorName')(
136
+                <Input placeholder="层" style={{width:'150px'}}/>,
137
+              )}
138
+            </Form.Item>
139
+            <Form.Item>
140
+              {getFieldDecorator('roomName')(
141
+                <Input placeholder="户号" style={{width:'150px'}}/>,
142
+              )}
143
+            </Form.Item>
144
+            <Form.Item>
145
+              <Button type="primary" htmlType="submit" >
146
+                搜索
147
+              </Button>
148
+              <Button style={{ marginLeft: 8 }} onClick={handleReset}>
149
+                重置
150
+              </Button>
151
+          </Form.Item>
152
+        </Form>
153
+        <Table dataSource={data.records} columns={columns} pagination={false} rowKey="carouseFigureList"/>
154
+        <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '30px' }}>
155
+          <Pagination showQuickJumper defaultCurrent={1} total={data.total} onChange={changePageNum} current={data.current}/>
156
+        </div>      
157
+      </Modal>
158
+    </>
159
+  );
160
+}
161
+
162
+const WrappedBase = Form.create({ name: 'HouseListInfo' })(HouseListInfo);
163
+
164
+export default WrappedBase

+ 36
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/HouseListInfo/style.less 파일 보기

@@ -0,0 +1,36 @@
1
+.article {
2
+    .section {
3
+        font-size: 16px;
4
+        line-height: 1.8em;
5
+        color: #666;
6
+
7
+        & + .section {
8
+            margin-top: 24px;
9
+        }
10
+    }
11
+
12
+    .title {
13
+        font-size: 18px;
14
+        line-height: 2em;
15
+        color: #333;
16
+    }
17
+
18
+    .subtitle {
19
+        font-size: 14px;
20
+        line-height: 1.6em;
21
+        color: #999;
22
+    }
23
+
24
+    .flex {
25
+        display: flex;
26
+        flex-wrap: wrap;
27
+
28
+        .flex-item {
29
+            margin-top: 16px;
30
+            margin-right: 8px;
31
+            flex: none;
32
+            width: 100px;
33
+            text-align: center;
34
+        }
35
+    }
36
+}

+ 26
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/RaiseHelpDoc/index.jsx 파일 보기

@@ -0,0 +1,26 @@
1
+import React, { PureComponent } from 'react'
2
+import { Modal, Row, Col } from 'antd'
3
+import EnDash from '../EnDash'
4
+
5
+import Style from './style.less'
6
+import HotBlock from '../HotBlock'
7
+
8
+
9
+export default function RaiseHelpDoc(props) {
10
+  return (
11
+    <Modal footer={null} title="相关说明" visible={props.visible} onCancel={props.onCancel} width={800}>
12
+      <div className={Style.article}>
13
+        <div className={Style.section}>
14
+          <div>
15
+          1.锁房方式:
16
+          自动锁房:用户提交一次认筹只能选择一套房源,交一笔认筹金,仅支持线上缴费。缴费完成后锁定房源,防止他人认筹。缴费期间其他人也无法认筹。<br/>
17
+          手动锁房:用户选定一到多个房源提交认筹单。选择缴费方式,若为线上缴费则线上支付,若为线下支付则直接提交认筹单。<br/><br/>
18
+          2.同一销售批次同一用户可以提交多个认筹单,只要房源不重复。<br/><br/>
19
+          3.管理员在后台可以为客户手工锁定认筹单中的某个房源,若认筹单中房源全部被锁定,需要增加未被锁定房源锁定(增加时需线下和客户确认)。也可以解锁认筹单已被锁定的房源。<br/><br/>
20
+          4."认筹需预选"若为"是",则代表不可只认筹不预选,在执行认筹操作时会提示未预选用户请先预选。如果此时仍然在预选期则可以预选后再认筹。"认筹需预选"若为"否",则代表可以不经过预选环节直接认筹。
21
+        </div>
22
+        </div>
23
+      </div>
24
+    </Modal>
25
+  );
26
+}

+ 36
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/RaiseHelpDoc/style.less 파일 보기

@@ -0,0 +1,36 @@
1
+.article {
2
+    .section {
3
+        font-size: 16px;
4
+        line-height: 1.8em;
5
+        color: #666;
6
+
7
+        & + .section {
8
+            margin-top: 24px;
9
+        }
10
+    }
11
+
12
+    .title {
13
+        font-size: 18px;
14
+        line-height: 2em;
15
+        color: #333;
16
+    }
17
+
18
+    .subtitle {
19
+        font-size: 14px;
20
+        line-height: 1.6em;
21
+        color: #999;
22
+    }
23
+
24
+    .flex {
25
+        display: flex;
26
+        flex-wrap: wrap;
27
+
28
+        .flex-item {
29
+            margin-top: 16px;
30
+            margin-right: 8px;
31
+            flex: none;
32
+            width: 100px;
33
+            text-align: center;
34
+        }
35
+    }
36
+}

+ 230
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/RaiseHouse.jsx 파일 보기

@@ -0,0 +1,230 @@
1
+import React, { useState, useEffect } from 'react';
2
+import { Form, Icon, Input, Button, DatePicker, Select, Card, Row, Col, Pagination, Alert, Radio, Tag, Tooltip, Tabs, Table, notification, Modal,message } from 'antd';
3
+import moment from 'moment';
4
+import request from '../../../../../utils/request';
5
+import apis from '../../../../../services/apis';
6
+import Styles from './style.less';
7
+import { router } from 'umi';
8
+import BlockSelect from '../../../../../components/HouseSelect/BlockSelect'
9
+import UnitSelect from '../../../../../components/HouseSelect/UnitSelect'
10
+import FloorSelect from '../../../../../components/HouseSelect/FloorSelect'
11
+import RoomSelect from '../../../../../components/HouseSelect/RoomSelect'
12
+import ApartmentSelect from '../../../../../components/HouseSelect/ApartmentSelect';
13
+import BasicHeat from './BasicHeat';
14
+import Navigate from '@/components/Navigate';
15
+/**
16
+ *图片设置
17
+ *
18
+ * @param {*} props
19
+ * @returns
20
+ */
21
+function RaiseHouse(props) {
22
+  // eslint-disable-next-line react-hooks/rules-of-hooks
23
+  const [data, setData] = useState([])
24
+  const [basicHeat, setBasicHeat] = useState({visable:false, houseId:'', salesBatchId:''})
25
+  const [houseId, setHouseId] = useState('')
26
+  const raiseId = props.raiseId.raiseId
27
+  const buildingId = props.buildingId
28
+  const salesBatchId = props.salesBatchId
29
+  console.log(salesBatchId,'updateNameupdateNameupdateName');
30
+  useEffect(() => {
31
+    getList()
32
+  }, [])
33
+
34
+  function openNotificationWithIcon(type, message) {
35
+    notification[type]({
36
+      message,
37
+      description:
38
+        '',
39
+    });
40
+  }
41
+
42
+  function getList(params) {
43
+    // 网路请求
44
+    request({ ...apis.house.houseRaise, params: { ...params,raiseId:raiseId, salesBatchId: salesBatchId, buildingId: buildingId} }).then(res => {
45
+      console.log(res,"resresres")
46
+      setData(res)
47
+    }).catch(err => {
48
+      openNotificationWithIcon('error', err.message)
49
+    })
50
+  }
51
+
52
+    // 重置搜索
53
+    function handleReset () {
54
+      props.form.resetFields();
55
+      getList({ pageNumber: 1, pageSize: 10 })
56
+    }
57
+
58
+    function showEdi(e) {
59
+      props.onSuccess(e);
60
+    }
61
+    
62
+  // 分页
63
+  const changePageNum = (pageNumber) => {
64
+    getList({ pageNumber: pageNumber, pageSize: 10,raiseId:raiseId, salesBatchId: salesBatchId, buildingId: buildingId, ...props.form.getFieldsValue() })
65
+  }
66
+
67
+  const rowSelection = {
68
+    onChange: (selectedRowKeys, selectedRows) => {
69
+      setHouseId(selectedRows)
70
+    },
71
+  };
72
+
73
+  // 提交事件
74
+  const handleSubmit = e => {
75
+    e.preventDefault();
76
+    props.form.validateFields((err, values) => {
77
+      if (!err) {
78
+        console.log('提交数据: ', values)
79
+        getList({ pageNumber: 1, pageSize: 10, ...values })
80
+      }
81
+    });
82
+  }
83
+
84
+  function showBaseModal(e){
85
+    if (houseId.length <=0){
86
+      message.info("请选择数据");
87
+      return;
88
+    }
89
+    setBasicHeat(e);
90
+  }
91
+
92
+  const columns = [
93
+    {
94
+      title: '房源编号',
95
+      dataIndex: 'houseId',
96
+      key: 'houseId',
97
+    },
98
+    {
99
+        title: '房源',
100
+        dataIndex: 'roomInfo',
101
+        key: 'roomInfo',
102
+        render: (text, records) => <span>{records.termName}/{records.blockName}/{records.unitName}/{records.floorName}/{records.roomName}</span>,
103
+    },
104
+    {
105
+        title: '价格(万元)',
106
+        dataIndex: 'price',
107
+        key: 'price',
108
+      },
109
+    {
110
+      title: '对应户型',
111
+      dataIndex: 'apartmentName',
112
+      key: 'apartmentName',
113
+    },
114
+    {
115
+      title: '发布状态',
116
+      dataIndex: 'status',
117
+      key: 'status',
118
+      render: (text, records) => <span>{records.status === 1 ? '已发布':'未发布'}</span>,
119
+    },
120
+    {
121
+        title: '认筹基础热度',
122
+        dataIndex: 'raiseHeat',
123
+        key: 'raiseHeat',
124
+    },
125
+    {
126
+        title: '认筹实际热度',
127
+        dataIndex: 'raiseRealHeat',
128
+        key: 'raiseRealHeat',
129
+        render:  (x, row) => <Navigate onClick={() => showEdi({type: "identifyingChips",houseId: row.houseId})}>{row.raiseRealHeat}</Navigate>,
130
+    },
131
+    {
132
+      title: '锁定状态',
133
+      dataIndex: 'houseLockingStatus',
134
+      key: 'houseLockingStatus',
135
+      render: (text, records) => <span>{records.houseLockingStatus === 'locked' ? '已锁定':'未锁定'}</span>,
136
+    },
137
+    {
138
+      title: '锁定认筹单编号',
139
+      dataIndex: 'raiseRecordId',
140
+      key: 'raiseRecordId',
141
+    },
142
+    {
143
+        title: '最后修改人',
144
+        dataIndex: 'updateName',
145
+        key: 'updateName',
146
+    },
147
+    {
148
+        title: '最后修改时间',
149
+        dataIndex: 'updateDate',
150
+        key: 'updateDate',
151
+        render: (x, row) => <><span>{row.updateDate == null ? null : `${moment(row.updateDate).format('YYYY-MM-DD HH:mm:ss')}`}</span></>,
152
+    },
153
+  ]
154
+  const { getFieldDecorator } = props.form
155
+  return (
156
+    <>
157
+    <Form layout="inline" onSubmit={e => handleSubmit(e)}>
158
+        <Form.Item>
159
+          {getFieldDecorator('termname')(
160
+            <Input placeholder="期区"/>,
161
+          )}
162
+        </Form.Item>
163
+        <Form.Item>
164
+          {getFieldDecorator('blockName')(
165
+            <Input placeholder="楼栋"/>,
166
+          )}
167
+        </Form.Item>
168
+        <Form.Item>
169
+          {getFieldDecorator('unitName')(
170
+            <Input placeholder="单元"/>,
171
+          )}
172
+        </Form.Item>
173
+        <Form.Item>
174
+          {getFieldDecorator('floorName')(
175
+            <Input placeholder="层"/>,
176
+          )}
177
+        </Form.Item>
178
+        <Form.Item>
179
+          {getFieldDecorator('roomName')(
180
+            <Input placeholder="房号"/>,
181
+          )}
182
+        </Form.Item>
183
+        <Form.Item>
184
+          {getFieldDecorator('apartmentId')(
185
+             <ApartmentSelect buildingId={props.buildingId} />
186
+          )}
187
+        </Form.Item>        
188
+        <Form.Item>
189
+          {getFieldDecorator('status')(
190
+             <Select placeholder="发布状态" style={{width: '120px'}}>
191
+             <Option value="0">否</Option>
192
+             <Option value="1">是</Option>
193
+           </Select>,
194
+          )}
195
+        </Form.Item>
196
+        <Form.Item>
197
+          {getFieldDecorator('lockingStatus')(
198
+             <Select placeholder="锁定状态" style={{width: '120px'}}>
199
+             <Option value="unlocked">未锁定</Option>
200
+             <Option value="locked">已锁定</Option>
201
+           </Select>,
202
+          )}
203
+        </Form.Item>
204
+        <Form.Item>
205
+          {getFieldDecorator('houseId')(
206
+            <Input placeholder="房源编号"/>,
207
+          )}
208
+        </Form.Item>
209
+        <Form.Item>
210
+          <Button type="primary" htmlType="submit" >
211
+            搜索
212
+          </Button>
213
+          <Button style={{ marginLeft: 8 }} onClick={handleReset}>
214
+            重置
215
+            </Button>
216
+        </Form.Item>
217
+
218
+      </Form>
219
+      <Button type="primary" onClick={() => showBaseModal({visable:true, houseId: houseId, salesBatchId:salesBatchId})} style={{ marginTop: '20px', marginRight:'20px'}}>批量修改基础热度</Button>
220
+      <div style={{marginTop:'20px', marginBottom:'20px'}}><span>共筛选出{data.total}条数据</span></div>
221
+      <Table rowSelection={rowSelection} dataSource={data.records} columns={columns} pagination={false} rowKey="carouseFigureList"/>
222
+      <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '30px' }}>
223
+        <Pagination showQuickJumper defaultCurrent={1} total={data.total} onChange={changePageNum} current={data.current}/>
224
+      </div>   
225
+      <BasicHeat visible={basicHeat.visable} houseId={basicHeat.houseId} salesBatchId={basicHeat.salesBatchId} onCancel={() => setBasicHeat({visable:false, salesBatchId:'',houseId:[]})} onSuccess={()=>getList()}/>   
226
+    </>
227
+  )
228
+}
229
+const WrappedHeader = Form.create({ name: 'RaiseHouse' })(RaiseHouse);
230
+export default WrappedHeader

+ 239
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/Refund.jsx 파일 보기

@@ -0,0 +1,239 @@
1
+import React, { useState, useEffect } from 'react';
2
+import { Form, Input, Button, Icon, Select, Tabs, Radio, DatePicker, message, Upload, Table, Pagination } from 'antd';
3
+import { FormattedMessage } from 'umi-plugin-react/locale';
4
+import moment from 'moment';
5
+import router from 'umi/router';
6
+import apis from '../../../../../services/apis';
7
+import BuildSelect from '../../../../../components/SelectButton/BuildSelect';
8
+import AuthButton from '@/components/AuthButton';
9
+import styles from './style.less';
10
+import request from '../../../../../utils/request';
11
+
12
+const { MonthPicker, RangePicker, WeekPicker } = DatePicker;
13
+const { TextArea } = Input;
14
+
15
+const header = (props) => {
16
+  const [ data, setData ] = useState({})
17
+  const [page, changePage] = useState({})
18
+  const raiseId = props.raiseId.raiseId
19
+  const type = props.type
20
+
21
+  useEffect(() => {
22
+    getList({ pageNum: 1, pageSize: 10, raiseId : raiseId, payStatus:type,});
23
+  },[])
24
+
25
+  // 查询列表
26
+  const getList = (params) => {
27
+    request({ ...apis.house.refundOrderList, params: { ...params, raiseId:raiseId, payStatus:type,},}).then((data) => {
28
+        console.log(data)
29
+        setData(data)
30
+    })
31
+  }
32
+  
33
+  function toDecimal2 (x){
34
+    var f = parseFloat(x);
35
+    if (isNaN(f)) {
36
+      return false;
37
+    }
38
+    var f = Math.round(x * 100) / 100;
39
+    var s = f.toString();
40
+    var rs = s.indexOf('.');
41
+    if (rs < 0) {
42
+      rs = s.length;
43
+      s += '.';
44
+    }
45
+    while (s.length <= rs + 2) {
46
+      s += '0';
47
+    }
48
+    console.log(s)
49
+    return s;
50
+  }
51
+  function regFenToYuan(fen){
52
+    var num = fen;
53
+    num = fen * 0.01;
54
+    num += '';
55
+    var reg = num.indexOf('.') > -1 ? /(\d{1,3})(?=(?:\d{3})+\.)/g : /(\d{1,3})(?=(?:\d{3})+$)/g;
56
+    num = num.replace(reg, '$1');
57
+    console.log(num, 'yuan')
58
+    num = toDecimal2(num)
59
+    return num
60
+  }
61
+  
62
+  const columns = [
63
+    {
64
+      title: '退费单编号',
65
+      // dataIndex: 'orderId',
66
+      // key: 'orderId',
67
+      align: 'center',
68
+      render: (text, record) => (<><span>{record.refundedOrderId}</span></>),
69
+    },
70
+    {
71
+      title: '缴费单编号',
72
+      // dataIndex: 'orderId',
73
+      // key: 'orderId',
74
+      align: 'center',
75
+      render: (text, record) => (<><span>{record.orderId}</span></>),
76
+    },
77
+    {
78
+      title: '认筹单编号',
79
+      dataIndex: 'raiseRecordId',
80
+      key: 'raiseRecordId',
81
+      align: 'center',
82
+    },
83
+    {
84
+      title: '用户手机号',
85
+      dataIndex: 'tel',
86
+      key: 'tel',
87
+      align: 'center',
88
+    },
89
+    {
90
+      title: '微信订单号',
91
+      dataIndex: 'refundNo',
92
+      key: 'refundNo',
93
+      align: 'center',
94
+    },
95
+    {
96
+      title: '退费状态',
97
+      // dataIndex: 'payStatus',
98
+      // key: 'payStatus1',
99
+      align: 'center',
100
+      render: (text, record) => (<><span>{record.payStatus === 'refunded' ? '已退费':'退费失败'}</span></>),
101
+    },
102
+    // {
103
+    //   title: '退费结果',
104
+    //   // dataIndex: 'payStatus',
105
+    //   // key: 'payStatus2',
106
+    //   align: 'center',
107
+    //   render: (text, record) => (<><span>{record.payStatus === 'refunded' ? '已退费':'未退费'}</span></>),
108
+    // },
109
+    {
110
+      title: '退费失败原因',
111
+      dataIndex: 'refundReason',
112
+      key: 'refundReason',
113
+      align: 'center',
114
+    },
115
+    {
116
+      title: '实退金额',
117
+      dataIndex: 'totalFee',
118
+      key: 'totalFee',
119
+      align: 'center',
120
+      render: (x, row) => <span>{regFenToYuan(row.totalFee)}</span>
121
+    },
122
+    {
123
+      title: '退费发起时间',
124
+      dataIndex: 'createDate',
125
+      key: 'createDate',
126
+      align: 'center',
127
+      render: (x, row) => <><span>{row.createDate != null ? `${moment(row.createDate).format('YYYY-MM-DD HH:mm:ss')}` : null}</span></>,
128
+    },
129
+    {
130
+      title: '退费时间',
131
+      // dataIndex: 'updateDate',
132
+      // key: 'updateDate',
133
+      align: 'center',
134
+      render: (x, row) => <><span>{row.payTime != null ? `${moment(row.payTime).format('YYYY-MM-DD HH:mm:ss')}` : null}</span></>,
135
+    },
136
+    // {
137
+    //   title: '退费失败时间',
138
+    //   // dataIndex: 'updateDate',
139
+    //   // key: 'updateDate',
140
+    //   align: 'center',
141
+    //   render: (x, row) => <><span>{`${moment(row.updateDate).format('YYYY-MM-DD HH:mm:ss')}`}</span></>,
142
+    // },
143
+  ];
144
+  
145
+  const changePageNum = (pageNumber) => {
146
+      getList({ pageNum: pageNumber, pageSize: 10, raiseId : raiseId, payStatus:type, ...props.form.getFieldsValue() })
147
+  }
148
+
149
+  // 提交事件
150
+const handleSubmit = (e, props) => {
151
+    e.preventDefault();
152
+    props.form.validateFields((err, values) => {
153
+      if (!err) {
154
+        console.log('提交数据: ', values)
155
+        let {liveTime, ...submitValue} = values
156
+        if (submitValue.payStartTime != null){
157
+          submitValue.payStartTime = moment(submitValue.payStartTime).format('YYYY-MM-DD HH:mm:ss')
158
+        }
159
+        if (submitValue.payEndTime != null){
160
+          submitValue.payEndTime = moment(submitValue.payEndTime).format('YYYY-MM-DD HH:mm:ss')
161
+        }
162
+        getList({ pageNum: 1, pageSize: 10, raiseId : raiseId, payStatus:type, ...values })
163
+      }
164
+    });
165
+  }
166
+
167
+   //重置搜索
168
+   function handleReset() {
169
+    props.form.resetFields();
170
+  }
171
+
172
+  const { getFieldDecorator } = props.form
173
+  return (
174
+
175
+    <>
176
+      <Form layout="inline" onSubmit={e => handleSubmit(e, props)}>
177
+        <Form.Item>
178
+          {getFieldDecorator('refundedOrderId')(
179
+            <Input placeholder="退费单编号"/>
180
+          )}
181
+        </Form.Item>
182
+        <Form.Item>
183
+          {getFieldDecorator('orderId')(
184
+            <Input placeholder="缴费单编号"/>
185
+          )}
186
+        </Form.Item>
187
+        <Form.Item>
188
+          {getFieldDecorator('raiseRecordId')(
189
+            <Input placeholder="认筹单编号"/>
190
+          )}
191
+        </Form.Item>
192
+        <Form.Item>
193
+          {getFieldDecorator('tel')(
194
+            <Input placeholder="用户手机号"/>
195
+          )}
196
+        </Form.Item>
197
+        <Form.Item>
198
+          {getFieldDecorator('tradeNo')(
199
+            <Input placeholder="微信订单号"/>
200
+          )}
201
+        </Form.Item>
202
+        <Form.Item>
203
+          {getFieldDecorator('payStatus')(
204
+            <Select style={{ width: '180px' }} placeholder="退费状态">
205
+              <Option value="unRefunded">已发起</Option>
206
+              <Option value="refunded">已退费</Option>
207
+            </Select>,
208
+          )}
209
+        </Form.Item>
210
+        {/* <Form.Item>
211
+          {getFieldDecorator('payStatus')(
212
+            <Select style={{ width: '180px' }} placeholder="退费结果">
213
+               <Option value="houseApp">成功</Option>
214
+               <Option value="houseApp">失败</Option>
215
+            </Select>,
216
+          )}
217
+        </Form.Item> */}
218
+        <Form.Item>
219
+        <AuthButton name="admin.extendContent.search" noRight={null}>
220
+          <Button type="primary" htmlType="submit" className={styles.searchBtn}>
221
+            搜索
222
+          </Button>
223
+          </AuthButton>
224
+          <Button style={{ marginLeft: 8 }} onClick={handleReset}>
225
+              重置
226
+            </Button>
227
+        </Form.Item>
228
+      </Form>
229
+      <div style={{marginTop:'20px', marginBottom:'20px'}}><span>共筛选出{data.total}条数据</span></div>  
230
+      <Table dataSource={data.records} columns={columns} pagination={false} rowKey="carouseFigureList"/>
231
+      <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '30px' }}>
232
+        <Pagination showQuickJumper defaultCurrent={1} total={data.total} onChange={changePageNum} current={data.current}/>
233
+      </div>
234
+    </>
235
+  )
236
+}
237
+const Refund = Form.create({ name: 'header' })(header);
238
+
239
+export default Refund

+ 29
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/SalesBatchHelpDoc/index.jsx 파일 보기

@@ -0,0 +1,29 @@
1
+import React, { PureComponent } from 'react'
2
+import { Modal, Row, Col } from 'antd'
3
+import EnDash from '../EnDash'
4
+
5
+import Style from './style.less'
6
+import HotBlock from '../HotBlock'
7
+
8
+
9
+export default function SaleBatchHelpDoc(props) {
10
+  return (
11
+    <Modal footer={null} title="相关说明" visible={props.visible} onCancel={props.onCancel} width={800}>
12
+      <div className={Style.article}>
13
+        <div className={Style.section}>
14
+          <div>
15
+            1.楼盘多次开盘加推等销售行为,记录为多个“销售批次”,每个批次销售当前楼盘的一批不同房源。同一楼盘不同批次中房源不能重叠,即1套房不能卖2次。<br/><br/>
16
+            2.销售楼盘下拉仅显示上架楼盘。未上架楼盘若想发布销售批次请先在楼盘列表中将楼盘上架。<br/><br/>
17
+            3.销售批次和房源均发布后,用户在小程序端可以查看并“预选”或“认筹”房源,设置“预选开始时间”和“预选结束时间"可以限制用户预选,超出时间范围禁止用户预选,设置"认筹开始时间"和"认筹结束时间"可以限制用户认筹,超出时间范围禁止用户认筹。<br/><br/>
18
+            4."认筹需预选"若为"是",则代表不可只认筹不预选,在执行认筹操作时会提示未预选用户请先预选。如果此时已超出预选期则无法预选,自然也无法认筹。如果此时仍然在预选期则可以预选后再认筹。"认筹需预选"若为"否",则代表可以不经过预选环节直接认筹。通过配置修改预选时间、认筹时间和认筹是否需预选,可以在销售过程中控制销售行为。<br/><br/>
19
+            5."认筹需缴费"若为"是",则代表在认筹过程中需要缴费(交认筹金/订金)才能最终认筹成功。"认筹需缴费"若为"否",则代表认筹不需要含缴费流程,执行完其他流程即可认筹成功。<br/><br/>
20
+            6.若"认筹需缴费"设置为"是",则需要再设置"缴费方式",目前支持2种缴费方式,"线上微信支付"和"线下付款上传凭据",可以多选,2种支付方式在缴费成功后都需要财务审核,审核不通过需要退费。<br/><br/>
21
+            7.认筹金额支持2位小数,整数部分最大8位数。<br/><br/>
22
+            8.发布状态为否,则在小程序端楼盘详情页面看不到当前销售批次入口。发布状态为是,则用户可以点击入口进入房源列表查看房源进行预选或认筹操作。<br/><br/>
23
+            </div>
24
+        </div>
25
+        
26
+      </div>
27
+    </Modal>
28
+  );
29
+}

+ 36
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/SalesBatchHelpDoc/style.less 파일 보기

@@ -0,0 +1,36 @@
1
+.article {
2
+    .section {
3
+        font-size: 16px;
4
+        line-height: 1.8em;
5
+        color: #666;
6
+
7
+        & + .section {
8
+            margin-top: 24px;
9
+        }
10
+    }
11
+
12
+    .title {
13
+        font-size: 18px;
14
+        line-height: 2em;
15
+        color: #333;
16
+    }
17
+
18
+    .subtitle {
19
+        font-size: 14px;
20
+        line-height: 1.6em;
21
+        color: #999;
22
+    }
23
+
24
+    .flex {
25
+        display: flex;
26
+        flex-wrap: wrap;
27
+
28
+        .flex-item {
29
+            margin-top: 16px;
30
+            margin-right: 8px;
31
+            flex: none;
32
+            width: 100px;
33
+            text-align: center;
34
+        }
35
+    }
36
+}

+ 58
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/UserInfo/index.jsx 파일 보기

@@ -0,0 +1,58 @@
1
+import React, { PureComponent, useState, useEffect } from 'react'
2
+import { Modal, Row, Col, Table, Pagination, Button, Form, Input,message } from 'antd'
3
+import EnDash from '../EnDash'
4
+
5
+import Style from './style.less'
6
+import HotBlock from '../HotBlock'
7
+import request from '../../../../../../utils/request';
8
+import apis from '../../../../../../services/apis';
9
+
10
+const UserInfo = props => {
11
+  // const [data, setData] = useState({})
12
+  const raiseRecord = props.raiseRecordId
13
+  const raiseId = props.raiseId
14
+
15
+  // useEffect(() => {
16
+  //   console.log('userInfoLog', raiseId)
17
+  //   getList({ pageNum: 1, pageSize: 10 });
18
+  // }, [raiseRecordId])
19
+
20
+  // function getList(params) {
21
+  //   // 网路请求
22
+  //   request({ ...apis.house.getUserInfo, params: { raiseRecordId:raiseRecordId} }).then(res => {
23
+  //     console.log(res,'adminData')
24
+  //     setData(res)
25
+  //   }).catch(err => {
26
+  //     message.info("出错了")
27
+  //   })
28
+  // }
29
+
30
+  function refreshList(e){
31
+    console.log('.....',e)
32
+    props.onCancel(e)
33
+  }
34
+
35
+  return (
36
+    <Modal footer={null} title="个人信息" visible={props.visible} onCancel={() => refreshList({visable:false, raiseRecord:raiseRecord})} width={800}>
37
+      <div className={Style.cardBox}>
38
+        <div className={Style.rightBox}>
39
+          <div className={Style.flexBox}>
40
+            <img className={Style.touxiang} src={raiseRecord.avatarurl} />
41
+            <div className={Style.right}>
42
+              <p className={Style.rightItem}>昵称:{raiseRecord.nickname}</p>
43
+              <p className={Style.rightItem}>姓名:{raiseRecord.name}</p>
44
+              <p className={Style.rightItem}>用户手机号:{raiseRecord.tel}</p>
45
+              <p className={Style.rightItem} style={{width:'400px'}}>身份证号:{raiseRecord.idcard}</p>
46
+              <p className={Style.rightItem}>认筹手机号:{raiseRecord.tel}</p> 
47
+            </div>
48
+          </div>
49
+        </div>
50
+      </div>
51
+    </Modal>
52
+  );
53
+}
54
+
55
+const WrappedBase = Form.create({ name: 'UserInfo' })(UserInfo);
56
+
57
+export default WrappedBase
58
+

+ 240
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/UserInfo/style.less 파일 보기

@@ -0,0 +1,240 @@
1
+.SubmitButton {
2
+    background: rgba(239,39,58,1);
3
+    border-radius: 7px;
4
+    border: 0px;
5
+  }
6
+  .text {
7
+    color: rgba(239,39,58,1);
8
+  }
9
+  .SelectFrom {
10
+    width: 180px;
11
+    background: #ffffff;
12
+    border-radius: 7px;
13
+    border: 1px solid #dbdbdb;
14
+  }
15
+  .addButton {
16
+    background: #50be00;
17
+    border-radius: 4px;
18
+    border: 0px;
19
+    margin: 10px 0px;
20
+  }
21
+  .cardText {
22
+    color: #333;
23
+    display: flex;
24
+    align-items: center;
25
+    position: relative;
26
+    line-height: 1.5;
27
+    font-size: 0.106rem;
28
+    margin-bottom: 0.08rem;
29
+  
30
+  }
31
+  .cardItem{
32
+    color: #666;
33
+    display: flex;
34
+    align-items: center; 
35
+    line-height: 1.5;
36
+    font-size: 0.106rem;
37
+    margin-bottom: 0.08rem; 
38
+  }
39
+  .ediText {
40
+    font-size: 0.106rem;
41
+    color: #ff925c;
42
+    line-height: 24px;
43
+    position: absolute;
44
+    right: 0;
45
+  }
46
+  .title{
47
+    display: inline-block;
48
+    width:  0.54rem;
49
+    justify-content: space-between;
50
+    text-align: justify;
51
+    text-align-last:justify
52
+  }
53
+  
54
+  .address { 
55
+    width: 400px;
56
+    height: 24px; 
57
+    text-overflow: ellipsis; 
58
+    white-space: nowrap;
59
+    overflow: hidden;
60
+  }
61
+  
62
+  .pitchButton { 
63
+    border-color: rgba(255,126,72,1);
64
+    background-color: rgba(255,126,72,1);
65
+    color: rgba(255,255,255,1); 
66
+  }
67
+  .noButton {
68
+    border-color: rgba(255,126,72,1);
69
+    color: rgba(255,126,72,1);
70
+  }
71
+  .displayS {
72
+    display: none;
73
+  }
74
+  
75
+  
76
+  // 客户详情样式
77
+  .cardBox{
78
+    display: flex;
79
+    .leftBox{
80
+      width:1000px;
81
+      min-width:350px;
82
+      height:1000px;
83
+      background:rgba(255,255,255,1);
84
+      box-shadow:0px 0px 16px 2px rgba(0,0,0,0.12);
85
+      border-radius:8px;
86
+      display: inline-block;
87
+      margin-right: 30px;
88
+      padding: 30px;
89
+      overflow: hidden;
90
+    }
91
+    .rightBox{
92
+      width:865px;
93
+      min-width:342px;
94
+      height:290px;
95
+      background:rgba(255,255,255,1);
96
+      // box-shadow:0px 0px 16px 2px rgba(0,0,0,0.12);
97
+      border-radius:8px;
98
+      display: inline-block;
99
+      margin-right: 30px;
100
+      padding: 30px;
101
+      overflow: hidden;
102
+    }
103
+    .rightBox{
104
+      width:-webkit-fill-available;
105
+      height:315px;
106
+      min-width: 100%;
107
+      background:rgba(255,255,255,1);
108
+      // box-shadow:0px 0px 16px 2px rgba(0,0,0,0.12);
109
+      border-radius:8px;
110
+      display: inline-block;
111
+      padding: 30px;
112
+      overflow: hidden;
113
+      position: relative;
114
+    }
115
+    .rightBoxCentre{
116
+      width:865px;
117
+      height:345px;
118
+      min-width: 60%;
119
+      background:rgba(255,255,255,1);
120
+      box-shadow:0px 0px 16px 2px rgba(0,0,0,0.12);
121
+      border-radius:8px;
122
+      display: inline-block;
123
+      padding: 30px;
124
+      overflow: hidden;
125
+      position: relative;
126
+    }
127
+    .leftBoxCentre{
128
+      width:100%;
129
+      height:345px;
130
+      background:rgba(255,255,255,1);
131
+      box-shadow:0px 0px 16px 2px rgba(0,0,0,0.12);
132
+      border-radius:8px;
133
+      display: inline-block;
134
+      padding: 30px;
135
+      overflow: hidden;
136
+      position: relative;
137
+    }
138
+    .tit{
139
+      font-size:0.15rem;
140
+      font-weight:600;
141
+      color:#222;
142
+      margin: 10px 0 0 0;
143
+    }
144
+    .flexBox{
145
+      display: flex;
146
+      align-items: end;
147
+    }
148
+    .touxiang{
149
+      width: 120px;
150
+      width: 120px;
151
+      border-radius: 6px;
152
+      margin: 80px 0 20px 0;
153
+    }
154
+    .touxiangphoto{
155
+      width: 80px;
156
+      height: 80px;
157
+      margin: 38px 0 0px 0;
158
+    }
159
+    .infoItem{
160
+      color:#666;
161
+      font-size: 0.1rem;
162
+      margin: 0 0 30px 0;
163
+      
164
+    }
165
+    .rightItem{
166
+      color:#666;
167
+      font-size: 0.1rem;
168
+      margin: 0 0 15px 0;
169
+    }
170
+    .right{
171
+      width: 25%;
172
+      min-width: 1.3rem;
173
+      margin-left: 0.1rem;
174
+      padding-top: 0.3rem;
175
+      // position: absolute;
176
+      // top:108px;
177
+      // left:170px;
178
+    }
179
+    .rightphone{
180
+    
181
+      position: absolute;
182
+      top:108px;
183
+      left:170px;
184
+    }
185
+    .left{
186
+      position: absolute;
187
+      top:108px;
188
+      left:60%;
189
+    
190
+    }
191
+    .rightInfo{
192
+      width: 25%;
193
+      min-width: 1.3rem;
194
+      margin-right: 0.1rem;
195
+      padding-top: 0.3rem;
196
+      // position: absolute;
197
+      // top:108px;
198
+      // left:80%;
199
+    }
200
+  
201
+    .Centered{
202
+      width: 25%;
203
+      // position: absolute;
204
+      // top:108px;
205
+      // left:30%;
206
+      min-width: 1.3rem;
207
+      margin: 0 0 15px 0;
208
+      color:#666;
209
+      font-size: 0.1rem;
210
+      padding-top: 0.3rem;
211
+    }
212
+  
213
+    .rightCentered{
214
+      // position: absolute;
215
+      // top:108px;
216
+      // left:55%;
217
+      width: 25%;
218
+      min-width: 1.3rem;
219
+      margin: 0 0 15px 0;
220
+      padding-top: 0.3rem;
221
+      color:#666;
222
+      font-size: 0.1rem;
223
+    }
224
+    
225
+  }
226
+  .recordBox{
227
+    width:100%;
228
+    background:rgba(255,255,255,1);
229
+    box-shadow:0px 0px 16px 2px rgba(0,0,0,0.12);
230
+    border-radius:8px;
231
+    margin-top: 30px;
232
+    padding: 30px;
233
+    .tableName{
234
+      font-size:24px;
235
+      font-weight:600;
236
+      color:#222;
237
+    }
238
+  }
239
+  
240
+  

+ 97
- 0
estateagents-admin-manager/src/pages/house/raise/edit/components/style.less 파일 보기

@@ -0,0 +1,97 @@
1
+.SubmitButton {
2
+  background: #3a91d5;
3
+  border-radius: 7px;
4
+  border: 0px;
5
+}
6
+.SelectFrom {
7
+  width: 180px;
8
+  background: #ffffff;
9
+  border-radius: 7px;
10
+  border: 1px solid #dbdbdb;
11
+}
12
+.addButton {
13
+  border-radius: 4px;
14
+  border: 0px;
15
+  margin: 10px 0px;
16
+}
17
+.cardText {
18
+  font-size: 0.106rem;
19
+  color: #333;
20
+  display: flex;
21
+  align-items: center;
22
+  position: relative;
23
+  margin-bottom: 0.08rem; 
24
+}
25
+
26
+.recommderTag{
27
+  position: absolute;
28
+  color: #fff;
29
+  line-height: 0.28rem;
30
+  width: 0.54rem;
31
+  background-color: rgba(0,0,0,0.4);
32
+  text-align: center;
33
+  border-radius: 12px 0 12px 0;
34
+  font-size: 0.09rem;
35
+}
36
+.cardItem{
37
+  font-size: 0.106rem;
38
+  font-weight: 400;
39
+  color: #666;
40
+  display: flex;
41
+  align-items: center;  
42
+  margin-bottom: 0.08rem;
43
+  .title{
44
+    display: inline-block;
45
+    width: 0.58rem;
46
+  
47
+    min-width: 0.58rem;
48
+    justify-content: space-between;
49
+    text-align: justify;
50
+    text-align-last:justify
51
+  }
52
+  
53
+}
54
+.cardText{
55
+  font-size: 0.106rem;
56
+  font-weight: 400;
57
+  color: #666;
58
+  display: flex;
59
+  align-items: center;  
60
+  margin-bottom: 0.08rem;
61
+  .title{
62
+    display: inline-block;
63
+    width: 0.58rem;
64
+  
65
+    min-width: 0.58rem;
66
+    justify-content: space-between;
67
+    text-align: justify;
68
+    text-align-last:justify
69
+  }
70
+  
71
+}
72
+.ediText {
73
+  font-size: 0.106rem;
74
+  color: #ff925c;
75
+  position: absolute;
76
+  right: 0;
77
+
78
+}
79
+
80
+
81
+.address { 
82
+  width: 400px;
83
+  height: 24px; 
84
+  text-overflow: ellipsis; 
85
+  white-space: nowrap;
86
+  overflow: hidden;
87
+}
88
+.cover{
89
+  width: 100%;
90
+
91
+  padding-bottom: 56.25%;
92
+  background-size: 100% 100% !important;
93
+ 
94
+  border-radius: 12px 12px 0 0;
95
+  
96
+    // height: '14vw';
97
+}

+ 332
- 0
estateagents-admin-manager/src/pages/house/raise/list/index.jsx 파일 보기

@@ -0,0 +1,332 @@
1
+import React, { useState, useEffect } from 'react';
2
+import { Form, Input, Button, Icon, Select, message, Table, Pagination, Modal, notification } from 'antd';
3
+import router from 'umi/router';
4
+import moment from 'moment';
5
+import AuthButton from '@/components/AuthButton';
6
+import withActions from '@/components/ActionList';
7
+import EditIcon from '@/components/EditIcon';
8
+import styles from '../../../style/GoodsList.less';
9
+import BuildSelect from '../../../../components/SelectButton/BuildSelect';
10
+import apis from '../../../../services/apis';
11
+import request from '../../../../utils/request';
12
+import RaiseHelpDoc from '../edit/components/RaiseHelpDoc';
13
+import Navigate from '@/components/Navigate';
14
+
15
+const { Option } = Select;
16
+
17
+const header = props => {
18
+  // eslint-disable-next-line react-hooks/rules-of-hooks
19
+  const [data, setData] = useState({ list: [], total: 0 })
20
+  //   const [page, changePage] = useState({})
21
+  const [houseIdList, setHouseIdList] = useState([])
22
+  const [time, setTime] = useState('')
23
+  const [showHelp, setShowHelp] = useState(false)
24
+
25
+  // 查询列表
26
+  const getList = params => {
27
+    request({ ...apis.house.taRaiseList, params: { ...params } }).then(data => {
28
+      console.log(data)
29
+      setData(data)
30
+    })
31
+  }
32
+
33
+  // eslint-disable-next-line react-hooks/rules-of-hooks
34
+  useEffect(() => {
35
+    getList({ pageNum: 1, pageSize: 10 });
36
+  }, [])
37
+
38
+  // 跳转到编辑
39
+  const toAddHouse = rowData => () => {
40
+    if(rowData) {
41
+      router.push({
42
+      pathname: '/house/raise/edit',
43
+      query: {
44
+        id: rowData.raiseId,
45
+        buildingId: rowData.buildingId,
46
+        salesBatchId: rowData.salesBatchId,
47
+      },
48
+    });
49
+      return
50
+    }
51
+    router.push({
52
+      pathname: '/house/raise/add',
53
+    });
54
+  }
55
+
56
+  function openNotificationWithIcon(type, message) {
57
+    notification[type]({
58
+      message,
59
+      description:
60
+        '',
61
+    });
62
+  }
63
+
64
+  function toDecimal2 (x){
65
+    var f = parseFloat(x);
66
+    if (isNaN(f)) {
67
+      return false;
68
+    }
69
+    var f = Math.round(x * 100) / 100;
70
+    var s = f.toString();
71
+    var rs = s.indexOf('.');
72
+    if (rs < 0) {
73
+      rs = s.length;
74
+      s += '.';
75
+    }
76
+    while (s.length <= rs + 2) {
77
+      s += '0';
78
+    }
79
+    console.log(s)
80
+    return s;
81
+  }
82
+  function regFenToYuan(fen){
83
+    var num = fen;
84
+    num = fen * 0.01;
85
+    num += '';
86
+    var reg = num.indexOf('.') > -1 ? /(\d{1,3})(?=(?:\d{3})+\.)/g : /(\d{1,3})(?=(?:\d{3})+$)/g;
87
+    num = num.replace(reg, '$1');
88
+    console.log(num, 'yuan')
89
+    num = toDecimal2(num)
90
+    return num
91
+  }
92
+  
93
+  const toDelBatch = rowData => () =>{
94
+    console.log(houseIdList, 'houseIdListhouseIdList')
95
+    if(houseIdList.length < 1){
96
+      openNotificationWithIcon('error', '请先选择需要删除的认筹单')
97
+      return
98
+    }
99
+
100
+    Modal.confirm({
101
+      title: '确定删除认筹单吗',
102
+      okText: '确定',
103
+      cancelText: '取消',
104
+      onOk () {
105
+        console.log(houseIdList,'houseIdListhouseIdList');
106
+        request({ ...apis.house.batchDelRaise, data: houseIdList, }).then((data) => {
107
+          message.info("操作成功")
108
+          getList({ pageNum: 1, pageSize: 10 });
109
+        }).catch((err) => {
110
+          // message.info(err.msg)
111
+        })
112
+      },
113
+    });
114
+  }
115
+
116
+  const newQrcode = row => {
117
+    const x = new XMLHttpRequest();
118
+    const resourceUrl = row.qrCode
119
+    x.open('GET', resourceUrl, true);
120
+    x.responseType = 'blob';
121
+    x.onload = function (e) {
122
+      const url = window.URL.createObjectURL(x.response)
123
+      const a = document.createElement('a');
124
+      a.href = url;
125
+      a.style.display = 'none'
126
+      a.download = '活动二维码.png';
127
+      a.click();
128
+    }
129
+    x.send();
130
+  }
131
+
132
+  /**
133
+   *
134
+   *
135
+   * @param {*} props
136
+   * @returns
137
+   */
138
+  const columns = [
139
+    {
140
+      title: '销售批次名',
141
+      dataIndex: 'salesBatchName',
142
+      key: 'salesBatchName',
143
+      align: 'center',
144
+      render:  (x, row) => <Navigate onClick={toAddHouse(row)}>{row.salesBatchName}</Navigate>,
145
+    },
146
+    {
147
+      title: '楼盘名称',
148
+      dataIndex: 'buildingName',
149
+      key: 'buildingName',
150
+      align: 'center',
151
+    },
152
+    {
153
+      title: '备注',
154
+      dataIndex: 'remark',
155
+      key: 'remark',
156
+      align: 'center',
157
+    },
158
+    {
159
+      title: '房源总数',
160
+      dataIndex: 'salesNumber',
161
+      key: 'salesNumber',
162
+      align: 'center',
163
+    },
164
+    {
165
+      title: '发布状态',
166
+      dataIndex: 'status',
167
+      key: 'status',
168
+      align: 'center',
169
+      render: status => <><span>{status == 0 ? '否' : '是'}</span></>,
170
+    },
171
+    {
172
+      title: '认筹开始时间',
173
+      dataIndex: 'raiseStartTime',
174
+      key: 'raiseStartTime',
175
+      align: 'center',
176
+      render: (x, row) => <><span>{`${moment(row.raiseStartTime).format('YYYY-MM-DD HH:mm:ss')}`}</span></>,
177
+    },
178
+    {
179
+      title: '认筹结束时间',
180
+      dataIndex: 'raiseEndTime',
181
+      key: 'raiseEndTime',
182
+      align: 'center',
183
+      render: (x, row) => <><span>{`${moment(row.raiseEndTime).format('YYYY-MM-DD HH:mm:ss')}`}</span></>,
184
+    },
185
+    {
186
+      title: '锁房方式',
187
+      dataIndex: 'houseLockingType',
188
+      key: 'houseLockingType',
189
+      align: 'center',
190
+      render: (x, row) => <><span>{row.houseLockingType == 'auto' ? "自动锁房" : "手动锁房"}</span></>,
191
+    },
192
+    {
193
+      title: '认筹金额',
194
+      dataIndex: 'raisePrice',
195
+      key: 'raisePrice',
196
+      align: 'center',
197
+      render: (x, row) => <span>{regFenToYuan(row.raisePrice)}</span>
198
+    },
199
+    {
200
+      title: '缴费方式',
201
+      dataIndex: 'payType',
202
+      key: 'payType',
203
+      align: 'center',
204
+      render: (x, row) => <><span>{row.payType == 'offLine' ? "线下缴费" : row.payType == 'onLine' ? "线上缴费" : "线上缴费,线下缴费"}</span></>,
205
+    },
206
+    {
207
+      title: '认筹单总数',
208
+      dataIndex: 'raiseRealHeat',
209
+      key: 'raiseRealHeat',
210
+      align: 'center',
211
+    },
212
+    {
213
+      title: '操作',
214
+      dataIndex: '',
215
+      key: '',
216
+      align: 'center',
217
+      render: withActions((text, record) => [
218
+        <AuthButton name="admin.raise.detail.get" noRight={null}>
219
+          <EditIcon type="look" text="查看详情" onClick={toAddHouse(record)} />
220
+        </AuthButton>,
221
+      ]),
222
+    },
223
+  ];
224
+  const getSignList = dynamicId => {
225
+    router.push({
226
+      pathname: '/activity/SignList',
227
+      query: {
228
+        dynamicId,
229
+      },
230
+    });
231
+  }
232
+
233
+  const changePageNum = pageNumber => {
234
+    getList({ pageNum: pageNumber, pageSize: 10, ...props.form.getFieldsValue() })
235
+  }
236
+
237
+  const rowSelection = {
238
+    onChange: (selectedRowKeys, selectedRows) => {
239
+      console.log('selectedRowKeys:', selectedRowKeys, 'selectedRows: ', selectedRows);
240
+      setHouseIdList(selectedRows)
241
+    },
242
+  };
243
+
244
+  // 提交事件
245
+  const handleSubmit = e => {
246
+    e.preventDefault();
247
+    props.form.validateFields((err, values) => {
248
+      if (!err) {
249
+        console.log('提交数据: ', values)
250
+        if (time) {
251
+          values.time = `${moment(time).format('YYYY-MM-DDT00:00:00.000')}Z`
252
+        } else {
253
+          values.time = null
254
+        }
255
+        
256
+        getList({ pageNum: 1, pageSize: 10, ...values })
257
+      }
258
+    });
259
+  }
260
+
261
+  // 重置搜索
262
+  function handleReset () {
263
+    props.form.resetFields();
264
+    setTime('')
265
+    getList({ pageNum: 1, pageSize: 10 })
266
+  }
267
+
268
+  // 时间回调
269
+  function timeOnChange(date, dateString) {
270
+    console.log(date, dateString)
271
+    setTime(date)
272
+  }
273
+
274
+
275
+  const { getFieldDecorator } = props.form
276
+  return (
277
+
278
+    <>
279
+      {/* style={{ display: 'none' }} */}
280
+      <div id="qrcode"></div>
281
+      <Form layout="inline" onSubmit={e => handleSubmit(e)}>
282
+        <Form.Item>
283
+          {getFieldDecorator('salesBatchName')(
284
+             <Input
285
+             prefix={<Icon type="text" style={{ color: 'rgba(0,0,0,.25)' }} />}
286
+             placeholder="销售批次名"
287
+           />,
288
+          )}
289
+        </Form.Item>
290
+        <Form.Item>
291
+          {getFieldDecorator('buildingId')(
292
+            <BuildSelect />,
293
+          )}
294
+        </Form.Item>
295
+        <Form.Item>
296
+          {getFieldDecorator('status')(
297
+            <Select style={{ width: '180px' }} placeholder="发布状态">
298
+            <Option value="1">是</Option>
299
+            <Option value="0">否</Option>
300
+          </Select>,
301
+          )}
302
+        </Form.Item>
303
+        <Form.Item>
304
+          <AuthButton name="admin.buildingDynamic.search" noRight={null}>
305
+            <Button type="primary" htmlType="submit" className={styles.searchBtn}>
306
+              搜索
307
+            </Button>
308
+          </AuthButton>
309
+          <Button style={{ marginLeft: 8 }} onClick={handleReset}>
310
+            重置
311
+            </Button>
312
+        </Form.Item>
313
+      </Form>
314
+      <AuthButton name="admin.raise.add.post" noRight={null}>
315
+        <Button type="danger" className={styles.addBtn} onClick={toAddHouse()}>新增</Button>
316
+      </AuthButton>
317
+      <AuthButton name="admin.raise.del" noRight={null}>
318
+        <Button type="primary" className={styles.addBtn} onClick={toDelBatch()} style={{marginLeft:'30px'}}>删除</Button>
319
+      </AuthButton>
320
+      <Icon type="question-circle" theme="filled" style={{ fontSize: '25px', color: '#F00', marginLeft:'30px'}} onClick={() => setShowHelp(true)} />
321
+      <Table rowSelection={rowSelection}
322
+       dataSource={data.records} columns={columns} pagination={false} rowKey="activityList" />
323
+      <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '30px' }}>
324
+        <Pagination showQuickJumper defaultCurrent={1} total={data.total} onChange={e => changePageNum(e)} current={data.current}/>
325
+      </div>
326
+      <RaiseHelpDoc visible={showHelp} onCancel={() => setShowHelp(false)} />
327
+    </>
328
+  )
329
+}
330
+const WrappedHeader = Form.create({ name: 'header' })(header);
331
+
332
+export default WrappedHeader

+ 132
- 0
estateagents-admin-manager/src/pages/indexEcharts/components/IntentionalCustomers.jsx 파일 보기

@@ -0,0 +1,132 @@
1
+import React, { Component, useState, useEffect } from 'react';
2
+import { Form, Icon, Input, Button, DatePicker, Select, Card, Row, Col, Pagination, Alert, Table, Avatar, Radio, Modal, Descriptions } from 'antd';
3
+import BuildSelect from '../../../components/SelectButton/BuildSelect'
4
+import { func } from 'prop-types';
5
+import request from '../../../utils/request';
6
+import apis from '../../../services/apis';
7
+// const { Option } = Select;
8
+
9
+const UserBehavior = (props) => {
10
+  const [data, setData] = useState({ records: [] })
11
+  const [buildingId, setBuildingId] = useState('')
12
+  useEffect(() => {
13
+    IntentionUsers({ pageNum: 1, pageSize: 5 })
14
+    // getUserBehaviorProfile(formatDate(props.startDate, props.endDate))
15
+
16
+  }, [])
17
+  function IntentionUsers (params) {
18
+    request({
19
+      ...apis.indexEcharts.intentionUsers,
20
+      params: { ...params }
21
+    }).then((data) => {
22
+      console.log(data,"datadata")
23
+      setData(data)
24
+    })
25
+  }
26
+
27
+  // 分页
28
+  function onChange(pageNum) {
29
+    // eslint-disable-next-line react-hooks/rules-of-hooks
30
+    IntentionUsers({ pageNum: pageNum, pageSize: 5, buildingId })
31
+  }
32
+
33
+  // getIntentionUsers({ commit }, payload) {
34
+  //   return new Promise((resolve, reject) => {
35
+  //     request({
36
+  //       ...apis.indexEcharts.intentionUsers,
37
+  //       params: { pageSize: 9999, ...payload }
38
+  //     }).then((data) => {
39
+  //       resolve(data.records)
40
+  //     }).catch((err) => {
41
+  //       reject(err)
42
+  //     })
43
+  //   })
44
+  // },
45
+  // const dataSource = [
46
+  //   {
47
+  //     key: '1',
48
+  //     name: '胡彦斌',
49
+  //     age: 32,
50
+  //     address: '西湖区湖底公园1号',
51
+  //   },
52
+  //   {
53
+  //     key: '2',
54
+  //     name: '胡彦祖',
55
+  //     age: 42,
56
+  //     address: '西湖区湖底公园1号',
57
+  //   },
58
+  // ];
59
+  
60
+  const columns = [
61
+    {
62
+      title: '用户姓名',
63
+      dataIndex: 'personName',
64
+      key: 'personName',
65
+      width: '25%',
66
+    },
67
+    {
68
+      title: '手机号',
69
+      dataIndex: 'phone',
70
+      key: 'phone',
71
+      width: '25%',
72
+    },
73
+    {
74
+      title: '意向楼盘',
75
+      dataIndex: 'buildingName',
76
+      key: 'buildingName',
77
+      width: '25%',
78
+    },
79
+    {
80
+      title: '意向值',
81
+      dataIndex: 'intention',
82
+      key: 'intention',
83
+      width: '25%',
84
+    },
85
+  ];
86
+
87
+  function handleBuildingChange (e) {
88
+    IntentionUsers({  pageNum: 1, pageSize: 5, buildingId: e })
89
+    setBuildingId(e)
90
+  }
91
+
92
+  //意向客户导出
93
+  function exportIntentionUsers () {
94
+    request({
95
+      ...apis.indexEcharts.exportIntentionUsers,
96
+      params: { buildingId }
97
+    }).then((data) => {
98
+      if (!data) {
99
+        return
100
+      }
101
+      const url = window.URL.createObjectURL(new Blob([data]))
102
+      const link = document.createElement('a')
103
+      link.style.display = 'none'
104
+      link.href = url
105
+      link.setAttribute('download', '意向客户.xlsx')
106
+      document.body.append(link)
107
+      link.click()
108
+    })
109
+  }
110
+
111
+  return (
112
+    <>
113
+      <div>
114
+      <p style={{fontSize:'0.12rem',fontWeight:'600'}}>意向客户</p>
115
+        <Row>
116
+          <Col span={22}>
117
+            <BuildSelect slot='action' onChange={(e => handleBuildingChange(e))} value={buildingId}></BuildSelect>
118
+          </Col>
119
+          <Col span={2}>
120
+            <Button type="primary" onClick={exportIntentionUsers}>导出</Button>
121
+          </Col>
122
+        </Row>
123
+
124
+        <Table rowKey="IntentionalCustomers" dataSource={data.records} columns={columns} style={{marginTop:'15px'}} pagination={{ total: data.total, defaultPageSize: 5, onChange: e => onChange(e) }} scroll={{ y: 500 }} />
125
+
126
+      </div>
127
+
128
+    </>
129
+  )
130
+}
131
+
132
+export default UserBehavior;

+ 103
- 0
estateagents-admin-manager/src/pages/indexEcharts/components/NewUsers.jsx 파일 보기

@@ -0,0 +1,103 @@
1
+import React, { Component, useState, useEffect } from 'react';
2
+import echarts from 'echarts/lib/echarts';
3
+import EChart from '../../../components/EchartsTest/EChart';
4
+import request from '../../../utils/request';
5
+import apis from '../../../services/apis';
6
+import moment from 'moment';
7
+import router from 'umi/router';
8
+import { Table, Select, Row, Col, Menu, Dropdown, Button, Icon, message } from 'antd';
9
+
10
+import styles from '../styles.less'
11
+const formatDate = (start, end) => {
12
+  const startDate = moment(start).format('YYYY-MM-DDT00:00:00.000') + 'Z'
13
+  const endDate = moment(end).format('YYYY-MM-DDT23:59:59.999') + 'Z'
14
+  return { startDate, endDate }
15
+}
16
+const NewUsers = (props) => {
17
+  const [data, setData] = useState({ records: [] })
18
+
19
+
20
+  useEffect(() => {
21
+    NewsUserCount(formatDate(props.startDate, props.endDate))
22
+  }, [props.startDate, props.endDate])
23
+
24
+
25
+  function NewsUserCount (params) {
26
+    request({
27
+      ...apis.indexEcharts.changeNewUser,
28
+      params,
29
+    }).then((data) => {
30
+      setData(data)
31
+    })
32
+  }
33
+
34
+  const dataZoom=props.dataZoom?[
35
+    {
36
+      type: 'inside',
37
+      start: 0,
38
+      end: 100
39
+    },
40
+    {
41
+      type: 'slider',
42
+      start: 0,
43
+      end: 100
44
+    },
45
+  ] : undefined 
46
+  const dataset = data || []
47
+  const options = {
48
+
49
+   
50
+      color: ["#FF814C", "#F02B3E"],
51
+      tooltip: {
52
+        trigger: "axis"
53
+      },
54
+      icon: "rect",
55
+      legend: {
56
+        data: ["新用户数", "授权注册"]
57
+      },
58
+      toolbox: {},
59
+      xAxis: {
60
+        type: "category",
61
+      },
62
+      yAxis: {},
63
+      dataZoom,
64
+      series: [
65
+        {
66
+          name: "新用户数",
67
+          type: "line",
68
+          smooth:true, 
69
+        },
70
+        {
71
+          name: "授权注册",
72
+          type: "line",
73
+          smooth:true, 
74
+        }
75
+      ],
76
+      dataset: {
77
+        dimensions: ['createTime', 'fromNum', 'registeredNum'],
78
+        source: dataset
79
+      }
80
+ 
81
+    
82
+    
83
+  }
84
+
85
+
86
+  const piestyles = {
87
+    width: '100%',
88
+    height: '400px',
89
+  }
90
+
91
+  return (
92
+    <>
93
+      <div>
94
+        <div >
95
+          <p onClick={()=>router.push('/statistical/newUsers')}><span style={{borderBottom:'1px solid #f02d40',cursor: 'pointer',fontSize:'0.12rem',fontWeight:'600'}}>新增用户</span> {!props.BuildSelectHide && <span style={{ fontSize: '0.09rem', color: '#888', marginLeft: '0.06rem' }}>最近七天</span>}</p>
96
+       </div>
97
+        <EChart options={options} style={piestyles}  />
98
+      </div>
99
+    </>
100
+  )
101
+}
102
+
103
+export default NewUsers;

+ 109
- 0
estateagents-admin-manager/src/pages/indexEcharts/components/UserActive.jsx 파일 보기

@@ -0,0 +1,109 @@
1
+import React, { Component, useState, useEffect } from 'react';
2
+import echarts from 'echarts/lib/echarts';
3
+import EChart from '../../../components/EchartsTest/EChart';
4
+import request from '../../../utils/request';
5
+import apis from '../../../services/apis';
6
+import moment from 'moment';
7
+import router from 'umi/router';
8
+import { Table, Select, Row, Col, Menu, Dropdown, Button, Icon, message } from 'antd';
9
+// import UserSource from './mmm';
10
+
11
+import styles from '../styles.less'
12
+const formatDate = (start, end) => {
13
+  const startDate = moment(start).format('YYYY-MM-DDT00:00:00.000') + 'Z'
14
+  const endDate = moment(end).format('YYYY-MM-DDT23:59:59.999') + 'Z'
15
+  return { startDate, endDate }
16
+}
17
+const UserSource = (props) => {
18
+  const [data, setData] = useState({ records: [] })
19
+  //柱图
20
+
21
+  useEffect(() => {
22
+    UserActive({ dateType: 'day' })
23
+  }, [])
24
+
25
+
26
+
27
+  function UserActive (params) {
28
+    request({
29
+      ...apis.indexEcharts.userActive,
30
+      params: { pageSize: 9999, ...params },
31
+    }).then((data) => {
32
+  
33
+      setData(data)
34
+    })
35
+  }
36
+
37
+  const dataset = (data.selectActiveUserCount) || []
38
+  const options = {
39
+
40
+    tooltip: {},
41
+    xAxis: { type: 'category' },
42
+    yAxis: {},
43
+    series: {
44
+      type: 'bar',
45
+      name: '活跃用户',
46
+      barWidth: 50,
47
+      data: dataset.map(x => ([x.date, !x.activityCount ? 0 : x.activityCount])),
48
+      itemStyle: {
49
+        normal: {
50
+          barBorderRadius: [50, 50, 0, 0],
51
+          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
52
+            offset: 0,
53
+            color: '#FD8A95'
54
+          }, {
55
+            offset: 1,
56
+            color: '#F13043'
57
+          }]),
58
+          shadowColor: 'rgba(0, 0, 0, 0.4)',
59
+
60
+        }
61
+      }
62
+    }
63
+
64
+  }
65
+
66
+
67
+  function onChange (value) {
68
+    UserActive({ dateType: value })
69
+  }
70
+
71
+
72
+  const piestyles = {
73
+    width: '100%',
74
+    height: '400px',
75
+
76
+  }
77
+
78
+
79
+  return (
80
+    <>
81
+      <div>
82
+
83
+
84
+        <div >
85
+        <p><span style={{fontSize:'0.12rem',fontWeight:'600'}}>用户活跃数</span></p>
86
+
87
+          <Select
88
+            showSearch
89
+            style={{ width: 100 }}
90
+            placeholder="日活跃"
91
+            optionFilterProp="children"
92
+            onChange={onChange}
93
+          >
94
+            <Option value="day">日活跃</Option>
95
+            <Option value="month">月活跃</Option>
96
+
97
+          </Select>
98
+        
99
+       </div>
100
+
101
+
102
+        <EChart options={options} style={piestyles} />
103
+      </div>
104
+
105
+    </>
106
+  )
107
+}
108
+
109
+export default UserSource;

+ 289
- 0
estateagents-admin-manager/src/pages/indexEcharts/components/UserBehavior.jsx 파일 보기

@@ -0,0 +1,289 @@
1
+import React, { Component, useState, useEffect } from 'react';
2
+import EChart from '../../../components/EchartsTest/EChart';
3
+import request from '../../../utils/request';
4
+import apis from '../../../services/apis';
5
+import moment from 'moment';
6
+import router from 'umi/router';
7
+import 'echarts/lib/component/dataZoom'
8
+import { Table, Select, Row, Col, Menu, Dropdown, Button, Icon, message, Modal } from 'antd';
9
+import BuildSelect from '../../../components/SelectButton/BuildSelect'
10
+
11
+const { Option } = Select;
12
+
13
+
14
+const eventcolumns = [
15
+  {
16
+    title: '编号',
17
+    dataIndex: 'recordId',
18
+    key: 'recordId',
19
+    align: 'center',
20
+    width: '16%',
21
+  },
22
+  {
23
+    title: '访问时间',
24
+    dataIndex: 'visitTime',
25
+    key: 'visitTime',
26
+    align: 'center',
27
+    width: '18%',
28
+    render: (x, row) => (
29
+      <>
30
+        <span>{ moment(row.visitTime).format('YYYY-MM-DD hh:mm:ss') }</span>
31
+      </>
32
+    ),
33
+  },
34
+  {
35
+    title: '离开时间',
36
+    dataIndex: 'leaveTime',
37
+    key: 'leaveTime',
38
+    align: 'center',
39
+    width: '18%',
40
+    render: (x, row) => (
41
+      <>
42
+        <span>{ row.leaveTime && moment(row.leaveTime).format('YYYY-MM-DD hh:mm:ss') }</span>
43
+      </>
44
+    ),
45
+  },
46
+]
47
+
48
+
49
+class EventcoModal extends React.Component {
50
+  constructor(props) {
51
+    super(props)
52
+    this.state = {
53
+      eventList: [],
54
+      visibleData: { visible: false, row: {} },
55
+    }
56
+  }
57
+
58
+  componentDidUpdate(prevProps) {
59
+    if (this.props.visibleData.visible !== prevProps.visibleData.visible) {
60
+      // eslint-disable-next-line react/no-did-update-set-state
61
+      this.setState({ visibleData: this.props.visibleData }, () => {
62
+        this.showDetails(this.props.visibleData.row)
63
+      })
64
+    }
65
+  }
66
+
67
+  showDetails = row => {
68
+    request({
69
+      ...apis.indexEcharts.userBehavior.profile,
70
+      params: { event: row.event, personId: row.personId },
71
+    }).then(data => {
72
+        this.setState({ eventList: data })
73
+    })
74
+  }
75
+
76
+  handleOk = e => {
77
+    this.props.onSuccess()
78
+  };
79
+
80
+  handleCancel = e => {
81
+    this.props.onSuccess()
82
+  };
83
+
84
+  render() {
85
+    return (
86
+      <>
87
+        <Modal
88
+          title="访问详情"
89
+          visible={this.state.visibleData.visible}
90
+          onOk={() => this.handleOk()}
91
+          onCancel={() => this.handleCancel()}
92
+          footer={null}
93
+        >
94
+         <Table rowKey="UserBehavior" dataSource={this.state.eventList} columns={eventcolumns} pagination={false} rowKey="eventall" scroll={{ y: 400 }} />
95
+        </Modal>
96
+      </>
97
+    )
98
+  }
99
+}
100
+
101
+
102
+const formatDate = (start, end) => {
103
+  const startDate = `${moment(start).format('YYYY-MM-DDT00:00:00.000')}Z`
104
+  const endDate = `${moment(end).format('YYYY-MM-DDT23:59:59.999')}Z`
105
+  return { startDate, endDate }
106
+}
107
+const UserBehavior = props => {
108
+  const [data, setData] = useState({ records: [] })
109
+  const [visibleData, setVisibleData] = useState({ visible: false, row: {} })
110
+  const [buildingId, setBuildingId] = useState('')
111
+
112
+  // 柱图
113
+  useEffect(() => {
114
+    const date = formatDate(props.startDate, props.endDate)
115
+    getUserBehaviorSummary({
116
+      ...date,
117
+      activity: props.activity,
118
+      event: props.event,
119
+      eventType: props.eventType,
120
+      buildingId: props.buildingId,
121
+    })
122
+    // getUserBehaviorProfile(formatDate(props.startDate, props.endDate))
123
+  }, [props.startDate, props.endDate, props.activity, props.event, props.eventType, props.buildingId])
124
+
125
+  const [recordList, setList] = useState([])
126
+  function getUserBehaviorSummary(params) {
127
+    request({
128
+      ...apis.indexEcharts.userBehavior.summary,
129
+      params,
130
+    }).then(data => {
131
+      setData(data || {})
132
+      setList((data.data.records || []).filter(e => e.activity !== '客户'))
133
+    })
134
+  }
135
+
136
+
137
+  const seriesMaker = (data.selectUserBehavior || []).filter(e => e.activity !== '客户' && e.activity !== '首页').reduce((series, item) => {
138
+    let { date, activityCount, activity } = item
139
+    date = moment(date).format('YYYY-MM-DD')
140
+    if (!activityCount) activityCount = 0
141
+
142
+    // 使用对象, 可以去重
143
+    series[`${activity}`] = (series[`${activity}`] || []).concat([[date, activityCount]])
144
+
145
+    return series;
146
+  }, {})
147
+
148
+
149
+  const dataZoom = props.dataZoom ? [
150
+    {
151
+      type: 'inside',
152
+      start: 0,
153
+      end: 100,
154
+    },
155
+    {
156
+      type: 'slider',
157
+      start: 0,
158
+      end: 100,
159
+    },
160
+  ] : undefined
161
+
162
+
163
+  const options = {
164
+    title: {},
165
+    icon: 'rect',
166
+    legend: {
167
+      show: true,
168
+      zlevel: 10,
169
+      itemGap: 100,
170
+    },
171
+    color: ['#F12B3E', '#FE929C', '#647CE1', '#A2B9FF', '#FF844F', '#FFBB9D'],
172
+    tooltip: {
173
+      trigger: 'axis',
174
+    },
175
+    xAxis: { type: 'category' },
176
+    yAxis: {},
177
+    dataZoom,
178
+    series: Object.keys(seriesMaker).map(x => ({
179
+        type: 'line',
180
+        smooth: true,
181
+        name: x,
182
+        data: seriesMaker[x],
183
+      })),
184
+  }
185
+  function handleBuildingChange(e) {
186
+    const date = formatDate(props.startDate, props.endDate)
187
+    getUserBehaviorSummary({
188
+      ...date,
189
+      activity: props.activity,
190
+      event: props.event,
191
+      eventType: props.eventType,
192
+      buildingId: e,
193
+    })
194
+    setBuildingId(e)
195
+  }
196
+
197
+  function showDetails(row) {
198
+    setVisibleData({ visible: true, row })
199
+  }
200
+
201
+  function onSuccess() {
202
+    setVisibleData({ visible: false, row: {} })
203
+  }
204
+
205
+
206
+  const style = {
207
+    width: '100%',
208
+    height: '400px',
209
+
210
+  }
211
+
212
+  const columns = [
213
+    {
214
+      title: '访问事件',
215
+      dataIndex: 'eventName',
216
+      key: 'eventName',
217
+      align: 'center',
218
+      width: '16%',
219
+
220
+    },
221
+    {
222
+      title: '访问用户',
223
+      dataIndex: 'userName',
224
+      key: 'userName',
225
+      align: 'center',
226
+      width: '15%',
227
+
228
+    },
229
+    {
230
+      title: '访问次数',
231
+      dataIndex: 'accessCount',
232
+      key: 'accessCount',
233
+      align: 'center',
234
+      width: '17%',
235
+
236
+      render: (x, row) => (
237
+        <>
238
+          <span style={{ color: '#EF273A', cursor: 'pointer' }} onClick={() => showDetails(row)}> {row.accessCount}</span>
239
+        </>
240
+      ),
241
+    },
242
+    {
243
+      title: '首次访问时间',
244
+      dataIndex: 'visitTime',
245
+      key: 'visitTime',
246
+      align: 'center',
247
+      width: '18%',
248
+      render: (x, row) => (
249
+        <>
250
+          <span>{ row.visitTime && moment(row.visitTime).format('YYYY-MM-DD hh:mm:ss') }</span>
251
+        </>
252
+      ),
253
+    },
254
+    {
255
+      title: '离开时间',
256
+      dataIndex: 'leaveTime',
257
+      key: 'leaveTime',
258
+      width: '18%',
259
+      align: 'center',
260
+      render: (x, row) => (
261
+        <>
262
+          <span>{ row.leaveTime && moment(row.leaveTime).format('YYYY-MM-DD hh:mm:ss') }</span>
263
+        </>
264
+      ),
265
+    },
266
+  ]
267
+
268
+
269
+  return (
270
+    <>
271
+      <div>
272
+        <p onClick={() => router.push('/statistical/userBehavior')} style={{cursor: 'pointer'}}>
273
+          <span style={{ borderBottom: '1px solid #f02d40', color: '#333', fontSize: '0.12rem', fontWeight: '600' }}>用户行为</span>
274
+          {!props.BuildSelectHide && <span style={{ fontSize: '0.09rem', color: '#888', marginLeft: '0.06rem' }}>最近七天</span>}
275
+        </p>
276
+        <div style={{ float: 'right', marginTop: '-40px', marginBottom: '20px' }}>
277
+          {!props.BuildSelectHide && <BuildSelect slot="action" onChange={(e => handleBuildingChange(e))} value={buildingId}></BuildSelect>}
278
+        </div>
279
+        <EChart options={options} style={style} />
280
+        {props.tableShow &&
281
+          <Table rowKey="UserBehaviorTwo" dataSource={recordList} columns={columns} pagination={false} rowKey="userbehavior" scroll={{ y: 500 }} />
282
+        }
283
+      </div>
284
+      <EventcoModal visibleData={visibleData} onSuccess={() => onSuccess()} />
285
+    </>
286
+  )
287
+}
288
+
289
+export default UserBehavior

+ 291
- 0
estateagents-admin-manager/src/pages/indexEcharts/components/UserBehaviorIndex.jsx 파일 보기

@@ -0,0 +1,291 @@
1
+import React, { Component, useState, useEffect } from 'react';
2
+import EChart from '../../../components/EchartsTest/EChart';
3
+import request from '../../../utils/request';
4
+import apis from '../../../services/apis';
5
+import moment from 'moment';
6
+import router from 'umi/router';
7
+import 'echarts/lib/component/dataZoom'
8
+import { Table, Select, Row, Col, Menu, Dropdown, Button, Icon, message, Modal } from 'antd';
9
+import BuildSelect from '../../../components/SelectButton/BuildSelect'
10
+
11
+const { Option } = Select;
12
+
13
+
14
+const eventcolumns = [
15
+  {
16
+    title: '编号',
17
+    dataIndex: 'recordId',
18
+    key: 'recordId',
19
+    align: 'center',
20
+    width: '16%',
21
+  },
22
+  {
23
+    title: '访问时间',
24
+    dataIndex: 'visitTime',
25
+    key: 'visitTime',
26
+    align: 'center',
27
+    width: '18%',
28
+    render: (x, row) => (
29
+      <>
30
+        <span>{moment(row.visitTime).format('YYYY-MM-DD hh:mm:ss')}</span>
31
+      </>
32
+    ),
33
+  },
34
+  {
35
+    title: '离开时间',
36
+    dataIndex: 'leaveTime',
37
+    key: 'leaveTime',
38
+    align: 'center',
39
+    width: '18%',
40
+    render: (x, row) => (
41
+      <>
42
+        <span>{row.leaveTime && moment(row.leaveTime).format('YYYY-MM-DD hh:mm:ss')}</span>
43
+      </>
44
+    ),
45
+  },
46
+]
47
+
48
+
49
+class EventcoModal extends React.Component {
50
+  constructor(props) {
51
+    super(props)
52
+    this.state = {
53
+      eventList: [],
54
+      visibleData: { visible: false, row: {} },
55
+    }
56
+  }
57
+
58
+  componentDidUpdate(prevProps) {
59
+    if (this.props.visibleData.visible !== prevProps.visibleData.visible) {
60
+      // eslint-disable-next-line react/no-did-update-set-state
61
+      this.setState({ visibleData: this.props.visibleData }, () => {
62
+        this.showDetails(this.props.visibleData.row)
63
+      })
64
+    }
65
+  }
66
+
67
+  showDetails = row => {
68
+    request({
69
+      ...apis.indexEcharts.userBehavior.profile,
70
+      params: { event: row.event, personId: row.personId },
71
+    }).then(data => {
72
+      this.setState({ eventList: data })
73
+    })
74
+  }
75
+
76
+  handleOk = e => {
77
+    this.props.onSuccess()
78
+  };
79
+
80
+  handleCancel = e => {
81
+    this.props.onSuccess()
82
+  };
83
+
84
+  render() {
85
+    return (
86
+      <>
87
+        <Modal
88
+          title="访问详情"
89
+          visible={this.state.visibleData.visible}
90
+          onOk={() => this.handleOk()}
91
+          onCancel={() => this.handleCancel()}
92
+          footer={null}
93
+        >
94
+          <Table rowKey="UserBehavior" dataSource={this.state.eventList} columns={eventcolumns} pagination={false} rowKey="eventall" scroll={{ y: 400 }} />
95
+        </Modal>
96
+      </>
97
+    )
98
+  }
99
+}
100
+
101
+
102
+const formatDate = (start, end) => {
103
+  const startDate = `${moment(start).format('YYYY-MM-DDT00:00:00.000')}Z`
104
+  const endDate = `${moment(end).format('YYYY-MM-DDT23:59:59.999')}Z`
105
+  return { startDate, endDate }
106
+}
107
+const UserBehaviorIndex = props => {
108
+  const [data, setData] = useState({ records: [] })
109
+  const [visibleData, setVisibleData] = useState({ visible: false, row: {} })
110
+  const [buildingId, setBuildingId] = useState('')
111
+
112
+  // 柱图
113
+  useEffect(() => {
114
+    const date = formatDate(props.startDate, props.endDate)
115
+    getUserBehaviorSummary({
116
+      ...date,
117
+      activity: props.activity,
118
+      event: props.event,
119
+      eventType: props.eventType,
120
+      buildingId: props.buildingId,
121
+    })
122
+    // getUserBehaviorProfile(formatDate(props.startDate, props.endDate))
123
+  }, [props.startDate, props.endDate, props.activity, props.event, props.eventType, props.buildingId])
124
+
125
+  const [recordList, setList] = useState([])
126
+  function getUserBehaviorSummary(params) {
127
+    request({
128
+      ...apis.indexEcharts.userBehavior.tsUserBehavior,
129
+      params,
130
+    }).then(data => {
131
+      setData(data || {})
132
+      // setList((data.data.records || []).filter(e => e.activity !== '客户'))
133
+    })
134
+  }
135
+
136
+
137
+  const seriesMaker = (data.selectUserBehavior || []).filter(e => e.activity !== '客户' && e.activity !== '首页').reduce((series, item) => {
138
+    let { date, activityCount, activity } = item
139
+    date = moment(date).format('YYYY-MM-DD')
140
+    if (!activityCount) activityCount = 0
141
+
142
+    // 使用对象, 可以去重
143
+    series[`${activity}`] = (series[`${activity}`] || []).concat([[date, activityCount]])
144
+
145
+    return series;
146
+  }, {})
147
+
148
+
149
+  const dataZoom = props.dataZoom ? [
150
+    {
151
+      type: 'inside',
152
+      start: 0,
153
+      end: 100,
154
+    },
155
+    {
156
+      type: 'slider',
157
+      start: 0,
158
+      end: 100,
159
+    },
160
+  ] : undefined
161
+
162
+
163
+  const options = {
164
+    title: {},
165
+    icon: 'rect',
166
+    legend: {
167
+      show: true,
168
+      zlevel: 10,
169
+      itemGap: 100,
170
+    },
171
+    color: ['#F12B3E', '#FE929C', '#647CE1', '#A2B9FF', '#FF844F', '#FFBB9D'],
172
+    tooltip: {
173
+      trigger: 'axis',
174
+    },
175
+    xAxis: { type: 'category' },
176
+    yAxis: {},
177
+    dataZoom,
178
+    series: Object.keys(seriesMaker).map(x => ({
179
+      type: 'line',
180
+      smooth: true,
181
+      name: x,
182
+      data: seriesMaker[x],
183
+    })),
184
+  }
185
+  function handleBuildingChange(e) {
186
+    const date = formatDate(props.startDate, props.endDate)
187
+    getUserBehaviorSummary({
188
+      ...date,
189
+      activity: props.activity,
190
+      event: props.event,
191
+      eventType: props.eventType,
192
+      buildingId: e,
193
+    })
194
+    setBuildingId(e)
195
+  }
196
+
197
+  function showDetails(row) {
198
+    setVisibleData({ visible: true, row })
199
+  }
200
+
201
+  function onSuccess() {
202
+    setVisibleData({ visible: false, row: {} })
203
+  }
204
+
205
+
206
+  const style = {
207
+    width: '100%',
208
+    height: '400px',
209
+
210
+  }
211
+
212
+  const columns = [
213
+    {
214
+      title: '访问事件',
215
+      dataIndex: 'eventName',
216
+      key: 'eventName',
217
+      align: 'center',
218
+      width: '16%',
219
+
220
+    },
221
+    {
222
+      title: '访问用户',
223
+      dataIndex: 'userName',
224
+      key: 'userName',
225
+      align: 'center',
226
+      width: '15%',
227
+
228
+    },
229
+    {
230
+      title: '访问次数',
231
+      dataIndex: 'accessCount',
232
+      key: 'accessCount',
233
+      align: 'center',
234
+      width: '17%',
235
+
236
+      render: (x, row) => (
237
+        <>
238
+          <span style={{ color: '#EF273A', cursor: 'pointer' }} onClick={() => showDetails(row)}> {row.accessCount}</span>
239
+        </>
240
+      ),
241
+    },
242
+    {
243
+      title: '首次访问时间',
244
+      dataIndex: 'visitTime',
245
+      key: 'visitTime',
246
+      align: 'center',
247
+      width: '18%',
248
+      render: (x, row) => (
249
+        <>
250
+          <span>{row.visitTime && moment(row.visitTime).format('YYYY-MM-DD hh:mm:ss')}</span>
251
+        </>
252
+      ),
253
+    },
254
+    {
255
+      title: '离开时间',
256
+      dataIndex: 'leaveTime',
257
+      key: 'leaveTime',
258
+      width: '18%',
259
+      align: 'center',
260
+      render: (x, row) => (
261
+        <>
262
+          <span>{row.leaveTime && moment(row.leaveTime).format('YYYY-MM-DD hh:mm:ss')}</span>
263
+        </>
264
+      ),
265
+    },
266
+  ]
267
+
268
+
269
+  return (
270
+    <>
271
+      <div>
272
+        {/* <p onClick={() => router.push('/statistical/userBehavior')} style={{cursor: 'pointer'}}> */}
273
+        <div style={{marginBottom:'40px'}}>
274
+          <span style={{ borderBottom: '1px solid #f02d40', color: '#333', fontSize: '0.12rem', fontWeight: '600' }}>用户行为</span>
275
+          {!props.BuildSelectHide && <span style={{ fontSize: '0.09rem', color: '#888', marginLeft: '0.06rem' }}>最近七天</span>}
276
+          {/* </p> */}
277
+          <div style={{ float: 'right' }}>
278
+            {!props.BuildSelectHide && <BuildSelect slot="action" onChange={(e => handleBuildingChange(e))} value={buildingId}></BuildSelect>}
279
+          </div>
280
+        </div>
281
+        <EChart options={options} style={style} />
282
+        {false &&
283
+          <Table rowKey="UserBehaviorTwo" dataSource={recordList} columns={columns} pagination={false} rowKey="userbehavior" scroll={{ y: 500 }} />
284
+        }
285
+      </div>
286
+      <EventcoModal visibleData={visibleData} onSuccess={() => onSuccess()} />
287
+    </>
288
+  )
289
+}
290
+
291
+export default UserBehaviorIndex

+ 139
- 0
estateagents-admin-manager/src/pages/indexEcharts/components/UserConversion.jsx 파일 보기

@@ -0,0 +1,139 @@
1
+import React, { Component, useState, useEffect } from 'react';
2
+import echarts from 'echarts/lib/echarts';
3
+import EChart from '../../../components/EchartsTest/EChart';
4
+import request from '../../../utils/request';
5
+import apis from '../../../services/apis';
6
+import moment from 'moment';
7
+import router from 'umi/router';
8
+import { Table, Select, Row, Col, Menu, Dropdown, Button, Icon, message } from 'antd';
9
+
10
+import styles from '../styles.less'
11
+
12
+
13
+const UserSource = props => {
14
+
15
+  const [theCurrent, setTheCurrent] = useState({ records: [] })
16
+  const [conversionRate, setConversionRate] = useState(0)
17
+  useEffect(() => {
18
+    UserConversionRate({ conversion: 'authorization_phone' })
19
+  }, [])
20
+
21
+  function UserConversionRate(params) {
22
+
23
+    request({
24
+      ...apis.indexEcharts.userConversion,
25
+      params,
26
+    }).then(data => {
27
+      console.log(data.data_count.registeredCount / data.data_count.pvNum, '1241234')
28
+      setDataset(data, params.conversion)
29
+    })
30
+  }
31
+
32
+  function setDataset(data, theStatis) {
33
+    const { pvNum, ...other } = data.data_count
34
+
35
+    // 获取第一个值
36
+    let num = 0
37
+    for (const v of Object.keys(other)) {
38
+      num = other[v]
39
+      break
40
+    }
41
+
42
+    if (pvNum < num) {
43
+      setTheCurrent([
44
+        { name: getStatisName(theStatis), value: '0' },
45
+        { name: '其余', value:  '0' },
46
+      ])
47
+    } else {
48
+
49
+      setConversionRate(num / pvNum)
50
+      setTheCurrent([
51
+        { name: getStatisName(theStatis), value: num },
52
+        { name: '其余', value: pvNum - num },
53
+      ])
54
+    }
55
+  }
56
+
57
+  function getStatisName(theStatis) {
58
+    const statisTypes = [
59
+      { label: '授权手机', value: 'authorization_phone' },
60
+      { label: '项目收藏', value: 'building_save' },
61
+      { label: '项目转发', value: 'building_share' },
62
+      { label: '活动收藏', value: 'activity_save' },
63
+      { label: '活动转发', value: 'activity_share' },
64
+      { label: '资讯收藏', value: 'news_save' },
65
+      { label: '资讯转发', value: 'news_share' },
66
+      { label: '活动报名', value: 'activity_sign' },
67
+
68
+    ]
69
+    return statisTypes.filter(x => x.value === theStatis)[0].label
70
+  }
71
+
72
+  const options = {
73
+    legend: {},
74
+    color: ['#FF7E48', '#dcdcdc'],
75
+    tooltip: {},
76
+    series: {
77
+      type: 'pie',
78
+      name: '转化率',
79
+      radius: ['34%', '52%'],
80
+      avoidLabelOverlap: false,
81
+      label: {
82
+        formatter: '{b} {@value}',
83
+        emphasis: {
84
+          show: true,
85
+          formatter: '{d}%',
86
+          textStyle: {
87
+            fontSize: '22',
88
+            fontWeight: 'bold'
89
+          }
90
+        }
91
+      },
92
+      labelLine: {
93
+        normal: {
94
+          show: false
95
+        }
96
+      },
97
+
98
+      data: theCurrent,
99
+    },
100
+  }
101
+
102
+  function onChange(e) {
103
+    UserConversionRate({ conversion: e })
104
+  }
105
+  const piestyles = {
106
+    width: '100%',
107
+    height: '400px',
108
+  }
109
+
110
+  return (
111
+    <>
112
+      <div>
113
+        <p style={{ fontSize: '0.12rem', fontWeight: '600' }}>转化率</p>
114
+
115
+        <Select
116
+          style={{ width: 200 }}
117
+          placeholder="授权手机"
118
+          onChange={onChange}
119
+        >
120
+          <Select.Option value="authorization_phone">授权手机</Select.Option>
121
+          <Select.Option value="building_save">项目收藏</Select.Option>
122
+          <Select.Option value="building_share">项目转发</Select.Option>
123
+          <Select.Option value="activity_save">活动收藏</Select.Option>
124
+          <Select.Option value="activity_share">活动转发</Select.Option>
125
+          <Select.Option value="news_save">资讯收藏</Select.Option>
126
+          <Select.Option value="news_share">资讯转发</Select.Option>
127
+          <Select.Option value="activity_sign">活动报名</Select.Option>
128
+        </Select>
129
+        <EChart options={options} style={piestyles} />
130
+
131
+
132
+      </div>
133
+
134
+
135
+    </>
136
+  )
137
+}
138
+
139
+export default UserSource

+ 92
- 0
estateagents-admin-manager/src/pages/indexEcharts/components/UserSex.jsx 파일 보기

@@ -0,0 +1,92 @@
1
+import React, { Component, useState, useEffect } from 'react';
2
+import echarts from 'echarts/lib/echarts';
3
+import EChart from '../../../components/EchartsTest/EChart';
4
+import request from '../../../utils/request';
5
+import apis from '../../../services/apis';
6
+import moment from 'moment';
7
+import router from 'umi/router';
8
+import { Table, Select, Row, Col, Menu, Dropdown, Button, Icon, message } from 'antd';
9
+
10
+import styles from '../styles.less'
11
+
12
+const formatDate = (start, end) => {
13
+  const startDate = moment(start).format('YYYY-MM-DDT00:00:00.000') + 'Z'
14
+  const endDate = moment(end).format('YYYY-MM-DDT23:59:59.999') + 'Z'
15
+  return { startDate, endDate }
16
+}
17
+
18
+const UserSource = (props) => {
19
+
20
+  const [data, setData] = useState({ records: [] })
21
+  const endDate = new Date()
22
+  const startDate = moment().subtract(7, 'day').toDate()
23
+
24
+  useEffect(() => {
25
+    UserSex(formatDate(startDate, endDate))
26
+  }, [])
27
+
28
+  function UserSex(params) {
29
+    request({
30
+      ...apis.indexEcharts.userSex,
31
+      params,
32
+    }).then((data) => {
33
+      setData(data)
34
+    })
35
+  }
36
+
37
+  const dataset = (data.selectSexUser) || []
38
+
39
+  const options = {
40
+    title: {
41
+      text: '性别比例'
42
+    },
43
+    legend: {},
44
+    color: ['#FF7E48', '#dcdcdc'],
45
+    tooltip: {
46
+      trigger: 'item',
47
+      formatter: "{b}: ({d}%)"
48
+    },
49
+    series: {
50
+      type: 'pie',
51
+      name: '性别比例',
52
+      center: ['44%', '65%'],
53
+      radius: ['34%', '52%'],
54
+      label: {
55
+        formatter: '{b} {@value}',
56
+      },
57
+      data:
58
+        dataset,
59
+    }
60
+  }
61
+
62
+
63
+  const piestyles = {
64
+    width: '100%',
65
+    height: '400px',
66
+    minWidth: '350px'
67
+
68
+  }
69
+
70
+
71
+  return (
72
+    <>
73
+      <div>
74
+        {/* <h3>性别比例</h3> */}
75
+
76
+
77
+        <EChart options={options} style={piestyles} />
78
+
79
+
80
+
81
+
82
+      </div>
83
+
84
+
85
+
86
+
87
+
88
+    </>
89
+  )
90
+}
91
+
92
+export default UserSource;

+ 125
- 0
estateagents-admin-manager/src/pages/indexEcharts/components/UserSource.jsx 파일 보기

@@ -0,0 +1,125 @@
1
+import React, { Component, useState, useEffect } from 'react';
2
+import echarts from 'echarts/lib/echarts';
3
+import EChart from '../../../components/EchartsTest/EChart';
4
+import request from '../../../utils/request';
5
+import apis from '../../../services/apis';
6
+import moment from 'moment';
7
+import router from 'umi/router';
8
+import { Table, Select, Row, Col, Menu, Dropdown, Button, Icon, message } from 'antd';
9
+
10
+import styles from '../styles.less'
11
+
12
+const formatDate = (start, end) => {
13
+  const startDate = moment(start).format('YYYY-MM-DDT00:00:00.000') + 'Z'
14
+  const endDate = moment(end).format('YYYY-MM-DDT23:59:59.999') + 'Z'
15
+  return { startDate, endDate }
16
+}
17
+
18
+const UserSource = (props) => {
19
+  const [xData, setxData] = useState([])
20
+  const [fromData, setFromData] = useState([])
21
+  const [registerData, setRegisterData] = useState([])
22
+  //柱图
23
+  useEffect(() => {
24
+    userResource(formatDate(props.startDate, props.endDate))
25
+  }, [props.startDate, props.endDate])
26
+
27
+  function userResource(params) {
28
+    request({
29
+      ...apis.indexEcharts.selectPersonFrom,
30
+      params,
31
+    }).then((data) => {
32
+      console.log(data,"222222")
33
+      setxData(data.tdWxDicts.map(x =>  x.sceneAlias))
34
+      setFromData(data.tdWxDicts.map(x => x.fromData))
35
+      setRegisterData(data.tdWxDicts.map(x => x.registerSum))
36
+      props.onSuccess(data)
37
+    })
38
+  }
39
+
40
+  const subtitle = '最近7天';
41
+  const baroptions = {
42
+    title: { },
43
+    xAxis: { 
44
+              type: 'category',
45
+              data: xData,
46
+              axisLabel: {rotate: 45}
47
+            },
48
+    legend: {
49
+      left: '20%',
50
+      data: ['所有用户', '注册用户']
51
+    },
52
+
53
+    tooltip: {},
54
+
55
+    yAxis: {},
56
+    series: [
57
+      {
58
+        type: 'bar', name: '所有用户', datasetIndex: 0,
59
+        barWidth: 20,
60
+        data: fromData,
61
+        itemStyle: {
62
+          normal: {
63
+            barBorderRadius: [20, 20, 0, 0],
64
+            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
65
+              offset: 0,
66
+              color: '#FFC4A8'
67
+            }, {
68
+              offset: 1,
69
+              color: '#FF7E49'
70
+            }]),
71
+            shadowColor: 'rgba(0, 0, 0, 0.4)',
72
+
73
+          }
74
+        }
75
+      },
76
+      {
77
+        type: 'bar',
78
+        name: '注册用户',
79
+        barWidth: 20,
80
+        data: registerData,
81
+        itemStyle: {
82
+          normal: {
83
+            barBorderRadius: [20, 20, 0, 0],
84
+            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
85
+              offset: 0,
86
+              color: '#FE939D'
87
+            }, {
88
+              offset: 1,
89
+              color: '#F0293C'
90
+            }]),
91
+            shadowColor: 'rgba(0, 0, 0, 0.4)',
92
+
93
+          }
94
+        }
95
+
96
+      },
97
+    ],
98
+    // dataset: {
99
+    //   id: 'bar',
100
+    //   dimensions: ['fromName', 'userCount', 'registered'],
101
+    //   source: source,
102
+    // },
103
+  }
104
+
105
+
106
+  const barstyle = {
107
+    width: '100%',
108
+    height: '480px',
109
+    minWidth: '400px'
110
+  }
111
+
112
+  return (
113
+    <>
114
+      <div>
115
+      <p onClick={()=>router.push('/statistical/userSource')}><span style={{borderBottom:'1px solid #f02d40',cursor: 'pointer',color:'#333',fontSize:'0.12rem',fontWeight:'600'}}>用户来源</span> {!props.BuildSelectHide && <span style={{ fontSize: '0.09rem', color: '#888', marginLeft: '0.06rem' }}>最近七天</span>}</p>
116
+
117
+        <EChart options={baroptions} style={barstyle} />
118
+
119
+      </div>
120
+
121
+    </>
122
+  )
123
+}
124
+
125
+export default UserSource;

+ 139
- 0
estateagents-admin-manager/src/pages/indexEcharts/components/UserSourceDetail.jsx 파일 보기

@@ -0,0 +1,139 @@
1
+import React, { Component, useState, useEffect } from 'react';
2
+import echarts from 'echarts/lib/echarts';
3
+import EChart from '../../../components/EchartsTest/EChart';
4
+import request from '../../../utils/request';
5
+import apis from '../../../services/apis';
6
+import moment from 'moment';
7
+import router from 'umi/router';
8
+import { Table, Select, Row, Col, Menu, Dropdown, Button, Icon, message } from 'antd';
9
+
10
+import styles from '../styles.less'
11
+
12
+const formatDate = (start, end) => {
13
+  const startDate = moment(start).format('YYYY-MM-DDT00:00:00.000') + 'Z'
14
+  const endDate = moment(end).format('YYYY-MM-DDT23:59:59.999') + 'Z'
15
+  return { startDate, endDate }
16
+}
17
+
18
+const UserSourceDetail = (props) => {
19
+  const [xData, setxData] = useState([])
20
+  const [fromData, setFromData] = useState([])
21
+  const [registerData, setRegisterData] = useState([])
22
+  //柱图
23
+  useEffect(() => {
24
+    userResource(formatDate(props.startDate, props.endDate))
25
+  }, [props.startDate, props.endDate])
26
+
27
+  function userResource(params) {
28
+    request({
29
+      ...apis.indexEcharts.selectPersonFromGroupByDay,
30
+      params,
31
+    }).then((data) => {
32
+      setxData(data.map(x =>  x.createTime))
33
+      setFromData(data.map(x => x.fromNum))
34
+      setRegisterData(data.map(x => x.registeredNum))
35
+      props.onSuccess(data)
36
+    })
37
+  }
38
+
39
+  const subtitle = '最近7天';
40
+  const baroptions = {
41
+    title: {
42
+    },
43
+    tooltip: {
44
+        trigger: 'axis'
45
+    },
46
+    legend: {
47
+        data: ['新用户数', '授权注册']
48
+    },
49
+    toolbox: {
50
+        show: true,
51
+        feature: {
52
+            dataZoom: {
53
+                yAxisIndex: 'none'
54
+            },
55
+            dataView: {readOnly: false},
56
+            magicType: {type: ['line', 'bar']},
57
+            restore: {},
58
+            saveAsImage: {}
59
+        }
60
+    },
61
+    xAxis: {
62
+        type: 'category',
63
+        boundaryGap: false,
64
+        data: xData
65
+    },
66
+    yAxis: {
67
+        type: 'value',
68
+        axisLabel: {
69
+            formatter: '{value} °C'
70
+        }
71
+    },
72
+    series: [
73
+        {
74
+            name: '新用户数',
75
+            type: 'line',
76
+            data: fromData,
77
+            markPoint: {
78
+                data: [
79
+                    {type: 'max', name: '最大值'},
80
+                    {type: 'min', name: '最小值'}
81
+                ]
82
+            },
83
+            markLine: {
84
+                data: [
85
+                    {type: 'average', name: '平均值'}
86
+                ]
87
+            }
88
+        },
89
+        {
90
+            name: '授权注册',
91
+            type: 'line',
92
+            data: registerData,
93
+            markPoint: {
94
+                data: [
95
+                    {name: '周最低', value: -2, xAxis: 1, yAxis: -1.5}
96
+                ]
97
+            },
98
+            markLine: {
99
+                data: [
100
+                    {type: 'average', name: '平均值'},
101
+                    [{
102
+                        symbol: 'none',
103
+                        x: '90%',
104
+                        yAxis: 'max'
105
+                    }, {
106
+                        symbol: 'circle',
107
+                        label: {
108
+                            position: 'start',
109
+                            formatter: '最大值'
110
+                        },
111
+                        type: 'max',
112
+                        name: '最高点'
113
+                    }]
114
+                ]
115
+            }
116
+        }
117
+    ]
118
+}
119
+
120
+  const barstyle = {
121
+    width: '100%',
122
+    height: '480px',
123
+    minWidth: '400px'
124
+  }
125
+
126
+  return (
127
+    <>
128
+      <div>
129
+      <p onClick={()=>router.push('/statistical/userSource')}><span style={{borderBottom:'1px solid #f02d40',cursor: 'pointer',color:'#333',fontSize:'0.12rem',fontWeight:'600'}}>用户来源</span> {!props.BuildSelectHide && <span style={{ fontSize: '0.09rem', color: '#888', marginLeft: '0.06rem' }}>最近七天</span>}</p>
130
+
131
+        <EChart options={baroptions} style={barstyle} />
132
+
133
+      </div>
134
+
135
+    </>
136
+  )
137
+}
138
+
139
+export default UserSourceDetail;

+ 104
- 0
estateagents-admin-manager/src/pages/indexEcharts/components/UserSourcepie.jsx 파일 보기

@@ -0,0 +1,104 @@
1
+import React, { Component, useState, useEffect } from 'react';
2
+import echarts from 'echarts/lib/echarts';
3
+import EChart from '../../../components/EchartsTest/EChart';
4
+import request from '../../../utils/request';
5
+import apis from '../../../services/apis';
6
+import moment from 'moment';
7
+import router from 'umi/router';
8
+import { Table, Select, Row, Col, Menu, Dropdown, Button, Icon, message } from 'antd';
9
+
10
+import styles from '../styles.less'
11
+const formatDate = (start, end) => {
12
+  const startDate = moment(start).format('YYYY-MM-DDT00:00:00.000') + 'Z'
13
+  const endDate = moment(end).format('YYYY-MM-DDT23:59:59.999') + 'Z'
14
+  return { startDate, endDate }
15
+}
16
+const UserSource = (props) => {
17
+  const [data, setData] = useState({ records: [] })
18
+
19
+
20
+  useEffect(() => {
21
+    userResource(formatDate(props.startDate, props.endDate))
22
+  }, [props.startDate, props.endDate])
23
+
24
+  function userResource(params) {
25
+    request({
26
+      ...apis.indexEcharts.userResource,
27
+      params,
28
+    }).then((data) => {
29
+      setData(data)
30
+    })
31
+  }
32
+
33
+  function toEdit() {
34
+    router.push({
35
+      pathname: '/statistical/userSource',
36
+    });
37
+  }
38
+
39
+  const dataset = data || {};
40
+
41
+
42
+  const { person_estate_agent = 0, person_null = 0, person_realty_consultant = 0 } = dataset.pie || {};
43
+  const pieoptions = {
44
+    color: ['#6B82E6', '#F02D40', '#FF834E'],
45
+    legend: {
46
+      orient: 'vertical',
47
+      x: 'left',
48
+      data: ['来源置业', '来源客户', '其他'],
49
+    },
50
+    tooltip: {
51
+      // trigger: 'item',
52
+      // formatter: "{a} <br/>{b} : {c} ({d}%)"
53
+    },
54
+    series: [
55
+      {
56
+        name: '用户来源',
57
+        type: 'pie',
58
+        center: ['50%', '65%'],
59
+        radius: ['25%', '40%'],
60
+        label: {
61
+          formatter: '{b} {@value}',
62
+          emphasis: {
63
+            show: true,
64
+            formatter: '{d}%',
65
+            textStyle: {
66
+              fontSize: '22',
67
+              fontWeight: 'bold'
68
+            }
69
+          },
70
+        },
71
+      },
72
+
73
+    ],
74
+
75
+    dataset: {
76
+      id: 'pie',
77
+      source: [
78
+        { '用户来源': '来源置业', value: person_realty_consultant, },
79
+        { '用户来源': '来源客户', value: person_estate_agent },
80
+        { '用户来源': '其他', value: person_null },
81
+      ]
82
+    },
83
+  }
84
+
85
+
86
+  const piestyles = {
87
+    width: '100%',
88
+    height: '400px',
89
+    minWidth: '350px',
90
+  }
91
+
92
+  return (
93
+    <>
94
+      <div>
95
+
96
+        <EChart options={pieoptions} style={piestyles} />
97
+
98
+      </div>
99
+
100
+    </>
101
+  )
102
+}
103
+
104
+export default UserSource;

+ 92
- 0
estateagents-admin-manager/src/pages/indexEcharts/index.jsx 파일 보기

@@ -0,0 +1,92 @@
1
+
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';
4
+import router from 'umi/router';
5
+import request from '../../utils/request'
6
+import apis from '../../services/apis';
7
+import UserSource from './components/UserSource.jsx';
8
+import UserSourcepie from './components/UserSourcepie.jsx';
9
+import UserBehaviorIndex from './components/UserBehaviorIndex.jsx';
10
+import UserActive from './components/UserActive';
11
+import UserSex from './components/UserSex';
12
+import NewUsers from './components/NewUsers'
13
+import UserConversion from './components/UserConversion'
14
+import IntentionalCustomers from './components/IntentionalCustomers'
15
+import styles from './styles.less'
16
+import moment from 'moment';
17
+import CityNums from '../charts/CityNums';
18
+const indexEcharts = props => {
19
+
20
+  // eslint-disable-next-line react-hooks/rules-of-hooks
21
+  const [checkData, setCheckData] = useState([])
22
+
23
+  // eslint-disable-next-line react-hooks/rules-of-hooks
24
+  useEffect(() => {
25
+    setCheckData(props.checkData)
26
+  }, [props.checkData]);
27
+
28
+  const endDate = new Date()
29
+
30
+  const startDate = moment().subtract(7, 'day').toDate()
31
+
32
+  function onTabledatas (e) {
33
+
34
+  }
35
+  
36
+  return (
37
+
38
+    <>
39
+      <div style={{ display: 'flex', width: '100%' }}>
40
+        {checkData.includes('user_source') &&
41
+          <div className={styles.bar}>
42
+            <UserSource endDate={endDate} startDate={startDate} onSuccess={e => onTabledatas(e)}></UserSource>
43
+          </div>
44
+        }
45
+        {checkData.includes('user_source') &&
46
+          <div className={styles.pie}>
47
+            <UserSourcepie endDate={endDate} startDate={startDate}></UserSourcepie>
48
+          </div>
49
+        }
50
+      </div>
51
+      {checkData.includes('urban_distribution') &&
52
+        <div>
53
+          <CityNums></CityNums>
54
+        </div>
55
+      }
56
+      {checkData.includes('user_behavior') &&
57
+        <div className={styles.behavior}>
58
+          <UserBehaviorIndex tableShow={false} endDate={endDate} startDate={startDate} dataZoom={false}></UserBehaviorIndex>
59
+        </div>
60
+      }
61
+      <div style={{ display: 'flex' }}>
62
+        {checkData.includes('active_users') &&
63
+          <div className={styles.bar}>
64
+            <UserActive ></UserActive>
65
+          </div>
66
+        }
67
+        {checkData.includes('sex_ratio') &&
68
+          <div className={styles.pie}><UserSex></UserSex> </div>
69
+        }
70
+      </div>
71
+      <div style={{ display: 'flex' }}>
72
+        {checkData.includes('number_of_new_users') &&
73
+          <div className={styles.bar}>
74
+            <NewUsers endDate={endDate} startDate={startDate} dataZoom={false}></NewUsers>
75
+          </div>
76
+        }
77
+        {checkData.includes('conversion_rate') &&
78
+          <div className={styles.pie}><UserConversion></UserConversion> </div>
79
+        }
80
+      </div >
81
+
82
+      {checkData.includes('intentional_user') &&
83
+        <div className={styles.customers}>
84
+          <IntentionalCustomers></IntentionalCustomers>
85
+        </div>
86
+      }
87
+    </>
88
+  )
89
+}
90
+
91
+
92
+export default indexEcharts

+ 191
- 0
estateagents-admin-manager/src/pages/indexEcharts/newUsers.jsx 파일 보기

@@ -0,0 +1,191 @@
1
+import React, { Component, useState, useEffect } from 'react';
2
+import { Radio, DatePicker, Form, Input, Button, Icon, Select, message, Table, Divider, Tag, Pagination, Modal, Breadcrumb } from 'antd';
3
+import { Row, Col, Menu, Dropdown } from 'antd';
4
+import NewUsers from './components/NewUsers'
5
+// import XForm, { FieldTypes } from '../../components/XForm';
6
+import moment from 'moment';
7
+import router from 'umi/router';
8
+import EChart from '../../components/EchartsTest/EChart';
9
+import request from '../../utils/request';
10
+import apis from '../../services/apis';
11
+
12
+
13
+// const formatDate = (start, end) => {
14
+//   const startDate = moment(start).format('YYYY-MM-DDT00:00:00.000') + 'Z'
15
+//   const endDate = moment(end).format('YYYY-MM-DDT23:59:59.999') + 'Z'
16
+//   return { startDate, endDate }
17
+// }
18
+
19
+let columns = [
20
+  {
21
+    title: '日期',
22
+    dataIndex: 'createTime',
23
+    key: 'createTime',
24
+  },
25
+]
26
+
27
+let daterange = []
28
+
29
+const header = props => {
30
+
31
+  const [tableData, setTableData] = useState([])
32
+  const [endDate, setEndDate] = useState({})
33
+  const [data, setDate] = useState({})
34
+  const [userType, setUserType] = useState({})
35
+  const [startDate, setStartDate] = useState({})
36
+
37
+
38
+  useEffect(() => {
39
+
40
+    setEndDate(new Date())
41
+    setStartDate(moment().subtract(7, 'day').toDate())
42
+    // setStartDate(moment().subtract(7, 'day').toDate())
43
+    userResource({ startDate: moment().subtract(7, 'day').toDate(), endDate: new Date() })
44
+  }, [])
45
+
46
+  const { RangePicker } = DatePicker;
47
+
48
+  function onChangetime(dates, dateStrings) {
49
+
50
+    daterange[1] = `${moment(dateStrings[1]).format('YYYY-MM-DDT00:00:00.000')}Z`
51
+    daterange[0] = `${moment(dateStrings[0]).format('YYYY-MM-DDT00:00:00.000')}Z`
52
+
53
+  }
54
+
55
+  const handleSubmit = (e, props) => {
56
+
57
+    e.preventDefault();
58
+
59
+  }
60
+
61
+  const getDataOf = (days) => () => {
62
+
63
+
64
+    setEndDate(new Date())
65
+    setStartDate(moment().subtract(days, 'day').toDate())
66
+    userResource({ startDate: moment().subtract(days, 'day').toDate(), endDate: new Date() })
67
+  }
68
+
69
+  function onChange(e) {
70
+
71
+
72
+  }
73
+
74
+  function datalist() {
75
+    setEndDate(daterange[1])
76
+    setStartDate(daterange[0])
77
+    userResource({ startDate, endDate })
78
+
79
+  }
80
+
81
+  function userResource(params) {
82
+    request({
83
+      ...apis.indexEcharts.selectPersonFrom,
84
+      params,
85
+    }).then((data) => {
86
+      setDate(data);
87
+      onTabledatas(data, "all")
88
+    })
89
+  }
90
+
91
+  const onTabledatas = (e, changeType) => {
92
+    e.tdWxDicts.map(x => {
93
+      columns = columns.filter(y => y.key != x.sceneType).concat({
94
+        title: x.sceneAlias,
95
+        dataIndex: x.sceneType,
96
+        key: x.sceneType,
97
+      })
98
+    })
99
+    const data = (e.list || []).reduce((acc, item) => {
100
+      const { sceneType, fromNum, registeredNum, createTime } = item
101
+      const num = changeType === 'registered' ? registeredNum : fromNum
102
+      acc[createTime] = { ...acc[createTime], ...item, [`${sceneType}`]: !num ? 0 : num }
103
+      return acc
104
+    }, {})
105
+
106
+    const dictData = e.tdWxDicts.reduce((acc, item, index) => {
107
+      const { sceneType } = item
108
+      acc[sceneType] = 0
109
+      return acc
110
+    }, {})
111
+
112
+    const tableData = Object.keys(data).map(k => data[k]).reduce((acc, item, index) => {
113
+      acc[index] = { ...dictData, ...item }
114
+      return acc
115
+    }, [])
116
+
117
+    setTableData(tableData)
118
+
119
+  }
120
+
121
+  function handleSelectChange(e) {
122
+    setUserType(e)
123
+    onTabledatas(data, e)
124
+  }
125
+
126
+  function exportUserStats() {
127
+    console.log(startDate, endDate, userType)
128
+    request({
129
+      ...apis.indexEcharts.exportUserStats,
130
+      params: { startDate, endDate, userType },
131
+    }).then((data) => {
132
+      if (!data) {
133
+        return
134
+      }
135
+      const url = window.URL.createObjectURL(new Blob([data]))
136
+      const link = document.createElement('a')
137
+      link.style.display = 'none'
138
+      link.href = url
139
+      link.setAttribute('download', '新增用户.xlsx')
140
+      document.body.append(link)
141
+      link.click()
142
+    })
143
+  }
144
+
145
+  const { Column, ColumnGroup } = Table;
146
+
147
+  return (<>
148
+    <div >
149
+      <Radio.Group onChange={onChange} buttonStyle="solid" defaultValue="a" style={{ marginBottom: '20px' }}>
150
+        {/* <Radio.Button value="c" onClick={getDataOf(0)}>今日</Radio.Button> */}
151
+        <Radio.Button value="a" onClick={getDataOf(7)}>最近7天</Radio.Button>
152
+        <Radio.Button value="b" onClick={getDataOf(30)}>最近1月</Radio.Button>
153
+      </Radio.Group>
154
+      <RangePicker
155
+        style={{ paddingLeft: '30px' }}
156
+        ranges={{
157
+          Today: [moment(), moment()],
158
+          'This Month': [moment().startOf('month'), moment().endOf('month')],
159
+        }}
160
+        // showTime
161
+        // format="YYYY/MM/DD HH:mm:ss"
162
+        onChange={onChangetime}
163
+      />
164
+      <Button type="primary" htmlType="submit" style={{ marginLeft: '30px' }} onClick={datalist}>
165
+        搜索
166
+          </Button>
167
+      <Button onClick={() => router.go(-1)} style={{ float: 'right' }}>返回</Button>
168
+      <div>
169
+        <NewUsers BuildSelectHide={true} endDate={endDate} startDate={startDate} dataZoom={true} ></NewUsers>
170
+        {/* */}
171
+
172
+        <Row>
173
+          <Col span={22}>
174
+            <Select style={{ width: '180px' }} placeholder="所有用户" onChange={(e) => handleSelectChange(e)}>
175
+              <Option value='all'>所有用户</Option>
176
+              <Option value='registered'>注册用户</Option>
177
+            </Select>
178
+          </Col>
179
+          <Col span={2}>
180
+            <Button type="primary" onClick={exportUserStats}>导出</Button>
181
+          </Col>
182
+        </Row>
183
+
184
+        <Table style={{ marginTop: '20px' }} dataSource={tableData} columns={columns} pagination={false} scroll={{ y: 500 }}></Table>
185
+      </div>
186
+    </div>
187
+  </>
188
+  )
189
+}
190
+
191
+export default header

+ 37
- 0
estateagents-admin-manager/src/pages/indexEcharts/styles.less 파일 보기

@@ -0,0 +1,37 @@
1
+.bar {
2
+  width: 70%;
3
+  min-width: 400px;
4
+  min-height: 560px;
5
+  background: rgba(255, 255, 255, 1);
6
+  box-shadow: 0px 0px 16px 2px rgba(0, 0, 0, 0.12);
7
+  border-radius: 12px;
8
+  margin-right: 30px;
9
+}
10
+
11
+.pie {
12
+  width: 30%;
13
+  min-width: 370px;
14
+  background: rgba(255, 255, 255, 1);
15
+  box-shadow: 0px 0px 16px 2px rgba(0, 0, 0, 0.12);
16
+  border-radius: 12px;
17
+
18
+}
19
+
20
+.behavior {
21
+  width: 100%;
22
+  height: 586px;
23
+  background: rgba(255, 255, 255, 1);
24
+  box-shadow: 0px 0px 16px 2px rgba(0, 0, 0, 0.12);
25
+  border-radius: 12px;
26
+  margin-bottom: 40px;
27
+  padding: 40px;
28
+}
29
+
30
+.customers {
31
+  width: 100%;
32
+  height: 718px;
33
+  background: rgba(255, 255, 255, 1);
34
+  box-shadow: 0px 0px 16px 2px rgba(0, 0, 0, 0.12);
35
+  border-radius: 12px 12px 0px 0px;
36
+  padding: 40px;
37
+}

+ 237
- 0
estateagents-admin-manager/src/pages/indexEcharts/userBehavior.jsx 파일 보기

@@ -0,0 +1,237 @@
1
+import React, { Component, useState, useEffect } from 'react';
2
+import { Radio, DatePicker, Form, Input, Button, Icon, Select, message, Table, Row, Col, Menu, Dropdown } from 'antd';
3
+
4
+import moment from 'moment';
5
+import UserBehavior from './components/UserBehavior'
6
+import EChart from '../../components/EchartsTest/EChart';
7
+import request from '../../utils/request';
8
+import apis from '../../services/apis';
9
+import BuildSelect from '../../components/SelectButton/BuildSelect'
10
+import { func } from 'prop-types';
11
+import router from 'umi/router';
12
+
13
+
14
+// const formatDate = (start, end) => {
15
+//   const startDate = moment(start).format('YYYY-MM-DDT00:00:00.000') + 'Z'
16
+//   const endDate = moment(end).format('YYYY-MM-DDT23:59:59.999') + 'Z'
17
+//   return { startDate, endDate }
18
+// }
19
+const { Option } = Select;
20
+
21
+const header = props => {
22
+  // eslint-disable-next-line react-hooks/rules-of-hooks
23
+  const [tableData, setTableData] = useState({ records: [] })
24
+
25
+  // eslint-disable-next-line react-hooks/rules-of-hooks
26
+  const [endDate, setEndDate] = useState({})
27
+  // eslint-disable-next-line react-hooks/rules-of-hooks
28
+  const [startDate, setStartDate] = useState({})
29
+  const daterange = []
30
+
31
+  // eslint-disable-next-line react-hooks/rules-of-hooks
32
+  useEffect(() => {
33
+    window.scrollTo(0, 0)
34
+    setEndDate(new Date())
35
+    setStartDate(moment().subtract(7, 'day').toDate())
36
+    getBizEventType()
37
+    getBizEventList()
38
+    getProperties()
39
+    props.form.setFieldsValue({ radioGroup: 'a' })
40
+  }, [])
41
+
42
+  // eslint-disable-next-line react-hooks/rules-of-hooks
43
+  const [eventypes, setEventTypes] = useState([])
44
+  function getBizEventType(row) {
45
+    request({
46
+      ...apis.indexEcharts.bizEvent.dict,
47
+    }).then(data => {
48
+      const eventType = ['agent', 'main']
49
+      setEventTypes(data.records.filter(item => !eventType.includes(item.typeId)))
50
+    })
51
+  }
52
+  const [eventList, setEventList] = useState([])
53
+  function getBizEventList(row) {
54
+    request({
55
+      ...apis.indexEcharts.bizEvent.list,
56
+    }).then(data => {
57
+      setEventList(data.records)
58
+    })
59
+  }
60
+  const [properties, setProperties] = useState([])
61
+  function getProperties(row) {
62
+    request({
63
+      ...apis.indexEcharts.bizEvent.properties,
64
+    }).then(data => {
65
+      setProperties(data.records)
66
+    })
67
+  }
68
+
69
+  const { RangePicker } = DatePicker;
70
+
71
+
72
+  function handleSubmit(e) {
73
+    e.preventDefault();
74
+    props.form.validateFields((err, values) => {
75
+      if (!err) {
76
+        const { rangePicker } = values
77
+        console.log('Received values of form: ', values.rangePicker);
78
+        setEndDate(rangePicker[1])
79
+        setStartDate(rangePicker[0])
80
+      }
81
+    });
82
+  }
83
+
84
+  const getDataOf = days => () => {
85
+    setEndDate(new Date())
86
+    setStartDate(moment().subtract(days, 'day').toDate())
87
+  }
88
+
89
+
90
+  function redata(e) {
91
+    console.log('行为回调数据:', e)
92
+  }
93
+  const [eventType, setEventType] = useState('')
94
+  function handleChangeType(value) {
95
+    setEventType(value)
96
+  }
97
+  const [event, setEvent] = useState('')
98
+  function handleChangeEvent(value) {
99
+    setEvent(value)
100
+  }
101
+  const [activity, setActivity] = useState('')
102
+  function handleChangeProperty(value) {
103
+    setActivity(value)
104
+  }
105
+
106
+  const [buildingId, setBuildingId] = useState('')
107
+  function handleBuildingChange(value) {
108
+    setBuildingId(value)
109
+  }
110
+
111
+  // 重置
112
+  function resetQuery() {
113
+    props.form.resetFields()
114
+    props.form.setFieldsValue({ radioGroup: 'a' })
115
+  }
116
+
117
+  const columns = [
118
+    {
119
+      title: '访问事件',
120
+      dataIndex: 'personName',
121
+      key: 'personName',
122
+      width: '20%',
123
+    },
124
+    {
125
+      title: '访问用户',
126
+      dataIndex: 'phone',
127
+      key: 'phone',
128
+      width: '20%',
129
+    },
130
+    {
131
+      title: '访问次数',
132
+      dataIndex: 'buildingName',
133
+      key: 'buildingName',
134
+      width: '20%',
135
+    },
136
+    {
137
+      title: '首次访问时间',
138
+      dataIndex: 'intention',
139
+      key: 'intention',
140
+      width: '20%',
141
+    },
142
+    {
143
+      title: '离开时间',
144
+      dataIndex: 'stion',
145
+      key: 'stion',
146
+
147
+    },
148
+  ];
149
+
150
+  const dataSource = []
151
+
152
+  const { getFieldDecorator, getFieldsError, getFieldError, isFieldTouched } = props.form;
153
+  return (
154
+    <>
155
+      <div>
156
+        <div>
157
+          <Form layout="inline" onSubmit={handleSubmit}>
158
+            <Form.Item>
159
+              {getFieldDecorator('radioGroup')(
160
+                <Radio.Group buttonStyle="solid">
161
+                  <Radio.Button value="a" onClick={getDataOf(7)}>最近7天</Radio.Button>
162
+                  <Radio.Button value="b" onClick={getDataOf(30)}>最近1月</Radio.Button>
163
+                </Radio.Group>,
164
+              )}
165
+            </Form.Item>
166
+            <Form.Item>
167
+              {getFieldDecorator('rangePicker')(
168
+                <RangePicker
169
+                  style={{ paddingLeft: '30px', width: '400px' }}
170
+                  ranges={{
171
+                    Today: [moment(), moment()],
172
+                    'This Month': [moment().startOf('month'), moment().endOf('month')],
173
+                  }}
174
+                  // defaultValue={[moment(new Date(new Date().setDate((new Date().getDate() - 6))), 'YYYY-MM-DD HH:MM:SS'), moment(new Date(), 'YYYY-MM-DD HH:MM:SS')]}
175
+                  showTime
176
+                />,
177
+              )}
178
+            </Form.Item>
179
+
180
+            <Button type="primary" htmlType="submit" style={{ marginLeft: '30px', float: 'right' }}>
181
+              搜索
182
+            </Button>
183
+            <Button style={{ marginLeft: '30px', float: 'right' }} onClick={resetQuery}>
184
+              重置
185
+            </Button>
186
+
187
+            <Button style={{ float: 'right' }} onClick={() => router.go(-1)}>返回</Button>
188
+
189
+            <div style={{ display: 'flex', margin: '24px 0' }}>
190
+              <Form.Item>
191
+                {getFieldDecorator('buildingId')(
192
+                  <BuildSelect style={{ width: '14%', minWidth: '160px' }} slot="action" onChange={(e => handleBuildingChange(e))}></BuildSelect>,
193
+                )}
194
+              </Form.Item>
195
+              <Form.Item>
196
+                {getFieldDecorator('handleType')(
197
+                  <Select style={{ width: '14%', minWidth: '160px', marginLeft: '2%' }} placeholder="所有事件组" onChange={handleChangeType}>
198
+                    {eventypes.map(type => (
199
+                      <Option key={type.typeId}>{type.typeName}</Option>
200
+                    ))}
201
+                  </Select>,
202
+                )}
203
+              </Form.Item>
204
+              <Form.Item>
205
+                {getFieldDecorator('handleEvent')(
206
+                  <Select style={{ width: '14%', minWidth: '200px', marginLeft: '2%' }} placeholder="请选择事件" onChange={handleChangeEvent}>
207
+                    {eventList.map(event => (
208
+                      <Option key={event.eventId}>{event.eventName}</Option>
209
+                    ))}
210
+                  </Select>,
211
+                )}
212
+              </Form.Item>
213
+              <Form.Item>
214
+                {getFieldDecorator('handleProperty')(
215
+                  <Select style={{ width: '14%', minWidth: '160px', marginLeft: '2%' }} placeholder="请选择属性" onChange={handleChangeProperty}>
216
+                    {properties.map(property => (
217
+                      <Option key={property.propertyId}>{property.propertyName}</Option>
218
+                    ))}
219
+                  </Select>,
220
+                )}
221
+              </Form.Item>
222
+            </div>
223
+          </Form>
224
+        </div>
225
+
226
+        <div style={{ margin: '24px 0' }}>
227
+          <UserBehavior tableShow BuildSelectHide buildingId={buildingId} endDate={endDate} startDate={startDate} eventType={eventType} activity={activity} event={event} dataZoom onReData={e => redata(e)}></UserBehavior>
228
+        </div>
229
+
230
+        {/* <Table dataSource={dataSource} columns={columns} pagination={false} scroll={{ y: 500 }} /> */}
231
+      </div>
232
+    </>
233
+  )
234
+}
235
+
236
+const WrappedHorizontalLoginForm = Form.create({ name: 'header' })(header);
237
+export default WrappedHorizontalLoginForm

+ 207
- 0
estateagents-admin-manager/src/pages/indexEcharts/userSource.jsx 파일 보기

@@ -0,0 +1,207 @@
1
+import React, { Component, useState, useEffect } from 'react';
2
+import { Form, Icon, Input, Button, DatePicker, Select, Card, Row, Col, Pagination, Alert, Table, Avatar, Radio, Modal, Descriptions } from 'antd';
3
+import UserSource from './components/UserSource.jsx';
4
+import UserSourcepie from './components/UserSourcepie.jsx';
5
+// import XForm, { FieldTypes } from '../../components/XForm';
6
+import moment from 'moment';
7
+import EChart from '../../components/EchartsTest/EChart';
8
+import request from '../../utils/request';
9
+import apis from '../../services/apis';
10
+import router from 'umi/router';
11
+
12
+
13
+const { RangePicker } = DatePicker;
14
+const { Option } = Select
15
+
16
+
17
+// const formatDate = (start, end) => {
18
+//   const startDate = moment(start).format('YYYY-MM-DDT00:00:00.000') + 'Z'
19
+//   const endDate = moment(end).format('YYYY-MM-DDT23:59:59.999') + 'Z'
20
+//   return { startDate, endDate }
21
+// }
22
+
23
+let daterange = []
24
+let tableTitle = ['类型']
25
+
26
+let columns = [
27
+  {
28
+    title: '日期',
29
+    dataIndex: 'createTime',
30
+    key: 'createTime',
31
+  },
32
+  // {
33
+  //   title: '名片分享',
34
+  //   dataIndex: '名片分享',
35
+  //   key: '名片分享',
36
+  // },
37
+  // {
38
+  //   title: '生成海报',
39
+  //   dataIndex: '生成海报',
40
+  //   key: '生成海报',
41
+  // },
42
+  // {
43
+  //   title: '小程序搜索',
44
+  //   dataIndex: '小程序搜索',
45
+  //   key: '小程序搜索',
46
+  // },
47
+  // {
48
+  //   title: '好友分享',
49
+  //   dataIndex: '好友分享',
50
+  //   key: '好友分享',
51
+  // },
52
+]
53
+
54
+// let columns = [
55
+//   {
56
+//     title: '类型',
57
+//     dataIndex: 'value',
58
+//     key: 'value',
59
+//   }
60
+// ]
61
+
62
+class Header extends React.Component {
63
+
64
+  constructor(props) {
65
+    super(props)
66
+    this.state = {
67
+      dataSoures: [],
68
+      tableData: [],
69
+      userType: 'all',
70
+      endDate: {},
71
+      startDate: {}
72
+    }
73
+  }
74
+
75
+  componentDidMount() {
76
+    this.setState({ endDate: new Date(), startDate: moment().subtract(7, 'day').toDate() })
77
+  }
78
+
79
+  formatDate = (start, end) => {
80
+    const tempStartDate = `${moment(start).format('YYYY-MM-DDT00:00:00.000')}Z`
81
+    const tempEndDate = `${moment(end).format('YYYY-MM-DDT23:59:59.999')}Z`
82
+    return { startDate: tempStartDate, endDate: tempEndDate }
83
+  }
84
+
85
+  onChangetime = (_dates, dateStrings) => {
86
+    daterange[1] = dateStrings[1]
87
+    daterange[0] = dateStrings[0]
88
+  }
89
+
90
+  handleSubmit = (e, props) => {
91
+
92
+    e.preventDefault();
93
+
94
+  }
95
+
96
+  getDataOf = (days) => {
97
+    this.setState({ endDate: new Date(), startDate: moment().subtract(days, 'day').toDate() })
98
+  }
99
+
100
+  datalist = () => {
101
+    console.log()
102
+    this.setState({
103
+      endDate: daterange[1] === '' ? new Date() : daterange[1],
104
+      startDate: daterange[0] === '' ? moment().subtract(7, 'day').toDate() : daterange[0],
105
+    })
106
+  }
107
+
108
+  onSuccess = e => {
109
+    this.setState({ dataSoures: e }, () => {
110
+      this.onTabledatas(e)
111
+    })
112
+  }
113
+
114
+  onTabledatas = (e) => {
115
+    console.log('this.state.userType: ', this.state.userType)
116
+    e.tdWxDicts.map(x => {
117
+      columns = columns.filter(y => y.key != x.sceneType).concat({
118
+        title: x.sceneAlias,
119
+        dataIndex: x.sceneType,
120
+        key: x.sceneType,
121
+      })
122
+    })
123
+    const data = (e.list || []).reduce((acc, item) => {
124
+      const { sceneType, fromNum, registeredNum, createTime } = item
125
+      const num = this.state.userType === 'registered' ? registeredNum : fromNum
126
+      acc[createTime] = { ...acc[createTime], ...item, [`${sceneType}`]: !num ? 0 : num }
127
+      return acc
128
+    }, {})
129
+
130
+    const dictData = e.tdWxDicts.reduce((acc, item, index) => {
131
+      const { sceneType } = item
132
+      acc[sceneType] = 0
133
+      return acc
134
+    }, {})
135
+
136
+    const tableData = Object.keys(data).map(k => data[k]).reduce((acc, item, index) => {
137
+      acc[index] = { ...dictData, ...item }
138
+      return acc
139
+    }, [])
140
+
141
+    this.setState({ tableData })
142
+
143
+  }
144
+
145
+  handleSelectChange = (e) => {
146
+    this.setState({ userType: e }, () => {
147
+      this.onTabledatas(this.state.dataSoures)
148
+    })
149
+  }
150
+
151
+
152
+  render() {
153
+    return (
154
+      <>
155
+        <div>
156
+          <Radio.Group buttonStyle="solid" defaultValue="a">
157
+            <Radio.Button value="a" onClick={() => this.getDataOf(7)}>最近7天</Radio.Button>
158
+            <Radio.Button value="b" onClick={() => this.getDataOf(30)}>最近1月</Radio.Button>
159
+          </Radio.Group>
160
+          <RangePicker
161
+            style={{ paddingLeft: '30px' }}
162
+            ranges={{
163
+              Today: [moment(), moment()],
164
+              'This Month': [moment().startOf('month'), moment().endOf('month')],
165
+            }}
166
+            // showTime
167
+            // format="YYYY/MM/DD HH:mm:ss"
168
+            onChange={(_dates, dateStrings) => this.onChangetime(_dates, dateStrings)}
169
+          />
170
+          <Button type="primary" htmlType="submit" style={{ marginLeft: '30px' }} onClick={() => this.datalist()}>
171
+            搜索
172
+        </Button>
173
+          <Button onClick={() => router.go(-1)} style={{ float: 'right' }}>返回</Button>
174
+          <div>
175
+
176
+            <div style={{ display: 'flex' }}>
177
+              <div style={{
178
+                width: '1060px',
179
+                height: '560px',
180
+                paddingTop: '40px',
181
+                marginRight: ' 40px',
182
+              }}>
183
+                <UserSource BuildSelectHide={true} endDate={this.state.endDate} startDate={this.state.startDate} onSuccess={(e) => this.onSuccess(e)}></UserSource>
184
+              </div>
185
+              <div style={{
186
+                width: '509px',
187
+                height: '600px',
188
+                paddingTop: '40px',
189
+
190
+              }}>
191
+                <UserSourcepie endDate={this.state.endDate} startDate={this.state.startDate}></UserSourcepie>
192
+              </div>
193
+            </div>
194
+            <Select style={{ width: '180px' }} placeholder="所有用户" onChange={(e) => this.handleSelectChange(e)}>
195
+              <Option value='all'>所有用户</Option>
196
+              <Option value='registered'>注册用户</Option>
197
+            </Select>
198
+
199
+            <Table style={{ marginTop: '20px' }} dataSource={this.state.tableData} columns={columns} pagination={false} scroll={{ y: 500 }}></Table>
200
+          </div>
201
+        </div>
202
+      </>
203
+    )
204
+  }
205
+}
206
+
207
+export default Header

+ 219
- 0
estateagents-admin-manager/src/pages/integralMall/GoodsList.jsx 파일 보기

@@ -0,0 +1,219 @@
1
+import React, { useState, useEffect } from 'react';
2
+import { Form, Input, Button, Icon, Select, message, Table, Pagination, Modal } from 'antd';
3
+import router from 'umi/router';
4
+import AuthButton from '@/components/AuthButton';
5
+import withActions from '@/components/ActionList';
6
+import EditIcon from '@/components/EditIcon';
7
+import BuildSelect from '../../components/SelectButton/BuildSelect'
8
+import apis from '../../services/apis';
9
+import request from '../../utils/request'
10
+import styles from '../style/GoodsList.less';
11
+import Navigate from '@/components/Navigate';
12
+
13
+const { Option } = Select;
14
+
15
+
16
+function header(props) {
17
+  // 获取初始化数据
18
+  const [ data, setData ] = useState({})
19
+
20
+  useEffect(() => {
21
+    getList({ pageNum: 1, pageSize: 10 });
22
+  },[])
23
+
24
+  // 查询列表
25
+  const getList = (params) => {
26
+    request({ ...apis.integralMall.getTaGoods, params: { ...params },}).then((data) => {
27
+        console.log(data)
28
+        setData(data)
29
+    })
30
+  }
31
+  
32
+  // 提交事件
33
+  const handleSubmit = (e, props) => {
34
+    e.preventDefault();
35
+    props.form.validateFields((err, values) => {
36
+      if (!err) {
37
+        getList({ pageNum: 1, pageSize: 10, ...values })
38
+      }
39
+    });
40
+  }
41
+
42
+  const changePageNum = (pageNumber) => {
43
+    props.form.validateFields((err, values) => {
44
+      if (!err) {
45
+        getList({ pageNumber: pageNumber, pageSize: 10, ...values })
46
+      }
47
+    });
48
+  }
49
+
50
+  function handleReset() {
51
+    props.form.resetFields();
52
+    getList({ pageNum: 1, pageSize: 10 });
53
+  }
54
+
55
+  // 跳转到编辑商品
56
+  const toEditGoods = (goodsId) => () => {
57
+    router.push({
58
+      pathname: '/integralMall/editGoods',
59
+      query: {
60
+        goodsId
61
+      },
62
+    });
63
+  }
64
+
65
+  
66
+  const changeGoodsStatus = (row) => () => {
67
+    const title = row.status === 1 ? '商品在小程序端隐藏,后台可继续编辑重新发布?':'商品会重新显示在小程序端?'
68
+
69
+    Modal.confirm({
70
+      title: title,
71
+      okText: '确认',
72
+      cancelText: '取消',
73
+      onOk() {
74
+        request({ ...apis.integralMall.changeTaGoods, data: { ...row },}).then((data) => {
75
+          message.info('操作成功!')
76
+          getList({ pageNum: 1, pageSize: 10, ...props.form.getFieldsValue() });
77
+        })
78
+      }
79
+    });
80
+  }
81
+  /**
82
+   *
83
+   *
84
+   * @param {*} props
85
+   * @returns
86
+   */
87
+  const columns = [
88
+    {
89
+      title: '商品图片',
90
+      dataIndex: 'imgUrl',
91
+      key: 'imgUrl',
92
+      align: 'center',
93
+      render: (text, record) => <img src={record.imgUrl} className={styles.touxiang} />,
94
+    },
95
+    {
96
+      title: '商品名称',
97
+      dataIndex: 'goodsName',
98
+      key: 'goodsName',
99
+      align: 'center',
100
+      render:  (x, row) => <Navigate onClick={toEditGoods(row.goodsId)}>{row.goodsName}</Navigate>,
101
+    },
102
+    {
103
+      title: '所属积分',
104
+      dataIndex: 'pointPrice',
105
+      key: 'pointPrice',
106
+      align: 'center',
107
+    },
108
+    {
109
+      title: '总数量',
110
+      dataIndex: 'totalNum',
111
+      key: 'totalNum',
112
+      align: 'center',
113
+    },
114
+    {
115
+      title: '已兑换数量',
116
+      dataIndex: 'exchanged',
117
+      key: 'exchanged',
118
+      align: 'center',
119
+      render: (x,row) => <><span>{row.totalNum - row.inventory}</span></>
120
+    },
121
+    {
122
+      title: '剩余数量',
123
+      dataIndex: 'inventory',
124
+      key: 'inventory',
125
+      align: 'center',
126
+    },
127
+    {
128
+      title: '状态',
129
+      dataIndex: 'status',
130
+      key: 'status',
131
+      align: 'center',
132
+      render: (status)=> <><span>{status == 1 ? '已上架' : '已下架'}</span></>
133
+    },
134
+    {
135
+      title: '操作',
136
+      dataIndex: 'handle',
137
+      key: 'handle',
138
+      align: 'center',
139
+      render: withActions((x, row) => [
140
+          <AuthButton name="admin.taGoods.change.put" noRight={null}>
141
+            {
142
+              row.status === 1 ?
143
+              <EditIcon onClick={changeGoodsStatus(row)} type="down" text="下架" /> :
144
+              <EditIcon onClick={changeGoodsStatus(row)} type="up" text="上架" />
145
+            }
146
+          </AuthButton>,
147
+          <AuthButton name="admin.taGoods.put" noRight={null}>
148
+            <EditIcon onClick={toEditGoods(row.goodsId)} type="edit" text="编辑" />
149
+          </AuthButton>,
150
+        ]),
151
+    },
152
+  ];
153
+
154
+  const { getFieldDecorator } = props.form
155
+  return (
156
+
157
+    <>
158
+      <Form layout="inline" onSubmit={e => handleSubmit(e, props)}>
159
+        <Form.Item>
160
+          {getFieldDecorator('goodsName')(
161
+            <Input
162
+              prefix={<Icon type="text" style={{ color: 'rgba(0,0,0,.25)' }} />}
163
+              placeholder="商品名称"
164
+            />,
165
+          )}
166
+        </Form.Item>
167
+        <Form.Item>
168
+          {getFieldDecorator('status')(
169
+            <Select style={{ width: '180px' }} placeholder="状态">
170
+              <Option value="1">已上架</Option>
171
+              <Option value="0">已下架</Option>
172
+            </Select>,
173
+          )}
174
+        </Form.Item>
175
+        <Form.Item>
176
+          {getFieldDecorator('buildingId')(
177
+            <BuildSelect />,
178
+          )}
179
+        </Form.Item>
180
+        <Form.Item>
181
+          {getFieldDecorator('priceLesser')(
182
+            <Input
183
+              prefix={<Icon type="text" style={{ color: 'rgba(0,0,0,.25)' }} />}
184
+              placeholder="价格小"
185
+            />,
186
+          )}
187
+        </Form.Item>
188
+        <Form.Item>
189
+          {getFieldDecorator('priceGreater')(
190
+            <Input
191
+              prefix={<Icon type="text" style={{ color: 'rgba(0,0,0,.25)' }} />}
192
+              placeholder="价格大"
193
+            />,
194
+          )}
195
+        </Form.Item>
196
+        <Form.Item>
197
+            <AuthButton name="admin.taGoods.search" noRight={null}>
198
+              <Button type="primary" htmlType="submit" className={styles.searchBtn}>
199
+                搜索
200
+              </Button>
201
+            </AuthButton>
202
+            <Button style={{ marginLeft: 8 }} onClick={handleReset}>
203
+              重置
204
+            </Button>
205
+        </Form.Item>
206
+      </Form>
207
+      <AuthButton name="admin.taGoods.add.post" noRight={null}>
208
+        <Button type="danger" className={styles.addBtn} onClick={toEditGoods()}>新增</Button>
209
+      </AuthButton>
210
+      <Table rowKey="goodsList" dataSource={data.records} columns={columns} pagination={false} />
211
+      <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '30px' }}>
212
+        <Pagination showQuickJumper defaultCurrent={1} total={data.total} onChange={changePageNum} current={data.current}/>
213
+      </div>
214
+    </>
215
+  )
216
+}
217
+const WrappedHeader = Form.create({ name: 'header' })(header);
218
+
219
+export default WrappedHeader

+ 161
- 0
estateagents-admin-manager/src/pages/integralMall/achieve.jsx 파일 보기

@@ -0,0 +1,161 @@
1
+import React, { useState, useEffect } from 'react';
2
+import { Form, Icon, Tabs, Table, Pagination, message, Modal } from 'antd';
3
+import router from 'umi/router';
4
+import moment from 'moment';
5
+import AuthButton from '@/components/AuthButton';
6
+import withActions from '@/components/ActionList';
7
+import EditIcon from '@/components/EditIcon';
8
+import apis from '../../services/apis';
9
+import request from '../../utils/request';
10
+import styles from '../style/GoodsList.less';
11
+import Navigate from '@/components/Navigate';
12
+
13
+const { TabPane } = Tabs;
14
+
15
+function header(props) {
16
+  const [ carType, setCarType ] = useState({})
17
+  const callback = (key) => {
18
+    setCarType(key)
19
+    getList({ pageNum: 1, pageSize: 10 , type: key});
20
+  }
21
+    
22
+  // 获取初始化数据
23
+  const [ data, setData ] = useState({})
24
+
25
+  useEffect(() => {
26
+    getList({ pageNum: 1, pageSize: 10 , type: 'platform'});
27
+  },[])
28
+
29
+  // 查询列表
30
+  const getList = (params) => {
31
+    request({ ...apis.integralMall.tdPointsRules, params: { ...params },}).then((data) => {
32
+        console.log(data)
33
+        setData(data)
34
+    })
35
+  }
36
+
37
+  const changePageNum = (pageNumber) => {
38
+    getList({ pageNum: pageNumber, pageSize: 10, type: carType })
39
+  }
40
+
41
+
42
+  // 提交事件
43
+  const handleSubmit = (e, props) => {
44
+    e.preventDefault();
45
+    props.form.validateFields((err, values) => {
46
+      if (!err) {
47
+        getList({ pageNum: 1, pageSize: 10, ...values, type: carType})
48
+      }
49
+    });
50
+  }
51
+
52
+  const changeStatus = row => () => {
53
+    const title = row.status === 1 ? '停用后用户操作将不再发放积分,请确认相关免责声明等文案已修订说明?':'启用后用户操作将发放积分'
54
+
55
+    Modal.confirm({
56
+      title,
57
+      okText: '确认',
58
+      cancelText: '取消',
59
+      onOk() {
60
+        request({ ...apis.integralMall.change, data: { ...row }}).then(data => {
61
+          message.info('操作成功!')
62
+          getList({ pageNum: 1, pageSize: 10, type: carType})
63
+        })
64
+      },
65
+    });
66
+  }
67
+
68
+  const updateRules = (row) => () => {
69
+    router.push({
70
+      pathname: '/integralMall/editAchieve',
71
+      query: {
72
+        ruleId: row.ruleId
73
+      },
74
+    });
75
+  }
76
+
77
+const columns = [
78
+    {
79
+      title: '类型',
80
+      dataIndex: 'ruleName',
81
+      key: 'ruleName',
82
+      align: 'center',
83
+      render:  (x, row) => <Navigate onClick={updateRules(row)}>{row.ruleName}</Navigate>,
84
+    },
85
+    {
86
+      title: '获取积分',
87
+      dataIndex: 'pointsAmount',
88
+      key: 'pointsAmount',
89
+      align: 'center',
90
+    },
91
+    {
92
+      title: '说明',
93
+      dataIndex: 'remark',
94
+      key: 'remark',
95
+      align: 'center',
96
+    },
97
+    {
98
+      title: '状态',
99
+      dataIndex: 'status',
100
+      key: 'status',
101
+      align: 'center',
102
+      render: (status) => <span>{status == 1 ? '启用' : '停用'}</span>
103
+    },
104
+    {
105
+      title: '操作时间',
106
+      dataIndex: 'updateDate',
107
+      key: 'updateDate',
108
+      align: 'center',
109
+      render: (updateDate) => <><span>{updateDate != null ? moment(updateDate).format('YYYY-MM-DD') : ''}</span></>
110
+    },
111
+    {
112
+      title: '操作',
113
+      dataIndex: 'handle',
114
+      key: 'handle',
115
+      align: 'center',
116
+      render: withActions((x,row) => [
117
+        <AuthButton name="admin.tdPointsRules.change.put" noRight={null}>
118
+          <EditIcon type={row.status === 1 ? 'stop' : 'start'} text={row.status === 1 ? '停用' : '启用'} onClick={changeStatus(row)} />
119
+        </AuthButton>,
120
+        <AuthButton name="admin.tdPointsRules.put" noRight={null}>
121
+          <EditIcon type="edit" text="编辑" onClick={updateRules(row)} />
122
+        </AuthButton>,
123
+      ]),
124
+    },
125
+  ];
126
+
127
+  return (
128
+    <>
129
+      <Tabs onChange={callback} type="card">
130
+        <TabPane tab="平台积分" key="platform">
131
+          <Table rowKey="achieve" style={{ marginTop: '40px' }} dataSource={data.records} columns={columns} pagination={false}/>
132
+          <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '30px' }}>
133
+            <Pagination showQuickJumper defaultCurrent={1} total={data.total} onChange={changePageNum} current={data.current}/>
134
+          </div>
135
+        </TabPane>
136
+        {/* <TabPane tab="项目积分" key="project">
137
+          <Form layout="inline" onSubmit={e => handleSubmit(e, props)}>
138
+              <Form.Item>
139
+                {getFieldDecorator('buildingId')(
140
+                  <BuildSelect />,
141
+                )}
142
+              </Form.Item>
143
+              
144
+              <Form.Item>
145
+                <Button type="primary" htmlType="submit" className={styles.searchBtn}>
146
+                  搜索
147
+                </Button>
148
+              </Form.Item>
149
+          </Form>
150
+          <Table rowKey="achie" style={{ marginTop: '40px' }} dataSource={data.records} columns={columns} pagination={false}/>
151
+          <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '30px' }}>
152
+            <Pagination showQuickJumper defaultCurrent={1} total={data.total} onChange={changePageNum} current={data.current}/>
153
+          </div>
154
+        </TabPane> */}
155
+      </Tabs>,
156
+    </>
157
+  )
158
+}
159
+const WrappedHeader = Form.create({ name: 'header' })(header);
160
+
161
+export default WrappedHeader

+ 73
- 0
estateagents-admin-manager/src/pages/integralMall/editAchieve.jsx 파일 보기

@@ -0,0 +1,73 @@
1
+import React, { useState, useEffect } from 'react';
2
+import { Input, Menu, Dropdown, Button, Icon, message, Table, Divider, Tag, Select, Form, Alert } from 'antd';
3
+import { FormattedMessage } from 'umi-plugin-react/locale';
4
+import channels from '../channel/channelList.less';
5
+import BuildSelect from '../../components/SelectButton/BuildSelect'
6
+import XForm, { FieldTypes } from '../../components/XForm';
7
+import Wangedit from '../../components/Wangedit/Wangedit'
8
+import router from 'umi/router';
9
+import apis from '../../services/apis';
10
+import request from '../../utils/request'
11
+
12
+const { TextArea } = Input;
13
+const { Option } = Select;
14
+
15
+const header = props => {
16
+  const ruleId = props.location.query.ruleId
17
+  const [ ruleData, setRuleData ] = useState({})
18
+  if(ruleId){
19
+    useEffect(() => {
20
+      getRuleData(ruleId);
21
+    },[])
22
+
23
+  // 查询列表
24
+  const getRuleData = (ruleId) => {
25
+    request({ ...apis.integralMall.rulesDetail, urlData: { id: ruleId },}).then((data) => {
26
+        console.log(data)
27
+        setRuleData(data)
28
+    })
29
+  }
30
+  }
31
+
32
+  const fields = [
33
+    {
34
+      label: '获取积分',
35
+      name: 'pointsAmount',
36
+      type: FieldTypes.Text,
37
+      value: ruleData.pointsAmount,
38
+    },
39
+    {
40
+      label: '说明',
41
+      name: 'remark',
42
+      type: FieldTypes.Text,
43
+      value: ruleData.remark,
44
+    }
45
+  ]
46
+
47
+   
48
+  const handleSubmit = (values) => {
49
+    if(ruleId){
50
+      values.ruleId = ruleId
51
+      request({ ...apis.integralMall.rulesUpdate, data: values,}).then((data) => {
52
+        cancelPage()
53
+      }).catch((err) => {
54
+        message.info(err.msg || err.message)
55
+      })
56
+      }else{
57
+       
58
+      }
59
+  }
60
+
61
+  const cancelPage = () => {
62
+    router.push({
63
+      pathname: '/integralMall/achieve',
64
+    });
65
+  }
66
+
67
+  return (
68
+    <XForm onSubmit={handleSubmit} onCancel={cancelPage} fields={fields}></XForm>
69
+  )
70
+}
71
+
72
+const WrappedNormalLoginForm = Form.create({ name: 'header' })(header);
73
+export default WrappedNormalLoginForm

+ 156
- 0
estateagents-admin-manager/src/pages/integralMall/editGoods.jsx 파일 보기

@@ -0,0 +1,156 @@
1
+import React, { useState, useEffect } from 'react';
2
+import { Input, Menu, Dropdown, Button, Icon, message, Table, Divider, Tag, Select, Form, Alert } from 'antd';
3
+import { FormattedMessage } from 'umi-plugin-react/locale';
4
+import channels from '../channel/channelList.less';
5
+import BuildSelect from '../../components/SelectButton/BuildSelect2'
6
+import XForm, { FieldTypes } from '../../components/XForm';
7
+import Wangedit from '../../components/Wangedit/Wangedit'
8
+import router from 'umi/router';
9
+import apis from '../../services/apis';
10
+import request from '../../utils/request'
11
+
12
+const { TextArea } = Input;
13
+const { Option } = Select;
14
+
15
+const header = props => {
16
+  const goodsId = props.location.query.goodsId
17
+  const [ goodsData, setGoodsData ] = useState({})
18
+  if(goodsId){
19
+    useEffect(() => {
20
+      getGoodsData(goodsId);
21
+    },[])
22
+
23
+  // 查询列表
24
+  const getGoodsData = (goodsId) => {
25
+    request({ ...apis.integralMall.taGoods, urlData: { id: goodsId },}).then((data) => {
26
+        console.log(data)
27
+        setGoodsData(data)
28
+    })
29
+  }
30
+  }
31
+
32
+  const fields = [
33
+    {
34
+      label: '所属项目',
35
+      name: 'buildingId',
36
+      render: <BuildSelect />,
37
+      value: goodsData.buildingId,
38
+      rules: [
39
+        {required: true, message: '请选择所属项目'},
40
+      ]
41
+    },
42
+    {
43
+      label: '商品封面图',
44
+      name: 'imgUrl',
45
+      type: FieldTypes.ImageUploader,
46
+      value: goodsData.imgUrl,
47
+      help: '建议图片尺寸:320*320px,比例1:1,格式:jpg,用于商品封面图',
48
+      rules: [
49
+        {required: true, message: '请选择商品封面图'},
50
+      ]
51
+    },
52
+    {
53
+      label: '商品主图',
54
+      name: 'detailImgUrl',
55
+      type: FieldTypes.ImageUploader,
56
+      value: goodsData.detailImgUrl,
57
+      help: '建议图片尺寸:750*750px,比例1:1,格式:jpg,用于商品主图',
58
+      rules: [
59
+        {required: true, message: '请选择商品主图'},
60
+      ]
61
+    },
62
+    {
63
+      label: '商品名称',
64
+      name: 'goodsName',
65
+      type: FieldTypes.Text,
66
+      value: goodsData.goodsName,
67
+      rules: [
68
+        {required: true, message: '请输入商品名称'},
69
+      ]
70
+    },
71
+    {
72
+      label: '所需积分',
73
+      name: 'pointPrice',
74
+      type: FieldTypes.Text,
75
+      value: goodsData.pointPrice,
76
+      rules: [
77
+        {required: true, message: '请输入所需积分'},
78
+      ]
79
+    },
80
+    {
81
+      label: '商品数量',
82
+      name: 'totalNum',
83
+      type: FieldTypes.Text,
84
+      value: goodsData.totalNum,
85
+      rules: [
86
+        {required: true, message: '请输入商品数量'},
87
+      ]
88
+    },
89
+    {
90
+      label: '剩余数量',
91
+      name: 'inventory',
92
+      type: FieldTypes.Text,
93
+      value: goodsData.inventory,
94
+      rules: [
95
+        {required: true, message: '请输入剩余数量'},
96
+      ]
97
+    },
98
+    {
99
+      label: '商品详情',
100
+      name: 'goodsDescription',
101
+      render: <Wangedit />,
102
+      value: goodsData.goodsDescription,
103
+    },
104
+    {
105
+      label: '状态',
106
+      name: 'status',
107
+      type: FieldTypes.Select,
108
+      dict: [{label:"已上架",value:1},{label:"已下架",value:0}],
109
+      value: goodsData.status != null ? goodsData.status : 1,
110
+    },
111
+    {
112
+      label: '领取地址',
113
+      name: 'address',
114
+      type: FieldTypes.Text,
115
+      value: goodsData.address,
116
+      rules: [
117
+        {required: true, message: '请输入领取地址'},
118
+      ]
119
+    },
120
+  ]
121
+
122
+  const handleSubmit = values => {
123
+    if (values.inventory > values.totalNum) {
124
+      message.error('商品剩余数量不能大于商品总数量')
125
+      return
126
+  }
127
+
128
+    if (goodsId) {
129
+      values.goodsId = goodsId
130
+      request({ ...apis.integralMall.updateTaGoods, data: values,}).then((data) => {
131
+        cancelPage()
132
+      }).catch((err) => {
133
+        message.info(err.msg || err.message)
134
+      })
135
+      }else{
136
+      request({ ...apis.integralMall.addTaGoods, data: values,}).then((data) => {
137
+        cancelPage()
138
+      }).catch((err) => {
139
+        message.info(err.msg || err.message)
140
+      })
141
+      }
142
+  }
143
+
144
+  const cancelPage = () => {
145
+    router.push({
146
+      pathname: '/integralMall/GoodsList',
147
+    });
148
+  }
149
+
150
+  return (
151
+    <XForm onSubmit={handleSubmit} onCancel={cancelPage} fields={fields}></XForm>
152
+  )
153
+}
154
+
155
+const WrappedNormalLoginForm = Form.create({ name: 'header' })(header);
156
+export default WrappedNormalLoginForm

+ 222
- 0
estateagents-admin-manager/src/pages/integralMall/exchangeRecords.jsx 파일 보기

@@ -0,0 +1,222 @@
1
+import React, { useState, useEffect } from 'react';
2
+import { Form, Input, Button, Icon, Select, DatePicker, Table, Pagination } from 'antd';
3
+import { FormattedMessage } from 'umi-plugin-react/locale';
4
+import styles from '../style/GoodsList.less';
5
+import router from 'umi/router';
6
+import moment from 'moment';
7
+import BuildSelect from '../../components/SelectButton/BuildSelect'
8
+import apis from '../../services/apis';
9
+import request from '../../utils/request'
10
+import AuthButton from '@/components/AuthButton';
11
+
12
+/**
13
+  @param {*} props
14
+  @returns
15
+ */
16
+const { Option } = Select;
17
+const { MonthPicker, RangePicker, WeekPicker } = DatePicker;
18
+
19
+function record(props) {
20
+  const { getFieldDecorator } = props.form
21
+
22
+  // 获取初始化数据
23
+  const [data, setData] = useState({})
24
+
25
+  useEffect(() => {
26
+    getList({ pageNum: 1, pageSize: 10 });
27
+  }, [])
28
+
29
+  // 查询列表
30
+  const getList = (params) => {
31
+    request({ ...apis.integralMall.taPointsExchange, params: { ...params }, }).then((data) => {
32
+      setData(data)
33
+      console.log("data:", data)
34
+    })
35
+  }
36
+
37
+  //重置搜索
38
+  function handleReset() {
39
+    props.form.resetFields();
40
+  }
41
+
42
+
43
+
44
+  // 提交事件
45
+  const handleSubmit = (e, props) => {
46
+    e.preventDefault();
47
+    props.form.validateFields((err, values) => {
48
+      if (!err) {
49
+        let { exchangeTime, receiveTime, ...submitValue } = values
50
+        if (null != exchangeTime && exchangeTime.length > 0) {
51
+          const [startCreateDate, endCreateDate] = exchangeTime
52
+          submitValue.startCreateDate = moment(startCreateDate).format('YYYY-MM-DD');
53
+          submitValue.endCreateDate = moment(endCreateDate).format('YYYY-MM-DD');
54
+        } else {
55
+          submitValue.startCreateDate = null
56
+          submitValue.endCreateDate = null
57
+        }
58
+
59
+        if (null != receiveTime && receiveTime.length > 0) {
60
+          const [startVerifyDate, endVerifyDate] = receiveTime
61
+          submitValue.startVerifyDate = moment(startVerifyDate).format('YYYY-MM-DD');
62
+          submitValue.endVerifyDate = moment(endVerifyDate).format('YYYY-MM-DD');
63
+        } else {
64
+          submitValue.startVerifyDate = null
65
+          submitValue.endVerifyDate = null
66
+        }
67
+
68
+        console.log(submitValue)
69
+        getList({ pageNum: 1, pageSize: 10, ...submitValue })
70
+      }
71
+    });
72
+  }
73
+
74
+  const changePageNum = (pageNumber) => {
75
+    props.form.validateFields((err, values) => {
76
+      if (!err) {
77
+        getList({ pageNum: pageNumber, pageSize: 10, ...values })
78
+      }
79
+    });
80
+  }
81
+
82
+  const columns = [
83
+
84
+    {
85
+      title: '用户姓名',
86
+      dataIndex: 'personName',
87
+      key: 'personName',
88
+      align: 'center',
89
+    },
90
+    {
91
+      title: '用户类型',
92
+      dataIndex: 'personType',
93
+      key: 'personType',
94
+      align: 'center',
95
+      render: (personType) => <><span>{personType === 'Realty Consultant' ? '置业顾问' : personType === 'Sales Executive' ? '销售主管' : personType === 'estate agent' ? '经纪人' : personType === 'customer' ? '客户' : ''}</span></>
96
+    },
97
+    {
98
+      title: '手机号',
99
+      dataIndex: 'phone',
100
+      key: 'phone',
101
+      align: 'center',
102
+    },
103
+    {
104
+      title: '商品图片',
105
+      dataIndex: 'image',
106
+      key: 'image',
107
+      align: 'center',
108
+      render: (text, record) => <img src={record.image} className={styles.touxiang} />,
109
+    },
110
+    {
111
+      title: '商品名称',
112
+      dataIndex: 'targetName',
113
+      key: 'targetName',
114
+      align: 'center',
115
+    },
116
+    {
117
+      title: '兑换时间',
118
+      dataIndex: 'createDate',
119
+      key: 'createDate',
120
+      align: 'center',
121
+      render: (_, recorde) => <><span>{moment(recorde.createDate).format('YYYY-MM-DD HH:mm')}</span></>,
122
+    },
123
+    {
124
+      title: '领取时间',
125
+      dataIndex: 'verifyDate',
126
+      key: 'verifyDate',
127
+      align: 'center',
128
+      render: (_, recorde) => <><span>{recorde.verifyDate != null ? moment(recorde.verifyDate).format('YYYY-MM-DD HH:mm') : ''}</span></>,
129
+    },
130
+    {
131
+      title: '状态',
132
+      dataIndex: 'status',
133
+      key: 'status',
134
+      align: 'center',
135
+      render: (status) => <><span>{status == 1 ? '已领取' : '未领取'}</span></>
136
+    },
137
+  ];
138
+
139
+  return (
140
+
141
+    <>
142
+      <Form layout="inline" onSubmit={e => handleSubmit(e, props)}>
143
+        <div style={{ display: 'flex' }}>
144
+          <Form.Item>
145
+            {getFieldDecorator('personName')(
146
+              <Input
147
+                prefix={<Icon type="text" style={{ color: 'rgba(0,0,0,.25)' }} />}
148
+                placeholder="用户姓名"
149
+              />,
150
+            )}
151
+          </Form.Item>
152
+          <Form.Item>
153
+            {getFieldDecorator('phone')(
154
+              <Input
155
+                prefix={<Icon type="text" style={{ color: 'rgba(0,0,0,.25)' }} />}
156
+                placeholder="手机号"
157
+              />,
158
+            )}
159
+          </Form.Item>
160
+          <Form.Item>
161
+            {getFieldDecorator('targetName')(
162
+              <Input
163
+                prefix={<Icon type="text" style={{ color: 'rgba(0,0,0,.25)' }} />}
164
+                placeholder="商品名称"
165
+              />,
166
+            )}
167
+          </Form.Item>
168
+          <Form.Item>
169
+            {getFieldDecorator('personType')(
170
+              <Select style={{ minWidth: '1.1rem' }} placeholder="用户类型">
171
+                <Option value="Realty Consultant">置业顾问</Option>
172
+                <Option value="customer">客户</Option>
173
+                <Option value="estate agent">经纪人</Option>
174
+              </Select>,
175
+            )}
176
+          </Form.Item>
177
+          <Form.Item>
178
+            {getFieldDecorator('status')(
179
+              <Select style={{ minWidth: '1.1rem' }} placeholder="状态">
180
+                <Option value="1">已领取</Option>
181
+                <Option value="0">未领取</Option>
182
+              </Select>,
183
+            )}
184
+          </Form.Item>
185
+
186
+        </div>
187
+        <div style={{ margin: '10px 0' }}>
188
+          <Form.Item>
189
+            <span style={{ marginRight: '10px' }}>兑换时间:</span>
190
+            {getFieldDecorator('exchangeTime')(
191
+              <RangePicker placeholder={['开始时间', '结束时间']} />
192
+            )}
193
+          </Form.Item>
194
+          <Form.Item>
195
+            <span style={{ marginRight: '10px' }}>领取时间:</span>
196
+            {getFieldDecorator('receiveTime')(
197
+              <RangePicker placeholder={['开始时间', '结束时间']} />
198
+            )}
199
+          </Form.Item>
200
+          <Form.Item >
201
+            <AuthButton name="admin.taGoods.exchange" noRight={null}>
202
+              <Button type="primary" htmlType="submit">
203
+                搜索
204
+              </Button>
205
+            </AuthButton>
206
+            <Button style={{ marginLeft: 8 }} onClick={handleReset}>
207
+              重置
208
+            </Button>
209
+          </Form.Item>
210
+        </div>
211
+
212
+      </Form>
213
+      <Table rowKey="exchangeRecords" style={{ marginTop: '40px' }} dataSource={data.records} columns={columns} pagination={false} />
214
+      <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '30px' }}>
215
+        <Pagination showQuickJumper defaultCurrent={1} total={data.total} onChange={changePageNum} current={data.current} />
216
+      </div>
217
+    </>
218
+  )
219
+}
220
+const WrappedHeader = Form.create({ name: 'record' })(record);
221
+
222
+export default WrappedHeader

+ 123
- 0
estateagents-admin-manager/src/pages/integralMall/verifyList.jsx 파일 보기

@@ -0,0 +1,123 @@
1
+import React, { useState, useEffect } from 'react';
2
+import { Form, Input, Button, Icon, Select, message, Table, Divider, Tag, Pagination, Modal, DatePicker } from 'antd';
3
+import { FormattedMessage } from 'umi-plugin-react/locale';
4
+import styles from '../style/GoodsList.less';
5
+import router from 'umi/router';
6
+import moment from 'moment';
7
+import apis from '../../services/apis';
8
+import request from '../../utils/request'
9
+
10
+const { Option } = Select;
11
+const { MonthPicker, RangePicker, WeekPicker } = DatePicker;
12
+
13
+const header = (props) => {
14
+  const [data, setData] = useState({})
15
+
16
+  useEffect(() => {
17
+    getVerifyList({ pageNum: 1, pageSize: 10, phone: props.location.query.telValue });
18
+  }, [])
19
+
20
+  // 查询列表
21
+  const getVerifyList = (params) => {
22
+    request({ ...apis.integralMall.taPointsExchange, params: { ...params }, }).then((data) => {
23
+      setData(data)
24
+    })
25
+  }
26
+
27
+  const changePageNum = (pageNumber) => {
28
+    getVerifyList({ pageNum: pageNumber, pageSize: 10, phone: props.location.query.telValue })
29
+  }
30
+
31
+  const toBack = () => {
32
+    router.push({
33
+      pathname: '/integralMall/writeOff',
34
+    });
35
+  }
36
+
37
+  const changeStatus = (row) => () => {
38
+    // console.log(new Date())
39
+    row.verifyDate = new Date()
40
+    // console.log('row.verifyDate: ', row.verifyDate)
41
+    request({ ...apis.integralMall.changeTaPointsExchange, data: row }).then((data) => {
42
+      message.info("操作成功")
43
+      getVerifyList({ pageNum: 1, pageSize: 10, phone: props.location.query.telValue })
44
+    })
45
+  }
46
+
47
+  const columns = [
48
+    {
49
+      title: '用户姓名',
50
+      dataIndex: 'personName',
51
+      key: 'personName',
52
+      align: 'center',
53
+    },
54
+    {
55
+      title: '用户类型',
56
+      dataIndex: 'personType',
57
+      key: 'personType',
58
+      align: 'center',
59
+      render: (personType) => <><span>{personType === 'Realty Consultant' ? '置业顾问' : personType === 'Sales Executive' ? '销售主管' : personType === 'estate agent' ? '经纪人' : personType === 'customer' ? '客户' : ''}</span></>
60
+    },
61
+    {
62
+      title: '手机号',
63
+      dataIndex: 'phone',
64
+      key: 'phone',
65
+      align: 'center',
66
+    },
67
+    {
68
+      title: '商品图片',
69
+      dataIndex: 'image',
70
+      key: 'image',
71
+      align: 'center',
72
+      render: (text, record) => <img src={record.image} className={styles.touxiang} />,
73
+    },
74
+    {
75
+      title: '商品名称',
76
+      dataIndex: 'targetName',
77
+      key: 'targetName',
78
+      align: 'center',
79
+    },
80
+    {
81
+      title: '兑换时间',
82
+      dataIndex: 'createDate',
83
+      key: 'createDate',
84
+      align: 'center',
85
+      render: (createDate) => <><span>{moment(createDate).format('YYYY-MM-DD HH:mm')}</span></>
86
+    },
87
+    {
88
+      title: '领取时间',
89
+      dataIndex: 'verifyDate',
90
+      key: 'verifyDate',
91
+      align: 'center',
92
+      render: (verifyDate) => <><span>{verifyDate != null ? moment(verifyDate).format('YYYY-MM-DD HH:mm') : ''}</span></>
93
+    },
94
+    {
95
+      title: '状态',
96
+      dataIndex: 'status',
97
+      key: 'status',
98
+      align: 'center',
99
+      render: (status) => <><span>{status == 1 ? '已领取' : '未领取'}</span></>
100
+    },
101
+    {
102
+      title: '操作',
103
+      dataIndex: 'handle',
104
+      key: 'handle',
105
+      align: 'center',
106
+      render: (x, row) => <span style={{ color: '#1990FF' }} onClick={changeStatus(row)}>{row.status == 1 ? '' : '核销'}</span>
107
+
108
+    },
109
+  ];
110
+
111
+  return (
112
+    <>
113
+      <div align="right" style={{marginBottom:'16px'}}><Button onClick={toBack}>返回</Button></div>
114
+      <Table rowKey="verifyList" dataSource={data.records} columns={columns} pagination={false} />
115
+      <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '30px' }}>
116
+        <Pagination showQuickJumper defaultCurrent={1} total={data.total} onChange={changePageNum} current={data.current} />
117
+      </div>
118
+    </>
119
+  )
120
+}
121
+const WrappedHeader = Form.create({ name: 'header' })(header);
122
+
123
+export default WrappedHeader

+ 161
- 0
estateagents-admin-manager/src/pages/integralMall/writeOff.jsx 파일 보기

@@ -0,0 +1,161 @@
1
+import React, { useState, useEffect } from 'react';
2
+import { Form, Input, Button, Icon, Tabs, Row, Col, Modal, message } from 'antd';
3
+import { FormattedMessage } from 'umi-plugin-react/locale';
4
+import styles from '../style/GoodsList.less';
5
+import router from 'umi/router';
6
+import erweima from '../../assets/erweima.png';
7
+import saoma from '../../assets/saoma.png';
8
+import list from '../../assets/list.png';
9
+import AuthButton from '@/components/AuthButton';
10
+
11
+const { TabPane } = Tabs;
12
+function callback(key) {
13
+  console.log(key);
14
+}
15
+
16
+/**
17
+ * @param {*} props
18
+ * @returns
19
+ */
20
+class Dialog extends React.Component {
21
+  state = {
22
+    visible: false,
23
+  };
24
+
25
+  showModal = () => {
26
+    this.setState({ visible: true, });
27
+  };
28
+
29
+  handleCancel = () => {
30
+    this.setState({ visible: false });
31
+  };
32
+
33
+  onKeyDown = (e) => {
34
+
35
+    if (e.keyCode == 13) {
36
+      this.setState({ visible: false });
37
+      this.props.onEnter();
38
+    }
39
+  }
40
+
41
+  render() {
42
+    const { visible, loading } = this.state;
43
+    return (
44
+      <div>
45
+        <AuthButton name="admin.taPointsExchange.recId.put" noRight={null}>
46
+          <Button type="primary" onClick={this.showModal} style={{ margin: '80px auto', display: 'block', padding: '6px 46px', backgroundColor: '#EA2323', border: 'none' }}>立即核销</Button>
47
+        </AuthButton>
48
+        <Modal
49
+          style={{ marginTop: '20vh' }}
50
+          visible={visible}
51
+          title="核销数据"
52
+          onCancel={this.handleCancel}
53
+          footer={[]}
54
+        >
55
+          <p>扫描二维码数据</p>
56
+          <Input placeholder="请用扫描枪扫描二维码" onKeyDown={this.onKeyDown} onChange={this.props.onChange} />
57
+        </Modal>
58
+      </div>
59
+    );
60
+  }
61
+}
62
+
63
+
64
+function header(props) {
65
+  const [telValue, setTelValue] = useState('')
66
+
67
+  const changeTel = (e) => {
68
+    setTelValue(e.target.value)
69
+  }
70
+
71
+  const [codeValue, setCodeValue] = useState('')
72
+  const changeCode = (e) => {
73
+
74
+    setCodeValue(e.target.value)
75
+
76
+  }
77
+
78
+  const verifyTel = () => {
79
+    if (telValue === "") {
80
+      message.error("请输入手机号");
81
+      return;
82
+    }
83
+    router.push({
84
+      pathname: '/integralMall/verifyList',
85
+      query: {
86
+        telValue
87
+      },
88
+    });
89
+  }
90
+
91
+
92
+  const handleEnter = (e) => {
93
+    if (codeValue === "") {
94
+      message.error("无二维码数据");
95
+      return;
96
+    } else {
97
+
98
+      router.push({
99
+        pathname: '/integralMall/verifyList',
100
+        query: {
101
+          telValue:codeValue
102
+        },
103
+      });
104
+    }
105
+  }
106
+
107
+  const { getFieldDecorator } = props.form
108
+  return (
109
+    <>
110
+      <Tabs onChange={callback} type="card">
111
+        {/* <TabPane tab="扫码核销" key="1">
112
+          <Row>
113
+            <Col span={8} style={{ textAlign: 'center' }}>
114
+              <img src={erweima} style={{ width: '50px', height: '50px', margin: '30px auto' }} />
115
+              <p>1</p>
116
+              <p>请用户出示核销的二维码</p>
117
+              <p>请将网页输入法切换成英文</p>
118
+            </Col>
119
+            <Col span={8} style={{ textAlign: 'center' }}>
120
+              <img src={saoma} style={{ width: '50px', height: '50px', margin: '30px auto' }} />
121
+              <p>2</p>
122
+              <p>点击“立即核销”按钮</p>
123
+              <p>使用扫码枪扫描客户二维码</p>
124
+            </Col>
125
+            <Col span={8} style={{ textAlign: 'center' }}>
126
+              <img src={list} style={{ width: '50px', height: '50px', margin: '30px auto' }} />
127
+              <p>3</p>
128
+              <p style={{ margin: '44px auto' }}>根据提示进行核销操作</p>
129
+            </Col>
130
+          </Row>
131
+          <Dialog onEnter={handleEnter} onChange={changeCode} />
132
+        </TabPane> */}
133
+        <TabPane tab="手机号核销" key="2">
134
+          <Row>
135
+            <Col span={12} style={{ textAlign: 'center' }}>
136
+              <img src={erweima} style={{ width: '50px', height: '50px', margin: '30px auto' }} />
137
+              <p>1</p>
138
+              <p>请输入用户的手机号</p>
139
+            </Col>
140
+            <Col span={12} style={{ textAlign: 'center' }}>
141
+              <img src={list} style={{ width: '50px', height: '50px', margin: '30px auto' }} />
142
+              <p>2</p>
143
+              <p>点击“立即核销”按钮</p>
144
+            </Col>
145
+          </Row>
146
+          <div style={{ margin: '110px auto', display: 'block', textAlign: 'center' }}>
147
+            <Input placeholder="请输入手机号" style={{ width: '200px' }} onChange={changeTel} />
148
+            <AuthButton name="admin.taPointsExchange.recId.put" noRight={null}>
149
+              <Button type="primary" style={{ marginLeft: '10px', padding: '0px 46px', backgroundColor: '#EA2323', border: 'none' }} onClick={verifyTel}>立即核销</Button>
150
+            </AuthButton>
151
+          </div>
152
+        </TabPane>
153
+      </Tabs>,
154
+    </>
155
+  )
156
+}
157
+
158
+const WrappedHeader = Form.create({ name: 'header' })(header);
159
+
160
+
161
+export default WrappedHeader

+ 96
- 0
estateagents-admin-manager/src/pages/miniapp/editIcons.jsx 파일 보기

@@ -0,0 +1,96 @@
1
+import React, { useState, useEffect } from 'react';
2
+import { Input, Menu, Dropdown, Button, Icon, message, Table, Divider, Tag, Select, Form, Alert } from 'antd';
3
+import { FormattedMessage } from 'umi-plugin-react/locale';
4
+import channels from '../channel/channelList.less';
5
+import MiniappIconSelect from '../../components/SelectButton/MiniappIconSelect'
6
+import XForm, { FieldTypes } from '../../components/XForm';
7
+import Wangedit from '../../components/Wangedit/Wangedit'
8
+import router from 'umi/router';
9
+import apis from '../../services/apis';
10
+import request from '../../utils/request'
11
+
12
+const { TextArea } = Input;
13
+const { Option } = Select;
14
+
15
+const header = props => {
16
+  const goodsId = props.location.query.goodsId
17
+  const [ goodsData, setGoodsData ] = useState({})
18
+  if(goodsId){
19
+    useEffect(() => {
20
+      getGoodsData(goodsId);
21
+    },[])
22
+
23
+  // 查询列表
24
+  const getGoodsData = (goodsId) => {
25
+    request({ ...apis.integralMall.taGoods, urlData: { id: goodsId },}).then((data) => {
26
+        console.log(data)
27
+        setGoodsData(data)
28
+    })
29
+  }
30
+  }
31
+
32
+  const fields = [
33
+    {
34
+      label: '请选择首页功能',
35
+      name: 'iconCode',
36
+      render: <MiniappIconSelect />,
37
+      value: goodsData.iconCode,
38
+      rules: [
39
+        {required: true, message: '请选择所属项目'},
40
+      ]
41
+    },
42
+    {
43
+      label: '功能名称',
44
+      name: 'iconName',
45
+      type: FieldTypes.Text,
46
+      value: goodsData.iconName ,
47
+      help: '不填就使用默认名称',
48
+    },
49
+    {
50
+      label: '权重',
51
+      name: 'sort',
52
+      type: FieldTypes.Number,
53
+      render: <Input type="number" style={{ width: 80}} />,
54
+      value: goodsData.sort,
55
+      rules: [
56
+        { required: true, message: '请输入权重' },
57
+      ],
58
+      help: '数字越大越靠前',
59
+    },
60
+  ]
61
+
62
+  const handleSubmit = values => {
63
+    if (values.inventory > values.totalNum) {
64
+      message.error('商品剩余数量不能大于商品总数量')
65
+      return
66
+  }
67
+
68
+    if (goodsId) {
69
+      values.goodsId = goodsId
70
+      request({ ...apis.integralMall.updateTaGoods, data: values,}).then((data) => {
71
+        cancelPage()
72
+      }).catch((err) => {
73
+        message.info(err.msg || err.message)
74
+      })
75
+      }else{
76
+      request({ ...apis.integralMall.addTaGoods, data: values,}).then((data) => {
77
+        cancelPage()
78
+      }).catch((err) => {
79
+        message.info(err.msg || err.message)
80
+      })
81
+      }
82
+  }
83
+
84
+  const cancelPage = () => {
85
+    router.push({
86
+      pathname: '/integralMall/GoodsList',
87
+    });
88
+  }
89
+
90
+  return (
91
+    <XForm onSubmit={handleSubmit} onCancel={cancelPage} fields={fields}></XForm>
92
+  )
93
+}
94
+
95
+const WrappedNormalLoginForm = Form.create({ name: 'header' })(header);
96
+export default WrappedNormalLoginForm

+ 220
- 0
estateagents-admin-manager/src/pages/miniapp/menuList.jsx 파일 보기

@@ -0,0 +1,220 @@
1
+import React, { useState, useEffect } from 'react';
2
+import { Form, Input, Button, Icon, Select, message, Table, Divider, Tag, Pagination, Modal,Breadcrumb } from 'antd';
3
+import { FormattedMessage } from 'umi-plugin-react/locale';
4
+import styles from '../style/GoodsList.less';
5
+import router from 'umi/router';
6
+import BuildSelect from '../../components/SelectButton/BuildSelect'
7
+import apis from '../../services/apis';
8
+import request from '../../utils/request'
9
+import AuthButton from '@/components/AuthButton';
10
+
11
+const { Option } = Select;
12
+
13
+
14
+function header(props) {
15
+  // 获取初始化数据
16
+  const [ data, setData ] = useState({})
17
+
18
+  useEffect(() => {
19
+    getList({ pageNum: 1, pageSize: 10 });
20
+  },[])
21
+
22
+  // 查询列表
23
+  const getList = (params) => {
24
+    request({ ...apis.integralMall.getTaGoods, params: { ...params },}).then((data) => {
25
+        console.log(data)
26
+        setData(data)
27
+    })
28
+  }
29
+  
30
+  // 提交事件
31
+  const handleSubmit = (e, props) => {
32
+    e.preventDefault();
33
+    props.form.validateFields((err, values) => {
34
+      if (!err) {
35
+        getList({ pageNum: 1, pageSize: 10, ...values })
36
+      }
37
+    });
38
+  }
39
+
40
+  const changePageNum = (pageNumber) => {
41
+    props.form.validateFields((err, values) => {
42
+      if (!err) {
43
+        getList({ pageNumber: pageNumber, pageSize: 10, ...values })
44
+      }
45
+    });
46
+  }
47
+
48
+  function handleReset() {
49
+    props.form.resetFields();
50
+    getList({ pageNum: 1, pageSize: 10 });
51
+  }
52
+
53
+  // 跳转到编辑商品
54
+  const toEditIcons = (goodsId) => () => {
55
+    router.push({
56
+      pathname: '/miniapp/editIcons',
57
+      query: {
58
+        goodsId
59
+      },
60
+    });
61
+  }
62
+
63
+  
64
+  const changeGoodsStatus = (row) => () => {
65
+    const title = row.status === 1 ? '商品在小程序端隐藏,后台可继续编辑重新发布?':'商品会重新显示在小程序端?'
66
+
67
+    Modal.confirm({
68
+      title: title,
69
+      okText: '确认',
70
+      cancelText: '取消',
71
+      onOk() {
72
+        request({ ...apis.integralMall.changeTaGoods, data: { ...row },}).then((data) => {
73
+          message.info('操作成功!')
74
+          getList({ pageNum: 1, pageSize: 10, ...props.form.getFieldsValue() });
75
+        })
76
+      }
77
+    });
78
+  }
79
+  /**
80
+   *
81
+   *
82
+   * @param {*} props
83
+   * @returns
84
+   */
85
+  const columns = [
86
+    {
87
+      title: '商品图片',
88
+      dataIndex: 'imgUrl',
89
+      key: 'imgUrl',
90
+      align: 'center',
91
+      render: (text, record) => <img src={record.imgUrl} className={styles.touxiang} />,
92
+    },
93
+    {
94
+      title: '商品名称',
95
+      dataIndex: 'goodsName',
96
+      key: 'goodsName',
97
+      align: 'center',
98
+
99
+    },
100
+    {
101
+      title: '所属积分',
102
+      dataIndex: 'pointPrice',
103
+      key: 'pointPrice',
104
+      align: 'center',
105
+    },
106
+    {
107
+      title: '总数量',
108
+      dataIndex: 'totalNum',
109
+      key: 'totalNum',
110
+      align: 'center',
111
+    },
112
+    {
113
+      title: '已兑换数量',
114
+      dataIndex: 'exchanged',
115
+      key: 'exchanged',
116
+      align: 'center',
117
+      render: (x,row) => <><span>{row.totalNum - row.inventory}</span></>
118
+    },
119
+    {
120
+      title: '剩余数量',
121
+      dataIndex: 'inventory',
122
+      key: 'inventory',
123
+      align: 'center',
124
+    },
125
+    {
126
+      title: '状态',
127
+      dataIndex: 'status',
128
+      key: 'status',
129
+      align: 'center',
130
+      render: (status)=> <><span>{status == 1 ? '已上架' : '已下架'}</span></>
131
+    },
132
+    {
133
+      title: '操作',
134
+      dataIndex: 'handle',
135
+      key: 'handle',
136
+      align: 'center',
137
+      render: (x, row) => (
138
+        <>
139
+          <AuthButton name="admin.taGoods.change.put" noRight={null}>
140
+            <span style={{ color: '#EF273A', marginRight: '20px',cursor: 'pointer' }} onClick={changeGoodsStatus(row)}>
141
+              {row.status == 1 ? '下架' : '上架'}
142
+              {<Icon type="shopping-cart" className={styles.shoppingCart} />}
143
+            </span>
144
+          </AuthButton>
145
+          <AuthButton name="admin.taGoods.put" noRight={null}>
146
+            <span style={{ color: '#FF925C',cursor: 'pointer' }} onClick={toEditIcons(row.goodsId)}>
147
+              编辑<Icon type="form" className={styles.edit} />
148
+            </span>
149
+          </AuthButton>
150
+        </>
151
+      ),
152
+    },
153
+  ];
154
+
155
+  const { getFieldDecorator } = props.form
156
+  return (
157
+
158
+    <>
159
+      <Form layout="inline" onSubmit={e => handleSubmit(e, props)}>
160
+        <Form.Item>
161
+          {getFieldDecorator('goodsName')(
162
+            <Input
163
+              prefix={<Icon type="text" style={{ color: 'rgba(0,0,0,.25)' }} />}
164
+              placeholder="商品名称"
165
+            />,
166
+          )}
167
+        </Form.Item>
168
+        <Form.Item>
169
+          {getFieldDecorator('status')(
170
+            <Select style={{ width: '180px' }} placeholder="状态">
171
+              <Option value="1">已上架</Option>
172
+              <Option value="0">已下架</Option>
173
+            </Select>,
174
+          )}
175
+        </Form.Item>
176
+        <Form.Item>
177
+          {getFieldDecorator('buildingId')(
178
+            <BuildSelect />,
179
+          )}
180
+        </Form.Item>
181
+        <Form.Item>
182
+          {getFieldDecorator('priceLesser')(
183
+            <Input
184
+              prefix={<Icon type="text" style={{ color: 'rgba(0,0,0,.25)' }} />}
185
+              placeholder="价格小"
186
+            />,
187
+          )}
188
+        </Form.Item>
189
+        <Form.Item>
190
+          {getFieldDecorator('priceGreater')(
191
+            <Input
192
+              prefix={<Icon type="text" style={{ color: 'rgba(0,0,0,.25)' }} />}
193
+              placeholder="价格大"
194
+            />,
195
+          )}
196
+        </Form.Item>
197
+        <Form.Item>
198
+            <AuthButton name="admin.taGoods.search" noRight={null}>
199
+              <Button type="primary" htmlType="submit" className={styles.searchBtn}>
200
+                搜索
201
+              </Button>
202
+            </AuthButton>
203
+            <Button style={{ marginLeft: 8 }} onClick={handleReset}>
204
+              重置
205
+            </Button>
206
+        </Form.Item>
207
+      </Form>
208
+      <AuthButton name="admin.taGoods.add.post" noRight={null}>
209
+        <Button type="danger" className={styles.addBtn} onClick={toEditIcons()}>新增</Button>
210
+      </AuthButton>
211
+      <Table rowKey="goodsList" dataSource={data.records} columns={columns} pagination={false} />
212
+      <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '30px' }}>
213
+        <Pagination showQuickJumper defaultCurrent={1} total={data.total} onChange={changePageNum} current={data.current}/>
214
+      </div>
215
+    </>
216
+  )
217
+}
218
+const WrappedHeader = Form.create({ name: 'header' })(header);
219
+
220
+export default WrappedHeader

+ 354
- 0
estateagents-admin-manager/src/pages/news/list/NewsList.jsx 파일 보기

@@ -0,0 +1,354 @@
1
+import React, { useState, useEffect } from 'react';
2
+import { Form, Icon, Input, Button, DatePicker, Select, Modal, message, Card, Row, Col, Pagination, Alert } from 'antd';
3
+import moment from 'moment';
4
+import router from 'umi/router';
5
+import request from '../../../utils/request';
6
+import apis from '../../../services/apis';
7
+import Styles from './style.less';
8
+import styles from '../../style/GoodsList.less';
9
+import NewsTypeSelect from '../../../components/SelectButton/NewTypeSelect'
10
+import BuildSelect from '../../../components/SelectButton/BuildSelect'
11
+import SelectCity from '../../../components/SelectButton/CitySelect'
12
+import Prompt from 'umi/prompt';
13
+
14
+import AuthButton from '@/components/AuthButton';
15
+import EditIcon from '@/components/EditIcon';
16
+import Navigate from '@/components/Navigate';
17
+
18
+
19
+const { Option } = Select;
20
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
21
+const { Meta } = Card;
22
+
23
+const tempDate = [{ code: 's101' }]
24
+
25
+/**
26
+ *
27
+ *
28
+ * @param {*} props
29
+ * @returns
30
+ */
31
+function body(props) {
32
+  const { getFieldDecorator } = props.form
33
+
34
+  // eslint-disable-next-line react-hooks/rules-of-hooks
35
+  const [dataSource, setDataSource] = useState({ records: [] })
36
+  const [page, setPage] = useState(props.location.query.page || 1)
37
+
38
+
39
+  // eslint-disable-next-line react-hooks/rules-of-hooks
40
+  useEffect(() => {
41
+    if (localStorage.getItem("newsPageParams")) {
42
+      props.form.setFieldsValue(JSON.parse(localStorage.getItem("newsPageParams")));
43
+      // const { getFieldDecorator } = JSON.parse(localStorage.getItem("pageParams"))
44
+
45
+      getList(JSON.parse(localStorage.getItem("newsPageParams")))
46
+    } else {
47
+      localStorage.setItem("newsPageParams", JSON.stringify({ pageNum: 1, pageSize: 6 }));
48
+      getList({ pageNum: 1, pageSize: 6 })
49
+    }
50
+  }, [])
51
+
52
+  function getList(params) {
53
+    // 网路请求
54
+    request({ ...apis.news.getList, params: { ...params } }).then(res => {
55
+      setDataSource(res)
56
+    }).catch(err => {
57
+      // eslint-disable-next-line no-unused-expressions
58
+      <Alert
59
+        style={{
60
+          marginBottom: 24,
61
+        }}
62
+        message={err}
63
+        type="error"
64
+        showIcon
65
+      />
66
+    })
67
+  }
68
+
69
+  // 提交事件
70
+  function handleSubmit(e) {
71
+    e.preventDefault();
72
+    props.form.validateFields((err, values) => {
73
+      if (!err) {
74
+        console.log('提交数据: ', values)
75
+        const { startDate } = values
76
+        localStorage.setItem("newsPageParams", (JSON.stringify({ pageNum: 1, pageSize: 6, ...values })));
77
+        getList({ pageNum: 1, pageSize: 6, ...values })
78
+      }
79
+    });
80
+  }
81
+
82
+  // 跳转到编辑资讯列表
83
+  const toEditList = (id) => () => {
84
+    router.push({
85
+      pathname: '/news/list/editNewsList',
86
+      query: {
87
+        id
88
+      },
89
+    });
90
+  }
91
+
92
+
93
+
94
+  /**
95
+   *卡片
96
+   *
97
+   * @returns
98
+   */
99
+  function CartBody(props) {
100
+    const { data } = props
101
+    console.log(data);
102
+    const cancelPage = () => {
103
+      router.push({
104
+        pathname: '/news/list/NewsList',
105
+      });
106
+    }
107
+
108
+    //删除资讯
109
+    const changeNewsListStatus = (row, newsId) => () => {
110
+      Modal.confirm({
111
+        title: '资讯会被删除,小程序端和后台都无法再看到',
112
+        okText: '确认',
113
+        cancelText: '取消',
114
+        onOk() {
115
+          request({ ...apis.news.put, urlData: { id: newsId }, data: { ...row, status: -1 } }).then((data) => {
116
+            message.info('操作成功!')
117
+            getList(JSON.parse(localStorage.getItem("newsPageParams")));
118
+          }).catch((err) => {
119
+            console.log(err)
120
+            message.info(err.msg || err.message)
121
+          })
122
+        }
123
+      });
124
+    }
125
+
126
+    // 跳转到编辑资讯列表
127
+    const toEditList = (newsId) => () => {
128
+      router.push({
129
+        pathname: '/news/list/editNewsList',
130
+        query: {
131
+          newsId,
132
+        },
133
+      });
134
+    }
135
+
136
+    //   置顶
137
+    const topNews = (weightParam, newsId) => () => {
138
+      const weight = Math.abs(weightParam - 1)
139
+      request({ ...apis.news.weight, params: { newsId: newsId, weight } }).then((data) => {
140
+        console.log(data)
141
+        message.info('操作成功!')
142
+        getList(JSON.parse(localStorage.getItem("newsPageParams")))
143
+      }).catch((err) => {
144
+        console.log(err)
145
+        message.info(err.msg || err.message)
146
+      })
147
+    }
148
+
149
+    function cancelRelease(newsId, newsStatus, buildingId, newsTypeId) {
150
+      console.log("newsId" + newsId + "status" + newsStatus);
151
+      if (newsStatus === 1) {
152
+        Modal.confirm({
153
+          title: '资讯会在小程序端隐藏,后台可继续编辑重新发布',
154
+          okText: '确认',
155
+          cancelText: '取消',
156
+          onOk() {
157
+            request({ ...apis.news.cancel, data: { "newsStatus": newsStatus, "buildingId": buildingId, "newsTypeId": newsTypeId }, urlData: { id: newsId }, }).then((data) => {
158
+              message.info('操作成功!')
159
+              getList(JSON.parse(localStorage.getItem("newsPageParams")));
160
+            }).catch((err) => {
161
+              console.log(err)
162
+              message.info(err.msg || err.message)
163
+            })
164
+          },
165
+          onCancel() {
166
+            console.log('Cancel');
167
+          },
168
+        });
169
+      } else if (newsStatus === 0) {
170
+        Modal.confirm({
171
+          title: '确认发布该资讯?',
172
+          okText: '确认',
173
+          cancelText: '取消',
174
+          onOk() {
175
+            request({ ...apis.news.cancel, data: { "newsStatus": newsStatus, "buildingId": buildingId, "newsTypeId": newsTypeId }, urlData: { id: newsId }, }).then((data) => {
176
+              message.info('操作成功!')
177
+              getList(JSON.parse(localStorage.getItem("newsPageParams")));
178
+            }).catch((err) => {
179
+              console.log(err)
180
+              message.info(err.msg || err.message)
181
+            })
182
+          },
183
+          onCancel() {
184
+            console.log('Cancel');
185
+          },
186
+        });
187
+      }
188
+    }
189
+
190
+    return (
191
+      <Card
192
+        // hoverable
193
+        style={{ height: '230px', minWidth: '570px', borderRadius: '12px', margin: '10px', boxShadow: '0px 0px 16px 2px rgba(0,0,0,0.12)', position: 'relative' }}
194
+        cover={<img alt="example" src={data.newsImg} style={{ borderRadius: '12px 0 0 12px', width: '230px', height: '228px' }}></img>}
195
+        bodyStyle={{ padding: '10px 20px' }}
196
+      >
197
+        <AuthButton name="admin.taNews.top" noRight={null}>
198
+          <span style={{ position: 'absolute', right: '83px', top: '16px', fontSize: ' 0.106rem', zIndex: 1, color: '#FF7E48', cursor: 'pointer' }} onClick={topNews(data.weight, data.newsId)}>{data.weight === 1 ? '取消置顶' : '置顶'}</span>
199
+        </AuthButton>
200
+
201
+        <AuthButton name="admin.taNews.id.put" noRight={null}>
202
+          <span style={{ position: 'absolute', right: '10px', top: '16px', fontSize: ' 0.106rem', zIndex: 1, color: '#FF7E48', cursor: 'pointer' }} onClick={toEditList(data.newsId)}>
203
+            <EditIcon text="编辑" color='#ff925c' type="edit"></EditIcon>
204
+          </span>
205
+        </AuthButton>
206
+        <AuthButton name="admin.taNews.publish" noRight={null}>
207
+          {data.newsStatus === 0 ?
208
+            <span style={{ position: 'absolute', left: '250px', bottom: ' 10px', fontSize: ' 0.106rem', color: '#FF7E48', zIndex: 1, cursor: 'pointer' }} onClick={cancelRelease.bind(this, data.newsId, 1, data.buildingId, data.newsType.newsTypeId)}>
209
+              <EditIcon text="取消发布" color='#FF4A4A' type="cancel"></EditIcon>
210
+            </span> :
211
+            <span style={{ position: 'absolute', left: '250px', bottom: ' 10px', fontSize: ' 0.106rem', color: '#FF7E48', zIndex: 1, cursor: 'pointer' }} onClick={cancelRelease.bind(this, data.newsId, 0, data.buildingId, data.newsType.newsTypeId)}>
212
+              <EditIcon text="发布" color='#ff925c' type="publish"></EditIcon>
213
+            </span>
214
+          }
215
+        </AuthButton>
216
+        <AuthButton name="admin.taNews.id.delete" noRight={null}>
217
+          <span style={{ position: 'absolute', right: '20px', bottom: ' 10px', fontSize: ' 0.106rem', color: '#FF7E48', cursor: 'pointer', zIndex: 1 }} onClick={changeNewsListStatus(data, data.newsId)}>
218
+            <EditIcon text="删除" color='#FF4A4A' type="delete"></EditIcon>
219
+          </span>
220
+        </AuthButton>
221
+        <div style={{ position: 'absolute', left: '240px', top: '0px', padding: '16px 10px', width: '64%' }}>
222
+          <p style={{
223
+            fontSize: ' 0.106rem', color: '#333', fontWeight: '600', marginBottom: '10px', overflow: 'hidden',
224
+            textOverflow: 'ellipsis',
225
+            whiteSpace: 'nowrap',
226
+            width: '75%',
227
+          }}><Navigate to={`/news/list/editNewsList?newsId=${data.newsId}`}>{data.newsName}</Navigate></p>
228
+          <p style={{ fontSize: ' 0.106rem', color: '#555', marginBottom: '8px', display: 'flex' }}>
229
+            <span style={{ display: 'inline-block', width: '50%', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>资讯类型:{data.newsType.newsTypeName}</span>
230
+            <span>状态:{data.newsStatus == 0 ? "已发布" : "未发布"}</span>
231
+          </p>
232
+
233
+          <p style={{ fontSize: ' 0.106rem', color: '#555', marginBottom: '8px', display: 'flex', alignItems: 'center' }}>
234
+            <span style={{ display: 'inline-block', width: '50%', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>阅读数量:{data.pvNum}</span>
235
+            <span>转发数量:{data.shareNum}</span>
236
+          </p>
237
+
238
+          <p style={{ fontSize: ' 0.106rem', color: '#555', marginBottom: '8px', display: 'flex', alignItems: 'center' }}>
239
+            {/* <span style={{ display: 'inline-block', width: '50%', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>点赞数量:{data.favorNum}</span> */}
240
+            <span>收藏数量:{data.saveNum}</span>
241
+          </p>
242
+
243
+          <p style={{ fontSize: ' 0.106rem', color: '#999', marginBottom: '8px' }}>发布时间:{moment(data.createDate).format('YYYY-MM-DD HH:mm:ss')}</p>
244
+        </div>
245
+      </Card>
246
+    )
247
+  }
248
+
249
+
250
+  // Change 事件
251
+  function handleSelectChange(e) {
252
+    // eslint-disable-next-line no-console
253
+    console.log(e)
254
+  }
255
+
256
+  // 分页
257
+  function onChange(pageNumber) {
258
+    props.form.validateFields((err, values) => {
259
+      if (!err) {
260
+        localStorage.setItem("newsPageParams", JSON.stringify({ pageNum: pageNumber, pageSize: 6, ...values }));
261
+        // eslint-disable-next-line react-hooks/rules-of-hooks
262
+        getList({ pageNum: pageNumber, pageSize: 6, ...values })
263
+      }
264
+    });
265
+  }
266
+
267
+  //重置搜索
268
+  function handleReset() {
269
+    props.form.resetFields();
270
+    localStorage.setItem("newsPageParams", JSON.stringify({ pageNum: 1, pageSize: 6 }));
271
+    getList({ pageNum: 1, pageSize: 6 })
272
+  }
273
+
274
+  function getDate(value, dateString) {
275
+    // moment(value).format('YYYY-MM-DD HH:mm:ss')
276
+    console.log(value, dateString)
277
+  }
278
+
279
+  return (
280
+    <>
281
+      <Form layout="inline" onSubmit={e => handleSubmit(e, props)}>
282
+
283
+        <Form.Item>
284
+          {getFieldDecorator('cityId')(
285
+            <SelectCity />,
286
+          )}
287
+        </Form.Item>
288
+        <Form.Item>
289
+          {getFieldDecorator('buildingId')(
290
+            <BuildSelect />,
291
+          )}
292
+        </Form.Item>
293
+        <Form.Item>
294
+          {getFieldDecorator('title')(
295
+            <Input
296
+              prefix={<Icon type="text" style={{ color: 'rgba(0,0,0,.25)' }} />}
297
+              placeholder="请输入标题"
298
+            />,
299
+          )}
300
+        </Form.Item>
301
+        <Form.Item>
302
+          {getFieldDecorator('newsTypeId')(
303
+            <NewsTypeSelect />,
304
+          )}
305
+        </Form.Item>
306
+        <Form.Item>
307
+          {getFieldDecorator('newsStatus')(
308
+            <Select style={{ width: '180px' }} placeholder="状态">
309
+              <Option value="0">已发布</Option>
310
+              <Option value="1">未发布</Option>
311
+            </Select>,
312
+          )}
313
+        </Form.Item>
314
+        <Form.Item>
315
+          <AuthButton name="admin.news.search" noRight={null}>
316
+            <Button type="primary" htmlType="submit" >
317
+              搜索
318
+            </Button>
319
+          </AuthButton>
320
+          <Button style={{ marginLeft: 8 }} onClick={handleReset}>
321
+            重置
322
+            </Button>
323
+        </Form.Item>
324
+      </Form>
325
+      <AuthButton name="admin.taNews.post" noRight={null}>
326
+        <Button type="danger" style={{ padding: '0 40px', margin: '20px 0' }} onClick={toEditList()}>
327
+          新增
328
+        </Button>
329
+      </AuthButton>
330
+
331
+      {/* 卡片内容,显示楼盘项目  */}
332
+      <Row>
333
+        {
334
+          dataSource.records.map((item, index) => (
335
+            <Col span={12}>
336
+              <CartBody data={item} key={item.buildingId} />
337
+            </Col>
338
+          ))
339
+        }
340
+      </Row>
341
+      {/* 分页 */}
342
+      <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '30px' }}>
343
+        <Pagination showQuickJumper defaultCurrent={1} total={dataSource.total} pageSize={6} onChange={onChange} current={dataSource.current} />
344
+      </div>
345
+      <Prompt message={location =>
346
+        location.pathname.startsWith("/news/list")
347
+          ? true
348
+          : localStorage.removeItem("newsPageParams")} />
349
+    </>
350
+  );
351
+}
352
+const WrappedBody = Form.create({ name: 'body' })(body);
353
+
354
+export default WrappedBody

+ 398
- 0
estateagents-admin-manager/src/pages/news/list/editNewsList.jsx 파일 보기

@@ -0,0 +1,398 @@
1
+import React, { useState, useEffect } from 'react';
2
+import moment from 'moment';
3
+import router from 'umi/router';
4
+import Prompt from 'umi/prompt';
5
+import { connect } from 'dva';
6
+import { Form, Input, Button, Icon, Select, Tabs, Radio, DatePicker,message } from 'antd';
7
+import { FormattedMessage } from 'umi-plugin-react/locale';
8
+import styles from '../../style/GoodsList.less';
9
+import apis from '../../../services/apis';
10
+import BuildSelect from '../../../components/SelectButton/BuildSelect2'
11
+import NewsTypeSelect from '../../../components/SelectButton/NewTypeSelect'
12
+import  { FieldTypes, createForm } from '../../../components/XForm';
13
+import Wangedit from '../../../components/Wangedit/Wangedit'
14
+import request from '../../../utils/request'
15
+import ImageUploader from '../../../components/XForm/ImageUpload';
16
+import logo from '../../../assets/logo.png';
17
+import yinhao from '../../../assets/yinhao.png'
18
+import touxiang from '../../../assets/touxiang.jpg';
19
+import poster1 from '../../../assets/poster1.png';
20
+import poster2 from '../../../assets/poster2.png';
21
+import xiaochengxu from '../../../assets/xiaochengxu.png'
22
+
23
+const { MonthPicker, RangePicker, WeekPicker } = DatePicker;
24
+const { TextArea } = Input;
25
+
26
+let detailVisible = false;
27
+let urlVisible = false;
28
+
29
+const setExtraData = (data) => {
30
+  detailVisible = data.newsDetailType == '1'
31
+  urlVisible = data.newsDetailType == '0'
32
+}
33
+
34
+const handleFormValueChange = (props, changedValues, allValues) => {
35
+    setExtraData(allValues)
36
+}
37
+
38
+const XForm = createForm({ onValuesChange: handleFormValueChange })
39
+
40
+const cancelPage = () =>{
41
+  router.push({
42
+    pathname: '/news/list/NewsList',
43
+  });
44
+}
45
+
46
+const Basic = (props) => {
47
+  const { data: dynamicData } = props
48
+  const [ changeBuildingId, setChangeBuildingIdData ] = useState('')
49
+
50
+  const handleBuildingChange = (e) => {
51
+    console.log(e)
52
+    setChangeBuildingIdData(e)
53
+  }
54
+
55
+  const fields = [
56
+    {
57
+      label: '意向项目',
58
+      name: 'buildingId',
59
+      render: <BuildSelect onChange={(e => handleBuildingChange(e))}/>,
60
+      value: dynamicData.buildingId,
61
+      rules: [
62
+        {required: true, message: '请选择所属项目'},
63
+      ]
64
+    },
65
+    {
66
+      label: '资讯列表图',
67
+      name: 'newsImg',
68
+      type: FieldTypes.ImageUploader,
69
+      value: dynamicData.newsImg,
70
+      help: '建议图片尺寸:320*240px,比例5:4,格式:jpg,用于资讯列表',
71
+      rules: [
72
+        {required: true, message: '请选择资讯列表'},
73
+      ]
74
+    },
75
+    {
76
+      label: '资讯标题',
77
+      name: 'newsName',
78
+      type: FieldTypes.Text,
79
+      value: dynamicData.newsName,
80
+      rules: [
81
+        {required: true, message: '请输入资讯标题'},
82
+      ]
83
+    },
84
+    {
85
+      label: '资讯类型',
86
+      name: 'newsTypeId',
87
+      render: <NewsTypeSelect buildingId={changeBuildingId || dynamicData.buildingId}/>,
88
+      value: dynamicData.newsTypeId,
89
+      rules: [
90
+        {required: true, message: '请选择资讯类型'},
91
+      ]
92
+    },
93
+    {
94
+      label: '资讯详情',
95
+      name: 'newsDetailType',
96
+      render: <Radio.Group> 
97
+              <Radio value={1}>自定义</Radio>
98
+              <Radio value={0}>公众号链接</Radio>
99
+              </Radio.Group>,
100
+      value: dynamicData.newsDetailType - 0,
101
+      rules: [
102
+        {required: true, message: '请选择资讯类型'},
103
+      ]
104
+    },
105
+    {
106
+      label: '详情内容',
107
+      name: 'newsDetail',
108
+      render: <Wangedit />,
109
+      hidden: () => !detailVisible,
110
+      value: dynamicData.newsDetail,
111
+      rules: [
112
+        {required: true, message: '请输入详情内容'},
113
+      ]
114
+    },
115
+    {
116
+      label: '公众号链接',
117
+      name: 'newsDetail',
118
+      type: FieldTypes.Text,
119
+      hidden: () => !urlVisible,
120
+      value: dynamicData.newsDetail,
121
+      help: "只能填写同一主体公众号的文章链接",
122
+      rules: [
123
+        {required: true, message: '请输入公众号链接'},
124
+      ]
125
+    },
126
+  ]
127
+
128
+  const handleSubmit = val => { 
129
+    console.log(dynamicData,'12312345')
130
+    let {...submitValue} = val
131
+    
132
+    if(dynamicData.newsId){
133
+      submitValue.newsId = dynamicData.newsId
134
+      request({ ...apis.news.put, urlData: {id: dynamicData.newsId}, data: { ...submitValue },}).then((data) => {
135
+        // cancelPage();
136
+        message.info("保存成功")
137
+        console.log(data,'data1')
138
+      }).catch((err) => {
139
+        message.info(err.msg || err.message)
140
+      })
141
+    }else{
142
+      request({ ...apis.news.post, data: { ...submitValue },}).then((data) => {
143
+        // cancelPage();
144
+        message.info("保存成功")
145
+        router.push({
146
+          pathname: '/news/list/editNewsList',
147
+          query: {
148
+            newsId:data.newsId
149
+          },
150
+        });
151
+        console.log(data,'data2')
152
+      }).catch((err) => {
153
+        message.info(err.msg || err.message)
154
+      })
155
+    }
156
+  }
157
+
158
+  const cancelPage = () =>{
159
+    router.push({
160
+      pathname: '/news/list/NewsList',
161
+    });
162
+  }
163
+  
164
+  return <XForm onSubmit={handleSubmit} onCancel={cancelPage}  fields={fields}></XForm>
165
+}
166
+
167
+/**
168
+ *
169
+ *
170
+ * @param {*} props
171
+ * @returns
172
+ */
173
+ const Edit = (props) => {
174
+  const [ tab, changeTab ] = useState('basic')
175
+  const newsId = props.location.query.newsId
176
+  const [ dynamicData, setDynamicData ] = useState({})
177
+
178
+    useEffect(() => {
179
+      if(newsId){
180
+        getDynamicData(newsId);
181
+      }
182
+    },[newsId])
183
+
184
+  // 查询列表
185
+  const getDynamicData = (newsId) => {
186
+    request({ ...apis.news.get, urlData: { id: newsId },}).then((data) => {
187
+      setDynamicData(data)
188
+      setExtraData(data)
189
+      // detailVisible = data.newsDetailType == '1'
190
+      // urlVisible = data.newsDetailType == '0'
191
+    }).catch((err) => {
192
+      console.log(err)
193
+      message.info(err.msg || err.message)
194
+    })
195
+    }
196
+
197
+  const Poster = (props) => {
198
+    const [inputValue, changeInput] = useState('')
199
+    const [textAreaValue, changeTextArea] = useState('')
200
+    const [imgValue, changeImg] = useState('')
201
+    const [posterId, setPosterId] = useState('')
202
+
203
+    if(newsId){
204
+      useEffect(() => {
205
+        request({ ...apis.activity.poster, params: {targetId: newsId,targetType: 'news'} }).then((data) => {
206
+          console.log(data,"2222")
207
+          if(data.length > 0){
208
+            setPosterId(data[0].posterId)
209
+            changeImg(data[0].posterImg)
210
+            changeTextArea(data[0].posterDescription)
211
+            changeInput(data[0].posterTitle)
212
+          }
213
+        }).catch((err) => {
214
+          message.info(err.msg || err.message)
215
+        })
216
+        getMiniappName()
217
+      }, [])
218
+    }else{
219
+      getMiniappName()
220
+    }
221
+
222
+    // 获取小程序名称
223
+  const [miniappName, setMiniappName] = useState('')
224
+  function getMiniappName() {
225
+    request({ ...apis.building.getMiniappName }).then(res => {
226
+      setMiniappName(res)
227
+    })
228
+  }
229
+    const submitPoster  = () => {
230
+       if(newsId){
231
+        if(posterId){
232
+          request({ ...apis.activity.updatePoster, urlData: {id: posterId}, data: {targetId: newsId,targetType: 'news',posterImg: imgValue,posterTitle: inputValue,posterDescription: textAreaValue},}).then((data) => {
233
+            message.info("保存成功")
234
+          }).catch((err) => {
235
+            message.info(err.msg || err.message)
236
+          })
237
+         }else{
238
+          request({ ...apis.activity.addPoster, data: {targetId: newsId,targetType: 'news',posterImg: imgValue,posterTitle: inputValue,posterDescription: textAreaValue},}).then((data) => {
239
+            setPosterId(data.posterId)
240
+            message.info("保存成功")
241
+          }).catch((err) => {
242
+            message.info(err.msg || err.message)
243
+          })
244
+         }
245
+       }else{
246
+        message.warn("请先保存基本信息数据")
247
+       }
248
+    }
249
+
250
+    return <div>
251
+      <div style={{ display: 'flex' }}>
252
+        <div style={{ width: '420px', height: '900px', display: 'inline-block', marginTop: '30px' }}>
253
+          <div style={{ width: '375px', height: '700px', backgroundColor: '#fff', boxShadow: '0px 0px 16px 6px rgba(0,0,0,0.15)', position: 'relative', margin: '0 auto' }}>
254
+            <img style={{ width: '100%', height: '300px' }} src={imgValue ? imgValue : poster1} alt="" />
255
+            <div style={{ display: 'flex', alignItems: 'center', marginTop: '-24px' }}>
256
+              <img style={{ width: '70px', height: '70px', border: '4px solid #fff', borderRadius: '35px', marginLeft: '16px' }} src={touxiang} alt="" />
257
+              <span style={{ color: '#222', fontWeight: '600', margin: '24px 10px 0 14px', fontSize: '17px' }}>喵喵</span>
258
+              <span style={{ color: '#999', marginTop: '25px', fontSize: '17px' }}>邀您阅读</span>
259
+              <span style={{ color: '#999', margin: '25px 0 0 60px', fontSize: '17px' }}>2019.09.21</span>
260
+            </div>
261
+            <p style={{
262
+              margin: '10px 20px', fontSize: '20px', color: '#222', fontWeight: '600',
263
+              display: '-webkit-box', lineClamp: '3', height: '60px',
264
+              WebkitLineClamp: '2',
265
+              WebkitBoxOrient: 'vertical',
266
+              overflow: 'hidden',
267
+              textOverflow: 'ellipsis'
268
+            }}>{inputValue ? inputValue : '海报标题'}</p>
269
+
270
+            <img src={yinhao} style={{ width: '30px', marginLeft: '20px' }} alt="" />
271
+            <p style={{
272
+              margin: '16px 20px 28px 20px', fontSize: '17px', color: '#999',
273
+              display: '-webkit-box', lineClamp: '3', height: '72px',
274
+              WebkitLineClamp: '3',
275
+              WebkitBoxOrient: 'vertical',
276
+              overflow: 'hidden',
277
+              textOverflow: 'ellipsis'
278
+            }}>{textAreaValue ? textAreaValue : '海报描述'}</p>
279
+               <div style={{ backgroundColor: '#f1f1f1', padding: '22px 30px', boxShadow: '0px 6px 12px -4px #dcdcdc',position:'relative' }}>
280
+            <p style={{margin:'0',fontSize:'18px',color:'#888'}}>长按识别小程序码</p>
281
+            <p style={{margin:'0',fontSize:'18px',color:'#888'}}>进入资讯查看详情</p>
282
+            <img style={{ width: '80px',position: 'absolute',right:'30px',top:'10px' }} src={xiaochengxu} alt="" />
283
+          </div>
284
+      
285
+          </div>
286
+          <p style={{ textAlign: 'center', fontSize: '19px', color: '#666', marginTop: '30px' }}>海报模板</p>
287
+        </div>
288
+
289
+        <div >
290
+          <div style={{ display: 'flex', width: '100%', margin: '60px 0' }}>
291
+            <p style={{ minWidth: '200px', color: '#222', textAlign: 'right', margin: '0 30px 0 0' }}>资讯海报图</p>
292
+            <ImageUploader value={imgValue} onChange={e => changeImg(e)} />
293
+          </div>
294
+          <p style={{ fontSize: '0.5vw', color: '#A9A9A9', marginLeft: '230px', marginBottom: '30px'}}>建议图片尺寸:640*670px,比例64:67,格式:jpg,用于资讯海报</p>
295
+          <div style={{ display: 'flex', alignItems: 'center', width: '100%', marginBottom: '60px' }}>
296
+            <p style={{ minWidth: '200px', color: '#222', textAlign: 'right', margin: '0 30px 0 0' }}>海报标题</p>
297
+            <Input style={{ width: '20vw' }} value={inputValue} placeholder="请输入海报标题" onChange={e => changeInput(e.target.value)} />
298
+          </div>
299
+          <div style={{ display: 'flex', margin: '10px 0 40px 0', width: '100%' }}>
300
+            <p style={{ minWidth: '200px', color: '#222', textAlign: 'right', margin: '0 30px 0 0' }}>海报描述</p>
301
+            <TextArea rows={5} maxLength={1024} value={textAreaValue} onChange={e => changeTextArea(e.target.value)} />
302
+          </div>
303
+
304
+        </div>
305
+      </div>
306
+      <Button type="primary" onClick={submitPoster} style={{ margin: '40px 40px 40px 30vw' }}> 确定</Button>
307
+      <Button onClick={cancelPage}>取消</Button>
308
+    </div>
309
+
310
+  }
311
+ 
312
+  const Share = (props) => {
313
+    const [inputValue, changeInput] = useState('')
314
+    const [imgValue, changeImg] = useState('')
315
+    const [shareContentId, setShareContentId] = useState('')
316
+    
317
+    if(newsId){
318
+      useEffect(() => {
319
+        request({ ...apis.activity.shareContent, params: {targetId: newsId,targetType: 'news'},}).then((data) => {
320
+          console.log(data,"2222")
321
+          if(data.length > 0){
322
+            setShareContentId(data[0].shareContentId)
323
+            changeImg(data[0].shareContentImg)
324
+            changeInput(data[0].shareContentTitle)
325
+          }
326
+        }).catch((err) => {
327
+          message.info(err.msg || err.message)
328
+        })
329
+      }, [])
330
+    }
331
+
332
+    const submitShare = () => {
333
+      if(newsId){
334
+        if(shareContentId){
335
+          request({ ...apis.activity.updateShareContent, urlData: {id: shareContentId},data: {targetId: newsId,shareContentType: 'news',shareContentImg: imgValue,shareContentTitle: inputValue},}).then((data) => {
336
+            message.info("保存成功")
337
+          }).catch((err) => {
338
+            message.info(err.msg || err.message)
339
+          })
340
+         }else{
341
+          request({ ...apis.activity.addShareContent, data: {targetId: newsId,shareContentType: 'news',shareContentImg: imgValue,shareContentTitle: inputValue},}).then((data) => {
342
+            setShareContentId(data.shareContentId)
343
+            message.info("保存成功")
344
+          }).catch((err) => {
345
+            message.info(err.msg || err.message)
346
+          })
347
+         }
348
+       }else{
349
+        message.warn("请先保存基本信息数据")
350
+       }
351
+    }
352
+
353
+    return <div style={{ padding: '20px' }}>
354
+      <div style={{ display: 'flex', margin: '10px 0 40px 0', width: '100%' }}>
355
+        <p style={{ minWidth: '200px', color: '#222', textAlign: 'right', margin: '0 30px 0 0' }}>分享模板</p>
356
+        <div>
357
+          {/* <p style={{ display: 'flex', alignItems: 'center', fontSize: '14px', color: '#999', margin: '0', lineHeight: '0' }}><img src={logo} style={{ width: '22px', marginRight: '10px' }} />南京云致</p> */}
358
+          <p style={{ fontSize: '16px', color: '#222', fontWeight: '600', margin: '0' }}>{inputValue ? inputValue : '精准获客平台'}</p>
359
+          <img style={{ width: '200px', height: '160px' }} src={imgValue ? imgValue : poster2} alt="" />
360
+        </div>
361
+      </div>
362
+      <div style={{ display: 'flex', alignItems: 'center', width: '100%' }}>
363
+        <p style={{ minWidth: '200px', color: '#222', textAlign: 'right', margin: '0 30px 0 0' }}>分享标题</p>
364
+        <Input placeholder="请输入分享标题" value={inputValue} onChange={e => changeInput(e.target.value)} />
365
+      </div>
366
+      <div style={{ display: 'flex', width: '100%', marginTop: '40px' }}>
367
+        <p style={{ minWidth: '200px', color: '#222', textAlign: 'right', margin: '0 30px 0 0' }}>资讯分享好友图</p>
368
+        <ImageUploader value={imgValue} onChange={e => changeImg(e)} />
369
+      </div>
370
+      <p style={{ fontSize: '0.5vw', color: '#A9A9A9', marginLeft: '230px', marginTop: '20px' }}>建议图片尺寸:750*600px,比例5:4,格式:jpg,用于资讯分享好友</p>
371
+      <Button type="primary" htmlType="submit" onClick={submitShare} style={{ margin: '40px 40px 40px 220px' }}> 确定</Button>
372
+      <Button onClick={cancelPage}>取消</Button>
373
+    </div>
374
+  }
375
+
376
+  return (
377
+    <div>
378
+      <div>
379
+        <Radio.Group value={tab} buttonStyle="solid" onChange={e => changeTab(e.target.value)}>
380
+          <Radio.Button value="basic">基本信息</Radio.Button>
381
+          <Radio.Button value="poster">海报图片</Radio.Button>
382
+          <Radio.Button value="share">分享设置</Radio.Button>
383
+        </Radio.Group>
384
+      </div>
385
+      <div>
386
+        { tab === 'basic' && <Basic data={dynamicData} /> }
387
+        { tab === 'poster' && <Poster /> }
388
+        { tab === 'share' && <Share /> }
389
+      </div>
390
+      <Prompt message={location =>
391
+                          location.pathname.startsWith("/news/list")
392
+                            ? true
393
+                            : localStorage.removeItem("newsPageParams")} />
394
+    </div>
395
+  );
396
+ }
397
+
398
+export default connect(s => ({ user: s.user.currentUser }))(Edit)