$ErrorActionPreference = "Stop" function Set-CellFormula { param($Shape, [string]$CellName, [string]$Formula) try { $Shape.CellsU($CellName).FormulaU = $Formula } catch { } } function Set-Page { param($Page, [string]$Name) $Page.Name = $Name $Page.NameU = $Name Set-CellFormula $Page.PageSheet "PageWidth" "13 in" Set-CellFormula $Page.PageSheet "PageHeight" "8.5 in" } function Add-TextBox { param($Page, [string]$Text, [double]$X, [double]$Y, [double]$W, [double]$H, [int]$Size = 9, [string]$Color = "RGB(0,0,0)") $s = $Page.DrawRectangle($X - $W / 2, $Y - $H / 2, $X + $W / 2, $Y + $H / 2) $s.Text = $Text Set-CellFormula $s "LinePattern" "0" Set-CellFormula $s "FillPattern" "0" Set-CellFormula $s "Char.Size" "$Size pt" Set-CellFormula $s "Char.Color" $Color Set-CellFormula $s "Para.HorzAlign" "1" Set-CellFormula $s "VerticalAlign" "1" return $s } function Add-Node { param( $Page, [string]$Text, [double]$X, [double]$Y, [double]$W = 2.35, [double]$H = 0.62, [string]$Fill = "RGB(221,235,247)", [string]$Line = "RGB(91,155,213)" ) $s = $Page.DrawRectangle($X - $W / 2, $Y - $H / 2, $X + $W / 2, $Y + $H / 2) $s.Text = $Text Set-CellFormula $s "FillForegnd" $Fill Set-CellFormula $s "LineColor" $Line Set-CellFormula $s "LineWeight" "1.25 pt" Set-CellFormula $s "Char.Size" "8.5 pt" Set-CellFormula $s "Para.HorzAlign" "1" Set-CellFormula $s "VerticalAlign" "1" return $s } function Add-Arrow { param($Page, [double]$X1, [double]$Y1, [double]$X2, [double]$Y2, [string]$Label = "") $l = $Page.DrawLine($X1, $Y1, $X2, $Y2) Set-CellFormula $l "LineColor" "RGB(89,89,89)" Set-CellFormula $l "LineWeight" "1.1 pt" Set-CellFormula $l "EndArrow" "4" if ($Label -ne "") { Add-TextBox $Page $Label (($X1 + $X2) / 2) (($Y1 + $Y2) / 2 + 0.16) 1.35 0.26 7 "RGB(89,89,89)" | Out-Null } return $l } function Add-Edge { param($Page, $From, $To, [string]$Label = "") $x1 = $From.CellsU("PinX").ResultIU $y1 = $From.CellsU("PinY").ResultIU - $From.CellsU("Height").ResultIU / 2 $x2 = $To.CellsU("PinX").ResultIU $y2 = $To.CellsU("PinY").ResultIU + $To.CellsU("Height").ResultIU / 2 Add-Arrow $Page $x1 $y1 $x2 $y2 $Label | Out-Null } function Add-Legend { param($Page) Add-TextBox $Page "颜色说明:蓝=输入/配置,绿=处理,黄=判断/转换,红=异常/兜底,紫=输出" 6.5 0.35 10.5 0.35 8 "RGB(89,89,89)" | Out-Null } function New-Page { param($Doc, [int]$Index, [string]$Name) if ($Index -eq 1) { $page = $Doc.Pages.Item(1) } else { $page = $Doc.Pages.Add() } Set-Page $page $Name Add-TextBox $page $Name 6.5 8.1 8.8 0.45 16 "RGB(31,78,121)" | Out-Null Add-Legend $page return $page } function Build-MainFlow { param($Doc) $p = New-Page $Doc 1 "主流程" $n = @{} $n.start = Add-Node $p "启动 pq_tool.exe" 6.5 7.25 2.2 0.58 "RGB(226,239,218)" "RGB(112,173,71)" $n.arg = Add-Node $p "判断命令行参数" 6.5 6.35 2.3 0.58 "RGB(255,242,204)" "RGB(191,143,0)" $n.gui = Add-Node $p "无参数:进入 Win32 GUI`nrunPqGuiApp()" 3.0 5.35 2.65 0.72 $n.cli = Add-Node $p "有参数:命令行解析`nXML + jsondata + origin" 10.0 5.35 2.8 0.72 $n.ledger = Add-Node $p "获取台账和 ICD/XML`npqFetchLedgerAndIcd()" 3.0 4.25 2.9 0.72 "RGB(221,235,247)" "RGB(91,155,213)" $n.trace = Add-Node $p "选择测点并数据追踪`n发送 set_log 消息" 3.0 3.15 2.9 0.72 "RGB(226,239,218)" "RGB(112,173,71)" $n.mq = Add-Node $p "MQ 回调落盘`njsondata_*.txt / origin_*.txt" 6.5 2.25 3.0 0.72 "RGB(226,239,218)" "RGB(112,173,71)" $n.parse = Add-Node $p "pqRunParser()`n生成 final_sorted.xls" 6.5 1.28 2.7 0.72 "RGB(226,239,218)" "RGB(112,173,71)" $n.preview = Add-Node $p "表格预览、筛选、编辑`n必要时逆向生成 XML" 10.0 1.28 2.9 0.72 "RGB(234,209,220)" "RGB(166,77,121)" Add-Edge $p $n.start $n.arg Add-Edge $p $n.arg $n.gui "无参数" Add-Edge $p $n.arg $n.cli "有参数" Add-Edge $p $n.gui $n.ledger Add-Edge $p $n.ledger $n.trace Add-Arrow $p 4.45 3.15 5.05 2.45 "" | Out-Null Add-Edge $p $n.trace $n.mq Add-Edge $p $n.mq $n.parse Add-Arrow $p 10.0 4.99 7.2 1.65 "直接解析" | Out-Null Add-Edge $p $n.parse $n.preview } function Build-UiFlow { param($Doc) $p = New-Page $Doc 2 "页面交互流程" $n = @{} $n.config = Add-Node $p "配置项页`n前置 / 接口 / MQ 参数" 2.0 6.8 2.75 0.75 $n.ledgerPage = Add-Node $p "台账列表页`nXML/json/origin/output 路径" 5.0 6.8 2.85 0.75 $n.tree = Add-Node $p "获取台账`n进程 -> 装置 -> 测点树" 8.0 6.8 2.7 0.75 "RGB(226,239,218)" "RGB(112,173,71)" $n.actions = Add-Node $p "按钮动作`n初始化 MQ / 数据追踪 / 一键解析" 11.0 6.8 2.9 0.75 "RGB(255,242,204)" "RGB(191,143,0)" $n.json = Add-Node $p "JSON 详情页`nsent / data / trace 分组" 3.4 4.9 2.85 0.75 $n.preview = Add-Node $p "表格预览页`nSheet、状态、相位、搜索过滤" 6.5 4.9 3.0 0.75 $n.edit = Add-Node $p "双击编辑配置列`n同步 A/B/C 三相" 9.6 4.9 2.85 0.75 "RGB(255,242,204)" "RGB(191,143,0)" $n.xml = Add-Node $p "XML 预览页`n搜索、导出逆向 XML" 6.5 3.0 2.9 0.75 "RGB(234,209,220)" "RGB(166,77,121)" Add-Edge $p $n.config $n.ledgerPage Add-Edge $p $n.ledgerPage $n.tree Add-Edge $p $n.tree $n.actions Add-Arrow $p 10.5 6.43 9.6 5.3 "解析/追踪后刷新" | Out-Null Add-Arrow $p 10.5 6.43 6.5 5.3 "生成工作簿" | Out-Null Add-Arrow $p 3.0 6.43 3.4 5.3 "MQ 事件" | Out-Null Add-Edge $p $n.preview $n.edit Add-Edge $p $n.edit $n.xml "逆向生成" Add-Arrow $p 3.4 4.52 6.5 3.38 "自动解析完成" | Out-Null } function Build-IcdFlow { param($Doc) $p = New-Page $Doc 3 "ICD解析流程" $n = @{} $n.xml = Add-Node $p "ICD/XML 模板文件" 2.0 7.0 2.4 0.62 $n.load = Add-Node $p "loadValueMetas()`n递归遍历 XML" 4.8 7.0 2.55 0.72 "RGB(226,239,218)" "RGB(112,173,71)" $n.ctx = Add-Node $p "继承上下文`nTopic/DataType/Item/Sequence" 7.8 7.0 3.0 0.72 "RGB(255,242,204)" "RGB(191,143,0)" $n.meta = Add-Node $p "生成 ValueMeta`nname/desc/DO/DA/wiring/offset" 10.8 7.0 3.05 0.72 "RGB(226,239,218)" "RGB(112,173,71)" $n.flag = Add-Node $p "标志转换`nSequence 7=star,112=delta`n%start,end%=序列模板" 4.0 5.45 3.25 0.9 "RGB(255,242,204)" "RGB(191,143,0)" $n.json = Add-Node $p "jsondata 压平`nValue_V_A_MAX_V1 -> value" 7.1 5.45 3.0 0.72 $n.merge = Add-Node $p "mergeSequences()`n连续编号 -> [start-end]" 10.2 5.45 3.0 0.72 "RGB(226,239,218)" "RGB(112,173,71)" $n.sheet = Add-Node $p "按 SheetSpec 生成行`nHISDATA/RTDATA + DATA_TYPE + 接线" 5.6 3.85 3.35 0.82 "RGB(226,239,218)" "RGB(112,173,71)" $n.origin = Add-Node $p "origin 路径匹配`nDO + 相位化 DA + 数组区间" 8.8 3.85 3.25 0.82 "RGB(226,239,218)" "RGB(112,173,71)" $n.out = Add-Node $p "写出 final_sorted.xls`n正常/异常/缺失/未匹配" 7.2 2.3 3.05 0.75 "RGB(234,209,220)" "RGB(166,77,121)" $n.import = Add-Node $p "导入外部 ICD`nLN/DOI desc -> 未匹配页字段说明" 7.2 1.15 4.0 0.75 "RGB(234,209,220)" "RGB(166,77,121)" Add-Edge $p $n.xml $n.load Add-Edge $p $n.load $n.ctx Add-Edge $p $n.ctx $n.meta Add-Arrow $p 10.0 6.64 5.0 5.85 "Value/@name" | Out-Null Add-Edge $p $n.json $n.merge Add-Arrow $p 10.2 5.09 8.8 4.28 "" | Out-Null Add-Arrow $p 4.0 5.00 5.6 4.28 "" | Out-Null Add-Edge $p $n.sheet $n.out Add-Edge $p $n.origin $n.out Add-Edge $p $n.out $n.import } function Build-TraceFlow { param($Doc) $p = New-Page $Doc 4 "数据追踪流程" $n = @{} $n.sel = Add-Node $p "左侧树选择测点`ndevice + monitor" 2.2 7.0 2.6 0.72 $n.dir = Add-Node $p "pqTraceDirectoryFor()`nprocess/device/monitor 目录" 5.1 7.0 3.0 0.72 "RGB(226,239,218)" "RGB(112,173,71)" $n.clean = Add-Node $p "清空旧文本记录`n准备 json/origin/output 路径" 8.2 7.0 3.1 0.72 "RGB(226,239,218)" "RGB(112,173,71)" $n.payload = Add-Node $p "pqBuildTracePayload()`nguid + set_log + frontType" 11.1 7.0 3.0 0.72 "RGB(255,242,204)" "RGB(191,143,0)" $n.ctx = Add-Node $p "setTraceTarget()`n写 trace_context.json" 3.6 5.45 2.9 0.72 "RGB(226,239,218)" "RGB(112,173,71)" $n.send = Add-Node $p "RocketMQ 可用?" 6.5 5.45 2.35 0.62 "RGB(255,242,204)" "RGB(191,143,0)" $n.mq = Add-Node $p "同步发送 TopicLOG`nTagLOG / KeyLOG" 9.3 5.45 2.65 0.72 "RGB(226,239,218)" "RGB(112,173,71)" $n.outbox = Add-Node $p "不可用:写 mq_outbox_*.jsonl" 9.3 4.35 2.95 0.62 "RGB(244,204,204)" "RGB(192,0,0)" $n.cb = Add-Node $p "MQ 消费回调`nTopic/Tag + monitorId/guid 路由" 3.6 3.45 3.25 0.82 "RGB(226,239,218)" "RGB(112,173,71)" $n.data = Add-Node $p "DATATopic`nDATA_TYPE 去重 -> jsondata_*.txt" 6.9 3.45 3.25 0.82 "RGB(226,239,218)" "RGB(112,173,71)" $n.trace = Add-Node $p "TraceTopic`n时间戳过滤 -> origin_*.txt" 10.2 3.45 3.25 0.82 "RGB(226,239,218)" "RGB(112,173,71)" $n.auto = Add-Node $p "PostMessage 到 GUI`nautoParseTraceDir()" 6.9 1.95 3.0 0.75 "RGB(234,209,220)" "RGB(166,77,121)" Add-Edge $p $n.sel $n.dir Add-Edge $p $n.dir $n.clean Add-Edge $p $n.clean $n.payload Add-Arrow $p 10.2 6.64 4.5 5.85 "" | Out-Null Add-Edge $p $n.ctx $n.send Add-Edge $p $n.send $n.mq "是" Add-Arrow $p 6.5 5.14 8.1 4.45 "否" | Out-Null Add-Arrow $p 9.3 5.09 3.6 3.88 "收到消息" | Out-Null Add-Edge $p $n.cb $n.data Add-Edge $p $n.data $n.trace Add-Arrow $p 6.9 3.04 6.9 2.33 "文件到齐后" | Out-Null } function Build-ReverseXmlFlow { param($Doc) $p = New-Page $Doc 5 "逆向生成XML流程" $n = @{} $n.preview = Add-Node $p "表格预览页`n读取 final_sorted.xls" 2.0 7.0 2.75 0.72 $n.edit = Add-Node $p "双击编辑配置列`n数组基准/偏移/DO/DA" 5.0 7.0 3.0 0.72 "RGB(255,242,204)" "RGB(191,143,0)" $n.sync = Add-Node $p "commitPreviewEdit()`n同步 A/B/C 三相并置 dirty" 8.2 7.0 3.15 0.72 "RGB(226,239,218)" "RGB(112,173,71)" $n.rows = Add-Node $p "collectReverseRows()`n只采集数据行和改动行" 11.1 7.0 3.0 0.72 "RGB(226,239,218)" "RGB(112,173,71)" $n.spec = Add-Node $p "reverseSpecForSheet()`nSheet 名 -> Topic/DataType/wiring" 3.6 5.4 3.35 0.82 "RGB(255,242,204)" "RGB(191,143,0)" $n.xml = Add-Node $p "读取原始 XML`ncollectValueNodes()" 6.9 5.4 2.9 0.72 $n.match = Add-Node $p "reverseNodeMatches()`n优先原始 DO/DA,再 name/desc" 10.2 5.4 3.35 0.82 "RGB(226,239,218)" "RGB(112,173,71)" $n.convert = Add-Node $p "标志还原`n[start-end] -> %start,end%`n[offset] -> [%offset]" 5.1 3.75 3.45 0.92 "RGB(255,242,204)" "RGB(191,143,0)" $n.update = Add-Node $p "更新 Value 属性`nname / DO / DA / Offset" 8.5 3.75 3.0 0.72 "RGB(226,239,218)" "RGB(112,173,71)" $n.out = Add-Node $p "XML 预览页`n搜索 / 导出 xml 或 icd" 6.8 2.15 3.0 0.75 "RGB(234,209,220)" "RGB(166,77,121)" Add-Edge $p $n.preview $n.edit Add-Edge $p $n.edit $n.sync Add-Edge $p $n.sync $n.rows Add-Arrow $p 10.2 6.64 4.3 5.82 "" | Out-Null Add-Edge $p $n.spec $n.xml Add-Edge $p $n.xml $n.match Add-Arrow $p 10.2 4.98 8.5 4.15 "匹配到节点" | Out-Null Add-Edge $p $n.convert $n.update Add-Edge $p $n.update $n.out } $outDir = $PSScriptRoot $outPath = Join-Path $outDir "pq_tool_flowcharts.vsdx" $visio = $null $doc = $null try { $visio = New-Object -ComObject Visio.Application $visio.Visible = $false $visio.AlertResponse = 7 $doc = $visio.Documents.Add("") Build-MainFlow $doc Build-UiFlow $doc Build-IcdFlow $doc Build-TraceFlow $doc Build-ReverseXmlFlow $doc if (Test-Path -LiteralPath $outPath) { Remove-Item -LiteralPath $outPath -Force } $doc.SaveAs($outPath) Write-Host "[OK] Saved $outPath" } finally { if ($doc -ne $null) { try { $doc.Close() } catch {} [System.Runtime.InteropServices.Marshal]::ReleaseComObject($doc) | Out-Null } if ($visio -ne $null) { try { $visio.Quit() } catch {} [System.Runtime.InteropServices.Marshal]::ReleaseComObject($visio) | Out-Null } [GC]::Collect() [GC]::WaitForPendingFinalizers() }