index.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. <template>
  2. <el-row
  3. v-loading="loading"
  4. :gutter="20"
  5. class="qualityModule"
  6. >
  7. <el-col :span="8">
  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="8">
  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="8">
  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. console.log(223, this.datas)
  248. // 线上问题表
  249. if (onlineProblemList) {
  250. this.mainData = { ...this.mainData, onlineProblemList: this.getOnlineProblemList() }
  251. }
  252. // 线上问题图
  253. if (onlineProblemChart) {
  254. const { xaxis, yaxis } = onlineProblemChart
  255. this.onlineProblemChartOption = getOption(xaxis, yaxis[0].data, 'bar', { endValue: 6 })
  256. }
  257. // 线下质量表
  258. if (offlineProblemList) {
  259. this.mainData = { ...this.mainData, offlineProblemList: this.getOfflineProblemList() }
  260. }
  261. // 线下质量图
  262. if (offlineProblemChart) {
  263. const { xaxis, yaxis } = offlineProblemChart
  264. this.offlineProblemChartOption = getOption(xaxis, yaxis[0].data, 'bar', { endValue: 6 })
  265. }
  266. // 上线过程
  267. if (onlineProcessList) {
  268. this.mainData = { ...this.mainData, onlineProcessList: this.getOnlineProcessList() }
  269. }
  270. // 移动端发布质量
  271. if (mobilePublishQualityList) {
  272. this.mainData = { ...this.mainData, mobilePublishQualityList: this.getMobilePublishQualityList() }
  273. }
  274. },
  275. // 组织线上问题表数据
  276. getOnlineProblemList() {
  277. const { ImprovementsOverRate, depleteUnavailableTime, newOnlineProblems, onlineBreakRate } = this.datas.onlineProblemList
  278. return [
  279. {
  280. ...this.redObj,
  281. 'label': newOnlineProblems.label,
  282. 'title': newOnlineProblems.countStr,
  283. 'titleUnit': '个',
  284. 'subTitleUnit': 'rate',
  285. 'subTitle': newOnlineProblems.chainRatio,
  286. 'IdList': newOnlineProblems.idList
  287. },
  288. {
  289. ...this.yellowObj,
  290. 'label': depleteUnavailableTime.label,
  291. 'title': depleteUnavailableTime.countStr,
  292. 'titleUnit': '分',
  293. 'subTitleUnit': 'rate',
  294. 'subTitle': depleteUnavailableTime.chainRatio,
  295. 'IdList': depleteUnavailableTime.IdList
  296. },
  297. {
  298. ...this.purpleObj,
  299. 'label': onlineBreakRate.label,
  300. 'title': onlineBreakRate.countStr,
  301. 'titleUnit': '%',
  302. 'subTitleUnit': 'rate',
  303. 'subTitle': onlineBreakRate.chainRatio,
  304. 'IdList': onlineBreakRate.IdList
  305. },
  306. {
  307. ...this.greenObj,
  308. 'label': ImprovementsOverRate.label,
  309. 'title': ImprovementsOverRate.countStr,
  310. 'titleUnit': '%',
  311. 'subTitleUnit': 'rate',
  312. 'subTitle': ImprovementsOverRate.chainRatio,
  313. 'IdList': ImprovementsOverRate.IdList
  314. }
  315. ]
  316. },
  317. // 线下质量数据
  318. getOfflineProblemList() {
  319. const { newBug, reopen, testBackRate, releaseNopass } = this.datas.offlineProblemList
  320. return [
  321. {
  322. ...this.redObj,
  323. 'label': newBug.label,
  324. 'title': newBug.countStr,
  325. 'titleUnit': '个',
  326. 'subTitleUnit': 'rate',
  327. 'subTitle': newBug.chainRatio,
  328. 'IdList': newBug.idList
  329. },
  330. {
  331. ...this.yellowObj,
  332. 'label': reopen.label,
  333. 'title': reopen.countStr,
  334. 'titleUnit': '次',
  335. 'subTitleUnit': 'rate',
  336. 'subTitle': reopen.chainRatio,
  337. 'IdList': reopen.idList
  338. },
  339. {
  340. 'color': '#3F9DFE',
  341. 'bgColor': '#F5F7FC',
  342. 'label': testBackRate.label,
  343. 'title': testBackRate.countStr,
  344. 'titleUnit': '%',
  345. 'subTitleUnit': 'rate',
  346. 'subTitle': testBackRate.chainRatio,
  347. 'IdList': testBackRate.idList,
  348. 'remark': testBackRate.remark,
  349. 'type': 'circle'
  350. },
  351. {
  352. 'color': '#7ED321',
  353. 'bgColor': '#F5F7FC',
  354. 'label': releaseNopass.label,
  355. 'title': releaseNopass.countStr,
  356. 'titleUnit': '%',
  357. 'subTitleUnit': 'rate',
  358. 'subTitle': releaseNopass.chainRatio,
  359. 'IdList': releaseNopass.idList,
  360. 'remark': releaseNopass.remark,
  361. 'type': 'circle'
  362. }
  363. ]
  364. },
  365. // 上线过程数据
  366. getOnlineProcessList() {
  367. const { online, testFreeOnlineRate, onlinebyStreakingRate, rollBack } = this.datas.onlineProcessList
  368. return {
  369. 'list': [
  370. {
  371. 'innerColor': '#3F9DFE',
  372. 'outColor': '#E2F0FF',
  373. 'padding': '8px 0px',
  374. 'label': online.label,
  375. 'title': online.countStr,
  376. 'titleUnit': '次',
  377. 'IdList': online.idList
  378. },
  379. {
  380. 'innerColor': '#7ED321',
  381. 'outColor': '#E4F2DC',
  382. 'padding': '8px 0px',
  383. 'label': testFreeOnlineRate.label,
  384. 'title': testFreeOnlineRate.countStr,
  385. 'titleUnit': '%',
  386. 'IdList': testFreeOnlineRate.idList
  387. },
  388. {
  389. 'innerColor': '#F5222D',
  390. 'outColor': '#F5DDE2',
  391. 'padding': '8px 0px',
  392. 'label': onlinebyStreakingRate.label,
  393. 'title': onlinebyStreakingRate.countStr,
  394. 'titleUnit': '次',
  395. 'IdList': onlinebyStreakingRate.idList
  396. }
  397. ],
  398. rollBack
  399. }
  400. },
  401. // 移动端发布质量数据
  402. getMobilePublishQualityList() {
  403. const { hotpacth, addIssue } = this.datas.mobilePublishQualityList
  404. return [
  405. {
  406. 'innerColor': '#3F9DFE',
  407. 'outColor': '#E2F0FF',
  408. 'padding': '8px 0px',
  409. 'label': hotpacth.label,
  410. 'title': hotpacth.countStr,
  411. 'titleUnit': '次',
  412. 'IdList': hotpacth.IdList
  413. },
  414. {
  415. 'innerColor': '#F5222D',
  416. 'outColor': '#F5DDE2',
  417. 'padding': '8px 0px',
  418. 'label': addIssue.label,
  419. 'title': addIssue.countStr,
  420. 'titleUnit': '次',
  421. 'IdList': addIssue.IdList
  422. }
  423. ]
  424. },
  425. changeList() {}
  426. }
  427. }
  428. </script>
  429. <style scoped lang='less'>
  430. .qualityModule {
  431. .divider {
  432. margin: 0 0 15px 0;
  433. }
  434. .rollBack {
  435. height: 94px;
  436. display: flex;
  437. align-items: center;
  438. .rollBackItem {
  439. color: #666;
  440. margin-bottom: 10px;
  441. .numText {
  442. color: #409EFF;
  443. font-weight: 600;
  444. }
  445. }
  446. .circle {
  447. display: inline-block;
  448. width: 6px;
  449. height: 6px;
  450. border-radius: 100%;
  451. margin-right: 6px;
  452. }
  453. .bigCircle {
  454. display: inline-block;
  455. width: 10px;
  456. height: 10px;
  457. border-radius: 100%;
  458. margin-right: 6px;
  459. }
  460. }
  461. .itemBox {
  462. box-shadow: 0px 6px 50px rgba(0, 0, 0, 0.05);
  463. padding: 10px 10px;
  464. border-radius: 6px;
  465. }
  466. .chartSearchbar {
  467. margin-top: 10px;
  468. //margin-bottom: 10px;
  469. }
  470. .chartViewHeight {
  471. height: 250px;
  472. // padding-left: 15px;
  473. }
  474. }
  475. </style>