param( [string]$OutputDirectory = '' ) $ErrorActionPreference = 'Stop' Add-Type -AssemblyName System.Drawing $scriptRoot = $PSScriptRoot $root = (Resolve-Path (Join-Path $scriptRoot '..\..')).Path $docDir = if ($OutputDirectory) { $OutputDirectory } else { Join-Path $root 'doc' } $assetDir = Join-Path $scriptRoot 'assets' $fileBase = '大连元利流体技术有限公司MES系统标准设计文档_V1.0_2026-07-24' $docxPath = Join-Path $docDir ($fileBase + '.docx') $pdfPath = Join-Path $docDir ($fileBase + '.pdf') $buildLog = Join-Path $scriptRoot 'build.log' New-Item -ItemType Directory -Force -Path $docDir, $assetDir | Out-Null [IO.File]::WriteAllText($buildLog, "开始生成 $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')`r`n", [Text.Encoding]::UTF8) function Write-ProgressLog { param([string]$Message) [IO.File]::AppendAllText($buildLog, "$(Get-Date -Format 'HH:mm:ss') $Message`r`n", [Text.Encoding]::UTF8) } function New-Canvas { param([int]$Width = 1800, [int]$Height = 980) $bitmap = New-Object System.Drawing.Bitmap $Width, $Height $graphics = [System.Drawing.Graphics]::FromImage($bitmap) $graphics.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias $graphics.TextRenderingHint = [System.Drawing.Text.TextRenderingHint]::AntiAliasGridFit $graphics.Clear([System.Drawing.Color]::FromArgb(248, 250, 252)) return @($bitmap, $graphics) } function Draw-Box { param( [System.Drawing.Graphics]$Graphics, [int]$X, [int]$Y, [int]$Width, [int]$Height, [string]$Title, [string]$Detail, [System.Drawing.Color]$Fill, [System.Drawing.Color]$Border = [System.Drawing.Color]::FromArgb(64, 80, 96) ) $rect = New-Object System.Drawing.Rectangle $X, $Y, $Width, $Height $brush = New-Object System.Drawing.SolidBrush $Fill $pen = New-Object System.Drawing.Pen $Border, 3 $Graphics.FillRectangle($brush, $rect) $Graphics.DrawRectangle($pen, $rect) $titleFont = New-Object System.Drawing.Font 'Microsoft YaHei', 21, ([System.Drawing.FontStyle]::Bold), ([System.Drawing.GraphicsUnit]::Pixel) $detailFont = New-Object System.Drawing.Font 'Microsoft YaHei', 16, ([System.Drawing.FontStyle]::Regular), ([System.Drawing.GraphicsUnit]::Pixel) $textBrush = New-Object System.Drawing.SolidBrush ([System.Drawing.Color]::FromArgb(30, 41, 59)) $format = New-Object System.Drawing.StringFormat $format.Alignment = [System.Drawing.StringAlignment]::Center $format.LineAlignment = [System.Drawing.StringAlignment]::Center $titleRect = New-Object System.Drawing.RectangleF ($X + 12), ($Y + 8), ($Width - 24), ([Math]::Min(48, $Height * 0.36)) $detailRect = New-Object System.Drawing.RectangleF ($X + 14), ($Y + 48), ($Width - 28), ($Height - 54) $Graphics.DrawString($Title, $titleFont, $textBrush, $titleRect, $format) $Graphics.DrawString($Detail, $detailFont, $textBrush, $detailRect, $format) $format.Dispose(); $textBrush.Dispose(); $detailFont.Dispose(); $titleFont.Dispose(); $pen.Dispose(); $brush.Dispose() } function Draw-Arrow { param([System.Drawing.Graphics]$Graphics, [int]$X1, [int]$Y1, [int]$X2, [int]$Y2, [string]$Label = '') $pen = New-Object System.Drawing.Pen ([System.Drawing.Color]::FromArgb(71, 85, 105)), 4 $pen.CustomEndCap = New-Object System.Drawing.Drawing2D.AdjustableArrowCap 6, 7 $Graphics.DrawLine($pen, $X1, $Y1, $X2, $Y2) if ($Label) { $font = New-Object System.Drawing.Font 'Microsoft YaHei', 14, ([System.Drawing.FontStyle]::Regular), ([System.Drawing.GraphicsUnit]::Pixel) $brush = New-Object System.Drawing.SolidBrush ([System.Drawing.Color]::FromArgb(71, 85, 105)) $Graphics.DrawString($Label, $font, $brush, (($X1 + $X2) / 2 - 40), (($Y1 + $Y2) / 2 - 25)) $brush.Dispose(); $font.Dispose() } $pen.Dispose() } function Save-Canvas { param([System.Drawing.Bitmap]$Bitmap, [System.Drawing.Graphics]$Graphics, [string]$Path) $Graphics.Dispose() $Bitmap.Save($Path, [System.Drawing.Imaging.ImageFormat]::Png) $Bitmap.Dispose() } function Build-Diagrams { $blue = [System.Drawing.Color]::FromArgb(219, 234, 254) $teal = [System.Drawing.Color]::FromArgb(204, 251, 241) $amber = [System.Drawing.Color]::FromArgb(254, 243, 199) $green = [System.Drawing.Color]::FromArgb(220, 252, 231) $gray = [System.Drawing.Color]::FromArgb(226, 232, 240) $red = [System.Drawing.Color]::FromArgb(254, 226, 226) $canvas = New-Canvas 1800 960; $b = $canvas[0]; $g = $canvas[1] Draw-Box $g 60 80 270 150 '用户访问层' 'Chrome / Edge`nPC 与车间终端' $blue Draw-Box $g 420 80 350 150 'MES 前端' 'Vue 2.7 + Element UI`n动态菜单、业务交互、报表' $teal Draw-Box $g 860 80 380 150 'MES 通用服务' 'HTTPS / MESCommonBase.ashx`n过程调用、上传下载、日志' $amber Draw-Box $g 1330 80 390 150 'SQL Server' 'YL_MESDB`n业务数据、视图、存储过程' $green Draw-Arrow $g 330 155 420 155 'HTTPS'; Draw-Arrow $g 770 155 860 155 'JSON'; Draw-Arrow $g 1240 155 1330 155 'T-SQL' Draw-Box $g 420 380 350 140 'SAP B1 代理服务' 'B1 Service Layer`nGET / POST / PATCH' $blue Draw-Box $g 860 380 380 140 'TM 开放接口' '领料、库存及相关业务接口' $teal Draw-Box $g 1330 380 390 140 '文件服务' '图纸、附件上传与下载' $gray Draw-Arrow $g 595 230 595 380 '业务集成'; Draw-Arrow $g 1050 230 1050 380 '业务集成'; Draw-Arrow $g 1525 230 1525 380 '文件' Draw-Box $g 420 680 350 140 'AGV / 物流接口' '搬运任务下发与状态维护' $amber Draw-Box $g 860 680 380 140 '设备 / MQTT' '设备变量读取、写入与状态采集' $red Draw-Box $g 1330 680 390 140 '质量与看板接口' 'SPC、趋势图、实时监控' $blue Draw-Arrow $g 595 520 595 680; Draw-Arrow $g 1050 520 1050 680; Draw-Arrow $g 1525 520 1525 680 Save-Canvas $b $g (Join-Path $assetDir 'logical-architecture.png') $canvas = New-Canvas 1800 930; $b = $canvas[0]; $g = $canvas[1] $steps = @( @('ERP 订单', '销售/生产订单、物料、BOM', $blue), @('工艺准备', '标准工艺、生产工艺、图纸', $teal), @('计划排产', '工位、人员、数量与时间', $amber), @('任务下发', '形成工序任务并进入执行队列', $green), @('生产执行', '收料、开工、暂停、报工、送检', $blue), @('质量闭环', '首检、序检、收检、终检、不合格处置', $red), @('完工交付', '工时校验、订单关闭、入库与发货', $green) ) for ($i = 0; $i -lt $steps.Count; $i++) { $x = 65 + ($i % 4) * 430; $y = if ($i -lt 4) { 130 } else { 540 } Draw-Box $g $x $y 335 170 $steps[$i][0] $steps[$i][1] $steps[$i][2] if ($i -lt 3) { Draw-Arrow $g ($x + 335) ($y + 85) ($x + 430) ($y + 85) } if ($i -eq 3) { Draw-Arrow $g ($x + 165) ($y + 170) ($x + 165) 455 '进入执行' } if ($i -ge 4 -and $i -lt 6) { Draw-Arrow $g ($x + 335) ($y + 85) ($x + 430) ($y + 85) } } Draw-Arrow $g 1510 540 1510 410; Draw-Arrow $g 1510 410 280 410 '异常、返工、计划调整反馈' Save-Canvas $b $g (Join-Path $assetDir 'business-flow.png') $canvas = New-Canvas 1800 900; $b = $canvas[0]; $g = $canvas[1] Draw-Box $g 80 100 300 150 '账号登录' '用户名、密码验证' $blue Draw-Box $g 500 100 300 150 '角色选择' '一个账号可对应多个角色' $teal Draw-Box $g 920 100 360 150 '菜单权限读取' '按角色加载菜单及增删改查权限' $amber Draw-Box $g 1400 100 300 150 '动态路由' '仅挂载可访问页面' $green Draw-Arrow $g 380 175 500 175; Draw-Arrow $g 800 175 920 175; Draw-Arrow $g 1280 175 1400 175 Draw-Box $g 300 500 360 160 '页面业务请求' '携带 UserID、UserName、ModularID' $blue Draw-Box $g 800 500 360 160 '服务端校验与执行' '校验身份、参数与业务规则' $teal Draw-Box $g 1300 500 360 160 '审计与结果' '记录操作上下文并返回结果' $gray Draw-Arrow $g 1550 250 480 500 '进入业务页面'; Draw-Arrow $g 660 580 800 580; Draw-Arrow $g 1160 580 1300 580 Save-Canvas $b $g (Join-Path $assetDir 'permission-flow.png') $canvas = New-Canvas 1800 900; $b = $canvas[0]; $g = $canvas[1] Draw-Box $g 80 110 330 170 '浏览器终端' '访问 MES Web 站点`n建议统一受管浏览器版本' $blue Draw-Box $g 530 110 340 170 'Web 静态资源' 'index.html、JS、CSS`nstatic/config.js 环境配置' $teal Draw-Box $g 990 110 340 170 '应用服务' '10101:MES 通用服务`n9996:B1/TM 代理服务' $amber Draw-Box $g 1410 110 310 170 '数据库服务' '192.168.2.92`nSQL Server / YL_MESDB' $green Draw-Arrow $g 410 195 530 195 'HTTPS'; Draw-Arrow $g 870 195 990 195 'HTTPS'; Draw-Arrow $g 1330 195 1410 195 '内网' Draw-Box $g 300 570 360 150 'SAP B1' 'ERP 主数据、订单、库存' $blue Draw-Box $g 800 570 360 150 '文件与图纸' '上传、下载、在线预览' $gray Draw-Box $g 1300 570 360 150 'AGV / 设备侧' '9981 AGV 接口及设备通信' $red Draw-Arrow $g 1160 280 480 570; Draw-Arrow $g 1160 280 980 570; Draw-Arrow $g 1160 280 1480 570 Save-Canvas $b $g (Join-Path $assetDir 'deployment-topology.png') } Build-Diagrams Write-ProgressLog '已生成四张技术架构与流程图' $modulePages = [ordered]@{ '系统管理' = @('人员管理', '角色管理', '菜单管理', '工位管理', '报工操作记录') '设备管理' = @('设备信息维护', '设备数据', '设备历史数据', '实时数据') '研发管理' = @('设计任务', '设计报工', '设计工时校验', '设计工时报表', '研发财务工时') '工艺管理' = @('工序管理', '制定标准工艺', '生产工艺', '工艺查询', '工艺任务', '图纸维护', '工艺维护', '查看图纸', '采购图纸查询') '计划排产' = @('机加件排产', '装配件排产', '机加件已排产', '机加件未排产', '优先装配', '计划用表', '装配未排产', '生产订单关闭', '工位任务汇总', '装配已排产', '系统类装配任务', '阀类装配任务', '及时齐套跟踪结果') '生产管理' = @('生产计划跟踪', '加工中心', '过程异常管控', '工时校验', '外协管理', '人员绑定', '装配中心', '班次管理', '工时报表', '加急件管理', '拣配任务', '采购外协管理', '工时查询', '机加正在进行中', '装配状态', '外协报表', '工时修正', '物料机器人', '手续确认报表', '发货通知列表', '结算工时') '异常提醒' = @('机加及时开工', '外协及时开工', '加急任务列表', '装配及时送检') '质量管理' = @('终检', '采购入库检', '销售退货检', '原材料退库检', '序检收检', '质量检验标准', '其他入库检', '质检明细', '不合格品处置', '质检报工', '测试装配任务', '及时检验报表', '产品合格率(工位)') '销售订单管理' = @('销售订单状态') } $moduleDesign = @( @('系统管理', '账号、角色、菜单、工位及操作审计', '人员/角色/菜单基础数据', '全部业务模块的登录与权限基础'), @('设备管理', '维护设备台账并查看实时与历史数据', '设备、工位、采集变量', '生产执行、设备看板和设备分析'), @('研发管理', '设计任务分派、报工、校验与财务工时', '研发项目、任务、人员、报工记录', '工时统计、成本核算和项目复盘'), @('工艺管理', '维护工序、标准工艺、订单工艺及图纸', '物料、工序、标准工艺、订单工艺、图纸', '计划排产、任务下发、生产执行和检验标准'), @('计划排产', '将订单工艺分配到工位、人员和时间', '生产订单、工艺路线、资源与日历', '生产任务、齐套跟踪、工位负荷和异常提醒'), @('生产管理', '执行收料、开工、暂停、报工、送检和工时闭环', '工序任务、人员、设备、物料和操作记录', '质量检验、完工关闭、工时报表和交付状态'), @('异常提醒', '识别未及时开工、未及时送检和加急事项', '计划时间、实际时间、任务状态', '计划调整、现场督办和管理看板'), @('质量管理', '执行质量标准、检验、判定与不合格处置', '检验任务、标准、实测值、量具和处置记录', '任务流转、入库、返工/让步/报废和质量统计'), @('销售订单管理', '汇总订单从计划到交付的全流程状态', 'SAP 销售订单与 MES 生产/质量/交付数据', '交付协调、客户响应和经营分析') ) $techStack = @( @('前端框架', 'Vue.js', '2.7.16', '单页应用与组件体系'), @('UI 组件', 'Element UI', '2.15.14', '表单、表格、弹窗、分页'), @('路由', 'Vue Router', '3.6.5', '动态权限路由'), @('状态管理', 'Vuex', '3.6.2', '用户、角色、标签页等全局状态'), @('HTTP', 'Axios', '0.21.4', 'MES、SAP B1、TM 与其他服务调用'), @('图表', 'ECharts', '5.4.3', '看板和统计图'), @('日历排程', 'FullCalendar', '6.1.x', '计划日历与排产交互'), @('设备通信', 'MQTT.js', '4.3.7', '设备与实时数据通信'), @('文档与报表', 'xlsx / jsPDF / pdfjs / docxtemplater', '见 package.json', '导入导出、PDF预览和模板生成'), @('构建工具', 'Webpack', '5.89.0', '开发服务、生产构建和代码分包'), @('数据库', 'Microsoft SQL Server', '2019 / 兼容级别150', 'YL_MESDB 业务数据与过程层') ) $word = $null; $doc = $null try { $word = New-Object -ComObject Word.Application $word.Visible = $false $word.DisplayAlerts = 0 $doc = $word.Documents.Add() $selection = $word.Selection $normal = $doc.Styles.Item(-1) $section = $doc.Sections.Item(1) $section.PageSetup.PaperSize = 7 $section.PageSetup.TopMargin = $word.CentimetersToPoints(2.3) $section.PageSetup.BottomMargin = $word.CentimetersToPoints(2.0) $section.PageSetup.LeftMargin = $word.CentimetersToPoints(2.4) $section.PageSetup.RightMargin = $word.CentimetersToPoints(2.1) $section.PageSetup.HeaderDistance = $word.CentimetersToPoints(1.0) $section.PageSetup.FooterDistance = $word.CentimetersToPoints(1.0) $section.PageSetup.DifferentFirstPageHeaderFooter = -1 $normal.Font.NameFarEast = '宋体'; $normal.Font.Name = 'Arial'; $normal.Font.Size = 10.5 $normal.ParagraphFormat.LineSpacingRule = 1 $normal.ParagraphFormat.LineSpacing = 18 $normal.ParagraphFormat.SpaceAfter = 6 foreach ($item in @(@(-2, 16, 0x8F4A31), @(-3, 13, 0x8F4A31), @(-4, 11, 0x6B594F))) { $style = $doc.Styles.Item($item[0]) $style.Font.NameFarEast = '微软雅黑'; $style.Font.Name = 'Arial'; $style.Font.Size = $item[1] $style.Font.Bold = 1; $style.Font.Color = $item[2] $style.ParagraphFormat.KeepWithNext = -1; $style.ParagraphFormat.SpaceBefore = 10; $style.ParagraphFormat.SpaceAfter = 6 } function Move-End { $selection.SetRange($doc.Content.End - 1, $doc.Content.End - 1) } function Add-Text { param([string]$Text, [double]$Size = 10.5, [bool]$Bold = $false, [int]$Align = 0, [int]$Color = 0, [double]$Before = 0, [double]$After = 6, [double]$FirstIndentCm = 0.74) $selection.Style = $normal $selection.Font.NameFarEast = '宋体'; $selection.Font.Name = 'Arial'; $selection.Font.Size = $Size $selection.Font.Bold = [int]$Bold; $selection.Font.Color = $Color $selection.ParagraphFormat.Alignment = $Align; $selection.ParagraphFormat.SpaceBefore = $Before; $selection.ParagraphFormat.SpaceAfter = $After $selection.ParagraphFormat.FirstLineIndent = $word.CentimetersToPoints($FirstIndentCm) $selection.TypeText($Text); $selection.TypeParagraph() } function Add-Heading { param([string]$Text, [int]$Level = 1) $styleId = switch ($Level) { 1 { -2 } 2 { -3 } default { -4 } } $selection.Style = $doc.Styles.Item($styleId) $selection.TypeText($Text); $selection.TypeParagraph(); $selection.Style = $normal } function Add-Bullet { param([string]$Text, [int]$Level = 1) $selection.Style = $normal $selection.Range.ListFormat.ApplyBulletDefault() $selection.ParagraphFormat.LeftIndent = $word.CentimetersToPoints(0.75 + (($Level - 1) * 0.65)) $selection.ParagraphFormat.FirstLineIndent = $word.CentimetersToPoints(-0.5) $selection.TypeText($Text); $selection.TypeParagraph(); $selection.Range.ListFormat.RemoveNumbers() $selection.ParagraphFormat.LeftIndent = 0; $selection.ParagraphFormat.FirstLineIndent = 0 } function Add-Number { param([string]$Text) $selection.Style = $normal $selection.Range.ListFormat.ApplyNumberDefault(); $selection.ParagraphFormat.LeftIndent = $word.CentimetersToPoints(0.75) $selection.TypeText($Text); $selection.TypeParagraph(); $selection.Range.ListFormat.RemoveNumbers(); $selection.ParagraphFormat.LeftIndent = 0 } function Add-Table { param([object[]]$Rows, [double[]]$WidthsCm = @(), [double]$FontSize = 8.7) if ($Rows.Count -eq 0) { return } Write-ProgressLog ("写入表格:{0}行 x {1}列,首项={2}" -f $Rows.Count, $Rows[0].Count, [string]$Rows[0][0]) $table = $doc.Tables.Add($selection.Range, $Rows.Count, $Rows[0].Count) $table.Borders.Enable = 1; $table.AllowAutoFit = -1 $table.Range.Font.NameFarEast = '宋体'; $table.Range.Font.Name = 'Arial'; $table.Range.Font.Size = $FontSize $table.Range.ParagraphFormat.SpaceAfter = 0; $table.Range.ParagraphFormat.LineSpacingRule = 0 for ($r = 0; $r -lt $Rows.Count; $r++) { for ($c = 0; $c -lt $Rows[$r].Count; $c++) { $cell = $table.Cell($r + 1, $c + 1) $cell.Range.Text = [string]$Rows[$r][$c] $cell.VerticalAlignment = 1 } } for ($c = 0; $c -lt $WidthsCm.Count -and $c -lt $table.Columns.Count; $c++) { $table.Columns.Item($c + 1).Width = $word.CentimetersToPoints($WidthsCm[$c]) } $table.Rows.Item(1).Range.Bold = 1 $table.Rows.Item(1).Range.Font.NameFarEast = '微软雅黑' $table.Rows.Item(1).Range.ParagraphFormat.Alignment = 1 $table.Rows.Item(1).Shading.BackgroundPatternColor = 0xE6D8D0 $table.Rows.Item(1).HeadingFormat = -1 $table.Rows.AllowBreakAcrossPages = 0 if ($Rows.Count -le 6) { for ($rowIndex = 1; $rowIndex -lt $table.Rows.Count; $rowIndex++) { $table.Rows.Item($rowIndex).Range.ParagraphFormat.KeepWithNext = -1 } } $selection.SetRange($table.Range.End, $table.Range.End); $selection.TypeParagraph() } function Add-Note { param([string]$Title, [string]$Text, [string]$Kind = 'info') $table = $doc.Tables.Add($selection.Range, 1, 1) $table.Borders.Enable = 1 $cell = $table.Cell(1, 1); $cell.Range.Text = "$Title:$Text" $cell.Range.Font.NameFarEast = '微软雅黑'; $cell.Range.Font.Name = 'Arial'; $cell.Range.Font.Size = 9.5 $cell.Range.ParagraphFormat.SpaceAfter = 0 $cell.Shading.BackgroundPatternColor = switch ($Kind) { 'warn' { 0xD9F2FF } 'risk' { 0xD9E2F3 } default { 0xEAF4E4 } } $selection.SetRange($table.Range.End, $table.Range.End); $selection.TypeParagraph() } function Add-Image { param([string]$Path, [double]$WidthCm = 16.0, [string]$Caption = '') $selection.ParagraphFormat.Alignment = 1; $selection.ParagraphFormat.FirstLineIndent = 0 $shape = $selection.InlineShapes.AddPicture($Path, $false, $true) $shape.LockAspectRatio = -1; $shape.Width = $word.CentimetersToPoints($WidthCm) $selection.TypeParagraph() if ($Caption) { Add-Text $Caption 9 $false 1 0 0 8 0 } } function Add-PageBreak { $selection.InsertBreak(7) } # 封面 Add-Text '大连元利流体技术有限公司' 18 $true 1 0x8F4A31 65 12 0 Add-Text 'MES 系统标准设计文档' 28 $true 1 0x51352A 70 16 0 Add-Text 'System Design Specification' 15 $false 1 0x6B594F 0 70 0 $coverRows = @( @('文档编号', 'YL-MES-TECH-001'), @('系统版本', 'V1.1.0'), @('文档版本', 'V1.0'), @('基线日期', '2026-07-24'), @('文档属性', '内部技术资料'), @('适用范围', 'MES 实施、开发、测试、运维及审计') ) Add-Table $coverRows @(4.2, 9.0) 10 Add-Text '编制依据:当前前端源代码、正式菜单配置、正式数据库只读元数据及现有业务技术资料' 9.5 $false 1 0x666666 55 0 0 Add-PageBreak Add-Heading '文档控制' 1 Add-Heading '修订记录' 2 Add-Table @( @('版本', '日期', '修订内容', '状态'), @('V1.0', '2026-07-24', '首次形成系统级标准设计文档,覆盖现状架构、部署、权限、数据、接口、运维与验收规范', '正式基线') ) @(2.0, 2.8, 10.0, 2.2) Add-Heading '审批与分发' 2 Add-Table @( @('角色', '职责', '签署/日期'), @('业务负责人', '确认业务边界和关键流程', ''), @('技术负责人', '确认架构、接口、数据与变更方案', ''), @('运维负责人', '确认部署、备份、监控和应急流程', ''), @('质量/测试负责人', '确认测试范围与验收证据', '') ) @(3.2, 9.2, 4.6) Add-Note '保密要求' '本文档包含正式环境拓扑、内部接口约定和数据库对象信息,仅限授权的实施、开发、测试、运维及审计人员使用。账号、口令、私钥和 SAP 会话信息不得写入正文或版本库。' 'warn' Add-PageBreak Add-Heading '目录' 1 $tocRange = $selection.Range [void]$doc.TablesOfContents.Add($tocRange, $true, 1, 3) Move-End; Add-PageBreak Add-Heading '1 文档说明' 1 Add-Heading '1.1 目的' 2 Add-Text '本文档定义 MES 系统当前系统设计基线,并给出部署、配置、权限、数据、接口、运维、变更和验收的统一要求。它用于技术交接和持续维护,不替代面向最终用户的操作手册。' Add-Heading '1.2 适用对象' 2 foreach ($t in @('实施人员:确认网络、服务、数据库、外部系统和上线条件。','开发人员:理解代码结构、请求约定、模块边界、数据链路和变更规则。','测试人员:依据关键状态、接口契约和验收清单设计测试。','运维人员:执行部署、监控、备份、恢复、故障定位和应急处置。','审计与管理人员:核对权限、日志、变更记录和数据保护措施。')) { Add-Bullet $t } Add-Heading '1.3 事实与规范的区分' 2 Add-Table @( @('标识', '含义', '使用方式'), @('当前实现', '由代码、配置或正式数据库只读元数据确认的现状', '用于复现和维护当前系统'), @('标准要求', '后续建设、变更和运维应遵循的控制要求', '作为评审和验收依据'), @('改进建议', '现状可运行但存在安全、可维护性或恢复能力风险', '纳入版本计划,评估后实施') ) @(3.0, 7.0, 7.0) Add-Heading '1.4 基线与范围' 2 Add-Table @( @('项目', '基线值'), @('项目目录', 'MES_Manage_View_V20'), @('前端版本', 'package.json:1.1.0'), @('功能范围', '9个一级业务模块,75个正式启用功能页面'), @('前端规模', '99个 Vue 页面文件、28个 API 脚本、8个共享 Vue 组件'), @('数据库', 'YL_MESDB,SQL Server 2019,兼容级别150'), @('数据库规模', '61张用户表、27个视图、425个存储过程、2个函数'), @('数据库容量', '约19.44 GB,其中数据约16.62 GB、日志约2.82 GB'), @('统计日期', '2026-07-24,只读采集') ) @(4.2, 12.8) Add-Heading '2 系统概述' 1 Add-Heading '2.1 建设目标' 2 Add-Text 'MES 连接 SAP 业务订单与车间执行过程,以工艺和计划为主线,将生产任务落实到工位、设备和人员,记录物料流转、生产操作、工时与质量结果,并向管理侧提供异常、齐套、进度、质量和交付视图。' Add-Heading '2.2 系统边界' 2 Add-Table @( @('系统/域', 'MES 负责', '外部系统负责'), @('订单与主数据', '接收并使用订单、物料、BOM、供应商等信息', 'SAP B1 维护 ERP 主数据、财务和库存权威记录'), @('工艺与计划', '标准/生产工艺、排产、任务下发、工位和时间安排', '外部系统提供订单需求和部分资源信息'), @('生产执行', '收料、开工、暂停、报工、送检、人员/设备工时', '设备侧提供状态或执行反馈'), @('质量', '检验任务、标准、实测值、判定及不合格处置', 'SAP/库存侧承接入库、退货等结果'), @('物流与交付', '拣配、AGV任务、发货通知及订单状态汇总', 'SAP/仓储侧完成库存和交付凭证') ) @(3.2, 7.1, 6.7) Add-Heading '2.3 功能模块' 2 $rows = @() $rows += ,@('模块', '核心职责', '主要输入', '主要输出') foreach ($moduleRow in $moduleDesign) { $rows += ,$moduleRow } Add-Table $rows @(2.6, 4.8, 4.9, 4.8) 8.2 Add-Heading '2.4 核心业务主线' 2 Add-Image (Join-Path $assetDir 'business-flow.png') 16.3 '图2-1 MES 核心业务闭环' Add-Note '状态控制原则' '任何会改变订单、工艺、任务、工时、检验或库存状态的操作,都必须在服务端再次校验当前状态和数量边界;前端按钮可见性不能代替业务校验。' 'warn' Add-Heading '3 总体技术架构' 1 Add-Heading '3.1 逻辑架构' 2 Add-Image (Join-Path $assetDir 'logical-architecture.png') 16.3 '图3-1 系统逻辑架构' Add-Text '浏览器加载 Vue 单页应用。常规 MES 请求经统一 Axios 实例发送到 MESCommonBase.ashx;前端通过统一请求载荷指定执行类型、过程名称、参数、分页和操作上下文。SAP B1、TM、文件、AGV和设备数据通过独立接口访问。' Add-Heading '3.2 分层职责' 2 Add-Table @( @('层次', '职责', '主要实现'), @('表现层', '查询、表格、表单、弹窗、状态提示和报表', 'Vue / Element UI / ECharts / FullCalendar'), @('前端业务层', '页面状态、输入校验、交互编排、路由与权限菜单', 'views、store、router、utils、api'), @('应用服务层', '身份上下文、请求解析、过程调用、上传下载、外部系统代理', 'MESCommonBase.ashx、B1/TM代理、文件服务'), @('数据逻辑层', '业务校验、状态流转、事务、查询和聚合', 'SQL Server 存储过程、视图、函数'), @('集成层', 'SAP、TM、AGV、设备/PLC、文件与质量数据交换', 'HTTPS/JSON、Service Layer、MQTT及专用接口') ) @(3.0, 7.2, 6.8) Add-Heading '3.3 架构约束' 2 foreach ($t in @('正式环境页面只能通过受控服务访问业务数据,不允许浏览器直连数据库。','写操作必须在数据库事务或等效原子边界内完成,并返回明确的成功、失败和业务原因。','跨系统操作应定义幂等键或重复提交校验,避免任务、报工、检验和库存记录重复。','前端不得持久化数据库密码、SAP密码、服务私钥或其他长期凭据。','所有外部接口失败都应保留可定位的业务编号、请求时间和错误摘要。')) { Add-Bullet $t } Add-Heading '4 技术栈与代码结构' 1 Add-Heading '4.1 技术栈基线' 2 $techRows = @() $techRows += ,@('类别', '技术', '版本', '用途') foreach ($techRow in $techStack) { $techRows += ,$techRow } Add-Table $techRows @(3.0, 4.0, 3.0, 7.0) Add-Heading '4.2 源码目录' 2 Add-Table @( @('路径', '职责', '变更注意事项'), @('src/views', '业务页面和模块组件', '大型页面改动需覆盖状态、权限和接口回归'), @('src/api', '封装登录、基础数据、B1、TM及专项接口', '保持请求参数和返回结构兼容'), @('src/router', '基础路由、动态菜单树和组件映射', '菜单 component 必须能解析到真实页面'), @('src/store', '用户、角色、权限、标签页和应用状态', '登出时清理身份与缓存'), @('src/utils', '统一请求、认证 Cookie、CRUD、PDF和设备工具', '共享工具变更需扩大回归范围'), @('static/config.js', '运行时环境地址', '按环境发布,不写入账号口令'), @('config / build', '开发代理与 Webpack 构建', '生产构建关闭 source map,核对资源路径'), @('db_backups', '数据库变更和回退证据', '一事一脚本,具备前置检查、事务和验证') ) @(4.0, 6.0, 7.0) Add-Heading '4.3 模块代码规模' 2 Add-Table @( @('目录', 'Vue 文件数', '说明'), @('ProductionManagement', '36', '生产、工时、外协、物流及研发相关页面,复杂度最高'), @('QualityManagement', '15', '检验、标准、处置和统计'), @('PlanManagement', '13', '机加与装配排产、齐套、关闭及汇总'), @('ProcessManagement', '9', '工序、工艺、图纸与工艺任务'), @('SystemMaintenance', '6', '人员、角色、菜单、工位和日志'), @('Device/Anomalous/Sale 等', '20', '设备、异常提醒、销售状态及框架页面') ) @(6.0, 3.0, 8.0) Add-Heading '4.4 编码与提交规范' 2 foreach ($t in @('所有源文件统一使用 UTF-8;发现乱码注释或字符串时在独立变更中修复并回归。','新增页面必须同时完成页面组件、菜单配置、权限配置、接口契约和用户/技术文档。','共享组件和全局工具不承载单一页面的特殊规则;跨三个以上页面的稳定重复逻辑才考虑抽取。','禁止在代码中提交正式密码、个人令牌、数据库连接串和私钥。','数据库脚本必须包含对象存在性检查、事务边界、错误回滚、影响说明和只读验证语句。')) { Add-Bullet $t } Add-Heading '5 部署架构与环境配置' 1 Add-Heading '5.1 正式环境拓扑' 2 Add-Image (Join-Path $assetDir 'deployment-topology.png') 16.3 '图5-1 当前部署与集成拓扑' Add-Heading '5.2 当前运行时端点' 2 Add-Table @( @('用途', '当前配置', '来源/说明'), @('MES 通用接口', 'https://192.168.2.92:10101/submit/MESCommonBase.ashx', 'static/config.js:常规业务请求'), @('MES 服务根地址', 'https://192.168.2.92:10101', '文件上传下载等'), @('SAP B1 代理', 'https://192.168.2.92:9996/b1s', '前端 b1s.js 统一 POST 代理'), @('TM 代理', 'https://192.168.2.92:9996/openapi', '前端 tm.js 统一 POST 代理'), @('AGV 搬运接口', 'http://192.168.2.92:9981/api/zk/call_agv_move_web', '物料机器人页面当前实现'), @('数据库', '192.168.2.92 / YL_MESDB', '凭据单独保管,不进入文档和代码') ) @(4.0, 8.3, 4.7) 8.4 Add-Note '安全边界' '上表用于技术维护和网络检查,不代表对所有终端开放。应通过服务器防火墙、反向代理和访问控制限制来源;AGV 当前为 HTTP 地址,应评估升级为 HTTPS 或限定在隔离网络。' 'risk' Add-Heading '5.3 前端构建与发布' 2 Add-Number '安装 Node.js 20 及 npm 9 或更高兼容版本,执行 npm ci 安装锁定依赖。' Add-Number '在目标环境准备 static/config.js;只配置服务地址,不加入账号和密码。' Add-Number '执行 npm run build,生成 dist 目录。构建脚本会清理 dist/static/config.js,因此发布包中必须由环境配置步骤补回该文件。' Add-Number '将 dist 发布至 Web 服务,启用 HTTPS、正确 MIME 类型、静态缓存和 index.html 回退。' Add-Number '使用非管理员账号完成登录、菜单、查询、写操作权限和附件访问冒烟测试。' Add-Heading '5.4 发布目录要求' 2 Add-Table @( @('内容', '缓存策略', '发布要求'), @('index.html', '不缓存或短缓存', '确保新版本入口及时生效'), @('带 contenthash 的 JS/CSS', '长期缓存', '文件名变化自动失效'), @('static/config.js', '不缓存或短缓存', '按环境独立管理,发布后检查端点'), @('图片、字体和图标', '长期缓存', '检查跨域、MIME和中文文件名'), @('图纸/附件', '按业务权限', '不得以公共静态目录绕过鉴权') ) @(4.2, 4.2, 8.6) Add-Heading '5.5 回退条件' 2 foreach ($t in @('登录或动态菜单无法正常加载。','核心查询、保存、下发、报工或检验出现批量失败。','数据库脚本验证失败或数据状态不一致。','SAP、TM、文件、AGV等关键集成产生不可接受的业务中断。','出现越权、敏感信息泄露或无法审计的写操作。')) { Add-Bullet $t } Add-Heading '6 配置管理' 1 Add-Heading '6.1 配置分类' 2 Add-Table @( @('配置类别', '位置', '管理要求'), @('前端运行时地址', 'static/config.js', '环境独立、发布时注入、禁止密码'), @('开发代理', 'config/index.js', '仅开发使用,不作为正式环境反向代理依据'), @('菜单与页面权限', '登录基础数据_二级菜单', '按角色维护,变更需校验动态路由'), @('人员与角色', '系统管理相关基础数据', '最小权限、离职停用、定期复核'), @('工位、班次和字典', '业务基础数据', '变更前评估对排产、工时和统计的影响'), @('数据库连接与服务凭据', '服务端安全配置', '密钥库/受限配置,不写入前端或文档'), @('外部系统端点', '前端运行时配置或服务端配置', '区分开发、测试、正式,纳入连通性检查') ) @(4.0, 5.5, 7.5) Add-Heading '6.2 配置变更控制' 2 foreach ($t in @('配置变更必须记录变更人、时间、原值、新值、原因、验证结果和回退值。','正式环境配置不得直接从开发环境复制覆盖,必须逐项比对。','菜单路径、组件路径和权限位变更后,需要清除登录缓存并使用目标角色重新登录验证。','工位、班次、字典和状态类配置变更应验证历史数据展示不受破坏。')) { Add-Bullet $t } Add-Heading '7 身份、权限与安全' 1 Add-Heading '7.1 权限流程' 2 Add-Image (Join-Path $assetDir 'permission-flow.png') 16.3 '图7-1 登录、菜单与业务请求权限链路' Add-Heading '7.2 当前实现' 2 Add-Table @( @('环节', '当前机制', '控制重点'), @('登录', '用户名和密码由统一 MES 接口验证', '必须使用可信 HTTPS 证书'), @('角色', '账号可关联多个角色;角色编号写入 Admin-Token Cookie', '角色选择后重新加载菜单'), @('菜单', '按角色读取菜单数据,getTreeData 构建树并动态 addRoutes', '组件路径必须受白名单/构建产物约束'), @('页面权限', '菜单记录含 AddData/DeleteData/EditData/SearchData 权限位', '按钮权限与后端写权限保持一致'), @('请求上下文', '公共请求包含 UserID、UserName、ModularID', '服务端不可只信任前端传值'), @('登出', '清理用户、账号、角色 Cookie', '同时使服务端会话或令牌失效') ) @(3.2, 7.4, 6.4) Add-Heading '7.3 标准安全要求' 2 foreach ($t in @('前端权限只用于界面控制,服务端必须对每次查询和写操作校验身份、角色、模块和数据范围。','Cookie 应设置 Secure、SameSite 和合理有效期;如架构允许,应使用 HttpOnly 会话令牌。','密码不得出现在日志、异常消息、浏览器存储、截图和文档中。','所有写操作记录操作人、模块、业务主键、动作、时间、结果和必要的变更摘要。','高风险操作包括删除、订单关闭、任务重置、工时修正、批量下发和质量放行,应增加二次确认与权限分离。','定期复核停用账号、重复角色、过宽菜单和长期未使用权限。')) { Add-Bullet $t } Add-Heading '7.4 当前风险与改进优先级' 2 Add-Table @( @('级别', '现状观察', '建议'), @('高', '角色编号存于可由前端读取的 Cookie,前端路由守卫将 roles 固定为 admin', '确保服务端基于可信会话重新鉴权;评估更安全的令牌与 Cookie 属性'), @('高', '正式端点直接写在 static/config.js,AGV 使用 HTTP', '端点环境化并限制网络来源;AGV 使用 HTTPS 或隔离网络'), @('中', 'MES 通用 Axios 超时为1,500,000毫秒(25分钟)', '按业务分类设置超时、取消请求和服务端作业化'), @('中', '部分源码中文注释显示编码异常', '统一 UTF-8,禁止乱码进入新提交'), @('中', '页面与数据库过程高度耦合', '建立接口契约、回归测试和变更影响清单') ) @(1.8, 7.1, 8.1) 8.2 Add-Heading '8 请求与接口设计' 1 Add-Heading '8.1 MES 通用请求' 2 Add-Text '常规页面通过统一服务地址 POST JSON。CreateData 将过程执行所需信息序列化,并补充当前用户和页面上下文。不同历史模块存在多个 type 编号,维护时应以对应服务端实现和现有页面为准,不得仅凭编号推断读写性质。' Add-Table @( @('字段', '含义', '标准要求'), @('type', '后端执行/返回策略标识', '新增类型必须形成接口契约'), @('name', '服务端过程或业务命令名称', '禁止由最终用户自由输入'), @('param', '参数数组序列化结果', '参数化执行,禁止拼接 SQL'), @('pageSize / pageList', '分页和页码信息', '大数据查询必须分页'), @('UserID / UserName', '操作用户上下文', '服务端从可信身份核验,不可盲信'), @('ModularID', '当前页面路由/模块标识', '用于权限和审计,必须与授权菜单匹配') ) @(3.5, 6.0, 7.5) Add-Heading '8.2 SAP B1 与 TM 代理' 2 Add-Text 'b1s.js 和 tm.js 将外部 GET、POST、PATCH 统一封装为对代理服务的 POST,请求体包含 func、cmd 和序列化 content。代理层负责与真正外部接口通信并返回结果。该设计避免浏览器直接保存 SAP 凭据,但仍需在代理层实施命令白名单、权限、超时和日志。' Add-Table @( @('接口族', '超时', '成功返回', '失败处理'), @('B1 代理', '100秒', '{ success: true, data }', '提取 SAP error.message 或网络错误'), @('TM 代理', '100秒', '{ success: true, data }', '复用相同错误提取逻辑'), @('MES 通用接口', '1500秒', 'Axios response', '当前统一实例未集中定义响应拦截器'), @('AGV', '页面 Axios 默认行为', '校验返回 ids 包含任务号', '失败后不应更新 MES 任务为 RUNNING') ) @(3.0, 2.4, 5.5, 6.1) Add-Heading '8.3 接口标准' 2 foreach ($t in @('所有写接口必须定义业务主键、幂等规则、允许状态、数量边界和事务范围。','统一返回结构至少包含 success/code/message/data/traceId;业务失败不使用模糊的“操作失败”。','查询接口明确分页、排序、最大导出量和日期范围;导出应与查询权限一致。','跨系统调用记录请求时间、目标系统、业务编号、结果码和耗时,但对密码、令牌、个人敏感信息脱敏。','对网络超时、重复提交和外部系统成功但 MES 更新失败定义补偿或人工对账流程。')) { Add-Bullet $t } Add-Heading '9 数据架构' 1 Add-Heading '9.1 正式数据库基线' 2 Add-Table @( @('项目', '当前值', '说明'), @('数据库', 'YL_MESDB', 'MES 主业务数据库'), @('数据库引擎', 'SQL Server 2019 RTM 15.0.2000.5', '建议评估累计更新补丁'), @('兼容级别', '150', 'SQL Server 2019'), @('排序规则', 'Chinese_PRC_CI_AS', '中文、不区分大小写、不区分重音'), @('恢复模式', 'SIMPLE', '当前不支持日志链上的时间点恢复'), @('用户表 / 视图', '61 / 27', '只读元数据统计'), @('存储过程 / 函数', '425 / 2', '业务逻辑主要集中在过程层'), @('容量', '总计约19.44 GB', '数据约16.62 GB、日志约2.82 GB') ) @(4.0, 5.4, 7.6) Add-Heading '9.2 核心数据域' 2 Add-Table @( @('数据域', '代表性对象', '关键关系'), @('订单与任务', 'MES_接口_生产计划、生产任务、子任务', '订单拆分为工序任务,任务关联工艺、工位、人员和数量'), @('工艺与图纸', '基础表_工序、标准工艺库、生产工艺库、零件/工艺图纸', '标准工艺可生成订单工艺,订单工艺下发任务'), @('生产与工时', '操作记录、报工记录、工时校验表', '开始/暂停/结束形成时段,报工和校验形成结算依据'), @('质量', '质检记录、检测零件、检测数据、检验标准、不合格处置', '任务产生检验,检验结果影响后续流转和统计'), @('资源', '设备台账、资源主数据、工位人员绑定、班次', '排产和执行以有效工位、设备、人员和班次为约束'), @('权限与审计', '人员、角色、人员角色、二级菜单、操作日志', '账号经角色获得菜单与操作权限,业务请求留痕'), @('集成与缓存', '物料、BOM、设备实时缓存、历史状态、附件', '承接 SAP、设备、文件等外部数据') ) @(3.2, 6.6, 7.2) 8.2 Add-Heading '9.3 关键状态模型' 2 Add-Table @( @('对象', '典型状态/动作', '控制要求'), @('生产订单', '未准备工艺 → 已准备工艺 → 已排产 → 执行中 → 完工/关闭', '状态转换需检查工艺、任务、数量和未完成工时'), @('工序任务', '待下发/可执行 → 已开工 → 暂停/恢复 → 已报工/完成', '重复开始、越量报工和跨状态操作必须拦截'), @('工艺', '生成/编辑 → 保存启用 → 下发任务', '字段即时保存与整条启用要区分;结构变更后重新启用'), @('质检任务', '待检 → 检验中 → 合格/不合格 → 处置/放行', '实测值、判定、数量和处置结果保持一致'), @('工时', '操作记录 → 计算工时 → 校验/修正 → 结算', '原始记录保留,修正需审计并可追溯') ) @(3.2, 7.0, 6.8) Add-Heading '9.4 数据完整性与事务' 2 Add-Note '现状观察' '61张用户表仅检测到8个外键约束,较多关联完整性可能由存储过程和业务代码维护。技术变更必须核对逻辑外键、孤儿数据和删除影响。' 'risk' foreach ($t in @('订单、任务、工艺、操作记录、报工和检验之间使用稳定业务主键关联。','批量下发、报工、检验保存、订单关闭等跨表写入在同一事务中完成。','数量字段统一精度和单位,写入前校验非负、累计不超计划及合格/不合格合计关系。','删除优先采用业务停用或软删除;确需物理删除时先检查下游引用并记录审计。','时间统一保存完整日期时间,明确计划时间、操作时间、服务器时间和班次边界。')) { Add-Bullet $t } Add-Heading '9.5 备份与恢复' 2 Add-Table @( @('项目', '最低要求', '验证证据'), @('全量备份', '每日一次,保留周期按公司制度', '备份作业日志与文件校验'), @('差异/日志备份', '若要求时间点恢复,将数据库切换为 FULL 并建立日志备份链', '恢复演练可定位到目标时间'), @('异地副本', '至少一份与数据库主机故障域隔离', '抽查可读与保留周期'), @('恢复演练', '季度或重大版本前执行', '恢复耗时、数据校验、问题清单'), @('变更前备份', '数据库结构/过程或批量数据变更前执行', '脚本、备份和回退编号互相引用') ) @(4.0, 8.0, 5.0) Add-Heading '10 关键业务技术设计' 1 Add-Heading '10.1 工艺到任务下发' 2 Add-Number '维护工序基础数据和物料标准工艺。标准工艺是后续订单生成生产工艺的来源。' Add-Number '为生产订单生成订单专用生产工艺;调整工序顺序、工时、车间、设备和说明。' Add-Number '保存当前订单工艺,使其进入可用于计划和任务生成的启用状态。字段即时保存不等同于整条工艺启用。' Add-Number '整单下发按工艺路线生成全部工序任务;单工序下发仅用于补发目标工序。必须防止重复任务。' Add-Number '任务进入计划和生产执行后,工艺结构变更必须评估已排产、已开工、工时和质量记录。' Add-Heading '10.2 计划排产到生产执行' 2 Add-Table @( @('阶段', '写入/改变', '下游影响'), @('排产', '工位、人员、数量、计划开始/完成、外协分组等', '工位负荷、任务可执行时间、物料准备和异常判断'), @('收料/领料', '物料接收或领用状态', '允许后续开始并形成物料追踪'), @('开工', '任务进入执行状态并形成开始记录', '设备/人员占用、在制进度和工时开始'), @('暂停/恢复', '记录暂停区间和原因', '净工时、设备状态和异常统计'), @('报工/结束', '完成数量、工时、操作记录和任务进度', '质量送检、后工序、完工判断和工时报表'), @('送检/收检', '检验任务或跨工序接收结果', '质量闭环及后续工序可执行性') ) @(3.1, 6.8, 7.1) Add-Heading '10.3 工时闭环' 2 Add-Text '系统以操作记录为原始事实,结合开始、暂停、恢复和结束时间计算生产/辅助工时;报工记录承载完成数量和确认信息;工时校验和工时修正用于处理异常。任何修正都应保留原值、修正值、原因、操作人和时间,结算工时只使用已满足校验规则的数据。' Add-Heading '10.4 质量闭环' 2 Add-Text '质量任务从生产送检、采购入库、销售退货、原材料退库或其他入库场景产生。检验标准提供项目、上下限、比例和量具要求;检验结果记录实测值、合格/不合格数量和判定。非合格结果进入返工、让步、报废或其他处置,并反馈生产、库存和统计。' Add-Heading '10.5 异常与交付' 2 Add-Text '异常提醒依据计划与实际时间、任务状态和加急标记形成。销售订单状态页面汇总 SAP 和 MES 的计划、齐套、拣配、发料、装配、送检、入库和发货状态。汇总页面原则上只读展示,不应成为绕过原业务模块直接改状态的入口。' Add-Heading '11 模块技术边界' 1 foreach ($m in $moduleDesign) { Add-Heading ("11.{0} {1}" -f ([array]::IndexOf($moduleDesign, $m) + 1), $m[0]) 2 Add-Table @( @('项目', '说明'), @('核心职责', $m[1]), @('主要输入', $m[2]), @('主要输出/影响', $m[3]), @('页面范围', ($modulePages[$m[0]] -join '、')) ) @(3.5, 13.5) 8.4 } Add-Heading '12 文件、设备与外部集成' 1 Add-Heading '12.1 图纸与附件' 2 Add-Table @( @('环节', '实现', '控制要求'), @('上传', 'MESUploadFile.ashx', '校验扩展名、MIME、大小、病毒和业务归属'), @('存储', '文件服务目录与数据库元数据', '文件名不可作为唯一标识,保留哈希/版本/上传人'), @('下载/预览', 'webpage/part/ 与 PDF 预览组件', '与业务记录权限一致,避免目录遍历'), @('删除', '业务删除记录或状态', '保留审计,防止已下发工艺失去依据') ) @(3.0, 6.0, 8.0) Add-Heading '12.2 AGV' 2 Add-Text '物料机器人页面先在 MES 创建搬运任务,再调用 AGV 接口下发 ContainerTransportOrder;只有接口返回任务号成功后才将 MES 状态更新为 RUNNING。应补充超时后的任务查询、重复下发幂等和“AGV成功但MES更新失败”的对账补偿。' Add-Heading '12.3 设备与 MQTT' 2 Add-Text '公共工具支持 Cmd_Opc_Read 和 Cmd_Opc_Write,通过设备 API 读取或写入 TagList;MQTT 用于实时数据订阅。写设备命令属于高风险操作,必须限制目标客户端、Tag 白名单、数值范围和操作权限,并记录请求与设备响应。' Add-Heading '12.4 SAP B1' 2 Add-Text 'SAP B1 是订单、物料、BOM、采购、库存等数据的重要外部来源。MES 通过代理执行 Service Layer 请求。集成设计必须明确主数据权威方、同步方向、时间窗口、失败重试、重复数据判定和日常对账。' Add-Heading '13 日志、监控与审计' 1 Add-Heading '13.1 日志分类' 2 Add-Table @( @('日志', '内容', '用途'), @('用户操作日志', '用户、模块、动作、业务主键、结果、时间', '责任追溯和安全审计'), @('API 请求/响应日志', '命令、参数摘要、耗时、结果码、traceId', '接口故障定位;敏感字段脱敏'), @('数据库作业日志', '备份、同步、清理和计划任务结果', '运维检查和恢复依据'), @('外部集成日志', 'SAP/TM/AGV/设备调用状态和业务编号', '跨系统对账和补偿'), @('前端错误', '页面、用户、版本、错误栈和时间', '定位浏览器端异常') ) @(3.8, 8.0, 5.2) Add-Heading '13.2 监控指标' 2 foreach ($t in @('站点与接口可用率、证书有效期、HTTP 5xx 和超时率。','MES 通用接口、B1、TM、AGV接口的P50/P95响应时间和失败率。','数据库 CPU、内存、数据/日志空间、阻塞、死锁、慢查询和备份状态。','订单同步延迟、待下发任务、超时任务、未闭环工时、待检和不合格处置积压。','文件服务容量、上传失败率和无业务引用文件。')) { Add-Bullet $t } Add-Heading '13.3 告警分级' 2 Add-Table @( @('级别', '示例', '响应目标'), @('P1', '系统不可用、数据破坏、越权或批量错误写入', '立即响应,停止相关写入并启动应急'), @('P2', '核心模块不可用、SAP/AGV关键链路中断', '30分钟内响应并给出绕行/恢复方案'), @('P3', '单一报表、导出或非核心页面异常', '工作时间内响应并纳入修复计划'), @('P4', '体验、文案或低风险数据展示问题', '按版本排期') ) @(2.0, 10.0, 5.0) Add-Heading '14 性能与容量' 1 Add-Heading '14.1 查询规范' 2 foreach ($t in @('列表查询默认分页,日期范围和导出量设置上限。','常用筛选字段建立与查询计划匹配的索引,避免对列进行不可搜索的函数包装。','页面首次加载不并发请求无关的大数据字典和全部明细;明细按需展开。','导出超过同步阈值时转后台任务,并提供下载状态。','对25分钟的通用超时进行业务分类,避免浏览器长期占用连接。')) { Add-Bullet $t } Add-Heading '14.2 容量基线与趋势' 2 Add-Text '当前数据库约19.44 GB。运维应每月记录数据文件、日志文件、核心大表行数、附件容量和增长率;当预计剩余空间不足三个月时提前扩容或归档。归档必须保持订单、任务、工时、质量和审计记录之间的可追溯性。' Add-Heading '14.3 性能验收建议' 2 Add-Table @( @('场景', '建议目标', '备注'), @('登录与菜单', '正常内网条件下5秒内完成', '包含动态路由构建'), @('普通分页查询', 'P95不超过5秒', '合理筛选范围'), @('复杂统计报表', 'P95不超过15秒', '超过阈值采用异步'), @('保存/状态操作', 'P95不超过5秒', '不含不可控外部系统等待'), @('关键外部接口', '定义独立超时、重试和熔断', '避免整页无期限等待') ) @(4.0, 5.0, 8.0) Add-Heading '15 运维与故障处理' 1 Add-Heading '15.1 日常检查' 2 Add-Table @( @('频率', '检查项'), @('每日', '站点/API可用、数据库空间、备份结果、同步/作业、P1/P2告警、待处理外部接口失败'), @('每周', '慢查询、阻塞/死锁、异常日志趋势、菜单权限变更、附件增长和关键业务积压'), @('每月', '容量趋势、账号权限复核、证书/密码到期、依赖漏洞、恢复点与监控覆盖'), @('每季度', '恢复演练、应急演练、技术债评审和关键业务全链路回归') ) @(3.0, 14.0) Add-Heading '15.2 故障定位顺序' 2 Add-Number '确认影响范围:单用户、单角色、单页面、单接口、单数据库对象或全系统。' Add-Number '记录时间、用户、页面、业务编号、操作和错误信息,不要求用户重复高风险操作。' Add-Number '检查浏览器网络请求、服务可用性、外部系统状态和数据库阻塞/错误。' Add-Number '使用 traceId、业务主键和操作人关联前端、服务、数据库与外部接口日志。' Add-Number '需要数据修复时先备份和评估影响,使用经评审脚本,完成后验证上下游一致性。' Add-Heading '15.3 常见故障矩阵' 2 Add-Table @( @('现象', '优先检查', '禁止做法'), @('登录后无菜单', '角色、菜单启用、组件路径、Cookie和getInfo返回', '直接给管理员权限绕过'), @('页面一直加载', '网络请求、25分钟超时、数据库阻塞和返回规模', '连续刷新并重复写操作'), @('保存成功但列表未变', '返回结果、事务提交、查询条件、缓存和刷新逻辑', '未核对数据就再次新增'), @('SAP/AGV失败', '外部接口日志、业务编号、幂等状态和MES本地状态', '盲目重复下发'), @('工时/数量不一致', '操作记录、报工、检验、修正审计和累计边界', '直接覆盖原始记录'), @('图纸打不开', '文件元数据、物理文件、权限、MIME和路径', '将目录改为匿名公开') ) @(4.0, 8.5, 4.5) 8.2 Add-Heading '16 变更、发布与回退' 1 Add-Heading '16.1 标准变更流程' 2 Add-Number '提出变更:说明问题、范围、业务规则、数据影响、权限影响和验收标准。' Add-Number '技术分析:定位页面、共享工具、接口、过程、表、视图、菜单和外部系统影响。' Add-Number '实施:代码和数据库脚本分离管理;正式凭据不进入版本库。' Add-Number '验证:静态检查、单元/定向测试、接口测试、数据库只读验证和关键链路回归。' Add-Number '发布:备份、窗口确认、脚本执行、前端发布、配置核对和冒烟测试。' Add-Number '观察与回退:监控错误率和业务状态;达到回退条件时按预案恢复。' Add-Heading '16.2 数据库脚本规范' 2 foreach ($t in @('文件名包含动作、模块、日期;不覆盖历史脚本。','先备份被修改对象定义;脚本使用 TRY/CATCH、事务和 XACT_ABORT。','对象创建/修改具备前置检查,重复执行不会产生重复业务数据。','禁止在同一脚本中混入无关结构变更和业务数据修复。','附带只读验证查询和明确回退方案;正式执行结果写入变更记录。')) { Add-Bullet $t } Add-Heading '16.3 前端发布检查' 2 Add-Table @( @('阶段', '检查项'), @('构建前', '锁文件一致、Node/npm版本、ESLint、git diff --check、无敏感信息'), @('构建后', 'index、JS/CSS、图标字体、懒加载页面、static/config.js'), @('发布后', 'HTTPS、缓存、登录、目标角色菜单、核心查询/写入、附件、导出'), @('观察期', '前端错误、接口失败、数据库阻塞和用户反馈') ) @(3.5, 13.5) Add-Heading '17 测试与验收' 1 Add-Heading '17.1 测试层次' 2 Add-Table @( @('层次', '覆盖重点', '证据'), @('静态检查', 'ESLint、编码、敏感信息、脚本语法', '命令输出与检查报告'), @('组件/函数', '校验、状态计算、导出字段和共享工具', '自动化测试结果'), @('接口', '参数、权限、分页、错误、幂等和事务', '请求响应样例与数据库核对'), @('业务链路', '工艺→排产→下发→生产→质量→关闭/交付', '测试记录和状态截图'), @('角色权限', '不同角色的菜单、按钮和数据范围', '权限矩阵'), @('非功能', '性能、恢复、安全、兼容性和容量', '压测/演练/扫描报告') ) @(3.2, 8.0, 5.8) Add-Heading '17.2 核心回归场景' 2 foreach ($t in @('登录、单/多角色选择、菜单加载和退出。','标准工艺生成生产工艺、编辑、保存启用、整单和单工序下发。','机加与装配排产、计划时间/工位/人员/数量调整及已排产查询。','收料、开工、暂停、恢复、报工、送检和工时计算。','采购/过程/终检、实测值保存、不合格处置及下游状态。','订单关闭、齐套、发货通知和销售订单全流程状态。','SAP、TM、图纸附件、AGV和设备接口的成功与失败分支。')) { Add-Bullet $t } Add-Heading '17.3 上线验收门槛' 2 Add-Note '上线条件' 'P1/P2缺陷为0;核心链路通过;数据库脚本、回退和备份验证完成;权限矩阵通过目标角色验证;监控和应急联系人就绪;文档与变更记录已更新。' 'warn' Add-Heading '18 风险与技术债' 1 Add-Table @( @('优先级', '风险/技术债', '影响', '建议行动'), @('P0', '正式凭据与权限完全依赖前端将造成越权风险', '数据安全与审计', '确认服务端强制鉴权,开展权限穿透测试'), @('P1', '数据库为 SIMPLE 恢复模式', '无法时间点恢复', '依据RPO/RTO决定是否切换FULL并建立日志备份'), @('P1', 'SQL Server 2019 RTM 未体现累计更新', '稳定性与安全补丁', '测试后升级到受支持CU'), @('P1', 'AGV接口使用HTTP且地址硬编码', '传输安全与环境切换', '服务端代理/HTTPS/配置化'), @('P1', '通用请求超时25分钟', '资源占用与用户重复操作', '分类超时、取消、异步任务和幂等'), @('P2', '大型单文件页面和过程耦合度高', '维护成本与回归风险', '按业务域拆分并建立契约测试'), @('P2', '外键较少,关系主要靠过程维护', '孤儿数据和删除风险', '补充数据质量检查,逐步增加约束'), @('P2', '源码存在编码异常', '可读性和误改风险', '统一UTF-8并加入检查') ) @(2.0, 5.4, 4.0, 5.6) 8.0 Add-Heading '19 附录A:正式功能页面清单' 1 $moduleNo = 1 foreach ($key in $modulePages.Keys) { Add-Heading ("A.{0} {1}" -f $moduleNo, $key) 2 $rows = @() $rows += ,@('序号', '页面名称', '技术归属') for ($i = 0; $i -lt $modulePages[$key].Count; $i++) { $rows += ,@(($i + 1).ToString(), $modulePages[$key][$i], $key) } Add-Table $rows @(2.0, 9.0, 6.0) $moduleNo++ } Add-Heading '20 附录B:关键对象参考' 1 Add-Heading 'B.1 代表性数据库对象' 2 Add-Table @( @('类别', '代表对象', '用途'), @('生产计划', 'MES_接口_生产计划、MES_接口_生产计划_生产任务', '订单和工序任务主数据'), @('工艺', '基础表_工序、标准工艺库、生产工艺库', '工序与路线'), @('工时', 'YL_加工中心_操作记录表、YL_加工中心_报工记录', '开始、暂停、结束和报工事实'), @('质量', 'YL_质量检验_质检记录及检测明细', '检验结果与实测数据'), @('资源', 'MES_资源主数据、设备台账、工位人员绑定表、班次表', '工位设备与人员班次'), @('权限', '登录基础数据_人员信息、角色信息、人员权限角色、二级菜单', '身份、角色和菜单权限'), @('日志', '_日志、记录_日志_项目运行日志', '用户操作与接口请求响应') ) @(3.0, 8.0, 6.0) 8.2 Add-Heading 'B.2 关键前端入口' 2 Add-Table @( @('文件', '职责'), @('src/main.js', '注册 Vue、Element UI、公共指令、CRUD、图表和根实例'), @('src/permission.js', '登录白名单、动态菜单加载和路由守卫'), @('src/router/getTreeData.js', '将数据库菜单转换为路由树'), @('src/utils/request.js', 'MES 通用 Axios 实例和文件地址'), @('src/utils/curd.js', '统一请求载荷、通用表格操作和设备读写辅助'), @('src/api/b1s.js / tm.js', 'SAP B1 与 TM 代理封装'), @('static/config.js', '正式运行时服务地址') ) @(6.0, 11.0) Add-Heading '21 附录C:上线与运维检查表' 1 Add-Table @( @('编号', '检查项', '结果', '责任人/日期'), @('C-01', '前端构建、版本号、资源和 static/config.js 正确', '□通过 □不通过', ''), @('C-02', 'HTTPS证书、端口、防火墙和DNS/地址可用', '□通过 □不通过', ''), @('C-03', '数据库备份完成且可读取,回退脚本已准备', '□通过 □不通过', ''), @('C-04', '数据库脚本执行与只读验证完成', '□通过 □不通过', ''), @('C-05', '目标角色菜单、按钮与数据权限验证完成', '□通过 □不通过', ''), @('C-06', '核心业务链路与外部接口冒烟通过', '□通过 □不通过', ''), @('C-07', '日志、监控、告警和应急联系人就绪', '□通过 □不通过', ''), @('C-08', '变更记录、技术文档和用户文档已更新', '□通过 □不通过', ''), @('C-09', '观察期和回退决策人已明确', '□通过 □不通过', '') ) @(1.8, 9.4, 3.4, 3.0) 8.2 # 页眉页脚 $header = $section.Headers.Item(1).Range $header.Text = '大连元利流体技术有限公司 MES 系统标准设计文档' $header.Font.NameFarEast = '微软雅黑'; $header.Font.Name = 'Arial'; $header.Font.Size = 8.5; $header.Font.Color = 0x777777 $header.ParagraphFormat.Alignment = 2 $footer = $section.Footers.Item(1).Range $footer.Text = '内部技术资料 | ' $footer.Font.NameFarEast = '微软雅黑'; $footer.Font.Name = 'Arial'; $footer.Font.Size = 8.5; $footer.Font.Color = 0x777777 $footer.ParagraphFormat.Alignment = 1 $footer.Collapse(0) [void]$footer.Fields.Add($footer, 33) foreach ($toc in $doc.TablesOfContents) { $toc.Update() } [void]$doc.Fields.Update() $doc.Repaginate() try { $doc.BuiltInDocumentProperties.Item('Title').Value = '大连元利流体技术有限公司MES系统标准设计文档' $doc.BuiltInDocumentProperties.Item('Subject').Value = 'MES系统架构、部署、数据、接口、权限、运维与验收技术基线' $doc.BuiltInDocumentProperties.Item('Author').Value = 'MESWORK' } catch { Write-ProgressLog '当前 Office 兼容层不支持写入内置文档属性,已跳过属性写入' } $doc.SaveAs2($docxPath, 16) $doc.ExportAsFixedFormat($pdfPath, 17) $pages = $doc.ComputeStatistics(2) Write-ProgressLog "已生成 DOCX 和 PDF,共 $pages 页" try { $doc.Close($false) } catch { Write-ProgressLog 'Office 已保存文档,但关闭文档时返回兼容层异常' } $doc = $null try { $word.Quit() } catch { Write-ProgressLog 'Office 进程已退出,但 Quit 调用返回 RPC 兼容层异常' } $word = $null [GC]::Collect(); [GC]::WaitForPendingFinalizers() [pscustomobject]@{ Docx = $docxPath Pdf = $pdfPath Pages = $pages Modules = $modulePages.Count PagesInScope = ($modulePages.Values | ForEach-Object { $_.Count } | Measure-Object -Sum).Sum } | Format-List } catch { Write-ProgressLog ("生成失败:" + $_.Exception.Message) if ($null -ne $doc) { try { $doc.Close($false) } catch {} } if ($null -ne $word) { try { $word.Quit() } catch {} } [GC]::Collect(); [GC]::WaitForPendingFinalizers() throw }