248 lines
11 KiB
JavaScript
248 lines
11 KiB
JavaScript
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import process from 'node:process';
|
|
import dotenv from 'dotenv';
|
|
|
|
const rootDir = path.resolve(process.cwd());
|
|
dotenv.config({ path: path.join(rootDir, '.env') });
|
|
|
|
const toBool = (value, fallback) => {
|
|
if (value == null) return fallback;
|
|
return ['1', 'true', 'yes', 'y', 'on'].includes(String(value).trim().toLowerCase());
|
|
};
|
|
|
|
const ensureDir = (dirPath) => {
|
|
fs.mkdirSync(dirPath, { recursive: true });
|
|
return dirPath;
|
|
};
|
|
|
|
export const config = {
|
|
rootDir,
|
|
baseUrl: process.env.ALIYUN_APS_BASE_URL || 'https://aps.aliyun.com',
|
|
headless: toBool(process.env.ALIYUN_APS_HEADLESS, false),
|
|
browserMode: (process.env.ALIYUN_APS_BROWSER_MODE || 'launch').trim().toLowerCase(),
|
|
browserChannel: (process.env.ALIYUN_APS_BROWSER_CHANNEL || '').trim(),
|
|
browserExecutablePath: (process.env.ALIYUN_APS_BROWSER_EXECUTABLE_PATH || '').trim(),
|
|
cdpUrl: (process.env.ALIYUN_APS_CDP_URL || 'http://127.0.0.1:9222').trim(),
|
|
timezone: process.env.ALIYUN_APS_TIMEZONE || 'Asia/Shanghai',
|
|
cron: process.env.ALIYUN_APS_CRON || '0 6 * * *',
|
|
orderStartDate: process.env.ALIYUN_APS_ORDER_START_DATE || '2024-01-01',
|
|
incrementalOrderStartDate: process.env.ALIYUN_APS_INCREMENTAL_ORDER_START_DATE || '',
|
|
billStartMonth: process.env.ALIYUN_APS_BILL_START_MONTH || '2024-01',
|
|
orderIncrementalOverlapDays: Math.max(0, Number.parseInt(process.env.ALIYUN_APS_ORDER_INCREMENTAL_OVERLAP_DAYS || '2', 10) || 2),
|
|
billIncrementalOverlapDays: Math.max(0, Number.parseInt(process.env.ALIYUN_APS_BILL_INCREMENTAL_OVERLAP_DAYS || '7', 10) || 7),
|
|
messageIncrementalOverlapDays: Math.max(0, Number.parseInt(process.env.ALIYUN_APS_MESSAGE_INCREMENTAL_OVERLAP_DAYS || '7', 10) || 7),
|
|
scheduleMode: process.env.ALIYUN_APS_SCHEDULE_MODE || 'incremental',
|
|
smtp: {
|
|
host: process.env.ALIYUN_APS_SMTP_HOST || 'smtp.qq.com',
|
|
port: parseInt(process.env.ALIYUN_APS_SMTP_PORT || '465', 10),
|
|
secure: toBool(process.env.ALIYUN_APS_SMTP_SECURE, true),
|
|
user: process.env.ALIYUN_APS_SMTP_USER || '',
|
|
pass: process.env.ALIYUN_APS_SMTP_PASS || '',
|
|
},
|
|
notifyEmail: process.env.ALIYUN_APS_NOTIFY_EMAIL || '',
|
|
closeBrowser: toBool(process.env.ALIYUN_APS_CLOSE_BROWSER, true),
|
|
fullSync: toBool(process.env.ALIYUN_APS_FULL_SYNC, true),
|
|
resumeBillMonth: process.env.ALIYUN_APS_RESUME_BILL_MONTH || '',
|
|
resumeBillPage: Math.max(1, Number.parseInt(process.env.ALIYUN_APS_RESUME_BILL_PAGE || '1', 10) || 1),
|
|
userDataDir: ensureDir(path.join(rootDir, '.browser')),
|
|
storageStateFile: path.join(rootDir, '.browser', 'storage-state.json'),
|
|
dataDir: ensureDir(path.join(rootDir, 'data')),
|
|
downloadDir: ensureDir(path.join(rootDir, 'downloads')),
|
|
errorDir: ensureDir(path.join(rootDir, 'data', 'errors')),
|
|
db: {
|
|
host: process.env.ALIYUN_APS_DB_HOST || '',
|
|
port: parseInt(process.env.ALIYUN_APS_DB_PORT || '3306', 10),
|
|
user: process.env.ALIYUN_APS_DB_USER || '',
|
|
password: process.env.ALIYUN_APS_DB_PASSWORD || '',
|
|
database: process.env.ALIYUN_APS_DB_NAME || '',
|
|
charset: process.env.ALIYUN_APS_DB_CHARSET || 'utf8mb4',
|
|
connectionLimit: Math.max(1, Number.parseInt(process.env.ALIYUN_APS_DB_CONNECTION_LIMIT || '5', 10) || 5),
|
|
connectTimeout: Math.max(1000, Number.parseInt(process.env.ALIYUN_APS_DB_CONNECT_TIMEOUT || '20000', 10) || 20000),
|
|
},
|
|
};
|
|
|
|
export const datasets = {
|
|
customers: {
|
|
name: 'customers',
|
|
url: `${config.baseUrl}/#/detail/my_customer/~/customer/list`,
|
|
heading: '我的客户',
|
|
pageSize: 20,
|
|
uniqueKey: (record) => record.accountId || record.loginName || record.__hash,
|
|
normalize: (record) => {
|
|
const loginAndUid = record['登录名称/账号ID'] || '';
|
|
const [loginName = '', accountId = ''] = splitLines(loginAndUid);
|
|
return {
|
|
loginName: loginName.replace(/\s+/g, ''),
|
|
accountId,
|
|
listPageNum: context.pageNum || '',
|
|
realName: record['UID实名认证名称'] || '',
|
|
reportSource: record['报备来源'] || '',
|
|
reportType: record['报备类型'] || '',
|
|
tradeMode: record['交易模式'] || '',
|
|
authStatus: record['实名认证状态'] || '',
|
|
relationTime: record['关联日期'] || '',
|
|
owner: record['跟进员工'] || '',
|
|
cashBalanceCny: record['账户现金余额(CNY)'] || '',
|
|
invoicePendingCny: record['待开票金额(CNY)'] || '',
|
|
lastMonthConsumptionCny: record['上月消费金额(CNY)'] || '',
|
|
thisMonthConsumptionCny: record['本月消费金额(CNY)'] || '',
|
|
paymentNoticeStatus: record['代为支付告知状态'] || '',
|
|
inviteType: record['邀约注册类型'] || '',
|
|
isNewCustomer: record['是否新客户'] || '',
|
|
isPerformanceQualified: record['是否达成业绩起算点'] || '',
|
|
customerCategory: record['客户分类'] || '',
|
|
remark: record['备注'] || '',
|
|
inactiveMonths: record['客户无消费月数'] || '',
|
|
releasePlanTime: record['计划释放时间'] || '',
|
|
releasePlanReason: record['计划释放原因'] || '',
|
|
};
|
|
},
|
|
},
|
|
orders: {
|
|
name: 'orders',
|
|
url: `${config.baseUrl}/#/detail/order/~/costCenter/order`,
|
|
heading: '订单查询',
|
|
pageSize: 20,
|
|
uniqueKey: (record) => record.orderId || record.__hash,
|
|
normalize: (record, context) => ({
|
|
orderId: record['订单号'] || '',
|
|
customerAccount: (record['客户账号'] || '').replace(/\s+/g, ''),
|
|
customerCategory: record['客户分类'] || '',
|
|
orderType: record['订单类型'] || '',
|
|
orderOriginalPriceCny: record['订单原价 (CNY)'] || '',
|
|
actualPaidCny: record['实付金额 (CNY)'] || '',
|
|
orderStatus: record['订单状态'] || '',
|
|
createdAt: record['下单时间'] || '',
|
|
windowStart: context.windowStart || '',
|
|
windowEnd: context.windowEnd || '',
|
|
}),
|
|
},
|
|
orderDetails: {
|
|
name: 'orderDetails',
|
|
url: `${config.baseUrl}/#/detail/order/~/costCenter/order`,
|
|
heading: '订单详情',
|
|
pageSize: 100,
|
|
uniqueKey: (record) => record.orderId || record.__hash,
|
|
normalize: (record, context) => ({
|
|
orderId: record.orderId || '',
|
|
orderType: record.orderType || '',
|
|
status: record.status || '',
|
|
tradeType: record.tradeType || '',
|
|
customerCategory: record.customerCategory || '',
|
|
dealerName: record.dealerName || '',
|
|
dealerUid: record.dealerUid || '',
|
|
customerType: record.customerType || '',
|
|
opportunityId: record.opportunityId || '',
|
|
paymentTime: record.paymentTime || '',
|
|
orderTime: record.orderTime || '',
|
|
productName: record.productName || '',
|
|
productCode: record.productCode || '',
|
|
originalPriceCny: record.originalPriceCny || '',
|
|
paidAmountCny: record.paidAmountCny || '',
|
|
discount: record.discount || '',
|
|
payableAmountCny: record.payableAmountCny || '',
|
|
couponAmountCny: record.couponAmountCny || '',
|
|
windowStart: context.windowStart || '',
|
|
windowEnd: context.windowEnd || '',
|
|
}),
|
|
},
|
|
customerDetails: {
|
|
name: 'customerDetails',
|
|
url: `${config.baseUrl}/#/detail/my_customer/~/customer/list`,
|
|
heading: '详情',
|
|
pageSize: 100,
|
|
uniqueKey: (record) => record.accountId || record.__hash,
|
|
normalize: (record, context) => ({
|
|
accountId: context.accountId || '',
|
|
customerAccount: record.customerAccount || '',
|
|
customerName: record.customerName || '',
|
|
customerType: record.customerType || '',
|
|
tradeMode: record.tradeMode || '',
|
|
customerSource: record.customerSource || '',
|
|
realNameStatus: record.realNameStatus || '',
|
|
email: record.email || '',
|
|
relationDate: record.relationDate || '',
|
|
phone: record.phone || '',
|
|
remark: record.remark || '',
|
|
paymentNoticeStatus: record.paymentNoticeStatus || '',
|
|
department: record.department || '',
|
|
lastMonthPayableTotalCny: record.lastMonthPayableTotalCny || '',
|
|
lastMonthPrepayCny: record.lastMonthPrepayCny || '',
|
|
lastMonthPostpayCny: record.lastMonthPostpayCny || '',
|
|
currentMonthPayableTotalCny: record.currentMonthPayableTotalCny || '',
|
|
currentMonthPrepayCny: record.currentMonthPrepayCny || '',
|
|
currentMonthPostpayCny: record.currentMonthPostpayCny || '',
|
|
}),
|
|
},
|
|
bills: {
|
|
name: 'bills',
|
|
url: `${config.baseUrl}/#/detail/bill/~/costCenter/bill`,
|
|
heading: '账单查询',
|
|
pageSize: 20,
|
|
uniqueKey: (record) => record.__hash,
|
|
normalize: (record, context) => ({
|
|
billingMonth: record['账期'] || '',
|
|
consumeDate: record['消费时间'] || '',
|
|
customerAccount: (record['客户账号'] || '').replace(/\s+/g, ''),
|
|
customerCategory: record['客户分类'] || '',
|
|
productCategory: record['产品分类'] || '',
|
|
productName: record['产品名称'] || '',
|
|
originalPriceCny: record['原价 (CNY)'] || '',
|
|
customerPayableCny: record['客户应付金额 (CNY)'] || '',
|
|
billType: record['账单类型'] || '',
|
|
countsForPerformance: record['是否计入业绩'] || '',
|
|
commissionable: record['是否返佣'] || '',
|
|
commissionMonth: record['佣金月份'] || context.month || '',
|
|
inviteType: record['邀约注册类型'] || '',
|
|
serviceStartAt: record['服务开始时间'] || '',
|
|
serviceEndAt: record['服务结束时间'] || '',
|
|
}),
|
|
},
|
|
messages: {
|
|
name: 'messages',
|
|
url: `${config.baseUrl}/#/message`,
|
|
heading: '消息',
|
|
pageSize: 20,
|
|
uniqueKey: (record) => record.msgId || record.__hash,
|
|
normalize: (record) => ({
|
|
msgId: pickFirst(record, ['消息ID', 'msg_id', '消息id', 'ID', 'id']),
|
|
title: pickFirst(record, ['消息标题', '标题', 'title']),
|
|
content: pickFirst(record, ['消息内容', '内容', 'content']),
|
|
msgType: pickFirst(record, ['消息类型', 'type', 'msg_type']),
|
|
fromApp: pickFirst(record, ['来源应用', 'from_app', '应用']),
|
|
bizCode: pickFirst(record, ['业务编码', 'biz_code']),
|
|
msgChannel: pickFirst(record, ['消息通道', 'msg_channel']),
|
|
categoryId: pickFirst(record, ['分类ID', 'category_id']),
|
|
categoryName: pickFirst(record, ['分类名称', 'category_name']),
|
|
lv1CategoryId: pickFirst(record, ['一级分类ID', 'lv1_category_id']),
|
|
lv2CategoryId: pickFirst(record, ['二级分类ID', 'lv2_category_id']),
|
|
lv3CategoryId: pickFirst(record, ['三级分类ID', 'lv3_category_id']),
|
|
messageClassification: pickFirst(record, ['归类结果', 'message_classification']),
|
|
customerName: pickFirst(record, ['客户名称', 'customer_name']),
|
|
orderNo: pickFirst(record, ['订单号', 'order_no']),
|
|
status: pickFirst(record, ['消息状态', '状态', 'status']),
|
|
gmtCreated: pickFirst(record, ['消息创建时间', '创建时间', 'gmt_created']),
|
|
gmtModified: pickFirst(record, ['消息修改时间', '修改时间', 'gmt_modified']),
|
|
extraData: record,
|
|
}),
|
|
},
|
|
};
|
|
|
|
function splitLines(value) {
|
|
return String(value)
|
|
.split('\n')
|
|
.map((part) => part.trim())
|
|
.filter(Boolean);
|
|
}
|
|
|
|
function pickFirst(record, keys) {
|
|
for (const key of keys) {
|
|
const value = record[key];
|
|
if (value != null && String(value).trim()) {
|
|
return String(value).trim();
|
|
}
|
|
}
|
|
return '';
|
|
}
|