'use strict'; const axios = require('axios'); const DEFAULT_BASE_URL = 'https://yyd.jiansuntuzhi.cn'; const DEFAULT_TIMEOUT_MS = 30000; class ProductCodePublicApiError extends Error { constructor(message, options = {}) { super(message); this.name = 'ProductCodePublicApiError'; this.status = options.status || 502; this.remoteStatus = options.remoteStatus || null; this.code = options.code || null; this.indeterminate = options.indeterminate === true; this.responseData = options.responseData || null; } } function getProductCodePublicApiConfig() { const apiKey = String( process.env.PRODUCT_CODE_PUBLIC_API_KEY || process.env.PRODUCT_CODE_API_KEY || '' ).trim(); const baseUrl = String( process.env.PRODUCT_CODE_PUBLIC_API_BASE_URL || DEFAULT_BASE_URL ).trim().replace(/\/+$/, ''); const timeoutValue = Number(process.env.PRODUCT_CODE_PUBLIC_API_TIMEOUT_MS); const timeoutMs = Number.isFinite(timeoutValue) && timeoutValue >= 5000 ? Math.min(timeoutValue, 120000) : DEFAULT_TIMEOUT_MS; return { apiKey, baseUrl, timeoutMs, configured: Boolean(apiKey && baseUrl), }; } function buildClient() { const config = getProductCodePublicApiConfig(); if (!config.configured) { throw new ProductCodePublicApiError('公司商品编码接口尚未配置', { status: 503, code: 'PRODUCT_CODE_API_NOT_CONFIGURED', }); } return { config, client: axios.create({ baseURL: config.baseUrl, timeout: config.timeoutMs, headers: { 'Content-Type': 'application/json', 'X-API-Key': config.apiKey, }, }), }; } function normalizeRemoteError(error, operation) { if (error instanceof ProductCodePublicApiError) return error; const remoteStatus = Number(error?.response?.status) || null; const responseData = error?.response?.data || null; const remoteMessage = String( responseData?.error || responseData?.message || error?.message || '未知错误' ).trim(); const isNetworkUncertain = !error?.response; const indeterminate = isNetworkUncertain || remoteStatus === 409 || remoteStatus >= 500; const status = remoteStatus === 400 ? 400 : (remoteStatus === 401 || remoteStatus === 403 ? 503 : 502); return new ProductCodePublicApiError(`${operation}失败:${remoteMessage}`, { status, remoteStatus, code: error?.code || responseData?.code || 'PRODUCT_CODE_API_ERROR', indeterminate, responseData, }); } async function getProductCodeMeta() { const { client } = buildClient(); try { const response = await client.get('/api/public/product-code-board/meta'); if (!response.data?.success || !response.data?.data) { throw new ProductCodePublicApiError('公司商品编码接口返回了无效的元数据', { status: 502, code: 'PRODUCT_CODE_META_INVALID', }); } return response.data.data; } catch (error) { throw normalizeRemoteError(error, '获取公司商品编码元数据'); } } async function createProductCodes(payload) { const { client } = buildClient(); try { const response = await client.post('/api/public/product-code-board/products', payload); if (!response.data?.success || !response.data?.data) { throw new ProductCodePublicApiError('公司商品编码接口返回了无效的编码结果', { status: 502, code: 'PRODUCT_CODE_RESULT_INVALID', indeterminate: true, responseData: response.data, }); } return response.data.data; } catch (error) { throw normalizeRemoteError(error, '申请公司SKU编码'); } } module.exports = { ProductCodePublicApiError, createProductCodes, getProductCodeMeta, getProductCodePublicApiConfig, };