ソースを参照

闲置厂房地图功能

yin_yu820 1 日 前
コミット
4c3abef2f5

+ 11 - 0
jp-console/jeeplus-module/ly/src/main/java/com/jeeplus/idlefactorybuildings/controller/IdleFactoryBuildingsController.java

@@ -136,6 +136,17 @@ public class IdleFactoryBuildingsController {
 		return ResponseEntity.ok (map);
 	}
 
+	/**
+	 *板块统计
+	 */
+	@ApiLog("板块统计")
+	@ApiOperation(value = "板块统计")
+	@GetMapping("getParkList")
+	public ResponseEntity<List<HashMap<String, Object>>> getParkList() throws Exception {
+		List<HashMap<String, Object>> map=idleFactoryBuildingsService.getParkList();
+		return ResponseEntity.ok (map);
+	}
+
 
 	/**
 	 * 根据Id获取闲置厂房数据

+ 2 - 0
jp-console/jeeplus-module/ly/src/main/java/com/jeeplus/idlefactorybuildings/mapper/IdleFactoryBuildingsMapper.java

@@ -26,5 +26,7 @@ public interface IdleFactoryBuildingsMapper extends BaseMapper<IdleFactoryBuildi
     IPage<IdleFactoryBuildingsDTO> findList(Page<IdleFactoryBuildingsDTO> page, @Param(Constants.WRAPPER) QueryWrapper queryWrapper);
     IdleFactoryBuildingsDTO findById(String id);
     List<HashMap<String, Object>> getDictList(String type);
+    List<HashMap<String, Object>> getParkList();
+
 
 }

+ 13 - 0
jp-console/jeeplus-module/ly/src/main/java/com/jeeplus/idlefactorybuildings/mapper/xml/IdleFactoryBuildingsMapper.xml

@@ -61,4 +61,17 @@
 		where b.type=#{type} ORDER BY a.sort asc
 	</select>
 
+	<select id="getParkList" resultType="map">
+		SELECT a.label,
+			   COUNT(b.id)  AS building_cnt,
+			   IFNULL(SUM(b.idle_area),0) AS total_idle_area,
+			   IFNULL(SUM(b.area),0) AS total_area
+		FROM sys_dict_value a
+				 LEFT JOIN ly_idle_factory_buildings b
+				 ON a.value = b.park
+				 AND b.del_flag = 0 and b.state=1
+		WHERE a.dict_type_id = '1995785139824984065'
+		GROUP BY a.label;
+	</select>
+
 </mapper>

+ 5 - 0
jp-console/jeeplus-module/ly/src/main/java/com/jeeplus/idlefactorybuildings/service/IdleFactoryBuildingsService.java

@@ -40,4 +40,9 @@ public class IdleFactoryBuildingsService extends ServiceImpl<IdleFactoryBuilding
         return baseMapper.getDictList (type);
     }
 
+    public List<HashMap<String, Object>> getParkList() {
+        return baseMapper.getParkList ();
+    }
+
+
 }

+ 1 - 0
jp-console/jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/security/config/WebSecurityConfig.java

@@ -90,6 +90,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
                         "/idlefactorybuildings/idleFactoryBuildings/list2",
                         "/idlefactorybuildings/idleFactoryBuildings/queryById2",
                         "/idlefactorybuildings/idleFactoryBuildings/getDictList",
+                        "/idlefactorybuildings/idleFactoryBuildings/getParkList",
 
                         "/dp/dp/getDzfCount",
                         "/dp/dp/getZcs",

+ 7 - 0
jp-mobile/api/auth/loginService.js

@@ -59,6 +59,13 @@ export default {
 		})
 	},
 	
+	getParkList: function() {
+		return request({
+			url: '/idlefactorybuildings/idleFactoryBuildings/getParkList',
+			method: 'get',
+		})
+	},
+	
 	
 	
 	policyList: function (params) {

+ 1 - 1
jp-mobile/common/config.js

@@ -3,7 +3,7 @@ let APP_SERVER_URL = ""
 if(process.env.NODE_ENV === 'development'){
     // 开发环境    http://47.97.69.114:8088/#/login 
     //APP_SERVER_URL = 'http://47.97.69.114:8088/panhuangly/'
-	APP_SERVER_URL = 'http://192.168.139.31:8072'
+	APP_SERVER_URL = 'http://192.168.139.34:8072'
 	//APP_SERVER_URL = 'https://ydwqfw.com.cn/yd_qycpfbWeb/yd_qycpfb'
 }else{
     // 生产环境

+ 16 - 0
jp-mobile/pages.json

@@ -49,6 +49,22 @@
 			"style": {}
 		},
 		
+		{
+			"path": "pages/index/factoryindex2",
+			"style": {}
+		},
+		{
+			"path": "pages/index/factoryindex3",
+			"style": {}
+		},
+		{
+			"path": "pages/index/factoryindex4",
+			"style": {}
+		},
+		{
+			"path": "pages/index/factoryindex5",
+			"style": {}
+		},
 		{
 			"path": "pages/factoryBuildings/factoryBuildingsList",
 			"style": {}

+ 84 - 84
jp-mobile/pages/index/factoryindex.vue

@@ -2,7 +2,7 @@
   <view class="page">
     <!-- 1. 顶部标题 -->
     <view class="header">
-      <text class="title">盐都区闲置厂房分布</text>
+      <text class="title">{{title}}</text>
     </view>
 
     <!-- 2. 轮播图 -->
@@ -19,100 +19,79 @@
       </swiper-item>
     </swiper>
 
-    <!-- 3. 地图 -->
+    <!-- 3. 九宫格导航 -->
+    <view class="grid-box">
+      <view
+        v-for="(item,index) in parkList2"
+        :key="index"
+        class="grid-card"
+        @tap="goListByValue(item.value)"
+      >
+        <text class="grid-label">{{item.label}}</text>
+      </view>
+    </view>
+
+    <!-- 地图已注释,如需恢复直接放开即可 -->
+    <!--
     <view class="map-box">
-      <canvas
-        canvas-id="ydChart"
-        id="ydChart"
-        class="map-canvas"
-      />
+      <view @touchend="onTouchEnd" class="map-wrap">
+        <canvas canvas-id="ydChart" id="ydChart" class="map-canvas" />
+      </view>
     </view>
+    -->
   </view>
 </template>
 
 <script>
-import * as echarts from 'echarts'
+// import * as echarts from 'echarts'   // 如不用地图可注释
 
 export default {
   data() {
     return {
-      chart: null,
-      /* 轮播图示例,换成你的真实图片即可 */
-      picture:["https://ydwqfw.com.cn/yd_qycpfbH5/bg1.jpg",
-      "https://ydwqfw.com.cn/yd_qycpfbH5/bg2.jpg",
-      "https://ydwqfw.com.cn/yd_qycpfbH5/bg3.jpg",
-      "https://ydwqfw.com.cn/yd_qycpfbH5/bg4.jpg"],
+      title: '盐都区闲置厂房分布图',
+      picture: [
+        'https://ydwqfw.com.cn/yd_qycpfbH5/bg1.jpg',
+        'https://ydwqfw.com.cn/yd_qycpfbH5/bg2.jpg',
+        'https://ydwqfw.com.cn/yd_qycpfbH5/bg3.jpg',
+        'https://ydwqfw.com.cn/yd_qycpfbH5/bg4.jpg'
+      ],
+      parkList2: [
+        { label: '全部', value: '' },
+        { label: '台创园', value: '台创园' },
+        { label: '大冈', value: '大冈镇' },
+        { label: '大纵湖', value: '大纵湖镇' },
+        { label: '学富', value: '学富镇' },
+        { label: '尚庄', value: '尚庄镇' },
+        { label: '张庄', value: '张庄街道' },
+        { label: '楼王', value: '楼王镇' },
+        { label: '潘黄', value: '潘黄街道' },
+        { label: '盐渎', value: '盐渎街道' },
+        { label: '秦南', value: '秦南镇' },
+        { label: '郭猛', value: '郭猛镇' },
+        { label: '高新区', value: '盐龙街道' },
+        { label: '龙冈', value: '龙冈镇' }
+      ]
     }
   },
+
+  /* 地图相关生命周期,如不用可全部注释
   async onReady() {
     const json = await this.loadGeoJSON()
     echarts.registerMap('yanduqu', json)
-
-    let canvasNode
-    // #ifdef H5
-    canvasNode = document.getElementById('ydChart')
-    // #endif
-    // #ifndef H5
-    canvasNode = await new Promise(resolve => {
-      uni.createSelectorQuery()
-        .in(this)
-        .select('#ydChart')
-        .node(res => resolve(res.node))
-        .exec()
-    })
-    // #endif
-
-    this.chart = echarts.init(canvasNode, null, {
-      width : uni.getSystemInfoSync().windowWidth,
-      height: uni.getSystemInfoSync().windowHeight * 0.6   // 地图占屏幕 50%
-    })
-    this.renderMap()
+    ...
   },
   methods: {
-    loadGeoJSON() {
-      return new Promise((resolve, reject) => {
-        uni.request({
-          url: './static/yandu.json',
-          method: 'GET',
-          success: res => resolve(res.data),
-          fail: reject
-        })
-      })
-    },
-    renderMap() {
-      const option = {
-         geo: [{
-              map: 'yanduqu',
-              roam: false,
-              aspectScale: 1.2,
-              zoom: 1.1,
-              itemStyle: {
-                areaColor: '#4ea397',
-                borderColor: '#fff',
-                borderWidth: 1
-              },
-              emphasis: {
-                itemStyle: { areaColor: '#ffca28' }
-              },
-              // 关键:打开标签
-              label: {
-                show: true,          // 默认显示名称
-                color: '#fff',       // 文字颜色
-                fontSize: 14,        // 字号
-                fontWeight: 'bold',
-                textBorderColor: 'rgba(85, 85, 255, 0.7)', // 描边让字更清晰
-                textBorderWidth: 2
-              }
-            }],
-            series: [{ type: 'map', geoIndex: 0, data: [] }]
-      }
-      this.chart.setOption(option)
+    loadGeoJSON() { ... },
+    onTouchEnd(e)  { ... },
+    renderMap()    { ... }
+  }
+  */
 
-      this.chart.on('click', params => {
-		uni.navigateTo({
-			url: `/pages/factoryBuildings/factoryBuildingsList?parkid=${params.name}`
-		})
-				
+  methods: {
+    // 九宫格跳转
+    goListByValue(val) {
+      uni.navigateTo({
+        url: `/pages/factoryBuildings/factoryBuildingsList?parkid=${val}`
       })
     }
   }
@@ -123,7 +102,7 @@ export default {
 .page {
   display: flex;
   flex-direction: column;
-  height: 100vh;
+  min-height: 100vh;
   background: #f5f5f5;
 }
 
@@ -149,13 +128,34 @@ export default {
   height: 100%;
 }
 
-/* 地图容器 */
-.map-box {
-  flex: 1;
+/* 九宫格区域 */
+.grid-box {
   width: 100%;
+  padding: 30rpx;
+  box-sizing: border-box;
+  display: grid;
+  grid-template-columns: repeat(3, 1fr);
+  gap: 24rpx;
+  background: #fff;
 }
-.map-canvas {
-  width: 100%;
-  height: 100%;
+
+.grid-card {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  height: 160rpx;
+  background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
+  border-radius: 16rpx;
+  box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.08);
+  transition: transform 0.15s;
+}
+.grid-card:active {
+  transform: scale(0.96);
+}
+
+.grid-label {
+  font-size: 30rpx;
+  font-weight: 600;
+  color: #fff;
 }
 </style>

+ 138 - 0
jp-mobile/pages/index/factoryindex2.vue

@@ -0,0 +1,138 @@
+<template>
+  <view class="page">
+    <!-- 1. 顶部标题 -->
+    <view class="header">
+      <text class="title">{{title}}</text>
+    </view>
+
+    <!-- 2. 轮播图 -->
+    <swiper
+      class="swiper"
+      circular
+      :indicator-dots="true"
+      :autoplay="true"
+      :interval="3000"
+      :duration="800"
+    >
+      <swiper-item v-for="(item, index) in picture" :key="index">
+        <image :src="item" class="swiper-item" mode="aspectFill" />
+      </swiper-item>
+    </swiper>
+
+    <!-- 3. 九宫格 -->
+    <view class="grid-box">
+      <view
+        v-for="(item, index) in parkList2"
+        :key="index"
+        class="grid-item"
+        @tap="goList(item.value)"
+      >
+        <image class="grid-icon" :src="item.icon" mode="aspectFit" />
+        <text class="grid-label">{{ item.label }}</text>
+      </view>
+    </view>
+	
+	
+  </view>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      title: '盐都区闲置厂房分布图',
+      picture: [
+        'https://ydwqfw.com.cn/yd_qycpfbH5/bg1.jpg',
+        'https://ydwqfw.com.cn/yd_qycpfbH5/bg2.jpg',
+        'https://ydwqfw.com.cn/yd_qycpfbH5/bg3.jpg',
+        'https://ydwqfw.com.cn/yd_qycpfbH5/bg4.jpg'
+      ],
+      // 九宫格数据
+      parkList2: [
+        { label: '全部',   value: '', icon: '/static/icon/all.png' },
+        { label: '台创园', value: '台创园', icon: '/static/icon/taichuang.png' },
+        { label: '大冈',   value: '大冈镇', icon: '/static/icon/dagang.png' },
+        { label: '大纵湖', value: '大纵湖镇', icon: '/static/icon/dazonghu.png' },
+        { label: '学富',   value: '学富镇', icon: '/static/icon/xuefu.png' },
+        { label: '尚庄',   value: '尚庄镇', icon: '/static/icon/shangzhuang.png' },
+        { label: '张庄',   value: '张庄街道', icon: '/static/icon/zhangzhuang.png' },
+        { label: '楼王',   value: '楼王镇', icon: '/static/icon/louwang.png' },
+        { label: '潘黄',   value: '潘黄街道', icon: '/static/icon/panhuang.png' },
+        { label: '盐渎',   value: '盐渎街道', icon: '/static/icon/yandu.png' },
+        { label: '秦南',   value: '秦南镇', icon: '/static/icon/qinnan.png' },
+        { label: '郭猛',   value: '郭猛镇', icon: '/static/icon/guomeng.png' },
+        { label: '高新区', value: '盐龙街道', icon: '/static/icon/gxq.png' },
+        { label: '龙冈',   value: '龙冈镇', icon: '/static/icon/longgang.png' }
+      ]
+    }
+  },
+  methods: {
+    // 与之前保持一致
+    goList(parkid) {
+      uni.navigateTo({
+        url: `/pages/factoryBuildings/factoryBuildingsList?parkid=${parkid}`
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+/* 原有样式不变,仅新增宫格 */
+.page {
+  display: flex;
+  flex-direction: column;
+  height: 100vh;
+  background: #f5f5f5;
+}
+.header {
+  padding: 20rpx 0;
+  text-align: center;
+  background: #fff;
+}
+.title {
+  font-size: 36rpx;
+  font-weight: bold;
+  color: #333;
+}
+.swiper {
+  width: 100%;
+  height: 300rpx;
+}
+.swiper-item {
+  width: 100%;
+  height: 100%;
+}
+
+/* 九宫格 */
+.grid-box {
+  flex: 1;
+  display: flex;
+  flex-wrap: wrap;
+  padding: 20rpx;
+  box-sizing: border-box;
+  background: #f5f5f5;
+}
+.grid-item {
+  width: 33.33%;
+  height: 180rpx;
+  display: flex;
+  flex-direction: column;   /* 图标在上,文字在下 */
+  align-items: center;
+  justify-content: center;
+  border: 1rpx solid #e0e0e0;
+  border-radius: 15rpx;	
+  margin: 0 -1rpx -1rpx 0;  /* 消除双边框 */
+  box-sizing: border-box;
+  background: #fff;
+}
+.grid-icon {
+  width: 96rpx;   /* 48px */
+  height: 96rpx;
+  margin-bottom: 10rpx;
+}
+.grid-label {
+  font-size: 28rpx;
+  color: #333;
+}
+</style>

+ 211 - 0
jp-mobile/pages/index/factoryindex3.vue

@@ -0,0 +1,211 @@
+<template>
+  <view class="page">
+    <!-- 1. 顶部标题 -->
+    <view class="header">
+      <text class="title">{{ title }}</text>
+    </view>
+
+    <!-- 2. 轮播图 -->
+    <swiper
+      class="swiper"
+      circular
+      :indicator-dots="true"
+      :autoplay="true"
+      :interval="3000"
+      :duration="800"
+    >
+      <swiper-item v-for="(item, index) in picture" :key="index">
+        <image :src="item" class="swiper-item" mode="aspectFill" />
+      </swiper-item>
+    </swiper>
+
+    <!-- 3. 横向滑动园区卡片 -->
+    <view class="panel">
+      <view class="panel-title">选择园区</view>
+      <scroll-view scroll-x class="card-scroll">
+        <view
+          v-for="(item,index) in parkList2"
+          :key="index"
+          class="card"
+          @tap="goListByValue(item.label)"
+        >
+          <image
+            class="card-bg"
+            :src="item.bg||defaultBg"
+            mode="aspectFill"
+          />
+          <view class="card-mask" />
+          <view class="card-content">
+            <text class="card-name">{{ item.label }}</text>
+            <text class="card-count">闲置厂房 {{ item.building_cnt||0 }} 处</text>
+          </view>
+        </view>
+
+        <!-- 末尾「全部」按钮 -->
+        <view class="card all" @tap="goListByValue('')">
+          <text class="all-txt">盐都区园区</text>
+		  <text class="all-txt2">总闲置 {{allcount}} 处</text>
+        </view>
+      </scroll-view>
+    </view>
+
+    <!-- 地图已注释 -->
+    <!--
+    <view class="map-box">
+      <canvas canvas-id="ydChart" id="ydChart" class="map-canvas" />
+    </view>
+    -->
+  </view>
+</template>
+
+<script>
+	import loginService from "@/api/auth/loginService";
+export default {
+  data() {
+    return {
+      title: '盐都区闲置厂房分布图',
+      defaultBg: 'https://ydwqfw.com.cn/yd_qycpfbH5/bg2.jpg', // 默认封面
+      picture: [
+        'https://ydwqfw.com.cn/yd_qycpfbH5/bg1.jpg',
+        'https://ydwqfw.com.cn/yd_qycpfbH5/bg2.jpg',
+        'https://ydwqfw.com.cn/yd_qycpfbH5/bg3.jpg',
+        'https://ydwqfw.com.cn/yd_qycpfbH5/bg4.jpg'
+      ],
+	  parkList2: [],
+	  allcount:0,
+	  
+    }
+  },
+  
+  onShow() {
+  	loginService.getParkList().then(({
+  		data
+  	}) => {
+		let alls=0;
+		for(var i = 0; i < data.length; i++){
+			alls=alls+data[i].building_cnt;
+		}
+		
+		this.allcount=alls;		
+		this.parkList2=data;
+		this.parkList2.unshift({total_area: 0, total_idle_area: 0, building_cnt: alls, label: "全部"})
+		
+  	}).catch(e => {
+  		
+  	})
+  	
+  },
+  methods: {
+    goListByValue(val) {
+      uni.navigateTo({
+        url: `/pages/factoryBuildings/factoryBuildingsList?parkid=${val}`
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.page {
+  display: flex;
+  flex-direction: column;
+  min-height: 100vh;
+  background: #f5f5f5;
+}
+
+.header {
+  padding: 20rpx 0;
+  text-align: center;
+  background: #fff;
+}
+.title {
+  font-size: 36rpx;
+  font-weight: bold;
+  color: #333;
+}
+
+.swiper {
+  width: 100%;
+  height: 300rpx;
+}
+.swiper-item {
+  width: 100%;
+  height: 100%;
+}
+
+/* 横向卡片区域 */
+.panel {
+  background: #fff;
+  padding: 30rpx 0;
+}
+.panel-title {
+  padding: 0 30rpx 20rpx;
+  font-size: 32rpx;
+  font-weight: 600;
+  color: #333;
+}
+.card-scroll {
+  white-space: nowrap;
+  padding: 0 30rpx;
+}
+.card {
+  position: relative;
+  display: inline-flex;
+  flex-direction: column;
+  justify-content: flex-end;
+  width: 240rpx;
+  height: 300rpx;
+  border-radius: 16rpx;
+  overflow: hidden;
+  margin-right: 20rpx;
+  box-shadow: 0 8rpx 16rpx rgba(0,0,0,.08);
+}
+.card-bg {
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  z-index: 1;
+}
+.card-mask {
+  position: absolute;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  height: 60%;
+  background: linear-gradient(to bottom, transparent, rgba(0,0,0,.6));
+  z-index: 2;
+}
+.card-content {
+  position: relative;
+  z-index: 3;
+  padding: 20rpx;
+  color: #fff;
+}
+.card-name {
+  display: block;
+  font-size: 30rpx;
+  font-weight: 600;
+}
+.card-count {
+  display: block;
+  margin-top: 8rpx;
+  font-size: 24rpx;
+  opacity: .9;
+}
+
+/* 全部按钮 */
+.card.all {
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  justify-content: center;
+  align-items: center;
+}
+.all-txt {
+  font-size: 30rpx;
+  font-weight: 600;
+  color: #fff;
+}
+.all-txt2 {
+  font-size: 25rpx;
+  color: #fff;
+}
+</style>

+ 234 - 0
jp-mobile/pages/index/factoryindex4.vue

@@ -0,0 +1,234 @@
+<template>
+  <view class="page">
+    <!-- 1. 顶部标题 -->
+    <view class="header">
+      <text class="title">{{title}}</text>
+    </view>
+
+    <!-- 2. 轮播图 -->
+    <swiper
+      class="swiper"
+      circular
+      :indicator-dots="true"
+      :autoplay="true"
+      :interval="3000"
+      :duration="800"
+    >
+      <swiper-item v-for="(item, index) in picture" :key="index">
+        <image :src="item" class="swiper-item" mode="aspectFill" />
+      </swiper-item>
+    </swiper>
+
+    <!-- 3. 地图 -->
+    <view class="map-box">
+      <view @touchend="onTouchEnd" class="map-wrap">
+        <canvas canvas-id="ydChart" id="ydChart" class="map-canvas" />
+      </view>
+    </view>
+  </view>
+</template>
+
+<script>
+import * as echarts from 'echarts'
+
+export default {
+  data() {
+    return {
+      chart: null,
+	  title:'盐都区闲置厂房分布图',
+      /* 轮播图示例,换成你的真实图片即可 */
+      picture:["https://ydwqfw.com.cn/yd_qycpfbH5/bg1.jpg",
+      "https://ydwqfw.com.cn/yd_qycpfbH5/bg2.jpg",
+      "https://ydwqfw.com.cn/yd_qycpfbH5/bg3.jpg",
+      "https://ydwqfw.com.cn/yd_qycpfbH5/bg4.jpg"],
+    }
+  },
+  async onReady() {
+    const json = await this.loadGeoJSON()
+    echarts.registerMap('yanduqu', json)
+
+    let canvasNode
+    // #ifdef H5
+    canvasNode = document.getElementById('ydChart')
+    // #endif
+    // #ifndef H5
+    canvasNode = await new Promise(resolve => {
+      uni.createSelectorQuery()
+        .in(this)
+        .select('#ydChart')
+        .node(res => resolve(res.node))
+        .exec()
+    })
+    // #endif
+
+    this.chart = echarts.init(canvasNode, null, {
+      width : uni.getSystemInfoSync().windowWidth,
+      height: uni.getSystemInfoSync().windowHeight * 0.6   // 地图占屏幕 50%
+    })
+    this.renderMap()
+  },
+  methods: {
+    loadGeoJSON() {
+      return new Promise((resolve, reject) => {
+        uni.request({
+          url: './static/yandu.json',
+          method: 'GET',
+          success: res => resolve(res.data),
+          fail: reject
+        })
+      })
+    },
+	goList(parkName) {
+
+	    // 真正跳转
+	    uni.navigateTo({
+	      url: `/pages/factoryBuildings/factoryBuildingsList?parkid=${parkName}`
+	    })
+	},
+	onTouchEnd(e) {
+		
+	  const touch = e.changedTouches[0]
+	  uni.createSelectorQuery()
+	    .in(this)
+	    .select('.map-wrap')
+	    .boundingClientRect(rect => {
+	      const dpr = uni.getSystemInfoSync().pixelRatio        // 关键1:拿到 dpr
+	      const xCss = touch.clientX - rect.left                // CSS 像素
+	      const yCss = touch.clientY - rect.top
+	      const xCanvas = xCss ;                            // 关键2:转成 canvas 物理像素
+	      const yCanvas = yCss ;
+
+	      // 用物理像素判断
+	      const inGeo = this.chart.containPixel('geo', [xCanvas, yCanvas])
+
+	      if (inGeo) {
+	        // 拿到逻辑坐标(供 emit 用)
+	        const [lng, lat] = this.chart.convertFromPixel('geo', [xCanvas, yCanvas])
+
+	        // 直接 emit 一个 click 事件,把 name 传出去
+	        // 先用 chart.getOption().series[0].data 里匹配,这里简化:用 convert 回来的坐标反查
+	        const geoModel = this.chart.getModel().getComponent('geo', 0)
+	        const region = geoModel.coordinateSystem.getRegionByCoord([lng, lat])
+			const name = region ? region.name : ''
+			
+	        if (region) {
+	          this.goList(name)
+	        }
+	      }
+	    })
+	    .exec()
+
+	},
+	
+    renderMap() {
+      const option = {
+         geo: [{
+              map: 'yanduqu',
+              roam: true,
+              aspectScale: 1.2,
+              zoom: 1.3,
+              itemStyle: {
+				normal: {
+				  areaColor: {
+					type: 'linear-gradient',
+					x: 0,
+					y: 400,
+					x2: 0,
+					y2: 0,
+					colorStops: [{
+					  offset: 0,
+					  color: 'rgba(37,108,190,0.8)' // 0% 处的颜色
+					}, {
+					  offset: 1,
+					  color: 'rgba(15,169,195,0.8)' // 50% 处的颜色
+					}],
+					global: true // 缺省为 false
+				  },
+				  borderColor: '#4ecee6',
+				  borderWidth: 1
+				},
+				emphasis: {
+				  areaColor: {
+					type: 'linear-gradient',
+					x: 0,
+					y: 300,
+					x2: 0,
+					y2: 0,
+					colorStops: [{
+					  offset: 0,
+					  color: 'rgba(37,108,190,1)' // 0% 处的颜色
+					}, {
+					  offset: 1,
+					  color: 'rgba(15,169,195,1)' // 50% 处的颜色
+					}],
+					global: false // 缺省为 false
+				  },
+				}
+			  },
+              emphasis: {
+                itemStyle: { areaColor: '#ffca28' }
+              },
+              // 关键:打开标签
+              label: {
+                show: true,          // 默认显示名称
+                color: '#fff',       // 文字颜色
+                fontSize: 12,        // 字号
+                fontWeight: 'bold',
+              }
+            }],
+            series: [{ type: 'map', geoIndex: 0, data: [] }]
+      }
+      this.chart.setOption(option)
+
+      this.chart.on('click', params => {
+		uni.navigateTo({
+			url: `/pages/factoryBuildings/factoryBuildingsList?parkid=${params.name}`
+		})
+
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.page {
+  display: flex;
+  flex-direction: column;
+  height: 100vh;
+  background: #f5f5f5;
+}
+
+/* 顶部标题 */
+.header {
+  padding: 20rpx 0;
+  text-align: center;
+  background: #fff;
+}
+.title {
+  font-size: 36rpx;
+  font-weight: bold;
+  color: #333;
+}
+
+/* 轮播图 */
+.swiper {
+  width: 100%;
+  height: 300rpx;
+}
+.swiper-item {
+  width: 100%;
+  height: 100%;
+}
+
+/* 地图容器 */
+.map-box {
+  flex: 1;
+  width: 100%;
+  /* background: #003366; */   /* 任意你想要的深色 */
+}
+.map-canvas {
+  width: 100%;
+  height: 100%;
+}
+</style>

+ 397 - 0
jp-mobile/pages/index/factoryindex5.vue

@@ -0,0 +1,397 @@
+<template>
+  <view class="page">
+    <!-- 1. 顶部标题 -->
+    <view class="header">
+      <text class="title">{{ title }}</text>
+    </view>
+
+    <!-- 2. 轮播图 -->
+    <swiper
+      class="swiper"
+      circular
+      :indicator-dots="true"
+      :autoplay="true"
+      :interval="3000"
+      :duration="800"
+    >
+      <swiper-item v-for="(item, index) in picture" :key="index">
+        <image :src="item" class="swiper-item" mode="aspectFill" />
+      </swiper-item>
+    </swiper>
+
+    <!-- 3. 全屏地图 -->
+    <view class="map-box">
+      <view class="map-wrap">
+        <canvas canvas-id="ydChart" id="ydChart" class="map-canvas" />
+      </view>
+    </view>
+
+    <!-- 4. 悬浮按钮 -->
+    <view class="fab" @tap="openDrawer">
+      <text class="fab-txt">园区</text>
+    </view>
+
+    <!-- 5. 侧边抽屉 -->
+    <view class="drawer-mask" :class="{show: drawerOpen}" @tap="closeDrawer" />
+    <view class="drawer" :class="{show: drawerOpen}">
+      <view class="drawer-header">
+        <input
+          v-model="keyword"
+          class="search-input"
+          placeholder="搜索园区"
+          @input="onSearch"
+        />
+        <view class="mode-toggle" @tap="toggleMode">
+          <text :class="{active: mode==='grid'}">宫格</text>
+          <text :class="{active: mode==='list'}">列表</text>
+        </view>
+      </view>
+
+      <!-- 宫格模式 -->
+      <scroll-view v-if="mode==='grid'" scroll-y class="drawer-body">
+        <view class="grid-box">
+          <view
+            v-for="(item,index) in filteredList"
+            :key="index"
+            class="grid-card"
+            @tap="onSelectPark(item)"
+          >
+            <text class="grid-label">{{ item.label }}</text>
+          </view>
+        </view>
+      </scroll-view>
+
+      <!-- 列表模式 -->
+      <scroll-view v-else scroll-y class="drawer-body">
+        <view
+          v-for="(item,index) in filteredList"
+          :key="index"
+          class="list-item"
+          @tap="onSelectPark(item)"
+        >
+          <text class="list-label">{{ item.label }}</text>
+          <text class="list-count">{{ item.count||0 }} 处</text>
+        </view>
+      </scroll-view>
+    </view>
+  </view>
+</template>
+
+<script>
+import * as echarts from 'echarts'
+
+export default {
+  data() {
+    return {
+      title: '盐都区闲置厂房分布图',
+      picture: [
+        'https://ydwqfw.com.cn/yd_qycpfbH5/bg1.jpg',
+        'https://ydwqfw.com.cn/yd_qycpfbH5/bg2.jpg',
+        'https://ydwqfw.com.cn/yd_qycpfbH5/bg3.jpg',
+        'https://ydwqfw.com.cn/yd_qycpfbH5/bg4.jpg'
+      ],
+      chart: null,
+      drawerOpen: false,
+      mode: 'grid',               // grid | list
+      keyword: '',
+      parkList2: [
+        { label: '全部', value: '', count: 99 },
+        { label: '台创园', value: '1', count: 12 },
+        { label: '大冈', value: '2', count: 8 },
+        { label: '大纵湖', value: '3', count: 15 },
+        { label: '学富', value: '4', count: 6 },
+        { label: '尚庄', value: '5', count: 9 },
+        { label: '张庄', value: '6', count: 11 },
+        { label: '楼王', value: '7', count: 7 },
+        { label: '潘黄', value: '8', count: 13 },
+        { label: '盐渎', value: '9', count: 18 },
+        { label: '秦南', value: '10', count: 5 },
+        { label: '郭猛', value: '11', count: 10 },
+        { label: '高新区', value: '12', count: 22 },
+        { label: '龙冈', value: '13', count: 14 }
+      ]
+    }
+  },
+  computed: {
+    filteredList() {
+      if (!this.keyword) return this.parkList2
+      const kw = this.keyword.toLowerCase()
+      return this.parkList2.filter(i => i.label.toLowerCase().includes(kw))
+    }
+  },
+  async onReady() {
+    const json = await this.loadGeoJSON()
+    echarts.registerMap('yanduqu', json)
+
+    let canvasNode
+    // #ifdef H5
+    canvasNode = document.getElementById('ydChart')
+    // #endif
+    // #ifndef H5
+    canvasNode = await new Promise(resolve => {
+      uni.createSelectorQuery()
+        .in(this)
+        .select('#ydChart')
+        .node(res => resolve(res.node))
+        .exec()
+    })
+    // #endif
+
+    this.chart = echarts.init(canvasNode, null, {
+      width: uni.getSystemInfoSync().windowWidth,
+      height: uni.getSystemInfoSync().windowHeight - uni.upx2px(300) // 扣掉轮播图高度
+    })
+    this.renderMap()
+  },
+  methods: {
+    loadGeoJSON() {
+      return new Promise((resolve, reject) => {
+        uni.request({
+          url: './static/yandu.json',
+          method: 'GET',
+          success: res => resolve(res.data),
+          fail: reject
+        })
+      })
+    },
+    renderMap() {
+      const option = {
+        geo: [{
+          map: 'yanduqu',
+          roam: true,
+          aspectScale: 1.2,
+          zoom: 1.3,
+          itemStyle: {
+            areaColor: {
+              type: 'linear-gradient',
+              x: 0, y: 400, x2: 0, y2: 0,
+              colorStops: [
+                { offset: 0, color: 'rgba(37,108,190,0.8)' },
+                { offset: 1, color: 'rgba(15,169,195,0.8)' }
+              ],
+              global: true
+            },
+            borderColor: '#4ecee6',
+            borderWidth: 1
+          },
+          emphasis: {
+            areaColor: 'rgba(255,202,40,.9)'
+          },
+          label: { show: true, color: '#fff', fontSize: 12, fontWeight: 'bold' }
+        }],
+        series: [{ type: 'map', geoIndex: 0, data: [] }]
+      }
+      this.chart.setOption(option)
+
+      this.chart.on('click', params => {
+        uni.navigateTo({
+          url: `/pages/factoryBuildings/factoryBuildingsList?parkid=${params.name}`
+        })
+      })
+    },
+    // 抽屉交互
+    openDrawer() {
+      this.drawerOpen = true
+    },
+    closeDrawer() {
+      this.drawerOpen = false
+    },
+    toggleMode() {
+      this.mode = this.mode === 'grid' ? 'list' : 'grid'
+    },
+    onSearch() {}, // 已用 computed 实时过滤
+    // 选中园区
+    onSelectPark(item) {
+      this.closeDrawer()
+      // 1. 地图高亮
+      if (this.chart && item.value) {
+        this.chart.dispatchAction({
+          type: 'highlight',
+          seriesIndex: 0,
+          name: item.label
+        })
+        setTimeout(() => {
+          this.chart.dispatchAction({
+            type: 'downplay',
+            seriesIndex: 0,
+            name: item.label
+          })
+        }, 1200)
+      }
+      // 2. 跳转列表
+      uni.navigateTo({
+        url: `/pages/factoryBuildings/factoryBuildingsList?parkid=${item.value}`
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+/* CSS 变量,一键换色 */
+:root {
+  --theme: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  --card-bg: #f7f9fc;
+  --text: #333;
+  --shadow: 0 6rpx 24rpx rgba(0,0,0,.08);
+}
+
+.page {
+  display: flex;
+  flex-direction: column;
+  height: 100vh;
+  background: #f5f5f5;
+}
+
+.header {
+  padding: 20rpx 0;
+  text-align: center;
+  background: #fff;
+}
+.title {
+  font-size: 36rpx;
+  font-weight: bold;
+  color: var(--text);
+}
+
+.swiper {
+  width: 100%;
+  height: 300rpx;
+}
+.swiper-item {
+  width: 100%;
+  height: 100%;
+}
+
+.map-box {
+  flex: 1;
+  width: 100%;
+  position: relative;
+}
+.map-canvas {
+  width: 100%;
+  height: 100%;
+}
+
+/* 悬浮按钮 */
+.fab {
+  position: fixed;
+  right: 40rpx;
+  bottom: 80rpx;
+  width: 100rpx;
+  height: 100rpx;
+  border-radius: 50%;
+  background: var(--theme);
+  box-shadow: var(--shadow);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 9;
+}
+.fab-txt {
+  font-size: 28rpx;
+  color: #fff;
+  font-weight: 600;
+}
+
+/* 抽屉 */
+.drawer-mask {
+  position: fixed;
+  left: 0;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(0,0,0,.45);
+  opacity: 0;
+  visibility: hidden;
+  transition: all .3s;
+  z-index: 10;
+}
+.drawer-mask.show {
+  opacity: 1;
+  visibility: visible;
+}
+.drawer {
+  position: fixed;
+  right: 0;
+  top: 0;
+  bottom: 0;
+  width: 75vw;
+  background: #fff;
+  transform: translateX(100%);
+  transition: transform .3s;
+  display: flex;
+  flex-direction: column;
+  z-index: 11;
+}
+.drawer.show {
+  transform: translateX(0);
+}
+.drawer-header {
+  padding: 30rpx;
+  border-bottom: 1rpx solid #eee;
+}
+.search-input {
+  height: 64rpx;
+  padding: 0 20rpx;
+  border: 1rpx solid #ddd;
+  border-radius: 8rpx;
+  font-size: 28rpx;
+}
+.mode-toggle {
+  display: flex;
+  margin-top: 20rpx;
+  justify-content: space-around;
+}
+.mode-toggle text {
+  padding: 8rpx 24rpx;
+  border-radius: 8rpx;
+  font-size: 26rpx;
+  color: #666;
+  background: var(--card-bg);
+}
+.mode-toggle text.active {
+  background: var(--theme);
+  color: #fff;
+}
+.drawer-body {
+  flex: 1;
+  padding: 20rpx 30rpx;
+}
+
+/* 宫格 */
+.grid-box {
+  display: grid;
+  grid-template-columns: repeat(3, 1fr);
+  gap: 20rpx;
+}
+.grid-card {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  height: 140rpx;
+  border-radius: 12rpx;
+  background: var(--card-bg);
+  box-shadow: var(--shadow);
+  font-size: 28rpx;
+  font-weight: 600;
+  color: var(--text);
+}
+
+/* 列表 */
+.list-item {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 24rpx 0;
+  border-bottom: 1rpx solid #f0f0f0;
+}
+.list-label {
+  font-size: 30rpx;
+  color: var(--text);
+}
+.list-count {
+  font-size: 26rpx;
+  color: #999;
+}
+</style>