Files
geo-tools/src/views/DistanceCalculator.vue
T
missumandCursor 88e201e50b refactor: harden deps, fix geo math, and add engineering tooling
Replace xlsx with exceljs, unify CRS/DMS logic, move pages to views with shared map/toast composables, and add Vitest/ESLint/Prettier plus docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-12 09:26:15 +08:00

161 lines
5.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="container">
<div class="tool-header">
<router-link to="/" class="back-link"> 返回首页</router-link>
<h2>📏 距离计算工具</h2>
<p>计算两点间的距离</p>
</div>
<div class="card">
<div class="input-group">
<label class="input-label">坐标类型</label>
<div class="radio-group">
<label>
<input type="radio" v-model="coordType" value="geographic" name="coordType">
经纬度坐标
</label>
<label>
<input type="radio" v-model="coordType" value="planar" name="coordType">
平面坐标
</label>
</div>
</div>
<div class="grid grid-2">
<div>
<h3 class="card-title">起点坐标</h3>
<div class="input-group">
<label class="input-label">{{ coordType === 'geographic' ? '纬度' : 'Y坐标' }}</label>
<input type="number" v-model.number="point1.lat" class="input" step="0.000001"
placeholder="例:39.9075">
</div>
<div class="input-group">
<label class="input-label">{{ coordType === 'geographic' ? '经度' : 'X坐标' }}</label>
<input type="number" v-model.number="point1.lon" class="input" step="0.000001"
placeholder="例:116.3972">
</div>
</div>
<div>
<h3 class="card-title">终点坐标</h3>
<div class="input-group">
<label class="input-label">{{ coordType === 'geographic' ? '纬度' : 'Y坐标' }}</label>
<input type="number" v-model.number="point2.lat" class="input" step="0.000001"
placeholder="例:31.2304">
</div>
<div class="input-group">
<label class="input-label">{{ coordType === 'geographic' ? '经度' : 'X坐标' }}</label>
<input type="number" v-model.number="point2.lon" class="input" step="0.000001"
placeholder="例:121.4737">
</div>
</div>
</div>
<button @click="calculate" class="btn btn-primary mt-lg">计算距离</button>
<div v-if="distance !== null" class="result mt-xl">
<div class="result-label">计算结果</div>
<div class="result-value">
{{ formatDistance(distance) }}
</div>
<div class="result-details mt-md">
<p v-if="coordType === 'geographic'">
<strong></strong>{{ distance.toFixed(2) }} m<br>
<strong>千米</strong>{{ (distance / 1000).toFixed(3) }} km
</p>
<p v-else>
<strong>距离</strong>{{ distance.toFixed(4) }} 单位
</p>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { haversineDistance, planarDistance } from '../utils/coordinate'
const coordType = ref('geographic')
const point1 = ref({ lat: 39.9075, lon: 116.3972 })
const point2 = ref({ lat: 31.2304, lon: 121.4737 })
const distance = ref(null)
const calculate = () => {
if (coordType.value === 'geographic') {
distance.value = haversineDistance(
point1.value.lat,
point1.value.lon,
point2.value.lat,
point2.value.lon
)
} else {
distance.value = planarDistance(
point1.value.lon,
point1.value.lat,
point2.value.lon,
point2.value.lat
)
}
}
const formatDistance = (dist) => {
if (coordType.value === 'geographic') {
if (dist < 1000) {
return `${dist.toFixed(2)} 米`
} else {
return `${(dist / 1000).toFixed(3)} 千米`
}
} else {
return `${dist.toFixed(4)}`
}
}
</script>
<style scoped>
.tool-header {
text-align: center;
margin-bottom: var(--spacing-xl);
}
.back-link {
display: inline-block;
color: var(--text-secondary);
text-decoration: none;
margin-bottom: var(--spacing-md);
transition: color var(--transition-base);
}
.back-link:hover {
color: var(--primary);
}
.radio-group {
display: flex;
gap: var(--spacing-lg);
}
.radio-group label {
display: flex;
align-items: center;
gap: var(--spacing-xs);
cursor: pointer;
font-size: var(--font-size-base);
color: var(--text-primary);
}
.radio-group input[type="radio"] {
cursor: pointer;
}
.result-details {
font-size: var(--font-size-base);
color: var(--text-secondary);
line-height: 1.8;
}
.result-details p {
margin: 0;
}
</style>