wzx há 9 meses atrás
pai
commit
74c6e39be4

+ 2 - 2
actMgt/manifest.json

@@ -2,8 +2,8 @@
     "name" : "actMgt",
     "appid" : "__UNI__F804C11",
     "description" : "彩图奔跑 - 赛事管理端",
-    "versionName" : "1.0.5",
-    "versionCode" : 105,
+    "versionName" : "1.0.6",
+    "versionCode" : 106,
     "transformPx" : false,
     /* 5+App特有相关 */
     "app-plus" : {

+ 222 - 26
actMgt/pages/actManage/track.vue

@@ -1,3 +1,8 @@
+<!-- 
+场控
+http://localhost:5173/actMgt/#/pages/actManage/track?compId=80 
+https://oss-mbh5.colormaprun.com/actMgt/#/pages/actManage/track?compId=80
+ -->
 <template>
 	<view class="body">
 		<view class="content uni-column">
@@ -15,13 +20,63 @@
 							@change="selectMapChange"></e-select>
 					</view>
 					<view class="select">
-						<e-select v-model="actionId" maxHeight="300px" :props="selectActionProps"
-							:options="actionList" :search="false" :inputClick="false" :clearable="false"
-							@getText="getESelectText" @change="selectActionChange"></e-select>
+						<e-select v-model="actionId" maxHeight="300px" :props="selectActionProps" :options="actionList"
+							:search="false" :inputClick="false" :clearable="false" @getText="getESelectText"
+							@change="selectActionChange"></e-select>
 					</view>
 				</view>
 
 				<view id="map" class="map"></view>
+
+				<view v-show="popupShow" class="popup"
+					:style="{ height: popupHeight + 'px', width: popupWidth + 'px' }">
+					<!-- <uni-section class="section" title="活动路线列表" type="line">
+						<uni-data-picker class="actionsTree" :style="{ width: popupWidth + 'px' }" placeholder="请选择活动" popup-title="请选择活动路线" :localdata="actionsTree"
+							v-model="sltActRoute" @change="onActionChange" @popupopened="onActionsTreePopupOpened" @popupclosed="onActionsTreePopupClosed"></uni-data-picker>
+					</uni-section> -->
+
+					<uni-section class="section" title="玩家列表" type="line">
+						<view class="norecord" v-if="players == null || players.length == 0">暂无记录</view>
+						<scroll-view :scroll-top="0" scroll-y="true" :style="{ height: popupHeight - 43 + 'px'}">
+							<uni-list v-for="(item, index) in players" :key="index" :border="true" class="list">
+								<uni-list-item :clickable="true" @click="onPlayerListItemClick(item)" class="list-item"
+									:class="{ 
+									'list-item-focus': focusPlayerId == item.id 
+									}">
+									<template v-slot:header>
+										<!-- <image class="slot-image" src="/static/logo.png" mode="widthFix"></image> -->
+										<div class="slot-image" :style="'background-color:' + getPlayerColor(item.id)">
+										</div>
+									</template>
+									<template v-slot:body>
+										<view class="slot-box">
+											<view class="slot-title">
+												<!-- <span class="slot-sn" :style="'background-color:' + getPlayerColor(item.id)">{{index+1}}</span> -->
+												[{{index+1}}]<span class="slot-phone" @click="onPhoneClick(item.phone)">
+													{{item.name}}
+													<uni-icons v-if="admin" type="phone" size="14"></uni-icons>
+												</span>
+												打点 {{item.EffectiveNum}}/{{item.TotalControlNum}} &nbsp; 目标点
+												{{item.nextControlPoint.orderNO}} &nbsp; 百味豆 {{item.sysPoint}}
+											</view>
+											<view class="slot-note">
+												距离 {{tools.fmtDistanctKm(item.distance)}}km &nbsp; 配速
+												{{tools.convertSecondsToHMS(item.pace, 2)}}
+												&nbsp; Cal {{Math.round(item.Calorie/1000)}} &nbsp; | &nbsp; 心率
+												{{item.lastHr}} &nbsp; 平均 {{item.avgHr}} &nbsp; 最大 {{item.maxHr}}
+												<!-- &nbsp; | &nbsp;  Ck {{item.Ck}} Ei {{Math.round(item.Ei*100)/100}}-->
+											</view>
+										</view>
+									</template>
+									<!-- <template v-slot:footer>
+										<image class="slot-image" src="/static/logo.png" mode="widthFix"></image>
+									</template> -->
+								</uni-list-item>
+							</uni-list>
+						</scroll-view>
+					</uni-section>
+				</view>
+
 			</view>
 		</view>
 	</view>
@@ -52,9 +107,12 @@
 	export default {
 		data() {
 			return {
+				tools: tools,
 				queryObj: {},
 				queryString: "",
 				interval: null,
+				refreshTime: 300000, // 刷新时间 ms
+				admin: true, // 是否场控管理员
 
 				compId: 0, // 赛事ID
 				actRs: card.actRs, // 赛事详情
@@ -65,7 +123,7 @@
 				mapInfo: {}, // (当前选中的)地图信息 mapDetail.mapInfo
 				mapUrl: null, // (当前选中的)地图图片URL
 				mapConfig: "", // (当前选中的)地图图片的地理参考信息
-				
+
 				actionList: [], // 活动列表
 				actionId: 0, // (当前选中的)活动ID
 				actionDetail: {}, // (当前选中的)活动详情
@@ -81,21 +139,17 @@
 					// disabled: 'noallowed'
 				},
 
-				popupShow: false,
-				extraIcon: {
-					// color: '#4cd964',
-					// size: '22',
-					// type: 'gear-filled'
-				},
-
-				
-
 				map: null,
 				checkPoints: [],
 				players: [],
 				players_position: [],
 				focusPlayerId: 0,
 				trailTime: 0,
+
+				popupHeight: 360,
+				popupWidth: 0,
+				popupType: 'bottom',
+				popupShow: false,
 			}
 		},
 		computed: {
@@ -120,12 +174,14 @@
 		},
 		mounted() {
 			console.log("mounted");
-			// this.initMap();
-			// this.loadData();
+			this.$global.getWindowInfo();
+			uni.$on('windowResize', this.reLoad);
+			this.popupShow = this.$store.state.mapPopupShow;
+			this.layoutInit()
 		},
 		beforeDestroy() {
-			// console.log("beforeDestroy")
-			// clearInterval(this.interval)
+			console.log("beforeDestroy")
+			clearInterval(this.interval)
 			leafletHelper.free()
 		},
 		methods: {
@@ -141,6 +197,28 @@
 					url: fullPath
 				});
 			},
+			// 布局初始化 设置地图高度
+			layoutInit() {
+				this.popupWidth = this.$global.windowWidth
+				/* this.windowHeight = this.$global.windowHeight
+				this.windowWidth = this.$global.windowWidth
+				if (this.$global.deviceOrientation == 'portrait') { // 竖屏
+					this.flexDirection = 'column'
+					this.mapWidth = this.$global.windowWidth
+					this.mapHeight = this.$global.windowHeight
+					
+					this.popupHeight = this.popupHeightPortrait
+					this.popupWidth = this.$global.windowWidth
+				} else { // 横屏
+					this.flexDirection = 'row'
+					this.mapHeight = this.$global.windowHeight
+					this.mapWidth = this.$global.windowWidth
+					
+					this.popupHeight = this.$global.windowHeight
+					this.popupWidth = this.popupWidthlandscape
+					// console.log("横屏 popupHeight", this.popupHeight)
+				} */
+			},
 			popupToggle() {
 				this.popupShow = !this.popupShow
 				this.$store.commit('setMapPopupShow', this.popupShow)
@@ -163,7 +241,7 @@
 			},
 			async loadData() {
 				await this.loadMap();
-				
+
 				await this.initMap();
 				this.handleMapDrawRoute();
 				if (this.interval != null) {
@@ -172,7 +250,7 @@
 
 				let that = this;
 				that.players = await that.getUsersInGameDetail();
-				// console.log('players', that.players)
+				console.log('players', that.players)
 				// leafletHelper.global.setPlayers(this.players)
 
 				that.players_position = await that.usersInGameGpsQuery();
@@ -180,7 +258,7 @@
 
 				that.handleMapDrawPlayer();
 				that.handleMapDrawTrail();
-				return;
+
 				this.interval = setInterval(async function() {
 					that.players = await that.getUsersInGameDetail();
 					that.players_position = await that.usersInGameGpsQuery();
@@ -188,7 +266,7 @@
 					// leafletHelper.global.setPlayersPosition(that.players_position);
 					that.handleMapDrawPlayer();
 					that.handleMapDrawTrail();
-				}, 1000);
+				}, that.refreshTime);
 
 				// await mapHelper.handleMapInfo(this, this.mapInfo)
 				this.handleMapToggle();
@@ -210,8 +288,6 @@
 				leafletHelper.global.setPlayers(this.players)
 				leafletHelper.global.setPlayersPosition(this.players_position)
 				leafletHelper.player.drawAllPlayers()
-				// leafletHelper.player.drawOnePlayer(2)
-				// leafletHelper.player.drawOnePlayer(3)
 
 				leafletHelper.global.dealStaleData()
 			},
@@ -355,7 +431,7 @@
 						if (checkResCode(res)) {
 							const data = res.data.data;
 							this.actionDetail = data;
-							
+
 							this.loadData();
 						}
 					},
@@ -408,7 +484,7 @@
 							success: (res) => {
 								console.log("getUsersInGameDetail", res);
 								if (checkResCode(res)) {
-									resolve(res);
+									resolve(res.data.data.users);
 								} else {
 									reject(res);
 								}
@@ -438,7 +514,7 @@
 							success: (res) => {
 								console.log("usersInGameGpsQuery", res);
 								if (checkResCode(res)) {
-									resolve(res);
+									resolve(res.data.data.gpsInfo);
 								} else {
 									reject(res);
 								}
@@ -463,6 +539,9 @@
 				this.handlePlayerListItemClick(item)
 			},
 			onPhoneClick(phoneNumber) {
+				if (!this.admin) {
+					return;
+				}
 				if (phoneNumber.length == 11) {
 					uni.makePhoneCall({
 						phoneNumber: phoneNumber
@@ -528,4 +607,121 @@
 		background-color: white;
 		z-index: 0;
 	}
+
+	.popup {
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		background-color: #f5f5f5;
+		/* border-left: #dedede solid 1px; */
+		border-top: #dedede solid 1px;
+	}
+
+	.section {
+		width: 100%;
+	}
+
+	.scroll {
+		overflow: scroll;
+	}
+
+	.section-title {
+		font-size: 14px;
+		color: #424242;
+		line-height: 20px;
+		padding: 10px 0 10px 10px;
+	}
+
+	.section-content {
+		width: 100%;
+		height: 100%;
+	}
+
+	/* .section-content-item {
+		display: flex;
+		flex-direction: row;
+		align-items: center;
+		height: 46px;
+	} */
+
+	/* .actionsTree {
+		/deep/ .input-value-border {
+		    border-top: 1px solid #e5e5e5;
+		    border-bottom: 1px solid #e5e5e5;
+		    border-radius: 0px;
+		}
+		
+		/deep/ .uni-scroll-view {
+		    overflow: unset !important;
+		}
+	} */
+
+	.list {
+		margin-left: -6px;
+	}
+
+	.list-item {
+		display: flex;
+		flex-direction: row;
+		align-items: center;
+		height: 46px;
+	}
+
+	.slot-box {
+		display: flex;
+		flex-direction: column;
+		align-items: flex-start;
+		width: 330px;
+		max-width: 350px;
+	}
+
+	.slot-image {
+		display: block;
+		margin-right: 6px;
+		width: 3px;
+		height: 33px;
+		align-self: center;
+	}
+
+	.slot-title {
+		flex: 1;
+		font-size: 13px;
+		color: #424242;
+		line-height: 18px;
+		white-space: nowrap;
+	}
+
+	.slot-sn {
+		display: inline-flex;
+		width: 15px;
+		height: 15px;
+		border-radius: 50%;
+	}
+
+	.slot-note {
+		flex: 1;
+		margin-left: 20px;
+		font-size: 12px;
+		color: #7d8da7;
+		line-height: 18px;
+		white-space: nowrap;
+	}
+
+	.slot-phone {
+		padding: 0 5px;
+		color: #000;
+		font-weight: bold;
+	}
+
+	.norecord {
+		font-weight: 500;
+		color: #818181;
+		font-size: 14px;
+		text-align: center;
+		line-height: 50px;
+	}
+
+	/* /deep/ .uni-data-tree-dialog {
+		top: 39px;
+	} */
 </style>

BIN
actMgt/static/map/fullscreen.png


BIN
actMgt/static/map/list.png


BIN
actMgt/static/map/marker-icon.png


BIN
actMgt/static/map/player.png


BIN
actMgt/static/map/point.png


BIN
actMgt/static/map/point_end.png


BIN
actMgt/static/map/point_start.png


BIN
actMgt/static/map/route.png


BIN
actMgt/static/map/tooltip.png


BIN
actMgt/static/map/trail.png


+ 2 - 2
actMgt/store/index.js

@@ -10,10 +10,10 @@ export default createStore({
 		// 场控地图页
 		// mapReload: false, // 页面是否重载 true: 需恢复暂存数据 false: 无需恢复暂存数据
 		mapPopupShow: false,
-		mapControlRoute: true,
+		mapControlRoute: false,
 		mapControlPlayer: true,
 		mapControlTooltip: true,
-		mapControlTrail: true,
+		mapControlTrail: false,
 		mapSltMapId: 0, // 存储用户选择的地图ID
 		mapSltActRoute: '', // 存储用户选择的活动路线信息 格式:活动ID-路线ID 例如:3-1 (0代表全部)
 		holdTime: null, // 暂存时间 用于数据过期管理

+ 2 - 0
actMgt/uni_modules/uni-section/changelog.md

@@ -0,0 +1,2 @@
+## 0.0.1(2022-07-22)
+- 初始化

+ 167 - 0
actMgt/uni_modules/uni-section/components/uni-section/uni-section.vue

@@ -0,0 +1,167 @@
+<template>
+	<view class="uni-section">
+		<view class="uni-section-header" @click="onClick">
+				<view class="uni-section-header__decoration" v-if="type" :class="type" />
+        <slot v-else name="decoration"></slot>
+
+        <view class="uni-section-header__content">
+          <text :style="{'font-size':titleFontSize,'color':titleColor}" class="uni-section__content-title" :class="{'distraction':!subTitle}">{{ title }}</text>
+          <text v-if="subTitle" :style="{'font-size':subTitleFontSize,'color':subTitleColor}" class="uni-section-header__content-sub">{{ subTitle }}</text>
+        </view>
+
+        <view class="uni-section-header__slot-right">
+          <slot name="right"></slot>
+        </view>
+		</view>
+
+		<view class="uni-section-content" :style="{padding: _padding}">
+			<slot />
+		</view>
+	</view>
+</template>
+
+<script>
+
+	/**
+	 * Section 标题栏
+	 * @description 标题栏
+	 * @property {String} type = [line|circle|square] 标题装饰类型
+	 * 	@value line 竖线
+	 * 	@value circle 圆形
+	 * 	@value square 正方形
+	 * @property {String} title 主标题
+	 * @property {String} titleFontSize 主标题字体大小
+	 * @property {String} titleColor 主标题字体颜色
+	 * @property {String} subTitle 副标题
+	 * @property {String} subTitleFontSize 副标题字体大小
+	 * @property {String} subTitleColor 副标题字体颜色
+	 * @property {String} padding 默认插槽 padding
+	 */
+
+	export default {
+		name: 'UniSection',
+    emits:['click'],
+		props: {
+			type: {
+				type: String,
+				default: ''
+			},
+			title: {
+				type: String,
+				required: true,
+				default: ''
+			},
+      titleFontSize: {
+        type: String,
+        default: '14px'
+      },
+			titleColor:{
+				type: String,
+				default: '#333'
+			},
+			subTitle: {
+				type: String,
+				default: ''
+			},
+      subTitleFontSize: {
+        type: String,
+        default: '12px'
+      },
+      subTitleColor: {
+        type: String,
+        default: '#999'
+      },
+			padding: {
+				type: [Boolean, String],
+				default: false
+			}
+		},
+    computed:{
+      _padding(){
+        if(typeof this.padding === 'string'){
+          return this.padding
+        }
+
+        return this.padding?'10px':''
+      }
+    },
+		watch: {
+			title(newVal) {
+				if (uni.report && newVal !== '') {
+					uni.report('title', newVal)
+				}
+			}
+		},
+    methods: {
+			onClick() {
+				this.$emit('click')
+			}
+		}
+	}
+</script>
+<style lang="scss" >
+	$uni-primary: #2979ff !default;
+
+	.uni-section {
+		background-color: #fff;
+    .uni-section-header {
+      position: relative;
+      /* #ifndef APP-NVUE */
+      display: flex;
+      /* #endif */
+      flex-direction: row;
+      align-items: center;
+      padding: 12px 10px;
+      font-weight: normal;
+
+      &__decoration{
+        margin-right: 6px;
+        background-color: $uni-primary;
+        &.line {
+          width: 4px;
+          height: 12px;
+          border-radius: 10px;
+        }
+
+        &.circle {
+          width: 8px;
+          height: 8px;
+          border-top-right-radius: 50px;
+          border-top-left-radius: 50px;
+          border-bottom-left-radius: 50px;
+          border-bottom-right-radius: 50px;
+        }
+
+        &.square {
+          width: 8px;
+          height: 8px;
+        }
+      }
+
+      &__content {
+        /* #ifndef APP-NVUE */
+        display: flex;
+        /* #endif */
+        flex-direction: column;
+        flex: 1;
+        color: #333;
+
+        .distraction {
+          flex-direction: row;
+          align-items: center;
+        }
+        &-sub {
+          margin-top: 2px;
+        }
+      }
+
+      &__slot-right{
+        font-size: 14px;
+      }
+    }
+
+    .uni-section-content{
+      font-size: 14px;
+    }
+	}
+</style>

+ 87 - 0
actMgt/uni_modules/uni-section/package.json

@@ -0,0 +1,87 @@
+{
+  "id": "uni-section",
+  "displayName": "uni-section 标题栏",
+  "version": "0.0.1",
+  "description": "标题栏组件",
+  "keywords": [
+    "uni-ui",
+    "uniui",
+    "标题栏"
+],
+  "repository": "https://github.com/dcloudio/uni-ui",
+  "engines": {
+    "HBuilderX": ""
+  },
+  "directories": {
+    "example": "../../temps/example_temps"
+  },
+  "dcloudext": {
+    "category": [
+      "前端组件",
+      "通用组件"
+    ],
+    "sale": {
+      "regular": {
+        "price": "0.00"
+      },
+      "sourcecode": {
+        "price": "0.00"
+      }
+    },
+    "contact": {
+      "qq": ""
+    },
+    "declaration": {
+      "ads": "无",
+      "data": "无",
+      "permissions": "无"
+    },
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+  },
+  "uni_modules": {
+    "dependencies": [
+      "uni-scss"
+    ],
+    "encrypt": [],
+    "platforms": {
+      "cloud": {
+        "tcb": "y",
+        "aliyun": "y"
+      },
+      "client": {
+        "App": {
+          "app-vue": "y",
+          "app-nvue": "y"
+        },
+        "H5-mobile": {
+          "Safari": "y",
+          "Android Browser": "y",
+          "微信浏览器(Android)": "y",
+          "QQ浏览器(Android)": "y"
+        },
+        "H5-pc": {
+          "Chrome": "y",
+          "IE": "y",
+          "Edge": "y",
+          "Firefox": "y",
+          "Safari": "y"
+        },
+        "小程序": {
+          "微信": "y",
+          "阿里": "y",
+          "百度": "y",
+          "字节跳动": "y",
+          "QQ": "y"
+        },
+        "快应用": {
+          "华为": "u",
+          "联盟": "u"
+        },
+        "Vue": {
+            "vue2": "y",
+            "vue3": "y"
+        }
+      }
+    }
+  }
+}

+ 8 - 0
actMgt/uni_modules/uni-section/readme.md

@@ -0,0 +1,8 @@
+## Section 标题栏
+> **组件名:uni-section**
+> 代码块: `uSection`
+
+uni-section 组件主要用于文章、列表详情等标题展示
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-section)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839

+ 31 - 10
actMgt/utils/map/leafletHelper.css

@@ -4,24 +4,45 @@
 	height: 257px !important;
 }
 
-.leaflet-control {
+.leaflet-bar {
+	width: 30px;
 	font-size: 12px;
+	background-color: #ffffff !important;
 }
 
 .leaflet-control-common {
-	/* font-size: 12px; */
-	/* color: red !important; */
+	margin-bottom: 2px;
+	display: flex;
+	flex-direction: column;
+	justify-content: center;
+	align-items: center;
+	background-color: #ffffff !important;
+	color: #9d9d9d !important;
+	filter: grayscale(100%);
 }
 
 .leaflet-control-selected {
-	background-color: #eff6ff !important;
-	color: #1888ff !important;
+	margin-bottom: 2px;
+	display: flex;
+	flex-direction: column;
+	justify-content: center;
+	align-items: center;
+	color: #282828 !important;
+	/* color: #ff8d1a !important; */
+	background-color: #ffffff !important;
+}
+
+.leaflet-bar-ico {
+	width: 21px;
+	height: 21px;
+	margin-top: 5px;
+	margin-bottom: 2px;
 }
 
 .my-div-icon {
 	z-index: -1000 !important;
-	text-align: center; 
-	font-size: 16px; 
-	font-weight: bold; 
-	color: #ff00ff;
-}
+	text-align: center;
+	font-size: 12px;
+	font-weight: bold;
+	color: #ac33c1;
+}

+ 16 - 15
actMgt/utils/map/leafletHelper.js

@@ -67,8 +67,8 @@ export default {
 		const jgwData = await this.parseJgwContent(mapConfig);
 		const bounds = await this.getImageBoundsByJgw(jgwData, mapImageInfo.width, mapImageInfo.height);
 		const center = this.getImageCenterByBounds(bounds);
-		global.mapOptions.maxBounds = bounds;
-		global.mapOptions.center = center;
+		// global.mapOptions.maxBounds = bounds;	// 地图最大范围,超出范围则地图无法拖动(可为空)
+		global.mapOptions.center = center; // 地图中心点
 		// console.log("global.mapOptions", global.mapOptions);
 
 		global.map = L.map(mapid, global.mapOptions);
@@ -266,38 +266,38 @@ export default {
 				//创建Dom元素 L.DomUtil.create('元素类型', 'class类名')
 				that.exControlContainer = L.DomUtil.create('div', 'leaflet-bar')
 
-				that.elRoute = L.DomUtil.create('a', 'leaflet-control-common')
-				that.elRoute.innerHTML = '<span>路线</span>'
+				that.elRoute = L.DomUtil.create('div', 'leaflet-control-common')
+				that.elRoute.innerHTML = '<img class="leaflet-bar-ico" src="static/map/route.png"></img><span>路线</span>'
 				if (store.state.mapControlRoute) {
 					L.DomUtil.setClass(that.elRoute, 'leaflet-control-selected')
 				}
 
-				that.elPlayer = L.DomUtil.create('a', 'leaflet-control-common')
-				that.elPlayer.innerHTML = '<span>玩家</span>'
+				that.elPlayer = L.DomUtil.create('div', 'leaflet-control-common')
+				that.elPlayer.innerHTML = '<img class="leaflet-bar-ico" src="static/map/player.png"></img><span>玩家</span>'
 				if (store.state.mapControlPlayer) {
 					L.DomUtil.setClass(that.elPlayer, 'leaflet-control-selected')
 				}
 
-				that.elPlayerTooltip = L.DomUtil.create('a', 'leaflet-control-common')
-				that.elPlayerTooltip.innerHTML = '<span>提示</span>'
+				that.elPlayerTooltip = L.DomUtil.create('div', 'leaflet-control-common')
+				that.elPlayerTooltip.innerHTML = '<img class="leaflet-bar-ico" src="static/map/tooltip.png"></img><span>提示</span>'
 				if (store.state.mapControlTooltip) {
 					L.DomUtil.setClass(that.elPlayerTooltip, 'leaflet-control-selected')
 				}
 
-				that.elPlayerTrail = L.DomUtil.create('a', 'leaflet-control-common')
-				that.elPlayerTrail.innerHTML = '<span>轨迹</span>'
+				that.elPlayerTrail = L.DomUtil.create('div', 'leaflet-control-common')
+				that.elPlayerTrail.innerHTML = '<img class="leaflet-bar-ico" src="static/map/trail.png"></img><span>轨迹</span>'
 				if (store.state.mapControlTrail) {
 					L.DomUtil.setClass(that.elPlayerTrail, 'leaflet-control-selected')
 				}
 
-				that.elList = L.DomUtil.create('a', 'leaflet-control-common')
-				that.elList.innerHTML = '<span>列表</span>'
+				that.elList = L.DomUtil.create('div', 'leaflet-control-common')
+				that.elList.innerHTML = '<img class="leaflet-bar-ico" src="static/map/list.png"></img><span>列表</span>'
 				if (store.state.mapPopupShow) {
 					L.DomUtil.setClass(that.elList, 'leaflet-control-selected')
 				}
 
-				that.elFullScreen = L.DomUtil.create('a', 'leaflet-control-common')
-				that.elFullScreen.innerHTML = '<span>全屏</span>'
+				that.elFullScreen = L.DomUtil.create('div', 'leaflet-control-common')
+				that.elFullScreen.innerHTML = '<img class="leaflet-bar-ico" src="static/map/fullscreen.png"></img><span>全屏</span>'
 				if (store.state.fullScreen) {
 					L.DomUtil.setClass(that.elFullScreen, 'leaflet-control-selected')
 				}
@@ -400,7 +400,8 @@ export default {
 	
 	toggleControl(el) {
 		if (L.DomUtil.hasClass(el, 'leaflet-control-selected')) {
-			L.DomUtil.removeClass(el, 'leaflet-control-selected')
+			// L.DomUtil.removeClass(el, 'leaflet-control-selected')
+			L.DomUtil.setClass(el, 'leaflet-control-common')
 		} else {
 			L.DomUtil.setClass(el, 'leaflet-control-selected')
 		}

+ 10 - 10
actMgt/utils/map/sub/config.js

@@ -4,7 +4,7 @@ export default {
 		center: null, // 地图的初始地理中心坐标
 		zoom: 16, // 初始地图缩放级别
 		minZoom: 14,
-		maxZoom: 18,
+		maxZoom: 20,
 		zoomControl: true,
 		// zoomSnap: 0.5,
 		// zoomDelta: 0.5,
@@ -86,14 +86,14 @@ export default {
 		checkPoint: {
 			default: {
 				radius: 15,
-				color: '#ff00ff',
+				color: '#ac33c1',
 				weight: 2,
 				fill: false,
 				interactive: true
 			},
 			focus: {
-				radius: 15,
-				color: '#ff00ff',
+				radius: 13,
+				color: '#ac33c1',
 				weight: 2,
 				fill: false,
 				interactive: true
@@ -108,19 +108,19 @@ export default {
 		// 检查点组成的路径
 		checkPointPath: {
 			default: {
-				dashArray: '8 12',
+				// dashArray: '8 12',
 				// dashOffset: '1',
 				stroke: true, // 是否描边
-				color: '#ff00ff', // 描边颜色
-				weight: 3, // 描边宽度 px
-				opacity: 0.6, // 描边不透明度
+				color: '#ac33c1', // 描边颜色
+				weight: 2, // 描边宽度 px
+				opacity: 1.0, // 描边不透明度
 				fill: false, // 是否填充
 				interactive: true
 			},
 			focus: {
 				stroke: true, // 是否描边
-				color: '#ff00ff', // 描边颜色
-				weight: 3, // 描边宽度 px
+				color: '#ac33c1', // 描边颜色
+				weight: 2, // 描边宽度 px
 				opacity: 1.0, // 描边不透明度
 				fill: false, // 是否填充
 				interactive: true

+ 1 - 0
actMgt/utils/map/sub/global.js

@@ -73,6 +73,7 @@ export default {
 		this.players = data // 指针复制,是同一个对象
 	},
 	setPlayersPosition(data) {
+		// console.log("[setPlayersPosition] data", data)
 		this.players_position = data // 指针复制,是同一个对象
 	},
 	// *** 非指针复制 *** 

+ 35 - 26
actMgt/utils/map/sub/player.js

@@ -1,6 +1,7 @@
 // import L from 'leaflet'
 import config from '@/utils/map/sub/config'
 import global from '@/utils/map/sub/global'
+import tools from '@/utils/tools'
 import store from '@/store/index'
 
 import {
@@ -45,7 +46,7 @@ export default {
 		if (flag != null) {
 			togglePlayerFlag = !flag
 		}
-		// console.log("[togglePlayer]", togglePlayerFlag)
+		console.log("[togglePlayer]", togglePlayerFlag)
 
 		if (togglePlayerFlag) {
 			this.playerLayerGroup.removeFrom(global.map)
@@ -98,7 +99,12 @@ export default {
 	},
 
 	drawAllPlayers() {
-		// console.log('[drawAllPlayers]', global.players)
+		if (global.players == null) {
+			console.log('[drawAllPlayers] 玩家列表为空')
+			return
+		} else {
+			console.log('[drawAllPlayers]', global.players)
+		}
 		// if (this.playerLayerGroup != null)
 		// 	this.playerLayerGroup.clearLayers()
 
@@ -123,7 +129,7 @@ export default {
 		if (storePlayer == null || storePlayer.marker == null) {
 			// 在地图上创建 marker 并存储用户信息
 			var playerIcon = L.icon({
-				iconUrl: 'static/image/marker-icon.png',
+				iconUrl: 'static/map/marker-icon.png',
 				iconSize: [20, 32.8],
 				iconAnchor: [10, 30]
 			});
@@ -223,20 +229,19 @@ export default {
 		return interval_creatCircleMarker
 	},
 	getPopupContent(player) {
-		var popupContent = '<div style="line-height: 20px;">'
-		popupContent += '<div>' + ' <span style="color: blue; font-weight: bold;" onClick="uni.makePhoneCall({phoneNumber: \'' + player
-			.phone + '\'});">' + player.name + '</span>'
-		if (player.nextcontrolpoint.sn != '') {
-			popupContent += ' &nbsp; <span style="font-weight: bold;">=> ' + player.nextcontrolpoint.sn  + '</span>'
-		}
-		popupContent += ' &nbsp; 百味豆 ' + player.syspoint + ' </div>'
-		popupContent += '<div>打点 ' + player.effectivenum + '/' + player.totalcontrolnum +
-			' &nbsp; 距离 ' + player.distance + '米 &nbsp; 配速 ' + formatTime(player.pace, false) + '</div>'
-		popupContent += '<div>' + '心率 ' + player.lasthr + ' &nbsp; 平均 ' + player.avghr + ' &nbsp; 最大 ' + player.maxhr + '</div>'
-		popupContent += '<div>Cal ' + Math.round(player.calorie / 1000) + ' &nbsp; Ck ' + player.ck +
-			' &nbsp; Ei ' + Math.round(player.ei * 100) / 100 + '</div>'
+		var popupContent = '<div style="line-height: 20px; text-wrap: nowrap;">'
+		popupContent += '<div><span style="color: #ff8d1a; font-weight: bold;" onClick="uni.makePhoneCall({phoneNumber: \''
+			+ player.phone + '\'});">' + player.name + ' ( ' + player.phone + ' )' + '</span></div>'
+		
+		// popupContent += ' &nbsp; <span style="font-weight: bold;">=> ' + player.nextControlPoint.sn  + '</span>'
+		popupContent += '<div>百味豆:' + player.sysPoint + ' &nbsp; 下一点位:' + player.nextControlPoint.orderNO 
+			+ ' &nbsp; 打点进度:' + player.EffectiveNum + '/' + player.TotalControlNum + '</div>'
+		popupContent += '<div>距离:' + tools.fmtDistanctKm(player.distance) + 'km &nbsp; 配速:' + tools.convertSecondsToHMS(player.pace, 2) + '</div>'
+		popupContent += '<div>心率:' + player.lastHr + ' &nbsp; 平均:' + player.avgHr + ' &nbsp; 最大:' + player.maxHr + '</div>'
+		popupContent += '<div>Cal:' + Math.round(player.Calorie / 1000) + ' &nbsp; Ck:' + player.Ck
+			 + ' &nbsp; Ei:' + Math.round(player.Ei * 100) / 100 + '</div>'
 		popupContent += '</div>'
-
+		
 		return popupContent
 	},
 	drawOnePlayer(playerId, animate = true) {
@@ -244,18 +249,18 @@ export default {
 		var player = global.getPlayerById(playerId)
 		var player_position = global.getPlayerPositionById(playerId)
 		var storePlayer = global.getStorePlayersById(playerId)
-		// console.log('[drawOnePlayer]', player, player_position)
+		console.log('[drawOnePlayer]', player, player_position)
 
 		if (player == null) {
 			console.warn('[drawOnePlayer] 玩家数据为空', player)
 			return
 		}
 		if (player_position == null) {
-			// console.log('[drawOnePlayer] 玩家位置数据为空', player_position)
+			console.log('[drawOnePlayer] 玩家位置数据为空', player_position)
 			return
 		}
 
-		var popupContent = this.getPopupContent(player)
+		// var popupContent = this.getPopupContent(player)
 
 		// 首次创建
 		if (storePlayer == null || storePlayer.marker == null) {
@@ -269,7 +274,7 @@ export default {
 
 			var marker = L.circleMarker([player_position.latitude, player_position.longitude], options)
 				.addTo(this.playerLayerGroup)
-				.bindPopup(popupContent)
+				// .bindPopup(popupContent)
 				.bindTooltip(`${player.name}`, config.gStyle.marker.tooltip)
 
 			marker.type = 'circleMarker'
@@ -326,7 +331,7 @@ export default {
 				// console.log('[drawOnePlayer] 更新玩家的标记位置', storePlayer.marker, curPoint)
 				marker.setLatLng(curPoint)
 				marker.bringToFront()
-				marker.setPopupContent(popupContent)
+				// marker.setPopupContent(popupContent)
 			}
 		}
 	},
@@ -370,11 +375,15 @@ export default {
 			options.color = config.gStyle.common.color
 
 			focusPlayer.marker.setStyle(options)
-			focusPlayer.marker.openPopup()
+			// focusPlayer.marker.openPopup()
 			focusPlayer.marker.bringToFront()
 		}
 	},
 	drawAllTrails(duration) {
+		if (global.players == null) {
+			console.log('[drawAllTrails] 玩家列表为空')
+			return
+		}
 		// if (this.trailLayerGroup != null)
 		// 	this.trailLayerGroup.clearLayers()
 
@@ -387,19 +396,19 @@ export default {
 		var player = global.getPlayerById(playerId)
 		var player_position = global.getPlayerPositionById(playerId)
 		var storePlayer = global.getStorePlayersById(playerId)
-		// console.log('[drawOneTrail] param', player, player_position, storePlayer)
+		console.log('[drawOneTrail] param', player, player_position, storePlayer)
 
 		if (player == null) {
 			console.warn('[drawOneTrail] 玩家数据为空', player)
 			return
 		}
 		if (player_position == null) {
-			// console.log('[drawOneTrail] 玩家位置数据为空', player_position)
+			console.log('[drawOneTrail] 玩家位置数据为空', player_position)
 			return
 		}
 
 		if (storePlayer == null || storePlayer.trail == null) {
-			// console.warn('[drawOneTrail] 轨迹数据为空', player, storePlayer)
+			console.warn('[drawOneTrail] 轨迹数据为空', player, storePlayer)
 
 			var trail = null
 			var trail2 = null
@@ -499,7 +508,7 @@ export default {
 							storePlayer.marker.setLatLng(curPoint.slice(0, 2)) // 更新玩家的标记位置
 							storePlayer.marker.bringToFront()
 							var popupContent = that.getPopupContent(player)
-							storePlayer.marker.setPopupContent(popupContent)
+							// storePlayer.marker.setPopupContent(popupContent)
 						}
 					}
 					// global.map.setView(point.slice(0, 2), 18); //地图中心跟踪最新位置

+ 67 - 14
actMgt/utils/map/sub/route.js

@@ -62,7 +62,7 @@ export default {
 		store.commit('setMapControlRoute', toggleFlag)
 	},
 	drawAllRoutes() {
-		// console.log("[drawAllRoutes] routes", global.routes)
+		console.log("[drawAllRoutes] routes", global.routes)
 		if (this.cpMarkLayerGroup != null)
 			this.cpMarkLayerGroup.clearLayers()
 		if (this.cpMemoLayerGroup != null)
@@ -80,15 +80,23 @@ export default {
 			console.warn('[drawOneRoute] 关键数据为空', cpList)
 			return
 		}
-		// console.warn('[drawOneRoute] cpList', cpList)
+		console.warn('[drawOneRoute] cpList', cpList)
 
+		var type = ''
 		for (var i = 0; i < cpList.length; i++) {
-			let res = this.drawOnePoint(cpList[i])
+			if (i == 0) {
+				type = 'start'
+			} else if (i == cpList.length - 1) {
+				type = 'end'
+			} else {
+				type = ''
+			}
+			let res = this.drawOnePoint(cpList[i], type)
 			cpList[i].marker = res.marker
 			cpList[i].markerMemo = res.markerMemo
 		}
 	},
-	drawOnePoint(data) {
+	drawOnePoint(data, type="") {
 		// console.log('[drawOnePoint] data', data)
 		if (data == null) {
 			console.warn('[drawOnePoint] 关键数据为空', data)
@@ -96,17 +104,64 @@ export default {
 		}
 		
 		var position = data.ciPosition
-		var marker = L.circleMarker([position.latitude, position.longitude], config.gStyle.checkPoint.default)
-			.addTo(this.cpMarkLayerGroup)
-		// .addTo(global.map)
-		// .bindPopup("Hello, I'm a Marker!<br><img src='my-image.png' width='100'>").openPopup();
-		// .bindTooltip(`检查点:${route.serial_num}`, config.gStyle.checkPoint.tooltip)
+		var radius = config.gStyle.checkPoint.default.radius
+		var iconSize = [radius*2, radius*2]
+		
+		var html = ""
+		var iconUrl = ""
+		var marker = ""
+		if (type == "start") {
+			// html = '<div>开始点</div>'
+			iconUrl = "static/map/point_start.png"
+			var markerIcon = L.icon({
+				iconUrl: iconUrl,
+				iconSize: iconSize,
+				// iconSize: [30, 30],
+				// iconAnchor: [10, 30]
+			});
+			var marker = L.marker([position.latitude, position.longitude], {
+					icon: markerIcon
+				})
+				.addTo(this.cpMarkLayerGroup)
+			
+		} else if (type == "end") {
+			// html = '<div>结束点</div>'
+			// html = '<div>' + data.orderNO + '</div>'
+			iconUrl = "static/map/point_end.png"
+			var markerIcon = L.icon({
+				iconUrl: iconUrl,
+				iconSize: iconSize,
+				// iconSize: [30, 30],
+				// iconAnchor: [10, 30]
+			});
+			var marker = L.marker([position.latitude, position.longitude], {
+					icon: markerIcon
+				})
+				.addTo(this.cpMarkLayerGroup)
+		}
+		else {	// 中间点
+			// html = '<div>' + data.sn + '</div>'
+			html = '<div>' + data.orderNO + '</div>'
+			iconUrl = "static/map/point.png"
+			var markerIcon = L.icon({
+				iconUrl: iconUrl,
+				iconSize: iconSize,
+				// iconSize: [30, 30],
+				// iconAnchor: [10, 30]
+			});
+			var marker = L.marker([position.latitude, position.longitude], {
+					icon: markerIcon
+				})
+				.addTo(this.cpMarkLayerGroup)
+			// marker = L.circleMarker([position.latitude, position.longitude], config.gStyle.checkPoint.default)
+			// 	.addTo(this.cpMarkLayerGroup)
+		}
 
 		var myIcon = L.divIcon({
-			html: '<div>' + data.sn + '</div>',
+			html: html,
 			className: 'my-div-icon',
 			iconSize: [60, 20], //宽高
-			iconAnchor: [30, 35] //文字标注相对位置
+			iconAnchor: [30, 30] //文字标注相对位置
 		});
 		var markerMemo = L.marker([position.latitude, position.longitude], {
 				icon: myIcon,
@@ -125,8 +180,6 @@ export default {
 		}
 	},
 	drawAllPath() {
-		return
-		
 		// console.log("[drawAllPath] routes", global.routes)
 		if (this.cpPathLayerGroup != null) {
 			this.cpPathLayerGroup.clearLayers()
@@ -167,7 +220,7 @@ export default {
 		// ]
 		var PointArry = []
 		// var Circles = []
-		var radius = 20 // 圆的半径 px
+		// var radius = 20 // 圆的半径 px
 		var DistanceArry = []
 		var Lines = []
 		for (let i = 0; i < LatLngArry.length; i++) {

+ 5 - 0
actMgt/utils/tools.js

@@ -232,6 +232,11 @@ var tools = {
 				return `${minutes}′${remainingSeconds.toString().padStart(2, '0')}″`;
 		}
 	},
+	
+	// 格式化距离为公里
+	fmtDistanctKm(val) {
+		return Math.round(val * 100 / 1000) / 100;
+	},
 
 	// 计算(中英文混合)字符串长度
 	calStrLen(str) {