BuildDeploy.vue 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016
  1. <template>
  2. <el-container>
  3. <el-header height="220">
  4. <h3>构建部署列表</h3>
  5. <el-row style="margin-top: 10px">
  6. <el-select
  7. v-model="queryInfo.env"
  8. placeholder="环境"
  9. style="margin-left: 5px; width: 10%"
  10. @change="onSelectChange"
  11. >
  12. <el-option
  13. v-for="(item, index) in envList"
  14. :key="index"
  15. :label="item.label"
  16. :value="item.value"
  17. />
  18. </el-select>
  19. <el-select
  20. v-model="queryInfo.appType"
  21. placeholder="类型"
  22. style="margin-left: 5px; width: 10%"
  23. @change="onSelectChange"
  24. >
  25. <el-option
  26. v-for="(item, index) in appTypeList"
  27. :key="index"
  28. :label="item.label"
  29. :value="item.value"
  30. />
  31. </el-select>
  32. <el-input
  33. v-model="queryInfo.appId"
  34. style="margin :5px; width: 20%"
  35. clearable
  36. placeholder="输入应用名(回车搜索)"
  37. @clear="onClear"
  38. @keyup.enter.native="onSearch"
  39. />
  40. <!-- <el-button type="success" icon="el-icon-search" style="margin-left: 5px" @click="onSearch">查询</el-button>-->
  41. <el-button type="text" style="margin-left: 5px" @click="onRefresh">刷新</el-button>
  42. <el-button type="text" style="margin-left: 5px" @click="handleBuildTask">构建任务</el-button>
  43. </el-row>
  44. </el-header>
  45. <el-main>
  46. <el-table
  47. :data="dataList"
  48. border
  49. height="480"
  50. style="width: 100%"
  51. >
  52. <el-table-column
  53. fixed="left"
  54. label="No"
  55. type="index"
  56. />
  57. <el-table-column
  58. prop="appId"
  59. label="应用 ID"
  60. >
  61. <template slot-scope="scope">
  62. <el-button type="text" @click="handleAppDetail(scope.row)">
  63. {{ scope.row.appId }}
  64. </el-button>
  65. </template>
  66. </el-table-column>
  67. <el-table-column
  68. prop="repoBranch"
  69. label="分支"
  70. />
  71. <el-table-column
  72. prop="httpPort"
  73. label="监听端口"
  74. />
  75. <el-table-column
  76. prop="commitId"
  77. label="当前版本"
  78. />
  79. <el-table-column
  80. prop="commitTime"
  81. label="提交时间"
  82. />
  83. <el-table-column
  84. prop="buildTime"
  85. label="构建时间"
  86. />
  87. <el-table-column
  88. prop="buildResult"
  89. label="构建结果"
  90. >
  91. <template slot-scope="scope">
  92. <el-popover
  93. placement="bottom"
  94. title="构建进度"
  95. width="300"
  96. trigger="hover"
  97. >
  98. <el-steps
  99. :active="getCurrentStepIndex(scope.row.steps)"
  100. finish-status="success"
  101. direction="vertical"
  102. space="50px"
  103. >
  104. <el-step
  105. v-for="step in scope.row.steps"
  106. :key="step.stepName"
  107. :title="step.stepName"
  108. :description="getStepDesc(step)"
  109. :status="getStepStatus(step.status)"
  110. />
  111. </el-steps>
  112. <el-button
  113. v-if="scope.row.buildResult.code !== 4"
  114. slot="reference"
  115. type="text"
  116. :style="{ color: scope.row.buildResult.color, fontWeight: 'bold' }"
  117. >
  118. <i v-if="scope.row.buildResult.code === 2" class="el-icon-loading" />
  119. {{ scope.row.buildResult.desc }}
  120. </el-button>
  121. <el-button
  122. v-else
  123. slot="reference"
  124. type="text"
  125. :style="{ color: scope.row.buildResult.color, fontWeight: 'bold' }"
  126. @click="handleBuildResult(scope.row)"
  127. >
  128. {{ scope.row.buildResult.desc }}
  129. </el-button>
  130. </el-popover>
  131. </template>
  132. </el-table-column>
  133. <el-table-column
  134. prop="buildBy"
  135. label="操作用户"
  136. />
  137. <el-table-column
  138. fixed="right"
  139. label="操作"
  140. width="280"
  141. >
  142. <template slot-scope="scope">
  143. <el-button
  144. style="margin-top: 5px; margin-left: 5px"
  145. size="mini"
  146. @click="handleUpdateApp(scope.$index, scope.row)"
  147. >更新</el-button>
  148. <el-button
  149. style="margin-top: 5px; margin-left: 5px"
  150. size="mini"
  151. @click="handleBuildApp(scope.$index, scope.row)"
  152. >构建</el-button>
  153. <el-button
  154. style="margin-top: 5px; margin-left: 5px"
  155. size="mini"
  156. @click="handleDeployList(scope.$index, scope.row)"
  157. >部署列表</el-button>
  158. <el-button
  159. style="margin-top: 5px; margin-left: 5px"
  160. size="mini"
  161. @click="handleBuildLog(scope.$index, scope.row)"
  162. >构建历史</el-button>
  163. </template>
  164. </el-table-column>
  165. </el-table>
  166. <el-pagination
  167. background
  168. :small="screenWidth <= 768"
  169. layout="prev, pager, next"
  170. :page-size="pageSize"
  171. :current-page="currentPage"
  172. :total="totalSize"
  173. @current-change="handleCurrentChange"
  174. @prev-click="handleCurrentChange"
  175. @next-click="handleCurrentChange"
  176. />
  177. </el-main>
  178. <el-dialog
  179. title="构建任务"
  180. append-to-body
  181. :visible.sync="showTaskDialog"
  182. center
  183. >
  184. <template>
  185. <el-table
  186. :data="buildTaskList"
  187. border
  188. height="480"
  189. style="width: 100%"
  190. >
  191. <el-table-column
  192. prop="appId"
  193. label="应用"
  194. />
  195. <el-table-column
  196. prop="status"
  197. label="状态"
  198. />
  199. <el-table-column
  200. prop="waitTime"
  201. label="等待时间(秒)"
  202. />
  203. <el-table-column
  204. fixed="right"
  205. label="操作"
  206. width="280"
  207. >
  208. <template slot-scope="scope">
  209. <el-button
  210. style="margin-top: 5px; margin-left: 5px"
  211. size="mini"
  212. @click="cancelTask(scope.$index, scope.row)"
  213. >取消</el-button>
  214. </template>
  215. </el-table-column>
  216. </el-table>
  217. </template>
  218. </el-dialog>
  219. <el-dialog
  220. :title="deployDialogTitle"
  221. append-to-body
  222. :visible.sync="showDeployDialog"
  223. width="70%"
  224. center
  225. >
  226. <template>
  227. <el-table
  228. :data="deployList"
  229. border
  230. height="480"
  231. style="width: 100%"
  232. >
  233. <el-table-column
  234. fixed="left"
  235. label="No"
  236. type="index"
  237. />
  238. <el-table-column
  239. prop="machineIpv4"
  240. label="机器地址"
  241. />
  242. <el-table-column
  243. prop="machineStatus"
  244. label="机器状态"
  245. >
  246. <template slot-scope="scope">
  247. <el-button
  248. v-if="scope.row.machineStatus === 'Online'"
  249. type="text"
  250. >
  251. <span style="color: green">{{ scope.row.machineStatus }}</span>
  252. </el-button>
  253. <el-button
  254. v-else
  255. type="text"
  256. >
  257. <span style="color: red">{{ scope.row.machineStatus }}</span>
  258. </el-button>
  259. </template>
  260. </el-table-column>
  261. <el-table-column
  262. prop="commitId"
  263. label="当前版本"
  264. />
  265. <el-table-column
  266. prop="packagePath"
  267. label="包路径"
  268. />
  269. <el-table-column
  270. prop="deployBy"
  271. label="部署用户"
  272. />
  273. <el-table-column
  274. prop="deployTime"
  275. label="部署时间"
  276. />
  277. <el-table-column
  278. prop="deployResult"
  279. label="部署结果"
  280. >
  281. <template slot-scope="scope">
  282. <el-popover
  283. placement="bottom"
  284. title="部署进度"
  285. width="300"
  286. trigger="hover"
  287. >
  288. <el-steps
  289. :active="getCurrentStepIndex(scope.row.steps)"
  290. finish-status="success"
  291. direction="vertical"
  292. space="50px"
  293. >
  294. <el-step
  295. v-for="step in scope.row.steps"
  296. :key="step.stepName"
  297. :title="step.stepName"
  298. :description="getStepDesc(step)"
  299. :status="getStepStatus(step.status)"
  300. />
  301. </el-steps>
  302. <el-button
  303. slot="reference"
  304. type="text"
  305. :style="{ color: scope.row.deployResult.color, fontWeight: 'bold' }"
  306. >
  307. <i v-if="scope.row.deployResult.code === 2" class="el-icon-loading" />
  308. {{ scope.row.deployResult.desc }}
  309. </el-button>
  310. </el-popover>
  311. </template>
  312. </el-table-column>
  313. <el-table-column
  314. fixed="right"
  315. label="操作"
  316. width="280"
  317. >
  318. <template slot-scope="scope">
  319. <el-button
  320. style="margin-top: 5px; margin-left: 5px"
  321. size="mini"
  322. @click="handleDeployApp(scope.row)"
  323. >部署</el-button>
  324. <el-button
  325. style="margin-top: 5px; margin-left: 5px"
  326. size="mini"
  327. @click="handleDeployLog(scope.row)"
  328. >部署日志</el-button>
  329. </template>
  330. </el-table-column>
  331. </el-table>
  332. </template>
  333. </el-dialog>
  334. <el-dialog
  335. :title="buildLogDialogTitle"
  336. append-to-body
  337. :visible.sync="showBuildLogDialog"
  338. width="100%"
  339. center
  340. >
  341. <template>
  342. <el-table
  343. :data="dataList1"
  344. border
  345. height="480"
  346. style="width: 100%"
  347. >
  348. <el-table-column
  349. prop="branch"
  350. label="分支"
  351. />
  352. <el-table-column
  353. prop="commitId"
  354. label="版本 ID"
  355. />
  356. <el-table-column
  357. prop="buildTime"
  358. label="构建时间"
  359. />
  360. <el-table-column
  361. prop="buildResult"
  362. label="构建结果"
  363. >
  364. <template slot-scope="scope">
  365. <el-button
  366. v-if="scope.row.buildResult.code !== 4"
  367. slot="reference"
  368. type="text"
  369. :style="{ color: scope.row.buildResult.color, fontWeight: 'bold' }"
  370. >
  371. <i v-if="scope.row.buildResult.code === 2" class="el-icon-loading" />
  372. {{ scope.row.buildResult.desc }}
  373. </el-button>
  374. <el-button
  375. v-else
  376. slot="reference"
  377. type="text"
  378. :style="{ color: scope.row.buildResult.color, fontWeight: 'bold' }"
  379. @click="handleBuildResult(scope.row)"
  380. >
  381. {{ scope.row.buildResult.desc }}
  382. </el-button>
  383. </template>
  384. </el-table-column>
  385. <el-table-column
  386. prop="buildBy"
  387. label="部署用户"
  388. />
  389. <el-table-column
  390. prop="packagePath"
  391. label="包路径"
  392. />
  393. <el-table-column
  394. prop="commitId"
  395. label="构建配置快照"
  396. >
  397. <template slot-scope="scope">
  398. <el-button
  399. size="mini"
  400. type="success"
  401. @click="handleBuildConfig(scope.$index, scope.row)"
  402. >查看</el-button>
  403. </template>
  404. </el-table-column>
  405. <el-table-column
  406. prop="commitTime"
  407. label="构建耗时"
  408. >
  409. <template slot-scope="scope">
  410. <el-button
  411. size="mini"
  412. type="success"
  413. @click="handleBuildConsumed(scope.$index, scope.row)"
  414. >查看</el-button>
  415. </template>
  416. </el-table-column>
  417. <el-table-column
  418. fixed="right"
  419. label="操作"
  420. width="280"
  421. >
  422. <template slot-scope="scope">
  423. <el-button
  424. style="margin-top: 5px; margin-left: 5px"
  425. size="mini"
  426. @click="handleBuildLogFile(scope.row)"
  427. >日志</el-button>
  428. <el-button
  429. style="margin-top: 5px; margin-left: 5px"
  430. size="mini"
  431. @click="handleDeployBuild(scope.$index, scope.row)"
  432. >部署</el-button>
  433. <el-button
  434. style="margin-top: 5px; margin-left: 5px"
  435. size="mini"
  436. @click="handleBuildPackage(scope.$index, scope.row)"
  437. >下载</el-button>
  438. <el-button
  439. style="margin-top: 5px; margin-left: 5px"
  440. size="mini"
  441. @click="handleDeleteBuildLog(scope.$index, scope.row)"
  442. >删除</el-button>
  443. </template>
  444. </el-table-column>
  445. </el-table>
  446. <el-pagination
  447. background
  448. :small="screenWidth <= 768"
  449. layout="prev, pager, next"
  450. :page-size="pageSize1"
  451. :current-page="currentPage1"
  452. :total="totalSize1"
  453. @current-change="handleCurrentChange1"
  454. @prev-click="handleCurrentChange1"
  455. @next-click="handleCurrentChange1"
  456. />
  457. </template>
  458. </el-dialog>
  459. <el-dialog
  460. title="应用详情"
  461. append-to-body
  462. :visible.sync="showAppDialog"
  463. width="100%"
  464. center
  465. >
  466. <template>
  467. </template>
  468. </el-dialog>
  469. <el-dialog
  470. title="构建结果"
  471. append-to-body
  472. :visible.sync="showResultDialog"
  473. width="100%"
  474. center
  475. >
  476. <template>
  477. <span v-html="buildResult" />
  478. </template>
  479. </el-dialog>
  480. <el-dialog
  481. title="构建配置快照"
  482. append-to-body
  483. :visible.sync="showSnapshotDialog"
  484. center
  485. >
  486. <template>
  487. <div v-if="buildConfigSnapshot !== null">
  488. <h3>仓库配置</h3>
  489. <el-descriptions direction="vertical" :column="3" border>
  490. <el-descriptions-item>
  491. <template slot="label">
  492. <i class="el-icon-mobile-phone" />
  493. 仓库认证
  494. </template>
  495. {{ buildConfigSnapshot.repoType }}
  496. </el-descriptions-item>
  497. <el-descriptions-item>
  498. <template slot="label">
  499. <i class="el-icon-location-outline" />
  500. 认证名字
  501. </template>
  502. {{ buildConfigSnapshot.repoName }}
  503. </el-descriptions-item>
  504. <el-descriptions-item>
  505. <template slot="label">
  506. <i class="el-icon-tickets" />
  507. 认证类型
  508. </template>
  509. {{ buildConfigSnapshot.repoAuthType }}
  510. </el-descriptions-item>
  511. </el-descriptions>
  512. <h3>编译配置</h3>
  513. <el-descriptions direction="vertical" :column="3" border>
  514. <el-descriptions-item>
  515. <template slot="label">
  516. <i class="el-icon-mobile-phone" />
  517. 编译器类型
  518. </template>
  519. {{ buildConfigSnapshot.compileType }}
  520. </el-descriptions-item>
  521. <el-descriptions-item>
  522. <template slot="label">
  523. <i class="el-icon-location-outline" />
  524. 编译名字
  525. </template>
  526. {{ buildConfigSnapshot.compileName }}
  527. </el-descriptions-item>
  528. <el-descriptions-item>
  529. <template slot="label">
  530. <i class="el-icon-tickets" />
  531. 编译命令
  532. </template>
  533. {{ buildConfigSnapshot.compileScript }}
  534. </el-descriptions-item>
  535. </el-descriptions>
  536. <h3>打包配置</h3>
  537. <el-descriptions direction="vertical" :column="4" border>
  538. <el-descriptions-item>
  539. <template slot="label">
  540. <i class="el-icon-mobile-phone" />
  541. 打包类型
  542. </template>
  543. {{ buildConfigSnapshot.packType }}
  544. </el-descriptions-item>
  545. <el-descriptions-item>
  546. <template slot="label">
  547. <i class="el-icon-location-outline" />
  548. 打包名字
  549. </template>
  550. {{ buildConfigSnapshot.packName }}
  551. </el-descriptions-item>
  552. <el-descriptions-item>
  553. <template slot="label">
  554. <i class="el-icon-tickets" />
  555. 打包路径
  556. </template>
  557. {{ buildConfigSnapshot.targetPath }}
  558. </el-descriptions-item>
  559. <el-descriptions-item>
  560. <template slot="label">
  561. <i class="el-icon-office-building" />
  562. Dockerfile
  563. </template>
  564. {{ buildConfigSnapshot.dockerfile }}
  565. </el-descriptions-item>
  566. </el-descriptions>
  567. </div>
  568. </template>
  569. </el-dialog>
  570. <el-dialog
  571. title="构建耗时"
  572. append-to-body
  573. :visible.sync="showConsumedDialog"
  574. center
  575. >
  576. <template>
  577. <div v-if="buildConsumed !== null" style="margin-bottom: 20px;">
  578. <el-row :gutter="20">
  579. <el-col :span="6">
  580. <el-statistic title="总构建耗时" :value="buildConsumed.totalDurationSeconds" suffix="秒" />
  581. </el-col>
  582. <el-col :span="18">
  583. <el-tag
  584. v-for="(time, name) in buildConsumed.stepDurations"
  585. :key="name"
  586. style="margin-right: 10px"
  587. >
  588. {{ name }}: {{ time }}s
  589. </el-tag>
  590. </el-col>
  591. </el-row>
  592. </div>
  593. </template>
  594. </el-dialog>
  595. <el-dialog
  596. title="构建日志"
  597. width="100%"
  598. append-to-body
  599. :visible.sync="showBuildLogFileDialog"
  600. center
  601. >
  602. <template>
  603. <div v-if="buildLogFile !== null" style="margin-bottom: 20px;">
  604. <span v-html="buildLogFile" />
  605. </div>
  606. </template>
  607. </el-dialog>
  608. </el-container>
  609. </template>
  610. <script>
  611. import {
  612. buildApp,
  613. cancelBuildTask, deleteBuildLog, deployApp, getBuildConfigSnapshot, getBuildConsumed,
  614. getBuildDeployList, getBuildLogFile,
  615. getBuildLogList, getBuildPackageUrl, getBuildResult,
  616. getBuildTaskList,
  617. getDeployList,
  618. getEnvList,
  619. updateApp
  620. } from '@/api/devops'
  621. export default {
  622. name: 'BuildDeploy',
  623. data() {
  624. return {
  625. envList: [],
  626. appTypeList: [],
  627. queryInfo: {
  628. env: 'test',
  629. appType: '',
  630. appId: '',
  631. pn: 1
  632. },
  633. // 屏幕宽度, 为了控制分页条的大小
  634. screenWidth: document.body.clientWidth,
  635. currentPage: 1,
  636. pageSize: 10,
  637. totalSize: 0,
  638. dataList: [],
  639. // **********************************************************************
  640. showTaskDialog: null,
  641. buildTaskList: [],
  642. // **********************************************************************
  643. buildLogDialogTitle: '',
  644. showBuildLogDialog: false,
  645. queryInfo1: {
  646. appId: '',
  647. pn: 1
  648. },
  649. currentPage1: 1,
  650. pageSize1: 10,
  651. totalSize1: 0,
  652. dataList1: [],
  653. showAppDialog: false,
  654. showResultDialog: false,
  655. buildResult: null,
  656. showSnapshotDialog: false,
  657. buildConfigSnapshot: null,
  658. showConsumedDialog: false,
  659. buildConsumed: null,
  660. showBuildLogFileDialog: false,
  661. buildLogFile: null,
  662. // **********************************************************************
  663. deployDialogTitle: '',
  664. showDeployDialog: false,
  665. deployList: [],
  666. deployForm: {
  667. appId: null,
  668. buildLogId: null,
  669. machineId: null
  670. }
  671. }
  672. },
  673. created() {
  674. getEnvList().then(resp => {
  675. if (resp.code === 0) {
  676. this.queryInfo.env = resp.data.userEnv
  677. this.queryInfo.appType = resp.data.userAppType
  678. this.envList = resp.data.envList
  679. this.appTypeList = resp.data.appTypeList
  680. const env = this.$route.query.env
  681. if (env !== undefined && env !== null) {
  682. this.queryInfo.env = env
  683. }
  684. const appType = this.$route.query.appType
  685. if (appType !== undefined && appType !== null) {
  686. this.queryInfo.appType = appType
  687. }
  688. const pageNumber = this.$route.query.pn
  689. if (pageNumber !== undefined && pageNumber !== null) {
  690. this.currentPage = parseInt(pageNumber)
  691. this.queryInfo.pn = parseInt(pageNumber)
  692. }
  693. this.getData()
  694. } else {
  695. this.$message.error(resp.msg)
  696. }
  697. }).catch(error => {
  698. this.$message.error(error.message)
  699. })
  700. document.title = '构建部署'
  701. },
  702. methods: {
  703. handleCurrentChange(pageNumber) {
  704. this.queryInfo.pn = pageNumber
  705. this.$router.push({
  706. path: '/bg/app/bd',
  707. query: this.queryInfo
  708. })
  709. this.getData()
  710. // 回到顶部
  711. scrollTo(0, 0)
  712. },
  713. getData() {
  714. this.dataList = []
  715. getBuildDeployList(this.queryInfo).then(resp => {
  716. if (resp.code === 0) {
  717. const respData = resp.data
  718. this.dataList = respData.list
  719. this.totalSize = respData.totalSize
  720. } else {
  721. this.$message.error(resp.msg)
  722. }
  723. }).catch(error => {
  724. this.$message.error(error.message)
  725. })
  726. },
  727. handleBuildTask() {
  728. this.showTaskDialog = true
  729. getBuildTaskList().then(resp => {
  730. if (resp.code === 0) {
  731. this.buildTaskList = resp.data
  732. } else {
  733. this.$message.error(resp.msg)
  734. }
  735. }).catch(error => {
  736. this.$message.error(error.message)
  737. })
  738. },
  739. cancelTask(index, row) {
  740. const formData = new FormData()
  741. formData.append('appId', row.appId)
  742. cancelBuildTask(formData).then(resp => {
  743. this.$message.info(resp.msg)
  744. }).catch(error => {
  745. this.$message.error(error.message)
  746. })
  747. },
  748. handleBuildLog(index, row) {
  749. this.queryInfo1.appId = row.appId
  750. this.queryInfo1.pn = 1
  751. getBuildLogList(this.queryInfo1).then(resp => {
  752. if (resp.code === 0) {
  753. const respData = resp.data
  754. this.dataList1 = respData.list
  755. this.totalSize1 = respData.totalSize
  756. this.buildLogDialogTitle = row.appId + ' 的构建历史列表'
  757. this.showBuildLogDialog = true
  758. } else {
  759. this.$message.error(resp.msg)
  760. }
  761. }).catch(error => {
  762. this.$message.error(error.message)
  763. })
  764. },
  765. handleCurrentChange1(pageNumber) {
  766. this.queryInfo1.pn = pageNumber
  767. getBuildLogList(this.queryInfo1).then(resp => {
  768. if (resp.code === 0) {
  769. const respData = resp.data
  770. this.dataList1 = respData.list
  771. this.totalSize1 = respData.totalSize
  772. } else {
  773. this.$message.error(resp.msg)
  774. }
  775. }).catch(error => {
  776. this.$message.error(error.message)
  777. })
  778. },
  779. handleAppDetail(row) {
  780. this.$message.info('get ' + row.appId + ' detail')
  781. const queryInfo = {}
  782. queryInfo.appId = row.appId
  783. this.showAppDialog = true
  784. },
  785. handleBuildResult(row) {
  786. const queryInfo = {}
  787. queryInfo.buildLogId = row.buildLogId
  788. getBuildResult(queryInfo).then(resp => {
  789. if (resp.code === 0) {
  790. this.buildResult = resp.data
  791. this.showResultDialog = true
  792. } else {
  793. this.$message.error(resp.msg)
  794. }
  795. }).catch(error => {
  796. this.$message.error(error.message)
  797. })
  798. },
  799. handleBuildConfig(index, row) {
  800. const queryInfo = {}
  801. queryInfo.buildLogId = row.buildLogId
  802. getBuildConfigSnapshot(queryInfo).then(resp => {
  803. if (resp.code === 0) {
  804. this.buildConfigSnapshot = resp.data
  805. this.showSnapshotDialog = true
  806. } else {
  807. this.$message.error(resp.msg)
  808. }
  809. }).catch(error => {
  810. this.$message.error(error.message)
  811. })
  812. },
  813. handleBuildConsumed(index, row) {
  814. const queryInfo = {}
  815. queryInfo.buildLogId = row.buildLogId
  816. getBuildConsumed(queryInfo).then(resp => {
  817. if (resp.code === 0) {
  818. this.buildConsumed = resp.data
  819. this.showConsumedDialog = true
  820. } else {
  821. this.$message.error(resp.msg)
  822. }
  823. }).catch(error => {
  824. this.$message.error(error.message)
  825. })
  826. },
  827. handleBuildPackage(index, row) {
  828. const queryInfo = {}
  829. queryInfo.buildLogId = row.buildLogId
  830. getBuildPackageUrl(queryInfo).then(resp => {
  831. if (resp.code === 0) {
  832. this.$message.info(resp.data)
  833. } else {
  834. this.$message.error(resp.msg)
  835. }
  836. }).catch(error => {
  837. this.$message.error(error.message)
  838. })
  839. },
  840. handleBuildLogFile(row) {
  841. const queryInfo = {}
  842. queryInfo.buildLogId = row.buildLogId
  843. getBuildLogFile(queryInfo).then(resp => {
  844. if (resp.code === 0) {
  845. this.buildLogFile = resp.data
  846. this.showBuildLogFileDialog = true
  847. } else {
  848. this.$message.error(resp.msg)
  849. }
  850. }).catch(error => {
  851. this.$message.error(error.message)
  852. })
  853. },
  854. handleDeployBuild(index, row) {
  855. const formData = new FormData()
  856. formData.append('buildLogId', row.buildLogId)
  857. formData.append('machineId', '')
  858. deployApp(formData).then(resp => {
  859. this.$message.info(resp.msg)
  860. }).catch(error => {
  861. this.$message.error(error.message)
  862. })
  863. },
  864. handleDeleteBuildLog(index, row) {
  865. const formData = new FormData()
  866. formData.append('buildLogId', row.buildLogId)
  867. deleteBuildLog(formData).then(resp => {
  868. this.$message.info(resp.msg)
  869. }).catch(error => {
  870. this.$message.error(error.message)
  871. })
  872. },
  873. handleUpdateApp(index, row) {
  874. const formData = new FormData()
  875. formData.append('appId', row.appId)
  876. updateApp(formData).then(resp => {
  877. this.getData()
  878. this.$message.info(resp.msg)
  879. }).catch(error => {
  880. this.$message.error(error.message)
  881. })
  882. },
  883. handleBuildApp(index, row) {
  884. const formData = new FormData()
  885. formData.append('appId', row.appId)
  886. buildApp(formData).then(resp => {
  887. this.getData()
  888. this.$message.info(resp.msg)
  889. }).catch(error => {
  890. this.$message.error(error.message)
  891. })
  892. },
  893. handleDeployList(index, row) {
  894. if (row.buildLogId === undefined) {
  895. this.$message.error('应用尚未构建')
  896. return
  897. }
  898. const queryInfo = {}
  899. queryInfo.appId = row.appId
  900. this.deployForm.appId = row.appId
  901. this.deployForm.buildLogId = row.buildLogId
  902. getDeployList(queryInfo).then(resp => {
  903. if (resp.code === 0) {
  904. this.deployList = resp.data
  905. this.deployDialogTitle = row.appId + ' 的部署列表'
  906. this.showDeployDialog = true
  907. } else {
  908. this.$message.error(resp.msg)
  909. }
  910. }).catch(error => {
  911. this.$message.error(error.message)
  912. })
  913. },
  914. handleDeployApp(row) {
  915. const formData = new FormData()
  916. formData.append('buildLogId', this.deployForm.buildLogId)
  917. formData.append('machineId', row.machineId)
  918. deployApp(formData).then(resp => {
  919. this.$message.info(resp.msg)
  920. const queryInfo = {}
  921. queryInfo.appId = this.deployForm.appId
  922. getDeployList(queryInfo).then(resp => {
  923. if (resp.code === 0) {
  924. this.deployList = resp.data
  925. }
  926. })
  927. }).catch(error => {
  928. this.$message.error(error.message)
  929. })
  930. },
  931. handleDeployLog(row) {
  932. this.$message.info('get deploy log')
  933. },
  934. onClear() {
  935. this.getData()
  936. },
  937. onSearch() {
  938. this.getData()
  939. },
  940. onRefresh() {
  941. this.queryInfo.appId = ''
  942. this.getData()
  943. },
  944. onSelectChange() {
  945. this.currentPage = 1
  946. this.queryInfo.pn = 1
  947. this.$router.push({
  948. path: '/bg/app/bd',
  949. query: this.queryInfo
  950. })
  951. this.getData()
  952. },
  953. /**
  954. * 获取当前激活步骤的索引
  955. * @param {Array} steps 步骤列表
  956. * @returns {Number} 索引值
  957. */
  958. getCurrentStepIndex(steps) {
  959. if (!steps || steps.length === 0) return 0
  960. // 找到第一个状态不是 SUCCESS 的步骤索引
  961. const index = steps.findIndex(step => step.status !== 'SUCCESS')
  962. // 如果全部都成功了,返回 steps.length 使进度条全绿
  963. return index === -1 ? steps.length : index
  964. },
  965. /**
  966. * 获取步骤描述信息
  967. * @param {Object} step 步骤对象
  968. */
  969. getStepDesc(step) {
  970. if (step.status === 'RUNNING') {
  971. return '正在执行...'
  972. }
  973. if (step.status === 'FAILURE' && step.errorMsg) {
  974. // 如果报错,显示错误摘要(截取前30个字符防止气泡框撑爆)
  975. return step.errorMsg.length > 30
  976. ? step.errorMsg.substring(0, 30) + '...'
  977. : step.errorMsg
  978. }
  979. if (step.status === 'SUCCESS' && step.endTime && step.startTime) {
  980. // 计算耗时(可选)
  981. const duration = (new Date(step.endTime) - new Date(step.startTime)) / 1000
  982. return `耗时: ${duration.toFixed(1)}s`
  983. }
  984. return ''
  985. },
  986. /**
  987. * 映射后端状态到 el-step 的 status 属性
  988. * el-step status 可选值: wait / process / finish / error / success
  989. * @param {String} backendStatus 后端传来的状态串
  990. */
  991. getStepStatus(backendStatus) {
  992. const statusMap = {
  993. 'PENDING': 'wait',
  994. 'RUNNING': 'process',
  995. 'SUCCESS': 'success',
  996. 'FAILED': 'error',
  997. 'SKIPPED': 'wait'
  998. }
  999. return statusMap[backendStatus] || 'wait'
  1000. }
  1001. }
  1002. }
  1003. </script>
  1004. <style>
  1005. </style>