index.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. <template>
  2. <el-row
  3. v-loading="loading"
  4. :gutter="10"
  5. class="qualityModule"
  6. >
  7. <el-col :span="9">
  8. <div class="itemBox onlineProblem" style="height: 470px">
  9. <div class="titleLevel3 mb10">线上问题</div>
  10. <el-row :gutter="10">
  11. <el-col
  12. v-for="(item, index) in mainData.onlineProblemList"
  13. :key="index"
  14. :span="12"
  15. class="mb10"
  16. >
  17. <div
  18. :style="{ cursor: item.label == '新增问题' && 'pointer'}"
  19. @click.stop="onDetial('线上问题', item)"
  20. >
  21. <dataItem :item="item" />
  22. </div>
  23. </el-col>
  24. </el-row>
  25. <div class="chartSearchbar inlineBetween mt15">
  26. <div style="width: 200px">
  27. <span style="margin-right: 10px">分布类型:</span>
  28. <el-select
  29. v-model="onlineProblemViweType"
  30. size="small"
  31. filterable
  32. style="width: 115px"
  33. @change="$emit('search', { onlineProblemViweType })"
  34. >
  35. <el-option v-for="(t, index) in onlineProblemSelect" :key="index" :label="t" :value="t" />
  36. </el-select>
  37. </div>
  38. </div>
  39. <div v-loading="onlineLoading" class="chartViewHeight">
  40. <normal-echart v-if="onlineProblemChartOption" :chart-id="'chart1'" :option="onlineProblemChartOption" @onClick="changeList" />
  41. </div>
  42. </div>
  43. </el-col>
  44. <el-col :span="9">
  45. <div class="itemBox quality" style="height: 470px">
  46. <div class="titleLevel3 mb10">线下质量</div>
  47. <el-row :gutter="10">
  48. <el-col v-for="(item, index) in mainData.offlineProblemList" :key="index" :span="12" class="mb10">
  49. <div
  50. :style="{ cursor: 'pointer'}"
  51. @click.stop="onDetial('线下质量', item)"
  52. >
  53. <dataItem :item="item" />
  54. </div>
  55. </el-col>
  56. </el-row>
  57. <div class="chartSearchbar inlineBetween mt15">
  58. <div style="width: 200px">
  59. <span style="margin-right: 10px">分布类型:</span>
  60. <el-select
  61. v-model="offlineProblemViweType"
  62. size="small"
  63. filterable
  64. style="width: 115px"
  65. @change="$emit('search', { offlineProblemViweType })"
  66. >
  67. <el-option v-for="(t, index) in offlineProblemSelect" :key="index" :label="t" :value="t" />
  68. </el-select>
  69. </div>
  70. </div>
  71. <div v-loading="offlineLoading" class="chartViewHeight">
  72. <normal-echart v-if="offlineProblemChartOption" :chart-id="'chart2'" :option="offlineProblemChartOption" @onClick="changeList" />
  73. </div>
  74. </div>
  75. </el-col>
  76. <el-col :span="6">
  77. <div class="itemBox progress" style="min-height: 328px">
  78. <div class="titleLevel3 mb10">上线过程</div>
  79. <el-row v-if="mainData.onlineProcessList" :gutter="10">
  80. <el-col v-for="(item, index) in mainData.onlineProcessList.list" :key="index" :span="12" class="mb10">
  81. <dataItem :item="item" />
  82. </el-col>
  83. </el-row>
  84. <el-divider class="divider" />
  85. <el-row
  86. v-if="mainData.onlineProcessList"
  87. :gutter="10"
  88. class="rollBack"
  89. style="margin-top: 40px"
  90. >
  91. <el-col :span="12" class="mb10">
  92. <span class="rollBackItem">
  93. <span class="bigCircle" style="background: #7ED321" />
  94. 回滚
  95. <span class="numText" style="font-size: 20px">{{ mainData.onlineProcessList.rollBack.countStr.countStr }}</span>
  96. </span>
  97. </el-col>
  98. <el-col :span="12" class="mb10">
  99. <div class="rollBackItem">
  100. <span class="circle" style="background: #3F9DFE" />
  101. 预发回滚
  102. <span class="numText">{{ mainData.onlineProcessList.rollBack.preCountStr.countStr }}</span>
  103. </div>
  104. <div class="rollBackItem">
  105. <span class="circle" style="background: #3F9DFE" />
  106. 全量回滚
  107. <span class="numText">{{ mainData.onlineProcessList.rollBack.fullCountStr.countStr }}</span>
  108. </div>
  109. <div class="rollBackItem">
  110. <span class="circle" style="background: #3F9DFE" />
  111. 小流量回滚
  112. <span class="numText">{{ mainData.onlineProcessList.rollBack.lowCountStr.countStr }}</span>
  113. </div>
  114. </el-col>
  115. </el-row>
  116. </div>
  117. <div class="itemBox progress" style="margin-top: 20px; height: 122px;">
  118. <div class="titleLevel3 mb10">移动端发布质量</div>
  119. <el-row :gutter="10">
  120. <el-col v-for="(item, index) in mainData.mobilePublishQualityList" :key="index" :span="12" class="mb10">
  121. <dataItem :item="item" />
  122. </el-col>
  123. </el-row>
  124. </div>
  125. </el-col>
  126. </el-row>
  127. </template>
  128. <script>
  129. import dataItem from '../dataItem'
  130. import normalEchart from '@/components/chart/normalEchart'
  131. import { getOption } from '@/utils/options'
  132. export default {
  133. components: {
  134. dataItem,
  135. normalEchart
  136. },
  137. props: {
  138. datas: {
  139. type: Object,
  140. required: true,
  141. default: () => {}
  142. },
  143. loading: {
  144. type: Boolean,
  145. required: false,
  146. default: false
  147. },
  148. onlineLoading: {
  149. type: Boolean,
  150. required: false,
  151. default: false
  152. },
  153. offlineLoading: {
  154. type: Boolean,
  155. required: false,
  156. default: false
  157. }
  158. },
  159. data() {
  160. return {
  161. itemList: [
  162. {
  163. 'innerColor': '#F5222D',
  164. 'outColor': '#F5DDE2',
  165. 'title': '123',
  166. 'subTitle': '123',
  167. 'bgColor': '#F5F7FC'
  168. },
  169. {
  170. 'innerColor': '#FAAD14',
  171. 'outColor': '#F7ECDA',
  172. 'title': '',
  173. 'subTitle': '',
  174. 'bgColor': '#F5F7FC'
  175. },
  176. {
  177. 'innerColor': '#C97DE9',
  178. 'outColor': '#EFE5FA',
  179. 'title': '',
  180. 'subTitle': '',
  181. 'bgColor': '#F5F7FC'
  182. },
  183. {
  184. 'innerColor': '#7ED321',
  185. 'outColor': '#E4F2DC',
  186. 'title': '',
  187. 'subTitle': '',
  188. 'bgColor': '#F5F7FC'
  189. }
  190. ],
  191. redObj: {
  192. 'innerColor': '#F5222D',
  193. 'outColor': '#F5DDE2',
  194. 'bgColor': '#F5F7FC'
  195. },
  196. yellowObj: {
  197. 'innerColor': '#FAAD14',
  198. 'outColor': '#F7ECDA',
  199. 'bgColor': '#F5F7FC'
  200. },
  201. purpleObj: {
  202. 'innerColor': '#C97DE9',
  203. 'outColor': '#EFE5FA',
  204. 'bgColor': '#F5F7FC'
  205. },
  206. greenObj: {
  207. 'innerColor': '#7ED321',
  208. 'outColor': '#E4F2DC',
  209. 'bgColor': '#F5F7FC'
  210. },
  211. onlineProblemSelect: ['日期', '等级', '影响业务方'],
  212. offlineProblemSelect: ['日期', '等级', '责任人', '发现阶段'],
  213. offlineProblemViweType: '日期',
  214. onlineProblemViweType: '日期',
  215. onlineProblemChartOption: null,
  216. offlineProblemChartOption: null,
  217. echartsOption1: null,
  218. viewType: null,
  219. mainData: {}
  220. }
  221. },
  222. watch: {
  223. datas(newVal, oldVal) {
  224. if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
  225. this.resetBaseData()
  226. }
  227. }
  228. },
  229. mounted() {
  230. this.resetBaseData()
  231. },
  232. methods: {
  233. onDetial(name, item) {
  234. if (name === '线上问题' && item.label === '新增问题' || name === '线下质量') {
  235. this.$emit('checkDetialModal', item)
  236. }
  237. },
  238. resetBaseData() {
  239. const {
  240. onlineProblemList,
  241. onlineProblemChart,
  242. offlineProblemList,
  243. offlineProblemChart,
  244. onlineProcessList,
  245. mobilePublishQualityList
  246. } = this.datas
  247. const {
  248. onlineProblemChart: mainDataOnlineProblemChart,
  249. offlineProblemChart: mainDataOfflineProblemChart
  250. } = this.mainData
  251. // 线上问题表
  252. if (onlineProblemList) {
  253. this.mainData = { ...this.mainData, onlineProblemList: this.getOnlineProblemList() }
  254. }
  255. // 线上问题图
  256. if (JSON.stringify(onlineProblemChart) !== JSON.stringify(mainDataOnlineProblemChart)) {
  257. const { xaxis, yaxis } = onlineProblemChart
  258. this.onlineProblemChartOption = getOption(xaxis, yaxis[0].data, 'bar', { endValue: 6 })
  259. this.mainData = { ...this.mainData, onlineProblemChart }
  260. }
  261. // 线下质量表
  262. if (offlineProblemList) {
  263. this.mainData = { ...this.mainData, offlineProblemList: this.getOfflineProblemList() }
  264. }
  265. // 线下质量图
  266. if (JSON.stringify(offlineProblemChart) !== JSON.stringify(mainDataOfflineProblemChart)) {
  267. const { xaxis, yaxis } = offlineProblemChart
  268. this.offlineProblemChartOption = getOption(xaxis, yaxis[0].data, 'bar', { endValue: 6 })
  269. this.mainData = { ...this.mainData, offlineProblemChart }
  270. }
  271. // 上线过程
  272. if (onlineProcessList) {
  273. this.mainData = { ...this.mainData, onlineProcessList: this.getOnlineProcessList() }
  274. }
  275. // 移动端发布质量
  276. if (mobilePublishQualityList) {
  277. this.mainData = { ...this.mainData, mobilePublishQualityList: this.getMobilePublishQualityList() }
  278. }
  279. },
  280. // 组织线上问题表数据
  281. getOnlineProblemList() {
  282. const { ImprovementsOverRate, depleteUnavailableTime, newOnlineProblems, onlineBreakRate } = this.datas.onlineProblemList
  283. return [
  284. {
  285. ...this.redObj,
  286. 'label': newOnlineProblems.label,
  287. 'title': newOnlineProblems.countStr,
  288. 'titleUnit': '个',
  289. 'subTitleUnit': 'rate',
  290. 'subTitle': newOnlineProblems.chainRatio,
  291. 'IdList': newOnlineProblems.idList
  292. },
  293. {
  294. ...this.yellowObj,
  295. 'label': depleteUnavailableTime.label,
  296. 'title': depleteUnavailableTime.countStr,
  297. 'titleUnit': '分',
  298. 'subTitleUnit': 'rate',
  299. 'subTitle': depleteUnavailableTime.chainRatio,
  300. 'IdList': depleteUnavailableTime.IdList
  301. },
  302. {
  303. ...this.purpleObj,
  304. 'label': onlineBreakRate.label,
  305. 'title': onlineBreakRate.countStr,
  306. 'titleUnit': '%',
  307. 'subTitleUnit': 'rate',
  308. 'subTitle': onlineBreakRate.chainRatio,
  309. 'IdList': onlineBreakRate.IdList
  310. },
  311. {
  312. ...this.greenObj,
  313. 'label': ImprovementsOverRate.label,
  314. 'title': ImprovementsOverRate.countStr,
  315. 'titleUnit': '%',
  316. 'subTitleUnit': 'rate',
  317. 'subTitle': ImprovementsOverRate.chainRatio,
  318. 'IdList': ImprovementsOverRate.IdList
  319. }
  320. ]
  321. },
  322. // 线下质量数据
  323. getOfflineProblemList() {
  324. const { newBug, reopen, testBackRate, releaseNopass } = this.datas.offlineProblemList
  325. return [
  326. {
  327. ...this.redObj,
  328. 'label': newBug.label,
  329. 'title': newBug.countStr,
  330. 'titleUnit': '个',
  331. 'subTitleUnit': 'rate',
  332. 'subTitle': newBug.chainRatio,
  333. 'IdList': newBug.idList
  334. },
  335. {
  336. ...this.yellowObj,
  337. 'label': reopen.label,
  338. 'title': reopen.countStr,
  339. 'titleUnit': '次',
  340. 'subTitleUnit': 'rate',
  341. 'subTitle': reopen.chainRatio,
  342. 'IdList': reopen.idList
  343. },
  344. {
  345. 'color': '#3F9DFE',
  346. 'bgColor': '#F5F7FC',
  347. 'label': testBackRate.label,
  348. 'title': testBackRate.countStr,
  349. 'titleUnit': '%',
  350. 'subTitleUnit': 'rate',
  351. 'subTitle': testBackRate.chainRatio,
  352. 'IdList': testBackRate.idList,
  353. 'remark': testBackRate.remark,
  354. 'type': 'circle'
  355. },
  356. {
  357. 'color': '#7ED321',
  358. 'bgColor': '#F5F7FC',
  359. 'label': releaseNopass.label,
  360. 'title': releaseNopass.countStr,
  361. 'titleUnit': '%',
  362. 'subTitleUnit': 'rate',
  363. 'subTitle': releaseNopass.chainRatio,
  364. 'IdList': releaseNopass.idList,
  365. 'remark': releaseNopass.remark,
  366. 'type': 'circle'
  367. }
  368. ]
  369. },
  370. // 上线过程数据
  371. getOnlineProcessList() {
  372. const { online, testFreeOnlineRate, onlinebyStreakingRate, rollBack } = this.datas.onlineProcessList
  373. return {
  374. 'list': [
  375. {
  376. 'innerColor': '#3F9DFE',
  377. 'outColor': '#E2F0FF',
  378. 'padding': '8px 0px',
  379. 'label': online.label,
  380. 'title': online.countStr,
  381. 'titleUnit': '次',
  382. 'IdList': online.idList
  383. },
  384. {
  385. 'innerColor': '#7ED321',
  386. 'outColor': '#E4F2DC',
  387. 'padding': '8px 0px',
  388. 'label': testFreeOnlineRate.label,
  389. 'title': testFreeOnlineRate.countStr,
  390. 'titleUnit': '%',
  391. 'IdList': testFreeOnlineRate.idList
  392. },
  393. {
  394. 'innerColor': '#F5222D',
  395. 'outColor': '#F5DDE2',
  396. 'padding': '8px 0px',
  397. 'label': onlinebyStreakingRate.label,
  398. 'title': onlinebyStreakingRate.countStr,
  399. 'titleUnit': '次',
  400. 'IdList': onlinebyStreakingRate.idList
  401. }
  402. ],
  403. rollBack
  404. }
  405. },
  406. // 移动端发布质量数据
  407. getMobilePublishQualityList() {
  408. const {
  409. hotpacth
  410. // addIssue // 增发
  411. } = this.datas.mobilePublishQualityList
  412. return [
  413. {
  414. 'innerColor': '#3F9DFE',
  415. 'outColor': '#E2F0FF',
  416. 'padding': '8px 0px',
  417. 'label': hotpacth.label,
  418. 'title': hotpacth.countStr,
  419. 'titleUnit': '次',
  420. 'IdList': hotpacth.IdList
  421. }
  422. // 增发次数暂时隐藏
  423. // {
  424. // 'innerColor': '#F5222D',
  425. // 'outColor': '#F5DDE2',
  426. // 'padding': '8px 0px',
  427. // 'label': addIssue.label,
  428. // 'title': addIssue.countStr,
  429. // 'titleUnit': '次',
  430. // 'IdList': addIssue.IdList
  431. // }
  432. ]
  433. },
  434. changeList() {}
  435. }
  436. }
  437. </script>
  438. <style scoped lang='less'>
  439. .qualityModule {
  440. .divider {
  441. margin: 0 0 15px 0;
  442. }
  443. .rollBack {
  444. height: 94px;
  445. display: flex;
  446. align-items: center;
  447. .rollBackItem {
  448. color: #666;
  449. margin-bottom: 10px;
  450. .numText {
  451. color: #409EFF;
  452. font-weight: 600;
  453. }
  454. }
  455. .circle {
  456. display: inline-block;
  457. width: 6px;
  458. height: 6px;
  459. border-radius: 100%;
  460. margin-right: 6px;
  461. }
  462. .bigCircle {
  463. display: inline-block;
  464. width: 10px;
  465. height: 10px;
  466. border-radius: 100%;
  467. margin-right: 6px;
  468. }
  469. }
  470. .itemBox {
  471. box-shadow: 0px 6px 50px rgba(0, 0, 0, 0.05);
  472. padding: 10px 10px;
  473. border-radius: 6px;
  474. }
  475. .chartSearchbar {
  476. margin-top: 10px;
  477. //margin-bottom: 10px;
  478. }
  479. .chartViewHeight {
  480. height: 250px;
  481. // padding-left: 15px;
  482. }
  483. }
  484. </style>