import React, { useState, useEffect, useRef } from 'react'; import { UploadCloud, Settings, Download, CheckCircle, Loader2, Activity, Ban, Trash2, Plus, AlertTriangle } from 'lucide-react'; export default function AmazonBidOptimizer() { const [activeTab, setActiveTab] = useState('optimizer'); const [isProcessing, setIsProcessing] = useState(false); const [progressMsg, setProgressMsg] = useState(""); const [fileData, setFileData] = useState(null); const [slimExport, setSlimExport] = useState(true); const fileInputRef = useRef(null); const [extractedSpus, setExtractedSpus] = useState([]); const [activeCampaigns, setActiveCampaigns] = useState([]); const [dedupSet, setDedupSet] = useState(new Set()); const [activeAdGroupIds, setActiveAdGroupIds] = useState(new Set()); const [spuRules, setSpuRules] = useState([{ id: Date.now(), keyword: '', targetAcos: 25 }]); const [summary, setSummary] = useState(null); const [params, setParams] = useState({ acosBuffer: 10, maxBid: 1.00, minBid: 0.10, clickThreshold: 20, impressionThreshold: 500, increasePcnt: 10, decreasePcnt: 20, increaseTosPcnt: 10, negClickThreshold: 25, negSpendThreshold: 15.0, pauseClickThresholdTarget: 35, pauseAcosThresholdTarget: 60, pauseClickThresholdSku: 30, pauseAcosThresholdSku: 50, pauseSpendThresholdCampaign: 40, pauseSpendThresholdAdGroup: 30, enableTimeBasedPause: false, pauseTimeThresholdDays: 14 }); const [globalNegState, setGlobalNegState] = useState({ spu: '', exact: '', phrase: '', asin: '' }); // 动态加载 XLSX useEffect(() => { if (typeof window !== 'undefined' && !window.XLSX) { const script = document.createElement('script'); script.src = 'https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js'; script.async = true; document.body.appendChild(script); } }, []); const handleParamChange = (e) => { const { name, value, type, checked } = e.target; const finalValue = type === 'checkbox' ? checked : (parseFloat(value) || 0); setParams(prev => ({ ...prev, [name]: finalValue })); setSummary(null); }; const addSpuRule = () => setSpuRules([{ id: Date.now(), keyword: '', targetAcos: 25 }, ...spuRules]); const updateSpuRule = (id, field, value) => { setSpuRules(spuRules.map(r => r.id === id ? { ...r, [field]: value } : r)); setSummary(null); }; const removeSpuRule = (id) => { setSpuRules(spuRules.filter(r => r.id !== id)); setSummary(null); }; const getVal = (row, keys) => { for (let k of keys) { if (row[k] !== undefined && row[k] !== null) return String(row[k]).trim(); } return ""; }; const parseAmzDate = (dateStr) => { if (!dateStr) return null; dateStr = String(dateStr).trim(); if (/^\d{8}$/.test(dateStr)) { return new Date(parseInt(dateStr.slice(0,4)), parseInt(dateStr.slice(4,6))-1, parseInt(dateStr.slice(6,8))); } const d = new Date(dateStr); if (!isNaN(d.getTime())) return d; return null; }; const handleFileUpload = (e) => { const file = e.target.files[0]; if (!file) return; if (!window.XLSX) { alert("组件正在加载中,请稍候几秒再上传..."); return; } setIsProcessing(true); setProgressMsg("正在解析底层数据引擎..."); setSummary(null); setFileData(null); const reader = new FileReader(); reader.onload = (evt) => { setTimeout(() => { try { const data = new Uint8Array(evt.target.result); const XLSX = window.XLSX; const workbook = XLSX.read(data, { type: 'array' }); const targetSheetName = workbook.SheetNames.find(n => n.includes('Sponsored Products') || n.includes('商品推广')) || workbook.SheetNames[0]; const worksheet = workbook.Sheets[targetSheetName]; const originalHeaders = XLSX.utils.sheet_to_json(worksheet, { header: 1 })[0]; const jsonData = XLSX.utils.sheet_to_json(worksheet, { raw: false }); const stSheetName = workbook.SheetNames.find(n => n.includes('Search Term Report') || n.includes('搜索词报告')); const stData = stSheetName ? XLSX.utils.sheet_to_json(workbook.Sheets[stSheetName], { raw: false }) : null; const allActiveCampaigns = []; const tempDedupSet = new Set(); const tempActiveAdGroups = new Set(); const spuSet = new Set(); jsonData.forEach(row => { const entity = getVal(row, ['Entity', '实体', '实体层级', 'Record Type']).toLowerCase(); const state = getVal(row, ['State', '状态', 'Status']).toLowerCase(); const cName = getVal(row, ['Campaign Name', '广告活动名称', 'Campaign Name (Informational only)']); const cId = getVal(row, ['Campaign Id', '广告活动编号', 'Campaign ID']); const aId = getVal(row, ['Ad Group Id', '广告组编号', 'Ad Group ID']); const pNameStr = getVal(row, ['Portfolio Name', '广告组合名称', 'Portfolio Name (Informational only)', '广告组合名称(仅供参考)']).toUpperCase(); if (aId && (state === 'enabled' || state === 'paused' || state === '已启用' || state === '已暂停')) { tempActiveAdGroups.add(aId); } if ((entity === 'campaign' || entity === '广告活动') && state !== 'archived' && state !== '已归档') { allActiveCampaigns.push({ cId, cName }); if (pNameStr === 'L') { const segments = cName.split(/[-_ \/]+/); for (const seg of segments) { if (!/[\u4e00-\u9fa5]/.test(seg) && seg.length >= 4 && /[A-Za-z0-9]/.test(seg)) { spuSet.add(seg.toUpperCase()); break; } } } } if (entity.includes('negative') || entity.includes('否定')) { const kw = getVal(row, ['Keyword Text', '关键词文本']).toLowerCase(); const expr = getVal(row, ['Product Targeting Expression', '商品投放表达式', 'Product targeting expression']).toLowerCase(); const matchTypeRaw = getVal(row, ['Match Type', '匹配类型']).toLowerCase(); const isCampaignLevel = entity.includes('campaign') || entity.includes('广告活动') || !aId; let matchType = ''; if (matchTypeRaw.includes('exact') || matchTypeRaw.includes('精准')) matchType = 'exact'; else if (matchTypeRaw.includes('phrase') || matchTypeRaw.includes('词组')) matchType = 'phrase'; if (kw) { if (isCampaignLevel) { tempDedupSet.add(`CAMP_${cId}_${kw}_${matchType}`); } else { tempDedupSet.add(`ADG_${cId}_${aId}_${kw}_${matchType}`); } } if (expr) { if (isCampaignLevel) { tempDedupSet.add(`CAMP_${cId}_${expr}`); } else { tempDedupSet.add(`ADG_${cId}_${aId}_${expr}`); } } } }); const spuArray = Array.from(spuSet).sort(); setExtractedSpus(spuArray); setActiveCampaigns(allActiveCampaigns); setDedupSet(tempDedupSet); setActiveAdGroupIds(tempActiveAdGroups); let autoGeneratedRules = spuArray.map((spu, index) => ({ id: Date.now() + index, keyword: spu, targetAcos: 25 })); autoGeneratedRules.push({ id: Date.now() + 10000, keyword: '', targetAcos: 25 }); setSpuRules(autoGeneratedRules); setFileData({ originalWorkbook: workbook, sheetName: targetSheetName, headers: originalHeaders, data: jsonData, stData: stData, fileName: file.name }); setIsProcessing(false); } catch (error) { console.error(error); alert("文件解析失败,请确认是否为合法的 Amazon Bulk 文件。"); setIsProcessing(false); } }, 50); }; reader.readAsArrayBuffer(file); }; const handleEngineAProcess = () => { if (!fileData || !fileData.data) return; setIsProcessing(true); setTimeout(() => { let modifiedCount = 0; let negativeAddedCount = 0; let tierCounts = { pausedKw: 0, pausedSku: 0, pausedCampaign: 0, pausedAdGroup: 0, tier1: 0, tier2: 0, tier3: 0, tier4: 0, tosBoost: 0 }; let skipDetails = { notTargeting: 0, notEnabled: 0, nullBid: 0, spuExcluded: 0, targetMetHold: 0, noConditionMet: 0, parseError: 0, alreadyNegated: 0, parentNotFound: 0 }; let unifiedLogs = []; let negativeKeywordsToCreate = []; const localDedupSet = new Set(dedupSet); const sortedSpuRules = [...spuRules].sort((a, b) => b.keyword.length - a.keyword.length); const headers = fileData.headers; const h_entity = headers.find(h => h === 'Entity' || h === 'Record Type' || h === '实体层级') || 'Entity'; const h_state = headers.find(h => h === 'State' || h === 'Status' || h === '状态') || 'State'; const h_bid = headers.find(h => h === 'Bid' || h === 'Max Bid' || h === '竞价') || 'Bid'; const h_op = headers.find(h => h === 'Operation' || h === '操作') || 'Operation'; const h_percentage = headers.find(h => h.includes('Percentage') || h.includes('百分比')) || 'Percentage'; // 1. 搜索词拉黑 if (fileData.stData) { const baseRow = fileData.data[0] || {}; const getK = (ch, en) => (ch in baseRow ? ch : en); fileData.stData.forEach(row => { const campId = getVal(row, ['Campaign ID', '广告活动编号', 'Campaign Id']); const adgId = getVal(row, ['Ad Group ID', '广告组编号', 'Ad Group Id']); const campName = getVal(row, ['Campaign Name (Informational only)', '广告活动名称(仅供参考)', 'Campaign Name']); let isMatched = false; for (const rule of sortedSpuRules) { const kw = rule.keyword.trim().toLowerCase(); if (kw === '' || campName.toLowerCase().includes(kw)) { isMatched = true; break; } } if (!isMatched) return; const searchTerm = getVal(row, ['Customer Search Term', '顾客搜索词']); const clicks = parseInt(String(row['点击量'] || row['Clicks'] || 0).replace(/,/g, ''), 10); const spend = parseFloat(String(row['花费'] || row['Spend'] || 0).replace(/,/g, '')); const orders = parseInt(String(row['订单数量'] || row['Orders'] || 0).replace(/,/g, ''), 10); if (!searchTerm || /^[Bb]0[A-Za-z0-9]{8}$/i.test(searchTerm)) return; if (orders === 0 && (clicks >= params.negClickThreshold || spend >= params.negSpendThreshold)) { if (!activeAdGroupIds.has(adgId)) { skipDetails.parentNotFound++; return; } const searchT = searchTerm.toLowerCase(); const campIdStr = String(campId).trim(); const adgIdStr = String(adgId).trim(); const adgKey = `ADG_${campIdStr}_${adgIdStr}_${searchT}_exact`; const campKey = `CAMP_${campIdStr}_${searchT}_exact`; if (localDedupSet.has(adgKey) || localDedupSet.has(campKey)) { skipDetails.alreadyNegated++; return; } localDedupSet.add(adgKey); negativeAddedCount++; unifiedLogs.push({ type: 'negative', campaign: campName, target: searchTerm, action: '精准否定', metrics: `花费: $${spend.toFixed(2)} | 点击: ${clicks}`, result: `+ 新增否定` }); let newNegRow = {}; newNegRow[getK('产品', 'Product')] = getK('商品推广', 'Sponsored Products'); newNegRow[h_entity] = getK('否定关键词', 'Negative Keyword'); newNegRow[h_op] = 'Create'; newNegRow[getK('广告活动编号', 'Campaign ID')] = campId; newNegRow[getK('广告组编号', 'Ad Group ID')] = adgId; newNegRow[getK('关键词文本', 'Keyword Text')] = searchTerm; newNegRow[getK('匹配类型', 'Match Type')] = getK('精准否定', 'Negative Exact'); newNegRow[h_state] = getK('已启用', 'Enabled'); newNegRow['Optimizer Note'] = `智能拉黑: ${clicks}点击, $${spend}花费, 0转化`; negativeKeywordsToCreate.push(newNegRow); } }); } // 2. 竞价与熔断处理 const processedData = []; const biddingAdjIndices = []; const campsToBoostTos = new Map(); fileData.data.forEach((originalRow, index) => { const row = { ...originalRow }; try { const entityStr = getVal(row, [h_entity]).toLowerCase(); const stateStr = getVal(row, [h_state]).toLowerCase(); if (entityStr === 'bidding adjustment' || entityStr === '竞价方案') { biddingAdjIndices.push(processedData.length); processedData.push(row); return; } const isNegative = entityStr.includes('negative') || entityStr.includes('否定'); const isTargeting = !isNegative && ['keyword', 'product targeting', 'targeting expression', '关键词', '商品投放', '投放表达式'].includes(entityStr); const isProductAd = ['product ad', '商品广告', 'ad', '广告', '商品推广广告'].includes(entityStr); const isCampaign = entityStr === 'campaign' || entityStr === '广告活动'; const isAdGroup = entityStr === 'ad group' || entityStr === '广告组'; if (!isTargeting && !isProductAd && !isCampaign && !isAdGroup) { skipDetails.notTargeting++; processedData.push(row); return; } if (!['enabled', '已启用'].includes(stateStr)) { skipDetails.notEnabled++; processedData.push(row); return; } const campName = getVal(row, ['Campaign Name (Informational only)', '广告活动名称(仅供参考)', 'Campaign Name', '广告活动名称']); const campIdStr = String(getVal(row, ['Campaign Id', '广告活动编号', 'Campaign ID'])).trim(); let appliedTargetAcos = null; let isMatched = false; for (const rule of sortedSpuRules) { const kw = rule.keyword.trim().toLowerCase(); if (kw === '' || campName.toLowerCase().includes(kw)) { appliedTargetAcos = parseFloat(rule.targetAcos); isMatched = true; break; } } if (!isMatched) { skipDetails.spuExcluded++; processedData.push(row); return; } const clicks = parseInt(String(row['点击量'] || row['Clicks'] || 0).replace(/,/g, ''), 10); const impressions = parseInt(String(row['展示量'] || row['Impressions'] || 0).replace(/,/g, ''), 10); const spend = parseFloat(String(row['花费'] || row['Spend'] || 0).replace(/,/g, '')); const sales = parseFloat(String(row['销量'] || row['Sales'] || 0).replace(/,/g, '')); const orders = parseInt(String(row['订单数量'] || row['Orders'] || 0).replace(/,/g, ''), 10); const acos = sales > 0 ? (spend / sales) * 100 : 0; const pausedStateValue = (h_state === '状态' || h_state === 'Status') ? '已暂停' : 'paused'; let isPaused = false; let action = ''; // 宏观防御网 if (isCampaign || isAdGroup) { if (orders === 0) { if (isCampaign && spend >= params.pauseSpendThresholdCampaign) { isPaused = true; action = `活动级熔断 (0单花费 $${spend} ≥ $${params.pauseSpendThresholdCampaign})`; tierCounts.pausedCampaign++; } else if (isAdGroup && spend >= params.pauseSpendThresholdAdGroup) { isPaused = true; action = `广告组熔断 (0单花费 $${spend} ≥ $${params.pauseSpendThresholdAdGroup})`; tierCounts.pausedAdGroup++; } if (!isPaused && params.enableTimeBasedPause) { const startDateObj = parseAmzDate(getVal(row, ['Start Date', '开始日期'])); if (startDateObj) { const diffDays = Math.ceil(Math.abs(new Date() - startDateObj) / (1000 * 60 * 60 * 24)); if (diffDays >= params.pauseTimeThresholdDays) { isPaused = true; action = `${isCampaign?'活动':'广告组'}存活超时熔断 (运行 ${diffDays}天 且 0单)`; if (isCampaign) tierCounts.pausedCampaign++; if (isAdGroup) tierCounts.pausedAdGroup++; } } } } if (isPaused) { modifiedCount++; const targetText = isCampaign ? '[整体广告活动]' : `[广告组] ${getVal(row, ['Ad Group Name', '广告组名称'])}`; unifiedLogs.push({ type: 'pause', campaign: campName, target: targetText, action: '宏观拦截暂停', metrics: `花费: $${spend.toFixed(2)} | 订单: ${orders}`, result: `状态 ➔ 已暂停`, reason: action }); row[h_state] = pausedStateValue; row[h_op] = 'Update'; row['Optimizer Note'] = `${action} (原状态: ${stateStr})`; } else { skipDetails.noConditionMet++; } processedData.push(row); return; } // 微观防御网 (SKU 层级) if (isProductAd) { if (orders === 0 && clicks >= params.pauseClickThresholdSku) { isPaused = true; action = `SKU 熔断 (0单超${params.pauseClickThresholdSku}次点击)`; tierCounts.pausedSku++; } else if (orders > 0 && acos >= params.pauseAcosThresholdSku) { isPaused = true; action = `SKU 熔断 (ACoS ≥ ${params.pauseAcosThresholdSku}%)`; tierCounts.pausedSku++; } if (isPaused) { modifiedCount++; const targetText = getVal(row, ['SKU', 'ASIN (Informational only)', 'ASIN(仅供参考)']) || '未知SKU'; unifiedLogs.push({ type: 'pause', campaign: campName, target: `[商品] ${targetText}`, action: '停用商品(SKU)', metrics: `花费: $${spend.toFixed(2)} | 点击: ${clicks} | ACoS: ${acos > 0 ? acos.toFixed(2)+'%' : '-'}`, result: `状态 ➔ 已暂停`, reason: action }); row[h_state] = pausedStateValue; row[h_op] = 'Update'; row['Optimizer Note'] = `${action} (原状态: ${stateStr})`; } else { skipDetails.noConditionMet++; } processedData.push(row); return; } // 微观竞价引擎 if (isTargeting) { const sweetSpotThreshold = Math.max(0, appliedTargetAcos - params.acosBuffer); if (orders === 0 && clicks >= params.pauseClickThresholdTarget) { isPaused = true; action = `投放熔断 (0单超${params.pauseClickThresholdTarget}次点击)`; tierCounts.pausedKw++; } else if (orders > 0 && acos >= params.pauseAcosThresholdTarget) { isPaused = true; action = `投放熔断 (ACoS ≥ ${params.pauseAcosThresholdTarget}%)`; tierCounts.pausedKw++; } if (isPaused) { modifiedCount++; const targetText = getVal(row, ['Keyword Text', '关键词文本', 'Product Targeting Expression', '商品投放表达式']) || '未知实体'; unifiedLogs.push({ type: 'pause', campaign: campName, target: targetText, action: '暂停投放', metrics: `花费: $${spend.toFixed(2)} | 点击: ${clicks} | ACoS: ${acos > 0 ? acos.toFixed(2)+'%' : '-'}`, result: `状态 ➔ 已暂停`, reason: action }); row[h_state] = pausedStateValue; row[h_op] = 'Update'; row['Optimizer Note'] = `${action} (原状态: ${stateStr})`; processedData.push(row); return; } const bidStr = String(row[h_bid] || '').replace(/,/g, '').trim(); if (!bidStr) { skipDetails.nullBid++; processedData.push(row); return; } const currentBid = parseFloat(bidStr); if (isNaN(currentBid)) { skipDetails.parseError++; processedData.push(row); return; } let newBid = currentBid; if (orders === 0 && clicks >= params.clickThreshold) { newBid = currentBid * (1 - (params.decreasePcnt / 100)); action = 'Tier 1 降价'; tierCounts.tier1++; } else if (orders > 0 && acos < sweetSpotThreshold) { newBid = currentBid * (1 + (params.increasePcnt / 100)); action = 'Tier 2 提价'; tierCounts.tier2++; campsToBoostTos.set(campIdStr, campName); } else if (orders > 0 && acos >= sweetSpotThreshold && acos <= appliedTargetAcos) { skipDetails.targetMetHold++; campsToBoostTos.set(campIdStr, campName); processedData.push(row); return; } else if (orders > 0 && acos > appliedTargetAcos) { newBid = currentBid * (appliedTargetAcos / acos); action = 'Tier 3 降价'; tierCounts.tier3++; } else if (impressions > 0 && impressions < params.impressionThreshold && clicks < params.clickThreshold) { newBid = currentBid * 1.05; action = 'Tier 4 提价'; tierCounts.tier4++; } else { skipDetails.noConditionMet++; processedData.push(row); return; } if (newBid > params.maxBid) newBid = params.maxBid; if (newBid < params.minBid) newBid = params.minBid; newBid = parseFloat(newBid.toFixed(2)); if (newBid !== currentBid) { modifiedCount++; const targetText = getVal(row, ['Keyword Text', '关键词文本', 'Product Targeting Expression', '商品投放表达式']) || '未知实体'; unifiedLogs.push({ type: 'bid', campaign: campName, target: targetText, action: '竞价调整', metrics: `目标ACoS: ${appliedTargetAcos}% | 实际: ${acos > 0 ? acos.toFixed(2)+'%' : '-'}`, result: `$${currentBid.toFixed(2)} ➔ $${newBid.toFixed(2)}`, reason: action }); row[h_bid] = newBid; row[h_op] = 'Update'; row['Optimizer Note'] = `${action} (Target: ${appliedTargetAcos}%, Old: $${currentBid})`; } else { skipDetails.noConditionMet++; } processedData.push(row); } } catch (err) { skipDetails.parseError++; processedData.push(row); } }); // 二次遍历: Bidding Adjustment 联动溢价 biddingAdjIndices.forEach(idx => { const row = processedData[idx]; const cId = String(getVal(row, ['Campaign Id', '广告活动编号', 'Campaign ID'])).trim(); const placement = getVal(row, ['Placement', '广告位']).toLowerCase(); if (campsToBoostTos.has(cId) && (placement.includes('top') || placement.includes('顶部'))) { let currentPcnt = parseInt(row[h_percentage] || 0, 10); if (isNaN(currentPcnt)) currentPcnt = 0; let newPcnt = currentPcnt + params.increaseTosPcnt; if (newPcnt > 900) newPcnt = 900; if (newPcnt !== currentPcnt) { const campName = campsToBoostTos.get(cId); unifiedLogs.push({ type: 'bid', campaign: campName, target: '[广告位] 顶部搜索结果 (TOS)', action: '溢价联动提升', metrics: `因活动下含放量/容忍词触发`, result: `${currentPcnt}% ➔ ${newPcnt}%`, reason: `+${params.increaseTosPcnt}%` }); row[h_percentage] = newPcnt; row[h_op] = 'Update'; row['Optimizer Note'] = `TOS 联动溢价: ${currentPcnt}% -> ${newPcnt}%`; modifiedCount++; tierCounts.tosBoost++; } } }); setSummary({ modifiedCount, negativeAddedCount, tierCounts, skipDetails, processedData, negativeKeywordsToCreate, unifiedLogs }); setIsProcessing(false); }, 500); }; const handleEngineAExport = () => { if (!summary || (!summary.processedData && summary.negativeKeywordsToCreate.length === 0)) return; if (!window.XLSX) { alert("组件未就绪,请稍等..."); return; } const XLSX = window.XLSX; const headers = fileData.headers || []; const h_op = headers.find(h => h === 'Operation' || h === '操作') || 'Operation'; const h_expr = headers.find(h => h === 'Product Targeting Expression' || h === '商品投放表达式') || 'Product Targeting Expression'; const h_resolved_expr = headers.find(h => h.includes('Resolved') || h.includes('已解析')); let baseExportData = summary.processedData; if (slimExport) { baseExportData = summary.processedData.filter(row => row[h_op] === 'Update'); if (baseExportData.length === 0 && summary.negativeKeywordsToCreate.length === 0) { alert("当前没有发生任何调价修改,无需导出。"); return; } } // 【核心修复 V6.6:数据离线净化管道】 let rawDataToExport = baseExportData.concat(summary.negativeKeywordsToCreate); const sanitizedDataToExport = rawDataToExport.map(row => { const cleanRow = { ...row }; // 1. 物理剔除诊断列,修复 "An invalid request was provided" 报错 delete cleanRow['Optimizer Note']; // 2. 绕过亚马逊官方 Auto-Targeting 校验 Bug,修复 "Unsupported targeting expression type" 报错 if (cleanRow[h_expr] && String(cleanRow[h_expr]).includes('keyword-group')) { cleanRow[h_expr] = ''; } if (h_resolved_expr && cleanRow[h_resolved_expr]) { cleanRow[h_resolved_expr] = ''; } return cleanRow; }); const newWs = XLSX.utils.json_to_sheet(sanitizedDataToExport, { header: headers }); const newWb = XLSX.utils.book_new(); const baseRow = sanitizedDataToExport[0] || {}; const isChinese = Object.keys(baseRow).some(k => k.includes('广告活动') || k.includes('商品推广')); const finalSheetName = isChinese ? '商品推广活动' : 'Sponsored Products Campaigns'; XLSX.utils.book_append_sheet(newWb, newWs, finalSheetName); const dateStr = new Date().toISOString().slice(0,10).replace(/-/g,""); XLSX.writeFile(newWb, `EngineA_Optimized_${slimExport ? 'Slim_' : ''}${dateStr}.xlsx`); }; const handleEngineBExport = () => { if (!fileData) return; if (!window.XLSX) { alert("组件未就绪"); return; } const { spu, exact, phrase, asin } = globalNegState; if (!spu) { alert("请先选择或输入目标 SPU!"); return; } const exList = Array.from(new Set(exact.split('\n').map(s => s.trim()).filter(Boolean))); const phList = Array.from(new Set(phrase.split('\n').map(s => s.trim()).filter(Boolean))); const asList = Array.from(new Set(asin.split('\n').map(s => s.trim()).filter(Boolean))); if (exList.length === 0 && phList.length === 0 && asList.length === 0) { alert("请至少输入一个待否定的特征!"); return; } const HEADERS = [ "Product", "Entity", "Operation", "Campaign Id", "Campaign Name", "Ad Group Id", "Ad Group Name", "Portfolio Id", "State", "Keyword Text", "Match Type", "Product Targeting Expression" ]; const buildRow = (cId, cName, entity, text, match, expr) => { let r = {}; HEADERS.forEach(h => r[h] = ""); r["Product"] = "Sponsored Products"; r["Entity"] = entity; r["Operation"] = "Create"; r["Campaign Id"] = cId; r["Campaign Name"] = cName; r["State"] = "enabled"; if(text !== undefined && text !== '') r["Keyword Text"] = text; if(match !== undefined && match !== '') r["Match Type"] = match; if(expr !== undefined && expr !== '') r["Product Targeting Expression"] = expr; return r; }; let rowsToExport = []; let blockCount = 0; let successCount = 0; const targetCampaigns = activeCampaigns.filter(c => c.cName.toUpperCase().includes(spu.toUpperCase())); if (targetCampaigns.length === 0) { alert("未在全表中检测到包含此 SPU 名称的广告活动,请检查输入或原始表格!"); return; } targetCampaigns.forEach(camp => { const cId = String(camp.cId).trim(); const cName = String(camp.cName).trim(); exList.forEach(text => { const textLower = text.toLowerCase(); const checkKey = `CAMP_${cId}_${textLower}_exact`; if (dedupSet.has(checkKey)) { blockCount++; } else { rowsToExport.push(buildRow(cId, cName, 'Campaign Negative Keyword', text, 'Negative Exact', '')); dedupSet.add(checkKey); successCount++; } }); phList.forEach(text => { const textLower = text.toLowerCase(); const checkKey = `CAMP_${cId}_${textLower}_phrase`; if (dedupSet.has(checkKey)) { blockCount++; } else { rowsToExport.push(buildRow(cId, cName, 'Campaign Negative Keyword', text, 'Negative Phrase', '')); dedupSet.add(checkKey); successCount++; } }); asList.forEach(rawAsin => { const asinVal = rawAsin.replace(/asin=|"|'/gi, '').toUpperCase(); const expr = `asin="${asinVal}"`; const checkKey = `CAMP_${cId}_${expr.toLowerCase()}`; if (dedupSet.has(checkKey)) { blockCount++; } else { rowsToExport.push(buildRow(cId, cName, 'Campaign Negative Product Targeting', '', '', expr)); dedupSet.add(checkKey); successCount++; } }); }); if (rowsToExport.length === 0) { alert(`所有指令已被防撞库雷达拦截!(共拦截 ${blockCount} 条已存在的重复数据)`); return; } alert(`成功生成 ${successCount} 条全局否定指令!\n(已跨全表精准下发至 ${targetCampaigns.length} 个广告活动,自动防重拦截 ${blockCount} 条)`); const XLSX = window.XLSX; const newWs = XLSX.utils.json_to_sheet(rowsToExport, { header: HEADERS }); const newWb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(newWb, newWs, 'Sponsored Products Campaigns'); const dateStr = new Date().toISOString().slice(0,10).replace(/-/g,""); XLSX.writeFile(newWb, `EngineB_GlobalNeg_${spu}_${dateStr}.xlsx`); }; return (

亚马逊全能双擎优化器 V6.6

【数据净化修复版】已恢复全能双引擎,并彻底拦截 Optimizer Note 列污染及 keyword-group 语法报错。

{fileData ? '✓' : '1'} 导入底层数据源 (Bulk File)

{!fileData ? (
!isProcessing && fileInputRef.current.click()} className={`border-2 border-dashed rounded-[18px] p-10 flex flex-col items-center justify-center transition-all ${isProcessing ? 'border-[#007aff] bg-[#f0f8ff] opacity-70' : 'border-[#d2d2d7] hover:border-[#007aff] hover:bg-[#f8f9fa] cursor-pointer'}`} > {isProcessing ? : }

{isProcessing ? progressMsg : "点击载入亚马逊 Bulk 文件 (.xlsx / .csv)"}

高阶建议:切换亚马逊后台至【English】再下载包含【Campaign Placements】的报表,可根绝一切多语言异常。

) : (

{fileData.fileName}

✓ 识别活跃广告活动: {activeCampaigns.length} 个 ✓ 提取 SPU 族群: {extractedSpus.length} 个 ✓ 载入防撞黑名单: {dedupSet.size} 条
)} e.target.value = null} className="hidden" accept=".xlsx, .csv" />
{fileData && (
{activeTab === 'optimizer' && (

执行与监控域

{!summary ? (

右侧参数已就绪。点击下方按钮启动多轨算法清洗。

) : (

防御矩阵拦截 (停用/拉黑)

活动熔断

{summary.tierCounts.pausedCampaign}

广告组熔断

{summary.tierCounts.pausedAdGroup}

投放停用

{summary.tierCounts.pausedKw}

SKU 停用

{summary.tierCounts.pausedSku}

搜词拉黑

{summary.negativeAddedCount}

阶梯竞价微调 (活跃实体)

降价止损

{summary.tierCounts.tier1}

放量提价

{summary.tierCounts.tier2}

逼近利润线

{summary.tierCounts.tier3}

激活长尾

{summary.tierCounts.tier4}

TOS 溢价联动

{summary.tierCounts.tosBoost}

执行明细追踪日志 Top 100
{summary.unifiedLogs.slice(0, 100).map((log, idx) => ( ))}
归属活动 操作对象 动作 指标 结果
{log.campaign} {log.target} {log.action} {log.metrics} {log.result}

底层探针状态:

无转化指标/非目标行跳过:{summary.skipDetails.notTargeting + summary.skipDetails.notEnabled + summary.skipDetails.spuExcluded + summary.skipDetails.nullBid + summary.skipDetails.targetMetHold + summary.skipDetails.noConditionMet}

防护引擎战报:

防重库拦截已存在烂词: {summary.skipDetails.alreadyNegated} | 过滤失联实体: {summary.skipDetails.parentNotFound}

)}

宏观层级熔断 (活动/组)

活动级 0单花费 ($)

广告组 0单花费 ($)

{params.enableTimeBasedPause && (

0单存活上限 (天)

)}

微观极端保护 (投放/SKU)

投放端 0单上限

投放端 ACoS ≥

SKU端 0单上限

SKU端 ACoS ≥

SPU 独立利润红线

{spuRules.map(rule => (
updateSpuRule(rule.id, 'keyword', e.target.value)} placeholder="SPU, 留空配全局" className="flex-1 text-xs outline-none bg-transparent font-mono" />
updateSpuRule(rule.id, 'targetAcos', e.target.value)} className="w-full text-xs font-bold text-center bg-transparent outline-none" /> %
))}

阶梯竞价微调

天花板 ($)

地板价 ($)

提价幅度 (%)

降价幅度 (%)

顶部广告位提价(%)

稳健容忍区 (%)

搜索词防腐拉黑

0单点击超出

0单花费超 ($)

)} {activeTab === 'globalNeg' && (

1. 靶向瞄准 (Targeting)

不再受组合与横杠限制!只要在下方输入或选择您的目标核心词,系统将自动扫描出名称中【包含】该词的所有存活广告活动,并强行注射否定指令。

setGlobalNegState({...globalNegState, spu: e.target.value.toUpperCase()})} placeholder="输入或选择目标 SPU (例如: D7A280)" className="w-full md:w-1/3 bg-white border border-gray-200 rounded-xl p-3 outline-none text-sm font-bold text-[#007aff] shadow-sm transition-all uppercase" /> {extractedSpus.map(spu =>

2. 录入绞杀名单 (Blacklist Payload)

每行一个烂词