소스 검색

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

Your Name 4 년 전
부모
커밋
8990f436bb
68개의 변경된 파일2564개의 추가작업 그리고 278개의 파일을 삭제
  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 파일 보기

12
   },
12
   },
13
   title: '远道荟',
13
   title: '远道荟',
14
   pwa: false,
14
   pwa: false,
15
-  iconfontUrl: '',
15
+  iconfontUrl: ''
16
 };
16
 };

+ 16
- 6
config/routes.js 파일 보기

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

+ 1
- 1
package.json 파일 보기

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

+ 56
- 0
src/components/CommunitySelect/index.jsx 파일 보기

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

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

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

1
-import React from 'react';
1
+import React, { useState, useRef, useEffect, useCallback } from 'react';
2
 import E from 'wangeditor';
2
 import E from 'wangeditor';
3
+import PreviewMenu from './PreviewMenu'
4
+import Preview from './Preview'
3
 import { fetch, apis } from '../../utils/request';
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
       if (!files.length) return
43
       if (!files.length) return
41
       
44
       
42
       const data = new FormData()
45
       const data = new FormData()
43
       data.append('file', files[0])
46
       data.append('file', files[0])
44
-
45
       fetch(apis.image.upload)({data}).then(insert)
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
       'head',  // 标题
56
       'head',  // 标题
49
       'bold',  // 粗体
57
       'bold',  // 粗体
50
       'fontSize',  // 字号
58
       'fontSize',  // 字号
59
       'quote',  // 引用
67
       'quote',  // 引用
60
       'image',  // 插入图片
68
       'image',  // 插入图片
61
       'undo',  // 撤销
69
       'undo',  // 撤销
62
-      'redo'  // 重复
70
+      'redo',  // 重复
71
+      'previewMenu'
63
     ]
72
     ]
64
-    
73
+
65
     // 过滤 word 字符
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
       const regs = [
77
       const regs = [
69
         /<!--\[if [\s\S]*?endif\]-->/ig,
78
         /<!--\[if [\s\S]*?endif\]-->/ig,
70
         /<[a-zA-Z0-9]+\:[^>]+>[^>]*<\/[a-zA-Z0-9]+\:[^>]+>/ig,
79
         /<[a-zA-Z0-9]+\:[^>]+>[^>]*<\/[a-zA-Z0-9]+\:[^>]+>/ig,
78
       }, content)
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 파일 보기

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

+ 9
- 0
src/global.less 파일 보기

196
     border-top:none;
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
 :global {
208
 :global {
200
   .ant-layout {
209
   .ant-layout {
201
     min-height: 100vh;
210
     min-height: 100vh;

+ 2
- 2
src/models/user.js 파일 보기

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

+ 9
- 1
src/pages/activity/SignList.jsx 파일 보기

68
 
68
 
69
 const header = props => {
69
 const header = props => {
70
   const [data, setData] = useState({ list: {} })
70
   const [data, setData] = useState({ list: {} })
71
+  const [actInfo, setActInfo] = useState()
72
+
71
   //   const [page, changePage] = useState({})
73
   //   const [page, changePage] = useState({})
72
   // 存入导入数据的值
74
   // 存入导入数据的值
73
   const { getFieldDecorator, getFieldsValue } = props.form
75
   const { getFieldDecorator, getFieldsValue } = props.form
75
   useEffect(() => {
77
   useEffect(() => {
76
     // eslint-disable-next-line no-use-before-define
78
     // eslint-disable-next-line no-use-before-define
77
     getSignList({ pageNum: 1, pageSize: 10, dynamicId: props.location.query.dynamicId });
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
         if (!data) {
124
         if (!data) {
118
           return
125
           return
119
         }
126
         }
127
+
120
         const url = window.URL.createObjectURL(new Blob([data]))
128
         const url = window.URL.createObjectURL(new Blob([data]))
121
         const link = document.createElement('a')
129
         const link = document.createElement('a')
122
         link.style.display = 'none'
130
         link.style.display = 'none'
123
         link.href = url
131
         link.href = url
124
-        link.setAttribute('download', '报名列表.xlsx')
132
+        link.setAttribute('download', `${actInfo.title || {}}-报名列表.xlsx`)
125
         document.body.append(link)
133
         document.body.append(link)
126
         link.click()
134
         link.click()
127
       }).catch(() => {
135
       }).catch(() => {

+ 1
- 1
src/pages/customer/customerlist/components/integralRecord.jsx 파일 보기

140
         title: '发生时间',
140
         title: '发生时间',
141
         dataIndex: 'createDate',
141
         dataIndex: 'createDate',
142
         key: 'createDate',
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
     return (
146
     return (

+ 17
- 2
src/pages/customer/personlist/index.jsx 파일 보기

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

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

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

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

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

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

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

8
 import apis from '../../services/apis';
8
 import apis from '../../services/apis';
9
 import request from '../../utils/request'
9
 import request from '../../utils/request'
10
 import AuthButton from '@/components/AuthButton';
10
 import AuthButton from '@/components/AuthButton';
11
+import { exportExcel } from '@/utils/utils'
11
 
12
 
12
 /**
13
 /**
13
   @param {*} props
14
   @param {*} props
21
 
22
 
22
   // 获取初始化数据
23
   // 获取初始化数据
23
   const [data, setData] = useState({})
24
   const [data, setData] = useState({})
25
+  const [queryParam, setQueryParam] = useState()
24
 
26
 
25
   useEffect(() => {
27
   useEffect(() => {
26
     getList({ pageNum: 1, pageSize: 10 });
28
     getList({ pageNum: 1, pageSize: 10 });
65
           submitValue.endVerifyDate = null
67
           submitValue.endVerifyDate = null
66
         }
68
         }
67
 
69
 
70
+        setQueryParam(submitValue)
71
+
68
         console.log(submitValue)
72
         console.log(submitValue)
69
         getList({ pageNum: 1, pageSize: 10, ...submitValue })
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
   const changePageNum = (pageNumber) => {
84
   const changePageNum = (pageNumber) => {
75
     props.form.validateFields((err, values) => {
85
     props.form.validateFields((err, values) => {
76
       if (!err) {
86
       if (!err) {
92
       dataIndex: 'personType',
102
       dataIndex: 'personType',
93
       key: 'personType',
103
       key: 'personType',
94
       align: 'center',
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
       title: '手机号',
108
       title: '手机号',
210
         </div>
220
         </div>
211
 
221
 
212
       </Form>
222
       </Form>
223
+      <div style={{marginTop: 24}}>
224
+        <Button onClick={handleExport}>导出</Button>
225
+      </div>
213
       <Table rowKey="exchangeRecords" style={{ marginTop: '40px' }} dataSource={data.records} columns={columns} pagination={false} />
226
       <Table rowKey="exchangeRecords" style={{ marginTop: '40px' }} dataSource={data.records} columns={columns} pagination={false} />
214
       <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '30px' }}>
227
       <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: '30px' }}>
215
         <Pagination showQuickJumper defaultCurrent={1} total={data.total} onChange={changePageNum} current={data.current} />
228
         <Pagination showQuickJumper defaultCurrent={1} total={data.total} onChange={changePageNum} current={data.current} />

+ 1
- 1
src/pages/mpSetting/components/MainSeting.jsx 파일 보기

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

+ 4
- 2
src/pages/mpSetting/components/TemplateItem.jsx 파일 보기

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

+ 1
- 1
src/pages/mpSetting/components/TemplateSetting.jsx 파일 보기

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

+ 13
- 10
src/pages/property/bill/edit/components/AddOn.jsx 파일 보기

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

+ 72
- 21
src/pages/property/bill/edit/index.jsx 파일 보기

1
 import React, { useEffect, useState, useRef } from 'react'
1
 import React, { useEffect, useState, useRef } from 'react'
2
 import router from 'umi/router'
2
 import router from 'umi/router'
3
 import { fetch, apis } from '@/utils/request'
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
 import AddOn from './components/AddOn'
6
 import AddOn from './components/AddOn'
6
 
7
 
7
 const formItemLayout = {
8
 const formItemLayout = {
30
 
31
 
31
 const billUploadExcelAdd = fetch(apis.bill.billUploadExcelAdd)
32
 const billUploadExcelAdd = fetch(apis.bill.billUploadExcelAdd)
32
 const billInvoiceGetInvoiceInvalid = fetch(apis.bill.billInvoiceGetInvoiceInvalid)
33
 const billInvoiceGetInvoiceInvalid = fetch(apis.bill.billInvoiceGetInvoiceInvalid)
34
+const fetchPhaseList = fetch(apis.buildingOwnerInfo.getPhaseList)
35
+const fetchBuildingList = fetch(apis.buildingOwnerInfo.getBuildingList)
33
 
36
 
34
 export default Form.create()(props => {
37
 export default Form.create()(props => {
38
+  const [loading, setLoading] = useState(false)
35
   const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
39
   const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
36
   const [formData, setFormData] = useState()
40
   const [formData, setFormData] = useState()
37
   const [addOnData, setAddOnData] = useState()
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
   const file = useRef()
48
   const file = useRef()
39
   
49
   
40
   const { id } = props.location.query
50
   const { id } = props.location.query
50
           return
60
           return
51
         }
61
         }
52
 
62
 
63
+        if (!rangeDate || rangeDate.length !== 2) {
64
+          notification.warn({
65
+            message: '请设置缴费时间'
66
+          })
67
+          return
68
+        }
69
+
53
         const data = new FormData()
70
         const data = new FormData()
54
         data.append('file', file.current)
71
         data.append('file', file.current)
55
-        data.append('billExplain', values.billExplain)
72
+        data.append('communityId', communityId)
73
+        // data.append('billExplain', values.billExplain)
56
         data.append('billName', values.billName)
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
         data.append('billStatus', billStatus)
77
         data.append('billStatus', billStatus)
59
 
78
 
60
         if (id) {
79
         if (id) {
61
           data.append('billId', id)
80
           data.append('billId', id)
62
         }
81
         }
63
 
82
 
83
+        setLoading(true)
64
         billUploadExcelAdd({ data }).then(res => {
84
         billUploadExcelAdd({ data }).then(res => {
85
+          setLoading(false)
65
           Modal.success({
86
           Modal.success({
66
             content: '生成数据成功',
87
             content: '生成数据成功',
67
             onOk: () => router.go(-1)
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
   useEffect(() => {
95
   useEffect(() => {
75
     if (id) {
96
     if (id) {
97
+      setLoading(true)
76
       billInvoiceGetInvoiceInvalid({
98
       billInvoiceGetInvoiceInvalid({
77
         data: {
99
         data: {
78
           ...queryParams,
100
           ...queryParams,
79
           billId: id,
101
           billId: id,
102
+          communityId,
80
         }
103
         }
81
       }).then(res => {
104
       }).then(res => {
82
         setFormData(res.bill)
105
         setFormData(res.bill)
106
+        // setCommunityId(communityId)
83
         setAddOnData(res)
107
         setAddOnData(res)
84
-      })
108
+        setLoading(false)
109
+      }).catch(e => console.error(e) || setLoading(false))
85
     }
110
     }
86
   }, [id, queryParams])
111
   }, [id, queryParams])
87
 
112
 
89
     setFieldsValue(formData || {})
114
     setFieldsValue(formData || {})
90
   }, [formData])
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
   return (
132
   return (
93
-    <div>
133
+    <Spin spinning={loading}>
94
       <Form {...formItemLayout} onSubmit={e => e.preventDefault()}>
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
           getFieldDecorator('billName', {
154
           getFieldDecorator('billName', {
98
             rules: [
155
             rules: [
99
-              { required: true, message: '请填写收费组名称', },
156
+              { required: true, message: '请填写收费名称', },
100
             ],
157
             ],
101
           })(<Input />)
158
           })(<Input />)
102
         }
159
         }
103
         </Form.Item>
160
         </Form.Item>
104
-        <Form.Item label="收费组说明">
161
+        {/* <Form.Item label="收费组说明">
105
         {
162
         {
106
           getFieldDecorator('billExplain', {
163
           getFieldDecorator('billExplain', {
107
             rules: [
164
             rules: [
109
             ],
166
             ],
110
           })(<Input />)
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
         </Form.Item>
172
         </Form.Item>
122
         <Form.Item label=" " colon={false}>
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
         </Form.Item>
175
         </Form.Item>
125
         <Form.Item {...tailFormItemLayout} >
176
         <Form.Item {...tailFormItemLayout} >
126
-          <Button type="primary" onClick={() => handleSubmit(2)}>草稿</Button>
177
+          {/* <Button type="primary" onClick={() => handleSubmit(2)}>草稿</Button> */}
127
           <Button type="danger" style={{ marginLeft: '24px' }} onClick={() => handleSubmit(0)}>发布</Button>
178
           <Button type="danger" style={{ marginLeft: '24px' }} onClick={() => handleSubmit(0)}>发布</Button>
128
           <Button style={{ marginLeft: '24px' }} onClick={() => router.go(-1)}>取消</Button>
179
           <Button style={{ marginLeft: '24px' }} onClick={() => router.go(-1)}>取消</Button>
129
         </Form.Item>
180
         </Form.Item>
130
       </Form>
181
       </Form>
131
-    </div>
182
+    </Spin>
132
   )
183
   )
133
 })
184
 })

+ 6
- 1
src/pages/property/bill/info/Add.jsx 파일 보기

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

+ 5
- 4
src/pages/property/bill/info/components/AddOne.jsx 파일 보기

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

+ 16
- 12
src/pages/property/bill/info/components/Edit.jsx 파일 보기

1
-import React, { useEffect, useState } from 'react'
1
+import React, { useEffect, useRef, useState } from 'react'
2
 import { Modal, Form, Input, DatePicker, Button } from 'antd'
2
 import { Modal, Form, Input, DatePicker, Button } from 'antd'
3
 import moment from 'moment'
3
 import moment from 'moment'
4
 
4
 
31
     e.preventDefault()
31
     e.preventDefault()
32
     props.form.validateFields((err, values) => {
32
     props.form.validateFields((err, values) => {
33
       if (!err && props.onSubmit) {
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
   useEffect(() => {
41
   useEffect(() => {
41
     const vals = props.initialData || {}
42
     const vals = props.initialData || {}
43
+    const startDate = vals.startDate ? moment(vals.startDate) : undefined
42
     const endDate = vals.endDate ? moment(vals.endDate) : undefined
44
     const endDate = vals.endDate ? moment(vals.endDate) : undefined
43
-    props.form.setFieldsValue({...vals, endDate})
45
+    props.form.setFieldsValue({...vals, startDate, endDate})
44
   }, [props.initialData])
46
   }, [props.initialData])
45
 
47
 
46
   return (
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
       <Form {...formItemLayout} onSubmit={handleSubmit}>
50
       <Form {...formItemLayout} onSubmit={handleSubmit}>
49
-        <Form.Item label="收费名称">
51
+        <Form.Item label="收费名称">
50
         {
52
         {
51
           props.form.getFieldDecorator('billName', {
53
           props.form.getFieldDecorator('billName', {
52
             rules: [
54
             rules: [
53
-              { required: true, message: '请填写收费名称' },
55
+              { required: true, message: '请填写收费名称' },
54
             ],
56
             ],
55
           })(<Input placeholder="收费组名称" />)
57
           })(<Input placeholder="收费组名称" />)
56
         }
58
         }
57
         </Form.Item>
59
         </Form.Item>
58
-        <Form.Item label="收费组说明">
60
+        <Form.Item label="开始时间">
59
         {
61
         {
60
-          props.form.getFieldDecorator('billExplain', {
62
+          props.form.getFieldDecorator('startDate', {
61
             rules: [
63
             rules: [
62
-              { required: true, message: '请填写收费组说明' },
64
+              { required: true, message: '请选择开始时间' },
63
             ],
65
             ],
64
-          })(<Input placeholder="收费组说明" />)
66
+          })(
67
+            <DatePicker placeholder="请选择开始时间" />
68
+          )
65
         }
69
         }
66
         </Form.Item>
70
         </Form.Item>
67
         <Form.Item label="截止时间">
71
         <Form.Item label="截止时间">
71
               { required: true, message: '请选择截止时间' },
75
               { required: true, message: '请选择截止时间' },
72
             ],
76
             ],
73
           })(
77
           })(
74
-            <DatePicker showTime placeholder="请选择截止时间" />
78
+            <DatePicker placeholder="请选择截止时间" />
75
           )
79
           )
76
         }
80
         }
77
         </Form.Item>
81
         </Form.Item>

+ 11
- 12
src/pages/property/bill/info/index.jsx 파일 보기

11
 
11
 
12
 const BillStatusDict = [
12
 const BillStatusDict = [
13
   { value: '0', label: '未缴费' },
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
 const PayTypeDict = [
19
 const PayTypeDict = [
48
     unitList,
49
     unitList,
49
     levelList,
50
     levelList,
50
     roomNoList
51
     roomNoList
51
-  } = useRoomSelect()
52
+  } = useRoomSelect(props.communityId)
52
   
53
   
53
   const handleSearch = vals => {
54
   const handleSearch = vals => {
54
     const data = {
55
     const data = {
283
         style={{ borderBottom: '1px solid rgb(235, 237, 240)' }}
284
         style={{ borderBottom: '1px solid rgb(235, 237, 240)' }}
284
       >
285
       >
285
         <Descriptions column={3}>
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
         </Descriptions>
290
         </Descriptions>
292
       </PageHeader>
291
       </PageHeader>
293
 
292
 
294
       <div style={{margin: '36px 0'}}>
293
       <div style={{margin: '36px 0'}}>
295
-        <Condition onSearch={handleSearch} onReset={handleSearch} />
294
+        <Condition onSearch={handleSearch} communityId={billData.communityId} onReset={handleSearch} />
296
       </div>
295
       </div>
297
 
296
 
298
       <div style={{margin: '24px 0'}}>
297
       <div style={{margin: '24px 0'}}>
316
           <Table.Column title="缴费途径" dataIndex="payType" key="payType" render={t => getDictLabel(PayTypeDict, t)} />
315
           <Table.Column title="缴费途径" dataIndex="payType" key="payType" render={t => getDictLabel(PayTypeDict, t)} />
317
           <Table.Column title="缴费人" dataIndex="payName" key="payName" />
316
           <Table.Column title="缴费人" dataIndex="payName" key="payName" />
318
           <Table.Column title="缴费时间" dataIndex="payDate" key="payDate" />
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
           <Table.Column title="新建人" dataIndex="createUserName" key="createUserName" />
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
           <Table.Column
322
           <Table.Column
324
             title="操作"
323
             title="操作"
325
             key="action"
324
             key="action"

+ 73
- 36
src/pages/property/bill/list/index.jsx 파일 보기

1
 import React, { useRef, useState, useEffect } from 'react'
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
 import router from 'umi/router'
3
 import router from 'umi/router'
4
 import NavLink from 'umi/navlink'
4
 import NavLink from 'umi/navlink'
5
+import moment from 'moment'
5
 import { fetch, fetchList, apis } from '@/utils/request'
6
 import { fetch, fetchList, apis } from '@/utils/request'
7
+import CommunitySelect from '@/components/CommunitySelect'
6
 import Search from '../../components/Search'
8
 import Search from '../../components/Search'
7
 import List from '../../components/List'
9
 import List from '../../components/List'
8
 
10
 
9
 
11
 
10
 const Condition = props => {
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
   return (    
39
   return (    
12
     <Search
40
     <Search
13
-      onSearch={props.onSearch}
14
-      onReset={props.onReset}
41
+      onSearch={handleSearch}
42
+      onReset={handleReset}
15
       render={form => {
43
       render={form => {
16
         const { getFieldDecorator } = form
44
         const { getFieldDecorator } = form
17
 
45
 
18
         return (
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
               getFieldDecorator('billId')(<Input />)
53
               getFieldDecorator('billId')(<Input />)
23
             }
54
             }
24
             </Form.Item>
55
             </Form.Item>
25
-            <Form.Item label="收费组名">
56
+            <Form.Item label="收费名">
26
             {
57
             {
27
               getFieldDecorator('billName')(<Input />)
58
               getFieldDecorator('billName')(<Input />)
28
             }
59
             }
29
             </Form.Item>
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
             </Form.Item>
73
             </Form.Item>
35
           </>
74
           </>
42
 const TableList = props => {
81
 const TableList = props => {
43
   const columns = [
82
   const columns = [
44
     {
83
     {
45
-      title: '收费编号',
84
+      title: '收费编号',
46
       dataIndex: 'id',
85
       dataIndex: 'id',
47
       key: 'id',
86
       key: 'id',
48
       align: 'center',
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
       dataIndex: 'billName',
97
       dataIndex: 'billName',
53
       key: 'billName',
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
       title: '应缴户数',
107
       title: '应缴户数',
73
       key: 'unpayedNum',
119
       key: 'unpayedNum',
74
     },
120
     },
75
     {
121
     {
76
-      title: '收费状态',
122
+      title: '收费状态',
77
       key: 'billStatus',
123
       key: 'billStatus',
78
       render: (t, row) => {
124
       render: (t, row) => {
79
         switch (row.billStatus) {
125
         switch (row.billStatus) {
80
           case '0':
126
           case '0':
81
-            return '正在收费'
127
+            return '进行中'
82
           case '1':
128
           case '1':
83
-            return '收费完成'
129
+            return '完成'
84
           case '2':
130
           case '2':
85
             return '草稿'
131
             return '草稿'
86
           default:
132
           default:
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
       title: '操作',
138
       title: '操作',
105
       key: 'action',
139
       key: 'action',
139
   const [listData, setListData] = useState([])
173
   const [listData, setListData] = useState([])
140
   const [pagination, setPagination] = useState({})
174
   const [pagination, setPagination] = useState({})
141
   const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
175
   const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
176
+  const [communityId, setCommunityId] = useState()
142
   
177
   
143
   const handleQuery = vals => {
178
   const handleQuery = vals => {
144
     setQueryParams({
179
     setQueryParams({
173
   }
208
   }
174
 
209
 
175
   useEffect(() => {
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
   return (
222
   return (
186
     <div>
223
     <div>
187
-      <Condition onReset={handleQuery} onSearch={handleQuery} />
224
+      <Condition onReset={handleQuery} onSearch={handleQuery} onCommunityChange={v => setCommunityId(v)} />
188
       <div style={{ margin: '24px 0' }}>
225
       <div style={{ margin: '24px 0' }}>
189
         <NavLink to={`/property/bill/management/add`}>
226
         <NavLink to={`/property/bill/management/add`}>
190
           <Button type="primary">添加</Button>
227
           <Button type="primary">添加</Button>

+ 77
- 5
src/pages/property/bill/order/index.jsx 파일 보기

1
 import React, { useState, useEffect } from 'react'
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
 import NavLink from 'umi/navlink'
3
 import NavLink from 'umi/navlink'
4
+import moment from 'moment';
4
 import { fetchList, apis, fetch } from '@/utils/request'
5
 import { fetchList, apis, fetch } from '@/utils/request'
5
 import Search from '../../components/Search'
6
 import Search from '../../components/Search'
6
 import List from '../../components/List'
7
 import List from '../../components/List'
7
 
8
 
9
+const { MonthPicker, RangePicker, WeekPicker } = DatePicker;
10
+
8
 const exportStatementExcel = fetch(apis.bill.exportStatementExcel)
11
 const exportStatementExcel = fetch(apis.bill.exportStatementExcel)
9
 const getBillStatementAll = fetch(apis.bill.getBillStatementAll)
12
 const getBillStatementAll = fetch(apis.bill.getBillStatementAll)
10
 
13
 
15
   '3': '已关闭',
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
 const PayTypeDict = {
40
 const PayTypeDict = {
19
   '0': '微信缴费',
41
   '0': '微信缴费',
20
   '1': '线下缴费',
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
 const Condition = props => {
57
 const Condition = props => {
25
   return (
58
   return (
26
     <Search
59
     <Search
56
               getFieldDecorator('payPhone')(<Input placeholder="缴费人手机号" />)
89
               getFieldDecorator('payPhone')(<Input placeholder="缴费人手机号" />)
57
             }
90
             }
58
             </Form.Item>
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
   const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
130
   const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
71
 
131
 
72
   const handleSearch = vals => {
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
     setQueryParams({
142
     setQueryParams({
74
       ...queryParams,
143
       ...queryParams,
75
-      ...vals,
144
+      ...submitValue,
76
       pageNum: 1,
145
       pageNum: 1,
77
     })
146
     })
78
   }
147
   }
151
           dataIndex="orderStatus"
220
           dataIndex="orderStatus"
152
           key="orderStatus"
221
           key="orderStatus"
153
           render={(_, row) => StatusDict[row.orderStatus]}
222
           render={(_, row) => StatusDict[row.orderStatus]}
223
+          sorter={(a, b) => a.orderStatus - b.orderStatus}
154
         />
224
         />
155
         <Table.Column title="缴费人手机号" dataIndex="payPhone" key="payPhone" />
225
         <Table.Column title="缴费人手机号" dataIndex="payPhone" key="payPhone" />
156
         <Table.Column title="缴费备注" dataIndex="payRemark" key="payRemark" />
226
         <Table.Column title="缴费备注" dataIndex="payRemark" key="payRemark" />
157
         <Table.Column title="缴费方式" dataIndex="payType" key="payType" render={payType => PayTypeDict[payType]}/>
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
       </List>
232
       </List>
161
 
233
 
162
     </div>
234
     </div>

+ 2
- 0
src/pages/property/building/BatchImport.jsx 파일 보기

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

+ 85
- 0
src/pages/property/building/components/Building.jsx 파일 보기

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

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

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

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

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

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

21
       {
21
       {
22
         props.data.type !== 'end' && (<Menu.Item key="add">增加子节点</Menu.Item>)
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
     </Menu>
25
     </Menu>
26
   );
26
   );
27
 
27
 

+ 104
- 0
src/pages/property/building/list.jsx 파일 보기

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

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

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

33
       if (!err) {
33
       if (!err) {
34
         props.onSubmit({
34
         props.onSubmit({
35
           ...(props.dataSource || {}),
35
           ...(props.dataSource || {}),
36
-          ...values
36
+          ...values,
37
+          type: props.type,
37
         })
38
         })
38
       }
39
       }
39
     })
40
     })
67
             props.form.getFieldDecorator('remark')(<Input placeholder="请填写备注" />)
68
             props.form.getFieldDecorator('remark')(<Input placeholder="请填写备注" />)
68
           }
69
           }
69
         </Form.Item>
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
         <Form.Item {...tailFormItemLayout}>
77
         <Form.Item {...tailFormItemLayout}>
79
           <Button type="primary" htmlType="submit">确定</Button>
78
           <Button type="primary" htmlType="submit">确定</Button>
80
           <Button onClick={props.onCancel} style={{ marginLeft: '48px' }}>取消</Button>
79
           <Button onClick={props.onCancel} style={{ marginLeft: '48px' }}>取消</Button>

+ 30
- 8
src/pages/property/contact/index.jsx 파일 보기

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

+ 15
- 3
src/pages/property/lifeConsultant/index.jsx 파일 보기

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

+ 3
- 2
src/pages/property/message/event/components/Preview.jsx 파일 보기

2
 import moment from 'moment'
2
 import moment from 'moment'
3
 import { Modal } from 'antd'
3
 import { Modal } from 'antd'
4
 import Styles from './style.less'
4
 import Styles from './style.less'
5
+import { APIBaseURL } from '@/utils/constant'
5
 
6
 
6
 export default props => {
7
 export default props => {
7
   const baseURL = props.dataSource.evtType === 'birthday'
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
   const queryString = [
12
   const queryString = [
12
     `name=${encodeURIComponent(' 张xx (先生)')}`,
13
     `name=${encodeURIComponent(' 张xx (先生)')}`,

+ 21
- 3
src/pages/property/news/index.jsx 파일 보기

1
 import React, { useState, useEffect } from 'react'
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
 import NavLink from 'umi/navlink'
3
 import NavLink from 'umi/navlink'
4
+import moment from 'moment';
4
 import { fetch, fetchList, apis } from '@/utils/request'
5
 import { fetch, fetchList, apis } from '@/utils/request'
5
 import Search from '../components/Search'
6
 import Search from '../components/Search'
6
 import List from '../components/List'
7
 import List from '../components/List'
7
 
8
 
9
+const { MonthPicker, RangePicker, WeekPicker } = DatePicker;
10
+
8
 const getNewsList = fetchList(apis.propNews.getNewsList)
11
 const getNewsList = fetchList(apis.propNews.getNewsList)
9
 const updateNews = fetch(apis.propNews.updateNews)
12
 const updateNews = fetch(apis.propNews.updateNews)
10
 const deleteNews = fetch(apis.propNews.deleteNews)
13
 const deleteNews = fetch(apis.propNews.deleteNews)
36
               getFieldDecorator('newsName')(<Input placeholder="标题" />)
39
               getFieldDecorator('newsName')(<Input placeholder="标题" />)
37
             }
40
             }
38
             </Form.Item>
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
   const [typeList, setTypeList] = useState([])
65
   const [typeList, setTypeList] = useState([])
57
 
66
 
58
   const handleSearch = vals => {
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
     setQueryParams({
77
     setQueryParams({
60
       ...queryParams,
78
       ...queryParams,
61
-      ...vals,
79
+      ...submitValue,
62
       pageNum: 1,
80
       pageNum: 1,
63
     })
81
     })
64
   }
82
   }
120
         </NavLink>
138
         </NavLink>
121
       </div>
139
       </div>
122
       <List dataSource={listData} loading={loading} pagination={pagination} onPageChange={handlePageChange} rowKey="newsId">
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
         <Table.Column
142
         <Table.Column
125
           title="分类"
143
           title="分类"
126
           dataIndex="newsTypeId"
144
           dataIndex="newsTypeId"

+ 14
- 1
src/pages/property/notice/Edit.jsx 파일 보기

1
 import React, { useEffect, useState } from 'react'
1
 import React, { useEffect, useState } from 'react'
2
 import router from 'umi/router'
2
 import router from 'umi/router'
3
 import { fetch, apis } from '@/utils/request'
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
 import Wangedit from '@/components/Wangedit/Wangedit'
5
 import Wangedit from '@/components/Wangedit/Wangedit'
6
 import ImageUpload from '@/components/uploadImage/ImageUpload'
6
 import ImageUpload from '@/components/uploadImage/ImageUpload'
7
+import CommunitySelect from '@/components/CommunitySelect'
7
 
8
 
8
 const formItemLayout = {
9
 const formItemLayout = {
9
   labelCol: {
10
   labelCol: {
86
   return (
87
   return (
87
     <div>
88
     <div>
88
       <Form {...formItemLayout} onSubmit={handleSubmit}>
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
         <Form.Item label="类型">
102
         <Form.Item label="类型">
90
         {
103
         {
91
           getFieldDecorator('annType')(
104
           getFieldDecorator('annType')(

+ 68
- 14
src/pages/property/notice/index.jsx 파일 보기

1
 import React, { useState, useEffect } from 'react'
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
 import NavLink from 'umi/navlink'
3
 import NavLink from 'umi/navlink'
4
+import moment from 'moment';
4
 import { fetch, apis } from '@/utils/request'
5
 import { fetch, apis } from '@/utils/request'
6
+import CommunitySelect from '@/components/CommunitySelect'
5
 import Search from '../components/Search'
7
 import Search from '../components/Search'
6
 import List from '../components/List'
8
 import List from '../components/List'
7
 
9
 
10
+const { MonthPicker, RangePicker, WeekPicker } = DatePicker;
11
+
8
 const listAnnouncement = fetch(apis.announcement.listAnnouncement)
12
 const listAnnouncement = fetch(apis.announcement.listAnnouncement)
9
 const deleteAnnouncement = fetch(apis.announcement.deleteAnnouncement)
13
 const deleteAnnouncement = fetch(apis.announcement.deleteAnnouncement)
10
 const updateannouncement = fetch(apis.announcement.updateannouncement)
14
 const updateannouncement = fetch(apis.announcement.updateannouncement)
11
 
15
 
12
 const Condition = props => {
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
   return (
25
   return (
14
     <Search
26
     <Search
15
       onSearch={props.onSearch}
27
       onSearch={props.onSearch}
19
         
31
         
20
         return (
32
         return (
21
           <>
33
           <>
34
+            <Form.Item label="小区">
35
+            {
36
+              <CommunitySelect value={communityId} onChange={handleCommunityChange} autoInited />
37
+            }
38
+            </Form.Item>
22
             <Form.Item label="公告编号">
39
             <Form.Item label="公告编号">
23
             {
40
             {
24
               getFieldDecorator('announcementNumber')(<Input placeholder="公告编号" />)
41
               getFieldDecorator('announcementNumber')(<Input placeholder="公告编号" />)
39
               )
56
               )
40
             }
57
             }
41
             </Form.Item>
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
 export default props => {
88
 export default props => {
56
   const [loading, setLoading] = useState(false)
89
   const [loading, setLoading] = useState(false)
57
   const [listData, setListData] = useState([])
90
   const [listData, setListData] = useState([])
91
+  const [communityId, setCommunityId] = useState()
58
   const [pagination, setPagination] = useState({})
92
   const [pagination, setPagination] = useState({})
59
   const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
93
   const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
60
 
94
 
61
   const handleSearch = vals => {
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
     setQueryParams({
105
     setQueryParams({
63
       ...queryParams,
106
       ...queryParams,
64
-      ...vals,
107
+      ...submitValue,
65
       pageNum: 1,
108
       pageNum: 1,
66
     })
109
     })
67
   }
110
   }
68
 
111
 
69
   const handleEditRow = row => {
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
   const handlePageChange = (pageNum, pageSize) => {
131
   const handlePageChange = (pageNum, pageSize) => {
86
 
138
 
87
   useEffect(() => {
139
   useEffect(() => {
88
     setLoading(true)
140
     setLoading(true)
89
-    listAnnouncement({ data: queryParams }).then(res => {
141
+    listAnnouncement({ data: {...queryParams, communityId} }).then(res => {
90
       const { list, ...pageInfo } = res || {}
142
       const { list, ...pageInfo } = res || {}
91
       setListData(list)
143
       setListData(list)
92
       setPagination(pageInfo)
144
       setPagination(pageInfo)
93
       setLoading(false)
145
       setLoading(false)
94
     }).catch(() => setLoading(false))
146
     }).catch(() => setLoading(false))
95
-  }, [queryParams])
147
+  }, [queryParams, communityId])
96
 
148
 
97
   return (
149
   return (
98
     <div>
150
     <div>
99
-      <Condition onSearch={handleSearch} onReset={handleSearch} />
151
+      <Condition onSearch={handleSearch} onReset={handleSearch} onCommunityChange={v => setCommunityId(v)} />
100
       <div style={{ margin: '24px 0' }}>
152
       <div style={{ margin: '24px 0' }}>
101
         <NavLink to={`/property/notice/edit`}>
153
         <NavLink to={`/property/notice/edit`}>
102
           <Button type="primary">添加</Button>
154
           <Button type="primary">添加</Button>
103
         </NavLink>
155
         </NavLink>
104
       </div>
156
       </div>
105
       <List dataSource={listData} loading={loading} pagination={pagination} onPageChange={handlePageChange} rowKey="id">
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
         <Table.Column title="类型" dataIndex="annType" key="annType" render={t => t === 'notice' ? '提醒' : null} />
159
         <Table.Column title="类型" dataIndex="annType" key="annType" render={t => t === 'notice' ? '提醒' : null} />
108
         <Table.Column
160
         <Table.Column
109
           title="标题"
161
           title="标题"
123
           dataIndex="status"
175
           dataIndex="status"
124
           key="status"
176
           key="status"
125
           render={(_, row) => StatusDict[row.status]}
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
         {/* <Table.Column title="发布人" dataIndex="createUserName" key="createUserName" />
182
         {/* <Table.Column title="发布人" dataIndex="createUserName" key="createUserName" />
129
         <Table.Column title="修改时间" dataIndex="updateDate" key="updateDate" />
183
         <Table.Column title="修改时间" dataIndex="updateDate" key="updateDate" />
130
         <Table.Column title="修改人" dataIndex="updateDateName" key="updateDateName" /> */}
184
         <Table.Column title="修改人" dataIndex="updateDateName" key="updateDateName" /> */}

+ 19
- 11
src/pages/property/proprietor/Add.jsx 파일 보기

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

+ 70
- 4
src/pages/property/proprietor/Audit.jsx 파일 보기

4
 import Search from '../components/Search'
4
 import Search from '../components/Search'
5
 import List from '../components/List'
5
 import List from '../components/List'
6
 import AuditNot from './components/AuditNot'
6
 import AuditNot from './components/AuditNot'
7
+import CommunitySelect from '@/components/CommunitySelect'
7
 
8
 
8
 const Condition = props => {
9
 const Condition = props => {
10
+  const [communityId, setCommunityId] = useState()
11
+
12
+  const handleCommunityChange = v => {
13
+    props.onCommunityChange(v)
14
+    setCommunityId(v)
15
+  }
16
+
9
   return (
17
   return (
10
     <Search
18
     <Search
11
       onSearch={props.onSearch}
19
       onSearch={props.onSearch}
15
 
23
 
16
         return (
24
         return (
17
           <>
25
           <>
26
+            <Form.Item label="小区">
27
+            {
28
+              <CommunitySelect autoInited value={communityId} onChange={handleCommunityChange} />
29
+            }
30
+            </Form.Item>
18
             <Form.Item label="姓名">
31
             <Form.Item label="姓名">
19
             {
32
             {
20
               getFieldDecorator('userName')(<Input style={{ width: '160px' }} placeholder="姓名" />)
33
               getFieldDecorator('userName')(<Input style={{ width: '160px' }} placeholder="姓名" />)
50
   const [loading, setLoading] = useState(false)
63
   const [loading, setLoading] = useState(false)
51
   const [noPassShow, setNoPassShow] = useState(false)
64
   const [noPassShow, setNoPassShow] = useState(false)
52
   const [listData, setListData] = useState([])
65
   const [listData, setListData] = useState([])
66
+  const [selectedKeys, setSelectedKeys] = useState([])
53
   const [pagination, setPagination] = useState({})
67
   const [pagination, setPagination] = useState({})
54
   const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
68
   const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
69
+  const [communityId, setCommunityId] = useState()
55
 
70
 
56
   const currentRow = useRef()
71
   const currentRow = useRef()
57
   
72
   
59
     setQueryParams({
74
     setQueryParams({
60
       ...queryParams,
75
       ...queryParams,
61
       ...vals,
76
       ...vals,
77
+      communityId,
62
       pageNum: 1
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
   const handleDeleteRow = row => {}
89
   const handleDeleteRow = row => {}
67
 
90
 
68
   const showAuditDialog = row => {
91
   const showAuditDialog = row => {
99
     const row = {
122
     const row = {
100
       ...currentRow.current,
123
       ...currentRow.current,
101
       ...vals,
124
       ...vals,
125
+      communityId,
102
     }
126
     }
103
 
127
 
104
     handleVerfiy(row, false)
128
     handleVerfiy(row, false)
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
   useEffect(() => {
160
   useEffect(() => {
117
     setLoading(true)
161
     setLoading(true)
118
-    userVerifyAll(queryParams).then(res => {
162
+    userVerifyAll({...queryParams, communityId}).then(res => {
119
       const [records, pagi] = res || []
163
       const [records, pagi] = res || []
120
       setListData(records)
164
       setListData(records)
121
       setPagination({total: pagi.total, pageSize: pagi.size, pageNum: pagi.current})
165
       setPagination({total: pagi.total, pageSize: pagi.size, pageNum: pagi.current})
122
       setLoading(false)
166
       setLoading(false)
123
     }).catch(() => setLoading(false))
167
     }).catch(() => setLoading(false))
124
-  }, [queryParams])
168
+  }, [queryParams, communityId])
125
 
169
 
126
   return (
170
   return (
127
     <div>
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
       <div style={{ marginTop: '24px' }}>
195
       <div style={{ marginTop: '24px' }}>
130
         <p style={{color: '#888', fontSize: '0.8em'}}>注意,审核后无法修改审核结果,请仔细确认</p>
196
         <p style={{color: '#888', fontSize: '0.8em'}}>注意,审核后无法修改审核结果,请仔细确认</p>
131
       </div>
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
         <Table.Column title="姓名" dataIndex="ownerName" key="ownerName" />
199
         <Table.Column title="姓名" dataIndex="ownerName" key="ownerName" />
134
         <Table.Column title="手机号" dataIndex="phone" key="phone" />
200
         <Table.Column title="手机号" dataIndex="phone" key="phone" />
135
         <Table.Column title="身份证" dataIndex="idCard" key="idCard" />
201
         <Table.Column title="身份证" dataIndex="idCard" key="idCard" />

+ 26
- 2
src/pages/property/proprietor/BatchImport.jsx 파일 보기

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

+ 1
- 1
src/pages/property/proprietor/Detail.jsx 파일 보기

63
       <Section title="基本信息">
63
       <Section title="基本信息">
64
         <Descriptions column={3}>
64
         <Descriptions column={3}>
65
           <Descriptions.Item label="姓名">{userData.ownerName}</Descriptions.Item>
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
           <Descriptions.Item label="手机号">{userData.phone}</Descriptions.Item>
67
           <Descriptions.Item label="手机号">{userData.phone}</Descriptions.Item>
68
           <Descriptions.Item label="微信昵称">{userData.nickname}</Descriptions.Item>
68
           <Descriptions.Item label="微信昵称">{userData.nickname}</Descriptions.Item>
69
           <Descriptions.Item label="微信ID">{userData.openid}</Descriptions.Item>
69
           <Descriptions.Item label="微信ID">{userData.openid}</Descriptions.Item>

+ 94
- 8
src/pages/property/proprietor/index.jsx 파일 보기

2
 import { Select, Spin, Table, Button, Form, Input, Icon, Modal, Popconfirm } from 'antd'
2
 import { Select, Spin, Table, Button, Form, Input, Icon, Modal, Popconfirm } from 'antd'
3
 import NavLink from 'umi/navlink'
3
 import NavLink from 'umi/navlink'
4
 import { fetch, fetchList, apis } from '@/utils/request'
4
 import { fetch, fetchList, apis } from '@/utils/request'
5
+import { exportExcel } from '@/utils/utils'
6
+import CommunitySelect from '@/components/CommunitySelect'
5
 import Search from '../components/Search'
7
 import Search from '../components/Search'
6
 import List from '../components/List'
8
 import List from '../components/List'
7
 import useRoomSelect from '../utils/hooks/useRoomSelect'
9
 import useRoomSelect from '../utils/hooks/useRoomSelect'
8
 
10
 
9
 const buildingInfoList = fetch(apis.buildingOwnerInfo.buildingList)
11
 const buildingInfoList = fetch(apis.buildingOwnerInfo.buildingList)
12
+const buildingInfoListExport = fetch(apis.buildingOwnerInfo.buildingListExport)
10
 const deleteBuilding = fetch(apis.buildingOwnerInfo.deleteBuilding)
13
 const deleteBuilding = fetch(apis.buildingOwnerInfo.deleteBuilding)
11
 
14
 
12
 const Condition = props => {
15
 const Condition = props => {
16
+  const [communityId, setCommunityId] = useState()
17
+
13
   const {
18
   const {
14
     phaseId,
19
     phaseId,
15
     setPhaseId,
20
     setPhaseId,
26
     unitList,
31
     unitList,
27
     levelList,
32
     levelList,
28
     roomNoList
33
     roomNoList
29
-  } = useRoomSelect()
34
+  } = useRoomSelect(communityId)
30
 
35
 
31
   const handleSearch = vals => {
36
   const handleSearch = vals => {
32
     const data = {
37
     const data = {
33
       ...vals,
38
       ...vals,
39
+      communityId,
34
       phaseId,
40
       phaseId,
35
       buildingId,
41
       buildingId,
36
       unitId,
42
       unitId,
64
     }
70
     }
65
   }
71
   }
66
 
72
 
73
+  const handleCommunityChange = v => {
74
+    setCommunityId(v)
75
+
76
+    props.onCommunityChange(v)
77
+  }
78
+
67
   return (
79
   return (
68
     <Search
80
     <Search
69
       onSearch={handleSearch}
81
       onSearch={handleSearch}
79
 
91
 
80
         return (
92
         return (
81
           <>
93
           <>
94
+            <Form.Item>
95
+              <CommunitySelect value={communityId} onChange={handleCommunityChange} autoInited />
96
+            </Form.Item>
82
             <Form.Item>
97
             <Form.Item>
83
               <Select value={phaseId} onChange={handlePhaseChange} style={{ minWidth: '120px' }} placeholder="期/区">
98
               <Select value={phaseId} onChange={handlePhaseChange} style={{ minWidth: '120px' }} placeholder="期/区">
84
                 {
99
                 {
129
               getFieldDecorator('idCard')(<Input style={{ width: '200px' }} placeholder="身份证" />)
144
               getFieldDecorator('idCard')(<Input style={{ width: '200px' }} placeholder="身份证" />)
130
             }
145
             }
131
             </Form.Item>
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
 export default props => {
182
 export default props => {
146
   const [loading, setLoading] = useState(false)
183
   const [loading, setLoading] = useState(false)
147
   const [listData, setListData] = useState([])
184
   const [listData, setListData] = useState([])
185
+  const [selectedKeys, setSelectedKeys] = useState([])
148
   const [pagination, setPagination] = useState({})
186
   const [pagination, setPagination] = useState({})
187
+  const [communityId, setCommunityId] = useState()
149
   const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
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
   const handleSearch = (vals) => {
197
   const handleSearch = (vals) => {
152
     setQueryParams({
198
     setQueryParams({
153
       ...vals,      
199
       ...vals,      
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
   const handlePageChange = (pageNum, pageSize) => {
227
   const handlePageChange = (pageNum, pageSize) => {
171
     setQueryParams({
228
     setQueryParams({
172
       ...queryParams,      
229
       ...queryParams,      
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
   useEffect(() => {
243
   useEffect(() => {
179
     setLoading(true)
244
     setLoading(true)
180
-    buildingInfoList({ data: queryParams }).then(res => {
245
+    buildingInfoList({ data: {...queryParams, communityId} }).then(res => {
181
       const { list, ...pageInfo } = res || {}
246
       const { list, ...pageInfo } = res || {}
182
       setListData(list)
247
       setListData(list)
183
       setPagination(pageInfo)
248
       setPagination(pageInfo)
184
       setLoading(false)
249
       setLoading(false)
185
     }).catch(() => setLoading(false))
250
     }).catch(() => setLoading(false))
186
-  }, [queryParams])
251
+  }, [queryParams, communityId])
187
 
252
 
188
   return (
253
   return (
189
     <div>
254
     <div>
190
-      <Condition onSearch={handleSearch} onReset={handleSearch} />
255
+      <Condition onSearch={handleSearch} onReset={handleSearch} onCommunityChange={v => setCommunityId(v)} />
191
       <div style={{ margin: '24px 0' }}>
256
       <div style={{ margin: '24px 0' }}>
192
         <NavLink to={`/property/proprietor/add`}>
257
         <NavLink to={`/property/proprietor/add`}>
193
           <Button type="primary">添加</Button>
258
           <Button type="primary">添加</Button>
194
         </NavLink>
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
           <Button type="link"><Icon type="upload"/>批量导入业主资料</Button>
274
           <Button type="link"><Icon type="upload"/>批量导入业主资料</Button>
197
         </NavLink>
275
         </NavLink>
198
       </div>
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
         <Table.Column
285
         <Table.Column
202
           title="姓名"
286
           title="姓名"
203
           dataIndex="ownerName"
287
           dataIndex="ownerName"
212
         />
296
         />
213
         <Table.Column title="手机号" dataIndex="ownerTel" key="ownerTel" />
297
         <Table.Column title="手机号" dataIndex="ownerTel" key="ownerTel" />
214
         <Table.Column title="身份证" dataIndex="idCard" key="idCard" />
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
         <Table.Column
300
         <Table.Column
216
           title="房间号"
301
           title="房间号"
217
           dataIndex="roomNoName"
302
           dataIndex="roomNoName"
236
               </span>
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
         <Table.Column title="编辑时间" dataIndex="createDate" key="createDate" />
327
         <Table.Column title="编辑时间" dataIndex="createDate" key="createDate" />
242
         <Table.Column
328
         <Table.Column
243
           title="操作"
329
           title="操作"

+ 25
- 9
src/pages/property/ticket/index.jsx 파일 보기

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

+ 5
- 3
src/pages/property/utils/hooks/useRoomSelect.js 파일 보기

7
 const fetchLevelList = fetch(apis.buildingOwnerInfo.getLevelList)
7
 const fetchLevelList = fetch(apis.buildingOwnerInfo.getLevelList)
8
 const fetchRoomNoList = fetch(apis.buildingOwnerInfo.getRoomNoList)
8
 const fetchRoomNoList = fetch(apis.buildingOwnerInfo.getRoomNoList)
9
 
9
 
10
-export default function useRoomSelect() {
10
+export default function useRoomSelect(communityId) {
11
   const [phaseList, setPhaseList] = useState([])
11
   const [phaseList, setPhaseList] = useState([])
12
   const [buildingList, setBuildingList] = useState([])
12
   const [buildingList, setBuildingList] = useState([])
13
   const [unitList, setUnitList] = useState([])
13
   const [unitList, setUnitList] = useState([])
22
 
22
 
23
   // 获取期
23
   // 获取期
24
   useEffect(() => {
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
   useEffect(() => {
31
   useEffect(() => {

+ 30
- 7
src/pages/staff/list/editStaff.jsx 파일 보기

2
 
2
 
3
 import { Input, Menu, Dropdown, Button, Icon, message, Table, Tooltip, Tabs, Radio, Divider, Tag, Select, Form, Alert, Modal } from 'antd';
3
 import { Input, Menu, Dropdown, Button, Icon, message, Table, Tooltip, Tabs, Radio, Divider, Tag, Select, Form, Alert, Modal } from 'antd';
4
 import { FormattedMessage } from 'umi-plugin-react/locale';
4
 import { FormattedMessage } from 'umi-plugin-react/locale';
5
-import BuildSelect from '../../../components/SelectButton/BuildSelect'
5
+import BuildSelect from '@/components/SelectButton/BuildSelect'
6
 import router from 'umi/router';
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
 import channels from './channelList.less';
10
 import channels from './channelList.less';
11
 import Tagss from '../components/Tagss.jsx';
11
 import Tagss from '../components/Tagss.jsx';
12
 import apis from '../../../services/apis';
12
 import apis from '../../../services/apis';
13
 import request from '../../../utils/request'
13
 import request from '../../../utils/request'
14
 import BuildingSelection from '../components/BuildingSelection'
14
 import BuildingSelection from '../components/BuildingSelection'
15
+import styles from '../../style/GoodsList.less';
15
 
16
 
16
 const { TextArea } = Input;
17
 const { TextArea } = Input;
17
 const { Option } = Select;
18
 const { Option } = Select;
27
 
28
 
28
 const XForm = createForm({ onValuesChange: handleFormValueChange })
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
         { required: true, message: '请选择头像' },
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
       label: '简介',
281
       label: '简介',
256
       name: 'description',
282
       name: 'description',
257
       render: <TextArea className={channels.inpuitTxt} placeholder="生活管家请在此填写服务范围" ></TextArea>,
283
       render: <TextArea className={channels.inpuitTxt} placeholder="生活管家请在此填写服务范围" ></TextArea>,
258
       value: userData.description
284
       value: userData.description
259
-
260
     },
285
     },
261
     {
286
     {
262
       label: '状态',
287
       label: '状态',
336
     // },
361
     // },
337
   ]
362
   ]
338
 
363
 
339
-  console.log('--------->', fields)
340
-
341
   return <div>
364
   return <div>
342
             <XForm onChange={console.log} onSubmit={handleSubmit} fields={fields.filter(Boolean)} onCancel={() => router.go(-1)}></XForm>
365
             <XForm onChange={console.log} onSubmit={handleSubmit} fields={fields.filter(Boolean)} onCancel={() => router.go(-1)}></XForm>
343
             {/* <Modal
366
             {/* <Modal

+ 26
- 0
src/pages/user/login/components/Login/CaptchaImg.jsx 파일 보기

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

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

+ 2
- 2
src/pages/user/login/components/Login/index.jsx 파일 보기

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

+ 13
- 0
src/pages/user/login/components/Login/map.jsx 파일 보기

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

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

+ 19
- 0
src/services/apis.js 파일 보기

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

+ 21
- 0
src/services/buildingOwnerInfo_api.js 파일 보기

44
       action: `admin.${moduleName}.roomno`
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
     buildingList: {
55
     buildingList: {
49
       url: `${prefix}/${moduleName}/list`,
56
       url: `${prefix}/${moduleName}/list`,
51
       action: `admin.${moduleName}.list.post`
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
     userPassCertification: {
69
     userPassCertification: {
56
       url: `${prefix}/${moduleName}/userPassCertification`,
70
       url: `${prefix}/${moduleName}/userPassCertification`,
128
       action: `admin.${moduleName}.addnode`
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
     deleteNode: {
153
     deleteNode: {
133
       url: `${prefix}/${moduleName}/deletenode`,
154
       url: `${prefix}/${moduleName}/deletenode`,

+ 28
- 0
src/services/community_api.js 파일 보기

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

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

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
 export const AMapAPIPrefix = `${APIBaseURL}gaode_amap`
4
 export const AMapAPIPrefix = `${APIBaseURL}gaode_amap`

+ 11
- 0
src/utils/utils.js 파일 보기

25
 export function ObjSpEqual(a = {}, b = {}) {
25
 export function ObjSpEqual(a = {}, b = {}) {
26
   return JSON.stringify(a) === JSON.stringify(b)
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
+}