Bläddra i källkod

Merge branch 'master' into onemap_zmg

mork 1 månad sedan
förälder
incheckning
386dc4f22d

+ 36 - 2
package-lock.json

@@ -13,6 +13,7 @@
         "echarts": "^5.6.0",
         "element-plus": "^2.2.15",
         "vue": "^3.2.13",
+        "vue-json-editor": "^1.4.3",
         "vue-json-viewer": "^3.0.4",
         "vue-router": "^4.0.3",
         "vue3-lottie": "^3.3.1",
@@ -5667,7 +5668,6 @@
     },
     "node_modules/prettier": {
       "version": "2.8.8",
-      "dev": true,
       "license": "MIT",
       "optional": true,
       "bin": {
@@ -6450,7 +6450,6 @@
     },
     "node_modules/source-map": {
       "version": "0.6.1",
-      "dev": true,
       "license": "BSD-3-Clause",
       "engines": {
         "node": ">=0.10.0"
@@ -7039,6 +7038,41 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/vue-json-editor": {
+      "version": "1.4.3",
+      "resolved": "https://registry.npmmirror.com/vue-json-editor/-/vue-json-editor-1.4.3.tgz",
+      "integrity": "sha512-st9HdXBgCnyEmmfWrZQiKzp4KuYXzmYVUNDn5h6Fa18MrrGS1amnyUFyv7hQFsNBDW27B7BKkdGOqszYT1srAg==",
+      "dependencies": {
+        "vue": "^2.2.6"
+      },
+      "engines": {
+        "node": ">= 4.0.0",
+        "npm": ">= 3.0.0"
+      }
+    },
+    "node_modules/vue-json-editor/node_modules/@vue/compiler-sfc": {
+      "version": "2.7.16",
+      "resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-2.7.16.tgz",
+      "integrity": "sha512-KWhJ9k5nXuNtygPU7+t1rX6baZeqOYLEforUPjgNDBnLicfHCoi48H87Q8XyLZOrNNsmhuwKqtpDQWjEFe6Ekg==",
+      "dependencies": {
+        "@babel/parser": "^7.23.5",
+        "postcss": "^8.4.14",
+        "source-map": "^0.6.1"
+      },
+      "optionalDependencies": {
+        "prettier": "^1.18.2 || ^2.0.0"
+      }
+    },
+    "node_modules/vue-json-editor/node_modules/vue": {
+      "version": "2.7.16",
+      "resolved": "https://registry.npmmirror.com/vue/-/vue-2.7.16.tgz",
+      "integrity": "sha512-4gCtFXaAA3zYZdTp5s4Hl2sozuySsgz4jy1EnpBHNfpMa9dK1ZCG7viqBPCwXtmgc8nHqUsAu3G4gtmXkkY3Sw==",
+      "deprecated": "Vue 2 has reached EOL and is no longer actively maintained. See https://v2.vuejs.org/eol/ for more details.",
+      "dependencies": {
+        "@vue/compiler-sfc": "2.7.16",
+        "csstype": "^3.1.0"
+      }
+    },
     "node_modules/vue-json-viewer": {
       "version": "3.0.4",
       "resolved": "https://mirrors.huaweicloud.com/repository/npm/vue-json-viewer/-/vue-json-viewer-3.0.4.tgz",

+ 1 - 0
package.json

@@ -12,6 +12,7 @@
     "echarts": "^5.6.0",
     "element-plus": "^2.2.15",
     "vue": "^3.2.13",
+    "vue-json-editor": "^1.4.3",
     "vue-json-viewer": "^3.0.4",
     "vue-router": "^4.0.3",
     "vue3-lottie": "^3.3.1",

+ 6 - 0
public/static/config/config.js

@@ -5,10 +5,16 @@ let systemConfig = {
         password: "Yysz@1234002"
     },
     baseServicerPath: "/oneMap",
+    // oauth和DMS环境
+    backServerPath: "http://121.43.55.7",
     // oauth地址
     oauthServiceUrlOrigin: "http://121.43.55.7:10086/",
     // oauth地址
     oauthServiceUrl: "/proxy_oauth",
+    // oauth前端地址
+    oauthWebUrlPort: "2100",
+    // dms前端地址
+    dmsWebUrlPort: "2101",
     // dms地址
     dmsDataProxy: "/proxy_dms",
     // 引擎基础js

BIN
src/assets/images/common/home-bg2.png


BIN
src/assets/images/common/home-bg3.png


BIN
src/assets/images/common/home-bg4.png


BIN
src/assets/images/common/home-bg5.png


BIN
src/assets/images/common/home-bg6.png


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 461 - 460
src/components/wgn/controlPanel.vue


+ 42 - 98
src/components/yxgl/EchartsDome.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="echartsDome">
     <div class="echartsDome_title">{{ title }}</div>
-    <div class="echartsDome_chart" ref="chartContainer" id="yxglEchart"></div>
+    <div class="echartsDome_chart" ref="chartContainer"></div>
   </div>
 </template>
 
@@ -14,106 +14,53 @@ export default {
       type: String,
       default: "图表标题",
     },
+    chartOption: {
+      type: Object,
+      default: {},
+    },
   },
   data() {
-    return {
-      chart: null,
-    };
+    return {};
   },
   mounted() {
-    this.initChart();
+    this.$nextTick(() => {
+      this.initChart();
+    });
+  },
+  watch: {
+    chartOption: {
+      handler(newVal, oldVal) {
+        if (newVal.length > 0) {
+          this.initChart();
+        }
+      },
+      deep: true,
+    },
   },
   methods: {
     initChart() {
-      let chart = echarts.init(document.getElementById("yxglEchart"));
-
-      let option = {
-        legend: {
-          data: ["调用次数", "平均响应时间"],
-        },
-        tooltip: {
-          show: true,
-          trigger: "axis",
-          axisPointer: { type: "shadow" },
-          // 给不同Y轴的提示文字加对应颜色
-          // formatter: (params) => {
-          //   let html = `<div style="color:#333;z-index:100;">${params[0].axisValue}</div>`;
-          //   params.forEach((item) => {
-          //     // 调用次数
-          //     if (item.yAxisIndex === 0) {
-          //       html += `<div style="color:#42a5f5">${item.seriesName}:${item.value}</div>`;
-          //     }
-          //     // 平均响应时间
-          //     else if (item.yAxisIndex === 1) {
-          //       html += `<div style="color:#4caf50">${item.seriesName}:${item.value}</div>`;
-          //     }
-          //   });
-          //   return html;
-          // },
-        },
-        xAxis: {
-          type: "category",
-          data: [
-            "Jan",
-            "Feb",
-            "Mar",
-            "Apr",
-            "May",
-            "Jun",
-            "Jul",
-            "Aug",
-            "Sep",
-            "Oct",
-            "Nov",
-          ],
-          axisTick: { show: false }, // 隐藏刻度
-          splitLine: { show: false }, // 隐藏分割线
-        },
-        yAxis: [
-          {
-            type: "value",
-            name: "调用次数", // 第一个Y轴(左侧)
-            axisLine: { lineStyle: { color: "#42a5f5" } }, // 区分样式
-          },
-          {
-            type: "value",
-            name: "响应时间(ms)", // 第二个Y轴(右侧)
-            position: "right", // 显示在右侧(关键)
-            axisLine: { lineStyle: { color: "#4caf50" } }, // 区分样式
-          },
-        ],
-        series: [
-          {
-            name: "调用次数",
-            type: "line",
-            smooth: true,
-            data: [7, 7, 15, 19, 21, 22, 25, 26, 23, 19, 12], // 模拟数据
-            lineStyle: { color: "#42a5f5" }, // 蓝色线条
-            itemStyle: { color: "#42a5f5" }, // 节点颜色
-            symbol: "circle", // 节点形状
-            symbolSize: 6, // 节点大小
-            yAxisIndex: 0, // 绑定第一个Y轴(调用次数)
-          },
-          {
-            name: "平均响应时间",
-            type: "line",
-            smooth: true,
-            data: [3, 3, 6, 12, 15, 17, 18, 17, 14, 10, 6], // 模拟数据
-            lineStyle: { color: "#4caf50", type: "dashed" }, // 绿色线条
-            itemStyle: {
-              color: "#4caf50",
-              color: "#FFF",
-              borderWidth: 2,
-              borderColor: "#4caf50",
-            },
-            symbol: "circle",
-            symbolSize: 6,
-            yAxisIndex: 1, // 绑定第二个Y轴(响应时间)
+      let chartDom = echarts.init(this.$refs.chartContainer);
+      if (this.chartOption) {
+        // 绘制图表
+        this.chartOption.grid = {
+          top: 80,
+          left: 10, // 核心1:grid左侧距离容器左侧0px
+          right: 50, // 核心2:grid右侧距离容器右侧0px
+          bottom: 0,
+          containLabel: true, // 关键:防止坐标轴标签超出容器(可选,根据需求添加)
+        };
+        if (!this.chartOption.legend) {
+          this.chartOption.legend = {};
+        }
+        Object.assign(this.chartOption.legend, {
+          textStyle: {
+            color: "#F2F3F5", // 字体颜色(支持十六进制、RGB、颜色名)
+            fontSize: 14, // 可选:字体大小
+            fontWeight: "normal", // 可选:字体粗细
           },
-        ],
-      };
-      // 绘制图表
-      chart.setOption(option);
+        });
+        chartDom.setOption(this.chartOption);
+      }
     },
   },
 };
@@ -122,18 +69,15 @@ export default {
 <style scoped>
 .echartsDome {
   width: 100%;
-  height: 400px;
-  /* background-color: #222;
-  color: #fff; */
+  height: 100%;
   padding: 20px;
   box-sizing: border-box;
 }
 .echartsDome_title {
   font-size: 16px;
-  /* font-weight: bold; */
 }
 .echartsDome_chart {
   width: 100%;
-  height: 360px;
+  height: calc(100% - 40px);
 }
 </style>

+ 86 - 0
src/components/yxgl/table.vue

@@ -0,0 +1,86 @@
+<template>
+  <div class="table_box">
+    <div class="table_title">{{ title }}</div>
+    <div class="table_more">
+      <el-button type="primary" link> 更多 </el-button>
+    </div>
+    <el-table
+      :data="tableData"
+      style="width: 100%; background-color: #00000032"
+      height="calc(100% - 60px)"
+    >
+      <el-table-column prop="serviceName" label="服务名称" width="300" />
+      <el-table-column prop="serviceType" label="类别" width="300" />
+      <el-table-column prop="callCount" label="调用次数" width="480" />
+      <el-table-column prop="successRate" label="成功率" width="180" />
+      <el-table-column prop="avgResponseTime" label="平均响应" />
+    </el-table>
+    <div class="table_pagination">
+      <el-pagination
+        v-model:current-page="currentPage"
+        v-model:page-size="pageSize"
+        :page-sizes="[100, 200, 300, 400]"
+        background
+        layout="total, sizes, prev, pager, next, jumper"
+        :total="400"
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"
+      />
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "Table",
+  props: {
+    title: {
+      type: String,
+      default: "图表标题",
+    },
+    tableData: {
+      type: Array,
+      default: () => [],
+    },
+  },
+  data() {
+    return {
+      pageSize: 100,
+      currentPage: 1,
+    };
+  },
+  methods: {
+    handleSizeChange(val) {
+      this.pageSize = val;
+    },
+    handleCurrentChange(val) {
+      this.currentPage = val;
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.table_box {
+  width: 100%;
+  height: 100%;
+  padding: 20px;
+  box-sizing: border-box;
+  position: relative;
+}
+.table_title {
+  font-size: 16px;
+}
+.table_more {
+  position: absolute;
+  top: 20px;
+  right: 20px;
+  font-size: 14px;
+  color: #1890ff;
+}
+.table_pagination {
+  position: absolute;
+  bottom: 20px;
+  right: 20px;
+}
+</style>

+ 2 - 0
src/main.js

@@ -17,6 +17,8 @@ initApp.use(ElementPlus, {
 import * as ElementPlusIconsVue from '@element-plus/icons-vue'
 import JsonViewer from 'vue-json-viewer'
 initApp.component('JsonViewer', JsonViewer)
+import VueJsonEditor from 'vue-json-editor'
+initApp.component('VueJsonEditor', VueJsonEditor)
 
 for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
     initApp.component(key, component)

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 844 - 182
src/views/HomePage.vue


+ 37 - 16
src/views/Sksjgl.vue

@@ -66,10 +66,12 @@
                 </div>
                 <!-- 功能卡片列表 -->
                 <!-- 单个功能卡片 -->
-                <div class="card-item" v-for="(item, index) in cardList" :key="index">
-                    <div class="card-title">{{ item.title }}</div>
-                    <div class="card-bg" :style="{ backgroundColor: item.bgColor }"></div>
-                    <div class="card-desc">{{ item.desc }}</div>
+                <div class="card-list">
+                    <div class="card-item" v-for="(item, index) in cardList" :key="index">
+                        <div class="card-title">{{ item.title }}</div>
+                        <div class="card-bg" :style="{ backgroundColor: item.bgColor }"></div>
+                        <div class="card-desc">{{ item.desc }}</div>
+                    </div>
                 </div>
             </div>
 
@@ -253,7 +255,6 @@ export default {
                 height: 400px;
                 // background: #f0f8ff;
                 // border: 1px solid #409eff;
-
                 display: flex;
                 align-items: center;
                 justify-content: center;
@@ -268,17 +269,23 @@ export default {
                         width: 100%;
                         height: 361px;
                         border-radius: 8px;
+                        transition: all 0.3s ease;
                     }
 
                     .label {
                         color: #ffffff;
                         text-align: center;
-                        height: 50px;
-                        line-height: 50px;
+                        height: 70px;
+                        line-height: 70px;
                         font-size: 24px;
                     }
                 }
 
+                &:hover .pictrue {
+                    transform: scale(1.05) translateY(-5px);
+                    box-shadow: 0 10px 30px rgba(24, 144, 255, 0.3);
+                    border-color: rgba(24, 144, 255, 0.6);
+                }
 
             }
         }
@@ -288,17 +295,16 @@ export default {
     .time-space-operator-lib {
         background-color: #1e407c;
         color: #fff;
-        padding: 50px 150px;
-        height: 700px;
+        padding: 100px 150px;
         box-sizing: border-box;
 
         /* 标题区域 */
         .title-section {
             text-align: center;
-            margin-bottom: 20px;
+            margin-bottom: 50px;
 
             h1 {
-                font-size: 28px;
+                font-size: 50px;
                 font-weight: bold;
             }
         }
@@ -306,14 +312,19 @@ export default {
         /* 描述区域 */
         .desc-section {
             margin-bottom: 30px;
-            line-height: 1.6;
-            font-size: 14px;
-            opacity: 0.9;
+            line-height: 2;
+            font-size: 20px;
+            text-indent: 2em;
         }
 
         /* 业务专区区域 */
         .business-section {
             margin-top: 20px;
+            border-radius: 16px 16px 16px 16px;
+            background-color: rgba(31, 41, 55, 0.16);
+            border: 1px solid #374151;
+            padding: 20px 20px;
+            box-sizing: border-box;
 
             .business-header {
                 display: flex;
@@ -322,6 +333,10 @@ export default {
                 margin-bottom: 15px;
                 font-size: 16px;
 
+                span {
+                    font-size: 20px;
+                }
+
                 .more-btn {
                     background-color: transparent;
                     border: 1px solid #fff;
@@ -337,16 +352,22 @@ export default {
         .card-list {
             display: grid;
             grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
-            gap: 20px;
+            gap: 55px;
 
             .card-item {
                 background-color: rgba(255, 255, 255, 0.1);
                 padding: 15px;
                 border-radius: 8px;
-                height: 180px;
+                height: 240px;
                 display: flex;
                 flex-direction: column;
 
+                &:hover {
+                    cursor: pointer;
+                    box-shadow: 0 10px 30px rgba(24, 144, 255, 0.3);
+                    border-color: rgba(24, 144, 255, 0.6);
+                }
+
                 .card-title {
                     font-size: 15px;
                     font-weight: 500;

+ 39 - 21
src/views/Wgn.vue

@@ -1,8 +1,9 @@
 <template>
-  <div class="container">
+  <div class="wgn_box">
+    <el-backtop target=".wgn_box" :right="20" :bottom="70" />
     <div class="server_title">
       <el-image
-        style="width: 824px; height: 786px"
+        style="width: 824px; height: calc(100vh - 70px)"
         src="static/images/wgn_title.png"
         fit="cover"
       />
@@ -18,27 +19,29 @@
     </div>
     <div class="server_list_box">
       <div class="server_list_box_title">微功能列表</div>
-      <div class="server_list_box_search">
-        功能搜索
-        <el-input
-          v-model="searchStr"
-          style="width: 525px; margin-left: 37px"
-          placeholder="输入搜索关键词"
-          class="input-with-select"
-          clearable
-          size="large"
-          @change="searchServerList()"
-        >
-          <template #append>
-            <el-button icon="Search" @click="searchServerList()" />
-          </template>
-        </el-input>
-      </div>
+      <el-affix :offset="0">
+        <div class="server_list_box_search">
+          <el-input
+            v-model="searchStr"
+            style="width: 525px; margin-left: 37px"
+            placeholder="输入搜索关键词"
+            class="input-with-select"
+            clearable
+            size="large"
+            @change="searchServerList()"
+          >
+            <template #append>
+              <el-button icon="Search" @click="searchServerList()" />
+            </template>
+          </el-input>
+        </div>
+      </el-affix>
       <div class="server_list_box_table" v-if="dmsServerList">
         <div
           v-for="item in dmsServerList"
           :key="item.c_scene_name"
           class="server_list_box_table_item"
+          :id="item.c_scene_name + 'list'"
         >
           <div class="server_list_box_table_item_content">
             <div class="server_list_box_table_item_content_title">{{ item.title }}</div>
@@ -108,7 +111,8 @@ export default {
         ]);
       }
       // 获取微功能服务列表
-      wgn.getDmsData(requestParams)
+      wgn
+        .getDmsData(requestParams)
         .then((res) => {
           if (res.code === 200) {
             this.dmsServerList = res.content.data;
@@ -163,7 +167,7 @@ export default {
 </script>
 
 <style lang="less" scoped>
-.container {
+.wgn_box {
   width: 100vw;
   margin: 0 auto;
   background-color: #08224a;
@@ -175,7 +179,7 @@ export default {
 }
 .server_title_text {
   width: calc(100vw - 824px);
-  height: 786px;
+  height: calc(100vh - 70px);
   background-color: #1c2631;
   color: #fff;
   padding: 0 160px 0 60px;
@@ -193,6 +197,10 @@ export default {
     font-size: 22px;
   }
 }
+.anchor_box {
+  background: #ffffff32;
+  float: left;
+}
 .server_list_box {
   width: 100vw;
   background-color: rgba(0, 0, 0, 0.15);
@@ -200,6 +208,13 @@ export default {
   flex-direction: column;
   align-items: center;
   color: #fff;
+  position: relative;
+  &_menu {
+    position: absolute;
+    top: 100px;
+    left: 10px;
+    z-index: 1;
+  }
   &_title {
     margin-top: 100px;
     font-size: 35px;
@@ -224,6 +239,9 @@ export default {
     align-items: center;
     width: -webkit-fill-available;
     justify-content: center;
+    .input-with-select {
+      background: #08224a;
+    }
   }
   &_table {
     margin-top: 50px;

+ 41 - 5
src/views/Yxgl.vue

@@ -6,6 +6,7 @@
       :collapse="isCollapse"
       @open="handleOpen"
       @close="handleClose"
+      @select="changeMenu"
     >
       <el-sub-menu index="/#">
         <template #title>
@@ -14,7 +15,7 @@
         </template>
         <el-menu-item index="StatisticalAnalysis">
           <el-icon><Histogram /></el-icon>
-          <template #title>统计分析</template>
+          <template #title>信息反馈</template>
         </el-menu-item>
       </el-sub-menu>
       <el-sub-menu index="2">
@@ -34,9 +35,15 @@
     </el-menu>
     <div
       class="viewBox"
-      :style="{ width: isCollapse ? 'calc(100vw - 60px)' : 'calc(100% - 200px)' }"
+      :style="{
+        width: isCollapse ? 'calc(100vw - 60px)' : 'calc(100% - 200px)',
+        background: menuActive == 'StatisticalAnalysis' ? '#08224a' : '#08224a',
+        overflowY: menuActive == 'StatisticalAnalysis' ? 'auto' : 'hidden',
+      }"
     >
-      <StatisticalAnalysis />
+      <el-backtop target=".viewBox" :right="20" :bottom="70" />
+      <StatisticalAnalysis v-if="menuActive == 'StatisticalAnalysis'" />
+      <iframe v-else :src="iframeUrl" frameborder="0"></iframe>
     </div>
   </div>
 </template>
@@ -49,6 +56,7 @@ export default {
     return {
       isCollapse: false,
       menuActive: "StatisticalAnalysis",
+      iframeUrl: "",
     };
   },
   // 2. 局部注册组件(键值同名可简写)
@@ -63,6 +71,30 @@ export default {
     handleClose(key, keyPath) {
       console.log(key, keyPath);
     },
+    changeMenu(key, keyPath) {
+      this.menuActive = key;
+      switch (key) {
+        case "dms":
+          // window.open(
+          //   systemConfig.backServerPath + ":" + systemConfig.dmsWebUrlPort,
+          //   "_blank"
+          // );
+          this.iframeUrl = systemConfig.backServerPath + ":" + systemConfig.dmsWebUrlPort;
+          break;
+        case "oauth":
+          // window.open(
+          //   systemConfig.backServerPath + ":" + systemConfig.oauthWebUrlPort,
+          //   "_blank"
+          // );
+
+          this.iframeUrl =
+            systemConfig.backServerPath + ":" + systemConfig.oauthWebUrlPort;
+          break;
+        default:
+          break;
+      }
+      console.log(this.menuActive, this.iframeUrl);
+    },
   },
 };
 </script>
@@ -80,7 +112,7 @@ export default {
   width: 200px;
   height: calc(100vh - 120px);
   margin: 0;
-  //   background: #08224a;
+  background: #08224a;
 }
 .viewBox {
   width: calc(100vw - 200px);
@@ -89,6 +121,10 @@ export default {
   position: relative;
   overflow: hidden;
   overflow-y: auto;
-  background-color: #eee;
+}
+iframe {
+  width: 100%;
+  height: calc(100% - 10px);
+  background: #08224a;
 }
 </style>

+ 95 - 88
src/views/skmh/scene/index.vue

@@ -1,110 +1,117 @@
 <template>
-    <div class="container">
-        <div style="padding: 20px;display: ruby-text;">
-            <div v-for="info in listData" :key="info" style="padding: 20px;">
-                <el-card style="border-radius: 10px !important;" @click="openVideo(info)">
-                    <div class="card picDiv"><img :src="info.img" ></div>
-                    <template #footer>
-                        <div style="width: 260px;">
-                            <div style="font-weight: bold;padding-bottom: 10px;">{{info.title}}</div>
-                            <div class="ellipsis3">
-                                <el-popover
-                                    title=""
-                                    width="300"
-                                    effect="dark"
-                                    :content="info.desc"
-                                    placement="top-start"
-                                >
-                                    <template #reference>
-                                        <div>{{info.desc}}</div>
-                                    </template>
-                                </el-popover>
-                            </div>
-                        </div>
-                    </template>
-                </el-card>
+  <div class="container">
+    <div style="padding: 20px; display: ruby-text">
+      <div v-for="info in listData" :key="info" style="padding: 20px">
+        <el-card style="border-radius: 10px !important" @click="openVideo(info)">
+          <div class="card picDiv"><img :src="info.img" /></div>
+          <template #footer>
+            <div style="width: 260px">
+              <div style="font-weight: bold; padding-bottom: 10px">{{ info.title }}</div>
+              <div class="ellipsis3">
+                <el-popover
+                  title=""
+                  width="300"
+                  effect="dark"
+                  :content="info.desc"
+                  placement="top-start"
+                >
+                  <template #reference>
+                    <div>{{ info.desc }}</div>
+                  </template>
+                </el-popover>
+              </div>
             </div>
-        </div>
-        <div>
-            <el-dialog v-model="centerDialogVisible" title="预览" width="800" center :before-close="closeDialog">
-                <video :src="videoUrl" controls style="width: 100%;"/>  
-            </el-dialog>
-        </div>
+          </template>
+        </el-card>
+      </div>
     </div>
+    <div>
+      <el-dialog
+        v-model="centerDialogVisible"
+        title="预览"
+        width="800"
+        center
+        :before-close="closeDialog"
+      >
+        <video :src="videoUrl" controls style="width: 100%" />
+      </el-dialog>
+    </div>
+  </div>
 </template>
 
 <script>
 export default {
-    name: "",
-    data() {
-        return {
-            listData:[],
-            centerDialogVisible:false,
-            videoUrl:''
-
+  name: "",
+  data() {
+    return {
+      listData: [],
+      centerDialogVisible: false,
+      videoUrl: "",
+    };
+  },
+  mounted() {
+    this.initData();
+  },
+  methods: {
+    initData() {
+      let that = this;
+      for (let i = 0; i < 10; i++) {
+        let str = {
+          url:
+            "https://realbot-oss.oss-accelerate.aliyuncs.com/scrm/2025/2025-05-21/659fa31d-dc87-4882-8be5-1fba8fb7e6ff/flower.mp4",
+          img: require("@static/images/u30.png"),
+          title: "无人机实时成图_" + i,
+          desc:
+            "无人机巡察场景可实时接入无人机视频画面,叠加到GIS场景中,实现边飞边出图的真实场景还原,并可将历史画面内容实现快速切图、上图展示,利用AI技术赋能无人机场景,实现无人机视频画面目标提取,实现关键目标要素点位标记及相关业务分析应用,可用于城市规划、应急、军用侦察等行业应用场景。",
         };
+        that.listData.push(str);
+      }
+    },
+    openVideo(param) {
+      this.videoUrl = param.url;
+      this.centerDialogVisible = true;
     },
-    mounted() {
-        this.initData()
+    closeDialog() {
+      this.videoUrl = "";
+      this.centerDialogVisible = false;
     },
-    methods: {
-        initData(){
-            let that = this;
-            for(let i=0; i<10; i++){
-                let str = {
-                    url:"https://realbot-oss.oss-accelerate.aliyuncs.com/scrm/2025/2025-05-21/659fa31d-dc87-4882-8be5-1fba8fb7e6ff/flower.mp4",
-                    img:require("@static/images/u30.png"),
-                    title:"无人机实时成图_"+i,
-                    desc:"无人机巡察场景可实时接入无人机视频画面,叠加到GIS场景中,实现边飞边出图的真实场景还原,并可将历史画面内容实现快速切图、上图展示,利用AI技术赋能无人机场景,实现无人机视频画面目标提取,实现关键目标要素点位标记及相关业务分析应用,可用于城市规划、应急、军用侦察等行业应用场景。"
-                }
-                that.listData.push(str);
-            }
-        },
-        openVideo(param){
-            this.videoUrl = param.url;
-            this.centerDialogVisible=true
-        },
-        closeDialog(){
-            this.videoUrl='';
-            this.centerDialogVisible=false
-        }
-    }
+  },
 };
 </script>
 
 <style lang="less" scoped>
-/deep/ .el-card__body{
-    padding: 0px !important;
-    height: 140px;
+:deep(.el-card__body) {
+  padding: 0px !important;
+  height: 140px;
 }
 .container {
-    width: 100%;
-    padding: 0px;
-    margin: 0 auto;
+  width: 100%;
+  padding: 0px;
+  margin: 0 auto;
 }
-.card{
-    float: left;
-    height: 150px;
-    width: 300px;
-    cursor: pointer;
-    box-sizing: border-box;
+.card {
+  float: left;
+  height: 150px;
+  width: 300px;
+  cursor: pointer;
+  box-sizing: border-box;
 }
-.picDiv{
-    overflow: hidden;
+.picDiv {
+  overflow: hidden;
 }
-.picDiv img{
-    width: 100%;
-    height: 100%;
-    transition: all 1s;
+.picDiv img {
+  width: 100%;
+  height: 100%;
+  transition: all 1s;
 }
-.picDiv img:hover{
-    transform:scale(1.2,1.2);
+.picDiv img:hover {
+  transform: scale(1.2, 1.2);
 }
-.ellipsis3{
-    display: -webkit-box;
-    -webkit-box-orient: vertical;
-    -webkit-line-clamp: 3;
-    overflow: hidden;
-    text-overflow: ellipsis;
+.ellipsis3 {
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-line-clamp: 3;
+  overflow: hidden;
+  text-overflow: ellipsis;
 }
-</style>
+</style>

+ 468 - 11
src/views/yxgl/StatisticalAnalysis.vue

@@ -64,40 +64,481 @@
       </div>
       <div class="flex">
         <div style="width: 48%; height: 400px">
-          <EchartsDome title="服务调用趋势(近30天)" />
+          <EchartsDome
+            :chartOption="chartOptions['服务调用趋势(近30天)']"
+            title="服务调用趋势(近30天)"
+          />
+        </div>
+        <div style="width: 48%; height: 400px">
+          <EchartsDome title="服务类别分布" :chartOption="chartOptions['服务类别分布']" />
         </div>
-        <div style="width: 48%; height: 400px">echarts2</div>
       </div>
-      <div style="width: 100%; height: 400px">tables</div>
+      <div style="width: 100%; height: 400px">
+        <Table title="服务调用" :tableData="tableDatas" />
+      </div>
     </div>
     <!-- 用户信息统计 -->
-    <div class="bigCard">用户信息统计</div>
+    <div class="bigCard">
+      <div class="bigCard_title">用户信息统计</div>
+      <div class="flex">
+        <div style="width: 28%; height: 400px">
+          <EchartsDome :chartOption="chartOptions['用户角色分布']" title="用户角色分布" />
+        </div>
+        <div style="width: 68%; height: 400px">
+          <EchartsDome
+            :chartOption="chartOptions['用户活跃度趋势']"
+            title="用户活跃度趋势"
+          />
+        </div>
+      </div>
+      <div style="width: 100%; height: 400px">
+        <EchartsDome :chartOption="chartOptions['用户部门分布']" title="用户部门分布" />
+      </div>
+    </div>
     <!-- 应用类信息统计 -->
-    <div class="bigCard">应用类信息统计</div>
+    <div class="bigCard">
+      <div class="bigCard_title">应用类信息统计</div>
+      <div class="flex">
+        <div style="width: 58%; height: 400px">
+          <EchartsDome
+            :chartOption="chartOptions['用户部门分布']"
+            title="热点应用TOP10排名"
+          />
+        </div>
+        <div style="width: 38%; height: 400px">
+          <EchartsDome :chartOption="chartOptions['服务类别分布']" title="应用状态分布" />
+        </div>
+      </div>
+    </div>
     <!-- 数据类信息统计 -->
-    <div class="bigCard">数据类信息统计</div>
+    <div class="bigCard">
+      <div class="bigCard_title">数据类信息统计</div>
+      <div class="flex">
+        <div style="width: 50%; height: 400px">
+          <EchartsDome :chartOption="chartOptions['数据类别分布']" title="数据类别分布" />
+        </div>
+        <div style="width: 50%; height: 400px">
+          <EchartsDome :chartOption="chartOptions['数据质量评分']" title="数据质量评分" />
+        </div>
+      </div>
+    </div>
     <!-- 区级特色信息统计 -->
-    <div class="bigCard">区级特色信息统计</div>
+    <div class="bigCard" style="background: #00000000">
+      <div class="bigCard_title">区级特色信息统计</div>
+      <div class="flex" style="margin-top: 20px">
+        <div class="flex_column" style="width: 28%; height: 420px">
+          <card
+            class="card2 flex"
+            :title="'服务机构总数'"
+            :value="8"
+            :growth="'较上个月增长了12%'"
+            iconColor="#2563db"
+            :upStatus="1"
+          />
+          <card
+            class="card2 flex"
+            :title="'服务总数'"
+            :value="100"
+            :growth="'较上个月下降了12%'"
+            iconColor="#16a34a"
+            :upStatus="-1"
+          />
+          <card
+            class="card2 flex"
+            :title="'服务调用总次数'"
+            :value="1000"
+            :growth="'较上个月增长了12%'"
+            iconColor="#9333ea"
+            :upStatus="1"
+          />
+        </div>
+        <div style="width: 68%; height: 420px">
+          <EchartsDome
+            :chartOption="chartOptions['服务调用趋势(近30天)']"
+            title="服务调用趋势(近30天)"
+          />
+        </div>
+      </div>
+    </div>
   </div>
 </template>
 
 <script>
 import card from "@/components/yxgl/card.vue";
 import EchartsDome from "@/components/yxgl/EchartsDome.vue";
+import Table from "@/components/yxgl/table.vue";
 export default {
   name: "",
   components: {
     card,
     EchartsDome,
+    Table,
   },
   data() {
     return {
       dateValue: "",
       shortcuts: this.shortcuts(),
+      chartOptions: {},
+      tableDatas: [],
     };
   },
-  mounted() {},
+  mounted() {
+    let datas = [
+      { value: 1048, name: "调用次数", value2: 3, date: "12/17" },
+      { value: 735, name: "平均响应时间", value2: 3, date: "12/18" },
+    ];
+
+    let datas2 = [
+      {
+        value: 20,
+        name: "业务数据",
+        children: [
+          { value: 7, name: "交通数据" },
+          { value: 5, name: "环保数据" },
+          { value: 5, name: "水务数据" },
+          { value: 3, name: "教育数据" },
+        ],
+      },
+      {
+        value: 13,
+        name: "基础数据",
+        children: [
+          { value: 5, name: "人口数据" },
+          { value: 5, name: "地理数据" },
+          { value: 3, name: "企业数据" },
+        ],
+      },
+      {
+        value: 9,
+        name: "专题数据",
+        children: [
+          { value: 4, name: "规划数据" },
+          { value: 3, name: "医疗数据" },
+          { value: 2, name: "文旅数据" },
+        ],
+      },
+    ];
+
+    this.dataToOption("数据类别分布", "sunburst", datas2, null);
+    this.dataToOption("数据质量评分", "radar", datas2, null);
+    this.dataToOption("服务调用趋势(近30天)", "line", datas, {
+      xData: [],
+      xKey: "date",
+      yAxis: [
+        {
+          type: "value",
+          name: "调用次数",
+          axisLine: { lineStyle: { color: "#42a5f5" } }, // 区分样式
+        },
+        {
+          type: "value",
+          name: "响应时间(ms)",
+          axisLine: { lineStyle: { color: "#4caf50" } }, // 区分样式
+          position: "right",
+        },
+      ],
+      yData: [
+        {
+          key: "value",
+          name: "调用次数",
+          color: "#42a5f5",
+          data: [],
+          yAxisIndex: 0,
+        },
+        {
+          key: "value2",
+          name: "响应时间(ms)",
+          color: "#4caf50",
+          data: [],
+          ifDashed: true,
+          yAxisIndex: 1,
+        },
+      ],
+    });
+    this.dataToOption("用户活跃度趋势", "line", datas, {
+      xData: [],
+      xKey: "date",
+      yData: [
+        {
+          key: "value",
+          name: "调用次数",
+          color: "#42a5f5",
+          data: [],
+        },
+        {
+          key: "value2",
+          name: "响应时间(ms)",
+          color: "#4caf50",
+          data: [],
+        },
+      ],
+    });
+
+    this.dataToOption("服务类别分布", "pie", datas, {
+      pieKey: { value: "value", name: "name" },
+      pieData: [],
+    });
+
+    this.dataToOption("用户角色分布", "pie", datas, {
+      pieKey: { value: "value", name: "name" },
+      pieData: [],
+      legend: {
+        bottom: 10,
+      },
+      radius: "60%",
+      padAngle: 0,
+      borderRadius: 0,
+      label: {},
+    });
+    this.dataToOption("用户部门分布", "bar", datas, {
+      showLegend: false,
+      xData: [],
+      xKey: "date",
+      yData: [
+        {
+          key: "value",
+          name: "调用次数",
+          color: "#42a5f5",
+          data: [],
+        },
+      ],
+    });
+    // 表格数据初始化
+    this.initTableDatas();
+  },
   methods: {
+    dataToOption(title, type, datas, keyRule) {
+      // 根据规则解析数据
+      if (keyRule) {
+        datas.forEach((item) => {
+          // 有的图表没有X轴
+          if (keyRule.xKey) {
+            keyRule.xData.push(item[keyRule.xKey]);
+          }
+          if (keyRule.yData) {
+            keyRule.legend = [];
+            keyRule.yData.forEach((dataItem) => {
+              dataItem.data.push(item[dataItem.key]);
+              keyRule.legend.push(dataItem.name);
+            });
+          }
+          if (keyRule.pieKey) {
+            keyRule.pieData.push({
+              value: item[keyRule.pieKey.value],
+              name: item[keyRule.pieKey.name],
+            });
+          }
+        });
+      }
+      let _option = {};
+      switch (type) {
+        case "line":
+          // 折线图基础
+          _option = {
+            legend: {
+              data: keyRule.legend,
+            },
+            tooltip: {
+              show: true,
+              trigger: "axis",
+              axisPointer: { type: "shadow" },
+            },
+            // 默认样式
+            xAxis: {
+              type: "category",
+              data: keyRule.xData,
+              axisTick: { show: false }, // 隐藏刻度
+              splitLine: { show: false }, // 隐藏分割线
+            },
+            yAxis: keyRule.yAxis ? keyRule.yAxis : { type: "value" },
+            series: [],
+          };
+          // 补充数据
+          keyRule.yData.forEach((item) => {
+            // 补充server
+            _option.series.push({
+              name: item.name,
+              type: "line",
+              smooth: true,
+              data: item.data, // 模拟数据
+              lineStyle: {
+                color: item.color ? item.color : "",
+                type: item.ifDashed ? "dashed" : "",
+              }, // 蓝色线条
+              itemStyle: item.color ? { color: item.color } : {}, // 节点颜色
+              symbol: "circle", // 节点形状
+              symbolSize: 6, // 节点大小
+              yAxisIndex: item.yAxisIndex != undefined ? item.yAxisIndex : 0, // 绑定Y轴
+            });
+          });
+          break;
+        case "pie":
+          // 饼状图
+          _option = {
+            tooltip: {
+              trigger: "item",
+            },
+            legend: keyRule.legend
+              ? keyRule.legend
+              : {
+                  orient: "vertical",
+                  top: "50%",
+                  right: 10,
+                },
+            series: [
+              {
+                name: title,
+                type: "pie",
+                radius: keyRule.radius ? keyRule.radius : ["40%", "70%"],
+                avoidLabelOverlap: false,
+                padAngle: keyRule.padAngle != undefined ? keyRule.padAngle : 5,
+                itemStyle: {
+                  borderRadius:
+                    keyRule.borderRadius != undefined ? keyRule.borderRadius : 10,
+                },
+                label:
+                  keyRule.label != undefined
+                    ? keyRule.label
+                    : {
+                        show: false,
+                        position: "center",
+                      },
+                emphasis: {
+                  label: {
+                    show: true,
+                    fontSize: 20,
+                    fontWeight: "bold",
+                  },
+                },
+                labelLine: {
+                  show: true,
+                },
+                data: keyRule.pieData,
+              },
+            ],
+          };
+          break;
+        case "bar":
+          // 柱状图
+          _option = {
+            tooltip: {
+              trigger: "axis",
+              axisPointer: {
+                type: "shadow",
+              },
+            },
+            legend: {
+              show: keyRule.showLegend ? keyRule.showLegend : false,
+              data: keyRule.legend,
+            },
+            xAxis: {
+              type: "value",
+            },
+            yAxis: {
+              type: "category",
+              data: keyRule.xData,
+            },
+            series: [],
+          };
+          keyRule.yData.forEach((item) => {
+            _option.series.push({
+              name: item.name,
+              type: "bar",
+              label: {
+                show: true,
+              },
+              emphasis: {
+                focus: "series",
+              },
+              data: item.data,
+            });
+          });
+          break;
+        case "sunburst":
+          // 旭日图
+          _option = {
+            series: {
+              type: "sunburst",
+              emphasis: {
+                focus: "ancestor",
+              },
+              data: datas,
+              radius: [0, "90%"],
+              label: {
+                rotate: "radial",
+              },
+            },
+          };
+          break;
+        default:
+          // 雷达图
+          _option = {
+            tooltip: {
+              trigger: "axis",
+            },
+            legend: {
+              show: false,
+              left: "center",
+            },
+            radar: [
+              {
+                indicator: [
+                  { text: "完整性", max: 100 },
+                  { text: "可用性", max: 100 },
+                  { text: "一致性", max: 100 },
+                  { text: "及时性", max: 100 },
+                  { text: "准确性", max: 100 },
+                ],
+              },
+            ],
+            series: [
+              {
+                type: "radar",
+                areaStyle: {},
+                data: [
+                  {
+                    value: [85, 90, 90, 95, 95],
+                    name: "A Phone",
+                  },
+                  {
+                    value: [95, 80, 95, 90, 93],
+                    name: "Another Phone",
+                  },
+                ],
+              },
+            ],
+          };
+          break;
+      }
+      this.chartOptions[title] = _option;
+    },
+    // 服务调用列表
+    initTableDatas() {
+      this.tableDatas = [
+        {
+          serviceName: "服务A",
+          serviceType: "类别A",
+          callCount: 100,
+          successRate: "90%",
+          avgResponseTime: "100ms",
+        },
+        {
+          serviceName: "服务B",
+          serviceType: "类别B",
+          callCount: 200,
+          successRate: "80%",
+          avgResponseTime: "150ms",
+        },
+        {
+          serviceName: "服务C",
+          serviceType: "类别C",
+          callCount: 300,
+          successRate: "70%",
+          avgResponseTime: "200ms",
+        },
+      ];
+    },
+    // 时间范围自定义时间
     shortcuts() {
       return [
         {
@@ -149,22 +590,31 @@ export default {
   & > div {
     margin: 20px 0;
     display: flex;
-    overflow: hidden;
   }
   .card {
     width: calc(25% - 56px);
     border-radius: 5px;
     padding: 20px 18px;
-    background: #ffffff;
+    background: #00000032;
+    box-shadow: 0 0 15px 1px rgba(0, 0, 0, 0.15);
+  }
+
+  .card2 {
+    width: 100%;
+    border-radius: 5px;
+    padding: 20px 18px;
+    background: #00000032;
+    box-shadow: 0 0 15px 1px rgba(0, 0, 0, 0.15);
   }
 
   .bigCard {
     width: calc(100% - 36px);
     border-radius: 5px;
     padding: 20px 18px;
-    background: #ffffff;
+    background: #00000032;
     position: relative;
     flex-direction: column;
+    box-shadow: 0 0 15px 1px rgba(0, 0, 0, 0.15);
     .tools {
       position: absolute;
       top: 20px;
@@ -184,6 +634,13 @@ export default {
     flex-direction: row;
     justify-content: space-between;
   }
+  .flex_column {
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    align-items: flex-start;
+    box-sizing: border-box;
+  }
 
   .searchBox {
     width: 100%;

Vissa filer visades inte eftersom för många filer har ändrats