Files
usa/server/situationData.js
2026-03-02 00:59:40 +08:00

142 lines
5.8 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 db = require('./db')
function toAsset(row) {
return {
id: row.id,
name: row.name,
type: row.type,
count: row.count,
status: row.status,
...(row.lat != null && { location: { lat: row.lat, lng: row.lng } }),
}
}
function toLosses(row) {
return {
bases: { destroyed: row.bases_destroyed, damaged: row.bases_damaged },
personnelCasualties: { killed: row.personnel_killed, wounded: row.personnel_wounded },
civilianCasualties: { killed: row.civilian_killed ?? 0, wounded: row.civilian_wounded ?? 0 },
aircraft: row.aircraft,
warships: row.warships,
armor: row.armor,
vehicles: row.vehicles,
}
}
const defaultLosses = {
bases: { destroyed: 0, damaged: 0 },
personnelCasualties: { killed: 0, wounded: 0 },
civilianCasualties: { killed: 0, wounded: 0 },
aircraft: 0,
warships: 0,
armor: 0,
vehicles: 0,
}
function getSituation() {
const summaryUs = db.prepare('SELECT * FROM force_summary WHERE side = ?').get('us')
const summaryIr = db.prepare('SELECT * FROM force_summary WHERE side = ?').get('iran')
const powerUs = db.prepare('SELECT * FROM power_index WHERE side = ?').get('us')
const powerIr = db.prepare('SELECT * FROM power_index WHERE side = ?').get('iran')
const assetsUs = db.prepare('SELECT * FROM force_asset WHERE side = ? ORDER BY id').all('us')
const assetsIr = db.prepare('SELECT * FROM force_asset WHERE side = ? ORDER BY id').all('iran')
const locUs = db.prepare('SELECT id, name, lat, lng, type, region, status, damage_level FROM key_location WHERE side = ?').all('us')
const locIr = db.prepare('SELECT id, name, lat, lng, type, region FROM key_location WHERE side = ?').all('iran')
const lossesUs = db.prepare('SELECT * FROM combat_losses WHERE side = ?').get('us')
const lossesIr = db.prepare('SELECT * FROM combat_losses WHERE side = ?').get('iran')
const trend = db.prepare('SELECT time, value FROM wall_street_trend ORDER BY time').all()
const retaliationCur = db.prepare('SELECT value FROM retaliation_current WHERE id = 1').get()
const retaliationHist = db.prepare('SELECT time, value FROM retaliation_history ORDER BY time').all()
const updates = db.prepare('SELECT * FROM situation_update ORDER BY timestamp DESC LIMIT 50').all()
const meta = db.prepare('SELECT updated_at FROM situation WHERE id = 1').get()
let conflictEvents = []
let conflictStats = { total_events: 0, high_impact_events: 0, estimated_casualties: 0, estimated_strike_count: 0 }
try {
conflictEvents = db.prepare('SELECT event_id, event_time, title, lat, lng, impact_score, url FROM gdelt_events ORDER BY event_time DESC LIMIT 30').all()
const statsRow = db.prepare('SELECT total_events, high_impact_events, estimated_casualties, estimated_strike_count FROM conflict_stats WHERE id = 1').get()
if (statsRow) conflictStats = statsRow
} catch (_) {}
// 根据爬虫 conflict_stats 实时合并平民伤亡估算GDELT 数据)
const usLossesBase = lossesUs ? toLosses(lossesUs) : defaultLosses
const irLossesBase = lossesIr ? toLosses(lossesIr) : defaultLosses
const est = conflictStats.estimated_casualties || 0
const mergeCivilian = (base, share) => {
if (est <= 0) return base.civilianCasualties || { killed: 0, wounded: 0 }
const gdeltKilled = Math.round(est * share)
const cur = base.civilianCasualties || { killed: 0, wounded: 0 }
return { killed: Math.max(cur.killed, gdeltKilled), wounded: cur.wounded }
}
const usLosses = { ...usLossesBase, civilianCasualties: mergeCivilian(usLossesBase, 0.35) }
const irLosses = { ...irLossesBase, civilianCasualties: mergeCivilian(irLossesBase, 0.65) }
return {
lastUpdated: meta?.updated_at || new Date().toISOString(),
usForces: {
summary: {
totalAssets: summaryUs?.total_assets ?? 0,
personnel: summaryUs?.personnel ?? 0,
navalShips: summaryUs?.naval_ships ?? 0,
aircraft: summaryUs?.aircraft ?? 0,
groundUnits: summaryUs?.ground_units ?? 0,
uav: summaryUs?.uav ?? 0,
missileConsumed: summaryUs?.missile_consumed ?? 0,
missileStock: summaryUs?.missile_stock ?? 0,
},
powerIndex: {
overall: powerUs?.overall ?? 0,
militaryStrength: powerUs?.military_strength ?? 0,
economicPower: powerUs?.economic_power ?? 0,
geopoliticalInfluence: powerUs?.geopolitical_influence ?? 0,
},
assets: (assetsUs || []).map(toAsset),
keyLocations: locUs || [],
combatLosses: usLosses,
wallStreetInvestmentTrend: trend || [],
},
iranForces: {
summary: {
totalAssets: summaryIr?.total_assets ?? 0,
personnel: summaryIr?.personnel ?? 0,
navalShips: summaryIr?.naval_ships ?? 0,
aircraft: summaryIr?.aircraft ?? 0,
groundUnits: summaryIr?.ground_units ?? 0,
uav: summaryIr?.uav ?? 0,
missileConsumed: summaryIr?.missile_consumed ?? 0,
missileStock: summaryIr?.missile_stock ?? 0,
},
powerIndex: {
overall: powerIr?.overall ?? 0,
militaryStrength: powerIr?.military_strength ?? 0,
economicPower: powerIr?.economic_power ?? 0,
geopoliticalInfluence: powerIr?.geopolitical_influence ?? 0,
},
assets: (assetsIr || []).map(toAsset),
keyLocations: locIr || [],
combatLosses: irLosses,
retaliationSentiment: retaliationCur?.value ?? 0,
retaliationSentimentHistory: retaliationHist || [],
},
recentUpdates: (updates || []).map((u) => ({
id: u.id,
timestamp: u.timestamp,
category: u.category,
summary: u.summary,
severity: u.severity,
})),
conflictEvents: conflictEvents.map((e) => ({
event_id: e.event_id,
event_time: e.event_time,
title: e.title,
lat: e.lat,
lng: e.lng,
impact_score: e.impact_score,
url: e.url,
})),
conflictStats,
}
}
module.exports = { getSituation }