Skip to content

商品详情功能示例

本文档提供商品详情 API 的基础使用示例。

基础使用

获取商品详情

typescript
import { Goofish } from "goofish-client";

const client = new Goofish({ cookie: "cookie2=xxxx" });

const result = await client.api.mtop.item.getDetail({
  itemId: "95xxxxxxxxx334",
});

console.log(result);

提取基本信息

typescript
const response = await client.api.mtop.item.getDetail({
  itemId: "95xxxxxxxxx334",
});

if (response.ret[0] === "SUCCESS::调用成功") {
  const itemDetail = response.data;

  console.log("商品标题:", itemDetail.itemDO.title);
  console.log("商品价格:", itemDetail.itemDO.soldPrice);
  console.log("商品描述:", itemDetail.itemDO.desc);
  console.log("卖家昵称:", itemDetail.sellerDO.nick);
  console.log("浏览次数:", itemDetail.itemDO.browseCnt);
  console.log("收藏次数:", itemDetail.itemDO.collectCnt);
}

实用示例

商品信息格式化

typescript
function formatItemDetail(itemDetail: ItemDetailResponse) {
  const { itemDO, sellerDO } = itemDetail;

  return {
    // 基本信息
    id: itemDO.itemId,
    title: itemDO.title,
    description: itemDO.desc,

    // 价格信息
    price: {
      current: itemDO.soldPrice,
      original: itemDO.originalPrice,
      shipping: itemDO.transportFee,
    },

    // 统计信息
    stats: {
      views: itemDO.browseCnt,
      favorites: itemDO.collectCnt,
      wants: itemDO.wantCnt,
    },

    // 商品状态
    status: {
      code: itemDO.itemStatus,
      text: itemDO.itemStatusStr,
      online: itemDO.itemStatus === 0,
    },

    // 图片列表
    images: itemDO.imageInfos.map((img) => ({
      url: img.url,
      isMain: img.major,
      dimensions: {
        width: img.widthSize,
        height: img.heightSize,
      },
    })),

    // 卖家信息
    seller: {
      id: sellerDO.sellerId,
      nickname: sellerDO.nick,
      city: sellerDO.city,
      avatar: sellerDO.portraitUrl,
      signature: sellerDO.signature,
      soldCount: sellerDO.hasSoldNumInteger,
      replyRate: sellerDO.replyRatio24h,
      replyTime: sellerDO.replyInterval,
      lastSeen: sellerDO.lastVisitTime,
    },

    // 时间信息
    createTime: new Date(itemDO.gmtCreate),
    serverTime: itemDetail.serverTime,
  };
}

// 使用示例
const response = await client.api.mtop.item.getDetail({
  itemId: "95xxxxxxxxx334",
});

if (response.ret[0] === "SUCCESS::调用成功") {
  const formattedItem = formatItemDetail(response.data);
  console.log(formattedItem);
}

图片处理

typescript
function processItemImages(itemDetail: ItemDetailResponse) {
  const images = itemDetail.itemDO.imageInfos;

  // 获取主图
  const mainImage = images.find((img) => img.major);

  // 获取所有图片
  const allImages = images.map((img) => ({
    url: img.url,
    isMain: img.major,
    width: img.widthSize,
    height: img.heightSize,
    // 生成不同尺寸的图片URL
    thumbnail: `${img.url}_200x200q90.jpg`,
    medium: `${img.url}_640x640q90.jpg`,
  }));

  return {
    mainImage,
    allImages,
    imageCount: images.length,
  };
}

商品标签处理

typescript
function processItemLabels(itemDetail: ItemDetailResponse) {
  const labels = itemDetail.itemDO.itemLabelExtList;

  return labels.map((label) => ({
    id: label.labelId,
    text: label.text,
    type: label.labelType,
    source: label.from,
    categoryId: label.channelCateId,
    // 解析属性
    properties: parseProperties(label.properties),
  }));
}

function parseProperties(properties: string) {
  // 解析属性字符串,格式如: "20879##成色:10941990949##轻微穿着痕迹"
  const parts = properties.split("##");
  const result: Record<string, string> = {};

  for (let i = 1; i < parts.length; i += 2) {
    if (parts[i] && parts[i + 1]) {
      const [key] = parts[i].split(":");
      result[key] = parts[i + 1];
    }
  }

  return result;
}

卖家信用评估

typescript
function evaluateSellerCredit(sellerDO: SellerDO) {
  const {
    hasSoldNumInteger,
    replyRatio24h,
    zhimaAuth,
    identityTags,
    levelTags,
  } = sellerDO;

  // 销售信用评分
  const salesScore = Math.min(hasSoldNumInteger * 2, 100);

  // 响应信用评分
  const replyRate = parseFloat(replyRatio24h.replace("%", ""));
  const responseScore = replyRate;

  // 认证信用评分
  let authScore = 0;
  if (zhimaAuth) authScore += 30;
  if (identityTags.length > 0) authScore += 20;
  if (levelTags.length > 0) authScore += 10;

  const totalScore = (salesScore + responseScore + authScore) / 3;

  return {
    totalScore: Math.round(totalScore),
    breakdown: {
      sales: salesScore,
      response: responseScore,
      auth: authScore,
    },
    level: totalScore >= 80 ? "高" : totalScore >= 60 ? "中" : "低",
    badges: {
      zhimaAuth,
      identityVerified: identityTags.length > 0,
      hasLevel: levelTags.length > 0,
    },
  };
}

错误处理示例

基础错误处理

typescript
async function getItemDetailSafely(itemId: string) {
  try {
    const result = await client.api.mtop.item.getDetail({ itemId });

    if (result.ret[0] === "SUCCESS::调用成功") {
      return {
        success: true,
        data: result.data,
      };
    } else {
      return {
        success: false,
        error: result.message || "获取商品详情失败",
        code: result.ret[0],
      };
    }
  } catch (error) {
    return {
      success: false,
      error: error.message || "网络请求失败",
      code: "NETWORK_ERROR",
    };
  }
}

// 使用示例
const result = await getItemDetailSafely("95xxxxxxxxx334");
if (result.success) {
  console.log(result.data);
} else {
  console.error(result.error);
}

批量获取商品详情

typescript
async function getBatchItemDetails(itemIds: string[]) {
  const results = await Promise.allSettled(
    itemIds.map((id) => client.api.mtop.item.getDetail({ itemId: id }))
  );

  return results.map((result, index) => {
    if (
      result.status === "fulfilled" &&
      result.value.ret[0] === "SUCCESS::调用成功"
    ) {
      return {
        itemId: itemIds[index],
        success: true,
        data: result.value.data,
      };
    } else {
      return {
        itemId: itemIds[index],
        success: false,
        error:
          result.status === "rejected"
            ? result.reason.message
            : result.value.message,
      };
    }
  });
}

// 使用示例
const itemIds = ["95xxxxxxxxx334", "950699239335", "950699239336"];
const batchResults = await getBatchItemDetails(itemIds);

batchResults.forEach((result) => {
  if (result.success) {
    console.log(`商品 ${result.itemId}:`, result.data.itemDO.title);
  } else {
    console.error(`商品 ${result.itemId} 获取失败:`, result.error);
  }
});

数据缓存示例

简单内存缓存

typescript
class ItemDetailCache {
  private cache = new Map<
    string,
    {
      data: ItemDetailResponse;
      timestamp: number;
    }
  >();

  private readonly TTL = 5 * 60 * 1000; // 5分钟

  async getItemDetail(itemId: string): Promise<ItemDetailResponse | null> {
    const cached = this.cache.get(itemId);

    if (cached && Date.now() - cached.timestamp < this.TTL) {
      return cached.data;
    }

    try {
      const result = await client.api.mtop.item.getDetail({ itemId });

      if (result.ret[0] === "SUCCESS::调用成功") {
        this.cache.set(itemId, {
          data: result.data,
          timestamp: Date.now(),
        });
        return result.data;
      }
    } catch (error) {
      console.error("获取商品详情失败:", error);
    }

    return null;
  }

  clearExpired(): void {
    const now = Date.now();
    for (const [key, value] of this.cache.entries()) {
      if (now - value.timestamp >= this.TTL) {
        this.cache.delete(key);
      }
    }
  }
}

// 使用示例
const cache = new ItemDetailCache();
const itemDetail = await cache.getItemDetail("95xxxxxxxxx334");

完整示例

商品详情页面组件

typescript
interface ItemDetailPageProps {
  itemId: string;
}

async function ItemDetailPage({ itemId }: ItemDetailPageProps) {
  const result = await getItemDetailSafely(itemId);

  if (!result.success) {
    return {
      error: result.error,
      code: result.code,
    };
  }

  const itemDetail = formatItemDetail(result.data);
  const sellerCredit = evaluateSellerCredit(result.data.sellerDO);
  const images = processItemImages(result.data);
  const labels = processItemLabels(result.data);

  return {
    item: itemDetail,
    seller: {
      ...itemDetail.seller,
      credit: sellerCredit,
    },
    images: images,
    labels: labels,
    recommendations: [], // 可以结合搜索API获取相关推荐
  };
}

// 使用示例
const pageData = await ItemDetailPage({ itemId: "95xxxxxxxxx334" });
console.log(pageData);

基于 GPL-3.0 许可证发布