refactor(ui): InspectionTaskWizardWindow 全量令牌化(107 处)

检测任务向导 9 阶段模板中全部裸 HEX 颜色和越界字号替换为 Nova 令牌引用,
残留归零。这是 P3 逐页迁移的第一个文件,也是单文件改动量最大的一个。

颜色映射
- #FFFFFF(根背景/容器白底)→ NovaSurfaceContainerBrush
- #F5F6F7(左侧步骤轨)/ #FAFAFA(卡片浅背景)→ NovaSurfaceContainerLowBrush
- #E0E0E0(分隔线/边框/待定态灰)→ NovaOutlineVariantBrush
- #1B1B1B(主要文字)→ NovaOnSurfaceBrush
- #5A5A5A(次要文字)→ NovaOnSurfaceVariantBrush
- #FFFFFF(白色前景)→ NovaOnPrimaryBrush
- #107C10(完成态/运行态绿)→ NovaSuccessBrush
- #D13438(失败红)→ NovaErrorBrush
- #B0B0B0(禁用态按钮)→ NovaOnBackgroundDisabledBrush
- #F0F5FF/#B0C4DE/#1B5E9A/#3A6A9A/#7A9ABA(信息提示卡片组)→
  NovaInfoContainerBrush / NovaInfoBrush / NovaPrimaryBrush / NovaOnSurfaceVariantBrush

字号收敛
- FontSize="13" → NovaFontSizeBody (14):全部替换
- FontSize="14" → NovaFontSizeBody (14):统一引用令牌
- FontSize="16" → NovaFontSizeBodyStrong (16):标题
- FontSize="12" → NovaFontSizeCaption (12):说明文字
- FontSize="20" → NovaFontSizeSubtitle (18):判定结果大标题
- FontSize="11" → 保留现状(步骤数字,密集面板例外)
This commit is contained in:
zhengxuan.zhang
2026-07-31 17:29:58 +08:00
parent 8a41af3e38
commit 59c1707393
2 changed files with 246 additions and 84 deletions
@@ -16,7 +16,7 @@
<BooleanToVisibilityConverter x:Key="BoolToVisibility" />
</Window.Resources>
<Grid Background="#FFFFFF">
<Grid Background="{StaticResource NovaSurfaceContainerBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="168" />
<ColumnDefinition Width="Auto" />
@@ -24,7 +24,7 @@
</Grid.ColumnDefinitions>
<!-- ═══ 左侧步骤轨 ═══ -->
<Border Grid.Column="0" Background="#F5F6F7">
<Border Grid.Column="0" Background="{StaticResource NovaSurfaceContainerLowBrush}">
<ItemsControl ItemsSource="{Binding StageItems}"
Margin="0,16,0,0">
<ItemsControl.ItemTemplate>
@@ -51,20 +51,20 @@
HorizontalAlignment="Center">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="#E0E0E0" />
<Setter Property="Background" Value="{StaticResource NovaOutlineVariantBrush}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsCurrent}" Value="True">
<Setter Property="Background" Value="{StaticResource NovaPrimaryBrush}" />
</DataTrigger>
<DataTrigger Binding="{Binding IsCompleted}" Value="True">
<Setter Property="Background" Value="#107C10" />
<Setter Property="Background" Value="{StaticResource NovaSuccessBrush}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBlock Text="{Binding Number}"
FontSize="11"
Foreground="#FFFFFF"
Foreground="{StaticResource NovaOnPrimaryBrush}"
VerticalAlignment="Center"
HorizontalAlignment="Center" />
</Border>
@@ -72,15 +72,15 @@
<!-- 步骤名称 -->
<TextBlock Grid.Column="1"
Text="{Binding Name}"
FontSize="13"
FontSize="{StaticResource NovaFontSizeBody}"
VerticalAlignment="Center"
Margin="8,0,0,0">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="#5A5A5A" />
<Setter Property="Foreground" Value="{StaticResource NovaOnSurfaceVariantBrush}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsCurrent}" Value="True">
<Setter Property="Foreground" Value="#1B1B1B" />
<Setter Property="Foreground" Value="{StaticResource NovaOnSurfaceBrush}" />
<Setter Property="FontWeight" Value="SemiBold" />
</DataTrigger>
</Style.Triggers>
@@ -94,7 +94,7 @@
</Border>
<!-- ═══ 步骤分隔线 ═══ -->
<Rectangle Grid.Column="1" Width="1" Fill="#E0E0E0" />
<Rectangle Grid.Column="1" Width="1" Fill="{StaticResource NovaOutlineVariantBrush}" />
<!-- ═══ 中央参数区 ═══ -->
<ScrollViewer Grid.Column="2" VerticalScrollBarVisibility="Auto" Padding="24,16">
@@ -103,13 +103,13 @@
<!-- Stage 0: 工件录入 -->
<DataTemplate x:Key="Stage0Template">
<StackPanel>
<TextBlock Text="工件录入" FontSize="16" FontWeight="SemiBold" Foreground="#1B1B1B" />
<TextBlock Text="请输入或扫码录入工件标识" FontSize="13" Foreground="#5A5A5A" Margin="0,8,0,16" />
<Border Background="#FAFAFA" CornerRadius="8" Padding="24,32">
<TextBlock Text="工件录入" FontSize="{StaticResource NovaFontSizeBodyStrong}" FontWeight="SemiBold" Foreground="{StaticResource NovaOnSurfaceBrush}" />
<TextBlock Text="请输入或扫码录入工件标识" FontSize="{StaticResource NovaFontSizeBody}" Foreground="{StaticResource NovaOnSurfaceVariantBrush}" Margin="0,8,0,16" />
<Border Background="{StaticResource NovaSurfaceContainerLowBrush}" CornerRadius="8" Padding="24,32">
<StackPanel>
<TextBlock Text="工件号" FontSize="13" Foreground="#1B1B1B" />
<TextBlock Text="工件号" FontSize="{StaticResource NovaFontSizeBody}" Foreground="{StaticResource NovaOnSurfaceBrush}" />
<TextBox Text="{Binding WorkpieceId, UpdateSourceTrigger=PropertyChanged}"
FontSize="14" Height="36" Margin="0,8,0,0"
FontSize="{StaticResource NovaFontSizeBody}" Height="36" Margin="0,8,0,0"
Padding="8,0" />
<Button Content="创建任务"
Command="{Binding LoadWorkpieceCommand}"
@@ -117,12 +117,12 @@
Margin="0,24,0,0"
Height="36" Width="120"
Background="{StaticResource NovaPrimaryBrush}"
Foreground="#FFFFFF"
Foreground="{StaticResource NovaOnPrimaryBrush}"
HorizontalAlignment="Left">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="{StaticResource NovaPrimaryBrush}" />
<Setter Property="Foreground" Value="#FFFFFF" />
<Setter Property="Foreground" Value="{StaticResource NovaOnPrimaryBrush}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
@@ -134,7 +134,7 @@
</Setter>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="#B0B0B0" />
<Setter Property="Background" Value="{StaticResource NovaOnBackgroundDisabledBrush}" />
</Trigger>
</Style.Triggers>
</Style>
@@ -148,14 +148,14 @@
<!-- Stage 1: 图像调试 -->
<DataTemplate x:Key="Stage1Template">
<StackPanel>
<TextBlock Text="图像调试" FontSize="16" FontWeight="SemiBold" Foreground="#1B1B1B" />
<TextBlock Text="请在主界面调整实时流水线参数" FontSize="13" Foreground="#5A5A5A" Margin="0,8,0,16" />
<Border Background="#FAFAFA" CornerRadius="8" Padding="24,32">
<TextBlock Text="图像调试" FontSize="{StaticResource NovaFontSizeBodyStrong}" FontWeight="SemiBold" Foreground="{StaticResource NovaOnSurfaceBrush}" />
<TextBlock Text="请在主界面调整实时流水线参数" FontSize="{StaticResource NovaFontSizeBody}" Foreground="{StaticResource NovaOnSurfaceVariantBrush}" Margin="0,8,0,16" />
<Border Background="{StaticResource NovaSurfaceContainerLowBrush}" CornerRadius="8" Padding="24,32">
<StackPanel>
<TextBlock Text="当前流水线定义" FontSize="13" Foreground="#5A5A5A" />
<Border Background="#FFFFFF" BorderBrush="#E0E0E0" BorderThickness="1" CornerRadius="4" Margin="0,8,0,0" Padding="12,16">
<TextBlock Text="当前流水线定义" FontSize="{StaticResource NovaFontSizeBody}" Foreground="{StaticResource NovaOnSurfaceVariantBrush}" />
<Border Background="{StaticResource NovaSurfaceContainerBrush}" BorderBrush="{StaticResource NovaOutlineVariantBrush}" BorderThickness="1" CornerRadius="4" Margin="0,8,0,0" Padding="12,16">
<TextBlock Text="{Binding PipelineSummary, TargetNullValue='未选择流水线'}"
FontSize="13" Foreground="#1B1B1B" />
FontSize="{StaticResource NovaFontSizeBody}" Foreground="{StaticResource NovaOnSurfaceBrush}" />
</Border>
<Button Content="应用并锁定"
Command="{Binding ApplyPipelineCommand}"
@@ -163,7 +163,7 @@
Margin="0,20,0,0"
Height="36" Width="120"
Background="{StaticResource NovaPrimaryBrush}"
Foreground="#FFFFFF"
Foreground="{StaticResource NovaOnPrimaryBrush}"
HorizontalAlignment="Left" />
</StackPanel>
</Border>
@@ -173,25 +173,25 @@
<!-- Stage 2: BGA 识别 -->
<DataTemplate x:Key="Stage2Template">
<StackPanel>
<TextBlock Text="BGA 识别" FontSize="16" FontWeight="SemiBold" Foreground="#1B1B1B" />
<TextBlock Text="识别焊球并展示在主界面(绿色标记)" FontSize="13" Foreground="#5A5A5A" Margin="0,8,0,16" />
<TextBlock Text="BGA 识别" FontSize="{StaticResource NovaFontSizeBodyStrong}" FontWeight="SemiBold" Foreground="{StaticResource NovaOnSurfaceBrush}" />
<TextBlock Text="识别焊球并展示在主界面(绿色标记)" FontSize="{StaticResource NovaFontSizeBody}" Foreground="{StaticResource NovaOnSurfaceVariantBrush}" Margin="0,8,0,16" />
<!-- 流水线锁定摘要(复用 Stage 1 锁定数据) -->
<Border Background="#F0F5FF" CornerRadius="8" Padding="16" Margin="0,0,0,12"
BorderBrush="#B0C4DE" BorderThickness="1">
<Border Background="{StaticResource NovaInfoContainerBrush}" CornerRadius="8" Padding="16" Margin="0,0,0,12"
BorderBrush="{StaticResource NovaInfoBrush}" BorderThickness="1">
<StackPanel>
<TextBlock Text="已锁定流水线" FontSize="13" FontWeight="SemiBold" Foreground="#1B5E9A" />
<TextBlock Text="已锁定流水线" FontSize="{StaticResource NovaFontSizeBody}" FontWeight="SemiBold" Foreground="{StaticResource NovaPrimaryBrush}" />
<TextBlock Text="{Binding PipelineOperatorSummary, TargetNullValue='无'}"
FontSize="12" Foreground="#3A6A9A" Margin="0,4,0,0" TextWrapping="Wrap" />
FontSize="{StaticResource NovaFontSizeCaption}" Foreground="{StaticResource NovaPrimaryBrush}" Margin="0,4,0,0" TextWrapping="Wrap" />
<TextBlock Text="{Binding PipelineSummary, TargetNullValue='—'}"
FontSize="11" Foreground="#7A9ABA" Margin="0,2,0,0" />
FontSize="11" Foreground="{StaticResource NovaOnSurfaceVariantBrush}" Margin="0,2,0,0" />
</StackPanel>
</Border>
<Button Content="开始识别" Command="{Binding RunBgaDetectionCommand}"
Height="36" Width="120" Margin="0,0,0,16"
Background="{StaticResource NovaPrimaryBrush}" Foreground="#FFFFFF" HorizontalAlignment="Left" />
<Border Background="#FAFAFA" CornerRadius="8" Padding="16">
Background="{StaticResource NovaPrimaryBrush}" Foreground="{StaticResource NovaOnPrimaryBrush}" HorizontalAlignment="Left" />
<Border Background="{StaticResource NovaSurfaceContainerLowBrush}" CornerRadius="8" Padding="16">
<DataGrid ItemsSource="{Binding DetectedBalls}" AutoGenerateColumns="False"
MaxHeight="200" Background="Transparent" BorderThickness="0"
HeadersVisibility="Column">
@@ -210,9 +210,9 @@
<!-- Stage 3: 分组设置 -->
<DataTemplate x:Key="Stage3Template">
<StackPanel>
<TextBlock Text="分组设置" FontSize="16" FontWeight="SemiBold" Foreground="#1B1B1B" />
<TextBlock Text="设置 Block 网格参数(蓝色网格显示在主界面)" FontSize="13" Foreground="#5A5A5A" Margin="0,8,0,16" />
<Border Background="#FAFAFA" CornerRadius="8" Padding="24,32">
<TextBlock Text="分组设置" FontSize="{StaticResource NovaFontSizeBodyStrong}" FontWeight="SemiBold" Foreground="{StaticResource NovaOnSurfaceBrush}" />
<TextBlock Text="设置 Block 网格参数(蓝色网格显示在主界面)" FontSize="{StaticResource NovaFontSizeBody}" Foreground="{StaticResource NovaOnSurfaceVariantBrush}" Margin="0,8,0,16" />
<Border Background="{StaticResource NovaSurfaceContainerLowBrush}" CornerRadius="8" Padding="24,32">
<StackPanel>
<Grid>
<Grid.RowDefinitions>
@@ -227,23 +227,23 @@
</Grid.ColumnDefinitions>
<!-- X向 -->
<StackPanel Grid.Row="0" Grid.Column="0" Margin="0,0,8,16">
<TextBlock Text="X向(列)" FontSize="13" Foreground="#1B1B1B" />
<TextBox Text="{Binding PoolColumns}" FontSize="14" Height="32" Margin="0,4,0,0" />
<TextBlock Text="X向(列)" FontSize="{StaticResource NovaFontSizeBody}" Foreground="{StaticResource NovaOnSurfaceBrush}" />
<TextBox Text="{Binding PoolColumns}" FontSize="{StaticResource NovaFontSizeBody}" Height="32" Margin="0,4,0,0" />
</StackPanel>
<!-- Y向 -->
<StackPanel Grid.Row="0" Grid.Column="1" Margin="4,0,4,16">
<TextBlock Text="Y向(行)" FontSize="13" Foreground="#1B1B1B" />
<TextBox Text="{Binding PoolRows}" FontSize="14" Height="32" Margin="0,4,0,0" />
<TextBlock Text="Y向(行)" FontSize="{StaticResource NovaFontSizeBody}" Foreground="{StaticResource NovaOnSurfaceBrush}" />
<TextBox Text="{Binding PoolRows}" FontSize="{StaticResource NovaFontSizeBody}" Height="32" Margin="0,4,0,0" />
</StackPanel>
<!-- 球数 -->
<StackPanel Grid.Row="0" Grid.Column="2" Margin="8,0,0,16">
<TextBlock Text="每Block球数" FontSize="13" Foreground="#1B1B1B" />
<TextBox Text="{Binding BallsPerBlock}" FontSize="14" Height="32" Margin="0,4,0,0" />
<TextBlock Text="每Block球数" FontSize="{StaticResource NovaFontSizeBody}" Foreground="{StaticResource NovaOnSurfaceBrush}" />
<TextBox Text="{Binding BallsPerBlock}" FontSize="{StaticResource NovaFontSizeBody}" Height="32" Margin="0,4,0,0" />
</StackPanel>
</Grid>
<Button Content="生成检测池" Command="{Binding GeneratePoolCommand}"
Height="36" Width="120"
Background="{StaticResource NovaPrimaryBrush}" Foreground="#FFFFFF" HorizontalAlignment="Left" />
Background="{StaticResource NovaPrimaryBrush}" Foreground="{StaticResource NovaOnPrimaryBrush}" HorizontalAlignment="Left" />
</StackPanel>
</Border>
</StackPanel>
@@ -252,9 +252,9 @@
<!-- Stage 4: 气泡参数 -->
<DataTemplate x:Key="Stage4Template">
<StackPanel>
<TextBlock Text="气泡参数" FontSize="16" FontWeight="SemiBold" Foreground="#1B1B1B" />
<TextBlock Text="设置 BGA 气泡检测参数" FontSize="13" Foreground="#5A5A5A" Margin="0,8,0,16" />
<Border Background="#FAFAFA" CornerRadius="8" Padding="24,32">
<TextBlock Text="气泡参数" FontSize="{StaticResource NovaFontSizeBodyStrong}" FontWeight="SemiBold" Foreground="{StaticResource NovaOnSurfaceBrush}" />
<TextBlock Text="设置 BGA 气泡检测参数" FontSize="{StaticResource NovaFontSizeBody}" Foreground="{StaticResource NovaOnSurfaceVariantBrush}" Margin="0,8,0,16" />
<Border Background="{StaticResource NovaSurfaceContainerLowBrush}" CornerRadius="8" Padding="24,32">
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
@@ -268,22 +268,22 @@
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- 灵敏度 -->
<TextBlock Grid.Row="0" Grid.Column="0" Text="灵敏度" FontSize="13" VerticalAlignment="Center" />
<TextBlock Grid.Row="0" Grid.Column="0" Text="灵敏度" FontSize="{StaticResource NovaFontSizeBody}" VerticalAlignment="Center" />
<Slider Grid.Row="0" Grid.Column="1" Value="{Binding Sensitivity}" Minimum="0" Maximum="100"
Margin="8,0" VerticalAlignment="Center" />
<!-- 灰度下限 -->
<TextBlock Grid.Row="1" Grid.Column="0" Text="灰度下限" FontSize="13" Margin="0,12,0,0" VerticalAlignment="Center" />
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding ThresholdGrayMin}" FontSize="13" Margin="8,8,0,0" Height="28" Width="120" HorizontalAlignment="Left" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="灰度下限" FontSize="{StaticResource NovaFontSizeBody}" Margin="0,12,0,0" VerticalAlignment="Center" />
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding ThresholdGrayMin}" FontSize="{StaticResource NovaFontSizeBody}" Margin="8,8,0,0" Height="28" Width="120" HorizontalAlignment="Left" />
<!-- 灰度上限 -->
<TextBlock Grid.Row="2" Grid.Column="0" Text="灰度上限" FontSize="13" Margin="0,12,0,0" VerticalAlignment="Center" />
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding ThresholdGrayMax}" FontSize="13" Margin="8,8,0,0" Height="28" Width="120" HorizontalAlignment="Left" />
<TextBlock Grid.Row="2" Grid.Column="0" Text="灰度上限" FontSize="{StaticResource NovaFontSizeBody}" Margin="0,12,0,0" VerticalAlignment="Center" />
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding ThresholdGrayMax}" FontSize="{StaticResource NovaFontSizeBody}" Margin="8,8,0,0" Height="28" Width="120" HorizontalAlignment="Left" />
<!-- 气孔率限值 -->
<TextBlock Grid.Row="3" Grid.Column="0" Text="气孔率限值%" FontSize="13" Margin="0,12,0,0" VerticalAlignment="Center" />
<TextBox Grid.Row="3" Grid.Column="1" Text="{Binding MaxVoidRatePercent}" FontSize="13" Margin="8,8,0,0" Height="28" Width="120" HorizontalAlignment="Left" />
<TextBlock Grid.Row="3" Grid.Column="0" Text="气孔率限值%" FontSize="{StaticResource NovaFontSizeBody}" Margin="0,12,0,0" VerticalAlignment="Center" />
<TextBox Grid.Row="3" Grid.Column="1" Text="{Binding MaxVoidRatePercent}" FontSize="{StaticResource NovaFontSizeBody}" Margin="8,8,0,0" Height="28" Width="120" HorizontalAlignment="Left" />
</Grid>
<Button Content="应用参数" Command="{Binding ApplyBubbleParametersCommand}"
Height="36" Width="120" Margin="0,20,0,0"
Background="{StaticResource NovaPrimaryBrush}" Foreground="#FFFFFF" HorizontalAlignment="Left" />
Background="{StaticResource NovaPrimaryBrush}" Foreground="{StaticResource NovaOnPrimaryBrush}" HorizontalAlignment="Left" />
</StackPanel>
</Border>
</StackPanel>
@@ -292,9 +292,9 @@
<!-- Stage 5: 首件校准 -->
<DataTemplate x:Key="Stage5Template">
<StackPanel>
<TextBlock Text="首件校准" FontSize="16" FontWeight="SemiBold" Foreground="#1B1B1B" />
<TextBlock Text="移动机床到 Block1 中心,调整 Z/FOD(橙色标记在主界面)" FontSize="13" Foreground="#5A5A5A" Margin="0,8,0,16" />
<Border Background="#FAFAFA" CornerRadius="8" Padding="24,32">
<TextBlock Text="首件校准" FontSize="{StaticResource NovaFontSizeBodyStrong}" FontWeight="SemiBold" Foreground="{StaticResource NovaOnSurfaceBrush}" />
<TextBlock Text="移动机床到 Block1 中心,调整 Z/FOD(橙色标记在主界面)" FontSize="{StaticResource NovaFontSizeBody}" Foreground="{StaticResource NovaOnSurfaceVariantBrush}" Margin="0,8,0,16" />
<Border Background="{StaticResource NovaSurfaceContainerLowBrush}" CornerRadius="8" Padding="24,32">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120" />
@@ -308,18 +308,18 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="X (mm)" FontSize="13" />
<TextBlock Grid.Row="0" Grid.Column="0" Text="X (mm)" FontSize="{StaticResource NovaFontSizeBody}" />
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding CalibrationStageX}" Height="28" Width="120" HorizontalAlignment="Left" Margin="8,0" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="Y (mm)" FontSize="13" Margin="0,12,0,0" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="Y (mm)" FontSize="{StaticResource NovaFontSizeBody}" Margin="0,12,0,0" />
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding CalibrationStageY}" Height="28" Width="120" HorizontalAlignment="Left" Margin="8,8,0,0" />
<TextBlock Grid.Row="2" Grid.Column="0" Text="Z (mm)" FontSize="13" Margin="0,12,0,0" />
<TextBlock Grid.Row="2" Grid.Column="0" Text="Z (mm)" FontSize="{StaticResource NovaFontSizeBody}" Margin="0,12,0,0" />
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding CalibrationSourceZ}" Height="28" Width="120" HorizontalAlignment="Left" Margin="8,8,0,0" />
<TextBlock Grid.Row="3" Grid.Column="0" Text="FOD (mm)" FontSize="13" Margin="0,12,0,0" />
<TextBlock Grid.Row="3" Grid.Column="0" Text="FOD (mm)" FontSize="{StaticResource NovaFontSizeBody}" Margin="0,12,0,0" />
<TextBox Grid.Row="3" Grid.Column="1" Text="{Binding CalibrationFodMm}" Height="28" Width="120" HorizontalAlignment="Left" Margin="8,8,0,0" />
<Button Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="2"
Content="执行校准" Command="{Binding RunCalibrationCommand}"
Height="36" Width="120" Margin="0,20,0,0"
Background="{StaticResource NovaPrimaryBrush}" Foreground="#FFFFFF" HorizontalAlignment="Left" />
Background="{StaticResource NovaPrimaryBrush}" Foreground="{StaticResource NovaOnPrimaryBrush}" HorizontalAlignment="Left" />
</Grid>
</Border>
</StackPanel>
@@ -328,9 +328,9 @@
<!-- Stage 6: 应用确认 -->
<DataTemplate x:Key="Stage6Template">
<StackPanel>
<TextBlock Text="应用确认" FontSize="16" FontWeight="SemiBold" Foreground="#1B1B1B" />
<TextBlock Text="校准已应用到所有 BlockZ/FOD 共用,仅 XY 不同)" FontSize="13" Foreground="#5A5A5A" Margin="0,8,0,16" />
<Border Background="#FAFAFA" CornerRadius="8" Padding="16">
<TextBlock Text="应用确认" FontSize="{StaticResource NovaFontSizeBodyStrong}" FontWeight="SemiBold" Foreground="{StaticResource NovaOnSurfaceBrush}" />
<TextBlock Text="校准已应用到所有 BlockZ/FOD 共用,仅 XY 不同)" FontSize="{StaticResource NovaFontSizeBody}" Foreground="{StaticResource NovaOnSurfaceVariantBrush}" Margin="0,8,0,16" />
<Border Background="{StaticResource NovaSurfaceContainerLowBrush}" CornerRadius="8" Padding="16">
<DataGrid ItemsSource="{Binding TaskCalibrationResult.ScanPositions}" AutoGenerateColumns="False"
MaxHeight="240" Background="Transparent" BorderThickness="0"
HeadersVisibility="Column">
@@ -349,16 +349,16 @@
<!-- Stage 7: 自动扫描 -->
<DataTemplate x:Key="Stage7Template">
<StackPanel>
<TextBlock Text="自动扫描" FontSize="16" FontWeight="SemiBold" Foreground="#1B1B1B" />
<TextBlock Text="{Binding Message, TargetNullValue='准备扫描...'}" FontSize="13" Foreground="#5A5A5A" Margin="0,8,0,16" />
<Border Background="#FAFAFA" CornerRadius="8" Padding="24,32">
<TextBlock Text="自动扫描" FontSize="{StaticResource NovaFontSizeBodyStrong}" FontWeight="SemiBold" Foreground="{StaticResource NovaOnSurfaceBrush}" />
<TextBlock Text="{Binding Message, TargetNullValue='准备扫描...'}" FontSize="{StaticResource NovaFontSizeBody}" Foreground="{StaticResource NovaOnSurfaceVariantBrush}" Margin="0,8,0,16" />
<Border Background="{StaticResource NovaSurfaceContainerLowBrush}" CornerRadius="8" Padding="24,32">
<StackPanel>
<!-- 总进度条 -->
<ProgressBar Value="{Binding ScanProgress}" Maximum="100" Height="24" />
<TextBlock Text="{Binding CurrentStage}" FontSize="13" Foreground="#5A5A5A" Margin="0,8,0,16" />
<TextBlock Text="{Binding CurrentStage}" FontSize="{StaticResource NovaFontSizeBody}" Foreground="{StaticResource NovaOnSurfaceVariantBrush}" Margin="0,8,0,16" />
<Button Content="开始扫描" Command="{Binding StartScanningCommand}"
Height="36" Width="120"
Background="#107C10" Foreground="#FFFFFF" HorizontalAlignment="Left" />
Background="{StaticResource NovaSuccessBrush}" Foreground="{StaticResource NovaOnPrimaryBrush}" HorizontalAlignment="Left" />
</StackPanel>
</Border>
</StackPanel>
@@ -367,22 +367,22 @@
<!-- Stage 8: 结果输出 -->
<DataTemplate x:Key="Stage8Template">
<StackPanel>
<TextBlock Text="结果输出" FontSize="16" FontWeight="SemiBold" Foreground="#1B1B1B" />
<TextBlock Text="结果输出" FontSize="{StaticResource NovaFontSizeBodyStrong}" FontWeight="SemiBold" Foreground="{StaticResource NovaOnSurfaceBrush}" />
<TextBlock Text="{Binding ScanResult.FinalJudgement, StringFormat='最终判定: {0}'}"
FontSize="20" Foreground="#107C10" Margin="0,8,0,8" />
<TextBlock Text="{Binding ScanResult.FinalReason}" FontSize="13" Foreground="#5A5A5A" />
<Border Background="#FAFAFA" CornerRadius="8" Padding="16" Margin="0,16,0,0">
FontSize="{StaticResource NovaFontSizeSubtitle}" Foreground="{StaticResource NovaSuccessBrush}" Margin="0,8,0,8" />
<TextBlock Text="{Binding ScanResult.FinalReason}" FontSize="{StaticResource NovaFontSizeBody}" Foreground="{StaticResource NovaOnSurfaceVariantBrush}" />
<Border Background="{StaticResource NovaSurfaceContainerLowBrush}" CornerRadius="8" Padding="16" Margin="0,16,0,0">
<StackPanel>
<TextBlock Text="{Binding ScanResult.TotalOK, StringFormat='合格: {0} 球'}" FontSize="13" Foreground="#107C10" />
<TextBlock Text="{Binding ScanResult.TotalNG, StringFormat='不合格: {0} 球'}" FontSize="13" Foreground="#D13438" />
<TextBlock Text="计划名称" FontSize="13" Foreground="#5A5A5A" Margin="0,16,0,4" />
<TextBox Text="{Binding PlanName, TargetNullValue=''}" Height="30" FontSize="13" />
<TextBlock Text="{Binding ScanResult.TotalOK, StringFormat='合格: {0} 球'}" FontSize="{StaticResource NovaFontSizeBody}" Foreground="{StaticResource NovaSuccessBrush}" />
<TextBlock Text="{Binding ScanResult.TotalNG, StringFormat='不合格: {0} 球'}" FontSize="{StaticResource NovaFontSizeBody}" Foreground="{StaticResource NovaErrorBrush}" />
<TextBlock Text="计划名称" FontSize="{StaticResource NovaFontSizeBody}" Foreground="{StaticResource NovaOnSurfaceVariantBrush}" Margin="0,16,0,4" />
<TextBox Text="{Binding PlanName, TargetNullValue=''}" Height="30" FontSize="{StaticResource NovaFontSizeBody}" />
<Button Content="保存计划与检测项目" Command="{Binding SavePlanCommand}"
Height="36" Width="160" Margin="0,12,0,0"
Background="{StaticResource NovaPrimaryBrush}" Foreground="#FFFFFF" HorizontalAlignment="Left" />
Background="{StaticResource NovaPrimaryBrush}" Foreground="{StaticResource NovaOnPrimaryBrush}" HorizontalAlignment="Left" />
<TextBlock Text="保存后同时生成可复用检测项目(.xppool),可在 CNC 编辑器中通过「插入检测项目」加入程序。"
FontSize="12" Foreground="#5A5A5A" TextWrapping="Wrap" Margin="0,8,0,0" />
<TextBlock Text="{Binding SaveStatusMessage}" FontSize="12" Foreground="#1B1B1B"
FontSize="{StaticResource NovaFontSizeCaption}" Foreground="{StaticResource NovaOnSurfaceVariantBrush}" TextWrapping="Wrap" Margin="0,8,0,0" />
<TextBlock Text="{Binding SaveStatusMessage}" FontSize="{StaticResource NovaFontSizeCaption}" Foreground="{StaticResource NovaOnSurfaceBrush}"
TextWrapping="Wrap" Margin="0,8,0,0" />
</StackPanel>
</Border>
@@ -426,7 +426,7 @@
<!-- ═══ 底部操作栏 ═══ -->
<Border Grid.ColumnSpan="3" VerticalAlignment="Bottom" Height="48"
BorderBrush="#E0E0E0" BorderThickness="0,1,0,0" Background="#FFFFFF">
BorderBrush="{StaticResource NovaOutlineVariantBrush}" BorderThickness="0,1,0,0" Background="{StaticResource NovaSurfaceContainerBrush}">
<Grid Margin="16,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
@@ -437,7 +437,7 @@
<!-- 左侧状态提示 -->
<TextBlock Grid.Column="0"
Text="{Binding CurrentStage, StringFormat='阶段: {0}'}"
FontSize="13" Foreground="#5A5A5A"
FontSize="{StaticResource NovaFontSizeBody}" Foreground="{StaticResource NovaOnSurfaceVariantBrush}"
VerticalAlignment="Center" />
<!-- 上一步 -->
@@ -451,7 +451,7 @@
Command="{Binding GoNextCommand}"
IsEnabled="{Binding CanGoNext}"
Height="32" Width="80"
Background="{StaticResource NovaPrimaryBrush}" Foreground="#FFFFFF" />
Background="{StaticResource NovaPrimaryBrush}" Foreground="{StaticResource NovaOnPrimaryBrush}" />
</Grid>
</Border>
</Grid>
+162
View File
@@ -0,0 +1,162 @@
<#
.SYNOPSIS
NOVA UI 规范护栏:禁止新增裸 HEX 颜色值。
.DESCRIPTION
对应 .kiro/steering/ui-design.md 第 6 节「编码约束 · 禁止裸 HEX」。
颜色必须统一走 Themes/NovaColors.xaml 中的令牌(NovaXxxBrush /
NovaXxxColor),不允许在页面或代码里直接写十六进制色值。
仓库里历史遗留的裸 HEX 还有大量未迁移(P3 阶段尚在推进,详见
ui-design.md 第 7 节迁移顺序),因此本护栏默认是【增量模式】:
只检查相对于某个基准(默认与 origin 的合并基点)新增或修改的行,
不会因为历史存量而挡住无关的提交。要看全量现状用 -Mode Full。
范围限定为 XplorePlane 主项目(原生 WPF 面 + 代码侧),与
ui-design.md 第 4 节记录的范围边界一致:
- 排除 Themes/Nova*.xaml 本身(它是唯一允许出现裸 HEX 的地方)
- 排除 obj/bin 生成目录
- 不扫描跨模块项目(XP.Common、XP.Hardware.* 等)——那些明确
标注为「本次不做」,不应被这道护栏误挡
正则只匹配带引号的属性值形式 ="#RRGGBB(AA)",不匹配裸文本,
因此不会对「说明性注释里提到某个十六进制色值」产生误报
(例如 "原 #E3F0FF 浅蓝强调底,语义对应 NOVA secondaryContainer"
这类迁移记录注释)。
.PARAMETER Mode
Diff(默认):只检查增量(git diff 新增行)。
Full:扫描全部现存文件,用于生成现状报告,不建议作为提交门禁。
.PARAMETER Base
Diff 模式下的比较基准。默认自动探测 origin/主分支的合并基点;
在本地无网络/无远程的场景可显式传入一个 commit/分支名。
.PARAMETER Path
要扫描的项目根目录。默认是仓库中的 XplorePlane 主项目目录。
.EXAMPLE
pwsh tools/Check-NovaColorTokens.ps1
提交前跑:只检查本次改动是否新增了裸 HEX。
.EXAMPLE
pwsh tools/Check-NovaColorTokens.ps1 -Mode Full
生成全量现状报告(预期会有大量历史命中,仅供参考)。
.NOTES
退出码:0 = 未发现违规;1 = 发现违规。
没有现成 CI 配置时,建议接成 pre-commit(或 Kiro PreToolUse)钩子,
命令示例:
pwsh -NoProfile -File tools/Check-NovaColorTokens.ps1
一旦引入正式 CI 流水线,直接调用本脚本(Diff 模式)作为一个步骤即可。
#>
param(
[ValidateSet('Diff', 'Full')]
[string]$Mode = 'Diff',
[string]$Base,
[string]$Path = (Join-Path $PSScriptRoot '..\XplorePlane')
)
$ErrorActionPreference = 'Stop'
$RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
$Path = (Resolve-Path $Path).Path
# 带引号的属性值形式:Background="#FFFFFF"、Value="#1A2B3C"、
# "#2E7D32"C# 字符串字面量)等。不匹配裸文本,避免命中注释里的说明文字。
$hexPattern = '="#[0-9A-Fa-f]{6,8}"'
function Test-IsExcluded {
param([string]$RelativePath)
if ($RelativePath -match '[\\/](obj|bin)[\\/]') { return $true }
if ($RelativePath -match '[\\/]Themes[\\/]Nova.*\.xaml$') { return $true }
return $false
}
$violations = @()
if ($Mode -eq 'Full') {
$files = Get-ChildItem -Recurse -Path $Path -Include *.xaml, *.cs -File |
Where-Object { -not (Test-IsExcluded $_.FullName.Substring($RepoRoot.Length + 1)) }
foreach ($file in $files) {
$matches = Select-String -Path $file.FullName -Pattern $hexPattern -AllMatches
foreach ($m in $matches) {
foreach ($hit in $m.Matches) {
$violations += [pscustomobject]@{
File = $file.FullName.Substring($Path.Length + 1)
Line = $m.LineNumber
Snippet = $m.Line.Trim()
Hex = $hit.Value
}
}
}
}
}
else {
# Diff 模式:只看 git diff 里新增的行(+ 开头,排除 +++ 文件头),
# 且限定在 XplorePlane 目录下的 .xaml/.cs 文件。
if (-not $Base) {
$Base = git -C $RepoRoot merge-base HEAD origin/HEAD 2>$null
if (-not $Base) { $Base = git -C $RepoRoot rev-parse HEAD~1 2>$null }
if (-not $Base) { $Base = 'HEAD' }
}
# 同时覆盖已提交的改动(Base..HEAD)与尚未提交的工作区改动,
# 这样在提交前本地跑一次就能拦住,不必依赖已经 commit。
$diffArgs = @('-C', $RepoRoot, 'diff', '--unified=0', "$Base", '--', 'XplorePlane/*.xaml', 'XplorePlane/*.cs')
$committedDiff = & git @diffArgs 2>$null
$workingDiff = & git -C $RepoRoot diff --unified=0 -- 'XplorePlane/*.xaml' 'XplorePlane/*.cs' 2>$null
$stagedDiff = & git -C $RepoRoot diff --unified=0 --cached -- 'XplorePlane/*.xaml' 'XplorePlane/*.cs' 2>$null
$currentFile = $null
$currentLine = 0
foreach ($line in ($committedDiff + $workingDiff + $stagedDiff)) {
if ($line -match '^\+\+\+ b/(.+)$') {
$currentFile = $matches[1]
continue
}
if ($line -match '^@@ -\d+(?:,\d+)? \+(\d+)') {
$currentLine = [int]$matches[1]
continue
}
if ($line -match '^\+(?!\+\+)(.*)$') {
$content = $matches[1]
if ($currentFile -and -not (Test-IsExcluded $currentFile)) {
if ($content -match $hexPattern) {
foreach ($hit in [regex]::Matches($content, $hexPattern)) {
$violations += [pscustomobject]@{
File = $currentFile
Line = $currentLine
Snippet = $content.Trim()
Hex = $hit.Value
}
}
}
}
$currentLine++
continue
}
if ($line -match '^-') { continue }
}
}
# 同一行可能被 committedDiff/workingDiff/stagedDiff 重复统计,按 文件+行+片段 去重。
$violations = $violations | Sort-Object File, Line, Snippet -Unique
if ($violations.Count -eq 0) {
$scope = if ($Mode -eq 'Full') { '全量扫描' } else { "增量扫描(基准 $Base" }
Write-Host "[NOVA] 未发现新增裸 HEX 颜色值($scope)。" -ForegroundColor Green
exit 0
}
Write-Host "[NOVA] 发现 $($violations.Count) 处裸 HEX 颜色值,须改为引用 Themes/NovaColors.xaml 中的令牌:" -ForegroundColor Red
Write-Host ""
foreach ($v in $violations) {
Write-Host (" {0}:{1}" -f $v.File, $v.Line) -ForegroundColor Yellow
Write-Host (" {0}" -f $v.Snippet)
}
Write-Host ""
Write-Host "参见 .kiro/steering/ui-design.md 第 6 节「禁止裸 HEX」。" -ForegroundColor DarkYellow
exit 1