Initial commit

This commit is contained in:
2026-06-05 17:46:51 +08:00
commit c04c890186
96 changed files with 6477 additions and 0 deletions

View File

@@ -0,0 +1 @@
{ "navigationStyle": "custom", "usingComponents": { "post-card": "/components/post-card/post-card" } }

View File

@@ -0,0 +1,73 @@
import { getAvatarGradient } from '../../utils/format'
Page({
data: {
statusBarHeight: 0,
keyword: '',
resultTab: 'posts' as 'posts' | 'users',
postResults: [] as any[],
userResults: [] as any[],
hotTopics: [] as any[],
loading: false,
},
onLoad() {
const info = wx.getSystemInfoSync()
this.setData({ statusBarHeight: info.statusBarHeight })
this.loadHotTopics()
},
async loadHotTopics() {
try {
const res = await wx.cloud.callFunction({ name: 'getHotTopics', data: {} }) as any
this.setData({ hotTopics: res.result?.data || [] })
} catch {}
},
onInput(e: WechatMiniprogram.CustomEvent) {
this.setData({ keyword: e.detail.value })
},
onClear() {
this.setData({ keyword: '', postResults: [], userResults: [] })
},
async onSearch() {
const kw = this.data.keyword.trim()
if (!kw) return
this.setData({ loading: true })
try {
const [posts, users] = await Promise.all([
wx.cloud.callFunction({ name: 'searchPosts', data: { keyword: kw } }) as any,
wx.cloud.callFunction({ name: 'searchUsers', data: { keyword: kw } }) as any,
])
this.setData({
postResults: posts.result?.data || [],
userResults: (users.result?.data || []).map((u: any) => ({
...u,
gradient: getAvatarGradient(u._id),
})),
})
} catch {
wx.showToast({ title: '搜索失败', icon: 'none' })
} finally {
this.setData({ loading: false })
}
},
onTopicTap(e: WechatMiniprogram.CustomEvent) {
const tag = e.currentTarget.dataset.tag as string
this.setData({ keyword: tag })
this.onSearch()
},
onResultTab(e: WechatMiniprogram.CustomEvent) {
this.setData({ resultTab: e.currentTarget.dataset.t as 'posts' | 'users' })
},
onUserTap(e: WechatMiniprogram.CustomEvent) {
wx.navigateTo({ url: `/pages/pet-detail/pet-detail?userId=${e.currentTarget.dataset.uid}` })
},
onBack() { wx.navigateBack() },
})

View File

@@ -0,0 +1,74 @@
<view class="page">
<view class="safe-top" style="height: {{statusBarHeight}}px"></view>
<view class="search-bar">
<view class="back" bindtap="onBack"></view>
<view class="input-wrap">
<text class="search-icon">🔍</text>
<input
class="search-input"
value="{{keyword}}"
bindinput="onInput"
bindconfirm="onSearch"
placeholder="搜索宠物、话题、用户..."
focus="{{true}}"
confirm-type="search"
/>
<view wx:if="{{keyword}}" class="clear" bindtap="onClear">×</view>
</view>
<view class="search-btn" bindtap="onSearch">搜索</view>
</view>
<!-- 热门话题 -->
<view wx:if="{{!keyword && !loading}}" class="hot-section">
<text class="section-title">热门话题</text>
<view class="hot-tags">
<view
wx:for="{{hotTopics}}"
wx:key="index"
class="hot-tag"
bindtap="onTopicTap"
data-tag="{{item.tag}}"
>
<text class="tag-rank">{{index + 1}}</text>
<text class="tag-text">{{item.tag}}</text>
<text class="tag-count">{{item.count}}篇</text>
</view>
</view>
</view>
<!-- 搜索结果 -->
<scroll-view wx:if="{{keyword}}" scroll-y="true" class="results-scroll" enhanced="true" show-scrollbar="false">
<view class="results-tabs">
<view class="rtab {{resultTab === 'posts' ? 'rtab-on' : ''}}" bindtap="onResultTab" data-t="posts">帖子</view>
<view class="rtab {{resultTab === 'users' ? 'rtab-on' : ''}}" bindtap="onResultTab" data-t="users">用户</view>
</view>
<view wx:if="{{resultTab === 'posts'}}">
<post-card wx:for="{{postResults}}" wx:key="_id" post="{{item}}" />
<view wx:if="{{!loading && postResults.length === 0}}" class="empty">
<text>没有找到相关帖子</text>
</view>
</view>
<view wx:if="{{resultTab === 'users'}}">
<view
wx:for="{{userResults}}"
wx:key="_id"
class="user-result"
bindtap="onUserTap"
data-uid="{{item._id}}"
>
<view class="u-avatar" style="background: {{item.gradient}}">{{item.nickName[0]}}</view>
<view class="u-info">
<text class="u-name">{{item.nickName}}</text>
<text class="u-bio">{{item.bio || '宠物爱好者'}}</text>
</view>
</view>
<view wx:if="{{!loading && userResults.length === 0}}" class="empty">
<text>没有找到相关用户</text>
</view>
</view>
<view style="height: 60rpx;"></view>
</scroll-view>
</view>

View File

@@ -0,0 +1,30 @@
.page { min-height: 100vh; background: linear-gradient(180deg, #fff8f2 0%, #f5f0ff 100%); }
.search-bar { display: flex; align-items: center; gap: 14rpx; padding: 14rpx 28rpx; }
.back { font-size: 60rpx; color: #272235; font-weight: 300; line-height: 1; }
.input-wrap { flex: 1; display: flex; align-items: center; background: rgba(255,255,255,0.88); border: 1rpx solid rgba(255,255,255,0.72); border-radius: 999rpx; padding: 0 20rpx; height: 76rpx; gap: 10rpx; box-shadow: 0 8rpx 18rpx rgba(78,56,96,0.08); }
.search-icon { font-size: 30rpx; }
.search-input { flex: 1; font-size: 28rpx; color: #272235; }
.clear { font-size: 36rpx; color: #9b8fa8; }
.search-btn { font-size: 28rpx; font-weight: 800; color: #ff4f91; padding: 0 6rpx; }
.hot-section { padding: 20rpx 28rpx; }
.section-title { display: block; font-size: 26rpx; font-weight: 900; color: #9b8fa8; margin-bottom: 20rpx; }
.hot-tags { display: flex; flex-direction: column; gap: 0; background: rgba(255,255,255,0.88); border-radius: 36rpx; overflow: hidden; border: 1rpx solid rgba(255,255,255,0.72); box-shadow: 0 12rpx 26rpx rgba(78,56,96,0.08); }
.hot-tag { display: flex; align-items: center; gap: 20rpx; padding: 22rpx 28rpx; border-bottom: 1rpx solid rgba(43,37,61,0.05); }
.hot-tag:last-child { border-bottom: none; }
.tag-rank { font-size: 30rpx; font-weight: 900; color: #ff4f91; width: 32rpx; text-align: center; }
.hot-tag:nth-child(n+4) .tag-rank { color: #9b8fa8; }
.tag-text { flex: 1; font-size: 28rpx; font-weight: 700; color: #272235; }
.tag-count { font-size: 24rpx; color: #9b8fa8; }
.results-tabs { display: flex; padding: 0 28rpx 20rpx; gap: 8rpx; }
.rtab { font-size: 28rpx; font-weight: 700; color: #9b8fa8; padding: 10rpx 20rpx; border-radius: 999rpx; }
.rtab-on { color: #ff4f91; background: rgba(255,79,145,0.10); font-weight: 900; }
.user-result { display: flex; align-items: center; gap: 20rpx; padding: 20rpx 28rpx; background: rgba(255,255,255,0.80); border-bottom: 1rpx solid rgba(43,37,61,0.05); }
.u-avatar { width: 88rpx; height: 88rpx; border-radius: 28rpx; display: flex; align-items: center; justify-content: center; font-size: 36rpx; font-weight: 800; color: rgba(39,34,53,0.72); flex-shrink: 0; }
.u-name { display: block; font-size: 28rpx; font-weight: 800; color: #272235; }
.u-bio { display: block; font-size: 24rpx; color: #9b8fa8; margin-top: 4rpx; }
.empty { text-align: center; font-size: 26rpx; color: #9b8fa8; padding: 80rpx; }
.results-scroll { }