cangku/backend/src/services/planningSupportSchema.js

569 lines
34 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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,
};