MandateDetail.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. import { queryMandate } from '@/services/SmartOps';
  2. import { UnityAction } from '@/utils/utils';
  3. import { connect, useRequest } from '@umijs/max';
  4. import {
  5. Button,
  6. Checkbox,
  7. Col,
  8. ConfigProvider,
  9. DatePicker,
  10. Divider,
  11. Form,
  12. Input,
  13. Modal,
  14. Row,
  15. Select,
  16. Spin,
  17. Table,
  18. message,
  19. } from 'antd';
  20. import dayjs from 'dayjs';
  21. import { useEffect, useState } from 'react';
  22. import {
  23. MandateClass,
  24. MandateStatus,
  25. MandateType,
  26. OrderStatus,
  27. OrderType,
  28. ignoreReason,
  29. } from '../constent';
  30. import styles from './MandateDetail.less';
  31. import zhCN from 'antd/es/locale/zh_CN';
  32. const MandateDetail = (props) => {
  33. const {
  34. projectID,
  35. mandateID,
  36. userList,
  37. ignoreTask,
  38. dispatchTask,
  39. autoHandleTask,
  40. dispatch,
  41. } = props;
  42. useEffect(() => {
  43. if (userList.length === 0) {
  44. dispatch({
  45. type: 'taskUser/fetchUserList',
  46. payload: { project_id: projectID },
  47. });
  48. }
  49. }, []);
  50. const [mandateDetail, setMandateDetail] = useState();
  51. const [mandateChild, setMandateChild] = useState([]);
  52. const [handledWorkOrder, setHandledWorkOrder] = useState([]);
  53. const [ignoreModalOpen, setIgnoreModalOpen] = useState(false);
  54. const [autoHandleModalOpen, setAutoHandleModalOpen] = useState(false);
  55. const [mandateSelectModalOpen, setMandateSelectModalOpen] = useState(false);
  56. const [selectedTask, setSelectedTask] = useState([]);
  57. const [dispatchModalOpen, setDispatchModalOpen] = useState(false);
  58. const columns = [
  59. {
  60. title: '序号',
  61. key: 'index',
  62. width: '1rem',
  63. render: (_text, _record, index) => {
  64. return index + 1 + '、';
  65. },
  66. },
  67. {
  68. title: '参数',
  69. dataIndex: 'Title',
  70. },
  71. {
  72. title: '调整内容',
  73. dataIndex: 'Content',
  74. },
  75. ];
  76. const { run: getMandateInfo, loading } = useRequest(queryMandate, {
  77. manual: true,
  78. formatResult: (result) => {
  79. if (result?.data) {
  80. const tempMandate = {
  81. ...result.data,
  82. Status: MandateStatus.find(
  83. (item) => item.value === result.data.Status,
  84. ),
  85. MandateClass: MandateClass.find(
  86. (item) => item.value === result.data.MandateClass,
  87. ),
  88. MandateType: MandateType.find(
  89. (item) => item.value === result.data.MandateType,
  90. ),
  91. ResponsiblePeople: userList.find(
  92. (item) => item.ID === result.data.ResponsiblePeople,
  93. ),
  94. CreateTime: dayjs(result.data.CreateTime).format('YYYY-MM-DD HH:mm'),
  95. };
  96. const workOrder = result.data.Records.map((item) => {
  97. return {
  98. ...item,
  99. CreateTime: dayjs(item.CreateTime).format('YYYY-MM-DD HH:mm'),
  100. Status: OrderStatus.find((status) => status.value === item.Status),
  101. RecordType: OrderType.find(
  102. (type) => type.value === item.RecordType,
  103. ),
  104. Responsible: userList.find((user) => user.ID === item.Responsible),
  105. };
  106. });
  107. setMandateDetail(tempMandate);
  108. setMandateChild(tempMandate.MandateChild);
  109. setHandledWorkOrder(workOrder);
  110. }
  111. },
  112. });
  113. // 打开指定弹窗
  114. const openSpecifiedModal = (type) => {
  115. switch (type) {
  116. case 'ignore':
  117. setIgnoreModalOpen(true);
  118. break;
  119. case 'manual':
  120. UnityAction.sendMsg('menuItem', '工艺监控');
  121. break;
  122. case 'auto':
  123. setAutoHandleModalOpen(true);
  124. break;
  125. case 'dispatch':
  126. setMandateSelectModalOpen(true);
  127. break;
  128. }
  129. };
  130. // 忽略
  131. const onIgnoreConfirm = async (reason) => {
  132. const result = await ignoreTask(mandateID, reason);
  133. if (result) {
  134. setIgnoreModalOpen(false);
  135. getMandateInfo({ mandate_id: mandateID });
  136. }
  137. };
  138. const onAutoHandleConfirm = async (pw) => {
  139. const result = await autoHandleTask(pw, mandateDetail);
  140. if (result) {
  141. setAutoHandleModalOpen(false);
  142. getMandateInfo({ mandate_id: mandateID });
  143. }
  144. };
  145. const onManualHandleConfirm = () => {
  146. console.log('manual handle Confirm');
  147. };
  148. const onMandateSelected = (records) => {
  149. // 打开派单Form弹窗将选中的任务进行派遣
  150. if (records?.length === 0) {
  151. message.warning('请先选择要派遣的任务');
  152. return;
  153. }
  154. setSelectedTask(records);
  155. setDispatchModalOpen(true);
  156. };
  157. const onDispatchConfirm = async (value) => {
  158. const params = {
  159. ...value,
  160. m_id: Number(mandateID),
  161. mc_id: selectedTask.join(),
  162. plan_end_time: dayjs(value.plan_end_time).format('YYYY-MM-DD HH:mm:ss'),
  163. };
  164. if (params.type === 5) {
  165. if (params.mc_id.split(',').length > 1) {
  166. message.warning('加药工单不可批量派遣');
  167. return;
  168. }
  169. params.note = `${
  170. mandateChild
  171. .find((mandate) => mandate.Id === Number(params.mc_id))
  172. ?.Title?.split(':')[1] + ',请及时加药'
  173. }`;
  174. } else {
  175. params.note = mandateDetail.Summary;
  176. }
  177. const result = await dispatchTask(params);
  178. if (result) {
  179. setDispatchModalOpen(false);
  180. getMandateInfo({ mandate_id: mandateID });
  181. }
  182. };
  183. const openWorkOrderModal = (record) => {
  184. UnityAction.sendMsg(
  185. 'OpenWorkOrderModal',
  186. `order_id=${record.Id}&order_type=${record.RecordType.value}`,
  187. );
  188. };
  189. useEffect(() => {
  190. getMandateInfo({ mandate_id: mandateID });
  191. }, []);
  192. return (
  193. <Spin spinning={loading}>
  194. <div>
  195. <div className={styles.mandate}>
  196. <div className={styles.taskOtherInfo}>
  197. <Row>
  198. <Col className={styles.fontS32} span={14}>
  199. 任务时间:{mandateDetail?.CreateTime || '-'}
  200. </Col>
  201. <Col className={styles.fontS32}>
  202. 任务类别:{mandateDetail?.MandateClass?.label || '-'}
  203. </Col>
  204. </Row>
  205. <Row style={{ marginTop: '0.2rem' }}>
  206. <Col className={styles.fontS32} span={14}>
  207. 任务状态:{' '}
  208. <span style={{ color: ' #5697e4' }}>
  209. {mandateDetail?.Status.label}
  210. </span>
  211. </Col>
  212. <Col className={styles.fontS32}>
  213. 任务负责人:{mandateDetail?.ResponsiblePeople?.CName || '-'}
  214. </Col>
  215. </Row>
  216. </div>
  217. <Row style={{ padding: '0 0.2rem' }} justify="space-between">
  218. <Col className={styles.fontS32} style={{ fontWeight: '600' }}>
  219. 任务内容:
  220. </Col>
  221. <Col className={styles.fontS32} span={20}>
  222. <Table
  223. className={styles.taskTable}
  224. columns={columns}
  225. dataSource={mandateChild}
  226. pagination={false}
  227. />
  228. </Col>
  229. </Row>
  230. </div>
  231. {handledWorkOrder?.length > 0 && <Divider />}
  232. {handledWorkOrder?.map((item) => {
  233. return (
  234. <div key={item.Id} className={styles.relatedOrder}>
  235. <div className={styles.leftInfo}>
  236. <Row>
  237. <Col span={11} className={styles.fontS32}>
  238. 工单类型:{item?.RecordType?.label}
  239. </Col>
  240. <Col className={styles.fontS32}>时间:{item?.CreateTime}</Col>
  241. </Row>
  242. <Row>
  243. <Col span={11} className={styles.fontS32}>
  244. 工单状态:
  245. <span style={{ color: ' #5697e4' }}>
  246. {item?.Status?.label}
  247. </span>
  248. </Col>
  249. <Col className={styles.fontS32}>
  250. 工单负责人:{item?.Responsible?.CName}
  251. </Col>
  252. </Row>
  253. </div>
  254. <Divider type="vertical" style={{ height: '0.4rem' }} />
  255. <div className={styles.rightButtonContainer}>
  256. <div
  257. className={styles.rightButton}
  258. onClick={() => openWorkOrderModal(item)}
  259. >
  260. 查看
  261. </div>
  262. {/* <div
  263. className={styles.rightButton}
  264. onClick={() => openWorkOrderModal(item)}
  265. >
  266. 关闭工单
  267. </div> */}
  268. </div>
  269. </div>
  270. );
  271. })}
  272. {mandateDetail?.Status?.value === 0 && <Divider />}
  273. {mandateDetail?.Status?.value === 0 && (
  274. <div className={styles.footerConstainer}>
  275. <Button
  276. className={styles.footerBtn}
  277. shape="round"
  278. onClick={() => {
  279. openSpecifiedModal('ignore');
  280. }}
  281. >
  282. 忽略
  283. </Button>
  284. {(mandateDetail?.MandateClass?.value === 1 ||
  285. mandateDetail?.MandateClass?.value === 2) &&
  286. mandateDetail?.Status?.value === 0 && (
  287. <>
  288. <Button
  289. className={styles.footerBtn}
  290. shape="round"
  291. onClick={() => {
  292. openSpecifiedModal('manual');
  293. }}
  294. >
  295. 手动处理
  296. </Button>
  297. <Button
  298. className={styles.footerBtn}
  299. shape="round"
  300. onClick={() => {
  301. openSpecifiedModal('auto');
  302. }}
  303. >
  304. 自动处理
  305. </Button>
  306. </>
  307. )}
  308. <Button
  309. className={styles.footerBtn}
  310. shape="round"
  311. onClick={() => {
  312. openSpecifiedModal('dispatch');
  313. }}
  314. >
  315. 派单
  316. </Button>
  317. </div>
  318. )}
  319. {/* 弹窗 */}
  320. <ConfigProvider locale={zhCN}>
  321. <IgnoreTaskModal
  322. open={ignoreModalOpen}
  323. onCancel={() => setIgnoreModalOpen(false)}
  324. onOk={onIgnoreConfirm}
  325. />
  326. <AutoHandleModal
  327. open={autoHandleModalOpen}
  328. onCancel={() => setAutoHandleModalOpen(false)}
  329. onOk={onAutoHandleConfirm}
  330. />
  331. <MandateSelectModal
  332. open={mandateSelectModalOpen}
  333. onCancel={() => setMandateSelectModalOpen(false)}
  334. selectedTask={selectedTask}
  335. setSelectedTask={setSelectedTask}
  336. onOk={onMandateSelected}
  337. list={mandateChild}
  338. />
  339. <DispatchTaskModal
  340. open={dispatchModalOpen}
  341. userList={userList}
  342. onCancel={() => {
  343. setDispatchModalOpen(false);
  344. }}
  345. onOK={onDispatchConfirm}
  346. />
  347. </ConfigProvider>
  348. </div>
  349. </Spin>
  350. );
  351. };
  352. export default connect(({ taskUser }) => {
  353. return {
  354. userList: taskUser.userList,
  355. };
  356. })(MandateDetail);
  357. const IgnoreTaskModal = (params) => {
  358. const { open, onCancel, onOk } = params;
  359. const [ignoreReasonText, setIgnoreReasonText] = useState('');
  360. const [selectedReason, setSelectedReason] = useState({});
  361. const [showInput, setShowInput] = useState(false);
  362. const onReasonChange = (reason, option) => {
  363. if (reason !== 4) {
  364. setSelectedReason(option);
  365. setShowInput(false);
  366. } else {
  367. setShowInput(true);
  368. }
  369. };
  370. const onReasonTextChange = (e) => {
  371. setIgnoreReasonText(e.target.value);
  372. };
  373. const handleCancle = () => {
  374. setSelectedReason({});
  375. setIgnoreReasonText('');
  376. setShowInput(false);
  377. onCancel();
  378. };
  379. const confirmIgnore = () => {
  380. if (showInput) {
  381. if (!ignoreReasonText.length) {
  382. message.warning('请输入忽略理由');
  383. } else {
  384. onOk(ignoreReasonText);
  385. }
  386. } else {
  387. if (selectedReason?.label) {
  388. onOk(selectedReason.label);
  389. } else {
  390. message.warning('请选择忽略理由');
  391. }
  392. }
  393. };
  394. return (
  395. <Modal
  396. className={styles.handleModal}
  397. title="忽略"
  398. maskStyle={{ borderRadius: '0.5rem' }}
  399. open={open}
  400. onCancel={handleCancle}
  401. onOk={confirmIgnore}
  402. width="60%"
  403. destroyOnClose
  404. >
  405. <div style={{ padding: '0.15rem' }}>
  406. <Form>
  407. <Form.Item label="忽略理由:">
  408. <Select
  409. className={styles.fontS28}
  410. options={ignoreReason}
  411. onChange={onReasonChange}
  412. allowClear
  413. />
  414. </Form.Item>
  415. {showInput && (
  416. <Form.Item label="输入理由:">
  417. <Input placeholder="请输入理由" onChange={onReasonTextChange} />
  418. </Form.Item>
  419. )}
  420. </Form>
  421. </div>
  422. </Modal>
  423. );
  424. };
  425. const AutoHandleModal = (props) => {
  426. const { open, onCancel, onOk } = props;
  427. const [automation, setAutomation] = useState();
  428. const confirmAutoHandle = () => {
  429. if (automation.length) {
  430. onOk(automation);
  431. } else {
  432. message.warning('请输入口令');
  433. }
  434. };
  435. return (
  436. <Modal
  437. className={styles.handleModal}
  438. title="自动处理"
  439. maskStyle={{ borderRadius: '0.5rem' }}
  440. open={open}
  441. onCancel={onCancel}
  442. onOk={confirmAutoHandle}
  443. width="60%"
  444. destroyOnClose
  445. >
  446. <div style={{ padding: '0.15rem' }}>
  447. <Form>
  448. <Form.Item label="用户口令:">
  449. {
  450. <Input
  451. autoFocus
  452. style={{ width: '100%' }}
  453. placeholder="请输入口令"
  454. onChange={(e) => {
  455. setAutomation(e.target.value);
  456. }}
  457. />
  458. }
  459. </Form.Item>
  460. </Form>
  461. </div>
  462. </Modal>
  463. );
  464. };
  465. const MandateSelectModal = (props) => {
  466. const { open, onCancel, list, onOk, selectedTask, setSelectedTask } = props;
  467. const [checkOptions, setCheckOptions] = useState([]);
  468. useEffect(() => {
  469. setCheckOptions(
  470. list.map((mandate, index) => {
  471. return {
  472. label: (
  473. <Row className={styles.taskCheckItem}>
  474. <span
  475. style={{
  476. textDecoration: `${
  477. mandate.Status === 0 ? '' : 'line-through'
  478. }`,
  479. }}
  480. >
  481. {`${index + 1}. ${mandate.Title}为${mandate.Content}`}
  482. </span>
  483. </Row>
  484. ),
  485. value: mandate.Id,
  486. disabled: mandate.Status !== 0,
  487. };
  488. }),
  489. );
  490. }, [list]);
  491. const onDispatchClick = () => {
  492. onOk(selectedTask);
  493. };
  494. const handleCheckChange = (checkedValue) => {
  495. setSelectedTask(checkedValue);
  496. };
  497. return (
  498. <Modal
  499. className={styles.handleModal}
  500. title="选择任务"
  501. maskStyle={{ borderRadius: '0.5rem' }}
  502. open={open}
  503. onCancel={onCancel}
  504. width={'80%'}
  505. destroyOnClose
  506. footer={[
  507. <Button key="back" onClick={onCancel}>
  508. 取消
  509. </Button>,
  510. <Button key="dispatch" type="primary" onClick={onDispatchClick}>
  511. 派单
  512. </Button>,
  513. ]}
  514. >
  515. <Checkbox.Group
  516. className={styles.taskCheckBox}
  517. options={checkOptions}
  518. onChange={handleCheckChange}
  519. />
  520. </Modal>
  521. );
  522. };
  523. const DispatchTaskModal = (props) => {
  524. const { open, onCancel, onOK, userList } = props;
  525. const [form] = Form.useForm();
  526. useEffect(() => {
  527. if (!open) {
  528. form.resetFields();
  529. }
  530. }, [open]);
  531. const handleDispatchConfirm = async () => {
  532. const value = await form.validateFields().catch((err) =>
  533. err.errorFields.forEach((item) => {
  534. message.error(item.errors);
  535. }),
  536. );
  537. if (!value) {
  538. return;
  539. }
  540. onOK(value);
  541. };
  542. return (
  543. <Modal
  544. className={styles.handleModal}
  545. title="派遣任务"
  546. maskStyle={{ borderRadius: '0.5rem' }}
  547. onCancel={onCancel}
  548. open={open}
  549. destroyOnClose
  550. width="65%"
  551. onOk={handleDispatchConfirm}
  552. >
  553. <Form
  554. form={form}
  555. layout="horizontal"
  556. labelCol={{ span: 8 }}
  557. wrapperCol={{ span: 14 }}
  558. >
  559. <Form.Item
  560. label="工单类型"
  561. name="type"
  562. rules={[{ required: true, message: '请选择工单类型' }]}
  563. >
  564. <Select options={OrderType} placeholder="请选择工单类型" />
  565. </Form.Item>
  566. <Form.Item
  567. label="操作人"
  568. name="operator_id"
  569. rules={[{ required: true, message: '请选择操作人' }]}
  570. >
  571. <Select
  572. options={userList.map((item) => {
  573. return {
  574. label: item.CName,
  575. value: item.ID,
  576. };
  577. })}
  578. placeholder="请选择操作人"
  579. />
  580. </Form.Item>
  581. <Form.Item
  582. label="计划完成时间"
  583. name="plan_end_time"
  584. rules={[{ required: true, message: '请选择完成时间' }]}
  585. >
  586. <DatePicker
  587. inputReadOnly
  588. style={{ width: '100%' }}
  589. placeholder="请选择完成时间"
  590. />
  591. </Form.Item>
  592. </Form>
  593. </Modal>
  594. );
  595. };