$ErrorActionPreference = 'Stop' Add-Type -AssemblyName System.Drawing $root = (Resolve-Path (Join-Path $PSScriptRoot '..\..')).Path $shots = Join-Path $PSScriptRoot 'screenshots' $prepared = Join-Path $PSScriptRoot 'prepared' $docDir = Join-Path $root 'doc' $desktop = [Environment]::GetFolderPath('Desktop') $fileName = '大连元利流体技术有限公司MES系统操作手册_系统管理篇_样稿' $docxPath = Join-Path $docDir ($fileName + '.docx') $pdfPath = Join-Path $docDir ($fileName + '.pdf') $desktopDocx = Join-Path $desktop ($fileName + '.docx') $desktopPdf = Join-Path $desktop ($fileName + '.pdf') New-Item -ItemType Directory -Force -Path $prepared, $docDir | Out-Null function New-Crop { param( [string]$Source, [string]$Target, [int]$X, [int]$Y, [int]$Width, [int]$Height ) $sourceImage = [System.Drawing.Bitmap]::FromFile($Source) try { $cropWidth = [Math]::Min($Width, $sourceImage.Width - $X) $cropHeight = [Math]::Min($Height, $sourceImage.Height - $Y) $targetImage = New-Object System.Drawing.Bitmap($cropWidth, $cropHeight) try { $graphics = [System.Drawing.Graphics]::FromImage($targetImage) try { $graphics.DrawImage( $sourceImage, (New-Object System.Drawing.Rectangle(0, 0, $cropWidth, $cropHeight)), (New-Object System.Drawing.Rectangle($X, $Y, $cropWidth, $cropHeight)), [System.Drawing.GraphicsUnit]::Pixel ) } finally { $graphics.Dispose() } $targetImage.Save($Target, [System.Drawing.Imaging.ImageFormat]::Png) } finally { $targetImage.Dispose() } } finally { $sourceImage.Dispose() } } Copy-Item (Join-Path $shots '01-personnel-list.png') (Join-Path $prepared 'personnel-list.png') -Force Copy-Item (Join-Path $shots '03-menu-list.png') (Join-Path $prepared 'menu-list.png') -Force Copy-Item (Join-Path $shots '03-menu-permission-panel.png') (Join-Path $prepared 'menu-permission.png') -Force Copy-Item (Join-Path $shots '05-operation-log.png') (Join-Path $prepared 'operation-log.png') -Force New-Crop (Join-Path $shots '01-personnel-add-dialog.png') (Join-Path $prepared 'personnel-add.png') 560 105 800 470 New-Crop (Join-Path $shots '02-role-list.png') (Join-Path $prepared 'role-list.png') 0 0 1020 940 New-Crop (Join-Path $shots '02-role-add-dialog.png') (Join-Path $prepared 'role-add.png') 560 105 800 390 New-Crop (Join-Path $shots '04-workstation-list.png') (Join-Path $prepared 'workstation-list.png') 0 0 1020 940 New-Crop (Join-Path $shots '04-workstation-add-dialog.png') (Join-Path $prepared 'workstation-add.png') 560 105 800 450 $word = $null $doc = $null $buildError = $null try { $word = New-Object -ComObject Word.Application $word.Visible = $false $word.DisplayAlerts = 0 $doc = $word.Documents.Add() $selection = $word.Selection $doc.PageSetup.PageWidth = $word.CentimetersToPoints(21) $doc.PageSetup.PageHeight = $word.CentimetersToPoints(29.7) $doc.PageSetup.TopMargin = $word.CentimetersToPoints(2.2) $doc.PageSetup.BottomMargin = $word.CentimetersToPoints(2.0) $doc.PageSetup.LeftMargin = $word.CentimetersToPoints(2.1) $doc.PageSetup.RightMargin = $word.CentimetersToPoints(2.1) $normal = $doc.Styles.Item(-1) $normal.Font.NameFarEast = '宋体' $normal.Font.Name = 'Arial' $normal.Font.Size = 10.5 $normal.ParagraphFormat.LineSpacingRule = 1 $normal.ParagraphFormat.SpaceAfter = 6 function Move-End { $end = $doc.Content.End - 1 $selection.SetRange($end, $end) } 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 ) $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) $styleId = switch ($Level) { 1 { -2 } 2 { -3 } default { -4 } } $selection.Style = $doc.Styles.Item($styleId) $selection.Font.NameFarEast = '微软雅黑' $selection.Font.Name = 'Arial' $selection.Font.Color = 0x8F4A31 $selection.Font.Bold = 1 $selection.ParagraphFormat.KeepWithNext = -1 $selection.TypeText($Text) $selection.TypeParagraph() $selection.Style = $normal } function Add-StepList { param([string[]]$Items) for ($i = 0; $i -lt $Items.Count; $i++) { Add-Text (('{0}. {1}' -f ($i + 1), $Items[$i])) 10.5 $false 0 0 0 4 0 } } function Add-ItemList { param([string[]]$Items) foreach ($item in $Items) { Add-Text ('(' + ([array]::IndexOf($Items, $item) + 1) + ')' + $item) 10.5 $false 0 0 0 4 0 } } function Add-Table { param([object[]]$Rows, [double[]]$WidthsCm = @()) $range = $selection.Range $table = $doc.Tables.Add($range, $Rows.Count, $Rows[0].Count) $table.Borders.Enable = 1 $table.Range.Font.NameFarEast = '宋体' $table.Range.Font.Name = 'Arial' $table.Range.Font.Size = 9 $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++) { $table.Cell($r + 1, $c + 1).Range.Text = [string]$Rows[$r][$c] $table.Cell($r + 1, $c + 1).VerticalAlignment = 1 if ($WidthsCm.Count -gt $c) { $table.Cell($r + 1, $c + 1).Width = $word.CentimetersToPoints($WidthsCm[$c]) } } } $table.Rows.Item(1).Range.Bold = 1 $table.Rows.Item(1).Shading.BackgroundPatternColor = 0xE6D8D0 $table.Rows.Item(1).Range.ParagraphFormat.Alignment = 1 $table.AllowAutoFit = -1 Move-End $selection.TypeParagraph() } function Add-Note { param([string]$Title, [string]$Text, [string]$Kind = 'info') $range = $selection.Range $table = $doc.Tables.Add($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.Font.Bold = 0 $cell.Range.ParagraphFormat.SpaceAfter = 0 if ($Kind -eq 'warn') { $cell.Shading.BackgroundPatternColor = 0xD9F2FF } elseif ($Kind -eq 'danger') { $cell.Shading.BackgroundPatternColor = 0xD9E2F3 } else { $cell.Shading.BackgroundPatternColor = 0xF4F1EE } Move-End $selection.TypeParagraph() } function Add-Figure { param([string]$Path, [string]$Caption, [double]$MaxWidthCm = 16.4) $selection.ParagraphFormat.Alignment = 1 $shape = $selection.InlineShapes.AddPicture($Path, $false, $true, $selection.Range) $shape.LockAspectRatio = -1 $maxWidth = $word.CentimetersToPoints($MaxWidthCm) if ($shape.Width -gt $maxWidth) { $shape.Width = $maxWidth } $selection.SetRange($shape.Range.End, $shape.Range.End) $selection.TypeParagraph() Add-Text $Caption 9 $false 1 0x777777 0 8 0 } function Add-PageBreak { $selection.InsertBreak(7) } # Cover Add-Text '' 12 $false 1 0 0 20 0 Add-Text '大连元利流体技术有限公司' 22 $true 1 0x8F4A31 0 12 0 Add-Text 'MES 系统用户操作手册' 30 $true 1 0x8F4A31 0 16 0 Add-Text '系统管理篇(样稿)' 24 $true 1 0x4D4D4D 0 30 0 Add-Text '版本:V1.0' 12 $false 1 0 0 8 0 Add-Text '编制日期:2026年7月23日' 12 $false 1 0 0 8 0 Add-Text '适用系统:大连元利 MES 正式环境' 12 $false 1 0 0 28 0 Add-Note '编制说明' '本样稿依据现有项目操作手册、当前前端程序、正式菜单配置及数据库只读核对结果编写。截图过程仅登录、查询、打开并取消弹窗,未执行任何新增、修改、删除或保存操作。' 'warn' Add-PageBreak Add-Heading '文档修订记录' 1 Add-Table @( @('版本', '日期', '修订内容', '说明'), @('V1.0', '2026-07-23', '首次编制系统管理篇样稿', '覆盖当前正式菜单中的五个功能') ) @(2, 3, 7, 4) Add-Heading '阅读说明' 1 Add-ItemList @( '本手册中的【按钮名称】表示页面可点击按钮,“字段名称”表示输入框、下拉框或表格列。', '截图中的业务数据来自正式环境,只用于说明界面;本次编制没有创建测试数据。', '涉及新增、编辑、删除、重置密码、菜单分配的步骤均为操作说明,编制时未实际提交。', '当前正式菜单以数据库配置为准,包括人员管理、菜单管理、角色管理、工位管理、报工操作记录。参考手册中的“节假日设定”不在当前正式菜单,本样稿不纳入。' ) Add-PageBreak Add-Text '目 录' 20 $true 1 0x8F4A31 0 12 0 $tocRange = $selection.Range $toc = $doc.TablesOfContents.Add($tocRange, $true, 1, 3, $true, '', $true, $true, '', $true, $true, $true) Move-End Add-PageBreak Add-Heading '1 系统管理概述' 1 Add-Text '系统管理用于维护登录账号、角色、角色可见菜单、生产工位主数据,并查询生产报工操作轨迹。该模块中的主数据会被计划排产、生产执行、质量、设备、工时和审计功能共同使用,因此操作人员应具备系统管理员权限,并在修改前确认影响范围。' 10.5 $false 0 0 0 6 0.74 Add-Heading '1.1 功能范围' 2 Add-Table @( @('序号', '功能', '主要用途', '是否会写入数据'), @('1', '人员管理', '维护账号、姓名、角色、班组及密码', '查询不写入;新增/编辑/重置/删除会写入'), @('2', '角色管理', '维护角色名称', '查询不写入;新增/编辑/删除会写入'), @('3', '菜单管理', '按角色分配或移除一级、二级菜单', '过滤不写入;分配/移除会写入'), @('4', '工位管理', '维护生产工位名称和工位号', '查询不写入;新增/编辑/删除会写入'), @('5', '报工操作记录', '按订单或操作人查询生产操作轨迹', '只读查询') ) @(1.2, 3, 7.6, 4.2) Add-Heading '1.2 数据关系总览' 2 Add-Table @( @('上游/主数据', '本模块关系', '下游使用位置', '变更影响'), @('角色主数据', '角色管理创建角色;菜单管理为角色分配页面', '用户登录后的左侧菜单和页面访问范围', '角色改名会同步显示;菜单变更通常需重新登录后验证'), @('人员主数据 + 人员角色关系', '人员管理把账号关联到一个角色,并可维护班组', '登录、排产指派、人员绑定、班次、工时、报工操作人', '更换角色会改变菜单;删除角色关系后账号不再出现在人员列表'), @('MES资源主数据(工位)', '工位管理维护工位号和工位名称', '排产、加工中心、人员绑定、设备/工位查询、工时记录', '新增/改名还会调用 SAP B1 Resources;删除当前仅删除MES记录'), @('生产执行动作', '开始、结束、报工、辅助等动作形成操作记录', '报工操作记录页面用于追溯订单、人员、工位和工时', '本页面不反向修改生产数据') ) @(3.5, 4.5, 5.2, 4.4) Add-Note '推荐顺序' '新增账号时,先确认角色,再配置角色菜单,最后新增人员并验证登录;新增工位时,先确认工位号和名称,再维护工位,随后到人员绑定或计划相关页面完成下游配置。' 'info' Add-Heading '1.3 通用查询与安全原则' 2 Add-ItemList @( '空白查询条件通常表示不限制该字段;多个条件同时填写时按“并且”组合。', '带“×”或清除图标的输入框可先清空,再点击【查询】恢复全量或默认结果。', '分页页面可切换每页10、20、30、40条;切换每页条数后从第1页重新查询。', '红色【删除】和所有确认弹窗均属于写操作。正式环境中应先确认下游占用和回退方案。', '本手册不要求使用示例数据验证写操作;如需验证,应在测试环境完成。' ) Add-PageBreak Add-Heading '2 人员管理' 1 Add-Text '入口:左侧菜单【系统管理】→【人员管理】。该页面用于维护能够登录MES的人员账号,以及账号对应的角色和班组。人员角色关系直接决定登录后的可见菜单;人员姓名、工号和班组还会被排产、生产、人员绑定、班次、工时等功能引用。' 10.5 $false 0 0 0 6 0.74 Add-Figure (Join-Path $prepared 'personnel-list.png') '图2-1 人员管理列表(正式环境只读截图)' Add-Heading '2.1 页面字段' 2 Add-Table @( @('区域', '字段/按钮', '说明'), @('查询区', '姓名', '按姓名关键字模糊匹配,可输入完整姓名或其中一部分'), @('查询区', '角色', '从现有角色中选择,按角色编号精确过滤'), @('列表', '姓名、工号、密码、角色、班组', '密码固定显示为“******”,页面不展示明文'), @('操作', '重置密码、编辑、删除', '分别重置初始密码、维护人员资料、解除人员登录角色关系'), @('分页', '总数、每页条数、页码、跳页', '默认每页10条,可选10/20/30/40条') ) @(2.3, 4.2, 10.5) Add-Heading '2.2 搜索与过滤' 2 Add-StepList @( '在“姓名”中输入关键字;不填写表示不限制姓名。', '在“角色”下拉框中选择一个角色;不选择表示不限制角色。', '点击【查询】。姓名和角色同时填写时,系统只显示同时满足两个条件的人员。', '如无结果,先清空一个条件再查询,并确认当前页码;必要时返回第1页。' ) Add-Table @( @('条件示例', '匹配方式', '结果说明'), @('姓名=“张”', '包含匹配', '姓名中包含“张”的人员'), @('角色=“计划员”', '精确匹配角色', '关联到计划员角色的人员'), @('姓名=“张” 且 角色=“计划员”', '两个条件取交集', '同时满足姓名关键字和角色的人员'), @('两个条件均为空', '不限制', '按人员内部编号倒序分页显示') ) @(5, 4, 8) Add-Heading '2.3 新增人员' 2 Add-Figure (Join-Path $prepared 'personnel-add.png') '图2-2 新增人员弹窗' Add-StepList @( '点击【新增】打开“增加人员”弹窗。', '填写“姓名”和“工号”,并从“角色”下拉框选择角色。三项均为必填。', '核对工号未被其他账号使用后,点击【确定】。点击【取消】不会产生数据。', '新增成功后列表回到第1页,并按默认每页10条重新查询。' ) Add-Note '初始密码' '新增人员的初始密码由系统固定为 123456,弹窗不显示密码输入框。应通知本人首次登录后按公司密码管理要求处理,避免长期使用初始密码。' 'warn' Add-Note '数据关系' '保存时同时创建人员基本记录和“人员—角色”关联。新增弹窗不能维护班组;如需班组,新增后使用【编辑】补充。工号已存在时新增失败。' 'info' Add-Heading '2.4 编辑人员' 2 Add-StepList @( '在目标人员行点击【编辑】。', '可修改姓名、班组和角色;工号为只读,不能在编辑弹窗中更换。', '班组可选装配、电气、机加、质检、技术、计划、库房、采购、销售、售后、工艺、其他,也可清空。', '点击【确定】写入人员资料并更新该人员的角色关联;点击【取消】放弃修改。' ) Add-Note '影响范围' '修改角色后,该账号下一次登录加载的新菜单以目标角色的菜单配置为准;修改姓名或班组会影响后续页面中的人员显示和筛选,但历史业务记录通常保留原记录内容。' 'warn' Add-Heading '2.5 重置密码' 2 Add-StepList @( '在目标人员行点击【重置密码】。', '核对人员姓名和工号,在确认框点击【确定】。', '系统将密码重置为 123456,并提示“密码重置成功”。点击【取消】不做任何修改。' ) Add-Heading '2.6 删除人员' 2 Add-StepList @( '先确认该人员不再需要登录,并完成在办任务、工位绑定、班次和责任事项交接。', '点击该行【删除】,在“当前人员将永久删除”确认框中再次核对。', '点击【确定】后,系统移除人员与角色的关联,列表提示“人员离职成功”;点击【取消】不做修改。' ) Add-Note '重要说明' '当前实现不是物理删除全部人员历史,而是移除人员角色关联,使其不再出现在本页联查结果中。已有报工、工时、检验等历史业务记录不会随此操作级联删除。' 'danger' Add-PageBreak Add-Heading '3 角色管理' 1 Add-Text '入口:左侧菜单【系统管理】→【角色管理】。角色是人员和菜单之间的中间层:人员选择角色,菜单管理再为角色分配页面。角色名称用于界面展示,角色编号用于保持人员、菜单关联。' 10.5 $false 0 0 0 6 0.74 Add-Figure (Join-Path $prepared 'role-list.png') '图3-1 角色管理列表(右侧空白为当前页面布局)' 15 Add-Heading '3.1 搜索与分页' 2 Add-StepList @( '在“角色功能”输入角色名称关键字。', '点击【查询】;系统按包含关系模糊匹配角色名称。', '清空输入框后再次查询可恢复全部普通角色。', '列表默认每页10条,可选10/20/30/40条并支持跳页。' ) Add-Note '系统保留角色' '超级管理员(角色编号1)被查询逻辑排除,不会显示在角色管理列表和人员页面的角色下拉框中,避免通过普通维护误改。' 'info' Add-Heading '3.2 新增角色' 2 Add-Figure (Join-Path $prepared 'role-add.png') '图3-2 新增角色弹窗' Add-StepList @( '点击【新增】。', '填写唯一的“角色功能”名称,如岗位或职责名称。该字段必填。', '点击【确定】创建角色;存在同名角色时系统提示失败。点击【取消】不产生数据。', '角色创建后还没有菜单权限,应进入【菜单管理】完成分配,再用于人员账号。' ) Add-Heading '3.3 编辑角色' 2 Add-StepList @( '在目标角色行点击【编辑】。', '修改角色名称后点击【确定】。系统校验不能与其他角色重名。', '编辑只修改显示名称,角色编号不变,因此原有人员关联和菜单配置仍保留。' ) Add-Heading '3.4 删除角色' 2 Add-StepList @( '先在人员管理中把该角色下的人员调整到其他角色。', '再到菜单管理逐项移除该角色下的二级菜单,最后移除一级菜单。', '返回角色管理点击【删除】,确认后完成删除。' ) Add-Table @( @('系统提示', '原因', '处理方法'), @('当前角色已经分配了菜单', '角色仍有关联菜单记录', '到菜单管理先移除子菜单,再移除一级菜单'), @('当前角色已经分配了人员', '仍有人员使用该角色', '到人员管理把相关人员改为其他角色'), @('删除成功', '菜单和人员关联均已解除', '角色从角色主数据中删除') ) @(5.2, 5.2, 6.6) Add-PageBreak Add-Heading '4 菜单管理' 1 Add-Text '入口:左侧菜单【系统管理】→【菜单管理】。当前正式页面用于“给角色分配菜单”,不是维护菜单名称、路径或页面代码。菜单数据在用户登录时转换为动态路由,因此分配结果决定该角色登录后左侧导航栏显示哪些模块。' 10.5 $false 0 0 0 6 0.74 Add-Figure (Join-Path $prepared 'menu-list.png') '图4-1 菜单管理初始页面(尚未选择角色)' Add-Heading '4.1 三栏布局与过滤' 2 Add-Table @( @('位置', '内容', '过滤规则'), @('顶部角色下拉框', '选择待配置的普通角色', '支持在下拉框中输入关键字筛选角色'), @('左栏:一级模块', '系统管理、计划排产、生产管理等一级菜单模板', '输入关键字后按模块名称包含匹配'), @('中栏:已分配菜单树', '当前角色已拥有的一级和二级菜单', '输入关键字后按树节点名称包含匹配'), @('右栏:二级菜单', '全部页面菜单及其所属一级模块路径', '输入关键字后按二级模块名称包含匹配') ) @(3.5, 7, 6.5) Add-Note '过滤性质' '三栏关键字过滤均在当前已加载列表中即时执行,不会修改权限,也不需要点击查询按钮。清空关键字即可恢复该栏全部内容。' 'info' Add-Figure (Join-Path $prepared 'menu-permission.png') '图4-2 选择“管理员”后的已分配菜单树' Add-Heading '4.2 分配一级菜单' 2 Add-StepList @( '在顶部选择目标角色,中栏随即加载该角色现有菜单。', '在左栏勾选一个或多个一级模块。已分配的一级模块复选框不可重复选择。', '点击左栏与中栏之间的向右箭头。', '在确认框核对角色和选择项,点击【确定】完成分配;点击【取消】不写入。' ) Add-Note '数据关系' '一级菜单以超级管理员的菜单模板为来源,分配时复制到目标角色的菜单配置中。一级菜单只是目录;要看到具体页面,还需继续分配二级菜单。' 'info' Add-Heading '4.3 分配二级菜单' 2 Add-StepList @( '在中栏仅勾选一个一级菜单,作为二级菜单的归属目录。', '在右栏勾选一个或多个二级菜单。已分配的二级菜单不可重复选择。', '点击中栏与右栏之间的向左箭头。', '确认后,所选页面加入目标角色的目标一级目录。' ) Add-Note '校验规则' '必须且只能选择一个中栏一级菜单;选中二级节点或同时选多个节点时,箭头不可用或系统提示“只可以分配给一个一级菜单”。' 'warn' Add-Heading '4.4 移除菜单' 2 Add-StepList @( '在中栏找到要撤回的二级菜单,必要时使用顶部关键字过滤。', '点击该二级菜单右侧【移除】,在确认框点击【确定】。', '如需移除一级菜单,必须先移除其全部二级菜单;有子节点时一级菜单的【移除】不可用。', '全部子菜单移除后,再移除空的一级菜单。' ) Add-Note '生效验证' '菜单变更后,应让目标账号退出并重新登录,核对左侧导航。移除菜单会影响页面入口,但不删除该页面产生的历史业务数据。' 'danger' Add-Heading '4.5 当前页面边界' 2 Add-ItemList @( '当前页面未提供可见的“新增菜单、编辑菜单名称、修改路径、删除菜单模板”入口。', '页面代码中的查询/新增/编辑/删除按钮级权限控件处于停用状态,当前只分配页面级菜单。', '因此正式操作中不要把本页理解为菜单结构设计器;新页面上线需由开发/实施人员维护模板和路由。' ) Add-PageBreak Add-Heading '5 工位管理' 1 Add-Text '入口:左侧菜单【系统管理】→【工位管理】。工位是生产任务、设备、人员绑定和工时记录的共同基础数据。列表只显示有效的机加工资源,以及名称为“外协”的特殊资源。' 10.5 $false 0 0 0 6 0.74 Add-Figure (Join-Path $prepared 'workstation-list.png') '图5-1 工位管理列表(右侧空白为当前页面布局)' 15 Add-Heading '5.1 列表与查询' 2 Add-Table @( @('字段/按钮', '说明'), @('工位名称', '业务人员识别工位的显示名称'), @('工位号', '工位唯一业务编码,供MES与SAP B1资源关联'), @('编辑', '只允许修改工位名称,工位号保持不变'), @('删除', '从MES资源主数据删除该工位'), @('查询', '当前版本刷新全部工位列表') ) @(5, 12) Add-Note '当前限制' '页面虽然显示“工位名称”输入框,但当前查询请求没有传递该字段。无论输入什么内容,点击【查询】都会重新加载全部工位,不能按名称过滤。' 'warn' Add-Heading '5.2 新增工位' 2 Add-Figure (Join-Path $prepared 'workstation-add.png') '图5-2 新增工位弹窗' Add-StepList @( '点击【新增】。', '填写“工位名称”和“工位号”,两项均为必填。工位号应沿用公司现有编码规则。', '确认名称未重复、工位号未占用后点击【确定】;点击【取消】不产生数据。', 'MES新增成功后,前端同时向 SAP B1 Resources 创建类型为 rtMachine 的资源。' ) Add-Note '保存前检查' '正式环境不得用临时名称或测试编码尝试保存。新增会同时影响MES和SAP B1,失败时应分别核对两端是否一致,避免重复创建。' 'danger' Add-Heading '5.3 编辑工位' 2 Add-StepList @( '在目标工位行点击【编辑】。', '修改工位名称。工位号作为关联键不在编辑弹窗中开放修改。', '点击【确定】后,MES更新资源名称,并调用 SAP B1 Resources 按同一工位号更新名称。', '如新名称已被其他工位使用,系统提示“存在同名工位”。' ) Add-Heading '5.4 删除工位' 2 Add-StepList @( '先确认工位没有未完排产、在制任务、人员绑定、设备关联和进行中的工时记录。', '记录工位号和名称,确认已具备可恢复依据。', '点击【删除】,在确认框点击【确定】后从MES资源主数据删除。' ) Add-Note '高风险操作' '当前删除过程没有启用菜单/人员等占用校验,也没有调用 SAP B1 删除资源。删除可能造成MES与SAP B1不一致,并影响历史关联查询。未经业务负责人和系统管理员确认,不应执行。' 'danger' Add-Heading '5.5 下游数据关系' 2 Add-Table @( @('下游功能', '使用方式', '变更影响'), @('计划排产/工位计划', '作为指派对象或工位维度', '改名后新查询显示新名称;删除会使后续选择缺失'), @('生产执行/加工中心', '定位任务执行工位并形成操作记录', '错误工位会影响报工归属和工时统计'), @('人员绑定/班次', '建立人员与工位的可执行关系', '删除前必须解除或确认绑定'), @('设备与工时', '关联设备状态、人员工时、设备工时', '删除可能导致历史或在制数据无法正常联查'), @('SAP B1 Resources', '新增和改名时以工位号同步资源', '两端应使用同一编码和名称') ) @(4, 6, 7) Add-PageBreak Add-Heading '6 报工操作记录' 1 Add-Text '入口:左侧菜单【系统管理】→【报工操作记录】。该页面是只读审计页面,用于追溯生产执行产生的操作轨迹,不提供新增、编辑、删除或导出。进入页面后自动加载最新记录。' 10.5 $false 0 0 0 6 0.74 Add-Figure (Join-Path $prepared 'operation-log.png') '图6-1 报工操作记录(正式环境只读截图)' Add-Heading '6.1 搜索与过滤' 2 Add-StepList @( '按订单追溯时,在“订单编号”输入完整订单编号。', '按人员追溯时,在“操作人”输入完整姓名。', '两个条件可同时填写,系统只返回订单编号和操作人均完全相同的记录。', '点击【查询】;清空两个条件后查询,恢复最新100条记录。' ) Add-Table @( @('条件', '匹配方式', '注意事项'), @('订单编号', '精确相等', '不支持包含匹配;少字符、多空格或编号不完整均可能无结果'), @('操作人', '精确相等', '应使用系统记录中的完整姓名'), @('订单编号 + 操作人', '两个条件取交集', '适合核对某人在指定订单上的操作'), @('均为空', '最新记录', '按记录内部编号倒序,仅返回前100条') ) @(4.5, 4, 8.5) Add-Note '当前限制' '页面分页控件已停用,后端每次最多返回最新100条。较早记录如不在最近100条内,必须填写准确订单编号或操作人缩小范围,但同一条件仍只返回该结果集最新100条。' 'warn' Add-Heading '6.2 表格字段说明' 2 Add-Table @( @('字段组', '字段', '业务含义'), @('业务定位', '订单编号、合同号、物料编号、物料描述', '定位生产订单及对应产品/零件'), @('工艺与资源', '工序名称、工位名称', '说明在哪一道工序、哪个工位发生操作'), @('人员与动作', '操作人、操作类别、操作数值、操作描述', '说明谁执行了什么动作及数量/补充说明'), @('时间与工时', '开始时间、结束时间、人员工时、设备工时', '用于核对动作区间及工时结果'), @('审计信息', '最后编辑人、最后编辑时间', '识别记录后续调整责任人和时间') ) @(3, 6, 8) Add-Heading '6.3 前后数据关系' 2 Add-Table @( @('前序动作', '形成的记录信息', '本页用途'), @('开始加工/辅助开始', '操作类别、订单、工序、工位、操作人、开始时间', '核对任务是否启动、由谁启动'), @('报工/辅助结束/加工结束', '结束时间、操作数值、人员工时、设备工时', '核对报工数量和工时结果'), @('后续编辑', '最后编辑人、最后编辑时间、操作描述', '追溯调整人员和调整时间') ) @(5, 7, 5) Add-Note '审计原则' '本页数据来自生产执行操作记录表,只用于查询展示。发现异常时应回到对应生产任务、工时或业务处理页面核对,不能在本页直接更改记录。' 'info' Add-PageBreak Add-Heading '7 典型业务链路' 1 Add-Heading '7.1 新增可登录人员' 2 Add-StepList @( '在角色管理确认目标角色存在;没有时创建唯一角色名称。', '在菜单管理选择该角色,先分配一级菜单,再分配二级页面。', '在人员管理新增姓名、工号和角色;系统使用初始密码123456。', '如需班组,新增成功后编辑人员补充班组。', '让本人登录验证菜单范围,禁止使用正式业务写操作做权限测试。' ) Add-Heading '7.2 下线一个角色' 2 Add-StepList @( '在人员管理按角色筛选,逐一把人员调整到其他有效角色。', '在菜单管理选择原角色,先移除所有二级菜单,再移除一级菜单。', '在角色管理删除角色。若仍提示占用,返回前两步继续核对。', '保留变更审批或操作记录,以便追溯权限调整。' ) Add-Heading '7.3 新增生产工位' 2 Add-StepList @( '由生产、设备、计划和系统管理员共同确认工位号、工位名称及SAP B1资源规则。', '在工位管理一次性准确填写并保存,避免用测试编码试录。', '核对MES工位列表和SAP B1 Resources是否一致。', '再到人员绑定、设备或计划页面完成下游关系配置。', '使用只读查询验证可选项,不创建正式生产任务作为测试。' ) Add-Heading '7.4 追溯一次报工操作' 2 Add-StepList @( '优先取得完整订单编号,在报工操作记录中精确查询。', '如需进一步缩小范围,再填写完整操作人姓名。', '横向滚动核对合同、物料、工序、工位、开始/结束时间和工时。', '结合最后编辑人、最后编辑时间判断是否发生后续调整。', '需要纠正时转到对应业务页面,并按审批流程处理。' ) Add-Heading '8 常见问题' 1 Add-Table @( @('问题', '原因判断', '处理建议'), @('人员查询不到', '姓名/角色组合无匹配,或人员角色关联已移除', '清空条件并回到第1页;确认人员是否已执行删除/离职'), @('新账号登录后没有菜单', '角色尚未配置一级/二级菜单,或登录会话未刷新', '菜单管理补充分配后退出并重新登录'), @('角色删除失败', '角色仍分配菜单或人员', '先转移人员,再按“二级→一级”顺序移除菜单'), @('工位名称输入后仍显示全部', '当前版本未把名称条件传给查询接口', '按列表滚动查找;不要反复输入或保存测试数据'), @('工位编辑提示同名', '目标名称已被资源主数据占用', '核对现有工位名称,使用经审批的唯一名称'), @('报工记录查询不到', '页面使用精确匹配,且最多返回最新100条', '输入完整订单编号/操作人,检查空格和编号格式'), @('菜单无法移除一级模块', '一级模块仍有子菜单', '先逐个移除二级菜单,再移除一级模块') ) @(5, 6, 6) Add-Heading '9 正式环境操作红线' 1 Add-ItemList @( '不得使用“测试、test、临时”等数据在正式环境验证新增功能。', '不得通过新增后删除的方式验证操作流程;删除不一定能恢复全部上下游关系。', '不得直接删除仍有关联任务、人员、菜单、设备或工时的角色和工位。', '重置密码、分配菜单、人员换角色均应取得授权,并通知受影响人员。', '涉及SAP B1同步的工位新增/改名,必须核对两端结果;异常时停止重复提交。', '所有截图、查询和核对优先使用只读操作;写操作应按审批、备份和回退方案执行。' ) Add-Heading '附录A 技术数据关系(供管理员核对)' 1 Add-Table @( @('功能', '主要数据对象', '关系说明'), @('人员管理', '登录基础数据_人员信息;登录基础数据_人员权限角色', '人员主记录通过人员编号关联角色编号'), @('角色管理', '登录基础数据_角色信息', '角色编号被人员关系和菜单配置引用'), @('菜单管理', '登录基础数据_二级菜单', '同一菜单模板按角色编号形成角色菜单配置'), @('工位管理', 'MES_资源主数据;View_基础数据_工位;SAP B1 Resources', '工位号/VisCode为跨系统关联键,名称用于显示'), @('报工操作记录', 'YL_加工中心_操作记录表', '生产动作写入,本页按订单或操作人只读查询') ) @(4, 7, 6) Add-Text '—— 系统管理篇结束 ——' 11 $true 1 0x777777 18 0 0 Write-Output 'PROGRESS=content-complete' # Header and footer foreach ($section in $doc.Sections) { $header = $section.Headers.Item(1).Range $header.Text = '大连元利流体技术有限公司 MES系统操作手册 | 系统管理篇' $header.Font.NameFarEast = '微软雅黑' $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.Size = 8.5 $footer.Font.Color = 0x777777 $footer.ParagraphFormat.Alignment = 1 $footer.Collapse(0) $footer.Fields.Add($footer, 33) | Out-Null } Write-Output 'PROGRESS=headers-complete' foreach ($item in $doc.TablesOfContents) { $item.Update() } $doc.Fields.Update() | Out-Null $doc.Repaginate() Write-Output 'PROGRESS=fields-complete' if (Test-Path $docxPath) { Remove-Item -LiteralPath $docxPath -Force } if (Test-Path $pdfPath) { Remove-Item -LiteralPath $pdfPath -Force } $doc.SaveAs($docxPath, 12) Write-Output 'PROGRESS=docx-saved' $doc.ExportAsFixedFormat($pdfPath, 17) Write-Output 'PROGRESS=pdf-saved' $pageCount = $doc.ComputeStatistics(2) $doc.Close(0) $doc = $null Copy-Item -LiteralPath $docxPath -Destination $desktopDocx -Force Copy-Item -LiteralPath $pdfPath -Destination $desktopPdf -Force Write-Output ('DOCX=' + $docxPath) Write-Output ('PDF=' + $pdfPath) Write-Output ('DESKTOP_DOCX=' + $desktopDocx) Write-Output ('DESKTOP_PDF=' + $desktopPdf) Write-Output ('PAGES=' + $pageCount) } catch { $buildError = $_ Write-Output ('BUILD_ERROR=' + $_.Exception.Message) Write-Output ('BUILD_ERROR_LINE=' + $_.InvocationInfo.ScriptLineNumber) } finally { if ($doc -ne $null) { try { $doc.Close(0) } catch {} } if ($word -ne $null) { try { $word.Quit() } catch {} } [GC]::Collect() [GC]::WaitForPendingFinalizers() } if ($buildError -ne $null) { throw $buildError }