123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431 |
- import Authorization from '@/components/Authorization'
- import { ZhSubmitButton } from '@/components/Button'
- import OssUploadModal from '@/components/OssUpload'
- import { contractStore, tenderStore } from '@/store/mobx'
- import { ContractType } from '@/store/mobx/contract'
- import { ContractTree, iShowTemplateState, iTemplateState } from '@/types/contract'
- import { iFile } from '@/types/file'
- import { apiSaveFileInfo } from '@/utils/common/api'
- import { contractConsts } from '@/utils/common/constStatus'
- import { useTableExpand } from '@/hooks/tableHooks'
- import consts from '@/utils/consts'
- import { formatMoney } from '@/utils/util'
- import { Button, message, Radio, Table, Tabs } from 'antd'
- import Modal from 'antd/lib/modal/Modal'
- import { RadioChangeEvent } from 'antd/lib/radio'
- import { ColumnsType } from 'antd/lib/table'
- import { observer } from 'mobx-react'
- import React, { useEffect, useState } from 'react'
- import { apiGetContractWithDetail, apiUpdateContractName, apiUpdateSerial } from '../../api'
- import { apiContractTree, apiSetTemplate } from '../Modal/api'
- import Detail from '../Tabs/Detail'
- import File from '../Tabs/File'
- import Receivable from '../Tabs/Receivable'
- import { EditableCell, EditableRow } from './EditableTable'
- import styles from './index.module.scss'
- import './index.scss'
- type EditableTableProps = Parameters<typeof Table>[0];
- type ColumnTypes = Exclude<EditableTableProps['columns'], undefined>;
- interface iTableContentPorps {
- changeModalType: (type: string) => void
- row: ContractTree
- setRow: (record: ContractTree) => void
- history: any
- type: 'income' | 'expenditure'
- }
- const GCsheet: React.FC<iTableContentPorps> = ({ changeModalType, row, setRow, history, type }) => {
- const [ sectionTemplate, setSectionTemplate ] = useState<iShowTemplateState>({
- isShow: false,
- template: '',
- loading: false
- })
- const [ ids, setRowKeys ] = useTableExpand(contractStore.tree)
- const [ tempalte, setTempalte ] = useState<{ template1: iTemplateState, template2: iTemplateState }>({
- template1: {
- attribution: '',
- children: undefined,
- depth: 0,
- id: 0,
- isEnd: false,
- leaf: false,
- name: '',
- parentId: 0,
- serial: ''
- },
- template2: {
- attribution: '',
- children: undefined,
- depth: 0,
- id: 0,
- isEnd: false,
- leaf: false,
- name: '',
- parentId: 0,
- serial: ''
- }
- })
- // 阿里oss弹窗控制器
- const [ visible, setVisible ] = useState<boolean>(false)
- const { TabPane } = Tabs
- useEffect(() => {
- initData()
- }, [])
- const initData = async () => {
- const data = await apiContractTree(type, tenderStore.bid)
- if (data.code === consts.RET_CODE.SUCCESS) {
- if (data.isTemplate && data.isTemplate === 1) {
- setSectionTemplate({
- ...sectionTemplate,
- isShow: true
- })
- setTempalte({
- ...tempalte,
- template1: data.sectionTemplate1,
- template2: data.sectionTemplate2
- })
- } else {
- contractStore.updateTree(data.sectionTree.children)
- }
- }
- // 初始化时如果id存在说明只是table更新了,那么要将store里面的合同数据也一起更新,防止合同详情不是最新的数据
- if (row.id) {
- handleRowClick(row.id, row.bidsectionId)
- }
- }
- const handleUpdateContractName = async (payload: object) => {
- const { code = -1 } = await apiUpdateContractName(payload)
- if (code === consts.RET_CODE.SUCCESS) {
- contractStore.resetTree(type, tenderStore.tender.bidsectionId)
- }
- }
- const codeChange = async (value: string, row: ContractTree) => {
- const { code = -1 } = await apiUpdateSerial(row.id, row.bidsectionId, value, type === ContractType.INCOME ? 0 : 1)
- if (code === consts.RET_CODE.SUCCESS) {
- initData()
- }
- }
- const modalColumns: ColumnsType<iTemplateState> = [
- {
- title: '项目节',
- dataIndex: 'serial',
- width: '30%',
- // eslint-disable-next-line react/display-name
- render: (text: string, row: iTemplateState) => {
- const { attribution = '', serial = '' } = row
- return <span>{`${attribution}${serial}`}</span>
- }
- },
- {
- title: '名称',
- dataIndex: 'name',
- width: '70%'
- }
- ]
- const tableColumns: (ColumnTypes[number] & { editable?: boolean; dataIndex: string })[] = [
- {
- title: '编号',
- dataIndex: 'code',
- width: '20%',
- editable: true
- },
- {
- title: '项目名称',
- dataIndex: 'name',
- width: '20%',
- editable: true
- },
- {
- title: '合同名称',
- dataIndex: 'contractName',
- width: '15%'
- },
- {
- title: '合同编号',
- dataIndex: 'contractCode',
- width: '15%'
- },
- {
- title: '合同金额',
- dataIndex: 'contractPrice',
- align: 'right',
- width: '10%',
- // eslint-disable-next-line react/display-name
- render: (text: any) => <span>{formatMoney(text)}</span>
- },
- {
- title: type === ContractType.INCOME ? '回款金额' : '支付金额',
- dataIndex: type === ContractType.INCOME ? 'contractReturned' : 'contractsPaid',
- align: 'right',
- width: '10%',
- // eslint-disable-next-line react/display-name
- render: (text: any) => <span>{formatMoney(text)}</span>
- },
- {
- title: '状态',
- dataIndex: 'contractStatus',
- width: '10%',
- // eslint-disable-next-line react/display-name
- render: (_: any, record: any) => record.contractCode ? <span className={contractConsts[record.contractStatus].className}>{contractConsts[record.contractStatus].text}</span> : null
- }
- ]
- // modal 确认 - 回调
- const handleModalConfirm = async () => {
- setSectionTemplate({
- ...sectionTemplate,
- loading: true
- })
- if (!sectionTemplate.template) {
- setSectionTemplate({
- ...sectionTemplate,
- loading: false
- })
- return message.error('请选择项目节模板')
- }
- const { code = -1 } = await apiSetTemplate(sectionTemplate.template, tenderStore.tender.bidsectionId, type === 'income' ? 0 : 1)
- if (code === consts.RET_CODE.SUCCESS) {
- await initData()
- }
- setSectionTemplate({
- ...sectionTemplate,
- loading: false,
- isShow: false
- })
- }
- // modal 关闭 - 回调
- const handleModalCancel = () => {
- history.push('/console/contract/content/summary')
- }
- // 模板选择radio切换回调
- const handleRadioEvent = (e: RadioChangeEvent) => {
- if (e.target.checked) {
- setSectionTemplate({
- ...sectionTemplate,
- template: e.target.value
- })
- }
- }
- const onClickRow = (record: any) => {
- return {
- onClick() {
- handleRowClick(record.id, record.bidsectionId)
- }
- }
- }
- // 行点击回调
- const handleRowClick = async (id: string, bid: string) => {
- const { code = -1, section = {}, contract: newContract = {} } = await apiGetContractWithDetail(id, bid, type)
- if (code === consts.RET_CODE.SUCCESS) {
- setRow(section)
- contractStore.updateContract(newContract)
- }
- }
- const handleRowClass = (record: any) => {
- return record.id === row.id ? 'ant-table-row-selected editable-row' : ''
- }
- const tabOnClick = (key: string) => {
- contractStore.changeActiveKey(key)
- }
- // 阿里oss上传弹窗
- const onShow = (show: boolean) => setVisible(show)
- const onCreate = async (fileList: iFile[]) => {
- const { code = -1 } = await apiSaveFileInfo(fileList, type === ContractType.INCOME ? consts.DATA_TYPE.INCOME : consts.DATA_TYPE.EXPENDITURE, row.contractId)
- if (code === consts.RET_CODE.SUCCESS) {
- setVisible(false)
- contractStore.changeActiveKey('3')
- }
- }
- const components = {
- body: {
- row: EditableRow,
- cell: EditableCell
- }
- }
- const handleSave = (dataIndex: keyof ContractTree, value: string, row: ContractTree) => {
- if (dataIndex === 'code') {
- codeChange(value, row)
- } else {
- handleUpdateContractName({ id: row.id, bidsectionId: row.bidsectionId, treeType: type === ContractType.INCOME ? 0 : 1, name: value })
- }
- }
- const _tableColumns = tableColumns.map(col => {
- if (!col.editable) {
- return col
- }
- return {
- ...col,
- onCell: (record: ContractTree) => ({
- record,
- editable: col.editable,
- dataIndex: col.dataIndex,
- title: col.title,
- handleSave
- })
- }
- })
- return sectionTemplate.isShow ?
- <Modal
- visible={sectionTemplate.isShow}
- getContainer={false}
- maskClosable={false}
- title="选择合同项目节模板"
- okText="确定"
- confirmLoading={sectionTemplate.loading}
- cancelText="关闭"
- onCancel={handleModalCancel}
- closable={false}
- keyboard={false}
- onOk={() => handleModalConfirm()}
- width='70vw'
- >
- <div className={styles.modalWarnText}>默认项目节无法修改,可自行增加维护子节点</div>
- <div className={styles.modalTemplateContent}>
- <div className={[ styles.leftTemplate, sectionTemplate.template == '1' ? styles.active : '' ].join(' ')}>
- <div className="pi-pd-20">
- <Radio value="1" checked={sectionTemplate.template === '1'} onChange={(e: RadioChangeEvent) => handleRadioEvent(e)}><span className="pi-gray">项目节模板1</span></Radio>
- </div>
- <div className={styles.projectTable}>
- {
- tempalte.template1?.children && tempalte.template1?.children.length ?
- <Table
- dataSource={tempalte.template1?.children}
- columns={modalColumns}
- pagination={false}
- bordered
- scroll={{ y: '300px' }}
- rowKey={record => record.id}
- defaultExpandAllRows={true}
- /> : ''
- }
- </div>
- </div>
- <div className={[ styles.rightTemplate, sectionTemplate.template == '2' ? styles.active : '' ].join(' ')}>
- <div className="pi-pd-20 pi-gray">
- <Radio value="2" checked={sectionTemplate.template === '2'} onChange={(e: RadioChangeEvent) => handleRadioEvent(e)}><span className="pi-gray">项目节模板2</span></Radio>
- </div>
- <div className={styles.projectTable}>
- {
- tempalte.template2?.children && tempalte.template2?.children.length ?
- <Table
- dataSource={tempalte.template2?.children}
- columns={modalColumns}
- bordered
- pagination={false}
- scroll={{ y: '300px' }}
- rowKey={record => record.id}
- defaultExpandAllRows={true}
- />
- : ''
- }
- </div>
- </div>
- </div>
- </Modal>
- :
- <div className={styles.spreadContent}>
- <div className={styles.spreadSheets}>
- {
- contractStore.showTable ?
- <Table
- components={components}
- dataSource={contractStore.tree}
- columns={_tableColumns as ColumnTypes}
- bordered
- pagination={false}
- defaultExpandAllRows={true}
- onRow={onClickRow}
- rowClassName={handleRowClass}
- expandable={{ expandedRowKeys: ids, onExpand: (expanded: boolean, record: any) => setRowKeys(expanded, record as ContractTree) }}
- style={{ height: '100%', overflowY: 'scroll' }}
- />
- : ''
- }
- </div>
- <div className={styles.extraControl}>
- <Tabs
- type="card"
- size="small"
- defaultActiveKey="1"
- onTabClick={(key: string) => tabOnClick(key)}
- tabBarExtraContent={{
- right:
- <div className="pi-mg-right-5 pi-flex-row">
- {
- contractStore.contract.id && contractStore.contract.status === contractConsts.status.checking ?
- <>
- <Button type="primary" size="small" onClick={() => changeModalType('add')} >{type === ContractType.INCOME ? '添加回款' : '添加支付'}</Button>
- </>
- : null
- }
- {
- contractStore.contract.id && contractStore.contract.status !== contractConsts.status.closed ?
- <>
- <Authorization type="contract" auth="add">
- <Button type="primary" size="small" onClick={() => changeModalType('update')} className="pi-mg-left-5">编辑合同</Button>
- </Authorization>
- <Button type="primary" size="small" onClick={() => setVisible(true)} className="pi-mg-left-5">上传文件</Button>
- </>
- : null
- }
- {
- contractStore.contract.id && contractStore.contract.status === contractConsts.status.willClose ?
- <Button type="primary" size="small" danger className="pi-mg-left-5" onClick={() => changeModalType('close')}>关闭合同</Button>
- : null
- }
- {
- contractStore.contract.id && contractStore.contract.status === contractConsts.status.closed ?
- <ZhSubmitButton type="primary" size="small" danger className="pi-mg-left-5" onClick={() => changeModalType('unlock')}>解锁合同</ZhSubmitButton>
- : null
- }
- </div>
- }}>
- <TabPane key="1" tab="合同详情">
- <Detail contract={{ ...contractStore.contract }} type={type} />
- </TabPane>
- <TabPane key="2" tab={type === ContractType.INCOME ? '合同回款' : '合同支付'}>
- <Receivable updateTreeAndContract={initData} type={type}/>
- </TabPane>
- <TabPane key="3" tab="合同文件" >
- <File type={type}/>
- </TabPane>
- </Tabs>
- </div>
- <OssUploadModal
- visible={visible}
- onCancel={() => setVisible(false)}
- onCreate={onCreate}
- onShow={onShow}
- />
- </div>
- }
- export default observer(GCsheet)
|