diff --git a/app/wails/frontend/components.d.ts b/app/wails/frontend/components.d.ts index 551f7c8..7003c82 100644 --- a/app/wails/frontend/components.d.ts +++ b/app/wails/frontend/components.d.ts @@ -10,12 +10,17 @@ declare module 'vue' { CPUUsage: typeof import('./src/components/system/cpu/CPUUsage.vue')['default'] CPUUsageChart: typeof import('./src/components/system/cpu/CPUUsageChart.vue')['default'] ElButton: typeof import('element-plus/es')['ElButton'] + ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup'] ElCol: typeof import('element-plus/es')['ElCol'] ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider'] + ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] + ElIcon: typeof import('element-plus/es')['ElIcon'] + ElInput: typeof import('element-plus/es')['ElInput'] ElProgress: typeof import('element-plus/es')['ElProgress'] ElRow: typeof import('element-plus/es')['ElRow'] ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] ElStatistic: typeof import('element-plus/es')['ElStatistic'] + ElSwitch: typeof import('element-plus/es')['ElSwitch'] ElTableV2: typeof import('element-plus/es')['ElTableV2'] ElTabPane: typeof import('element-plus/es')['ElTabPane'] ElTabs: typeof import('element-plus/es')['ElTabs'] diff --git a/app/wails/frontend/index.html b/app/wails/frontend/index.html index c6011c4..c3b93d3 100644 --- a/app/wails/frontend/index.html +++ b/app/wails/frontend/index.html @@ -4,6 +4,14 @@ wails + +
diff --git a/app/wails/frontend/package.json b/app/wails/frontend/package.json index 8009489..ec8fe88 100644 --- a/app/wails/frontend/package.json +++ b/app/wails/frontend/package.json @@ -19,7 +19,9 @@ "vite": "^4.0.0" }, "dependencies": { + "@amap/amap-jsapi-loader": "^1.0.1", "@vueuse/core": "^10.2.1", + "axios": "^1.4.0", "echarts": "^5.4.2", "element-plus": "^2.3.7", "eruda": "^3.0.0", diff --git a/app/wails/frontend/package.json.md5 b/app/wails/frontend/package.json.md5 index 432f504..e933267 100644 --- a/app/wails/frontend/package.json.md5 +++ b/app/wails/frontend/package.json.md5 @@ -1 +1 @@ -d09bd561bfdf7ff46efd368fe8aa4abe \ No newline at end of file +56a069904657d2e7c850e467b8924bd9 \ No newline at end of file diff --git a/app/wails/frontend/src/router/router.js b/app/wails/frontend/src/router/router.js index a547b72..8b64642 100644 --- a/app/wails/frontend/src/router/router.js +++ b/app/wails/frontend/src/router/router.js @@ -31,6 +31,14 @@ const routes = [ groups: "/", } }, + { + path: "/location-record", + component: ()=>import("src/views/tabs/location-record/index.vue"), + meta: { + title: "定位记录", + groups: "/" + } + }, { path: "/test", component: ()=>import("src/views/tabs/home/Test.vue"), diff --git a/app/wails/frontend/src/utils/axios/index.ts b/app/wails/frontend/src/utils/axios/index.ts new file mode 100644 index 0000000..18b4167 --- /dev/null +++ b/app/wails/frontend/src/utils/axios/index.ts @@ -0,0 +1,62 @@ +import axios, {AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig} from "axios"; +import {ElNotification} from "element-plus"; + +export function getAxiosInstance(axiosRequestConfig: AxiosRequestConfig): AxiosInstance { + let instance = axios.create(axiosRequestConfig); + // 全局 请求拦截器 + instance.interceptors.request.use(async (config: InternalAxiosRequestConfig) => { + let headers = config.headers || {} + return config; + }) + // 全局 响应拦截器 + instance.interceptors.response.use(successCB, rejectCB); + return instance; +} + + +// 请求成功回调 +export function successCB(response: AxiosResponse | Promise): AxiosResponse | Promise { + function processResponse(response: AxiosResponse) { + if (response.status === 200) { // 响应成功 + if (response.data.code === 401) { + ElNotification.warning({ + message: "登录状态失效, 请重新登录", + }) + console.log(response,response.data.msg) + } else if (response.data.code === 403) { + setTimeout(() => { + console.log(response,response.data.msg) + }, 0) + } + return response; + } else { + return Promise.reject(response); + } + } + + if (response instanceof Promise) { + let resp: AxiosResponse + return new Promise((resolve)=>{ + response.then((r: AxiosResponse) => { + resp = r; + resolve(processResponse(resp)) + }); + }) + } else { + return processResponse(response); + } +} + +// 请求失败回调 +export function rejectCB(error: any): any { + let response = error.response + if(response.status === 401){ + return response; + } else if(response.status === 403){ + setTimeout(() => { + console.log(response.data.msg) + }, 0) + return response; + } + return Promise.reject(error); +} diff --git a/app/wails/frontend/src/views/tabs/home/Home.vue b/app/wails/frontend/src/views/tabs/home/Home.vue index 8afd865..052a0f7 100644 --- a/app/wails/frontend/src/views/tabs/home/Home.vue +++ b/app/wails/frontend/src/views/tabs/home/Home.vue @@ -151,6 +151,7 @@ const cpuInfo = useCpuInfo() 添加tab 环境变量 + 定位记录 diff --git a/app/wails/frontend/src/views/tabs/location-record/logic/color.ts b/app/wails/frontend/src/views/tabs/location-record/logic/color.ts new file mode 100644 index 0000000..97da563 --- /dev/null +++ b/app/wails/frontend/src/views/tabs/location-record/logic/color.ts @@ -0,0 +1,10 @@ +export const COLOR = [ + '#6090e0', '#30c030', '#d070d0', '#80c0f0', '#f07050', '#ffb900', + '#37a2da', '#ffdb5c', '#8378ea', '#e7bcf3', '#32c5e9', '#67e0e3', + '#dd6b66', '#759aa0', '#e69d87', '#8dc1a9', '#ea7e53', '#eedd78', +] + +export function randomColorList(len:number){ + return Array.from({ length: len }) + .map(() => COLOR[Math.floor(Math.random() * COLOR.length)]); +} diff --git a/app/wails/frontend/src/views/tabs/location-record/logic/icon.ts b/app/wails/frontend/src/views/tabs/location-record/logic/icon.ts new file mode 100644 index 0000000..54c8ae3 --- /dev/null +++ b/app/wails/frontend/src/views/tabs/location-record/logic/icon.ts @@ -0,0 +1,18 @@ +export function createCanvasDir(){ + let canvasDir = document.createElement('canvas') + let width = 24; + let height = 24; + canvasDir.width = width; + canvasDir.height = height; + + let context = canvasDir.getContext('2d')!; + context.strokeStyle = 'white'; + context.lineJoin = 'round'; + context.lineWidth = 8; + context.moveTo(-4, width - 4); + context.lineTo(width / 2, 6); + context.lineTo(width + 4, width - 4); + context.stroke(); + + return canvasDir; +} diff --git a/app/wails/frontend/src/views/tabs/location-record/logic/lines.ts b/app/wails/frontend/src/views/tabs/location-record/logic/lines.ts new file mode 100644 index 0000000..f440b82 --- /dev/null +++ b/app/wails/frontend/src/views/tabs/location-record/logic/lines.ts @@ -0,0 +1,72 @@ +import {randomColorList} from "src/views/tabs/location-record/logic/color"; +import {createCanvasDir} from "src/views/tabs/location-record/logic/icon"; +import {getAvgSpeed, getMaxSpeed} from "src/views/tabs/location-record/logic/speed"; + +const canvasDir = createCanvasDir(); +const SLOW = "#ff0036" +const NORMAL = "#ff8119" +const FAST = "#AF5" +export function drawLines(map,data,lines){ + map.remove(data.polylines) + data.polylines = [] + let colorList = randomColorList(lines.length) + + lines.forEach((_data,index) => { + let max = getMaxSpeed(_data) + let avg = getAvgSpeed(_data) + + let p:any = [] + for (let i = 0; i < _data.length; i++) { + let item = _data[i] + let speed = item.speed || 0 + let type + if(speed < avg / 2){ + type= SLOW + } else if(speed >= avg/2 && speed < avg){ + type = NORMAL + } else { + type = FAST + } + + if(p.length === 0){ + p.push({ + path: [new AMap.LngLat(item.longitude, item.latitude)], + strokeColor: type, + }) + } else { + if(p[p.length - 1].strokeColor === type){ + p[p.length - 1].path.push(new AMap.LngLat(item.longitude, item.latitude)) + } else { + let prevPath = p[p.length - 1].path + let prev = prevPath[prevPath.length - 1] + p.push({ + path: [prev, new AMap.LngLat(item.longitude, item.latitude)], + strokeColor: type, + }) + } + } + } + console.log("p",p) + + let polylineArr:any[] = [] + p.forEach((item)=>{ + let polyline = new AMap.Polyline({ + path: item.path, + showDir: true, + dirImg: canvasDir, + borderWeight: 6, // 线条宽度,默认为 1 + strokeWeight: 6, + strokeOpacity: 0.9, // 透明度 + strokeColor: item.strokeColor, // 线条颜色 + dirColor: 'white', + lineJoin: 'round' // 折线拐点连接处样式}) + }) + polylineArr.push(polyline) + }) + data.polylines.push(polylineArr) + }) + + data.polylines = data.polylines.flat() + console.log("polylines",data.polylines) + map.add(data.polylines) +} diff --git a/app/wails/frontend/src/views/tabs/location-record/logic/location.ts b/app/wails/frontend/src/views/tabs/location-record/logic/location.ts new file mode 100644 index 0000000..4cf45f7 --- /dev/null +++ b/app/wails/frontend/src/views/tabs/location-record/logic/location.ts @@ -0,0 +1,65 @@ +export function fixedLocationHandler(map,data) { + console.log(map,data) + let task:Promise[] = [] + let startTime + let preFixedData = (data.data || []).map((item, index) => { + if (index % 500 === 0) { + startTime = data.data[0].time + } + + let time = item.time + return { + x: item.longitude, + y: item.latitude, + sp: item.speed || 0, + ag: item.bearing || 0, + tm: index % 500 === 0 ? time.unix() : time.diff(startTime, 's') + } + }) + console.log("纠偏路线 预处理数据: ", preFixedData) + + let group:any[] = [] + let len = preFixedData.length + for (let i = 0; i < Math.ceil(len / 500); i++) { + group.push(preFixedData.splice(0, 500)) + } + console.log("分组: ", group) + + task = group.map(item => { + return new Promise(resolve => { + AMap.plugin('AMap.GraspRoad', function () { + let grasp = new AMap.GraspRoad(); + grasp.driving(item, function (error, result) { + if (error) { + resolve([]) + } + if (!error) { + let newPath = result.data.points;//纠偏后的轨迹 + let distance = result.data.distance;//里程 + + console.log("返回值 => ", "路径: ", newPath, "里程: ", distance) + resolve(newPath) + } + }) + }) + }) + }) + + Promise.all(task).then(paths => { + let fixedData = paths.flat(1) + console.log("纠偏路线数据: ", fixedData) + + data.fixedPolyline = new AMap.Polyline({ + path: fixedData.map(item => { + return new AMap.LngLat(item.x, item.y) + }), + showDir: true, + strokeColor: 'orange', // 线条颜色 + borderWeight: 6, // 线条宽度,默认为 1 + strokeWeight: 6, + }) + map.add(data.fixedPolyline) + }) +} + + diff --git a/app/wails/frontend/src/views/tabs/location-record/logic/login.ts b/app/wails/frontend/src/views/tabs/location-record/logic/login.ts new file mode 100644 index 0000000..7ff0415 --- /dev/null +++ b/app/wails/frontend/src/views/tabs/location-record/logic/login.ts @@ -0,0 +1,54 @@ +import {auth, LoginDTO} from "src/views/tabs/location-record/api"; +import moment from "moment"; +import {ElMessage, ElNotification} from "element-plus"; + +export function checkLoginStatus(){ + let user = localStorage.getItem("user") + let lastLogin = localStorage.getItem("lastLogin") + let token = localStorage.getItem("token") + + return !!user && + !!lastLogin && + !!token && + moment().diff(moment(lastLogin),"h") < 24 +} + +export function logoutHandler(){ + localStorage.removeItem("user") + localStorage.removeItem("lastLogin") + localStorage.removeItem("token") +} + +export function loginRequest(authModel:LoginDTO, server:string){ + logoutHandler() + + return new Promise((resolve)=>{ + auth.login(authModel,server).then((resp)=>{ + let res = resp.data + console.log("login", res) + if(res.code !== 200){ + ElMessage.warning({ + message: res.data || res.msg, + duration: 500 + }) + resolve(false) + } else { + ElMessage.success({ + message: "登录成功", + duration: 500 + }) + localStorage.setItem("user", authModel.account) + localStorage.setItem("lastLogin", moment().format("YYYY-MM-DD HH:mm:ss")) + localStorage.setItem("token",res.data.token) + resolve(true) + } + }).catch((e)=>{ + console.error(e) + ElMessage.error({ + message: "登录失败", + duration: 500, + }) + resolve(false) + }) + }) +} diff --git a/app/wails/frontend/src/views/tabs/location-record/logic/markers.ts b/app/wails/frontend/src/views/tabs/location-record/logic/markers.ts new file mode 100644 index 0000000..f13fa59 --- /dev/null +++ b/app/wails/frontend/src/views/tabs/location-record/logic/markers.ts @@ -0,0 +1,91 @@ +export function getMarkers(map,data,line){ + if(!data.tmpMarker){ + data.tmpMarker = new AMap.Marker({ + anchor: 'bottom-center', + offset: [0, -15], + }); + } + return line.filter((_, index) => index % 1 === 0).map((item) => { + let text = { + fontSize: 10, + content: `时间:${item.locationTime}
速度: ${((item.speed || 0) * 3.6).toFixed(2)}km/h 方向角: ${(item.bearing || 0).toFixed(2)}°` + } + + let marker = new AMap.LabelMarker({ + name: item.id, + position: [item.longitude, item.latitude], + zIndex: 10, + icon: { + // 图标类型,现阶段只支持 image 类型 + type: 'image', + // 图片 url + image: 'https://webapi.amap.com/theme/v1.3/markers/n/mark_b.png', + // 图片尺寸 + size: [6, 9], + // 图片相对 position 的锚点,默认为 bottom-center + anchor: 'bottom-center' + }, + // text, + }) + + function show(e) { + let position = e.data.data && e.data.data.position; + + if (position) { + data.tmpMarker.setContent( + `
` + + text.content + + '
' + + '
'); + data.tmpMarker.setPosition(position); + map.add(data.tmpMarker); + } + } + + function hide() { + map.remove(data.tmpMarker); + } + + marker.on('mouseover', (e) => show(e)); + marker.on('touchstart', (e) => show(e)); + marker.on('mouseout', () => hide()); + marker.on('touchend', () => hide()); + + return marker; + }); +} + +export function drawMarkers(map,data,options,lines){ + if(!data.labelsLayer){ + data.labelsLayer = new AMap.LabelsLayer({ + zooms: [3, 20], + zIndex: 1000, + // 该层内标注是否避让 + collision: true, + // 设置 allowCollision:true,可以让标注避让用户的标注 + allowCollision: false, + }); + map.add(data.labelsLayer) + } + data.labelsLayer.remove(data.markers) + data.markers = [] + + if(!options.showMarker){ + return + } + data.markers = lines.map(line=>{ + return getMarkers(map,data,line) + }).flat() + data.labelsLayer.add(data.markers) +} diff --git a/app/wails/frontend/src/views/tabs/location-record/logic/play.ts b/app/wails/frontend/src/views/tabs/location-record/logic/play.ts new file mode 100644 index 0000000..0df2cf3 --- /dev/null +++ b/app/wails/frontend/src/views/tabs/location-record/logic/play.ts @@ -0,0 +1,84 @@ +let index = 0 + +export function playAnimation(map,data,line,animateRate,view,itemIndex){ + console.log("playAnimation",line) + if(data.animateMarker){ + map.remove(data.animateMarker) + } + data.animateMarker = new AMap.Marker({ + map: map, + position: [0,0], + icon: "https://a.amap.com/jsapi_demos/static/demo-center-v2/car.png", + offset: new AMap.Pixel(-13, -26), + autoRotation: true + }) + + if(!data.infoWindow){ + data.infoWindow = new AMap.InfoWindow({ + offset: new AMap.Pixel(6, -25), + content: "", + isCustom: true + }); + } + + if(itemIndex !== view.animating){ + index = 0 + } + + let path = line.slice(index).map((item) => { + return new AMap.LngLat(item.longitude, item.latitude) + }) + + data.animateMarker.stopMove(); + data.animateMarker.on("movealong",()=>{}) + let lastMovingIndex = 0 + data.animateMarker.on("moving",(e)=>{ + if(lastMovingIndex != e.index){ + index++ + } + lastMovingIndex = e.index + let lastLocation = e.passedPath[e.passedPath.length - 1]; + data.infoWindow.setPosition(lastLocation); + let speed = ((line[index].speed||0) * 3.6).toFixed(2) + data.infoWindow.setContent(`
+
${line[index].locationTime}
+
${speed} km/h
+
`); + map.setCenter(e.target.getPosition(),true) + }) + data.animateMarker.on("moveend",()=>{ + if(index >= line.length-2){ + setTimeout(()=>{ + view.animating = -1 + index = 0 + data.animateMarker.stopMove() + map.remove(data.animateMarker) + data.infoWindow.close() + },100) + } + }) + let polyline = new AMap.Polyline({ + path: path, + }) + data.animateMarker.moveAlong(polyline.getPath(),{ + duration: 1000/animateRate, + autoRotation: true + }); + data.infoWindow.open(map, data.animateMarker.getPosition()) +} + +export function stopAnimation(map,data,view){ + if(!data.animateMarker){ + return + } + pauseAnimation(data) + view.animating = -1 + index = 0 +} + +export function pauseAnimation(data){ + if(!data.animateMarker){ + return + } + data.animateMarker.stopMove() +} diff --git a/app/wails/frontend/src/views/tabs/location-record/logic/speed.ts b/app/wails/frontend/src/views/tabs/location-record/logic/speed.ts new file mode 100644 index 0000000..0467bdc --- /dev/null +++ b/app/wails/frontend/src/views/tabs/location-record/logic/speed.ts @@ -0,0 +1,14 @@ +export function getMaxSpeed(data:any[]){ + let sortSpeedData = JSON.parse(JSON.stringify(data)).sort((a,b)=>{return (b.speed || 0) - (a.speed||0)}) + return ((sortSpeedData[0]||{}).speed || 0) +} + +export function getAvgSpeed(data:any[]){ + if(data.length === 0){ + return 0 + } else { + return ((data.map(item=>item.speed || 0).reduce((prev,cur)=>{ + return prev + cur + },0) / data.length)) + } +} diff --git a/app/wails/frontend/tsconfig.json b/app/wails/frontend/tsconfig.json index 2726733..d3c066f 100644 --- a/app/wails/frontend/tsconfig.json +++ b/app/wails/frontend/tsconfig.json @@ -10,6 +10,7 @@ "resolveJsonModule": true, "isolatedModules": false, "esModuleInterop": true, + "noImplicitAny": false, "lib": [ "ESNext", "DOM" @@ -24,7 +25,8 @@ "src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", - "src/**/*.vue" + "src/**/*.vue", + "node_modules/@amap/amap-jsapi-loader/src/global.d.ts" ], "references": [ { diff --git a/app/wails/frontend/yarn.lock b/app/wails/frontend/yarn.lock index 36c5fdc..b1e87be 100644 --- a/app/wails/frontend/yarn.lock +++ b/app/wails/frontend/yarn.lock @@ -7,6 +7,11 @@ resolved "https://registry.npmmirror.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== +"@amap/amap-jsapi-loader@^1.0.1": + version "1.0.1" + resolved "https://registry.npmmirror.com/@amap/amap-jsapi-loader/-/amap-jsapi-loader-1.0.1.tgz#9ec4b4d5d2467eac451f6c852e35db69e9f9f0c0" + integrity sha512-nPyLKt7Ow/ThHLkSvn2etQlUzqxmTVgK7bIgwdBRTg2HK5668oN7xVxkaiRe3YZEzGzfV2XgH5Jmu2T73ljejw== + "@ampproject/remapping@^2.2.0": version "2.2.1" resolved "https://registry.npmmirror.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" @@ -728,6 +733,11 @@ async-validator@^4.2.5: resolved "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz#c96ea3332a521699d0afaaceed510a54656c6339" integrity sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg== +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + autoprefixer@^10.4.14: version "10.4.14" resolved "https://registry.npmmirror.com/autoprefixer/-/autoprefixer-10.4.14.tgz#e28d49902f8e759dd25b153264e862df2705f79d" @@ -740,6 +750,15 @@ autoprefixer@^10.4.14: picocolors "^1.0.0" postcss-value-parser "^4.2.0" +axios@^1.4.0: + version "1.4.0" + resolved "https://registry.npmmirror.com/axios/-/axios-1.4.0.tgz#38a7bf1224cd308de271146038b551d725f0be1f" + integrity sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA== + dependencies: + follow-redirects "^1.15.0" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -833,6 +852,13 @@ color-name@1.1.3: resolved "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + commander@^4.0.0: version "4.1.1" resolved "https://registry.npmmirror.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" @@ -870,6 +896,11 @@ debug@^4.1.0, debug@^4.3.4: dependencies: ms "2.1.2" +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + didyoumean@^1.2.2: version "1.2.2" resolved "https://registry.npmmirror.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" @@ -992,6 +1023,20 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +follow-redirects@^1.15.0: + version "1.15.2" + resolved "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + fraction.js@^4.2.0: version "4.2.0" resolved "https://registry.npmmirror.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" @@ -1196,6 +1241,18 @@ micromatch@^4.0.4, micromatch@^4.0.5: braces "^3.0.2" picomatch "^2.3.1" +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + minimatch@^3.0.4: version "3.1.2" resolved "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -1362,6 +1419,11 @@ postcss@^8.1.10, postcss@^8.4.23, postcss@^8.4.24: picocolors "^1.0.0" source-map-js "^1.0.2" +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"