Kaynağa Gözat

fit:new way error

悦 陈 1 hafta önce
ebeveyn
işleme
e8183986c5

+ 16 - 0
myapp/src/app/tab1/neighborhood/neighborhood.page.ts

@@ -33,6 +33,7 @@ getStars(rating: number): string[] {
 }
 
   ngOnInit() {
+    this.birdList = []; 
   }
   async importBrid(){
     const birdDataset = [
@@ -159,6 +160,21 @@ getStars(rating: number): string[] {
     ];
     const BirdType=new CloudObject("BirdType");
     const query=new CloudQuery("Birdtype");
+    // 1. 获取所有现有鸟类名称
+    const existingBirds = await query.find();
+    const existingNames = existingBirds.map(bird => bird.get('name'));
+
+    // 2. 找出需要删除的重复记录
+    const birdsToDelete = existingBirds.filter(bird => 
+        birdDataset.some(newBird => newBird.name === bird.get('name'))
+    );
+
+    // 3. 删除重复记录
+    if (birdsToDelete.length > 0) {
+        console.log(`找到${birdsToDelete.length}条需要删除的重复记录`);
+        await Promise.all(birdsToDelete.map(bird => bird.destroy()));
+        console.log('已删除所有重复鸟类记录');
+    }
 
     for(const bird of birdDataset){
       try{

+ 87 - 56
myapp/src/app/tab1/way/way.page.html

@@ -5,49 +5,71 @@
 </ion-header>
 
 <ion-content [fullscreen]="true">
-     <!-- 新增路线表单模态框 -->
-  <div class="modal-overlay" *ngIf="showCreateModal" (click)="closeModal()">
+    <!-- 新增路线表单模态框 -->
+    <div class="modal-overlay" *ngIf="showCreateModal" (click)="closeModal()">
     <div class="create-modal" (click)="$event.stopPropagation()">
-      <div class="modal-header">
+        <div class="modal-header">
         <h3>创建新路线</h3>
         <ion-icon name="close" (click)="closeModal()"></ion-icon>
-      </div>
-      <div class="modal-body">
-        <div class="form-group">
-          <label>路线标题</label>
-          <input type="text" [(ngModel)]="newRouteData.title" placeholder="请输入路线标题">
         </div>
+
+        <div class="modal-body">
+        <!-- 路线名称 -->
         <div class="form-group">
-          <label>位置</label>
-          <input type="text" [(ngModel)]="newRouteData.location" placeholder="请输入位置">
+            <label>路线名称</label>
+            <input type="text" [(ngModel)]="newRouteData.title" placeholder="请输入路线名称" />
         </div>
+
+        <!-- 描述 -->
         <div class="form-group">
-          <label>预计时长</label>
-          <input type="text" [(ngModel)]="newRouteData.duration" placeholder="例如:3小时">
+            <label>描述</label>
+            <textarea [(ngModel)]="newRouteData.description" placeholder="请输入路线描述"></textarea>
         </div>
-        <div class="form-group">
-          <label>描述</label>
-          <textarea [(ngModel)]="newRouteData.description" placeholder="请输入路线描述"></textarea>
+
+        <!-- 长度和难度 行内排列 -->
+        <div class="form-row">
+            <div class="form-group half">
+            <label>长度(公里)</label>
+            <input type="number" step="0.1" [(ngModel)]="newRouteData.routelength" placeholder="8.5" />
+            </div>
+            <div class="form-group half">
+            <label>难度(1-5)</label>
+            <input type="number" min="1" max="5" [(ngModel)]="newRouteData.difficulty" />
+            </div>
         </div>
+
+        <!-- 常见鸟类 -->
+        <ion-item class="form-group">
+            <ion-label position="floating">常见鸟类</ion-label>
+            <ion-select multiple="true" [(ngModel)]="newRouteData.birds">
+            <ion-select-option *ngFor="let bird of birdTypes" [value]="bird.toPointer()">
+                {{ bird.get('name') }}
+            </ion-select-option>
+            </ion-select>
+        </ion-item>
+
+        <!-- 路线图片URL -->
         <div class="form-group">
-          <label>缩略图URL</label>
-          <input type="text" [(ngModel)]="newRouteData.thumbnail" 
-                 placeholder="https://example.com/image.jpg">
+            <label>路线图片URL</label>
+            <input type="text" [(ngModel)]="newRouteData.thumbnail" placeholder="https://example.com/image.jpg" />
         </div>
-      </div>
-      <div class="modal-footer">
+        </div>
+
+        <!-- 按钮区域 -->
+        <div class="modal-footer">
         <button class="cancel-btn" (click)="closeModal()">取消</button>
         <button class="confirm-btn" (click)="confirmCreate()">确定</button>
-      </div>
+        </div>
     </div>
-  </div>
-   <div class="container">
+    </div>
+  
+  <div class="container">
     <!-- 顶部导航栏 -->
     <div class="header">
       <div class="back-btn">
         <i class="iconfont icon-arrow-left"></i>
       </div>
-      <div class="title">路线推荐</div>
+      <div class="title">观鸟路线</div>
       <div style="width: 24px;"></div>
     </div>
 
@@ -58,49 +80,58 @@
 
     <!-- 路线推荐卡片 -->
     <div class="route-container">
-      <div class="route-card" *ngFor="let route of routes">
+    <div class="route-card" *ngFor="let route of routes">
         <div class="route-thumbnail" [style.background-image]="'url(' + route.get('thumbnail') + ')'"></div>
         <div class="route-info">
-          <div class="route-title">{{ route.get('title') }}</div>
-          <div class="route-actions">
+        <div class="route-title">{{ route.get('title') }}</div>
+        <div class="route-actions">
             <button class="delete-btn" (click)="deleteRoute(route)">删除</button>
-          </div>
-          <div class="route-rating">
+        </div>
+        <div class="route-rating">
             <span *ngFor="let star of getStars(route.get('rating'))">{{ star }}</span>
             <span class="rating-value">{{ route.get('rating')?.toFixed(1) || '0.0' }}</span>
-          </div>
-          
-          <div class="route-meta">
-            <span><i class="iconfont icon-location"></i>{{ route.get('location') }}</span>
+        </div>
+        
+        <div class="route-meta">
             <span><i class="iconfont icon-clock"></i>{{ route.get('duration') }}</span>
-            <span><i class="iconfont icon-eye"></i>{{ route.get('birdCount') }}种鸟类</span>
-          </div>
-          
-          <div class="route-description">
+            <span><i class="iconfont icon-ruler"></i>{{ route.get('routelength') }}公里</span>
+            <span><i class="iconfont icon-difficulty"></i>难度: {{ route.get('difficulty') }}/5</span>
+        </div>
+        
+        <div class="route-description">
             {{ route.get('description') || '暂无描述' }}
-          </div>
-          
-          <div class="birds-section" *ngIf="route.get('birds')?.length > 0">
-            <div class="section-title">
-              <i class="iconfont icon-bird"></i>
-              沿途鸟类
+        </div>
+        
+       <div class="birds-section" *ngIf="!isLoading">
+        <div class="section-title">
+        <i class="iconfont icon-bird"></i>
+        常见鸟类 ({{ getRouteBirds(route.id).length }}种)
+        </div>
+        
+        <div *ngIf="getRouteBirds(route.id).length === 0" class="no-birds">
+        暂无鸟类数据
+        </div>
+        
+        <div class="birds-grid" *ngIf="getRouteBirds(route.id).length > 0">
+        <div class="bird-item" *ngFor="let bird of getRouteBirds(route.id)">
+            <div class="bird-avatar" 
+                [style.background-image]="'url(' + (bird.get('image') || 'assets/default-bird.png') + ')'">
+            </div>
+            <div class="bird-name">
+                {{ bird.get('name') }}
+                <span class="protected-badge" *ngIf="bird.get('conservationStatus')">
+                {{ bird.get('conservationStatus') }}
+                </span>
             </div>
-            <div class="birds-grid">
-              <div class="bird-item" *ngFor="let bird of route.get('birds')">
-                <div class="bird-avatar" [style.background-image]="'url(' + bird.avatar + ')'"></div>
-                <div class="bird-name">
-                  {{ bird.name }}
-                  <span class="protected-badge" *ngIf="bird.protectionLevel">{{ bird.protectionLevel }}</span>
-                </div>
-              </div>
             </div>
-          </div>
-          
-          <div class="route-tags" *ngIf="route.get('tags')?.length > 0">
+        </div>
+        </div>
+        
+        <div class="route-tags" *ngIf="route.get('tags')?.length > 0">
             <span class="tag" *ngFor="let tag of route.get('tags')">{{ tag }}</span>
-          </div>
         </div>
-      </div>
+        </div>
+    </div>
     </div>
     
     <!-- 底部操作按钮 -->

+ 99 - 44
myapp/src/app/tab1/way/way.page.scss

@@ -240,68 +240,123 @@ body {
   left: 0;
   right: 0;
   bottom: 0;
-  background-color: rgba(0, 0, 0, 0.5);
+  background-color: rgba(0, 0, 0, 0.6);
   display: flex;
-  justify-content: center;
   align-items: center;
+  justify-content: center;
   z-index: 1000;
 }
 
 .create-modal {
-  background-color: white;
+  background-color: #fff;
+  border-radius: 12px;
   width: 90%;
   max-width: 500px;
-  border-radius: 10px;
-  padding: 20px;
+  overflow: hidden;
   box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
+  animation: fadeIn 0.3s ease-in-out;
 }
 
 .modal-header {
+  padding: 16px 24px;
   display: flex;
   justify-content: space-between;
   align-items: center;
-  margin-bottom: 20px;
-  
-  h3 {
-    margin: 0;
-    font-size: 18px;
-    color: #333;
-  }
-  
-  ion-icon {
-    font-size: 24px;
-    color: #999;
-    cursor: pointer;
-  }
+  background-color: #f7f7f7;
+  border-bottom: 1px solid #ddd;
+}
+
+.modal-header h3 {
+  margin: 0;
+  font-size: 1.2rem;
+  color: #333;
+}
+
+.modal-body {
+  padding: 20px 24px;
+  display: flex;
+  flex-direction: column;
+  gap: 16px;
 }
 
 .form-group {
-  margin-bottom: 15px;
-  
-  label {
-    display: block;
-    margin-bottom: 5px;
-    font-size: 14px;
-    color: #666;
-  }
-  
-  input, textarea {
-    width: 100%;
-    padding: 10px;
-    border: 1px solid #ddd;
-    border-radius: 5px;
-    font-size: 14px;
-    
-    &:focus {
-      outline: none;
-      border-color: #67c23a;
-    }
-  }
-  
-  textarea {
-    height: 80px;
-    resize: vertical;
-  }
+  display: flex;
+  flex-direction: column;
+  gap: 6px;
+}
+
+.form-row {
+  display: flex;
+  gap: 16px;
+}
+
+.form-row .half {
+  flex: 1;
+}
+
+label {
+  font-weight: 500;
+  font-size: 0.95rem;
+  color: #444;
+}
+
+input,
+textarea {
+  padding: 10px 12px;
+  border: 1px solid #ccc;
+  border-radius: 6px;
+  font-size: 1rem;
+  outline: none;
+  transition: border-color 0.2s ease-in-out;
+}
+
+input:focus,
+textarea:focus {
+  border-color: #0d6efd;
+}
+
+textarea {
+  resize: vertical;
+  min-height: 80px;
+}
+
+.modal-footer {
+  padding: 16px 24px;
+  background-color: #f9f9f9;
+  border-top: 1px solid #ddd;
+  display: flex;
+  justify-content: flex-end;
+  gap: 12px;
+}
+
+.cancel-btn,
+.confirm-btn {
+  padding: 10px 20px;
+  border: none;
+  border-radius: 6px;
+  font-size: 0.95rem;
+  cursor: pointer;
+  transition: background-color 0.2s ease-in-out;
+}
+
+.cancel-btn {
+  background-color: #e0e0e0;
+  color: #333;
+}
+
+.confirm-btn {
+  background-color: #0d6efd;
+  color: white;
+}
+
+.confirm-btn:hover {
+  background-color: #0b5ed7;
+}
+
+/* 动画效果 */
+@keyframes fadeIn {
+  from { opacity: 0; transform: scale(0.95); }
+  to { opacity: 1; transform: scale(1); }
 }
 
 .modal-footer {

+ 247 - 94
myapp/src/app/tab1/way/way.page.ts

@@ -1,5 +1,4 @@
 import { Component, OnInit } from '@angular/core';
-
 import { CloudObject, CloudQuery } from 'src/lib/ncloud';
 
 @Component({
@@ -11,24 +10,31 @@ import { CloudObject, CloudQuery } from 'src/lib/ncloud';
 export class WayPage implements OnInit {
 
   routes:CloudObject[]=[];
+  birdTypes: CloudObject[] = [];
   isLoading: boolean = false;
   showCreateModal: boolean = false;
   newRouteData: any = {
-    title: '',
-    location: '',
-    duration: '',
-    description: '',
-    thumbnail: '',
-    birdCount: 0,
-    rating: 0,
-    birds: [],
-    tags: []
-  };
+  title: '',
+  description: '',
+  routelength: null, // 数字类型
+  difficulty: null,
+  thumbnail: '',
+  bestMonths: [],
+  startPoint: '',
+  endPoint: '',
+  facilities: [],
+  rating: 0,
+  birdCount: 0,
+  birds: [],       // BirdType 的 Pointer 数组
+  featureTags: [], // 字符串数组
+  region: null     // Region 的 Pointer 对象
+};
 
   constructor() { }
 
   ngOnInit() {
     this.loadRoutes();
+    this.loadBirdTypes();
   }
   // 显示创建表单
   showCreateForm() {
@@ -51,34 +57,56 @@ export class WayPage implements OnInit {
       birdCount: 0,
       rating: 0,
       birds: [],
-      tags: []
+      featureTags: []
     };
   }
 
-  // 确认创建
   async confirmCreate() {
-    if (!this.newRouteData.title || !this.newRouteData.location) {
-      alert('请填写标题和位置');
-      return;
-    }
+  if (!this.newRouteData.title) {
+    alert('请填写标题');
+    return;
+  }
 
-    try {
-      const newRoute = new CloudObject("Route");
-      newRoute.set({
-        ...this.newRouteData,
-        thumbnail: this.newRouteData.thumbnail || 
-                 `https://picsum.photos/600/400?random=${Math.floor(Math.random() * 1000)}`
-      });
-      
-      await newRoute.save();
-      this.closeModal();
-      await this.loadRoutes();
-      console.log('路线创建成功');
-    } catch (error) {
-      console.error('创建路线失败', error);
-      alert('创建路线失败,请重试');
+  try {
+    // 创建鸟类指针数组
+    const birdPointers = [];
+    for (const birdId of this.newRouteData.birds) {
+      const birdQuery = new CloudQuery("BirdType");
+      birdQuery.equalTo("objectId", birdId);
+      const bird = await birdQuery.first();
+      if (bird) {
+        birdPointers.push(bird.toPointer());
+      }
     }
+
+    const newRoute = new CloudObject("Route");
+    newRoute.set({
+      title: this.newRouteData.title,
+      description: this.newRouteData.description || '',
+      length: parseFloat(this.newRouteData.routelength) || 0,
+      difficulty: parseInt(this.newRouteData.difficulty) || 0,
+      thumbnail: this.newRouteData.thumbnail || 
+               `https://picsum.photos/600/400?random=${Math.floor(Math.random() * 1000)}`,
+      bestMonths: Array.isArray(this.newRouteData.bestMonths) ? this.newRouteData.bestMonths : [],
+      startPoint: this.newRouteData.startPoint || '',
+      endPoint: this.newRouteData.endPoint || '',
+      facilities: Array.isArray(this.newRouteData.facilities) ? this.newRouteData.facilities : [],
+      rating: parseFloat(this.newRouteData.rating) || 0,
+      birdCount: birdPointers.length,
+      birds: birdPointers,
+      tags: this.newRouteData.featureTags || [],
+      region: this.newRouteData.region || null
+    });
+
+    await newRoute.save();
+    this.closeModal();
+    await this.loadRoutes();
+    console.log('路线创建成功');
+  } catch (error) {
+    console.error('创建路线失败', error);
+    alert('创建路线失败,请重试');
   }
+}
 
   // 删除路线
   async deleteRoute(route: CloudObject) {
@@ -95,17 +123,51 @@ export class WayPage implements OnInit {
       alert('删除路线失败,请重试');
     }
   }
-  async loadRoutes() {
-    this.isLoading = true;
-    try {
-      let query = new CloudQuery("Route");
-      this.routes = await query.find();
-      console.log("路线数据加载完成", this.routes);
-    } catch (error) {
-      console.error("加载路线数据失败", error);
-    } finally {
-      this.isLoading = false;
-    }
+
+  // 在组件类中添加
+routeDetailedBirdsMap = new Map<string, CloudObject[]>(); // 存储路线ID到鸟类数组的映射
+
+async loadRoutes() {
+  this.isLoading = true;
+  try {
+    let query = new CloudQuery("Route");
+    query.include("birds"); // 如果birds是指针数组,可能需要这个
+    
+    const routes: CloudObject[] = await query.find();
+    this.routeDetailedBirdsMap.clear(); // 清空旧数据
+    
+    // 并行获取所有路线的鸟类数据
+    await Promise.all(routes.map(async route => {
+      const detailedBirds = [];
+      const birdPointers = route.get('birds') || [];
+      
+      for (const birdPointer of birdPointers) {
+        const birdQuery = new CloudQuery("BirdType");
+        birdQuery.equalTo("objectId", birdPointer.objectId);
+        const bird = await birdQuery.first();
+        if (bird) detailedBirds.push(bird);
+      }
+      
+      this.routes.forEach(route => {
+    if (!route.id) return;
+    this.routeDetailedBirdsMap.set(route.id, this.routeDetailedBirdsMap.get(route.id) || []);
+  });
+    }));
+    
+    this.routes = [...routes];
+  } catch (error) {
+    console.error("加载路线数据失败", error);
+  } finally {
+    this.isLoading = false;
+  }
+}
+
+// 添加辅助方法
+getRouteBirds(routeId: string | undefined): CloudObject[] {
+    if (!routeId) return [];
+    const birds = this.routeDetailedBirdsMap.get(routeId);
+    console.log(`获取路线 ${routeId} 的鸟类:`, birds);
+    return birds || [];
   }
 
   getStars(rating: number): string[] {
@@ -121,68 +183,150 @@ export class WayPage implements OnInit {
   }
 
   async importSampleRoutes() {
-    const routeDataset = [
-      {
-        title: "鄱阳湖冬季候鸟观赏路线",
-        location: "江西九江",
-        duration: "3小时",
-        birdCount: 23,
-        rating: 4.5,
-        thumbnail: "https://picsum.photos/600/400?random=101",
-        description: "冬季观赏候鸟的最佳路线,可观察到多种珍稀候鸟",
-        birds: [
-          { name: "白鹤", avatar: "https://picsum.photos/100/100?random=1", protectionLevel: "一级" },
-          { name: "小天鹅", avatar: "https://picsum.photos/100/100?random=2" },
-          { name: "东方白鹳", avatar: "https://picsum.photos/100/100?random=3", protectionLevel: "一级" }
-        ],
-        tags: ["冬季", "候鸟", "湿地"]
+  const routeDataset = [
+    {
+      name: "鄱阳湖冬季候鸟观赏路线",
+      description: "冬季观赏候鸟的最佳路线,可观察到多种珍稀候鸟",
+      routelength: 8.5,
+      difficulty: 3,
+      estimatedTime: 3,
+      bestMonths: ["12", "1", "2"],
+      startPoint: "鄱阳湖东门入口",
+      endPoint: "观鸟塔",
+      rating: 4.5,
+      facilities: ["观鸟塔", "休息区", "停车场"],
+      routeImage: "https://picsum.photos/600/400?random=101",
+      popularity: 85,
+      region: {
+        name: "鄱阳湖自然保护区",
+        description: "中国最大的淡水湖,冬季候鸟重要栖息地",
+        climate: "亚热带湿润气候",
+        terrain: "湿地",
+        areaSize: 4125,
+        bestSeason: "冬季",
+        featureTags: ["湿地", "候鸟", "自然保护区"],
+        mapImage: "https://picsum.photos/600/400?random=201",
+        popularity: 90
       },
-      {
-        title: "庐山森林鸟类观察路线",
-        location: "江西九江",
-        duration: "5小时",
-        birdCount: 18,
-        rating: 4.2,
-        thumbnail: "https://picsum.photos/600/400?random=102",
-        description: "穿越庐山森林,观察多种留鸟和森林鸟类",
-        birds: [
-          { name: "白鹇", avatar: "https://picsum.photos/100/100?random=7", protectionLevel: "二级" },
-          { name: "红嘴相思鸟", avatar: "https://picsum.photos/100/100?random=8" },
-          { name: "画眉", avatar: "https://picsum.photos/100/100?random=9" }
-        ],
-        tags: ["森林", "留鸟", "山地"]
-      }
-    ];
+      commonBirds: [
+        { 
+          name: "红嘴相思鸟"
+        },
+        { 
+          name: "白鹭"
+        }
+      ]
+    },
+    {
+      name: "庐山森林鸟类观察路线",
+      description: "穿越庐山森林,观察多种留鸟和森林鸟类",
+      routelength: 12.3,
+      difficulty: 4,
+      estimatedTime: 5,
+      bestMonths: ["4", "5", "9", "10"],
+      startPoint: "庐山植物园",
+      endPoint: "五老峰",
+      rating: 4.2,
+      facilities: ["休息区", "观景台"],
+      routeImage: "https://picsum.photos/600/400?random=102",
+      popularity: 75,
+      region: {
+        name: "庐山国家公园",
+        description: "世界文化遗产地,森林覆盖率高",
+        climate: "山地气候",
+        terrain: "山地",
+        areaSize: 302,
+        bestSeason: "春秋季",
+        featureTags: ["森林", "山地", "世界遗产"],
+        mapImage: "https://picsum.photos/600/400?random=202",
+        popularity: 85
+      },
+      commonBirds: [
+        { 
+          name: "红腹锦鸡"
+        },
+        { 
+          name: "黑脸琵鹭"
+        }
+      ]
+    }
+  ];
 
-    const query = new CloudQuery("Route");
+  for (const routeData of routeDataset) {
+    try {
+      // 检查是否已存在同名路线
+      const routeQuery = new CloudQuery("Route");
+      routeQuery.equalTo("title", routeData.name);
+      const existingRoute = await routeQuery.first();
 
-    for (const route of routeDataset) {
-      try {
-        // 检查是否已存在同名路线
-        query.equalTo("title", route.title);
-        const existing = await query.first();
+      if (existingRoute) {
+        console.log(`路线"${routeData.name}"已存在,跳过保存`);
+        continue;
+      }
 
-        if (existing) {
-          console.log(`路线"${route.title}"已存在,跳过保存`);
-          continue;
+      // 创建或获取Region
+      let regionPointer = null;
+      if (routeData.region) {
+        const regionQuery = new CloudQuery("Region");
+        regionQuery.equalTo("name", routeData.region.name);
+        let region = await regionQuery.first();
+        
+        if (!region) {
+          region = new CloudObject("Region");
+          region.set(routeData.region);
+          await region.save();
         }
+        regionPointer = region.toPointer();
+      }
 
-        // 创建新路线对象
-        const newRoute = new CloudObject("Route");
-        newRoute.set(route);
+      // 创建CommonBirds指针数组
+      const birdPointers = [];
+      for (const birdData of routeData.commonBirds) {
+        const birdQuery = new CloudQuery("BirdType");
+        birdQuery.equalTo("name", birdData.name);
+        let bird = await birdQuery.first();
         
-        // 保存到数据库
-        await newRoute.save();
-        console.log(`路线"${route.title}"保存成功`);
-      } catch (error) {
-        console.error(`保存路线"${route.title}"时出错`, error);
+        if (bird) {
+          birdPointers.push(bird.toPointer());
+        } else {
+          console.warn(`未找到鸟类: ${birdData.name}`);
+        }
       }
-    }
 
-    console.log("所有路线数据处理完成");
-    await this.loadRoutes(); // 刷新列表
+      // 创建新路线对象
+      const newRoute = new CloudObject("Route");
+      newRoute.set({
+        title: routeData.name,
+        location: routeData.region?.name || routeData.startPoint,
+        duration: `${routeData.estimatedTime}小时`,
+        description: routeData.description,
+        thumbnail: routeData.routeImage,
+        birdCount: routeData.commonBirds?.length || 0,
+        rating: routeData.rating,
+        birds: birdPointers,
+        tags: routeData.region?.featureTags || [],
+        region: regionPointer,
+        routelength: routeData.routelength,
+        difficulty: routeData.difficulty,
+        bestMonths: routeData.bestMonths,
+        startPoint: routeData.startPoint,
+        endPoint: routeData.endPoint,
+        facilities: routeData.facilities,
+        popularity: routeData.popularity
+      });
+      
+      // 保存到数据库
+      await newRoute.save();
+      console.log(`路线"${routeData.name}"保存成功`);
+    } catch (error) {
+      console.error(`保存路线"${routeData.name}"时出错`, error);
+    }
   }
 
+  console.log("所有路线数据处理完成");
+  await this.loadRoutes(); // 刷新列表
+}
+
   async handleUploadClick() {
     const newRoute = new CloudObject("Route");
     newRoute.set({
@@ -204,4 +348,13 @@ export class WayPage implements OnInit {
       console.error('创建路线失败', error);
     }
   }
+  async loadBirdTypes() {
+  try {
+    const query = new CloudQuery("BirdType");
+    this.birdTypes = await query.find();
+    console.log("鸟类数据加载成功", this.birdTypes);
+  } catch (error) {
+    console.error("加载鸟类数据失败", error);
+  }
+}
 }

+ 1 - 1
myapp/src/lib/ncloud.ts

@@ -20,7 +20,7 @@ export class CloudObject {
         return { "__type": "Pointer", "className": this.className, "objectId": this.id };
     }
 
-    set(json: Record<string, any>) {
+   set(json: Record<string, any>) {
         Object.keys(json).forEach(key => {
             if (["objectId", "id", "createdAt", "updatedAt"].indexOf(key) > -1) {
                 return;