Przeglądaj źródła

报表管理左侧菜单树,视频墙功能修改-提交

lxh 11 miesięcy temu
rodzic
commit
9f59dcc0ea

+ 5 - 0
src/views/vent/monitorManager/camera/camera.api.ts

@@ -4,6 +4,9 @@ enum Api {
   getCameraDevKind='/safety/ventanalyCamera/getCameraDevKind',
   list = '/safety/ventanalyCamera/listNew',
   getCameraUrl = '/ventanaly-device/camera/queryByCameraCode',
+  getDevice='/ventanaly-device/monitor/device',
+  getVentanalyCamera='/safety/ventanalyCamera/list'
+
 }
 /**
  * 列表接口
@@ -14,3 +17,5 @@ export const list = (params) => defHttp.get({ url: Api.list, params });
 export const cameraAddr = (params) => defHttp.get({ url: Api.getCameraUrl, params });
 
 export const getCameraDevKind = () => defHttp.get({ url: Api.getCameraDevKind, });
+export const getDevice = (params) => defHttp.post({ url: Api.getDevice,params });
+export const getVentanalyCamera = (params) => defHttp.get({ url: Api.getVentanalyCamera,params });

+ 5 - 5
src/views/vent/monitorManager/camera/common/cameraTree.vue

@@ -4,7 +4,7 @@
     v-bind="$attrs"
     :model="model"
     :key="model.id"
-    @delete-node="onDeltet"
+    @detail-node="onDetail"
   >
     <template #icon="slotProps">
       <slot name="icon" v-bind="slotProps"></slot>
@@ -17,7 +17,7 @@
 <script setup lang="ts">
   import { ref } from 'vue';
   import treeList from './treeList.vue';
-  const emit = defineEmits([ 'deleteNode']);
+  const emit = defineEmits([ 'detailNode']);
   interface IFileSystem {
     id: string;
     title: string;
@@ -51,10 +51,10 @@
     return targetNode.children;
   }
   // 删除
-  const onDeltet = (node) => {
-    emit('deleteNode', {
+  const onDetail = (node) => {
+    emit('detailNode', {
       ...node,
-      eventType: 'delete',
+      eventType: 'detail',
     });
   };
  

+ 9 - 8
src/views/vent/monitorManager/camera/common/treeList.vue

@@ -10,6 +10,7 @@
         <template v-if="isFolder">
           <slot v-if="expanded" :item="{ title: model.title, isFolder: true, expanded: true }" name="icon"> </slot>
           <slot v-else :item="{ title: model.title, isFolder: true, expanded: false }" name="icon"></slot>
+       
         </template>
         <slot v-else :item="{ title: model.title, isFolder: false }" name="icon"></slot>
         <span class="vtl-node-content ellipsis" >
@@ -18,16 +19,16 @@
       </div>
       <div class="vtl-operation" v-show="isHover && !isFolder">
         <span @click.stop.prevent="delNode">
-          <slot name="operation" type="deleteNode"></slot>
+          <slot name="operation" type="detailNode"></slot>
         </span>
       </div>
     </div>
   </div>
-  <div class="vtl-tree-margin" v-show="expanded" v-if="isFolder">
+  <div class="vtl-tree-margin" v-show="expanded">
     <!-- 这里无法使用$attr来透传属性官方还未解决此bug -->
     <treeList
       @on-click="(depth) => $emit('onClick', depth)"
-      @delete-node="(depth) => $emit('deleteNode', depth)"
+      @detail-node="(depth) => $emit('detailNode', depth)"
       v-for="newmodel in model.children"
       :selected="selected"
       :model="newmodel"
@@ -55,7 +56,7 @@
   // 吐出去的事件
   const emit = defineEmits([
     'onClick',
-    'deleteNode',
+    'detailNode',
   ]);
   // 拿到传入的值
   const props = withDefaults(
@@ -70,7 +71,7 @@
   //是否移入
   const isHover = ref(false);
   // 是否展开
-  const expanded = ref(true);
+  const expanded = ref(false);
   // 是否是文件夹
   const isFolder = computed(() => {
     return props.model.isFolder;
@@ -86,16 +87,16 @@
  
   // 删除目录
   const delNode = () => {
-    emit('deleteNode', {
+    emit('detailNode', {
       ...props.model,
-      eventType: 'delete',
+      eventType: 'detail',
     });
   };
  
   
   // 展开收起
   const toggle = () => {
-    if (isFolder.value) {
+    if (isFolder.value ) {
       expanded.value = !expanded.value;
       emit('onClick', {
         ...props.model,

+ 110 - 24
src/views/vent/monitorManager/camera/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="camera-container">
     <div class="left-area">
-      <cameraTree :selected="selected" :list="listArr" :draggable="true" @delete-node="onDeltet" @on-click="onClick">
+      <cameraTree :selected="selected" :list="listArr" :draggable="true" @detail-node="onDetail" @on-click="onClick">
         <template #icon="{ item }">
           <template v-if="item.isFolder">
             <SvgIcon v-if="item.expanded" size="18" name="file-open" />
@@ -41,8 +41,9 @@
 </template>
 <script lang="ts" setup>
 import { onMounted, onUnmounted, ref, reactive, nextTick } from 'vue';
+import { useRouter } from 'vue-router';
 import { Pagination, Empty } from 'ant-design-vue';
-import { list, cameraAddr, getCameraDevKind } from './camera.api'
+import { list, cameraAddr, getCameraDevKind, getDevice, getVentanalyCamera } from './camera.api'
 import Player, { I18N } from 'xgplayer';
 import ZH from 'xgplayer/es/lang/zh-cn'
 import HlsPlugin from 'xgplayer-hls';
@@ -60,13 +61,14 @@ let selected = reactive<any>({
   isFolder: false,
 });
 //tree菜单列表
-let listArr = ref<any[]>([]);
+let listArr = reactive<any[]>([]);
 let searchParam = reactive({
   devKind: '',
   strType: '',
 })
 
 I18N.use(ZH)
+let router = useRouter(); //路由
 const pageSize = 8
 const current = ref(1)
 const total = ref(0)
@@ -77,45 +79,129 @@ let addrList = ref<{ name: string, addr: string }[]>([])
 async function getCameraDevKindList() {
   let res = await getCameraDevKind()
   if (res.length != 0) {
+    listArr.length = 0
+    listArr.push({
+      pid: 'root',
+      isFolder: true,
+      expanded: true,
+      title: '全部',
+      id: 0,
+      children: []
+    })
     res.forEach(el => {
-      el.pid = 'root'
-      el.isFolder = true
-      el.title = el.itemText
+      el.pid = 0
+      el.isFolder = true,
+        el.expanded = false,
+        el.title = el.itemText
       el.id = el.subDictId
-      el.children.forEach(v => {
-        v.pid = v.dictId
-        v.isFolder = false
-        v.title = v.itemText
-      })
+      el.children = []
+      listArr[0].children.push(el)
     })
-    listArr.value = res
-    selected.id = listArr['value'][0].id;
-    selected.pid = listArr['value'][0].pid;
-    selected.title = listArr['value'][0].title;
-    selected.isFolder = listArr['value'][0].isFolder;
+    selected.id = listArr[0].id;
+    selected.pid = listArr[0].pid;
+    selected.title = listArr[0].title;
+    selected.isFolder = listArr[0].isFolder;
   }
 }
 
 
 //点击目录
-function onClick(node) {
+async function onClick(node) {
+  console.log(node, 'node--------------')
+  selected.id = node.id;
+  selected.pid = node.pid;
+  selected.title = node.title;
+  selected.isFolder = node.isFolder;
   if (node.pid != 'root') {
-    console.log(node, 'node--------------')
-    selected.id = node.id;
-    selected.pid = node.pid;
-    selected.title = node.title;
-    selected.isFolder = node.isFolder;
-    searchParam.devKind = listArr.value.filter(v => v.id == node.pid)[0]['itemValue']
-    searchParam.strType = node.itemValue
+    if (node.isFolder) {
+      let res = await getDevice({ devicetype: node.itemValue })
+      if (res.msgTxt.length != 0) {
+        res.msgTxt[0].datalist.forEach(el => {
+          el.pid = node.id
+          el.isFolder = false
+          el.title = el.strinstallpos
+          el.id = el.deviceID
+        })
+        listArr[0].children.forEach(v => {
+          if (v.id == node.id) {
+            v.children = res.msgTxt[0].datalist
+          }
+        })
+      }
+      searchParam.devKind = node.itemValue
+      searchParam.strType = ''
+      getVideoAddrs()
+    } else {
+      getVideoAddrsSon(node.deviceID)
+    }
+
+  } else {
+    searchParam.devKind = ''
+    searchParam.strType = ''
     getVideoAddrs()
   }
 
 };
 
+//点击详情跳转
+function onDetail(node) {
+  console.log(node, '详情-------------')
+  switch (node.deviceType) {
+    case 'gate_qd':
+      router.push('/monitorChannel/monitor-gate?id=' + node.deviceID)
+      break;
+    case 'pump_over':
+      router.push('/monitorChannel/gasPump-home?id=' + node.deviceID)
+      break;
+    case 'pump_under':
+      router.push('/monitorChannel/gasPump-home?id=' + node.deviceID)
+      break;
+  }
+}
+
 async function getVideoAddrs() {
   clearCamera();
   playerList.value = []
   let res = await list({ ...searchParam })
+  console.log(res, '摄像头信息--------')
+  if (res.records.length != 0) {
+    const cameraList = <{ name: string, addr: string }[]>[]
+    const cameras = res.records
+    for (let i = 0; i < cameras.length; i++) {
+      const item = cameras[i];
+
+      if (item['devicekind'] === 'toHKRtsp') {
+        // 从海康平台接口获取视频流
+        try {
+          const data = await cameraAddr({ cameraCode: item['addr'] });
+          if (data && data['url']) {
+            cameraList.push({ name: item['name'], addr: data['url'] });
+          }
+          // cameraList.push({
+          //   name: item['name'],
+          //   // addr: 'http://219.151.31.38/liveplay-kk.rtxapp.com/live/program/live/hnwshd/4000000/mnf.m3u8'
+          //   addr: 'https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.mp4/.m3u8',
+          // });
+        } catch (error) {
+
+        }
+
+      } else {
+        if (item['addr'].includes('0.0.0.0')) {
+          item['addr'] = item['addr'].replace('0.0.0.0', window.location.hostname)
+        }
+        cameraList.push({ name: item['name'], addr: item['addr'] });
+      }
+    }
+    addrList.value = cameraList
+  }
+}
+
+async function getVideoAddrsSon(Id) {
+  clearCamera();
+  playerList.value = []
+  let res = await getVentanalyCamera({ deviceid: Id })
+  console.log(res, 'xin---------------')
   if (res.records.length != 0) {
     const cameraList = <{ name: string, addr: string }[]>[]
     const cameras = res.records

+ 5 - 2
src/views/vent/reportManager/comment/NormalTable.vue

@@ -34,7 +34,10 @@ import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns';
 import { useListPage } from '/@/hooks/system/useListPage';
 
 const props = defineProps({
-  
+  reportType:{
+    type:String,
+    default:''
+  },
   //下载文件接口
   downLoad: {
     type: Function,
@@ -116,7 +119,7 @@ const { prefixCls, tableContext, onExportXls, onImportXls, doRequest } = useList
       width: 180,
     },
     beforeFetch: (params) => {
-      return Object.assign(params, { column: 'createTime', });
+      return Object.assign(params , { column: 'createTime',reportType:props.reportType });
     },
   },
 });

+ 12 - 0
src/views/vent/reportManager/comment/common/Icon/index.vue

@@ -0,0 +1,12 @@
+<template>
+  <svg aria-hidden="true">
+    <use :xlink:href="name" />
+  </svg>
+</template>
+<script setup lang="ts">
+  import { computed } from 'vue';
+  const props = defineProps<{
+    iconName: string;
+  }>();
+  const name = computed(() => `#${props.iconName}`);
+</script>

+ 42 - 0
src/views/vent/reportManager/comment/common/Icon/treeIcon.vue

@@ -0,0 +1,42 @@
+<template>
+  <icon class="iconfont" :iconName="iconNam" />
+</template>
+<script setup lang="ts">
+  import icon from './index.vue';
+  import { computed } from 'vue';
+  const type = {
+    file: 'icon-document',
+    // js: 'icon-javascript',
+    // json: 'icon-json',
+    // vue: 'icon-vue',
+    // scss: 'icon-sass',
+    // file: 'icon-file',
+    // md: 'icon-mdx',
+    // tsx: 'icon-react1',
+    // ts: 'icon-typescript',
+    // css: 'icon-css',
+    // png: 'icon-image',
+    // jpg: 'icon-image',
+    // jpeg: 'icon-image',
+    // webp: 'icon-image',
+    // gif: 'icon-image',
+    // html: 'icon-html',
+    // babelrc: 'icon-babel',
+  };
+  const props = defineProps({
+    title: String,
+  });
+  const iconNam = computed(() => {
+    // const suffix = (props.title || '.file').split('.').pop().toLowerCase();
+    // console.log(suffix, 'suffix');
+    // if (props.title == 'package.json') return 'icon-npm';
+    // return type[suffix];
+    return type['file'];
+  });
+</script>
+<style lang="less" scoped>
+  .iconfont {
+    width: 16px;
+    height: 16px;
+  }
+</style>

+ 63 - 0
src/views/vent/reportManager/comment/common/cameraTree.vue

@@ -0,0 +1,63 @@
+<template>
+  <treeList
+    v-for="model in list"
+    v-bind="$attrs"
+    :model="model"
+    :key="model.id"
+    @detail-node="onDetail"
+  >
+    <template #icon="slotProps">
+      <slot name="icon" v-bind="slotProps"></slot>
+    </template>
+    <template #operation="slotProps">
+      <slot name="operation" v-bind="slotProps"></slot>
+    </template>
+  </treeList>
+</template>
+<script setup lang="ts">
+  import { ref } from 'vue';
+  import treeList from './treeList.vue';
+  const emit = defineEmits([ 'detailNode']);
+  interface IFileSystem {
+    id: string;
+    title: string;
+    pid: string;
+    isFolder: boolean;
+    isAdd: boolean;
+    children?: IFileSystem[];
+  }
+  const props = withDefaults(
+    defineProps<{
+      list: IFileSystem[];
+    }>(),
+    {}
+  );
+  // 递归寻找父组件
+  function findParent(pid, Tree) {
+    let targetNode = null;
+    function find(item, flattenTree) {
+      flattenTree.find((ele) => {
+        if (ele.id == pid) {
+          targetNode = ele;
+          return true;
+        } else {
+          if (ele.children) {
+            find(pid, ele.children);
+          }
+        }
+      });
+    }
+    find(pid, Tree);
+    return targetNode.children;
+  }
+  // 删除
+  const onDetail = (node) => {
+    emit('detailNode', {
+      ...node,
+      eventType: 'detail',
+    });
+  };
+ 
+  
+</script>
+<style scoped></style>

+ 184 - 0
src/views/vent/reportManager/comment/common/treeList.vue

@@ -0,0 +1,184 @@
+<template>
+  <div class="vtl-node" :id="model.id" :class="{ 'vtl-leaf-node': !isFolder, 'vtl-tree-node': isFolder }">
+    <div
+      :class="treeNodeClass"
+      @mouseover="mouseOver"
+      @mouseout="mouseOut"
+      @click.stop="toggle"
+    >
+      <div class="vtl-border-text">
+        <template v-if="isFolder">
+          <slot v-if="expanded" :item="{ title: model.title, isFolder: true, expanded: true }" name="icon"> </slot>
+          <slot v-else :item="{ title: model.title, isFolder: true, expanded: false }" name="icon"></slot>
+       
+        </template>
+        <slot v-else :item="{ title: model.title, isFolder: false }" name="icon"></slot>
+        <span class="vtl-node-content ellipsis" >
+          {{ model.title }}
+        </span>
+      </div>
+      <div class="vtl-operation" v-show="isHover && !isFolder">
+        <span @click.stop.prevent="delNode">
+          <slot name="operation" type="detailNode"></slot>
+        </span>
+      </div>
+    </div>
+  </div>
+  <div class="vtl-tree-margin" v-show="expanded">
+    <!-- 这里无法使用$attr来透传属性官方还未解决此bug -->
+    <treeList
+      @on-click="(depth) => $emit('onClick', depth)"
+      @detail-node="(depth) => $emit('detailNode', depth)"
+      v-for="newmodel in model.children"
+      :selected="selected"
+      :model="newmodel"
+      :key="newmodel.id"
+    >
+      <template #icon="slotProps">
+        <slot name="icon" v-bind="slotProps"></slot>
+      </template>
+      <template #operation="slotProps">
+        <slot name="operation" v-bind="slotProps"></slot>
+      </template>
+    </treeList>
+  </div>
+</template>
+<script setup lang="ts">
+  import { computed, ref,  } from 'vue';
+  interface IFileSystem {
+    id: string;
+    title: string;
+    pid: string;
+    isFolder: boolean;
+    isAdd: boolean;
+    children?: IFileSystem[];
+  }
+  // 吐出去的事件
+  const emit = defineEmits([
+    'onClick',
+    'detailNode',
+  ]);
+  // 拿到传入的值
+  const props = withDefaults(
+    defineProps<{
+      model: IFileSystem;
+      selected: IFileSystem;
+    }>(),
+    {
+      // draggable: false,
+    }
+  );
+  //是否移入
+  const isHover = ref(false);
+  // 是否展开
+  const expanded = ref(true);
+  // 是否是文件夹
+  const isFolder = computed(() => {
+    return props.model.isFolder;
+  });
+  const isSelected = computed(() => props.selected.id === props.model.id);
+  // 拖拽样式
+  const treeNodeClass = computed(() => {
+    return {
+      'vtl-node-main': true,
+      selected: isSelected.value,
+    };
+  });
+ 
+  // 删除目录
+  const delNode = () => {
+    emit('detailNode', {
+      ...props.model,
+      eventType: 'detail',
+    });
+  };
+ 
+  
+  // 展开收起
+  const toggle = () => {
+    if (isFolder.value ) {
+      expanded.value = !expanded.value;
+      emit('onClick', {
+        ...props.model,
+      }); //lxh
+    } else {
+      emit('onClick', {
+        ...props.model,
+      });
+    }
+  };
+  // 拖拽结束
+  const mouseOver = () => {
+    isHover.value = true;
+  };
+  // 移出
+  const mouseOut = () => {
+    isHover.value = false;
+  };
+ 
+  
+  
+</script>
+<style lang="less">
+  .vtl-node {
+    .vtl-node-main {
+      display: flex;
+      align-items: center;
+      padding: 2px 0 2px 2px;
+      cursor: pointer;
+
+      &:hover {
+        .vtl-border-text {
+          width: 80%;
+        }
+      }
+
+      .vtl-border-text {
+        display: flex; //lxh
+        flex: 1;
+        align-items: center; //lxh
+        width: 100%;
+        padding-left: 5px;
+
+        .iconfont {
+          width: 16px;
+          height: 16px;
+          vertical-align: text-bottom;
+        }
+      }
+
+      &.selected {
+        // background-color: rgba(45, 113, 134, 0.2);
+        background-color: #1c4869;
+      }
+
+   
+
+      .vtl-node-content {
+        color: #fff;
+        padding-left: 5px;
+        font-size: 14px;
+        width: 80%;
+        display: inline-block;
+        vertical-align: bottom;
+      }
+
+      &:hover {
+        .vtl-node-content {
+          color: #fff;
+          overflow: hidden;
+        }
+      }
+
+
+
+      .vtl-operation {
+        padding-right: 10px;
+      }
+    }
+  }
+
+  .vtl-tree-margin {
+    padding-left: 1em;
+  }
+</style>

+ 127 - 34
src/views/vent/reportManager/index.vue

@@ -2,51 +2,144 @@
   <div class="reportManager">
     <customHeader>报表管理中心</customHeader>
     <div class="content">
-      <NormalTable
-        v-if="refesh"
-        :columns="columns"
-        :searchFormSchema="searchFormSchema"
-        :deleteById="deleteById"
-        :downLoad="downLoad"
-        :list="reportList"
-        designScope="device-tabel"
-        title="报表管理"
-        :showTab="true"
-        @saveAdd="saveAdd"
-      />
+      <div class="left-box">
+        <!-- 左侧树菜单 -->
+        <fileSystem :selected="selected" :list="listArr" :draggable="true" @on-click="onClick">
+          <template #icon="{ item }">
+            <template v-if="item.isFolder">
+              <SvgIcon v-if="item.expanded" size="18" name="file-open" />
+              <SvgIcon v-else size="18" name="file-close" />
+            </template>
+            <treeIcon class="iconfont" :title="item.title" v-else />
+          </template>
+        </fileSystem>
+      </div>
+      <div class="right-box">
+        <NormalTable :key="dataNow" :reportType="reportType" :columns="columns" :searchFormSchema="searchFormSchema"
+          :deleteById="deleteById" :downLoad="downLoad" :list="reportList" designScope="device-tabel" title="报表管理"
+          :showTab="true" @saveAdd="saveAdd" />
+      </div>
+
     </div>
   </div>
 </template>
 
 <script setup lang="ts">
-  import { ref, nextTick } from 'vue';
-  import customHeader from '/@/components/vent/customHeader.vue';
-  import NormalTable from './comment/NormalTable.vue';
-  import { columns, searchFormSchema } from './reportManager.data';
-  import { reportList, save, deleteById, downLoad } from './reportManager.api';
-
-  let refesh = ref(true);
-  async function saveAdd(params) {
-    let res = await save({ ...params });
-    console.log(res, '新增成功-------');
-    refesh.value = false;
-    nextTick(() => {
-      refesh.value = true;
-    });
+import { ref, nextTick, reactive, onMounted } from 'vue';
+import customHeader from '/@/components/vent/customHeader.vue';
+import fileSystem from './comment/common/cameraTree.vue';
+import { SvgIcon } from '/@/components/Icon';
+import treeIcon from './comment/common/Icon/treeIcon.vue';
+import NormalTable from './comment/NormalTable.vue';
+import { columns, searchFormSchema } from './reportManager.data';
+import { reportList, save, deleteById, downLoad } from './reportManager.api';
+import { getDictItemsByCode } from '/@/utils/dict';
+
+let dataNow = ref(0)
+let reportType = ref('')
+
+//左侧菜单列表
+let listArr = reactive<any[]>([
+  {
+    pid: 'root',
+    isFolder: true,
+    title: '全部',
+    id: '',
+    children: []
   }
+]);
+//lxh 当前选中树节点
+let selected = reactive<any>({
+  id: null,
+  pid: null,
+  title: '',
+  isFolder: false,
+});
+
+//获取左侧菜单树
+function getTreeList() {
+  const res = getDictItemsByCode('reportType')
+  console.log(res, 'res====----')
+  if (res.length != 0) {
+    listArr[0].children.length = 0
+    res.forEach(el => {
+      listArr[0].children.push({
+        pid: '',
+        isFolder: false,
+        title: el.label,
+        id: el.value,
+        children: []
+      })
+    })
+
+  }
+}
+//点击目录
+async function onClick(node) {
+  // if (node.pid != 'root') {
+    console.log(node, 'node--------------')
+    selected.id = node.id;
+    selected.pid = node.pid;
+    selected.title = node.title;
+    selected.isFolder = node.isFolder;
+    reportType.value = node.id
+    dataNow.value = new Date().getTime()
+  // }
+
+};
+
+async function saveAdd(params) {
+  let res = await save({ ...params });
+  console.log(res, '新增成功-------');
+  dataNow.value = new Date().getTime()
+}
+
+onMounted(() => {
+  getTreeList()
+})
 </script>
 
 <style lang="less" scoped>
-  .reportManager {
-    width: calc(100% - 20px);
-    height: calc(100% - 90px);
+.reportManager {
+  width: calc(100% - 20px);
+  height: calc(100% - 90px);
+  position: relative;
+  margin: 80px 10px 10px 10px;
+
+  .content {
+    width: 100%;
+    height: calc(100% - 30px);
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: flex-start;
     position: relative;
-    margin: 80px 10px 10px 10px;
 
-    .content {
-      width: 100%;
-      height: calc(100% - 30px);
-      position: relative;
+    // z-index: 999;
+    .left-box {
+      width: 15%;
+      height: 100%;
+      padding: 20px;
+      border: 1px solid #99e8ff66;
+      background: #27546e1a;
+      box-shadow: 0px 0px 20px 7px rgba(145, 233, 254, 0.7) inset;
+      -moz-box-shadow: 0px 0px 20px 7px rgba(145, 233, 254, 0.7) inset;
+      -webkit-box-shadow: 0px 0px 50px 1px rgb(149 235 255 / 5%) inset;
+
+      // lxh
+      .iconfont {
+        color: #fff;
+        font-size: 12px;
+        margin-left: 5px;
+      }
+    }
+
+    .right-box {
+      width: 85%;
+      height: 100%;
+      padding: 0px 0px 0px 15px;
+      box-sizing: border-box;
     }
   }
+}
 </style>