index.jsx 12KB

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