204 lines
6.7 KiB
JavaScript
204 lines
6.7 KiB
JavaScript
const express = require('express');
|
|
const {
|
|
claimSelectionFissionDeliveryTask,
|
|
getSelectionFissionDeliveryPackage,
|
|
listSelectionFissionDeliveryPlans,
|
|
listSelectionFissionUserShops,
|
|
receiveSelectionFissionAutoListingFailure,
|
|
receiveSelectionFissionAutoListingResult,
|
|
syncSelectionFissionUserShops,
|
|
} = require('../services/planningSelectionFissionService');
|
|
const {
|
|
requireExternalAutomationApiKey: requireApiKey,
|
|
requireDesktopPageAccess,
|
|
} = require('../services/externalAutomationAuth');
|
|
|
|
const router = express.Router();
|
|
const requirePlanningAccess = requireDesktopPageAccess('planning_upload');
|
|
|
|
function normalizeBoolean(value, fallback = false) {
|
|
if (value === true || value === false) return value;
|
|
const text = String(value ?? '').trim().toLowerCase();
|
|
if (['1', 'true', 'yes', 'on'].includes(text)) return true;
|
|
if (['0', 'false', 'no', 'off'].includes(text)) return false;
|
|
return fallback;
|
|
}
|
|
|
|
function getAuthenticatedDesktopUserName(req) {
|
|
if (req.externalApiKey?.authType !== 'jwt') return '';
|
|
return String(req.user?.name || req.user?.username || '').trim();
|
|
}
|
|
|
|
function buildInput(req) {
|
|
const authenticatedUserName = getAuthenticatedDesktopUserName(req);
|
|
return {
|
|
...req.query,
|
|
schemeCode: req.params.schemeCode || req.query.schemeCode || req.query.scheme_code,
|
|
schemeId: req.params.schemeCode || req.query.schemeId || req.query.scheme_id,
|
|
dingtalkUserName: authenticatedUserName ||
|
|
req.query.dingtalkUserName
|
|
|| req.query.dingtalk_user_name
|
|
|| req.query.dingtalkUsername
|
|
|| req.query.userName
|
|
|| req.query.user_name,
|
|
includeIncomplete: normalizeBoolean(req.query.includeIncomplete || req.query.include_incomplete, false),
|
|
};
|
|
}
|
|
|
|
function buildListingResultInput(req) {
|
|
const body = req.body || {};
|
|
const query = req.query || {};
|
|
const input = {
|
|
...query,
|
|
...body,
|
|
claimToken: req.get('x-task-claim-token')
|
|
|| req.get('x-claim-token')
|
|
|| body.claimToken
|
|
|| body.claim_token
|
|
|| body.taskClaimToken
|
|
|| body.task_claim_token
|
|
|| body.task?.claimToken
|
|
|| body.task?.claim_token
|
|
|| body.claim?.claimToken
|
|
|| body.claim?.claim_token
|
|
|| query.claimToken
|
|
|| query.claim_token
|
|
|| query.taskClaimToken
|
|
|| query.task_claim_token,
|
|
};
|
|
const authenticatedUserName = getAuthenticatedDesktopUserName(req);
|
|
return authenticatedUserName
|
|
? { ...input, dingtalkUserName: authenticatedUserName }
|
|
: input;
|
|
}
|
|
|
|
function buildRequestInput(req) {
|
|
const input = {
|
|
...(req.query || {}),
|
|
...(req.body || {}),
|
|
};
|
|
const authenticatedUserName = getAuthenticatedDesktopUserName(req);
|
|
return authenticatedUserName
|
|
? { ...input, dingtalkUserName: authenticatedUserName }
|
|
: input;
|
|
}
|
|
|
|
function buildRequestContext(req) {
|
|
return {
|
|
apiKeyId: req.externalApiKey?.id,
|
|
apiKeyName: req.externalApiKey?.name,
|
|
remoteIp: req.externalApiKey?.remoteIp,
|
|
};
|
|
}
|
|
|
|
function handleError(res, error, fallbackMessage) {
|
|
const statusCode = error.statusCode || error.status || 500;
|
|
if (statusCode >= 500) {
|
|
console.error('[SelectionFissionExternalAPI] 请求失败:', error);
|
|
}
|
|
return res.status(statusCode).json({
|
|
success: false,
|
|
error: error.message || fallbackMessage,
|
|
data: error.data || undefined,
|
|
});
|
|
}
|
|
|
|
router.get('/plans', requireApiKey, requirePlanningAccess, async (req, res) => {
|
|
try {
|
|
const data = await listSelectionFissionDeliveryPlans(buildInput(req));
|
|
res.setHeader('Cache-Control', 'no-store');
|
|
return res.json({ success: true, data });
|
|
} catch (error) {
|
|
return handleError(res, error, '查询可交付选品方案失败');
|
|
}
|
|
});
|
|
|
|
router.get('/plans/:schemeCode', requireApiKey, requirePlanningAccess, async (req, res) => {
|
|
try {
|
|
const data = await getSelectionFissionDeliveryPackage(buildInput(req));
|
|
res.setHeader('Cache-Control', 'no-store');
|
|
return res.json({ success: true, data });
|
|
} catch (error) {
|
|
return handleError(res, error, '查询选品方案交付包失败');
|
|
}
|
|
});
|
|
|
|
router.get('/shops', requireApiKey, requirePlanningAccess, async (req, res) => {
|
|
try {
|
|
const input = buildRequestInput(req);
|
|
const dingtalkUserName = input.dingtalkUserName
|
|
|| input.dingtalk_user_name
|
|
|| input.dingtalkUsername
|
|
|| input.userName
|
|
|| input.user_name;
|
|
const data = await listSelectionFissionUserShops(dingtalkUserName, {
|
|
includeInactive: normalizeBoolean(input.includeInactive || input.include_inactive, false),
|
|
});
|
|
res.setHeader('Cache-Control', 'no-store');
|
|
return res.json({ success: true, data });
|
|
} catch (error) {
|
|
return handleError(res, error, '查询用户上架店铺失败');
|
|
}
|
|
});
|
|
|
|
router.post('/shops/sync', requireApiKey, requirePlanningAccess, async (req, res) => {
|
|
try {
|
|
const data = await syncSelectionFissionUserShops(
|
|
buildRequestInput(req),
|
|
buildRequestContext(req)
|
|
);
|
|
res.setHeader('Cache-Control', 'no-store');
|
|
return res.json({ success: true, data });
|
|
} catch (error) {
|
|
return handleError(res, error, '同步用户上架店铺失败');
|
|
}
|
|
});
|
|
|
|
router.post('/tasks/claim', requireApiKey, requirePlanningAccess, async (req, res) => {
|
|
try {
|
|
const data = await claimSelectionFissionDeliveryTask(
|
|
buildRequestInput(req),
|
|
buildRequestContext(req)
|
|
);
|
|
res.setHeader('Cache-Control', 'no-store');
|
|
return res.json({ success: true, data });
|
|
} catch (error) {
|
|
return handleError(res, error, '领取自动上架任务失败');
|
|
}
|
|
});
|
|
|
|
async function receiveListingResult(req, res) {
|
|
try {
|
|
const data = await receiveSelectionFissionAutoListingResult(
|
|
req.params.taskId,
|
|
buildListingResultInput(req),
|
|
buildRequestContext(req)
|
|
);
|
|
res.setHeader('Cache-Control', 'no-store');
|
|
return res.json({ success: true, data });
|
|
} catch (error) {
|
|
return handleError(res, error, '回传自动上架商品ID失败');
|
|
}
|
|
}
|
|
|
|
async function receiveListingFailure(req, res) {
|
|
try {
|
|
const data = await receiveSelectionFissionAutoListingFailure(
|
|
req.params.taskId,
|
|
buildListingResultInput(req),
|
|
buildRequestContext(req)
|
|
);
|
|
res.setHeader('Cache-Control', 'no-store');
|
|
return res.json({ success: true, data });
|
|
} catch (error) {
|
|
return handleError(res, error, '回传自动上架失败结果失败');
|
|
}
|
|
}
|
|
|
|
router.post('/tasks/:taskId/listing-result', requireApiKey, requirePlanningAccess, receiveListingResult);
|
|
router.post('/plans/:taskId/listing-result', requireApiKey, requirePlanningAccess, receiveListingResult);
|
|
router.post('/tasks/:taskId/listing-failure', requireApiKey, requirePlanningAccess, receiveListingFailure);
|
|
router.post('/plans/:taskId/listing-failure', requireApiKey, requirePlanningAccess, receiveListingFailure);
|
|
|
|
module.exports = router;
|