Authored by 王涛

Merge branch 'master-500-dev-lushangqing' into 'master-500-dev'

CMDB数据同步功能静态页面搭建及路由配置;日志视图详情页的日志时间字段更改为logDate



See merge request !549
  1 +<title>CMDB数据同步</title>
  2 +<iframe src="/vue3/index.html#/cmdbdatasync" frameborder="0" class="layadmin-iframe" style="height: 99.5%!important;"/>
@@ -109,6 +109,12 @@ const routes = [{ @@ -109,6 +109,12 @@ const routes = [{
109 name: 'esDataIndex', 109 name: 'esDataIndex',
110 component: () => myImport('views/esData/index'), 110 component: () => myImport('views/esData/index'),
111 }, 111 },
  112 + //监控对接CMDB功能
  113 + {
  114 + path: '/cmdbdatasync',
  115 + name: 'cmdbdatasync',
  116 + component: () => myImport('views/cmdbdatasync/index'),
  117 + },
112 ]; 118 ];
113 119
114 // hash模式: createWebHashHistory 120 // hash模式: createWebHashHistory
  1 +<div class="cmdbdatasyncEdit-container" style="min-height: 500px;">
  2 + <div class="search-table">
  3 + <cm-table-page :columns="columns" :dataList="editTbaleData"
  4 + :showIndex="true"
  5 + @loaddata = "loaddata"
  6 + :showSelection="false"
  7 + :showBorder="true"
  8 + :loading="false"
  9 + :pageSize="pageSize"
  10 + :showPage="false"
  11 + :showTools="false"
  12 + :height="height - 110">
  13 + <template #default="{row,prop,column}">
  14 + <div>
  15 + <el-input v-model="row[prop]" placeholder="Please input" />
  16 + <!--<el-select placeholder="请选择" size="small" style="width: 100%"
  17 + @change="changeProperty(row,prop,column)" v-model="row[prop]"
  18 + :multiple="false"
  19 + collapse-tags clearable filterable placeholder="请选择">
  20 + <el-option label="是" :value="0"></el-option>
  21 + <el-option label="否" :value="1"></el-option>
  22 + </el-select>-->
  23 + </div>
  24 + </template>
  25 + </cm-table-page>
  26 + </div>
  27 + <div class="save-button" style="text-align:right;">
  28 + <el-button type="primary" style="margin-top:20px;margin-right:10px;" @click="saveEdit">确定</el-button>
  29 + </div>
  30 +</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 + //保存编辑
  19 + let saveEdit=()=>{
  20 + //保存接口 todo
  21 + let param={
  22 + editTbaleData:editTbaleData.value,
  23 + visibility:false
  24 + }
  25 + emit("callbackedit",param)
  26 + }
  27 + // 挂载完
  28 + Vue.onMounted(() => {
  29 + })
  30 +
  31 +
  32 + return {
  33 + height,
  34 + editTbaleData,
  35 + columns,
  36 + saveEdit
  37 + }
  38 + }
  39 +
  40 +}
  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 treeData=Vue.ref([
  14 + {
  15 + label: '计算机设备计算机设备计算机设备计算机设备计算机设备',
  16 + id:1,
  17 + children: [
  18 + {
  19 + label: '小型机分区',
  20 + id:"1-1",
  21 + },
  22 + {
  23 + label: 'PC服务器',
  24 + id:'1-2',
  25 + children:[]
  26 + },
  27 + ],
  28 + },
  29 + {
  30 + label: '虚拟化',
  31 + id:2,
  32 + children: [
  33 + {
  34 + label: 'VMWARE',
  35 + id:'2-1',
  36 + children: [
  37 + {
  38 + label: 'vm资源池',
  39 + id:"2-1-1",
  40 + children: []
  41 + },
  42 + ],
  43 + },
  44 + {
  45 + label: '虚拟机',
  46 + id:"2-2",
  47 + },
  48 + ],
  49 + },
  50 + {
  51 + label: '存储设备',
  52 + id:'3',
  53 + children: [
  54 + {
  55 + label: '共享存储',
  56 + id:'3-1',
  57 + },
  58 +
  59 + ],
  60 + }]) // 所有的树结点
  61 + let handleNodeClick=(data,node)=>{
  62 + //点击树节点,根据某个字段获取列表 todo
  63 + getDataList();
  64 + }
  65 +
  66 + let search = Vue.ref({
  67 + keyword: '',
  68 + pageNum: 1,
  69 + pageSize: 20,
  70 + });
  71 + //表格字段
  72 + let tableData = Vue.ref({
  73 + count:0,
  74 + dataList: [{
  75 + resName:'资源一'
  76 + },{
  77 + resName:'资源34'
  78 + }],
  79 + columns: [
  80 + {
  81 + prop: 'resName',
  82 + label: '资源名称',
  83 + sortable: true,
  84 + align: 'center',
  85 + width: '250'
  86 + },
  87 + {
  88 + prop: 'resTypeName',
  89 + label: '资源类型',
  90 + sortable: true,
  91 + align: 'center',
  92 + width: '200'
  93 + }, {
  94 + prop: 'host',
  95 + label: 'IP地址',
  96 + sortable: true,
  97 + align: 'center',
  98 + width: '200'
  99 + }, {
  100 + prop: 'type',
  101 + label: '日志来源',
  102 + sortable: true,
  103 + align: 'center',
  104 + width: '200'
  105 + },
  106 + {
  107 + prop: 'program',
  108 + label: '日志类型',
  109 + sortable: true,
  110 + align: 'center',
  111 + width: '200'
  112 + },
  113 + {
  114 + prop: 'message',
  115 + label: '日志内容',
  116 + sortable: true,
  117 + align: 'center',
  118 + },
  119 + ]
  120 + })
  121 + let dialog = Vue.ref({
  122 + title : "编辑",
  123 + show:false,
  124 + tableData : {}
  125 + });
  126 + let loaddata = ({page, limit}) => {
  127 + search.value.pageNum = page;
  128 + search.value.pageSize = limit;
  129 + }
  130 + let hideDialog = (flg) => {
  131 + dialog.value.show = flg;
  132 + }
  133 + //全选事件
  134 + let selectionData=Vue.ref([]);//选择的数据
  135 + let selectionChange= (val) =>{
  136 + selectionData.value=val;
  137 + }
  138 + // 处理弹框
  139 + let handle = (row) =>{
  140 + hideDialog(true);
  141 + dialog.value.tableData.dataList= row;
  142 + dialog.value.tableData.columns=tableData.value.columns;
  143 + }
  144 + //编辑
  145 + let handleEdit = (flag,row) =>{
  146 + if(flag==1){
  147 + handle([row]);
  148 + }else{
  149 + if(selectionData.value.length>0){
  150 + handle(selectionData.value);
  151 + }else{
  152 + proxy.$global.showMsg('请选择数据','warning')
  153 + }
  154 + }
  155 + }
  156 + //同步 todo
  157 + let handleRefresh = (flag,row) =>{
  158 + if(flag==1){
  159 + //单个同步 row-->对象
  160 + }else{
  161 + //多选同步 selectionData.value-->数组
  162 + if(selectionData.value.length>0){
  163 + //...
  164 + }else{
  165 + proxy.$global.showMsg('请选择数据','warning')
  166 + }
  167 + }
  168 + }
  169 + //编辑返回数据
  170 + let callbackedit=(obj)=>{
  171 + console.log("***",obj.editTbaleData,obj.visibility)
  172 + hideDialog(obj.visibility)
  173 +
  174 + //obj.editTbaleData编辑后的数据,todo
  175 + // getDataList();//获取列表数据
  176 + }
  177 + //查看资源详情
  178 + let goResDetail=(resId,resName,resType)=>{
  179 + proxy.$global.openDetail(resId, resType, proxy);
  180 +
  181 + }
  182 + //获取资源树数据 todo
  183 + let getResData=()=>{
  184 + proxy.$http.post(`/api-web/`, {}, function (res) {
  185 + if (res && res.data) {
  186 + treeData.value = res.data;
  187 + }
  188 + });
  189 + }
  190 + // 获取列表 todo
  191 + let getDataList = () => {
  192 + let params={
  193 + pageNum: search.value.pageNum,
  194 + pageSize: search.value.pageSize,
  195 + keyword:search.value.keyword
  196 + }
  197 + proxy.$http.post(`/api-web/`, params, function (res) {
  198 + if (res && res.object) {
  199 + tableData.value.dataList = res.object;
  200 + tableData.value.count = parseInt(res.object.total);
  201 + } else {
  202 + tableData.value.dataList = [];
  203 + tableData.value.count = 0;
  204 + }
  205 + });
  206 + }
  207 +
  208 + // 挂载完
  209 + Vue.onMounted(() => {
  210 + // getDataList();//获取列表数据
  211 + // getResData();//获取资源树数据
  212 + })
  213 +
  214 +
  215 + return {
  216 + treeData,
  217 + handleNodeClick,
  218 + getResData,
  219 + height,
  220 + search,
  221 + dialog,
  222 + hideDialog,
  223 + selectionChange,
  224 + selectionData,
  225 + handle,
  226 + loaddata,
  227 + tableData,
  228 + getDataList,
  229 + handleEdit,
  230 + handleRefresh,
  231 + callbackedit,
  232 + goResDetail,
  233 + }
  234 + }
  235 +
  236 +}
@@ -60,7 +60,7 @@ @@ -60,7 +60,7 @@
60 日志时间 60 日志时间
61 </div> 61 </div>
62 </template> 62 </template>
63 - {{detail.timestamp}} 63 + {{detail.logDate}}
64 </el-descriptions-item> 64 </el-descriptions-item>
65 </el-descriptions> 65 </el-descriptions>
66 <div class="info-title"> 66 <div class="info-title">
@@ -176,6 +176,12 @@ const routes = [{ @@ -176,6 +176,12 @@ const routes = [{
176 name: 'esDataIndex', 176 name: 'esDataIndex',
177 component: () => myImport('views/esData/index'), 177 component: () => myImport('views/esData/index'),
178 }, 178 },
  179 + //监控对接CMDB功能
  180 + {
  181 + path: '/cmdbdatasync',
  182 + name: 'cmdbdatasync',
  183 + component: () => myImport('views/cmdbdatasync/index'),
  184 + },
179 ]; 185 ];
180 186
181 // hash模式: createWebHashHistory 187 // hash模式: createWebHashHistory