index.jsx 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752
  1. import React, { useEffect, useRef, useState } from 'react';
  2. import { Form, Row, Col, Card, Modal, Input, Select, Upload, Button, message, Tag, Badge } from 'antd';
  3. import { connect } from 'umi';
  4. import styles from './index.less';
  5. import {
  6. ForkOutlined,
  7. PlusOutlined,
  8. ExclamationCircleFilled,
  9. UploadOutlined,
  10. EditOutlined,
  11. EyeOutlined,
  12. } from '@ant-design/icons';
  13. import * as echarts from 'echarts';
  14. import { recurrent, severity, bug_categories } from './const';
  15. import { timeToString,getBase64 } from '../../utils';
  16. import BugGuideTree from '../BugGuideTree';
  17. import { instanceOf } from 'prop-types';
  18. const formItemLayout = {
  19. labelCol: {
  20. span: 8,
  21. },
  22. wrapperCol: {
  23. span: 19,
  24. },
  25. };
  26. const modalFormItemLayout = {
  27. labelCol: {
  28. span: 5,
  29. },
  30. wrapperCol: {
  31. span: 19,
  32. },
  33. };
  34. const uploadButton = (
  35. <div>
  36. <PlusOutlined />
  37. <div style={{ marginTop: 8 }}>点击上传</div>
  38. </div>
  39. );
  40. const Step2 = (props) => {
  41. const [reportForm] = Form.useForm();
  42. const [addCaseForm] = Form.useForm();
  43. const [addBugForm] = Form.useForm();
  44. const [editReportForm] = Form.useForm();
  45. const {
  46. dispatch, reportCommonInfo, osType,
  47. testCaseList, caseBugList, categories, pathInfo,
  48. } = props;
  49. const [showTaskRecommendModal, setTaskRecommendModal] = useState(false);
  50. const [showAddTestCaseModal, setAddTestCaseModal] = useState(false);
  51. const [showAddBugModal, setAddTestBugModal] = useState(false);
  52. const [showEditReportModal, setEditReportModal] = useState(false);
  53. const currentTestCaseRef = useRef({});
  54. const [isAddCaseStatus, setIsAddCaseStatus] = useState(true);
  55. // const [currActiveTestCase, setCurrActiveTestCase] = useState({});
  56. //上传图片廊需要的字段
  57. const [fileList,setFileList] = useState([]);
  58. const [previewTitle,setPreviewTitle] = useState('');
  59. const [previewImage,setPreviewImage] = useState('');
  60. const [previewVisible,setPreviewVisible] = useState(false);
  61. const [page2List, setPage2List] = useState([]);
  62. const [page3List, setPage3List] = useState([]);
  63. const handleEditReportInfo = () => {
  64. editReportForm.validateFields().then((res)=> {
  65. let formData = new FormData();
  66. formData.append('name', res.name);
  67. formData.append('report_id', reportCommonInfo.id);
  68. formData.append('worker_id', '2');
  69. formData.append('case_take_id', '1718-1718');
  70. formData.append('device_model', res.device_model);
  71. formData.append('device_brand', res.device_brand);
  72. formData.append('device_os', res.device_os);
  73. dispatch({
  74. type: 'editReport/updateReportCommonDetail',
  75. payload: { formData }
  76. })
  77. })
  78. setEditReportModal(false)
  79. };
  80. const handleAddOrEditTestCase = () => {
  81. addCaseForm.validateFields().then((res) => {
  82. let formData = new FormData();
  83. // formData.append("id", values.reportName);
  84. formData.append('report_id', reportCommonInfo.id);
  85. formData.append('name', res.name);
  86. formData.append('front', res.front);
  87. formData.append('behind', res.behind);
  88. formData.append('description', res.description);
  89. if (!isAddCaseStatus) {
  90. //处理编辑用例
  91. formData.append('id', currentTestCaseRef.current.id);
  92. dispatch({
  93. type: 'editReport/updateTestCase',
  94. payload: {
  95. formData,
  96. report_id: reportCommonInfo.id,
  97. },
  98. }).then((res) => {
  99. if (res && res.status === 200) {
  100. message.success('修改成功!');
  101. }
  102. });
  103. } else {
  104. //处理添加用例
  105. dispatch({
  106. type: 'editReport/createTestCase',
  107. payload: {
  108. formData,
  109. report_id: reportCommonInfo.id,
  110. },
  111. }).then((res) => {
  112. if (res && res.id) {
  113. message.success('添加成功!');
  114. }
  115. });
  116. }
  117. setAddTestCaseModal(false);
  118. });
  119. };
  120. const handleAddBug = () => {
  121. addBugForm.validateFields().then((res) => {
  122. let formData = new FormData();
  123. formData.append('report_id', reportCommonInfo.id);
  124. formData.append('title', res.title);
  125. formData.append('description', res.description);
  126. formData.append('bug_category', res.bug_category);
  127. formData.append('severity', res.severity);
  128. formData.append('recurrent', res.recurrent);
  129. formData.append('parent', null);
  130. formData.append('useCase', currentTestCaseRef.current.id);
  131. formData.append('case_id', '1718');
  132. formData.append('case_take_id', '1718-1718');
  133. formData.append('worker_id', '2');
  134. formData.append('page', `${res.page1}-${res.page2}-${res.page3}`);
  135. if(fileList.length){
  136. let str = '';
  137. fileList.map(item=>{
  138. str += (item.response + ',')
  139. })
  140. str = str.substring(0,str.length-1);
  141. formData.append('img_url', str);
  142. }
  143. //新建bug
  144. dispatch({
  145. type: 'editReport/createCaseBug',
  146. payload: {
  147. formData,
  148. useCase: currentTestCaseRef.current.id,
  149. },
  150. }).then(res => {
  151. setAddTestBugModal(false);
  152. });
  153. });
  154. };
  155. const handleClickTestCase = (caseItem) => {
  156. // setCurrActiveTestCase(caseItem);
  157. currentTestCaseRef.current = caseItem;
  158. dispatch({
  159. type: 'editReport/getCaseBugList',
  160. payload: caseItem.id,
  161. });
  162. };
  163. const handleEditTestCase = (item) => {
  164. setIsAddCaseStatus(false);
  165. currentTestCaseRef.current = item;
  166. addCaseForm.setFieldsValue(currentTestCaseRef.current);
  167. setAddTestCaseModal(true);
  168. };
  169. const handleClickAddCase = () => {
  170. addCaseForm.resetFields();
  171. setAddTestCaseModal(true);
  172. };
  173. const handleClickAddBug = () => {
  174. //current目前只在点击edit cease的时候会有用
  175. addBugForm.resetFields();
  176. setAddTestBugModal(true);
  177. };
  178. const handleClickRecommendBtn = () => {
  179. dispatch({
  180. type: 'editReport/getPathInfo',
  181. payload: {
  182. case_take_id: '1718-1718',
  183. report_id: reportCommonInfo.id,
  184. },
  185. });
  186. dispatch({
  187. type: 'editReport/getBugRecommendPath',
  188. payload: {
  189. case_take_id: '1718-1718',
  190. report_id: reportCommonInfo.id,
  191. },
  192. });
  193. dispatch({
  194. type: 'editReport/getBugRecommendList',
  195. payload: {
  196. case_take_id: '1718-1718',
  197. report_id: reportCommonInfo.id,
  198. },
  199. });
  200. setTaskRecommendModal(true);
  201. };
  202. const handleSelectPage1 = (val) => {
  203. let item = categories.find(x => x.item === val);
  204. setPage2List(item.children);
  205. };
  206. const handleSelectPage2 = (val) => {
  207. let item = page2List.find(x => x.item === val);
  208. setPage3List(item.children);
  209. };
  210. const handlePreview = async file => {
  211. if (!file.url && !file.preview) {
  212. file.preview = await getBase64(file.originFileObj);
  213. }
  214. setPreviewImage(file.url || file.preview);
  215. setPreviewVisible(true);
  216. setPreviewTitle(file.name || file.url.substring(file.url.lastIndexOf('/') + 1))
  217. };
  218. const handleCancel = () => setPreviewVisible(false);
  219. const handleChange = ({ fileList }) => {
  220. setFileList(fileList);
  221. };
  222. useEffect(() => {
  223. //判断是否已经有报告
  224. dispatch({
  225. type: 'editReport/getReportInfo',
  226. payload: {
  227. case_take_id: '1718-1718',
  228. worker_id: '2',
  229. },
  230. }).then((res) => {
  231. // console.log(res)
  232. // console.log(reportCommonInfo)
  233. //有报告,获取对应信息。没有就直接转去了第一步
  234. dispatch({
  235. type: 'editReport/getTestCaseList',
  236. payload: { report_id: reportCommonInfo.id },
  237. }).then((res) => {
  238. if (res && res.length) {
  239. currentTestCaseRef.current = res[0];
  240. dispatch({
  241. type: 'editReport/getCaseBugList',
  242. payload: currentTestCaseRef.current.id,
  243. });
  244. }
  245. });
  246. dispatch({
  247. type: 'editReport/getCategories',
  248. payload: { examId: 1718 },
  249. });
  250. });
  251. }, [dispatch, reportCommonInfo.id]);
  252. return (
  253. <div id="main">
  254. <Row gutter={10}>
  255. <Col span={23}>
  256. <Form
  257. {...formItemLayout}
  258. form={reportForm}
  259. className={styles.stepForm}
  260. hideRequiredMark
  261. >
  262. <Row gutter={10}>
  263. <Col span={5}>
  264. <Form.Item label="创建日期" rules={[{ required: true, message: '请输入报告名称' }]}>
  265. {timeToString(reportCommonInfo.create_time_millis)}
  266. </Form.Item>
  267. </Col>
  268. <Col span={5}>
  269. <Form.Item label="报告名称" rules={[{ required: true, message: '请输入报告名称' }]}>
  270. {reportCommonInfo.name}
  271. </Form.Item>
  272. </Col>
  273. <Col span={5}>
  274. <Form.Item label="设备名称" required>
  275. {reportCommonInfo.device_brand}
  276. </Form.Item>
  277. </Col>
  278. <Col span={5}>
  279. <Form.Item label="设备品牌" required>
  280. {reportCommonInfo.device_model}
  281. </Form.Item>
  282. </Col>
  283. <Col span={4}>
  284. <Form.Item label="操作系统" required>
  285. {reportCommonInfo.device_os}
  286. </Form.Item>
  287. </Col>
  288. </Row>
  289. </Form>
  290. </Col>
  291. <Col span={1}>
  292. <EditOutlined className={styles.editReportInfoIcon}
  293. onClick={() => setEditReportModal(true)}
  294. />
  295. </Col>
  296. </Row>
  297. <Card>
  298. <div className={styles.reportContainer}>
  299. <Row gutter={10}>
  300. <Col span={8}>
  301. <div gutter={10} className={styles.testCaseTitle}>
  302. <h3>测试用例列表</h3>
  303. <Button size="small" type="primary"
  304. onClick={() => {
  305. handleClickAddCase();
  306. }}>
  307. <PlusOutlined className={styles.addIcon} />
  308. 用例
  309. </Button>
  310. </div>
  311. <div className={styles.testCaseList}>
  312. {testCaseList && testCaseList.length ? testCaseList.map((item) => {
  313. return (
  314. <div
  315. className={`${styles.testCaseItem} ${currentTestCaseRef.current.id === item.id ? styles.activeCase : ''}`}
  316. key={item.id}
  317. onClick={() => {
  318. handleClickTestCase(item);
  319. }}>
  320. <Row gutter={10}>
  321. <Col span={6}>
  322. {<span
  323. className={styles.testCaseItemNo}>{`NO.${((item.id).substring((item.id.length) - 6)).toUpperCase()}`}</span>}
  324. {/*<Badge color="#2db7f5"*/}
  325. {/* text={} />*/}
  326. </Col>
  327. <Col span={15}>
  328. <span>{item.name}</span>
  329. </Col>
  330. <Col span={3}>
  331. <EditOutlined className={styles.editTestBug}
  332. onClick={() => handleEditTestCase(item)} />
  333. </Col>
  334. </Row>
  335. </div>);
  336. }) : <div>快来创建你的第一个测试用例吧~</div>}
  337. </div>
  338. </Col>
  339. <Col span={16}>
  340. <div gutter={10} className={styles.testBugTitle}>
  341. <h3>缺陷列表</h3>
  342. <div>
  343. <Button size="small" type="primary"
  344. disabled={JSON.stringify(currentTestCaseRef.current) === '{}'}
  345. onClick={() => handleClickAddBug()}>
  346. <PlusOutlined className={styles.addIcon} />
  347. 缺陷
  348. </Button>
  349. <Button size="small"
  350. className={styles.recommendBtn}
  351. disabled={JSON.stringify(currentTestCaseRef.current) === '{}'}
  352. onClick={() => handleClickRecommendBtn()}>
  353. <ForkOutlined className={styles.addIcon} />
  354. 推荐
  355. </Button>
  356. </div>
  357. </div>
  358. <div className={styles.testBugList}>
  359. {caseBugList && caseBugList.length ? caseBugList.map((item) => {
  360. return (
  361. <div className={styles.testBugItem} key={item.detail.id}>
  362. <Row gutter={10}>
  363. <Col span={12}>
  364. <div>
  365. <div className={styles.testBugItemTitleBlock}>
  366. <span className={styles.testBugItemTitle}>标题:</span>
  367. <span className={styles.testBugItemTitleDetail}>{item.detail.title}</span>
  368. <Tag color="cyan">{recurrent[item.detail.recurrent]}</Tag>
  369. <Tag color="red">{severity[item.detail.severity]}</Tag>
  370. <Tag color="geekblue">{item.detail.bug_category}</Tag>
  371. </div>
  372. <div className={styles.testBugItemTitleBlock}>
  373. <span className={styles.testBugItemTitle}>路径:</span>
  374. {item.detail.bug_page}
  375. </div>
  376. <div className={styles.testBugItemTitleBlock}>
  377. <span className={styles.testBugItemTitle}>描述:</span>
  378. {item.detail.description}
  379. </div>
  380. </div>
  381. </Col>
  382. <Col span={12} className={styles.bugImgList}>
  383. <img src={require('../../assets/report1.jpeg')} alt='bug_img' />
  384. <img src={require('../../assets/report2.jpeg')} alt='bug_img' />
  385. <img src={require('../../assets/report3.jpeg')} alt='bug_img' />
  386. </Col>
  387. </Row>
  388. </div>
  389. );
  390. }) : <div>当前用例暂无提交记录,快去创建第一个BUG吧~</div>}
  391. </div>
  392. </Col>
  393. </Row>
  394. </div>
  395. </Card>
  396. <Modal title={isAddCaseStatus ? '添加测试用例' : '编辑测试用例'} width={720}
  397. visible={showAddTestCaseModal}
  398. forceRender={true}
  399. className="addModal"
  400. footer={[
  401. <Button key='submit' type="primary" htmlType="submit" onClick={handleAddOrEditTestCase}>确定</Button>,
  402. <Button key='cancel' htmlType="button" style={{ marginLeft: '10px' }}
  403. onClick={() => {
  404. setAddTestCaseModal(false);
  405. }}>取消</Button>]}
  406. onCancel={() => {
  407. setAddTestCaseModal(false);
  408. }}
  409. >
  410. <ExclamationCircleFilled className={styles.addModalInfo} />为了评分准确,请勿提交重复测试用例
  411. <Form
  412. {...modalFormItemLayout}
  413. form={addCaseForm}
  414. layout="horizontal"
  415. className={styles.stepForm}
  416. >
  417. <Form.Item
  418. label="用例名称"
  419. name="name"
  420. rules={[
  421. {
  422. required: true,
  423. message: '请输入用例名称!',
  424. },
  425. ]}
  426. >
  427. <Input />
  428. </Form.Item>
  429. <Form.Item
  430. label="前置条件"
  431. name="front"
  432. rules={[
  433. {
  434. required: true,
  435. message: '请输入前置条件!',
  436. },
  437. ]}
  438. >
  439. <Input.TextArea autoSize={{ minRows: 3, maxRows: 999 }} />
  440. </Form.Item>
  441. <Form.Item
  442. label="测试步骤"
  443. name="behind"
  444. rules={[
  445. {
  446. required: true,
  447. message: '请输入测试步骤!',
  448. },
  449. ]}
  450. >
  451. <Input.TextArea autoSize={{ minRows: 3, maxRows: 999 }} />
  452. </Form.Item>
  453. <Form.Item
  454. label="预期结果"
  455. name="description"
  456. rules={[
  457. {
  458. required: true,
  459. message: '请输入预期结果!',
  460. },
  461. ]}
  462. >
  463. <Input.TextArea autoSize={{ minRows: 3, maxRows: 999 }} />
  464. </Form.Item>
  465. </Form>
  466. </Modal>
  467. <Modal title="添加用例缺陷" visible={showAddBugModal} width={720}
  468. forceRender={true}
  469. footer={[
  470. <Button key='submit' type="primary" htmlType="submit" onClick={handleAddBug}>确定</Button>,
  471. <Button key='cancel' htmlType="button" style={{ marginLeft: '10px' }}
  472. onClick={() => {
  473. setAddTestBugModal(false);
  474. }}>取消</Button>]}
  475. onCancel={() => {
  476. setAddTestBugModal(false);
  477. }}
  478. className={styles.bugForm}
  479. >
  480. <ExclamationCircleFilled className={styles.addModalInfo} />为了评分准确,请勿提交重复Bug
  481. <Form
  482. form={addBugForm}
  483. {...modalFormItemLayout}
  484. layout="horizontal"
  485. className={styles.stepForm}
  486. >
  487. <Form.Item
  488. label="测试标题"
  489. name="title"
  490. rules={[
  491. {
  492. required: true,
  493. message: '请输入测试标题!',
  494. },
  495. ]}
  496. >
  497. <Input.TextArea autoSize={{ minRows: 1, maxRows: 999 }} />
  498. </Form.Item>
  499. <Form.Item
  500. label="题目描述"
  501. name="description"
  502. rules={[
  503. {
  504. required: true,
  505. message: '请输入题目描述!',
  506. },
  507. ]}
  508. >
  509. <Input.TextArea autoSize={{ minRows: 2, maxRows: 999 }} />
  510. </Form.Item>
  511. <Form.Item
  512. label="三级页面"
  513. name="page3"
  514. rules={[
  515. {
  516. required: true,
  517. message: '',
  518. },
  519. ]}
  520. >
  521. <Row gutter={5} className={styles.pageSelect}>
  522. <Col span={8}>
  523. <Form.Item
  524. name="page1"
  525. rules={[
  526. {
  527. required: true,
  528. message: '请输入一级页面',
  529. },
  530. ]}
  531. >
  532. <Select onSelect={(val) => {
  533. handleSelectPage1(val);
  534. }}>
  535. {categories.map((item) => {
  536. return <Select.Option value={item.item} key={item.item}>{item.item}
  537. </Select.Option>;
  538. })}
  539. </Select>
  540. </Form.Item>
  541. </Col>
  542. <Col span={8}>
  543. <Form.Item
  544. name="page2"
  545. rules={[
  546. {
  547. required: true,
  548. message: '请输入二级页面',
  549. },
  550. ]}
  551. >
  552. <Select disabled={!page2List.length}
  553. onSelect={(val) => {
  554. handleSelectPage2(val);
  555. }}>
  556. {page2List.map((item) => {
  557. return <Select.Option value={item.item} key={item.item}>{item.item}</Select.Option>;
  558. })}
  559. </Select>
  560. </Form.Item>
  561. </Col>
  562. <Col span={8}>
  563. <Form.Item
  564. name="page3"
  565. rules={[
  566. {
  567. required: true,
  568. message: '请输入三级页面',
  569. },
  570. ]}
  571. >
  572. <Select disabled={!page3List.length}>
  573. {page3List.map((item) => {
  574. return <Select.Option value={item.item} key={item.item}>{item.item}</Select.Option>;
  575. })}
  576. </Select>
  577. </Form.Item>
  578. </Col>
  579. </Row>
  580. </Form.Item>
  581. <Form.Item
  582. label="漏洞分类"
  583. name="bug_category"
  584. rules={[
  585. {
  586. required: true,
  587. message: '请选择漏洞分类!',
  588. },
  589. ]}
  590. >
  591. <Select>
  592. {bug_categories.map((item) => {
  593. return <Select.Option value={item} key={item}>{item}</Select.Option>;
  594. })}
  595. </Select>
  596. </Form.Item>
  597. <Form.Item
  598. label="严重等级"
  599. name="severity"
  600. rules={[
  601. {
  602. required: true,
  603. message: '请选择严重等级!',
  604. },
  605. ]}
  606. >
  607. <Select>
  608. {severity.map((item) => {
  609. return <Select.Option value={item} key={item}>{item}</Select.Option>;
  610. })}
  611. </Select>
  612. </Form.Item>
  613. <Form.Item
  614. label="复现程度"
  615. name="recurrent"
  616. rules={[
  617. {
  618. required: true,
  619. message: '请选择复现程度!',
  620. },
  621. ]}
  622. >
  623. <Select>
  624. {recurrent.map((item) => {
  625. return <Select.Option value={item} key={item}>{item}</Select.Option>;
  626. })}
  627. </Select>
  628. </Form.Item>
  629. <Form.Item
  630. label="上传截图"
  631. name="testName"
  632. >
  633. <Upload
  634. action='/api/upload/image'
  635. data={file => ({ // data里存放的是接口的请求参数
  636. file,
  637. caseId:currentTestCaseRef.current.id,
  638. work_id:'2'
  639. })}
  640. listType="picture-card"
  641. fileList={fileList}
  642. onPreview={handlePreview}
  643. onChange={handleChange}
  644. >
  645. {uploadButton}
  646. </Upload>
  647. <Modal
  648. visible={previewVisible}
  649. title={previewTitle}
  650. footer={null}
  651. onCancel={()=>handleCancel()}
  652. >
  653. <img alt="example" style={{ width: '100%' }} src={previewImage} />
  654. </Modal>
  655. </Form.Item>
  656. </Form>
  657. </Modal>
  658. <Modal title="修改报告基础信息" visible={showEditReportModal}
  659. footer={[
  660. <Button key='submit' type="primary" htmlType="submit"
  661. onClick={handleEditReportInfo}>确定</Button>,
  662. <Button key='cancel' htmlType="button" style={{ marginLeft: '10px' }}
  663. onClick={() => {
  664. setEditReportModal(false);
  665. }}>取消</Button>]}
  666. onCancel={() => {
  667. setEditReportModal(false);
  668. }}>
  669. <div>
  670. <Form
  671. {...modalFormItemLayout}
  672. form={editReportForm}
  673. layout="horizontal"
  674. initialValues={reportCommonInfo}
  675. >
  676. <Form.Item label="报告名称" name="name" rules={[{ required: true, message: '请输入报告名称' }]}>
  677. <Input placeholder="请输入报告名称" />
  678. </Form.Item>
  679. <Form.Item label="设备名称" name="device_model" rules={[{ required: true, message: '请输入设备品牌' }]}>
  680. <Input placeholder="请输入设备名称" />
  681. </Form.Item>
  682. <Form.Item label="设备品牌" name="device_brand" rules={[{ required: true, message: '请输入设备品牌' }]}>
  683. <Input placeholder="请输入设备品牌" />
  684. </Form.Item>
  685. <Form.Item label="操作系统" name="device_os" rules={[{ required: true, message: '请输入操作系统' }]}>
  686. <Select placeholder="请选择操作系统">
  687. {osType.map((option) => {
  688. return <Select.Option value={option} key={option}>{option}</Select.Option>;
  689. })}
  690. </Select>
  691. </Form.Item>
  692. </Form>
  693. </div>
  694. </Modal>
  695. <Modal title="任务推荐" visible={showTaskRecommendModal}
  696. destroyOnClose width={1000}
  697. onOk={() => setTaskRecommendModal(false)}
  698. onCancel={() => {
  699. setTaskRecommendModal(false);
  700. }
  701. }
  702. className="addModal">
  703. <div>
  704. <BugGuideTree />
  705. </div>
  706. </Modal>
  707. </div>
  708. );
  709. };
  710. export default connect(({ editReport, loading }) => ({
  711. submitting: loading.effects['editReport/submitStepForm'],
  712. reportCommonInfo: editReport.reportCommonInfo,
  713. testCaseList: editReport.testCaseList,
  714. caseBugList: editReport.caseBugList,
  715. categories: editReport.categories,
  716. pathInfo: editReport.pathInfo,
  717. osType: editReport.osType,
  718. }))(Step2);