index.jsx 29 KB

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