125 lines
3.7 KiB
JavaScript
125 lines
3.7 KiB
JavaScript
'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,
|
|
};
|