# 汪圈 HTML 转 Taro 微信小程序设计文档

## 1. 背景与目标

当前参考稿位于 `refrence_html/`，共 6 个 HTML 文件：

| HTML 文件 | 目标页面 | 说明 |
| --- | --- | --- |
| `plaza.html` | `pages/plaza` | 广场信息流、搜索、频道 Tab、话题 Chip、点赞动效 |
| `nearby.html` | `pages/nearby` | 附近地图、宠物 Pin、可拖拽底部 Sheet、匹配喜欢动效 |
| `messages.html` | `pages/messages` | 消息页、活跃用户横滑、会话列表、未读状态 |
| `profile.html` | `pages/profile` | 我的页面、资料卡、宠物档案、偏好设置 |
| `publish.html` | `pages/publish` | 发布动态、图片网格、话题、可见范围 Sheet、发布成功弹层 |
| `wangquan-ios-launcher.html` | `pages/launcher`，可选 | 设计总览页，仅用于开发预览或品牌落地页，不进入主 Tab |

迁移目标：

1. 使用 Taro + React + TypeScript 构建微信小程序。
2. 保持参考 HTML 的内屏视觉、色彩、间距、圆角、阴影、字体层级和动效一致。
3. 适配微信小程序运行环境，使用自定义导航、真实安全区和微信胶囊位置。
4. 页面拆成可维护组件，避免把 HTML 直接平铺到单个页面。
5. 使用微信云开发模式：页面通过云函数访问业务数据，云数据库和云存储承载帖子、宠物、消息和媒体。
6. 输出可直接落地的目录结构、组件边界、云函数规划和迁移步骤。

## 2. 视觉一致性边界

参考 HTML 是桌面浏览器里的 iPhone 预览稿，包含 `stage-wrap`、`.phone`、刘海、状态栏、底部 home indicator 等展示壳。

小程序实现时采用以下边界：

- 保留 `.screen` 内的产品视觉：深紫背景、顶部内容、卡片、Tab、FAB、底部导航、Sheet、Toast、地图和发布页结构。
- 不把桌面预览用的外层 `.stage-wrap`、`.phone` 手机壳放进小程序页面，避免用户在微信里看到二次手机框。
- 使用 `navigationStyle: custom`，通过 `Taro.getSystemInfoSync()` 和 `Taro.getMenuButtonBoundingClientRect()` 计算状态栏、安全区和胶囊避让。
- 原 HTML 的 `status-bar` 抽象为 `CustomNavBar` 的安全区占位。正式小程序不模拟运营商、电量图标；视觉稿比对模式可通过 `VISUAL_PARITY_MODE` 开关显示模拟状态栏。
- 原 HTML 的 `home-indicator` 抽象为 `SafeAreaBottom`，在真机上优先使用系统安全区，视觉稿比对模式可显示白色横条。

## 3. 技术选型

| 层 | 选择 | 用途 |
| --- | --- | --- |
| 框架 | Taro 3.x/4.x | 编译到微信小程序 |
| UI | React + TypeScript | 页面和组件开发 |
| 样式 | SCSS + Taro pxTransform | 从 HTML CSS 迁移并统一设计 token |
| 状态 | React hooks + 轻量 store | 页面局部状态、用户会话、未读数量 |
| 数据 | 微信云开发云函数 + 云数据库 | Feed、宠物、消息、匹配、用户资料 |
| 媒体 | 云存储 | 图片、视频封面、头像 |
| 地图视觉 | CSS + 绝对定位，必要时 Canvas | 还原 `nearby.html` 的装饰地图 |
| 图标 | 原 SVG 路径资产化 | 统一转成 iconfont 或 PNG/SVG asset，避免直接依赖 Web SVG DOM |

关键约束：

- Taro 页面只能使用小程序支持的组件和样式能力，HTML 中的 `div/button/input/textarea/a` 需要迁移为 `View/Button/Input/Textarea/Navigator/Text/Image/ScrollView`。
- 小程序没有 DOM API，所有 `querySelector`、`classList`、`dataset` 直接操作改为 React state 驱动。
- `pointerdown/pointermove/pointerup` 改为 `onTouchStart/onTouchMove/onTouchEnd`。
- `hover` 效果改为 `hoverClass`、`active` 状态或点击反馈。
- CSS 变量统一转 SCSS token，减少不同基础库对 CSS custom properties 的兼容风险。

## 4. 小程序路由与页面

### 4.1 `app.config.ts`

```ts
export default defineAppConfig({
  pages: [
    'pages/plaza/index',
    'pages/nearby/index',
    'pages/publish/index',
    'pages/messages/index',
    'pages/profile/index'
  ],
  window: {
    navigationStyle: 'custom',
    backgroundColor: '#14102b',
    backgroundTextStyle: 'dark'
  },
  tabBar: {
    custom: true,
    color: '#8a7aab',
    selectedColor: '#d8b4ff',
    backgroundColor: '#14102b',
    list: [
      { pagePath: 'pages/plaza/index', text: '广场' },
      { pagePath: 'pages/nearby/index', text: '附近' },
      { pagePath: 'pages/messages/index', text: '消息' },
      { pagePath: 'pages/profile/index', text: '我的' }
    ]
  }
})
```

说明：

- `publish` 不是原生 tabBar 项，而是中间 FAB 跳转页。
- 使用自定义 `BottomTabBar` 实现 HTML 中间凸起发布按钮。
- `launcher` 可作为开发预览页放入 `subPackages/dev/pages/launcher`，不放入正式主包。

### 4.2 页面职责

| 页面 | 组件构成 | 主要状态 | 云函数 |
| --- | --- | --- | --- |
| `pages/plaza` | `CustomNavBar`、`SearchBar`、`SegmentedTabs`、`TopicChips`、`PostCard`、`FeedAdCard`、`LikeToast`、`BottomTabBar` | 当前频道、话题、帖子列表、点赞状态、toast 显示 | `feedList`、`postLike`、`postFavorite` |
| `pages/nearby` | `NearbyMap`、`PetPin`、`MapControls`、`LocationPill`、`NearbySheet`、`NearbyPetCard`、`MatchToast`、`BottomTabBar` | 选中宠物、Sheet 高度、筛选项、喜欢 toast | `nearbyPets`、`locationUpdate`、`matchLike` |
| `pages/messages` | `CustomNavBar`、`SearchBar`、`MessageTabs`、`ActiveUserRow`、`ConversationItem`、`BottomTabBar` | 消息分类、会话列表、未读状态 | `messageList`、`conversationRead` |
| `pages/profile` | `ProfileHero`、`StatsRow`、`ActionButtons`、`PetShelf`、`QuickGrid`、`PreferenceList`、`BottomTabBar` | 用户资料、宠物列表、开关状态 | `profileGet`、`profileUpdate`、`petList` |
| `pages/publish` | `PublishNav`、`ComposerAuthor`、`ComposerTextarea`、`MediaGrid`、`TopicSelector`、`PublishOptions`、`ComposerToolbar`、`VisibilitySheet`、`SuccessModal` | 文本、图片、话题、宠物、位置、可见范围、草稿 | `postCreate`、`draftSave`、`petList` |

## 5. 组件拆分

### 5.1 基础组件

| 组件 | 路径 | 说明 |
| --- | --- | --- |
| `PageShell` | `src/components/layout/PageShell` | 页面背景、滚动容器、安全区和底部留白 |
| `CustomNavBar` | `src/components/layout/CustomNavBar` | 自定义顶部栏，计算状态栏与胶囊避让 |
| `BottomTabBar` | `src/components/navigation/BottomTabBar` | 复刻 HTML 的底部 Tab 和中间发布 FAB |
| `Icon` | `src/components/ui/Icon` | 统一图标入口，映射原 SVG 到资产或 iconfont |
| `Avatar` | `src/components/ui/Avatar` | 渐变头像、在线点、宠物角标 |
| `Chip` | `src/components/ui/Chip` | 话题、筛选、标签选中态 |
| `SegmentedTabs` | `src/components/ui/SegmentedTabs` | 顶部频道切换和下划线 |
| `SearchBar` | `src/components/ui/SearchBar` | 搜索框视觉复用 |
| `ToastOverlay` | `src/components/feedback/ToastOverlay` | 点赞、匹配等居中放大 toast |
| `BottomSheet` | `src/components/feedback/BottomSheet` | 发布页可见范围选择、通用底部弹层 |
| `Switch` | `src/components/forms/Switch` | 复刻开关 knob 动效 |

### 5.2 业务组件

| 组件 | 路径 | 对应 HTML |
| --- | --- | --- |
| `PostCard` | `src/features/feed/components/PostCard` | `plaza.html` 的 `.post` |
| `FeedAdCard` | `src/features/feed/components/FeedAdCard` | `plaza.html` 的 `.ad-card` |
| `NearbyMap` | `src/features/nearby/components/NearbyMap` | `nearby.html` 的地图层、道路、水域、绿地 |
| `PetPin` | `src/features/nearby/components/PetPin` | `nearby.html` 的 `.pin` |
| `NearbySheet` | `src/features/nearby/components/NearbySheet` | `nearby.html` 的可拖拽 `.sheet` |
| `NearbyPetCard` | `src/features/nearby/components/NearbyPetCard` | `nearby.html` 的宠物卡片 |
| `ActiveUserRow` | `src/features/messages/components/ActiveUserRow` | `messages.html` 的活跃用户横向列表 |
| `ConversationItem` | `src/features/messages/components/ConversationItem` | `messages.html` 的 `.conv` |
| `ProfileHero` | `src/features/profile/components/ProfileHero` | `profile.html` 的 `.hero` |
| `PetShelf` | `src/features/profile/components/PetShelf` | `profile.html` 的毛孩子列表 |
| `PreferenceList` | `src/features/profile/components/PreferenceList` | `profile.html` 的设置列表 |
| `PublishComposer` | `src/features/publish/components/PublishComposer` | `publish.html` 的输入区 |
| `MediaGrid` | `src/features/publish/components/MediaGrid` | `publish.html` 的图片网格 |
| `PublishOptions` | `src/features/publish/components/PublishOptions` | `publish.html` 的关联宠物、位置、可见范围、草稿 |
| `ComposerToolbar` | `src/features/publish/components/ComposerToolbar` | `publish.html` 的底部工具栏 |

## 6. 动画与交互迁移方案

| 参考行为 | HTML 实现 | Taro 实现 |
| --- | --- | --- |
| 点赞爱心 toast | `.like-toast.show` + `scale` transition | `useToast()` 控制 `show` class，`setTimeout` 480ms 隐藏 |
| 附近匹配 toast | `.match-toast.show` | 复用 `ToastOverlay`，传入 `heart` 图标 |
| 发布页底部 Sheet | `@keyframes slideUp` | `BottomSheet` 使用 `animation: slideUp 280ms cubic-bezier(0.2, 0, 0, 1)` |
| 附近 Sheet 拖拽 | `pointer` 事件 + CSS 变量 `--sheet-h` | `useDragSheet` 用 touch 事件维护高度，snap 点按设计稿 60/220/420/620 px 等比转 rpx |
| 地图定位脉冲 | `@keyframes pulse` | 保留 WXSS keyframes，`View` 伪元素改为子节点 |
| Tab/Chip 选中 | `classList.toggle('act')` | React state 控制 `activeKey` 和 `selectedIds` |
| 发布按钮启用 | `textarea input` + disabled | `content.length > 0 && content.length <= 2000` |
| 开关滑块 | `.switch.off`、`::after` | `Switch` 组件通过 `checked` class 驱动 knob 位移 |
| 图片删除 | DOM remove | `mediaIds.filter()` 更新列表 |
| 搜索区域点击缩放 | 直接写 `style.transform` | `pressed` state + class，180ms 后还原 |

注意：

- 微信小程序不支持所有 Web 伪元素场景。复杂 `::before/::after` 需要改为显式 `View` 子节点，例如电池图标、地图 pulse、底部 home indicator。
- `position: sticky` 在发布页底部工具栏中改为 `position: fixed`，结合 `padding-bottom: env(safe-area-inset-bottom)` 避免被系统区域遮挡。
- `backdrop-filter` 兼容性需真机确认；无法完全稳定时，使用半透明背景 + 较高模糊感渐变替代。

## 7. 设计 Token

从 HTML 抽出统一 token，放入 `src/styles/tokens.scss`：

```scss
$bg: #14102b;
$bg-warm: #1c1442;
$surface: #1f1742;
$surface-2: #251c4a;
$surface-hi: #2d2255;
$fg: #f0e9ff;
$fg-2: #c7b9e0;
$muted: #8a7aab;
$border: #2e234a;
$border-soft: #251c40;
$accent: #d8b4ff;
$accent-2: #ffb3c8;
$primary: #ffd9a8;
$primary-on: #2a1d10;
$success: #8fe5b5;
$warn: #ffd166;
$danger: #ff8a9b;
$map-bg: #0e0a22;

$font-display: "Space Grotesk", "Inter", system-ui, sans-serif;
$font-body: "Inter", system-ui, -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif;

$radius-sm: 10px;
$radius-md: 16px;
$radius-lg: 24px;
$radius-pill: 9999px;
```

迁移策略：

- 原样保留色值、透明度、渐变角度和阴影参数。
- Taro 构建配置按 390px 参考宽度做 px 到 rpx 的转换；如果当前 Taro 版本对自定义 `designWidth: 390` 支持不理想，则用 750 基准并执行 `750 / 390` 的机械转换。
- 字体在微信里不能稳定加载 Google Fonts。正式版以系统字体 + `PingFang SC` 为准；若必须完全还原 `Space Grotesk/Inter`，将字体文件放入云存储或本地资产并通过 `Taro.loadFontFace` 加载。

## 8. 数据模型

### 8.1 TypeScript 类型

```ts
export interface UserProfile {
  _id: string
  openid: string
  nickname: string
  avatarUrl?: string
  location?: string
  yearsWithPets?: number
  level: number
  stats: {
    posts: number
    following: number
    followers: number
    favorites: number
  }
  preferences: {
    notifications: boolean
    nearbyVisible: boolean
  }
}

export interface Pet {
  _id: string
  ownerId: string
  name: string
  species: 'dog' | 'cat' | 'other'
  breed: string
  ageText: string
  avatarFileId?: string
  tags: string[]
  location?: GeoPoint
  online?: boolean
}

export interface Post {
  _id: string
  authorId: string
  petId?: string
  content: string
  topics: string[]
  media: MediaAsset[]
  locationText?: string
  visibility: 'public' | 'friends' | 'private'
  counts: {
    likes: number
    comments: number
    shares: number
    favorites: number
  }
  likedByMe?: boolean
  favoritedByMe?: boolean
  createdAt: number
}

export interface Conversation {
  _id: string
  type: 'single' | 'group' | 'system'
  title: string
  avatarKey?: string
  preview: string
  unreadCount: number
  pinned?: boolean
  muted?: boolean
  updatedAt: number
}
```

### 8.2 云数据库集合

| 集合 | 用途 | 关键索引 |
| --- | --- | --- |
| `users` | 用户基础资料、偏好、统计 | `openid` 唯一 |
| `pets` | 宠物档案 | `ownerId`、`location` |
| `posts` | 动态内容 | `visibility + createdAt`、`authorId + createdAt`、`topics` |
| `postLikes` | 点赞关系 | `postId + userId` 唯一 |
| `postFavorites` | 收藏关系 | `postId + userId` 唯一 |
| `comments` | 评论 | `postId + createdAt` |
| `locations` | 附近页定位快照 | `userId`、`geo` |
| `matches` | 附近喜欢/匹配 | `fromUserId + toPetId` |
| `conversations` | 会话元信息 | `memberIds`、`updatedAt` |
| `messages` | 消息内容 | `conversationId + createdAt` |
| `notifications` | 系统通知 | `userId + read + createdAt` |
| `drafts` | 发布草稿 | `userId + updatedAt` |

## 9. 云函数设计

统一入口原则：

- 小程序端通过 `Taro.cloud.callFunction` 调用云函数。
- 除云存储上传文件外，业务写操作都走云函数，云函数内校验 `openid`、参数、权限和数据归属。
- 查询函数返回页面所需 DTO，减少小程序端多次拼接请求。
- 点赞、收藏、计数更新在云函数内用事务或幂等逻辑完成。

| 云函数 | 入参 | 出参 | 说明 |
| --- | --- | --- | --- |
| `login` | `{ userInfo? }` | `{ openid, user }` | 获取 openid，初始化或更新用户 |
| `feedList` | `{ channel, topic?, cursor?, pageSize }` | `{ list, nextCursor }` | 广场/关注/附近信息流 |
| `postCreate` | `{ content, topics, media, petId?, location?, visibility }` | `{ postId }` | 发布动态并更新统计 |
| `postLike` | `{ postId, liked }` | `{ liked, likes }` | 幂等点赞/取消点赞 |
| `postFavorite` | `{ postId, favorited }` | `{ favorited, favorites }` | 幂等收藏 |
| `draftSave` | `{ draft }` | `{ draftId, updatedAt }` | 保存发布草稿 |
| `nearbyPets` | `{ location, filters }` | `{ list }` | 附近宠物列表和地图 pin |
| `locationUpdate` | `{ location, visible }` | `{ ok }` | 更新自己的附近可见状态 |
| `matchLike` | `{ petId }` | `{ matched }` | 附近页喜欢/匹配 |
| `messageList` | `{ tab, cursor? }` | `{ activeUsers, conversations, nextCursor }` | 消息页聚合数据 |
| `conversationRead` | `{ conversationId }` | `{ unreadCount }` | 标记会话已读 |
| `profileGet` | `{ userId? }` | `{ user, pets }` | 获取我的/他人资料 |
| `profileUpdate` | `{ patch }` | `{ user }` | 更新资料和偏好 |
| `petList` | `{ ownerId? }` | `{ list }` | 宠物列表 |
| `petSave` | `{ pet }` | `{ petId }` | 创建或更新宠物 |

### 9.1 云开发工程配置

`project.config.json` 需要显式声明 Taro 构建产物和云函数根目录：

```json
{
  "miniprogramRoot": "dist/",
  "cloudfunctionRoot": "cloudfunctions/",
  "setting": {
    "urlCheck": true,
    "es6": true,
    "postcss": true,
    "minified": true
  }
}
```

`src/app.tsx` 中初始化云开发环境：

```ts
import Taro from '@tarojs/taro'

const cloudEnv = process.env.TARO_APP_CLOUD_ENV

if (process.env.TARO_ENV === 'weapp' && cloudEnv) {
  Taro.cloud.init({
    env: cloudEnv,
    traceUser: true
  })
}
```

环境 ID 不写死在页面代码里，放到 `config/dev.ts`、`config/prod.ts` 或 `.env`，方便区分开发、测试和正式环境。

云函数目录采用单函数目录结构，便于微信开发者工具识别和单独部署：

```text
cloudfunctions/
  login/
    index.ts
    package.json
  feedList/
    index.ts
    package.json
  postCreate/
    index.ts
    package.json
  postLike/
    index.ts
    package.json
  postFavorite/
    index.ts
    package.json
  draftSave/
    index.ts
    package.json
  nearbyPets/
    index.ts
    package.json
  locationUpdate/
    index.ts
    package.json
  matchLike/
    index.ts
    package.json
  messageList/
    index.ts
    package.json
  conversationRead/
    index.ts
    package.json
  profileGet/
    index.ts
    package.json
  profileUpdate/
    index.ts
    package.json
  petList/
    index.ts
    package.json
  petSave/
    index.ts
    package.json
```

## 10. 客户端服务层

客户端不在页面里直接散落 `callFunction`，统一封装：

```ts
export async function callCloud<TReq extends object, TRes>(
  name: CloudFunctionName,
  data: TReq
): Promise<TRes> {
  const res = await Taro.cloud.callFunction({ name, data })
  return res.result as TRes
}
```

服务分层：

```text
src/services/
  cloud.ts              # callCloud、错误归一化、loading guard
  auth.service.ts       # login
  feed.service.ts       # feedList/postLike/postFavorite
  publish.service.ts    # postCreate/draftSave/uploadMedia
  nearby.service.ts     # nearbyPets/locationUpdate/matchLike
  message.service.ts    # messageList/conversationRead
  profile.service.ts    # profileGet/profileUpdate/petList/petSave
```

页面只依赖 service 和 hooks，不直接依赖云函数细节。

## 11. 完整目录结构

```text
Pet/
  project.config.json
  project.private.config.json
  package.json
  tsconfig.json
  config/
    index.ts
    dev.ts
    prod.ts
  src/
    app.config.ts
    app.scss
    app.tsx
    assets/
      icons/
        compass.svg
        heart.svg
        message.svg
        plus.svg
        user.svg
        search.svg
        map-pin.svg
        more.svg
        close.svg
      images/
        README.md
    components/
      layout/
        PageShell/
          index.tsx
          index.scss
        CustomNavBar/
          index.tsx
          index.scss
        SafeAreaBottom/
          index.tsx
          index.scss
      navigation/
        BottomTabBar/
          index.tsx
          index.scss
          tabConfig.ts
      ui/
        Avatar/
          index.tsx
          index.scss
        Chip/
          index.tsx
          index.scss
        Icon/
          index.tsx
          iconMap.ts
          index.scss
        SearchBar/
          index.tsx
          index.scss
        SegmentedTabs/
          index.tsx
          index.scss
        Switch/
          index.tsx
          index.scss
      feedback/
        BottomSheet/
          index.tsx
          index.scss
        ToastOverlay/
          index.tsx
          index.scss
    features/
      feed/
        components/
          FeedAdCard/
            index.tsx
            index.scss
          PostCard/
            index.tsx
            index.scss
        feed.types.ts
      nearby/
        components/
          MapControls/
            index.tsx
            index.scss
          NearbyMap/
            index.tsx
            index.scss
          NearbyPetCard/
            index.tsx
            index.scss
          NearbySheet/
            index.tsx
            index.scss
          PetPin/
            index.tsx
            index.scss
        nearby.types.ts
      messages/
        components/
          ActiveUserRow/
            index.tsx
            index.scss
          ConversationItem/
            index.tsx
            index.scss
        message.types.ts
      profile/
        components/
          PetShelf/
            index.tsx
            index.scss
          PreferenceList/
            index.tsx
            index.scss
          ProfileHero/
            index.tsx
            index.scss
          QuickGrid/
            index.tsx
            index.scss
          StatsRow/
            index.tsx
            index.scss
        profile.types.ts
      publish/
        components/
          ComposerToolbar/
            index.tsx
            index.scss
          MediaGrid/
            index.tsx
            index.scss
          PublishComposer/
            index.tsx
            index.scss
          PublishOptions/
            index.tsx
            index.scss
          VisibilitySheet/
            index.tsx
            index.scss
          SuccessModal/
            index.tsx
            index.scss
        publish.types.ts
    hooks/
      useCloudQuery.ts
      useDragSheet.ts
      useSystemLayout.ts
      useToast.ts
      useUploadMedia.ts
    pages/
      plaza/
        index.config.ts
        index.tsx
        index.scss
      nearby/
        index.config.ts
        index.tsx
        index.scss
      publish/
        index.config.ts
        index.tsx
        index.scss
      messages/
        index.config.ts
        index.tsx
        index.scss
      profile/
        index.config.ts
        index.tsx
        index.scss
    services/
      auth.service.ts
      cloud.ts
      feed.service.ts
      message.service.ts
      nearby.service.ts
      profile.service.ts
      publish.service.ts
    store/
      session.store.ts
      ui.store.ts
    styles/
      animations.scss
      mixins.scss
      tokens.scss
      utilities.scss
    types/
      cloud.ts
      domain.ts
      global.d.ts
    utils/
      date.ts
      px.ts
      validators.ts
  cloudfunctions/
    login/
      index.ts
      package.json
    feedList/
      index.ts
      package.json
    postCreate/
      index.ts
      package.json
    postLike/
      index.ts
      package.json
    postFavorite/
      index.ts
      package.json
    draftSave/
      index.ts
      package.json
    nearbyPets/
      index.ts
      package.json
    locationUpdate/
      index.ts
      package.json
    matchLike/
      index.ts
      package.json
    messageList/
      index.ts
      package.json
    conversationRead/
      index.ts
      package.json
    profileGet/
      index.ts
      package.json
    profileUpdate/
      index.ts
      package.json
    petList/
      index.ts
      package.json
    petSave/
      index.ts
      package.json
  docs/
    taro-miniapp-design.md
  refrence_html/
    messages.html
    nearby.html
    plaza.html
    profile.html
    publish.html
    wangquan-ios-launcher.html
```

## 12. 迁移步骤

### 第 1 阶段：工程初始化

1. 使用 Taro React TypeScript 模板初始化项目。
2. 配置微信小程序编译、`navigationStyle: custom`、自定义 tabBar。
3. 配置云开发环境 ID，`app.tsx` 中初始化 `Taro.cloud.init({ env })`。
4. 建立 `styles/tokens.scss`、`animations.scss` 和基础布局组件。

### 第 2 阶段：静态视觉还原

1. 先迁移 `plaza`，抽出全局 `PageShell`、`CustomNavBar`、`BottomTabBar`、`PostCard`。
2. 再迁移 `messages` 和 `profile`，复用头像、搜索、tab、switch。
3. 迁移 `publish`，重点处理 `Textarea`、底部 fixed toolbar、Sheet 和成功弹层。
4. 迁移 `nearby`，重点处理地图层、pin 布局、底部拖拽 Sheet。

### 第 3 阶段：交互和动画

1. 全部 DOM 操作替换为 state。
2. 完整还原点赞 toast、匹配 toast、Sheet slideUp、地图 pulse、switch knob、FAB active。
3. 用微信开发者工具和真机分别确认 `backdrop-filter`、fixed 底部、safe-area、键盘弹起表现。

### 第 4 阶段：云函数接入

1. 先实现 `login`、`feedList`、`profileGet`，让页面能加载真实用户态。
2. 接入 `postLike`、`postFavorite`，验证计数幂等。
3. 接入 `postCreate` 和媒体上传，发布后跳转广场并展示新动态。
4. 接入 `nearbyPets`、`matchLike`、`messageList`、`conversationRead`。
5. 补充数据库权限规则：客户端默认只读必要公开数据，写入走云函数。

### 第 5 阶段：验收

1. 与参考 HTML 做逐页截图对比，基准宽度 390px。
2. 检查 320/375/390/414 宽度下内容不重叠、不溢出。
3. 真机检查 iPhone 刘海屏、普通屏、安卓微信的状态栏、胶囊和底部安全区。
4. 云函数使用测试环境数据跑通发布、点赞、匹配、消息已读、资料更新。

## 13. 风险与处理

| 风险 | 影响 | 处理 |
| --- | --- | --- |
| HTML 使用大量 inline SVG | 微信小程序无法像 Web 一样直接渲染全部 SVG DOM | 将图标资产化为 iconfont 或图片资产；地图 SVG 改为 CSS/Canvas 组合 |
| Google Fonts 不可直接加载 | 字体观感略有差异 | 本地/云存储加载字体，或确认系统字体可接受 |
| `backdrop-filter` 兼容性 | 玻璃模糊效果可能变弱 | 半透明深色背景 + 渐变阴影兜底 |
| `position: sticky`/伪元素差异 | 发布页底部栏和装饰元素偏移 | fixed + safe area；伪元素改显式节点 |
| 附近页拖拽性能 | touch move 频繁 setState 可能卡顿 | 用 `useRef` 缓存拖拽值，必要时节流，最终 snap 时 setState |
| 视觉 100% 与真实小程序系统 UI 冲突 | 状态栏/胶囊不可完全控制 | 明确只对产品内屏做 100% 还原；系统区域用真实安全区适配 |

## 14. 参考文档

- Taro 官方文档：`https://docs.taro.zone/`
- Taro 云开发 API：`https://docs.taro.zone/docs/apis/cloud/`
- 微信小程序云开发文档：`https://developers.weixin.qq.com/miniprogram/dev/wxcloud/basis/getting-started.html`
- 微信云函数调用：`https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-sdk-api/functions/callFunction/client.callFunction.html`
