Bladeren bron

Merge branch 'master' of http://git.ycjcjy.com/xiangsong/xs-manage

Your Name 4 jaren geleden
bovenliggende
commit
8990f436bb
68 gewijzigde bestanden met toevoegingen van 2564 en 278 verwijderingen
  1. 1
    1
      config/defaultSettings.js
  2. 16
    6
      config/routes.js
  3. 1
    1
      package.json
  4. 56
    0
      src/components/CommunitySelect/index.jsx
  5. 44
    0
      src/components/Wangedit/Preview.jsx
  6. 27
    0
      src/components/Wangedit/PreviewMenu.js
  7. 76
    66
      src/components/Wangedit/Wangedit.jsx
  8. 0
    1
      src/components/XForm/WrapperForm.jsx
  9. 9
    0
      src/global.less
  10. 2
    2
      src/models/user.js
  11. 9
    1
      src/pages/activity/SignList.jsx
  12. 1
    1
      src/pages/customer/customerlist/components/integralRecord.jsx
  13. 17
    2
      src/pages/customer/personlist/index.jsx
  14. 15
    0
      src/pages/dashboard/components/ABPart.jsx
  15. 35
    0
      src/pages/dashboard/components/BuildingStatic.jsx
  16. 69
    0
      src/pages/dashboard/components/CommAlert.jsx
  17. 74
    0
      src/pages/dashboard/components/ScrollAlert.jsx
  18. 89
    0
      src/pages/dashboard/components/ShortCut.jsx
  19. 49
    0
      src/pages/dashboard/index.jsx
  20. 14
    1
      src/pages/integralMall/exchangeRecords.jsx
  21. 1
    1
      src/pages/mpSetting/components/MainSeting.jsx
  22. 4
    2
      src/pages/mpSetting/components/TemplateItem.jsx
  23. 1
    1
      src/pages/mpSetting/components/TemplateSetting.jsx
  24. 13
    10
      src/pages/property/bill/edit/components/AddOn.jsx
  25. 72
    21
      src/pages/property/bill/edit/index.jsx
  26. 6
    1
      src/pages/property/bill/info/Add.jsx
  27. 5
    4
      src/pages/property/bill/info/components/AddOne.jsx
  28. 16
    12
      src/pages/property/bill/info/components/Edit.jsx
  29. 11
    12
      src/pages/property/bill/info/index.jsx
  30. 73
    36
      src/pages/property/bill/list/index.jsx
  31. 77
    5
      src/pages/property/bill/order/index.jsx
  32. 2
    0
      src/pages/property/building/BatchImport.jsx
  33. 85
    0
      src/pages/property/building/components/Building.jsx
  34. 97
    0
      src/pages/property/building/components/BuildingLevelCell.jsx
  35. 114
    0
      src/pages/property/building/components/BuildingLevelRow.jsx
  36. 96
    0
      src/pages/property/building/components/BuildingRoomCell.jsx
  37. 236
    0
      src/pages/property/building/components/BuildingUnit.jsx
  38. 107
    0
      src/pages/property/building/components/BuildingUnitCell.jsx
  39. 1
    1
      src/pages/property/building/components/NodeLabel.jsx
  40. 104
    0
      src/pages/property/building/list.jsx
  41. 123
    0
      src/pages/property/community/index.jsx
  42. 135
    0
      src/pages/property/contact/PublicServ.jsx
  43. 8
    9
      src/pages/property/contact/components/Editor.jsx
  44. 30
    8
      src/pages/property/contact/index.jsx
  45. 15
    3
      src/pages/property/lifeConsultant/index.jsx
  46. 3
    2
      src/pages/property/message/event/components/Preview.jsx
  47. 21
    3
      src/pages/property/news/index.jsx
  48. 14
    1
      src/pages/property/notice/Edit.jsx
  49. 68
    14
      src/pages/property/notice/index.jsx
  50. 19
    11
      src/pages/property/proprietor/Add.jsx
  51. 70
    4
      src/pages/property/proprietor/Audit.jsx
  52. 26
    2
      src/pages/property/proprietor/BatchImport.jsx
  53. 1
    1
      src/pages/property/proprietor/Detail.jsx
  54. 94
    8
      src/pages/property/proprietor/index.jsx
  55. 25
    9
      src/pages/property/ticket/index.jsx
  56. 5
    3
      src/pages/property/utils/hooks/useRoomSelect.js
  57. 30
    7
      src/pages/staff/list/editStaff.jsx
  58. 26
    0
      src/pages/user/login/components/Login/CaptchaImg.jsx
  59. 5
    2
      src/pages/user/login/components/Login/LoginItem.jsx
  60. 2
    2
      src/pages/user/login/components/Login/index.jsx
  61. 13
    0
      src/pages/user/login/components/Login/map.jsx
  62. 1
    0
      src/pages/user/login/index.jsx
  63. 19
    0
      src/services/apis.js
  64. 21
    0
      src/services/buildingOwnerInfo_api.js
  65. 28
    0
      src/services/community_api.js
  66. 25
    0
      src/services/dashboard_api.js
  67. 1
    1
      src/utils/constant.js
  68. 11
    0
      src/utils/utils.js

+ 1
- 1
config/defaultSettings.js Bestand weergeven

@@ -12,5 +12,5 @@ export default {
12 12
   },
13 13
   title: '远道荟',
14 14
   pwa: false,
15
-  iconfontUrl: '',
15
+  iconfontUrl: ''
16 16
 };

+ 16
- 6
config/routes.js Bestand weergeven

@@ -25,7 +25,7 @@ export default [
25 25
           {
26 26
             path: '/index',
27 27
             name: '首页',
28
-            component: './Index',
28
+            component: './dashboard',
29 29
           },
30 30
           // {
31 31
           //   path: '/',
@@ -70,10 +70,15 @@ export default [
70 70
             name: '物业管理',
71 71
             component: '../layouts/BlankLayout',
72 72
             routes: [
73
+              {
74
+                path: 'community',
75
+                name: '社区管理',
76
+                component: './property/community'
77
+              },
73 78
               {
74 79
                 path: 'buildingInfo',
75 80
                 name: '楼栋管理',
76
-                component: './property/building'
81
+                component: './property/building/list'
77 82
               },
78 83
               {
79 84
                 path: 'buildingInfo/importExcel',
@@ -142,20 +147,25 @@ export default [
142 147
                 component: './property/news/Edit',
143 148
                 hideInMenu: true,
144 149
               },
150
+              {
151
+                path: 'public-service',
152
+                name: '公共服务',
153
+                component: './property/contact/PublicServ'
154
+              },
145 155
               {
146 156
                 path: 'bill/management',
147
-                name: '收费组管理',
157
+                name: '收费管理',
148 158
                 component: './property/bill/list',
149 159
               },
150 160
               {
151 161
                 path: 'bill/management/add',
152
-                name: '新增收费',
162
+                name: '新增收费项目',
153 163
                 component: './property/bill/edit',
154 164
                 hideInMenu: true,
155 165
               },
156 166
               {
157 167
                 path: 'bill/management/info',
158
-                name: '收费详情',
168
+                name: '收费详情',
159 169
                 component: './property/bill/info',
160 170
                 hideInMenu: true,
161 171
               },
@@ -200,7 +210,7 @@ export default [
200 210
               },
201 211
               {
202 212
                 path: 'contact',
203
-                name: '联系方式',
213
+                name: '联系物业',
204 214
                 component: './property/contact'
205 215
               },
206 216
               {

+ 1
- 1
package.json Bestand weergeven

@@ -72,7 +72,7 @@
72 72
     "umi-plugin-pro-block": "^1.3.6",
73 73
     "umi-plugin-react": "^1.15.8",
74 74
     "umi-request": "^1.0.8",
75
-    "wangeditor": "^3.1.1"
75
+    "wangeditor": "^4.6.2"
76 76
   },
77 77
   "devDependencies": {
78 78
     "@ant-design/colors": "^3.1.0",

+ 56
- 0
src/components/CommunitySelect/index.jsx Bestand weergeven

@@ -0,0 +1,56 @@
1
+import React, { useEffect, useState, useRef } from 'react'
2
+import { connect } from 'dva'
3
+import { Select } from 'antd'
4
+
5
+const CommunitySelect = props => {
6
+  const [value, setValue] = useState()
7
+  const inited = useRef(false)
8
+
9
+  const { communityList, user, dispatch, autoInited, ...selectProps } = props
10
+
11
+  const dataList = ((user || {}).isAdmin ? communityList : (user || {}).communityList) || []
12
+
13
+  const handleChange = val => {
14
+    if (props.onChange) {
15
+      props.onChange(val)
16
+    } else {
17
+      setValue(val)
18
+    }
19
+  }
20
+
21
+  useEffect(() => {
22
+    if (!user || !user.userId) {
23
+      return
24
+    }
25
+
26
+    // 初始化逻辑
27
+    if (!inited.current) {
28
+      // 如果有默认值, 则使用默认值
29
+      if (props.value) {
30
+        setValue(props.value)
31
+        inited.current = true
32
+      } else if (autoInited) {
33
+        // 如果没有默认值, 但是需要设置默认值
34
+        // 那么默认使用第一个
35
+        const first = (dataList[0] || {}).id
36
+        if (first) {
37
+          handleChange(props.mode === 'multiple' ? [first] : first)
38
+        }
39
+
40
+        inited.current = true
41
+      }
42
+    } else {
43
+      setValue(props.value)
44
+    }
45
+  }, [user, autoInited, dataList, props.value])
46
+
47
+  return (
48
+    <Select {...selectProps} value={value} onChange={handleChange}>
49
+      {
50
+        dataList.map(community => (<Select.Option key={community.id} value={community.id}>{community.name}</Select.Option>))
51
+      }
52
+    </Select>
53
+  )
54
+}
55
+
56
+export default connect(s => ({ communityList: (s.user || {}).communityList, user: (s.user || {}).currentUser }))(CommunitySelect)

+ 44
- 0
src/components/Wangedit/Preview.jsx Bestand weergeven

@@ -0,0 +1,44 @@
1
+import React, { useEffect, useRef } from 'react'
2
+import { Modal } from 'antd'
3
+import PreviewMenu from './PreviewMenu'
4
+
5
+export default props => {
6
+  const ref = useRef()
7
+
8
+  useEffect(() => {
9
+    let t = null
10
+    if (props.visible) {
11
+      // 防止 postMessage 的时候 iframe 内容还没有加载完成
12
+      t = setInterval(() => {
13
+        console.log('----postMessage----->', ref.current)
14
+        // window.preViewFrame.window.postMessage(props.html, '*')
15
+        if (ref.current) {
16
+          ref.current.contentWindow.postMessage(props.html, '*')
17
+        }
18
+      }, 800)
19
+    }
20
+
21
+    return () => t && clearInterval(t)
22
+  }, [props.visible, props.html])
23
+
24
+  return (
25
+    <Modal
26
+      visible={props.visible}
27
+      wrapClassName="editor-preivew-modal-content"
28
+      width={props.width}
29
+      bodyStyle={props.style}
30
+      footer={null}
31
+      closable={false}
32
+      title={null}
33
+      onCancel={props.onCancel}
34
+      >
35
+      <iframe
36
+        ref={ref}
37
+        style={{width: '100%', height: '100%'}}
38
+        src={`${window.location.origin}/preview-html/index.html`}
39
+        frameBorder={0}
40
+        name="preViewFrame"
41
+      ></iframe>
42
+    </Modal>
43
+  )
44
+}

+ 27
- 0
src/components/Wangedit/PreviewMenu.js Bestand weergeven

@@ -0,0 +1,27 @@
1
+import E from 'wangeditor'
2
+
3
+const { $, BtnMenu } = E
4
+
5
+class PreViewMenu extends BtnMenu {
6
+  constructor(editor) {
7
+    // data-title属性表示当鼠标悬停在该按钮上时提示该按钮的功能简述
8
+      const $elem = E.$(
9
+          `<div class="w-e-menu" data-title="预览">
10
+            <i>预览</i>
11
+          </div>`
12
+      )
13
+      super($elem, editor)
14
+      this.editor = editor
15
+      // <i class="w-e-icon-fullscreen"></i>
16
+  }
17
+
18
+  static preview() {}
19
+
20
+  clickHandler() {
21
+    PreViewMenu.preview(this.editor.txt.html())
22
+  }
23
+
24
+  tryChangeActive(){}
25
+}
26
+
27
+export default PreViewMenu

+ 76
- 66
src/components/Wangedit/Wangedit.jsx Bestand weergeven

@@ -1,50 +1,58 @@
1
-import React from 'react';
1
+import React, { useState, useRef, useEffect, useCallback } from 'react';
2 2
 import E from 'wangeditor';
3
+import PreviewMenu from './PreviewMenu'
4
+import Preview from './Preview'
3 5
 import { fetch, apis } from '../../utils/request';
4 6
 
5
-/**
6
- * @param {*} props
7
- * @returns
8
- */
9
-class Wangedit extends React.Component {
10
-  constructor(props, context) {
11
-    super(props, context);
12
-    this.state = {
13
-      html: undefined,
14
-      contenteditable: props.contenteditable == false ? false : true
15
-    }
16
-    this.editor = undefined;
17
-  }
18
-
19
-  render() {
20
-    return (
21
-      <div ref="editorElem" style={{ textAlign: 'left' }}>
22
-      </div>
23
-    );
24
-  }
25
-
26
-  componentDidMount() {
27
-    const elem = this.refs.editorElem
28
-    this.editor = new E(elem)
29
-    // 使用 onchange 函数监听内容的变化
30
-    this.editor.customConfig.onchange = html => {
31
-      this.setState({ html })
32
-
33
-      if (typeof this.props.onChange === 'function') {
34
-        this.props.onChange(html)
7
+export default props => {
8
+  const ref = useRef()
9
+  const editorRef = useRef()
10
+  const [preview, setPreview] = useState(false)
11
+  const [content, setContent] = useState()
12
+
13
+  // wangeditor 有bug, 初始先触发 onchange
14
+  const firstChanged = useRef(false)
15
+
16
+  const initEditor = useCallback(() => {
17
+    const editor = new E(ref.current)
18
+    editorRef.current = editor
19
+    
20
+    // 取消自动 focus
21
+    editor.config.focus = false
22
+
23
+    // 触发 change
24
+    editor.config.onchange = html => {
25
+      // 规避 bug
26
+      if (!firstChanged.current) {
27
+        firstChanged.current = true
28
+        return
29
+      }
30
+
31
+      setContent(html)
32
+
33
+      if (typeof props.onChange === 'function') {
34
+        props.onChange(html)
35 35
       }
36 36
     }
37
-    this.editor.customConfig.zIndex = 100
38
-    this.editor.customConfig.uploadImgMaxLength = 1
39
-    this.editor.customConfig.customUploadImg = function (files, insert) {
37
+
38
+    editor.config.zIndex = 100
39
+
40
+    // 自定义图片上传
41
+    editor.config.uploadImgMaxLength = 1
42
+    editor.config.customUploadImg = function (files, insert) {
40 43
       if (!files.length) return
41 44
       
42 45
       const data = new FormData()
43 46
       data.append('file', files[0])
44
-
45 47
       fetch(apis.image.upload)({data}).then(insert)
46 48
     }
47
-    this.editor.customConfig.menus = [
49
+
50
+    // 扩展预览按钮
51
+    editor.menus.extend('previewMenu', PreviewMenu)
52
+    PreviewMenu.preview = (html) => setPreview(true)
53
+
54
+    // 配置菜单
55
+    editor.config.menus = [
48 56
       'head',  // 标题
49 57
       'bold',  // 粗体
50 58
       'fontSize',  // 字号
@@ -59,12 +67,13 @@ class Wangedit extends React.Component {
59 67
       'quote',  // 引用
60 68
       'image',  // 插入图片
61 69
       'undo',  // 撤销
62
-      'redo'  // 重复
70
+      'redo',  // 重复
71
+      'previewMenu'
63 72
     ]
64
-    
73
+
65 74
     // 过滤 word 字符
66
-    this.editor.customConfig.pasteFilterStyle = false
67
-    this.editor.customConfig.pasteTextHandle = function(content) {
75
+    editor.config.pasteFilterStyle = false
76
+    editor.config.pasteTextHandle = content => {
68 77
       const regs = [
69 78
         /<!--\[if [\s\S]*?endif\]-->/ig,
70 79
         /<[a-zA-Z0-9]+\:[^>]+>[^>]*<\/[a-zA-Z0-9]+\:[^>]+>/ig,
@@ -78,32 +87,33 @@ class Wangedit extends React.Component {
78 87
       }, content)
79 88
     }
80 89
 
81
-    this.editor.create()
82
-    this.editor.$textElem.attr('contenteditable',this.state.contenteditable);
83
-    this.editor.customConfig.uploadImgShowBase64 = true
84
-    this.editor.txt.html(this.props.value)
85
-  }
90
+    editor.create()
91
+    editor.$textElem.attr('contenteditable', props.contenteditable !== false)
86 92
 
87
-  componentDidUpdate(props, state) {
88
-    if (this.props.value && !state.html) {
89
-      if (this.editor) {
90
-        this.editor.txt.html(this.props.value)
91
-      }
92
-    }
93
-  }
94
-
95
-  /**
96
-   *增加这个 shouldComponentUpdate 生命函数
97
-    处理自动聚焦到富文本上
98
-   *
99
-   * @param {*} nextProps
100
-   * @returns
101
-   * @memberof Wangedit
102
-   */
103
-  shouldComponentUpdate(nextProps) {
104
-    return nextProps.value !== this.editor.txt.html()
105
-  }
106
-}
93
+    return () => editor.destroy()
94
+  }, [props.contenteditable])
107 95
 
108
-export default Wangedit
96
+  useEffect(() => {
97
+    initEditor()
98
+  }, [])
99
+  
100
+  useEffect(() => {
101
+    if (props.value !== content && editorRef.current) {
102
+      setContent(props.value)
103
+      editorRef.current.txt.html(props.value)
104
+    }
105
+  }, [props.value])
109 106
 
107
+  return (
108
+    <>
109
+      <div ref={ref} style={{ textAlign: 'left' }} />
110
+      <Preview
111
+        width={426}
112
+        style={{width: '426px', height: '863px', margin: 0, padding: 0}}
113
+        visible={preview}
114
+        html={props.value}
115
+        onCancel={() => setPreview(false)}
116
+      />
117
+    </>
118
+  )
119
+}

+ 0
- 1
src/components/XForm/WrapperForm.jsx Bestand weergeven

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

+ 9
- 0
src/global.less Bestand weergeven

@@ -196,6 +196,15 @@ ol {
196 196
     border-top:none;
197 197
   }
198 198
 }
199
+
200
+.editor-preivew-modal-content {
201
+  .ant-modal-content {
202
+    background: transparent !important;
203
+    box-shadow: none;
204
+  }
205
+}
206
+
207
+
199 208
 :global {
200 209
   .ant-layout {
201 210
     min-height: 100vh;

+ 2
- 2
src/models/user.js Bestand weergeven

@@ -30,13 +30,13 @@ const UserModel = {
30 30
   },
31 31
   reducers: {
32 32
     saveCurrentUser(state, { payload }) {
33
-      const { taUser = {} , menuList = [], buttonList = [] } = payload || {}
33
+      const { taUser = {} , menuList = [], buttonList = [], ...others } = payload || {}
34 34
       const currentUser = { ...taUser, roles: (taUser.roles || []).map(x => x.roleId) }
35 35
 
36 36
       setAllBtnAuth(buttonList)
37 37
       setUserBtnAuth(currentUser.buttons)
38 38
 
39
-      return { ...state, currentUser, menuList, buttonList };
39
+      return { ...state, currentUser, menuList, buttonList, ...others };
40 40
     },
41 41
     changeNotifyCount(
42 42
       state = {

+ 9
- 1
src/pages/activity/SignList.jsx Bestand weergeven

@@ -68,6 +68,8 @@ const columns = [
68 68
 
69 69
 const header = props => {
70 70
   const [data, setData] = useState({ list: {} })
71
+  const [actInfo, setActInfo] = useState()
72
+
71 73
   //   const [page, changePage] = useState({})
72 74
   // 存入导入数据的值
73 75
   const { getFieldDecorator, getFieldsValue } = props.form
@@ -75,6 +77,11 @@ const header = props => {
75 77
   useEffect(() => {
76 78
     // eslint-disable-next-line no-use-before-define
77 79
     getSignList({ pageNum: 1, pageSize: 10, dynamicId: props.location.query.dynamicId });
80
+    //
81
+    
82
+    request({ ...apis.activity.details, params: { dynamicId: props.location.query.dynamicId } }).then(res => {
83
+      setActInfo(res)
84
+    })
78 85
   }, [])
79 86
 
80 87
   // 查询列表
@@ -117,11 +124,12 @@ const header = props => {
117 124
         if (!data) {
118 125
           return
119 126
         }
127
+
120 128
         const url = window.URL.createObjectURL(new Blob([data]))
121 129
         const link = document.createElement('a')
122 130
         link.style.display = 'none'
123 131
         link.href = url
124
-        link.setAttribute('download', '报名列表.xlsx')
132
+        link.setAttribute('download', `${actInfo.title || {}}-报名列表.xlsx`)
125 133
         document.body.append(link)
126 134
         link.click()
127 135
       }).catch(() => {

+ 1
- 1
src/pages/customer/customerlist/components/integralRecord.jsx Bestand weergeven

@@ -140,7 +140,7 @@ class ModalIntegralRecord extends React.Component {
140 140
         title: '发生时间',
141 141
         dataIndex: 'createDate',
142 142
         key: 'createDate',
143
-        render: (createDate, records) => <span> {moment(createDate).format('YYYY-MM-DD')}</span>,
143
+        render: (createDate, records) => <span> {moment(createDate).format('YYYY-MM-DD HH:mm')}</span>,
144 144
       },
145 145
     ]
146 146
     return (

+ 17
- 2
src/pages/customer/personlist/index.jsx Bestand weergeven

@@ -2,9 +2,11 @@ import React, { useState, useEffect } from 'react'
2 2
 import { Select, Spin, Table, Button, Form, Input, Divider, Modal,Popconfirm } from 'antd'
3 3
 import NavLink from 'umi/navlink'
4 4
 import { fetch, apis, fetchList } from '@/utils/request'
5
+import { exportExcel } from '@/utils/utils'
5 6
 import IntegralRecord from '../customerlist/components/integralRecord'
6 7
 
7 8
 const getPersonList = fetchList(apis.person.getPersonList)
9
+const exportPersonList = fetch(apis.person.export)
8 10
 
9 11
 const Condition = Form.create()(props => {
10 12
   const handleSubmit = e => {
@@ -39,6 +41,11 @@ const Condition = Form.create()(props => {
39 41
               getFieldDecorator('phone')(<Input placeholder="手机号" />)
40 42
             }
41 43
             </Form.Item>
44
+            <Form.Item label="推荐人">
45
+            {
46
+              getFieldDecorator('recommended')(<Input placeholder="推荐人" />)
47
+            }
48
+            </Form.Item>
42 49
         </div>
43 50
         <div style={{ flex: 'none', width: '180px' }}>
44 51
           <Form.Item>
@@ -76,6 +83,12 @@ export default props => {
76 83
     })
77 84
   }
78 85
 
86
+  const handleExport = () => {
87
+    exportPersonList({params: queryParams}).then(res => {
88
+      exportExcel(res, '会员列表')
89
+    })
90
+  }
91
+
79 92
   useEffect(() => {
80 93
     setLoading(true)
81 94
     getPersonList(queryParams).then(res => {
@@ -89,7 +102,7 @@ export default props => {
89 102
   return (
90 103
     <div>
91 104
       <Condition onSearch={handleSearch} onReset={handleSearch} />
92
-      <div style={{margin: '24px 0'}}> </div>
105
+      <div style={{margin: '24px 0'}}><Button type="" onClick={handleExport}>导出</Button></div>
93 106
       <Table dataSource={listData} loading={loading} pagination={{...pagination, onChange: handlePageChange}} rowKey="personId">
94 107
         <Table.Column
95 108
           title="头像"
@@ -99,6 +112,8 @@ export default props => {
99 112
         />
100 113
         <Table.Column title="姓名" dataIndex="nickname" key="nickname" />
101 114
         <Table.Column title="电话" dataIndex="phone" key="phone" render={t => t ? t.replace(/(\d{3})\d*(\d{4})/,'$1****$2') : ''} />
115
+        <Table.Column title="推荐人" dataIndex="sharePersonName" key="sharePersonName" />
116
+        <Table.Column title="总积分" dataIndex="points" key="points" />
102 117
         <Table.Column title="创建时间" dataIndex="createDate" key="createDate" />
103 118
         <Table.Column
104 119
           title="操作"
@@ -106,7 +121,7 @@ export default props => {
106 121
           render={(_, row) => {
107 122
             return (
108 123
               <>
109
-                <Button type="link" onClick={() => setShowPoints({visible: true, customerId: row.personId})}>积分</Button>
124
+                <Button type="link" onClick={() => setShowPoints({visible: true, customerId: row.personId})}>积分明细</Button>
110 125
               </>
111 126
             )
112 127
           }}

+ 15
- 0
src/pages/dashboard/components/ABPart.jsx Bestand weergeven

@@ -0,0 +1,15 @@
1
+import React, { useEffect, useState } from 'react'
2
+import { Row, Col } from 'antd'
3
+
4
+export default props => {
5
+
6
+  const left = props.left || 16
7
+  const right = 24 - left
8
+
9
+  return (
10
+    <Row type="flex" align={props.align || "top"} justify="space-around" gutter={props.gutter || 24}>
11
+      <Col span={left}>{props.a}</Col>
12
+      <Col span={right}>{props.b}</Col>
13
+    </Row>
14
+  )
15
+}

+ 35
- 0
src/pages/dashboard/components/BuildingStatic.jsx Bestand weergeven

@@ -0,0 +1,35 @@
1
+import React, { useEffect, useState } from 'react'
2
+import { Row, Col, Statistic, Icon, Spin } from 'antd'
3
+import { apis, fetch } from '@/utils/request'
4
+
5
+const getHouseVerified = fetch(apis.dashboard.houseVerified)
6
+
7
+export default props => {
8
+  const [loading, setLoading] = useState({})
9
+  const [data, setData] = useState({})
10
+
11
+  useEffect(() => {
12
+    setLoading(true)
13
+    getHouseVerified().then(res => {
14
+      setData(res)
15
+      setLoading(false)
16
+    }).catch(e => console.error(e) || setLoading(false))
17
+  }, [])
18
+
19
+
20
+  return (
21
+    <Spin spinning={loading}>
22
+      <Row gutter={16}>
23
+        <Col span={4}>
24
+          {/* <Statistic title={<div><Icon type="bell" style={{fontSize: '1.2em'}} /> 工单 </div>} value={112893} /> */}
25
+        </Col>
26
+        <Col span={10}>
27
+          <Statistic title={<div><Icon type="home" style={{fontSize: '1.2em'}} /> 已认证(户) </div>} value={data.valid} />
28
+        </Col>
29
+        <Col span={10}>
30
+          <Statistic title={<div><Icon type="home" style={{fontSize: '1.2em'}} /> 未认证(户) </div>} value={data.total - data.valid} />
31
+        </Col>
32
+      </Row>
33
+    </Spin>
34
+  )
35
+}

+ 69
- 0
src/pages/dashboard/components/CommAlert.jsx Bestand weergeven

@@ -0,0 +1,69 @@
1
+import React, { useEffect, useState } from 'react'
2
+import { Card, Alert, Icon } from 'antd'
3
+import { fetch, apis } from '@/utils/request'
4
+import Link from 'umi/link'
5
+
6
+const getTips = fetch(apis.dashboard.tips)
7
+
8
+export default props => {
9
+  const [loading, setLoading] = useState(false)
10
+  const [data, setData] = useState({})
11
+
12
+  useEffect(() => {
13
+    setLoading(true)
14
+    getTips().then(res => {
15
+      setData(res)
16
+      setLoading(false)
17
+    }).catch(e => console.error(e) || setLoading(false))
18
+  }, [])
19
+
20
+  const ticket = data.ticketNum ? `您有 ${data.ticketNum} 个待处理工单, 点击处理` : '暂无未处理工单'
21
+  const verify = data.verifyNum ? `您有 ${data.verifyNum} 条待审核记录, 点击处理` : '暂无业主申请'
22
+  const exchange = data.exchangeNum ? `累计有 ${data.exchangeNum} 条兑换记录, 点击查看` : '暂兑换记录'
23
+  const enlistNum = data.enlistNum && data.enlistNum.dynamicId ? `总计 ${data.enlistNum.num} 人报名参与 ${data.enlistNum.title} 活动, 点击查看` : '暂进行中活动'
24
+
25
+  return (
26
+    <Card title="日常工作" bordered={false} loading={loading}>
27
+      <Link to="/property/ticket">
28
+        <Alert
29
+          message="工单报修"
30
+          description={ticket}
31
+          type="success"
32
+          showIcon
33
+          icon={<Icon type="snippets" />}
34
+          style={{marginBottom: 16}}
35
+        />
36
+      </Link>
37
+      <Link to="/property/proprietor/audit">
38
+        <Alert
39
+          message="业主审核"
40
+          description={verify}
41
+          type="info"
42
+          showIcon
43
+          icon={<Icon type="user-add" />}
44
+          style={{marginBottom: 16}}
45
+        />
46
+      </Link>
47
+      <Link to="/integralMall/exchangeRecords">
48
+        <Alert
49
+          message="商品兑换"
50
+          description={exchange}
51
+          type="warning"
52
+          showIcon
53
+          icon={<Icon type="gift" />}
54
+          style={{marginBottom: 16}}
55
+        />
56
+      </Link>
57
+      <Link to={data.enlistNum && data.enlistNum.dynamicId ? `/activity/detailActivity?dynamicId=${data.enlistNum.dynamicId}` : '/activity/ActivityList'}>
58
+        <Alert
59
+          message="活动报名"
60
+          description={enlistNum}
61
+          type="error"
62
+          showIcon
63
+          icon={<Icon type="crown" />}
64
+          // style={{marginBottom: 16}}
65
+        />
66
+      </Link>
67
+    </Card>
68
+  )
69
+}

+ 74
- 0
src/pages/dashboard/components/ScrollAlert.jsx Bestand weergeven

@@ -0,0 +1,74 @@
1
+import React, { useEffect, useState } from 'react'
2
+import { Card, Carousel, Row, Col } from 'antd'
3
+import moment from 'moment'
4
+import { orderBy } from 'lodash'
5
+import { fetch, apis } from '@/utils/request'
6
+
7
+const getDynamic = fetch(apis.dashboard.dynamic)
8
+
9
+const Item = props => (
10
+  <Row gutter={16} type="flex" align="middle" style={{ marginTop: 8, marginBottom: 8 }}>
11
+    <Col span={8}>{props.dataSource.createDate}</Col>
12
+    <Col span={16}>{`${props.dataSource.nickname} ${props.dataSource.desc}`}</Col>
13
+  </Row>
14
+)
15
+
16
+const showMax = 10
17
+
18
+export default props => {
19
+  const [loading, setLoading] = useState(false)
20
+  const [list, setList] = useState([])
21
+  const [showSlides, setShowSlides] = useState(0)
22
+
23
+  useEffect(() => {
24
+    const today = moment()
25
+    // 取最近 15 天的记录
26
+    const endDate = today.format('YYYY-MM-DD')
27
+    today.subtract(15, 'days')
28
+    const startDate = today.format('YYYY-MM-DD')
29
+
30
+    setLoading(true)
31
+    getDynamic({params: {startDate, endDate}}).then(res => {
32
+      const { ticketList, propList, billList } = res
33
+
34
+      // 组合list
35
+      const compList = [
36
+        ...(ticketList || []).map(x => ({...x, createDate: moment(x.createDate).format('MM-DD HH:mm'), desc: '提了一个工单'})),
37
+        ...(propList || []).map(x => ({...x, createDate: moment(x.createDate).format('MM-DD HH:mm'), desc: '申请了一个业主认证'})),
38
+        ...(billList || []).map(x => ({...x, createDate: moment(x.createDate).format('MM-DD HH:mm'), desc: '缴了一笔费用'})),
39
+      ]
40
+      
41
+      if (compList.length === 0) {
42
+        setShowSlides(0)
43
+      } else {
44
+        setShowSlides(compList.length > showMax ? showMax : compList.length - 1)
45
+      }
46
+
47
+      // 按照时间倒叙
48
+      const newList = orderBy(compList, ['createDate'], ['desc'])
49
+      setList(newList)
50
+
51
+      setLoading(false)
52
+    }).catch(e => console.error(e) || setLoading(false))
53
+
54
+  }, [])
55
+
56
+  return (
57
+    <Card title="最新动态" loading={loading}>
58
+      <Carousel
59
+        dots={false}
60
+        autoplay={true}
61
+        lazyLoad={true}
62
+        infinite={true}
63
+        speed={500}
64
+        slidesToShow={showSlides}
65
+        slidesToScroll={1}
66
+        dotPosition="right"
67
+      >
68
+        {
69
+          list.map(x => <Item key={x.createDate} dataSource={x} />)
70
+        }
71
+      </Carousel>
72
+    </Card>
73
+  )
74
+}

+ 89
- 0
src/pages/dashboard/components/ShortCut.jsx Bestand weergeven

@@ -0,0 +1,89 @@
1
+import React, { useEffect, useState } from 'react'
2
+import { Card, Row, Col, Icon, Spin } from 'antd'
3
+import moment from 'moment'
4
+import Link from 'umi/link'
5
+import { fetch, apis } from '@/utils/request'
6
+import ABPart from './ABPart'
7
+
8
+const Title = props => <div> <Icon type={props.icon} style={{color: props.color, fontSize: '1.2em'}} /> <span style={{display: 'inline-block', marginLeft: 8}}>{props.children}</span></div>
9
+const StatNum = props => <Spin spinning={props.loading}><div style={{textAlign: 'center'}}><span style={{fontSize: '1.6em'}}>{props.value}</span> {props.unit}</div></Spin>
10
+
11
+const getStatis = fetch(apis.dashboard.statis)
12
+
13
+export default props => {
14
+  const [loading, setLoading] = useState(false)
15
+  const [data, setData] = useState({})
16
+
17
+  useEffect(() => {
18
+    const today = moment()
19
+    // 当月第一天
20
+    const startDate = today.format('YYYY-MM-01')
21
+
22
+    // 当月最后一天,
23
+    // 因为当前日期是业务数据最大值, 因此当天的数据跟月末是一致的
24
+    const endDate = today.format(`YYYY-MM-DD`)
25
+
26
+    setLoading(true)
27
+    getStatis({params: {startDate, endDate}}).then(res => {
28
+      setData(res)
29
+      setLoading(false)
30
+    }).catch(er => setLoading(false))
31
+  }, [])
32
+
33
+  return (
34
+    <Row gutter={24}>
35
+      <Col span={6}>
36
+        <Link to="/property/buildingInfo">
37
+          <Card title={false}>
38
+            <ABPart
39
+              align="middle"
40
+              gutter={8}
41
+              left={12}
42
+              a={<Title icon="home" color="#f50">楼栋管理</Title>}
43
+              b={<StatNum loading={loading} value={data.buildingNum} unit="栋" />}
44
+            />
45
+          </Card>
46
+        </Link>
47
+      </Col>
48
+      <Col span={6}>
49
+        <Link to="/property/proprietor">
50
+          <Card title={false}>
51
+            <ABPart
52
+              align="middle"
53
+              gutter={8}
54
+              left={12}
55
+              a={<Title icon="user" color="#2db7f5">业主管理</Title>}
56
+              b={<StatNum loading={loading} value={data.propNum} unit="人" />}
57
+            />
58
+          </Card>
59
+        </Link>
60
+      </Col>
61
+      <Col span={6}>
62
+        <Link to="/property/bill/management">
63
+          <Card title={false}>
64
+            <ABPart
65
+              align="middle"
66
+              gutter={8}
67
+              left={12}
68
+              a={<Title icon="bank" color="#87d068">缴费(本月)</Title>}
69
+              b={<StatNum loading={loading} value={data.houseNum} unit="单" />}
70
+            />
71
+          </Card>
72
+        </Link>
73
+      </Col>
74
+      <Col span={6}>
75
+        <Link to="/property/bill/ticket">
76
+          <Card title={false}>
77
+            <ABPart
78
+              align="middle"
79
+              gutter={8}
80
+              left={12}
81
+              a={<Title icon="bell" color="#108ee9">工单(本月)</Title>}
82
+              b={<StatNum loading={loading} value={data.ticketNum} unit="条" />}
83
+            />
84
+          </Card>
85
+        </Link>
86
+      </Col>
87
+    </Row>
88
+  )
89
+}

+ 49
- 0
src/pages/dashboard/index.jsx Bestand weergeven

@@ -0,0 +1,49 @@
1
+import React, { useEffect, useState } from 'react'
2
+import { PageHeader, Row, Col, Card, Icon } from 'antd'
3
+import CommunitySelect from '@/components/CommunitySelect'
4
+import ABPart from './components/ABPart'
5
+import BuildingStatic from './components/BuildingStatic'
6
+import ShortCut from './components/ShortCut'
7
+import CommAlert from './components/CommAlert'
8
+import ScrollAlert from './components/ScrollAlert'
9
+
10
+export default props => {
11
+  // const [] = useState()
12
+
13
+
14
+  // useEffect(() => {
15
+
16
+  // }, [])
17
+
18
+  const randText = `精铸致远,盛道自来。
19
+  今天的远道集团,以卓越的产品和服务创造高品质生活与理想工作为使命,建设家园,服务社会,创造美好生活。
20
+  我们相信,致远需要我们时刻创新奋进,而盛道的来临也正因为我们每一天为创造美好而不懈的努力!`
21
+
22
+  return (
23
+    <div>
24
+      <PageHeader
25
+        title="工作台"
26
+        backIcon={false}
27
+        ghost={false}
28
+        extra={[
29
+          <CommunitySelect key="1" style={{minWidth: 200}} autoInited />
30
+        ]}
31
+      >
32
+        <ABPart
33
+          align="middle"
34
+          a={<div style={{verticalAlign: 'center'}}><p>管理员您好, 祝您开心每一天! </p><p>{randText}</p></div>}
35
+          b={<BuildingStatic />}
36
+        />
37
+      </PageHeader>
38
+
39
+      <div style={{marginTop: 24}}><ShortCut /></div>
40
+      
41
+      <div style={{marginTop: 24}}>
42
+        <ABPart
43
+          a={<CommAlert />}
44
+          b={<ScrollAlert />}
45
+        />
46
+      </div>
47
+    </div>
48
+  )
49
+}

+ 14
- 1
src/pages/integralMall/exchangeRecords.jsx Bestand weergeven

@@ -8,6 +8,7 @@ import BuildSelect from '../../components/SelectButton/BuildSelect'
8 8
 import apis from '../../services/apis';
9 9
 import request from '../../utils/request'
10 10
 import AuthButton from '@/components/AuthButton';
11
+import { exportExcel } from '@/utils/utils'
11 12
 
12 13
 /**
13 14
   @param {*} props
@@ -21,6 +22,7 @@ function record(props) {
21 22
 
22 23
   // 获取初始化数据
23 24
   const [data, setData] = useState({})
25
+  const [queryParam, setQueryParam] = useState()
24 26
 
25 27
   useEffect(() => {
26 28
     getList({ pageNum: 1, pageSize: 10 });
@@ -65,12 +67,20 @@ function record(props) {
65 67
           submitValue.endVerifyDate = null
66 68
         }
67 69
 
70
+        setQueryParam(submitValue)
71
+
68 72
         console.log(submitValue)
69 73
         getList({ pageNum: 1, pageSize: 10, ...submitValue })
70 74
       }
71 75
     });
72 76
   }
73 77
 
78
+  const handleExport = () => {
79
+    request({ ...apis.integralMall.taPointsExchangeExport, params: queryParam, }).then((data) => {
80
+      exportExcel(data, '积分兑换记录')
81
+    })
82
+  }
83
+
74 84
   const changePageNum = (pageNumber) => {
75 85
     props.form.validateFields((err, values) => {
76 86
       if (!err) {
@@ -92,7 +102,7 @@ function record(props) {
92 102
       dataIndex: 'personType',
93 103
       key: 'personType',
94 104
       align: 'center',
95
-      render: (personType) => <><span>{personType === 'Realty Consultant' ? '置业顾问' : personType === 'Sales Executive' ? '销售主管' : personType === 'estate agent' ? '经纪人' : personType === 'customer' ? '客户' : ''}</span></>
105
+      render: (personType) => <><span>{personType === 'prop' ? '物业相关' : personType === 'life-consultant' ? '生活管家' : ''}</span></>
96 106
     },
97 107
     {
98 108
       title: '手机号',
@@ -210,6 +220,9 @@ function record(props) {
210 220
         </div>
211 221
 
212 222
       </Form>
223
+      <div style={{marginTop: 24}}>
224
+        <Button onClick={handleExport}>导出</Button>
225
+      </div>
213 226
       <Table rowKey="exchangeRecords" style={{ marginTop: '40px' }} dataSource={data.records} columns={columns} pagination={false} />
214 227
       <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '30px' }}>
215 228
         <Pagination showQuickJumper defaultCurrent={1} total={data.total} onChange={changePageNum} current={data.current} />

+ 1
- 1
src/pages/mpSetting/components/MainSeting.jsx Bestand weergeven

@@ -71,7 +71,7 @@ export default Form.create()(props => {
71 71
         <Form.Item label="小程序封面" help="仅支持JPG图片,建议大小为520*416">
72 72
           <div>
73 73
             {props.value.miniappMedia && <span style={{display: 'inline-block', marginRight: '24px'}}>{props.value.miniappMedia}</span>}
74
-            <MiniAppMedia onChange={handleMiniAppChange} />
74
+            {/* <MiniAppMedia onChange={handleMiniAppChange} /> */}
75 75
           </div>
76 76
         </Form.Item>
77 77
       </Form>

+ 4
- 2
src/pages/mpSetting/components/TemplateItem.jsx Bestand weergeven

@@ -9,6 +9,7 @@ export default props => {
9 9
   const [typeDict, setTypeDict] = useState([
10 10
     {typeCode: 'birthday', typeName: '生日'},
11 11
     {typeCode: 'festival', typeName: '节日'},
12
+    {typeCode: 'ticket', typeName: '工单'},
12 13
   ])
13 14
 
14 15
   const handleChange = e => {
@@ -88,8 +89,9 @@ export default props => {
88 89
         onChange={handleChange}
89 90
         style={{width: '70%'}}
90 91
         placeholder="请填写消息模板ID"
92
+        readOnly={true}
91 93
         />
92
-      <Dropdown.Button
94
+      {/* <Dropdown.Button
93 95
          size="large"
94 96
         overlay={OverMenu}
95 97
         onClick={handleSubmit}
@@ -97,7 +99,7 @@ export default props => {
97 99
         style={{width: '15%'}}
98 100
       >
99 101
         提交
100
-      </Dropdown.Button>
102
+      </Dropdown.Button> */}
101 103
     </Input.Group>
102 104
   )
103 105
 }

+ 1
- 1
src/pages/mpSetting/components/TemplateSetting.jsx Bestand weergeven

@@ -68,7 +68,7 @@ export default props => {
68 68
 
69 69
   return (
70 70
     <div>
71
-      <Button onClick={handleAdd}>新增</Button>
71
+      {/* <Button onClick={handleAdd}>新增</Button> */}
72 72
       <div style={{maxWidth: '800px', marginTop: '24px'}}>
73 73
         <List
74 74
           loading={loading}

+ 13
- 10
src/pages/property/bill/edit/components/AddOn.jsx Bestand weergeven

@@ -8,9 +8,9 @@ const billUploadExcel = fetch(apis.bill.billUploadExcel)
8 8
 
9 9
 const Section = props => {
10 10
   return (
11
-    <p style={{ color: '#99a9bf', fontSize: '13px' }}>
11
+    <div style={{ color: '#99a9bf', fontSize: '13px' }}>
12 12
       {props.children}
13
-    </p>
13
+    </div>
14 14
   )
15 15
 }
16 16
 
@@ -19,8 +19,10 @@ export default props => {
19 19
   const [listData, setListData] = useState([])
20 20
   const [pagination, setPagination] = useState({})
21 21
 
22
+  const {communityId, phaseId, buildingId, dataSource} = props
23
+
22 24
   const handleDownloadExcel = () => {
23
-    billDownloadExcel().then(res => {
25
+    billDownloadExcel({params: {communityId, phaseId,buildingId}}).then(res => {
24 26
       const url = window.URL.createObjectURL(new Blob([res]))
25 27
       const link = document.createElement('a')
26 28
       link.href = url
@@ -57,16 +59,17 @@ export default props => {
57 59
   }
58 60
 
59 61
   useEffect(() => {
60
-    if (props.dataSource) {
61
-      setListData(props.dataSource.billInvoice)
62
-      setPagination({ total: props.dataSource.total })
62
+    if (dataSource) {
63
+      setListData(dataSource.billInvoice)
64
+      setPagination({ total: dataSource.total })
65
+      
63 66
     }
64
-  }, [props.dataSource])
67
+  }, [dataSource])
65 68
 
66 69
   return (
67 70
     <div>
68 71
       <Section>
69
-        <span>如果还未制作账单,请先下载账单模板,按规则填写费用后再上传</span>
72
+        <span> 如果还未制作账单,请先下载账单模板,按规则填写费用后再上传 </span>            
70 73
         <Button type="link" size="small" style={{ marginLeft: '6px' }} onClick={handleDownloadExcel}><Icon type="download" />下载模板</Button>
71 74
         <Button type="link" size="small" onClick={handleUploadExcel}><Icon type="upload" />选取账单文件并预览</Button>
72 75
       </Section>
@@ -75,8 +78,8 @@ export default props => {
75 78
       </Section>
76 79
       <List dataSource={listData} loading={loading} pagination={pagination} size="small" bordered>
77 80
         <Table.Column align="center" title="房屋信息" dataIndex="phase" key="phase" render={(_, row) => (row.phase + row.building + row.unit + row.level + row.roomNo)} />
78
-        <Table.Column align="center" title="收费说明" dataIndex="billExplain" key="billExplain" />
79
-        <Table.Column align="center" title="收费金额(元)" dataIndex="payPrice" key="payPrice" render={payPrice => (payPrice === null || payPrice === undefined ? '' : Number(payPrice/100).toFixed(2))} />
81
+        {/* <Table.Column align="center" title="收费说明" dataIndex="billExplain" key="billExplain" /> */}
82
+        <Table.Column align="center" title="收费金额(元)" dataIndex="payPrice" key="payPrice" width={160} render={payPrice => (payPrice === null || payPrice === undefined ? '' : Number(payPrice/100).toFixed(2))} />
80 83
       </List>
81 84
       <Section>
82 85
         <span>点击发送后账单会发送给对应家庭,家庭中的成员都可以查看到他们家的收费项,缴费成功无法线上退款,只能线下当面退款,请先保存为草稿,核对无误后再发送账单给住户</span>

+ 72
- 21
src/pages/property/bill/edit/index.jsx Bestand weergeven

@@ -1,7 +1,8 @@
1 1
 import React, { useEffect, useState, useRef } from 'react'
2 2
 import router from 'umi/router'
3 3
 import { fetch, apis } from '@/utils/request'
4
-import { Button, Form, Input, DatePicker, notification, Modal } from 'antd'
4
+import { Button, Form, Input, Select, DatePicker, notification, Modal, Spin } from 'antd'
5
+import CommunitySelect from '@/components/CommunitySelect'
5 6
 import AddOn from './components/AddOn'
6 7
 
7 8
 const formItemLayout = {
@@ -30,11 +31,20 @@ const tailFormItemLayout = {
30 31
 
31 32
 const billUploadExcelAdd = fetch(apis.bill.billUploadExcelAdd)
32 33
 const billInvoiceGetInvoiceInvalid = fetch(apis.bill.billInvoiceGetInvoiceInvalid)
34
+const fetchPhaseList = fetch(apis.buildingOwnerInfo.getPhaseList)
35
+const fetchBuildingList = fetch(apis.buildingOwnerInfo.getBuildingList)
33 36
 
34 37
 export default Form.create()(props => {
38
+  const [loading, setLoading] = useState(false)
35 39
   const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
36 40
   const [formData, setFormData] = useState()
37 41
   const [addOnData, setAddOnData] = useState()
42
+  const [communityId, setCommunityId] = useState()
43
+  const [phaseId, setPhaseId] = useState()
44
+  const [buildingId, setBuildingId] = useState()
45
+  const [phaseList, setPhaseList] = useState([])
46
+  const [buildingList, setBuildingList] = useState([])
47
+  const [rangeDate, setRangeDate] = useState([])
38 48
   const file = useRef()
39 49
   
40 50
   const { id } = props.location.query
@@ -50,38 +60,53 @@ export default Form.create()(props => {
50 60
           return
51 61
         }
52 62
 
63
+        if (!rangeDate || rangeDate.length !== 2) {
64
+          notification.warn({
65
+            message: '请设置缴费时间'
66
+          })
67
+          return
68
+        }
69
+
53 70
         const data = new FormData()
54 71
         data.append('file', file.current)
55
-        data.append('billExplain', values.billExplain)
72
+        data.append('communityId', communityId)
73
+        // data.append('billExplain', values.billExplain)
56 74
         data.append('billName', values.billName)
57
-        data.append('endDate', values.endDate)
75
+        data.append('startDate', rangeDate[0].format('YYYY-MM-DD'))
76
+        data.append('endDate', rangeDate[1].format('YYYY-MM-DD'))
58 77
         data.append('billStatus', billStatus)
59 78
 
60 79
         if (id) {
61 80
           data.append('billId', id)
62 81
         }
63 82
 
83
+        setLoading(true)
64 84
         billUploadExcelAdd({ data }).then(res => {
85
+          setLoading(false)
65 86
           Modal.success({
66 87
             content: '生成数据成功',
67 88
             onOk: () => router.go(-1)
68 89
           })
69
-        })
90
+        }).catch(e => console.error(e) || setLoading(false))
70 91
       }
71 92
     })
72 93
   }
73 94
 
74 95
   useEffect(() => {
75 96
     if (id) {
97
+      setLoading(true)
76 98
       billInvoiceGetInvoiceInvalid({
77 99
         data: {
78 100
           ...queryParams,
79 101
           billId: id,
102
+          communityId,
80 103
         }
81 104
       }).then(res => {
82 105
         setFormData(res.bill)
106
+        // setCommunityId(communityId)
83 107
         setAddOnData(res)
84
-      })
108
+        setLoading(false)
109
+      }).catch(e => console.error(e) || setLoading(false))
85 110
     }
86 111
   }, [id, queryParams])
87 112
 
@@ -89,19 +114,51 @@ export default Form.create()(props => {
89 114
     setFieldsValue(formData || {})
90 115
   }, [formData])
91 116
 
117
+  // 获取期
118
+  useEffect(() => {
119
+    if (communityId) {
120
+      fetchPhaseList({params: {communityId}}).then(res => setPhaseList(res))
121
+    }
122
+  }, [communityId])
123
+
124
+  // 楼栋
125
+  useEffect(() => {
126
+    if (phaseId) {
127
+      fetchBuildingList({params: {phaseId}}).then(res => setBuildingList(res))
128
+    }
129
+    setBuildingId()
130
+  }, [phaseId])
131
+
92 132
   return (
93
-    <div>
133
+    <Spin spinning={loading}>
94 134
       <Form {...formItemLayout} onSubmit={e => e.preventDefault()}>
95
-        <Form.Item label="收费组名称">
135
+        <Form.Item label="小区" required>
136
+          <CommunitySelect value={communityId} onChange={v => setCommunityId(v)} autoInited />
137
+        </Form.Item>
138
+        <Form.Item label="期/区">
139
+          <Select onChange={v => setPhaseId(v)} placeholder="期/区" allowClear>
140
+            {
141
+              phaseList.map(x => (<Select.Option key={x.id} value={x.id}>{x.name}</Select.Option>))
142
+            }
143
+          </Select>
144
+        </Form.Item>
145
+        <Form.Item label="楼栋">
146
+          <Select onChange={v => setBuildingId(v)} placeholder="栋" allowClear>
147
+            {
148
+              buildingList.map(x => (<Select.Option key={x.id} value={x.id}>{x.name}</Select.Option>))
149
+            }
150
+          </Select>
151
+        </Form.Item>
152
+        <Form.Item label="收费名称">
96 153
         {
97 154
           getFieldDecorator('billName', {
98 155
             rules: [
99
-              { required: true, message: '请填写收费组名称', },
156
+              { required: true, message: '请填写收费名称', },
100 157
             ],
101 158
           })(<Input />)
102 159
         }
103 160
         </Form.Item>
104
-        <Form.Item label="收费组说明">
161
+        {/* <Form.Item label="收费组说明">
105 162
         {
106 163
           getFieldDecorator('billExplain', {
107 164
             rules: [
@@ -109,25 +166,19 @@ export default Form.create()(props => {
109 166
             ],
110 167
           })(<Input />)
111 168
         }
112
-        </Form.Item>
113
-        <Form.Item label="截止时间">
114
-        {
115
-          getFieldDecorator('endDate', {
116
-            rules: [
117
-              { required: true, message: '请填写公告内容', },
118
-            ],
119
-          })(<DatePicker />)
120
-        }
169
+        </Form.Item> */}
170
+        <Form.Item label="缴费时间" required>
171
+          <DatePicker.RangePicker value={rangeDate} onChange={v => setRangeDate(v)} style={{width: '100%'}} />
121 172
         </Form.Item>
122 173
         <Form.Item label=" " colon={false}>
123
-          <AddOn dataSource={addOnData} onFileInput={f => file.current = f}/>
174
+          <AddOn dataSource={addOnData} onFileInput={f => file.current = f} communityId={communityId} phaseId={phaseId} buildingId={buildingId} />
124 175
         </Form.Item>
125 176
         <Form.Item {...tailFormItemLayout} >
126
-          <Button type="primary" onClick={() => handleSubmit(2)}>草稿</Button>
177
+          {/* <Button type="primary" onClick={() => handleSubmit(2)}>草稿</Button> */}
127 178
           <Button type="danger" style={{ marginLeft: '24px' }} onClick={() => handleSubmit(0)}>发布</Button>
128 179
           <Button style={{ marginLeft: '24px' }} onClick={() => router.go(-1)}>取消</Button>
129 180
         </Form.Item>
130 181
       </Form>
131
-    </div>
182
+    </Spin>
132 183
   )
133 184
 })

+ 6
- 1
src/pages/property/bill/info/Add.jsx Bestand weergeven

@@ -5,6 +5,7 @@ import NavLink from 'umi/navlink'
5 5
 import List from '../../components/List'
6 6
 import AddOne from './components/AddOne'
7 7
 
8
+const getBillInfoBydId = fetch(apis.bill.getBillInfoBydId)
8 9
 const getTempBillInvoice = fetch(apis.bill.getTempBillInvoice)
9 10
 const addTempBillInvoice = fetch(apis.bill.addTempBillInvoice)
10 11
 const deleteTempBillInvoice = fetch(apis.bill.deleteTempBillInvoice)
@@ -13,7 +14,9 @@ const updateBillInvoiceStatus = fetch(apis.bill.updateBillInvoiceStatus)
13 14
 export default props => {
14 15
   const [loading, setLoading] = useState(false)
15 16
   const [showAdd, setShowAdd] = useState(false)
17
+  const [billInfo, setBillInfo] = useState({})
16 18
   const [listData, setListData] = useState([])
19
+  const [communityId, setCommunityId] = useState()
17 20
   const [formData, setFormData] = useState({})
18 21
 
19 22
   const { id } = props.location.query
@@ -32,6 +35,7 @@ export default props => {
32 35
   const handleAdd = (vals, callback) => {
33 36
     addTempBillInvoice({data: {
34 37
       billId: id,
38
+      communityId: billInfo.communityId,
35 39
       ...vals,
36 40
     }}).then(res => {
37 41
       callback()
@@ -63,6 +67,7 @@ export default props => {
63 67
   useEffect(() => {
64 68
     if (id) {
65 69
       getListData()
70
+      getBillInfoBydId({urlData: {id}}).then(x => setBillInfo(x))
66 71
     }
67 72
     getListData()
68 73
   }, [])
@@ -98,7 +103,7 @@ export default props => {
98 103
         />
99 104
       </List>
100 105
       <Modal title="收费组信息" visible={showAdd} footer={null} maskClosable={false} destroyOnClose onCancel={() => setShowAdd(false)}>
101
-        <AddOne onSubmit={handleAdd} onCancel={() => setShowAdd(false)} />
106
+        <AddOne communityId={billInfo.communityId} onSubmit={handleAdd} onCancel={() => setShowAdd(false)} />
102 107
       </Modal>
103 108
     </div>
104 109
   )

+ 5
- 4
src/pages/property/bill/info/components/AddOne.jsx Bestand weergeven

@@ -43,7 +43,8 @@ export default Form.create()(props => {
43 43
     unitList,
44 44
     levelList,
45 45
     roomNoList
46
-  } = useRoomSelect()
46
+  } = useRoomSelect(props.communityId)
47
+
47 48
   const [formData, setFormData] = useState({})
48 49
 
49 50
   const [phaseErr, setPhaseErr] = useState('')
@@ -159,13 +160,13 @@ export default Form.create()(props => {
159 160
           }
160 161
         </Select>
161 162
       </Form.Item>
162
-      <Form.Item label="收费单说明">
163
+      <Form.Item label="收费名称">
163 164
       {
164 165
         props.form.getFieldDecorator('billInvoiceExplain', {
165 166
           rules: [
166
-            {required: true, message: '请填写收费单说明'}
167
+            {required: true, message: '请填写收费名称'}
167 168
           ]
168
-        })(<Input placeholder="收费单说明" />)
169
+        })(<Input placeholder="收费名称" />)
169 170
       }
170 171
       </Form.Item>
171 172
       <Form.Item label="收费金额(元)">

+ 16
- 12
src/pages/property/bill/info/components/Edit.jsx Bestand weergeven

@@ -1,4 +1,4 @@
1
-import React, { useEffect, useState } from 'react'
1
+import React, { useEffect, useRef, useState } from 'react'
2 2
 import { Modal, Form, Input, DatePicker, Button } from 'antd'
3 3
 import moment from 'moment'
4 4
 
@@ -31,37 +31,41 @@ export default Form.create()(props => {
31 31
     e.preventDefault()
32 32
     props.form.validateFields((err, values) => {
33 33
       if (!err && props.onSubmit) {
34
-        const endDate = values.endDate ? moment(values.endDate).toDate() : undefined
35
-        props.onSubmit({...values, endDate})
34
+        const startDate = values.startDate ? moment(values.startDate).format('YYYY-MM-DDT00:00:00[Z]') : undefined
35
+        const endDate = values.endDate ? moment(values.endDate).format('YYYY-MM-DDT23:59:59[Z]') : undefined
36
+        props.onSubmit({...values, startDate, endDate})
36 37
       }
37 38
     })
38 39
   }
39 40
 
40 41
   useEffect(() => {
41 42
     const vals = props.initialData || {}
43
+    const startDate = vals.startDate ? moment(vals.startDate) : undefined
42 44
     const endDate = vals.endDate ? moment(vals.endDate) : undefined
43
-    props.form.setFieldsValue({...vals, endDate})
45
+    props.form.setFieldsValue({...vals, startDate, endDate})
44 46
   }, [props.initialData])
45 47
 
46 48
   return (
47
-    <Modal title="收费信息" visible={props.visible} footer={null} maskClosable={false} destroyOnClose onCancel={props.onCancel}>
49
+    <Modal title="收费信息" visible={props.visible} footer={null} maskClosable={false} onCancel={props.onCancel}>
48 50
       <Form {...formItemLayout} onSubmit={handleSubmit}>
49
-        <Form.Item label="收费名称">
51
+        <Form.Item label="收费名称">
50 52
         {
51 53
           props.form.getFieldDecorator('billName', {
52 54
             rules: [
53
-              { required: true, message: '请填写收费名称' },
55
+              { required: true, message: '请填写收费名称' },
54 56
             ],
55 57
           })(<Input placeholder="收费组名称" />)
56 58
         }
57 59
         </Form.Item>
58
-        <Form.Item label="收费组说明">
60
+        <Form.Item label="开始时间">
59 61
         {
60
-          props.form.getFieldDecorator('billExplain', {
62
+          props.form.getFieldDecorator('startDate', {
61 63
             rules: [
62
-              { required: true, message: '请填写收费组说明' },
64
+              { required: true, message: '请选择开始时间' },
63 65
             ],
64
-          })(<Input placeholder="收费组说明" />)
66
+          })(
67
+            <DatePicker placeholder="请选择开始时间" />
68
+          )
65 69
         }
66 70
         </Form.Item>
67 71
         <Form.Item label="截止时间">
@@ -71,7 +75,7 @@ export default Form.create()(props => {
71 75
               { required: true, message: '请选择截止时间' },
72 76
             ],
73 77
           })(
74
-            <DatePicker showTime placeholder="请选择截止时间" />
78
+            <DatePicker placeholder="请选择截止时间" />
75 79
           )
76 80
         }
77 81
         </Form.Item>

+ 11
- 12
src/pages/property/bill/info/index.jsx Bestand weergeven

@@ -11,8 +11,9 @@ import useRoomSelect from '../../utils/hooks/useRoomSelect'
11 11
 
12 12
 const BillStatusDict = [
13 13
   { value: '0', label: '未缴费' },
14
-  { value: '1', label: '已线上缴费' },
15
-  { value: '2', label: '已线下缴费' },
14
+  { value: '1', label: '已缴费' },
15
+  // { value: '2', label: '已线下缴费' },
16
+  { value: '3', label: '支付中' },
16 17
 ]
17 18
 
18 19
 const PayTypeDict = [
@@ -48,7 +49,7 @@ const Condition = props => {
48 49
     unitList,
49 50
     levelList,
50 51
     roomNoList
51
-  } = useRoomSelect()
52
+  } = useRoomSelect(props.communityId)
52 53
   
53 54
   const handleSearch = vals => {
54 55
     const data = {
@@ -283,16 +284,14 @@ export default props => {
283 284
         style={{ borderBottom: '1px solid rgb(235, 237, 240)' }}
284 285
       >
285 286
         <Descriptions column={3}>
286
-          <Descriptions.Item label="收费组名称">{billData.billName}</Descriptions.Item>
287
-          <Descriptions.Item label="截止时间">{billData.endDate}</Descriptions.Item>
288
-          <Descriptions.Item label="收费组说明">
289
-            <Typography.Text ellipsis>{billData.billExplain}</Typography.Text>
290
-          </Descriptions.Item>
287
+          <Descriptions.Item label="收费名称">{billData.billName}</Descriptions.Item>
288
+          <Descriptions.Item label="开始时间">{(billData.startDate || '').substring(0, 10)}</Descriptions.Item>
289
+          <Descriptions.Item label="截止时间">{(billData.endDate || '').substring(0, 10)}</Descriptions.Item>
291 290
         </Descriptions>
292 291
       </PageHeader>
293 292
 
294 293
       <div style={{margin: '36px 0'}}>
295
-        <Condition onSearch={handleSearch} onReset={handleSearch} />
294
+        <Condition onSearch={handleSearch} communityId={billData.communityId} onReset={handleSearch} />
296 295
       </div>
297 296
 
298 297
       <div style={{margin: '24px 0'}}>
@@ -316,10 +315,10 @@ export default props => {
316 315
           <Table.Column title="缴费途径" dataIndex="payType" key="payType" render={t => getDictLabel(PayTypeDict, t)} />
317 316
           <Table.Column title="缴费人" dataIndex="payName" key="payName" />
318 317
           <Table.Column title="缴费时间" dataIndex="payDate" key="payDate" />
319
-          <Table.Column title="新建时间" dataIndex="createDate" key="createDate" render={t => moment(t).format('YYYY-MM-DD HH:mm')} />
318
+          {/* <Table.Column title="新建时间" dataIndex="createDate" key="createDate" render={t => t ? moment(t).format('YYYY-MM-DD HH:mm') : ''} />
320 319
           <Table.Column title="新建人" dataIndex="createUserName" key="createUserName" />
321
-          <Table.Column title="修改时间" dataIndex="updateDate" key="updateDate" render={t => moment(t).format('YYYY-MM-DD HH:mm')}/>
322
-          <Table.Column title="修改人" dataIndex="updateUserName" key="updateUserName" />
320
+          <Table.Column title="修改时间" dataIndex="updateDate" key="updateDate" render={t => t ? moment(t).format('YYYY-MM-DD HH:mm'): ''}/>
321
+          <Table.Column title="修改人" dataIndex="updateUserName" key="updateUserName" /> */}
323 322
           <Table.Column
324 323
             title="操作"
325 324
             key="action"

+ 73
- 36
src/pages/property/bill/list/index.jsx Bestand weergeven

@@ -1,35 +1,74 @@
1 1
 import React, { useRef, useState, useEffect } from 'react'
2
-import { Spin, Form, Input, Divider, Button, Row, Col, Popconfirm } from 'antd'
2
+import { Spin, Form, Input, Divider, Button, Row, Col, Popconfirm, DatePicker, Select } from 'antd'
3 3
 import router from 'umi/router'
4 4
 import NavLink from 'umi/navlink'
5
+import moment from 'moment'
5 6
 import { fetch, fetchList, apis } from '@/utils/request'
7
+import CommunitySelect from '@/components/CommunitySelect'
6 8
 import Search from '../../components/Search'
7 9
 import List from '../../components/List'
8 10
 
9 11
 
10 12
 const Condition = props => {
13
+  const [communityId, setCommunityId] = useState()
14
+  const [rangeDate, setRangeDate] = useState([])
15
+
16
+  const handleCommunityChange = v => {
17
+    setCommunityId(v)
18
+
19
+    props.onCommunityChange(v)
20
+  }
21
+
22
+  const handleSearch = v => {
23
+    props.onSearch({
24
+      ...v,
25
+      startDate: rangeDate[0] ? rangeDate[0].format('YYYY-MM-DD') : undefined,
26
+      endDate: rangeDate[1] ? rangeDate[1].format('YYYY-MM-DD') : undefined,
27
+    })
28
+  }
29
+
30
+  const handleReset = v => {
31
+    setRangeDate([])
32
+    props.onReset({
33
+      ...v,
34
+      startDate: undefined,
35
+      endDate: undefined,
36
+    })
37
+  }
38
+
11 39
   return (    
12 40
     <Search
13
-      onSearch={props.onSearch}
14
-      onReset={props.onReset}
41
+      onSearch={handleSearch}
42
+      onReset={handleReset}
15 43
       render={form => {
16 44
         const { getFieldDecorator } = form
17 45
 
18 46
         return (
19 47
           <>
20
-            <Form.Item label="收费组编号">
48
+            <Form.Item label="小区">
49
+              <CommunitySelect value={communityId} onChange={handleCommunityChange} autoInited />
50
+            </Form.Item>
51
+            <Form.Item label="收费ID">
21 52
             {
22 53
               getFieldDecorator('billId')(<Input />)
23 54
             }
24 55
             </Form.Item>
25
-            <Form.Item label="收费组名">
56
+            <Form.Item label="收费名">
26 57
             {
27 58
               getFieldDecorator('billName')(<Input />)
28 59
             }
29 60
             </Form.Item>
30
-            <Form.Item label="收费组说明">
61
+            <Form.Item label="收费时间">
62
+              <DatePicker.RangePicker value={rangeDate} onChange={v => setRangeDate(v)} />
63
+            </Form.Item>
64
+            <Form.Item label="收费类型">
31 65
             {
32
-              getFieldDecorator('billExplain')(<Input />)
66
+              getFieldDecorator('isTicket')(
67
+                <Select style={{minWidth: 100}} allowClear>
68
+                  <Select.Option value={1}>物业</Select.Option>
69
+                  <Select.Option value={0}>工单</Select.Option>
70
+                </Select>
71
+              )
33 72
             }
34 73
             </Form.Item>
35 74
           </>
@@ -42,20 +81,27 @@ const Condition = props => {
42 81
 const TableList = props => {
43 82
   const columns = [
44 83
     {
45
-      title: '收费编号',
84
+      title: '收费编号',
46 85
       dataIndex: 'id',
47 86
       key: 'id',
48 87
       align: 'center',
49 88
     },
50 89
     {
51
-      title: '收费组名称',
90
+      title: '类型',
91
+      dataIndex: 'isTicket',
92
+      key: 'isTicket',
93
+      render: t => t === 1 || t === true ? '工单' : '物业'
94
+    },
95
+    {
96
+      title: '收费名称',
52 97
       dataIndex: 'billName',
53 98
       key: 'billName',
54 99
     },
55 100
     {
56
-      title: '收费组说明',
57
-      dataIndex: 'billExplain',
58
-      key: 'billExplain',
101
+      title: '收费时间',
102
+      dataIndex: 'startDate',
103
+      key: 'startDate',
104
+      render: (t, row) => `${row.startDate ? moment(row.startDate).format('YYYY-MM-DD') : '--'} ~ ${row.endDate ? moment(row.endDate).format('YYYY-MM-DD') : '--'}`
59 105
     },
60 106
     {
61 107
       title: '应缴户数',
@@ -73,14 +119,14 @@ const TableList = props => {
73 119
       key: 'unpayedNum',
74 120
     },
75 121
     {
76
-      title: '收费状态',
122
+      title: '收费状态',
77 123
       key: 'billStatus',
78 124
       render: (t, row) => {
79 125
         switch (row.billStatus) {
80 126
           case '0':
81
-            return '正在收费'
127
+            return '进行中'
82 128
           case '1':
83
-            return '收费完成'
129
+            return '完成'
84 130
           case '2':
85 131
             return '草稿'
86 132
           default:
@@ -88,18 +134,6 @@ const TableList = props => {
88 134
         }
89 135
       }
90 136
     },
91
-    {
92
-      title: '发布时间',
93
-      dataIndex: 'createDate',
94
-      key: 'createDate',
95
-      render: dt => (dt || '').substr(0, 16)
96
-    },
97
-    {
98
-      title: '截止时间',
99
-      dataIndex: 'endDate',
100
-      key: 'endDate',
101
-      render: dt => (dt || '').substr(0, 16)
102
-    },
103 137
     {
104 138
       title: '操作',
105 139
       key: 'action',
@@ -139,6 +173,7 @@ export default props => {
139 173
   const [listData, setListData] = useState([])
140 174
   const [pagination, setPagination] = useState({})
141 175
   const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
176
+  const [communityId, setCommunityId] = useState()
142 177
   
143 178
   const handleQuery = vals => {
144 179
     setQueryParams({
@@ -173,18 +208,20 @@ export default props => {
173 208
   }
174 209
 
175 210
   useEffect(() => {
176
-    setLoading(true)
177
-    FetchBillList(queryParams).then(res => {
178
-      const {list, ...pagi} = res[1]
179
-      setListData(list)
180
-      setPagination(pagi)
181
-      setLoading(false)
182
-    })
183
-  }, [queryParams])
211
+    if (communityId) {
212
+      setLoading(true)
213
+      FetchBillList({...queryParams, communityId}).then(res => {
214
+        const {list, ...pagi} = res[1]
215
+        setListData(list)
216
+        setPagination(pagi)
217
+        setLoading(false)
218
+      })
219
+    }
220
+  }, [queryParams, communityId])
184 221
 
185 222
   return (
186 223
     <div>
187
-      <Condition onReset={handleQuery} onSearch={handleQuery} />
224
+      <Condition onReset={handleQuery} onSearch={handleQuery} onCommunityChange={v => setCommunityId(v)} />
188 225
       <div style={{ margin: '24px 0' }}>
189 226
         <NavLink to={`/property/bill/management/add`}>
190 227
           <Button type="primary">添加</Button>

+ 77
- 5
src/pages/property/bill/order/index.jsx Bestand weergeven

@@ -1,10 +1,13 @@
1 1
 import React, { useState, useEffect } from 'react'
2
-import { Select, Spin, Table, Button, Form, Input, Divider, Icon } from 'antd'
2
+import { Select, Spin, Table, Button, Form, Input, Divider, Icon, DatePicker } from 'antd'
3 3
 import NavLink from 'umi/navlink'
4
+import moment from 'moment';
4 5
 import { fetchList, apis, fetch } from '@/utils/request'
5 6
 import Search from '../../components/Search'
6 7
 import List from '../../components/List'
7 8
 
9
+const { MonthPicker, RangePicker, WeekPicker } = DatePicker;
10
+
8 11
 const exportStatementExcel = fetch(apis.bill.exportStatementExcel)
9 12
 const getBillStatementAll = fetch(apis.bill.getBillStatementAll)
10 13
 
@@ -15,12 +18,42 @@ const StatusDict = {
15 18
   '3': '已关闭',
16 19
 }
17 20
 
21
+const PayStatusDict = [
22
+  {
23
+    label: '未支付',
24
+    value: '0',
25
+  },
26
+  {
27
+    label: '已支付',
28
+    value: '1',
29
+  },
30
+  {
31
+    label: '支付中',
32
+    value: '2',
33
+  },
34
+  {
35
+    label: '已关闭',
36
+    value: '3',
37
+  },
38
+]
39
+
18 40
 const PayTypeDict = {
19 41
   '0': '微信缴费',
20 42
   '1': '线下缴费',
21
-  '2': '支付宝缴费',
43
+  // '2': '支付宝缴费',
22 44
 }
23 45
 
46
+const PayTypesDict = [
47
+  {
48
+    label: '微信缴费',
49
+    value: '0',
50
+  },
51
+  {
52
+    label: '线下缴费',
53
+    value: '1',
54
+  },
55
+]
56
+
24 57
 const Condition = props => {
25 58
   return (
26 59
     <Search
@@ -56,6 +89,33 @@ const Condition = props => {
56 89
               getFieldDecorator('payPhone')(<Input placeholder="缴费人手机号" />)
57 90
             }
58 91
             </Form.Item>
92
+            <Form.Item label="订单状态">
93
+            {
94
+              getFieldDecorator('orderStatus')(
95
+                <Select placeholder="选择订单状态" style={{ width: '120px' }}>
96
+                  {
97
+                    PayStatusDict.map(x => (<Select.Option key={x.value} value={x.value}>{x.label}</Select.Option>))
98
+                  }
99
+                </Select>
100
+              )
101
+            }
102
+            </Form.Item>
103
+            <Form.Item label="缴费方式">
104
+            {
105
+              getFieldDecorator('payType')(
106
+                <Select placeholder="选择缴费方式" style={{ width: '120px' }}>
107
+                  {
108
+                    PayTypesDict.map(x => (<Select.Option key={x.value} value={x.value}>{x.label}</Select.Option>))
109
+                  }
110
+                </Select>
111
+              )
112
+            }
113
+            </Form.Item>
114
+            <Form.Item label="缴费时间">
115
+            {getFieldDecorator('createTime')(
116
+              <RangePicker placeholder={['开始时间', '结束时间']} />
117
+            )}
118
+          </Form.Item>
59 119
           </>
60 120
         )
61 121
       }}
@@ -70,9 +130,18 @@ export default props => {
70 130
   const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
71 131
 
72 132
   const handleSearch = vals => {
133
+    let { createTime, ...submitValue  } = vals
134
+    if (null != createTime && createTime.length > 0) {
135
+      const [startCreateDate, endCreateDate] = createTime
136
+      submitValue.startCreateDate = moment(startCreateDate).format('YYYY-MM-DD');
137
+      submitValue.endCreateDate = moment(endCreateDate).format('YYYY-MM-DD');
138
+    } else {
139
+      submitValue.startCreateDate = null
140
+      submitValue.endCreateDate = null
141
+    }
73 142
     setQueryParams({
74 143
       ...queryParams,
75
-      ...vals,
144
+      ...submitValue,
76 145
       pageNum: 1,
77 146
     })
78 147
   }
@@ -151,12 +220,15 @@ export default props => {
151 220
           dataIndex="orderStatus"
152 221
           key="orderStatus"
153 222
           render={(_, row) => StatusDict[row.orderStatus]}
223
+          sorter={(a, b) => a.orderStatus - b.orderStatus}
154 224
         />
155 225
         <Table.Column title="缴费人手机号" dataIndex="payPhone" key="payPhone" />
156 226
         <Table.Column title="缴费备注" dataIndex="payRemark" key="payRemark" />
157 227
         <Table.Column title="缴费方式" dataIndex="payType" key="payType" render={payType => PayTypeDict[payType]}/>
158
-        <Table.Column title="订单生成时间" dataIndex="createTime" key="createTime" />
159
-        <Table.Column title="缴费完成时间" dataIndex="updateDate" key="updateDate" />
228
+        <Table.Column title="订单生成时间" dataIndex="createDate" key="createDate" 
229
+          sorter={(a, b) => new Date(a.createDate).getTime() - new Date(b.createDate).getTime()}/>
230
+        <Table.Column title="缴费完成时间" dataIndex="createTime" key="createTime" 
231
+          sorter={(a, b) => new Date(a.createTime).getTime() - new Date(b.createTime).getTime()}/>
160 232
       </List>
161 233
 
162 234
     </div>

+ 2
- 0
src/pages/property/building/BatchImport.jsx Bestand weergeven

@@ -32,6 +32,7 @@ export default props => {
32 32
         excelRef.current = files[0]
33 33
         const formData = new FormData()
34 34
         formData.append('file', excelRef.current)
35
+        formData.append("communityId", props.community)
35 36
         
36 37
         setLoading(true)
37 38
         uploadBuildingTreeExcel({ data: formData }).then(res => {
@@ -58,6 +59,7 @@ export default props => {
58 59
 
59 60
     const formData = new FormData()
60 61
     formData.append('file', excelRef.current)
62
+    formData.append("communityId", props.community)
61 63
 
62 64
     setLoading(true)
63 65
     submitBuildingTreeExcel({ data: formData }).then(res => {

+ 85
- 0
src/pages/property/building/components/Building.jsx Bestand weergeven

@@ -0,0 +1,85 @@
1
+import React, { useEffect, useState } from 'react'
2
+import { Tabs, Spin, Button, Icon, Modal, notification } from 'antd'
3
+import { fetch, fetchList, apis } from '@/utils/request'
4
+import Prompt from '@/components/Prompt'
5
+import BuildingUnit from './BuildingUnit'
6
+
7
+const fetchBuildingList = fetch(apis.buildingOwnerInfo.getBuildingList)
8
+const addNode = fetch(apis.buildingOwnerInfo.addNode)
9
+const deleteNode = fetch(apis.buildingOwnerInfo.deleteNode)
10
+
11
+export default props => {
12
+  const [loading, setLoading] = useState(false)
13
+  const [buildingVisible, setBuildingVisible] = useState(false)
14
+  const [buildingList, setBuildingList] = useState([])
15
+
16
+  const handleAddBuilding = v => {
17
+    addNode({ data: {
18
+      id: props.phase.id,
19
+      name: props.phase.name,
20
+      type: 'building',
21
+      nodeNumber: v,
22
+      communityId: props.community,
23
+    }}).then((res) => {
24
+      notification.success({message: '添加成功'})
25
+      setBuildingList(buildingList.concat(res))
26
+    })
27
+    setBuildingVisible(false)
28
+  }
29
+
30
+  const handleDeleteBuilding = building => {
31
+    Modal.confirm({
32
+      title: `确认删除 ${building.name} 数据?`,
33
+      content: '谨慎操作, 数据不可恢复',
34
+      onOk: () => {
35
+        deleteNode({ data: {
36
+          id: building.id,
37
+          name: building.name,
38
+          type: 'unit', // 删除的时候, type 是 unit 。这个接口比较诡异
39
+          nodeNumber: building.name,
40
+        }}).then(() => {
41
+          notification.success({message: '删除成功'})
42
+          setBuildingList(buildingList.filter(x => x.id !== building.id))
43
+        })
44
+
45
+      }
46
+    })
47
+  }
48
+
49
+  useEffect(() => {
50
+    if (props.phase && props.phase.id) {
51
+      setLoading(true)
52
+      fetchBuildingList({params: {phaseId: props.phase.id}}).then(res => {
53
+        setBuildingList(res)
54
+        setLoading(false)
55
+      }).catch(() => setLoading(false))
56
+    }
57
+  }, [props.phase])
58
+
59
+  return (
60
+    <div style={{marginTop: 8}}>
61
+      <Spin spinning={loading}>
62
+        <Tabs
63
+          defaultActiveKey="0"
64
+          type="line"
65
+          tabPosition="left"
66
+          tabBarExtraContent={<Button type="link" onClick={() => setBuildingVisible(true)}><Icon type="plus" />栋</Button>}
67
+        >
68
+        {
69
+          buildingList.map((building, index) => {
70
+            return (
71
+              <Tabs.TabPane
72
+                key={`${index}`}
73
+                tab={<span>{building.name} <Icon type="close" style={{fontSize: '0.8em', color: '#888', marginLeft: 8}} onClick={() => handleDeleteBuilding(building)} /></span>}
74
+              >
75
+                <BuildingUnit building={building} phase={props.phase} community={props.community} />
76
+              </Tabs.TabPane>
77
+            )
78
+          })
79
+        }
80
+        </Tabs>
81
+      </Spin>
82
+      <Prompt visible={buildingVisible} onOk={handleAddBuilding} onCancel={() => setBuildingVisible(false)} placeholder="请填写楼栋名称" />
83
+    </div>
84
+  )
85
+}

+ 97
- 0
src/pages/property/building/components/BuildingLevelCell.jsx Bestand weergeven

@@ -0,0 +1,97 @@
1
+import React, { useEffect, useState } from 'react'
2
+import { Menu, Dropdown, Button, Popconfirm, Icon, notification } from 'antd'
3
+import Prompt from '@/components/Prompt'
4
+import { fetchList, fetch, apis } from '@/utils/request'
5
+
6
+const addNode = fetch(apis.buildingOwnerInfo.addNode)
7
+const updateNode = fetch(apis.buildingOwnerInfo.updateNode)
8
+const deleteNode = fetch(apis.buildingOwnerInfo.deleteNode)
9
+
10
+export default props => {
11
+  const [roomInfo, setRoomInfo] = useState({})
12
+  const [levelVisible, setLevelVisible] = useState(false)
13
+  const [houseVisible, setHouseVisible] = useState(false)
14
+
15
+  const handleEdit = val => {
16
+    updateNode({ data: {
17
+      id: roomInfo.levelId,
18
+      name: val,
19
+      type: 'level',
20
+    }}).then(() => {
21
+      const room = {
22
+        ...roomInfo,
23
+        levelName: val
24
+      }
25
+      if (props.onEdit) {
26
+        props.onEdit(room)
27
+      }
28
+      notification.success({message: '修改成功'})
29
+    })
30
+    setLevelVisible(false)
31
+  }
32
+
33
+  const handleDelete = () => {
34
+    deleteNode({ data: {
35
+      id: roomInfo.levelId,
36
+      name: roomInfo.levelName,
37
+      type: 'roomNo',   // 删除楼层传 roomNo
38
+      nodeNumber: undefined,
39
+    }}).then(() => {
40
+      if (props.onDelete) {
41
+        props.onDelete(roomInfo)
42
+      }
43
+      notification.success({message: '删除成功'})
44
+    })
45
+  }
46
+
47
+  const handleHouseAdd = val => {
48
+    addNode({ data: {
49
+      id: roomInfo.levelId,
50
+      name: roomInfo.levelName,
51
+      type: 'roomNo',
52
+      nodeNumber: val,
53
+      communityId: props.community,
54
+    }}).then((res) => {
55
+      if (props.onHouseAdd) {
56
+        props.onHouseAdd(res)
57
+      }
58
+      notification.success({message: '添加成功'})
59
+    })
60
+    setHouseVisible(false)
61
+  }
62
+
63
+  const menu = (
64
+    <Menu>
65
+      <Menu.Item>
66
+        <Button type="link" onClick={() => setHouseVisible(true)}><Icon type="plus" />房</Button>
67
+      </Menu.Item>
68
+      <Menu.Item>
69
+        <Button type="link" onClick={() => setLevelVisible(true)}>编辑</Button>
70
+      </Menu.Item>
71
+      <Menu.Item>
72
+        <Popconfirm
73
+         title={`确认删除 ${roomInfo.levelName}`}
74
+         onConfirm={handleDelete}
75
+         okText="是"
76
+         cancelText="否"
77
+        >
78
+          <Button type="danger" ghost style={{border: 'none', boxShadow: 'none'}}>删除</Button>
79
+        </Popconfirm>
80
+      </Menu.Item>
81
+    </Menu>
82
+  );
83
+  
84
+  useEffect(() => {
85
+    setRoomInfo(props.dataSource || {})
86
+  }, [props.dataSource])
87
+
88
+  return (
89
+    <span>
90
+      <Dropdown overlay={menu} trigger={['contextMenu']} placement="topCenter">
91
+        <div style={{cursor: 'pointer'}}>{roomInfo.levelName}</div>
92
+      </Dropdown>
93
+      <Prompt visible={levelVisible} onOk={handleEdit} onCancel={() => setLevelVisible(false)} placeholder="请填写楼层名称" />
94
+      <Prompt visible={houseVisible} onOk={handleHouseAdd} onCancel={() => setHouseVisible(false)} placeholder="请填写房室名称" />
95
+    </span>
96
+  )
97
+}

+ 114
- 0
src/pages/property/building/components/BuildingLevelRow.jsx Bestand weergeven

@@ -0,0 +1,114 @@
1
+import React, { useEffect, useMemo, useRef, useState } from 'react'
2
+import { Table, Spin, Menu, Dropdown, Button, Popconfirm, Icon, notification } from 'antd'
3
+import { maxBy } from 'lodash'
4
+import Prompt from '@/components/Prompt'
5
+import { fetchList, fetch, apis } from '@/utils/request'
6
+import BuildingRoomCell from './BuildingRoomCell'
7
+import BuildingLevelCell from './BuildingLevelCell'
8
+import BuildingUnitCell from './BuildingUnitCell'
9
+
10
+const addNode = fetch(apis.buildingOwnerInfo.addNode)
11
+const updateNode = fetch(apis.buildingOwnerInfo.updateNode)
12
+const deleteNode = fetch(apis.buildingOwnerInfo.deleteNode)
13
+
14
+const nvlIdStart = 'tmp'
15
+
16
+export default props => {
17
+  const [dataList, setDataList] = useState([])
18
+  const [roomNum, setRoomNum] = useState(0)
19
+
20
+  // 表格列
21
+  const columns = useMemo(() => {
22
+    const rooms = new Array(roomNum).fill()
23
+
24
+    return [
25
+      // 楼层字段
26
+      {
27
+        title: '#',
28
+        dataIndex: 'levelName',
29
+        key: 'levelName',
30
+        width: 80,
31
+        align: 'center',
32
+        render: (t, row) => (
33
+          <BuildingLevelCell
34
+            dataSource={row}
35
+            community={props.community}
36
+            onHouseAdd={props.onHouseAdd}
37
+            onEdit={props.onLevelEdit}
38
+            onDelete={props.onLevelDelete}
39
+          />
40
+        )
41
+      },
42
+      ...rooms.map((_, index) => ({
43
+        title: `房间 ${index + 1}`,
44
+        dataIndex: `name-${index}`,
45
+        key: `name-${index}`,
46
+        align: 'center',      
47
+        render: (t, row) => (
48
+          <BuildingRoomCell
49
+            dataSource={{
50
+              ...row,
51
+              id: row[`id-${index}`],
52
+              name: row[`name-${index}`]
53
+            }}
54
+            community={props.community}
55
+            onEdit={props.onHouseEdit}
56
+            onDelete={props.onHouseDelete}
57
+          />
58
+        )
59
+      }))
60
+    ]
61
+  }, [roomNum, props])
62
+  
63
+  useEffect(() => {
64
+    const list = (props.dataSource || []).slice()
65
+    if (!list.length) {
66
+      return
67
+    }
68
+
69
+    // 找到 房间最多的那层, 然后所有的楼层都按照这个房间数造数据
70
+    const maxRooms = maxBy(list, x => x.length)
71
+    setRoomNum(maxRooms.length)
72
+
73
+    // 合并同楼层的房间
74
+    const zipedList = list.map(rooms => {
75
+      return maxRooms.reduce((acc, _, index) => {
76
+        const room = rooms[index] || {}
77
+
78
+        return {
79
+          ...acc,
80
+          ...room,
81
+          id: acc.id || room.id || `${nvlIdStart}-${Math.random().toString(36).substring(2)}`,
82
+          [`id-${index}`]: room.id,
83
+          [`name-${index}`]: room.name || '#'
84
+        }
85
+      }, {})
86
+    })
87
+
88
+    setDataList(zipedList)
89
+  }, [props.dataSource])
90
+
91
+  // 任意一个房间数据都可以
92
+  // 因为所有房间的单元信息都是一样的
93
+  const anyRoom = dataList[0]
94
+
95
+  return (
96
+    <div>
97
+      <BuildingUnitCell
98
+        dataSource={anyRoom}
99
+        community={props.community}
100
+        onLevelAdd={props.onLevelAdd}
101
+        onEdit={props.onUnitEdit}
102
+        onDelete={props.onUnitDelete}
103
+      />
104
+      <Table
105
+        columns={columns}
106
+        dataSource={dataList}
107
+        pagination={false}
108
+        rowKey="id"
109
+        size="middle"
110
+        bordered
111
+      />
112
+    </div>
113
+  )
114
+}

+ 96
- 0
src/pages/property/building/components/BuildingRoomCell.jsx Bestand weergeven

@@ -0,0 +1,96 @@
1
+import React, { useEffect, useState } from 'react'
2
+import { Menu, Dropdown, Button, Popconfirm, Icon, notification } from 'antd'
3
+import Prompt from '@/components/Prompt'
4
+import { fetchList, fetch, apis } from '@/utils/request'
5
+
6
+const addNode = fetch(apis.buildingOwnerInfo.addNode)
7
+const updateNode = fetch(apis.buildingOwnerInfo.updateNode)
8
+const deleteNode = fetch(apis.buildingOwnerInfo.deleteNode)
9
+
10
+export default props => {
11
+  const [houseVisible, setHouseVisible] = useState(false)
12
+  const [roomInfo, setRoomInfo] = useState({})
13
+
14
+  const handleDelete = () => {
15
+    deleteNode({ data: {
16
+      id: roomInfo.id,
17
+      name: roomInfo.name,
18
+      type: 'end',   // 删除房间传 end
19
+      nodeNumber: undefined,
20
+    }}).then(() => {
21
+      if (props.onDelete) {
22
+        props.onDelete(roomInfo)
23
+      }
24
+      notification.success({message: '删除成功'})
25
+    })
26
+  }
27
+
28
+  const handleEdit = val => {
29
+    if (!roomInfo.id) {
30
+      addNode({ data: {
31
+        id: roomInfo.levelId,
32
+        name: roomInfo.levelName,
33
+        type: 'roomNo',
34
+        nodeNumber: val,
35
+        communityId: props.community,
36
+      }}).then((res) => {
37
+        if (props.onEdit) {
38
+          props.onEdit(res)
39
+        }
40
+        notification.success({message: '修改成功'})
41
+      })
42
+    } else {
43
+      updateNode({ data: {
44
+        id: roomInfo.id,
45
+        name: val,
46
+        type: 'roomNo',
47
+      }}).then(() => {
48
+        const room = {
49
+          ...roomInfo,
50
+          name: val
51
+        }
52
+
53
+        if (props.onEdit) {
54
+          props.onEdit(room)
55
+        }
56
+        notification.success({message: '修改成功'})
57
+      })
58
+    }
59
+    setHouseVisible(false)
60
+  }
61
+
62
+  const menu = (
63
+    <Menu>
64
+      <Menu.Item>
65
+        <Button type="link" onClick={() => setHouseVisible(true)}>编辑</Button>
66
+      </Menu.Item>
67
+      {
68
+        roomInfo.id && (
69
+          <Menu.Item>
70
+            <Popconfirm
71
+             title={`确认删除 ${roomInfo.name} ?`}
72
+             onConfirm={handleDelete}
73
+             okText="是"
74
+             cancelText="否"
75
+            >
76
+              <Button type="danger" ghost style={{border: 'none', boxShadow: 'none'}}>删除</Button>
77
+            </Popconfirm>
78
+          </Menu.Item>
79
+        )
80
+      }
81
+    </Menu>
82
+  );
83
+
84
+  useEffect(() => {
85
+    setRoomInfo(props.dataSource || {})
86
+  }, [props.dataSource])
87
+
88
+  return (
89
+    <span>
90
+      <Dropdown overlay={menu} trigger={['contextMenu']} placement="topCenter">
91
+        <div style={{cursor: 'pointer'}}>{roomInfo.name}</div>
92
+      </Dropdown>
93
+      <Prompt visible={houseVisible} onOk={handleEdit} onCancel={() => setHouseVisible(false)} placeholder="请填写房室名称" />
94
+    </span>
95
+  )
96
+}

+ 236
- 0
src/pages/property/building/components/BuildingUnit.jsx Bestand weergeven

@@ -0,0 +1,236 @@
1
+import React, { useEffect, useMemo, useState, useCallback } from 'react'
2
+import { Table, Spin, Button, Icon, notification } from 'antd'
3
+import { fetchList, fetch, apis } from '@/utils/request'
4
+import { groupBy, orderBy } from 'lodash'
5
+import Prompt from '@/components/Prompt'
6
+import BuildingLevelRow from './BuildingLevelRow'
7
+
8
+const fetchBuildingList = fetchList(apis.buildingOwnerInfo.getAllRoomNoList)
9
+const addNode = fetch(apis.buildingOwnerInfo.addNode)
10
+const deleteNode = fetch(apis.buildingOwnerInfo.deleteNode)
11
+
12
+const getNumFromStr = str => {
13
+  return ((str || '').match(/\d+/g) || []).join('') - 0
14
+}
15
+
16
+/**
17
+ * 房间排序规则
18
+ * 1、维护内容必须有数字
19
+ * 2、单元 从小到大
20
+ * 3、楼层 从大到小
21
+ * 4、房号 从小到大
22
+ * @param {*} room 
23
+ */
24
+const sortRoomList = roomList => {
25
+  return orderBy(roomList,
26
+    [
27
+      room => getNumFromStr(room.unitName),
28
+      room => getNumFromStr(room.levelName),
29
+      room => getNumFromStr(room.name),
30
+    ],
31
+    [
32
+      'asc',
33
+      'desc',
34
+      'asc'
35
+    ]
36
+  )
37
+}
38
+
39
+export default props => {
40
+  const [loading, setLoading] = useState(false)
41
+  const [unitVisible, setUnitVisible] = useState(false)
42
+  const [roomList, setRoomList] = useState([])
43
+  const [roomGroup, setRoomGroup] = useState({})
44
+  
45
+  const handleAddUnit = v => {
46
+    addNode({ data: {
47
+      id: props.building.id,
48
+      name: props.building.name,
49
+      type: 'unit',
50
+      nodeNumber: v,
51
+      communityId: props.community,
52
+    }}).then((res) => {
53
+      // 构造房间数据
54
+      const roomInfo = {
55
+        ...res,
56
+        unitId: res.id,
57
+        unitName: res.name,
58
+        id: undefined,
59
+        name: undefined,
60
+        levelId: undefined,
61
+        levelName: undefined,
62
+      }
63
+
64
+      setRoomList(roomList.concat(roomInfo))
65
+      notification.success({message: '添加成功'})
66
+    })
67
+    setUnitVisible(false)
68
+  }
69
+
70
+  const handleDeleteUnit = room => {
71
+    setRoomList(roomList.filter(r => r.unitId !== room.unitId))
72
+  }
73
+
74
+  const addHouse = useCallback(
75
+    room => {
76
+      // 如果有空房间, 直接替换空房间,否则新增一条记录
77
+      let nvlRoom = false
78
+  
79
+      let newList = roomList.map(item => {
80
+        if (room.phaseId === item.phaseId &&
81
+          room.buildingId === item.buildingId &&
82
+          room.unitId === item.unitId &&
83
+          room.levelId === item.levelId &&
84
+          !item.id && !nvlRoom) {
85
+            nvlRoom = true
86
+            return room
87
+          } else {
88
+            return item
89
+          }
90
+      })
91
+  
92
+      if (!nvlRoom) {
93
+        newList = newList.concat(room)
94
+      }
95
+  
96
+      setRoomList(sortRoomList(newList))
97
+    },
98
+    [roomList],
99
+  )
100
+
101
+  const handleHouseAdd = room => {
102
+    addHouse(room)
103
+  }
104
+
105
+  // 如果编辑 # 的房间, 实际上是新增房间
106
+  const handleHouseEdit = room => {
107
+    let edited = false
108
+    const newList = roomList.map(r => {
109
+      if (r.id === room.id) {
110
+        edited = true
111
+        return room
112
+      } else {
113
+        return r
114
+      }
115
+    })
116
+
117
+    if (edited) {
118
+      setRoomList(newList)
119
+    } else {
120
+      addHouse(room)
121
+    }
122
+  }
123
+
124
+  const handleHouseDelete = room => {
125
+    let newList = []
126
+    // 如果本层只有一个房间, 那么替换为空, 不删除数据
127
+    const sameLevelRooms = roomList.filter(r => r.levelId === room.levelId)
128
+    if (sameLevelRooms.length === 1) {
129
+      newList = roomList.map(item => {
130
+        if (item.id === room.id) {
131
+          return {
132
+            ...room,
133
+            id: undefined,
134
+            name: undefined,
135
+          }
136
+        } else {
137
+          return item
138
+        }
139
+      })
140
+    } else {
141
+      newList = roomList.filter(r => r.id !== room.id)
142
+    }
143
+    setRoomList(newList)
144
+  }
145
+
146
+  const handleLevelAdd = room => {
147
+    // 如果有空房间,替换空房间
148
+    let nvlRoom = false
149
+  
150
+    let newList = roomList.map(item => {
151
+      if (room.phaseId === item.phaseId &&
152
+        room.buildingId === item.buildingId &&
153
+        room.unitId === item.unitId &&
154
+        !item.levelId && !nvlRoom) {
155
+          nvlRoom = true
156
+          return room
157
+        } else {
158
+          return item
159
+        }
160
+    })
161
+
162
+    if (!nvlRoom) {
163
+      newList = newList.concat(room)
164
+    }
165
+
166
+    setRoomList(sortRoomList(newList))
167
+  }
168
+
169
+  const handleLevelEdit = room => {
170
+    setRoomList(roomList.map(item => {
171
+      return item.levelId === room.levelId ?
172
+        {...item, levelName: room.levelName} :
173
+        item
174
+    }))
175
+  }
176
+
177
+  const handleLevelDelete = room => {
178
+    setRoomList(roomList.filter(r => r.levelId !== room.levelId))
179
+  }
180
+
181
+  useEffect(() => {
182
+    if (props.building && props.phase && props.building.id && props.phase.id) {
183
+      setLoading(true)
184
+      fetchBuildingList({pageNum: 1, pageSize: 9999, phaseId: props.phase.id, buildingId: props.building.id}).then(res => {
185
+        const [list = []] = res || []
186
+        setRoomList(sortRoomList(list))
187
+        setLoading(false)
188
+      }).catch(e => console.error(e) || setLoading(false))
189
+    }
190
+  }, [props.building, props.phase])
191
+
192
+  useEffect(() => {
193
+    const groupByUnit = groupBy(roomList, row => [row.unitId, row.unitName].join(','))
194
+    const groupByLevel = Object.keys(groupByUnit).reduce((acc, key) => {
195
+      const groupWithLevelKey = groupBy(groupByUnit[key], row => [row.levelId, row.levelName].join(','))
196
+      const pureLevelArr = Object.keys(groupWithLevelKey).map(k => groupWithLevelKey[k])
197
+
198
+      return {
199
+        ...acc,
200
+        [key]: pureLevelArr
201
+      }
202
+    }, {})
203
+
204
+    setRoomGroup(groupByLevel)
205
+  }, [roomList])
206
+
207
+  return (
208
+    <div>
209
+      <Button style={{marginLeft: 24}} onClick={() => setUnitVisible(true)}><Icon type="plus" />单元</Button>
210
+      <Spin spinning={loading}>
211
+        <div style={{display: 'flex', overflowX: 'auto'}}>
212
+        {
213
+          Object.keys(roomGroup).map(key => {
214
+            return (
215
+              <div style={{flex: 'none', marginLeft: 48}} key={key}>
216
+                <BuildingLevelRow
217
+                  dataSource={roomGroup[key]}
218
+                  community={props.community}
219
+                  onUnitDelete={handleDeleteUnit}
220
+                  onHouseAdd={handleHouseAdd}
221
+                  onHouseEdit={handleHouseEdit}
222
+                  onHouseDelete={handleHouseDelete}
223
+                  onLevelAdd={handleLevelAdd}
224
+                  onLevelEdit={handleLevelEdit}
225
+                  onLevelDelete={handleLevelDelete}
226
+                />
227
+              </div>
228
+            )
229
+          })
230
+        }
231
+        </div>
232
+      </Spin>
233
+      <Prompt visible={unitVisible} onOk={handleAddUnit} onCancel={() => setUnitVisible(false)} placeholder="请填写单元名称" />
234
+    </div>
235
+  )
236
+}

+ 107
- 0
src/pages/property/building/components/BuildingUnitCell.jsx Bestand weergeven

@@ -0,0 +1,107 @@
1
+import React, { useEffect, useState } from 'react'
2
+import { Menu, Dropdown, Button, Popconfirm, Icon, notification } from 'antd'
3
+import Prompt from '@/components/Prompt'
4
+import { fetchList, fetch, apis } from '@/utils/request'
5
+
6
+const addNode = fetch(apis.buildingOwnerInfo.addNode)
7
+const updateNode = fetch(apis.buildingOwnerInfo.updateNode)
8
+const deleteNode = fetch(apis.buildingOwnerInfo.deleteNode)
9
+
10
+export default props => {
11
+  const [roomInfo, setRoomInfo] = useState({})
12
+  const [unitVisible, setUnitVisible] = useState(false)
13
+  const [levelVisible, setLevelVisible] = useState(false)
14
+  
15
+  const handleEdit = val => {
16
+    updateNode({ data: {
17
+      id: roomInfo.unitId,
18
+      name: val,
19
+      type: 'unit',
20
+    }}).then(() => {
21
+      const room = {
22
+        ...roomInfo,
23
+        unitName: val
24
+      }
25
+      if (props.onEdit) {
26
+        props.onEdit(room)
27
+      }
28
+      notification.success({message: '修改成功'})
29
+    })
30
+    setUnitVisible(false)
31
+  }
32
+
33
+  const handleDelete = () => {
34
+    deleteNode({ data: {
35
+      id: roomInfo.unitId,
36
+      name: roomInfo.unitName,
37
+      type: 'level',   // 删除单元传 level
38
+      nodeNumber: undefined,
39
+    }}).then(() => {
40
+      if (props.onDelete) {
41
+        props.onDelete(roomInfo)
42
+      }
43
+      notification.success({message: '删除成功'})
44
+    })
45
+  }
46
+
47
+  const handleLevelAdd = val => {
48
+    addNode({ data: {
49
+      id: roomInfo.unitId,
50
+      name: roomInfo.unitName,
51
+      type: 'level',
52
+      nodeNumber: val,
53
+      communityId: props.community,
54
+    }}).then((res) => {
55
+      // 构造房间数据
56
+      const room = {
57
+        ...res,
58
+        levelId: res.id,
59
+        levelName: res.name,
60
+        id: undefined,
61
+        name: undefined,
62
+      }
63
+
64
+      if (props.onLevelAdd) {
65
+        props.onLevelAdd(room)
66
+      }
67
+      notification.success({message: '添加成功'})
68
+    })
69
+
70
+    setLevelVisible(false)
71
+  }
72
+
73
+  useEffect(() => {
74
+    setRoomInfo(props.dataSource || {})
75
+  }, [props.dataSource])
76
+
77
+  const menu = (
78
+    <Menu>
79
+      <Menu.Item>
80
+        <Button type="link" onClick={() => setLevelVisible(true)}><Icon type="plus"/>层</Button>
81
+      </Menu.Item>
82
+      <Menu.Item>
83
+        <Button type="link" onClick={() => setUnitVisible(true)}>编辑</Button>
84
+      </Menu.Item>
85
+      <Menu.Item>
86
+        <Popconfirm
87
+         title={`确认删除 ${roomInfo.unitName} ?`}
88
+         onConfirm={handleDelete}
89
+         okText="是"
90
+         cancelText="否"
91
+        >
92
+          <Button type="danger" ghost style={{border: 'none', boxShadow: 'none'}}>删除</Button>
93
+        </Popconfirm>
94
+      </Menu.Item>
95
+    </Menu>
96
+  )
97
+
98
+  return (
99
+    <div style={{textAlign: 'center', fontSize: '1.2em', lineHeight: '3.5em'}} >
100
+      <Dropdown overlay={menu} trigger={['contextMenu']} placement="topCenter">
101
+        <div style={{cursor: 'pointer', height: 60}}>{roomInfo.unitName}</div>
102
+      </Dropdown>
103
+      <Prompt visible={unitVisible} onOk={handleEdit} onCancel={() => setUnitVisible(false)} placeholder="请填写单元名称" />
104
+      <Prompt visible={levelVisible} onOk={handleLevelAdd} onCancel={() => setLevelVisible(false)} placeholder="请填写楼层名称" />
105
+    </div>
106
+  )
107
+}

+ 1
- 1
src/pages/property/building/components/NodeLabel.jsx Bestand weergeven

@@ -21,7 +21,7 @@ export default props => {
21 21
       {
22 22
         props.data.type !== 'end' && (<Menu.Item key="add">增加子节点</Menu.Item>)
23 23
       }
24
-      <Menu.Item key="delete">删除</Menu.Item>
24
+      {/* <Menu.Item key="delete">删除</Menu.Item> */}
25 25
     </Menu>
26 26
   );
27 27
 

+ 104
- 0
src/pages/property/building/list.jsx Bestand weergeven

@@ -0,0 +1,104 @@
1
+import React, { useEffect, useState } from 'react'
2
+import { PageHeader, Tabs, Spin, Button, Icon, Modal, notification } from 'antd'
3
+import router from 'umi/router'
4
+import { fetch, fetchList, apis } from '@/utils/request'
5
+import Prompt from '@/components/Prompt'
6
+import Building from './components/Building'
7
+import CommunitySelect from '@/components/CommunitySelect'
8
+
9
+const fetchPhaseList = fetch(apis.buildingOwnerInfo.getPhaseList)
10
+const addNode = fetch(apis.buildingOwnerInfo.addNode)
11
+const deleteNode = fetch(apis.buildingOwnerInfo.deleteNode)
12
+
13
+export default props => {
14
+  const [phaseList, setPhaseList] = useState([])
15
+  const [loading, setLoading] = useState(false)
16
+  const [phaseVisible, setPhaseVisible] = useState(false)
17
+  const [community, setCommunity] = useState()
18
+
19
+  const handleEdit = (key, act) => {
20
+    const phase = phaseList[key - 0]
21
+
22
+    if (act === 'remove') {
23
+      Modal.confirm({
24
+        title: `确认删除 ${phase.name} 数据?`,
25
+        content: '谨慎操作, 数据不可恢复',
26
+        onOk: () => {
27
+          deleteNode({ data: {
28
+            id: phase.id,
29
+            name: phase.name,
30
+            type: 'building', // 删除的时候, type 是 building 。这个接口比较诡异
31
+            nodeNumber: phase.name,
32
+          }}).then(() => {
33
+            notification.success({message: '删除成功'})
34
+            setPhaseList(phaseList.filter(x => x.id !== phase.id))
35
+          })
36
+
37
+        }
38
+      })
39
+    }
40
+  }
41
+
42
+  const handleBatchImport = () => {
43
+    router.push(`/property/buildingInfo/importExcel?community=${community}`)
44
+  }
45
+
46
+  const handleAddPhase = v => {
47
+    addNode({ data: {
48
+      type: 'phase',
49
+      nodeNumber: v,
50
+      communityId: community,
51
+    }}).then((res) => {
52
+      notification.success({message: '添加成功'})
53
+      setPhaseList(phaseList.concat(res))
54
+    })
55
+    setPhaseVisible(false)
56
+  }
57
+
58
+  // 获取期
59
+  useEffect(() => {
60
+    if (community) {
61
+      setLoading(true)
62
+      fetchPhaseList({params: {communityId: community}}).then(res => {
63
+        setPhaseList(res)
64
+        setLoading(false)
65
+      }).catch(() => setLoading(false))
66
+    }
67
+  }, [community])
68
+
69
+  return (
70
+    <div>
71
+      <PageHeader
72
+        title="楼栋管理"
73
+        backIcon={false}
74
+        extra={<Button type="link" onClick={handleBatchImport}><Icon type="upload"/>批量导入</Button>}
75
+      />
76
+      <div style={{marginTop: 16}}>
77
+        <span style={{display: 'inline-block', marginRight: '1em'}}>选择小区: </span>
78
+        <CommunitySelect style={{minWidth: 200}} value={community} autoInited onChange={v => setCommunity(v)} />
79
+      </div>
80
+      <div style={{marginTop: 16}}>
81
+        <Spin spinning={loading}>
82
+          <Tabs
83
+            defaultActiveKey="0"
84
+            type="editable-card"
85
+            onEdit={handleEdit}
86
+            tabBarExtraContent={<Button type="link" onClick={() => setPhaseVisible(true)}><Icon type="plus" />期</Button>}
87
+            hideAdd={true}
88
+            >
89
+          {
90
+            phaseList.map((phase, index) => {
91
+              return (
92
+                <Tabs.TabPane tab={phase.name} key={`${index}`}>
93
+                  <Building phase={phase} community={community} />
94
+                </Tabs.TabPane>
95
+              )
96
+            })
97
+          }
98
+          </Tabs>
99
+        </Spin>
100
+      </div>
101
+      <Prompt visible={phaseVisible} onOk={handleAddPhase} onCancel={() => setPhaseVisible(false)} placeholder="请填写期数名称" />
102
+    </div>
103
+  )
104
+}

+ 123
- 0
src/pages/property/community/index.jsx Bestand weergeven

@@ -0,0 +1,123 @@
1
+import React, { useEffect, useRef, useState } from 'react'
2
+import { fetchList, fetch, apis } from '@/utils/request'
3
+import moment from 'moment'
4
+import { Icon, Table, Button, Popconfirm, Divider, notification } from 'antd'
5
+import Prompt from '@/components/Prompt'
6
+
7
+const getList = fetchList(apis.community.list)
8
+const updateCommunity = fetch(apis.community.update)
9
+const saveCommunity = fetch(apis.community.save)
10
+const deleteCommunity = fetch(apis.community.delete)
11
+
12
+export default props => {
13
+  const [loading, setLoading] = useState(false)
14
+  const [showPrompt, setShowPrompt] = useState(false)
15
+  const [listData, setListData] = useState([])
16
+  const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 100 })
17
+  const selectedRow = useRef()
18
+
19
+  const handleRowPrepare = row => {
20
+    selectedRow.current = row
21
+    setShowPrompt(true)
22
+  }
23
+
24
+  const handleStatusTrigger = row => {
25
+    // 发布 -> 取消发布
26
+    // 取消发布 -> 发布
27
+    const status = Math.abs(row.status - 1)
28
+    const data = { ...row, status }
29
+    updateCommunity({data, urlData: {id: row.id}}).then(res => {
30
+      notification.success({message: "操作成功"})
31
+      // 触发数据刷新
32
+      setQueryParams({...queryParams})
33
+    })
34
+  }
35
+
36
+  const handleRowEdit = v => {
37
+    if (!selectedRow.current) {
38
+      // 新增
39
+      const data = {name: v}
40
+      saveCommunity({data}).then(res => {
41
+        // 刷新页面
42
+        setQueryParams({...queryParams})
43
+      })
44
+    } else {
45
+      // 修改
46
+      const data = {
47
+        ...selectedRow.current,
48
+        name: v
49
+      }
50
+      updateCommunity({data, urlData: {id: data.id}}).then(res => {
51
+        // 刷新页面
52
+        setQueryParams({...queryParams})
53
+      })
54
+    }
55
+
56
+    setShowPrompt(false)
57
+  }
58
+
59
+  const handleDeleteRow = row => {
60
+    deleteCommunity({ urlData: {id: row.id} }).then(res => {
61
+      Modal.success({
62
+        content: '删除内容成功',
63
+        onOk: () => {
64
+          // 触发数据刷新
65
+          setQueryParams({...queryParams})
66
+        }
67
+      })
68
+    })
69
+  }
70
+
71
+  useEffect(() => {
72
+    setLoading(true)
73
+    getList(queryParams).then(res => {
74
+      const [list] = res
75
+      setListData(list)
76
+      setLoading(false)
77
+    }).catch(e => console.error(e) || setLoading(false))
78
+  }, [queryParams])
79
+
80
+  return (
81
+    <div>
82
+      <div style={{marginBottom: 16}}>
83
+        <Button type="primary" onClick={() => handleRowPrepare()}><Icon type="plug" />新增社区</Button>
84
+      </div>
85
+      <Table loading={loading} dataSource={listData} rowKey="id">
86
+        <Table.Column title="名称" dataIndex="name" key="name" width={480} />
87
+        <Table.Column title="状态" dataIndex="status" key="status" render={t => t === 1 ? '正常' : '未发布'} />
88
+        <Table.Column title="创建时间" dataIndex="createDate" key="createDate" render={t => moment(t).format('YYYY-MM-DD HH:mm')} />
89
+        <Table.Column
90
+          title="操作"
91
+          key="action"
92
+          align="center"
93
+          render={(_, row) => {
94
+            return (
95
+              <>
96
+                <Popconfirm
97
+                  title="确认进行删除操作?"
98
+                  onConfirm={() => handleDeleteRow(row)}
99
+                  okText="删除"
100
+                  cancelText="取消"
101
+                >
102
+                  <Button type="link">删除</Button>
103
+                </Popconfirm>
104
+                <Divider type="vertical" />
105
+                {/* <Popconfirm
106
+                  title={`确认进行${row.status === 1? '取消发布' : '发布'}操作`}
107
+                  onConfirm={() => handleStatusTrigger(row)}
108
+                  okText={row.status === 1? '取消发布' : '发布'}
109
+                  cancelText="取消"
110
+                >
111
+                  <Button type="link">{row.status === 1? '取消发布' : '发布'}</Button>
112
+                </Popconfirm>
113
+                <Divider type="vertical" /> */}
114
+                <Button type="link" onClick={() => handleRowPrepare(row) }>编辑</Button>
115
+              </>
116
+            )
117
+          }}
118
+        />
119
+      </Table>
120
+      <Prompt visible={showPrompt} onOk={handleRowEdit} placeholder="请输入小区名称" />
121
+    </div>
122
+  )
123
+}

+ 135
- 0
src/pages/property/contact/PublicServ.jsx Bestand weergeven

@@ -0,0 +1,135 @@
1
+import React, { useState, useEffect } from 'react'
2
+import { Select, Spin, Table, Button, Form, Input, Divider, Typography, Popconfirm, notification } from 'antd'
3
+import NavLink from 'umi/navlink'
4
+import { fetchList, apis, fetch } from '@/utils/request'
5
+import Search from '../components/Search'
6
+import List from '../components/List'
7
+import Editor from './components/Editor'
8
+
9
+const listTel = fetch(apis.announcement.getTelList)
10
+const deleteTel = fetch(apis.announcement.deleteTel)
11
+const saveTel = fetch(apis.announcement.saveTel)
12
+const updateTel = fetch(apis.announcement.updateTel)
13
+
14
+const Condition = props => {
15
+  return (
16
+    <Search
17
+      onSearch={props.onSearch}
18
+      onReset={props.onReset}
19
+      render={form => {
20
+        const { getFieldDecorator, setFieldsValue } = form
21
+        
22
+        return (
23
+          <>
24
+            <Form.Item label="名称">
25
+            {
26
+              getFieldDecorator('name')(<Input placeholder="名称" />)
27
+            }
28
+            </Form.Item>
29
+            <Form.Item label="电话">
30
+            {
31
+              getFieldDecorator('tel')(<Input placeholder="电话" />)
32
+            }
33
+            </Form.Item>
34
+          </>
35
+        )
36
+      }}
37
+    />
38
+  )
39
+}
40
+
41
+export default props => {
42
+  const telType = "common"
43
+  const [loading, setLoading] = useState(false)
44
+  const [listData, setListData] = useState([])
45
+  const [pagination, setPagination] = useState({})
46
+  const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10, type: telType })
47
+  const [showEditor, setShowEditor] = useState(false)
48
+  const [currentRow, setCurrentRow] = useState()
49
+
50
+  const handleSearch = vals => {
51
+    setQueryParams({
52
+      ...queryParams,
53
+      ...vals,
54
+      pageNum: 1,
55
+    })
56
+  }
57
+
58
+  const handlePageChange = (pageNum, pageSize) => {
59
+    setQueryParams({
60
+      ...queryParams,      
61
+      pageNum,
62
+      pageSize,
63
+    })
64
+  }
65
+
66
+  const triggerShowEditor = row => {
67
+    setShowEditor(!showEditor)
68
+    setCurrentRow({...(row || {})})
69
+  }
70
+
71
+  const handleEditor = vals => {
72
+    if (vals.id) {
73
+      updateTel({data: vals}).then(res => {
74
+        notification.success({message: '信息更新成功'})
75
+        triggerShowEditor()
76
+        setQueryParams({...queryParams})
77
+      })
78
+    } else {
79
+      saveTel({data: vals}).then(res => {
80
+        notification.success({message: '信息保存成功'})
81
+        triggerShowEditor()
82
+        setQueryParams({...queryParams})
83
+      })
84
+    }
85
+  }
86
+
87
+  const handleDeleteRow = row => {
88
+    deleteTel({data: [row.id]}).then(res => {
89
+      notification.success({ message: '删除成功' })
90
+      setQueryParams({...queryParams})
91
+    })
92
+  }
93
+
94
+  useEffect(() => {
95
+    setLoading(true)
96
+    listTel({params: queryParams}).then(res => {
97
+      const {list, ...pagi} = res
98
+      setListData(list)
99
+      setPagination(pagi)
100
+      setLoading(false)
101
+    }).catch(e => setLoading(false))
102
+  }, [queryParams])
103
+
104
+  return (
105
+    <div>
106
+      <Condition onSearch={handleSearch} onReset={handleSearch} />
107
+      <div style={{ margin: '24px 0' }}>
108
+        <Button type="primary" onClick={() => triggerShowEditor()}>添加</Button>
109
+      </div>
110
+      <List dataSource={listData} loading={loading} pagination={pagination} onPageChange={handlePageChange} rowKey="id">
111
+        <Table.Column title="名称" dataIndex="name" key="name" />
112
+        <Table.Column title="电话" dataIndex="tel" key="tel" />
113
+        {/* <Table.Column title="物业类型" dataIndex="type" key="type" render={(item, row) => (
114
+          <span>{item == "prop" ? "物业电话" : "公共服务电话"}</span>
115
+        )}/> */}
116
+        <Table.Column title="备注" dataIndex="remark" key="remark" />
117
+        <Table.Column title="操作" dataIndex="id" key="id" width="200px" render={(_, row) => (
118
+          <>
119
+            <Popconfirm
120
+              title="确认进行删除操作?"
121
+              onConfirm={() => handleDeleteRow(row)}
122
+              okText="删除"
123
+              cancelText="取消"
124
+            >
125
+              <Button type="link">删除</Button>
126
+            </Popconfirm>
127
+            <Divider type="vertical" />
128
+            <Button type="link" onClick={() => triggerShowEditor(row)}>编辑</Button>
129
+          </>
130
+        )} />
131
+      </List>
132
+      <Editor visible={showEditor} type={telType} dataSource={currentRow} onSubmit={handleEditor} onCancel={triggerShowEditor} />
133
+    </div>
134
+  )
135
+}

+ 8
- 9
src/pages/property/contact/components/Editor.jsx Bestand weergeven

@@ -33,7 +33,8 @@ export default Form.create()(props => {
33 33
       if (!err) {
34 34
         props.onSubmit({
35 35
           ...(props.dataSource || {}),
36
-          ...values
36
+          ...values,
37
+          type: props.type,
37 38
         })
38 39
       }
39 40
     })
@@ -67,14 +68,12 @@ export default Form.create()(props => {
67 68
             props.form.getFieldDecorator('remark')(<Input placeholder="请填写备注" />)
68 69
           }
69 70
         </Form.Item>
70
-        <Form.Item label="物业类型">
71
-          {props.form.getFieldDecorator('type')(
72
-            <Select defaultValue="prop" placeholder="物业类型">
73
-              <Option value="prop">物业电话</Option>
74
-              <Option value="common">公共服务</Option>
75
-            </Select>,
76
-          )}
77
-        </Form.Item>
71
+        {/* <Form.Item label="类型">
72
+          <Select value={props.type} disabled placeholder="物业类型">
73
+            <Option value="prop">物业电话</Option>
74
+            <Option value="common">公共服务</Option>
75
+          </Select>,
76
+        </Form.Item> */}
78 77
         <Form.Item {...tailFormItemLayout}>
79 78
           <Button type="primary" htmlType="submit">确定</Button>
80 79
           <Button onClick={props.onCancel} style={{ marginLeft: '48px' }}>取消</Button>

+ 30
- 8
src/pages/property/contact/index.jsx Bestand weergeven

@@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react'
2 2
 import { Select, Spin, Table, Button, Form, Input, Divider, Typography, Popconfirm, notification } from 'antd'
3 3
 import NavLink from 'umi/navlink'
4 4
 import { fetchList, apis, fetch } from '@/utils/request'
5
+import CommunitySelect from '@/components/CommunitySelect'
5 6
 import Search from '../components/Search'
6 7
 import List from '../components/List'
7 8
 import Editor from './components/Editor'
@@ -12,6 +13,14 @@ const saveTel = fetch(apis.announcement.saveTel)
12 13
 const updateTel = fetch(apis.announcement.updateTel)
13 14
 
14 15
 const Condition = props => {
16
+  const [communityId, setCommunityId] = useState()
17
+
18
+  const handleCommunityChange = v => {
19
+    setCommunityId(v)
20
+
21
+    props.onCommunityChange(v)
22
+  }
23
+
15 24
   return (
16 25
     <Search
17 26
       onSearch={props.onSearch}
@@ -21,6 +30,9 @@ const Condition = props => {
21 30
         
22 31
         return (
23 32
           <>
33
+            <Form.Item label="小区">
34
+              <CommunitySelect value={communityId} onChange={handleCommunityChange} autoInited />
35
+            </Form.Item>
24 36
             <Form.Item label="名称">
25 37
             {
26 38
               getFieldDecorator('name')(<Input placeholder="名称" />)
@@ -39,12 +51,14 @@ const Condition = props => {
39 51
 }
40 52
 
41 53
 export default props => {
54
+  const telType = "prop"
42 55
   const [loading, setLoading] = useState(false)
43 56
   const [listData, setListData] = useState([])
44 57
   const [pagination, setPagination] = useState({})
45
-  const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
58
+  const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10, type: telType })
46 59
   const [showEditor, setShowEditor] = useState(false)
47 60
   const [currentRow, setCurrentRow] = useState()
61
+  const [communityId, setCommunityId] = useState()
48 62
 
49 63
   const handleSearch = vals => {
50 64
     setQueryParams({
@@ -68,6 +82,11 @@ export default props => {
68 82
   }
69 83
 
70 84
   const handleEditor = vals => {
85
+    if (!communityId) {
86
+      notification.warn({message: '请选择小区'})
87
+      return
88
+    }
89
+
71 90
     if (vals.id) {
72 91
       updateTel({data: vals}).then(res => {
73 92
         notification.success({message: '信息更新成功'})
@@ -75,7 +94,7 @@ export default props => {
75 94
         setQueryParams({...queryParams})
76 95
       })
77 96
     } else {
78
-      saveTel({data: vals}).then(res => {
97
+      saveTel({data: {...vals, communityId}}).then(res => {
79 98
         notification.success({message: '信息保存成功'})
80 99
         triggerShowEditor()
81 100
         setQueryParams({...queryParams})
@@ -91,27 +110,30 @@ export default props => {
91 110
   }
92 111
 
93 112
   useEffect(() => {
113
+    if (!communityId) {
114
+      return
115
+    }
94 116
     setLoading(true)
95
-    listTel({params: queryParams}).then(res => {
117
+    listTel({params: {...queryParams, communityId}}).then(res => {
96 118
       const {list, ...pagi} = res
97 119
       setListData(list)
98 120
       setPagination(pagi)
99 121
       setLoading(false)
100 122
     }).catch(e => setLoading(false))
101
-  }, [queryParams])
123
+  }, [queryParams, communityId])
102 124
 
103 125
   return (
104 126
     <div>
105
-      <Condition onSearch={handleSearch} onReset={handleSearch} />
127
+      <Condition onSearch={handleSearch} onReset={handleSearch} onCommunityChange={v => setCommunityId(v)} />
106 128
       <div style={{ margin: '24px 0' }}>
107 129
         <Button type="primary" onClick={() => triggerShowEditor()}>添加</Button>
108 130
       </div>
109 131
       <List dataSource={listData} loading={loading} pagination={pagination} onPageChange={handlePageChange} rowKey="id">
110 132
         <Table.Column title="名称" dataIndex="name" key="name" />
111 133
         <Table.Column title="电话" dataIndex="tel" key="tel" />
112
-        <Table.Column title="物业类型" dataIndex="type" key="type" render={(item, row) => (
134
+        {/* <Table.Column title="物业类型" dataIndex="type" key="type" render={(item, row) => (
113 135
           <span>{item == "prop" ? "物业电话" : "公共服务电话"}</span>
114
-        )}/>
136
+        )}/> */}
115 137
         <Table.Column title="备注" dataIndex="remark" key="remark" />
116 138
         <Table.Column title="操作" dataIndex="id" key="id" width="200px" render={(_, row) => (
117 139
           <>
@@ -128,7 +150,7 @@ export default props => {
128 150
           </>
129 151
         )} />
130 152
       </List>
131
-      <Editor visible={showEditor} dataSource={currentRow} onSubmit={handleEditor} onCancel={triggerShowEditor} />
153
+      <Editor visible={showEditor} type={telType} dataSource={currentRow} onSubmit={handleEditor} onCancel={triggerShowEditor} />
132 154
     </div>
133 155
   )
134 156
 }

+ 15
- 3
src/pages/property/lifeConsultant/index.jsx Bestand weergeven

@@ -2,12 +2,20 @@ import React, { useState, useEffect } from 'react'
2 2
 import { Select, Spin, Table, Button, Form, Input, Divider, Modal, Rate, Popconfirm } from 'antd'
3 3
 import NavLink from 'umi/navlink'
4 4
 import { fetchList, apis, fetch } from '@/utils/request'
5
+import CommunitySelect from '@/components/CommunitySelect'
5 6
 import Search from '../components/Search'
6 7
 import List from '../components/List'
7 8
 
8 9
 const lifeConsultant = fetchList(apis.propUser.lifeConsultant)
9 10
 
10 11
 const Condition = props => {
12
+  const [communityId, setCommunityId] = useState()
13
+
14
+  const handleCommunityChange = v => {
15
+    setCommunityId(v)
16
+
17
+    props.onCommunityChange(v)
18
+  }
11 19
   return (
12 20
     <Search
13 21
       onSearch={props.onSearch}
@@ -17,6 +25,9 @@ const Condition = props => {
17 25
         
18 26
         return (
19 27
           <>
28
+            <Form.Item label="小区">
29
+              <CommunitySelect value={communityId} onChange={handleCommunityChange} autoInited />
30
+            </Form.Item>
20 31
             <Form.Item label="管家名称">
21 32
             {
22 33
               getFieldDecorator('userName')(<Input placeholder="管家名称" />)
@@ -39,6 +50,7 @@ export default props => {
39 50
   const [listData, setListData] = useState([])
40 51
   const [pagination, setPagination] = useState({})
41 52
   const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
53
+  const [communityId, setCommunityId] = useState()
42 54
 
43 55
   const handleSearch = vals => {
44 56
     setQueryParams({
@@ -58,17 +70,17 @@ export default props => {
58 70
 
59 71
   useEffect(() => {
60 72
     setLoading(true)
61
-    lifeConsultant(queryParams).then(res => {
73
+    lifeConsultant({...queryParams, communityId}).then(res => {
62 74
       const [list, pageInfo] = res || {}
63 75
       setListData(list)
64 76
       setPagination(pageInfo)
65 77
       setLoading(false)
66 78
     }).catch(() => setLoading(false))
67
-  }, [queryParams])
79
+  }, [queryParams, communityId])
68 80
 
69 81
   return (
70 82
     <div>
71
-      <Condition onSearch={handleSearch} onReset={handleSearch} />
83
+      <Condition onSearch={handleSearch} onReset={handleSearch} onCommunityChange={v => setCommunityId(v)} />
72 84
       <div style={{ margin: '24px 0' }}>
73 85
         {/* <NavLink to={`/staff/editStaff`}>
74 86
           <Button type="primary">添加管家</Button>

+ 3
- 2
src/pages/property/message/event/components/Preview.jsx Bestand weergeven

@@ -2,11 +2,12 @@ import React, { useEffect, useState } from 'react'
2 2
 import moment from 'moment'
3 3
 import { Modal } from 'antd'
4 4
 import Styles from './style.less'
5
+import { APIBaseURL } from '@/utils/constant'
5 6
 
6 7
 export default props => {
7 8
   const baseURL = props.dataSource.evtType === 'birthday'
8
-    ? 'https://xs.ycjcjy.com/shengrih5.html'
9
-    : 'https://xs.ycjcjy.com/jierih5.html'
9
+    ? `${APIBaseURL}shengrih5.html`
10
+    : `${APIBaseURL}jierih5.html`
10 11
 
11 12
   const queryString = [
12 13
     `name=${encodeURIComponent(' 张xx (先生)')}`,

+ 21
- 3
src/pages/property/news/index.jsx Bestand weergeven

@@ -1,10 +1,13 @@
1 1
 import React, { useState, useEffect } from 'react'
2
-import { Select, Spin, Table, Button, Form, Input, Divider, Modal, Popconfirm, Typography, notification } from 'antd'
2
+import { Select, Spin, Table, Button, Form, Input, Divider, Modal, Popconfirm, Typography, notification, DatePicker } from 'antd'
3 3
 import NavLink from 'umi/navlink'
4
+import moment from 'moment';
4 5
 import { fetch, fetchList, apis } from '@/utils/request'
5 6
 import Search from '../components/Search'
6 7
 import List from '../components/List'
7 8
 
9
+const { MonthPicker, RangePicker, WeekPicker } = DatePicker;
10
+
8 11
 const getNewsList = fetchList(apis.propNews.getNewsList)
9 12
 const updateNews = fetch(apis.propNews.updateNews)
10 13
 const deleteNews = fetch(apis.propNews.deleteNews)
@@ -36,6 +39,12 @@ const Condition = props => {
36 39
               getFieldDecorator('newsName')(<Input placeholder="标题" />)
37 40
             }
38 41
             </Form.Item>
42
+            <Form.Item>
43
+            <span style={{ marginRight: '10px' }}>创建时间:</span>
44
+            {getFieldDecorator('createTime')(
45
+              <RangePicker placeholder={['开始时间', '结束时间']} />
46
+            )}
47
+          </Form.Item>
39 48
           </>
40 49
         )
41 50
       }}
@@ -56,9 +65,18 @@ export default props => {
56 65
   const [typeList, setTypeList] = useState([])
57 66
 
58 67
   const handleSearch = vals => {
68
+    let { createTime, ...submitValue  } = vals
69
+    if (null != createTime && createTime.length > 0) {
70
+      const [startCreateDate, endCreateDate] = createTime
71
+      submitValue.startCreateDate = moment(startCreateDate).format('YYYY-MM-DD');
72
+      submitValue.endCreateDate = moment(endCreateDate).format('YYYY-MM-DD');
73
+    } else {
74
+      submitValue.startCreateDate = null
75
+      submitValue.endCreateDate = null
76
+    }
59 77
     setQueryParams({
60 78
       ...queryParams,
61
-      ...vals,
79
+      ...submitValue,
62 80
       pageNum: 1,
63 81
     })
64 82
   }
@@ -120,7 +138,7 @@ export default props => {
120 138
         </NavLink>
121 139
       </div>
122 140
       <List dataSource={listData} loading={loading} pagination={pagination} onPageChange={handlePageChange} rowKey="newsId">
123
-        <Table.Column title="#ID" dataIndex="newsId" key="newsId" />
141
+        {/* <Table.Column title="#ID" dataIndex="newsId" key="newsId" /> */}
124 142
         <Table.Column
125 143
           title="分类"
126 144
           dataIndex="newsTypeId"

+ 14
- 1
src/pages/property/notice/Edit.jsx Bestand weergeven

@@ -1,9 +1,10 @@
1 1
 import React, { useEffect, useState } from 'react'
2 2
 import router from 'umi/router'
3 3
 import { fetch, apis } from '@/utils/request'
4
-import { Button, Form, Input, InputNumber, Modal, Radio, Select } from 'antd'
4
+import { Button, Form, Input, InputNumber, Modal, notification, Radio, Select } from 'antd'
5 5
 import Wangedit from '@/components/Wangedit/Wangedit'
6 6
 import ImageUpload from '@/components/uploadImage/ImageUpload'
7
+import CommunitySelect from '@/components/CommunitySelect'
7 8
 
8 9
 const formItemLayout = {
9 10
   labelCol: {
@@ -86,6 +87,18 @@ export default Form.create()(props => {
86 87
   return (
87 88
     <div>
88 89
       <Form {...formItemLayout} onSubmit={handleSubmit}>
90
+        <Form.Item label="小区">
91
+        {
92
+          getFieldDecorator('communityId', {
93
+            rules: [
94
+              {
95
+                required: true,
96
+                message: '请选择小区',
97
+              },
98
+            ],
99
+          })(<CommunitySelect />)
100
+        }
101
+        </Form.Item>
89 102
         <Form.Item label="类型">
90 103
         {
91 104
           getFieldDecorator('annType')(

+ 68
- 14
src/pages/property/notice/index.jsx Bestand weergeven

@@ -1,15 +1,27 @@
1 1
 import React, { useState, useEffect } from 'react'
2
-import { Select, Spin, Table, Button, Form, Input, Divider, Modal,Popconfirm, notification } from 'antd'
2
+import { Select, Spin, Table, Button, Form, Input, Divider, Modal,Popconfirm, notification, DatePicker } from 'antd'
3 3
 import NavLink from 'umi/navlink'
4
+import moment from 'moment';
4 5
 import { fetch, apis } from '@/utils/request'
6
+import CommunitySelect from '@/components/CommunitySelect'
5 7
 import Search from '../components/Search'
6 8
 import List from '../components/List'
7 9
 
10
+const { MonthPicker, RangePicker, WeekPicker } = DatePicker;
11
+
8 12
 const listAnnouncement = fetch(apis.announcement.listAnnouncement)
9 13
 const deleteAnnouncement = fetch(apis.announcement.deleteAnnouncement)
10 14
 const updateannouncement = fetch(apis.announcement.updateannouncement)
11 15
 
12 16
 const Condition = props => {
17
+  const [communityId, setCommunityId] = useState()
18
+  
19
+  const handleCommunityChange = v => {
20
+    setCommunityId(v)
21
+
22
+    props.onCommunityChange(v)
23
+  }
24
+
13 25
   return (
14 26
     <Search
15 27
       onSearch={props.onSearch}
@@ -19,6 +31,11 @@ const Condition = props => {
19 31
         
20 32
         return (
21 33
           <>
34
+            <Form.Item label="小区">
35
+            {
36
+              <CommunitySelect value={communityId} onChange={handleCommunityChange} autoInited />
37
+            }
38
+            </Form.Item>
22 39
             <Form.Item label="公告编号">
23 40
             {
24 41
               getFieldDecorator('announcementNumber')(<Input placeholder="公告编号" />)
@@ -39,6 +56,22 @@ const Condition = props => {
39 56
               )
40 57
             }
41 58
             </Form.Item>
59
+            <Form.Item label="状态">
60
+            {
61
+              getFieldDecorator('status')(
62
+                <Select style={{minWidth: '120px'}}>
63
+                  <Select.Option value="">全部</Select.Option>
64
+                  <Select.Option value="0">未发布</Select.Option>
65
+                  <Select.Option value="1">已发布</Select.Option>
66
+                </Select>
67
+              )
68
+            }
69
+            </Form.Item>
70
+            <Form.Item label="创建时间">
71
+            {getFieldDecorator('createTime')(
72
+              <RangePicker placeholder={['开始时间', '结束时间']} />
73
+            )}
74
+          </Form.Item>
42 75
           </>
43 76
         )
44 77
       }}
@@ -55,25 +88,44 @@ const StatusDict = {
55 88
 export default props => {
56 89
   const [loading, setLoading] = useState(false)
57 90
   const [listData, setListData] = useState([])
91
+  const [communityId, setCommunityId] = useState()
58 92
   const [pagination, setPagination] = useState({})
59 93
   const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
60 94
 
61 95
   const handleSearch = vals => {
96
+    let { createTime, ...submitValue  } = vals
97
+    if (null != createTime && createTime.length > 0) {
98
+      const [startCreateDate, endCreateDate] = createTime
99
+      submitValue.startCreateDate = moment(startCreateDate).format('YYYY-MM-DD');
100
+      submitValue.endCreateDate = moment(endCreateDate).format('YYYY-MM-DD');
101
+    } else {
102
+      submitValue.startCreateDate = null
103
+      submitValue.endCreateDate = null
104
+    }
62 105
     setQueryParams({
63 106
       ...queryParams,
64
-      ...vals,
107
+      ...submitValue,
65 108
       pageNum: 1,
66 109
     })
67 110
   }
68 111
 
69 112
   const handleEditRow = row => {
70
-    updateannouncement({data: {
71
-      ...row,
72
-      status: Math.abs(row.status - 1)
73
-    }}).then(res => {
74
-      notification.success({message: '操作成功'})
75
-      setQueryParams({...queryParams})
76
-    })
113
+    // 发布改为不发布, 调用删除接口
114
+    if (1 === row.status - 0) {
115
+      deleteAnnouncement({data: {id: [row.id]}}).then(res => {
116
+        notification.success({message: '取消发布成功'})
117
+        setQueryParams({...queryParams})
118
+      })
119
+    } else {
120
+      // 未发布修改为已发布
121
+      updateannouncement({data: {
122
+        ...row,
123
+        status: '1'
124
+      }}).then(res => {
125
+        notification.success({message: '发布成功'})
126
+        setQueryParams({...queryParams})
127
+      })
128
+    }
77 129
   }
78 130
 
79 131
   const handlePageChange = (pageNum, pageSize) => {
@@ -86,24 +138,24 @@ export default props => {
86 138
 
87 139
   useEffect(() => {
88 140
     setLoading(true)
89
-    listAnnouncement({ data: queryParams }).then(res => {
141
+    listAnnouncement({ data: {...queryParams, communityId} }).then(res => {
90 142
       const { list, ...pageInfo } = res || {}
91 143
       setListData(list)
92 144
       setPagination(pageInfo)
93 145
       setLoading(false)
94 146
     }).catch(() => setLoading(false))
95
-  }, [queryParams])
147
+  }, [queryParams, communityId])
96 148
 
97 149
   return (
98 150
     <div>
99
-      <Condition onSearch={handleSearch} onReset={handleSearch} />
151
+      <Condition onSearch={handleSearch} onReset={handleSearch} onCommunityChange={v => setCommunityId(v)} />
100 152
       <div style={{ margin: '24px 0' }}>
101 153
         <NavLink to={`/property/notice/edit`}>
102 154
           <Button type="primary">添加</Button>
103 155
         </NavLink>
104 156
       </div>
105 157
       <List dataSource={listData} loading={loading} pagination={pagination} onPageChange={handlePageChange} rowKey="id">
106
-        <Table.Column title="编号" dataIndex="id" key="id" />
158
+        {/* <Table.Column title="编号" dataIndex="id" key="id" /> */}
107 159
         <Table.Column title="类型" dataIndex="annType" key="annType" render={t => t === 'notice' ? '提醒' : null} />
108 160
         <Table.Column
109 161
           title="标题"
@@ -123,8 +175,10 @@ export default props => {
123 175
           dataIndex="status"
124 176
           key="status"
125 177
           render={(_, row) => StatusDict[row.status]}
178
+          sorter={(a, b) => a.status - b.status}
126 179
         />
127
-        <Table.Column title="创建时间" dataIndex="createDate" key="createDate" />
180
+        <Table.Column title="创建时间" dataIndex="createDate" key="createDate" 
181
+        sorter={(a, b) => new Date(a.createDate).getTime() - new Date(b.createDate).getTime()}/>
128 182
         {/* <Table.Column title="发布人" dataIndex="createUserName" key="createUserName" />
129 183
         <Table.Column title="修改时间" dataIndex="updateDate" key="updateDate" />
130 184
         <Table.Column title="修改人" dataIndex="updateDateName" key="updateDateName" /> */}

+ 19
- 11
src/pages/property/proprietor/Add.jsx Bestand weergeven

@@ -3,6 +3,7 @@ import { Form, Input, Select, Button, Radio, Modal, Descriptions } from 'antd'
3 3
 import router from 'umi/router'
4 4
 import { fetch, apis } from '@/utils/request'
5 5
 import useRoomSelect from '../utils/hooks/useRoomSelect'
6
+import CommunitySelect from '@/components/CommunitySelect'
6 7
 
7 8
 const addPerson = fetch(apis.buildingOwnerInfo.addBuilding)
8 9
 const taUserHasOwner = fetch(apis.propUser.taUserHasOwner)
@@ -35,6 +36,7 @@ const tailFormItemLayout = {
35 36
 const isEmpty = o => !o || (Array.isArray(o) && !o.length) || (typeof o === 'object' && !Object.keys(o).length)
36 37
 
37 38
 export default Form.create()(props => {
39
+  const [communityId, setCommunityId] = useState()
38 40
   const {
39 41
     phaseId,
40 42
     setPhaseId,
@@ -51,7 +53,7 @@ export default Form.create()(props => {
51 53
     unitList,
52 54
     levelList,
53 55
     roomNoList
54
-  } = useRoomSelect()
56
+  } = useRoomSelect(communityId)
55 57
 
56 58
   const [owerExist, setOwnerExist] = useState(false)
57 59
   const [telAccUser, setTelAccUser] = useState()
@@ -74,21 +76,12 @@ export default Form.create()(props => {
74 76
 
75 77
   useEffect(() => {
76 78
     if (roomNoId) {
77
-      taUserHasOwner({ params: {phaseId, buildingId, unitId, levelId, roomNoId} }).then(res => {
79
+      taUserHasOwner({ params: {communityId, phaseId, buildingId, unitId, levelId, roomNoId} }).then(res => {
78 80
         setOwnerExist(res.boolRole)
79 81
       })
80 82
     }
81 83
   }, [roomNoId])
82 84
   
83
-  useEffect(() => {
84
-    if (roomNoId) {
85
-      taUserHasOwner({ params: {phaseId, buildingId, unitId, levelId, roomNoId} }).then(res => {
86
-        setOwnerExist(res.boolRole)
87
-      })
88
-    }
89
-  }, [roomNoId])
90
-
91
-
92 85
   const handleSubmit = e => {
93 86
     e.preventDefault();
94 87
     if (!isEmpty(telAccUser)) {
@@ -99,6 +92,7 @@ export default Form.create()(props => {
99 92
       if (!err) {
100 93
         const data = {
101 94
           ...values,
95
+          communityId,
102 96
           phaseId,
103 97
           buildingId,
104 98
           unitId,
@@ -121,6 +115,9 @@ export default Form.create()(props => {
121 115
   return (
122 116
     <div>
123 117
       <Form {...formItemLayout} onSubmit={handleSubmit}>
118
+        <Form.Item label="小区" required>
119
+          <CommunitySelect value={communityId} onChange={v => setCommunityId(v)} autoInited />
120
+        </Form.Item>
124 121
         <Form.Item label="期/区" required>
125 122
           <Select value={phaseId} onChange={handlePhaseChange} style={{ minWidth: '120px' }} placeholder="期/区">
126 123
             {
@@ -182,6 +179,17 @@ export default Form.create()(props => {
182 179
             props.form.getFieldDecorator('ownerName')(<Input />)
183 180
           }
184 181
         </Form.Item>
182
+        <Form.Item label="身份证号">
183
+          {
184
+            props.form.getFieldDecorator('idCard', {
185
+              rules: [
186
+                {
187
+                  len: 18, message: '身份证号长度为18位'
188
+                }
189
+              ]
190
+            })(<Input />)
191
+          }
192
+        </Form.Item>
185 193
         <Form.Item label="性别">
186 194
           {
187 195
             props.form.getFieldDecorator('gender')(

+ 70
- 4
src/pages/property/proprietor/Audit.jsx Bestand weergeven

@@ -4,8 +4,16 @@ import { fetch, fetchList, apis } from '@/utils/request'
4 4
 import Search from '../components/Search'
5 5
 import List from '../components/List'
6 6
 import AuditNot from './components/AuditNot'
7
+import CommunitySelect from '@/components/CommunitySelect'
7 8
 
8 9
 const Condition = props => {
10
+  const [communityId, setCommunityId] = useState()
11
+
12
+  const handleCommunityChange = v => {
13
+    props.onCommunityChange(v)
14
+    setCommunityId(v)
15
+  }
16
+
9 17
   return (
10 18
     <Search
11 19
       onSearch={props.onSearch}
@@ -15,6 +23,11 @@ const Condition = props => {
15 23
 
16 24
         return (
17 25
           <>
26
+            <Form.Item label="小区">
27
+            {
28
+              <CommunitySelect autoInited value={communityId} onChange={handleCommunityChange} />
29
+            }
30
+            </Form.Item>
18 31
             <Form.Item label="姓名">
19 32
             {
20 33
               getFieldDecorator('userName')(<Input style={{ width: '160px' }} placeholder="姓名" />)
@@ -50,8 +63,10 @@ export default props => {
50 63
   const [loading, setLoading] = useState(false)
51 64
   const [noPassShow, setNoPassShow] = useState(false)
52 65
   const [listData, setListData] = useState([])
66
+  const [selectedKeys, setSelectedKeys] = useState([])
53 67
   const [pagination, setPagination] = useState({})
54 68
   const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
69
+  const [communityId, setCommunityId] = useState()
55 70
 
56 71
   const currentRow = useRef()
57 72
   
@@ -59,10 +74,18 @@ export default props => {
59 74
     setQueryParams({
60 75
       ...queryParams,
61 76
       ...vals,
77
+      communityId,
62 78
       pageNum: 1
63 79
     })
64 80
   }
65 81
 
82
+  const rowSelection = {
83
+    onChange: (selectedRowKeys, selectedRows) => {
84
+      // console.log('------>', selectedRowKeys)
85
+      setSelectedKeys(selectedRowKeys)
86
+    }
87
+  }
88
+
66 89
   const handleDeleteRow = row => {}
67 90
 
68 91
   const showAuditDialog = row => {
@@ -99,6 +122,7 @@ export default props => {
99 122
     const row = {
100 123
       ...currentRow.current,
101 124
       ...vals,
125
+      communityId,
102 126
     }
103 127
 
104 128
     handleVerfiy(row, false)
@@ -113,23 +137,65 @@ export default props => {
113 137
     })
114 138
   }
115 139
 
140
+  const handleChangeSelected = (verifyStatus) => {
141
+      selectedKeys.map(x => {
142
+         const params = {
143
+            verifyStatus,
144
+            remark: ''
145
+          }
146
+      
147
+          userVerifyAudit({ urlData: { id: x }, params }).then(res => {
148
+              console.log(res)
149
+          })
150
+      })
151
+      Modal.success({
152
+        content: '审核提交成功',
153
+        onOk: () => {
154
+          // 触发数据刷新
155
+          setQueryParams({...queryParams})
156
+        }
157
+      })
158
+  }
159
+
116 160
   useEffect(() => {
117 161
     setLoading(true)
118
-    userVerifyAll(queryParams).then(res => {
162
+    userVerifyAll({...queryParams, communityId}).then(res => {
119 163
       const [records, pagi] = res || []
120 164
       setListData(records)
121 165
       setPagination({total: pagi.total, pageSize: pagi.size, pageNum: pagi.current})
122 166
       setLoading(false)
123 167
     }).catch(() => setLoading(false))
124
-  }, [queryParams])
168
+  }, [queryParams, communityId])
125 169
 
126 170
   return (
127 171
     <div>
128
-      <Condition onSearch={handleSearch} onSearch={handleSearch} />
172
+      <Condition onSearch={handleSearch} onSearch={handleSearch} onCommunityChange={v => setCommunityId(v)} />
173
+      <div style={{ margin: '24px 0' }}>
174
+        <div style={{marginLeft: 16, display: 'inline-block'}}>
175
+          <Popconfirm
176
+            title="确认进行批量审核通过操作?"
177
+            onConfirm={() => handleChangeSelected(true)}
178
+            okText="确定"
179
+            cancelText="取消"
180
+          >
181
+            <Button type="danger" disabled={!selectedKeys.length}>批量通过</Button>
182
+          </Popconfirm>
183
+        </div>
184
+        <div style={{marginLeft: 16, display: 'inline-block'}}>
185
+          <Popconfirm
186
+            title="确认进行批量审核不通过操作?"
187
+            onConfirm={() => handleChangeSelected(false)}
188
+            okText="确定"
189
+            cancelText="取消"
190
+          >
191
+            <Button type="danger" disabled={!selectedKeys.length}>批量不通过</Button>
192
+          </Popconfirm>
193
+        </div>
194
+      </div>
129 195
       <div style={{ marginTop: '24px' }}>
130 196
         <p style={{color: '#888', fontSize: '0.8em'}}>注意,审核后无法修改审核结果,请仔细确认</p>
131 197
       </div>
132
-      <List dataSource={listData} onPageChange={handlePageChange} pagination={pagination} loading={loading} rowKey="id">
198
+      <List dataSource={listData} onPageChange={handlePageChange} pagination={pagination} rowSelection={rowSelection} loading={loading} rowKey="id">
133 199
         <Table.Column title="姓名" dataIndex="ownerName" key="ownerName" />
134 200
         <Table.Column title="手机号" dataIndex="phone" key="phone" />
135 201
         <Table.Column title="身份证" dataIndex="idCard" key="idCard" />

+ 26
- 2
src/pages/property/proprietor/BatchImport.jsx Bestand weergeven

@@ -15,10 +15,24 @@ export default props => {
15 15
   const [dataList, setDataList] = useState([])
16 16
   const [pagenavi, setPagenavi] = useState({ pageSize: 10, total: 0 })
17 17
 
18
+  const communityId = props.location.query.community
18 19
   const excelRef = useRef()
19 20
 
21
+  const checkCommunity = () => {
22
+    if (!communityId) {
23
+      notification.warn({message: '没有选择小区'})
24
+      return false
25
+    }
26
+
27
+    return true
28
+  }
29
+
20 30
   const downloadExcel = () => {
21
-    buildingDownloadExcel().then(res => {
31
+    if (!checkCommunity()) {
32
+      return
33
+    }
34
+
35
+    buildingDownloadExcel({params: {communityId}}).then(res => {
22 36
       const url = window.URL.createObjectURL(new Blob([res]))
23 37
       const link = document.createElement('a')
24 38
       link.href = url
@@ -28,6 +42,10 @@ export default props => {
28 42
   }
29 43
 
30 44
   const importExcel = () => {
45
+    if (!checkCommunity()) {
46
+      return
47
+    }
48
+
31 49
     const input = document.createElement('input')
32 50
     input.setAttribute('type', 'file')
33 51
     input.addEventListener('input', e => {
@@ -36,6 +54,7 @@ export default props => {
36 54
         excelRef.current = files[0]
37 55
         const formData = new FormData()
38 56
         formData.append('file', excelRef.current)
57
+        formData.append('communityId', communityId)
39 58
         
40 59
         setLoading(true)
41 60
         uploadBuildingExcel({ data: formData }).then(res => {
@@ -55,6 +74,10 @@ export default props => {
55 74
   }
56 75
 
57 76
   const submitExcel = () => {
77
+    if (!checkCommunity()) {
78
+      return
79
+    }
80
+
58 81
     if (!excelRef.current) {
59 82
       notification.warning({ message: '没有选择文件' })
60 83
       return
@@ -62,6 +85,7 @@ export default props => {
62 85
 
63 86
     const formData = new FormData()
64 87
     formData.append('file', excelRef.current)
88
+    formData.append('communityId', communityId)
65 89
 
66 90
     setLoading(true)
67 91
     submitBuildingExcel({ data: formData }).then(res => {
@@ -89,7 +113,7 @@ export default props => {
89 113
         <Column key="levelName" title="楼层" dataIndex="levelName" />
90 114
         <Column key="roomNoName" title="户号" dataIndex="roomNoName" />
91 115
         <Column key="ownerName" title="户主姓名" dataIndex="ownerName" />
92
-        <Column key="roleName" title="身份" dataIndex="roleName" />
116
+        {/* <Column key="roleName" title="身份" dataIndex="roleName" /> */}
93 117
         <Column key="ownerTel" title="手机号码" dataIndex="ownerTel" />
94 118
       </Table>
95 119
     </div>

+ 1
- 1
src/pages/property/proprietor/Detail.jsx Bestand weergeven

@@ -63,7 +63,7 @@ export default props => {
63 63
       <Section title="基本信息">
64 64
         <Descriptions column={3}>
65 65
           <Descriptions.Item label="姓名">{userData.ownerName}</Descriptions.Item>
66
-          <Descriptions.Item label="性别">{userData.gender === '2' ? '女' : '男'}</Descriptions.Item>
66
+          <Descriptions.Item label="性别">{!userData.idCard ? '' : (userData.idCard.substring(-2, 1) - 0) % 2 === 1 ? '男' : '女'}</Descriptions.Item>
67 67
           <Descriptions.Item label="手机号">{userData.phone}</Descriptions.Item>
68 68
           <Descriptions.Item label="微信昵称">{userData.nickname}</Descriptions.Item>
69 69
           <Descriptions.Item label="微信ID">{userData.openid}</Descriptions.Item>

+ 94
- 8
src/pages/property/proprietor/index.jsx Bestand weergeven

@@ -2,14 +2,19 @@ import React, { useState, useEffect } from 'react'
2 2
 import { Select, Spin, Table, Button, Form, Input, Icon, Modal, Popconfirm } from 'antd'
3 3
 import NavLink from 'umi/navlink'
4 4
 import { fetch, fetchList, apis } from '@/utils/request'
5
+import { exportExcel } from '@/utils/utils'
6
+import CommunitySelect from '@/components/CommunitySelect'
5 7
 import Search from '../components/Search'
6 8
 import List from '../components/List'
7 9
 import useRoomSelect from '../utils/hooks/useRoomSelect'
8 10
 
9 11
 const buildingInfoList = fetch(apis.buildingOwnerInfo.buildingList)
12
+const buildingInfoListExport = fetch(apis.buildingOwnerInfo.buildingListExport)
10 13
 const deleteBuilding = fetch(apis.buildingOwnerInfo.deleteBuilding)
11 14
 
12 15
 const Condition = props => {
16
+  const [communityId, setCommunityId] = useState()
17
+
13 18
   const {
14 19
     phaseId,
15 20
     setPhaseId,
@@ -26,11 +31,12 @@ const Condition = props => {
26 31
     unitList,
27 32
     levelList,
28 33
     roomNoList
29
-  } = useRoomSelect()
34
+  } = useRoomSelect(communityId)
30 35
 
31 36
   const handleSearch = vals => {
32 37
     const data = {
33 38
       ...vals,
39
+      communityId,
34 40
       phaseId,
35 41
       buildingId,
36 42
       unitId,
@@ -64,6 +70,12 @@ const Condition = props => {
64 70
     }
65 71
   }
66 72
 
73
+  const handleCommunityChange = v => {
74
+    setCommunityId(v)
75
+
76
+    props.onCommunityChange(v)
77
+  }
78
+
67 79
   return (
68 80
     <Search
69 81
       onSearch={handleSearch}
@@ -79,6 +91,9 @@ const Condition = props => {
79 91
 
80 92
         return (
81 93
           <>
94
+            <Form.Item>
95
+              <CommunitySelect value={communityId} onChange={handleCommunityChange} autoInited />
96
+            </Form.Item>
82 97
             <Form.Item>
83 98
               <Select value={phaseId} onChange={handlePhaseChange} style={{ minWidth: '120px' }} placeholder="期/区">
84 99
                 {
@@ -129,6 +144,28 @@ const Condition = props => {
129 144
               getFieldDecorator('idCard')(<Input style={{ width: '200px' }} placeholder="身份证" />)
130 145
             }
131 146
             </Form.Item>
147
+            <Form.Item>
148
+            {
149
+              getFieldDecorator('roleName')(
150
+                <Select style={{ width: '200px' }} placeholder="身份">
151
+                  <Select.Option value={1}>户主</Select.Option>
152
+                  <Select.Option value={3}>家属</Select.Option>
153
+                  <Select.Option value={2}>租客</Select.Option>
154
+                </Select>
155
+              )
156
+            }
157
+            </Form.Item>
158
+            <Form.Item>
159
+            {
160
+              getFieldDecorator('verifyStatus')(
161
+                <Select style={{ width: '200px' }} placeholder="审核状态">
162
+                  <Select.Option value={0}>未审核</Select.Option>
163
+                  <Select.Option value={1}>审核通过</Select.Option>
164
+                  <Select.Option value={2}>审核不通过</Select.Option>
165
+                </Select>
166
+              )
167
+            }
168
+            </Form.Item>
132 169
           </>
133 170
         )
134 171
       }}
@@ -145,9 +182,18 @@ const verifyStatusDict = {
145 182
 export default props => {
146 183
   const [loading, setLoading] = useState(false)
147 184
   const [listData, setListData] = useState([])
185
+  const [selectedKeys, setSelectedKeys] = useState([])
148 186
   const [pagination, setPagination] = useState({})
187
+  const [communityId, setCommunityId] = useState()
149 188
   const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
150 189
 
190
+  const rowSelection = {
191
+    onChange: (selectedRowKeys, selectedRows) => {
192
+      // console.log('------>', selectedRowKeys)
193
+      setSelectedKeys(selectedRowKeys)
194
+    }
195
+  }
196
+
151 197
   const handleSearch = (vals) => {
152 198
     setQueryParams({
153 199
       ...vals,      
@@ -167,6 +213,17 @@ export default props => {
167 213
     })
168 214
   }
169 215
 
216
+  const handleDeleteSelected = () => {
217
+    deleteBuilding({ data: selectedKeys }).then(res => {
218
+      Modal.success({
219
+        content: '数据删除成功',
220
+        onOk: () => {
221
+          window.location.reload()
222
+        }
223
+      })
224
+    })
225
+  }
226
+
170 227
   const handlePageChange = (pageNum, pageSize) => {
171 228
     setQueryParams({
172 229
       ...queryParams,      
@@ -175,29 +232,56 @@ export default props => {
175 232
     })
176 233
   }
177 234
 
235
+  const handleExport = () => {
236
+    setLoading(true)
237
+    buildingInfoListExport({ data: {...queryParams, communityId, pageNum: 1, pageSize: 9999} }).then(res => {
238
+      setLoading(false)
239
+      exportExcel(res, "业主列表")
240
+    }).catch(() => setLoading(false))
241
+  }
242
+
178 243
   useEffect(() => {
179 244
     setLoading(true)
180
-    buildingInfoList({ data: queryParams }).then(res => {
245
+    buildingInfoList({ data: {...queryParams, communityId} }).then(res => {
181 246
       const { list, ...pageInfo } = res || {}
182 247
       setListData(list)
183 248
       setPagination(pageInfo)
184 249
       setLoading(false)
185 250
     }).catch(() => setLoading(false))
186
-  }, [queryParams])
251
+  }, [queryParams, communityId])
187 252
 
188 253
   return (
189 254
     <div>
190
-      <Condition onSearch={handleSearch} onReset={handleSearch} />
255
+      <Condition onSearch={handleSearch} onReset={handleSearch} onCommunityChange={v => setCommunityId(v)} />
191 256
       <div style={{ margin: '24px 0' }}>
192 257
         <NavLink to={`/property/proprietor/add`}>
193 258
           <Button type="primary">添加</Button>
194 259
         </NavLink>
195
-        <NavLink to={`/property/proprietor/batch`}>
260
+        <div style={{marginLeft: 16, display: 'inline-block'}}>
261
+          <Popconfirm
262
+            title="确认进行批量删除操作?"
263
+            onConfirm={handleDeleteSelected}
264
+            okText="确定"
265
+            cancelText="取消"
266
+          >
267
+            <Button type="danger" disabled={!selectedKeys.length}>批量删除</Button>
268
+          </Popconfirm>
269
+        </div>
270
+        <div style={{marginLeft: 16, display: 'inline-block'}}>
271
+          <Button onClick={handleExport}>导出</Button>
272
+        </div>
273
+        <NavLink to={`/property/proprietor/batch?community=${communityId}`}>
196 274
           <Button type="link"><Icon type="upload"/>批量导入业主资料</Button>
197 275
         </NavLink>
198 276
       </div>
199
-      <List dataSource={listData} loading={loading} onPageChange={handlePageChange} pagination={pagination} rowKey="userVerifyId">
200
-        <Table.Column title="编号" dataIndex="userVerifyId" key="userVerifyId" />
277
+      <List
278
+        dataSource={listData}
279
+        loading={loading}
280
+        pagination={pagination}
281
+        rowSelection={rowSelection} 
282
+        onPageChange={handlePageChange}
283
+        rowKey="id"
284
+      >
201 285
         <Table.Column
202 286
           title="姓名"
203 287
           dataIndex="ownerName"
@@ -212,6 +296,7 @@ export default props => {
212 296
         />
213 297
         <Table.Column title="手机号" dataIndex="ownerTel" key="ownerTel" />
214 298
         <Table.Column title="身份证" dataIndex="idCard" key="idCard" />
299
+        <Table.Column title="性别" dataIndex="idCard" key="idCard1" render={t => !t ? '' : (t.substring(-2, 1) - 0) % 2 === 1 ? '男' : '女'} />
215 300
         <Table.Column
216 301
           title="房间号"
217 302
           dataIndex="roomNoName"
@@ -236,8 +321,9 @@ export default props => {
236 321
               </span>
237 322
             )
238 323
           }}
324
+          sorter={(a, b) => a.verifyStatus - b.verifyStatus}
239 325
         />
240
-        <Table.Column title="编辑人" dataIndex="updateName" key="updateName" />
326
+        <Table.Column title="审核人" dataIndex="updateName" key="updateName" />
241 327
         <Table.Column title="编辑时间" dataIndex="createDate" key="createDate" />
242 328
         <Table.Column
243 329
           title="操作"

+ 25
- 9
src/pages/property/ticket/index.jsx Bestand weergeven

@@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react'
2 2
 import { Select, Spin, Table, Button, Form, Input, Divider, Typography } from 'antd'
3 3
 import NavLink from 'umi/navlink'
4 4
 import { fetchList, apis, fetch } from '@/utils/request'
5
+import CommunitySelect from '@/components/CommunitySelect'
5 6
 import Search from '../components/Search'
6 7
 import List from '../components/List'
7 8
 
@@ -41,10 +42,10 @@ const StatusDict = [
41 42
     label: '已评价',
42 43
     value: '5',
43 44
   },
44
-  {
45
-    label: '已终止',
46
-    value: '6',
47
-  },
45
+  // {
46
+  //   label: '已终止',
47
+  //   value: '6',
48
+  // },
48 49
 ]
49 50
 
50 51
 const getDictValue = (dict, val) => (dict.filter(x => x.value === val)[0] || {}).label
@@ -52,6 +53,14 @@ const getDictValue = (dict, val) => (dict.filter(x => x.value === val)[0] || {})
52 53
 const listTicket = fetch(apis.ticket.listTicket)
53 54
 
54 55
 const Condition = props => {
56
+  const [communityId, setCommunityId] = useState()
57
+  
58
+  const handleCommunityChange = v => {
59
+    setCommunityId(v)
60
+
61
+    props.onCommunityChange(v)
62
+  }
63
+
55 64
   return (
56 65
     <Search
57 66
       onSearch={props.onSearch}
@@ -61,6 +70,11 @@ const Condition = props => {
61 70
         
62 71
         return (
63 72
           <>
73
+            <Form.Item label="小区">
74
+            {
75
+              <CommunitySelect value={communityId} onChange={handleCommunityChange} autoInited />
76
+            }
77
+            </Form.Item>
64 78
             <Form.Item label="工单编号">
65 79
             {
66 80
               getFieldDecorator('id')(<Input placeholder="工单编号" />)
@@ -92,7 +106,7 @@ const Condition = props => {
92 106
               getFieldDecorator('status')(
93 107
                 <Select placeholder="选择状态" style={{ width: '120px' }}>
94 108
                   {
95
-                    TypeDict.map(x => (<Select.Option key={x.value} value={x.value}>{x.label}</Select.Option>))
109
+                    StatusDict.map(x => (<Select.Option key={x.value} value={x.value}>{x.label}</Select.Option>))
96 110
                   }
97 111
                 </Select>
98 112
               )
@@ -113,6 +127,7 @@ const Condition = props => {
113 127
 export default props => {
114 128
   const [loading, setLoading] = useState(false)
115 129
   const [listData, setListData] = useState([])
130
+  const [communityId, setCommunityId] = useState()
116 131
   const [pagination, setPagination] = useState({})
117 132
   const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
118 133
 
@@ -134,17 +149,17 @@ export default props => {
134 149
 
135 150
   useEffect(() => {
136 151
     setLoading(true)
137
-    listTicket({data: queryParams}).then(res => {
152
+    listTicket({data: {...queryParams, communityId}}).then(res => {
138 153
       const {list, ...pagi} = res
139 154
       setListData(list)
140 155
       setPagination(pagi)
141 156
       setLoading(false)
142 157
     }).catch(e => setLoading(false))
143
-  }, [queryParams])
158
+  }, [queryParams, communityId])
144 159
 
145 160
   return (
146 161
     <div>
147
-      <Condition onSearch={handleSearch} onReset={handleSearch} />
162
+      <Condition onSearch={handleSearch} onReset={handleSearch} onCommunityChange={v => setCommunityId(v)} />
148 163
       <div style={{ margin: '24px 0' }}>
149 164
         {/* <NavLink to={`/property/notice/edit`}>
150 165
           <Button type="primary">添加</Button>
@@ -166,8 +181,9 @@ export default props => {
166 181
           }}
167 182
         />
168 183
         <Table.Column title="发起人" dataIndex="createUserNmae" key="createUserNmae" />
184
+        <Table.Column title="业主楼栋信息" dataIndex="address" key="address" />
169 185
         <Table.Column title="发起时间" dataIndex="createDate" key="createDate" />
170
-        <Table.Column title="流转状态" dataIndex="status" key="status" render={x => getDictValue(StatusDict, x)} />
186
+        <Table.Column title="流转状态" dataIndex="status" key="status" render={x => getDictValue(StatusDict, x)}/>
171 187
         <Table.Column title="当前处理人" dataIndex="tpUserNmae" key="tpUserNmae" />
172 188
         <Table.Column title="最近操作时间" dataIndex="updateDate" key="updateDate" />
173 189
       </List>

+ 5
- 3
src/pages/property/utils/hooks/useRoomSelect.js Bestand weergeven

@@ -7,7 +7,7 @@ const fetchUnitList = fetch(apis.buildingOwnerInfo.getUnitList)
7 7
 const fetchLevelList = fetch(apis.buildingOwnerInfo.getLevelList)
8 8
 const fetchRoomNoList = fetch(apis.buildingOwnerInfo.getRoomNoList)
9 9
 
10
-export default function useRoomSelect() {
10
+export default function useRoomSelect(communityId) {
11 11
   const [phaseList, setPhaseList] = useState([])
12 12
   const [buildingList, setBuildingList] = useState([])
13 13
   const [unitList, setUnitList] = useState([])
@@ -22,8 +22,10 @@ export default function useRoomSelect() {
22 22
 
23 23
   // 获取期
24 24
   useEffect(() => {
25
-    fetchPhaseList().then(res => setPhaseList(res))
26
-  }, [])
25
+    if (communityId) {
26
+      fetchPhaseList({params: {communityId}}).then(res => setPhaseList(res))
27
+    }
28
+  }, [communityId])
27 29
 
28 30
   // 楼栋
29 31
   useEffect(() => {

+ 30
- 7
src/pages/staff/list/editStaff.jsx Bestand weergeven

@@ -2,16 +2,17 @@ import React, { useState, useEffect } from 'react';
2 2
 
3 3
 import { Input, Menu, Dropdown, Button, Icon, message, Table, Tooltip, Tabs, Radio, Divider, Tag, Select, Form, Alert, Modal } from 'antd';
4 4
 import { FormattedMessage } from 'umi-plugin-react/locale';
5
-import BuildSelect from '../../../components/SelectButton/BuildSelect'
5
+import BuildSelect from '@/components/SelectButton/BuildSelect'
6 6
 import router from 'umi/router';
7
-import styles from '../../style/GoodsList.less';
8
-import { FieldTypes, createForm } from '../../../components/XForm';
9
-import Wangedit from '../../../components/Wangedit/Wangedit'
7
+import { FieldTypes, createForm } from '@/components/XForm';
8
+import Wangedit from '@/components/Wangedit/Wangedit'
9
+import CommunitySelect from '@/components/CommunitySelect';
10 10
 import channels from './channelList.less';
11 11
 import Tagss from '../components/Tagss.jsx';
12 12
 import apis from '../../../services/apis';
13 13
 import request from '../../../utils/request'
14 14
 import BuildingSelection from '../components/BuildingSelection'
15
+import styles from '../../style/GoodsList.less';
15 16
 
16 17
 const { TextArea } = Input;
17 18
 const { Option } = Select;
@@ -27,6 +28,22 @@ const handleFormValueChange = (props, changedValues, allValues) => {
27 28
 
28 29
 const XForm = createForm({ onValuesChange: handleFormValueChange })
29 30
 
31
+const AuthCommunity = props => {
32
+  const value = (props.value || []).map(x => x.id)
33
+  const handleChange = vals => {
34
+    const data = (vals || []).map(x => ({id: x}))
35
+    props.onChange(data)
36
+  }
37
+
38
+  return (
39
+    <CommunitySelect
40
+      mode="multiple"
41
+      value={value}
42
+      onChange={handleChange}
43
+    />
44
+  )
45
+}
46
+
30 47
 /**
31 48
  *
32 49
  *
@@ -251,12 +268,20 @@ const Edit = (props) => {
251 268
         { required: true, message: '请选择头像' },
252 269
       ]
253 270
     },
271
+    {
272
+      label: '授权小区',
273
+      name: 'communityList',
274
+      render: <AuthCommunity />,
275
+      value: userData.communityList,
276
+      rules: [
277
+        { required: true, message: '请选择授权小区' },
278
+      ]
279
+    },
254 280
     {
255 281
       label: '简介',
256 282
       name: 'description',
257 283
       render: <TextArea className={channels.inpuitTxt} placeholder="生活管家请在此填写服务范围" ></TextArea>,
258 284
       value: userData.description
259
-
260 285
     },
261 286
     {
262 287
       label: '状态',
@@ -336,8 +361,6 @@ const Edit = (props) => {
336 361
     // },
337 362
   ]
338 363
 
339
-  console.log('--------->', fields)
340
-
341 364
   return <div>
342 365
             <XForm onChange={console.log} onSubmit={handleSubmit} fields={fields.filter(Boolean)} onCancel={() => router.go(-1)}></XForm>
343 366
             {/* <Modal

+ 26
- 0
src/pages/user/login/components/Login/CaptchaImg.jsx Bestand weergeven

@@ -0,0 +1,26 @@
1
+import React, { useEffect, useState } from 'react'
2
+import { fetch, apis } from '@/utils/request'
3
+
4
+const getCaptcha = fetch(apis.image.captcha)
5
+
6
+export default props => {
7
+  const [ver, setVer] = useState(0)
8
+  const [captcha, setCaptcha] = useState({image: '验证码'})
9
+
10
+  const handleClick = () => {
11
+    setVer(ver + 1)
12
+  }
13
+
14
+  useEffect(() => {
15
+    getCaptcha().then(res => {
16
+      setCaptcha(res)
17
+      if (props.onChange) {
18
+        props.onChange(res.key)
19
+      }
20
+    })
21
+  }, [ver])
22
+
23
+  return (
24
+    <img src={captcha.image} width="100%" height="40" onClick={handleClick} style={{cursor: 'pointer'}} />
25
+  )
26
+}

+ 5
- 2
src/pages/user/login/components/Login/LoginItem.jsx Bestand weergeven

@@ -4,6 +4,8 @@ import omit from 'omit.js';
4 4
 import ItemMap from './map';
5 5
 import LoginContext from './LoginContext';
6 6
 import styles from './index.less';
7
+import CaptchaImg from './CaptchaImg'
8
+
7 9
 const FormItem = Form.Item;
8 10
 
9 11
 class WrapFormItem extends Component {
@@ -119,14 +121,15 @@ class WrapFormItem extends Component {
119 121
               {getFieldDecorator(name, options)(<Input {...customProps} {...inputProps} />)}
120 122
             </Col>
121 123
             <Col span={8}>
122
-              <Button
124
+              {/* <Button
123 125
                 disabled={!!count}
124 126
                 className={styles.getCaptcha}
125 127
                 size="large"
126 128
                 onClick={this.onGetCaptcha}
127 129
               >
128 130
                 {count ? `${count} ${getCaptchaSecondText}` : getCaptchaButtonText}
129
-              </Button>
131
+              </Button> */}
132
+              {getFieldDecorator('captchaKey')(<CaptchaImg />)}
130 133
             </Col>
131 134
           </Row>
132 135
         </FormItem>

+ 2
- 2
src/pages/user/login/components/Login/index.jsx Bestand weergeven

@@ -88,7 +88,7 @@ class Login extends Component {
88 88
 
89 89
     if (form) {
90 90
       form.validateFields(
91
-        activeFields,
91
+        activeFields.concat('captchaKey'),
92 92
         {
93 93
           force: true,
94 94
         },
@@ -118,7 +118,7 @@ class Login extends Component {
118 118
           <div className={styles.con}>
119 119
             <p className={styles.welcome}>欢迎使用</p>
120 120
             <div className={styles.title}>
121
-              <p className={styles.name}>远道 · 系统</p>
121
+              <p className={styles.name}>远道 · 系统</p>
122 122
               {/* <span style={{fontSize:' 0.106rem',lineHeight:' 0.106rem'}}>YUANDAO HUI</span> */}
123 123
             </div>
124 124
           </div>

+ 13
- 0
src/pages/user/login/components/Login/map.jsx Bestand weergeven

@@ -31,4 +31,17 @@ export default {
31 31
       },
32 32
     ],
33 33
   },
34
+  Captcha: {
35
+    props: {
36
+      size: 'large',
37
+      id: 'captcha',
38
+      placeholder: '888888',
39
+    },
40
+    rules: [
41
+      {
42
+        required: true,
43
+        message: '请输入验证码!',
44
+      },
45
+    ],
46
+  },
34 47
 };

+ 1
- 0
src/pages/user/login/index.jsx Bestand weergeven

@@ -120,6 +120,7 @@ class Login extends Component {
120 120
               }
121 121
             }}
122 122
           />
123
+          <Captcha name="captcha" placeholder="请填写验证码" />
123 124
           <Submit loading={submitting}>
124 125
             <FormattedMessage id="user-login.login.login" />
125 126
           </Submit>

+ 19
- 0
src/services/apis.js Bestand weergeven

@@ -5,6 +5,8 @@ import propUser from './prop_user_api'
5 5
 import announcement from './announcement_api'
6 6
 import ticket from './ticket_api'
7 7
 import propNews from './prop_news_api'
8
+import dashboard from './dashboard_api'
9
+import community from './community_api'
8 10
 
9 11
 const prefix = `${APIBaseURL}api/admin`
10 12
 
@@ -19,6 +21,8 @@ export default {
19 21
   announcement: announcement(prefix),
20 22
   ticket: ticket(prefix),
21 23
   propNews: propNews(prefix),
24
+  dashboard: dashboard(prefix),
25
+  community: community(prefix),
22 26
   mp: {
23 27
     detail: {
24 28
       url: `${prefix}/taMpInfo`,
@@ -58,6 +62,11 @@ export default {
58 62
       url: `${prefix}/person-list`,
59 63
       method: 'GET',
60 64
       action: 'admin.person.list',
65
+    },
66
+    export: {
67
+      url: `${prefix}/person-list/export`,
68
+      method: 'GET',
69
+      action: 'admin.person.export',
61 70
     }
62 71
   },
63 72
   image: {
@@ -75,6 +84,11 @@ export default {
75 84
       url: `${prefix}/qrcode`,
76 85
       method: 'POST',
77 86
       action: 'upload',
87
+    },
88
+    captcha: {
89
+      url: `${prefix}/image-captcha`,
90
+      method: 'GET',
91
+      action: 'upload',
78 92
     }
79 93
   },
80 94
   user: {
@@ -727,6 +741,11 @@ export default {
727 741
       method: 'GET',
728 742
       action: 'admin.taPointsExchange.get',
729 743
     },
744
+    taPointsExchangeExport: {
745
+      url: `${prefix}/taPointsExchange/export`,
746
+      method: 'GET',
747
+      action: 'admin.taPointsExchange.get',
748
+    },
730 749
     getTaGoods: {
731 750
       url: `${prefix}/taGoods`,
732 751
       method: 'GET',

+ 21
- 0
src/services/buildingOwnerInfo_api.js Bestand weergeven

@@ -44,6 +44,13 @@ export default prefix => {
44 44
       action: `admin.${moduleName}.roomno`
45 45
     },
46 46
 
47
+    //  查询 楼栋/单元/楼层/户号
48
+    getAllRoomNoList: {
49
+      url: `${prefix}/${moduleName}/building-room/list`,
50
+      method: 'get',
51
+      action: `admin.${moduleName}.all-room`
52
+    },
53
+
47 54
     // 获取楼栋户主信息列表
48 55
     buildingList: {
49 56
       url: `${prefix}/${moduleName}/list`,
@@ -51,6 +58,13 @@ export default prefix => {
51 58
       action: `admin.${moduleName}.list.post`
52 59
     },
53 60
 
61
+    // 导出楼栋户主信息列表
62
+    buildingListExport: {
63
+      url: `${prefix}/${moduleName}/list/export`,
64
+      method: 'post',
65
+      action: `admin.${moduleName}.list-export.post`
66
+    },
67
+
54 68
     // 认证通过户主信息
55 69
     userPassCertification: {
56 70
       url: `${prefix}/${moduleName}/userPassCertification`,
@@ -128,6 +142,13 @@ export default prefix => {
128 142
       action: `admin.${moduleName}.addnode`
129 143
     },
130 144
 
145
+    // 编辑当前期/栋/单元/层/户/节点
146
+    updateNode: {
147
+      url: `${prefix}/${moduleName}/updatenode`,
148
+      method: 'post',
149
+      action: `admin.${moduleName}.updatenode`
150
+    },
151
+
131 152
     // 删除当前期/栋/单元/层/户/节点
132 153
     deleteNode: {
133 154
       url: `${prefix}/${moduleName}/deletenode`,

+ 28
- 0
src/services/community_api.js Bestand weergeven

@@ -0,0 +1,28 @@
1
+
2
+export default prefix => ({
3
+  list: {
4
+    url: `${prefix}/tpCommunity`,
5
+    method: 'GET',
6
+    action: 'admin.community.list'
7
+  },
8
+  detail: {
9
+    url: `${prefix}/tpCommunity/:id`,
10
+    method: 'GET',
11
+    action: 'admin.community.detail'
12
+  },
13
+  update: {
14
+    url: `${prefix}/tpCommunity/:id`,
15
+    method: 'PUT',
16
+    action: 'admin.community.update'
17
+  },
18
+  save: {
19
+    url: `${prefix}/tpCommunity`,
20
+    method: 'POST',
21
+    action: 'admin.community.save'
22
+  },
23
+  delete: {
24
+    url: `${prefix}/tpCommunity/:id`,
25
+    method: 'DELETE',
26
+    action: 'admin.community.delete'
27
+  },
28
+})

+ 25
- 0
src/services/dashboard_api.js Bestand weergeven

@@ -0,0 +1,25 @@
1
+
2
+export default prefix => {
3
+  return {
4
+    statis: {
5
+      url: `${prefix}/dashboard/statis`,
6
+      method: 'get',
7
+      action: `admin.dashboard.statis`
8
+    },
9
+    dynamic: {
10
+      url: `${prefix}/dashboard/dynamic`,
11
+      method: 'get',
12
+      action: `admin.dashboard.dynamic`
13
+    },
14
+    houseVerified: {
15
+      url: `${prefix}/dashboard/house-verified`,
16
+      method: 'get',
17
+      action: `admin.dashboard.house-verified`
18
+    },
19
+    tips: {
20
+      url: `${prefix}/dashboard/tips`,
21
+      method: 'get',
22
+      action: `admin.dashboard.tips`
23
+    }
24
+  }
25
+}

+ 1
- 1
src/utils/constant.js Bestand weergeven

@@ -1,4 +1,4 @@
1 1
 
2
-export const APIBaseURL = process.env.NODE_ENV === 'production' ? 'https://xs.ycjcjy.com/' : '/'
2
+export const APIBaseURL = process.env.NODE_ENV === 'production' ? 'https://xs.njyunzhi.com/' : '/'
3 3
 
4 4
 export const AMapAPIPrefix = `${APIBaseURL}gaode_amap`

+ 11
- 0
src/utils/utils.js Bestand weergeven

@@ -25,3 +25,14 @@ export const getPageQuery = () => parse(window.location.href.split('?')[1]);
25 25
 export function ObjSpEqual(a = {}, b = {}) {
26 26
   return JSON.stringify(a) === JSON.stringify(b)
27 27
 }
28
+
29
+
30
+export function exportExcel(data, title) {  
31
+  const url = window.URL.createObjectURL(new Blob([data]))
32
+  const link = document.createElement('a')
33
+  link.style.display = 'none'
34
+  link.href = url
35
+  link.setAttribute('download', `${title}.xlsx`)
36
+  document.body.append(link)
37
+  link.click()
38
+}