udpate
This commit is contained in:
1
.env.example
Normal file
1
.env.example
Normal file
@@ -0,0 +1 @@
|
|||||||
|
AMAP_KEY=***
|
||||||
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
node_modules
|
||||||
|
.env
|
||||||
|
!.env*example
|
||||||
6
address.json
Normal file
6
address.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"from": "北京市朝阳区望京SOHO",
|
||||||
|
"to": "杭州市西湖区雅仕苑"
|
||||||
|
}
|
||||||
|
]
|
||||||
8
distance-results.json
Normal file
8
distance-results.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"from": "北京市朝阳区望京SOHO",
|
||||||
|
"to": "杭州市西湖区雅仕苑",
|
||||||
|
"distanceMeters": 1128950.5753619769,
|
||||||
|
"distanceKm": "1128.95"
|
||||||
|
}
|
||||||
|
]
|
||||||
21
package.json
Normal file
21
package.json
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "test-map-distance",
|
||||||
|
"version": "0.0.2",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"pub": "ev deploy ./public -k test-map-distance -v 0.0.2 -u -y y"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
|
||||||
|
"license": "MIT",
|
||||||
|
"packageManager": "pnpm@10.26.0",
|
||||||
|
"type": "module",
|
||||||
|
"dependencies": {
|
||||||
|
"dotenv": "^17.2.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "^1.3.5",
|
||||||
|
"@types/node": "^25.0.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
34
plan/v0.0.1.md
Normal file
34
plan/v0.0.1.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# 地图两点距离计算
|
||||||
|
|
||||||
|
## 需求
|
||||||
|
|
||||||
|
使用高德地图 API,实现输入起点地址和终点地址,计算两者之间的直线距离。
|
||||||
|
|
||||||
|
## 实现方案
|
||||||
|
|
||||||
|
1. 使用高德地图**地理编码 API**将地址转换为经纬度坐标
|
||||||
|
2. 使用**Haversine 公式**计算两点间的直线距离
|
||||||
|
|
||||||
|
## API 依赖
|
||||||
|
|
||||||
|
- 高德地理编码 API: `https://restapi.amap.com/v3/geocode/geo`
|
||||||
|
- 需要在高德开放平台申请 API Key
|
||||||
|
|
||||||
|
## 输入输出
|
||||||
|
|
||||||
|
- 输入:起点地址(字符串)、终点地址(字符串)
|
||||||
|
- 输出:距离(米/公里)
|
||||||
|
|
||||||
|
## 文件结构
|
||||||
|
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
index.ts # 主逻辑实现
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## 参考链接- 高德开放平台:
|
||||||
|
|
||||||
|
https://console.amap.com/dev/key/app
|
||||||
|
|
||||||
|
创建应用类型,选择 Web 服务,获取 API Key。
|
||||||
56
pnpm-lock.yaml
generated
Normal file
56
pnpm-lock.yaml
generated
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
lockfileVersion: '9.0'
|
||||||
|
|
||||||
|
settings:
|
||||||
|
autoInstallPeers: true
|
||||||
|
excludeLinksFromLockfile: false
|
||||||
|
|
||||||
|
importers:
|
||||||
|
|
||||||
|
.:
|
||||||
|
dependencies:
|
||||||
|
dotenv:
|
||||||
|
specifier: ^17.2.3
|
||||||
|
version: 17.2.3
|
||||||
|
devDependencies:
|
||||||
|
'@types/bun':
|
||||||
|
specifier: ^1.3.5
|
||||||
|
version: 1.3.5
|
||||||
|
'@types/node':
|
||||||
|
specifier: ^25.0.3
|
||||||
|
version: 25.0.3
|
||||||
|
|
||||||
|
packages:
|
||||||
|
|
||||||
|
'@types/bun@1.3.5':
|
||||||
|
resolution: {integrity: sha512-RnygCqNrd3srIPEWBd5LFeUYG7plCoH2Yw9WaZGyNmdTEei+gWaHqydbaIRkIkcbXwhBT94q78QljxN0Sk838w==}
|
||||||
|
|
||||||
|
'@types/node@25.0.3':
|
||||||
|
resolution: {integrity: sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==}
|
||||||
|
|
||||||
|
bun-types@1.3.5:
|
||||||
|
resolution: {integrity: sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw==}
|
||||||
|
|
||||||
|
dotenv@17.2.3:
|
||||||
|
resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
undici-types@7.16.0:
|
||||||
|
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
|
||||||
|
|
||||||
|
snapshots:
|
||||||
|
|
||||||
|
'@types/bun@1.3.5':
|
||||||
|
dependencies:
|
||||||
|
bun-types: 1.3.5
|
||||||
|
|
||||||
|
'@types/node@25.0.3':
|
||||||
|
dependencies:
|
||||||
|
undici-types: 7.16.0
|
||||||
|
|
||||||
|
bun-types@1.3.5:
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 25.0.3
|
||||||
|
|
||||||
|
dotenv@17.2.3: {}
|
||||||
|
|
||||||
|
undici-types@7.16.0: {}
|
||||||
109
public/docs.md
Normal file
109
public/docs.md
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
# 地图两点距离计算工具
|
||||||
|
|
||||||
|
## 简介
|
||||||
|
|
||||||
|
使用高德地图 API,输入起点地址和终点地址,自动计算两者之间的直线距离。
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
### 1. 安装 Deno
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Linux/macOS (WSL)
|
||||||
|
curl -fsSL https://deno.land/install.sh | sh
|
||||||
|
|
||||||
|
# macOS
|
||||||
|
brew install deno
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 配置高德 API Key
|
||||||
|
|
||||||
|
**申请步骤:**
|
||||||
|
1. 访问 [高德开放平台](https://console.amap.com/dev/key/app)
|
||||||
|
2. 注册/登录账号
|
||||||
|
3. 点击「控制台」→「应用管理」→「创建新应用」
|
||||||
|
4. 填写应用名称,点击「添加 Key」
|
||||||
|
5. 勾选 **Web 服务** 权限
|
||||||
|
6. 复制生成的 Key
|
||||||
|
|
||||||
|
**配置环境变量:**
|
||||||
|
|
||||||
|
在项目根目录创建 `.env` 文件:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
AMAP_KEY=你的高德APIKey
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 运行程序
|
||||||
|
|
||||||
|
```bash
|
||||||
|
deno run -A https://kevisual.xiongxiao.me/root/test-map-distance/index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 查看结果
|
||||||
|
|
||||||
|
程序运行完成后,会在当前目录生成 `distance-results.json` 文件:
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"from": "起点地址",
|
||||||
|
"to": "终点地址",
|
||||||
|
"distanceMeters": 1120000,
|
||||||
|
"distanceKm": "1120.00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
## 本地开发
|
||||||
|
|
||||||
|
代码路径:https://git.xiongxiao.me/test/test-map-distance
|
||||||
|
|
||||||
|
### 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
test-map-distance/
|
||||||
|
├── .env # 环境变量(API Key)
|
||||||
|
├── address.json # 地址列表配置
|
||||||
|
├── distance-results.json # 计算结果(自动生成)
|
||||||
|
├── plan/
|
||||||
|
│ └── v0.0.1.md # 设计文档
|
||||||
|
└── public/
|
||||||
|
└── docs.md # 使用说明
|
||||||
|
```
|
||||||
|
|
||||||
|
### address.json 格式
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{ "from": "北京市", "to": "上海市" },
|
||||||
|
{ "from": "广州市", "to": "深圳市" }
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
## 实现原理
|
||||||
|
|
||||||
|
1. **地理编码**:使用高德地图 [地理编码 API](https://restapi.amap.com/v3/geocode/geo) 将地址转换为经纬度坐标
|
||||||
|
2. **距离计算**:使用 Haversine 公式计算两点间的直线距离
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Haversine 公式
|
||||||
|
const R = 6371000; // 地球半径(米)
|
||||||
|
const dLat = (to.lat - from.lat) * Math.PI / 180;
|
||||||
|
const dLng = (to.lng - from.lng) * Math.PI / 180;
|
||||||
|
const a = Math.sin(dLat/2)² + Math.cos(from.lat) * Math.cos(to.lat) * Math.sin(dLng/2)²;
|
||||||
|
const distance = R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
|
||||||
|
```
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
| 错误 | 原因 | 解决方案 |
|
||||||
|
|------|------|----------|
|
||||||
|
| `USERKEY_PLAT_NOMATCH` | API Key 未启用 Web 服务 | 登录高德开放平台,勾选 Web 服务权限 |
|
||||||
|
| `请在环境变量中设置 AMAP_KEY` | 未配置 .env 文件 | 创建 .env 文件并设置 AMAP_KEY |
|
||||||
|
| `地址解析失败` | 地址无法被识别 | 使用更详细或更简化的地址 |
|
||||||
|
|
||||||
|
## 参考链接
|
||||||
|
|
||||||
|
- [高德开放平台](https://lbs.amap.com/)
|
||||||
|
- [Deno 官方文档](https://deno.com/)
|
||||||
183
public/index.html
Normal file
183
public/index.html
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>地图距离计算工具 - 使用说明</title>
|
||||||
|
<!-- Bootstrap CSS -->
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<!-- Highlight.js -->
|
||||||
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
min-height: 100vh;
|
||||||
|
padding: 40px 0;
|
||||||
|
}
|
||||||
|
.card {
|
||||||
|
border: none;
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
||||||
|
}
|
||||||
|
.card-header {
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
color: white;
|
||||||
|
border-radius: 16px 16px 0 0 !important;
|
||||||
|
padding: 25px 30px;
|
||||||
|
}
|
||||||
|
.card-header h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
.card-body {
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
#content {
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
#content h1 {
|
||||||
|
color: #667eea;
|
||||||
|
border-bottom: 2px solid #667eea;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
#content h2 {
|
||||||
|
color: #764ba2;
|
||||||
|
margin-top: 30px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
#content h3 {
|
||||||
|
color: #555;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
#content h4 {
|
||||||
|
color: #666;
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
#content p {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
#content ul, #content ol {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
padding-left: 25px;
|
||||||
|
}
|
||||||
|
#content li {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
#content a {
|
||||||
|
color: #667eea;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
#content a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
#content pre {
|
||||||
|
border-radius: 10px;
|
||||||
|
margin: 15px 0;
|
||||||
|
}
|
||||||
|
#content code:not(pre code) {
|
||||||
|
background: #f3f4f6;
|
||||||
|
color: #e91e63;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
#content table {
|
||||||
|
margin: 15px 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
#content th, #content td {
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
padding: 12px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
#content th {
|
||||||
|
background: #f8f9fa;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
#content tr:hover {
|
||||||
|
background: #f8f9fa;
|
||||||
|
}
|
||||||
|
#content blockquote {
|
||||||
|
border-left: 4px solid #667eea;
|
||||||
|
padding-left: 20px;
|
||||||
|
margin: 15px 0;
|
||||||
|
color: #666;
|
||||||
|
background: #f8f9fa;
|
||||||
|
padding: 15px 20px;
|
||||||
|
border-radius: 0 8px 8px 0;
|
||||||
|
}
|
||||||
|
#content img {
|
||||||
|
max-width: 100%;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin: 15px 0;
|
||||||
|
}
|
||||||
|
.loading {
|
||||||
|
text-align: center;
|
||||||
|
padding: 50px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
.spinner-border {
|
||||||
|
width: 3rem;
|
||||||
|
height: 3rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-10">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h1>地图距离计算工具 - 使用说明</h1>
|
||||||
|
</div>
|
||||||
|
<div class="card-body" id="content">
|
||||||
|
<div class="loading">
|
||||||
|
<div class="spinner-border text-primary" role="status">
|
||||||
|
<span class="visually-hidden">加载中...</span>
|
||||||
|
</div>
|
||||||
|
<p class="mt-3">文档加载中...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Bootstrap Bundle JS -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
<!-- Marked JS -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||||
|
<!-- Highlight.js -->
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
async function loadDocs() {
|
||||||
|
try {
|
||||||
|
const response = await fetch('./docs.md');
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('文档加载失败');
|
||||||
|
}
|
||||||
|
const markdown = await response.text();
|
||||||
|
document.getElementById('content').innerHTML = marked.parse(markdown);
|
||||||
|
|
||||||
|
// 代码高亮
|
||||||
|
document.querySelectorAll('pre code').forEach((block) => {
|
||||||
|
hljs.highlightElement(block);
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
document.getElementById('content').innerHTML = `
|
||||||
|
<div class="alert alert-danger" role="alert">
|
||||||
|
<h4 class="alert-heading">加载失败</h4>
|
||||||
|
<p>${error.message}</p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadDocs();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
133
public/index.ts
Normal file
133
public/index.ts
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
// deno run -A https://kevisual.xiongxiao.me/root/test-map-distance/index.ts?a=1
|
||||||
|
|
||||||
|
import path from 'node:path';
|
||||||
|
import fs from 'node:fs';
|
||||||
|
/**
|
||||||
|
* 手动读取 .env 文件
|
||||||
|
*/
|
||||||
|
function loadEnv() {
|
||||||
|
const envPath = path.resolve(process.cwd(), '.env');
|
||||||
|
if (!fs.existsSync(envPath)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const content = fs.readFileSync(envPath, 'utf-8');
|
||||||
|
const env: Record<string, string> = {};
|
||||||
|
for (const line of content.split('\n')) {
|
||||||
|
const trimmed = line.trim();
|
||||||
|
if (!trimmed || trimmed.startsWith('#')) continue;
|
||||||
|
const [key, ...valueParts] = trimmed.split('=');
|
||||||
|
if (key && valueParts.length > 0) {
|
||||||
|
env[key.trim()] = valueParts.join('=').trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
|
||||||
|
const env = loadEnv();
|
||||||
|
const AMAP_KEY = env.AMAP_KEY || '';
|
||||||
|
|
||||||
|
if (!AMAP_KEY) {
|
||||||
|
throw new Error('请在环境变量中设置 AMAP_KEY');
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 地理编码:将地址转换为经纬度
|
||||||
|
*/
|
||||||
|
async function geocode(address: string): Promise<{ lng: number; lat: number } | null> {
|
||||||
|
const url = `https://restapi.amap.com/v3/geocode/geo?address=${encodeURIComponent(address)}&key=${AMAP_KEY}`;
|
||||||
|
const res = await fetch(url).then(r => r.json());
|
||||||
|
|
||||||
|
if (res.status === '1' && res.geocodes?.length > 0) {
|
||||||
|
const [lng, lat] = res.geocodes[0].location.split(',').map(Number);
|
||||||
|
return { lng, lat };
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算两点间的直线距离(米)
|
||||||
|
*/
|
||||||
|
function calculateDistance(
|
||||||
|
from: { lng: number; lat: number },
|
||||||
|
to: { lng: number; lat: number }
|
||||||
|
): number {
|
||||||
|
const R = 6371000; // 地球半径(米)
|
||||||
|
const dLat = (to.lat - from.lat) * Math.PI / 180;
|
||||||
|
const dLng = (to.lng - from.lng) * Math.PI / 180;
|
||||||
|
const a =
|
||||||
|
Math.sin(dLat / 2) ** 2 +
|
||||||
|
Math.cos(from.lat * Math.PI / 180) *
|
||||||
|
Math.cos(to.lat * Math.PI / 180) *
|
||||||
|
Math.sin(dLng / 2) ** 2;
|
||||||
|
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
||||||
|
return R * c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主函数:计算两个地址间的距离
|
||||||
|
*/
|
||||||
|
async function getDistance(fromAddress: string, toAddress: string) {
|
||||||
|
const [from, to] = await Promise.all([
|
||||||
|
geocode(fromAddress),
|
||||||
|
geocode(toAddress)
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!from || !to) {
|
||||||
|
throw new Error('地址解析失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
const distance = calculateDistance(from, to);
|
||||||
|
return {
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
distanceMeters: distance,
|
||||||
|
distanceKm: (distance / 1000).toFixed(2)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用示例
|
||||||
|
// getDistance('北京市', '上海市').then(console.log);
|
||||||
|
// const fromAddress = '北京市朝阳区望京SOHO';
|
||||||
|
// const toAddress = '杭州市西湖区雅仕苑';
|
||||||
|
|
||||||
|
|
||||||
|
const addressPath = path.resolve(process.cwd(), 'address.json');
|
||||||
|
|
||||||
|
type Address = {
|
||||||
|
from: string;
|
||||||
|
to: string;
|
||||||
|
}
|
||||||
|
let addressJson: Address[];
|
||||||
|
// 读取 address.json 文件
|
||||||
|
const addressData = fs.readFileSync(addressPath, 'utf-8');
|
||||||
|
try {
|
||||||
|
addressJson = JSON.parse(addressData) as Address[];
|
||||||
|
} catch (error) {
|
||||||
|
console.error('无法解析 address.json 文件,请确保其为有效的 JSON 格式');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
if (!Array.isArray(addressJson)) {
|
||||||
|
console.error('address.json 文件格式错误,应为地址对象数组');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const results: any[] = [];
|
||||||
|
|
||||||
|
for (const addr of addressJson) {
|
||||||
|
try {
|
||||||
|
// 计算距离
|
||||||
|
const result = await getDistance(addr.from, addr.to);
|
||||||
|
results.push({
|
||||||
|
from: addr.from,
|
||||||
|
to: addr.to,
|
||||||
|
distanceMeters: result.distanceMeters,
|
||||||
|
distanceKm: result.distanceKm,
|
||||||
|
});
|
||||||
|
console.log(`地址对 (${addr.from} -> ${addr.to}) 的距离为: ${result.distanceKm} 公里`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`计算地址对 (${addr.from} -> ${addr.to}) 距离时出错:`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 将结果写入 distance-results.json 文件
|
||||||
|
const resultPath = path.resolve(process.cwd(), 'distance-results.json');
|
||||||
|
fs.writeFileSync(resultPath, JSON.stringify(results, null, 2), 'utf-8');
|
||||||
|
console.log(`距离结果已保存到 ${resultPath}`);
|
||||||
Reference in New Issue
Block a user