优化 cloudtentacles 多账号管理与任务展示

This commit is contained in:
yml
2026-05-25 16:48:23 +08:00
parent e3d318d7f3
commit 28c8575a11
17 changed files with 495 additions and 167 deletions
@@ -90,6 +90,10 @@ export function mapKuaishouCloudFulfillmentContext(value: unknown): JsonRecord |
binding: {
prepareStatus: String(binding.prepareStatus || 'pending').trim() || 'pending',
cloudSourceKey: String(binding.cloudSourceKey || '').trim(),
cloudSourceKeyFallbacks: Array.isArray(binding.cloudSourceKeyFallbacks)
? binding.cloudSourceKeyFallbacks.map((value) => String(value || '').trim()).filter(Boolean)
: [],
resolvedSourceKey: String(binding.resolvedSourceKey || '').trim(),
skuId: Number(binding.skuId || 0) || 0,
skuName: String(binding.skuName || '').trim(),
vnKey: String(binding.vnKey || '').trim(),
@@ -8,10 +8,12 @@ import {
} from "../../platforms/cloudtentacles/source-config-service.js";
import {
clearCloudtentaclesSessionStateByKey,
deleteCloudtentaclesSessionStateByKey,
getCloudtentaclesSessionFilePath,
getCloudtentaclesSessionStateByKey,
saveCloudtentaclesSessionStateByKey,
getAllCloudtentaclesSessionStates,
pruneCloudtentaclesSessionStates,
} from "../../platforms/cloudtentacles/session-state-service.js";
import {
loginCloudtentaclesSession,
@@ -102,7 +104,9 @@ export function updateAdminCloudtentaclesSourceConfig(
enabled: payload.enabled !== false,
sources: normalizedList,
});
const sessions = getAllCloudtentaclesSessionStates();
const sessions = pruneCloudtentaclesSessionStates(
normalizedList.map((item) => item.key)
);
const sources = Array.isArray(savedList.sources)
? savedList.sources.map((s) => mapAdminCloudtentaclesSourceConfig(s))
@@ -151,7 +155,7 @@ export function deleteAdminCloudtentaclesSource(sourceKey: string) {
if (!key) {
throw new Error("sourceKey is required for deletion");
}
clearCloudtentaclesSessionStateByKey(key);
deleteCloudtentaclesSessionStateByKey(key);
deleteCloudtentaclesSourceByKey(key);
}
@@ -190,3 +190,23 @@ test('buildAdminCloudtentaclesValidateResult assembles validate response payload
},
)
})
test('buildAdminCloudtentaclesSessionSummary preserves sourceKey', () => {
assert.deepEqual(
buildAdminCloudtentaclesSessionSummary(
{
token: 'abcdef1234567890',
permissions: [],
},
{},
'account2',
),
{
sourceKey: 'account2',
tokenMasked: 'abcdef****567890',
permissionCount: 0,
permissions: [],
persisted: false,
},
)
})
@@ -104,6 +104,7 @@ test('mapAdminKuaishouCloudFulfillmentSource normalizes items and defaults', ()
externalSkuName: '',
resolvedSkuName: '',
cloudSourceKey: 'default',
cloudSourceKeyFallbacks: [],
cloudSkuId: 0,
cloudSkuName: '',
vnKey: '',
@@ -77,6 +77,11 @@ export function mapAdminKuaishouCloudFulfillmentItem(item: JsonObject = {}) {
resolvedSkuName: String(item.resolvedSkuName || "").trim(),
cloudSourceKey:
String(item.cloudSourceKey || "default").trim() || "default",
cloudSourceKeyFallbacks: Array.isArray(item.cloudSourceKeyFallbacks)
? item.cloudSourceKeyFallbacks
.map((value) => String(value || "").trim())
.filter(Boolean)
: [],
cloudSkuId: Number(item.cloudSkuId || 0) || 0,
cloudSkuName: String(item.cloudSkuName || "").trim(),
vnKey: String(item.vnKey || "").trim(),
@@ -61,6 +61,13 @@ export function resolvePersistedCloudtentaclesContextWithFallback(
const session = getCloudtentaclesSessionStateByKey(sourceKey);
if (!source) continue;
if (source.enabled === false) {
lastError = createHttpError(
`cloudtentacles 账号 ${sourceKey} 已停用`,
{ statusCode: 409, errorCode: "kuaishou_cloud_source_disabled" }
);
continue;
}
const token = String(session?.token || "").trim();
if (!token) {
@@ -65,6 +65,23 @@ export function saveCloudtentaclesSessionStateByKey(sourceKey: unknown, rawValue
return states.sessions[key]
}
/**
* Delete a session by sourceKey.
*/
export function deleteCloudtentaclesSessionStateByKey(sourceKey: unknown) {
const key = String(sourceKey || '').trim()
if (!key) {
throw new Error('deleteCloudtentaclesSessionStateByKey: sourceKey is required')
}
const states = loadCloudtentaclesSessionStatesFromFile()
delete states.sessions[key]
fs.mkdirSync(path.dirname(CLOUDTENTACLES_SESSION_FILE_PATH), { recursive: true })
fs.writeFileSync(CLOUDTENTACLES_SESSION_FILE_PATH, `${JSON.stringify(states, null, 2)}\n`, 'utf8')
return states
}
/**
* Backward-compatible clear: clears the 'default' session only.
*/
@@ -86,6 +103,26 @@ export function clearCloudtentaclesSessionStateByKey(sourceKey: unknown) {
return cleared
}
/**
* Keep only sessions whose sourceKey still exists in source config.
*/
export function pruneCloudtentaclesSessionStates(sourceKeys: unknown[] = []) {
const allowedKeys = new Set(
Array.isArray(sourceKeys)
? sourceKeys.map((value) => String(value || '').trim()).filter(Boolean)
: []
)
const states = loadCloudtentaclesSessionStatesFromFile()
states.sessions = Object.fromEntries(
Object.entries(states.sessions || {}).filter(([key]) => allowedKeys.has(String(key || '').trim()))
)
fs.mkdirSync(path.dirname(CLOUDTENTACLES_SESSION_FILE_PATH), { recursive: true })
fs.writeFileSync(CLOUDTENTACLES_SESSION_FILE_PATH, `${JSON.stringify(states, null, 2)}\n`, 'utf8')
return states
}
// ---------------------------------------------------------------------------
// Internal helpers
// ---------------------------------------------------------------------------
@@ -133,6 +133,7 @@ function normalizeCloudtentaclesSourceItem(rawValue: unknown) {
return {
key: String(source.key || 'default').trim() || 'default',
label: String(source.label || '').trim(),
enabled: source.enabled !== false,
baseUrl: String(source.baseUrl || 'https://123.207.217.176').trim() || 'https://123.207.217.176',
username: String(source.username || '').trim(),
password: String(source.password || '').trim(),