JSPM

  • Created
  • Published
  • Downloads 14
  • Score
    100M100P100Q73747F
  • License MIT

GT6 SDK for articles management - A comprehensive JavaScript/TypeScript library for managing articles, categories, and tags in GT6 platform

Package Exports

  • @gt6/sdk

Readme

@gt6/sdk

GT6 SDK 是一个用于管理文章、分类和标签的JavaScript/TypeScript库,专门为GT6平台设计。

安装

npm install @gt6/sdk

快速开始

基本使用

import { GT6SDK } from '@gt6/sdk';

// 初始化SDK
const sdk = new GT6SDK({
  baseUrl: 'https://data.shopasb.io',
  platformId: '1750838492',
  rootCategoryId: '671920', // 可选,默认为671920
  tagAlias: '001' // 可选,默认为001
});

// 获取文章详情
const article = await sdk.getArticle(921546067);
console.log(article.title);

// 获取分类列表
const categories = await sdk.getCategories();
console.log('分类列表:', categories.map(cat => cat.categoryName));

// 获取标签列表
const tags = await sdk.getTags();
console.log('标签列表:', tags.map(tag => tag.tagName));

// 根据分类获取文章
const categoryArticles = await sdk.getArticlesByCategory(782714);
console.log(`分类文章总数: ${categoryArticles.total}`);

// 根据标签获取文章
const tagArticles = await sdk.getArticlesByTag(136424);
console.log(`标签文章总数: ${tagArticles.total}`);

// 获取分类层级路径
const categoryPath = await sdk.getCategoryPath(782714);
console.log('面包屑路径:', categoryPath.breadcrumbs.map(crumb => crumb.categoryName).join(' > '));

// 获取子分类
const subCategories = await sdk.getSubCategories(671920);
console.log(`子分类数量: ${subCategories.total}`);

高级功能

// 按分类获取文章
const categoryArticles = await sdk.getArticlesByCategory(782714);

// 按标签获取文章
const tagArticles = await sdk.getArticlesByTag(136424);

// 获取分类层级路径(用于面包屑导航)
const categoryPath = await sdk.getCategoryPath(782714);

// 获取子分类
const subCategories = await sdk.getSubCategories(671920);

// 获取已发布的文章
const publishedArticles = await sdk.articles.getPublishedArticles();

// 搜索文章
const searchResults = await sdk.articles.searchArticles('CRM');

// 获取文章统计信息
const stats = await sdk.articles.getArticleStats();
console.log(`总文章数: ${stats.total}`);
console.log(`已发布: ${stats.published}`);
console.log(`草稿: ${stats.draft}`);

// 获取推荐文章
const recommended = await sdk.articles.getRecommendedArticles(921546067, 5);

在Astro项目中使用

// [id].astro
---
import { GT6SDK } from '@gt6/sdk';

const sdk = new GT6SDK({
  baseUrl: 'https://data.shopasb.io',
  platformId: '1750838492'
});

const { id } = Astro.params;
const article = await sdk.getArticle(id);
const recommended = await sdk.articles.getRecommendedArticles(Number(id), 3);
---

<html>
  <head>
    <title>{article.title}</title>
  </head>
  <body>
    <h1>{article.title}</h1>
    <div set:html={article.content}></div>
    
    <h2>推荐文章</h2>
    <ul>
      {recommended.map(rec => (
        <li><a href={`/articles/${rec.articleId}`}>{rec.title}</a></li>
      ))}
    </ul>
  </body>
</html>

面包屑导航使用示例

基本面包屑导航

// 获取分类层级路径
const categoryPath = await sdk.getCategoryPath(782714);

// 输出面包屑数据
console.log('当前分类:', categoryPath.currentCategory?.categoryName);
console.log('完整路径:', categoryPath.path.map(cat => cat.categoryName).join(' > '));

// 前端面包屑导航使用
categoryPath.breadcrumbs.forEach((crumb, index) => {
  if (index < categoryPath.breadcrumbs.length - 1) {
    console.log(`<a href="/category/${crumb.categoryId}">${crumb.categoryName}</a> >`);
  } else {
    console.log(`<span>${crumb.categoryName}</span>`);
  }
});

在Astro中使用面包屑导航

---
// [categoryId]-[pageId].astro
import { GT6SDK } from '@gt6/sdk';

const { categoryId, pageId } = Astro.params;
const sdk = new GT6SDK({ 
  baseUrl: 'https://data.shopasb.io', 
  platformId: '1750838492' 
});

// 获取分类层级路径
const categoryPath = await sdk.getCategoryPath(parseInt(categoryId));
const currentCategory = categoryPath.currentCategory;
---

<html>
  <head>
    <title>{currentCategory?.categoryName} - GT6TRADE</title>
  </head>
  <body>
    <!-- 面包屑导航 -->
    <nav aria-label="面包屑导航" class="mb-3">
      <ol class="breadcrumb justify-content-center">
        <li class="breadcrumb-item">
          <a href="/" class="text-decoration-none">首页</a>
        </li>
        {categoryPath.breadcrumbs.map((crumb, index) => (
          <li class={`breadcrumb-item ${index === categoryPath.breadcrumbs.length - 1 ? 'active' : ''}`}>
            {index === categoryPath.breadcrumbs.length - 1 ? (
              <span>{crumb.categoryName}</span>
            ) : (
              <a href={`/postlist/${crumb.categoryId}-1`} class="text-decoration-none">
                {crumb.categoryName}
              </a>
            )}
          </li>
        ))}
      </ol>
    </nav>
    
    <h1>{currentCategory?.categoryName}</h1>
    <!-- 其他内容 -->
  </body>
</html>

面包屑导航组件

---
// Breadcrumb.astro
export interface Props {
  categoryId: number;
  currentPage?: number;
}

const { categoryId, currentPage = 1 } = Astro.props;
const sdk = new GT6SDK({ 
  baseUrl: 'https://data.shopasb.io', 
  platformId: '1750838492' 
});
const categoryPath = await sdk.getCategoryPath(categoryId);
---

<nav aria-label="面包屑导航" class="mb-3">
  <ol class="breadcrumb justify-content-center">
    <li class="breadcrumb-item">
      <a href="/" class="text-decoration-none">
        <i class="bi bi-house"></i> 首页
      </a>
    </li>
    {categoryPath.breadcrumbs.map((crumb, index) => (
      <li class={`breadcrumb-item ${index === categoryPath.breadcrumbs.length - 1 ? 'active' : ''}`}>
        {index === categoryPath.breadcrumbs.length - 1 ? (
          <span>{crumb.categoryName}</span>
        ) : (
          <a href={`/postlist/${crumb.categoryId}-1`} class="text-decoration-none">
            {crumb.categoryName}
          </a>
        )}
      </li>
    ))}
    {currentPage > 1 && (
      <li class="breadcrumb-item active">
        <span>第 {currentPage} 页</span>
      </li>
    )}
  </ol>
</nav>

<style>
  .breadcrumb {
    background: transparent;
    padding: 0.5rem 0;
  }
  
  .breadcrumb-item + .breadcrumb-item::before {
    content: ">";
    color: #6c757d;
  }
  
  .breadcrumb-item.active span {
    color: #495057;
    font-weight: 500;
  }
</style>

标签面包屑导航组件

---
// TagBreadcrumb.astro
export interface Props {
  tagId: number;
  currentPage?: number;
  baseUrl?: string;
  platformId?: string | number;
  rootCategoryId?: string | number;
}

const { 
  tagId, 
  currentPage = 1, 
  baseUrl = 'https://data.shopasb.io',
  platformId = '1747558688',
  rootCategoryId = '969287034'
} = Astro.props;

const sdk = new GT6SDK({ 
  baseUrl, 
  platformId, 
  rootCategoryId 
});
const tags = await sdk.getTags();
const currentTag = tags.find(tag => tag.tagId === tagId);
---

<nav aria-label="面包屑导航" class="mb-3">
  <ol class="breadcrumb justify-content-center">
    <li class="breadcrumb-item">
      <a href="/" class="text-decoration-none">
        <i class="bi bi-house"></i> 首页
      </a>
    </li>
    <li class="breadcrumb-item">
      <a href="/tags" class="text-decoration-none">标签</a>
    </li>
    <li class="breadcrumb-item active">
      <span>{currentTag?.tagName || `标签 ${tagId}`}</span>
    </li>
    {currentPage > 1 && (
      <li class="breadcrumb-item active">
        <span>第 {currentPage} 页</span>
      </li>
    )}
  </ol>
</nav>

<style>
  .breadcrumb {
    background: transparent;
    padding: 0.5rem 0;
    margin-bottom: 0;
  }
  
  .breadcrumb-item + .breadcrumb-item::before {
    content: ">";
    color: #6c757d;
    margin: 0 0.5rem;
  }
  
  .breadcrumb-item.active span {
    color: #495057;
    font-weight: 500;
  }
  
  .breadcrumb-item a {
    color: #6c757d;
    text-decoration: none;
  }
  
  .breadcrumb-item a:hover {
    color: #495057;
    text-decoration: underline;
  }
  
  .breadcrumb-item i {
    margin-right: 0.25rem;
  }
</style>

在文章详情页使用面包屑导航

---
// [articleId].astro
import { GT6SDK } from '@gt6/sdk';
import Breadcrumb from '../components/Breadcrumb.astro';

const { articleId } = Astro.params;
const sdk = new GT6SDK({ 
  baseUrl: 'https://data.shopasb.io', 
  platformId: '1750838492' 
});

const article = await sdk.getArticle(articleId);
// 假设文章属于第一个分类
const firstCategoryId = article.categories?.[0]?.categoryId;
const categoryPath = firstCategoryId ? await sdk.getCategoryPath(firstCategoryId) : null;
---

<html>
  <head>
    <title>{article.title} - GT6TRADE</title>
  </head>
  <body>
    {categoryPath && (
      <Breadcrumb categoryId={firstCategoryId} />
    )}
    
    <article>
      <h1>{article.title}</h1>
      <div set:html={article.content}></div>
    </article>
  </body>
</html>

在标签列表页使用面包屑导航

---
// [tagId]-[pageId].astro
import { GT6SDK } from '@gt6/sdk';
import TagBreadcrumb from '../components/TagBreadcrumb.astro';

const { tagId, pageId } = Astro.params;
const sdk = new GT6SDK({ 
  baseUrl: 'https://data.shopasb.io', 
  platformId: '1750838492' 
});

const currentPage = parseInt(pageId);
const tagArticles = await sdk.getArticlesByTag(parseInt(tagId), {
  page: currentPage,
  limit: 9,
  status: 'published'
});
---

<html>
  <head>
    <title>标签文章 - GT6TRADE</title>
  </head>
  <body>
    <TagBreadcrumb 
      tagId={parseInt(tagId)} 
      currentPage={currentPage}
    />
    
    <section>
      <h1>标签文章列表</h1>
      <div class="articles">
        {tagArticles.articles.map(article => (
          <article>
            <h2><a href={`/post/${article.articleId}`}>{article.title}</a></h2>
            <p>{article.content.substring(0, 200)}...</p>
          </article>
        ))}
      </div>
    </section>
  </body>
</html>

新方法使用示例

根据分类获取文章

// 获取单个分类的文章
const result = await sdk.getArticlesByCategory(782714);
console.log(`分类文章总数: ${result.total}`);
console.log(`返回文章数: ${result.articles.length}`);

// 获取多个分类的文章(去重)
const multiResult = await sdk.getArticlesByCategory([782714, 821172]);
console.log(`多分类文章总数: ${multiResult.total}`);

// 使用分页和状态过滤
const paginatedResult = await sdk.getArticlesByCategory(782714, {
  offset: 0,
  limit: 10,
  status: 'published'
});

根据标签获取文章

// 获取单个标签的文章
const result = await sdk.getArticlesByTag(136424);
console.log(`标签文章总数: ${result.total}`);

// 获取多个标签的文章(去重)
const multiResult = await sdk.getArticlesByTag([136424, 136425]);
console.log(`多标签文章总数: ${multiResult.total}`);

// 使用分页和状态过滤
const paginatedResult = await sdk.getArticlesByTag(136424, {
  offset: 0,
  limit: 10,
  status: 'published'
});

// 指定标签别名获取文章
const customTagResult = await sdk.getArticlesByTag(136424, {
  tagAlias: 'custom', // 使用自定义标签别名
  limit: 10,
  status: 'published'
});

获取分类层级路径(面包屑导航)

// 获取分类的完整层级路径
const pathResult = await sdk.getCategoryPath(821172);

// 输出面包屑导航数据
console.log('当前分类:', pathResult.currentCategory?.categoryName);
console.log('完整路径:', pathResult.path.map(cat => cat.categoryName).join(' > '));

// 前端面包屑导航使用
pathResult.breadcrumbs.forEach((crumb, index) => {
  if (index < pathResult.breadcrumbs.length - 1) {
    console.log(`<a href="/category/${crumb.categoryId}">${crumb.categoryName}</a> >`);
  } else {
    console.log(`<span>${crumb.categoryName}</span>`);
  }
});

获取子分类

// 获取直接子分类
const result = await sdk.getSubCategories(671920);
console.log(`子分类数量: ${result.total}`);
console.log(`递归深度: ${result.depth}`);

// 递归获取所有层级的子分类
const recursiveResult = await sdk.getSubCategories(671920, { 
  recursive: true 
});
console.log(`所有子分类数量: ${recursiveResult.total}`);

// 包含当前分类
const includeCurrentResult = await sdk.getSubCategories(671920, { 
  includeCurrent: true 
});
console.log(`包含当前分类的总数量: ${includeCurrentResult.total}`);

// 限制递归深度
const limitedResult = await sdk.getSubCategories(671920, { 
  recursive: true, 
  maxDepth: 2 
});
console.log(`限制深度后的子分类数量: ${limitedResult.total}`);

在Astro中使用面包屑导航

---
// Breadcrumb.astro
import { GT6SDK } from '@gt6/sdk';

const { categoryId } = Astro.props;
const sdk = new GT6SDK({ baseUrl: 'https://data.shopasb.io', platformId: '1750838492' });
const pathResult = await sdk.articles.getCategoryPath(categoryId);
---

<nav class="breadcrumb">
  <ol>
    <li><a href="/">首页</a></li>
    {pathResult.breadcrumbs.map((crumb, index) => (
      <li>
        {index === pathResult.breadcrumbs.length - 1 ? (
          <span>{crumb.categoryName}</span>
        ) : (
          <a href={`/category/${crumb.categoryId}`}>{crumb.categoryName}</a>
        )}
        {index < pathResult.breadcrumbs.length - 1 && <span> > </span>}
      </li>
    ))}
  </ol>
</nav>

在Astro中使用分类树导航

---
// CategoryTree.astro
import { GT6SDK } from '@gt6/sdk';

const { categoryId, recursive = false, maxDepth = 3 } = Astro.props;
const sdk = new GT6SDK({ baseUrl: 'https://data.shopasb.io', platformId: '1750838492' });
const result = await sdk.articles.getSubCategories(categoryId, { recursive, maxDepth });
---

<div class="category-tree">
  <h3>{result.currentCategory?.categoryName}</h3>
  <ul>
    {result.subCategories.map(category => (
      <li>
        <a href={`/category/${category.categoryId}`}>
          {category.categoryName} ({category.articleIds.length})
        </a>
      </li>
    ))}
  </ul>
</div>

API 参考

GT6SDK 类

构造函数

new GT6SDK(config: GT6Config)

配置参数:

  • baseUrl (string): API基础URL
  • platformId (string | number): 平台ID
  • rootCategoryId (string | number, 可选): 根分类ID,默认为'671920'
  • tagAlias (string, 可选): 标签别名,默认为'001'
  • timeout (number, 可选): 请求超时时间,默认为10000ms
  • cache (object, 可选): 缓存配置
    • enabled (boolean): 是否启用缓存,默认为true
    • ttl (number): 缓存时间,默认为300000ms (5分钟)

方法

便捷方法
  • getArticle(articleId: number | string): Promise<Article>
  • getCategories(rootCategoryId?: number | string): Promise<Category[]>
  • getTags(tagAlias?: string): Promise<Tag[]>
  • getArticlesByCategory(categoryId: number | number[], options?: { offset?: number; limit?: number; status?: string }): Promise<{ articles: Article[]; total: number; categoryIds: number[] }>
  • getArticlesByTag(tagId: number | number[], options?: { offset?: number; limit?: number; status?: string }): Promise<{ articles: Article[]; total: number; tagIds: number[] }>
  • getCategoryPath(categoryId: number): Promise<{ path: Category[]; currentCategory: Category | null; breadcrumbs: Array<{ categoryId: number; categoryName: string; level: number }> }>
  • getSubCategories(categoryId: number, options?: { recursive?: boolean; includeCurrent?: boolean; maxDepth?: number }): Promise<{ subCategories: Category[]; currentCategory: Category | null; total: number; depth: number }>
缓存管理
  • clearCache(): void - 清除所有缓存
  • getCacheStats() - 获取缓存统计信息

ArticlesAPI 类

文章相关方法

  • getArticle(articleId: number | string): Promise<Article>
  • getArticles(params?: ArticleQueryParams): Promise<Article[]>
  • getArticleList(params?: ArticleQueryParams): Promise<ArticleListItem[]>
  • getArticlesByCategory(categoryId: number | number[], options?: { offset?: number; limit?: number; status?: string }): Promise<{ articles: Article[]; total: number; categoryIds: number[] }>
  • getArticlesByTag(tagId: number | number[], options?: { offset?: number; limit?: number; status?: string }): Promise<{ articles: Article[]; total: number; tagIds: number[] }>
  • getCategoryPath(categoryId: number): Promise<{ path: Category[]; currentCategory: Category | null; breadcrumbs: Array<{ categoryId: number; categoryName: string; level: number }> }>
  • getSubCategories(categoryId: number, options?: { recursive?: boolean; includeCurrent?: boolean; maxDepth?: number }): Promise<{ subCategories: Category[]; currentCategory: Category | null; total: number; depth: number }>
  • getPublishedArticles(params?: Omit<ArticleQueryParams, 'status'>): Promise<Article[]>
  • searchArticles(query: string, params?: ArticleQueryParams): Promise<Article[]>
  • getRecommendedArticles(articleId: number, limit?: number): Promise<Article[]>

分类和标签方法

  • getCategories(rootCategoryId?: number | string): Promise<Category[]>
  • getTags(tagAlias?: string): Promise<Tag[]>

统计方法

  • getArticleStats(): Promise<ArticleStats>

数据类型

Article (文章)

interface Article {
  articleId: number;
  title: string;
  content: string;
  status: 'published' | 'draft' | 'archived';
  publishedAt: string;
  templateId: number;
  aiId: number;
  platformId: number;
  isVisible: boolean;
  displayTemplate: string;
  createdAt: any;
  updatedAt: any;
  categories: Category[];
  tags: Tag[];
  metaData: ArticleMetaData[];
  images: ArticleImage[];
  generatedAt: string;
}

Category (分类)

interface Category {
  categoryId: number;
  categoryName: string;
  categoryDescription: string;
  metaKeywords: string;
  status: number;
  parentId: number;
  sortOrder: number;
  createdAt: any;
  updatedAt: any;
  platformId: number;
  articleIds: number[];
  children: Category[];
}

Tag (标签)

interface Tag {
  tagId: number;
  tagName: string;
  type: number;
  platformId: number;
  aliases: string;
  createdAt: any;
  articleIds: number[];
}

错误处理

SDK使用自定义的 GT6Error 类来处理错误:

import { GT6Error } from '@gt6/sdk';

try {
  const article = await sdk.getArticle(999999);
} catch (error) {
  if (error instanceof GT6Error) {
    console.error(`错误: ${error.message}`);
    console.error(`状态码: ${error.status}`);
  }
}

缓存机制

SDK内置缓存机制,默认缓存5分钟:

const sdk = new GT6SDK({
  baseUrl: 'https://data.shopasb.io',
  platformId: '1750838492',
  cache: {
    enabled: true,
    ttl: 300000 // 5分钟
  }
});

// 清除缓存
sdk.clearCache();

// 获取缓存统计
const stats = sdk.getCacheStats();
console.log(`缓存条目数: ${stats.size}`);

开发

安装依赖

npm install

构建

npm run build

测试

npm test

类型检查

npm run type-check

许可证

MIT