import 'dotenv/config'; import { loadConfig } from '../src/config/env.js'; import { ParseRestClient } from '../src/db/parse-rest.client.js'; import { VOC_PARSE_CLASSES } from '../src/db/parse-rest.schema.js'; interface ProductObject { workspaceId: string; productKey: string; productId: string; role: 'own' | 'competitor'; category1?: string; category2?: string; category3?: string; summary?: { gmv?: number; soldUnits?: number }; } const config = loadConfig(); if (config.storageDriver !== 'parse_rest') throw new Error('STORAGE_DRIVER must be parse_rest'); const workspaceId = process.argv[2] || config.auth.defaultWorkspaceId; const limitArgument = process.argv[3] || '8'; const limit = Math.max(1, Math.min(50, Number.parseInt(limitArgument, 10) || 8)); const actorUserId = config.auth.localUserId || 'bootstrap'; const client = new ParseRestClient({ serverUrl: config.parse.serverUrl, appId: config.parse.appId, masterKey: config.parse.masterKey, timeoutMs: config.parse.timeoutMs, }); const products = await client.findAll(VOC_PARSE_CLASSES.product, { workspaceId, role: 'own', }); const candidates = products .sort((left, right) => Number(right.summary?.gmv ?? 0) - Number(left.summary?.gmv ?? 0) || Number(right.summary?.soldUnits ?? 0) - Number(left.summary?.soldUnits ?? 0)) .slice(0, limit); let created = 0; let existing = 0; for (const product of candidates) { const naturalKey = `${workspaceId}:${product.productKey}`; if (await client.findOne(VOC_PARSE_CLASSES.productKnowledge, { naturalKey })) { existing += 1; continue; } const category = product.category3 || product.category2 || product.category1 || ''; await client.create(VOC_PARSE_CLASSES.productKnowledge, { naturalKey, workspaceId, productKey: product.productKey, productId: product.productId, productRole: product.role, featured: true, status: 'active', tags: ['经营TOP', ...(category ? [category] : [])], note: '按成交金额初始化的重点商品,可在知识库内补充关注事项。', ownerUserId: '', createdBy: actorUserId, updatedBy: actorUserId, }); created += 1; } console.log(JSON.stringify({ workspaceId, candidates: candidates.length, created, existing }, null, 2));