悦 陈 1 тиждень тому
батько
коміт
c6a74a418a

+ 94 - 125
myapp/src/app/tab1/way/way.page.html

@@ -5,144 +5,113 @@
 </ion-header>
 
 <ion-content [fullscreen]="true">
-  <div class="container">
+     <!-- 新增路线表单模态框 -->
+  <div class="modal-overlay" *ngIf="showCreateModal" (click)="closeModal()">
+    <div class="create-modal" (click)="$event.stopPropagation()">
+      <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="form-group">
+          <label>位置</label>
+          <input type="text" [(ngModel)]="newRouteData.location" placeholder="请输入位置">
+        </div>
+        <div class="form-group">
+          <label>预计时长</label>
+          <input type="text" [(ngModel)]="newRouteData.duration" placeholder="例如:3小时">
+        </div>
+        <div class="form-group">
+          <label>描述</label>
+          <textarea [(ngModel)]="newRouteData.description" placeholder="请输入路线描述"></textarea>
+        </div>
+        <div class="form-group">
+          <label>缩略图URL</label>
+          <input type="text" [(ngModel)]="newRouteData.thumbnail" 
+                 placeholder="https://example.com/image.jpg">
+        </div>
+      </div>
+      <div class="modal-footer">
+        <button class="cancel-btn" (click)="closeModal()">取消</button>
+        <button class="confirm-btn" (click)="confirmCreate()">确定</button>
+      </div>
+    </div>
+  </div>
+   <div class="container">
     <!-- 顶部导航栏 -->
     <div class="header">
-        <div class="back-btn">
-            <i class="iconfont icon-arrow-left"></i>
-        </div>
-        <div class="title">路线推荐</div>
-        <div style="width: 24px;"></div>
+      <div class="back-btn">
+        <i class="iconfont icon-arrow-left"></i>
+      </div>
+      <div class="title">路线推荐</div>
+      <div style="width: 24px;"></div>
     </div>
-    
+
+    <!-- 加载状态指示 -->
+    <div *ngIf="isLoading" class="loading-indicator">
+      加载中...
+    </div>
+
     <!-- 路线推荐卡片 -->
     <div class="route-container">
-        <!-- 路线1 -->
-        <div class="route-card">
-            <div class="route-thumbnail" style="background-image: url('https://picsum.photos/600/400?random=101');">
-                <!-- 可以在缩略图上叠加路线标记 -->
+      <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">
+            <button class="delete-btn" (click)="deleteRoute(route)">删除</button>
+          </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>
+            <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">
+            {{ 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="route-info">
-                <div class="route-title">鄱阳湖冬季候鸟观赏路线</div>
-                <div class="route-meta">
-                    <span><i class="iconfont icon-location"></i>江西九江</span>
-                    <span><i class="iconfont icon-clock"></i>3小时</span>
-                    <span><i class="iconfont icon-eye"></i>23种鸟类</span>
-                </div>
-                
-                <div class="birds-section">
-                    <div class="section-title">
-                        <i class="iconfont icon-bird"></i>
-                        沿途鸟类
-                    </div>
-                    <div class="birds-grid">
-                        <div class="bird-item">
-                            <div class="bird-avatar" style="background-image: url('https://picsum.photos/100/100?random=1');"></div>
-                            <div class="bird-name">白鹤<span class="protected-badge">一级</span></div>
-                        </div>
-                        <div class="bird-item">
-                            <div class="bird-avatar" style="background-image: url('https://picsum.photos/100/100?random=2');"></div>
-                            <div class="bird-name">小天鹅</div>
-                        </div>
-                        <div class="bird-item">
-                            <div class="bird-avatar" style="background-image: url('https://picsum.photos/100/100?random=3');"></div>
-                            <div class="bird-name">东方白鹳<span class="protected-badge">一级</span></div>
-                        </div>
-                        <div class="bird-item">
-                            <div class="bird-avatar" style="background-image: url('https://picsum.photos/100/100?random=4');"></div>
-                            <div class="bird-name">鸿雁</div>
-                        </div>
-                        <div class="bird-item">
-                            <div class="bird-avatar" style="background-image: url('https://picsum.photos/100/100?random=5');"></div>
-                            <div class="bird-name">白琵鹭</div>
-                        </div>
-                        <div class="bird-item">
-                            <div class="bird-avatar" style="background-image: url('https://picsum.photos/100/100?random=6');"></div>
-                            <div class="bird-name">灰鹤</div>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </div>
-        
-        <!-- 路线2 -->
-        <div class="route-card">
-            <div class="route-thumbnail" style="background-image: url('https://picsum.photos/600/400?random=102');"></div>
-            <div class="route-info">
-                <div class="route-title">庐山森林鸟类观察路线</div>
-                <div class="route-meta">
-                    <span><i class="iconfont icon-location"></i>江西九江</span>
-                    <span><i class="iconfont icon-clock"></i>5小时</span>
-                    <span><i class="iconfont icon-eye"></i>18种鸟类</span>
-                </div>
-                
-                <div class="birds-section">
-                    <div class="section-title">
-                        <i class="iconfont icon-bird"></i>
-                        沿途鸟类
-                    </div>
-                    <div class="birds-grid">
-                        <div class="bird-item">
-                            <div class="bird-avatar" style="background-image: url('https://picsum.photos/100/100?random=7');"></div>
-                            <div class="bird-name">白鹇<span class="protected-badge">二级</span></div>
-                        </div>
-                        <div class="bird-item">
-                            <div class="bird-avatar" style="background-image: url('https://picsum.photos/100/100?random=8');"></div>
-                            <div class="bird-name">红嘴相思鸟</div>
-                        </div>
-                        <div class="bird-item">
-                            <div class="bird-avatar" style="background-image: url('https://picsum.photos/100/100?random=9');"></div>
-                            <div class="bird-name">画眉</div>
-                        </div>
-                        <div class="bird-item">
-                            <div class="bird-avatar" style="background-image: url('https://picsum.photos/100/100?random=10');"></div>
-                            <div class="bird-name">松鸦</div>
-                        </div>
-                        <div class="bird-item">
-                            <div class="bird-avatar" style="background-image: url('https://picsum.photos/100/100?random=11');"></div>
-                            <div class="bird-name">红嘴蓝鹊</div>
-                        </div>
-                        <div class="bird-item">
-                            <div class="bird-avatar" style="background-image: url('https://picsum.photos/100/100?random=12');"></div>
-                            <div class="bird-name">黑脸噪鹛</div>
-                        </div>
-                    </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">
+            <span class="tag" *ngFor="let tag of route.get('tags')">{{ tag }}</span>
+          </div>
         </div>
+      </div>
     </div>
     
     <!-- 底部操作按钮 -->
     <div class="action-buttons">
-        <div class="action-btn select-btn">
-            <i class="iconfont icon-select"></i> 路线选择
-        </div>
-        <div class="action-btn upload-btn">
-            <i class="iconfont icon-upload"></i> 路线上传
-        </div>
+      <div class="action-btn select-btn" (click)="importSampleRoutes()">
+        <i class="iconfont icon-select"></i> 导入示例
+      </div>
+      <div class="action-btn upload-btn" (click)="showCreateForm()">
+        <i class="iconfont icon-upload"></i> 创建路线
+      </div>
     </div>
-</div>
+  </div>
 
-<script>
-    // 简单的交互逻辑
-    document.querySelector('.back-btn').addEventListener('click', function() {
-        alert('返回上一页');
-    });
-    
-    document.querySelector('.select-btn').addEventListener('click', function() {
-        alert('打开路线选择筛选器');
-    });
-    
-    document.querySelector('.upload-btn').addEventListener('click', function() {
-        alert('打开路线上传页面');
-    });
-    
-    // 鸟类头像点击效果
-    document.querySelectorAll('.bird-avatar').forEach(avatar => {
-        avatar.addEventListener('click', function() {
-            const birdName = this.nextElementSibling.textContent;
-            alert(`查看${birdName}的详细信息`);
-        });
-    });
-</script>
 </ion-content>

+ 164 - 0
myapp/src/app/tab1/way/way.page.scss

@@ -54,6 +54,7 @@ body {
     box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);
     overflow: hidden;
     margin-bottom: 15px;
+    position: relative;
 }
 
 /* 路线缩略图 */
@@ -183,3 +184,166 @@ body {
     background-color: #67c23a;
     color: white;
 }
+
+.loading-indicator {
+  text-align: center;
+  padding: 20px;
+  color: #666;
+}
+
+.route-rating {
+  margin: 8px 0;
+  color: #ffc107;
+  font-size: 16px;
+  
+  .rating-value {
+    color: #666;
+    font-size: 14px;
+    margin-left: 5px;
+  }
+}
+
+.route-description {
+  font-size: 14px;
+  color: #666;
+  margin: 10px 0;
+  line-height: 1.4;
+}
+
+.route-tags {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 5px;
+  margin-top: 10px;
+  
+  .tag {
+    background-color: #e8f5e9;
+    color: #2e7d32;
+    padding: 3px 8px;
+    border-radius: 10px;
+    font-size: 12px;
+  }
+}
+
+/* 鸟类头像点击效果 */
+.bird-avatar {
+  cursor: pointer;
+  transition: transform 0.2s;
+  
+  &:hover {
+    transform: scale(1.05);
+  }
+}
+.modal-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background-color: rgba(0, 0, 0, 0.5);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  z-index: 1000;
+}
+
+.create-modal {
+  background-color: white;
+  width: 90%;
+  max-width: 500px;
+  border-radius: 10px;
+  padding: 20px;
+  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
+}
+
+.modal-header {
+  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;
+  }
+}
+
+.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;
+  }
+}
+
+.modal-footer {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 20px;
+  
+  button {
+    padding: 8px 15px;
+    border-radius: 5px;
+    font-size: 14px;
+    cursor: pointer;
+    border: none;
+    
+    &.cancel-btn {
+      background-color: #f5f5f5;
+      color: #666;
+      margin-right: 10px;
+    }
+    
+    &.confirm-btn {
+      background-color: #67c23a;
+      color: white;
+    }
+  }
+}
+
+.route-actions {
+  position: absolute;
+  top: 10px;
+  right: 10px;
+  
+  .delete-btn {
+    background-color: #f56c6c;
+    color: white;
+    border: none;
+    padding: 5px 10px;
+    border-radius: 4px;
+    font-size: 12px;
+    cursor: pointer;
+    &:hover {
+    background-color: #e65151;
+  }
+}
+}

+ 191 - 0
myapp/src/app/tab1/way/way.page.ts

@@ -1,5 +1,7 @@
 import { Component, OnInit } from '@angular/core';
 
+import { CloudObject, CloudQuery } from 'src/lib/ncloud';
+
 @Component({
   selector: 'app-way',
   templateUrl: './way.page.html',
@@ -8,9 +10,198 @@ import { Component, OnInit } from '@angular/core';
 })
 export class WayPage implements OnInit {
 
+  routes:CloudObject[]=[];
+  isLoading: boolean = false;
+  showCreateModal: boolean = false;
+  newRouteData: any = {
+    title: '',
+    location: '',
+    duration: '',
+    description: '',
+    thumbnail: '',
+    birdCount: 0,
+    rating: 0,
+    birds: [],
+    tags: []
+  };
+
   constructor() { }
 
   ngOnInit() {
+    this.loadRoutes();
+  }
+  // 显示创建表单
+  showCreateForm() {
+    this.showCreateModal = true;
+  }
+
+  // 关闭模态框
+  closeModal() {
+    this.showCreateModal = false;
+    this.resetForm();
+  }
+  // 重置表单
+  resetForm() {
+    this.newRouteData = {
+      title: '',
+      location: '',
+      duration: '',
+      description: '',
+      thumbnail: '',
+      birdCount: 0,
+      rating: 0,
+      birds: [],
+      tags: []
+    };
+  }
+
+  // 确认创建
+  async confirmCreate() {
+    if (!this.newRouteData.title || !this.newRouteData.location) {
+      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('创建路线失败,请重试');
+    }
+  }
+
+  // 删除路线
+  async deleteRoute(route: CloudObject) {
+    if (!confirm('确定要删除这条路线吗?')) {
+      return;
+    }
+
+    try {
+      await route.destroy();
+      this.routes = this.routes.filter(r => r.id !== route.id);
+      console.log('路线删除成功');
+    } catch (error) {
+      console.error('删除路线失败', error);
+      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;
+    }
+  }
+
+  getStars(rating: number): string[] {
+    const fullStars = Math.floor(rating);
+    const halfStar = rating % 1 >= 0.5 ? 1 : 0;
+    const emptyStars = 5 - fullStars - halfStar;
+
+    return [
+      ...Array(fullStars).fill('★'),
+      ...(halfStar ? ['½'] : []),
+      ...Array(emptyStars).fill('☆')
+    ];
+  }
+
+  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: ["冬季", "候鸟", "湿地"]
+      },
+      {
+        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: ["森林", "留鸟", "山地"]
+      }
+    ];
+
+    const query = new CloudQuery("Route");
 
+    for (const route of routeDataset) {
+      try {
+        // 检查是否已存在同名路线
+        query.equalTo("title", route.title);
+        const existing = await query.first();
+
+        if (existing) {
+          console.log(`路线"${route.title}"已存在,跳过保存`);
+          continue;
+        }
+
+        // 创建新路线对象
+        const newRoute = new CloudObject("Route");
+        newRoute.set(route);
+        
+        // 保存到数据库
+        await newRoute.save();
+        console.log(`路线"${route.title}"保存成功`);
+      } catch (error) {
+        console.error(`保存路线"${route.title}"时出错`, error);
+      }
+    }
+
+    console.log("所有路线数据处理完成");
+    await this.loadRoutes(); // 刷新列表
+  }
+
+  async handleUploadClick() {
+    const newRoute = new CloudObject("Route");
+    newRoute.set({
+      title: "新建路线",
+      location: "未设置位置",
+      duration: "0小时",
+      birdCount: 0,
+      rating: 0,
+      thumbnail: "https://picsum.photos/600/400?random=" + Math.floor(Math.random() * 1000),
+      birds: [],
+      tags: []
+    });
+    
+    try {
+      await newRoute.save();
+      await this.loadRoutes();
+      console.log('路线已创建并保存!');
+    } catch (error) {
+      console.error('创建路线失败', error);
+    }
+  }
 }