fix: 新增态 效果
This commit is contained in:
Binary file not shown.
19
server/db.js
19
server/db.js
@@ -291,6 +291,25 @@ function runMigrations(db) {
|
||||
exec('ALTER TABLE map_strike_line ADD COLUMN struck_at TEXT')
|
||||
}
|
||||
} catch (_) {}
|
||||
try {
|
||||
exec(`
|
||||
CREATE TABLE IF NOT EXISTS animation_config (
|
||||
id INTEGER PRIMARY KEY CHECK (id = 1),
|
||||
strike_cutoff_days INTEGER NOT NULL DEFAULT 5,
|
||||
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
INSERT OR IGNORE INTO animation_config (id, strike_cutoff_days) VALUES (1, 5);
|
||||
`)
|
||||
} catch (_) {}
|
||||
try {
|
||||
exec(`
|
||||
CREATE TABLE IF NOT EXISTS war_map_config (
|
||||
id INTEGER PRIMARY KEY CHECK (id = 1),
|
||||
config TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
`)
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
async function initDb() {
|
||||
|
||||
@@ -191,6 +191,41 @@ router.get('/stats', (req, res) => {
|
||||
}
|
||||
})
|
||||
|
||||
// 战区地图配置:钳形轴线、以黎轴线、防御线路径,供前端 useWarMapData 拉取;新增/修改数据落库
|
||||
router.get('/war-map-config', (req, res) => {
|
||||
try {
|
||||
const row = db.prepare('SELECT config FROM war_map_config WHERE id = 1').get()
|
||||
if (!row || !row.config) {
|
||||
return res.json({})
|
||||
}
|
||||
const data = JSON.parse(row.config)
|
||||
res.json(data)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
res.status(500).json({ error: err.message })
|
||||
}
|
||||
})
|
||||
|
||||
router.put('/war-map-config', requireAdmin, (req, res) => {
|
||||
try {
|
||||
const body = req.body || {}
|
||||
const pincerAxes = Array.isArray(body.pincerAxes) ? body.pincerAxes : null
|
||||
const israelLebanonAxis = body.israelLebanonAxis && typeof body.israelLebanonAxis === 'object' ? body.israelLebanonAxis : null
|
||||
const defenseLinePath = Array.isArray(body.defenseLinePath) ? body.defenseLinePath : null
|
||||
if (!pincerAxes?.length || !israelLebanonAxis || !defenseLinePath?.length) {
|
||||
return res.status(400).json({ error: 'pincerAxes (array), israelLebanonAxis (object), defenseLinePath (array) required' })
|
||||
}
|
||||
const config = JSON.stringify({ pincerAxes, israelLebanonAxis, defenseLinePath })
|
||||
db.prepare(
|
||||
'INSERT INTO war_map_config (id, config, updated_at) VALUES (1, ?, datetime(\'now\')) ON CONFLICT(id) DO UPDATE SET config = excluded.config, updated_at = datetime(\'now\')'
|
||||
).run(config)
|
||||
res.json({ ok: true })
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
res.status(500).json({ error: err.message })
|
||||
}
|
||||
})
|
||||
|
||||
router.get('/events', (req, res) => {
|
||||
try {
|
||||
const s = getSituation()
|
||||
@@ -225,9 +260,13 @@ router.get('/edit/raw', (req, res) => {
|
||||
const summaryUs = db.prepare('SELECT * FROM force_summary WHERE side = ?').get('us')
|
||||
const summaryIr = db.prepare('SELECT * FROM force_summary WHERE side = ?').get('iran')
|
||||
let displayStats = null
|
||||
let animationConfig = null
|
||||
try {
|
||||
displayStats = db.prepare('SELECT override_enabled, viewers, cumulative, share_count, like_count, feedback_count FROM display_stats WHERE id = 1').get()
|
||||
} catch (_) {}
|
||||
try {
|
||||
animationConfig = db.prepare('SELECT strike_cutoff_days FROM animation_config WHERE id = 1').get()
|
||||
} catch (_) {}
|
||||
const realCumulative = db.prepare('SELECT total FROM visitor_count WHERE id = 1').get()?.total ?? 0
|
||||
const realShare = db.prepare('SELECT total FROM share_count WHERE id = 1').get()?.total ?? 0
|
||||
const liveViewers = db.prepare(
|
||||
@@ -251,6 +290,9 @@ router.get('/edit/raw', (req, res) => {
|
||||
likeCount: displayStats?.like_count ?? realLikeCount,
|
||||
feedbackCount: displayStats?.feedback_count ?? realFeedback,
|
||||
},
|
||||
animationConfig: {
|
||||
strikeCutoffDays: animationConfig?.strike_cutoff_days ?? 5,
|
||||
},
|
||||
})
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
@@ -438,4 +480,20 @@ router.put('/edit/display-stats', (req, res) => {
|
||||
}
|
||||
})
|
||||
|
||||
router.put('/edit/animation-config', (req, res) => {
|
||||
try {
|
||||
const body = req.body || {}
|
||||
const v = body.strikeCutoffDays
|
||||
const n = Math.max(1, parseInt(v, 10) || 0)
|
||||
if (!Number.isFinite(n)) return res.status(400).json({ error: 'strikeCutoffDays must be number' })
|
||||
db.prepare('INSERT OR IGNORE INTO animation_config (id, strike_cutoff_days) VALUES (1, 5)').run()
|
||||
db.prepare('UPDATE animation_config SET strike_cutoff_days = ?, updated_at = datetime(\'now\') WHERE id = 1').run(n)
|
||||
broadcastAfterEdit(req)
|
||||
res.json({ ok: true })
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
res.status(400).json({ error: err.message })
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = router
|
||||
|
||||
@@ -190,7 +190,16 @@ function seed() {
|
||||
[46.42, 33.64, '伊拉姆导弹阵地', '2026-02-28T02:40:00.000Z'],
|
||||
[48.35, 33.48, '霍拉马巴德储备库', '2026-02-28T02:42:00.000Z'],
|
||||
]
|
||||
// 以色列攻击黎巴嫩(真主党目标),时间在伊朗反击之后 14:00–14:40
|
||||
const israelLebanonTargets = [
|
||||
[35.5, 33.86, '贝鲁特南郊指挥所', '2026-02-28T14:00:00.000Z'],
|
||||
[35.32, 33.34, '利塔尼弹药库', '2026-02-28T14:10:00.000Z'],
|
||||
[36.2, 34.01, '巴勒贝克后勤枢纽', '2026-02-28T14:20:00.000Z'],
|
||||
[35.19, 33.27, '提尔海岸阵地', '2026-02-28T14:30:00.000Z'],
|
||||
[36.38, 34.39, '赫尔梅勒无人机阵地', '2026-02-28T14:40:00.000Z'],
|
||||
]
|
||||
israelTargets.forEach(([lng, lat, name, struckAt]) => insertStrikeLine.run('israel', lng, lat, name, struckAt))
|
||||
israelLebanonTargets.forEach(([lng, lat, name, struckAt]) => insertStrikeLine.run('israel', lng, lat, name, struckAt))
|
||||
lincolnTargets.forEach(([lng, lat, name, struckAt]) => insertStrikeLine.run('lincoln', lng, lat, name, struckAt))
|
||||
fordTargets.forEach(([lng, lat, name, struckAt]) => insertStrikeLine.run('ford', lng, lat, name, struckAt))
|
||||
|
||||
@@ -229,6 +238,28 @@ function seed() {
|
||||
const insertUpdate = db.prepare('INSERT INTO situation_update (id, timestamp, category, summary, severity) VALUES (?, ?, ?, ?, ?)')
|
||||
updateRows.forEach((row) => insertUpdate.run(...row))
|
||||
|
||||
try {
|
||||
db.prepare(
|
||||
'INSERT OR REPLACE INTO animation_config (id, strike_cutoff_days, updated_at) VALUES (1, ?, datetime(\'now\'))'
|
||||
).run(5)
|
||||
} catch (_) {}
|
||||
|
||||
// 战区地图配置:钳形轴线、以黎轴线、防御线(与 src/data/extendedWarData 一致,新增数据落库)
|
||||
const warMapConfig = {
|
||||
pincerAxes: [
|
||||
{ start: [43.6, 37.2], end: [46.27, 38.08], name: 'North Pincer (Tabriz)' },
|
||||
{ start: [45.0, 35.4], end: [46.99, 35.31], name: 'Central Pincer (Sanandaj)' },
|
||||
{ start: [45.6, 35.2], end: [47.07, 34.31], name: 'South Pincer (Kermanshah)' },
|
||||
],
|
||||
israelLebanonAxis: { start: [35.25, 32.95], end: [35.55, 33.45], name: 'Israel → Lebanon' },
|
||||
defenseLinePath: [[46.27, 38.08], [46.99, 35.31], [47.07, 34.31]],
|
||||
}
|
||||
try {
|
||||
db.prepare(
|
||||
'INSERT INTO war_map_config (id, config, updated_at) VALUES (1, ?, datetime(\'now\')) ON CONFLICT(id) DO UPDATE SET config = excluded.config, updated_at = datetime(\'now\')'
|
||||
).run(JSON.stringify(warMapConfig))
|
||||
} catch (_) {}
|
||||
|
||||
db.prepare("INSERT OR REPLACE INTO situation (id, data, updated_at) VALUES (1, '{}', ?)").run('2026-03-01T11:45:00.000Z')
|
||||
console.log('Seed completed.')
|
||||
}
|
||||
|
||||
@@ -82,6 +82,10 @@ function getSituation() {
|
||||
const updates = db.prepare('SELECT * FROM situation_update ORDER BY timestamp DESC LIMIT 50').all()
|
||||
// 数据更新时间:与前端「实时更新」一致,仅在爬虫 notify / 编辑保存时由 index.js 或 routes 更新
|
||||
const meta = db.prepare('SELECT updated_at FROM situation WHERE id = 1').get()
|
||||
let animationConfigRow = null
|
||||
try {
|
||||
animationConfigRow = db.prepare('SELECT strike_cutoff_days FROM animation_config WHERE id = 1').get()
|
||||
} catch (_) {}
|
||||
|
||||
let conflictEvents = []
|
||||
let conflictStats = { total_events: 0, high_impact_events: 0, estimated_casualties: 0, estimated_strike_count: 0 }
|
||||
@@ -180,6 +184,9 @@ function getSituation() {
|
||||
strikeSources: mapStrikeSources,
|
||||
strikeLines: mapStrikeLines,
|
||||
},
|
||||
animationConfig: {
|
||||
strikeCutoffDays: animationConfigRow?.strike_cutoff_days ?? 5,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user