index.vue 17 KB

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