# Genex 小程序 + H5 开发指南

> 基于 Taro 3.x 的跨端轻量级应用

---

## 1. 产品定位

小程序/H5作为**轻量获客入口**，主要通过社交分享引流，提供核心消费者功能的精简版。完整功能引导下载原生App。

**覆盖平台**：
- 微信小程序（主要）
- 支付宝小程序
- H5（移动浏览器、App内嵌WebView）

---

## 2. 技术栈

| 技术 | 版本 | 用途 |
|------|------|------|
| **Taro** | 3.x | 跨端框架（React语法） |
| **React** | 18.x | UI框架 |
| **TypeScript** | 5.x | 类型安全 |
| **Zustand** | 4.x | 状态管理 |
| **Taro UI / NutUI** | 最新 | 跨端UI组件库 |

---

## 3. 项目结构

```
genex-mini/
├── src/
│   ├── app.ts                       # 应用入口
│   ├── app.config.ts                # 全局配置
│   ├── pages/
│   │   ├── index/                   # 首页（券推荐）
│   │   ├── coupon-detail/           # 券详情
│   │   ├── purchase/                # 购买页
│   │   ├── my-coupons/              # 我的券
│   │   ├── redeem/                  # 券使用（出示券码）
│   │   ├── login/                   # 登录/注册
│   │   └── profile/                 # 个人中心
│   ├── components/
│   │   ├── coupon-card/             # 券卡片组件
│   │   ├── ai-guide/                # AI引导气泡
│   │   └── share-card/              # 分享卡片
│   ├── services/
│   │   ├── api.ts                   # API请求封装
│   │   └── auth.ts                  # 认证服务
│   ├── stores/
│   │   ├── user-store.ts            # 用户状态
│   │   └── coupon-store.ts          # 券状态
│   ├── utils/
│   │   ├── share.ts                 # 分享工具
│   │   └── platform.ts             # 平台判断
│   └── assets/
├── config/
│   ├── index.ts                     # Taro编译配置
│   ├── dev.ts
│   └── prod.ts
└── package.json
```

---

## 4. 核心功能（精简版）

### 4.1 功能矩阵

| 功能 | 小程序/H5 | 原生App |
|------|----------|---------|
| 浏览券市场 | ✅ | ✅ |
| 购买券 | ✅ | ✅ |
| 我的券 | ✅ | ✅ |
| 出示券码使用 | ✅ | ✅ |
| 二级市场交易 | ❌（引导下载App） | ✅ |
| P2P转赠 | ❌（引导下载App） | ✅ |
| AI Agent完整对话 | ❌（精简版） | ✅ |
| KYC认证 | L0/L1 | L0/L1/L2/L3 |

### 4.2 首页

```tsx
// src/pages/index/index.tsx
import { View, ScrollView } from '@tarojs/components';
import { useEffect } from 'react';
import { useCouponStore } from '@/stores/coupon-store';
import CouponCard from '@/components/coupon-card';
import AiGuide from '@/components/ai-guide';

export default function IndexPage() {
  const { hotCoupons, fetchHotCoupons } = useCouponStore();

  useEffect(() => {
    fetchHotCoupons();
  }, []);

  return (
    <View className="index-page">
      {/* AI轻量推荐条 */}
      <AiGuide type="recommendation" />

      {/* 搜索栏 */}
      <SearchBar placeholder="搜索券..." />

      {/* 分类标签 */}
      <CategoryTabs />

      {/* 券列表 */}
      <ScrollView scrollY>
        {hotCoupons.map((coupon) => (
          <CouponCard key={coupon.id} coupon={coupon} />
        ))}
      </ScrollView>
    </View>
  );
}
```

### 4.3 购买流程

```tsx
// src/pages/purchase/index.tsx
export default function PurchasePage() {
  const { id } = useRouter().params;
  const coupon = useCouponDetail(id!);

  const handlePurchase = async () => {
    // 微信小程序：调用微信支付
    // H5：调用支付宝/银联等H5支付
    const paymentResult = await Taro.requestPayment({
      ...paymentParams,
    });

    if (paymentResult.errMsg === 'requestPayment:ok') {
      // 后端自动完成：法币→稳定币→链上原子交换
      await api.confirmPurchase(orderId);
      Taro.navigateTo({ url: '/pages/purchase-success/index' });
    }
  };

  return (
    <View>
      <CouponDetailCard coupon={coupon} />
      <PriceSection price={coupon.currentPrice} faceValue={coupon.faceValue} />
      <Button onClick={handlePurchase}>立即购买</Button>
    </View>
  );
}
```

### 4.4 出示券码

```tsx
// src/pages/redeem/index.tsx
export default function RedeemPage() {
  const { couponId } = useRouter().params;
  const qrCode = useRedeemCode(couponId!);

  return (
    <View className="redeem-page">
      <Text>出示给商户扫码</Text>
      <QRCode value={qrCode.data} size={200} />
      <Text className="coupon-code">{qrCode.numericCode}</Text>
      <BrightnessMaxWidget /> {/* 自动调高亮度 */}
      <CountdownTimer expiry={qrCode.expiresAt} />
    </View>
  );
}
```

---

## 5. 社交分享

```typescript
// src/utils/share.ts
export function configShare(coupon: Coupon) {
  return {
    title: `${coupon.issuerName} ${coupon.faceValue}元券 仅${coupon.currentPrice}元`,
    path: `/pages/coupon-detail/index?id=${coupon.id}&from=share`,
    imageUrl: coupon.shareImage || coupon.imageUrl,
  };
}

// 小程序页面配置
export default {
  onShareAppMessage() {
    return configShare(currentCoupon);
  },
  onShareTimeline() {
    return {
      title: `限时折扣券`,
      query: `id=${currentCoupon.id}`,
    };
  },
};
```

---

## 6. AI Agent（精简版）

小程序/H5中AI Agent以轻量形式集成：

| 组件 | 说明 |
|------|------|
| 推荐条 | 首页顶部横向滚动AI推荐标签 |
| 购买引导 | 新用户首次进入时的对话气泡引导 |

```tsx
// src/components/ai-guide/index.tsx
export default function AiGuide({ type }: { type: 'recommendation' | 'purchase' }) {
  const suggestions = useAiSuggestions(type);

  if (type === 'recommendation') {
    return (
      <ScrollView scrollX className="ai-suggest-bar">
        {suggestions.map((s) => (
          <Tag key={s.id} onClick={() => navigateToCoupon(s.couponId)}>
            {s.text}
          </Tag>
        ))}
      </ScrollView>
    );
  }

  return <ChatBubble message={suggestions[0]?.text} />;
}
```

---

## 7. 平台适配

```typescript
// src/utils/platform.ts
import Taro from '@tarojs/taro';

export function getPlatform(): 'weapp' | 'alipay' | 'h5' {
  return Taro.getEnv() as any;
}

export function getPaymentMethod() {
  switch (getPlatform()) {
    case 'weapp': return 'wechat_pay';
    case 'alipay': return 'alipay';
    case 'h5': return 'h5_pay';
  }
}
```

### 条件编译

```typescript
// Taro支持条件编译
// #ifdef WEAPP
// 微信小程序专用代码
wx.login({ success: (res) => { /* ... */ } });
// #endif

// #ifdef H5
// H5专用代码
window.location.href = authUrl;
// #endif
```

---

## 8. 性能优化

| 策略 | 实现 |
|------|------|
| 分包加载 | 主包只含首页+登录，其余分包 |
| 图片优化 | WebP格式 + CDN + 懒加载 |
| 数据预拉取 | `onPrefetch` 预加载详情页数据 |
| 骨架屏 | 关键页面skeleton loading |
| 缓存策略 | 券列表本地缓存，增量更新 |

### 分包配置

```typescript
// src/app.config.ts
export default defineAppConfig({
  pages: [
    'pages/index/index',
    'pages/login/index',
  ],
  subPackages: [
    {
      root: 'pages/coupon-detail',
      pages: ['index'],
    },
    {
      root: 'pages/purchase',
      pages: ['index'],
    },
    {
      root: 'pages/my-coupons',
      pages: ['index'],
    },
  ],
});
```

---

## 9. 测试与发布

| 平台 | 发布流程 |
|------|---------|
| 微信小程序 | 开发版 → 体验版 → 审核 → 正式版 |
| 支付宝小程序 | 开发版 → 灰度 → 审核 → 正式版 |
| H5 | CI/CD自动部署至CDN |

---

## 10. 多语言与国际化

### 10.1 i18n配置

```typescript
// src/utils/i18n.ts
import Taro from '@tarojs/taro';

// 支持语言：中文（默认）、英文、日文
type Locale = 'zh-CN' | 'en-US' | 'ja-JP';

const messages: Record<Locale, Record<string, string>> = {
  'zh-CN': {
    'home.title': '发现好券',
    'coupon.buy': '立即购买',
    'coupon.faceValue': '面值',
    'coupon.discount': '折扣',
    'coupon.expiry': '有效期至',
    'my.coupons': '我的券',
    'my.orders': '我的订单',
    'redeem.show': '出示给商户扫码',
    // ...
  },
  'en-US': {
    'home.title': 'Discover Deals',
    'coupon.buy': 'Buy Now',
    'coupon.faceValue': 'Face Value',
    'coupon.discount': 'Discount',
    'coupon.expiry': 'Valid Until',
    'my.coupons': 'My Coupons',
    'my.orders': 'My Orders',
    'redeem.show': 'Show to Merchant',
    // ...
  },
  'ja-JP': {
    'home.title': 'クーポンを探す',
    'coupon.buy': '今すぐ購入',
    'coupon.faceValue': '額面',
    'coupon.discount': '割引',
    'coupon.expiry': '有効期限',
    'my.coupons': 'マイクーポン',
    'my.orders': '注文履歴',
    'redeem.show': '店舗に提示',
    // ...
  },
};

export function useI18n() {
  const locale = useLocaleStore((s) => s.locale);
  const t = (key: string) => messages[locale]?.[key] || messages['zh-CN'][key] || key;
  return { t, locale };
}

// 自动检测系统语言
export function detectLocale(): Locale {
  const systemInfo = Taro.getSystemInfoSync();
  const lang = systemInfo.language || 'zh-CN';
  if (lang.startsWith('en')) return 'en-US';
  if (lang.startsWith('ja')) return 'ja-JP';
  return 'zh-CN';
}
```

### 10.2 多币种展示

```typescript
// src/utils/currency.ts
export function formatPrice(amount: number, currency: string = 'USD'): string {
  const formatters: Record<string, Intl.NumberFormat> = {
    USD: new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }),
    CNY: new Intl.NumberFormat('zh-CN', { style: 'currency', currency: 'CNY' }),
    JPY: new Intl.NumberFormat('ja-JP', { style: 'currency', currency: 'JPY' }),
    SGD: new Intl.NumberFormat('en-SG', { style: 'currency', currency: 'SGD' }),
  };
  return formatters[currency]?.format(amount) || `$${amount.toFixed(2)}`;
}
```

---

*文档版本: v2.0*
*基于: Genex 券交易平台 - 软件需求规格说明书 v4.1*
*技术栈: Taro 3.x + React 18 + TypeScript*
*更新: 补充多语言国际化(i18n)、多币种展示*
