Showing
11 changed files
with
494 additions
and
14 deletions
@@ -5,6 +5,8 @@ | @@ -5,6 +5,8 @@ | ||
5 | @import "../css/cacheData.css"; | 5 | @import "../css/cacheData.css"; |
6 | /*告警消除处理*/ | 6 | /*告警消除处理*/ |
7 | @import "../css/alarmsClear.css"; | 7 | @import "../css/alarmsClear.css"; |
8 | +/*日志详情*/ | ||
9 | +@import "../css/esData.css"; | ||
8 | 10 | ||
9 | .d-flex { | 11 | .d-flex { |
10 | display: flex; | 12 | display: flex; |
1 | +.esData-detail-container{ | ||
2 | + padding:0 15px; | ||
3 | + min-height: 500px; | ||
4 | + max-height:800px; | ||
5 | + overflow: auto; | ||
6 | +} | ||
7 | +.esData-detail-container .info-title{ | ||
8 | + display: flex; | ||
9 | + justify-content: space-between; | ||
10 | + margin-bottom: 10px; | ||
11 | + padding-top:10px; | ||
12 | + font-size: 16px; | ||
13 | + margin-top:10px; | ||
14 | +} | ||
15 | +.esData-detail-container .info-content{ | ||
16 | + margin-bottom: 5px; | ||
17 | +} | ||
18 | +.esData-detail-container .info-content-body{ | ||
19 | + background: #ffffff; | ||
20 | + padding:10px 30px; | ||
21 | +} | ||
22 | +.esData-detail-container .content-body-info{ | ||
23 | + display: flex; | ||
24 | + align-items: center; | ||
25 | + justify-content: flex-start; | ||
26 | + flex-wrap: wrap; | ||
27 | +} | ||
28 | +.esData-detail-container .info-item{ | ||
29 | + width:33%; | ||
30 | + margin:8px 0; | ||
31 | + text-align: left; | ||
32 | +} | ||
33 | +.esData-detail-info-content{ | ||
34 | + text-align: left; | ||
35 | +} |
@@ -103,6 +103,12 @@ const routes = [{ | @@ -103,6 +103,12 @@ const routes = [{ | ||
103 | name: 'busDoc', | 103 | name: 'busDoc', |
104 | component: () => myImport('views/busDoc/index') | 104 | component: () => myImport('views/busDoc/index') |
105 | }, | 105 | }, |
106 | + //日志 | ||
107 | + { | ||
108 | + path: '/esData', | ||
109 | + name: 'esDataIndex', | ||
110 | + component: () => myImport('views/esData/index'), | ||
111 | + }, | ||
106 | ]; | 112 | ]; |
107 | 113 | ||
108 | // hash模式: createWebHashHistory | 114 | // hash模式: createWebHashHistory |
@@ -271,22 +271,28 @@ global.openDetail = (resId, resType, proxy) => { | @@ -271,22 +271,28 @@ global.openDetail = (resId, resType, proxy) => { | ||
271 | 271 | ||
272 | // 获取资源详情 | 272 | // 获取资源详情 |
273 | proxy.$http.get(`/api-web/v32/res/detail/${resId}`, {}, function (res) { | 273 | proxy.$http.get(`/api-web/v32/res/detail/${resId}`, {}, function (res) { |
274 | - if (res && res.map) { | ||
275 | - let data = res.map; | ||
276 | - | ||
277 | - provider = data.provider; | ||
278 | - ip = data.ip; | ||
279 | - resTypeName = data.resTypeName; | ||
280 | - adminName = data.adminName; | ||
281 | - manageIp = data.manageIp; | ||
282 | - collProtocol = data.collProtocol; | ||
283 | - name = data.resName; | ||
284 | - if(resType == ''){ | ||
285 | - resType = data.resType; | 274 | + if(res && res.success){ |
275 | + if (res && res.map) { | ||
276 | + let data = res.map; | ||
277 | + | ||
278 | + provider = data.provider; | ||
279 | + ip = data.ip; | ||
280 | + resTypeName = data.resTypeName; | ||
281 | + adminName = data.adminName; | ||
282 | + manageIp = data.manageIp; | ||
283 | + collProtocol = data.collProtocol; | ||
284 | + name = data.resName; | ||
285 | + if(resType == ''){ | ||
286 | + resType = data.resType; | ||
287 | + } | ||
288 | + | ||
289 | + lyaui.commonCols.detailPage(resId, resType, editFlag, provider, name, ip, resTypeName, adminName, manageIp, collProtocol); | ||
286 | } | 290 | } |
291 | + }else{ | ||
292 | + proxy.$global.showMsg('该资源暂未监控', "error"); | ||
287 | 293 | ||
288 | - lyaui.commonCols.detailPage(resId, resType, editFlag, provider, name, ip, resTypeName, adminName, manageIp, collProtocol); | ||
289 | } | 294 | } |
295 | + | ||
290 | }); | 296 | }); |
291 | } | 297 | } |
292 | 298 |
hg-monitor-web-base/src/main/resources/static/vue3/src/views/esData/esDataDetail/index.html
0 → 100644
1 | +<div class="esData-detail-container"> | ||
2 | + <el-descriptions | ||
3 | + class="" | ||
4 | + title="日志信息" | ||
5 | + :column="2" | ||
6 | + :size="size" | ||
7 | + border | ||
8 | + > | ||
9 | + <el-descriptions-item> | ||
10 | + <template #label> | ||
11 | + <div class="cell-item"> | ||
12 | + 资源名称 | ||
13 | + </div> | ||
14 | + </template> | ||
15 | + {{detail.resName}} | ||
16 | + </el-descriptions-item> | ||
17 | + <el-descriptions-item> | ||
18 | + <template #label> | ||
19 | + <div class="cell-item"> | ||
20 | + IP地址 | ||
21 | + </div> | ||
22 | + </template> | ||
23 | + {{detail.host}} | ||
24 | + </el-descriptions-item> | ||
25 | + <el-descriptions-item> | ||
26 | + <template #label> | ||
27 | + <div class="cell-item"> | ||
28 | + 资源类型 | ||
29 | + </div> | ||
30 | + </template> | ||
31 | + {{detail.resTypeName}} | ||
32 | + </el-descriptions-item> | ||
33 | + <el-descriptions-item> | ||
34 | + <template #label> | ||
35 | + <div class="cell-item"> | ||
36 | + 日志来源 | ||
37 | + </div> | ||
38 | + </template> | ||
39 | + {{detail.type}} | ||
40 | + </el-descriptions-item> | ||
41 | + <el-descriptions-item> | ||
42 | + <template #label> | ||
43 | + <div class="cell-item"> | ||
44 | + 日志类型 | ||
45 | + </div> | ||
46 | + </template> | ||
47 | + {{detail.program}} | ||
48 | + </el-descriptions-item> | ||
49 | + <el-descriptions-item> | ||
50 | + <template #label> | ||
51 | + <div class="cell-item"> | ||
52 | + 采集时间 | ||
53 | + </div> | ||
54 | + </template> | ||
55 | + {{detail.dbTimeStr}} | ||
56 | + </el-descriptions-item> | ||
57 | + <el-descriptions-item> | ||
58 | + <template #label> | ||
59 | + <div class="cell-item"> | ||
60 | + 日志时间 | ||
61 | + </div> | ||
62 | + </template> | ||
63 | + {{detail.timestamp}} | ||
64 | + </el-descriptions-item> | ||
65 | + </el-descriptions> | ||
66 | + <div class="info-title"> | ||
67 | + <span style="font-weight:bold">日志内容</span> | ||
68 | + </div> | ||
69 | + <div class="esData-detail-info-content" v-html="detail.message"> | ||
70 | + </div> | ||
71 | +</div> |
hg-monitor-web-base/src/main/resources/static/vue3/src/views/esData/esDataDetail/index.js
0 → 100644
1 | +export default { | ||
2 | + name: 'esDataDetail', | ||
3 | + template: '', | ||
4 | + components: { | ||
5 | + | ||
6 | + }, | ||
7 | + props: { | ||
8 | + detail:{ | ||
9 | + type:Object, | ||
10 | + default: {} | ||
11 | + } | ||
12 | + }, | ||
13 | + setup(props, {attrs, slots, emit}) { | ||
14 | + const {proxy} = Vue.getCurrentInstance(); | ||
15 | + | ||
16 | + // 挂载完 | ||
17 | + Vue.onMounted(() => { | ||
18 | + }) | ||
19 | + | ||
20 | + | ||
21 | + return { | ||
22 | + | ||
23 | + } | ||
24 | + } | ||
25 | + | ||
26 | +} |
1 | +<div class="container" :style="{'height':height+'px','max-height':height+'px'}"> | ||
2 | + <div class="cm-card" :style="{'min-height':height+'px','max-height':height+'px','height':'100%','padding-top':'3px'}"> | ||
3 | + <div class="search"> | ||
4 | + <div class="condition"> | ||
5 | + <el-form-item > | ||
6 | + <el-input v-model="search.keyword" placeholder="=资源名称、日志内容="></el-input> | ||
7 | + </el-form-item> | ||
8 | + <el-form-item > | ||
9 | + <el-dropdown> | ||
10 | + <cm-res-type-tree-input multiple clearable collapseTags @callback="getResType"/> | ||
11 | + </el-dropdown> | ||
12 | + </el-form-item> | ||
13 | + <el-form-item > | ||
14 | + <el-select v-model="search.program" class="m-2" placeholder="日志类型" clearable> | ||
15 | + <el-option | ||
16 | + v-for="item in logTypeData" | ||
17 | + :key="item.ddicCode" | ||
18 | + :label="item.ddicName" | ||
19 | + :value="item.ddicCode" | ||
20 | + /> | ||
21 | + </el-select> | ||
22 | + </el-form-item> | ||
23 | + | ||
24 | + <el-form-item> | ||
25 | + <el-date-picker | ||
26 | + v-model="search.dateTime" | ||
27 | + type="datetimerange" | ||
28 | + range-separator="-" | ||
29 | + start-placeholder="开始时间" | ||
30 | + end-placeholder="结束时间" | ||
31 | + format="YYYY-MM-DD HH:mm:ss" | ||
32 | + value-format="YYYY-MM-DD HH:mm:ss" | ||
33 | + /> | ||
34 | + </el-form-item> | ||
35 | + <el-form-item > | ||
36 | + <el-button @click="getDataList">查询</el-button> | ||
37 | + </el-form-item> | ||
38 | + </div> | ||
39 | + </div> | ||
40 | + | ||
41 | + <div class="search-table"> | ||
42 | + <cm-table-page :columns="tableData.columns" :dataList="tableData.dataList" | ||
43 | + :showIndex="true" | ||
44 | + :total="tableData.count" | ||
45 | + @loaddata = "loaddata" | ||
46 | + :showSelection="true" | ||
47 | + :showBorder="true" | ||
48 | + :loading="false" | ||
49 | + :pageSize="pageSize" | ||
50 | + :showPage="true" | ||
51 | + :showTools="true" | ||
52 | + :height="height - 110"> | ||
53 | + <template #default="{row,prop,column}"> | ||
54 | + <div v-if="prop == 'resName'"> | ||
55 | + <span class="resName-span" style="cursor: pointer;color:#1e9fff" @click="goResDetail(row.resId,row.resName,row.resType)">{{row.resName}}</span> | ||
56 | + </div> | ||
57 | + <div v-if="prop == 'message'" > | ||
58 | + <div v-html="row.message" style="overflow: hidden; text-overflow: ellipsis;display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical;"></div> | ||
59 | + </div> | ||
60 | + </template> | ||
61 | + <template #tools="{scope}"> | ||
62 | + <div class="list-handle"> | ||
63 | + <span class="icon-bg"> | ||
64 | + <i class="el-icon-view" title="查看" @click="handleView(scope.row)"></i> | ||
65 | + </span> | ||
66 | + </div> | ||
67 | + </template> | ||
68 | + </cm-table-page> | ||
69 | + </div> | ||
70 | + </div> | ||
71 | +</div> | ||
72 | + | ||
73 | +<!--弹框--> | ||
74 | +<cm-dialog :title="dialog.title" width="60%" :showDialogVisible="dialog.show" @hidedialog="hideDialog" :showFooter="false"> | ||
75 | + <template v-slot> | ||
76 | + <esDataDetail :detail="dialog.detail" /> | ||
77 | + </template> | ||
78 | +</cm-dialog> | ||
79 | + |
1 | +export default { | ||
2 | + name: 'esDataIndex', | ||
3 | + template: '', | ||
4 | + components: { | ||
5 | + 'esDataDetail': Vue.defineAsyncComponent( | ||
6 | + () => myImport('views/esData/esDataDetail/index') | ||
7 | + ) | ||
8 | + }, | ||
9 | + props: [], | ||
10 | + setup(props, {attrs, slots, emit}) { | ||
11 | + const {proxy} = Vue.getCurrentInstance(); | ||
12 | + let height = Vue.ref(window.innerHeight); | ||
13 | + let dateTime=Vue.ref([]) | ||
14 | + let search = Vue.ref({ | ||
15 | + program:'', | ||
16 | + sortBy:'dbTime', | ||
17 | + scopeBy:'dbTime', | ||
18 | + keyword: '', | ||
19 | + type:'syslog', | ||
20 | + pageNum: 1, | ||
21 | + pageSize: 20, | ||
22 | + dateTime:[], | ||
23 | + resType:'', | ||
24 | + }); | ||
25 | + let dialog = Vue.ref({ | ||
26 | + title : "日志详情", | ||
27 | + show:false, | ||
28 | + esId : '' | ||
29 | + }); | ||
30 | + //表格字段 | ||
31 | + let tableData = Vue.ref({ | ||
32 | + count:0, | ||
33 | + dataList: [], | ||
34 | + columns: [ | ||
35 | + { | ||
36 | + prop: 'timestamp', | ||
37 | + label: '日志时间', | ||
38 | + sortable: true, | ||
39 | + align: 'center', | ||
40 | + width: '250', | ||
41 | + }, | ||
42 | + { | ||
43 | + prop: 'resName', | ||
44 | + label: '资源名称', | ||
45 | + sortable: true, | ||
46 | + align: 'center', | ||
47 | + width: '250' | ||
48 | + }, | ||
49 | + { | ||
50 | + prop: 'resTypeName', | ||
51 | + label: '资源类型', | ||
52 | + sortable: true, | ||
53 | + align: 'center', | ||
54 | + width: '200' | ||
55 | + }, { | ||
56 | + prop: 'host', | ||
57 | + label: 'IP地址', | ||
58 | + sortable: true, | ||
59 | + align: 'center', | ||
60 | + width: '200' | ||
61 | + }, { | ||
62 | + prop: 'type', | ||
63 | + label: '日志来源', | ||
64 | + sortable: true, | ||
65 | + align: 'center', | ||
66 | + width: '200' | ||
67 | + }, | ||
68 | + { | ||
69 | + prop: 'program', | ||
70 | + label: '日志类型', | ||
71 | + sortable: true, | ||
72 | + align: 'center', | ||
73 | + width: '200' | ||
74 | + }, | ||
75 | + { | ||
76 | + prop: 'message', | ||
77 | + label: '日志内容', | ||
78 | + sortable: true, | ||
79 | + align: 'center', | ||
80 | + }, | ||
81 | + ] | ||
82 | + }) | ||
83 | + let resTypeArr = Vue.ref([]); | ||
84 | + let getResType = (arr) => { | ||
85 | + var types = arr.map(function (v) { | ||
86 | + return v.id; | ||
87 | + }); | ||
88 | + resTypeArr.value = types; | ||
89 | + search.value.resType=resTypeArr.value.join(','); | ||
90 | + // getDataList(); | ||
91 | + } | ||
92 | + //获取时间点 转年月日的方法 | ||
93 | + const getDateTime=(newDate)=>{ | ||
94 | + let dateTime=''; | ||
95 | + let year=newDate.getFullYear();//获取当前年 | ||
96 | + let month1=(newDate.getMonth()+1)+''; | ||
97 | + let month=timeFormat(month1);//获取当前月 | ||
98 | + let day=timeFormat(newDate.getDate());//获取当前日 | ||
99 | + let hours=timeFormat(newDate.getHours()+'');//获取当前时 | ||
100 | + let minutes=timeFormat(newDate.getMinutes()+'');//获取当前分 | ||
101 | + let seconds=timeFormat(newDate.getSeconds()+'');//获取当前秒 | ||
102 | + dateTime= year+'-'+month+'-'+day;//' '+hours+':'+minutes+':'+seconds; | ||
103 | + return dateTime; | ||
104 | + } | ||
105 | + //转换个位数为 00 | ||
106 | + let timeFormat =(number)=> { | ||
107 | + return number.length == 1 ? ('0' + number) : number | ||
108 | + } | ||
109 | + // 获取列表 | ||
110 | + let getDataList = () => { | ||
111 | + let nowDate=getDateTime(new Date()); | ||
112 | + let startTime=search.value.dateTime[0]?search.value.dateTime[0]:''; | ||
113 | + let endTime=search.value.dateTime[1]?search.value.dateTime[1]:''; | ||
114 | + let startDateStr=startTime?startTime.split(' ')[0]:''; | ||
115 | + let endDateStr=endTime?endTime.split(' ')[0]:''; | ||
116 | + let dateStr=''; | ||
117 | + if(search.value.dateTime.length>0){ | ||
118 | + if(startDateStr!=endDateStr){ | ||
119 | + dateStr='log-syslog-search'; | ||
120 | + }else{ | ||
121 | + dateStr='log-syslog_'+startDateStr; | ||
122 | + | ||
123 | + } | ||
124 | + }else { | ||
125 | + dateStr='log-syslog_'+nowDate; | ||
126 | + } | ||
127 | + | ||
128 | + let params={ | ||
129 | + indexName:dateStr, | ||
130 | + pageNum: search.value.pageNum, | ||
131 | + pageSize: search.value.pageSize, | ||
132 | + type:search.value.type, | ||
133 | + sortBy:search.value.sortBy, | ||
134 | + scopeBy:search.value.scopeBy, | ||
135 | + startTime:startTime, | ||
136 | + endTime: endTime, | ||
137 | + resType:search.value.resType, | ||
138 | + program:search.value.program, | ||
139 | + param:{ | ||
140 | + 'resName.keyword': search.value.keyword, | ||
141 | + 'host.keyword':search.value.keyword, | ||
142 | + 'message.keyword':search.value.keyword, | ||
143 | + } | ||
144 | + } | ||
145 | + proxy.$http.post(`/api-web/esData/list`, params, function (res) { | ||
146 | + if (res && res.object) { | ||
147 | + let dataList=res.object.content; | ||
148 | + let arr=[]; | ||
149 | + dataList.map(item=>{ | ||
150 | + /* for(let key in item[0]){ | ||
151 | + if(key=='timestamp'){ | ||
152 | + console.log("item[0]['timestamp']",item[0]['timestamp']) | ||
153 | + item[0]['timestampStr']=getDateTime(item[0]['timestamp']) | ||
154 | + } | ||
155 | + }*/ | ||
156 | + arr.push(item[0]) | ||
157 | + }) | ||
158 | + tableData.value.dataList = arr; | ||
159 | + tableData.value.count = parseInt(res.object.total); | ||
160 | + } else { | ||
161 | + tableData.value.dataList = []; | ||
162 | + tableData.value.count = 0; | ||
163 | + } | ||
164 | + }); | ||
165 | + } | ||
166 | + | ||
167 | + let loaddata = ({page, limit}) => { | ||
168 | + search.value.pageNum = page; | ||
169 | + search.value.pageSize = limit; | ||
170 | + } | ||
171 | + | ||
172 | + let hideDialog = (flg) => { | ||
173 | + dialog.value.show = flg; | ||
174 | + } | ||
175 | + | ||
176 | + // 处理弹框 | ||
177 | + let handle = (row) =>{ | ||
178 | + hideDialog(true); | ||
179 | + dialog.value.detail = row; | ||
180 | + } | ||
181 | + | ||
182 | + //查看详情 | ||
183 | + let handleView = (row) =>{ | ||
184 | + handle(row); | ||
185 | + } | ||
186 | + //查看资源详情 | ||
187 | + let goResDetail=(resId,resName,resType)=>{ | ||
188 | + proxy.$global.openDetail(resId, resType, proxy); | ||
189 | + | ||
190 | + } | ||
191 | + //日志类型数据 | ||
192 | + let logTypeData=Vue.ref([]); | ||
193 | + let getLogType=()=>{ | ||
194 | + proxy.$http.post(`/api-web/manage/ddic/findSucDdics/LOG_SOURCE_TYPE`, {}, function (res) { | ||
195 | + if (res && res.data) { | ||
196 | + logTypeData.value = res.data; | ||
197 | + } | ||
198 | + }); | ||
199 | + } | ||
200 | + // 挂载完 | ||
201 | + Vue.onMounted(() => { | ||
202 | + getDataList(); | ||
203 | + getLogType(); | ||
204 | + }) | ||
205 | + | ||
206 | + | ||
207 | + return { | ||
208 | + logTypeData, | ||
209 | + getLogType, | ||
210 | + dateTime, | ||
211 | + height, | ||
212 | + search, | ||
213 | + dialog, | ||
214 | + hideDialog, | ||
215 | + handle, | ||
216 | + loaddata, | ||
217 | + tableData, | ||
218 | + getDataList, | ||
219 | + resTypeArr, | ||
220 | + getResType, | ||
221 | + handleView, | ||
222 | + goResDetail, | ||
223 | + getDateTime | ||
224 | + } | ||
225 | + } | ||
226 | + | ||
227 | +} |
@@ -359,6 +359,26 @@ layui.define(['view'], function(exports){ | @@ -359,6 +359,26 @@ layui.define(['view'], function(exports){ | ||
359 | //纠正首尾 | 359 | //纠正首尾 |
360 | return href.replace(/^(\/+)/, '/') | 360 | return href.replace(/^(\/+)/, '/') |
361 | .replace(new RegExp('\/' + setter.entry + '$'), '/'); //过滤路由最后的默认视图文件名(如:index) | 361 | .replace(new RegExp('\/' + setter.entry + '$'), '/'); //过滤路由最后的默认视图文件名(如:index) |
362 | + }, | ||
363 | + //封装获取cookie | ||
364 | + getCookie:function(name) { | ||
365 | + var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)"); | ||
366 | + if (arr = document.cookie.match(reg)) | ||
367 | + return (arr[2]); | ||
368 | + else | ||
369 | + return null; | ||
370 | + }, | ||
371 | + setCookie:function (c_name, value, expiredays) { | ||
372 | + var exdate = new Date(); | ||
373 | + exdate.setDate(exdate.getDate() + expiredays); | ||
374 | + document.cookie = c_name + "=" + escape(value) + ((expiredays == null) ? "" : ";expires=" + exdate.toGMTString()); | ||
375 | + }, | ||
376 | + delCookie:function (name) { | ||
377 | + var exp = new Date(); | ||
378 | + exp.setTime(exp.getTime() - 1); | ||
379 | + var cval = getCookie(name); | ||
380 | + if (cval != null) | ||
381 | + document.cookie = name + "=" + cval + ";expires=" + exp.toGMTString(); | ||
362 | } | 382 | } |
363 | 383 | ||
364 | //…… | 384 | //…… |
@@ -169,7 +169,13 @@ const routes = [{ | @@ -169,7 +169,13 @@ const routes = [{ | ||
169 | path: '/alarmsubscribe/excludeKpi', | 169 | path: '/alarmsubscribe/excludeKpi', |
170 | name: 'alarmSubscribeExcludeKpi', | 170 | name: 'alarmSubscribeExcludeKpi', |
171 | component: () => myImport('views/alarmsubscribe/index') | 171 | component: () => myImport('views/alarmsubscribe/index') |
172 | - } | 172 | + }, |
173 | + //日志 | ||
174 | + { | ||
175 | + path: '/esData', | ||
176 | + name: 'esDataIndex', | ||
177 | + component: () => myImport('views/esData/index'), | ||
178 | + }, | ||
173 | ]; | 179 | ]; |
174 | 180 | ||
175 | // hash模式: createWebHashHistory | 181 | // hash模式: createWebHashHistory |
-
Please register or login to post a comment