Browse Source

✨ feat(route): 增强路线地区信息展示与空状态优化

- 后端添加路线起点和终点的省市区详细信息返回
- 前端实现地区名称拼接逻辑,显示完整省市区信息
- 优化加载中和活动为空状态的UI展示,增加表情符号和更友好提示文本
- 更新活动匹配说明文字,更准确反映系统功能

🐛 fix(route): 修复路线查询和数据处理问题

- 修改路线查询构建方式,显式连接省市区表获取完整地区信息
- 修复排序逻辑实现,确保价格和时间排序正确应用
- 优化路线数据处理流程,提高地区信息准确性
yourname 3 months ago
parent
commit
e1fdc40de8

+ 58 - 14
mini/src/pages/select-activity/ActivitySelectPage.tsx

@@ -109,6 +109,48 @@ const ActivitySelectPage: React.FC = () => {
 
   const activities = routeData?.activities || []
 
+  // 从路线数据中获取地区名称
+  const getAreaNames = () => {
+    if (!routeData?.routes || routeData.routes.length === 0) {
+      return { startAreaName: '出发地', endAreaName: '目的地' }
+    }
+
+    // 从第一条路线中获取出发地和目的地的地区信息
+    const firstRoute = routeData.routes[0]
+    const startLocation = firstRoute.startLocation
+    const endLocation = firstRoute.endLocation
+
+    const getAreaDisplayName = (location: any) => {
+      if (!location) return ''
+
+      // 显示完整的省市区信息
+      const parts: string[] = []
+      if (location.province?.name) {
+        parts.push(location.province.name)
+      }
+      if (location.city?.name) {
+        parts.push(location.city.name)
+      }
+      if (location.district?.name) {
+        parts.push(location.district.name)
+      }
+
+      // 如果都没有,则使用location.name
+      if (parts.length === 0 && location.name) {
+        parts.push(location.name)
+      }
+
+      return parts.join('') || ''
+    }
+
+    return {
+      startAreaName: getAreaDisplayName(startLocation) || '出发地',
+      endAreaName: getAreaDisplayName(endLocation) || '目的地'
+    }
+  }
+
+  const areaNames = getAreaNames()
+
   // 分离去程和返程活动
   const departureActivities = (activities as Activity[])
     .filter((activity: Activity) => activity.type === 'departure')
@@ -151,21 +193,20 @@ const ActivitySelectPage: React.FC = () => {
     }
   }
 
-  // 获取路线信息显示
-  const getRouteInfo = () => {
-    // 这里可以根据省市区ID获取地区名称,暂时使用默认值
-    return {
-      fromCity: '出发地',
-      toCity: '目的地'
-    }
+  // 使用获取到的地区名称
+  const routeInfo = {
+    fromCity: areaNames.startAreaName,
+    toCity: areaNames.endAreaName
   }
 
-  const routeInfo = getRouteInfo()
-
   if (isLoading) {
     return (
       <View className="min-h-screen bg-gray-50 flex items-center justify-center">
-        <Text className="text-gray-500">加载中...</Text>
+        <View className="text-center">
+          <Text className="text-4xl mb-4">⏳</Text>
+          <Text className="text-lg text-gray-600 block mb-2">正在加载活动</Text>
+          <Text className="text-sm text-gray-500">请稍候...</Text>
+        </View>
       </View>
     )
   }
@@ -182,14 +223,13 @@ const ActivitySelectPage: React.FC = () => {
         </Text>
       </View>
 
-
       <ScrollView className="flex-1">
         <View className="p-4">
           <Text className="text-lg font-bold text-gray-800 mb-2 block">
             选择观看活动
           </Text>
           <Text className="text-sm text-gray-500 mb-4 block">
-            系统已为您自动匹配出发地和目的地的热门活动
+            系统已根据您选择的地区自动匹配相关活动
           </Text>
 
           {/* 去程活动区域 */}
@@ -249,7 +289,9 @@ const ActivitySelectPage: React.FC = () => {
               </View>
             ) : (
               <View className="bg-white rounded-b-lg border border-gray-200 p-8 text-center">
-                <Text className="text-gray-500">{routeInfo.toCity}暂无活动</Text>
+                <Text className="text-4xl mb-4">🎭</Text>
+                <Text className="text-lg text-gray-600 block mb-2">暂无去程活动</Text>
+                <Text className="text-sm text-gray-500">{routeInfo.toCity}当前没有相关活动</Text>
               </View>
             )}
           </View>
@@ -311,7 +353,9 @@ const ActivitySelectPage: React.FC = () => {
               </View>
             ) : (
               <View className="bg-white rounded-b-lg border border-gray-200 p-8 text-center">
-                <Text className="text-gray-500">{routeInfo.fromCity}暂无活动</Text>
+                <Text className="text-4xl mb-4">🎭</Text>
+                <Text className="text-lg text-gray-600 block mb-2">暂无返程活动</Text>
+                <Text className="text-sm text-gray-500">{routeInfo.fromCity}当前没有相关活动</Text>
               </View>
             )}
           </View>

+ 74 - 2
src/server/api/routes/index.ts

@@ -72,7 +72,43 @@ const routeSearchResultSchema = z.object({
         provinceId: z.number(),
         cityId: z.number(),
         districtId: z.number(),
-        address: z.string()
+        address: z.string(),
+        province: z.object({
+          id: z.number(),
+          name: z.string(),
+          level: z.number(),
+          code: z.string(),
+          isDisabled: z.number(),
+          isDeleted: z.number(),
+          createdBy: z.number().nullable(),
+          updatedBy: z.number().nullable(),
+          createdAt: z.string(),
+          updatedAt: z.string()
+        }).nullable(),
+        city: z.object({
+          id: z.number(),
+          name: z.string(),
+          level: z.number(),
+          code: z.string(),
+          isDisabled: z.number(),
+          isDeleted: z.number(),
+          createdBy: z.number().nullable(),
+          updatedBy: z.number().nullable(),
+          createdAt: z.string(),
+          updatedAt: z.string()
+        }).nullable(),
+        district: z.object({
+          id: z.number(),
+          name: z.string(),
+          level: z.number(),
+          code: z.string(),
+          isDisabled: z.number(),
+          isDeleted: z.number(),
+          createdBy: z.number().nullable(),
+          updatedBy: z.number().nullable(),
+          createdAt: z.string(),
+          updatedAt: z.string()
+        }).nullable()
       }),
       endLocation: z.object({
         id: z.number(),
@@ -80,7 +116,43 @@ const routeSearchResultSchema = z.object({
         provinceId: z.number(),
         cityId: z.number(),
         districtId: z.number(),
-        address: z.string()
+        address: z.string(),
+        province: z.object({
+          id: z.number(),
+          name: z.string(),
+          level: z.number(),
+          code: z.string(),
+          isDisabled: z.number(),
+          isDeleted: z.number(),
+          createdBy: z.number().nullable(),
+          updatedBy: z.number().nullable(),
+          createdAt: z.string(),
+          updatedAt: z.string()
+        }).nullable(),
+        city: z.object({
+          id: z.number(),
+          name: z.string(),
+          level: z.number(),
+          code: z.string(),
+          isDisabled: z.number(),
+          isDeleted: z.number(),
+          createdBy: z.number().nullable(),
+          updatedBy: z.number().nullable(),
+          createdAt: z.string(),
+          updatedAt: z.string()
+        }).nullable(),
+        district: z.object({
+          id: z.number(),
+          name: z.string(),
+          level: z.number(),
+          code: z.string(),
+          isDisabled: z.number(),
+          isDeleted: z.number(),
+          createdBy: z.number().nullable(),
+          updatedBy: z.number().nullable(),
+          createdAt: z.string(),
+          updatedAt: z.string()
+        }).nullable()
       }),
       pickupPoint: z.string(),
       dropoffPoint: z.string(),

+ 23 - 10
src/server/modules/routes/route.service.ts

@@ -107,16 +107,29 @@ export class RouteService extends GenericCrudService<RouteEntity> {
       order.departureTime = sortOrder;
     }
 
-    // 获取路线列表
-    const [routes, total] = await this.getList(
-      page,
-      pageSize,
-      undefined,
-      undefined,
-      where,
-      ['startLocation', 'endLocation', 'activity'],
-      order
-    );
+    // 获取路线列表 - 直接使用查询构建器避免关联关系冲突
+    const query = this.repository.createQueryBuilder('route')
+      .leftJoinAndSelect('route.startLocation', 'startLocation')
+      .leftJoinAndSelect('startLocation.province', 'startLocation_province')
+      .leftJoinAndSelect('startLocation.city', 'startLocation_city')
+      .leftJoinAndSelect('startLocation.district', 'startLocation_district')
+      .leftJoinAndSelect('route.endLocation', 'endLocation')
+      .leftJoinAndSelect('endLocation.province', 'endLocation_province')
+      .leftJoinAndSelect('endLocation.city', 'endLocation_city')
+      .leftJoinAndSelect('endLocation.district', 'endLocation_district')
+      .leftJoinAndSelect('route.activity', 'activity')
+      .where(where)
+      .skip((page - 1) * pageSize)
+      .take(pageSize);
+
+    // 添加排序
+    if (sortBy === 'price') {
+      query.orderBy('route.price', sortOrder);
+    } else {
+      query.orderBy('route.departureTime', sortOrder);
+    }
+
+    const [routes, total] = await query.getManyAndCount();
 
     // 根据省市区筛选(如果提供了省市区ID)
     let filteredRoutes = routes;