List.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  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. } from 'antd';
  13. import moment from 'moment';
  14. import styles from './List.less';
  15. import ApprovalModal from './ApprovalModal';
  16. import DetailModal from './DetailModal';
  17. import ExecutionModal from './ExecutionModal';
  18. import MemberModal from './MemberModal';
  19. import QualityOperateModal from './QualityOperateModal';
  20. import BudgetModal from './BudgetModal';
  21. import ModifyManagerModal from './ModifyManagerModal';
  22. import { connect } from 'dva';
  23. import { useRequest, useModel } from '@umijs/max';
  24. const { Option } = Select;
  25. //状态
  26. const STATUS = [
  27. { value: 0, label: '售前' },
  28. { value: 1, label: '转执行' },
  29. { value: 2, label: '转运营' },
  30. { value: 3, label: '转质保' },
  31. ];
  32. function List(props) {
  33. const {
  34. initialState: { user },
  35. } = useModel('@@initialState');
  36. const {
  37. industryList,
  38. typeList,
  39. data,
  40. flowList,
  41. dispatch,
  42. loading,
  43. depUserTree,
  44. member,
  45. budget,
  46. } = props;
  47. const [form] = Form.useForm();
  48. const [addVisible, setAddVisible] = useState(false);
  49. const [detailVisible, setDetailVisible] = useState(false);
  50. const [executionVisible, setExecutionVisible] = useState(false);
  51. const [qualityOperateVisible, setQualityOperateVisible] = useState(false);
  52. const [memberVisible, setMemberVisible] = useState(false);
  53. const [budgetVisible, setBudgetVisible] = useState(false);
  54. const [selfItems, setSelfItems] = useState(false);
  55. const [currentItem, setCurrentItem] = useState({});
  56. const [qualityOperate, setQualityOperate] = useState(0);
  57. const [modifyManagerVisible, setModifyManagerVisible] = useState(false);
  58. const columns = [
  59. {
  60. title: '项目编号',
  61. dataIndex: 'project_full_code',
  62. },
  63. {
  64. title: '项目名称',
  65. dataIndex: 'project_name',
  66. },
  67. {
  68. title: '分类',
  69. dataIndex: 'TypeInfo',
  70. render: (TypeInfo) =>
  71. TypeInfo ? `${TypeInfo.name}(${TypeInfo.code})` : '-',
  72. },
  73. /*
  74. {
  75. title: '名称',
  76. dataIndex: 'name',
  77. },
  78. {
  79. title: '行业',
  80. dataIndex: 'IndustryInfo',
  81. render: IndustryInfo => `${IndustryInfo.name}(${IndustryInfo.code})`,
  82. },
  83. {
  84. title: '所在地',
  85. dataIndex: 'location',
  86. render: (location, record) => `${location}(${record.location_code})`,
  87. },
  88. {
  89. title: '期数',
  90. dataIndex: 'version',
  91. render: version => `${version}期`,
  92. },
  93. */
  94. {
  95. title: '流程',
  96. dataIndex: ['FlowInfo', 'name'],
  97. },
  98. {
  99. title: '状态',
  100. dataIndex: 'project_status',
  101. render: (project_status) => {
  102. // return project_status === 0 ? <>售前</> : <>转执行</>;
  103. //若添加其他状态则启用以下switch case:
  104. switch (project_status) {
  105. case 0:
  106. return <>售前</>;
  107. case 1:
  108. return <>转执行</>;
  109. case 2:
  110. return <>转运营</>;
  111. case 3:
  112. return <>转质保</>;
  113. }
  114. },
  115. },
  116. {
  117. title: '节点',
  118. dataIndex: 'NodeInfo',
  119. render: (nodeInfo, item) => {
  120. let statusDom;
  121. switch (item.audit_status) {
  122. case 0:
  123. statusDom = '待提交';
  124. break;
  125. case 1:
  126. statusDom = <span style={{ color: '#1890ff' }}>审核中</span>;
  127. break;
  128. case 2:
  129. statusDom = (
  130. <Popover content={`拒绝原因: ${item.audit_comment}`}>
  131. <span style={{ color: '#f5222d' }}>审核拒绝</span>
  132. </Popover>
  133. );
  134. break;
  135. case 3:
  136. statusDom = <span style={{ color: '#a0d911' }}>审核通过</span>;
  137. break;
  138. }
  139. return (
  140. <>
  141. {nodeInfo.node}({statusDom})
  142. </>
  143. );
  144. },
  145. },
  146. {
  147. title: '售前项目经理',
  148. dataIndex: 'AuthorUser',
  149. render: (AuthorUser) => (AuthorUser ? AuthorUser.CName : '-'),
  150. },
  151. {
  152. title: '创建时间',
  153. dataIndex: 'c_time',
  154. render: (c_time) => moment(c_time).format('YYYY.MM.DD'),
  155. },
  156. {
  157. title: '执行经理',
  158. dataIndex: 'Leader',
  159. render: (Leader) => (Leader ? Leader.CName : '-'),
  160. },
  161. {
  162. title: '操作',
  163. render: (record) => renderEditBtns(record),
  164. },
  165. ];
  166. const handleSearch = () => {
  167. const { projectName, projectCode, projectStatus } = form.getFieldsValue();
  168. let params = {};
  169. params.project_name = projectName;
  170. params.project_code = projectCode?.toUpperCase();
  171. params.project_status = projectStatus;
  172. params.currentPage = 1;
  173. dispatch({
  174. type: 'approval/queryApproval',
  175. payload: params,
  176. });
  177. };
  178. const checkSelf = (e) => {
  179. let checked = e.target.checked;
  180. setCurrentItem({});
  181. setSelfItems(checked);
  182. dispatch({
  183. type: 'approval/queryApproval',
  184. payload: {
  185. filter_type: Number(checked),
  186. currentPage: 1,
  187. },
  188. });
  189. };
  190. const renderSearch = () => {
  191. return (
  192. <Form
  193. form={form}
  194. layout="inline"
  195. initialValues={{
  196. projectName: null,
  197. projectCode: null,
  198. projectStatus: null,
  199. }}
  200. >
  201. <Form.Item label="项目名称" name="projectName">
  202. <Input style={{ width: 200 }} />
  203. </Form.Item>
  204. <Form.Item label="项目编号" name="projectCode">
  205. <Input style={{ width: 200 }} />
  206. </Form.Item>
  207. <Form.Item label="状态" name="projectStatus">
  208. <Select
  209. showSearch
  210. style={{ width: 120 }}
  211. filterOption={(input, option) =>
  212. option.props.children
  213. .toLowerCase()
  214. .indexOf(input.toLowerCase()) >= 0
  215. }
  216. >
  217. <Option value={null}>全部</Option>
  218. {STATUS.map((item) => (
  219. <Option key={item.value}>{item.label}</Option>
  220. ))}
  221. </Select>
  222. </Form.Item>
  223. <Form.Item>
  224. <Button type="primary" loading={loading} onClick={handleSearch}>
  225. 查询
  226. </Button>
  227. </Form.Item>
  228. </Form>
  229. );
  230. };
  231. const onOk = (values) => {
  232. if (values.id) {
  233. dispatch({
  234. type: 'approval/updateApproval',
  235. payload: values,
  236. callback: () => setAddVisible(false),
  237. });
  238. } else {
  239. dispatch({
  240. type: 'approval/createApproval',
  241. payload: values,
  242. callback: () => setAddVisible(false),
  243. });
  244. }
  245. };
  246. const onDelete = (item) => {
  247. Modal.confirm({
  248. title: '删除',
  249. content: '是否确认删除该项目',
  250. okText: '删除',
  251. okType: 'danger',
  252. cancelText: '取消',
  253. onOk() {
  254. dispatch({
  255. type: 'approval/deleteApproval',
  256. payload: item,
  257. });
  258. },
  259. });
  260. };
  261. const onSubmitAuth = (item) => {
  262. Modal.confirm({
  263. title: '提交审核',
  264. content: '是否确认提交审核',
  265. okText: '提审',
  266. cancelText: '取消',
  267. onOk() {
  268. dispatch({
  269. type: 'approval/submitAudit',
  270. payload: {
  271. id: item.id,
  272. flow_id: item.flow_id,
  273. node_id: item.node_id,
  274. },
  275. });
  276. },
  277. });
  278. };
  279. const queryList = (page) => {
  280. dispatch({
  281. type: 'approval/queryApproval',
  282. payload: {
  283. currentPage: page.current,
  284. },
  285. });
  286. };
  287. const renderEditBtns = (record) => {
  288. let dividerPush = (item, list) => {
  289. if (list.length === 0) list.push(item);
  290. else {
  291. list.push(<Divider type="vertical" />);
  292. list.push(item);
  293. }
  294. };
  295. let detailBtn = (
  296. <a
  297. onClick={() => {
  298. setCurrentItem(record);
  299. setDetailVisible(true);
  300. }}
  301. >
  302. 项目详情
  303. </a>
  304. );
  305. let memberBtn = (
  306. <a
  307. onClick={() => {
  308. setCurrentItem(record);
  309. setMemberVisible(true);
  310. }}
  311. >
  312. 成员管理
  313. </a>
  314. );
  315. let executionBtn = (
  316. <a
  317. onClick={() => {
  318. setCurrentItem(record);
  319. setExecutionVisible(true);
  320. }}
  321. >
  322. 转执行
  323. </a>
  324. );
  325. let editBtn = (
  326. <>
  327. <a
  328. onClick={() => {
  329. setCurrentItem(record);
  330. setAddVisible(true);
  331. }}
  332. >
  333. 编辑
  334. </a>
  335. <Divider type="vertical" />
  336. <a
  337. onClick={() => {
  338. onDelete(record);
  339. }}
  340. >
  341. 删除
  342. </a>
  343. <Divider type="vertical" />
  344. <a
  345. onClick={() => {
  346. onSubmitAuth(record);
  347. }}
  348. >
  349. 提交审核
  350. </a>
  351. </>
  352. );
  353. let statusBtn = (
  354. <>
  355. <a
  356. onClick={() => {
  357. setCurrentItem(record);
  358. dispatch({
  359. type: 'approval/queryBudget',
  360. payload: {
  361. project_id: record?.id,
  362. },
  363. callback: () => {
  364. setBudgetVisible(true);
  365. },
  366. });
  367. }}
  368. >
  369. 设置人日预算
  370. </a>
  371. <Divider type="vertical" />
  372. <a
  373. onClick={() => {
  374. setCurrentItem(record);
  375. setQualityOperateVisible(true);
  376. setQualityOperate(0);
  377. }}
  378. >
  379. 转质保
  380. </a>
  381. <Divider type="vertical" />
  382. <a
  383. onClick={() => {
  384. setCurrentItem(record);
  385. setQualityOperateVisible(true);
  386. setQualityOperate(1);
  387. }}
  388. >
  389. 转运营
  390. </a>
  391. </>
  392. );
  393. let { audit_status, project_status, type_id } = record;
  394. //权限审核
  395. let canEdit = () => {
  396. if (user.IsSuper) return true;
  397. switch (audit_status) {
  398. case 0:
  399. return user.ID == record.author;
  400. case 1:
  401. return false;
  402. case 2:
  403. if (project_status == 0) return user.ID == record.author;
  404. if (project_status == 1) return user.ID == record.LeaderId;
  405. return false;
  406. case 3:
  407. switch (project_status) {
  408. case 0:
  409. return user.ID == record.author;
  410. case 1:
  411. return user.ID == record.LeaderId;
  412. case 2:
  413. return (
  414. user.ID == record.LeaderId || user.ID == record.opt_manager_id
  415. );
  416. case 3:
  417. return (
  418. user.ID == record.LeaderId || user.ID == record.wty_manager_id
  419. );
  420. }
  421. return false;
  422. }
  423. };
  424. let toReturn = [];
  425. dividerPush(detailBtn, toReturn);
  426. switch (audit_status) {
  427. //未提交
  428. case 0:
  429. canEdit() && dividerPush(editBtn, toReturn);
  430. break;
  431. //审核中
  432. case 1:
  433. break;
  434. //审核拒绝
  435. case 2:
  436. if (project_status == 0 && canEdit()) dividerPush(editBtn, toReturn);
  437. else if (project_status == 1 && canEdit()) {
  438. dividerPush(memberBtn, toReturn);
  439. dividerPush(statusBtn, toReturn);
  440. }
  441. break;
  442. //审核通过
  443. case 3:
  444. switch (project_status) {
  445. //售前
  446. case 0:
  447. if (canEdit()) {
  448. dividerPush(memberBtn, toReturn);
  449. dividerPush(executionBtn, toReturn);
  450. }
  451. break;
  452. //转执行
  453. case 1:
  454. if (canEdit()) {
  455. dividerPush(memberBtn, toReturn);
  456. dividerPush(statusBtn, toReturn);
  457. }
  458. break;
  459. //转运营
  460. case 2:
  461. canEdit() && dividerPush(memberBtn, toReturn);
  462. break;
  463. //转质保
  464. case 3:
  465. canEdit() && dividerPush(memberBtn, toReturn);
  466. break;
  467. }
  468. break;
  469. }
  470. let modifyManager = (
  471. <a
  472. onClick={() => {
  473. setCurrentItem(record);
  474. setModifyManagerVisible(true);
  475. }}
  476. >
  477. 修改项目经理
  478. </a>
  479. );
  480. if (
  481. (project_status === 0 || project_status === 1) &&
  482. (user.Permission['func-01-point-pm-list-change'] || user.IsSuper)
  483. )
  484. dividerPush(modifyManager, toReturn);
  485. return toReturn;
  486. };
  487. useEffect(() => {
  488. dispatch({
  489. type: 'approval/queryFlow',
  490. });
  491. dispatch({
  492. type: 'approval/queryType',
  493. });
  494. dispatch({
  495. type: 'approval/queryIndustry',
  496. });
  497. dispatch({
  498. type: 'approval/queryApproval',
  499. });
  500. dispatch({
  501. type: 'approval/fetchDepV2',
  502. });
  503. }, []);
  504. return (
  505. <div>
  506. {renderSearch()}
  507. <div className={styles.btns}>
  508. <Button
  509. onClick={() => {
  510. setCurrentItem({});
  511. setAddVisible(true);
  512. }}
  513. >
  514. 新增项目
  515. </Button>
  516. <Checkbox checked={selfItems} onChange={checkSelf}>
  517. 只看自己
  518. </Checkbox>
  519. </div>
  520. <Table
  521. loading={loading}
  522. rowKey="id"
  523. dataSource={data.list}
  524. pagination={data.pagination}
  525. columns={columns}
  526. onChange={queryList}
  527. />
  528. <ApprovalModal
  529. currentUser={user}
  530. depUserTree={depUserTree}
  531. loading={loading}
  532. industryList={industryList}
  533. flowList={flowList}
  534. typeList={typeList}
  535. visible={addVisible}
  536. onOk={onOk}
  537. data={currentItem}
  538. total={data.pagination.total}
  539. onClose={() => setAddVisible(false)}
  540. />
  541. <DetailModal
  542. industryList={industryList}
  543. flowList={flowList}
  544. typeList={typeList}
  545. visible={detailVisible}
  546. data={currentItem}
  547. onClose={() => setDetailVisible(false)}
  548. />
  549. <ExecutionModal
  550. depUserTree={depUserTree}
  551. loading={loading}
  552. visible={executionVisible}
  553. currentItem={currentItem}
  554. onOk={() => setExecutionVisible(false)}
  555. onClose={() => setExecutionVisible(false)}
  556. />
  557. <MemberModal
  558. depUserTree={depUserTree}
  559. loading={loading}
  560. visible={memberVisible}
  561. onClose={() => setMemberVisible(false)}
  562. currentItem={currentItem}
  563. dataSource={member}
  564. />
  565. <QualityOperateModal
  566. depUserTree={depUserTree}
  567. loading={loading}
  568. visible={qualityOperateVisible}
  569. currentItem={currentItem}
  570. onOk={() => setQualityOperateVisible(false)}
  571. onClose={() => setQualityOperateVisible(false)}
  572. qualityOperate={qualityOperate}
  573. />
  574. <BudgetModal
  575. visible={budgetVisible}
  576. loading={loading}
  577. currentItem={currentItem}
  578. onCancel={() => setBudgetVisible(false)}
  579. onOk={() => setBudgetVisible(false)}
  580. budget={budget}
  581. />
  582. <ModifyManagerModal
  583. depUserTree={depUserTree}
  584. loading={loading}
  585. visible={modifyManagerVisible}
  586. onClose={() => setModifyManagerVisible(false)}
  587. currentItem={currentItem}
  588. dataSource={member}
  589. onOk={() => setModifyManagerVisible(false)}
  590. />
  591. </div>
  592. );
  593. }
  594. export default connect(({ approval, user, loading }) => ({
  595. data: approval.list,
  596. typeList: approval.typeList,
  597. flowList: approval.flowList,
  598. industryList: approval.industryList,
  599. loading: loading.models.approval,
  600. depUserTree: approval.depUserTree,
  601. member: approval.member,
  602. budget: approval.budget,
  603. }))(List);