List.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. import React, { useState, useEffect } from 'react';
  2. import {
  3. Table,
  4. Button,
  5. Form,
  6. Select,
  7. Divider,
  8. Modal,
  9. Popover,
  10. Input,
  11. Checkbox,
  12. message,
  13. } from 'antd';
  14. import moment from 'moment';
  15. import router from 'umi/router';
  16. import styles from './List.less';
  17. import ApprovalModal from './ApprovalModal';
  18. import DetailModal from './DetailModal';
  19. import ExecutionModal from './ExecutionModal';
  20. import MemberModal from './MemberModal';
  21. import QualityOperateModal from './QualityOperateModal';
  22. import BudgetModal from './BudgetModal';
  23. import ModifyManagerModal from './ModifyManagerModal';
  24. import { connect } from 'dva';
  25. import FirmModal from './ManufacturerModal';
  26. import { queryCreaterList, saveMfr } from '@/services/manufacturer';
  27. import ProjectRecordModal from './ProjectRecordModal';
  28. const { Option } = Select;
  29. //项目阶段
  30. export const STATUS = [
  31. { value: 0, label: '售前' },
  32. { value: 1, label: '执行' },
  33. { value: 2, label: '运营' },
  34. { value: 3, label: '质保' },
  35. ];
  36. //现阶段状态
  37. export const SUB_STATUS = [
  38. { value: 1, label: '初步交流' },
  39. { value: 2, label: '预算和方式' },
  40. { value: 3, label: '招标' },
  41. { value: 4, label: '中标' },
  42. { value: 11, label: '执行' },
  43. { value: 21, label: '运营' },
  44. { value: 31, label: '质保' },
  45. { value: 41, label: '失败' },
  46. { value: 42, label: '放弃' },
  47. { value: 43, label: '关闭' },
  48. ];
  49. function List(props) {
  50. const {
  51. industryList,
  52. typeList,
  53. data,
  54. flowList,
  55. currentUser,
  56. permission,
  57. dispatch,
  58. loading,
  59. depUserTree,
  60. member,
  61. budget,
  62. supplierList,
  63. } = props;
  64. const [form] = Form.useForm();
  65. const [addVisible, setAddVisible] = useState(false);
  66. const [detailVisible, setDetailVisible] = useState(false);
  67. const [executionVisible, setExecutionVisible] = useState(false);
  68. const [qualityOperateVisible, setQualityOperateVisible] = useState(false);
  69. const [memberVisible, setMemberVisible] = useState(false);
  70. const [budgetVisible, setBudgetVisible] = useState(false);
  71. const [selfItems, setSelfItems] = useState(false);
  72. const [currentItem, setCurrentItem] = useState({});
  73. const [qualityOperate, setQualityOperate] = useState(0);
  74. const [modifyManagerVisible, setModifyManagerVisible] = useState(false);
  75. const [addFirmVisible, setAddFirmVisible] = useState(false);
  76. const [recordVisible, setRecordVisible] = useState(false);
  77. const [isEdit, setIsEdit] = useState(false);
  78. const columns = [
  79. {
  80. title: '项目编号',
  81. dataIndex: 'project_full_code',
  82. },
  83. {
  84. title: '项目名称',
  85. dataIndex: 'project_name',
  86. },
  87. {
  88. title: '客户',
  89. dataIndex: 'supplier_name',
  90. },
  91. {
  92. title: '工艺',
  93. dataIndex: 'process_info',
  94. render: info => {
  95. let str = '';
  96. if (info) {
  97. const data = JSON.parse(info) || [];
  98. const list = data.map(item => item.type);
  99. str = list.join('+');
  100. }
  101. return str;
  102. },
  103. },
  104. // {
  105. // title: '规模',
  106. // dataIndex: 'process_info',
  107. // render: info => {
  108. // let str = '';
  109. // if (info) {
  110. // const data = JSON.parse(info) || [];
  111. // console.log('-----------------', data);
  112. // const list = data.map(item => item.scale);
  113. // str = list.join('+');
  114. // }
  115. // return str;
  116. // },
  117. // },
  118. {
  119. title: '项目种类',
  120. dataIndex: 'TypeInfo',
  121. render: TypeInfo => (TypeInfo ? `${TypeInfo.name}(${TypeInfo.code})` : '-'),
  122. },
  123. {
  124. title: '项目阶段',
  125. dataIndex: 'project_status',
  126. render: project_status => STATUS.find(item => item.value == project_status)?.label || '-',
  127. },
  128. {
  129. title: '现阶段状态',
  130. dataIndex: 'status',
  131. render: status => SUB_STATUS.find(item => item.value == status)?.label || '-',
  132. },
  133. {
  134. title: '现阶段状态时间(天)',
  135. dataIndex: 'current_status_start ',
  136. align: 'center',
  137. render: time => {
  138. const date = moment(new Date());
  139. const daysDiff = date.diff(time, 'days');
  140. return daysDiff;
  141. },
  142. },
  143. {
  144. title: '节点',
  145. dataIndex: 'NodeInfo',
  146. render: (nodeInfo, item) => {
  147. let statusDom;
  148. switch (item.audit_status) {
  149. case 0:
  150. statusDom = '待提交';
  151. break;
  152. case 1:
  153. statusDom = <span style={{ color: '#1890ff' }}>审核中</span>;
  154. break;
  155. case 2:
  156. statusDom = (
  157. <Popover content={`拒绝原因: ${item.audit_comment}`}>
  158. <span style={{ color: '#f5222d' }}>审核拒绝</span>
  159. </Popover>
  160. );
  161. break;
  162. case 3:
  163. statusDom = <span style={{ color: '#a0d911' }}>审核通过</span>;
  164. break;
  165. }
  166. return (
  167. <>
  168. {nodeInfo.node}({statusDom})
  169. </>
  170. );
  171. },
  172. },
  173. {
  174. title: '售前项目经理',
  175. dataIndex: 'AuthorUser',
  176. render: AuthorUser => (AuthorUser ? AuthorUser.CName : '-'),
  177. },
  178. {
  179. title: '创建时间',
  180. dataIndex: 'c_time',
  181. render: c_time => moment(c_time).format('YYYY.MM.DD'),
  182. },
  183. {
  184. title: '执行经理',
  185. dataIndex: 'Leader',
  186. render: Leader => (Leader ? Leader.CName : '-'),
  187. },
  188. {
  189. title: '操作',
  190. render: record => renderEditBtns2(record),
  191. },
  192. ];
  193. const renderEditBtns = record => {
  194. return (
  195. <>
  196. <a
  197. onClick={() => {
  198. setIsEdit(false);
  199. setCurrentItem(record);
  200. setDetailVisible(true);
  201. }}
  202. >
  203. 项目详情
  204. </a>
  205. <Divider type="vertical" />
  206. <a
  207. onClick={() => {
  208. setIsEdit(true);
  209. setCurrentItem(record);
  210. setDetailVisible(true);
  211. }}
  212. >
  213. 项目编辑
  214. </a>
  215. <Divider type="vertical" />
  216. <a
  217. onClick={() => {
  218. setCurrentItem(record);
  219. setRecordVisible(true);
  220. }}
  221. >
  222. 项目日志
  223. </a>
  224. <Divider type="vertical" />
  225. <a
  226. onClick={() => {
  227. setCurrentItem(record);
  228. dispatch({
  229. type: 'approval/queryBudget',
  230. payload: {
  231. project_id: record?.id,
  232. },
  233. callback: () => {
  234. setBudgetVisible(true);
  235. },
  236. });
  237. }}
  238. >
  239. 设置人日预算
  240. </a>
  241. </>
  242. );
  243. };
  244. const handleSearch = () => {
  245. const { projectName, projectCode, projectStatus } = form.getFieldsValue();
  246. let params = {};
  247. params.project_name = projectName;
  248. params.project_code = projectCode?.toUpperCase();
  249. params.project_status = projectStatus;
  250. params.currentPage = 1;
  251. dispatch({
  252. type: 'approval/queryApproval',
  253. payload: params,
  254. });
  255. };
  256. const checkSelf = e => {
  257. let checked = e.target.checked;
  258. setCurrentItem({});
  259. setSelfItems(checked);
  260. dispatch({
  261. type: 'approval/queryApproval',
  262. payload: {
  263. filter_type: Number(checked),
  264. currentPage: 1,
  265. },
  266. });
  267. };
  268. const renderSearch = () => {
  269. return (
  270. <Form
  271. form={form}
  272. layout="inline"
  273. initialValues={{ projectName: null, projectCode: null, projectStatus: null }}
  274. >
  275. <Form.Item label="项目名称" name="projectName">
  276. <Input style={{ width: 200 }} />
  277. </Form.Item>
  278. <Form.Item label="项目编号" name="projectCode">
  279. <Input style={{ width: 200 }} />
  280. </Form.Item>
  281. <Form.Item label="项目阶段" name="projectStatus">
  282. <Select
  283. showSearch
  284. style={{ width: 160 }}
  285. filterOption={(input, option) =>
  286. option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
  287. }
  288. >
  289. <Option value={null}>全部</Option>
  290. {STATUS.map(item => (
  291. <Option key={item.value}>{item.label}</Option>
  292. ))}
  293. </Select>
  294. </Form.Item>
  295. <Form.Item label="现阶段状态" name="projectStatus">
  296. <Select
  297. showSearch
  298. style={{ width: 160 }}
  299. filterOption={(input, option) =>
  300. option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
  301. }
  302. >
  303. <Option value={null}>全部</Option>
  304. {SUB_STATUS.map(item => (
  305. <Option key={item.value}>{item.label}</Option>
  306. ))}
  307. </Select>
  308. </Form.Item>
  309. <Form.Item>
  310. <Button type="primary" loading={loading} onClick={handleSearch}>
  311. 查询
  312. </Button>
  313. </Form.Item>
  314. </Form>
  315. );
  316. };
  317. const onOk = values => {
  318. if (values.id) {
  319. dispatch({
  320. type: 'approval/updateApproval',
  321. payload: values,
  322. callback: () => setAddVisible(false),
  323. });
  324. } else {
  325. dispatch({
  326. type: 'approval/createApproval',
  327. payload: values,
  328. callback: () => setAddVisible(false),
  329. });
  330. }
  331. // 刷新table
  332. queryList({ current: 1 });
  333. };
  334. const onDelete = item => {
  335. Modal.confirm({
  336. title: '删除',
  337. content: '是否确认删除该项目',
  338. okText: '删除',
  339. okType: 'danger',
  340. cancelText: '取消',
  341. onOk() {
  342. dispatch({
  343. type: 'approval/deleteApproval',
  344. payload: item,
  345. });
  346. },
  347. });
  348. };
  349. const onSubmitAuth = item => {
  350. Modal.confirm({
  351. title: '提交审核',
  352. content: '是否确认提交审核',
  353. okText: '提审',
  354. cancelText: '取消',
  355. onOk() {
  356. dispatch({
  357. type: 'approval/submitAudit',
  358. payload: {
  359. id: item.id,
  360. flow_id: item.flow_id,
  361. node_id: item.node_id,
  362. },
  363. });
  364. },
  365. });
  366. };
  367. const queryList = page => {
  368. dispatch({
  369. type: 'approval/queryApproval',
  370. payload: {
  371. currentPage: page.current,
  372. },
  373. });
  374. };
  375. const renderEditBtns2 = record => {
  376. let dividerPush = (item, list) => {
  377. if (list.length === 0) list.push(item);
  378. else {
  379. list.push(<Divider type="vertical" />);
  380. list.push(item);
  381. }
  382. };
  383. let detailBtn = (
  384. <a
  385. onClick={() => {
  386. setCurrentItem(record);
  387. setDetailVisible(true);
  388. setIsEdit(false);
  389. }}
  390. >
  391. 项目详情
  392. </a>
  393. );
  394. // let memberBtn = (
  395. // <a
  396. // onClick={() => {
  397. // setCurrentItem(record);
  398. // setMemberVisible(true);
  399. // }}
  400. // >
  401. // 成员管理
  402. // </a>
  403. // );
  404. // let executionBtn = (
  405. // <a
  406. // onClick={() => {
  407. // setCurrentItem(record);
  408. // setExecutionVisible(true);
  409. // }}
  410. // >
  411. // 转执行
  412. // </a>
  413. // );
  414. let editBtn = (
  415. <>
  416. <a
  417. onClick={() => {
  418. setCurrentItem(record);
  419. setAddVisible(true);
  420. setIsEdit(true);
  421. }}
  422. >
  423. 编辑
  424. </a>
  425. <Divider type="vertical" />
  426. <a
  427. onClick={() => {
  428. onDelete(record);
  429. }}
  430. >
  431. 删除
  432. </a>
  433. <Divider type="vertical" />
  434. <a
  435. onClick={() => {
  436. onSubmitAuth(record);
  437. }}
  438. >
  439. 提交审核
  440. </a>
  441. </>
  442. );
  443. let projectEditBtn = (
  444. <a
  445. onClick={() => {
  446. setIsEdit(true);
  447. setCurrentItem(record);
  448. setDetailVisible(true);
  449. }}
  450. >
  451. 项目编辑
  452. </a>
  453. );
  454. let statusBtn = (
  455. <>
  456. <a
  457. onClick={() => {
  458. setCurrentItem(record);
  459. dispatch({
  460. type: 'approval/queryBudget',
  461. payload: {
  462. project_id: record?.id,
  463. },
  464. callback: () => {
  465. setBudgetVisible(true);
  466. },
  467. });
  468. }}
  469. >
  470. 设置人日预算
  471. </a>
  472. {/* <Divider type="vertical" />
  473. <a
  474. onClick={() => {
  475. setCurrentItem(record);
  476. setQualityOperateVisible(true);
  477. setQualityOperate(0);
  478. }}
  479. >
  480. 转质保
  481. </a>
  482. <Divider type="vertical" />
  483. <a
  484. onClick={() => {
  485. setCurrentItem(record);
  486. setQualityOperateVisible(true);
  487. setQualityOperate(1);
  488. }}
  489. >
  490. 转运营
  491. </a> */}
  492. </>
  493. );
  494. let { audit_status, project_status, type_id } = record;
  495. //权限审核
  496. let getEditStatus = () => {
  497. if (currentUser.IsSuper) return true;
  498. switch (audit_status) {
  499. case 0:
  500. return currentUser.ID == record.author;
  501. case 1:
  502. return false;
  503. case 2:
  504. if (project_status == 0) return currentUser.ID == record.author;
  505. if (project_status == 1) return currentUser.ID == record.LeaderId;
  506. return false;
  507. case 3:
  508. switch (project_status) {
  509. case 0:
  510. return currentUser.ID == record.author;
  511. case 1:
  512. return currentUser.ID == record.LeaderId;
  513. case 2:
  514. return currentUser.ID == record.LeaderId || currentUser.ID == record.opt_manager_id;
  515. case 3:
  516. return currentUser.ID == record.LeaderId || currentUser.ID == record.wty_manager_id;
  517. }
  518. return false;
  519. }
  520. };
  521. let toReturn = [];
  522. const canEdit = getEditStatus();
  523. dividerPush(detailBtn, toReturn);
  524. switch (audit_status) {
  525. //未提交
  526. case 0:
  527. canEdit && dividerPush(editBtn, toReturn);
  528. break;
  529. //审核中
  530. case 1:
  531. break;
  532. //审核拒绝
  533. case 2:
  534. if (project_status == 0 && canEdit) dividerPush(editBtn, toReturn);
  535. else if (project_status == 1 && canEdit) {
  536. // dividerPush(memberBtn, toReturn);
  537. dividerPush(statusBtn, toReturn);
  538. }
  539. break;
  540. //审核通过
  541. case 3:
  542. canEdit && dividerPush(projectEditBtn, toReturn);
  543. switch (project_status) {
  544. //售前
  545. case 0:
  546. if (canEdit) {
  547. // dividerPush(memberBtn, toReturn);
  548. // dividerPush(executionBtn, toReturn);
  549. }
  550. break;
  551. //转执行
  552. case 1:
  553. if (canEdit) {
  554. // dividerPush(memberBtn, toReturn);
  555. dividerPush(statusBtn, toReturn);
  556. }
  557. break;
  558. //转运营
  559. case 2:
  560. // canEdit && dividerPush(memberBtn, toReturn);
  561. break;
  562. //转质保
  563. case 3:
  564. // canEdit && dividerPush(memberBtn, toReturn);
  565. break;
  566. }
  567. break;
  568. }
  569. // let modifyManager = (
  570. // <a
  571. // onClick={() => {
  572. // setCurrentItem(record);
  573. // setModifyManagerVisible(true);
  574. // }}
  575. // >
  576. // 修改项目经理
  577. // </a>
  578. // );
  579. // if (
  580. // (project_status === 0 || project_status === 1) &&
  581. // (permission['func-01-point-pm-list-change'] || currentUser.IsSuper)
  582. // )
  583. // dividerPush(modifyManager, toReturn);
  584. return toReturn;
  585. };
  586. useEffect(() => {
  587. dispatch({
  588. type: 'approval/queryFlow',
  589. });
  590. dispatch({
  591. type: 'approval/queryType',
  592. });
  593. dispatch({
  594. type: 'approval/queryIndustry',
  595. });
  596. dispatch({
  597. type: 'approval/queryApproval',
  598. });
  599. dispatch({
  600. type: 'approval/fetchDepV2',
  601. });
  602. dispatch({
  603. type: 'approval/querySupplierList',
  604. payload: { project_id: 1, is_super: true, page_size: 999 },
  605. });
  606. }, []);
  607. const handlerSaveFirm = async fieldsValue => {
  608. const res = await saveMfr({
  609. ...fieldsValue,
  610. project_id: 1,
  611. created_by: currentUser?.CName,
  612. });
  613. if (res.code == 200) {
  614. message.success('新增成功');
  615. setAddFirmVisible(false);
  616. dispatch({
  617. type: 'approval/querySupplierList',
  618. payload: { project_id: 1, is_super: true, page_size: 999 },
  619. });
  620. }
  621. console.log(res);
  622. };
  623. return (
  624. <div>
  625. {renderSearch()}
  626. <div className={styles.btns}>
  627. <Button
  628. onClick={() => {
  629. setCurrentItem({});
  630. setAddVisible(true);
  631. }}
  632. >
  633. 新增项目
  634. </Button>
  635. <Checkbox checked={selfItems} onChange={checkSelf}>
  636. 只看自己
  637. </Checkbox>
  638. </div>
  639. <Table
  640. loading={loading}
  641. rowKey="id"
  642. dataSource={data.list}
  643. pagination={data.pagination}
  644. columns={columns}
  645. onChange={queryList}
  646. />
  647. <ApprovalModal
  648. supplierList={supplierList}
  649. currentUser={currentUser}
  650. depUserTree={depUserTree}
  651. loading={loading}
  652. industryList={industryList}
  653. flowList={flowList}
  654. typeList={typeList}
  655. visible={addVisible}
  656. onOk={onOk}
  657. data={currentItem}
  658. total={data.pagination.total}
  659. onClose={() => setAddVisible(false)}
  660. onAddFirm={() => setAddFirmVisible(true)}
  661. />
  662. <DetailModal
  663. depUserTree={depUserTree}
  664. industryList={industryList}
  665. flowList={flowList}
  666. typeList={typeList}
  667. visible={detailVisible}
  668. data={currentItem}
  669. isEdit={isEdit}
  670. currentUser={currentUser}
  671. onClose={() => setDetailVisible(false)}
  672. />
  673. <ExecutionModal
  674. depUserTree={depUserTree}
  675. loading={loading}
  676. visible={executionVisible}
  677. currentItem={currentItem}
  678. onOk={() => setExecutionVisible(false)}
  679. onClose={() => setExecutionVisible(false)}
  680. />
  681. <QualityOperateModal
  682. depUserTree={depUserTree}
  683. loading={loading}
  684. visible={qualityOperateVisible}
  685. currentItem={currentItem}
  686. onOk={() => setQualityOperateVisible(false)}
  687. onClose={() => setQualityOperateVisible(false)}
  688. qualityOperate={qualityOperate}
  689. />
  690. <BudgetModal
  691. visible={budgetVisible}
  692. loading={loading}
  693. currentItem={currentItem}
  694. onCancel={() => setBudgetVisible(false)}
  695. onOk={() => setBudgetVisible(false)}
  696. budget={budget}
  697. />
  698. <ModifyManagerModal
  699. depUserTree={depUserTree}
  700. loading={loading}
  701. visible={modifyManagerVisible}
  702. onClose={() => setModifyManagerVisible(false)}
  703. currentItem={currentItem}
  704. dataSource={member}
  705. onOk={() => setModifyManagerVisible(false)}
  706. />
  707. <FirmModal
  708. visible={addFirmVisible}
  709. onCancel={() => setAddFirmVisible(false)}
  710. onOk={handlerSaveFirm}
  711. />
  712. <ProjectRecordModal
  713. depUserTree={depUserTree}
  714. currentItem={currentItem}
  715. visible={recordVisible}
  716. onClose={() => setRecordVisible(false)}
  717. />
  718. </div>
  719. );
  720. }
  721. export default connect(({ approval, user, loading }) => ({
  722. data: approval.list,
  723. typeList: approval.typeList,
  724. flowList: approval.flowList,
  725. industryList: approval.industryList,
  726. currentUser: user.currentUser,
  727. permission: user.currentUser.Permission,
  728. loading: loading.models.approval,
  729. depUserTree: approval.depUserTree,
  730. member: approval.member,
  731. budget: approval.budget,
  732. supplierList: approval.supplierList,
  733. }))(List);