feat: 增加多账号备选退避机制支持 cloudSourceKeyFallbacks
- kuaishou-cloud-fulfillment-config-service: 新增 cloudSourceKeyFallbacks 字段和 normalizeStringArray 辅助函数 - kuaishou-cloud-task-service: 新增 resolvePersistedCloudtentaclesContextWithFallback 函数实现备选账号自动切换 - 改造 5 个调用点(prepare/refresh/roleRefresh/dispatch/return)使用 fallback 机制 - binding 中新增 resolvedSourceKey 字段持久化首次选定的 sourceKey - admin-write-inputs: 类型定义增加 cloudSourceKeyFallbacks 可选字段 - 向后兼容:旧数据无 fallbacks 字段时等同于旧行为
This commit is contained in:
@@ -101,6 +101,10 @@ export function normalizeKuaishouCloudFlow(value) {
|
|||||||
String(binding.prepareStatus || "pending").trim() || "pending",
|
String(binding.prepareStatus || "pending").trim() || "pending",
|
||||||
cloudSourceKey:
|
cloudSourceKey:
|
||||||
String(binding.cloudSourceKey || "default").trim() || "default",
|
String(binding.cloudSourceKey || "default").trim() || "default",
|
||||||
|
cloudSourceKeyFallbacks: normalizeStringArray(
|
||||||
|
binding.cloudSourceKeyFallbacks
|
||||||
|
),
|
||||||
|
resolvedSourceKey: String(binding.resolvedSourceKey || "").trim(),
|
||||||
skuId: Number(binding.skuId || 0) || 0,
|
skuId: Number(binding.skuId || 0) || 0,
|
||||||
skuName: String(binding.skuName || "").trim(),
|
skuName: String(binding.skuName || "").trim(),
|
||||||
vnKey:
|
vnKey:
|
||||||
@@ -219,6 +223,66 @@ export function resolvePersistedCloudtentaclesContext(sourceKey = "default") {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按优先级依次尝试 cloudSourceKey 和 fallbacks 列表中的账号,
|
||||||
|
* 找到第一个有可用 token 的账号返回其 context。
|
||||||
|
* 将实际使用的 resolvedSourceKey 也返回,确保后续操作(退号、发货等)
|
||||||
|
* 使用同一个 sourceKey,防止跨账号操作导致数据不一致。
|
||||||
|
*/
|
||||||
|
export function resolvePersistedCloudtentaclesContextWithFallback(
|
||||||
|
primarySourceKey = "default",
|
||||||
|
fallbacks = []
|
||||||
|
) {
|
||||||
|
const candidates = [
|
||||||
|
String(primarySourceKey || "default").trim() || "default",
|
||||||
|
...normalizeStringArray(fallbacks),
|
||||||
|
];
|
||||||
|
|
||||||
|
// 去重但保持顺序
|
||||||
|
const uniqueCandidates = [...new Set(candidates)];
|
||||||
|
|
||||||
|
let lastError = null;
|
||||||
|
|
||||||
|
for (const sourceKey of uniqueCandidates) {
|
||||||
|
const source = getCloudtentaclesSourceByKey(sourceKey);
|
||||||
|
const session = getCloudtentaclesSessionStateByKey(sourceKey);
|
||||||
|
|
||||||
|
// 该账号不存在配置 → 跳过
|
||||||
|
if (!source) continue;
|
||||||
|
|
||||||
|
// 该账号没有 token → 标记跳过但不报错
|
||||||
|
const token = String(session?.token || "").trim();
|
||||||
|
if (!token) {
|
||||||
|
lastError = createHttpError(
|
||||||
|
`cloudtentacles 账号 ${sourceKey} 没有可用 token`,
|
||||||
|
{ statusCode: 409, errorCode: "kuaishou_cloud_missing_cloud_token" }
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 找到可用账号
|
||||||
|
return {
|
||||||
|
baseUrl:
|
||||||
|
String(session.baseUrl || source.baseUrl || "").trim() ||
|
||||||
|
"https://123.207.217.176",
|
||||||
|
token,
|
||||||
|
deviceId:
|
||||||
|
String(session.deviceId || source.deviceId || "-").trim() || "-",
|
||||||
|
deviceType: Number(session.deviceType ?? source.deviceType ?? 0),
|
||||||
|
resolvedSourceKey: sourceKey,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 所有备选都不可用
|
||||||
|
throw (
|
||||||
|
lastError ||
|
||||||
|
createHttpError(
|
||||||
|
"所有 cloudtentacles 备选账号均不可用,请先到平台配置完成登录校验",
|
||||||
|
{ statusCode: 409, errorCode: "kuaishou_cloud_all_source_keys_exhausted" }
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export async function ensureTaskClaimLink(task) {
|
export async function ensureTaskClaimLink(task) {
|
||||||
const tokenStatus = String(task?.primary_claim_token_status || "").trim();
|
const tokenStatus = String(task?.primary_claim_token_status || "").trim();
|
||||||
const token = String(
|
const token = String(
|
||||||
@@ -292,8 +356,9 @@ export async function prepareKuaishouCloudFulfillmentTask(task, options = {}) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const cloudContext = resolvePersistedCloudtentaclesContext(
|
const cloudContext = resolvePersistedCloudtentaclesContextWithFallback(
|
||||||
flow.binding.cloudSourceKey || "default"
|
flow.binding.cloudSourceKey || "default",
|
||||||
|
flow.binding.cloudSourceKeyFallbacks || []
|
||||||
);
|
);
|
||||||
const [knapsack, skuList] = await Promise.all([
|
const [knapsack, skuList] = await Promise.all([
|
||||||
getCloudtentaclesKnapsack(cloudContext),
|
getCloudtentaclesKnapsack(cloudContext),
|
||||||
@@ -395,6 +460,7 @@ export async function prepareKuaishouCloudFulfillmentTask(task, options = {}) {
|
|||||||
...flowWithResolvedBinding,
|
...flowWithResolvedBinding,
|
||||||
binding: {
|
binding: {
|
||||||
...flowWithResolvedBinding.binding,
|
...flowWithResolvedBinding.binding,
|
||||||
|
resolvedSourceKey: cloudContext.resolvedSourceKey,
|
||||||
vnKey: preparedBinding.vnKey,
|
vnKey: preparedBinding.vnKey,
|
||||||
prepareStatus: "ready",
|
prepareStatus: "ready",
|
||||||
vnId: preparedBinding.vnId,
|
vnId: preparedBinding.vnId,
|
||||||
@@ -488,8 +554,11 @@ export async function refreshKuaishouCloudTaskBindUrl(task, options = {}) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const cloudContext = resolvePersistedCloudtentaclesContext(
|
const effectiveSourceKey =
|
||||||
flow.binding.cloudSourceKey || "default"
|
flow.binding.resolvedSourceKey || flow.binding.cloudSourceKey || "default";
|
||||||
|
const cloudContext = resolvePersistedCloudtentaclesContextWithFallback(
|
||||||
|
effectiveSourceKey,
|
||||||
|
flow.binding.cloudSourceKeyFallbacks || []
|
||||||
);
|
);
|
||||||
const oldVnKey = flow.binding.vnKey;
|
const oldVnKey = flow.binding.vnKey;
|
||||||
const oldVnId = flow.binding.vnId;
|
const oldVnId = flow.binding.vnId;
|
||||||
@@ -851,8 +920,11 @@ export async function refreshKuaishouCloudTaskRoleInfo(task, options = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const cloudContext = resolvePersistedCloudtentaclesContext(
|
const effectiveSourceKey =
|
||||||
flow.binding.cloudSourceKey || "default"
|
flow.binding.resolvedSourceKey || flow.binding.cloudSourceKey || "default";
|
||||||
|
const cloudContext = resolvePersistedCloudtentaclesContextWithFallback(
|
||||||
|
effectiveSourceKey,
|
||||||
|
flow.binding.cloudSourceKeyFallbacks || []
|
||||||
);
|
);
|
||||||
const bindInfoResult = await getCloudtentaclesBindInfo({
|
const bindInfoResult = await getCloudtentaclesBindInfo({
|
||||||
...cloudContext,
|
...cloudContext,
|
||||||
@@ -925,8 +997,11 @@ export async function dispatchKuaishouCloudFulfillmentTask(task, options = {}) {
|
|||||||
const now = nowIso();
|
const now = nowIso();
|
||||||
const taskContext = parseTaskContext(task);
|
const taskContext = parseTaskContext(task);
|
||||||
const flow = normalizeKuaishouCloudFlow(taskContext.kuaishouCloudFulfillment);
|
const flow = normalizeKuaishouCloudFlow(taskContext.kuaishouCloudFulfillment);
|
||||||
const cloudContext = resolvePersistedCloudtentaclesContext(
|
const effectiveSourceKey =
|
||||||
flow.binding.cloudSourceKey || "default"
|
flow.binding.resolvedSourceKey || flow.binding.cloudSourceKey || "default";
|
||||||
|
const cloudContext = resolvePersistedCloudtentaclesContextWithFallback(
|
||||||
|
effectiveSourceKey,
|
||||||
|
flow.binding.cloudSourceKeyFallbacks || []
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!flow.binding.skuId || !flow.binding.vnId || !flow.binding.vnPhone) {
|
if (!flow.binding.skuId || !flow.binding.vnId || !flow.binding.vnPhone) {
|
||||||
@@ -1054,8 +1129,11 @@ export async function returnKuaishouCloudFulfillmentTask(task, options = {}) {
|
|||||||
const now = nowIso();
|
const now = nowIso();
|
||||||
const taskContext = parseTaskContext(task);
|
const taskContext = parseTaskContext(task);
|
||||||
const flow = normalizeKuaishouCloudFlow(taskContext.kuaishouCloudFulfillment);
|
const flow = normalizeKuaishouCloudFlow(taskContext.kuaishouCloudFulfillment);
|
||||||
const cloudContext = resolvePersistedCloudtentaclesContext(
|
const effectiveSourceKey =
|
||||||
flow.binding.cloudSourceKey || "default"
|
flow.binding.resolvedSourceKey || flow.binding.cloudSourceKey || "default";
|
||||||
|
const cloudContext = resolvePersistedCloudtentaclesContextWithFallback(
|
||||||
|
effectiveSourceKey,
|
||||||
|
flow.binding.cloudSourceKeyFallbacks || []
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!flow.binding.vnId || !flow.binding.vnKey) {
|
if (!flow.binding.vnId || !flow.binding.vnKey) {
|
||||||
@@ -1561,3 +1639,16 @@ function isClaimExpired(expiredAt) {
|
|||||||
const timestamp = new Date(expiredAt).getTime();
|
const timestamp = new Date(expiredAt).getTime();
|
||||||
return Number.isFinite(timestamp) && timestamp <= Date.now();
|
return Number.isFinite(timestamp) && timestamp <= Date.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeStringArray(value) {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value.map((v) => String(v || "").trim()).filter(Boolean);
|
||||||
|
}
|
||||||
|
if (typeof value === "string") {
|
||||||
|
return value
|
||||||
|
.split(",")
|
||||||
|
.map((v) => v.trim())
|
||||||
|
.filter(Boolean);
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,174 +1,227 @@
|
|||||||
import fs from 'node:fs'
|
import fs from "node:fs";
|
||||||
import path from 'node:path'
|
import path from "node:path";
|
||||||
|
|
||||||
import { PROJECT_ROOT } from '../../config/runtime.js'
|
import { PROJECT_ROOT } from "../../config/runtime.js";
|
||||||
import { resolveKuaishouEticketShopConfig } from '../platforms/kuaishou-eticket/source-config-service.js'
|
import { resolveKuaishouEticketShopConfig } from "../platforms/kuaishou-eticket/source-config-service.js";
|
||||||
|
|
||||||
const KUAISHOU_CLOUD_FULFILLMENT_FILE_PATH = path.join(PROJECT_ROOT, 'data', 'kuaishou-cloud-fulfillment.json')
|
const KUAISHOU_CLOUD_FULFILLMENT_FILE_PATH = path.join(
|
||||||
|
PROJECT_ROOT,
|
||||||
|
"data",
|
||||||
|
"kuaishou-cloud-fulfillment.json"
|
||||||
|
);
|
||||||
|
|
||||||
export function getKuaishouCloudFulfillmentFilePath() {
|
export function getKuaishouCloudFulfillmentFilePath() {
|
||||||
return KUAISHOU_CLOUD_FULFILLMENT_FILE_PATH
|
return KUAISHOU_CLOUD_FULFILLMENT_FILE_PATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getKuaishouCloudFulfillmentConfig() {
|
export function getKuaishouCloudFulfillmentConfig() {
|
||||||
return loadKuaishouCloudFulfillmentConfigFromFile()
|
return loadKuaishouCloudFulfillmentConfigFromFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function saveKuaishouCloudFulfillmentConfig(rawValue) {
|
export function saveKuaishouCloudFulfillmentConfig(rawValue) {
|
||||||
const normalized = normalizeKuaishouCloudFulfillmentConfig(rawValue)
|
const normalized = normalizeKuaishouCloudFulfillmentConfig(rawValue);
|
||||||
fs.mkdirSync(path.dirname(KUAISHOU_CLOUD_FULFILLMENT_FILE_PATH), { recursive: true })
|
fs.mkdirSync(path.dirname(KUAISHOU_CLOUD_FULFILLMENT_FILE_PATH), {
|
||||||
|
recursive: true,
|
||||||
|
});
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
KUAISHOU_CLOUD_FULFILLMENT_FILE_PATH,
|
KUAISHOU_CLOUD_FULFILLMENT_FILE_PATH,
|
||||||
`${JSON.stringify(normalized, null, 2)}\n`,
|
`${JSON.stringify(normalized, null, 2)}\n`,
|
||||||
'utf8',
|
"utf8"
|
||||||
)
|
);
|
||||||
return normalized
|
return normalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mapKuaishouCloudFulfillmentItemsToBindings(config = {}) {
|
export function mapKuaishouCloudFulfillmentItemsToBindings(config = {}) {
|
||||||
const items = Array.isArray(config.items) ? config.items : []
|
const items = Array.isArray(config.items) ? config.items : [];
|
||||||
|
|
||||||
return items
|
return items
|
||||||
.filter((item) => item && item.enabled !== false)
|
.filter((item) => item && item.enabled !== false)
|
||||||
.map((item) => ({
|
.map((item) => ({
|
||||||
provider: String(item.provider || '91kaquan').trim() || '91kaquan',
|
provider: String(item.provider || "91kaquan").trim() || "91kaquan",
|
||||||
platform: String(item.platform || 'kuaishou').trim() || 'kuaishou',
|
platform: String(item.platform || "kuaishou").trim() || "kuaishou",
|
||||||
shopId: String(item.shopId || '').trim(),
|
shopId: String(item.shopId || "").trim(),
|
||||||
skuCode: String(item.internalSkuCode || '').trim(),
|
skuCode: String(item.internalSkuCode || "").trim(),
|
||||||
skuName: String(item.internalSkuName || '').trim(),
|
skuName: String(item.internalSkuName || "").trim(),
|
||||||
profileKey: 'kuaishou_ct_assisted',
|
profileKey: "kuaishou_ct_assisted",
|
||||||
enabled: item.enabled !== false,
|
enabled: item.enabled !== false,
|
||||||
priority: normalizePriority(item.priority),
|
priority: normalizePriority(item.priority),
|
||||||
config: {
|
config: {
|
||||||
flowType: 'kuaishou_cloud_fulfillment',
|
flowType: "kuaishou_cloud_fulfillment",
|
||||||
configId: String(item.id || '').trim(),
|
configId: String(item.id || "").trim(),
|
||||||
cloudtentacles: {
|
cloudtentacles: {
|
||||||
cloudSourceKey: String(item.cloudSourceKey || 'default').trim() || 'default',
|
cloudSourceKey:
|
||||||
|
String(item.cloudSourceKey || "default").trim() || "default",
|
||||||
|
cloudSourceKeyFallbacks: Array.isArray(item.cloudSourceKeyFallbacks)
|
||||||
|
? item.cloudSourceKeyFallbacks
|
||||||
|
: [],
|
||||||
skuId: normalizePositiveInteger(item.cloudSkuId),
|
skuId: normalizePositiveInteger(item.cloudSkuId),
|
||||||
skuName: String(item.cloudSkuName || '').trim(),
|
skuName: String(item.cloudSkuName || "").trim(),
|
||||||
vnKey: '1',
|
vnKey: "1",
|
||||||
autoBuyEnabled: item.autoBuyEnabled !== false,
|
autoBuyEnabled: item.autoBuyEnabled !== false,
|
||||||
minAssetReserve: normalizeNonNegativeInteger(item.minAssetReserve, 0),
|
minAssetReserve: normalizeNonNegativeInteger(item.minAssetReserve, 0),
|
||||||
autoReturnNumberAfterDispatch: item.autoReturnNumberAfterDispatch === true,
|
autoReturnNumberAfterDispatch:
|
||||||
|
item.autoReturnNumberAfterDispatch === true,
|
||||||
},
|
},
|
||||||
kuaishouConsume: {
|
kuaishouConsume: {
|
||||||
shopId: String(item.kuaishouConsumeShopId || '').trim(),
|
shopId: String(item.kuaishouConsumeShopId || "").trim(),
|
||||||
shopName: String(item.kuaishouConsumeShopName || '').trim(),
|
shopName: String(item.kuaishouConsumeShopName || "").trim(),
|
||||||
autoConsumeAfterDispatch: item.autoConsumeAfterDispatch === true,
|
autoConsumeAfterDispatch: item.autoConsumeAfterDispatch === true,
|
||||||
},
|
},
|
||||||
notes: String(item.notes || '').trim(),
|
notes: String(item.notes || "").trim(),
|
||||||
},
|
},
|
||||||
match: {
|
match: {
|
||||||
externalSkuCode: String(item.externalSkuCode || '').trim(),
|
externalSkuCode: String(item.externalSkuCode || "").trim(),
|
||||||
externalItemId: String(item.externalItemId || '').trim(),
|
externalItemId: String(item.externalItemId || "").trim(),
|
||||||
externalSkuName: String(item.externalSkuName || '').trim(),
|
externalSkuName: String(item.externalSkuName || "").trim(),
|
||||||
config: {
|
config: {
|
||||||
resolvedSkuName: String(item.resolvedSkuName || item.internalSkuName || '').trim(),
|
resolvedSkuName: String(
|
||||||
|
item.resolvedSkuName || item.internalSkuName || ""
|
||||||
|
).trim(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
.filter((item) => item.skuCode && (item.match.externalSkuCode || item.match.externalItemId || item.match.externalSkuName))
|
.filter(
|
||||||
|
(item) =>
|
||||||
|
item.skuCode &&
|
||||||
|
(item.match.externalSkuCode ||
|
||||||
|
item.match.externalItemId ||
|
||||||
|
item.match.externalSkuName)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadKuaishouCloudFulfillmentConfigFromFile() {
|
function loadKuaishouCloudFulfillmentConfigFromFile() {
|
||||||
if (!fs.existsSync(KUAISHOU_CLOUD_FULFILLMENT_FILE_PATH)) {
|
if (!fs.existsSync(KUAISHOU_CLOUD_FULFILLMENT_FILE_PATH)) {
|
||||||
return normalizeKuaishouCloudFulfillmentConfig({})
|
return normalizeKuaishouCloudFulfillmentConfig({});
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const rawText = fs.readFileSync(KUAISHOU_CLOUD_FULFILLMENT_FILE_PATH, 'utf8')
|
const rawText = fs.readFileSync(
|
||||||
const parsed = JSON.parse(rawText)
|
KUAISHOU_CLOUD_FULFILLMENT_FILE_PATH,
|
||||||
return normalizeKuaishouCloudFulfillmentConfig(parsed)
|
"utf8"
|
||||||
|
);
|
||||||
|
const parsed = JSON.parse(rawText);
|
||||||
|
return normalizeKuaishouCloudFulfillmentConfig(parsed);
|
||||||
} catch {
|
} catch {
|
||||||
return normalizeKuaishouCloudFulfillmentConfig({})
|
return normalizeKuaishouCloudFulfillmentConfig({});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeKuaishouCloudFulfillmentConfig(rawValue) {
|
function normalizeKuaishouCloudFulfillmentConfig(rawValue) {
|
||||||
const source = isPlainObject(rawValue) ? rawValue : {}
|
const source = isPlainObject(rawValue) ? rawValue : {};
|
||||||
return {
|
return {
|
||||||
enabled: source.enabled !== false,
|
enabled: source.enabled !== false,
|
||||||
items: Array.isArray(source.items)
|
items: Array.isArray(source.items)
|
||||||
? source.items.map((item) => normalizeKuaishouCloudFulfillmentItem(item)).filter(Boolean)
|
? source.items
|
||||||
|
.map((item) => normalizeKuaishouCloudFulfillmentItem(item))
|
||||||
|
.filter(Boolean)
|
||||||
: [],
|
: [],
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeKuaishouCloudFulfillmentItem(rawValue) {
|
function normalizeKuaishouCloudFulfillmentItem(rawValue) {
|
||||||
if (!isPlainObject(rawValue)) {
|
if (!isPlainObject(rawValue)) {
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const internalSkuCode = String(rawValue.internalSkuCode || '').trim()
|
const internalSkuCode = String(rawValue.internalSkuCode || "").trim();
|
||||||
const cloudSkuId = normalizePositiveInteger(rawValue.cloudSkuId)
|
const cloudSkuId = normalizePositiveInteger(rawValue.cloudSkuId);
|
||||||
const externalSkuCode = String(rawValue.externalSkuCode || '').trim()
|
const externalSkuCode = String(rawValue.externalSkuCode || "").trim();
|
||||||
const externalItemId = String(rawValue.externalItemId || '').trim()
|
const externalItemId = String(rawValue.externalItemId || "").trim();
|
||||||
const externalSkuName = String(rawValue.externalSkuName || '').trim()
|
const externalSkuName = String(rawValue.externalSkuName || "").trim();
|
||||||
const kuaishouConsumeShopId = String(rawValue.kuaishouConsumeShopId || '').trim()
|
const kuaishouConsumeShopId = String(
|
||||||
const kuaishouConsumeShopName = String(rawValue.kuaishouConsumeShopName || '').trim()
|
rawValue.kuaishouConsumeShopId || ""
|
||||||
|
).trim();
|
||||||
|
const kuaishouConsumeShopName = String(
|
||||||
|
rawValue.kuaishouConsumeShopName || ""
|
||||||
|
).trim();
|
||||||
const kuaishouShopConfig = resolveKuaishouEticketShopConfig({
|
const kuaishouShopConfig = resolveKuaishouEticketShopConfig({
|
||||||
shopId: kuaishouConsumeShopId,
|
shopId: kuaishouConsumeShopId,
|
||||||
shopName: kuaishouConsumeShopName,
|
shopName: kuaishouConsumeShopName,
|
||||||
})
|
});
|
||||||
|
|
||||||
if (!internalSkuCode) {
|
if (!internalSkuCode) {
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cloudSkuId) {
|
if (!cloudSkuId) {
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!externalSkuCode && !externalItemId && !externalSkuName) {
|
if (!externalSkuCode && !externalItemId && !externalSkuName) {
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: String(rawValue.id || internalSkuCode).trim() || internalSkuCode,
|
id: String(rawValue.id || internalSkuCode).trim() || internalSkuCode,
|
||||||
enabled: rawValue.enabled !== false,
|
enabled: rawValue.enabled !== false,
|
||||||
priority: normalizePriority(rawValue.priority),
|
priority: normalizePriority(rawValue.priority),
|
||||||
provider: String(rawValue.provider || '91kaquan').trim() || '91kaquan',
|
provider: String(rawValue.provider || "91kaquan").trim() || "91kaquan",
|
||||||
platform: String(rawValue.platform || 'kuaishou').trim() || 'kuaishou',
|
platform: String(rawValue.platform || "kuaishou").trim() || "kuaishou",
|
||||||
shopId: String(rawValue.shopId || '').trim(),
|
shopId: String(rawValue.shopId || "").trim(),
|
||||||
internalSkuCode,
|
internalSkuCode,
|
||||||
internalSkuName: String(rawValue.internalSkuName || '').trim() || internalSkuCode,
|
internalSkuName:
|
||||||
|
String(rawValue.internalSkuName || "").trim() || internalSkuCode,
|
||||||
externalSkuCode,
|
externalSkuCode,
|
||||||
externalItemId,
|
externalItemId,
|
||||||
externalSkuName,
|
externalSkuName,
|
||||||
resolvedSkuName: String(rawValue.resolvedSkuName || rawValue.internalSkuName || '').trim(),
|
resolvedSkuName: String(
|
||||||
cloudSourceKey: String(rawValue.cloudSourceKey || 'default').trim() || 'default',
|
rawValue.resolvedSkuName || rawValue.internalSkuName || ""
|
||||||
|
).trim(),
|
||||||
|
cloudSourceKey:
|
||||||
|
String(rawValue.cloudSourceKey || "default").trim() || "default",
|
||||||
|
cloudSourceKeyFallbacks: normalizeStringArray(
|
||||||
|
rawValue.cloudSourceKeyFallbacks
|
||||||
|
),
|
||||||
cloudSkuId,
|
cloudSkuId,
|
||||||
cloudSkuName: String(rawValue.cloudSkuName || '').trim(),
|
cloudSkuName: String(rawValue.cloudSkuName || "").trim(),
|
||||||
vnKey: '1',
|
vnKey: "1",
|
||||||
autoBuyEnabled: rawValue.autoBuyEnabled !== false,
|
autoBuyEnabled: rawValue.autoBuyEnabled !== false,
|
||||||
minAssetReserve: normalizeNonNegativeInteger(rawValue.minAssetReserve, 0),
|
minAssetReserve: normalizeNonNegativeInteger(rawValue.minAssetReserve, 0),
|
||||||
autoReturnNumberAfterDispatch: rawValue.autoReturnNumberAfterDispatch === true,
|
autoReturnNumberAfterDispatch:
|
||||||
|
rawValue.autoReturnNumberAfterDispatch === true,
|
||||||
autoConsumeAfterDispatch: rawValue.autoConsumeAfterDispatch === true,
|
autoConsumeAfterDispatch: rawValue.autoConsumeAfterDispatch === true,
|
||||||
kuaishouConsumeShopId: String(kuaishouShopConfig?.shopId || kuaishouConsumeShopId).trim(),
|
kuaishouConsumeShopId: String(
|
||||||
kuaishouConsumeShopName: String(kuaishouShopConfig?.kshopName || kuaishouConsumeShopName).trim(),
|
kuaishouShopConfig?.shopId || kuaishouConsumeShopId
|
||||||
notes: String(rawValue.notes || '').trim(),
|
).trim(),
|
||||||
}
|
kuaishouConsumeShopName: String(
|
||||||
|
kuaishouShopConfig?.kshopName || kuaishouConsumeShopName
|
||||||
|
).trim(),
|
||||||
|
notes: String(rawValue.notes || "").trim(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizePositiveInteger(value) {
|
function normalizePositiveInteger(value) {
|
||||||
const parsed = Number(value)
|
const parsed = Number(value);
|
||||||
return Number.isInteger(parsed) && parsed > 0 ? parsed : 0
|
return Number.isInteger(parsed) && parsed > 0 ? parsed : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeNonNegativeInteger(value, fallback) {
|
function normalizeNonNegativeInteger(value, fallback) {
|
||||||
const parsed = Number(value)
|
const parsed = Number(value);
|
||||||
return Number.isInteger(parsed) && parsed >= 0 ? parsed : fallback
|
return Number.isInteger(parsed) && parsed >= 0 ? parsed : fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizePriority(value) {
|
function normalizePriority(value) {
|
||||||
const parsed = Number(value)
|
const parsed = Number(value);
|
||||||
if (!Number.isFinite(parsed)) {
|
if (!Number.isFinite(parsed)) {
|
||||||
return 100
|
return 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Math.max(1, Math.round(parsed))
|
return Math.max(1, Math.round(parsed));
|
||||||
}
|
}
|
||||||
|
|
||||||
function isPlainObject(value) {
|
function isPlainObject(value) {
|
||||||
return Object.prototype.toString.call(value) === '[object Object]'
|
return Object.prototype.toString.call(value) === "[object Object]";
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeStringArray(value) {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value.map((v) => String(v || "").trim()).filter(Boolean);
|
||||||
|
}
|
||||||
|
// 兼容旧格式:字符串用逗号分隔
|
||||||
|
if (typeof value === "string") {
|
||||||
|
return value
|
||||||
|
.split(",")
|
||||||
|
.map((v) => v.trim())
|
||||||
|
.filter(Boolean);
|
||||||
|
}
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ export {};
|
|||||||
* externalSkuName?: string
|
* externalSkuName?: string
|
||||||
* resolvedSkuName?: string
|
* resolvedSkuName?: string
|
||||||
* cloudSourceKey?: string
|
* cloudSourceKey?: string
|
||||||
|
* cloudSourceKeyFallbacks?: string[]
|
||||||
* cloudSkuId?: number | string
|
* cloudSkuId?: number | string
|
||||||
* cloudSkuName?: string
|
* cloudSkuName?: string
|
||||||
* vnKey?: string
|
* vnKey?: string
|
||||||
|
|||||||
Reference in New Issue
Block a user