keyBusinessCon.vue 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316
  1. <template>
  2. <div style="padding:16px;">
  3. <div class="TableBox">
  4. <el-table
  5. ref="tableRef"
  6. :key="isUpdate"
  7. v-loading="loading"
  8. :data="serveceMapList"
  9. @row-click="handleRowClick"
  10. >
  11. <el-table-column v-if="colData[0].istrue" align="center" header-align="center" class-name="column_one" label="业务名" prop="name" :show-overflow-tooltip="true" />
  12. <el-table-column v-if="colData[4].istrue" header-align="center" align="center" label="请求总数" sortable prop="request_total" :show-overflow-tooltip="true">
  13. <template slot-scope="scope">
  14. <div :class="scope.row.request_total!=0&&scope.row.request_total!= undefined?'table_bg':'table_bg_yellow'">
  15. <div class="table-num-box">
  16. {{ scope.row.request_total== undefined?0:Number(scope.row.request_total).toFixed(2) }}
  17. </div>
  18. <div class="table-day-rate-box">
  19. <i v-show="processNumber(scope.row.request_total_dod).sign" :class="processNumber(scope.row.request_total_dod).sign == 'up'? 'el-icon-up up':'el-icon-down down'" />
  20. <span>
  21. {{ scope.row.request_total_dod==undefined?0:getErrRate(processNumber(scope.row.request_total_dod).value) }}
  22. </span>
  23. </div>
  24. </div>
  25. </template>
  26. </el-table-column>
  27. <el-table-column v-if="colData[1].istrue" header-align="center" align="center" label="调用占比" prop="request_rate" :show-overflow-tooltip="true">
  28. <template slot-scope="scope">
  29. <div class="table_bg">
  30. <div class="table-num-box">
  31. {{ getErrRate(scope.row.request_rate) }}
  32. </div>
  33. <div class="table-day-rate-box">
  34. <i v-show="processNumber(scope.row.request_rate_dod).sign" :class="processNumber(scope.row.request_rate_dod).sign == 'up'? 'el-icon-up up':'el-icon-down down'" />
  35. <span>
  36. {{ scope.row.request_rate_dod==undefined?0:getErrRate(processNumber(scope.row.request_rate_dod).value) }}
  37. </span>
  38. </div>
  39. </div>
  40. </template>
  41. </el-table-column>
  42. <el-table-column v-if="colData[2].istrue" header-align="center" align="center" label="SpanName" prop="span_name" :show-overflow-tooltip="true">
  43. <template slot-scope="scope">
  44. <span>{{ scope.row.span_name }}</span>
  45. </template>
  46. </el-table-column>
  47. <el-table-column v-if="colData[3].istrue" header-align="center" align="center" label="rpm" sortable prop="rpm" :show-overflow-tooltip="true">
  48. <template slot-scope="scope">
  49. <div class="table_bg">
  50. {{ scope.row.rpm == undefined?0:Number(scope.row.rpm).toFixed(2) }}
  51. </div>
  52. </template>
  53. </el-table-column>
  54. <el-table-column v-if="colData[5].istrue" header-align="center" align="center" label="错误率" sortable prop="error_rate" :show-overflow-tooltip="true">
  55. <template slot-scope="scope">
  56. <div :class="scope.row.error_rate==0?'table_bg':'table_bg_red'">
  57. <div class="table-num-box">
  58. {{ getErrRate(scope.row.error_rate) }}
  59. </div>
  60. <div class="table-day-rate-box">
  61. <i v-show="processNumber(scope.row.error_rate_dod).sign" :class="processNumber(scope.row.error_rate_dod).sign == 'up'? 'el-icon-up up':'el-icon-down down'" />
  62. <span>
  63. {{ scope.row.error_rate_dod==undefined?0:getErrRate(processNumber(scope.row.error_rate_dod).value) }}
  64. </span>
  65. </div>
  66. </div>
  67. </template>
  68. </el-table-column>
  69. <el-table-column header-align="center" align="center" label="最大延迟(ms)" sortable prop="max" :show-overflow-tooltip="true">
  70. <template slot-scope="scope">
  71. <div :class="scope.row.max<2000?'table_bg':'table_bg_red'">
  72. {{ scope.row.max==undefined?0:Number(scope.row.max).toFixed(2) }}
  73. </div>
  74. </template>
  75. </el-table-column>
  76. <el-table-column v-if="colData[7].istrue" header-align="center" align="center" label="平均延迟(ms)" sortable prop="duration_average" :show-overflow-tooltip="true">
  77. <template slot-scope="scope">
  78. <div :class="scope.row.duration_average<2000?'table_bg':'table_bg_red'">
  79. <div class="table-num-box">
  80. {{ scope.row.duration_average==undefined?0:Number(scope.row.duration_average).toFixed(2) }}
  81. </div>
  82. <div class="table-day-rate-box">
  83. <i v-show="processNumber(scope.row.duration_average_dod).sign" :class="processNumber(scope.row.duration_average_dod).sign == 'up'? 'el-icon-up up':'el-icon-down down'" />
  84. <span>
  85. {{ scope.row.duration_average_dod==undefined?0:getErrRate(processNumber(scope.row.duration_average_dod).value) }}
  86. </span>
  87. </div>
  88. </div>
  89. </template>
  90. </el-table-column>
  91. <el-table-column v-if="colData[8].istrue" header-align="center" align="center" label="中位延迟11" prop="duration_median" width="200">
  92. <template slot-scope="scope">
  93. <div :class="scope.row.duration_median<2000?'table_bg':'table_bg_red'" style="display:flex;">
  94. <div>
  95. <div class="table-num-box">
  96. {{ scope.row.duration_median==undefined?0:Number(scope.row.duration_median).toFixed(2) }}
  97. </div>
  98. <div class="table-day-rate-box">
  99. <i v-show="processNumber(scope.row.duration_median_dod).sign" :class="processNumber(scope.row.duration_median_dod).sign == 'up'? 'el-icon-up up':'el-icon-down down'" />
  100. <span>
  101. {{ scope.row.duration_median_dod==undefined?0:getErrRate(processNumber(scope.row.duration_median_dod).value) }}
  102. </span>
  103. </div>
  104. </div>
  105. <span v-if="scope.row.quantiles!=undefined" style="display:flex;">
  106. {{ drawEchartsp5(scope.row, scope.$index, 'five') }}
  107. <div :id="`tiger-five-trend-index` + scope.$index" style="flex:1;padding-left:10px" class="tiger-trend-charts" />
  108. </span>
  109. </div>
  110. </template>
  111. </el-table-column>
  112. <el-table-column
  113. label="操作"
  114. align="center"
  115. class-name="small-padding fixed-width"
  116. width="160"
  117. sortable
  118. >
  119. <template slot-scope="scope">
  120. <el-button
  121. size="mini"
  122. type="text"
  123. icon="el-icon-edit"
  124. @click.native.stop="handleUpdate(scope.row)"
  125. >标注</el-button>
  126. <el-button
  127. v-if="scope.row.favor == 0"
  128. size="mini"
  129. type="text"
  130. icon="el-icon-star-off"
  131. @click.native.stop="handleFavor(scope.row)"
  132. />
  133. <el-button
  134. v-if="scope.row.favor == 1"
  135. size="mini"
  136. type="text"
  137. icon="el-icon-star-on"
  138. @click.native.stop="handleFavor(scope.row)"
  139. />
  140. <el-button
  141. style="color:#F56C6C"
  142. size="mini"
  143. type="text"
  144. icon="el-icon-delete"
  145. @click.native.stop="handleDelete(scope.row)"
  146. >删除</el-button>
  147. </template>
  148. </el-table-column>
  149. </el-table>
  150. </div>
  151. <pagination
  152. v-show="tableCount>0"
  153. :total="tableCount"
  154. :page.sync="queryParams.page_num"
  155. :limit.sync="queryParams.page_size"
  156. @pagination="getList"
  157. />
  158. <!-- 添加或修改应用配置对话框 -->
  159. <el-dialog v-if="open" :title="title" :visible.sync="open" width="700px" :center="true" :close-on-click-modal="false">
  160. <el-form ref="form" :model="form" :rules="rules" label-width="95px">
  161. <el-form-item label="中文别名" prop="name">
  162. <el-input v-model="form.name" placeholder="请输入中文别名" />
  163. </el-form-item>
  164. </el-form>
  165. <div slot="footer" class="dialog-footer">
  166. <el-button type="primary" @click="submitForm">确 定</el-button>
  167. <el-button @click="cancel">取 消</el-button>
  168. </div>
  169. </el-dialog>
  170. <!-- 业务空间 -->
  171. <ServiceSpaceDrawer v-if="isShowServiceSpaceDrawer" :is-opendrawer="isShowServiceSpaceDrawer" :bussiness-id="currentBussinessId" :bussiness-name="currentBussinessName" @handleClose="handleClose" />
  172. </div>
  173. </template>
  174. <script>
  175. import ServiceSpaceDrawer from './ServiceSpaceDrawer.vue'
  176. import { addUrlMapping, getNewBusinessList, listBizStats, listBizGraph, updateBiz, delBiz, favorBiz } from '@/api/mapping'
  177. import { formatJson } from '@/utils'
  178. import storage from '@/utils/storage'
  179. // import bus from '@/utils/bus'
  180. import { getToken } from '@/utils/auth'
  181. // import echarts from 'echarts'
  182. import resize from '../../mixins/resize'
  183. import moment from 'moment'
  184. // import elTableInfiniteScroll from 'el-table-infinite-scroll';
  185. import Topo from './Topo'
  186. import BigNumber from 'bignumber.js'
  187. export default {
  188. name: 'KeyBusiness',
  189. components: {
  190. Topo,
  191. ServiceSpaceDrawer
  192. },
  193. mixins: [resize],
  194. data() {
  195. return {
  196. loading: false,
  197. // 设置选中的列的复选框
  198. colSelect: [
  199. '业务名',
  200. '调用占比',
  201. // "SpanName",
  202. // "rpm",
  203. '请求总数',
  204. '错误率',
  205. // '最大延迟(ms)',
  206. // "延迟比例",
  207. '中位延迟'
  208. // '90分位延迟',
  209. // '99分位延迟'
  210. ],
  211. colData: [
  212. { title: '业务名', istrue: false },
  213. { title: '调用占比', istrue: false },
  214. { title: 'SpanName', istrue: false },
  215. { title: 'rpm', istrue: false },
  216. { title: '请求总数', istrue: false },
  217. { title: '错误率', istrue: false },
  218. { title: '最大延迟(ms)', istrue: false },
  219. { title: '平均延迟(ms)', istrue: false },
  220. // { title: "延迟比例", istrue: false },
  221. { title: '中位延迟', istrue: false }
  222. ],
  223. isUpdate: false,
  224. isflag: false,
  225. tableflag: false,
  226. isShowServiceSpaceDrawer: false,
  227. topflag: false,
  228. detailData: {},
  229. drawerDetail: false,
  230. tableLoading: false,
  231. // 表格高度
  232. tableHeight: '',
  233. // 数据总数
  234. tableCount: 0,
  235. serveceMapList: [],
  236. // 应用数据列表
  237. appData: [],
  238. // 遮罩层
  239. loading: false,
  240. // 选中数组
  241. ids: [],
  242. // 非单个禁用
  243. single: true,
  244. // 非多个禁用
  245. multiple: true,
  246. // 总条数
  247. total: 0,
  248. menuIdsChecked: [],
  249. // 弹出层标题
  250. title: '',
  251. // 是否显示弹出层
  252. open: false,
  253. isEdit: false,
  254. // 日期范围
  255. dateRange: [],
  256. // 查询参数
  257. queryParams: {
  258. app_alias: '', // 应用别名
  259. service_name: null, // 服务名称
  260. // duration:'',//最小延迟
  261. // error_rate:'',//最小错误率
  262. // request_total:'',//最低请求量
  263. // node_num:'',//最小节点数量
  264. // access_database: '',//是否涉及数据库
  265. vip: true, // 是否为重点业务
  266. // favor:'',//是否收藏
  267. page_num: 1, // 当前页码
  268. page_size: 10 // 每页条数
  269. },
  270. // 表单参数
  271. form: {
  272. },
  273. // 表单校验
  274. rules: {
  275. name: [
  276. { required: true, message: '接口名称不能为空', trigger: 'blur' }
  277. ],
  278. url: [
  279. { required: true, message: 'URL组不能为空', trigger: 'blur' }
  280. ]
  281. },
  282. appsAction: process.env.VUE_APP_BASE_API + '/api/v1/public/uploadFile',
  283. appsfileList: [],
  284. headers: { 'Authorization': 'Bearer ' + getToken() },
  285. appsItem: {},
  286. expands: [],
  287. rowData: [],
  288. serviceMapTimer: null,
  289. BizStatsQuery: {
  290. biz_id: 0,
  291. start_time: '',
  292. end_time: ''
  293. },
  294. tempList: [],
  295. graphData: {},
  296. graphStatsQuery: {
  297. biz_node_id: 0, // 仅支持传递单个节点,多个节点需要并发请求分别调用
  298. end_time: 1702972800,
  299. start_time: 1702969200
  300. },
  301. graphObj: [],
  302. detailTitle: '',
  303. detailObj: {},
  304. myChartList: [],
  305. myChartboxList: [],
  306. myChartBox2List: [],
  307. currentBussinessId: '', // 当前点击业务id
  308. currentBussinessName: '相关业务'// 当前点击业务名字
  309. }
  310. },
  311. watch: {
  312. '$store.state.time.globalTimes': {
  313. handler(newValue, oldValue) {
  314. if (newValue) {
  315. this.queryParams.start_time = newValue.startTime
  316. this.queryParams.end_time = newValue.endTime
  317. this.BizStatsQuery.start_time = newValue.startTime
  318. this.BizStatsQuery.end_time = newValue.endTime
  319. this.graphStatsQuery.start_time = newValue.startTime
  320. this.graphStatsQuery.end_time = newValue.endTime
  321. this.queryParams.page_num = 1
  322. this.serveceMapList = []
  323. this.getList()
  324. if (newValue.timeOut) {
  325. if (newValue.timeOut == 1) {
  326. clearInterval(this.serviceMapTimer)
  327. } else {
  328. clearInterval(this.serviceMapTimer)
  329. this.Refresh(newValue.timeOut)
  330. }
  331. }
  332. }
  333. },
  334. // immediate: true,
  335. deep: true
  336. },
  337. serveceMapList: {
  338. handler(newVal, oldVal) {
  339. if (newVal) {
  340. this.serveceMapList = newVal
  341. this.tableflag = true
  342. }
  343. },
  344. // immediate: true,
  345. deep: true
  346. }
  347. },
  348. created() {
  349. this.$store.commit('time/setTimeFlag', false)
  350. this.appItem = storage.get('appsItem')
  351. if (JSON.stringify(this.appItem) != '{}') {
  352. this.appItem = storage.get('appsItem')
  353. this.queryParams.app_alias = this.appItem.alias
  354. this.getList()
  355. this.$forceUpdate()
  356. }
  357. this.columnChange()
  358. },
  359. mounted() {
  360. this.$forceUpdate()
  361. },
  362. beforeDestroy() {
  363. clearInterval(this.serviceMapTimer)
  364. this.disposeEcharts(this.myChartList)
  365. this.disposeEcharts(this.myChartboxList)
  366. this.disposeEcharts(this.myChartBox2List)
  367. },
  368. methods: {
  369. // 判断数字是正是负还是零并给出标识
  370. processNumber(num) {
  371. const result = {
  372. value: num,
  373. sign: ''
  374. }
  375. if (num > 0) {
  376. result.sign = 'up'
  377. } else if (num < 0) {
  378. result.value = Math.abs(num) // 返回绝对值
  379. result.sign = 'down'
  380. } else {
  381. result.sign = ''
  382. }
  383. return result
  384. },
  385. getErrRate(error_rate) {
  386. const strErrorRate = numToString(error_rate)
  387. let length = 0
  388. if (strErrorRate !== '0') {
  389. const arr = strErrorRate.split('.')
  390. if (arr.length > 1) {
  391. length = strErrorRate.split('.')[1].length
  392. }
  393. }
  394. if (error_rate == 0) {
  395. return error_rate
  396. } else if (error_rate == 1) {
  397. return error_rate * 100 + '%'
  398. } else if (length <= 2) {
  399. return error_rate * 100 + '%'
  400. } else {
  401. return convertToPercentage(error_rate)
  402. }
  403. function numToString(num) {
  404. let str = num.toString()
  405. if (str.includes('e')) {
  406. const parts = str.split('e')
  407. const base = parts[0]
  408. const exp = parseInt(parts[1])
  409. const decimalPlaces = base.split('.')[1]?.length || 0
  410. const zerosNeeded = Math.abs(exp) - decimalPlaces
  411. if (exp < 0) {
  412. str = '0.' + '0'.repeat(zerosNeeded) + base.replace('.', '')
  413. } else {
  414. str = base + '0'.repeat(zerosNeeded)
  415. }
  416. }
  417. return str
  418. }
  419. function convertToPercentage(value) {
  420. const bnValue = new BigNumber(value)
  421. const percentage = bnValue.multipliedBy(100)// 乘法运算
  422. let roundedPercentage = percentage.decimalPlaces(2, BigNumber.ROUND_FLOOR)// decimalPlaces保留小数位
  423. // 如果四舍五入后的值小于原始值,手动增加 0.01
  424. if (roundedPercentage.isLessThan(percentage)) { // 判断是否小于
  425. roundedPercentage = roundedPercentage.plus(0.01)
  426. }
  427. return `${roundedPercentage.toFixed(2)}%`
  428. }
  429. },
  430. handleUpdateName() {
  431. this.open = true
  432. this.form = this.detailObj
  433. },
  434. // 控制列的显示和隐藏
  435. columnChange(val) {
  436. this.colData.filter((i) => {
  437. if (this.colSelect.indexOf(i.title) !== -1) {
  438. i.istrue = true
  439. } else {
  440. i.istrue = false
  441. }
  442. })
  443. },
  444. Refresh(timeOut) {
  445. this.serviceMapTimer = setInterval(() => {
  446. this.getList()
  447. }, timeOut)
  448. },
  449. handleClose() {
  450. this.isShowServiceSpaceDrawer = false
  451. },
  452. drawerCloseDetail() {
  453. this.drawerDetail = false
  454. },
  455. handleRowClick(row, column, event) {
  456. this.currentBussinessId = row.id
  457. this.currentBussinessName = row.name
  458. this.isShowServiceSpaceDrawer = true
  459. },
  460. getListBizGraph(id) {
  461. this.loading = true
  462. listBizGraph({ biz_id: id }).then((res) => {
  463. this.graphData = {}
  464. if (res.code == 200) {
  465. const arr = res.data
  466. console.log(10000001111, arr)
  467. if (arr.length > 0) {
  468. const List = this.handelListBizData(arr)
  469. this.graphData = List[0]
  470. this.loading = false
  471. } else {
  472. this.graphData = {}
  473. }
  474. }
  475. })
  476. },
  477. handelListBizData(data) {
  478. data.forEach((v, k) => {
  479. // v.collapsed = false;
  480. v.id = v.id.toString()
  481. v.name = v.name
  482. v.label = v.stats.duration != undefined ? (v.stats.duration).toString() : ''
  483. v.currency = 'ms'
  484. v.rate = v.stats.success_rate
  485. v.status = v.stats.success_rate >= 0.6 ? 'B' : v.stats.success_rate == 0 ? 'DI' : 'R'
  486. v.variableValue = v.stats.success_rate
  487. v.variableUp = v.stats.success_rate_up
  488. if (v.children != undefined && v.children.length > 0) {
  489. v.children = this.handelListBizData(v.children)
  490. }
  491. })
  492. return data
  493. },
  494. handleData(data) {
  495. console.log(3000, data)
  496. data.forEach((v, k) => {
  497. v.id = v.biz_id
  498. v.collapsed = false
  499. v.name = v.name
  500. v.label = v.service_name
  501. v.currency = 'ms'
  502. v.rate = v.duration_persent
  503. v.status = (v.status_code == 'STATUS_CODE_ERROR' || v.events_timestamp.length > 0 || v.http_code > 399) ? 'R' : (v.duration > 500) ? 'Y' : 'G'
  504. v.variableValue = v.duration_persent
  505. // v.status_code = 'UNSET'
  506. if (v.children != undefined && v.children.length > 0) {
  507. v.children = this.handleData(v.children)
  508. }
  509. })
  510. return data
  511. },
  512. // 根据行的id判断
  513. getRowKeys(row) {
  514. return row.id
  515. },
  516. clickRowHandle(row, column, event) {
  517. // alert('a')
  518. },
  519. clickRowHandleNode(item) {
  520. this.detailData = item
  521. this.drawerDetail = true
  522. },
  523. toggle() {
  524. this.$router.push({
  525. path: 'dashboard'
  526. })
  527. },
  528. // 加载更多
  529. loadMore() {
  530. if (!this.loading) {
  531. this.loading = true
  532. if (this.serveceMapList.length < this.tableCount) {
  533. this.queryParams.page_num++
  534. this.getList()
  535. } else {
  536. // this.$message("已加载完所有的数据!");
  537. this.loading = false
  538. }
  539. }
  540. },
  541. // 获取左侧table 数据
  542. getList() {
  543. const _this = this
  544. this.loading = true
  545. this.myChartList = []
  546. this.myChartboxList = []
  547. this.myChartBox2List = []
  548. getNewBusinessList(this.queryParams).then(res => {
  549. if (res.code == 200) {
  550. this.serveceMapList = res.data.list || []
  551. this.tableCount = res.data.total || 0
  552. this.loading = false
  553. if (_this.serveceMapList.length > 0) {
  554. for (let i = 0; i < _this.serveceMapList.length; i++) {
  555. this.BizStatsQuery.biz_id = _this.serveceMapList[i].id
  556. listBizStats(this.BizStatsQuery).then(response => {
  557. if (response.code == 200) {
  558. if (response.data.biz_id != undefined) {
  559. if (_this.serveceMapList[i].id == response.data.biz_id) {
  560. _this.serveceMapList[i] = Object.assign({}, _this.serveceMapList[i], response.data)
  561. _this.isUpdate = !_this.isUpdate
  562. }
  563. }
  564. }
  565. })
  566. }
  567. }
  568. this.$nextTick(() => {
  569. this.$forceUpdate()
  570. })
  571. }
  572. })
  573. },
  574. beforeUpload(file) {
  575. const isRightSize = file.size / 1024 / 1024 < 2
  576. if (!isRightSize) {
  577. this.$message.error('文件大小超过 2MB')
  578. }
  579. return isRightSize
  580. },
  581. uploadSuccess(response, file, fileList) {
  582. this.form.imgUrl = process.env.VUE_APP_BASE_API + response.data.full_path
  583. },
  584. // 取消按钮
  585. cancel() {
  586. this.open = false
  587. this.reset()
  588. },
  589. // 表单重置
  590. reset() {
  591. this.form = {
  592. id: undefined,
  593. name: undefined,
  594. url: undefined,
  595. type: undefined,
  596. module: undefined,
  597. summary: undefined,
  598. favor: undefined
  599. }
  600. this.resetForm('form')
  601. },
  602. /** 搜索按钮操作 */
  603. handleQuery() {
  604. this.queryParams.page_num = 1
  605. this.serveceMapList = []
  606. this.tempList = []
  607. this.getList()
  608. },
  609. /** 重置按钮操作 */
  610. resetQuery() {
  611. this.dateRange = []
  612. this.resetForm('queryForm')
  613. this.handleQuery()
  614. },
  615. // 多选框选中数据
  616. handleSelectionChange(selection) {
  617. this.ids = selection.map(item => item.id)
  618. this.single = selection.length !== 1
  619. this.multiple = !selection.length
  620. },
  621. /** 新增按钮操作 */
  622. handleAdd() {
  623. this.reset()
  624. // this.getMenuTreeselect(0)
  625. this.open = true
  626. this.title = '新增URL组'
  627. this.isEdit = false
  628. },
  629. handleSortChang(column, prop, order) {
  630. prop = column.prop
  631. order = column.order
  632. if (order === 'descending') {
  633. this.queryParams[prop + 'Order'] = 'desc'
  634. } else if (order === 'ascending') {
  635. this.queryParams[prop + 'Order'] = 'asc'
  636. } else {
  637. this.queryParams[prop + 'Order'] = undefined
  638. }
  639. this.getList()
  640. },
  641. /** 修改按钮操作 */
  642. handleUpdate(row) {
  643. this.reset()
  644. // this.form = row;
  645. this.form.name = row.name
  646. this.form.id = row.id
  647. this.title = '修改业务别名'
  648. this.isEdit = true
  649. this.open = true
  650. },
  651. /** 提交按钮 */
  652. submitForm: function() {
  653. this.$refs['form'].validate(valid => {
  654. if (valid) {
  655. if (this.form.id !== undefined || this.form.id != 0) {
  656. updateBiz(this.form, this.form.id).then(response => {
  657. if (response.code === 200) {
  658. this.msgSuccess(response.msg)
  659. this.open = false
  660. this.drawer = false
  661. this.queryParams.page_num = 1
  662. this.serveceMapList = []
  663. this.tempList = []
  664. this.getList()
  665. } else {
  666. this.msgError(response.msg)
  667. }
  668. })
  669. } else {
  670. addUrlMapping(this.form).then(response => {
  671. if (response.code === 200) {
  672. this.msgSuccess(response.msg)
  673. this.open = false
  674. this.queryParams.page_num = 1
  675. this.serveceMapList = []
  676. this.tempList = []
  677. this.getList()
  678. } else {
  679. this.msgError(response.msg)
  680. }
  681. })
  682. }
  683. }
  684. })
  685. },
  686. /** 删除按钮操作 */
  687. handleDelete(row) {
  688. // const id = (row.id && [row.id]) || this.ids
  689. const id = row.id
  690. this.$confirm('是否确认删除接口映射编号为"' + id + '"的数据项?', '警告', {
  691. confirmButtonText: '确定',
  692. cancelButtonText: '取消',
  693. type: 'warning'
  694. }).then(function() {
  695. return delBiz(id)
  696. }).then((response) => {
  697. this.queryParams.page_num = 1
  698. this.serveceMapList = []
  699. this.tempList = []
  700. this.msgSuccess(response.msg)
  701. this.getList()
  702. }).catch(function() {})
  703. },
  704. handleFavor(row) {
  705. let favor = ''
  706. if (row.favor == 1) {
  707. favor = '0'
  708. } else if (row.favor == 0) {
  709. favor = '1'
  710. }
  711. favorBiz({ favor: favor }, row.id).then(res => {
  712. if (res.code === 200) {
  713. this.msgSuccess(res.msg)
  714. this.queryParams.page_num = 1
  715. this.serveceMapList = []
  716. this.tempList = []
  717. this.getList()
  718. }
  719. })
  720. },
  721. /** 导出按钮操作 */
  722. handleExport() {
  723. this.$confirm('是否确认导出所有角色数据项?', '警告', {
  724. confirmButtonText: '确定',
  725. cancelButtonText: '取消',
  726. type: 'warning'
  727. }).then(() => {
  728. this.downloadLoading = true
  729. import('@/vendor/Export2Excel').then(excel => {
  730. const tHeader = ['角色编号', '角色名称', '权限字符', '显示顺序', '状态', '创建时间']
  731. const filterVal = ['roleId', 'roleName', 'roleKey', 'roleSort', 'status', 'createdAt']
  732. const list = this.roleList
  733. const data = formatJson(filterVal, list)
  734. excel.export_json_to_excel({
  735. header: tHeader,
  736. data,
  737. filename: '角色管理',
  738. autoWidth: true, // Optional
  739. bookType: 'xlsx' // Optional
  740. })
  741. this.downloadLoading = false
  742. })
  743. })
  744. },
  745. drawEcharts(row, index) {
  746. const option = {
  747. tooltip: {
  748. trigger: 'axis',
  749. confine: false,
  750. appendToBody: true
  751. },
  752. grid: {
  753. top: 10,
  754. left: 0,
  755. right: '4%',
  756. bottom: '-2%',
  757. containLabel: false
  758. },
  759. xAxis: {
  760. type: 'category',
  761. boundaryGap: false,
  762. // data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  763. data: row.duration_stats.time,
  764. show: false
  765. },
  766. yAxis: {
  767. type: 'value',
  768. show: false
  769. },
  770. series: [
  771. {
  772. name: 'P.50',
  773. type: 'line',
  774. stack: 'Total',
  775. symbol: 'none',
  776. // // data: [120, 132, 101, 134, 90, 230, 210]
  777. // data: Number(row.duration_stats.p50).toFixed(2)
  778. data: row.duration_stats.p50
  779. },
  780. {
  781. name: 'P.95',
  782. type: 'line',
  783. stack: 'Total',
  784. symbol: 'none',
  785. // data: [320, 332, 301, 334, 390, 330, 320]
  786. // data: Number(row.duration_stats.p90).toFixed(2)
  787. data: row.duration_stats.p90
  788. },
  789. {
  790. name: 'P.99',
  791. type: 'line',
  792. stack: 'Total',
  793. symbol: 'none',
  794. // data: [820, 932, 901, 934, 1290, 1330, 1320]
  795. // data: Number(row.duration_stats.p99).toFixed(2)
  796. data: row.duration_stats.p99
  797. }
  798. ]
  799. }
  800. const chartId = 'tiger-' + arguments[2] + '-trend-index' + arguments[1]
  801. this.$nextTick(() => {
  802. const myChart = this.$echarts5.init(document.getElementById(chartId), 'macarons')
  803. myChart.setOption(option)
  804. myChart.resize()
  805. })
  806. },
  807. drawEchartsp5(row, index) {
  808. const that = this
  809. let obj = {}
  810. obj = row
  811. // if(row.quantiles != undefined&&row.quantiles.time !=null){
  812. const option = {
  813. tooltip: {
  814. trigger: 'axis',
  815. confine: false,
  816. appendToBody: true
  817. },
  818. xAxis: {
  819. type: 'category',
  820. boundaryGap: false,
  821. data: obj.quantiles.time,
  822. show: false
  823. },
  824. grid: {
  825. top: '15%',
  826. bottom: '10%',
  827. left: '1%',
  828. right: '1%'
  829. },
  830. yAxis: {
  831. type: 'value',
  832. show: false
  833. },
  834. series: [
  835. {
  836. name: 'P50',
  837. data: obj.quantiles.p50,
  838. type: 'line',
  839. showSymbol: false,
  840. lineStyle: {
  841. width: 1
  842. },
  843. areaStyle: {
  844. z: 3,
  845. coordinateSystem: 'cartesian2d',
  846. legendHoverLink: true,
  847. clip: true,
  848. color: 'rgba(0, 0, 180, 0.2)'
  849. },
  850. tooltip: {
  851. valueFormatter: function(value) {
  852. return value + ' ms'
  853. }
  854. }
  855. }
  856. ]
  857. }
  858. setTimeout(() => {
  859. this.$nextTick(() => {
  860. const chartId = 'tiger-' + arguments[2] + '-trend-index' + arguments[1]
  861. let myChart = this.$echarts5.getInstanceByDom(document.getElementById(chartId))
  862. if (myChart == null) {
  863. myChart = that.$echarts5.init(document.getElementById(chartId), 'macarons')
  864. }
  865. myChart.dispatchAction({ type: 'hideTip' })
  866. this.myChartList.push(myChart)
  867. option && myChart.setOption(option, true)
  868. // myChart.group = `index${row.id}`
  869. // this.$echarts5.connect(`index${row.id}`)
  870. })
  871. }, 1000)
  872. },
  873. drawEchartsp90(row, index) {
  874. const that = this
  875. let obj = {}
  876. obj = row
  877. // if(row.quantiles != undefined&&row.quantiles.time !=null){
  878. const option = {
  879. tooltip: {
  880. trigger: 'axis',
  881. confine: false,
  882. appendToBody: true
  883. },
  884. xAxis: {
  885. type: 'category',
  886. boundaryGap: false,
  887. data: obj.quantiles.time,
  888. show: false
  889. },
  890. grid: {
  891. top: '15%',
  892. bottom: '10%',
  893. left: '1%',
  894. right: '1%'
  895. },
  896. yAxis: {
  897. type: 'value',
  898. show: false
  899. },
  900. series: [
  901. {
  902. name: 'P90',
  903. data: obj.quantiles.p90,
  904. type: 'line',
  905. showSymbol: false,
  906. lineStyle: {
  907. width: 1
  908. },
  909. areaStyle: {
  910. z: 3,
  911. coordinateSystem: 'cartesian2d',
  912. legendHoverLink: true,
  913. clip: true,
  914. color: 'rgba(0, 0, 180, 0.3)'
  915. },
  916. tooltip: {
  917. valueFormatter: function(value) {
  918. return value + ' ms'
  919. }
  920. }
  921. }
  922. ]
  923. }
  924. setTimeout(() => {
  925. const chartId = 'tiger-' + arguments[2] + '-trend-index' + arguments[1]
  926. let myChartbox = this.$echarts5.getInstanceByDom(document.getElementById(chartId))
  927. if (myChartbox == null) {
  928. myChartbox = that.$echarts5.init(document.getElementById(chartId), 'ninebox')
  929. }
  930. this.myChartboxList.push(myChartbox)
  931. myChartbox.dispatchAction({ type: 'hideTip' })
  932. option && myChartbox.setOption(option, true)
  933. // myChartbox.group = `index${row.id}`
  934. // this.$echarts5.connect(`index${row.id}`)
  935. }, 1000)
  936. // }
  937. },
  938. drawEchartsp99(row, index) {
  939. const that = this
  940. // if(row.quantiles != undefined&&row.quantiles.time !=null){
  941. const option = {
  942. tooltip: {
  943. trigger: 'axis',
  944. confine: false,
  945. appendToBody: true
  946. },
  947. xAxis: {
  948. type: 'category',
  949. boundaryGap: false,
  950. data: row.quantiles.time,
  951. show: false
  952. },
  953. grid: {
  954. top: '15%',
  955. bottom: '10%',
  956. left: '1%',
  957. right: '1%'
  958. },
  959. yAxis: {
  960. type: 'value',
  961. show: false
  962. },
  963. animation: true,
  964. animationDuration: 1000,
  965. series: [
  966. {
  967. name: 'P99',
  968. data: row.quantiles.p99,
  969. type: 'line',
  970. showSymbol: false,
  971. lineStyle: {
  972. width: 1
  973. },
  974. areaStyle: {
  975. z: 3,
  976. coordinateSystem: 'cartesian2d',
  977. legendHoverLink: true,
  978. clip: true,
  979. color: 'rgba(0, 0, 180, 0.3)'
  980. },
  981. tooltip: {
  982. valueFormatter: function(value) {
  983. return value + ' ms'
  984. }
  985. }
  986. }
  987. ]
  988. }
  989. setTimeout(() => {
  990. const chartId = 'tiger-' + arguments[2] + '-trend-index' + arguments[1]
  991. let myChartBox2 = this.$echarts5.getInstanceByDom(document.getElementById(chartId))
  992. if (myChartBox2 == null) {
  993. myChartBox2 = that.$echarts5.init(document.getElementById(chartId), 'hundredbox')
  994. }
  995. this.myChartBox2List.push(myChartBox2)
  996. myChartBox2.dispatchAction({ type: 'hideTip' })
  997. option && myChartBox2.setOption(option, true)
  998. // myChartBox2.group = `index${row.id}`
  999. // this.$echarts5.connect(`index${row.id}`)
  1000. }, 1000)
  1001. // }
  1002. },
  1003. drawEchartsScale(row) {
  1004. const _this = this
  1005. let myChartScale = this.$echarts5.getInstanceByDom(document.getElementById(chartId))
  1006. if (myChartScale == null) {
  1007. myChartScale = this.$echarts5.init(document.getElementById('scaleMain'))
  1008. }
  1009. // 绘制趋势echarts
  1010. const option = {
  1011. tooltip: {
  1012. trigger: 'axis',
  1013. confine: false,
  1014. appendToBody: true,
  1015. show: true,
  1016. formatter: function(params) {
  1017. storage.set('paramsValue', params)
  1018. const axisValueLabel = params[0].axisValueLabel
  1019. let str0 = ''
  1020. params.forEach((item, idx) => {
  1021. // str1+=`${}`
  1022. str0 += `${item.marker}${item.seriesName}<span style='margin-left:30px;text-align:right;font-weight:400'>${item.data}</span>`
  1023. switch (idx) {
  1024. case 0:
  1025. str0
  1026. break
  1027. case 1:
  1028. str0
  1029. break
  1030. default:
  1031. str0
  1032. }
  1033. str0 += idx === params.length - 1 ? '' : '<br/>'
  1034. })
  1035. return axisValueLabel + '<br>' + str0
  1036. }
  1037. },
  1038. title: {
  1039. text: '延迟比例',
  1040. // subtext: 'ms',
  1041. textStyle: {
  1042. fontSize: 14
  1043. }
  1044. // triggerEvent: true,
  1045. },
  1046. grid: {
  1047. // top:'5%',
  1048. left: '3%',
  1049. right: '6%',
  1050. bottom: '1%',
  1051. containLabel: true
  1052. },
  1053. xAxis: {
  1054. type: 'category',
  1055. boundaryGap: false,
  1056. data: row.quantiles.time,
  1057. axisLabel: {
  1058. textStyle: {
  1059. fontSize: 12,
  1060. textAlign: 'center'
  1061. },
  1062. formatter: function(params) {
  1063. let newParams = ''
  1064. const dateStr = params.substring(0, 10)
  1065. // dateStr = dateStr.replace(/\-/g, function(match) {
  1066. // return match.replace(/\-/g, '.');
  1067. // });
  1068. const timeStr = params.substring(11, 19)
  1069. newParams = dateStr + '\n' + timeStr
  1070. return newParams
  1071. }
  1072. }
  1073. },
  1074. yAxis: {
  1075. type: 'value',
  1076. scale: true,
  1077. gridIndex: 0,
  1078. axisLabel: {
  1079. formatter: '{value}'
  1080. },
  1081. axisLine: {
  1082. show: true
  1083. },
  1084. axisTick: {
  1085. show: true
  1086. },
  1087. splitLine: {
  1088. show: true
  1089. }
  1090. },
  1091. series: [
  1092. {
  1093. name: 'P.50',
  1094. type: 'line',
  1095. stack: 'Total',
  1096. symbol: 'none',
  1097. // symbol: 'emptyCircle',//拐点
  1098. data: row.quantiles.p50
  1099. },
  1100. {
  1101. name: 'P.95',
  1102. type: 'line',
  1103. stack: 'Total',
  1104. symbol: 'none', // 拐点
  1105. // symbol: 'emptyCircle',//拐点
  1106. data: row.quantiles.p90
  1107. },
  1108. {
  1109. name: 'P.99',
  1110. type: 'line',
  1111. stack: 'Total',
  1112. symbol: 'none', // 拐点
  1113. // symbol: 'emptyCircle',//拐点
  1114. data: row.quantiles.p99
  1115. }
  1116. ]
  1117. }
  1118. myChartScale.setOption(option)
  1119. },
  1120. disposeEcharts(echartsList) {
  1121. if (echartsList.length > 0) {
  1122. for (let i = 0; i < echartsList.length; i++) {
  1123. echartsList[i].dispose()
  1124. }
  1125. }
  1126. }
  1127. }
  1128. }
  1129. </script>
  1130. <style lang="scss" scoped>
  1131. .iconfont {
  1132. font-family: "iconfont" !important;
  1133. font-size: 20px;
  1134. font-style: normal;
  1135. -webkit-font-smoothing: antialiased;
  1136. -moz-osx-font-smoothing: grayscale;
  1137. }
  1138. .icon-jiantou_zuoyouqiehuan:before {
  1139. content: "\eb0d";
  1140. }
  1141. .icon-qiehuan:before {
  1142. content: "\e606";
  1143. }
  1144. .icon-qiehuan1:before {
  1145. content: "\e789";
  1146. }
  1147. ::v-deep .el-card__body{
  1148. position: relative !important;
  1149. }
  1150. .back{
  1151. position: absolute;
  1152. top:10px;
  1153. right:10px;
  1154. width:20px;
  1155. height:20px;
  1156. }
  1157. .tiger-trend-charts {
  1158. height: 40px;
  1159. // width:100px;
  1160. min-width: 80px;
  1161. max-width: 140px;
  1162. }
  1163. ::v-deep .el-icon-star-on{
  1164. font-size: 16px;
  1165. }
  1166. .more{
  1167. margin:16px 0;
  1168. text-align: center;
  1169. font-size: 16px;
  1170. color:#1890ff;
  1171. cursor: pointer;
  1172. }
  1173. .nomore{
  1174. color:#999;
  1175. }
  1176. .green_small{
  1177. display: inline-block;
  1178. width:8px;
  1179. height: 8px;
  1180. border-radius: 50%;
  1181. background:#67C23A;
  1182. margin-right:8px;
  1183. }
  1184. .red_small{
  1185. width:8px;
  1186. height: 8px;
  1187. display: inline-block;
  1188. border-radius: 50%;
  1189. background:#F56C6C;
  1190. margin-right:8px;
  1191. }
  1192. .flexWrap{
  1193. // display:flex;
  1194. // justify-content: space-between;
  1195. }
  1196. .flex-left{
  1197. // width:calc (100% - 720px);
  1198. width:100%;
  1199. }
  1200. .flex-right{
  1201. width:100%;
  1202. // width:39.99%;
  1203. // width: 720px;
  1204. }
  1205. .noData{
  1206. width: 100%;
  1207. height: calc(100vh - 120px);
  1208. background: #fff;
  1209. }
  1210. .noData_title{
  1211. margin-bottom: 0px;
  1212. padding: 2px 5px;
  1213. text-overflow: ellipsis;
  1214. overflow: hidden;
  1215. white-space: nowrap;
  1216. font-size: 14px;
  1217. font-weight: 500;
  1218. line-height: 1.57143;
  1219. font-family: Inter, Helvetica, Arial, sans-serif;
  1220. }
  1221. ::v-deep .el-drawer__title{
  1222. margin-top:50px;
  1223. }
  1224. .table_bg{
  1225. background: #e8f4ff;
  1226. color:#1890ff;
  1227. padding:0 4px;
  1228. }
  1229. .table_bg_red{
  1230. background-color: #fef0f0;
  1231. color: #f56c6c;
  1232. padding:0 8px;
  1233. }
  1234. .table_bg_yellow{
  1235. background-color: #fdf6ec;
  1236. color: #e6a23c;
  1237. padding:0 4px;
  1238. }
  1239. .table-num-box{
  1240. height:20px;
  1241. line-height:30px;
  1242. }
  1243. .table-day-rate-box{
  1244. height:20px;
  1245. line-height:20px;
  1246. font-size:10px;
  1247. }
  1248. .up{
  1249. color:#ea463d;
  1250. }
  1251. .down{
  1252. color:#00b54f;
  1253. }
  1254. .el-icon-up:before{
  1255. content:'\e6e6'
  1256. }
  1257. .el-icon-down:before{
  1258. content:'\e6eb'
  1259. }
  1260. .TableBox ::v-deep .el-table .cell{
  1261. line-height: 40px !important;
  1262. padding-left: 1px;
  1263. padding-right: 1px;
  1264. cursor: pointer;
  1265. }
  1266. .TableBox ::v-deep .el-table--medium .el-table__cell {
  1267. padding: 2px 0!important;
  1268. }
  1269. // .P_box{
  1270. // width:58px;
  1271. // min-width: 58px;
  1272. // text-align: right;
  1273. // overflow: hidden;
  1274. // text-overflow: ellipsis;
  1275. // white-space:nowrap;
  1276. // padding-right: 10px;
  1277. // box-sizing: border-box;
  1278. // }
  1279. .P_box{
  1280. // width:68px;
  1281. min-width: 68px;
  1282. max-width: 100px;
  1283. // text-align: right;
  1284. text-align:left;
  1285. overflow: hidden;
  1286. text-overflow: ellipsis;
  1287. white-space:nowrap;
  1288. padding-right: 10px;
  1289. box-sizing: border-box;
  1290. margin-left: 10px;
  1291. }
  1292. .TableBox ::v-deep .el-table__cell.column_one .cell{
  1293. padding-left:10px !important;
  1294. padding-right:10px !important;
  1295. }
  1296. </style>