Update: 2026-07-06 19:17:19

This commit is contained in:
Hamza-Ayed
2026-07-06 19:17:20 +03:00
parent d6ab09c19b
commit 3c9a3dbef8
4 changed files with 112 additions and 3 deletions
@@ -164,6 +164,43 @@ export async function saveSurgeInsights(
await pool.execute(sql, flatParams);
}
export async function saveSurgeZones(
pool: mysql.Pool,
zones: Array<{
competitorName: string;
countryCode: string;
zoneKey: string;
latitude: number;
longitude: number;
avgPpk: number;
sampleCount: number;
surgeMultiplier: number;
}>
): Promise<void> {
if (zones.length === 0) return;
const values = zones.map(() => `(?, ?, ?, ?, ?, ?, ?, ?, NOW())`).join(',');
const flatParams: (string | number)[] = [];
for (const z of zones) {
flatParams.push(
z.competitorName, z.countryCode, z.zoneKey,
z.latitude, z.longitude, z.avgPpk, z.sampleCount, z.surgeMultiplier
);
}
const sql = `INSERT INTO competitor_surge_zones
(competitor_name, country_code, zone_key, latitude, longitude, avg_ppk, sample_count, surge_multiplier, detected_at)
VALUES ${values}
ON DUPLICATE KEY UPDATE
avg_ppk = VALUES(avg_ppk),
sample_count = VALUES(sample_count),
surge_multiplier = VALUES(surge_multiplier),
detected_at = NOW()`;
await pool.execute(sql, flatParams);
}
export async function closeConnections(): Promise<void> {
if (mysqlPool) {
await mysqlPool.end();
+26 -1
View File
@@ -10,7 +10,7 @@
* Cron integration: see crontab examples in package.json scripts
*/
import { getMySQL, fetchSamples, saveFormulas, saveSurgeInsights, closeConnections } from './db/connection';
import { getMySQL, fetchSamples, saveFormulas, saveSurgeInsights, saveSurgeZones, closeConnections } from './db/connection';
import { runAnalysis } from './analysis/engine';
import { Pool, RowDataPacket } from 'mysql2/promise';
@@ -255,6 +255,31 @@ async function processCompetitor(
await saveSurgeInsights(pool, surgeInsights);
console.log(` ✅ Saved surge insight: avg ${avgMultiplier.toFixed(3)}x, hours ${peakStart}:00-${peakEnd}:00`);
}
// --- Save surge zones ---
if (opts.mode !== 'report' && report.zones.length > 0) {
// Find the standard tier formula to use as a baseline for calculating surge multipliers
const standardTier = formulas.find(f => f.tier === 'standard') || formulas[0];
const baselinePpk = standardTier ? standardTier.kmRate : 0.350;
const surgeZones = report.zones
.filter(z => z.avgPpk > baselinePpk * 1.1) // Only keep zones with > 10% surge
.map(z => ({
competitorName: comp.competitor_name,
countryCode: comp.country_code,
zoneKey: z.zoneKey,
latitude: z.centerLat,
longitude: z.centerLng,
avgPpk: z.avgPpk,
sampleCount: z.samples.length,
surgeMultiplier: parseFloat((z.avgPpk / baselinePpk).toFixed(3)),
}));
if (surgeZones.length > 0) {
await saveSurgeZones(pool, surgeZones);
console.log(` ✅ Saved ${surgeZones.length} surge zones for heatmap`);
}
}
}
async function fetchCompetitors(