APITest.vue 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125
  1. <template>
  2. <ElTabs class="tabs" v-model="activeTab">
  3. <ElTabPane label="接口测试" name="apitest">
  4. <ElTable :data="apitests" width="100%">
  5. <ElTableColumn
  6. prop="testId"
  7. label="ID"
  8. align="center"
  9. width="60">
  10. </ElTableColumn>
  11. <ElTableColumn
  12. prop="testName"
  13. label="测试名称"
  14. align="center"
  15. width="300">
  16. </ElTableColumn>
  17. <ElTableColumn
  18. prop="username"
  19. label="创建者"
  20. align="center"
  21. width="180">
  22. </ElTableColumn>
  23. <ElTableColumn
  24. prop="createTime"
  25. label="创建时间"
  26. align="center"
  27. width="250">
  28. </ElTableColumn>
  29. <ElTableColumn
  30. label="详情"
  31. align="center">
  32. <template #default="scope">
  33. <ElButton
  34. @click="handleClick('latest', scope.row.testId)"
  35. type="text"
  36. size="small">最近执行详情</ElButton>
  37. <ElButton @click="handleClick('detail', scope.row.testId)" type="text" size="small">测试任务详情</ElButton>
  38. </template>
  39. </ElTableColumn>
  40. <ElTableColumn
  41. align="center">
  42. <template #header>
  43. <span>操作</span>
  44. <ElButton @click="handleClick('create')" type="text" class="add-button">新建</ElButton>
  45. </template>
  46. <template #default="scope">
  47. <ElButton @click="handleClick('trigger', scope.row.testId)" type="text" size="small">触发</ElButton>
  48. <ElButton @click="handleClick('delete', scope.row.testId)" type="text" size="small">删除</ElButton>
  49. </template>
  50. </ElTableColumn>
  51. </ElTable>
  52. <!-- 测试任务详情 -->
  53. <ElDrawer
  54. v-model="detailDrawer"
  55. :size="800">
  56. <template #title>
  57. <el-row class="entry-row">
  58. <el-col :span="2">
  59. <div class="node-type">测试</div>
  60. </el-col>
  61. <el-col :span="2">
  62. <template class="entry-row">
  63. <span>#{{detailAPIInfo.testId}}</span>
  64. </template>
  65. </el-col>
  66. <el-col :span="4">
  67. <template class="entry-row">
  68. <span>{{detailAPIInfo.testName}}</span>
  69. </template>
  70. </el-col>
  71. </el-row>
  72. </template>
  73. <template #default>
  74. <el-row type="flex" justify="center">
  75. <el-col :span="20">
  76. <el-tabs
  77. v-model="detailTab">
  78. <el-tab-pane label="基本信息" name="basic_info">
  79. <el-row class="entry-row" style="margin-top: 15px">
  80. <el-col :span="4">
  81. <h4>url: </h4>
  82. </el-col>
  83. <el-col :span="18">
  84. <div>{{detailAPIInfo.url}}</div>
  85. </el-col>
  86. </el-row>
  87. <el-row class="entry-row" style="margin-top: 15px">
  88. <el-col :span="4">
  89. <h4>params: </h4>
  90. </el-col>
  91. <el-col :span="18">
  92. <div>
  93. <vue-json-editor
  94. :height="'400px'"
  95. v-model="detailAPIInfo.params"
  96. :show-btns="false"
  97. :mode="'code'"
  98. :modes="['code']"
  99. lang="zh"></vue-json-editor>
  100. </div>
  101. </el-col>
  102. </el-row>
  103. <el-row class="entry-row" style="margin-top: 15px">
  104. <el-col :span="4">
  105. <h4>method: </h4>
  106. </el-col>
  107. <el-col :span="18">
  108. <div>{{detailAPIInfo.method}}</div>
  109. </el-col>
  110. </el-row>
  111. <el-row class="entry-row" style="margin-top: 15px">
  112. <el-col :span="4">
  113. <h4>qps: </h4>
  114. </el-col>
  115. <el-col :span="18">
  116. <div>{{detailAPIInfo.qps}}</div>
  117. </el-col>
  118. </el-row>
  119. </el-tab-pane>
  120. <el-tab-pane label="执行历史" name="execute_history">
  121. <h5>注:Max、Min、Average的单位均为ms</h5>
  122. <el-table :data="testResults" width="100%">
  123. <el-table-column
  124. prop="id"
  125. label="ID"
  126. align="center"
  127. width="60">
  128. </el-table-column>
  129. <el-table-column
  130. prop="executeTime"
  131. label="执行时间"
  132. align="center">
  133. </el-table-column>
  134. <el-table-column
  135. prop="success"
  136. label="成功"
  137. align="center">
  138. </el-table-column>
  139. <el-table-column
  140. prop="failure"
  141. label="失败"
  142. align="center">
  143. <template #default="scope">
  144. {{scope.row.failure}}
  145. <span v-if="scope.row.success === 0">
  146. <i class="el-icon-warning" title="url/参数有误或者服务器出错!"></i>
  147. </span>
  148. </template>
  149. </el-table-column>
  150. <el-table-column
  151. prop="maxTime"
  152. label="Max"
  153. align="center">
  154. </el-table-column>
  155. <el-table-column
  156. prop="minTime"
  157. label="Min"
  158. align="center">
  159. </el-table-column>
  160. <el-table-column
  161. prop="averageTime"
  162. label="Average"
  163. align="center">
  164. </el-table-column>
  165. </el-table>
  166. </el-tab-pane>
  167. </el-tabs>
  168. </el-col>
  169. </el-row>
  170. </template>
  171. </ElDrawer>
  172. <!-- 新建测试任务 -->
  173. <el-dialog
  174. v-model="showAPITestCreateModel"
  175. width="600px"
  176. :before-close="(done) => {$refs['createAPITestForm'].resetFields();done();}"
  177. destroy-on-close>
  178. <template #title>创建测试任务</template>
  179. <el-form
  180. :model="createAPITestForm"
  181. :rules="rules"
  182. ref="createAPITestForm"
  183. label-position="right"
  184. label-width="100px"
  185. label-suffix=":"
  186. class="create-APITest-form">
  187. <el-form-item label="测试名称" prop="testName" required>
  188. <el-input v-model="createAPITestForm.testName" placeholder="请输入接口测试的名称"></el-input>
  189. </el-form-item>
  190. <el-form-item label="待测URL" prop="url" required>
  191. <el-input v-model="createAPITestForm.url" placeholder="请输入待测试的URL"></el-input>
  192. </el-form-item>
  193. <el-form-item label="参数" prop="params">
  194. <div>
  195. <vue-json-editor
  196. :height="'400px'"
  197. v-model="createAPITestForm.params"
  198. :show-btns="false"
  199. :mode="'code'"
  200. :modes="['code']"
  201. lang="zh"
  202. @json-change="onJsonChange"
  203. @json-save="onJsonSave"
  204. @has-error="onError"
  205. ></vue-json-editor>
  206. <span v-if="!jsonValid" style="color: #F56C6C; font-size: 12px">JSON is invalid.</span>
  207. </div>
  208. </el-form-item>
  209. <el-form-item label="方法" prop="method" required>
  210. <ElSelect v-model="createAPITestForm.method" placeholder="请选择待测URL的方法">
  211. <ElOption
  212. v-for="(method, index) in methodList"
  213. :key="index" :label="method"
  214. :value="method">
  215. </ElOption>
  216. </ElSelect>
  217. </el-form-item>
  218. <el-form-item label="并发数" prop="qps" required="">
  219. <el-input v-model="createAPITestForm.qps" placeholder="请输入并发数(10的倍数)"></el-input>
  220. </el-form-item>
  221. </el-form>
  222. <template #footer>
  223. <span class="dialog-footer">
  224. <el-button type="primary" @click="handleAPITestCreateConfirm">确 定</el-button>
  225. </span>
  226. </template>
  227. </el-dialog>
  228. <ElDrawer
  229. v-model="latestDrawer"
  230. :size="750">
  231. <template #title>
  232. <el-row class="entry-row">
  233. <el-col :span="3">
  234. <div class="node-type">测试结果</div>
  235. </el-col>
  236. <el-col :span="2">
  237. <template class="entry-row">
  238. <span>#{{latestResultInfo.id}}</span>
  239. </template>
  240. </el-col>
  241. </el-row>
  242. </template>
  243. <template #default>
  244. <el-row type="flex" justify="center">
  245. <el-col :span="22">
  246. <el-row class="entry-row" style="margin-top: 15px">
  247. <el-col :span="5">
  248. <h4>执行时间:</h4>
  249. </el-col>
  250. <el-col :span="18">
  251. <div>{{latestResultInfo.executeTime}}</div>
  252. </el-col>
  253. </el-row>
  254. <el-row class="entry-row" style="margin-top: 15px">
  255. <el-col :span="5">
  256. <h4>成功:</h4>
  257. </el-col>
  258. <el-col :span="18">
  259. <div>{{latestResultInfo.success}}</div>
  260. </el-col>
  261. </el-row>
  262. <el-row class="entry-row" style="margin-top: 15px">
  263. <el-col :span="5">
  264. <h4>失败:</h4>
  265. </el-col>
  266. <el-col :span="18">
  267. <div>
  268. {{latestResultInfo.failure}}
  269. <span v-if="latestResultInfo.success === 0" style="color: red">(url/参数输入有误或者服务器出错!)</span>
  270. </div>
  271. </el-col>
  272. </el-row>
  273. <el-row class="entry-row" style="margin-top: 15px">
  274. <el-col :span="5">
  275. <h4>maxTime:</h4>
  276. </el-col>
  277. <el-col :span="18">
  278. <div>{{latestResultInfo.maxTime}} ms</div>
  279. </el-col>
  280. </el-row>
  281. <el-row class="entry-row" style="margin-top: 15px">
  282. <el-col :span="5">
  283. <h4>minTime:</h4>
  284. </el-col>
  285. <el-col :span="18">
  286. <div>{{latestResultInfo.minTime}} ms</div>
  287. </el-col>
  288. </el-row>
  289. <el-row class="entry-row" style="margin-top: 15px">
  290. <el-col :span="5">
  291. <h4>averageTime:</h4>
  292. </el-col>
  293. <el-col :span="18">
  294. <div>{{latestResultInfo.averageTime}} ms</div>
  295. </el-col>
  296. </el-row>
  297. </el-col>
  298. </el-row>
  299. <el-row>
  300. <el-col :span="12">
  301. <div id="chart1" style="height: 500px; width: 350px"></div>
  302. </el-col>
  303. <el-col :span="12">
  304. <div id="chart2" style="height: 500px; width: 350px"></div>
  305. </el-col>
  306. </el-row>
  307. </template>
  308. </ElDrawer>
  309. </ElTabPane>
  310. <ElTabPane label="黑盒测试" name="testCases">
  311. <ElTable :data="testcases" width="100%">
  312. <ElTableColumn
  313. prop="id"
  314. label="ID"
  315. align="center"
  316. width="60">
  317. </ElTableColumn>
  318. <ElTableColumn
  319. prop="title"
  320. label="title"
  321. align="center">
  322. </ElTableColumn>
  323. <ElTableColumn
  324. prop="pass"
  325. label="执行状态"
  326. align="center"
  327. width="100"
  328. :filters="[{ text: '进行中', value: false }, { text: '已完成', value: true }]"
  329. :filter-method="(value, row) => {
  330. return row.pass === value;
  331. }"
  332. filter-placement="bottom-end">
  333. <template #default="scope">
  334. <template v-if="scope.row.pass === false">
  335. <ElTag>进行中<i class="el-icon-loading"></i></ElTag>
  336. </template>
  337. <template v-else-if="scope.row.pass === true">
  338. <ElTag type="success">已完成</ElTag>
  339. </template>
  340. <template v-else>
  341. <ElTag type="warning">未知状态</ElTag>
  342. </template>
  343. </template>
  344. </ElTableColumn>
  345. <ElTableColumn
  346. label="详情"
  347. align="center">
  348. <template #default="scope">
  349. <ElButton
  350. @click="handleTestCasesClick('steps', scope.row.id)"
  351. type="text"
  352. size="small">测试用例步骤列表</ElButton>
  353. </template>
  354. </ElTableColumn>
  355. <ElTableColumn
  356. align="center">
  357. <template #header>
  358. <span>操作</span>
  359. <ElButton
  360. @click="handleTestCasesClick('latest', 0)"
  361. type="text"
  362. class="add-button">部署的历史记录</ElButton>
  363. <ElButton @click="handleTestCasesClick('create')" type="text" class="add-button">新建</ElButton>
  364. </template>
  365. <template #default="scope">
  366. <ElButton v-if="scope.row.pass === false" @click="handleTestCasesClick('finish', scope.row.id)" type="text" size="small">
  367. 完成测试
  368. </ElButton>
  369. <ElButton v-else @click="handleTestCasesClick('finish', scope.row.id)" type="text" size="small" disabled>完成测试</ElButton>
  370. <ElButton v-if="scope.row.pass === true" @click="handleTestCasesClick('reopen', scope.row.id)" type="text" size="small">
  371. 重新开放测试
  372. </ElButton>
  373. <ElButton v-else @click="handleTestCasesClick('reopen', scope.row.id)" type="text" size="small" disabled>重新开放测试</ElButton>
  374. <ElButton @click="handleTestCasesClick('edit', scope.row.id)" type="text" size="small">编辑</ElButton>
  375. <ElButton @click="handleTestCasesClick('delete', scope.row.id)" type="text" size="small">删除</ElButton>
  376. </template>
  377. </ElTableColumn>
  378. </ElTable>
  379. <!-- 部署的历史记录 -->
  380. <ElDrawer
  381. v-model="deployHistoryDrawer"
  382. :size="650">
  383. <template #title>
  384. <el-row class="entry-row">
  385. <el-col :span="3">
  386. <div class="node-type">项目</div>
  387. </el-col>
  388. <el-col :span="2">
  389. <template class="entry-row">
  390. <span>#{{currentProjectId}}</span>
  391. </template>
  392. </el-col>
  393. </el-row>
  394. </template>
  395. <template #default>
  396. <el-row type="flex" justify="center">
  397. <el-col :span="20">
  398. <el-table :data="deployHistoryInfo" width="100%">
  399. <el-table-column
  400. prop="id"
  401. label="ID"
  402. align="center"
  403. width="60">
  404. </el-table-column>
  405. <el-table-column
  406. prop="timestamp"
  407. label="部署时间"
  408. align="center"
  409. width="150">
  410. </el-table-column>
  411. <el-table-column
  412. prop="operationType"
  413. label="操作类型"
  414. align="center">
  415. </el-table-column>
  416. <el-table-column
  417. prop="pipelineRecordId"
  418. label="流水线ID"
  419. align="center"
  420. width="80">
  421. </el-table-column>
  422. </el-table>
  423. </el-col>
  424. </el-row>
  425. </template>
  426. </ElDrawer>
  427. <!-- 新建测试用例 -->
  428. <el-dialog
  429. v-model="showTestCaseCreateModel"
  430. width="600px"
  431. :before-close="(done) => {$refs['createTestCaseForm'].resetFields();done();}"
  432. destroy-on-close>
  433. <template #title>创建测试用例</template>
  434. <el-form
  435. :model="createTestCaseForm"
  436. ref="createTestCaseForm"
  437. label-position="right"
  438. label-width="60px"
  439. label-suffix=":"
  440. class="create-APITest-form">
  441. <el-form-item label="title" prop="title">
  442. <el-input
  443. v-model="createTestCaseForm.title"
  444. type="textarea"
  445. :rows="5"
  446. placeholder="请输入测试用例的标题"></el-input>
  447. </el-form-item>
  448. </el-form>
  449. <template #footer>
  450. <span class="dialog-footer">
  451. <el-button type="primary" @click="handleTestCaseCreateConfirm">确 定</el-button>
  452. </span>
  453. </template>
  454. </el-dialog>
  455. <!-- 测试用例步骤详情 -->
  456. <ElDrawer
  457. v-model="stepsDrawer"
  458. :size="800">
  459. <template #title>
  460. <el-row class="entry-row">
  461. <el-col :span="3">
  462. <div class="node-type">测试用例</div>
  463. </el-col>
  464. <el-col :span="2">
  465. <template class="entry-row">
  466. <span>#{{detailTestCaseInfo.id}}</span>
  467. </template>
  468. </el-col>
  469. <el-col :span="6">
  470. <div>
  471. <ElButton @click="handleSteps('create', detailTestCaseInfo.id, 0)" type="text" class="add-button">新建测试用例步骤</ElButton>
  472. </div>
  473. </el-col>
  474. </el-row>
  475. </template>
  476. <template #default>
  477. <el-row type="flex" justify="center">
  478. <el-col :span="20">
  479. <el-row class="entry-row" style="margin-top: 15px; margin-bottom: 30px">
  480. <el-col :span="2">
  481. <h4>title: </h4>
  482. </el-col>
  483. <el-col :span="18">
  484. <div>{{detailTestCaseInfo.title}}</div>
  485. </el-col>
  486. </el-row>
  487. <el-tabs v-model="stepsTab">
  488. <el-tab-pane label="测试用例步骤" name="steps">
  489. <el-table :data="detailStepsInfo" width="100%">
  490. <el-table-column
  491. prop="id"
  492. label="ID"
  493. align="center"
  494. width="60">
  495. </el-table-column>
  496. <el-table-column
  497. prop="description"
  498. label="描述"
  499. align="center">
  500. </el-table-column>
  501. <el-table-column
  502. prop="expectation"
  503. label="预期输出"
  504. align="center">
  505. </el-table-column>
  506. <el-table-column
  507. prop="state"
  508. label="状态"
  509. align="center">
  510. </el-table-column>
  511. <el-table-column
  512. align="center">
  513. <template #header>
  514. <span>操作</span>
  515. </template>
  516. <template #default="scope">
  517. <ElButton @click="handleSteps('update', scope.row.testCaseId, scope.row.id)" type="text" size="small">更新</ElButton>
  518. <ElButton
  519. @click="handleSteps('updateState', scope.row.testCaseId, scope.row.id)" type="text" size="small">修改状态</ElButton>
  520. <ElButton @click="handleSteps('delete', scope.row.testCaseId, scope.row.id)" type="text" size="small">删除</ElButton>
  521. </template>
  522. </el-table-column>
  523. </el-table>
  524. </el-tab-pane>
  525. </el-tabs>
  526. </el-col>
  527. </el-row>
  528. </template>
  529. </ElDrawer>
  530. <!-- 修改测试用例步骤 -->
  531. <el-dialog
  532. v-model="showUpdateStepModel"
  533. width="600px"
  534. :before-close="(done) => {$refs['updateStepForm'].resetFields();done();}"
  535. destroy-on-close>
  536. <template #title>修改测试用例步骤</template>
  537. <el-form
  538. :model="updateStepForm"
  539. ref="updateStepForm"
  540. label-position="right"
  541. label-width="100px"
  542. label-suffix=":">
  543. <el-form-item label="id" prop="id">
  544. <el-input
  545. v-model="updateStepForm.id"
  546. disabled>
  547. </el-input>
  548. </el-form-item>
  549. <el-form-item label="description" prop="description">
  550. <el-input
  551. v-model="updateStepForm.description"
  552. type="textarea"
  553. :rows="4">
  554. </el-input>
  555. </el-form-item>
  556. <el-form-item label="expectation" prop="expectation">
  557. <el-input
  558. v-model="updateStepForm.expectation"
  559. type="textarea"
  560. :rows="4">
  561. </el-input>
  562. </el-form-item>
  563. </el-form>
  564. <template #footer>
  565. <span class="dialog-footer">
  566. <el-button type="primary" @click="handleStepUpdateConfirm">确 定</el-button>
  567. </span>
  568. </template>
  569. </el-dialog>
  570. <!-- 修改测试用例步骤state -->
  571. <el-dialog
  572. v-model="showUpdateStepStateModel"
  573. width="600px"
  574. :before-close="(done) => {$refs['updateStepForm'].resetFields();done();}"
  575. destroy-on-close>
  576. <template #title>修改测试用例步骤状态</template>
  577. <el-form
  578. :model="updateStepForm"
  579. ref="updateStepForm"
  580. label-position="right"
  581. label-width="100px"
  582. label-suffix=":">
  583. <el-form-item label="id" prop="id">
  584. <el-input
  585. v-model="updateStepForm.id"
  586. disabled>
  587. </el-input>
  588. </el-form-item>
  589. <el-form-item label="state" prop="state">
  590. <ElSelect
  591. v-model="updateStepForm.state">
  592. <ElOption
  593. v-for="(state, index) in stateList"
  594. :key="index"
  595. :label="state"
  596. :value="state">
  597. </ElOption>
  598. </ElSelect>
  599. </el-form-item>
  600. </el-form>
  601. <template #footer>
  602. <span class="dialog-footer">
  603. <el-button type="primary" @click="handleStepUpdateStateConfirm">确 定</el-button>
  604. </span>
  605. </template>
  606. </el-dialog>
  607. <!-- 修改测试用例title -->
  608. <el-dialog
  609. v-model="showEditTestCaseModel"
  610. width="600px"
  611. :before-close="(done) => {$refs['detailTestCaseInfo'].resetFields();done();}"
  612. destroy-on-close>
  613. <template #title>编辑测试用例标题</template>
  614. <el-form
  615. :model="detailTestCaseInfo"
  616. ref="detailTestCaseInfo"
  617. label-position="right"
  618. label-width="100px"
  619. label-suffix=":">
  620. <el-form-item label="id" prop="id">
  621. <el-input
  622. v-model="detailTestCaseInfo.id"
  623. disabled>
  624. </el-input>
  625. </el-form-item>
  626. <el-form-item label="title" prop="title">
  627. <el-input
  628. v-model="detailTestCaseInfo.title"
  629. type="textarea"
  630. :rows="4">
  631. </el-input>
  632. </el-form-item>
  633. </el-form>
  634. <template #footer>
  635. <span class="dialog-footer">
  636. <el-button type="primary" @click="handleTestCaseEditConfirm">确 定</el-button>
  637. </span>
  638. </template>
  639. </el-dialog>
  640. </ElTabPane>
  641. <ElTabPane label="自动化测试" name="autotest">
  642. <ElTable :data="autoTestResult" width="100%">
  643. <ElTableColumn
  644. prop="id"
  645. label="ID"
  646. align="center"
  647. width="60">
  648. </ElTableColumn>
  649. <ElTableColumn
  650. prop="testId"
  651. label="所属测试ID"
  652. align="center"
  653. width="120">
  654. </ElTableColumn>
  655. <ElTableColumn
  656. prop="executeTime"
  657. label="执行时间"
  658. align="center"
  659. width="250">
  660. </ElTableColumn>
  661. <ElTableColumn
  662. prop="timeList"
  663. label="执行时间列表"
  664. align="center">
  665. </ElTableColumn>
  666. <ElTableColumn
  667. prop="success"
  668. label="success"
  669. align="center"
  670. width="100">
  671. </ElTableColumn>
  672. <ElTableColumn
  673. prop="failure"
  674. label="failure"
  675. align="center"
  676. width="100">
  677. </ElTableColumn>
  678. <ElTableColumn
  679. prop="maxTime"
  680. label="Max"
  681. align="center"
  682. width="100">
  683. </ElTableColumn>
  684. <ElTableColumn
  685. prop="minTime"
  686. label="Min"
  687. align="center"
  688. width="100">
  689. </ElTableColumn>
  690. <ElTableColumn
  691. prop="averageTime"
  692. label="Average"
  693. align="center"
  694. width="100">
  695. </ElTableColumn>
  696. <ElTableColumn
  697. prop="pipelineRecordId"
  698. label="流水线ID"
  699. align="center"
  700. width="100">
  701. </ElTableColumn>
  702. </ElTable>
  703. </ElTabPane>
  704. </ElTabs>
  705. </template>
  706. <script>
  707. import vueJsonEditor from 'vue-json-editor';
  708. import { APITestAPI, FuncTestAPI, AutoTestAPI } from '@/api';
  709. import { ElMessage } from 'element-plus';
  710. import * as echarts from 'echarts';
  711. export default {
  712. components: {
  713. vueJsonEditor,
  714. },
  715. data() {
  716. return {
  717. currentProjectId: -1,
  718. activeTab: 'apitest',
  719. apitests: [],
  720. detailDrawer: false,
  721. detailAPIInfo: [],
  722. detailTab: 'basic_info',
  723. testResults: [],
  724. showAPITestCreateModel: false,
  725. createAPITestForm: {
  726. testName: '',
  727. url: '',
  728. params: {},
  729. method: '',
  730. qps: '',
  731. createTime: '',
  732. username: '',
  733. },
  734. methodList: ['GET', 'POST'],
  735. jsonValid: true,
  736. latestDrawer: false,
  737. latestResultInfo: {},
  738. qps: 0,
  739. timer: null,
  740. testcases: [],
  741. showTestCaseCreateModel: false,
  742. createTestCaseForm: {
  743. projectId: -1,
  744. title: '',
  745. },
  746. stepsDrawer: false,
  747. detailTestCaseInfo: [],
  748. stepsTab: 'steps',
  749. detailStepsInfo: {},
  750. showUpdateStepModel: false,
  751. updateStepForm: {},
  752. showEditTestCaseModel: false,
  753. stateList: ['待测试', '已测试', '出现bug'],
  754. showUpdateStepStateModel: false,
  755. deployHistoryInfo: {},
  756. deployHistoryDrawer: false,
  757. autoTestResult: [],
  758. };
  759. },
  760. async mounted() {
  761. this.currentProjectId = this.$store.state.workspace.currentProjectId;
  762. this.apitests = await APITestAPI.getAPITestInfosByProjectId(this.$store.state.workspace.currentProjectId);
  763. this.testcases = await FuncTestAPI.getTestCases(this.$store.state.workspace.currentProjectId);
  764. this.autoTestResult = await AutoTestAPI.getAutoTestResultByProjectId(this.$store.state.workspace.currentProjectId);
  765. },
  766. methods: {
  767. async handleClick(action, id) {
  768. switch (action) {
  769. case 'create': {
  770. this.showAPITestCreateModel = true;
  771. break;
  772. }
  773. case 'latest': {
  774. this.latestResultInfo = await APITestAPI.getLatestResultByTestId(id);
  775. if (this.latestResultInfo === null) {
  776. ElMessage.error('还未执行!');
  777. } else {
  778. this.apitests.forEach((item) => {
  779. if (item.testId === id) {
  780. this.qps = item.qps;
  781. }
  782. });
  783. this.latestDrawer = true;
  784. const that = this;
  785. this.timer = setTimeout(() => {
  786. this.$nextTick(() => {
  787. that.initChart1();
  788. that.initChart2();
  789. });
  790. }, 1500);
  791. }
  792. break;
  793. }
  794. case 'detail': {
  795. this.apitests.forEach((item) => {
  796. if (item.testId === id) {
  797. this.detailAPIInfo = item;
  798. }
  799. });
  800. this.testResults = await APITestAPI.getAPITestResultByTestId(id);
  801. this.detailDrawer = true;
  802. break;
  803. }
  804. case 'trigger': {
  805. await APITestAPI.executeAPITestByTestId(id);
  806. break;
  807. }
  808. case 'delete': {
  809. await APITestAPI.deleteAPITestByTestId(id);
  810. ElMessage.success('删除成功!');
  811. this.apitests = await APITestAPI.getAPITestInfosByProjectId(this.$store.state.workspace.currentProjectId);
  812. break;
  813. }
  814. default: {
  815. console.warn('Unknown type of action.');
  816. }
  817. }
  818. },
  819. onJsonChange(value) {
  820. this.onJsonSave(value);
  821. },
  822. onJsonSave(value) {
  823. this.createAPITestForm.params = value;
  824. console.log(this.createAPITestForm.params);
  825. this.jsonValid = true;
  826. },
  827. onError(value) {
  828. this.jsonValid = false;
  829. },
  830. async handleAPITestCreateConfirm() {
  831. this.$refs.createAPITestForm.validate(async (valid) => {
  832. if (valid) {
  833. this.createAPITestForm.createTime = this.getCurrentTime();
  834. await APITestAPI.createAPITest({
  835. projectId: this.$store.state.workspace.currentProjectId,
  836. createTime: this.createAPITestForm.createTime,
  837. username: this.$store.state.user.username,
  838. testName: this.createAPITestForm.testName,
  839. url: this.createAPITestForm.url,
  840. params: this.createAPITestForm.params,
  841. method: this.createAPITestForm.method,
  842. qps: this.createAPITestForm.qps,
  843. });
  844. this.apitests = await APITestAPI.getAPITestInfosByProjectId(this.$store.state.workspace.currentProjectId);
  845. this.$refs.createAPITestForm.resetFields();
  846. this.showAPITestCreateModel = false;
  847. ElMessage.success('创建成功!');
  848. }
  849. });
  850. },
  851. getCurrentTime() {
  852. const yy = new Date().getFullYear();
  853. const mm = new Date().getMonth() + 1;
  854. const dd = new Date().getDate();
  855. const hh = new Date().getHours();
  856. const mf = new Date().getMinutes() < 10 ? `0${new Date().getMinutes()}` : new Date().getMinutes();
  857. const ss = new Date().getSeconds() < 10 ? `0${new Date().getSeconds()}` : new Date().getSeconds();
  858. return `${yy}-${mm}-${dd} ${hh}:${mf}:${ss}`;
  859. },
  860. async initChart1() {
  861. const chart1 = echarts.init(document.getElementById('chart1'));
  862. const options1 = {
  863. title: {
  864. text: `并发数: ${this.qps}`,
  865. x: 'center',
  866. y: 'center',
  867. textStyle: {
  868. fontSize: 16,
  869. },
  870. },
  871. tooltip: {
  872. trigger: 'item',
  873. },
  874. series: [
  875. {
  876. type: 'pie',
  877. radius: ['40%', '50%'],
  878. clockwise: true,
  879. avoidLabelOverlap: true,
  880. hoverOffset: 15,
  881. data: [
  882. { value: this.latestResultInfo.success, name: '成功', itemStyle: { color: '#CCFF99' } },
  883. { value: this.latestResultInfo.failure, name: '失败', itemStyle: { color: '#FF6600' } },
  884. ],
  885. },
  886. ],
  887. };
  888. chart1.setOption(options1);
  889. },
  890. async initChart2() {
  891. const chart2 = echarts.init(document.getElementById('chart2'));
  892. const option2 = {
  893. title: {
  894. text: '访问时间曲线图',
  895. bottom: '5%',
  896. left: 'center',
  897. },
  898. tooltip: {
  899. trigger: 'trigger',
  900. axisPointer: {
  901. type: 'cross',
  902. label: {
  903. backgroundColor: '#6a7985',
  904. },
  905. },
  906. },
  907. xAxis: [
  908. {
  909. type: 'category',
  910. boundaryGap: false,
  911. },
  912. ],
  913. yAxis: [
  914. {
  915. name: '执行时间/单位ms',
  916. type: 'value',
  917. min: 'dataMin',
  918. max: 'dataMax',
  919. },
  920. ],
  921. series: [
  922. {
  923. name: '访问时间',
  924. data: this.latestResultInfo.timeList,
  925. type: 'line',
  926. smooth: true,
  927. showSymbol: true,
  928. symbolSize: 3,
  929. symbol: 'circle',
  930. itemStyle: { color: '#8D67FF' },
  931. markPoint: {
  932. data: [
  933. { type: 'max', name: '最大值' },
  934. { type: 'min', name: '最小值' },
  935. ],
  936. },
  937. markLine: {
  938. data: [
  939. { type: 'average', name: '平均值' },
  940. ],
  941. },
  942. },
  943. ],
  944. };
  945. chart2.setOption(option2);
  946. },
  947. async handleTestCasesClick(action, id) {
  948. switch (action) {
  949. case 'create': {
  950. this.showTestCaseCreateModel = true;
  951. break;
  952. }
  953. case 'latest': {
  954. this.deployHistoryInfo = await FuncTestAPI.getLatestRecord(this.$store.state.workspace.currentProjectId);
  955. console.log(this.deployHistoryInfo);
  956. this.deployHistoryDrawer = true;
  957. break;
  958. }
  959. case 'finish': {
  960. await FuncTestAPI.finishTestCase(id);
  961. this.testcases = await FuncTestAPI.getTestCases(this.$store.state.workspace.currentProjectId);
  962. break;
  963. }
  964. case 'reopen': {
  965. await FuncTestAPI.reopenTestCase(id);
  966. this.testcases = await FuncTestAPI.getTestCases(this.$store.state.workspace.currentProjectId);
  967. break;
  968. }
  969. case 'edit': {
  970. this.testcases.forEach((item) => {
  971. if (item.id === id) {
  972. this.detailTestCaseInfo = item;
  973. }
  974. });
  975. this.showEditTestCaseModel = true;
  976. break;
  977. }
  978. case 'delete': {
  979. await FuncTestAPI.deleteTestCase(id);
  980. ElMessage.success('删除成功!');
  981. this.testcases = await FuncTestAPI.getTestCases(this.$store.state.workspace.currentProjectId);
  982. break;
  983. }
  984. case 'steps': {
  985. this.testcases.forEach((item) => {
  986. if (item.id === id) {
  987. this.detailTestCaseInfo = item;
  988. }
  989. });
  990. this.detailStepsInfo = await FuncTestAPI.getTestCaseSteps(id);
  991. this.stepsDrawer = true;
  992. break;
  993. }
  994. default: {
  995. console.warn('Unknown type of action.');
  996. }
  997. }
  998. },
  999. async handleTestCaseCreateConfirm() {
  1000. this.$refs.createTestCaseForm.validate(async (valid) => {
  1001. if (valid) {
  1002. this.createTestCaseForm.projectId = this.$store.state.workspace.currentProjectId;
  1003. await FuncTestAPI.createTestCase(this.createTestCaseForm.projectId, this.createTestCaseForm.title);
  1004. this.testcases = await FuncTestAPI.getTestCases(this.$store.state.workspace.currentProjectId);
  1005. this.$refs.createTestCaseForm.resetFields();
  1006. this.showTestCaseCreateModel = false;
  1007. ElMessage.success('创建成功!');
  1008. }
  1009. });
  1010. },
  1011. async handleSteps(action, caseId, stepId) {
  1012. switch (action) {
  1013. case 'create': {
  1014. await FuncTestAPI.createTestCaseStep(caseId);
  1015. ElMessage.success('创建成功!');
  1016. this.detailStepsInfo = await FuncTestAPI.getTestCaseSteps(caseId);
  1017. break;
  1018. }
  1019. case 'delete': {
  1020. await FuncTestAPI.deleteTestCaseStep(stepId);
  1021. ElMessage.success('删除成功!');
  1022. this.detailStepsInfo = await FuncTestAPI.getTestCaseSteps(caseId);
  1023. break;
  1024. }
  1025. case 'update': {
  1026. this.showUpdateStepModel = true;
  1027. this.detailStepsInfo.forEach((item) => {
  1028. if (item.id === stepId) {
  1029. this.updateStepForm = item;
  1030. }
  1031. });
  1032. break;
  1033. }
  1034. case 'updateState': {
  1035. this.showUpdateStepStateModel = true;
  1036. this.detailStepsInfo.forEach((item) => {
  1037. if (item.id === stepId) {
  1038. this.updateStepForm = item;
  1039. }
  1040. });
  1041. break;
  1042. }
  1043. default: {
  1044. console.warn('Unknown type of action.');
  1045. }
  1046. }
  1047. },
  1048. async handleStepUpdateConfirm() {
  1049. this.$refs.updateStepForm.validate(async (valid) => {
  1050. if (valid) {
  1051. await FuncTestAPI.updateTestCaseStep(this.updateStepForm.id, this.updateStepForm.description, this.updateStepForm.expectation);
  1052. this.detailStepsInfo = await FuncTestAPI.getTestCaseSteps(this.updateStepForm.testCaseId);
  1053. this.$refs.updateStepForm.resetFields();
  1054. this.showUpdateStepModel = false;
  1055. ElMessage.success('修改成功!');
  1056. }
  1057. });
  1058. },
  1059. async handleStepUpdateStateConfirm() {
  1060. this.$refs.updateStepForm.validate(async (valid) => {
  1061. if (valid) {
  1062. let state;
  1063. if (this.updateStepForm.state === '待测试') {
  1064. state = 'WAITING';
  1065. } else if (this.updateStepForm.state === '已测试') {
  1066. state = 'PASS';
  1067. } else if (this.updateStepForm.state === '出现bug') {
  1068. state = 'BUG';
  1069. }
  1070. await FuncTestAPI.updateTestCaseStepState(this.updateStepForm.id, state);
  1071. this.detailStepsInfo = await FuncTestAPI.getTestCaseSteps(this.updateStepForm.testCaseId);
  1072. this.$refs.updateStepForm.resetFields();
  1073. this.showUpdateStepStateModel = false;
  1074. ElMessage.success('修改成功!');
  1075. }
  1076. });
  1077. },
  1078. async handleTestCaseEditConfirm() {
  1079. this.$refs.detailTestCaseInfo.validate(async (valid) => {
  1080. if (valid) {
  1081. await FuncTestAPI.updateTestCase(this.detailTestCaseInfo.id, this.detailTestCaseInfo.title);
  1082. this.testcases = await FuncTestAPI.getTestCases(this.$store.state.workspace.currentProjectId);
  1083. this.$refs.detailTestCaseInfo.resetFields();
  1084. this.showEditTestCaseModel = false;
  1085. ElMessage.success('修改成功!');
  1086. }
  1087. });
  1088. },
  1089. },
  1090. };
  1091. </script>
  1092. <style lang="scss" scoped>
  1093. .tabs {
  1094. width: 80%;
  1095. margin: auto auto;
  1096. }
  1097. .add-button {
  1098. margin-left: 14px;
  1099. }
  1100. .entry-row {
  1101. width: 100%;
  1102. margin: 3px 20px;
  1103. display: flex;
  1104. flex-direction: row;
  1105. align-items: center;
  1106. justify-content: flex-start;
  1107. h3, h4{
  1108. color: #172b4d;
  1109. }
  1110. }
  1111. .node-type{
  1112. color: #FFFFFF;
  1113. border-radius: 3px;
  1114. font-size: 14px;
  1115. background-color: #42b983;
  1116. text-align: center;
  1117. }
  1118. .create-APITest-form {
  1119. width: 80%;
  1120. margin: 0 auto;
  1121. }
  1122. </style>