文章目录
- 一、前言
- 二、 项目背景
- 三、交互开发流程
-
- 第一次任务:项目初始化
- 第二次任务:地图交互功能
- 第三次任务:模式选择与量测功能
- 第四次任务:数据库查询功能
- 第五次任务:地名搜索功能
- 最终任务 应用代码重构和添加注释
-
- 重构目标
- 重构方案
- 重构成果
- 重构优势
- 构建验证
- 四 AI SOLO模式的优势总结
-
- 项目成果
- 技术亮点
一、前言
上一篇文章里,学会了搭建第一个Vue应用。本文,通过Trae的SOLO模式,做一个具备简单功能的Web页面。近年来,在软件开发领域,AI辅助编程已经成为一种趋势。最近,老丁体验了Trae IDE的AI SOLO模式,印象挺深!本文记录用AI SOLO开发一个基于Vue 3和OpenLayers的地图应用的全过程,展示AI在实际项目开发中的表现。 
二、 项目背景
我们需要开发一个地图应用,主要功能包括:
- 显示本地摩卡托投影瓦片地图
- 支持双图层显示(底图+DEM等高线)
- 提供地图交互功能(缩放、漫游、重置视图等)
- 实现量测功能
- 集成SQLite数据库查询功能
技术栈选择:
- 前端:Vue 3 + Vite + OpenLayers 9
- 后端:Flask + SQLite
其产品界面如下: 
SOLO 是采用对话的方式,人类提需求,AI自主编程。 为了配置Trae,我们提前在PATH里安装好了Python、NodeJS,在Trae里配置了Node、Python等扩展插件,并用手工传统编程模式跑通了Vue的Hello-World例子。同时,在PATH里安装了Git,保证每个子任务最后都可以以git提交的模式直接签入。
三、交互开发流程
第一次任务:项目初始化
任务描述:创建Vue 3项目,集成OpenLayers,实现基础地图显示
AI SOLO模式的表现让我眼前一亮。当我提出需求后,AI立即:
关键代码片段:
// MapView.vue – 地图初始化
import Map from 'ol/Map'
import View from 'ol/View'
import TileLayer from 'ol/layer/Tile'
import XYZ from 'ol/source/XYZ'
map = new Map({
target: mapRef.value,
layers: [
new TileLayer({
source: new XYZ({
url: 'http://127.0.0.1:8087/osm_tiles/{z}/{x}/{y}.png',
maxZoom: 20,
minZoom: 0
})
})
],
view: new View({
center: [0, 0],
zoom: 2,
maxZoom: 20,
minZoom: 0
})
})
评价:AI准确理解了需求,代码结构清晰,符合Vue 3 Composition API的最佳实践。
第二次任务:地图交互功能
任务描述:添加缩放控制、漫游功能、重置视图、经纬度网格显示、鼠标位置实时显示
AI在理解需求后,迅速实现了这些功能:
关键实现:
// 缩放控制
const zoomIn = () => {
const view = map.getView()
const zoom = view.getZoom()
view.setZoom(zoom + 1)
}
// 经纬度网格
graticuleLayer = new Graticule({
strokeStyle: new Stroke({
color: 'rgba(255, 0, 0, 0.5)',
width: 1
}),
showLabels: true,
wrapX: false
})
// 鼠标位置
map.on('pointermove', (evt) => {
const coords = evt.coordinate
mouseCoordinates.value = {
lon: coords[0],
lat: coords[1]
}
})
评价:AI对OpenLayers的API非常熟悉,代码实现简洁高效,UI布局合理。
第三次任务:模式选择与量测功能
任务描述:实现漫游模式和量测模式的切换,以及量测距离的功能
这是最复杂的任务之一,AI的表现依然出色:
核心实现:
// 量测功能
const startMeasure = () => {
isMeasuring.value = true
measureResult.value = null
const handleClick = (evt) => {
if (!isDrawing) {
isDrawing = true
coordinates = [evt.coordinate]
const feature = new Feature({
geometry: new LineString(coordinates)
})
sketch = feature
measureSource.addFeature(feature)
} else {
coordinates.push(evt.coordinate)
if (sketch) {
sketch.getGeometry().setCoordinates(coordinates)
}
}
}
const handleDoubleClick = (evt) => {
if (isDrawing) {
isDrawing = false
const geometry = sketch.getGeometry()
const output = formatLength(geometry)
measureResult.value = output
stopMeasure()
}
}
}
const formatLength = (line) => {
const length = getLength(line, { projection: 'EPSG:3857' })
const kilometers = length / 1000
return kilometers.toFixed(3)
}
评价:AI准确理解了量测的交互逻辑,代码实现完整,考虑了各种边界情况(如拖拽时忽略事件)。 
第四次任务:数据库查询功能
任务描述:集成SQLite数据库,实现按日期查询测试记录,并在地图上显示结果
这个任务涉及前后端的协作,AI的表现依然令人满意:
后端实现(Flask):
@app.route('/api/query_by_date', methods=['GET'])
def query_by_date():
date_str = request.args.get('date')
if not date_str:
return jsonify({'error': '请提供日期参数'}), 400
try:
datetime.strptime(date_str, '%Y-%m-%d')
except ValueError:
return jsonify({'error': '日期格式不正确,请使用 YYYY-MM-DD 格式'}), 400
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute('''
SELECT test_id, test_time, test_name, test_lat, test_lon
FROM test_table
WHERE DATE(test_time) = ?
ORDER BY test_time
''', (date_str,))
rows = cursor.fetchall()
conn.close()
results = []
for row in rows:
results.append({
'test_id': row['test_id'],
'test_time': row['test_time'],
'test_name': row['test_name'],
'test_lat': row['test_lat'],
'test_lon': row['test_lon']
})
return jsonify({
'date': date_str,
'count': len(results),
'data': results
})
前端实现:
const queryData = async () => {
if (!selectedDate.value) {
alert('请选择日期')
return
}
try {
clearTestLayer()
const response = await fetch(`http://127.0.0.1:5000/api/query_by_date?date=${selectedDate.value}`)
const data = await response.json()
if (data.error) {
alert(data.error)
return
}
queryResult.value = data
if (!testLayer) {
createTestLayer()
}
const source = testLayer.getSource()
data.data.forEach(item => {
const coords = transform([item.test_lon, item.test_lat], 'EPSG:4326', 'EPSG:3857')
const feature = new Feature({
geometry: new Point(coords),
test_id: item.test_id,
test_time: item.test_time,
test_name: item.test_name
})
source.addFeature(feature)
})
if (data.data.length > 0) {
const extent = source.getExtent()
const view = map.getView()
view.fit(extent, { padding: [50, 50, 50, 50], maxZoom: 15 })
}
} catch (error) {
console.error('查询失败:', error)
alert('查询失败,请检查服务器是否运行')
}
}
评价:AI正确处理了坐标转换(WGS84到Web Mercator),实现了自动缩放到数据区域的功能,错误处理也很完善。
第五次任务:地名搜索功能
任务描述:集成OSM地名查询服务,实现按名称搜索地标位置,并在地图上显示结果
这个任务涉及第三方API集成和CORS跨域问题处理,AI的解决方案非常专业:
前端实现:
const searchPlaceByName = async () => {
if (!searchPlace.value) {
alert('请输入地名')
return
}
try {
clearSearchPlaceLayer()
const encodedName = encodeURIComponent(searchPlace.value)
const response = await fetch(`/api/query_osm/?indented=1&function=object_by_name&name=${encodedName}&submit=submit`)
const data = await response.json()
if (data.result !== 'succeeded') {
alert('查询失败')
return
}
searchResult.value = data
if (!searchPlaceLayer) {
createSearchPlaceLayer()
}
const source = searchPlaceLayer.getSource()
for (let i = 0; i < data.items; i++) {
const resultKey = `result${i}`
const result = data[resultKey]
if (result && result.center_pos) {
const coords = parseCenterPos(result.center_pos)
if (coords) {
const transformedCoords = transform([coords.lon, coords.lat], 'EPSG:4326', 'EPSG:3857')
const feature = new Feature({
geometry: new Point(transformedCoords),
name: result.name,
osm_id: result.osm_id
})
source.addFeature(feature)
}
}
}
if (data.items > 0) {
const extent = source.getExtent()
const view = map.getView()
view.fit(extent, { padding: [50, 50, 50, 50], maxZoom: 15 })
}
} catch (error) {
console.error('查询失败:', error)
alert('查询失败,请检查服务器是否运行')
}
}
const createSearchPlaceLayer = () => {
const vectorSource = new VectorSource()
searchPlaceLayer = new VectorLayer({
source: vectorSource,
style: new Style({
image: new Circle({
radius: 7,
fill: new Fill({
color: 'rgba(0, 0, 139, 0.5)'
})
})
})
})
map.addLayer(searchPlaceLayer)
}
const parseCenterPos = (centerPos) => {
const match = centerPos.match(/POINT\\(([\\d.]+) ([\\d.]+)\\)/)
if (match) {
return {
lon: parseFloat(match[1]),
lat: parseFloat(match[2])
}
}
return null
}
Vite代理配置(解决CORS问题):
// vite.config.js
export default defineConfig({
plugins: [vue()],
server: {
port: 3000,
https: false,
strictPort: true,
host: true,
proxy: {
'/api/query_osm': {
target: 'http://127.0.0.1:8087/query_osm',
changeOrigin: true,
rewrite: (path) => path
}
}
}
})
评价:AI准确理解了OSM查询服务的API格式,正确解析了POINT格式的坐标数据,并通过Vite代理优雅地解决了CORS跨域问题。深蓝色半透明圆形标记的样式实现完全符合需求。 
最终任务 应用代码重构和添加注释
随着项目功能的不断完善,MapView.vue 文件逐渐膨胀到 754 行,包含了地图初始化、数据查询、地名搜索、量测功能、地图控制等多个功能模块。这种单一文件包含过多职责的代码组织方式存在以下问题:
重构目标
- 将 MapView.vue 从 754 行减少到合理规模
- 按功能职责拆分为多个子组件
- 提取可复用的业务逻辑到 composables
- 提取纯函数到 utils
- 保持所有功能不变
重构方案
目录结构:
src/
├── components/ # UI 组件
│ ├── MapView.vue # 主容器组件 (117行)
│ ├── Sidebar.vue # 侧边栏 – 查询和搜索
│ ├── ModeSelector.vue # 模式选择器
│ ├── MapControls.vue # 地图控制按钮
│ ├── MeasureControls.vue # 量测控制
│ ├── MeasureResult.vue # 量测结果显示
│ └── MousePosition.vue # 鼠标位置显示
├── composables/ # 可复用逻辑
│ ├── useMap.js # 地图初始化和基础操作
│ ├── useDataQuery.js # 数据查询功能
│ ├── usePlaceSearch.js # 地名搜索功能
│ └── useMeasure.js # 量测功能
├── utils/ # 工具函数
│ ├── mapUtils.js # 地图工具函数
│ └── api.js # API 调用函数
├── App.vue
└── main.js
模块划分:
- Utils 层 – 纯函数和 API 调用
- Composables 层 – 可复用业务逻辑
- Components 层 – UI 组件
- MapView.vue – 主容器组件
重构成果
| MapView.vue | 754 行 | 117 行 | -84.5% |
| 总计 | 754 行 | 117 行 + 12 个新文件 | 模块化 |
- Utils: 2 个文件
- Composables: 4 个文件
- Components: 6 个文件
重构优势
- Composables 可以在其他项目中复用
- Utils 中的纯函数可以在任何地方使用
构建验证
重构完成后,项目构建成功,无任何错误:
npm run build
vite v5.4.21 building for production...
✓ 229 modules transformed.
dist/index.html 0.41 kB │ gzip: 0.30 kB
dist/assets/index-CUmN_D1s.css 8.62 kB │ gzip: 2.07 kB
dist/assets/index-B2uDXUdW.js 388.77 kB │ gzip: 120.35 kB
✓ built in 1.74s
四 AI SOLO模式的优势总结
通过这次合作开发,感觉对通用的Web简单页面开发,AI的成功率还是很高的。能准确理解复杂的需求,并将其转化为具体的实现方案。特别是在地图应用这种涉及多个技术栈的项目中,AI能够快速理解前后端的协作关系。从项目初始化到功能完成,整个过程非常流畅。AI能够快速生成代码,大大缩短了开发时间。
对于初学者,因为AI对OpenLayers、Vue 3、Flask等技术栈都非常熟悉,能够熟练使用各种API和最佳实践,你看着AI写程序,很快就知道一个含有大量文件的项目,每一步是怎么从Hello-World丰富起来的,看一次胜读十遍书。此外,AI每次提出新的需求或修改意见,AI都能快速响应并调整代码,迭代效率很高。
项目成果
最终,我们成功构建了一个功能完整的地图应用,包含:
- ✅ 双图层显示(底图+DEM等高线)
- ✅ 地图交互(缩放、漫游、重置视图)
- ✅ 经纬度网格显示
- ✅ 鼠标位置实时显示
- ✅ 模式选择(漫游/量测)
- ✅ 量测功能(距离计算,精确到小数点后3位)
- ✅ 数据查询(SQLite数据库,按日期查询)
- ✅ 结果可视化(红色圆点显示)
- ✅ 自动缩放到数据区域
- ✅ 地名搜索(OSM查询服务,按名称搜索)
- ✅ 搜索结果可视化(深蓝色半透明圆形)
- ✅ CORS跨域问题解决(Vite代理)
技术亮点
注:本文记录了与Trae IDE AI SOLO模式合作开发Vue地图应用的全过程,展示了AI在实际项目开发中的表现和价值。




