请问如何S地图层级控制:「『
// qrc:/qml/common/DiscoverPage/PersonalRidingPage.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtPositioning 5.15
import Qt5Compat.GraphicalEffects
import QtWebView 1.15
import "qrc:/qml/common/DiscoverPage/"
import App.Models 1.0
import RadioApp.Permission 1.0
Page {
id: root
background: Rectangle { color: "#0f0f14" }
// 使用 RidingDataModel 的属性
property real todayTotalDistance: RidingDataModel ? RidingDataModel.todayTotalDistance : 0.0
property real currentRideDistance: RidingDataModel ? RidingDataModel.currentDistance / 1000.0 : 0.0 // 米转公里
property real currentSpeed: RidingDataModel ? RidingDataModel.currentSpeed * 3.6 : 0.0 // m/s 转 km/h
property real maxSpeed: RidingDataModel ? RidingDataModel.maxSpeed * 3.6 : 0.0 // m/s 转 km/h
property real maxAltitude: RidingDataModel ? RidingDataModel.maxAltitude : 0.0
property int ridingTime: RidingDataModel ? RidingDataModel.ridingTime : 0
property string formattedRidingTime: formatTime(ridingTime)
// 从 RidingDataModel 获取状态
property bool isRiding: RidingDataModel ? RidingDataModel.isRiding : false
property bool isPaused: RidingDataModel ? RidingDataModel.isPaused : false
property string lastRecordId: RidingDataModel ? RidingDataModel.recordId : ""
// 状态标志
property bool isDestroyed: false
property bool isInitialized: false
property bool permissionsGranted: false
property bool permissionsChecking: false
// 地图控制按钮属性
property string btnBlue: "#007bff"
property real btnSize: 0.6
property bool requestCenter: false
// JavaScript 通信相关的属性 - 修改为直接使用 HTTP URL
//property string mapUrl: "https://www.xjsfly.com/radio_map/map.html" // 直接使用网络URL
property string mapUrl: "http://119.91.39.85/maps/map.html" // 直接使用网络URL
property bool mapLoadedFromWeb: false
property bool mapLoading: false
// 平台特定调整
property real platformScale: Qt.platform.os === "android" ? 1.2 : 1.0
property real buttonTopMargin: Qt.platform.os === "android" ? 50 : 30
property real buttonSideMargin: Qt.platform.os === "android" ? 25 : 20
// 权限管理器
property PermissionManager permissionManager: PermissionManager {
id: permissionManager
onPermissionGranted: {
console.log("权限已授予:", permissionTypeToString(permissionType))
checkAllRequiredPermissions()
}
onPermissionDenied: {
console.log("权限被拒绝:", permissionTypeToString(permissionType))
showPermissionDeniedDialog(permissionType)
}
onAllRequiredPermissionsGranted: {
console.log("所有必需权限已授予")
permissionsGranted = true
permissionsChecking = false
// 权限就绪后继续初始化
if (!isInitialized) {
continueInitialization()
}
}
onEssentialPermissionsGranted: {
console.log("核心权限已授予")
permissionsGranted = true
}
onShowPermissionRationale: {
console.log("显示权限解释:", rationale)
showPermissionRationaleDialog(permissionType, rationale)
}
onShowPermissionExplanation: {
console.log("显示权限说明:", title, message)
showPermissionExplanationDialog(permissionType, title, message)
}
}
// 时间格式化函数
function formatTime(seconds) {
if (isDestroyed) return "00:00";
var hours = Math.floor(seconds / 3600);
var minutes = Math.floor((seconds % 3600) / 60);
var secs = seconds % 60;
if (hours > 0) {
return hours + ":" +
(minutes < 10 ? "0" + minutes : minutes) + ":" +
(secs < 10 ? "0" + secs : secs);
} else {
return (minutes < 10 ? "0" + minutes : minutes) + ":" +
(secs < 10 ? "0" + secs : secs);
}
}
// 权限检查函数
function checkLocationPermission() {
if (isDestroyed) return false;
if (positionSource.supportedPositioningMethods === PositionSource.NoPositioningMethods) {
console.error("设备不支持定位功能");
showPermissionDialog("定位功能不可用", "您的设备不支持定位功能,请检查设备设置。");
return false;
}
if (positionSource.active === false) {
console.warn("定位服务未激活");
showPermissionDialog("定位权限", "请确保已授予应用定位权限,并在系统设置中开启定位服务。");
return false;
}
return true;
}
// 检查所有必需的权限
function checkAllRequiredPermissions() {
console.log("开始检查所有必需权限...")
permissionsChecking = true
// 使用 PermissionManager 的枚举值
var locationGranted = permissionManager.checkPermission(permissionManager.LocationPermission)
var coarseLocationGranted = permissionManager.checkPermission(permissionManager.CoarseLocationPermission)
var backgroundLocationGranted = permissionManager.checkPermission(permissionManager.BackgroundLocationPermission)
console.log("定位权限状态 - 精确定位:", locationGranted,
"粗略定位:", coarseLocationGranted,
"后台定位:", backgroundLocationGranted)
if (locationGranted && coarseLocationGranted) {
permissionsGranted = true
permissionsChecking = false
console.log("定位权限已授予,继续初始化")
if (!isInitialized) {
continueInitialization()
}
} else {
console.log("定位权限未完全授予,请求权限...")
requestLocationPermissions()
}
}
// 请求定位相关权限
function requestLocationPermissions() {
if (isDestroyed) return;
console.log("请求定位相关权限...")
// 使用智能上下文请求权限
permissionManager.requestSmartPermissions("navigation_app")
}
// 权限类型转字符串
function permissionTypeToString(permissionType) {
// 这里 permissionType 已经是数字值,直接比较即可
if (permissionType === permissionManager.LocationPermission) return "精确定位"
if (permissionType === permissionManager.CoarseLocationPermission) return "粗略定位"
if (permissionType === permissionManager.BackgroundLocationPermission) return "后台定位"
if (permissionType === permissionManager.CameraPermission) return "相机"
if (permissionType === permissionManager.MicrophonePermission) return "麦克风"
if (permissionType === permissionManager.StoragePermission) return "存储"
if (permissionType === permissionManager.BluetoothPermission) return "蓝牙"
return "未知权限"
}
// 显示权限解释对话框
function showPermissionRationaleDialog(permissionType, rationale) {
if (isDestroyed) return;
var component = Qt.createComponent("qrc:/qml/common/PermissionRationaleDialog.qml");
if (component.status === Component.Ready) {
var dialog = component.createObject(root, {
permissionType: permissionType,
rationale: rationale,
permissionManager: permissionManager
});
dialog.open();
} else {
// 回退到通用对话框
showPermissionDialog("权限说明", rationale)
}
}
// 显示权限说明对话框
function showPermissionExplanationDialog(permissionType, title, message) {
if (isDestroyed) return;
showPermissionDialog(title, message)
}
// 显示权限被拒绝对话框
function showPermissionDeniedDialog(permissionType) {
if (isDestroyed) return;
var permissionName = permissionTypeToString(permissionType)
var message = permissionName + "权限被拒绝,相关功能将无法正常使用。"
var suggestion = "请前往应用设置中手动启用此权限"
showPermissionDialog("权限被拒绝", message + "\n\n" + suggestion)
}
// 通用权限对话框
function showPermissionDialog(title, message) {
if (isDestroyed) return;
var component = Qt.createComponent("qrc:/qml/common/CommonDialog.qml");
if (component.status === Component.Ready) {
var dialog = component.createObject(root, {
title: title,
message: message
});
dialog.open();
}
}
// 继续初始化(权限检查通过后)
function continueInitialization() {
if (isDestroyed || isInitialized) return;
console.log("权限检查通过,继续初始化...")
console.log("使用新的布局结构 - 地图区域:", mapContainer.width + "x" + mapContainer.height)
console.log("按钮覆盖层区域:", buttonsOverlay.width + "x" + buttonsOverlay.height)
// 直接使用网络URL加载地图
loadMapFromWeb()
initTimer.start()
// 安卓上延迟调试按钮布局
if (Qt.platform.os === "android") {
Qt.callLater(function() {
if (!isDestroyed) {
debugButtonLayout()
// 安卓上可能需要额外的刷新
Qt.callLater(forceButtonsRefresh)
}
})
}
}
// 从网络加载地图文件
function loadMapFromWeb() {
if (isDestroyed) return;
console.log("使用网络URL加载地图...")
mapLoading = true
// 直接使用网络URL
console.log("设置地图 URL:", mapUrl)
webView.url = mapUrl
}
// 更新统计数据
function updateStats() {
if (!permissionsGranted) return;
todayTotalDistance = RidingDataModel ? RidingDataModel.todayTotalDistance : 0.0;
currentRideDistance = RidingDataModel ? RidingDataModel.currentDistance / 1000.0 : 0.0;
currentSpeed = RidingDataModel ? RidingDataModel.currentSpeed * 3.6 : 0.0;
maxSpeed = RidingDataModel ? RidingDataModel.maxSpeed * 3.6 : 0.0;
maxAltitude = RidingDataModel ? RidingDataModel.maxAltitude : 0.0;
ridingTime = RidingDataModel ? RidingDataModel.ridingTime : 0;
console.log("更新统计数据:",
"今日总距离:", todayTotalDistance.toFixed(2),
"当前距离:", currentRideDistance.toFixed(2),
"当前速度:", currentSpeed.toFixed(1),
"最高速度:", maxSpeed.toFixed(1),
"最高海拔:", maxAltitude.toFixed(0));
}
// JavaScript 调用函数
function executeJavaScript(code) {
if (isDestroyed || !webView || !permissionsGranted) return;
try {
webView.runJavaScript(code);
} catch (error) {
console.error("执行 JavaScript 失败:", error);
}
}
// 处理来自 JavaScript 的消息
function handleJavaScriptMessage(url) {
if (isDestroyed || !permissionsGranted || !url) return;
var urlString = url.toString();
if (urlString.indexOf("qtbridge://") === -1) return;
try {
var message = urlString.split("qtbridge://")[1];
var parts = message.split("/");
var action = parts[0].toLowerCase(); // 转换为小写统一处理
var data = parts.length > 1 ? parts[1] : "";
console.log("收到 JavaScript 消息:", action, data);
switch(action) {
case "mapready":
console.log("高德地图初始化完成");
handleMapReady();
break;
case "distancecalculated":
var distance = parseFloat(data);
console.log("JavaScript计算距离:", distance, "米");
handleDistanceCalculated(distance);
break;
case "positionupdated":
var coords = data.split(",");
var lat = parseFloat(coords[0]);
var lng = parseFloat(coords[1]);
console.log("地图位置更新:", lat, lng);
break;
case "error":
console.error("JavaScript错误:", decodeURIComponent(data));
break;
default:
console.log("未知消息类型:", action);
}
} catch (error) {
console.error("处理JavaScript消息失败:", error);
}
}
// 清除地图轨迹
function clearMapTrack() {
executeJavaScript(`
if (window.clearTrack) {
window.clearTrack();
} else if (window.qtTrackLine && window.qtMap) {
window.qtTrackPoints = [];
window.qtTrackLine.setPath([]);
window.qtTotalDistance = 0;
console.log("轨迹已清除");
}
`);
}
// 添加轨迹点
function addTrackPoint(latitude, longitude) {
executeJavaScript(`
if (window.addTrackPoint) {
window.addTrackPoint(${latitude}, ${longitude});
} else if (window.qtTrackLine && window.qtMap && window.qtMarker) {
try {
var point = new AMap.LngLat(${longitude}, ${latitude});
window.qtTrackPoints.push(point);
window.qtTrackLine.setPath(window.qtTrackPoints);
// 更新标记位置
window.qtMarker.setPosition(point);
// 计算距离
if (window.qtTrackPoints.length > 1) {
var total = 0;
for (var i = 1; i < window.qtTrackPoints.length; i++) {
total += window.qtTrackPoints[i-1].distance(window.qtTrackPoints[i]);
}
window.qtTotalDistance = total;
// 发送距离到Qt
window.location.href = "qtbridge://distanceCalculated/" + total;
}
// 自动调整地图视野
if (window.qtTrackPoints.length === 1) {
window.qtMap.setCenter(point);
} else {
window.qtMap.setFitView();
}
console.log("添加轨迹点:", ${latitude}, ${longitude});
} catch (error) {
console.error("添加轨迹点失败:", error);
}
}
`);
}
// 设置地图中心
function setMapCenter(latitude, longitude) {
executeJavaScript(`
if (window.setMapCenter) {
window.setMapCenter(${latitude}, ${longitude});
} else if (window.qtMap && window.qtMarker) {
try {
var point = new AMap.LngLat(${longitude}, ${latitude});
window.qtMap.setCenter(point);
window.qtMarker.setPosition(point);
console.log("设置地图中心:", ${latitude}, ${longitude});
} catch (error) {
console.error("设置地图中心失败:", error);
}
}
`);
}
// 处理JavaScript计算的距离
function handleDistanceCalculated(distance) {
if (isDestroyed || !RidingDataModel) return;
console.log("收到JavaScript计算的距离:", distance, "米");
RidingDataModel.updateDistance(distance);
}
// 处理地图就绪
function handleMapReady() {
if (isDestroyed) return;
console.log("高德地图准备就绪");
// 地图就绪后可以执行一些初始化操作
}
// 调试按钮布局
function debugButtonLayout() {
if (isDestroyed) return
console.log("=== 按钮布局调试信息 ===")
console.log("平台:", Qt.platform.os)
console.log("屏幕尺寸:", root.width, "x", root.height)
console.log("地图容器尺寸:", mapContainer.width, "x", mapContainer.height)
console.log("按钮覆盖层尺寸:", buttonsOverlay.width, "x", buttonsOverlay.height)
console.log("按钮覆盖层z值:", buttonsOverlay.z)
console.log("WebView z值:", webView.z)
var buttons = [
{name: "速度按钮", obj: speedButton},
{name: "功能按钮组", obj: functionButtons},
{name: "中心按钮", obj: centerButton},
{name: "倾角按钮", obj: tiltButton},
{name: "打卡按钮", obj: checkinButton}
]
buttons.forEach(function(btn) {
if (btn.obj) {
console.log(btn.name + ":",
"可见:", btn.obj.visible,
"位置:", btn.obj.x + "," + btn.obj.y,
"尺寸:", btn.obj.width + "x" + btn.obj.height,
"z值:", btn.obj.z,
"图层启用:", btn.obj.layer ? btn.obj.layer.enabled : "N/A")
} else {
console.log(btn.name + ": 未定义")
}
})
}
// 强制刷新按钮显示
function forceButtonsRefresh() {
if (isDestroyed) return
console.log("强制刷新按钮显示状态")
// 临时隐藏再显示,强制重绘
var buttons = [speedButton, functionButtons, centerButton, tiltButton, checkinButton]
buttons.forEach(function(button) {
if (button) {
var wasVisible = button.visible
button.visible = false
Qt.callLater(function() {
if (button && !isDestroyed) {
button.visible = wasVisible
console.log("刷新按钮:", button.objectName || "未知", "位置:", button.x, button.y)
}
})
}
})
}
// 在 Component.onCompleted 中添加更多调试信息
Component.onCompleted: {
console.log("个人骑行页面初始化开始");
console.log("RidingDataModel 可用:", RidingDataModel !== undefined);
console.log("PermissionManager 可用:", permissionManager !== undefined);
console.log("地图URL:", mapUrl);
console.log("WebView 组件状态:", webView !== undefined);
console.log("当前平台:", Qt.platform.os);
// 安卓特定初始化
if (Qt.platform.os === "android") {
console.log("安卓平台检测到,应用特定优化")
// 调整按钮大小和位置以适应安卓
btnSize = 0.8
}
// 调试权限类型
permissionManager.debugPermissionTypes();
// 首先检查权限
checkAllRequiredPermissions();
}
Component.onDestruction: {
console.log("个人骑行页面开始销毁");
isDestroyed = true;
// 停止所有定时器
statsTimer.stop();
initTimer.stop();
positionSource.active = false;
console.log("个人骑行页面销毁完成");
}
// 延迟初始化定时器
Timer {
id: initTimer
interval: 500
running: false
repeat: false
onTriggered: {
if (isDestroyed || !permissionsGranted) return;
console.log("执行延迟初始化");
updateStats();
// 启动统计更新定时器
statsTimer.start();
isInitialized = true;
console.log("个人骑行页面初始化完成");
}
}
// 定时器用于定期更新统计
Timer {
id: statsTimer
interval: 1000
running: false
repeat: true
onTriggered: {
if (!isDestroyed && isInitialized && permissionsGranted) {
updateStats();
}
}
}
// 权限检查覆盖层
Rectangle {
id: permissionOverlay
anchors.fill: parent
color: "#CC000000"
visible: !permissionsGranted || permissionsChecking
z: 1000
Column {
anchors.centerIn: parent
spacing: 20
BusyIndicator {
id: permissionBusyIndicator
running: permissionsChecking
width: 50
height: 50
anchors.horizontalCenter: parent.horizontalCenter
}
Text {
text: permissionsChecking ? "正在检查权限..." : "需要定位权限才能使用骑行功能"
color: "white"
font.pixelSize: 16
anchors.horizontalCenter: parent.horizontalCenter
}
Button {
text: "请求权限"
visible: !permissionsChecking && !permissionsGranted
anchors.horizontalCenter: parent.horizontalCenter
onClicked: {
requestLocationPermissions()
}
}
Text {
text: "骑行功能需要精确定位权限来记录您的轨迹和位置"
color: "#CCCCCC"
font.pixelSize: 14
width: parent.width * 0.8
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
anchors.horizontalCenter: parent.horizontalCenter
}
}
}
// 地图加载状态覆盖层
Rectangle {
id: mapLoadingOverlay
anchors.fill: parent
color: "#CC000000"
visible: mapLoading
z: 999
Column {
anchors.centerIn: parent
spacing: 20
BusyIndicator {
id: mapLoadingIndicator
running: mapLoading
width: 50
height: 50
anchors.horizontalCenter: parent.horizontalCenter
}
Text {
text: "正在加载地图..."
color: "white"
font.pixelSize: 16
anchors.horizontalCenter: parent.horizontalCenter
}
Text {
text: "请确保网络连接正常"
color: "#CCCCCC"
font.pixelSize: 14
width: parent.width * 0.8
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
anchors.horizontalCenter: parent.horizontalCenter
}
// 添加重试按钮
Button {
text: "重试加载"
visible: !mapLoadingIndicator.running && mapLoading
anchors.horizontalCenter: parent.horizontalCenter
onClicked: {
console.log("手动重试地图加载")
webView.reload()
}
}
}
}
// 状态变化监听 - 监听 RidingDataModel
Connections {
id: ridingDataModelConnections
target: RidingDataModel
enabled: !isDestroyed && isInitialized && RidingDataModel !== undefined && permissionsGranted
function onIsRidingChanged() {
if (isDestroyed) return;
console.log("骑行状态改变 - 是否骑行:", RidingDataModel.isRiding);
Qt.callLater(updateStats);
}
function onIsPausedChanged() {
if (isDestroyed) return;
console.log("暂停状态改变 - 是否暂停:", RidingDataModel.isPaused);
Qt.callLater(updateStats);
}
function onCurrentDistanceChanged() {
if (isDestroyed) return;
Qt.callLater(updateStats);
}
function onCurrentSpeedChanged() {
if (isDestroyed) return;
Qt.callLater(updateStats);
}
function onRidingTimeChanged() {
if (isDestroyed) return;
Qt.callLater(updateStats);
}
function onMaxSpeedChanged() {
if (isDestroyed) return;
Qt.callLater(updateStats);
}
function onMaxAltitudeChanged() {
if (isDestroyed) return;
Qt.callLater(updateStats);
}
function onTodayTotalDistanceChanged() {
if (isDestroyed) return;
Qt.callLater(updateStats);
}
}
// 主要修改:使用Column布局分离地图和数据面板
Item {
anchors.fill: parent
enabled: permissionsGranted
opacity: permissionsGranted ? 1.0 : 0.3
// 使用Column布局分离地图和数据面板
Column {
anchors.fill: parent
spacing: 0
// 地图区域 - 固定高度
Item {
id: mapContainer
width: parent.width
height: parent.height * 28/33
z: 0
Component.onCompleted: {
console.log("地图容器创建完成,尺寸:", width, "x", height)
}
// 使用 WebView 显示地图
WebView {
id: webView
anchors.fill: parent
visible: !isDestroyed && permissionsGranted && !mapLoading
url: mapUrl
z: 0
Component.onCompleted: {
if (Qt.platform.os === "android") {
console.log("安卓 WebView 配置: 启用混合内容和文件访问");
}
}
onLoadingChanged: function(loadRequest) {
if (isDestroyed || !permissionsGranted) return;
console.log("=== 页面加载状态 ===");
console.log("当前平台:", Qt.platform.os);
console.log("页面加载状态:", loadRequest.status);
console.log("页面URL:", webView.url);
console.log("请求URL:", loadRequest.url);
console.log("错误信息:", loadRequest.errorString);
if (loadRequest.url.toString().indexOf("qtbridge://") === 0) {
console.log("忽略 qtbridge 通信请求,状态:", loadRequest.status);
return;
}
switch(loadRequest.status) {
case WebView.LoadStartedStatus:
console.log("开始加载地图页面");
mapLoading = true;
break;
case WebView.LoadSucceededStatus:
console.log("地图页面加载成功");
mapLoading = false;
mapLoadedFromWeb = true;
// Android上尝试设置透明背景
if (Qt.platform.os === "android") {
Qt.callLater(function() {
if (!isDestroyed) {
webView.runJavaScript(`
try {
document.body.style.backgroundColor = 'transparent';
document.body.style.overflow = 'hidden';
if (document.querySelector('.amap-container')) {
document.querySelector('.amap-container').style.backgroundColor = 'transparent';
}
} catch(e) {
console.log('设置透明背景失败:', e);
}
`);
}
});
}
if (Qt.platform.os === "android") {
Qt.callLater(forceButtonsRefresh)
}
break;
case WebView.LoadFailedStatus:
console.error("地图页面加载失败:", loadRequest.errorString);
console.error("错误详情:", {
url: loadRequest.url,
errorString: loadRequest.errorString
});
mapLoading = false;
showMapLoadError(loadRequest.errorString);
break;
}
}
onUrlChanged: {
if (isDestroyed || !permissionsGranted) return;
var urlString = webView.url.toString();
console.log("URL改变:", urlString);
if (urlString.indexOf("qtbridge://") === 0) {
handleJavaScriptMessage(webView.url);
}
}
}
// 定位源
PositionSource {
id: positionSource
active: false
updateInterval: 1000
preferredPositioningMethods: PositionSource.AllPositioningMethods
onPositionChanged: {
if (isDestroyed || !permissionsGranted) {
active = false;
return;
}
if (requestCenter && position.latitudeValid && position.longitudeValid) {
var coord = position.coordinate;
setMapCenter(coord.latitude, coord.longitude);
requestCenter = false;
active = false;
console.log("回到中心位置:", coord.latitude, coord.longitude);
}
}
onSourceErrorChanged: {
if (isDestroyed || !permissionsGranted) return;
if (sourceError !== PositionSource.NoError) {
console.error("定位错误:", sourceError);
requestCenter = false;
active = false;
}
}
}
}
// 运动数据区域 - 固定高度
Rectangle {
id: dataPanel
width: parent.width
height: parent.height * 5/33
color: "#333333"
z: 10 // 确保在按钮层之上
visible: !isDestroyed && permissionsGranted
property real rowSpacing: 10
property real columnSpacing: 10
property real topMargin: 10
property real valueFontSize: 21
property real labelFontSize: 10
ColumnLayout {
anchors.fill: parent
anchors.margins: dataPanel.topMargin
spacing: dataPanel.rowSpacing
Item {
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: parent.width * 3/4
Layout.fillHeight: true
Row {
anchors.fill: parent
spacing: dataPanel.columnSpacing
// 今日总里程
Column {
width: parent.width / 3
height: parent.height
spacing: 2
Text {
text: isDestroyed ? "0.00" : todayTotalDistance.toFixed(2)
color: "white"
font.pixelSize: dataPanel.valueFontSize
font.bold: true
anchors.horizontalCenter: parent.horizontalCenter
}
Text {
text: "今日总里程(km)"
color: "#aaaaaa"
font.pixelSize: dataPanel.labelFontSize
anchors.horizontalCenter: parent.horizontalCenter
}
}
// 本次骑行里程
Column {
width: parent.width / 3
height: parent.height
spacing: 2
Text {
text: isDestroyed ? "0.00" : currentRideDistance.toFixed(2)
color: "white"
font.pixelSize: dataPanel.valueFontSize
font.bold: true
anchors.horizontalCenter: parent.horizontalCenter
}
Text {
text: "本次骑行里程(km)"
color: "#aaaaaa"
font.pixelSize: dataPanel.labelFontSize
anchors.horizontalCenter: parent.horizontalCenter
}
}
// 本次骑行时间
Column {
width: parent.width / 3
height: parent.height
spacing: 2
Text {
text: isDestroyed ? "00:00" : formattedRidingTime
color: "white"
font.pixelSize: dataPanel.valueFontSize
font.bold: true
anchors.horizontalCenter: parent.horizontalCenter
}
Text {
text: "本次骑行时间"
color: "#aaaaaa"
font.pixelSize: dataPanel.labelFontSize
anchors.horizontalCenter: parent.horizontalCenter
}
}
}
}
Item {
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: parent.width * 3/5
Layout.fillHeight: true
Row {
anchors.fill: parent
spacing: dataPanel.columnSpacing
Row {
width: parent.width / 2
height: parent.height
spacing: 5
anchors.verticalCenter: parent.verticalCenter
Text {
text: "最高海拔"
color: "#aaaaaa"
font.pixelSize: dataPanel.labelFontSize
anchors.verticalCenter: parent.verticalCenter
}
Text {
text: isDestroyed ? "0" : maxAltitude.toFixed(0)
color: "white"
font.pixelSize: dataPanel.valueFontSize
font.bold: true
anchors.verticalCenter: parent.verticalCenter
}
Text {
text: "m"
color: "#aaaaaa"
font.pixelSize: dataPanel.labelFontSize
anchors.verticalCenter: parent.verticalCenter
}
}
Row {
width: parent.width / 2
height: parent.height
spacing: 5
anchors.verticalCenter: parent.verticalCenter
Text {
text: "最高车速"
color: "#aaaaaa"
font.pixelSize: dataPanel.labelFontSize
anchors.verticalCenter: parent.verticalCenter
}
Text {
text: isDestroyed ? "0.0" : maxSpeed.toFixed(1)
color: "white"
font.pixelSize: dataPanel.valueFontSize
font.bold: true
anchors.verticalCenter: parent.verticalCenter
}
Text {
text: "km/h"
color: "#aaaaaa"
font.pixelSize: dataPanel.labelFontSize
anchors.verticalCenter: parent.verticalCenter
}
}
}
}
}
}
}
// 按钮覆盖层 - 只覆盖地图区域,不覆盖数据面板
Item {
id: buttonsOverlay
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
height: mapContainer.height // 只覆盖地图区域
z: 999 // 设置为最高层级
enabled: !isDestroyed && permissionsGranted
Component.onCompleted: {
console.log("按钮覆盖层创建完成,尺寸:", width, "x", height)
console.log("地图容器高度:", mapContainer.height)
debugButtonLayout()
}
// 1. 左上角:速度显示按钮
Rectangle {
id: speedButton
width: 120 * btnSize * platformScale
height: 120 * btnSize * platformScale
radius: height/2
color: btnBlue
x: buttonSideMargin
y: buttonTopMargin
visible: !isDestroyed && permissionsGranted
z: 1000 // 最高优先级
// 添加强制渲染属性
layer.enabled: true
layer.smooth: true
Component.onCompleted: {
console.log("速度按钮创建完成,位置:", x, y, "尺寸:", width, height)
}
Column {
anchors.centerIn: parent
spacing: 0
Text {
text: isDestroyed ? "0.0" : Math.min(currentSpeed.toFixed(1), 99.9)
color: "white"
font.pixelSize: 19 * platformScale
font.bold: true
anchors.horizontalCenter: parent.horizontalCenter
}
Text {
text: "km/h"
color: "white"
font.pixelSize: 14 * 0.8 * platformScale
anchors.horizontalCenter: parent.horizontalCenter
}
}
}
// 2. 右上角:功能按钮组
Rectangle {
id: functionButtons
width: 60 * platformScale
height: 240 * platformScale
radius: 8
color: "#CC000000"
x: parent.width - width - buttonSideMargin
y: buttonTopMargin
visible: !isDestroyed && permissionsGranted
z: 1000
Component.onCompleted: {
console.log("功能按钮组创建完成,位置:", x, y, "尺寸:", width, height)
}
Column {
anchors.fill: parent
spacing: 0
FunctionButton {
width: parent.width
height: parent.height / 5
iconSource: "qrc:/assets/icons/discover/floating.png"
tooltip: "悬浮窗功能"
iconWidth: parent.width - 10
iconHeight: parent.height / 5 - 20
containerPadding: 0
enableOpacityEffect: true
enableScaleEffect: true
enableColorEffect: true
onClicked: {
if (!isDestroyed) console.log("悬浮窗功能")
}
}
Rectangle {
width: parent.width * 2 / 3
height: 1
anchors.horizontalCenter: parent.horizontalCenter
color: "#80FFFFFF"
}
// 暂停/继续按钮
FunctionButton {
width: parent.width
height: parent.height / 5
iconSource: {
if (isDestroyed || !RidingDataModel) return "qrc:/assets/icons/pause.png";
return RidingDataModel.isPaused ?
"qrc:/assets/icons/play.png" :
"qrc:/assets/icons/pause.png";
}
tooltip: {
if (isDestroyed || !RidingDataModel) return "暂停";
return RidingDataModel.isPaused ? "继续" : "暂停";
}
iconWidth: parent.width - 10
iconHeight: parent.height / 5 - 20
containerPadding: 0
enableOpacityEffect: true
enableScaleEffect: true
enableColorEffect: true
onClicked: {
if (isDestroyed || !RidingDataModel || !permissionsGranted) return;
try {
if (RidingDataModel.isRiding && !RidingDataModel.isPaused) {
RidingDataModel.pauseRiding();
} else if (RidingDataModel.isRiding && RidingDataModel.isPaused) {
RidingDataModel.resumeRiding();
}
} catch (error) {
console.error("操作骑行状态失败:", error);
}
}
}
Rectangle {
width: parent.width * 2 / 3
height: 1
anchors.horizontalCenter: parent.horizontalCenter
color: "#80FFFFFF"
}
FunctionButton {
width: parent.width
height: parent.height / 5
iconSource: "qrc:/assets/icons/discover/friends.png"
tooltip: "交友功能"
iconWidth: parent.width - 10
iconHeight: parent.height / 5 - 20
containerPadding: 0
enableOpacityEffect: true
enableScaleEffect: true
enableColorEffect: true
onClicked: {
if (!isDestroyed) console.log("交友功能")
}
}
Rectangle {
width: parent.width * 2 / 3
height: 1
anchors.horizontalCenter: parent.horizontalCenter
color: "#80FFFFFF"
}
FunctionButton {
width: parent.width
height: parent.height / 5
iconSource: "qrc:/assets/icons/discover/vlink.png"
tooltip: "已链接状态"
iconWidth: parent.width - 10
iconHeight: parent.height / 5 - 20
containerPadding: 0
enableOpacityEffect: true
enableScaleEffect: true
enableColorEffect: true
onClicked: {
if (!isDestroyed) console.log("已链接状态")
}
}
Rectangle {
width: parent.width * 2 / 3
height: 1
anchors.horizontalCenter: parent.horizontalCenter
color: "#80FFFFFF"
}
// 分享按钮
FunctionButton {
width: parent.width
height: parent.height / 5
iconSource: "qrc:/assets/icons/discover/share.png"
tooltip: "分享轨迹"
iconWidth: parent.width - 10
iconHeight: parent.height / 5 - 20
containerPadding: 0
enableOpacityEffect: true
enableScaleEffect: true
enableColorEffect: true
onClicked: {
if (isDestroyed || !permissionsGranted) return;
console.log("分享轨迹");
}
}
}
}
// 3. 回到中心按钮
Rectangle {
id: centerButton
width: functionButtons.width
height: functionButtons.width
x: parent.width - width - buttonSideMargin
y: functionButtons.y + functionButtons.height + 30
radius: 8
color: "#CC000000"
visible: !isDestroyed && permissionsGranted
z: 1000
Component.onCompleted: {
console.log("中心按钮创建完成,位置:", x, y)
}
FunctionButton {
anchors.fill: parent
iconSource: "qrc:/assets/icons/discover/location.png"
iconWidth: 30
iconHeight: 30
containerPadding: (parent.width - 24) / 2
enableOpacityEffect: true
enableScaleEffect: true
enableColorEffect: true
normalColor: "white"
pressedColor: "#4d8eff"
onClicked: {
if (isDestroyed || !permissionsGranted) return;
console.log("回到中心位置");
requestCenter = true;
positionSource.active = true;
}
}
}
// 4. 左下角:记录倾角按钮
Rectangle {
id: tiltButton
width: 100 * btnSize * platformScale
height: 100 * btnSize * platformScale
radius: height/2
color: btnBlue
x: buttonSideMargin
y: parent.height - height - buttonSideMargin
z: 1000
visible: !isDestroyed && permissionsGranted
// 添加强制渲染属性
layer.enabled: true
layer.smooth: true
Component.onCompleted: {
console.log("倾角按钮创建完成,位置:", x, y)
}
scale: mouseAreaTilt.pressed ? 0.95 : 1.0
opacity: mouseAreaTilt.pressed ? 0.95 : 1.0
Behavior on scale {
enabled: !isDestroyed
NumberAnimation { duration: 150; easing.type: Easing.InOutQuad }
}
Behavior on opacity {
enabled: !isDestroyed
NumberAnimation { duration: 150; easing.type: Easing.InOutQuad }
}
Text {
text: "记录倾角"
color: "white"
font.pixelSize: 13 * platformScale
anchors.centerIn: parent
}
MouseArea {
id: mouseAreaTilt
anchors.fill: parent
onClicked: {
if (!isDestroyed && permissionsGranted) console.log("记录倾角功能")
}
}
}
// 5. 右下角:打卡按钮
Rectangle {
id: checkinButton
width: 120 * btnSize * platformScale
height: 50 * btnSize * platformScale
radius: 8
color: btnBlue
x: parent.width - width - buttonSideMargin
y: parent.height - height - buttonSideMargin
visible: !isDestroyed && permissionsGranted
z: 1000
// 添加强制渲染属性
layer.enabled: true
layer.smooth: true
Component.onCompleted: {
console.log("打卡按钮创建完成,位置:", x, y)
}
scale: mouseAreaCheckin.pressed ? 0.95 : 1.0
opacity: mouseAreaCheckin.pressed ? 0.95 : 1.0
Behavior on scale {
enabled: !isDestroyed
NumberAnimation { duration: 150; easing.type: Easing.InOutQuad }
}
Behavior on opacity {
enabled: !isDestroyed
NumberAnimation { duration: 150; easing.type: Easing.InOutQuad }
}
Text {
text: {
if (isDestroyed || !RidingDataModel) return "开始记录";
if (!RidingDataModel.isRiding) return "开始记录";
return RidingDataModel.isPaused ? "继续记录" : "停止记录";
}
color: "white"
font.pixelSize: 16 * platformScale
anchors.centerIn: parent
}
MouseArea {
id: mouseAreaCheckin
anchors.fill: parent
onClicked: {
if (isDestroyed || !RidingDataModel) {
console.error("RidingDataModel 未定义");
return;
}
if (!permissionsGranted) {
showPermissionDialog("权限提示", "请先授予定位权限以使用骑行记录功能");
requestLocationPermissions();
return;
}
if (!checkLocationPermission()) {
return;
}
try {
if (!RidingDataModel.isRiding) {
clearMapTrack();
RidingDataModel.startRiding();
} else {
if (RidingDataModel.isPaused) {
RidingDataModel.resumeRiding();
} else {
RidingDataModel.stopRiding();
}
}
} catch (error) {
console.error("操作骑行状态失败:", error);
}
}
onPressAndHold: {
if (isDestroyed || !RidingDataModel || !permissionsGranted) return;
if (RidingDataModel.isRiding && !RidingDataModel.isPaused) {
try {
RidingDataModel.pauseRiding();
} catch (error) {
console.error("暂停骑行失败:", error);
}
}
}
}
}
}
}
// 添加错误显示函数
function showMapLoadError(errorMsg) {
console.error("地图加载错误:", errorMsg);
var errorRect = Qt.createQmlObject(`
import QtQuick 2.15
import QtQuick.Controls 2.15
Rectangle {
id: errorOverlay
anchors.fill: parent
color: "#2C3E50"
Column {
anchors.centerIn: parent
spacing: 20
Text {
text: "地图加载失败"
color: "white"
font.pixelSize: 18
font.bold: true
}
Text {
text: "错误信息: ${errorMsg}"
color: "#E74C3C"
font.pixelSize: 14
width: parent.width * 0.8
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
}
Text {
text: "可能的原因:\\n• 网络连接问题\\n• 高德地图API密钥问题\\n• 跨域访问限制"
color: "#CCCCCC"
font.pixelSize: 12
width: parent.width * 0.8
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
}
Button {
text: "重新加载"
onClicked: {
webView.reload()
}
}
}
}
`, webView.parent, "errorOverlay");
}
}
』」
最新发布