From f69744df237584f2a61cfcb05883c221a4c648dd Mon Sep 17 00:00:00 2001 From: zhenyuWang <13641039885@163.com> Date: Thu, 14 Nov 2024 22:28:44 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20chooseLocation=20=E7=A4=BA=E4=BE=8B?= =?UTF-8?q?=E6=94=AF=E6=8C=81=20app=20=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../API/choose-location/choose-location.uvue | 165 +-- uni_modules/uni-map-common/changelog.md | 14 + uni_modules/uni-map-common/package.json | 83 ++ uni_modules/uni-map-common/readme.md | 11 + .../common/uni-map-common/index.js | 100 ++ .../common/uni-map-common/libs/common.js | 74 ++ .../common/uni-map-common/libs/error.js | 13 + .../common/uni-map-common/libs/index.js | 7 + .../common/uni-map-common/package.json | 19 + .../common/uni-map-common/service/amap.js | 979 ++++++++++++++++++ .../common/uni-map-common/service/index.js | 4 + .../common/uni-map-common/service/qqmap.js | 856 +++++++++++++++ .../cloudfunctions/uni-map-co/index.obj.js | 518 +++++++++ .../cloudfunctions/uni-map-co/package.json | 9 + .../uni-map-co/uni-map-co.param.js | 123 +++ 15 files changed, 2897 insertions(+), 78 deletions(-) create mode 100644 uni_modules/uni-map-common/changelog.md create mode 100644 uni_modules/uni-map-common/package.json create mode 100644 uni_modules/uni-map-common/readme.md create mode 100644 uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/index.js create mode 100644 uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/libs/common.js create mode 100644 uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/libs/error.js create mode 100644 uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/libs/index.js create mode 100644 uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/package.json create mode 100644 uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/service/amap.js create mode 100644 uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/service/index.js create mode 100644 uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/service/qqmap.js create mode 100644 uni_modules/uni-map-common/uniCloud/cloudfunctions/uni-map-co/index.obj.js create mode 100644 uni_modules/uni-map-common/uniCloud/cloudfunctions/uni-map-co/package.json create mode 100644 uni_modules/uni-map-common/uniCloud/cloudfunctions/uni-map-co/uni-map-co.param.js diff --git a/pages/API/choose-location/choose-location.uvue b/pages/API/choose-location/choose-location.uvue index 364edb05..6d8e3020 100644 --- a/pages/API/choose-location/choose-location.uvue +++ b/pages/API/choose-location/choose-location.uvue @@ -1,79 +1,88 @@ - - - - diff --git a/uni_modules/uni-map-common/changelog.md b/uni_modules/uni-map-common/changelog.md new file mode 100644 index 00000000..21749635 --- /dev/null +++ b/uni_modules/uni-map-common/changelog.md @@ -0,0 +1,14 @@ +## 1.1.3(2024-11-11) +优化 chooseLocation 函数供 uni-app x 的 uni.chooseLocation 使用 +## 1.1.2(2024-10-21) +新增chooseLocation函数供uni.chooseLocation使用 +## 1.1.1(2024-07-23) +[调整] 移除db_init.json文件,初始化数据库请用新版方式(右键database,初始化数据库) +## 1.1.0(2024-03-25) +[重要] 支持支付宝小程序云 +## 1.0.2(2023-08-01) +优化配置读取方式 +## 1.0.1(2023-08-01) +初版 +## 1.0.0(2023-08-01) +初版,文档地址:https://uniapp.dcloud.net.cn/uniCloud/uni-map-common.html diff --git a/uni_modules/uni-map-common/package.json b/uni_modules/uni-map-common/package.json new file mode 100644 index 00000000..daf00bb1 --- /dev/null +++ b/uni_modules/uni-map-common/package.json @@ -0,0 +1,83 @@ +{ + "id": "uni-map-common", + "displayName": "uni-map-common地图服务端API", + "version": "1.1.3", + "description": "聚合了多家地图供应商的服务端API,几行代码即可快速接入地图API", + "keywords": [ + "uni-map-common", + "地图服务端API" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "type": "unicloud-template-function", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "插件不采集任何数据", + "permissions": "无" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "y" + }, + "client": { + "Vue": { + "vue2": "u", + "vue3": "u" + }, + "App": { + "app-vue": "u", + "app-nvue": "u" + }, + "H5-mobile": { + "Safari": "u", + "Android Browser": "u", + "微信浏览器(Android)": "u", + "QQ浏览器(Android)": "u" + }, + "H5-pc": { + "Chrome": "u", + "IE": "u", + "Edge": "u", + "Firefox": "u", + "Safari": "u" + }, + "小程序": { + "微信": "u", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u", + "钉钉": "u", + "快手": "u", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-map-common/readme.md b/uni_modules/uni-map-common/readme.md new file mode 100644 index 00000000..21580ccb --- /dev/null +++ b/uni_modules/uni-map-common/readme.md @@ -0,0 +1,11 @@ +# uni-map-common + +聚合了多家地图供应商的服务端API + +## 使用教程 + +> 文档地址:[https://uniapp.dcloud.net.cn/uniCloud/uni-map-common.html](https://uniapp.dcloud.net.cn/uniCloud/uni-map-common.html) + +## bug反馈地址 + +> 加群:[uni-map交流群](https://im.dcloud.net.cn/#/?joinGroup=64d62b106823de10406ad72f) diff --git a/uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/index.js b/uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/index.js new file mode 100644 index 00000000..82253e4e --- /dev/null +++ b/uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/index.js @@ -0,0 +1,100 @@ +const service = require('./service/index.js'); + +class UniMap { + + // 构造函数 + constructor(data = {}) { + let { + provider, // 平台 weixin-mp 微信小程序 weixin-h5 微信公众号 + key, // 密钥 + needOriginalResult = false, // 是否需要返回原始信息,默认false + } = data; + + let runService = service[provider]; + if (!runService) { + throw new Error(`不支持平台:${provider}`); + } + this.service = new runService({ + provider, + key, + needOriginalResult + }); + //return this.service; + } + + // API - 逆地址解析(坐标转地址) + async location2address(data = {}) { + let res = await this._call("location2address", data); + return res; + } + + // API - 地址解析(地址转坐标) + async address2location(data = {}) { + let res = await this._call("address2location", data); + return res; + } + + // API - 坐标转换 + async translate(data = {}) { + let res = await this._call("translate", data); + return res; + } + + // API - IP定位 + async ip2location(data = {}) { + let res = await this._call("ip2location", data); + return res; + } + + // API - 关键词输入提示 + async inputtips(data = {}) { + let res = await this._call("inputtips", data); + return res; + } + + // API - 周边搜索 + async search(data = {}) { + let res = await this._call("search", data); + return res; + } + + // API - 行政区划 + async districtSearch(data = {}) { + let res = await this._call("districtSearch", data); + return res; + } + + // API - 路线规划(驾车/步行/骑行/电动车/公交) + async route(data = {}) { + let urlObj = { + "driving": "drivingRoute", + "walking": "walkingRoute", + "bicycling": "bicyclingRoute", + "ebicycling": "ebicyclingRoute", + "transit": "transitRoute" + }; + let res = await this._call(urlObj[data.mode], data); + res.result.mode = data.mode; + return res; + } + + // 私有函数 + async _call(name, data = {}) { + let runFunction = this.service[name]; + if (!runFunction) { + throw new Error(`平台:${this.service.config.provider} 不支持API:${name}`); + } + let res = await runFunction.call(this.service, data); // 此处需要使用call,防止里面的this作用域被意外改变 + if (!this.service.config.needOriginalResult) { + delete res.originalResult; + } + //res = JSON.parse(JSON.stringify(res)); + return { + provider: this.service.config.provider, + ...res + }; + } + +} + +module.exports = UniMap; \ No newline at end of file diff --git a/uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/libs/common.js b/uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/libs/common.js new file mode 100644 index 00000000..d15e145c --- /dev/null +++ b/uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/libs/common.js @@ -0,0 +1,74 @@ +/** + * 通用公共函数 + */ +var common = {}; + +// 经纬度表示形式转换 +common.getLocation = function(location = "", type = "", returnType = "") { + let lat; + let lng; + // 去除所有空格 + type = type.trim(); + returnType = returnType.replace(/\s+/g, ''); + if (type === "lat,lng") { + location = location.replace(/\s+/g, ''); + let arr = location.split(","); + lat = arr[0]; + lng = arr[1]; + } else if (type === "lng,lat") { + location = location.replace(/\s+/g, ''); + let arr = location.split(","); + lat = arr[1]; + lng = arr[0]; + } else if (type === "lat lng") { + let arr = location.split(" "); + lat = arr[0]; + lng = arr[1]; + } else if (type === "lng lat") { + let arr = location.split(" "); + lat = arr[1]; + lng = arr[0]; + } else { + lat = location.lat; + lng = location.lng; + } + if (returnType == "lng,lat") { + return `${lng},${lat}`; + } else if (returnType == "lat,lng") { + return `${lat},${lng}`; + } else { + return { + lat: Number(lat), + lng: Number(lng) + } + } +}; + +// 字符串格式的坐标经纬度反转 +common.getReversalLocation = function(input="") { + // 按分隔符拆分字符串 + let parts = input.split("|"); + + // 遍历每个部分进行值交换 + for (let i = 0; i < parts.length; i++) { + let pairs = parts[i].split(";"); + for (let j = 0; j < pairs.length; j++) { + let values = pairs[j].split(","); + // 交换两个值 + let temp = values[0]; + values[0] = values[1]; + values[1] = temp; + // 更新交换后的值 + pairs[j] = values.join(","); + } + // 更新交换后的部分 + parts[i] = pairs.join(";"); + } + + // 返回交换后的结果 + return parts.join("|"); +}; + + + +module.exports = common; \ No newline at end of file diff --git a/uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/libs/error.js b/uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/libs/error.js new file mode 100644 index 00000000..4cdda804 --- /dev/null +++ b/uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/libs/error.js @@ -0,0 +1,13 @@ +const errSubject = "uni-map-common"; + +class UniCloudError { + constructor(options = {}) { + this.errCode = options.errCode || options.code; + this.errMsg = options.errMsg || options.msg || options.message || ""; + this.errSubject = options.subject || errSubject; + } +} + +module.exports = { + UniCloudError +} \ No newline at end of file diff --git a/uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/libs/index.js b/uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/libs/index.js new file mode 100644 index 00000000..dbaf95f9 --- /dev/null +++ b/uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/libs/index.js @@ -0,0 +1,7 @@ +const common = require('./common'); +const error = require('./error'); + +module.exports = { + common, + error +}; \ No newline at end of file diff --git a/uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/package.json b/uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/package.json new file mode 100644 index 00000000..dfbb59e8 --- /dev/null +++ b/uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/package.json @@ -0,0 +1,19 @@ +{ + "name": "uni-map-common", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "uni-config-center": "file:..\/..\/..\/..\/..\/uni-config-center\/uniCloud\/cloudfunctions\/common\/uni-config-center" + }, + "origin-plugin-dev-name": "uni-map-common", + "origin-plugin-version": "1.1.3", + "plugin-dev-name": "uni-map-common", + "plugin-version": "1.1.3" +} \ No newline at end of file diff --git a/uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/service/amap.js b/uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/service/amap.js new file mode 100644 index 00000000..18a66c54 --- /dev/null +++ b/uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/service/amap.js @@ -0,0 +1,979 @@ +const libs = require('../libs'); + +// https://lbs.amap.com/api/webservice/guide/tools/info + +const ERRCODE = { + "10000": 0, + "10001": 190, + "10002": 113, + "10003": 121, + "10004": 120, + "10005": 112, + "10006": 110, + "10007": 111, + "10008": 111, + "10009": 110, + "10010": 122, + "10011": 311, + "10012": 113, + "10013": 190, + "10014": 500, + "10015": 500, + "10016": 500, + "10017": 500, + "10019": 500, + "10020": 500, + "10021": 500, + "10026": 110, + "10029": 500, + "10041": 110, + "10044": 121, + "10045": 121, + "20000": 395, + "20001": 300, + "20002": 500, + "20003": 500, + "20011": 395, + "20012": 395, + "20801": 395, + "20802": 395, + "20803": 373, + "40000": 123, + "40001": 123, + "40002": 123, + "40003": 123 +}; + +class Service { + + // 构造函数 + constructor(data = {}) { + let { + key, + needOriginalResult = false, // 是否需要返回原始信息,默认false + } = data; + + this.config = { + provider: "amap", + key, + needOriginalResult, + serviceUrl: "https://restapi.amap.com" + } + } + + async request(obj = {}) { + let { + url, + data = {} + } = obj; + if (url.indexOf("http") !== 0) { + url = `${this.config.serviceUrl}/${url}` + } + if (this.config.key && !data.key) { + data.key = this.config.key; + } + obj.data = JSON.parse(JSON.stringify(obj.data)); + let requestRes = await uniCloud.httpclient.request(url, obj); + let result = this.getResult(requestRes); + if (result.errCode != 0) { + throw new libs.error.UniCloudError(result); + } + return result; + } + + getResult(requestRes) { + let { + data: originalResult = {} + } = requestRes; + let res = { + errCode: originalResult.infocode == "10000" ? 0 : this.getErrCode(originalResult.infocode), + errMsg: originalResult.info, + originalResult, + }; + return res; + } + + getErrCode(errCode) { + return ERRCODE[errCode] || errCode; + } + + // API - 逆地址解析(坐标转地址) + async location2address(data = {}) { + let { + location, + get_poi, + poi_options, + } = data; + + let requestData = { + location: libs.common.getLocation(location, "lat,lng", "lng,lat"), + extensions: get_poi ? "all" : "base", + }; + + if (get_poi && typeof poi_options == "object") { + let { + poitype, + radius, + roadlevel, + homeorcorp + } = poi_options; + requestData = Object.assign(requestData, { + poitype, + radius, + roadlevel, + homeorcorp + }) + } + + let requestRes = await this.request({ + method: "GET", + url: "v3/geocode/regeo", + dataType: "json", + data: requestData + }); + + let originalResult = requestRes.originalResult.regeocode; + let pois; + if (originalResult.pois) { + pois = originalResult.pois.map((item) => { + return { + id: item.id, + title: item.name, + address: item.address, + location: libs.common.getLocation(item.location, "lng,lat", "object"), + distance: item.distance, + direction: item.direction, + category: item.type + } + }); + } + + let roads; + if (originalResult.roads) { + roads = originalResult.roads.map((item) => { + return { + id: item.id, + title: item.name, + distance: Number(item.distance), + direction: item.direction, + location: libs.common.getLocation(item.location, "lng,lat", "object") + } + }); + } + + let roadinters; + if (originalResult.roadinters) { + roadinters = originalResult.roadinters.map((item) => { + return { + distance: Number(item.distance), + direction: item.direction, + first_id: item.first_id, + first_name: item.first_name, + second_id: item.second_id, + second_name: item.second_name, + location: libs.common.getLocation(item.location, "lng,lat", "object") + } + }); + } + + let result = { + formatted_addresses: originalResult.formatted_address, + country: originalResult.addressComponent.country, + province: originalResult.addressComponent.province, + city: JSON.stringify(originalResult.addressComponent.city) === "[]" || !originalResult.addressComponent.city ? originalResult.addressComponent.province : originalResult + .addressComponent.city, + district: originalResult.addressComponent.district, + street: originalResult.addressComponent.country, + street_number: originalResult.addressComponent.streetNumber.street + originalResult.addressComponent.streetNumber.number, + adcode: originalResult.addressComponent.adcode, + pois, + roads, + roadinters + }; + let res = { + result, + ...requestRes + }; + return res; + } + + // API - 地址解析(地址转坐标) + async address2location(data = {}) { + let { + address, + city, + } = data; + + let requestRes = await this.request({ + method: "GET", + url: "v3/geocode/geo", + dataType: "json", + data: { + address, + city + } + }); + + let originalResult = requestRes.originalResult.geocodes[0]; + let result = { + location: libs.common.getLocation(originalResult.location, "lng,lat", "object"), + adcode: originalResult.adcode, + province: originalResult.province, + city: originalResult.city, + district: originalResult.district, + street: originalResult.street, + street_number: originalResult.number, + }; + let res = { + result, + ...requestRes + }; + return res; + } + + // API - 坐标转换 + async translate(data = {}) { + let { + locations, + type, + } = data; + let locationsStr = ""; + locations.map((item, index) => { + if (index > 0) { + locationsStr += ";"; + } + locationsStr += libs.common.getLocation(item, "object", "lng,lat"); + }) + + let coordsys = { + "1": "gps", + "4": "mapbar", + "3": "baidu", + "": "autonavi", + } [type + ""]; + let requestRes = await this.request({ + method: "GET", + url: "v3/assistant/coordinate/convert", + dataType: "json", + data: { + locations: locationsStr, + coordsys + } + }); + let originalResult = requestRes.originalResult; + let returnLocationsStr = originalResult.locations; + let arr = returnLocationsStr.split(";"); + + let returnLocations = arr.map((item) => { + return libs.common.getLocation(item, "lng,lat", "object"); + }); + + let result = { + locations: returnLocations + }; + let res = { + result, + ...requestRes + }; + return res; + } + + // API - IP定位 + async ip2location(data = {}) { + let { + ip, + } = data; + + let requestRes = await this.request({ + method: "GET", + url: "v3/ip", + dataType: "json", + data: { + ip + } + }); + let originalResult = requestRes.originalResult; + let result = { + adcode: originalResult.adcode, + province: originalResult.province, + city: originalResult.city, + rectangle: originalResult.rectangle + }; + let res = { + result, + ...requestRes + }; + return res; + } + + // API - 关键词输入提示 + async inputtips(data = {}) { + let { + keyword, + city, + citylimit, + location, + datatype, + } = data; + + let requestData = { + keywords: keyword, + city, + citylimit, + datatype + }; + if (location) { + requestData.location = libs.common.getLocation(location, "object", "lng,lat"); + } + + let requestRes = await this.request({ + method: "GET", + url: "v3/assistant/inputtips", + dataType: "json", + data: requestData, + }); + + let originalResult = requestRes.originalResult; + + let _data = originalResult.tips.map((item) => { + return { + id: item.id, + name: item.name, + address: item.address, + location: libs.common.getLocation(item.location, "lng,lat", "object"), + adcode: item.adcode, + district: item.district + } + }); + + let result = { + data: _data + }; + let res = { + result, + ...requestRes + }; + return res; + } + + // API - 周边搜索 + async search(data = {}) { + let { + keyword, + location, + radius = 1000, + auto_extend = 1, + get_subpois, + orderby, + page_index = 1, + page_size = 20, + types, + city + } = data; + + let requestData = { + keywords: keyword, + types, + location: libs.common.getLocation(location, "object", "lng,lat"), + radius, + sortrule: orderby, + region: city, + city_limit: auto_extend ? false : true, + page_num: page_index, + page_size, + show_fields: get_subpois ? "children,business,navi,photos" : "business,navi,photos" + }; + + let requestRes = await this.request({ + method: "GET", + url: "v5/place/around", + dataType: "json", + data: requestData + }); + let originalResult = requestRes.originalResult; + + let _data = originalResult.pois.map((item) => { + return { + id: item.id, + title: item.name, + tel: item.business.tel, + address: item.address, + category: item.type, + location: libs.common.getLocation(item.location, "lng,lat", "object"), + distance: Number(item.distance), + adcode: item.adcode, + province: item.pname, + city: item.cityname, + district: item.adname, + children: item.children ? item.children.map((item2) => { + return { + parent_id: item.id, + id: item2.id, + title: item2.name, + address: item2.address, + category: item2.subtype, + location: libs.common.getLocation(item2.location, "lng,lat", "object") + } + }) : get_subpois ? [] : undefined, + } + }); + let result = { + data: _data + }; + let res = { + result, + ...requestRes + }; + return res; + } + + // API - 行政区划 + async districtSearch(data = {}) { + let { + adcode, + get_polygon, + page_index, + page_size, + filter, + subdistrict + } = data; + + let requestData = { + keywords: adcode, + subdistrict, + page: page_index, + offset: page_size, + filter + }; + + let requestRes = await this.request({ + method: "GET", + url: "v3/config/district", + dataType: "json", + data: requestData + }); + let originalResult = requestRes.originalResult; + + const formatDistricts = (list) => { + return list.map((item) => { + return { + adcode: item.adcode, + name: item.name, + fullname: item.name, + location: libs.common.getLocation(item.center, "lng,lat", "object"), + level: item.level, + children: typeof item.districts !== "undefined" ? formatDistricts(item.districts): undefined, + //polygon: item.polyline, + } + }); + } + let _data = formatDistricts(originalResult.districts[0].districts); + + let result = { + data: _data + }; + let res = { + result, + ...requestRes + }; + return res; + } + + // API - 路线规划(驾车) + async drivingRoute(data = {}) { + let { + mode, + from, + to, + from_poi, + to_poi, + policy, + waypoints, + avoid_polygons, + road_type, + plate_number, + cartype, + avoidroad, + ferry, + } = data; + + let requestRes = await this.request({ + method: "GET", + url: `v5/direction/driving`, + dataType: "json", + data: { + origin: libs.common.getLocation(from, "lat,lng", "lng,lat"), + destination: libs.common.getLocation(to, "lat,lng", "lng,lat"), + origin_id: from_poi, + destination_id: to_poi, + strategy: policy, + waypoints: libs.common.getReversalLocation(waypoints), + avoidpolygons: libs.common.getReversalLocation(avoid_polygons), + origin_type: road_type, + plate: plate_number, + cartype, + avoidroad, + ferry, + show_fields: "cost,tmcs,navi,cities,polyline" + } + }); + + let originalResult = requestRes.originalResult.route; + let routes = originalResult.paths.map((item) => { + let steps = item.steps.map((item2) => { + return { + instruction: item2.instruction, + road_name: item2.road_name, + dir_desc: item2.orientation, + distance: Number(item2.step_distance), + act_desc: item2.navi.action, + accessorial_desc: item2.navi.assistant_action, + cost: this.costFormat(item2.cost), + speed: item2.tmcs ? item2.tmcs.map((item3) => { + let levelIndex = { + "畅通": 0, + "缓行": 1, + "拥堵": 2, + "未知": 3, + "严重拥堵": 4, + } + return { + distance: Number(item3.tmc_distance), + level: levelIndex[item3.tmc_status], + polyline: this.polylineFormat(item3.tmc_polyline), + } + }) : undefined, + cities: item2.cities, + polyline: this.polylineFormat(item2.polyline), + } + }); + return { + mode: "driving", + distance: Number(item.distance), + restriction_status: Number(item.restriction), + taxi_cost: Number(originalResult.taxi_cost), + steps + } + }); + let result = { + routes + }; + let res = { + result, + ...requestRes + }; + return res; + } + + // API - 路线规划(步行) + async walkingRoute(data = {}) { + let { + mode, + from, + to, + alternative_route, + } = data; + + let requestRes = await this.request({ + method: "GET", + url: `v5/direction/walking`, + dataType: "json", + data: { + origin: libs.common.getLocation(from, "lat,lng", "lng,lat"), + destination: libs.common.getLocation(to, "lat,lng", "lng,lat"), + alternative_route, + show_fields: "cost,navi,polyline", // 此处强制传,为了和腾讯地图字段对齐 + } + }); + let originalResult = requestRes.originalResult.route; + let routes = originalResult.paths.map((item) => { + let duration1 = 0; + let steps = item.steps.map((item2) => { + let duration2 = this.durationFormat(item2.cost.duration); + duration1 += duration2; + return { + instruction: item2.instruction, + road_name: item2.road_name, + dir_desc: item2.orientation, + distance: Number(item2.step_distance), + act_desc: item2.navi.action || item2.navi.assistant_action, + taxi_cost: item2.cost.taxi ? this.priceFormat(item2.cost.taxi) : undefined, + duration: duration2, + polyline: this.polylineFormat(item2.polyline), + } + }); + + return { + mode: "walking", + distance: Number(item.distance), + duration: duration1, + steps + } + + }); + let result = { + routes + }; + let res = { + result, + ...requestRes + }; + return res; + } + + // API - 路线规划(骑行) + async bicyclingRoute(data = {}) { + let { + mode, + from, + to, + alternative_route, + } = data; + + let requestRes = await this.request({ + method: "GET", + url: `v5/direction/bicycling`, + dataType: "json", + data: { + origin: libs.common.getLocation(from, "lat,lng", "lng,lat"), + destination: libs.common.getLocation(to, "lat,lng", "lng,lat"), + alternative_route, + show_fields: "cost,navi,polyline", // 此处强制传,为了和腾讯地图字段对齐 + } + }); + let originalResult = requestRes.originalResult.route; + let routes = originalResult.paths.map((item) => { + let duration1 = 0; + let steps = item.steps.map((item2) => { + let duration2 = this.durationFormat(item2.cost.duration); + duration1 += duration2; + return { + instruction: item2.instruction, + road_name: item2.road_name, + dir_desc: item2.orientation, + distance: Number(item2.step_distance), + act_desc: item2.navi.action || item2.navi.assistant_action, + duration: duration2, + polyline: this.polylineFormat(item2.polyline), + } + }); + + return { + mode: "walking", + distance: Number(item.distance), + duration: duration1, + steps + } + + }); + let result = { + routes + }; + let res = { + result, + ...requestRes + }; + return res; + } + + // API - 路线规划(电动车) + async ebicyclingRoute(data = {}) { + let { + mode, + from, + to, + alternative_route, + } = data; + + let requestRes = await this.request({ + method: "GET", + url: `v5/direction/electrobike`, + dataType: "json", + data: { + origin: libs.common.getLocation(from, "lat,lng", "lng,lat"), + destination: libs.common.getLocation(to, "lat,lng", "lng,lat"), + alternative_route, + show_fields: "cost,navi,polyline", // 此处强制传,为了和腾讯地图字段对齐 + } + }); + let originalResult = requestRes.originalResult.route; + let routes = originalResult.paths.map((item) => { + let duration1 = 0; + let steps = item.steps.map((item2) => { + let duration2 = this.durationFormat(item2.cost.duration); + duration1 += duration2; + return { + instruction: item2.instruction, + road_name: item2.road_name, + dir_desc: item2.orientation, + distance: Number(item2.step_distance), + act_desc: item2.navi.action || item2.navi.assistant_action, + duration: duration2, + polyline: this.polylineFormat(item2.polyline), + } + }); + + return { + mode: "walking", + distance: Number(item.distance), + duration: duration1, + steps + } + + }); + let result = { + routes + }; + let res = { + result, + ...requestRes + }; + return res; + } + + // API - 路线规划(公交) + async transitRoute(data = {}) { + let { + mode, + from, + to, + from_poi, + to_poi, + policy, + ad1, + ad2, + city1, + city2, + alternative_route, + multiexport, + max_trans, + nightflag, + date, + time + } = data; + + let requestRes = await this.request({ + method: "GET", + url: `v5/direction/transit/integrated`, + dataType: "json", + data: { + origin: libs.common.getLocation(from, "lat,lng", "lng,lat"), + destination: libs.common.getLocation(to, "lat,lng", "lng,lat"), + originpoi: from_poi, + destinationpoi: to_poi, + strategy: policy, + ad1, + ad2, + city1, + city2, + AlternativeRoute: alternative_route, + multiexport, + max_trans, + nightflag, + date, + time, + show_fields: "cost,navi,polyline", // 此处强制传,为了和腾讯地图字段对齐 + } + }); + + let originalResult = requestRes.originalResult.route; + let routes = originalResult.transits.map((item) => { + let stepsItem = this.getSteps(item.segments); + let steps = stepsItem.map((item2) => { + let mode = item2.mode.toLowerCase(); + if (mode === "walking") { + // 步行 + return { + mode: "walking", + distance: Number(item2.distance), + duration: this.durationFormat(item2.cost.duration), + steps: item2.steps.map((item3) => { + return { + instruction: item3.instruction, + road_name: item3.road, + distance: Number(item3.distance), + act_desc: item3.navi.action || item3.navi.assistant_action, + polyline: this.polylineFormat(item3.polyline) + } + }), + } + } else if (mode === "bus") { + return { + mode: "transit", + lines: item2.buslines.map((item3) => { + return { + vehicle: item3.type.indexOf("地铁") > -1 ? "SUBWAY" : "BUS", + id: item3.id, + title: item3.name, + type: item3.type, + station_count: Number(item3.via_num), + distance: Number(item3.distance), + duration: this.durationFormat(item3.cost.duration), + polyline: this.polylineFormat(item3.polyline), + start_time: item3.start_time, + end_time: item3.end_time, + geton: { + id: item3.departure_stop.id, + title: item3.departure_stop.name, + location: libs.common.getLocation(item3.departure_stop.location, "lng,lat", "object"), + }, + getoff: { + id: item3.arrival_stop.id, + title: item3.arrival_stop.name, + location: libs.common.getLocation(item3.arrival_stop.location, "lng,lat", "object"), + }, + stations: item3.via_stops.map((item4) => { + return { + id: item4.id, + title: item4.name, + location: libs.common.getLocation(item4.location, "lng,lat", "object"), + } + }) + } + }), + } + } else if (mode === "railway") { + // 火车 + let item3 = item2; + return { + mode: "transit", + lines: [{ + vehicle: "RAIL", + id: item3.id, + title: item3.name, + type: item3.type, + distance: Number(item3.distance), + duration: this.durationFormat(item3.time), + geton: { + id: item3.departure_stop.id, + title: item3.departure_stop.name, + location: libs.common.getLocation(item3.departure_stop.location, "lng lat", "object"), + adcode: item3.departure_stop.adcode, + time: item3.departure_stop.time, + start: Number(item3.departure_stop.start), + }, + getoff: { + id: item3.arrival_stop.id, + title: item3.arrival_stop.name, + location: libs.common.getLocation(item3.arrival_stop.location, "lng lat", "object"), + adcode: item3.arrival_stop.adcode, + time: item3.arrival_stop.time, + end: Number(item3.arrival_stop.end), + }, + spaces: item3.spaces ? item3.spaces.map((item4) => { + return { + code: item4.code, + cost: this.priceFormat(item4.cost), + } + }) : undefined + }], + } + } else if (mode === "taxi") { + // 打车 + let item3 = item2; + return { + mode: "transit", + lines: [{ + vehicle: "TAXI", + distance: Number(item3.distance), + price: this.priceFormat(item3.price), + drivetime: this.durationFormat(item3.drivetime), + polyline: this.polylineFormat(item3.polyline), + startpoint: libs.common.getLocation(item3.startpoint, "lng,lat", "lat,lng"), + startname: item3.startname, + endpoint: libs.common.getLocation(item3.endpoint, "lng,lat", "lat,lng"), + endname: item3.endname + }] + } + } + }); + + return { + mode: "transit", + distance: Number(item.distance), + duration: this.durationFormat(item.cost.duration), + transit_fee: this.priceFormat(item.cost.transit_fee), + steps + } + }); + let result = { + routes + }; + let res = { + result, + ...requestRes + }; + return res; + } + + getSteps(segments) { + let steps = []; + segments.map((item, index) => { + for (let mode in item) { + steps.push({ + mode, + ...item[mode] + }); + } + }); + return steps; + } + + // 格式化价格,将字符串价格转成数值,保留2位小数 + priceFormat(price) { + try { + if (price === "") { + return -1; + } else { + return parseFloat(Number(price).toFixed(2)); + } + } catch (err) { + return -1; + } + } + + // 格式化cost + costFormat(cost = {}) { + let { + duration, + taxi_cost, + transit_fee, + tolls, + toll_distance, + toll_road, + traffic_lights + } = cost; + let res = {}; + if (typeof duration !== "undefined") res.duration = this.durationFormat(duration); + if (typeof taxi_cost !== "undefined") res.taxi_cost = this.priceFormat(taxi_cost); + if (typeof transit_fee !== "undefined") res.transit_fee = this.priceFormat(transit_fee); + if (typeof tolls !== "undefined") res.tolls = this.priceFormat(tolls); + if (typeof toll_distance !== "undefined") res.toll_distance = Number(toll_distance); + if (typeof toll_road !== "undefined") res.toll_road = toll_road; + if (typeof traffic_lights !== "undefined") res.traffic_lights = Number(traffic_lights); + + return res; + } + + // 格式化polyline,将原本polyline.polyline转成polyline + polylineFormat(polyline = {}) { + if (polyline.polyline) { + return libs.common.getReversalLocation(polyline.polyline); + } else if (typeof polyline === "string") { + return libs.common.getReversalLocation(polyline); + } else { + return ""; + } + } + + // 格式化时间(秒转分,向上进1) + durationFormat(duration) { + try { + return Math.ceil(Number(duration) / 60); + } catch (err) { + return undefined; + } + } + +} +module.exports = Service; \ No newline at end of file diff --git a/uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/service/index.js b/uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/service/index.js new file mode 100644 index 00000000..f78b2d6d --- /dev/null +++ b/uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/service/index.js @@ -0,0 +1,4 @@ +module.exports = { + "qqmap": require('./qqmap.js'), + "amap": require('./amap.js') +} \ No newline at end of file diff --git a/uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/service/qqmap.js b/uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/service/qqmap.js new file mode 100644 index 00000000..d90e820c --- /dev/null +++ b/uni_modules/uni-map-common/uniCloud/cloudfunctions/common/uni-map-common/service/qqmap.js @@ -0,0 +1,856 @@ +const libs = require('../libs'); + +class Service { + + // 构造函数 + constructor(data = {}) { + let { + key, + needOriginalResult = false, // 是否需要返回原始信息,默认false + } = data; + + this.config = { + provider: "qqmap", + key, + needOriginalResult, + serviceUrl: "https://apis.map.qq.com" + } + } + + async request(obj = {}) { + let { + url, + data = {} + } = obj; + if (url.indexOf("http") !== 0) { + url = `${this.config.serviceUrl}/${url}` + } + if (this.config.key && !data.key) { + data.key = this.config.key; + } + obj.data = JSON.parse(JSON.stringify(obj.data)); + let requestRes = await uniCloud.httpclient.request(url, obj); + let result = this.getResult(requestRes); + if (result.errCode != 0) { + throw new libs.error.UniCloudError(result); + } + return result; + } + + getResult(requestRes) { + let { + data: originalResult = {} + } = requestRes; + + let res = { + errCode: originalResult.status == 0 ? 0 : this.getErrCode(originalResult.status), + errMsg: originalResult.message, + originalResult, + }; + + return res; + } + + getErrCode(errCode) { + return errCode; + } + + // API - 逆地址解析(坐标转地址) + async location2address(data = {}) { + let { + location, + get_poi, + poi_options + } = data; + + let _poi_options = ""; + if (typeof poi_options === "object") { + let { + address_format, + radius, + policy, + page_index, + page_size + } = poi_options; + if (address_format && address_format !== "long") { + _poi_options += `address_format=${address_format};` + } + if (radius) { + _poi_options += `radius=${radius};` + } + if (policy) { + _poi_options += `policy=${policy};` + } + if (page_index) { + _poi_options += `page_index=${page_index};` + } + if (page_size) { + _poi_options += `page_size=${page_size};` + } + + if (_poi_options.lastIndexOf(";") === _poi_options.length - 1) { + _poi_options = _poi_options.substring(0, _poi_options.length - 1); + } + } + if (!_poi_options) _poi_options = undefined; + let requestRes = await this.request({ + method: "GET", + url: "ws/geocoder/v1/", + dataType: "json", + data: { + location, + get_poi, + poi_options: _poi_options, + } + }); + let originalResult = requestRes.originalResult.result; + let pois; + if (originalResult.pois) { + pois = originalResult.pois.map((item) => { + return { + id: item.id, + title: item.title, + address: item.address, + location: item.location, + distance: item._distance, + direction: item._dir_desc, + category: item.category + } + }); + } + let result = { + formatted_addresses: originalResult.address, + country: originalResult.address_component.nation, + province: originalResult.address_component.province, + city: originalResult.address_component.city, + district: originalResult.address_component.district, + street: originalResult.address_component.street, + street_number: originalResult.address_component.street_number, + adcode: originalResult.ad_info.adcode, + pois + }; + let res = { + result, + ...requestRes + }; + return res; + } + + // API - 地址解析(地址转坐标) + async address2location(data = {}) { + let { + address, + city, + } = data; + + let requestRes = await this.request({ + method: "GET", + url: "ws/geocoder/v1/", + dataType: "json", + data: { + address: address, + region: city, + } + }); + let originalResult = requestRes.originalResult.result; + + let result = { + location: originalResult.location, + adcode: originalResult.ad_info.adcode, + province: originalResult.address_components.province, + city: originalResult.address_components.city, + district: originalResult.address_components.district, + street: originalResult.address_components.street, + street_number: originalResult.address_components.street_number, + }; + let res = { + result, + ...requestRes + }; + + return res; + } + + // API - 坐标转换 + async translate(data = {}) { + let { + locations, + type, + } = data; + let locationsStr = ""; + locations.map((item, index) => { + if (index > 0) { + locationsStr += ";"; + } + locationsStr += libs.common.getLocation(item, "object", "lat,lng"); + }) + + let requestRes = await this.request({ + method: "GET", + url: "ws/coord/v1/translate", + dataType: "json", + data: { + locations: locationsStr, + type + } + }); + let originalResult = requestRes.originalResult; + + let result = { + locations: originalResult.locations + }; + let res = { + result, + ...requestRes + }; + return res; + } + + // API - IP定位 + async ip2location(data = {}) { + let { + ip, + } = data; + + let requestRes = await this.request({ + method: "GET", + url: "ws/location/v1/ip", + dataType: "json", + data: { + ip + } + }); + let originalResult = requestRes.originalResult.result; + let result = { + location: libs.common.getLocation(originalResult.location, "object", "object"), + nation: originalResult.ad_info.nation, + nation_code: originalResult.ad_info.nation_code, + adcode: originalResult.ad_info.adcode, + province: originalResult.ad_info.province, + city: originalResult.ad_info.city, + district: originalResult.ad_info.district + }; + let res = { + result, + ...requestRes + }; + return res; + } + + // API - 关键词输入提示 + async inputtips(data = {}) { + let { + keyword, + city, + citylimit, + location, + get_subpois, + policy, + filter, + address_format, + page_index, + page_size + } = data; + + let requestData = { + keyword, + region: city, + region_fix: citylimit ? 1 : 0, + get_subpois, + policy, + filter, + address_format, + page_index, + page_size + }; + if (location) { + requestData.location = libs.common.getLocation(location, "object", "lat,lng"); + } + + let requestRes = await this.request({ + method: "GET", + url: "ws/place/v1/suggestion", + dataType: "json", + data: requestData + }); + let originalResult = requestRes.originalResult; + + let _data = originalResult.data.map((item) => { + + let children; + if (originalResult.sub_pois) { + children = []; + originalResult.sub_pois.map((item2) => { + if (item2.parent_id === item.id) { + children.push({ + parent_id: item.id, + id: item2.id, + title: item2.title, + address: item2.address, + category: item2.category, + location: item2.location, + adcode: String(item2.adcode), + city: item2.city, + }); + } + }); + } + + return { + id: item.id, + title: item.title, + address: item.address, + category: item.category, + type: item.type, + location: item.location, + adcode: item.adcode, + province: item.province, + city: item.city, + district: item.district, + children + } + }); + + let result = { + data: _data + }; + let res = { + result, + ...requestRes + }; + return res; + } + + // API - 周边搜索 + async search(data = {}) { + let { + keyword, + location, + radius = 1000, + auto_extend = 1, + get_subpois, + orderby, + page_index = 1, + page_size = 20, + filter + } = data; + + if (radius < 10) radius = 10; + + let boundary = `nearby(${location.lat},${location.lng},${radius},${auto_extend})`; + + let requestData = { + keyword, + boundary, + get_subpois, + filter, + orderby: orderby === "distance" ? "_distance" : undefined, + page_index, + page_size + }; + + let requestRes = await this.request({ + method: "GET", + url: "ws/place/v1/search", + dataType: "json", + data: requestData + }); + let originalResult = requestRes.originalResult; + + let _data = originalResult.data.map((item) => { + let children; + if (originalResult.sub_pois) { + children = []; + originalResult.sub_pois.map((item2) => { + if (item2.parent_id === item.id) { + children.push({ + parent_id: item.id, + id: item2.id, + title: item2.title, + address: item2.address, + category: item2.category, + location: item2.location, + tel: item2.tel, + adcode: String(item2.ad_info.adcode), + province: item2.ad_info.province, + city: item2.ad_info.city, + district: item2.ad_info.district, + }); + } + }); + } + + return { + id: item.id, + title: item.title, + tel: item.tel, + address: item.address, + category: item.category, + type: item.type, + location: item.location, + distance: item._distance, + adcode: String(item.ad_info.adcode), + province: item.ad_info.province, + city: item.ad_info.city, + district: item.ad_info.district, + children + } + }); + + let result = { + data: _data + }; + let res = { + result, + ...requestRes + }; + return res; + } + + // API - 行政区划 + async districtSearch(data = {}) { + let { + adcode, + get_polygon, + max_offset + } = data; + + let requestData = { + id: adcode, + get_polygon, + max_offset + }; + + let requestRes = await this.request({ + method: "GET", + url: "ws/district/v1/getchildren", + dataType: "json", + data: requestData + }); + let originalResult = requestRes.originalResult; + let _data = originalResult.result[0].map((item) => { + return { + adcode: item.id, + name: item.name || item.fullname, + fullname: item.fullname, + location: item.location, + pinyin: item.pinyin, + cidx: item.cidx, + polygon: item.polygon, + } + }); + + let result = { + data: _data, + data_version: originalResult.data_version + }; + let res = { + result, + ...requestRes + }; + return res; + } + + // API - 路线规划(驾车) + async drivingRoute(data = {}) { + let { + mode, + from, + to, + from_poi, + to_poi, + policy, + waypoints, + avoid_polygons, + road_type, + plate_number, + cartype, + heading, + speed, + accuracy, + from_track, + get_mp, + no_step + } = data; + + let requestRes = await this.request({ + method: "GET", + url: `ws/direction/v1/driving`, + dataType: "json", + data: { + from, + to, + from_poi, + to_poi, + policy, + waypoints, + avoid_polygons, + road_type, + plate_number, + cartype, + heading, + speed, + accuracy, + from_track, + get_mp, + get_speed: 1, + added_fields: "cities", + no_step + } + }); + + let originalResult = requestRes.originalResult.result; + let routes = originalResult.routes.map((item) => { + let waypoints; + if (item.waypoints) { + waypoints = item.waypoints.map((item2) => { + return { + title: item2.title, + location: item2.location, + duration: item2.duration, + distance: item2.distance, + polyline: this.getPolyline(item.polyline, item2.polyline_idx), + polyline_idx: item2.polyline_idx, + } + }); + } + let steps = item.steps.map((item2) => { + return { + instruction: item2.instruction, + road_name: item2.road_name, + dir_desc: item2.dir_desc, + distance: item2.distance, + act_desc: item2.act_desc, + accessorial_desc: item2.accessorial_desc, + polyline: this.getPolyline(item.polyline, item2.polyline_idx), + polyline_idx: item2.polyline_idx, + } + }); + + let speed = item.speed.map((item2) => { + return { + distance: item2.distance, + level: item2.level, + polyline: this.getPolyline(item.polyline, item2.polyline_idx), + polyline_idx: item2.polyline_idx, + } + }); + + return { + mode: "driving", + tags: item.tags, + distance: item.distance, + duration: item.duration, + traffic_light_count: item.traffic_light_count, + restriction_status: item.restriction.status, + polyline: this.polylineFormat(item.polyline), + waypoints, + taxi_cost: item.taxi_fare.fare, + cities: item.cities, + steps, + speed + } + }); + let result = { + routes + }; + let res = { + result, + ...requestRes + }; + return res; + } + + // API - 路线规划(步行) + async walkingRoute(data = {}) { + let { + mode, + from, + to, + to_poi + } = data; + + let requestRes = await this.request({ + method: "GET", + url: `ws/direction/v1/walking`, + dataType: "json", + data: { + from, + to, + to_poi + } + }); + + let originalResult = requestRes.originalResult.result; + let routes = originalResult.routes.map((item) => { + let steps = item.steps.map((item2) => { + return { + instruction: item2.instruction, + road_name: item2.road_name, + dir_desc: item2.dir_desc, + distance: item2.distance, + act_desc: item2.act_desc, + type: item2.type, + polyline: this.getPolyline(item.polyline, item2.polyline_idx), + polyline_idx: item2.polyline_idx, + } + }); + + return { + mode: "walking", + distance: item.distance, + duration: item.duration, + direction: item.direction, + polyline: this.polylineFormat(item.polyline), + steps + } + }); + let result = { + routes + }; + let res = { + result, + ...requestRes + }; + return res; + } + + // API - 路线规划(骑行) + async bicyclingRoute(data = {}) { + let { + mode, + from, + to, + to_poi + } = data; + + let requestRes = await this.request({ + method: "GET", + url: `ws/direction/v1/bicycling`, + dataType: "json", + data: { + from, + to, + to_poi + } + }); + + let originalResult = requestRes.originalResult.result; + let routes = originalResult.routes.map((item) => { + let steps = item.steps.map((item2) => { + return { + instruction: item2.instruction, + road_name: item2.road_name, + dir_desc: item2.dir_desc, + distance: item2.distance, + act_desc: item2.act_desc, + polyline: this.getPolyline(item.polyline, item2.polyline_idx), + polyline_idx: item2.polyline_idx + } + }); + + return { + mode: "bicycling", + distance: item.distance, + duration: item.duration, + direction: item.direction, + polyline: this.polylineFormat(item.polyline), + steps + } + }); + let result = { + routes + }; + let res = { + result, + ...requestRes + }; + return res; + } + + // API - 路线规划(电动车) + async ebicyclingRoute(data = {}) { + let { + mode, + from, + to, + to_poi + } = data; + + let requestRes = await this.request({ + method: "GET", + url: `ws/direction/v1/ebicycling`, + dataType: "json", + data: { + from, + to, + to_poi + } + }); + + let originalResult = requestRes.originalResult.result; + let routes = originalResult.routes.map((item) => { + let steps = item.steps.map((item2) => { + return { + instruction: item2.instruction, + polyline_idx: item2.polyline_idx, + road_name: item2.road_name, + dir_desc: item2.dir_desc, + distance: item2.distance, + act_desc: item2.act_desc, + polyline: this.getPolyline(item.polyline, item2.polyline_idx) + } + }); + + return { + mode: "ebicycling", + distance: item.distance, + duration: item.duration, + direction: item.direction, + polyline: this.polylineFormat(item.polyline), + steps + } + }); + let result = { + routes + }; + let res = { + result, + ...requestRes + }; + return res; + } + + // API - 路线规划(公交) + async transitRoute(data = {}) { + let { + mode, + from, + to, + from_poi, + to_poi, + departure_time, + policy + } = data; + + let requestRes = await this.request({ + method: "GET", + url: `ws/direction/v1/transit`, + dataType: "json", + data: { + from, + to, + from_poi, + to_poi, + departure_time, + policy + } + }); + + let originalResult = requestRes.originalResult.result; + let routes = originalResult.routes.map((item) => { + let steps = item.steps.map((item2) => { + let mode = item2.mode.toLowerCase(); + if (mode === "walking") { + // 步行 + return { + mode: mode, + distance: item2.distance, + duration: item2.duration, + direction: item2.direction, + polyline: this.polylineFormat(item2.polyline), + steps: item2.steps ? item2.steps.map((item3) => { + return { + instruction: item3.instruction, + road_name: item3.road_name, + act_desc: item3.dir_desc, + distance: item3.distance, + polyline: this.getPolyline(item2.polyline, item3.polyline_idx), + polyline_idx: item3.polyline_idx, + } + }) : undefined, + } + } else { + // 非步行 + return { + mode: mode, + lines: item2.lines.map((item3) => { + return { + ...item3, + price: item3.vehicle !== "RAIL" ? this.priceFormat(item3.price) : item3.price, + polyline: this.polylineFormat(item3.polyline) + } + }) + } + } + }); + + return { + mode: "transit", + distance: item.distance, + duration: item.duration, + bounds: item.bounds, + steps + } + }); + let result = { + routes + }; + let res = { + result, + ...requestRes + }; + return res; + } + + // 格式化polyline,将压缩的polyline还原成完整的经纬度 + polylineFormat(polyline) { + try { + let coors = JSON.parse(JSON.stringify(polyline)); + for (let i = 2; i < coors.length; i++) { + coors[i] = parseFloat((coors[i - 2] + coors[i] / 1000000).toFixed(6)); + } + return coors; + } catch (err) { + return ""; + } + } + + // 格式化价格,将以分为单位的价格转元,保留2位小数 + priceFormat(price) { + try { + if (price === "" || price == -1) { + return -1; + } else { + return parseFloat((price / 100).toFixed(2)); + } + } catch (err) { + return -1; + } + } + + getPolyline(polyline, polyline_idx) { + let polylineArr = this.polylineFormat(polyline); + if (typeof polyline_idx == "object") { + let arr = polylineArr.slice(polyline_idx[0], polyline_idx[1] + 1); + let str = ""; + arr.map((item, index) => { + if (index % 2 === 0) { + str += `${item}` + } else { + str += `,${item};` + } + }); + // 去除最后一个; + if (str.lastIndexOf(";") === str.length - 1) { + str = str.substring(0, str.length - 1); + } + return str; + } else { + return polylineArr[polyline_idx] + "," + polylineArr[polyline_idx + 1]; + } + + } + +} +module.exports = Service; \ No newline at end of file diff --git a/uni_modules/uni-map-common/uniCloud/cloudfunctions/uni-map-co/index.obj.js b/uni_modules/uni-map-common/uniCloud/cloudfunctions/uni-map-co/index.obj.js new file mode 100644 index 00000000..0211e7c1 --- /dev/null +++ b/uni_modules/uni-map-common/uniCloud/cloudfunctions/uni-map-co/index.obj.js @@ -0,0 +1,518 @@ +// 引入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"); + +module.exports = { + _before: function() { + // 如果配置中心不存在地图配置,则使用本地地图配置 + if (!UniMapConfig) { + UniMapConfig = LocalMapConfig; + } + let defaultProvider = UniMapConfig.default || "qqmap"; + let params = this.getParams(); + let { + provider = defaultProvider, + needOriginalResult = false + } = params[0] || {}; + console.log('provider: ', provider) + 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; + }, + _after: function(error, res) { + if (error) { + throw error; // 如果方法抛出错误,也直接抛出不处理 + } + 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; + 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; +} \ No newline at end of file diff --git a/uni_modules/uni-map-common/uniCloud/cloudfunctions/uni-map-co/package.json b/uni_modules/uni-map-common/uniCloud/cloudfunctions/uni-map-co/package.json new file mode 100644 index 00000000..5d4ecb92 --- /dev/null +++ b/uni_modules/uni-map-common/uniCloud/cloudfunctions/uni-map-co/package.json @@ -0,0 +1,9 @@ +{ + "name": "uni-map-co", + "dependencies": { + "uni-config-center": "file:../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center", + "uni-map-common": "file:../common/uni-map-common", + "uni-id-common": "file:../../../../uni-id-common/uniCloud/cloudfunctions/common/uni-id-common" + }, + "extensions": {} +} \ No newline at end of file diff --git a/uni_modules/uni-map-common/uniCloud/cloudfunctions/uni-map-co/uni-map-co.param.js b/uni_modules/uni-map-common/uniCloud/cloudfunctions/uni-map-co/uni-map-co.param.js new file mode 100644 index 00000000..d5c1dd13 --- /dev/null +++ b/uni_modules/uni-map-common/uniCloud/cloudfunctions/uni-map-co/uni-map-co.param.js @@ -0,0 +1,123 @@ +// chooseLocation({ +// action: "location2address", +// needOriginalResult: true, +// data: { +// location: "39.908815,116.397507", +// get_poi: 1, +// poi_options: { +// address_format: "short", +// radius: 5000, +// policy: 4, +// //poitype: "010101", +// roadlevel: 1, +// homeorcorp: 1, +// page_index: 1, +// page_size: 1, +// } +// } +// }) + +// location2address({ +// location: "39.908815,116.397507", +// get_poi: 1, +// poi_options: { +// address_format: "short", +// radius: 5000, +// policy: 4, +// //poitype: "010101", +// roadlevel: 1, +// homeorcorp: 1 +// } +// }); + +address2location({ + address: "北京市海淀区彩和坊路海淀西大街74号", + city: "北京" +}); + +// translate({ +// locations: [ +// { lat: 39.908815, lng: 116.397507 }, +// { lat: 39.908815, lng: 116.397107 } +// ], +// type: 3 +// }); + +// ip定位 +// ip2location({ +// ip: "111.206.145.41" +// }); + +// 输入提示 +// inputtips({ +// keyword: "人民医院", +// city: "北京市", +// datatype: "all", +// get_subpois: 1 +// }); + +// 周边搜索 +// search({ +// keyword: "酒店", +// location: { +// lat: 39.908815, +// lng: 116.397507 +// }, +// radius: 1000, +// auto_extend: 1, +// get_subpois: 1, +// orderby: "weight", +// page_index: 1, +// page_size: 20, +// city: "北京市" +// }); + +// 行政区划 +// districtSearch({ +// adcode: "110000", +// get_polygon: 2, +// max_offset: 500, +// subdistrict: 2 +// }); + +// 导航 - 驾车 +// route({ +// mode: "driving", +// from: "39.808815,116.387507", +// to: "39.908815,116.397507", +// get_mp: 1, +// }); + +// 导航 - 步行 +// route({ +// mode: "walking", +// from: "40.034852,116.319820", +// to: "39.771075,116.351395", +// alternative_route: 3 +// }); + +// 导航 - 骑行 +// route({ +// mode: "bicycling", +// from: "40.034852,116.319820", +// to: "39.771075,116.351395", +// alternative_route: 3 +// }); + +// 导航 - 电动车 +// route({ +// mode: "ebicycling", +// from: "40.034852,116.319820", +// to: "39.771075,116.351395", +// alternative_route: 3 +// }); + +// 导航 - 公交 +// route({ +// mode: "transit", +// from: "40.034852,116.319820", +// to: "29.771075,116.351395", +// //alternative_route: 3, +// city1: "010", +// city2: "0792", +// }); \ No newline at end of file -- GitLab