xiaokuaisong-xiaochengxu/uniapp04/uni_modules/uni-map-common/uniCloud/cloudfunctions/uni-map-co/index.obj.js
2025-04-11 14:42:29 +08:00

558 lines
15 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 引入uni-map-common公共模块
const UniMap = require('uni-map-common');
const configCenter = require("uni-config-center");
// 读取配置中心地图配置
var UniMapConfig = configCenter({ pluginId: 'uni-map' }).requireFile('config.js');
// 本地地图配置
var LocalMapConfig = {
"default": "", // 默认使用的平台
"key": {
"qqmap": "", // 腾讯地图key
"amap": "", // 高德地图key
}
}
const db = uniCloud.database();
const _ = db.command;
const $ = _.aggregate;
const opendbPoiDB = db.collection("opendb-poi");
class MyError extends Error {
constructor(errMsg, errCode = -1) {
super(errMsg);
this.err = {
errCode,
errMsg
}
}
}
module.exports = {
_before: function() {
// 如果配置中心不存在地图配置,则使用本地地图配置
if (!UniMapConfig) {
UniMapConfig = LocalMapConfig;
}
let defaultProvider = UniMapConfig.default || "qqmap";
let params = this.getParams();
let {
provider = defaultProvider,
needOriginalResult = false
} = params[0] || {};
const key = UniMapConfig.key[provider] || LocalMapConfig.key[provider];
if (!key) {
throw { errCode: -1, errMsg: `请在uni-config-center/uni-map/config.js中或LocalMapConfig中配置地图供应商${provider}对应的key` };
}
// 初始化实例
let uniMap = new UniMap({
provider: provider, // 指定使用哪家地图供应商
key: key,
needOriginalResult
});
this.uniMap = uniMap;
// // 在这里可以做一些统一的前置处理,比如权限校验、参数校验等
// let {
// payload, // payload参数为前端传递的参数可以在前端调用uni.chooseLocation时传递
// } = this.getParams()[0] || {};
// if (!payload) {
// throw new MyError("payload参数不能为空", -1);
// }
// // 如果业务在uniCloud上则直接在这里写判断逻辑即可
// if (true) {
// throw new MyError("权限不足", -1);
// }
// // 如果业务不在uniCloud上可通过 uniCloud.request 调用自己的服务进行校验
// const requestRes = await uniCloud.request({
// method: 'POST',
// url: '你自己的接口地址',
// data: payload,
// });
// // 约定errCode不为0代表校验失败errMsg为失败原因
// if (requestRes.data.errCode !== 0) {
// throw new MyError(requestRes.data.errMsg, requestRes.data.errCode);
// }
},
_after: function(err, res) {
if (err) {
if (err.err) {
return err.err;
}
if (err.errCode) {
return err;
}
throw err; // 如果方法抛出错误,也直接抛出不处理
}
console.log("result", res.result);
return res;
},
// 函数chooseLocation是给uni.chooseLocation使用请勿修改chooseLocation函数的代码
async chooseLocation(parame = {}) {
let res = {};
let {
action,
data,
needOriginalResult
} = parame;
// 获取uniMap实例
const uniMap = this.uniMap;
// 调用API
let result = await uniMap[action](data);
res.result = needOriginalResult ? result.originalResult : result;
// 模拟错误
// res.errCode = 121;
// res.errMsg = '此key每日调用量已达到上限'
return res;
},
// 经纬度坐标转地址
async location2address(data = {}) {
let res = {};
// 获取uniMap实例
const uniMap = this.uniMap;
// 调用API
let result = await uniMap.location2address(data);
res.result = result;
return res;
},
// 地址转经纬度坐标
async address2location(data = {}) {
let res = {};
// 获取uniMap实例
const uniMap = this.uniMap;
// 调用API
let result = await uniMap.address2location(data);
res.result = result;
return res;
},
// 坐标系转换
async translate(data = {}) {
let res = {};
// 获取uniMap实例
const uniMap = this.uniMap;
// 调用API
let result = await uniMap.translate(data);
res.result = result;
return res;
},
// ip定位
async ip2location(data = {}) {
let res = {};
// 获取uniMap实例
const uniMap = this.uniMap;
// 调用API
let result = await uniMap.ip2location(data);
res.result = result;
return res;
},
// 输入提示
async inputtips(data = {}) {
let res = {};
// 获取uniMap实例
const uniMap = this.uniMap;
// 调用API
let result = await uniMap.inputtips(data);
res.result = result;
return res;
},
// 搜索
async search(data = {}) {
let res = {};
// 获取uniMap实例
const uniMap = this.uniMap;
// 调用API
let result = await uniMap.search(data);
res.result = result;
return res;
},
// 行政区划
async districtSearch(data = {}) {
let res = {};
// 获取uniMap实例
const uniMap = this.uniMap;
// 调用API
let result = await uniMap.districtSearch(data);
res.result = result;
return res;
},
// 路径规划
async route(data = {}) {
let res = {};
// 获取uniMap实例
const uniMap = this.uniMap;
// 调用API
let result = await uniMap.route(data);
res.result = result;
return res;
},
// 演示用 - 清空所有的测试POI
async clearPoi(data = {}) {
let res = { errCode: 0 };
const db = uniCloud.database();
await db.collection("opendb-poi").where({
is_random: true
}).remove();
return res;
},
// 演示用 - 初始化静态001场景演示数据
async initStatic001(data = {}) {
let res = { errCode: 0 };
const category = "static-001";
// 先删除
await opendbPoiDB.where({
category: category
}).remove();
// 后添加随机数据
// 以天安门为中心
let tiananmen = {
longitude: 116.39747,
latitude: 39.908823,
};
let time = Date.now();
// 随机生成6个门店地址
let list = [];
for (let i = 1; i <= 6; i++) {
let randomCoordinate = getRandomCoordinateWithinRadius(tiananmen.longitude, tiananmen.latitude, 10); // 随机生成在天安门方圆X KM内的坐标
list.push({
category: category, // 场景值用于区分这些POI所属哪张地图
type: "门店",
title: `随机门店-${i}`,
location: new db.Geo.Point(randomCoordinate.longitude, randomCoordinate.latitude),
create_date: time,
visible: true,
is_random: true, // 表示此为随机生成的点,方便删除
level: i
});
}
// 随机生成1个总部地址
let randomCoordinate = getRandomCoordinateWithinRadius(tiananmen.longitude, tiananmen.latitude, 1); // 随机生成在天安门方圆X KM内的坐标
list.push({
category: category, // 场景值用于区分这些POI所属哪张地图
type: "总部",
title: `随机总部`,
location: new db.Geo.Point(randomCoordinate.longitude, randomCoordinate.latitude),
create_date: time,
visible: true,
is_random: true, // 表示此为随机生成的点,方便删除
level: 7
});
// 添加到数据库
await opendbPoiDB.add(list);
return res;
},
// 演示用 - 初始化动态001场景演示数据模拟送外卖场景
async initDynamics001(data = {}) {
let res = { errCode: 0 };
const category = "dynamics-001";
// 先删除
await opendbPoiDB.where({
category: category
}).remove();
// 后添加随机数据
// 以天安门为中心
let tiananmen = {
longitude: 116.39747,
latitude: 39.908823,
};
let time = Date.now();
// 随机生成配送员坐标
let randomCoordinate1 = getRandomCoordinateWithinRadius(tiananmen.longitude, tiananmen.latitude, 2); // 随机生成在天安门方圆X KM内的坐标
let data1 = {
category: category, // 场景值用于区分这些POI所属哪张地图
type: "配送员",
title: "配送员",
location: new db.Geo.Point(randomCoordinate1.longitude, randomCoordinate1.latitude),
create_date: time,
visible: true,
is_random: true, // 表示此为随机生成的点,方便删除
}
// 随机生成目的地坐标
let randomCoordinate2 = getRandomCoordinateWithinRadius(tiananmen.longitude, tiananmen.latitude, 2); // 随机生成在天安门方圆X KM内的坐标
let data2 = {
category: category, // 场景值用于区分这些POI所属哪张地图
type: "目的地",
title: "配送目的地",
location: new db.Geo.Point(randomCoordinate2.longitude, randomCoordinate2.latitude),
create_date: time,
visible: true,
is_random: true, // 表示此为随机生成的点,方便删除
}
let list = [data1, data2];
// 添加到数据库
await opendbPoiDB.add(list);
// 获取配送路线
// 获取uniMap实例
const uniMap = this.uniMap;
// 调用电瓶车路径规划API
let result = await uniMap.route({
mode: "ebicycling",
from: `${randomCoordinate1.latitude},${randomCoordinate1.longitude}`,
to: `${randomCoordinate2.latitude},${randomCoordinate2.longitude}`,
alternative_route: 1
});
let route = result.result.routes[0];
let { steps = [] } = route;
let points = [];
steps.map((step) => {
let {
polyline = ""
} = step;
let arr = polyline.split(";");
arr.map((item) => {
let arr2 = item.split(",");
points.push({
latitude: arr2[0],
longitude: arr2[1],
});
});
});
let polyline = {
points,
color: "#19b411",
width: 6,
dottedLine: false,
arrowLine: true,
borderWidth: 1,
borderColor: "#000000",
};
res.polyline = [polyline];
return res;
},
// 演示用 - 获取配送员配送路径
async getPolyline(data = {}) {
let res = { errCode: 0 };
const category = "dynamics-001";
let getRes1 = await opendbPoiDB.where({
category: category,
type: "配送员",
visible: true
}).get();
let poi1 = getRes1.data[0];
let getRes2 = await opendbPoiDB.where({
category: category,
type: "目的地",
visible: true
}).get();
let poi2 = getRes2.data[0];
if (!poi2) {
return {
errCode: 0,
end: true
}
}
let coordinate1 = {
longitude: poi1.location.coordinates[0],
latitude: poi1.location.coordinates[1]
};
let coordinate2 = {
longitude: poi2.location.coordinates[0],
latitude: poi2.location.coordinates[1]
};
// 获取uniMap实例
const uniMap = this.uniMap;
// 调用电瓶车路径规划API
let result = await uniMap.route({
mode: "ebicycling",
from: `${coordinate1.latitude},${coordinate1.longitude}`,
to: `${coordinate2.latitude},${coordinate2.longitude}`,
alternative_route: 1
});
let route = result.result.routes[0];
//console.log('route: ', route)
let { steps = [], distance, duration } = route;
let points = [];
let dir_desc;
steps.map((step) => {
let {
polyline = ""
} = step;
if (!dir_desc) dir_desc = step.dir_desc;
if (polyline) {
let arr = polyline.split(";");
arr.map((item) => {
let arr2 = item.split(",");
if (!isNaN(arr2[0]) && !isNaN(arr2[1])) {
points.push({
latitude: Number(arr2[0]),
longitude: Number(arr2[1]),
});
}
});
}
});
let polyline = {
points,
color: "#19b411",
width: 6,
dottedLine: false,
arrowLine: true,
borderWidth: 1,
borderColor: "#000000",
};
res.polyline = [polyline];
if (distance <= 30 || duration <= 0) {
await opendbPoiDB.doc(poi1._id).update({
title: `配送员已到达目的地`,
location: new db.Geo.Point(Number(coordinate2.longitude), Number(coordinate2.latitude)),
rotate: 0
});
// 隐藏目的地
await opendbPoiDB.doc(poi2._id).update({
visible: false,
});
return {
errCode: 0,
end: true
}
} else {
// 从最近2个点计算出当前行驶方向
let rotate = 0;
if (points && points.length >= 2) {
rotate = calculateDirectionAngle(points[0], points[1]);
}
await opendbPoiDB.doc(poi1._id).update({
title: `配送员正在配送\r\n还有 ${distance}\r\n预计 ${duration} 分钟送达`,
rotate: rotate, // 设置角度0°的图片方向应朝左(西) 故90° 朝上(北) 180° 朝右(东) 270° 朝下(南)
});
}
return res;
},
// 演示用 - 模拟上报配送员坐标
async updateMyLocation(data = {}) {
let res = {};
const category = "dynamics-001";
let {
longitude,
latitude
} = data;
let getRes1 = await opendbPoiDB.where({
category: category,
type: "配送员",
visible: true
}).get();
let poi1 = getRes1.data[0];
await opendbPoiDB.doc(poi1._id).update({
location: new db.Geo.Point(Number(longitude), Number(latitude))
});
return res;
},
// 演示用 - xxxx
async test(data = {}) {
let res = {};
// 获取uniMap实例
const uniMap = this.uniMap;
// 调用API
let result = await uniMap.location2address({
});
res.result = result;
return res;
}
}
/**
* 生成在指定经纬度圆内的随机坐标
const latitude = 39.908823; // 指定纬度
const longitude = 116.39747; // 指定经度
const radiusInKm = 10; // 指定圆的半径(单位:千米)
const randomCoordinate = getRandomCoordinateWithinRadius(latitude, longitude, radiusInKm);
console.log(randomCoordinate);
*/
function getRandomCoordinateWithinRadius(longitude, latitude, radiusInKm) {
// 地球半径(单位:千米)
const earthRadius = 6371;
// 将圆的半径转换为弧度
const radiusInRad = radiusInKm / earthRadius;
// 生成随机的方位角弧度0到2π
const randomAngleRad = Math.random() * 2 * Math.PI;
// 生成随机的距离弧度0到圆的半径
const randomDistanceRad = Math.acos(Math.random() * (Math.cos(radiusInRad) - 1) + 1);
// 使用球面三角学计算随机点的纬度和经度
const randomLatitudeRad = latitude * (Math.PI / 180) + randomDistanceRad * Math.cos(randomAngleRad);
const randomLongitudeRad = longitude * (Math.PI / 180) + randomDistanceRad * Math.sin(randomAngleRad) / Math.cos(latitude * (Math.PI / 180));
// 转换为度并保留6位小数
const randomLatitude = parseFloat((randomLatitudeRad * (180 / Math.PI)).toFixed(6));
const randomLongitude = parseFloat((randomLongitudeRad * (180 / Math.PI)).toFixed(6));
return { latitude: randomLatitude, longitude: randomLongitude };
}
/**
* 计算坐标B在坐标A的方向0代表正西方 90 代表正北方
const latitude = 39.908823; // 指定纬度
const longitude = 116.39747; // 指定经度
const radiusInKm = 10; // 指定圆的半径(单位:千米)
const randomCoordinate = getRandomCoordinateWithinRadius(latitude, longitude, radiusInKm);
console.log(randomCoordinate);
*/
function calculateDirectionAngle(coordA, coordB) {
const toRadians = (angle) => angle * (Math.PI / 180);
const toDegrees = (angle) => angle * (180 / Math.PI);
const lat1 = toRadians(coordA.latitude);
const lon1 = toRadians(coordA.longitude);
const lat2 = toRadians(coordB.latitude);
const lon2 = toRadians(coordB.longitude);
const dLon = lon2 - lon1;
const y = Math.sin(dLon) * Math.cos(lat2);
const x =
Math.cos(lat1) * Math.sin(lat2) -
Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon);
const angleRadians = Math.atan2(y, x);
let angleDegrees = toDegrees(angleRadians);
angleDegrees = (angleDegrees + 360) % 360;
angleDegrees = (angleDegrees > 180) ? angleDegrees - 180 : angleDegrees + 180;
angleDegrees -= 90; // 以正西方为0°表示因此需要-90
return angleDegrees;
}