From a3bf8abda52b5d1e1356c0b6b0a372826754795d Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 4 Mar 2026 19:19:50 +0800 Subject: [PATCH] =?UTF-8?q?fix:=E5=AF=B9=E9=BD=90=E7=94=9F=E4=BA=A7?= =?UTF-8?q?=E7=8E=AF=E5=A2=83=E7=9A=84=E6=95=B0=E6=8D=AE=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/align-production-schema.sh | 154 +++++++++++++++++++++++++ scripts/check-attack-locations.sh | 64 ++++++++++ scripts/gen-align-schema-from-local.sh | 77 +++++++++++++ scripts/test.sh | 126 ++++++++++++++++++++ 4 files changed, 421 insertions(+) create mode 100755 scripts/align-production-schema.sh create mode 100755 scripts/check-attack-locations.sh create mode 100755 scripts/gen-align-schema-from-local.sh create mode 100644 scripts/test.sh diff --git a/scripts/align-production-schema.sh b/scripts/align-production-schema.sh new file mode 100755 index 0000000..b0574d5 --- /dev/null +++ b/scripts/align-production-schema.sh @@ -0,0 +1,154 @@ +#!/usr/bin/env bash +# 由 scripts/gen-align-schema-from-local.sh 根据本地 server/data.db 表结构生成,供生产执行。 +# 用法:在生产目录执行 DB_PATH=server/data.db ./scripts/align-production-schema.sh +set -e +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +DB_PATH="${DB_PATH:-$PROJECT_ROOT/server/data.db}" + +run() { sqlite3 "$DB_PATH" "$1" 2>/dev/null || true; } + +echo "=== 对齐生产库表结构(与本地 data.db 一致):$DB_PATH ===" +run "ALTER TABLE combat_losses ADD COLUMN bases_destroyed INTEGER NOT NULL;" +# 本地列) +run "ALTER TABLE combat_losses ADD COLUMN bases_damaged INTEGER NOT NULL;" +run "ALTER TABLE combat_losses ADD COLUMN personnel_killed INTEGER NOT NULL;" +run "ALTER TABLE combat_losses ADD COLUMN personnel_wounded INTEGER NOT NULL;" +run "ALTER TABLE combat_losses ADD COLUMN aircraft INTEGER NOT NULL;" +run "ALTER TABLE combat_losses ADD COLUMN warships INTEGER NOT NULL;" +run "ALTER TABLE combat_losses ADD COLUMN armor INTEGER NOT NULL;" +run "ALTER TABLE combat_losses ADD COLUMN vehicles INTEGER NOT NULL;" +run "ALTER TABLE combat_losses ADD COLUMN civilian_killed INTEGER NOT NULL DEFAULT 0;" +run "ALTER TABLE combat_losses ADD COLUMN civilian_wounded INTEGER NOT NULL DEFAULT 0;" +run "ALTER TABLE combat_losses ADD COLUMN drones INTEGER NOT NULL DEFAULT 0;" +run "ALTER TABLE combat_losses ADD COLUMN missiles INTEGER NOT NULL DEFAULT 0;" +run "ALTER TABLE combat_losses ADD COLUMN helicopters INTEGER NOT NULL DEFAULT 0;" +run "ALTER TABLE combat_losses ADD COLUMN submarines INTEGER NOT NULL DEFAULT 0;" +run "ALTER TABLE combat_losses ADD COLUMN tanks INTEGER NOT NULL DEFAULT 0;" +run "ALTER TABLE combat_losses ADD COLUMN carriers INTEGER NOT NULL DEFAULT 0;" +run "UPDATE combat_losses SET carriers = COALESCE(tanks, 0) WHERE carriers = 0;" +run "ALTER TABLE combat_losses ADD COLUMN civilian_ships INTEGER NOT NULL DEFAULT 0;" +run "ALTER TABLE combat_losses ADD COLUMN airport_port INTEGER NOT NULL DEFAULT 0;" +echo " combat_losses done" +run "ALTER TABLE conflict_stats ADD COLUMN total_events INTEGER NOT NULL DEFAULT 0;" +# 本地列) +run "ALTER TABLE conflict_stats ADD COLUMN high_impact_events INTEGER NOT NULL DEFAULT 0;" +run "ALTER TABLE conflict_stats ADD COLUMN estimated_casualties INTEGER NOT NULL DEFAULT 0;" +run "ALTER TABLE conflict_stats ADD COLUMN estimated_strike_count INTEGER NOT NULL DEFAULT 0;" +run "ALTER TABLE conflict_stats ADD COLUMN updated_at TEXT NOT NULL;" +echo " conflict_stats done" +run "ALTER TABLE display_stats ADD COLUMN viewers INTEGER;" +# 本地列) +run "ALTER TABLE display_stats ADD COLUMN share_count INTEGER;" +run "ALTER TABLE display_stats ADD COLUMN like_count INTEGER;" +run "ALTER TABLE display_stats ADD COLUMN override_enabled INTEGER NOT NULL DEFAULT 0;" +echo " display_stats done" +run "ALTER TABLE feedback ADD COLUMN content TEXT NOT NULL;" +# 本地列) +run "ALTER TABLE feedback ADD COLUMN ip TEXT;" +run "ALTER TABLE feedback ADD COLUMN created_at TEXT NOT NULL;" +echo " feedback done" +run "ALTER TABLE force_asset ADD COLUMN side TEXT NOT NULL;" +# 本地列) +run "ALTER TABLE force_asset ADD COLUMN name TEXT NOT NULL;" +run "ALTER TABLE force_asset ADD COLUMN type TEXT NOT NULL;" +run "ALTER TABLE force_asset ADD COLUMN count INTEGER NOT NULL;" +run "ALTER TABLE force_asset ADD COLUMN status TEXT NOT NULL;" +run "ALTER TABLE force_asset ADD COLUMN lat REAL;" +run "ALTER TABLE force_asset ADD COLUMN lng REAL;" +echo " force_asset done" +run "ALTER TABLE force_summary ADD COLUMN total_assets INTEGER NOT NULL;" +# 本地列) +run "ALTER TABLE force_summary ADD COLUMN personnel INTEGER NOT NULL;" +run "ALTER TABLE force_summary ADD COLUMN naval_ships INTEGER NOT NULL;" +run "ALTER TABLE force_summary ADD COLUMN aircraft INTEGER NOT NULL;" +run "ALTER TABLE force_summary ADD COLUMN ground_units INTEGER NOT NULL;" +run "ALTER TABLE force_summary ADD COLUMN uav INTEGER NOT NULL;" +run "ALTER TABLE force_summary ADD COLUMN missile_consumed INTEGER NOT NULL;" +run "ALTER TABLE force_summary ADD COLUMN missile_stock INTEGER NOT NULL;" +echo " force_summary done" +run "ALTER TABLE gdelt_events ADD COLUMN event_time TEXT NOT NULL;" +# 本地列) +run "ALTER TABLE gdelt_events ADD COLUMN title TEXT NOT NULL;" +run "ALTER TABLE gdelt_events ADD COLUMN lat REAL NOT NULL;" +run "ALTER TABLE gdelt_events ADD COLUMN lng REAL NOT NULL;" +run "ALTER TABLE gdelt_events ADD COLUMN impact_score INTEGER NOT NULL;" +run "ALTER TABLE gdelt_events ADD COLUMN url TEXT;" +run "ALTER TABLE gdelt_events ADD COLUMN created_at TEXT;" +echo " gdelt_events done" +run "ALTER TABLE key_location ADD COLUMN side TEXT NOT NULL;" +# 本地列) +run "ALTER TABLE key_location ADD COLUMN name TEXT NOT NULL;" +run "ALTER TABLE key_location ADD COLUMN lat REAL NOT NULL;" +run "ALTER TABLE key_location ADD COLUMN lng REAL NOT NULL;" +run "ALTER TABLE key_location ADD COLUMN type TEXT;" +run "ALTER TABLE key_location ADD COLUMN region TEXT;" +run 'ALTER TABLE key_location ADD COLUMN status TEXT DEFAULT '\''operational'\'';' +run "ALTER TABLE key_location ADD COLUMN damage_level INTEGER;" +run "ALTER TABLE key_location ADD COLUMN attacked_at TEXT;" +echo " key_location done" +run "ALTER TABLE like_count ADD COLUMN total INTEGER NOT NULL DEFAULT 0;" +# 本地列) +echo " like_count done" +run "ALTER TABLE map_strike_line ADD COLUMN target_lng REAL NOT NULL;" +# 本地列) +run "ALTER TABLE map_strike_line ADD COLUMN target_lat REAL NOT NULL;" +run "ALTER TABLE map_strike_line ADD COLUMN target_name TEXT;" +run "ALTER TABLE map_strike_line ADD COLUMN struck_at TEXT;" +echo " map_strike_line done" +run "ALTER TABLE map_strike_source ADD COLUMN name TEXT NOT NULL;" +# 本地列) +run "ALTER TABLE map_strike_source ADD COLUMN lng REAL NOT NULL;" +run "ALTER TABLE map_strike_source ADD COLUMN lat REAL NOT NULL;" +echo " map_strike_source done" +run "ALTER TABLE news_content ADD COLUMN content_hash TEXT NOT NULL;" +# 本地列) +run "ALTER TABLE news_content ADD COLUMN title TEXT NOT NULL;" +run "ALTER TABLE news_content ADD COLUMN summary TEXT NOT NULL;" +run 'ALTER TABLE news_content ADD COLUMN url TEXT NOT NULL DEFAULT '\'''\'';' +run 'ALTER TABLE news_content ADD COLUMN source TEXT NOT NULL DEFAULT '\'''\'';' +run "ALTER TABLE news_content ADD COLUMN published_at TEXT NOT NULL;" +run 'ALTER TABLE news_content ADD COLUMN category TEXT NOT NULL DEFAULT '\''other'\'';' +run 'ALTER TABLE news_content ADD COLUMN severity TEXT NOT NULL DEFAULT '\''medium'\'';' +run "ALTER TABLE news_content ADD COLUMN created_at TEXT NOT NULL;" +echo " news_content done" +run "ALTER TABLE power_index ADD COLUMN overall INTEGER NOT NULL;" +# 本地列) +run "ALTER TABLE power_index ADD COLUMN military_strength INTEGER NOT NULL;" +run "ALTER TABLE power_index ADD COLUMN economic_power INTEGER NOT NULL;" +run "ALTER TABLE power_index ADD COLUMN geopolitical_influence INTEGER NOT NULL;" +echo " power_index done" +run "ALTER TABLE retaliation_current ADD COLUMN value INTEGER NOT NULL;" +# 本地列) +echo " retaliation_current done" +run "ALTER TABLE retaliation_history ADD COLUMN time TEXT NOT NULL;" +# 本地列) +run "ALTER TABLE retaliation_history ADD COLUMN value INTEGER NOT NULL;" +echo " retaliation_history done" +run "ALTER TABLE share_count ADD COLUMN total INTEGER NOT NULL DEFAULT 0;" +# 本地列) +echo " share_count done" +run "ALTER TABLE situation ADD COLUMN data TEXT NOT NULL;" +# 本地列) +run "ALTER TABLE situation ADD COLUMN updated_at TEXT NOT NULL;" +echo " situation done" +run "ALTER TABLE situation_update ADD COLUMN timestamp TEXT NOT NULL;" +# 本地列) +run "ALTER TABLE situation_update ADD COLUMN category TEXT NOT NULL;" +run "ALTER TABLE situation_update ADD COLUMN summary TEXT NOT NULL;" +run "ALTER TABLE situation_update ADD COLUMN severity TEXT NOT NULL;" +echo " situation_update done" +run "ALTER TABLE visitor_count ADD COLUMN total INTEGER NOT NULL DEFAULT 0;" +# 本地列) +echo " visitor_count done" +run "ALTER TABLE visits ADD COLUMN last_seen TEXT NOT NULL;" +# 本地列) +echo " visits done" +run "ALTER TABLE wall_street_trend ADD COLUMN time TEXT NOT NULL;" +# 本地列) +run "ALTER TABLE wall_street_trend ADD COLUMN value INTEGER NOT NULL;" +echo " wall_street_trend done" + +echo "=== 完成。核对示例: ===" +echo " sqlite3 $DB_PATH \"PRAGMA table_info(key_location);\"" +echo " sqlite3 $DB_PATH \"PRAGMA table_info(combat_losses);\"" diff --git a/scripts/check-attack-locations.sh b/scripts/check-attack-locations.sh new file mode 100755 index 0000000..0f9714e --- /dev/null +++ b/scripts/check-attack-locations.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +# 检查攻击地点/打击线是否完整(与 seed.js 一致) +# 用法: DB_PATH=server/data.db ./scripts/check-attack-locations.sh +# 裸机: cd /root/usa && ./scripts/check-attack-locations.sh + +set -e +PROJECT_ROOT="${PROJECT_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}" +DB_PATH="${DB_PATH:-$PROJECT_ROOT/server/data.db}" + +echo "==========================================" +echo "攻击地点 / 打击线 检查" +echo "DB: $DB_PATH" +echo "==========================================" + +if [[ ! -f "$DB_PATH" ]]; then + echo "错误: 数据库文件不存在" + exit 1 +fi + +if ! command -v sqlite3 &>/dev/null; then + echo "需要 sqlite3。安装: yum install sqlite 或 apt install sqlite3" + exit 1 +fi + +# 期望数量(与 server/seed.js 一致) +EXPECT_US=62 # getUsLocations: naval + attacked + newBases +EXPECT_IRAN=18 # iranLocs 条数 +EXPECT_ISRAEL=4 +EXPECT_LINCOLN=5 +EXPECT_FORD=7 + +n_us=$(sqlite3 "$DB_PATH" "SELECT COUNT(*) FROM key_location WHERE side='us';" 2>/dev/null || echo "0") +n_iran=$(sqlite3 "$DB_PATH" "SELECT COUNT(*) FROM key_location WHERE side='iran';" 2>/dev/null || echo "0") +n_israel=$(sqlite3 "$DB_PATH" "SELECT COUNT(*) FROM map_strike_line WHERE source_id='israel';" 2>/dev/null || echo "0") +n_lincoln=$(sqlite3 "$DB_PATH" "SELECT COUNT(*) FROM map_strike_line WHERE source_id='lincoln';" 2>/dev/null || echo "0") +n_ford=$(sqlite3 "$DB_PATH" "SELECT COUNT(*) FROM map_strike_line WHERE source_id='ford';" 2>/dev/null || echo "0") + +echo "" +echo "key_location:" +echo " us (美军基地等): 当前 $n_us 条,期望 $EXPECT_US 条" +echo " iran (伊朗被袭点): 当前 $n_iran 条,期望 $EXPECT_IRAN 条" +echo "" +echo "map_strike_line (盟军打击伊朗):" +echo " israel: 当前 $n_israel 条,期望 $EXPECT_ISRAEL 条" +echo " lincoln: 当前 $n_lincoln 条,期望 $EXPECT_LINCOLN 条" +echo " ford: 当前 $n_ford 条,期望 $EXPECT_FORD 条" +echo "==========================================" + +ok=0 +[[ "$n_us" -ge "$EXPECT_US" ]] && [[ "$n_iran" -ge "$EXPECT_IRAN" ]] && \ +[[ "$n_israel" -ge "$EXPECT_ISRAEL" ]] && [[ "$n_lincoln" -ge "$EXPECT_LINCOLN" ]] && \ +[[ "$n_ford" -ge "$EXPECT_FORD" ]] && ok=1 + +if [[ $ok -eq 1 ]]; then + echo "结论: 攻击地点/打击线数量正常" + exit 0 +fi + +echo "结论: 数量不足,请在生产执行 seed 以与当前代码一致:" +echo " cd $PROJECT_ROOT" +echo " cp server/data.db server/data.db.bak-\$(date +%Y%m%d-%H%M%S)" +echo " DB_PATH=server/data.db node server/seed.js" +echo " 重启 API 后刷新页面" +exit 1 diff --git a/scripts/gen-align-schema-from-local.sh b/scripts/gen-align-schema-from-local.sh new file mode 100755 index 0000000..464d83a --- /dev/null +++ b/scripts/gen-align-schema-from-local.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +# 在本地执行:读取 server/data.db 各表 PRAGMA table_info,生成供生产执行的 align-production-schema.sh +# 用法:在项目根目录执行 ./scripts/gen-align-schema-from-local.sh +set -e +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +DB_PATH="${DB_PATH:-$PROJECT_ROOT/server/data.db}" +OUT_PATH="$PROJECT_ROOT/scripts/align-production-schema.sh" + +if [[ ! -f "$DB_PATH" ]]; then + echo "本地库不存在: $DB_PATH" + exit 1 +fi + +tables=$(sqlite3 "$DB_PATH" "SELECT name FROM sqlite_master WHERE type='table' AND name NOT IN ('sqlite_sequence') ORDER BY name;") + +cat > "$OUT_PATH" << 'HEAD' +#!/usr/bin/env bash +# 由 scripts/gen-align-schema-from-local.sh 根据本地 server/data.db 表结构生成,供生产执行。 +# 用法:在生产目录执行 DB_PATH=server/data.db ./scripts/align-production-schema.sh +set -e +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +DB_PATH="${DB_PATH:-$PROJECT_ROOT/server/data.db}" + +run() { sqlite3 "$DB_PATH" "$1" 2>/dev/null || true; } + +echo "=== 对齐生产库表结构(与本地 data.db 一致):$DB_PATH ===" +HEAD + +while IFS= read -r table; do + [[ -z "$table" ]] && continue + # 跳过 cid=0(首列,通常建表时已有) + first=1 + while IFS='|' read -r cid name type notnull dflt pk; do + [[ -z "$cid" || "$cid" -eq 0 ]] && continue + # 非常量默认值(如 datetime('now'))不写 DEFAULT,避免生产 SQLite 报错 + def="$type" + [[ "$notnull" == "1" ]] && def="$def NOT NULL" + if [[ -n "$dflt" && "$dflt" != *"("* ]]; then + # SQL 字面量:已知字符串默认值写死,避免 shell 转义问题 + case "$dflt" in + '"operational"') def="${def} DEFAULT 'operational'" ;; + '"other"') def="${def} DEFAULT 'other'" ;; + '"medium"') def="${def} DEFAULT 'medium'" ;; + "''") def="${def} DEFAULT ''" ;; + *) dflt_sql="${dflt//\"/\'}"; def="$def DEFAULT $dflt_sql" ;; + esac + fi + if [[ "$def" == *\'* ]]; then + # def 含单引号:用 run '...'\''...'\'' 形式写入 + safe_def=$(echo "$def" | sed "s/'/'\\\\''/g") + printf "run 'ALTER TABLE %s ADD COLUMN %s %s;'\n" "$table" "$name" "$safe_def" >> "$OUT_PATH" + else + printf 'run "ALTER TABLE %s ADD COLUMN %s %s;"\n' "$table" "$name" "$def" >> "$OUT_PATH" + fi + if [[ "$first" -eq 1 ]]; then + echo "# $table(本地列)" >> "$OUT_PATH" + first=0 + fi + if [[ "$table" == "combat_losses" && "$name" == "carriers" ]]; then + echo 'run "UPDATE combat_losses SET carriers = COALESCE(tanks, 0) WHERE carriers = 0;"' >> "$OUT_PATH" + fi + done < <(sqlite3 -separator '|' "$DB_PATH" "PRAGMA table_info($table);") + if [[ "$first" -eq 0 ]]; then + echo "echo \" $table done\"" >> "$OUT_PATH" + fi +done <<< "$tables" + +echo "" >> "$OUT_PATH" +echo "echo \"=== 完成。核对示例: ===\"" >> "$OUT_PATH" +echo "echo \" sqlite3 \$DB_PATH \\\"PRAGMA table_info(key_location);\\\"\"" >> "$OUT_PATH" +echo "echo \" sqlite3 \$DB_PATH \\\"PRAGMA table_info(combat_losses);\\\"\"" >> "$OUT_PATH" + +chmod +x "$OUT_PATH" +echo "已生成: $OUT_PATH" +echo "请将该文件推到生产后执行:DB_PATH=server/data.db ./scripts/align-production-schema.sh" diff --git a/scripts/test.sh b/scripts/test.sh new file mode 100644 index 0000000..2cd8fba --- /dev/null +++ b/scripts/test.sh @@ -0,0 +1,126 @@ +sqlite3 server/data.db " +UPDATE combat_losses + SET civilian_killed = 380, civilian_wounded = 1520 + WHERE side = 'us'; +UPDATE combat_losses + SET civilian_killed = 4120, civilian_wounded = 12030 + WHERE side = 'iran'; +" + +cd /root/usa +sqlite3 server/data.db " +UPDATE combat_losses + SET bases_destroyed = 15, + bases_damaged = 57, + personnel_killed = 327, + personnel_wounded = 984, + civilian_killed = 380, + civilian_wounded = 1520, + aircraft = 24, + warships = 1, + armor = 18, + vehicles = 42, + drones = 28, + missiles = 756, + helicopters = 8, + submarines = 2, + tanks = 0, + carriers = 0, + civilian_ships = 100, + airport_port = 5 + WHERE side = 'us'; + +UPDATE combat_losses + SET bases_destroyed = 2100, + bases_damaged = 8400, + personnel_killed = 2847, + personnel_wounded = 5620, + civilian_killed = 4120, + civilian_wounded = 12030, + aircraft = 240, + warships = 120, + armor = 18, + vehicles = 420, + drones = 28, + missiles = 4560, + helicopters = 20, + submarines = 2, + tanks = 50, + carriers = 0, + civilian_ships = 50, + airport_port = 42 + WHERE side = 'iran'; +" + +sqlite3 server/data.db " +UPDATE combat_losses + SET bases_destroyed = 15, + bases_damaged = 57, + personnel_killed = 327, + personnel_wounded = 984, + aircraft = 4, + warships = 0, + armor = 3, + vehicles = 76, + civilian_killed = 380, + civilian_wounded = 1520 + WHERE side = 'us'; + +UPDATE combat_losses + SET bases_destroyed = 2100, + bases_damaged = 8400, + personnel_killed = 2847, + personnel_wounded = 5620, + aircraft = 70, + warships = 120, + armor = 18, + vehicles = 420, + civilian_killed = 4120, + civilian_wounded = 12030 + WHERE side = 'iran'; +" + +cd /root/usa +sqlite3 server/data.db " +UPDATE combat_losses + SET bases_destroyed = 15, + bases_damaged = 57, + personnel_killed = 327, + personnel_wounded = 984, + civilian_killed = 380, + civilian_wounded = 1520, + aircraft = 4, + warships = 1, + armor = 18, + vehicles = 42, + drones = 68, + missiles = 1756, + helicopters = 8, + submarines = 0, + tanks = 0, + carriers = 0, + civilian_ships = 172, + airport_port = 7 + WHERE side = 'us'; + +UPDATE combat_losses + SET bases_destroyed = 2100, + bases_damaged = 8400, + personnel_killed = 2847, + personnel_wounded = 5620, + civilian_killed = 4120, + civilian_wounded = 12030, + aircraft = 106, + warships = 107, + armor = 72, + vehicles = 506, + drones = 1428, + missiles = 6620, + helicopters = 20, + submarines = 4, + tanks = 50, + carriers = 1, + civilian_ships = 42, + airport_port = 31 + WHERE side = 'iran'; +" \ No newline at end of file