UNPKG

@gt6/sdk

Version:

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

1,326 lines (1,322 loc) 152 kB
// 错误类型 class GT6Error extends Error { constructor(message, statusCode) { super(message); this.statusCode = statusCode; this.name = 'GT6Error'; } } class GT6Client { constructor(config) { this.config = { timeout: 10000, cache: { enabled: true, ttl: 300000 // 5分钟默认缓存 }, ...config }; this.cache = new Map(); } /** * 发起HTTP请求 */ async request(endpoint, options = {}) { const url = `${this.config.baseUrl}${endpoint}`; const cacheKey = `${options.method || 'GET'}:${url}`; // 检查缓存(只对GET请求缓存) if (this.config.cache?.enabled && options.method !== 'POST' && options.method !== 'PUT' && options.method !== 'DELETE') { const cached = this.cache.get(cacheKey); if (cached && Date.now() - cached.timestamp < this.config.cache.ttl) { return cached.data; } } try { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), this.config.timeout); // 对于FormData,不设置Content-Type,让浏览器自动设置 const headers = new Headers(options.headers); if (!(options.body instanceof FormData)) { headers.set('Content-Type', 'application/json'); } const response = await fetch(url, { ...options, headers, signal: controller.signal }); clearTimeout(timeoutId); if (!response.ok) { throw new GT6Error(`HTTP ${response.status}: ${response.statusText}`, response.status); } const data = await response.json(); // 更新缓存(只对GET请求缓存) if (this.config.cache?.enabled && options.method !== 'POST' && options.method !== 'PUT' && options.method !== 'DELETE') { this.cache.set(cacheKey, { data, timestamp: Date.now() }); } return data; } catch (error) { if (error instanceof GT6Error) { throw error; } if (error.name === 'AbortError') { throw new GT6Error('Request timeout', 408); } throw new GT6Error(`Network error: ${error.message}`); } } /** * 获取配置 */ getConfig() { return { ...this.config }; } /** * 清除缓存 */ clearCache() { this.cache.clear(); } /** * 获取缓存统计 */ getCacheStats() { const entries = Array.from(this.cache.entries()).map(([key, value]) => ({ key, age: Date.now() - value.timestamp })); return { size: this.cache.size, entries }; } } class ArticlesAPI { constructor(client) { this.client = client; } /** * 1. 根据文章ID获取文章详情 */ async getArticle(articleId) { return this.client.request(`/articles/${articleId}.json`); } /** * 1.1 根据文章ID获取文章详情(平台使用) */ async getArticle_p(articleId) { return this.client.request(`/parentarticles/${articleId}.json`); } /** * 2. 获取文章分类列表 */ async getCategories(rootCategoryId) { const config = this.client.getConfig(); const categoryId = rootCategoryId || config.rootCategoryId || '671920'; const response = await this.client.request(`/article-categories/platform-${config.platformId}-root-${categoryId}.json`); return response.categories; } /** * 2.1 获取文章分类列表(使用下级平台ID) */ async getCategories_p(rootCategoryId_p) { const config = this.client.getConfig(); const categoryId = rootCategoryId_p || config.rootCategoryId_p || '671920'; const response = await this.client.request(`/article-categories/platform/platform-${config.platformId_p}-root-${categoryId}.json`); return response.categories; } /** * 2.2 获取文章分类列表(使用下级平台ID) */ async getCategories_a(rootCategoryId) { const config = this.client.getConfig(); const categoryId = rootCategoryId || config.rootCategoryId; const response = await this.client.request(`/big-article-categories/platform-${config.platformId}-root-${categoryId}.json`); return response.categories; } /** * 3. 获取文章标签列表 */ async getTags(tagAlias) { const config = this.client.getConfig(); const alias = tagAlias || config.tagAlias || '001'; const response = await this.client.request(`/article-tags/platform-${config.platformId}-${alias}.json`); return response.tags; } /** * 3.1 获取文章标签列表(使用下级平台ID) */ async getTags_p(tagAlias_p) { const config = this.client.getConfig(); const alias = tagAlias_p || config.tagAlias_p || '001'; const response = await this.client.request(`/article-tags/platform-${config.platformId_p}-${alias}.json`); return response.tags; } /** * 3.2. 获取单个平台文章标签列表 */ async getTags_p_single(tagId_p) { const config = this.client.getConfig(); const tagId = tagId_p || config.tagId_p; if (!tagId) { throw new Error('Article tag ID is required'); } const response = await this.client.request(`/article-tags/${tagId}.json`); return response; } /** * 3.3. 获取单个平台文章标签的文章ID列表 */ async getTagArticleIds_p(tagId_p) { const tagData = await this.getTags_p_single(tagId_p); return tagData.articleIds; } /** * 4. 根据分类ID获取文章列表 * 支持单个分类ID或分类ID数组 */ async getArticlesByCategory(categoryId, options) { // 获取分类数据 const categories = await this.getCategories(); // 将单个分类ID转换为数组 const categoryIds = Array.isArray(categoryId) ? categoryId : [categoryId]; // 收集所有指定分类下的文章ID const allArticleIds = []; categoryIds.forEach(id => { const targetCategory = categories.find(cat => cat.categoryId === id); if (targetCategory) { allArticleIds.push(...targetCategory.articleIds); } }); // 去重 const uniqueArticleIds = [...new Set(allArticleIds)]; if (uniqueArticleIds.length === 0) { return { articles: [], total: 0, page: options?.page || 1, limit: options?.limit || 10 }; } // 应用分页 const page = options?.page || 1; const limit = options?.limit || 10; const offset = (page - 1) * limit; const paginatedArticleIds = uniqueArticleIds.slice(offset, offset + limit); // 获取文章详情 const articles = await Promise.all(paginatedArticleIds.map(articleId => this.getArticle(articleId))); // 应用状态过滤 let filteredArticles = articles; if (options?.status) { filteredArticles = articles.filter(article => article.status === options.status); } return { articles: filteredArticles, total: uniqueArticleIds.length, page, limit }; } /** * 4.1 根据分类ID获取文章列表 * 支持单个分类ID或分类ID数组 */ async getArticlesByCategory_p(categoryId, options) { // 获取分类数据 const categories = await this.getCategories_p(); // 将单个分类ID转换为数组 const categoryIds = Array.isArray(categoryId) ? categoryId : [categoryId]; // 收集所有指定分类下的文章ID const allArticleIds = []; categoryIds.forEach(id => { const targetCategory = categories.find(cat => cat.categoryId === id); if (targetCategory) { allArticleIds.push(...targetCategory.articleIds); } }); // 去重 const uniqueArticleIds = [...new Set(allArticleIds)]; if (uniqueArticleIds.length === 0) { return { articles: [], total: 0, page: options?.page || 1, limit: options?.limit || 10 }; } // 应用分页 const page = options?.page || 1; const limit = options?.limit || 10; const offset = (page - 1) * limit; const paginatedArticleIds = uniqueArticleIds.slice(offset, offset + limit); // 获取文章详情 const articles = await Promise.all(paginatedArticleIds.map(articleId => this.getArticle_p(articleId))); // 应用状态过滤 let filteredArticles = articles; if (options?.status) { filteredArticles = articles.filter(article => article.status === options.status); } return { articles: filteredArticles, total: uniqueArticleIds.length, page, limit }; } /** * 4.2 根据分类ID获取文章列表 * 支持单个分类ID或分类ID数组 */ async getArticlesByCategory_t(categoryId, options) { // 获取分类数据 const categories = await this.getCategories(); // 将单个分类ID转换为数组 const categoryIds = Array.isArray(categoryId) ? categoryId : [categoryId]; // 收集所有指定分类下的文章ID const allArticleIds = []; categoryIds.forEach(id => { const targetCategory = categories.find(cat => cat.categoryId === id); if (targetCategory) { allArticleIds.push(...targetCategory.articleIds); } }); // 去重 const uniqueArticleIds = [...new Set(allArticleIds)]; if (uniqueArticleIds.length === 0) { return { articles: [], total: 0, page: options?.page || 1, limit: options?.limit || 10 }; } // 应用分页 const page = options?.page || 1; const limit = options?.limit || 10; const offset = (page - 1) * limit; const paginatedArticleIds = uniqueArticleIds.slice(offset, offset + limit); // 获取文章详情 const articles = await Promise.all(paginatedArticleIds.map(articleId => this.getArticle_p(articleId))); // 应用状态过滤 let filteredArticles = articles; if (options?.status) { filteredArticles = articles.filter(article => article.status === options.status); } return { articles: filteredArticles, total: uniqueArticleIds.length, page, limit }; } /** * 4.3 根据分类ID获取文章列表(使用大型分类静态文件) * 只支持单个分类ID,从大型分类静态文件获取文章ID列表 */ async getArticlesByCategory_a(categoryId, options) { // 从大型分类静态文件获取该分类的文章ID列表 const categoryData = await this.client.request(`/big-article-categories/${categoryId}.json`); if (!categoryData || !categoryData.articleIds || categoryData.articleIds.length === 0) { return { articles: [], total: 0, page: options?.page || 1, limit: options?.limit || 10 }; } // 应用分页 const page = options?.page || 1; const limit = options?.limit || 10; const offset = (page - 1) * limit; const paginatedArticleIds = categoryData.articleIds.slice(offset, offset + limit); // 获取文章详情(使用上级平台数据) const articles = await Promise.all(paginatedArticleIds.map(articleId => this.getArticle_p(articleId))); // 应用状态过滤 let filteredArticles = articles; if (options?.status) { filteredArticles = articles.filter(article => article.status === options.status); } return { articles: filteredArticles, total: categoryData.articleIds.length, page, limit }; } /** * 5. 根据标签ID获取文章列表 * 支持单个标签ID或标签ID数组 */ async getArticlesByTag(tagId, options) { // 获取标签数据,传递tagAlias参数 const tags = await this.getTags(options?.tagAlias); // 将单个标签ID转换为数组 const tagIds = Array.isArray(tagId) ? tagId : [tagId]; // 收集所有指定标签下的文章ID const allArticleIds = []; tagIds.forEach(id => { const targetTag = tags.find(tag => tag.tagId === id); if (targetTag) { allArticleIds.push(...targetTag.articleIds); } }); // 去重 const uniqueArticleIds = [...new Set(allArticleIds)]; if (uniqueArticleIds.length === 0) { return { articles: [], total: 0, page: options?.page || 1, limit: options?.limit || 10 }; } // 应用分页 const page = options?.page || 1; const limit = options?.limit || 10; const offset = (page - 1) * limit; const paginatedArticleIds = uniqueArticleIds.slice(offset, offset + limit); // 获取文章详情 const articles = await Promise.all(paginatedArticleIds.map(articleId => this.getArticle(articleId))); // 应用状态过滤 let filteredArticles = articles; if (options?.status) { filteredArticles = articles.filter(article => article.status === options.status); } return { articles: filteredArticles, total: uniqueArticleIds.length, page, limit }; } /** * 5.1 根据标签ID获取文章列表 * 支持单个标签ID或标签ID数组 */ async getArticlesByTag_p(tagId, options) { // 获取标签数据,传递tagAlias参数 const tags = await this.getTags_p(options?.tagAlias); // 将单个标签ID转换为数组 const tagIds = Array.isArray(tagId) ? tagId : [tagId]; // 收集所有指定标签下的文章ID const allArticleIds = []; tagIds.forEach(id => { const targetTag = tags.find(tag => tag.tagId === id); if (targetTag) { allArticleIds.push(...targetTag.articleIds); } }); // 去重 const uniqueArticleIds = [...new Set(allArticleIds)]; if (uniqueArticleIds.length === 0) { return { articles: [], total: 0, page: options?.page || 1, limit: options?.limit || 10 }; } // 应用分页 const page = options?.page || 1; const limit = options?.limit || 10; const offset = (page - 1) * limit; const paginatedArticleIds = uniqueArticleIds.slice(offset, offset + limit); // 获取文章详情 const articles = await Promise.all(paginatedArticleIds.map(articleId => this.getArticle_p(articleId))); // 应用状态过滤 let filteredArticles = articles; if (options?.status) { filteredArticles = articles.filter(article => article.status === options.status); } return { articles: filteredArticles, total: uniqueArticleIds.length, page, limit }; } /** * 5.2 根据标签ID获取文章列表 * 支持单个标签ID或标签ID数组 */ async getArticlesByTag_t(tagId, options) { // 获取标签数据,传递tagAlias参数 const tags = await this.getTags(options?.tagAlias); // 将单个标签ID转换为数组 const tagIds = Array.isArray(tagId) ? tagId : [tagId]; // 收集所有指定标签下的文章ID const allArticleIds = []; tagIds.forEach(id => { const targetTag = tags.find(tag => tag.tagId === id); if (targetTag) { allArticleIds.push(...targetTag.articleIds); } }); // 去重 const uniqueArticleIds = [...new Set(allArticleIds)]; if (uniqueArticleIds.length === 0) { return { articles: [], total: 0, page: options?.page || 1, limit: options?.limit || 10 }; } // 应用分页 const page = options?.page || 1; const limit = options?.limit || 10; const offset = (page - 1) * limit; const paginatedArticleIds = uniqueArticleIds.slice(offset, offset + limit); // 获取文章详情 const articles = await Promise.all(paginatedArticleIds.map(articleId => this.getArticle_p(articleId))); // 应用状态过滤 let filteredArticles = articles; if (options?.status) { filteredArticles = articles.filter(article => article.status === options.status); } return { articles: filteredArticles, total: uniqueArticleIds.length, page, limit }; } /** * 5.3. 根据单个标签ID获取平台文章列表 * 使用getTags_p_single获取指定标签数据,然后获取文章详情 * @param tagId 单个标签ID * @param options 查询选项 */ async getArticlesByTag_single(tagId, options) { // 获取指定标签的数据 const tagData = await this.getTags_p_single(tagId); if (!tagData || !tagData.articleIds || tagData.articleIds.length === 0) { // 剔除articleIds字段 const { articleIds, ...tagInfo } = tagData; return { articles: [], total: 0, page: options?.page || 1, limit: options?.limit || 10, tag: tagInfo }; } // 应用分页 const page = options?.page || 1; const limit = options?.limit || 10; const offset = (page - 1) * limit; const paginatedArticleIds = tagData.articleIds.slice(offset, offset + limit); // 获取文章详情 const articles = await Promise.all(paginatedArticleIds.map(articleId => this.getArticle_p(articleId))); // 应用状态过滤 let filteredArticles = articles; if (options?.status) { filteredArticles = articles.filter(article => article.status === options.status); } // 剔除articleIds字段 const { articleIds, ...tagInfo } = tagData; return { articles: filteredArticles, total: tagData.articleIds.length, page, limit, tag: tagInfo }; } /** * 6. 根据分类ID获取该分类的层级路径 * 用于前端面包屑导航 */ async getCategoryPath(categoryId) { // 获取所有分类数据 const categories = await this.getCategories(); // 查找目标分类 const targetCategory = categories.find(cat => cat.categoryId === categoryId); if (!targetCategory) { return { path: [], currentCategory: null, breadcrumbs: [] }; } // 构建分类路径 const path = []; const breadcrumbs = []; // 递归查找父分类 const buildPath = (currentCategory, level = 0) => { // 将当前分类添加到路径开头(因为我们要从根到叶子构建) path.unshift(currentCategory); breadcrumbs.unshift({ categoryId: currentCategory.categoryId, categoryName: currentCategory.categoryName, level }); // 如果有父分类,继续递归 if (currentCategory.parentId && currentCategory.parentId !== 0) { const parentCategory = categories.find(cat => cat.categoryId === currentCategory.parentId); if (parentCategory) { buildPath(parentCategory, level + 1); } } }; // 从目标分类开始构建路径 buildPath(targetCategory); return { path, currentCategory: targetCategory, breadcrumbs }; } /** * 7. 获取指定分类ID下的子分类 * 支持递归获取所有层级的子分类 */ async getSubCategories(categoryId, options) { // 获取所有分类数据 const categories = await this.getCategories(); // 查找目标分类 const targetCategory = categories.find(cat => cat.categoryId === categoryId); if (!targetCategory) { return { subCategories: [], currentCategory: null, total: 0, depth: 0 }; } const subCategories = []; let maxDepth = options?.maxDepth || Infinity; let actualDepth = 0; // 递归获取子分类的函数 const collectSubCategories = (parentId, currentDepth = 0) => { if (currentDepth >= maxDepth) { return; } // 查找直接子分类 const children = categories.filter(cat => cat.parentId === parentId); children.forEach(child => { subCategories.push(child); // 如果需要递归且未达到最大深度,继续查找子分类 if (options?.recursive && currentDepth < maxDepth - 1) { collectSubCategories(child.categoryId, currentDepth + 1); } }); // 更新实际深度 actualDepth = Math.max(actualDepth, currentDepth); }; // 开始收集子分类 collectSubCategories(categoryId); // 如果需要包含当前分类,添加到结果中 if (options?.includeCurrent) { subCategories.unshift(targetCategory); } return { subCategories, currentCategory: targetCategory, total: subCategories.length, depth: actualDepth }; } /****************************************************************************************** * 1.1 根据文章ID获取文章详情(平台用户都可以使用) */ async getArticle_all(articleId) { return this.client.request(`/articles_all/${articleId}.json`); } /** * 1.2 根据分类ID获取文章列表(平台用户都可以使用) */ async getArticlesByCategory_all(categoryId, options) { // 从大型分类静态文件获取该分类的文章ID列表 const categoryData = await this.client.request(`/big-article-categories/${categoryId}.json`); if (!categoryData || !categoryData.articleIds || categoryData.articleIds.length === 0) { return { articles: [], total: 0, page: options?.page || 1, limit: options?.limit || 10 }; } // 将文章ID列表倒序排列 const reversedArticleIds = [...categoryData.articleIds].reverse(); // 应用分页 const page = options?.page || 1; const limit = options?.limit || 10; const offset = (page - 1) * limit; const paginatedArticleIds = reversedArticleIds.slice(offset, offset + limit); // 获取文章详情 - 修复:提取 articleId 字段 const articles = await Promise.all(paginatedArticleIds.map(articleId => this.getArticle_all(articleId))); // 应用状态过滤 let filteredArticles = articles; if (options?.status) { filteredArticles = articles.filter(article => article.status === options.status); } return { articles: filteredArticles, total: categoryData.articleIds.length, page, limit }; } /** * 1.2.2 根据分类ID获取文章列表(支持搜索过滤) */ async getArticlesByCategory_all_search(categoryId, searchOptions) { // 从大型分类静态文件获取该分类的文章ID列表 const categoryData = await this.client.request(`/big-article-categories/${categoryId}.json`); if (!categoryData || !categoryData.articleIds || categoryData.articleIds.length === 0) { return { articles: [], total: 0, page: searchOptions?.page || 1, limit: searchOptions?.limit || 10, filteredTotal: 0 }; } // 将文章数据倒序排列 const reversedArticleIds = [...categoryData.articleIds].reverse(); // 应用搜索过滤 let filteredArticleIds = reversedArticleIds.filter(articleObj => { // 1. regionId 过滤 if (searchOptions?.regionIds && searchOptions.regionIds.length > 0) { if (!articleObj.regionId || !searchOptions.regionIds.includes(articleObj.regionId)) { return false; } } // 2. price 范围过滤 if (searchOptions?.priceRange) { const price = parseFloat(articleObj.price || '0'); if (searchOptions.priceRange.min !== undefined && price < searchOptions.priceRange.min) { return false; } if (searchOptions.priceRange.max !== undefined && price > searchOptions.priceRange.max) { return false; } } // 3. Salary 范围过滤 if (searchOptions?.salaryRange) { const salary = parseFloat(articleObj.Salary || '0'); if (searchOptions.salaryRange.min !== undefined && salary < searchOptions.salaryRange.min) { return false; } if (searchOptions.salaryRange.max !== undefined && salary > searchOptions.salaryRange.max) { return false; } } // 4. mileage 范围过滤 if (searchOptions?.mileageRange) { // 处理里程数格式,如 "26000 km" -> 26000 const mileageStr = articleObj.Mileage || '0'; const mileageMatch = mileageStr.match(/(\d+(?:\.\d+)?)/); const mileage = mileageMatch ? parseFloat(mileageMatch[1]) : 0; if (searchOptions.mileageRange.min !== undefined && mileage < searchOptions.mileageRange.min) { return false; } if (searchOptions.mileageRange.max !== undefined && mileage > searchOptions.mileageRange.max) { return false; } } // 5. propertyArea 范围过滤 if (searchOptions?.propertyAreaRange) { const propertyArea = parseFloat(articleObj.propertyArea || '0'); if (searchOptions.propertyAreaRange.min !== undefined && propertyArea < searchOptions.propertyAreaRange.min) { return false; } if (searchOptions.propertyAreaRange.max !== undefined && propertyArea > searchOptions.propertyAreaRange.max) { return false; } } // 6. plotArea 范围过滤 if (searchOptions?.plotAreaRange) { const plotArea = parseFloat(articleObj.plotArea || '0'); if (searchOptions.plotAreaRange.min !== undefined && plotArea < searchOptions.plotAreaRange.min) { return false; } if (searchOptions.plotAreaRange.max !== undefined && plotArea > searchOptions.plotAreaRange.max) { return false; } } // 7. tagIds 过滤 if (searchOptions?.tagIds && searchOptions.tagIds.length > 0) { if (!articleObj.tagIds || articleObj.tagIds.length === 0) { return false; } if (searchOptions.requireAllTags) { // 要求包含所有指定的 tagIds const hasAllTags = searchOptions.tagIds.every(tagId => articleObj.tagIds.includes(tagId)); if (!hasAllTags) { return false; } } else { // 包含任意一个指定的 tagId 即可 const hasAnyTag = searchOptions.tagIds.some(tagId => articleObj.tagIds.includes(tagId)); if (!hasAnyTag) { return false; } } } return true; }); const filteredTotal = filteredArticleIds.length; if (filteredTotal === 0) { return { articles: [], total: categoryData.articleIds.length, page: searchOptions?.page || 1, limit: searchOptions?.limit || 10, filteredTotal: 0 }; } // 应用分页 const page = searchOptions?.page || 1; const limit = searchOptions?.limit || 10; const offset = (page - 1) * limit; const paginatedArticleIds = filteredArticleIds.slice(offset, offset + limit); // 获取文章详情 const articles = await Promise.all(paginatedArticleIds.map(articleObj => this.getArticle_all(articleObj.articleId))); // 应用状态过滤 let finalArticles = articles; if (searchOptions?.status) { finalArticles = articles.filter(article => article.status === searchOptions.status); } return { articles: finalArticles, total: categoryData.articleIds.length, // 原始总数 page, limit, filteredTotal // 过滤后的总数 }; } /** * 1.2.2 根据分类ID获取文章列表(支持搜索过滤) */ async getArticlesByCategory_all_search01(categoryId, searchOptions) { // 将单个分类ID转换为数组 const categoryIds = Array.isArray(categoryId) ? categoryId : [categoryId]; // 收集所有指定分类下的文章数据 const allArticleData = []; let totalArticles = 0; // 遍历所有分类ID,获取每个分类的文章数据 for (const singleCategoryId of categoryIds) { try { const categoryData = await this.client.request(`/big-article-categories/${singleCategoryId}.json`); if (categoryData && categoryData.articleIds && categoryData.articleIds.length > 0) { // 将每个分类的文章数据倒序排列后再追加 const reversedArticleIds = [...categoryData.articleIds].reverse(); allArticleData.push(...reversedArticleIds); totalArticles += categoryData.articleIds.length; } } catch (error) { console.warn(`Failed to fetch data for category ${singleCategoryId}:`, error); // 继续处理其他分类,不中断整个流程 } } if (allArticleData.length === 0) { return { articles: [], total: 0, page: searchOptions?.page || 1, limit: searchOptions?.limit || 10, filteredTotal: 0 }; } // 应用搜索过滤 let filteredArticleIds = allArticleData.filter(articleObj => { // 1. regionId 过滤 if (searchOptions?.regionIds && searchOptions.regionIds.length > 0) { if (!articleObj.regionId || !searchOptions.regionIds.includes(articleObj.regionId)) { return false; } } // 2. price 范围过滤 if (searchOptions?.priceRange) { const price = parseFloat(articleObj.price || '0'); if (searchOptions.priceRange.min !== undefined && price < searchOptions.priceRange.min) { return false; } if (searchOptions.priceRange.max !== undefined && price > searchOptions.priceRange.max) { return false; } } // 3. Salary 范围过滤 if (searchOptions?.salaryRange) { const salary = parseFloat(articleObj.Salary || '0'); if (searchOptions.salaryRange.min !== undefined && salary < searchOptions.salaryRange.min) { return false; } if (searchOptions.salaryRange.max !== undefined && salary > searchOptions.salaryRange.max) { return false; } } // 4. mileage 范围过滤 if (searchOptions?.mileageRange) { // 处理里程数格式,如 "26000 km" -> 26000 const mileageStr = articleObj.Mileage || '0'; const mileageMatch = mileageStr.match(/(\d+(?:\.\d+)?)/); const mileage = mileageMatch ? parseFloat(mileageMatch[1]) : 0; if (searchOptions.mileageRange.min !== undefined && mileage < searchOptions.mileageRange.min) { return false; } if (searchOptions.mileageRange.max !== undefined && mileage > searchOptions.mileageRange.max) { return false; } } // 5. propertyArea 范围过滤 if (searchOptions?.propertyAreaRange) { const propertyArea = parseFloat(articleObj.propertyArea || '0'); if (searchOptions.propertyAreaRange.min !== undefined && propertyArea < searchOptions.propertyAreaRange.min) { return false; } if (searchOptions.propertyAreaRange.max !== undefined && propertyArea > searchOptions.propertyAreaRange.max) { return false; } } // 6. plotArea 范围过滤 if (searchOptions?.plotAreaRange) { const plotArea = parseFloat(articleObj.plotArea || '0'); if (searchOptions.plotAreaRange.min !== undefined && plotArea < searchOptions.plotAreaRange.min) { return false; } if (searchOptions.plotAreaRange.max !== undefined && plotArea > searchOptions.plotAreaRange.max) { return false; } } // 7. tagIds 过滤 if (searchOptions?.tagIds && searchOptions.tagIds.length > 0) { if (!articleObj.tagIds || articleObj.tagIds.length === 0) { return false; } if (searchOptions.requireAllTags) { // 要求包含所有指定的 tagIds const hasAllTags = searchOptions.tagIds.every(tagId => articleObj.tagIds.includes(tagId)); if (!hasAllTags) { return false; } } else { // 包含任意一个指定的 tagId 即可 const hasAnyTag = searchOptions.tagIds.some(tagId => articleObj.tagIds.includes(tagId)); if (!hasAnyTag) { return false; } } } return true; }); const filteredTotal = filteredArticleIds.length; if (filteredTotal === 0) { return { articles: [], total: totalArticles, page: searchOptions?.page || 1, limit: searchOptions?.limit || 10, filteredTotal: 0 }; } // 应用分页 const page = searchOptions?.page || 1; const limit = searchOptions?.limit || 10; const offset = (page - 1) * limit; const paginatedArticleIds = filteredArticleIds.slice(offset, offset + limit); // 获取文章详情 const articles = await Promise.all(paginatedArticleIds.map(articleObj => this.getArticle_all(articleObj.articleId))); // 应用状态过滤 let finalArticles = articles; if (searchOptions?.status) { finalArticles = articles.filter(article => article.status === searchOptions.status); } return { articles: finalArticles, total: totalArticles, // 原始总数 page, limit, filteredTotal // 过滤后的总数 }; } /** * 1.2.1 根据平台ID获取文章列表(平台用户都可以使用) */ async getArticlesByplatform_all(platformId, options) { // 从大型分类静态文件获取该分类的文章ID列表 const categoryData = await this.client.request(`/platform-advertise/platform-${platformId}.json`); if (!categoryData || !categoryData.articleIds || categoryData.articleIds.length === 0) { return { articles: [], total: 0, page: options?.page || 1, limit: options?.limit || 10 }; } // 应用分页 const page = options?.page || 1; const limit = options?.limit || 10; const offset = (page - 1) * limit; const paginatedArticleIds = categoryData.articleIds.slice(offset, offset + limit); // 获取文章详情 const articles = await Promise.all(paginatedArticleIds.map(articleId => this.getArticle_all(articleId))); // 应用状态过滤 let filteredArticles = articles; if (options?.status) { filteredArticles = articles.filter(article => article.status === options.status); } return { articles: filteredArticles, total: categoryData.articleIds.length, page, limit }; } /** * 1.3 获取文章分类列表(平台用户都可以使用) */ async getArticlesCategories_all(rootCategoryId) { const config = this.client.getConfig(); const categoryId = rootCategoryId || config.rootCategoryId; const response = await this.client.request(`/big-article-categories/platform-${config.platformId}-root-${categoryId}.json`); return response.categories; } /** * 1.4 根据单个标签ID获取平台文章列表 * 使用getTags_p_single获取指定标签数据,然后获取文章详情 * @param tagId 单个标签ID * @param options 查询选项 */ async getArticlesByTag_single_all(tagId, options) { // 获取指定标签的数据 const tagData = await this.getTags_p_single(tagId); if (!tagData || !tagData.articleIds || tagData.articleIds.length === 0) { // 剔除articleIds字段 const { articleIds, ...tagInfo } = tagData; return { articles: [], total: 0, page: options?.page || 1, limit: options?.limit || 10, tag: tagInfo }; } // 将文章ID列表倒序排列 const reversedArticleIds = [...tagData.articleIds].reverse(); // 应用分页 const page = options?.page || 1; const limit = options?.limit || 10; const offset = (page - 1) * limit; const paginatedArticleIds = reversedArticleIds.slice(offset, offset + limit); // 获取文章详情 const articles = await Promise.all(paginatedArticleIds.map(articleId => this.getArticle_all(articleId))); // 应用状态过滤 let filteredArticles = articles; if (options?.status) { filteredArticles = articles.filter(article => article.status === options.status); } // 剔除articleIds字段 const { articleIds, ...tagInfo } = tagData; return { articles: filteredArticles, total: tagData.articleIds.length, page, limit, tag: tagInfo }; } } class ProductsAPI { constructor(client) { this.client = client; } /** * 1. 根据产品ID获取产品详情 */ async getProduct(productId) { const product = await this.client.request(`/products/${productId}.json`); // 检查产品是否有销售区域和税费模板 if (product.regions && product.regions.length > 0 && product.taxTemplates && product.taxTemplates.length > 0) { try { // 获取税费信息 const taxInfo = await this.getTaxInfo(); // 为每个税费模板添加规则 product.taxTemplates = product.taxTemplates.map(template => { const matchingTemplate = taxInfo.templates.find(t => t.templateId === template.templateId); if (matchingTemplate) { // 过滤出产品可销售区域的规则 const productRegionIds = product.regions.map(r => r.regionId); const applicableRules = matchingTemplate.rules.filter(rule => productRegionIds.includes(rule.regionId)); return { ...template, rules: applicableRules }; } return template; }); } catch (error) { // 如果获取税费信息失败,不影响产品详情返回 console.warn('Failed to fetch tax info:', error); } } // 检查产品是否有销售区域和运费模板 if (product.regions && product.regions.length > 0 && product.shippingTemplates && product.shippingTemplates.length > 0) { try { // 获取运费信息 const shippingInfo = await this.getShippingInfo(); // 为每个运费模板添加规则 product.shippingTemplates = product.shippingTemplates.map(template => { const matchingTemplate = shippingInfo.templates.find(t => t.templateId === template.templateId); if (matchingTemplate) { // 过滤出产品可销售区域的规则 const productRegionIds = product.regions.map(r => r.regionId); const applicableRules = matchingTemplate.rules.filter(rule => productRegionIds.includes(rule.regionId)); return { ...template, rules: applicableRules }; } return template; }); } catch (error) { // 如果获取运费信息失败,不影响产品详情返回 console.warn('Failed to fetch shipping info:', error); } } return product; } /** * 1.1. 根据产品ID获取父平台产品详情 */ async getProduct_p(productId) { const product = await this.client.request(`/parentproducts/${productId}.json`); // 检查产品是否有销售区域和税费模板 if (product.regions && product.regions.length > 0 && product.taxTemplates && product.taxTemplates.length > 0) { try { // 获取税费信息 const taxInfo = await this.getTaxInfo(); // 为每个税费模板添加规则 product.taxTemplates = product.taxTemplates.map(template => { const matchingTemplate = taxInfo.templates.find(t => t.templateId === template.templateId); if (matchingTemplate) { // 过滤出产品可销售区域的规则 const productRegionIds = product.regions.map(r => r.regionId); const applicableRules = matchingTemplate.rules.filter(rule => productRegionIds.includes(rule.regionId)); return { ...template, rules: applicableRules }; } return template; }); } catch (error) { // 如果获取税费信息失败,不影响产品详情返回 console.warn('Failed to fetch tax info:', error); } } // 检查产品是否有销售区域和运费模板 if (product.regions && product.regions.length > 0 && product.shippingTemplates && product.shippingTemplates.length > 0) { try { // 获取运费信息 const shippingInfo = await this.getShippingInfo(); // 为每个运费模板添加规则 product.shippingTemplates = product.shippingTemplates.map(template => { const matchingTemplate = shippingInfo.templates.find(t => t.templateId === template.templateId); if (matchingTemplate) { // 过滤出产品可销售区域的规则 const productRegionIds = product.regions.map(r => r.regionId); const applicableRules = matchingTemplate.rules.filter(rule => productRegionIds.includes(rule.regionId)); return { ...template, rules: applicableRules }; } return template; }); } catch (error) { // 如果获取运费信息失败,不影响产品详情返回 console.warn('Failed to fetch shipping info:', error); } } return product; } /** * 2. 获取产品分类列表 */ async getCategories(productRootCategoryId) { const config = this.client.getConfig(); const categoryId = productRootCategoryId || config.productRootCategoryId || '277233'; const response = await this.client.request(`/product-categories/platform-${config.platformId}-root-${categoryId}.json`); return response.categories; } /** * 2.1. 获取平台产品分类列表 */ async getCategories_p(productRootCategoryId_p) { const config = this.client.getConfig(); const categoryId = productRootCategoryId_p || config.productRootCategoryId_p; const response = await this.client.request(`/product-categories/platform/platform-${config.platformId_p}-root-${categoryId}.json`); return response.categories; } /** * 2.2. 获取平台产品分类列表 */ async getCategories_b(productRootCategoryId) { const config = this.client.getConfig(); const categoryId = productRootCategoryId || config.productRootCategoryId; const response = await this.client.request(`/big-product-categories/platform-${config.platformId}-root-${categoryId}.json`); return response.categories; } /** * 3. 获取产品标签列表 */ async getTags(productTagAlias) { const config = this.client.getConfig(); const alias = productTagAlias || config.productTagAlias || '01'; const response = await this.client.request(`/product-tags/platform-${config.platformId}-${alias}.json`); return response.tags; } /** * 3.1. 获取平台产品标签列表 */ async getTags_p(productTagAlias_p) { const config = this.client.getConfig(); const alias = productTagAlias_p || config.productTagAlias_p; const response = await this.client.request(`/product-tags/platform-${config.platformId_p}-${alias}.json`); return response.tags; } /** * 3.2. 获取单个平台产品标签列表 */ async getTags_p_single(productTagId_p) { const config = this.client.getConfig(); const productTagId = productTagId_p || config.productTagId_p; if (!productTagId) { throw new Error('Product tag ID is required'); } const response = await this.client.request(`/product-tags/${productTagId}.json`); return response; } /** * 3.3. 获取单个平台产品标签的产品ID列表 */ async getTagProductIds_p(productTagId_p) { const tagData = await this.getTags_p_single(productTagId_p); return tagData.productIds; } /** * 4. 根据分类ID获取产品列表 * 支持单个分类ID或分类ID数组 */ async getProductsByCategory(categoryId, options) { // 获取分类数据 const categories = await this.getCategories(); // 递归查找分类的函数 const findCategoryById = (cats, targetId) => { for (const cat of cats) { if (cat.categoryId === targetId) { return cat; } if (cat.children && cat.children.length > 0) { const found = findCategoryById(cat.children, targetId); if (found) return found; } } return null; }; // 将单个分类ID转换为数组 const categoryIds = Array.isArray(categoryId) ? categoryId : [categoryId]; // 收集所有指定分类下的产品ID const allProductIds = []; categoryIds.forEach(id => { const targetCategory = findCategoryById(categories, id); if (targetCategory) { allProductIds.push(...targetCategory.productIds); } }); // 去重 const uniqueProductIds = [...new Set(allProductIds)]; if (uniqueProductIds.length === 0) { return { products: [], total: 0, page: options?.page || 1, limit: options?.limit || 10 }; } // 应用分页 const page = options?.page || 1; const limit = options?.limit || 10; const offset = (page - 1) * limit; const paginatedProductIds = uniqueProductIds.slice(offset, offset + limit); // 获取产品详情 const products = await Promise.all(paginatedProductIds.map(productId => this.getProduct(productId))); // 应用状态过滤 let filteredProducts = products; if (options?.status !== undefined) { filteredProducts = products.filter(product => product.status === options.status); } return { products: filteredProducts, total: uniqueProductIds.length, page, limit }; } /** * 4.1. 根据分类ID获取平台产品列表 */ async getProductsByCategory_p(categoryId, options) { // 获取分类数据 const categories = await this.getCategories_p(); // 递归查找分类的函数 const findCategoryById = (cats, targetId) => { for (const cat of cats) { if (cat.categoryId === targetId) { return cat; } if (cat.children && cat.children.length > 0) { const found = findCategoryById(cat.children, targetId); if (found) return found; } } return null; }; // 将单个分类ID转换为数组 const categoryIds = Array.isArray(categoryId) ? categoryId : [categoryId]; // 收集所有指定分类下的产品ID const allProductIds = []; categoryIds.forEach(id => { const targetCategory = findCategoryById(categories, id); if (targetCategory) { allProductIds.push(...targetCategory.productIds); } }); // 去重 const uniqueProductIds = [...new Set(allProductIds)]; if (uniqueProductIds.length === 0) { return { products: [], total: 0, page: options?.page || 1, limit: options?.limit || 10 }; } // 应用分页 const page = options?.page || 1; const limit = options?.limit || 10; const offset = (page - 1) * limit; const paginatedProductIds = uniqueProductIds.slice(offset, offset + limit); // 获取产品详情 const products = await Promise.all(paginatedProductIds.map(productId => this.getProduct_p(productId))); // 应用状态过滤 let filteredProducts = products; if (options?.status !== undefined) { filteredProducts = products.filter(product => product.status === options.status); }