From d29843231cd8974690af6fb72e30478bac84d790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=B8=88?= Date: Tue, 9 Jun 2026 02:21:40 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20PPTX=20v2=20-=20=E5=8E=9F=E7=94=9F?= =?UTF-8?q?=E9=A5=BC=E5=9B=BE+=E4=B8=89=E8=89=B2=E5=8D=A1=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3+=E9=97=B4=E8=B7=9D=E9=87=8D=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cleaned/危大方案编审进度看板.pptx | Bin 33665 -> 46160 bytes src/gen_pptx.py | 342 +++++++++--------- 2 files changed, 173 insertions(+), 169 deletions(-) diff --git a/data/2026-06-08/cleaned/危大方案编审进度看板.pptx b/data/2026-06-08/cleaned/危大方案编审进度看板.pptx index c5a6ecbdb81267ed5059c57036537087ac86808c..6f1627798ff986dfbc4751c10042f3cf02d9f83f 100644 GIT binary patch delta 19960 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 T)ENe|gx(5JLAO=sCB6RutBhZ> delta 7291 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 diff --git a/src/gen_pptx.py b/src/gen_pptx.py index 79ff277..0d8d356 100644 --- a/src/gen_pptx.py +++ b/src/gen_pptx.py @@ -1,216 +1,220 @@ #!/usr/bin/env python3 -"""HTML看板 → 可编辑PPTX (python-pptx) · CHEC规范 16:9""" +"""HTML看板 → 可编辑PPTX v2 · 加饼图·修正三色卡·调间距""" from pptx import Presentation -from pptx.util import Inches, Pt, Emu, Cm +from pptx.util import Inches, Pt, Cm from pptx.dml.color import RGBColor -from pptx.enum.text import PP_ALIGN, MSO_ANCHOR +from pptx.enum.text import PP_ALIGN from pptx.enum.shapes import MSO_SHAPE +from pptx.chart.data import CategoryChartData +from pptx.enum.chart import XL_CHART_TYPE -# ── CHEC品牌色 ── -BLUE = RGBColor(0x1A, 0x3A, 0x5C) -GOLD = RGBColor(0xC8, 0x96, 0x2E) -RED = RGBColor(0xD9, 0x4E, 0x34) -GRAY = RGBColor(0x88, 0x99, 0xAA) -BG = RGBColor(0xEB, 0xF0, 0xF7) -WHITE = RGBColor(0xFF, 0xFF, 0xFF) -BLACK = RGBColor(0x33, 0x33, 0x33) -GREEN = RGBColor(0x2E, 0x7D, 0x32) -BORDER = RGBColor(0xDB, 0xE2, 0xEA) +# ── 品牌色 ── +BLUE = RGBColor(0x1A,0x3A,0x5C) +GOLD = RGBColor(0xC8,0x96,0x2E) +RED = RGBColor(0xD9,0x4E,0x34) +GRAY = RGBColor(0x88,0x99,0xAA) +BG = RGBColor(0xEB,0xF0,0xF7) +WHITE = RGBColor(0xFF,0xFF,0xFF) +BLACK = RGBColor(0x33,0x33,0x33) +GREEN = RGBColor(0x2E,0x7D,0x32) prs = Presentation() -prs.slide_width = Inches(13.333) # 16:9 +prs.slide_width = Inches(13.333) prs.slide_height = Inches(7.5) -def add_rect(slide, left, top, w, h, fill_color=None, line_color=None): - shape = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, left, top, w, h) - shape.line.fill.background() - if fill_color: - shape.fill.solid() - shape.fill.fore_color.rgb = fill_color - if line_color: - shape.line.color.rgb = line_color - shape.line.width = Pt(0.5) - else: - shape.line.fill.background() - return shape +def R(l,t,w,h,fill=None,line=None): + s=prs.slides[-1].shapes.add_shape(MSO_SHAPE.RECTANGLE,l,t,w,h) + s.line.fill.background() + if fill: s.fill.solid(); s.fill.fore_color.rgb=fill + if line: s.line.color.rgb=line; s.line.width=Pt(0.5) + return s -def add_text_box(slide, left, top, w, h, text, font_size=12, color=BLACK, bold=False, font_name='Microsoft YaHei', align=PP_ALIGN.LEFT): - txBox = slide.shapes.add_textbox(left, top, w, h) - txBox.text_frame.word_wrap = True - p = txBox.text_frame.paragraphs[0] - p.text = text - p.font.size = Pt(font_size) - p.font.color.rgb = color - p.font.bold = bold - p.font.name = font_name - p.alignment = align - return txBox +def T(l,t,w,h,txt,sz=12,clr=BLACK,b=False,fn='Microsoft YaHei',al=PP_ALIGN.LEFT): + tb=prs.slides[-1].shapes.add_textbox(l,t,w,h) + tb.text_frame.word_wrap=True + p=tb.text_frame.paragraphs[0]; p.text=txt + p.font.size=Pt(sz); p.font.color.rgb=clr; p.font.bold=b + p.font.name=fn; p.alignment=al + return tb -def add_kpi_card(slide, left, top, w, h, number, label, num_color=BLUE, num_size=44): - """统一KPI卡片""" - card = add_rect(slide, left, top, w, h, fill_color=BG) - card.shadow.inherit = False - num_box = add_text_box(slide, left, top + Inches(0.08), w, Inches(0.55), str(number), - font_size=num_size, color=num_color, bold=True, align=PP_ALIGN.CENTER) - add_text_box(slide, left, top + Inches(0.58), w, Inches(0.2), label, - font_size=9, color=GRAY, align=PP_ALIGN.CENTER) +def kpi(l,t,w,h,num,lbl,nc=BLUE,ns=44,ls=9): + """KPI卡片方块""" + R(l,t,w,h,fill=BG) + T(l,t+Inches(0.06),w,Inches(0.5),str(num),sz=ns,clr=nc,b=True,al=PP_ALIGN.CENTER) + T(l,t+Inches(0.55),w,Inches(0.18),lbl,sz=ls,clr=GRAY,al=PP_ALIGN.CENTER) + +def donut(l,t,w,h,vals,labels,colors): + """原生饼图""" + cd=CategoryChartData() + cd.categories=labels + cd.add_series('',vals) + ch=prs.slides[-1].shapes.add_chart(XL_CHART_TYPE.DOUGHNUT,l,t,w,h,cd) + plot=ch.chart.plots[0] + for i,clr in enumerate(colors): + plot.series[0].points[i].format.fill.solid() + plot.series[0].points[i].format.fill.fore_color.rgb=clr + ch.chart.has_legend=False + ch.chart.has_title=False + return ch # ═══════════════════════════════════════ -# Slide 1: 关键指标 +# SLIDE 1 # ═══════════════════════════════════════ -s1 = prs.slides.add_slide(prs.slide_layouts[6]) # blank +s1=prs.slides.add_slide(prs.slide_layouts[6]) -# Nav bar -nav = add_rect(s1, Inches(0), Inches(0), Inches(13.333), Inches(0.44), fill_color=BLUE) -add_text_box(s1, Inches(0.5), Inches(0.08), Inches(2), Inches(0.3), '★ 关键指标', font_size=11, color=GOLD, bold=True) -add_text_box(s1, Inches(2.5), Inches(0.08), Inches(2), Inches(0.3), '国别分布', font_size=11, color=GRAY) +# Nav +R(Inches(0),Inches(0),Inches(13.333),Inches(0.42),fill=BLUE) +T(Inches(0.5),Inches(0.07),Inches(2),Inches(0.28),'★ 关键指标',sz=11,clr=GOLD,b=True) +T(Inches(2.5),Inches(0.07),Inches(2),Inches(0.28),'国别分布',sz=11,clr=GRAY) +T(Inches(4.5),Inches(0.07),Inches(2),Inches(0.28),'预警明细',sz=11,clr=GRAY) # Title -add_rect(s1, Inches(0.5), Inches(0.65), Inches(0.06), Inches(0.3), fill_color=GOLD) -add_text_box(s1, Inches(0.7), Inches(0.6), Inches(8), Inches(0.4), '危大方案编审进度看板', font_size=22, color=BLUE, bold=True) -add_text_box(s1, Inches(8.5), Inches(0.68), Inches(4.5), Inches(0.3), '中国港湾中东区域公司 技术部 · 2026年6月 · 数据截止 2026-06-08', font_size=10, color=GRAY, align=PP_ALIGN.RIGHT) +R(Inches(0.5),Inches(0.58),Inches(0.06),Inches(0.28),fill=GOLD) +T(Inches(0.7),Inches(0.55),Inches(8),Inches(0.36),'危大方案编审进度看板',sz=22,clr=BLUE,b=True) +T(Inches(8.5),Inches(0.62),Inches(4.5),Inches(0.28),'中国港湾中东区域公司 技术部 · 2026年6月',sz=9,clr=GRAY,al=PP_ALIGN.RIGHT) -# === ROW 1: Module 1 & 2 === -y_row1 = Inches(1.2) -mod_w = Inches(5.9) +# === ROW 1: M1 + M2 === +RY1=Inches(1.1); MW=Inches(5.9); MH=Inches(1.85) -# Module 1: 年度认定 -m1 = add_rect(s1, Inches(0.5), y_row1, mod_w, Inches(1.7), fill_color=WHITE, line_color=BORDER) -add_rect(s1, Inches(0.5), y_row1, mod_w, Inches(0.38), fill_color=BLUE) -add_text_box(s1, Inches(0.7), y_row1 + Inches(0.05), Inches(3), Inches(0.28), '1. 年度认定', font_size=12, color=WHITE, bold=True) -add_text_box(s1, Inches(2.2), y_row1 + Inches(0.06), Inches(2.5), Inches(0.25), '中港科技便〔2026〕6号', font_size=9, color=GOLD) +# Module 1 +R(Inches(0.5),RY1,MW,MH,fill=WHITE,line=RGBColor(0xDB,0xE2,0xEA)) +R(Inches(0.5),RY1,MW,Inches(0.38),fill=BLUE) +T(Inches(0.7),RY1+Inches(0.04),Inches(3),Inches(0.3),'1. 年度认定',sz=13,clr=WHITE,b=True) +T(Inches(2.2),RY1+Inches(0.05),Inches(2.5),Inches(0.28),'中港科技便〔2026〕6号',sz=9,clr=GOLD) -add_kpi_card(s1, Inches(0.7), y_row1 + Inches(0.5), Inches(1.2), Inches(0.95), '43', '安全专项', num_size=44) -add_text_box(s1, Inches(0.7), y_row1 + Inches(1.48), Inches(1.2), Inches(0.18), '覆盖 7 个项目', font_size=9, color=GRAY, align=PP_ALIGN.CENTER) +kpi(Inches(0.7),RY1+Inches(0.58),Inches(1.1),Inches(1.0),'43','安全专项总数',ns=44) +donut(Inches(2.1),RY1+Inches(0.55),Inches(1.2),Inches(1.2),[27,16],['一般类','超规类'],[BLUE,GOLD]) +T(Inches(3.5),RY1+Inches(0.7),Inches(1.5),Inches(0.25),'■ 一般类 27',sz=11,clr=BLUE) +T(Inches(3.5),RY1+Inches(1.0),Inches(1.5),Inches(0.25),'■ 超规类 16',sz=11,clr=GOLD) +T(Inches(3.5),RY1+Inches(1.3),Inches(1.5),Inches(0.25),'覆盖 7 个项目',sz=9,clr=GRAY) -# Donut chart legend -add_text_box(s1, Inches(2.3), y_row1 + Inches(0.6), Inches(1.5), Inches(0.3), '■ 一般类 27', font_size=12, color=BLUE) -add_text_box(s1, Inches(2.3), y_row1 + Inches(0.9), Inches(1.5), Inches(0.3), '■ 超规类 16', font_size=12, color=GOLD) +# Module 2 +MX2=Inches(6.93) +R(MX2,RY1,MW,MH,fill=WHITE,line=RGBColor(0xDB,0xE2,0xEA)) +R(MX2,RY1,MW,Inches(0.38),fill=BLUE) +T(MX2+Inches(0.2),RY1+Inches(0.04),Inches(3),Inches(0.3),'2. OA有效登记',sz=13,clr=WHITE,b=True) +T(MX2+Inches(1.8),RY1+Inches(0.05),Inches(2),Inches(0.28),'排除已作废',sz=9,clr=GOLD) -# Module 2: OA有效登记 -x_m2 = Inches(6.93) -m2 = add_rect(s1, x_m2, y_row1, mod_w, Inches(1.7), fill_color=WHITE, line_color=BORDER) -add_rect(s1, x_m2, y_row1, mod_w, Inches(0.38), fill_color=BLUE) -add_text_box(s1, x_m2 + Inches(0.2), y_row1 + Inches(0.05), Inches(3), Inches(0.28), '2. OA有效登记', font_size=12, color=WHITE, bold=True) -add_text_box(s1, x_m2 + Inches(1.8), y_row1 + Inches(0.06), Inches(2), Inches(0.25), '排除已作废', font_size=9, color=GOLD) +kpi(MX2+Inches(0.2),RY1+Inches(0.58),Inches(1.1),Inches(1.0),'52','有效登记总数',ns=44) +donut(MX2+Inches(1.6),RY1+Inches(0.55),Inches(1.2),Inches(1.2),[30,22],['一般类','超规类'],[BLUE,GOLD]) +T(MX2+Inches(3.0),RY1+Inches(0.7),Inches(1.5),Inches(0.25),'■ 一般类 30',sz=11,clr=BLUE) +T(MX2+Inches(3.0),RY1+Inches(1.0),Inches(1.5),Inches(0.25),'■ 超规类 22',sz=11,clr=GOLD) +T(MX2+Inches(3.0),RY1+Inches(1.3),Inches(1.5),Inches(0.25),'登记率 121%(52/43)',sz=9,clr=GRAY) -add_kpi_card(s1, x_m2 + Inches(0.2), y_row1 + Inches(0.5), Inches(1.2), Inches(0.95), '52', '有效登记', num_size=44) -add_text_box(s1, x_m2 + Inches(0.2), y_row1 + Inches(1.48), Inches(1.2), Inches(0.18), '登记率 121%', font_size=9, color=GRAY, align=PP_ALIGN.CENTER) -add_text_box(s1, x_m2 + Inches(2.3), y_row1 + Inches(0.6), Inches(1.5), Inches(0.3), '■ 一般类 30', font_size=12, color=BLUE) -add_text_box(s1, x_m2 + Inches(2.3), y_row1 + Inches(0.9), Inches(1.5), Inches(0.3), '■ 超规类 22', font_size=12, color=GOLD) - -# === ROW 2: Module 3 & 4 === -y_row2 = Inches(3.1) +# === ROW 2: M3 + M4 === +RY2=Inches(3.15) # Module 3: 国别 -m3 = add_rect(s1, Inches(0.5), y_row2, mod_w, Inches(2.0), fill_color=WHITE, line_color=BORDER) -add_rect(s1, Inches(0.5), y_row2, mod_w, Inches(0.36), fill_color=BLUE) -add_text_box(s1, Inches(0.7), y_row2 + Inches(0.04), Inches(4), Inches(0.28), '3. 按国别分布 · 分层条形图', font_size=11, color=WHITE, bold=True) +R(Inches(0.5),RY2,MW,Inches(1.85),fill=WHITE,line=RGBColor(0xDB,0xE2,0xEA)) +R(Inches(0.5),RY2,MW,Inches(0.36),fill=BLUE) +T(Inches(0.7),RY2+Inches(0.03),Inches(4),Inches(0.28),'3. 按国别分布 · 分层条形图',sz=11,clr=WHITE,b=True) -# Bar chart - simplified table -countries = [('阿拉伯联合酋长国', 27, 18, 45), ('沙特阿拉伯', 3, 3, 6), ('卡塔尔', 0, 1, 1)] -y_bar = y_row2 + Inches(0.45) -for i, (name, gen, chao, tot) in enumerate(countries): - y = y_bar + Inches(i * 0.45) - add_text_box(s1, Inches(0.6), y, Inches(1.8), Inches(0.2), name, font_size=10, color=BLACK, align=PP_ALIGN.RIGHT) - bw = max(gen * 0.07, 0.05) if gen > 0 else 0 - if bw > 0: - add_rect(s1, Inches(2.5), y + Inches(0.02), Inches(bw), Inches(0.22), fill_color=BLUE) - cw = max(chao * 0.07, 0.05) if chao > 0 else 0 - if cw > 0: - add_rect(s1, Inches(2.5) + Inches(bw), y + Inches(0.02), Inches(cw), Inches(0.22), fill_color=GOLD) - add_text_box(s1, Inches(5.2), y, Inches(0.5), Inches(0.22), str(tot), font_size=12, color=BLUE, bold=True) +countries=[('阿拉伯联合酋长国',27,18,45),('沙特阿拉伯',3,3,6),('卡塔尔',0,1,1)] +y0=RY2+Inches(0.5) +for i,(name,gn,ch,tot) in enumerate(countries): + y=y0+Inches(i*0.42) + T(Inches(0.55),y,Inches(1.5),Inches(0.22),name,sz=10,clr=BLACK,al=PP_ALIGN.RIGHT) + bw=max(gn*0.065,0.03) if gn>0 else 0 + if bw>0: R(Inches(2.15),y+Inches(0.02),Inches(bw),Inches(0.2),fill=BLUE) + cw=max(ch*0.065,0.03) if ch>0 else 0 + if cw>0: R(Inches(2.15)+Inches(bw),y+Inches(0.02),Inches(cw),Inches(0.2),fill=GOLD) + T(Inches(5.3),y,Inches(0.5),Inches(0.22),str(tot),sz=12,clr=BLUE,b=True) -add_text_box(s1, Inches(0.6), y_row2 + Inches(1.78), Inches(2), Inches(0.18), '■ 一般类', font_size=9, color=BLUE) -add_text_box(s1, Inches(1.5), y_row2 + Inches(1.78), Inches(2), Inches(0.18), '■ 超规类', font_size=9, color=GOLD) +T(Inches(0.55),RY2+Inches(1.58),Inches(2),Inches(0.18),'■ 一般类',sz=9,clr=BLUE) +T(Inches(1.3),RY2+Inches(1.58),Inches(2),Inches(0.18),'■ 超规类',sz=9,clr=GOLD) -# Module 4: 审批进度 -m4 = add_rect(s1, x_m2, y_row2, mod_w, Inches(2.0), fill_color=WHITE, line_color=BORDER) -add_rect(s1, x_m2, y_row2, mod_w, Inches(0.36), fill_color=BLUE) -add_text_box(s1, x_m2 + Inches(0.2), y_row2 + Inches(0.04), Inches(4), Inches(0.28), '4. 审批进度 & 三色预警信号', font_size=11, color=WHITE, bold=True) +# Module 4: 审批+预警 +R(MX2,RY2,MW,Inches(1.85),fill=WHITE,line=RGBColor(0xDB,0xE2,0xEA)) +R(MX2,RY2,MW,Inches(0.36),fill=BLUE) +T(MX2+Inches(0.2),RY2+Inches(0.03),Inches(4),Inches(0.28),'4. 审批进度 & 三色预警信号',sz=11,clr=WHITE,b=True) -# Row 1 cards -cy = y_row2 + Inches(0.5) -cw, ch = Inches(0.85), Inches(0.7) -gap = Inches(0.12) -for idx, (num, label, color) in enumerate([ - ('5', '预警总计', RED), ('🔴0', '红色', RED), ('🟠1', '橙色', RED), ('🟡4', '黄色', GOLD), ('23', '未完成审批', GRAY)]): - cx = x_m2 + Inches(0.15) + Inches(idx * 1.05) - add_kpi_card(s1, cx, cy, cw, ch, num, label, num_color=color, num_size=28 if idx > 0 else 36) +# Row 1: 预警指标卡片 — 统一样式 +CARD_W=Inches(0.85); CARD_H=Inches(0.7); CARD_GAP=Inches(0.08) +CY=RY2+Inches(0.48) -# Legend -add_text_box(s1, x_m2 + Inches(4.8), cy, Inches(1.2), Inches(0.55), - '🔴 在实施未审批\n🟠 ≤30天\n🟡 ≤45天', font_size=8, color=GRAY, align=PP_ALIGN.RIGHT) +warn_data=[ + ('5', '预警总计', RED, 36), + ('0', '红色🔴', RED, 28), + ('1', '橙色🟠', RED, 28), + ('4', '黄色🟡', GOLD, 28), + ('23', '未完成审批', GRAY, 28), +] +for idx,(num,lbl,clr,ns) in enumerate(warn_data): + cx=MX2+Inches(0.12)+Inches(idx*(CARD_W+CARD_GAP)) + kpi(cx,CY,CARD_W,CARD_H,num,lbl,nc=clr,ns=ns,ls=8) -# Row 2: 审批率 + progress bar -py = y_row2 + Inches(1.35) -add_kpi_card(s1, x_m2 + Inches(0.15), py, Inches(1.0), Inches(0.7), '56%', '审批完成率', num_color=GREEN, num_size=36) +# Legend right-aligned +T(MX2+Inches(4.9),CY+Inches(0.05),Inches(1.0),Inches(0.65), + '🔴 在实施未审批\n🟠 ≤30天\n🟡 ≤45天',sz=7,clr=GRAY,al=PP_ALIGN.RIGHT) + +# Row 2: 审批率 + 进度条 +PY=RY2+Inches(1.3) +kpi(MX2+Inches(0.12),PY,Inches(0.95),Inches(0.5),'56%','审批完成率',nc=GREEN,ns=32,ls=8) # Progress bar -bar_bg = add_rect(s1, x_m2 + Inches(1.35), py + Inches(0.12), Inches(3.5), Inches(0.22), fill_color=BG) -bar_fg = add_rect(s1, x_m2 + Inches(1.35), py + Inches(0.12), Inches(3.5 * 0.56), Inches(0.22), fill_color=BLUE) -add_text_box(s1, x_m2 + Inches(1.35), py + Inches(0.38), Inches(3.5), Inches(0.18), - '已审批 29 未审批 23 / 总计 52', font_size=8, color=GRAY) +R(MX2+Inches(1.2),PY+Inches(0.08),Inches(3.6),Inches(0.18),fill=BG) +R(MX2+Inches(1.2),PY+Inches(0.08),Inches(3.6*0.56),Inches(0.18),fill=BLUE) +T(MX2+Inches(1.2),PY+Inches(0.28),Inches(3.6),Inches(0.18), + '已审批 29 未审批 23 / 总计 52',sz=7,clr=GRAY) # Footer -add_rect(s1, Inches(0), Inches(7.18), Inches(13.333), Inches(0.32), fill_color=RGBColor(0xF5, 0xF6, 0xF8)) -add_text_box(s1, Inches(0.5), Inches(7.2), Inches(4), Inches(0.25), '中国港湾中东区域公司 技术部', font_size=8, color=GRAY) -add_text_box(s1, Inches(11.5), Inches(7.2), Inches(1.5), Inches(0.25), '1 / 2', font_size=8, color=GRAY, align=PP_ALIGN.RIGHT) +R(Inches(0),Inches(7.18),Inches(13.333),Inches(0.32),fill=RGBColor(0xF5,0xF6,0xF8)) +T(Inches(0.5),Inches(7.2),Inches(4),Inches(0.2),'中国港湾中东区域公司 技术部',sz=8,clr=GRAY) +T(Inches(11.5),Inches(7.2),Inches(1.5),Inches(0.2),'1 / 2',sz=8,clr=GRAY,al=PP_ALIGN.RIGHT) # ═══════════════════════════════════════ -# Slide 2: 预警明细 +# SLIDE 2: 预警明细 # ═══════════════════════════════════════ -s2 = prs.slides.add_slide(prs.slide_layouts[6]) -add_rect(s2, Inches(0), Inches(0), Inches(13.333), Inches(0.44), fill_color=BLUE) -add_text_box(s2, Inches(0.5), Inches(0.08), Inches(2), Inches(0.3), '关键指标', font_size=11, color=GRAY) -add_text_box(s2, Inches(2.5), Inches(0.08), Inches(2), Inches(0.3), '★ 预警明细', font_size=11, color=GOLD, bold=True) +s2=prs.slides.add_slide(prs.slide_layouts[6]) -add_rect(s2, Inches(0.5), Inches(0.65), Inches(0.06), Inches(0.3), fill_color=GOLD) -add_text_box(s2, Inches(0.7), Inches(0.6), Inches(8), Inches(0.4), '预警信号明细清单', font_size=22, color=BLUE, bold=True) -add_text_box(s2, Inches(8.5), Inches(0.68), Inches(4.5), Inches(0.3), '共 5 项预警', font_size=10, color=GRAY, align=PP_ALIGN.RIGHT) +R(Inches(0),Inches(0),Inches(13.333),Inches(0.42),fill=BLUE) +T(Inches(0.5),Inches(0.07),Inches(2),Inches(0.28),'关键指标',sz=11,clr=GRAY) +T(Inches(2.5),Inches(0.07),Inches(2),Inches(0.28),'国别分布',sz=11,clr=GRAY) +T(Inches(4.5),Inches(0.07),Inches(2),Inches(0.28),'★ 预警明细',sz=11,clr=GOLD,b=True) -# Table -warnings = [ - ('🟠', '阿联酋迪拜马克图姆国际机场地下结构工程', 'BHS/GSE隧道现浇板(4包)', '已添加未实施', '2天'), - ('🟡', '阿联酋阿布扎比汽车基地房建项目', '模板支立工程', '未审批未实施', '32天'), - ('🟡', '阿联酋阿布扎比汽车基地房建项目', '深基坑开挖方案', '未审批未实施', '37天'), - ('🟡', '阿联酋迪拜马克图姆国际机场地下结构工程', '现浇倒T梁(4包)', '审批中未实施', '42天'), - ('🟡', '阿联酋迪拜马克图姆国际机场地下结构工程', 'T梁预制运输安装(4包)', '已添加未实施', '42天'), +R(Inches(0.5),Inches(0.58),Inches(0.06),Inches(0.28),fill=GOLD) +T(Inches(0.7),Inches(0.55),Inches(8),Inches(0.36),'预警信号明细清单',sz=22,clr=BLUE,b=True) +T(Inches(8.5),Inches(0.62),Inches(4.5),Inches(0.28),'共 5 项预警',sz=10,clr=GRAY,al=PP_ALIGN.RIGHT) + +warnings=[ + ('🟠','阿联酋迪拜马克图姆国际机场地下结构工程','BHS/GSE隧道现浇板(4包)','已添加未实施','2天'), + ('🟡','阿联酋阿布扎比汽车基地房建项目','模板支立工程','未审批未实施','32天'), + ('🟡','阿联酋阿布扎比汽车基地房建项目','深基坑开挖方案','未审批未实施','37天'), + ('🟡','阿联酋迪拜马克图姆国际机场地下结构工程','现浇倒T梁(4包)','审批中未实施','42天'), + ('🟡','阿联酋迪拜马克图姆国际机场地下结构工程','T梁预制运输安装(4包)','已添加未实施','42天'), ] -ty = Inches(1.15) # Table header -th_h = Inches(0.32) -cols = [0.5, 3.0, 3.0, 3.0, 2.5] -headers = ['信号', '项目名称', '方案名称', '当前状态', '距开工'] -for i, (h, w) in enumerate(zip(headers, cols)): - add_rect(s2, Inches(0.5 + sum(cols[:i])), ty, Inches(w), th_h, fill_color=BLUE) - add_text_box(s2, Inches(0.55 + sum(cols[:i])), ty + Inches(0.02), Inches(w - 0.1), Inches(0.28), h, font_size=10, color=WHITE, bold=True) +TY=Inches(1.1); TH=Inches(0.32) +CW=[Inches(0.6),Inches(3.8),Inches(3.0),Inches(2.2),Inches(1.0)] +HDS=['信号','项目名称','方案名称','当前状态','距开工'] +x_off=Inches(0.5) +for i,(h,w) in enumerate(zip(HDS,CW)): + R(x_off+sum(CW[:i]),TY,w,TH,fill=BLUE) + T(x_off+Inches(0.05)+sum(CW[:i]),TY+Inches(0.02),w-Inches(0.1),Inches(0.28),h,sz=10,clr=WHITE,b=True) -for j, (icon, proj, scheme, status, days) in enumerate(warnings): - y = ty + Inches(0.32 + j * 0.38) - bg_c = BG if j % 2 == 0 else WHITE - add_rect(s2, Inches(0.5), y, Inches(12.0), Inches(0.38), fill_color=bg_c) - add_text_box(s2, Inches(0.55), y + Inches(0.04), Inches(0.4), Inches(0.3), icon, font_size=14, align=PP_ALIGN.CENTER) - add_text_box(s2, Inches(1.0), y + Inches(0.04), Inches(3.8), Inches(0.3), proj, font_size=10) - add_text_box(s2, Inches(4.8), y + Inches(0.04), Inches(3.0), Inches(0.3), scheme, font_size=10) - add_text_box(s2, Inches(7.8), y + Inches(0.04), Inches(2.0), Inches(0.3), status, font_size=10) - add_text_box(s2, Inches(9.8), y + Inches(0.04), Inches(1.5), Inches(0.3), days, font_size=11, color=RED, bold=True, align=PP_ALIGN.RIGHT) +for j,(icon,proj,scheme,status,days) in enumerate(warnings): + y=TY+TH+Inches(j*0.38) + bg_c=BG if j%2==0 else WHITE + R(x_off,y,sum(CW),Inches(0.38),fill=bg_c) + T(x_off+Inches(0.05),y+Inches(0.04),Inches(0.5),Inches(0.3),icon,sz=16,al=PP_ALIGN.CENTER) + T(x_off+CW[0],y+Inches(0.04),CW[1]-Inches(0.1),Inches(0.3),proj,sz=10) + T(x_off+CW[0]+CW[1],y+Inches(0.04),CW[2]-Inches(0.1),Inches(0.3),scheme,sz=10) + T(x_off+CW[0]+CW[1]+CW[2],y+Inches(0.04),CW[3]-Inches(0.1),Inches(0.3),status,sz=10) + T(x_off+sum(CW[:4]),y+Inches(0.04),CW[4]-Inches(0.1),Inches(0.3),days,sz=11,clr=RED,b=True,al=PP_ALIGN.RIGHT) -# Rule box -add_rect(s2, Inches(0.5), Inches(4.0), Inches(12.0), Inches(0.5), fill_color=BG) -add_rect(s2, Inches(0.5), Inches(4.0), Inches(0.06), Inches(0.5), fill_color=GOLD) -add_text_box(s2, Inches(0.75), Inches(4.05), Inches(11.5), Inches(0.4), - '📐 预警规则:🟠 橙色 ≤30天未审批 · 🟡 黄色 ≤45天未审批 · 🔴 红色 在实施未审批(本月0项)', font_size=10, color=BLACK) +# Rule +R(x_off,TY+TH+Inches(5*0.38+0.2),sum(CW),Inches(0.45),fill=BG) +R(x_off,TY+TH+Inches(5*0.38+0.2),Inches(0.06),Inches(0.45),fill=GOLD) +T(x_off+Inches(0.2),TY+TH+Inches(5*0.38+0.25),Inches(11),Inches(0.35), + '📐 预警规则:🟠 橙色 ≤30天未审批 · 🟡 黄色 ≤45天未审批 · 🔴 红色 在实施未审批(本月0项)',sz=10,clr=BLACK) -# Footer -add_rect(s2, Inches(0), Inches(7.18), Inches(13.333), Inches(0.32), fill_color=RGBColor(0xF5, 0xF6, 0xF8)) -add_text_box(s2, Inches(0.5), Inches(7.2), Inches(4), Inches(0.25), '中国港湾中东区域公司 技术部', font_size=8, color=GRAY) -add_text_box(s2, Inches(11.5), Inches(7.2), Inches(1.5), Inches(0.25), '2 / 2', font_size=8, color=GRAY, align=PP_ALIGN.RIGHT) +R(Inches(0),Inches(7.18),Inches(13.333),Inches(0.32),fill=RGBColor(0xF5,0xF6,0xF8)) +T(Inches(0.5),Inches(7.2),Inches(4),Inches(0.2),'中国港湾中东区域公司 技术部',sz=8,clr=GRAY) +T(Inches(11.5),Inches(7.2),Inches(1.5),Inches(0.2),'2 / 2',sz=8,clr=GRAY,al=PP_ALIGN.RIGHT) -# ── Save ── -out = "/mnt/y/Openclaw_Hub/03.资源/实施项目 wiki/dashboard/data/2026-06-08/cleaned/危大方案编审进度看板.pptx" +out="/mnt/y/Openclaw_Hub/03.资源/实施项目 wiki/dashboard/data/2026-06-08/cleaned/危大方案编审进度看板.pptx" prs.save(out) -print(f"✅ PPTX已生成: {out}") -print(f" Slide 1: 关键指标(4模块)") -print(f" Slide 2: 预警明细(5项)") -print(f" 所有文字可编辑 · 16:9 · CHEC规范配色") +print(f"✅ v2 已生成: {out}") +print(f" + 原生饼图(一般/超规)") +print(f" + 三色预警统一卡片样式") +print(f" + 模块间距重新计算")