张延森 4 лет назад
Родитель
Сommit
cf1191a2c7

+ 12
- 0
config/routes.js Просмотреть файл

@@ -613,11 +613,23 @@ export default [
613 613
                 component: './property/bill/edit',
614 614
                 hideInMenu: true,
615 615
               },
616
+              {
617
+                path: 'bill/management/info',
618
+                name: '收费组详情',
619
+                component: './property/bill/info',
620
+                hideInMenu: true,
621
+              },
616 622
               {
617 623
                 path: 'bill/order',
618 624
                 name: '订单管理',
619 625
                 component: './property/bill/order',
620 626
               },
627
+              {
628
+                path: 'bill/order/info',
629
+                name: '订单信息',
630
+                component: './property/bill/order/Info',
631
+                hideInMenu: true,
632
+              },
621 633
               {
622 634
                 path: 'bill/ticket',
623 635
                 name: '工单管理',

+ 38
- 34
src/global.less Просмотреть файл

@@ -68,6 +68,10 @@ ol {
68 68
     padding-left: 40px;
69 69
   }
70 70
 }
71
+
72
+.ant-pro-grid-content .ant-pro-page-header-wrap-children-content {
73
+  margin-top: 8px !important;
74
+}
71 75
  
72 76
 .ant-layout{
73 77
 //   .ant-menu-vertical .ant-menu-item,
@@ -123,50 +127,50 @@ ol {
123 127
     font-size: 0.096rem;
124 128
   }
125 129
 } 
126
-  .ant-pro-global-header-trigger{
127
-    display: none;
128
-  }
129
-  .ant-pro-sider-menu-sider.light{
130
-    box-shadow: none;
131
-    .ant-pro-sider-menu-logo h1{
132
-      color: #fff;
133
-    }
134
-  }
130
+  // .ant-pro-global-header-trigger{
131
+  //   display: none;
132
+  // }
133
+  // .ant-pro-sider-menu-sider.light{
134
+  //   box-shadow: none;
135
+  //   .ant-pro-sider-menu-logo h1{
136
+  //     color: #fff;
137
+  //   }
138
+  // }
135 139
   .ant-pro-page-header-wrap-page-header-warp{
136 140
     background:rgba(240,240,240,1);
137 141
   }
138
-   .ant-menu:not(.ant-menu-horizontal)  .ant-menu-item-selected{
139
-    // background:rgb(230, 227, 227)!important;
140
-    // background: #1890ff !important;
141
-    border: none!important;
142
-  }
143
-  .ant-menu-inline .ant-menu-selected::after, .ant-menu-inline .ant-menu-item-selected::after{
144
-    opacity: 0;
145
-  }
146
-  .ant-menu-inline > .ant-menu-item{
147
-    height: 45px;
148
-    line-height: 45px;
142
+  //  .ant-menu:not(.ant-menu-horizontal)  .ant-menu-item-selected{
143
+  //   // background:rgb(230, 227, 227)!important;
144
+  //   // background: #1890ff !important;
145
+  //   border: none!important;
146
+  // }
147
+  // .ant-menu-inline .ant-menu-selected::after, .ant-menu-inline .ant-menu-item-selected::after{
148
+  //   opacity: 0;
149
+  // }
150
+  // .ant-menu-inline > .ant-menu-item{
151
+  //   height: 45px;
152
+  //   line-height: 45px;
149 153
     
150
-    margin: 0;
151
-    .ant-menu-submenu-title{
152
-      font-size: 16px!important;
153
-    }
154
-  }
155
-  .ant-menu.ant-pro-sider-menu{
156
-    padding: 0!important;
157
-  }
154
+  //   margin: 0;
155
+  //   .ant-menu-submenu-title{
156
+  //     font-size: 16px!important;
157
+  //   }
158
+  // }
159
+  // .ant-menu.ant-pro-sider-menu{
160
+  //   padding: 0!important;
161
+  // }
158 162
   
159 163
   .ant-breadcrumb + .ant-page-header-heading{
160 164
     display: none;
161 165
   }
162 166
   .ant-page-header{
163
-    height: 50px;
164
-    padding:0 30px;
165
-    line-height: 50px;
167
+    // height: 50px;
168
+    // padding:0 30px;
169
+    // line-height: 50px;
166 170
     
167
-    .ant-breadcrumb{
168
-      color: #333;
169
-    }
171
+    // .ant-breadcrumb{
172
+    //   color: #333;
173
+    // }
170 174
   }
171 175
   .ant-pro-sider-menu-logo img{
172 176
     height: 41px;

+ 3
- 2
src/layouts/BlankLayout.jsx Просмотреть файл

@@ -7,8 +7,9 @@ const Layout = ({ children }) => (
7 7
       style={{
8 8
         backgroundColor: '#fff',
9 9
         padding: '32PX 28px',
10
-        boxShadow: '0px 0px 16px 2px rgba(0,0,0,0.12)',
11
-        borderRadius: '12px',
10
+        border: '1px solid rgba(0, 0, 0, 0.12)',
11
+        boxShadow: '0 1px 4px rgba(0, 21, 41, 0.08)',
12
+        borderRadius: '2px',
12 13
         minHeight:'60vh'
13 14
       }}
14 15
     >

+ 54
- 4
src/pages/property/bill/edit/components/AddOn.jsx Просмотреть файл

@@ -1,7 +1,11 @@
1
-import React, { useState } from 'react'
1
+import React, { useEffect, useState } from 'react'
2 2
 import { Button, Upload, Icon, Table } from 'antd'
3
+import { fetch, apis } from '@/utils/request'
3 4
 import List from '../../../components/List'
4 5
 
6
+const billDownloadExcel = fetch(apis.bill.billDownloadExcel)
7
+const billUploadExcel = fetch(apis.bill.billUploadExcel)
8
+
5 9
 const Section = props => {
6 10
   return (
7 11
     <p style={{ color: '#99a9bf', fontSize: '13px' }}>
@@ -11,19 +15,65 @@ const Section = props => {
11 15
 }
12 16
 
13 17
 export default props => {
18
+  const [loading, setLoading] = useState(false)
14 19
   const [listData, setListData] = useState([])
20
+  const [pagination, setPagination] = useState({})
21
+
22
+  const handleDownloadExcel = () => {
23
+    billDownloadExcel().then(res => {
24
+      const url = window.URL.createObjectURL(new Blob([res]))
25
+      const link = document.createElement('a')
26
+      link.href = url
27
+      link.setAttribute('download', '缴费单模板.xls')
28
+      link.click()
29
+    })
30
+  }
31
+
32
+  const handleUploadExcel = () => {
33
+    const input = document.createElement('input')
34
+    input.setAttribute('type', 'file')
35
+    input.addEventListener('input', e => {
36
+      const file = e.target.files[0]
37
+      if (!file) {
38
+        return
39
+      }
40
+
41
+      const data = new FormData()
42
+      data.append('file', file)
43
+
44
+      if (props.onFileInput) {
45
+        props.onFileInput(file)
46
+      }
47
+
48
+      setLoading(true)
49
+      billUploadExcel({data}).then(res => {
50
+        setListData(res.list)
51
+        setPagination({ total: res.total })
52
+        setLoading(false)
53
+      }).catch(() => setLoading(false))
54
+    })
55
+
56
+    input.click()
57
+  }
58
+
59
+  useEffect(() => {
60
+    if (props.dataSource) {
61
+      setListData(props.dataSource.billInvoice)
62
+      setPagination({ total: props.dataSource.total })
63
+    }
64
+  }, [props.dataSource])
15 65
 
16 66
   return (
17 67
     <div>
18 68
       <Section>
19 69
         <span>如果还未制作账单,请先下载账单模板,按规则填写费用后再上传</span>
20
-        <Button type="link" size="small" style={{ marginLeft: '6px' }}><Icon type="download" />下载模板</Button>
21
-        <Button type="link" size="small"><Icon type="upload" />选取账单文件并预览</Button>
70
+        <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>
22 72
       </Section>
23 73
       <Section>
24 74
         <span>如果想修改下表的内容,请重新下载excel模板填写金额后上传,系统会直接删除下表所有旧数据,以新的excel内容为准</span>
25 75
       </Section>
26
-      <List dataSource={listData} size="small" bordered>
76
+      <List dataSource={listData} loading={loading} pagination={pagination} size="small" bordered>
27 77
         <Table.Column align="center" title="房屋信息" dataIndex="phase" key="phase" render={(_, row) => (row.phase + row.building + row.unit + row.level + row.roomNo)} />
28 78
         <Table.Column align="center" title="收费说明" dataIndex="billExplain" key="billExplain" />
29 79
         <Table.Column align="center" title="收费金额(元)" dataIndex="payPrice" key="payPrice" render={payPrice => (payPrice === null || payPrice === undefined ? '' : Number(payPrice/100).toFixed(2))} />

+ 68
- 29
src/pages/property/bill/edit/index.jsx Просмотреть файл

@@ -1,6 +1,7 @@
1
-import React from 'react'
1
+import React, { useEffect, useState, useRef } from 'react'
2 2
 import router from 'umi/router'
3
-import { Button, Form, Input, DatePicker } from 'antd'
3
+import { fetch, apis } from '@/utils/request'
4
+import { Button, Form, Input, DatePicker, notification, Modal } from 'antd'
4 5
 import AddOn from './components/AddOn'
5 6
 
6 7
 const formItemLayout = {
@@ -27,65 +28,103 @@ const tailFormItemLayout = {
27 28
   },
28 29
 }
29 30
 
31
+const billUploadExcelAdd = fetch(apis.bill.billUploadExcelAdd)
32
+const billInvoiceGetInvoiceInvalid = fetch(apis.bill.billInvoiceGetInvoiceInvalid)
33
+
30 34
 export default Form.create()(props => {
35
+  const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
36
+  const [formData, setFormData] = useState()
37
+  const [addOnData, setAddOnData] = useState()
38
+  const file = useRef()
39
+  
40
+  const { id } = props.location.query
41
+  const { getFieldDecorator, setFieldsValue } = props.form
42
+
43
+  const handleSubmit = billStatus => {
44
+    props.form.validateFields((err, values) => {
45
+      if (!err) {
46
+        if (!file.current) {
47
+          notification.warn({
48
+            message: '请先上传账单文件'
49
+          })
50
+          return
51
+        }
31 52
 
32
-  const handleSubmit = values => {
53
+        const data = new FormData()
54
+        data.append('file', file.current)
55
+        data.append('billExplain', values.billExplain)
56
+        data.append('billName', values.billName)
57
+        data.append('endDate', values.endDate)
58
+        data.append('billStatus', billStatus)
33 59
 
60
+        if (id) {
61
+          data.append('billId', id)
62
+        }
63
+
64
+        billUploadExcelAdd({ data }).then(res => {
65
+          Modal.success({
66
+            content: '生成数据成功',
67
+            onOk: () => router.go(-1)
68
+          })
69
+        })
70
+      }
71
+    })
34 72
   }
35 73
 
36
-  const { getFieldDecorator } = props.form
74
+  useEffect(() => {
75
+    if (id) {
76
+      billInvoiceGetInvoiceInvalid({
77
+        data: {
78
+          ...queryParams,
79
+          billId: id,
80
+        }
81
+      }).then(res => {
82
+        setFormData(res.bill)
83
+        setAddOnData(res)
84
+      })
85
+    }
86
+  }, [id, queryParams])
87
+
88
+  useEffect(() => {
89
+    setFieldsValue(formData || {})
90
+  }, [formData])
37 91
 
38 92
   return (
39 93
     <div>
40
-      <Form {...formItemLayout} onSubmit={handleSubmit}>
94
+      <Form {...formItemLayout} onSubmit={e => e.preventDefault()}>
41 95
         <Form.Item label="收费组名称">
42 96
         {
43 97
           getFieldDecorator('billName', {
44 98
             rules: [
45
-              {
46
-                required: true,
47
-                message: '请填写收费组名称',
48
-              },
99
+              { required: true, message: '请填写收费组名称', },
49 100
             ],
50
-          })(
51
-            <Input />
52
-          )
101
+          })(<Input />)
53 102
         }
54 103
         </Form.Item>
55 104
         <Form.Item label="收费组说明">
56 105
         {
57 106
           getFieldDecorator('billExplain', {
58 107
             rules: [
59
-              {
60
-                required: true,
61
-                message: '请填写收费组说明',
62
-              },
108
+              { required: true, message: '请填写收费组说明', },
63 109
             ],
64
-          })(
65
-            <Input />
66
-          )
110
+          })(<Input />)
67 111
         }
68 112
         </Form.Item>
69 113
         <Form.Item label="截止时间">
70 114
         {
71 115
           getFieldDecorator('endDate', {
72 116
             rules: [
73
-              {
74
-                required: true,
75
-                message: '请填写公告内容',
76
-              },
117
+              { required: true, message: '请填写公告内容', },
77 118
             ],
78
-          })(
79
-            <DatePicker />
80
-          )
119
+          })(<DatePicker />)
81 120
         }
82 121
         </Form.Item>
83 122
         <Form.Item label=" " colon={false}>
84
-          <AddOn />
123
+          <AddOn dataSource={addOnData} onFileInput={f => file.current = f}/>
85 124
         </Form.Item>
86 125
         <Form.Item {...tailFormItemLayout} >
87
-          <Button type="primary" htmlType="submit">草稿</Button>
88
-          <Button type="danger" style={{ marginLeft: '24px' }}>发布</Button>
126
+          <Button type="primary" onClick={() => handleSubmit(2)}>草稿</Button>
127
+          <Button type="danger" style={{ marginLeft: '24px' }} onClick={() => handleSubmit(0)}>发布</Button>
89 128
           <Button style={{ marginLeft: '24px' }} onClick={() => router.go(-1)}>取消</Button>
90 129
         </Form.Item>
91 130
       </Form>

+ 91
- 0
src/pages/property/bill/info/Add.jsx Просмотреть файл

@@ -0,0 +1,91 @@
1
+import React, { useEffect, useState } from 'react'
2
+import { Button, Icon, Modal, Table, Popconfirm } from 'antd'
3
+import { fetch, fetchList, apis } from '@/utils/request'
4
+import NavLink from 'umi/navlink'
5
+import List from '../../components/List'
6
+import AddOne from './components/AddOne'
7
+
8
+const getTempBillInvoice = fetch(apis.bill.getTempBillInvoice)
9
+const addTempBillInvoice = fetch(apis.bill.addTempBillInvoice)
10
+const deleteTempBillInvoice = fetch(apis.bill.deleteTempBillInvoice)
11
+
12
+export default props => {
13
+  const [loading, setLoading] = useState(false)
14
+  const [showAdd, setShowAdd] = useState(false)
15
+  const [listData, setListData] = useState([])
16
+  const [formData, setFormData] = useState({})
17
+
18
+  const { id } = props.location.query
19
+  
20
+  const getListData = useCallback(
21
+    () => {
22
+      setLoading(true)
23
+      getTempBillInvoice({urlData: {id}}).then(res => {
24
+        setListData(res)
25
+        setLoading(false)
26
+      }).catch(e => setLoading(false))
27
+    },
28
+    [id],
29
+  )
30
+
31
+  const handleAdd = (vals, callback) => {
32
+    addTempBillInvoice({
33
+      billId: id,
34
+      ...vals,
35
+    }).then(res => {
36
+      callback()
37
+      getListData()
38
+      setShowAdd(false)
39
+    }).catch(() => setShowAdd(false))
40
+  }
41
+
42
+  const handleDeleteRow = row => {
43
+    deleteTempBillInvoice({urlData: {id: row.id}}).then(res => {
44
+      notification.success({ message: '删除费用信息成功' })
45
+      getListData()
46
+    })
47
+  }
48
+
49
+  useEffect(() => {
50
+    if (id) {
51
+      getListData()
52
+    }
53
+    getListData()
54
+  }, [])
55
+
56
+
57
+  return (
58
+    <div>
59
+      <div>
60
+        <Button type="primary" onClick={() => setShowAdd(true)}><Icon type="plus"/>新增记录</Button>
61
+        <Button type="danger" style={{marginLeft: '48px'}} onClick={}><Icon type="save"/>提交全部</Button>
62
+      </div>
63
+      <List dataSource={listData} loading={loading} rowKey="id">
64
+        <Table.Column title="房屋信息" dataIndex="roomNo" key="roomNo" render={(_, row) => row.phase + row.building + row.unit + row.roomNo} />
65
+        <Table.Column title="收费单说明" dataIndex="billInvoiceExplain" key="billInvoiceExplain" />
66
+        <Table.Column title="收费金额(元)" dataIndex="payPrice" key="payPrice" render={x => x/100} />
67
+        <Table.Column
68
+          title="操作"
69
+          key="action"
70
+          render={(_, row) => {
71
+            return (
72
+              <>
73
+                <Popconfirm
74
+                  title="确认进行删除操作?"
75
+                  onConfirm={() => handleDeleteRow(row)}
76
+                  okText="删除"
77
+                  cancelText="取消"
78
+                >
79
+                  <Button type="link">删除</Button>
80
+                </Popconfirm>
81
+              </>
82
+            )
83
+          }}
84
+        />
85
+      </List>
86
+      <Modal title="收费组信息" visible={showAdd} footer={null} maskClosable={false} destroyOnClose onCancel={() => setShowAdd(false)}>
87
+        <AddOne onSubmit={handleAdd} onCancel={() => setShowAdd(false)} />
88
+      </Modal>
89
+    </div>
90
+  )
91
+}

+ 179
- 0
src/pages/property/bill/info/components/AddOne.jsx Просмотреть файл

@@ -0,0 +1,179 @@
1
+import React, { useEffect, useState } from 'react'
2
+import { Form, Button, Input, Select } from 'antd'
3
+import useRoomSelect from '../../../utils/hooks/useRoomSelect'
4
+
5
+const formItemLayout = {
6
+  labelCol: {
7
+    xs: { span: 24 },
8
+    sm: { span: 6 },
9
+  },
10
+  wrapperCol: {
11
+    xs: { span: 24 },
12
+    sm: { span: 12 },
13
+  },
14
+}
15
+
16
+const tailFormItemLayout = {
17
+  wrapperCol: {
18
+    xs: {
19
+      span: 24,
20
+      offset: 0,
21
+    },
22
+    sm: {
23
+      span: 16,
24
+      offset: 6,
25
+    },
26
+  },
27
+}
28
+
29
+export default Form.create()(props => {
30
+  const {
31
+    phaseId,
32
+    setPhaseId,
33
+    buildingId,
34
+    setBuildingId,
35
+    unitId,
36
+    setUnitId,
37
+    levelId,
38
+    setLevelId,
39
+    roomNoId,
40
+    setRoomNoId,
41
+    phaseList,
42
+    buildingList,
43
+    unitList,
44
+    levelList,
45
+    roomNoList
46
+  } = useRoomSelect()
47
+  const [formData, setFormData] = useState({})
48
+
49
+  const [phaseErr, setPhaseErr] = useState('')
50
+  const [buildingErr, setBuildingErr] = useState('')
51
+  const [unitErr, setUnitErr] = useState('')
52
+  const [levelErr, setLevelErr] = useState('')
53
+  const [roomNoErr, setRoomNoErr] = useState('')
54
+
55
+  const resetForm = () => {
56
+    setPhaseId()
57
+    setBuildingId()
58
+    setUnitId()
59
+    setLevelId()
60
+    setRoomNoId()
61
+    setFormData({})
62
+  }
63
+
64
+  const handleSubmit = e => {
65
+    e.preventDefault();
66
+    props.form.validateFields((err, values) => {
67
+      if (!err && !phaseId && !buildingId && !unitId && !levelId && !roomNoId) {
68
+        props.onSubmit({
69
+          phaseId,
70
+          buildingId,
71
+          unitId,
72
+          levelId,
73
+          roomNoId,
74
+          ...values,
75
+        }, () => resetForm())
76
+      }
77
+    });
78
+  }
79
+
80
+  const handleReset = e => {
81
+    resetForm()
82
+    if (props.onReset) {
83
+      props.onReset({
84
+        phaseId,
85
+        buildingId,
86
+        unitId,
87
+        levelId,
88
+        roomNoId,
89
+        ...formData,
90
+      })
91
+    }
92
+  }
93
+
94
+  useEffect(() => {
95
+    props.form.setFieldsValue(formData)
96
+  }, [formData])
97
+
98
+  useEffect(() => {
99
+    setPhaseErr(phaseId ? '请选择期数': undefined)
100
+  }, [phaseId])
101
+
102
+  useEffect(() => {
103
+    setBuildingErr(buildingId ? '请选择楼栋': undefined)
104
+  }, [buildingId])
105
+
106
+  useEffect(() => {
107
+    setUnitErr(setUnitId ? '请选择单元': undefined)
108
+  }, [setUnitId])
109
+
110
+  useEffect(() => {
111
+    setLevelErr(levelId ? '请选择层数': undefined)
112
+  }, [levelId])
113
+
114
+  useEffect(() => {
115
+    setRoomNoErr(roomNoId ? '请选择户号': undefined)
116
+  }, [roomNoId])
117
+
118
+  return (
119
+    <Form {...formItemLayout} onSubmit={handleSubmit}>
120
+      <Form.Item label="请选择期数" required validateStatus={phaseErr ? 'error' : undefined} help={phaseErr}>
121
+        <Select value={phaseId} onChange={handlePhaseChange} style={{ minWidth: '120px' }} placeholder="期/区">
122
+          {
123
+            phaseList.map(x => (<Select.Option key={x.id} value={x.id}>{x.name}</Select.Option>))
124
+          }
125
+        </Select>
126
+      </Form.Item>
127
+      <Form.Item label="请选择楼栋" required validateStatus={buildingErr ? 'error' : undefined} help={buildingErr}>
128
+        <Select value={buildingId} onChange={handleBuildingChange} style={{ minWidth: '120px' }} placeholder="栋">
129
+          {
130
+            buildingList.map(x => (<Select.Option key={x.id} value={x.id}>{x.name}</Select.Option>))
131
+          }
132
+        </Select>
133
+      </Form.Item>
134
+      <Form.Item label="请选择单元" required validateStatus={unitErr ? 'error' : undefined} help={unitErr}>
135
+        <Select value={unitId} onChange={handleUnitChange} style={{ minWidth: '120px' }} placeholder="单元">
136
+          {
137
+            unitList.map(x => (<Select.Option key={x.id} value={x.id}>{x.name}</Select.Option>))
138
+          }
139
+        </Select>
140
+      </Form.Item>
141
+      <Form.Item label="请选择楼层" required validateStatus={levelErr ? 'error' : undefined} help={levelErr}>
142
+        <Select value={levelId} onChange={handleLevelChange} style={{ minWidth: '120px' }} placeholder="楼层">
143
+          {
144
+            levelList.map(x => (<Select.Option key={x.id} value={x.id}>{x.name}</Select.Option>))
145
+          }
146
+        </Select>
147
+      </Form.Item>
148
+      <Form.Item label="请选择户号" required validateStatus={roomNoErr ? 'error' : undefined} help={roomNoErr}>
149
+        <Select value={roomNoId} onChange={handleRoomChange} style={{ minWidth: '120px' }} placeholder="户号">
150
+          {
151
+            roomNoList.map(x => (<Select.Option key={x.id} value={x.id}>{x.name}</Select.Option>))
152
+          }
153
+        </Select>
154
+      </Form.Item>
155
+      <Form.Item label="收费单说明">
156
+      {
157
+        getFieldDecorator('billInvoiceExplain', {
158
+          rules: [
159
+            {required: true, message: '请填写收费单说明'}
160
+          ]
161
+        })(<Input placeholder="收费单说明" />)
162
+      }
163
+      </Form.Item>
164
+      <Form.Item label="收费金额(元)">
165
+      {
166
+        getFieldDecorator('payPrice', {
167
+          rules: [
168
+            {required: true, message: '请填写收费金额'}
169
+          ]
170
+        })(<Input placeholder="收费金额(元)" />)
171
+      }
172
+      </Form.Item>
173
+      <Form.Item {...tailFormItemLayout} >
174
+        <Button type="primary" htmlType="submit">添加到列表</Button>
175
+        <Button style={{ marginLeft: '24px' }} onClick={props.onCancel}>取消</Button>
176
+      </Form.Item>
177
+    </Form>
178
+  )
179
+})

+ 81
- 0
src/pages/property/bill/info/components/Edit.jsx Просмотреть файл

@@ -0,0 +1,81 @@
1
+import React, { useEffect, useState } from 'react'
2
+import { Modal, Form, Input, DatePicker, Button } from 'antd'
3
+
4
+const formItemLayout = {
5
+  labelCol: {
6
+    xs: { span: 24 },
7
+    sm: { span: 6 },
8
+  },
9
+  wrapperCol: {
10
+    xs: { span: 24 },
11
+    sm: { span: 12 },
12
+  },
13
+}
14
+
15
+const tailFormItemLayout = {
16
+  wrapperCol: {
17
+    xs: {
18
+      span: 24,
19
+      offset: 0,
20
+    },
21
+    sm: {
22
+      span: 16,
23
+      offset: 6,
24
+    },
25
+  },
26
+}
27
+
28
+export default Form.create()(props => {
29
+  const handleSubmit = e => {
30
+    e.preventDefault()
31
+    props.form.validateFields((err, values) => {
32
+      if (!err && props.onSubmit) {
33
+        props.onSubmit(values)
34
+      }
35
+    })
36
+  }
37
+
38
+  useEffect(() => {
39
+    props.form.setFieldsValue(props.initialData || {})
40
+  }, [props.initialData])
41
+
42
+  return (
43
+    <Modal title="收费组信息" visible={props.visible} footer={null} maskClosable={false} destroyOnClose onCancel={props.onCancel}>
44
+      <Form {...formItemLayout} onSubmit={handleSubmit}>
45
+        <Form.Item label="收费组名称">
46
+        {
47
+          props.form.getFieldDecorator('billName', {
48
+            rules: [
49
+              { required: true, message: '请填写收费组名称' },
50
+            ],
51
+          })(<Input placeholder="收费组名称" />)
52
+        }
53
+        </Form.Item>
54
+        <Form.Item label="收费组说明">
55
+        {
56
+          props.form.getFieldDecorator('billExplain', {
57
+            rules: [
58
+              { required: true, message: '请填写收费组说明' },
59
+            ],
60
+          })(<Input placeholder="收费组说明" />)
61
+        }
62
+        </Form.Item>
63
+        <Form.Item label="截止时间">
64
+        {
65
+          props.form.getFieldDecorator('endDate', {
66
+            rules: [
67
+              { required: true, message: '请选择截止时间' },
68
+            ],
69
+          })(
70
+            <DatePicker showTime placeholder="请选择截止时间" />
71
+          )
72
+        }
73
+        </Form.Item>
74
+        <Form.Item {...tailFormItemLayout} >
75
+          <Button type="primary" htmlType="submit">确定</Button>
76
+          <Button style={{ marginLeft: '24px' }} onClick={props.onCancel}>取消</Button>
77
+        </Form.Item>
78
+      </Form>
79
+    </Modal>
80
+  )
81
+})

+ 360
- 0
src/pages/property/bill/info/index.jsx Просмотреть файл

@@ -0,0 +1,360 @@
1
+import React, { useEffect, useRef, useState } from 'react'
2
+import { PageHeader, Button, Descriptions, Typography, Select, Icon, Table, Modal, Form, Input, notification } from 'antd'
3
+import { fetch, fetchList, apis } from '@/utils/request'
4
+import NavLink from 'umi/navlink'
5
+import Prompt from '@/components/Prompt'
6
+import Search from '../../components/Search'
7
+import List from '../../components/List'
8
+import Edit from './components/Edit'
9
+import useRoomSelect from '../../utils/hooks/useRoomSelect'
10
+
11
+const BillStatusDict = [
12
+  { value: '0', label: '未缴费' },
13
+  { value: '1', label: '已线上缴费' },
14
+  { value: '2', label: '已线下缴费' },
15
+]
16
+
17
+const PayTypeDict = [
18
+  { value: '0', label: '微信支付' },
19
+  { value: '1', label: '线下支付' },
20
+  { value: '2', label: '支付宝支付' },
21
+]
22
+
23
+const getDictLabel = (dict, v) => (dict.filter(x => x.value === v)[0] || {}).label
24
+
25
+const getBillInvoiceList = fetch(apis.bill.getBillInvoiceList)
26
+const deleteBillInvoiceById = fetch(apis.bill.deleteBillInvoiceById)
27
+const billInvoiceOfflinePayment = fetch(apis.bill.billInvoiceOfflinePayment)
28
+const updateBillInvoiceIdPayPrice = fetch(apis.bill.updateBillInvoiceIdPayPrice)
29
+const updateBillInvoiceIdBillInvoiceExplain = fetch(apis.bill.updateBillInvoiceIdBillInvoiceExplain)
30
+const updateBillNameAndBillExplainAndEndDate = fetch(apis.bill.updateBillNameAndBillExplainAndEndDate)
31
+const exportBillInvoiceExcel = fetch(apis.bill.exportBillInvoiceExcel)
32
+
33
+const Condition = props => {
34
+  const {
35
+    phaseId,
36
+    setPhaseId,
37
+    buildingId,
38
+    setBuildingId,
39
+    unitId,
40
+    setUnitId,
41
+    levelId,
42
+    setLevelId,
43
+    roomNoId,
44
+    setRoomNoId,
45
+    phaseList,
46
+    buildingList,
47
+    unitList,
48
+    levelList,
49
+    roomNoList
50
+  } = useRoomSelect()
51
+  
52
+  const handleSearch = vals => {
53
+    const data = {
54
+      ...vals,
55
+      phaseId,
56
+      buildingId,
57
+      unitId,
58
+      levelId,
59
+      roomNoId
60
+    }
61
+
62
+    if (props.onSearch) {
63
+      props.onSearch(data)
64
+    }
65
+  }
66
+
67
+  const handleReset = vals => {
68
+    const data = {
69
+      ...vals,
70
+      phaseId: '',
71
+      buildingId: '',
72
+      unitId: '',
73
+      levelId: '',
74
+      roomNoId: ''
75
+    }
76
+
77
+    setPhaseId()
78
+    setBuildingId()
79
+    setUnitId()
80
+    setLevelId()
81
+    setRoomNoId()
82
+
83
+    if (props.onReset) {
84
+      props.onReset(data)
85
+    }
86
+  }
87
+
88
+  return (
89
+    <Search
90
+      onSearch={handleSearch}
91
+      onReset={handleReset}
92
+      render={form => {
93
+        const { getFieldDecorator } = form
94
+        
95
+        const handlePhaseChange = e => setPhaseId(e)
96
+        const handleBuildingChange = e => setBuildingId(e)
97
+        const handleUnitChange = e => setUnitId(e)
98
+        const handleLevelChange = e => setLevelId(e)
99
+        const handleRoomChange = e => setRoomNoId(e)
100
+
101
+        return (
102
+          <>
103
+            <Form.Item label="选择房子">
104
+              <Select value={phaseId} onChange={handlePhaseChange} style={{ minWidth: '120px' }} placeholder="期/区">
105
+                {
106
+                  phaseList.map(x => (<Select.Option key={x.id} value={x.id}>{x.name}</Select.Option>))
107
+                }
108
+              </Select>
109
+            </Form.Item>
110
+            <Form.Item>
111
+              <Select value={buildingId} onChange={handleBuildingChange} style={{ minWidth: '120px' }} placeholder="栋">
112
+                {
113
+                  buildingList.map(x => (<Select.Option key={x.id} value={x.id}>{x.name}</Select.Option>))
114
+                }
115
+              </Select>
116
+            </Form.Item>
117
+            <Form.Item>
118
+              <Select value={unitId} onChange={handleUnitChange} style={{ minWidth: '120px' }} placeholder="单元">
119
+                {
120
+                  unitList.map(x => (<Select.Option key={x.id} value={x.id}>{x.name}</Select.Option>))
121
+                }
122
+              </Select>
123
+            </Form.Item>
124
+            <Form.Item>
125
+              <Select value={levelId} onChange={handleLevelChange} style={{ minWidth: '120px' }} placeholder="楼层">
126
+                {
127
+                  levelList.map(x => (<Select.Option key={x.id} value={x.id}>{x.name}</Select.Option>))
128
+                }
129
+              </Select>
130
+            </Form.Item>
131
+            <Form.Item>
132
+              <Select value={roomNoId} onChange={handleRoomChange} style={{ minWidth: '120px' }} placeholder="户号">
133
+                {
134
+                  roomNoList.map(x => (<Select.Option key={x.id} value={x.id}>{x.name}</Select.Option>))
135
+                }
136
+              </Select>
137
+            </Form.Item>
138
+            <Form.Item label="缴费状态">
139
+            {
140
+              getFieldDecorator('billStatus')(
141
+                <Select style={{ width: '160px' }} placeholder="缴费状态">
142
+                  {
143
+                    BillStatusDict.map(x => <Select.Option key={x.value} value={x.value}>{x.label}</Select.Option>)
144
+                  }
145
+                </Select>
146
+              )
147
+            }
148
+            </Form.Item>
149
+            <Form.Item label="缴费人姓名">
150
+            {
151
+              getFieldDecorator('payName')(<Input style={{ width: '160px' }} placeholder="缴费人姓名" />)
152
+            }
153
+            </Form.Item>
154
+          </>
155
+        )
156
+      }}
157
+    />
158
+  )
159
+}
160
+
161
+export default props => {
162
+  const [loading, setLoading] = useState(false)
163
+  const [showEditor, setShowEditor] = useState(false)
164
+  const [showPrompt, setShowPrompt] = useState(false)
165
+  const [billData, setBillData] = useState({})
166
+  const [listData, setListData] = useState([])
167
+  const [pagination, setPagination] = useState({})
168
+  const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
169
+  
170
+  const { id } = props.location.query
171
+  const editData = useRef({ type: undefined, data: undefined })
172
+
173
+  const handleSearch = vals => {
174
+    setQueryParams({
175
+      ...queryParams,
176
+      ...vals,
177
+      pageNum: 1,
178
+    })
179
+  }
180
+
181
+  const handlePageChange = (pageNum, pageSize) => {
182
+    setQueryParams({
183
+      ...queryParams,      
184
+      pageNum,
185
+      pageSize,
186
+    })
187
+  }
188
+
189
+  const handleExplainChange = row => {
190
+    editData.current = {type: 'explain', data: row}
191
+    setShowPrompt(true)
192
+  }
193
+
194
+  const handlePriceChange = row => {
195
+    editData.current = {type: 'price', data: row}
196
+    setShowPrompt(true)
197
+  }
198
+
199
+  const handleDeleteRow = row => {
200
+    deleteBillInvoiceById({data: [row.id]}).then(res => {
201
+      notification.success({ message: '删除数据成功' })
202
+
203
+      // 触发数据刷新
204
+      setQueryParams({...queryParams})   
205
+    })
206
+  }
207
+
208
+  const handleOffline = row => {
209
+    billInvoiceOfflinePayment({data: [row.id]}).then(res => {
210
+      notification.success({ message: '设置线下缴费成功' })
211
+
212
+      // 触发数据刷新
213
+      setQueryParams({...queryParams})
214
+    })
215
+  }
216
+
217
+  const handlePrompt = val => {
218
+    const {type, data} = editData.current
219
+    if (type === 'explain') {
220
+      updateBillInvoiceIdBillInvoiceExplain({urlData: {id: data.id}, data: {billInvoiceExplain: val}}).then(res => {
221
+        notification.success({ message: '修改费用说明成功' })
222
+  
223
+        // 触发数据刷新
224
+        setQueryParams({...queryParams})
225
+        setShowPrompt(false)
226
+      })
227
+    } else if (type === 'price') {
228
+      updateBillInvoiceIdPayPrice({urlData: {id: data.id}, data: {payPrice: val}}).then(res => {
229
+        notification.success({ message: '修改费用成功' })
230
+  
231
+        // 触发数据刷新
232
+        setQueryParams({...queryParams})
233
+        setShowPrompt(false)
234
+      })
235
+    }
236
+  }
237
+
238
+  const handleEditorSubmit = vals => {
239
+    updateBillNameAndBillExplainAndEndDate({data: {id, ...vals}}).then(res => {
240
+      notification.success({ message: '修改费用信息成功' })
241
+
242
+      // 触发数据刷新
243
+      setQueryParams({...queryParams})
244
+      setShowEditor(false)
245
+    })
246
+  }
247
+
248
+  const exportExcel = () => {
249
+    exportBillInvoiceExcel({ urlData: {id} }).then(res => {
250
+      const link = document.createElement('a')
251
+      link.href = window.URL.createObjectURL(new Blob([res]))
252
+      link.setAttribute('download', '缴费单.xls')
253
+      link.click()
254
+    })
255
+  }
256
+
257
+  useEffect(() => {
258
+    setLoading(true)
259
+    getBillInvoiceList({data: {
260
+      billId: id,
261
+      ...queryParams,
262
+    }}).then(res => {
263
+      const {list, pageNum, pageSize, total, ...billInfo} = res || {}
264
+      setListData(list)
265
+      setPagination({
266
+        ...pagination,
267
+        current: pageNum,
268
+        pageSize,
269
+        total,
270
+      })
271
+      setBillData(billInfo)
272
+      setLoading(false)
273
+    }).catch(e => setLoading(false))
274
+  }, [id, queryParams])
275
+
276
+  return (
277
+    <div>
278
+      <PageHeader
279
+        title="收费情况"
280
+        backIcon={false}
281
+        extra={[<Button key="1" onClick={() => setShowEditor(true)}>修改</Button>]}
282
+        style={{ borderBottom: '1px solid rgb(235, 237, 240)' }}
283
+      >
284
+        <Descriptions column={3}>
285
+          <Descriptions.Item label="收费组名称">{billData.billName}</Descriptions.Item>
286
+          <Descriptions.Item label="截止时间">{billData.endDate}</Descriptions.Item>
287
+          <Descriptions.Item label="收费组说明">
288
+            <Typography.Text ellipsis>{billData.billExplain}</Typography.Text>
289
+          </Descriptions.Item>
290
+        </Descriptions>
291
+      </PageHeader>
292
+
293
+      <div style={{margin: '36px 0'}}>
294
+        <Condition onSearch={handleSearch} onReset={handleSearch} />
295
+      </div>
296
+
297
+      <div style={{margin: '24px 0'}}>
298
+        <NavLink to=""><Button type="primary"><Icon type="plus" />添加更多收费单</Button></NavLink>
299
+        <Button type="link" onClick={exportExcel}><Icon type="export" />导出数据</Button>
300
+        <div style={{height: '40px', lineHeight: '40px', marginLeft: '10px', fontSize: '14px', color: '#888' }}>未缴户主费用可以直接点击 收费金额数字 修改,已缴费户主无法修改,需要线下多退少补</div>
301
+      </div>
302
+
303
+      <div>
304
+        <List dataSource={listData} loading={loading} pagination={pagination} onPageChange={handlePageChange} rowKey="id">
305
+          <Table.Column title="收费单号" dataIndex="id" key="id" />
306
+          <Table.Column title="房屋信息" dataIndex="roomNo" key="roomNo" render={(_, row) => row.phase + row.building + row.unit + row.roomNo} />
307
+          <Table.Column title="收费单说明" dataIndex="billInvoiceExplain" key="billInvoiceExplain" render={(t, row) => (
308
+            <Button type="link" onClick={() => handleExplainChange(row)}><Icon type="edit" />{t}</Button>
309
+          )} />
310
+          <Table.Column title="金额(元)" dataIndex="payPrice" key="payPrice" render={(t, row) => (
311
+            <Button type="link" onClick={() => handlePriceChange(row)}><Icon type="edit" />{t/100}</Button>
312
+          )} />
313
+          <Table.Column title="订单号" dataIndex="billStatement" key="billStatement" />
314
+          <Table.Column title="缴费状态" dataIndex="billStatus" key="billStatus" render={t => getDictLabel(BillStatusDict, t)} />
315
+          <Table.Column title="缴费途径" dataIndex="payType" key="payType" render={t => getDictLabel(PayTypeDict, t)} />
316
+          <Table.Column title="缴费人" dataIndex="payName" key="payName" />
317
+          <Table.Column title="缴费时间" dataIndex="payDate" key="payDate" />
318
+          <Table.Column title="新建时间" dataIndex="createDate" key="createDate" />
319
+          <Table.Column title="新建人" dataIndex="createUserName" key="createUserName" />
320
+          <Table.Column title="修改时间" dataIndex="updateDate" key="updateDate" />
321
+          <Table.Column title="修改人" dataIndex="updateUserName" key="updateUserName" />
322
+          <Table.Column
323
+            title="操作"
324
+            key="action"
325
+            render={(_, row) => {
326
+              return (
327
+                <>
328
+                  <Popconfirm
329
+                    title="确认进行删除操作?"
330
+                    onConfirm={() => handleDeleteRow(row)}
331
+                    okText="删除"
332
+                    cancelText="取消"
333
+                  >
334
+                    <Button type="link">删除</Button>
335
+                  </Popconfirm>
336
+                  <Divider type="vertical" />
337
+                  <Popconfirm
338
+                    title="确认设置为线下缴费?"
339
+                    onConfirm={() => handleOffline(row)}
340
+                    okText="缴费"
341
+                    cancelText="取消"
342
+                  >
343
+                    <Button type="link">线下缴费</Button>
344
+                  </Popconfirm>
345
+                </>
346
+              )
347
+            }}
348
+          />
349
+        </List>
350
+      </div>
351
+      <Prompt visible={showPrompt} onOk={handlePrompt} onCancel={() => setShowPrompt(false)} />
352
+      <Edit
353
+        visible={showEditor}
354
+        initialData={billData}
355
+        onSubmit={handleEditorSubmit}
356
+        onCancel={() => setShowEditor(false)}
357
+      />
358
+    </div>
359
+  )
360
+}

+ 21
- 35
src/pages/property/bill/list/index.jsx Просмотреть файл

@@ -1,4 +1,4 @@
1
-import React, { useRef, useState } from 'react'
1
+import React, { useRef, useState, useEffect } from 'react'
2 2
 import { Spin, Form, Input, Divider, Button, Row, Col } from 'antd'
3 3
 import router from 'umi/router'
4 4
 import NavLink from 'umi/navlink'
@@ -131,52 +131,28 @@ const TableList = props => {
131 131
   )
132 132
 }
133 133
 
134
-const defaultPage = { pageNum: 1, pageSize: 10, total: 0 }
135 134
 const FetchBillList = fetchList(apis.bill.fetchBillList)
136 135
 const deleteBillBeach = fetch(apis.bill.deleteBillBeach)
137 136
 
138 137
 export default props => {
139 138
   const [loading, setLoading] = useState(false)
140 139
   const [listData, setListData] = useState([])
141
-  const [pagination, setPagination] = useState(defaultPage)
140
+  const [pagination, setPagination] = useState({})
141
+  const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
142 142
   
143
-  const queryRef = useRef()
144
-
145
-  const getListData = params => {
146
-    setLoading(true)
147
-
148
-    const opts = params || {
149
-      pageNum: pagination.pageNum,
150
-      pageSize: pagination.pageSize,
151
-      ...queryRef.current
152
-    }
153
-
154
-    FetchBillList(opts).then(res => {
155
-      setListData(res.billList)
156
-      setPagination({
157
-        ...pagination,
158
-        total: res.total
159
-      })
160
-      setLoading(false)
161
-    })
162
-  }
163
-
164
-  const handleQuery = (vals) => {
165
-    queryRef.current = vals
166
-    setPagination(defaultPage)
167
-    getListData({
168
-      ...defaultPage,
169
-      ...queryRef.current,
143
+  const handleQuery = vals => {
144
+    setQueryParams({
145
+      ...queryParams,
146
+      ...vals,
147
+      pageNum: 1
170 148
     })
171 149
   }
172 150
 
173 151
   const handlePageChange = (pageNum, pageSize) => {
174
-    setPagination({ pageNum, pageSize, ...pagination })
175
-    
176
-    getListData({
177
-      pageNum,
152
+    setQueryParams({
153
+      ...queryParams,
178 154
       pageSize,
179
-      ...queryRef.current,
155
+      pageNum
180 156
     })
181 157
   }
182 158
 
@@ -196,6 +172,16 @@ export default props => {
196 172
     })
197 173
   }
198 174
 
175
+  useEffect(() => {
176
+    setLoading(true)
177
+    FetchBillList(queryParams).then(res => {
178
+      const [records, pagi] = res || []
179
+      setListData(records)
180
+      setPagination(pagi)
181
+      setLoading(false)
182
+    })
183
+  }, [queryParams])
184
+
199 185
   return (
200 186
     <div>
201 187
       <Condition onReset={handleQuery} onSearch={handleQuery} />

+ 50
- 0
src/pages/property/bill/order/Info.jsx Просмотреть файл

@@ -0,0 +1,50 @@
1
+import React, { useEffect, useState } from 'react'
2
+import { Button, Collapse, Icon, Descriptions, Typography, Spin } from 'antd'
3
+import NavLink from 'umi/navlink'
4
+import { fetch, apis } from '@/utils/request'
5
+// import List from '../components/List'
6
+
7
+const getByOrderNumberBillInvoice = fetch(apis.bill.getByOrderNumberBillInvoice)
8
+
9
+const renderBillLink = bill => () => <NavLink><Button type="link"><Icon type="export" /></Button></NavLink>
10
+
11
+export default props => {
12
+  const [loading, setLoading] = useState(false)
13
+  const [billList, setBillList] = useState([])
14
+
15
+  const { id } = props.location.query
16
+
17
+  useEffect(() => {
18
+    if (id) {
19
+      getByOrderNumberBillInvoice({urlData: {id}}).then(res => {
20
+        setBillList(res)
21
+      })
22
+    }
23
+  }, [id])
24
+
25
+  return (
26
+    <Spin spinning={loading}>
27
+      <Collapse>
28
+        {
29
+          billList.map(bill => {
30
+            <Collapse.Panel key={bill.id} header={bill.billName} extra={renderBillLink(bill)}>
31
+              <Descriptions bordered column={3}>
32
+              {
33
+                (bill.billInvoiceList || []).map(item => (
34
+                  <>
35
+                    <Descriptions.Item key={`${item.id}-1`} label="收费单号">{item.id}</Descriptions.Item>
36
+                    <Descriptions.Item key={`${item.id}-2`} label="金额(元)">{ item.payPrice / 100 }</Descriptions.Item>
37
+                    <Descriptions.Item key={`${item.id}-3`} label="收费单说明">
38
+                      <Typography.Text ellipsis>{item.billInvoiceExplain}</Typography.Text>
39
+                    </Descriptions.Item>
40
+                  </>
41
+                ))
42
+              }
43
+              </Descriptions>
44
+            </Collapse.Panel>
45
+          })
46
+        }
47
+      </Collapse>
48
+    </Spin>
49
+  )
50
+}

+ 96
- 78
src/pages/property/bill/order/index.jsx Просмотреть файл

@@ -1,10 +1,26 @@
1 1
 import React, { useState, useEffect } from 'react'
2 2
 import { Select, Spin, Table, Button, Form, Input, Divider } from 'antd'
3 3
 import NavLink from 'umi/navlink'
4
-import { fetchList, apis } from '@/utils/request'
4
+import { fetchList, apis, fetch } from '@/utils/request'
5 5
 import Search from '../../components/Search'
6 6
 import List from '../../components/List'
7 7
 
8
+const exportStatementExcel = fetch(apis.bill.exportStatementExcel)
9
+const getBillStatementAll = fetch(apis.bill.getBillStatementAll)
10
+
11
+const StatusDict = {
12
+  '0': '未支付',
13
+  '1': '已支付',
14
+  '2': '支付中',
15
+  '3': '已关闭',
16
+}
17
+
18
+const PayTypeDict = {
19
+  '0': '微信缴费',
20
+  '1': '线下缴费',
21
+  '2': '支付宝缴费',
22
+}
23
+
8 24
 const Condition = props => {
9 25
   return (
10 26
     <Search
@@ -17,7 +33,7 @@ const Condition = props => {
17 33
           <>
18 34
             <Form.Item label="订单号">
19 35
             {
20
-              getFieldDecorator('orderBumber')(<Input placeholder="公告编号" />)
36
+              getFieldDecorator('orderBumber')(<Input placeholder="订单号" />)
21 37
             }
22 38
             </Form.Item>
23 39
             <Form.Item label="缴费项目编号">
@@ -47,99 +63,101 @@ const Condition = props => {
47 63
   )
48 64
 }
49 65
 
50
-const StatusDict = {
51
-  '0': '未支付',
52
-  '1': '已支付',
53
-  '2': '支付中',
54
-  '3': '已关闭',
55
-}
56
-
57
-const PayTypeDict = {
58
-  '0': '微信缴费',
59
-  '1': '线下缴费',
60
-  '2': '支付宝缴费',
61
-}
62
-
63 66
 export default props => {
64 67
   const [loading, setLoading] = useState(false)
65 68
   const [listData, setListData] = useState([])
66
-
67
-  const handleSearch = () => {
68
-
69
-  }
70
-
71
-  const handleDeleteRow = row => {
72
-
73
-  }
74
-
75
-  const handleEditRow = row => {
76
-
69
+  const [pagination, setPagination] = useState({})
70
+  const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
71
+
72
+  const handleSearch = vals => {
73
+    setQueryParams({
74
+      ...queryParams,
75
+      ...vals,
76
+      pageNum: 1,
77
+    })
77 78
   }
78 79
 
79 80
   const handlePageChange = (pageNum, pageSize) => {
80
-
81
+    setQueryParams({
82
+      ...queryParams,      
83
+      pageNum,
84
+      pageSize,
85
+    })
81 86
   }
82 87
 
83 88
   const exportExcel = () => {
84
-
89
+    exportStatementExcel().then(res => {
90
+      const link = document.createElement('a')
91
+      link.href = window.URL.createObjectURL(new Blob([res]))
92
+      link.setAttribute('download', '流水信息.xls')
93
+      link.click()
94
+    })
85 95
   }
86 96
 
97
+  useEffect(() => {
98
+    setLoading(true)
99
+    getBillStatementAll({ data: queryParams }).then(res => {
100
+      const {list, ...pagi} = res || {}
101
+      setListData(list)
102
+      setPagination(pagi)
103
+      setLoading(false)
104
+    }).catch(err => setLoading(false))
105
+  }, [queryParams])
106
+
87 107
   return (
88 108
     <div>
89 109
       <Condition onSearch={handleSearch} onReset={handleSearch} />
90 110
       <div style={{ margin: '24px 0' }}>
91 111
         <Button type="primary" onClick={exportExcel}>导出数据</Button>
92 112
       </div>
93
-      <Spin spinning={loading}>
94
-        <List dataSource={listData} onPageChange={handlePageChange} rowKey="id">
95
-          <Table.Column
96
-            title="订单号"
97
-            dataIndex="id"
98
-            key="id"
99
-            render={(_, row) => {
100
-              return (
101
-                <NavLink to={`/xxx?id=${row.id}`}>
102
-                  <Button type="link">{row.orderBumber}</Button>
103
-                </NavLink>
104
-              )
105
-            }}
106
-          />
107
-          <Table.Column
108
-            title="收费组编号"
109
-            dataIndex="billId"
110
-            key="billId"
111
-            render={(_, row) => {
112
-              return (row.billIdList || []).map(item => (
113
-                <NavLink key={item} to={`/xxx?id=${item}`}>
114
-                  <Button type="link">{item}</Button>
115
-                </NavLink>
116
-              ))
117
-            }}
118
-          />
119
-          <Table.Column
120
-            title="收费单号"
121
-            dataIndex="billInvoiceId"
122
-            key="billInvoiceId"
123
-            render={(_, row) => {
124
-              return (row.billInvoiceIdList || []).map(item => (
125
-                <span key={item}>{item}</span>
126
-              ))
127
-            }}
128
-          />
129
-          <Table.Column title="总费用金额" dataIndex="sumPrice" key="sumPrice" render={sumPrice => (sumPrice === null || sumPrice === undefined ? '' : Number(sumPrice).toFixed(2))} />
130
-          <Table.Column
131
-            title="订单状态"
132
-            dataIndex="orderStatus"
133
-            key="orderStatus"
134
-            render={(_, row) => StatusDict[row.orderStatus]}
135
-          />
136
-          <Table.Column title="缴费人手机号" dataIndex="payPhone" key="payPhone" />
137
-          <Table.Column title="缴费备注" dataIndex="payRemark" key="payRemark" />
138
-          <Table.Column title="缴费方式" dataIndex="payType" key="payType" render={payType => PayTypeDict[payType]}/>
139
-          <Table.Column title="订单生成时间" dataIndex="createTime" key="createTime" />
140
-          <Table.Column title="缴费完成时间" dataIndex="updateDate" key="updateDate" />
141
-        </List>
142
-      </Spin>
113
+      <List dataSource={listData} loading={loading} pagination={pagination} onPageChange={handlePageChange} rowKey="id">
114
+        <Table.Column
115
+          title="订单号"
116
+          dataIndex="id"
117
+          key="id"
118
+          render={(_, row) => {
119
+            return (
120
+              <NavLink to={`/property/bill/order/info?id=${row.id}`}>
121
+                <Button type="link">{row.orderBumber}</Button>
122
+              </NavLink>
123
+            )
124
+          }}
125
+        />
126
+        <Table.Column
127
+          title="收费组编号"
128
+          dataIndex="billId"
129
+          key="billId"
130
+          render={(_, row) => {
131
+            return (row.billIdList || []).map(item => (
132
+              <NavLink key={item} to={`/xxx?id=${item}`}>
133
+                <Button type="link">{item}</Button>
134
+              </NavLink>
135
+            ))
136
+          }}
137
+        />
138
+        <Table.Column
139
+          title="收费单号"
140
+          dataIndex="billInvoiceId"
141
+          key="billInvoiceId"
142
+          render={(_, row) => {
143
+            return (row.billInvoiceIdList || []).map(item => (
144
+              <span key={item}>{item}</span>
145
+            ))
146
+          }}
147
+        />
148
+        <Table.Column title="总费用金额" dataIndex="sumPrice" key="sumPrice" render={sumPrice => (sumPrice === null || sumPrice === undefined ? '' : Number(sumPrice).toFixed(2))} />
149
+        <Table.Column
150
+          title="订单状态"
151
+          dataIndex="orderStatus"
152
+          key="orderStatus"
153
+          render={(_, row) => StatusDict[row.orderStatus]}
154
+        />
155
+        <Table.Column title="缴费人手机号" dataIndex="payPhone" key="payPhone" />
156
+        <Table.Column title="缴费备注" dataIndex="payRemark" key="payRemark" />
157
+        <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" />
160
+      </List>
143 161
 
144 162
     </div>
145 163
   )

+ 3
- 1
src/pages/property/components/List.jsx Просмотреть файл

@@ -7,7 +7,9 @@ export default props => {
7 7
   const pgSetting = {
8 8
     ...props.pagination,
9 9
     onChange: (page, pageSize) => {
10
-      props.onPageChange(page, pageSize)
10
+      if (props.onPageChange) {
11
+        props.onPageChange(page, pageSize)
12
+      }
11 13
     }
12 14
   }
13 15
 

+ 75
- 6
src/pages/property/notice/Edit.jsx Просмотреть файл

@@ -1,8 +1,9 @@
1
-import React from 'react'
1
+import React, { useEffect, useState } from 'react'
2 2
 import router from 'umi/router'
3
-import { Button, Form, Input } from 'antd'
3
+import { fetch, apis } from '@/utils/request'
4
+import { Button, Form, Input, InputNumber, Modal, Radio } from 'antd'
4 5
 import Wangedit from '@/components/Wangedit/Wangedit'
5
-import ImageListUpload from '@/components/XForm/ImageListUpload'
6
+import ImageUpload from '@/components/uploadImage/ImageUpload'
6 7
 
7 8
 const formItemLayout = {
8 9
   labelCol: {
@@ -28,13 +29,59 @@ const tailFormItemLayout = {
28 29
   },
29 30
 }
30 31
 
32
+const announcementById = fetch(apis.announcement.announcementById)
33
+const addAnnouncement = fetch(apis.announcement.addAnnouncement)
34
+const updateannouncement = fetch(apis.announcement.updateannouncement)
35
+
31 36
 export default Form.create()(props => {
37
+  const [noticeData, setNoticeData] = useState()
32 38
 
33
-  const handleSubmit = values => {
39
+  const { id } = props.location.query
40
+  const { getFieldDecorator, setFieldsValue } = props.form
34 41
 
42
+  const handleSubmit = e => {
43
+    e.preventDefault()
44
+    props.form.validateFields((err, values) => {
45
+      if (!err) {
46
+        if (!id) {
47
+          addAnnouncement({ data: {contentImg:[], ...values } }).then(() => {
48
+            Modal.success({
49
+              content: '保存内容成功',
50
+              onOk: () => {
51
+                router.go(-1)
52
+              }
53
+            })
54
+          })
55
+        } else {
56
+          updateannouncement({
57
+            data: {
58
+              ...noticeData,
59
+              ...values,
60
+            }
61
+          }).then(res => {
62
+            Modal.success({
63
+              content: '修改内容成功',
64
+              // onOk: () => {
65
+              //   router.go(-1)
66
+              // }
67
+            })
68
+          })
69
+        }
70
+      }
71
+    })
35 72
   }
36 73
 
37
-  const { getFieldDecorator } = props.form
74
+  useEffect(() => {
75
+    if (id) {
76
+      announcementById({ data: {id} }).then(res => {
77
+        setNoticeData(res.tpAnnouncement)
78
+      })
79
+    }
80
+  }, [id])
81
+
82
+  useEffect(() => {
83
+    setFieldsValue(noticeData)
84
+  }, [noticeData])
38 85
 
39 86
   return (
40 87
     <div>
@@ -63,7 +110,7 @@ export default Form.create()(props => {
63 110
               },
64 111
             ],
65 112
           })(
66
-            <ImageListUpload />
113
+            <ImageUpload />
67 114
           )
68 115
         }
69 116
         </Form.Item>
@@ -81,6 +128,28 @@ export default Form.create()(props => {
81 128
           )
82 129
         }
83 130
         </Form.Item>
131
+        <Form.Item label="权重值" help="权重值越大,在活动列表中排序越靠前,权重相同时按发布时间排序">
132
+        {
133
+          getFieldDecorator('sort', {
134
+            rules: [
135
+              {
136
+                required: true,
137
+                message: '请填写权重值',
138
+              },
139
+            ],
140
+          })(<InputNumber />)
141
+        }
142
+        </Form.Item>
143
+        <Form.Item label="是否发布">
144
+        {
145
+          getFieldDecorator('status')(
146
+            <Radio.Group>
147
+              <Radio value="1">发布</Radio>
148
+              <Radio value="0">不发布</Radio>
149
+            </Radio.Group>
150
+          )
151
+        }
152
+        </Form.Item>
84 153
         <Form.Item {...tailFormItemLayout} >
85 154
           <Button type="primary" htmlType="submit">确定</Button>
86 155
           <Button style={{ marginLeft: '24px' }} onClick={() => router.go(-1)}>取消</Button>

+ 91
- 64
src/pages/property/notice/index.jsx Просмотреть файл

@@ -1,17 +1,20 @@
1 1
 import React, { useState, useEffect } from 'react'
2
-import { Select, Spin, Table, Button, Form, Input, Divider } from 'antd'
2
+import { Select, Spin, Table, Button, Form, Input, Divider, Modal } from 'antd'
3 3
 import NavLink from 'umi/navlink'
4
-import { fetchList, apis } from '@/utils/request'
4
+import { fetch, apis } from '@/utils/request'
5 5
 import Search from '../components/Search'
6 6
 import List from '../components/List'
7 7
 
8
+const listAnnouncement = fetch(apis.announcement.listAnnouncement)
9
+const deleteAnnouncement = fetch(apis.announcement.deleteAnnouncement)
10
+
8 11
 const Condition = props => {
9 12
   return (
10 13
     <Search
11 14
       onSearch={props.onSearch}
12 15
       onReset={props.onReset}
13 16
       render={form => {
14
-        const { getFieldDecorator, setFieldsValue } = form
17
+        const { getFieldDecorator } = form
15 18
         
16 19
         return (
17 20
           <>
@@ -41,23 +44,47 @@ const StatusDict = {
41 44
 export default props => {
42 45
   const [loading, setLoading] = useState(false)
43 46
   const [listData, setListData] = useState([])
47
+  const [pagination, setPagination] = useState({})
48
+  const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
44 49
 
45
-  const handleSearch = () => {
46
-
50
+  const handleSearch = vals => {
51
+    setQueryParams({
52
+      ...queryParams,
53
+      ...vals,
54
+      pageNum: 1,
55
+    })
47 56
   }
48 57
 
49 58
   const handleDeleteRow = row => {
50
-
51
-  }
52
-
53
-  const handleEditRow = row => {
54
-
59
+    deleteAnnouncement({ data: [row.id] }).then(res => {
60
+      Modal.success({
61
+        content: '删除内容成功',
62
+        onOk: () => {
63
+          // 触发数据刷新
64
+          setQueryParams({...queryParams})
65
+        }
66
+      })
67
+    })
55 68
   }
56 69
 
57 70
   const handlePageChange = (pageNum, pageSize) => {
58
-
71
+    setQueryParams({
72
+      ...queryParams,      
73
+      pageNum,
74
+      pageSize,
75
+    })
59 76
   }
60 77
 
78
+  useEffect(() => {
79
+    setLoading(true)
80
+    listAnnouncement({ data: queryParams }).then(res => {
81
+      const { records, ...pageInfo } = res || {}
82
+      setListData(records)
83
+      setPagination(pageInfo)
84
+      setLoading(false)
85
+    }).catch(() => setLoading(false))
86
+  }, [queryParams])
87
+
61 88
   return (
62 89
     <div>
63 90
       <Condition onSearch={handleSearch} onReset={handleSearch} />
@@ -66,60 +93,60 @@ export default props => {
66 93
           <Button type="primary">添加</Button>
67 94
         </NavLink>
68 95
       </div>
69
-      <Spin spinning={loading}>
70
-        <List dataSource={listData} onPageChange={handlePageChange} rowKey="id">
71
-          <Table.Column title="编号" dataIndex="id" key="id" />
72
-          <Table.Column
73
-            title="标题"
74
-            dataIndex="announcementTitle"
75
-            key="announcementTitle"
76
-            render={(_, row) => {
77
-              return (
78
-                <NavLink to={`/xxx?id=${row.id}`}>
79
-                  <Button type="link">{row.announcementTitle}</Button>
80
-                </NavLink>
81
-              )
82
-            }}
83
-          />
84
-          <Table.Column title="查看数量" dataIndex="viewCount" key="viewCount" />
85
-          <Table.Column
86
-            title="状态"
87
-            dataIndex="status"
88
-            key="status"
89
-            render={(_, row) => {
90
-              if (row.status === '1' && (row.updateDate > row.createDate)) {
91
-                return '已修改'
92
-              }
96
+      <List dataSource={listData} loading={loading} pagination={pagination} onPageChange={handlePageChange} rowKey="id">
97
+        <Table.Column title="编号" dataIndex="id" key="id" />
98
+        <Table.Column
99
+          title="标题"
100
+          dataIndex="announcementTitle"
101
+          key="announcementTitle"
102
+          render={(_, row) => {
103
+            return (
104
+              <NavLink to={`/property/notice/edit?id=${row.id}`}>
105
+                <Button type="link">{row.announcementTitle}</Button>
106
+              </NavLink>
107
+            )
108
+          }}
109
+        />
110
+        <Table.Column title="查看数量" dataIndex="viewCount" key="viewCount" />
111
+        <Table.Column
112
+          title="状态"
113
+          dataIndex="status"
114
+          key="status"
115
+          render={(_, row) => {
116
+            if (row.status === '1' && (row.updateDate > row.createDate)) {
117
+              return '已修改'
118
+            }
93 119
 
94
-              return StatusDict[row.status]
95
-            }}
96
-          />
97
-          <Table.Column title="发布时间" dataIndex="createDate" key="createDate" />
98
-          <Table.Column title="发布人" dataIndex="createUserName" key="createUserName" />
99
-          <Table.Column title="修改时间" dataIndex="updateDate" key="updateDate" />
100
-          <Table.Column title="修改人" dataIndex="updateDateName" key="updateDateName" />
101
-          <Table.Column
102
-            title="操作"
103
-            key="action"
104
-            render={(_, row) => {
105
-              return (
106
-                <>
107
-                  <Popconfirm
108
-                    title="确认进行作废操作?"
109
-                    onConfirm={() => handleDeleteRow(row)}
110
-                    okText="作废"
111
-                    cancelText="取消"
112
-                  >
113
-                    <Button type="link">删除</Button>
114
-                  </Popconfirm>
115
-                  <Divider type="vertical" />
116
-                  <Button type="link" onClick={() => handleEdit(row)}>编辑</Button>
117
-                </>
118
-              )
119
-            }}
120
-          />
121
-        </List>
122
-      </Spin>
120
+            return StatusDict[row.status]
121
+          }}
122
+        />
123
+        <Table.Column title="发布时间" dataIndex="createDate" key="createDate" />
124
+        <Table.Column title="发布人" dataIndex="createUserName" key="createUserName" />
125
+        <Table.Column title="修改时间" dataIndex="updateDate" key="updateDate" />
126
+        <Table.Column title="修改人" dataIndex="updateDateName" key="updateDateName" />
127
+        <Table.Column
128
+          title="操作"
129
+          key="action"
130
+          render={(_, row) => {
131
+            return (
132
+              <>
133
+                <Popconfirm
134
+                  title="确认进行作废操作?"
135
+                  onConfirm={() => handleDeleteRow(row)}
136
+                  okText="作废"
137
+                  cancelText="取消"
138
+                >
139
+                  <Button type="link">删除</Button>
140
+                </Popconfirm>
141
+                <Divider type="vertical" />
142
+                <NavLink to={`/property/notice/edit?id=${row.id}`}>
143
+                  <Button type="link">编辑</Button>
144
+                </NavLink>
145
+              </>
146
+            )
147
+          }}
148
+        />
149
+      </List>
123 150
 
124 151
     </div>
125 152
   )

+ 1
- 1
src/pages/property/proprietor/Audit.jsx Просмотреть файл

@@ -121,7 +121,7 @@ export default props => {
121 121
       <div style={{ marginTop: '24px' }}>
122 122
         <p style={{color: '#888', fontSize: '0.8em'}}>注意,审核后无法修改审核结果,请仔细确认</p>
123 123
       </div>
124
-      <List dataSource={listData} loading={loading} rowKey="id">
124
+      <List dataSource={listData} pagination={pagination} loading={loading} rowKey="id">
125 125
         <Table.Column title="姓名" dataIndex="userName" key="userName" />
126 126
         <Table.Column title="手机号" dataIndex="phone" key="phone" />
127 127
         <Table.Column title="身份证" dataIndex="idCard" key="idCard" />

+ 47
- 46
src/pages/property/proprietor/index.jsx Просмотреть файл

@@ -4,69 +4,70 @@ import NavLink from 'umi/navlink'
4 4
 import { fetch, fetchList, apis } from '@/utils/request'
5 5
 import Search from '../components/Search'
6 6
 import List from '../components/List'
7
+import useRoomSelect from '../utils/hooks/useRoomSelect'
7 8
 
8
-const fetchPhaseList = fetch(apis.buildingOwnerInfo.getPhaseList)
9
-const fetchBuildingList = fetch(apis.buildingOwnerInfo.getBuildingList)
10
-const fetchUnitList = fetch(apis.buildingOwnerInfo.getUnitList)
11
-const fetchLevelList = fetch(apis.buildingOwnerInfo.getLevelList)
12
-const fetchRoomNoList = fetch(apis.buildingOwnerInfo.getRoomNoList)
13 9
 const buildingInfoList = fetch(apis.buildingOwnerInfo.buildingList)
14 10
 const deleteBuilding = fetch(apis.buildingOwnerInfo.deleteBuilding)
15 11
 
16 12
 const Condition = props => {
17
-  const [phaseList, setPhaseList] = useState([])
18
-  const [buildingList, setBuildingList] = useState([])
19
-  const [unitList, setUnitList] = useState([])
20
-  const [levelList, setLevelList] = useState([])
21
-  const [roomNoList, setRoomNoList] = useState([])
13
+  const {
14
+    phaseId,
15
+    setPhaseId,
16
+    buildingId,
17
+    setBuildingId,
18
+    unitId,
19
+    setUnitId,
20
+    levelId,
21
+    setLevelId,
22
+    roomNoId,
23
+    setRoomNoId,
24
+    phaseList,
25
+    buildingList,
26
+    unitList,
27
+    levelList,
28
+    roomNoList
29
+  } = useRoomSelect()
22 30
 
23
-  const [phaseId, setPhaseId] = useState()
24
-  const [buildingId, setBuildingId] = useState()
25
-  const [unitId, setUnitId] = useState()
26
-  const [levelId, setLevelId] = useState()
27
-  const [roomNoId, setRoomNoId] = useState()
28
-
29
-  // 获取期
30
-  useEffect(() => {
31
-    fetchPhaseList().then(res => setPhaseList(res))
32
-  }, [])
33
-
34
-  // 楼栋
35
-  useEffect(() => {
36
-    if (phaseId) {
37
-      fetchBuildingList({params: {phaseId}}).then(res => setBuildingList(res))
31
+  const handleSearch = vals => {
32
+    const data = {
33
+      ...vals,
34
+      phaseId,
35
+      buildingId,
36
+      unitId,
37
+      levelId,
38
+      roomNoId
38 39
     }
39
-    setBuildingId()
40
-  }, [phaseId])
41 40
 
42
-  // 单元
43
-  useEffect(() => {
44
-    if (phaseId && buildingId) {
45
-      fetchUnitList({params: {phaseId, buildingId}}).then(res => setUnitList(res))
41
+    if (props.onSearch) {
42
+      props.onSearch(data)
46 43
     }
47
-    setUnitId()
48
-  }, [phaseId, buildingId])
44
+  }
49 45
 
50
-  // 楼层
51
-  useEffect(() => {
52
-    if (phaseId && buildingId && unitId) {
53
-      fetchLevelList({params: {phaseId, buildingId, unitId}}).then(res => setLevelList(res))
46
+  const handleReset = vals => {
47
+    const data = {
48
+      ...vals,
49
+      phaseId: '',
50
+      buildingId: '',
51
+      unitId: '',
52
+      levelId: '',
53
+      roomNoId: ''
54 54
     }
55
+
56
+    setPhaseId()
57
+    setBuildingId()
58
+    setUnitId()
55 59
     setLevelId()
56
-  }, [phaseId, buildingId, unitId])
60
+    setRoomNoId()
57 61
 
58
-  // 房号
59
-  useEffect(() => {
60
-    if (phaseId && buildingId && unitId && levelId) {
61
-      fetchRoomNoList({params: {phaseId, buildingId, unitId, levelId}}).then(res => setRoomNoList(res))
62
+    if (props.onReset) {
63
+      props.onReset(data)
62 64
     }
63
-    setRoomNoId()
64
-  }, [phaseId, buildingId, unitId, levelId])
65
+  }
65 66
 
66 67
   return (
67 68
     <Search
68
-      onSearch={props.onSearch}
69
-      onReset={props.onReset}
69
+      onSearch={handleSearch}
70
+      onReset={handleReset}
70 71
       render={form => {
71 72
         const { getFieldDecorator } = form
72 73
         

+ 47
- 55
src/pages/property/ticket/index.jsx Просмотреть файл

@@ -1,7 +1,7 @@
1 1
 import React, { useState, useEffect } from 'react'
2 2
 import { Select, Spin, Table, Button, Form, Input, Divider, Typography } from 'antd'
3 3
 import NavLink from 'umi/navlink'
4
-import { fetchList, apis } from '@/utils/request'
4
+import { fetchList, apis, fetch } from '@/utils/request'
5 5
 import Search from '../components/Search'
6 6
 import List from '../components/List'
7 7
 
@@ -49,6 +49,8 @@ const StatusDict = [
49 49
 
50 50
 const getDictValue = (dict, val) => dict.filter(x => x.value === val)[0]
51 51
 
52
+const listTicket = fetch(apis.ticket.listTicket)
53
+
52 54
 const Condition = props => {
53 55
   return (
54 56
     <Search
@@ -111,23 +113,35 @@ const Condition = props => {
111 113
 export default props => {
112 114
   const [loading, setLoading] = useState(false)
113 115
   const [listData, setListData] = useState([])
116
+  const [pagination, setPagination] = useState({})
117
+  const [queryParams, setQueryParams] = useState({ pageNum: 1, pageSize: 10 })
114 118
 
115
-  const handleSearch = () => {
116
-
117
-  }
118
-
119
-  const handleDeleteRow = row => {
120
-
121
-  }
122
-
123
-  const handleEditRow = row => {
124
-
119
+  const handleSearch = vals => {
120
+    setQueryParams({
121
+      ...queryParams,
122
+      ...vals,
123
+      pageNum: 1,
124
+    })
125 125
   }
126 126
 
127 127
   const handlePageChange = (pageNum, pageSize) => {
128
-
128
+    setQueryParams({
129
+      ...queryParams,      
130
+      pageNum,
131
+      pageSize,
132
+    })
129 133
   }
130 134
 
135
+  useEffect(() => {
136
+    setLoading(true)
137
+    listTicket({data: queryParams}).then(res => {
138
+      const {list, ...pagi} = res
139
+      setListData(list)
140
+      setPagination(pagi)
141
+      setLoading(false)
142
+    }).catch(e => setLoading(false))
143
+  }, [queryParams])
144
+
131 145
   return (
132 146
     <div>
133 147
       <Condition onSearch={handleSearch} onReset={handleSearch} />
@@ -136,49 +150,27 @@ export default props => {
136 150
           <Button type="primary">添加</Button>
137 151
         </NavLink> */}
138 152
       </div>
139
-      <Spin spinning={loading}>
140
-        <List dataSource={listData} onPageChange={handlePageChange} rowKey="id">
141
-          <Table.Column title="编号" dataIndex="id" key="id" />
142
-          <Table.Column title="类型" dataIndex="type" key="type" render={x => getDictValue(TypeDict, x)} />
143
-          <Table.Column
144
-            title="标题"
145
-            dataIndex="ticketTitle"
146
-            key="ticketTitle"
147
-            render={(_, row) => {
148
-              return (
149
-                <NavLink to={`/xxx?id=${row.id}`}>
150
-                  <Typography.Text ellipsis>{row.ticketTitle}</Typography.Text>
151
-                </NavLink>
152
-              )
153
-            }}
154
-          />
155
-          <Table.Column title="发起人" dataIndex="createUserNmae" key="createUserNmae" />
156
-          <Table.Column title="发起时间" dataIndex="createDate" key="createDate" />
157
-          <Table.Column title="流转状态" dataIndex="status" key="status" render={x => getDictValue(StatusDict, x)} />
158
-          <Table.Column title="当前处理人" dataIndex="tpUserNmae" key="tpUserNmae" />
159
-          <Table.Column title="最近操作时间" dataIndex="updateDate" key="updateDate" />
160
-          <Table.Column
161
-            title="操作"
162
-            key="action"
163
-            render={(_, row) => {
164
-              return (
165
-                <>
166
-                  <Popconfirm
167
-                    title="确认进行作废操作?"
168
-                    onConfirm={() => handleDeleteRow(row)}
169
-                    okText="作废"
170
-                    cancelText="取消"
171
-                  >
172
-                    <Button type="link">删除</Button>
173
-                  </Popconfirm>
174
-                  <Divider type="vertical" />
175
-                  <Button type="link" onClick={() => handleEdit(row)}>编辑</Button>
176
-                </>
177
-              )
178
-            }}
179
-          />
180
-        </List>
181
-      </Spin>
153
+      <List dataSource={listData} loading={loading} pagination={pagination} onPageChange={handlePageChange} rowKey="id">
154
+        <Table.Column title="编号" dataIndex="id" key="id" />
155
+        <Table.Column title="类型" dataIndex="type" key="type" render={x => getDictValue(TypeDict, x)} />
156
+        <Table.Column
157
+          title="标题"
158
+          dataIndex="ticketTitle"
159
+          key="ticketTitle"
160
+          render={(_, row) => {
161
+            return (
162
+              <NavLink to={`/property/bill/ticket/detail?id=${row.id}`}>
163
+                <Typography.Text ellipsis>{row.ticketTitle}</Typography.Text>
164
+              </NavLink>
165
+            )
166
+          }}
167
+        />
168
+        <Table.Column title="发起人" dataIndex="createUserNmae" key="createUserNmae" />
169
+        <Table.Column title="发起时间" dataIndex="createDate" key="createDate" />
170
+        <Table.Column title="流转状态" dataIndex="status" key="status" render={x => getDictValue(StatusDict, x)} />
171
+        <Table.Column title="当前处理人" dataIndex="tpUserNmae" key="tpUserNmae" />
172
+        <Table.Column title="最近操作时间" dataIndex="updateDate" key="updateDate" />
173
+      </List>
182 174
 
183 175
     </div>
184 176
   )

+ 77
- 0
src/pages/property/utils/hooks/useRoomSelect.js Просмотреть файл

@@ -0,0 +1,77 @@
1
+import React, { useState, useEffect } from 'react'
2
+import { fetch, apis } from '@/utils/request'
3
+
4
+const fetchPhaseList = fetch(apis.buildingOwnerInfo.getPhaseList)
5
+const fetchBuildingList = fetch(apis.buildingOwnerInfo.getBuildingList)
6
+const fetchUnitList = fetch(apis.buildingOwnerInfo.getUnitList)
7
+const fetchLevelList = fetch(apis.buildingOwnerInfo.getLevelList)
8
+const fetchRoomNoList = fetch(apis.buildingOwnerInfo.getRoomNoList)
9
+
10
+export default function useRoomSelect() {
11
+  const [phaseList, setPhaseList] = useState([])
12
+  const [buildingList, setBuildingList] = useState([])
13
+  const [unitList, setUnitList] = useState([])
14
+  const [levelList, setLevelList] = useState([])
15
+  const [roomNoList, setRoomNoList] = useState([])
16
+
17
+  const [phaseId, setPhaseId] = useState()
18
+  const [buildingId, setBuildingId] = useState()
19
+  const [unitId, setUnitId] = useState()
20
+  const [levelId, setLevelId] = useState()
21
+  const [roomNoId, setRoomNoId] = useState()
22
+
23
+  // 获取期
24
+  useEffect(() => {
25
+    fetchPhaseList().then(res => setPhaseList(res))
26
+  }, [])
27
+
28
+  // 楼栋
29
+  useEffect(() => {
30
+    if (phaseId) {
31
+      fetchBuildingList({params: {phaseId}}).then(res => setBuildingList(res))
32
+    }
33
+    setBuildingId()
34
+  }, [phaseId])
35
+
36
+  // 单元
37
+  useEffect(() => {
38
+    if (phaseId && buildingId) {
39
+      fetchUnitList({params: {phaseId, buildingId}}).then(res => setUnitList(res))
40
+    }
41
+    setUnitId()
42
+  }, [phaseId, buildingId])
43
+
44
+  // 楼层
45
+  useEffect(() => {
46
+    if (phaseId && buildingId && unitId) {
47
+      fetchLevelList({params: {phaseId, buildingId, unitId}}).then(res => setLevelList(res))
48
+    }
49
+    setLevelId()
50
+  }, [phaseId, buildingId, unitId])
51
+
52
+  // 房号
53
+  useEffect(() => {
54
+    if (phaseId && buildingId && unitId && levelId) {
55
+      fetchRoomNoList({params: {phaseId, buildingId, unitId, levelId}}).then(res => setRoomNoList(res))
56
+    }
57
+    setRoomNoId()
58
+  }, [phaseId, buildingId, unitId, levelId])
59
+
60
+  return {
61
+    phaseId,
62
+    setPhaseId,
63
+    buildingId,
64
+    setBuildingId,
65
+    unitId,
66
+    setUnitId,
67
+    levelId,
68
+    setLevelId,
69
+    roomNoId,
70
+    setRoomNoId,
71
+    phaseList,
72
+    buildingList,
73
+    unitList,
74
+    levelList,
75
+    roomNoList
76
+  }
77
+}

+ 41
- 0
src/services/announcement_api.js Просмотреть файл

@@ -0,0 +1,41 @@
1
+
2
+export default prefix => {
3
+  return {
4
+    
5
+    // 获取当前小区的所有公告
6
+    listAnnouncement: {
7
+      url: `${prefix}/tpAnnouncement`,
8
+      method: 'post',
9
+      action: 'admin.announcement.post'
10
+    },
11
+
12
+    // 添加公告
13
+    addAnnouncement: {
14
+      url: `${prefix}/addAnnouncement`,
15
+      method: 'post',
16
+      action: 'admin.announcement.add'
17
+    },
18
+
19
+    // 根据id查询公告
20
+    announcementById: {
21
+      url: `${prefix}/announcementById`,
22
+      method: 'post',
23
+      action: 'admin.announcement.detail'
24
+    },
25
+
26
+    // 修改公告
27
+    updateannouncement: {
28
+      url: `${prefix}/updateAnnouncement`,
29
+      method: 'post',
30
+      action: 'admin.announcement.update'
31
+    },
32
+
33
+    // 批量删除(data)里面是单子字段的多个id
34
+    deleteAnnouncement: {
35
+      url: `${prefix}/deleteAnnouncement`,
36
+      method: 'post',
37
+      action: 'admin.announcement.delete'
38
+    },
39
+
40
+  }
41
+}

+ 4
- 0
src/services/apis.js Просмотреть файл

@@ -2,6 +2,8 @@ import { APIBaseURL, AMapAPIPrefix } from '../utils/constant'
2 2
 import bill from './bill_api'
3 3
 import buildingOwnerInfo from './buildingOwnerInfo_api'
4 4
 import propUser from './prop_user_api'
5
+import announcement from './announcement_api'
6
+import ticket from './ticket_api'
5 7
 
6 8
 const prefix = `${APIBaseURL}api/admin`
7 9
 
@@ -13,6 +15,8 @@ export default {
13 15
   bill: bill(prefix),
14 16
   propUser: propUser(prefix),
15 17
   buildingOwnerInfo: buildingOwnerInfo(prefix),
18
+  announcement: announcement(prefix),
19
+  ticket: ticket(prefix),
16 20
   image: {
17 21
     uploadForAnt: {
18 22
       url: `${prefix}/antd/image`,

+ 112
- 0
src/services/bill_api.js Просмотреть файл

@@ -34,11 +34,123 @@ export default prefix => ({
34 34
     action: 'admin.bill.downloadExcel'
35 35
   },
36 36
 
37
+  // 上传 excel 模板
38
+  billUploadExcel: {
39
+    url: `${prefix}/bill/uploadExcel/get`,
40
+    method: 'post',
41
+    action: 'admin.bill.uploadExcel'
42
+  },
43
+
37 44
   // 根据收费项ID查询,收费项详情
38 45
   getBillInfoBydId: {
39 46
     url: `${prefix}/bill/:id`,
40 47
     method: 'get',
41 48
     action: 'admin.bill.get'
49
+  },
50
+
51
+  // 根据缴费项id, 查询草稿
52
+  billInvoiceGetInvoiceInvalid: {
53
+    url: `${prefix}/bill/invoice/getInvoiceInvalid`,
54
+    method: 'post',
55
+    action: 'admin.bill-invoice.getInvoiceInvalid'
56
+  },
57
+
58
+  // 获取流水信息
59
+  getBillStatementAll: {
60
+    url: `${prefix}/bill/statement/all`,
61
+    method: 'post',
62
+    action: 'admin.bill-statement.all'
63
+  },
64
+
65
+  // 下载excel
66
+  exportStatementExcel: {
67
+    url: `${prefix}/bill/statement/exportExcel`,
68
+    method: 'get',
69
+    action: 'admin.bill-statement.export'
70
+  },
71
+
72
+  // 根据点单查询,缴费单
73
+  getByOrderNumberBillInvoice: {
74
+    url: `${prefix}/bill/order/getByOrderNumberBillInvoice/:id`,
75
+    method: 'get',
76
+    action: 'admin.bill-statement.getByOrderNumberBillInvoice'
77
+  },
78
+
79
+  // 查询缴费单
80
+  getBillInvoiceList: {
81
+    url: `${prefix}/bill/invoice/list`,
82
+    method: 'post',
83
+    action: 'admin.bill-invoice.list'
84
+  },
85
+
86
+  //  根据 id 批量删除 缴费单
87
+  deleteBillInvoiceById: {
88
+    url: `${prefix}/bill/invoice/delete`,
89
+    method: 'post',
90
+    action: 'admin.bill-invoice.delete'
91
+  },
92
+
93
+  // 设置线下缴费
94
+  billInvoiceOfflinePayment: {
95
+    url: `${prefix}/bill/invoice/offlinePayment`,
96
+    method: 'post',
97
+    action: 'admin.bill-invoice.offlinePayment'
98
+  },
99
+
100
+  // 根据缴费单id, 修改金额
101
+  updateBillInvoiceIdPayPrice: {
102
+    url: `${prefix}/bill/invoice/updateBillInvoiceIdPayPrice/:id`,
103
+    method: 'post',
104
+    action: 'admin.bill-invoice.updatePrice'
105
+  },
106
+  
107
+// 根据收费单id, 修改收费说明
108
+  updateBillInvoiceIdBillInvoiceExplain: {
109
+    url: `${prefix}/bill/invoice/updateBillInvoiceIdBillInvoiceExplain/:id`,
110
+    method: 'post',
111
+    action: 'admin.bill-invoice.updateExplain'
112
+  },
113
+
114
+  // 修改缴费项 收费项名称,缴费项说明,截止时间
115
+  updateBillNameAndBillExplainAndEndDate: {
116
+    url: `${prefix}/bill/invoice/updateBill`,
117
+    method: 'put',
118
+    action: 'admin.bill-invoice.updateBill'
119
+  },
120
+
121
+  // 导出excel
122
+  exportBillInvoiceExcel: {
123
+    url: `${prefix}/bill/invoice/exportExcel/:id`,
124
+    method: 'get',
125
+    action: 'admin.bill-invoice.exportExcel'
126
+  },
127
+
128
+// 由前台批量添加收费单, 默认定为 作废
129
+  addTempBillInvoice: {
130
+    url: `${prefix}/bill/invoice/addTempBillInvoice`,
131
+    method: 'post',
132
+    action: 'admin.bill-invoice.addTempBill'
133
+  },
134
+
135
+  // 查询前台批量添加的收费单, 状态是作废
136
+  getTempBillInvoice: {
137
+    url: `${prefix}/bill/invoice/getTempBillInvoice/:id`,
138
+    method: 'get',
139
+    action: 'admin.bill-invoice.tempBill'
140
+  },
141
+
142
+  // 根据id删除收费单, 只能删除作废的
143
+  deleteTempBillInvoice: {
144
+    url: `${prefix}/bill/invoice/deleteTempBillInvoice/:id`,
145
+    method: 'delete',
146
+    action: 'admin.bill-invoice.deleteTempBill'
147
+  },
148
+
149
+  // 由前台批量添加收费单, 进行统一的提交, 修改为有效
150
+  updateBillInvoiceStatus: {
151
+    url: '/bill/invoice/updateBillInvoiceStatus',
152
+    method: 'post',
153
+    action: 'admin.bill-invoice.updateStatus'
42 154
   }
43 155
 
44 156
 })

+ 40
- 0
src/services/ticket_api.js Просмотреть файл

@@ -0,0 +1,40 @@
1
+
2
+export default prefix => {
3
+  return {
4
+    listTicket: {
5
+      url: `${prefix}/ticketLiset`,
6
+      method: 'post',
7
+      action: 'admin.ticket.list'
8
+    },
9
+
10
+    ticketEdit: {
11
+      url: `${prefix}/ticketDetails`,
12
+      method: 'post',
13
+      action: 'admin.ticket.detail'
14
+    },
15
+
16
+    addRecordComment: {
17
+      url: `${prefix}/addRecordComment`,
18
+      method: 'post',
19
+      action: 'admin.comment.add'
20
+    },
21
+
22
+    addRecord: {
23
+      url: `${prefix}/addRecord`,
24
+      method: 'post',
25
+      action: 'admin.record.add'
26
+    },
27
+
28
+    updateTicketStatus: {
29
+      url: `${prefix}/updateTicketStatus`,
30
+      method: 'post',
31
+      action: 'admin.ticket-status.update'
32
+    },
33
+
34
+    updateTicket: {
35
+      url: `${prefix}/updateTicket`,
36
+      method: 'post',
37
+      action: 'admin.ticket.update'
38
+    }
39
+  }
40
+}