From 78c80cf5f733d42c5f5fb209333daa4efd3471f7 Mon Sep 17 00:00:00 2001
From: zhangshun <453905631@qq.com>
Date: Mon, 29 Jun 2026 09:29:25 +0800
Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9ESPC=E5=9F=BA=E6=9C=AC?=
=?UTF-8?q?=E8=B6=8B=E5=8A=BF=E5=9B=BE=E9=A1=B5=E9=9D=A2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
spc-vue/README.md | 1 +
spc-vue/src/router.ts | 2 +
spc-vue/src/utils/chartOptions.ts | 127 +++++++++++++++++++++++++++++
spc-vue/src/views/RunChartView.vue | 49 +++++++++++
4 files changed, 179 insertions(+)
create mode 100644 spc-vue/src/views/RunChartView.vue
diff --git a/spc-vue/README.md b/spc-vue/README.md
index 265db89..ad7e554 100644
--- a/spc-vue/README.md
+++ b/spc-vue/README.md
@@ -15,6 +15,7 @@ npm run dev
## 页面路由
- `/overview`:SPC 总览和关键指标
+- `/run-chart`:基本趋势图,显示原始序列、均值线、中位线、规格限和移动平均线
- `/xbar-r`:Xbar 控制图,控制限来自 XR 结果
- `/r-chart`:R 极差控制图
- `/xbar-s`:Xbar 控制图,控制限来自 XS 结果
diff --git a/spc-vue/src/router.ts b/spc-vue/src/router.ts
index 688ea56..41d1182 100644
--- a/spc-vue/src/router.ts
+++ b/spc-vue/src/router.ts
@@ -5,10 +5,12 @@ import RChartView from "./views/RChartView.vue";
import XBarSView from "./views/XBarSView.vue";
import SChartView from "./views/SChartView.vue";
import CpkView from "./views/CpkView.vue";
+import RunChartView from "./views/RunChartView.vue";
export const routes = [
{ path: "/", redirect: "/overview" },
{ path: "/overview", component: OverviewView, meta: { title: "总览" } },
+ { path: "/run-chart", component: RunChartView, 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" } },
diff --git a/spc-vue/src/utils/chartOptions.ts b/spc-vue/src/utils/chartOptions.ts
index ba86785..3948c35 100644
--- a/spc-vue/src/utils/chartOptions.ts
+++ b/spc-vue/src/utils/chartOptions.ts
@@ -3,6 +3,14 @@ import type { ControlLimitChart, CpkResult } from "../types/spc";
const chartColors = ["#0f766e", "#b45309", "#991b1b", "#2563eb"];
+export interface RunChartInput {
+ values: readonly number[];
+ usl: number;
+ lsl: number;
+ target: number;
+ movingAverageWindow?: number;
+}
+
// 生成从 1 开始的子组序号,用于控制图横轴。
export function sequenceLabels(length: number): string[] {
return Array.from({ length }, (_, index) => String(index + 1));
@@ -13,6 +21,36 @@ function constantSeries(length: number, value: number): number[] {
return Array.from({ length }, () => value);
}
+// 计算算术平均值,用于基本趋势图的均值线。
+function mean(values: readonly number[]): number {
+ if (!values.length) return 0;
+ return values.reduce((sum, value) => sum + value, 0) / values.length;
+}
+
+// 计算中位数,用于基本趋势图的中心参考线。
+function median(values: readonly number[]): number {
+ if (!values.length) return 0;
+ const sorted = [...values].sort((a, b) => a - b);
+ const middle = Math.floor(sorted.length / 2);
+ return sorted.length % 2 === 0 ? (sorted[middle - 1] + sorted[middle]) / 2 : sorted[middle];
+}
+
+// 计算移动平均线,窗口不足时使用当前已有数据,避免前几项为空。
+function movingAverage(values: readonly number[], windowSize: number): number[] {
+ return values.map((_, index) => {
+ const start = Math.max(0, index - windowSize + 1);
+ return mean(values.slice(start, index + 1));
+ });
+}
+
+// 找出超出规格限的原始数据点,用于基本趋势图标红。
+function outOfSpecPoints(values: readonly number[], usl: number, lsl: number): Array<[number, number]> {
+ return values
+ .map((value, index) => ({ value, index }))
+ .filter((point) => point.value > usl || point.value < lsl)
+ .map((point) => [point.index, point.value]);
+}
+
// 计算直方图 X 轴范围,覆盖分箱、规格限、正态曲线和原始极值,并保留少量边距。
function calculateHistogramXAxisRange(cpk: CpkResult): { min: number; max: number } {
const values = [
@@ -114,6 +152,95 @@ export function createControlLimitOption(chart: ControlLimitChart): EChartsOptio
};
}
+// 创建基本趋势图配置,按原始顺序展示数据并叠加规格限、均值线、中位线和移动平均线。
+export function createRunChartOption(input: RunChartInput): EChartsOption {
+ const labels = sequenceLabels(input.values.length);
+ const average = mean(input.values);
+ const middle = median(input.values);
+ const windowSize = Math.max(2, Math.floor(input.movingAverageWindow || 5));
+ const outliers = outOfSpecPoints(input.values, input.usl, input.lsl);
+
+ return {
+ color: chartColors,
+ tooltip: { trigger: "axis" },
+ legend: { top: 0, right: 0 },
+ grid: { left: 56, right: 34, top: 46, bottom: 44 },
+ xAxis: {
+ type: "category",
+ name: "样本序号",
+ data: labels,
+ boundaryGap: false,
+ axisLabel: { color: "#667085" }
+ },
+ yAxis: {
+ type: "value",
+ name: "测量值",
+ scale: true,
+ axisLabel: { color: "#667085" },
+ splitLine: { lineStyle: { color: "#e5e7eb" } }
+ },
+ series: [
+ {
+ name: "原始数据",
+ type: "line",
+ data: [...input.values],
+ symbolSize: 4,
+ lineStyle: { width: 1.8 }
+ },
+ {
+ name: `${windowSize}点移动平均`,
+ type: "line",
+ data: movingAverage(input.values, windowSize),
+ smooth: true,
+ symbol: "none",
+ lineStyle: { width: 2 }
+ },
+ {
+ name: "均值",
+ type: "line",
+ data: constantSeries(input.values.length, average),
+ symbol: "none",
+ lineStyle: { type: "dashed", width: 1.4 }
+ },
+ {
+ name: "中位线",
+ type: "line",
+ data: constantSeries(input.values.length, middle),
+ symbol: "none",
+ lineStyle: { type: "dashed", width: 1.4 }
+ },
+ {
+ name: "超规格点",
+ type: "scatter",
+ data: outliers,
+ symbolSize: 10,
+ itemStyle: { color: "#dc2626" }
+ },
+ {
+ name: "USL",
+ type: "line",
+ data: constantSeries(input.values.length, input.usl),
+ symbol: "none",
+ lineStyle: { type: "dotted", width: 1.5 }
+ },
+ {
+ name: "LSL",
+ type: "line",
+ data: constantSeries(input.values.length, input.lsl),
+ symbol: "none",
+ lineStyle: { type: "dotted", width: 1.5 }
+ },
+ {
+ name: "目标值",
+ type: "line",
+ data: constantSeries(input.values.length, input.target),
+ symbol: "none",
+ lineStyle: { type: "dotted", width: 1.5 }
+ }
+ ]
+ };
+}
+
// 创建过程能力指标柱状图,便于快速查看 Cp/Cpk/Pp/Ppk 门槛。
export function createCapabilityBarOption(cpk: CpkResult): EChartsOption {
const labels = ["Cp", "Cpk", "Pp", "Ppk", "CPU", "CPL"];
diff --git a/spc-vue/src/views/RunChartView.vue b/spc-vue/src/views/RunChartView.vue
new file mode 100644
index 0000000..f809497
--- /dev/null
+++ b/spc-vue/src/views/RunChartView.vue
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+