index.jsx 25 KB

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