steelforesight/panel/scripts/migrate-content.mjs

121 lines
11 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.

// ─────────────────────────────────────────────────────────────────────────────
// One-off content migration:
// 1) move every existing radar_item → articles(type='radarfuture') as a BLOCK
// article (رادار آینده), mapping its category to one of the 5 sub-menus.
// 2) clear radar_items, then seed it with the 10 «در یک نگاه» (/at-a-glance) cards.
//
// Safe to run once. If radarfuture articles already exist it assumes the
// migration ran and exits without doing anything.
//
// cd panel && node scripts/migrate-content.mjs
// ─────────────────────────────────────────────────────────────────────────────
import 'dotenv/config';
import { nanoid } from 'nanoid';
import { db } from '../db.js';
// radar_item.category → رادار آینده sub-menu
const CAT_TO_SUBMENU = {
market: 'بازار و زنجیره فولاد',
commodity: 'بازار و زنجیره فولاد',
tech: 'فناوری و نوآوری',
geo: 'ژئوپلیتیک و اقتصاد جهانی',
energy: 'پایداری و فولاد سبز',
};
// the 10 «در یک نگاه» cards (mirrors src/pages/AtAGlance/AtAGlance.tsx)
const GLANCE = [
{ cat:'market', img:'/news/photo-1504307651254-35680f356dfd.jpg', title:'شوک هیدروژنی به بازار جهانی فولاد',
body:['پروژه عظیم «فولاد سبز H2» در سوئد با جذب بی‌سابقه ۶.۵ میلیارد یورو سرمایه، رسماً وارد فاز اجرایی شد.','این تأسیسات با هدف کاهش ۹۵ درصدی انتشار CO₂، قواعد رقابت در زنجیره ارزش اروپا را برای همیشه بازتعریف می‌کند.'],
analysis:'تحول فولاد سبز، فرصت صادراتی ایران را در بازارهای سنتی تهدید می‌کند.', tags:['فولاد سبز','هیدروژن','اروپا'], source:'Financial Times', date:'۱۴ اردیبهشت ۱۴۰۵' },
{ cat:'market', img:'/news/photo-1581092160607-ee22731c9b4e.jpg', title:'CBAM اروپا وارد اجرای کامل شد',
body:['با اجرای کامل مکانیسم تنظیم مرزهای کربنی، صادرکنندگان فولاد به اروپا موظف به پرداخت هزینه کامل کربن شدند.','این تحول فشار بی‌سابقه‌ای بر تولیدکنندگان مبتنی بر کوره بلند وارد کرده است.'],
analysis:'ایران باید فوری‌ترین اولویت خود را کربن‌زدایی از فرآیند تولید قرار دهد.', tags:['CBAM','کربن','صادرات'], source:'Reuters', date:'۱۲ اردیبهشت ۱۴۰۵' },
{ cat:'tech', img:'/news/photo-1518770660439-4636190af475.jpg', title:'هوش مصنوعی تقاضای فولاد مراکز داده را بازتعریف می‌کند',
body:['موج ساخت مراکز داده هوش مصنوعی، تقاضای جدیدی برای مقاطع ساختمانی و فولاد ویژه ایجاد کرده است.','تحلیلگران پیش‌بینی می‌کنند این روند تا پایان دهه یکی از پیشران‌های اصلی رشد مصرف فولاد باشد.'],
analysis:'فولادسازان باید ظرفیت تولید مقاطع ساختمانی پیشرفته را افزایش دهند.', tags:['هوش مصنوعی','مراکز داده','تقاضا'], source:'Bloomberg', date:'۱۰ اردیبهشت ۱۴۰۵' },
{ cat:'tech', img:'/news/photo-1567789884554-0b844b597180.jpg', title:'اتوماسیون کوره‌های القایی در ایران',
body:['چندین کارخانه بزرگ فولاد ایران سرمایه‌گذاری در سیستم‌های کنترل هوشمند کوره را آغاز کرده‌اند.','این سیستم‌ها توانایی کاهش مصرف انرژی تا ۱۵ درصد را دارند.'],
analysis:'گام مثبتی است اما سرعت پیاده‌سازی باید افزایش یابد.', tags:['اتوماسیون','کوره','انرژی'], source:'فولاد نیوز', date:'۸ اردیبهشت ۱۴۰۵' },
{ cat:'geo', img:'/news/photo-1540575467063-178a50c2df87.jpg', title:'تنش‌های خاورمیانه و تجارت فولاد',
body:['ناآرامی‌های منطقه‌ای مسیرهای حمل‌ونقل دریایی را مختل کرده و هزینه‌های لجستیک را افزایش داده است.','صادرکنندگان ایرانی با چالش‌های اضافی در انتقال محصولات روبرو هستند.'],
analysis:'تنوع‌بخشی در مسیرهای صادراتی اکنون یک ضرورت استراتژیک است.', tags:['ژئوپلیتیک','حمل دریایی','صادرات'], source:'Al Jazeera', date:'۶ اردیبهشت ۱۴۰۵' },
{ cat:'geo', img:'/news/photo-1570168007204-dfb528c6958f.jpg', title:'رقابت چین و آمریکا بر سر فلزات استراتژیک',
body:['تنش‌های ژئوپلیتیک میان قدرت‌های بزرگ، زنجیره تأمین فلزات حیاتی را بی‌ثبات کرده است.','این رقابت فرصت‌هایی برای تأمین‌کنندگان جایگزین ایجاد می‌کند.'],
analysis:'ایران می‌تواند نقش تأمین‌کننده جایگزین برخی فلزات را ایفا کند.', tags:['چین','آمریکا','فلزات'], source:'Reuters', date:'۴ اردیبهشت ۱۴۰۵' },
{ cat:'energy', img:'/news/photo-1466611653911-95081537e5b7.jpg', title:'بحران گاز و صنعت فولاد ایران',
body:['کمبود گاز در فصل سرما چندین واحد فولادسازی را مجبور به تعلیق موقت تولید کرد.','این چالش ساختاری نیاز به سرمایه‌گذاری جدی در زیرساخت انرژی دارد.'],
analysis:'بدون تأمین پایدار انرژی، اهداف تولید فولاد محقق نمی‌شود.', tags:['گاز','انرژی','تولید'], source:'ایسنا', date:'۲ اردیبهشت ۱۴۰۵' },
{ cat:'energy', img:'/news/photo-1611273426858-450d8e3c9fce.jpg', title:'انرژی خورشیدی برای فولادسازی پایدار',
body:['پتانسیل عظیم انرژی خورشیدی ایران می‌تواند پایه‌ای برای فولادسازی کم‌کربن باشد.','اولین پروژه‌های آزمایشی ترکیب پنل خورشیدی با کوره‌های الکتریکی در حال بررسی است.'],
analysis:'سرمایه‌گذاری در این حوزه می‌تواند چند مشکل را هم‌زمان حل کند.', tags:['خورشیدی','فولاد سبز','EAF'], source:'PV Magazine', date:'۳۰ فروردین ۱۴۰۵' },
{ cat:'commodity', img:'/news/photo-1540575467063-178a50c2df87.jpg', title:'قیمت سنگ‌آهن در مسیر کاهش',
body:['کاهش تقاضای چین در بخش ساختمان قیمت سنگ‌آهن را به پایین‌ترین سطح دو سال گذشته رساند.','این کاهش برای تولیدکنندگان فولاد مبتنی بر کوره بلند مزیت هزینه‌ای ایجاد می‌کند.'],
analysis:'فرصتی برای افزایش ذخیره‌سازی سنگ‌آهن با قیمت پایین وجود دارد.', tags:['سنگ‌آهن','چین','قیمت'], source:'Bloomberg', date:'۲۸ فروردین ۱۴۰۵' },
{ cat:'commodity', img:'/news/photo-1504307651254-35680f356dfd.jpg', title:'نوسان قیمت زغال‌سنگ کک‌شو',
body:['محدودیت‌های صادرات استرالیا و بارندگی در مناطق استخراجی، قیمت زغال کک‌شو را نوسانی کرده است.','این بی‌ثباتی برنامه‌ریزی تولید را برای کارخانه‌های کوره بلند دشوار می‌کند.'],
analysis:'تنوع در منابع تأمین زغال‌سنگ یک اولویت استراتژیک است.', tags:['زغال‌سنگ','استرالیا','تولید'], source:'Metal Bulletin', date:'۲۶ فروردین ۱۴۰۵' },
];
const done = await db.prepare("SELECT COUNT(*)::int AS n FROM articles WHERE type = 'radarfuture'").get();
if (done.n > 0) {
console.log(`${done.n} radarfuture article(s) already exist — migration already ran, exiting.`);
process.exit(0);
}
// 1) radar_items → articles(radarfuture) as block articles
const radars = await db.prepare('SELECT * FROM radar_items ORDER BY sort_order, created_at').all();
let migrated = 0;
for (const r of radars) {
const blocks = [];
if (r.img) blocks.push({ type: 'image', url: r.img, caption: '' });
if (r.body_fa) blocks.push({ type: 'text', value: r.body_fa });
if (r.analysis_fa) blocks.push({ type: 'text', value: 'تحلیل راهبردی: ' + r.analysis_fa });
if (!blocks.length) blocks.push({ type: 'text', value: r.excerpt_fa || r.title_fa || '' });
const tags = r.tags ? JSON.parse(r.tags) : [];
const sources = r.source ? [{ title: r.source, url: '' }] : [];
await db.prepare(`INSERT INTO articles
(id,title,category,type,publish_date,summary,body,cover_image,blocks,sources,tags,featured)
VALUES (@id,@title,@category,'radarfuture',@publish_date,@summary,@body,@cover_image,@blocks,@sources,@tags,0)`)
.run({
id: nanoid(14),
title: r.title_fa || 'بدون عنوان',
category: CAT_TO_SUBMENU[r.category] || 'آینده‌پژوهی و رصد هوشمند',
publish_date: r.date_fa || null,
summary: r.excerpt_fa || null,
body: r.body_fa || null,
cover_image: r.img || null,
blocks: JSON.stringify(blocks),
sources: JSON.stringify(sources),
tags: JSON.stringify(tags),
});
migrated++;
}
console.log(`✓ migrated ${migrated} radar_item(s) → رادار آینده (articles/radarfuture)`);
// 2) clear radar_items, seed with the 10 «در یک نگاه» cards
await db.prepare('DELETE FROM radar_items').run();
let seeded = 0;
for (let i = 0; i < GLANCE.length; i++) {
const c = GLANCE[i];
await db.prepare(`INSERT INTO radar_items
(id,category,img,title_fa,date_fa,excerpt_fa,body_fa,analysis_fa,tags,source,sort_order)
VALUES (@id,@category,@img,@title_fa,@date_fa,@excerpt_fa,@body_fa,@analysis_fa,@tags,@source,@sort_order)`)
.run({
id: nanoid(14),
category: c.cat,
img: c.img,
title_fa: c.title,
date_fa: c.date,
excerpt_fa: c.body[0] || '',
body_fa: c.body.join('\n\n'),
analysis_fa: c.analysis,
tags: JSON.stringify(c.tags),
source: c.source,
sort_order: i,
});
seeded++;
}
console.log(`✓ seeded ${seeded} «در یک نگاه» card(s) → radar_items`);
console.log('🎉 migration complete.');
process.exit(0);