Преглед на файлове

头部添加初始化状态判断,避免用户刷新页面后渲染异常。
运行管理联调了两个接口。
运行管理UI微调。
Echarts组件优化。

DESKTOP-6LTVLN7\Liumouren преди 3 седмици
родител
ревизия
f0bf3c9596

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

@@ -19,7 +19,6 @@ let systemConfig = {
     dmsDataProxy: "/proxy_dms",
     // 引擎基础js
     scriptMain: "/static/plugins/skyscenery/SkyScenery.js",
-
     GEOSERVER_URL_WMS: "http://121.43.55.7:8889/geoserver/kdyjs/wms",
     GEOSERVER_URL_WFS: "http://121.43.55.7:8889/geoserver/kdyjs/wfs",
     TDT_URL: "https://{s}.tianditu.gov.cn/",

+ 71 - 38
src/App.vue

@@ -8,11 +8,10 @@ export default {
   data() {
     return {
       loadedScripts: [],
-    }
+    };
   },
   mounted() {
-    let that = this;
-    window.loadScripts = this.loadScripts
+    window.loadScripts = this.loadScripts;
     // document.querySelector("#app").style.transform = `scale(${this.getScale()}) translate(-50%, 0%)`
     // document.querySelector("#app").style.height = window.innerHeight / this.getScale() + "px"
     // window.onresize = () => {
@@ -22,29 +21,66 @@ export default {
     // this.$nextTick(() => {
     //   this.scrollUpdate();
     // });
+    let that = this;
     // 默认登录
-    api.login({
-      userName: systemConfig.defaultAccount.userName,
-      password: systemConfig.defaultAccount.password,
-      clientId: "1",
-      serviceId: "0",
-    }).then((result) => {
-      if (result.code == 200) {
-        that.$store.commit("setUserInfo", result.content);
-        that.$store.commit("setToken", result.message);
-        that.$store.commit("setUserState", true);
-      } else {
+    api
+      .login({
+        userName: systemConfig.defaultAccount.userName,
+        password: systemConfig.defaultAccount.password,
+        clientId: "1",
+        serviceId: "0",
+      })
+      .then((result) => {
+        if (result.code == 200) {
+          that.$store.commit("setUserInfo", result.content);
+          that.$store.commit("setToken", result.message);
+          that.$store.commit("setUserState", true);
+          // 登录成功之后要批量加载一下DMS的字典,后续全局可调用
+          that.$store.state.DMSTypes.forEach((item) => {
+            api
+              .getDmsTypes({
+                cName: item,
+                type: 0,
+              })
+              .then((result2) => {
+                if (result2.code == 200) {
+                  // 遍历result2.content,将每个元素的index作为key,name作为value,存储到DmsTypesMap中
+                  let dmsTypesMap = {};
+                  result2.content.forEach((element) => {
+                    dmsTypesMap[element.index] = element.name;
+                  });
+                  that.$store.commit("setDmsTypesMap", {
+                    name: item,
+                    list: dmsTypesMap,
+                  });
+                } else {
+                  that.$message({
+                    type: "error",
+                    message: result2.content,
+                  });
+                }
+              })
+              .catch((err) => {
+                console.log(err);
+                that.$message({
+                  type: "error",
+                  message: "服务器忙碌,请稍后重试!",
+                });
+              });
+          });
+        } else {
+          that.$message({
+            type: "error",
+            message: result.content,
+          });
+        }
+      })
+      .catch((err) => {
         that.$message({
           type: "error",
-          message: result.content,
+          message: "服务器忙碌,请稍后重试!",
         });
-      }
-    }).catch((err) => {
-      that.$message({
-        type: "error",
-        message: "服务器忙碌,请稍后重试!",
       });
-    });
   },
   methods: {
     // scrollUpdate() {
@@ -54,52 +90,52 @@ export default {
     //   }, 1000);
     // },
     getScale() {
-      const ww = window.innerWidth / 1920
+      const ww = window.innerWidth / 1920;
       // const wh = window.innerHeight / 945
       // return ww < wh ? ww : wh;
-      return ww
+      return ww;
     },
 
     initScript() {
       let that = this;
       window.SkySceneryConfig = {
         authUrl: systemConfig.oauthServiceUrlOrigin,
-        token: localStorage.getItem("token")
+        token: localStorage.getItem("token"),
       };
       return new Promise((resolve, reject) => {
         const str = systemConfig.scriptMain;
-        let strArr = str.split("/")
+        let strArr = str.split("/");
         if (that.loadedScripts.indexOf(strArr[strArr.length - 1]) == -1) {
           // SkyScenery.js
           that.loadedScripts.push(strArr[strArr.length - 1]);
           that.addScripts(systemConfig.scriptMain).then(function () {
             resolve();
-          })
+          });
         } else {
           resolve();
         }
-      })
+      });
     },
     loadScripts(scriptArr) {
       // 初始化 SkyScenery.js
       let that = this;
       return new Promise((resolve, reject) => {
         that.initScript().then(function () {
-          let arr = []
+          let arr = [];
           for (let i = 0; i < scriptArr.length; i++) {
             const str = scriptArr[i];
-            let strArr = str.split("/")
+            let strArr = str.split("/");
             if (that.loadedScripts.indexOf(strArr[strArr.length - 1]) == -1) {
               let pro = that.addScripts(str);
               that.loadedScripts.push(strArr[strArr.length - 1]);
-              arr.push(pro)
+              arr.push(pro);
             }
           }
           Promise.all(arr).then(function () {
-            resolve()
+            resolve();
           });
-        })
-      })
+        });
+      });
     },
     addScripts(src) {
       return new Promise((resolve, reject) => {
@@ -112,10 +148,7 @@ export default {
         if (script.readyState) {
           // IE
           script.onreadystatechange = function () {
-            if (
-              script.readyState === "loaded" ||
-              script.readyState === "complete"
-            ) {
+            if (script.readyState === "loaded" || script.readyState === "complete") {
               script.onreadystatechange = null;
               resolve();
             }
@@ -128,7 +161,7 @@ export default {
         }
       });
     },
-  }
+  },
 };
 </script>
 <style lang="less">

+ 5 - 0
src/api/common.js

@@ -7,6 +7,11 @@ const login = (params) => {
   return postform(systemConfig.oauthServiceUrl + '/user/login', params)
 }
 
+const getDmsTypes = (params) => {
+  return postform(systemConfig.backServerPath + ":" + systemConfig.dmsWebUrlPort + systemConfig.dmsDataProxy + '/category/selectByCNameAType', params)
+}
+
 export default {
   login,
+  getDmsTypes,
 }

+ 60 - 5
src/api/count.js

@@ -1,8 +1,8 @@
 import {
-    postform,get
+    postform, get
 } from '../utils/request'
 
-const dmsPath = systemConfig.dmsDataProxy 
+const dmsPath = systemConfig.dmsDataProxy
 
 const oauthPath = systemConfig.oauthServiceUrl
 
@@ -238,7 +238,7 @@ export function totalCountGroupByTime(start, end) {
             }, {
                 "table": "precount",
                 "column": "c_date",
-                "alias":"time"
+                "alias": "time"
             }
         ]),
         "groupBy": JSON.stringify([
@@ -254,8 +254,8 @@ export function totalCountGroupByTime(start, end) {
 
     return resolveDmsMultiTableResult(postform(multiSearch, data));
 }
-export function countUserData(){
-        return resolveoauthResult(get(oauthCountUser))
+export function countUserData() {
+    return resolveoauthResult(get(oauthCountUser))
 }
 function timeCheckers(start, end) {
     let output = []
@@ -309,4 +309,59 @@ async function resolveoauthResult(result) {
     } else {
         return null;
     }
+}
+
+// 服务类别分布、服务调用TOP10、详细报告。导出数据是另外一个接口?导出数据显示的数据不就是详细报告的数据吗?
+export function serviceInfo(start, end) {
+    let data = {
+        "columnId": preCountDmsId,
+        "autoSelectItem": false,
+        "page": 1,
+        "pageSize": 10000,
+        "columnAlias": "precount",
+        // "orderBy": "c_count",
+        "selectItem": JSON.stringify([
+            {
+                // 调用次数
+                "table": "precount",
+                "column": "c_count",
+                "function": "sum",
+                "alias": "count"
+            }, {
+                // 调用时间
+                "table": "precount",
+                "column": "c_date",
+                "alias": "time"
+            }, {
+                // 委办单位
+                "table": "precount",
+                "column": "c_unit",
+                "alias": "cUnit"
+            }, {
+                // 接口描述
+                "table": "precount",
+                "column": "c_path_comment",
+                "alias": "cPathComment"
+            }
+        ]),
+        "groupBy": JSON.stringify([
+            {
+                "table": "precount",
+                "column": "c_date"
+            },
+            {
+                "table": "precount",
+                "column": "c_unit"
+            },
+            {
+                "table": "precount",
+                "column": "c_path_comment"
+            }
+        ]),
+        "conditionsList": JSON.stringify([
+            ...timeCheckers(start, end),
+            ...notNullAndEmptyCheckers("precount", "c_unit")
+        ])
+    }
+    return resolveDmsMultiTableResult(postform(multiSearch, data));
 }

+ 28 - 49
src/components/AppVue/Header.vue

@@ -3,8 +3,12 @@
     <div class="logo">青浦一张图</div>
     <div class="menu">
       <ul class="menu_ul">
-        <li v-for="(item, index) in menuList" :key="index" :class="{ active: item.isActive }"
-          @click="menuClick(item.index, $event)">
+        <li
+          v-for="(item, index) in menuList"
+          :key="index"
+          :class="{ active: item.isActive }"
+          @click="menuClick(item.index, $event)"
+        >
           {{ item.label }}
         </li>
       </ul>
@@ -17,68 +21,43 @@ export default {
   data() {
     return {
       menuList: [
-        { index: 1, label: "首页", isActive: true },
-        { index: 2, label: "时空数据管理", isActive: false },
-        { index: 3, label: "二维GIS引擎", isActive: false },
-        { index: 4, label: "时空门户", isActive: false },
-        { index: 5, label: "微功能", isActive: false },
-        { index: 6, label: "应用管理", isActive: false },
-        { index: 7, label: "运行管理", isActive: false },
+        { index: 1, path: "/", label: "首页", isActive: true },
+        { index: 2, path: "/sksjgl", label: "时空数据管理", isActive: false },
+        { index: 3, path: "/skmh/scene", label: "二维GIS引擎", isActive: false },
+        { index: 4, path: "/skmh", label: "时空门户", isActive: false },
+        { index: 5, path: "/wgn", label: "微功能", isActive: false },
+        { index: 6, path: "/yygl", label: "应用管理", isActive: false },
+        { index: 7, path: "/yxgl", label: "运行管理", isActive: false },
       ],
     };
   },
+  mounted() {
+    // 初始化判断路径并自动选中菜单
+    let path = this.$route.path;
+    console.log(path);
+    this.menuList.map(function (item) {
+      if (item.path == path) {
+        item.isActive = true;
+      } else {
+        item.isActive = false;
+      }
+    });
+  },
   methods: {
     menuClick(index) {
-      let that = this
+      let that = this;
       this.menuList.map(function (item) {
         if (item.index == index) {
           item.isActive = true;
+          that.$router.push(item.path);
         } else {
           item.isActive = false;
         }
       });
-
-      switch (index) {
-        case 1:
-          this.$router.push("/");
-          break;
-        case 2:
-          this.$router.push("/sksjgl");
-          break;
-        case 3:
-          // this.$router.push("/application");
-          this.$router.push("/skmh/scene");
-          break;
-        case 4:
-          // this.$router.push("/function");
-          this.$router.push("/skmh");
-          break;
-        case 5:
-          this.$router.push("/wgn");
-          break;
-        case 6:
-          this.$router.push("/yygl");
-          break;
-        case 7:
-          this.$router.push("/yxgl");
-          break;
-      }
       this.$nextTick(() => {
-        this.$emit('updateScroll');
+        this.$emit("updateScroll");
       });
     },
-    // addClass(element, className) {
-    //   if (
-    //     !new RegExp("(^|\\s)" + className + "(\\s|$)").test(element.className)
-    //   )
-    //     element.className += " " + className;
-    // },
-    // removeClass(element, className) {
-    //   element.className = element.className.replace(
-    //     new RegExp("(^|\\s)" + className + "(?=(\\s|$))", "g"),
-    //     ""
-    //   );
-    // }
   },
 };
 </script>

+ 26 - 34
src/components/yxgl/EchartsDome.vue

@@ -31,14 +31,13 @@ export default {
   },
   watch: {
     chartOption: {
-      handler(newVal) {
+      handler(newVal, oldVal) {
         // 检查是否为有效对象
         if (newVal && typeof newVal === "object") {
           this.updateChart(newVal);
         }
       },
       deep: true,
-      immediate: true, // 立即执行一次
     },
   },
   methods: {
@@ -47,49 +46,42 @@ export default {
       if (this.chartInstance) {
         this.chartInstance.dispose();
       }
-
       // 创建新实例
-      this.chartInstance = echarts.init(this.$refs.chartContainer);
-
+      let chartInstance = echarts.init(this.$refs.chartContainer);
+      this.chartInstance = chartInstance;
       // 更新图表配置
       this.updateChart(this.chartOption);
     },
-
     updateChart(option) {
-      if (!this.chartInstance || !option || typeof option !== "object") return;
-
+      // 创建新实例
+      // 如果已存在实例,先销毁
+      if (this.chartInstance) {
+        this.chartInstance.dispose();
+      }
+      // 创建新实例
+      let chartInstance = echarts.init(this.$refs.chartContainer);
+      this.chartInstance = chartInstance;
       // 深拷贝配置,避免修改原始props
       const mergedOption = JSON.parse(JSON.stringify(option));
-
-      // 添加默认grid配置(不直接修改原始配置)
-      mergedOption.grid = mergedOption.grid || {
+      // 绘制图表
+      mergedOption.grid = {
         top: 80,
-        left: 10,
-        right: 50,
+        left: 10, // 核心1:grid左侧距离容器左侧0px
+        right: 50, // 核心2:grid右侧距离容器右侧0px
         bottom: 0,
-        containLabel: true,
+        containLabel: true, // 关键:防止坐标轴标签超出容器(可选,根据需求添加)
       };
-
-      // 添加默认legend配置
-      if (mergedOption.legend) {
-        // 如果已有legend配置,合并默认文本样式
-        mergedOption.legend.textStyle = {
-          color: "#F2F3F5",
-          fontWeight: "normal",
-          ...mergedOption.legend.textStyle,
-        };
-      }
-
-      // 设置图表配置
-      this.chartInstance.setOption(mergedOption, true);
-    },
-
-    destroyChart() {
-      // 销毁ECharts实例
-      if (this.chartInstance) {
-        this.chartInstance.dispose();
-        this.chartInstance = null;
+      if (!mergedOption.legend) {
+        mergedOption.legend = {};
       }
+      Object.assign(mergedOption.legend, {
+        textStyle: {
+          color: "#F2F3F5", // 字体颜色(支持十六进制、RGB、颜色名)
+          fontSize: 14, // 可选:字体大小
+          fontWeight: "normal", // 可选:字体粗细
+        },
+      });
+      chartInstance.setOption(mergedOption, true);
     },
   },
 };

+ 3 - 2
src/components/yxgl/card.vue

@@ -26,8 +26,8 @@ export default {
       default: "",
     },
     value: {
-      type: String,
-      default: "",
+      type: Number,
+      default: 0,
     },
     growth: {
       type: String,
@@ -85,6 +85,7 @@ export default {
   height: 40px;
   border-radius: 5px;
   background: #ccc;
+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);
   font-size: 20px;
   display: flex;
   justify-content: center;

+ 113 - 5
src/components/yxgl/table.vue

@@ -6,12 +6,20 @@
     </div> -->
     <el-table
       :data="tableData"
-      style="width: 100%; background-color: #00000032"
-      height="calc(100% - 20px)"
+      style="width: 100%"
+      height="calc(100% - 40px);
+  background-color: rgba(255, 255, 255, 0.1);"
+      :header-cell-style="headerCellStyle"
+      :row-style="rowStyle"
+      :cell-style="cellStyle"
+      stripe
+      border
     >
+      <!-- 添加序号列 -->
+      <el-table-column type="index" label="" width="50" align="center" />
       <el-table-column prop="serviceName" label="服务名称" />
-      <el-table-column prop="serviceType" label="类别" width="300" />
-      <el-table-column prop="callCount" label="调用次数" width="480" />
+      <el-table-column prop="serviceType" label="类别" width="600" />
+      <el-table-column prop="callCount" label="调用次数" width="280" />
     </el-table>
     <!-- <div class="table_pagination">
       <el-pagination
@@ -47,6 +55,32 @@ export default {
       currentPage: 1,
     };
   },
+  computed: {
+    headerCellStyle() {
+      return {
+        backgroundColor: "rgba(24, 144, 255, 0.25)",
+        color: "#0071e3",
+        fontWeight: "bold",
+        borderBottom: "2px solid rgba(24, 144, 255, 0.3)",
+        padding: "12px 8px",
+      };
+    },
+    rowStyle() {
+      return {
+        // 调整行背景色为更浅的黑色,增加透明度
+        backgroundColor: "rgba(0, 0, 0, 0.05)",
+        borderBottom: "1px solid rgba(255, 255, 255, 0.05)",
+        transition: "all 0.3s ease",
+      };
+    },
+    cellStyle() {
+      return {
+        color: "#e0e0e0",
+        padding: "12px 8px",
+        borderRight: "1px solid rgba(255, 255, 255, 0.05)",
+      };
+    },
+  },
   methods: {
     handleSizeChange(val) {
       this.pageSize = val;
@@ -65,9 +99,18 @@ export default {
   padding: 20px;
   box-sizing: border-box;
   position: relative;
+  // background-color: rgba(255, 255, 255, 0.1);
+  border-radius: 8px;
+  // box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);
 }
+
 .table_title {
-  font-size: 16px;
+  font-size: 18px;
+  color: #ffffff;
+  font-weight: bold;
+  margin-bottom: 15px;
+  padding-bottom: 8px;
+  // border-bottom: 2px solid rgba(24, 144, 255, 0.2);
 }
 
 .table_more {
@@ -76,10 +119,75 @@ export default {
   right: 20px;
   font-size: 14px;
   color: #1890ff;
+
+  .el-button {
+    color: #0071e3;
+
+    &:hover {
+      color: #0056b3;
+    }
+  }
 }
+
 .table_pagination {
   position: absolute;
   bottom: 20px;
   right: 20px;
+
+  .el-pagination {
+    color: #e0e0e0;
+
+    .btn-prev,
+    .btn-next,
+    .el-pager li {
+      background-color: rgba(0, 0, 0, 0.3);
+      color: #e0e0e0;
+      border: 1px solid rgba(255, 255, 255, 0.1);
+
+      &:hover {
+        background-color: rgba(24, 144, 255, 0.2);
+        color: #0071e3;
+        border-color: rgba(24, 144, 255, 0.3);
+      }
+    }
+
+    .el-pager li.active {
+      background-color: rgba(24, 144, 255, 0.3);
+      color: #0071e3;
+      border-color: rgba(24, 144, 255, 0.5);
+    }
+  }
+}
+
+// 美化表格行悬停效果
+:deep(.el-table__body tr:hover > td) {
+  background-color: rgba(24, 144, 255, 0.1) !important;
+}
+
+// 美化表格边框
+:deep(.el-table__inner-wrapper) {
+  border-radius: 6px;
+  overflow: hidden;
+}
+
+:deep(.el-table__cell) {
+  border-right: 1px solid rgba(255, 255, 255, 0.05);
+}
+
+:deep(.el-table__row) {
+  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
+}
+
+// 调整奇偶行背景色,使其更明亮
+:deep(.el-table--striped .el-table__body tr.el-table__row--striped) {
+  background-color: rgba(255, 255, 255, 0.02) !important;
+}
+
+// 调整表格主体背景色
+:deep(.el-table__body) {
+  background-color: rgba(0, 0, 0, 0.05);
+}
+:deep(.el-table--striped .el-table__body tr.el-table__row--striped td.el-table__cell) {
+  background-color: rgba(255, 255, 255, 0.02);
 }
 </style>

+ 20 - 15
src/main.js

@@ -1,30 +1,35 @@
-import { createApp } from 'vue'
-import App from './App.vue'
+import { createApp } from 'vue';
+import App from './App.vue';
 let initApp = createApp(App);
 
-import router from './router'
+import router from './router';
+import store from './store';
+import ElementPlus from 'element-plus';
+import zhCn from 'element-plus/es/locale/lang/zh-cn';
+import 'element-plus/dist/index.css'; // 引入默认主题样式
+import 'element-plus/theme-chalk/dark/css-vars.css'; // 引入暗色主题样式
 initApp.use(router);
-import store from './store'
 initApp.use(store);
-import ElementPlus from 'element-plus'
-import zhCn from 'element-plus/es/locale/lang/zh-cn'
-import 'element-plus/dist/index.css' // 引入默认主题样式
-import 'element-plus/theme-chalk/dark/css-vars.css' // 引入暗色主题样式
 initApp.use(ElementPlus, {
     locale: zhCn,
-})
+});
 // 如果您正在使用CDN引入,请删除下面一行。
-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)
+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);
 
 import moment from 'moment';
 initApp.config.globalProperties.$moment = moment;
 
+// 添加自定义方法,传入DMS字典名称,返回对应字典数据
+initApp.config.globalProperties.$getDmsTypes = (cName, index) => {
+    return store.state.DmsTypesMap[cName] ? store.state.DmsTypesMap[cName][index + ''] : cName + "_" + index;
+};
+
 for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
     initApp.component(key, component)
-}
+};
 
 initApp.mount('#app');

+ 9 - 2
src/store/index.js

@@ -7,7 +7,10 @@ export default createStore({
     token: "",
     userState: false,
     userInfo: null,
-
+    // DMS字典,系统app.vue初始化一次之后,后续直接全局$getDmsTypes可调用,传入字典cName和index,返回对应字典数据
+    DMSTypes: ["appstatus"],
+    // appstatus: 应用状态
+    DmsTypesMap: localStorage.getItem("DmsTypesMap") ? JSON.parse(localStorage.getItem("DmsTypesMap")) : {},
     sksjgl: {},
     skmh: {},
     wgn: {},
@@ -26,9 +29,13 @@ export default createStore({
     },
   },
   mutations: {
+    setDmsTypesMap(state, obj) {
+      state.DmsTypesMap[obj.name] = obj.list;
+      localStorage.setItem("DmsTypesMap", JSON.stringify(state.DmsTypesMap));
+    },
     setToken(state, str) {
       state.token = str;
-      localStorage.setItem("token",str)
+      localStorage.setItem("token", str)
     },
     setUserState(state, bool) {
       state.userState = bool;

+ 162 - 68
src/views/yxgl/StatisticalAnalysis.vue

@@ -3,6 +3,19 @@
     <!-- 搜索区域 -->
     <div class="searchBox">
       <div>
+        对比时间:
+        <el-date-picker
+          v-model="compareTimes"
+          type="daterange"
+          unlink-panels
+          range-separator="到"
+          start-placeholder="开始时间"
+          end-placeholder="结束时间"
+          disabled
+          size="large"
+          style="margin-right: 30px"
+        />
+        搜索时间:
         <el-date-picker
           v-model="dateValue"
           type="daterange"
@@ -10,7 +23,7 @@
           range-separator="到"
           start-placeholder="开始时间"
           end-placeholder="结束时间"
-          :shortcuts="shortcuts"
+          :shortcuts="shortcutsFun"
           size="large"
         />
       </div>
@@ -106,7 +119,7 @@
           />
         </div>
         <div style="width: 38%; height: 400px">
-          <EchartsDome :chartOption="chartOptions['服务类别分布']" title="应用状态分布" />
+          <EchartsDome :chartOption="chartOptions['应用状态分布']" title="应用状态分布" />
         </div>
       </div>
     </div>
@@ -123,7 +136,7 @@
       </div>
     </div>
     <!-- 区级特色信息统计 -->
-    <div class="bigCard" style="background: #00000000">
+    <div class="bigCard">
       <div class="bigCard_title">区级特色信息统计</div>
       <div class="flex" style="margin-top: 20px">
         <div class="flex_column" style="width: 28%; height: 420px">
@@ -167,7 +180,8 @@
 import card from "@/components/yxgl/card.vue";
 import EchartsDome from "@/components/yxgl/EchartsDome.vue";
 import Table from "@/components/yxgl/table.vue";
-import { totalCountGroupByTime } from "@/api/count";
+import { totalCountGroupByTime, serviceInfo } from "@/api/count";
+import appCenter from "@/api/appCenter";
 export default {
   name: "",
   components: {
@@ -178,16 +192,10 @@ export default {
   data() {
     return {
       // 比较的时间范围(默认60天到30天前,主要跟dateValue有关系)
-      compareTimes: [
-        new Date(new Date().setTime(new Date() - 3600 * 1000 * 24 * 60)),
-        new Date(new Date().setTime(new Date() - 3600 * 1000 * 24 * 30)),
-      ],
+      compareTimes: [],
       // 当前选中的时间范围
-      dateValue: [
-        new Date(new Date().setTime(new Date() - 3600 * 1000 * 24 * 30)),
-        new Date(),
-      ],
-      shortcuts: this.shortcuts(),
+      dateValue: [],
+      shortcutsFun: this.shortcuts(),
       chartOptions: {},
       tableDatas: [],
     };
@@ -196,24 +204,32 @@ export default {
     dateValue: {
       handler(newVal, oldVal) {
         if (newVal !== oldVal && newVal.length > 0) {
-          this.initChart();
-          // 要先算出来dateValue的开始时间,和范围天数。然后根据范围天数,计算出比较的时间。其中dateValue的开始时间是比较时间的结束时间,比较的开始时间是比较时间的结束时间减去范围天数。
           // 计算出比较的时间范围
           this.compareTimes = [
-            new Date(
-              new Date(newVal[0]).setTime(
-                new Date(newVal[0]).getTime() - 3600 * 1000 * 24 * (newVal[1] - newVal[0])
+            this.$moment(
+              new Date(
+                new Date(newVal[0]).setTime(
+                  new Date(newVal[0]).getTime() - (newVal[1] - newVal[0])
+                )
               )
-            ),
-            new Date(newVal[0]),
+            ).format("YYYY-MM-DD"),
+            this.$moment(new Date(newVal[0])).format("YYYY-MM-DD"),
           ];
+          this.initChart();
         }
       },
       deep: true,
-      immediate: true,
+      // immediate: true,
     },
   },
-  mounted() {},
+  mounted() {
+    this.$nextTick(() => {
+      this.dateValue = [
+        new Date(new Date().setTime(new Date() - 3600 * 1000 * 24 * 30)),
+        new Date(),
+      ];
+    });
+  },
   methods: {
     initChart() {
       let datas = [
@@ -245,24 +261,118 @@ export default {
           });
         }
       });
+      serviceInfo(this.dateValue[0], this.dateValue[1]).then((res) => {
+        if (res) {
+          // 得到服务类别分布,map中key是cUnit,value是count,可以写一个公共方法,专门用来统计服务类别分布
+          let serviceTypeMap = {};
+          res.forEach((item) => {
+            if (serviceTypeMap[item.cUnit]) {
+              serviceTypeMap[item.cUnit] += item.count;
+            } else {
+              serviceTypeMap[item.cUnit] = item.count;
+            }
+          });
+          // 转换为数组
+          let serviceTypeDatas = [];
+          for (let key in serviceTypeMap) {
+            if (serviceTypeMap[key] && key) {
+              serviceTypeDatas.push({
+                name: key,
+                value: serviceTypeMap[key],
+              });
+            }
+          }
+          this.dataToOption("服务类别分布", "pie", [...serviceTypeDatas], {
+            pieKey: { value: "value", name: "name" },
+            pieData: [],
+          });
 
-      // timeCheckers拼接时间参数,topUnit添加一个,然后修改查询字段:c_unit,修改成c_path
-      this.dataToOption("服务类别分布", "pie", datas, {
-        pieKey: { value: "value", name: "name" },
-        pieData: [],
+          this.dataToOption("委办分布", "pie", [...serviceTypeDatas], {
+            pieKey: { value: "value", name: "name" },
+            pieData: [],
+            legend: {
+              bottom: 10,
+            },
+            radius: "60%",
+            padAngle: 0,
+            borderRadius: 0,
+            label: {},
+          });
+          // 服务调用TOP10《cPathComment+cUnit,调用次数》
+          let serviceTypeMap2 = {};
+          res.forEach((item) => {
+            if (serviceTypeMap2[item.cPathComment + item.cUnit]) {
+              serviceTypeMap2[item.cPathComment + item.cUnit].push(item);
+            } else {
+              serviceTypeMap2[item.cPathComment + item.cUnit] = [item];
+            }
+          });
+          // 转换为数组
+          let serviceTypeDatas2 = [];
+          for (let key in serviceTypeMap2) {
+            if (serviceTypeMap2[key] && key) {
+              let item = serviceTypeMap2[key];
+              let tableDataItem = {
+                serviceName: "",
+                serviceType: "",
+                callCount: 0,
+              };
+              item.forEach((item2) => {
+                tableDataItem.serviceName = item2.cPathComment;
+                tableDataItem.serviceType = item2.cUnit;
+                tableDataItem.callCount += item2.count;
+              });
+              serviceTypeDatas2.push(tableDataItem);
+            }
+          }
+          // 根据callCount进行降序排序并截取前10条
+          serviceTypeDatas2.sort((a, b) => b.callCount - a.callCount);
+          serviceTypeDatas2 = serviceTypeDatas2.slice(0, 10);
+          this.initTableDatas(serviceTypeDatas2);
+        }
       });
+      // 应用状态分布,cloumnId:1659
+      appCenter
+        .getDmsDataList({
+          columnId: 1659,
+          pageSize: 1000,
+          page: 0,
+        })
+        .then((res) => {
+          if (res.code == 200) {
+            let dmsDatas = res.content.data;
+            let tableDatas = [];
+            // 根据状态进行groupBy统计个数
+            let statusMap = {};
+            dmsDatas.forEach((item) => {
+              if (statusMap[item.appstauts + ""]) {
+                statusMap[item.appstauts + ""] += 1;
+              } else {
+                statusMap[item.appstauts + ""] = 1;
+              }
+            });
+            // 转换为数组
+            for (let key in statusMap) {
+              if (statusMap[key] && key) {
+                tableDatas.push({
+                  name: this.$getDmsTypes("appstatus", key),
+                  value: statusMap[key],
+                });
+              }
+            }
+            this.dataToOption("应用状态分布", "pie", tableDatas, {
+              pieKey: { value: "value", name: "name" },
+              pieData: [],
+            });
+          } else {
+            this.$message({
+              type: "error",
+              message: "服务器忙碌,请稍后重试!",
+            });
+          }
+        });
 
-      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: [],
@@ -286,8 +396,6 @@ export default {
         label: {},
       });
       this.dataToOption("数据质量评分", "radar", null, null);
-      // 表格数据初始化
-      this.initTableDatas();
     },
     /**
      * 数据转换为图表选项
@@ -452,11 +560,11 @@ export default {
             radar: [
               {
                 indicator: [
-                  { text: "健壮性", max: 100 },
-                  { text: "完整性", max: 100 },
-                  { text: "一致性", max: 100 },
-                  { text: "及时性", max: 100 },
-                  { text: "准确性", max: 100 },
+                  { name: "健壮性", max: 100 },
+                  { name: "完整性", max: 100 },
+                  { name: "一致性", max: 100 },
+                  { name: "及时性", max: 100 },
+                  { name: "准确性", max: 100 },
                 ],
               },
             ],
@@ -478,24 +586,8 @@ export default {
       this.chartOptions[title] = _option;
     },
     // 服务调用列表
-    initTableDatas() {
-      this.tableDatas = [
-        {
-          serviceName: "服务A",
-          serviceType: "类别A",
-          callCount: 100,
-        },
-        {
-          serviceName: "服务B",
-          serviceType: "类别B",
-          callCount: 200,
-        },
-        {
-          serviceName: "服务C",
-          serviceType: "类别C",
-          callCount: 300,
-        },
-      ];
+    initTableDatas(serviceTypeDatas2) {
+      this.tableDatas = serviceTypeDatas2;
     },
     // 时间范围自定义时间
     shortcuts() {
@@ -554,26 +646,28 @@ export default {
     width: calc(25% - 56px);
     border-radius: 5px;
     padding: 20px 18px;
-    background: #00000032;
-    box-shadow: 0 0 15px 1px rgba(0, 0, 0, 0.15);
+    // background: #00000032;
+    background: rgba(255, 255, 255, 0.1);
+    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);
   }
 
   .card2 {
     width: 100%;
     border-radius: 5px;
     padding: 20px 18px;
-    background: #00000032;
-    box-shadow: 0 0 15px 1px rgba(0, 0, 0, 0.15);
+    // background: rgba(255, 255, 255, 0.1);
+    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);
   }
 
   .bigCard {
     width: calc(100% - 36px);
     border-radius: 5px;
     padding: 20px 18px;
-    background: #00000032;
+    // background: #00000032;
     position: relative;
     flex-direction: column;
-    box-shadow: 0 0 15px 1px rgba(0, 0, 0, 0.15);
+    background: rgba(255, 255, 255, 0.1);
+    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);
     .tools {
       position: absolute;
       top: 20px;

+ 131 - 109
src/views/yygl/overview/index.vue

@@ -2,32 +2,38 @@
   <div class="application-overview">
     <!-- 右侧主内容区 -->
     <div class="main-content">
-        <div style="display: flex;justify-content: space-between;">
-            <!-- 搜索栏 -->
-            <div class="search-bar">
-                <el-input
-                    placeholder="请输入应用名称关键字"
-                    v-model="searchKeyword"
-                    class="search-input"
-                    >
-                    <!-- <template #append>
+      <div style="display: flex; justify-content: space-between">
+        <!-- 搜索栏 -->
+        <div class="search-bar">
+          <el-input
+            placeholder="请输入应用名称关键字"
+            v-model="searchKeyword"
+            class="search-input"
+          >
+            <!-- <template #append>
                         <el-button type="primary" class="search-btn">搜索</el-button>
                     </template> -->
-                    
-                </el-input>
-                <el-button type="primary" class="search-btn" @click="getDmsDataList">搜索</el-button>
-            </div>
-            
+          </el-input>
+          <el-button type="primary" class="search-btn" @click="getDmsDataList"
+            >搜索</el-button
+          >
+        </div>
 
-            <!-- 应用范围过滤 -->
-            <div class="filter-tabs">
-                <el-radio-group v-model="activeTab" size="medium" @change="handleTabChange" v-for="item in levelOptions" :key="item.value">
-                    <el-radio-button :label="item.label">{{ item.value }}</el-radio-button>
-                    <!-- <el-radio-button label="1">区级</el-radio-button>
+        <!-- 应用范围过滤 -->
+        <div class="filter-tabs">
+          <el-radio-group
+            v-model="activeTab"
+            size="medium"
+            @change="handleTabChange"
+            v-for="item in levelOptions"
+            :key="item.value"
+          >
+            <el-radio-button :label="item.label">{{ item.value }}</el-radio-button>
+            <!-- <el-radio-button label="1">区级</el-radio-button>
                     <el-radio-button label="2">街镇</el-radio-button> -->
-                </el-radio-group>
-            </div>
+          </el-radio-group>
         </div>
+      </div>
       <!-- 应用卡片网格 -->
       <div class="app-content">
         <div class="applications-grid">
@@ -48,7 +54,9 @@
               <p class="app-description">{{ app.content }}</p>
               <div class="app-footer">
                 <span class="app-date">{{ app.createTime }}</span>
-                <el-button type="primary" size="small" class="visit-button">访问</el-button>
+                <el-button type="primary" size="small" class="visit-button"
+                  >访问</el-button
+                >
               </div>
             </div>
           </div>
@@ -64,29 +72,31 @@
 
 <script>
 import appCenter from "@/api/appCenter";
-import moment from 'moment';
+import moment from "moment";
 export default {
   name: "ApplicationOverview",
   data() {
     return {
-      searchKeyword: '',
-      activeTab: 'all',
-      curUrl:systemConfig.dmsDataProxy,
+      searchKeyword: "",
+      activeTab: "all",
+      curUrl: systemConfig.dmsDataProxy,
       levelOptions: [],
       tagOptions: [],
       applications: [],
-      itemApplications: []
-    }
+      itemApplications: [],
+    };
   },
-   mounted() {
-    this.initData()
+  mounted() {
+    this.initData();
   },
   methods: {
     handleTabChange() {
-      if (this.activeTab == 'all') {
+      if (this.activeTab == "all") {
         this.applications = this.itemApplications;
       } else {
-        this.applications = this.itemApplications.filter(item => item.level == this.activeTab);
+        this.applications = this.itemApplications.filter(
+          (item) => item.level == this.activeTab
+        );
       }
     },
     initData() {
@@ -94,52 +104,50 @@ export default {
       this.getDmsTagSName();
       this.getDmsDataList();
     },
-    getDmsTagSName(){
+    getDmsTagSName() {
       let requestParams = {
-        sName: 'tag',
+        sName: "tag",
       };
-      appCenter.getDmsSName(requestParams).then(res => {
+      appCenter.getDmsSName(requestParams).then((res) => {
         if (res.code === 200) {
-            this.tagOptions = res.content.map(item => ({
-              label: item.index,
-              value: item.name
-            }));
-            let allOption = {
-              label: 'all',
-              value: '全部'
-            }
-            this.tagOptions.unshift(allOption);
-            
+          this.tagOptions = res.content.map((item) => ({
+            label: item.index,
+            value: item.name,
+          }));
+          let allOption = {
+            label: "all",
+            value: "全部",
+          };
+          this.tagOptions.unshift(allOption);
         }
-      })
+      });
     },
     getDmsCNameAType() {
       let requestParams = {
-        cName: 'applevel',
-        type: 0
+        cName: "applevel",
+        type: 0,
       };
-      
-      appCenter.getDmsCNameAType(requestParams).then(res => {
+
+      appCenter.getDmsCNameAType(requestParams).then((res) => {
         if (res.code === 200) {
-            this.levelOptions = res.content.map(item => ({
-              label: item.index,
-              value: item.name
-            }));
-            let allOption = {
-              label: 'all',
-              value: '全部'
-            }
-            this.levelOptions.unshift(allOption);
-            
+          this.levelOptions = res.content.map((item) => ({
+            label: item.index,
+            value: item.name,
+          }));
+          let allOption = {
+            label: "all",
+            value: "全部",
+          };
+          this.levelOptions.unshift(allOption);
         }
-      })
+      });
     },
     getDmsDataList() {
       let requestParams = {
         columnId: 1658,
         states: 0,
         pageSize: 999,
-        page: 0
+        page: 0,
       };
       if (this.searchKeyword) {
         requestParams.search = JSON.stringify([
@@ -150,25 +158,39 @@ export default {
           },
         ]);
       }
-      appCenter.getDmsDataList(requestParams).then(res => {
+      appCenter.getDmsDataList(requestParams).then((res) => {
         if (res.code === 200) {
-          this.itemApplications = res.content.data.map(item => ({
+          this.itemApplications = res.content.data.map((item) => ({
             ...item,
-            status: item.status === 0 ? '待审核' : item.status === 1 ? '待发布' : item.status === 2 ? '未完成' : '已完成',
+            status:
+              item.status === 0
+                ? "待审核"
+                : item.status === 1
+                ? "待发布"
+                : item.status === 2
+                ? "未完成"
+                : "已完成",
             // levelName: item.level == 0 ? '区级' : item.level == 1 ? '街镇' : item.level == 2 ? '社区' : '',
-            levelName: this.levelOptions.find(info => info.label == item.level.trim())?.value || '',
-            tags: item.tag.split(',').map(tag => this.tagOptions.find(info => info.label == tag.trim())?.value || ''),
-            createTime: moment(item.create_time).format('YYYY-MM-DD HH:mm:ss')
-          }))
+            levelName:
+              this.levelOptions.find((info) => info.label == item.level.trim())?.value ||
+              "",
+            tags: item.tag
+              .split(",")
+              .map(
+                (tag) =>
+                  this.tagOptions.find((info) => info.label == tag.trim())?.value || ""
+              ),
+            createTime: moment(item.create_time).format("YYYY-MM-DD HH:mm:ss"),
+          }));
           this.applications = this.itemApplications;
           this.handleTabChange();
-        }else{
+        } else {
           this.applications = [];
         }
-      })
-    }
-  }
-}
+      });
+    },
+  },
+};
 </script>
 
 <style lang="less" scoped>
@@ -189,20 +211,20 @@ export default {
 /* 搜索栏样式 */
 .search-bar {
   margin-bottom: 20px;
-  
+
   .search-input {
     width: 400px;
-    
+
     // ::v-deep .el-input__inner {
     //   background-color: rgba(255, 255, 255, 0.1);
     //   border: 1px solid rgba(255, 255, 255, 0.2);
     //   color: #ffffff;
-      
+
     //   &::placeholder {
     //     color: rgba(255, 255, 255, 0.6);
     //   }
     // }
-    
+
     // ::v-deep .el-input__prepend {
     //   background-color: rgba(255, 255, 255, 0.1);
     //   border-color: rgba(255, 255, 255, 0.2);
@@ -217,26 +239,26 @@ export default {
 /* 过滤标签样式 */
 .filter-tabs {
   margin-bottom: 30px;
-  
-  ::v-deep .el-radio-group {
+
+  :deep(.el-radio-group) {
     .el-radio-button {
       background-color: rgba(255, 255, 255, 0.1);
       border-color: rgba(255, 255, 255, 0.2);
       color: rgba(255, 255, 255, 0.8);
-      
+
       &:first-child .el-radio-button__inner {
         border-left-color: rgba(255, 255, 255, 0.2);
       }
-      
+
       .el-radio-button__inner {
         background-color: transparent;
         border-color: rgba(255, 255, 255, 0.2);
         color: rgba(255, 255, 255, 0.8);
       }
-      
+
       &.is-active {
         background-color: #1890ff;
-        
+
         .el-radio-button__inner {
           background-color: #1890ff;
           border-color: #1890ff;
@@ -246,10 +268,10 @@ export default {
     }
   }
 }
-.app-content{
-    // height: 640px;
-    height: calc(100vh - 266px);
-    overflow: auto;
+.app-content {
+  // height: 640px;
+  height: calc(100vh - 266px);
+  overflow: auto;
 }
 
 /* 应用卡片网格样式 */
@@ -266,40 +288,40 @@ export default {
   border-radius: 8px;
   overflow: hidden;
   transition: all 0.3s ease;
-  
+
   &:hover {
     transform: translateY(-5px);
     box-shadow: 0 10px 30px rgba(24, 144, 255, 0.2);
     border-color: rgba(24, 144, 255, 0.4);
   }
-  
+
   .card-image {
     width: 100%;
     height: 160px;
     overflow: hidden;
-    
+
     img {
       width: 100%;
       height: 100%;
       object-fit: cover;
       transition: transform 0.3s ease;
     }
-    
+
     &:hover img {
       transform: scale(1.05);
     }
   }
-  
+
   .card-content {
     padding: 15px;
   }
-  
+
   .app-header {
     display: flex;
     justify-content: space-between;
     align-items: center;
     margin-bottom: 10px;
-    
+
     .app-name {
       font-size: 16px;
       font-weight: bold;
@@ -322,16 +344,16 @@ export default {
       border-radius: 4px;
     }
   }
-  
+
   .app-tags {
     margin-bottom: 10px;
-    
+
     .el-tag {
       margin-right: 5px;
       margin-bottom: 5px;
     }
   }
-  
+
   .app-description {
     font-size: 13px;
     line-height: 1.6;
@@ -343,17 +365,17 @@ export default {
     -webkit-line-clamp: 2;
     -webkit-box-orient: vertical;
   }
-  
+
   .app-footer {
     display: flex;
     justify-content: space-between;
     align-items: center;
-    
+
     .app-date {
       font-size: 12px;
       color: rgba(255, 255, 255, 0.5);
     }
-    
+
     .visit-button {
       padding: 4px 12px;
       font-size: 12px;
@@ -366,13 +388,13 @@ export default {
 .load-more {
   text-align: center;
   margin-bottom: 30px;
-  
+
   .el-button {
     padding: 10px 30px;
     background-color: rgba(24, 144, 255, 0.2);
     border-color: rgba(24, 144, 255, 0.4);
     color: #1890ff;
-    
+
     &:hover {
       background-color: rgba(24, 144, 255, 0.3);
       border-color: rgba(24, 144, 255, 0.6);
@@ -391,27 +413,27 @@ export default {
 @media (max-width: 992px) {
   .sidebar {
     width: 180px;
-    
+
     .sidebar-menu .menu-item {
       padding: 12px 15px;
-      
+
       i {
         font-size: 16px;
       }
     }
   }
-  
+
   .main-content {
     padding: 15px 20px;
   }
-  
+
   .search-input {
     width: 300px !important;
   }
-  
+
   .applications-grid {
     grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
     gap: 15px;
   }
 }
-</style>
+</style>