QualityConsistencyInspection.vue 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. <template>
  2. <div class="multi-product-ring-container">
  3. <ScreenComHeader :module-id="moduleId" title="质量一致性检验" />
  4. <div ref="chartRef" style="width: 100%; height: 100%"></div>
  5. </div>
  6. </template>
  7. <script setup>
  8. import * as echarts from "echarts";
  9. import ScreenComHeader from "@/views/screens/configs/screenComHeader.vue";
  10. import { qualityConsistentInspection } from "@/api/screens";
  11. const props = defineProps({
  12. moduleId: {
  13. type: String,
  14. required: true,
  15. },
  16. });
  17. const chartRef = ref(null);
  18. const chartData = ref([]);
  19. let chartInstance = null;
  20. let timer = null;
  21. const currentProductIndex = ref(0);
  22. // 初始化图表
  23. const initChart = () => {
  24. if (!chartRef.value) return;
  25. chartInstance = echarts.init(chartRef.value);
  26. updateChart();
  27. window.addEventListener("resize", handleResize);
  28. // 5秒切换产品批次
  29. timer = setInterval(() => {
  30. if (chartData.value.length > 0) {
  31. currentProductIndex.value =
  32. (currentProductIndex.value + 1) % chartData.value.length;
  33. updateChart();
  34. }
  35. }, 5000);
  36. };
  37. // 更新图表
  38. const updateChart = () => {
  39. if (!chartInstance || chartData.value.length === 0) return;
  40. const currentItem = chartData.value[currentProductIndex.value];
  41. // 计算总时长用于比例
  42. const totalDuration = currentItem.optionList.reduce(
  43. (sum, item) => sum + item.duration,
  44. 0
  45. );
  46. const option = {
  47. backgroundColor: "transparent",
  48. title: [
  49. {
  50. text: `产品:${currentItem.productName} 批号:${currentItem.batchCode}`,
  51. subtext: `检验类型:${currentItem.inspectType}`,
  52. left: "center",
  53. top: 10,
  54. textStyle: {
  55. color: "#fff",
  56. fontSize: 16,
  57. fontWeight: "bold",
  58. },
  59. subtextStyle: {
  60. color: "#aaa",
  61. fontSize: 12,
  62. marginTop: 5,
  63. },
  64. },
  65. ],
  66. tooltip: {
  67. trigger: "item",
  68. formatter: (params) => {
  69. const item = currentItem.optionList[params.dataIndex];
  70. const percentage = ((item.duration / totalDuration) * 100).toFixed(1);
  71. return `
  72. <div style="font-weight:bold;margin-bottom:5px">${params.name}</div>
  73. <div style="margin:3px 0">检验时长: ${item.duration}小时</div>
  74. <div style="margin:3px 0">占比: ${percentage}%</div>
  75. <div style="margin:3px 0">状态: ${item.status === 1 ? "通过" : "未通过"}</div>
  76. `;
  77. },
  78. backgroundColor: "rgba(0,0,0,0.8)",
  79. borderColor: "#333",
  80. textStyle: {
  81. color: "#fff",
  82. fontSize: 12,
  83. },
  84. },
  85. series: [
  86. {
  87. name: "检验项目",
  88. type: "pie",
  89. radius: ["40%", "60%"],
  90. center: ["50%", "50%"],
  91. avoidLabelOverlap: false,
  92. selectedMode: "multiple", // 允许选中单个扇区
  93. selectedOffset: 20, // 选中扇区的偏移量
  94. itemStyle: {
  95. borderRadius: 4,
  96. borderColor: "#0f1325",
  97. borderWidth: 2,
  98. },
  99. label: {
  100. show: true,
  101. formatter: "{b}",
  102. fontSize: 12,
  103. color: "#fff",
  104. fontWeight: "normal",
  105. },
  106. labelLine: {
  107. show: true,
  108. length: 20,
  109. length2: 30,
  110. smooth: 0.2,
  111. },
  112. data: currentItem.optionList.map((item, index) => ({
  113. name: item.optionName,
  114. value: item.duration,
  115. // 状态为1的项目默认选中(凸出)
  116. selected: item.status === 1,
  117. itemStyle: {
  118. color: getColorByIndex(index),
  119. // 状态为1的项目增加发光效果
  120. shadowBlur: item.status === 1 ? 10 : 0,
  121. shadowColor:
  122. item.status === 1 ? getColorByIndex(index) : "transparent",
  123. },
  124. emphasis: {
  125. itemStyle: {
  126. shadowBlur: 15,
  127. shadowColor: getColorByIndex(index),
  128. },
  129. },
  130. })),
  131. },
  132. ],
  133. };
  134. chartInstance.setOption(option, true);
  135. };
  136. // 根据索引获取颜色
  137. const getColorByIndex = (index) => {
  138. const colors = [
  139. "#5470C6",
  140. "#91CC75",
  141. "#EE6666",
  142. "#73C0DE",
  143. "#FAC858",
  144. "#3BA272",
  145. "#FC8452",
  146. "#9A60B4",
  147. ];
  148. return colors[index % colors.length];
  149. };
  150. const handleResize = () => {
  151. chartInstance?.resize();
  152. };
  153. // 加载数据
  154. const loadData = async () => {
  155. try {
  156. const res = await qualityConsistentInspection(2);
  157. chartData.value = res.data;
  158. if (chartData.value.length > 0) {
  159. updateChart();
  160. }
  161. } catch (error) {
  162. console.error("加载数据失败:", error);
  163. }
  164. };
  165. onMounted(() => {
  166. initChart();
  167. loadData();
  168. });
  169. onBeforeUnmount(() => {
  170. if (timer) clearInterval(timer);
  171. if (chartInstance) {
  172. chartInstance.dispose();
  173. window.removeEventListener("resize", handleResize);
  174. }
  175. });
  176. </script>
  177. <style scoped>
  178. .multi-product-ring-container {
  179. width: 100%;
  180. height: 100%;
  181. min-height: 450px;
  182. position: relative;
  183. background-color: transparent;
  184. border-radius: 8px;
  185. padding: 10px;
  186. box-sizing: border-box;
  187. }
  188. </style>