fix:增面
This commit is contained in:
140
scripts/check-crawler-data.cjs
Normal file
140
scripts/check-crawler-data.cjs
Normal file
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* 检查爬虫写入的数据:条数 + 最近内容(situation_update、news_content、gdelt_events)
|
||||
* 用法(项目根目录): node scripts/check-crawler-data.cjs
|
||||
* 可选:先启动爬虫 npm run gdelt,再启动 API 或直接运行本脚本读 DB
|
||||
*/
|
||||
const path = require('path')
|
||||
const http = require('http')
|
||||
|
||||
const projectRoot = path.resolve(__dirname, '..')
|
||||
process.chdir(projectRoot)
|
||||
|
||||
const db = require('../server/db')
|
||||
|
||||
const CRAWLER_URL = process.env.CRAWLER_URL || 'http://localhost:8000'
|
||||
const SHOW_ROWS = 10
|
||||
|
||||
function fetchCrawlerStatus() {
|
||||
return new Promise((resolve) => {
|
||||
const url = new URL(`${CRAWLER_URL}/crawler/status`)
|
||||
const req = http.request(
|
||||
{ hostname: url.hostname, port: url.port || 80, path: url.pathname, method: 'GET', timeout: 3000 },
|
||||
(res) => {
|
||||
let body = ''
|
||||
res.on('data', (c) => (body += c))
|
||||
res.on('end', () => {
|
||||
try {
|
||||
resolve(JSON.parse(body))
|
||||
} catch {
|
||||
resolve(null)
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
req.on('error', () => resolve(null))
|
||||
req.end()
|
||||
})
|
||||
}
|
||||
|
||||
async function run() {
|
||||
console.log('========================================')
|
||||
console.log('爬虫数据检查(条数 + 最近内容)')
|
||||
console.log('========================================\n')
|
||||
|
||||
// ---------- 爬虫服务状态(可选)----------
|
||||
const status = await fetchCrawlerStatus()
|
||||
if (status) {
|
||||
console.log('--- 爬虫服务状态 GET /crawler/status ---')
|
||||
console.log(' db_path:', status.db_path)
|
||||
console.log(' db_exists:', status.db_exists)
|
||||
console.log(' situation_update_count:', status.situation_update_count)
|
||||
console.log(' last_fetch_items:', status.last_fetch_items, '(本轮抓取条数)')
|
||||
console.log(' last_fetch_inserted:', status.last_fetch_inserted, '(去重后新增)')
|
||||
if (status.last_fetch_error) console.log(' last_fetch_error:', status.last_fetch_error)
|
||||
console.log('')
|
||||
} else {
|
||||
console.log('--- 爬虫服务 ---')
|
||||
console.log(' 未启动或不可达:', CRAWLER_URL)
|
||||
console.log('')
|
||||
}
|
||||
|
||||
// ---------- situation_update(事件脉络,看板「近期更新」)----------
|
||||
let situationUpdateRows = []
|
||||
let situationUpdateCount = 0
|
||||
try {
|
||||
situationUpdateCount = db.prepare('SELECT COUNT(*) as c FROM situation_update').get().c
|
||||
situationUpdateRows = db
|
||||
.prepare(
|
||||
'SELECT id, timestamp, category, summary, severity FROM situation_update ORDER BY timestamp DESC LIMIT ?'
|
||||
)
|
||||
.all(SHOW_ROWS)
|
||||
} catch (e) {
|
||||
console.log('situation_update 表读取失败:', e.message)
|
||||
}
|
||||
|
||||
console.log('--- situation_update(事件脉络)---')
|
||||
console.log(' 总条数:', situationUpdateCount)
|
||||
if (situationUpdateRows.length > 0) {
|
||||
console.log(' 最近', situationUpdateRows.length, '条:')
|
||||
situationUpdateRows.forEach((r, i) => {
|
||||
const summary = (r.summary || '').slice(0, 50)
|
||||
console.log(` ${i + 1}. [${r.timestamp}] ${r.category}/${r.severity} ${summary}${summary.length >= 50 ? '…' : ''}`)
|
||||
})
|
||||
}
|
||||
console.log('')
|
||||
|
||||
// ---------- news_content(资讯表,爬虫去重后写入)----------
|
||||
let newsCount = 0
|
||||
let newsRows = []
|
||||
try {
|
||||
newsCount = db.prepare('SELECT COUNT(*) as c FROM news_content').get().c
|
||||
newsRows = db
|
||||
.prepare(
|
||||
'SELECT title, summary, source, published_at, category, severity FROM news_content ORDER BY published_at DESC LIMIT ?'
|
||||
)
|
||||
.all(SHOW_ROWS)
|
||||
} catch (e) {
|
||||
console.log('news_content 表读取失败:', e.message)
|
||||
}
|
||||
|
||||
console.log('--- news_content(资讯表)---')
|
||||
console.log(' 总条数:', newsCount)
|
||||
if (newsRows.length > 0) {
|
||||
console.log(' 最近', newsRows.length, '条:')
|
||||
newsRows.forEach((r, i) => {
|
||||
const title = (r.title || '').slice(0, 45)
|
||||
console.log(` ${i + 1}. [${r.published_at || ''}] ${r.source || ''} ${title}${title.length >= 45 ? '…' : ''}`)
|
||||
if (r.summary) console.log(` summary: ${(r.summary || '').slice(0, 60)}…`)
|
||||
})
|
||||
}
|
||||
console.log('')
|
||||
|
||||
// ---------- gdelt_events(地图冲突点)----------
|
||||
let gdeltCount = 0
|
||||
let gdeltRows = []
|
||||
try {
|
||||
gdeltCount = db.prepare('SELECT COUNT(*) as c FROM gdelt_events').get().c
|
||||
gdeltRows = db
|
||||
.prepare('SELECT event_id, event_time, title, impact_score FROM gdelt_events ORDER BY event_time DESC LIMIT 5')
|
||||
.all()
|
||||
} catch (e) {
|
||||
console.log('gdelt_events 表读取失败:', e.message)
|
||||
}
|
||||
|
||||
console.log('--- gdelt_events(地图冲突点)---')
|
||||
console.log(' 总条数:', gdeltCount)
|
||||
if (gdeltRows.length > 0) {
|
||||
console.log(' 最近 5 条:')
|
||||
gdeltRows.forEach((r, i) => {
|
||||
const title = (r.title || '').slice(0, 50)
|
||||
console.log(` ${i + 1}. [${r.event_time}] impact=${r.impact_score} ${title}${title.length >= 50 ? '…' : ''}`)
|
||||
})
|
||||
}
|
||||
console.log('========================================')
|
||||
}
|
||||
|
||||
db.initDb().then(() => run()).catch((err) => {
|
||||
console.error('失败:', err.message)
|
||||
process.exit(1)
|
||||
})
|
||||
78
scripts/debug-panels-focus.sh
Executable file
78
scripts/debug-panels-focus.sh
Executable file
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env bash
|
||||
# 仅检查:战损、基地、地图战区 三块数据
|
||||
# 用法: ./scripts/debug-panels-focus.sh
|
||||
|
||||
set -e
|
||||
API_URL="${API_URL:-http://localhost:3001}"
|
||||
PROJECT_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
DB_PATH="${DB_PATH:-$PROJECT_ROOT/server/data.db}"
|
||||
|
||||
echo "=========================================="
|
||||
echo "战损 / 基地 / 地图战区 — 数据检查"
|
||||
echo "API: $API_URL | DB: $DB_PATH"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
|
||||
# ---------- API 连通 ----------
|
||||
if ! curl -sf "$API_URL/api/health" >/dev/null 2>&1; then
|
||||
echo "✗ API 无响应,请先运行: npm run api"
|
||||
exit 1
|
||||
fi
|
||||
echo "✓ API 正常"
|
||||
echo ""
|
||||
|
||||
SIT=$(curl -sf "$API_URL/api/situation" 2>/dev/null || echo "{}")
|
||||
|
||||
# ---------- 1. 战损 ----------
|
||||
echo "[1] 战损 (combat_losses)"
|
||||
if command -v jq &>/dev/null; then
|
||||
us_k=$(echo "$SIT" | jq -r '.usForces.combatLosses.personnelCasualties.killed // "?"')
|
||||
us_w=$(echo "$SIT" | jq -r '.usForces.combatLosses.personnelCasualties.wounded // "?"')
|
||||
ir_k=$(echo "$SIT" | jq -r '.iranForces.combatLosses.personnelCasualties.killed // "?"')
|
||||
ir_w=$(echo "$SIT" | jq -r '.iranForces.combatLosses.personnelCasualties.wounded // "?"')
|
||||
echo " 美军 阵亡=$us_k 受伤=$us_w | 伊朗 阵亡=$ir_k 受伤=$ir_w"
|
||||
echo " conflictStats: $(echo "$SIT" | jq -c '.conflictStats')"
|
||||
else
|
||||
echo " (安装 jq 可显示详细数字)"
|
||||
fi
|
||||
if [[ -f "$DB_PATH" ]] && command -v sqlite3 &>/dev/null; then
|
||||
echo " 表 combat_losses:"
|
||||
sqlite3 "$DB_PATH" "SELECT side, personnel_killed, personnel_wounded, bases_destroyed, bases_damaged FROM combat_losses" 2>/dev/null | while read -r line; do echo " $line"; done
|
||||
fi
|
||||
echo " 数据来源: seed 初始;爬虫从新闻提取 combat_losses_delta 后 db_merge 增量叠加。不更新→检查是否跑 gdelt、提取器是否输出、新闻是否含伤亡数字。"
|
||||
echo ""
|
||||
|
||||
# ---------- 2. 基地 ----------
|
||||
echo "[2] 基地 (key_location)"
|
||||
if command -v jq &>/dev/null; then
|
||||
us_loc=$(echo "$SIT" | jq -r '.usForces.keyLocations | length')
|
||||
ir_loc=$(echo "$SIT" | jq -r '.iranForces.keyLocations | length')
|
||||
us_attacked=$(echo "$SIT" | jq -r '[.usForces.keyLocations[] | select(.status == "attacked")] | length')
|
||||
ir_attacked=$(echo "$SIT" | jq -r '[.iranForces.keyLocations[] | select(.status == "attacked")] | length')
|
||||
echo " 美军 据点=$us_loc 遭袭=$us_attacked | 伊朗 据点=$ir_loc 遭袭=$ir_attacked"
|
||||
fi
|
||||
if [[ -f "$DB_PATH" ]] && command -v sqlite3 &>/dev/null; then
|
||||
echo " 表 key_location 遭袭/有损伤的:"
|
||||
sqlite3 "$DB_PATH" "SELECT side, name, status, damage_level FROM key_location WHERE status != 'operational' OR damage_level IS NOT NULL LIMIT 10" 2>/dev/null | while read -r line; do echo " $line"; done
|
||||
fi
|
||||
echo " 数据来源: seed 写入全部据点;爬虫只更新 status/damage_level,需 name_keywords 与 name LIKE 匹配。不更新→检查新闻是否提基地遭袭、关键词与 seed name 是否一致。"
|
||||
echo ""
|
||||
|
||||
# ---------- 3. 地图战区 ----------
|
||||
echo "[3] 地图战区 (gdelt_events + conflict_stats)"
|
||||
if command -v jq &>/dev/null; then
|
||||
ev_cnt=$(echo "$SIT" | jq -r '.conflictEvents | length')
|
||||
echo " conflictEvents 条数: $ev_cnt"
|
||||
echo " conflictStats: $(echo "$SIT" | jq -c '.conflictStats')"
|
||||
fi
|
||||
if [[ -f "$DB_PATH" ]] && command -v sqlite3 &>/dev/null; then
|
||||
n_ev=$(sqlite3 "$DB_PATH" "SELECT COUNT(*) FROM gdelt_events" 2>/dev/null || echo "0")
|
||||
echo " 表 gdelt_events 行数: $n_ev"
|
||||
sqlite3 "$DB_PATH" "SELECT total_events, high_impact_events, estimated_casualties, estimated_strike_count FROM conflict_stats WHERE id = 1" 2>/dev/null | while read -r line; do echo " conflict_stats: $line"; done
|
||||
fi
|
||||
echo " 数据来源: GDELT API 写入;或 GDELT_DISABLED=1 时由 situation_update 回填。无点→跑 gdelt 或开启 RSS 回填。"
|
||||
echo ""
|
||||
|
||||
echo "=========================================="
|
||||
echo "详细说明与排查顺序见: docs/DEBUG_战损_基地_地图.md"
|
||||
echo "=========================================="
|
||||
83
scripts/debug-panels.sh
Executable file
83
scripts/debug-panels.sh
Executable file
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env bash
|
||||
# 看板板块数据快速检查:各表/API 与板块对应关系,便于逐项 debug
|
||||
# 用法: ./scripts/debug-panels.sh
|
||||
# 依赖: curl;可选 jq、sqlite3 以输出更清晰
|
||||
|
||||
set -e
|
||||
API_URL="${API_URL:-http://localhost:3001}"
|
||||
PROJECT_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
DB_PATH="${DB_PATH:-$PROJECT_ROOT/server/data.db}"
|
||||
|
||||
echo "=========================================="
|
||||
echo "看板板块数据检查 (DEBUG_PANELS)"
|
||||
echo "API: $API_URL | DB: $DB_PATH"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
|
||||
# ---------- 1. API 健康与态势摘要 ----------
|
||||
echo "[1] API 与态势摘要"
|
||||
if ! curl -sf "$API_URL/api/health" >/dev/null 2>&1; then
|
||||
echo " ✗ API 无响应,请先运行: npm run api"
|
||||
echo " 后续表检查将跳过(依赖 API 或直接读 DB)"
|
||||
else
|
||||
echo " ✓ API 正常"
|
||||
SIT=$(curl -sf "$API_URL/api/situation" 2>/dev/null || echo "{}")
|
||||
if command -v jq &>/dev/null; then
|
||||
echo " lastUpdated: $(echo "$SIT" | jq -r '.lastUpdated // "?"')"
|
||||
echo " recentUpdates: $(echo "$SIT" | jq -r '.recentUpdates | length') 条 → 事件脉络"
|
||||
echo " conflictEvents: $(echo "$SIT" | jq -r '.conflictEvents | length') 条 → 地图冲突点"
|
||||
echo " us powerIndex: $(echo "$SIT" | jq -r '.usForces.powerIndex.overall') → 顶栏/战力图"
|
||||
echo " iran powerIndex: $(echo "$SIT" | jq -r '.iranForces.powerIndex.overall')"
|
||||
echo " us keyLocations: $(echo "$SIT" | jq -r '.usForces.keyLocations | length') 条 → 美国基地/地图"
|
||||
echo " iran keyLocations: $(echo "$SIT" | jq -r '.iranForces.keyLocations | length') 条 → 伊朗基地/地图"
|
||||
echo " us combatLosses: killed=$(echo "$SIT" | jq -r '.usForces.combatLosses.personnelCasualties.killed') wounded=$(echo "$SIT" | jq -r '.usForces.combatLosses.personnelCasualties.wounded')"
|
||||
echo " wallStreet points: $(echo "$SIT" | jq -r '.usForces.wallStreetInvestmentTrend | length') → 华尔街图"
|
||||
echo " retaliation: $(echo "$SIT" | jq -r '.iranForces.retaliationSentiment') (history: $(echo "$SIT" | jq -r '.iranForces.retaliationSentimentHistory | length') 条)"
|
||||
else
|
||||
echo " (安装 jq 可显示详细字段) 态势已拉取,长度: ${#SIT}"
|
||||
fi
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# ---------- 2. 各表行数(直接读 DB)----------
|
||||
echo "[2] 数据库表行数(与板块对应)"
|
||||
if ! [[ -f "$DB_PATH" ]]; then
|
||||
echo " ✗ 数据库文件不存在: $DB_PATH"
|
||||
echo " 请先 seed: node server/seed.js 或 启动 API 后由 initDb 创建"
|
||||
elif ! command -v sqlite3 &>/dev/null; then
|
||||
echo " (未安装 sqlite3,跳过表统计。可安装后重试)"
|
||||
else
|
||||
TABLES="force_summary power_index force_asset key_location combat_losses wall_street_trend retaliation_current retaliation_history situation_update situation gdelt_events conflict_stats news_content"
|
||||
for t in $TABLES; do
|
||||
n=$(sqlite3 "$DB_PATH" "SELECT COUNT(*) FROM $t" 2>/dev/null || echo "?")
|
||||
case "$t" in
|
||||
force_summary) desc="力量摘要(美/伊)" ;;
|
||||
power_index) desc="战力指数 → 顶栏/战力图" ;;
|
||||
force_asset) desc="资产列表 → 左右侧摘要" ;;
|
||||
key_location) desc="据点 → 地图/美伊基地面板" ;;
|
||||
combat_losses) desc="战损 → 战损面板" ;;
|
||||
wall_street_trend) desc="华尔街趋势图" ;;
|
||||
retaliation_current) desc="报复当前值" ;;
|
||||
retaliation_history) desc="报复历史 → 仪表盘" ;;
|
||||
situation_update) desc="事件脉络 → 时间线" ;;
|
||||
situation) desc="updated_at → 顶栏时间" ;;
|
||||
gdelt_events) desc="冲突点 → 地图图层" ;;
|
||||
conflict_stats) desc="冲突统计 → 战损区" ;;
|
||||
news_content) desc="资讯表 → /api/news" ;;
|
||||
*) desc="" ;;
|
||||
esac
|
||||
printf " %-22s %6s %s\n" "$t" "$n" "$desc"
|
||||
done
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# ---------- 3. 板块健康简要判断 ----------
|
||||
echo "[3] 板块数据来源与可能问题"
|
||||
echo " • 仅 seed、爬虫不写: force_summary, power_index, force_asset"
|
||||
echo " • 爬虫可更新: situation_update(事件脉络), key_location(基地状态), combat_losses(战损), retaliation_*, wall_street_trend, gdelt_events"
|
||||
echo " • 事件脉络不更新 → 检查爬虫是否启动、是否调用 POST /api/crawler/notify"
|
||||
echo " • 战损/基地不更新 → 检查是否跑 npm run gdelt、提取器是否输出、新闻是否含相关表述"
|
||||
echo " • 地图无冲突点 → 检查 gdelt_events 是否有数据、GDELT 或 RSS 回填是否执行"
|
||||
echo ""
|
||||
echo "详细逐板块说明见: docs/DEBUG_PANELS.md"
|
||||
echo "=========================================="
|
||||
17
scripts/run-crawler-range.sh
Executable file
17
scripts/run-crawler-range.sh
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
# 按时间范围跑一轮爬虫(RSS:仅保留指定起始时间之后的条目)
|
||||
# 用法:
|
||||
# ./scripts/run-crawler-range.sh # 默认从 2026-02-28 0:00 到现在
|
||||
# ./scripts/run-crawler-range.sh 2026-02-25T00:00:00
|
||||
#
|
||||
# GDELT 时间范围需在启动 gdelt 服务时设置,例如:
|
||||
# GDELT_TIMESPAN=3d npm run gdelt
|
||||
|
||||
set -e
|
||||
START="${1:-2026-02-28T00:00:00}"
|
||||
cd "$(dirname "$0")/.."
|
||||
echo "RSS 抓取时间范围: 仅保留 ${START} 之后"
|
||||
echo "运行: cd crawler && CRAWL_START_DATE=${START} python run_once.py"
|
||||
echo ""
|
||||
export CRAWL_START_DATE="$START"
|
||||
(cd crawler && python3 run_once.py)
|
||||
81
scripts/verify-panels.cjs
Normal file
81
scripts/verify-panels.cjs
Normal file
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* 代码层执行看板验证:直接调用 getSituation() 与 DB,输出战损 / 基地 / 地图战区 结果。
|
||||
* 用法(项目根目录): node scripts/verify-panels.cjs
|
||||
*/
|
||||
const path = require('path')
|
||||
|
||||
const projectRoot = path.resolve(__dirname, '..')
|
||||
process.chdir(projectRoot)
|
||||
|
||||
const db = require('../server/db')
|
||||
const { getSituation } = require('../server/situationData')
|
||||
|
||||
function run() {
|
||||
const s = getSituation()
|
||||
|
||||
console.log('========================================')
|
||||
console.log('看板数据验证(与 API getSituation 一致)')
|
||||
console.log('========================================\n')
|
||||
|
||||
console.log('lastUpdated:', s.lastUpdated)
|
||||
console.log('')
|
||||
|
||||
// ---------- 1. 战损 ----------
|
||||
console.log('--- [1] 战损 combat_losses ---')
|
||||
const us = s.usForces.combatLosses
|
||||
const ir = s.iranForces.combatLosses
|
||||
console.log('美军 阵亡:', us.personnelCasualties.killed, '受伤:', us.personnelCasualties.wounded)
|
||||
console.log('美军 基地毁/损:', us.bases.destroyed, '/', us.bases.damaged)
|
||||
console.log('美军 战机/舰艇/装甲/车辆:', us.aircraft, us.warships, us.armor, us.vehicles)
|
||||
console.log('伊朗 阵亡:', ir.personnelCasualties.killed, '受伤:', ir.personnelCasualties.wounded)
|
||||
console.log('伊朗 基地毁/损:', ir.bases.destroyed, '/', ir.bases.damaged)
|
||||
console.log('平民合计 killed/wounded:', s.civilianCasualtiesTotal.killed, s.civilianCasualtiesTotal.wounded)
|
||||
console.log('conflictStats:', JSON.stringify(s.conflictStats))
|
||||
console.log('')
|
||||
|
||||
// ---------- 2. 基地(与看板口径一致:美军仅 type===Base,伊朗为 Base/Port/Nuclear/Missile)----------
|
||||
console.log('--- [2] 基地 key_location ---')
|
||||
const usLoc = s.usForces.keyLocations || []
|
||||
const irLoc = s.iranForces.keyLocations || []
|
||||
const usBases = usLoc.filter((l) => l.type === 'Base')
|
||||
const irBases = irLoc.filter((l) => ['Base', 'Port', 'Nuclear', 'Missile'].includes(l.type))
|
||||
const usAttacked = usBases.filter((l) => l.status === 'attacked')
|
||||
const irAttacked = irBases.filter((l) => l.status === 'attacked')
|
||||
console.log('美军 总基地数(仅Base):', usBases.length, '| 遭袭:', usAttacked.length, '(与看板「美军基地态势」一致)')
|
||||
console.log('伊朗 总基地数(Base/Port/Nuclear/Missile):', irBases.length, '| 遭袭:', irAttacked.length, '(与看板「伊朗基地态势」一致)')
|
||||
if (usAttacked.length > 0) {
|
||||
console.log('美军遭袭示例:', usAttacked.slice(0, 3).map((l) => `${l.name}(${l.status},damage=${l.damage_level})`).join(', '))
|
||||
}
|
||||
if (irAttacked.length > 0) {
|
||||
console.log('伊朗遭袭示例:', irAttacked.slice(0, 3).map((l) => `${l.name}(${l.status},damage=${l.damage_level})`).join(', '))
|
||||
}
|
||||
console.log('')
|
||||
|
||||
// ---------- 3. 地图战区 ----------
|
||||
console.log('--- [3] 地图战区 gdelt_events + conflict_stats ---')
|
||||
const events = s.conflictEvents || []
|
||||
console.log('conflictEvents 条数:', events.length)
|
||||
console.log('conflictStats:', JSON.stringify(s.conflictStats))
|
||||
if (events.length > 0) {
|
||||
console.log('最近 3 条:', events.slice(0, 3).map((e) => `${e.event_time} ${(e.title || '').slice(0, 40)} impact=${e.impact_score}`))
|
||||
}
|
||||
console.log('')
|
||||
|
||||
// ---------- 附加:事件脉络 ----------
|
||||
const updates = s.recentUpdates || []
|
||||
console.log('--- [附] 事件脉络 situation_update ---')
|
||||
console.log('recentUpdates 条数:', updates.length)
|
||||
if (updates.length > 0) {
|
||||
console.log('最新 1 条:', updates[0].timestamp, (updates[0].summary || '').slice(0, 50))
|
||||
}
|
||||
console.log('========================================')
|
||||
}
|
||||
|
||||
db
|
||||
.initDb()
|
||||
.then(() => run())
|
||||
.catch((err) => {
|
||||
console.error('验证失败:', err.message)
|
||||
process.exit(1)
|
||||
})
|
||||
Reference in New Issue
Block a user