136 lines
8.3 KiB
JavaScript
136 lines
8.3 KiB
JavaScript
const pptxgen = require("pptxgenjs");
|
||
const fs = require("fs");
|
||
|
||
const pres = new pptxgen();
|
||
pres.layout = "LAYOUT_16x9";
|
||
pres.title = "Star Cloud Demo Day - Technical Edition";
|
||
pres.author = "許家偉";
|
||
|
||
// --- Theme Colors ---
|
||
const COLORS = {
|
||
bg: "0F172A",
|
||
cardBg: "1E293B",
|
||
highlight: "2DD4BF",
|
||
secondary: "7DD3FC",
|
||
text: "FFFFFF",
|
||
muted: "94A3B8"
|
||
};
|
||
|
||
const FONTS = {
|
||
header: "Georgia",
|
||
body: "Calibri"
|
||
};
|
||
|
||
const makeShadow = (opacity = 0.2) => ({
|
||
type: "outer",
|
||
blur: 8,
|
||
offset: 3,
|
||
angle: 135,
|
||
color: "000000",
|
||
opacity: opacity
|
||
});
|
||
|
||
// --- Slide 1: Title ---
|
||
const slide1 = pres.addSlide();
|
||
slide1.background = { color: COLORS.bg };
|
||
slide1.addShape(pres.shapes.RECTANGLE, { x: 0, y: 0, w: 0.15, h: "100%", fill: { color: COLORS.highlight } });
|
||
slide1.addText("Star Cloud Demo Day", { x: 1.0, y: 1.8, w: 8, h: 1, fontSize: 48, fontFace: FONTS.header, color: COLORS.text, bold: true, margin: 0 });
|
||
slide1.addText("2026-03-25 ~ 2026-03-31 成果發表", { x: 1.0, y: 2.8, w: 8, h: 0.5, fontSize: 24, fontFace: FONTS.body, color: COLORS.secondary, italic: true });
|
||
slide1.addShape(pres.shapes.RECTANGLE, { x: 7.5, y: 4.5, w: 2, h: 0.6, fill: { color: COLORS.highlight, transparency: 10 }, shadow: makeShadow() });
|
||
slide1.addText("演講者:許家偉", { x: 7.5, y: 4.5, w: 2, h: 0.6, fontSize: 14, fontFace: FONTS.body, color: COLORS.text, align: "center", valign: "middle", bold: true });
|
||
|
||
// --- Slide 2: Overview ---
|
||
const slide2 = pres.addSlide();
|
||
slide2.background = { color: COLORS.bg };
|
||
slide2.addText("本週進度總覽 / Overview", { x: 0.5, y: 0.4, w: 9, h: 0.6, fontSize: 32, fontFace: FONTS.header, color: COLORS.highlight, bold: true });
|
||
slide2.addShape(pres.shapes.LINE, { x: 2, y: 3, w: 6, h: 0, line: { color: COLORS.highlight, width: 4 } });
|
||
const timelineItems = [
|
||
{ title: "機台權限管理", desc: "模組獨立化與效能優化" },
|
||
{ title: "商品管理整合", desc: "狀態整合與多語系修復" },
|
||
{ title: "廣告隔離機制", desc: "多租戶素材歸屬強化" }
|
||
];
|
||
timelineItems.forEach((item, idx) => {
|
||
const x = 2 + (idx * 3);
|
||
slide2.addShape(pres.shapes.OVAL, { x: x - 0.2, y: 2.8, w: 0.4, h: 0.4, fill: { color: COLORS.secondary }, line: { color: COLORS.text, width: 2 } });
|
||
slide2.addText(item.title, { x: x - 1, y: 3.3, w: 2, h: 0.4, fontSize: 18, fontFace: FONTS.header, color: COLORS.text, align: "center", bold: true });
|
||
slide2.addText(item.desc, { x: x - 1, y: 3.7, w: 2, h: 0.6, fontSize: 12, fontFace: FONTS.body, color: COLORS.muted, align: "center" });
|
||
});
|
||
|
||
// --- Slide 3: Highlight 1 - Machine Permissions (WITH EAGER LOADING) ---
|
||
const slide3 = pres.addSlide();
|
||
slide3.background = { color: COLORS.bg };
|
||
slide3.addText("亮點一:機台權限管理獨立化", { x: 0.5, y: 0.4, w: 9, h: 0.6, fontSize: 28, fontFace: FONTS.header, color: COLORS.highlight, bold: true });
|
||
|
||
const features = [
|
||
{ title: "直覺檢索", text: "管理員可快速檢索、分配所屬帳號對應的機台清單。" },
|
||
{ title: "即時過濾", text: "透過 Alpine.js 實作,輸入關鍵字即動態無刷新過濾。" },
|
||
{ title: "效能關鍵:Eager Loading", text: "使用 with('machines') 解決 N+1 問題,萬筆資料秒開。" }
|
||
];
|
||
|
||
features.forEach((f, idx) => {
|
||
const y = 1.2 + (idx * 1.3);
|
||
slide3.addShape(pres.shapes.RECTANGLE, { x: 0.5, y: y, w: 4, h: 1.1, fill: { color: COLORS.cardBg }, line: { color: COLORS.secondary, width: 1 }, shadow: makeShadow() });
|
||
slide3.addText(f.title, { x: 0.7, y: y + 0.1, w: 3.5, h: 0.3, fontSize: 16, fontFace: FONTS.header, color: COLORS.highlight, bold: true });
|
||
slide3.addText(f.text, { x: 0.7, y: y + 0.45, w: 3.5, h: 0.5, fontSize: 12, fontFace: FONTS.body, color: COLORS.text });
|
||
});
|
||
|
||
slide3.addImage({
|
||
path: "/home/mama/.gemini/antigravity/brain/58a170d0-7144-4e9f-9396-3e753a0bf69a/machine_permissions_table_1774944648298.png",
|
||
x: 4.8, y: 1.2, w: 4.8, h: 3.7, sizing: { type: 'contain' }, shadow: makeShadow(0.3)
|
||
});
|
||
|
||
// --- Slide 4: Highlight 2 ---
|
||
const slide4 = pres.addSlide();
|
||
slide4.background = { color: COLORS.bg };
|
||
slide4.addText("亮點二:商品管理整合與 UX 完善", { x: 0.5, y: 0.4, w: 9, h: 0.6, fontSize: 28, fontFace: FONTS.header, color: COLORS.highlight, bold: true });
|
||
const comparison = [
|
||
{ title: "功能整合 (Integrated)", items: ["• 「商品狀態」納入主流程", "• 減少跳轉,提升管理效率"] },
|
||
{ title: "細節優化 (Enhanced)", items: ["• 修復多語系(ZH/EN/JA)存取故障", "• 密碼欄位新增顯隱切換按鈕"] }
|
||
];
|
||
comparison.forEach((c, idx) => {
|
||
const x = 0.5 + (idx * 4.75);
|
||
slide4.addShape(pres.shapes.RECTANGLE, { x: x, y: 1.2, w: 4.25, h: 3.5, fill: { color: COLORS.cardBg }, line: { color: COLORS.highlight, width: 2 }, shadow: makeShadow(0.2) });
|
||
slide4.addText(c.title, { x: x + 0.2, y: 1.4, w: 3.8, h: 0.4, fontSize: 18, fontFace: FONTS.header, color: COLORS.highlight, bold: true, align: "center" });
|
||
slide4.addText(c.items.map(i => ({ text: i, options: { breakLine: true, bullet: true } })), { x: x + 0.3, y: 2.0, w: 3.6, h: 2.5, fontSize: 14, fontFace: FONTS.body, color: COLORS.text, margin: 0 });
|
||
});
|
||
|
||
// --- Slide 5: Highlight 3 ---
|
||
const slide5 = pres.addSlide();
|
||
slide5.background = { color: COLORS.bg };
|
||
slide5.addText("亮點三:多租戶廣告素材隔離機制", { x: 1.0, y: 0.4, w: 8, h: 1, fontSize: 32, fontFace: FONTS.header, color: COLORS.highlight, bold: true, align: "center" });
|
||
slide5.addShape(pres.shapes.OVAL, { x: 4.25, y: 2.0, w: 1.5, h: 1.5, fill: { color: COLORS.highlight, transparency: 30 }, line: { color: COLORS.secondary, width: 2 } });
|
||
slide5.addText("安全性隔離\n(Shield)", { x: 4.25, y: 2.5, w: 1.5, h: 0.5, fontSize: 14, fontFace: FONTS.header, color: COLORS.text, align: "center", bold: true });
|
||
const isolations = [
|
||
{ x: 1, y: 1.8, label: "公司 A\n廣告素材", color: "A8DADC" },
|
||
{ x: 7.5, y: 1.8, label: "公司 B\n廣告素材", color: "A8DADC" },
|
||
{ x: 1, y: 3.8, label: "公司 C\n廣告素材", color: "A8DADC" },
|
||
{ x: 7.5, y: 3.8, label: "公司 D\n廣告素材", color: "A8DADC" }
|
||
];
|
||
isolations.forEach(i => {
|
||
slide5.addShape(pres.shapes.ROUNDED_RECTANGLE, { x: i.x, y: i.y, w: 1.5, h: 0.8, fill: { color: COLORS.cardBg }, line: { color: COLORS.secondary, width: 1 }, rectRadius: 0.1 });
|
||
slide5.addText(i.label, { x: i.x, y: i.y, w: 1.5, h: 0.8, fontSize: 12, fontFace: FONTS.body, color: COLORS.text, align: "center", valign: "middle" });
|
||
slide5.addShape(pres.shapes.LINE, { x: i.x + (i.x < 5 ? 1.5 : 0), y: i.y + 0.4, w: i.x < 5 ? (4.25 - (i.x + 1.5)) : (7.5 - (i.x + 1.5)), h: 2.75 - (i.y + 0.4), line: { color: COLORS.secondary, width: 1, dashType: "dash" } });
|
||
});
|
||
slide5.addText("嚴格驗證 company_id,確保素材 100% 歸屬隔離。", { x: 0.5, y: 5.0, w: 9, h: 0.4, fontSize: 14, fontFace: FONTS.body, color: COLORS.muted, align: "center", italic: true });
|
||
|
||
// --- Slide 6: Future Roadmap ---
|
||
const slide6 = pres.addSlide();
|
||
slide6.background = { color: COLORS.bg };
|
||
slide6.addText("未來計畫 / Roadmap", { x: 0.5, y: 0.4, w: 9, h: 1, fontSize: 36, fontFace: FONTS.header, color: COLORS.highlight, bold: true, align: "center" });
|
||
const roadmap = [
|
||
{ icon: "Optim", title: "操作優化", text: "針對樂樂反饋優化操作流程與介面體驗。" },
|
||
{ icon: "Sync", title: "API 對接", text: "與 Terry 配合,實現機台通訊穩定與對接。" },
|
||
{ icon: "Remote", title: "遠端管理", text: "實作遠端控制與異常即時監控監管。" }
|
||
];
|
||
roadmap.forEach((r, idx) => {
|
||
const x = 0.5 + (idx * 3.1);
|
||
slide6.addShape(pres.shapes.RECTANGLE, { x: x, y: 2.0, w: 2.8, h: 2.5, fill: { color: COLORS.highlight, transparency: 85 }, line: { color: COLORS.highlight, width: 2 }, shadow: makeShadow() });
|
||
slide6.addText(r.title, { x: x, y: 2.3, w: 2.8, h: 0.5, fontSize: 20, fontFace: FONTS.header, color: COLORS.highlight, bold: true, align: "center" });
|
||
slide6.addText(r.text, { x: x + 0.2, y: 3.0, w: 2.4, h: 1.2, fontSize: 14, fontFace: FONTS.body, color: COLORS.text, align: "center" });
|
||
});
|
||
slide6.addText("Star Cloud 將持續進化,打造最領先的智能雲端平台。🚀", { x: 0.5, y: 5.0, w: 9, h: 0.4, fontSize: 14, fontFace: FONTS.body, color: COLORS.secondary, align: "center", bold: true });
|
||
|
||
pres.writeFile({ fileName: "star-cloud-demo-20260331.pptx" })
|
||
.then(fileName => console.log(`Presentation created: ${fileName}`))
|
||
.catch(err => { console.error("Error creating presentation:", err); process.exit(1); });
|