Browse Source

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

DESKTOP-6LTVLN7\Liumouren 1 day ago
parent
commit
04a4b38a3d
100 changed files with 2602 additions and 716 deletions
  1. 24 11
      README.md
  2. 245 1
      public/static/config/config.js
  3. BIN
      public/static/font/DIN-Bold/din-bold-2.ttf
  4. BIN
      public/static/images/example/1-1.png
  5. BIN
      public/static/images/example/1-2.png
  6. BIN
      public/static/images/example/1-3.jpg
  7. BIN
      public/static/images/example/1-4.png
  8. BIN
      public/static/images/example/2-1.jpg
  9. BIN
      public/static/images/example/2-2.jpg
  10. BIN
      public/static/images/example/2-3.jpg
  11. BIN
      public/static/images/example/2-4.jpg
  12. BIN
      public/static/images/example/2-5.jpg
  13. BIN
      public/static/images/example/2-6.jpg
  14. BIN
      public/static/images/example/3-1.png
  15. BIN
      public/static/images/example/3-10.jpg
  16. BIN
      public/static/images/example/3-11.jpg
  17. BIN
      public/static/images/example/3-12.png
  18. BIN
      public/static/images/example/3-13.png
  19. BIN
      public/static/images/example/3-14.jpg
  20. BIN
      public/static/images/example/3-15.jpg
  21. BIN
      public/static/images/example/3-16.png
  22. BIN
      public/static/images/example/3-17.png
  23. BIN
      public/static/images/example/3-18.jpg
  24. BIN
      public/static/images/example/3-19.jpg
  25. BIN
      public/static/images/example/3-2.jpg
  26. BIN
      public/static/images/example/3-20.png
  27. BIN
      public/static/images/example/3-21.jpg
  28. BIN
      public/static/images/example/3-22.png
  29. BIN
      public/static/images/example/3-23.png
  30. BIN
      public/static/images/example/3-3.jpg
  31. BIN
      public/static/images/example/3-4.jpg
  32. BIN
      public/static/images/example/3-5.jpg
  33. BIN
      public/static/images/example/3-6.jpg
  34. BIN
      public/static/images/example/3-7.jpg
  35. BIN
      public/static/images/example/3-8.jpg
  36. BIN
      public/static/images/example/3-9.jpg
  37. BIN
      public/static/images/example/def.png
  38. BIN
      public/static/images/example/item-black.png
  39. BIN
      public/static/images/example/item-white.png
  40. BIN
      public/static/images/example/item.webp
  41. BIN
      public/static/images/home/bg-1.png
  42. BIN
      public/static/images/home/bg-2.png
  43. BIN
      public/static/images/home/bg-3.png
  44. BIN
      public/static/images/home/bg-4.png
  45. BIN
      public/static/images/home/bg.png
  46. BIN
      public/static/images/logo.png
  47. BIN
      public/static/images/sjgl/bg.png
  48. BIN
      public/static/images/skmh/bg.png
  49. BIN
      public/static/images/wgn/bg.png
  50. BIN
      public/static/images/yyzx/bg.png
  51. 0 0
      public/static/plugins/createAuth.js
  52. 23 17
      src/api/rwgl.js
  53. BIN
      src/assets/images/common/example/1-1.png
  54. BIN
      src/assets/images/common/example/1-2.png
  55. BIN
      src/assets/images/common/example/1-3.jpg
  56. BIN
      src/assets/images/common/example/2-1.jpg
  57. BIN
      src/assets/images/common/example/2-2.jpg
  58. BIN
      src/assets/images/common/example/2-3.jpg
  59. BIN
      src/assets/images/common/example/2-4.jpg
  60. BIN
      src/assets/images/common/example/2-5.jpg
  61. BIN
      src/assets/images/common/example/2-6.jpg
  62. BIN
      src/assets/images/common/example/3-1.png
  63. BIN
      src/assets/images/common/example/3-10.jpg
  64. BIN
      src/assets/images/common/example/3-2.jpg
  65. BIN
      src/assets/images/common/example/3-3.jpg
  66. BIN
      src/assets/images/common/example/3-4.jpg
  67. BIN
      src/assets/images/common/example/3-5.jpg
  68. BIN
      src/assets/images/common/example/3-6.jpg
  69. BIN
      src/assets/images/common/example/3-7.jpg
  70. BIN
      src/assets/images/common/example/3-8.jpg
  71. BIN
      src/assets/images/common/example/3-9.jpg
  72. BIN
      src/assets/images/common/gn/1.png
  73. BIN
      src/assets/images/common/gn/2.png
  74. BIN
      src/assets/images/common/gn/3.png
  75. BIN
      src/assets/images/common/gn/4.png
  76. BIN
      src/assets/images/common/gn/5.png
  77. BIN
      src/assets/images/common/gn/6.png
  78. 1 1
      src/components/AppVue/Footer.vue
  79. 41 15
      src/components/AppVue/Header.vue
  80. 26 22
      src/components/AppVue/digitalScrollersComp.vue
  81. 22 18
      src/components/AppVue/numberScroll.vue
  82. 1 0
      src/components/user/user.vue
  83. 583 17
      src/components/wgn/controlPanel.vue
  84. 5 5
      src/store/index.js
  85. 12 32
      src/utils/request.js
  86. 533 155
      src/views/HomePage.vue
  87. 8 6
      src/views/Root.vue
  88. 78 6
      src/views/Sksjgl.vue
  89. 82 8
      src/views/Wgn.vue
  90. 12 3
      src/views/Yxgl.vue
  91. 324 168
      src/views/rwgl/Index.vue
  92. 285 130
      src/views/skmh/index.vue
  93. 19 17
      src/views/wgn/sksj/index.vue
  94. 1 0
      src/views/yxgl/StatisticalAnalysis.vue
  95. 9 2
      src/views/yygl/appCenter.vue
  96. 228 61
      src/views/yygl/index.vue
  97. 1 1
      src/views/yygl/manage/index.vue
  98. 2 1
      src/views/yygl/monitor/index.vue
  99. 36 18
      src/views/yygl/overview/index.vue
  100. 1 1
      vue.config.js

+ 24 - 11
README.md

@@ -1,28 +1,34 @@
 # qp_onemap
 
 ## Project setup
-```
+
+```bash
 npm install
 ```
 
 ### Compiles and hot-reloads for development
-```
+
+```bash
 npm run serve
 ```
 
 ### Compiles and minifies for production
-```
+
+```bash
 npm run build
 ```
 
 ### Customize configuration
+
 See [Configuration Reference](https://cli.vuejs.org/config/).
 
 ## 路线
+
 vue + axios + element-plus + less
 
 ## 业务模块对应关系
-skszk   时空算子库 
+
+skszk   时空算子库
 skmh    时空门户
 wgn     微功能
 yygl    应用管理
@@ -30,6 +36,7 @@ xxfk    信息反馈
 yxgl    运行管理
 
 ## 业务模块说明
+
 src路径下的api、assets/images、components、views中都有以 模块名称首字母英文命名 的文件或文件夹
 
 注:example相关文件、文件夹、变量皆为示例用途
@@ -55,20 +62,25 @@ views为路由视图文件夹,已创建各模块的父级路由;
 若有 新增/删除 子路由 的情况,需同步在router中进行更新。
 
 ## 通用文件说明
+
 public/static中,config文件夹下config.js用于定义全局变量文件夹,各模块需要使用的全局变量需在config对应的各模块下定义,用以区分避免混淆;
 
 ## 地图开发
-参考 views/example/Map.vue 
+
+参考 views/example/Map.vue
 
 ## 其他
+
 系统默认登录,登录请求在App.vue中,登录后用户信息、token存放在localStorage中,可使用 localStorage.getItem("token")获取;
 
 接口在请求时无论当前接口是否需要token,在请求头中都会添加token,配置在src/utils/request.js中
 
 若开发过程中哪有不妥之处可以跟我沟通,若创建分支开发,模块开发完成后请合并到主分支中
 
-# 更新
-## 0.0.1
+## 更新
+
+### 0.0.1
+
 地图开发引擎插件包引入代码集成到App.vue中
 
 并在App.vue的mounted函数中注册一个全局函数loadScripts
@@ -79,13 +91,14 @@ config.js中更新各模块引入插件包的数据组织方式
 
 相应修改可见 src/views/example/Map.vue 示例
 
-# 更新
-## 0.0.2
+### 0.0.2
+
 移除 xxfk 文件夹
 
-### 业务模块对应关系
+#### 更新后的业务模块对应关系
+
 sksjgl  时空数据管理
 skmh    时空门户
 wgn     微功能
 yygl    应用管理
-yxgl    运行管理
+yxgl    运行管理

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

@@ -3,7 +3,7 @@ let systemConfig = {
     defaultAccount: {
         username: "user_yztmh_dev",
     },
-    touristUserId: "191", //默认游客用户(user002)id,Oauth中配置
+    touristUserId: "191", //默认游客用户(user_yztmh_dev)id,Oauth中配置
     adminRoleId: "1", //默认管理员角色id,Oauth中配置“系统管理员”角色
     /*
          * 模型id如下
@@ -181,4 +181,248 @@ let systemConfig = {
     },
     yygl: {},
     yxgl: {},
+    examplelist:[
+        {
+            title:"基础能力",
+            data:[
+                {
+                    index:"1-1",
+                    tags: ["盈浦街道", "夏阳街道"],
+                    title: "一张图资源预览",
+                    text: "一张图资源聚焦于资源预览的高效性与便捷性核心需求,打造轻量化、高适配的单图资源快速预览解决方案,覆盖各类图片素材场景的预览诉求,旨在解决传统资源查看中加载繁琐、信息获取不直观、筛选效率低等问题。",
+                    picture: "./static/images/example/1-4.png",
+                    url:"http://10.235.245.174:2024?token=1"
+                }, {
+                    index:"1-2",
+                    tags: ["盈浦街道", "夏阳街道"],
+                    title: "一张图开发者中心",
+                    text: "一张图开发者中心是面向开发者打造的图片资源预览能力开放与集成服务平台,作为一张图资源预览产品的技术开放枢纽,聚焦图片快速预览核心能力的高效输出,为企业开发者、第三方开发团队及个人开发者提供标准化、轻量化、高适配的图片预览技术解决方案。",
+                    picture: "./static/images/example/1-2.png",
+                    url:"http://10.235.245.174:2103/?token=123456"
+                }, {
+                    index:"1-3",
+                    tags: ["盈浦街道、夏阳街道"],
+                    title: "一张图二三维引擎组件库",
+                    text: "一张图二三维引擎组件库是依托一张图技术体系打造的二三维一体化引擎能力演示与实践参考体系,聚焦图片资源在二三维可视化场景下的渲染、交互、融合应用,通过丰富的示例场景、可复用的代码模板、完整的能力演示。",
+                    picture: "./static/images/example/1-3.jpg",
+                    url:"http://10.235.245.174:2102/"
+                }, {
+                    index:"1-4",
+                    tags: ["盈浦街道、夏阳街道"],
+                    title: "二维GIS引擎",
+                    text:"工程师们正在建设中……",
+                    // text: "几何计算是对青浦区三维数字底板中的面要素(支持单个或多个)进行几何形态运算的功能,核心输出 “并集、交集、差集” 三类新的面要素,运算过程严格遵循矢量几何运算规则,确保新要素的拓扑一致性(如无重叠、无悬挂节点),可用于要素合并、重叠提取、范围裁剪等场景。",
+                    // picture: "./static/images/example/1-2.png",
+                    picture: "./static/images/example/item-white.png",
+                    url:""
+                }, {
+                    index:"1-5",
+                    tags: ["盈浦街道、夏阳街道"],
+                    title: "数字孪生引擎",
+                    text:"工程师们正在建设中……",
+                    // text: "空间量算是基于青浦区三维数字底板的基础数据源(如矢量数据、DEM 高程数据),计算空间要素几何参数的功能,核心输出 “距离、面积、高程” 三类关键指标,精度适配数字底板的坐标系统(SH2000 投影坐标系)与数据分辨率(如 DEM 数据精度为 5 米 ×5 米),可满足规划设计、工程施工、资源统计等场景的量算需求。",
+                    // picture: "./static/images/example/1-2.png",
+                    picture: "./static/images/example/item-white.png",
+                    url:""
+                }
+            ]
+        },
+        {
+            title:"统建应用",
+            data:[
+                {
+                    tags: ["盈浦街道", "夏阳街道"],
+                    title: "青浦区香花桥农业信息平台",
+                    text: "青浦区香花桥农业信息平台是街道立足本地稻米、林果、花卉等特色农业产业基础,以科技赋能农业现代化、数字化转型为核心,联动上海市农业科学院等科研院所打造的综合性农业智慧服务平台,是香花桥街道推进乡村振兴、落实 “智慧农业 + 产业融合” 发展战略的核心载体。",
+                    picture: "./static/images/example/2-1.jpg",
+                    url:"http://10.235.245.174:2030"
+                },
+                {
+                    tags: ["盈浦街道", "夏阳街道"],
+                    title: "学区查询",
+                    text: "学区查询是面向家长、教育管理部门、学校打造的义务教育阶段学区信息精准查询与管理服务体系,是破解传统学区查询 “信息滞后、流程繁琐、核实困难” 等问题的数字化便民举措,也是教育部门实现学区科学管理、教育资源均衡分配的重要数字化支撑,核心实现学区信息的权威发布、精准匹配与高效查询,保障入学相关主体的信息知情权与获取便利性。",
+                    picture: "./static/images/example/2-2.jpg",
+                    url:"http://121.43.55.7:2121/#/"
+                }, {
+                    tags: ["盈浦街道", "夏阳街道"],
+                    title: "科委产业地图",
+                    text: "科委产业地图是由科技主管部门主导打造的产业创新要素数字化整合与智能服务平台,作为区域科技创新与产业发展的 “数字仪表盘”,以破解产业 “底数不清、资源分散、匹配低效” 等痛点为核心,深度融合 GIS 地理信息、AI 大数据、可视化技术,整合产业链、创新链、人才链、服务链 “四链” 核心资源,构建全域产业发展全景画像",
+                    picture: "./static/images/example/2-3.jpg",
+                    url:"http://10.235.245.174:2032/#/"
+                },{
+                    tags: ["盈浦街道、夏阳街道"],
+                    title: "青浦区资环审计",
+                    text: "青浦区资源环境审计(简称 “青浦区资环审计”)是青浦区审计局围绕长三角生态绿色一体化发展等国家战略,以守护区域生态环境、规范资源利用、推动绿色发展为核心的审计监督工作,由资源环境审计科具体负责,在组织架构、审计重点、协作机制、实践成效等方面形成了鲜明特色。青浦区资环审计通过机制创新与精准监督,有效推动了区域生态保护与绿色发展,为长三角生态绿色一体化提供了坚实审计保障。",
+                    picture: "./static/images/example/2-4.jpg",
+                    url:"http://10.235.245.174:2025/"
+                },{
+                    tags: ["盈浦街道", "夏阳街道"],
+                    title: "开店一件事",
+                    text: "开店一件事是一套从前期调研规划到后期运营优化的系统性实操工作,核心是以市场需求为导向,完成合法筹备、资源落地与可持续经营,最终实现盈利和长期发展,核心逻辑是 “精准定位 + 合规落地 + 高效运营”。分析行业趋势、周边竞品,明确目标客群的消费能力和需求,找到自身差异化竞争优势,避免盲目入局。",
+                    picture: "./static/images/example/2-5.jpg",
+                    url:"https://aixq.shqp.gov.cn/kdyjs/"
+                },
+                {
+                    tags: ["盈浦街道", "夏阳街道"],
+                    title: "青浦区小区画像专题",
+                    text: "青浦区小区画像专题是立足区域 “幸福温暖家” 治理体系建设目标,依托区大数据资源平台与新版 “社区云” 基层治理底座打造的小区精细化数字刻画与智能赋能服务体系。作为青浦区全量信息视图在社区治理场景的深化应用,专题以破解小区管理 “底数不清、诉求分散、治理粗放” 等痛点为核心,通过整合多维度小区数据资源、构建标准化画像体系、赋能全场景治理应用,为基层治理、民生服务、城市更新等提供精准数据支撑,助力打造更具温度、更高效能的智慧社区生态。",
+                    picture: "./static/images/example/2-6.jpg",
+                    url:"http://10.235.245.174:2026/community/"
+                }
+            ]
+        },
+        {
+            title:"应用支撑",
+            data:[
+                // {
+                //     tags: ["盈浦街道", "夏阳街道"],
+                //     title: "青浦幸福云数字化看板",
+                //     text: "青浦区基层治理的 “最后一公里枢纽” 与 “民生服务前沿阵地”,村居 “一网统管” 深度融入区级城运体系,承接街镇平台调度指令,聚焦群众 “急难愁盼” 问题,构建 “党建引领、数据驱动、多元参与、闭环处置” 的精细化治理模式,破解村居事务繁杂、响应滞后、协同不足等治理痛点。",
+                //     picture: "./static/images/example/3-11.png",
+                //     url:"http://10.249.33.246:8016/screen/"
+                // }, 
+                {
+                    tags: ["盈浦街道", "夏阳街道"],
+                    title: "新兴领域党的组织体系全覆盖数字化看板",
+                    text: "新兴领域党的组织体系全覆盖数字化看板,是依托大数据、人工智能、地理信息等数字化技术,立足新经济组织、新社会组织、新就业群体等新兴领域党建工作特点,构建的集数据汇聚、全景展示、动态监测、智能预警、协同处置于一体的可视化管理平台。其核心目标是破解新兴领域党组织摸排难、覆盖散、管理弱、服务虚等痛点,以数字赋能推动党的组织体系和工作体系在新兴领域有形覆盖、有效覆盖,切实把新兴领域“最活跃地带”打造为“最坚强阵地”,为基层党建工作提质增效、赋能基层治理提供有力支撑。",
+                    picture: "./static/images/example/3-23.png",
+                    url:"http://10.235.246.71/screen/"
+                }, 
+                {
+                    tags: ["盈浦街道", "夏阳街道"],
+                    title: "赵巷镇环宝龙综合网格治理平台",
+                    text: "赵巷镇环宝龙综合网格治理平台是上海青浦区赵巷镇以党建引领、智慧赋能、多元共治为核心,依托 “一网统管” 打造的基层治理创新平台,聚焦宝龙片区商业多元、人员复杂的特点,破解 “三跨” 难题,形成 “问题发现 — 协同议事 — 联动处置 — 效果评估” 闭环,已获评上海市城运中心 2025 年优秀案例。以下从核心定位、架构机制、功能应用、治理模式与成效、发展方向展开概述。",
+                    picture: "./static/images/example/3-22.png",
+                    url:"http://10.235.234.99/grid/#/login"
+                }, 
+                {
+                    tags: ["盈浦街道", "夏阳街道"],
+                    title: "徐泾镇产业数智服务平台",
+                    text: "徐泾镇产业高质量发展的 “数智引擎” 与 “服务枢纽”,平台深度融入青浦区营商环境优化体系,承接区级 “一网通办”“一网统管” 协同要求,聚焦企业全生命周期需求,构建 “党建引领、数智赋能、全链覆盖、政企共赢” 的产业服务生态,破解企业办事流程繁琐、资源对接不畅、政策匹配不准等痛点。",
+                    picture: "./static/images/example/3-12.png",
+                    url:"http://demo.metamaker.cn/xujing-gis-blank/#/"
+                }, 
+                {
+                    tags: ["盈浦街道、夏阳街道"],
+                    title: "青浦区全量信息视图",
+                    text: "青浦区全量信息视图是立足区域数字化转型与城市治理现代化需求打造的全域数据融合可视化智慧管理平台,作为青浦区 “一网通办”“一网统管” 建设的核心数字底座,深度整合全区跨部门、跨领域全量数据资源,构建起 “一屏观全域、一网管全城” 的智慧化管理体系,为区域政务服务、城市治理、产业发展、民生保障等全场景提供全景化数据支撑与科学决策依据。",
+                    picture: "./static/images/example/3-3.jpg",
+                    url:"http://10.235.245.84:9099/eleOverview/eleOverview?loginToken=21232f297a57a5a743894a0e4a801fc3"
+                }, 
+                {
+                    tags: ["盈浦街道、夏阳街道"],
+                    title: "一网统管业务智能协同平台",
+                    text: "一网统管业务智能协同平台是城市运行 “一网统管” 体系的核心中枢,以 “数据融合、智能分拨、联动处置、闭环评价” 为核心,打通跨部门数据与业务壁垒,实现城市事件 “一网受理、一体派单、联动处置、一屏总览”,支撑 “高效处置一件事”,推动治理从 “各自为战” 向 “协同共治”、从 “被动响应” 向 “主动预警” 转型,是超大城市精细化治理的核心技术与业务载体。以下从核心定位、技术架构、治理机制、核心功能、实施成效与发展方向展开概述。",
+                    picture: "./static/images/example/3-1.png",
+                    url:"http://10.235.234.131/vue-dispatch/login?redirect=dashboard"
+                },
+                {
+                    tags: ["盈浦街道", "夏阳街道"],
+                    title: "城市体征3.0",
+                    text: "城市体征是对城市运行状态、发展特征、功能表现的系统性量化与质性描述,类比人体生理体征(如心率、血压、体温),将城市视为有机整体,通过多维度指标、数据和现象,反映其在经济、社会、空间、生态、治理等方面的实时状态、发展趋势、健康程度及问题短板,是城市精细化管理、科学规划决策、可持续发展的核心依据。",
+                    picture: "./static/images/example/3-2.jpg",
+                    url:"http://10.249.33.189:81/cockpit/"
+                },
+                {
+                    tags: ["盈浦街道", "夏阳街道"],
+                    title: "青浦区统一地址管理平台",
+                    text: "青浦区统一地址管理平台是立足区域数字化转型战略、紧扣 “一网通办”“一网统管” 建设要求打造的全域地址标准化管理与数据融合支撑平台,作为青浦区空间地理信息数字化的核心基础设施,以破解地址管理 “多库并存、标准不一、关联困难” 等痛点为目标。",
+                    picture: "./static/images/example/3-4.jpg",
+                    url:"https://10.235.251.4:2008/geoAM/?accessToken=66e1605cb81047d4803368972c5a64e3#/"
+                },
+                {
+                    tags: ["盈浦街道", "夏阳街道"],
+                    title: "青浦区城市运行管理平台",
+                    text: "青浦区城市运行管理平台是上海 “一网统管” 体系在青浦的本地化落地载体,以 “三级平台、五级应用” 为架构,以 “数据驱动、智能协同、高效处置” 为核心,覆盖 “一屏观全城、一网管全域、一体抓落实”,支撑跨部门、跨层级、跨场景的城市治理与应急响应,是青浦数字化治理的核心中枢,也是服务进博会、防汛抗台等重大任务的关键保障。以下从核心定位、技术架构、核心功能、治理机制、实施成效与发展方向展开概述。",
+                    picture: "./static/images/example/3-5.jpg",
+                    url:"http://10.235.234.98/#/index"
+                },
+                // {
+                //   tags: ["盈浦街道", "夏阳街道"],
+                //   title: "赵巷镇城市运行管理平台",
+                //   text: "赵巷镇城市运行管理平台是上海青浦区赵巷镇落实 “一网统管” 建设的核心载体,以镇城运中心为枢纽,融合 AI、大数据、物联网等技术,构建 “一屏观全域、一网管全城” 的精细化治理体系,实现城市运行态势实时感知、联勤联动高效处置与治理流程闭环管理。",
+                //   picture: "./static/images/example/3-6.jpg",
+                //   url:"http://10.235.234.99/grid/#/login"
+                // }, 
+                 
+                {
+                    tags: ["盈浦街道", "夏阳街道"],
+                    title: "青浦区渣土管理平台",
+                    text: "青浦区渣土治理的 “数字监管中枢” 与 “全链条协同枢纽”,平台深度融入区级城运 “一网统管” 体系,承接上海市建筑垃圾监管标准,聚焦工程渣土、装修垃圾等全品类处置环节,构建 “源头可溯、运输可控、消纳可查、执法可依” 的数字化闭环管理体系,破解非法排放、“黑车” 运营、跨域倾倒等行业痛点。",
+                    picture: "./static/images/example/3-8.jpg",
+                    url:"http://10.235.80.66:8082/#/index"
+                },   
+                {
+                    tags: ["盈浦街道", "夏阳街道"],
+                    title: "华新产业资源全生命周期管理平台",
+                    text: "华新产业资源全生命周期管理平台是上海市青浦区华新镇为优化营商环境、防控产业风险、提升资源配置效率打造的数字化治理中枢,以 “全周期覆盖、全要素协同、全流程闭环” 为核心,打通招商、准入、监管、服务、退出各环节,形成 “数据驱动 + 风险防控 + 精准服务” 的产业治理模式,支撑楼宇经济与园区高质量发展,是华新镇 “通达华新・易企行” 营商服务体系的核心载体。以下从核心定位、建设背景、技术架构、关键功能、实施成效与发展方向展开概述。",
+                    picture: "./static/images/example/3-10.jpg",
+                    url:"http://3ddataanalytics.huaxinsz.cn:8787/#/login"
+                }, 
+                {
+                    tags: ["盈浦街道", "夏阳街道"],
+                    title: "赵巷大居环卫一体化管理平台",
+                    text: "赵巷大居环卫一体化管理平台是青浦区 “一网统管” 在赵巷新城一站大居的环卫专属落地载体,以 “全流程闭环、智能协同、精细监管” 为核心,整合垃圾收运、道路保洁、水域保洁、绿化管养等业务,通过物联网、AI、GIS 等技术打通人、车、物、事全链条,实现环卫作业从 “被动应对” 到 “主动管控”、从 “各自为战” 到 “一体协同” 的转型,是大型居住区环卫精细化治理的标杆案例。以下从核心定位、技术架构、核心功能、治理机制、实施成效与发展方向展开概述。",
+                    picture: "./static/images/example/3-13.png",
+                    url:"http://222.71.55.194:3510/bigscreen"
+                },
+                {
+                    tags: ["盈浦街道", "夏阳街道"],
+                    title: "水务一张图二期平台",
+                    text: "基于水务行业 “一网统管” 分级建设逻辑与 “平台 + 应用” 核心模式,水务一张图二期平台作为连接市级(一级)统筹平台与基层水务治理单元的关键枢纽,聚焦区域化水务管理实战需求,实现数据汇聚、业务协同与精准处置的闭环运作。以下从核心定位、架构设计、核心功能、技术支撑、应用价值等方面进行详细介绍。",
+                    picture: "./static/images/example/3-14.jpg",
+                    url:"http://221.181.88.134:9999/qp-swyth-web-v2/login"
+                },  
+                {
+                    tags: ["盈浦街道", "夏阳街道"],
+                    title: "长三角一体化无人机监管平台",
+                    text: "长三角低空经济协同发展的 “安全中枢” 与 “服务枢纽”,平台打破省市行政壁垒与空域管理碎片化格局,承接国家低空管理政策标准,整合苏浙皖沪四地无人机飞行数据、空域资源、监管力量,构建 “统一标准、跨域协同、智能高效” 的低空飞行治理体系,实现 “一网管低空、一屏观全域” 的跨区域监管闭环。",
+                    picture: "./static/images/example/3-15.jpg",
+                    url:"http://10.235.220.134:8889/#/index"
+                },
+                // {
+                //     tags: ["盈浦街道", "夏阳街道"],
+                //     title: "青浦区城市运行管理平台",
+                //     text: "青浦城市治理的 “数字大脑” 与 “指挥中枢”,平台立足长三角生态绿色一体化发展示范区定位,承接上海市 “一网统管” 建设要求,整合全域治理资源、打通部门壁垒,构建 “一屏观全域、一网管全城” 的精细化治理体系,实现城市运行态势实时感知、联勤联动高效处置与治理流程闭环管理。",
+                //     picture: "./static/images/example/3-16.png",
+                //     url:"http://10.235.234.98/#/login"
+                // },
+                {
+                    tags: ["盈浦街道", "夏阳街道"],
+                    title: "夏阳街道青湖路智慧化管理",
+                    text: "夏阳街道青湖路智慧化管理,是上海青浦区夏阳街道依托 “一网统管” 与 “智・夏阳” 城运平台打造的智慧街区标杆,以 “四位一体感知网络 + 闭环治理 + 多元共治” 为核心,聚焦交通、安全、环境等治理痛点,实现从 “人海战术” 到 “精准智理” 的转型,成为超大城市街区智慧化管理的典型实践。以下从核心定位、技术支撑、治理机制、核心应用、实施成效与发展方向展开概述。",
+                    picture: "./static/images/example/3-17.png",
+                    url:"http://10.235.234.10:8001/#/"
+                },  
+                {
+                    tags: ["盈浦街道", "夏阳街道"],
+                    title: "青浦农业农村信息共享平台",
+                    text: "青浦农业农村信息共享平台是上海市青浦区农业农村委牵头打造的区级农业农村数据与服务中枢,以 “数据整合、业务协同、服务下沉、决策赋能” 为核心,依托 “农业农村一张图 2.0” 与 APP,打通数据壁垒、覆盖生产 / 监管 / 服务 / 治理全链条,已完成二期建设并上线运行,为乡村振兴与农业现代化提供数字底座。以下从核心定位、建设背景、核心架构、关键功能、实施成效与发展方向展开概述。",
+                    picture: "./static/images/example/3-18.jpg",
+                    url:"https://10.235.251.4:2027/"
+                },
+                {
+                    tags: ["盈浦街道", "夏阳街道"],
+                    title: "青浦区清明(冬至)工作指挥平台",
+                    text: "青浦区清明(冬至)工作指挥平台是区城运中心与民政局在 “一网统管” 体系下共建的祭扫保障专用指挥中枢,以 “一屏观全、三级联动、精准管控、闭环处置” 为核心,聚焦 8 家经营性公墓及周边区域,通过数据整合、智能感知与协同调度,破解祭扫高峰人流车流管控难、安全隐患多、处置效率低等痛点,成为上海殡葬祭扫智慧保障的标杆平台。以下从核心定位、技术架构、治理机制、核心应用、实施成效与发展方向。",
+                    picture: "./static/images/example/3-19.jpg",
+                    url:"http://10.235.234.10:8008/#/index"
+                },
+                // {
+                //     tags: ["盈浦街道", "夏阳街道"],
+                //     title: "智慧环卫管理系统",
+                //     text: "智慧环卫管理系统是依托物联网、大数据、AI、GIS 等技术,对环卫作业的人、车、物、事全流程数字化管控的平台,核心是 “数据驱动、智能协同、精细监管、降本增效”,推动环卫从 “被动应对” 转向 “主动预判”、从 “粗放管理” 走向 “精细治理”,是智慧城市与 “一网统管” 在环卫领域的关键落地载体。以下从核心定位、技术架构、核心功能、应用价值、实施要点与发展方向展开概述。",
+                //     picture: "./static/images/example/3-20.png",
+                //     url:"http://10.90.11.155:9608/#/"
+                // },
+                {
+                    tags: ["盈浦街道", "夏阳街道"],
+                    title: "青浦区消防救援支队一网统管",
+                    text: "青浦区消防安全治理的 “数字大脑” 与 “应急中枢”,平台深度融入区级城运 “一网统管” 体系,承接上海市消防救援局物联网联网标准与安全韧性城市建设要求,聚焦火灾预防、应急救援、隐患治理全链条,构建 “感知全面、预警精准、处置高效、协同闭环” 的数字化消防治理体系,破解高层建筑、人员密集场所、乡村聚落等场景火灾防控难题。",
+                    picture: "./static/images/example/3-21.jpg",
+                    url:"http://10.249.32.183:9608/#/"
+                },  
+            ]
+        }
+    ]
 };

BIN
public/static/font/DIN-Bold/din-bold-2.ttf


BIN
public/static/images/example/1-1.png


BIN
public/static/images/example/1-2.png


BIN
public/static/images/example/1-3.jpg


BIN
public/static/images/example/1-4.png


BIN
public/static/images/example/2-1.jpg


BIN
public/static/images/example/2-2.jpg


BIN
public/static/images/example/2-3.jpg


BIN
public/static/images/example/2-4.jpg


BIN
public/static/images/example/2-5.jpg


BIN
public/static/images/example/2-6.jpg


BIN
public/static/images/example/3-1.png


BIN
public/static/images/example/3-10.jpg


BIN
public/static/images/example/3-11.jpg


BIN
public/static/images/example/3-12.png


BIN
public/static/images/example/3-13.png


BIN
public/static/images/example/3-14.jpg


BIN
public/static/images/example/3-15.jpg


BIN
public/static/images/example/3-16.png


BIN
public/static/images/example/3-17.png


BIN
public/static/images/example/3-18.jpg


BIN
public/static/images/example/3-19.jpg


BIN
public/static/images/example/3-2.jpg


BIN
public/static/images/example/3-20.png


BIN
public/static/images/example/3-21.jpg


BIN
public/static/images/example/3-22.png


BIN
public/static/images/example/3-23.png


BIN
public/static/images/example/3-3.jpg


BIN
public/static/images/example/3-4.jpg


BIN
public/static/images/example/3-5.jpg


BIN
public/static/images/example/3-6.jpg


BIN
public/static/images/example/3-7.jpg


BIN
public/static/images/example/3-8.jpg


BIN
public/static/images/example/3-9.jpg


BIN
public/static/images/example/def.png


BIN
public/static/images/example/item-black.png


BIN
public/static/images/example/item-white.png


BIN
public/static/images/example/item.webp


BIN
public/static/images/home/bg-1.png


BIN
public/static/images/home/bg-2.png


BIN
public/static/images/home/bg-3.png


BIN
public/static/images/home/bg-4.png


BIN
public/static/images/home/bg.png


BIN
public/static/images/logo.png


BIN
public/static/images/sjgl/bg.png


BIN
public/static/images/skmh/bg.png


BIN
public/static/images/wgn/bg.png


BIN
public/static/images/yyzx/bg.png


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


+ 23 - 17
src/api/rwgl.js

@@ -1,12 +1,14 @@
 import {
-    postform
+    postform,
+    post
 } from '../utils/request'
 import content from './content'
 
 
 const dmsPath = systemConfig.dmsDataProxy
 const multiSearch = dmsPath + "/content/multipleFormsOfJointInvestigation"
-const taskSearch = systemConfig.baseServicerPath+"/task/getTask"
+const taskSearch = systemConfig.baseServicerPath + "/task/getTask"
+const taskExecute = "/oneMap/task/execute"
 
 const taskDmsId = systemConfig.columnIds[6]
 
@@ -17,26 +19,26 @@ export function getCName(cName) {
     }))
 }
 
-export function getTasks(page, pageSize, name, status,type) {
+export function getTasks(page, pageSize, name, status, type) {
     let data = {
         "columnId": taskDmsId,
         "autoSelectItem": true,
         "page": page,
         "pageSize": pageSize,
         "columnAlias": "main",
-        "orderBy":"main,c_start_time,desc",
+        "orderBy": "main,c_start_time,desc",
         "conditionsList": JSON.stringify([
-            ...getEqualChecker(name,"c_name"),
-            ...getTypeChecker(status,"c_state"),
-            ...getTypeChecker(type,"c_type"),
+            ...getEqualChecker(name, "c_name"),
+            ...getTypeChecker(status, "c_state"),
+            ...getTypeChecker(type, "c_type"),
         ]),
     }
 
     return resolveDmsMultiTableResult(postform(taskSearch, data));
 }
 
-function getEqualChecker(value,param) {
-    if (value == null||value=="") {
+function getEqualChecker(value, param) {
+    if (value == null || value == "") {
         return []
     }
     return [{
@@ -46,22 +48,22 @@ function getEqualChecker(value,param) {
         "value": `%${value}%`
     }]
 }
-function getTypeChecker(value,param) {
-    
+function getTypeChecker(value, param) {
+
     if (value == null || value.length == 0) {
         return []
     }
     let output = []
     for (let i = 0; i < value.length; i++) {
         const e = value[i];
-        output.push(e+"")
+        output.push(e + "")
     }
     return [{
-            "columnId": "main",
-            "columnName": param,
-            "condition": "in",
-            "value": output
-        }]
+        "columnId": "main",
+        "columnName": param,
+        "condition": "in",
+        "value": output
+    }]
 }
 
 async function resolveResult(result) {
@@ -82,4 +84,8 @@ async function resolveDmsMultiTableResult(result) {
     } else {
         return null;
     }
+}
+
+export function executeTask(taskId) {
+    return post(taskExecute, { taskId });
 }

BIN
src/assets/images/common/example/1-1.png


BIN
src/assets/images/common/example/1-2.png


BIN
src/assets/images/common/example/1-3.jpg


BIN
src/assets/images/common/example/2-1.jpg


BIN
src/assets/images/common/example/2-2.jpg


BIN
src/assets/images/common/example/2-3.jpg


BIN
src/assets/images/common/example/2-4.jpg


BIN
src/assets/images/common/example/2-5.jpg


BIN
src/assets/images/common/example/2-6.jpg


BIN
src/assets/images/common/example/3-1.png


BIN
src/assets/images/common/example/3-10.jpg


BIN
src/assets/images/common/example/3-2.jpg


BIN
src/assets/images/common/example/3-3.jpg


BIN
src/assets/images/common/example/3-4.jpg


BIN
src/assets/images/common/example/3-5.jpg


BIN
src/assets/images/common/example/3-6.jpg


BIN
src/assets/images/common/example/3-7.jpg


BIN
src/assets/images/common/example/3-8.jpg


BIN
src/assets/images/common/example/3-9.jpg


BIN
src/assets/images/common/gn/1.png


BIN
src/assets/images/common/gn/2.png


BIN
src/assets/images/common/gn/3.png


BIN
src/assets/images/common/gn/4.png


BIN
src/assets/images/common/gn/5.png


BIN
src/assets/images/common/gn/6.png


+ 1 - 1
src/components/AppVue/Footer.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="footer">Copyright@2025 青浦区一张图 主办单位:青浦区政务服务中心</div>
+  <div class="footer">Copyright © 2026青浦区“一张图”区级节点 主办单位:青浦区政务服务中心</div>
 </template>
 
 <script>

+ 41 - 15
src/components/AppVue/Header.vue

@@ -1,6 +1,9 @@
 <template>
   <div id="header">
-    <div class="logo">青浦一张图</div>
+    <div class="logo">
+      <img src="/static/images/logo.png" style="width: 24px;height: 24px;vertical-align: middle;" alt="" />
+      青浦区“一张图”区级节点
+    </div>
     <div class="userdropdown">
       <User />
     </div>
@@ -42,43 +45,66 @@ export default {
 </script>
 
 <style lang="less" scoped>
+#header::after {
+  content: '';
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  width: 100%;
+  height: 1px; /* 边框厚度 */
+  background-image: linear-gradient(to right, #071b3c, #71a5d4, #071b3c);
+}
 #header {
   width: 100vw;
-  height: 70px;
+  height: 44px;
   background: linear-gradient(180deg, #2c2f74, #494d98);
   color: #ffffff;
   margin: 0 auto;
+  position: absolute;
+  background: #00215387;
+  z-index: 999;
   .logo {
     display: inline-block;
-    height: 70px;
-    width: 200px;
+    height: 44px;
+    // width: 200px;
+    // padding: 0 20px;
+    padding: 0 20px 0px 20px;
     text-align: center;
-    line-height: 70px;
-    font-size: 24px;
+    line-height: 44px;
+    font-size: 18px;
+    font-weight: bold;
   }
 
   .menu {
-    display: inline-block;
     float: right;
     .menu_ul {
       li {
         display: inline-block;
-        height: 50px;
+        height: 24px;
         width: fit-content;
-        line-height: 50px;
+        line-height: 24px;
         text-align: center;
         cursor: pointer;
-        margin: 10px 20px;
-        font-size: 20px;
-        font-weight: bold;
+        // margin: 10px 20px;
+        padding: 10px 20px;
+        font-size: 16px;
+        // font-weight: bold;
       }
 
       li:hover {
-        color: #00bbff;
+        // color: #00bbff;
+        color: #fff;
+        font-weight: bold;
+        border-radius: 4px;
+        background: linear-gradient(97deg, #1586FF 12%, #0E5AF4 90%);
       }
 
       li.active {
-        color: #00bbff;
+        // color: #00bbff;
+        color: #fff;
+        font-weight: bold;
+        border-radius: 4px;
+        background: linear-gradient(97deg, #1586FF 12%, #0E5AF4 90%);
       }
     }
   }
@@ -88,7 +114,7 @@ export default {
   width: 150px;
   display: flex;
   align-items: center;
-  height: 70px;
+  height: 44px;
   justify-content: center;
   cursor: pointer;
   border: 0;

+ 26 - 22
src/components/AppVue/digitalScrollersComp.vue

@@ -1,18 +1,21 @@
 <template>
   <div class="count-flop" :key="compKey">
     <!--  -->
-    <div
-      :class="item !== '.' ? 'count-flop-box' : 'count-flop-point'"
-      v-for="(item, index) in value"
-      :key="index"
-    >
-      <div v-if="item !== '.'" class="count-flop-content" :class="['rolling_' + item]">
-        <div v-for="(item2, index2) in numberList" :key="index2" class="count-flop-num">
-          {{ item2 }}
+    
+      <div
+        :class="item !== ',' ? 'count-flop-box' : 'count-flop-point'"
+        v-for="(item, index) in value"
+        :key="index"
+      >
+        <div>
+        <div v-if="item !== ','" class="count-flop-content" :class="['rolling_' + item]">
+          <div v-for="(item2, index2) in numberList" :key="index2" class="count-flop-num">
+            {{ item2 }}
+          </div>
+        </div>
+        <div v-else class="count-flop-content">,</div>
         </div>
       </div>
-      <div v-else class="count-flop-content">.</div>
-    </div>
     <!--  -->
     <div v-if="suffix" class="count-flop-unit">{{ suffix }}</div>
   </div>
@@ -53,8 +56,8 @@ watch(
   display: inline-block;
   font-size: 0;
   /* 可更改 */
-  height: 100px;
-  line-height: 100px;
+  height: 80px;
+  line-height: 80px;
   font-size: 50px;
   font-weight: 700;
   color: #ffffff;
@@ -70,22 +73,23 @@ watch(
 .count-flop-box {
   /* 可更改 */
   margin-right: 5px;
-  width: 86px;
+  width: 60px;
   color: #ffffff;
-  background-color: rgba(6, 41, 78, 0.7);
+  /* background-color: rgba(6, 41, 78, 0.7); */
   border: 1px solid #2663a5;
   /* box-shadow: 0 2px 5px #2663a5; */
-  /*
-  这里的高度要比上面height的少2px
-  */
-  line-height: 98px;
-  border-radius: 6px;
-}
- 
+  /* line-height: 98px; */
+  border: 2px solid transparent;
+  border-radius: 8px;
+  background-clip: padding-box, border-box;
+  background-origin: padding-box, border-box;
+  background-image: linear-gradient(128deg, #00002d, #2220), linear-gradient(136deg, #e5e5e5de, #00000000, #00000000, #00000000);
+}
+
 .count-flop-point {
   /* 可更改 */
   margin-right: 5px;
-  width: 10px;
+  width: 15px;
 }
  
 .count-flop-content {

+ 22 - 18
src/components/AppVue/numberScroll.vue

@@ -3,35 +3,39 @@
 </template>
 
 <script setup>
-import { ref, watch, onMounted } from 'vue'
+import { ref, watch, onMounted } from "vue";
 
 const props = defineProps({
   value: { type: Number, default: 0 },
   duration: { type: Number, default: 1500 },
-  easing: { type: Function, default: (t) => t * (2 - t) }
-})
+  easing: { type: Function, default: (t) => t * (2 - t) },
+});
 
-const displayValue = ref(0)
-const numberEl = ref(null)
+const displayValue = ref(0);
+const numberEl = ref(null);
 
 function animate(start, end) {
-  const startTime = performance.now()
+  const startTime = performance.now();
   const frame = (currentTime) => {
-    const elapsed = currentTime - startTime
-    const progress = Math.min(elapsed / props.duration, 1)
-    displayValue.value = Math.floor(start + (end - start) * props.easing(progress))
+    const elapsed = currentTime - startTime;
+    const progress = Math.min(elapsed / props.duration, 1);
+    displayValue.value = Math.floor(start + (end - start) * props.easing(progress));
+    displayValue.value = displayValue.value.toLocaleString();
     if (progress < 1) {
-      requestAnimationFrame(frame)
+      requestAnimationFrame(frame);
     }
-  }
-  requestAnimationFrame(frame)
+  };
+  requestAnimationFrame(frame);
 }
 
-watch(() => props.value, (newVal, oldVal) => {
-  animate(oldVal, newVal)
-})
+watch(
+  () => props.value,
+  (newVal, oldVal) => {
+    animate(oldVal, newVal);
+  }
+);
 
 onMounted(() => {
-  animate(0, props.value)
-})
-</script>
+  animate(0, props.value);
+});
+</script>

+ 1 - 0
src/components/user/user.vue

@@ -139,6 +139,7 @@ export default {
     .container{
         padding: 0;
         margin: 0;
+        position: relative;
     }
     .el-dropdown-link {
         cursor: pointer;

+ 583 - 17
src/components/wgn/controlPanel.vue

@@ -115,12 +115,21 @@
             <div class="vueJsonEditor_tools">
               <span
                 v-if="jsonData && (jsonData.features || jsonData.geometry)"
-                @click="showToMap(jsonData)"
+                @click="showToMap(jsonData, 'input')"
                 >渲染到地图中</span
               >
+              <el-tooltip content="定位到当前入参渲染要素" placement="top">
+                <span
+                  v-if="renderStatus.input"
+                  @click="locateRenderedGeojson('input')"
+                >
+                  定位
+                </span>
+              </el-tooltip>
               <span @click="copyJsonData(jsonData)">copy</span>
             </div>
             <vue-json-editor
+              :key="'json-input-editor-' + inputEditorKey"
               v-model="jsonData"
               :value="jsonData"
               :show-btns="false"
@@ -151,13 +160,22 @@
                   backData.content &&
                   (backData.content.features || backData.content.geometry)
                 "
-                @click="showToMap(backData.content)"
+                @click="showToMap(backData.content, 'output')"
                 >渲染到地图中</span
               >
+              <el-tooltip content="定位到当前返回渲染要素" placement="top">
+                <span
+                  v-if="renderStatus.output"
+                  @click="locateRenderedGeojson('output')"
+                >
+                  定位
+                </span>
+              </el-tooltip>
               <span @click="copyJsonData(backData.content)">copy</span>
             </div>
             <vue-json-editor
               v-if="backData.content"
+              :key="'json-output-editor-' + outputEditorKey"
               v-model="backData.content"
               :value="backData.content"
               @json-change="handleJsonChange2"
@@ -169,6 +187,56 @@
         ></el-tab-pane>
       </el-tabs>
     </div>
+    <el-dialog
+      v-model="propertyDialog.visible"
+      title="要素属性"
+      width="420px"
+      draggable
+      :modal="false"
+      append-to-body
+      class="feature-property-dialog"
+    >
+      <div class="feature-property-content">
+        <div class="feature-property-tip">支持直接编辑属性值,失焦后自动同步 JSON。</div>
+        <div
+          class="feature-property-item"
+          v-for="item in propertyDialog.list"
+          :key="'feature-property-' + item.id"
+        >
+          <div class="feature-property-row">
+            <el-input
+              v-model="item.editKey"
+              class="feature-property-input feature-property-key-input"
+              placeholder="属性名"
+              @change="handlePropertyKeyChange(item)"
+            />
+            <el-button
+              type="danger"
+              plain
+              size="small"
+              class="feature-property-delete-btn"
+              @click="deleteProperty(item)"
+            >
+              删除
+            </el-button>
+          </div>
+          <el-input
+            v-model="item.editValue"
+            class="feature-property-input"
+            placeholder="属性值"
+            @change="handlePropertyValueChange(item)"
+          />
+        </div>
+        <el-empty
+          v-if="!propertyDialog.list.length"
+          description="当前要素无属性信息"
+          :image-size="80"
+        />
+      </div>
+      <template #footer>
+        <el-button type="primary" plain @click="addProperty">+ 新增属性</el-button>
+      </template>
+    </el-dialog>
     <!-- 绘制工具栏 -->
     <div
       class="toolbar"
@@ -511,6 +579,29 @@ export default {
       currentPolygonEntity: null, // 当前要添加镂空的多边形实体
       currentPolygonGeometry: null, // 当前要添加镂空的多边形几何对象
       tempEntity: null, // 临时预览实体
+      // 地图渲染状态(入参/返回)
+      renderStatus: {
+        input: false,
+        output: false,
+      },
+      // 缓存两侧最近一次成功渲染的geojson,用于定位时恢复
+      renderedGeojsonCache: {
+        input: null,
+        output: null,
+      },
+      currentRenderedSource: "",
+      // 地图点击属性弹窗
+      featurePickHandler: null,
+      inputEditorKey: 0,
+      outputEditorKey: 0,
+      propertyIdSeed: 1,
+      propertyDialog: {
+        visible: false,
+        list: [],
+        source: "",
+        propertiesRef: null,
+        featureIndex: -1,
+      },
     };
   },
   mounted() {
@@ -523,6 +614,10 @@ export default {
     if (this.handler) {
       this.handler.destroy();
     }
+    if (this.featurePickHandler) {
+      this.featurePickHandler.destroy();
+      this.featurePickHandler = null;
+    }
   },
   watch: {
     SceneValue(newVal, oldVal) {
@@ -596,30 +691,346 @@ export default {
           });
       }
     },
+    getSourceGeojsonData(source) {
+      return source === "output" ? this.backData.content : this.jsonData;
+    },
     // 将用户输入或后台返回的geojson渲染到地图中
-    showToMap(geojson) {
+    showToMap(geojson, source = "input") {
+      if (!geojson || (!geojson.features && !geojson.geometry)) {
+        this.$message({
+          message: "当前JSON缺少有效几何信息,无法渲染",
+          type: "warning",
+        });
+        return;
+      }
+      this.currentRenderedSource = source;
       // 1. 清除所有地图中的元素
       this.clearAllMap();
       // 2. 将geojson添加到地图中
       this.addToMap(geojson);
+      this.currentRenderedSource = source;
+      this.renderStatus[source] = true;
+      // 仅缓存纯数据,避免响应式对象带来的引用副作用
+      this.renderedGeojsonCache[source] = JSON.parse(JSON.stringify(geojson));
+      this.flyToGeojson(geojson);
+    },
+    // 定位到已渲染要素
+    locateRenderedGeojson(source) {
+      if (!this.renderStatus[source]) {
+        return;
+      }
+      // 当前地图不是该来源数据时,优先恢复对应渲染结果,再飞行定位
+      if (this.currentRenderedSource !== source && this.renderedGeojsonCache[source]) {
+        this.showToMap(this.renderedGeojsonCache[source], source);
+        return;
+      }
+      const sourceGeojson = this.getSourceGeojsonData(source) || this.renderedGeojsonCache[source];
+      this.flyToGeojson(sourceGeojson);
+    },
+    collectGeometryCoordinates(geometry) {
+      if (!geometry || !geometry.coordinates) {
+        return [];
+      }
+      const { type, coordinates } = geometry;
+      const points = [];
+      if (type === "Point") {
+        points.push([coordinates[0], coordinates[1]]);
+      } else if (type === "LineString") {
+        coordinates.forEach((coord) => points.push([coord[0], coord[1]]));
+      } else if (type === "Polygon") {
+        coordinates.forEach((ring) => {
+          ring.forEach((coord) => points.push([coord[0], coord[1]]));
+        });
+      } else if (type === "MultiPolygon") {
+        coordinates.forEach((polygon) => {
+          polygon.forEach((ring) => {
+            ring.forEach((coord) => points.push([coord[0], coord[1]]));
+          });
+        });
+      }
+      return points;
+    },
+    collectGeojsonCoordinates(geojson) {
+      if (!geojson) {
+        return [];
+      }
+      if (geojson.features && Array.isArray(geojson.features)) {
+        return geojson.features.flatMap((feature) =>
+          this.collectGeometryCoordinates(feature.geometry)
+        );
+      }
+      if (geojson.geometry) {
+        return this.collectGeometryCoordinates(geojson.geometry);
+      }
+      return [];
+    },
+    // 飞行定位到geojson范围
+    flyToGeojson(geojson) {
+      if (!viewer || !geojson) {
+        return;
+      }
+      const points = this.collectGeojsonCoordinates(geojson);
+      if (!points.length) {
+        return;
+      }
+      if (points.length === 1) {
+        viewer.camera.flyTo({
+          destination: SkyScenery.Cartesian3.fromDegrees(points[0][0], points[0][1], 1200),
+          duration: 1.1,
+          orientation: {
+            heading: viewer.camera.heading,
+            pitch: SkyScenery.Math.toRadians(-65),
+            roll: 0,
+          },
+        });
+        viewer.scene.requestRender();
+        return;
+      }
+      let minLon = Infinity;
+      let maxLon = -Infinity;
+      let minLat = Infinity;
+      let maxLat = -Infinity;
+      points.forEach((point) => {
+        minLon = Math.min(minLon, point[0]);
+        maxLon = Math.max(maxLon, point[0]);
+        minLat = Math.min(minLat, point[1]);
+        maxLat = Math.max(maxLat, point[1]);
+      });
+      const lonPad = Math.max((maxLon - minLon) * 0.25, 0.0008);
+      const latPad = Math.max((maxLat - minLat) * 0.25, 0.0008);
+      viewer.camera.flyTo({
+        destination: SkyScenery.Rectangle.fromDegrees(
+          minLon - lonPad,
+          minLat - latPad,
+          maxLon + lonPad,
+          maxLat + latPad
+        ),
+        duration: 1.1,
+      });
+      viewer.scene.requestRender();
+    },
+    // 把属性对象格式化为可编辑列表
+    formatFeatureProperties(properties) {
+      if (!properties || typeof properties !== "object") {
+        return [];
+      }
+      return Object.keys(properties).map((key) => {
+        const rawValue = properties[key];
+        const editValue =
+          rawValue === null || rawValue === undefined
+            ? ""
+            : typeof rawValue === "object"
+            ? JSON.stringify(rawValue)
+            : String(rawValue);
+        return {
+          id: this.propertyIdSeed++,
+          originalKey: key,
+          editKey: key,
+          editValue,
+        };
+      });
+    },
+    parsePropertyValue(inputValue) {
+      if (typeof inputValue !== "string") {
+        return inputValue;
+      }
+      const value = inputValue.trim();
+      if (value === "") {
+        return "";
+      }
+      if (value === "true") {
+        return true;
+      }
+      if (value === "false") {
+        return false;
+      }
+      if (value === "null") {
+        return null;
+      }
+      if (!isNaN(Number(value))) {
+        return Number(value);
+      }
+      if ((value.startsWith("{") && value.endsWith("}")) || (value.startsWith("[") && value.endsWith("]"))) {
+        try {
+          return JSON.parse(value);
+        } catch (e) {
+          return inputValue;
+        }
+      }
+      return inputValue;
+    },
+    syncJsonEditorData(source) {
+      if (source === "output") {
+        if (!this.backData.content) {
+          return;
+        }
+        this.backData = {
+          ...this.backData,
+          content: JSON.parse(JSON.stringify(this.backData.content)),
+        };
+      } else {
+        this.jsonData = JSON.parse(JSON.stringify(this.jsonData));
+      }
+      if (source === "output") {
+        this.outputEditorKey += 1;
+      } else {
+        this.inputEditorKey += 1;
+      }
+      this.renderedGeojsonCache[source] = JSON.parse(
+        JSON.stringify(this.getSourceGeojsonData(source))
+      );
+      const latestGeojson = this.getSourceGeojsonData(source);
+      if (
+        latestGeojson &&
+        this.propertyDialog.visible &&
+        this.propertyDialog.source === source
+      ) {
+        if (
+          this.propertyDialog.featureIndex >= 0 &&
+          latestGeojson.features &&
+          latestGeojson.features[this.propertyDialog.featureIndex]
+        ) {
+          if (!latestGeojson.features[this.propertyDialog.featureIndex].properties) {
+            latestGeojson.features[this.propertyDialog.featureIndex].properties = {};
+          }
+          this.propertyDialog.propertiesRef =
+            latestGeojson.features[this.propertyDialog.featureIndex].properties;
+        } else {
+          if (!latestGeojson.properties) {
+            latestGeojson.properties = {};
+          }
+          this.propertyDialog.propertiesRef = latestGeojson.properties;
+        }
+      }
+    },
+    handlePropertyValueChange(item) {
+      if (!this.propertyDialog.propertiesRef || !item) {
+        return;
+      }
+      const currentKey = (item.editKey || "").trim();
+      if (!currentKey) {
+        this.$message({
+          message: "属性名不能为空",
+          type: "warning",
+        });
+        item.editKey = item.originalKey || "";
+        return;
+      }
+      this.propertyDialog.propertiesRef[currentKey] = this.parsePropertyValue(item.editValue);
+      item.originalKey = currentKey;
+      item.editKey = currentKey;
+      this.syncPropertyToEntity(this.propertyDialog.propertiesRef);
+      this.syncJsonEditorData(this.propertyDialog.source || this.currentRenderedSource || "input");
+    },
+    handlePropertyKeyChange(item) {
+      if (!this.propertyDialog.propertiesRef || !item) {
+        return;
+      }
+      const oldKey = item.originalKey;
+      const newKey = (item.editKey || "").trim();
+      if (!newKey) {
+        this.$message({
+          message: "属性名不能为空",
+          type: "warning",
+        });
+        item.editKey = oldKey;
+        return;
+      }
+      if (newKey !== oldKey && Object.prototype.hasOwnProperty.call(this.propertyDialog.propertiesRef, newKey)) {
+        this.$message({
+          message: "属性名已存在,请更换",
+          type: "warning",
+        });
+        item.editKey = oldKey;
+        return;
+      }
+      const oldValue = this.propertyDialog.propertiesRef[oldKey];
+      if (newKey !== oldKey) {
+        delete this.propertyDialog.propertiesRef[oldKey];
+        this.propertyDialog.propertiesRef[newKey] = oldValue;
+      }
+      item.originalKey = newKey;
+      item.editKey = newKey;
+      this.syncPropertyToEntity(this.propertyDialog.propertiesRef);
+      this.syncJsonEditorData(this.propertyDialog.source || this.currentRenderedSource || "input");
+    },
+    deleteProperty(item) {
+      if (!this.propertyDialog.propertiesRef || !item) {
+        return;
+      }
+      const key = (item.originalKey || "").trim();
+      if (key && Object.prototype.hasOwnProperty.call(this.propertyDialog.propertiesRef, key)) {
+        delete this.propertyDialog.propertiesRef[key];
+      }
+      this.propertyDialog.list = this.propertyDialog.list.filter((property) => property.id !== item.id);
+      this.syncPropertyToEntity(this.propertyDialog.propertiesRef);
+      this.syncJsonEditorData(this.propertyDialog.source || this.currentRenderedSource || "input");
+    },
+    addProperty() {
+      if (!this.propertyDialog.propertiesRef) {
+        this.$message({
+          message: "请先点击地图中的已渲染要素",
+          type: "warning",
+        });
+        return;
+      }
+      let index = 1;
+      let newKey = "newKey";
+      while (Object.prototype.hasOwnProperty.call(this.propertyDialog.propertiesRef, newKey)) {
+        newKey = `newKey${index}`;
+        index += 1;
+      }
+      this.propertyDialog.propertiesRef[newKey] = "";
+      this.propertyDialog.list.push({
+        id: this.propertyIdSeed++,
+        originalKey: newKey,
+        editKey: newKey,
+        editValue: "",
+      });
+      this.syncPropertyToEntity(this.propertyDialog.propertiesRef);
+      this.syncJsonEditorData(this.propertyDialog.source || this.currentRenderedSource || "input");
+    },
+    syncPropertyToEntity(propertiesRef) {
+      if (!propertiesRef || !viewer || !this.currentRenderedSource) {
+        return;
+      }
+      const targetSource = this.propertyDialog.source || this.currentRenderedSource;
+      const targetIndex = this.propertyDialog.featureIndex;
+      this.drawnEntities.forEach((entity) => {
+        if (!entity || !entity.__featureRef) {
+          return;
+        }
+        if (
+          entity.__featureRef.source === targetSource &&
+          entity.__featureRef.featureIndex === targetIndex
+        ) {
+          entity.__featureProperties = propertiesRef;
+        }
+      });
     },
     // 将geojson添加到地图中
     addToMap(geojson) {
+      const source = this.currentRenderedSource || "input";
       if (!geojson.features && geojson.geometry) {
         const { type, coordinates } = geojson.geometry;
+        const featureProperties = geojson.properties || {};
+        const featureRefInfo = {
+          source,
+          featureIndex: -1,
+        };
         switch (type) {
           case "Point":
             // 点
-            this.addPoint(coordinates);
+            this.addPoint(coordinates, featureProperties, featureRefInfo);
             break;
           case "LineString":
             // 线
-            this.addLine(coordinates);
+            this.addLine(coordinates, featureProperties, featureRefInfo);
             break;
           case "Polygon":
           case "MultiPolygon":
             // 面
-            this.addPolygon(coordinates);
+            this.addPolygon(coordinates, featureProperties, featureRefInfo);
             break;
           default:
             break;
@@ -628,21 +1039,26 @@ export default {
         const features = geojson.features;
         // 2. 遍历features,根据type添加到地图中
         console.log("features", features);
-        features.forEach((feature) => {
+        features.forEach((feature, featureIndex) => {
           const { type, coordinates } = feature.geometry;
+          const featureProperties = feature.properties || {};
+          const featureRefInfo = {
+            source,
+            featureIndex,
+          };
           switch (type) {
             case "Point":
               // 点
-              this.addPoint(coordinates);
+              this.addPoint(coordinates, featureProperties, featureRefInfo);
               break;
             case "LineString":
               // 线
-              this.addLine(coordinates);
+              this.addLine(coordinates, featureProperties, featureRefInfo);
               break;
             case "Polygon":
             case "MultiPolygon":
               // 面
-              this.addPolygon(coordinates);
+              this.addPolygon(coordinates, featureProperties, featureRefInfo);
               break;
             default:
               break;
@@ -654,7 +1070,7 @@ export default {
       });
     },
     // 添加点到地图中
-    addPoint(coordinates) {
+    addPoint(coordinates, featureProperties = null, featureRefInfo = null) {
       // 1. 解析点的坐标
       console.log("addPoint coordinates", coordinates);
       // 2. 创建点实体
@@ -676,11 +1092,13 @@ export default {
           outlineWidth: 2,
         },
       });
+      pointEntity.__featureProperties = featureProperties;
+      pointEntity.__featureRef = featureRefInfo;
       // 3. 将点实体添加到drawnEntities中
       this.drawnEntities.push(pointEntity);
     },
     // 添加线到地图中
-    addLine(coordinates) {
+    addLine(coordinates, featureProperties = null, featureRefInfo = null) {
       // 1. 解析线的坐标
       console.log("addLine coordinates", coordinates);
       // 2. 处理坐标格式:如果是二维数组则取第一个元素,否则直接使用
@@ -716,6 +1134,7 @@ export default {
 
       // 5. 创建线实体
       const lineEntity = viewer.entities.add({
+        name: "line",
         polyline: {
           show: true,
           positions: positions,
@@ -723,12 +1142,14 @@ export default {
           width: 3,
         },
       });
+      lineEntity.__featureProperties = featureProperties;
+      lineEntity.__featureRef = featureRefInfo;
 
       // 6. 将线实体添加到drawnEntities中
       this.drawnEntities.push(lineEntity);
     },
     // 添加面到地图中
-    addPolygon(coordinates) {
+    addPolygon(coordinates, featureProperties = null, featureRefInfo = null) {
       // 检测是否为MultiPolygon类型(MultiPolygon的坐标是三维数组)
       if (
         Array.isArray(coordinates[0]) &&
@@ -738,15 +1159,15 @@ export default {
         console.log("MultiPolygon coordinates", coordinates);
         // 是MultiPolygon类型,遍历每个Polygon
         coordinates.forEach((polygonCoordinates) => {
-          this.renderSinglePolygon(polygonCoordinates);
+          this.renderSinglePolygon(polygonCoordinates, featureProperties, featureRefInfo);
         });
       } else {
         // 是单个Polygon类型
-        this.renderSinglePolygon(coordinates);
+        this.renderSinglePolygon(coordinates, featureProperties, featureRefInfo);
       }
     },
     // 渲染单个Polygon
-    renderSinglePolygon(coordinates) {
+    renderSinglePolygon(coordinates, featureProperties = null, featureRefInfo = null) {
       // 1. 处理坐标格式:确保获取外部环坐标
       const outerRingCoordinates =
         Array.isArray(coordinates[0]) && Array.isArray(coordinates[0][0])
@@ -811,6 +1232,8 @@ export default {
           extrudedMaterial: SkyScenery.Color.GREEN.withAlpha(0.8),
         },
       });
+      polygonEntity.__featureProperties = featureProperties;
+      polygonEntity.__featureRef = featureRefInfo;
 
       // 5. 将面实体添加到drawnEntities中
       this.drawnEntities.push(polygonEntity);
@@ -864,12 +1287,99 @@ export default {
       this.clearAll();
       this.jsonData = {};
       this.backData = {};
+      this.renderStatus = {
+        input: false,
+        output: false,
+      };
+      this.renderedGeojsonCache = {
+        input: null,
+        output: null,
+      };
+      this.currentRenderedSource = "";
+      this.propertyDialog.visible = false;
+      this.propertyDialog.list = [];
+      this.propertyDialog.source = "";
+      this.propertyDialog.propertiesRef = null;
+      this.propertyDialog.featureIndex = -1;
       this.SceneValue = emit[emit.length - 1];
     },
     // 初始化绘制处理器
     initDrawHandler() {
       // 创建绘制处理器
-      this.handler = new SkyScenery.ScreenSpaceEventHandler(viewer.canvas);
+      if (!this.handler) {
+        this.handler = new SkyScenery.ScreenSpaceEventHandler(viewer.canvas);
+      }
+      this.initFeaturePickHandler();
+    },
+    // 初始化地图要素拾取处理器(用于属性弹框)
+    initFeaturePickHandler() {
+      if (this.featurePickHandler || !viewer || !viewer.canvas) {
+        return;
+      }
+      this.featurePickHandler = new SkyScenery.ScreenSpaceEventHandler(viewer.canvas);
+      this.featurePickHandler.setInputAction((movement) => {
+        // 绘制模式中不触发属性弹框,避免用户操作冲突
+        if (this.currentTool || this.isDrawingHole) {
+          return;
+        }
+        const pickedObject = viewer.scene.pick(movement.position);
+        if (!SkyScenery.defined(pickedObject) || !SkyScenery.defined(pickedObject.id)) {
+          this.propertyDialog.visible = false;
+          this.propertyDialog.list = [];
+          this.propertyDialog.source = "";
+          this.propertyDialog.propertiesRef = null;
+          this.propertyDialog.featureIndex = -1;
+          return;
+        }
+        const entity = pickedObject.id;
+        const featureIndex =
+          entity.__featureRef && typeof entity.__featureRef.featureIndex === "number"
+            ? entity.__featureRef.featureIndex
+            : -1;
+        const propertySource =
+          (entity.__featureRef && entity.__featureRef.source) ||
+          this.currentRenderedSource ||
+          "input";
+        const geojsonData =
+          this.getSourceGeojsonData(propertySource) || this.renderedGeojsonCache[propertySource];
+        let propertiesRef = null;
+        if (geojsonData) {
+          if (
+            entity.__featureRef &&
+            typeof entity.__featureRef.featureIndex === "number" &&
+            entity.__featureRef.featureIndex >= 0 &&
+            geojsonData.features &&
+            geojsonData.features[entity.__featureRef.featureIndex]
+          ) {
+            if (!geojsonData.features[entity.__featureRef.featureIndex].properties) {
+              geojsonData.features[entity.__featureRef.featureIndex].properties = {};
+            }
+            propertiesRef = geojsonData.features[entity.__featureRef.featureIndex].properties;
+          } else {
+            if (!geojsonData.properties) {
+              geojsonData.properties = {};
+            }
+            propertiesRef = geojsonData.properties;
+          }
+        }
+        const propertyList = this.formatFeatureProperties(
+          propertiesRef || entity.__featureProperties || {}
+        );
+        if (propertiesRef || (entity.__featureProperties && typeof entity.__featureProperties === "object")) {
+          this.propertyDialog.source = propertySource;
+          this.propertyDialog.propertiesRef =
+            propertiesRef || entity.__featureProperties || {};
+          this.propertyDialog.featureIndex = featureIndex;
+          this.propertyDialog.list = propertyList;
+          this.propertyDialog.visible = true;
+        } else {
+          this.propertyDialog.visible = false;
+          this.propertyDialog.list = [];
+          this.propertyDialog.source = "";
+          this.propertyDialog.propertiesRef = null;
+          this.propertyDialog.featureIndex = -1;
+        }
+      }, SkyScenery.ScreenSpaceEventType.LEFT_CLICK);
     },
 
     // 激活绘制工具
@@ -1594,6 +2104,12 @@ export default {
       // 清空数组
       this.drawnEntities = [];
       this.geometries = [];
+      this.currentRenderedSource = "";
+      this.propertyDialog.visible = false;
+      this.propertyDialog.list = [];
+      this.propertyDialog.source = "";
+      this.propertyDialog.propertiesRef = null;
+      this.propertyDialog.featureIndex = -1;
       // 取消当前绘制模式
       this.deactivateDraw();
       console.log("已清除所有绘制的元素");
@@ -1679,6 +2195,56 @@ export default {
     border-color: rgba(255, 255, 255, 0.4);
   }
 }
+.feature-property-content {
+  max-height: 360px;
+  overflow: auto;
+  padding-right: 4px;
+}
+.feature-property-tip {
+  color: #9ed2ff;
+  margin-bottom: 12px;
+  font-size: 13px;
+}
+.feature-property-item {
+  padding: 10px 12px;
+  margin-bottom: 8px;
+  border-radius: 8px;
+  background: rgba(61, 132, 205, 0.14);
+  border: 1px solid rgba(111, 186, 255, 0.35);
+}
+.feature-property-row {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  margin-bottom: 8px;
+}
+.feature-property-delete-btn {
+  flex-shrink: 0;
+}
+.feature-property-key-input {
+  width: 180px;
+}
+:deep(.feature-property-input .el-input__wrapper) {
+  background: rgba(8, 34, 74, 0.68);
+  box-shadow: inset 0 0 0 1px rgba(130, 198, 255, 0.4);
+}
+:deep(.feature-property-input .el-input__inner) {
+  color: #ffffff;
+}
+:deep(.feature-property-dialog .el-dialog) {
+  background: rgba(7, 24, 48, 0.95);
+  border: 1px solid rgba(111, 186, 255, 0.5);
+}
+:deep(.feature-property-dialog .el-dialog__title) {
+  color: #e8f4ff;
+  font-weight: 700;
+}
+:deep(.feature-property-dialog .el-dialog__headerbtn .el-dialog__close) {
+  color: #d8ecff;
+}
+:deep(.feature-property-dialog .el-dialog__body) {
+  padding-top: 12px;
+}
 :deep(.ace_editor) {
   height: 600px !important;
   max-height: calc(100vh - 300px) !important;

+ 5 - 5
src/store/index.js

@@ -14,11 +14,11 @@ export default createStore({
     activeMenu: sessionStorage.getItem('activeMenu') ? parseInt(sessionStorage.getItem('activeMenu')) : 1, // 初始化为1或具体的菜单项ID
     menuList: [
       { id: 1, path: "/", label: "首页" },
-      { id: 2, path: "/sksjgl", label: "时空数据管理" },
-      // { id:3,path: "/skmh/scene", label: "二维GIS引擎"},
-      { id: 4, path: "/skmh", label: "时空门户" },
-      { id: 5, path: "/wgn", label: "微功能" },
-      { id: 6, path: "/yygl", label: "应用管理" },
+      { id: 2, path: "/skmh", label: "时空门户" },
+      { id: 3, path: "/yygl", label: "应用中心" },
+      // { id: 4, path: "/sksjgl", label: "数据管理中心" },
+      { id: 5, path: "/wgn", label: "微功能中心" },
+      // { id:6,path: "/skmh/scene", label: "二维GIS引擎"},
       { id: 7, path: "/yxgl", label: "运行管理" },
       { id: 8, path: "/taskManger", label: "任务管理" }
     ],

+ 12 - 32
src/utils/request.js

@@ -91,40 +91,20 @@ function get(url, params) {
 }
 
 function post(url, data) {
-  var myHeaders = new Headers();
-  myHeaders.append("Content-Type", "application/json");
-  myHeaders.append("token", ls.get('token'));
-
-  var requestOptions = {
-    method: 'POST',
-    headers: myHeaders,
-    redirect: 'follow'
-  };
-
-  // console.log(url);
-  return fetch(url, requestOptions)
-    .then(response => { return response.json() })
-    .then(result => {
-      // console.log(result);
-      return result;
+  return new Promise((resolve, reject) => {
+    service({
+      method: 'POST',
+      url,
+      data: data,
+      headers: {
+        'Content-Type': 'application/json;'
+      }
+    }).then(res => {
+      resolve(res.data)
     }).catch(err => {
-      return JSON.parse(err)
+      reject(err)
     })
-
-  // return new Promise((resolve, reject) => {
-  //   service({
-  //     method: 'POST',
-  //     url,
-  //     data: data,
-  //     headers: {
-  //       'Content-Type': 'application/json;'
-  //     }
-  //   }).then(res => {
-  //     resolve(res.data)
-  //   }).catch(err => {
-  //     reject(err)
-  //   })
-  // })
+  })
 }
 
 function postform(url, data) {

File diff suppressed because it is too large
+ 533 - 155
src/views/HomePage.vue


+ 8 - 6
src/views/Root.vue

@@ -1,10 +1,10 @@
 <template>
   <div class="main">
     <Header />
-    <el-scrollbar ref="pagescrollbar" class="el-scrollbar">
-      <router-view />
-    </el-scrollbar>
-    <Footer></Footer>
+      <el-scrollbar ref="pagescrollbar" class="el-scrollbar">
+          <router-view />
+      </el-scrollbar>
+    <!-- <Footer></Footer> -->
   </div>
 </template>
 
@@ -49,15 +49,17 @@ export default {
   width: 100%;
   height: 100%;
   margin: 0 auto;
-  overflow: hidden;
+  //overflow: hidden;
 
   .el-scrollbar {
     position: relative;
     width: 100%;
-    height: calc(100% - 120px);
+    height: 100%;
+    // height: calc(100% - 120px);
     box-sizing: border-box;
     overflow: hidden;
     overflow: auto;
+    // padding-bottom: 120px
   }
 }
 </style>

+ 78 - 6
src/views/Sksjgl.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="sksjgl container">
-    <div class="server_title">
+    <!-- <div class="server_title">
       <el-image
         style="width: 50%; height: calc(100vh - 120px)"
         src="static/images/sksjgl/sksjgl_title.png"
@@ -12,7 +12,21 @@
           二维数据服务是围绕二维地理信息数据展开的综合服务体系。它涵盖以像元阵列形式存储的栅格服务,广泛应用于影像地图展示、地形分析等;通过将地图切割成小图片进行快速加载的瓦片服务,提升地图浏览流畅度;能够精确表达地理要素几何形状和属性的矢量时空数据服务,记录地理对象随时间的变化;以及包含特定主题数据集合的专题库服务,如交通专题库、土地利用专题库等,满足不同行业对特定地理信息的深度挖掘与分析需求,为城市规划、资源管理、环境监测等领域提供有力的数据支撑。
         </div>
       </div>
+    </div> -->
+
+    <!-- 顶部横幅区域 -->
+    <div class="banner">
+      <div class="banner-content">
+        <h1 class="banner-title">时空数据管理</h1>
+        <p class="banner-description">
+          &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;二维数据服务是围绕二维地理信息数据展开的综合服务体系。它涵盖以像元阵列形式存储的栅格服务,广泛应用于影像地图展示、地形分析等;通过将地图切割成小图片进行快速加载的瓦片服务,提升地图浏览流畅度;能够精确表达地理要素几何形状和属性的矢量时空数据服务,记录地理对象随时间的变化;以及包含特定主题数据集合的专题库服务,如交通专题库、土地利用专题库等,满足不同行业对特定地理信息的深度挖掘与分析需求,为城市规划、资源管理、环境监测等领域提供有力的数据支撑。
+        </p>
+        <!-- <div>
+          <el-button type="primary" class="enter-button" @click="handleEnterClick">立即体验</el-button>
+        </div> -->
+      </div>
     </div>
+
     <div class="checkModule">
       <!-- 流程步骤 -->
       <div class="process-bar">
@@ -213,7 +227,7 @@ export default {
       &_title {
         font-size: 64px;
         font-weight: bold;
-        letter-spacing: 0.5rem;
+        // letter-spacing: 0.5rem;
       }
 
       &_content {
@@ -225,7 +239,7 @@ export default {
 
   .checkModule {
     width: 100%;
-    background-color: #0f2545;
+    background-color: #00002e;
 
     /* 流程步骤样式 */
     .process-bar {
@@ -255,7 +269,7 @@ export default {
           line-height: 50px;
           font-size: 24px;
           text-align: center;
-          letter-spacing: 5px;
+          // letter-spacing: 5px;
         }
 
         &.active {
@@ -350,7 +364,7 @@ export default {
   }
 
   .time-space-operator-lib {
-    background-color: #1e407c;
+    background-color: #00002e;
     color: #fff;
     padding: 100px 150px;
     box-sizing: border-box;
@@ -361,7 +375,7 @@ export default {
       margin-bottom: 50px;
 
       h1 {
-        font-size: 50px;
+        font-size: 36px;
         font-weight: bold;
       }
     }
@@ -453,4 +467,62 @@ export default {
     }
   }
 }
+
+/* 顶部横幅样式 */
+.banner {
+  width: 100%;
+  // height: calc(100vh - 120px);
+  height: 552px;
+  background: url('@static/images/sjgl/bg.png');
+  background-size: cover;
+  display: flex;
+  justify-content: right;
+  align-items: start;
+  position: relative;
+  overflow: hidden;
+
+  .banner-content {
+    position: relative;
+    z-index: 2;
+    text-align: right;
+    max-width: 500px;
+    padding: 0 10%;
+    justify-content: right;
+    display: grid;
+    padding-top: 100px;
+  }
+
+  .banner-title {
+    font-size: 56px;
+    font-weight: bold;
+    // letter-spacing: 0.5rem;
+    // margin-bottom: 20px;
+    color: #ffffff;
+    text-align: right;
+    text-shadow: 0 2px 10px rgba(0, 0, 0, 0.5);
+  }
+
+  .banner-description {
+    font-size: 16px;
+    // line-height: 1.8;
+    margin: 20px 0px;
+    text-align: left;
+    color: rgba(255, 255, 255, 0.9);
+  }
+
+  .enter-button {
+    padding: 12px 36px;
+    font-size: 18px;
+    border-radius: 10px;
+    background-color: #1890ff;
+    border: none;
+    transition: all 0.3s ease;
+
+    &:hover {
+      background-color: #40a9ff;
+      transform: translateY(-2px);
+      box-shadow: 0 4px 12px rgba(24, 144, 255, 0.4);
+    }
+  }
+}
 </style>

+ 82 - 8
src/views/Wgn.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="wgn_box">
-    <div class="server_title">
+    <!-- <div class="server_title">
       <el-image
         style="width: 50%; height: calc(100vh - 120px)"
         src="static/images/wgn_title.png"
@@ -14,14 +14,30 @@
           两大核心能力,所有功能均以标准化服务接口形式对外提供(支持第三方委办、上层应用系统调用),同时在系统内部集成可视化操作界面,实现
           “计算 - 分析 - 展示” 闭环。
         </div>
-        <div class="server_title_text_btu" v-if="$getUserType() == 3">
+        <div class="server_title_text_btu" v-if="$getUserType() == 3"> -->
           <!-- 先打开弹窗,然后上传文件保存信息到DMS的任务表,同时发送任务到微功能子系统,微功能子系统处理完成后,更新任务状态 -->
-          <el-button type="primary" round plain size="large" @click="createTask"
+          <!-- <el-button type="primary" round plain size="large" @click="createTask"
+            >大批量数据处理任务<el-icon><Position /></el-icon
+          ></el-button>
+        </div>
+      </div>
+    </div> -->
+
+    <!-- 顶部横幅区域 -->
+    <div class="banner">
+      <div class="banner-content">
+        <h1 class="banner-title">微功能服务</h1>
+        <p class="banner-description">
+          &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;微功能子系统专注于提供强大的空间计算与数据处理能力,是支撑青浦区三维数字底板空间分析与数据流转的核心模块,聚焦“精准计算 + 灵活处理”两大核心能力,所有功能均以标准化服务接口形式对外提供(支持第三方委办、上层应用系统调用),同时在系统内部集成可视化操作界面,实现“计算 - 分析 - 展示” 闭环。
+        </p>
+        <div v-if="$getUserType() == 3">
+           <el-button type="primary" round plain size="large" @click="createTask"
             >大批量数据处理任务<el-icon><Position /></el-icon
           ></el-button>
         </div>
       </div>
     </div>
+
     <div class="server_list_box">
       <div class="server_list_box_title">微功能列表</div>
       <el-affix :offset="80">
@@ -670,6 +686,7 @@ export default {
                 message: "任务创建成功",
                 type: "success",
               });
+              // 不直接开始任务,需要到任务管理页面启动
               that.showTaskFrom = false;
             } else {
               that.$message({
@@ -778,7 +795,7 @@ export default {
   &_title {
     font-size: 64px;
     font-weight: bold;
-    letter-spacing: 0.5rem;
+    // letter-spacing: 0.5rem;
   }
   &_content {
     margin-top: 77px;
@@ -787,7 +804,7 @@ export default {
   &_btu {
     margin-top: 77px;
     font-size: 22px;
-    letter-spacing: 0.2rem;
+    // letter-spacing: 0.2rem;
     color: #4095e5;
   }
 }
@@ -797,7 +814,7 @@ export default {
 }
 .server_list_box {
   width: 100vw;
-  background-color: rgba(0, 0, 0, 0.15);
+  background-color: #00002e;
   display: flex;
   flex-direction: column;
   align-items: center;
@@ -862,7 +879,7 @@ export default {
         &_title {
           font-size: 35px;
           font-weight: bold;
-          color: #4095e5;
+          color: #fff;
         }
         &_text {
           margin-top: 35px;
@@ -875,7 +892,7 @@ export default {
           &_item {
             margin-top: 35px;
             font-size: 20px;
-            letter-spacing: 0.2rem;
+            // letter-spacing: 0.2rem;
             color: #4095e5;
             border: 1px solid #4095e5;
             border-radius: 10px;
@@ -899,4 +916,61 @@ export default {
     }
   }
 }
+/* 顶部横幅样式 */
+.banner {
+  width: 100%;
+  // height: calc(100vh - 120px);
+  height: 552px;
+  background: url('@static/images/wgn/bg.png');
+  background-size: cover;
+  display: flex;
+  justify-content: right;
+  align-items: start;
+  position: relative;
+  overflow: hidden;
+
+  .banner-content {
+    position: relative;
+    z-index: 2;
+    text-align: right;
+    max-width: 500px;
+    padding: 0 10%;
+    justify-content: right;
+    display: grid;
+    padding-top: 100px;
+  }
+
+  .banner-title {
+    font-size: 56px;
+    font-weight: bold;
+    // letter-spacing: 0.5rem;
+    // margin-bottom: 20px;
+    color: #ffffff;
+    text-align: right;
+    text-shadow: 0 2px 10px rgba(0, 0, 0, 0.5);
+  }
+
+  .banner-description {
+    font-size: 16px;
+    // line-height: 1.8;
+    margin: 20px 0px;
+    text-align: left;
+    color: rgba(255, 255, 255, 0.9);
+  }
+
+  .enter-button {
+    padding: 12px 36px;
+    font-size: 18px;
+    border-radius: 10px;
+    background-color: #1890ff;
+    border: none;
+    transition: all 0.3s ease;
+
+    &:hover {
+      background-color: #40a9ff;
+      transform: translateY(-2px);
+      box-shadow: 0 4px 12px rgba(24, 144, 255, 0.4);
+    }
+  }
+}
 </style>

+ 12 - 3
src/views/Yxgl.vue

@@ -1,4 +1,8 @@
 <template>
+  <el-affix :offset="0">
+    <div style="height: 44px;width: 100vw;background: #08224a;"></div>
+  </el-affix>
+  <el-affix :offset="44">
   <div id="yxgl_box">
     <el-menu
       :default-active="menuActive"
@@ -46,6 +50,7 @@
       <iframe v-else :src="iframeUrl" frameborder="0"></iframe>
     </div>
   </div>
+  </el-affix>
 </template>
 
 <script>
@@ -102,7 +107,8 @@ export default {
 <style lang="less" scoped>
 #yxgl_box {
   width: 100vw;
-  height: calc(100vh - 120px);
+  // height: calc(100vh - 120px);
+  height: 100vh;
   margin: 0;
   display: flex;
   overflow: hidden;
@@ -110,17 +116,20 @@ export default {
 
 .el-menu-vertical-demo:not(.el-menu--collapse) {
   width: 200px;
-  height: calc(100vh - 120px);
+  // height: calc(100vh - 120px);
+  height: 100vh;
   margin: 0;
   background: #08224a;
 }
 .viewBox {
   width: calc(100vw - 200px);
   margin: 0;
-  height: calc(100vh - 120px);
+  // height: calc(100vh - 120px);
+  height: 100vh;
   position: relative;
   overflow: hidden;
   overflow-y: auto;
+  padding-bottom: 120px;
 }
 iframe {
   width: 100%;

+ 324 - 168
src/views/rwgl/Index.vue

@@ -1,174 +1,264 @@
 <template>
-  <div class="blue-background">
-    <div class="lighter-container">
-      <div class="left-row">
-        <div>
-          <div>状态:</div>
-          <el-tag size="large" :effect="focusTaskStatus.includes('all') ? 'dark' : ''" type="primary"
-            @click="changeTaskStatus()">
-            全部
-          </el-tag>
-          <template v-for="status in taskStatus" :key="status.index">
-            <el-tag size="large" :effect="focusTaskStatus.includes(status.index) ? 'dark' : ''" type="primary"
-              @click="changeTaskStatus(status)">
-              {{ status.name }}
+  <el-affix :offset="0">
+    <div style="height: 44px; width: 100vw; background: #08224a"></div>
+  </el-affix>
+  <el-affix :offset="44">
+    <div class="blue-background">
+      <div class="lighter-container">
+        <div class="left-row">
+          <div>
+            <span>状态:</span>
+            <el-tag
+              size="large"
+              :effect="focusTaskStatus.includes('all') ? 'dark' : ''"
+              type="primary"
+              @click="changeTaskStatus()"
+              style="cursor: pointer; margin: 10px 5px"
+            >
+              全部
             </el-tag>
-          </template>
-        </div>
-        <div>
-          <div>类别:</div>
-          <el-tag size="large" :effect="focusTaskType.includes('all') ? 'dark' : ''" type="primary"
-            @click="changeTaskType()">
-            全部
-          </el-tag>
-          <template v-for="type in taskType" :key="type.index">
-            <el-tag size="large" :effect="focusTaskType.includes(type.index) ? 'dark' : ''" type="primary"
-              @click="changeTaskType(type)">
-              {{ type.name }}
+            <template v-for="status in taskStatus" :key="status.index">
+              <el-tag
+                size="large"
+                :effect="focusTaskStatus.includes(status.index) ? 'dark' : ''"
+                type="primary"
+                @click="changeTaskStatus(status)"
+                style="cursor: pointer; margin: 10px 5px"
+              >
+                {{ status.name }}
+              </el-tag>
+              <template v-for="status in taskStatus" :key="status.index">
+                <el-tag
+                  size="large"
+                  :effect="focusTaskStatus.includes(status.index) ? 'dark' : ''"
+                  type="primary"
+                  @click="changeTaskStatus(status)"
+                  style="cursor: pointer; margin: 10px 5px"
+                >
+                  {{ status.name }}
+                </el-tag>
+              </template>
+            </template>
+          </div>
+          <div>
+            <span>类别:</span>
+            <el-tag
+              size="large"
+              :effect="focusTaskType.includes('all') ? 'dark' : ''"
+              type="primary"
+              @click="changeTaskType()"
+              style="cursor: pointer; margin: 10px 5px"
+            >
+              全部
             </el-tag>
-          </template>
+            <template v-for="type in taskType" :key="type.index">
+              <el-tag
+                size="large"
+                :effect="focusTaskType.includes(type.index) ? 'dark' : ''"
+                type="primary"
+                @click="changeTaskType(type)"
+                style="cursor: pointer; margin: 10px 5px"
+              >
+                {{ type.name }}
+              </el-tag>
+            </template>
+          </div>
+        </div>
+        <div class="row">
+          <el-input
+            class="searcher"
+            v-model="searcher"
+            placeholder="请输入任务名称相关关键字"
+          />
+          <el-button type="primary" @click="pullTaskData(1)">搜索</el-button>
+          <el-button type="primary" @click="reset(), pullTaskData(1)">重置</el-button>
         </div>
       </div>
-      <div class="row">
-        <el-input class="searcher" v-model="searcher" placeholder="请输入任务名称相关关键字" />
-        <el-button type="primary" @click="pullTaskData(1)">搜索</el-button>
-        <el-button type="primary" @click="reset(), pullTaskData(1)">重置</el-button>
+      <div class="lighter-container">
+        <div style="padding-bottom: 10px">查询到{{ taskNum }}条任务</div>
+        <el-table table-layout="fixed" row-key="main_id" :data="taskData" class="table">
+          <el-table-column prop="main_c_name" label="名称" />
+          <el-table-column prop="main_c_user_name" label="用户" />
+          <el-table-column prop="main_c_state" label="类型">
+            <template #default="scope">
+              <el-tag
+                effect="dark"
+                v-show="getType(scope.row.main_c_type) != null"
+                disable-transitions
+                >{{ getType(scope.row.main_c_type)?.name ?? "" }}
+              </el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column prop="main_c_state" label="状态">
+            <template #default="scope">
+              <el-tag
+                effect="dark"
+                v-show="getStatus(scope.row.main_c_state) != null"
+                :type="statusStaticInfo[scope.row.main_c_state]?.tagType ?? ''"
+                disable-transitions
+                >{{ getStatus(scope.row.main_c_state)?.name ?? "" }}</el-tag
+              >
+            </template>
+          </el-table-column>
+          <el-table-column prop="main_c_start_time" label="任务开始时间">
+            <template #default="scope">
+              {{ timeFormatter(scope.row.main_c_start_time) }}
+            </template>
+          </el-table-column>
+          <el-table-column prop="main_c_end_time" label="任务结束时间">
+            <template #default="scope">
+              {{ timeFormatter(scope.row.main_c_end_time) }}
+            </template>
+          </el-table-column>
+          <el-table-column prop="main_c_file_name" label="结果">
+            <template #default="scope">
+              <span
+                class="link"
+                v-if="scope.row.main_c_file != null && scope.row.main_c_file_name != null"
+                @click="
+                  downloadWithBlob(scope.row.main_c_file, scope.row.main_c_file_name)
+                "
+              >
+                {{ scope.row.main_c_file_name }}
+              </span>
+            </template>
+          </el-table-column>
+          <el-table-column label="操作" width="420">
+            <template #default="scope">
+              <el-button
+                type="primary"
+                @click="
+                  () => {
+                    dialog = true;
+                    focusTask = scope.row;
+                  }
+                "
+              >
+                查看详情
+              </el-button>
+              <el-button
+                v-if="scope.row.main_c_state == 0"
+                type="success"
+                @click="runTask(scope.row.main_id)"
+              >
+                运行
+              </el-button>
+              <template
+                v-if="scope.row.main_c_file != null && scope.row.main_c_file_name != null"
+              >
+                <el-button
+                  type="primary"
+                  @click="
+                    downloadWithBlob(scope.row.main_c_file, scope.row.main_c_file_name)
+                  "
+                >
+                  下载结果
+                </el-button>
+                <el-button type="primary" @click="preView(scope.row.main_c_file)">
+                  预览结果
+                </el-button>
+              </template>
+            </template>
+          </el-table-column>
+        </el-table>
+        <div class="between-row pagination-container">
+          <div><!--empty div--></div>
+          <el-pagination
+            layout="prev, pager, next"
+            :total="taskNum"
+            @change="(page) => pullTaskData(page)"
+          />
+        </div>
       </div>
-    </div>
-    <div class="lighter-container">
-      查询到{{ taskNum }}条任务
-      <el-table table-layout="fixed" row-key="main_id" :data="taskData" class="table">
-        <el-table-column prop="main_c_name" label="名称" />
-        <el-table-column prop="main_c_user_name" label="用户" />
-        <el-table-column prop="main_c_state" label="类型">
-          <template #default="scope">
-            <el-tag effect="dark" v-show="getType(scope.row.main_c_type) != null" disable-transitions>{{
-              getType(scope.row.main_c_type)?.name ?? "" }}
+      <el-dialog v-model="dialog" :show-close="true" width="750">
+        <template #header>
+          <div class="my-header">
+            <span class="second-title">{{ focusTask.main_c_name }}</span>
+          </div>
+        </template>
+        <el-descriptions class="margin-top" label-width="128" :column="1" border>
+          <el-descriptions-item label="任务名称">
+            {{ focusTask.main_c_name }}
+          </el-descriptions-item>
+          <el-descriptions-item label="任务描述">
+            {{ focusTask.main_c_comment }}
+          </el-descriptions-item>
+          <el-descriptions-item label="任务类型">
+            <el-tag
+              effect="dark"
+              v-show="getType(focusTask.main_c_type) != null"
+              disable-transitions
+              >{{ getType(focusTask.main_c_type)?.name ?? "" }}
+            </el-tag>
+          </el-descriptions-item>
+          <el-descriptions-item label="用户名">
+            {{ focusTask.main_c_user_name }}
+          </el-descriptions-item>
+          <el-descriptions-item label="用户id">
+            {{ focusTask.main_c_user_id }}
+          </el-descriptions-item>
+          <el-descriptions-item label="状态">
+            <el-tag
+              effect="dark"
+              :type="statusStaticInfo[focusTask.main_c_state]?.tagType ?? ''"
+              disable-transitions
+              >{{ getStatus(focusTask.main_c_state)?.name ?? "" }}
             </el-tag>
-          </template>
-        </el-table-column>
-        <el-table-column prop="main_c_state" label="状态">
-          <template #default="scope">
-            <el-tag effect="dark" v-show="getStatus(scope.row.main_c_state) != null"
-              :type="statusStaticInfo[scope.row.main_c_state]?.tagType ?? ''" disable-transitions>{{
-                getStatus(scope.row.main_c_state)?.name ?? "" }}</el-tag>
-          </template>
-        </el-table-column>
-        <el-table-column prop="main_c_start_time" label="任务开始时间">
-          <template #default="scope">
-            {{ timeFormatter(scope.row.main_c_start_time) }}
-          </template>
-        </el-table-column>
-        <el-table-column prop="main_c_end_time" label="任务结束时间">
-          <template #default="scope">
-            {{ timeFormatter(scope.row.main_c_end_time) }}
-          </template>
-        </el-table-column>
-        <el-table-column prop="main_c_file_name" label="结果">
-          <template #default="scope">
-            <span class="link" v-if="scope.row.main_c_file != null && scope.row.main_c_file_name != null"
-              @click="downloadWithBlob(scope.row.main_c_file, scope.row.main_c_file_name)">
-              {{ scope.row.main_c_file_name }}
-            </span>
-          </template>
-        </el-table-column>
-        <el-table-column label="操作" width="360">
-          <template #default="scope">
-            <el-button type="primary" @click="
-              () => {
-                dialog = true;
-                focusTask = scope.row;
-              }
-            ">
-              查看详情
-            </el-button>
-            <template v-if="scope.row.main_c_file != null && scope.row.main_c_file_name != null">
-              <el-button type="primary" @click="
-                downloadWithBlob(scope.row.main_c_file, scope.row.main_c_file_name)
-                ">
+          </el-descriptions-item>
+          <el-descriptions-item label="任务开始时间">
+            {{ timeFormatter(focusTask.main_c_start_time) }}
+          </el-descriptions-item>
+          <el-descriptions-item label="任务结束时间">
+            {{ timeFormatter(focusTask.main_c_end_time) }}
+          </el-descriptions-item>
+          <el-descriptions-item label="结果文件">
+            {{ focusTask.main_c_file_name }}
+
+            <template
+              v-if="focusTask.main_c_file != null && focusTask.main_c_file_name != null"
+            >
+              <el-button
+                type="primary"
+                size="small"
+                @click="
+                  downloadWithBlob(focusTask.main_c_file, focusTask.main_c_file_name)
+                "
+              >
                 下载结果
               </el-button>
-              <el-button type="primary" @click="preView(scope.row.main_c_file)">
+              <el-button
+                type="primary"
+                size="small"
+                @click="preView(focusTask.main_c_file)"
+              >
                 预览结果
               </el-button>
             </template>
-          </template>
-        </el-table-column>
-      </el-table>
-      <div class="between-row">
-        <div><!--empty div--></div>
-        <el-pagination layout="prev, pager, next" :total="taskNum" @change="(page) => pullTaskData(page)" />
-      </div>
+          </el-descriptions-item>
+          <el-descriptions-item label="原始数据">
+            <template
+              v-if="
+                focusTask.main_c_source_file_name != null &&
+                focusTask.main_c_source_file != null
+              "
+            >
+              {{ focusTask.main_c_source_file_name }}
+              <br />
+            </template>
+            <template v-if="focusTask.main_c_source_data != null">
+              <div class="hide-scrollbar long-text">
+                {{ truncateText(focusTask.main_c_source_data, 10000) }}
+              </div>
+            </template>
+          </el-descriptions-item>
+        </el-descriptions>
+      </el-dialog>
     </div>
-    <el-dialog v-model="dialog" :show-close="true" width="750">
-      <template #header>
-        <div class="my-header">
-          <span class="second-title">{{ focusTask.main_c_name }}</span>
-        </div>
-      </template>
-      <el-descriptions class="margin-top" label-width="128" :column="1" border>
-        <el-descriptions-item label="任务名称">
-          {{ focusTask.main_c_name }}
-        </el-descriptions-item>
-        <el-descriptions-item label="任务描述">
-          {{ focusTask.main_c_comment }}
-        </el-descriptions-item>
-        <el-descriptions-item label="任务类型">
-          <el-tag effect="dark" v-show="getType(focusTask.main_c_type) != null" disable-transitions>{{
-            getType(focusTask.main_c_type)?.name ?? "" }}
-          </el-tag>
-        </el-descriptions-item>
-        <el-descriptions-item label="用户名">
-          {{ focusTask.main_c_user_name }}
-        </el-descriptions-item>
-        <el-descriptions-item label="用户id">
-          {{ focusTask.main_c_user_id }}
-        </el-descriptions-item>
-        <el-descriptions-item label="状态">
-          <el-tag effect="dark" :type="statusStaticInfo[focusTask.main_c_state]?.tagType ?? ''" disable-transitions>{{
-            getStatus(focusTask.main_c_state)?.name ?? "" }}
-          </el-tag>
-        </el-descriptions-item>
-        <el-descriptions-item label="任务开始时间">
-          {{ timeFormatter(focusTask.main_c_start_time) }}
-        </el-descriptions-item>
-        <el-descriptions-item label="任务结束时间">
-          {{ timeFormatter(focusTask.main_c_end_time) }}
-        </el-descriptions-item>
-        <el-descriptions-item label="结果文件">
-          {{ focusTask.main_c_file_name }}
-
-          <template v-if="focusTask.main_c_file != null && focusTask.main_c_file_name != null">
-            <el-button type="primary" size="small"
-              @click="downloadWithBlob(focusTask.main_c_file, focusTask.main_c_file_name)">
-              下载结果
-            </el-button>
-            <el-button type="primary" size="small" @click="preView(focusTask.main_c_file)">
-              预览结果
-            </el-button>
-          </template>
-        </el-descriptions-item>
-        <el-descriptions-item label="原始数据">
-          <template v-if="
-            focusTask.main_c_source_file_name != null &&
-            focusTask.main_c_source_file != null
-          ">
-            {{ focusTask.main_c_source_file_name }}
-            <br />
-          </template>
-          <template v-if="focusTask.main_c_source_data != null">
-            <div class="hide-scrollbar long-text">
-              {{ truncateText(focusTask.main_c_source_data, 10000) }}
-            </div>
-          </template>
-        </el-descriptions-item>
-      </el-descriptions>
-    </el-dialog>
-  </div>
+  </el-affix>
 </template>
 
 <script>
-import { getTasks, getCName } from "@/api/rwgl";
+import { getTasks, getCName, executeTask } from "@/api/rwgl";
 
 export default {
   data() {
@@ -197,12 +287,18 @@ export default {
       focusTask: {},
       dialog: false,
       page: 1,
+      tableHeight: 0,
     };
   },
   mounted() {
     this.pullTaskStatus();
     this.pullTaskType();
     this.pullTaskData(1);
+    this.calculateTableHeight();
+    window.addEventListener("resize", this.calculateTableHeight);
+  },
+  beforeUnmount() {
+    window.removeEventListener("resize", this.calculateTableHeight);
   },
   methods: {
     async pullTaskStatus() {
@@ -211,8 +307,8 @@ export default {
       for (const key of Object.keys(oData)) {
         newData.push({
           index: Number(key),
-          name: oData[key]
-        })
+          name: oData[key],
+        });
       }
       this.taskStatus = newData.sort((a, b) => a.index - b.index);
     },
@@ -255,8 +351,8 @@ export default {
       for (const key of Object.keys(oData)) {
         newData.push({
           index: Number(key),
-          name: oData[key]
-        })
+          name: oData[key],
+        });
       }
       let taskType = newData.sort((a, b) => a.index - b.index);
       for (let i = 0; i < taskType.length; i++) {
@@ -267,7 +363,7 @@ export default {
           break;
         }
       }
-      this.taskType = taskType
+      this.taskType = taskType;
     },
     changeTaskType(types) {
       if (types == null) {
@@ -341,12 +437,62 @@ export default {
     preView(url) {
       window.open("fileView?url=" + systemConfig.dmsDataProxy + url, "_blank");
     },
+    async runTask(taskId) {
+      try {
+        const res = await executeTask(taskId);
+        if (res.code === 200) {
+          this.$message({
+            type: "success",
+            message: res.content || "任务已提交,正在后台执行",
+          });
+          // 先禁用按钮,防止重复点击
+          this.$refs.runTaskBtn.disabled = true;
+          // 刷新任务列表
+          setTimeout(() => {
+            // 执行成功后,刷新任务列表
+            this.pullTaskData(this.page);
+          }, 300);
+        } else {
+          this.$message({
+            type: "error",
+            message: res.message || "执行任务失败",
+          });
+        }
+      } catch (error) {
+        console.error("执行任务失败:", error);
+        this.$message({
+          type: "error",
+          message: "执行任务失败,请稍后重试",
+        });
+      }
+    },
     truncateText(text, maxLength = 40) {
       if (typeof text !== "string" || text.length <= maxLength) {
         return text;
       }
       return text.substring(0, maxLength) + "…";
     },
+    calculateTableHeight() {
+      // 计算表格高度:窗口高度 - header高度 - footer高度 - 页面padding - 其他元素高度
+      const windowHeight = window.innerHeight;
+      const headerHeight = 70; // Header组件高度
+      const footerHeight = 50; // Footer组件高度
+      const pagePadding = 40 * 2; // 页面上下padding
+      const filterAreaHeight = 120; // 筛选条件区域高度
+      const taskCountHeight = 30; // 任务数量文字高度
+      const paginationHeight = 50; // 分页区域高度
+      const containerMargin = 15 * 2; // 容器上下margin
+
+      this.tableHeight =
+        windowHeight -
+        headerHeight -
+        footerHeight -
+        pagePadding -
+        filterAreaHeight -
+        taskCountHeight -
+        paginationHeight -
+        containerMargin;
+    },
   },
 };
 </script>
@@ -413,7 +559,8 @@ link {
   margin-left: 0;
   padding-left: 90px;
   padding-right: 90px;
-  min-height: 80vh
+  // min-height: 80vh
+  height: 100vh;
 }
 
 .darkblue-background {
@@ -426,7 +573,7 @@ link {
 
 .blue-background,
 body {
-  background: #0f3460;
+  background: #08224a;
 }
 
 .bluedark-background {
@@ -441,15 +588,24 @@ body {
 
 .lighter-container {
   background-color: #eeeeee0b;
-  padding: 10px;
+  padding: 20px;
   margin: 15px;
   vertical-align: middle;
-  border-radius: 3%;
+  border-radius: 10px;
+}
+
+.task-count {
+  margin-bottom: 10px;
+  color: #fff;
+}
+
+.pagination-container {
+  margin-top: 15px;
 }
 
 .lightblue-container {
   border-radius: 3%;
-  padding: 10px;
+  padding: 20px;
   margin: 15px;
   background: linear-gradient(to bottom, #215476 0%, #28638b 66%, #337aac 100%);
   font-size: 20px;
@@ -490,7 +646,7 @@ body {
   justify-content: flex-start;
 }
 
-.left-row>* {
+.left-row > * {
   margin-right: 15px;
 }
 
@@ -512,8 +668,8 @@ body {
   flex-direction: column-reverse;
 }
 
-.dense-col>*,
-.start-reverse-col>* {
+.dense-col > *,
+.start-reverse-col > * {
   margin: 10px;
 }
 

+ 285 - 130
src/views/skmh/index.vue

@@ -2,7 +2,7 @@
   <div class="dashboard-container">
     <!-- 顶部横幅 -->
 
-    <div class="server_title">
+    <!-- <div class="server_title">
       <el-image
         style="width: 50%; height: calc(100vh - 120px)"
         src="static/images/wgn_title.png"
@@ -14,18 +14,58 @@
           时空门户子系统为用户提供信息概览、导航入口及交互功能,帮助用户快速了解和使用平台服务。系统统计访问量(累计和日均)、用户使用时长及活跃时段;展示平台功能、核心能力及操作演示视频;统计并展示服务总数、分类占比及新上线服务;同时统计各委办平台的注册用户信息及用户总数。
         </div>
       </div>
-    </div>
+    </div> -->
 
-    <!-- <div class="banner">
+    <!-- 顶部横幅区域 -->
+    <div class="banner">
       <div class="banner-content">
-        <h1>时空门户</h1>
-        <p>时空门户是一个集数据采集、分析、展示于一体的综合性平台,为用户提供全面的设备监控和数据分析服务</p>
-        <button class="enter-btn">进入系统</button>
+        <h1 class="banner-title">时空门户</h1>
+        <p class="banner-description">
+          &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;时空门户子系统为用户提供信息概览、导航入口及交互功能,帮助用户快速了解和使用平台服务。系统统计访问量(累计和日均)、用户使用时长及活跃时段;展示平台功能、核心能力及操作演示视频;统计并展示服务总数、分类占比及新上线服务;同时统计各委办平台的注册用户信息及用户总数。
+        </p>
+        <!-- <div>
+          <el-button type="primary" class="enter-button" @click="handleEnterClick">立即体验</el-button>
+        </div> -->
       </div>
-    </div> -->
-
+    </div>
+   
+    <div class="server_list_box">
+      <div class="server_list_box_table">
+        <div
+          v-for="(item, index) in dataList[0].data"
+          :key="item.index"
+          class="server_list_box_table_item"
+          :id="item.index + 'list'"
+        >
+          <div class="server_list_box_table_item_content">
+            <div class="server_list_box_table_item_content_title">{{ item.title }}</div>
+            <div class="server_list_box_table_item_content_text">{{ item.text }}</div>
+            <div class="server_list_box_table_item_content_button_box">
+              <div v-if="index < 3"
+                class="server_list_box_table_item_content_button_box_item"
+                @click.stop="handleOpenPage(item)"
+              >
+                在线演示
+              </div>
+              <div v-else
+                class="server_list_box_table_item_content_button_box_expect"
+              >
+                敬请期待
+              </div>
+            </div>
+          </div>
+          <div class="server_list_box_table_item_image">
+            <el-image
+              style="width: 690px; height: 410px"
+              :src="item.picture"
+              fit="cover"
+            />
+          </div>
+        </div>
+      </div>
+    </div>
     <!-- 平台数据统计 -->
-    <div class="stats-section">
+    <!-- <div class="stats-section">
       <div class="overview-header">
         <h2>平台数据统计</h2>
       </div>
@@ -64,18 +104,12 @@
           <div class="stat-label">本周新增{{countData.curWeek.username}}人</div>
         </div>
       </div>
-    </div>
+    </div> -->
 
     <!-- 数据概览 -->
-    <div class="data-overview">
+    <!-- <div class="data-overview">
       <div class="overview-header">
         <h2>数据概览</h2>
-        <!-- <div class="time-tabs">
-          <div class="tab active">今日</div>
-          <div class="tab">本周</div>
-          <div class="tab">本月</div>
-          <div class="tab">本年</div>
-        </div> -->
       </div>
        <div class="time-section">
         <div class="time-card">
@@ -102,18 +136,18 @@
           </div>
           </div>
         </div>
-      </div>
-      <div class="charts-grid">
+      </div> -->
+      <!-- <div class="charts-grid"> -->
         <!-- 访问量统计柱状图 -->
-        <div class="chart-card">
+        <!-- <div class="chart-card">
           <div class="chart-title">访问量统计</div>
           <div ref="deviceChart" class="chart-container"></div>
-        </div>
+        </div> -->
         <!-- 服务分类占比饼图 -->
-        <div class="chart-card">
+        <!-- <div class="chart-card">
           <div class="chart-title">服务分类占比</div>
           <div ref="statusChart" class="chart-container"></div>
-        </div>
+        </div> -->
         <!-- 用户活跃度分析折线图 -->
         <!-- <div class="chart-card">
           <div class="chart-title">用户活跃度分析</div>
@@ -124,14 +158,13 @@
           <div class="chart-title">数据量</div>
           <div ref="dataVolumeChart" class="chart-container"></div>
         </div> -->
-      </div>
-    </div>
+      <!-- </div>
+    </div> -->
 
     <!-- 设备综合分析比较 -->
-    <div class="comparison-section">
+    <!-- <div class="comparison-section">
       <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%;"
           height="530"
           :header-cell-style="headerCellStyle"
@@ -145,10 +178,10 @@
           <el-table-column prop="count" label="服务使用量" />
         </el-table>
       </div>
-    </div>
+    </div> -->
 
     <!-- 功能演示 -->
-    <div class="demo-section">
+    <!-- <div class="demo-section">
       <div class="overview-header">
         <h2>功能演示</h2>
       </div>
@@ -162,37 +195,8 @@
             <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">
-            <div class="demo-label">核心功能操作演示</div>
-            <div class="demo-text">展示系统核心功能操作流程与交互方式</div>
-          </div>
-        </div>
-        <div class="demo-card">
-          <div class="demo-thumbnail">
-            <div class="play-btn">▶</div>
-          </div>
-          <div class="demo-title">
-            <div class="demo-label">二三维一体化引擎</div>
-            <div class="demo-text">展示空间数据可视化与交互分析能力</div>
-          </div>
-        </div>
-        <div class="demo-card">
-          <div class="demo-thumbnail">
-            <div class="play-btn">▶</div>
-          </div>
-          <div class="demo-title">
-            <div class="demo-label">实际业务场景应用</div>
-            <div class="demo-text">展示系统在行业中的实际应用案例</div>
-          </div>
-        </div> -->
-
       </div>
-    </div>
+    </div> -->
 
     <div>
       <el-dialog
@@ -210,6 +214,7 @@
 
 <script>
 import * as echarts from 'echarts'
+import { ElNotification } from "element-plus";
 import appCenter from "@/api/appCenter";
 import { countUserList,coutService,totalCountGroupByTime,countUserDataByAutoTime } from "@/api/count";
 import moment from "moment";
@@ -229,6 +234,7 @@ export default {
       centerDialogVisible: false,
       videoUrl: "",
       imageUrl: "static/images/wgn_title.png",
+      dataList:systemConfig.examplelist,
       countData:{
         total:{
           service:0,
@@ -282,12 +288,12 @@ export default {
     },
   },
   mounted() {
-    this.initData()
-    window.addEventListener('resize', this.handleResize)
+    // this.initData()
+    // window.addEventListener('resize', this.handleResize)
   },
   beforeUnmount() {
-    window.removeEventListener('resize', this.handleResize)
-    this.destroyCharts()
+    // window.removeEventListener('resize', this.handleResize)
+    // this.destroyCharts()
   },
   methods: {
     initData(){
@@ -309,6 +315,18 @@ export default {
       this.videoUrl = "";
       this.centerDialogVisible = false;
     },
+    handleOpenPage(item){
+      if(item.url){
+        window.open(item.url, '_blank');
+      }else{
+        ElNotification.success({
+            title: "提示",
+            message: "暂未开放服务",
+            offset: 80,
+          });
+      }
+      
+    },
     getDmsDataList() {
       let requestParams = {
         columnId: systemConfig.columnIds[2], // 应用中心栏目id(示范应用)
@@ -897,6 +915,64 @@ export default {
 
 <style lang="less" scoped>
 
+/* 顶部横幅样式 */
+.banner {
+  width: 100%;
+  // height: calc(100vh - 120px);
+  height: 552px;
+  background: url('@static/images/skmh/bg.png');
+  background-size: cover;
+  display: flex;
+  justify-content: right;
+  align-items: start;
+  position: relative;
+  overflow: hidden;
+
+  .banner-content {
+    position: relative;
+    z-index: 2;
+    text-align: right;
+    max-width: 500px;
+    padding: 0 10%;
+    justify-content: right;
+    display: grid;
+    padding-top: 100px;
+  }
+
+  .banner-title {
+    font-size: 56px;
+    font-weight: bold;
+    // letter-spacing: 0.5rem;
+    // margin-bottom: 20px;
+    color: #ffffff;
+    text-align: right;
+    text-shadow: 0 2px 10px rgba(0, 0, 0, 0.5);
+  }
+
+  .banner-description {
+    font-size: 16px;
+    // line-height: 1.8; 
+    margin: 20px 0px;
+    text-align: left;
+    color: rgba(255, 255, 255, 0.9);
+  }
+
+  .enter-button {
+    padding: 12px 36px;
+    font-size: 18px;
+    border-radius: 10px;
+    background-color: #1890ff;
+    border: none;
+    transition: all 0.3s ease;
+
+    &:hover {
+      background-color: #40a9ff;
+      transform: translateY(-2px);
+      box-shadow: 0 4px 12px rgba(24, 144, 255, 0.4);
+    }
+  }
+}
+
 /* 确保你的自定义样式优先级更高 */
 .el-date-picker {
     /* 重置为期望的样式 */
@@ -904,9 +980,15 @@ export default {
     background-color: white !important; /* 确保背景色正确 */
 }
 .dashboard-container {
-  background-color: #0A192F;
+  // background-color: #0A192F;
+  // min-height: 100vh;
+  // color: #fff;
+
+  width: 100%;
   min-height: 100vh;
-  color: #fff;
+  background-color: #01012f;
+  color: #ffffff;
+  overflow-x: hidden;
 }
 
 .server_title {
@@ -927,7 +1009,7 @@ export default {
   &_title {
     font-size: 64px;
     font-weight: bold;
-    letter-spacing: 0.5rem;
+    // letter-spacing: 0.5rem;
   }
   &_content {
     margin-top: 77px;
@@ -935,68 +1017,10 @@ export default {
   }
 }
 
-/* 顶部横幅 */
-.banner {
-  position: relative;
-  height: 500px;
-  background: url('@/assets/images/common/home-bg1.png') center/cover no-repeat;
-  display: flex;
-  align-items: center;
-  justify-content: flex-end;
-  padding-right: 10%;
-  
-  &::before {
-    content: '';
-    position: absolute;
-    top: 0;
-    left: 0;
-    right: 0;
-    bottom: 0;
-    background: linear-gradient(to right, rgba(10, 25, 47, 0.9), rgba(10, 25, 47, 0.7));
-  }
-  
-  .banner-content {
-    position: relative;
-    max-width: 600px;
-    text-align: left;
-    padding: 0 20px;
-    
-    h1 {
-      font-size: 42px;
-      font-weight: bold;
-      margin-bottom: 20px;
-      color: #fff;
-    }
-    
-    p {
-      font-size: 14px;
-      line-height: 1.8;
-      margin-bottom: 30px;
-      color: #a3b6c7;
-    }
-    
-    .enter-btn {
-      background-color: transparent;
-      color: #409eff;
-      border: 1px solid #409eff;
-      padding: 8px 30px;
-      font-size: 16px;
-      border-radius: 20px;
-      cursor: pointer;
-      transition: all 0.3s ease;
-      
-      &:hover {
-        background-color: #409eff;
-        color: #fff;
-        transform: translateY(-2px);
-      }
-    }
-  }
-}
-
 /* 平台数据统计 */
 .stats-section {
   padding: 40px 10%;
+  margin-top: 100px;
   .overview-header {
     display: flex;
     justify-content: space-between;
@@ -1129,12 +1153,12 @@ export default {
 }
 // 时间筛选
 .time-section{
-  padding: 0 0px 40px;
+  padding: 0 0px 10px;
   .time-card {
-    background-color: rgba(30, 41, 59, 0.6);
-    border-radius: 12px;
-    padding: 20px;
-    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
+    // background-color: rgba(30, 41, 59, 0.6);
+    // border-radius: 12px;
+    padding: 10px;
+    // box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
   }
   .time-content{
     display: flex;
@@ -1351,4 +1375,135 @@ export default {
 :deep(.el-table--striped .el-table__body tr.el-table__row--striped td.el-table__cell) {
   background-color: rgba(255, 255, 255, 0.02);
 }
+
+.server_list_box {
+  width: 100vw;
+  background-color: #00002e;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  color: #fff;
+  position: relative;
+  padding-bottom: 100px;
+  &_menu {
+    position: absolute;
+    top: 100px;
+    left: 10px;
+    z-index: 1;
+  }
+  &_title {
+    margin: 100px 0;
+    font-size: 35px;
+    font-weight: bold;
+    position: relative;
+    &::after {
+      content: "";
+      position: absolute;
+      bottom: -12px;
+      left: 50%;
+      transform: translateX(-50%);
+      width: 100px;
+      height: 4px;
+      background-image: linear-gradient(to right, #1d88f0, #00bfff);
+    }
+  }
+  &_search {
+    // margin-top: 100px;
+    font-size: 25px;
+    display: flex;
+    flex-wrap: nowrap;
+    align-items: center;
+    width: -webkit-fill-available;
+    justify-content: center;
+    .input-with-select {
+      background: #08224a;
+    }
+  }
+  &_table {
+    // margin-top: 50px;
+    width: 100vw;
+    &_item {
+      display: flex;
+      justify-content: space-evenly;
+      align-items: center;
+      padding: 50px 0;
+
+      &:nth-child(odd) {
+        flex-direction: row;
+      }
+      &:nth-child(even) {
+        flex-direction: row-reverse;
+      }
+      &_content {
+        width: 760px;
+        height: 100px;
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+        align-items: center;
+        &_title {
+          font-size: 35px;
+          font-weight: bold;
+          color: #fff;
+          text-align: left;
+          width: 100%;
+        }
+        &_text {
+          margin-top: 35px;
+          font-size: 18px;
+          text-align: left;
+          width: 100%;
+        }
+        &_button_box {
+          display: flex;
+          // justify-content: space-evenly;
+          text-align: left;
+          width: 100%;
+          &_item {
+            margin-top: 35px;
+            font-size: 20px;
+            // letter-spacing: 0.2rem;
+            // color: #4095e5;
+            // border: 1px solid #4095e5;
+            background: linear-gradient(97.31deg, #1586FF 12.71%, #0E5AF4 91.55%);
+            color: #fff;
+            border-radius: 10px;
+            padding: 10px 36px;
+            cursor: pointer;
+            &:hover {
+              // background-color: #077ae6;
+               background: linear-gradient(97.31deg, #067cfa 12.71%, #0047d4 91.55%);
+              color: #fff;
+            }
+          }
+          &_expect {
+            margin-top: 35px;
+            font-size: 20px;
+            // letter-spacing: 0.2rem;
+            // color: #4095e5;
+            // border: 1px solid #4095e5;
+            background: linear-gradient(97.31deg, #2f2f30 12.71%, #202020 91.55%);
+            color: #ccc;
+            border-radius: 10px;
+            padding: 10px 36px;
+            cursor: pointer;
+            &:hover {
+              // background-color: #077ae6;
+               background: linear-gradient(97.31deg, #424242 12.71%, #212122 91.55%);
+              color: #ccc;
+            }
+          }
+        }
+      }
+      &_image {
+        width: 690px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        border-radius: 30px;
+        overflow: hidden;
+      }
+    }
+  }
+}
 </style>

+ 19 - 17
src/views/wgn/sksj/index.vue

@@ -1,6 +1,6 @@
 <template>
     <div class="container">
-        <div style="position: absolute;top: 20px;left: 20px;z-index: 9;">
+        <div style="position: absolute;top: 60px;left: 20px;z-index: 9;">
             <div style="display: flex;">
                 <el-select
                 v-model="typeValue"
@@ -394,35 +394,36 @@ export default {
             // inputAddress:'',
             
             if(that.typeValue == 1){
-                // let curUrl = that.inputAddress;
-                let curUrl = 'http://121.43.55.7:8889/geoserver/kdyjs/wms';
-                that.inputAddress = curUrl;
+                let curUrl = that.inputAddress;
+                // let curUrl = 'http://121.43.55.7:8889/geoserver/kdyjs/wms';
+                // that.inputAddress = curUrl;
                 let param = {url:curUrl,layers:'kdyjs:CourtyardFace'}
                 that.addWMSLayer(param)
 
             }else if(that.typeValue == 2){
+                let curUrl = that.inputAddress;
                 let type = "vec"; //cia  img  vec  cva
-                let curUrl = "https://{s}.tianditu.gov.cn/"+type+"_w/wmts?tk=f74e6c0cc247c42af05f7053e0b5fb9b";
-                that.inputAddress = curUrl;
+                // let curUrl = "https://{s}.tianditu.gov.cn/"+type+"_w/wmts?tk=f74e6c0cc247c42af05f7053e0b5fb9b";
+                // that.inputAddress = curUrl;
                 let param = {url:curUrl,layers:type}
                 that.addWMTSLayer(param)
              
             }else if(that.typeValue == 3){
-                // let curUrl = that.inputAddress;
-                let curUrl = 'https://service-api.onemap.sh.gov.cn/data-service-manage-service/MapProxyApi/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBsaWNhdGlvbl9pZCI6NjEsImFwcGxpY2F0aW9uX25hbWUiOiLpnZLmtabkuozkuInnu7TmnI3liqHns7vnu58iLCJleHAiOjIwNDY2Nzg0MDN9.IKUMdjUX4U1jncIUNren-iotL7duXI90aLECMjpvUX8/shmap_normal_web/MapServer';
-                that.inputAddress = curUrl;
+                let curUrl = that.inputAddress;
+                // let curUrl = 'https://service-api.onemap.sh.gov.cn/data-service-manage-service/MapProxyApi/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBsaWNhdGlvbl9pZCI6NjEsImFwcGxpY2F0aW9uX25hbWUiOiLpnZLmtabkuozkuInnu7TmnI3liqHns7vnu58iLCJleHAiOjIwNDY2Nzg0MDN9.IKUMdjUX4U1jncIUNren-iotL7duXI90aLECMjpvUX8/shmap_normal_web/MapServer';
+                // that.inputAddress = curUrl;
                 let param = {url:curUrl,layers:'arcgisLayer'}
                 that.addARCGISLayer(param)
             }else if(that.typeValue == 4){
-                // let curUrl = that.inputAddress;
-                let curUrl = "http://121.43.55.7:65456/shzx/tileset.json";
-                that.inputAddress = curUrl;
+                let curUrl = that.inputAddress;
+                // let curUrl = "http://121.43.55.7:65456/shzx/tileset.json";
+                // that.inputAddress = curUrl;
                 let param = {url:curUrl}
                 that.add3dtilesData(param);
             }else if(that.typeValue == 5){
-                // let curUrl = that.inputAddress;
-                let curUrl = "https://kdyjs-proxy.metamaker.cn/proxy_map/static/json/%E6%A5%BC%E5%AE%87%E6%95%B0%E6%8D%AE-20250820.geojson";
-                that.inputAddress = curUrl;
+                let curUrl = that.inputAddress;
+                // let curUrl = "https://kdyjs-proxy.metamaker.cn/proxy_map/static/json/%E6%A5%BC%E5%AE%87%E6%95%B0%E6%8D%AE-20250820.geojson";
+                // that.inputAddress = curUrl;
                 let param = {url:curUrl}
                 that.getVectorData(param);
             }else if(that.typeValue == 6){
@@ -445,10 +446,11 @@ export default {
 };
 </script>
 <style lang="less" scoped>
-
 .container {
     width: 100%;
-    height: calc(100vh - 120px);
+    height: 100%;
+    height: 100vh;
+    // height: calc(100vh - 120px);
     padding: 0px;
     margin: 0 auto;
     overflow: hidden;

+ 1 - 0
src/views/yxgl/StatisticalAnalysis.vue

@@ -1085,6 +1085,7 @@ export default {
 .mainBox {
   width: calc(100% - 60px);
   margin: 30px;
+  padding-bottom: 80px;
   & > div {
     margin: 20px 0;
     display: flex;

+ 9 - 2
src/views/yygl/appCenter.vue

@@ -1,4 +1,8 @@
 <template>
+  <el-affix :offset="0">
+  <div style="height: 44px;width: 100vw;background: #08224a;"></div>
+  </el-affix>
+  <el-affix :offset="44">
   <div class="app-center">
     <div class="container">
       <!-- 左侧导航栏 -->
@@ -40,6 +44,7 @@
       </div>
     </div>
   </div>
+  </el-affix>
 </template>
 
 <script>
@@ -72,8 +77,10 @@ export default {
 <style lang="less" scoped>
 .app-center {
   width: 100%;
-  //   min-height: 100vh;
-  height: calc(100vh - 120px);
+  // height: 100%;
+    // min-height: 100vh;
+  // height: calc(100vh - 120px);
+  height: 100vh;
   background-color: #08224a;
   color: #ffffff;
   overflow-x: hidden;

+ 228 - 61
src/views/yygl/index.vue

@@ -5,28 +5,29 @@
       <div class="banner-content">
         <h1 class="banner-title">应用中心</h1>
         <p class="banner-description">
-          收集、管理区级应用的访问地址、使用单位、使用情况等。
-          区委办局、街镇、居村应基于区级节点开展区级时空应用建设。
+          &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;收集、管理区级应用的访问地址、使用单位、使用情况等。区委办局、街镇、居村应基于区级节点开展区级时空应用建设。
         </p>
-        <el-button type="primary" class="enter-button" @click="handleEnterClick">点击进入</el-button>
+        <!-- <div>
+          <el-button type="primary" class="enter-button" @click="handleEnterClick">立即体验</el-button>
+        </div> -->
       </div>
     </div>
 
     <!-- 示范应用区域 -->
     <div class="demo-applications">
-      <div class="section-title">
+      <!-- <div class="section-title">
         <h2>示范应用</h2>
         <div class="title-line"></div>
-      </div>
+      </div> -->
 
       
-      <div class="applications-grid" >
+      <!-- <div class="applications-grid" >
         <div v-for="item in applications" :key="item.id">
           <div class="application-card">
             <div class="card-image">
-              <img :src="curUrl + item.c_picture" :alt="item.c_jsdw" />
+              <img :src="curUrl + item.c_picture" :alt="item.title" />
             </div>
-            <h3 class="card-title"> {{ item.c_jsdw }}</h3>
+            <h3 class="card-title"> {{ item.title }}</h3>
             <div class="card-info">
               <p><strong>访问类型:</strong> {{ item.type }}</p>
               <p><strong>建设单位:</strong> {{ item.jsdw }}</p>
@@ -34,33 +35,50 @@
             </div>
           </div>
         </div>
+      </div> -->
+
+      <div v-for="useCaseItem in appCenterlications" :key="useCaseItem.title">
+        <div class="title " v-if="useCaseItem.title != '基础能力'"  style="margin: 50px 0px;display: flex;justify-content: space-between;align-items: baseline;">
+          <div></div>
+          <div style="font-size: 24px;margin-top: 10px;text-align: center;font-weight: bold;">{{useCaseItem.title}}</div>
+          <div style="color: #ADE8FE;cursor: pointer;" @click="handleEnterClick(useCaseItem.title)">查看更多></div>
+        </div>
+        <div class="warp-container" v-if="useCaseItem.title != '基础能力'" >
+        <el-carousel :interval="40000" type="card" height="600px">
+            <el-carousel-item v-for="item in useCaseItem.data" :key="item.title" @click="handleTabsOpenPage(item)">
+                <div class="warp-page-card" >
+                  <div class="warp-page-img" :style="`background-image: url(${curUrl}${item.picture});`"></div>
+                  <div class="warp-page-text">
+                    <div class="warp-page-text-title">{{ item.title }}</div>
+                    <div class="warp-page-text-desc">{{ item.text }}</div>
+                  </div>
+                </div>
+              </el-carousel-item>
+          </el-carousel>
+        </div>
       </div>
-       <!-- <div class="applications-grid">
-            <div class="application-card">
-            <div class="card-image">
-                <img src="~@/assets/images/common/app-bg-3.png" alt="青浦区环境自动监测信息化平台" />
-            </div>
-            <h3 class="card-title">青浦区环境自动监测信息化平台</h3>
-            <div class="card-info">
-                <p><strong>访问类型:</strong>公开</p>
-                <p><strong>建设单位:</strong>青浦区环境局</p>
-                <p><strong>建设时间:</strong>2024.10.25</p>
-            </div>
-            </div>
 
-            <div class="application-card">
-            <div class="card-image">
-                <img src="~@/assets/images/common/app-bg-4.png" alt="青浦区消防救援支队一网统管平台" />
-            </div>
-            <h3 class="card-title">青浦区消防救援支队一网统管平台</h3>
-            <div class="card-info">
-                <p><strong>访问类型:</strong>公开</p>
-                <p><strong>建设单位:</strong>青浦区环境局</p>
-                <p><strong>建设时间:</strong>2024.10.25</p>
-            </div>
+
+      <!-- <div v-for="useCaseItem in examplelist" :key="useCaseItem.title" :id="useCaseItem.title === '统建应用' ? 'tjyy' : useCaseItem.title === '应用支撑' ? 'yyzc' : ''">
+        <div class="title " v-if="useCaseItem.title != '基础能力'"  style="margin: 50px 0px;display: flex;justify-content: space-between;align-items: baseline;">
+          <div></div>
+          <div style="font-size: 24px;margin-top: 10px;text-align: center;font-weight: bold;">{{useCaseItem.title}}</div>
+          <div style="color: #ADE8FE;cursor: pointer;" @click="handleEnterClick">查看更多></div>
+        </div>
+        <div class="warp-container" v-if="useCaseItem.title != '基础能力'" >
+          <div class="warp-page-card" v-for="item in useCaseItem.data" :key="item.title" @click="handleTabsOpenPage(item)">
+            <div class="warp-page-img" :style="`background-image: url(${item.picture});`"></div>
+            <div class="warp-page-text">
+              <div class="warp-page-text-title">{{ item.title }}</div>
+              <div class="warp-page-text-desc">{{ item.text }}</div>
             </div>
-       </div> -->
+          </div>
+
+        </div>
+      </div> -->
+
     </div>
+
   </div>
 </template>
 
@@ -72,17 +90,45 @@ export default {
   data() {
     return {
       applications:[],
-      curUrl:systemConfig.dmsDataProxy
+      appCenterlications:[],
+      itemAppCenterlications:[],
+      tagOptions: [],
+      curUrl:systemConfig.dmsDataProxy,
+      examplelist:systemConfig.examplelist,
     }
   },
   mounted() {
     this.initData()
   },
   methods: {
-    handleEnterClick() {
+    handleEnterClick(val) {
+      let tag = this.tagOptions.find((info)=>info.value == val).label;
+      sessionStorage.setItem('activeTag', parseInt(tag));
       this.$router.push('appCenter');
     },
     initData() {
+      this.getDmsTagSName();
+    },
+    getDmsTagSName() {
+      let requestParams = {
+        sName: "tag",
+      };
+      appCenter.getDmsSName(requestParams).then((res) => {
+        if (res.code === 200) {
+          this.tagOptions = res.content.map((item) => ({
+            label: item.index,
+            value: item.name,
+          }));
+          this.appCenterlications = res.content.map((item) => ({
+            title: item.name,
+            data: [],
+          }));
+          this.getDmsDataList();
+        }
+      });
+    },
+    //示范数据
+    getDmsSFDataList(){
       let requestParams = {
         columnId: systemConfig.columnIds[0], // 应用中心栏目id(示范应用)
         states: 0,
@@ -102,15 +148,69 @@ export default {
         }
       })
     },
+    // 应用中心数据
+    getDmsDataList() {
+       let requestParams = {
+        columnId: systemConfig.columnIds[1], // 应用中心栏目id
+        states: 0,
+        orderBy: JSON.stringify([{"field":"frame_time","orderByType":2}]),
+        pageSize: 9999,
+        page: 0
+      };
+      appCenter.getDmsDataList(requestParams).then((res) => {
+        if (res.code === 200) {
+           let arr = res.content.data.map((item) => ({
+            ...item,
+            tags: item.apptags.split(',').map(tag => this.tagOptions.find(info => info.label == tag.trim())?.value || ''),
+            createTime: moment(item.create_time).format('YYYY-MM-DD HH:mm:ss')
+          }))
+          this.appCenterlications.forEach(item => {
+             arr.forEach(info => {
+                if(info.tags.includes(item.title) == true && info.issf != '0'){
+                  let str = {
+                      id:info.id,
+                      tags: ["盈浦街道", "夏阳街道"],
+                      title: info.title,
+                      text: info.content,
+                      picture: info.c_picture,
+                      url:info.c_url
+                  }
+                  item.data.push(str);
+                }
+              })
+          })
+          console.log(this.appCenterlications);
+        } else {
+          this.appCenterlications = [];
+        }
+      });
+    },
+    handleTabsOpenPage(item){
+        if(item.url){
+          window.open(item.url);
+        }
+    }
+
   }
 }
 </script>
 
 <style lang="less" scoped>
+
+:deep(.el-carousel__arrow--left) {
+  background: #18a6ff; /* 左箭头背景色 */
+  opacity: 0.8;
+}
+
+:deep(.el-carousel__arrow--right) {
+  background: #18a6ff; /* 右箭头背景色 */
+  opacity: 0.8;
+}
+
 .application-center {
   width: 100%;
   min-height: 100vh;
-  background-color: #08224a;
+  background-color: #01012f;
   color: #ffffff;
   overflow-x: hidden;
 }
@@ -118,49 +218,52 @@ export default {
 /* 顶部横幅样式 */
 .banner {
   width: 100%;
-  height: calc(100vh - 120px);
-  background: url(~@/assets/images/common/u720.png) no-repeat center center;
+  // height: calc(100vh - 120px);
+  height: 552px;
+  background: url('@static/images/yyzx/bg.png');
   background-size: cover;
   display: flex;
-  justify-content: center;
-  align-items: center;
+  justify-content: right;
+  align-items: start;
   position: relative;
   overflow: hidden;
 
-  &::before {
-    content: '';
-    position: absolute;
-    top: 0;
-    left: 0;
-    width: 100%;
-    height: 100%;
-    background: rgba(8, 34, 74, 0.7);
-    z-index: 1;
-  }
+  // &::before {
+  //   content: '';
+  //   position: absolute;
+  //   top: 0;
+  //   left: 0;
+  //   width: 100%;
+  //   height: 100%;
+  //   background: rgba(8, 34, 74, 0.7);
+  //   z-index: 1;
+  // }
 
   .banner-content {
     position: relative;
     z-index: 2;
-    text-align: center;
-    max-width: 800px;
-    padding: 0 20px;
+    text-align: right;
+    max-width: 500px;
+    padding: 0 10%;
+    justify-content: right;
+    display: grid;
+    padding-top: 100px;
   }
 
   .banner-title {
-    font-size: 64px;
+    font-size: 56px;
     font-weight: bold;
-    letter-spacing: 0.5rem;
-    margin-bottom: 20px;
+    // letter-spacing: 0.5rem;
+    // margin-bottom: 20px;
     color: #ffffff;
-    text-align: left;
+    text-align: right;
     text-shadow: 0 2px 10px rgba(0, 0, 0, 0.5);
   }
 
   .banner-description {
-    font-size: 22px;
-    line-height: 1.8;
-    margin-bottom: 40px;
-    margin-top: 70px;
+    font-size: 16px;
+    // line-height: 1.8;
+    margin: 20px 0px; 
     text-align: left;
     color: rgba(255, 255, 255, 0.9);
   }
@@ -183,10 +286,13 @@ export default {
 
 /* 示范应用区域样式 */
 .demo-applications {
-  padding: 60px 20px;
+  // padding: 60px 20px;
 //   max-width: 1400px;
-  width: 80%;
+  // width: 80%;
   margin: 0 auto;
+  padding-left: 120px;
+  padding-right: 120px;
+  padding-bottom: 120px;
 
   .section-title {
     text-align: center;
@@ -303,4 +409,65 @@ export default {
     }
   }
 }
+
+.el-carousel__item:nth-child(2n) {
+    background-color: #01012f;
+    border-radius: 20px;
+  }
+
+  .el-carousel__item:nth-child(2n + 1) {
+    background-color: #01012f;
+    border-radius: 20px;
+}
+
+.warp-container{
+    display: grid;
+    justify-content: flex-start;
+    align-items: center;
+    grid-template-columns: repeat(auto-fit, minmax(500px, 1fr));
+    gap: 30px;
+  .warp-page-card{
+    cursor: pointer;
+    justify-content: flex-start;
+    width: 100%;
+    height: 600px;
+    // display: grid;
+    border: 1px solid transparent;
+    border-radius: 16px;
+    background-clip: padding-box, border-box;
+    background-origin: padding-box, border-box;
+    background-image: linear-gradient(345deg, #08113e, #2220), linear-gradient(345deg, #fffdfd6b, #00000000, #00000000, #00000000);
+    .warp-page-img{
+      cursor: pointer;
+      height: 400px;
+      background-size: cover;
+      border-radius: 16px 16px 0px 0px;
+    }
+    .warp-page-text{
+      padding: 0px 20px 20px 20px;
+      // height: 200px;
+      // font-size: 24px;
+      color: #c7c2c2;
+      .warp-page-text-title{
+        font-weight: bold;
+        margin: 10px 0px;
+        color: #ffffff;
+      }
+      .warp-page-text-desc{
+        display: -webkit-box;
+        -webkit-box-orient: vertical;
+        -webkit-line-clamp: 5; /* 限制显示4行 */
+        line-clamp: 5; /* 标准属性 */
+        overflow: hidden;
+        text-overflow: ellipsis;
+      }
+    }
+    transition: all 0.3s ease;
+    // &:hover {
+    //   background-color: #152736;
+    //   transform: translateY(-5px);
+    //   box-shadow: 0 4px 12px rgba(24, 144, 255, 0.4);
+    // }
+  }
+}
 </style>

+ 1 - 1
src/views/yygl/manage/index.vue

@@ -554,7 +554,7 @@ export default {
   display: flex;
   align-items: center;
   // flex: 1;
-  width: 400px;
+  width: 410px;
   gap: 15px;
 }
 

+ 2 - 1
src/views/yygl/monitor/index.vue

@@ -555,7 +555,8 @@ export default {
 /* 右侧主内容区 */
 .main-content {
   flex: 1;
-  padding: 20px 30px;
+  // padding: 20px 30px;
+  padding: 20px 30px 100px 20px;
   overflow-y: auto;
 }
 

+ 36 - 18
src/views/yygl/overview/index.vue

@@ -20,12 +20,17 @@
             
 
             <!-- 应用范围过滤 -->
-            <div class="filter-tabs">
+            <!-- <div class="filter-tabs">
                 <el-radio-group v-model="activeTab" size="medium" @change="handleTabChange" v-for="item in buffOptions" :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="filter-group">
+              <el-radio-group v-model="tagFilter" size="medium" @change="handleTagFilterChange" v-for="item in tagOptions" :key="item.value">
+                <el-radio-button :label="item.label">{{ item.value }}</el-radio-button>
+              </el-radio-group>
             </div>
         </div>
     
@@ -33,7 +38,13 @@
       <div class="app-content">
         <div class="applications-grid">
           <div class="application-card" v-for="(app, index) in applications" :key="index">
+            
             <div class="card-image">
+              <div v-if="app.issf != '0'" style="position: absolute;background: #0e3a74;border-radius: 5px 0px 5px 0px;width: 30px;height: 30px;">
+                <el-icon :size="20" color="yellow" style="position: relative;left: 5px;top: 5px;">
+                  <StarFilled />
+                </el-icon>
+              </div>
               <img :src="curUrl + app.c_picture" :alt="app.title" />
             </div>
             <div class="card-content">
@@ -54,7 +65,7 @@
                   type="primary"
                   size="small"
                   class="visit-button"
-                  @click="handleVisit"
+                  @click="handleOpenPage(app)"
                   >访问</el-button
                 >
               </div>
@@ -79,6 +90,7 @@ export default {
     return {
       searchKeyword: '',
       activeTab: 'all',
+      tagFilter: sessionStorage.getItem('activeTag') ? parseInt(sessionStorage.getItem('activeTag')) : 'all',
       curUrl:systemConfig.dmsDataProxy,
       buffOptions: [],
       tagOptions: [],
@@ -98,20 +110,24 @@ export default {
         this.applications = this.itemApplications.filter(item => item.appbuff == this.activeTab);
       }
     },
+    handleTagFilterChange() {
+      if (this.tagFilter == 'all') {
+        sessionStorage.setItem('activeTag', "");
+        this.applications = this.itemApplications;
+      } else {
+        sessionStorage.setItem('activeTag', this.tagFilter);
+        this.applications = this.itemApplications.filter(item => item.apptags.split(",").includes(this.tagFilter.toString()));
+      }
+    },
     initData() {
       this.getDmsCNameAType();
       this.getDmsTagSName();
       this.getDmsDataList();
     },
-    handleVisit() {
-      // http://localhost:2027/fileView?url=/proxy_dms/static/1_青浦大数据中心一张图功能表20240531.xlsx
-      // http://localhost:2027/fileView?url=/proxy_dms/static/test.geojson
-      // window.open(
-      //   "fileView?url=" +
-      //     this.curUrl +
-      //     "/static/1_青浦大数据中心一张图功能表20240531.xlsx",
-      //   "_blank"
-      // );
+    handleOpenPage(param) {
+      if(param.c_url){
+          window.open(param.c_url);
+      }
     },
     getDmsTagSName() {
       let requestParams = {
@@ -190,7 +206,8 @@ export default {
             createTime: moment(item.create_time).format('YYYY-MM-DD HH:mm:ss')
           }))
           this.applications = this.itemApplications;
-          this.handleTabChange();
+          // this.handleTabChange();
+          this.handleTagFilterChange();
         } else {
           this.applications = [];
         }
@@ -277,7 +294,7 @@ export default {
 }
 .app-content{
     // height: 640px;
-    height: calc(100vh - 266px);
+    height: calc(100vh - 160px);
     overflow: auto;
     padding-right: 20px;
 }
@@ -307,6 +324,7 @@ export default {
     width: 100%;
     height: 160px;
     overflow: hidden;
+    position: relative;
 
     img {
       width: 100%;
@@ -315,9 +333,9 @@ export default {
       transition: transform 0.3s ease;
     }
 
-    &:hover img {
-      transform: scale(1.05);
-    }
+    // &:hover img {
+    //   transform: scale(1.05);
+    // }
   }
 
   .card-content {

+ 1 - 1
vue.config.js

@@ -20,7 +20,7 @@ module.exports = defineConfig({
       filename: 'index.html',
       // 当使用 title 选项时,
       // template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
-      title: '青浦一张图',
+      title: '青浦区“一张图”区级节点',
       // 在这个页面中包含的块,默认情况下会包含
       // 提取出来的通用 chunk 和 vendor chunk。
       chunks: ['chunk-vendors', 'chunk-common', 'index']

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