初次提交
This commit is contained in:
143
src/components/AreaCalculator.vue
Normal file
143
src/components/AreaCalculator.vue
Normal file
@@ -0,0 +1,143 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<div class="tool-header">
|
||||
<router-link to="/" class="back-link">← 返回首页</router-link>
|
||||
<h2>📐 面积计算工具</h2>
|
||||
<p>多边形面积计算(基于平面坐标)</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3 class="card-title">输入顶点坐标</h3>
|
||||
|
||||
<div v-for="(point, index) in points" :key="index" class="point-input">
|
||||
<span class="point-label">点 {{ index + 1 }}</span>
|
||||
<input type="number" v-model.number="point.x" class="input" placeholder="X坐标" step="0.0001">
|
||||
<input type="number" v-model.number="point.y" class="input" placeholder="Y坐标" step="0.0001">
|
||||
<button v-if="points.length > 3" @click="removePoint(index)" class="btn-remove" title="删除此点">
|
||||
✕
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button @click="addPoint" class="btn btn-secondary">➕ 添加顶点</button>
|
||||
<button @click="calculate" class="btn btn-primary">计算面积</button>
|
||||
</div>
|
||||
|
||||
<div v-if="area !== null" class="result mt-xl">
|
||||
<div class="result-label">多边形面积</div>
|
||||
<div class="result-value">
|
||||
{{ area.toFixed(4) }} 平方单位
|
||||
</div>
|
||||
<div class="result-details mt-md">
|
||||
<p><strong>顶点数量:</strong>{{ points.length }}</p>
|
||||
<p v-if="area > 10000"><strong>换算:</strong>{{ (area / 10000).toFixed(4) }} 公顷</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { calculatePolygonArea } from '../utils/geometry'
|
||||
|
||||
const points = ref([
|
||||
{ x: 0, y: 0 },
|
||||
{ x: 100, y: 0 },
|
||||
{ x: 100, y: 100 },
|
||||
{ x: 0, y: 100 }
|
||||
])
|
||||
|
||||
const area = ref(null)
|
||||
|
||||
const addPoint = () => {
|
||||
points.value.push({ x: 0, y: 0 })
|
||||
}
|
||||
|
||||
const removePoint = (index) => {
|
||||
points.value.splice(index, 1)
|
||||
}
|
||||
|
||||
const calculate = () => {
|
||||
area.value = calculatePolygonArea(points.value)
|
||||
}
|
||||
</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);
|
||||
}
|
||||
|
||||
.point-input {
|
||||
display: grid;
|
||||
grid-template-columns: 60px 1fr 1fr auto;
|
||||
gap: var(--spacing-sm);
|
||||
align-items: center;
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.point-label {
|
||||
font-weight: 500;
|
||||
color: var(--text-secondary);
|
||||
font-size: var(--font-size-sm);
|
||||
}
|
||||
|
||||
.btn-remove {
|
||||
background: var(--danger);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: var(--border-radius-sm);
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-base);
|
||||
font-size: var(--font-size-lg);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.btn-remove:hover {
|
||||
transform: scale(1.1);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: var(--spacing-md);
|
||||
margin-top: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.result-details {
|
||||
font-size: var(--font-size-base);
|
||||
color: var(--text-secondary);
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.result-details p {
|
||||
margin-bottom: var(--spacing-xs);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.point-input {
|
||||
grid-template-columns: 50px 1fr 1fr 36px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user