feat: 新增多模块功能与服务实现

新增广告计划、用户资产、B2B交易、合规规则等核心模型
实现爬虫工作器、贸易服务、现金流预测等业务服务
添加RBAC权限测试、压力测试等测试用例
完善扩展程序的消息处理与内容脚本功能
重构应用入口与文档生成器
更新项目规则与业务闭环分析文档
This commit is contained in:
2026-03-18 09:38:09 +08:00
parent 72cd7f6f45
commit 037e412aad
158 changed files with 50217 additions and 1313 deletions

View File

@@ -0,0 +1,146 @@
import { Logger } from '../utils/Logger';
const logger = new Logger('ContentScript');
logger.info('Content script loaded', { url: window.location.href });
const platform = detectPlatform();
function detectPlatform(): string {
const hostname = window.location.hostname;
if (hostname.includes('tiktok')) return 'tiktok';
if (hostname.includes('temu')) return 'temu';
if (hostname.includes('shopee')) return 'shopee';
return 'unknown';
}
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
logger.info('Content script received message', { type: message.type, platform });
switch (message.type) {
case 'EXTRACT_PAGE_DATA':
const data = extractPageData(message.payload?.selectors);
sendResponse({ success: true, data });
break;
case 'GET_PAGE_ORDERS':
const orders = extractOrders();
sendResponse({ success: true, orders });
break;
case 'GET_PAGE_RETURNS':
const returns = extractReturns();
sendResponse({ success: true, returns });
break;
case 'CHECK_LOGIN_STATUS':
const isLoggedIn = checkLoginStatus();
sendResponse({ success: true, isLoggedIn });
break;
default:
sendResponse({ success: false, error: 'Unknown message type' });
}
return true;
});
function extractPageData(selectors?: Record<string, string>): Record<string, any> {
const data: Record<string, any> = {};
if (!selectors) {
return data;
}
for (const [key, selector] of Object.entries(selectors)) {
const element = document.querySelector(selector);
if (element) {
data[key] = element.textContent?.trim() || '';
}
}
return data;
}
function extractOrders(): any[] {
const orders: any[] = [];
const orderElements = document.querySelectorAll('[data-order-id]');
for (const el of orderElements) {
const orderId = el.getAttribute('data-order-id');
const statusEl = el.querySelector('[data-order-status]');
const amountEl = el.querySelector('[data-order-amount]');
if (orderId) {
orders.push({
orderId,
platform,
status: statusEl?.textContent?.trim() || 'UNKNOWN',
totalAmount: parseFloat(amountEl?.textContent?.replace(/[^0-9.]/g, '') || '0'),
currency: getCurrencyForPlatform(platform),
extractedAt: new Date().toISOString(),
});
}
}
logger.info('Orders extracted', { count: orders.length, platform });
return orders;
}
function extractReturns(): any[] {
const returns: any[] = [];
const returnElements = document.querySelectorAll('[data-return-id]');
for (const el of returnElements) {
const returnId = el.getAttribute('data-return-id');
const orderId = el.getAttribute('data-order-id');
const statusEl = el.querySelector('[data-return-status]');
if (returnId) {
returns.push({
returnId,
orderId,
platform,
status: statusEl?.textContent?.trim() || 'UNKNOWN',
extractedAt: new Date().toISOString(),
});
}
}
logger.info('Returns extracted', { count: returns.length, platform });
return returns;
}
function checkLoginStatus(): boolean {
const loginIndicators = {
tiktok: () => !!document.querySelector('[data-user-avatar]'),
temu: () => !!document.querySelector('[data-user-name]'),
shopee: () => !!document.querySelector('[data-shop-name]'),
};
const checker = loginIndicators[platform as keyof typeof loginIndicators];
if (checker) {
return checker();
}
return false;
}
function getCurrencyForPlatform(platform: string): string {
const currencies: Record<string, string> = {
tiktok: 'USD',
temu: 'USD',
shopee: 'MYR',
};
return currencies[platform] || 'USD';
}
export { extractPageData, extractOrders, extractReturns, checkLoginStatus };