index.obj.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. // 引入uni-map-common公共模块
  2. const UniMap = require('uni-map-common');
  3. const configCenter = require("uni-config-center");
  4. // 读取配置中心地图配置
  5. var UniMapConfig = configCenter({ pluginId: 'uni-map' }).requireFile('config.js');
  6. // 本地地图配置
  7. var LocalMapConfig = {
  8. "default": "", // 默认使用的平台
  9. "key": {
  10. "qqmap": "", // 腾讯地图key
  11. "amap": "", // 高德地图key
  12. }
  13. }
  14. const db = uniCloud.database();
  15. const _ = db.command;
  16. const $ = _.aggregate;
  17. const opendbPoiDB = db.collection("opendb-poi");
  18. module.exports = {
  19. _before: function() {
  20. // 如果配置中心不存在地图配置,则使用本地地图配置
  21. if (!UniMapConfig) {
  22. UniMapConfig = LocalMapConfig;
  23. }
  24. let defaultProvider = UniMapConfig.default || "qqmap";
  25. let params = this.getParams();
  26. let {
  27. provider = defaultProvider,
  28. needOriginalResult = false
  29. } = params[0] || {};
  30. console.log('provider: ', provider)
  31. const key = UniMapConfig.key[provider] || LocalMapConfig.key[provider];
  32. if (!key) {
  33. throw { errCode: -1, errMsg: `请在uni-config-center/uni-map/config.js中或LocalMapConfig中配置地图供应商${provider}对应的key` };
  34. }
  35. // 初始化实例
  36. let uniMap = new UniMap({
  37. provider: provider, // 指定使用哪家地图供应商
  38. key: key,
  39. needOriginalResult
  40. });
  41. this.uniMap = uniMap;
  42. },
  43. _after: function(error, res) {
  44. if (error) {
  45. throw error; // 如果方法抛出错误,也直接抛出不处理
  46. }
  47. console.log("result", res.result);
  48. return res;
  49. },
  50. // 函数chooseLocation是给uni.chooseLocation使用,请勿修改chooseLocation函数的代码
  51. async chooseLocation(parame = {}) {
  52. let res = {};
  53. let {
  54. action,
  55. data
  56. } = parame;
  57. // 初始化实例
  58. // 获取uniMap实例
  59. const uniMap = this.uniMap;
  60. // 调用API
  61. let result = await uniMap[action](data);
  62. res.result = result.originalResult;
  63. return res;
  64. },
  65. // 经纬度坐标转地址
  66. async location2address(data = {}) {
  67. let res = {};
  68. // 获取uniMap实例
  69. const uniMap = this.uniMap;
  70. // 调用API
  71. let result = await uniMap.location2address(data);
  72. res.result = result;
  73. return res;
  74. },
  75. // 地址转经纬度坐标
  76. async address2location(data = {}) {
  77. let res = {};
  78. // 获取uniMap实例
  79. const uniMap = this.uniMap;
  80. // 调用API
  81. let result = await uniMap.address2location(data);
  82. res.result = result;
  83. return res;
  84. },
  85. // 坐标系转换
  86. async translate(data = {}) {
  87. let res = {};
  88. // 获取uniMap实例
  89. const uniMap = this.uniMap;
  90. // 调用API
  91. let result = await uniMap.translate(data);
  92. res.result = result;
  93. return res;
  94. },
  95. // ip定位
  96. async ip2location(data = {}) {
  97. let res = {};
  98. // 获取uniMap实例
  99. const uniMap = this.uniMap;
  100. // 调用API
  101. let result = await uniMap.ip2location(data);
  102. res.result = result;
  103. return res;
  104. },
  105. // 输入提示
  106. async inputtips(data = {}) {
  107. let res = {};
  108. // 获取uniMap实例
  109. const uniMap = this.uniMap;
  110. // 调用API
  111. let result = await uniMap.inputtips(data);
  112. res.result = result;
  113. return res;
  114. },
  115. // 搜索
  116. async search(data = {}) {
  117. let res = {};
  118. // 获取uniMap实例
  119. const uniMap = this.uniMap;
  120. // 调用API
  121. let result = await uniMap.search(data);
  122. res.result = result;
  123. return res;
  124. },
  125. // 行政区划
  126. async districtSearch(data = {}) {
  127. let res = {};
  128. // 获取uniMap实例
  129. const uniMap = this.uniMap;
  130. // 调用API
  131. let result = await uniMap.districtSearch(data);
  132. res.result = result;
  133. return res;
  134. },
  135. // 路径规划
  136. async route(data = {}) {
  137. let res = {};
  138. // 获取uniMap实例
  139. const uniMap = this.uniMap;
  140. // 调用API
  141. let result = await uniMap.route(data);
  142. res.result = result;
  143. return res;
  144. },
  145. // 演示用 - 清空所有的测试POI
  146. async clearPoi(data = {}) {
  147. let res = { errCode: 0 };
  148. const db = uniCloud.database();
  149. await db.collection("opendb-poi").where({
  150. is_random: true
  151. }).remove();
  152. return res;
  153. },
  154. // 演示用 - 初始化静态001场景演示数据
  155. async initStatic001(data = {}) {
  156. let res = { errCode: 0 };
  157. const category = "static-001";
  158. // 先删除
  159. await opendbPoiDB.where({
  160. category: category
  161. }).remove();
  162. // 后添加随机数据
  163. // 以天安门为中心
  164. let tiananmen = {
  165. longitude: 116.39747,
  166. latitude: 39.908823,
  167. };
  168. let time = Date.now();
  169. // 随机生成6个门店地址
  170. let list = [];
  171. for (let i = 1; i <= 6; i++) {
  172. let randomCoordinate = getRandomCoordinateWithinRadius(tiananmen.longitude, tiananmen.latitude, 10); // 随机生成在天安门方圆X KM内的坐标
  173. list.push({
  174. category: category, // 场景值,用于区分这些POI所属哪张地图
  175. type: "门店",
  176. title: `随机门店-${i}`,
  177. location: new db.Geo.Point(randomCoordinate.longitude, randomCoordinate.latitude),
  178. create_date: time,
  179. visible: true,
  180. is_random: true, // 表示此为随机生成的点,方便删除
  181. level: i
  182. });
  183. }
  184. // 随机生成1个总部地址
  185. let randomCoordinate = getRandomCoordinateWithinRadius(tiananmen.longitude, tiananmen.latitude, 1); // 随机生成在天安门方圆X KM内的坐标
  186. list.push({
  187. category: category, // 场景值,用于区分这些POI所属哪张地图
  188. type: "总部",
  189. title: `随机总部`,
  190. location: new db.Geo.Point(randomCoordinate.longitude, randomCoordinate.latitude),
  191. create_date: time,
  192. visible: true,
  193. is_random: true, // 表示此为随机生成的点,方便删除
  194. level: 7
  195. });
  196. // 添加到数据库
  197. await opendbPoiDB.add(list);
  198. return res;
  199. },
  200. // 演示用 - 初始化动态001场景演示数据(模拟送外卖场景)
  201. async initDynamics001(data = {}) {
  202. let res = { errCode: 0 };
  203. const category = "dynamics-001";
  204. // 先删除
  205. await opendbPoiDB.where({
  206. category: category
  207. }).remove();
  208. // 后添加随机数据
  209. // 以天安门为中心
  210. let tiananmen = {
  211. longitude: 116.39747,
  212. latitude: 39.908823,
  213. };
  214. let time = Date.now();
  215. // 随机生成配送员坐标
  216. let randomCoordinate1 = getRandomCoordinateWithinRadius(tiananmen.longitude, tiananmen.latitude, 2); // 随机生成在天安门方圆X KM内的坐标
  217. let data1 = {
  218. category: category, // 场景值,用于区分这些POI所属哪张地图
  219. type: "配送员",
  220. title: "配送员",
  221. location: new db.Geo.Point(randomCoordinate1.longitude, randomCoordinate1.latitude),
  222. create_date: time,
  223. visible: true,
  224. is_random: true, // 表示此为随机生成的点,方便删除
  225. }
  226. // 随机生成目的地坐标
  227. let randomCoordinate2 = getRandomCoordinateWithinRadius(tiananmen.longitude, tiananmen.latitude, 2); // 随机生成在天安门方圆X KM内的坐标
  228. let data2 = {
  229. category: category, // 场景值,用于区分这些POI所属哪张地图
  230. type: "目的地",
  231. title: "配送目的地",
  232. location: new db.Geo.Point(randomCoordinate2.longitude, randomCoordinate2.latitude),
  233. create_date: time,
  234. visible: true,
  235. is_random: true, // 表示此为随机生成的点,方便删除
  236. }
  237. let list = [data1, data2];
  238. // 添加到数据库
  239. await opendbPoiDB.add(list);
  240. // 获取配送路线
  241. // 获取uniMap实例
  242. const uniMap = this.uniMap;
  243. // 调用电瓶车路径规划API
  244. let result = await uniMap.route({
  245. mode: "ebicycling",
  246. from: `${randomCoordinate1.latitude},${randomCoordinate1.longitude}`,
  247. to: `${randomCoordinate2.latitude},${randomCoordinate2.longitude}`,
  248. alternative_route: 1
  249. });
  250. let route = result.result.routes[0];
  251. let { steps = [] } = route;
  252. let points = [];
  253. steps.map((step) => {
  254. let {
  255. polyline = ""
  256. } = step;
  257. let arr = polyline.split(";");
  258. arr.map((item) => {
  259. let arr2 = item.split(",");
  260. points.push({
  261. latitude: arr2[0],
  262. longitude: arr2[1],
  263. });
  264. });
  265. });
  266. let polyline = {
  267. points,
  268. color: "#19b411",
  269. width: 6,
  270. dottedLine: false,
  271. arrowLine: true,
  272. borderWidth: 1,
  273. borderColor: "#000000",
  274. };
  275. res.polyline = [polyline];
  276. return res;
  277. },
  278. // 演示用 - 获取配送员配送路径
  279. async getPolyline(data = {}) {
  280. let res = { errCode: 0 };
  281. const category = "dynamics-001";
  282. let getRes1 = await opendbPoiDB.where({
  283. category: category,
  284. type: "配送员",
  285. visible: true
  286. }).get();
  287. let poi1 = getRes1.data[0];
  288. let getRes2 = await opendbPoiDB.where({
  289. category: category,
  290. type: "目的地",
  291. visible: true
  292. }).get();
  293. let poi2 = getRes2.data[0];
  294. if (!poi2) {
  295. return {
  296. errCode: 0,
  297. end: true
  298. }
  299. }
  300. let coordinate1 = {
  301. longitude: poi1.location.coordinates[0],
  302. latitude: poi1.location.coordinates[1]
  303. };
  304. let coordinate2 = {
  305. longitude: poi2.location.coordinates[0],
  306. latitude: poi2.location.coordinates[1]
  307. };
  308. // 获取uniMap实例
  309. const uniMap = this.uniMap;
  310. // 调用电瓶车路径规划API
  311. let result = await uniMap.route({
  312. mode: "ebicycling",
  313. from: `${coordinate1.latitude},${coordinate1.longitude}`,
  314. to: `${coordinate2.latitude},${coordinate2.longitude}`,
  315. alternative_route: 1
  316. });
  317. let route = result.result.routes[0];
  318. //console.log('route: ', route)
  319. let { steps = [], distance, duration } = route;
  320. let points = [];
  321. let dir_desc;
  322. steps.map((step) => {
  323. let {
  324. polyline = ""
  325. } = step;
  326. if (!dir_desc) dir_desc = step.dir_desc;
  327. if (polyline) {
  328. let arr = polyline.split(";");
  329. arr.map((item) => {
  330. let arr2 = item.split(",");
  331. if (!isNaN(arr2[0]) && !isNaN(arr2[1])) {
  332. points.push({
  333. latitude: Number(arr2[0]),
  334. longitude: Number(arr2[1]),
  335. });
  336. }
  337. });
  338. }
  339. });
  340. let polyline = {
  341. points,
  342. color: "#19b411",
  343. width: 6,
  344. dottedLine: false,
  345. arrowLine: true,
  346. borderWidth: 1,
  347. borderColor: "#000000",
  348. };
  349. res.polyline = [polyline];
  350. if (distance <= 30 || duration <= 0) {
  351. await opendbPoiDB.doc(poi1._id).update({
  352. title: `配送员已到达目的地`,
  353. location: new db.Geo.Point(Number(coordinate2.longitude), Number(coordinate2.latitude)),
  354. rotate: 0
  355. });
  356. // 隐藏目的地
  357. await opendbPoiDB.doc(poi2._id).update({
  358. visible: false,
  359. });
  360. return {
  361. errCode: 0,
  362. end: true
  363. }
  364. } else {
  365. // 从最近2个点计算出当前行驶方向
  366. let rotate = 0;
  367. if (points && points.length >= 2) {
  368. rotate = calculateDirectionAngle(points[0], points[1]);
  369. }
  370. await opendbPoiDB.doc(poi1._id).update({
  371. title: `配送员正在配送\r\n还有 ${distance} 米\r\n预计 ${duration} 分钟送达`,
  372. rotate: rotate, // 设置角度,0°的图片方向应朝左(西) 故90° 朝上(北) 180° 朝右(东) 270° 朝下(南)
  373. });
  374. }
  375. return res;
  376. },
  377. // 演示用 - 模拟上报配送员坐标
  378. async updateMyLocation(data = {}) {
  379. let res = {};
  380. const category = "dynamics-001";
  381. let {
  382. longitude,
  383. latitude
  384. } = data;
  385. let getRes1 = await opendbPoiDB.where({
  386. category: category,
  387. type: "配送员",
  388. visible: true
  389. }).get();
  390. let poi1 = getRes1.data[0];
  391. await opendbPoiDB.doc(poi1._id).update({
  392. location: new db.Geo.Point(Number(longitude), Number(latitude))
  393. });
  394. return res;
  395. },
  396. // 演示用 - xxxx
  397. async test(data = {}) {
  398. let res = {};
  399. // 获取uniMap实例
  400. const uniMap = this.uniMap;
  401. // 调用API
  402. let result = await uniMap.location2address({
  403. });
  404. res.result = result;
  405. return res;
  406. }
  407. }
  408. /**
  409. * 生成在指定经纬度圆内的随机坐标
  410. const latitude = 39.908823; // 指定纬度
  411. const longitude = 116.39747; // 指定经度
  412. const radiusInKm = 10; // 指定圆的半径(单位:千米)
  413. const randomCoordinate = getRandomCoordinateWithinRadius(latitude, longitude, radiusInKm);
  414. console.log(randomCoordinate);
  415. */
  416. function getRandomCoordinateWithinRadius(longitude, latitude, radiusInKm) {
  417. // 地球半径(单位:千米)
  418. const earthRadius = 6371;
  419. // 将圆的半径转换为弧度
  420. const radiusInRad = radiusInKm / earthRadius;
  421. // 生成随机的方位角(弧度,0到2π)
  422. const randomAngleRad = Math.random() * 2 * Math.PI;
  423. // 生成随机的距离(弧度,0到圆的半径)
  424. const randomDistanceRad = Math.acos(Math.random() * (Math.cos(radiusInRad) - 1) + 1);
  425. // 使用球面三角学计算随机点的纬度和经度
  426. const randomLatitudeRad = latitude * (Math.PI / 180) + randomDistanceRad * Math.cos(randomAngleRad);
  427. const randomLongitudeRad = longitude * (Math.PI / 180) + randomDistanceRad * Math.sin(randomAngleRad) / Math.cos(latitude * (Math.PI / 180));
  428. // 转换为度,并保留6位小数
  429. const randomLatitude = parseFloat((randomLatitudeRad * (180 / Math.PI)).toFixed(6));
  430. const randomLongitude = parseFloat((randomLongitudeRad * (180 / Math.PI)).toFixed(6));
  431. return { latitude: randomLatitude, longitude: randomLongitude };
  432. }
  433. /**
  434. * 计算坐标B在坐标A的方向,0代表正西方 90 代表正北方
  435. const latitude = 39.908823; // 指定纬度
  436. const longitude = 116.39747; // 指定经度
  437. const radiusInKm = 10; // 指定圆的半径(单位:千米)
  438. const randomCoordinate = getRandomCoordinateWithinRadius(latitude, longitude, radiusInKm);
  439. console.log(randomCoordinate);
  440. */
  441. function calculateDirectionAngle(coordA, coordB) {
  442. const toRadians = (angle) => angle * (Math.PI / 180);
  443. const toDegrees = (angle) => angle * (180 / Math.PI);
  444. const lat1 = toRadians(coordA.latitude);
  445. const lon1 = toRadians(coordA.longitude);
  446. const lat2 = toRadians(coordB.latitude);
  447. const lon2 = toRadians(coordB.longitude);
  448. const dLon = lon2 - lon1;
  449. const y = Math.sin(dLon) * Math.cos(lat2);
  450. const x =
  451. Math.cos(lat1) * Math.sin(lat2) -
  452. Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon);
  453. const angleRadians = Math.atan2(y, x);
  454. let angleDegrees = toDegrees(angleRadians);
  455. angleDegrees = (angleDegrees + 360) % 360;
  456. angleDegrees = (angleDegrees > 180) ? angleDegrees - 180 : angleDegrees + 180;
  457. angleDegrees -= 90; // 以正西方为0°表示,因此需要-90
  458. return angleDegrees;
  459. }