List.js 15 KB

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