Ver Fonte

运行管理页面UI完善,和示例数据格式,内嵌页面

DESKTOP-6LTVLN7\Liumouren há 1 mês atrás
pai
commit
f3e3ede6d2

+ 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

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

@@ -14,106 +14,43 @@ 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() {
-      this.chart = echarts.init(this.$refs.chartContainer);
-
-      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轴(响应时间)
-          },
-        ],
-      };
-      // 绘制图表
-      this.chart.setOption(option);
+      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, // 关键:防止坐标轴标签超出容器(可选,根据需求添加)
+        };
+        chartDom.setOption(this.chartOption);
+      }
     },
   },
 };
@@ -122,18 +59,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>

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

@@ -0,0 +1,72 @@
+<template>
+  <div class="table_box">
+    <div class="table_title">{{ title }}</div>
+    <el-table :data="tableData" style="width: 100%" 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>
+.table_box {
+  width: 100%;
+  height: 100%;
+  padding: 20px;
+  box-sizing: border-box;
+  position: inherit;
+}
+.table_title {
+  font-size: 16px;
+}
+.table_pagination {
+  position: absolute;
+  bottom: 20px;
+  right: 20px;
+}
+</style>

+ 38 - 3
src/views/Yxgl.vue

@@ -6,6 +6,7 @@
       :collapse="isCollapse"
       @open="handleOpen"
       @close="handleClose"
+      @select="changeMenu"
     >
       <el-sub-menu index="/#">
         <template #title>
@@ -34,9 +35,14 @@
     </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' ? '#FFF' : '#FFF',
+        overflowY: menuActive == 'StatisticalAnalysis' ? 'auto' : 'hidden',
+      }"
     >
-      <StatisticalAnalysis />
+      <StatisticalAnalysis v-if="menuActive == 'StatisticalAnalysis'" />
+      <iframe v-else :src="iframeUrl" frameborder="0"></iframe>
     </div>
   </div>
 </template>
@@ -49,6 +55,7 @@ export default {
     return {
       isCollapse: false,
       menuActive: "StatisticalAnalysis",
+      iframeUrl: "",
     };
   },
   // 2. 局部注册组件(键值同名可简写)
@@ -63,6 +70,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>
@@ -89,6 +120,10 @@ export default {
   position: relative;
   overflow: hidden;
   overflow-y: auto;
-  background-color: #eee;
+}
+iframe {
+  width: 100%;
+  height: calc(100% - 10px);
+  background: #fff;
 }
 </style>

+ 466 - 9
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,13 +590,21 @@ export default {
   & > div {
     margin: 20px 0;
     display: flex;
-    overflow: hidden;
   }
   .card {
     width: calc(25% - 56px);
     border-radius: 5px;
     padding: 20px 18px;
     background: #ffffff;
+    box-shadow: 0 0 15px 1px rgba(0, 0, 0, 0.15);
+  }
+
+  .card2 {
+    width: 100%;
+    border-radius: 5px;
+    padding: 20px 18px;
+    background: #ffffff;
+    box-shadow: 0 0 15px 1px rgba(0, 0, 0, 0.15);
   }
 
   .bigCard {
@@ -165,6 +614,7 @@ export default {
     background: #ffffff;
     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%;