From 82d150e53a0f6cc75023f93ce1f542513c047c4f Mon Sep 17 00:00:00 2001 From: MaysWind Date: Sun, 18 Jun 2023 00:26:56 +0800 Subject: [PATCH] support amap --- conf/ezbookkeeping.ini | 11 +- pkg/errs/setting.go | 13 +- pkg/middlewares/server_settings_cookie.go | 12 ++ pkg/settings/setting.go | 28 +++- src/consts/api.js | 4 +- src/lib/map/amap.js | 165 ++++++++++++++++++++++ src/lib/map/index.js | 21 +++ src/lib/services.js | 3 + src/lib/settings.js | 3 + 9 files changed, 248 insertions(+), 12 deletions(-) create mode 100644 src/lib/map/amap.js diff --git a/conf/ezbookkeeping.ini b/conf/ezbookkeeping.ini index a9c936fa..671edeba 100644 --- a/conf/ezbookkeeping.ini +++ b/conf/ezbookkeeping.ini @@ -111,7 +111,7 @@ enable_register = true enable_export = true [map] -# Map provider, supports "openstreetmap", "googlemap", "baidumap". Leave blank if you want to disable map +# Map provider, supports "openstreetmap", "googlemap", "baidumap", "amap". Leave blank if you want to disable map map_provider = openstreetmap # Set to true to use the ezbookkeeping server to proxy map data requests, for "openstreetmap" @@ -123,6 +123,15 @@ google_map_api_key = # For "baidumap" only, Baidu map JavaScript API application key, please visit https://lbsyun.baidu.com/index.php?title=jspopular3.0/guide/getkey for more information baidu_map_ak = +# For "amap" only, Amap JavaScript API application key, please visit https://lbs.amap.com/api/javascript-api/guide/abc/prepare for more information +amap_application_key = + +# For "amap" only, Amap JavaScript API security verification method, supports "plain" (not recommend). +amap_security_verification_method = plain + +# For "amap" only, Amap JavaScript API application secret, this setting must be provided when "amap_security_verification_method" is set to "plain", please visit https://lbs.amap.com/api/javascript-api/guide/abc/prepare for more information +amap_application_secret = + [exchange_rates] # Exchange rates data source, supports the following types: # "euro_central_bank" diff --git a/pkg/errs/setting.go b/pkg/errs/setting.go index f6684271..f460f531 100644 --- a/pkg/errs/setting.go +++ b/pkg/errs/setting.go @@ -4,10 +4,11 @@ import "net/http" // Error codes related to settings var ( - ErrInvalidProtocol = NewSystemError(SystemSubcategorySetting, 0, http.StatusInternalServerError, "invalid server protocol") - ErrInvalidLogMode = NewSystemError(SystemSubcategorySetting, 1, http.StatusInternalServerError, "invalid log mode") - ErrGettingLocalAddress = NewSystemError(SystemSubcategorySetting, 2, http.StatusInternalServerError, "failed to get local address") - ErrInvalidUuidMode = NewSystemError(SystemSubcategorySetting, 3, http.StatusInternalServerError, "invalid uuid mode") - ErrInvalidExchangeRatesDataSource = NewSystemError(SystemSubcategorySetting, 4, http.StatusInternalServerError, "invalid exchange rates data source") - ErrInvalidMapProvider = NewSystemError(SystemSubcategorySetting, 5, http.StatusInternalServerError, "invalid map provider") + ErrInvalidProtocol = NewSystemError(SystemSubcategorySetting, 0, http.StatusInternalServerError, "invalid server protocol") + ErrInvalidLogMode = NewSystemError(SystemSubcategorySetting, 1, http.StatusInternalServerError, "invalid log mode") + ErrGettingLocalAddress = NewSystemError(SystemSubcategorySetting, 2, http.StatusInternalServerError, "failed to get local address") + ErrInvalidUuidMode = NewSystemError(SystemSubcategorySetting, 3, http.StatusInternalServerError, "invalid uuid mode") + ErrInvalidExchangeRatesDataSource = NewSystemError(SystemSubcategorySetting, 4, http.StatusInternalServerError, "invalid exchange rates data source") + ErrInvalidMapProvider = NewSystemError(SystemSubcategorySetting, 5, http.StatusInternalServerError, "invalid map provider") + ErrInvalidAmapSecurityVerificationMethod = NewSystemError(SystemSubcategorySetting, 6, http.StatusInternalServerError, "invalid amap security verification method") ) diff --git a/pkg/middlewares/server_settings_cookie.go b/pkg/middlewares/server_settings_cookie.go index 2f4a430d..231a61ba 100644 --- a/pkg/middlewares/server_settings_cookie.go +++ b/pkg/middlewares/server_settings_cookie.go @@ -31,6 +31,18 @@ func ServerSettingsCookie(config *settings.Config) core.MiddlewareHandlerFunc { settingsArr = append(settingsArr, buildStringSetting("bmak", config.BaiduMapAK)) } + if config.AMapApplicationKey != "" { + settingsArr = append(settingsArr, buildStringSetting("amak", config.AMapApplicationKey)) + } + + if config.AMapSecurityVerificationMethod != "" { + settingsArr = append(settingsArr, buildStringSetting("amsv", config.AMapSecurityVerificationMethod)) + + if config.AMapSecurityVerificationMethod == settings.AmapSecurityVerificationPlainMethod { + settingsArr = append(settingsArr, buildStringSetting("amas", config.AMapApplicationSecret)) + } + } + bundledSettings := strings.Join(settingsArr, "_") c.SetCookie(settingsCookieName, bundledSettings, int(config.TokenExpiredTime), "", "", false, false) diff --git a/pkg/settings/setting.go b/pkg/settings/setting.go index 2b20a8b6..023c9eef 100644 --- a/pkg/settings/setting.go +++ b/pkg/settings/setting.go @@ -67,6 +67,12 @@ const ( OpenStreetMapProvider string = "openstreetmap" GoogleMapProvider string = "googlemap" BaiduMapProvider string = "baidumap" + AmapProvider string = "amap" +) + +// Amap security verification method +const ( + AmapSecurityVerificationPlainMethod string = "plain" ) // Exchange rates data source types @@ -177,10 +183,13 @@ type Config struct { EnableDataExport bool // Map - MapProvider string - GoogleMapAPIKey string - BaiduMapAK string - EnableMapDataFetchProxy bool + MapProvider string + GoogleMapAPIKey string + BaiduMapAK string + AMapApplicationKey string + AMapSecurityVerificationMethod string + AMapApplicationSecret string + EnableMapDataFetchProxy bool // Exchange Rates ExchangeRatesDataSource string @@ -444,6 +453,8 @@ func loadMapConfiguration(config *Config, configFile *ini.File, sectionName stri config.MapProvider = GoogleMapProvider } else if getConfigItemStringValue(configFile, sectionName, "map_provider") == BaiduMapProvider { config.MapProvider = BaiduMapProvider + } else if getConfigItemStringValue(configFile, sectionName, "map_provider") == AmapProvider { + config.MapProvider = AmapProvider } else { return errs.ErrInvalidMapProvider } @@ -451,6 +462,15 @@ func loadMapConfiguration(config *Config, configFile *ini.File, sectionName stri config.EnableMapDataFetchProxy = getConfigItemBoolValue(configFile, sectionName, "map_data_fetch_proxy", false) config.GoogleMapAPIKey = getConfigItemStringValue(configFile, sectionName, "google_map_api_key") config.BaiduMapAK = getConfigItemStringValue(configFile, sectionName, "baidu_map_ak") + config.AMapApplicationKey = getConfigItemStringValue(configFile, sectionName, "amap_application_key") + + if getConfigItemStringValue(configFile, sectionName, "amap_security_verification_method") == AmapSecurityVerificationPlainMethod { + config.AMapSecurityVerificationMethod = AmapSecurityVerificationPlainMethod + } else { + return errs.ErrInvalidAmapSecurityVerificationMethod + } + + config.AMapApplicationSecret = getConfigItemStringValue(configFile, sectionName, "amap_application_secret") return nil } diff --git a/src/consts/api.js b/src/consts/api.js index 78a59358..99df5a8a 100644 --- a/src/consts/api.js +++ b/src/consts/api.js @@ -2,10 +2,12 @@ const baseApiUrlPath = '/api'; const baseProxyUrlPath = '/proxy'; const googleMapJavascriptUrl = 'https://maps.googleapis.com/maps/api/js'; const baiduMapJavascriptUrl = 'https://api.map.baidu.com/api?v=3.0'; +const amapJavascriptUrl = 'https://webapi.amap.com/maps?v=2.0'; export default { baseApiUrlPath: baseApiUrlPath, baseProxyUrlPath: baseProxyUrlPath, googleMapJavascriptUrl: googleMapJavascriptUrl, - baiduMapJavascriptUrl: baiduMapJavascriptUrl + baiduMapJavascriptUrl: baiduMapJavascriptUrl, + amapJavascriptUrl: amapJavascriptUrl } diff --git a/src/lib/map/amap.js b/src/lib/map/amap.js new file mode 100644 index 00000000..96cd21a6 --- /dev/null +++ b/src/lib/map/amap.js @@ -0,0 +1,165 @@ +import { asyncLoadAssets } from "@/lib/misc.js"; +import services from "@/lib/services.js"; +import settings from "@/lib/settings.js"; +import logger from '@/lib/logger.js'; + +const amapHolder = { + AMap: null +}; + +export function loadAmapAssets() { + if (amapHolder.AMap) { + return; + } + + if (!window._AMapSecurityConfig) { + const amapSecurityConfig = {}; + + if (settings.getAmapSecurityVerificationMethod() === 'plain') { + amapSecurityConfig.securityJsCode = settings.getAmapApplicationSecret(); + } + + window._AMapSecurityConfig = amapSecurityConfig; + } + + if (!window.onAMapCallback) { + window.onAMapCallback = () => { + amapHolder.AMap = window.AMap; + }; + } + + return asyncLoadAssets('js', services.generateAmapJavascriptUrl('onAMapCallback')); +} + +export function createAmapHolder() { + return { + mapProvider: 'amap', + dependencyLoaded: !!amapHolder.AMap, + inited: false, + defaultZoomLevel: 14, + minZoomLevel: 1, + amapInstance: null, + amapToolbar: null, + amapCenterPosition: null, + amapCenterMarker: null + }; +} + +export function createAmapInstance(mapHolder, mapContainer, options) { + if (!amapHolder.AMap) { + return null; + } + + const AMap = amapHolder.AMap; + const amapInstance = new AMap.Map(mapContainer, { + zoom: options.zoomLevel, + center: [ options.initCenter.longitude, options.initCenter.latitude ], + zooms: [ 1, 19 ], + jogEnable: false + }); + + AMap.plugin([ + 'AMap.ToolBar' + ], function() { + mapHolder.amapToolbar = new AMap.ToolBar({ + position: 'LT' + }); + + amapInstance.addControl(mapHolder.amapToolbar); + }); + + mapHolder.amapInstance = amapInstance; + mapHolder.inited = true; +} + +export function setAmapCenterTo(mapHolder, center, zoomLevel) { + if (!amapHolder.AMap || !mapHolder.amapInstance) { + return; + } + + const AMap = amapHolder.AMap; + + if (amapHolder.amapCenterPosition + && amapHolder.amapCenterPosition.originalLongitude === center.longitude + && amapHolder.amapCenterPosition.originalLatitude === center.latitude + && amapHolder.amapCenterPosition.convertedLongitude + && amapHolder.amapCenterPosition.convertedLatitude + ) { + mapHolder.amapInstance.setZoomAndCenter(zoomLevel, new AMap.LngLat(amapHolder.amapCenterPosition.convertedLongitude, amapHolder.amapCenterPosition.convertedLatitude)); + return; + } + + amapHolder.amapCenterPosition = { + originalLongitude: center.longitude, + originalLatitude: center.latitude, + convertedLongitude: null, + convertedLatitude: null + }; + + const centerPoint = new AMap.LngLat(center.longitude, center.latitude); + + AMap.convertFrom(centerPoint, 'gps', (status, result) => { + let convertedCenterPoint = centerPoint; + + if (result.info !== 'ok' || !result.locations) { + logger.warn('amap geo position convert failed'); + } else { + convertedCenterPoint = result.locations[0]; + amapHolder.amapCenterPosition.convertedLongitude = convertedCenterPoint.getLng(); + amapHolder.amapCenterPosition.convertedLatitude = convertedCenterPoint.getLat(); + } + + mapHolder.amapInstance.setZoomAndCenter(zoomLevel, convertedCenterPoint); + }); +} + +export function setAmapCenterMaker(mapHolder, position) { + if (!amapHolder.AMap || !mapHolder.amapInstance) { + return; + } + + const AMap = amapHolder.AMap; + const setMaker = function (point) { + if (!mapHolder.amapCenterMarker) { + mapHolder.amapCenterMarker = new AMap.Marker({ + position: point + }); + mapHolder.amapInstance.add(mapHolder.amapCenterMarker); + } else { + mapHolder.amapCenterMarker.setPosition(point); + } + } + + if (amapHolder.amapCenterPosition + && amapHolder.amapCenterPosition.originalLongitude === position.longitude + && amapHolder.amapCenterPosition.originalLatitude === position.latitude + && amapHolder.amapCenterPosition.convertedLongitude + && amapHolder.amapCenterPosition.convertedLatitude + ) { + setMaker(new AMap.LngLat(amapHolder.amapCenterPosition.convertedLongitude, amapHolder.amapCenterPosition.convertedLatitude)); + return; + } + + const markerPoint = new AMap.LngLat(position.longitude, position.latitude); + + AMap.convertFrom(markerPoint, 'gps', (status, result) => { + let convertedMarkPoint = markerPoint; + + if (result.info !== 'ok' || !result.locations) { + logger.warn('amap geo position convert failed'); + } else { + convertedMarkPoint = result.locations[0]; + } + + setMaker(convertedMarkPoint); + }); +} + +export function removeAmapCenterMaker(mapHolder) { + if (!mapHolder.amapInstance || !mapHolder.amapCenterMarker) { + return; + } + + mapHolder.amapInstance.remove(mapHolder.amapCenterMarker); + mapHolder.amapCenterMarker = null; +} diff --git a/src/lib/map/index.js b/src/lib/map/index.js index 242645de..f9b2d12a 100644 --- a/src/lib/map/index.js +++ b/src/lib/map/index.js @@ -27,6 +27,15 @@ import { removeBaiduMapCenterMaker } from './baidumap.js'; +import { + loadAmapAssets, + createAmapHolder, + createAmapInstance, + setAmapCenterTo, + setAmapCenterMaker, + removeAmapCenterMaker +} from './amap.js'; + export function loadMapAssets(language) { if (settings.getMapProvider() === 'openstreetmap') { return loadLeafletMapAssets(language); @@ -34,6 +43,8 @@ export function loadMapAssets(language) { return loadGoogleMapAssets(language); } else if (settings.getMapProvider() === 'baidumap') { return loadBaiduMapAssets(language); + } else if (settings.getMapProvider() === 'amap') { + return loadAmapAssets(language); } } @@ -44,6 +55,8 @@ export function createMapHolder() { return createGoogleMapHolder(); } else if (settings.getMapProvider() === 'baidumap') { return createBaiduMapHolder(); + } else if (settings.getMapProvider() === 'amap') { + return createAmapHolder(); } else { return null; } @@ -60,6 +73,8 @@ export function initMapInstance(mapHolder, mapContainer, options) { createGoogleMapInstance(mapHolder, mapContainer, options); } else if (mapHolder.mapProvider === 'baidumap') { createBaiduMapInstance(mapHolder, mapContainer, options); + } else if (mapHolder.mapProvider === 'amap') { + createAmapInstance(mapHolder, mapContainer, options); } } @@ -74,6 +89,8 @@ export function setMapCenterTo(mapHolder, center, zoomLevel) { setGoogleMapCenterTo(mapHolder, center, zoomLevel); } else if (mapHolder.mapProvider === 'baidumap') { setBaiduMapCenterTo(mapHolder, center, zoomLevel); + } else if (mapHolder.mapProvider === 'amap') { + setAmapCenterTo(mapHolder, center, zoomLevel); } } @@ -88,6 +105,8 @@ export function setMapCenterMarker(mapHolder, position) { setGoogleMapCenterMaker(mapHolder, position); } else if (mapHolder.mapProvider === 'baidumap') { setBaiduMapCenterMaker(mapHolder, position); + } else if (mapHolder.mapProvider === 'amap') { + setAmapCenterMaker(mapHolder, position); } } @@ -102,5 +121,7 @@ export function removeMapCenterMarker(mapHolder) { removeGoogleMapCenterMaker(mapHolder); } else if (mapHolder.mapProvider === 'baidumap') { removeBaiduMapCenterMaker(mapHolder); + } else if (mapHolder.mapProvider === 'amap') { + removeAmapCenterMaker(mapHolder); } } diff --git a/src/lib/services.js b/src/lib/services.js index 10f705b4..4ef1ca70 100644 --- a/src/lib/services.js +++ b/src/lib/services.js @@ -420,5 +420,8 @@ export default { }, generateBaiduMapJavascriptUrl: (callbackFnName) => { return `${api.baiduMapJavascriptUrl}&ak=${settings.getBaiduMapAK()}&callback=${callbackFnName}`; + }, + generateAmapJavascriptUrl: (callbackFnName) => { + return `${api.amapJavascriptUrl}&key=${settings.getAmapApplicationKey()}&callback=${callbackFnName}`; } }; diff --git a/src/lib/settings.js b/src/lib/settings.js index c771a81c..01c5eec4 100644 --- a/src/lib/settings.js +++ b/src/lib/settings.js @@ -171,5 +171,8 @@ export default { isMapDataFetchProxyEnabled: () => getServerSetting('mp') === '1', getGoogleMapAPIKey: () => getServerSetting('gmak'), getBaiduMapAK: () => getServerSetting('bmak'), + getAmapApplicationKey: () => getServerSetting('amak'), + getAmapSecurityVerificationMethod: () => getServerSetting('amsv'), + getAmapApplicationSecret: () => getServerSetting('amas'), clearSettings: clearSettings };