浏览代码

1. SPC任务管理页面多条件筛选完善
2. SPC控制图页面增加八大控制图选择
3. SPC控制图页面指标数据展示修改
4. 过程能力指标页面增加多条件筛选
5. 过程能力指标页面指标数据展示修改
6. SPC八大控制图(Xbar-R、Xbar-S)

“luofeng” 3 月之前
父节点
当前提交
03230284aa

+ 8 - 0
src/api/analysis/index.js

@@ -1,5 +1,13 @@
 import request from "@/utils/request";
 
+export function XBarSCompute(data) {
+  return request({
+    url: "/api/v1/spc/XBarSCompute",
+    method: "post",
+    data,
+  });
+}
+
 export function getData(data) {
   return request({
     url: "/api/v1/spc/page1",

+ 1 - 1
src/store/modules/dictionary.ts

@@ -32,7 +32,7 @@ export const useDictionaryStore = defineStore("dictionaryStore", () => {
     "excel_type",
     "excel_states",
     "spc_operation",
-    
+    "spc_control_chart",
   ];
   const dicts = ref<{ [key: string]: any[] }>({});
 

+ 550 - 0
src/views/analysis/process/Xbar-R.vue

@@ -0,0 +1,550 @@
+<template>
+  <div class="container1">
+    <div class="databox">
+      <el-scrollbar :style="{ height: Height + 'px' }">
+        <div class="box" v-show="!addStatus">
+          <div
+            style="
+              display: flex;
+              align-items: center;
+              justify-content: space-between;
+            "
+          >
+            <div style="display: flex; align-items: center">
+              <div class="bg"></div>
+              控制图绘制
+            </div>
+
+            <el-button
+              type="primary"
+              v-print="'#print'"
+              style="margin-left: 10px; height: 25px"
+              >打 印</el-button
+            >
+          </div>
+          <div class="info">
+            <div id="print">
+              <div id="charts" :style="{ height: maxHeight / 2 + 'px' }"></div>
+              <div id="charts1" :style="{ height: maxHeight / 2 + 'px' }"></div>
+            </div>
+          </div>
+        </div>
+      </el-scrollbar>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import * as echarts from "echarts";
+import { useDictionaryStore } from "@/store";
+
+const props = defineProps({
+  process: {
+    type: String,
+    required: true,
+  },
+});
+const { dicts } = useDictionaryStore();
+const opOptions = ref([...dicts.spc_operation]);
+const value = ref(opOptions.value[0].remark);
+const Y1value = ref([]);
+const X1array = ref([]);
+const setY1value = () => {
+  Y1value.value = [];
+  tableData.value.forEach((item) => {
+    Y1value.value.push(item.avg);
+  });
+  Y1value.value.unshift("");
+  Y1value.value.push("");
+
+  chartsOption1.value.series[0].data = Y1value.value;
+};
+const tableData = ref([]);
+const setX1array = async () => {
+  X1array.value = await [];
+  tableData.value.forEach((item, index) => {
+    X1array.value.push(index + 1);
+  });
+  X1array.value.unshift("");
+  X1array.value.push("");
+  chartsOption1.value.xAxis[0].data = X1array.value;
+};
+
+const setChart1Info = () => {
+  // chartsOption1.value.title[0].text = `上限=${showData.value.avgMax ? showData.value.avgMax : "-"}`;
+  // chartsOption1.value.title[0].text = `x̄=${showData.value.avgAvg ? showData.value.avgAvg : "-"}`;
+  chartsOption1.value.series[0].markLine.data[0].yAxis = JSON.parse(
+    value.value
+  ).avgMax;
+  chartsOption1.value.series[0].markLine.data[0].label.formatter = `                          上限=${
+    JSON.parse(value.value).avgMax ? JSON.parse(value.value).avgMax : "0"
+  }`;
+  chartsOption1.value.series[0].markLine.data[1].yAxis = JSON.parse(value.value)
+    .avgMin
+    ? JSON.parse(value.value).avgMin
+    : 0;
+  chartsOption1.value.series[0].markLine.data[1].label.formatter = `           下限=${JSON.parse(value.value).avgMin ? JSON.parse(value.value).avgMin : "0"}`;
+  chartsOption1.value.series[0].markLine.data[2].yAxis = JSON.parse(
+    value.value
+  ).avgMid;
+  chartsOption1.value.series[0].markLine.data[2].label.formatter = `x̄=${
+    JSON.parse(value.value).avgMid
+  }`;
+  // chartsOption1.value.title[2].text = `下限=${showData.value.avgMin ? showData.value.avgMin : "0"}`;
+};
+const setChart2Info = () => {
+  // chartsOption2.value.title[0].text = `上限=${showData.value.rangeMax ? showData.value.rangeMax : "-"}`;
+  // chartsOption2.value.title[0].text = `R=${showData.value.rangeAvg ? showData.value.rangeAvg : "-"}`;
+  chartsOption2.value.series[0].markLine.data[0].yAxis = JSON.parse(
+    value.value
+  ).rangeMax;
+  chartsOption2.value.series[0].markLine.data[0].label.formatter = `                          上限=${
+    JSON.parse(value.value).rangeMax ? JSON.parse(value.value).rangeMax : "0"
+  }`;
+  chartsOption2.value.series[0].markLine.data[1].yAxis = JSON.parse(value.value)
+    .rangeMin
+    ? JSON.parse(value.value).rangeMin
+    : 0;
+  chartsOption2.value.series[0].markLine.data[1].label.formatter = `           下限=${
+    JSON.parse(value.value).rangeMin ? JSON.parse(value.value).rangeMin : "0"
+  }`;
+  chartsOption2.value.series[0].markLine.data[2].yAxis = JSON.parse(
+    value.value
+  ).rangeMid;
+  chartsOption2.value.series[0].markLine.data[2].label.formatter = `x̄=${
+    JSON.parse(value.value).rangeMid
+  }`;
+  // chartsOption2.value.title[2].text = `下限=${showData.value.rangeMin ? showData.value.rangeMin : "0"}`;
+};
+const setChart1 = () => {
+  setChart1Info();
+  setY1value();
+  setX1array();
+  charts1.value.setOption(chartsOption1.value, true);
+};
+const setChart2 = () => {
+  setChart2Info();
+  setY2value();
+  setX2array();
+  charts2.value.setOption(chartsOption2.value, true);
+};
+
+const title = ref("调阻精度");
+const showLable = ref("调阻");
+const changeSelect = () => {
+  setTimeout(async () => {
+    // showLable.value = selectRef.value.currentPlaceholder;
+    // opOptions.value.forEach((item) => {
+    //   if (item.dictLabel == showLable.value) {
+    //     lableValue.value = item.dictValue;
+    //   }
+    // });
+    switch (process) {
+      case "调阻":
+        title.value = "调阻精度";
+        break;
+      case "粘片":
+        title.value = "剪切强度";
+        break;
+      case "键合":
+        title.value = "键合强度";
+        break;
+      default:
+        title.value = "调阻精度";
+        break;
+    }
+    // await getTableData();
+    chartsOption1.value.title[0].text = `${title.value}的Xbar-R控制图`;
+    setChart1();
+    setChart2();
+  }, 0);
+};
+
+const maxHeight = ref(null);
+const maxWidth = ref(null);
+const charts1 = shallowRef(null);
+const charts2 = shallowRef(null);
+const chartsOption1 = ref({
+  title: [
+    // {
+    //   text: `x̄=${showData.value.avgAvg ? showData.value.avgAvg : "-"}`,
+    //   right: "5%",
+    //   top: "42%",
+    //   textStyle: {
+    //     fontSize: 15,
+    //     color: "#333",
+    //     fontWeight: 100,
+    //   },
+    // },
+    {
+      text: `${title.value}的Xbar-R控制图`,
+      left: "40%",
+    },
+    {
+      text: "样",
+      left: "4%",
+      top: "28%",
+    },
+    {
+      text: "本",
+      left: "4%",
+      top: "35%",
+    },
+    {
+      text: "均",
+      left: "4%",
+      top: "42%",
+    },
+    {
+      text: "值",
+      left: "4%",
+      top: "49%",
+    },
+  ],
+  grid: {
+    right: "15%",
+  },
+  toolbox: {
+    feature: {
+      saveAsImage: {},
+    },
+  },
+  tooltip: {
+    show: true,
+  },
+  xAxis: [
+    {
+      type: "category",
+      boundaryGap: false,
+      data: [],
+    },
+  ],
+  yAxis: [
+    {
+      type: "value",
+    },
+  ],
+  series: [
+    {
+      type: "line",
+      lineStyle: {
+        color: "rgb(26, 122, 240)",
+      },
+      symbolSize: 13,
+      symbol: "circle",
+      itemStyle: {
+        color: (params) => {
+          const avg = JSON.parse(value.value);
+          const paramValue = Number(params.value);
+          if (
+            paramValue <= Number(avg.avgMax) &&
+            paramValue >= Number(avg.avgMin)
+          ) {
+            return "rgb(26, 122, 240)";
+          } else {
+            return "red";
+          }
+        },
+      },
+      markLine: {
+        silent: true,
+        data: [
+          {
+            silent: false,
+            yAxis: 0,
+            label: {
+              position: "end",
+              formatter: `上限=${JSON.parse(value.value).avgMax ? JSON.parse(value.value).avgMax : "-"}`,
+              color: "#333",
+            },
+            lineStyle: { type: "solid", color: "#333", width: 2 },
+          },
+          {
+            silent: false,
+            yAxis: 0,
+            label: {
+              position: "end",
+              formatter: `下限=${JSON.parse(value.value).avgMin ? JSON.parse(value.value).avgMin : "-"}`,
+              color: "#333",
+            },
+            lineStyle: {
+              type: "solid",
+              color: "#333",
+              width: 2,
+            },
+          },
+          {
+            yAxis: 0,
+            silent: false,
+            label: {
+              position: "end",
+              formatter: ``,
+              color: "#333",
+            },
+            lineStyle: {
+              type: "solid",
+              color: "#333",
+              width: 2,
+            },
+          },
+        ],
+      },
+    },
+  ],
+});
+const chartsOption2 = ref({
+  title: [
+    // {
+    //   text: `R=${showData.value.rangeAvg ? showData.value.rangeAvg : "-"}`,
+    //   right: "5%",
+    //   top: "42%",
+    //   textStyle: {
+    //     fontSize: 15,
+    //     color: "#333",
+    //     fontWeight: 100,
+    //   },
+    // },
+    {
+      text: "样",
+      left: "4%",
+      top: "28%",
+    },
+    {
+      text: "本",
+      left: "4%",
+      top: "35%",
+    },
+    {
+      text: "极",
+      left: "4%",
+      top: "42%",
+    },
+    {
+      text: "值",
+      left: "4%",
+      top: "49%",
+    },
+  ],
+  toolbox: {
+    feature: {
+      saveAsImage: {},
+    },
+  },
+  grid: {
+    right: "15%",
+  },
+  xAxis: [
+    {
+      type: "category",
+      boundaryGap: false,
+      data: [],
+    },
+  ],
+  yAxis: [
+    {
+      type: "value",
+    },
+  ],
+  tooltip: {
+    show: true,
+  },
+  series: [
+    {
+      type: "line",
+      lineStyle: {
+        color: "rgb(26, 122, 240)",
+      },
+      symbolSize: 13,
+      symbol: "circle",
+      itemStyle: {
+        color: (params) => {
+          const range = JSON.parse(value.value);
+          const paramValue = Number(params.value);
+          if (
+            paramValue <= Number(range.rangeMax) &&
+            paramValue >= Number(range.rangeMin)
+          ) {
+            return "rgb(26, 122, 240)";
+          } else {
+            return "red";
+          }
+        },
+      },
+      markLine: {
+        silent: true,
+        data: [
+          {
+            silent: false,
+            yAxis: 0,
+            label: {
+              position: "end",
+              formatter: `上限=${JSON.parse(value.value).rangeMax ? JSON.parse(value.value).rangeMax : "-"}`,
+              color: "#333",
+            },
+            lineStyle: { type: "solid", color: "#333", width: 2 },
+          },
+          {
+            silent: false,
+            yAxis: 0,
+            label: {
+              position: "end",
+              formatter: `下限=${JSON.parse(value.value).rangeMin ? JSON.parse(value.value).rangeMin : "-"}`,
+              color: "#333",
+            },
+            lineStyle: { type: "solid", color: "#333", width: 2 },
+          },
+          {
+            yAxis: 0,
+            silent: false,
+            label: {
+              position: "end",
+              formatter: ``,
+              color: "#333",
+            },
+            lineStyle: {
+              type: "solid",
+              color: "#333",
+              width: 2,
+            },
+          },
+        ],
+      },
+    },
+  ],
+});
+const Height = ref(0);
+const setHeight = () => {
+  Height.value = document.querySelector(".databox").clientHeight;
+  maxHeight.value = document.querySelector(".info").clientHeight;
+  maxWidth.value = document.querySelector(".info").clientWidth;
+};
+const Y2value = ref([]);
+const X2array = ref([]);
+const setY2value = () => {
+  Y2value.value = [];
+  tableData.value.forEach((item) => {
+    Y2value.value.push(item.range);
+  });
+  Y2value.value.unshift("");
+  Y2value.value.push("");
+  chartsOption2.value.series[0].data = Y2value.value;
+};
+const setX2array = () => {
+  X2array.value = [];
+  tableData.value.forEach((item, index) => {
+    X2array.value.push(index + 1);
+  });
+  X2array.value.unshift("");
+  X2array.value.push("");
+  chartsOption2.value.xAxis[0].data = X2array.value;
+};
+
+const setView = () => {
+  setHeight();
+  charts1.value = echarts.init(document.getElementById("charts"));
+  charts2.value = echarts.init(document.getElementById("charts1"));
+  charts1.value.setOption(chartsOption1.value, true);
+  charts2.value.setOption(chartsOption2.value, true);
+};
+onMounted(() => {
+  init();
+});
+const init = (data, str) => {
+  console.log(data, "data");
+  console.log(str, "str");
+  tableData.value = data;
+  changeSelect();
+  setHeight();
+  nextTick(() => {
+    charts1.value = echarts.init(document.getElementById("charts"));
+    charts2.value = echarts.init(document.getElementById("charts1"));
+    charts1.value.setOption(chartsOption1.value, true);
+    charts2.value.setOption(chartsOption2.value, true);
+  });
+  window.addEventListener("resize", setView);
+};
+
+onBeforeUnmount(() => {
+  window.removeEventListener("resize", setView);
+});
+
+// 暴露 init 方法
+defineExpose({
+  init,
+});
+</script>
+
+<style lang="scss" scoped>
+@media print {
+  #print {
+    margin-left: -18%;
+  }
+}
+.formStyle {
+  width: 400px;
+  margin: 20px auto;
+}
+.container1 {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  background-color: white;
+  .infobox {
+    width: 200px;
+    .header {
+      height: 120px;
+      border-bottom: 2px solid #00000010;
+      padding: 20px;
+    }
+    .body {
+      padding: 20px;
+    }
+  }
+  .databox {
+    flex: 1;
+    border-left: 2px solid #00000010;
+    .box {
+      height: 710px;
+      padding: 5px 20px;
+      display: flex;
+      flex-direction: column;
+      .illustrate {
+        padding: 20px 60px;
+      }
+      .tableTitle {
+        text-align: center;
+        margin: 10px 0;
+        padding-right: 40px;
+      }
+      .header {
+        margin-top: 20px;
+        //margin-left: 100px;
+        display: flex;
+        width: 100%;
+        height: auto;
+      }
+      //.title {
+      //  height: 50px;
+      //  display: flex;
+      //  align-items: center;
+      //  margin-bottom: 10px;
+      //  justify-content: space-between;
+      //  .btns {
+      //    display: flex;
+      //    align-items: center;
+      //    .btn {
+      //      height: 24px;
+      //      font-size: 14px;
+      //      margin: 0 5px;
+      //    }
+      //  }
+      //}
+      .info {
+        margin-top: 20px;
+        flex: 1;
+        height: 300px;
+      }
+    }
+  }
+}
+</style>

+ 570 - 0
src/views/analysis/process/Xbar-S-2.vue

@@ -0,0 +1,570 @@
+<template>
+  <div class="container1">
+    <div class="databox">
+      <el-scrollbar :style="{ height: Height + 'px' }">
+        <div class="box" v-show="!addStatus">
+          <div
+            style="
+              display: flex;
+              align-items: center;
+              justify-content: space-between;
+            "
+          >
+            <div style="display: flex; align-items: center">
+              <div class="bg"></div>
+              控制图绘制
+            </div>
+
+            <el-button
+              type="primary"
+              v-print="'#print'"
+              style="margin-left: 10px; height: 25px"
+              >打 印</el-button
+            >
+          </div>
+          <div class="info">
+            <div id="print">
+              <div id="charts" :style="{ height: maxHeight / 2 + 'px' }"></div>
+              <div id="charts1" :style="{ height: maxHeight / 2 + 'px' }"></div>
+            </div>
+          </div>
+        </div>
+      </el-scrollbar>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import * as echarts from "echarts";
+import { useDictionaryStore } from "@/store";
+import { XBarSCompute } from "@/api/analysis";
+
+const tableData = ref([]);
+const chartData = ref([]);
+const getTableData = async () => {
+  // 存储提取的 accuracys 数据
+  const accuracysList = ref([]);
+
+  // 提取 accuracys 数据
+  console.log(JSON.stringify(tableData.value), "tableData.value");
+  tableData.value.forEach((v) => {
+    accuracysList.value.push(v.accuracys);
+  });
+
+  console.log(accuracysList.value, "dataList");
+  const { data } = await XBarSCompute({
+    dataList: accuracysList.value,
+    scale: accuracysList.value[0].length,
+  });
+  console.log(JSON.stringify(data), "resultDataList");
+  data.lclX = data.lclX.toFixed(4);
+  data.uclS = data.uclS.toFixed(4);
+  data.sBar = data.sBar.toFixed(4);
+  data.xDoubleBar = data.xDoubleBar.toFixed(4);
+  data.uclX = data.uclX.toFixed(4);
+  data.lclS = data.lclS.toFixed(4);
+  data.subgroupStdDevs = data.subgroupStdDevs.map((num) =>
+    parseFloat(num.toFixed(4))
+  );
+  data.subgroupMeans = data.subgroupMeans.map((num) =>
+    parseFloat(num.toFixed(4))
+  );
+  chartData.value = data;
+};
+
+const { dicts } = useDictionaryStore();
+const opOptions = ref([...dicts.spc_operation]);
+const value = ref(opOptions.value[0].remark);
+const Y1value = ref([]);
+const X1array = ref([]);
+const setY1value = () => {
+  Y1value.value = [];
+  console.log(chartData.value, "chartData.value");
+  console.log(chartData.value.subgroupMeans, "chartData.value.subgroupMeans");
+  chartData.value.subgroupMeans.forEach((item) => {
+    Y1value.value.push(item);
+  });
+  Y1value.value.unshift("");
+  Y1value.value.push("");
+
+  chartsOption1.value.series[0].data = Y1value.value;
+};
+
+const setX1array = async () => {
+  X1array.value = await [];
+  chartData.value.subgroupMeans.forEach((item, index) => {
+    X1array.value.push(index + 1);
+  });
+  X1array.value.unshift("");
+  X1array.value.push("");
+  chartsOption1.value.xAxis[0].data = X1array.value;
+};
+
+const setChart1Info = () => {
+  // chartsOption1.value.title[0].text = `上限=${showData.value.avgMax ? showData.value.avgMax : "-"}`;
+  // chartsOption1.value.title[0].text = `x̄=${showData.value.avgAvg ? showData.value.avgAvg : "-"}`;
+  chartsOption1.value.series[0].markLine.data[0].yAxis = chartData.value.uclX;
+  chartsOption1.value.series[0].markLine.data[0].label.formatter = `           上限=${
+    chartData.value.uclX
+  }`;
+  chartsOption1.value.series[0].markLine.data[1].yAxis = chartData.value.lclX;
+  chartsOption1.value.series[0].markLine.data[1].label.formatter = `           下限=${chartData.value.lclX}`;
+  chartsOption1.value.series[0].markLine.data[2].yAxis =
+    chartData.value.xDoubleBar;
+  chartsOption1.value.series[0].markLine.data[2].label.formatter = `x̄=${
+    chartData.value.xDoubleBar
+  }`;
+  // chartsOption1.value.title[2].text = `下限=${showData.value.avgMin ? showData.value.avgMin : "0"}`;
+};
+const setChart2Info = () => {
+  // chartsOption2.value.title[0].text = `上限=${showData.value.rangeMax ? showData.value.rangeMax : "-"}`;
+  // chartsOption2.value.title[0].text = `R=${showData.value.rangeAvg ? showData.value.rangeAvg : "-"}`;
+  chartsOption2.value.series[0].markLine.data[0].yAxis = chartData.value.uclS;
+  chartsOption2.value.series[0].markLine.data[0].label.formatter = `   上限=${
+    chartData.value.uclS
+  }`;
+  chartsOption2.value.series[0].markLine.data[1].yAxis = chartData.value.lclS;
+  chartsOption2.value.series[0].markLine.data[1].label.formatter = `   下限=${
+    chartData.value.lclS
+  }`;
+  chartsOption2.value.series[0].markLine.data[2].yAxis = chartData.value.sBar;
+  chartsOption2.value.series[0].markLine.data[2].label.formatter = `   x̄=${
+    chartData.value.sBar
+  }`;
+  // chartsOption2.value.title[2].text = `下限=${showData.value.rangeMin ? showData.value.rangeMin : "0"}`;
+};
+const setChart1 = () => {
+  setChart1Info();
+  setY1value();
+  setX1array();
+  charts1.value.setOption(chartsOption1.value, true);
+};
+const setChart2 = () => {
+  setChart2Info();
+  setY2value();
+  setX2array();
+  charts2.value.setOption(chartsOption2.value, true);
+};
+
+const title = ref("调阻精度");
+const showLable = ref("调阻");
+const changeSelect = () => {
+  setTimeout(async () => {
+    // showLable.value = selectRef.value.currentPlaceholder;
+    // opOptions.value.forEach((item) => {
+    //   if (item.dictLabel == showLable.value) {
+    //     lableValue.value = item.dictValue;
+    //   }
+    // });
+    // switch (showLable.value) {
+    //   case "调阻":
+    //     title.value = "调阻精度";
+    //     break;
+    //   case "粘片":
+    //     title.value = "剪切强度";
+    //     break;
+    //   case "键合":
+    //     title.value = "键合强度";
+    //     break;
+    //   default:
+    //     title.value = "调阻精度";
+    //     break;
+    // }
+    // await getTableData();
+    chartsOption1.value.title[0].text = `${title.value}的Xbar-S控制图`;
+    setChart1();
+    setChart2();
+  }, 0);
+};
+
+const maxHeight = ref(null);
+const maxWidth = ref(null);
+const charts1 = shallowRef(null);
+const charts2 = shallowRef(null);
+const chartsOption1 = ref({
+  title: [
+    // {
+    //   text: `x̄=${showData.value.avgAvg ? showData.value.avgAvg : "-"}`,
+    //   right: "5%",
+    //   top: "42%",
+    //   textStyle: {
+    //     fontSize: 15,
+    //     color: "#333",
+    //     fontWeight: 100,
+    //   },
+    // },
+    {
+      text: `${title.value}的Xbar-S控制图`,
+      left: "40%",
+    },
+    {
+      text: "样",
+      left: "4%",
+      top: "28%",
+    },
+    {
+      text: "本",
+      left: "4%",
+      top: "35%",
+    },
+    {
+      text: "均",
+      left: "4%",
+      top: "42%",
+    },
+    {
+      text: "值",
+      left: "4%",
+      top: "49%",
+    },
+  ],
+  grid: {
+    right: "15%",
+  },
+  toolbox: {
+    feature: {
+      saveAsImage: {},
+    },
+  },
+  tooltip: {
+    show: true,
+  },
+  xAxis: [
+    {
+      type: "category",
+      boundaryGap: false,
+      data: [],
+    },
+  ],
+  yAxis: [
+    {
+      type: "value",
+    },
+  ],
+  series: [
+    {
+      type: "line",
+      lineStyle: {
+        color: "rgb(26, 122, 240)",
+      },
+      symbolSize: 13,
+      symbol: "circle",
+      itemStyle: {
+        color: (params) => {
+          const paramValue = Number(params.value);
+          if (
+            paramValue <= Number(chartData.value.uclX) &&
+            paramValue >= Number(chartData.value.lclX)
+          ) {
+            return "rgb(26, 122, 240)";
+          } else {
+            return "red";
+          }
+        },
+      },
+      markLine: {
+        silent: true,
+        data: [
+          {
+            silent: false,
+            yAxis: 0,
+            label: {
+              position: "end",
+              formatter: `上限=${chartData.value.uclX}`,
+              color: "#333",
+            },
+            lineStyle: { type: "solid", color: "#333", width: 2 },
+          },
+          {
+            silent: false,
+            yAxis: 0,
+            label: {
+              position: "end",
+              formatter: `下限=${chartData.value.lclX}`,
+              color: "#333",
+            },
+            lineStyle: {
+              type: "solid",
+              color: "#333",
+              width: 2,
+            },
+          },
+          {
+            yAxis: 0,
+            silent: false,
+            label: {
+              position: "end",
+              formatter: ``,
+              color: "#333",
+            },
+            lineStyle: {
+              type: "solid",
+              color: "#333",
+              width: 2,
+            },
+          },
+        ],
+      },
+    },
+  ],
+});
+const chartsOption2 = ref({
+  title: [
+    // {
+    //   text: `R=${showData.value.rangeAvg ? showData.value.rangeAvg : "-"}`,
+    //   right: "5%",
+    //   top: "42%",
+    //   textStyle: {
+    //     fontSize: 15,
+    //     color: "#333",
+    //     fontWeight: 100,
+    //   },
+    // },
+    {
+      text: "样",
+      left: "4%",
+      top: "28%",
+    },
+    {
+      text: "本",
+      left: "4%",
+      top: "35%",
+    },
+    {
+      text: "标",
+      left: "4%",
+      top: "42%",
+    },
+    {
+      text: "准",
+      left: "4%",
+      top: "49%",
+    },
+    {
+      text: "差",
+      left: "4%",
+      top: "56%",
+    },
+  ],
+  toolbox: {
+    feature: {
+      saveAsImage: {},
+    },
+  },
+  grid: {
+    right: "15%",
+  },
+  xAxis: [
+    {
+      type: "category",
+      boundaryGap: false,
+      data: [],
+    },
+  ],
+  yAxis: [
+    {
+      type: "value",
+    },
+  ],
+  tooltip: {
+    show: true,
+  },
+  series: [
+    {
+      type: "line",
+      lineStyle: {
+        color: "rgb(26, 122, 240)",
+      },
+      symbolSize: 13,
+      symbol: "circle",
+      itemStyle: {
+        color: (params) => {
+          const paramValue = Number(params.value);
+          if (
+            paramValue <= Number(chartData.value.uclS) &&
+            paramValue >= Number(chartData.value.lclS)
+          ) {
+            return "rgb(26, 122, 240)";
+          } else {
+            return "red";
+          }
+        },
+      },
+      markLine: {
+        silent: true,
+        data: [
+          {
+            silent: false,
+            yAxis: 0,
+            label: {
+              position: "end",
+              formatter: `上限=${chartData.value.uclS}`,
+              color: "#333",
+            },
+            lineStyle: { type: "solid", color: "#333", width: 2 },
+          },
+          {
+            silent: false,
+            yAxis: 0,
+            label: {
+              position: "end",
+              formatter: `下限=${chartData.value.lclS}`,
+              color: "#333",
+            },
+            lineStyle: { type: "solid", color: "#333", width: 2 },
+          },
+          {
+            yAxis: 0,
+            silent: false,
+            label: {
+              position: "end",
+              formatter: ``,
+              color: "#333",
+            },
+            lineStyle: {
+              type: "solid",
+              color: "#333",
+              width: 2,
+            },
+          },
+        ],
+      },
+    },
+  ],
+});
+const Height = ref(0);
+const setHeight = () => {
+  Height.value = document.querySelector(".databox").clientHeight;
+  maxHeight.value = document.querySelector(".info").clientHeight;
+  maxWidth.value = document.querySelector(".info").clientWidth;
+};
+const Y2value = ref([]);
+const X2array = ref([]);
+const setY2value = () => {
+  Y2value.value = [];
+  chartData.value.subgroupStdDevs.forEach((item) => {
+    Y2value.value.push(item);
+  });
+  Y2value.value.unshift("");
+  Y2value.value.push("");
+  chartsOption2.value.series[0].data = Y2value.value;
+};
+const setX2array = () => {
+  X2array.value = [];
+  chartData.value.subgroupStdDevs.forEach((item, index) => {
+    X2array.value.push(index + 1);
+  });
+  X2array.value.unshift("");
+  X2array.value.push("");
+  chartsOption2.value.xAxis[0].data = X2array.value;
+};
+
+const setView = () => {
+  setHeight();
+  charts1.value = echarts.init(document.getElementById("charts"));
+  charts2.value = echarts.init(document.getElementById("charts1"));
+  charts1.value.setOption(chartsOption1.value, true);
+  charts2.value.setOption(chartsOption2.value, true);
+};
+onMounted(() => {
+  init();
+});
+const init = (data, str) => {
+  tableData.value = data;
+
+  setHeight();
+
+  nextTick(async () => {
+    await getTableData();
+    await changeSelect();
+    charts1.value = echarts.init(document.getElementById("charts"));
+    charts2.value = echarts.init(document.getElementById("charts1"));
+    charts1.value.setOption(chartsOption1.value, true);
+    charts2.value.setOption(chartsOption2.value, true);
+  });
+  window.addEventListener("resize", setView);
+};
+onBeforeUnmount(() => {
+  window.removeEventListener("resize", setView);
+});
+
+// 暴露 init 方法
+defineExpose({
+  init,
+});
+</script>
+
+<style lang="scss" scoped>
+@media print {
+  #print {
+    margin-left: -18%;
+  }
+}
+.formStyle {
+  width: 400px;
+  margin: 20px auto;
+}
+.container1 {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  background-color: white;
+  .infobox {
+    width: 200px;
+    .header {
+      height: 120px;
+      border-bottom: 2px solid #00000010;
+      padding: 20px;
+    }
+    .body {
+      padding: 20px;
+    }
+  }
+  .databox {
+    flex: 1;
+    border-left: 2px solid #00000010;
+    .box {
+      height: 710px;
+      padding: 5px 20px;
+      display: flex;
+      flex-direction: column;
+      .illustrate {
+        padding: 20px 60px;
+      }
+      .tableTitle {
+        text-align: center;
+        margin: 10px 0;
+        padding-right: 40px;
+      }
+      .header {
+        margin-top: 20px;
+        //margin-left: 100px;
+        display: flex;
+        width: 100%;
+        height: auto;
+      }
+      //.title {
+      //  height: 50px;
+      //  display: flex;
+      //  align-items: center;
+      //  margin-bottom: 10px;
+      //  justify-content: space-between;
+      //  .btns {
+      //    display: flex;
+      //    align-items: center;
+      //    .btn {
+      //      height: 24px;
+      //      font-size: 14px;
+      //      margin: 0 5px;
+      //    }
+      //  }
+      //}
+      .info {
+        margin-top: 20px;
+        flex: 1;
+        height: 300px;
+      }
+    }
+  }
+}
+</style>

+ 547 - 0
src/views/analysis/process/Xbar-S.vue

@@ -0,0 +1,547 @@
+<template>
+  <div class="container1">
+    <div class="databox">
+      <el-scrollbar :style="{ height: Height + 'px' }">
+        <div class="box" v-show="!addStatus">
+          <div
+            style="
+              display: flex;
+              align-items: center;
+              justify-content: space-between;
+            "
+          >
+            <div style="display: flex; align-items: center">
+              <div class="bg"></div>
+              控制图绘制
+            </div>
+
+            <el-button
+              type="primary"
+              v-print="'#print'"
+              style="margin-left: 10px; height: 25px"
+              >打 印</el-button
+            >
+          </div>
+          <div class="info">
+            <div id="print">
+              <div id="charts" :style="{ height: maxHeight / 2 + 'px' }"></div>
+              <div id="charts1" :style="{ height: maxHeight / 2 + 'px' }"></div>
+            </div>
+          </div>
+        </div>
+      </el-scrollbar>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import * as echarts from "echarts";
+import { useDictionaryStore } from "@/store";
+
+const { dicts } = useDictionaryStore();
+const opOptions = ref([...dicts.spc_operation]);
+const value = ref(opOptions.value[0].remark);
+const Y1value = ref([]);
+const X1array = ref([]);
+const setY1value = () => {
+  Y1value.value = [];
+  tableData.value.forEach((item) => {
+    Y1value.value.push(item.avg);
+  });
+  Y1value.value.unshift("");
+  Y1value.value.push("");
+
+  chartsOption1.value.series[0].data = Y1value.value;
+};
+const tableData = ref([]);
+const setX1array = async () => {
+  X1array.value = await [];
+  tableData.value.forEach((item, index) => {
+    X1array.value.push(index + 1);
+  });
+  X1array.value.unshift("");
+  X1array.value.push("");
+  chartsOption1.value.xAxis[0].data = X1array.value;
+};
+
+const setChart1Info = () => {
+  // chartsOption1.value.title[0].text = `上限=${showData.value.avgMax ? showData.value.avgMax : "-"}`;
+  // chartsOption1.value.title[0].text = `x̄=${showData.value.avgAvg ? showData.value.avgAvg : "-"}`;
+  chartsOption1.value.series[0].markLine.data[0].yAxis = JSON.parse(
+    value.value
+  ).avgMax;
+  chartsOption1.value.series[0].markLine.data[0].label.formatter = `                          上限=${
+    JSON.parse(value.value).avgMax ? JSON.parse(value.value).avgMax : "0"
+  }`;
+  chartsOption1.value.series[0].markLine.data[1].yAxis = JSON.parse(value.value)
+    .avgMin
+    ? JSON.parse(value.value).avgMin
+    : 0;
+  chartsOption1.value.series[0].markLine.data[1].label.formatter = `           下限=${JSON.parse(value.value).avgMin ? JSON.parse(value.value).avgMin : "0"}`;
+  chartsOption1.value.series[0].markLine.data[2].yAxis = JSON.parse(
+    value.value
+  ).avgMid;
+  chartsOption1.value.series[0].markLine.data[2].label.formatter = `x̄=${
+    JSON.parse(value.value).avgMid
+  }`;
+  // chartsOption1.value.title[2].text = `下限=${showData.value.avgMin ? showData.value.avgMin : "0"}`;
+};
+const setChart2Info = () => {
+  // chartsOption2.value.title[0].text = `上限=${showData.value.rangeMax ? showData.value.rangeMax : "-"}`;
+  // chartsOption2.value.title[0].text = `R=${showData.value.rangeAvg ? showData.value.rangeAvg : "-"}`;
+  chartsOption2.value.series[0].markLine.data[0].yAxis = JSON.parse(
+    value.value
+  ).rangeMax;
+  chartsOption2.value.series[0].markLine.data[0].label.formatter = `                          上限=${
+    JSON.parse(value.value).rangeMax ? JSON.parse(value.value).rangeMax : "0"
+  }`;
+  chartsOption2.value.series[0].markLine.data[1].yAxis = JSON.parse(value.value)
+    .rangeMin
+    ? JSON.parse(value.value).rangeMin
+    : 0;
+  chartsOption2.value.series[0].markLine.data[1].label.formatter = `           下限=${
+    JSON.parse(value.value).rangeMin ? JSON.parse(value.value).rangeMin : "0"
+  }`;
+  chartsOption2.value.series[0].markLine.data[2].yAxis = JSON.parse(
+    value.value
+  ).rangeMid;
+  chartsOption2.value.series[0].markLine.data[2].label.formatter = `x̄=${
+    JSON.parse(value.value).rangeMid
+  }`;
+  // chartsOption2.value.title[2].text = `下限=${showData.value.rangeMin ? showData.value.rangeMin : "0"}`;
+};
+const setChart1 = () => {
+  setChart1Info();
+  setY1value();
+  setX1array();
+  charts1.value.setOption(chartsOption1.value, true);
+};
+const setChart2 = () => {
+  setChart2Info();
+  setY2value();
+  setX2array();
+  charts2.value.setOption(chartsOption2.value, true);
+};
+
+const title = ref("调阻精度");
+const showLable = ref("调阻");
+const changeSelect = () => {
+  setTimeout(async () => {
+    // showLable.value = selectRef.value.currentPlaceholder;
+    // opOptions.value.forEach((item) => {
+    //   if (item.dictLabel == showLable.value) {
+    //     lableValue.value = item.dictValue;
+    //   }
+    // });
+    // switch (showLable.value) {
+    //   case "调阻":
+    //     title.value = "调阻精度";
+    //     break;
+    //   case "粘片":
+    //     title.value = "剪切强度";
+    //     break;
+    //   case "键合":
+    //     title.value = "键合强度";
+    //     break;
+    //   default:
+    //     title.value = "调阻精度";
+    //     break;
+    // }
+    // await getTableData();
+    chartsOption1.value.title[0].text = `${title.value}的Xbar-S控制图`;
+    setChart1();
+    setChart2();
+  }, 0);
+};
+
+const maxHeight = ref(null);
+const maxWidth = ref(null);
+const charts1 = shallowRef(null);
+const charts2 = shallowRef(null);
+const chartsOption1 = ref({
+  title: [
+    // {
+    //   text: `x̄=${showData.value.avgAvg ? showData.value.avgAvg : "-"}`,
+    //   right: "5%",
+    //   top: "42%",
+    //   textStyle: {
+    //     fontSize: 15,
+    //     color: "#333",
+    //     fontWeight: 100,
+    //   },
+    // },
+    {
+      text: `${title.value}的Xbar-S控制图`,
+      left: "40%",
+    },
+    {
+      text: "样",
+      left: "4%",
+      top: "28%",
+    },
+    {
+      text: "本",
+      left: "4%",
+      top: "35%",
+    },
+    {
+      text: "均",
+      left: "4%",
+      top: "42%",
+    },
+    {
+      text: "值",
+      left: "4%",
+      top: "49%",
+    },
+  ],
+  grid: {
+    right: "15%",
+  },
+  toolbox: {
+    feature: {
+      saveAsImage: {},
+    },
+  },
+  tooltip: {
+    show: true,
+  },
+  xAxis: [
+    {
+      type: "category",
+      boundaryGap: false,
+      data: [],
+    },
+  ],
+  yAxis: [
+    {
+      type: "value",
+    },
+  ],
+  series: [
+    {
+      type: "line",
+      lineStyle: {
+        color: "rgb(26, 122, 240)",
+      },
+      symbolSize: 13,
+      symbol: "circle",
+      itemStyle: {
+        color: (params) => {
+          const avg = JSON.parse(value.value);
+          const paramValue = Number(params.value);
+          if (
+            paramValue <= Number(avg.avgMax) &&
+            paramValue >= Number(avg.avgMin)
+          ) {
+            return "rgb(26, 122, 240)";
+          } else {
+            return "red";
+          }
+        },
+      },
+      markLine: {
+        silent: true,
+        data: [
+          {
+            silent: false,
+            yAxis: 0,
+            label: {
+              position: "end",
+              formatter: `上限=${JSON.parse(value.value).avgMax ? JSON.parse(value.value).avgMax : "-"}`,
+              color: "#333",
+            },
+            lineStyle: { type: "solid", color: "#333", width: 2 },
+          },
+          {
+            silent: false,
+            yAxis: 0,
+            label: {
+              position: "end",
+              formatter: `下限=${JSON.parse(value.value).avgMin ? JSON.parse(value.value).avgMin : "-"}`,
+              color: "#333",
+            },
+            lineStyle: {
+              type: "solid",
+              color: "#333",
+              width: 2,
+            },
+          },
+          {
+            yAxis: 0,
+            silent: false,
+            label: {
+              position: "end",
+              formatter: ``,
+              color: "#333",
+            },
+            lineStyle: {
+              type: "solid",
+              color: "#333",
+              width: 2,
+            },
+          },
+        ],
+      },
+    },
+  ],
+});
+const chartsOption2 = ref({
+  title: [
+    // {
+    //   text: `R=${showData.value.rangeAvg ? showData.value.rangeAvg : "-"}`,
+    //   right: "5%",
+    //   top: "42%",
+    //   textStyle: {
+    //     fontSize: 15,
+    //     color: "#333",
+    //     fontWeight: 100,
+    //   },
+    // },
+    {
+      text: "样",
+      left: "4%",
+      top: "28%",
+    },
+    {
+      text: "本",
+      left: "4%",
+      top: "35%",
+    },
+    {
+      text: "标",
+      left: "4%",
+      top: "42%",
+    },
+    {
+      text: "准",
+      left: "4%",
+      top: "49%",
+    },
+    {
+      text: "差",
+      left: "4%",
+      top: "56%",
+    },
+  ],
+  toolbox: {
+    feature: {
+      saveAsImage: {},
+    },
+  },
+  grid: {
+    right: "15%",
+  },
+  xAxis: [
+    {
+      type: "category",
+      boundaryGap: false,
+      data: [],
+    },
+  ],
+  yAxis: [
+    {
+      type: "value",
+    },
+  ],
+  tooltip: {
+    show: true,
+  },
+  series: [
+    {
+      type: "line",
+      lineStyle: {
+        color: "rgb(26, 122, 240)",
+      },
+      symbolSize: 13,
+      symbol: "circle",
+      itemStyle: {
+        color: (params) => {
+          const range = JSON.parse(value.value);
+          const paramValue = Number(params.value);
+          if (
+            paramValue <= Number(range.rangeMax) &&
+            paramValue >= Number(range.rangeMin)
+          ) {
+            return "rgb(26, 122, 240)";
+          } else {
+            return "red";
+          }
+        },
+      },
+      markLine: {
+        silent: true,
+        data: [
+          {
+            silent: false,
+            yAxis: 0,
+            label: {
+              position: "end",
+              formatter: `上限=${JSON.parse(value.value).rangeMax ? JSON.parse(value.value).rangeMax : "-"}`,
+              color: "#333",
+            },
+            lineStyle: { type: "solid", color: "#333", width: 2 },
+          },
+          {
+            silent: false,
+            yAxis: 0,
+            label: {
+              position: "end",
+              formatter: `下限=${JSON.parse(value.value).rangeMin ? JSON.parse(value.value).rangeMin : "-"}`,
+              color: "#333",
+            },
+            lineStyle: { type: "solid", color: "#333", width: 2 },
+          },
+          {
+            yAxis: 0,
+            silent: false,
+            label: {
+              position: "end",
+              formatter: ``,
+              color: "#333",
+            },
+            lineStyle: {
+              type: "solid",
+              color: "#333",
+              width: 2,
+            },
+          },
+        ],
+      },
+    },
+  ],
+});
+const Height = ref(0);
+const setHeight = () => {
+  Height.value = document.querySelector(".databox").clientHeight;
+  maxHeight.value = document.querySelector(".info").clientHeight;
+  maxWidth.value = document.querySelector(".info").clientWidth;
+};
+const Y2value = ref([]);
+const X2array = ref([]);
+const setY2value = () => {
+  Y2value.value = [];
+  tableData.value.forEach((item) => {
+    Y2value.value.push(item.range);
+  });
+  Y2value.value.unshift("");
+  Y2value.value.push("");
+  chartsOption2.value.series[0].data = Y2value.value;
+};
+const setX2array = () => {
+  X2array.value = [];
+  tableData.value.forEach((item, index) => {
+    X2array.value.push(index + 1);
+  });
+  X2array.value.unshift("");
+  X2array.value.push("");
+  chartsOption2.value.xAxis[0].data = X2array.value;
+};
+
+const setView = () => {
+  setHeight();
+  charts1.value = echarts.init(document.getElementById("charts"));
+  charts2.value = echarts.init(document.getElementById("charts1"));
+  charts1.value.setOption(chartsOption1.value, true);
+  charts2.value.setOption(chartsOption2.value, true);
+};
+onMounted(() => {
+  init();
+});
+const init = (data, str) => {
+  tableData.value = data;
+  console.log(JSON.stringify(data), "data");
+  changeSelect();
+  setHeight();
+  nextTick(() => {
+    charts1.value = echarts.init(document.getElementById("charts"));
+    charts2.value = echarts.init(document.getElementById("charts1"));
+    charts1.value.setOption(chartsOption1.value, true);
+    charts2.value.setOption(chartsOption2.value, true);
+  });
+  window.addEventListener("resize", setView);
+};
+onBeforeUnmount(() => {
+  window.removeEventListener("resize", setView);
+});
+
+// 暴露 init 方法
+defineExpose({
+  init,
+});
+</script>
+
+<style lang="scss" scoped>
+@media print {
+  #print {
+    margin-left: -18%;
+  }
+}
+.formStyle {
+  width: 400px;
+  margin: 20px auto;
+}
+.container1 {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  background-color: white;
+  .infobox {
+    width: 200px;
+    .header {
+      height: 120px;
+      border-bottom: 2px solid #00000010;
+      padding: 20px;
+    }
+    .body {
+      padding: 20px;
+    }
+  }
+  .databox {
+    flex: 1;
+    border-left: 2px solid #00000010;
+    .box {
+      height: 710px;
+      padding: 5px 20px;
+      display: flex;
+      flex-direction: column;
+      .illustrate {
+        padding: 20px 60px;
+      }
+      .tableTitle {
+        text-align: center;
+        margin: 10px 0;
+        padding-right: 40px;
+      }
+      .header {
+        margin-top: 20px;
+        //margin-left: 100px;
+        display: flex;
+        width: 100%;
+        height: auto;
+      }
+      //.title {
+      //  height: 50px;
+      //  display: flex;
+      //  align-items: center;
+      //  margin-bottom: 10px;
+      //  justify-content: space-between;
+      //  .btns {
+      //    display: flex;
+      //    align-items: center;
+      //    .btn {
+      //      height: 24px;
+      //      font-size: 14px;
+      //      margin: 0 5px;
+      //    }
+      //  }
+      //}
+      .info {
+        margin-top: 20px;
+        flex: 1;
+        height: 300px;
+      }
+    }
+  }
+}
+</style>

+ 91 - 9
src/views/analysis/process/index.vue

@@ -18,7 +18,23 @@
         </el-select>
       </div>
       <div class="body">
-        <div class="text">
+        <div>
+          <div class="text">控制图:</div>
+          <el-select
+            v-model="value2"
+            placeholder="Select"
+            ref="selectRef2"
+            @change="changeSelect2"
+          >
+            <el-option
+              v-for="item in sccOptions"
+              :key="item.value"
+              :label="item.dictLabel"
+              :value="item.dictValue"
+            />
+          </el-select>
+        </div>
+        <div class="text" style="margin-top: 20px">
           Xbar-UCL:{{ value ? JSON.parse(value).avgMax : "-" }}
         </div>
         <div class="text">
@@ -161,13 +177,38 @@
                   ><span>{{ row.batchNo }}</span>
                 </template>
               </el-table-column>
-              <el-table-column width="100" prop="accuracys" label="数据">
+              <el-table-column
+                width="100"
+                align="center"
+                prop="accuracys"
+                label="数据"
+                :show-overflow-tooltip="false"
+              >
+                <template #default="{ row }">
+                  <el-tooltip placement="top">
+                    <template #content>
+                      <div v-for="(item, index) in row.accuracys" :key="index">
+                        <span>数值{{ index + 1 }}: {{ item }}</span>
+                      </div>
+                    </template>
+                    <div class="ellipsis-text">
+                      {{ row.accuracys.join(", ") }}
+                    </div>
+                  </el-tooltip>
+                </template>
+              </el-table-column>
+<!--              <el-table-column
+                width="100"
+                prop="accuracys"
+                align="center"
+                label="数据"
+              >
                 <template #default="{ row }">
                   <div v-for="(item, index) in row.accuracys" :key="index">
-                    <span>数值{{ index }}:{{ item }}</span>
+                    <span>数值{{ index + 1 }}: {{ item }}</span>
                   </div>
                 </template>
-              </el-table-column>
+              </el-table-column>-->
               <!-- <el-table-column align="center" :label="title">
                 <el-table-column
                   align="center"
@@ -604,7 +645,7 @@
           </div>
         </div>
         <div class="box" v-show="!addStatus">
-          <div
+          <!--          <div
             style="
               display: flex;
               align-items: center;
@@ -628,6 +669,12 @@
               <div id="charts" :style="{ height: maxHeight / 2 + 'px' }"></div>
               <div id="charts1" :style="{ height: maxHeight / 2 + 'px' }"></div>
             </div>
+          </div>-->
+          <div class="info" v-if="value2 === 'X̅-R'">
+            <XbarR ref="xbarRRef" :process="showLable" />
+          </div>
+          <div class="info" v-if="value2 === 'X̅-S'">
+            <XbarS ref="xbarSRef" :process="showLable" />
           </div>
         </div>
       </el-scrollbar>
@@ -636,6 +683,9 @@
 </template>
 
 <script setup>
+import { ref } from "vue";
+import XbarR from "./Xbar-R.vue";
+import XbarS from "./Xbar-S-2.vue";
 import * as echarts from "echarts";
 import { useDictionaryStore } from "@/store";
 import {
@@ -646,6 +696,22 @@ import {
   getTaskCode,
 } from "@/api/analysis";
 import Search from "@/components/Search/index.vue";
+
+const xbarRRef = ref("xbarRRef");
+const xbarRRefMethod = async () => {
+  await nextTick();
+  if (xbarRRef.value) {
+    xbarRRef.value.init(tableData.value);
+  }
+};
+
+const xbarSRef = ref("xbarSRef");
+const xbarSRefMethod = async () => {
+  await nextTick();
+  if (xbarSRef.value) {
+    xbarSRef.value.init(tableData.value);
+  }
+};
 const year = ref("0");
 const currentOption = reactive({
   total: 0,
@@ -684,8 +750,8 @@ const getTableData = async () => {
 };
 const searchForm = [
   {
-    label: "创建时间",
-    prop: "created",
+    label: "日期",
+    prop: "createds",
     type: "daterange",
   },
   {
@@ -898,6 +964,7 @@ const showData = ref({});
 const url = ref(import.meta.env.VITE_APP_BASE_API + "/api/v1/spc/import");
 const headers = { Authorization: `${localStorage.getItem("token")}` };
 const opOptions = ref([...dicts.spc_operation]);
+const sccOptions = ref([...dicts.spc_control_chart]);
 const setChart1Info = () => {
   // chartsOption1.value.title[0].text = `上限=${showData.value.avgMax ? showData.value.avgMax : "-"}`;
   // chartsOption1.value.title[0].text = `x̄=${showData.value.avgAvg ? showData.value.avgAvg : "-"}`;
@@ -981,6 +1048,8 @@ const taskOption = ref([]);
 const value = ref(opOptions.value[0].remark);
 const title = ref("调阻精度");
 
+const value2 = ref(sccOptions.value[0].dictValue);
+
 const showLable = ref("调阻");
 const changeSelect = () => {
   setTimeout(async () => {
@@ -1020,6 +1089,15 @@ const changeSelect = () => {
     setChart2();
   }, 0);
 };
+const changeSelect2 = () => {
+  if (value2.value === "X̅-R") {
+    console.log("X̅-R");
+    xbarRRefMethod();
+  } else if (value2.value === "X̅-S") {
+    console.log("X̅-S");
+    xbarSRefMethod();
+  }
+};
 
 // const searchData = computed(() =>
 //   tableData.value.filter((item) => item.data.includes(searchValue.value))
@@ -1171,7 +1249,6 @@ const chartsOption1 = ref({
               type: "solid",
               color: "#333",
               width: 2,
-              type: "dashed",
             },
           },
         ],
@@ -1292,7 +1369,6 @@ const chartsOption2 = ref({
               type: "solid",
               color: "#333",
               width: 2,
-              type: "dashed",
             },
           },
         ],
@@ -1421,6 +1497,12 @@ onBeforeUnmount(() => {
     margin-left: -18%;
   }
 }
+.ellipsis-text {
+  white-space: nowrap; /* 禁止换行 */
+  overflow: hidden; /* 隐藏超出部分 */
+  text-overflow: ellipsis; /* 显示省略号 */
+  width: 100%; /* 宽度占满单元格 */
+}
 .formStyle {
   width: 400px;
   margin: 20px auto;

+ 13 - 3
src/views/analysis/spc/index.vue

@@ -1,7 +1,12 @@
 <template>
   <div class="container1">
     <div class="header" v-show="!addStatus && !editStatus">
-      <Search :searchOptions="searchForm" ref="searchRef" />
+      <Search
+        :searchOptions="searchForm"
+        ref="searchRef"
+        @data-list="getData"
+        @reset-list="resetData"
+      />
     </div>
     <div class="table" v-if="!addStatus && !editStatus">
       <el-button
@@ -177,7 +182,6 @@ import {
   add,
   updateData,
   deleteData,
-
 } from "@/api/spc";
 defineOptions({
   name: "SPCrules",
@@ -201,7 +205,7 @@ const searchRef = ref(null);
 const searchForm = [
   {
     label: "创建时间",
-    prop: "created",
+    prop: "createds",
     type: "daterange",
   },
   {
@@ -372,6 +376,12 @@ const reset = () => {
   addStatus.value = false;
   editStatus.value = false;
 };
+
+const resetData = () => {
+  searchRef.value.searchForm = {};
+  getData();
+};
+
 const toSubmit = async () => {
   if (addStatus.value) {
     await ruleFormRef.value.validate(async (valid, fields) => {

+ 213 - 153
src/views/analysis/target/index/index.vue

@@ -37,6 +37,14 @@
               <div class="bg"></div>
               样本数据录入
             </div>
+            <div class="header" v-show="!addStatus && !editStatus">
+              <Search
+                :searchOptions="searchForm"
+                ref="searchRef"
+                @data-list="getTableData"
+                @reset-list="resetData"
+              />
+            </div>
             <div class="btns">
               <!-- <el-button
                 v-if="!editStatus && !addStatus"
@@ -49,8 +57,17 @@
                 v-if="!addStatus && !editStatus"
                 type="primary"
                 class="btn"
+                @click="updataItem(row.Index)"
+                size="small"
+                >计算Cpk</el-button
+              >
+              <el-button
+                v-if="!addStatus && !editStatus"
+                type="primary"
+                class="btn"
                 v-print="'#print'"
                 @click="printFnc"
+                size="small"
                 >打印</el-button
               >
               <el-button
@@ -58,6 +75,7 @@
                 type="primary"
                 class="btn"
                 @click="changeaddstatus"
+                size="small"
                 >新增</el-button
               >
               <el-button
@@ -75,7 +93,8 @@
                 @click="canceleOp"
                 id="cancel"
                 >取消</el-button
-              ><span v-if="!addStatus && !editStatus" style="margin: 10px"
+              >
+              <!--              <span v-if="!addStatus && !editStatus" style="margin: 10px"
                 >年份:</span
               >
               <el-date-picker
@@ -88,7 +107,7 @@
                 placeholder="Pick a year"
                 :clear-icon="''"
                 @change="getTableData"
-              />
+              />-->
             </div>
             <!-- 导入代码 -->
             <!-- <div class="btns">
@@ -128,16 +147,14 @@
               <div class="tableTitle">
                 <div></div>
                 <div>{{ title }}一致性检测表</div>
-                <div>{{ year }}年</div>
+                <div></div>
               </div>
               <el-table
                 v-if="!printStatus"
                 :data="showTableData"
-                :span-method="objectSpanMethod"
-                id="table"
                 border
                 :style="{
-                  height: Height - 230 + 'px',
+                  height: Height - 50 + 'px',
                   width: maxWidth + 'px',
                 }"
                 :show-overflow-tooltip="true"
@@ -173,108 +190,42 @@
                     ><span>{{ row.batchNo }}</span>
                   </template>
                 </el-table-column>
-                <el-table-column align="center" :label="title">
-                  <el-table-column
-                    align="center"
-                    prop="accuracy1"
-                    width="60"
-                    label="数值1"
-                  >
-                    <template #default="{ row }"
-                      ><span>{{ row.accuracy1 }}</span>
-                    </template>
-                  </el-table-column>
-                  <el-table-column
-                    align="center"
-                    prop="accuracy2"
-                    width="60"
-                    label="数值2"
-                  >
-                    <template #default="{ row }"
-                      ><span>{{ row.accuracy2 }}</span>
-                    </template>
-                  </el-table-column>
-                  <el-table-column
-                    align="center"
-                    prop="accuracy3"
-                    width="60"
-                    label="数值3"
-                  >
-                    <template #default="{ row }"
-                      ><span>{{ row.accuracy3 }}</span>
-                    </template>
-                  </el-table-column>
-                  <el-table-column
-                    align="center"
-                    prop="accuracy4"
-                    width="60"
-                    label="数值4"
-                  >
-                    <template #default="{ row }"
-                      ><span>{{ row.accuracy4 }}</span>
-                    </template>
-                  </el-table-column>
-                  <el-table-column
-                    align="center"
-                    prop="accuracy5"
-                    width="60"
-                    label="数值5"
-                  >
-                    <template #default="{ row }"
-                      ><span>{{ row.accuracy5 }}</span>
-                    </template>
-                  </el-table-column>
-                  <el-table-column
-                    align="center"
-                    prop="accuracy6"
-                    width="60"
-                    label="数值6"
-                  >
-                    <template #default="{ row }"
-                      ><span>{{ row.accuracy6 }}</span>
-                    </template>
-                  </el-table-column>
-                  <el-table-column
-                    align="center"
-                    prop="accuracy7"
-                    width="60"
-                    label="数值7"
-                  >
-                    <template #default="{ row }"
-                      ><span>{{ row.accuracy7 }}</span>
-                    </template>
-                  </el-table-column>
-                  <el-table-column
-                    align="center"
-                    prop="accuracy8"
-                    width="60"
-                    label="数值8"
-                  >
-                    <template #default="{ row }"
-                      ><span>{{ row.accuracy8 }}</span>
-                    </template>
-                  </el-table-column>
-                  <el-table-column
-                    align="center"
-                    prop="accuracy9"
-                    width="60"
-                    label="数值9"
-                  >
-                    <template #default="{ row }"
-                      ><span>{{ row.accuracy9 }}</span>
-                    </template>
-                  </el-table-column>
-                  <el-table-column
-                    align="center"
-                    prop="accuracy10"
-                    width="60"
-                    label="数值10"
-                  >
-                    <template #default="{ row }"
-                      ><span>{{ row.accuracy10 }}</span>
-                    </template>
-                  </el-table-column> </el-table-column
-                ><el-table-column
+                <el-table-column
+                  width="100"
+                  align="center"
+                  prop="accuracys"
+                  label="数据"
+                  :show-overflow-tooltip="false"
+                >
+                  <template #default="{ row }">
+                    <el-tooltip placement="top">
+                      <template #content>
+                        <div
+                          v-for="(item, index) in row.accuracys"
+                          :key="index"
+                        >
+                          <span>数值{{ index + 1 }}: {{ item }}</span>
+                        </div>
+                      </template>
+                      <div class="ellipsis-text">
+                        {{ row.accuracys.join(", ") }}
+                      </div>
+                    </el-tooltip>
+                  </template>
+                </el-table-column>
+<!--                <el-table-column
+                  width="100"
+                  align="center"
+                  prop="accuracys"
+                  label="数据"
+                >
+                  <template #default="{ row }">
+                    <div v-for="(item, index) in row.accuracys" :key="index">
+                      <span>数值{{ index + 1 }}: {{ item }}</span>
+                    </div>
+                  </template>
+                </el-table-column>-->
+                <!--                <el-table-column
                   align="center"
                   prop="Cpk"
                   label="Cpk值"
@@ -283,7 +234,7 @@
                   <template #default="{ row }"
                     ><span>{{ Number(row.cpk).toFixed(2) }}</span>
                   </template>
-                </el-table-column>
+                </el-table-column>-->
                 <el-table-column
                   align="center"
                   width="70"
@@ -333,7 +284,7 @@
                 </el-table-column>
                 <el-table-column
                   align="center"
-                  width="160"
+                  width="260"
                   prop=""
                   label="操作"
                   id="opear"
@@ -603,7 +554,7 @@
                 <template #default="{ row }"
                   >
                   <el-input-number
-           
+
                     v-model="row.accuracy1"
                     :precision="2"
                     :step="0.01"
@@ -620,7 +571,7 @@
                 <template #default="{ row }"
                   >
                   <el-input-number
-        
+
                     v-model="row.accuracy1"
                     :precision="2"
                     :step="0.01"
@@ -637,7 +588,7 @@
                 <template #default="{ row }"
                   >
                   <el-input-number
-     
+
                     v-model="row.accuracy1"
                     :precision="2"
                     :step="0.01"
@@ -655,7 +606,7 @@
                   <template #default="{ row }"
                     >
                     <el-input-number
-       
+
                       v-model="row.accuracy1"
                       :precision="2"
                       :step="0.01"
@@ -672,7 +623,7 @@
                   <template #default="{ row }"
                     >
                     <el-input-number
-          
+
                       v-model="row.accuracy2"
                       :precision="2"
                       :step="0.01"
@@ -688,7 +639,7 @@
                   <template #default="{ row }"
                     >
                     <el-input-number
-              
+
                       v-model="row.accuracy3"
                       :precision="2"
                       :step="0.01"
@@ -704,7 +655,7 @@
                   <template #default="{ row }"
                     >
                     <el-input-number
-          
+
                       v-model="row.accuracy4"
                       :precision="2"
                       :step="0.01"
@@ -720,7 +671,7 @@
                   <template #default="{ row }"
                     >
                     <el-input-number
-          
+
                       v-model="row.accuracy5"
                       :precision="2"
                       :step="0.01"
@@ -731,7 +682,7 @@
                 <template #default="{ row }"
                   >
                   <el-input-number
-            
+
                     v-model="row.accuracy1"
                     :precision="2"
                     :step="0.01"
@@ -742,7 +693,7 @@
                 <template #default="{ row }"
                   >
                   <el-input-number
-             
+
                     v-model="row.accuracy1"
                     :precision="2"
                     :step="0.01"
@@ -753,7 +704,7 @@
                 <template #default="{ row }"
                   >
                   <el-input-number
-              
+
                     v-model="row.accuracy1"
                     :precision="2"
                     :step="0.01"
@@ -768,7 +719,7 @@
                 <template #default="{ row }"
                   >
                   <el-input-number
-           
+
                     v-model="row.accuracy1"
                     :precision="2"
                     :step="0.01"
@@ -780,7 +731,7 @@
                 <template #default="{ row }"
                   >
                   <el-input-number
-    
+
                     v-model="row.accuracy1"
                     :precision="2"
                     :step="0.01"
@@ -792,7 +743,7 @@
                 <template #default="{ row }"
                   >
                   <el-input-number
-              
+
                     v-model="row.accuracy1"
                     :precision="2"
                     :step="0.01"
@@ -828,21 +779,41 @@
                     value-format="YYYY-MM-DD"
                   />
                 </el-form-item>
+                <el-form-item label="任务编号" prop="qualityTaskId">
+                  <el-select
+                    v-model="addData.qualityTaskId"
+                    @change="
+                      (value) => {
+                        taskChange(value);
+                      }
+                    "
+                  >
+                    <el-option
+                      v-for="(item, index) in taskOption"
+                      :key="index"
+                      :label="item.taskCode"
+                      :value="item.id"
+                    />
+                  </el-select>
+                </el-form-item>
                 <el-form-item label="产品型号" prop="model">
-                  <!-- <el-select  v-model="addData.model">
+                  <el-input :disabled="true" v-model="addData.model" />
+                </el-form-item>
+                <!--                <el-form-item label="产品型号" prop="model">
+                  &lt;!&ndash; <el-select  v-model="addData.model">
                     <el-option
                       v-for="item in modelOptions"
                       :key="item.dictLabel"
                       :label="item.dictLabel"
                       :value="item.dictValue"
                     />
-                  </el-select> -->
+                  </el-select> &ndash;&gt;
                   <el-input v-model="addData.model" />
-                </el-form-item>
+                </el-form-item>-->
                 <el-form-item label="生产批号" prop="batchNo">
                   <el-input v-model="addData.batchNo" />
                 </el-form-item>
-                <template v-for="(item, index) in 30" :key="index">
+                <!--                <template v-for="(item, index) in 30" :key="index">
                   <el-form-item
                     :label="'数值' + addIndex(index)"
                     :prop="'accuracy' + addIndex(index)"
@@ -860,7 +831,25 @@
                       v-model="addData[`accuracy${addIndex(index)}`]"
                     />
                   </el-form-item>
-                </template>
+                </template>-->
+                <el-form-item
+                  v-for="(item, index) in addData.accuracys"
+                  :label="'数值' + (index + 1)"
+                  :key="index"
+                  :rules="[
+                    {
+                      required: true,
+                      trigger: 'change',
+                    },
+                  ]"
+                >
+                  <el-input-number
+                    :precision="2"
+                    :step="0.01"
+                    style="width: 100%"
+                    v-model="addData.accuracys[index]"
+                  />
+                </el-form-item>
                 <!-- <el-form-item label="平均值" prop="avg">
                 <el-input v-model="addData.avg" />
               </el-form-item>
@@ -926,10 +915,40 @@
 
 <script setup>
 import { useDictionaryStore } from "@/store";
-import { getData2, addDatas, deleteData, updateData } from "@/api/analysis";
+import {
+  getData2,
+  addDatas,
+  deleteData,
+  updateData,
+  getTaskCode,
+} from "@/api/analysis";
+import Search from "@/components/Search/index.vue";
 const tableData = ref([]);
 const printStatus = ref(false);
 const printLoading = ref(false);
+const taskOption = ref([]);
+const getTaskOption = async () => {
+  const { data } = await getTaskCode({
+    operationCode: JSON.parse(value.value).value,
+  });
+  taskOption.value = data;
+};
+const accuracysSum = ref(0);
+const taskChange = (value) => {
+  taskOption.value.forEach((item) => {
+    if (item.id == value) {
+      addData.value.model = item.prodtModel;
+      accuracysSum.value = Number(item.processCount);
+      addData.value.accuracys = [];
+      let array = [];
+      for (let i = 0; i < accuracysSum.value; i++) {
+        array.push(0);
+      }
+      addData.value.accuracys = array;
+    }
+  });
+};
+
 //打印功能
 const printFnc = () => {
   printLoading.value = true;
@@ -995,23 +1014,24 @@ const setTableData = (array) => {
   //★Index 为实际接口数据Index
   array.forEach((item, index) => {
     let obj1 = { ...item, Index: index };
-    let obj2 = { ...item, Index: index };
-    let obj3 = { ...item, Index: index };
-    for (let i = 1; i < 11; i++) {
-      obj2[`accuracy${i}`] = obj2[`accuracy${i + 10}`];
-      obj3[`accuracy${i}`] = obj3[`accuracy${i + 20}`];
-    }
+    // let obj2 = { ...item, Index: index };
+    // let obj3 = { ...item, Index: index };
+    // for (let i = 1; i < 11; i++) {
+    //   obj2[`accuracy${i}`] = obj2[`accuracy${i + 10}`];
+    //   obj3[`accuracy${i}`] = obj3[`accuracy${i + 20}`];
+    // }
     showTableData.value.push(obj1);
-    showTableData.value.push(obj2);
-    showTableData.value.push(obj3);
+    // showTableData.value.push(obj2);
+    // showTableData.value.push(obj3);
   });
 };
 //接口获取实际data
 const getTableData = async () => {
   const { data, code, msg } = await getData2({
+    ...searchRef.value.searchForm,
     pageNo: currentOption.page,
     pageSize: currentOption.limit,
-    yearStr: year.value,
+    // yearStr: year.value,
     operation: lableValue.value,
   });
   if (code == "200") {
@@ -1026,6 +1046,24 @@ const getTableData = async () => {
   }
   disabled.value = false;
 };
+const searchRef = ref(null);
+const searchForm = [
+  {
+    label: "日期",
+    prop: "createds",
+    type: "daterange",
+  },
+  {
+    label: "产品型号",
+    prop: "model",
+    type: "input",
+  },
+  {
+    label: "生产批号",
+    prop: "batchNo",
+    type: "input",
+  },
+];
 //编辑状态
 const editStatus = ref(false);
 //新增状态
@@ -1236,6 +1274,7 @@ const showLable = ref("调阻");
 const lableValue = ref("");
 const changeSelect = () => {
   setTimeout(() => {
+    getTaskOption();
     showLable.value = selectRef.value.currentPlaceholder;
     opOptions.value.forEach((item) => {
       if (item.dictLabel == showLable.value) {
@@ -1565,6 +1604,7 @@ const addSubmit = async () => {
       const { data, code } = await addDatas({
         ...addData.value,
         yearStr: year.value,
+        operation: lableValue.value,
       });
       if (code == "200") {
         ElMessage.success("添加成功!");
@@ -1606,6 +1646,12 @@ const reset = () => {
     pageSizes: [4],
   };
 };
+
+const resetData = () => {
+  searchRef.value.searchForm = {};
+  getTableData();
+};
+
 watch(
   () => showTableData.value,
   (newVal, oldVal) => {
@@ -1616,6 +1662,7 @@ watch(
   }
 );
 onMounted(() => {
+  getTaskOption();
   setHeight();
   year.value = new Date().getFullYear() + "";
   opOptions.value.forEach((item) => {
@@ -1679,6 +1726,12 @@ onMounted(() => {
     alignitems: center;
   }
 }
+.ellipsis-text {
+  white-space: nowrap; /* 禁止换行 */
+  overflow: hidden; /* 隐藏超出部分 */
+  text-overflow: ellipsis; /* 显示省略号 */
+  width: 100%; /* 宽度占满单元格 */
+}
 .formStyle {
   width: 400px;
   margin: 20px auto;
@@ -1716,22 +1769,29 @@ onMounted(() => {
         margin: 10px 0;
         padding-right: 40px;
       }
-      .title {
-        height: 30px;
+      .header {
+        margin-top: 20px;
+        //margin-left: 100px;
         display: flex;
-        align-items: center;
-        margin-bottom: 10px;
-        justify-content: space-between;
-        .btns {
-          display: flex;
-          align-items: center;
-          .btn {
-            height: 24px;
-            font-size: 14px;
-            margin: 0 5px;
-          }
-        }
+        width: 100%;
+        height: auto;
       }
+      //.title {
+      //  height: 30px;
+      //  display: flex;
+      //  align-items: center;
+      //  margin-bottom: 10px;
+      //  justify-content: space-between;
+      //  .btns {
+      //    display: flex;
+      //    align-items: center;
+      //    .btn {
+      //      height: 24px;
+      //      font-size: 14px;
+      //      margin: 0 5px;
+      //    }
+      //  }
+      //}
       .info {
         flex: 1;
         .tableTitle {