拆分SPC直方图和正态曲线页面

This commit is contained in:
zhangshun
2026-06-29 09:37:23 +08:00
parent 78c80cf5f7
commit 9192ccbe83
6 changed files with 145 additions and 44 deletions

View File

@@ -16,11 +16,13 @@ npm run dev
- `/overview`SPC 总览和关键指标
- `/run-chart`:基本趋势图,显示原始序列、均值线、中位线、规格限和移动平均线
- `/histogram`:频数直方图,只显示分箱频数和规格限,不叠加正态曲线
- `/normal-curve`:正态曲线,单独显示拟合分布和规格限
- `/xbar-r`Xbar 控制图,控制限来自 XR 结果
- `/r-chart`R 极差控制图
- `/xbar-s`Xbar 控制图,控制限来自 XS 结果
- `/s-chart`S 标准差控制图
- `/cpk`:过程能力与直方图
- `/cpk`:过程能力指标
## 接口校验重点

View File

@@ -6,11 +6,15 @@ import XBarSView from "./views/XBarSView.vue";
import SChartView from "./views/SChartView.vue";
import CpkView from "./views/CpkView.vue";
import RunChartView from "./views/RunChartView.vue";
import HistogramView from "./views/HistogramView.vue";
import NormalCurveView from "./views/NormalCurveView.vue";
export const routes = [
{ path: "/", redirect: "/overview" },
{ path: "/overview", component: OverviewView, meta: { title: "总览" } },
{ path: "/run-chart", component: RunChartView, meta: { title: "趋势图" } },
{ path: "/histogram", component: HistogramView, meta: { title: "直方图" } },
{ path: "/normal-curve", component: NormalCurveView, meta: { title: "正态曲线" } },
{ path: "/xbar-r", component: XBarRView, meta: { title: "Xbar-R" } },
{ path: "/r-chart", component: RChartView, meta: { title: "R 图" } },
{ path: "/xbar-s", component: XBarSView, meta: { title: "Xbar-S" } },

View File

@@ -287,12 +287,12 @@ export function createCapabilityBarOption(cpk: CpkResult): EChartsOption {
};
}
// 创建直方图和正态曲线配置,用来核对分布和规格限位置
export function createHistogramOption(cpk: CpkResult): EChartsOption {
// 创建单独直方图配置,只展示频数分布和规格限,不叠加正态曲线
export function createFrequencyHistogramOption(cpk: CpkResult): EChartsOption {
const xRange = calculateHistogramXAxisRange(cpk);
return {
color: ["#0f766e", "#b45309"],
color: ["#0f766e"],
tooltip: { trigger: "axis" },
legend: { top: 0, right: 0 },
grid: { left: 52, right: 48, top: 46, bottom: 42 },
@@ -303,44 +303,73 @@ export function createHistogramOption(cpk: CpkResult): EChartsOption {
max: xRange.max,
axisLabel: { color: "#667085" }
},
yAxis: [
{
type: "value",
name: "频数",
axisLabel: { color: "#667085" },
splitLine: { lineStyle: { color: "#e5e7eb" } }
},
{
type: "value",
name: "正态曲线",
axisLabel: { color: "#667085" },
splitLine: { show: false }
}
],
yAxis: {
type: "value",
name: "频数",
minInterval: 1,
axisLabel: { color: "#667085" },
splitLine: { lineStyle: { color: "#e5e7eb" } }
},
series: [
{
name: "频数",
type: "bar",
data: cpk.Xk.map((value, index) => [value, cpk.YkCount[index]]),
barMaxWidth: 28,
barMaxWidth: 34,
markLine: {
symbol: "none",
data: [
{ xAxis: cpk.LSL, name: "LSL" },
{ xAxis: cpk.USL, name: "USL" },
{ xAxis: cpk.SL, name: "SL" }
{ xAxis: cpk.SL, name: "目标值" }
],
label: { color: "#667085" },
lineStyle: { color: "#991b1b", type: "dashed" }
}
}
]
};
}
// 创建正态曲线配置,单独查看拟合曲线与规格限关系。
export function createNormalCurveOption(cpk: CpkResult): EChartsOption {
const xRange = calculateHistogramXAxisRange(cpk);
return {
color: ["#b45309"],
tooltip: { trigger: "axis" },
legend: { top: 0, right: 0 },
grid: { left: 52, right: 48, top: 46, bottom: 42 },
xAxis: {
type: "value",
name: "测量值",
min: xRange.min,
max: xRange.max,
axisLabel: { color: "#667085" }
},
yAxis: {
type: "value",
name: "概率密度",
axisLabel: { color: "#667085" },
splitLine: { lineStyle: { color: "#e5e7eb" } }
},
series: [
{
name: "正态曲线",
type: "line",
smooth: true,
symbolSize: 4,
data: cpk.NormalDistributionX.map((value, index) => [value, cpk.NormalDistributionY[index]]),
markLine: {
symbol: "none",
data: [
{ xAxis: cpk.LSL, name: "LSL" },
{ xAxis: cpk.USL, name: "USL" },
{ xAxis: cpk.SL, name: "目标值" }
],
label: { color: "#667085" },
lineStyle: { color: "#991b1b", type: "dashed" }
}
},
{
name: "正态曲线",
type: "line",
yAxisIndex: 1,
smooth: true,
symbolSize: 4,
data: cpk.NormalDistributionX.map((value, index) => [value, cpk.NormalDistributionY[index]])
}
]
};

View File

@@ -3,7 +3,7 @@ import { computed } from "vue";
import EChartPanel from "../components/EChartPanel.vue";
import MetricStrip from "../components/MetricStrip.vue";
import { useSpc } from "../composables/useSpc";
import { createCapabilityBarOption, createHistogramOption } from "../utils/chartOptions";
import { createCapabilityBarOption } from "../utils/chartOptions";
const { result } = useSpc();
@@ -21,25 +21,16 @@ const metrics = computed(() => {
});
const capabilityOption = computed(() => (result.value?.Cpk ? createCapabilityBarOption(result.value.Cpk) : null));
const histogramOption = computed(() => (result.value?.Cpk ? createHistogramOption(result.value.Cpk) : null));
</script>
<template>
<article class="page-stack">
<MetricStrip v-if="metrics.length" :metrics="metrics" />
<div class="two-column">
<EChartPanel
title="过程能力指标"
eyebrow="Capability"
description="能力柱状图用于快速比较 Cp、Cpk、Pp、Ppk。页面保留 1.00 与 1.33 参考线,方便验证常见能力门槛。"
:option="capabilityOption"
/>
<EChartPanel
title="直方图与正态曲线"
eyebrow="Distribution"
description="直方图展示测量值分布,并叠加正态曲线和规格限,便于判断能力指标是否被偏态或边界数据影响。"
:option="histogramOption"
/>
</div>
<EChartPanel
title="过程能力指标"
eyebrow="Capability"
description="能力柱状图用于快速比较 Cp、Cpk、Pp、Ppk。页面保留 1.00 与 1.33 参考线,方便验证常见能力门槛;分布形态请在直方图和正态曲线页面单独查看。"
:option="capabilityOption"
/>
</article>
</template>

View File

@@ -0,0 +1,38 @@
<script setup lang="ts">
import { computed } from "vue";
import EChartPanel from "../components/EChartPanel.vue";
import MetricStrip from "../components/MetricStrip.vue";
import { useSpc } from "../composables/useSpc";
import { createFrequencyHistogramOption } from "../utils/chartOptions";
const { result } = useSpc();
const option = computed(() => (result.value?.Cpk ? createFrequencyHistogramOption(result.value.Cpk) : null));
const metrics = computed(() => {
const cpk = result.value?.Cpk;
if (!cpk) return [];
const maxCount = Math.max(...cpk.YkCount);
return [
{ label: "分箱数", value: cpk.GroupCount },
{ label: "组距", value: cpk.GroupWidth },
{ label: "最大频数", value: maxCount },
{ label: "最小值", value: cpk.ValueMin },
{ label: "最大值", value: cpk.ValueMax },
{ label: "规格限", value: `${cpk.LSL} ~ ${cpk.USL}` }
];
});
</script>
<template>
<article class="page-stack">
<MetricStrip v-if="metrics.length" :metrics="metrics" />
<EChartPanel
title="频数直方图"
eyebrow="Histogram"
description="直方图只展示各测量区间的频数分布,并标出规格限和目标值。它适合先观察真实分布形态、偏态、双峰、离群区间以及数据是否靠近规格边界。"
:option="option"
/>
</article>
</template>

View File

@@ -0,0 +1,37 @@
<script setup lang="ts">
import { computed } from "vue";
import EChartPanel from "../components/EChartPanel.vue";
import MetricStrip from "../components/MetricStrip.vue";
import { useSpc } from "../composables/useSpc";
import { createNormalCurveOption } from "../utils/chartOptions";
const { result } = useSpc();
const option = computed(() => (result.value?.Cpk ? createNormalCurveOption(result.value.Cpk) : null));
const metrics = computed(() => {
const cpk = result.value?.Cpk;
if (!cpk) return [];
return [
{ label: "Sigma", value: cpk.Singma },
{ label: "SigmaS", value: cpk.SingmaS },
{ label: "Ca", value: cpk.Ca },
{ label: "SL", value: cpk.SL },
{ label: "USL", value: cpk.USL },
{ label: "LSL", value: cpk.LSL }
];
});
</script>
<template>
<article class="page-stack">
<MetricStrip v-if="metrics.length" :metrics="metrics" />
<EChartPanel
title="正态曲线"
eyebrow="Normal Curve"
description="正态曲线单独展示当前 SPC 结果中的拟合分布,并标出规格限和目标值。它用于辅助判断能力指标解释是否依赖正态分布假设。"
:option="option"
/>
</article>
</template>