| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775 |
- # -*- coding: utf-8 -*-
- from docx import Document
- from docx.shared import Pt, Cm, RGBColor, Inches
- from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_TAB_LEADER
- from docx.enum.table import WD_TABLE_ALIGNMENT, WD_ALIGN_VERTICAL
- from docx.oxml.ns import qn
- from docx.oxml import OxmlElement
- import copy
- doc = Document()
- # ── 页面设置 A4 ──────────────────────────────────────────────
- section = doc.sections[0]
- section.page_width = Cm(21)
- section.page_height = Cm(29.7)
- section.left_margin = Cm(2.5)
- section.right_margin = Cm(2.5)
- section.top_margin = Cm(2.5)
- section.bottom_margin = Cm(2.0)
- # ── 颜色常量 ────────────────────────────────────────────────
- C_TITLE = RGBColor(0x1e, 0x3a, 0x8a) # 深蓝
- C_H2 = RGBColor(0x1d, 0x4e, 0xd8) # 中蓝
- C_H3 = RGBColor(0x0e, 0x7a, 0x9e) # 青蓝
- C_LABEL = RGBColor(0x37, 0x41, 0x51) # 深灰
- C_BODY = RGBColor(0x1f, 0x29, 0x37) # 正文黑
- C_WHITE = RGBColor(0xFF, 0xFF, 0xFF)
- C_TH_BG = RGBColor(0x1e, 0x40, 0xaf)
- C_ROW1 = RGBColor(0xef, 0xf6, 0xff)
- C_ROW2 = RGBColor(0xff, 0xff, 0xff)
- C_BORDER = RGBColor(0xc3, 0xda, 0xf7)
- C_NOTE_BG= RGBColor(0xfe, 0xf9, 0xc3)
- C_NOTE_BD= RGBColor(0xf5, 0x9e, 0x0b)
- def set_cell_bg(cell, rgb: RGBColor):
- tc = cell._tc
- tcPr = tc.get_or_add_tcPr()
- shd = OxmlElement('w:shd')
- shd.set(qn('w:val'), 'clear')
- shd.set(qn('w:color'), 'auto')
- hex_color = '{:02X}{:02X}{:02X}'.format(rgb[0], rgb[1], rgb[2])
- shd.set(qn('w:fill'), hex_color)
- tcPr.append(shd)
- def set_cell_border(cell, top=None, bottom=None, left=None, right=None):
- tc = cell._tc
- tcPr = tc.get_or_add_tcPr()
- tcBorders = OxmlElement('w:tcBorders')
- for side, val in [('top',top),('bottom',bottom),('left',left),('right',right)]:
- if val:
- el = OxmlElement(f'w:{side}')
- el.set(qn('w:val'), val.get('val','single'))
- el.set(qn('w:sz'), str(val.get('sz',4)))
- el.set(qn('w:space'), '0')
- el.set(qn('w:color'), val.get('color','C3DAF7'))
- tcBorders.append(el)
- tcPr.append(tcBorders)
- def add_run(para, text, bold=False, size=None, color=None, italic=False):
- run = para.add_run(text)
- run.bold = bold
- run.italic = italic
- run.font.name = '微软雅黑'
- run._element.rPr.rFonts.set(qn('w:eastAsia'), '微软雅黑')
- if size:
- run.font.size = Pt(size)
- if color:
- run.font.color.rgb = color
- return run
- def heading1(text):
- para = doc.add_paragraph()
- para.paragraph_format.space_before = Pt(18)
- para.paragraph_format.space_after = Pt(8)
- para.paragraph_format.left_indent = Cm(0)
- # 左侧蓝条效果通过 border
- pPr = para._p.get_or_add_pPr()
- pBdr = OxmlElement('w:pBdr')
- left = OxmlElement('w:left')
- left.set(qn('w:val'), 'single')
- left.set(qn('w:sz'), '24')
- left.set(qn('w:space'), '6')
- left.set(qn('w:color'), '1E3A8A')
- pBdr.append(left)
- pPr.append(pBdr)
- para.paragraph_format.left_indent = Cm(0.5)
- add_run(para, text, bold=True, size=14, color=C_TITLE)
- return para
- def heading2(text):
- para = doc.add_paragraph()
- para.paragraph_format.space_before = Pt(10)
- para.paragraph_format.space_after = Pt(4)
- add_run(para, '◆ ', bold=True, size=12, color=C_H2)
- add_run(para, text, bold=True, size=12, color=C_H2)
- return para
- def heading3(text):
- para = doc.add_paragraph()
- para.paragraph_format.space_before = Pt(6)
- para.paragraph_format.space_after = Pt(3)
- add_run(para, '▸ ', bold=True, size=11, color=C_H3)
- add_run(para, text, bold=True, size=11, color=C_H3)
- return para
- def body(text, indent=0):
- para = doc.add_paragraph()
- para.paragraph_format.space_before = Pt(2)
- para.paragraph_format.space_after = Pt(2)
- para.paragraph_format.left_indent = Cm(indent)
- para.paragraph_format.first_line_indent = Cm(0)
- add_run(para, text, size=10.5, color=C_BODY)
- return para
- def bullet(text, level=0):
- para = doc.add_paragraph()
- para.paragraph_format.space_before = Pt(1)
- para.paragraph_format.space_after = Pt(1)
- indent = 0.5 + level * 0.5
- para.paragraph_format.left_indent = Cm(indent)
- bullets = ['●', '○', '–']
- add_run(para, bullets[level] + ' ', bold=(level==0), size=10, color=C_H3)
- add_run(para, text, size=10, color=C_BODY)
- return para
- def note(text):
- para = doc.add_paragraph()
- para.paragraph_format.space_before = Pt(6)
- para.paragraph_format.space_after = Pt(6)
- para.paragraph_format.left_indent = Cm(0.5)
- para.paragraph_format.right_indent = Cm(0.5)
- pPr = para._p.get_or_add_pPr()
- pBdr = OxmlElement('w:pBdr')
- for side in ['top','bottom','left','right']:
- el = OxmlElement(f'w:{side}')
- el.set(qn('w:val'), 'single')
- el.set(qn('w:sz'), '4' if side in ('top','bottom','right') else '18')
- el.set(qn('w:space'), '4')
- el.set(qn('w:color'), 'F59E0B')
- pBdr.append(el)
- pPr.append(pBdr)
- add_run(para, '📌 注意:', bold=True, size=10, color=RGBColor(0xd9,0x77,0x06))
- add_run(para, text, size=10, color=C_BODY)
- return para
- def make_table(headers, rows, col_widths=None):
- table = doc.add_table(rows=1+len(rows), cols=len(headers))
- table.alignment = WD_TABLE_ALIGNMENT.CENTER
- table.style = 'Table Grid'
- # 表头
- hdr = table.rows[0]
- for i, h in enumerate(headers):
- cell = hdr.cells[i]
- set_cell_bg(cell, C_TH_BG)
- cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
- para = cell.paragraphs[0]
- para.alignment = WD_ALIGN_PARAGRAPH.CENTER
- add_run(para, h, bold=True, size=10, color=C_WHITE)
- # 数据行
- for r_idx, row in enumerate(rows):
- tr = table.rows[r_idx+1]
- bg = C_ROW1 if r_idx % 2 == 0 else C_ROW2
- for c_idx, val in enumerate(row):
- cell = tr.cells[c_idx]
- set_cell_bg(cell, bg)
- cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
- para = cell.paragraphs[0]
- para.alignment = WD_ALIGN_PARAGRAPH.LEFT
- add_run(para, str(val), size=10, color=C_BODY)
- # 列宽
- if col_widths:
- for i, w in enumerate(col_widths):
- for row in table.rows:
- row.cells[i].width = Cm(w)
- doc.add_paragraph() # 表格后空行
- return table
- def divider():
- para = doc.add_paragraph()
- para.paragraph_format.space_before = Pt(4)
- para.paragraph_format.space_after = Pt(4)
- pPr = para._p.get_or_add_pPr()
- pBdr = OxmlElement('w:pBdr')
- bottom = OxmlElement('w:bottom')
- bottom.set(qn('w:val'), 'single')
- bottom.set(qn('w:sz'), '6')
- bottom.set(qn('w:space'), '1')
- bottom.set(qn('w:color'), 'C3DAF7')
- pBdr.append(bottom)
- pPr.append(pBdr)
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- # 封面
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- doc.add_paragraph()
- doc.add_paragraph()
- doc.add_paragraph()
- p = doc.add_paragraph()
- p.alignment = WD_ALIGN_PARAGRAPH.CENTER
- add_run(p, '实验室安全智能监测与管控中心', bold=True, size=22, color=C_TITLE)
- doc.add_paragraph()
- p = doc.add_paragraph()
- p.alignment = WD_ALIGN_PARAGRAPH.CENTER
- add_run(p, '数据可视化大屏', bold=True, size=16, color=C_H2)
- doc.add_paragraph()
- p = doc.add_paragraph()
- p.alignment = WD_ALIGN_PARAGRAPH.CENTER
- add_run(p, '使 用 说 明 文 档', bold=True, size=14, color=C_H3)
- doc.add_paragraph()
- doc.add_paragraph()
- p = doc.add_paragraph()
- p.alignment = WD_ALIGN_PARAGRAPH.CENTER
- add_run(p, '中国安全生产科学研究院', bold=True, size=12, color=C_LABEL)
- p = doc.add_paragraph()
- p.alignment = WD_ALIGN_PARAGRAPH.CENTER
- add_run(p, 'National Institute for Occupational Safety', italic=True, size=10, color=C_LABEL)
- doc.add_paragraph()
- p = doc.add_paragraph()
- p.alignment = WD_ALIGN_PARAGRAPH.CENTER
- add_run(p, '文档版本:V1.0 编制日期:2026年03月', size=10, color=C_LABEL)
- doc.add_page_break()
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- # 目录
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- p = doc.add_paragraph()
- p.alignment = WD_ALIGN_PARAGRAPH.CENTER
- add_run(p, '目 录', bold=True, size=14, color=C_TITLE)
- doc.add_paragraph()
- toc_items = [
- ('1', '文档概述', '3'),
- ('2', '系统简介', '3'),
- ('3', '运行环境与访问方式', '4'),
- ('4', '整体界面布局说明', '4'),
- ('5', '顶部导航栏', '5'),
- ('6', '1区 — 实验室基本情况统计', '5'),
- ('7', '2区 — 智能设备与实验室设备统计', '7'),
- ('8', '3区 — 实时监控', '8'),
- ('9', '4区 — 实验环境感知与风险预警', '10'),
- ('10', '全屏预警弹窗', '11'),
- ('11', '通用交互说明', '12'),
- ('12', '数据说明', '12'),
- ('13', '常见问题(FAQ)', '13'),
- ]
- for no, title, page in toc_items:
- para = doc.add_paragraph()
- para.paragraph_format.space_before = Pt(3)
- para.paragraph_format.space_after = Pt(3)
- tab_stops = para.paragraph_format.tab_stops
- tab_stops.add_tab_stop(Cm(14.5), leader=WD_TAB_LEADER.DOTS)
- add_run(para, f'{no}. {title}', size=10.5, color=C_BODY)
- para.add_run('\t')
- add_run(para, page, size=10.5, color=C_BODY)
- doc.add_page_break()
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- # 1. 文档概述
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- heading1('1. 文档概述')
- body('本文档为《实验室安全智能监测与管控中心》数据可视化大屏的使用说明,旨在帮助操作人员、管理人员及相关使用者快速了解系统各功能模块的展示内容、交互方式及数据含义,确保系统功能得到正确、高效的使用。')
- doc.add_paragraph()
- body('本文档适用对象:')
- bullet('实验室安全管理人员(日常监控运维)')
- bullet('院级行政管理人员(决策数据查看)')
- bullet('IT运维人员(系统部署与维护参考)')
- divider()
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- # 2. 系统简介
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- heading1('2. 系统简介')
- body('《实验室安全智能监测与管控中心》大屏系统是面向中国安全生产科学研究院(简称"安科院")各实验室的综合安全管理可视化平台,通过数据可视化手段将实验室的安全状态、环境感知数据、设备运行状况、人员进出信息及风险预警等核心数据以直观、实时的方式呈现于大屏上,便于管理人员进行统一监控与快速决策。')
- doc.add_paragraph()
- heading2('系统定位')
- make_table(
- ['维度', '说明'],
- [
- ['系统名称', '实验室安全智能监测与管控中心'],
- ['所属单位', '中国安全生产科学研究院(National Institute for Occupational Safety)'],
- ['系统类型', '数据可视化大屏(单页面应用)'],
- ['设计分辨率', '9600 × 2800 px(约为1920×1080的2.5倍)'],
- ['视觉风格', '深蓝科幻风,边框流动效果,科技感动效图标'],
- ['技术框架', 'HTML5 + CSS3 + ECharts 5.4.3(单文件内联,无需构建工具)'],
- ],
- col_widths=[4, 11.5]
- )
- heading2('主要功能概览')
- bullet('实验室基本情况统计(总数、分级、状态)')
- bullet('实验室安全分级统计(各二级单位堆叠柱状图)')
- bullet('实验室人员进出数量统计及走势折线图')
- bullet('智能环境感知应用设备统计(在线率、设备分类)')
- bullet('实验室设备分类及使用统计(分类、使用率、状态)')
- bullet('3区固定显示实时监控(9宫格监控画面,AI危险行为检测)')
- bullet('实验环境安全智能感知(传感器实时数据滚动)')
- bullet('实验室实时风险预警(预警通知轮播)')
- bullet('全屏预警弹窗(超阈值自动触发,科幻警报样式)')
- divider()
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- # 3. 运行环境与访问方式
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- heading1('3. 运行环境与访问方式')
- heading2('硬件环境要求')
- make_table(
- ['项目', '最低要求', '推荐配置'],
- [
- ['显示屏', '1920×1080(FHD)', '超大屏/拼接屏 9600×2800 px'],
- ['处理器', 'Intel i5 / 同等级别', 'Intel i7 或以上'],
- ['内存', '8 GB', '16 GB 或以上'],
- ['显卡', '支持硬件加速', '独立显卡(GPU加速渲染)'],
- ],
- col_widths=[4, 5, 6.5]
- )
- heading2('软件环境要求')
- make_table(
- ['软件', '版本要求', '说明'],
- [
- ['浏览器', 'Chrome 90+ / Edge 90+', '推荐使用最新版 Chrome,需支持 WebGL'],
- ['ECharts CDN', '5.4.3', '通过 jsDelivr CDN 在线加载,需保证网络可达'],
- ['操作系统', 'Windows 10+ / macOS 12+', '支持主流64位操作系统'],
- ],
- col_widths=[3, 5, 7.5]
- )
- heading2('访问方式')
- bullet('将项目文件夹(含 index-v2.html 及 baseBg.png)部署到本地或局域网 Web 服务器。')
- bullet('用浏览器打开 http://[服务器IP]/index-v2.html 即可访问。')
- bullet('也可直接双击 index-v2.html 在浏览器中本地打开(部分资源需本地服务器访问)。')
- bullet('首次加载时,系统将自动请求进入全屏模式(浏览器弹出授权提示,点击"允许"即可)。')
- note('若 ECharts 图表未正常显示,请检查网络连接是否可访问 cdn.jsdelivr.net,或将 ECharts 替换为本地文件引用。')
- divider()
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- # 4. 整体界面布局说明
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- heading1('4. 整体界面布局说明')
- body('大屏整体由顶部导航栏 + 内容区域两大部分构成,内容区域按从左到右 2:1.5:4.5:2 的比例划分为四个区域。布局示意如下:')
- doc.add_paragraph()
- # 布局示意表
- table = doc.add_table(rows=3, cols=5)
- table.alignment = WD_TABLE_ALIGNMENT.CENTER
- table.style = 'Table Grid'
- # 第1行:导航栏
- row0 = table.rows[0]
- row0.cells[0].merge(row0.cells[4])
- set_cell_bg(row0.cells[0], C_TH_BG)
- p = row0.cells[0].paragraphs[0]
- p.alignment = WD_ALIGN_PARAGRAPH.CENTER
- add_run(p, '顶部导航栏(时钟 | LOGO + 单位名称 + 系统大标题 | 天气)', bold=True, size=10, color=C_WHITE)
- # 第2行:列标题
- row1 = table.rows[1]
- for i, (txt, bg) in enumerate([
- ('1区(比例2)', C_ROW1),
- ('2区(比例1.5)', C_ROW2),
- ('3区(比例4.5)', C_ROW1),
- ('4区(比例2)', C_ROW2),
- ]):
- if i < 4:
- cell = row1.cells[i]
- set_cell_bg(cell, C_TH_BG if i in [0,2] else RGBColor(0x1d, 0x4e, 0xd8))
- p = cell.paragraphs[0]
- p.alignment = WD_ALIGN_PARAGRAPH.CENTER
- add_run(p, txt, bold=True, size=10, color=C_WHITE)
- # merge last 2 cols for col 4
- # Actually use 4 cols only: remove 5th
- row1.cells[4].merge(row1.cells[3])
- # 第3行:内容描述
- row2 = table.rows[2]
- contents = [
- '• 基本情况统计\n• 安全分级统计\n• 人员进出走势',
- '• 智能环境感知\n 应用设备统计\n• 设备分类及\n 使用统计',
- '实时监控(固定显示)\n左侧:搜索/筛选/树状图\n右侧:9宫格摄像头',
- '• 实验环境安全\n 智能感知\n• 实时风险预警',
- ]
- bgs = [C_ROW1, C_ROW2, C_ROW1, C_ROW2]
- for i, (txt, bg) in enumerate(zip(contents, bgs)):
- cell = row2.cells[i]
- set_cell_bg(cell, bg)
- cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
- p = cell.paragraphs[0]
- p.alignment = WD_ALIGN_PARAGRAPH.LEFT
- add_run(p, txt, size=9.5, color=C_BODY)
- row2.cells[4].merge(row2.cells[3])
- doc.add_paragraph()
- body('各区域均设有科幻装饰线框(四角装饰线)、边框流动动画(border-beam)及动效图标,模块之间有呼吸感的间距,整体采用深蓝科幻主题色系。')
- divider()
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- # 5. 顶部导航栏
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- heading1('5. 顶部导航栏')
- body('导航栏位于页面最顶部,横贯全宽,分为左、中、右三个区域。')
- make_table(
- ['区域', '显示内容', '说明'],
- [
- ['左侧', '实时时钟(时:分:秒)\n日期及星期', '每秒自动更新,金色数字显示,字体采用等宽字体'],
- ['中间', 'LOGO图标\n中国安全生产科学研究院(单位名称)\n竖向分隔线\n实验室安全智能监测与管控中心(系统大标题)', 'LOGO为蓝色方形图标,带脉冲光晕动效;\n大标题采用渐变流光动画,中英文双语单位名称显示'],
- ['右侧', '城市 · 天气状况\n气温(°C) / AQI空气质量指数', '显示当前天气信息及空气质量'],
- ],
- col_widths=[2.5, 7, 6]
- )
- note('导航栏不含任何操作按钮,3区实时监控为固定显示,无需切换。')
- divider()
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- # 6. 1区
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- heading1('6. 1区 — 实验室基本情况统计')
- body('1区位于大屏左侧,由上至下包含三个功能模块。')
- heading2('6.1 实验室基本情况统计')
- body('本模块分为上部(80%)和下部(20%)两部分:')
- doc.add_paragraph()
- heading3('上部(按左4:右6比例划分)')
- bullet('左侧(4):SVG圆弧仪表图形,展示实验室总数(共128间),图形中心显示总数数字,下方配分级比例色条(I级红、II级橙、III级黄、IV级蓝)。', 0)
- bullet('右侧(6):环形图(donut chart),展示四个安全分级(I~IV级)的占比及数量,图外标注各级名称、数量(间)、百分比;图表圆心显示总数;右侧配彩色左边框明细行。', 0)
- doc.add_paragraph()
- heading3('下部(三种状态徽章)')
- bullet('横向并排三个状态徽章,实时显示各状态实验室数量:', 0)
- bullet('使用(绿色):当前正在使用的实验室数量', 1)
- bullet('异常(橙色):当前处于异常告警状态的实验室数量', 1)
- bullet('空闲(靛蓝):当前闲置的实验室数量', 1)
- doc.add_paragraph()
- body('分级说明:')
- make_table(
- ['安全级别', '标识颜色', '含义', '数量(示例)'],
- [
- ['I 级', '红色', '危险实验室', '12 间'],
- ['II 级', '橙色', '较危险实验室', '28 间'],
- ['III 级', '黄色', '一般危险实验室', '45 间'],
- ['IV 级', '蓝色', '较安全实验室', '43 间'],
- ],
- col_widths=[3, 3, 5, 4.5]
- )
- divider()
- heading2('6.2 实验室安全分级统计')
- body('本模块使用堆叠柱状图统计各二级单位实验室总数及分级数据。')
- bullet('X轴:各二级单位名称,单位名称下方显示该单位实验室总数。')
- bullet('Y轴:实验室数量(间)。')
- bullet('每根柱子由I~IV级叠加组成,颜色对应分级(红/橙/黄/蓝)。')
- bullet('图表顶部显示图例(I级、II级、III级、IV级及对应颜色)。')
- bullet('一屏展示6个柱子,当数据量超出时,图表每5秒自动向左滚动1个单位,循环展示所有二级单位数据。')
- doc.add_paragraph()
- note('鼠标悬停在柱状图上可显示当前单位各分级详细数量的悬浮提示框。')
- divider()
- heading2('6.3 实验室进入人数统计及走势')
- body('本模块展示今日实验室进入与在场人数统计,以及全天走势趋势。')
- doc.add_paragraph()
- heading3('数字翻牌器(上方)')
- bullet('今日进入总人数:以翻牌动画形式显示,共4位数字滚动展示,金色高亮。')
- bullet('当前在场实验人数:同样以翻牌动画形式显示,实时更新。')
- heading3('折线图(下方)')
- bullet('X轴:当天0~24小时,按9个时间节点显示(00:00、03:00、06:00…24:00)。')
- bullet('Y轴:人数(人)。')
- bullet('进入人数(蓝色实线+渐变填充)与在场人数(金色实线+渐变填充)双线对比展示。')
- divider()
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- # 7. 2区
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- heading1('7. 2区 — 智能设备与实验室设备统计')
- body('2区位于1区右侧,由上至下包含两个功能模块。')
- heading2('7.1 智能环境感知应用设备统计')
- body('本模块统计展示布设的智能物联应用设备整体情况,分为上部统计栏和下部图表区。')
- doc.add_paragraph()
- heading3('上部统计栏')
- bullet('在线设备数量(绿色高亮,示例:312台)')
- bullet('离线设备数量(红色高亮,示例:18台)')
- heading3('下部图表区(左右布局)')
- bullet('左侧:速度仪表盘样式图表,展示设备在线率百分比(示例:94.5%),金色数字显示。')
- bullet('右侧:2×2网格卡片,分别显示:')
- bullet('电子信息铭牌(86台)', 1)
- bullet('化学品智能终端(44台)', 1)
- bullet('传感器套件(128台)', 1)
- bullet('智能摄像设备(72台)', 1)
- divider()
- heading2('7.2 实验室设备分类及使用统计')
- body('本模块按 4:2:4 比例分为上、中、下三部分:')
- doc.add_paragraph()
- heading3('上部(占4)— 设备分类环形图')
- bullet('使用环形图展示所有实验室设备的分类分布情况。')
- bullet('右侧显示图例:各设备分类的颜色圆点标识、分类名称及数量(台)。')
- body('设备分类示例:', indent=1)
- make_table(
- ['分类', '数量(台)'],
- [
- ['检测设备', '680'],
- ['分析仪器', '520'],
- ['制备设备', '380'],
- ['安全设备', '280'],
- ['辅助设备', '240'],
- ['其他', '358'],
- ],
- col_widths=[7, 8.5]
- )
- heading3('中部(占2)— 汇总统计')
- make_table(
- ['指标', '说明'],
- [
- ['设备总数', '所有实验室设备总数(示例:2,458台)'],
- ['使用总时长', '累计设备使用时长(示例:18,620小时)'],
- ['设备使用率', '当前设备使用率(示例:62.4%)'],
- ],
- col_widths=[4, 11.5]
- )
- heading3('下部(占4)— 设备状态饼图')
- bullet('使用饼图统计各使用状态的设备数量及占比。')
- bullet('右侧显示四种状态的颜色圆点标识及对应数量(台)。')
- make_table(
- ['状态', '说明', '示例数量'],
- [
- ['使用', '当前正在使用中的设备', '486 台'],
- ['空闲', '空置未使用的设备', '1,840 台'],
- ['正常', '状态正常待命的设备', '98 台'],
- ['维修', '正在维修或故障设备', '34 台'],
- ],
- col_widths=[3, 8, 4.5]
- )
- divider()
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- # 8. 3区
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- heading1('8. 3区 — 实时监控')
- body('3区是大屏中央最大区域(比例占4.5),固定显示实时监控视图,分为左侧面板和右侧画面区两部分,无需切换。')
- heading2('8.1 左侧面板(功能操作区)')
- make_table(
- ['功能组件', '说明'],
- [
- ['搜索框', '可输入关键词搜索楼栋、楼层或房间名称'],
- ['二级单位下拉筛选', '下拉选择框,可按化学研究所/物理研究所等单位进行筛选过滤'],
- ['建筑结构树状图', '可展开/折叠的树形结构,层级为:院区 > 楼栋 > 楼层 > 房间\n点击节点可选中并高亮对应监控画面'],
- ],
- col_widths=[4, 11.5]
- )
- heading2('8.2 右侧画面区(9宫格监控)')
- bullet('标题行:左侧显示当前位置面包屑导航(院区 › 楼栋名称 › 楼层),右侧显示翻页按钮(‹ / ›)及页码信息。')
- bullet('9宫格画面:以3×3网格排列9路摄像头画面(16:9比例),每路画面使用Canvas模拟实时视频。')
- bullet('第一路摄像头(AI摄像头)特殊标注:')
- bullet('顶部左角:绿色"🤖 AI检测"徽标', 1)
- bullet('顶部右角:红色 REC 录制指示灯(闪烁)', 1)
- bullet('画面中叠加红色危险行为检测框及标签(如"危险行为: 未佩戴防护")', 1)
- bullet('其余8路摄像头显示常规画面(带室内场景模拟)。')
- note('9宫格摄像头画面为Canvas模拟渲染,不接入真实摄像头信号,如需接入真实视频流请联系IT运维人员进行配置。')
- divider()
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- # 9. 4区
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- heading1('9. 4区 — 实验环境感知与风险预警')
- body('4区位于大屏最右侧,由上至下按7:3比例划分为两个功能模块。')
- heading2('9.1 实验环境安全智能感知(占7)')
- body('本模块展示每间实验室硬件传感器的实时监测数据,区域内由下向上自动滚动展示所有实验室条目(30秒一循环,鼠标悬停自动暂停)。')
- doc.add_paragraph()
- heading3('每条实验室条目包含以下信息:')
- make_table(
- ['信息字段', '说明', '示例'],
- [
- ['实验室名称', '实验室中文名称(房号)', '化学分析实验室(A301)'],
- ['所属单位', '二级单位名称', '化学研究所'],
- ['告警状态', '正常/告警指示图标及文字', '● 正常 / 🚨 告警(闪烁)'],
- ['温度 T', '当前室内温度(°C)', '22.5°C'],
- ['湿度 H', '当前室内相对湿度(%RH)', '58%'],
- ['TVOC', '总挥发性有机化合物浓度(mg/m³)\n超标(>0.6)时标红闪烁', '0.82 mg/m³(红色告警)'],
- ['CO₂', '二氧化碳浓度(ppm)\n超标(>700)时标红闪烁', '650 ppm'],
- ['O₂', '氧气浓度(%)', '20.9%'],
- ],
- col_widths=[3, 7, 5.5]
- )
- body('当某传感器数值超出阈值时,该实验室条目整体高亮为红色渐变效果,并触发全屏预警弹窗(详见第10章)。')
- divider()
- heading2('9.2 实验室实时风险预警(占3)')
- body('本模块展示本月预警响应总数及实时预警通知轮播(22秒一循环,最新通知始终显示在最上方)。')
- doc.add_paragraph()
- heading3('顶部统计')
- bullet('本月预警响应总数:以琥珀色/橙黄色高亮数字显示(示例:42次)。')
- heading3('预警通知列表(每条包含)')
- make_table(
- ['字段', '说明'],
- [
- ['实验室信息', '实验室名称(房号)- 所属二级单位'],
- ['异常指标', '异常传感器类型及当前超标值'],
- ['预警时间', '精确到秒的时间戳(日期-时-分-秒)'],
- ],
- col_widths=[4, 11.5]
- )
- note('预警区域字体采用琥珀/橙色调(#fcd34d / #fb923c),不使用红色字体,区别于传感器告警区域。')
- divider()
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- # 10. 全屏预警弹窗
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- heading1('10. 全屏预警弹窗')
- body('当传感器监测数据超出设定阈值,系统将自动弹出全屏预警弹窗(系统启动约5秒后自动触发演示),以科幻电影系统报警样式呈现。')
- doc.add_paragraph()
- heading2('弹窗布局')
- body('弹窗分为左右两个区域:')
- make_table(
- ['区域', '内容', '说明'],
- [
- ['左侧', '告警实验室实时监控画面\n(900×700 Canvas模拟)', '带红色扫描线、噪点效果;\n叠加AI危险行为检测框;\n顶部显示摄像头编号、REC录制状态;\n底部显示实验室名称及AI检测标识'],
- ['右侧', '告警详细信息', '告警实验室、所属单位、告警指标、当前值/安全阈值四项信息卡片;\n底部显示紧急疏散提示文字(闪烁动效)'],
- ],
- col_widths=[2, 5, 8.5]
- )
- heading2('弹窗操作按钮')
- make_table(
- ['按钮', '功能'],
- [
- ['稍后处理', '关闭弹窗,暂时忽略告警(后续可在4区预警列表查看)'],
- ['确认处理', '关闭弹窗,标记告警已处理'],
- ],
- col_widths=[4, 11.5]
- )
- heading2('弹窗视觉特征')
- bullet('全屏深红色半透明遮罩,背景模糊(backdrop-filter: blur)。')
- bullet('弹窗主体为深红渐变边框,红色扫描线从上到下持续扫描(1.5秒一循环)。')
- bullet('标题"⚡ 系统预警 · ALERT"红色字体,💥 图标快速闪烁动效。')
- note('弹窗为全屏展示,关闭弹窗后系统恢复正常监控状态,预警信息仍保留在4区实时风险预警列表中。')
- divider()
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- # 11. 通用交互说明
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- heading1('11. 通用交互说明')
- make_table(
- ['交互行为', '触发方式', '效果说明'],
- [
- ['全屏显示', '页面加载时自动触发', '请求浏览器进入全屏模式(F11手动切换亦可)'],
- ['图表悬停提示', '鼠标悬停在图表区域', '显示详细数据悬浮提示框(Tooltip)'],
- ['安全分级柱状图滚动', '自动(每5秒)', '自动向左滚动1个X轴单位,循环展示'],
- ['传感器列表滚动', '自动(30秒一循环)', '由下向上平滑滚动,鼠标悬停可暂停'],
- ['预警通知滚动', '自动(22秒一循环)', '由下向上平滑滚动,鼠标悬停可暂停'],
- ['树状图展开/折叠', '点击监控视图左侧树状图节点', '展开或折叠对应子节点'],
- ['关闭预警弹窗', '点击"确认处理"或"稍后处理"按钮', '关闭全屏预警弹窗,恢复正常显示'],
- ],
- col_widths=[4, 5, 6.5]
- )
- divider()
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- # 12. 数据说明
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- heading1('12. 数据说明')
- body('当前版本大屏展示的数据均为内置模拟数据(Demo数据),用于系统功能演示。如需接入真实数据,请由IT运维人员按照以下说明进行后端数据对接。')
- doc.add_paragraph()
- heading2('传感器告警阈值(默认配置)')
- make_table(
- ['传感器指标', '正常范围', '告警阈值', '单位'],
- [
- ['TVOC', '< 0.6', '≥ 0.6', 'mg/m³'],
- ['CO₂', '< 700', '≥ 700', 'ppm'],
- ['O₂', '19.5 ~ 23.5', '< 19.5 或 > 23.5', '%'],
- ['温度', '16 ~ 28', '< 16 或 > 28', '°C'],
- ['湿度', '30 ~ 80', '< 30 或 > 80', '% RH'],
- ],
- col_widths=[4, 4, 5, 2.5]
- )
- heading2('数据刷新说明')
- make_table(
- ['数据模块', '刷新方式'],
- [
- ['实时时钟', '每秒刷新'],
- ['数字翻牌器(进入人数)', '页面加载时动画计数(2秒内完成)'],
- ['传感器数据列表', '页面加载时渲染(静态模拟数据)'],
- ['风险预警列表', '页面加载时渲染(静态模拟数据)'],
- ['ECharts图表', '页面加载时初始化渲染(静态模拟数据)'],
- ['柱状图自动滚动', '每5秒自动切换1个X轴步长'],
- ],
- col_widths=[6, 9.5]
- )
- divider()
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- # 13. FAQ
- # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- heading1('13. 常见问题(FAQ)')
- faqs = [
- ('Q1:打开页面后图表区域空白,没有显示图表?',
- '请检查网络连接是否正常,确保可以访问 cdn.jsdelivr.net(ECharts CDN地址)。如无外网访问条件,请将 ECharts JS 文件下载至本地,并将 HTML 文件头部的 CDN 引用路径改为本地相对路径。'),
- ('Q2:页面一打开就弹出了预警弹窗,如何关闭?',
- '这是系统的演示效果,页面加载约5秒后会自动弹出全屏预警弹窗。点击弹窗右下角的"确认处理"或"稍后处理"按钮即可关闭。'),
- ('Q3:3区实时监控画面不显示或摄像头为黑屏?',
- '9宫格摄像头画面为Canvas模拟渲染,页面加载完成后自动初始化。若画面为黑屏,请刷新页面后等待3~5秒。如需接入真实摄像头,请联系IT运维人员进行后端视频流配置。'),
- ('Q4:页面内容显示不完整或过小,无法正常查看?',
- '本大屏设计分辨率为 9600×2800px,需配合超大屏/拼接屏使用。普通1080p显示器需通过浏览器滚动查看完整内容,或将浏览器缩放比例调整为25%~33%以适配屏幕。'),
- ('Q5:9宫格监控画面是否为真实摄像头接入?',
- '当前版本为Canvas模拟画面,不接入真实摄像头信号。如需接入真实CCTV/RTSP视频流,需进行后端视频推流对接开发,请联系IT运维人员处理。'),
- ('Q6:传感器数据是否实时更新?',
- '当前版本数据为静态模拟数据,页面加载后不会自动刷新传感器数值。如需接入真实IoT传感器数据,需配置WebSocket或轮询接口,由IT运维人员进行后端集成开发。'),
- ('Q7:如何修改告警阈值?',
- '当前阈值配置在 index-v2.html 的 JavaScript 代码中(LABS数组及判断逻辑),修改对应字段的判断条件即可。生产环境建议将阈值配置抽取为后端可配置参数。'),
- ]
- for q, a in faqs:
- p = doc.add_paragraph()
- p.paragraph_format.space_before = Pt(8)
- p.paragraph_format.space_after = Pt(2)
- add_run(p, q, bold=True, size=11, color=C_H2)
- p2 = doc.add_paragraph()
- p2.paragraph_format.space_before = Pt(2)
- p2.paragraph_format.space_after = Pt(6)
- p2.paragraph_format.left_indent = Cm(0.5)
- add_run(p2, 'A:' + a, size=10.5, color=C_BODY)
- divider()
- # ── 页脚说明 ─────────────────────────────────────────────────────
- doc.add_paragraph()
- p = doc.add_paragraph()
- p.alignment = WD_ALIGN_PARAGRAPH.CENTER
- add_run(p, '中国安全生产科学研究院 · 实验室安全智能监测与管控中心 · 使用说明文档 V1.0', size=9, color=C_LABEL)
- p = doc.add_paragraph()
- p.alignment = WD_ALIGN_PARAGRAPH.CENTER
- add_run(p, '本文档仅供内部使用,未经许可不得对外发布。', size=9, italic=True, color=C_LABEL)
- # ── 保存 ────────────────────────────────────────────────────────
- out = r'C:\Users\Administrator\lab-safety-monitor\实验室安全大屏使用说明.docx'
- doc.save(out)
- print(f'已保存:{out}')
|