Showing 20 changed files with 963 additions and 15 deletions
  1 +<title>CMDB数据同步</title>
  2 +<iframe src="/vue3/index.html#/cmdbdatasync" frameborder="0" class="layadmin-iframe" style="height: 99.5%!important;"/>
  1 +<title>日志视图</title>
  2 +<iframe src="/vue3/index.html#/esData" frameborder="0" class="layadmin-iframe" style="height: 99.5%!important;"/>
@@ -5,6 +5,10 @@ @@ -5,6 +5,10 @@
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";
  10 +/*cmdb数据同步*/
  11 +@import "../css/cmdbdatasync.css";
8 12
9 .d-flex { 13 .d-flex {
10 display: flex; 14 display: flex;
  1 +.protocol-btn{
  2 + display: flex;
  3 + justify-content: center;
  4 + align-items: center;
  5 +}
  6 +.icon-add{
  7 + margin-left:10px;
  8 + width:20px;
  9 + height:20px;
  10 + background: #1e9fff;
  11 + display: flex;
  12 + align-items: center;
  13 + justify-content: center;
  14 + cursor: pointer;
  15 +}
  16 +.protocol-btn i{
  17 + color:#ffffff;
  18 +}
  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 +}
1 <div > 1 <div >
2 <!-- 表格--> 2 <!-- 表格-->
3 <el-table :border="showBorder" v-loading="loading" :size="size" ref="multipleTable" @selection-change="handleSelectionChange" :data="dataList" stripe header-row-class-name="tbl-header-class" :height="height" 3 <el-table :border="showBorder" v-loading="loading" :size="size" ref="multipleTable" @selection-change="handleSelectionChange" :data="dataList" stripe header-row-class-name="tbl-header-class" :height="height"
4 - style="width: 100%;margin: 0px 0px; font-size:13.5px;"> 4 + style="width: 100%;margin: 0px 0px; font-size:13.5px;" :row-key="getRowKeys" :expand-row-keys="expands">
  5 +
  6 + <el-table-column type="expand" v-if="showExpand">
  7 + <template #default="scope">
  8 + <slot name="expand" :scope="scope" >
  9 +
  10 + </slot>
  11 + </template>
  12 + </el-table-column>
5 <el-table-column v-if="showSelection && columns.length > 0" align="center" type="selection" width="55" /> 13 <el-table-column v-if="showSelection && columns.length > 0" align="center" type="selection" width="55" />
6 <el-table-column v-if="showIndex && columns.length > 0" type="index" :label="indexLabel" align="center" width="50"/> 14 <el-table-column v-if="showIndex && columns.length > 0" type="index" :label="indexLabel" align="center" width="50"/>
7 15
@@ -87,6 +87,21 @@ export default { @@ -87,6 +87,21 @@ export default {
87 multipleSelection:{ 87 multipleSelection:{
88 type:Array, 88 type:Array,
89 default:[] 89 default:[]
  90 + },
  91 + //展开行
  92 + showExpand:{
  93 + type: Boolean,
  94 + default: false
  95 + },
  96 + //行数据的key
  97 + getRowKeys:{
  98 + type: String,
  99 + default: 'id'
  100 + },
  101 + //是否默认展开所有行
  102 + expands:{
  103 + type: Array,
  104 + default: []
90 } 105 }
91 }, 106 },
92 data() { 107 data() {
@@ -103,6 +103,18 @@ const routes = [{ @@ -103,6 +103,18 @@ 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 + },
  112 + //监控对接CMDB功能
  113 + {
  114 + path: '/cmdbdatasync',
  115 + name: 'cmdbdatasync',
  116 + component: () => myImport('views/cmdbdatasync/index'),
  117 + },
106 ]; 118 ];
107 119
108 // hash模式: createWebHashHistory 120 // 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
@@ -363,6 +369,15 @@ global.getAlarmLevel = (level) => { @@ -363,6 +369,15 @@ global.getAlarmLevel = (level) => {
363 return params[level]; 369 return params[level];
364 } 370 }
365 371
  372 +global.getHealthDesc = (level) => {
  373 + let params = {
  374 + "3": {name: '优', color: '#7be00d'},
  375 + "2": {name: '良', color: '#f5a623'},
  376 + "1": {name: '中', color: '#d81e06'}
  377 + }
  378 + return params[level];
  379 +}
  380 +
366 // 组件默认大小 medium / small / mini 381 // 组件默认大小 medium / small / mini
367 global.elementSize = ''; 382 global.elementSize = '';
368 global.height = window.innerHeight - 20; 383 global.height = window.innerHeight - 20;
  1 +<div class="cmdbdatasyncEdit-container" style="min-height: 500px;">
  2 +
  3 + <div class="search-table">
  4 + <cm-table-page :columns="tableData.columns" :dataList="editTbaleData"
  5 + :showIndex="true"
  6 + @loaddata = "loaddata"
  7 + :showSelection="false"
  8 + :showBorder="true"
  9 + :loading="false"
  10 + :pageSize="pageSize"
  11 + :showPage="false"
  12 + :showTools="true"
  13 + :showExpand="true"
  14 + :getRowKeys="tableData.getRowKeys"
  15 + :expands="tableData.expands"
  16 + :height="height - 110">
  17 + <template #expand="{scope}">
  18 + aaa{{scope.row.expand}}
  19 + </template>
  20 + <template #default="{row,prop,column}">
  21 + <div>
  22 + <el-input v-model="row[prop]" placeholder="Please input" />
  23 + <!--<el-select placeholder="请选择" size="small" style="width: 100%"
  24 + @change="changeProperty(row,prop,column)" v-model="row[prop]"
  25 + :multiple="false"
  26 + collapse-tags clearable filterable placeholder="请选择">
  27 + <el-option label="是" :value="0"></el-option>
  28 + <el-option label="否" :value="1"></el-option>
  29 + </el-select>-->
  30 + </div>
  31 + </template>
  32 + <template #tools="{scope}">
  33 + <div class="protocol-btn">
  34 + <span class="icon-add" @click="addProtocol" title="协议参数"><i class="el-icon-plus"></i></span>
  35 + </div>
  36 + </template>
  37 + </cm-table-page>
  38 + </div>
  39 + <div class="save-button" style="text-align:right;">
  40 + <el-button type="primary" style="margin-top:20px;margin-right:10px;" @click="saveEdit">确定</el-button>
  41 + </div>
  42 +</div>
  1 +export default {
  2 + name: 'cmdbdatasyncEdit',
  3 + template: '',
  4 + components: {
  5 +
  6 + },
  7 + props: {
  8 + tableData:{
  9 + type:Object,
  10 + default: {}
  11 + }
  12 + },
  13 + setup(props, {attrs, slots, emit}) {
  14 + const {proxy} = Vue.getCurrentInstance();
  15 + let height = Vue.ref(window.innerHeight);
  16 + let editTbaleData=Vue.ref(props.tableData.dataList);
  17 + // let columns=Vue.ref(props.tableData.columns);
  18 + // let getRowKeys=Vue.ref(props.tableData.getRowKeys);
  19 + // let expands=Vue.ref(props.tableData.expands);
  20 + //保存编辑
  21 + let saveEdit=()=>{
  22 + //保存接口 todo
  23 + let param={
  24 + editTbaleData:editTbaleData.value,
  25 + visibility:false
  26 + }
  27 + emit("callbackedit",param)
  28 + }
  29 + //添加协议
  30 + let addProtocol=()=>{
  31 + proxy.$global.layer.open({
  32 + title:'资源协议',
  33 + id:'resManageChooseProtocolHtml',
  34 + type:1,
  35 + area: ['80%', '90%'],
  36 + btn:['确定','取消'],
  37 + scrollbar:true,
  38 + success: function(){
  39 + proxy.$global.layui.view('resManageChooseProtocolHtml').render('/baseconfig/protocol/index',{'hasParam':'1'});
  40 + },
  41 + yes:function (index,layero) {
  42 + var data = proxy.$global.layui.table.checkStatus('protocol_table').data;
  43 + formData.ip = $('#resManageAddForm').find('input[name="ip"]').val();
  44 + formData.port = $('#resManageAddForm').find('input[name="port"]').val();
  45 + if(data.length>0){
  46 + createProtocolDom(data,false);
  47 + form.render()
  48 + layer.close(index);
  49 + }else{
  50 + layer.msg("无选中的数据或当",{ offset: '15px' , icon: 7 , time: 2000 })
  51 + return false;
  52 + }
  53 + }
  54 + })
  55 + }
  56 + // 挂载完
  57 + Vue.onMounted(() => {
  58 + })
  59 +
  60 +
  61 + return {
  62 + height,
  63 + editTbaleData,
  64 + // columns,
  65 + saveEdit,
  66 + addProtocol,
  67 + // getRowKeys,
  68 + // expands
  69 + }
  70 + }
  71 +
  72 +}
  1 +<div class="container" :style="{'height':height+'px','max-height':height+'px','display':'flex'}">
  2 + <div class="async-left-tree" style="width:200px;overflow-x: auto;background: #fff;border-right:1px solid #f2f2f2;">
  3 + <el-tree style="padding-top:10px;" class="tree-div" ref="roleTree" :data="treeData" :props="defaultProps" @node-click="handleNodeClick"
  4 + node-key="id" :default-checked-keys="checkedKeys"
  5 + />
  6 + </div>
  7 + <div class="cm-card" :style="{'min-height':height+'px','max-height':height+'px','height':'100%','padding-top':'3px','flex':'1'}">
  8 + <div class="search">
  9 + <div class="condition">
  10 + <el-form-item >
  11 + <el-input v-model="search.keyword" placeholder="关键字"></el-input>
  12 + </el-form-item>
  13 + <el-form-item >
  14 + <el-button @click="getDataList">查询</el-button>
  15 + </el-form-item>
  16 + <el-form-item >
  17 + <el-button @click="handleEdit">编辑</el-button>
  18 + </el-form-item>
  19 + <el-form-item >
  20 + <el-button @click="handleRefresh">同步</el-button>
  21 + </el-form-item>
  22 + </div>
  23 + </div>
  24 + <div class="search-table">
  25 + <cm-table-page :columns="tableData.columns" :dataList="tableData.dataList"
  26 + :showIndex="true"
  27 + :total="tableData.count"
  28 + @loaddata = "loaddata"
  29 + @selectionChange="selectionChange"
  30 + :showSelection="true"
  31 + :showBorder="true"
  32 + :loading="false"
  33 + :pageSize="pageSize"
  34 + :showPage="true"
  35 + :showTools="true"
  36 + :height="height - 110">
  37 + <template #default="{row,prop,column}">
  38 + <div v-if="prop == 'resName'">
  39 + <span class="resName-span" style="cursor: pointer;color:#1e9fff" @click="goResDetail(row.resId,row.resName,row.resType)">{{row.resName}}</span>
  40 + </div>
  41 + </template>
  42 + <template #tools="{scope}">
  43 + <div class="list-handle">
  44 + <span class="icon-bg" @click="handleEdit(1,scope.row)"><i class="el-icon-edit-outline" title="编辑"></i></span>
  45 + <span class="icon-bg" @click="handleRefresh(1,scope.row)"><i class="el-icon-refresh" title="同步"></i></span>
  46 + </div>
  47 + </template>
  48 + </cm-table-page>
  49 + </div>
  50 + </div>
  51 +</div>
  52 +
  53 +<!--弹框-->
  54 +<cm-dialog :title="dialog.title" width="90%" :showDialogVisible="dialog.show" @hidedialog="hideDialog" :showFooter="false">
  55 + <template v-slot>
  56 + <cmdbdatasyncEdit :tableData="dialog.tableData" @callbackedit="callbackedit"/>
  57 + </template>
  58 +</cm-dialog>
  59 +
  1 +export default {
  2 + name: 'cmdbdatasync',
  3 + template: '',
  4 + components: {
  5 + 'cmdbdatasyncEdit': Vue.defineAsyncComponent(
  6 + () => myImport('views/cmdbdatasync/cmdbdatasyncEdit/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 defaultProps=Vue.ref({
  14 + children: 'children',
  15 + label: 'title'
  16 + })
  17 + let treeData=Vue.ref([]) // 所有的树结点
  18 + let defaultNode=Vue.ref(true);//默认节点
  19 + let resType=Vue.ref('');//选中的树节点值
  20 + let handleNodeClick=(data,node)=>{
  21 + //点击树节点,根据某个字段获取列表 todo
  22 + console.log("*(*(*(*",data,node)
  23 + proxy.$global.showMsg(data.id,'warning')
  24 + resType.value=data.value;
  25 + defaultNode.value=false;
  26 + getDataList();
  27 + }
  28 +
  29 + let search = Vue.ref({
  30 + keyword: '',
  31 + pageNum: 1,
  32 + pageSize: 20,
  33 + });
  34 + //表格字段
  35 + let tableData = Vue.ref({
  36 + count:0,
  37 + dataList: [{
  38 + id:1,
  39 + resName:'资源一'
  40 + },{
  41 + id:2,
  42 + resName:'资源34'
  43 + }],
  44 + columns: [
  45 + {
  46 + prop: 'resName',
  47 + label: '资源名称',
  48 + sortable: true,
  49 + align: 'center',
  50 + width: '250'
  51 + },
  52 + {
  53 + prop: 'resTypeName',
  54 + label: '资源类型',
  55 + sortable: true,
  56 + align: 'center',
  57 + width: '200'
  58 + }, {
  59 + prop: 'host',
  60 + label: 'IP地址',
  61 + sortable: true,
  62 + align: 'center',
  63 + width: '200'
  64 + }, {
  65 + prop: 'type',
  66 + label: '日志来源',
  67 + sortable: true,
  68 + align: 'center',
  69 + width: '200'
  70 + },
  71 + {
  72 + prop: 'program',
  73 + label: '日志类型',
  74 + sortable: true,
  75 + align: 'center',
  76 + width: '200'
  77 + },
  78 + {
  79 + prop: 'message',
  80 + label: '日志内容',
  81 + sortable: true,
  82 + align: 'center',
  83 + },
  84 + ]
  85 + })
  86 + let dialog = Vue.ref({
  87 + title : "编辑",
  88 + show:false,
  89 + tableData : {}
  90 + });
  91 + let loaddata = ({page, limit}) => {
  92 + search.value.pageNum = page;
  93 + search.value.pageSize = limit;
  94 + }
  95 + let hideDialog = (flg) => {
  96 + dialog.value.show = flg;
  97 + }
  98 + //全选事件
  99 + let selectionData=Vue.ref([]);//选择的数据
  100 + let selectionChange= (val) =>{
  101 + selectionData.value=val;
  102 + }
  103 + // 处理弹框
  104 + let handle = (row) =>{
  105 + hideDialog(true);
  106 + dialog.value.tableData.dataList= row;
  107 + dialog.value.tableData.columns=tableData.value.columns;
  108 + dialog.value.tableData.getRowKeys= 'id';
  109 + let arr=[];
  110 + row.map(item=>{
  111 + arr.push(item.id)
  112 + })
  113 + //默认展开第一行
  114 + dialog.value.tableData.expands= [arr[0]];
  115 +
  116 + }
  117 + //编辑
  118 + let handleEdit = (flag,row) =>{
  119 + if(flag==1){
  120 + handle([row]);
  121 + }else{
  122 + if(selectionData.value.length>0){
  123 + handle(selectionData.value);
  124 + }else{
  125 + proxy.$global.showMsg('请选择数据','warning')
  126 + }
  127 + }
  128 + }
  129 + //同步 todo
  130 + let handleRefresh = (flag,row) =>{
  131 + if(flag==1){
  132 + //单个同步 row-->对象
  133 + }else{
  134 + //多选同步 selectionData.value-->数组
  135 + if(selectionData.value.length>0){
  136 + //...
  137 + }else{
  138 + proxy.$global.showMsg('请选择数据','warning')
  139 + }
  140 + }
  141 + }
  142 + //编辑返回数据
  143 + let callbackedit=(obj)=>{
  144 + console.log("***",obj.editTbaleData,obj.visibility)
  145 + hideDialog(obj.visibility)
  146 +
  147 + //obj.editTbaleData编辑后的数据,todo
  148 + // getDataList();//获取列表数据
  149 + }
  150 + //查看资源详情
  151 + let goResDetail=(resId,resName,resType)=>{
  152 + proxy.$global.openDetail(resId, resType, proxy);
  153 +
  154 + }
  155 + //获取资源树数据
  156 + let getResData=()=>{
  157 + proxy.$http.post(`/api-web/attribute/getTree`, {}, function (res) {
  158 + if (res && res.data) {
  159 + treeData.value = res.data;
  160 + }
  161 + });
  162 + }
  163 + // 获取列表 todo
  164 + let getDataList = () => {
  165 + if(defaultNode.value){
  166 + resType.value=treeData.value[0].children[0].value;
  167 + }
  168 + let params={
  169 + resType:resType.value,
  170 + pageNum: search.value.pageNum,
  171 + pageSize: search.value.pageSize,
  172 + keyword:search.value.keyword
  173 + }
  174 + proxy.$http.post(`/api-web/`, params, function (res) {
  175 + if (res && res.object) {
  176 + tableData.value.dataList = res.object;
  177 + tableData.value.count = parseInt(res.object.total);
  178 + } else {
  179 + tableData.value.dataList = [];
  180 + tableData.value.count = 0;
  181 + }
  182 + });
  183 + }
  184 +
  185 + // 挂载完
  186 + Vue.onMounted(() => {
  187 + // getDataList();//获取列表数据
  188 + getResData();//获取资源树数据
  189 + })
  190 +
  191 +
  192 + return {
  193 + defaultProps,
  194 + treeData,
  195 + defaultNode,
  196 + handleNodeClick,
  197 + getResData,
  198 + height,
  199 + search,
  200 + dialog,
  201 + hideDialog,
  202 + selectionChange,
  203 + selectionData,
  204 + handle,
  205 + loaddata,
  206 + tableData,
  207 + getDataList,
  208 + handleEdit,
  209 + handleRefresh,
  210 + callbackedit,
  211 + goResDetail,
  212 + resType
  213 + }
  214 + }
  215 +
  216 +}
  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.logDate}}
  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>
  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="false"
  47 + :showBorder="true"
  48 + :loading="false"
  49 + :pageSize="search.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 + <el-tooltip >
  59 + <template #content>
  60 + <div style="max-width:400px;overflow: hidden; text-overflow: ellipsis;display: -webkit-box; -webkit-line-clamp: 5; -webkit-box-orient: vertical;">
  61 + {{row.message}}
  62 + </div>
  63 + </template>
  64 + <div v-html="row.message" style="overflow: hidden; text-overflow: ellipsis;display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical;"></div>
  65 + </el-tooltip>
  66 + </div>
  67 + </template>
  68 + <template #tools="{scope}">
  69 + <div class="list-handle">
  70 + <span class="icon-bg">
  71 + <i class="el-icon-view" title="查看" @click="handleView(scope.row)"></i>
  72 + </span>
  73 + </div>
  74 + </template>
  75 + </cm-table-page>
  76 + </div>
  77 + </div>
  78 +</div>
  79 +
  80 +<!--弹框-->
  81 +<cm-dialog :title="dialog.title" width="60%" :showDialogVisible="dialog.show" @hidedialog="hideDialog" :showFooter="false">
  82 + <template v-slot>
  83 + <esDataDetail :detail="dialog.detail" />
  84 + </template>
  85 +</cm-dialog>
  86 +
  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:'dbTimeStr.keyword',
  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: 'logDate',
  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 && search.value.dateTime[0])?search.value.dateTime[0]:'';
  113 + let endTime=(search.value.dateTime && 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 && 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 + param:{}
  139 + }
  140 + if(search.value.keyword){
  141 + params.param={
  142 + 'resName.keyword': search.value.keyword,
  143 + 'host.keyword':search.value.keyword,
  144 + 'message.keyword':search.value.keyword,
  145 + }
  146 + }
  147 + if(search.value.program){
  148 + params['param']['program.keyword']=search.value.program;
  149 + }
  150 + proxy.$http.post(`/api-web/esData/list`, params, function (res) {
  151 + if (res && res.object) {
  152 + let dataList=res.object.content;
  153 + let arr=[];
  154 + dataList.map(item=>{
  155 + arr.push(item[0])
  156 + })
  157 + tableData.value.dataList = arr;
  158 + tableData.value.count = parseInt(res.object.total);
  159 + } else {
  160 + tableData.value.dataList = [];
  161 + tableData.value.count = 0;
  162 + }
  163 + });
  164 + }
  165 +
  166 + let loaddata = ({page, limit}) => {
  167 + search.value.pageNum = page;
  168 + search.value.pageSize = limit;
  169 + getDataList();
  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 +}
@@ -198,6 +198,12 @@ const routes = [{ @@ -198,6 +198,12 @@ const routes = [{
198 name: 'busDoc', 198 name: 'busDoc',
199 component: () => myImport('views/busDoc/index') 199 component: () => myImport('views/busDoc/index')
200 }, 200 },
  201 + //日志
  202 + {
  203 + path: '/esData',
  204 + name: 'esDataIndex',
  205 + component: () => myImport('views/esData/index'),
  206 + },
201 ]; 207 ];
202 208
203 // hash模式: createWebHashHistory 209 // hash模式: createWebHashHistory
@@ -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,19 @@ const routes = [{ @@ -169,7 +169,19 @@ 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 + },
  179 + //监控对接CMDB功能
  180 + {
  181 + path: '/cmdbdatasync',
  182 + name: 'cmdbdatasync',
  183 + component: () => myImport('views/cmdbdatasync/index'),
  184 + },
173 ]; 185 ];
174 186
175 // hash模式: createWebHashHistory 187 // hash模式: createWebHashHistory