forked from lunanting/cangku
569 lines
34 KiB
JavaScript
569 lines
34 KiB
JavaScript
const planningDatabase = require('./planningDatabase');
|
||
|
||
const schemaState = new Map();
|
||
|
||
function escapeIdentifier(value) {
|
||
return `\`${String(value).replace(/`/g, '``')}\``;
|
||
}
|
||
|
||
async function withSchemaState(key, runner) {
|
||
const state = schemaState.get(key) || { ready: false, pending: null };
|
||
if (state.ready) {
|
||
return;
|
||
}
|
||
|
||
if (state.pending) {
|
||
await state.pending;
|
||
return;
|
||
}
|
||
|
||
state.pending = (async () => {
|
||
await runner();
|
||
state.ready = true;
|
||
})();
|
||
schemaState.set(key, state);
|
||
|
||
try {
|
||
await state.pending;
|
||
} finally {
|
||
state.pending = null;
|
||
}
|
||
}
|
||
|
||
async function ensureTable(_tableName, createSql) {
|
||
await planningDatabase.execute(createSql);
|
||
}
|
||
|
||
async function hasColumn(tableName, columnName) {
|
||
const rows = await planningDatabase.query(
|
||
`SELECT 1 AS ok
|
||
FROM information_schema.columns
|
||
WHERE table_schema = DATABASE()
|
||
AND table_name = ?
|
||
AND column_name = ?
|
||
LIMIT 1`,
|
||
[tableName, columnName]
|
||
);
|
||
return rows.length > 0;
|
||
}
|
||
|
||
async function ensureColumn(tableName, columnName, definition) {
|
||
if (await hasColumn(tableName, columnName)) {
|
||
return;
|
||
}
|
||
await planningDatabase.execute(`ALTER TABLE ${escapeIdentifier(tableName)} ADD COLUMN ${escapeIdentifier(columnName)} ${definition}`);
|
||
}
|
||
|
||
async function hasIndex(tableName, indexName) {
|
||
const rows = await planningDatabase.query(
|
||
`SELECT 1 AS ok
|
||
FROM information_schema.statistics
|
||
WHERE table_schema = DATABASE()
|
||
AND table_name = ?
|
||
AND index_name = ?
|
||
LIMIT 1`,
|
||
[tableName, indexName]
|
||
);
|
||
return rows.length > 0;
|
||
}
|
||
|
||
async function ensureIndex(tableName, indexName, definition) {
|
||
if (await hasIndex(tableName, indexName)) {
|
||
return;
|
||
}
|
||
await planningDatabase.execute(`ALTER TABLE ${escapeIdentifier(tableName)} ADD INDEX ${indexName} ${definition}`);
|
||
}
|
||
|
||
async function ensurePlanningUploadBatchSchema() {
|
||
await withSchemaState('planning-upload-batches', async () => {
|
||
await ensureTable(
|
||
'planning_upload_batches',
|
||
`CREATE TABLE IF NOT EXISTS planning_upload_batches (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 'Planning upload batch ID',
|
||
batch_id VARCHAR(36) NOT NULL COMMENT 'Upload batch UUID',
|
||
source_file_name VARCHAR(255) NOT NULL COMMENT 'Uploaded file name',
|
||
target_table_name VARCHAR(128) NOT NULL COMMENT 'Target planning table name',
|
||
row_count INT NOT NULL DEFAULT 0 COMMENT 'Detected row count',
|
||
success_count INT NOT NULL DEFAULT 0 COMMENT 'Inserted row count',
|
||
source_sheet_summary JSON NULL COMMENT 'Recognized sheet summary',
|
||
uploaded_by_user_id BIGINT NULL COMMENT 'Uploader user ID',
|
||
uploaded_by_username VARCHAR(100) NULL COMMENT 'Uploader username',
|
||
uploaded_by_name VARCHAR(100) NULL COMMENT 'Uploader display name',
|
||
uploaded_department_id BIGINT NULL COMMENT 'Uploader department ID',
|
||
uploaded_department_name VARCHAR(100) NULL COMMENT 'Uploader department name',
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 'Created at',
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Updated at',
|
||
UNIQUE KEY uk_batch_id (batch_id),
|
||
INDEX idx_created_at (created_at)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Planning upload batch logs'`
|
||
);
|
||
});
|
||
}
|
||
|
||
async function ensurePlanningAiImageSchema() {
|
||
await withSchemaState('planning-ai-image', async () => {
|
||
await ensureTable(
|
||
'ai_image_feature_library',
|
||
`CREATE TABLE IF NOT EXISTS ai_image_feature_library (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
|
||
biz_type VARCHAR(30) NOT NULL COMMENT '业务类型: internal/upload/market',
|
||
source_system VARCHAR(50) NULL COMMENT '来源系统',
|
||
source_table VARCHAR(100) NULL COMMENT '来源表名',
|
||
source_id VARCHAR(100) NULL COMMENT '来源记录ID',
|
||
sku_id VARCHAR(100) NULL COMMENT 'SKU编码',
|
||
goods_id VARCHAR(100) NULL COMMENT '商品ID',
|
||
product_name VARCHAR(500) NULL COMMENT '商品名称',
|
||
category_name VARCHAR(200) NULL COMMENT '原始类目名称',
|
||
appearance_similarity_code VARCHAR(160) NULL COMMENT '外观相似编码',
|
||
image_url VARCHAR(1000) NOT NULL COMMENT '图片地址',
|
||
image_hash VARCHAR(64) NULL COMMENT '图片哈希',
|
||
image_status VARCHAR(20) NOT NULL DEFAULT 'pending' COMMENT '处理状态: pending/processing/success/failed',
|
||
raw_tags_json LONGTEXT NULL COMMENT '模型原始标签JSON',
|
||
normalized_tags_json LONGTEXT NULL COMMENT '标准化标签JSON',
|
||
category_tag VARCHAR(100) NULL COMMENT '类目标签',
|
||
space_tag VARCHAR(50) NULL COMMENT '空间标签',
|
||
scene_tag VARCHAR(50) NULL COMMENT '场景标签',
|
||
style_tag VARCHAR(100) NULL COMMENT '风格标签',
|
||
color_tag VARCHAR(100) NULL COMMENT '颜色标签',
|
||
material_tag VARCHAR(100) NULL COMMENT '材质标签',
|
||
vision_provider VARCHAR(50) NULL COMMENT '标签识别服务商',
|
||
vision_model VARCHAR(100) NULL COMMENT '标签识别模型',
|
||
vision_prompt_version VARCHAR(50) NULL COMMENT '标签提示词版本',
|
||
vision_prompt_tokens INT NULL COMMENT '标签识别输入Token数',
|
||
vision_completion_tokens INT NULL COMMENT '标签识别输出Token数',
|
||
vision_total_tokens INT NULL COMMENT '标签识别总Token数',
|
||
embedding_provider VARCHAR(50) NULL COMMENT '向量服务商',
|
||
embedding_model VARCHAR(100) NULL COMMENT '向量模型',
|
||
embedding_vector_json LONGTEXT NULL COMMENT '图片向量JSON',
|
||
embedding_dimension INT NULL COMMENT '向量维度',
|
||
embedding_prompt_tokens INT NULL COMMENT '向量输入Token数',
|
||
embedding_total_tokens INT NULL COMMENT '向量总Token数',
|
||
processed_at DATETIME NULL COMMENT '处理完成时间',
|
||
error_message VARCHAR(2000) NULL COMMENT '错误信息',
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||
UNIQUE KEY uk_ai_image_feature_source (biz_type, source_system, source_table, source_id),
|
||
UNIQUE KEY uk_ai_image_feature_image_hash (image_hash),
|
||
KEY idx_ai_image_feature_status (image_status, processed_at),
|
||
KEY idx_ai_image_feature_sku (sku_id),
|
||
KEY idx_ai_image_feature_goods (goods_id),
|
||
KEY idx_ai_image_feature_tag (category_tag, space_tag, scene_tag, style_tag)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI图片标签与向量特征库'`
|
||
);
|
||
await ensureColumn('ai_image_feature_library', 'appearance_similarity_code', "VARCHAR(160) NULL COMMENT '外观相似编码'");
|
||
await ensureIndex('ai_image_feature_library', 'idx_ai_image_feature_biz_vector', '(biz_type, embedding_dimension, id)');
|
||
await ensureIndex('ai_image_feature_library', 'idx_ai_image_feature_biz_similarity_code', '(biz_type, appearance_similarity_code, material_tag)');
|
||
|
||
await ensureTable(
|
||
'ai_image_search_logs',
|
||
`CREATE TABLE IF NOT EXISTS ai_image_search_logs (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
|
||
biz_no VARCHAR(64) NOT NULL COMMENT '检索业务单号',
|
||
source_type VARCHAR(20) NOT NULL COMMENT '来源类型:url/upload',
|
||
source_input VARCHAR(1000) NULL COMMENT '来源输入内容',
|
||
query_image_url VARCHAR(1000) NULL COMMENT '检索图片地址',
|
||
query_image_hash VARCHAR(64) NULL COMMENT '检索图片哈希',
|
||
selected_category_tag VARCHAR(100) NOT NULL COMMENT '用户选择类目',
|
||
raw_tags_json LONGTEXT NULL COMMENT '模型原始标签JSON',
|
||
normalized_tags_json LONGTEXT NULL COMMENT '标准化标签JSON',
|
||
embedding_dimension INT NULL COMMENT '查询图片向量维度',
|
||
candidate_count INT NOT NULL DEFAULT 0 COMMENT '候选集数量',
|
||
result_count INT NOT NULL DEFAULT 0 COMMENT '命中结果数量',
|
||
similarity_threshold DECIMAL(6,4) NOT NULL DEFAULT 0.5000 COMMENT '相似度阈值',
|
||
result_snapshot_json LONGTEXT NULL COMMENT '结果快照JSON',
|
||
status VARCHAR(20) NOT NULL DEFAULT 'processing' COMMENT '状态:processing/success/failed',
|
||
response_ms INT NULL COMMENT '接口耗时毫秒',
|
||
error_message VARCHAR(2000) NULL COMMENT '错误信息',
|
||
created_by_user_id BIGINT NULL COMMENT '操作人ID',
|
||
created_by_username VARCHAR(100) NULL COMMENT '操作人账号',
|
||
created_by_name VARCHAR(100) NULL COMMENT '操作人姓名',
|
||
created_department_id BIGINT NULL COMMENT '操作人部门ID',
|
||
created_department_name VARCHAR(100) NULL COMMENT '操作人部门名称',
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||
UNIQUE KEY uk_ai_image_search_logs_biz_no (biz_no),
|
||
KEY idx_ai_image_search_logs_user (created_by_user_id, created_at),
|
||
KEY idx_ai_image_search_logs_status (status, created_at),
|
||
KEY idx_ai_image_search_logs_category (selected_category_tag, created_at)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI图片相似检索操作日志'`
|
||
);
|
||
});
|
||
}
|
||
|
||
async function ensurePlanningAppearanceMatchSchema() {
|
||
await withSchemaState('planning-appearance-match', async () => {
|
||
await ensureTable(
|
||
'planning_appearance_similarity_matches',
|
||
`CREATE TABLE IF NOT EXISTS planning_appearance_similarity_matches (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
|
||
snapshot_date VARCHAR(32) NOT NULL COMMENT '企划统计月份',
|
||
market_goods_id VARCHAR(100) NOT NULL COMMENT '市场商品ID',
|
||
market_goods_title VARCHAR(500) NULL COMMENT '市场商品标题',
|
||
market_goods_image_url VARCHAR(1000) NULL COMMENT '市场商品图片',
|
||
market_material VARCHAR(500) NULL COMMENT '市场核心主材质/原始材质',
|
||
matched_sku_id VARCHAR(100) NULL COMMENT '最相似我方SKU编码',
|
||
matched_goods_id VARCHAR(100) NULL COMMENT '最相似我方在销ID',
|
||
matched_spu VARCHAR(100) NULL COMMENT '最相似我方SPU',
|
||
matched_product_name VARCHAR(500) NULL COMMENT '最相似我方商品名称',
|
||
matched_image_url VARCHAR(1000) NULL COMMENT '最相似我方商品图片',
|
||
similarity_score DECIMAL(8,6) NULL COMMENT '外观相似度0-1',
|
||
similarity_percent DECIMAL(8,2) NULL COMMENT '外观相似度百分比',
|
||
appearance_group_key VARCHAR(160) NOT NULL COMMENT '外观相似款组键',
|
||
appearance_group_name VARCHAR(500) NOT NULL COMMENT '外观相似款组名称',
|
||
match_status VARCHAR(30) NOT NULL DEFAULT 'matched' COMMENT '匹配状态: matched/unmatched/manual',
|
||
source_table VARCHAR(100) NULL COMMENT '市场特征来源表',
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||
UNIQUE KEY uk_planning_appearance_market (snapshot_date, market_goods_id),
|
||
KEY idx_planning_appearance_group (snapshot_date, appearance_group_key, market_material),
|
||
KEY idx_planning_appearance_sku (matched_sku_id),
|
||
KEY idx_planning_appearance_goods (matched_goods_id),
|
||
KEY idx_planning_appearance_status (match_status, similarity_score)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='企划外观相似款匹配缓存'`
|
||
);
|
||
|
||
await planningDatabase.execute(
|
||
`ALTER TABLE planning_appearance_similarity_matches
|
||
MODIFY COLUMN market_material VARCHAR(500) NULL COMMENT '市场核心主材质/原始材质'`
|
||
);
|
||
});
|
||
}
|
||
|
||
async function ensurePlanningStockSelectionSchema() {
|
||
await withSchemaState('planning-stock-selection', async () => {
|
||
await ensureTable(
|
||
'op_BarcodeChannelDecisionBase',
|
||
`CREATE TABLE IF NOT EXISTS op_BarcodeChannelDecisionBase (
|
||
statDate DATE NOT NULL COMMENT '统计日期',
|
||
channelName VARCHAR(50) NOT NULL COMMENT '渠道名称',
|
||
barcode VARCHAR(255) NOT NULL COMMENT '条码(货号)',
|
||
isListedInChannel TINYINT(1) NULL COMMENT '本渠道是否上架过',
|
||
isListedInTmall TINYINT(1) NULL COMMENT '是否在天猫上架过',
|
||
isListedInJingxi TINYINT(1) NULL COMMENT '是否在京喜上架过',
|
||
isListedInAlibaba TINYINT(1) NULL COMMENT '是否在阿里巴巴上架过',
|
||
firstListedDate DATE NULL COMMENT '全渠道首次铺货日期',
|
||
listedDays INT NULL COMMENT '距首次铺货天数',
|
||
listingShopCount INT NULL COMMENT '全渠道铺货店铺数',
|
||
dailySales30d DECIMAL(18,4) NULL COMMENT '最近30天日销件数',
|
||
dailySales90d DECIMAL(18,4) NULL COMMENT '最近90天日销件数',
|
||
momGrowth30d DECIMAL(18,4) NULL COMMENT '最近30天环比增长',
|
||
realAfterSaleRate90d DECIMAL(18,6) NULL COMMENT '最近90天真实售后率',
|
||
channelAfterSaleRedline DECIMAL(18,6) NULL COMMENT '渠道售后红线',
|
||
createdAt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||
updatedAt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||
PRIMARY KEY (statDate, channelName, barcode),
|
||
KEY idx_op_barcode_channel_decision_base_statDate (statDate),
|
||
KEY idx_op_barcode_channel_decision_base_channelName (channelName),
|
||
KEY idx_op_barcode_channel_decision_base_barcode (barcode)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='条码渠道判定底表(企划库)'`
|
||
);
|
||
await ensureColumn('op_BarcodeChannelDecisionBase', 'isListedInTmall', "TINYINT(1) NULL COMMENT '是否在天猫上架过'");
|
||
await ensureColumn('op_BarcodeChannelDecisionBase', 'isListedInJingxi', "TINYINT(1) NULL COMMENT '是否在京喜上架过'");
|
||
await ensureColumn('op_BarcodeChannelDecisionBase', 'isListedInAlibaba', "TINYINT(1) NULL COMMENT '是否在阿里巴巴上架过'");
|
||
|
||
await ensureTable(
|
||
'op_BarcodeChannelDecisionResult',
|
||
`CREATE TABLE IF NOT EXISTS op_BarcodeChannelDecisionResult (
|
||
statDate DATE NOT NULL COMMENT '统计日期',
|
||
channelName VARCHAR(50) NOT NULL COMMENT '渠道名称',
|
||
barcode VARCHAR(255) NOT NULL COMMENT '条码(货号)',
|
||
ruleCode VARCHAR(10) NULL COMMENT '规则编号',
|
||
poolType VARCHAR(30) NULL COMMENT '结果池类型',
|
||
ruleTag VARCHAR(200) NULL COMMENT '规则标记文案',
|
||
ruleExplain VARCHAR(1000) NULL COMMENT '规则说明',
|
||
createdAt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||
updatedAt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||
PRIMARY KEY (statDate, channelName, barcode),
|
||
KEY idx_op_barcode_channel_decision_result_statDate (statDate),
|
||
KEY idx_op_barcode_channel_decision_result_poolType (poolType),
|
||
KEY idx_op_barcode_channel_decision_result_ruleCode (ruleCode),
|
||
KEY idx_op_barcode_channel_decision_result_channelName (channelName),
|
||
KEY idx_op_barcode_channel_decision_result_barcode (barcode)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='条码渠道判定结果表(企划库)'`
|
||
);
|
||
|
||
await ensureTable(
|
||
'op_barcode_channel_decision_sync_log',
|
||
`CREATE TABLE IF NOT EXISTS op_barcode_channel_decision_sync_log (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
|
||
sync_type VARCHAR(30) NOT NULL COMMENT '同步类型: full/incremental',
|
||
source_latest_stat_date DATE NULL COMMENT '源表最新业务日期',
|
||
base_row_count INT NOT NULL DEFAULT 0 COMMENT '底表同步行数',
|
||
result_row_count INT NOT NULL DEFAULT 0 COMMENT '结果表同步行数',
|
||
status VARCHAR(20) NOT NULL DEFAULT 'success' COMMENT '同步状态',
|
||
error_message VARCHAR(2000) NULL COMMENT '错误信息',
|
||
synced_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '同步时间',
|
||
KEY idx_op_barcode_channel_decision_sync_log_synced_at (synced_at),
|
||
KEY idx_op_barcode_channel_decision_sync_log_status (status)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='条码渠道判定表同步日志'`
|
||
);
|
||
});
|
||
}
|
||
|
||
async function ensurePlanningChannelDailyReadSchema() {
|
||
await withSchemaState('planning-channel-daily-read', async () => {
|
||
await ensureTable(
|
||
'channel_daily_read',
|
||
`CREATE TABLE IF NOT EXISTS channel_daily_read (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
|
||
stat_date DATE NOT NULL COMMENT '统计日期',
|
||
channel_name VARCHAR(100) NOT NULL COMMENT '渠道',
|
||
shop_name VARCHAR(255) NOT NULL COMMENT '店铺名称',
|
||
shop_key VARCHAR(255) NOT NULL COMMENT '归一化店铺键',
|
||
sku_code VARCHAR(100) NOT NULL COMMENT 'SKU编码',
|
||
spu VARCHAR(100) NULL COMMENT '产品编码/SPU',
|
||
spu_key VARCHAR(100) NULL COMMENT 'SPU聚合键',
|
||
sku_image_url VARCHAR(500) NULL COMMENT 'SKU图片',
|
||
sale_status VARCHAR(50) NULL COMMENT '销售状态',
|
||
purchaser_name VARCHAR(100) NULL COMMENT '采购负责人',
|
||
sales_amount DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '销售额',
|
||
after_sale_amount DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '售后金额',
|
||
ship_count DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '发货件数',
|
||
refund_count DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '退货件数',
|
||
sales_amount_zone1 DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '一区销售额',
|
||
sales_amount_zone2 DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '二区销售额',
|
||
sales_amount_zone3 DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '三区销售额',
|
||
sales_amount_zone4 DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '四区销售额',
|
||
after_sale_amount_zone1 DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '一区售后金额',
|
||
after_sale_amount_zone2 DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '二区售后金额',
|
||
after_sale_amount_zone3 DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '三区售后金额',
|
||
after_sale_amount_zone4 DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '四区售后金额',
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||
UNIQUE KEY uk_channel_daily_read (stat_date, channel_name, shop_key, sku_code),
|
||
INDEX idx_channel_daily_read_stat_date (stat_date),
|
||
INDEX idx_channel_daily_read_shop_key (shop_key(120)),
|
||
INDEX idx_channel_daily_read_sku_code (sku_code),
|
||
INDEX idx_channel_daily_read_stat_spu_key (stat_date, spu_key),
|
||
INDEX idx_channel_daily_read_spu_key_stat (spu_key, stat_date),
|
||
INDEX idx_channel_daily_read_channel_name (channel_name),
|
||
INDEX idx_channel_daily_read_sale_status (sale_status),
|
||
INDEX idx_channel_daily_read_purchaser_name (purchaser_name)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='渠道页读库日汇总表(企划库)'`
|
||
);
|
||
await ensureColumn('channel_daily_read', 'spu_key', "VARCHAR(100) NULL COMMENT 'SPU聚合键'");
|
||
await ensureIndex('channel_daily_read', 'idx_channel_daily_read_stat_spu_key', '(stat_date, spu_key)');
|
||
await ensureIndex('channel_daily_read', 'idx_channel_daily_read_spu_key_stat', '(spu_key, stat_date)');
|
||
await ensureColumn('channel_daily_read', 'sales_amount_zone1', "DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '一区销售额'");
|
||
await ensureColumn('channel_daily_read', 'sales_amount_zone2', "DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '二区销售额'");
|
||
await ensureColumn('channel_daily_read', 'sales_amount_zone3', "DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '三区销售额'");
|
||
await ensureColumn('channel_daily_read', 'sales_amount_zone4', "DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '四区销售额'");
|
||
await ensureColumn('channel_daily_read', 'after_sale_amount_zone1', "DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '一区售后金额'");
|
||
await ensureColumn('channel_daily_read', 'after_sale_amount_zone2', "DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '二区售后金额'");
|
||
await ensureColumn('channel_daily_read', 'after_sale_amount_zone3', "DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '三区售后金额'");
|
||
await ensureColumn('channel_daily_read', 'after_sale_amount_zone4', "DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '四区售后金额'");
|
||
|
||
await ensureTable(
|
||
'channel_daily_read_sync',
|
||
`CREATE TABLE IF NOT EXISTS channel_daily_read_sync (
|
||
stat_date DATE PRIMARY KEY COMMENT '同步日期',
|
||
source_latest_biz_date DATE NULL COMMENT '同步时业务库最新日期',
|
||
sync_version VARCHAR(64) NULL COMMENT '同步口径版本',
|
||
row_count INT NOT NULL DEFAULT 0 COMMENT '同步行数',
|
||
status ENUM('success', 'failed') NOT NULL DEFAULT 'success' COMMENT '同步状态',
|
||
error_message VARCHAR(1000) NULL COMMENT '错误信息',
|
||
synced_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最近同步时间',
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||
INDEX idx_channel_daily_read_sync_status (status),
|
||
INDEX idx_channel_daily_read_sync_source_latest (source_latest_biz_date)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='渠道页读库同步日志(企划库)'`
|
||
);
|
||
await ensureColumn('channel_daily_read_sync', 'sync_version', "VARCHAR(64) NULL COMMENT '同步口径版本'");
|
||
});
|
||
}
|
||
|
||
async function ensurePlanningChannelIdDailyReadSchema() {
|
||
await withSchemaState('planning-channel-id-daily-read', async () => {
|
||
await ensureTable(
|
||
'channel_id_daily_read',
|
||
`CREATE TABLE IF NOT EXISTS channel_id_daily_read (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
|
||
stat_date DATE NOT NULL COMMENT '统计日期',
|
||
channel_name VARCHAR(100) NOT NULL COMMENT '渠道',
|
||
shop_name VARCHAR(255) NOT NULL COMMENT '店铺名称',
|
||
shop_key VARCHAR(255) NOT NULL COMMENT '归一化店铺键',
|
||
item_id VARCHAR(255) NOT NULL COMMENT '商品ID',
|
||
primary_sku_code VARCHAR(100) NULL COMMENT '主贡献SKU编码',
|
||
primary_spu VARCHAR(100) NULL COMMENT '主贡献SPU/产品编码',
|
||
sku_image_url VARCHAR(500) NULL COMMENT '商品图片',
|
||
sale_status VARCHAR(50) NULL COMMENT '销售状态',
|
||
purchaser_name VARCHAR(100) NULL COMMENT 'ID负责人/采购负责人',
|
||
sku_count INT NOT NULL DEFAULT 0 COMMENT '关联SKU数量',
|
||
performance_amount DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '真实业绩',
|
||
fee_amount DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '真实费用',
|
||
transaction_amount DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '成交金额',
|
||
after_sale_amount DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '售后金额',
|
||
push_fee_amount DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '推广费',
|
||
marketing_fee_amount DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '营销费',
|
||
gross_cost_amount DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '成本金额',
|
||
goods_count DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '成交件数',
|
||
refund_count DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '退款件数',
|
||
order_count INT NOT NULL DEFAULT 0 COMMENT '订单数',
|
||
install_order_count INT NOT NULL DEFAULT 0 COMMENT '安装订单数',
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||
UNIQUE KEY uk_channel_id_daily_read (stat_date, channel_name, shop_key, item_id),
|
||
INDEX idx_channel_id_daily_read_stat_date (stat_date),
|
||
INDEX idx_channel_id_daily_read_item_id (item_id),
|
||
INDEX idx_channel_id_daily_read_shop_key (shop_key(120)),
|
||
INDEX idx_channel_id_daily_read_channel_name (channel_name),
|
||
INDEX idx_channel_id_daily_read_purchaser (purchaser_name),
|
||
INDEX idx_channel_id_daily_read_performance (stat_date, performance_amount)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='渠道页ID维度读库日汇总表(企划库)'`
|
||
);
|
||
|
||
await ensureTable(
|
||
'channel_id_daily_read_sync',
|
||
`CREATE TABLE IF NOT EXISTS channel_id_daily_read_sync (
|
||
stat_date DATE PRIMARY KEY COMMENT '同步日期',
|
||
source_latest_biz_date DATE NULL COMMENT '同步时业务库最新日期',
|
||
sync_version VARCHAR(64) NULL COMMENT '同步口径版本',
|
||
row_count INT NOT NULL DEFAULT 0 COMMENT '同步行数',
|
||
status ENUM('success', 'failed') NOT NULL DEFAULT 'success' COMMENT '同步状态',
|
||
error_message VARCHAR(1000) NULL COMMENT '错误信息',
|
||
synced_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最近同步时间',
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||
INDEX idx_channel_id_daily_read_sync_status (status),
|
||
INDEX idx_channel_id_daily_read_sync_source_latest (source_latest_biz_date)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='渠道页ID维度读库同步日志(企划库)'`
|
||
);
|
||
});
|
||
}
|
||
|
||
async function ensurePlanningPddSkuDimensionSchema() {
|
||
await withSchemaState('planning-pdd-sku-dimension', async () => {
|
||
await ensureTable(
|
||
'op_pdd_sku_dimension_spu_daily',
|
||
`CREATE TABLE IF NOT EXISTS op_pdd_sku_dimension_spu_daily (
|
||
statDate DATE NOT NULL COMMENT '业务日期',
|
||
startDate DATE NOT NULL COMMENT '统计开始日期',
|
||
endDate DATE NOT NULL COMMENT '统计结束日期',
|
||
spu VARCHAR(100) NOT NULL COMMENT 'SPU',
|
||
goodsIdCount INT NOT NULL DEFAULT 0 COMMENT '铺货商品id数',
|
||
activeGoodsIdCount INT NOT NULL DEFAULT 0 COMMENT '动销商品id数',
|
||
skuListingActiveRate DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT 'SPU铺货动销率',
|
||
skuIdEfficiency DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT 'SPU链接效能',
|
||
isPriceBreak TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否破价 0否1是',
|
||
payOrdrAmt DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天真实销售额',
|
||
feeRatio DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT '近7天真实费比',
|
||
afterSaleRate DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT '近7天真实售后率',
|
||
goodsUv DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天访客数',
|
||
orderNum DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天订单量',
|
||
payOrdrUsrCnt DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天买家数',
|
||
payOrdrGoodsQty DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天成交件数',
|
||
ctr DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT '近7天点击率',
|
||
goodsVcr DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT '近7天成交转化率',
|
||
customerUnitPrice DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天客单价',
|
||
pieceUnitPrice DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天件单价',
|
||
spend DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天总花费',
|
||
shopNameList TEXT NULL COMMENT '关联店铺名称列表',
|
||
idOwnerList TEXT NULL COMMENT '关联id负责人列表',
|
||
ownerDeptList TEXT NULL COMMENT '关联所属部门列表',
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||
PRIMARY KEY (statDate, spu),
|
||
KEY idx_op_pdd_spu_daily_spu (spu),
|
||
KEY idx_op_pdd_spu_daily_payOrdrAmt (statDate, payOrdrAmt),
|
||
KEY idx_op_pdd_spu_daily_feeRatio (statDate, feeRatio)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='拼多多SPU维度看板快照表(企划库)'`
|
||
);
|
||
|
||
await ensureTable(
|
||
'op_pdd_sku_dimension_sku_daily',
|
||
`CREATE TABLE IF NOT EXISTS op_pdd_sku_dimension_sku_daily (
|
||
statDate DATE NOT NULL COMMENT '业务日期',
|
||
startDate DATE NOT NULL COMMENT '统计开始日期',
|
||
endDate DATE NOT NULL COMMENT '统计结束日期',
|
||
spu VARCHAR(100) NOT NULL COMMENT 'SPU',
|
||
skuCode VARCHAR(100) NOT NULL COMMENT 'SKU货号',
|
||
goodsIdCount INT NOT NULL DEFAULT 0 COMMENT '铺货商品id数',
|
||
activeGoodsIdCount INT NOT NULL DEFAULT 0 COMMENT '动销商品id数',
|
||
skuListingActiveRate DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT 'SKU铺货动销率',
|
||
skuIdEfficiency DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT 'SKU链接效能',
|
||
isPriceBreak TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否破价 0否1是',
|
||
payOrdrAmt DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天真实销售额',
|
||
feeRatio DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT '近7天真实费比',
|
||
afterSaleRate DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT '近7天真实售后率',
|
||
goodsUv DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天访客数',
|
||
orderNum DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天订单量',
|
||
payOrdrUsrCnt DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天买家数',
|
||
payOrdrGoodsQty DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天成交件数',
|
||
ctr DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT '近7天点击率',
|
||
goodsVcr DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT '近7天成交转化率',
|
||
customerUnitPrice DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天客单价',
|
||
pieceUnitPrice DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天件单价',
|
||
spend DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天总花费',
|
||
shopNameList TEXT NULL COMMENT '关联店铺名称列表',
|
||
idOwnerList TEXT NULL COMMENT '关联id负责人列表',
|
||
ownerDeptList TEXT NULL COMMENT '关联所属部门列表',
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||
PRIMARY KEY (statDate, spu, skuCode),
|
||
KEY idx_op_pdd_sku_daily_spu (statDate, spu),
|
||
KEY idx_op_pdd_sku_daily_sku (skuCode),
|
||
KEY idx_op_pdd_sku_daily_payOrdrAmt (statDate, payOrdrAmt)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='拼多多SKU维度看板快照表(企划库)'`
|
||
);
|
||
|
||
await ensureTable(
|
||
'op_pdd_sku_dimension_goods_daily',
|
||
`CREATE TABLE IF NOT EXISTS op_pdd_sku_dimension_goods_daily (
|
||
statDate DATE NOT NULL COMMENT '业务日期',
|
||
startDate DATE NOT NULL COMMENT '统计开始日期',
|
||
endDate DATE NOT NULL COMMENT '统计结束日期',
|
||
spu VARCHAR(100) NOT NULL COMMENT 'SPU',
|
||
skuCode VARCHAR(100) NOT NULL COMMENT 'SKU货号',
|
||
goodsId VARCHAR(50) NOT NULL COMMENT '商品id',
|
||
goodsName VARCHAR(500) NULL COMMENT '商品名称',
|
||
hdThumbUrl VARCHAR(1000) NULL COMMENT '商品主图',
|
||
idOwner VARCHAR(100) NULL COMMENT 'id负责人',
|
||
ownerDept VARCHAR(100) NULL COMMENT '所属部门',
|
||
shopName VARCHAR(255) NULL COMMENT '店铺名称',
|
||
goodsUv DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天访客数',
|
||
inquiryNum DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天询单量',
|
||
goodsFavCnt DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天收藏用户',
|
||
goodsFavNum DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天收藏量',
|
||
orderUserCount DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天下单人数',
|
||
ctr DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT '近7天点击率',
|
||
clickConversionRate DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT '近7天点击转化率',
|
||
goodsVcr DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT '近7天成交转化率',
|
||
ordrVstrRto DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT '近7天下单率',
|
||
payOrdrRto DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT '近7天成交率',
|
||
imprUsrCnt DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天流失指数',
|
||
unpaidUserCount DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天未支付人数',
|
||
payOrdrAmt DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天真实销售额',
|
||
orderNum DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天订单量',
|
||
payOrdrUsrCnt DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天买家数',
|
||
payOrdrGoodsQty DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天成交件数',
|
||
customerUnitPrice DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天客单价',
|
||
pieceUnitPrice DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天件单价',
|
||
spend DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天总花费',
|
||
feeRatio DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT '近7天真实费比',
|
||
afterSaleRate DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT '近7天真实售后率',
|
||
afterSaleCount DECIMAL(18,2) NOT NULL DEFAULT 0 COMMENT '近7天售后单量',
|
||
badReviewCount INT NOT NULL DEFAULT 0 COMMENT '近7天差评量',
|
||
isPriceBreak TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否破价 0否1是',
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||
PRIMARY KEY (statDate, goodsId),
|
||
KEY idx_op_pdd_goods_daily_spu (statDate, spu),
|
||
KEY idx_op_pdd_goods_daily_sku (statDate, skuCode),
|
||
KEY idx_op_pdd_goods_daily_shop (statDate, shopName),
|
||
KEY idx_op_pdd_goods_daily_owner (statDate, idOwner),
|
||
KEY idx_op_pdd_goods_daily_dept (statDate, ownerDept),
|
||
KEY idx_op_pdd_goods_daily_payOrdrAmt (statDate, payOrdrAmt)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='拼多多商品id维度看板快照表(企划库)'`
|
||
);
|
||
});
|
||
}
|
||
|
||
module.exports = {
|
||
ensurePlanningUploadBatchSchema,
|
||
ensurePlanningAiImageSchema,
|
||
ensurePlanningAppearanceMatchSchema,
|
||
ensurePlanningStockSelectionSchema,
|
||
ensurePlanningChannelDailyReadSchema,
|
||
ensurePlanningChannelIdDailyReadSchema,
|
||
ensurePlanningPddSkuDimensionSchema,
|
||
};
|