hejianhao
2026-03-04 cd16c12cbac60bcb8ec6d994a16ff48762e86529
feat(select-city): 添加加载骨架屏以提升用户体验

在 select-city 页面添加加载状态的骨架屏,避免数据加载时页面空白。
- 添加 isLoading 状态控制骨架屏显示
- 新增骨架屏样式,包含服务城市和非运营城市的占位布局
- 在数据加载完成后显示实际内容
2个文件已修改
101 ■■■■■ 已修改文件
src/robotaxi/pages/select-city/index.less 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/select-city/index.tsx 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/select-city/index.less
@@ -43,6 +43,71 @@
        min-height: 0;
    }
    .skeleton {
        padding: 0 32px;
        gap: 48px;
    }
    .skeleton-service,
    .skeleton-non-operational {
        display: flex;
        flex-direction: column;
        gap: 24px;
    }
    .skeleton-title {
        width: 160px;
        height: 32px;
        border-radius: 8px;
        background: #F2F3F7;
    }
    .skeleton-chip-list {
        display: flex;
        flex-wrap: wrap;
        gap: 20px;
    }
    .skeleton-chip {
        width: 140px;
        height: 72px;
        border-radius: 12px;
        background: #F2F3F7;
    }
    .skeleton-line-group {
        display: flex;
        flex-direction: column;
        gap: 20px;
    }
    .skeleton-line {
        width: 100%;
        height: 28px;
        border-radius: 8px;
        background: #F2F3F7;
    }
    .skeleton-shortcut {
        position: fixed;
        top: 50%;
        right: 12px;
        transform: translateY(-50%);
        display: flex;
        flex-direction: column;
        gap: 8px;
        padding: 10px 0;
        background-color: rgba(255, 255, 255, 0.5);
        border-radius: 20px;
    }
    .skeleton-shortcut-item {
        width: 24px;
        height: 24px;
        border-radius: 6px;
        background: #F2F3F7;
    }
    .service-city-box {
        margin: 60px 32px 64px 32px;
        flex-shrink: 0;
@@ -199,4 +264,4 @@
            height: 400px;
        }
    }
}
}
src/robotaxi/pages/select-city/index.tsx
@@ -13,6 +13,7 @@
  const [filteredPendingList, setFilteredPendingList] = useState<any[]>([]); // 过滤后的开放城市列表
  const [openCityList, setOpenCityList] = useState<any[]>([]); // 开放城市列表
  const [searchResultList, setSearchResultList] = useState<any[]>([]); // 搜索结果列表
  const [isLoading, setIsLoading] = useState(true);
  useEffect(() => {
    const city = Taro.getStorageSync('selectedCity');
@@ -21,6 +22,7 @@
    }
    // 并行请求:获取开通城市列表和所有城市列表
    setIsLoading(true);
    Promise.all([
      getOpenCity(),
      getCityList({ isOpen: 0 }) // 0代表待开通
@@ -52,6 +54,8 @@
    }).catch(err => {
      console.error('获取城市数据失败', err);
    }).finally(() => {
      setIsLoading(false);
    });
  }, [])
@@ -114,6 +118,34 @@
          placeholderClass='placeholder-class'
        />
      </View>
      {
        isLoading &&
        <View className='city-content skeleton'>
          <View className='skeleton-service'>
            <View className='skeleton-title'></View>
            <View className='skeleton-chip-list'>
              {Array.from({ length: 6 }).map((_, index) => (
                <View className='skeleton-chip' key={index}></View>
              ))}
            </View>
          </View>
          <View className='skeleton-non-operational'>
            <View className='skeleton-title'></View>
            <View className='skeleton-line-group'>
              {Array.from({ length: 8 }).map((_, index) => (
                <View className='skeleton-line' key={index}></View>
              ))}
            </View>
          </View>
          <View className='skeleton-shortcut'>
            {Array.from({ length: 6 }).map((_, index) => (
              <View className='skeleton-shortcut-item' key={index}></View>
            ))}
          </View>
        </View>
      }
      {!isLoading && (
        <>
      {/* 搜索前 */}
      {
        !searchValue &&
@@ -207,6 +239,8 @@
          }
        </View>
      }
        </>
      )}
    </View>
  )
}