index.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. import { contractStore, tenderStore } from '@/store/mobx'
  2. import { iContractState, iIncomeTree } from '@/types/contract'
  3. import { contractConsts } from '@/utils/common/constStatus'
  4. import consts from '@/utils/consts'
  5. import { Button, Input, message, Radio, Table, Tabs } from 'antd'
  6. import Modal from 'antd/lib/modal/Modal'
  7. import { RadioChangeEvent } from 'antd/lib/radio'
  8. import { ColumnsType } from 'antd/lib/table'
  9. import { observer } from 'mobx-react'
  10. import React, { useEffect, useRef, useState } from 'react'
  11. import { apiGetIncome, apiResfulContractTree } from '../../api'
  12. import { apiContractIncome, apiSetTemplate } from '../Modal/api'
  13. import Detail from '../Tabs/Detail'
  14. import File from '../Tabs/File'
  15. import Receivable from '../Tabs/Receivable'
  16. import styles from './index.module.scss'
  17. interface iTableContentPorps {
  18. modalHandler: (type: string) => void
  19. row: iIncomeTree
  20. setRow: (record: iIncomeTree) => void
  21. }
  22. interface iTemplateState {
  23. attribution: string
  24. children: iTemplateState[] | undefined
  25. depth: number
  26. id: number
  27. isEnd: boolean
  28. leaf: boolean
  29. name: string
  30. parentId: number
  31. serial: string
  32. }
  33. interface iShowTemplateState {
  34. isShow: boolean
  35. template: string
  36. loading: boolean
  37. }
  38. const GCsheet: React.FC<iTableContentPorps> = ({ modalHandler, row, setRow }) => {
  39. const [ sectionTemplate, setSectionTemplate ] = useState<iShowTemplateState>({
  40. isShow: false,
  41. template: '',
  42. loading: false
  43. })
  44. const [ tempalte, setTempalte ] = useState<{template1: iTemplateState, template2: iTemplateState}>({
  45. template1: {
  46. attribution: '',
  47. children: undefined,
  48. depth: 0,
  49. id: 0,
  50. isEnd: false,
  51. leaf: false,
  52. name: '',
  53. parentId: 0,
  54. serial: ''
  55. },
  56. template2: {
  57. attribution: '',
  58. children: undefined,
  59. depth: 0,
  60. id: 0,
  61. isEnd: false,
  62. leaf: false,
  63. name: '',
  64. parentId: 0,
  65. serial: ''
  66. }
  67. })
  68. const [ contract, setContract ] = useState<iContractState>({
  69. bidsectionId: "",
  70. code: "",
  71. content: "",
  72. contractsType: 0,
  73. createTime: "",
  74. id: "",
  75. name: "",
  76. paid: "",
  77. partyA: "",
  78. partyASigner: "",
  79. partyB: "",
  80. partyBSigner: "",
  81. price: "",
  82. projectId: "",
  83. remarks: "",
  84. returned: "",
  85. signerTime: "",
  86. status: 0,
  87. treeId: "",
  88. updateTime: ""
  89. })
  90. const { TabPane } = Tabs
  91. useEffect(() => {
  92. initHandler()
  93. }, [])
  94. const initHandler = async () => {
  95. const data = await apiContractIncome(tenderStore.bid)
  96. if (data.code === consts.RET_CODE.SUCCESS) {
  97. if (data.isTemplate && data.isTemplate === 1) {
  98. setSectionTemplate({
  99. ...sectionTemplate,
  100. isShow: true
  101. })
  102. setTempalte({
  103. ...tempalte,
  104. template1: data.sectionTemplate1,
  105. template2: data.sectionTemplate2
  106. })
  107. } else {
  108. contractStore.updateTree(data.sectionTree.children)
  109. }
  110. }
  111. }
  112. interface iLabelHandlerProps {
  113. id: string
  114. bidsectionId: string
  115. name?: string
  116. }
  117. const newLabelHandler = async (type: string, payload: iLabelHandlerProps) => {
  118. let RET_CODE: number = -1
  119. if (type === 'name') {
  120. payload.name = inputEl.current?.state.value
  121. const { code = -1 } = await apiResfulContractTree('add', payload)
  122. RET_CODE = code
  123. }
  124. if (RET_CODE === consts.RET_CODE.SUCCESS) {
  125. contractStore.resetTree(tenderStore.bidsectionId)
  126. }
  127. }
  128. const inputEl = useRef<Input>(null)
  129. const modalColumns: ColumnsType<iTemplateState> = [
  130. {
  131. title: '项目节',
  132. dataIndex: 'serial',
  133. width: '30%',
  134. // eslint-disable-next-line react/display-name
  135. render: (text: string, row: iTemplateState) => {
  136. const { attribution = '', serial = '' } = row
  137. return <span>{`${attribution}${serial}`}</span>
  138. }
  139. },
  140. {
  141. title: '名称',
  142. dataIndex: 'name',
  143. width: '70%'
  144. }
  145. ]
  146. const TableColumns: ColumnsType<iIncomeTree> = [
  147. {
  148. title: '编号',
  149. dataIndex: 'code',
  150. width: '15%',
  151. // eslint-disable-next-line react/display-name
  152. render: (text: string, row: iIncomeTree) => {
  153. // if (row.isEdit) {
  154. // return <Input value={row.serial} addonBefore={row.attribution} size="small"></Input>
  155. // } else {
  156. // return <span>{row.code}</span>
  157. // }
  158. return <span>{row.code}</span>
  159. }
  160. },
  161. {
  162. title: '项目名称',
  163. dataIndex: 'name',
  164. render: (text:any, record: iIncomeTree) => {
  165. if (record.isEdit) {
  166. return <Input value={record.name} size="small" type="text" ref={inputEl} onPressEnter={() => newLabelHandler('name', { id: record.parentId, bidsectionId: record.bidsectionId })} onBlur={() => newLabelHandler('name', { id: record.parentId, bidsectionId: record.bidsectionId })}></Input>
  167. } else {
  168. return <span>{text}</span>
  169. }
  170. }
  171. },
  172. {
  173. title: '合同名称',
  174. dataIndex: 'contractName'
  175. },
  176. {
  177. title: '合同编号',
  178. dataIndex: 'contractCode'
  179. },
  180. {
  181. title: '合同金额',
  182. dataIndex: 'contractPrice',
  183. align: 'right',
  184. // eslint-disable-next-line react/display-name
  185. render: (text:any, record: iIncomeTree) => record.contractCode ? <span>{text}</span> : ''
  186. },
  187. {
  188. title: '回款金额',
  189. dataIndex: 'contractReturned',
  190. align: 'right',
  191. // eslint-disable-next-line react/display-name
  192. render: (text:any, record: iIncomeTree) => record.contractCode ? <span>{text}</span> : ''
  193. },
  194. {
  195. title: '状态',
  196. dataIndex: 'contractStatus',
  197. // eslint-disable-next-line react/display-name
  198. render: (_: any, record: iIncomeTree) => record.contractCode ? <span><i className={contractConsts[record.contractStatus].className}></i>{contractConsts[record.contractStatus].text}</span> : ''
  199. }
  200. ]
  201. // modal 确认 - 回调
  202. const handleModalConfirm = async () => {
  203. setSectionTemplate({
  204. ...sectionTemplate,
  205. loading: true
  206. })
  207. if (!sectionTemplate.template) return message.error('请选择项目节模板!')
  208. const { code = -1 } = await apiSetTemplate(sectionTemplate.template, tenderStore.bidsectionId)
  209. if (code === consts.RET_CODE.SUCCESS) {
  210. await initHandler()
  211. }
  212. setSectionTemplate({
  213. ...sectionTemplate,
  214. loading: false,
  215. isShow: false
  216. })
  217. }
  218. // 模板选择radio切换回调
  219. const handleRadioEvent = (e: RadioChangeEvent) => {
  220. if (e.target.checked) {
  221. setSectionTemplate({
  222. ...sectionTemplate,
  223. template: e.target.value
  224. })
  225. }
  226. }
  227. const onClickRow = (record: iIncomeTree) => {
  228. return {
  229. onClick() {
  230. console.log(record.id)
  231. rowClickHandler(record.id, record.bidsectionId, record.isEdit)
  232. }
  233. }
  234. }
  235. // 行点击回调
  236. const rowClickHandler = async (id: string, bid: string, isEdit?: boolean) => {
  237. if (!isEdit) {
  238. const { code = -1, section = {}, contract: newContract = {} } = await apiGetIncome(id, bid)
  239. if (code === consts.RET_CODE.SUCCESS) {
  240. setRow(section)
  241. setContract({ ...contract, ...newContract })
  242. contractStore.rowChange(id)
  243. }
  244. }
  245. }
  246. const handleRowClass = (record: iIncomeTree) => {
  247. return record.id === row.id ? 'ant-table-row-selected' : ''
  248. }
  249. return sectionTemplate.isShow ?
  250. <Modal
  251. visible={sectionTemplate.isShow}
  252. maskClosable={false}
  253. title="选择合同项目节模板"
  254. okText="确定"
  255. confirmLoading={sectionTemplate.loading}
  256. cancelText="关闭"
  257. closable={false}
  258. keyboard={false}
  259. onOk={() => handleModalConfirm()}
  260. width='70vw'
  261. >
  262. <div className={styles.modalWarnText}>默认项目节无法修改,可自行增加维护子节点</div>
  263. <div className={styles.modalTemplateContent}>
  264. <div className={styles.leftTemplate}>
  265. <div className="pi-pd-20">
  266. <Radio value="1" checked={sectionTemplate.template === '1'} onChange={(e: RadioChangeEvent) => handleRadioEvent(e)}><span className="pi-gray">项目节模板1</span></Radio>
  267. </div>
  268. <div className={styles.projectTable}>
  269. {
  270. tempalte.template1?.children && tempalte.template1?.children.length?
  271. <Table
  272. dataSource={tempalte.template1?.children}
  273. columns={modalColumns}
  274. pagination={false}
  275. bordered
  276. scroll={{ y: '300px' }}
  277. rowKey={record => record.id}
  278. defaultExpandAllRows={true}
  279. >
  280. </Table> : ''
  281. }
  282. </div>
  283. </div>
  284. <div className={styles.rightTemplate}>
  285. <div className="pi-pd-20 pi-gray">
  286. <Radio value="2" checked={sectionTemplate.template === '2'} onChange={(e: RadioChangeEvent) => handleRadioEvent(e)}><span className="pi-gray">项目节模板2</span></Radio>
  287. </div>
  288. <div className={styles.projectTable}>
  289. {
  290. tempalte.template2?.children && tempalte.template2?.children.length? <Table
  291. dataSource={tempalte.template2?.children}
  292. columns={modalColumns}
  293. bordered
  294. pagination={false}
  295. scroll={{ y: '300px' }}
  296. rowKey={record => record.id}
  297. defaultExpandAllRows={true}
  298. >
  299. </Table> : ''
  300. }
  301. </div>
  302. </div>
  303. </div>
  304. </Modal>
  305. :
  306. <div className={styles.spreadContent}>
  307. <div className={styles.spreadSheets}>
  308. {
  309. contractStore.showTable ?
  310. <Table<iIncomeTree>
  311. dataSource={contractStore.tree}
  312. columns={TableColumns}
  313. bordered
  314. pagination={false}
  315. rowKey={record => record.id}
  316. defaultExpandAllRows={true}
  317. onRow={onClickRow}
  318. rowClassName={handleRowClass}
  319. style={{ height: '100%', overflowY: 'scroll' }}
  320. />
  321. : ''
  322. }
  323. </div>
  324. <div className={styles.extraControl}>
  325. <Tabs
  326. type="card"
  327. size="small"
  328. defaultActiveKey="1"
  329. tabBarExtraContent={{ right: <div className="pi-mg-right-5"><Button type="primary" size="small" danger className="pi-mg-right-3" onClick={() => modalHandler('close')}>关闭合同</Button><Button type="primary" size="small" onClick={() => modalHandler('edit')}>编辑合同</Button></div> }}>
  330. <TabPane key="1" tab="合同详情">
  331. <Detail></Detail>
  332. </TabPane>
  333. <TabPane key="2" tab="合同回款">
  334. <Receivable></Receivable>
  335. </TabPane>
  336. <TabPane key="3" tab="合同文件">
  337. <File></File>
  338. </TabPane>
  339. </Tabs>
  340. </div>
  341. </div>
  342. }
  343. export default observer(GCsheet)