123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988 |
- <template>
- <view class="search-page">
- <!-- 自定义导航栏 -->
- <view class="custom-navbar" :style="{ paddingTop: statusBarHeight + 'px' }">
- <view class="navbar-content">
- <!-- 返回按钮 -->
- <view class="back-button" @click="goBack">
- <text class="back-icon">←</text>
- </view>
-
- <!-- 搜索输入框 -->
- <view class="search-input-container">
- <view class="search-icon">
- <text class="icon">🔍</text>
- </view>
- <input
- class="search-input"
- v-model="searchKeyword"
- placeholder="搜索商品名称"
- @input="onSearchInput"
- @confirm="performSearch"
- :focus="true"
- confirm-type="search"
- />
- </view>
-
- <!-- 搜索按钮 -->
- <view class="search-button" @click="performSearch">
- <text class="search-text">搜索</text>
- </view>
- </view>
- </view>
-
- <!-- 搜索历史 -->
- <view v-if="!searchKeyword && searchHistory.length > 0" class="search-history">
- <view class="history-header">
- <text class="history-title">历史记录</text>
- <view class="clear-history" @click="clearHistory">
- <text class="clear-icon">🗑</text>
- </view>
- </view>
- <view class="history-tags">
- <view
- v-for="(item, index) in searchHistory"
- :key="index"
- class="history-tag"
- @click="searchFromHistory(item)"
- >
- <text class="tag-text">{{ item }}</text>
- </view>
- </view>
- </view>
-
- <!-- 热门搜索 -->
- <view v-if="!searchKeyword" class="hot-search">
- <view class="hot-header">
- <text class="hot-title">热门搜索</text>
- </view>
-
- <!-- 如果没有数据,显示提示 -->
- <view v-if="hotSearchList.length === 0" class="no-data" style="padding: 60rpx; text-align: center; color: #999;">
- <text>暂无热门搜索数据</text>
- </view>
-
- <view v-else class="hot-list">
- <view
- v-for="(item, index) in hotSearchList"
- :key="index"
- class="hot-item"
- @click="searchFromHot(item)"
- >
- <view class="hot-rank" :class="[index === 0 ? 'rank-first' : index === 1 ? 'rank-second' : index === 2 ? 'rank-third' : 'rank-normal']">
- <text class="rank-number">{{ index + 1 }}</text>
- </view>
- <text class="hot-text">{{ item }}</text>
- </view>
- </view>
- </view>
-
- <!-- 搜索建议 -->
- <view v-if="searchKeyword && searchSuggestions.length > 0" class="search-suggestions">
- <view
- v-for="(suggestion, index) in searchSuggestions"
- :key="index"
- class="suggestion-item"
- @click="selectSuggestion(suggestion)"
- >
- <text class="suggestion-icon">🔍</text>
- <text class="suggestion-text">{{ suggestion }}</text>
- </view>
- </view>
-
- <!-- 搜索结果 -->
- <view v-if="hasSearched" class="search-results">
- <!-- 结果统计 -->
- <view class="result-stats">
- <text class="stats-text">
- 找到 <text class="stats-count">{{ searchResults.length }}</text> 个相关商品
- </text>
- </view>
-
- <!-- 排序筛选 -->
- <view class="filter-bar">
- <view
- v-for="(filter, index) in filterOptions"
- :key="index"
- class="filter-item"
- :class="{ active: currentFilter === filter.value }"
- @click="changeFilter(filter.value)"
- >
- <text class="filter-text">{{ filter.label }}</text>
- <text v-if="filter.sortable" class="sort-arrow">{{ getSortArrow(filter.value) }}</text>
- </view>
- </view>
-
- <!-- 商品列表 -->
- <view v-if="searchResults.length > 0" class="product-list">
- <view
- v-for="product in searchResults"
- :key="product.id"
- class="product-item"
- @click="goToProductDetail(product)"
- >
- <image :src="product.imageUrl" class="product-image" mode="aspectFill"></image>
- <view class="product-info">
- <text class="product-name">{{ highlightKeyword(product.name) }}</text>
- <view class="product-meta">
- <text class="product-category">{{ product.categoryName }}</text>
- <text class="product-sales">销量: {{ product.sales }}</text>
- </view>
- <view class="product-stock">
- <text class="stock-text" :class="{ 'low-stock': product.stock < 10 }">
- 库存: {{ product.stock }}
- </text>
- </view>
- </view>
- </view>
- </view>
-
- <!-- 无搜索结果 -->
- <view v-else class="no-results">
- <view class="no-results-icon">😔</view>
- <text class="no-results-text">未找到相关商品</text>
- <text class="no-results-tip">试试搜索其他关键词</text>
- </view>
- </view>
-
- <!-- 加载状态 -->
- <view v-if="loading" class="loading-container">
- <view class="loading-spinner"></view>
- <text class="loading-text">搜索中...</text>
- </view>
- </view>
- </template>
- <script>
- // TODO: API替换 - 搜索相关接口
- import { searchProducts, getHotSearch, handleApiError } from '@/api/search.js'
-
- export default {
- data() {
- return {
- statusBarHeight: 0,
-
- // 搜索相关
- searchKeyword: '', // 搜索关键词
- searchSuggestions: [], // 搜索建议
- searchResults: [], // 搜索结果
- searchHistory: [], // 搜索历史
- hotSearchList: [], // 热门搜索
- hasSearched: false, // 是否已执行搜索
-
- // 筛选排序
- currentFilter: 'default', // 当前筛选方式
- currentSort: 'asc', // 当前排序方向
- filterOptions: [
- { label: '综合', value: 'default', sortable: false },
- { label: '销量', value: 'sales', sortable: true },
- { label: '库存', value: 'stock', sortable: true },
- { label: '名称', value: 'name', sortable: true }
- ],
-
- // 状态
- loading: false,
-
- // 防抖定时器
- searchTimer: null
- }
- },
- onLoad() {
- console.log('🚀 搜索页面开始加载')
-
- // 获取系统信息
- const systemInfo = uni.getSystemInfoSync()
- this.statusBarHeight = systemInfo.statusBarHeight || 20
-
- // 加载搜索历史
- console.log('📚 开始加载搜索历史')
- this.loadSearchHistory()
-
- // 加载热门搜索
- console.log('🔥 开始加载热门搜索')
- this.loadHotSearch()
-
- console.log('✅ 搜索页面加载完成')
- },
- onUnload() {
- // 清除定时器
- if (this.searchTimer) {
- clearTimeout(this.searchTimer)
- }
- },
- methods: {
- /**
- * 加载搜索历史
- */
- loadSearchHistory() {
- try {
- const history = uni.getStorageSync('searchHistory') || []
- this.searchHistory = history.slice(0, 10) // 最多保存10条历史
-
- // 如果没有搜索历史,添加一些示例数据(仅用于演示)
- if (this.searchHistory.length === 0) {
- this.searchHistory = ['茅台', '酒谷特酿']
- console.log('🔄 使用示例搜索历史数据')
- }
- } catch (error) {
- console.error('加载搜索历史失败:', error)
- this.searchHistory = []
- }
- },
-
- /**
- * 加载热门搜索
- * TODO: API替换 - 从后台获取热门搜索词
- */
- async loadHotSearch() {
- try {
- const response = await getHotSearch()
- if (response.success) {
- // 确保数据是数组格式
- const searchList = response.data.hotSearchList || []
-
- // 清空现有数据并重新赋值,确保响应式更新
- this.hotSearchList.splice(0, this.hotSearchList.length, ...searchList)
-
- console.log('✅ 热门搜索数据加载成功:', this.hotSearchList)
- console.log('📊 数据长度:', this.hotSearchList.length)
-
- // 使用nextTick确保DOM更新
- this.$nextTick(() => {
- console.log('🔄 视图已更新')
- })
- } else {
- console.error('❌ 热门搜索API返回失败:', response)
- // 使用默认数据
- this.setDefaultHotSearch()
- }
- } catch (error) {
- console.error('❌ 加载热门搜索失败:', error)
- handleApiError(error)
- // 使用默认数据
- this.setDefaultHotSearch()
- }
- },
-
- /**
- * 设置默认热门搜索数据
- */
- setDefaultHotSearch() {
- const defaultData = [
- '酒谷',
- '茅台',
- '红酒',
- '陈酿',
- '特酿',
- '飞天',
- '波尔多',
- '珍藏'
- ]
-
- // 清空现有数据并重新赋值,确保响应式更新
- this.hotSearchList.splice(0, this.hotSearchList.length, ...defaultData)
-
- console.log('🔄 使用默认热门搜索数据:', this.hotSearchList)
- console.log('📊 默认数据长度:', this.hotSearchList.length)
-
- // 使用nextTick确保DOM更新
- this.$nextTick(() => {
- console.log('🔄 默认数据视图已更新')
- })
- },
-
- /**
- * 搜索输入事件 - 实时搜索建议
- */
- onSearchInput(e) {
- const keyword = e.detail.value.trim()
- this.searchKeyword = keyword
-
- // 清除之前的定时器
- if (this.searchTimer) {
- clearTimeout(this.searchTimer)
- }
-
- if (keyword) {
- // 防抖:500ms后触发搜索建议
- this.searchTimer = setTimeout(() => {
- this.getSearchSuggestions(keyword)
- }, 300)
- } else {
- this.searchSuggestions = []
- this.hasSearched = false
- }
- },
-
- /**
- * 获取搜索建议
- * TODO: API替换 - 从后台获取搜索建议
- */
- async getSearchSuggestions(keyword) {
- try {
- // 模拟搜索建议逻辑
- const allProducts = await this.getAllProducts()
- const suggestions = []
-
- // 根据商品名称生成建议
- allProducts.forEach(product => {
- if (product.name.includes(keyword) && !suggestions.includes(product.name)) {
- suggestions.push(product.name)
- }
- })
-
- // 根据分类名称生成建议
- const categories = ['酒谷酒', '茅台酒', '红酒', '白酒', '洋酒']
- categories.forEach(category => {
- if (category.includes(keyword) && !suggestions.includes(category)) {
- suggestions.push(category)
- }
- })
-
- this.searchSuggestions = suggestions.slice(0, 8) // 最多显示8个建议
-
- } catch (error) {
- console.error('获取搜索建议失败:', error)
- this.searchSuggestions = []
- }
- },
-
- /**
- * 执行搜索
- */
- async performSearch(keyword = null) {
- const searchKeyword = keyword || this.searchKeyword.trim()
-
- if (!searchKeyword) {
- uni.showToast({
- title: '请输入搜索关键词',
- icon: 'none'
- })
- return
- }
-
- try {
- this.loading = true
- this.hasSearched = true
- this.searchSuggestions = []
-
- console.log('🔍 开始搜索:', searchKeyword)
-
- // TODO: API替换 - 调用真实搜索接口
- const response = await searchProducts({
- keyword: searchKeyword,
- filter: this.currentFilter,
- sort: this.currentSort
- })
-
- if (response.success) {
- this.searchResults = response.data.products || []
-
- // 保存搜索历史
- this.saveSearchHistory(searchKeyword)
-
- console.log('✅ 搜索完成:', {
- keyword: searchKeyword,
- results: this.searchResults.length
- })
-
- } else {
- throw new Error(response.message || '搜索失败')
- }
-
- } catch (error) {
- console.error('❌ 搜索失败:', error)
- handleApiError(error)
- this.searchResults = []
-
- } finally {
- this.loading = false
- }
- },
-
- /**
- * 保存搜索历史
- */
- saveSearchHistory(keyword) {
- try {
- // 移除重复项
- let history = this.searchHistory.filter(item => item !== keyword)
- // 添加到开头
- history.unshift(keyword)
- // 限制数量
- history = history.slice(0, 10)
-
- this.searchHistory = history
- uni.setStorageSync('searchHistory', history)
-
- } catch (error) {
- console.error('保存搜索历史失败:', error)
- }
- },
-
- /**
- * 从历史记录搜索
- */
- searchFromHistory(keyword) {
- this.searchKeyword = keyword
- this.performSearch(keyword)
- },
-
- /**
- * 从热门搜索
- */
- searchFromHot(keyword) {
- this.searchKeyword = keyword
- this.performSearch(keyword)
- },
-
- /**
- * 选择搜索建议
- */
- selectSuggestion(suggestion) {
- this.searchKeyword = suggestion
- this.performSearch(suggestion)
- },
-
- /**
- * 改变筛选方式
- */
- changeFilter(filterValue) {
- if (this.currentFilter === filterValue) {
- // 如果是可排序的,切换排序方向
- const filter = this.filterOptions.find(f => f.value === filterValue)
- if (filter && filter.sortable) {
- this.currentSort = this.currentSort === 'asc' ? 'desc' : 'asc'
- }
- } else {
- this.currentFilter = filterValue
- this.currentSort = 'asc'
- }
-
- // 重新执行搜索
- if (this.hasSearched) {
- this.performSearch()
- }
- },
-
- /**
- * 获取排序箭头
- */
- getSortArrow(filterValue) {
- if (this.currentFilter !== filterValue) return ''
- return this.currentSort === 'asc' ? '↑' : '↓'
- },
-
- /**
- * 高亮关键词
- */
- highlightKeyword(text) {
- if (!this.searchKeyword) return text
- // 简单的高亮处理,实际项目中可以用更复杂的方案
- return text
- },
-
- /**
- * 清空搜索
- */
- clearSearch() {
- this.searchKeyword = ''
- this.searchSuggestions = []
- this.searchResults = []
- this.hasSearched = false
- },
-
- /**
- * 清空历史记录
- */
- clearHistory() {
- uni.showModal({
- title: '提示',
- content: '确定要清空搜索历史吗?',
- success: (res) => {
- if (res.confirm) {
- this.searchHistory = []
- uni.removeStorageSync('searchHistory')
- uni.showToast({
- title: '已清空历史',
- icon: 'success'
- })
- }
- }
- })
- },
-
- /**
- * 跳转商品详情
- */
- goToProductDetail(product) {
- console.log('查看商品详情:', product)
- uni.navigateTo({
- url: `/pages/product/detail?id=${product.id}`
- })
- },
-
- /**
- * 返回上一页或清除搜索结果
- */
- goBack() {
- // 如果当前有搜索结果,先清除搜索结果回到搜索页面
- if (this.hasSearched) {
- console.log('🔙 清除搜索结果,返回搜索页面')
- this.clearSearch()
- } else {
- // 如果没有搜索结果,直接返回上一页
- console.log('🔙 返回上一页')
- uni.navigateBack()
- }
- },
-
- /**
- * 获取所有商品数据(用于搜索建议)
- * TODO: API替换 - 这应该是一个专门的搜索建议接口
- */
- async getAllProducts() {
- try {
- // 临时使用模拟数据
- const { MOCK_PRODUCTS, MOCK_CATEGORIES, MOCK_ASSETS } = require('@/mock/mockData.js')
-
- return MOCK_PRODUCTS.data.products
- .filter(product => product.status === 1)
- .map(product => {
- const category = MOCK_CATEGORIES.data.categories.find(c => c.id === product.categoryId)
- return {
- ...product,
- categoryName: category ? category.name : '未分类',
- imageUrl: MOCK_ASSETS.products[product.assetId]
- }
- })
- } catch (error) {
- console.error('获取商品数据失败:', error)
- return []
- }
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- .search-page {
- min-height: 100vh;
- background: #f8f8f8;
- }
- /* 自定义导航栏 */
- .custom-navbar {
- background: #FF6600;
- position: sticky;
- top: 0;
- z-index: 999;
-
- .navbar-content {
- display: flex;
- align-items: center;
- padding: 20rpx;
- gap: 20rpx;
-
- .back-button {
- width: 60rpx;
- height: 60rpx;
- display: flex;
- align-items: center;
- justify-content: center;
-
- .back-icon {
- font-size: 36rpx;
- color: #ffffff;
- font-weight: bold;
- }
- }
-
- .search-input-container {
- flex: 1;
- position: relative;
- background: #ffffff;
- border-radius: 50rpx;
- display: flex;
- align-items: center;
- padding: 0 30rpx;
- height: 80rpx;
-
- .search-icon {
- margin-right: 15rpx;
-
- .icon {
- font-size: 28rpx;
- color: #999;
- }
- }
-
- .search-input {
- flex: 1;
- height: 80rpx;
- font-size: 28rpx;
- color: #333;
- background: transparent;
- }
- }
-
- .search-button {
- padding: 0 30rpx;
- height: 80rpx;
- display: flex;
- align-items: center;
- justify-content: center;
-
- .search-text {
- font-size: 28rpx;
- color: #ffffff;
- font-weight: bold;
- }
- }
- }
- }
- /* 搜索历史 */
- .search-history {
- background: #ffffff;
- margin: 20rpx 0 0 0;
- padding: 30rpx 40rpx;
-
- .history-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 30rpx;
-
- .history-title {
- font-size: 32rpx;
- color: #333;
- }
-
- .clear-history {
- .clear-icon {
- font-size: 32rpx;
- color: #ccc;
- }
- }
- }
-
- .history-tags {
- display: flex;
- flex-wrap: wrap;
- gap: 20rpx;
-
- .history-tag {
- background: #f5f5f5;
- border-radius: 30rpx;
- padding: 15rpx 30rpx;
-
- .tag-text {
- font-size: 28rpx;
- color: #666;
- }
-
- &:active {
- background: #e0e0e0;
- }
- }
- }
- }
- /* 热门搜索 */
- .hot-search {
- background: #ffffff;
- margin: 20rpx 0 0 0;
- padding: 30rpx 40rpx;
-
- .hot-header {
- margin-bottom: 30rpx;
-
- .hot-title {
- font-size: 32rpx;
- color: #333;
- }
- }
-
- .hot-list {
- .hot-item {
- display: flex;
- align-items: center;
- padding: 25rpx 0;
- border-bottom: 1rpx solid #f5f5f5;
-
- .hot-rank {
- width: 50rpx;
- height: 50rpx;
- border-radius: 50%;
- display: flex;
- align-items: center;
- justify-content: center;
- margin-right: 30rpx;
-
- .rank-number {
- font-size: 26rpx;
- font-weight: bold;
- }
-
- &.rank-first {
- background: #FF6B6B;
-
- .rank-number {
- color: #ffffff;
- }
- }
-
- &.rank-second {
- background: #FFA500;
-
- .rank-number {
- color: #ffffff;
- }
- }
-
- &.rank-third {
- background: #FFD700;
-
- .rank-number {
- color: #ffffff;
- }
- }
-
- &.rank-normal {
- background: #f5f5f5;
-
- .rank-number {
- color: #999;
- }
- }
- }
-
- .hot-text {
- font-size: 28rpx;
- color: #333;
- flex: 1;
- }
-
- &:last-child {
- border-bottom: none;
- }
-
- &:active {
- background: #f9f9f9;
- }
- }
- }
- }
- /* 搜索建议 */
- .search-suggestions {
- background: #ffffff;
- margin: 0 20rpx;
- border-radius: 20rpx;
- overflow: hidden;
-
- .suggestion-item {
- display: flex;
- align-items: center;
- padding: 25rpx 30rpx;
- border-bottom: 1rpx solid #f0f0f0;
-
- .suggestion-icon {
- font-size: 24rpx;
- color: #999;
- margin-right: 20rpx;
- }
-
- .suggestion-text {
- font-size: 28rpx;
- color: #333;
- flex: 1;
- }
-
- &:last-child {
- border-bottom: none;
- }
-
- &:active {
- background: #f5f5f5;
- }
- }
- }
- /* 搜索结果 */
- .search-results {
- margin: 20rpx;
-
- .result-stats {
- background: #ffffff;
- border-radius: 20rpx;
- padding: 25rpx 30rpx;
- margin-bottom: 20rpx;
-
- .stats-text {
- font-size: 28rpx;
- color: #666;
-
- .stats-count {
- color: #FF6600;
- font-weight: bold;
- }
- }
- }
-
- .filter-bar {
- background: #ffffff;
- border-radius: 20rpx;
- padding: 20rpx 30rpx;
- margin-bottom: 20rpx;
- display: flex;
- gap: 30rpx;
-
- .filter-item {
- display: flex;
- align-items: center;
- gap: 8rpx;
-
- .filter-text {
- font-size: 28rpx;
- color: #666;
- }
-
- .sort-arrow {
- font-size: 24rpx;
- color: #666;
- }
-
- &.active {
- .filter-text,
- .sort-arrow {
- color: #FF6600;
- font-weight: bold;
- }
- }
- }
- }
-
- .product-list {
- .product-item {
- background: #ffffff;
- border-radius: 20rpx;
- margin-bottom: 20rpx;
- padding: 20rpx;
- display: flex;
- gap: 20rpx;
-
- .product-image {
- width: 160rpx;
- height: 160rpx;
- border-radius: 12rpx;
- background: #f5f5f5;
- }
-
- .product-info {
- flex: 1;
- display: flex;
- flex-direction: column;
- justify-content: space-between;
-
- .product-name {
- font-size: 30rpx;
- font-weight: bold;
- color: #333;
- line-height: 1.4;
- margin-bottom: 10rpx;
- }
-
- .product-meta {
- display: flex;
- gap: 20rpx;
- margin-bottom: 10rpx;
-
- .product-category {
- font-size: 24rpx;
- color: #FF6600;
- background: rgba(255, 102, 0, 0.1);
- padding: 4rpx 12rpx;
- border-radius: 12rpx;
- }
-
- .product-sales {
- font-size: 24rpx;
- color: #999;
- }
- }
-
- .product-stock {
- .stock-text {
- font-size: 24rpx;
- color: #666;
-
- &.low-stock {
- color: #ff4757;
- }
- }
- }
- }
-
- &:active {
- background: #f5f5f5;
- }
- }
- }
- }
- /* 无搜索结果 */
- .no-results {
- background: #ffffff;
- border-radius: 20rpx;
- padding: 80rpx 30rpx;
- text-align: center;
-
- .no-results-icon {
- font-size: 80rpx;
- margin-bottom: 20rpx;
- }
-
- .no-results-text {
- font-size: 32rpx;
- color: #333;
- display: block;
- margin-bottom: 10rpx;
- }
-
- .no-results-tip {
- font-size: 26rpx;
- color: #999;
- }
- }
- /* 加载状态 */
- .loading-container {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- padding: 60rpx;
-
- .loading-spinner {
- width: 60rpx;
- height: 60rpx;
- border: 4rpx solid #f3f3f3;
- border-top: 4rpx solid #FF6600;
- border-radius: 50%;
- animation: loading-spin 1s linear infinite;
- margin-bottom: 20rpx;
- }
-
- .loading-text {
- font-size: 28rpx;
- color: #666;
- }
- }
- @keyframes loading-spin {
- 0% { transform: rotate(0deg); }
- 100% { transform: rotate(360deg); }
- }
- </style>
|