Bladeren bron

Merge branch 'master' of http://47.103.92.60:3003/skyversation/qp_onemap_ui

ximinghao 3 weken geleden
bovenliggende
commit
1fdc711cab

+ 3 - 2
public/static/config/config.js

@@ -1,9 +1,10 @@
 let systemConfig = {
     /* 通用全局变量 */
     defaultAccount: {
-        userName: "user002",
-        password: "Yysz@1234002"
+        username: "user002",
     },
+    touristUserId: "5",//默认游客用户(user002)id,Oauth中配置
+    adminRoleId: "1",//默认管理员角色id,Oauth中配置“系统管理员”角色
     baseServicerPath: "/oneMap",
     // oauth和DMS环境
     backServerPath: "http://121.43.55.7",

File diff suppressed because it is too large
+ 0 - 0
public/static/plugins/createAuth.js


+ 38 - 54
src/App.vue

@@ -3,6 +3,7 @@
 </template>
 <script>
 import api from "@/api/common";
+import encrypt‌ from "@/utils/encrypt‌";
 export default {
   name: "App",
   data() {
@@ -23,63 +24,46 @@ export default {
     // });
     let that = this;
     // 默认登录
-    api
-      .login({
-        userName: systemConfig.defaultAccount.userName,
-        password: AesEncryptUtil.getPassword(),
-        clientId: "1",
-      })
-      .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: "服务器忙碌,请稍后重试!",
-                });
+    encrypt‌().then(() => {
+      // 登录成功之后要批量加载一下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: "服务器忙碌,请稍后重试!",
-        });
       });
+    }).catch((err) => {
+      that.$message({
+        type: "error",
+        message: err,
+      });
+    });
   },
   methods: {
     // scrollUpdate() {

+ 11 - 3
src/api/appCenter.js

@@ -1,5 +1,6 @@
 import {
-    postform
+    postform,
+    postBody
 } from '../utils/request'
 //获得数据列表接口
 const getDmsDataList = (params) => {
@@ -19,12 +20,19 @@ const getModelById = (params) => {
 }
 // 获取内容
 const getContentById = (params) => {
-  return postform(systemConfig.dmsDataProxy + '/content/selectContentById', params);
+    return postform(systemConfig.dmsDataProxy + '/content/selectContentById', params);
 }
+
+// 获取运行管理页面数据(params:{nowTimes:[],lastTimes:[]})
+const getAllYxglDatas = (params) => {
+    return postBody(systemConfig.baseServicerPath + '/OperationManagementController/getAllYxglDatas', params);
+}
+
 export default {
     getDmsDataList,
     getDmsCNameAType,
     getDmsSName,
     getModelById,
-    getContentById
+    getContentById,
+    getAllYxglDatas
 }

+ 13 - 2
src/api/count.js

@@ -519,8 +519,19 @@ export function countUserDataByTime(time1, time2, time3) {
     return resolveoauthResult(postform(oauthCountUser, data))
 }
 
-export function coutService() {
-    return resolveoauthResult(postform(oauthCountPermission))
+export function countUserDataByAutoTime(param) {
+    let data = {
+        "time": param
+    }
+    return resolveoauthResult(postform(oauthCountUser, data))
+}
+
+export function coutService(start, end) {
+    let data = {
+        start: formatDateToDb(start),
+        end: formatDateToDb(end)
+    };
+    return resolveoauthResult(postform(oauthCountPermission,data))
 }
 
 function timeCheckers(start, end) {

+ 3 - 9
src/components/wgn/controlPanel.vue

@@ -5,7 +5,7 @@
         <div class="">
           场景名称:
           <el-cascader
-            :disabled="$route.query.sceneId"
+            :disabled="$route.query.sceneId != undefined"
             v-model="SceneValue"
             placeholder="试试搜索:距离"
             :options="SceneList"
@@ -144,14 +144,7 @@
             {{ backData.message || backData.error }}
           </div>
 
-          <div
-            class="vueJsonEditor_box"
-            v-show="
-              SceneValue &&
-              dmsServerItem &&
-              (ifHasType('point') || ifHasType('polyline') || ifHasType('polygon'))
-            "
-          >
+          <div class="vueJsonEditor_box" v-show="SceneValue && dmsServerItem">
             <div class="vueJsonEditor_tools">
               <span
                 v-if="
@@ -164,6 +157,7 @@
               <span @click="copyJsonData(backData.content)">copy</span>
             </div>
             <vue-json-editor
+              v-if="backData.content"
               v-model="backData.content"
               :value="backData.content"
               @json-change="handleJsonChange2"

+ 12 - 0
src/components/yxgl/EchartsDome.vue

@@ -81,6 +81,18 @@ export default {
           fontWeight: "normal", // 可选:字体粗细
         },
       });
+
+      // 合并tooltip配置
+      if (!mergedOption.tooltip) {
+        mergedOption.tooltip = {};
+      }
+      Object.assign(mergedOption.tooltip, {
+        backgroundColor: "rgba(0, 25, 50, 0.8)",
+        borderColor: "#1E90FF",
+        textStyle: {
+          color: "#fff",
+        },
+      });
       chartInstance.setOption(mergedOption, true);
       // 添加resize事件监听
       window.addEventListener("resize", () => {

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

@@ -12,7 +12,10 @@
       </div>
     </div>
     <div class="icon" :style="{ background: iconColor + '32' }">
-      <el-icon><Flag :color="iconColor" /></el-icon>
+      <el-icon>
+        <component :is="iconName" :color="iconColor" />
+        <!-- <Flag :color="iconColor" /> -->
+      </el-icon>
     </div>
   </div>
 </template>
@@ -26,8 +29,8 @@ export default {
       default: "",
     },
     value: {
-      type: Number,
-      default: 0,
+      type: String,
+      default: "-",
     },
     growth: {
       type: String,
@@ -37,6 +40,10 @@ export default {
       type: String,
       default: "#CCCCCC",
     },
+    iconName: {
+      type: String,
+      default: "WalletFilled",
+    },
     upStatus: {
       type: Number,
       //   -1 下降

+ 6 - 7
src/components/yxgl/table.vue

@@ -6,9 +6,8 @@
     </div> -->
     <el-table
       :data="tableData"
-      style="width: 100%"
-      height="calc(100% - 40px);
-  background-color: rgba(255, 255, 255, 0.1);"
+      style="width: 100%; background-color: rgba(255, 255, 255, 0.1)"
+      height="320px"
       :header-cell-style="headerCellStyle"
       :row-style="rowStyle"
       :cell-style="cellStyle"
@@ -16,10 +15,10 @@
       border
     >
       <!-- 添加序号列 -->
-      <el-table-column type="index" label="" width="50" align="center" />
-      <el-table-column prop="serviceName" label="服务名称" />
-      <el-table-column prop="serviceType" label="类别" width="600" />
-      <el-table-column prop="callCount" label="调用次数" width="280" />
+      <el-table-column type="index" label="" width="100" align="center" />
+      <el-table-column prop="c_path_comment" label="服务名称" />
+      <el-table-column prop="service_type" label="类别" width="600" />
+      <el-table-column prop="c_count" label="调用次数" width="280" />
     </el-table>
     <!-- <div class="table_pagination">
       <el-pagination

+ 0 - 0
src/views/yygl/manage/editManage.vue → src/components/yygl/editManage.vue


+ 21 - 0
src/main.js

@@ -27,6 +27,27 @@ initApp.config.globalProperties.$moment = moment;
 initApp.config.globalProperties.$getDmsTypes = (cName, index) => {
     return store.state.DmsTypesMap[cName] ? store.state.DmsTypesMap[cName][index + ''] : cName + "_" + index;
 };
+// 添加自定义方法,得到用户类型【1:游客;2:普通用户;3:管理员】
+initApp.config.globalProperties.$getUserType = () => {
+    // 得到用户id
+    let userId = store.state.userInfo.id;
+    // 得到角色ids
+    let roleIds = store.state.userInfo.roleId;
+    // 得到默认游客id
+    let touristUserId = systemConfig.touristUserId;
+    // 得到默认管理员角色id(roleId,在Oauth中配置)
+    let adminRoleId = systemConfig.adminRoleId;
+    if (!store.state.userInfo || !userId || !roleIds || userId == touristUserId) {
+        // 游客
+        return 1;
+    } else if (roleIds.split(',').includes(adminRoleId)) {
+        // 管理员
+        return 3;
+    } else {
+        // 普通用户
+        return 2;
+    }
+}
 
 for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
     initApp.component(key, component)

+ 46 - 0
src/utils/encrypt‌.js

@@ -0,0 +1,46 @@
+import api from "../api/common";
+import store from '../store';
+
+function login(username, password) {
+    return new Promise((resolve, reject) => {
+        api.login({
+            userName: username,
+            password: password,
+            clientId: "1",
+        }).then((result) => {
+            if (result.code == 200) {
+                store.commit("setUserInfo", result.content);
+                store.commit("setToken", result.message);
+                store.commit("setUserState", true);
+                resolve();
+            } else {
+                reject(result.content);
+            }
+        }).catch((err) => {
+            reject("服务器忙碌,请稍后重试!");
+        });
+    });
+}
+export default function encrypt(loginObj) {
+    return new Promise((resolve, reject) => {
+        if (loginObj == undefined) {
+            login(systemConfig.defaultAccount.username, AesEncryptUtil.getPassword()).then(function (result) {
+                resolve("登录成功");
+            }).catch(function (err) {
+                reject(err);
+            });
+        } else {
+            if (loginObj.username != undefined || loginObj.username != "" || loginObj.username != null) {
+                reject("用户名为空")
+            }
+            if (loginObj.password != undefined || loginObj.password != "" || loginObj.password != null) {
+                reject("密码为空")
+            }
+            return login(loginObj.username, AesEncryptUtil.getPassword(loginObj.password)).then(function (result) {
+                resolve("登录成功");
+            }).catch(function (err) {
+                reject(err);
+            });
+        }
+    })
+}

+ 24 - 10
src/views/HomePage.vue

@@ -167,15 +167,15 @@
       <div class="row" style="margin-top: 90px;">
         <div>
           <div class="strong-data blue ">365个</div>
-          <div class="font middle">地址</div>
+          <div class="font middle">地名地址</div>
         </div>
         <div>
           <div class="strong-data blue ">366个</div>
-          <div class="font middle">应用场景</div>
+          <div class="font middle">坐标转换</div>
         </div>
         <div>
           <div class="strong-data blue ">367个</div>
-          <div class="font middle">服务人数</div>
+          <div class="font middle">地图服务</div>
         </div>
       </div>
       <el-tabs v-model="activeUseCase" class="usecase-tabs" @tab-click="handleClick" stretch="true">
@@ -455,7 +455,7 @@
 <script>
 import { countAppUseByUnitName, countServiceUseByApp, countUnitUse, countUserData, topService, topUnit, totalCount, totalCountGroupByTime } from "@/api/count";
 import * as echarts from "echarts";
-
+import moment from "moment";
 let chart1 = null;
 let chartMultiLevelUse = null;
 
@@ -568,7 +568,7 @@ export default {
     this.initchartMultiLevelUse();
     const nowDate = new Date();
     nowDate.setHours(0, 0, 0, 0);
-    this.chartMluTimeRange = [new Date(new Date(nowDate).setDate(nowDate.getDate() - 7)), new Date(nowDate)];
+    this.chartMluTimeRange = [new Date(new Date(nowDate).setDate(nowDate.getDate() - 6)), new Date(nowDate)];
     this.chartMluFocusRoot()
     this.pullTopUnit()
     this.pullTopService()
@@ -596,11 +596,12 @@ export default {
       }
     },
     async initChart1() {
-
       const nowDate = new Date();
       nowDate.setHours(0, 0, 0, 0);
       let end = new Date(nowDate)
       let start = new Date(nowDate.setDate(nowDate.getDate() - 30))
+      start = new Date(moment(start).format("YYYY-MM-DD 00:00:00"));
+      end = new Date(moment(end).format("YYYY-MM-DD 23:59:59"));
       let data = await totalCountGroupByTime(start, end)
       let dataMap = {}
       for (let i = 0; i < data.length; i++) {
@@ -792,7 +793,10 @@ export default {
       this.chartMluFocus()
     },
     async chartMluFocusRoot() {
-      const data = await countUnitUse(...this.chartMluTimeRange);
+      let start = this.chartMluTimeRange[0], end = this.chartMluTimeRange[1];
+      start = new Date(moment(start).format("YYYY-MM-DD 00:00:00"));
+      end = new Date(moment(end).format("YYYY-MM-DD 23:59:59"));
+      const data = await countUnitUse(start, end);
       const names = [];
       const values = [];
       for (let index = 0; index < data.length; index++) {
@@ -803,7 +807,10 @@ export default {
       this.chartMluUpdateData(names, values)
     },
     async chartMluFocusApp(father) {
-      const data = await countAppUseByUnitName(...this.chartMluTimeRange, father);
+      let start = this.chartMluTimeRange[0], end = this.chartMluTimeRange[1];
+      start = new Date(moment(start).format("YYYY-MM-DD 00:00:00"));
+      end = new Date(moment(end).format("YYYY-MM-DD 23:59:59"));
+      const data = await countAppUseByUnitName(start, end, father);
       const names = [];
       const values = [];
       for (let index = 0; index < data.length; index++) {
@@ -814,7 +821,10 @@ export default {
       this.chartMluUpdateData(names, values)
     },
     async chartMluFocusService(father) {
-      const data = await countServiceUseByApp(...this.chartMluTimeRange, father);
+      let start = this.chartMluTimeRange[0], end = this.chartMluTimeRange[1];
+      start = new Date(moment(start).format("YYYY-MM-DD 00:00:00"));
+      end = new Date(moment(end).format("YYYY-MM-DD 23:59:59"));
+      const data = await countServiceUseByApp(start, end, father);
       const names = [];
       const values = [];
       for (let index = 0; index < data.length; index++) {
@@ -849,6 +859,8 @@ export default {
       nowDate.setHours(0, 0, 0, 0);
       let end = new Date(nowDate)
       let start = new Date(nowDate.setDate(nowDate.getDate() - 1))
+      start = new Date(moment(start).format("YYYY-MM-DD 00:00:00"));
+      end = new Date(moment(end).format("YYYY-MM-DD 23:59:59"));
       let data = (await totalCount(start, end))[0]
       this.lastDayCall = data == null ? 0 : data.count
     },
@@ -863,6 +875,8 @@ export default {
       nowDate.setHours(0, 0, 0, 0);
       let end = new Date(nowDate)
       let start = new Date(nowDate.setDate(nowDate.getDate() - days))
+      start = new Date(moment(start).format("YYYY-MM-DD 00:00:00"));
+      end = new Date(moment(end).format("YYYY-MM-DD 23:59:59")); 
       let data = (await totalCount(start, end))[0]
       return data == null ? 0 : data.count
     },
@@ -1275,7 +1289,7 @@ export default {
     .part1-1 {
       width: 1000px;
       height: 200px;
-      background: #09284c;
+      //background: #09284c;
       margin: 0 auto;
       margin-top: 120px;
       overflow: hidden;

+ 415 - 351
src/views/Sksjgl.vue

@@ -1,391 +1,455 @@
 <template>
-    <div class="sksjgl container">
-        <div class="server_title">
-            <el-image style="width: 824px; height: 786px" src="static/images/sksjgl/sksjgl_title.png" fit="cover" />
-            <div class="server_title_text">
-                <div class="server_title_text_title">时空数据管理</div>
-                <div class="server_title_text_content">
-                    二维数据服务是围绕二维地理信息数据展开的综合服务体系。它涵盖以像元阵列形式存储的栅格服务,广泛应用于影像地图展示、地形分析等;通过将地图切割成小图片进行快速加载的瓦片服务,提升地图浏览流畅度;能够精确表达地理要素几何形状和属性的矢量时空数据服务,记录地理对象随时间的变化;以及包含特定主题数据集合的专题库服务,如交通专题库、土地利用专题库等,满足不同行业对特定地理信息的深度挖掘与分析需求,为城市规划、资源管理、环境监测等领域提供有力的数据支撑。
-                </div>
-            </div>
+  <div class="sksjgl container">
+    <div class="server_title">
+      <el-image
+        style="width: 824px; height: 786px"
+        src="static/images/sksjgl/sksjgl_title.png"
+        fit="cover"
+      />
+      <div class="server_title_text">
+        <div class="server_title_text_title">时空数据管理</div>
+        <div class="server_title_text_content">
+          二维数据服务是围绕二维地理信息数据展开的综合服务体系。它涵盖以像元阵列形式存储的栅格服务,广泛应用于影像地图展示、地形分析等;通过将地图切割成小图片进行快速加载的瓦片服务,提升地图浏览流畅度;能够精确表达地理要素几何形状和属性的矢量时空数据服务,记录地理对象随时间的变化;以及包含特定主题数据集合的专题库服务,如交通专题库、土地利用专题库等,满足不同行业对特定地理信息的深度挖掘与分析需求,为城市规划、资源管理、环境监测等领域提供有力的数据支撑。
         </div>
-        <div class="checkModule">
-            <!-- 流程步骤 -->
-            <div class="process-bar">
-                <div :class="{ 'process-item': true, 'active': activePanel == 'sjzljc' }"
-                    @click="changePanel('sjzljc')">
-                    <div class="icon-box"> </div>
-                    <div class="label">数据质量检查</div>
-                </div>
-                <div class="divider"></div>
-                <div :class="{ 'process-item': true, 'active': activePanel == 'sksjjg' }"
-                    @click="changePanel('sksjjg')">
-                    <div class="icon-box"></div>
-                    <div class="label">时空数据加工</div>
-                </div>
-                <div class="divider"></div>
-                <div :class="{ 'process-item': true, 'active': activePanel == 'sksjgl' }"
-                    @click="changePanel('sksjgl')">
-                    <div class="icon-box"></div>
-                    <div class="label">时空数据管理</div>
-                </div>
-                <div class="divider"></div>
-                <div :class="{ 'process-item': true, 'active': activePanel == 'sksjfb' }"
-                    @click="changePanel('sksjfb')">
-                    <div class="icon-box"></div>
-                    <div class="label">时空数据发布</div>
-                </div>
-            </div>
-            <!-- 流程内容 -->
-            <div class="process-content">
-                <div class="process-content-item" v-for="(item, index) in nowFuncContent" :key="index">
-                    <a :href="item.url" target="_blank" rel="noopener noreferrer">
-                        <div class="pictrue"
-                            :style="{ background: 'url(' + item.image + ') no-repeat center center/100% 100%' }"></div>
-                        <div class="label">{{ item.label }}</div>
-                    </a>
-                </div>
-            </div>
+      </div>
+    </div>
+    <div class="checkModule">
+      <!-- 流程步骤 -->
+      <div class="process-bar">
+        <div
+          :class="{ 'process-item': true, active: activePanel == 'sjzljc' }"
+          @click="changePanel('sjzljc')"
+        >
+          <div class="icon-box"></div>
+          <div class="label">数据质量检查</div>
         </div>
-        <div class="time-space-operator-lib">
-            <!-- 标题区域 -->
-            <div class="title-section">
-                <h1>时空算子库</h1>
-            </div>
-            <!-- 描述区域 -->
-            <div class="desc-section">
-                <p>
-                    时空算子库具备丰富且强大的功能能力,在空间计算方面,涵盖量托轮廓下的宽度和面积计算,可利用投影坐标系结合既定定理与比例尺换算公式计算宽度,将多边形分割成三角形计算面积;还能判断点线面体的相互状态,通过计算点到线距离、射线法等方式判断点与线、面关系,利用计算几何方法判断线与线、线与面、体与点线面的关系;可进行缓冲区计算,以点、线、面为基础按给定距离生成缓冲区,支持线面体分割,依据指定规则对其进行分割并重新构建边和拓扑关系。在时空分析方面,能够对个面进行时空差异分析,判断空间重叠部分并通过求差来得到不相交面,同时考虑时间因素分析不同时间点面的状态变化。
-                </p>
-            </div>
-            <!-- 业务专区区域 -->
-            <div class="business-section">
-                <div class="business-header">
-                    <span>业务专属时空数据</span>
-                    <button class="more-btn">查看更多</button>
-                </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 class="divider"></div>
+        <div
+          :class="{ 'process-item': true, active: activePanel == 'sksjjg' }"
+          @click="changePanel('sksjjg')"
+        >
+          <div class="icon-box"></div>
+          <div class="label">时空数据加工</div>
+        </div>
+        <div class="divider"></div>
+        <div
+          :class="{ 'process-item': true, active: activePanel == 'sksjgl' }"
+          @click="changePanel('sksjgl')"
+        >
+          <div class="icon-box"></div>
+          <div class="label">时空数据管理</div>
+        </div>
+        <div class="divider"></div>
+        <div
+          :class="{ 'process-item': true, active: activePanel == 'sksjfb' }"
+          @click="changePanel('sksjfb')"
+        >
+          <div class="icon-box"></div>
+          <div class="label">时空数据发布</div>
+        </div>
+      </div>
+      <!-- 流程内容 -->
+      <div class="process-content">
+        <div
+          class="process-content-item"
+          v-for="(item, index) in nowFuncContent"
+          :key="index"
+        >
+          <a :href="item.url" target="_blank" rel="noopener noreferrer">
+            <div
+              class="pictrue"
+              :style="{
+                background: 'url(' + item.image + ') no-repeat center center/100% 100%',
+              }"
+            ></div>
+            <div class="label">{{ item.label }}</div>
+          </a>
+        </div>
+      </div>
+    </div>
+    <div class="time-space-operator-lib">
+      <!-- 标题区域 -->
+      <div class="title-section">
+        <h1>时空算子库</h1>
+      </div>
+      <!-- 描述区域 -->
+      <div class="desc-section">
+        <p>
+          时空算子库具备丰富且强大的功能能力,在空间计算方面,涵盖量托轮廓下的宽度和面积计算,可利用投影坐标系结合既定定理与比例尺换算公式计算宽度,将多边形分割成三角形计算面积;还能判断点线面体的相互状态,通过计算点到线距离、射线法等方式判断点与线、面关系,利用计算几何方法判断线与线、线与面、体与点线面的关系;可进行缓冲区计算,以点、线、面为基础按给定距离生成缓冲区,支持线面体分割,依据指定规则对其进行分割并重新构建边和拓扑关系。在时空分析方面,能够对个面进行时空差异分析,判断空间重叠部分并通过求差来得到不相交面,同时考虑时间因素分析不同时间点面的状态变化。
+        </p>
+      </div>
+      <!-- 业务专区区域 -->
+      <div class="business-section">
+        <div class="business-header">
+          <span>业务专属时空数据</span>
+          <!-- <button class="more-btn">查看更多</button> -->
+        </div>
+        <!-- 功能卡片列表 -->
+        <!-- 单个功能卡片 -->
+        <div class="card-list">
+          <div
+            class="card-item"
+            v-for="(item, index) in cardList"
+            :key="index"
+            @click.stop="handleOnlineDemo(item)"
+          >
+            <div class="card-title">{{ item.title.split("/")[1] }}</div>
+            <div class="card-bg">
+              <el-image
+                style="width: 100%; height: 100%"
+                :src="dmsDataProxy + item.c_picture"
+                fit="cover"
+              />
             </div>
-
+            <div class="card-desc">{{ item.content }}</div>
+          </div>
         </div>
-
+      </div>
     </div>
+  </div>
 </template>
 
 <script>
+import wgn from "@/api/wgn";
 export default {
-    data() {
-        return {
-            activePanel: 'sjzljc',
-            funcList: systemConfig.sksjgl.funcList,
-            nowFuncContent: [],
-
-            cardList: [
-                {
-                    title: "量托计算宽度面积",
-                    bgColor: "#1a4b8e",
-                    desc: "城市水系承载空间分析数据,包括主干道网和街道直径"
-                },
-                {
-                    title: "设置障碍的路径计算",
-                    bgColor: "#3a3a4a",
-                    desc: "城市大气降水水位时空监测,数据的历史分析"
-                },
-                {
-                    title: "判断点线面体的相互状态",
-                    bgColor: "#5a3a7a",
-                    desc: "公共服务设施分布分析,包含医院、教育、交通等场所"
-                },
-                {
-                    title: "缓冲区计算",
-                    bgColor: "#2a7a5a",
-                    desc: "农业用地分布现状与种植结构空间数据、全域耕地空间"
-                },
-                {
-                    title: "线面体分割",
-                    bgColor: "#1a5a8a",
-                    desc: "主要河网分布与水文监测数据、流域相关大数据"
-                },
-                {
-                    title: "时空差异分析",
-                    bgColor: "#1a6a9a",
-                    desc: "主要河网分布与水文监测数据、流域相关大数据"
-                }
-            ]
-        };
+  data() {
+    return {
+      dmsDataProxy: "",
+      activePanel: "sjzljc",
+      funcList: systemConfig.sksjgl.funcList,
+      nowFuncContent: [],
+      cardList: [],
+    };
+  },
+  mounted() {
+    this.dmsDataProxy = systemConfig.dmsDataProxy;
+    this.changePanel(this.activePanel);
+    this.searchServerList();
+  },
+  methods: {
+    changePanel(active) {
+      this.activePanel = active;
+      this.nowFuncContent = this.funcList[this.activePanel];
     },
-    mounted() {
-        this.changePanel(this.activePanel)
+    // 搜索微功能服务
+    searchServerList() {
+      let requestParams = {
+        columnId: 1651,
+        states: 0,
+        pageSize: 999,
+        page: 0,
+      };
+      requestParams.search = JSON.stringify([
+        {
+          field: "title",
+          searchType: 2,
+          content: { value: "%时空算子库%" },
+        },
+      ]);
+      // 获取微功能服务列表
+      wgn
+        .getDmsData(requestParams)
+        .then((res) => {
+          if (res.code === 200) {
+            this.cardList = res.content.data;
+          } else {
+            this.$message({
+              message: "搜索到0条微功能服务",
+              type: "warning",
+            });
+          }
+        })
+        .catch((e) => {
+          this.$message({
+            message: "搜索微功能服务失败" + e,
+            type: "error",
+          });
+        });
     },
-    methods: {
-        changePanel(active) {
-            this.activePanel = active;
-            this.nowFuncContent = this.funcList[this.activePanel]
-        }
-    }
+    // 在线演示微功能服务
+    handleOnlineDemo(item) {
+      let routerPath = {};
+      // 1. 解析目标路由(支持传参、命名路由等)
+      if (item.c_scene_name == "view") {
+        routerPath = {
+          path: item.c_url,
+        };
+      } else {
+        routerPath = {
+          path: "/wgnSingle", // 微功能
+          query: { sceneId: item.c_scene_name },
+        };
+      }
+      const routeData = this.$router.resolve(routerPath);
+      // 2. 打开新窗口(_blank 表示新窗口)
+      window.open(routeData.href, "_blank");
+    },
+  },
 };
 </script>
 
 <style lang="less" scoped>
 .container {
+  width: 100%;
+  margin: 0 auto;
+
+  .server_title {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+
+    .server_title_text {
+      width: calc(100vw - 824px);
+      height: 786px;
+      background-color: #1c2631;
+      color: #fff;
+      padding: 0 160px 0 60px;
+      display: flex;
+      flex-direction: column;
+      justify-content: center;
+      overflow: hidden;
+
+      &_title {
+        font-size: 64px;
+        font-weight: bold;
+        letter-spacing: 0.5rem;
+      }
+
+      &_content {
+        margin-top: 77px;
+        font-size: 22px;
+      }
+    }
+  }
+
+  .checkModule {
     width: 100%;
-    margin: 0 auto;
+    background-color: #0f2545;
+
+    /* 流程步骤样式 */
+    .process-bar {
+      width: fit-content;
+      margin: 0 auto;
+      padding-top: 100px;
+      padding-bottom: 100px;
+
+      .process-item {
+        width: 250px;
+        height: 200px;
+        display: inline-block;
+        color: #ffffff;
+        cursor: pointer;
+        border-radius: 10px;
+        padding: 10px 15px;
+
+        .icon-box {
+          width: 90px;
+          height: 90px;
+          text-align: center;
+          margin: 30px 80px 30px 80px;
+        }
+
+        .label {
+          height: 50px;
+          line-height: 50px;
+          font-size: 24px;
+          text-align: center;
+          letter-spacing: 5px;
+        }
+
+        &.active {
+          background-color: rgba(64, 149, 229, 0.69);
+        }
+
+        &:hover {
+          background-color: rgba(64, 149, 229, 0.69);
+        }
 
-    .server_title {
+        &:nth-child(1) .icon-box {
+          background: url("~@/assets/images/sksjgl/sjzljc.png") no-repeat center
+            center/100% 100%;
+        }
+
+        &:nth-child(3) .icon-box {
+          background: url("~@/assets/images/sksjgl/sksjjg.png") no-repeat center
+            center/100% 100%;
+        }
+
+        &:nth-child(5) .icon-box {
+          background: url("~@/assets/images/sksjgl/sksjgl.png") no-repeat center
+            center/100% 100%;
+        }
+
+        &:nth-child(7) .icon-box {
+          background: url("~@/assets/images/sksjgl/sksjfb.png") no-repeat center
+            center/100% 100%;
+        }
+      }
+
+      .divider {
+        width: 60px;
+        height: 200px;
+        vertical-align: top;
+        display: inline-block;
+        background: url("~@/assets/images/sksjgl/jiantou.png") no-repeat center
+          center/100%;
+      }
+    }
+
+    /* 流程内容样式 */
+    .process-content {
+      width: 100%;
+      padding: 50px 150px;
+      box-sizing: border-box;
+      display: flex;
+      /* 允许换行 */
+      flex-wrap: wrap;
+      /* 元素之间的间距(可选) */
+      gap: 75px;
+
+      .process-content-item {
+        /* 核心:每行2个,扣除gap间距 */
+        width: calc(50% - 38px);
+        // height: 400px;
+        // background: #f0f8ff;
+        // border: 1px solid #409eff;
         display: flex;
-        justify-content: center;
         align-items: center;
+        justify-content: center;
+        font-size: 18px;
+        color: #333;
+
+        a {
+          width: 100%;
+          height: 100%;
+
+          .pictrue {
+            width: 100%;
+            aspect-ratio: 1920 / 900;
+            border-radius: 8px;
+            transition: all 0.3s ease;
+          }
 
-        .server_title_text {
-            width: calc(100vw - 824px);
-            height: 786px;
-            background-color: #1c2631;
-            color: #fff;
-            padding: 0 160px 0 60px;
-            display: flex;
-            flex-direction: column;
-            justify-content: center;
-            overflow: hidden;
-
-            &_title {
-                font-size: 64px;
-                font-weight: bold;
-                letter-spacing: 0.5rem;
-            }
-
-            &_content {
-                margin-top: 77px;
-                font-size: 22px;
-            }
+          .label {
+            color: #ffffff;
+            text-align: center;
+            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);
         }
+      }
+    }
+  }
+
+  .time-space-operator-lib {
+    background-color: #1e407c;
+    color: #fff;
+    padding: 100px 150px;
+    box-sizing: border-box;
+
+    /* 标题区域 */
+    .title-section {
+      text-align: center;
+      margin-bottom: 50px;
+
+      h1 {
+        font-size: 50px;
+        font-weight: bold;
+      }
     }
 
-    .checkModule {
-        width: 100%;
-        background-color: #0f2545;
-
-        /* 流程步骤样式 */
-        .process-bar {
-            width: fit-content;
-            margin: 0 auto;
-            padding-top: 100px;
-            padding-bottom: 100px;
-
-            .process-item {
-                width: 250px;
-                height: 200px;
-                display: inline-block;
-                color: #ffffff;
-                cursor: pointer;
-                border-radius: 10px;
-                padding: 10px 15px;
-
-                .icon-box {
-                    width: 90px;
-                    height: 90px;
-                    text-align: center;
-                    margin: 30px 80px 30px 80px;
-                }
-
-                .label {
-                    height: 50px;
-                    line-height: 50px;
-                    font-size: 24px;
-                    text-align: center;
-                    letter-spacing: 5px;
-                }
-
-                &.active {
-                    background-color: rgba(64, 149, 229, 0.69);
-                }
-
-                &:hover {
-                    background-color: rgba(64, 149, 229, 0.69);
-                }
-
-                &:nth-child(1) .icon-box {
-                    background: url("~@/assets/images/sksjgl/sjzljc.png") no-repeat center center/100% 100%;
-                }
-
-                &:nth-child(3) .icon-box {
-                    background: url("~@/assets/images/sksjgl/sksjjg.png") no-repeat center center/100% 100%;
-                }
-
-                &:nth-child(5) .icon-box {
-                    background: url("~@/assets/images/sksjgl/sksjgl.png") no-repeat center center/100% 100%;
-                }
-
-                &:nth-child(7) .icon-box {
-                    background: url("~@/assets/images/sksjgl/sksjfb.png") no-repeat center center/100% 100%;
-                }
-            }
-
-            .divider {
-                width: 60px;
-                height: 200px;
-                vertical-align: top;
-                display: inline-block;
-                background: url("~@/assets/images/sksjgl/jiantou.png") no-repeat center center/100%;
-            }
+    /* 描述区域 */
+    .desc-section {
+      margin-bottom: 30px;
+      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;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 15px;
+        font-size: 16px;
+
+        span {
+          font-size: 20px;
         }
 
-        /* 流程内容样式 */
-        .process-content {
-            width: 100%;
-            padding: 50px 150px;
-            box-sizing: border-box;
-            display: flex;
-            /* 允许换行 */
-            flex-wrap: wrap;
-            /* 元素之间的间距(可选) */
-            gap: 75px;
-
-
-            .process-content-item {
-                /* 核心:每行2个,扣除gap间距 */
-                width: calc(50vw - 190px);
-                // height: 400px;
-                // background: #f0f8ff;
-                // border: 1px solid #409eff;
-                display: flex;
-                align-items: center;
-                justify-content: center;
-                font-size: 18px;
-                color: #333;
-
-                a {
-                    width: 100%;
-                    height: 100%;
-
-                    .pictrue {
-                        width: 100%;
-                        height: 20vw;
-                        border-radius: 8px;
-                        transition: all 0.3s ease;
-                    }
-
-                    .label {
-                        color: #ffffff;
-                        text-align: center;
-                        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);
-                }
-
-            }
+        .more-btn {
+          background-color: transparent;
+          border: 1px solid #fff;
+          color: #fff;
+          padding: 4px 12px;
+          border-radius: 4px;
+          cursor: pointer;
         }
+      }
     }
 
-    .time-space-operator-lib {
-        background-color: #1e407c;
-        color: #fff;
-        padding: 100px 150px;
-        box-sizing: border-box;
-
-        /* 标题区域 */
-        .title-section {
-            text-align: center;
-            margin-bottom: 50px;
+    /* 卡片列表 */
+    .card-list {
+      display: flex;
+      grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
+      justify-content: space-between;
+
+      .card-item {
+        background-color: rgba(255, 255, 255, 0.1);
+        padding: 15px;
+        border-radius: 8px;
+        height: 240px;
+        display: flex;
+        width: 10vw;
+        flex-direction: column;
 
-            h1 {
-                font-size: 50px;
-                font-weight: bold;
-            }
+        &:hover {
+          cursor: pointer;
+          box-shadow: 0 10px 30px rgba(24, 144, 255, 0.3);
+          border-color: rgba(24, 144, 255, 0.6);
         }
 
-        /* 描述区域 */
-        .desc-section {
-            margin-bottom: 30px;
-            line-height: 2;
-            font-size: 20px;
-            text-indent: 2em;
+        .card-title {
+          font-size: 15px;
+          font-weight: 500;
+          margin-bottom: 10px;
         }
 
-        /* 业务专区区域 */
-        .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;
-                justify-content: space-between;
-                align-items: center;
-                margin-bottom: 15px;
-                font-size: 16px;
-
-                span {
-                    font-size: 20px;
-                }
-
-                .more-btn {
-                    background-color: transparent;
-                    border: 1px solid #fff;
-                    color: #fff;
-                    padding: 4px 12px;
-                    border-radius: 4px;
-                    cursor: pointer;
-                }
-            }
+        .card-bg {
+          flex: 1;
+          border-radius: 4px;
+          margin: 8px 0;
         }
 
-        /* 卡片列表 */
-        .card-list {
-            display: grid;
-            grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
-            gap: 55px;
-
-            .card-item {
-                background-color: rgba(255, 255, 255, 0.1);
-                padding: 15px;
-                border-radius: 8px;
-                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;
-                    margin-bottom: 10px;
-                }
-
-                .card-bg {
-                    flex: 1;
-                    border-radius: 4px;
-                    margin: 8px 0;
-                }
-
-                .card-desc {
-                    font-size: 12px;
-                    opacity: 0.8;
-                    line-height: 1.4;
-                }
-            }
+        .card-desc {
+          font-size: 12px;
+          opacity: 0.8;
+          line-height: 1.4;
+          /* 文字最多显示两行,超出部分省略号 */
+          overflow: hidden;
+          text-overflow: ellipsis;
+          display: -webkit-box;
+          -webkit-line-clamp: 2;
+          -webkit-box-orient: vertical;
         }
+      }
     }
+  }
 }
-</style>
+</style>

+ 47 - 38
src/views/Wgn.vue

@@ -3,7 +3,7 @@
     <el-backtop target=".wgn_box" :right="20" :bottom="70" />
     <div class="server_title">
       <el-image
-        style="width: 43vw; height: calc(100vh - 120px)"
+        style="width: 50%; height: calc(100vh - 120px)"
         src="static/images/wgn_title.png"
         fit="cover"
       />
@@ -195,6 +195,8 @@ export default {
           c_department: "",
         },
       },
+      // 搜索微功能服务的防抖定时器
+      searchTimeout: null,
     };
   },
   mounted() {
@@ -204,44 +206,50 @@ export default {
   methods: {
     // 搜索微功能服务
     searchServerList() {
-      let requestParams = {
-        columnId: 1651,
-        states: 0,
-        pageSize: 999,
-        page: 0,
-      };
-      if (this.searchStr) {
-        requestParams.search = JSON.stringify([
-          {
-            field: "title",
-            searchType: 2,
-            content: { value: "%" + this.searchStr + "%" },
-          },
-        ]);
+      // 添加防抖功能,避免频繁搜索导致性能问题
+      if (this.searchTimeout != null) {
+        clearTimeout(this.searchTimeout);
       }
-      // 获取微功能服务列表
-      wgn
-        .getDmsData(requestParams)
-        .then((res) => {
-          if (res.code === 200) {
-            this.dmsServerList = res.content.data;
-            this.$message({
-              message: "搜索到" + this.dmsServerList.length + "条微功能服务",
-              type: "success",
-            });
-          } else {
+      this.searchTimeout = setTimeout(() => {
+        let requestParams = {
+          columnId: 1651,
+          states: 0,
+          pageSize: 999,
+          page: 0,
+        };
+        if (this.searchStr) {
+          requestParams.search = JSON.stringify([
+            {
+              field: "title",
+              searchType: 2,
+              content: { value: "%" + this.searchStr + "%" },
+            },
+          ]);
+        }
+        // 获取微功能服务列表
+        wgn
+          .getDmsData(requestParams)
+          .then((res) => {
+            if (res.code === 200) {
+              this.dmsServerList = res.content.data;
+              this.$message({
+                message: "搜索到" + this.dmsServerList.length + "条微功能服务",
+                type: "success",
+              });
+            } else {
+              this.$message({
+                message: "搜索到0条微功能服务",
+                type: "warning",
+              });
+            }
+          })
+          .catch((e) => {
             this.$message({
-              message: "搜索到0条微功能服务",
-              type: "warning",
+              message: "搜索微功能服务失败" + e,
+              type: "error",
             });
-          }
-        })
-        .catch((e) => {
-          this.$message({
-            message: "搜索微功能服务失败" + e,
-            type: "error",
           });
-        });
+      }, 0);
     },
     // 申请使用微功能服务
     handleApply(item) {
@@ -306,15 +314,16 @@ export default {
         routerPath = {
           path: item.c_url,
         };
+        this.$router.push(routerPath);
       } else {
         routerPath = {
           path: "/wgnSingle", // 微功能
           query: { sceneId: item.c_scene_name },
         };
+        const routeData = this.$router.resolve(routerPath);
+        // 2. 打开新窗口(_blank 表示新窗口)
+        window.open(routeData.href, "_blank");
       }
-      const routeData = this.$router.resolve(routerPath);
-      // 2. 打开新窗口(_blank 表示新窗口)
-      window.open(routeData.href, "_blank");
     },
   },
 };

+ 1 - 1
src/views/Yxgl.vue

@@ -18,7 +18,7 @@
           <template #title>信息反馈</template>
         </el-menu-item>
       </el-sub-menu>
-      <el-sub-menu index="2">
+      <el-sub-menu index="2" v-if="$getUserType() == 3">
         <template #title>
           <el-icon><Tools /></el-icon>
           <span>运行管理子系统</span>

+ 340 - 65
src/views/skmh/index.vue

@@ -4,7 +4,7 @@
 
     <div class="server_title">
       <el-image
-        style="width: 824px; height: 786px"
+        style="width: 50%; height: calc(100vh - 120px)"
         src="static/images/wgn_title.png"
         fit="cover"
       />
@@ -38,8 +38,8 @@
               fit="cover"
             />
           </div>
-          <div class="stat-number">1,248</div>
-          <div class="stat-label">较上月增长12.5%</div>
+          <div class="stat-number">{{countData.total.service}}</div>
+          <div class="stat-label">较上月增长{{countData.grown}}%</div>
         </div>
         <div class="stat-card card-2">
           <div class="stat-label">新上线服务统计
@@ -49,7 +49,7 @@
               fit="cover"
             />
           </div>
-          <div class="stat-number">86</div>
+          <div class="stat-number">{{countData.curMonth.service}}</div>
           <div class="stat-label">本月新增服务</div>
         </div>
         <div class="stat-card card-3">
@@ -60,8 +60,8 @@
               fit="cover"
             />
           </div>
-          <div class="stat-number">24,586</div>
-          <div class="stat-label">本周新增12,34人</div>
+          <div class="stat-number">{{countData.total.username}}</div>
+          <div class="stat-label">本周新增{{countData.curWeek.username}}人</div>
         </div>
       </div>
     </div>
@@ -131,11 +131,18 @@
       <div class="chart-card full-width">
         <div class="chart-title">用户分布</div>
         <!-- <div ref="comparisonChart" class="chart-container"></div> -->
-        <el-table :data="tableData" style="width: 100%">
-          <el-table-column prop="name" label="委办单位" />
-          <el-table-column prop="number" label="用户名称" />
-          <el-table-column prop="activity" label="活跃天数" />
-          <el-table-column prop="server" label="服务使用量" />
+        <el-table :data="tableData" 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 prop="unit" label="委办单位" />
+          <el-table-column prop="user" label="用户数量" />
+          <el-table-column prop="active" label="活跃天数" />
+          <el-table-column prop="count" label="服务使用量" />
         </el-table>
       </div>
     </div>
@@ -146,8 +153,18 @@
         <h2>功能演示</h2>
       </div>
       <div class="demo-grid">
-        <div class="demo-card">
-          <div class="demo-thumbnail">
+        <div class="demo-card" v-for="item in applications" :key="item.id">
+          <div class="demo-thumbnail" :style="{ backgroundImage: 'url(' + item.backImg + ')',backgroundSize: 'cover' }">
+            <div class="play-btn" @click="openVideo(item)">▶</div>
+          </div>
+          <div class="demo-title">
+            <div class="demo-label">{{item.title}}</div>
+            <div class="demo-text">{{item.content}}</div>
+          </div>
+        </div>
+
+        <!-- <div class="demo-card">
+          <div class="demo-thumbnail" :style="{ backgroundImage: 'url(' + imageUrl + ')' }">
             <div class="play-btn">▶</div>
           </div>
           <div class="demo-title">
@@ -172,16 +189,30 @@
             <div class="demo-label">实际业务场景应用</div>
             <div class="demo-text">展示系统在行业中的实际应用案例</div>
           </div>
-          
-        </div>
+        </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>
   </div>
 </template>
 
 <script>
 import * as echarts from 'echarts'
-
+import appCenter from "@/api/appCenter";
+import { countUserList,coutService,totalCountGroupByTime,countUserDataByAutoTime } from "@/api/count";
+import moment from "moment";
 export default {
   name: 'SpatialTemporalPortal',
   data() {
@@ -191,39 +222,63 @@ export default {
       activityChart: null,
       dataVolumeChart: null,
       comparisonChart: null,
-      fromTime:{
-        date:[new Date(),new Date()]
-      },
-      tableData:[
-        {
-          number: '1234',
-          name: 'tom',
-          activity:'87',
-          server: '2324',
+      centerDialogVisible: false,
+      videoUrl: "",
+      imageUrl: "static/images/wgn_title.png",
+      countData:{
+        total:{
+          service:0,
+          username:0,
         },
-        {
-          number: '1234',
-          name: 'canver',
-          activity:'78',
-          server: '2324',
+        curWeek:{
+          service:0,
+          username:0,
         },
-        {
-          number: '1234',
-          name: 'lina',
-          activity:'88',
-          server: '2324',
+        curMonth:{
+          service:0,
+          username:0,
         },
-        {
-          number: '1234',
-          name: 'wang',
-          activity:'86',
-          server: '2324',
+        lastMonth:{
+          service:0,
+          username:0,
         },
-      ]
+        grown:0,
+      },
+      fromTime:{
+        date:[new Date(new Date().setMonth(new Date().getMonth() - 1)),new Date()],// 默认显示最近一个月
+      },
+      tableData:[],
+      applications:[],
     }
   },
+  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)",
+      };
+    },
+  },
   mounted() {
-    this.initCharts()
+    this.initData()
     window.addEventListener('resize', this.handleResize)
   },
   beforeUnmount() {
@@ -231,26 +286,218 @@ export default {
     this.destroyCharts()
   },
   methods: {
-    initCharts() {
-      this.initDeviceChart()
-      this.initStatusChart()
-      // this.initActivityChart()
-      // this.initDataVolumeChart()
-      // this.initComparisonChart()
+    initData(){
+      this.getTimeRange();
+      this.getCountUserDataByAutoTime();
+      this.getDmsDataList();
+    },
+    getTimeRange(){
+      this.getTotalCountGroupByTime();
+      this.getCountUserList();
+      this.getCoutService();
+    },
+    openVideo(param) {
+      console.log(param)
+      this.videoUrl = param.url;
+      this.centerDialogVisible = true;
+    },
+    closeDialog() {
+      this.videoUrl = "";
+      this.centerDialogVisible = false;
+    },
+    getDmsDataList() {
+      let requestParams = {
+        columnId: 1666,
+        states: 0,
+        orderBy: JSON.stringify([{"field":"update_time","orderByType":2}]),
+        pageSize: 9999,
+        page: 0,
+      };
+      this.applications = [];
+      appCenter.getDmsDataList(requestParams).then((res) => {
+        if (res.code === 200) {
+          this.applications = res.content.data.map((item) => ({
+            ...item,
+            status:
+              item.status === 0
+                ? "待审核"
+                : item.status === 1
+                ? "待发布"
+                : item.status === 2
+                ? "未完成"
+                : "已完成",
+            createTime: moment(item.create_time).format("YYYY-MM-DD HH:mm:ss"),
+            backImg: systemConfig.dmsDataProxy + item.c_picture,
+            url: item.c_url,
+          }));
+        }
+      });
+    },
+    getCountUserDataByAutoTime(){
+      let param = JSON.stringify([
+        {
+          name: "total",
+          start: '2000-01-01 00:00:00', // 从2000年1月1日开始
+          end: moment(new Date()).format("YYYY-MM-DD 23:59:59") // 到当前一天结束时间
+        },
+        {
+          name: "curWeek",
+          start: moment().weekday(1).format("YYYY-MM-DD 00:00:00"), //本周一00:00:00
+          end: moment(new Date()).format("YYYY-MM-DD 23:59:59") // 到当前一天结束时间
+        },
+        {
+          name: "curMonth",
+          start: moment().startOf('month').format('YYYY-MM-DD 00:00:00'), //本月1日00:00:00
+          end: moment(new Date()).format("YYYY-MM-DD 23:59:59") // 到当前一天结束时间
+        },
+        {
+          name: "lastMonth",
+          start: moment().subtract(1, 'month').startOf('month').format('YYYY-MM-DD 00:00:00'), //上月1日00:00:00
+          end:  moment().subtract(1, 'month').endOf('month').format("YYYY-MM-DD 23:59:59") //上月最后一天23:59:59
+        },
+      ])
+      // console.log(param)
+      countUserDataByAutoTime(param).then(res => {
+        // console.log(res)
+        this.countData = res;
+        this.countData.grown = (res.curMonth.service/res.lastMonth.service)*100;
+        this.countData.grown = this.countData.grown.toFixed(2)
+      })
+    },
+    getTotalCountGroupByTime(){
+      let start = this.fromTime.date[0], end = this.fromTime.date[1];
+      start = moment(start).format("YYYY-MM-DD 00:00:00");
+      end = moment(end).format("YYYY-MM-DD 23:59:59");
+      totalCountGroupByTime(start,end).then(res => {
+        this.drawLineChart(res)
+      })
+    },
+    drawLineChart(data){
+      let that = this;
+      let times = []
+      let values = []
+      data.sort((a, b) => a.time - b.time)
+      data.forEach((item,index) => {
+        times.push(moment(item.time).format("YYYY-MM-DD"))
+        values.push(item.count)
+      })
+      // 基于准备好的dom,初始化echarts实例
+      let lineChart = echarts.init(this.$refs.deviceChart)
+      const option = {
+        tooltip: {
+          trigger: "axis",
+          axisPointer: { type: "shadow" },
+          backgroundColor: 'rgba(0, 25, 50, 0.8)',
+          borderColor: '#1E90FF',
+          textStyle: {
+            color: '#fff'
+          },
+          formatter: function (params) {
+            let str = '';
+            params.forEach(item => {
+              str += `${item.name} <br/> ${item.seriesName}: ${item.value}次<br/>`;
+            });
+            return str;
+          }
+        },
+        grid: {
+          left: '3%',
+          right: '4%',
+          bottom: '3%',
+          containLabel: true
+        },
+        xAxis: {
+          type: 'category',
+          data: times,
+          axisLabel: {
+            color: '#a3b6c7',
+            formatter: function (params) {
+              let str = '';
+              let arr = params.split("-")
+              str = `${arr[1]}/${arr[2]}`
+              return str;
+            }
+          },
+          axisLine: {
+            lineStyle: {
+              color: '#1E90FF'
+            }
+          }
+          
+        },
+        yAxis: {
+          type: 'value',
+          axisLabel: {
+            color: '#a3b6c7'
+          },
+          axisLine: {
+            lineStyle: {
+              color: '#1E90FF'
+            }
+          },
+          splitLine: {
+            lineStyle: {
+              color: 'rgba(30, 144, 255, 0.2)'
+            }
+          }
+        },
+        series: [
+          {
+            name: "访问次数",
+            type: 'line',
+            data: values,
+            itemStyle: {
+              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                { offset: 0, color: '#1E90FF' },
+                { offset: 1, color: '#00BFFF' }
+              ])
+            }
+          }
+        ]
+      }
+      // 绘制图表
+      lineChart.setOption(option);
+      that.deviceChart = lineChart;
+    },
+    getCoutService(){
+        let start = this.fromTime.date[0], end = this.fromTime.date[1];
+        start = moment(start).format("YYYY-MM-DD 00:00:00");
+        end = moment(end).format("YYYY-MM-DD 23:59:59");
+        coutService(new Date(start),new Date(end)).then(res => {
+          // console.log('[ res ] >', res)
+          let arr = [];
+          if(res !=  undefined){
+            res.sort((a, b) => b.count - a.count)
+            res.forEach(item => {
+              // let str = { value: item.count, name: item.service_name, itemStyle: { color: '#52C41A' } }
+              let str = { value: item.count, name: item.service_name }
+              arr.push(str)
+            })
+          }
+          this.initStatusChart(arr)
+        })
+    },
+    getCountUserList(){
+      let that = this
+      let start = this.fromTime.date[0], end = this.fromTime.date[1];
+      start = moment(start).format("YYYY-MM-DD 00:00:00");
+      end = moment(end).format("YYYY-MM-DD 23:59:59");
+      countUserList(start,end).then(res => {
+        res.sort((a, b) => b.count - a.count)
+        that.tableData = res;
+      })
     },
     handleType(param){
       const end = new Date()
       const start = new Date()
-      start.setTime(start.getTime() - 3600 * 1000 * 24 * param) //天计算
-      end.setTime(end.getTime() - 3600 * 1000 * 24 * 1) //天计算
-      // start.setMonth(start.getMonth() - 6)
-      this.fromTime.date = [start,end]
+      start.setDate(start.getDate() - (param - 1))
+      console.log(start,end)
+      this.fromTime.date = [start,end];
+      this.getTimeRange();
     },
     changeTime(v){
-      debugger
-      console.log('[ eee ] >', v)
       this.fromTime.date=v
-      
+      this.getTimeRange();
     },
     
     initDeviceChart() {
@@ -323,7 +570,7 @@ export default {
       this.deviceChart.setOption(option)
     },
     
-    initStatusChart() {
+    initStatusChart(seriesData) {
       this.statusChart = echarts.init(this.$refs.statusChart)
       const option = {
         tooltip: {
@@ -367,12 +614,7 @@ export default {
             labelLine: {
               show: false
             },
-            data: [
-              { value: 400, name: '空间分析', itemStyle: { color: '#52C41A' } },
-              { value: 300, name: '数据查询', itemStyle: { color: '#FAAD14' } },
-              { value: 200, name: '三维可视化', itemStyle: { color: '#F5222D' } },
-              { value: 100, name: '路径规划', itemStyle: { color: '#8C8C8C' } }
-            ]
+            data: seriesData
           }
         ]
       }
@@ -766,12 +1008,12 @@ export default {
   
   .stats-grid {
     display: flex;
-    justify-content: center;
+    justify-content: space-between;
     gap: 30px;
     flex-wrap: wrap;
     
     .stat-card {
-      width: 29%;
+      width: 400px;
       height: 150px;
       border-radius: 12px;
       padding: 20px;
@@ -957,8 +1199,10 @@ export default {
       box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
       transition: transform 0.3s ease;
       
-      &:hover {
+       &:hover {
         transform: translateY(-5px);
+        box-shadow: 0 10px 30px rgba(24, 144, 255, 0.3);
+        border-color: rgba(24, 144, 255, 0.6);
       }
       
       .demo-thumbnail {
@@ -1072,4 +1316,35 @@ export default {
     }
   }
 }
+// 美化表格行悬停效果
+: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>

+ 292 - 191
src/views/yxgl/StatisticalAnalysis.vue

@@ -3,9 +3,11 @@
     <!-- 搜索区域 -->
     <div class="searchBox">
       <div>
-        对比时间:
+        <!-- 添加一个按钮触发事件 -->
+        <!-- <el-button type="primary" @click="playTTS()">请求音频</el-button> -->
+        <!-- 对比时间:
         <el-date-picker
-          v-model="compareTimes"
+          v-model="lastTimes"
           type="daterange"
           unlink-panels
           range-separator="到"
@@ -14,10 +16,10 @@
           disabled
           size="large"
           style="margin-right: 30px"
-        />
+        /> -->
         搜索时间:
         <el-date-picker
-          v-model="dateValue"
+          v-model="nowTimes"
           type="daterange"
           unlink-panels
           range-separator="到"
@@ -31,36 +33,14 @@
     <!-- 服务调用card -->
     <div class="flex">
       <card
+        v-for="item in TopCardDatas"
+        :key="item.name"
         class="card flex"
-        :title="'委办总数'"
-        :value="8"
-        :growth="'较上个月增长了12%'"
-        iconColor="#2563db"
-        :upStatus="1"
-      />
-      <card
-        class="card flex"
-        :title="'系统总数'"
-        :value="100"
-        :growth="'较上个月下降了12%'"
-        iconColor="#16a34a"
-        :upStatus="-1"
-      />
-      <card
-        class="card flex"
-        :title="'服务总数'"
-        :value="1000"
-        :growth="'较上个月增长了12%'"
-        iconColor="#9333ea"
-        :upStatus="1"
-      />
-      <card
-        class="card flex"
-        :title="'服务调用总数'"
-        :value="10"
-        :growth="'与上月持平'"
-        iconColor="#ca8a04"
-        :upStatus="0"
+        :title="item.name"
+        :value="item.value"
+        :growth="item.growth"
+        :iconColor="item.iconColor"
+        :upStatus="item.upStatus"
       />
     </div>
     <!-- 服务类信息统计 -->
@@ -77,10 +57,7 @@
       </div>
       <div class="flex">
         <div style="width: 48%; height: 400px">
-          <EchartsDome
-            :chartOption="chartOptions['服务调用趋势(近30天)']"
-            title="服务调用趋势(近30天)"
-          />
+          <EchartsDome :chartOption="chartOptions['服务调用趋势']" title="服务调用趋势" />
         </div>
         <div style="width: 48%; height: 400px">
           <EchartsDome title="服务类别分布" :chartOption="chartOptions['服务类别分布']" />
@@ -99,7 +76,7 @@
         </div>
         <div style="width: 68%; height: 400px">
           <EchartsDome
-            :chartOption="chartOptions['服务调用趋势(近30天)']"
+            :chartOption="chartOptions['委办活跃度趋势']"
             title="委办活跃度趋势"
           />
         </div>
@@ -114,7 +91,7 @@
       <div class="flex">
         <div style="width: 58%; height: 400px">
           <EchartsDome
-            :chartOption="chartOptions['用户部门分布']"
+            :chartOption="chartOptions['热点应用TOP10排名']"
             title="热点应用TOP10排名"
           />
         </div>
@@ -143,7 +120,7 @@
           <card
             class="card2 flex"
             :title="'服务机构总数'"
-            :value="8"
+            value="8"
             :growth="'较上个月增长了12%'"
             iconColor="#2563db"
             :upStatus="1"
@@ -151,7 +128,7 @@
           <card
             class="card2 flex"
             :title="'服务总数'"
-            :value="100"
+            value="100"
             :growth="'较上个月下降了12%'"
             iconColor="#16a34a"
             :upStatus="-1"
@@ -159,17 +136,14 @@
           <card
             class="card2 flex"
             :title="'服务调用总次数'"
-            :value="1000"
+            value="1000"
             :growth="'较上个月增长了12%'"
             iconColor="#9333ea"
             :upStatus="1"
           />
         </div>
         <div style="width: 68%; height: 420px">
-          <EchartsDome
-            :chartOption="chartOptions['服务调用趋势(近30天)']"
-            title="服务调用趋势(近30天)"
-          />
+          <EchartsDome :chartOption="chartOptions['服务调用趋势']" title="服务调用趋势" />
         </div>
       </div>
     </div>
@@ -180,8 +154,9 @@
 import card from "@/components/yxgl/card.vue";
 import EchartsDome from "@/components/yxgl/EchartsDome.vue";
 import Table from "@/components/yxgl/table.vue";
-import { totalCountGroupByTime, serviceInfo } from "@/api/count";
 import appCenter from "@/api/appCenter";
+import { color } from "echarts";
+
 export default {
   name: "",
   components: {
@@ -191,29 +166,65 @@ export default {
   },
   data() {
     return {
-      // 比较的时间范围(默认60天到30天前,主要跟dateValue有关系)
-      compareTimes: [],
+      // 比较的时间范围(默认60天到30天前,主要跟nowTimes有关系)
+      lastTimes: [],
       // 当前选中的时间范围
-      dateValue: [],
+      nowTimes: [],
+      TopCardDatas: [
+        {
+          name: "委办总数",
+          value: "-",
+          growth: "--",
+          iconColor: "#2563db",
+          iconName: "OfficeBuilding",
+          upStatus: 0,
+        },
+        {
+          name: "系统总数",
+          value: "-",
+          growth: "--",
+          iconColor: "#16a34a",
+          iconName: "WalletFilled",
+          upStatus: 0,
+        },
+        {
+          name: "服务总数",
+          value: "-",
+          growth: "--",
+          iconColor: "#9333ea",
+          iconName: "TrendCharts",
+          upStatus: 0,
+        },
+        {
+          name: "服务调用总数",
+          value: "-",
+          growth: "--",
+          iconColor: "#ca8a04",
+          iconName: "TrendCharts",
+          upStatus: 0,
+        },
+      ],
       shortcutsFun: this.shortcuts(),
       chartOptions: {},
       tableDatas: [],
     };
   },
   watch: {
-    dateValue: {
+    nowTimes: {
       handler(newVal, oldVal) {
         if (newVal !== oldVal && newVal.length > 0) {
           // 计算出比较的时间范围
-          this.compareTimes = [
+          this.lastTimes = [
             this.$moment(
               new Date(
                 new Date(newVal[0]).setTime(
-                  new Date(newVal[0]).getTime() - (newVal[1] - newVal[0])
+                  new Date(newVal[0]).getTime() -
+                    (newVal[1] - newVal[0]) -
+                    24 * 60 * 60 * 1000
                 )
               )
-            ).format("YYYY-MM-DD"),
-            this.$moment(new Date(newVal[0])).format("YYYY-MM-DD"),
+            ).format("YYYY-MM-DD 00:00:00"),
+            this.$moment(new Date(newVal[0])).format("YYYY-MM-DD 00:00:00"),
           ];
           this.initChart();
         }
@@ -224,113 +235,166 @@ export default {
   },
   mounted() {
     this.$nextTick(() => {
-      this.dateValue = [
+      this.nowTimes = [
         new Date(new Date().setTime(new Date() - 3600 * 1000 * 24 * 30)),
         new Date(),
       ];
     });
   },
   methods: {
+    playTTS() {
+      const url = "http://192.168.2.8:8008/api/tts/audio";
+      fetch(url, {
+        method: "POST",
+        headers: {
+          "Content-Type": "application/json",
+        },
+        body: JSON.stringify({
+          text: `纸扎铺的灯笼
+深巷尽头的纸扎铺,夜半总飘出灯笼光。
+我加班晚归,撞见铺门虚掩,昏黄的灯笼悬在檐下,穗子无风自动。老板低头扎纸人,指尖翻飞,纸人眉眼竟和巷口失踪的外卖员一模一样。
+“要灯笼吗?” 他头也不抬,声音像揉皱的黄纸。
+我拔腿就跑,身后传来细碎的脚步声。回头看,那盏灯笼悠悠跟着,灯笼里的烛火,映出一张纸糊的脸。
+次日清晨,巷口多了一盏新灯笼,上面贴着我的名字。`,
+        }),
+      })
+        .then((response) => response.blob()) // 转换为Blob对象
+        .then((blob) => {
+          const audio = new Audio();
+          const blobUrl = window.URL.createObjectURL(blob);
+          audio.src = blobUrl;
+          audio.play();
+          audio.onended = () => {
+            window.URL.revokeObjectURL(blobUrl);
+          };
+        })
+        .catch((error) => {
+          console.error("TTS请求失败:", error);
+        });
+    },
     initChart() {
-      let datas = [
-        { value: 1048, name: "调用次数", value2: 3, date: "12/17" },
-        { value: 735, name: "平均响应时间", value2: 3, date: "12/18" },
-      ];
+      // 获取运行管理页面数据
+      appCenter
+        .getAllYxglDatas({
+          nowTimes: [
+            this.$moment(new Date(this.nowTimes[0])).format("YYYY-MM-DD 00:00:00"),
+            this.$moment(new Date(this.nowTimes[1])).format("YYYY-MM-DD 23:59:59"),
+          ],
+          lastTimes: this.lastTimes,
+        })
+        .then((res) => {
+          if (res && res.code == 200) {
+            this.TopCardDatas = res.content.TopCardDatas;
+            this.dataToOption(
+              "服务调用趋势",
+              "line",
+              [...res.content.serviceCountTrend],
+              {
+                legend: { data: ["调用次数"] },
+                xData: [],
+                xKey: "key",
+                xFormart: "YYYY-MM-DD",
+                yAxis: {
+                  type: "value",
+                  name: "调用次数",
+                  axisLine: { lineStyle: { color: "#42a5f5" } }, // 区分样式
+                },
+                yData: {
+                  key: "value",
+                  name: "调用次数",
+                  color: "#42a5f5",
+                  data: [],
+                  yAxisIndex: 0,
+                },
+              }
+            );
+            // 初始化服务类别分布,这个地方需要先根据serviceType进行groupBy统计调用次数
+            this.dataToOption("服务类别分布", "pie", [...res.content.serviceCountType], {
+              pieKey: { value: "value", name: "key" },
+              pieData: [],
+            });
 
-      // 根据时间返回服务调用趋势(近30天)
-      totalCountGroupByTime(this.dateValue[0], this.dateValue[1]).then((res) => {
-        if (res) {
-          const sortAsc = [...res].sort((a, b) => a.time - b.time);
-          this.dataToOption("服务调用趋势(近30天)", "line", [...sortAsc], {
-            legend: { data: ["调用次数"] },
-            xData: [],
-            xKey: "time",
-            xFormart: "YYYY-MM-DD",
-            yAxis: {
-              type: "value",
-              name: "调用次数",
-              axisLine: { lineStyle: { color: "#42a5f5" } }, // 区分样式
-            },
-            yData: {
-              key: "count",
-              name: "调用次数",
-              color: "#42a5f5",
-              data: [],
-              yAxisIndex: 0,
-            },
-          });
-        }
-      });
-      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: [],
-          });
+            // 服务调用TOP10《cPathComment+cUnit,调用次数》
+            let serviceDatas = [];
+            serviceDatas = res.content.serviceCountTop;
+            // 排序
+            serviceDatas.sort((a, b) => b.c_count - a.c_count);
+            this.initTableDatas(serviceDatas.slice(0, 10));
 
-          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];
+            // 委办分布
+            this.dataToOption("委办分布", "pie", [...res.content.serviceCountUnit], {
+              pieKey: { value: "value", name: "key" },
+              pieData: [],
+              legend: {
+                bottom: 10,
+              },
+              radius: "60%",
+              padAngle: 0,
+              borderRadius: 0,
+              label: {},
+            });
+
+            // 先清洗一下res.content.serviceCountUnitTrend
+            let serviceCountUnitTrend = [];
+            serviceCountUnitTrend = res.content.serviceCountUnitTrend;
+            let serviceCountUnitTrendLegend = [];
+            let itemData = serviceCountUnitTrend[0];
+            for (let key in itemData) {
+              if (key !== "key") {
+                serviceCountUnitTrendLegend.push(key);
+              }
             }
-          });
-          // 转换为数组
-          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;
+            this.dataToOption(
+              "委办活跃度趋势",
+              "line",
+              [...res.content.serviceCountUnitTrend],
+              {
+                legend: { data: serviceCountUnitTrendLegend },
+                xData: [],
+                xKey: "key",
+                xFormart: "YYYY-MM-DD",
+                yAxis: {
+                  type: "value",
+                  axisLine: { lineStyle: { color: "#42a5f5" } }, // 区分样式
+                },
+                yDatas: { auto: true },
+              }
+            );
+
+            let serviceDatas2 = [];
+            serviceDatas2 = res.content.serviceCountApplicationTop;
+            // 排序
+            serviceDatas2.sort((a, b) => a.c_count - b.c_count);
+            // 用户部门分布
+            this.dataToOption("热点应用TOP10排名", "bar", serviceDatas2.slice(0, 10), {
+              showLegend: false,
+              xData: [],
+              xKey: "c_application",
+              yData: {
+                key: "c_count",
+                name: "调用次数",
+                color: "#42a5f5",
+                data: [],
+              },
+            });
+            // 数据类别分布
+            if (res.content.dataTypes && res.content.dataTypes.length > 0) {
+              this.dataToOption("数据类别分布", "pie", [...res.content.dataTypes], {
+                pieKey: { value: "count", name: "service_name" },
+                pieData: [],
+                legend: {
+                  bottom: 10,
+                },
+                radius: "60%",
+                padAngle: 0,
+                borderRadius: 0,
+                label: {},
               });
-              serviceTypeDatas2.push(tableDataItem);
             }
+
+            // console.log("getAllYxglDatas", res);
           }
-          // 根据callCount进行降序排序并截取前10条
-          serviceTypeDatas2.sort((a, b) => b.callCount - a.callCount);
-          serviceTypeDatas2 = serviceTypeDatas2.slice(0, 10);
-          this.initTableDatas(serviceTypeDatas2);
-        }
-      });
+        });
       // 应用状态分布,cloumnId:1659
       appCenter
         .getDmsDataList({
@@ -372,29 +436,6 @@ export default {
           }
         });
 
-      // 用户部门分布
-      this.dataToOption("用户部门分布", "bar", datas, {
-        showLegend: false,
-        xData: [],
-        xKey: "date",
-        yData: {
-          key: "value",
-          name: "调用次数",
-          color: "#42a5f5",
-          data: [],
-        },
-      });
-      this.dataToOption("数据类别分布", "pie", datas, {
-        pieKey: { value: "value", name: "name" },
-        pieData: [],
-        legend: {
-          bottom: 10,
-        },
-        radius: "60%",
-        padAngle: 0,
-        borderRadius: 0,
-        label: {},
-      });
       this.dataToOption("数据质量评分", "radar", null, null);
     },
     /**
@@ -419,6 +460,34 @@ export default {
           }
           if (keyRule.yData) {
             keyRule.yData.data.push(item[keyRule.yData.key]);
+            keyRule.series = [
+              {
+                name: keyRule.yData.name,
+                type: "line",
+                smooth: true,
+                data: keyRule.yData.data,
+                lineStyle: {
+                  color: keyRule.yData.color ? keyRule.yData.color : "",
+                  type: keyRule.yData.ifDashed ? "dashed" : "",
+                }, // 蓝色线条
+                itemStyle: keyRule.yData.color,
+                symbol: "circle", // 节点形状
+                symbolSize: 6, // 节点大小
+              },
+            ];
+          }
+          if (keyRule.yDatas) {
+            // 先根据lenged得到data集合
+            for (let name of keyRule.legend.data) {
+              if (keyRule.yDatas[name]) {
+                keyRule.yDatas[name].data.push(item[name]);
+              } else {
+                keyRule.yDatas[name] = {
+                  name: name,
+                  data: [item[name]],
+                };
+              }
+            }
           }
           if (keyRule.pieKey) {
             keyRule.pieData.push({
@@ -427,6 +496,20 @@ export default {
             });
           }
         });
+        // 专门用来处理多y数据的series
+        if (keyRule.yDatas) {
+          keyRule.series = [];
+          for (let name of keyRule.legend.data) {
+            keyRule.series.push({
+              name: name,
+              type: "line",
+              smooth: true,
+              data: keyRule.yDatas[name].data,
+              symbol: "circle", // 节点形状
+              symbolSize: 6, // 节点大小
+            });
+          }
+        }
       }
       let _option = {};
       switch (type) {
@@ -447,23 +530,22 @@ export default {
               data: keyRule.xData,
               axisTick: { show: false }, // 隐藏刻度
               splitLine: { show: false }, // 隐藏分割线
+              axisLabel: {
+                color: "#F2F3F5cc", // 字体颜色(支持十六进制、RGB、颜色名)
+                fontSize: 14, // 可选:字体大小
+                fontWeight: "normal", // 可选:字体粗细
+              },
             },
-            yAxis: keyRule.yAxis ? keyRule.yAxis : { type: "value" },
-            series: [
-              {
-                name: keyRule.yData.name,
-                type: "line",
-                smooth: true,
-                data: keyRule.yData.data,
-                lineStyle: {
-                  color: keyRule.yData.color ? keyRule.yData.color : "",
-                  type: keyRule.yData.ifDashed ? "dashed" : "",
-                }, // 蓝色线条
-                itemStyle: keyRule.yData.color,
-                symbol: "circle", // 节点形状
-                symbolSize: 6, // 节点大小
+            yAxis: {
+              type: "value",
+              axisLabel: {
+                color: "#42a5f5cc", // 字体颜色(支持十六进制、RGB、颜色名)
+                fontSize: 14, // 可选:字体大小
+                fontWeight: "normal", // 可选:字体粗细
               },
-            ],
+              splitLine: { lineStyle: { color: "#42a5f532" } },
+            },
+            series: keyRule.series,
           };
           break;
         case "pie":
@@ -527,10 +609,21 @@ export default {
             },
             xAxis: {
               type: "value",
+              axisLabel: {
+                color: "#42a5f5cc", // 字体颜色(支持十六进制、RGB、颜色名)
+                fontSize: 14, // 可选:字体大小
+                fontWeight: "normal", // 可选:字体粗细
+              },
+              splitLine: { lineStyle: { color: "#42a5f532" } },
             },
             yAxis: {
               type: "category",
               data: keyRule.xData,
+              axisLabel: {
+                color: "#F2F3F5cc", // 字体颜色(支持十六进制、RGB、颜色名)
+                fontSize: 14, // 可选:字体大小
+                fontWeight: "normal", // 可选:字体粗细
+              },
             },
             series: [
               {
@@ -592,12 +685,20 @@ export default {
     // 时间范围自定义时间
     shortcuts() {
       return [
+        {
+          text: "当天",
+          value: () => {
+            const end = new Date();
+            const start = new Date();
+            return [start, end];
+          },
+        },
         {
           text: "最近7天",
           value: () => {
             const end = new Date();
             const start = new Date();
-            start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 6);
             return [start, end];
           },
         },
@@ -606,7 +707,7 @@ export default {
           value: () => {
             const end = new Date();
             const start = new Date();
-            start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 29);
             return [start, end];
           },
         },
@@ -615,7 +716,7 @@ export default {
           value: () => {
             const end = new Date();
             const start = new Date();
-            start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 89);
             return [start, end];
           },
         },
@@ -624,7 +725,7 @@ export default {
           value: () => {
             const end = new Date();
             const start = new Date();
-            start.setTime(start.getTime() - 3600 * 1000 * 24 * 365);
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 364);
             return [start, end];
           },
         },

+ 43 - 28
src/views/yygl/appCenter.vue

@@ -1,30 +1,43 @@
 <template>
   <div class="app-center">
     <div class="container">
-        <!-- 左侧导航栏 -->
-        <div class="sidebar">
+      <!-- 左侧导航栏 -->
+      <div class="sidebar">
         <div class="sidebar-menu">
-            <div class="menu-item" :class="{'active': menuValue === 1}" @click="handleMenuClick(1)">
+          <div
+            class="menu-item"
+            :class="{ active: menuValue === 1 }"
+            @click="handleMenuClick(1)"
+          >
             <el-icon><Menu /></el-icon>
             <span>应用概览</span>
-            </div>
-            <div class="menu-item" :class="{'active': menuValue === 2}" @click="handleMenuClick(2)">
+          </div>
+          <div
+            class="menu-item"
+            v-if="$getUserType() != 1"
+            :class="{ active: menuValue === 2 }"
+            @click="handleMenuClick(2)"
+          >
             <el-icon><Grid /></el-icon>
             <span>应用管理</span>
-            </div>
-            <div class="menu-item" :class="{'active': menuValue === 3}" @click="handleMenuClick(3)">
+          </div>
+          <div
+            class="menu-item"
+            :class="{ active: menuValue === 3 }"
+            @click="handleMenuClick(3)"
+          >
             <el-icon><Monitor /></el-icon>
             <span>应用监测</span>
-            </div>
-        </div>
+          </div>
         </div>
+      </div>
 
-        <!-- 右侧主内容区 -->
-        <div class="main-content">
-            <AppOverview v-if="menuValue === 1" />
-            <AppManagement v-if="menuValue === 2" />
-            <AppMonitoring v-if="menuValue === 3" />
-        </div>
+      <!-- 右侧主内容区 -->
+      <div class="main-content">
+        <AppOverview v-if="menuValue === 1" />
+        <AppManagement v-if="menuValue === 2" />
+        <AppMonitoring v-if="menuValue === 3" />
+      </div>
     </div>
   </div>
 </template>
@@ -42,21 +55,24 @@ export default {
   },
   data() {
     return {
-        menuValue:1
-    }
+      userInfo: this.$store.state.userInfo,
+      userState: this.$store.state.userState,
+      menuValue: 1,
+    };
   },
   methods: {
     handleMenuClick(value) {
+      console.log(value);
       this.menuValue = value;
-    }
-  }
-}
+    },
+  },
+};
 </script>
 
 <style lang="less" scoped>
 .app-center {
   width: 100%;
-//   min-height: 100vh;
+  //   min-height: 100vh;
   height: calc(100vh - 120px);
   background-color: #08224a;
   color: #ffffff;
@@ -75,10 +91,10 @@ export default {
   width: 200px;
   background-color: #0a2a5a;
   border-right: 1px solid rgba(255, 255, 255, 0.1);
-  
+
   .sidebar-menu {
     padding: 20px 0;
-    
+
     .menu-item {
       display: flex;
       align-items: center;
@@ -86,17 +102,17 @@ export default {
       cursor: pointer;
       transition: all 0.3s ease;
       color: rgba(255, 255, 255, 0.8);
-      
+
       i {
         margin-right: 12px;
         font-size: 18px;
       }
-      
+
       &:hover {
         background-color: rgba(24, 144, 255, 0.2);
         color: #ffffff;
       }
-      
+
       &.active {
         background-color: rgba(24, 144, 255, 0.3);
         color: #ffffff;
@@ -112,5 +128,4 @@ export default {
   padding: 20px 30px;
   overflow: auto;
 }
-
-</style>
+</style>

+ 3 - 2
src/views/yygl/manage/index.vue

@@ -168,7 +168,7 @@ export default {
   name: "ApplicationManagement",
    components: {
     editManage: defineAsyncComponent(() =>
-      import("@/views/yygl/manage/editManage.vue")
+      import("@/components/yygl/editManage.vue")
     )
   },
   data() {
@@ -498,7 +498,8 @@ export default {
 /* 应用列表 */
 .applications-list {
   margin-bottom: 20px;
-  height: 500px;
+  // height: 500px
+  height: calc(100vh - 420px);
   overflow: auto;
   padding: 0px 10px 0px 10px;
 }

+ 224 - 19
src/views/yygl/monitor/index.vue

@@ -66,18 +66,42 @@
         <!-- 快捷应用 -->
         <div class="module">
           <div class="module-header">
-            <h3 class="module-title">快捷应用</h3>
-            <a href="#" class="module-more">更多</a>
+            <h3 class="module-title">应用趋势图</h3>
+            <el-select v-model="selectedAppRange" size="small" style="width: 120px;" @change="handleAppChange">
+              <el-option
+                    v-for="item in selectAapplications"
+                    :key="item.id"
+                    :label="item.title"
+                    :value="item.title"
+                />
+            </el-select>
+            <div>
+              <el-date-picker
+                size="small"
+                :clearable="false"
+                v-model="datetimeValue"
+                type="daterange"
+                @change="handleDateChange"
+                :shortcuts="shortcuts"
+                format="YYYY-MM-DD"
+                range-separator="-"
+                start-placeholder="开始时间"
+                end-placeholder="结束时间"
+              />
+            </div>
+            <!-- <a href="#" class="module-more">更多</a> -->
           </div>
           <div class="module-content">
-            <div class="quick-app" v-for="(app, index) in quickApps" :key="index">
+            <div ref="lineChartRes" class="chart-container"></div>
+            <!-- <div class="quick-app" v-for="(app, index) in quickApps" :key="index">
               <div class="app-item">
                 <span class="app-icon" :style="{ backgroundColor: getAppColor(app.type) }"
                   ><el-icon><Promotion /></el-icon
                 ></span>
                 <span class="app-name">{{ app.name }}</span>
               </div>
-            </div>
+            </div> -->
+
           </div>
         </div>
 
@@ -88,9 +112,9 @@
             <!-- <a href="#" class="module-more">更多</a> -->
           </div>
           <div class="module-content">
-            <div class="new-app" v-for="(app, index) in applications" :key="index">
+            <div class="new-app" v-for="(app, index) in newApplications" :key="index">
               <div class="app-info">
-                <span class="app-name">{{ app.title }}</span>
+                <span class="app-name">{{ app.title }} </span>
                 <span class="app-date">{{ app.createTime }}</span>
               </div>
             </div>
@@ -101,7 +125,7 @@
         <div class="module">
           <div class="module-header">
             <h3 class="module-title">应用热度排行TOP5</h3>
-            <a href="#" class="module-more">更多</a>
+            <!-- <a href="#" class="module-more">更多</a> -->
           </div>
           <div class="module-content">
             <div class="hot-app" v-for="(app, index) in hotApps" :key="index">
@@ -127,6 +151,7 @@
 <script>
 import * as echarts from "echarts";
 import appCenter from "@/api/appCenter";
+import { topApp,countAppInfo } from "@/api/count";
 import moment from "moment";
 export default {
   name: "ApplicationMonitor",
@@ -134,13 +159,67 @@ export default {
   data() {
     return {
       statusChart: null,
+      lineChart: null,
       itemApplications: [],
       applications: [],
+      newApplications: [],
       statusOptions: [],
       buffOptions: [],
       tagOptions: [],
       typeArrs: [],
-
+      selectAapplications: [],
+      selectedAppRange: '',
+      datetimeValue:[new Date(new Date(new Date().setMonth(new Date().getMonth() - 1))).setDate(new Date().getDate() + 1),new Date()],// 默认显示最近一个月
+      shortcuts: [
+        {
+          text: '当天',
+          value: () => {
+            const end = new Date()
+            const start = new Date()
+            start.setDate(start.getDate())
+            return [start, end]
+          },
+        },
+        {
+          text: '最近一周',
+          value: () => {
+            const end = new Date()
+            const start = new Date()
+            start.setDate(start.getDate() - 7)
+            start.setDate(start.getDate() + 1)
+            return [start, end]
+          },
+        },
+        {
+          text: '最近1月',
+          value: () => {
+            const end = new Date()
+            const start = new Date()
+            start.setMonth(start.getMonth() - 1)
+            start.setDate(start.getDate() + 1)
+            return [start, end]
+          },
+        },
+        {
+          text: '最近1年',
+          value: () => {
+            const end = new Date()
+            const start = new Date()
+            start.setFullYear(start.getFullYear() - 1)
+            start.setDate(start.getDate() + 1)
+            return [start, end]
+          },
+        },
+        // {
+        //   text: 'Last 3 months',
+        //   value: () => {
+        //     const end = new Date()
+        //     const start = new Date()
+        //     start.setMonth(start.getMonth() - 3)
+        //     return [start, end]
+        //   },
+        // },
+      ],
       // 快捷应用数据
       quickApps: [
         { name: "农产品安全管控示范应用场", type: "green" },
@@ -149,13 +228,7 @@ export default {
       ],
 
       // 应用热度排行数据
-      hotApps: [
-        { name: "崇明区乡村振兴一张图", count: 128, percentage: 100 },
-        { name: "数字孪生浦江", count: 65, percentage: 50.8 },
-        { name: '上海"一张图"大数据', count: 62, percentage: 48.4 },
-        { name: "黄浦智慧城管系统", count: 45, percentage: 35.2 },
-        { name: "上海生态环境管理", count: 38, percentage: 29.7 },
-      ],
+      hotApps: [],
     };
   },
   mounted() {
@@ -172,15 +245,140 @@ export default {
       this.getDmsCNameAType("appstatus");
       this.getDmsCNameAType("tag");
       this.getDmsDataList();
+      let param = {
+        num: 6,
+        start: '2000-01-01',
+        end: moment().format("YYYY-MM-DD"),
+      }
+      this.getAppCount(param);
+    },
+    // 获取应用统计数据
+    getAppCount(param) {
+      let that = this;
+      that.hotApps =[]
+      topApp(param.num,param.start,param.end).then((res) => {
+        let maxv = 100;
+        res.forEach((item,index) => {
+          if(index === 0){
+            maxv = item.count;
+          }
+          item.percentage = (item.count/maxv*100).toFixed(1);
+          let str = { name: item.name.trim() == '' ? '其他' : item.name, count: item.count, percentage: item.percentage }
+          that.hotApps.push(str);
+        });
+        //  console.log(that.hotApps);
+      });
+    },
+    handleAppChange(){
+      // console.log(this.selectedAppRange);
+      this.getCountAppInfo();
+    },
+    handleDateChange(){
+      // console.log(this.datetimeValue);
+      this.getCountAppInfo();
+    },
+    //获取应用统计Charts图表
+    getCountAppInfo(){
+      let start = moment(this.datetimeValue[0]).format("YYYY-MM-DD 00:00:00")
+      let end = moment(this.datetimeValue[1]).format("YYYY-MM-DD 23:59:59")
+      countAppInfo(start,end,this.selectedAppRange).then((res) => {
+        // console.log(res);
+        this.drawLineChart(res);
+      })
+    },
+    drawLineChart(data){
+      let that = this;
+      let times = []
+      let values = []
+      data.forEach((item,index) => {
+        times.push(moment(item.time).format("YYYY-MM-DD"))
+        values.push(item.count)
+      })
+      // 基于准备好的dom,初始化echarts实例
+      let lineChart = echarts.init(this.$refs.lineChartRes);
+      const option = {
+        tooltip: {
+          trigger: "axis",
+          axisPointer: { type: "shadow" },
+          backgroundColor: 'rgba(0, 25, 50, 0.8)',
+          borderColor: '#1E90FF',
+          textStyle: {
+            color: '#fff'
+          },
+          formatter: function (params) {
+            let str = '';
+            params.forEach(item => {
+              str += `${item.name} <br/> ${item.seriesName}: ${item.value}次<br/>`;
+            });
+            return str;
+          }
+        },
+        grid: {
+          left: '3%',
+          right: '4%',
+          bottom: '3%',
+          containLabel: true
+        },
+        xAxis: {
+          type: 'category',
+          data: times,
+          axisLabel: {
+            color: '#a3b6c7'
+          },
+          axisLine: {
+            lineStyle: {
+              color: '#1E90FF'
+            }
+          }
+        },
+        yAxis: {
+          type: 'value',
+          axisLabel: {
+            color: '#a3b6c7'
+          },
+          axisLine: {
+            lineStyle: {
+              color: '#1E90FF'
+            }
+          },
+          splitLine: {
+            lineStyle: {
+              color: 'rgba(30, 144, 255, 0.2)'
+            }
+          }
+        },
+        series: [
+          {
+            name: "调用次数",
+            type: 'line',
+            data: values,
+            itemStyle: {
+              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                { offset: 0, color: '#1E90FF' },
+                { offset: 1, color: '#00BFFF' }
+              ])
+            }
+          }
+        ]
+      }
+      // 绘制图表
+      lineChart.setOption(option);
+      that.lineChart = lineChart;
+
     },
     handleResize() {
       if (this.statusChart) this.statusChart.resize();
+      if (this.lineChart) this.lineChart.resize();
     },
     destroyCharts() {
       if (this.statusChart) {
         this.statusChart.dispose();
         this.statusChart = null;
       }
+      if (this.lineChart) {
+        this.lineChart.dispose();
+        this.lineChart = null;
+      }
     },
     getLimitedList() {
       return this.typeArrs.slice(0, 4); // 获取前四个元素
@@ -241,9 +439,15 @@ export default {
             createTime: moment(item.create_time).format("YYYY-MM-DD HH:mm:ss"),
           }));
           this.applications = this.itemApplications;
+          this.selectAapplications = this.applications.filter((item) => item.yylx == "0"); //yylx 0:内部 1:外部
+          this.newApplications = this.applications.slice(0, 10); // 获取前十个元素
+          this.selectedAppRange = this.applications[0].title;
           this.getTypeArrs();
+          this.getCountAppInfo();
         } else {
           this.applications = [];
+          this.selectAapplications = [];
+          this.selectedAppRange = '';
         }
       });
     },
@@ -251,8 +455,7 @@ export default {
       let that = this;
       that.statusOptions.forEach((item) => {
         let arr = this.applications.filter((info) => info.appstauts == item.label);
-        let name = item.value,
-          length = arr.length;
+        let name = item.value,length = arr.length;
         let str = { name: name, value: length };
         that.typeArrs.push(str);
       });
@@ -265,6 +468,7 @@ export default {
         value: item.value,
         name: item.name, // 随机颜色
       }));
+      seriesData = seriesData.filter((item) => item.value > 0);// 过滤掉值为0的项
       this.statusChart = echarts.init(this.$refs.statusChart);
       const option = {
         tooltip: {
@@ -502,8 +706,9 @@ export default {
 
 /* 应用上新 */
 .new-app {
-  margin-bottom: 15px;
-  padding-bottom: 15px;
+ // margin-bottom: 15px;
+ // padding-bottom: 15px;
+  padding: 6px 0px 6px 0px;
   border-bottom: 1px solid rgba(255, 255, 255, 0.05);
 
   &:last-child {

+ 1 - 16
src/views/yygl/overview/index.vue

@@ -28,21 +28,6 @@
                 </el-radio-group>
             </div>
         </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>
-                    <el-radio-button label="2">街镇</el-radio-button> -->
-          </el-radio-group>
-        </div>
     
       <!-- 应用卡片网格 -->
       <div class="app-content">
@@ -231,7 +216,7 @@ export default {
 /* 右侧主内容区 */
 .main-content {
   flex: 1;
-  padding: 20px 30px;
+  padding: 5px 30px;
   overflow-y: auto;
 }
 

Some files were not shown because too many files changed in this diff