index.jsx 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. import React, { useEffect, useRef, useState } from 'react';
  2. import { Form, Row, Col, Card, Modal, Input, Select, Upload, Button, message } 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 { recurrent, severity, bug_categories } from './const';
  14. const formItemLayout = {
  15. labelCol: {
  16. span: 5,
  17. },
  18. wrapperCol: {
  19. span: 19,
  20. },
  21. };
  22. const Step2 = (props) => {
  23. const [reportForm] = Form.useForm();
  24. const [addCaseForm] = Form.useForm();
  25. const [addBugForm] = Form.useForm();
  26. const { data, dispatch, reportCommonInfo, testCaseList, caseBugList, categories } = props;
  27. const [showTaskRecommendModal, setTaskRecommendModal] = useState(false);
  28. const [showAddTestCaseModal, setAddTestCaseModal] = useState(false);
  29. const [showAddBugModal, setAddTestBugModal] = useState(false);
  30. const currentTestCaseRef = useRef({});
  31. const [isAddCaseStatus, setIsAddCaseStatus] = useState(true);
  32. // const [currActiveTestCase, setCurrActiveTestCase] = useState({});
  33. const [page2List, setPage2List] = useState([]);
  34. const [page3List, setPage3List] = useState([]);
  35. if (!data) {
  36. return null;
  37. }
  38. const handleAddOrEditTestCase = () => {
  39. addCaseForm.validateFields().then((res) => {
  40. let formData = new FormData();
  41. // formData.append("id", values.reportName);
  42. formData.append('report_id', reportCommonInfo.id);
  43. formData.append('name', res.name);
  44. formData.append('front', res.front);
  45. formData.append('behind', res.behind);
  46. formData.append('description', res.result);
  47. if (!isAddCaseStatus) {
  48. //处理编辑用例
  49. formData.append('id', currentTestCaseRef.current.id);
  50. dispatch({
  51. type: 'editReport/updateTestCase',
  52. payload: {
  53. formData,
  54. report_id: reportCommonInfo.id,
  55. },
  56. }).then((res) => {
  57. if (res && res.status === 200) {
  58. message.success('修改成功!');
  59. }
  60. });
  61. } else {
  62. //处理添加用例
  63. dispatch({
  64. type: 'editReport/createTestCase',
  65. payload: {
  66. formData,
  67. report_id: reportCommonInfo.id,
  68. },
  69. }).then((res) => {
  70. if (res && res.id) {
  71. message.success('添加成功!');
  72. }
  73. });
  74. }
  75. setAddTestCaseModal(false);
  76. });
  77. };
  78. const handleAddBug = () => {
  79. addBugForm.validateFields().then((res) => {
  80. let formData = new FormData();
  81. formData.append('report_id', reportCommonInfo.id);
  82. formData.append('title', res.title);
  83. formData.append('description', res.description);
  84. formData.append('bug_category', res.bug_category);
  85. formData.append('severity', res.severity);
  86. formData.append('recurrent', res.recurrent);
  87. formData.append('parent', null);
  88. formData.append('useCase', currentTestCaseRef.current.id);
  89. formData.append('case_id', '1718');
  90. formData.append('case_take_id', '1718-1718');
  91. formData.append('worker_id', '1');
  92. formData.append('page', `${res.page1}-${res.page2}-${res.page3}`);
  93. //新建bug
  94. dispatch({
  95. type:'editReport/createCaseBug',
  96. payload: {
  97. formData,
  98. useCase:currentTestCaseRef.current.id
  99. }
  100. }).then(res=>{
  101. console.log(res.status)
  102. })
  103. });
  104. };
  105. const handleClickTestCase = (caseItem) => {
  106. // setCurrActiveTestCase(caseItem);
  107. currentTestCaseRef.current = caseItem;
  108. dispatch({
  109. type: 'editReport/getCaseBugList',
  110. payload: caseItem.id,
  111. })
  112. };
  113. const handleEditTestCase = (item) => {
  114. setIsAddCaseStatus(false);
  115. currentTestCaseRef.current = item;
  116. addCaseForm.setFieldsValue(currentTestCaseRef.current);
  117. setAddTestCaseModal(true);
  118. };
  119. const handleClickAddCase = () => {
  120. addCaseForm.resetFields();
  121. setAddTestCaseModal(true);
  122. };
  123. const handleClickAddBug = () => {
  124. //current目前只在点击edit cease的时候会有用
  125. addBugForm.resetFields();
  126. setAddTestBugModal(true);
  127. };
  128. const handleSelectPage1 = (val) =>{
  129. let item = categories.find(x=>x.item === val);
  130. setPage2List(item.children)
  131. }
  132. const handleSelectPage2 = (val) =>{
  133. let item = page2List.find(x=>x.item === val);
  134. setPage3List(item.children)
  135. }
  136. useEffect(() => {
  137. //判断是否已经有报告
  138. dispatch({
  139. type: 'editReport/getReportInfo',
  140. payload: {
  141. case_take_id: '1718-1718',
  142. worker_id: 1,
  143. },
  144. }).then((res) => {
  145. // console.log(res)
  146. // console.log(reportCommonInfo)
  147. //有报告,获取对应信息。没有就直接转去了第一步
  148. dispatch({
  149. type: 'editReport/getTestCaseList',
  150. payload: { report_id: reportCommonInfo.id },
  151. }).then((res)=>{
  152. currentTestCaseRef.current = res;
  153. // setCurrActiveTestCase(res);
  154. });
  155. dispatch({
  156. type: 'editReport/getCategories',
  157. payload: { examId: 1945 },
  158. });
  159. });
  160. }, [dispatch,reportCommonInfo.id]);
  161. return (
  162. <div>
  163. <Form
  164. {...formItemLayout}
  165. form={reportForm}
  166. layout="horizontal"
  167. className={styles.stepForm}
  168. hideRequiredMark
  169. initialValues={data}
  170. >
  171. <Row gutter={10}>
  172. <Col span={5}>
  173. <Form.Item label="创建日期" rules={[{ required: true, message: '请输入报告名称' }]}>
  174. {'2021.4.12'}
  175. </Form.Item>
  176. </Col>
  177. <Col span={5}>
  178. <Form.Item label="报告名称" rules={[{ required: true, message: '请输入报告名称' }]}>
  179. {reportCommonInfo.name}
  180. </Form.Item>
  181. </Col>
  182. <Col span={5}>
  183. <Form.Item label="设备名称" required>
  184. {reportCommonInfo.device_brand}
  185. </Form.Item>
  186. </Col>
  187. <Col span={5}>
  188. <Form.Item label="设备品牌" required>
  189. {reportCommonInfo.device_model}
  190. </Form.Item>
  191. </Col>
  192. <Col span={4}>
  193. <Form.Item label="操作系统" required>
  194. {reportCommonInfo.device_os}
  195. </Form.Item>
  196. </Col>
  197. </Row>
  198. </Form>
  199. <Card>
  200. <div className={styles.reportContainer}>
  201. <Row gutter={10}>
  202. <Col span={8}>
  203. <div>
  204. <Row gutter={10} style={{ marginBottom: 10 }}>
  205. <Col span={20}><h3>测试用例列表</h3></Col>
  206. <Col span={4}>
  207. <Button size="small" onClick={() => {
  208. handleClickAddCase();
  209. }}>
  210. <PlusOutlined className={styles.addIcon} />
  211. 用例
  212. </Button>
  213. </Col>
  214. </Row>
  215. </div>
  216. <div className={styles.testCaseList}>
  217. {testCaseList && testCaseList.map((item) => {
  218. return (
  219. <div
  220. className={`${styles.testCaseItem} ${currentTestCaseRef.current.id === item.id ? styles.activeCase : ''}`}
  221. key={item.id}
  222. onClick={() => {
  223. handleClickTestCase(item);
  224. }}>
  225. <Row gutter={10}>
  226. <Col span={21}><p>{item.name}</p></Col>
  227. <Col span={3}>
  228. <EditOutlined className={styles.editTestBug}
  229. onClick={() => handleEditTestCase(item)} />
  230. </Col>
  231. </Row>
  232. </div>);
  233. })}
  234. </div>
  235. </Col>
  236. <Col span={16} style={{ paddingLeft: 20 }}>
  237. <Row gutter={10} style={{ marginBottom: 10 }}>
  238. <Col span={20}><h3>缺陷列表</h3></Col>
  239. <Col span={2}>
  240. <Button size="small" onClick={() => handleClickAddBug()}>
  241. <PlusOutlined className={styles.addIcon} />
  242. 缺陷
  243. </Button>
  244. </Col>
  245. <Col span={2}>
  246. <Button size="small" onClick={() => setTaskRecommendModal(true)}>
  247. <ForkOutlined className={styles.addIcon} />
  248. 推荐
  249. </Button>
  250. </Col>
  251. </Row>
  252. <div className={styles.testBugList}>
  253. {/*{console.log(props)}*/}
  254. {/*{console.log(props.caseBugList)}*/}
  255. {/*{console.log(props.caseBugList.length)}*/}
  256. {caseBugList && caseBugList.map((item) => {
  257. return (
  258. <div className={styles.testBugItem} key={item.detail.id}>
  259. <Row gutter={10}>
  260. <Col span={20}>
  261. <div><span className={styles.bugItemTitle}>Bug标题:</span>{item.detail.title}</div>
  262. <div><span className={styles.bugItemTitle}>复现程度:</span>{recurrent[item.detail.recurrent]}
  263. </div>
  264. <div><span className={styles.bugItemTitle}>严重程度:</span>{severity[item.detail.severity]}</div>
  265. <div><span
  266. className={styles.bugItemTitle}>缺陷分类:</span>{item.detail.bug_category}
  267. </div>
  268. </Col>
  269. <Col span={4}>
  270. <Button size='small' style={{ marginTop: 10 }}>
  271. <EyeOutlined />详情</Button>
  272. </Col>
  273. </Row>
  274. </div>
  275. );
  276. })}
  277. </div>
  278. </Col>
  279. </Row>
  280. </div>
  281. </Card>
  282. <Modal title={isAddCaseStatus ? '添加测试用例' : '编辑测试用例'} width={720}
  283. visible={showAddTestCaseModal}
  284. forceRender={true}
  285. className="addModal"
  286. footer={[
  287. <Button key='submit' type="primary" htmlType="submit" onClick={handleAddOrEditTestCase}>确定</Button>,
  288. <Button key='cancel' htmlType="button" style={{ marginLeft: '10px' }}
  289. onClick={() => {
  290. setAddTestCaseModal(false);
  291. }}>取消</Button>]}
  292. onCancel={() => {
  293. setAddTestCaseModal(false);
  294. }}
  295. >
  296. <ExclamationCircleFilled className={styles.addModalInfo} />为了评分准确,请勿提交重复测试用例
  297. <Form
  298. {...formItemLayout}
  299. form={addCaseForm}
  300. layout="horizontal"
  301. className={styles.stepForm}
  302. >
  303. <Form.Item
  304. label="用例名称"
  305. name="name"
  306. rules={[
  307. {
  308. required: true,
  309. message: '请输入用例名称!',
  310. },
  311. ]}
  312. >
  313. <Input />
  314. </Form.Item>
  315. <Form.Item
  316. label="前置条件"
  317. name="front"
  318. rules={[
  319. {
  320. required: true,
  321. message: '请输入前置条件!',
  322. },
  323. ]}
  324. >
  325. <Input.TextArea autoSize={{ minRows: 3, maxRows: 999 }} />
  326. </Form.Item>
  327. <Form.Item
  328. label="测试步骤"
  329. name="behind"
  330. rules={[
  331. {
  332. required: true,
  333. message: '请输入测试步骤!',
  334. },
  335. ]}
  336. >
  337. <Input.TextArea autoSize={{ minRows: 3, maxRows: 999 }} />
  338. </Form.Item>
  339. <Form.Item
  340. label="预期结果"
  341. name="result"
  342. rules={[
  343. {
  344. required: true,
  345. message: '请输入预期结果!',
  346. },
  347. ]}
  348. >
  349. <Input.TextArea autoSize={{ minRows: 3, maxRows: 999 }} />
  350. </Form.Item>
  351. </Form>
  352. </Modal>
  353. <Modal title="添加用例缺陷" visible={showAddBugModal} width={720}
  354. forceRender={true}
  355. footer={[
  356. <Button key='submit' type="primary" htmlType="submit" onClick={handleAddBug}>确定</Button>,
  357. <Button key='cancel' htmlType="button" style={{ marginLeft: '10px' }}
  358. onClick={() => {
  359. setAddTestBugModal(false);
  360. }}>取消</Button>]}
  361. onCancel={() => {
  362. setAddTestBugModal(false);
  363. }}
  364. className={styles.bugForm}
  365. >
  366. <ExclamationCircleFilled className={styles.addModalInfo} />为了评分准确,请勿提交重复Bug
  367. <Form
  368. form={addBugForm}
  369. {...formItemLayout}
  370. layout="horizontal"
  371. className={styles.stepForm}
  372. >
  373. <Form.Item
  374. label="测试标题"
  375. name="title"
  376. rules={[
  377. {
  378. required: true,
  379. message: '请输入测试标题!',
  380. },
  381. ]}
  382. >
  383. <Input.TextArea autoSize={{ minRows: 1, maxRows: 999 }} />
  384. </Form.Item>
  385. <Form.Item
  386. label="题目描述"
  387. name="description"
  388. rules={[
  389. {
  390. required: true,
  391. message: '请输入题目描述!',
  392. },
  393. ]}
  394. >
  395. <Input.TextArea autoSize={{ minRows: 2, maxRows: 999 }} />
  396. </Form.Item>
  397. <Form.Item
  398. label="三级页面"
  399. name="pages"
  400. >
  401. <Row gutter={5} className={styles.pageSelect}>
  402. <Col span={8}>
  403. <Form.Item
  404. name="page1"
  405. rules={[
  406. {
  407. required: true,
  408. message: '请输入一级页面',
  409. },
  410. ]}
  411. >
  412. <Select onSelect={(val)=>{handleSelectPage1(val)}}>
  413. {categories.map((item) => {
  414. return <Select.Option value={item.item} key={item.item}>{item.item}
  415. </Select.Option>;
  416. })}
  417. </Select>
  418. </Form.Item>
  419. </Col>
  420. <Col span={8}>
  421. <Form.Item
  422. name="page2"
  423. rules={[
  424. {
  425. required: true,
  426. message: '请输入二级页面',
  427. },
  428. ]}
  429. >
  430. <Select disabled={!page2List.length}
  431. onSelect={(val)=>{handleSelectPage2(val)}}>
  432. {page2List.map((item)=>{
  433. return <Select.Option value={item.item} key={item.item}>{item.item}</Select.Option>
  434. })}
  435. </Select>
  436. </Form.Item>
  437. </Col>
  438. <Col span={8}>
  439. <Form.Item
  440. name="page3"
  441. rules={[
  442. {
  443. required: true,
  444. message: '请输入三级页面',
  445. },
  446. ]}
  447. >
  448. <Select disabled={!page3List.length}>
  449. {page3List.map((item)=>{
  450. return <Select.Option value={item.item} key={item.item}>{item.item}</Select.Option>
  451. })}
  452. </Select>
  453. </Form.Item>
  454. </Col>
  455. </Row>
  456. </Form.Item>
  457. <Form.Item
  458. label="漏洞分类"
  459. name="bug_category"
  460. rules={[
  461. {
  462. required: true,
  463. message: '请选择漏洞分类!',
  464. },
  465. ]}
  466. >
  467. <Select>
  468. {bug_categories.map((item) => {
  469. return <Select.Option value={item} key={item}>{item}</Select.Option>;
  470. })}
  471. </Select>
  472. </Form.Item>
  473. <Form.Item
  474. label="严重等级"
  475. name="severity"
  476. rules={[
  477. {
  478. required: true,
  479. message: '请选择严重等级!',
  480. },
  481. ]}
  482. >
  483. <Select>
  484. {severity.map((item) => {
  485. return <Select.Option value={item} key={item}>{item}</Select.Option>;
  486. })}
  487. </Select>
  488. </Form.Item>
  489. <Form.Item
  490. label="复现程度"
  491. name="recurrent"
  492. rules={[
  493. {
  494. required: true,
  495. message: '请选择复现程度!',
  496. },
  497. ]}
  498. >
  499. <Select>
  500. {recurrent.map((item) => {
  501. return <Select.Option value={item} key={item}>{item}</Select.Option>;
  502. })}
  503. </Select>
  504. </Form.Item>
  505. {/*<Form.Item*/}
  506. {/* label="上传截图"*/}
  507. {/* name="testName"*/}
  508. {/*>*/}
  509. {/* <Upload*/}
  510. {/* action="https://www.mocky.io/v2/5cc8019d300000980a055e76"*/}
  511. {/* listType="picture"*/}
  512. {/* >*/}
  513. {/* <Button icon={<UploadOutlined />}>Upload</Button>*/}
  514. {/* </Upload>*/}
  515. {/*</Form.Item>*/}
  516. </Form>
  517. </Modal>
  518. <Modal title="任务推荐" visible={showTaskRecommendModal} onOk={() => setTaskRecommendModal(false)}
  519. onCancel={() => setTaskRecommendModal(false)} className="addModal">
  520. <div>
  521. <div id="forceChart"></div>
  522. </div>
  523. </Modal>
  524. </div>
  525. );
  526. };
  527. export default connect(({ editReport, loading }) => ({
  528. submitting: loading.effects['editReport/submitStepForm'],
  529. data: editReport.step,
  530. reportCommonInfo: editReport.reportCommonInfo,
  531. testCaseList: editReport.testCaseList,
  532. caseBugList: editReport.caseBugList,
  533. categories: editReport.categories,
  534. }))(Step2);