|
@@ -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);
|
|
|
+ }
|
|
|
+}
|
|
|
}
|