@yangyongtao/gaea 1.1.10 → 1.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +178 -52
- package/package.json +4 -2
- package/public/image/CommonDialog/icon-/345/272/223/345/256/271@2x.png +0 -0
- package/public/image/CommonDialog/icon-/346/260/264/344/275/215@2x.png +0 -0
- package/public/image/CommonDialog/icon-/351/233/250/351/207/217@2x.png +0 -0
- package/public/image/CommonDialog//345/274/271/347/252/227_bg.png +0 -0
- package/public/image/CommonDialog//345/274/271/347/252/227/346/240/207/351/242/230/350/203/214/346/231/257.png +0 -0
- package/public/image/CommonDialog//345/274/271/347/252/227/346/240/207/351/242/230/350/243/205/351/245/260@2x.png +0 -0
- package/public/static/css/main.css +111 -0
- package/scripts/postinstall.mjs +18 -107
- package/src/GaeaMethods.js +1473 -7
- package/src/components/CommonDialog.vue +289 -0
- package/src/components/FlyAlongRoute.vue +35 -45
- package/src/components/HydrologicStationDialog.vue +435 -0
- package/src/components/LayerTree.vue +264 -0
- package/src/components/SecTourView.vue +83 -0
- package/src/components/WaterGateTour.vue +121 -0
- package/src/components/WeatherControl.vue +2 -2
- package/src/components/index.js +5 -0
- package/src/components/pathChart.vue +282 -0
- package/src/components/swiperSecAnimation.vue +208 -0
- package/src/vite-plugin.js +5 -2
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Teleport to="body">
|
|
3
|
+
<div
|
|
4
|
+
v-if="dialogVisible"
|
|
5
|
+
class="common-dialog-overlay"
|
|
6
|
+
:class="{ 'overlay-enter': showAnimation }"
|
|
7
|
+
@click="handleOverlayClick"
|
|
8
|
+
>
|
|
9
|
+
<div
|
|
10
|
+
class="common-dialog-container"
|
|
11
|
+
:class="{ 'dialog-enter': showAnimation }"
|
|
12
|
+
:style="{ width: width + 'px', height: height + 'px' }"
|
|
13
|
+
@click.stop
|
|
14
|
+
>
|
|
15
|
+
<!-- 头部 -->
|
|
16
|
+
<div class="dialog-header" v-if="showHeader">
|
|
17
|
+
<span class="dialog-title">{{ title }}</span>
|
|
18
|
+
<span class="dialog-close" v-if="closable" @click="handleClose">✕</span>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<!-- 内容区 -->
|
|
22
|
+
<div class="dialog-body" :style="{ maxHeight: maxHeight + 'px' }">
|
|
23
|
+
<slot />
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<!-- 底部 -->
|
|
27
|
+
<div class="dialog-footer" v-if="showFooter">
|
|
28
|
+
<slot name="footer">
|
|
29
|
+
<button class="dialog-btn btn-cancel" v-if="showCancelBtn" @click="handleCancel">
|
|
30
|
+
{{ cancelText }}
|
|
31
|
+
</button>
|
|
32
|
+
<button class="dialog-btn btn-confirm" :disabled="confirmLoading" @click="handleConfirm">
|
|
33
|
+
<span v-if="confirmLoading" class="loading-spinner"></span>
|
|
34
|
+
{{ confirmText }}
|
|
35
|
+
</button>
|
|
36
|
+
</slot>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</Teleport>
|
|
41
|
+
</template>
|
|
42
|
+
|
|
43
|
+
<script setup>
|
|
44
|
+
import { ref, watch, onBeforeUnmount } from 'vue';
|
|
45
|
+
|
|
46
|
+
const props = defineProps({
|
|
47
|
+
// v-model:visible
|
|
48
|
+
modelValue: { type: Boolean, default: false },
|
|
49
|
+
title: { type: String, default: '提示' },
|
|
50
|
+
width: { type: [String, Number], default: 1662 },
|
|
51
|
+
height: { type: [String, Number], default: 773 },
|
|
52
|
+
maxHeight: { type: [String, Number], default: 647 },
|
|
53
|
+
// 显示控制
|
|
54
|
+
showHeader: { type: Boolean, default: true },
|
|
55
|
+
showFooter: { type: Boolean, default: false },
|
|
56
|
+
showCancelBtn: { type: Boolean, default: true },
|
|
57
|
+
closable: { type: Boolean, default: true },
|
|
58
|
+
// 按钮文案
|
|
59
|
+
confirmText: { type: String, default: '确认' },
|
|
60
|
+
cancelText: { type: String, default: '取消' },
|
|
61
|
+
// 行为
|
|
62
|
+
closeOnOverlay: { type: Boolean, default: true },
|
|
63
|
+
confirmLoading: { type: Boolean, default: false },
|
|
64
|
+
// 确认后是否自动关闭
|
|
65
|
+
autoCloseOnConfirm: { type: Boolean, default: true },
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const emit = defineEmits(['update:modelValue', 'confirm', 'cancel', 'close']);
|
|
69
|
+
|
|
70
|
+
const dialogVisible = ref(false);
|
|
71
|
+
const showAnimation = ref(false);
|
|
72
|
+
let timer = null;
|
|
73
|
+
|
|
74
|
+
watch(() => props.modelValue, (val) => {
|
|
75
|
+
if (val) {
|
|
76
|
+
dialogVisible.value = true;
|
|
77
|
+
// 下一帧触发动画
|
|
78
|
+
timer = setTimeout(() => { showAnimation.value = true; }, 16);
|
|
79
|
+
document.body.style.overflow = 'hidden';
|
|
80
|
+
} else {
|
|
81
|
+
showAnimation.value = false;
|
|
82
|
+
timer = setTimeout(() => {
|
|
83
|
+
dialogVisible.value = false;
|
|
84
|
+
}, 300);
|
|
85
|
+
document.body.style.overflow = '';
|
|
86
|
+
}
|
|
87
|
+
}, { immediate: true });
|
|
88
|
+
|
|
89
|
+
onBeforeUnmount(() => {
|
|
90
|
+
document.body.style.overflow = '';
|
|
91
|
+
clearTimeout(timer);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
function close() {
|
|
95
|
+
emit('close');
|
|
96
|
+
emit('update:modelValue', false);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function handleOverlayClick() {
|
|
100
|
+
if (props.closeOnOverlay && props.closable) close();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function handleClose() {
|
|
104
|
+
if (props.closable) close();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function handleCancel() {
|
|
108
|
+
emit('cancel');
|
|
109
|
+
close();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function handleConfirm() {
|
|
113
|
+
if (props.confirmLoading) return;
|
|
114
|
+
emit('confirm');
|
|
115
|
+
if (props.autoCloseOnConfirm) close();
|
|
116
|
+
}
|
|
117
|
+
</script>
|
|
118
|
+
|
|
119
|
+
<style lang="less" scoped>
|
|
120
|
+
@font-face {
|
|
121
|
+
font-family: 'youshebiaotihei';
|
|
122
|
+
src: url('/font/youshebiaotihei.ttf') format('truetype');
|
|
123
|
+
font-weight: normal;
|
|
124
|
+
font-style: normal;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.common-dialog-overlay {
|
|
128
|
+
position: fixed;
|
|
129
|
+
inset: 0;
|
|
130
|
+
background: rgba(0, 0, 0, 0.5);
|
|
131
|
+
display: flex;
|
|
132
|
+
align-items: center;
|
|
133
|
+
justify-content: center;
|
|
134
|
+
z-index: 9999999;
|
|
135
|
+
opacity: 0;
|
|
136
|
+
transition: opacity 0.3s ease;
|
|
137
|
+
|
|
138
|
+
&.overlay-enter {
|
|
139
|
+
opacity: 1;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.common-dialog-container {
|
|
144
|
+
background: url('/image/CommonDialog/弹窗_bg.png') no-repeat center;
|
|
145
|
+
background-size: 100% 100%;
|
|
146
|
+
padding: 30px;
|
|
147
|
+
box-sizing: border-box;
|
|
148
|
+
display: flex;
|
|
149
|
+
flex-direction: column;
|
|
150
|
+
|
|
151
|
+
&.dialog-enter {
|
|
152
|
+
transform: translateY(0);
|
|
153
|
+
opacity: 1;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// 头部
|
|
158
|
+
.dialog-header {
|
|
159
|
+
display: flex;
|
|
160
|
+
align-items: center;
|
|
161
|
+
justify-content: space-between;
|
|
162
|
+
height: 44px;
|
|
163
|
+
padding: 0 16px;
|
|
164
|
+
border-radius: 8px 8px 0 0;
|
|
165
|
+
user-select: none;
|
|
166
|
+
background: url('/image/CommonDialog/弹窗标题背景.png') no-repeat center;
|
|
167
|
+
background-size: 100% 100%;
|
|
168
|
+
|
|
169
|
+
.dialog-title {
|
|
170
|
+
font-family: 'youshebiaotihei';
|
|
171
|
+
font-size: 24px;
|
|
172
|
+
font-weight: normal;
|
|
173
|
+
color: #fff;
|
|
174
|
+
letter-spacing: 1px;
|
|
175
|
+
-webkit-font-smoothing: antialiased;
|
|
176
|
+
-moz-osx-font-smoothing: grayscale;
|
|
177
|
+
display: flex;
|
|
178
|
+
align-items: center;
|
|
179
|
+
gap: 8px;
|
|
180
|
+
|
|
181
|
+
&::before {
|
|
182
|
+
content: '';
|
|
183
|
+
display: inline-block;
|
|
184
|
+
width: 40px;
|
|
185
|
+
height: 40px;
|
|
186
|
+
background: url('/image/CommonDialog/弹窗标题装饰@2x.png') no-repeat center;
|
|
187
|
+
background-size: contain;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.dialog-close {
|
|
192
|
+
width: 24px;
|
|
193
|
+
height: 24px;
|
|
194
|
+
display: flex;
|
|
195
|
+
align-items: center;
|
|
196
|
+
justify-content: center;
|
|
197
|
+
color: rgba(255, 255, 255, 0.7);
|
|
198
|
+
font-size: 16px;
|
|
199
|
+
cursor: pointer;
|
|
200
|
+
border-radius: 4px;
|
|
201
|
+
transition: all 0.2s;
|
|
202
|
+
|
|
203
|
+
&:hover {
|
|
204
|
+
background: rgba(255, 255, 255, 0.15);
|
|
205
|
+
color: #fff;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// 内容区
|
|
211
|
+
.dialog-body {
|
|
212
|
+
padding: 20px 24px;
|
|
213
|
+
color: rgba(255, 255, 255, 0.9);
|
|
214
|
+
font-size: 14px;
|
|
215
|
+
overflow-y: auto;
|
|
216
|
+
flex: 1;
|
|
217
|
+
display: flex;
|
|
218
|
+
flex-direction: column;
|
|
219
|
+
|
|
220
|
+
&::-webkit-scrollbar {
|
|
221
|
+
width: 4px;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
&::-webkit-scrollbar-thumb {
|
|
225
|
+
background: #0088FF;
|
|
226
|
+
border-radius: 2px;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// 底部
|
|
231
|
+
.dialog-footer {
|
|
232
|
+
display: flex;
|
|
233
|
+
justify-content: flex-end;
|
|
234
|
+
gap: 10px;
|
|
235
|
+
padding: 12px 16px;
|
|
236
|
+
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
|
237
|
+
|
|
238
|
+
.dialog-btn {
|
|
239
|
+
padding: 7px 22px;
|
|
240
|
+
border-radius: 4px;
|
|
241
|
+
font-size: 13px;
|
|
242
|
+
cursor: pointer;
|
|
243
|
+
border: none;
|
|
244
|
+
transition: all 0.2s;
|
|
245
|
+
display: flex;
|
|
246
|
+
align-items: center;
|
|
247
|
+
gap: 6px;
|
|
248
|
+
|
|
249
|
+
&.btn-cancel {
|
|
250
|
+
background: rgba(255, 255, 255, 0.1);
|
|
251
|
+
color: rgba(255, 255, 255, 0.8);
|
|
252
|
+
border: 1px solid rgba(255, 255, 255, 0.15);
|
|
253
|
+
|
|
254
|
+
&:hover {
|
|
255
|
+
background: rgba(255, 255, 255, 0.2);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
&.btn-confirm {
|
|
260
|
+
background: #3b82f6;
|
|
261
|
+
color: #fff;
|
|
262
|
+
|
|
263
|
+
&:hover {
|
|
264
|
+
background: #2563eb;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
&:disabled {
|
|
268
|
+
opacity: 0.6;
|
|
269
|
+
cursor: not-allowed;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.loading-spinner {
|
|
274
|
+
width: 14px;
|
|
275
|
+
height: 14px;
|
|
276
|
+
border: 2px solid rgba(255, 255, 255, 0.3);
|
|
277
|
+
border-top-color: #fff;
|
|
278
|
+
border-radius: 50%;
|
|
279
|
+
animation: spin 0.6s linear infinite;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
@keyframes spin {
|
|
285
|
+
to {
|
|
286
|
+
transform: rotate(360deg);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
</style>
|
|
@@ -30,13 +30,12 @@
|
|
|
30
30
|
</div>
|
|
31
31
|
|
|
32
32
|
<div class="empty-tip" v-else>
|
|
33
|
-
|
|
33
|
+
暂无飞行点位,请开启"地图拾取坐标"后点击地图添加
|
|
34
34
|
</div>
|
|
35
35
|
|
|
36
|
-
<!--
|
|
36
|
+
<!-- 添加点位:统一使用地图拾取 -->
|
|
37
37
|
<div class="form-section">
|
|
38
38
|
<h4>添加点位</h4>
|
|
39
|
-
<!-- 地图拾取模式开关 -->
|
|
40
39
|
<div class="pick-row">
|
|
41
40
|
<button class="btn" :class="isPicking ? 'btn-picking-active' : 'btn-picking'" @click="togglePickMode">
|
|
42
41
|
<i class="fas" :class="isPicking ? 'fa-check-circle' : 'fa-map-marker-alt'"></i>
|
|
@@ -45,27 +44,14 @@
|
|
|
45
44
|
</div>
|
|
46
45
|
<div class="form-row">
|
|
47
46
|
<div class="form-group">
|
|
48
|
-
<label
|
|
49
|
-
<input type="
|
|
50
|
-
</div>
|
|
51
|
-
</div>
|
|
52
|
-
<div class="form-row">
|
|
53
|
-
<div class="form-group">
|
|
54
|
-
<label>经度</label>
|
|
55
|
-
<input type="number" v-model.number="inputLng" class="form-control" placeholder="点击地图或手动输入"
|
|
56
|
-
step="0.000001" />
|
|
47
|
+
<label>飞行高度(m)</label>
|
|
48
|
+
<input type="number" v-model.number="flightHeight" class="form-control" min="0" step="10" placeholder="飞行高度" />
|
|
57
49
|
</div>
|
|
58
50
|
<div class="form-group">
|
|
59
|
-
<label
|
|
60
|
-
<input type="number" v-model.number="
|
|
61
|
-
step="0.000001" />
|
|
62
|
-
</div>
|
|
63
|
-
<div class="form-group">
|
|
64
|
-
<label>高度(m)</label>
|
|
65
|
-
<input type="number" v-model.number="inputAlt" class="form-control" placeholder="高度" />
|
|
51
|
+
<label>飞行时长(秒)</label>
|
|
52
|
+
<input type="number" v-model.number="flightDuration" class="form-control" min="1" step="1" placeholder="飞行时长" />
|
|
66
53
|
</div>
|
|
67
54
|
</div>
|
|
68
|
-
<button class="btn btn-add" @click="addManualWaypoint">添加点位</button>
|
|
69
55
|
</div>
|
|
70
56
|
|
|
71
57
|
<!-- 飞行控制 -->
|
|
@@ -105,11 +91,10 @@ const currentIndex = ref(-1);
|
|
|
105
91
|
const isFlying = ref(false);
|
|
106
92
|
const isFlyOver = ref(false);
|
|
107
93
|
|
|
108
|
-
//
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
const inputAlt = ref(500);
|
|
94
|
+
// 固定飞行高度(避免拾取时高度随地形累加),可在面板中调整
|
|
95
|
+
const flightHeight = ref(150);
|
|
96
|
+
// 飞行时长(秒),可在面板中调整
|
|
97
|
+
const flightDuration = ref(20);
|
|
113
98
|
|
|
114
99
|
// 地图拾取模式
|
|
115
100
|
const isPicking = ref(false);
|
|
@@ -149,7 +134,7 @@ const togglePickMode = () => {
|
|
|
149
134
|
name: `点位 ${waypoints.value.length + 1}`,
|
|
150
135
|
lat: +pos.lat.toFixed(6),
|
|
151
136
|
lng: +pos.lng.toFixed(6),
|
|
152
|
-
alt:
|
|
137
|
+
alt: Number(flightHeight.value) || 150,
|
|
153
138
|
});
|
|
154
139
|
}
|
|
155
140
|
};
|
|
@@ -171,22 +156,6 @@ const removeCanvasListener = () => {
|
|
|
171
156
|
}
|
|
172
157
|
};
|
|
173
158
|
|
|
174
|
-
// 手动添加点位
|
|
175
|
-
const addManualWaypoint = () => {
|
|
176
|
-
if (inputLng.value == null || inputLat.value == null) return;
|
|
177
|
-
const name = inputName.value || `点位 ${waypoints.value.length + 1}`;
|
|
178
|
-
waypoints.value.push({
|
|
179
|
-
name,
|
|
180
|
-
lat: inputLat.value,
|
|
181
|
-
lng: inputLng.value,
|
|
182
|
-
alt: inputAlt.value || 500,
|
|
183
|
-
});
|
|
184
|
-
inputName.value = '';
|
|
185
|
-
inputLng.value = null;
|
|
186
|
-
inputLat.value = null;
|
|
187
|
-
inputAlt.value = 500;
|
|
188
|
-
};
|
|
189
|
-
|
|
190
159
|
// 删除点位
|
|
191
160
|
const removeWaypoint = (index) => {
|
|
192
161
|
waypoints.value.splice(index, 1);
|
|
@@ -217,11 +186,11 @@ const startFlight = async () => {
|
|
|
217
186
|
const lineData = waypoints.value.map(wp => ({
|
|
218
187
|
x: wp.lat,
|
|
219
188
|
y: wp.lng,
|
|
220
|
-
z: 150
|
|
189
|
+
z: Number(flightHeight.value) || 150
|
|
221
190
|
}));
|
|
222
191
|
|
|
223
192
|
await APP.flyAlongPath(lineData, {
|
|
224
|
-
duration:
|
|
193
|
+
duration: Number(flightDuration.value) > 0 ? Number(flightDuration.value) : 20,
|
|
225
194
|
xrotation: 30,
|
|
226
195
|
lockEye: false
|
|
227
196
|
});
|
|
@@ -278,7 +247,7 @@ onBeforeUnmount(() => {
|
|
|
278
247
|
position: absolute;
|
|
279
248
|
top: 100px;
|
|
280
249
|
left: 600px;
|
|
281
|
-
z-index:
|
|
250
|
+
z-index: 10000;
|
|
282
251
|
width: 380px;
|
|
283
252
|
background: rgba(15, 23, 42, 0.95);
|
|
284
253
|
border-radius: 12px;
|
|
@@ -369,6 +338,27 @@ onBeforeUnmount(() => {
|
|
|
369
338
|
.waypoint-list {
|
|
370
339
|
max-height: 200px;
|
|
371
340
|
overflow-y: auto;
|
|
341
|
+
padding-right: 4px;
|
|
342
|
+
scrollbar-width: thin;
|
|
343
|
+
scrollbar-color: rgba(59, 130, 246, 0.6) transparent;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.waypoint-list::-webkit-scrollbar {
|
|
347
|
+
width: 6px;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.waypoint-list::-webkit-scrollbar-track {
|
|
351
|
+
background: transparent;
|
|
352
|
+
border-radius: 3px;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.waypoint-list::-webkit-scrollbar-thumb {
|
|
356
|
+
background: linear-gradient(180deg, rgba(59, 130, 246, 0.7), rgba(6, 182, 212, 0.7));
|
|
357
|
+
border-radius: 3px;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.waypoint-list::-webkit-scrollbar-thumb:hover {
|
|
361
|
+
background: linear-gradient(180deg, rgba(59, 130, 246, 1), rgba(6, 182, 212, 1));
|
|
372
362
|
}
|
|
373
363
|
|
|
374
364
|
.waypoint-item {
|