index.jsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. import React, { useState, useRef, useEffect } from 'react';
  2. import {
  3. Button,
  4. DatePicker,
  5. Input,
  6. Select,
  7. Space,
  8. Table,
  9. message,
  10. Modal,
  11. } from 'antd';
  12. import styles from './index.less';
  13. import ContractModal, { Type, Status } from './component/Modal';
  14. import { PageContainer } from '@ant-design/pro-components';
  15. import { useRequest, useModel } from '@umijs/max';
  16. import { connect } from 'umi';
  17. import {
  18. queryApproval,
  19. queryCompany,
  20. queryContract,
  21. queryContractCancel,
  22. queryContractCancelCheck,
  23. queryContractCheck,
  24. queryContractDownload,
  25. queryGetContractList,
  26. } from '../../services/contract';
  27. import dayjs from 'dayjs';
  28. import FileViewerModal from '@/components/FileViewerNew';
  29. import { getToken } from '@/utils/utils';
  30. import PageContent from '@/components/PageContent';
  31. import EllipsisText from './component/EllipsisText';
  32. import { stringify } from 'qs';
  33. const ConteactManager = (props) => {
  34. const { dispatch } = props;
  35. const [searchData, setSearchData] = useState({
  36. effect_on: '',
  37. project_name: '',
  38. status: '',
  39. page_size: 10,
  40. current: 1,
  41. name: '',
  42. });
  43. const {
  44. initialState: { user },
  45. } = useModel('@@initialState');
  46. const [visible, setVisible] = useState(false);
  47. const [detail, setDetail] = useState({});
  48. const [data, setData] = useState([]);
  49. const [pagination, setPagination] = useState({ current: 1 });
  50. const typeRef = useRef();
  51. const parentIdRef = useRef(0);
  52. const [fileViewerVisible, setFileViewerVisible] = useState(false);
  53. const [fileViewerData, setFileViewerData] = useState();
  54. const [modal, contextHolder] = Modal.useModal();
  55. const showBtn = (record, type) => {
  56. let bool = false;
  57. switch (type) {
  58. case 'download':
  59. if (user?.Permission['menu-001-audit'] || record.created_by == user.ID)
  60. bool = true;
  61. break;
  62. // case 'addOrCal':
  63. // if (record.created_by == user.ID) bool = true;
  64. // break;
  65. }
  66. return bool;
  67. };
  68. const columns = [
  69. {
  70. title: '合同编号',
  71. dataIndex: 'code',
  72. key: 'code',
  73. align: 'center',
  74. width: 160,
  75. },
  76. {
  77. title: '合同签订时间',
  78. dataIndex: 'effect_on',
  79. key: 'effect_on',
  80. align: 'center',
  81. width: 120,
  82. },
  83. {
  84. title: '合同名称',
  85. dataIndex: 'name',
  86. key: 'name',
  87. align: 'center',
  88. },
  89. {
  90. title: '甲方',
  91. dataIndex: 'party_a',
  92. key: 'party_a',
  93. align: 'center',
  94. render: (text) => <EllipsisText text={text} width={120} />,
  95. },
  96. {
  97. title: '乙方',
  98. dataIndex: 'party_b',
  99. key: 'party_b',
  100. align: 'center',
  101. render: (text) => <EllipsisText text={text} width={120} />,
  102. },
  103. {
  104. title: '丙方',
  105. dataIndex: 'party_c',
  106. key: 'party_c',
  107. align: 'center',
  108. render: (text) => {
  109. let str = text;
  110. try {
  111. str = JSON.parse(text).join('、');
  112. } catch (error) {}
  113. return <EllipsisText text={str} width={120} />;
  114. },
  115. },
  116. {
  117. title: '所属部门/子公司',
  118. dataIndex: 'dep_name',
  119. key: 'dep_name',
  120. align: 'center',
  121. width: 160,
  122. },
  123. {
  124. title: '项目名称',
  125. dataIndex: 'project_name',
  126. key: 'project_name',
  127. align: 'center',
  128. width: 120,
  129. },
  130. {
  131. title: '合同总价(万元)',
  132. dataIndex: 'amount',
  133. key: 'amount',
  134. align: 'center',
  135. width: 160,
  136. },
  137. {
  138. title: '经办人',
  139. dataIndex: 'deal_by',
  140. key: 'deal_by',
  141. align: 'center',
  142. width: 80,
  143. },
  144. {
  145. title: '状态',
  146. dataIndex: 'status',
  147. key: 'status',
  148. align: 'center',
  149. width: 100,
  150. render: (status) => {
  151. let str = '';
  152. switch (status) {
  153. case 1:
  154. str = '待审核';
  155. break;
  156. case 2:
  157. str = '审核拒绝';
  158. break;
  159. case 3:
  160. str = '已存档';
  161. break;
  162. case 4:
  163. str = '作废待审核';
  164. break;
  165. case 5:
  166. str = '作废拒绝';
  167. break;
  168. case 6:
  169. str = '已作废';
  170. break;
  171. }
  172. return <div>{str}</div>;
  173. },
  174. },
  175. {
  176. title: '操作',
  177. width: '210px',
  178. align: 'center',
  179. render: (record) => {
  180. return (
  181. <Space>
  182. <a
  183. onClick={() => {
  184. typeRef.current = Type.detail;
  185. parentIdRef.current = 0;
  186. setDetail(record);
  187. setVisible(true);
  188. }}
  189. >
  190. 详情
  191. </a>
  192. <a onClick={() => handlePreView(record)}>预览</a>
  193. {showBtn(record, 'download') && (
  194. <a onClick={() => handleUpload(record)}>下载</a>
  195. )}
  196. {/* {showBtn(record, 'addOrCal') && !record.parent_id && (
  197. <a
  198. onClick={() => {
  199. typeRef.current = Type.add;
  200. parentIdRef.current = record.id;
  201. setDetail({});
  202. setVisible(true);
  203. }}
  204. >
  205. 增补
  206. </a>
  207. )} */}
  208. {record.status == 3 && (
  209. <a
  210. onClick={() => {
  211. typeRef.current = Type.cancel;
  212. setDetail(record);
  213. setVisible(true);
  214. }}
  215. >
  216. 作废
  217. </a>
  218. )}
  219. </Space>
  220. );
  221. },
  222. },
  223. ];
  224. const config = {
  225. title: '添加成功!',
  226. content: (
  227. <>
  228. 将合同(含附件)的原件和相关资料交给集团档案管理部门或分子公司合同专员才能完成合同存档,请注意及时存档。
  229. </>
  230. ),
  231. };
  232. useEffect(() => {
  233. dispatch({
  234. type: 'user/fetch',
  235. });
  236. }, []);
  237. //请求列表
  238. const { run, loading } = useRequest((data) => queryGetContractList(data), {
  239. defaultParams: [searchData],
  240. onSuccess: (data) => {
  241. let resultData = data?.list?.map((item) => {
  242. return item.sub_num > 0 ? { ...item, children: [] } : item;
  243. });
  244. setData(resultData);
  245. setPagination(data?.pagination);
  246. },
  247. });
  248. //编辑新增接口
  249. const { run: editRun } = useRequest((data) => queryContract(data), {
  250. manual: true,
  251. onSuccess: () => {
  252. // message.success('添加成功');
  253. setVisible(false);
  254. run(searchData);
  255. modal.info(config);
  256. },
  257. onError: () => {
  258. message.success('添加失败');
  259. },
  260. });
  261. //作废发起
  262. const { run: calRun } = useRequest((data) => queryContractCancel(data), {
  263. manual: true,
  264. onSuccess: () => {
  265. message.success('发起作废成功');
  266. setVisible(false);
  267. run(searchData);
  268. },
  269. onError: () => {
  270. message.success('发起作废失败');
  271. },
  272. });
  273. //作废审核
  274. const { run: calCheckRun } = useRequest(
  275. (data) => queryContractCancelCheck(data),
  276. {
  277. manual: true,
  278. onSuccess: () => {
  279. message.success('审核成功');
  280. setVisible(false);
  281. run(searchData);
  282. },
  283. onError: () => {
  284. message.success('审核失败');
  285. },
  286. },
  287. );
  288. //审核合同
  289. const { run: runCheck, loading: checkLoading } = useRequest(
  290. (data) => queryContractCheck(data),
  291. {
  292. manual: true,
  293. onSuccess: () => {
  294. // conAuditRun({ multi_status: '1,4', currentPage: 1, page_size: 10 });
  295. // conAuditedRun({ check_by: user.CName });
  296. setVisible(false);
  297. run(searchData);
  298. message.success('审核成功');
  299. },
  300. onErroe: () => {
  301. message.error('审核失败');
  302. },
  303. },
  304. );
  305. //请求项目列表
  306. const { data: projectData } = useRequest(queryApproval, {
  307. defaultParams: [{ pageSize: 99999 }],
  308. });
  309. const handlePreView = (record) => {
  310. if (!record.attach) return;
  311. const attach = JSON.parse(record.attach);
  312. setFileViewerData(attach);
  313. setFileViewerVisible(true);
  314. };
  315. //单个合同下载
  316. const handleUpload = (record) => {
  317. const token = getToken();
  318. window.downloadFile(
  319. `/api/contract/v1/contract/download?id=${record.id}&JWT-TOKEN=${token}`,
  320. record.name,
  321. false,
  322. );
  323. };
  324. const handleSearch = () => {
  325. run(searchData);
  326. };
  327. //合同列表导出列表下载
  328. const handleExport = async () => {
  329. const token = getToken();
  330. const params = { ...searchData, current_user: user.ID };
  331. window.downloadFile(
  332. `/api/contract/v1/contract-list/download?${stringify(
  333. params,
  334. )}&JWT-TOKEN=${token}`,
  335. '合同列表.xlsx',
  336. false,
  337. );
  338. };
  339. const handleQueryChildren = async (req) => {
  340. const res = await queryGetContractList(req);
  341. if (res?.data?.list) {
  342. let resultData = [...data];
  343. let idx = data.findIndex((item) => item.id == req.is_parent);
  344. if (idx > -1) {
  345. resultData[idx].children = res?.data?.list;
  346. setData(resultData);
  347. setPagination(res.data?.pagination);
  348. // setData({ list: resultData, pagination: res.data?.pagination });
  349. }
  350. }
  351. };
  352. const handleOk = (data, type) => {
  353. if (type == Type.add) {
  354. editRun(data);
  355. } else if (type == Type.cancel) {
  356. calRun(data);
  357. } else if (type == Status.Checking) {
  358. runCheck(data);
  359. } else if (type == Status.CalChecking) {
  360. calCheckRun(data);
  361. }
  362. };
  363. const onPageChange = (page) => {
  364. run({ ...searchData, current: page });
  365. };
  366. return (
  367. <PageContent>
  368. <div className={styles.searchContent}>
  369. <div className={styles.itemFlex}>
  370. <div>合同签订日期:</div>
  371. <DatePicker
  372. onChange={(e) => {
  373. setSearchData({
  374. ...searchData,
  375. effect_on: e ? dayjs(e).format('YYYY-MM-DD') : null,
  376. });
  377. }}
  378. />
  379. </div>
  380. <div className={styles.itemFlex}>
  381. <div>项目名称:</div>
  382. <Select
  383. style={{ width: 200 }}
  384. placeholder="请选择"
  385. onChange={(e) => {
  386. setSearchData({
  387. ...searchData,
  388. project_name: e,
  389. });
  390. }}
  391. options={projectData?.list?.map((item) => {
  392. return {
  393. value: item.project_name,
  394. label: item.project_name,
  395. };
  396. })}
  397. />
  398. </div>
  399. <div className={styles.itemFlex}>
  400. <div>状态:</div>
  401. <Select
  402. style={{ width: 150 }}
  403. placeholder="请选择"
  404. allowClear
  405. onChange={(e) => {
  406. setSearchData({
  407. ...searchData,
  408. status: e,
  409. });
  410. }}
  411. options={[
  412. { value: 3, label: '已归档' },
  413. { value: 1, label: '归档审核中' },
  414. { value: 4, label: '作废审核中' },
  415. { value: 6, label: '已作废' },
  416. { value: 2, label: '归档拒绝' },
  417. { value: 5, label: '作废拒绝' },
  418. ]}
  419. />
  420. </div>
  421. <Input
  422. style={{ width: 150 }}
  423. className={styles.inputSty}
  424. placeholder="请输入合同名称/编号"
  425. allowClear
  426. onChange={(e) => {
  427. setSearchData({
  428. ...searchData,
  429. name: e.target.value,
  430. });
  431. }}
  432. />
  433. <Button
  434. type="primary"
  435. className={styles.searchBtnSty}
  436. onClick={handleSearch}
  437. >
  438. 查询
  439. </Button>
  440. <Button
  441. type="primary"
  442. onClick={() => {
  443. typeRef.current = Type.add;
  444. setDetail({});
  445. setVisible(true);
  446. }}
  447. >
  448. 新增
  449. </Button>
  450. <Button
  451. type="primary"
  452. className={styles.exportBtnSty}
  453. onClick={handleExport}
  454. >
  455. 导出
  456. </Button>
  457. </div>
  458. <Table
  459. rowKey="code"
  460. loading={loading}
  461. columns={columns}
  462. dataSource={data}
  463. indentSize={70}
  464. onExpand={(expanded, record) => {
  465. console.log(expanded, record);
  466. if (expanded) handleQueryChildren({ is_parent: record.id });
  467. }}
  468. pagination={{ ...pagination, onChange: onPageChange }}
  469. />
  470. <ContractModal
  471. detail={detail}
  472. type={typeRef.current}
  473. parent_id={parentIdRef.current}
  474. projectList={projectData?.list}
  475. visible={visible}
  476. handleOk={handleOk}
  477. handlePreView={handlePreView}
  478. handleCancel={() => setVisible(false)}
  479. />
  480. <FileViewerModal
  481. data={fileViewerData}
  482. visible={fileViewerVisible}
  483. downloadFile={() => {}}
  484. onCancel={() => {
  485. setFileViewerVisible(false);
  486. }}
  487. />
  488. {contextHolder}
  489. </PageContent>
  490. );
  491. };
  492. export default connect(({ user, loading }) => ({
  493. userList: user.list,
  494. }))(ConteactManager);