383 lines
24 KiB
PowerShell
383 lines
24 KiB
PowerShell
$ErrorActionPreference = 'Stop'
|
||
|
||
$root = (Resolve-Path (Join-Path $PSScriptRoot '..\..')).Path
|
||
$prepared = Join-Path $PSScriptRoot 'prepared'
|
||
$docDir = Join-Path $root 'doc'
|
||
$desktop = [Environment]::GetFolderPath('Desktop')
|
||
$fileName = '大连元利流体技术有限公司MES系统_系统管理问题清单_2026-07-23'
|
||
$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 $docDir | Out-Null
|
||
|
||
$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.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.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)
|
||
$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)
|
||
for ($i = 0; $i -lt $Items.Count; $i++) {
|
||
Add-Text ('(' + ($i + 1) + ')' + $Items[$i]) 10.5 $false 0 0 0 4 0
|
||
}
|
||
}
|
||
|
||
function Add-Table {
|
||
param([object[]]$Rows, [double[]]$WidthsCm = @())
|
||
$table = $doc.Tables.Add($selection.Range, $Rows.Count, $Rows[0].Count)
|
||
$table.Borders.Enable = 1
|
||
$table.Range.Font.NameFarEast = '宋体'
|
||
$table.Range.Font.Name = 'Arial'
|
||
$table.Range.Font.Size = 8.8
|
||
$table.Range.ParagraphFormat.SpaceAfter = 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')
|
||
$table = $doc.Tables.Add($selection.Range, 1, 1)
|
||
$cell = $table.Cell(1, 1)
|
||
$table.Borders.Enable = 1
|
||
$cell.Range.Text = $Title + ':' + $Text
|
||
$cell.Range.Font.NameFarEast = '微软雅黑'
|
||
$cell.Range.Font.Size = 9.5
|
||
$cell.Range.ParagraphFormat.SpaceAfter = 0
|
||
if ($Kind -eq 'danger') {
|
||
$cell.Shading.BackgroundPatternColor = 0xD9E2F3
|
||
} elseif ($Kind -eq 'warn') {
|
||
$cell.Shading.BackgroundPatternColor = 0xD9F2FF
|
||
} 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-Issue {
|
||
param(
|
||
[string]$Id,
|
||
[string]$Title,
|
||
[string]$Priority,
|
||
[string]$Status,
|
||
[string]$Description,
|
||
[string]$Evidence,
|
||
[string]$Impact,
|
||
[string]$Recommendation,
|
||
[string]$Verification
|
||
)
|
||
Add-Heading ($Id + ' ' + $Title) 2
|
||
Add-Table @(
|
||
@('优先级', '确认状态', '涉及模块'),
|
||
@($Priority, $Status, $Id.Split('-')[0])
|
||
) @(4, 5, 8)
|
||
Add-Text ('问题描述:' + $Description) 10.5 $false 0 0 0 5 0
|
||
Add-Text ('证据:' + $Evidence) 10 $false 0 0x555555 0 5 0
|
||
Add-Text ('影响:' + $Impact) 10.5 $false 0 0 0 5 0
|
||
Add-Text ('建议:' + $Recommendation) 10.5 $false 0 0 0 5 0
|
||
Add-Text ('验证建议:' + $Verification) 10 $false 0 0x555555 0 9 0
|
||
}
|
||
|
||
function Add-PageBreak { $selection.InsertBreak(7) }
|
||
|
||
Add-Text '' 12 $false 1 0 0 18 0
|
||
Add-Text '大连元利流体技术有限公司' 22 $true 1 0x8F4A31 0 12 0
|
||
Add-Text 'MES 系统管理问题清单' 30 $true 1 0x8F4A31 0 16 0
|
||
Add-Text '操作手册编制发现项(独立文档)' 19 $true 1 0x4D4D4D 0 28 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 '问题来源:前端代码、正式菜单、数据库对象定义及只读页面检查' 11 $false 1 0 0 24 0
|
||
Add-Note '安全声明' '本清单通过只读查询、源代码检查和页面查看形成。没有在正式环境执行新增、修改、删除、密码重置、权限分配或其他写操作。涉及写操作的问题未在正式环境提交复现。' 'warn'
|
||
Add-PageBreak
|
||
|
||
Add-Text '目 录' 20 $true 1 0x8F4A31 0 12 0
|
||
$toc = $doc.TablesOfContents.Add($selection.Range, $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-Table @(
|
||
@('级别', '定义', '处理建议'),
|
||
@('P1 高', '可能造成账号安全、跨系统数据不一致、主数据不可恢复或权限风险', '优先评审,修复前设置管理措施'),
|
||
@('P2 中', '影响常用查询、维护准确性、审计完整性或容易导致误操作', '纳入近期版本,补充测试用例'),
|
||
@('P3 低', '文档、可维护性或未启用代码问题,当前业务影响较小', '随版本整理或技术债处理')
|
||
) @(2.5, 9, 5.5)
|
||
Add-Note '确认状态说明' '“已确认”表示代码、页面或数据库定义可直接证明;“待测试环境复现”表示风险已从实现中识别,但为避免正式环境产生数据,尚未提交写操作验证。' 'info'
|
||
|
||
Add-Heading '2 问题汇总' 1
|
||
Add-Table @(
|
||
@('编号', '优先级', '问题摘要', '确认状态'),
|
||
@('SEC-001', 'P1', '登录和人员接口存在明文密码暴露风险,初始密码固定', '已确认'),
|
||
@('MENU-001', 'P1', '菜单管理前端发送原始SQL文本,接口授权边界风险', '已确认'),
|
||
@('WS-001', 'P1', '工位MES与SAP B1写入非原子,失败无补偿', '待测试环境复现'),
|
||
@('WS-002', 'P1', '工位删除无占用校验,且未同步删除B1资源', '已确认'),
|
||
@('WS-003', 'P2', '工位名称查询框不生效', '已确认'),
|
||
@('WS-004', 'P2', '工位名称/工位号校验不完整', '已确认'),
|
||
@('PER-001', 'P2', '人员“永久删除”提示与实际处理语义不一致', '已确认'),
|
||
@('LOG-001', 'P2', '报工记录精确匹配、最多100条且无分页', '已确认'),
|
||
@('MENU-002', 'P2', '菜单结构维护和按钮级权限界面未开放', '已确认'),
|
||
@('DOC-001', 'P3', '参考手册与当前正式菜单范围不一致', '已确认'),
|
||
@('WS-005', 'P3', '工位分页回调引用不存在的方法', '已确认')
|
||
) @(2.4, 2.2, 9, 3.4)
|
||
|
||
Add-PageBreak
|
||
Add-Heading '3 P1 高优先级问题' 1
|
||
|
||
Add-Issue 'SEC-001' '密码处理与默认密码存在安全风险' 'P1 高' '已确认' `
|
||
'人员查询响应包含密码字段;前端虽然显示为星号,仍把返回值保存到页面对象。登录页“记住账号”会把用户输入的密码写入浏览器Cookie并保留7天。新增和重置密码统一使用固定初始密码123456。' `
|
||
'src/views/SystemMaintenance/PersonnelManagement/index.vue:279、383、460;src/views/login/index.vue:206、243-245;数据库重置过程直接写入固定密码。' `
|
||
'拥有浏览器本机访问权限、调试权限或接口访问权限的人员可能取得密码;统一初始密码会扩大弱口令和批量撞库风险。' `
|
||
'后端仅保存加盐哈希;人员查询接口不得返回密码;移除密码Cookie,记住登录应使用短期安全令牌;新账号生成随机一次性密码并强制首次登录修改;重置后立即失效其他会话。' `
|
||
'在隔离测试环境完成登录、记住账号、创建账号、重置密码和首次改密的安全测试,并检查浏览器Cookie、网络响应和数据库字段。'
|
||
Add-Figure (Join-Path $prepared 'personnel-list.png') '图3-1 人员页面虽然遮蔽密码,但接口对象仍接收密码字段'
|
||
|
||
Add-Issue 'MENU-001' '菜单管理由浏览器发送原始SQL文本' 'P1 高' '已确认' `
|
||
'菜单管理的角色菜单查询、一级菜单初始化和二级菜单初始化由前端把SELECT语句放在请求name字段中发送给通用接口,其中角色编号直接插入SQL字符串。' `
|
||
'src/api/BasicData/MenuManagement.js:20-59,getModule、initFisrtLevel、initSecondLevel均使用type=3和原始SQL文本。' `
|
||
'即使正常页面只允许选择数字角色,攻击者仍可绕过页面直接构造请求。若后端缺少严格白名单和参数化限制,可能形成越权查询或SQL注入入口。' `
|
||
'改为固定后端接口或存储过程,角色编号使用强类型参数;服务器按当前用户权限校验目标角色;关闭通用任意SQL执行能力;增加安全审计和异常请求告警。' `
|
||
'由安全人员在测试环境检查通用接口是否允许修改SQL、跨角色查询和非SELECT语句,禁止在正式环境进行攻击性验证。'
|
||
|
||
Add-Issue 'WS-001' '工位MES与SAP B1写入缺少一致性保障' 'P1 高' '待测试环境复现' `
|
||
'新增和编辑工位时先等待MES接口成功,然后调用postB1或patchB1,但B1调用没有await、失败处理、重试或回滚。页面在MES成功后即可提示成功并关闭弹窗。' `
|
||
'src/views/SystemMaintenance/WorkstationManagement/index.vue:193-205、228-249。' `
|
||
'B1超时、证书、登录态或业务校验失败时,MES已经成功而B1可能失败,形成同一工位号在两个系统中的名称或存在状态不一致。用户重复提交还可能产生重复资源。' `
|
||
'将跨系统写入放到后端编排;记录同步状态和错误详情;B1成功后再向页面返回整体成功;失败时执行补偿或进入可重试队列;按工位号实现幂等。' `
|
||
'测试环境模拟B1成功、超时、业务拒绝和重复编码四种情况,核对MES、B1和页面提示是否一致。'
|
||
|
||
Add-Issue 'WS-002' '工位删除无占用校验且未同步B1' 'P1 高' '已确认' `
|
||
'工位删除存储过程中的菜单/人员占用校验代码已注释,当前直接删除MES_资源主数据;前端删除成功后没有调用SAP B1资源删除或停用接口。' `
|
||
'src/views/SystemMaintenance/WorkstationManagement/index.vue:257-280;数据库过程“系统管理_工位管理_工位信息删除”直接DELETE,依赖检查为注释。' `
|
||
'可能删除仍被排产、在制任务、人员绑定、设备或工时使用的工位;同时B1保留资源,造成主数据不一致和历史联查异常。' `
|
||
'恢复并扩展占用校验;有历史记录时优先停用而不是物理删除;同步B1停用状态;增加删除审批、影响预览和可恢复机制。' `
|
||
'只在测试环境建立完整的排产、人员绑定和工时引用场景,验证阻止删除、停用和跨系统同步。'
|
||
|
||
Add-PageBreak
|
||
Add-Heading '4 P2 中优先级问题' 1
|
||
|
||
Add-Issue 'WS-003' '工位名称查询框不生效' 'P2 中' '已确认' `
|
||
'页面绑定了工位名称输入框,但searchData构造的参数数组为空,没有把RoleFunctioning传入查询接口。输入任意名称点击查询仍刷新全部工位。' `
|
||
'src/views/SystemMaintenance/WorkstationManagement/index.vue:4-10、122、163-169;只读页面检查结果与代码一致。' `
|
||
'工位数量增多后无法快速定位,用户可能误以为没有匹配结果或误操作同名/相近工位。' `
|
||
'前端把工位名称作为查询参数传入参数化存储过程;后端按业务要求采用包含匹配;增加空条件、中文关键字、无结果和特殊字符测试。' `
|
||
'测试环境准备多个相近名称工位,验证空条件、部分名称和完整名称查询。'
|
||
Add-Figure (Join-Path $prepared 'workstation-list.png') '图4-1 工位页面显示查询框,但当前请求未使用输入值' 15
|
||
|
||
Add-Issue 'WS-004' '工位校验规则不完整' 'P2 中' '已确认' `
|
||
'新增只显式检查同名工位,没有在存储过程中预检查工位号重复。编辑的同名检查统计全部记录,包含当前工位本身,因此不修改名称直接保存时也会被判断为同名。' `
|
||
'数据库过程“系统管理_工位管理_工位信息增加”和“系统管理_工位管理_工位信息修改”;编辑过程的同名条件未排除当前工位号。' `
|
||
'重复工位号可能依赖数据库异常兜底并产生不友好提示;无变化保存可能失败,增加用户困惑和重复操作。' `
|
||
'新增时同时校验工位号和名称唯一;编辑时使用“Name=@名称 AND VisCode<>@当前工位号”;后端返回明确错误码和字段级提示。' `
|
||
'测试空值、重复名称、重复编号、原名称不变、名称仅大小写/空格变化等边界。'
|
||
|
||
Add-Issue 'PER-001' '人员删除提示与实际处理语义不一致' 'P2 中' '已确认' `
|
||
'页面确认文字为“当前人员将永久删除”,成功提示为“人员离职成功”;数据库过程没有物理删除人员主记录,而是写Quit=0并删除人员角色关系。列表通过角色关系联查,因此人员从列表消失。' `
|
||
'src/views/SystemMaintenance/PersonnelManagement/index.vue:345-366;数据库过程“人员管理_人员信息修改_删除”。' `
|
||
'管理员难以判断人员是离职、停用还是永久删除;人员主记录仍在但无角色关系,后续重新启用和历史查询缺少明确流程。' `
|
||
'统一业务语义为“停用/离职”;明确Quit字段状态定义;保留角色历史或增加有效期;页面展示在职/离职状态和恢复入口;禁止使用“永久删除”误导。' `
|
||
'测试环境验证离职后登录、列表、历史工时、报工记录和重新启用行为。'
|
||
|
||
Add-Issue 'LOG-001' '报工操作记录查询能力不足' 'P2 中' '已确认' `
|
||
'订单编号和操作人采用精确相等;查询最多返回按记录编号倒序的前100条;页面分页控件整体注释,日期和操作类别等已存在的数据字段没有查询入口。' `
|
||
'src/views/SystemMaintenance/OperationLog/index.vue:63-75、87-93、108-125;数据库过程“系统管理_报工操作记录_查询”使用TOP 100和等值条件。' `
|
||
'较早或同一订单超过100条的记录无法完整查看;姓名/订单输入不完整时无结果;审计人员无法按时间范围和操作类别定位。' `
|
||
'增加服务端分页、总数、开始/结束日期和操作类别;订单支持精确优先并可选包含匹配;提供导出并限制最大范围;建立合适索引。' `
|
||
'使用脱敏测试数据验证跨页、超过100条、时间边界、空条件和导出结果完整性。'
|
||
Add-Figure (Join-Path $prepared 'operation-log.png') '图4-2 报工操作记录当前仅提供订单编号和操作人条件'
|
||
|
||
Add-Issue 'MENU-002' '菜单结构维护和按钮级权限界面未开放' 'P2 中' '已确认' `
|
||
'页面存在“新增一级模块”弹窗和相关方法,但模板没有可见入口;查询、新增、编辑、删除按钮级权限复选框被注释。当前实际功能只是把既有一级、二级菜单分配给角色。' `
|
||
'src/views/SystemMaintenance/MenuManagement/index.vue:82-89、152-170、367-393。' `
|
||
'旧手册描述新增、编辑、删除菜单和权限分配,容易让管理员寻找不存在的功能;页面级授权过粗,不能限制同页写操作。' `
|
||
'明确产品边界:如不开放结构维护,删除不可达代码并修订文档;如需按钮权限,完成前后端授权校验,不能只依赖前端隐藏按钮。' `
|
||
'测试不同角色的查询、新增、编辑、删除接口权限,确认直接请求也会被服务器拒绝。'
|
||
Add-Figure (Join-Path $prepared 'menu-permission.png') '图4-3 当前菜单页实际为角色菜单树分配'
|
||
|
||
Add-PageBreak
|
||
Add-Heading '5 P3 低优先级问题' 1
|
||
|
||
Add-Issue 'DOC-001' '参考手册与当前正式菜单不一致' 'P3 低' '已确认' `
|
||
'参考手册系统管理包含“节假日设定”,但正式数据库菜单没有该页面;正式菜单新增“报工操作记录”,参考手册没有对应章节。项目中还存在OrgManagement页面,但未配置为正式菜单。' `
|
||
'参考文档系统管理章节;正式表“登录基础数据_二级菜单”;src/views/SystemMaintenance目录。' `
|
||
'继续沿用旧手册会遗漏正式功能并培训不存在的入口,造成操作人员和实施人员理解不一致。' `
|
||
'以正式菜单版本为基线建立文档版本号和发布日期;每次菜单上线同步更新手册;未上线页面标注“开发中/停用”而不是混入正式手册。' `
|
||
'发布前由业务、实施和开发三方按角色逐项核对左侧菜单与手册目录。'
|
||
|
||
Add-Issue 'WS-005' '工位分页回调引用不存在的方法' 'P3 低' '已确认' `
|
||
'工位页面当前没有显示分页控件,但handleSizeChange和handleCurrentChange均调用this.searchTable(),组件实际查询方法名为searchData()。' `
|
||
'src/views/SystemMaintenance/WorkstationManagement/index.vue:163-175、288-297。' `
|
||
'当前未触发;如果后续恢复分页控件,切换页码将产生运行时错误,查询无法执行。' `
|
||
'把回调统一改为searchData,补充组件测试;删除未使用的分页状态或完整实现服务端分页。' `
|
||
'在测试环境启用分页后验证切换每页条数、页码和末页行为。'
|
||
|
||
Add-Heading '6 建议处理顺序' 1
|
||
Add-Table @(
|
||
@('阶段', '建议事项', '目标'),
|
||
@('立即管理措施', '禁用共享账号;不勾选记住密码;限制系统管理权限;禁止直接删除工位;工位变更人工核对MES/B1', '在代码修复前降低安全和数据风险'),
|
||
@('第一批修复', 'SEC-001、MENU-001、WS-001、WS-002', '处理账号安全、接口授权和跨系统一致性'),
|
||
@('第二批修复', 'WS-003、WS-004、PER-001、LOG-001、MENU-002', '改善维护准确性、审计完整性和权限粒度'),
|
||
@('文档与技术债', 'DOC-001、WS-005', '统一正式菜单与文档,清理潜在故障代码')
|
||
) @(3, 10, 4)
|
||
|
||
Add-Heading '7 验收要求' 1
|
||
Add-ItemList @(
|
||
'所有写操作问题必须在测试环境复现和回归,不得以正式业务数据作为测试数据。',
|
||
'涉及账号安全的修改需完成接口响应、Cookie、日志、数据库存储和会话失效检查。',
|
||
'涉及MES与SAP B1的修改需覆盖单边成功、单边失败、超时、重复请求和补偿重试。',
|
||
'删除/停用类功能需验证下游占用、历史查询、恢复和审计记录。',
|
||
'菜单权限必须同时验证页面可见性和后端接口授权,不能只检查按钮是否隐藏。',
|
||
'修复上线后同步更新操作手册、问题状态、版本号和发布日期。'
|
||
)
|
||
Add-Note '结论' '本清单共记录11项:P1高优先级4项、P2中优先级5项、P3低优先级2项。问题清单与操作手册分开交付,便于技术整改和业务培训分别管理。' 'danger'
|
||
|
||
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
|
||
}
|
||
|
||
foreach ($item in $doc.TablesOfContents) { $item.Update() }
|
||
$doc.Fields.Update() | Out-Null
|
||
$doc.Repaginate()
|
||
|
||
if (Test-Path $docxPath) { Remove-Item -LiteralPath $docxPath -Force }
|
||
if (Test-Path $pdfPath) { Remove-Item -LiteralPath $pdfPath -Force }
|
||
$doc.SaveAs($docxPath, 12)
|
||
$doc.ExportAsFixedFormat($pdfPath, 17)
|
||
$pageCount = $doc.ComputeStatistics(2)
|
||
$tableCount = $doc.Tables.Count
|
||
$imageCount = $doc.InlineShapes.Count
|
||
$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 ('PAGES=' + $pageCount)
|
||
Write-Output ('TABLES=' + $tableCount)
|
||
Write-Output ('IMAGES=' + $imageCount)
|
||
} 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 }
|